Skip to content

Commit

Permalink
feat: new backend dashboard [wip][ref Codeinwp/neve-pro-addon#2914]
Browse files Browse the repository at this point in the history
  • Loading branch information
abaicus committed Dec 20, 2024
1 parent 5a91060 commit d5d23ab
Show file tree
Hide file tree
Showing 39 changed files with 1,610 additions and 966 deletions.
38 changes: 22 additions & 16 deletions assets/apps/dashboard/src/Components/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,9 @@ import { fetchOptions } from '../utils/rest';

import { withDispatch, withSelect } from '@wordpress/data';
import { compose } from '@wordpress/compose';
import { useState, Fragment, useEffect } from '@wordpress/element';
import { useState, useEffect } from '@wordpress/element';
import Deal from './Deal';

Check failure on line 12 in assets/apps/dashboard/src/Components/App.js

View workflow job for this annotation

GitHub Actions / npm (14.x)

'Deal' is defined but never used
import Container from '../Layout/Container';

const App = ({ setSettings, toast, currentTab, setTab }) => {
const [loading, setLoading] = useState(true);
Expand All @@ -19,27 +20,32 @@ const App = ({ setSettings, toast, currentTab, setTab }) => {
setLoading(false);
});
}, []);

if (loading) {
return <Loading />;
}

return (
<Fragment>
<Header currentTab={currentTab} setTab={setTab} />
<div className="content-wrap">
<div className="container content">
<div className="main">
<Deal />
{'starter-sites' !== currentTab && <Notifications />}
<TabsContent currentTab={currentTab} setTab={setTab} />
</div>
{'starter-sites' !== currentTab &&
'custom-layouts' !== currentTab && (
<Sidebar currentTab={currentTab} />
)}
<div className="antialiased grow flex flex-col gap-6 h-full">
<Header />

{/*<Deal />*/}
{'starter-sites' !== currentTab && <Notifications />}

<Container className="flex flex-col md:flex-row gap-6 h-full grow">
<div className="grow">
<TabsContent currentTab={currentTab} setTab={setTab} />
</div>
</div>

{'starter-sites' !== currentTab && (
<div className="shrink-0 md:w-[350px]">
<Sidebar />
</div>
)}
</Container>

{toast && <Snackbar />}
</Fragment>
</div>
);
};

Expand Down
77 changes: 77 additions & 0 deletions assets/apps/dashboard/src/Components/Common/Button.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import cn from 'classnames';
import { LoaderCircle } from 'lucide-react';
import PropTypes from 'prop-types';

const Button = (props) => {
const {
href,
onClick,
className,
isSubmit,
isPrimary,
isSecondary,
isLink,
children,
disabled,
loading,
} = props;

const classNames = cn([
'flex items-center px-3 py-2 transition-colors duration-150 rounded text-sm border gap-2',
{
'border-transparent bg-blue-600 text-white hover:bg-blue-700 hover:text-white':
isPrimary,
'border-blue-600 text-blue-600 hover:bg-blue-600 hover:text-white':
isSecondary,
'border-transparent text-gray-600 hover:text-gray-900': isLink,
'cursor-not-allowed opacity-50 pointer-events-none': disabled,
},
className,
]);

const passedProps = {
className: classNames,
onClick,
};

if (isSubmit) {
passedProps.type = 'submit';
}

if (href) {
passedProps.href = href;
}

if (props.target) {
passedProps.target = props.target;

if (props.target === '_blank') {
passedProps.rel = 'noopener noreferrer';
}
}

const TAG = href && !onClick ? 'a' : 'button';

return (
<TAG {...passedProps}>
{loading && <LoaderCircle size={18} className="animate-spin" />}

{children}
</TAG>
);
};

Button.propTypes = {
href: PropTypes.string,
onClick: PropTypes.func,
className: PropTypes.string,
isSubmit: PropTypes.bool,
isPrimary: PropTypes.bool,
isSecondary: PropTypes.bool,
isLink: PropTypes.bool,
children: PropTypes.node,
disabled: PropTypes.bool,
target: PropTypes.oneOf(['_blank', '_self', '_parent', '_top']),
};

export default Button;
36 changes: 36 additions & 0 deletions assets/apps/dashboard/src/Components/Common/Link.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { __ } from '@wordpress/i18n';

import { LucideExternalLink } from 'lucide-react';
import cn from 'classnames';

export default ({ text, url, isExternal, className }) => {
const linkClasses = cn([
'text-blue-600 hover:text-blue-700 hover:underline text-sm',
className,
{
'inline-flex gap-1.5 items-center': isExternal,
},
]);
if (!isExternal) {
return (
<a href={url} className={linkClasses}>
{text}
</a>
);
}

return (
<a
href={url}
target="_blank"
rel="noopener noreferrer"
className={linkClasses}
>
{text}
<span className="sr-only">
{__('(opens in a new tab)', 'neve')}
</span>
<LucideExternalLink size={16} className="shrink-0" />
</a>
);
};
79 changes: 79 additions & 0 deletions assets/apps/dashboard/src/Components/Common/Notice.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
import { useEffect } from '@wordpress/element';
import cn from 'classnames';
import {
LucideCircleAlert,
LucideCircleCheck,
LucideCircleX,
LucideInfo,
} from 'lucide-react';

const Notice = ({
children,
className = '',

// Type variants
isSuccess = false,
isWarning = false,
isError = false,

// Optional custom icon
icon: CustomIcon,
isAutoDismiss: autoDismiss = 0,
onDismiss = () => {},
}) => {
useEffect(() => {
if (autoDismiss < 1000) return;

const dismissTimeout = setTimeout(() => {
onDismiss();
}, autoDismiss);

return () => {
clearTimeout(dismissTimeout);
};
}, [autoDismiss, onDismiss]);

if (!children) return null;

const getTypeClasses = () => {
if (isSuccess) return 'border-lime-300 bg-lime-50 text-lime-800';
if (isWarning) return 'border-orange-300 bg-orange-50 text-yellow-800';
if (isError) return 'border-red-300 bg-red-50 text-red-800';
return 'border-sky-300 bg-sky-50 text-sky-800';
};

const getIcon = () => {
if (CustomIcon) return CustomIcon;
if (isSuccess) return LucideCircleCheck;
if (isWarning) return LucideCircleAlert;
if (isError) return LucideCircleX;
return LucideInfo;
};

const iconColor = {
'text-lime-500': isSuccess,
'text-orange-500': isWarning,
'text-red-500': isError,
'text-sky-500': !isSuccess && !isWarning && !isError,
};

const Icon = getIcon();

return (
<div
className={cn(
'flex gap-2 p-3 rounded border transition-all duration-500 items-center',
getTypeClasses(),
className
)}
>
<Icon className={cn('size-4.5 shrink-0 mt-0.5', iconColor)} />

<div className="flex-1 flex flex-col gap-1">
{children && <div className="text-sm">{children}</div>}
</div>
</div>
);
};

export default Notice;
Loading

0 comments on commit d5d23ab

Please sign in to comment.