Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

✨ feat: add light/dark theme switch #68

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions src/app/events/handles/canvas.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,10 @@ class CanvasHandleEvents extends BaseEventHandle {
currentSection = (sectionId: string) => {
this.emit(Events.CANVAS_SET_CURRENT_SECTION, sectionId);
};

switchTheme = (theme: boolean) => {
this.emit(Events.CANVAS_SWITCH_THEME, theme);
};
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Move it to the app handle (the file need to be created)

import { themes } from "styles"
import { Modals, Events } from 'types';

import { BaseEventHandle } from './base';

class AppHandleEvents extends BaseEventHandle {
  constructor() {
    super();

    this.close = this.close.bind(this);
  }

  theme(theme: keyof typeof themes) {
    this.emit(Events.APP_SET_THEME, theme);
  }
}

export { ModalHandleEvents };

Then, include it in the index handles

  app = new AppHandleEvents();

}

export { CanvasHandleEvents };
25 changes: 22 additions & 3 deletions src/components/canvas/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import { Reorder } from 'framer-motion';
import {
Trash as TrashIcon,
Check as CheckIcon,
Moon as MoonIcon,
Sun as SunIcon,
X as CloseIcon,
} from '@styled-icons/feather';

Expand All @@ -24,7 +26,7 @@ import { CanvasErrorFallback } from './error';

const Canvas = () => {
const { extensions } = useExtensions();
const { sections, currentSection, previewMode } = useCanvas();
const { sections, currentSection, previewMode, lightTheme } = useCanvas();
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here, that logic with be moved to the pages/_app.tsx

const { theme } = useTheme();

const curTheme = themes[theme]

return (
  <ThemeProvider theme={curTheme }>
  ...
)

const [hasError, setHasError] = useState(false);

const sectionIds = sections.map(section => section.id);
Expand All @@ -41,9 +43,26 @@ const Canvas = () => {
<S.Container
onContextMenu={handleOpenContextMenu}
fullHeight={hasError || !hasSection}
isLightTheme={lightTheme}
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It can be removed

>
<S.Wrapper isLeftAligned={false}>
<Tooltip
position="right"
content={`Preview: ${lightTheme ? 'dark' : 'light'} mode`}
variant="info"
>
<S.Button
aria-label={`Preview: ${lightTheme ? 'dark' : 'light'} mode`}
onClick={() => events.canvas.switchTheme(lightTheme)}
variant="success"
>
{lightTheme ? <MoonIcon size={16} /> : <SunIcon size={16} />}
</S.Button>
</Tooltip>
</S.Wrapper>
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The theme switch can be done together with the other actions.

image

And keep it on the template preview.

image


{hasSection && !previewMode && (
<S.Wrapper>
<S.Wrapper isLeftAligned={true}>
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It can be removed

<Tooltip position="left" content="Clear canvas" variant="danger">
<S.Button
aria-label="Clear canvas"
Expand All @@ -61,7 +80,7 @@ const Canvas = () => {
onChange={setHasError}
>
{previewMode && (
<S.Wrapper>
<S.Wrapper isLeftAligned={true}>
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It can be removed

<Tooltip position="left" content="Use template" variant="success">
<S.Button
aria-label="Use template"
Expand Down
23 changes: 19 additions & 4 deletions src/components/canvas/styles.ts
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All changes in this file can be reverted because we will use the theme feature of the styled-components to make the theme change.

ref: https://styled-components.com/docs/advanced#theming

Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,15 @@ import styled, { css, DefaultTheme } from 'styled-components';

type ContainerProps = {
fullHeight: boolean;
isLightTheme: boolean;
};

type WrapperProps = {
isLeftAligned: boolean;
};

export const Container = styled.div<ContainerProps>`
${({ theme, fullHeight }) => css`
${({ theme, fullHeight, isLightTheme }) => css`
padding: ${theme.spacings.xlarge};
border-radius: ${theme.border.radius};
border-width: ${theme.border.width};
Expand All @@ -16,6 +21,10 @@ export const Container = styled.div<ContainerProps>`
padding-right: ${theme.spacings.small};
height: ${fullHeight ? '100%' : 'auto'};

background: ${isLightTheme && '#eee'};
color: ${isLightTheme && theme.colors.bg};
transition: color 0.25s linear, background 0.25s linear;

&::-webkit-scrollbar {
width: 0.8rem;
overflow: hidden;
Expand All @@ -31,8 +40,8 @@ export const Container = styled.div<ContainerProps>`
`}
`;

export const Wrapper = styled.div`
${({ theme }) => css`
export const Wrapper = styled.div<WrapperProps>`
${({ theme, isLeftAligned }) => css`
width: 3rem;
position: absolute;
display: flex;
Expand All @@ -44,7 +53,7 @@ export const Wrapper = styled.div`
color: ${theme.colors.text};

top: ${theme.spacings.medium};
left: 0;
left: ${isLeftAligned ? '0%' : '100%'};
transform: translateX(-50%);
transition: 0.3s;

Expand Down Expand Up @@ -75,6 +84,12 @@ const buttonModifiers = {
color: ${theme.colors.secondary};
}
`,

info: (theme: DefaultTheme) => css`
&:hover {
color: ${theme.colors.primary};
}
`,
};

export const Button = styled.button<ButtonsProps>`
Expand Down
17 changes: 15 additions & 2 deletions src/contexts/canvas.tsx
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The theme switch logic needs to be separated into another react context, which can be called ThemeContext

Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ type CanvasContextData = {
sections: CanvasSection[];
currentSection?: CanvasSection;
previewMode: boolean;
lightTheme: boolean;
};

type CanvasProviderProps = {
Expand All @@ -32,6 +33,7 @@ const CanvasProvider = ({ children }: CanvasProviderProps) => {
[]
);

const [lightTheme, setLightTheme] = useState(false);
const [currentSection, setCurrentSection] = useState<CanvasSection>();
const [previewTemplate, setPreviewTemplate] = useState<CanvasSection[]>([]);

Expand Down Expand Up @@ -135,6 +137,10 @@ const CanvasProvider = ({ children }: CanvasProviderProps) => {

const handleClearCanvas = () => setSections([]);

const handleSwitchTheme = () => {
setLightTheme(!lightTheme);
};

useEffect(() => {
// Canvas events

Expand All @@ -144,6 +150,7 @@ const CanvasProvider = ({ children }: CanvasProviderProps) => {
events.on(Events.CANVAS_REORDER_SECTIONS, handleReorderSections);
events.on(Events.CANVAS_DUPLICATE_SECTION, handleDuplicateSection);
events.on(Events.CANVAS_CLEAR_SECTIONS, handleClearCanvas);
events.on(Events.CANVAS_SWITCH_THEME, handleSwitchTheme);

return () => {
events.off(Events.CANVAS_EDIT_SECTION, handleEditSection);
Expand All @@ -152,8 +159,9 @@ const CanvasProvider = ({ children }: CanvasProviderProps) => {
events.off(Events.CANVAS_REORDER_SECTIONS, handleReorderSections);
events.off(Events.CANVAS_DUPLICATE_SECTION, handleDuplicateSection);
events.off(Events.CANVAS_CLEAR_SECTIONS, handleClearCanvas);
events.off(Events.CANVAS_SWITCH_THEME, handleSwitchTheme);
};
}, [sections, currentSection]);
}, [sections, currentSection, lightTheme]);

useEffect(() => {
// Canvas events
Expand Down Expand Up @@ -182,7 +190,12 @@ const CanvasProvider = ({ children }: CanvasProviderProps) => {

return (
<CanvasContext.Provider
value={{ sections: canvas, currentSection, previewMode }}
value={{
sections: canvas,
currentSection,
previewMode,
lightTheme: lightTheme,
}}
>
{children}
</CanvasContext.Provider>
Expand Down
1 change: 1 addition & 0 deletions src/types/events.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ export enum Events {
CANVAS_REORDER_SECTIONS = 'canvas.section.reorder',
CANVAS_DUPLICATE_SECTION = 'canvas.section.duplicate',
CANVAS_CLEAR_SECTIONS = 'canvas.clear',
CANVAS_SWITCH_THEME = 'canvas.switchTheme',
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Change the event name to APP_SET_THEME = "app.set.theme"


TEMPLATE_USE = 'template.use',
TEMPLATE_PREVIEW = 'template.preview',
Expand Down