From 51de3a3cdd22f862c63057b0bf7a924a5c296f93 Mon Sep 17 00:00:00 2001 From: Kamal Qureshi Date: Wed, 25 Jun 2025 13:40:15 +0500 Subject: [PATCH 1/3] Initialize tags component --- .../src/comps/comps/tagsComp/tagsCompView.tsx | 92 +++++++++++++++++++ .../src/comps/controls/optionsControl.tsx | 32 +++++++ client/packages/lowcoder/src/comps/index.tsx | 14 +++ .../lowcoder/src/comps/uiCompRegistry.ts | 1 + .../packages/lowcoder/src/i18n/locales/en.ts | 1 + .../src/pages/editor/editorConstants.tsx | 1 + 6 files changed, 141 insertions(+) create mode 100644 client/packages/lowcoder/src/comps/comps/tagsComp/tagsCompView.tsx diff --git a/client/packages/lowcoder/src/comps/comps/tagsComp/tagsCompView.tsx b/client/packages/lowcoder/src/comps/comps/tagsComp/tagsCompView.tsx new file mode 100644 index 0000000000..9979c5a1b5 --- /dev/null +++ b/client/packages/lowcoder/src/comps/comps/tagsComp/tagsCompView.tsx @@ -0,0 +1,92 @@ +import { AnimationStyle, BoolCodeControl, ButtonEventHandlerControl, CommonNameConfig, DropdownOptionControl, IconControl, LinkStyle, NameConfig, NameConfigDisabled, RefControl, Section, SelectOptionControl, StringControl, TabsOptionControl, TagsOptionControl, UICompBuilder, blurMethod, clickMethod, focusWithOptions, migrateOldData, refMethods, sectionNames, stringExposingStateControl, styleControl, withDefault, withExposingConfigs } from "@lowcoder-ee/index.sdk"; +import React from "react"; +import { trans } from "i18n"; +import { buttonRefMethods } from "../buttonComp/buttonCompConstants"; +import { Tag } from "antd"; +import { autoCompleteRefMethods } from "../autoCompleteComp/autoCompleteConstants"; + + +// const TagsCompView = (function () { +// // const childrenMap = { +// // text: withDefault(StringControl, trans("link.link")), +// // onEvent: ButtonEventHandlerControl, +// // disabled: BoolCodeControl, +// // loading: BoolCodeControl, + +// // // style: migrateOldData(styleControl(LinkStyle, 'style')), +// // animationStyle: styleControl(AnimationStyle, 'animationStyle'), +// // prefixIcon: IconControl, +// // suffixIcon: IconControl, +// // viewRef: RefControl, +// // }; + +// const childrenMap = { +// text: stringExposingStateControl("text", "world"), +// // options: TabsOptionControl, +// }; +// return new UICompBuilder(childrenMap, (props) => { +// return ( +// Tag 1 +// ) +// }) +// .setPropertyViewFn((children) => { +// return( +//
+// {/* {children.options.propertyView({})} */} +// {children.text.propertyView({ label: trans("text") })} +//
+// ) +// }) +// .build(); +// })(); + +const multiTags = (function () { + const childrenMap = { + text: stringExposingStateControl("text", "world"), + options: TagsOptionControl, + }; + + return new UICompBuilder(childrenMap, (props) => { + const text = props.text.value; + console.log(props.options) + return ( + <> + {props.options.map(tag => ( + {tag.label} + ))} + + ); + }) + .setPropertyViewFn((children: any) => { + return ( +
+ {children.options.propertyView({})} + {children.text.propertyView({ label: "Text" })} +
+ ) + }) + .build(); +})() + + +// const childrenMap = { +// text: stringExposingStateControl("text", "world"), +// options: TagsOptionControl, +// }; + +// const TagsCompView = new UICompBuilder(childrenMap, (props: any) => { +// const text = props.text.value; +// return
Hello {text}
; +// }) +// .setPropertyViewFn((children: any) => { +// return ( +//
+// {children.options.propertyView({})} +// {children.text.propertyView({ label: "Text" })} +//
+// ) +// }) +// .build(); + +export const MultiTagsComp = withExposingConfigs(multiTags, [new NameConfig("text", "")]); + diff --git a/client/packages/lowcoder/src/comps/controls/optionsControl.tsx b/client/packages/lowcoder/src/comps/controls/optionsControl.tsx index 1d36ec52c5..55e6554c63 100644 --- a/client/packages/lowcoder/src/comps/controls/optionsControl.tsx +++ b/client/packages/lowcoder/src/comps/controls/optionsControl.tsx @@ -557,6 +557,7 @@ const TabsOption = new MultiCompBuilder( )) .build(); + export const TabsOptionControl = manualOptionsControl(TabsOption, { initOptions: [ @@ -567,6 +568,37 @@ export const TabsOptionControl = manualOptionsControl(TabsOption, { autoIncField: "id", }); +const TagsOption = new MultiCompBuilder( + { + id: valueComp(-1), + label: StringControl, + icon: IconControl, + iconPosition: withDefault(LeftRightControl, "left"), + hidden: BoolCodeControl, + }, + (props) => props +) + .setPropertyViewFn((children) => ( + <> + {children.label.propertyView({ label: trans("label") })} + {children.icon.propertyView({ label: trans("icon") })} + {children.iconPosition.propertyView({ + label: trans("tabbedContainer.iconPosition"), + radioButton: true, + })} + {hiddenPropertyView(children)} + + )) + .build(); + +export const TagsOptionControl = optionsControl(TagsOption, { + initOptions: [ + { id: 0, label: "Option 1" }, + { id: 1, label: "Option 2" }, + ], + autoIncField: "id", +}); + const StyledIcon = styled.span` margin: 0 4px 0 14px; `; diff --git a/client/packages/lowcoder/src/comps/index.tsx b/client/packages/lowcoder/src/comps/index.tsx index 2395f4f290..00d54a9b2a 100644 --- a/client/packages/lowcoder/src/comps/index.tsx +++ b/client/packages/lowcoder/src/comps/index.tsx @@ -193,6 +193,7 @@ import { DrawerComp } from "./hooks/drawerComp"; import { ModalComp } from "./hooks/modalComp"; import { defaultCollapsibleContainerData } from "./comps/containerComp/collapsibleContainerComp"; import { ContainerComp as FloatTextContainerComp } from "./comps/containerComp/textContainerComp"; +import { MultiTagsComp } from "./comps/tagsComp/tagsCompView"; type Registry = { [key in UICompType]?: UICompManifest; @@ -709,6 +710,19 @@ export var uiCompMap: Registry = { }, defaultDataFn: defaultGridData, }, + multiTags: { + name: trans("tags"), + enName: "tags", + description: "Desc of Tags", + categories: ["layout"], + icon: FloatingButtonCompIcon, + keywords: trans("uiComp.floatButtonCompKeywords"), + comp: MultiTagsComp, + layoutInfo: { + w: 9, + h: 5, + }, + }, modal: { name: trans("uiComp.modalCompName"), enName: "Modal", diff --git a/client/packages/lowcoder/src/comps/uiCompRegistry.ts b/client/packages/lowcoder/src/comps/uiCompRegistry.ts index 4c320de479..07f0e54b43 100644 --- a/client/packages/lowcoder/src/comps/uiCompRegistry.ts +++ b/client/packages/lowcoder/src/comps/uiCompRegistry.ts @@ -106,6 +106,7 @@ export type UICompType = | "container" | "pageLayout" // added by Falk Wolsky | "floatTextContainer" + | "multiTags" // Added by Kamal Qureshi | "tabbedContainer" | "modal" | "listView" diff --git a/client/packages/lowcoder/src/i18n/locales/en.ts b/client/packages/lowcoder/src/i18n/locales/en.ts index 44f5f4b1dd..31750f7897 100644 --- a/client/packages/lowcoder/src/i18n/locales/en.ts +++ b/client/packages/lowcoder/src/i18n/locales/en.ts @@ -45,6 +45,7 @@ export const en = { "accessControl": "Access Control", "copySuccess": "Copied Successfully", "copyError": "Copy Error", + "tags": "Tags", "api": { "publishSuccess": "Published Successfully", diff --git a/client/packages/lowcoder/src/pages/editor/editorConstants.tsx b/client/packages/lowcoder/src/pages/editor/editorConstants.tsx index a931455d4b..9087b1e7d2 100644 --- a/client/packages/lowcoder/src/pages/editor/editorConstants.tsx +++ b/client/packages/lowcoder/src/pages/editor/editorConstants.tsx @@ -237,6 +237,7 @@ export const CompStateIcon: { step: , table: , text: , + multiTags: , timeline: , toggleButton: , tour: , From 1c6f8bd15c56a1fa1a810c4e7514ea0fb29c71f0 Mon Sep 17 00:00:00 2001 From: Kamal Qureshi Date: Thu, 17 Jul 2025 17:58:38 +0500 Subject: [PATCH 2/3] Tags Component Completed --- .../lowcoder-design/src/icons/index.tsx | 2 + .../lowcoder-design/src/icons/v2/tags-l.svg | 10 + .../lowcoder-design/src/icons/v2/tags-s.svg | 10 + .../comps/selectInputComp/multiSelectComp.tsx | 2 +- .../comps/selectInputComp/selectComp.tsx | 2 +- .../src/comps/comps/tagsComp/tagsCompView.tsx | 229 ++++++++++++------ .../src/comps/controls/optionsControl.tsx | 79 +++++- client/packages/lowcoder/src/comps/index.tsx | 4 +- .../packages/lowcoder/src/i18n/locales/en.ts | 12 + 9 files changed, 270 insertions(+), 80 deletions(-) create mode 100644 client/packages/lowcoder-design/src/icons/v2/tags-l.svg create mode 100644 client/packages/lowcoder-design/src/icons/v2/tags-s.svg diff --git a/client/packages/lowcoder-design/src/icons/index.tsx b/client/packages/lowcoder-design/src/icons/index.tsx index b033d52e92..9c00866feb 100644 --- a/client/packages/lowcoder-design/src/icons/index.tsx +++ b/client/packages/lowcoder-design/src/icons/index.tsx @@ -355,6 +355,7 @@ export { ReactComponent as VideoCameraStreamCompIconSmall } from "./v2/camera-st export { ReactComponent as VideoScreenshareCompIconSmall } from "./v2/screen-share-stream-s.svg"; // new export { ReactComponent as SignatureCompIconSmall } from "./v2/signature-s.svg"; export { ReactComponent as StepCompIconSmall } from "./v2/steps-s.svg"; +export { ReactComponent as TagsCompIconSmall } from "./v2/tags-s.svg" export { ReactComponent as CandlestickChartCompIconSmall } from "./v2/candlestick-chart-s.svg"; // new @@ -468,6 +469,7 @@ export { ReactComponent as SignatureCompIcon } from "./v2/signature-m.svg"; export { ReactComponent as GanttCompIcon } from "./v2/gantt-chart-m.svg"; export { ReactComponent as KanbanCompIconSmall } from "./v2/kanban-s.svg"; export { ReactComponent as KanbanCompIcon } from "./v2/kanban-m.svg"; +export { ReactComponent as TagsCompIcon } from "./v2/tags-l.svg"; export { ReactComponent as CandlestickChartCompIcon } from "./v2/candlestick-chart-m.svg"; export { ReactComponent as FunnelChartCompIcon } from "./v2/funnel-chart-m.svg"; diff --git a/client/packages/lowcoder-design/src/icons/v2/tags-l.svg b/client/packages/lowcoder-design/src/icons/v2/tags-l.svg new file mode 100644 index 0000000000..cd1d0368c3 --- /dev/null +++ b/client/packages/lowcoder-design/src/icons/v2/tags-l.svg @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff --git a/client/packages/lowcoder-design/src/icons/v2/tags-s.svg b/client/packages/lowcoder-design/src/icons/v2/tags-s.svg new file mode 100644 index 0000000000..d45fcb0aa8 --- /dev/null +++ b/client/packages/lowcoder-design/src/icons/v2/tags-s.svg @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff --git a/client/packages/lowcoder/src/comps/comps/selectInputComp/multiSelectComp.tsx b/client/packages/lowcoder/src/comps/comps/selectInputComp/multiSelectComp.tsx index 8380c56722..2527d57bd4 100644 --- a/client/packages/lowcoder/src/comps/comps/selectInputComp/multiSelectComp.tsx +++ b/client/packages/lowcoder/src/comps/comps/selectInputComp/multiSelectComp.tsx @@ -30,7 +30,7 @@ let MultiSelectBasicComp = (function () { padding: PaddingControl, }; return new UICompBuilder(childrenMap, (props, dispatch) => { - const valueSet = new Set(props.options.map((o) => o.value)); // Filter illegal default values entered by the user + const valueSet = new Set((props.options as any[]).map((o: any) => o.value)); // Filter illegal default values entered by the user const [ validateState, handleChange, diff --git a/client/packages/lowcoder/src/comps/comps/selectInputComp/selectComp.tsx b/client/packages/lowcoder/src/comps/comps/selectInputComp/selectComp.tsx index eef8cad608..a2415b4a58 100644 --- a/client/packages/lowcoder/src/comps/comps/selectInputComp/selectComp.tsx +++ b/client/packages/lowcoder/src/comps/comps/selectInputComp/selectComp.tsx @@ -39,7 +39,7 @@ let SelectBasicComp = (function () { const propsRef = useRef>(props); propsRef.current = props; - const valueSet = new Set(props.options.map((o) => o.value)); // Filter illegal default values entered by the user + const valueSet = new Set((props.options as any[]).map((o: any) => o.value)); // Filter illegal default values entered by the user return props.label({ required: props.required, diff --git a/client/packages/lowcoder/src/comps/comps/tagsComp/tagsCompView.tsx b/client/packages/lowcoder/src/comps/comps/tagsComp/tagsCompView.tsx index 9979c5a1b5..f59898964c 100644 --- a/client/packages/lowcoder/src/comps/comps/tagsComp/tagsCompView.tsx +++ b/client/packages/lowcoder/src/comps/comps/tagsComp/tagsCompView.tsx @@ -1,92 +1,179 @@ -import { AnimationStyle, BoolCodeControl, ButtonEventHandlerControl, CommonNameConfig, DropdownOptionControl, IconControl, LinkStyle, NameConfig, NameConfigDisabled, RefControl, Section, SelectOptionControl, StringControl, TabsOptionControl, TagsOptionControl, UICompBuilder, blurMethod, clickMethod, focusWithOptions, migrateOldData, refMethods, sectionNames, stringExposingStateControl, styleControl, withDefault, withExposingConfigs } from "@lowcoder-ee/index.sdk"; -import React from "react"; +import { + BoolCodeControl, + ButtonEventHandlerControl, + InputLikeStyle, + NameConfig, + Section, + UICompBuilder, + hiddenPropertyView, + sectionNames, + showDataLoadingIndicatorsPropertyView, + styleControl, + withExposingConfigs +} from "@lowcoder-ee/index.sdk"; +import styled from "styled-components"; +import React, { useContext } from "react"; import { trans } from "i18n"; -import { buttonRefMethods } from "../buttonComp/buttonCompConstants"; import { Tag } from "antd"; -import { autoCompleteRefMethods } from "../autoCompleteComp/autoCompleteConstants"; +import { EditorContext } from "comps/editorState"; +import { PresetStatusColorTypes } from "antd/es/_util/colors"; +import { hashToNum } from "util/stringUtils"; +import { TagsCompOptionsControl } from "comps/controls/optionsControl"; +import { useCompClickEventHandler } from "@lowcoder-ee/comps/utils/useCompClickEventHandler"; +const colors = PresetStatusColorTypes; -// const TagsCompView = (function () { -// // const childrenMap = { -// // text: withDefault(StringControl, trans("link.link")), -// // onEvent: ButtonEventHandlerControl, -// // disabled: BoolCodeControl, -// // loading: BoolCodeControl, - -// // // style: migrateOldData(styleControl(LinkStyle, 'style')), -// // animationStyle: styleControl(AnimationStyle, 'animationStyle'), -// // prefixIcon: IconControl, -// // suffixIcon: IconControl, -// // viewRef: RefControl, -// // }; +// These functions are used for individual tag styling +function getTagColor(tagText : any, tagOptions: any[]) { + const foundOption = tagOptions.find((option: { label: any; }) => option.label === tagText); + if (foundOption) { + if (foundOption.colorType === "preset") { + return foundOption.presetColor; + } else if (foundOption.colorType === "custom") { + return undefined; + } + return foundOption.color; + } + const index = Math.abs(hashToNum(tagText)) % colors.length; + return colors[index]; +} -// const childrenMap = { -// text: stringExposingStateControl("text", "world"), -// // options: TabsOptionControl, -// }; -// return new UICompBuilder(childrenMap, (props) => { -// return ( -// Tag 1 -// ) -// }) -// .setPropertyViewFn((children) => { -// return( -//
-// {/* {children.options.propertyView({})} */} -// {children.text.propertyView({ label: trans("text") })} -//
-// ) -// }) -// .build(); -// })(); +const getTagStyle = (tagText: any, tagOptions: any[], baseStyle: any = {}) => { + const foundOption = tagOptions.find((option: { label: any; }) => option.label === tagText); + if (foundOption) { + const style: any = { ...baseStyle }; + + if (foundOption.colorType === "custom") { + style.backgroundColor = foundOption.color; + style.color = foundOption.textColor; + style.border = `1px solid ${foundOption.color}`; + } + + if (foundOption.border) { + style.borderColor = foundOption.border; + if (!foundOption.colorType || foundOption.colorType !== "custom") { + style.border = `1px solid ${foundOption.border}`; + } + } + + if (foundOption.radius) { + style.borderRadius = foundOption.radius; + } + + if (foundOption.margin) { + style.margin = foundOption.margin; + } + + if (foundOption.padding) { + style.padding = foundOption.padding; + } + + return style; + } + return baseStyle; +}; + +function getTagIcon(tagText: any, tagOptions: any[]) { + const foundOption = tagOptions.find(option => option.label === tagText); + return foundOption ? foundOption.icon : undefined; +} const multiTags = (function () { + + const StyledTag = styled(Tag)<{ $style: any, $bordered: boolean, $customStyle: any }>` + display: flex; + justify-content: center; + align-items: center; + width: 100%; + background: ${(props) => props.$customStyle?.backgroundColor || props.$style?.background}; + color: ${(props) => props.$customStyle?.color || props.$style?.text}; + border-radius: ${(props) => props.$customStyle?.borderRadius || props.$style?.borderRadius}; + border: ${(props) => { + if (props.$customStyle?.border) return props.$customStyle.border; + return props.$bordered ? `${props.$style?.borderStyle} ${props.$style?.borderWidth} ${props.$style?.border}` : 'none'; + }}; + padding: ${(props) => props.$customStyle?.padding || props.$style?.padding}; + margin: ${(props) => props.$customStyle?.margin || props.$style?.margin}; + font-size: ${(props) => props.$style?.textSize}; + font-weight: ${(props) => props.$style?.fontWeight}; + cursor: pointer; + `; + + const StyledTagContainer = styled.div` + display: flex; + gap: 5px; + padding: 5px; + `; + const childrenMap = { - text: stringExposingStateControl("text", "world"), - options: TagsOptionControl, + options: TagsCompOptionsControl, + style: styleControl(InputLikeStyle, 'style'), + onEvent: ButtonEventHandlerControl, + borderless: BoolCodeControl, + enableIndividualStyling: BoolCodeControl, }; return new UICompBuilder(childrenMap, (props) => { - const text = props.text.value; - console.log(props.options) + const handleClickEvent = useCompClickEventHandler({onEvent: props.onEvent}); + return ( - <> - {props.options.map(tag => ( - {tag.label} - ))} - - ); + + {props.options.map((tag, index) => { + + // Use individual styling only if enableIndividualStyling is true + const tagColor = props.enableIndividualStyling ? getTagColor(tag.label, props.options) : undefined; + const tagIcon = props.enableIndividualStyling ? getTagIcon(tag.label, props.options) : tag.icon; + const tagStyle = props.enableIndividualStyling ? getTagStyle(tag.label, props.options, props.style) : {}; + + return ( + handleClickEvent()} + > + {tag.label} + + ); + })} + + ); }) .setPropertyViewFn((children: any) => { return ( -
- {children.options.propertyView({})} - {children.text.propertyView({ label: "Text" })} -
+ <> +
+ {children.options.propertyView({})} +
+ + {["logic", "both"].includes(useContext(EditorContext).editorModeStatus) && ( +
+ {children.onEvent.getPropertyView()} + {hiddenPropertyView(children)} + {showDataLoadingIndicatorsPropertyView(children)} +
+ )} + + {["layout", "both"].includes( + useContext(EditorContext).editorModeStatus + ) && ( +
+ {children.enableIndividualStyling.propertyView({ + label: trans("style.individualStyling"), + tooltip: trans("style.individualStylingTooltip") + })} + {children.borderless.propertyView({ label: trans("style.borderless") })} + {children.style.getPropertyView()} +
+ )} + ) }) .build(); })() - -// const childrenMap = { -// text: stringExposingStateControl("text", "world"), -// options: TagsOptionControl, -// }; - -// const TagsCompView = new UICompBuilder(childrenMap, (props: any) => { -// const text = props.text.value; -// return
Hello {text}
; -// }) -// .setPropertyViewFn((children: any) => { -// return ( -//
-// {children.options.propertyView({})} -// {children.text.propertyView({ label: "Text" })} -//
-// ) -// }) -// .build(); - -export const MultiTagsComp = withExposingConfigs(multiTags, [new NameConfig("text", "")]); +export const MultiTagsComp = withExposingConfigs(multiTags, [new NameConfig("options", "")]); diff --git a/client/packages/lowcoder/src/comps/controls/optionsControl.tsx b/client/packages/lowcoder/src/comps/controls/optionsControl.tsx index 55e6554c63..1186057d9c 100644 --- a/client/packages/lowcoder/src/comps/controls/optionsControl.tsx +++ b/client/packages/lowcoder/src/comps/controls/optionsControl.tsx @@ -782,14 +782,83 @@ export const StepOptionControl = optionsControl(StepOption, { uniqField: "label", }); +let TagsCompOptions = new MultiCompBuilder( + { + label: StringControl, + icon: IconControl, + colorType: withDefault(dropdownControl([ + { label: trans("style.preset"), value: "preset" }, + { label: trans("style.custom"), value: "custom" }, + ] as const, "preset"), "preset"), + presetColor: withDefault(dropdownControl(TAG_PRESET_COLORS, "blue"), "blue"), + color: withDefault(ColorControl, "#1890ff"), + textColor: withDefault(ColorControl, "#ffffff"), + border: withDefault(ColorControl, ""), + radius: withDefault(RadiusControl, ""), + margin: withDefault(StringControl, ""), + padding: withDefault(StringControl, ""), + }, + (props) => props +).build(); + +TagsCompOptions = class extends TagsCompOptions implements OptionCompProperty { + propertyView(param: { autoMap?: boolean }) { + const colorType = this.children.colorType.getView(); + return ( + <> + {this.children.label.propertyView({ label: trans("coloredTagOptionControl.tag") })} + {this.children.icon.propertyView({ label: trans("coloredTagOptionControl.icon") })} + {this.children.colorType.propertyView({ + label: trans("style.colorType"), + radioButton: true + })} + {colorType === "preset" && this.children.presetColor.propertyView({ + label: trans("style.presetColor") + })} + {colorType === "custom" && ( + <> + {this.children.color.propertyView({ label: trans("coloredTagOptionControl.color") })} + {this.children.textColor.propertyView({ label: trans("style.textColor") })} + + )} + {this.children.border.propertyView({ + label: trans('style.border') + })} + {this.children.radius.propertyView({ + label: trans('style.borderRadius'), + preInputNode: , + placeholder: '3px', + })} + {this.children.margin.propertyView({ + label: trans('style.margin'), + preInputNode: , + placeholder: '3px', + })} + {this.children.padding.propertyView({ + label: trans('style.padding'), + preInputNode: , + placeholder: '3px', + })} + + ); + } +}; + +export const TagsCompOptionsControl = optionsControl(TagsCompOptions, { + initOptions: [ + { label: "Option 1", colorType: "preset", presetColor: "blue" }, + { label: "Option 2", colorType: "preset", presetColor: "green" } + ], + uniqField: "label", +}); let ColoredTagOption = new MultiCompBuilder( { label: StringControl, icon: IconControl, colorType: withDefault(dropdownControl([ - { label: "Preset", value: "preset" }, - { label: "Custom", value: "custom" }, + { label: trans("style.preset"), value: "preset" }, + { label: trans("style.custom"), value: "custom" }, ] as const, "preset"), "preset"), presetColor: withDefault(dropdownControl(TAG_PRESET_COLORS, "blue"), "blue"), color: withDefault(ColorControl, "#1890ff"), @@ -811,16 +880,16 @@ ColoredTagOption = class extends ColoredTagOption implements OptionCompProperty {this.children.label.propertyView({ label: trans("coloredTagOptionControl.tag") })} {this.children.icon.propertyView({ label: trans("coloredTagOptionControl.icon") })} {this.children.colorType.propertyView({ - label: "Color Type", + label: trans("style.colorType"), radioButton: true })} {colorType === "preset" && this.children.presetColor.propertyView({ - label: "Preset Color" + label: trans("style.presetColor") })} {colorType === "custom" && ( <> {this.children.color.propertyView({ label: trans("coloredTagOptionControl.color") })} - {this.children.textColor.propertyView({ label: "Text Color" })} + {this.children.textColor.propertyView({ label: trans("style.textColor") })} )} {this.children.border.propertyView({ diff --git a/client/packages/lowcoder/src/comps/index.tsx b/client/packages/lowcoder/src/comps/index.tsx index 00d54a9b2a..609ddf5b0a 100644 --- a/client/packages/lowcoder/src/comps/index.tsx +++ b/client/packages/lowcoder/src/comps/index.tsx @@ -94,7 +94,7 @@ import { TourCompIcon, StepCompIcon, ShapesCompIcon, - + TagsCompIcon, CandlestickChartCompIcon, FunnelChartCompIcon, HeatmapChartCompIcon, @@ -715,7 +715,7 @@ export var uiCompMap: Registry = { enName: "tags", description: "Desc of Tags", categories: ["layout"], - icon: FloatingButtonCompIcon, + icon: TagsCompIcon, keywords: trans("uiComp.floatButtonCompKeywords"), comp: MultiTagsComp, layoutInfo: { diff --git a/client/packages/lowcoder/src/i18n/locales/en.ts b/client/packages/lowcoder/src/i18n/locales/en.ts index 95fd8671a2..1ff980d532 100644 --- a/client/packages/lowcoder/src/i18n/locales/en.ts +++ b/client/packages/lowcoder/src/i18n/locales/en.ts @@ -572,6 +572,10 @@ export const en = { "headerText": "Header Text Color", "labelColor": "Label Color", "label": "Label Color", + "colorType": "Color Type", + "presetColor": "Preset Color", + "preset": "Preset", + "custom": "Custom", "lineHeight":"Line Height", "subTitleColor": "SubTitle Color", "titleText": "Title Color", @@ -601,6 +605,14 @@ export const en = { "chartTextColor": "Text Color", "detailSize": "Detail Size", "hideColumn": "Hide Column", + "height": "Height", + "gap": "Gap", + "flexWrap": "Flex Wrap", + "justifyContent": "Justify Content", + "alignItems": "Align Items", + "borderless": "Borderless", + "individualStyling": "Individual Styling", + "individualStylingTooltip": "When enabled, each tag can have its own colors, borders, and spacing. When disabled, all tags use the general style settings.", "radiusTip": "Specifies the radius of the element's corners. Example: 5px, 50%, or 1em.", "gapTip": "Specifies the gap between rows and columns in a grid or flex container. Example: 10px, 1rem, or 5%.", From 3ede19e1d84bbcb25089b9ecb529333476790d2c Mon Sep 17 00:00:00 2001 From: Kamal Qureshi Date: Thu, 17 Jul 2025 18:05:28 +0500 Subject: [PATCH 3/3] Tags icon --- client/packages/lowcoder/src/pages/editor/editorConstants.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/client/packages/lowcoder/src/pages/editor/editorConstants.tsx b/client/packages/lowcoder/src/pages/editor/editorConstants.tsx index 9087b1e7d2..beea9cae7a 100644 --- a/client/packages/lowcoder/src/pages/editor/editorConstants.tsx +++ b/client/packages/lowcoder/src/pages/editor/editorConstants.tsx @@ -104,6 +104,7 @@ import { TurnstileCaptchaCompIconSmall, PivotTableCompIconSmall, GraphChartCompIconSmall, + TagsCompIconSmall, } from "lowcoder-design"; // Memoize icon components to prevent unnecessary re-renders @@ -237,7 +238,7 @@ export const CompStateIcon: { step: , table: , text: , - multiTags: , + multiTags: , timeline: , toggleButton: , tour: ,