code card update

Update toaster naming

Update BusterNotifications.tsx

Update BusterChart.tsx

remove theme detector
This commit is contained in:
Nate Kelley 2025-02-26 17:27:02 -07:00
parent 4b4ba2e21e
commit 61916ce7ce
No known key found for this signature in database
GPG Key ID: FD90372AB8D98B4F
13 changed files with 131 additions and 158 deletions

View File

@ -30,9 +30,9 @@ const roundingVariants = {
};
const sizeVariants = {
default: 'h-7',
tall: 'h-8',
small: 'h-6'
default: 'h-6',
tall: 'h-7',
small: 'h-5'
};
export const buttonVariants = cva(

View File

@ -5,6 +5,7 @@ import { cn } from '@/lib/utils';
const sizeVariants = cva('', {
variants: {
size: {
xsmall: 'h-[32px] min-h-[32px] px-2.5',
small: 'p-2.5',
default: 'p-4'
}
@ -19,7 +20,7 @@ const Card = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElemen
<div
ref={ref}
className={cn(
'bg-background text-foreground overflow-hidden rounded border shadow',
'bg-background text-foreground flex flex-col overflow-hidden rounded border shadow',
className
)}
{...props}

View File

@ -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]'
}
};

View File

@ -1,11 +1,11 @@
import { createStyles } from 'antd-style';
import React from 'react';
import { Text } from '@/components/ui';
import { AppCodeEditor } from '../inputs/AppCodeEditor';
import { Button } from 'antd';
import { AppMaterialIcons } from '../icons';
import { AppCodeEditor } from '../inputs/AppCodeEditor/AppCodeEditor';
import { Download, Copy } from '../icons';
import { useMemoizedFn } from 'ahooks';
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<{
code: string;
@ -28,22 +28,17 @@ export const CodeCard: React.FC<{
onChange,
readOnly = false
}) => {
const { styles, cx } = useStyles();
const ShownButtons = buttons === true ? <CardButtons fileName={fileName} code={code} /> : buttons;
return (
<div className={cx(styles.container, className)}>
<div
className={cx(
styles.containerHeader,
'flex items-center justify-between space-x-1 px-2.5'
)}>
<Text className="truncate">{fileName}</Text>
{ShownButtons}
</div>
<div className={cx(styles.containerBody, bodyClassName)}>
<Card className={cn('h-full', className)}>
<CardHeader variant={'gray'} size={'xsmall'} className="justify-center">
<div className="flex items-center justify-between gap-x-1">
<span className="truncate text-base">{fileName}</span>
{ShownButtons}
</div>
</CardHeader>
<CardContent className={cn('bg-background overflow-hidden p-0', bodyClassName)}>
<AppCodeEditor
language={language}
value={code}
@ -52,8 +47,8 @@ export const CodeCard: React.FC<{
height="100%"
onMetaEnter={onMetaEnter}
/>
</div>
</div>
</CardContent>
</Card>
);
};
@ -90,15 +85,10 @@ const CardButtons: React.FC<{
return (
<div className="flex items-center gap-1">
<Button variant="ghost" prefix={<Copy />} onClick={handleCopyCode} title="Copy code" />
<Button
type="text"
icon={<AppMaterialIcons icon="content_copy" />}
onClick={handleCopyCode}
title="Copy code"
/>
<Button
type="text"
icon={<AppMaterialIcons icon="download" />}
variant="ghost"
prefix={<Download />}
onClick={handleDownload}
title="Download file"
/>
@ -106,18 +96,3 @@ const CardButtons: React.FC<{
);
});
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};
`
}));

View File

@ -153,7 +153,7 @@ export const BusterChart: React.FC<BusterChartProps> = React.memo(
return (
<BusterChartErrorWrapper>
<BusterChartWrapper id={id} className={className} bordered={bordered} loading={loading}>
<BusterChartWrapper id={id} className={className} loading={loading}>
{SwitchComponent()}
</BusterChartWrapper>
</BusterChartErrorWrapper>

View File

@ -36,5 +36,3 @@ export const CircleSpinnerLoader: React.FC<{
</div>
);
};
export default CircleSpinnerLoader;

View File

@ -1,6 +1,5 @@
import React from 'react';
import CircleSpinnerLoader from './CircleSpinnerLoader';
import { Text } from '@/components/ui';
import { CircleSpinnerLoader } from './CircleSpinnerLoader';
export const CircleSpinnerLoaderContainer: React.FC<{
text?: string;
@ -9,7 +8,7 @@ export const CircleSpinnerLoaderContainer: React.FC<{
return (
<div className={`flex h-full w-full flex-col items-center justify-center ${className}`}>
<CircleSpinnerLoader />
{text && <Text className="mt-3">{text}</Text>}
{text && <span className="mt-3 text-base">{text}</span>}
</div>
);
};

View File

@ -1,4 +1,3 @@
import { BusterNotificationsProvider } from '@/context/BusterNotifications';
import type { Meta, StoryObj } from '@storybook/react';
import { useBusterNotifications } from '@/context/BusterNotifications';
@ -84,11 +83,7 @@ const meta: Meta<typeof TestComponent> = {
},
decorators: [
(Story) => {
return (
<BusterNotificationsProvider>
<Story />
</BusterNotificationsProvider>
);
return <Story />;
}
]
};

View File

@ -2,13 +2,13 @@
import React from 'react';
import { useTheme } from 'next-themes';
import { Toaster } from 'sonner';
import { CircleCheck } from '@/components/ui/icons';
import { Toaster as SonnerToaster } from 'sonner';
import { CircleCheck, CircleXmark, CircleWarning } from '@/components/ui/icons';
type ToasterProps = React.ComponentProps<typeof Toaster>;
type ToasterProps = React.ComponentProps<typeof SonnerToaster>;
const AppToaster = ({ ...props }: ToasterProps) => {
const { theme = 'system' } = useTheme();
export const Toaster = ({ ...props }: ToasterProps) => {
const { theme = 'light' } = useTheme();
return (
<Toaster
@ -16,7 +16,9 @@ const AppToaster = ({ ...props }: ToasterProps) => {
expand={true}
visibleToasts={5}
icons={{
success: <CircleCheck />
success: <CircleCheck />,
error: <CircleXmark />,
warning: <CircleWarning />
}}
swipeDirections={['right']}
theme={theme as ToasterProps['theme']}
@ -24,8 +26,8 @@ const AppToaster = ({ ...props }: ToasterProps) => {
toastOptions={{
classNames: {
toast:
'group toast group-[.toaster]:bg-background group-[.toaster]:text-foreground group-[.toaster]:border-border group-[.toaster]:shadow-lg',
description: 'group-[.toast]:text-muted-foreground',
'group toast group-[.toaster]:bg-background group-[.toaster]:text-foreground group-[.toaster]:border-border group-[.toaster]:shadow-hard',
description: 'group-[.toast]:text-foreground',
actionButton: 'group-[.toast]:bg-primary group-[.toast]:text-primary-foreground',
cancelButton: 'group-[.toast]:bg-border group-[.toast]:text-foreground'
}
@ -34,5 +36,3 @@ const AppToaster = ({ ...props }: ToasterProps) => {
/>
);
};
export { AppToaster };

View File

@ -1 +1 @@
export * from './AppToaster';
export * from './Toaster';

View File

@ -1,7 +1,7 @@
'use client';
import React, { PropsWithChildren } from 'react';
// import { App, ModalFuncProps } from 'antd';
import { toast, type ExternalToast } from 'sonner';
// import { createStyles } from 'antd-style';
import { useMemoizedFn } from 'ahooks';
import {
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 = () => {
// const { message, notification, modal } = App.useApp();
// const { cx, styles } = useStyles();
const openNotification = useMemoizedFn((props: NotificationProps) => {
const { title, message, type } = props;

View File

@ -1,4 +1,3 @@
export * from './useThemeDetector';
export * from './usePreventBackwardsNavigation';
export * from './useIsShowingEllipsis';
export * from './useBeforeUnload';

View File

@ -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;
};