mirror of https://github.com/buster-so/buster.git
code card update
Update toaster naming Update BusterNotifications.tsx Update BusterChart.tsx remove theme detector
This commit is contained in:
parent
4b4ba2e21e
commit
61916ce7ce
|
@ -30,9 +30,9 @@ const roundingVariants = {
|
||||||
};
|
};
|
||||||
|
|
||||||
const sizeVariants = {
|
const sizeVariants = {
|
||||||
default: 'h-7',
|
default: 'h-6',
|
||||||
tall: 'h-8',
|
tall: 'h-7',
|
||||||
small: 'h-6'
|
small: 'h-5'
|
||||||
};
|
};
|
||||||
|
|
||||||
export const buttonVariants = cva(
|
export const buttonVariants = cva(
|
||||||
|
|
|
@ -5,6 +5,7 @@ import { cn } from '@/lib/utils';
|
||||||
const sizeVariants = cva('', {
|
const sizeVariants = cva('', {
|
||||||
variants: {
|
variants: {
|
||||||
size: {
|
size: {
|
||||||
|
xsmall: 'h-[32px] min-h-[32px] px-2.5',
|
||||||
small: 'p-2.5',
|
small: 'p-2.5',
|
||||||
default: 'p-4'
|
default: 'p-4'
|
||||||
}
|
}
|
||||||
|
@ -19,7 +20,7 @@ const Card = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElemen
|
||||||
<div
|
<div
|
||||||
ref={ref}
|
ref={ref}
|
||||||
className={cn(
|
className={cn(
|
||||||
'bg-background text-foreground overflow-hidden rounded border shadow',
|
'bg-background text-foreground flex flex-col overflow-hidden rounded border shadow',
|
||||||
className
|
className
|
||||||
)}
|
)}
|
||||||
{...props}
|
{...props}
|
||||||
|
|
|
@ -0,0 +1,91 @@
|
||||||
|
import type { Meta, StoryObj } from '@storybook/react';
|
||||||
|
import { CodeCard } from './CodeCard';
|
||||||
|
|
||||||
|
const meta: Meta<typeof CodeCard> = {
|
||||||
|
title: 'Base/Cards/CodeCard',
|
||||||
|
component: CodeCard,
|
||||||
|
parameters: {
|
||||||
|
layout: 'centered'
|
||||||
|
},
|
||||||
|
tags: ['autodocs'],
|
||||||
|
decorators: [
|
||||||
|
(Story) => (
|
||||||
|
<div className="w-full min-w-[500px]">
|
||||||
|
<Story />
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
||||||
|
export default meta;
|
||||||
|
type Story = StoryObj<typeof CodeCard>;
|
||||||
|
|
||||||
|
const sampleCode = `function helloWorld() {
|
||||||
|
console.log('Hello, World!');
|
||||||
|
}`;
|
||||||
|
|
||||||
|
const longCode = `import React from 'react';
|
||||||
|
import { Button } from 'antd';
|
||||||
|
|
||||||
|
export const MyComponent = () => {
|
||||||
|
const handleClick = () => {
|
||||||
|
console.log('Button clicked!');
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="container">
|
||||||
|
<h1>Hello World</h1>
|
||||||
|
<Button onClick={handleClick}>
|
||||||
|
Click me
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};`;
|
||||||
|
|
||||||
|
export const Default: Story = {
|
||||||
|
args: {
|
||||||
|
code: sampleCode,
|
||||||
|
language: 'javascript',
|
||||||
|
fileName: 'example.js',
|
||||||
|
className: 'w-[500px] h-[300px]'
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export const ReadOnly: Story = {
|
||||||
|
args: {
|
||||||
|
code: sampleCode,
|
||||||
|
language: 'javascript',
|
||||||
|
fileName: 'readonly.js',
|
||||||
|
readOnly: true,
|
||||||
|
className: 'w-[500px] h-[300px]'
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export const LargerEditor: Story = {
|
||||||
|
args: {
|
||||||
|
code: longCode,
|
||||||
|
language: 'typescript',
|
||||||
|
fileName: 'MyComponent.tsx',
|
||||||
|
className: 'w-[600px] h-[400px]'
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export const NoButtons: Story = {
|
||||||
|
args: {
|
||||||
|
code: sampleCode,
|
||||||
|
language: 'javascript',
|
||||||
|
fileName: 'no-buttons.js',
|
||||||
|
buttons: false,
|
||||||
|
className: 'w-[500px] h-[300px]'
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
export const CustomButtons: Story = {
|
||||||
|
args: {
|
||||||
|
code: sampleCode,
|
||||||
|
language: 'javascript',
|
||||||
|
fileName: 'custom-buttons.js',
|
||||||
|
buttons: <div className="px-2">Custom Buttons</div>,
|
||||||
|
className: 'w-[500px] h-[300px]'
|
||||||
|
}
|
||||||
|
};
|
|
@ -1,11 +1,11 @@
|
||||||
import { createStyles } from 'antd-style';
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { Text } from '@/components/ui';
|
import { AppCodeEditor } from '../inputs/AppCodeEditor/AppCodeEditor';
|
||||||
import { AppCodeEditor } from '../inputs/AppCodeEditor';
|
import { Download, Copy } from '../icons';
|
||||||
import { Button } from 'antd';
|
|
||||||
import { AppMaterialIcons } from '../icons';
|
|
||||||
import { useMemoizedFn } from 'ahooks';
|
import { useMemoizedFn } from 'ahooks';
|
||||||
import { useBusterNotifications } from '@/context/BusterNotifications';
|
import { useBusterNotifications } from '@/context/BusterNotifications';
|
||||||
|
import { cn } from '@/lib/classMerge';
|
||||||
|
import { Button } from '../buttons/Button';
|
||||||
|
import { Card, CardHeader, CardContent, CardDescription, CardFooter, CardTitle } from './CardBase';
|
||||||
|
|
||||||
export const CodeCard: React.FC<{
|
export const CodeCard: React.FC<{
|
||||||
code: string;
|
code: string;
|
||||||
|
@ -28,22 +28,17 @@ export const CodeCard: React.FC<{
|
||||||
onChange,
|
onChange,
|
||||||
readOnly = false
|
readOnly = false
|
||||||
}) => {
|
}) => {
|
||||||
const { styles, cx } = useStyles();
|
|
||||||
|
|
||||||
const ShownButtons = buttons === true ? <CardButtons fileName={fileName} code={code} /> : buttons;
|
const ShownButtons = buttons === true ? <CardButtons fileName={fileName} code={code} /> : buttons;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={cx(styles.container, className)}>
|
<Card className={cn('h-full', className)}>
|
||||||
<div
|
<CardHeader variant={'gray'} size={'xsmall'} className="justify-center">
|
||||||
className={cx(
|
<div className="flex items-center justify-between gap-x-1">
|
||||||
styles.containerHeader,
|
<span className="truncate text-base">{fileName}</span>
|
||||||
'flex items-center justify-between space-x-1 px-2.5'
|
|
||||||
)}>
|
|
||||||
<Text className="truncate">{fileName}</Text>
|
|
||||||
|
|
||||||
{ShownButtons}
|
{ShownButtons}
|
||||||
</div>
|
</div>
|
||||||
<div className={cx(styles.containerBody, bodyClassName)}>
|
</CardHeader>
|
||||||
|
<CardContent className={cn('bg-background overflow-hidden p-0', bodyClassName)}>
|
||||||
<AppCodeEditor
|
<AppCodeEditor
|
||||||
language={language}
|
language={language}
|
||||||
value={code}
|
value={code}
|
||||||
|
@ -52,8 +47,8 @@ export const CodeCard: React.FC<{
|
||||||
height="100%"
|
height="100%"
|
||||||
onMetaEnter={onMetaEnter}
|
onMetaEnter={onMetaEnter}
|
||||||
/>
|
/>
|
||||||
</div>
|
</CardContent>
|
||||||
</div>
|
</Card>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -90,15 +85,10 @@ const CardButtons: React.FC<{
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex items-center gap-1">
|
<div className="flex items-center gap-1">
|
||||||
|
<Button variant="ghost" prefix={<Copy />} onClick={handleCopyCode} title="Copy code" />
|
||||||
<Button
|
<Button
|
||||||
type="text"
|
variant="ghost"
|
||||||
icon={<AppMaterialIcons icon="content_copy" />}
|
prefix={<Download />}
|
||||||
onClick={handleCopyCode}
|
|
||||||
title="Copy code"
|
|
||||||
/>
|
|
||||||
<Button
|
|
||||||
type="text"
|
|
||||||
icon={<AppMaterialIcons icon="download" />}
|
|
||||||
onClick={handleDownload}
|
onClick={handleDownload}
|
||||||
title="Download file"
|
title="Download file"
|
||||||
/>
|
/>
|
||||||
|
@ -106,18 +96,3 @@ const CardButtons: React.FC<{
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
CardButtons.displayName = 'CardButtons';
|
CardButtons.displayName = 'CardButtons';
|
||||||
|
|
||||||
const useStyles = createStyles(({ token, css }) => ({
|
|
||||||
container: css`
|
|
||||||
border-radius: ${token.borderRadius}px;
|
|
||||||
border: 0.5px solid ${token.colorBorder};
|
|
||||||
`,
|
|
||||||
containerHeader: css`
|
|
||||||
background: ${token.controlItemBgActive};
|
|
||||||
border-bottom: 0.5px solid ${token.colorBorder};
|
|
||||||
height: 32px;
|
|
||||||
`,
|
|
||||||
containerBody: css`
|
|
||||||
background: ${token.colorBgBase};
|
|
||||||
`
|
|
||||||
}));
|
|
||||||
|
|
|
@ -153,7 +153,7 @@ export const BusterChart: React.FC<BusterChartProps> = React.memo(
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<BusterChartErrorWrapper>
|
<BusterChartErrorWrapper>
|
||||||
<BusterChartWrapper id={id} className={className} bordered={bordered} loading={loading}>
|
<BusterChartWrapper id={id} className={className} loading={loading}>
|
||||||
{SwitchComponent()}
|
{SwitchComponent()}
|
||||||
</BusterChartWrapper>
|
</BusterChartWrapper>
|
||||||
</BusterChartErrorWrapper>
|
</BusterChartErrorWrapper>
|
||||||
|
|
|
@ -36,5 +36,3 @@ export const CircleSpinnerLoader: React.FC<{
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default CircleSpinnerLoader;
|
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import CircleSpinnerLoader from './CircleSpinnerLoader';
|
import { CircleSpinnerLoader } from './CircleSpinnerLoader';
|
||||||
import { Text } from '@/components/ui';
|
|
||||||
|
|
||||||
export const CircleSpinnerLoaderContainer: React.FC<{
|
export const CircleSpinnerLoaderContainer: React.FC<{
|
||||||
text?: string;
|
text?: string;
|
||||||
|
@ -9,7 +8,7 @@ export const CircleSpinnerLoaderContainer: React.FC<{
|
||||||
return (
|
return (
|
||||||
<div className={`flex h-full w-full flex-col items-center justify-center ${className}`}>
|
<div className={`flex h-full w-full flex-col items-center justify-center ${className}`}>
|
||||||
<CircleSpinnerLoader />
|
<CircleSpinnerLoader />
|
||||||
{text && <Text className="mt-3">{text}</Text>}
|
{text && <span className="mt-3 text-base">{text}</span>}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
import { BusterNotificationsProvider } from '@/context/BusterNotifications';
|
|
||||||
import type { Meta, StoryObj } from '@storybook/react';
|
import type { Meta, StoryObj } from '@storybook/react';
|
||||||
import { useBusterNotifications } from '@/context/BusterNotifications';
|
import { useBusterNotifications } from '@/context/BusterNotifications';
|
||||||
|
|
||||||
|
@ -84,11 +83,7 @@ const meta: Meta<typeof TestComponent> = {
|
||||||
},
|
},
|
||||||
decorators: [
|
decorators: [
|
||||||
(Story) => {
|
(Story) => {
|
||||||
return (
|
return <Story />;
|
||||||
<BusterNotificationsProvider>
|
|
||||||
<Story />
|
|
||||||
</BusterNotificationsProvider>
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
};
|
};
|
|
@ -2,13 +2,13 @@
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { useTheme } from 'next-themes';
|
import { useTheme } from 'next-themes';
|
||||||
import { Toaster } from 'sonner';
|
import { Toaster as SonnerToaster } from 'sonner';
|
||||||
import { CircleCheck } from '@/components/ui/icons';
|
import { CircleCheck, CircleXmark, CircleWarning } from '@/components/ui/icons';
|
||||||
|
|
||||||
type ToasterProps = React.ComponentProps<typeof Toaster>;
|
type ToasterProps = React.ComponentProps<typeof SonnerToaster>;
|
||||||
|
|
||||||
const AppToaster = ({ ...props }: ToasterProps) => {
|
export const Toaster = ({ ...props }: ToasterProps) => {
|
||||||
const { theme = 'system' } = useTheme();
|
const { theme = 'light' } = useTheme();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Toaster
|
<Toaster
|
||||||
|
@ -16,7 +16,9 @@ const AppToaster = ({ ...props }: ToasterProps) => {
|
||||||
expand={true}
|
expand={true}
|
||||||
visibleToasts={5}
|
visibleToasts={5}
|
||||||
icons={{
|
icons={{
|
||||||
success: <CircleCheck />
|
success: <CircleCheck />,
|
||||||
|
error: <CircleXmark />,
|
||||||
|
warning: <CircleWarning />
|
||||||
}}
|
}}
|
||||||
swipeDirections={['right']}
|
swipeDirections={['right']}
|
||||||
theme={theme as ToasterProps['theme']}
|
theme={theme as ToasterProps['theme']}
|
||||||
|
@ -24,8 +26,8 @@ const AppToaster = ({ ...props }: ToasterProps) => {
|
||||||
toastOptions={{
|
toastOptions={{
|
||||||
classNames: {
|
classNames: {
|
||||||
toast:
|
toast:
|
||||||
'group toast group-[.toaster]:bg-background group-[.toaster]:text-foreground group-[.toaster]:border-border group-[.toaster]:shadow-lg',
|
'group toast group-[.toaster]:bg-background group-[.toaster]:text-foreground group-[.toaster]:border-border group-[.toaster]:shadow-hard',
|
||||||
description: 'group-[.toast]:text-muted-foreground',
|
description: 'group-[.toast]:text-foreground',
|
||||||
actionButton: 'group-[.toast]:bg-primary group-[.toast]:text-primary-foreground',
|
actionButton: 'group-[.toast]:bg-primary group-[.toast]:text-primary-foreground',
|
||||||
cancelButton: 'group-[.toast]:bg-border group-[.toast]:text-foreground'
|
cancelButton: 'group-[.toast]:bg-border group-[.toast]:text-foreground'
|
||||||
}
|
}
|
||||||
|
@ -34,5 +36,3 @@ const AppToaster = ({ ...props }: ToasterProps) => {
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export { AppToaster };
|
|
|
@ -1 +1 @@
|
||||||
export * from './AppToaster';
|
export * from './Toaster';
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
|
'use client';
|
||||||
|
|
||||||
import React, { PropsWithChildren } from 'react';
|
import React, { PropsWithChildren } from 'react';
|
||||||
// import { App, ModalFuncProps } from 'antd';
|
|
||||||
import { toast, type ExternalToast } from 'sonner';
|
import { toast, type ExternalToast } from 'sonner';
|
||||||
// import { createStyles } from 'antd-style';
|
|
||||||
import { useMemoizedFn } from 'ahooks';
|
import { useMemoizedFn } from 'ahooks';
|
||||||
import {
|
import {
|
||||||
useContextSelector,
|
useContextSelector,
|
||||||
|
@ -22,35 +22,7 @@ export interface NotificationProps {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// const useStyles = createStyles(({ token, css }) => ({
|
|
||||||
// modal: css`
|
|
||||||
// .busterv2-modal-body {
|
|
||||||
// padding: 0px !important;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// .busterv2-modal-confirm-body {
|
|
||||||
// padding: 24px 32px 16px 32px !important;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// .busterv2-modal-confirm-btns {
|
|
||||||
// margin-top: 0px !important;
|
|
||||||
// padding: 12px 32px !important;
|
|
||||||
// border-top: 0.5px solid ${token.colorBorder};
|
|
||||||
// display: flex;
|
|
||||||
// align-items: center;
|
|
||||||
// justify-content: flex-end;
|
|
||||||
// }
|
|
||||||
|
|
||||||
// .busterv2-modal-confirm-content {
|
|
||||||
// color: ${token.colorTextSecondary} !important;
|
|
||||||
// }
|
|
||||||
// `
|
|
||||||
// }));
|
|
||||||
|
|
||||||
export const useBusterNotificationsInternal = () => {
|
export const useBusterNotificationsInternal = () => {
|
||||||
// const { message, notification, modal } = App.useApp();
|
|
||||||
// const { cx, styles } = useStyles();
|
|
||||||
|
|
||||||
const openNotification = useMemoizedFn((props: NotificationProps) => {
|
const openNotification = useMemoizedFn((props: NotificationProps) => {
|
||||||
const { title, message, type } = props;
|
const { title, message, type } = props;
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
export * from './useThemeDetector';
|
|
||||||
export * from './usePreventBackwardsNavigation';
|
export * from './usePreventBackwardsNavigation';
|
||||||
export * from './useIsShowingEllipsis';
|
export * from './useIsShowingEllipsis';
|
||||||
export * from './useBeforeUnload';
|
export * from './useBeforeUnload';
|
||||||
|
|
|
@ -1,57 +0,0 @@
|
||||||
'use client';
|
|
||||||
|
|
||||||
import { ENABLE_DARK_MODE } from '@/context/BusterStyles/BusterStyles';
|
|
||||||
import { useMemoizedFn } from 'ahooks';
|
|
||||||
import { useEffect, useLayoutEffect, useState } from 'react';
|
|
||||||
import { isServer } from '@tanstack/react-query';
|
|
||||||
|
|
||||||
const DARK_MODE_MEDIA = '(prefers-color-scheme: dark)';
|
|
||||||
|
|
||||||
export const useThemeDetector = ({ addDarkClass }: { addDarkClass?: boolean }) => {
|
|
||||||
const [isDarkTheme, setIsDarkTheme] = useState(() => getSystemTheme());
|
|
||||||
|
|
||||||
const getSystemTheme = (e?: MediaQueryList | MediaQueryListEvent) => {
|
|
||||||
if (!ENABLE_DARK_MODE) return false;
|
|
||||||
if (isServer) return false;
|
|
||||||
if (!e) e = window.matchMedia(DARK_MODE_MEDIA);
|
|
||||||
const isDark = e.matches;
|
|
||||||
return isDark;
|
|
||||||
};
|
|
||||||
|
|
||||||
const getCurrentTheme = useMemoizedFn(() => {
|
|
||||||
if (!isServer) {
|
|
||||||
document.documentElement.style.display = 'none';
|
|
||||||
|
|
||||||
const isDarkMode = getSystemTheme();
|
|
||||||
|
|
||||||
if (addDarkClass) {
|
|
||||||
const d = document.documentElement;
|
|
||||||
d.classList.toggle('dark', isDarkMode);
|
|
||||||
d.classList.toggle('bg-black', isDarkMode);
|
|
||||||
d.setAttribute('data-color-scheme', !isDarkMode ? 'light' : 'dark');
|
|
||||||
}
|
|
||||||
|
|
||||||
// trigger reflow so that overflow style is applied
|
|
||||||
document.documentElement.style.display = '';
|
|
||||||
|
|
||||||
return isDarkMode;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
});
|
|
||||||
|
|
||||||
const mqListener = useMemoizedFn(() => {
|
|
||||||
setIsDarkTheme(getCurrentTheme());
|
|
||||||
});
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
const darkThemeMq = window.matchMedia(DARK_MODE_MEDIA);
|
|
||||||
darkThemeMq.addEventListener('change', mqListener);
|
|
||||||
return () => darkThemeMq.removeEventListener('change', mqListener);
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
useLayoutEffect(() => {
|
|
||||||
setIsDarkTheme(getCurrentTheme());
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
return isDarkTheme;
|
|
||||||
};
|
|
Loading…
Reference in New Issue