Resize modal to show content appropriately

Change-type: patch
Changelog-entry: Resize modal to show content appropriately
Signed-off-by: Lorenzo Alberto Maria Ambrosi <lorenzothunder.ambrosi@gmail.com>
This commit is contained in:
Lorenzo Alberto Maria Ambrosi 2020-07-02 17:03:26 +02:00
parent 5c5273bd6c
commit 630f6c691c
5 changed files with 78 additions and 75 deletions

View File

@ -120,10 +120,6 @@ export function SettingsModal({ toggleModal }: SettingsModalProps) {
</Txt> </Txt>
} }
done={() => toggleModal(false)} done={() => toggleModal(false)}
style={{
width: 780,
height: 420,
}}
> >
<Flex flexDirection="column"> <Flex flexDirection="column">
{_.map(settingsList, (setting: Setting, i: number) => { {_.map(settingsList, (setting: Setting, i: number) => {

View File

@ -52,6 +52,7 @@ import {
Modal, Modal,
StepButton, StepButton,
StepNameButton, StepNameButton,
ScrollableFlex,
} from '../../styled-components'; } from '../../styled-components';
import { colors } from '../../theme'; import { colors } from '../../theme';
import { middleEllipsis } from '../../utils/middle-ellipsis'; import { middleEllipsis } from '../../utils/middle-ellipsis';
@ -61,19 +62,24 @@ import ImageSvg from '../../../assets/image.svg';
const recentUrlImagesKey = 'recentUrlImages'; const recentUrlImagesKey = 'recentUrlImages';
function normalizeRecentUrlImages(urls: any): string[] { function normalizeRecentUrlImages(urls: any[]): URL[] {
if (!Array.isArray(urls)) { if (!Array.isArray(urls)) {
urls = []; urls = [];
} }
return _.chain(urls) urls = urls
.filter(_.isString) .map((url) => {
.reject(_.isEmpty) try {
.uniq() return new URL(url);
.takeRight(5) } catch (error) {
.value(); // Invalid URL, skip
}
})
.filter((url) => url !== undefined);
urls = _.uniqBy(urls, (url) => url.href);
return urls.slice(urls.length - 5);
} }
function getRecentUrlImages(): string[] { function getRecentUrlImages(): URL[] {
let urls = []; let urls = [];
try { try {
urls = JSON.parse(localStorage.getItem(recentUrlImagesKey) || '[]'); urls = JSON.parse(localStorage.getItem(recentUrlImagesKey) || '[]');
@ -83,11 +89,9 @@ function getRecentUrlImages(): string[] {
return normalizeRecentUrlImages(urls); return normalizeRecentUrlImages(urls);
} }
function setRecentUrlImages(urls: string[]) { function setRecentUrlImages(urls: URL[]) {
localStorage.setItem( const normalized = normalizeRecentUrlImages(urls.map((url: URL) => url.href));
recentUrlImagesKey, localStorage.setItem(recentUrlImagesKey, JSON.stringify(normalized));
JSON.stringify(normalizeRecentUrlImages(urls)),
);
} }
const Card = styled(BaseCard)` const Card = styled(BaseCard)`
@ -124,13 +128,13 @@ const URLSelector = ({
}) => { }) => {
const [imageURL, setImageURL] = React.useState(''); const [imageURL, setImageURL] = React.useState('');
const [recentImages, setRecentImages]: [ const [recentImages, setRecentImages]: [
string[], URL[],
(value: React.SetStateAction<string[]>) => void, (value: React.SetStateAction<URL[]>) => void,
] = React.useState([]); ] = React.useState([]);
const [loading, setLoading] = React.useState(false); const [loading, setLoading] = React.useState(false);
React.useEffect(() => { React.useEffect(() => {
const fetchRecentUrlImages = async () => { const fetchRecentUrlImages = async () => {
const recentUrlImages: string[] = await getRecentUrlImages(); const recentUrlImages: URL[] = await getRecentUrlImages();
setRecentImages(recentUrlImages); setRecentImages(recentUrlImages);
}; };
fetchRecentUrlImages(); fetchRecentUrlImages();
@ -139,15 +143,16 @@ const URLSelector = ({
<Modal <Modal
cancel={cancel} cancel={cancel}
primaryButtonProps={{ primaryButtonProps={{
disabled: loading || !imageURL, className: loading || !imageURL ? 'disabled' : '',
}} }}
done={async () => { done={async () => {
setLoading(true); setLoading(true);
const sanitizedRecentUrls = normalizeRecentUrlImages([ const urlStrings = recentImages.map((url: URL) => url.href);
...recentImages, const normalizedRecentUrls = normalizeRecentUrlImages([
...urlStrings,
imageURL, imageURL,
]); ]);
setRecentUrlImages(sanitizedRecentUrls); setRecentUrlImages(normalizedRecentUrls);
await done(imageURL); await done(imageURL);
}} }}
> >
@ -164,24 +169,29 @@ const URLSelector = ({
} }
/> />
</Flex> </Flex>
{!_.isEmpty(recentImages) && ( {recentImages.length > 0 && (
<Flex flexDirection="column"> <Flex flexDirection="column" height="78.6%">
<Txt fontSize={18}>Recent</Txt> <Txt fontSize={18}>Recent</Txt>
<Card <ScrollableFlex flexDirection="column">
style={{ padding: '10px 15px' }} <Card
rows={_.map(recentImages, (recent) => ( p="10px 15px"
<Txt rows={recentImages
key={recent} .map((recent) => (
onClick={() => { <Txt
setImageURL(recent); key={recent.href}
}} onClick={() => {
> setImageURL(recent.href);
<span> }}
{_.last(_.split(recent, '/'))} - {recent} style={{
</span> overflowWrap: 'break-word',
</Txt> }}
))} >
/> {recent.pathname.split('/').pop()} - {recent.href}
</Txt>
))
.reverse()}
/>
</ScrollableFlex>
</Flex> </Flex>
)} )}
</Modal> </Modal>
@ -280,7 +290,7 @@ export class SourceSelector extends React.Component<
private async onSelectImage(_event: IpcRendererEvent, imagePath: string) { private async onSelectImage(_event: IpcRendererEvent, imagePath: string) {
const isURL = const isURL =
_.startsWith(imagePath, 'https://') || _.startsWith(imagePath, 'http://'); imagePath.startsWith('https://') || imagePath.startsWith('http://');
await this.selectImageByPath({ await this.selectImageByPath({
imagePath, imagePath,
SourceType: isURL ? sourceDestination.Http : sourceDestination.File, SourceType: isURL ? sourceDestination.Http : sourceDestination.File,
@ -354,8 +364,8 @@ export class SourceSelector extends React.Component<
}); });
} else { } else {
if ( if (
!_.startsWith(imagePath, 'https://') && !imagePath.startsWith('https://') &&
!_.startsWith(imagePath, 'http://') !imagePath.startsWith('http://')
) { ) {
const invalidImageError = errors.createUserError({ const invalidImageError = errors.createUserError({
title: 'Unsupported protocol', title: 'Unsupported protocol',

View File

@ -50,7 +50,7 @@ import {
import { store } from '../../models/store'; import { store } from '../../models/store';
import { logEvent, logException } from '../../modules/analytics'; import { logEvent, logException } from '../../modules/analytics';
import { open as openExternal } from '../../os/open-external/services/open-external'; import { open as openExternal } from '../../os/open-external/services/open-external';
import { Modal } from '../../styled-components'; import { Modal, ScrollableFlex } from '../../styled-components';
import TargetSVGIcon from '../../../assets/tgt.svg'; import TargetSVGIcon from '../../../assets/tgt.svg';
@ -83,19 +83,6 @@ function isDrivelistDrive(
return typeof (drive as scanner.adapters.DrivelistDrive).size === 'number'; return typeof (drive as scanner.adapters.DrivelistDrive).size === 'number';
} }
const ScrollableFlex = styled(Flex)`
overflow: auto;
::-webkit-scrollbar {
display: none;
}
> div > div {
/* This is required for the sticky table header in TargetsTable */
overflow-x: visible;
}
`;
const TargetsTable = styled(({ refFn, ...props }) => { const TargetsTable = styled(({ refFn, ...props }) => {
return ( return (
<div> <div>
@ -376,10 +363,6 @@ export class TargetSelectorModal extends React.Component<
cancel={cancel} cancel={cancel}
done={() => done(selectedList)} done={() => done(selectedList)}
action={`Select (${selectedList.length})`} action={`Select (${selectedList.length})`}
style={{
width: '780px',
height: '420px',
}}
primaryButtonProps={{ primaryButtonProps={{
primary: !hasStatus, primary: !hasStatus,
warning: hasStatus, warning: hasStatus,
@ -387,7 +370,7 @@ export class TargetSelectorModal extends React.Component<
}} }}
{...props} {...props}
> >
<Flex width="100%" height="100%"> <Flex width="100%" height="90%">
{!hasAvailableDrives() ? ( {!hasAvailableDrives() ? (
<Flex <Flex
flexDirection="column" flexDirection="column"
@ -399,11 +382,7 @@ export class TargetSelectorModal extends React.Component<
<b>Plug a target drive</b> <b>Plug a target drive</b>
</Flex> </Flex>
) : ( ) : (
<ScrollableFlex <ScrollableFlex flexDirection="column" width="100%">
flexDirection="column"
width="100%"
height="calc(100% - 15px)"
>
<TargetsTable <TargetsTable
refFn={(t: Table<Target>) => { refFn={(t: Table<Target>) => {
if (t !== null) { if (t !== null) {

View File

@ -63,5 +63,5 @@ button:focus,
} }
.disabled { .disabled {
opacity: 0.2; opacity: 0.4;
} }

View File

@ -121,8 +121,7 @@ export const DetailsText = (props: FlexProps) => (
/> />
); );
export const Modal = styled((props) => { export const Modal = styled(({ style, ...props }) => {
const { style = { height: 420 } } = props;
return ( return (
<Provider <Provider
theme={{ theme={{
@ -143,23 +142,29 @@ export const Modal = styled((props) => {
> >
<ModalBase <ModalBase
position="top" position="top"
width={780} width="96vw"
cancelButtonProps={{ cancelButtonProps={{
style: { style: {
marginRight: '20px', marginRight: '20px',
border: 'solid 1px #2a506f', border: 'solid 1px #2a506f',
}, },
}} }}
style={style} style={{
height: '86.5vh',
...style,
}}
{...props} {...props}
/> />
</Provider> </Provider>
); );
})` })`
> div { > div {
padding: 30px; padding: 24px 30px;
height: calc(100% - 80px); height: calc(100% - 80px);
overflow-y: auto;
::-webkit-scrollbar {
display: none;
}
> h3 { > h3 {
margin: 0; margin: 0;
@ -178,3 +183,16 @@ export const Modal = styled((props) => {
} }
} }
`; `;
export const ScrollableFlex = styled(Flex)`
overflow: auto;
::-webkit-scrollbar {
display: none;
}
> div > div {
/* This is required for the sticky table header in TargetsTable */
overflow-x: visible;
}
`;