Skip to content

Commit 2240519

Browse files
feat: responsive layout (#631)
* feat: wip of responsiveness * feat: stash * feat: responsive layout * fix: run prettier
1 parent 9ccf87e commit 2240519

32 files changed

Lines changed: 339 additions & 156 deletions

File tree

admin/src/pages/HomePage/components/CollapseButton/index.tsx

Lines changed: 26 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { CaretDown, CaretUp } from '@strapi/icons';
33
import styled from 'styled-components';
44

55
import { Effect } from '../../../../types';
6+
import { usePluginMediaQuery } from '../../hooks/usePluginMediaQuery';
67

78
const Wrapper = styled.div`
89
border-radius: 50%;
@@ -21,17 +22,28 @@ interface Props {
2122
itemsCount?: number;
2223
}
2324

24-
export const CollapseButton = ({ toggle, collapsed, itemsCount }: Props) => (
25-
<Flex
26-
justifyContent="space-between"
27-
alignItems="center"
28-
onClick={toggle}
29-
cursor="pointer"
30-
style={{ marginRight: '16px' }}
31-
>
32-
<Wrapper>
33-
{collapsed ? <CaretDown width="16px" height="9px" /> : <CaretUp width="16px" height="9px" />}
34-
</Wrapper>
35-
<Typography variant="pi">{itemsCount} nested items</Typography>
36-
</Flex>
37-
);
25+
export const CollapseButton = ({ toggle, collapsed, itemsCount }: Props) => {
26+
const { isSmallMobile } = usePluginMediaQuery();
27+
return (
28+
<Flex
29+
justifyContent="space-between"
30+
alignItems="center"
31+
onClick={toggle}
32+
cursor="pointer"
33+
style={{ marginRight: '16px' }}
34+
>
35+
<Wrapper>
36+
{collapsed ? (
37+
<CaretDown width="16px" height="9px" />
38+
) : (
39+
<CaretUp width="16px" height="9px" />
40+
)}
41+
</Wrapper>
42+
{!isSmallMobile && (
43+
<Typography variant="pi">
44+
{itemsCount} nested {itemsCount === 1 ? 'item' : 'items'}
45+
</Typography>
46+
)}
47+
</Flex>
48+
);
49+
};

admin/src/pages/HomePage/components/DragButton/index.tsx

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,16 @@
11
import { Drag } from '@strapi/icons';
22
import React from 'react';
33
import styled, { DefaultTheme } from 'styled-components';
4+
import { usePluginMediaQuery } from '../../hooks';
45

5-
const DragButtonWrapper = styled.span<{ ref: unknown; isActive?: boolean }>`
6+
const DragButtonWrapper = styled.span<{ ref: unknown; isActive?: boolean; isMobile?: boolean }>`
67
display: flex;
78
align-items: center;
89
justify-content: center;
910
10-
height: 32px;
11-
width: 32px;
12-
padding: ${({ theme }) => theme.spaces[2]};
11+
height: ${({ isMobile }) => (isMobile ? '24px' : '32px')};
12+
width: ${({ isMobile }) => (isMobile ? '24px' : '32px')};
13+
padding: ${({ theme, isMobile }) => (isMobile ? theme.spaces[1] : theme.spaces[2])};
1314
1415
background: ${({ theme, isActive }) =>
1516
isActive ? theme.colors.neutral150 : theme.colors.neutral0};
@@ -53,10 +54,13 @@ const DragButtonWrapper = styled.span<{ ref: unknown; isActive?: boolean }>`
5354
}
5455
`;
5556

56-
const DragButton = React.forwardRef<unknown, { isActive?: boolean }>((props, ref) => (
57-
<DragButtonWrapper {...props} ref={ref}>
58-
<Drag />
59-
</DragButtonWrapper>
60-
));
57+
const DragButton = React.forwardRef<unknown, { isActive?: boolean }>((props, ref) => {
58+
const { isSmallMobile } = usePluginMediaQuery();
59+
return (
60+
<DragButtonWrapper {...props} ref={ref} isMobile={isSmallMobile}>
61+
<Drag />
62+
</DragButtonWrapper>
63+
);
64+
});
6165

6266
export default DragButton;

admin/src/pages/HomePage/components/NavigationContentHeader/ManageNavigationItems/index.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ export const ManageNavigationItems: React.FC<ManageNavigationItemsProps> = ({
9898
}
9999

100100
return actions.map(({ tradId, margin, ...item }, i) => (
101-
<Box marginLeft={margin} key={i}>
101+
<Box marginLeft={{ initial: 0, small: margin }} key={i}>
102102
<Button {...item}> {formatMessage(getTrad(tradId))} </Button>
103103
</Box>
104104
));

admin/src/pages/HomePage/components/NavigationContentHeader/Search/index.tsx

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { useIntl } from 'react-intl';
55

66
import { getTrad } from '../../../../../translations';
77
import { Effect } from '../../../../../types';
8+
import { usePluginMediaQuery } from '../../../hooks';
89

910
interface Props {
1011
value: string;
@@ -18,7 +19,9 @@ export const Search = ({ value, setValue, initialIndex = DEFAULT_INDEX }: Props)
1819
const [currentValue, setCurrentValue] = useState(value);
1920
const [previousValue, setPreviousValue] = useState(value);
2021
const [currentIndex, setCurrentIndex] = useState(initialIndex);
21-
const [isOpen, setIsOpen] = useState(!!value);
22+
const { isSmallMobile, isMobile } = usePluginMediaQuery();
23+
24+
const [isOpen, setIsOpen] = useState(!!value || isSmallMobile);
2225
const wrapperRef = useRef<HTMLDivElement>(null);
2326
const { formatMessage } = useIntl();
2427

@@ -68,7 +71,7 @@ export const Search = ({ value, setValue, initialIndex = DEFAULT_INDEX }: Props)
6871

6972
if (isOpen) {
7073
return (
71-
<div ref={wrapperRef}>
74+
<div ref={wrapperRef} style={{ width: '100%' }}>
7275
<Searchbar
7376
name="searchbar"
7477
onClear={onClear}
@@ -86,7 +89,8 @@ export const Search = ({ value, setValue, initialIndex = DEFAULT_INDEX }: Props)
8689
<Typography
8790
variant="pi"
8891
fontColor="neutral150"
89-
style={{ margin: '3px 0 0', display: 'inline-block' }}
92+
style={{ margin: '3px 0 0' }}
93+
display={{ initial: 'none', medium: 'inline-block' }}
9094
>
9195
{formatMessage(
9296
getTrad('pages.main.search.subLabel', 'press ENTER to highlight next item')

admin/src/pages/HomePage/components/NavigationContentHeader/index.tsx

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,23 @@ interface Props {
88

99
export const NavigationContentHeader = ({ startActions, endActions }: Props) => {
1010
return (
11-
<Flex justifyContent="space-between" width="100%">
12-
<Flex alignItems="space-between">{startActions}</Flex>
13-
<Flex alignItems="space-between">{endActions}</Flex>
11+
<Flex
12+
direction={{ initial: 'column-reverse', small: 'row' }}
13+
justifyContent={{ initial: 'flex-start', small: 'space-between' }}
14+
width="100%"
15+
gap={{ initial: 2, small: 0 }}
16+
>
17+
<Flex alignItems="space-between" width="100%">
18+
{startActions}
19+
</Flex>
20+
<Flex
21+
gap={{ initial: 2, small: 0 }}
22+
alignItems="space-between"
23+
width="100%"
24+
justifyContent={{ initial: 'flex-start', small: 'flex-end' }}
25+
>
26+
{endActions}
27+
</Flex>
1428
</Flex>
1529
);
1630
};

admin/src/pages/HomePage/components/NavigationHeader/index.tsx

Lines changed: 105 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,29 @@ import { Check, Information } from '@strapi/icons';
1212
import { Layouts } from '@strapi/strapi/admin';
1313
import React from 'react';
1414
import { useIntl } from 'react-intl';
15+
import styled from 'styled-components';
1516
import { NavigationSchema } from '../../../../api/validators';
1617
import { getTrad } from '../../../../translations';
1718
import { Effect } from '../../../../types';
18-
import { useConfig } from '../../hooks';
19+
import { useConfig, usePluginMediaQuery } from '../../hooks';
1920
import { useNavigationManager } from './hooks';
2021

22+
const StyledGridItem = styled(Grid.Item)<{
23+
orderInitial?: number;
24+
orderSmall?: number;
25+
orderMedium?: number;
26+
}>`
27+
order: ${({ orderInitial }) => orderInitial ?? 'unset'};
28+
29+
@media (min-width: 520px) {
30+
order: ${({ orderSmall }) => orderSmall ?? 'unset'};
31+
}
32+
33+
@media (min-width: 768px) {
34+
order: ${({ orderMedium }) => orderMedium ?? 'unset'};
35+
}
36+
`;
37+
2138
const submitIcon = <Check />;
2239

2340
interface Props {
@@ -55,27 +72,41 @@ export const NavigationHeader: React.FC<Props> = ({
5572
const { formatMessage } = useIntl();
5673
const { openNavigationManagerModal, navigationManagerModal } = useNavigationManager();
5774

58-
const hasLocalizations = !!locale.restLocale;
75+
const configQuery = useConfig();
76+
77+
const hasLocalizations = !!locale.restLocale?.length;
78+
const hasCache = configQuery.data?.isCacheEnabled;
5979

6080
const { canUpdate } = permissions;
6181

62-
const configQuery = useConfig();
82+
const { isDesktop, isMobile, isLargeDesktop } = usePluginMediaQuery();
6383

6484
return (
6585
<>
6686
<Layouts.Header
6787
title={formatMessage(getTrad('header.title', 'UI Navigation'))}
68-
subtitle={formatMessage(getTrad('header.description'))}
88+
subtitle={isLargeDesktop && formatMessage(getTrad('header.description'))}
6989
primaryAction={
70-
<Flex direction="row" size={2}>
71-
<Box>
90+
<Flex
91+
direction="row"
92+
size={2}
93+
width={isLargeDesktop ? 'auto' : !isMobile ? '728px' : '100%'}
94+
>
95+
<Box width="100%">
7296
<Grid.Root
73-
gap={4}
97+
gap={{ initial: 2, medium: 4 }}
98+
width="100%"
7499
style={configQuery.data?.isCacheEnabled ? { display: 'flex' } : undefined}
75100
>
76-
{!hasLocalizations ? <Grid.Item col={2} /> : null}
101+
{!hasLocalizations && isLargeDesktop ? <Grid.Item m={2} xs={0} /> : null}
77102
{canUpdate && (
78-
<Grid.Item col={3}>
103+
<StyledGridItem
104+
m={3}
105+
xs={hasCache ? 4 : 6}
106+
orderInitial={3}
107+
orderSmall={3}
108+
orderMedium={1}
109+
>
79110
<Button
80111
onClick={openNavigationManagerModal}
81112
startIcon={null}
@@ -86,9 +117,15 @@ export const NavigationHeader: React.FC<Props> = ({
86117
>
87118
{formatMessage(getTrad('header.action.manage'))}
88119
</Button>
89-
</Grid.Item>
120+
</StyledGridItem>
90121
)}
91-
<Grid.Item col={canUpdate ? 4 : 10}>
122+
<StyledGridItem
123+
m={canUpdate ? 4 : 10}
124+
xs={hasLocalizations ? 9 : 12}
125+
orderInitial={1}
126+
orderSmall={1}
127+
orderMedium={2}
128+
>
92129
<Field.Root width="100%">
93130
<SingleSelect
94131
type="select"
@@ -116,29 +153,37 @@ export const NavigationHeader: React.FC<Props> = ({
116153
))}
117154
</SingleSelect>
118155
</Field.Root>
119-
</Grid.Item>
156+
</StyledGridItem>
120157
{hasLocalizations ? (
121-
<Grid.Item col={2}>
122-
<SingleSelect
123-
type="select"
124-
placeholder={formatMessage(
125-
getTrad('pages.main.header.localization.select.placeholder')
126-
)}
127-
name="navigationLocalizationSelect"
128-
onChange={handleLocalizationSelection}
129-
value={currentLocale}
130-
size="S"
131-
>
132-
{[locale.defaultLocale, ...locale.restLocale].map((code) => (
133-
<SingleSelectOption key={code} value={code}>
134-
{code}
135-
</SingleSelectOption>
136-
))}
137-
</SingleSelect>
138-
</Grid.Item>
158+
<StyledGridItem m={2} xs={3} orderInitial={2} orderSmall={2} orderMedium={3}>
159+
<Field.Root width="100%">
160+
<SingleSelect
161+
type="select"
162+
placeholder={formatMessage(
163+
getTrad('pages.main.header.localization.select.placeholder')
164+
)}
165+
name="navigationLocalizationSelect"
166+
onChange={handleLocalizationSelection}
167+
value={currentLocale}
168+
size="S"
169+
>
170+
{[locale.defaultLocale, ...locale.restLocale].map((code) => (
171+
<SingleSelectOption key={code} value={code}>
172+
{code}
173+
</SingleSelectOption>
174+
))}
175+
</SingleSelect>
176+
</Field.Root>
177+
</StyledGridItem>
139178
) : null}
140179
{canUpdate && (
141-
<Grid.Item col={3}>
180+
<StyledGridItem
181+
m={3}
182+
xs={hasCache ? 4 : 6}
183+
orderInitial={4}
184+
orderSmall={4}
185+
orderMedium={4}
186+
>
142187
<Button
143188
onClick={handleSave}
144189
startIcon={submitIcon}
@@ -149,36 +194,43 @@ export const NavigationHeader: React.FC<Props> = ({
149194
>
150195
{formatMessage(getTrad('submit.cta.save'))}
151196
</Button>
152-
</Grid.Item>
197+
</StyledGridItem>
153198
)}
154-
{configQuery.data?.isCacheEnabled && (
155-
<Grid.Item col={3}>
156-
<Button
157-
onClick={handleCachePurge}
158-
startIcon={submitIcon}
159-
variant="danger"
160-
type="submit"
161-
fullWidth
162-
size="S"
163-
>
164-
{formatMessage(getTrad('submit.cta.cache.purge'))}
165-
</Button>
166-
</Grid.Item>
199+
{hasCache && (
200+
<>
201+
{isDesktop && (
202+
<StyledGridItem m={9} orderInitial={5} orderSmall={5} orderMedium={5} />
203+
)}
204+
<StyledGridItem m={3} xs={4} orderInitial={6} orderSmall={6} orderMedium={6}>
205+
<Button
206+
onClick={handleCachePurge}
207+
startIcon={submitIcon}
208+
variant="danger"
209+
type="submit"
210+
fullWidth
211+
size="S"
212+
>
213+
{formatMessage(getTrad('submit.cta.cache.purge'))}
214+
</Button>
215+
</StyledGridItem>
216+
</>
167217
)}
168218
</Grid.Root>
169219
</Box>
170220
{canUpdate && navigationManagerModal}
171221
</Flex>
172222
}
173223
secondaryAction={
174-
<Tag icon={<Information aria-hidden={true} />}>
175-
{activeNavigation
176-
? formatMessage(getTrad('header.meta'), {
177-
id: activeNavigation?.documentId,
178-
key: activeNavigation?.slug,
179-
})
180-
: null}
181-
</Tag>
224+
!isMobile && (
225+
<Tag icon={<Information aria-hidden={true} />}>
226+
{activeNavigation
227+
? formatMessage(getTrad('header.meta'), {
228+
id: activeNavigation?.documentId,
229+
key: activeNavigation?.slug,
230+
})
231+
: null}
232+
</Tag>
233+
)
182234
}
183235
/>
184236
</>

admin/src/pages/HomePage/components/NavigationItemForm/components/AdditionalFields/CustomFieldsField/index.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ export const CustomFieldsField: React.FC<CustomFieldsFieldProps> = ({ additional
1414
useNavigationItemFormContext();
1515

1616
return (
17-
<Grid.Item alignItems="flex-start" key={additionalField.name} col={6}>
17+
<Grid.Item alignItems="flex-start" key={additionalField.name} s={6} xs={12}>
1818
<Field
1919
name={`additionalFields.${additionalField.name}`}
2020
label={additionalField.label}

0 commit comments

Comments
 (0)