Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
123 changes: 108 additions & 15 deletions client/packages/lowcoder/src/comps/comps/progressCircleComp.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,30 +3,35 @@ import { styleControl } from "comps/controls/styleControl";
import { AnimationStyle, AnimationStyleType, CircleProgressStyle, CircleProgressType, heightCalculator, widthCalculator } from "comps/controls/styleControlConstants";
import styled, { css } from "styled-components";
import { Section, sectionNames } from "lowcoder-design";
import { numberExposingStateControl } from "../controls/codeStateControl";
import { numberExposingStateControl, stringExposingStateControl } from "../controls/codeStateControl";
import { UICompBuilder } from "../generators";
import { NameConfig, NameConfigHidden, withExposingConfigs } from "../generators/withExposing";
import { hiddenPropertyView } from "comps/utils/propertyUtils";
import { trans } from "i18n";

import { BoolControl } from "../controls/boolControl";
import { dropdownControl } from "../controls/dropdownControl";
import { NumberControl } from "../controls/codeControl";
import { useContext } from "react";
import { EditorContext } from "comps/editorState";

// TODO: after Update of ANTd, introduce Size attribute to ProgressCircle
import {
ProgressTypeOptions,
StrokeLinecapOptions,
GapPositionOptions
} from "./progressCircleConstants";

const getStyle = (style: CircleProgressType) => {
return css`
width: ${widthCalculator(style.margin)};
height: ${heightCalculator(style.margin)};
margin: ${style.margin};
padding: ${style.padding};
border-radius:${style.radius};
border-radius: ${style.radius};
.ant-progress-text {
color: ${style.text} !important;
font-family:${style.fontFamily};
font-style:${style.fontStyle};
font-size:${style.textSize} !important;
font-weight:${style.textWeight};
font-family: ${style.fontFamily};
font-style: ${style.fontStyle};
font-size: ${style.textSize} !important;
font-weight: ${style.textWeight};
}
.ant-progress-circle-trail {
stroke: ${style.track};
Expand Down Expand Up @@ -68,30 +73,117 @@ export const StyledProgressCircle = styled(Progress)<{
let ProgressCircleTmpComp = (function () {
const childrenMap = {
value: numberExposingStateControl("value", 60),
// borderRadius property hidden as it's not valid for progress circle
progressType: dropdownControl(ProgressTypeOptions, "circle"),
showInfo: BoolControl.DEFAULT_TRUE,
strokeWidth: NumberControl,
strokeLinecap: dropdownControl(StrokeLinecapOptions, "round"),
gapDegree: NumberControl,
gapPosition: dropdownControl(GapPositionOptions, "bottom"),
customFormat: stringExposingStateControl("customFormat", ""),
// Steps configuration for segmented progress
stepsEnabled: BoolControl,
stepsCount: NumberControl,
stepsGap: NumberControl,
// Style controls
style: styleControl(CircleProgressStyle, 'style'),
animationStyle: styleControl(AnimationStyle, 'animationStyle'),
};

return new UICompBuilder(childrenMap, (props) => {
const percent = Math.round(props.value.value);
const customFormatValue = props.customFormat.value?.trim();

// Simple format function - just returns the custom text if provided
const formatFunction = customFormatValue ? () => customFormatValue : undefined;

// Build steps configuration if enabled
const stepsConfig = props.stepsEnabled && props.stepsCount > 0
? { count: props.stepsCount, gap: props.stepsGap || 2 }
: undefined;

return (
<StyledProgressCircle
$style={props.style}
$animationStyle={props.animationStyle}
percent={Math.round(props.value.value)}
type="circle"
percent={percent}
type={props.progressType}
showInfo={props.showInfo}
strokeWidth={props.strokeWidth || 6}
strokeLinecap={props.strokeLinecap}
gapDegree={props.progressType === "dashboard" ? (props.gapDegree || 75) : undefined}
gapPosition={props.progressType === "dashboard" ? props.gapPosition : undefined}
format={formatFunction}
steps={stepsConfig}
/>
);
})
.setPropertyViewFn((children) => {
const progressType = children.progressType.getView();
const stepsEnabled = children.stepsEnabled.getView();

return (
<>
<Section name={sectionNames.basic}>
{children.value.propertyView({
label: trans("progress.value"),
tooltip: trans("progress.valueTooltip"),
})}
{children.progressType.propertyView({
label: trans("progressCircle.progressType"),
tooltip: trans("progressCircle.progressTypeTooltip"),
})}
</Section>

<Section name={trans("progressCircle.appearance")}>
{children.showInfo.propertyView({
label: trans("progress.showInfo"),
})}
{children.customFormat.propertyView({
label: trans("progressCircle.customFormat"),
tooltip: trans("progressCircle.customFormatTooltip"),
})}
{children.strokeWidth.propertyView({
label: trans("progressCircle.strokeWidth"),
tooltip: trans("progressCircle.strokeWidthTooltip"),
placeholder: "6",
})}
{children.strokeLinecap.propertyView({
label: trans("progressCircle.strokeLinecap"),
tooltip: trans("progressCircle.strokeLinecapTooltip"),
})}
</Section>

<Section name={trans("progressCircle.segments")}>
{children.stepsEnabled.propertyView({
label: trans("progressCircle.stepsEnabled"),
tooltip: trans("progressCircle.stepsEnabledTooltip"),
})}
{stepsEnabled && children.stepsCount.propertyView({
label: trans("progressCircle.stepsCount"),
tooltip: trans("progressCircle.stepsCountTooltip"),
placeholder: "5",
})}
{stepsEnabled && children.stepsGap.propertyView({
label: trans("progressCircle.stepsGap"),
tooltip: trans("progressCircle.stepsGapTooltip"),
placeholder: "2",
})}
</Section>

{progressType === "dashboard" && (
<Section name={trans("progressCircle.dashboardSettings")}>
{children.gapDegree.propertyView({
label: trans("progressCircle.gapDegree"),
tooltip: trans("progressCircle.gapDegreeTooltip"),
placeholder: "75",
})}
{children.gapPosition.propertyView({
label: trans("progressCircle.gapPosition"),
tooltip: trans("progressCircle.gapPositionTooltip"),
})}
</Section>
)}

{["logic", "both"].includes(useContext(EditorContext).editorModeStatus) && (
<Section name={sectionNames.interaction}>
{hiddenPropertyView(children)}
Expand All @@ -101,12 +193,12 @@ let ProgressCircleTmpComp = (function () {
{["layout", "both"].includes(useContext(EditorContext).editorModeStatus) && (
<>
<Section name={sectionNames.style}>
{children.style.getPropertyView()}
{children.style.getPropertyView()}
</Section>
<Section name={sectionNames.animationStyle} hasTooltip={true}>
{children.animationStyle.getPropertyView()}
{children.animationStyle.getPropertyView()}
</Section>
</>
</>
)}
</>
);
Expand All @@ -122,5 +214,6 @@ ProgressCircleTmpComp = class extends ProgressCircleTmpComp {

export const ProgressCircleComp = withExposingConfigs(ProgressCircleTmpComp, [
new NameConfig("value", trans("progress.valueDesc")),
new NameConfig("customFormat", trans("progressCircle.customFormatDesc")),
NameConfigHidden,
]);
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { trans } from "i18n";

// Progress type options (circle or dashboard)
export const ProgressTypeOptions = [
{ label: trans("progressCircle.circle"), value: "circle" },
{ label: trans("progressCircle.dashboard"), value: "dashboard" },
] as const;

// Stroke linecap options (line ending style)
export const StrokeLinecapOptions = [
{ label: trans("progressCircle.round"), value: "round" },
{ label: trans("progressCircle.butt"), value: "butt" },
{ label: trans("progressCircle.square"), value: "square" },
] as const;

// Gap position options (for dashboard type)
export const GapPositionOptions = [
{ label: trans("progressCircle.top"), value: "top" },
{ label: trans("progressCircle.bottom"), value: "bottom" },
{ label: trans("progressCircle.left"), value: "left" },
{ label: trans("progressCircle.right"), value: "right" },
] as const;
33 changes: 33 additions & 0 deletions client/packages/lowcoder/src/i18n/locales/en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2257,6 +2257,39 @@ export const en = {
"valueDesc": "Current Progress Value, Ranging from 0 to 100",
"showInfoDesc": "Whether to Display the Current Progress Value"
},
"progressCircle": {
"circle": "Circle",
"dashboard": "Dashboard",
"progressType": "Type",
"progressTypeTooltip": "Choose between a full circle or dashboard (semi-circle) style",
"appearance": "Appearance",
"customFormat": "Custom Text",
"customFormatTooltip": "Custom text to display instead of the percentage",
"customFormatDesc": "Custom text displayed in the progress circle",
"strokeWidth": "Stroke Width",
"strokeWidthTooltip": "The width of the progress stroke line (default: 6)",
"strokeLinecap": "Line Cap Style",
"strokeLinecapTooltip": "The shape of the progress line endings",
"round": "Round",
"butt": "Flat",
"square": "Square",
"dashboardSettings": "Dashboard Settings",
"gapDegree": "Gap Degree",
"gapDegreeTooltip": "The gap degree of the dashboard, 0-295 (default: 75)",
"gapPosition": "Gap Position",
"gapPositionTooltip": "The position of the gap in the dashboard",
"top": "Top",
"bottom": "Bottom",
"left": "Left",
"right": "Right",
"segments": "Segments",
"stepsEnabled": "Enable Steps",
"stepsEnabledTooltip": "Display progress as segmented steps instead of continuous",
"stepsCount": "Step Count",
"stepsCountTooltip": "The total number of steps/segments to display",
"stepsGap": "Step Gap",
"stepsGapTooltip": "The gap between each step in pixels (default: 2)"
},
"fileViewer": {
"invalidURL": "Please Enter a Valid URL or Base64 String",
"src": "File URI",
Expand Down
Loading