From ef5948e183b15009615818e22e9ea9c748abce2c Mon Sep 17 00:00:00 2001 From: Nathan-SR <144961007+Nathan-SR@users.noreply.github.com> Date: Thu, 10 Oct 2024 01:02:51 -0400 Subject: docCreatorMenu refactor work --- src/client/views/MainView.tsx | 2 +- src/client/views/nodes/DataVizBox/DataVizBox.tsx | 2 +- .../views/nodes/DataVizBox/DocCreatorMenu.scss | 1044 --------- .../views/nodes/DataVizBox/DocCreatorMenu.tsx | 2361 -------------------- .../DataVizBox/DocCreatorMenu/DocCreatorMenu.scss | 1044 +++++++++ .../DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx | 2328 +++++++++++++++++++ .../nodes/DataVizBox/DocCreatorMenu/FieldTypes.tsx | 159 ++ 7 files changed, 3533 insertions(+), 3407 deletions(-) delete mode 100644 src/client/views/nodes/DataVizBox/DocCreatorMenu.scss delete mode 100644 src/client/views/nodes/DataVizBox/DocCreatorMenu.tsx create mode 100644 src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.scss create mode 100644 src/client/views/nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu.tsx create mode 100644 src/client/views/nodes/DataVizBox/DocCreatorMenu/FieldTypes.tsx (limited to 'src') diff --git a/src/client/views/MainView.tsx b/src/client/views/MainView.tsx index fc159d96b..6ee42d256 100644 --- a/src/client/views/MainView.tsx +++ b/src/client/views/MainView.tsx @@ -58,7 +58,7 @@ import { ImageLabelHandler } from './collections/collectionFreeForm/ImageLabelHa import { MarqueeOptionsMenu } from './collections/collectionFreeForm/MarqueeOptionsMenu'; import { CollectionLinearView } from './collections/collectionLinear'; import { LinkMenu } from './linking/LinkMenu'; -import { DocCreatorMenu } from './nodes/DataVizBox/DocCreatorMenu'; +import { DocCreatorMenu } from './nodes/DataVizBox/DocCreatorMenu/DocCreatorMenu'; import { SchemaCSVPopUp } from './nodes/DataVizBox/SchemaCSVPopUp'; import { DocButtonState } from './nodes/DocumentLinksButton'; import { DocumentView, DocumentViewInternal } from './nodes/DocumentView'; diff --git a/src/client/views/nodes/DataVizBox/DataVizBox.tsx b/src/client/views/nodes/DataVizBox/DataVizBox.tsx index 896048ab3..1243831c8 100644 --- a/src/client/views/nodes/DataVizBox/DataVizBox.tsx +++ b/src/client/views/nodes/DataVizBox/DataVizBox.tsx @@ -32,7 +32,7 @@ import { DocumentView } from '../DocumentView'; import { FieldView, FieldViewProps } from '../FieldView'; import { FocusViewOptions } from '../FocusViewOptions'; import './DataVizBox.scss'; -import { Col, DataVizTemplateInfo, DocCreatorMenu, LayoutType, TemplateFieldSize, TemplateFieldType } from './DocCreatorMenu'; +import { Col, DataVizTemplateInfo, DocCreatorMenu, LayoutType, TemplateFieldSize, TemplateFieldType } from './DocCreatorMenu/DocCreatorMenu'; import { Histogram } from './components/Histogram'; import { LineChart } from './components/LineChart'; import { PieChart } from './components/PieChart'; diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu.scss b/src/client/views/nodes/DataVizBox/DocCreatorMenu.scss deleted file mode 100644 index 4ea904b8e..000000000 --- a/src/client/views/nodes/DataVizBox/DocCreatorMenu.scss +++ /dev/null @@ -1,1044 +0,0 @@ -.no-margin { - margin-top: 0px !important; - margin-bottom: 0px !important; - margin-left: 0px !important; - margin-right: 0px !important; -} - -.docCreatorMenu-cont { - position: absolute; - z-index: 100000; - // box-shadow: 0px 3px 4px rgba(0, 0, 0, 30%); - // background: whitesmoke; - // color: black; - border-radius: 3px; -} - -.docCreatorMenu-menu { - display: flex; - flex-direction: row; - height: 25px; - align-items: flex-end; -} - -.docCreatorMenu-menu-button { - width: 25px; - height: 25px; - background: whitesmoke; - background-color: rgb(50, 50, 50); - border-radius: 5px; - border: 1px solid rgb(180, 180, 180); - padding: 0px; - font-size: 13px; - //box-shadow: 3px 3px rgb(29, 29, 31); - - &:hover { - box-shadow: none; - } - - &.right{ - margin-left: 0px; - font-size: 12px; - } - - &.close-menu { - font-size: 12px; - width: 18px; - height: 18px; - border-radius: 2px; - font-size: 12px; - margin-left: auto; - } - - &.options { - margin-left: 0px; - } - - &:hover { - background-color: rgb(60, 60, 65); - } - - &.top-bar { - border-bottom: 25px solid #555; - border-left: 12px solid transparent; - border-right: 12px solid transparent; - // border-top-left-radius: 5px; - // border-top-right-radius: 5px; - border-radius: 0px; - height: 0; - width: 50px; - } - - &.preview-toggle { - margin: 0px; - border-top-left-radius: 0px; - border-bottom-left-radius: 0px; - border-left: 0px; - } -} - -.docCreatorMenu-top-buttons-container { - position: relative; - margin-top: 5px; - margin-left: 7px; - display: flex; - flex-direction: row; - align-items: flex-end; - width: 150px; - height: auto; -} - -.top-button-container { - position: relative; - width: 52px; - height: 20px; - display: flex; - align-items: center; - justify-content: center; - - &.left { - z-index: 3; - } - - &.middle { - position: absolute; - left: 40px; - z-index: 2; - - &.selected { - z-index: 4; - } - } - - &.right { - position: absolute; - left: 80px; - z-index: 1; - - &.selected { - z-index: 4; - } - } - - &:hover::before{ - border-bottom: 20px solid rgb(82, 82, 82); - } - - &::before { - content: ""; - position: absolute; - top: 0; - left: 0; - border-bottom: 20px solid rgb(50, 50, 50); - border-left: 12px solid transparent; - border-right: 12px solid transparent; - height: 0; - width: 50px; - } - - &::after { - content: ""; - position: absolute; - top: -1px; - left: -1px; - border-bottom: 22px solid rgb(180, 180, 180); - border-left: 12px solid transparent; - border-right: 12px solid transparent; - height: 0; - width: 52px; - z-index: -1; - } - - &.selected::before { - border-bottom-color: rgb(67, 119, 214); - } -} - -.top-button-content { - position: relative; - z-index: 1; - color: white; -} - -.docCreatorMenu-menu-hr{ - margin-top: 0px; - margin-bottom: 0px; - color: rgb(180, 180, 180); -} - -.docCreatorMenu-placement-indicator { - position: absolute; - z-index: 100000; - border-left: solid 3px #9fd7fb; - border-top: solid 3px #9fd7fb; - width: 25px; - height: 25px; -} - -.docCreatorMenu-general-options-container { - display: flex; - justify-content: center; - align-items: center; - margin: 0px; - padding: 0px; - gap: 5px; -} - -.docCreatorMenu-save-layout-button { - display: flex; - justify-content: center; - align-items: center; - width: 40px; - height: 40px; - background-color: rgb(99, 148, 238); - border: 2px solid rgb(80, 107, 152); - border-radius: 5px; - margin-bottom: 20px; - font-size: 25px; - - &:hover{ - background-color: rgb(59, 128, 255); - border: 2px solid rgb(53, 80, 127); - } -} - -.docCreatorMenu-create-docs-button { - width: 40px; - height: 40px; - background-color: rgb(176, 229, 149); - border: 2px solid rgb(126, 219, 80); - border-radius: 5px; - padding: 0px; - font-size: 25px; - color: white; - flex: 0 0 auto; - margin-bottom: 20px; //remove later !!! - - &:hover { - background-color: rgb(129, 223, 83); - border: 2px solid rgb(80, 185, 28); - } -} - -.docCreatorMenu-option-divider { - border-top: 1px solid rgb(180, 180, 180); - width: 95%; - margin-top: 10px; - margin-bottom: 10px; - - &.full { - width: 100%; - } -} - -//------------------------------------------------------------------------------------------------------------------------------------------ -// Resizers CSS -//-------------------------------------------------------------------------------------------------------------------------------------------- - -.docCreatorMenu-resizer { - position: absolute; - background-color: none; - - &.top, &.bottom { - height: 10px; - cursor: ns-resize; - } - - &.right, &.left { - width: 10px; - cursor: ew-resize; - } - - &.topRight, &.topLeft, &.bottomRight, &.bottomLeft { - height: 15px; - width: 15px; - background-color: none; - } -} - -//------------------------------------------------------------------------------------------------------------------------------------------ -// DocCreatorMenu templates preview CSS -//-------------------------------------------------------------------------------------------------------------------------------------------- - -.docCreatorMenu-templates-view { - display: flex; - flex-direction: column; - justify-content: flex-start; - overflow-y: scroll; - //align-items: flex-start; - margin: 5px; - margin-top: 0px; - width: calc(100% - 10px); - height: calc(100% - 30px); - border: 1px solid rgb(180, 180, 180); - border-radius: 5px; - -ms-overflow-style: none; - scrollbar-width: none; -} - -.docCreatorMenu-preview-container { - display: grid; - grid-template-columns: repeat(2, 140px); - grid-template-rows: 140px; - grid-auto-rows: 141px; - overflow-y: scroll; - margin: 0px; - margin-top: 0px; - width: 100%; - height: 100%; -} - -.docCreatorMenu-expanded-template-preview { - display: flex; - flex-direction: column; - justify-content: flex-start; - position: relative; - width: 100%; - height: 100%; - - .top-panel{ - width: 100%; - height: 10px; - } - - .right-buttons-panel { - display: flex; - flex-direction: column; - justify-content: flex-start; - height: 100%; - position: absolute; - right: 0px; - top: 0px; - width: 40px; - padding: 5px; - gap: 2px; - } -} - -.docCreatorMenu-preview-window { - position: relative; - display: flex; - justify-content: center; - align-items: center; - width: 113px; - height: 113px; - margin-top: 10px; - margin-left: 10px; - border: 1px solid rgb(163, 163, 163); - border-radius: 5px; - box-shadow: 5px 5px rgb(29, 29, 31); - flex: 0 0 auto; - - &:hover{ - background-color: rgb(72, 72, 73); - } - - &.empty { - font-size: 35px; - - &.GPT { - margin-top: 0px; - } - } - - .option-button { - display: none; - height: 25px; - width: 25px; - margin: 0px; - background: none; - border: 0px; - padding: 0px; - font-size: 15px; - - &.right { - position: absolute; - bottom: 0px; - right: 0px; - } - - &.left { - position: absolute; - bottom: 0px; - left: 0px; - } - - &.top-left { - position: absolute; - top: 0px; - left: 0px; - } - } - - &:hover .option-button { - display: block; - } - -} - -.docCreatorMenu-preview-image{ - background-color: transparent; - height: 100px; - width: 100px; - display: block; - object-fit: contain; - border-radius: 5px; - - &.expanded { - height: 100%; - width: 100%; - } -} - -.docCreatorMenu-section { - display: flex; - flex-direction: column; - align-items: center; - position: relative; - margin: 0px; - margin-top: 0px; - margin-bottom: 0px; - width: 100%; - height: 200; - flex: 0 0 auto; -} - -.docCreatorMenu-GPT-options-container { - display: flex; - flex-direction: row; - justify-content: center; - align-items: center; - position: relative; - width: auto; - margin: 0px; - margin-top: 5px; - padding: 0px; -} - -.docCreatorMenu-templates-preview-window { - display: flex; - flex-direction: row; - //justify-content: center; - align-items: center; - overflow-y: scroll; - position: relative; - height: 125px; - width: calc(100% - 10px); - -ms-overflow-style: none; - scrollbar-width: none; - - .loading-spinner { - justify-self: center; - } -} - -.divvv{ - width: 200; - height: 200; - border: solid 1px white; -} - -.docCreatorMenu-section-topbar { - position: relative; - display: flex; - flex-direction: row; - width: 100%; -} - -.section-reveal-options { - margin-top: 0px; - margin-bottom: 0px; - margin-right: 0px; - margin-left: auto; - border: 0px; - background: none; - - &.float-right { - float: right; - } -} - -.docCreatorMenu-section-title { - border: 1px solid rgb(163, 163, 163); - border-top: 0px; - border-left: 0px; - border-bottom-right-radius: 5px; - font-size: 12px; - padding: 2px; - padding-left: 3px; - padding-right: 3px; - margin-bottom: 3px; -} - -.docCreatorMenu-GPT-generate { - height: 30px; - width: 30px; - background-color: rgb(176, 229, 149); - border: 1px solid rgb(126, 219, 80); - border-radius: 5px; - padding: 0px; - font-size: 14px; - color: white; - letter-spacing: 1px; - flex: 0 0 auto; - - &:hover { - background-color: rgb(129, 223, 83); - border: 2px solid rgb(80, 185, 28); - } -} - -.docCreatorMenu-GPT-prompt-input { - width: 140px; - height: 25px; - overflow-y: scroll; - border: 1px solid rgb(180, 180, 180); - background-color: rgb(35, 35, 35); - border-radius: 3px; - padding-left: 4px; -} - -//------------------------------------------------------------------------------------------------------------------------------------------ -// DocCreatorMenu options CSS -//-------------------------------------------------------------------------------------------------------------------------------------------- - -.docCreatorMenu-option-container{ - display: flex; - width: 180px; - height: 30px; - flex-direction: row; - justify-content: center; - align-items: center; - margin-top: 10px; - margin-bottom: 10px; - - &.layout{ - z-index: 5; - } -} - -.docCreatorMenu-option-title{ - display: flex; - width: 140px; - height: 30px; - background: whitesmoke; - background-color: rgb(34, 34, 37); - border-radius: 5px; - border-top-right-radius: 0px; - border-bottom-right-radius: 0px; - border: 1px solid rgb(180, 180, 180); - padding: 0px; - font-size: 12px; - align-items: center; - justify-content: center; - text-transform: uppercase; - cursor: pointer; - - &.spacer { - border-left: none; - border-right: none; - border-radius: 0px; - width: auto; - text-transform: none; - - &.small { - height: 20px; - transform: translateY(-5px); - } - } - - &.config { - border-radius: 4px; - border-top-right-radius: 0px; - border-bottom-right-radius: 0px; - width: 30px; - border-right: 0px; - gap: 3px; - - &.layout-config { - height: 20px; - transform: translateY(-5px); - text-transform: none; - padding-left: 2px; - } - - &.dimensions { - text-transform: none; - height: 20px; - transform: translateY(-5px); - width: 70px; - } - } -} - -.docCreatorMenu-input { - display: flex; - height: 30px; - background-color: rgb(34, 34, 37); - border: 1px solid rgb(180, 180, 180); - align-items: center; - justify-content: center; - - &.config { - border-radius: 4px; - margin: 0px; - border-top-left-radius: 0px; - border-bottom-left-radius: 0px; - border-left: 0px; - width: 25px; - - &.layout-config { - height: 20px; - transform: translateY(-5px); - } - - &.dimensions { - height: 20px; - width: 30px; - transform: translateY(-5px); - - &.right { - border-top-left-radius: 0px; - border-bottom-left-radius: 0px; - } - - &.left { - border-radius: 0px; - border-right: 0px; - } - } - } -} - -.docCreatorMenu-configuration-bar { - width: 200; - gap: 5px; - display: flex; - flex-direction: row; - align-items: center; - justify-content: center; - - &.no-gap { - gap: 0px; - } -} - -.docCreatorMenu-menu-container { - display: flex; - flex-direction: column; - align-items: center; - overflow-y: scroll; - margin: 5px; - margin-top: 0px; - width: calc(100% - 10px); - height: calc(100% - 30px); - border: 1px solid rgb(180, 180, 180); - border-radius: 5px; - - .docCreatorMenu-option-container{ - width: 180px; - height: 30px; - - .docCreatorMenu-dropdown-hoverable { - width: 140px; - height: 30px; - - &:hover .docCreatorMenu-dropdown-content { - display: block; - } - - &:hover .docCreatorMenu-option-title { - border-bottom-left-radius: 0px; - border-bottom-right-radius: 0px; - } - - .docCreatorMenu-dropdown-content { - display: none; - min-width: 100px; - height: 75px; - overflow-y: scroll; - -ms-overflow-style: none; - scrollbar-width: none; - border-bottom: 1px solid rgb(180, 180, 180); - border-bottom-left-radius: 5px; - border-bottom-right-radius: 5px; - - .docCreatorMenu-dropdown-option{ - display: flex; - background-color: rgb(42, 42, 46); - border-left: 1px solid rgb(180, 180, 180); - border-right: 1px solid rgb(180, 180, 180); - border-bottom: 1px solid rgb(180, 180, 180); - width: 140px; - height: 25px; - justify-content: center; - justify-items: center; - padding-top: 3px; - - &:hover { - background-color: rgb(68, 68, 74); - cursor: pointer; - } - } - } - } - } -} - -.docCreatorMenu-layout-preview-window-wrapper { - display: flex; - justify-content: center; - align-items: center; - width: 85%; - height: auto; - position: relative; - padding: 0px; - - &:hover .docCreatorMenu-zoom-button-container { - display: block; - } - - .docCreatorMenu-layout-preview-window { - padding: 5px; - flex: 0 0 auto; - overflow: scroll; - display: grid; - width: 100%; - aspect-ratio: 1; - //height: auto; - // max-width: 240; - // max-height: 240; - border: 1px solid rgb(180, 180, 180); - border-radius: 5px; - background-color: rgb(34, 34, 37); - -ms-overflow-style: none; - scrollbar-width: none; - - &.small { - max-width: 100; - max-height: 100; - } - - .docCreatorMenu-layout-preview-item { - display: flex; - justify-content: center; - align-items: center; - border-radius: 3px; - border: solid 1px lightblue; - - &:hover { - border: solid 2px rgb(68, 153, 233); - z-index: 2; - } - } - } - - .docCreatorMenu-zoom-button-container { - position: absolute; - top: 0px; - display: flex; - justify-content: center; - align-items: center; - display: none; - z-index: 999; - } - - .docCreatorMenu-zoom-button{ - width: 15px; - height: 15px; - background: whitesmoke; - background-color: rgb(34, 34, 37); - border-radius: 3px; - border: 1px solid rgb(180, 180, 180); - padding: 0px; - font-size: 10px; - z-index: 6; - margin-left: 0px; - margin-top: 0px; - margin-right: 0px; //225px - margin-bottom: 0px; - } -} - -//------------------------------------------------------------------------------------------------------------------------------------------ -// DocCreatorMenu dashboard CSS -//-------------------------------------------------------------------------------------------------------------------------------------------- - -.docCreatorMenu-dashboard-view { - position: relative; - display: flex; - flex-direction: column; - justify-content: flex-start; - overflow-y: hidden; - //align-items: flex-start; - margin: 5px; - margin-top: 0px; - width: calc(100% - 10px); - height: calc(100% - 30px); - border: 1px solid rgb(180, 180, 180); - border-radius: 5px; - -ms-overflow-style: none; - scrollbar-width: none; - - .panels-container { - height: 100%; - width: 100%; - flex-direction: column; - justify-content: flex-start; - overflow-y: scroll; - } - - .topbar { - height: 30px; - width: 100%; - background-color: rgb(50, 50, 50); - } - -// .field-panel { -// position: relative; -// display: flex; -// // align-items: flex-start; -// flex-direction: column; -// gap: 5px; -// padding: 5px; -// height: 100px; -// //width: 100%; -// border: 1px solid rgb(180, 180, 180); -// margin: 5px; -// margin-top: 0px; -// border-radius: 3px; -// flex: 0 0 auto; - -// .properties-wrapper { -// display: flex; -// flex-direction: row; -// align-items: flex-start; -// gap: 5px; - -// .field-property-container { -// background-color: rgb(40, 40, 40); -// border: 1px solid rgb(100, 100, 100); -// border-radius: 3px; -// width: 30%; -// height: 25px; -// padding-left: 3px; -// align-items: center; -// color: whitesmoke; -// } - -// .field-type-selection-container { -// display: flex; -// flex-direction: row; -// align-items: center; -// background-color: rgb(40, 40, 40); -// border: 1px solid rgb(100, 100, 100); -// border-radius: 3px; -// width: 31%; -// height: 25px; -// padding-left: 3px; -// color: whitesmoke; - -// .placeholder { -// color: gray; -// } - -// &:hover .placeholder { -// display: none; -// } - -// .bubbles { -// display: none; -// } - -// .text { -// margin-top: 5px; -// margin-bottom: 5px; -// } - -// &:hover .bubbles { -// display: flex; -// flex-direction: row; -// align-items: flex-start; -// } - -// &:hover .type-display { -// display: none; -// } - -// .bubble { -// margin: 5px; -// } - -// &:hover .bubble { -// margin-top: 7px; -// } -// } -// } - -// .field-description-container { -// background-color: rgb(40, 40, 40); -// border: 1px solid rgb(100, 100, 100); -// border-radius: 3px; -// width: 100%; -// height: 100%; -// resize: none; - -// ::-webkit-scrollbar-track { -// background: none; -// } -// } - -// .top-right { -// position: absolute; -// top: 0px; -// right: 0px; -// } -// } -// } - - .field-panel { - display: flex; - flex-direction: column; - align-items: center; - justify-content: flex-start; - height: 285px; - width: calc(100% - 10px); - border: 1px solid rgb(180, 180, 180); - margin: 5px; - margin-top: 0px; - margin-bottom: 10px; - border-radius: 3px; - flex: 0 0 auto; - gap: 25px; - background-color: rgb(60, 60, 60); - - .top-bar { - position: relative; - display: flex; - flex-direction: row; - align-items: center; - justify-content: center; - border-bottom: 1px solid rgb(180, 180, 180); - border-top-right-radius: 5px; - border-top-left-radius: 5px; - width: 100%; - height: 20px; - background-color: rgb(50, 50, 50); - color: rgb(168, 167, 167); - - .field-title { - color: whitesmoke; - } - } - - .opts-bar { - display: flex; - flex-direction: row; - align-items: center; - justify-content: center; - width: 100%; - - .opt-box { - border: 1px solid rgb(180, 180, 180); - border-radius: 5px; - width: 40%; - height: 50px; - margin-right: 4%; - margin-left: 4%; - box-shadow: 5px 5px rgb(29, 29, 31); - } - - .content { - display: flex; - flex-direction: row; - justify-content: center; - align-items: center; - height: calc(100% - 20px); - width: 100%; - background-color: rgb(50, 50, 50); - border-bottom-right-radius: 5px; - border-bottom-left-radius: 5px; - resize: none; - - .bubbles { - display: none; - } - - .text { - margin-right: 5px; - } - - &:hover .bubbles { - display: flex; - flex-direction: row; - align-items: flex-start; - } - - &:hover .type-display { - display: none; - } - - .bubble { - margin: 3px; - } - } - } - - .sizes-box { - width: 88%; - height: 60px; - border: 1px solid rgb(180, 180, 180); - border-radius: 5px; - background-color: rgb(50, 50, 50); - box-shadow: 5px 5px rgb(29, 29, 31); - - .content { - display: flex; - flex-direction: row; - justify-content: center; - align-items: center; - height: calc(100% - 20px); - width: 100%; - background-color: rgb(50, 50, 50); - border-bottom-right-radius: 5px; - border-bottom-left-radius: 5px; - - .text { - margin-right: 9px; - } - - .bubbles { - display: flex; - flex-direction: row; - align-items: center; - } - - .bubble { - margin: 3px; - margin-right: 4px; - } - } - } - - .desc-box { - width: 88%; - height: 50px; - border: 1px solid rgb(180, 180, 180); - border-radius: 5px; - background-color: rgb(50, 50, 50); - box-shadow: 5px 5px rgb(29, 29, 31); - - .content { - height: calc(100% - 20px); - width: 100%; - background-color: rgb(50, 50, 50); - border-bottom-right-radius: 5px; - border-bottom-left-radius: 5px; - resize: none; - - } - } - - } - -} diff --git a/src/client/views/nodes/DataVizBox/DocCreatorMenu.tsx b/src/client/views/nodes/DataVizBox/DocCreatorMenu.tsx deleted file mode 100644 index 6c649bde3..000000000 --- a/src/client/views/nodes/DataVizBox/DocCreatorMenu.tsx +++ /dev/null @@ -1,2361 +0,0 @@ -import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; -import { Colors } from 'browndash-components'; -import { action, computed, makeObservable, observable, reaction, runInAction } from 'mobx'; -import { observer } from 'mobx-react'; -import { IDisposer } from 'mobx-utils'; -import * as React from 'react'; -import ReactLoading from 'react-loading'; -import { ClientUtils, returnEmptyFilter, returnFalse, returnTrue, setupMoveUpEvents } from '../../../../ClientUtils'; -import { emptyFunction } from '../../../../Utils'; -import { Doc, NumListCast, StrListCast, returnEmptyDoclist } from '../../../../fields/Doc'; -import { Id } from '../../../../fields/FieldSymbols'; -import { Cast, DocCast, ImageCast, StrCast } from '../../../../fields/Types'; -import { ImageField } from '../../../../fields/URLField'; -import { Networking } from '../../../Network'; -import { GPTCallType, gptAPICall, gptImageCall } from '../../../apis/gpt/GPT'; -import { Docs } from '../../../documents/Documents'; -import { DragManager } from '../../../util/DragManager'; -import { MakeTemplate } from '../../../util/DropConverter'; -import { SnappingManager } from '../../../util/SnappingManager'; -import { UndoManager, undoable } from '../../../util/UndoManager'; -import { LightboxView } from '../../LightboxView'; -import { ObservableReactComponent } from '../../ObservableReactComponent'; -import { CollectionFreeFormView } from '../../collections/collectionFreeForm/CollectionFreeFormView'; -import { DocumentView, DocumentViewInternal } from '../DocumentView'; -import { FieldViewProps } from '../FieldView'; -import { OpenWhere } from '../OpenWhere'; -import { DataVizBox } from './DataVizBox'; -import './DocCreatorMenu.scss'; -import { DefaultStyleProvider, returnEmptyDocViewList } from '../../StyleProvider'; -import { Transform } from '../../../util/Transform'; -import { IconProp } from '@fortawesome/fontawesome-svg-core'; - -export enum LayoutType { - Stacked = 'stacked', - Grid = 'grid', - Row = 'row', - Column = 'column', - Custom = 'custom', -} - -@observer -export class DocCreatorMenu extends ObservableReactComponent { - static Instance: DocCreatorMenu; - - private _disposers: { [name: string]: IDisposer } = {}; - - private _ref: HTMLDivElement | null = null; - - @observable _templateDocs: Doc[] = []; - @observable _selectedTemplate: Doc | undefined = undefined; - @observable _columns: Col[] = []; - @observable _selectedCols: { title: string; type: string; desc: string }[] | undefined = []; - - @observable _layout: { type: LayoutType; yMargin: number; xMargin: number; columns?: number; repeat: number } = { type: LayoutType.Grid, yMargin: 0, xMargin: 0, repeat: 0 }; - @observable _layoutPreview: boolean = true; - @observable _layoutPreviewScale: number = 1; - @observable _savedLayouts: DataVizTemplateLayout[] = []; - @observable _expandedPreview: { icon: ImageField; doc: Doc } | undefined = undefined; - - @observable _suggestedTemplates: Doc[] = []; - @observable _GPTOpt: boolean = false; - @observable _userPrompt: string = ''; - @observable _callCount: number = 0; - @observable _GPTLoading: boolean = false; - - @observable _pageX: number = 0; - @observable _pageY: number = 0; - @observable _indicatorX: number | undefined = undefined; - @observable _indicatorY: number | undefined = undefined; - - @observable _hoveredLayoutPreview: number | undefined = undefined; - @observable _mouseX: number = -1; - @observable _mouseY: number = -1; - @observable _startPos?: { x: number; y: number }; - @observable _shouldDisplay: boolean = false; - - @observable _menuContent: 'templates' | 'options' | 'saved' | 'dashboard' = 'templates'; - @observable _dragging: boolean = false; - @observable _draggingIndicator: boolean = false; - @observable _dataViz?: DataVizBox; - @observable _interactionLock: any; - @observable _snapPt: any; - @observable _resizeHdlId: string = ''; - @observable _resizing: boolean = false; - @observable _offset: { x: number; y: number } = { x: 0, y: 0 }; - @observable _resizeUndo: UndoManager.Batch | undefined = undefined; - @observable _initDimensions: { width: number; height: number; x?: number; y?: number } = { width: 300, height: 400, x: undefined, y: undefined }; - @observable _menuDimensions: { width: number; height: number } = { width: 400, height: 400 }; - @observable _editing: boolean = false; - - constructor(props: any) { - super(props); - makeObservable(this); - DocCreatorMenu.Instance = this; - //setTimeout(() => this.generateTemplates('')); - } - - @action setDataViz = (dataViz: DataVizBox) => { - this._dataViz = dataViz; - }; - @action setTemplateDocs = (docs: Doc[]) => { - this._templateDocs = docs.map(doc => (doc.annotationOn ? DocCast(doc.annotationOn) : doc)); - }; - @action setGSuggestedTemplates = (docs: Doc[]) => { - this._suggestedTemplates = docs; - }; - - @computed get docsToRender() { - return this._selectedTemplate ? NumListCast(this._dataViz?.layoutDoc.dataViz_selectedRows) : []; - } - - @computed get rowsCount() { - switch (this._layout.type) { - case LayoutType.Row: - case LayoutType.Stacked: - return 1; - case LayoutType.Column: - return this.docsToRender.length; - case LayoutType.Grid: - return Math.ceil(this.docsToRender.length / (this._layout.columns ?? 1)) ?? 0; - default: - return 0; - } - } - - @computed get columnsCount() { - switch (this._layout.type) { - case LayoutType.Row: - return this.docsToRender.length; - case LayoutType.Column: - case LayoutType.Stacked: - return 1; - case LayoutType.Grid: - return this._layout.columns ?? 0; - default: - return 0; - } - } - - @computed get selectedFields() { - return StrListCast(this._dataViz?.layoutDoc._dataViz_axes); - } - - @computed get fieldsInfos(): Col[] { - const colInfo = this._dataViz?.colsInfo; - return this.selectedFields - .map(field => { - const fieldInfo = colInfo?.get(field); - - const col: Col = { - title: field, - type: fieldInfo?.type ?? TemplateFieldType.UNSET, - desc: fieldInfo?.desc ?? '', - sizes: fieldInfo?.sizes ?? [TemplateFieldSize.MEDIUM], - }; - - if (fieldInfo?.defaultContent !== undefined) { - col.defaultContent = fieldInfo.defaultContent; - } - - return col; - }) - .concat(this._columns); - } - - @computed get canMakeDocs() { - return this._selectedTemplate !== undefined && this._layout !== undefined; - } - - get bounds(): { t: number; b: number; l: number; r: number } { - const rect = this._ref?.getBoundingClientRect(); - const bounds = { t: rect?.top ?? 0, b: rect?.bottom ?? 0, l: rect?.left ?? 0, r: rect?.right ?? 0 }; - return bounds; - } - - setUpButtonClick = (e: any, func: Function) => { - setupMoveUpEvents( - this, - e, - returnFalse, - emptyFunction, - undoable(clickEv => { - clickEv.stopPropagation(); - clickEv.preventDefault(); - func(); - }, 'create docs') - ); - }; - - @action - onPointerDown = (e: PointerEvent) => { - this._mouseX = e.clientX; - this._mouseY = e.clientY; - }; - - @action - onPointerUp = (e: PointerEvent) => { - if (this._resizing) { - this._initDimensions.width = this._menuDimensions.width; - this._initDimensions.height = this._menuDimensions.height; - this._initDimensions.x = this._pageX; - this._initDimensions.y = this._pageY; - document.removeEventListener('pointermove', this.onResize); - SnappingManager.SetIsResizing(undefined); - this._resizing = false; - } - if (this._dragging) { - document.removeEventListener('pointermove', this.onDrag); - this._dragging = false; - } - if (e.button !== 2 && !e.ctrlKey) return; - const curX = e.clientX; - const curY = e.clientY; - if (Math.abs(this._mouseX - curX) > 1 || Math.abs(this._mouseY - curY) > 1) { - this._shouldDisplay = false; - } - }; - - componentDidMount() { - document.addEventListener('pointerdown', this.onPointerDown, true); - document.addEventListener('pointerup', this.onPointerUp); - this._disposers.templates = reaction( - () => this._templateDocs.slice(), - docs => this.updateIcons(docs) - ); - this._disposers.gpt = reaction( - () => this._suggestedTemplates.slice(), - docs => this.updateIcons(docs) - ); - //this._disposers.columns = reaction(() => this._dataViz?.layoutDoc._dataViz_axes, () => {this.generateTemplates('')}) - this._disposers.lightbox = reaction( - () => LightboxView.LightboxDoc(), - doc => { - doc ? this._shouldDisplay && this.closeMenu() : !this._shouldDisplay && this.openMenu(); - } - ); - //this._disposers.fields = reaction(() => this._dataViz?.axes, cols => this._selectedCols = cols?.map(col => { return {title: col, type: '', desc: ''}})) - } - - componentWillUnmount() { - Object.values(this._disposers).forEach(disposer => disposer?.()); - document.removeEventListener('pointerdown', this.onPointerDown, true); - document.removeEventListener('pointerup', this.onPointerUp); - } - - updateIcons = (docs: Doc[]) => { - console.log('called') - docs.map(this.getIcon); - }; - - @action - updateSelectedCols = (cols: string[]) => { - this._selectedCols; - }; - - @action - toggleDisplay = (x: number, y: number) => { - if (this._shouldDisplay) { - this._shouldDisplay = false; - } else { - this._pageX = x; - this._pageY = y; - this._shouldDisplay = true; - } - }; - - @action - closeMenu = () => { - this._shouldDisplay = false; - }; - - @action - openMenu = () => { - const allTemplates = this._templateDocs.concat(this._suggestedTemplates); - this._shouldDisplay = true; - this.updateIcons(allTemplates); - }; - - @action - onResizePointerDown = (e: React.PointerEvent): void => { - this._resizing = true; - document.addEventListener('pointermove', this.onResize); - SnappingManager.SetIsResizing(DocumentView.Selected().lastElement()?.Document[Id]); // turns off pointer events on things like youtube videos and web pages so that dragging doesn't get "stuck" when cursor moves over them - e.stopPropagation(); - const id = (this._resizeHdlId = e.currentTarget.className); - const pad = id.includes('Left') || id.includes('Right') ? Number(getComputedStyle(e.target as any).width.replace('px', '')) / 2 : 0; - const bounds = e.currentTarget.getBoundingClientRect(); - this._offset = { - x: id.toLowerCase().includes('left') ? bounds.right - e.clientX - pad : bounds.left - e.clientX + pad, // - y: id.toLowerCase().includes('top') ? bounds.bottom - e.clientY - pad : bounds.top - e.clientY + pad, - }; - this._resizeUndo = UndoManager.StartBatch('drag resizing'); - this._snapPt = { x: e.pageX, y: e.pageY }; - }; - - @action - onResize = (e: any): boolean => { - const dragHdl = this._resizeHdlId.split(' ')[1]; - const thisPt = DragManager.snapDrag(e, -this._offset.x, -this._offset.y, this._offset.x, this._offset.y); - - const { scale, refPt, transl } = this.getResizeVals(thisPt, dragHdl); - !this._interactionLock && runInAction(async () => { // resize selected docs if we're not in the middle of a resize (ie, throttle input events to frame rate) - this._interactionLock = true; - const scaleAspect = {x: scale.x, y: scale.y}; - this.resizeView(refPt, scaleAspect, transl); // prettier-ignore - await new Promise(res => { setTimeout(() => { res(this._interactionLock = undefined)})}); - }); // prettier-ignore - return true; - }; - - @action - onDrag = (e: any): boolean => { - this._pageX = e.pageX - (this._startPos?.x ?? 0); - this._pageY = e.pageY - (this._startPos?.y ?? 0); - this._initDimensions.x = this._pageX; - this._initDimensions.y = this._pageY; - return true; - }; - - getResizeVals = (thisPt: { x: number; y: number }, dragHdl: string) => { - const [w, h] = [this._initDimensions.width, this._initDimensions.height]; - const [moveX, moveY] = [thisPt.x - this._snapPt.x, thisPt.y - this._snapPt.y]; - let vals: { scale: { x: number; y: number }; refPt: [number, number]; transl: { x: number; y: number } }; - switch (dragHdl) { - case 'topLeft': vals = { scale: { x: 1 - moveX / w, y: 1 -moveY / h }, refPt: [this.bounds.r, this.bounds.b], transl: {x: moveX, y: moveY } }; break; - case 'topRight': vals = { scale: { x: 1 + moveX / w, y: 1 -moveY / h }, refPt: [this.bounds.l, this.bounds.b], transl: {x: 0, y: moveY } }; break; - case 'top': vals = { scale: { x: 1, y: 1 -moveY / h }, refPt: [this.bounds.l, this.bounds.b], transl: {x: 0, y: moveY } }; break; - case 'left': vals = { scale: { x: 1 - moveX / w, y: 1 }, refPt: [this.bounds.r, this.bounds.t], transl: {x: moveX, y: 0 } }; break; - case 'bottomLeft': vals = { scale: { x: 1 - moveX / w, y: 1 + moveY / h }, refPt: [this.bounds.r, this.bounds.t], transl: {x: moveX, y: 0 } }; break; - case 'right': vals = { scale: { x: 1 + moveX / w, y: 1 }, refPt: [this.bounds.l, this.bounds.t], transl: {x: 0, y: 0 } }; break; - case 'bottomRight':vals = { scale: { x: 1 + moveX / w, y: 1 + moveY / h }, refPt: [this.bounds.l, this.bounds.t], transl: {x: 0, y: 0 } }; break; - case 'bottom': vals = { scale: { x: 1, y: 1 + moveY / h }, refPt: [this.bounds.l, this.bounds.t], transl: {x: 0, y: 0 } }; break; - default: vals = { scale: { x: 1, y: 1 }, refPt: [this.bounds.l, this.bounds.t], transl: {x: 0, y: 0 } }; break; - } // prettier-ignore - return vals; - }; - - resizeView = (refPt: number[], scale: { x: number; y: number }, translation: { x: number; y: number }) => { - const refCent = [refPt[0], refPt[1]]; // fixed reference point for resize (ie, a point that doesn't move) - if (this._initDimensions.x === undefined) this._initDimensions.x = this._pageX; - if (this._initDimensions.y === undefined) this._initDimensions.y = this._pageY; - const { height, width, x, y } = this._initDimensions; - - this._menuDimensions.width = Math.max(300, scale.x * width); - this._menuDimensions.height = Math.max(200, scale.y * height); - this._pageX = x + translation.x; - this._pageY = y + translation.y; - }; - - async getIcon(doc: Doc) { - const docView = DocumentView.getDocumentView(doc); - if (docView) { - docView.ComponentView?.updateIcon?.(); - return new Promise(res => setTimeout(() => res(ImageCast(docView.Document.icon)), 500)); - } - return undefined; - } - - @action updateSelectedTemplate = (template: Doc) => { - if (this._selectedTemplate === template) { - this._selectedTemplate = undefined; - return; - } else { - this._selectedTemplate = template; - MakeTemplate(template); - } - }; - - @action updateSelectedSavedLayout = (layout: DataVizTemplateLayout) => { - this._layout.xMargin = layout.layout.xMargin; - this._layout.yMargin = layout.layout.yMargin; - this._layout.type = layout.layout.type; - this._layout.columns = layout.columns; - }; - - isSelectedLayout = (layout: DataVizTemplateLayout) => { - return this._layout.xMargin === layout.layout.xMargin && this._layout.yMargin === layout.layout.yMargin && this._layout.type === layout.layout.type && this._layout.columns === layout.columns; - }; - - @action - generateTemplates = async (inputText: string) => { - ++this._callCount; - const origCount = this._callCount; - - let prompt: string = `(#${origCount}) Please generate for the fields:`; - this.selectedFields?.forEach(field => (prompt += ` ${field},`)); - prompt += ` (-----NOT A FIELD-----) Additional prompt: ${inputText}`; - - this._GPTLoading = true; - - try { - const res = await gptAPICall(prompt, GPTCallType.TEMPLATE); - - if (res && this._callCount === origCount) { - this._suggestedTemplates = []; - const templates: { template_type: string; fieldVals: { title: string; tlx: string; tly: string; brx: string; bry: string }[] }[] = JSON.parse(res); - this.createGeneratedTemplates(templates, 500, 500); - } - } catch (err) { - console.error(err); - } - }; - - @action - createGeneratedTemplates = (layouts: { template_type: string; fieldVals: { title: string; tlx: string; tly: string; brx: string; bry: string }[] }[], tempWidth: number, tempHeight: number) => { - const mainCollection = this._dataViz?.DocumentView?.().containerViewPath?.().lastElement()?.ComponentView as CollectionFreeFormView; - const GPTTemplates: Doc[] = []; - - layouts.forEach(layout => { - const fields: Doc[] = layout.fieldVals.map(field => { - const left: number = (Number(field.tlx) * tempWidth) / 2; - const top: number = Number(field.tly) * tempHeight / 2; //prettier-ignore - const right: number = (Number(field.brx) * tempWidth) / 2; - const bottom: number = Number(field.bry) * tempHeight / 2; //prettier-ignore - const height = bottom - top; - const width = right - left; - const doc = !field.title.includes('$$') - ? Docs.Create.TextDocument('', { _height: height, _width: width, title: field.title, x: left, y: top, _text_fontSize: `${height / 2}` }) - : Docs.Create.ImageDocument('', { _height: height, _width: width, title: field.title.replace(/\$\$/g, ''), x: left, y: top }); - return doc; - }); - - const template = Docs.Create.FreeformDocument(fields, { _height: tempHeight, _width: tempWidth, title: layout.template_type, x: 400000, y: 400000 }); - - mainCollection.addDocument(template); - - GPTTemplates.push(template); - }); - - setTimeout(() => { - this.setGSuggestedTemplates(GPTTemplates); /*GPTTemplates.forEach(template => mainCollection.removeDocument(template))*/ - }, 100); - - this.forceUpdate(); - }; - - editTemplate = (doc: Doc) => { - //this.closeMenu(); - DocumentViewInternal.addDocTabFunc(doc, OpenWhere.addRight); - DocumentView.DeselectAll(); - Doc.UnBrushDoc(doc); - }; - - removeTemplate = (doc: Doc) => { - this._templateDocs.splice(this._templateDocs.indexOf(doc), 1); - }; - - testTemplate = async () => { - this.updateIcons(this._suggestedTemplates.slice()); - this.forceUpdate(); - - // try { - // const res = await gptImageCall('Image of panda eating a cookie'); - - // if (res) { - // const result = await Networking.PostToServer('/uploadRemoteImage', { sources: res }); - - // console.log(result); - // } - // } catch (e) { - // console.log(e); - // } - }; - - @action addField = () => { - const newFields: Col[] = this._columns.concat([{ title: '', type: TemplateFieldType.UNSET, desc: '', sizes: [] }]); - this._columns = newFields; - }; - - @action removeField = (field: { title: string; type: string; desc: string }) => { - if (this._dataViz?.axes.includes(field.title)) { - this._dataViz.selectAxes(this._dataViz.axes.filter(col => col !== field.title)); - } else { - const toRemove = this._columns.filter(f => f === field); - if (!toRemove) return; - - if (toRemove.length > 1) { - while (toRemove.length > 1) { - toRemove.pop(); - } - } - - if (this._columns.length === 1) { - this._columns = []; - } else { - this._columns.splice(this._columns.indexOf(toRemove[0]), 1); - } - } - }; - - @action setColTitle = (column: Col, title: string) => { - if (this.selectedFields.includes(column.title)) { - this._dataViz?.setColumnTitle(column.title, title); - } else { - column.title = title; - } - this.forceUpdate(); - }; - - @action setColType = (column: Col, type: TemplateFieldType) => { - if (this.selectedFields.includes(column.title)) { - this._dataViz?.setColumnType(column.title, type); - } else { - column.type = type; - } - this.forceUpdate(); - }; - - modifyColSizes = (column: Col, size: TemplateFieldSize, valid: boolean) => { - if (this.selectedFields.includes(column.title)) { - this._dataViz?.modifyColumnSizes(column.title, size, valid); - } else { - if (!valid && column.sizes.includes(size)) { - column.sizes.splice(column.sizes.indexOf(size), 1); - } else if (valid && !column.sizes.includes(size)) { - column.sizes.push(size); - } - } - this.forceUpdate(); - }; - - setColDesc = (column: Col, desc: string) => { - if (this.selectedFields.includes(column.title)) { - this._dataViz?.setColumnDesc(column.title, desc); - } else { - column.desc = desc; - } - this.forceUpdate(); - }; - - generateGPTImage = async (prompt: string): Promise => { - console.log(prompt); - - try { - const res = await gptImageCall(prompt); - - if (res) { - const result = await Networking.PostToServer('/uploadRemoteImage', { sources: res }); - const source = ClientUtils.prepend(result[0].accessPaths.agnostic.client); - return source; - } - } catch (e) { - console.log(e); - } - }; - - matchesForTemplate = (template: TemplateDocInfos, cols: Col[]): number[][] => { - const colMatchesField = (col: Col, field: Field) => { - return field.sizes?.some(size => col.sizes?.includes(size)) && field.types?.includes(col.type); - }; - - const matches: number[][] = Array(template.fields.length) - .fill([]) - .map(() => []); - - template.fields.forEach((field, i) => { - cols.forEach((col, v) => { - if (colMatchesField(col, field)) { - matches[i].push(v); - } - }); - }); - - return matches; - }; - - maxMatches = (fieldsCt: number, matches: number[][]) => { - const used: boolean[] = Array(fieldsCt).fill(false); - const mt: number[] = Array(fieldsCt).fill(-1); - - const augmentingPath = (v: number): boolean => { - if (used[v]) return false; - used[v] = true; - for (const to of matches[v]) { - if (mt[to] === -1 || augmentingPath(mt[to])) { - mt[to] = v; - return true; - } - } - return false; - }; - - for (let v = 0; v < fieldsCt; ++v) { - used.fill(false); - augmentingPath(v); - } - - let count: number = 0; - - for (let i = 0; i < fieldsCt; ++i) { - if (mt[i] !== -1) ++count; - } - - return count; - }; - - findValidTemplates = (cols: Col[], templates: TemplateDocInfos[]) => { - let validTemplates: any[] = []; - templates.forEach(template => { - const numFields = template.fields.length; - if (!(numFields === cols.length)) return; - const matches = this.matchesForTemplate(template, cols); - if (this.maxMatches(numFields, matches) === numFields) { - validTemplates.push(template.title); - } - }); - - validTemplates = validTemplates.map(title => TemplateLayouts.getTemplateByTitle(title)); - - return validTemplates; - }; - - // createColumnField = (template: TemplateDocInfos, field: Field, column: Col): Doc => { - - // if (field.subfields) { - // const doc = FieldFuncs.FreeformField({ - // tl: field.tl, - // br: field.br }, - // template.height, - // template.width, - // column.title, - // '', - // field.opts - // ); - - // field.subfields[1].forEach(f => { - // const fDoc = () - // }) - - // } - - // return new Doc; - // } - - /** - * Populates a preset template framework with content from a datavizbox or any AI-generated content. - * @param template the preloaded template framework being filled in - * @param assignments a list of template field numbers (from top to bottom) and their assigned columns from the linked dataviz - * @returns a doc containing the fully rendered template - */ - fillPresetTemplate = async (template: TemplateDocInfos, assignments: { [field: string]: Col }): Promise => { - const wordLimit = (size: TemplateFieldSize) => { - switch (size) { - case TemplateFieldSize.TINY: - return 2; - case TemplateFieldSize.SMALL: - return 5; - case TemplateFieldSize.MEDIUM: - return 20; - case TemplateFieldSize.LARGE: - return 50; - case TemplateFieldSize.HUGE: - return 100; - default: - return 10; - } - }; - - const renderTextCalls = async (): Promise => { - const rendered: Doc[] = []; - - if (GPTTextCalls.length) { - try { - const prompt = fieldContent + GPTTextAssignment; - - const res = await gptAPICall(prompt, GPTCallType.FILL); - - if (res) { - const assignments: { [title: string]: { number: string; content: string } } = JSON.parse(res); - //console.log('assignments', GPTAssignments, 'assignment string', GPTAssignmentString, 'field content', fieldContent, 'response', res, 'assignments', assignments); - Object.entries(assignments).forEach(([title, info]) => { - const field: Field = template.fields[Number(info.number)]; - const col = this.getColByTitle(title); - - const doc = FieldUtils.TextField( - { - tl: field.tl, - br: field.br, - }, - template.height, - template.width, - col.title, - info.content ?? '', - field.opts - ); - - rendered.push(doc); - }); - } - } catch (err) { - console.log(err); - } - } - - return rendered; - }; - - const createGeneratedImage = async (fieldNum: string, col: Col, prompt: string) => { - const url = await this.generateGPTImage(prompt); - const field: Field = template.fields[Number(fieldNum)]; - const doc = FieldUtils.ImageField( - { - tl: field.tl, - br: field.br, - }, - template.height, - template.width, - col.title, - url ?? '', - field.opts - ); - - return doc; - }; - - const renderImageCalls = async (): Promise => { - const rendered: Doc[] = []; - const calls = GPTIMGCalls; - - if (calls.length) { - try { - const renderedImages: Doc[] = await Promise.all( - calls.map(async ([fieldNum, col]) => { - const sysPrompt = - 'Your job is to create a prompt for an AI image generator to help it generate an image based on existing content in a template and a user prompt. Your prompt should focus heavily on visual elements to help the image generator; avoid unecessary info that might distract it. ONLY INCLUDE THE PROMPT, NO OTHER TEXT OR EXPLANATION. The existing content is as follows: ' + - fieldContent + - ' **** The user prompt is: ' + - col.desc; - - const prompt = await gptAPICall(sysPrompt, GPTCallType.COMPLETEPROMPT); - console.log(sysPrompt, prompt); - - return createGeneratedImage(fieldNum, col, prompt); - }) - ); - - const renderedTemplates: Doc[] = await Promise.all(renderedImages); - renderedTemplates.forEach(doc => rendered.push(doc)); - } catch (e) { - console.log(e); - } - } - - return rendered; - }; - - const fields: Doc[] = []; - - const GPTAssignments = Object.entries(assignments).filter(([f, col]) => this._columns.includes(col)); - const nonGPTAssignments: [string, Col][] = Object.entries(assignments).filter(a => !GPTAssignments.includes(a)); - const GPTTextCalls = GPTAssignments.filter(([str, col]) => col.type === TemplateFieldType.TEXT); - const GPTIMGCalls = GPTAssignments.filter(([str, col]) => col.type === TemplateFieldType.VISUAL); - - const stringifyGPTInfo = (calls: [string, Col][]): string => { - let string: string = '*** COLUMN INFO:'; - calls.forEach(([fieldNum, col]) => { - string += `--- title: ${col.title}, prompt: ${col.desc}, word limit: ${wordLimit(col.sizes[0])} words, assigned field: ${fieldNum} ---`; - }); - return (string += ' ***'); - }; - - const GPTTextAssignment = stringifyGPTInfo(GPTTextCalls); - - let fieldContent: string = ''; - - Object.entries(nonGPTAssignments).forEach(([f, strCol]) => { - const field: Field = template.fields[Number(f)]; - const col = strCol[1]; - - const doc = (col.type === TemplateFieldType.VISUAL ? FieldUtils.ImageField : FieldUtils.TextField)( - { - tl: field.tl, - br: field.br, - }, - template.height, - template.width, - col.title, - col.defaultContent ?? '', - field.opts - ); - - fieldContent += `--- Field #${f} (title: ${col.title}): ${col.defaultContent ?? ''} ---`; - - fields.push(doc); - }); - - template.decorations.forEach(dec => { - const doc = FieldUtils.FreeformField( - { - tl: dec.tl, - br: dec.br, - }, - template.height, - template.width, - '', - '', - dec.opts - ); - - fields.push(doc); - }); - - const createMainDoc = (): Doc => { - const main = Docs.Create.FreeformDocument(fields, { - _height: template.height, - _width: template.width, - title: template.title, - backgroundColor: template.opts.backgroundColor, - _layout_borderRounding: `${template.opts.cornerRounding}px` ?? '0px', - borderWidth: template.opts.borderWidth, - borderColor: template.opts.borderColor, - x: 40000, - y: 40000, - }); - - const mainCollection = this._dataViz?.DocumentView?.().containerViewPath?.().lastElement()?.ComponentView as CollectionFreeFormView; - mainCollection.addDocument(main); - - return main; - }; - - const textCalls = await renderTextCalls(); - const imageCalls = await renderImageCalls(); - - textCalls.forEach(doc => { - fields.push(doc); - }); - imageCalls.forEach(doc => { - fields.push(doc); - }); - - return createMainDoc(); - }; - - compileFieldDescriptions = (templates: TemplateDocInfos[]): string => { - let descriptions: string = ''; - templates.forEach(template => { - descriptions += `---------- NEW TEMPLATE TO INCLUDE: Description of template ${template.title}'s fields: `; - template.fields.forEach((field, index) => { - descriptions += `{Field #${index}: ${field.description}} `; - }); - }); - - return descriptions; - }; - - compileColDescriptions = (cols: Col[]): string => { - let descriptions: string = ' ------------- COL DESCRIPTIONS START HERE:'; - cols.forEach(col => (descriptions += `{title: ${col.title}, sizes: ${String(col.sizes)}, type: ${col.type}, descreiption: ${col.desc}} `)); - - return descriptions; - }; - - getColByTitle = (title: string) => { - return this.fieldsInfos.filter(col => col.title === title)[0]; - }; - - @action - assignColsToFields = async (templates: TemplateDocInfos[], cols: Col[]): Promise<[TemplateDocInfos, { [field: number]: Col }][]> => { - const fieldDescriptions: string = this.compileFieldDescriptions(templates); - const colDescriptions: string = this.compileColDescriptions(cols); - - const inputText = fieldDescriptions.concat(colDescriptions); - - ++this._callCount; - const origCount = this._callCount; - - let prompt: string = `(${origCount}) ${inputText}`; - - this._GPTLoading = true; - - try { - const res = await gptAPICall(prompt, GPTCallType.TEMPLATE); - - if (res && this._callCount === origCount) { - const assignments: { [templateTitle: string]: { [field: string]: string } } = JSON.parse(res); - const brokenDownAssignments: [TemplateDocInfos, { [field: number]: Col }][] = []; - - Object.entries(assignments).forEach(([tempTitle, assignment]) => { - const template = TemplateLayouts.getTemplateByTitle(tempTitle); - if (!template) return; - const toObj = Object.entries(assignment).reduce( - (a, [fieldNum, colTitle]) => { - a[Number(fieldNum)] = this.getColByTitle(colTitle); - return a; - }, - {} as { [field: number]: Col } - ); - brokenDownAssignments.push([template, toObj]); - }); - return brokenDownAssignments; - } - } catch (err) { - console.error(err); - } - - return []; - }; - - generatePresetTemplates = async () => { - this._dataViz?.updateColDefaults(); - - const cols = this.fieldsInfos; - const templates = this.findValidTemplates(cols, TemplateLayouts.allTemplates); - - const assignments: [TemplateDocInfos, { [field: number]: Col }][] = await this.assignColsToFields(templates, cols); - - const renderedTemplatePromises: Promise[] = assignments.map(([template, assignments]) => this.fillPresetTemplate(template, assignments)); - - const renderedTemplates: Doc[] = await Promise.all(renderedTemplatePromises); - - setTimeout(() => { - this.setGSuggestedTemplates(renderedTemplates); - this._GPTLoading = false; - }); - }; - - @action setExpandedView = (info: { icon: ImageField; doc: Doc } | undefined) => { - if (info) { - const doc = info.doc; - const wrapper: Doc = Docs.Create.FreeformDocument([info.doc], { _height: NumListCast(doc._height)[0], _width: NumListCast(doc._width)[0], title: ''}); - const newInfo = {icon: new ImageField(''), doc: wrapper} - this._expandedPreview = newInfo; - } else { - this._expandedPreview = info; - } - }; - - get editingWindow(){ - const doc = this._expandedPreview?.doc ?? new Doc(); - const rendered = -
- Cast(doc.childLayoutTemplate, Doc, null)} - isContentActive={emptyFunction} - isAnyChildContentActive={() => true} - select={emptyFunction} - isSelected={returnFalse} - fieldKey={Doc.LayoutFieldKey(doc)} - addDocument={returnFalse} - moveDocument={returnFalse} - removeDocument={returnFalse} - PanelWidth={() => this._menuDimensions.width - 10} - PanelHeight={() => this._menuDimensions.height - 60} - ScreenToLocalTransform={() => new Transform(-this._pageX,-this._pageY, 1)} - renderDepth={5} - whenChildContentsActiveChanged={emptyFunction} - focus={emptyFunction} - styleProvider={DefaultStyleProvider} - addDocTab={this._props.addDocTab} - // eslint-disable-next-line no-use-before-define - pinToPres={() => undefined} - childFilters={returnEmptyFilter} - childFiltersByRanges={returnEmptyFilter} - searchFilterDocs={returnEmptyDoclist} - fitContentsToBox={returnTrue} - xPadding={0} - yPadding={0} - /> -
- - - return ( -
-
- {rendered} -
- - -
-
- - ); - } - - get templatesPreviewContents() { - const renderedTemplates: Doc[] = []; - - const GPTOptions =
; - - // - - return ( -
- {this._expandedPreview ? ( - this.editingWindow - ) : ( -
-
-
-
Suggested Templates
- -
-
400 ? 'center' : '' }}> - {this._GPTLoading ? ( -
- -
- ) : ( - this._suggestedTemplates - ?.map(doc => ({ icon: ImageCast(doc.icon), doc })) - .filter(info => info.icon && info.doc) - .map(info => ( -
this.setUpButtonClick(e, () => runInAction(() => this.updateSelectedTemplate(info.doc)))}> - - - -
- )) - )} -
-
-
- -
- {this._GPTOpt ? GPTOptions : null} -
-
-
-
-
-
Your Templates
- -
-
400 ? 'center' : '' }}> -
this.testTemplate()}> - -
- {this._templateDocs - .map(doc => ({ icon: ImageCast(doc.icon), doc })) - .filter(info => info.icon && info.doc) - .map(info => { - if (renderedTemplates.includes(info.doc)) return undefined; - renderedTemplates.push(info.doc); - return ( -
this.setUpButtonClick(e, () => runInAction(() => this.updateSelectedTemplate(info.doc)))}> - - - -
- ); - })} -
-
-
- )} -
- ); - } - - get savedLayoutsPreviewContents() { - return ( -
- {this._savedLayouts.map((layout, index) => ( -
this.setUpButtonClick(e, () => runInAction(() => this.updateSelectedSavedLayout(layout)))}> - {this.layoutPreviewContents(87, layout, true, index)} -
- ))} -
- ); - } - - @action updateXMargin = (input: string) => { - this._layout.xMargin = Number(input); - }; - @action updateYMargin = (input: string) => { - this._layout.yMargin = Number(input); - }; - @action updateColumns = (input: string) => { - this._layout.columns = Number(input); - }; - - get layoutConfigOptions() { - const optionInput = (icon: string, func: Function, def?: number, key?: string, noMargin?: boolean) => { - return ( -
-
- -
- func(e.currentTarget.value)} className="docCreatorMenu-input config layout-config" /> -
- ); - }; - - switch (this._layout.type) { - case LayoutType.Row: - return
{optionInput('arrows-left-right', this.updateXMargin, this._layout.xMargin, '0')}
; - case LayoutType.Column: - return
{optionInput('arrows-up-down', this.updateYMargin, this._layout.yMargin, '1')}
; - case LayoutType.Grid: - return ( -
- {optionInput('arrows-up-down', this.updateYMargin, this._layout.xMargin, '2')} - {optionInput('arrows-left-right', this.updateXMargin, this._layout.xMargin, '3')} - {optionInput('table-columns', this.updateColumns, this._layout.columns, '4', true)} -
- ); - case LayoutType.Stacked: - return null; - default: - break; - } - } - - // doc = () => { - // return Docs.Create.FreeformDocument([], { _height: 200, _width: 200, title: 'title'}); - // } - - screenToLocalTransform = () => this._props.ScreenToLocalTransform(); - - layoutPreviewContents = (outerSpan: number, altLayout?: DataVizTemplateLayout, small: boolean = false, id?: number) => { - const doc: Doc | undefined = altLayout ? altLayout.template : this._selectedTemplate; - if (!doc) return; - - const layout = altLayout ? altLayout.layout : this._layout; - - const docWidth: number = Number(doc._width); - const docHeight: number = Number(doc._height); - const horizontalSpan: number = (docWidth + layout.xMargin) * (altLayout ? altLayout.columns : this.columnsCount) - layout.xMargin; - const verticalSpan: number = (docHeight + layout.yMargin) * (altLayout ? altLayout.rows : this.rowsCount) - layout.yMargin; - const largerSpan: number = horizontalSpan > verticalSpan ? horizontalSpan : verticalSpan; - const scaledDown = (input: number) => { - return input / ((largerSpan / outerSpan) * this._layoutPreviewScale); - }; - const fontSize = Math.min(scaledDown(docWidth / 3), scaledDown(docHeight / 3)); - - return ( - //
- // 100} - // NativeHeight={() => 100} - // pointerEvents={SnappingManager.IsDragging ? returnAll : returnNone} - // isAnnotationOverlay - // isAnnotationOverlayScrollable - // childDocumentsActive={returnFalse} - // fieldKey={this._props.fieldKey + '_annotations'} - // dropAction={dropActionType.move} - // select={emptyFunction} - // addDocument={returnFalse} - // removeDocument={returnFalse} - // moveDocument={returnFalse} - // renderDepth={this._props.renderDepth + 1}> - // {null} - // - //
-
-
- - - {altLayout ? ( - - ) : null} -
- { -
- {this._layout.type === LayoutType.Stacked ? ( -
- All -
- ) : ( - this.docsToRender.map(num => ( -
this._dataViz?.setSpecialHighlightedRow(num)} - onMouseLeave={() => this._dataViz?.setSpecialHighlightedRow(undefined)} - className="docCreatorMenu-layout-preview-item" - style={{ - width: scaledDown(docWidth), - height: scaledDown(docHeight), - fontSize: fontSize, - }}> - {num} -
- )) - )} -
- } -
- ); - }; - - get optionsMenuContents() { - const layoutEquals = (layout: DataVizTemplateLayout) => {}; //TODO: ADD LATER - - const layoutOption = (option: LayoutType, optStyle?: {}, specialFunc?: Function) => { - return ( -
- this.setUpButtonClick(e, () => { - specialFunc?.(); - runInAction(() => (this._layout.type = option)); - }) - }> - {option} -
- ); - }; - - const selectionBox = (width: number, height: number, icon: string, specClass?: string, options?: JSX.Element[], manual?: boolean): JSX.Element => { - return ( -
-
- -
- {manual ? ( - - ) : ( - - )} -
- ); - }; - - const repeatOptions = [0, 1, 2, 3, 4, 5]; - - return ( -
-
-
-
{this._layout.type ? this._layout.type.toUpperCase() : 'Choose Layout'}
-
- {layoutOption(LayoutType.Stacked)} - {layoutOption(LayoutType.Grid, undefined, () => { - if (!this._layout.columns) this._layout.columns = Math.ceil(Math.sqrt(this.docsToRender.length)); - })} - {layoutOption(LayoutType.Row)} - {layoutOption(LayoutType.Column)} - {layoutOption(LayoutType.Custom, { borderBottom: `0px` })} -
-
- -
- {this._layout.type ? this.layoutConfigOptions : null} - {this._layoutPreview ? this.layoutPreviewContents(this._menuDimensions.width * 0.75) : null} - {selectionBox( - 60, - 20, - 'repeat', - undefined, - repeatOptions.map(num => ) - )} -
-
- - -
-
- ); - } - - get dashboardContents() { - const sizes: string[] = ['tiny', 'small', 'medium', 'large', 'huge']; - - const fieldPanel = (field: Col) => { - return ( -
-
- {`${field.title} Field`} - -
-
-
-
Title
-