Skip to content

Commit

Permalink
✨ feat: add light/dark theme switch
Browse files Browse the repository at this point in the history
Include a new switch button that allows users to
preview their README files for both light and
dark themes (default theme is dark one).

This feature aims to reduce the issue with black
colored icons (mostly devicons / simple icons)
being barely visible on the dark canvas. Also it
is a nice UX enhancement for those users who
simply prefer light theming.

Fixes: maurodesouza#44
  • Loading branch information
Martimex committed Feb 7, 2024
1 parent e49da3c commit 34b65a7
Show file tree
Hide file tree
Showing 5 changed files with 61 additions and 9 deletions.
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);
};
}

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();
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}
>
<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>

{hasSection && !previewMode && (
<S.Wrapper>
<S.Wrapper isLeftAligned={true}>
<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}>
<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
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
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',

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

0 comments on commit 34b65a7

Please sign in to comment.