diff --git a/.gitignore b/.gitignore index 81c0e6c82..6efa61305 100644 --- a/.gitignore +++ b/.gitignore @@ -10,3 +10,8 @@ client/packages/lowcoder-plugin-demo/.yarn/install-state.gz client/packages/lowcoder-plugin-demo/yarn.lock client/packages/lowcoder-plugin-demo/.yarn/cache/@types-node-npm-16.18.68-56f72825c0-094ae9ed80.zip application-dev.yml +server/api-service/lowcoder-server/src/main/resources/application-lowcoder.yml +server/api-service/lowcoder-server/src/main/resources/application-debug.yaml +.vscode/settings.json +.vscode/launch.json +server/api-service/lowcoder-server/src/main/resources/application-dev-localhost.yaml diff --git a/.vscode/settings.json b/.vscode/settings.json index 39649ae48..9cae45514 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -3,5 +3,6 @@ "activityBar.background": "#2A3012", "titleBar.activeBackground": "#3B431A", "titleBar.activeForeground": "#F9FAF2" - } + }, + "java.debug.settings.onBuildFailureProceed": true } \ No newline at end of file diff --git a/client/VERSION b/client/VERSION index 9183195ac..58073ef8d 100644 --- a/client/VERSION +++ b/client/VERSION @@ -1 +1 @@ -2.4.0 \ No newline at end of file +2.4.1 \ No newline at end of file diff --git a/client/packages/lowcoder-cli-template-typescript/src/i18n/comps/index.tsx b/client/packages/lowcoder-cli-template-typescript/src/i18n/comps/index.tsx index 452f3327b..3e2b2c6ae 100644 --- a/client/packages/lowcoder-cli-template-typescript/src/i18n/comps/index.tsx +++ b/client/packages/lowcoder-cli-template-typescript/src/i18n/comps/index.tsx @@ -14,6 +14,8 @@ export function getEchartsLocale() { switch (locale.language) { case "en": return "EN"; + case "pt": + return "PT"; case "zh": return "ZH"; } @@ -24,6 +26,8 @@ export function getCalendarLocale() { switch (language) { case "zh": return "zh-cn"; + case "pt": + return "pt-br"; default: return "en-gb"; } diff --git a/client/packages/lowcoder-cli-template-typescript/src/i18n/comps/locales/pt.ts b/client/packages/lowcoder-cli-template-typescript/src/i18n/comps/locales/pt.ts new file mode 100644 index 000000000..b573b43ee --- /dev/null +++ b/client/packages/lowcoder-cli-template-typescript/src/i18n/comps/locales/pt.ts @@ -0,0 +1,37 @@ +import {en} from "./en" +export const pt: typeof en = { + ...en, + "style": { + "textColor": "Cor do Texto", + "contrastText": "Cor de Contraste do Texto", + "accent": "Acento", + "border": "Cor da Borda", + "borderRadius": "Raio da Borda", + "borderWidth": "Grossura da Borda", + "backgroundColor": "Cor de Fundo", + "headerBackground": "Cor do Header", + "footerBackground": "Cor do Footer", + "checkedBackground": "Cor com Seleção", + "uncheckedBackground": "Cor sem Seleção", + "uncheckedBorder": "Borda sem Seleção", + "indicatorBackground": "Cor de Indicação", + "toolbarBackground": "Cor de Fundo da Barra de Informações", + "margin": "Margem", + "padding": "Preenchimento", + "marginLeft": "Margem Esquerda", + "marginRight": "Margem Direita", + "marginTop": "Margem Superior", + "marginBottom": "Margem Inferior", + "minWidth": "Largura Mínima", + "aspectRatio": "Proporção de Tela", + "textSize": "Tamanho do Texto", + }, + "component": { + "data": "Dados Hillchart", + }, + "methods": { + "setPoint": "Definir Ponto", + "invalidInput": "Entrada Inválida", + "requiredField": "{field} é obrigatório", + } +}; diff --git a/client/packages/lowcoder-cli-template-typescript/src/i18n/comps/locales/ptObj.tsx b/client/packages/lowcoder-cli-template-typescript/src/i18n/comps/locales/ptObj.tsx new file mode 100644 index 000000000..11fcf8e47 --- /dev/null +++ b/client/packages/lowcoder-cli-template-typescript/src/i18n/comps/locales/ptObj.tsx @@ -0,0 +1,40 @@ +import { I18nObjects } from "./types"; + +export const enObj: I18nObjects = { + defaultData: [ + { + id : 1, + color: 'gray', + description: 'Validação: Integração do Salesforce', + x: 25, + size: 15 + }, + { + id : 2, + color: 'maroon', + description: 'Renovações', + x: 80, + size: 10 }, + { + id : 3, + color: 'maroon', + description: 'Rafatoramento: Fancy Pants', + x: 35, + size: 10 + }, + { + id : 4, + color: 'cyan', + description: 'Refatoramento: Lighthouse Orbs', + x: 45, + size: 10 + }, + { + id : 5, + color: 'yellow', + description: 'Migração e Atualização de Dados', + x: 50, + size: 20 + } + ], +}; diff --git a/client/packages/lowcoder-comps/package.json b/client/packages/lowcoder-comps/package.json index 1c417f1d4..7a31785b7 100644 --- a/client/packages/lowcoder-comps/package.json +++ b/client/packages/lowcoder-comps/package.json @@ -1,6 +1,6 @@ { "name": "lowcoder-comps", - "version": "2.4.5", + "version": "2.4.7", "type": "module", "license": "MIT", "dependencies": { diff --git a/client/packages/lowcoder-comps/src/comps/agoraMeetingComp/meetingControllerComp.tsx b/client/packages/lowcoder-comps/src/comps/agoraMeetingComp/meetingControllerComp.tsx index 268b16404..9af1f3f6c 100644 --- a/client/packages/lowcoder-comps/src/comps/agoraMeetingComp/meetingControllerComp.tsx +++ b/client/packages/lowcoder-comps/src/comps/agoraMeetingComp/meetingControllerComp.tsx @@ -240,366 +240,386 @@ const meetingControllerChildren = { messages: stateComp([]), }; -let MeetingControllerComp = () =>
Meeting Component is not available. It needs Lowcoder from Version v2.4
; - -if (typeof ContainerCompBuilder === 'function') { - -let MTComp = (function () { - return new ContainerCompBuilder( - meetingControllerChildren, (props: any, dispatch: any) => { - - const isTopBom = ["top", "bottom"].includes(props.placement); - const { items, ...otherContainerProps } = props.container; - // const userViewMode = useUserViewMode(); - // const resizable = !userViewMode && (!isTopBom || !props.autoHeight); - const onResizeStop = useCallback( - ( - e: React.SyntheticEvent, - node: HTMLElement, - size: { width: number; height: number }, - handle: ResizeHandle - ) => { - isTopBom - ? dispatch(changeChildAction("height", size.height, true)) - : dispatch(changeChildAction("width", size.width, true)); - }, - [dispatch, isTopBom] - ); - const [userIds, setUserIds] = useState([]); - const [updateVolume, setUpdateVolume] = useState({ - update: false, - userid: null, - }); - const [rtmMessages, setRtmMessages] = useState([]); - const [localUserSpeaking, setLocalUserSpeaking] = useState(false); - const [localUserVideo, setLocalUserVideo] = - useState(); - const [userJoined, setUserJoined] = useState(); - const [userLeft, setUserLeft] = useState(); - - useEffect(() => { - if (userJoined) { - // console.log("userJoined ", userJoined); - - let prevUsers: any[] = props.participants as []; - // console.log("prevUsers ", prevUsers); - let userData = { - user: userJoined.uid, - audiostatus: userJoined.hasAudio, - streamingVideo: true, - }; - // console.log("userData ", userData); - setUserIds((userIds: any) => [...userIds, userData]); - // console.log("userIds ", userIds); - /* console.log( +let MeetingControllerComp = () => ( +
+ Meeting Component is not available. It needs Lowcoder from Version v2.4 +
+); + +if (typeof ContainerCompBuilder === "function") { + let MTComp = (function () { + return new ContainerCompBuilder( + meetingControllerChildren, + (props: any, dispatch: any) => { + const isTopBom = ["top", "bottom"].includes(props.placement); + const { items, ...otherContainerProps } = props.container; + const userViewMode = useUserViewMode(); + const resizable = !userViewMode && (!isTopBom || !props.autoHeight); + const onResizeStop = useCallback( + ( + e: React.SyntheticEvent, + node: HTMLElement, + size: { width: number; height: number }, + handle: ResizeHandle + ) => { + isTopBom + ? dispatch(changeChildAction("height", size.height, true)) + : dispatch(changeChildAction("width", size.width, true)); + }, + [dispatch, isTopBom] + ); + const [userIds, setUserIds] = useState([]); + const [updateVolume, setUpdateVolume] = useState({ + update: false, + userid: null, + }); + const [rtmMessages, setRtmMessages] = useState([]); + const [localUserSpeaking, setLocalUserSpeaking] = useState(false); + const [localUserVideo, setLocalUserVideo] = + useState(); + const [userJoined, setUserJoined] = useState(); + const [userLeft, setUserLeft] = useState(); + + useEffect(() => { + if (userJoined) { + // console.log("userJoined ", userJoined); + + let prevUsers: any[] = props.participants as []; + // console.log("prevUsers ", prevUsers); + let userData = { + user: userJoined.uid, + audiostatus: userJoined.hasAudio, + streamingVideo: true, + }; + // console.log("userData ", userData); + setUserIds((userIds: any) => [...userIds, userData]); + // console.log("userIds ", userIds); + /* console.log( "removeDuplicates ", removeDuplicates(getData([...prevUsers, userData]).data, "user") ); */ - dispatch( - changeChildAction( - "participants", - removeDuplicates(getData([...prevUsers, userData]).data, "user"), - false - ) - ); - } - }, [userJoined]); + dispatch( + changeChildAction( + "participants", + removeDuplicates( + getData([...prevUsers, userData]).data, + "user" + ), + false + ) + ); + } + }, [userJoined]); - function removeDuplicates(arr: any, prop: any) { - const uniqueObjects = []; - const seenValues = new Set(); + function removeDuplicates(arr: any, prop: any) { + const uniqueObjects = []; + const seenValues = new Set(); - for (const obj of arr) { - const objValue = obj[prop]; + for (const obj of arr) { + const objValue = obj[prop]; - if (!seenValues.has(objValue)) { - seenValues.add(objValue); - uniqueObjects.push(obj); + if (!seenValues.has(objValue)) { + seenValues.add(objValue); + uniqueObjects.push(obj); + } } - } - return uniqueObjects; - } - useEffect(() => { - if (userLeft) { - let newUsers = userIds.filter( - (item: any) => item.user !== userLeft.uid - ); - let hostExists = newUsers.filter((f: any) => f.host === true); - if (hostExists.length == 0 && newUsers.length > 0) { - newUsers[0].host = true; - } - setUserIds(newUsers); - dispatch( - changeChildAction( - "participants", - removeDuplicates(getData(newUsers).data, "user"), - false - ) - ); + return uniqueObjects; } - }, [userLeft]); + useEffect(() => { + if (userLeft) { + let newUsers = userIds.filter( + (item: any) => item.user !== userLeft.uid + ); + let hostExists = newUsers.filter((f: any) => f.host === true); + if (hostExists.length == 0 && newUsers.length > 0) { + newUsers[0].host = true; + } + setUserIds(newUsers); + dispatch( + changeChildAction( + "participants", + removeDuplicates(getData(newUsers).data, "user"), + false + ) + ); + } + }, [userLeft]); - // console.log("sharing", props.sharing); + // console.log("sharing", props.sharing); - useEffect(() => { - if (updateVolume.userid) { - let prevUsers: [] = props.participants as []; + useEffect(() => { + if (updateVolume.userid) { + let prevUsers: [] = props.participants as []; + const updatedItems = prevUsers.map((userInfo: any) => { + if ( + userInfo.user === updateVolume.userid && + userInfo.speaking != updateVolume.update + ) { + return { ...userInfo, speaking: updateVolume.update }; + } + return userInfo; + }); + dispatch( + changeChildAction( + "participants", + getData(updatedItems).data, + false + ) + ); + } + }, [updateVolume]); + + useEffect(() => { + let prevUsers: [] = props.participants as []; const updatedItems = prevUsers.map((userInfo: any) => { - if ( - userInfo.user === updateVolume.userid && - userInfo.speaking != updateVolume.update - ) { - return { ...userInfo, speaking: updateVolume.update }; + if (userInfo.user === localUserVideo?.uid) { + return { ...userInfo, streamingSharing: props.sharing.value }; } return userInfo; }); dispatch( changeChildAction("participants", getData(updatedItems).data, false) ); - } - }, [updateVolume]); - - useEffect(() => { - let prevUsers: [] = props.participants as []; - const updatedItems = prevUsers.map((userInfo: any) => { - if (userInfo.user === localUserVideo?.uid) { - return { ...userInfo, streamingSharing: props.sharing.value }; - } - return userInfo; - }); - dispatch( - changeChildAction("participants", getData(updatedItems).data, false) - ); - let localObject = { - user: userId + "", - audiostatus: props.audioControl.value, - streamingVideo: props.videoControl.value, - streamingSharing: props.sharing.value, - speaking: localUserSpeaking, - }; - props.localUser.onChange(localObject); - }, [props.sharing.value]); - - // console.log("participants ", props.participants); - - useEffect(() => { - let prevUsers: [] = props.participants as []; - const updatedItems = prevUsers.map((userInfo: any) => { - if (userInfo.user === localUserVideo?.uid) { - return { ...userInfo, streamingVideo: localUserVideo?.hasVideo }; - } - return userInfo; - }); - dispatch( - changeChildAction("participants", getData(updatedItems).data, false) - ); - }, [localUserVideo?.hasVideo]); - - useEffect(() => { - if (rtmMessages) { - dispatch( - changeChildAction("messages", getData(rtmMessages).data, false) - ); - } - }, [rtmMessages]); - - useEffect(() => { - if (localUserSpeaking === true || localUserVideo) { let localObject = { user: userId + "", audiostatus: props.audioControl.value, streamingVideo: props.videoControl.value, + streamingSharing: props.sharing.value, speaking: localUserSpeaking, }; props.localUser.onChange(localObject); - } - }, [localUserSpeaking]); - - useEffect(() => { - if (rtmChannelResponse) { - rtmClient.on("MessageFromPeer", function (message, peerId) { - setRtmMessages((prevMessages: any[]) => { - // Check if the messages array exceeds the maximum limit - if (prevMessages.length >= 500) { - prevMessages.pop(); // Remove the oldest message - } - return [ - ...prevMessages, - { peermessage: JSON.parse(message.text + ""), from: peerId }, - ]; - }); - }); + }, [props.sharing.value]); - rtmChannelResponse.on("ChannelMessage", function (message, memberId) { - setRtmMessages((prevMessages: any[]) => { - // Check if the messages array exceeds the maximum limit - if (prevMessages.length >= 500) { - prevMessages.pop(); // Remove the oldest message - } - return [ - ...prevMessages, - { - channelmessage: JSON.parse(message.text + ""), - from: memberId, - }, - ]; - }); + // console.log("participants ", props.participants); + + useEffect(() => { + let prevUsers: [] = props.participants as []; + const updatedItems = prevUsers.map((userInfo: any) => { + if (userInfo.user === localUserVideo?.uid) { + return { ...userInfo, streamingVideo: localUserVideo?.hasVideo }; + } + return userInfo; + }); + dispatch( + changeChildAction("participants", getData(updatedItems).data, false) + ); + }, [localUserVideo?.hasVideo]); + useEffect(() => { + if (rtmMessages) { dispatch( changeChildAction("messages", getData(rtmMessages).data, false) ); - }); - } - }, [rtmChannelResponse]); - useEffect(() => { - if (client) { - //Enable Agora to send audio bytes - client.enableAudioVolumeIndicator(); - //user activity listeners - client.on("user-joined", (user: IAgoraRTCRemoteUser) => { - setUserJoined(user); - }); - client.on("user-left", (user: IAgoraRTCRemoteUser, reason: any) => { - setUserLeft(user); - }); + } + }, [rtmMessages]); + + useEffect(() => { + if (localUserSpeaking === true || localUserVideo) { + let localObject = { + user: userId + "", + audiostatus: props.audioControl.value, + streamingVideo: props.videoControl.value, + speaking: localUserSpeaking, + }; + props.localUser.onChange(localObject); + } + }, [localUserSpeaking]); + + useEffect(() => { + if (rtmChannelResponse) { + rtmClient.on("MessageFromPeer", function (message, peerId) { + setRtmMessages((prevMessages: any[]) => { + // Check if the messages array exceeds the maximum limit + if (prevMessages.length >= 500) { + prevMessages.pop(); // Remove the oldest message + } + return [ + ...prevMessages, + { peermessage: JSON.parse(message.text + ""), from: peerId }, + ]; + }); + }); - //listen to user speaking, - client.on("volume-indicator", (volumeInfos: any) => { - if (volumeInfos.length === 0) return; - volumeInfos.map((volumeInfo: any) => { - //when the volume is above 30, user is probably speaking - const speaking = volumeInfo.level >= 30; - if ( - volumeInfo.uid === userId && - props.localUser.value.speaking != speaking - ) { - setLocalUserSpeaking(speaking); - } else { - setUpdateVolume({ update: speaking, userid: volumeInfo.uid }); + rtmChannelResponse.on( + "ChannelMessage", + function (message, memberId) { + setRtmMessages((prevMessages: any[]) => { + // Check if the messages array exceeds the maximum limit + if (prevMessages.length >= 500) { + prevMessages.pop(); // Remove the oldest message + } + return [ + ...prevMessages, + { + channelmessage: JSON.parse(message.text + ""), + from: memberId, + }, + ]; + }); + + dispatch( + changeChildAction( + "messages", + getData(rtmMessages).data, + false + ) + ); } + ); + } + }, [rtmChannelResponse]); + useEffect(() => { + if (client) { + //Enable Agora to send audio bytes + client.enableAudioVolumeIndicator(); + //user activity listeners + client.on("user-joined", (user: IAgoraRTCRemoteUser) => { + setUserJoined(user); + }); + client.on("user-left", (user: IAgoraRTCRemoteUser, reason: any) => { + setUserLeft(user); }); - }); - client.on( - "user-published", - async (user: IAgoraRTCRemoteUser, mediaType: "video" | "audio") => { - setLocalUserVideo(user); - } - ); - client.on( - "user-unpublished", - (user: IAgoraRTCRemoteUser, mediaType: "video" | "audio") => { - setLocalUserVideo(user); - } - ); - } - }, [client]); - - return ( - - {/* */} - - document.querySelector(`#${CanvasContainerID}`) || document.body - } - footer={null} - width={transToPxSize(props.width || DEFAULT_SIZE)} - height={ - !props.autoHeight - ? transToPxSize(props.height || DEFAULT_SIZE) - : "" - } - onClose={(e: any) => { - props.visible.onChange(false); - }} - afterOpenChange={(visible: any) => { - if (!visible) { - props.onEvent("close"); + //listen to user speaking, + client.on("volume-indicator", (volumeInfos: any) => { + if (volumeInfos.length === 0) return; + volumeInfos.map((volumeInfo: any) => { + //when the volume is above 30, user is probably speaking + const speaking = volumeInfo.level >= 30; + if ( + volumeInfo.uid === userId && + props.localUser.value.speaking != speaking + ) { + setLocalUserSpeaking(speaking); + } else { + setUpdateVolume({ update: speaking, userid: volumeInfo.uid }); + } + }); + }); + + client.on( + "user-published", + async ( + user: IAgoraRTCRemoteUser, + mediaType: "video" | "audio" + ) => { + setLocalUserVideo(user); + } + ); + client.on( + "user-unpublished", + (user: IAgoraRTCRemoteUser, mediaType: "video" | "audio") => { + setLocalUserVideo(user); + } + ); + } + }, [client]); + + return ( + + {/* */} + - {/* + document.querySelector(`#${CanvasContainerID}`) || document.body + } + footer={null} + width={transToPxSize(props.width || DEFAULT_SIZE)} + height={ + !props.autoHeight + ? transToPxSize(props.height || DEFAULT_SIZE) + : "" + } + onClose={(e: any) => { + props.visible.onChange(false); + }} + afterOpenChange={(visible: any) => { + if (!visible) { + props.onEvent("close"); + } + }} + zIndex={Layers.drawer} + maskClosable={props.maskClosable} + mask={props.showMask} + > + {/* { props.visible.onChange(false); }} > */} - - - {/* */} - - ); - } - ) - .setPropertyViewFn((children: any) => ( - <> - {/* {(EditorContext.editorModeStatus === "logic" || + + + {/* */} + + ); + } + ) + .setPropertyViewFn((children: any) => ( + <> + {/* {(EditorContext.editorModeStatus === "logic" || EditorContext.editorModeStatus === "both") && ( <> */} -
- {children.appId.propertyView({ - label: trans("meeting.appid"), - })} - {children.meetingName.propertyView({ - label: trans("meeting.meetingName"), - })} - {children.localUserID.propertyView({ - label: trans("meeting.localUserID"), - })} - {children.rtmToken.propertyView({ - label: trans("meeting.rtmToken"), - })} - {children.rtcToken.propertyView({ - label: trans("meeting.rtcToken"), - })} -
-
- {children.onEvent.getPropertyView()} - {children.onMeetingEvent.getPropertyView()} -
- {/* +
+ {children.appId.propertyView({ + label: trans("meeting.appid"), + })} + {children.meetingName.propertyView({ + label: trans("meeting.meetingName"), + })} + {children.localUserID.propertyView({ + label: trans("meeting.localUserID"), + })} + {children.rtmToken.propertyView({ + label: trans("meeting.rtmToken"), + })} + {children.rtcToken.propertyView({ + label: trans("meeting.rtcToken"), + })} +
+
+ {children.onEvent.getPropertyView()} + {children.onMeetingEvent.getPropertyView()} +
+ {/* )} */} - {/* {(EditorContext.editorModeStatus === "layout" || + {/* {(EditorContext.editorModeStatus === "layout" || EditorContext.editorModeStatus === "both") && ( <> */} - {/*
+ {/*
{children.placement.propertyView({ label: trans("meeting.placement"), radioButton: true, @@ -629,254 +649,254 @@ let MTComp = (function () {
{children.style.getPropertyView()}
*/} - {/* */} - {/* )} */} - - )) - .build(); - - })(); - - MTComp = class extends MTComp { - autoHeight(): boolean { - return false; - } - }; - - MTComp = withMethodExposing(MTComp, [ - { - method: { - name: "openDrawer", - params: [], - }, - execute: (comp: any, values: any) => { - comp.children.visible.getView().onChange(true); - }, + {/* */} + {/* )} */} + + )) + .build(); + })(); + + MTComp = class extends MTComp { + autoHeight(): boolean { + return false; + } + }; + + MTComp = withMethodExposing(MTComp, [ + { + method: { + name: "openDrawer", + params: [], }, - { - method: { - name: "startSharing", - params: [], - }, - execute: async (comp: any, values: any) => { - if (!comp.children.meetingActive.getView().value) return; - let sharing = !comp.children.sharing.getView().value; - await shareScreen(sharing); - comp.children.sharing.change(sharing); - }, + execute: (comp: any, values: any) => { + comp.children.visible.getView().onChange(true); }, - { - method: { - name: "audioControl", - description: trans("meeting.actionBtnDesc"), - params: [], - }, - execute: async (comp: any, values: any) => { - if (!comp.children.meetingActive.getView().value) return; - let value = !comp.children.audioControl.getView().value; - comp.children.localUser.change({ - user: userId + "", - audiostatus: value, - streamingVideo: comp.children.videoControl.getView().value, - speaking: false, - }); - await turnOnMicrophone(value); - comp.children.audioControl.change(value); - }, + }, + { + method: { + name: "startSharing", + params: [], }, - { - method: { - name: "videoControl", - description: trans("meeting.actionBtnDesc"), - params: [], - }, - execute: async (comp: any, values: any) => { - //check if meeting is active - if (!comp.children.meetingActive.getView().value) return; - //toggle videoControl - let value = !comp.children.videoControl.getView().value; - if (videoTrack) { - videoTrack.setEnabled(value); - } else { - await turnOnCamera(value); - } - //change my local user data - let localData = { - user: userId + "", - streamingVideo: value, - audiostatus: comp.children.audioControl.getView().value, - speaking: comp.children.localUser.getView().value.speaking, - }; - - comp.children.localUser.change(localData); - comp.children.videoControl.change(value); - }, + execute: async (comp: any, values: any) => { + if (!comp.children.meetingActive.getView().value) return; + let sharing = !comp.children.sharing.getView().value; + await shareScreen(sharing); + comp.children.sharing.change(sharing); }, - { - method: { - name: "startMeeting", - description: trans("meeting.actionBtnDesc"), - params: [], - }, - execute: async (comp: any, values: any) => { - /* console.log("startMeeting ", { + }, + { + method: { + name: "audioControl", + description: trans("meeting.actionBtnDesc"), + params: [], + }, + execute: async (comp: any, values: any) => { + if (!comp.children.meetingActive.getView().value) return; + let value = !comp.children.audioControl.getView().value; + comp.children.localUser.change({ + user: userId + "", + audiostatus: value, + streamingVideo: comp.children.videoControl.getView().value, + speaking: false, + }); + await turnOnMicrophone(value); + comp.children.audioControl.change(value); + }, + }, + { + method: { + name: "videoControl", + description: trans("meeting.actionBtnDesc"), + params: [], + }, + execute: async (comp: any, values: any) => { + //check if meeting is active + if (!comp.children.meetingActive.getView().value) return; + //toggle videoControl + let value = !comp.children.videoControl.getView().value; + if (videoTrack) { + videoTrack.setEnabled(value); + } else { + await turnOnCamera(value); + } + //change my local user data + let localData = { + user: userId + "", + streamingVideo: value, + audiostatus: comp.children.audioControl.getView().value, + speaking: comp.children.localUser.getView().value.speaking, + }; + + comp.children.localUser.change(localData); + comp.children.videoControl.change(value); + }, + }, + { + method: { + name: "startMeeting", + description: trans("meeting.actionBtnDesc"), + params: [], + }, + execute: async (comp: any, values: any) => { + /* console.log("startMeeting ", { // user: userId + "", audiostatus: false, speaking: false, streamingVideo: true, }); */ - if (comp.children.meetingActive.getView().value) return; - userId = - comp.children.localUserID.getView().value === "" - ? uuidv4() - : comp.children.localUserID.getView().value; - comp.children.localUser.change({ - user: userId + "", - audiostatus: false, - speaking: false, - streamingVideo: true, - }); - /* console.log("startMeeting localUser ", { + if (comp.children.meetingActive.getView().value) return; + userId = + comp.children.localUserID.getView().value === "" + ? uuidv4() + : comp.children.localUserID.getView().value; + comp.children.localUser.change({ + user: userId + "", + audiostatus: false, + speaking: false, + streamingVideo: true, + }); + /* console.log("startMeeting localUser ", { user: userId + "", audiostatus: false, speaking: false, streamingVideo: true, }); */ - - comp.children.localUser.children.value.dispatch( - changeChildAction( - "localUser", - { - user: userId + "", - audiostatus: false, - speaking: false, - streamingVideo: true, - }, - false - ) - ); - comp.children.videoControl.change(true); - await publishVideo( - comp.children.appId.getView(), - comp.children.meetingName.getView().value === "" - ? uuidv4() - : comp.children.meetingName.getView().value, - comp.children.rtmToken.getView().value, - comp.children.rtcToken.getView().value - ); - comp.children.meetingActive.change(true); - }, + + comp.children.localUser.children.value.dispatch( + changeChildAction( + "localUser", + { + user: userId + "", + audiostatus: false, + speaking: false, + streamingVideo: true, + }, + false + ) + ); + comp.children.videoControl.change(true); + await publishVideo( + comp.children.appId.getView(), + comp.children.meetingName.getView().value === "" + ? uuidv4() + : comp.children.meetingName.getView().value, + comp.children.rtmToken.getView().value, + comp.children.rtcToken.getView().value + ); + comp.children.meetingActive.change(true); }, - { - method: { - name: "broadCast", - description: trans("meeting.broadCast"), - params: [], - }, - execute: async (comp: any, values: any) => { - if (!comp.children.meetingActive.getView().value) return; - let messagedata = - values !== undefined && values[0] !== undefined ? values[0] : ""; - let toUsers: any = - values !== undefined && values[1] !== undefined ? values[1] : ""; - - let message: any = { - time: Date.now(), - message: messagedata, - }; - - if (toUsers.length > 0 && toUsers[0] !== undefined) { - toUsers.forEach((peer: any) => { - message.to = peer; - sendPeerMessageRtm(message, String(peer)); - }); - } else { - sendMessageRtm(message); - } - }, + }, + { + method: { + name: "broadCast", + description: trans("meeting.broadCast"), + params: [], }, - { - method: { - name: "setMeetingName", - description: trans("meeting.meetingName"), - params: [], - }, - execute: async (comp: any, values: any) => { - let meetingName: any = values[0]; - comp.children.meetingName.change(meetingName); - }, + execute: async (comp: any, values: any) => { + if (!comp.children.meetingActive.getView().value) return; + let messagedata = + values !== undefined && values[0] !== undefined ? values[0] : ""; + let toUsers: any = + values !== undefined && values[1] !== undefined ? values[1] : ""; + + let message: any = { + time: Date.now(), + message: messagedata, + }; + + if (toUsers.length > 0 && toUsers[0] !== undefined) { + toUsers.forEach((peer: any) => { + message.to = peer; + sendPeerMessageRtm(message, String(peer)); + }); + } else { + sendMessageRtm(message); + } }, - { - method: { - name: "setUserName", - description: trans("meeting.userName"), - params: [], - }, - execute: async (comp: any, values: any) => { - let userName: any = values[0]; - let userLocal = comp.children.localUser.getView().value; - comp.children.localUser.change({ ...userLocal, userName: userName }); - }, + }, + { + method: { + name: "setMeetingName", + description: trans("meeting.meetingName"), + params: [], }, - { - method: { - name: "setRTCToken", - description: trans("meeting.rtcToken"), - params: [], - }, - execute: async (comp: any, values: any) => { - let rtcToken: any = values[0]; - comp.children.rtcToken.change(rtcToken); - }, + execute: async (comp: any, values: any) => { + let meetingName: any = values[0]; + comp.children.meetingName.change(meetingName); }, - { - method: { - name: "setRTMToken", - description: trans("meeting.rtmToken"), - params: [], - }, - execute: async (comp: any, values: any) => { - let rtmToken: any = values[0]; - comp.children.rtmToken.change(rtmToken); - }, + }, + { + method: { + name: "setUserName", + description: trans("meeting.userName"), + params: [], }, - { - method: { - name: "endMeeting", - description: trans("meeting.actionBtnDesc"), - params: [], - }, - execute: async (comp: any, values: any) => { - if (!comp.children.meetingActive.getView().value) return; - - let value = !comp.children.endCall.getView().value; - comp.children.endCall.change(value); - comp.children.meetingActive.change(false); - - await leaveChannel(); - - comp.children.localUser.change({ - user: userId + "", - streamingVideo: false, - }); - }, + execute: async (comp: any, values: any) => { + let userName: any = values[0]; + let userLocal = comp.children.localUser.getView().value; + comp.children.localUser.change({ ...userLocal, userName: userName }); + }, + }, + { + method: { + name: "setRTCToken", + description: trans("meeting.rtcToken"), + params: [], + }, + execute: async (comp: any, values: any) => { + let rtcToken: any = values[0]; + comp.children.rtcToken.change(rtcToken); + }, + }, + { + method: { + name: "setRTMToken", + description: trans("meeting.rtmToken"), + params: [], + }, + execute: async (comp: any, values: any) => { + let rtmToken: any = values[0]; + comp.children.rtmToken.change(rtmToken); + }, + }, + { + method: { + name: "endMeeting", + description: trans("meeting.actionBtnDesc"), + params: [], }, - ]); - - MeetingControllerComp = withExposingConfigs(MTComp, [ - new NameConfig("appId", trans("meeting.appid")), - new NameConfig("localUser", trans("meeting.host")), - new NameConfig("participants", trans("meeting.participants")), - new NameConfig("meetingActive", trans("meeting.meetingActive")), - new NameConfig("meetingName", trans("meeting.meetingName")), - new NameConfig("localUserID", trans("meeting.localUserID")), - new NameConfig("messages", trans("meeting.messages")), - new NameConfig("rtmToken", trans("meeting.rtmToken")), - new NameConfig("rtcToken", trans("meeting.rtcToken")), - ]); + execute: async (comp: any, values: any) => { + if (!comp.children.meetingActive.getView().value) return; + let value = !comp.children.endCall.getView().value; + comp.children.endCall.change(value); + comp.children.meetingActive.change(false); + + await leaveChannel(); + + comp.children.localUser.change({ + user: userId + "", + streamingVideo: false, + }); + }, + }, + ]); + + MeetingControllerComp = withExposingConfigs(MTComp, [ + new NameConfig("appId", trans("meeting.appid")), + new NameConfig("localUser", trans("meeting.host")), + new NameConfig("participants", trans("meeting.participants")), + new NameConfig("meetingActive", trans("meeting.meetingActive")), + new NameConfig("meetingName", trans("meeting.meetingName")), + new NameConfig("localUserID", trans("meeting.localUserID")), + new NameConfig("messages", trans("meeting.messages")), + new NameConfig("rtmToken", trans("meeting.rtmToken")), + new NameConfig("rtcToken", trans("meeting.rtcToken")), + ]); } else { - console.error("ContainerCompBuilder for Meeting Comp is not available. Please ensure that Lowcoder SDK version v2.4 or higher is installed."); + console.error( + "ContainerCompBuilder for Meeting Comp is not available. Please ensure that Lowcoder SDK version v2.4 or higher is installed." + ); } -export { MeetingControllerComp }; \ No newline at end of file +export { MeetingControllerComp }; diff --git a/client/packages/lowcoder-comps/src/comps/agoraMeetingComp/videoMeetingStreamComp.tsx b/client/packages/lowcoder-comps/src/comps/agoraMeetingComp/videoMeetingStreamComp.tsx index 7c5569804..a6d49b854 100644 --- a/client/packages/lowcoder-comps/src/comps/agoraMeetingComp/videoMeetingStreamComp.tsx +++ b/client/packages/lowcoder-comps/src/comps/agoraMeetingComp/videoMeetingStreamComp.tsx @@ -130,7 +130,7 @@ let VideoCompBuilder = (function () { setVideo(userData.streamingVideo); } }, [props.userId.value]); - console.log("userId", userId); + // console.log("userId", userId); return ( diff --git a/client/packages/lowcoder-comps/src/comps/agoraMeetingComp/videoSharingStreamComp.tsx b/client/packages/lowcoder-comps/src/comps/agoraMeetingComp/videoSharingStreamComp.tsx index 35b94ebdf..dbedc1fd5 100644 --- a/client/packages/lowcoder-comps/src/comps/agoraMeetingComp/videoSharingStreamComp.tsx +++ b/client/packages/lowcoder-comps/src/comps/agoraMeetingComp/videoSharingStreamComp.tsx @@ -231,4 +231,3 @@ export const VideoSharingStreamComp = withExposingConfigs(SharingCompBuilder, [ new NameConfig("loading", trans("meeting.loadingDesc")), ...CommonNameConfig, ]); - \ No newline at end of file diff --git a/client/packages/lowcoder-comps/src/i18n/comps/index.tsx b/client/packages/lowcoder-comps/src/i18n/comps/index.tsx index 72683c23b..2f3e9ce70 100644 --- a/client/packages/lowcoder-comps/src/i18n/comps/index.tsx +++ b/client/packages/lowcoder-comps/src/i18n/comps/index.tsx @@ -13,6 +13,8 @@ export function getEchartsLocale() { switch (locale.language) { case "en": return "EN"; + case "pt": + return "PT"; case "zh": return "ZH"; } @@ -23,6 +25,8 @@ export function getCalendarLocale() { switch (language) { case "zh": return "zh-cn"; + case "pt": + return "pt-br"; default: return "en-gb"; } diff --git a/client/packages/lowcoder-comps/src/i18n/comps/locales/pt.ts b/client/packages/lowcoder-comps/src/i18n/comps/locales/pt.ts new file mode 100644 index 000000000..3b5a5aa4b --- /dev/null +++ b/client/packages/lowcoder-comps/src/i18n/comps/locales/pt.ts @@ -0,0 +1,333 @@ +import {en} from "./en" + +export const pt: typeof en = { + ...en, + calendarChart: { + calendarType: 'Gráfico Estilo Calendário', + title: 'Título', + defaultTitle: 'Gráfico de Calendário', + tooltip: 'Dica', + }, + themeriverChart: { + themeriverType: 'Gráfico Estilo Themeriver', + title: 'Título', + defaultTitle: 'Gráfico Themeriver', + tooltip: 'Dica', + }, + sunburstChart: { + sunburstType: 'Gráfico Estilo Sunburst', + title: 'Título', + defaultTitle: 'Gráfico Sunburst', + tooltip: 'Dica', + }, + treemapChart: { + treemapType: 'Gráfico Estilo Mapa de Árvore', + title: 'Título', + defaultTitle: 'Gráfico Mapa de Árvore', + tooltip: 'Dica', + }, + treeChart: { + treeType: 'Gráfico Estilo Árvore', + title: 'Título', + defaultTitle: 'Gráfico Árvore', + tooltip: 'Dica', + }, + graphChart: { + graphType: 'Gráfico Estilo Gráfico', + title: 'Título', + defaultTitle: 'Gráfico', + tooltip: 'Dica', + }, + heatmapChart: { + heatmapType: 'Gráfico Estilo Mapa de Calor', + title: 'Título', + defaultTitle: 'Gráfico Mapa de Calor', + tooltip: 'Dica', + }, + radarChart: { + radarType: 'Gráfico Estilo Radar', + title: 'Título', + defaultTitle: 'Gráfico Radar', + tooltip: 'Dica', + }, + candleStickChart: { + candleStickType: 'Gráfico Estilo Castiçal', + title: 'Título', + defaultTitle: 'Gráfico Castiçal', + tooltip: 'Dica', + }, + sankeyChart: { + sankeyType: 'Gráfico Estilo Sankey', + title: 'Título', + defaultTitle: 'Gráfico Sankey', + tooltip: 'Dica', + }, + funnelChart: { + title: 'Título', + defaultTitle: 'Gráfico Funil', + funnelType:'Gráfico Estilo Funil', + tooltip: 'Dica', + legendVisibility: 'Visibilidade da Legenda', + left: 'Esquerda', + defaultLeft:'35', + top: 'Superior', + defaultTop:'60', + bottom: 'Inferior', + defaultBottom:'60', + width: 'Largura', + defaultWidth:'80', + min: 'Min', + defaultMin:'0', + max: 'Máx', + defaultMax:'100', + gap: 'Espaço', + defaultGap: '2', + label:'Rótulo', + }, + gaugeChart: { + title: 'Título', + defaultTitle: 'Gráfico Medidor', + gaugeType: 'Gráfico Estilo Medidor', + tooltip: 'Dica', + left: 'Esquerda', + defaultLeft:'35', + top: 'Superior', + defaultTop:'60', + bottom: 'Inferior', + defaultBottom:'60', + width: 'Largura', + defaultWidth:'80', + min: 'Min', + defaultMin:'0', + max: 'Máx', + defaultMax:'100', + gap: 'Espaço', + defaultGap: '2', + label:'Rótulo', + }, + echarts: { + defaultTitle: "Dados Mostrados", + legendPosition: "Posição da Legenda", + labelPosition: "Posição do Rótulo", + titlePosition: "Posição do Título", + }, + chart: { + delete: "Remover", + data: "Dados", + mode: "Modo", + config: "Configuração", + UIMode: "Modo de UI", + chartType: "Tipo de Gráfico", + xAxis: "Eixo X", + chartSeries: "Série do Gráfico", + customSeries: "Série Customizada", + add: "Adicionar", + confirmDelete: "Confirmar Remover: ", + seriesName: "Nome da Série", + dataColumns: "Coluna de Dados", + title: "Título", + tooltip:'Dica', + xAxisDirection: "Direção do Eixo X", + xAxisName: "Nome do Eixo X", + xAxisType: "Tipo do Eixo X", + xAxisTypeTooltip: + "Automaticamente detectado baseado nos dados do eixo X, referência: ", + logBase: "Base Log", + yAxisName: "Nome do Eixo Y", + yAxisType: "Tipo do Eixo Y", + yAxisDataFormat: "Tipo dos Dados do Eixo Y", + yAxisDataFormatTooltip: + "Indica o valor de cada coordenada. Exemplo: '{{value * 100 + \"%\"}}'", + basicBar: "Barra Básica", + stackedBar: "Barra Empilhada", + barType: "Gráfico Estilo Barra", + categoryAxis: "Eixo de Categoria", + valueAxis: "Eixo de Valor", + timeAxis: "Eixo de Tempo", + logAxis: "Eixo de Log", + auto: "Padrão", + legendPosition: "Posição da Legenda", + basicLine: "Linha Básica", + stackedLine: "Linha Empilhada", + areaLine: "Linha de Área", + smooth: "Curva Suave", + lineType: "Gráfic Estilo Linha", + basicPie: "Pizza Básica", + doughnutPie: "Pizza com Furo", + rosePie: "Pizza de Rosa", + pieType: "Gráfico Estilo Pizza", + spending: "Gastos", + budget: "Orçamento", + bar: "Gráfico de Barra", + line: "Gráfico de Linha", + scatter: "Gráfico de Dispersão", + pie: "Gráfico de Pizza", + horizontal: "Horizontal", + vertical: "Vertical", + noData: "Sem Dados", + unknown: "Desconhecido", + select: "Selecionar", + unSelect: "Remover Seleção", + echartsOptionLabel: "Opção", + echartsOptionTooltip: "Opção ECharts", + echartsOptionExamples: "Exemplos ECharts", + echartsMapOptionTooltip: "Opção de Mapas ECharts", + echartsMapOptionExamples: "Exemplos de Mapas ECharts", + selectDesc: "Ativado quando um usuário seleciona parte dos dados do gráfico", + unselectDesc: + "Ativado quando um usuário remove a seleção de parte dos dados do gráfico", + selectedPointsDesc: "Pontos Selecionados", + lastInteractionDataDesc: "Último Dado de Interação", + dataDesc: "Dados JSON para o Gráfico", + titleDesc: "Título Atual do Gráfico", + scatterShape: "Forma da Dispersão", + circle: "Círculo", + rect: "Retângulo", + triangle: "Triângulo", + diamond: "Diamante", + pin: "Pino", + arrow: "Flecha", + pointColorLabel: "Cor do Ponto", + pointColorTooltip: + 'Definir cor do ponto baseado no nome da série e valor. Variáveis: nomeSerie, valor. Exemplo: \'{{valor < 25000 ? "vermelho" : "verde"}}\'', + mapReady: "Mapa Pronto", + mapReadyDesc: "Ativado quando o mapa estiver pronto", + zoomLevelChange: "Mudar Nível de Zoom", + zoomLevelChangeDesc: "Ativado quando o nível de zoom do mapa é trocado", + centerPositionChange: "Trocar Posição Central", + centerPositionChangeDesc: "Ativado quando a posição central do mapa é trocada", + chartEventHandlers: "Manipuladores de Eventos de Gráficos", + }, + imageEditor: { + defaultSrc: "", + save: "Salvar", + saveDesc: "Salvar Imagem", + src: "Origem da Imagem", + name: "Nome da Imagem", + buttonText: "Texto do Botão", + srcDesc: "Origem da Imagem", + nameDesc: "Nome da Imagem", + dataURIDesc: "URI dos Dados da Imagem", + dataDesc: "Dados da Imagem", + buttonTextDesc: "Texto do Botão", + }, + meeting: { + logLevel: "Nível de Log do SDK Agora", + placement: "Posição da Gaventa de Reunião", + meeting: "Configurações da Gaveta", + loadingDesc: "loadingDesc", + cameraView: "Visão da Câmera", + cameraViewDesc: "Visão da Câmera do Usuário Local (Anfitrião)", + screenShared: "Tela Compartilhada", + heightTooltip: "Pixel, ex.: 378", + height: "Altura da Gaveta", + widthTooltip: "Pixel ou Porcentagem, ex.: 520, 60%", + width: "Largura da Gaveta", + screenSharedDesc: "Tela Compartilhada pelo Usuário Local (Anfitrião)", + audioUnmuted: "Áudio Desmutado", + audioMuted: "Áudio Mutado", + videoClicked: "Vídeo Clicado", + showMask: "Mostrar Máscara", + maskClosable: "Clique Fora para Fechar", + videoOff: "Vídeo Desligado", + videoOn: "Vídeo Ligado", + size: "Tamanho", + top: "Superior", + host: "Anfitrião da Sala. Você precisaria gerenciar o anfitrião como própria Lógica de Aplicação", + participants: "Participantes da Sala", + shareScreen: "Mostrar Tela Compartilhada pelo Usuário Local", + appid: "ID de Aplicação Agora", + meetingName: "Nome da Reunião", + localUserID: "ID de Usuário do Anfitrião", + userName: "Nome de Usuário do Anfitrião", + rtmToken: "Agora RTM Token", + rtcToken: "Agora RTC Token", + noVideo: "Sem Vídeo", + profileImageUrl: "URL da Imagem de Perfil", + right: "Direita", + bottom: "Inferior", + videoId: "ID do Stream de Vídeo", + audioStatus: "Status do Áudio", + left: "Esquerda", + openDrawerDesc: "Abrir Gaveta", + closeDrawerDesc: "Fechar Gaveta", + actionBtnDesc: "Botão de Ação", + broadCast: "Emitir Mensagem", + title: "Título da Reunião", + meetingCompName: "Controlador da Reunião Agora", + sharingCompName: "Transmissão do Compartilhamento de Tela", + videoCompName: "Transmissão de Câmera", + videoSharingCompName: "Transmissão de Compartilhemento de Tela", + meetingControlCompName: "Botão de Controle", + meetingCompDesc: "Componente de Reunião", + meetingCompControls: "Controlador de Reunião", + meetingCompKeywords: "Reunião Agora, Reunião Web, Colaboração", + iconSize: "Tamanho do Ícone", + userId: "ID de Usuário do Anfitrião", + roomId: "ID da Sala", + meetingActive: "Reunião Atual", + messages: "Transmistir Mensagem", + }, + calendar: { + events: "Dados de Eventos", + resources: "Recursos", + resourcesDefault: "Salas", + resourcesName: "Nome do Recurso", + resourcesEvents : "Dados dos Recursos de Eventos", + editable: "Editável", + license: "Chave de Ativação", + licenseTooltip: "Busque sua chave de ativação em https://fullcalendar.io/purchase para liberar visualizações premium como Linha do Tempo de Recursos e Grid de Recursos.", + defaultDate: "Data Padrão", + defaultDateTooltip: "Data inicial padrão do calendário", + defaultView: "Visualização Padrão", + defaultViewTooltip: "Visualização inicial do calendário", + showEventTime: "Mostrar Horário dos Eventos", + showEventTimeTooltip: "Mostrar texto dos horários do Evento", + showWeekends: "Mostrar Fim-de-semana", + showAllDay: "Mostrar Dia Inteiro", + showAllDayTooltip: "Exibir o intervalo do dia inteiro nas visualizações semanal e diária", + dayMaxEvents: "Eventos do Dia Máximos", + dayMaxEventsTooltip: "Máximo de eventos por dia na visualização mensal, 0 para limite de altura da célula", + eventMaxStack: "Empilhamento Máximo de Eventos", + eventMaxStackTooltip: "Máximo de eventos para emplilhar horizontalmente na visualização de dias e mês, 0 para não haver limite", + selectInterval: "Intervalo Selecionado", + selectEvent: "Evento Selecionado", + changeSet: "Mudar Objeto de Evento", + headerBtnBackground: "Cor do Botão", + btnText: "Texto do Botão", + title: "Título", + selectBackground: "Selecionar Fundo", + today: "Hoje", + month: "Mês", + week: "Semana", + weekdaygrid : "Dias da Semana", + daygrid : "Lista de Eventos do Dia", + year: "Ano", + day: "Dia", + list: "Lista de Eventos", + timeline: "Linha do Tempo de Recursos", //added by fred + resourceTimeGridDay: "Grid de Recursos", //added by fred + monday: "Segunda-Feira", + tuesday: "Terça-Feira", + wednesday: "Quarta-Feira", + thursday: "Quinta-Feira", + friday: "Sexta-Feira", + saturday: "Sábado", + sunday: "Domingo", + startWeek: "Começar Em", + creatEvent: "Criar Evento", + editEvent: "Editar Evento", + eventName: "Nome do Evento", + eventColor: "Cor do Evento", + eventGroupId: "ID do Grupo", + groupIdTooltip: "ID de grupos de eventos para arrastar e trocar tamanho juntos.", + more: "Mais", + allDay: "Dia Inteiro", + eventNameRequire: "Insira Nome do Evento", + eventId: "ID do Evento", + eventIdRequire: "Insira ID do Evento", + eventIdTooltip: "ID único para cada evento", + eventIdExist: "ID Já Existe", + dragDropEventHandlers: "Manipuladores de Arrastar/Soltar de Eventos", + }, +}; diff --git a/client/packages/lowcoder-comps/src/i18n/comps/locales/ptObj.tsx b/client/packages/lowcoder-comps/src/i18n/comps/locales/ptObj.tsx new file mode 100644 index 000000000..b87a27ce7 --- /dev/null +++ b/client/packages/lowcoder-comps/src/i18n/comps/locales/ptObj.tsx @@ -0,0 +1,400 @@ +import { I18nObjects } from "./types"; +import { chartColorPalette } from "lowcoder-sdk"; + + +const defaultMapData = { + tooltip: { + trigger: "item" + }, + animation: true, + series: [ + { + name: 'População', + type: 'scatter', + coordinateSystem: 'gmap', + itemStyle: { + color: "#00c1de" + }, + data: [ + { "name":"Azerbaijão","value":[47.395,40.43,8352021] }, + { "name":"Albania","value":[20.068,41.143,3153731] }, + { "name":"Armenia","value":[44.563,40.534,3017661] }, + { "name":"Bosnia e Herzegovina","value":[17.786,44.169,3915238] }, + { "name":"Bulgaria","value":[25.231,42.761,7744591] }, + { "name":"Cyprus","value":[33.219,35.043,836321] }, + { "name":"Denmark","value":[9.264,56.058,5416945] }, + { "name":"Ireland","value":[-8.152,53.177,4143294] }, + { "name":"Estonia","value":[25.793,58.674,1344312] }, + { "name":"Áustria","value":[14.912,47.683,8291979] }, + { "name":"República Checa","value":[15.338,49.743,10191762] }, + { "name":"Finlândia","value":[26.272,64.504,5246004] }, + { "name":"França","value":[2.55,46.565,60990544] }, + { "name":"Georgia","value":[43.518,42.176,4473409] }, + { "name":"Alemanha","value":[9.851,51.11,82652369] }, + { "name":"Grécia","value":[21.766,39.666,11099737] }, + { "name":"Croácia","value":[16.693,45.723,455149] }, + { "name":"Hungria","value":[19.134,47.07,10086387] }, + { "name":"Islândia","value":[-18.48,64.764,295732] }, + { "name":"Israel","value":[34.851,31.026,6692037] }, + { "name":"Itália","value":[12.8,42.7,5864636] }, + { "name":"Látvia","value":[25.641,56.858,2301793] }, + { "name":"Belarus","value":[28.047,53.54,9795287] }, + { "name":"Lituânia","value":[23.897,55.336,3425077] }, + { "name":"Slovakia","value":[19.491,48.707,5386995] }, + { "name":"Liechtenstein","value":[9.555,47.153,34598] }, + { "name":"Macedonia","value":[21.698,41.6,2033655] }, + { "name":"Malta","value":[14.442,35.89,402617] }, + { "name":"Bélgica","value":[4.664,50.643,10398049] }, + { "name":"Ilhas Faroe","value":[-6.864,62.05,48205] }, + { "name":"Andorra","value":[1.576,42.549,73483] }, + { "name":"Luxemburgo","value":[6.088,49.771,456613] }, + { "name":"Mônaco","value":[7.412,43.75,325] }, + { "name":"Montenegro","value":[19.254,42.792,607969] }, + { "name":"Holanda","value":[5.389,52.077,1632769] }, + { "name":"Noruega","value":[8.74,61.152,4638836] }, + { "name":"Polônia","value":[19.401,52.125,38195558] }, + { "name":"Portugal","value":[-8.058,40.309,10528226] }, + { "name":"Romania","value":[24.969,45.844,21627557] }, + { "name":"Moldova","value":[28.599,47.193,3876661] }, + { "name":"Eslovenia","value":[14.827,46.124,1999425] }, + { "name":"Espanha","value":[-3.649,40.227,43397491] }, + { "name":"Suécia","value":[15.27,62.011,9038049] }, + { "name":"Suíça","value":[7.908,46.861,7424389] }, + { "name":"Turquia","value":[35.179,39.061,72969723] }, + { "name":"Reino Unido","value":[-1.6,53,60244834] }, + { "name":"Ucrânia","value":[31.388,49.016,46917544] }, + { "name":"São Marino","value":[12.46,43.942,30214] }, + { "name":"Sérbia","value":[20.806,44.032,9863026] }, + { "name":"Cidade do Vaticano","value":[12.451,41.904,783] }, + { "name":"Rússia","value":[96.689,61.988,143953092]} + ], + encode: { + value: 2, + lng: 0, + lat: 1 + } + } + ] +} + +export const enObj: I18nObjects = { + defaultDataSource: [ + { + date: "2021-09", + department: "Administração", + spending: 9003, + budget: 8000, + }, + { + date: "2021-09", + department: "Finanças", + spending: 3033, + budget: 4000, + }, + { + date: "2021-09", + department: "Vendas", + spending: 9230, + budget: 8000, + }, + { + date: "2021-10", + department: "Administração", + spending: 13032, + budget: 15000, + }, + { + date: "2021-10", + department: "Finanças", + spending: 2300, + budget: 5000, + }, + { + date: "2021-10", + department: "Vendas", + spending: 7323.5, + budget: 8000, + }, + { + date: "2021-11", + department: "Administração", + spending: 13000, + budget: 16023, + }, + { + date: "2021-11", + department: "Finanças", + spending: 3569.5, + budget: 3000, + }, + { + date: "2021-11", + department: "Vendas", + spending: 10000, + budget: 9932, + }, + { + date: "2021-12", + department: "Administração", + spending: 18033, + budget: 20000, + }, + { + date: "2021-12", + department: "Finanças", + spending: 4890, + budget: 4500, + }, + { + date: "2021-12", + department: "Vendas", + spending: 9322, + budget: 8000, + }, + ], + + defaultEchartsJsonOption: { + data: [ + { value: 100, name: "Mostrar",color:'#fc8452' }, + { value: 80, name: "Clicar" ,color:'#9a60b4'}, + { value: 60, name: "Visitar" ,color:'#fac858'}, + { value: 40, name: "Query" ,color:'#ee6666'}, + { value: 20, name: "Comprar" ,color:'#3ba272'}, + ], + }, + defaultFunnelChartOption: { + data: [ + { value: 100, name: "Mostrar",color:'#fc8452' }, + { value: 80, name: "Clicar" ,color:'#9a60b4'}, + { value: 60, name: "Visitar" ,color:'#fac858'}, + { value: 40, name: "Query" ,color:'#ee6666'}, + { value: 20, name: "Comprar" ,color:'#3ba272'}, + ], + }, + defaultGaugeChartOption: { + data: [ + { value: 60, name: "Completed",color:'#fc8452' } + ] + }, + defaultSankeyChartOption: { + data: [ + {name: "Mostrar"}, + {name: "Clicar"}, + {name: "Visitar"}, + {name: "Query"}, + {name: "Comprar"} + ], + links: [ + {source: "Mostrar", target: "Clicar", value: 80}, + {source: "Clicar", target: "Visitar", value: 60}, + {source: "Visitar", target: "Query", value: 40}, + {source: "Query", target: "Comprar", value: 20} + ] + }, + defaultCandleStickChartOption: { + xAxis: { + data: ["Dia 1", "Dia 2", "Dia 3", "Dia 4", "Dia 5"] + }, + data:[ + [100, 200, 50, 150], + [120, 220, 80, 180], + [80, 150, 60, 130], + [130, 230, 110, 190], + [90, 180, 70, 160] + ] + }, + defaultRadarChartOption: { + indicator: [ + { name: "Indicador 1", max: 100 }, + { name: "Indicador 2", max: 100 }, + { name: "Indicador 3", max: 100 }, + { name: "Indicador 4", max: 100 }, + { name: "Indicador 5", max: 100 } + ], + series: [ + { + "name": "Dado 1", + "data": [ + { + "value": [90, 80, 70, 60, 50], + "name": "Dado 1" + } + ] + }, + { + "name": "Dado 2", + "data": [ + { + "value": [70, 60, 50, 40, 30], + "name": "Dado 2" + } + ] + } + ] + }, + defaultHeatmapChartOption: { + xAxis: { + "data": ["Segunda-Feira", "Terça-Feira", "Quarta-Feira", "Quinta-Feira", "Sexta-Feira", "Sábado", "Domingo"] + }, + yAxis: { + "data": ["Manhã", "Tarde", "Noite"] + }, + data: [ + [0, 0, 10], + [0, 1, 20], + [0, 2, 30], + [1, 0, 40], + [1, 1, 50], + [1, 2, 60], + [2, 0, 70], + [2, 1, 80], + [2, 2, 90], + [3, 0, 100], + [3, 1, 90], + [3, 2, 80], + [4, 0, 70], + [4, 1, 60], + [4, 2, 50], + [5, 0, 40], + [5, 1, 30], + [5, 2, 20], + [6, 0, 10], + [6, 1, 0], + [6, 2, 10] + ] + }, + defaultGraphChartOption: { + categories: [ + {name: "Módulos"}, + {name: "Bordas"} + ], + nodes: [ + {name: "Módulo 1", category: 0}, + {name: "Módulo 2", category: 0}, + {name: "Módulo 3", category: 0} + ], + links: [ + {source: "Módulo 1", target: "Módulo 2", category: 1}, + {source: "Módulo 2", target: "Módulo 3", category: 1} + ] + }, + defaultTreeChartOption: { + data: [{ + name: "Parent", + children: [ + { + name: "Child 1", + children: [ + { name: "Child 1-1" }, + { name: "Child 1-2" } + ] + }, + { + name: "Child 2", + children: [ + { name: "Child 2-1" }, + { name: "Child 2-2" } + ] + } + ] + }] + }, + defaultTreemapChartOption: { + data: [ + { + name: 'nodeA', + value: 10, + children: [ + { + name: 'nodeAa', + value: 4, + }, + { + name: 'nodeAb', + value: 6 + } + ] + }, + { + name: 'nodeB', + value: 20, + children: [ + { + name: 'nodeBa', + value: 20, + children: [ + { + name: 'nodeBa1', + value: 20 + } + ] + } + ] + } + ] + }, + defaultSunburstChartOption: { + data: [ + { + name: "Avô", + children: [ + { + name: "Pai A", + children: [ + {name: "Filho A1", value: 10}, + {name: "Filho A2", value: 20} + ] + }, + { + name: "Pai B", + children: [ + {name: "Filho B1", value: 15}, + {name: "Filho B2", value: 25} + ] + } + ] + } + ] + }, + defaultCalendarChartOption: { + data:[ + ["2022-01-01", 10], + ["2022-02-05", 30], + ["2022-03-15", 50], + ["2022-04-20", 70], + ["2022-05-25", 90], + ["2022-06-30", 100], + ["2022-07-10", 80], + ["2022-08-20", 60], + ["2022-09-25", 40], + ["2022-10-30", 20], + ["2022-11-05", 5] + ] + }, + defaultThemeriverChartOption: { + data: [ + ["2024-01-01", 10, "Categoria A"], + ["2024-01-02", 15, "Categoria A"], + ["2024-01-03", 20, "Categoria A"], + ["2024-01-04", 25, "Categoria A"], + ["2024-01-05", 30, "Categoria A"], + ["2024-01-06", 35, "Categoria A"], + ["2024-01-07", 40, "Categoria A"], + ["2024-01-08", 45, "Categoria A"], + ["2024-01-09", 50, "Categoria A"], + ["2024-01-10", 55, "Categoria A"], + ["2024-01-01", 15, "Categoria B"], + ["2024-01-02", 20, "Categoria B"], + ["2024-01-03", 25, "Categoria B"], + ["2024-01-04", 30, "Categoria B"], + ["2024-01-05", 35, "Categoria B"], + ["2024-01-06", 40, "Categoria B"], + ["2024-01-07", 45, "Categoria B"], + ["2024-01-08", 50, "Categoria B"], + ["2024-01-09", 55, "Categoria B"], + ["2024-01-10", 60, "Categoria B"] + ] + }, + + defaultMapJsonOption: defaultMapData, +}; diff --git a/client/packages/lowcoder-core/src/i18n/locales/index.ts b/client/packages/lowcoder-core/src/i18n/locales/index.ts index a43758e20..802214859 100644 --- a/client/packages/lowcoder-core/src/i18n/locales/index.ts +++ b/client/packages/lowcoder-core/src/i18n/locales/index.ts @@ -3,3 +3,4 @@ export * from "./en"; export * from "./zh"; export * from "./de"; +export * from "./pt"; diff --git a/client/packages/lowcoder-core/src/i18n/locales/pt.ts b/client/packages/lowcoder-core/src/i18n/locales/pt.ts new file mode 100644 index 000000000..1801bc9ca --- /dev/null +++ b/client/packages/lowcoder-core/src/i18n/locales/pt.ts @@ -0,0 +1,3 @@ +import { en } from "./en"; + +export const pt: typeof en = {}; \ No newline at end of file diff --git a/client/packages/lowcoder-design/src/components/Section.tsx b/client/packages/lowcoder-design/src/components/Section.tsx index cad6e8bf0..92fc4f3f3 100644 --- a/client/packages/lowcoder-design/src/components/Section.tsx +++ b/client/packages/lowcoder-design/src/components/Section.tsx @@ -4,6 +4,7 @@ import styled from "styled-components"; import { ReactComponent as Packup } from "icons/icon-Pack-up.svg"; import { labelCss } from "./Label"; import { controlItem, ControlNode } from "./control"; +import { Tooltip } from "./toolTip"; const SectionItem = styled.div<{ $width?: number }>` width: ${(props) => (props.$width ? props.$width : 312)}px; @@ -73,6 +74,12 @@ const ShowChildren = styled.div<{ $show?: string; $noMargin?: boolean }>` padding-right: ${(props) => (props.$noMargin ? 0 : "16px")}; `; +const TooltipWrapper = styled.span` + word-wrap: break-word; + word-break: break-word; + white-space: pre-wrap; + color:#fff; +`; interface ISectionConfig { name?: string; open?: boolean; @@ -81,6 +88,7 @@ interface ISectionConfig { style?: React.CSSProperties; children: T; additionalButton?: React.ReactNode; + hasTooltip?: boolean; } export interface PropertySectionState { @@ -102,7 +110,7 @@ export const PropertySectionContext = React.createContext) => { - const { name } = props; + const { name,hasTooltip } = props; const { compName, state, toggle } = useContext(PropertySectionContext); const open = props.open !== undefined ? props.open : name ? state[compName]?.[name] !== false : true; @@ -118,17 +126,35 @@ export const BaseSection = (props: ISectionConfig) => { return ( {props.name && ( - + {props.name} -
+
{open && props.additionalButton} - +
)} - - {props.children} - + + Here you can enter the animation type codes. Like bounce, swing or + tada. Read more about all possible codes at:{" "} + https://animate.style + + ) + } + arrow={{ + pointAtCenter: true, + }} + placement="top" + color="#2c2c2c" + getPopupContainer={(node: any) => node.closest('.react-grid-item')} + > + + {props.children} + + ); }; @@ -146,6 +172,7 @@ export const sectionNames = { layout: trans("prop.layout"), style: trans("prop.style"), labelStyle:trans("prop.labelStyle"), + animationStyle:trans("prop.animationStyle"), data: trans("prop.data"), meetings: trans("prop.meetings"), // added by Falk Wolsky field: trans("prop.field"), @@ -157,4 +184,5 @@ export const sectionNames = { headerStyle:trans("prop.headerStyle"), bodyStyle:trans("prop.bodyStyle"), badgeStyle:trans("prop.badgeStyle"), + columnStyle:trans("prop.columnStyle"), }; diff --git a/client/packages/lowcoder-design/src/components/control.tsx b/client/packages/lowcoder-design/src/components/control.tsx index e8f1f4ca1..a25f9df8b 100644 --- a/client/packages/lowcoder-design/src/components/control.tsx +++ b/client/packages/lowcoder-design/src/components/control.tsx @@ -164,7 +164,8 @@ export const ControlPropertyViewWrapper = ( )} {preInputNode} - + {/* margin and padding are calculated differently so they're made equal */} + {children} {extraChildren} diff --git a/client/packages/lowcoder-design/src/i18n/design/locales/en.ts b/client/packages/lowcoder-design/src/i18n/design/locales/en.ts index b15621be1..99fd5ceef 100644 --- a/client/packages/lowcoder-design/src/i18n/design/locales/en.ts +++ b/client/packages/lowcoder-design/src/i18n/design/locales/en.ts @@ -23,6 +23,7 @@ export const en = { advanced: "Advanced", validation: "Validation", layout: "Layout", + animationStyle:"Animation Style", labelStyle: "Label Style", style: "Style", meetings: "Meeting Settings", @@ -36,6 +37,7 @@ export const en = { headerStyle: 'Header Style', bodyStyle: 'Body Style', badgeStyle: 'Badge Style', + columnStyle: 'Column Style', }, passwordInput: { label: "Password:", diff --git a/client/packages/lowcoder-design/src/i18n/design/locales/index.ts b/client/packages/lowcoder-design/src/i18n/design/locales/index.ts index dbf19146b..a7ba5832c 100644 --- a/client/packages/lowcoder-design/src/i18n/design/locales/index.ts +++ b/client/packages/lowcoder-design/src/i18n/design/locales/index.ts @@ -2,4 +2,5 @@ // fallback example: current locale is zh-HK, fallback order is zhHK => zh => en export * from "./en"; export * from "./zh"; -export * from "./de"; \ No newline at end of file +export * from "./de"; +export * from "./pt" \ No newline at end of file diff --git a/client/packages/lowcoder-design/src/i18n/design/locales/pt.ts b/client/packages/lowcoder-design/src/i18n/design/locales/pt.ts new file mode 100644 index 000000000..846faa31d --- /dev/null +++ b/client/packages/lowcoder-design/src/i18n/design/locales/pt.ts @@ -0,0 +1,90 @@ +import {en} from "./en"; + +export const pt: typeof en = { + ...en, + addItem: "Adicionar", + duplicate: "Duplicar", + rename: "Renomear", + delete: "Deletar", + edit: "Editar", + ok: "OK", + cancel: "Cancelar", + previousStep: "Anterior", + nextStep: "Próximo", + finish: "Finalizar", + country: { + ...en.country, + china: "China", + }, + notification: { + ...en.notification, + copySuccess: "Sucesso ao Copiar", + copyFail: "Falha ao Copiar", + }, + prop: { + ...en.prop, + basic: "Básico", + resources: "Recursos", + interaction: "Interação", + advanced: "Avançado", + validation: "Validação", + layout: "Layout", + labelStyle: "Estilo do Rótulo", + style: "Estilo", + meetings: "Configurações da Reunião", + data: "Dados", + field: 'Campo', + inputFieldStyle: 'Estilo do Campo de Entrada', + avatarStyle: 'Estilo do Avatar', + captionStyle: 'Estilo da Legenda', + startButtonStyle: 'Estilo do Botão de Começar', + resetButtonStyle: 'Estilo do Botão de Resetar', + headerStyle: 'Estilo do Cabeçalho', + bodyStyle: 'Estilo do Corpo', + badgeStyle: 'Estilo do Emblema', + }, + passwordInput: { + ...en.passwordInput, + label: "Senha:", + placeholder: "Insira sua senha", + inconsistentPassword: "As duas senhas não são iguais", + confirmPasswordLabel: "Confirme a senha:", + confirmPasswordPlaceholder: "Por favor insira a senha novamente", + }, + verifyCodeInput: { + ...en.verifyCodeInput, + label: "Código de verificação:", + errorMsg: "O código deve ter {digitNum} digitos", + placeholder: "Por favor insira {digitNum} digitos", + sendCode: "Enviar Código", + }, + iconSelect: { + ...en.iconSelect, + title: "Selecionar Ícone", + searchPlaceholder: "Pesquisar Ícone", + }, + shapeSelect: { + ...en.shapeSelect, + title: "Selecionar Forma", + searchPlaceholder: "Pesquisar Forma", + }, + eventHandler: { + ...en.eventHandler, + advanced: "Avançado", + }, + comp: { + ...en.comp, + selectedCompsTitle: "{selectCompNum} componentes selecionados", + selectedCompsDetail: "Clique no componente para ver suas propriedades", + batchDelete: "Deletar em massa", + }, + optionsControl: { + ...en.optionsControl, + optionItemErrorMSg: `Opção de valor encontrada duplicada "{value}". Somente o primeiro item será mostrado. Por favor, troque para um valor único.`, + emptyList: "Sem opções", + }, + container: { + ...en.container, + hintPlaceHolder: "Arraste componentes do painel da direita", + }, +}; diff --git a/client/packages/lowcoder-design/src/i18n/design/locales/zh.ts b/client/packages/lowcoder-design/src/i18n/design/locales/zh.ts index 9b9d6a742..d1567e624 100644 --- a/client/packages/lowcoder-design/src/i18n/design/locales/zh.ts +++ b/client/packages/lowcoder-design/src/i18n/design/locales/zh.ts @@ -1,4 +1,7 @@ -export const zh = { +import {en} from "./en"; + +export const zh: typeof en = { + ...en, addItem: "添加", duplicate: "复制", rename: "重命名", @@ -10,25 +13,29 @@ export const zh = { nextStep: "下一步", finish: "完成", country: { - china: "中国", + ...en.country, + china: "中国", }, notification: { - copySuccess: "复制成功", - copyFail: "复制失败", + ...en.notification, + copySuccess: "复制成功", + copyFail: "复制失败", }, prop: { - basic: "基础", - resources: "资源", - interaction: "交互", - advanced: "高级", - validation: "验证", - layout: "布局", - labelStyle:"标签样式", - style: "样式", - meetings: "会议", - data: "数据", + ...en.prop, + basic: "基础", + resources: "资源", + interaction: "交互", + advanced: "高级", + validation: "验证", + layout: "布局", + labelStyle:"标签样式", + style: "样式", + meetings: "会议", + data: "数据", }, passwordInput: { + ...en.passwordInput, label: "密码:", placeholder: "请输入密码", inconsistentPassword: "两次密码输入不一致", @@ -36,28 +43,34 @@ export const zh = { confirmPasswordPlaceholder: "请再次输入密码", }, verifyCodeInput: { + ...en.verifyCodeInput, label: "验证码:", errorMsg: "验证码应为 {digitNum} 位数字", placeholder: "请输入 {digitNum} 位数字验证码", sendCode: "发送验证码", }, iconSelect: { + ...en.iconSelect, title: "选择图标", searchPlaceholder: "搜索图标", }, eventHandler: { + ...en.eventHandler, advanced: "高级", }, comp: { + ...en.comp, selectedCompsTitle: "已选择 {selectCompNum} 个组件", selectedCompsDetail: "点击组件查看其属性", batchDelete: "批量删除", }, optionsControl: { + ...en.optionsControl, optionItemErrorMSg: `发现重复的选项值 "{value}",只会显示第一项,请更改为唯一值.`, emptyList: "无选项", }, container: { + ...en.container, hintPlaceHolder: "从右侧面板拖动组件", }, }; diff --git a/client/packages/lowcoder-design/src/icons/index.ts b/client/packages/lowcoder-design/src/icons/index.ts index bac14e692..18aab7063 100644 --- a/client/packages/lowcoder-design/src/icons/index.ts +++ b/client/packages/lowcoder-design/src/icons/index.ts @@ -125,6 +125,7 @@ export { ReactComponent as InviteUserIcon } from "./icon-application-invite-user export { ReactComponent as HomeEmptyIcon } from "./icon-application-empty.svg"; export { ReactComponent as HomeListIcon } from "./icon-application-list.svg"; export { ReactComponent as HomeCardIcon } from "./icon-application-card.svg"; +export { ReactComponent as APIDocsIcon } from "./remix/instance-line.svg"; // export { ReactComponent as AllAppIcon } from "./icon-all-app.svg"; @@ -161,6 +162,10 @@ export { ReactComponent as ResetIcon } from "./icon-style-reset.svg"; export { ReactComponent as EditIcon } from "./icon-edit.svg"; export { ReactComponent as EditableIcon } from "./icon-editable.svg"; export { ReactComponent as LeftStateIcon } from "./remix/node-tree.svg"; +export {ReactComponent as StarSmileIcon} from "./remix/star-smile-line.svg"; +export {ReactComponent as Timer2Icon} from "./remix/timer-2-line.svg"; +export {ReactComponent as TimerFlashIcon} from "./remix/timer-flash-line.svg"; +export {ReactComponent as RefreshLineIcon} from "./remix/refresh-line.svg"; export { ReactComponent as LeftSettingIcon } from "./remix/tools-fill.svg"; export { ReactComponent as LeftLayersIcon } from "./remix/stack-line.svg"; export { ReactComponent as LeftHelpIcon } from "./icon-left-help.svg"; @@ -259,6 +264,7 @@ export { ReactComponent as ChartCompIconSmall } from "./v2/pie-chart-s.svg"; export { ReactComponent as CheckboxCompIconSmall } from "./v2/checkbox-s.svg"; export { ReactComponent as ColorPickerCompIconSmall } from "./v2/colorpicker-s.svg"; // new export { ReactComponent as CollapsibleContainerCompIconSmall } from "./v2/collapsible-container-s.svg"; // new +export { ReactComponent as ColumnLayoutCompIconSmall } from "./v2/column-layout-s.svg"; // new export { ReactComponent as CommentCompIconSmall } from "./v2/comment-s.svg"; export { ReactComponent as ContainerCompIconSmall } from "./v2/container-s.svg"; export { ReactComponent as CustomCompIconSmall } from "./v2/custom-code-s.svg"; // new @@ -360,6 +366,7 @@ export { ReactComponent as CascaderCompIcon } from "./v2/cascader-m.svg"; export { ReactComponent as ChartCompIcon } from "./v2/pie-chart-m.svg"; export { ReactComponent as CheckboxCompIcon } from "./v2/checkbox-m.svg"; export { ReactComponent as CollapsibleContainerCompIcon } from "./v2/collapsible-container-m.svg"; +export { ReactComponent as ColumnLayoutCompIcon } from "./v2/column-layout-m.svg"; export { ReactComponent as CommentCompIcon } from "./v2/comment-m.svg"; export { ReactComponent as ColorPickerCompIcon } from "./v2/colorpicker-m.svg"; export { ReactComponent as ContainerCompIcon } from "./v2/container-m.svg"; diff --git a/client/packages/lowcoder-sdk/package.json b/client/packages/lowcoder-sdk/package.json index d269e29e3..2c3ffb289 100644 --- a/client/packages/lowcoder-sdk/package.json +++ b/client/packages/lowcoder-sdk/package.json @@ -1,6 +1,6 @@ { "name": "lowcoder-sdk", - "version": "2.4.3", + "version": "2.4.4", "type": "module", "files": [ "src", diff --git a/client/packages/lowcoder/package.json b/client/packages/lowcoder/package.json index 62560576b..69c5e2817 100644 --- a/client/packages/lowcoder/package.json +++ b/client/packages/lowcoder/package.json @@ -36,6 +36,7 @@ "@types/react-signature-canvas": "^1.0.2", "@types/react-test-renderer": "^18.0.0", "@types/react-virtualized": "^9.21.21", + "animate.css": "^4.1.1", "antd": "5.13.2", "axios": "^1.6.2", "buffer": "^6.0.3", @@ -127,6 +128,7 @@ "vite-plugin-checker": "^0.5.1", "vite-plugin-dynamic-import": "^1.5.0", "vite-plugin-html": "^3.2.0", + "vite-plugin-node-polyfills": "^0.22.0", "vite-plugin-svgr": "^2.2.2", "vite-tsconfig-paths": "^3.6.0" } diff --git a/client/packages/lowcoder/site.webmanifest b/client/packages/lowcoder/site.webmanifest index 91352b1a9..c445421d9 100644 --- a/client/packages/lowcoder/site.webmanifest +++ b/client/packages/lowcoder/site.webmanifest @@ -1 +1 @@ -{"name":"Lowcoder.cloud","short_name":"Lowcoder","icons":[{"src":"/android-chrome-192x192.png","sizes":"192x192","type":"image/png"},{"src":"/android-chrome-512x512.png","sizes":"512x512","type":"image/png"}],"theme_color":"#ffffff","background_color":"#ffffff","display":"standalone"} +{"name":"Lowcoder.cloud","short_name":"Lowcoder","icons":[{"src":"/android-chrome-192x192.png","sizes":"192x192","type":"image/png"},{"src":"/android-chrome-512x512.png","sizes":"512x512","type":"image/png"}],"theme_color":"#b480de","background_color":"#ffffff","display":"standalone"} \ No newline at end of file diff --git a/client/packages/lowcoder/src/api/apiUtils.ts b/client/packages/lowcoder/src/api/apiUtils.ts index 826ae90ed..cb578fbef 100644 --- a/client/packages/lowcoder/src/api/apiUtils.ts +++ b/client/packages/lowcoder/src/api/apiUtils.ts @@ -121,10 +121,13 @@ export const apiFailureResponseInterceptor = (error: any) => { // Need authorization if (!notAuthRequiredPath(error.config?.url)) { if (error.response.status === API_STATUS_CODES.REQUEST_NOT_AUTHORISED) { + // get x-org-id from failed request + const organizationId = error.response.headers['x-org-id'] || undefined; // Redirect to login and set a redirect url. StoreRegistry.getStore().dispatch( logoutAction({ notAuthorised: true, + organizationId, }) ); return Promise.reject({ diff --git a/client/packages/lowcoder/src/api/commonSettingApi.ts b/client/packages/lowcoder/src/api/commonSettingApi.ts index 48a17cc2a..135794440 100644 --- a/client/packages/lowcoder/src/api/commonSettingApi.ts +++ b/client/packages/lowcoder/src/api/commonSettingApi.ts @@ -44,10 +44,17 @@ export interface ThemeDetail { primarySurface: string; // comp bg-color borderRadius: string; chart?: string; - margin?: string; + margin?: string; padding?: string; gridColumns?: string; //Added By Aqib Mirza textSize?: string; + animation?: string; + animationDelay?: string; + animationDuration?: string; + opacity?: string; + boxShadow?: string; + boxShadowColor?: string; + animationIterationCount?: string; } export function getThemeDetailName(key: keyof ThemeDetail) { diff --git a/client/packages/lowcoder/src/app.tsx b/client/packages/lowcoder/src/app.tsx index d252efcd2..1e9b5ebb1 100644 --- a/client/packages/lowcoder/src/app.tsx +++ b/client/packages/lowcoder/src/app.tsx @@ -27,8 +27,8 @@ import { ADMIN_APP_URL, ORG_AUTH_FORGOT_PASSWORD_URL, ORG_AUTH_RESET_PASSWORD_URL, + API_DOCS_URL, } from "constants/routesURL"; - import React from "react"; import { createRoot } from "react-dom/client"; import { Helmet } from "react-helmet"; @@ -123,10 +123,43 @@ class AppIndex extends React.Component { {{this.props.brandName}} {} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {/* }, */} + + {isLowCoderDomain && [ // Adding Support for iframely to be able to embedd the component explorer in the docu - , - , + , + , + , , , @@ -176,6 +209,7 @@ class AppIndex extends React.Component { SETTING, MARKETPLACE_URL, ADMIN_APP_URL, + API_DOCS_URL, ]} // component={ApplicationListPage} component={LazyApplicationHome} @@ -189,7 +223,6 @@ class AppIndex extends React.Component { - {developEnv() && ( <> diff --git a/client/packages/lowcoder/src/appView/AppViewInstance.tsx b/client/packages/lowcoder/src/appView/AppViewInstance.tsx index 90942c946..59d333cc4 100644 --- a/client/packages/lowcoder/src/appView/AppViewInstance.tsx +++ b/client/packages/lowcoder/src/appView/AppViewInstance.tsx @@ -14,6 +14,8 @@ import { saveAuthSearchParams } from "pages/userAuth/authUtils"; import { Suspense, lazy } from "react"; import Flex from "antd/es/flex"; import { TacoButton } from "components/button"; +import { DatasourceApi } from "@lowcoder-ee/api/datasourceApi"; +import { registryDataSourcePlugin } from "@lowcoder-ee/constants/queryConstants"; const AppView = lazy( () => import('./AppView') @@ -101,6 +103,12 @@ export class AppViewInstance { }; } }); + + await DatasourceApi.fetchJsDatasourceByApp(this.appId).then((res) => { + res.data.data.forEach((i) => { + registryDataSourcePlugin(i.type, i.id, i.pluginDefinition); + }); + }); setGlobalSettings({ orgCommonSettings: data.data.orgCommonSettings, diff --git a/client/packages/lowcoder/src/assets/images/android-chrome-192x192.png b/client/packages/lowcoder/src/assets/images/android-chrome-192x192.png index 23d6e525e..cc961521b 100644 Binary files a/client/packages/lowcoder/src/assets/images/android-chrome-192x192.png and b/client/packages/lowcoder/src/assets/images/android-chrome-192x192.png differ diff --git a/client/packages/lowcoder/src/assets/images/android-chrome-512x512.png b/client/packages/lowcoder/src/assets/images/android-chrome-512x512.png index c690d113c..f2be2bb72 100644 Binary files a/client/packages/lowcoder/src/assets/images/android-chrome-512x512.png and b/client/packages/lowcoder/src/assets/images/android-chrome-512x512.png differ diff --git a/client/packages/lowcoder/src/assets/images/apple-touch-icon.png b/client/packages/lowcoder/src/assets/images/apple-touch-icon.png index 6fff652aa..1d4ffb43b 100644 Binary files a/client/packages/lowcoder/src/assets/images/apple-touch-icon.png and b/client/packages/lowcoder/src/assets/images/apple-touch-icon.png differ diff --git a/client/packages/lowcoder/src/assets/images/favicon-16x16.png b/client/packages/lowcoder/src/assets/images/favicon-16x16.png index a87cf442d..617bd92d9 100644 Binary files a/client/packages/lowcoder/src/assets/images/favicon-16x16.png and b/client/packages/lowcoder/src/assets/images/favicon-16x16.png differ diff --git a/client/packages/lowcoder/src/assets/images/favicon-32x32.png b/client/packages/lowcoder/src/assets/images/favicon-32x32.png index 127dc44cb..3ab16e28f 100644 Binary files a/client/packages/lowcoder/src/assets/images/favicon-32x32.png and b/client/packages/lowcoder/src/assets/images/favicon-32x32.png differ diff --git a/client/packages/lowcoder/src/assets/images/favicon.ico b/client/packages/lowcoder/src/assets/images/favicon.ico index 91f1543d0..ac2130fd5 100644 Binary files a/client/packages/lowcoder/src/assets/images/favicon.ico and b/client/packages/lowcoder/src/assets/images/favicon.ico differ diff --git a/client/packages/lowcoder/src/assets/images/index.tsx b/client/packages/lowcoder/src/assets/images/index.tsx index c40310d6f..be83253fa 100644 --- a/client/packages/lowcoder/src/assets/images/index.tsx +++ b/client/packages/lowcoder/src/assets/images/index.tsx @@ -1,5 +1,5 @@ //window.matchMedia && window.matchMedia("(prefers-color-scheme: dark)").matches -import { ReactComponent as LogoIcon } from "./logo-with-name-home.svg"; +import { ReactComponent as LogoIcon } from "./Lowcoder-Logo.svg"; import { ReactComponent as LogoWithNameIcon } from "./logo-with-name-home.svg"; import { ReactComponent as LogoHomeIcon } from "./logo-with-name-home.svg"; diff --git a/client/packages/lowcoder/src/assets/images/marketplaceHeaderImage.jpg b/client/packages/lowcoder/src/assets/images/marketplaceHeaderImage.jpg deleted file mode 100644 index a4eeb5714..000000000 Binary files a/client/packages/lowcoder/src/assets/images/marketplaceHeaderImage.jpg and /dev/null differ diff --git a/client/packages/lowcoder/src/components/JSLibraryModal.tsx b/client/packages/lowcoder/src/components/JSLibraryModal.tsx index 64a4941f8..edbc8f547 100644 --- a/client/packages/lowcoder/src/components/JSLibraryModal.tsx +++ b/client/packages/lowcoder/src/components/JSLibraryModal.tsx @@ -341,6 +341,9 @@ export function JSLibraryModal(props: JSLibraryModalProps) { )} + + {trans("preLoad.externalLibsHelperText")} +
); diff --git a/client/packages/lowcoder/src/components/table/EditableCell.tsx b/client/packages/lowcoder/src/components/table/EditableCell.tsx index 388d37e1b..936f1a047 100644 --- a/client/packages/lowcoder/src/components/table/EditableCell.tsx +++ b/client/packages/lowcoder/src/components/table/EditableCell.tsx @@ -84,12 +84,14 @@ export function EditableCell(props: EditableCellProps) { useEffect(() => { setTmpValue(value); }, [value]); + const onChange = useCallback( (value: T) => { setTmpValue(value); }, [setTmpValue] ); + const onChangeEnd = useCallback(() => { setIsEditing(false); dispatch( @@ -127,12 +129,21 @@ export function EditableCell(props: EditableCellProps) { textOverflow={props.textOverflow} > {status === "toSave" && !isEditing && } -
- {normalView} -
+ {normalView} + {/* overlay on normal view to handle double click for editing */} + {editable && ( +
+
+ )} ); } diff --git a/client/packages/lowcoder/src/components/table/columnTypeView.tsx b/client/packages/lowcoder/src/components/table/columnTypeView.tsx index 645c0764e..264db7af8 100644 --- a/client/packages/lowcoder/src/components/table/columnTypeView.tsx +++ b/client/packages/lowcoder/src/components/table/columnTypeView.tsx @@ -4,6 +4,7 @@ import styled from "styled-components"; const ColumnTypeViewWrapper = styled.div<{ $textOverflow?: boolean }>` + position: relative; ${props => !props.$textOverflow && ` div { overflow: hidden; diff --git a/client/packages/lowcoder/src/comps/comps/autoCompleteComp/autoCompleteComp.tsx b/client/packages/lowcoder/src/comps/comps/autoCompleteComp/autoCompleteComp.tsx index ae6fb9457..c310f9d19 100644 --- a/client/packages/lowcoder/src/comps/comps/autoCompleteComp/autoCompleteComp.tsx +++ b/client/packages/lowcoder/src/comps/comps/autoCompleteComp/autoCompleteComp.tsx @@ -3,6 +3,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, @@ -15,7 +16,7 @@ import { withExposingConfigs, } from "comps/generators/withExposing"; import styled, { css } from "styled-components"; -import { UICompBuilder } from "../../generators"; +import { UICompBuilder, withDefault } from "../../generators"; import { FormDataPropertyView } from "../formComp/formDataConstants"; import { jsonControl } from "comps/controls/codeControl"; import { dropdownControl } from "comps/controls/dropdownControl"; @@ -57,7 +58,8 @@ import { -const InputStyle = styled(Input)<{ $style: InputLikeStyleType }>` +const InputStyle = styled(Input) <{ $style: InputLikeStyleType }>` +box-shadow: ${props=>`${props.$style?.boxShadow} ${props.$style?.boxShadowColor}`}; ${(props) => css` ${getStyle(props.$style)} input { @@ -74,7 +76,7 @@ const childrenMap = { ...textInputChildren, viewRef: RefControl, allowClear: BoolControl.DEFAULT_TRUE, - style: styleControl(InputFieldStyle), + style: withDefault(styleControl(InputFieldStyle),{background:'transparent'}), labelStyle:styleControl(LabelStyle), prefixIcon: IconControl, suffixIcon: IconControl, @@ -88,7 +90,8 @@ const childrenMap = { autocompleteIconColor: dropdownControl(autocompleteIconColor, "blue"), componentSize: dropdownControl(componentSize, "small"), valueInItems: booleanExposingStateControl("valueInItems"), - inputFieldStyle: styleControl(InputLikeStyle), + inputFieldStyle: withDefault(styleControl(InputLikeStyle),{borderWidth:'1px'}), + animationStyle: styleControl(AnimationStyle), }; const getValidate = (value: any): "" | "warning" | "error" | undefined => { @@ -283,6 +286,7 @@ let AutoCompleteCompBase = (function () { style: props.style, labelStyle: props.labelStyle, inputFieldStyle:props.inputFieldStyle, + animationStyle: props.animationStyle, ...validateState, }); }) @@ -290,38 +294,38 @@ let AutoCompleteCompBase = (function () { return ( <>
- {children.autoCompleteType.getView() === "normal" && + {children.autoCompleteType.getView() === 'normal' && children.prefixIcon.propertyView({ - label: trans("button.prefixIcon"), + label: trans('button.prefixIcon'), })} - {children.autoCompleteType.getView() === "normal" && + {children.autoCompleteType.getView() === 'normal' && children.suffixIcon.propertyView({ - label: trans("button.suffixIcon"), + label: trans('button.suffixIcon'), })} - {allowClearPropertyView(children)} + {allowClearPropertyView(children)}
-
+
{children.items.propertyView({ - label: trans("autoComplete.value"), + label: trans('autoComplete.value'), tooltip: itemsDataTooltip, - placeholder: "[]", + placeholder: '[]', })} - {getDayJSLocale() === "zh-cn" && + {getDayJSLocale() === 'zh-cn' && children.searchFirstPY.propertyView({ - label: trans("autoComplete.searchFirstPY"), + label: trans('autoComplete.searchFirstPY'), })} - {getDayJSLocale() === "zh-cn" && + {getDayJSLocale() === 'zh-cn' && children.searchCompletePY.propertyView({ - label: trans("autoComplete.searchCompletePY"), + label: trans('autoComplete.searchCompletePY'), })} {children.searchLabelOnly.propertyView({ - label: trans("autoComplete.searchLabelOnly"), + label: trans('autoComplete.searchLabelOnly'), })} {children.ignoreCase.propertyView({ - label: trans("autoComplete.ignoreCase"), + label: trans('autoComplete.ignoreCase'), })} {children.valueOrLabel.propertyView({ - label: trans("autoComplete.checkedValueFrom"), + label: trans('autoComplete.checkedValueFrom'), radioButton: true, })}
@@ -347,6 +351,12 @@ let AutoCompleteCompBase = (function () {
{children.inputFieldStyle.getPropertyView()}
+
+ {children.animationStyle.getPropertyView()} +
); }) diff --git a/client/packages/lowcoder/src/comps/comps/avatar.tsx b/client/packages/lowcoder/src/comps/comps/avatar.tsx index 61779a1c7..d97e3fed9 100644 --- a/client/packages/lowcoder/src/comps/comps/avatar.tsx +++ b/client/packages/lowcoder/src/comps/comps/avatar.tsx @@ -74,7 +74,6 @@ white-space: nowrap; font-weight: ${props=>props.$style.textWeight}; border-radius: ${props=>props.$style.radius}; font-size: ${props=>props.$style.textSize}; -rotate: ${props=>props.$style.rotation}; text-transform: ${props=>props.$style.textTransform}; color: ${props=>props.$style.text}; border: ${props => props.$style.border}; @@ -95,7 +94,6 @@ white-space: nowrap; font-weight: ${props=>props.$style.textWeight}; border-radius: ${props=>props.$style.radius}; font-size: ${props=>props.$style.textSize}; -rotate: ${props=>props.$style.rotation}; text-transform: ${props=>props.$style.textTransform}; color: ${props=>props.$style.text}; border: ${props => props.$style.border}; diff --git a/client/packages/lowcoder/src/comps/comps/buttonComp/buttonComp.tsx b/client/packages/lowcoder/src/comps/comps/buttonComp/buttonComp.tsx index 6e02a5ea3..1511ec66d 100644 --- a/client/packages/lowcoder/src/comps/comps/buttonComp/buttonComp.tsx +++ b/client/packages/lowcoder/src/comps/comps/buttonComp/buttonComp.tsx @@ -25,6 +25,7 @@ import { import { RefControl } from "comps/controls/refControl"; import React, { useContext } from "react"; +import { AnimationStyle, styleControl } from "@lowcoder-ee/index.sdk"; const FormLabel = styled(CommonBlueLabel)` font-size: 13px; @@ -129,6 +130,7 @@ const ButtonTmpComp = (function () { prefixIcon: IconControl, suffixIcon: IconControl, style: ButtonStyleControl, + animationStyle:styleControl(AnimationStyle), viewRef: RefControl, }; return new UICompBuilder(childrenMap, (props) => ( diff --git a/client/packages/lowcoder/src/comps/comps/buttonComp/buttonCompConstants.tsx b/client/packages/lowcoder/src/comps/comps/buttonComp/buttonCompConstants.tsx index 8ebcd250c..c509aeaa9 100644 --- a/client/packages/lowcoder/src/comps/comps/buttonComp/buttonCompConstants.tsx +++ b/client/packages/lowcoder/src/comps/comps/buttonComp/buttonCompConstants.tsx @@ -14,8 +14,9 @@ export function getButtonStyle(buttonStyle: ButtonStyleType) { &&& { border-radius: ${buttonStyle.radius}; border-width:${buttonStyle.borderWidth}; - margin: ${buttonStyle.margin}; + margin: ${buttonStyle.margin}; padding: ${buttonStyle.padding}; + rotate: ${buttonStyle.rotation&&buttonStyle.rotation}; &:not(:disabled) { --antd-wave-shadow-color: ${buttonStyle.border}; border-color: ${buttonStyle.border}; @@ -28,9 +29,9 @@ export function getButtonStyle(buttonStyle: ButtonStyleType) { text-decoration:${buttonStyle.textDecoration}; background-color: ${buttonStyle.background}; border-radius: ${buttonStyle.radius}; - margin: ${buttonStyle.margin}; + margin: ${buttonStyle.margin}; padding: ${buttonStyle.padding}; - + &:hover, &:focus { color: ${buttonStyle.text}; diff --git a/client/packages/lowcoder/src/comps/comps/buttonComp/dropdownComp.tsx b/client/packages/lowcoder/src/comps/comps/buttonComp/dropdownComp.tsx index 3a00a887d..150eec23a 100644 --- a/client/packages/lowcoder/src/comps/comps/buttonComp/dropdownComp.tsx +++ b/client/packages/lowcoder/src/comps/comps/buttonComp/dropdownComp.tsx @@ -3,7 +3,7 @@ import { default as Dropdown } from "antd/es/dropdown"; import { default as DropdownButton } from "antd/es/dropdown/dropdown-button"; import { BoolControl } from "comps/controls/boolControl"; import { BoolCodeControl, StringControl } from "comps/controls/codeControl"; -import { ButtonStyleType } from "comps/controls/styleControlConstants"; +import { DropdownStyle, DropdownStyleType } from "comps/controls/styleControlConstants"; import { withDefault } from "comps/generators"; import { UICompBuilder } from "comps/generators/uiCompBuilder"; import { disabledPropertyView, hiddenPropertyView } from "comps/utils/propertyUtils"; @@ -21,6 +21,7 @@ import { ButtonStyleControl, getButtonStyle, } from "./buttonCompConstants"; +import { styleControl } from "@lowcoder-ee/index.sdk"; const StyledDropdownButton = styled(DropdownButton)` @@ -32,7 +33,7 @@ const StyledDropdownButton = styled(DropdownButton)` } `; -const LeftButtonWrapper = styled.div<{ $buttonStyle: ButtonStyleType }>` +const LeftButtonWrapper = styled.div<{ $buttonStyle: DropdownStyleType }>` width: calc(100%); ${(props) => `margin: ${props.$buttonStyle.margin};`} margin-right: 0; @@ -62,7 +63,7 @@ const LeftButtonWrapper = styled.div<{ $buttonStyle: ButtonStyleType }>` `; -const RightButtonWrapper = styled.div<{ $buttonStyle: ButtonStyleType }>` +const RightButtonWrapper = styled.div<{ $buttonStyle: DropdownStyleType }>` // width: 32px; ${(props) => `margin: ${props.$buttonStyle.margin};`} margin-left: -1px; @@ -85,7 +86,7 @@ const DropdownTmpComp = (function () { options: DropdownOptionControl, disabled: BoolCodeControl, onEvent: ButtonEventHandlerControl, - style: ButtonStyleControl, + style: styleControl(DropdownStyle), }; return new UICompBuilder(childrenMap, (props) => { const hasIcon = diff --git a/client/packages/lowcoder/src/comps/comps/buttonComp/floatButtonComp.tsx b/client/packages/lowcoder/src/comps/comps/buttonComp/floatButtonComp.tsx index 01ec6226d..1797dd070 100644 --- a/client/packages/lowcoder/src/comps/comps/buttonComp/floatButtonComp.tsx +++ b/client/packages/lowcoder/src/comps/comps/buttonComp/floatButtonComp.tsx @@ -3,7 +3,7 @@ import { BoolControl } from "comps/controls/boolControl"; import { stringExposingStateControl } from "comps/controls/codeStateControl"; import { dropdownControl } from "comps/controls/dropdownControl"; import { styleControl } from "comps/controls/styleControl"; -import { BadgeStyle, BadgeStyleType, FloatButtonStyle, FloatButtonStyleType } from "comps/controls/styleControlConstants"; +import { AnimationStyle, AnimationStyleType, BadgeStyle, BadgeStyleType, FloatButtonStyle, FloatButtonStyleType } from "comps/controls/styleControlConstants"; import { UICompBuilder } from "comps/generators/uiCompBuilder"; import { NameConfig, NameConfigHidden, withExposingConfigs } from "comps/generators/withExposing"; import { Section, sectionNames } from "lowcoder-design"; @@ -17,6 +17,12 @@ import styled from "styled-components"; import { ButtonEventHandlerControl } from "comps/controls/eventHandlerControl"; import { manualOptionsControl } from "comps/controls/optionsControl"; +const StyledFloatButton = styled(FloatButton)<{ + $animationStyle: AnimationStyleType; +}>` + ${(props) => props.$animationStyle} +`; + const Wrapper = styled.div<{ $badgeStyle: BadgeStyleType, $style: FloatButtonStyleType}>` width: 0px; height: 0px; @@ -78,6 +84,7 @@ const childrenMap = { icon: withDefault(IconControl, '/icon:antd/questioncircleoutlined'), badgeStyle: styleControl(BadgeStyle), style: styleControl(FloatButtonStyle), + animationStyle: styleControl(AnimationStyle), buttons: manualOptionsControl(buttonGroupOption, { initOptions: [ { id: 0, label: trans("optionsControl.optionI", { i: '1' }), icon: "/icon:antd/filetextoutlined", badge: '1' }, @@ -93,7 +100,8 @@ const childrenMap = { const FloatButtonView = (props: RecordConstructorToView) => { const renderButton = (button: any, onlyOne?: boolean) => { return !button?.hidden ? ( - button.onEvent("click")} @@ -108,7 +116,7 @@ const FloatButtonView = (props: RecordConstructorToView) => return ( {props.buttons.length === 1 ? (renderButton(props.buttons[0], true)) : - () => type={props.buttonTheme} > {props.buttons.map((button: any) => renderButton(button))} - ) + ) } ); }; let FloatButtonBasicComp = (function () { - return new UICompBuilder(childrenMap, (props) => ) - .setPropertyViewFn((children) => ( - <> -
- {children.buttons.propertyView({})} - {children.icon.propertyView({ label: trans("icon") })} - {children.shape.propertyView({ label: trans("floatButton.buttonShape"), radioButton: true })} - {children.buttonTheme.propertyView({ label: trans("floatButton.buttonTheme"), radioButton: true })} - {children.dot.propertyView({ label: trans("floatButton.dot") })} -
-
- {hiddenPropertyView(children)} -
-
{children.badgeStyle.getPropertyView()}
-
{children.style.getPropertyView()}
- - )) - .build(); + return new UICompBuilder(childrenMap, (props) => ( + + )) + .setPropertyViewFn((children) => ( + <> +
+ {children.buttons.propertyView({})} + {children.icon.propertyView({ label: trans("icon") })} + {children.shape.propertyView({ label: trans("floatButton.buttonShape"), radioButton: true })} + {children.buttonTheme.propertyView({ label: trans("floatButton.buttonTheme"), radioButton: true })} + {children.dot.propertyView({ label: trans("floatButton.dot") })} +
+
+ {hiddenPropertyView(children)} +
+
{children.badgeStyle.getPropertyView()}
+
+ {children.style.getPropertyView()} +
+
+ {children.animationStyle.getPropertyView()} +
+ + )) + .build(); })(); FloatButtonBasicComp = class extends FloatButtonBasicComp { diff --git a/client/packages/lowcoder/src/comps/comps/buttonComp/linkComp.tsx b/client/packages/lowcoder/src/comps/comps/buttonComp/linkComp.tsx index 274a29e13..bd3765681 100644 --- a/client/packages/lowcoder/src/comps/comps/buttonComp/linkComp.tsx +++ b/client/packages/lowcoder/src/comps/comps/buttonComp/linkComp.tsx @@ -3,7 +3,7 @@ import { ButtonCompWrapper, buttonRefMethods } from "comps/comps/buttonComp/butt import { BoolCodeControl, StringControl } from "comps/controls/codeControl"; import { ButtonEventHandlerControl } from "comps/controls/eventHandlerControl"; import { styleControl } from "comps/controls/styleControl"; -import { LinkStyle, LinkStyleType } from "comps/controls/styleControlConstants"; +import { AnimationStyle, AnimationStyleType, LinkStyle, LinkStyleType } from "comps/controls/styleControlConstants"; import { withDefault } from "comps/generators"; import { migrateOldData } from "comps/generators/simpleGenerators"; import { UICompBuilder } from "comps/generators/uiCompBuilder"; @@ -23,16 +23,21 @@ import { RefControl } from "comps/controls/refControl"; import { EditorContext } from "comps/editorState"; import React, { useContext } from "react"; -const Link = styled(Button) <{ $style: LinkStyleType }>` +const Link = styled(Button)<{ + $style: LinkStyleType; + $animationStyle: AnimationStyleType; +}>` + ${(props) => props.$animationStyle} ${(props) => ` color: ${props.$style.text}; + rotate: ${props.$style.rotation}; margin: ${props.$style.margin}; padding: ${props.$style.padding}; font-size: ${props.$style.textSize}; font-style:${props.$style.fontStyle}; font-family:${props.$style.fontFamily}; font-weight:${props.$style.textWeight}; - border: ${props.$style.borderWidth} solid ${props.$style.border}; + border: ${props.$style.borderWidth} ${props.$style.borderStyle} ${props.$style.border}; border-radius:${props.$style.radius ? props.$style.radius:'0px'}; text-transform:${props.$style.textTransform ? props.$style.textTransform:''}; text-decoration:${props.$style.textDecoration ? props.$style.textDecoration:''} !important; @@ -81,6 +86,7 @@ const LinkTmpComp = (function () { disabled: BoolCodeControl, loading: BoolCodeControl, style: migrateOldData(styleControl(LinkStyle), fixOldData), + animationStyle:styleControl(AnimationStyle), prefixIcon: IconControl, suffixIcon: IconControl, viewRef: RefControl, @@ -91,6 +97,7 @@ const LinkTmpComp = (function () { return (
{children.style.getPropertyView()}
+ <> +
{children.style.getPropertyView()}
+
{children.animationStyle.getPropertyView()}
+ )} ); diff --git a/client/packages/lowcoder/src/comps/comps/buttonComp/scannerComp.tsx b/client/packages/lowcoder/src/comps/comps/buttonComp/scannerComp.tsx index ddd6364c3..4f497fb68 100644 --- a/client/packages/lowcoder/src/comps/comps/buttonComp/scannerComp.tsx +++ b/client/packages/lowcoder/src/comps/comps/buttonComp/scannerComp.tsx @@ -10,7 +10,7 @@ import { import { BoolCodeControl, StringControl } from "comps/controls/codeControl"; import { ScannerEventHandlerControl } from "comps/controls/eventHandlerControl"; import { styleControl } from "comps/controls/styleControl"; -import { ButtonStyle } from "comps/controls/styleControlConstants"; +import { DropdownStyle } from "comps/controls/styleControlConstants"; import { withDefault } from "comps/generators"; import { UICompBuilder } from "comps/generators/uiCompBuilder"; import { CustomModal, Section, sectionNames } from "lowcoder-design"; @@ -70,7 +70,7 @@ const ScannerTmpComp = (function () { maskClosable: withDefault(BoolControl, true), onEvent: ScannerEventHandlerControl, disabled: BoolCodeControl, - style: styleControl(ButtonStyle), + style: styleControl(DropdownStyle), 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 edfab9222..e8238e4c2 100644 --- a/client/packages/lowcoder/src/comps/comps/buttonComp/toggleButtonComp.tsx +++ b/client/packages/lowcoder/src/comps/comps/buttonComp/toggleButtonComp.tsx @@ -15,7 +15,11 @@ import { Button100, ButtonCompWrapper, buttonRefMethods } from "./buttonCompCons import { IconControl } from "comps/controls/iconControl"; import { AlignWithStretchControl, LeftRightControl } from "comps/controls/dropdownControl"; import { booleanExposingStateControl } from "comps/controls/codeStateControl"; -import { ToggleButtonStyle } from "comps/controls/styleControlConstants"; +import { + AnimationStyle, + AnimationStyleType, + ToggleButtonStyle, +} from "comps/controls/styleControlConstants"; import { styleControl } from "comps/controls/styleControl"; import { BoolControl } from "comps/controls/boolControl"; import { RefControl } from "comps/controls/refControl"; @@ -29,7 +33,9 @@ const IconWrapper = styled.div` const ButtonCompWrapperStyled = styled(ButtonCompWrapper)<{ $align: "left" | "center" | "right" | "stretch"; $showBorder: boolean; + $animationStyle: AnimationStyleType; }>` + ${(props) => props.$animationStyle} width: 100%; display: flex; justify-content: ${(props) => props.$align}; @@ -55,7 +61,8 @@ const ToggleTmpComp = (function () { iconPosition: LeftRightControl, alignment: AlignWithStretchControl, style: styleControl(ToggleButtonStyle), - showBorder: withDefault(BoolControl, true), + animationStyle: styleControl(AnimationStyle), + showBorder: withDefault(BoolControl, true), viewRef: RefControl, }; return new UICompBuilder(childrenMap, (props) => { @@ -67,6 +74,7 @@ const ToggleTmpComp = (function () { disabled={props.disabled} $align={props.alignment} $showBorder={props.showBorder} + $animationStyle={props.animationStyle} > )} - {(useContext(EditorContext).editorModeStatus === "layout" || useContext(EditorContext).editorModeStatus === "both") && ( - <>
- {children.showBorder.propertyView({ label: trans("toggleButton.showBorder") })} - {children.style.getPropertyView()} -
- )} - + {(useContext(EditorContext).editorModeStatus === "layout" || + useContext(EditorContext).editorModeStatus === "both") && ( + <> +
+ {children.showBorder.propertyView({ + label: trans("toggleButton.showBorder"), + })} + {children.style.getPropertyView()} +
+
+ {children.animationStyle.getPropertyView()} +
+ + )} + )) .setExposeMethodConfigs(buttonRefMethods) diff --git a/client/packages/lowcoder/src/comps/comps/carouselComp.tsx b/client/packages/lowcoder/src/comps/comps/carouselComp.tsx index 8e9c776d4..6ad2edf60 100644 --- a/client/packages/lowcoder/src/comps/comps/carouselComp.tsx +++ b/client/packages/lowcoder/src/comps/comps/carouselComp.tsx @@ -13,7 +13,7 @@ import { useRef, useState } from "react"; import ReactResizeDetector from "react-resize-detector"; import { ArrayStringControl } from "comps/controls/codeControl"; import { styleControl } from "comps/controls/styleControl"; -import { CarouselStyle } from "comps/controls/styleControlConstants"; +import { AnimationStyle, AnimationStyleType, CarouselStyle } from "comps/controls/styleControlConstants"; import { useContext } from "react"; import { EditorContext } from "comps/editorState"; @@ -25,11 +25,12 @@ const CarouselItem = styled.div<{ $src: string }>` background-size: contain; `; -const Container = styled.div<{ $bg: string }>` +const Container = styled.div<{$bg: string; $animationStyle:AnimationStyleType}>` &, .ant-carousel { height: 100%; background-color: ${(props) => props.$bg}; + ${props=>props.$animationStyle} } `; @@ -44,7 +45,7 @@ let CarouselBasicComp = (function () { showDots: withDefault(BoolControl, true), dotPosition: withDefault(PositionControl, "bottom"), style: styleControl(CarouselStyle), - + animationStyle: styleControl(AnimationStyle), ...formDataChildren, }; return new UICompBuilder(childrenMap, (props) => { @@ -56,7 +57,11 @@ let CarouselBasicComp = (function () { } }; return ( - + {children.style.getPropertyView()}
+
+ {children.animationStyle.getPropertyView()} +
)} diff --git a/client/packages/lowcoder/src/comps/comps/columnLayout/columnLayout.tsx b/client/packages/lowcoder/src/comps/comps/columnLayout/columnLayout.tsx new file mode 100644 index 000000000..2302d31e5 --- /dev/null +++ b/client/packages/lowcoder/src/comps/comps/columnLayout/columnLayout.tsx @@ -0,0 +1,339 @@ +import { default as Row } from "antd/es/row"; +import { default as Col } from "antd/es/col"; +import { JSONObject, JSONValue } from "util/jsonTypes"; +import { CompAction, CompActionTypes, deleteCompAction, wrapChildAction } from "lowcoder-core"; +import { DispatchType, RecordConstructorToView, wrapDispatch } from "lowcoder-core"; +import { AutoHeightControl } from "comps/controls/autoHeightControl"; +import { ColumnOptionControl } from "comps/controls/optionsControl"; +import { styleControl } from "comps/controls/styleControl"; +import { + ContainerStyle, + ContainerStyleType, + ResponsiveLayoutColStyleType, + ResponsiveLayoutColStyle +} from "comps/controls/styleControlConstants"; + +import { sameTypeMap, UICompBuilder, withDefault } from "comps/generators"; +import { addMapChildAction } from "comps/generators/sameTypeMap"; +import { NameConfigHidden, withExposingConfigs } from "comps/generators/withExposing"; +import { NameGenerator } from "comps/utils"; +import { Section, controlItem, sectionNames } from "lowcoder-design"; +import { HintPlaceHolder } from "lowcoder-design"; +import _ from "lodash"; +import styled from "styled-components"; +import { IContainer } from "../containerBase/iContainer"; +import { SimpleContainerComp } from "../containerBase/simpleContainerComp"; +import { CompTree, mergeCompTrees } from "../containerBase/utils"; +import { + ContainerBaseProps, + gridItemCompToGridItems, + InnerGrid, +} from "../containerComp/containerView"; +import { BackgroundColorContext } from "comps/utils/backgroundColorContext"; +import { trans } from "i18n"; +import { messageInstance } from "lowcoder-design/src/components/GlobalInstances"; +import { BoolControl } from "comps/controls/boolControl"; +import { BoolCodeControl, NumberControl, StringControl } from "comps/controls/codeControl"; + +import { useContext } from "react"; +import { EditorContext } from "comps/editorState"; + +import { disabledPropertyView, hiddenPropertyView } from "comps/utils/propertyUtils"; +import { DisabledContext } from "comps/generators/uiCompBuilder"; + +const ContainWrapper = styled.div<{ + $style: ContainerStyleType & { + display: string, + gridTemplateColumns: string, + columnGap: string, + gridTemplateRows: string, + rowGap: string, + } | undefined; +}>` + display: ${(props) => props.$style?.display}; + grid-template-columns: ${(props) => props.$style?.gridTemplateColumns}; + grid-template-rows: ${(props) => props.$style?.gridTemplateRows}; + column-gap: ${(props) => props.$style?.columnGap}; + row-gap: ${(props) => props.$style?.rowGap}; + + background-color: ${(props) => props.$style?.background} !important; + border-radius: ${(props) => props.$style?.radius}; + border-width: ${(props) => props.$style?.borderWidth}; + border-color: ${(props) => props.$style?.border}; + border-style: ${(props) => props.$style?.borderStyle}; + margin: ${(props) => props.$style?.margin}; + padding: ${(props) => props.$style?.padding}; +`; + +const ColWrapper = styled(Col)<{ + $style: ResponsiveLayoutColStyleType | undefined, + $minWidth?: string, + $matchColumnsHeight: boolean, +}>` + > div { + height: ${(props) => props.$matchColumnsHeight ? `calc(100% - ${props.$style?.padding || 0} - ${props.$style?.padding || 0})` : 'auto'}; + background-color: ${(props) => props.$style?.background} !important; + border-radius: ${(props) => props.$style?.radius}; + border-width: ${(props) => props.$style?.borderWidth}; + border-color: ${(props) => props.$style?.border}; + border-style: ${(props) => props.$style?.borderStyle}; + margin: ${(props) => props.$style?.margin}; + padding: ${(props) => props.$style?.padding}; + } +`; + +const childrenMap = { + disabled: BoolCodeControl, + columns: ColumnOptionControl, + containers: withDefault(sameTypeMap(SimpleContainerComp), { + 0: { view: {}, layout: {} }, + 1: { view: {}, layout: {} }, + }), + autoHeight: AutoHeightControl, + matchColumnsHeight: withDefault(BoolControl, true), + templateRows: withDefault(StringControl, "1fr"), + rowGap: withDefault(StringControl, "20px"), + templateColumns: withDefault(StringControl, "1fr 1fr"), + columnGap: withDefault(StringControl, "20px"), + style: withDefault(styleControl(ContainerStyle), {}), + columnStyle: withDefault(styleControl(ResponsiveLayoutColStyle),{borderWidth:'1px'}) +}; + +type ViewProps = RecordConstructorToView; +type ColumnLayoutProps = ViewProps & { dispatch: DispatchType }; +type ColumnContainerProps = Omit & { + style: ResponsiveLayoutColStyleType, +} + +const ColumnContainer = (props: ColumnContainerProps) => { + return ( + + ); +}; + + +const ColumnLayout = (props: ColumnLayoutProps) => { + let { + columns, + containers, + dispatch, + matchColumnsHeight, + templateRows, + rowGap, + templateColumns, + columnGap, + columnStyle, + } = props; + + return ( + + + + {columns.map(column => { + const id = String(column.id); + const childDispatch = wrapDispatch(wrapDispatch(dispatch, "containers"), id); + if(!containers[id]) return null + const containerProps = containers[id].children; + const noOfColumns = columns.length; + return ( + + + + + + ) + }) + } + + + + ); +}; + +export const ResponsiveLayoutBaseComp = (function () { + return new UICompBuilder(childrenMap, (props, dispatch) => { + return ( + + ); + }) + .setPropertyViewFn((children) => { + return ( + <> +
+ {children.columns.propertyView({ + title: trans("responsiveLayout.column"), + newOptionLabel: trans("responsiveLayout.addColumn"), + })} +
+ + {(useContext(EditorContext).editorModeStatus === "logic" || useContext(EditorContext).editorModeStatus === "both") && ( +
+ {disabledPropertyView(children)} + {hiddenPropertyView(children)} +
+ )} + + {["layout", "both"].includes(useContext(EditorContext).editorModeStatus) && ( + <> +
+ {children.autoHeight.getPropertyView()} +
+
+ {children.matchColumnsHeight.propertyView({ label: trans("responsiveLayout.matchColumnsHeight") + })} + {controlItem({}, ( +
{trans("responsiveLayout.columnsSpacing")}
+ ))} + {children.templateColumns.propertyView({label: trans("responsiveLayout.columnDefinition"), tooltip: trans("responsiveLayout.columnsDefinitionTooltip")})} + {children.templateRows.propertyView({label: trans("responsiveLayout.rowDefinition"), tooltip: trans("responsiveLayout.rowsDefinitionTooltip")})} + {children.columnGap.propertyView({label: trans("responsiveLayout.columnGap")})} + {children.rowGap.propertyView({label: trans("responsiveLayout.rowGap")})} +
+ + )} + + {(useContext(EditorContext).editorModeStatus === "layout" || useContext(EditorContext).editorModeStatus === "both") && ( + <> +
+ {children.style.getPropertyView()} +
+
+ {children.columnStyle.getPropertyView()} +
+ + )} + + ); + }) + .build(); +})(); + +class ColumnLayoutImplComp extends ResponsiveLayoutBaseComp implements IContainer { + private syncContainers(): this { + const columns = this.children.columns.getView(); + const ids: Set = new Set(columns.map((column) => String(column.id))); + let containers = this.children.containers.getView(); + // delete + const actions: CompAction[] = []; + Object.keys(containers).forEach((id) => { + if (!ids.has(id)) { + // log.debug("syncContainers delete. ids=", ids, " id=", id); + actions.push(wrapChildAction("containers", wrapChildAction(id, deleteCompAction()))); + } + }); + // new + ids.forEach((id) => { + if (!containers.hasOwnProperty(id)) { + // log.debug("syncContainers new containers: ", containers, " id: ", id); + actions.push( + wrapChildAction("containers", addMapChildAction(id, { layout: {}, items: {} })) + ); + } + }); + // log.debug("syncContainers. actions: ", actions); + let instance = this; + actions.forEach((action) => { + instance = instance.reduce(action); + }); + return instance; + } + + override reduce(action: CompAction): this { + const columns = this.children.columns.getView(); + if (action.type === CompActionTypes.CUSTOM) { + const value = action.value as JSONObject; + if (value.type === "push") { + const itemValue = value.value as JSONObject; + if (_.isEmpty(itemValue.key)) itemValue.key = itemValue.label; + action = { + ...action, + value: { + ...value, + value: { ...itemValue }, + }, + } as CompAction; + } + const { path } = action; + if (value.type === "delete" && path[0] === 'columns' && columns.length <= 1) { + messageInstance.warning(trans("responsiveLayout.atLeastOneColumnError")); + // at least one column + return this; + } + } + // log.debug("before super reduce. action: ", action); + let newInstance = super.reduce(action); + if (action.type === CompActionTypes.UPDATE_NODES_V2) { + // Need eval to get the value in StringControl + newInstance = newInstance.syncContainers(); + } + // log.debug("reduce. instance: ", this, " newInstance: ", newInstance); + return newInstance; + } + + realSimpleContainer(key?: string): SimpleContainerComp | undefined { + return Object.values(this.children.containers.children).find((container) => + container.realSimpleContainer(key) + ); + } + + getCompTree(): CompTree { + const containerMap = this.children.containers.getView(); + const compTrees = Object.values(containerMap).map((container) => container.getCompTree()); + return mergeCompTrees(compTrees); + } + + findContainer(key: string): IContainer | undefined { + const containerMap = this.children.containers.getView(); + for (const container of Object.values(containerMap)) { + const foundContainer = container.findContainer(key); + if (foundContainer) { + return foundContainer === container ? this : foundContainer; + } + } + return undefined; + } + + getPasteValue(nameGenerator: NameGenerator): JSONValue { + const containerMap = this.children.containers.getView(); + const containerPasteValueMap = _.mapValues(containerMap, (container) => + container.getPasteValue(nameGenerator) + ); + + return { ...this.toJsonValue(), containers: containerPasteValueMap }; + } + + override autoHeight(): boolean { + return this.children.autoHeight.getView(); + } +} + +export const ColumnLayoutComp = withExposingConfigs( + ColumnLayoutImplComp, + [ NameConfigHidden] +); diff --git a/client/packages/lowcoder/src/comps/comps/columnLayout/index.tsx b/client/packages/lowcoder/src/comps/comps/columnLayout/index.tsx new file mode 100644 index 000000000..bd529a048 --- /dev/null +++ b/client/packages/lowcoder/src/comps/comps/columnLayout/index.tsx @@ -0,0 +1 @@ +export { ColumnLayoutComp } from "./columnLayout"; diff --git a/client/packages/lowcoder/src/comps/comps/commentComp/commentComp.tsx b/client/packages/lowcoder/src/comps/comps/commentComp/commentComp.tsx index 74857007c..d927b6795 100644 --- a/client/packages/lowcoder/src/comps/comps/commentComp/commentComp.tsx +++ b/client/packages/lowcoder/src/comps/comps/commentComp/commentComp.tsx @@ -31,6 +31,7 @@ import { EditorContext } from "comps/editorState"; // Introducing styles import { + AnimationStyle, CommentStyle, heightCalculator, widthCalculator, @@ -100,6 +101,7 @@ const childrenMap = { }), onEvent: eventHandlerControl(EventOptions), style: styleControl(CommentStyle), + animationStyle: styleControl(AnimationStyle), commentList: jsonValueExposingStateControl("commentList", []), deletedItem: jsonValueExposingStateControl("deletedItem", []), submitedItem: jsonValueExposingStateControl("submitedItem", []), @@ -125,6 +127,7 @@ const CommentCompBase = ( userInfo, placeholder, deleteAble, + animationStyle, } = props; type PrefixType = "@" | keyof typeof mentionList; // Used to save the consolidated list of mentions @@ -233,7 +236,11 @@ const CommentCompBase = ( width: widthCalculator(style.margin ?? "3px"), height: heightCalculator(style.margin ?? "3px"), background: style.background, - borderRadius: style.radius, + borderRadius: style.radius, + animation: animationStyle.animation, + animationDelay: animationStyle.animationDelay, + animationDuration: animationStyle.animationDuration, + animationIterationCount:animationStyle.animationIterationCount }}>
+
+
{children.style.getPropertyView()} +
+
+ {children.animationStyle.getPropertyView()}
)} diff --git a/client/packages/lowcoder/src/comps/comps/containerComp/cardComp.tsx b/client/packages/lowcoder/src/comps/comps/containerComp/cardComp.tsx index d8784192c..7c8bea425 100644 --- a/client/packages/lowcoder/src/comps/comps/containerComp/cardComp.tsx +++ b/client/packages/lowcoder/src/comps/comps/containerComp/cardComp.tsx @@ -13,7 +13,7 @@ import { useContext, useEffect, useRef, useState } from "react"; import { EditorContext } from "comps/editorState"; import { Card } from "antd"; import styled from "styled-components"; -import { CardHeaderStyle, CardHeaderStyleType, CardStyle, CardStyleType } from "comps/controls/styleControlConstants"; +import { AnimationStyle, AnimationStyleType, CardHeaderStyle, CardHeaderStyleType, CardStyle, CardStyleType } from "comps/controls/styleControlConstants"; import { MultiCompBuilder, withDefault } from "comps/generators"; import { IconControl } from "comps/controls/iconControl"; import { ButtonEventHandlerControl, CardEventHandlerControl, clickEvent, refreshEvent } from "comps/controls/eventHandlerControl"; @@ -22,7 +22,14 @@ import { dropdownControl } from "comps/controls/dropdownControl"; import { styleControl } from "comps/controls/styleControl"; const { Meta } = Card; -const Warpper = styled.div<{ $style: CardStyleType | undefined, $showMate: boolean, $cardType: string, $headerStyle:CardHeaderStyleType, $bodyStyle:CardHeaderStyleType }>` +const Wrapper = styled.div<{ + $style: CardStyleType | undefined; + $showMate: boolean; + $cardType: string; + $headerStyle: CardHeaderStyleType; + $bodyStyle: CardHeaderStyleType; + $animationStyle:AnimationStyleType; +}>` height: 100%; width: 100%; .ant-card-small >.ant-card-head { @@ -42,6 +49,10 @@ const Warpper = styled.div<{ $style: CardStyleType | undefined, $showMate: boole margin: ${props => props.$headerStyle?.margin}; padding: ${props => props.$headerStyle?.padding}; } + .ant-card-head-title{ + font-size: ${props => props.$headerStyle?.textSize}; + font-family: ${props => props.$headerStyle?.fontFamily}; + } .ant-card .ant-card-actions { border-top: 1px solid ${props => props.$style?.border}; } @@ -65,11 +76,16 @@ const Warpper = styled.div<{ $style: CardStyleType | undefined, $showMate: boole display: flex; flex-direction: column; justify-content: space-between; + margin: ${props => props.$style?.margin}; + padding: ${props => props.$style?.padding}; background-color: ${props => props.$style?.background}; border: ${props => props.$style?.border}; + rotate: ${props => props.$style?.rotation}; border-style: ${props => props.$style?.borderStyle}; border-radius: ${props => props.$style?.radius}; border-width: ${props => props.$style?.borderWidth}; + box-shadow: ${props=>`${props.$style?.boxShadow} ${props.$style?.boxShadowColor}`}; + ${props=>props.$animationStyle} } .ant-card-body { display: ${props => props.$showMate ? '' : 'none'}; @@ -95,12 +111,12 @@ const Warpper = styled.div<{ $style: CardStyleType | undefined, $showMate: boole } `; -const ContainWarpper = styled.div` +const ContainWrapper = styled.div` height: 100%; width: 100%; ` -const IconWarpper = styled.div<{ $style: CardStyleType | undefined, disabled: boolean }>` +const IconWrapper = styled.div<{ $style: CardStyleType | undefined, disabled: boolean }>` pointer-events: ${props => props.disabled ? 'none' : ''}; svg { color: ${props => props.disabled ? '#d9d9d9' : props.$style?.IconColor}; @@ -173,6 +189,7 @@ export const ContainerBaseComp = (function () { style: styleControl(CardStyle), headerStyle: styleControl(CardHeaderStyle), bodyStyle: styleControl(CardHeaderStyle), + animationStyle: styleControl(AnimationStyle), }; return new ContainerCompBuilder(childrenMap, (props, dispatch) => { @@ -199,9 +216,10 @@ export const ContainerBaseComp = (function () { }; return ( - !item.hidden).map(item => { return ( - item.onEvent('click')} disabled={item.disabled} $style={props.style} > {item.icon} - ) + ) } ) : [] } > {props.cardType == 'common' && props.showMeta && } - {props.cardType == 'custom' && - } + {props.cardType == 'custom' && + } } - + ); }) @@ -321,6 +339,9 @@ export const ContainerBaseComp = (function () {
{children.bodyStyle.getPropertyView()}
+
+ {children.animationStyle.getPropertyView()} +
)} diff --git a/client/packages/lowcoder/src/comps/comps/containerComp/containerComp.tsx b/client/packages/lowcoder/src/comps/comps/containerComp/containerComp.tsx index d088a51c0..9005d7de2 100644 --- a/client/packages/lowcoder/src/comps/comps/containerComp/containerComp.tsx +++ b/client/packages/lowcoder/src/comps/comps/containerComp/containerComp.tsx @@ -16,10 +16,12 @@ import { BoolCodeControl } from "comps/controls/codeControl"; import { DisabledContext } from "comps/generators/uiCompBuilder"; import React, { useContext } from "react"; import { EditorContext } from "comps/editorState"; +import { AnimationStyle, styleControl } from "@lowcoder-ee/index.sdk"; export const ContainerBaseComp = (function () { const childrenMap = { disabled: BoolCodeControl, + animationStyle: styleControl(AnimationStyle), }; return new ContainerCompBuilder(childrenMap, (props, dispatch) => { return ( diff --git a/client/packages/lowcoder/src/comps/comps/containerComp/pageLayoutComp.tsx b/client/packages/lowcoder/src/comps/comps/containerComp/pageLayoutComp.tsx index 489398a94..0439d0848 100644 --- a/client/packages/lowcoder/src/comps/comps/containerComp/pageLayoutComp.tsx +++ b/client/packages/lowcoder/src/comps/comps/containerComp/pageLayoutComp.tsx @@ -18,11 +18,12 @@ import { ContainerCompBuilder, } from "../pageLayoutComp/pageLayoutCompBuilder"; import { PageLayout } from "../pageLayoutComp/pageLayout"; - +import { AnimationStyle, styleControl } from "@lowcoder-ee/index.sdk"; export const ContainerBaseComp = (function () { - const childrenMap = { - disabled: BoolCodeControl + const childrenMap = { + disabled: BoolCodeControl, + animationStyle: styleControl(AnimationStyle), }; return new ContainerCompBuilder(childrenMap, (props, dispatch) => { @@ -52,7 +53,10 @@ export const ContainerBaseComp = (function () {
{ children.container.stylePropertyView() } -
+
+
+ {children.animationStyle.getPropertyView()} +
{children.container.children.showHeader.getView() && (
{ children.container.headerStylePropertyView() } diff --git a/client/packages/lowcoder/src/comps/comps/containerComp/textContainerComp.tsx b/client/packages/lowcoder/src/comps/comps/containerComp/textContainerComp.tsx index 6681a9635..653363f01 100644 --- a/client/packages/lowcoder/src/comps/comps/containerComp/textContainerComp.tsx +++ b/client/packages/lowcoder/src/comps/comps/containerComp/textContainerComp.tsx @@ -20,7 +20,7 @@ import { TriContainer } from "../triContainerComp/triFloatTextContainer"; import { dropdownControl } from "comps/controls/dropdownControl"; import { withDefault } from "comps/generators/simpleGenerators"; import { styleControl } from "comps/controls/styleControl"; -import { TextStyle } from "comps/controls/styleControlConstants"; +import { AnimationStyle, TextContainerStyle } from "comps/controls/styleControlConstants"; import { useContext } from "react"; import { EditorContext } from "comps/editorState"; import { alignWithJustifyControl } from "comps/controls/alignControl"; @@ -62,7 +62,8 @@ export const ContainerBaseComp = (function () { float: dropdownControl(floatOptions, "left"), horizontalAlignment: alignWithJustifyControl(), width: withDefault(StringControl, "40"), - style: styleControl(TextStyle), + style: styleControl(TextContainerStyle), + animationStyle: styleControl(AnimationStyle), }; return new ContainerCompBuilder(childrenMap, (props, dispatch) => { return ; @@ -95,6 +96,9 @@ export const ContainerBaseComp = (function () {
{children.style.getPropertyView()}
+
+ {children.animationStyle.getPropertyView()} +
{children.container.stylePropertyView()}
diff --git a/client/packages/lowcoder/src/comps/comps/customComp/customComp.tsx b/client/packages/lowcoder/src/comps/comps/customComp/customComp.tsx index 07d72b701..ee9d4c754 100644 --- a/client/packages/lowcoder/src/comps/comps/customComp/customComp.tsx +++ b/client/packages/lowcoder/src/comps/comps/customComp/customComp.tsx @@ -12,6 +12,7 @@ import { EventData, EventTypeEnum } from "./types"; import { hiddenPropertyView } from "comps/utils/propertyUtils"; import { trans } from "i18n"; import { EditorContext } from "comps/editorState"; +import { AnimationStyle, AnimationStyleType, CustomStyle, CustomStyleType, styleControl } from "@lowcoder-ee/index.sdk"; // TODO: eventually to embedd in container so we have styling? // TODO: support different starter templates for different frameworks (react, ANT, Flutter, Angular, etc) @@ -67,13 +68,21 @@ const defaultCode = ` type IProps = { code: string; model: any; + style: CustomStyleType; + animationStyle:AnimationStyleType onModelChange: (v: any) => void; dispatch: (action: CompAction) => void; }; -const Wrapper = styled.div` +const Wrapper = styled.div<{ + $style: CustomStyleType; + $animationStyle: AnimationStyleType; +}>` width: 100%; height: 100%; + ${(props) => props.$style}; + rotate: ${(props) => props.$style.rotation}; + ${(props) => props.$animationStyle}; iframe { border: 0; width: 100%; @@ -196,8 +205,12 @@ function InnerCustomComponent(props: IProps) { }, [code]); return ( - -