Content-Length: 55183 | pFad | http://github.com/lowcoder-org/lowcoder/pull/1815.diff

thub.com diff --git a/client/packages/lowcoder/src/comps/comps/buttonComp/buttonComp.tsx b/client/packages/lowcoder/src/comps/comps/buttonComp/buttonComp.tsx index 70a8de5d8..a6d6f8889 100644 --- a/client/packages/lowcoder/src/comps/comps/buttonComp/buttonComp.tsx +++ b/client/packages/lowcoder/src/comps/comps/buttonComp/buttonComp.tsx @@ -21,6 +21,7 @@ import { ButtonCompWrapper, buttonRefMethods, ButtonStyleControl, + DisabledButtonStyleControl, } from "./buttonCompConstants"; import { RefControl } from "comps/controls/refControl"; import { Tooltip } from "antd"; @@ -133,6 +134,7 @@ const childrenMap = { prefixIcon: IconControl, suffixIcon: IconControl, style: ButtonStyleControl, + disabledStyle: DisabledButtonStyleControl, animationStyle: styleControl(AnimationStyle, 'animationStyle'), viewRef: RefControl, tooltip: StringControl @@ -173,6 +175,7 @@ const ButtonPropertyView = React.memo((props: { {props.children.suffixIcon.propertyView({ label: trans("button.suffixIcon") })}
{props.children.style.getPropertyView()}
+
{props.children.disabledStyle.getPropertyView()}
)} @@ -212,6 +215,7 @@ const ButtonView = React.memo((props: ToViewReturn) => { ` - ${(props) => props.$buttonStyle && getButtonStyle(props.$buttonStyle)} +export const Button100 = styled(Button)<{ + $buttonStyle?: ButtonStyleType; + $disabledStyle?: DisabledButtonStyleType; +}>` + ${(props) => props.$buttonStyle && getButtonStyle(props.$buttonStyle, props.$disabledStyle)} width: 100%; height: auto; display: inline-flex; @@ -73,13 +84,15 @@ export const ButtonCompWrapper = styled.div<{ $disabled: boolean }>` // The button component is disabled but can respond to drag & select events ${(props) => - props.$disabled && - ` - cursor: not-allowed; - button:disabled { - pointer-events: none; - } - `}; + props.$disabled + ? ` + cursor: not-allowed; + button:disabled { + pointer-events: none; + } + ` + : "" + } `; /** @@ -103,6 +116,10 @@ function fixOldData(oldData: any) { const ButtonTmpStyleControl = styleControl(ButtonStyle, 'style'); export const ButtonStyleControl = migrateOldData(ButtonTmpStyleControl, fixOldData); +// Create disabled style control +const DisabledButtonTmpStyleControl = styleControl(DisabledButtonStyle, 'disabledStyle'); +export const DisabledButtonStyleControl = migrateOldData(DisabledButtonTmpStyleControl, fixOldData); + export const buttonRefMethods = refMethods([ focusWithOptions, blurMethod, diff --git a/client/packages/lowcoder/src/comps/comps/buttonComp/scannerComp.tsx b/client/packages/lowcoder/src/comps/comps/buttonComp/scannerComp.tsx index 811ed91be..a4ecd85a6 100644 --- a/client/packages/lowcoder/src/comps/comps/buttonComp/scannerComp.tsx +++ b/client/packages/lowcoder/src/comps/comps/buttonComp/scannerComp.tsx @@ -4,11 +4,10 @@ import { Button100, ButtonCompWrapper, buttonRefMethods, + ButtonStyleControl, } from "comps/comps/buttonComp/buttonCompConstants"; import { BoolCodeControl, StringControl } from "comps/controls/codeControl"; import { ScannerEventHandlerControl } from "comps/controls/eventHandlerControl"; -import { styleControl } from "comps/controls/styleControl"; -import { DropdownStyle } from "comps/controls/styleControlConstants"; import { withDefault } from "comps/generators"; import { UICompBuilder } from "comps/generators/uiCompBuilder"; import { CustomModal, Section, sectionNames } from "lowcoder-design"; @@ -127,7 +126,7 @@ const ScannerTmpComp = (function () { maskClosable: withDefault(BoolControl, true), onEvent: ScannerEventHandlerControl, disabled: BoolCodeControl, - style: styleControl(DropdownStyle, "style"), + style: ButtonStyleControl, viewRef: RefControl, }; return new UICompBuilder(childrenMap, (props) => { diff --git a/client/packages/lowcoder/src/comps/comps/buttonComp/toggleButtonComp.tsx b/client/packages/lowcoder/src/comps/comps/buttonComp/toggleButtonComp.tsx index 0184fb87a..654ec6659 100644 --- a/client/packages/lowcoder/src/comps/comps/buttonComp/toggleButtonComp.tsx +++ b/client/packages/lowcoder/src/comps/comps/buttonComp/toggleButtonComp.tsx @@ -12,7 +12,7 @@ import { trans } from "i18n"; import styled from "styled-components"; import { ChangeEventHandlerControl } from "../../controls/eventHandlerControl"; import { CommonNameConfig, NameConfig, withExposingConfigs } from "../../generators/withExposing"; -import { Button100, ButtonCompWrapper, buttonRefMethods } from "./buttonCompConstants"; +import { Button100, ButtonCompWrapper, buttonRefMethods, DisabledButtonStyleControl } from "./buttonCompConstants"; import { IconControl } from "comps/controls/iconControl"; import { AlignWithStretchControl, LeftRightControl } from "comps/controls/dropdownControl"; import { booleanExposingStateControl } from "comps/controls/codeStateControl"; @@ -63,6 +63,7 @@ const ToggleTmpComp = (function () { iconPosition: LeftRightControl, alignment: AlignWithStretchControl, style: styleControl(ToggleButtonStyle , 'style'), + disabledStyle: DisabledButtonStyleControl, animationStyle: styleControl(AnimationStyle , 'animationStyle'), showBorder: withDefault(BoolControl, true), viewRef: RefControl, @@ -84,6 +85,7 @@ const ToggleTmpComp = (function () { { @@ -153,6 +155,7 @@ const ToggleTmpComp = (function () { )} +
{children.disabledStyle.getPropertyView()}
)) .setExposeMethodConfigs(buttonRefMethods) diff --git a/client/packages/lowcoder/src/comps/comps/dateComp/dateComp.tsx b/client/packages/lowcoder/src/comps/comps/dateComp/dateComp.tsx index 8068829d8..ea6f37f5a 100644 --- a/client/packages/lowcoder/src/comps/comps/dateComp/dateComp.tsx +++ b/client/packages/lowcoder/src/comps/comps/dateComp/dateComp.tsx @@ -21,7 +21,7 @@ import { UICompBuilder, withDefault } from "../../generators"; import { CommonNameConfig, depsConfig, withExposingConfigs } from "../../generators/withExposing"; import { formDataChildren, FormDataPropertyView } from "../formComp/formDataConstants"; import { styleControl } from "comps/controls/styleControl"; -import { AnimationStyle, ChildrenMultiSelectStyle, ChildrenMultiSelectStyleType, DateTimeStyle, DateTimeStyleType, InputFieldStyle, LabelStyle } from "comps/controls/styleControlConstants"; +import { AnimationStyle, ChildrenMultiSelectStyle, ChildrenMultiSelectStyleType, DateTimeStyle, DateTimeStyleType, InputFieldStyle, LabelStyle, DisabledInputStyle, DisabledInputStyleType } from "comps/controls/styleControlConstants"; import { withMethodExposing } from "../../generators/withMethodExposing"; import { disabledPropertyView, @@ -81,6 +81,7 @@ const commonChildren = { format: StringControl, inputFormat: withDefault(StringControl, DATE_FORMAT), disabled: BoolCodeControl, + disabledStyle: styleControl(DisabledInputStyle, 'disabledStyle'), onEvent: eventHandlerControl(EventOptions), showTime: BoolControl, use12Hours: BoolControl, @@ -179,11 +180,13 @@ export type DateCompViewProps = Pick< | "viewRef" | "timeZone" | "pickerMode" + | "disabledStyle" > & { onFocus: () => void; onBlur: () => void; $style: DateTimeStyleType; $childrenInputFieldStyle: ChildrenMultiSelectStyleType; + $disabledStyle?: DisabledInputStyleType; disabledTime: () => ReturnType; suffixIcon: ReactNode; placeholder?: string | [string, string]; @@ -264,6 +267,7 @@ const DatePickerTmpCmp = new UICompBuilder(childrenMap, (props) => { disabledTime={() => disabledTime(props.minTime, props.maxTime)} $style={props.inputFieldStyle} $childrenInputFieldStyle={props.childrenInputFieldStyle} + $disabledStyle={props.disabledStyle} disabled={props.disabled} {...datePickerProps(props)} hourStep={props.hourStep} @@ -285,6 +289,7 @@ const DatePickerTmpCmp = new UICompBuilder(childrenMap, (props) => { onBlur={() => props.onEvent("blur")} suffixIcon={hasIcon(props.suffixIcon) && props.suffixIcon} tabIndex={typeof props.tabIndex === 'number' ? props.tabIndex : undefined} + disabledStyle={props.disabledStyle} /> ), showValidationWhenEmpty: props.showValidationWhenEmpty, @@ -366,6 +371,9 @@ const DatePickerTmpCmp = new UICompBuilder(childrenMap, (props) => {
{children.animationStyle.getPropertyView()}
+
+ {children.disabledStyle.getPropertyView()} +
)} @@ -457,6 +465,7 @@ let DateRangeTmpCmp = (function () { viewRef={props.viewRef} $style={props.inputFieldStyle} $childrenInputFieldStyle={props.childrenInputFieldStyle} + $disabledStyle={props.disabledStyle} disabled={props.disabled} {...datePickerProps(props)} start={tempStartValue?.isValid() ? tempStartValue : null} @@ -482,6 +491,7 @@ let DateRangeTmpCmp = (function () { onBlur={() => props.onEvent("blur")} suffixIcon={hasIcon(props.suffixIcon) && props.suffixIcon} tabIndex={typeof props.tabIndex === 'number' ? props.tabIndex : undefined} + disabledStyle={props.disabledStyle} /> ); @@ -579,6 +589,9 @@ let DateRangeTmpCmp = (function () {
{children.childrenInputFieldStyle.getPropertyView()}
+
+ {children.disabledStyle.getPropertyView()} +
)} diff --git a/client/packages/lowcoder/src/comps/comps/dateComp/dateCompUtil.ts b/client/packages/lowcoder/src/comps/comps/dateComp/dateCompUtil.ts index 63a030cda..16bc634ed 100644 --- a/client/packages/lowcoder/src/comps/comps/dateComp/dateCompUtil.ts +++ b/client/packages/lowcoder/src/comps/comps/dateComp/dateCompUtil.ts @@ -85,8 +85,23 @@ export const getStyle = (style: DateTimeStyleType) => { color: ${style.text}; &::-webkit-input-placeholder { - color: ${style.text}; - opacity: 0.25; + color: ${style.placeholder}; + opacity: 1; + } + + &::-moz-placeholder { + color: ${style.placeholder}; + opacity: 1; + } + + &:-ms-input-placeholder { + color: ${style.placeholder}; + opacity: 1; + } + + &::placeholder { + color: ${style.placeholder}; + opacity: 1; } } @@ -132,6 +147,26 @@ export const getMobileStyle = (style: DateTimeStyleType) => background-color: ${style.background}; border-radius: ${style.radius}; border-color: ${style.border}; + + &::-webkit-input-placeholder { + color: ${style.placeholder}; + opacity: 1; + } + + &::-moz-placeholder { + color: ${style.placeholder}; + opacity: 1; + } + + &:-ms-input-placeholder { + color: ${style.placeholder}; + opacity: 1; + } + + &::placeholder { + color: ${style.placeholder}; + opacity: 1; + } `; export const dateRefMethods = refMethods([focusMethod, blurMethod]); diff --git a/client/packages/lowcoder/src/comps/comps/dateComp/dateRangeUIView.tsx b/client/packages/lowcoder/src/comps/comps/dateComp/dateRangeUIView.tsx index c56ddecb6..65677b63b 100644 --- a/client/packages/lowcoder/src/comps/comps/dateComp/dateRangeUIView.tsx +++ b/client/packages/lowcoder/src/comps/comps/dateComp/dateRangeUIView.tsx @@ -5,7 +5,7 @@ import { useUIView } from "../../utils/useUIView"; import { checkIsMobile } from "util/commonUtils"; import React, { useContext } from "react"; import styled from "styled-components"; -import type { ChildrenMultiSelectStyleType, DateTimeStyleType } from "../../controls/styleControlConstants"; +import type { ChildrenMultiSelectStyleType, DateTimeStyleType, DisabledInputStyleType } from "../../controls/styleControlConstants"; import { EditorContext } from "../../editorState"; import { default as DatePicker } from "antd/es/date-picker"; import { hasIcon } from "comps/utils"; @@ -16,11 +16,28 @@ import { timeZoneOptions } from "./timeZone"; const { RangePicker } = DatePicker; -const RangePickerStyled = styled(RangePicker)<{$style: DateTimeStyleType}>` +const RangePickerStyled = styled(RangePicker)<{$style: DateTimeStyleType; $disabledStyle?: DisabledInputStyleType}>` width: 100%; box-shadow: ${(props) => `${props.$style.boxShadow} ${props.$style.boxShadowColor}`}; ${(props) => props.$style && getStyle(props.$style)} + + &.ant-picker-disabled { + cursor: not-allowed; + color: ${(props) => props.$disabledStyle?.disabledText}; + background: ${(props) => props.$disabledStyle?.disabledBackground}; + border-color: ${(props) => props.$disabledStyle?.disabledBorder}; + + .ant-picker-input > input { + color: ${(props) => props.$disabledStyle?.disabledText}; + background: ${(props) => props.$disabledStyle?.disabledBackground}; + } + .ant-picker-suffix, + .ant-picker-clear, + .ant-picker-separator { + color: ${(props) => props.$disabledStyle?.disabledText}; + } + } `; const StyledAntdSelect = styled(AntdSelect)` @@ -46,6 +63,7 @@ export interface DateRangeUIViewProps extends DateCompViewProps { onPanelChange: (value: any, mode: [string, string]) => void; onClickDateRangeTimeZone:(value:any)=>void; tabIndex?: number; + $disabledStyle?: DisabledInputStyleType; } export const DateRangeUIView = (props: DateRangeUIViewProps) => { @@ -98,6 +116,7 @@ export const DateRangeUIView = (props: DateRangeUIViewProps) => { ) )} + $disabledStyle={props.$disabledStyle} /> ); }; diff --git a/client/packages/lowcoder/src/comps/comps/dateComp/dateUIView.tsx b/client/packages/lowcoder/src/comps/comps/dateComp/dateUIView.tsx index a98a1eaa5..c66ac2a02 100644 --- a/client/packages/lowcoder/src/comps/comps/dateComp/dateUIView.tsx +++ b/client/packages/lowcoder/src/comps/comps/dateComp/dateUIView.tsx @@ -5,7 +5,7 @@ import { useUIView } from "../../utils/useUIView"; import { checkIsMobile } from "util/commonUtils"; import React, { useContext } from "react"; import styled from "styled-components"; -import type { ChildrenMultiSelectStyleType, DateTimeStyleType } from "../../controls/styleControlConstants"; +import type { ChildrenMultiSelectStyleType, DateTimeStyleType, DisabledInputStyleType } from "../../controls/styleControlConstants"; import { EditorContext } from "../../editorState"; import { default as DatePicker } from "antd/es/date-picker"; import type { DatePickerProps } from "antd/es/date-picker"; @@ -15,10 +15,28 @@ import { timeZoneOptions } from "./timeZone"; import { default as AntdSelect } from "antd/es/select"; import { omit } from "lodash"; -const DatePickerStyled = styled(DatePicker)<{ $style: DateTimeStyleType }>` +const DatePickerStyled = styled(DatePicker)<{ $style: DateTimeStyleType; $disabledStyle?: DisabledInputStyleType; }>` width: 100%; box-shadow: ${props=>`${props.$style.boxShadow} ${props.$style.boxShadowColor}`}; ${(props) => props.$style && getStyle(props.$style)} + + /* Disabled state styling */ + &.ant-picker-disabled { + cursor: not-allowed; + color: ${(props) => props.$disabledStyle?.disabledText}; + background: ${(props) => props.$disabledStyle?.disabledBackground}; + border-color: ${(props) => props.$disabledStyle?.disabledBorder}; + + .ant-picker-input > input { + color: ${(props) => props.$disabledStyle?.disabledText}; + background: ${(props) => props.$disabledStyle?.disabledBackground}; + } + .ant-picker-suffix, + .ant-picker-clear, + .ant-picker-separator { + color: ${(props) => props.$disabledStyle?.disabledText}; + } + } `; const StyledDiv = styled.div` @@ -40,6 +58,7 @@ export interface DataUIViewProps extends DateCompViewProps { onPanelChange: () => void; onClickDateTimeZone:(value:any)=>void; tabIndex?: number; + $disabledStyle?: DisabledInputStyleType; } const DateMobileUIView = React.lazy(() => @@ -54,6 +73,7 @@ export const DateUIView = (props: DataUIViewProps) => { , {children.style.getPropertyView()} +
+ {children.disabledStyle.getPropertyView()} +
)} diff --git a/client/packages/lowcoder/src/comps/comps/meetingComp/videobuttonCompConstants.tsx b/client/packages/lowcoder/src/comps/comps/meetingComp/videobuttonCompConstants.tsx index 9a7a0d43b..2ffa2e6cf 100644 --- a/client/packages/lowcoder/src/comps/comps/meetingComp/videobuttonCompConstants.tsx +++ b/client/packages/lowcoder/src/comps/comps/meetingComp/videobuttonCompConstants.tsx @@ -1,5 +1,5 @@ import { styleControl } from "@lowcoder-ee/comps/controls/styleControl"; -import { ButtonStyle } from "@lowcoder-ee/comps/controls/styleControlConstants"; +import { ButtonStyle, DisabledButtonStyle } from "@lowcoder-ee/comps/controls/styleControlConstants"; import { migrateOldData } from "@lowcoder-ee/comps/generators/simpleGenerators"; import { refMethods } from "@lowcoder-ee/comps/generators/withMethodExposing"; import { blurMethod, clickMethod, focusWithOptions } from "@lowcoder-ee/comps/utils/methodUtils"; @@ -8,7 +8,7 @@ import { genActiveColor, genHoverColor } from "components/colorSelect/colorUtils import styled, { css } from "styled-components"; // import { genActiveColor, genHoverColor } from "lowcoder-design"; -export function getButtonStyle(buttonStyle: any) { +export function getButtonStyle(buttonStyle: any, disabledStyle: any) { const hoverColor = buttonStyle.background && genHoverColor(buttonStyle.background); const activeColor = buttonStyle.background && genActiveColor(buttonStyle.background); return css` @@ -42,13 +42,20 @@ export function getButtonStyle(buttonStyle: any) { ? activeColor : buttonStyle.border}; } + + } + &:disabled, + &.ant-btn-disabled { + color: ${disabledStyle.disabledText}; + background: ${disabledStyle.disabledBackground}; + cursor: not-allowed; } } `; } -export const Button100 = styled(Button)<{ $buttonStyle?: any }>` - ${(props) => props.$buttonStyle && getButtonStyle(props.$buttonStyle)} +export const Button100 = styled(Button)<{ $buttonStyle?: any; $disabledStyle?: any }>` + ${(props) => props.$buttonStyle && getButtonStyle(props.$buttonStyle, props.$disabledStyle)} width: 100%; height: auto; display: inline-flex; @@ -98,6 +105,12 @@ export const ButtonStyleControl = migrateOldData( fixOldData ); +export const DisabledButtonTmpStyleControl = styleControl(DisabledButtonStyle); +export const DisabledButtonStyleControl = migrateOldData( + DisabledButtonTmpStyleControl, + fixOldData +); + export const buttonRefMethods = refMethods([ focusWithOptions, blurMethod, diff --git a/client/packages/lowcoder/src/comps/comps/numberInputComp/numberInputComp.tsx b/client/packages/lowcoder/src/comps/comps/numberInputComp/numberInputComp.tsx index 7dbacf900..15db21305 100644 --- a/client/packages/lowcoder/src/comps/comps/numberInputComp/numberInputComp.tsx +++ b/client/packages/lowcoder/src/comps/comps/numberInputComp/numberInputComp.tsx @@ -30,7 +30,7 @@ import { formDataChildren, FormDataPropertyView } from "../formComp/formDataCons import { withMethodExposing, refMethods } from "../../generators/withMethodExposing"; import { RefControl } from "../../controls/refControl"; import { styleControl } from "comps/controls/styleControl"; -import { AnimationStyle, InputFieldStyle, InputLikeStyle, InputLikeStyleType, LabelStyle, heightCalculator, widthCalculator } from "comps/controls/styleControlConstants"; +import { AnimationStyle, InputFieldStyle, InputLikeStyle, InputLikeStyleType, LabelStyle, DisabledInputStyle, DisabledInputStyleType, heightCalculator, widthCalculator } from "comps/controls/styleControlConstants"; import { disabledPropertyView, hiddenPropertyView, @@ -59,7 +59,6 @@ const getStyle = (style: InputLikeStyleType) => { return css` border-radius: ${style.radius}; border-width:${style.borderWidth} !important; - // line-height: ${style.lineHeight} !important; // still use antd style when disabled &:not(.ant-input-number-disabled) { color: ${style.text}; @@ -75,11 +74,7 @@ const getStyle = (style: InputLikeStyleType) => { &:hover { border-color: ${style.accent}; } - - &::-webkit-input-placeholder { - color: ${style.text}; - opacity: 0.4; - } + .ant-input-number { margin: 0; @@ -93,6 +88,26 @@ const getStyle = (style: InputLikeStyleType) => { font-weight:${style.textWeight} !important; font-size:${style.textSize} !important; font-style:${style.fontStyle} !important; + + &::-webkit-input-placeholder { + color: ${style.placeholder}; + opacity: 1; + } + + &::-moz-placeholder { + color: ${style.placeholder}; + opacity: 1; + } + + &:-ms-input-placeholder { + color: ${style.placeholder}; + opacity: 1; + } + + &::placeholder { + color: ${style.placeholder}; + opacity: 1; + } } .ant-input-number-handler-wrap { @@ -122,11 +137,27 @@ const getStyle = (style: InputLikeStyleType) => { const InputNumber = styled(AntdInputNumber)<{ $style: InputLikeStyleType; + $disabledStyle?: DisabledInputStyleType; }>` box-shadow: ${(props) => `${props.$style?.boxShadow} ${props.$style?.boxShadowColor}`}; width: 100%; ${(props) => props.$style && getStyle(props.$style)} + + /* Disabled state styling */ + &:disabled, + &.ant-input-number-disabled { + color: ${(props) => props.$disabledStyle?.disabledText}; + background: ${(props) => props.$disabledStyle?.disabledBackground}; + border-color: ${(props) => props.$disabledStyle?.disabledBorder}; + cursor: not-allowed; + + .ant-input-number-input { + color: ${(props) => props.$disabledStyle?.disabledText}; + background: ${(props) => props.$disabledStyle?.disabledBackground}; + } + + } `; const FormatterOptions = [ @@ -266,6 +297,7 @@ const childrenMap = { animationStyle: styleControl(AnimationStyle , 'animationStyle'), prefixIcon: IconControl, inputFieldStyle: styleControl(InputLikeStyle , 'inputFieldStyle'), + disabledStyle: styleControl(DisabledInputStyle, 'disabledStyle'), // validation required: BoolControl, showValidationWhenEmpty: BoolControl, @@ -382,6 +414,7 @@ const CustomInputNumber = (props: RecordConstructorToView) = stringMode={true} precision={props.precision} $style={props.inputFieldStyle} + $disabledStyle={props.disabledStyle} prefix={hasIcon(props.prefixIcon) ? props.prefixIcon : props.prefixText.value} tabIndex={typeof props.tabIndex === 'number' ? props.tabIndex : undefined} onPressEnter={() => { @@ -473,6 +506,9 @@ let NumberInputTmpComp = (function () {
{children.inputFieldStyle.getPropertyView()}
+
+ {children.disabledStyle.getPropertyView()} +
{children.animationStyle.getPropertyView()}
diff --git a/client/packages/lowcoder/src/comps/comps/numberInputComp/rangeSliderComp.tsx b/client/packages/lowcoder/src/comps/comps/numberInputComp/rangeSliderComp.tsx index 74b32347d..48480bacd 100644 --- a/client/packages/lowcoder/src/comps/comps/numberInputComp/rangeSliderComp.tsx +++ b/client/packages/lowcoder/src/comps/comps/numberInputComp/rangeSliderComp.tsx @@ -65,6 +65,7 @@ const RangeSliderBasicComp = (function () { range={true} value={[props.start.value, props.end.value]} $style={props.inputFieldStyle} + $disabledStyle={props.disabledSliderStyle} style={{ margin: 0 }} $vertical={Boolean(props.vertical) || false} tabIndex={typeof props.tabIndex === 'number' ? props.tabIndex : undefined} diff --git a/client/packages/lowcoder/src/comps/comps/numberInputComp/sliderComp.tsx b/client/packages/lowcoder/src/comps/comps/numberInputComp/sliderComp.tsx index e31117cdf..a1156ec69 100644 --- a/client/packages/lowcoder/src/comps/comps/numberInputComp/sliderComp.tsx +++ b/client/packages/lowcoder/src/comps/comps/numberInputComp/sliderComp.tsx @@ -46,6 +46,7 @@ const SliderBasicComp = (function () { {...props} value={props.value.value} $style={props.inputFieldStyle} + $disabledStyle={props.disabledSliderStyle} style={{margin: 0}} $vertical={Boolean(props.vertical) || false} tabIndex={typeof props.tabIndex === 'number' ? props.tabIndex : undefined} diff --git a/client/packages/lowcoder/src/comps/comps/numberInputComp/sliderCompConstants.tsx b/client/packages/lowcoder/src/comps/comps/numberInputComp/sliderCompConstants.tsx index ae4c5abd8..c2a45c121 100644 --- a/client/packages/lowcoder/src/comps/comps/numberInputComp/sliderCompConstants.tsx +++ b/client/packages/lowcoder/src/comps/comps/numberInputComp/sliderCompConstants.tsx @@ -5,7 +5,7 @@ import { ChangeEventHandlerControl } from "../../controls/eventHandlerControl"; import { Section, lightenColor, sectionNames } from "lowcoder-design"; import { RecordConstructorToComp } from "lowcoder-core"; import { styleControl } from "comps/controls/styleControl"; -import { AnimationStyle, InputFieldStyle, LabelStyle, SliderStyle, SliderStyleType, heightCalculator, widthCalculator } from "comps/controls/styleControlConstants"; +import { AnimationStyle, InputFieldStyle, LabelStyle, SliderStyle, SliderStyleType, DisabledSliderStyle, DisabledSliderStyleType, heightCalculator, widthCalculator } from "comps/controls/styleControlConstants"; import styled, { css } from "styled-components"; import { default as Slider } from "antd/es/slider"; import { darkenColor, fadeColor } from "lowcoder-design"; @@ -15,7 +15,7 @@ import { trans } from "i18n"; import { memo, useCallback, useContext } from "react"; import { EditorContext } from "comps/editorState"; -const getStyle = (style: SliderStyleType, vertical: boolean) => { +const getStyle = (style: SliderStyleType, vertical: boolean, disabledStyle?: DisabledSliderStyleType) => { return css` &.ant-slider:not(.ant-slider-disabled) { &, @@ -56,11 +56,30 @@ const getStyle = (style: SliderStyleType, vertical: boolean) => { margin: ${style.margin} auto !important; `} } + + /* Disabled state styling */ + &.ant-slider-disabled { + .ant-slider-rail { + background-color: ${disabledStyle?.disabledTrack || lightenColor(style.track, 0.2)} !important; + } + .ant-slider-track { + background-color: ${disabledStyle?.disabledFill || lightenColor(style.fill, 0.3)} !important; + } + ${vertical && css` + width: auto; + min-height: calc(300px - ${style.margin}); + margin: ${style.margin} auto !important; + `} + } `; }; -export const SliderStyled = styled(Slider)<{ $style: SliderStyleType, $vertical: boolean }>` - ${(props) => props.$style && getStyle(props.$style, props.$vertical)} +export const SliderStyled = styled(Slider)<{ + $style: SliderStyleType, + $vertical: boolean, + $disabledStyle?: DisabledSliderStyleType +}>` + ${(props) => props.$style && getStyle(props.$style, props.$vertical, props.$disabledStyle)} `; export const SliderWrapper = styled.div<{ $vertical: boolean }>` @@ -88,6 +107,7 @@ export const SliderChildren = { prefixIcon: IconControl, suffixIcon: IconControl, inputFieldStyle: styleControl(SliderStyle, 'inputFieldStyle'), + disabledSliderStyle: styleControl(DisabledSliderStyle, 'disabledSliderStyle'), animationStyle: styleControl(AnimationStyle, 'animationStyle') }; @@ -132,6 +152,9 @@ const LayoutSection = memo(({ children }: { children: RecordConstructorToComp {children.inputFieldStyle.getPropertyView()} +
+ {children.disabledSliderStyle.getPropertyView()} +
{children.animationStyle.getPropertyView()}
diff --git a/client/packages/lowcoder/src/comps/comps/selectInputComp/stepControl.tsx b/client/packages/lowcoder/src/comps/comps/selectInputComp/stepControl.tsx index ca24b7492..9fcfaa621 100644 --- a/client/packages/lowcoder/src/comps/comps/selectInputComp/stepControl.tsx +++ b/client/packages/lowcoder/src/comps/comps/selectInputComp/stepControl.tsx @@ -5,7 +5,7 @@ import { stringExposingStateControl, numberExposingStateControl } from "comps/co import { ChangeEventHandlerControl } from "comps/controls/eventHandlerControl"; import { StepOptionControl } from "comps/controls/optionsControl"; import { styleControl } from "comps/controls/styleControl"; -import { StepsStyle, StepsStyleType, heightCalculator, widthCalculator, marginCalculator, AnimationStyle, AnimationStyleType } from "comps/controls/styleControlConstants"; +import { StepsStyle, StepsStyleType, heightCalculator, widthCalculator, marginCalculator, AnimationStyle, AnimationStyleType, DisabledStepStyle, DisabledStepStyleType } from "comps/controls/styleControlConstants"; import styled, { css } from "styled-components"; import { UICompBuilder, withDefault } from "../../generators"; import { CommonNameConfig, NameConfig, withExposingConfigs } from "../../generators/withExposing"; @@ -98,11 +98,12 @@ const StepsChildrenMap = { animationStyle: styleControl(AnimationStyle ,'animationStyle' ), showScrollBars: withDefault(BoolControl, false), minHorizontalWidth: withDefault(RadiusControl, ''), + disabledStyle: styleControl(DisabledStepStyle, 'disabledStyle'), }; let StepControlBasicComp = (function () { return new UICompBuilder(StepsChildrenMap, (props) => { - const StyledWrapper = styled.div<{ style: StepsStyleType, $animationStyle: AnimationStyleType }>` + const StyledWrapper = styled.div<{ style: StepsStyleType, $animationStyle: AnimationStyleType, $disabledStyle: DisabledStepStyleType }>` ${props=>props.$animationStyle} height: 100%; overflow-y: scroll; @@ -124,6 +125,30 @@ let StepControlBasicComp = (function () { border: ${props.style.borderWidth} solid ${props.style.border}; border-radius: ${props.style.radius}; ${getBackgroundStyle(props.style)} + /* Disabled step styles */ + .ant-steps-item-disabled { + .ant-steps-item-icon { + background: ${(props) => props.$disabledStyle?.disabledBackground}; + border-color: ${(props) => props.$disabledStyle?.disabledBorder}; + + /* When using icon as dot */ + .ant-steps-icon-dot { + background: ${(props) => props.$disabledStyle?.disabledBackground}; + } + + /* Default icon or custom icon */ + .ant-steps-icon, + > * { + color: ${(props) => props.$disabledStyle?.disabledText}; + } + } + + .ant-steps-item-title, + .ant-steps-item-subtitle, + .ant-steps-item-description { + color: ${(props) => props.$disabledStyle?.disabledText}; + } + } .ant-steps-item { padding-top: 5px !important; } .ant-steps.ant-steps-label-vertical.ant-steps-small .ant-steps-item-icon { margin-top: 17px !important; } .ant-steps.ant-steps-label-vertical.ant-steps-default .ant-steps-item-icon { margin-top: 12px !important; } @@ -172,7 +197,7 @@ let StepControlBasicComp = (function () { } }} > - + {children.animationStyle.getPropertyView()} +
+ {children.disabledStyle.getPropertyView()} +
)} diff --git a/client/packages/lowcoder/src/comps/comps/textInputComp/inputComp.tsx b/client/packages/lowcoder/src/comps/comps/textInputComp/inputComp.tsx index cfbdfe042..0a3ca6bf6 100644 --- a/client/packages/lowcoder/src/comps/comps/textInputComp/inputComp.tsx +++ b/client/packages/lowcoder/src/comps/comps/textInputComp/inputComp.tsx @@ -1,7 +1,7 @@ import { Input, Section, sectionNames } from "lowcoder-design"; import { BoolControl } from "comps/controls/boolControl"; import { styleControl } from "comps/controls/styleControl"; -import { AnimationStyle, InputFieldStyle, InputLikeStyle, InputLikeStyleType, LabelStyle, LabelStyleType } from "comps/controls/styleControlConstants"; +import { AnimationStyle, InputFieldStyle, InputLikeStyle, InputLikeStyleType, LabelStyle, LabelStyleType, DisabledInputStyle, DisabledInputStyleType } from "comps/controls/styleControlConstants"; import { NameConfig, NameConfigPlaceHolder, @@ -42,10 +42,22 @@ import { EditorContext } from "comps/editorState"; * Input Comp */ -const InputStyle = styled(Input)<{$style: InputLikeStyleType}>` +const InputStyle = styled(Input)<{ + $style: InputLikeStyleType; + $disabledStyle?: DisabledInputStyleType; +}>` box-shadow: ${(props) => `${props.$style?.boxShadow} ${props.$style?.boxShadowColor}`}; ${(props) => props.$style && getStyle(props.$style)} + + /* Disabled state styling */ + &:disabled, + &.ant-input-disabled { + color: ${(props) => props.$disabledStyle?.disabledText}; + background: ${(props) => props.$disabledStyle?.disabledBackground}; + border-color: ${(props) => props.$disabledStyle?.disabledBorder}; + cursor: not-allowed; + } `; const childrenMap = { @@ -59,6 +71,7 @@ const childrenMap = { suffixIcon: IconControl, inputFieldStyle: styleControl(InputLikeStyle, 'inputFieldStyle'), animationStyle: styleControl(AnimationStyle, 'animationStyle'), + disabledStyle: styleControl(DisabledInputStyle, 'disabledStyle'), tabIndex: NumberControl, }; @@ -73,6 +86,7 @@ let InputBasicComp = new UICompBuilder(childrenMap, (props) => { showCount={props.showCount} allowClear={props.allowClear} $style={props.inputFieldStyle} + $disabledStyle={props.disabledStyle} prefix={hasIcon(props.prefixIcon) && props.prefixIcon} suffix={hasIcon(props.suffixIcon) && props.suffixIcon} tabIndex={typeof props.tabIndex === 'number' ? props.tabIndex : undefined} @@ -114,6 +128,7 @@ let InputBasicComp = new UICompBuilder(childrenMap, (props) => {
{children.style.getPropertyView()}
{children.labelStyle.getPropertyView()}
{children.inputFieldStyle.getPropertyView()}
+
{children.disabledStyle.getPropertyView()}
{children.animationStyle.getPropertyView()}
)} diff --git a/client/packages/lowcoder/src/comps/comps/textInputComp/passwordComp.tsx b/client/packages/lowcoder/src/comps/comps/textInputComp/passwordComp.tsx index 434704387..4b9cf5638 100644 --- a/client/packages/lowcoder/src/comps/comps/textInputComp/passwordComp.tsx +++ b/client/packages/lowcoder/src/comps/comps/textInputComp/passwordComp.tsx @@ -26,7 +26,7 @@ import { import { withMethodExposing } from "../../generators/withMethodExposing"; import { styleControl } from "comps/controls/styleControl"; import styled from "styled-components"; -import { AnimationStyle, InputFieldStyle, InputLikeStyle, InputLikeStyleType, LabelStyle } from "comps/controls/styleControlConstants"; +import { AnimationStyle, InputFieldStyle, InputLikeStyle, InputLikeStyleType, LabelStyle, DisabledInputStyle, DisabledInputStyleType } from "comps/controls/styleControlConstants"; import { hiddenPropertyView, minLengthPropertyView, @@ -46,10 +46,19 @@ import { NumberControl } from "comps/controls/codeControl"; const PasswordStyle = styled(InputPassword)<{ $style: InputLikeStyleType; + $disabledStyle?: DisabledInputStyleType; }>` box-shadow: ${(props) => `${props.$style?.boxShadow} ${props.$style?.boxShadowColor}`}; ${(props) => props.$style && getStyle(props.$style)} + + /* Disabled state styling */ + &:disabled, + &.ant-input-disabled { + color: ${(props) => props.$disabledStyle?.disabledText || props.$style.text} !important; + background: ${(props) => props.$disabledStyle?.disabledBackground || props.$style.background} !important; + cursor: not-allowed; + } `; let PasswordTmpComp = (function () { @@ -64,6 +73,7 @@ let PasswordTmpComp = (function () { labelStyle: styleControl(LabelStyle,'labelStyle'), inputFieldStyle: styleControl(InputLikeStyle , 'inputFieldStyle'), animationStyle: styleControl(AnimationStyle , 'animationStyle'), + disabledInputStyle: styleControl(DisabledInputStyle, 'disabledInputStyle'), tabIndex: NumberControl, }; return new UICompBuilder(childrenMap, (props, dispatch) => { @@ -78,6 +88,7 @@ let PasswordTmpComp = (function () { ref={props.viewRef} visibilityToggle={props.visibilityToggle} $style={props.inputFieldStyle} + $disabledStyle={props.disabledInputStyle} tabIndex={typeof props.tabIndex === 'number' ? props.tabIndex : undefined} /> ), @@ -124,6 +135,7 @@ let PasswordTmpComp = (function () {
{children.style.getPropertyView()}
{children.labelStyle.getPropertyView()}
{children.inputFieldStyle.getPropertyView()}
+
{children.disabledInputStyle.getPropertyView()}
{children.animationStyle.getPropertyView()}
)} diff --git a/client/packages/lowcoder/src/comps/comps/textInputComp/textAreaComp.tsx b/client/packages/lowcoder/src/comps/comps/textInputComp/textAreaComp.tsx index c8a7582eb..049d5d88d 100644 --- a/client/packages/lowcoder/src/comps/comps/textInputComp/textAreaComp.tsx +++ b/client/packages/lowcoder/src/comps/comps/textInputComp/textAreaComp.tsx @@ -22,7 +22,7 @@ import { import { withMethodExposing, refMethods } from "../../generators/withMethodExposing"; import { styleControl } from "comps/controls/styleControl"; import styled from "styled-components"; -import { AnimationStyle, InputFieldStyle, InputLikeStyle, InputLikeStyleType, LabelStyle } from "comps/controls/styleControlConstants"; +import { AnimationStyle, InputFieldStyle, InputLikeStyle, InputLikeStyleType, LabelStyle, DisabledInputStyle, DisabledInputStyleType } from "comps/controls/styleControlConstants"; import { TextArea } from "components/TextArea"; import { allowClearPropertyView, @@ -41,10 +41,20 @@ import { migrateOldData } from "comps/generators/simpleGenerators"; const TextAreaStyled = styled(TextArea)<{ $style: InputLikeStyleType; + $disabledStyle?: DisabledInputStyleType; }>` box-shadow: ${(props) => `${props.$style?.boxShadow} ${props.$style?.boxShadowColor}`}; ${(props) => props.$style && getStyle(props.$style)} + + /* Disabled state styling */ + &:disabled, + &.ant-input-disabled { + color: ${(props) => props.$disabledStyle?.disabledText}; + background: ${(props) => props.$disabledStyle?.disabledBackground}; + border-color: ${(props) => props.$disabledStyle?.disabledBorder}; + cursor: not-allowed; + } `; const Wrapper = styled.div<{ @@ -82,6 +92,7 @@ let TextAreaTmpComp = (function () { textAreaScrollBar: withDefault(BoolControl, false), inputFieldStyle: styleControl(InputLikeStyle , 'inputFieldStyle'), animationStyle: styleControl(AnimationStyle, 'animationStyle'), + disabledStyle: styleControl(DisabledInputStyle, 'disabledStyle'), tabIndex: NumberControl }; return new UICompBuilder(childrenMap, (props) => { @@ -98,6 +109,7 @@ let TextAreaTmpComp = (function () { allowClear={props.allowClear} style={{ height: "100% !important", resize: "vertical" }} $style={props.inputFieldStyle} + $disabledStyle={props.disabledStyle} tabIndex={typeof props.tabIndex === 'number' ? props.tabIndex : undefined} /> @@ -141,6 +153,7 @@ let TextAreaTmpComp = (function () {
{children.style.getPropertyView()}
{children.labelStyle.getPropertyView()}
{children.inputFieldStyle.getPropertyView()}
+
{children.disabledStyle.getPropertyView()}
{children.animationStyle.getPropertyView()}
)} diff --git a/client/packages/lowcoder/src/comps/comps/textInputComp/textInputConstants.tsx b/client/packages/lowcoder/src/comps/comps/textInputComp/textInputConstants.tsx index 006d263f3..bacb892bd 100644 --- a/client/packages/lowcoder/src/comps/comps/textInputComp/textInputConstants.tsx +++ b/client/packages/lowcoder/src/comps/comps/textInputComp/textInputConstants.tsx @@ -315,8 +315,23 @@ export function getStyle(style: InputLikeStyleType, labelStyle?: LabelStyleType) } &::-webkit-input-placeholder { - color: ${style.text}; - opacity: 0.4; + color: ${style.placeholder}; + opacity: 1; + } + + &::-moz-placeholder { + color: ${style.placeholder}; + opacity: 1; + } + + &:-ms-input-placeholder { + color: ${style.placeholder}; + opacity: 1; + } + + &::placeholder { + color: ${style.placeholder}; + opacity: 1; } .ant-input-show-count-suffix, diff --git a/client/packages/lowcoder/src/comps/controls/styleControlConstants.tsx b/client/packages/lowcoder/src/comps/controls/styleControlConstants.tsx index 92b64b7eb..176afbbfc 100644 --- a/client/packages/lowcoder/src/comps/controls/styleControlConstants.tsx +++ b/client/packages/lowcoder/src/comps/controls/styleControlConstants.tsx @@ -244,9 +244,14 @@ export type DepColorConfig = CommonColorConfig & { transformer: (color: string, ...rest: string[]) => string; }; +export type PlaceholderConfig = CommonColorConfig & { + readonly placeholder?: string; +}; + export type SingleColorConfig = | SimpleColorConfig | DepColorConfig + | PlaceholderConfig | RadiusConfig | BorderWidthConfig | RotationConfig @@ -959,11 +964,101 @@ function replaceAndMergeMultipleStyles( return temp; } +// Add disabled style constants +const DISABLED_BACKGROUND = { + name: "disabledBackground", + label: trans("style.disabledBackground"), + color: SECOND_SURFACE_COLOR, +} as const; + + + +const DISABLED_TEXT = { + name: "disabledText", + label: trans("style.disabledText"), + depName: "disabledBackground", + depType: DEP_TYPE.CONTRAST_TEXT, + transformer: (color: string) => lightenColor(color, 0.8), +} as const; + + +export const DISABLED_BORDER = { + name: "disabledBorder", + label: trans("style.disabledBorder"), + color: SECOND_SURFACE_COLOR, +} as const; + +export const DISABLED_STYLE_FIELDS = [ + DISABLED_BACKGROUND, + DISABLED_TEXT, + DISABLED_BORDER, +] as const; + +// Add disabled style constants specifically for slider components +const DISABLED_SLIDER_FILL = { + name: "disabledFill", + label: trans("style.disabledFill"), + depName: "fill", + transformer: (color: string) => lightenColor(color, 0.8), +} as const; + +const DISABLED_SLIDER_TRACK = { + name: "disabledTrack", + label: trans("style.disabledTrack"), + depName: "track", + transformer: (color: string) => lightenColor(color, 0.8), +} as const; + +const DISABLED_SLIDER_THUMB = { + name: "disabledThumb", + label: trans("style.disabledThumb"), + depName: "thumb", + transformer: (color: string) => lightenColor(color, 0.8), +} as const; + +const DISABLED_SLIDER_THUMB_BORDER = { + name: "disabledThumbBorder", + label: trans("style.disabledThumbBorder"), + depName: "thumbBorder", + transformer: (color: string) => lightenColor(color, 0.8), +} as const; + +// Re-export for reuse in slider components +export const DISABLED_SLIDER_STYLE_FIELDS = [ + DISABLED_SLIDER_FILL, + DISABLED_SLIDER_TRACK, +] as const; + +// Helper to quickly create a component-specific disabled style list by +// extending the two generic disabled tokens above. +export const withDisabled = ( + extra: Extra = [] as unknown as Extra, +) => [...DISABLED_STYLE_FIELDS, ...extra] as const; + + +export const withDisabledSlider = ( + extra: Extra = [] as unknown as Extra, +) => [...DISABLED_SLIDER_STYLE_FIELDS, ...extra] as const; + + +export const DisabledSliderStyle = withDisabledSlider(); + export const ButtonStyle = [ getBackground('primary'), - ...STYLING_FIELDS_SEQUENCE.filter(style=>style.name!=='lineHeight'), + ...STYLING_FIELDS_SEQUENCE, ] as const; +// Create separate disabled style control +export const DisabledButtonStyle = withDisabled(); + + +// For input components +export const DisabledInputStyle = withDisabled(); + +// for step control +export const DisabledStepStyle = withDisabled(); + + export const DropdownStyle = [ getBackground(), ...STYLING_FIELDS_SEQUENCE.filter(style=>style.name!=='rotation'), @@ -1217,14 +1312,24 @@ export const SliderStyle = [ PADDING, ] as const; + +const PLACEHOLDER = { + name: "placeholder", + label: "Placeholder", + depName: "text", + transformer: (color: string) => lightenColor(color, 0.4), +} as const; + export const InputLikeStyle = [ getStaticBackground(SURFACE_COLOR), BOXSHADOW, BOXSHADOWCOLOR, ...STYLING_FIELDS_SEQUENCE.filter((style)=>style.name!=='rotation' && style.name!=='lineHeight'), + PLACEHOLDER, ...ACCENT_VALIDATE, ] as const; + // added by Mousheng export const ColorPickerStyle = [ @@ -1786,6 +1891,7 @@ export const DateTimeStyle = [ ...getStaticBgBorderRadiusByBg(SURFACE_COLOR), getStaticBorder(SECOND_SURFACE_COLOR), TEXT, + PLACEHOLDER, MARGIN, PADDING, BORDER_STYLE, @@ -2290,6 +2396,9 @@ export type InputFieldStyleType = StyleConfigType; export type SignatureContainerStyleType = StyleConfigType; export type ColorPickerStyleType = StyleConfigType; export type ButtonStyleType = StyleConfigType; +export type DisabledButtonStyleType = StyleConfigType; +export type DisabledInputStyleType = StyleConfigType; +export type DisabledStepStyleType = StyleConfigType; export type ToggleButtonStyleType = StyleConfigType; export type TextStyleType = StyleConfigType; export type TextContainerStyleType = StyleConfigType; @@ -2305,6 +2414,7 @@ export type ContainerFooterStyleType = StyleConfigType< typeof ContainerFooterStyle >; export type SliderStyleType = StyleConfigType; +export type DisabledSliderStyleType = StyleConfigType; export type RatingStyleType = StyleConfigType; export type SwitchStyleType = StyleConfigType; export type SelectStyleType = StyleConfigType; @@ -2436,3 +2546,4 @@ export function marginCalculator(margin: string) { } export type {ThemeDetail}; + diff --git a/client/packages/lowcoder/src/i18n/locales/en.ts b/client/packages/lowcoder/src/i18n/locales/en.ts index 44f5f4b1d..c85c520a7 100644 --- a/client/packages/lowcoder/src/i18n/locales/en.ts +++ b/client/packages/lowcoder/src/i18n/locales/en.ts @@ -229,6 +229,7 @@ export const en = { "className": "CSS Class name", "dataTestId": "Individual ID", "preventOverwriting": "Prevent overwriting styles", + "disabledStyle": "Disabled Style", "color": "Color", "horizontalGridCells": "Horizontal Grid Cells", "verticalGridCells": "Vertical Grid Cells", @@ -511,6 +512,11 @@ export const en = { "tabAccent": "Tab Accent", "checkedBackground": "Checked Background Color", "uncheckedBackground": "Unchecked Background Color", + "disabledBackground": "Background Color", + "disabledBorder": "Border Color", + "disabledText": "Text Color", + "disabledTrack": "Track Color", + "disabledFill": "Fill Color", "uncheckedBorder": "Unchecked Border Color", "indicatorBackground": "Indicator Background Color", "tableCellText": "Cell Text",








ApplySandwichStrip

pFad - (p)hone/(F)rame/(a)nonymizer/(d)eclutterfier!      Saves Data!


--- a PPN by Garber Painting Akron. With Image Size Reduction included!

Fetched URL: http://github.com/lowcoder-org/lowcoder/pull/1815.diff

Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy