From 66a4b04c09b8bb9d8ad4ba6c488cff516ff0af50 Mon Sep 17 00:00:00 2001 From: Dylan Vorster Date: Sat, 1 Jul 2023 18:16:57 -0600 Subject: [PATCH] confirm deletes --- tornado-frontend/src/System.ts | 7 ++ .../src/routes/manage/ConceptBoardsPage.tsx | 10 ++- tornado-frontend/src/stores/DialogStore.tsx | 51 ++++++++++++++ tornado-frontend/src/theme/theme-dark.ts | 7 ++ tornado-frontend/src/theme/theme.ts | 7 ++ .../src/widgets/dialog/DialogWidget.tsx | 70 +++++++++++++++++++ .../src/widgets/layout/LayersWidget.tsx | 5 +- .../src/widgets/layout/RootWidget.tsx | 4 ++ 8 files changed, 157 insertions(+), 4 deletions(-) create mode 100644 tornado-frontend/src/stores/DialogStore.tsx create mode 100644 tornado-frontend/src/widgets/dialog/DialogWidget.tsx diff --git a/tornado-frontend/src/System.ts b/tornado-frontend/src/System.ts index fcfabdf..a2f4fa2 100644 --- a/tornado-frontend/src/System.ts +++ b/tornado-frontend/src/System.ts @@ -6,6 +6,7 @@ import { ThemeDark } from './theme/theme-dark'; import { ConceptsStore } from './stores/ConceptsStore'; import { MediaClient } from './client/MediaClient'; import { LayerStore } from './stores/LayerStore'; +import { DialogStore } from './stores/DialogStore'; export class System { client: TornadoClient; @@ -13,6 +14,7 @@ export class System { userStore: UserStore; layerStore: LayerStore; + dialogStore: DialogStore; @observable conceptStore: ConceptsStore; @@ -23,6 +25,7 @@ export class System { constructor() { this.theme = ThemeDark; + // clients this.client = new TornadoClient({ baseURL: window.location.origin }); @@ -30,10 +33,14 @@ export class System { baseURL: window.location.origin }); + // stores this.userStore = new UserStore({ client: this.client }); this.layerStore = new LayerStore(); + this.dialogStore = new DialogStore({ + layerStore: this.layerStore + }); autorun(() => { if (this.userStore.authenticatedUser) { diff --git a/tornado-frontend/src/routes/manage/ConceptBoardsPage.tsx b/tornado-frontend/src/routes/manage/ConceptBoardsPage.tsx index 73d3328..5a9cb34 100644 --- a/tornado-frontend/src/routes/manage/ConceptBoardsPage.tsx +++ b/tornado-frontend/src/routes/manage/ConceptBoardsPage.tsx @@ -54,8 +54,14 @@ export const ConceptBoardsPage: React.FC = observer((props) => { { - return row.board.delete(); + action={async () => { + const confirm = await system.dialogStore.showConfirmDialog({ + title: 'Are you sure?', + desc: `You are about to delete concept board ${row.board.board.name}` + }); + if (confirm) { + return row.board.delete(); + } }} /> diff --git a/tornado-frontend/src/stores/DialogStore.tsx b/tornado-frontend/src/stores/DialogStore.tsx new file mode 100644 index 0000000..8f98f84 --- /dev/null +++ b/tornado-frontend/src/stores/DialogStore.tsx @@ -0,0 +1,51 @@ +import * as React from 'react'; +import { Layer, LayerStore } from './LayerStore'; +import { DialogWidget } from '../widgets/dialog/DialogWidget'; +import { ButtonType } from '../widgets/forms/ButtonWidget'; + +export interface DialogStoreOptions { + layerStore: LayerStore; +} + +export class DialogStore { + constructor(protected options: DialogStoreOptions) {} + + async showConfirmDialog(options: { title: string; desc: string }): Promise { + return await new Promise((resolve) => { + let confirm = false; + const layer = new Layer(() => { + return ( + { + confirm = true; + layer.dispose(); + }, + type: ButtonType.PRIMARY + }, + { + label: 'Cancel', + action: async () => { + layer.dispose(); + }, + type: ButtonType.NORMAL + } + ]} + /> + ); + }); + const l1 = layer.registerListener({ + disposed: () => { + l1(); + resolve(confirm); + } + }); + + this.options.layerStore.addLayer(layer); + }); + } +} diff --git a/tornado-frontend/src/theme/theme-dark.ts b/tornado-frontend/src/theme/theme-dark.ts index 24cd666..8f39d56 100644 --- a/tornado-frontend/src/theme/theme-dark.ts +++ b/tornado-frontend/src/theme/theme-dark.ts @@ -7,6 +7,13 @@ export const ThemeDark: TornadoTheme = { separatorLine: '#2d2d2f', centerPanel: '#121215' }, + dialog: { + background: '#131315', + border: '#000', + header: '#fff', + desc: '#5f5f60', + shadow: 'rgba(0,0,0,0.3)' + }, text: { heading: '#fff', description: '#5f5f60' diff --git a/tornado-frontend/src/theme/theme.ts b/tornado-frontend/src/theme/theme.ts index 10b7bc3..0d963db 100644 --- a/tornado-frontend/src/theme/theme.ts +++ b/tornado-frontend/src/theme/theme.ts @@ -25,6 +25,13 @@ export interface TornadoTheme { backgroundHover: string; }; }; + dialog: { + background: string; + header: string; + desc: string; + shadow: string; + border: string; + }; text: { heading: string; description: string; diff --git a/tornado-frontend/src/widgets/dialog/DialogWidget.tsx b/tornado-frontend/src/widgets/dialog/DialogWidget.tsx new file mode 100644 index 0000000..28f0df2 --- /dev/null +++ b/tornado-frontend/src/widgets/dialog/DialogWidget.tsx @@ -0,0 +1,70 @@ +import * as React from 'react'; +import { styled } from '../../theme/theme'; +import { ButtonWidget, ButtonWidgetProps } from '../forms/ButtonWidget'; +import { FONT } from '../../fonts'; + +export interface DialogWidgetProps { + title: string; + desc: string; + btns: ButtonWidgetProps[]; +} + +export const DialogWidget: React.FC> = (props) => { + return ( + + + {props.title} + {props.desc} + {props.children ? {props.children} : null} + + {props.btns.map((b) => { + return ; + })} + + + + ); +}; +namespace S { + export const DialogLayer = styled.div` + display: flex; + align-items: center; + justify-content: center; + height: 100%; + `; + export const Container = styled.div` + padding: 50px; + border-radius: 8px; + background: ${(p) => p.theme.dialog.background}; + border: solid 1px ${(p) => p.theme.dialog.border}; + box-shadow: 0 11px 30px ${(p) => p.theme.dialog.shadow}; + `; + + export const Title = styled.div` + color: ${(p) => p.theme.dialog.header}; + font-size: 25px; + padding-bottom: 20px; + user-select: none; + ${FONT}; + `; + + export const Desc = styled.div` + color: ${(p) => p.theme.dialog.desc}; + font-size: 14px; + padding-bottom: 20px; + ${FONT}; + `; + + export const Content = styled.div` + padding-bottom: 20px; + `; + + export const Button = styled(ButtonWidget)` + margin-left: 5px; + `; + + export const Buttons = styled.div` + display: flex; + justify-content: flex-end; + `; +} diff --git a/tornado-frontend/src/widgets/layout/LayersWidget.tsx b/tornado-frontend/src/widgets/layout/LayersWidget.tsx index 5d458d7..09bb795 100644 --- a/tornado-frontend/src/widgets/layout/LayersWidget.tsx +++ b/tornado-frontend/src/widgets/layout/LayersWidget.tsx @@ -2,6 +2,7 @@ import * as React from 'react'; import styled from '@emotion/styled'; import { Layer } from '../../stores/LayerStore'; import { useSystem } from '../../hooks/useSystem'; +import { observer } from 'mobx-react'; export interface LayersWidgetProps { className?: any; @@ -11,7 +12,7 @@ export const LayerWidget: React.FC<{ layer: Layer; index: number }> = (props) => return {props.layer.render()}; }; -export const LayersWidget: React.FC = (props) => { +export const LayersWidget: React.FC = observer((props) => { const system = useSystem(); return ( @@ -22,7 +23,7 @@ export const LayersWidget: React.FC = (props) => { ); -}; +}); namespace S { export const Container = styled.div` display: flex; diff --git a/tornado-frontend/src/widgets/layout/RootWidget.tsx b/tornado-frontend/src/widgets/layout/RootWidget.tsx index 29d4871..9af7daa 100644 --- a/tornado-frontend/src/widgets/layout/RootWidget.tsx +++ b/tornado-frontend/src/widgets/layout/RootWidget.tsx @@ -47,6 +47,10 @@ namespace S { export const Layers = styled(LayersWidget)` position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; `; export const Global = css`