Logic improvements, move stat blocks to right side

This commit is contained in:
DaneEveritt 2022-06-27 19:56:26 -04:00
parent ad6e9f076b
commit bf287c45d6
No known key found for this signature in database
GPG key ID: EEA66103B3D71F53
5 changed files with 27 additions and 32 deletions

View file

@ -4,7 +4,7 @@ import Portal from '@/components/elements/Portal';
import copy from 'copy-to-clipboard'; import copy from 'copy-to-clipboard';
import classNames from 'classnames'; import classNames from 'classnames';
const CopyOnClick: React.FC<{ text: any; disabled?: boolean }> = ({ text, disabled, children }) => { const CopyOnClick: React.FC<{ text: string | number | null | undefined }> = ({ text, children }) => {
const [copied, setCopied] = useState(false); const [copied, setCopied] = useState(false);
useEffect(() => { useEffect(() => {
@ -23,12 +23,12 @@ const CopyOnClick: React.FC<{ text: any; disabled?: boolean }> = ({ text, disabl
throw new Error('Component passed to <CopyOnClick/> must be a valid React element.'); throw new Error('Component passed to <CopyOnClick/> must be a valid React element.');
} }
const child = disabled const child = !text
? React.Children.only(children) ? React.Children.only(children)
: React.cloneElement(React.Children.only(children), { : React.cloneElement(React.Children.only(children), {
className: classNames(children.props.className || '', 'cursor-pointer'), className: classNames(children.props.className || '', 'cursor-pointer'),
onClick: (e: React.MouseEvent<HTMLElement>) => { onClick: (e: React.MouseEvent<HTMLElement>) => {
copy(text); copy(String(text));
setCopied(true); setCopied(true);
if (typeof children.props.onClick === 'function') { if (typeof children.props.onClick === 'function') {
children.props.onClick(e); children.props.onClick(e);

View file

@ -50,7 +50,7 @@ export default ({ className }: PowerButtonProps) => {
</Dialog.Confirm> </Dialog.Confirm>
<Can action={'control.start'}> <Can action={'control.start'}>
<Button <Button
className={'w-full sm:w-24'} className={'flex-1'}
disabled={status !== 'offline'} disabled={status !== 'offline'}
onClick={onButtonClick.bind(this, 'start')} onClick={onButtonClick.bind(this, 'start')}
> >
@ -58,17 +58,13 @@ export default ({ className }: PowerButtonProps) => {
</Button> </Button>
</Can> </Can>
<Can action={'control.restart'}> <Can action={'control.restart'}>
<Button.Text <Button.Text className={'flex-1'} disabled={!status} onClick={onButtonClick.bind(this, 'restart')}>
className={'w-full sm:w-24'}
disabled={!status}
onClick={onButtonClick.bind(this, 'restart')}
>
Restart Restart
</Button.Text> </Button.Text>
</Can> </Can>
<Can action={'control.stop'}> <Can action={'control.stop'}>
<Button.Danger <Button.Danger
className={'w-full sm:w-24'} className={'flex-1'}
disabled={status === 'offline'} disabled={status === 'offline'}
onClick={onButtonClick.bind(this, killable ? 'kill' : 'stop')} onClick={onButtonClick.bind(this, killable ? 'kill' : 'stop')}
> >

View file

@ -23,24 +23,24 @@ const ServerConsoleContainer = () => {
return ( return (
<ServerContentBlock title={'Console'} className={'flex flex-col gap-2 sm:gap-4'}> <ServerContentBlock title={'Console'} className={'flex flex-col gap-2 sm:gap-4'}>
<div className={'flex gap-4 items-end'}> <div className={'grid grid-cols-4 gap-4'}>
<div className={'hidden sm:block flex-1'}> <div className={'hidden sm:block sm:col-span-2 lg:col-span-3 pr-4'}>
<h1 className={'font-header text-2xl text-gray-50 leading-relaxed line-clamp-1'}>{name}</h1> <h1 className={'font-header text-2xl text-gray-50 leading-relaxed line-clamp-1'}>{name}</h1>
<p className={'text-sm line-clamp-2'}>{description}</p> <p className={'text-sm line-clamp-2'}>{description}</p>
</div> </div>
<div className={'flex-1'}> <div className={'col-span-4 sm:col-span-2 lg:col-span-1 self-end'}>
<Can action={['control.start', 'control.stop', 'control.restart']} matchAny> <Can action={['control.start', 'control.stop', 'control.restart']} matchAny>
<PowerButtons className={'flex sm:justify-end space-x-2'} /> <PowerButtons className={'flex sm:justify-end space-x-2'} />
</Can> </Can>
</div> </div>
</div> </div>
<div className={'grid grid-cols-4 gap-2 sm:gap-4'}> <div className={'grid grid-cols-4 gap-2 sm:gap-4'}>
<ServerDetailsBlock className={'col-span-4 lg:col-span-1 order-last lg:order-none'} />
<div className={'col-span-4 lg:col-span-3'}> <div className={'col-span-4 lg:col-span-3'}>
<Spinner.Suspense> <Spinner.Suspense>
<Console /> <Console />
</Spinner.Suspense> </Spinner.Suspense>
</div> </div>
<ServerDetailsBlock className={'col-span-4 lg:col-span-1 order-last lg:order-none'} />
{isInstalling ? ( {isInstalling ? (
<div css={tw`mt-4 rounded bg-yellow-500 p-3`}> <div css={tw`mt-4 rounded bg-yellow-500 p-3`}>
<ContentContainer> <ContentContainer>

View file

@ -22,20 +22,20 @@ export default ({ title, copyOnClick, icon, color, description, className, child
return ( return (
<Tooltip arrow placement={'top'} disabled={!description} content={description || ''}> <Tooltip arrow placement={'top'} disabled={!description} content={description || ''}>
<CopyOnClick text={copyOnClick} disabled={!copyOnClick}> <div className={classNames(styles.stat_block, 'bg-gray-600', className)}>
<div className={classNames(styles.stat_block, 'bg-gray-600', className)}> <div className={classNames(styles.status_bar, color || 'bg-gray-700')} />
<div className={classNames(styles.status_bar, color || 'bg-gray-700')} /> <div className={classNames(styles.icon, color || 'bg-gray-700')}>
<div className={classNames(styles.icon, color || 'bg-gray-700')}> <Icon
<Icon icon={icon}
icon={icon} className={classNames({
className={classNames({ 'text-gray-100': !color || color === 'bg-gray-700',
'text-gray-100': !color || color === 'bg-gray-700', 'text-gray-50': color && color !== 'bg-gray-700',
'text-gray-50': color && color !== 'bg-gray-700', })}
})} />
/> </div>
</div> <div className={'flex flex-col justify-center overflow-hidden w-full'}>
<div className={'flex flex-col justify-center overflow-hidden w-full'}> <p className={'font-header leading-tight text-xs md:text-sm text-gray-200'}>{title}</p>
<p className={'font-header leading-tight text-xs md:text-sm text-gray-200'}>{title}</p> <CopyOnClick text={copyOnClick}>
<div <div
ref={ref} ref={ref}
className={'h-[1.75rem] w-full font-semibold text-gray-50 truncate'} className={'h-[1.75rem] w-full font-semibold text-gray-50 truncate'}
@ -43,9 +43,9 @@ export default ({ title, copyOnClick, icon, color, description, className, child
> >
{children} {children}
</div> </div>
</div> </CopyOnClick>
</div> </div>
</CopyOnClick> </div>
</Tooltip> </Tooltip>
); );
}; };

View file

@ -2,8 +2,7 @@
* Determines if the value provided to the function is an object type that * Determines if the value provided to the function is an object type that
* is not null. * is not null.
*/ */
// eslint-disable-next-line @typescript-eslint/ban-types function isObject(val: unknown): val is Record<string, unknown> {
function isObject(val: unknown): val is {} {
return typeof val === 'object' && val !== null && !Array.isArray(val); return typeof val === 'object' && val !== null && !Array.isArray(val);
} }