mirror of https://github.com/buster-so/buster.git
diff component v1
This commit is contained in:
parent
c76bd59622
commit
4167bb439d
|
@ -1,7 +1,13 @@
|
|||
'use client';
|
||||
|
||||
import type { editor } from 'monaco-editor';
|
||||
|
||||
const editorBackground = '#ffffff';
|
||||
const primaryColor = '#7C3AED';
|
||||
const editorBackground = getComputedStyle(document.documentElement).getPropertyValue(
|
||||
'--color-background'
|
||||
);
|
||||
const primaryColor = getComputedStyle(document.documentElement).getPropertyValue('--color-primary');
|
||||
const borderColor = getComputedStyle(document.documentElement).getPropertyValue('--color-border');
|
||||
const textColor = getComputedStyle(document.documentElement).getPropertyValue('--color-foreground');
|
||||
|
||||
const theme: editor.IStandaloneThemeData = {
|
||||
base: 'vs',
|
||||
|
@ -356,7 +362,11 @@ const theme: editor.IStandaloneThemeData = {
|
|||
'editorIndentGuide.background': '#959da5',
|
||||
'editorIndentGuide.activeBackground': '#24292e',
|
||||
'editor.selectionHighlightBorder': '#fafbfc',
|
||||
focusBorder: '#00000000'
|
||||
focusBorder: '#00000000',
|
||||
'editorHoverWidget.background': editorBackground,
|
||||
'editorHoverWidget.border': borderColor,
|
||||
'inputValidation.infoBorder': borderColor,
|
||||
'editorHoverWidget.foreground': textColor
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -0,0 +1,160 @@
|
|||
import type { Meta, StoryObj } from '@storybook/react';
|
||||
import { AppDiffCodeEditor } from './AppDiffCodeEditor';
|
||||
|
||||
const meta: Meta<typeof AppDiffCodeEditor> = {
|
||||
title: 'UI/Inputs/AppDiffCodeEditor',
|
||||
component: AppDiffCodeEditor,
|
||||
parameters: {
|
||||
layout: 'centered'
|
||||
},
|
||||
tags: ['autodocs'],
|
||||
argTypes: {
|
||||
viewMode: {
|
||||
control: 'radio',
|
||||
options: ['side-by-side', 'inline'],
|
||||
defaultValue: 'side-by-side',
|
||||
description: 'Controls whether the diff is displayed side-by-side or inline'
|
||||
}
|
||||
},
|
||||
decorators: [
|
||||
(Story) => (
|
||||
<div className="min-h-[500px] min-w-[1000px]">
|
||||
<Story />
|
||||
</div>
|
||||
)
|
||||
]
|
||||
};
|
||||
|
||||
export default meta;
|
||||
type Story = StoryObj<typeof AppDiffCodeEditor>;
|
||||
|
||||
const originalYaml = `# Original YAML configuration
|
||||
server:
|
||||
port: 8080
|
||||
host: localhost
|
||||
database:
|
||||
url: jdbc:mysql://localhost:3306/mydb
|
||||
username: admin
|
||||
password: secret
|
||||
logging:
|
||||
level: INFO
|
||||
path: /var/logs`;
|
||||
|
||||
const modifiedYaml = `# Updated YAML configuration
|
||||
server:
|
||||
port: 9090
|
||||
host: localhost
|
||||
timeout: 30s
|
||||
database:
|
||||
url: jdbc:mysql://localhost:3306/mydb
|
||||
username: admin
|
||||
password: secret
|
||||
pool:
|
||||
maxConnections: 20
|
||||
minIdle: 5
|
||||
logging:
|
||||
level: DEBUG
|
||||
path: /var/logs/app`;
|
||||
|
||||
const originalSql = `-- Original SQL query
|
||||
SELECT
|
||||
customers.id,
|
||||
customers.name,
|
||||
orders.order_date
|
||||
FROM customers
|
||||
JOIN orders ON customers.id = orders.customer_id
|
||||
WHERE orders.status = 'completed'
|
||||
ORDER BY orders.order_date DESC;`;
|
||||
|
||||
const modifiedSql = `-- Updated SQL query
|
||||
SELECT
|
||||
customers.id,
|
||||
customers.name,
|
||||
customers.email,
|
||||
orders.order_date,
|
||||
orders.total_amount
|
||||
FROM customers
|
||||
JOIN orders ON customers.id = orders.customer_id
|
||||
LEFT JOIN order_items ON orders.id = order_items.order_id
|
||||
WHERE orders.status = 'completed'
|
||||
AND orders.total_amount > 100
|
||||
GROUP BY customers.id
|
||||
ORDER BY orders.order_date DESC
|
||||
LIMIT 100;`;
|
||||
|
||||
export const Default: Story = {
|
||||
args: {
|
||||
original: originalYaml,
|
||||
modified: modifiedYaml,
|
||||
height: '300px',
|
||||
language: 'yaml',
|
||||
variant: 'bordered',
|
||||
viewMode: 'side-by-side'
|
||||
}
|
||||
};
|
||||
|
||||
export const InlineView: Story = {
|
||||
args: {
|
||||
original: originalYaml,
|
||||
modified: modifiedYaml,
|
||||
height: '300px',
|
||||
language: 'yaml',
|
||||
variant: 'bordered',
|
||||
viewMode: 'inline'
|
||||
}
|
||||
};
|
||||
|
||||
export const SQL: Story = {
|
||||
args: {
|
||||
original: originalSql,
|
||||
modified: modifiedSql,
|
||||
height: '300px',
|
||||
language: 'sql',
|
||||
variant: 'bordered',
|
||||
viewMode: 'side-by-side'
|
||||
}
|
||||
};
|
||||
|
||||
export const SQLInline: Story = {
|
||||
args: {
|
||||
original: originalSql,
|
||||
modified: modifiedSql,
|
||||
height: '300px',
|
||||
language: 'sql',
|
||||
variant: 'bordered',
|
||||
viewMode: 'inline'
|
||||
}
|
||||
};
|
||||
|
||||
export const ReadOnly: Story = {
|
||||
args: {
|
||||
original: originalYaml,
|
||||
modified: modifiedYaml,
|
||||
height: '300px',
|
||||
language: 'yaml',
|
||||
readOnly: true,
|
||||
variant: 'bordered',
|
||||
readOnlyMessage: 'This is a read-only view',
|
||||
viewMode: 'side-by-side'
|
||||
}
|
||||
};
|
||||
|
||||
export const TallerView: Story = {
|
||||
args: {
|
||||
original: originalSql,
|
||||
modified: modifiedSql,
|
||||
height: '500px',
|
||||
language: 'sql',
|
||||
variant: 'bordered',
|
||||
viewMode: 'side-by-side'
|
||||
}
|
||||
};
|
||||
|
||||
export const EmptyEditor: Story = {
|
||||
args: {
|
||||
height: '300px',
|
||||
language: 'yaml',
|
||||
variant: 'bordered',
|
||||
viewMode: 'side-by-side'
|
||||
}
|
||||
};
|
|
@ -0,0 +1,138 @@
|
|||
'use client';
|
||||
|
||||
import React, { forwardRef, useRef, useMemo } from 'react';
|
||||
import { CircleSpinnerLoaderContainer } from '../../loaders/CircleSpinnerLoaderContainer';
|
||||
import { useMemoizedFn } from '@/hooks';
|
||||
import { cn } from '@/lib/classMerge';
|
||||
import type { editor } from 'monaco-editor/esm/vs/editor/editor.api';
|
||||
import { DiffEditor } from '@monaco-editor/react';
|
||||
import { useTheme } from 'next-themes';
|
||||
|
||||
export interface AppDiffCodeEditorProps {
|
||||
className?: string;
|
||||
height?: string;
|
||||
isDarkMode?: boolean;
|
||||
onMount?: (editor: editor.IStandaloneDiffEditor, monaco: typeof import('monaco-editor')) => void;
|
||||
original?: string;
|
||||
modified?: string;
|
||||
onChange?: (value: string) => void;
|
||||
style?: React.CSSProperties;
|
||||
language?: string;
|
||||
readOnly?: boolean;
|
||||
readOnlyMessage?: string;
|
||||
monacoEditorOptions?: editor.IStandaloneDiffEditorConstructionOptions;
|
||||
variant?: 'bordered' | null;
|
||||
viewMode?: 'side-by-side' | 'inline';
|
||||
}
|
||||
|
||||
export interface AppDiffCodeEditorHandle {
|
||||
resetCodeEditor: () => void;
|
||||
}
|
||||
|
||||
export const AppDiffCodeEditor = forwardRef<AppDiffCodeEditorHandle, AppDiffCodeEditorProps>(
|
||||
(
|
||||
{
|
||||
style,
|
||||
monacoEditorOptions,
|
||||
language = 'typescript',
|
||||
className,
|
||||
readOnly,
|
||||
onChange,
|
||||
height = '100%',
|
||||
isDarkMode,
|
||||
onMount,
|
||||
original = '',
|
||||
modified = '',
|
||||
readOnlyMessage = 'Editing code is not allowed',
|
||||
variant,
|
||||
viewMode = 'side-by-side'
|
||||
},
|
||||
ref
|
||||
) => {
|
||||
const isDarkModeContext = useTheme()?.theme === 'dark';
|
||||
const useDarkMode = isDarkMode ?? isDarkModeContext;
|
||||
|
||||
const memoizedMonacoEditorOptions: editor.IStandaloneDiffEditorConstructionOptions =
|
||||
useMemo(() => {
|
||||
return {
|
||||
originalEditable: false,
|
||||
automaticLayout: true,
|
||||
readOnly,
|
||||
renderSideBySide: viewMode === 'side-by-side',
|
||||
folding: false,
|
||||
lineDecorationsWidth: 15,
|
||||
lineNumbersMinChars: 3,
|
||||
renderOverviewRuler: false,
|
||||
wordWrap: 'off',
|
||||
wordWrapColumn: 999,
|
||||
wrappingStrategy: 'simple',
|
||||
scrollBeyondLastLine: false,
|
||||
minimap: {
|
||||
enabled: false
|
||||
},
|
||||
contextmenu: false,
|
||||
readOnlyMessage: {
|
||||
value: readOnlyMessage
|
||||
},
|
||||
...monacoEditorOptions
|
||||
};
|
||||
}, [readOnlyMessage, monacoEditorOptions, viewMode]);
|
||||
|
||||
const onMountDiffEditor = useMemoizedFn(
|
||||
async (editor: editor.IStandaloneDiffEditor, monaco: typeof import('monaco-editor')) => {
|
||||
const [GithubLightTheme, NightOwlTheme] = await Promise.all([
|
||||
(await import('../AppCodeEditor/themes/github_light_theme')).default,
|
||||
(await import('../AppCodeEditor/themes/tomorrow_night_theme')).default
|
||||
]);
|
||||
|
||||
monaco.editor.defineTheme('github-light', GithubLightTheme);
|
||||
monaco.editor.defineTheme('night-owl', NightOwlTheme);
|
||||
|
||||
// Apply theme to diff editor
|
||||
const theme = useDarkMode ? 'night-owl' : 'github-light';
|
||||
monaco.editor.setTheme(theme);
|
||||
|
||||
console.log('theme', theme, GithubLightTheme);
|
||||
|
||||
// Get the modified editor and add change listener
|
||||
const modifiedEditor = editor.getModifiedEditor();
|
||||
if (!readOnly) {
|
||||
modifiedEditor.onDidChangeModelContent(() => {
|
||||
onChange?.(modifiedEditor.getValue() || '');
|
||||
});
|
||||
}
|
||||
|
||||
onMount?.(editor, monaco);
|
||||
}
|
||||
);
|
||||
|
||||
return (
|
||||
<div
|
||||
className={cn(
|
||||
'app-diff-code-editor relative h-full w-full',
|
||||
variant === 'bordered' && 'overflow-hidden border',
|
||||
className
|
||||
)}
|
||||
style={style}>
|
||||
<DiffEditor
|
||||
key={`${useDarkMode ? 'dark' : 'light'}-${viewMode}`}
|
||||
height={height}
|
||||
loading={<LoadingContainer />}
|
||||
language={language}
|
||||
className={className}
|
||||
original={original}
|
||||
modified={modified}
|
||||
theme={useDarkMode ? 'night-owl' : 'github-light'}
|
||||
onMount={onMountDiffEditor}
|
||||
options={memoizedMonacoEditorOptions}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
);
|
||||
AppDiffCodeEditor.displayName = 'AppDiffCodeEditor';
|
||||
|
||||
const LoadingContainer = React.memo(() => {
|
||||
return <CircleSpinnerLoaderContainer className="animate-in fade-in-0 duration-300" />;
|
||||
});
|
||||
LoadingContainer.displayName = 'LoadingContainer';
|
|
@ -0,0 +1 @@
|
|||
export { AppDiffCodeEditor } from './AppDiffCodeEditor';
|
|
@ -1,2 +1,3 @@
|
|||
export * from './Input';
|
||||
export * from './InputNumber';
|
||||
export * from './AppDiffCodeEditor';
|
||||
|
|
Loading…
Reference in New Issue