From dceb413ebaa7868549888e67e22a1534ee33333a Mon Sep 17 00:00:00 2001 From: dineug Date: Mon, 4 Dec 2023 21:38:35 +0900 Subject: [PATCH] feat: TableProperties layout --- .../components/erd-editor/ErdEditor.styles.ts | 2 +- .../src/components/erd-editor/ErdEditor.ts | 36 +++-- packages/erd-editor/src/components/erd/Erd.ts | 31 ++-- .../AutomaticTablePlacement.ts | 11 +- .../erd/erd-context-menu/ErdContextMenu.ts | 33 ++++- .../components/erd/erdShortcutPerformCheck.ts | 30 ++++ .../TableProperties.styles.ts | 31 ++++ .../erd/table-properties/TableProperties.ts | 59 ++++++++ .../src/components/erd/useErdShortcut.ts | 51 ++++--- .../generator-code/GeneratorCode.ts | 6 +- .../GeneratorCodeContextMenu.ts | 19 ++- .../primitives/code-block/CodeBlock.styles.ts | 1 + .../src/components/schema-sql/SchemaSQL.ts | 4 +- .../SchemaSQLContextMenu.ts | 15 +- .../components/settings/Settings.styles.ts | 25 ++-- .../src/components/settings/Settings.ts | 138 +++++++++++------- .../settings-lnb/SettingsLnb.styles.ts | 39 +++++ .../settings/settings-lnb/SettingsLnb.ts | 43 ++++++ .../settings/shortcuts/Shortcuts.styles.ts | 6 - .../settings/shortcuts/Shortcuts.ts | 3 - .../toast-container/ToastContainer.styles.ts | 4 +- packages/erd-editor/src/constants/open.ts | 7 + .../src/engine/modules/editor/actions.ts | 6 +- .../src/engine/modules/editor/atom.actions.ts | 31 ++-- .../src/engine/modules/editor/state.ts | 4 +- packages/erd-editor/src/utils/emitter.ts | 8 + 26 files changed, 481 insertions(+), 162 deletions(-) create mode 100644 packages/erd-editor/src/components/erd/erdShortcutPerformCheck.ts create mode 100644 packages/erd-editor/src/components/erd/table-properties/TableProperties.styles.ts create mode 100644 packages/erd-editor/src/components/erd/table-properties/TableProperties.ts create mode 100644 packages/erd-editor/src/components/settings/settings-lnb/SettingsLnb.styles.ts create mode 100644 packages/erd-editor/src/components/settings/settings-lnb/SettingsLnb.ts create mode 100644 packages/erd-editor/src/constants/open.ts diff --git a/packages/erd-editor/src/components/erd-editor/ErdEditor.styles.ts b/packages/erd-editor/src/components/erd-editor/ErdEditor.styles.ts index 11017b2f..be4d36fc 100644 --- a/packages/erd-editor/src/components/erd-editor/ErdEditor.styles.ts +++ b/packages/erd-editor/src/components/erd-editor/ErdEditor.styles.ts @@ -29,6 +29,6 @@ export const root = css` } `; -export const main = css` +export const scope = css` ${container}; `; diff --git a/packages/erd-editor/src/components/erd-editor/ErdEditor.ts b/packages/erd-editor/src/components/erd-editor/ErdEditor.ts index 021e5c1a..0c343520 100644 --- a/packages/erd-editor/src/components/erd-editor/ErdEditor.ts +++ b/packages/erd-editor/src/components/erd-editor/ErdEditor.ts @@ -172,20 +172,28 @@ const ErdEditor: FC = (props, ctx) => { @focusout=${handleFocusout} > <${Toolbar} /> -
- ${cache( - settings.canvasType === CanvasType.ERD ? html`<${Erd} />` : null - )} - ${settings.canvasType === CanvasType.visualization - ? html`<${Visualization} />` - : settings.canvasType === CanvasType.schemaSQL - ? html`<${SchemaSQL} isDarkMode=${isDarkMode} />` - : settings.canvasType === CanvasType.generatorCode - ? html`<${GeneratorCode} isDarkMode=${isDarkMode} />` - : settings.canvasType === CanvasType.settings - ? html`<${Settings} />` - : null} -
+ ${cache( + settings.canvasType === CanvasType.ERD + ? html`
<${Erd} />
` + : null + )} + ${settings.canvasType === CanvasType.visualization + ? html`
<${Visualization} />
` + : settings.canvasType === CanvasType.schemaSQL + ? html` +
+ <${SchemaSQL} isDarkMode=${isDarkMode} /> +
+ ` + : settings.canvasType === CanvasType.generatorCode + ? html` +
+ <${GeneratorCode} isDarkMode=${isDarkMode} /> +
+ ` + : settings.canvasType === CanvasType.settings + ? html`
<${Settings} />
` + : null} <${ToastContainer} /> ${text.span} diff --git a/packages/erd-editor/src/components/erd/Erd.ts b/packages/erd-editor/src/components/erd/Erd.ts index 0eeec372..96a4db6d 100644 --- a/packages/erd-editor/src/components/erd/Erd.ts +++ b/packages/erd-editor/src/components/erd/Erd.ts @@ -17,8 +17,10 @@ import ErdContextMenu, { ErdContextMenuType, } from '@/components/erd/erd-context-menu/ErdContextMenu'; import Minimap from '@/components/erd/minimap/Minimap'; +import TableProperties from '@/components/erd/table-properties/TableProperties'; import ColorPicker from '@/components/primitives/color-picker/ColorPicker'; import { useContextMenuRootProvider } from '@/components/primitives/context-menu/context-menu-root/contextMenuRootContext'; +import { Open } from '@/constants/open'; import { changeColorAllAction$, unselectAllAction$, @@ -58,6 +60,7 @@ const Erd: FC = (props, ctx) => { colorPickerY: 0, colorPickerViewport: null as Viewport | null, colorPickerInitialColor: '', + tablePropertiesId: '', }); useErdShortcut(ctx); @@ -186,6 +189,9 @@ const Erd: FC = (props, ctx) => { closeColorPicker: () => { state.colorPickerShow = false; }, + openTableProperties: ({ payload: { tableId } }) => { + state.tablePropertiesId = tableId; + }, }) ); }); @@ -193,7 +199,7 @@ const Erd: FC = (props, ctx) => { return () => { const { store } = app.value; const { - editor: { drawRelationship, runAutomaticTablePlacement }, + editor: { drawRelationship, openMap }, } = store.state; const cursor = drawRelationship @@ -225,13 +231,17 @@ const Erd: FC = (props, ctx) => { /> ` : null} - <${ErdContextMenu} - type=${state.contextMenuType} - canvas=${canvas} - relationshipId=${state.relationshipId} - tableId=${state.tableId} - .onClose=${handleContextmenuClose} - /> + ${contextMenu.state.show + ? html` + <${ErdContextMenu} + type=${state.contextMenuType} + canvas=${canvas} + relationshipId=${state.relationshipId} + tableId=${state.tableId} + .onClose=${handleContextmenuClose} + /> + ` + : null} ${state.colorPickerShow ? html` <${ColorPicker} @@ -243,7 +253,7 @@ const Erd: FC = (props, ctx) => { /> ` : null} - ${runAutomaticTablePlacement + ${openMap[Open.automaticTablePlacement] ? html`
<${AutomaticTablePlacement} @@ -253,6 +263,9 @@ const Erd: FC = (props, ctx) => {
` : null} + ${openMap[Open.tableProperties] + ? html`<${TableProperties} tableId=${state.tablePropertiesId} />` + : null} `; }; diff --git a/packages/erd-editor/src/components/erd/automatic-table-placement/AutomaticTablePlacement.ts b/packages/erd-editor/src/components/erd/automatic-table-placement/AutomaticTablePlacement.ts index 87de90ce..954583dc 100644 --- a/packages/erd-editor/src/components/erd/automatic-table-placement/AutomaticTablePlacement.ts +++ b/packages/erd-editor/src/components/erd/automatic-table-placement/AutomaticTablePlacement.ts @@ -12,8 +12,9 @@ import Canvas from '@/components/erd/canvas/Canvas'; import Minimap from '@/components/erd/minimap/Minimap'; import Button from '@/components/primitives/button/Button'; import Toast from '@/components/primitives/toast/Toast'; +import { Open } from '@/constants/open'; import { CANVAS_ZOOM_MIN } from '@/constants/schema'; -import { endAutomaticTablePlacementAction } from '@/engine/modules/editor/atom.actions'; +import { changeOpenMapAction } from '@/engine/modules/editor/atom.actions'; import { initialLoadJsonAction$ } from '@/engine/modules/editor/generator.actions'; import { changeZoomLevelAction, @@ -93,7 +94,9 @@ const AutomaticTablePlacement: FC = ( const handleCancel = () => { onClose(); - prevApp.store.dispatch(endAutomaticTablePlacementAction()); + prevApp.store.dispatch( + changeOpenMapAction({ [Open.automaticTablePlacement]: false }) + ); }; if (!tables.length) { @@ -144,9 +147,7 @@ const AutomaticTablePlacement: FC = ( simulation.on('end', handleStop); addUnsubscribe( shortcut$.subscribe(({ type }) => { - if (type === KeyBindingName.stop) { - handleCancel(); - } + type === KeyBindingName.stop && handleCancel(); }) ); } catch (e) { diff --git a/packages/erd-editor/src/components/erd/erd-context-menu/ErdContextMenu.ts b/packages/erd-editor/src/components/erd/erd-context-menu/ErdContextMenu.ts index 4f0e852a..dfcbd997 100644 --- a/packages/erd-editor/src/components/erd/erd-context-menu/ErdContextMenu.ts +++ b/packages/erd-editor/src/components/erd/erd-context-menu/ErdContextMenu.ts @@ -1,17 +1,23 @@ -import { FC, html, Ref } from '@dineug/r-html'; +import { FC, html, onMounted, Ref } 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 Kbd from '@/components/primitives/kbd/Kbd'; -import { startAutomaticTablePlacementAction } from '@/engine/modules/editor/atom.actions'; +import { Open } from '@/constants/open'; +import { changeOpenMapAction } from '@/engine/modules/editor/atom.actions'; import { addMemoAction$ } from '@/engine/modules/memo/generator.actions'; import { removeRelationshipAction } from '@/engine/modules/relationship/atom.actions'; import { addTableAction$ } from '@/engine/modules/table/generator.actions'; import { changeColumnPrimaryKeyAction$ } from '@/engine/modules/table-column/generator.actions'; +import { useUnmounted } from '@/hooks/useUnmounted'; import { ValuesType } from '@/internal-types'; import { query } from '@/utils/collection/query'; -import { openColorPickerAction } from '@/utils/emitter'; +import { + openColorPickerAction, + openTablePropertiesAction, +} from '@/utils/emitter'; +import { KeyBindingName } from '@/utils/keyboard-shortcut'; import { createDatabaseMenus } from './menus/databaseMenus'; import { createDrawRelationshipMenus } from './menus/drawRelationshipMenus'; @@ -38,6 +44,7 @@ export type ErdContextMenuProps = { const ErdContextMenu: FC = (props, ctx) => { const app = useAppContext(ctx); const chevronRightIcon = html`<${Icon} name="chevron-right" size=${14} />`; + const { addUnsubscribe } = useUnmounted(); const handleAddTable = () => { const { store } = app.value; @@ -53,7 +60,9 @@ const ErdContextMenu: FC = (props, ctx) => { const handleAutomaticTablePlacement = () => { const { store } = app.value; - store.dispatch(startAutomaticTablePlacementAction()); + store.dispatch( + changeOpenMapAction({ [Open.automaticTablePlacement]: true }) + ); props.onClose(); }; @@ -84,8 +93,10 @@ const ErdContextMenu: FC = (props, ctx) => { const handleOpenTableProperties = () => { if (!props.tableId) return; - // TODO: handleOpenTableProperties - console.log('handleOpenTableProperties'); + + const { store, emitter } = app.value; + emitter.emit(openTablePropertiesAction({ tableId: props.tableId })); + store.dispatch(changeOpenMapAction({ [Open.tableProperties]: true })); props.onClose(); }; @@ -109,6 +120,16 @@ const ErdContextMenu: FC = (props, ctx) => { props.onClose(); }; + onMounted(() => { + const { shortcut$ } = app.value; + + addUnsubscribe( + shortcut$.subscribe(({ type }) => { + type === KeyBindingName.stop && props.onClose(); + }) + ); + }); + return () => { const { keyBindingMap } = app.value; diff --git a/packages/erd-editor/src/components/erd/erdShortcutPerformCheck.ts b/packages/erd-editor/src/components/erd/erdShortcutPerformCheck.ts new file mode 100644 index 00000000..243059e6 --- /dev/null +++ b/packages/erd-editor/src/components/erd/erdShortcutPerformCheck.ts @@ -0,0 +1,30 @@ +import { Observable } from 'rxjs'; + +import { Open } from '@/constants/open'; +import { CanvasType } from '@/constants/schema'; +import { RootState } from '@/engine/state'; + +export const erdShortcutPerformCheck = + ({ editor, settings }: RootState) => + (source$: Observable) => + new Observable(subscriber => + source$.subscribe({ + next: value => { + const showAutomaticTablePlacement = + editor.openMap[Open.automaticTablePlacement]; + const showTableProperties = editor.openMap[Open.tableProperties]; + const isCanvasType = settings.canvasType === CanvasType.ERD; + + const canPerform = + isCanvasType && + !showAutomaticTablePlacement && + !showTableProperties; + + if (canPerform) { + subscriber.next(value); + } + }, + error: err => subscriber.error(err), + complete: () => subscriber.complete(), + }) + ); diff --git a/packages/erd-editor/src/components/erd/table-properties/TableProperties.styles.ts b/packages/erd-editor/src/components/erd/table-properties/TableProperties.styles.ts new file mode 100644 index 00000000..2c7a12ce --- /dev/null +++ b/packages/erd-editor/src/components/erd/table-properties/TableProperties.styles.ts @@ -0,0 +1,31 @@ +import { css } from '@dineug/r-html'; + +export const root = css` + position: absolute; + inset: 0; + width: 100%; + height: 100%; + display: flex; + align-items: center; + justify-content: center; + padding: 16px; + + &::after { + content: ''; + position: absolute; + inset: 0; + background-color: rgba(0, 0, 0, 0.5); + } +`; + +export const container = css` + width: 100%; + max-width: 900px; + max-height: calc(100% - 32px); + overflow: auto; + z-index: 1; + border-radius: 6px; + padding: 12px; + background-color: var(--context-menu-background); + border: 1px solid var(--context-menu-border); +`; diff --git a/packages/erd-editor/src/components/erd/table-properties/TableProperties.ts b/packages/erd-editor/src/components/erd/table-properties/TableProperties.ts new file mode 100644 index 00000000..77b2c0e6 --- /dev/null +++ b/packages/erd-editor/src/components/erd/table-properties/TableProperties.ts @@ -0,0 +1,59 @@ +import { FC, html, onMounted } from '@dineug/r-html'; + +import { useAppContext } from '@/components/appContext'; +import { Open } from '@/constants/open'; +import { changeOpenMapAction } from '@/engine/modules/editor/atom.actions'; +import { useUnmounted } from '@/hooks/useUnmounted'; +import { onStop } from '@/utils/domEvent'; +import { KeyBindingName } from '@/utils/keyboard-shortcut'; + +import * as styles from './TableProperties.styles'; + +export type TablePropertiesProps = { + tableId: string; +}; + +const TableProperties: FC = (props, ctx) => { + const app = useAppContext(ctx); + const { addUnsubscribe } = useUnmounted(); + + const handleClose = () => { + const { store } = app.value; + store.dispatch(changeOpenMapAction({ [Open.tableProperties]: false })); + }; + + const handleOutsideClick = (event: MouseEvent) => { + const el = event.target as HTMLElement | null; + if (!el) return; + + const canClose = !el.closest(`.${styles.container}`); + canClose && handleClose(); + }; + + onMounted(() => { + const { shortcut$ } = app.value; + + addUnsubscribe( + shortcut$.subscribe(({ type }) => { + type === KeyBindingName.stop && handleClose(); + }) + ); + }); + + return () => html` +
+
+
TableProperties
+
+
+ `; +}; + +export default TableProperties; diff --git a/packages/erd-editor/src/components/erd/useErdShortcut.ts b/packages/erd-editor/src/components/erd/useErdShortcut.ts index d2e74fc1..57c5d3dc 100644 --- a/packages/erd-editor/src/components/erd/useErdShortcut.ts +++ b/packages/erd-editor/src/components/erd/useErdShortcut.ts @@ -2,8 +2,10 @@ import { onMounted } from '@dineug/r-html'; import { arrayHas } from '@dineug/shared'; import { useAppContext } from '@/components/appContext'; -import { CanvasType, RelationshipType } from '@/constants/schema'; +import { Open } from '@/constants/open'; +import { RelationshipType } from '@/constants/schema'; import { + changeOpenMapAction, drawEndRelationshipAction, editTableAction, editTableEndAction, @@ -17,7 +19,11 @@ import { removeSelectedAction$, unselectAllAction$, } from '@/engine/modules/editor/generator.actions'; -import { hasMoveKeys, MoveKey } from '@/engine/modules/editor/state'; +import { + hasMoveKeys, + MoveKey, + SelectType, +} from '@/engine/modules/editor/state'; import { addMemoAction$ } from '@/engine/modules/memo/generator.actions'; import { streamZoomLevelAction } from '@/engine/modules/settings/atom.actions'; import { addTableAction$ } from '@/engine/modules/table/generator.actions'; @@ -30,10 +36,13 @@ import { } from '@/engine/modules/table-column/generator.actions'; import { useUnmounted } from '@/hooks/useUnmounted'; import { Ctx } from '@/internal-types'; +import { openTablePropertiesAction } from '@/utils/emitter'; import { focusEvent, forceFocusEvent } from '@/utils/internalEvents'; import { KeyBindingName } from '@/utils/keyboard-shortcut'; import { isHighLevelTable } from '@/utils/validation'; +import { erdShortcutPerformCheck } from './erdShortcutPerformCheck'; + const isRelationshipKeyBindingName = arrayHas([ KeyBindingName.relationshipZeroOne, KeyBindingName.relationshipZeroN, @@ -57,11 +66,7 @@ export function useErdShortcut(ctx: Ctx) { const { editor, settings } = store.state; const showHighLevelTable = isHighLevelTable(settings.zoomLevel); - if ( - settings.canvasType !== CanvasType.ERD || - showHighLevelTable || - editor.runAutomaticTablePlacement - ) { + if (showHighLevelTable) { return; } @@ -102,17 +107,10 @@ export function useErdShortcut(ctx: Ctx) { type: KeyBindingName; event: KeyboardEvent; }) => { - const { store } = app.value; + const { store, emitter } = app.value; const { editor, settings } = store.state; const showHighLevelTable = isHighLevelTable(settings.zoomLevel); - if ( - settings.canvasType !== CanvasType.ERD || - editor.runAutomaticTablePlacement - ) { - return; - } - if (!editor.focusTable || !editor.focusTable.edit) { type === KeyBindingName.addTable && store.dispatch(addTableAction$()); type === KeyBindingName.addColumn && store.dispatch(addColumnAction$()); @@ -131,7 +129,18 @@ export function useErdShortcut(ctx: Ctx) { store.dispatch(removeSelectedAction$()); } - // KeyBindingName.tableProperties + if (type === KeyBindingName.tableProperties) { + const selectedTable = Object.entries(editor.selectedMap).find( + ([, type]) => type === SelectType.table + ); + + if (selectedTable) { + emitter.emit( + openTablePropertiesAction({ tableId: selectedTable[0] }) + ); + store.dispatch(changeOpenMapAction({ [Open.tableProperties]: true })); + } + } // KeyBindingName.find @@ -203,11 +212,15 @@ export function useErdShortcut(ctx: Ctx) { }; onMounted(() => { - const { keydown$, shortcut$ } = app.value; + const { store, keydown$, shortcut$ } = app.value; addUnsubscribe( - keydown$.subscribe(handleKeydown), - shortcut$.subscribe(handleShortcut) + keydown$ + .pipe(erdShortcutPerformCheck(store.state)) + .subscribe(handleKeydown), + shortcut$ + .pipe(erdShortcutPerformCheck(store.state)) + .subscribe(handleShortcut) ); }); } diff --git a/packages/erd-editor/src/components/generator-code/GeneratorCode.ts b/packages/erd-editor/src/components/generator-code/GeneratorCode.ts index bef4352c..1fd73d24 100644 --- a/packages/erd-editor/src/components/generator-code/GeneratorCode.ts +++ b/packages/erd-editor/src/components/generator-code/GeneratorCode.ts @@ -88,7 +88,11 @@ const GeneratorCode: FC = (props, ctx) => { value=${state.code} .onCopy=${handleCopy} /> - <${GeneratorCodeContextMenu} .onClose=${handleContextmenuClose} /> + ${contextMenu.state.show + ? html` + <${GeneratorCodeContextMenu} .onClose=${handleContextmenuClose} /> + ` + : null} `; }; diff --git a/packages/erd-editor/src/components/generator-code/generator-code-context-menu/GeneratorCodeContextMenu.ts b/packages/erd-editor/src/components/generator-code/generator-code-context-menu/GeneratorCodeContextMenu.ts index 5e119f43..5836786b 100644 --- a/packages/erd-editor/src/components/generator-code/generator-code-context-menu/GeneratorCodeContextMenu.ts +++ b/packages/erd-editor/src/components/generator-code/generator-code-context-menu/GeneratorCodeContextMenu.ts @@ -1,14 +1,18 @@ -import { FC, html } from '@dineug/r-html'; +import { FC, html, onMounted } 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 { useUnmounted } from '@/hooks/useUnmounted'; +import { KeyBindingName } from '@/utils/keyboard-shortcut'; import { createColumnNameCaseMenus } from './menus/columnNameCaseMenus'; import { createLanguageMenus } from './menus/languageMenus'; import { createTableNameCaseMenus } from './menus/tableNameCaseMenus'; -export type GeneratorCodeContextMenuProps = {}; +export type GeneratorCodeContextMenuProps = { + onClose: () => void; +}; const GeneratorCodeContextMenu: FC = ( props, @@ -16,6 +20,17 @@ const GeneratorCodeContextMenu: FC = ( ) => { const app = useAppContext(ctx); const chevronRightIcon = html`<${Icon} name="chevron-right" size=${14} />`; + const { addUnsubscribe } = useUnmounted(); + + onMounted(() => { + const { shortcut$ } = app.value; + + addUnsubscribe( + shortcut$.subscribe(({ type }) => { + type === KeyBindingName.stop && props.onClose(); + }) + ); + }); return () => html` <${ContextMenu.Root} diff --git a/packages/erd-editor/src/components/primitives/code-block/CodeBlock.styles.ts b/packages/erd-editor/src/components/primitives/code-block/CodeBlock.styles.ts index 55295611..704cdcd0 100644 --- a/packages/erd-editor/src/components/primitives/code-block/CodeBlock.styles.ts +++ b/packages/erd-editor/src/components/primitives/code-block/CodeBlock.styles.ts @@ -11,6 +11,7 @@ export const clipboard = css` color: var(--foreground); opacity: 0; transition: opacity 0.15s; + user-select: none; &:hover { fill: var(--active); diff --git a/packages/erd-editor/src/components/schema-sql/SchemaSQL.ts b/packages/erd-editor/src/components/schema-sql/SchemaSQL.ts index 6b87aed8..a0978da2 100644 --- a/packages/erd-editor/src/components/schema-sql/SchemaSQL.ts +++ b/packages/erd-editor/src/components/schema-sql/SchemaSQL.ts @@ -79,7 +79,9 @@ const SchemaSQL: FC = (props, ctx) => { value=${state.sql} .onCopy=${handleCopy} /> - <${SchemaSQLContextMenu} .onClose=${handleContextmenuClose} /> + ${contextMenu.state.show + ? html`<${SchemaSQLContextMenu} .onClose=${handleContextmenuClose} />` + : null} `; }; diff --git a/packages/erd-editor/src/components/schema-sql/schema-sql-context-menu/SchemaSQLContextMenu.ts b/packages/erd-editor/src/components/schema-sql/schema-sql-context-menu/SchemaSQLContextMenu.ts index 5e2ce506..6b06e906 100644 --- a/packages/erd-editor/src/components/schema-sql/schema-sql-context-menu/SchemaSQLContextMenu.ts +++ b/packages/erd-editor/src/components/schema-sql/schema-sql-context-menu/SchemaSQLContextMenu.ts @@ -1,9 +1,11 @@ -import { FC, html } from '@dineug/r-html'; +import { FC, html, onMounted } from '@dineug/r-html'; import { useAppContext } from '@/components/appContext'; import { createDatabaseMenus } from '@/components/erd/erd-context-menu/menus/databaseMenus'; import ContextMenu from '@/components/primitives/context-menu/ContextMenu'; import Icon from '@/components/primitives/icon/Icon'; +import { useUnmounted } from '@/hooks/useUnmounted'; +import { KeyBindingName } from '@/utils/keyboard-shortcut'; import { createBracketMenus } from './menus/bracketMenus'; @@ -14,6 +16,17 @@ export type SchemaSQLContextMenuProps = { const SchemaSQLContextMenu: FC = (props, ctx) => { const app = useAppContext(ctx); const chevronRightIcon = html`<${Icon} name="chevron-right" size=${14} />`; + const { addUnsubscribe } = useUnmounted(); + + onMounted(() => { + const { shortcut$ } = app.value; + + addUnsubscribe( + shortcut$.subscribe(({ type }) => { + type === KeyBindingName.stop && props.onClose(); + }) + ); + }); return () => html` diff --git a/packages/erd-editor/src/components/settings/Settings.styles.ts b/packages/erd-editor/src/components/settings/Settings.styles.ts index c6598020..dd04841c 100644 --- a/packages/erd-editor/src/components/settings/Settings.styles.ts +++ b/packages/erd-editor/src/components/settings/Settings.styles.ts @@ -1,23 +1,33 @@ import { css } from '@dineug/r-html'; -import { fontSize6 } from '@/styles/typography.styles'; - export const root = css` display: flex; - flex-direction: column; position: relative; width: 100%; height: 100%; overflow: hidden; padding: 32px; + background-color: var(--context-menu-background); .column-order-move { transition: transform 0.3s; } `; -export const title = css` - ${fontSize6}; +export const lnbArea = css` + display: flex; + width: 200px; + height: 100%; + overflow: hidden; +`; + +export const contentArea = css` + display: flex; + flex-direction: column; + width: 100%; + height: 100%; + overflow: hidden; + padding-left: 16px; `; export const content = css` @@ -81,8 +91,3 @@ export const columnOrderItem = css` opacity: 0.5; } `; - -export const shortcutsSection = css` - margin: 0 32px 32px 0; - min-width: calc(100% - 364px); -`; diff --git a/packages/erd-editor/src/components/settings/Settings.ts b/packages/erd-editor/src/components/settings/Settings.ts index 0eabfa38..b532ee8d 100644 --- a/packages/erd-editor/src/components/settings/Settings.ts +++ b/packages/erd-editor/src/components/settings/Settings.ts @@ -1,5 +1,13 @@ import { delay } from '@dineug/go'; -import { createRef, FC, html, onUpdated, ref, repeat } from '@dineug/r-html'; +import { + createRef, + FC, + html, + observable, + onUpdated, + ref, + repeat, +} from '@dineug/r-html'; import { useAppContext } from '@/components/appContext'; import Button from '@/components/primitives/button/Button'; @@ -8,12 +16,16 @@ import Icon from '@/components/primitives/icon/Icon'; import Separator from '@/components/primitives/separator/Separator'; import Switch from '@/components/primitives/switch/Switch'; import Toast from '@/components/primitives/toast/Toast'; +import SettingsLnb, { + Lnb, +} from '@/components/settings/settings-lnb/SettingsLnb'; import Shortcuts from '@/components/settings/shortcuts/Shortcuts'; import { ColumnTypeToName } from '@/constants/schema'; import { changeColumnOrderAction, changeRelationshipDataTypeSyncAction, } from '@/engine/modules/settings/atom.actions'; +import { fontSize6 } from '@/styles/typography.styles'; import { recalculateTableWidth } from '@/utils/calcTable'; import { onPrevent } from '@/utils/domEvent'; import { relationshipSort } from '@/utils/draw-relationship/sort'; @@ -34,6 +46,10 @@ const Settings: FC = (props, ctx) => { 'column-order-move' ); + const state = observable({ + lnb: Lnb.preferences as Lnb, + }); + const handleChangeRelationshipDataTypeSync = (value: boolean) => { const { store } = app.value; store.dispatch(changeRelationshipDataTypeSyncAction({ value })); @@ -85,68 +101,80 @@ const Settings: FC = (props, ctx) => { onUpdated(() => flipAnimation.play()); + const handleChangeLnb = (value: Lnb) => { + state.lnb = value; + }; + return () => { const { store } = app.value; const { settings } = store.state; return html`
-
Settings
- <${Separator} space=${24} /> -
-
-
-
Relationship DataType Sync
-
- <${Switch} - value=${settings.relationshipDataTypeSync} - .onChange=${handleChangeRelationshipDataTypeSync} - /> -
-
-
Recalculation table width
-
- <${Button} - variant="soft" - size="1" - text=${html` - <${Icon} size=${14} name="rotate" /> -
- Sync - `} - .onClick=${handleRecalculationTableWidth} - /> -
-
-
Column Order
- <${Separator} space=${12} /> -
- ${repeat( - settings.columnOrder, - columnType => columnType, - columnType => html` -
- <${Menu} - icon=${html`<${Icon} name="bars" size=${14} />`} - name=${ColumnTypeToName[columnType]} +
+ <${SettingsLnb} value=${state.lnb} .onChange=${handleChangeLnb} /> +
+
+
${state.lnb}
+ <${Separator} space=${12} /> +
+ ${state.lnb === Lnb.preferences + ? html` +
+
+
Relationship DataType Sync
+
+ <${Switch} + value=${settings.relationshipDataTypeSync} + .onChange=${handleChangeRelationshipDataTypeSync} />
- ` - )} -
-
-
-
- <${Shortcuts} /> +
+
Recalculation table width
+
+ <${Button} + variant="soft" + size="1" + text=${html` + <${Icon} size=${14} name="rotate" /> +
+ Sync + `} + .onClick=${handleRecalculationTableWidth} + /> +
+
+
Column Order
+ <${Separator} space=${12} /> +
+ ${repeat( + settings.columnOrder, + columnType => columnType, + columnType => html` +
+ <${Menu} + icon=${html`<${Icon} name="bars" size=${14} />`} + name=${ColumnTypeToName[columnType]} + /> +
+ ` + )} +
+
+
+ ` + : state.lnb === Lnb.shortcuts + ? html`<${Shortcuts} />` + : null}
diff --git a/packages/erd-editor/src/components/settings/settings-lnb/SettingsLnb.styles.ts b/packages/erd-editor/src/components/settings/settings-lnb/SettingsLnb.styles.ts new file mode 100644 index 00000000..011c7d99 --- /dev/null +++ b/packages/erd-editor/src/components/settings/settings-lnb/SettingsLnb.styles.ts @@ -0,0 +1,39 @@ +import { css } from '@dineug/r-html'; + +export const lnb = css` + display: flex; + flex-direction: column; + width: 100%; + height: 100%; + overflow: hidden; +`; + +export const list = css` + display: flex; + flex-direction: column; + width: 100%; + height: 100%; + overflow-x: hidden; + overflow-y: auto; +`; + +export const item = css` + display: flex; + align-items: center; + padding: 0 12px; + height: 32px; + border-radius: 4px; + cursor: default; + + &:hover { + background-color: var(--context-menu-hover); + color: var(--active); + fill: var(--active); + } + + &.selected { + background-color: var(--context-menu-select); + color: var(--active); + fill: var(--active); + } +`; diff --git a/packages/erd-editor/src/components/settings/settings-lnb/SettingsLnb.ts b/packages/erd-editor/src/components/settings/settings-lnb/SettingsLnb.ts new file mode 100644 index 00000000..d0b4fafe --- /dev/null +++ b/packages/erd-editor/src/components/settings/settings-lnb/SettingsLnb.ts @@ -0,0 +1,43 @@ +import { FC, html } from '@dineug/r-html'; + +import Separator from '@/components/primitives/separator/Separator'; +import { ValuesType } from '@/internal-types'; +import { fontSize6 } from '@/styles/typography.styles'; + +import * as styles from './SettingsLnb.styles'; + +export const Lnb = { + preferences: 'Preferences', + shortcuts: 'Shortcuts', +} as const; +export type Lnb = ValuesType; +const LnbList: ReadonlyArray = Object.values(Lnb); + +export type SettingsLnbProps = { + value: Lnb; + onChange: (value: Lnb) => void; +}; + +const SettingsLnb: FC = (props, ctx) => { + return () => html` +
+
Settings
+ <${Separator} space=${12} /> +
+ ${LnbList.map( + lnb => + html` +
props.onChange(lnb as Lnb)} + > + ${lnb} +
+ ` + )} +
+
+ `; +}; + +export default SettingsLnb; diff --git a/packages/erd-editor/src/components/settings/shortcuts/Shortcuts.styles.ts b/packages/erd-editor/src/components/settings/shortcuts/Shortcuts.styles.ts index 7053e087..10fc0954 100644 --- a/packages/erd-editor/src/components/settings/shortcuts/Shortcuts.styles.ts +++ b/packages/erd-editor/src/components/settings/shortcuts/Shortcuts.styles.ts @@ -1,11 +1,5 @@ import { css } from '@dineug/r-html'; -import { fontSize4 } from '@/styles/typography.styles'; - -export const title = css` - ${fontSize4}; -`; - const cell = css` padding: 12px; height: 44px; diff --git a/packages/erd-editor/src/components/settings/shortcuts/Shortcuts.ts b/packages/erd-editor/src/components/settings/shortcuts/Shortcuts.ts index 5433585e..c01a201c 100644 --- a/packages/erd-editor/src/components/settings/shortcuts/Shortcuts.ts +++ b/packages/erd-editor/src/components/settings/shortcuts/Shortcuts.ts @@ -2,7 +2,6 @@ import { FC, html } from '@dineug/r-html'; import { useAppContext } from '@/components/appContext'; import Kbd from '@/components/primitives/kbd/Kbd'; -import Separator from '@/components/primitives/separator/Separator'; import { ShortcutOption } from '@/utils/keyboard-shortcut'; import * as styles from './Shortcuts.styles'; @@ -114,8 +113,6 @@ const Shortcuts: FC = (props, ctx) => { return () => { return html` -
Shortcuts
- <${Separator} space=${12} /> diff --git a/packages/erd-editor/src/components/toast-container/ToastContainer.styles.ts b/packages/erd-editor/src/components/toast-container/ToastContainer.styles.ts index 9307b300..b8cb410f 100644 --- a/packages/erd-editor/src/components/toast-container/ToastContainer.styles.ts +++ b/packages/erd-editor/src/components/toast-container/ToastContainer.styles.ts @@ -19,7 +19,7 @@ export const root = css` display: flex; margin-top: 10px; justify-content: flex-end; - animation: showMove 0.3s ease; + animation: toastShowMove 0.3s ease; &[data-animation-one] { animation: none; @@ -30,7 +30,7 @@ export const root = css` margin-top: 0; } - @keyframes showMove { + @keyframes toastShowMove { 0% { transform: translateY(30px); opacity: 0; diff --git a/packages/erd-editor/src/constants/open.ts b/packages/erd-editor/src/constants/open.ts new file mode 100644 index 00000000..17c076cd --- /dev/null +++ b/packages/erd-editor/src/constants/open.ts @@ -0,0 +1,7 @@ +import { ValuesType } from '@/internal-types'; + +export const Open = { + automaticTablePlacement: 'automaticTablePlacement', + tableProperties: 'tableProperties', +} as const; +export type Open = ValuesType; diff --git a/packages/erd-editor/src/engine/modules/editor/actions.ts b/packages/erd-editor/src/engine/modules/editor/actions.ts index 1d2ae5df..afd75b77 100644 --- a/packages/erd-editor/src/engine/modules/editor/actions.ts +++ b/packages/erd-editor/src/engine/modules/editor/actions.ts @@ -28,8 +28,7 @@ export const ActionType = { drawEndRelationship: 'editor.drawEndRelationship', drawRelationship: 'editor.drawRelationship', hoverColumnMap: 'editor.hoverColumnMap', - startAutomaticTablePlacement: 'editor.startAutomaticTablePlacement', - endAutomaticTablePlacement: 'editor.endAutomaticTablePlacement', + changeOpenMap: 'editor.changeOpenMap', } as const; export type ActionType = ValuesType; @@ -86,8 +85,7 @@ export type ActionMap = { [ActionType.hoverColumnMap]: { columnIds: string[]; }; - [ActionType.startAutomaticTablePlacement]: void; - [ActionType.endAutomaticTablePlacement]: void; + [ActionType.changeOpenMap]: Record; }; export type ReducerType = Reducer< diff --git a/packages/erd-editor/src/engine/modules/editor/atom.actions.ts b/packages/erd-editor/src/engine/modules/editor/atom.actions.ts index cddd14bd..75cf9a6a 100644 --- a/packages/erd-editor/src/engine/modules/editor/atom.actions.ts +++ b/packages/erd-editor/src/engine/modules/editor/atom.actions.ts @@ -428,24 +428,15 @@ const hoverColumnMap: ReducerType = ( } }; -export const startAutomaticTablePlacementAction = createAction< - ActionMap[typeof ActionType.startAutomaticTablePlacement] ->(ActionType.startAutomaticTablePlacement); +export const changeOpenMapAction = createAction< + ActionMap[typeof ActionType.changeOpenMap] +>(ActionType.changeOpenMap); -const startAutomaticTablePlacement: ReducerType< - typeof ActionType.startAutomaticTablePlacement -> = ({ editor }) => { - editor.runAutomaticTablePlacement = true; -}; - -export const endAutomaticTablePlacementAction = createAction< - ActionMap[typeof ActionType.endAutomaticTablePlacement] ->(ActionType.endAutomaticTablePlacement); - -const endAutomaticTablePlacement: ReducerType< - typeof ActionType.endAutomaticTablePlacement -> = ({ editor }) => { - editor.runAutomaticTablePlacement = false; +const changeOpenMap: ReducerType = ( + { editor }, + { payload } +) => { + Object.assign(editor.openMap, payload); }; export const editorReducers = { @@ -470,8 +461,7 @@ export const editorReducers = { [ActionType.drawEndRelationship]: drawEndRelationship, [ActionType.drawRelationship]: drawRelationship, [ActionType.hoverColumnMap]: hoverColumnMap, - [ActionType.startAutomaticTablePlacement]: startAutomaticTablePlacement, - [ActionType.endAutomaticTablePlacement]: endAutomaticTablePlacement, + [ActionType.changeOpenMap]: changeOpenMap, }; export const actions = { @@ -496,6 +486,5 @@ export const actions = { drawEndRelationshipAction, drawRelationshipAction, hoverColumnMapAction, - startAutomaticTablePlacementAction, - endAutomaticTablePlacementAction, + changeOpenMapAction, }; diff --git a/packages/erd-editor/src/engine/modules/editor/state.ts b/packages/erd-editor/src/engine/modules/editor/state.ts index 23d315f6..3b2c3ba5 100644 --- a/packages/erd-editor/src/engine/modules/editor/state.ts +++ b/packages/erd-editor/src/engine/modules/editor/state.ts @@ -11,7 +11,7 @@ export type Editor = { focusTable: FocusTable | null; drawRelationship: DrawRelationship | null; hoverColumnMap: Record; - runAutomaticTablePlacement: boolean; + openMap: Record; }; export type Viewport = { @@ -78,5 +78,5 @@ export const createEditor = (): Editor => ({ focusTable: null, drawRelationship: null, hoverColumnMap: {}, - runAutomaticTablePlacement: false, + openMap: {}, }); diff --git a/packages/erd-editor/src/utils/emitter.ts b/packages/erd-editor/src/utils/emitter.ts index 523f16c5..f3f16db7 100644 --- a/packages/erd-editor/src/utils/emitter.ts +++ b/packages/erd-editor/src/utils/emitter.ts @@ -13,6 +13,7 @@ const InternalActionType = { closeColorPicker: 'closeColorPicker', openToast: 'openToast', loadShikiService: 'loadShikiService', + openTableProperties: 'openTableProperties', } as const; type InternalActionType = ValuesType; @@ -28,6 +29,9 @@ type InternalActionMap = { close?: Promise; }; [InternalActionType.loadShikiService]: void; + [InternalActionType.openTableProperties]: { + tableId: string; + }; }; type Reducer = (action: Action) => void; @@ -69,3 +73,7 @@ export const openToastAction = createAction< export const loadShikiServiceAction = createAction< InternalActionMap[typeof InternalActionType.loadShikiService] >(InternalActionType.loadShikiService); + +export const openTablePropertiesAction = createAction< + InternalActionMap[typeof InternalActionType.openTableProperties] +>(InternalActionType.openTableProperties);