mirror of
https://github.com/ilyakooo0/urbit.git
synced 2024-12-16 02:22:12 +03:00
Merge pull request #4725 from urbit/james/image-input
interface: redesign ImageInput
This commit is contained in:
commit
05711cbe14
@ -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' />
|
||||
)}
|
||||
</>
|
||||
);
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user