Merge pull request #4725 from urbit/james/image-input

interface: redesign ImageInput
This commit is contained in:
matildepark 2021-04-14 18:26:27 -04:00 committed by GitHub
commit 05711cbe14
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 99 additions and 39 deletions

View File

@ -64,20 +64,20 @@ export function ProfileHeaderImageEdit(props: any): ReactElement {
{contact?.cover ? (
<div>
{editCover ? (
<ImageInput id='cover' marginTop='-8px' />
<ImageInput id='cover' marginTop='-8px' width='288px' />
) : (
<Row>
<Button mr='2' onClick={() => setEditCover(true)}>
Replace Header
</Button>
<Button onClick={(e) => handleClear(e)}>
<Button onClick={e => handleClear(e)}>
{removedCoverLabel}
</Button>
</Row>
)}
</div>
) : (
<ImageInput id='cover' marginTop='-8px' />
<ImageInput id='cover' marginTop='-8px' width='288px' />
)}
</>
);

View File

@ -1,32 +1,36 @@
import React, { ReactElement } from 'react';
import {
Box,
Text,
Row,
Label,
Col,
ManagedRadioButtonField as Radio,
ManagedRadioButtonField as Radio
} from '@tlon/indigo-react';
import GlobalApi from '~/logic/api/global';
import { ImageInput } from '~/views/components/ImageInput';
import { ColorInput } from '~/views/components/ColorInput';
import { StorageState } from '~/types';
export type BgType = 'none' | 'url' | 'color';
export function BackgroundPicker({
bgType,
bgUrl,
api,
api
}: {
bgType: BgType;
bgUrl?: string;
api: GlobalApi;
}): ReactElement {
const rowSpace = { my: 0, alignItems: 'center' };
const colProps = { my: 3, mr: 4, gapY: 1 };
const colProps = {
my: 3,
mr: 4,
gapY: 1,
minWidth: '266px',
width: ['100%', '288px']
};
return (
<Col>
<Label>Landscape Background</Label>
@ -40,7 +44,7 @@ export function BackgroundPicker({
id="bgUrl"
placeholder="Drop or upload a file, or paste a link here"
name="bgUrl"
url={bgUrl || ""}
url={bgUrl || ''}
/>
</Col>
</Row>
@ -48,13 +52,13 @@ export function BackgroundPicker({
<Col {...colProps}>
<Radio mb="1" label="Color" id="color" name="bgType" />
<Text ml="5" gray>Set a hex-based background</Text>
<ColorInput placeholder="FFFFFF" ml="5" id="bgColor" />
<ColorInput placeholder="FFFFFF" ml="5" id="bgColor" />
</Col>
</Row>
<Radio
my="3"
caption="Your home screen will simply render as its respective day/night mode color"
name="bgType"
name="bgType"
label="None"
id="none" />
</Col>

View File

@ -7,11 +7,10 @@ import {
Row,
Button,
Label,
ErrorLabel,
BaseInput
BaseInput,
Text
} from '@tlon/indigo-react';
import { StorageState } from '~/types';
import useStorage from '~/logic/lib/useStorage';
type ImageInputProps = Parameters<typeof Box>[0] & {
@ -20,13 +19,75 @@ type ImageInputProps = Parameters<typeof Box>[0] & {
placeholder?: string;
};
const prompt = (field, uploading, meta, clickUploadButton) => {
if (!field.value && !uploading && meta.error === undefined) {
return (
<Text
black
fontWeight='500'
position='absolute'
left={2}
top={2}
style={{ pointerEvents: 'none' }}
>
Paste a link here, or{' '}
<Text
fontWeight='500'
cursor='pointer'
color='blue'
style={{ pointerEvents: 'all' }}
onClick={clickUploadButton}
>
upload
</Text>{' '}
a file
</Text>
);
}
return null;
};
const uploadingStatus = (uploading, meta) => {
if (uploading && meta.error === undefined) {
return (
<Text position='absolute' left={2} top={2} gray>
Uploading...
</Text>
);
}
return null;
};
const errorRetry = (meta, uploading, clickUploadButton) => {
if (meta.error !== undefined) {
return (
<Text
position='absolute'
left={2}
top={2}
color='red'
style={{ pointerEvents: 'none' }}
>
{meta.error}{', '}please{' '}
<Text
fontWeight='500'
cursor='pointer'
color='blue'
style={{ pointerEvents: 'all' }}
onClick={clickUploadButton}
>
retry
</Text>
</Text>
);
}
return null;
};
export function ImageInput(props: ImageInputProps): ReactElement {
const { id, label, caption, placeholder } = props;
const { id, label, caption } = props;
const { uploadDefault, canUpload, uploading } = useStorage();
const [field, meta, { setValue, setError }] = useField(id);
const ref = useRef<HTMLInputElement | null>(null);
const onImageUpload = useCallback(async () => {
@ -43,10 +104,9 @@ export function ImageInput(props: ImageInputProps): ReactElement {
}
}, [ref.current, uploadDefault, canUpload, setValue]);
const onClick = useCallback(() => {
const clickUploadButton = useCallback(() => {
ref.current?.click();
}, [ref]);
return (
<Box display="flex" flexDirection="column" {...props}>
<Label htmlFor={id}>{label}</Label>
@ -55,25 +115,24 @@ export function ImageInput(props: ImageInputProps): ReactElement {
{caption}
</Label>
) : null}
<Row mt="2" alignItems="flex-end">
<Input
type={'text'}
hasError={meta.touched && meta.error !== undefined}
placeholder={placeholder}
{...field}
/>
<Row mt="2" alignItems="flex-end" position='relative' width='100%'>
{prompt(field, uploading, meta, clickUploadButton)}
{uploadingStatus(uploading, meta)}
{errorRetry(meta, uploading, clickUploadButton)}
<Box background='white' borderRadius={2} width='100%'>
<Input
width='100%'
type={'text'}
hasError={meta.touched && meta.error !== undefined}
{...field}
/>
</Box>
{canUpload && (
<>
<Button
type="button"
ml={1}
border={1}
borderColor="lightGray"
onClick={onClick}
flexShrink={0}
>
{uploading ? 'Uploading' : 'Upload'}
</Button>
display='none'
onClick={clickUploadButton}
/>
<BaseInput
style={{ display: 'none' }}
type="file"
@ -85,9 +144,6 @@ export function ImageInput(props: ImageInputProps): ReactElement {
</>
)}
</Row>
<ErrorLabel mt="2" hasError={Boolean(meta.touched && meta.error)}>
{meta.error}
</ErrorLabel>
</Box>
);
}