mirror of
https://github.com/chartdb/chartdb.git
synced 2025-11-03 21:43:23 +00:00
fix(examples): add loader (#678)
This commit is contained in:
@@ -1,4 +1,4 @@
|
|||||||
import React, { useCallback } from 'react';
|
import React, { useRef } from 'react';
|
||||||
import type { Example } from './examples-data/examples-data';
|
import type { Example } from './examples-data/examples-data';
|
||||||
import { randomColor } from '@/lib/colors';
|
import { randomColor } from '@/lib/colors';
|
||||||
import { Import } from 'lucide-react';
|
import { Import } from 'lucide-react';
|
||||||
@@ -13,35 +13,23 @@ import {
|
|||||||
TooltipContent,
|
TooltipContent,
|
||||||
TooltipTrigger,
|
TooltipTrigger,
|
||||||
} from '@/components/tooltip/tooltip';
|
} from '@/components/tooltip/tooltip';
|
||||||
import { useStorage } from '@/hooks/use-storage';
|
|
||||||
import type { Diagram } from '@/lib/domain/diagram';
|
|
||||||
import { useNavigate } from 'react-router-dom';
|
|
||||||
import { useTheme } from '@/hooks/use-theme';
|
import { useTheme } from '@/hooks/use-theme';
|
||||||
|
import { Spinner } from '@/components/spinner/spinner';
|
||||||
|
|
||||||
export interface ExampleCardProps {
|
export interface ExampleCardProps {
|
||||||
example: Example;
|
example: Example;
|
||||||
|
utilizeExample: () => void;
|
||||||
|
loading: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const ExampleCard: React.FC<ExampleCardProps> = ({ example }) => {
|
export const ExampleCard: React.FC<ExampleCardProps> = ({
|
||||||
const navigate = useNavigate();
|
example,
|
||||||
|
utilizeExample,
|
||||||
|
loading,
|
||||||
|
}) => {
|
||||||
const { effectiveTheme } = useTheme();
|
const { effectiveTheme } = useTheme();
|
||||||
const { addDiagram, deleteDiagram } = useStorage();
|
const color = useRef(randomColor());
|
||||||
const { diagram } = example;
|
|
||||||
const utilizeExample = useCallback(async () => {
|
|
||||||
const { id } = diagram;
|
|
||||||
|
|
||||||
await deleteDiagram(id);
|
|
||||||
|
|
||||||
const now = new Date();
|
|
||||||
const diagramToAdd: Diagram = {
|
|
||||||
...diagram,
|
|
||||||
createdAt: now,
|
|
||||||
updatedAt: now,
|
|
||||||
};
|
|
||||||
|
|
||||||
await addDiagram({ diagram: diagramToAdd });
|
|
||||||
navigate(`/diagrams/${id}`);
|
|
||||||
}, [addDiagram, diagram, navigate, deleteDiagram]);
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
onClick={utilizeExample}
|
onClick={utilizeExample}
|
||||||
@@ -49,7 +37,7 @@ export const ExampleCard: React.FC<ExampleCardProps> = ({ example }) => {
|
|||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
className="h-4 rounded-t-[10px]"
|
className="h-4 rounded-t-[10px]"
|
||||||
style={{ backgroundColor: randomColor() }}
|
style={{ backgroundColor: color.current }}
|
||||||
></div>
|
></div>
|
||||||
<div className="flex h-12 items-center justify-between bg-slate-200 px-2 dark:bg-slate-900">
|
<div className="flex h-12 items-center justify-between bg-slate-200 px-2 dark:bg-slate-900">
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
@@ -78,12 +66,16 @@ export const ExampleCard: React.FC<ExampleCardProps> = ({ example }) => {
|
|||||||
</Label>
|
</Label>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex flex-row">
|
<div className="flex flex-row">
|
||||||
|
{loading ? (
|
||||||
|
<Spinner className="size-5" />
|
||||||
|
) : (
|
||||||
<Button
|
<Button
|
||||||
variant="ghost"
|
variant="ghost"
|
||||||
className="size-9 p-0 text-slate-500 hover:bg-primary-foreground hover:text-slate-700 dark:text-slate-400 dark:hover:bg-slate-800 dark:hover:text-slate-200"
|
className="size-9 p-0 text-slate-500 hover:bg-primary-foreground hover:text-slate-700 dark:text-slate-400 dark:hover:bg-slate-800 dark:hover:text-slate-200"
|
||||||
>
|
>
|
||||||
<Import className="size-5" />
|
<Import className="size-5" />
|
||||||
</Button>
|
</Button>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="grow overflow-hidden">
|
<div className="grow overflow-hidden">
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import React from 'react';
|
import React, { useCallback } from 'react';
|
||||||
import ChartDBLogo from '@/assets/logo-light.png';
|
import ChartDBLogo from '@/assets/logo-light.png';
|
||||||
import ChartDBDarkLogo from '@/assets/logo-dark.png';
|
import ChartDBDarkLogo from '@/assets/logo-dark.png';
|
||||||
|
import type { Example } from './examples-data/examples-data';
|
||||||
import { examples } from './examples-data/examples-data';
|
import { examples } from './examples-data/examples-data';
|
||||||
import { ExampleCard } from './example-card';
|
import { ExampleCard } from './example-card';
|
||||||
import { useTheme } from '@/hooks/use-theme';
|
import { useTheme } from '@/hooks/use-theme';
|
||||||
@@ -8,9 +9,44 @@ import { LocalConfigProvider } from '@/context/local-config-context/local-config
|
|||||||
import { StorageProvider } from '@/context/storage-context/storage-provider';
|
import { StorageProvider } from '@/context/storage-context/storage-provider';
|
||||||
import { ThemeProvider } from '@/context/theme-context/theme-provider';
|
import { ThemeProvider } from '@/context/theme-context/theme-provider';
|
||||||
import { Helmet } from 'react-helmet-async';
|
import { Helmet } from 'react-helmet-async';
|
||||||
|
import { useNavigate } from 'react-router-dom';
|
||||||
|
import { useStorage } from '@/hooks/use-storage';
|
||||||
|
import type { Diagram } from '@/lib/domain/diagram';
|
||||||
|
|
||||||
const ExamplesPageComponent: React.FC = () => {
|
const ExamplesPageComponent: React.FC = () => {
|
||||||
const { effectiveTheme } = useTheme();
|
const { effectiveTheme } = useTheme();
|
||||||
|
const navigate = useNavigate();
|
||||||
|
const { addDiagram, deleteDiagram } = useStorage();
|
||||||
|
const [loadingExampleId, setLoadingExampleId] = React.useState<string>();
|
||||||
|
const utilizeExample = useCallback(
|
||||||
|
async ({ example }: { example: Example }) => {
|
||||||
|
if (loadingExampleId) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
setLoadingExampleId(example.id);
|
||||||
|
const { diagram } = example;
|
||||||
|
const { id } = diagram;
|
||||||
|
|
||||||
|
await deleteDiagram(id);
|
||||||
|
|
||||||
|
const now = new Date();
|
||||||
|
const diagramToAdd: Diagram = {
|
||||||
|
...diagram,
|
||||||
|
createdAt: now,
|
||||||
|
updatedAt: now,
|
||||||
|
};
|
||||||
|
|
||||||
|
await addDiagram({ diagram: diagramToAdd });
|
||||||
|
navigate(`/diagrams/${id}`);
|
||||||
|
},
|
||||||
|
[
|
||||||
|
addDiagram,
|
||||||
|
navigate,
|
||||||
|
deleteDiagram,
|
||||||
|
loadingExampleId,
|
||||||
|
setLoadingExampleId,
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
@@ -54,7 +90,14 @@ const ExamplesPageComponent: React.FC = () => {
|
|||||||
</h2>
|
</h2>
|
||||||
<div className="mt-6 grid grid-flow-row grid-cols-1 gap-6 md:grid-cols-2 lg:grid-cols-3">
|
<div className="mt-6 grid grid-flow-row grid-cols-1 gap-6 md:grid-cols-2 lg:grid-cols-3">
|
||||||
{examples.map((example) => (
|
{examples.map((example) => (
|
||||||
<ExampleCard key={example.id} example={example} />
|
<ExampleCard
|
||||||
|
key={example.id}
|
||||||
|
example={example}
|
||||||
|
utilizeExample={() =>
|
||||||
|
utilizeExample({ example })
|
||||||
|
}
|
||||||
|
loading={loadingExampleId === example.id}
|
||||||
|
/>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user