From b438cbdebce0562b007afd5c9edaa4fa10aa3fcb Mon Sep 17 00:00:00 2001 From: Florian Scholdei Date: Wed, 25 Mar 2020 15:35:46 +0100 Subject: [PATCH] Fix behavior of secondary navigation and content (with different display sizes) --- .../layout/CustomQueryFlexWrappedColumns.tsx | 43 ++++++++++++++ .../src/layout/PrimaryContentColumn.tsx | 56 ++++++++++++++++++ .../src/layout/SecondaryNavigationColumn.tsx | 59 +++++++++++++++++++ scm-ui/ui-components/src/layout/index.ts | 4 ++ .../src/navigation/SecondaryNavigation.tsx | 5 +- .../ui-webapp/src/admin/containers/Admin.tsx | 15 +++-- scm-ui/ui-webapp/src/containers/Profile.tsx | 15 +++-- .../src/groups/containers/SingleGroup.tsx | 15 +++-- .../src/repos/containers/RepositoryRoot.tsx | 15 +++-- .../src/users/containers/SingleUser.tsx | 19 +++--- 10 files changed, 211 insertions(+), 35 deletions(-) create mode 100644 scm-ui/ui-components/src/layout/CustomQueryFlexWrappedColumns.tsx create mode 100644 scm-ui/ui-components/src/layout/PrimaryContentColumn.tsx create mode 100644 scm-ui/ui-components/src/layout/SecondaryNavigationColumn.tsx diff --git a/scm-ui/ui-components/src/layout/CustomQueryFlexWrappedColumns.tsx b/scm-ui/ui-components/src/layout/CustomQueryFlexWrappedColumns.tsx new file mode 100644 index 0000000000..7c9b42d743 --- /dev/null +++ b/scm-ui/ui-components/src/layout/CustomQueryFlexWrappedColumns.tsx @@ -0,0 +1,43 @@ +/* + * MIT License + * + * Copyright (c) 2020-present Cloudogu GmbH and Contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +import React, { ReactNode } from "react"; +import styled from "styled-components"; + +type Props = { + children?: ReactNode; +}; + +const FlexWrapped = styled.div` + /* Do not wrap before using the media query, + otherwise long content will always break the navigation. */ + @media (max-width: 785px) { + flex-wrap: wrap; + } +`; + +export default class CustomQueryFlexWrappedColumns extends React.Component { + render() { + return {this.props.children}; + } +} diff --git a/scm-ui/ui-components/src/layout/PrimaryContentColumn.tsx b/scm-ui/ui-components/src/layout/PrimaryContentColumn.tsx new file mode 100644 index 0000000000..76427dc4e0 --- /dev/null +++ b/scm-ui/ui-components/src/layout/PrimaryContentColumn.tsx @@ -0,0 +1,56 @@ +/* + * MIT License + * + * Copyright (c) 2020-present Cloudogu GmbH and Contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +import React, { ReactNode } from "react"; +import styled from "styled-components"; + +type Props = { + children?: ReactNode; + collapsed: boolean; +}; + +const PrimaryColumn = styled.div<{ collapsed: boolean }>` + /* This is the counterpart to the specific column in SecondaryNavigationColumn. */ + flex: none; + width: ${(props: { collapsed: boolean }) => (props.collapsed ? "89.7%" : "75%")}; + /* Render this column to full size if column construct breaks (page size too small). */ + @media (max-width: 785px) { + width: 100%; + } +`; + +export default class PrimaryContentColumn extends React.Component { + static defaultProps = { + collapsed: false + }; + + render() { + const { children, collapsed } = this.props; + + return ( + + {children} + + ); + } +} diff --git a/scm-ui/ui-components/src/layout/SecondaryNavigationColumn.tsx b/scm-ui/ui-components/src/layout/SecondaryNavigationColumn.tsx new file mode 100644 index 0000000000..aae722bbe3 --- /dev/null +++ b/scm-ui/ui-components/src/layout/SecondaryNavigationColumn.tsx @@ -0,0 +1,59 @@ +/* + * MIT License + * + * Copyright (c) 2020-present Cloudogu GmbH and Contributors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ +import React, { ReactNode } from "react"; +import styled from "styled-components"; + +type Props = { + children?: ReactNode; + collapsed: boolean; +}; + +const SecondaryColumn = styled.div<{ collapsed: boolean }>` + /* In Bulma there is unfortunately no intermediate step between .is-1 and .is-2, hence the size. + Navigation size should be as constant as possible. */ + flex: none; + width: ${props => (props.collapsed ? "5.5rem" : "20.5rem")}; + max-width: ${(props: { collapsed: boolean }) => (props.collapsed ? "11.3%" : "25%")}; + /* Render this column to full size if column construct breaks (page size too small). */ + @media (max-width: 785px) { + width: 100%; + max-width: 100%; + } +`; + +export default class SecondaryNavigationColumn extends React.Component { + static defaultProps = { + collapsed: false + }; + + render() { + const { children, collapsed } = this.props; + + return ( + + {children} + + ); + } +} diff --git a/scm-ui/ui-components/src/layout/index.ts b/scm-ui/ui-components/src/layout/index.ts index abba371ea3..2c9f7fba72 100644 --- a/scm-ui/ui-components/src/layout/index.ts +++ b/scm-ui/ui-components/src/layout/index.ts @@ -31,3 +31,7 @@ export { default as Page } from "./Page"; export { default as PageActions } from "./PageActions"; export { default as Subtitle } from "./Subtitle"; export { default as Title } from "./Title"; +export { default as CustomQueryFlexWrappedColumns } from "./CustomQueryFlexWrappedColumns"; +export { default as PrimaryContentColumn } from "./PrimaryContentColumn"; +export { default as SecondaryNavigationColumn } from "./SecondaryNavigationColumn"; + diff --git a/scm-ui/ui-components/src/navigation/SecondaryNavigation.tsx b/scm-ui/ui-components/src/navigation/SecondaryNavigation.tsx index b8b8531365..fd8e1dd3eb 100644 --- a/scm-ui/ui-components/src/navigation/SecondaryNavigation.tsx +++ b/scm-ui/ui-components/src/navigation/SecondaryNavigation.tsx @@ -38,11 +38,10 @@ type CollapsedProps = { collapsed: boolean; }; -const SectionContainer = styled.aside` +const SectionContainer = styled.aside` position: sticky; position: -webkit-sticky; /* Safari */ top: 2rem; - width: ${props => (props.collapsed ? "5.5rem" : "20.5rem")}; `; const Icon = styled.i` @@ -80,7 +79,7 @@ const SecondaryNavigation: FC = ({ label, children, collapsed, onCollapse const arrowIcon = isCollapsed ? : ; return ( - +
{ value={{ menuCollapsed, setMenuCollapsed: (collapsed: boolean) => this.setState({ menuCollapsed: collapsed }) }} > -
-
+ + @@ -143,8 +146,8 @@ class Admin extends React.Component { } /> -
-
+ + this.onCollapseAdminMenu(!menuCollapsed)} @@ -189,8 +192,8 @@ class Admin extends React.Component { -
-
+ +
); diff --git a/scm-ui/ui-webapp/src/containers/Profile.tsx b/scm-ui/ui-webapp/src/containers/Profile.tsx index 1d9e06b317..221e8974c7 100644 --- a/scm-ui/ui-webapp/src/containers/Profile.tsx +++ b/scm-ui/ui-webapp/src/containers/Profile.tsx @@ -34,6 +34,9 @@ import { MenuContext, NavLink, Page, + CustomQueryFlexWrappedColumns, + PrimaryContentColumn, + SecondaryNavigationColumn, SecondaryNavigation, SubNavigation } from "@scm-manager/ui-components"; @@ -107,13 +110,13 @@ class Profile extends React.Component { value={{ menuCollapsed, setMenuCollapsed: (collapsed: boolean) => this.setState({ menuCollapsed: collapsed }) }} > -
-
+ + } /> } /> -
-
+ + this.onCollapseProfileMenu(!menuCollapsed)} @@ -134,8 +137,8 @@ class Profile extends React.Component { -
-
+ +
); diff --git a/scm-ui/ui-webapp/src/groups/containers/SingleGroup.tsx b/scm-ui/ui-webapp/src/groups/containers/SingleGroup.tsx index c25592c24f..c7c658c059 100644 --- a/scm-ui/ui-webapp/src/groups/containers/SingleGroup.tsx +++ b/scm-ui/ui-webapp/src/groups/containers/SingleGroup.tsx @@ -34,6 +34,9 @@ import { MenuContext, NavLink, Page, + CustomQueryFlexWrappedColumns, + PrimaryContentColumn, + SecondaryNavigationColumn, SecondaryNavigation, SubNavigation } from "@scm-manager/ui-components"; @@ -113,8 +116,8 @@ class SingleGroup extends React.Component { value={{ menuCollapsed, setMenuCollapsed: (collapsed: boolean) => this.setState({ menuCollapsed: collapsed }) }} > -
-
+ +
} /> } /> { component={() => } /> -
-
+ + this.onCollapseGroupMenu(!menuCollapsed)} @@ -147,8 +150,8 @@ class SingleGroup extends React.Component { -
-
+ +
); diff --git a/scm-ui/ui-webapp/src/repos/containers/RepositoryRoot.tsx b/scm-ui/ui-webapp/src/repos/containers/RepositoryRoot.tsx index 1e2b5624d6..88aff9fcd7 100644 --- a/scm-ui/ui-webapp/src/repos/containers/RepositoryRoot.tsx +++ b/scm-ui/ui-webapp/src/repos/containers/RepositoryRoot.tsx @@ -32,6 +32,9 @@ import { Loading, NavLink, Page, + CustomQueryFlexWrappedColumns, + PrimaryContentColumn, + SecondaryNavigationColumn, SecondaryNavigation, SubNavigation, MenuContext, @@ -170,8 +173,8 @@ class RepositoryRoot extends React.Component { }} > -
-
+ + @@ -220,8 +223,8 @@ class RepositoryRoot extends React.Component { } /> -
-
+ + this.onCollapseRepositoryMenu(!menuCollapsed)} @@ -265,8 +268,8 @@ class RepositoryRoot extends React.Component { -
-
+ +
); diff --git a/scm-ui/ui-webapp/src/users/containers/SingleUser.tsx b/scm-ui/ui-webapp/src/users/containers/SingleUser.tsx index c1b2fa13d8..5050b3ea05 100644 --- a/scm-ui/ui-webapp/src/users/containers/SingleUser.tsx +++ b/scm-ui/ui-webapp/src/users/containers/SingleUser.tsx @@ -33,8 +33,12 @@ import { MenuContext, NavLink, Page, + CustomQueryFlexWrappedColumns, + PrimaryContentColumn, + SecondaryNavigationColumn, SecondaryNavigation, - SubNavigation + SubNavigation, + storeMenuCollapsed } from "@scm-manager/ui-components"; import { Details } from "./../components/table"; import EditUser from "./EditUser"; @@ -44,7 +48,6 @@ import { WithTranslation, withTranslation } from "react-i18next"; import { getUsersLink } from "../../modules/indexResource"; import SetUserPassword from "../components/SetUserPassword"; import SetPermissions from "../../permissions/components/SetPermissions"; -import { storeMenuCollapsed } from "@scm-manager/ui-components/src"; type Props = RouteComponentProps & WithTranslation & { @@ -114,8 +117,8 @@ class SingleUser extends React.Component { value={{ menuCollapsed, setMenuCollapsed: (collapsed: boolean) => this.setState({ menuCollapsed: collapsed }) }} > -
-
+ +
} /> } /> } /> @@ -124,8 +127,8 @@ class SingleUser extends React.Component { component={() => } /> -
-
+ + this.onCollapseUserMenu(!menuCollapsed)} @@ -148,8 +151,8 @@ class SingleUser extends React.Component { -
-
+ +
);