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:
parent
212400c283
commit
18252ab854
346 changed files with 642 additions and 644 deletions
8
app/react/components/Widget/Loading.tsx
Normal file
8
app/react/components/Widget/Loading.tsx
Normal file
|
@ -0,0 +1,8 @@
|
|||
export function Loading() {
|
||||
return (
|
||||
<div className="loading">
|
||||
<div className="double-bounce1" />
|
||||
<div className="double-bounce2" />
|
||||
</div>
|
||||
);
|
||||
}
|
91
app/react/components/Widget/Widget.stories.tsx
Normal file
91
app/react/components/Widget/Widget.stories.tsx
Normal 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>
|
||||
);
|
||||
}
|
19
app/react/components/Widget/Widget.tsx
Normal file
19
app/react/components/Widget/Widget.tsx
Normal 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>
|
||||
);
|
||||
}
|
24
app/react/components/Widget/WidgetBody.tsx
Normal file
24
app/react/components/Widget/WidgetBody.tsx
Normal 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>
|
||||
);
|
||||
}
|
9
app/react/components/Widget/WidgetFooter.tsx
Normal file
9
app/react/components/Widget/WidgetFooter.tsx
Normal 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>;
|
||||
}
|
22
app/react/components/Widget/WidgetTaskbar.tsx
Normal file
22
app/react/components/Widget/WidgetTaskbar.tsx
Normal 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>
|
||||
);
|
||||
}
|
31
app/react/components/Widget/WidgetTitle.tsx
Normal file
31
app/react/components/Widget/WidgetTitle.tsx
Normal 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>
|
||||
);
|
||||
}
|
31
app/react/components/Widget/index.ts
Normal file
31
app/react/components/Widget/index.ts
Normal 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,
|
||||
};
|
Loading…
Add table
Add a link
Reference in a new issue