diff --git a/packages/client/.storybook/main.ts b/packages/client/.storybook/main.ts index 10fde5f32..a1f2d6bec 100644 --- a/packages/client/.storybook/main.ts +++ b/packages/client/.storybook/main.ts @@ -5,4 +5,9 @@ import { defineMain } from '@storybook/react-vite/node' export default defineMain({ framework: '@storybook/react-vite', stories: ['../stories/**/*.stories.tsx'], + addons: ['@storybook/addon-docs'], + viteFinal: async config => { + config.define = { ...config.define, 'process.env': {} } + return config + }, }) diff --git a/packages/client/.storybook/preview-head.html b/packages/client/.storybook/preview-head.html new file mode 100644 index 000000000..e1aa23c44 --- /dev/null +++ b/packages/client/.storybook/preview-head.html @@ -0,0 +1,20 @@ + diff --git a/packages/client/.storybook/preview.ts b/packages/client/.storybook/preview.ts deleted file mode 100644 index 6fc8b03fb..000000000 --- a/packages/client/.storybook/preview.ts +++ /dev/null @@ -1,13 +0,0 @@ -/* eslint-disable import/no-extraneous-dependencies */ - -import { definePreview } from '@storybook/react-vite' -import * as addonActions from '@storybook/addon-actions/preview' -import * as addonBackgrounds from '@storybook/addon-backgrounds/preview' -import * as addonViewport from '@storybook/addon-viewport/preview' - -export default definePreview({ - addons: [addonActions, addonBackgrounds, addonViewport], - initialGlobals: { - viewport: { value: '', isRotated: false }, - }, -}) diff --git a/packages/client/.storybook/preview.tsx b/packages/client/.storybook/preview.tsx new file mode 100644 index 000000000..416361cc8 --- /dev/null +++ b/packages/client/.storybook/preview.tsx @@ -0,0 +1,69 @@ +/* eslint-disable import/no-extraneous-dependencies */ + +import { definePreview, type Decorator } from '@storybook/react-vite' +import addonDocs from '@storybook/addon-docs' + +import { MemoryRouter, Route, Routes } from 'react-router-dom' +import { ThemeProvider } from 'styled-components' +import { I18nextProvider } from 'react-i18next' +import { AntConfigProvider } from '@coko/client' + +import { makeTheme } from '../app/theme' +import GlobalStyle from '../app/theme/elements/GlobalStyle' +import i18next from '../app/i18n' + +const theme = makeTheme() + +const withProviders: Decorator = (Story, context) => { + const initialEntries = context.parameters?.router?.initialEntries ?? ['/'] + const routePath = context.parameters?.router?.path + + const content = ( + + + + +
{ + const anchor = (e.target as HTMLElement).closest('a') + if (anchor) { + /* eslint-disable-next-line no-console */ + console.log('navigate to:', anchor.getAttribute('href')) + } + }} + onKeyDown={e => { + if (e.key === 'Enter' || e.key === ' ') { + const anchor = (e.target as HTMLElement).closest('a') + if (anchor) { + /* eslint-disable-next-line no-console */ + console.log('navigate to:', anchor.getAttribute('href')) + } + } + }} + role="presentation" + > + +
+
+
+
+ ) + + return ( + + {routePath ? ( + + + + ) : ( + content + )} + + ) +} + +export default definePreview({ + addons: [addonDocs()], + tags: ['autodocs'], + decorators: [withProviders], +}) diff --git a/packages/client/app/Router.tsx b/packages/client/app/Router.tsx index ac748276e..928dda1e9 100644 --- a/packages/client/app/Router.tsx +++ b/packages/client/app/Router.tsx @@ -39,7 +39,13 @@ import UsersPage from './components/component-users-manager/src/UsersPage' import { ConfigContext } from './components/config/src' import { XpubContext } from './components/xpub-with-context/src' -import { AuthenticatedPage, GroupPage, MenuPage } from './pages' +import { + AuthenticatedPage, + CMSPage, + FormsPage, + GroupPage, + MenuPage, +} from './pages' import { CURRENT_USER } from './queries' @@ -107,16 +113,19 @@ const RoleGate = (props: RoleGateProps): ReactNode => { */ const DashboardRoutes = (): ReactNode => { const config = useContext(ConfigContext) + // @ts-ignore + const dashboard = config?.dashboard + return ( } path="" /> - {config?.dashboard?.showSections?.includes('submission') && ( + {dashboard?.showSections?.includes('submission') && ( } path="submissions" /> )} - {config?.dashboard?.showSections?.includes('review') && ( + {dashboard?.showSections?.includes('review') && ( } path="reviews" /> )} - {config?.dashboard?.showSections?.includes('editor') && ( + {dashboard?.showSections?.includes('editor') && ( } path="edits" /> )} @@ -216,35 +225,39 @@ const Router = (): ReactNode => { > } path="reports" /> + } path="forms" /> + } - path="submission-form-builder" + path="forms/submission-form-builder" /> } - path="review-form-builder" + path="forms/review-form-builder" /> } - path="decision-form-builder" + path="forms/decision-form-builder" /> } path="users" /> } path="tasks" /> - - } path="pages/:pageId?" /> - } path="layout" /> - } path="article" /> - } path="filebrowser" /> - } path="metadata" /> - } - path="collections" - /> - + } path="cms" /> + } path="cms/pages/:pageId?" /> + } path="cms/layout" /> + } path="cms/article" /> + } + path="cms/filebrowser" + /> + } path="cms/metadata" /> + } + path="cms/collections" + /> } path="configuration" /> diff --git a/packages/client/app/components/Menu.jsx b/packages/client/app/components/Menu.jsx deleted file mode 100644 index 7b35ef473..000000000 --- a/packages/client/app/components/Menu.jsx +++ /dev/null @@ -1,119 +0,0 @@ -import { useState, useMemo } from 'react' -import PropTypes from 'prop-types' -import { useTranslation } from 'react-i18next' -import { useMutation } from '@apollo/client/react' -import { - NavItem, - NavLinks, - MainNavWrapper, - SectionNavLayoutSettings, - Root, - ScrollWrapper, - SubMenu, - UserComponent, - StyledPinButton, -} from './component-menu' - -import { UPDATE_MENU } from '../queries' - -const Menu = ({ - // loginLink = '/login', - navLinkComponents, - user, - notice, - profileLink, -}) => { - const { t } = useTranslation() - const [menuIsMinimal, setMenuIsMinimal] = useState(!user.menuPinned) - const [menuPinned, setMenuPinned] = useState(!!user.menuPinned) - const [updateMenuState] = useMutation(UPDATE_MENU) - - const renderLinks = useMemo(() => { - return ( - navLinkComponents && - navLinkComponents.map(navInfo => - navInfo.menu ? ( - - ) : ( - - ), - ) - ) - }, [menuIsMinimal, navLinkComponents]) - - const handlers = { - pinNavbar: () => { - updateMenuState({ variables: { expanded: !menuPinned } }) - setMenuPinned(!menuPinned) - }, - mouseoverNav: () => { - if (menuIsMinimal) { - setMenuIsMinimal(false) - } - }, - mouseleaveNav: () => { - if (!menuPinned) { - setMenuIsMinimal(true) - } - }, - expandCollapse: () => { - setMenuIsMinimal(!menuIsMinimal) - }, - } - - return ( - - - - - {/* TODO: Place this notice (used for offline notification) better */} - {notice} - - - - {renderLinks} - - - - ) -} - -Menu.propTypes = { - className: PropTypes.string.isRequired, - loginLink: PropTypes.string.isRequired, - navLinkComponents: PropTypes.arrayOf(PropTypes.object).isRequired, - user: PropTypes.oneOfType([PropTypes.object]), - notice: PropTypes.node.isRequired, - profileLink: PropTypes.string.isRequired, -} - -export default Menu diff --git a/packages/client/app/components/component-ai-assistant/ChatBubble.jsx b/packages/client/app/components/component-ai-assistant/ChatBubble.jsx index 10a12f369..a4bf3704e 100644 --- a/packages/client/app/components/component-ai-assistant/ChatBubble.jsx +++ b/packages/client/app/components/component-ai-assistant/ChatBubble.jsx @@ -176,8 +176,8 @@ const ChatBubble = ({ forceHide, icons, hasApiKey }) => { width: '35px', height: '35px', borderRadius: '50%', - backgroundColor: theme.color.brand1.base(), - border: theme.color.brand1.shade50(), + backgroundColor: theme.color.brand1.base, + border: theme.color.brand1.shade50, textAlign: 'center', color: '#fff', }} diff --git a/packages/client/app/components/component-cms-manager/src/CMSFileBrowserPage.jsx b/packages/client/app/components/component-cms-manager/src/CMSFileBrowserPage.jsx index cdb06bf01..25909b526 100644 --- a/packages/client/app/components/component-cms-manager/src/CMSFileBrowserPage.jsx +++ b/packages/client/app/components/component-cms-manager/src/CMSFileBrowserPage.jsx @@ -12,13 +12,14 @@ import { css } from '@codemirror/lang-css' import SplitPane, { Pane } from 'split-pane-react' import 'split-pane-react/esm/themes/default.css' -import { serverUrl } from '@coko/client' +import { serverUrl, th } from '@coko/client' import Browser from './browser/FileBrowser' -import { CommsErrorBanner, Spinner } from '../../shared' +import { CommsErrorBanner, SectionContent, Spinner } from '../../shared' import UploadComponent from '../../component-production/src/components/uploadManager/UploadComponent' import { EditPageContainer } from './style' import { ConfigContext } from '../../config/src' +import Page from '../../../ui/shared/Page' import { GET_CMS_FILE_CONTENT, @@ -45,8 +46,13 @@ const SpanActive = styled.span` font-weight: bold; ` +const FullHeightContainer = styled(EditPageContainer)` + background: ${th('color.backgroundC')}; + height: calc(100vh - 160px); +` + const MainFileContent = styled.div` - background-color: #f4f5f7; + border-left: 2px solid ${th('colorPrimary')}; display: flex; height: 100%; overflow: auto; @@ -283,47 +289,56 @@ const CMSFileBrowserPage = () => { } return ( - - - - - - - {!activeContent.isFolder && - activeContent.id && - !activeContent.isImage && ( - - )} - {activeContent.isFolder && activeContent.id && ( - - Upload To Folder {activeContent.name}: - + + + + + - - )} - {activeContent.isImage && Preview} - - - + + + {!activeContent.isFolder && + activeContent.id && + !activeContent.isImage && ( + + )} + {activeContent.isFolder && activeContent.id && ( + + Upload To Folder {activeContent.name} + : + + + )} + {activeContent.isImage && Preview} + + + + + ) } diff --git a/packages/client/app/components/component-cms-manager/src/CMSLayoutPage.jsx b/packages/client/app/components/component-cms-manager/src/CMSLayoutPage.jsx index 95c4e58f7..7a76c8300 100644 --- a/packages/client/app/components/component-cms-manager/src/CMSLayoutPage.jsx +++ b/packages/client/app/components/component-cms-manager/src/CMSLayoutPage.jsx @@ -4,8 +4,8 @@ import { useMutation, useQuery } from '@apollo/client/react' import { useTranslation } from 'react-i18next' import { ConfigContext } from '../../config/src' import LayoutForm from './layout/LayoutForm' -import { Container, Spinner, CommsErrorBanner } from '../../shared' -import PageHeader from './components/PageHeader' +import { Spinner, CommsErrorBanner } from '../../shared' +import Page from '../../../ui/shared/Page' import { GET_CMS_LAYOUT, @@ -125,9 +125,7 @@ const CMSLayoutPage = () => { const { cmsLayout } = data return ( - - - + publish(values)} @@ -148,7 +146,7 @@ const CMSLayoutPage = () => { ) }} - + ) } diff --git a/packages/client/app/components/component-cms-manager/src/CMSMetadataPage.jsx b/packages/client/app/components/component-cms-manager/src/CMSMetadataPage.jsx index 9e7eac285..7a3655154 100644 --- a/packages/client/app/components/component-cms-manager/src/CMSMetadataPage.jsx +++ b/packages/client/app/components/component-cms-manager/src/CMSMetadataPage.jsx @@ -9,15 +9,14 @@ import { useTranslation } from 'react-i18next' import { ConfigContext } from '../../config/src' import journalSchema from './collection/ui/journalSchema' // Import the function that generates the schema and uiSchema -import { - ActionButton, - Container, - HeadingWithAction, - Heading, - PaddedContent, - SectionContent, - WidthLimiter, -} from '../../shared' +import { ActionButton, PaddedContent, SectionContent } from '../../shared' +import Page from '../../../ui/shared/Page' + +const StyledContent = styled.div` + font-family: ${th('fontInterface')}; + font-size: ${th('fontSizeBase')}; + line-height: ${th('lineHeightBase')}; +` const FieldWrapper = styled.div` display: flex; @@ -73,11 +72,10 @@ const CmsMetadataPage = () => { integrity="sha384-HSMxcRTRxnN+Bdg0JdbxYKrThecOKuH5zCYotlSAcp1+c8xmyTe9GYg1l9a69psu" rel="stylesheet" /> - - - {t('leftMenu.Metadata')} - - + {/* Reset Bootstrap 3's html { font-size: 10px } which bleeds into the rest of the app */} + + +
{ /> - - + + ) } diff --git a/packages/client/app/components/component-cms-manager/src/CMSPagesPage.jsx b/packages/client/app/components/component-cms-manager/src/CMSPagesPage.jsx index ec1694386..1643a94b6 100644 --- a/packages/client/app/components/component-cms-manager/src/CMSPagesPage.jsx +++ b/packages/client/app/components/component-cms-manager/src/CMSPagesPage.jsx @@ -2,7 +2,9 @@ import { useContext, useState } from 'react' import { useNavigate, useParams } from 'react-router-dom' import { useMutation, useQuery } from '@apollo/client/react' import { useTranslation } from 'react-i18next' -import { Spinner, CommsErrorBanner } from '../../shared' +import styled from 'styled-components' +import { th, grid } from '@coko/client' +import { Spinner, CommsErrorBanner, SectionContent } from '../../shared' import CMSPageEditForm from './pages/CMSPageEdit' @@ -10,9 +12,13 @@ import CMSPageEditSidebar from './pages/CMSPageEditSidebar' import { ConfigContext } from '../../config/src' -import { EditPageContainer, EditPageLeft, EditPageRight } from './style' +import { + EditPageContainer, + EditPageLeft as BaseEditPageLeft, + EditPageRight as BaseEditPageRight, +} from './style' -import PageHeader from './components/PageHeader' +import Page from '../../../ui/shared/Page' import { GET_CMS_PAGES, @@ -22,6 +28,26 @@ import { DELETE_CMS_PAGE, } from '../../../queries' +const EditPageLeft = styled(BaseEditPageLeft)` + overflow-y: auto; +` + +const EditPageRight = styled(BaseEditPageRight)` + background-color: transparent; + border-left: 2px solid ${th('colorPrimary')}; + overflow-y: auto; + + /* stylelint-disable-next-line selector-class-pattern */ + .ProseMirror { + padding: ${grid(2)}; + } +` + +const FullHeightContainer = styled(EditPageContainer)` + background: ${th('color.backgroundC')}; + height: calc(100vh - 160px); +` + const CMSPagesPage = () => { const navigate = useNavigate() const params = useParams() @@ -86,38 +112,40 @@ const CMSPagesPage = () => { } return ( - - - showPage(selectedCmsPage)} - onNewItemButtonClick={() => addNewPage()} - /> - - - - {cmsPage && ( - - )} - - + + + + + showPage(selectedCmsPage)} + onNewItemButtonClick={() => addNewPage()} + /> + + + {cmsPage && ( + + )} + + + + ) } diff --git a/packages/client/app/components/component-cms-manager/src/article/article.jsx b/packages/client/app/components/component-cms-manager/src/article/article.jsx index e53ccee99..b68a83816 100644 --- a/packages/client/app/components/component-cms-manager/src/article/article.jsx +++ b/packages/client/app/components/component-cms-manager/src/article/article.jsx @@ -11,40 +11,48 @@ import { html } from '@codemirror/lang-html' import { css } from '@codemirror/lang-css' import { - Heading, - HeadingWithAction, - HiddenTabs, - Manuscript, + HiddenTabsContainer, + Tab, + TabContainer, ErrorBoundary, } from '../../../shared' import { FormActionButton } from '../style' +import Page from '../../../../ui/shared/Page' +import { FlexRow } from '../../../../globals' import UploadAsset from '../../../component-production/src/components/uploadManager/UploadAsset' import ManuscriptMetadata from './ManuscriptMetadata' -const FlexRow = styled.div` +const Tabs = styled.div` display: flex; - gap: ${grid(1)}; - justify-content: space-between; + margin-top: ${grid(1)}; ` -const StyledManuscript = styled(Manuscript)` - display: flex; - flex: 1 1 100%; - flex-direction: column; - height: 100vh; - overflow-y: auto; +const TabRow = styled(FlexRow)` width: 100%; ` +const PublishButton = styled(FormActionButton)` + margin-bottom: ${grid(1)}; + margin-left: auto; + margin-right: 0; +` + const ScrollableTabContent = styled.section` background-color: ${th('color.backgroundA')}; border-radius: ${th('borderRadius')}; - box-shadow: ${({ theme }) => theme.boxShadow.shades[200]}; - height: calc(100vh - 108px); + height: calc(100vh - 180px); + overflow: auto; - width: calc(100% - 50px); + + .cm-theme-light { + height: 100%; + } + + .cm-editor { + height: 100%; + } ` const Article = ({ @@ -59,6 +67,8 @@ const Article = ({ const [htmlValue, setHtmlValue] = useState(articleTemplate.article) + const [activeTab, setActiveTab] = useState('article-template') + const onChangeCss = useCallback( debounce(cssContent => { setCssValue(cssContent) @@ -107,84 +117,90 @@ const Article = ({ ), } - const cssArticle = { - content: ( - - - - ), - key: 'article-css', - label: 'Article Css', - } - - const htmlTemplate = { - content: ( - - - - ), - key: 'article-template', - label: 'Article Template', - } - - const uploadAssets = { - content: ( - - - - ), - key: 'template-assets', - label: 'Template Assets', - } - - const manuscriptMetadata = { - content: ( - - - - ), - key: 'manuscript-metadata', - label: 'Article Metadata', - } + const sections = [ + { + key: 'article-css', + label: 'Article Css', + content: ( + + + + ), + }, + { + key: 'article-template', + label: 'Article Template', + content: ( + + + + ), + }, + { + key: 'template-assets', + label: 'Template Assets', + content: ( + + + + ), + }, + { + key: 'manuscript-metadata', + label: 'Article Metadata', + content: ( + + + + ), + }, + ] return ( - - - - {t('cmsPage.article.title')} - - {submitButtonText} - - - + - + + + + {sections.map(({ key, label }) => ( + setActiveTab(key)}> + +
{label}
+
+
+ ))} +
+ + {submitButtonText} + +
+
+ {sections.map(section => ( +
+ {section.content} +
+ ))}
-
+ ) } diff --git a/packages/client/app/components/component-cms-manager/src/collection/CollectionList.jsx b/packages/client/app/components/component-cms-manager/src/collection/CollectionList.jsx index b5b839ef3..5a8c4fe0a 100644 --- a/packages/client/app/components/component-cms-manager/src/collection/CollectionList.jsx +++ b/packages/client/app/components/component-cms-manager/src/collection/CollectionList.jsx @@ -12,16 +12,19 @@ import { HeadingCell } from '../../../component-production/src/components/styles import { Action, ActionButton, - Container, - HeadingWithAction, - Heading, PaddedContent, SectionContent, - WidthLimiter, LabelBadge, } from '../../../shared' +import Page from '../../../../ui/shared/Page' import CollectionModalForm from './CollectionModalForm' +const StyledContent = styled.div` + font-family: ${th('fontInterface')}; + font-size: ${th('fontSizeBase')}; + line-height: ${th('lineHeightBase')}; +` + const CmsHeadStyled = styled.div` button { font-size: ${th('fontSizeBase')}; @@ -216,11 +219,10 @@ const CollectionList = ({ integrity="sha384-HSMxcRTRxnN+Bdg0JdbxYKrThecOKuH5zCYotlSAcp1+c8xmyTe9GYg1l9a69psu" rel="stylesheet" /> - - - {t('leftMenu.Collections')} - - + {/* Reset Bootstrap 3's html { font-size: 10px } which bleeds into the rest of the app */} + + + @@ -263,8 +265,8 @@ const CollectionList = ({ )} - - + + ) } diff --git a/packages/client/app/components/component-cms-manager/src/collection/ui/journalSchema.js b/packages/client/app/components/component-cms-manager/src/collection/ui/journalSchema.js index 003e813a8..f507c64f9 100644 --- a/packages/client/app/components/component-cms-manager/src/collection/ui/journalSchema.js +++ b/packages/client/app/components/component-cms-manager/src/collection/ui/journalSchema.js @@ -1,7 +1,7 @@ const generateSchema = t => { const schema = { type: 'object', - title: t('leftMenu.Metadata'), + title: t('cmsIndexPage.metadataTitle'), properties: { title: { type: 'string', diff --git a/packages/client/app/components/component-cms-manager/src/editor/EditorStyles.jsx b/packages/client/app/components/component-cms-manager/src/editor/EditorStyles.jsx index e28c8bab6..27fb6a77d 100644 --- a/packages/client/app/components/component-cms-manager/src/editor/EditorStyles.jsx +++ b/packages/client/app/components/component-cms-manager/src/editor/EditorStyles.jsx @@ -1,7 +1,7 @@ /* stylelint-disable string-quotes, declaration-block-no-redundant-longhand-properties */ import styled from 'styled-components' -import { th } from '@coko/client' +import { th, grid } from '@coko/client' import waxDefaultStyles from '../../../wax-collab/src/layout/waxDefaultStyles' import EditorElements from '../../../wax-collab/src/layout/EditorElements' @@ -59,7 +59,7 @@ export const EditorDiv = styled.div` height: 100%; ${props => !props.$hideComments && 'min-width: 800px'}; overflow: auto; - padding: 5px; + padding: ${grid(2)}; position: relative; .error & { diff --git a/packages/client/app/components/component-cms-manager/src/layout/LayoutForm.jsx b/packages/client/app/components/component-cms-manager/src/layout/LayoutForm.jsx index ad00b1cb3..6af9a7041 100644 --- a/packages/client/app/components/component-cms-manager/src/layout/LayoutForm.jsx +++ b/packages/client/app/components/component-cms-manager/src/layout/LayoutForm.jsx @@ -1,5 +1,7 @@ /* eslint-disable react/prop-types */ +import styled from 'styled-components' + import { SectionContent, PaddedContent } from '../../../shared' import { ActionButtonContainer, FormActionButton } from '../style' import PublishStatus from '../components/PublishStatus' @@ -9,6 +11,12 @@ import Branding from './Branding' import Footer from './Footer' import SiteStatus from './SiteStatus' +const Wrapper = styled.div` + > section:first-child > div { + margin-top: 0; + } +` + const LayoutForm = ({ formikProps, flaxSiteUrlForGroup, @@ -81,7 +89,7 @@ const LayoutForm = ({ } return ( -
+ {renderBranding()} {renderHeader()} {renderFooter()} @@ -98,7 +106,7 @@ const LayoutForm = ({
- + ) } diff --git a/packages/client/app/components/component-coar/CoarNotifyInbox.jsx b/packages/client/app/components/component-coar/CoarNotifyInbox.jsx index c2bd027c6..a54d3f593 100644 --- a/packages/client/app/components/component-coar/CoarNotifyInbox.jsx +++ b/packages/client/app/components/component-coar/CoarNotifyInbox.jsx @@ -1,16 +1,16 @@ /* eslint-disable react/prop-types */ import { useTranslation } from 'react-i18next' +import styled from 'styled-components' import CoarMessages from '../component-review/src/components/coar/CoarMessages' -import { - Container, - FlexRow, - Heading, - Pagination, - PaginationContainerShadowed, -} from '../shared' +import { FlexRow, Pagination, PaginationContainerShadowed } from '../shared' +import Page from '../../ui/shared/Page' import SearchControl from '../component-manuscripts/src/SearchControl' import { URI_PAGENUM_PARAM, URI_SEARCH_PARAM } from '../../shared/urlParamUtils' +const SearchRow = styled(FlexRow)` + justify-content: flex-end; +` + // type CoarNotifyMessageProps = { // id: string // manuscriptId: string | null @@ -43,40 +43,41 @@ const CoarNotifyInbox = ({ const { t } = useTranslation() return ( - - - {t('coarNotifyInboxPage.title')} - - applyQueryParams({ - [URI_PAGENUM_PARAM]: 1, - [URI_SEARCH_PARAM]: newQuery, - }) - } - currentSearchQuery={currentSearchQuery} - /> - +
- - {!loading && ( - - applyQueryParams({ [URI_PAGENUM_PARAM]: newPage }) + + + applyQueryParams({ + [URI_PAGENUM_PARAM]: 1, + [URI_SEARCH_PARAM]: newQuery, + }) } - totalCount={totalMessageCount} + currentSearchQuery={currentSearchQuery} + /> + +
+ - )} + {!loading && ( + + applyQueryParams({ [URI_PAGENUM_PARAM]: newPage }) + } + totalCount={totalMessageCount} + /> + )} +
-
+ ) } diff --git a/packages/client/app/components/component-config-manager/src/ConfigManagerForm.jsx b/packages/client/app/components/component-config-manager/src/ConfigManagerForm.jsx index 99925d1ee..32c7e287a 100644 --- a/packages/client/app/components/component-config-manager/src/ConfigManagerForm.jsx +++ b/packages/client/app/components/component-config-manager/src/ConfigManagerForm.jsx @@ -17,15 +17,8 @@ import { configTabLabels, } from './ui/schema' // Import the function that generates the schema and uiSchema -import { - ActionButton, - Container, - HeadingWithAction, - Heading, - SectionContent, - HiddenTabs, - Alert, -} from '../../shared' +import { ActionButton, SectionContent, HiddenTabs, Alert } from '../../shared' +import Page from '../../../ui/shared/Page' import EmailTemplatesPage from '../../component-email-templates/src/EmailTemplatesPage' import emailTemplatesToSchema from './helpers' import { EmailTemplatesProvider } from '../../component-email-templates/hooks/EmailTemplatesContext' @@ -34,24 +27,29 @@ import { T } from '../../component-notification-event/misc/constants' import { getFormBadgeBg } from '../../component-email-templates/src/handlebarsAutocomplete/helpers' import DescriptionField from './ui/DescriptionField' -const StyledContainer = styled(Container)` +const StyledContainer = styled.div` --tabs-border: 1px solid #ddd; display: flex; flex-direction: column; + height: 100%; + min-height: 0; overflow: hidden; + + /* stylelint-disable-next-line declaration-no-important */ + font-family: ${th('fontInterface')} !important; + /* stylelint-disable-next-line declaration-no-important */ + font-size: ${th('fontSizeBase')} !important; + /* stylelint-disable-next-line declaration-no-important */ + line-height: ${th('lineHeightBase')} !important; ` const StyledSectionContent = styled(SectionContent)` margin: 0; overflow-y: auto; - padding: ${th('spacing.g')} ${th('spacing.g')} 0 ${th('spacing.g')}; + padding: ${grid(3.75)} ${grid(3.75)} 0 ${grid(3.75)}; width: 100%; ` -const StyledHeading = styled(Heading)` - padding: 0.5rem 0 1.5rem; -` - const InstanceTypeLegend = styled.legend` border: 0; border-bottom: 1px solid #e5e5e5; @@ -396,31 +394,32 @@ const ConfigManagerForm = ({ integrity="sha384-HSMxcRTRxnN+Bdg0JdbxYKrThecOKuH5zCYotlSAcp1+c8xmyTe9GYg1l9a69psu" rel="stylesheet" /> - - - {t('configPage.Configuration')} - - - {!['emails', 'events'].includes(activeTab) && ( -
-
You have unsaved changes.
- - {t('common.Save')} - -
- )} -
+ {/* Reset Bootstrap 3's html { font-size: 10px } which bleeds into the rest of the app */} + + + + + {!['emails', 'events'].includes(activeTab) && ( +
+
You have unsaved changes.
+ + {t('common.Save')} + +
+ )} +
+
) } diff --git a/packages/client/app/components/component-dashboard/src/components/DashboardLayout.jsx b/packages/client/app/components/component-dashboard/src/components/DashboardLayout.jsx index ee63cecb3..a4fa72a9e 100644 --- a/packages/client/app/components/component-dashboard/src/components/DashboardLayout.jsx +++ b/packages/client/app/components/component-dashboard/src/components/DashboardLayout.jsx @@ -2,19 +2,13 @@ import { useContext } from 'react' import { th, grid } from '@coko/client' -import { Link, useLocation, useParams, useNavigate } from 'react-router-dom' +import { Link, useLocation, useNavigate, useParams } from 'react-router-dom' import styled from 'styled-components' import { useTranslation } from 'react-i18next' import { Button } from '../../../pubsweet' -import { - Heading, - HeadingWithAction, - HiddenTabsContainer, - Tab, - TabContainer, -} from '../../../shared' -import { Container } from '../style' +import { HiddenTabsContainer, Tab, TabContainer } from '../../../shared' +import Page from '../../../../ui/shared/Page' import SearchControl from '../../../component-manuscripts/src/SearchControl' import { ControlsContainer } from '../../../component-manuscripts/src/style' import { @@ -35,13 +29,21 @@ const Tabs = styled.div` margin-top: ${grid(1)}; ` +const TabRow = styled(FlexRow)` + width: 100%; +` + +const RightControls = styled(ControlsContainer)` + margin-left: auto; + margin-bottom: ${grid(1)}; +` + const DashboardLayout = ({ children }) => { const config = useContext(ConfigContext) const navigate = useNavigate() const location = useLocation() const { groupName } = useParams() const applyQueryParams = useQueryParams() - const uriQueryParams = new URLSearchParams(location.search) const currentSearchQuery = uriQueryParams.get(URI_SEARCH_PARAM) const dashboardPages = [] @@ -67,11 +69,22 @@ const DashboardLayout = ({ children }) => { }) return ( - - - - {t('dashboardPage.Dashboard')} - + + {/* TODO The following block should be replaced with a new LinkTabs component */} + + + + {dashboardPages.map(({ href, label }) => ( + + + +
{label}
+
+
+
+ ))} +
+ applyQueryParams({ @@ -87,26 +100,11 @@ const DashboardLayout = ({ children }) => { > {t('dashboardPage.New submission')} -
-
-
- - {/* TODO The following block should be replaced with a new LinkTabs component */} - - - {dashboardPages.map(({ href, label }) => ( - - - -
{label}
-
-
-
- ))} -
+ +
{children} -
+ ) } diff --git a/packages/client/app/components/component-dashboard/src/style.jsx b/packages/client/app/components/component-dashboard/src/style.jsx index ffa78d6a5..19d560041 100644 --- a/packages/client/app/components/component-dashboard/src/style.jsx +++ b/packages/client/app/components/component-dashboard/src/style.jsx @@ -90,7 +90,7 @@ export const Centered = styled.div` export const InvitationContent = styled.div` background: ${th('color.backgroundA')}; border-radius: ${th('borderRadius')}; - box-shadow: ${th('boxShadow')}; + box-shadow: ${th('boxShadow200')}; margin-bottom: 1rem; max-height: calc(100vh - 32px); max-width: 50em; diff --git a/packages/client/app/components/component-formbuilder/src/components/FormBuilderLayout.jsx b/packages/client/app/components/component-formbuilder/src/components/FormBuilderLayout.jsx index 2aa0b2538..b3ec38144 100644 --- a/packages/client/app/components/component-formbuilder/src/components/FormBuilderLayout.jsx +++ b/packages/client/app/components/component-formbuilder/src/components/FormBuilderLayout.jsx @@ -11,8 +11,6 @@ import FormSettingsModal from './FormSettingsModal' import FieldSettingsModal from './FieldSettingsModal' import FormBuilder from './FormBuilder' import { - Container, - Heading, HiddenTabs, SectionContent, SectionRow, @@ -20,6 +18,7 @@ import { ActionButton, RoundIconButton, } from '../../../shared' +import Page from '../../../../ui/shared/Page' import { ConfirmationModal } from '../../../component-modal/src/ConfirmationModal' import FormSummary from './FormSummary' import { ConfigContext } from '../../../config/src' @@ -53,7 +52,6 @@ const WidthLimiter = styled.div` display: flex; flex: 1 1 0; flex-direction: column; - max-width: 1200px; min-height: 0; ` @@ -228,48 +226,49 @@ const FormBuilderLayout = ({ return ( <> - - - {t(`formBuilder.${category}.title`)} -
- { - setSelectedFormId(null) - setIsEditingFormSettings(true) + +
+ +
- {t('formBuilder.Add new form')} - - { - setSelectedFormId(tab) - setSelectedFieldId(null) - }} - sections={sections} - shouldFillFlex - /> -
-
- + { + setSelectedFormId(null) + setIsEditingFormSettings(true) + }} + > + {t('formBuilder.Add new form')} + + { + setSelectedFormId(tab) + setSelectedFieldId(null) + }} + sections={sections} + shouldFillFlex + /> +
+ +
+ @@ -81,12 +81,8 @@ const TitleWithAbstractAsTooltip = ({ manuscript }) => { )} - {isManuscriptFromSemanticScholar && ( - - )} - {isManuscriptFromCoarNotify && ( - - )} + {isManuscriptFromSemanticScholar && } + {isManuscriptFromCoarNotify && } {url ? ( diff --git a/packages/client/app/components/component-manuscripts/src/Manuscripts.jsx b/packages/client/app/components/component-manuscripts/src/Manuscripts.jsx index d65daf352..cd60f9d13 100644 --- a/packages/client/app/components/component-manuscripts/src/Manuscripts.jsx +++ b/packages/client/app/components/component-manuscripts/src/Manuscripts.jsx @@ -9,6 +9,7 @@ import { ToastContainer } from 'react-toastify' import 'react-toastify/dist/ReactToastify.css' import { grid } from '@coko/client' +import Page from '../../../ui/shared/Page' import { Checkbox, Dropdown } from '../../pubsweet' @@ -26,7 +27,6 @@ import { Columns, CommsErrorBanner, Container, - Heading, Pagination, PaginationContainerShadowed, RoundIconButton, @@ -47,19 +47,24 @@ const OuterContainer = styled(Container)` padding: 0; ` +const ManuscriptsColumns = styled(Columns)` + height: 100%; +` + const ManuscriptsPane = styled.div` - overflow-y: scroll; - padding: 16px 16px 0; + overflow-y: auto; ` const FlexRow = styled.div` display: flex; gap: ${grid(1)}; - justify-content: space-between; + justify-content: flex-end; ` const FlexRowWithSmallGapAbove = styled(FlexRow)` - margin-top: 10px; + align-items: end; + justify-content: flex-start; + margin-bottom: ${grid(1)}; ` const RoundIconButtonWrapper = styled(RoundIconButton).attrs({ @@ -349,7 +354,11 @@ const Manuscripts = props => { : t('manuscriptsPage.Refresh')} )} + + ) + const searchAndChatControls = ( + applyQueryParams({ @@ -399,115 +408,115 @@ const Manuscripts = props => { ] return ( - - - - - - - {t( - archived - ? 'manuscriptsPage.archivedManuscripts' - : 'manuscriptsPage.Manuscripts', - )} - - {topRightControls} - - - - - - selectedNewManuscripts.includes(manuscript.id), + + + + + + {topRightControls} + + + + + selectedNewManuscripts.includes(manuscript.id), + )} + label={t('manuscriptsPage.Select All')} + onChange={toggleAllNewManuscriptsCheck} + /> + + + + + + {t('manuscriptsPage.takeAction')} + + + + + {t( + archived + ? 'manuscriptsPage.viewUnarchived' + : 'manuscriptsPage.viewArchived', )} - label={t('manuscriptsPage.Select All')} - onChange={toggleAllNewManuscriptsCheck} - /> - - + {searchAndChatControls} + + +
+ + - - - - {t('manuscriptsPage.takeAction')} - - - - - {t( - archived - ? 'manuscriptsPage.viewUnarchived' - : 'manuscriptsPage.viewArchived', - )} - - - -
- - + + applyQueryParams({ [URI_PAGENUM_PARAM]: newPage }) + } + totalCount={totalCount} /> - - - applyQueryParams({ [URI_PAGENUM_PARAM]: newPage }) - } - totalCount={totalCount} +
+ + + {/* Group Manager Discussion, Video Chat, Hide Chat, Chat component */} + {isAdminChatOpen && !hideManuscriptsChat && ( + -
-
- - {/* Group Manager Discussion, Video Chat, Hide Chat, Chat component */} - {isAdminChatOpen && !hideManuscriptsChat && ( - - )} -
- setIsOpenBulkArchiveModal(false)} - confirmationAction={doBulkArchive} - isOpen={isOpenBulkArchiveModal} - message={t('manuscriptsPage.confirmArchive')} - /> - setIsOpenBulkUnarchiveModal(false)} - confirmationAction={doBulkUnarchive} - isOpen={isOpenBulkUnarchiveModal} - message={t('manuscriptsPage.confirmUnarchive')} - /> -
+ )} + + setIsOpenBulkArchiveModal(false)} + confirmationAction={doBulkArchive} + isOpen={isOpenBulkArchiveModal} + message={t('manuscriptsPage.confirmArchive')} + /> + setIsOpenBulkUnarchiveModal(false)} + confirmationAction={doBulkUnarchive} + isOpen={isOpenBulkUnarchiveModal} + message={t('manuscriptsPage.confirmUnarchive')} + /> + + ) } diff --git a/packages/client/app/components/component-manuscripts/src/SearchControl.jsx b/packages/client/app/components/component-manuscripts/src/SearchControl.jsx index 08721f233..717b737d3 100644 --- a/packages/client/app/components/component-manuscripts/src/SearchControl.jsx +++ b/packages/client/app/components/component-manuscripts/src/SearchControl.jsx @@ -36,7 +36,7 @@ const InlineTextField = styled.input` &:focus { border-color: ${th('color.brand1.base')}; - box-shadow: ${th('boxShadow')}; + box-shadow: ${th('boxShadow200')}; } ` diff --git a/packages/client/app/components/component-menu/components/NavItem.jsx b/packages/client/app/components/component-menu/components/NavItem.jsx deleted file mode 100644 index 3f12812a0..000000000 --- a/packages/client/app/components/component-menu/components/NavItem.jsx +++ /dev/null @@ -1,70 +0,0 @@ -/* stylelint-disable declaration-no-important */ - -/* eslint-disable react/prop-types */ - -import { useLocation } from 'react-router-dom' -import PropTypes from 'prop-types' -import { Icon } from '../../pubsweet' -import { AlertIndicator, LinkLabel, StyledIcon, StyledLink } from '../styles' - -const MenuItem = ({ alert, icon, menu, name, open }) => ( - - {icon && {icon}} - {name} - {alert && } - {menu && chevron-{open ? 'up' : 'down'}} - -) - -const NavItem = props => { - const { - className = '', - link, - onClick, - alert, - icon, - menu, - menuIsMinimal, - name, - open, - depth, - } = props - - const itemProps = { alert, icon, menu, name, open } - const location = useLocation() - - return link ? ( - - - - ) : ( - - - - ) -} - -NavItem.propTypes = { - className: PropTypes.string, - link: PropTypes.string, - name: PropTypes.string.isRequired, - icon: PropTypes.string, -} - -export default NavItem diff --git a/packages/client/app/components/component-menu/components/SubMenu.jsx b/packages/client/app/components/component-menu/components/SubMenu.jsx deleted file mode 100644 index b836cc039..000000000 --- a/packages/client/app/components/component-menu/components/SubMenu.jsx +++ /dev/null @@ -1,64 +0,0 @@ -/* eslint-disable react/prop-types */ - -import { useState, memo } from 'react' -import { useLocation } from 'react-router-dom' -import { - SubMenuContainer, - SubMenuFirstLevelContainer, - menuItemContainsCurrentPage, -} from '../styles' -import NavItem from './NavItem' - -const SubMenu = ({ - depth = 0, - menuIsMinimal, - setMenuIsMinimal, - ...navInfo -}) => { - const location = useLocation() - - const [open, setOpen] = useState( - menuItemContainsCurrentPage(navInfo, location), - ) - - const handleOpen = () => { - setOpen(!open || menuIsMinimal) - setMenuIsMinimal(false) - } - - return ( - - - - {navInfo.links.map(subNavInfo => - subNavInfo.menu ? ( - - ) : ( - - ), - )} - - - ) -} - -export default memo(SubMenu) diff --git a/packages/client/app/components/component-menu/components/UserComponent.jsx b/packages/client/app/components/component-menu/components/UserComponent.jsx deleted file mode 100644 index d41e45500..000000000 --- a/packages/client/app/components/component-menu/components/UserComponent.jsx +++ /dev/null @@ -1,55 +0,0 @@ -/* eslint-disable react/prop-types */ - -/* eslint-disable new-cap */ - -import PropTypes from 'prop-types' -import { UserAvatar } from '../../component-avatar/src' -import { - FormattedGlobalAndGroupRoles, - RolesLabel, - UserInfo, - UserItem, - UserMenuContainer, - UserName, -} from '../styles' -// import NavItem from './NavItem' - -const UserComponent = ({ - user, - // loginLink, - profileLink, - t, - expanded, -}) => { - return ( - - {user && ( - - - - {user.username} - {!user.isOnline && Offline} - ({FormattedGlobalAndGroupRoles(user, t)}) - - - )} - {/* {!user && } */} - - ) -} - -UserComponent.propTypes = { - user: PropTypes.oneOfType([PropTypes.object]), - loginLink: PropTypes.string.isRequired, - profileLink: PropTypes.string.isRequired, -} - -export default UserComponent diff --git a/packages/client/app/components/component-menu/components/index.js b/packages/client/app/components/component-menu/components/index.js deleted file mode 100644 index 86db63700..000000000 --- a/packages/client/app/components/component-menu/components/index.js +++ /dev/null @@ -1,3 +0,0 @@ -export { default as SubMenu } from './SubMenu' -export { default as UserComponent } from './UserComponent' -export { default as NavItem } from './NavItem' diff --git a/packages/client/app/components/component-menu/index.js b/packages/client/app/components/component-menu/index.js deleted file mode 100644 index 22424051e..000000000 --- a/packages/client/app/components/component-menu/index.js +++ /dev/null @@ -1,2 +0,0 @@ -export * from './components' -export * from './styles' diff --git a/packages/client/app/components/component-menu/styles/PinButton.jsx b/packages/client/app/components/component-menu/styles/PinButton.jsx deleted file mode 100644 index 22f66f078..000000000 --- a/packages/client/app/components/component-menu/styles/PinButton.jsx +++ /dev/null @@ -1,14 +0,0 @@ -/* eslint-disable react/prop-types */ - -import { Sidebar } from 'react-feather' - -const PinButton = props => { - return ( - - ) -} - -export default PinButton diff --git a/packages/client/app/components/component-menu/styles/helpers.js b/packages/client/app/components/component-menu/styles/helpers.js deleted file mode 100644 index cf15f5d6a..000000000 --- a/packages/client/app/components/component-menu/styles/helpers.js +++ /dev/null @@ -1,27 +0,0 @@ -/* eslint-disable react/prop-types */ - -import { convertCamelCaseToTitleCase } from '../../../shared/textUtils' - -export const menuItemContainsCurrentPage = (item, location) => - item.link === location.pathname || - item.links?.some(subItem => menuItemContainsCurrentPage(subItem, location)) - -export const FormattedGlobalAndGroupRoles = ( - { globalRoles, groupRoles }, - t, -) => { - const allRoles = globalRoles.concat(groupRoles) - - let unCamelCasedRoles = - allRoles.includes('groupManager') || allRoles.includes('admin') - ? allRoles - .filter(role => role !== 'user') - .map(role => convertCamelCaseToTitleCase(role)) - : allRoles.map(role => convertCamelCaseToTitleCase(role)) - - if (!unCamelCasedRoles.length) return null - unCamelCasedRoles = unCamelCasedRoles.map(elem => { - return t(`common.roles.${elem}`) - }) - return unCamelCasedRoles.join(', ') -} diff --git a/packages/client/app/components/component-menu/styles/index.js b/packages/client/app/components/component-menu/styles/index.js deleted file mode 100644 index f529ef3d0..000000000 --- a/packages/client/app/components/component-menu/styles/index.js +++ /dev/null @@ -1,3 +0,0 @@ -export * from './menuStyleds' -export * from './styleGlobals' -export * from './helpers' diff --git a/packages/client/app/components/component-menu/styles/menuStyleds.jsx b/packages/client/app/components/component-menu/styles/menuStyleds.jsx deleted file mode 100644 index ffaca5561..000000000 --- a/packages/client/app/components/component-menu/styles/menuStyleds.jsx +++ /dev/null @@ -1,355 +0,0 @@ -/* stylelint-disable declaration-no-important, string-quotes */ -import styled from 'styled-components' -import { Link } from 'react-router-dom' -import { th, grid } from '@coko/client' - -import { Icon } from '../../pubsweet' -import { menuStyles } from './styleGlobals' -import PinButton from './PinButton' - -// #region Menu - -export const MainNavWrapper = styled.div.attrs({ - 'data-testid': 'main-nav-wrapper', -})` - /* stylelint-disable declaration-no-important */ - - align-items: center; - background: linear-gradient( - 134deg, - ${th('color.brand1.base')}, - ${th('color.brand1.tint25')} - ); - display: flex; - flex-direction: column; - height: 100%; - justify-content: center; - overflow: hidden; - padding: 3.2px 4.8px; - transition: all var(--transition-time); - width: 100%; -` - -export const ScrollWrapper = styled.div` - align-items: center; - display: flex; - flex-direction: column; - height: 100%; - overflow: hidden auto; - position: relative; - scrollbar-color: ${th('color.brand1.tint50')} #fff0; - scrollbar-width: thin; - transition: all var(transition-time); - width: 100%; - - ::-webkit-scrollbar { - height: 10px; - width: 5px; - } - - ::-webkit-scrollbar-thumb { - background: ${th('color.brand1.tint50')}; - border-radius: 0.3rem; - } - - ::-webkit-scrollbar-track { - background: #0000; - } -` - -export const NavLinks = styled.div` - align-items: flex-start; - display: flex; - flex-direction: column; - padding: 0; - transition: padding var(--transition-time); - width: 100%; -` -// #endregion Menu - -// #region PinNav -export const SectionNavLayoutSettings = styled.div` - background: ${th('color.brand1.shade10')}; - border: none; - border-bottom: 1px solid #fff2; - height: ${p => (p.$pinned ? '0' : '22px')}; - margin-bottom: ${p => (p.$pinned ? '0' : '-14px')}; - position: relative; - transition: - margin ease 0.5s, - height ease 0.5s, - background-color ease 0.2s; - width: 100%; - - &:hover { - background-color: ${th('color.brand1.shade15')}; - - * { - color: ${th('color.brand1.tint70')}; - } - } -` - -export const StyledPinButton = styled(PinButton)` - background: ${p => (p.$pinned ? '#fff4' : 'transparent')}; - border-radius: 4px; - color: ${p => - p.$pinned ? p.theme.color.brand1.tint90 : p.theme.color.brand1.tint25}; - max-width: ${p => (p.$menuIsMinimal ? '0' : '100%')}; - opacity: ${p => (p.$menuIsMinimal ? '0' : '1')}; - overflow: hidden; - padding: 1px 2px 2px; - position: absolute; - right: 4px; - top: 1px; - transition: opacity ease 0.2s; - - svg { - aspect-ratio: 1 / 1; - fill: #fff0; - height: 15px; - vertical-align: middle; - width: 15px; - } -` -// #endregion PinNav - -// #region Link -export const StyledLink = styled(Link)` - background-color: ${p => (p.$active ? p.theme.color.brand1.tint70 : 'unset')}; - border-radius: 10px; - color: ${p => - p.$active ? p.theme.color.text : p.theme.color.textReverse} !important; - cursor: pointer; - display: flex; - font-size: ${th('fontSizeBase')} !important; - height: ${grid(5)}; - justify-content: space-between; - line-height: ${grid(3)}; - margin-bottom: 4.8px; - padding: 0 ${grid(1)}; - position: relative; - text-decoration: none !important; - transition: - max-width var(--transition-time), - background-color var(--transition-link-colors), - color var(--transition-link-colors); - user-select: none; - width: calc(100% - ${p => (p.$depth || 0) * 1.6 * 10}px); - - & > span { - align-items: center; - display: flex; - - line-height: 1; - overflow: ${p => (p.$submenu ? 'hidden' : 'unset')}; - width: 100%; - } - - svg { - stroke: ${p => - p.$active ? p.theme.color.text : p.theme.color.textReverse}; - transition: stroke var(--transition-link-colors); - width: 1em; - } - - svg#coar { - color: ${p => (p.$active ? p.theme.color.text : p.theme.color.textReverse)}; - transition: color var(--transition-time); - } - - &:hover { - background-color: ${th('color.brand1.tint70')}; - color: ${th('color.text')} !important; - stroke: ${th('color.text')}; - - svg { - stroke: ${th('color.text')}; - } - - svg#coar { - color: ${th('color.text')}; - } - } -` - -export const NonLink = styled.div` - & > span { - justify-content: center; - overflow: hidden; - } -` - -export const LinkLabel = styled.span` - margin-left: 0; - opacity: 0; - overflow: hidden; - padding-top: 2px; - transition: - margin var(--transition-time), - opacity 0.2s; - white-space: nowrap; - width: 100%; -` - -export const StyledIcon = styled(Icon)`` - -export const AlertIndicator = styled.div` - background: ${th('color.error.base')}; - border-radius: 50%; - display: flex; - height: 10px; - margin: 0; - position: absolute; - right: 4.8px; - transition: top var(--transition-time); - width: 10px; -` -// #endregion Link - -// #region SubMenu -export const SubMenuFirstLevelContainer = styled.span` - display: flex; - flex-direction: column; - justify-items: ${p => (p.$depth > 0 ? 'end' : '')}; - overflow: hidden; - width: 100%; -` - -export const SubMenuContainer = styled(NavLinks)` - align-items: end; - height: fit-content; - max-height: 0; - opacity: 0; - overflow: hidden; - padding: 0; - position: relative; - transition: all var(--transition-time); - width: 100%; -` -// #endregion SubMenu - -// #region UserNav -export const RolesLabel = styled.div` - color: ${th('color.brand1.tint50')}; - font-size: ${th('fontSizeBaseSmaller')}; - font-weight: normal; - line-height: 1; - white-space: nowrap; -` - -export const UserItem = styled(Link).attrs({ - 'data-testid': 'user-item', -})` - align-items: end; - border-bottom: 1px solid #fff2; - color: ${th('color.textReverse')}; - display: flex; - gap: ${p => (p.$expanded ? '16px' : '0')}; - overflow: hidden; - padding: ${p => (p.$expanded ? '11.2px 16px 16px 8px' : '8px 0 8px 2.4px')}; - text-decoration: none !important; - transition: all var(--transition-time); - width: 100%; - - &:hover { - color: ${th('color.textReverse')} !important; - } -` - -export const UserInfo = styled.div` - display: flex; - flex-direction: column; - font-size: ${th('fontSizeBase')} !important; - justify-content: center; - opacity: ${p => (p.$expanded ? '1' : '0')}; - overflow: hidden; - transition: all var(--transition-time); - width: ${p => (p.$expanded ? '100%' : '0')}; -` - -export const UserName = styled.div` - max-width: 30ch; - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; -` - -export const UserMenuContainer = styled.div` - display: flex; - gap: 24px; - justify-content: flex-start; - margin-bottom: 4.8px; - margin-top: -5px; - overflow: visible; - width: 100%; - - & img { - outline: 4px solid ${th('color.brand1.base')}; - } -` -// #endregion UserNav - -// Here all related to expand/collapse -// Handling it based on aria-expanded instead of state to avoid re-renders -export const Root = styled.nav` - --transition-time: ${menuStyles.transition.time} ease; - --transition-link-colors: 0.3s ease; - - align-items: flex-start; - background: ${th('color.brand1.base')}; - display: flex; - flex-direction: column; - font-family: ${th('fontInterface')}, sans-serif !important; - max-height: 100vh; - max-width: 100%; - min-width: 250px; - transition: all var(--transition-time); - width: fit-content; - - &[aria-expanded='false'] { - max-width: 50px; - min-width: 0; - - ${LinkLabel} { - margin-left: 0; - opacity: 0; - } - - ${AlertIndicator} { - top: 3.2px; - } - } - - &[aria-expanded='true'] { - ${LinkLabel} { - margin-left: 6px; - opacity: 1; - } - - ${NavLinks} { - padding: 4.8px; - } - - ${SubMenuFirstLevelContainer} { - display: grid; - } - - ${SubMenuContainer} { - &[aria-expanded='true'] { - max-height: 100%; - opacity: 1; - padding: 0; - } - - &[aria-expanded='false'] { - max-height: 0; - padding: 0; - } - } - - ${AlertIndicator} { - top: 4.8px; - } - } -` diff --git a/packages/client/app/components/component-menu/styles/styleGlobals.js b/packages/client/app/components/component-menu/styles/styleGlobals.js deleted file mode 100644 index 70cb35b8a..000000000 --- a/packages/client/app/components/component-menu/styles/styleGlobals.js +++ /dev/null @@ -1,5 +0,0 @@ -export const menuStyles = { - transition: { - time: '0.2s', - }, -} diff --git a/packages/client/app/components/component-notification-event/components/CustomInputs.jsx b/packages/client/app/components/component-notification-event/components/CustomInputs.jsx index 5951de83b..95a26eda3 100644 --- a/packages/client/app/components/component-notification-event/components/CustomInputs.jsx +++ b/packages/client/app/components/component-notification-event/components/CustomInputs.jsx @@ -39,7 +39,7 @@ const styles = theme => ({ : 'inset 0px 0px 4px rgb(0 0 0 / 7%)' : state.isFocused ? `0 0 0 1px ${theme.color.brand1.base}` - : theme.boxShadow, + : theme.boxShadow200, borderRadius: theme.borderRadius, '&:hover': { diff --git a/packages/client/app/components/component-production/src/components/Production.jsx b/packages/client/app/components/component-production/src/components/Production.jsx index 396b3cc0b..68b052142 100644 --- a/packages/client/app/components/component-production/src/components/Production.jsx +++ b/packages/client/app/components/component-production/src/components/Production.jsx @@ -10,17 +10,17 @@ import CodeMirror from '@uiw/react-codemirror' import { html } from '@codemirror/lang-html' import { css } from '@codemirror/lang-css' +import Page from '../../../../ui/shared/Page' +import { FlexRow } from '../../../../globals' import { ConfigContext } from '../../../config/src' import ProductionWaxEditor from '../../../wax-collab/src/ProductionWaxEditor' import { DownloadDropdown } from './DownloadDropdown' import { - Heading, - HeadingWithAction, - Tabs, - Manuscript, ErrorBoundary, - SectionContent, + HiddenTabsContainer, Spinner, + Tab, + TabContainer, VersionSwitcher, } from '../../../shared' import { Info } from './styles' @@ -41,31 +41,38 @@ const PreviousFeedBackSection = styled.div` margin-bottom: calc(${th('gridUnit')} * 3); ` -const FlexRow = styled.div` +const TabsRow = styled.div` display: flex; - gap: ${grid(1)}; - justify-content: space-between; + margin-top: ${grid(1)}; ` -const FormTemplateStyled = styled.div` - max-height: calc(100vh - 150px); +const TabRow = styled(FlexRow)` + width: 100%; ` -const StyledManuscript = styled(Manuscript)` - display: flex; - flex-direction: column; - height: 100vh; - overflow-y: auto; - width: 100%; +const RightControls = styled(ControlsContainer)` + margin-left: auto; + margin-bottom: ${grid(1)}; +` + +const FormTemplateStyled = styled.div` + max-height: calc(100vh - 150px); ` const ScrollableTabContent = styled.section` background-color: ${th('color.backgroundA')}; border-radius: ${th('borderRadius')}; - box-shadow: ${({ theme }) => theme.boxShadow.shades[200]}; - height: calc(100vh - 108px); + box-shadow: ${({ theme }) => theme.boxShadow200}; + height: calc(100vh - 180px); overflow: auto; - width: calc(100vw - 232px); + + .cm-theme-light { + height: 100%; + } + + .cm-editor { + height: 100%; + } ` const LabeledTab = styled.div` @@ -109,6 +116,8 @@ const Production = ({ authorList, addNewVersion, }) => { + const [activeKey, setActiveKey] = useState('editor') + const versions = gatherManuscriptVersions(unparsedManuscript) const showFeedbackTab = versions.some( @@ -209,9 +218,9 @@ const Production = ({ const editorSection = { content: ( - <> + {showContent ? ( - + <> {manuscript ? ( )} - + ) : ( - - {t('productionPage.No supported view of the file')} - + {t('productionPage.No supported view of the file')} )} - + ), key: 'editor', label: `${t('productionPage.Editor')} ${ @@ -249,16 +256,14 @@ const Production = ({ const feedbackSection = { content: ( - <> + {isAuthorProofingVersion && ['assigned', 'inProgress'].includes(manuscript.status) && ( - - - + )} @@ -270,7 +275,7 @@ const Production = ({ ))} - + ), key: 'feedback', label: t('productionPage.Feedback'), @@ -340,13 +345,15 @@ const Production = ({ const cssAiAssistant = { content: ( - - JSON.parse(manuscript.meta.comments) || []} - /> - + + + JSON.parse(manuscript.meta.comments) || []} + /> + + ), hideOnly: true, key: 'css-ai-assistant', @@ -359,15 +366,17 @@ const Production = ({ key: 'versioning', label: 'History', content: ( - JSON.parse(manuscript.meta.comments) || []} - /> + + JSON.parse(manuscript.meta.comments) || []} + /> + ), } @@ -395,15 +404,25 @@ const Production = ({ } return ( - - - - - {isAuthorProofingVersion - ? t('productionPage.AuthorProofing') - : t('productionPage.Production')} - - + + + + + {tabSections.map(({ key, label }) => ( + setActiveKey(key)}> + +
{label}
+
+
+ ))} +
+ -
-
-
+ + + - + {tabSections.map(section => + section.key === activeKey ? ( +
{section.content}
+ ) : null, + )}
-
+ ) } diff --git a/packages/client/app/components/component-production/src/components/ProductionPage.jsx b/packages/client/app/components/component-production/src/components/ProductionPage.jsx index 67650c751..cf090a543 100644 --- a/packages/client/app/components/component-production/src/components/ProductionPage.jsx +++ b/packages/client/app/components/component-production/src/components/ProductionPage.jsx @@ -279,7 +279,7 @@ const ProductionPage = () => { isOpen={modalKey !== undefined} /> )} -
+
{makingPdf ? ( +

{shownVersion + 1 < versionList.length ? ( @@ -365,7 +359,7 @@ const Versioning = ({ - +

) } diff --git a/packages/client/app/components/component-production/src/components/uploadManager/UploadAsset.jsx b/packages/client/app/components/component-production/src/components/uploadManager/UploadAsset.jsx index b81d4cf27..97ce0936d 100644 --- a/packages/client/app/components/component-production/src/components/uploadManager/UploadAsset.jsx +++ b/packages/client/app/components/component-production/src/components/uploadManager/UploadAsset.jsx @@ -12,24 +12,23 @@ import { convertTimestampToRelativeDateString } from '../../../../../shared/date import { Placeholder } from '../../../../component-dashboard/src/style' import { ConfirmationModal } from '../../../../component-modal/src/ConfirmationModal' import FileRow from '../FileRow' -import { - Container, - SectionContent, - SectionRow, - ActionButton, -} from '../../../../shared' +import { SectionContent, SectionRow, ActionButton } from '../../../../shared' import { HeadingCell } from '../styles' import UploadComponent from './UploadComponent' import { TagDropdown } from './TagDropDown' import { UPDATE_FILE_TAGS } from '../../../../../queries' -const UploadAssetContainer = styled(Container)` +const NoShadowSectionContent = styled(SectionContent)` + box-shadow: none; +` + +const UploadAssetContainer = styled.div` display: flex; flex-direction: column; height: 100%; justify-content: space-between; overflow: auto; - padding: calc(8px * 2) calc(8px * 3); + width: 100%; ` export const FileTableStyled = styled.div` @@ -294,7 +293,7 @@ const UploadAsset = ({ return ( - + Css Upload: @@ -340,7 +339,7 @@ const UploadAsset = ({ )} - + setFileBeingDeletedId(null)} confirmationAction={onDelete(fileBeingDeletedId)} diff --git a/packages/client/app/components/component-profile/src/Profile.jsx b/packages/client/app/components/component-profile/src/Profile.jsx index 54ef14e22..48059fad1 100644 --- a/packages/client/app/components/component-profile/src/Profile.jsx +++ b/packages/client/app/components/component-profile/src/Profile.jsx @@ -15,13 +15,8 @@ import { Button, Checkbox } from '../../pubsweet' import Modal from '../../component-modal/src/ConfirmationModal' import { convertCamelCaseToTitleCase } from '../../../shared/textUtils' -import { - Container, - SectionContent, - HeadingWithAction, - SectionRow, - Heading, -} from '../../shared' +import { SectionContent, SectionRow } from '../../shared' +import Page from '../../../ui/shared/Page' import ChangeUsername from './ChangeUsername' import { BigProfileImage } from './ProfileImage' import ChangeEmail from './ChangeEmail' @@ -31,14 +26,15 @@ import { getLanguages } from '../../../i18n' const VersionText = styled.div` color: #757575; - display: flex; - justify-content: flex-end; + position: fixed; + bottom: ${grid(2)}; + right: ${grid(3)}; ` -const ProfileContainer = styled(Container)` +const RolesRow = styled.div` display: flex; - flex-direction: column; - justify-content: space-between; + align-items: end; + margin-bottom: ${grid(1)}; ` const StyledCheckbox = styled(Checkbox)` @@ -194,104 +190,102 @@ const Profile = ({ user.profilePicture || `${serverUrl}/profiles/default_avatar.svg` return ( - + -
- - - {isCurrentUsersOwnProfile - ? t('profilePage.Your profile') - : t('profilePage.Profile: ') + user.username} - - - {isCurrentUsersOwnProfile && ( - - )} - - + - - - -
- {isCurrentUsersOwnProfile ? ( - - ) : ( - - )} -
-
- - - {' '} -
{user.defaultIdentity.identifier}
-
- - - -
- {canEditProfile ? ( - - ) : ( -
{user.username}
- )} -
-
- - - -
- {canEditProfile ? ( - - ) : ( -
{user.email}
- )} -
-
- - - -
- {canEditProfile ? ( - - ) : ( -
- { - languages.find(elem => elem.value === i18next.language) - .label - } -
- )} -
-
-
- - - - -
+ {isCurrentUsersOwnProfile && ( + + )} + + + + +
+ {isCurrentUsersOwnProfile ? ( + + ) : ( + + )} +
+
+ + + {' '} +
{user.defaultIdentity.identifier}
+
+ + + +
+ {canEditProfile ? ( + + ) : ( +
{user.username}
+ )} +
+
+ + + +
+ {canEditProfile ? ( + + ) : ( +
{user.email}
+ )} +
+
+ + + +
+ {canEditProfile ? ( + + ) : ( +
+ {languages.find(elem => elem.value === i18next.language).label} +
+ )} +
+
+
+ + + + {kotahiVersion} -
+ ) } diff --git a/packages/client/app/components/component-profile/src/ProfilePage.jsx b/packages/client/app/components/component-profile/src/ProfilePage.jsx index 52e43ca0e..2348847e6 100644 --- a/packages/client/app/components/component-profile/src/ProfilePage.jsx +++ b/packages/client/app/components/component-profile/src/ProfilePage.jsx @@ -1,8 +1,7 @@ /* eslint-disable promise/catch-or-return */ /* eslint-disable promise/always-return */ -import { useContext, useState } from 'react' -import { Navigate, useParams } from 'react-router-dom' +import { useNavigate, useParams } from 'react-router-dom' import { useQuery, useMutation } from '@apollo/client/react' import { serverUrl } from '@coko/client' @@ -11,8 +10,8 @@ import Profile from './Profile' import { Spinner, CommsErrorBanner } from '../../shared' import packageJson from '../../../../package.json' -import { ConfigContext } from '../../config/src' import { useCurrentUser } from '../../../pages/hooks/useCurrentUser' +import { useLogout } from '../../../pages/hooks/useLogout' import { GET_USER, @@ -26,16 +25,15 @@ import { const { version: kotahiVersion } = packageJson const ProfilePage = () => { - const { id } = useParams() + const { id, groupName } = useParams() const currentUser = useCurrentUser() - const { urlFrag } = useContext(ConfigContext) - const [didLogout, setDidLogout] = useState(false) + const navigate = useNavigate() + const logout = useLogout() const { loading, error, data, - client, refetch: refetchUser, } = useQuery(GET_USER, { variables: { id: id || currentUser?.id }, @@ -73,16 +71,9 @@ const ProfilePage = () => { if (loading) return if (error) return - if (didLogout) { - return - } - - const localStorage = window.localStorage || undefined - const logoutUser = () => { - localStorage.removeItem('token') - client.clearStore() - setDidLogout(true) + logout() + navigate(`/${groupName}/login`, { replace: true }) } // This is a bridge between the fetch results and the Apollo cache/state diff --git a/packages/client/app/components/component-published-artifact/components/ArticleArtifactPage.jsx b/packages/client/app/components/component-published-artifact/components/ArticleArtifactPage.jsx index bb9a6a2b3..40827f6be 100644 --- a/packages/client/app/components/component-published-artifact/components/ArticleArtifactPage.jsx +++ b/packages/client/app/components/component-published-artifact/components/ArticleArtifactPage.jsx @@ -3,7 +3,7 @@ import { useParams } from 'react-router-dom' import PropTypes from 'prop-types' import { sanitize } from 'isomorphic-dompurify' import styled from 'styled-components' -import { th } from '@coko/client' +import { grid, th } from '@coko/client' import { Spinner, CommsErrorBanner, PlainOrRichText } from '../../shared' import { PUBLISHED_MANUSCRIPT_AND_FORMS } from '../../../queries' @@ -18,16 +18,15 @@ const Container = styled.div` background: ${th('color.gray97')}; border: 1px solid ${th('color.brand1.shade25')}; border-radius: ${th('borderRadius')}; - margin: ${th('spacing.g')} auto; + margin: ${grid(3.75)} auto; max-width: 1000px; - padding: ${th('spacing.h')} ${th('spacing.i')} ${th('spacing.i')} - ${th('spacing.i')}; + padding: ${grid(5.625)} ${grid(7.5)} ${grid(7.5)} ${grid(7.5)}; width: 90%; & > h1 { color: ${th('color.brand1.shade25')}; font-size: 180%; - margin: ${th('spacing.e')} 0 ${th('spacing.f')} 0; + margin: ${grid(0.9375)} 0 ${grid(1.875)} 0; } ` diff --git a/packages/client/app/components/component-reporting/src/Report.jsx b/packages/client/app/components/component-reporting/src/Report.jsx index 5027a07df..4c4b07759 100644 --- a/packages/client/app/components/component-reporting/src/Report.jsx +++ b/packages/client/app/components/component-reporting/src/Report.jsx @@ -4,37 +4,23 @@ import PropTypes from 'prop-types' import styled, { useTheme } from 'styled-components' import { forEach, map } from 'lodash' -import { th, grid } from '@coko/client' +import { th } from '@coko/client' import { Trans, useTranslation } from 'react-i18next' import i18next from 'i18next' import { Icon } from '../../pubsweet' +import Page from '../../../ui/shared/Page' import DateRangePicker from './DateRangePicker' import SummaryReport from './SummaryReport' import Table from './Table' import SparkBar from './SparkBar' import Tooltip from './Tooltip' -const Page = styled.div` - flex: 1 1 100%; - height: 100vh; - overflow-y: auto; - padding: 0 ${grid(2)} ${grid(3)} ${grid(2)}; -` - const Select = styled.select` border: 1px solid ${th('colorBorder')}; padding: 5px; ` -const Heading = styled.div` - color: ${th('color.brand1.base')}; - font-family: ${th('fontReading')}; - font-size: ${th('fontSizeHeading3')}; - line-height: ${th('lineHeightHeading3')}; - margin: ${th('gridUnit')} 0; -` - const MinorNote = styled.span` color: ${th('color.gray50')}; font-size: 80%; @@ -43,7 +29,7 @@ const MinorNote = styled.span` export const Content = styled.div` background-color: ${th('color.backgroundC')}; border-radius: ${th('borderRadius')}; - box-shadow: ${th('boxShadow')}; + box-shadow: ${th('boxShadow200')}; ` const SelectionLine = styled.div` @@ -413,8 +399,7 @@ const Report = ({ }) => { const { t } = useTranslation() return ( - - {t('reportsPage.Reports')} + {t('reportsPage.Show')}{' '}