Skip to content

Commit

Permalink
Add Citrouille theme (#324)
Browse files Browse the repository at this point in the history
* POC Citrouille

* Add hooks

* Add halloween theme & icons

* Make use of feature flag

* Add caching to useFeatureFlags

* Use session storage for flags

---------

Co-authored-by: thibautbremand <thibaut.bremand@gmail.com>
  • Loading branch information
FlorianBouron and ThibautBremand authored Oct 19, 2023
1 parent 2150f33 commit d08d421
Show file tree
Hide file tree
Showing 13 changed files with 279 additions and 95 deletions.
1 change: 1 addition & 0 deletions packages/extension/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
"react": "^17.0.2",
"react-content-loader": "^6.2.0",
"react-dom": "^17.0.2",
"react-icons": "^4.11.0",
"react-infinite-scroll-component": "^6.1.0",
"react-json-view": "^1.21.3",
"react-lazy-load-image-component": "^1.6.0",
Expand Down
38 changes: 29 additions & 9 deletions packages/extension/src/components/atoms/Logo/Logo.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,30 @@
import { FC, SVGProps } from 'react';
import { FC, SVGProps, useMemo } from 'react';

import { useFeatureFlags } from '../../../hooks';

interface LogoProps extends SVGProps<SVGSVGElement> {
isAnimated?: boolean;
}

export const Logo: FC<LogoProps> = ({ isAnimated, ...rest }) => {
const { featureFlags } = useFeatureFlags();

const colors = useMemo(() => {
if ((featureFlags as any)['CITROUILLE_2K23']) {
return {
primary: '#FF7518',
secondary: '#FFA500',
tertiary: '#FFD700'
};
}
//TODO: In another MR these colors will need to come from the template
return {
primary: '#00A8EA',
secondary: '#33D3F4',
tertiary: '#40EEFF'
};
}, [featureFlags]);

if (isAnimated) {
return (
<svg
Expand All @@ -23,17 +43,17 @@ export const Logo: FC<LogoProps> = ({ isAnimated, ...rest }) => {
}
</style>
<path
fill="#00a8ea"
fill={colors.primary}
d="M20 34.578.593 12.088h38.814z"
style={{
animation: 'emDoUNTzlg85_c_o 2000ms linear infinite normal forwards'
}}
transform="translate(-.593 4.622)"
/>
<path fill="#33d3f4" d="M32.593 4.622H6.223L0 16.712h38.815z" />
<path fill="#40eeff" d="M19.407 39.2 12.37 16.711h14.074z" />
<path fill={colors.secondary} d="M32.593 4.622H6.223L0 16.712h38.815z" />
<path fill={colors.tertiary} d="M19.407 39.2 12.37 16.711h14.074z" />
<path
fill="#40eeff"
fill={colors.tertiary}
d="M14.222 14.4 8.667 5.333H20z"
opacity={0.1}
style={{
Expand All @@ -42,7 +62,7 @@ export const Logo: FC<LogoProps> = ({ isAnimated, ...rest }) => {
transform="translate(-.593 -.711)"
/>
<path
fill="#40eeff"
fill={colors.tertiary}
d="M25.481 14.4 20 5.333h11.333z"
opacity={0.1}
style={{
Expand Down Expand Up @@ -79,10 +99,10 @@ export const Logo: FC<LogoProps> = ({ isAnimated, ...rest }) => {
return (
<svg width={40} height={40} xmlns="http://www.w3.org/2000/svg" {...rest}>
<g fill="none">
<path fill="#00A8EA" d="M20 39.911.593 17.422h38.814z" />
<path fill="#33D3F4" d="M33.185 5.333H6.815L.593 17.423h38.814z" />
<path fill={colors.primary} d="M20 39.911.593 17.422h38.814z" />
<path fill={colors.secondary} d="M33.185 5.333H6.815L.593 17.423h38.814z" />
<path
fill="#40EEFF"
fill={colors.tertiary}
d="m20 39.911-7.037-22.489h14.074zM14.222 14.4 8.667 5.333H20zm11.259 0L20 5.333h11.333z"
/>
<path
Expand Down
41 changes: 28 additions & 13 deletions packages/extension/src/components/organisms/Header/Header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import OutboundIcon from '@mui/icons-material/Outbound';
import { AppBar, Box, Button, IconButton, Toolbar, Tooltip, Typography } from '@mui/material';
import { styled } from '@mui/material/styles';
import copyToClipboard from 'copy-to-clipboard';
import { GiHangingSpider } from 'react-icons/gi';
import { SiGhostery } from 'react-icons/si';
import { useNavigate } from 'react-router-dom';

import {
Expand All @@ -15,7 +17,7 @@ import {
SEND_PATH,
RECEIVE_PATH
} from '../../../constants';
import { useTimeout } from '../../../hooks';
import { useFeatureFlags, useTimeout } from '../../../hooks';
import { WalletLedger } from '../../../types';
import { truncateAddress, truncateWalletName } from '../../../utils';
import { WalletIcon } from '../../atoms';
Expand All @@ -38,11 +40,16 @@ export interface HeaderProps {
export const Header: FC<HeaderProps> = ({ wallet: { name, publicAddress } }) => {
const navigate = useNavigate();
const setTimeout = useTimeout(2000);
const { featureFlags } = useFeatureFlags();

const [isCopied, setIsCopied] = useState(false);

const truncatedAddress = useMemo(() => truncateAddress(publicAddress), [publicAddress]);

const isHalloween = useMemo(() => {
return (featureFlags as any)['CITROUILLE_2K23'];
}, [featureFlags]);

const handleShare = useCallback(() => {
copyToClipboard(publicAddress);
setIsCopied(true);
Expand Down Expand Up @@ -117,12 +124,16 @@ export const Header: FC<HeaderProps> = ({ wallet: { name, publicAddress } }) =>
alignItems: 'center'
}}
>
<OutboundIcon
style={{
transform: 'rotate(-45deg)',
color: 'white'
}}
/>
{isHalloween ? (
<SiGhostery size={20} color="white" />
) : (
<OutboundIcon
style={{
transform: 'rotate(-45deg)',
color: 'white'
}}
/>
)}
<Typography color="white" variant="caption">
Send
</Typography>
Expand All @@ -137,12 +148,16 @@ export const Header: FC<HeaderProps> = ({ wallet: { name, publicAddress } }) =>
}}
onClick={handleReceive}
>
<OutboundIcon
style={{
transform: 'rotate(135deg)',
color: 'white'
}}
/>
{isHalloween ? (
<GiHangingSpider size={20} color="white" />
) : (
<OutboundIcon
style={{
transform: 'rotate(135deg)',
color: 'white'
}}
/>
)}
<Typography color="white" variant="caption">
Receive
</Typography>
Expand Down
75 changes: 53 additions & 22 deletions packages/extension/src/components/organisms/NavMenu/NavMenu.tsx
Original file line number Diff line number Diff line change
@@ -1,36 +1,23 @@
import { CSSProperties, FC, MouseEvent, useEffect } from 'react';
import { CSSProperties, FC, MouseEvent, useEffect, useMemo } from 'react';

import { BottomNavigation, BottomNavigationAction } from '@mui/material';
import { styled } from '@mui/system';
import { FaGhost, FaHatWizard, FaSpider } from 'react-icons/fa';
import { GiPumpkinLantern } from 'react-icons/gi';
import { useNavigate } from 'react-router-dom';

import { GEMWALLET_BLUE, navigation } from '../../../constants';
import {
GEMWALLET_BLUE,
GEMWALLET_HALLOWEEN_ORANGE,
navigation as navigationConstant
} from '../../../constants';
import { useNavBarPosition } from '../../../contexts';

const defaultDecoration = {
'--decoration-left': '50%',
'--decoration-width': '0'
};

const StyledBottomNavigation = styled(BottomNavigation)`
${defaultDecoration}
position: relative;
border-top: none !important;
box-shadow: 0 -2px 15px rgba(0, 0, 0, 0.35);
&::after {
content: '';
position: absolute;
top: 0;
left: var(--decoration-left);
width: var(--decoration-width);
height: 2px;
background: ${GEMWALLET_BLUE};
transition: 300ms;
border-radius: 2px;
}
`;

const StyledBottomNavigationAction = styled(BottomNavigationAction)`
border-top: none !important;
box-shadow: none !important;
Expand All @@ -42,7 +29,51 @@ export interface NavMenuProps {

export const NavMenu: FC<NavMenuProps> = ({ indexDefaultNav }) => {
const navigate = useNavigate();
const { navBarPosition, setNavBarPosition } = useNavBarPosition();
const { navBarPosition, setNavBarPosition, isHalloween } = useNavBarPosition();

const StyledBottomNavigation = useMemo(() => {
const backgroundColor = isHalloween ? GEMWALLET_HALLOWEEN_ORANGE : GEMWALLET_BLUE;

return styled(BottomNavigation)`
${defaultDecoration}
position: relative;
border-top: none !important;
box-shadow: 0 -2px 15px rgba(0, 0, 0, 0.35);
&::after {
content: '';
position: absolute;
top: 0;
left: var(--decoration-left);
width: var(--decoration-width);
height: 2px;
background: ${backgroundColor};
transition: 300ms;
border-radius: 2px;
}
`;
}, [isHalloween]);

const navigation = useMemo(() => {
if (!isHalloween) {
return navigationConstant;
}
const navigationHalloween = [
<GiPumpkinLantern size={25} />,
<FaGhost size={25} />,
<FaHatWizard size={25} />,
<FaSpider size={25} />
];

if (navigationConstant.length !== navigationHalloween.length) {
throw new Error('navigation constant and navigation Halloween must have the same length');
}

return navigationConstant.map((navItem, index) => ({
...navItem,
icon: navigationHalloween[index]
}));
}, [isHalloween]);

useEffect(() => {
if (indexDefaultNav !== -1) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ export const Welcome: FC = () => {
}}
>
<Container style={{ textAlign: 'center', marginTop: '30%' }}>
<Logo style={{ transform: 'scale(2)' }} />
<Logo isAnimated style={{ transform: 'scale(2)' }} />
<Typography variant="h4" component="h1" style={{ marginTop: '30px' }}>
GemWallet
</Typography>
Expand Down
1 change: 1 addition & 0 deletions packages/extension/src/constants/colors.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
export const SECONDARY_GRAY = '#797A7F';
export const ERROR_RED = '#F44336';
export const GEMWALLET_BLUE = '#87CEEB';
export const GEMWALLET_HALLOWEEN_ORANGE = '#FFA500';
4 changes: 4 additions & 0 deletions packages/extension/src/constants/storage.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
// Keys
export const STORAGE_CURRENT_WINDOW_ID = 'currentWindowId';
export const STORAGE_CUSTOM_NETWORKS = 'customNetworks';
export const STORAGE_FEATURE_FLAGS = 'featureFlags';
export const STORAGE_NETWORK = 'network';
export const STORAGE_PERMISSION_SUBMIT_BULK = 'permissionSubmitBulkTransactions';
export const STORAGE_REMEMBER_SESSION = 'rememberSession';
export const STORAGE_SELECTED_WALLET = 'selectedWallet';
export const STORAGE_STATE_TRANSACTION = 'hasTxInProgress';
export const STORAGE_TRUSTED_APPS = 'trustedApps';
export const STORAGE_WALLETS = 'wallets';

// TTL
export const TTL_FEATURE_FLAGS = 60 * 60 * 1000; // 1 hour
16 changes: 13 additions & 3 deletions packages/extension/src/contexts/NavBarContext/NavBarContext.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import { createContext, FC, useContext, useState } from 'react';
import { createContext, FC, useContext, useMemo, useState } from 'react';

import * as Sentry from '@sentry/react';

import { useFeatureFlags } from '../../hooks';

interface NavBarPosition {
left: string;
width: string;
Expand All @@ -10,6 +12,7 @@ interface NavBarPosition {
interface NavBarPositionContextType {
setNavBarPosition: (position: NavBarPosition) => void;
navBarPosition: NavBarPosition;
isHalloween: boolean;
}

const defaultPosition = {
Expand All @@ -19,15 +22,22 @@ const defaultPosition = {

const NavBarPositionContext = createContext<NavBarPositionContextType>({
setNavBarPosition: () => {},
navBarPosition: defaultPosition
navBarPosition: defaultPosition,
isHalloween: false
});

const NavBarPositionProvider: FC = ({ children }) => {
const [navBarPosition, setNavBarPosition] = useState<NavBarPosition>(defaultPosition);
const { featureFlags } = useFeatureFlags();

const isHalloween = useMemo<boolean>(() => {
return (featureFlags as any)['CITROUILLE_2K23'];
}, [featureFlags]);

const contextValue: NavBarPositionContextType = {
navBarPosition,
setNavBarPosition
setNavBarPosition,
isHalloween
};

return (
Expand Down
1 change: 1 addition & 0 deletions packages/extension/src/hooks/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
export * from './useBeforeUnload';
export * from './useFeatureFlags';
export * from './useFees';
export * from './useKeyUp';
export * from './useTimeout';
Expand Down
1 change: 1 addition & 0 deletions packages/extension/src/hooks/useFeatureFlags/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './useFeatureFlags';
Loading

0 comments on commit d08d421

Please sign in to comment.