From 7a50709df5d3b524a5a6c686a8aa7a6eb9454970 Mon Sep 17 00:00:00 2001 From: Rizky Date: Sun, 24 Mar 2024 11:22:35 +0700 Subject: [PATCH] wip fix --- .../src/nova/ed/panel/side/prop-instance.tsx | 7 + .../panel/side/prop-instance/prop-button.tsx | 24 -- .../panel/side/prop-instance/prop-option.tsx | 343 ++++++++++++------ .../ed/panel/side/prop-master/prop-form.tsx | 2 +- app/web/src/utils/types/meta-fn.ts | 2 +- app/web/src/utils/ui/popover.tsx | 2 + 6 files changed, 251 insertions(+), 129 deletions(-) diff --git a/app/web/src/nova/ed/panel/side/prop-instance.tsx b/app/web/src/nova/ed/panel/side/prop-instance.tsx index b9340683..fca52aa3 100644 --- a/app/web/src/nova/ed/panel/side/prop-instance.tsx +++ b/app/web/src/nova/ed/panel/side/prop-instance.tsx @@ -235,6 +235,13 @@ export const EdSidePropInstance: FC<{ meta: IMeta }> = ({ meta }) => { if (type === "button") hasCode = false; + if ( + type === "option" && + cprop.meta?.option_mode === "checkbox" + ) { + hasCode = false; + } + const labelClick = (e: MouseEvent) => { e.preventDefault(); local.pick = { mprop, name }; diff --git a/app/web/src/nova/ed/panel/side/prop-instance/prop-button.tsx b/app/web/src/nova/ed/panel/side/prop-instance/prop-button.tsx index d4e075e6..29a74235 100644 --- a/app/web/src/nova/ed/panel/side/prop-instance/prop-button.tsx +++ b/app/web/src/nova/ed/panel/side/prop-instance/prop-button.tsx @@ -87,30 +87,6 @@ export const EdPropInstanceButton: FC<{ ); }; -const Preview: FC<{ filename: string }> = ({ filename }) => { - const p = useGlobal(EDGlobal, "EDITOR"); - const ext = filename.split(".").pop() || ""; - const is_image = isImage(ext); - return ( -
- {is_image && ( - {" - )} - {!is_image && ( -
- {ext} -
- )} - Browse File -
- ); -}; - const parseval = (text: string) => { const val = text.substring(`siteurl('/_file`.length); diff --git a/app/web/src/nova/ed/panel/side/prop-instance/prop-option.tsx b/app/web/src/nova/ed/panel/side/prop-instance/prop-option.tsx index 3d867e97..17c18240 100644 --- a/app/web/src/nova/ed/panel/side/prop-instance/prop-option.tsx +++ b/app/web/src/nova/ed/panel/side/prop-instance/prop-option.tsx @@ -1,4 +1,4 @@ -import { FC, useEffect } from "react"; +import { FC, Fragment, useEffect } from "react"; import { useGlobal, useLocal } from "web-utils"; import { apiProxy } from "../../../../../base/load/api/api-proxy"; import { dbProxy } from "../../../../../base/load/db/db-proxy"; @@ -6,6 +6,14 @@ import { FMCompDef, FNCompDef } from "../../../../../utils/types/meta-fn"; import { EDGlobal } from "../../../logic/ed-global"; import { treeRebuild } from "../../../logic/tree/build"; import { EdPropLabel } from "./prop-label"; +import { ChevronDown } from "../../tree/node/item/indent"; +import { Popover } from "../../../../../utils/ui/popover"; + +type MetaOption = { + label: string; + value: any; + options?: MetaOption[]; +}; export const EdPropInstanceOptions: FC<{ name: string; @@ -20,11 +28,14 @@ export const EdPropInstanceOptions: FC<{ loaded: false as any, isOpen: false, val: "", - metaFn: null as null | (() => Promise<{ label: string; value: any }[]>), + metaFn: null as null | (() => Promise), + checkbox: { + width: 0, + }, }); const p = useGlobal(EDGlobal, "EDITOR"); - let metaOptions: { label: string; value: any }[] = []; + let metaOptions: MetaOption[] = []; if (cprop.meta?.options || cprop.meta?.optionsBuilt) { if (!local.loaded) { @@ -70,7 +81,7 @@ else metaOptions = resOpt; } catch (e) {} useEffect(() => { - if (Array.isArray(metaOptions)) { + if (Array.isArray(metaOptions) && !Array.isArray(evalue)) { local.val = evalue; local.render(); } @@ -120,105 +131,6 @@ else metaOptions = resOpt; )} - {/* {mode === "dropdown" && ( - <> - { - local.isOpen = false; - local.render(); - }} - onInputValueChange={(e) => { - local.val = e; - local.isOpen = true; - local.render(); - }} - onChange={(sel) => { - if (!sel) { - local.val = evalue; - local.isOpen = false; - local.render(); - } else { - const val = JSON.stringify(sel.value); - local.isOpen = false; - onChange(val); - } - }} - itemToString={(item) => (item ? item.value : "")} - > - {({ - getInputProps, - getItemProps, - getLabelProps, - getMenuProps, - isOpen, - inputValue, - highlightedIndex, - selectedItem, - getRootProps, - }) => ( -
-
- { - local.val = ""; - local.isOpen = true; - local.render(); - }} - onClick={() => { - local.isOpen = true; - local.render(); - }} - onBlur={() => { - local.val = evalue; - local.isOpen = false; - local.render(); - }} - type="search" - spellCheck={false} - className="flex-1 self-stretch font-mono border-2 border-transparent outline-none bg-transparent focus:bg-white focus:border-blue-500 border-slate-300 text-[11px] min-h-[28px] pl-1 " - /> -
-
    - {isOpen - ? metaOptions - .filter( - (item) => - !inputValue || item.value.includes(inputValue) - ) - .map((item, index) => ( -
  • - {item.label || item.value} -
  • - )) - : null} -
-
- )} -
- - )} */} {mode === "button" && (
{Array.isArray(metaOptions) && @@ -242,7 +154,232 @@ else metaOptions = resOpt; })}
)} + + {mode === "checkbox" && ( + +
+ {Array.isArray(metaOptions) && + metaOptions.map((item, idx) => { + const val: any[] = Array.isArray(evalue) ? evalue : []; + + const found = val.find((e) => { + if (!item.options) { + return e === item.value; + } else { + if (typeof e === "object" && e.value === item.value) { + return true; + } + return false; + } + }); + return ( + + { + onChange(JSON.stringify(val)); + local.render(); + }} + /> + {item.options && + found && + item.options.map((child, idx) => { + let checked: any[] = found.checked; + + return ( + { + found.checked = newval; + + onChange(JSON.stringify(val)); + local.render(); + }} + /> + ); + })} + + ); + })} +
+ + } + asChild + > +
{}} + ref={(el) => { + if (!local.checkbox.width && el) { + const bound = el.getBoundingClientRect(); + local.checkbox.width = bound.width; + local.render(); + } + }} + > +
+
+ {Array.isArray(evalue) + ? evalue.length === 0 + ? "Select Item" + : `${evalue.length} selected` + : `Select Item`} +
+
+
+ +
+
+
+ )} ); }; + +const SingleCheckbox = ({ + val, + item, + idx, + onChange, + depth, +}: { + item: MetaOption; + idx: number; + depth?: number; + val: any[]; + onChange: (val: MetaOption[]) => void; +}) => { + const is_check = !!val.find((e) => { + if (!item.options) { + return e === item.value; + } else { + if (typeof e === "object" && e.value === item.value) { + return true; + } + return false; + } + }); + + return ( +
{ + if (item.options) { + let idx = val.findIndex((e) => { + if (typeof e === "object" && e.value === item.value) { + return true; + } + return false; + }); + + if (idx >= 0) { + val.splice(idx, 1); + } else { + val.push({ value: item.value, checked: [] }); + } + } else { + let idx = val.findIndex((e) => e === item.value); + + if (idx >= 0) { + val.splice(idx, 1); + } else { + val.push(item.value); + } + } + onChange(val); + }} + > + {!is_check ? unchecked : checked} +
{item.label}
+
+ ); +}; + +const checked = ( + + + + +); +const unchecked = ( + + + +); diff --git a/app/web/src/nova/ed/panel/side/prop-master/prop-form.tsx b/app/web/src/nova/ed/panel/side/prop-master/prop-form.tsx index 9d64d720..2ff9cc21 100644 --- a/app/web/src/nova/ed/panel/side/prop-master/prop-form.tsx +++ b/app/web/src/nova/ed/panel/side/prop-master/prop-form.tsx @@ -337,7 +337,7 @@ export const EdPropPopoverForm: FC<{
MODE
- {["button", "dropdown"].map((e) => ( + {["button", "dropdown", "checkbox"].map((e) => (
{ diff --git a/app/web/src/utils/types/meta-fn.ts b/app/web/src/utils/types/meta-fn.ts index 591fb6a4..2876467c 100644 --- a/app/web/src/utils/types/meta-fn.ts +++ b/app/web/src/utils/types/meta-fn.ts @@ -44,7 +44,7 @@ type FNCompMeta = { type: "file" | "text" | "option" | "content-element" | "button"; options?: string; optionsBuilt?: string; - option_mode?: "dropdown" | "button"; + option_mode?: "dropdown" | "button" | "checkbox"; }; export type FMCompDef = TypedMap< diff --git a/app/web/src/utils/ui/popover.tsx b/app/web/src/utils/ui/popover.tsx index 308e6bb7..58232229 100644 --- a/app/web/src/utils/ui/popover.tsx +++ b/app/web/src/utils/ui/popover.tsx @@ -187,6 +187,7 @@ export function Popover({ children: React.ReactNode; content?: React.ReactNode; arrow?: boolean; + asChild?: boolean } & PopoverOptions) { const popover = usePopover({ modal, ...restOptions }); @@ -196,6 +197,7 @@ export function Popover({ return (