From 5e0a11302f75485e06be3dcdf1a1d6dca27a02d8 Mon Sep 17 00:00:00 2001
From: rlazarini <remi.lazarini@cea.fr>
Date: Mon, 9 Dec 2024 11:15:12 +0100
Subject: [PATCH] [Ivette] Modal : renamed modalContainer + added basic modal
 in Dialogs + added test in sandbox panel

---
 ivette/src/dome/renderer/dialogs.tsx | 46 ++++++++++++++++++++++++++++
 ivette/src/dome/renderer/dome.tsx    | 13 +++-----
 ivette/src/dome/renderer/style.css   | 39 +++++++++++++++++++++++
 ivette/src/sandbox/panel.tsx         | 24 ++++++++++++++-
 ivette/src/sandbox/style.css         |  9 ++++++
 5 files changed, 122 insertions(+), 9 deletions(-)

diff --git a/ivette/src/dome/renderer/dialogs.tsx b/ivette/src/dome/renderer/dialogs.tsx
index ebcebbd2eda..d5b7dfb0b40 100644
--- a/ivette/src/dome/renderer/dialogs.tsx
+++ b/ivette/src/dome/renderer/dialogs.tsx
@@ -26,10 +26,14 @@
    @module dome/dialogs
  */
 
+import React from 'react';
 import * as filepath from 'path';
 import { ipcRenderer } from 'electron';
 import { modal } from 'dome';
 import * as System from 'dome/system';
+import { classes } from 'dome/misc/utils';
+import { Label } from './controls/labels';
+import { IconButton } from './controls/buttons';
 
 // --------------------------------------------------------------------------
 // --- Message Box
@@ -307,7 +311,49 @@ export async function showOpenDir(
 // --------------------------------------------------------------------------
 // --- Modal
 // --------------------------------------------------------------------------
+
 export function showModal(val: React.ReactNode): void { modal.setValue(val); }
 export function closeModal(): void { showModal(undefined); }
 
+interface ModalProps {
+  /** Text of the label. Prepend to other children elements. */
+  label: string;
+  /** Icon identifier. Displayed on the left side of the label. */
+  icon?: string;
+  /** Tool-tip description. */
+  title?: string;
+  /** custom Classes name */
+  className?: string;
+  /** Function onClose */
+  onClose?: () => void
+  /** Modal content */
+  children: JSX.Element;
+}
+
+export function Modal(
+  props: ModalProps
+): JSX.Element {
+  const { label, title, icon, className, onClose, children } = props;
+
+  const contentClasses = classes('dome-xModal-content', className);
+  const onCloseModal = (): void => {
+    closeModal();
+    if(onClose) onClose();
+  };
+
+  return (
+    <div className={contentClasses}>
+      <div className='dome-xModal-header'>
+        <Label className='dome-xModal-title'
+          label={label} icon={icon} title={title}
+        />
+        <IconButton icon='CROSS' size={18} onClick={onCloseModal} />
+      </div>
+      <div className='dome-xModal-body dome-xBoxes-vbox dome-xBoxes-box'>
+        {children}
+      </div>
+    </div>
+  );
+}
+
 // --------------------------------------------------------------------------
diff --git a/ivette/src/dome/renderer/dome.tsx b/ivette/src/dome/renderer/dome.tsx
index 8bb7597f502..19b04a7f0c4 100644
--- a/ivette/src/dome/renderer/dome.tsx
+++ b/ivette/src/dome/renderer/dome.tsx
@@ -321,20 +321,17 @@ export function setTitle(title: string): void {
 }
 
 // --------------------------------------------------------------------------
-// --- Window Modal
+// --- Window Modal Container
 // --------------------------------------------------------------------------
 
 export const modal = new GlobalState<React.ReactNode | undefined>(undefined);
 
-function Modal(): JSX.Element | null {
-  const [ modalContent, setModalContent ] = useGlobalState(modal);
+function ModalContainer(): JSX.Element | null {
+  const [ modalContent, ] = useGlobalState(modal);
 
   if(modalContent === undefined) return null;
   return (
-    <div
-      className="dome-xModal-overlay"
-      onClick={() => setModalContent(undefined)}
-    >
+    <div className="dome-xModal-overlay" >
       <div
         className="dome-xModal"
         onClick={(event) => event.stopPropagation()}
@@ -355,7 +352,7 @@ function setContainer(
   Settings.synchronize();
   const appNode = setContextAppNode();
   if (appNode) {
-    createRoot(appNode).render(<><Component /><Modal /></>);
+    createRoot(appNode).render(<><Component /><ModalContainer /></>);
   }
   else
     // eslint-disable-next-line no-console
diff --git a/ivette/src/dome/renderer/style.css b/ivette/src/dome/renderer/style.css
index a0800a53d14..f0d5e43fdb9 100644
--- a/ivette/src/dome/renderer/style.css
+++ b/ivette/src/dome/renderer/style.css
@@ -213,6 +213,7 @@ input[type="checkbox"]:checked {
 /* -------------------------------------------------------------------------- */
 /* --- Modal                                                              --- */
 /* -------------------------------------------------------------------------- */
+
 .dome-xModal {
   position: absolute;
   display: flex;
@@ -226,6 +227,44 @@ input[type="checkbox"]:checked {
   max-width: calc(100% - 100px);
   max-height: calc(100% - 50px);
   overflow: hidden;
+
+  .dome-xModal-header {
+    display: flex;
+    justify-content: space-between;
+    background-color: var(--background-profound);
+    padding: 5px;
+    font-size: medium;
+    align-items: center;
+
+    .dome-xModal-title {
+      margin-right: 20px;
+
+      .dome-xIcon {
+        padding-right: .3em;
+
+        svg {
+          height: 16px;
+        }
+      }
+    }
+
+    &>.dome-xIcon:hover {
+      cursor: pointer;
+    }
+  }
+
+  .dome-xModal-body {
+      background-color: var(--background);
+
+      .dome-xModal-waiting {
+        display: flex;
+        justify-content: center;
+        align-items: center;
+        padding: 20px;
+
+        svg { bottom: 0 !important; }
+      }
+  }
 }
 
 .dome-xModal-overlay {
diff --git a/ivette/src/sandbox/panel.tsx b/ivette/src/sandbox/panel.tsx
index 407bbde1701..bbae94cf524 100644
--- a/ivette/src/sandbox/panel.tsx
+++ b/ivette/src/sandbox/panel.tsx
@@ -36,6 +36,7 @@ import { Button, ButtonGroup } from 'dome/frame/toolbars';
 import { Icon } from 'dome/controls/icons';
 import './style.css';
 import { Label } from 'dome/controls/labels';
+import { Modal, showModal } from 'dome/dialogs';
 
 /* -------------------------------------------------------------------------- */
 /* --- Use Panel                                                          --- */
@@ -54,6 +55,10 @@ function UsePanel(): JSX.Element {
       ]
     }
   );
+  const [modalTestOpen, setModalTestOpen] = React.useState(false);
+  // eslint-disable-next-line max-len
+  const modalText = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Morbi eros ligula, fermentum vitae turpis sed, semper rutrum nisl. Morbi non lacus scelerisque, facilisis urna sit amet, dapibus lorem. Sed ultrices pulvinar molestie. Duis semper condimentum lectus sed egestas. Quisque faucibus nisl vel nisi mattis volutpat. Curabitur aliquet arcu a diam semper, commodo efficitur purus placerat. Integer dapibus non urna eget pretium. Pellentesque in feugiat magna, ut condimentum lectus.";
+
 
   return (
     <>
@@ -79,6 +84,23 @@ function UsePanel(): JSX.Element {
       </TitleBar>
       <div style={{ position: 'relative', height: '100%' }}>
         <Panel visible={visible} position={position}>
+          <Label label="Open test modal">
+            <Button
+              label='Open'
+              kind={modalTestOpen ? 'positive' : 'default'}
+              onClick={() => {
+                setModalTestOpen(true);
+                showModal(<Modal
+                  label="Test modal title"
+                  className='sandbox-modal'
+                  onClose={() => setModalTestOpen(false)}
+                >
+                  <div>{ modalText }</div>
+                </Modal>); }
+              }
+            />
+          </Label>
+
           <Label
             label="label"
             title="Text Component"
@@ -175,7 +197,7 @@ function UsePanel(): JSX.Element {
 
 registerSandbox({
   id: 'sandbox.panel',
-  label: 'Panel',
+  label: 'Panel + Modal',
   children: <UsePanel />,
 });
 
diff --git a/ivette/src/sandbox/style.css b/ivette/src/sandbox/style.css
index 6263e25d48a..106c5cf63f6 100644
--- a/ivette/src/sandbox/style.css
+++ b/ivette/src/sandbox/style.css
@@ -17,3 +17,12 @@
 .sandbox-panel-button-position-top {
     transform: rotate(270deg);
 }
+
+/* -------------------------------------------------------------------------- */
+/* --- Sandbox Modal                                                      --- */
+/* -------------------------------------------------------------------------- */
+.sandbox-modal {
+    .dome-xModal-body {
+        padding: 10px;
+    }
+}
-- 
GitLab