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 = { 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(

View File

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

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 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' {ShownButtons}
)}> </div>
<Text className="truncate">{fileName}</Text> </CardHeader>
<CardContent className={cn('bg-background overflow-hidden p-0', bodyClassName)}>
{ShownButtons}
</div>
<div className={cx(styles.containerBody, 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};
`
}));

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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