1
0
Fork 0
mirror of https://github.com/portainer/portainer.git synced 2025-07-24 15:59:41 +02:00

refactor(app): move react components to react codebase [EE-3179] (#6971)

This commit is contained in:
Chaim Lev-Ari 2022-06-17 19:18:42 +03:00 committed by GitHub
parent 212400c283
commit 18252ab854
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
346 changed files with 642 additions and 644 deletions

View file

@ -0,0 +1,8 @@
export function Loading() {
return (
<div className="loading">
<div className="double-bounce1" />
<div className="double-bounce2" />
</div>
);
}

View file

@ -0,0 +1,91 @@
import type { Meta } from '@storybook/react';
import { Widget } from './Widget';
import { WidgetBody } from './WidgetBody';
import { WidgetTitle } from './WidgetTitle';
import { WidgetFooter } from './WidgetFooter';
import { WidgetTaskbar } from './WidgetTaskbar';
interface WidgetProps {
loading: boolean;
title: string;
icon: string;
bodyText: string;
footerText: string;
}
const meta: Meta<WidgetProps> = {
title: 'Widget',
component: Widget,
args: {
loading: false,
title: 'Title',
icon: 'fa-rocket',
bodyText: 'Body',
footerText: 'Footer',
},
};
export default meta;
export { Default, WidgetWithCustomImage, WidgetWithTaskBar };
function Default({ loading, bodyText, footerText, icon, title }: WidgetProps) {
return (
<Widget>
<WidgetTitle title={title} icon={icon} />
<WidgetBody loading={loading}>{bodyText}</WidgetBody>
<WidgetFooter>{footerText}</WidgetFooter>
</Widget>
);
}
function WidgetWithCustomImage({
loading,
bodyText,
footerText,
icon,
title,
}: WidgetProps) {
return (
<Widget>
<WidgetTitle
title={title}
icon={
<img
className="custom-header-ico space-right"
src={icon}
alt="header-icon"
/>
}
/>
<WidgetBody loading={loading}>{bodyText}</WidgetBody>
<WidgetFooter>{footerText}</WidgetFooter>
</Widget>
);
}
WidgetWithCustomImage.args = {
icon: 'https://via.placeholder.com/150',
};
function WidgetWithTaskBar({
loading,
bodyText,
footerText,
icon,
title,
}: WidgetProps) {
return (
<Widget>
<WidgetTitle title={title} icon={icon} />
<WidgetTaskbar>
<button type="button" className="btn btn-primary">
Button
</button>
</WidgetTaskbar>
<WidgetBody loading={loading}>{bodyText}</WidgetBody>
<WidgetFooter>{footerText}</WidgetFooter>
</Widget>
);
}

View file

@ -0,0 +1,19 @@
import { createContext, PropsWithChildren, useContext } from 'react';
const Context = createContext<null | boolean>(null);
export function useWidgetContext() {
const context = useContext(Context);
if (context == null) {
throw new Error('Should be inside a Widget component');
}
}
export function Widget({ children }: PropsWithChildren<unknown>) {
return (
<Context.Provider value>
<div className="widget">{children}</div>
</Context.Provider>
);
}

View file

@ -0,0 +1,24 @@
import clsx from 'clsx';
import { PropsWithChildren } from 'react';
import { useWidgetContext } from './Widget';
import { Loading } from './Loading';
interface Props {
loading?: boolean;
className?: string;
}
export function WidgetBody({
loading,
className,
children,
}: PropsWithChildren<Props>) {
useWidgetContext();
return (
<div className={clsx(className, 'widget-body')}>
{loading ? <Loading /> : <div className="widget-content">{children}</div>}
</div>
);
}

View file

@ -0,0 +1,9 @@
import { PropsWithChildren } from 'react';
import { useWidgetContext } from './Widget';
export function WidgetFooter({ children }: PropsWithChildren<unknown>) {
useWidgetContext();
return <div className="widget-footer">{children}</div>;
}

View file

@ -0,0 +1,22 @@
import { PropsWithChildren } from 'react';
import { useWidgetContext } from './Widget';
interface Props {
className?: string;
}
export function WidgetTaskbar({
children,
className,
}: PropsWithChildren<Props>) {
useWidgetContext();
return (
<div className="widget-header">
<div className="row">
<div className={className}>{children}</div>
</div>
</div>
);
}

View file

@ -0,0 +1,31 @@
import clsx from 'clsx';
import { PropsWithChildren, ReactNode } from 'react';
import { useWidgetContext } from './Widget';
interface Props {
title: ReactNode;
icon: ReactNode;
className?: string;
}
export function WidgetTitle({
title,
icon,
className,
children,
}: PropsWithChildren<Props>) {
useWidgetContext();
return (
<div className="widget-header">
<div className="row">
<span className={clsx('pull-left', className)}>
{typeof icon === 'string' ? <i className={clsx('fa', icon)} /> : icon}
<span>{title}</span>
</span>
<span className={clsx('pull-right', className)}>{children}</span>
</div>
</div>
);
}

View file

@ -0,0 +1,31 @@
import { Widget as MainComponent } from './Widget';
import { WidgetBody } from './WidgetBody';
import { WidgetFooter } from './WidgetFooter';
import { WidgetTitle } from './WidgetTitle';
import { WidgetTaskbar } from './WidgetTaskbar';
import { Loading } from './Loading';
interface WithSubcomponents {
Body: typeof WidgetBody;
Footer: typeof WidgetFooter;
Title: typeof WidgetTitle;
Taskbar: typeof WidgetTaskbar;
Loading: typeof Loading;
}
const Widget = MainComponent as typeof MainComponent & WithSubcomponents;
Widget.Body = WidgetBody;
Widget.Footer = WidgetFooter;
Widget.Title = WidgetTitle;
Widget.Taskbar = WidgetTaskbar;
Widget.Loading = Loading;
export {
Widget,
WidgetBody,
WidgetFooter,
WidgetTitle,
WidgetTaskbar,
Loading,
};