ui: fix borked styling
This commit is contained in:
parent
7f290c6e52
commit
b8b481b57b
8 changed files with 68 additions and 55 deletions
|
@ -14,12 +14,14 @@ export const TableCheckbox = styled(Input)`
|
||||||
|
|
||||||
export default ({ name, checked, onChange }: { name: string, checked: boolean, onChange(e: React.ChangeEvent<HTMLInputElement>): void }) => {
|
export default ({ name, checked, onChange }: { name: string, checked: boolean, onChange(e: React.ChangeEvent<HTMLInputElement>): void }) => {
|
||||||
return (
|
return (
|
||||||
<TableCheckbox
|
<div css={tw`flex items-center`}>
|
||||||
type={'checkbox'}
|
<TableCheckbox
|
||||||
name={'selectedItems'}
|
type={'checkbox'}
|
||||||
value={name}
|
name={'selectedItems'}
|
||||||
checked={checked}
|
value={name}
|
||||||
onChange={onChange}
|
checked={checked}
|
||||||
/>
|
onChange={onChange}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
@ -2,6 +2,7 @@ import React, { forwardRef } from 'react';
|
||||||
import { Field as FormikField, FieldProps } from 'formik';
|
import { Field as FormikField, FieldProps } from 'formik';
|
||||||
import Input from '@/components/elements/Input';
|
import Input from '@/components/elements/Input';
|
||||||
import Label from '@/components/elements/Label';
|
import Label from '@/components/elements/Label';
|
||||||
|
import InputError from '@/components/elements/InputError';
|
||||||
|
|
||||||
interface OwnProps {
|
interface OwnProps {
|
||||||
name: string;
|
name: string;
|
||||||
|
@ -28,13 +29,9 @@ const Field = forwardRef<HTMLInputElement, Props>(({ id, name, light = false, la
|
||||||
isLight={light}
|
isLight={light}
|
||||||
hasError={!!(touched[field.name] && errors[field.name])}
|
hasError={!!(touched[field.name] && errors[field.name])}
|
||||||
/>
|
/>
|
||||||
{touched[field.name] && errors[field.name] ?
|
<InputError errors={errors} touched={touched} name={field.name}>
|
||||||
<p className={'input-help error'}>
|
{description || null}
|
||||||
{(errors[field.name] as string).charAt(0).toUpperCase() + (errors[field.name] as string).slice(1)}
|
</InputError>
|
||||||
</p>
|
|
||||||
:
|
|
||||||
description ? <p className={'input-help'}>{description}</p> : null
|
|
||||||
}
|
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,7 +17,11 @@ const FormikFieldWrapper = ({ id, name, label, className, description, validate,
|
||||||
<Field name={name} validate={validate}>
|
<Field name={name} validate={validate}>
|
||||||
{
|
{
|
||||||
({ field, form: { errors, touched } }: FieldProps) => (
|
({ field, form: { errors, touched } }: FieldProps) => (
|
||||||
<div className={`${className} ${(touched[field.name] && errors[field.name]) ? 'has-error' : undefined}`}>
|
<div className={className ?
|
||||||
|
`${className} ${(touched[field.name] && errors[field.name]) ? 'has-error' : undefined}`
|
||||||
|
:
|
||||||
|
`${(touched[field.name] && errors[field.name]) ? 'has-error' : undefined}`}
|
||||||
|
>
|
||||||
{label && <Label htmlFor={id}>{label}</Label>}
|
{label && <Label htmlFor={id}>{label}</Label>}
|
||||||
{children}
|
{children}
|
||||||
<InputError errors={errors} touched={touched} name={field.name}>
|
<InputError errors={errors} touched={touched} name={field.name}>
|
||||||
|
|
|
@ -77,7 +77,13 @@ const Input = styled.input<Props>`
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
const Textarea = styled.textarea<Props>`${inputStyle}`;
|
const Textarea = styled.textarea<Props>`
|
||||||
|
${inputStyle};
|
||||||
|
|
||||||
|
& + .input-help {
|
||||||
|
${tw`mt-0`};
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
export { Textarea };
|
export { Textarea };
|
||||||
export default Input;
|
export default Input;
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { FormikErrors, FormikTouched } from 'formik';
|
import { FormikErrors, FormikTouched } from 'formik';
|
||||||
import tw from 'twin.macro';
|
|
||||||
import { capitalize } from '@/helpers';
|
import { capitalize } from '@/helpers';
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
|
@ -12,7 +11,7 @@ interface Props {
|
||||||
|
|
||||||
const InputError = ({ errors, touched, name, children }: Props) => (
|
const InputError = ({ errors, touched, name, children }: Props) => (
|
||||||
touched[name] && errors[name] ?
|
touched[name] && errors[name] ?
|
||||||
<p css={tw`text-xs text-red-400 pt-2`}>
|
<p className={'input-help error'}>
|
||||||
{typeof errors[name] === 'string' ?
|
{typeof errors[name] === 'string' ?
|
||||||
capitalize(errors[name] as string)
|
capitalize(errors[name] as string)
|
||||||
:
|
:
|
||||||
|
@ -21,7 +20,7 @@ const InputError = ({ errors, touched, name, children }: Props) => (
|
||||||
</p>
|
</p>
|
||||||
:
|
:
|
||||||
<>
|
<>
|
||||||
{children ? <p css={tw`text-xs text-neutral-400 pt-2`}>{children}</p> : null}
|
{children ? <p className={'input-help'}>{children}</p> : null}
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -139,7 +139,7 @@ const FileDropdownMenu = ({ file }: { file: FileObject }) => {
|
||||||
<DropdownMenu
|
<DropdownMenu
|
||||||
ref={onClickRef}
|
ref={onClickRef}
|
||||||
renderToggle={onClick => (
|
renderToggle={onClick => (
|
||||||
<div css={tw`p-3 hover:text-white`} onClick={onClick}>
|
<div css={tw`flex items-center hover:text-white ml-4`} onClick={onClick}>
|
||||||
<FontAwesomeIcon icon={faEllipsisH}/>
|
<FontAwesomeIcon icon={faEllipsisH}/>
|
||||||
{modal ?
|
{modal ?
|
||||||
modal === 'chmod' ?
|
modal === 'chmod' ?
|
||||||
|
|
|
@ -14,7 +14,7 @@ import { usePermissions } from '@/plugins/usePermissions';
|
||||||
import { join } from 'path';
|
import { join } from 'path';
|
||||||
|
|
||||||
const Row = styled.div`
|
const Row = styled.div`
|
||||||
${tw`flex bg-neutral-700 rounded-sm mb-px text-sm hover:text-neutral-100 cursor-pointer items-center no-underline hover:bg-neutral-600`};
|
${tw`flex items-center w-full h-10 px-3 rounded-sm cursor-pointer bg-neutral-700 hover:bg-neutral-600 mb-px`};
|
||||||
`;
|
`;
|
||||||
|
|
||||||
const Clickable: React.FC<{ file: FileObject }> = memo(({ file, children }) => {
|
const Clickable: React.FC<{ file: FileObject }> = memo(({ file, children }) => {
|
||||||
|
@ -25,13 +25,14 @@ const Clickable: React.FC<{ file: FileObject }> = memo(({ file, children }) => {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
(!canReadContents || (file.isFile && !file.isEditable())) ?
|
(!canReadContents || (file.isFile && !file.isEditable())) ?
|
||||||
<div css={tw`flex flex-1 text-neutral-300 no-underline p-3 cursor-default overflow-hidden truncate`}>
|
<div css={tw`flex items-center w-full h-full`}>
|
||||||
{children}
|
{children}
|
||||||
</div>
|
</div>
|
||||||
:
|
:
|
||||||
<NavLink
|
<NavLink
|
||||||
to={`${match.url}${file.isFile ? '/edit' : ''}#${encodePathSegments(join(directory, file.name))}`}
|
to={`${match.url}${file.isFile ? '/edit' : ''}#${encodePathSegments(join(directory, file.name))}`}
|
||||||
css={tw`flex flex-1 text-neutral-300 no-underline p-3 overflow-hidden truncate`}
|
css={tw`flex items-center w-full h-full`}
|
||||||
|
draggable={false}
|
||||||
>
|
>
|
||||||
{children}
|
{children}
|
||||||
</NavLink>
|
</NavLink>
|
||||||
|
@ -45,33 +46,37 @@ const FileObjectRow = ({ file }: { file: FileObject }) => (
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
window.dispatchEvent(new CustomEvent(`pterodactyl:files:ctx:${file.key}`, { detail: e.clientX }));
|
window.dispatchEvent(new CustomEvent(`pterodactyl:files:ctx:${file.key}`, { detail: e.clientX }));
|
||||||
}}
|
}}
|
||||||
|
css={tw`h-10`}
|
||||||
>
|
>
|
||||||
<SelectFileCheckbox name={file.name}/>
|
<div css={tw`flex mr-4`}>
|
||||||
|
<SelectFileCheckbox name={file.name}/>
|
||||||
|
</div>
|
||||||
<Clickable file={file}>
|
<Clickable file={file}>
|
||||||
<div css={tw`flex-none self-center text-neutral-400 ml-6 mr-4 text-lg pl-3`}>
|
<div css={tw`flex flex-row items-center justify-center w-5 text-neutral-400 mr-2`}>
|
||||||
{file.isFile ?
|
{file.isFile ?
|
||||||
<FontAwesomeIcon icon={file.isSymlink ? faFileImport : file.isArchiveType() ? faFileArchive : faFileAlt}/>
|
<FontAwesomeIcon icon={file.isSymlink ? faFileImport : file.isArchiveType() ? faFileArchive : faFileAlt}/>
|
||||||
:
|
:
|
||||||
<FontAwesomeIcon icon={faFolder}/>
|
<FontAwesomeIcon icon={faFolder}/>
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
<div css={tw`flex-1 truncate`}>
|
<div css={tw`block`}>
|
||||||
{file.name}
|
<span css={tw`text-sm font-normal leading-none text-neutral-300`}>{file.name}</span>
|
||||||
</div>
|
</div>
|
||||||
{file.isFile &&
|
|
||||||
<div css={tw`w-1/6 text-right mr-4 hidden sm:block`}>
|
<div css={tw`hidden w-24 ml-auto sm:flex`}>
|
||||||
{bytesToHuman(file.size)}
|
<span css={tw`ml-auto text-sm font-normal leading-none text-right text-neutral-300`}>
|
||||||
|
{bytesToHuman(file.size)}
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
}
|
|
||||||
<div
|
<div css={tw`hidden w-48 md:flex`}>
|
||||||
css={tw`w-1/5 text-right mr-4 hidden md:block`}
|
<span css={tw`ml-auto text-sm font-normal leading-none text-right text-neutral-300`} title={file.modifiedAt.toString()}>
|
||||||
title={file.modifiedAt.toString()}
|
{Math.abs(differenceInHours(file.modifiedAt, new Date())) > 48 ?
|
||||||
>
|
format(file.modifiedAt, 'MMM do, yyyy h:mma')
|
||||||
{Math.abs(differenceInHours(file.modifiedAt, new Date())) > 48 ?
|
:
|
||||||
format(file.modifiedAt, 'MMM do, yyyy h:mma')
|
formatDistanceToNow(file.modifiedAt, { addSuffix: true })
|
||||||
:
|
}
|
||||||
formatDistanceToNow(file.modifiedAt, { addSuffix: true })
|
</span>
|
||||||
}
|
|
||||||
</div>
|
</div>
|
||||||
</Clickable>
|
</Clickable>
|
||||||
<FileDropdownMenu file={file}/>
|
<FileDropdownMenu file={file}/>
|
||||||
|
|
|
@ -4,6 +4,8 @@ import Input from '@/components/elements/Input';
|
||||||
import { ServerContext } from '@/state/server';
|
import { ServerContext } from '@/state/server';
|
||||||
|
|
||||||
export const FileActionCheckbox = styled(Input)`
|
export const FileActionCheckbox = styled(Input)`
|
||||||
|
${tw`w-4 h-4 transition-all duration-75 border rounded-sm cursor-pointer border-neutral-500 hover:border-neutral-300 text-primary-400`};
|
||||||
|
|
||||||
&& {
|
&& {
|
||||||
${tw`border-neutral-500 bg-transparent`};
|
${tw`border-neutral-500 bg-transparent`};
|
||||||
|
|
||||||
|
@ -19,20 +21,18 @@ export default ({ name }: { name: string }) => {
|
||||||
const removeSelectedFile = ServerContext.useStoreActions(actions => actions.files.removeSelectedFile);
|
const removeSelectedFile = ServerContext.useStoreActions(actions => actions.files.removeSelectedFile);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<label css={tw`flex-none p-4 absolute self-center z-30 cursor-pointer`}>
|
<FileActionCheckbox
|
||||||
<FileActionCheckbox
|
name={'selectedFiles'}
|
||||||
name={'selectedFiles'}
|
value={name}
|
||||||
value={name}
|
checked={isChecked}
|
||||||
checked={isChecked}
|
type={'checkbox'}
|
||||||
type={'checkbox'}
|
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
|
||||||
onChange={(e: React.ChangeEvent<HTMLInputElement>) => {
|
if (e.currentTarget.checked) {
|
||||||
if (e.currentTarget.checked) {
|
appendSelectedFile(name);
|
||||||
appendSelectedFile(name);
|
} else {
|
||||||
} else {
|
removeSelectedFile(name);
|
||||||
removeSelectedFile(name);
|
}
|
||||||
}
|
}}
|
||||||
}}
|
/>
|
||||||
/>
|
|
||||||
</label>
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in a new issue