diff --git a/app/client/src/assets/icons/ads/logout.svg b/app/client/src/assets/icons/ads/logout.svg
new file mode 100644
index 0000000000..f301b2b502
--- /dev/null
+++ b/app/client/src/assets/icons/ads/logout.svg
@@ -0,0 +1,15 @@
+
+
+
diff --git a/app/client/src/components/ads/EditableText.tsx b/app/client/src/components/ads/EditableText.tsx
index 5632662b38..0b855cc4ca 100644
--- a/app/client/src/components/ads/EditableText.tsx
+++ b/app/client/src/components/ads/EditableText.tsx
@@ -154,7 +154,7 @@ export const EditableText = (props: EditableTextProps) => {
const bgColor = useMemo(
() =>
editModeBgcolor(!!isInvalid, isEditing, savingState, themeDetails.theme),
- [isInvalid, isEditing, savingState],
+ [isInvalid, isEditing, savingState, themeDetails],
);
const editMode = useCallback(
diff --git a/app/client/src/components/ads/Icon.tsx b/app/client/src/components/ads/Icon.tsx
index dbefb9df31..7550f46194 100644
--- a/app/client/src/components/ads/Icon.tsx
+++ b/app/client/src/components/ads/Icon.tsx
@@ -17,6 +17,7 @@ import { ReactComponent as InviteUserIcon } from "assets/icons/ads/invite-users.
import { ReactComponent as ViewAllIcon } from "assets/icons/ads/view-all.svg";
import { ReactComponent as ContextMenuIcon } from "assets/icons/ads/context-menu.svg";
import { ReactComponent as DuplicateIcon } from "assets/icons/ads/duplicate.svg";
+import { ReactComponent as LogoutIcon } from "assets/icons/ads/logout.svg";
import styled from "styled-components";
import { CommonComponentProps, Classes } from "./common";
import { noop } from "lodash";
@@ -86,6 +87,7 @@ export const IconCollection = [
"downArrow",
"context-menu",
"duplicate",
+ "logout",
] as const;
export type IconName = typeof IconCollection[number];
@@ -184,6 +186,9 @@ const Icon = (props: IconProps & CommonComponentProps) => {
case "duplicate":
returnIcon = ;
break;
+ case "logout":
+ returnIcon = ;
+ break;
default:
returnIcon = null;
break;
diff --git a/app/client/src/components/ads/Menu.tsx b/app/client/src/components/ads/Menu.tsx
index b264540bf5..d19971d87c 100644
--- a/app/client/src/components/ads/Menu.tsx
+++ b/app/client/src/components/ads/Menu.tsx
@@ -16,7 +16,6 @@ const MenuWrapper = styled.div`
width: 234px;
background: ${props => props.theme.colors.blackShades[3]};
box-shadow: 0px 12px 28px rgba(0, 0, 0, 0.75);
- padding: ${props => props.theme.spaces[5]}px 0px;
`;
const MenuOption = styled.div`
diff --git a/app/client/src/components/ads/MenuItem.tsx b/app/client/src/components/ads/MenuItem.tsx
index 2f040eaaf7..917107f0e4 100644
--- a/app/client/src/components/ads/MenuItem.tsx
+++ b/app/client/src/components/ads/MenuItem.tsx
@@ -17,15 +17,15 @@ const ItemRow = styled.a<{ disabled?: boolean }>`
align-items: center;
justify-content: space-between;
text-decoration: none;
- padding: ${props => props.theme.spaces[4]}px
- ${props => props.theme.spaces[6]}px;
+ padding: 0px ${props => props.theme.spaces[6]}px;
+ height: 38px;
${props =>
!props.disabled
? `
&:hover {
- text-decoration: none;
cursor: pointer;
+ text-decoration: none;
background-color: ${props.theme.colors.blackShades[4]};
.${Classes.TEXT} {
color: ${props.theme.colors.blackShades[9]};
@@ -38,7 +38,8 @@ const ItemRow = styled.a<{ disabled?: boolean }>`
}`
: `
&:hover {
- cursor: not-allowed;
+ text-decoration: none;
+ cursor: default;
}
`}
`;
@@ -68,7 +69,7 @@ function MenuItem(props: MenuItemProps) {
) : null}
- {props.label ? {props.label} : null}
+ {props.label ? props.label : null}
);
}
diff --git a/app/client/src/components/ads/RectangularSwitcher.tsx b/app/client/src/components/ads/RectangularSwitcher.tsx
new file mode 100644
index 0000000000..03dd1ce2cf
--- /dev/null
+++ b/app/client/src/components/ads/RectangularSwitcher.tsx
@@ -0,0 +1,129 @@
+import { CommonComponentProps, Classes } from "./common";
+import React, { useState, useEffect } from "react";
+import styled from "styled-components";
+import Text, { TextType } from "./Text";
+
+type SwitchProps = CommonComponentProps & {
+ onSwitch: (value: boolean) => void;
+ value: boolean;
+};
+
+const StyledSwitch = styled.label<{
+ isLoading?: boolean;
+ value: boolean;
+ firstRender: boolean;
+}>`
+ position: relative;
+ display: block;
+ width: 78px;
+ height: 26px;
+ cursor: pointer;
+
+ input {
+ opacity: 0;
+ width: 0;
+ height: 0;
+ }
+
+ .slider {
+ position: absolute;
+ cursor: pointer;
+ top: 0;
+ left: 0;
+ border: 1px solid ${props => props.theme.colors.blackShades[5]};
+ background-color: ${props => props.theme.colors.info.main};
+ width: 78px;
+ height: 26px;
+ }
+
+ ${props =>
+ `.slider:before {
+ position: absolute;
+ content: "";
+ width: 36px;
+ height: 20px;
+ top: 2px;
+ background-color: ${props.theme.colors.blackShades[0]};
+ left: ${props.value && !props.firstRender ? "38px" : "2px"};
+ transition: ${props.firstRender ? "0.4s" : "none"};
+ }
+ `}
+
+ input:checked + .slider:before {
+ transform: ${props => (props.firstRender ? "translateX(36px)" : "none")};
+ }
+
+ input:checked + .slider:before {
+ background-color: ${props => props.theme.colors.blackShades[0]};
+ }
+
+ input:hover + .slider {
+ border: 1px solid ${props => props.theme.colors.blackShades[7]};
+ }
+`;
+
+const Light = styled.div<{ value: boolean }>`
+ .${Classes.TEXT} {
+ color: ${props => (props.value ? "#FFFFFF" : "#939090")};
+ font-size: 10px;
+ line-height: 12px;
+ letter-spacing: -0.171429px;
+ }
+ position: absolute;
+ top: 3px;
+ left: 10px;
+`;
+
+const Dark = styled.div<{ value: boolean }>`
+ .${Classes.TEXT} {
+ font-size: 10px;
+ line-height: 12px;
+ letter-spacing: -0.171429px;
+ color: ${props => (!props.value ? "#FFFFFF" : "#939090")};
+ }
+ position: absolute;
+ top: 3px;
+ left: 46px;
+`;
+
+export default function Switch(props: SwitchProps) {
+ const [value, setValue] = useState(false);
+ const [firstRender, setFirstRender] = useState(false);
+
+ useEffect(() => {
+ setValue(props.value);
+ }, [props.value]);
+
+ const onChangeHandler = (value: boolean) => {
+ setValue(value);
+ props.onSwitch && props.onSwitch(value);
+ };
+
+ return (
+
+ ) => {
+ if (!firstRender) {
+ setFirstRender(true);
+ }
+ onChangeHandler(e.target.checked);
+ }}
+ />
+
+
+ Light
+
+
+ Dark
+
+
+ );
+}
diff --git a/app/client/src/components/ads/TextInput.tsx b/app/client/src/components/ads/TextInput.tsx
index f19f2b1440..92c040cef1 100644
--- a/app/client/src/components/ads/TextInput.tsx
+++ b/app/client/src/components/ads/TextInput.tsx
@@ -113,8 +113,8 @@ const InputWrapper = styled.div`
`;
const ErrorWrapper = styled.div`
- position absolute;
- bottom: -17px;
+ position: absolute;
+ bottom: -17px;
`;
const TextInput = forwardRef(
(props: TextInputProps, ref: Ref) => {
@@ -135,7 +135,7 @@ const TextInput = forwardRef(
const inputStyle = useMemo(
() => boxStyles(props, validation.isValid, theme),
- [props, validation.isValid],
+ [props, validation.isValid, theme],
);
const memoizedChangeHandler = useCallback(
diff --git a/app/client/src/pages/common/PageHeader.tsx b/app/client/src/pages/common/PageHeader.tsx
index 41a095c9f4..8efbb04401 100644
--- a/app/client/src/pages/common/PageHeader.tsx
+++ b/app/client/src/pages/common/PageHeader.tsx
@@ -5,15 +5,13 @@ import { getCurrentUser } from "selectors/usersSelectors";
import styled from "styled-components";
import StyledHeader from "components/designSystems/appsmith/StyledHeader";
import AppsmithLogo from "assets/images/appsmith_logo_white.png";
-import CustomizedDropdown from "./CustomizedDropdown";
-import DropdownProps from "./CustomizedDropdown/HeaderDropdownData";
import { AppState } from "reducers";
import { User, ANONYMOUS_USERNAME } from "constants/userConstants";
import { AUTH_LOGIN_URL, APPLICATIONS_URL } from "constants/routes";
import Button from "components/editorComponents/Button";
import history from "utils/history";
import { Colors } from "constants/Colors";
-// import ThemeSwitcher from "./ThemeSwitcher";
+import ProfileDropdown from "./ProfileDropdown";
const StyledPageHeader = styled(StyledHeader)`
background: ${Colors.BALTIC_SEA};
@@ -42,10 +40,6 @@ type PageHeaderProps = {
user?: User;
};
-// const StyledSwitcher = styled(ThemeSwitcher)`
-// flex: 1;
-// `;
-
export const PageHeader = (props: PageHeaderProps) => {
const { user } = props;
const location = useLocation();
@@ -62,7 +56,6 @@ export const PageHeader = (props: PageHeaderProps) => {
- {/* */}
{user && (
{user.username === ANONYMOUS_USERNAME ? (
@@ -74,7 +67,7 @@ export const PageHeader = (props: PageHeaderProps) => {
onClick={() => history.push(loginUrl)}
/>
) : (
-
+
)}
)}
diff --git a/app/client/src/pages/common/ProfileDropdown.tsx b/app/client/src/pages/common/ProfileDropdown.tsx
new file mode 100644
index 0000000000..d663794afa
--- /dev/null
+++ b/app/client/src/pages/common/ProfileDropdown.tsx
@@ -0,0 +1,67 @@
+import React from "react";
+import { CommonComponentProps } from "components/ads/common";
+import { getInitialsAndColorCode } from "utils/AppsmithUtils";
+import { useSelector } from "react-redux";
+import { getThemeDetails } from "selectors/themeSelectors";
+import Text, { TextType } from "components/ads/Text";
+import styled from "styled-components";
+import { Position } from "@blueprintjs/core";
+import Menu from "components/ads/Menu";
+import ThemeSwitcher from "./ThemeSwitcher";
+import MenuDivider from "components/ads/MenuDivider";
+import MenuItem from "components/ads/MenuItem";
+import {
+ getOnSelectAction,
+ DropdownOnSelectActions,
+} from "./CustomizedDropdown/dropdownHelpers";
+import { ReduxActionTypes } from "constants/ReduxActionConstants";
+
+type TagProps = CommonComponentProps & {
+ onClick?: (text: string) => void;
+ userName?: string;
+};
+
+const ProfileImage = styled.div<{ backgroundColor?: string }>`
+ width: 30px;
+ height: 30px;
+ display: flex;
+ align-items: center;
+ border-radius: 50%;
+ justify-content: center;
+ cursor: pointer;
+ background-color: ${props => props.backgroundColor};
+`;
+
+export default function ProfileDropdown(props: TagProps) {
+ const themeDetails = useSelector(getThemeDetails);
+
+ const initialsAndColorCode = getInitialsAndColorCode(
+ props.userName,
+ themeDetails.theme.colors.appCardColors,
+ );
+
+ return (
+
+ );
+}
diff --git a/app/client/src/pages/common/ThemeSwitcher.tsx b/app/client/src/pages/common/ThemeSwitcher.tsx
index 4b784da2dd..a8bb831c51 100644
--- a/app/client/src/pages/common/ThemeSwitcher.tsx
+++ b/app/client/src/pages/common/ThemeSwitcher.tsx
@@ -1,18 +1,31 @@
-import Toggle from "components/ads/Toggle";
-import React from "react";
-import { useDispatch } from "react-redux";
+import React, { useState } from "react";
+import { useDispatch, useSelector } from "react-redux";
import { setThemeMode } from "actions/themeActions";
import { ThemeMode } from "reducers/uiReducers/themeReducer";
+import Switch from "components/ads/RectangularSwitcher";
+import MenuItem from "components/ads/MenuItem";
+import { getThemeDetails } from "selectors/themeSelectors";
export default function ThemeSwitcher(props: { className?: string }) {
const dispatch = useDispatch();
+ const themeDetails = useSelector(getThemeDetails);
+ const [switchedOn, setSwitchOn] = useState(
+ themeDetails.mode === ThemeMode.DARK,
+ );
+
return (
- {
- dispatch(setThemeMode(value ? ThemeMode.LIGHT : ThemeMode.DARK));
- }}
- >
+