Skip to content

Commit

Permalink
feat: Generator Code
Browse files Browse the repository at this point in the history
  • Loading branch information
dineug committed Dec 3, 2023
1 parent bc2fe19 commit bce542d
Show file tree
Hide file tree
Showing 28 changed files with 1,604 additions and 99 deletions.
3 changes: 2 additions & 1 deletion packages/erd-editor-schema/src/convert/v2ToV3.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import { createMemo } from '@/v3/parser/memo.entity';
import { createRelationship } from '@/v3/parser/relationship.entity';
import { createTable } from '@/v3/parser/table.entity';
import { createColumn } from '@/v3/parser/tableColumn.entity';
import { CanvasType } from '@/v3/schema/settings';

export function v2ToV3(schemaV2: ERDEditorSchemaV2): ERDEditorSchemaV3 {
const schemaV3 = schemaV3Parser({});
Expand All @@ -36,7 +37,7 @@ function assignCanvas(
target.scrollLeft = source.scrollLeft;
target.zoomLevel = source.zoomLevel;
target.databaseName = source.databaseName;
target.canvasType = source.canvasType;
target.canvasType = CanvasType.ERD;

target.show = Object.keys(source.show).reduce((acc, key) => {
const flag: boolean = propOr(source.show, key, false);
Expand Down
6 changes: 3 additions & 3 deletions packages/erd-editor-schema/src/v3/schema/settings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,9 @@ export type Settings = {

export const CanvasType = {
ERD: 'ERD',
visualization: '@dineug/builtin-visualization',
schemaSQL: '@dineug/builtin-schema-sql',
generatorCode: '@dineug/builtin-generator-code',
visualization: '@dineug/erd-editor/builtin-visualization',
schemaSQL: '@dineug/erd-editor/builtin-schema-sql',
generatorCode: '@dineug/erd-editor/builtin-generator-code',
} as const;
export type CanvasType = ValuesType<typeof CanvasType>;
export const CanvasTypeList: ReadonlyArray<string> = Object.values(CanvasType);
Expand Down
8 changes: 6 additions & 2 deletions packages/erd-editor/src/components/erd-editor/ErdEditor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import { fromEvent, throttleTime } from 'rxjs';

import { appContext, createAppContext } from '@/components/appContext';
import Erd from '@/components/erd/Erd';
import GeneratorCode from '@/components/generator-code/GeneratorCode';
import GlobalStyles from '@/components/global-styles/GlobalStyles';
import SchemaSQL from '@/components/schema-sql/SchemaSQL';
import Theme from '@/components/theme/Theme';
Expand Down Expand Up @@ -151,6 +152,7 @@ const ErdEditor: FC<ErdEditorProps, ErdEditorElement> = (props, ctx) => {
return () => {
const { store } = appContextValue;
const { settings } = store.state;
const isDarkMode = hasDarkMode();

return html`
<${GlobalStyles} />
Expand All @@ -160,7 +162,7 @@ const ErdEditor: FC<ErdEditorProps, ErdEditorElement> = (props, ctx) => {
class=${[
'root',
styles.root,
{ dark: hasDarkMode(), 'none-focus': !state.isFocus },
{ dark: isDarkMode, 'none-focus': !state.isFocus },
]}
tabindex="-1"
@keydown=${handleKeydown}
Expand All @@ -176,7 +178,9 @@ const ErdEditor: FC<ErdEditorProps, ErdEditorElement> = (props, ctx) => {
${settings.canvasType === CanvasType.visualization
? html`<${Visualization} />`
: settings.canvasType === CanvasType.schemaSQL
? html`<${SchemaSQL} isDarkMode=${hasDarkMode()} />`
? html`<${SchemaSQL} isDarkMode=${isDarkMode} />`
: settings.canvasType === CanvasType.generatorCode
? html`<${GeneratorCode} isDarkMode=${isDarkMode} />`
: null}
</div>
<${ToastContainer} />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ export type ErdContextMenuProps = {

const ErdContextMenu: FC<ErdContextMenuProps> = (props, ctx) => {
const app = useAppContext(ctx);
const chevronRightIcon = html`<${Icon} name="chevron-right" size=${14} />`;

const handleAddTable = () => {
const { store } = app.value;
Expand Down Expand Up @@ -108,8 +109,6 @@ const ErdContextMenu: FC<ErdContextMenuProps> = (props, ctx) => {
props.onClose();
};

const chevronRightIcon = html`<${Icon} name="chevron-right" size=${14} />`;

return () => {
const { keyBindingMap } = app.value;

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { css } from '@dineug/r-html';

export const root = css`
position: relative;
height: 100%;
overflow: auto;
background-color: var(--canvas-background);
`;
97 changes: 97 additions & 0 deletions packages/erd-editor/src/components/generator-code/GeneratorCode.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
import { delay } from '@dineug/go';
import { FC, html, observable, onBeforeMount, watch } from '@dineug/r-html';
import { arrayHas } from '@dineug/shared';

import { useAppContext } from '@/components/appContext';
import GeneratorCodeContextMenu from '@/components/generator-code/generator-code-context-menu/GeneratorCodeContextMenu';
import CodeBlock from '@/components/primitives/code-block/CodeBlock';
import { useContextMenuRootProvider } from '@/components/primitives/context-menu/context-menu-root/contextMenuRootContext';
import Toast from '@/components/primitives/toast/Toast';
import { LanguageToLangMap } from '@/constants/language';
import { useUnmounted } from '@/hooks/useUnmounted';
import { copyToClipboard } from '@/utils/clipboard';
import { openToastAction } from '@/utils/emitter';
import { createGeneratorCode } from '@/utils/generator-code';

import * as styles from './GeneratorCode.styles';

const hasPropName = arrayHas<string | number | symbol>([
'language',
'tableNameCase',
'columnNameCase',
]);

export type GeneratorCodeProps = {
isDarkMode: boolean;
};

const GeneratorCode: FC<GeneratorCodeProps> = (props, ctx) => {
const app = useAppContext(ctx);
const { addUnsubscribe } = useUnmounted();
const contextMenu = useContextMenuRootProvider(ctx);

const state = observable({
code: '',
});

const setCode = () => {
const { store } = app.value;
state.code = createGeneratorCode(store.state);
};

const handleCopy = () => {
const { emitter } = app.value;

copyToClipboard(state.code).then(() => {
emitter.emit(
openToastAction({
close: delay(2000),
message: html`<${Toast} description="Copied!" />`,
})
);
});
};

const handleContextmenuClose = () => {
contextMenu.state.show = false;
};

onBeforeMount(() => {
const { store } = app.value;
const { settings } = store.state;

setCode();

addUnsubscribe(
watch(settings).subscribe(propName => {
hasPropName(propName) && setCode();
})
);
});

return () => {
const { store } = app.value;
const {
settings: { language },
} = store.state;
const lang = LanguageToLangMap[language];

return html`
<div
class=${styles.root}
@contextmenu=${contextMenu.onContextmenu}
@mousedown=${contextMenu.onMousedown}
>
<${CodeBlock}
lang=${lang}
theme=${props.isDarkMode ? 'dark' : 'light'}
value=${state.code}
.onCopy=${handleCopy}
/>
<${GeneratorCodeContextMenu} .onClose=${handleContextmenuClose} />
</div>
`;
};
};

export default GeneratorCode;
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
import { FC, html } from '@dineug/r-html';

import { useAppContext } from '@/components/appContext';
import ContextMenu from '@/components/primitives/context-menu/ContextMenu';
import Icon from '@/components/primitives/icon/Icon';

import { createColumnNameCaseMenus } from './menus/columnNameCaseMenus';
import { createLanguageMenus } from './menus/languageMenus';
import { createTableNameCaseMenus } from './menus/tableNameCaseMenus';

export type GeneratorCodeContextMenuProps = {};

const GeneratorCodeContextMenu: FC<GeneratorCodeContextMenuProps> = (
props,
ctx
) => {
const app = useAppContext(ctx);
const chevronRightIcon = html`<${Icon} name="chevron-right" size=${14} />`;

return () => html`
<${ContextMenu.Root}
children=${html`
<${ContextMenu.Item}
children=${html`
<${ContextMenu.Menu}
icon=${html`<${Icon} name="code" size=${14} />`}
name="Language"
right=${chevronRightIcon}
/>
`}
subChildren=${html`${createLanguageMenus(app.value).map(
menu => html`
<${ContextMenu.Item}
.onClick=${menu.onClick}
children=${html`
<${ContextMenu.Menu}
icon=${menu.checked
? html`<${Icon} name="check" size=${14} />`
: null}
name=${menu.name}
/>
`}
/>
`
)}`}
/>
<${ContextMenu.Item}
children=${html`
<${ContextMenu.Menu}
icon=${html`
<${Icon} prefix="mdi" name="format-letter-case" size=${14} />
`}
name="Table Name Case"
right=${chevronRightIcon}
/>
`}
subChildren=${html`${createTableNameCaseMenus(app.value).map(
menu => html`
<${ContextMenu.Item}
.onClick=${menu.onClick}
children=${html`
<${ContextMenu.Menu}
icon=${menu.checked
? html`<${Icon} name="check" size=${14} />`
: null}
name=${menu.name}
/>
`}
/>
`
)}`}
/>
<${ContextMenu.Item}
children=${html`
<${ContextMenu.Menu}
icon=${html`<${Icon}
prefix="mdi"
name="format-letter-case"
size=${14}
/>`}
name="Column Name Case"
right=${chevronRightIcon}
/>
`}
subChildren=${html`${createColumnNameCaseMenus(app.value).map(
menu => html`
<${ContextMenu.Item}
.onClick=${menu.onClick}
children=${html`
<${ContextMenu.Menu}
icon=${menu.checked
? html`<${Icon} name="check" size=${14} />`
: null}
name=${menu.name}
/>
`}
/>
`
)}`}
/>
`}
/>
`;
};

export default GeneratorCodeContextMenu;
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import { AppContext } from '@/components/appContext';
import { NameCase } from '@/constants/schema';
import { changeColumnNameCaseAction } from '@/engine/modules/settings/atom.actions';

type Menu = {
name: string;
value: number;
};

const menus: Menu[] = [
{
name: 'Pascal',
value: NameCase.pascalCase,
},
{
name: 'Camel',
value: NameCase.camelCase,
},
{
name: 'Snake',
value: NameCase.snakeCase,
},
{
name: 'None',
value: NameCase.none,
},
];

export function createColumnNameCaseMenus({ store }: AppContext) {
const { settings } = store.state;

return menus.map(menu => {
const checked = menu.value === settings.columnNameCase;

return {
checked,
name: menu.name,
onClick: () => {
store.dispatch(
changeColumnNameCaseAction({
value: menu.value,
})
);
},
};
});
}
Loading

0 comments on commit bce542d

Please sign in to comment.