From b1fc8f322b20e9ed031838673393b8facc201e8a Mon Sep 17 00:00:00 2001 From: Trang Doan Date: Wed, 2 Apr 2025 13:39:14 -0400 Subject: [PATCH 1/3] add formating option --- src/features/attributeSelect.tsx | 180 ++++++++++++++++++++++++++++--- 1 file changed, 163 insertions(+), 17 deletions(-) diff --git a/src/features/attributeSelect.tsx b/src/features/attributeSelect.tsx index 09bcb4d..f0cdac4 100644 --- a/src/features/attributeSelect.tsx +++ b/src/features/attributeSelect.tsx @@ -12,6 +12,8 @@ import { NumericInput, Slider, Popover, + Icon, + Tooltip, } from "@blueprintjs/core"; import { Select } from "@blueprintjs/select"; import createHTMLObserver from "roamjs-components/dom/createHTMLObserver"; @@ -35,6 +37,17 @@ import getSettingValueFromTree from "roamjs-components/util/getSettingValueFromT const CONFIG = `roam/js/attribute-select`; +const TEMPLATE_MAP = { + "No styling": "text => text", + "Remove Double Brackets": `text => text.replace(/^\\[\\[(.*?)\\]\\]$/g, '$1')`, + "Convert to Uppercase": "text => text.toUpperCase()", + "Add Prefix": "text => `Status: ${text}`", + "Capitalize Words": "text => text.split(' ').map(word => word.charAt(0).toUpperCase() + word.slice(1)).join(' ')", + "Custom Format": "text => text" +} as const; + +type TemplateName = keyof typeof TEMPLATE_MAP; + type AttributeButtonPopoverProps = { items: T[]; onItemSelect?: (selectedItem: T) => void; @@ -59,17 +72,40 @@ const AttributeButtonPopover = ({ return String(item).toLowerCase().includes(query.toLowerCase()); }; const [sliderValue, setSliderValue] = useState(0); + useEffect(() => { setSliderValue(Number(currentValue)); }, [isOpen, currentValue]); const formatDisplayText = (text: string): string => { - // TODO: for doantrang982/eng-77-decouple-display-from-output: Create formatDisplayText from configPage - // const match = text.match(/\[\[(.*?)\]\]/); - // if (match && match[1]) { - // return match[1]; - // } - return text; + try { + const configUid = getPageUidByPageTitle(CONFIG); + const attributesNode = getSubTree({ + key: "attributes", + parentUid: configUid, + }); + const attributeUid = getSubTree({ + key: attributeName, + parentUid: attributesNode.uid, + }).uid; + const format = getSettingValueFromTree({ + key: "format", + parentUid: attributeUid, + }) || "text => text"; + + const transform = new Function("text", ` + try { + return (${format})(text); + } catch (e) { + console.error("Error in transform function:", e); + return text; + } + `) as (text: string) => string; + return transform(text); + } catch (e) { + console.error("Invalid transformation function:", e); + return text; + } }; // Only show filter if we have more than 10 items @@ -82,7 +118,7 @@ const AttributeButtonPopover = ({ items={items} activeItem={currentValue as T} filterable={shouldFilter} - // transformItem={(item) => formatDisplayText(String(item))} + transformItem={(item) => formatDisplayText(String(item))} onItemSelect={(s) => { updateBlock({ text: `${attributeName}:: ${s}`, @@ -471,6 +507,33 @@ const TabsPanel = ({ const [optionType, setOptionType] = useState(initialOptionType || "text"); const [min, setMin] = useState(Number(rangeNode.children[0]?.text) || 0); const [max, setMax] = useState(Number(rangeNode.children[1]?.text) || 10); + + const { initialFormat, initialTemplate } = useMemo(() => { + const savedFormat = getSettingValueFromTree({ + key: "format", + parentUid: attributeUid, + }) || "text => text"; + + const savedTemplate = getSettingValueFromTree({ + key: "template", + parentUid: attributeUid, + }); + + if (savedTemplate) { + return { initialFormat: savedFormat, initialTemplate: savedTemplate }; + } + + const matchingTemplate = Object.entries(TEMPLATE_MAP).find( + ([_, func]) => func === savedFormat + ); + return { + initialFormat: savedFormat, + initialTemplate: matchingTemplate ? matchingTemplate[0] : "No styling" + }; + }, [attributeUid]); + + const [transformFunction, setTransformFunction] = useState(initialFormat); + const [selectedTemplate, setSelectedTemplate] = useState(initialTemplate); // For a better UX replace renderBlock with a controlled list // add Edit, Delete, and Add New buttons @@ -567,16 +630,99 @@ const TabsPanel = ({ {optionType === "text" && ( -