feat: Preferences (Theme and Support)

This commit is contained in:
Anoop M D 2023-08-18 00:18:30 +05:30
parent bf5ee7e409
commit 417b50b0ad
11 changed files with 216 additions and 170 deletions

View File

@ -0,0 +1,36 @@
import styled from 'styled-components';
const StyledWrapper = styled.div`
div.tabs {
margin-top: -0.5rem;
div.tab {
padding: 6px 0px;
border: none;
border-bottom: solid 2px transparent;
margin-right: 1.25rem;
color: var(--color-tab-inactive);
cursor: pointer;
&:focus,
&:active,
&:focus-within,
&:focus-visible,
&:target {
outline: none !important;
box-shadow: none !important;
}
&.active {
color: ${(props) => props.theme.tabs.active.color} !important;
border-bottom: solid 2px ${(props) => props.theme.tabs.active.border} !important;
}
}
}
section.tab-panel {
min-height: 300px;
}
`;
export default StyledWrapper;

View File

@ -1,8 +1,8 @@
import styled from 'styled-components';
const StyledWrapper = styled.div`
color: var(--color-text);
.collection-options {
color: ${(props) => props.theme.text};
.rows {
svg {
position: relative;
top: -1px;

View File

@ -0,0 +1,44 @@
import React from 'react';
import { IconSpeakerphone, IconBrandTwitter, IconBrandGithub, IconBrandDiscord, IconBook } from '@tabler/icons';
import StyledWrapper from './StyledWrapper';
const Support = () => {
return (
<StyledWrapper>
<div className="rows">
<div>
<a href="https://docs.usebruno.com" target="_blank" className="flex items-end">
<IconBook size={18} strokeWidth={2} />
<span className="label ml-2">Documentation</span>
</a>
</div>
<div className="mt-2">
<a href="https://github.com/usebruno/bruno/issues" target="_blank" className="flex items-end">
<IconSpeakerphone size={18} strokeWidth={2} />
<span className="label ml-2">Report Issues</span>
</a>
</div>
<div className="mt-2">
<a href="https://discord.com/invite/KgcZUncpjq" target="_blank" className="flex items-end">
<IconBrandDiscord size={18} strokeWidth={2} />
<span className="label ml-2">Discord</span>
</a>
</div>
<div className="mt-2">
<a href="https://github.com/usebruno/bruno" target="_blank" className="flex items-end">
<IconBrandGithub size={18} strokeWidth={2} />
<span className="label ml-2">Github</span>
</a>
</div>
<div className="mt-2">
<a href="https://twitter.com/use_bruno" target="_blank" className="flex items-end">
<IconBrandTwitter size={18} strokeWidth={2} />
<span className="label ml-2">Twitter</span>
</a>
</div>
</div>
</StyledWrapper>
);
};
export default Support;

View File

@ -0,0 +1,7 @@
import styled from 'styled-components';
const StyledWrapper = styled.div`
color: var(--color-text);
`;
export default StyledWrapper;

View File

@ -0,0 +1,64 @@
import React from 'react';
import { useFormik } from 'formik';
import * as Yup from 'yup';
import StyledWrapper from './StyledWrapper';
import { useTheme } from 'providers/Theme';
const Theme = () => {
const { storedTheme, setStoredTheme } = useTheme();
const formik = useFormik({
enableReinitialize: true,
initialValues: {
theme: storedTheme
},
validationSchema: Yup.object({
theme: Yup.string().oneOf(['light', 'dark']).required('theme is required')
}),
onSubmit: (values) => {
setStoredTheme(values.theme);
}
});
return (
<StyledWrapper>
<div className='bruno-form'>
<div className="flex items-center mt-2">
<input
id="light-theme"
className="cursor-pointer"
type="radio"
name="theme"
onChange={(e) => {
formik.handleChange(e);
formik.handleSubmit()
}}
value="light"
checked={formik.values.theme === 'light'}
/>
<label htmlFor="light-theme" className="ml-1 cursor-pointer select-none">
Light
</label>
<input
id="dark-theme"
className="ml-4 cursor-pointer"
type="radio"
name="theme"
onChange={(e) => {
formik.handleChange(e);
formik.handleSubmit()
}}
value="dark"
checked={formik.values.theme === 'dark'}
/>
<label htmlFor="dark-theme" className="ml-1 cursor-pointer select-none">
Dark
</label>
</div>
</div>
</StyledWrapper>
);
};
export default Theme;

View File

@ -0,0 +1,53 @@
import Modal from 'components/Modal/index';
import classnames from 'classnames';
import React, { useState } from 'react';
import Support from './Support';
import Theme from './Theme';
import StyledWrapper from './StyledWrapper';
const Preferences = ({ onClose }) => {
const [tab, setTab] = useState('general');
const getTabClassname = (tabName) => {
return classnames(`tab select-none ${tabName}`, {
active: tabName === tab
});
};
const getTabPanel = (tab) => {
switch (tab) {
case 'general': {
return <div>General</div>;
}
case 'theme': {
return <Theme />;
}
case 'support': {
return <Support />;
}
}
};
return (
<StyledWrapper>
<Modal size="lg" title="Preferences" handleCancel={onClose} hideFooter={true}>
<div className="flex items-center px-2 tabs" role="tablist">
<div className={getTabClassname('general')} role="tab" onClick={() => setTab('general')}>
General
</div>
<div className={getTabClassname('theme')} role="tab" onClick={() => setTab('theme')}>
Theme
</div>
<div className={getTabClassname('support')} role="tab" onClick={() => setTab('support')}>
Support
</div>
</div>
<section className="flex flex-grow px-2 mt-4 tab-panel">{getTabPanel(tab)}</section>
</Modal>
</StyledWrapper>
);
};
export default Preferences;

View File

@ -1,19 +0,0 @@
import styled from 'styled-components';
const Wrapper = styled.div`
background-color: ${(props) => props.theme.menubar.bg};
color: rgba(255, 255, 255, 0.4);
min-height: 100vh;
.menu-item {
padding: 0.6rem;
cursor: pointer;
&:hover,
&.active {
color: rgba(255, 255, 255);
}
}
`;
export default Wrapper;

View File

@ -1,60 +0,0 @@
import { useState } from 'react';
import { useRouter } from 'next/router';
import { useDispatch } from 'react-redux';
import { isElectron } from 'utils/common/platform';
import { toggleLeftMenuBar } from 'providers/ReduxStore/slices/app';
import { IconCode, IconFiles, IconMoon, IconChevronsLeft, IconLifebuoy } from '@tabler/icons';
import Link from 'next/link';
import StyledWrapper from './StyledWrapper';
import BrunoSupport from 'components/BrunoSupport';
import SwitchTheme from 'components/SwitchTheme';
const MenuBar = () => {
const router = useRouter();
const dispatch = useDispatch();
const [openTheme, setOpenTheme] = useState(false);
const [openBrunoSupport, setOpenBrunoSupport] = useState(false);
const isPlatformElectron = isElectron();
const getClassName = (menu) => {
return router.pathname === menu ? 'active menu-item' : 'menu-item';
};
return (
<StyledWrapper className="h-full flex flex-col">
{openBrunoSupport && <BrunoSupport onClose={() => setOpenBrunoSupport(false)} />}
{openTheme && <SwitchTheme onClose={() => setOpenTheme(false)} />}
<div className="flex flex-col">
{/* Todo: Fix this: Clicking on this crashes the app */}
{/* <Link href="/">
<div className={getClassName('/')}>
<IconCode size={28} strokeWidth={1.5} />
</div>
</Link> */}
{/* <div className="menu-item">
<IconUsers size={28} strokeWidth={1.5}/>
</div> */}
</div>
<div className="flex flex-col flex-grow justify-end">
{/* <Link href="/login">
<div className="menu-item">
<IconUser size={28} strokeWidth={1.5}/>
</div>
</Link> */}
<div className="menu-item" onClick={() => setOpenBrunoSupport(true)}>
<IconLifebuoy size={28} strokeWidth={1.5}/>
</div>
<div className="menu-item" onClick={() => setOpenTheme(true)}>
<IconMoon size={28} strokeWidth={1.5}/>
</div>
<div className="menu-item" onClick={() => dispatch(toggleLeftMenuBar())}>
<IconChevronsLeft size={28} strokeWidth={1.5} />
</div>
</div>
</StyledWrapper>
);
};
export default MenuBar;

View File

@ -1,13 +1,13 @@
import MenuBar from './MenuBar';
import TitleBar from './TitleBar';
import Collections from './Collections';
import StyledWrapper, { BottomWrapper, VersionNumber } from './StyledWrapper';
import GitHubButton from 'react-github-btn'
import StyledWrapper from './StyledWrapper';
import GitHubButton from 'react-github-btn';
import Preferences from 'components/Preferences';
import { useState, useEffect } from 'react';
import { useSelector, useDispatch } from 'react-redux';
import { IconChevronsRight } from '@tabler/icons';
import { updateLeftSidebarWidth, updateIsDragging, toggleLeftMenuBar } from 'providers/ReduxStore/slices/app';
import { IconSettings } from '@tabler/icons';
import { updateLeftSidebarWidth, updateIsDragging } from 'providers/ReduxStore/slices/app';
import { useTheme } from 'providers/Theme';
const MIN_LEFT_SIDEBAR_WIDTH = 222;
@ -15,7 +15,7 @@ const MAX_LEFT_SIDEBAR_WIDTH = 600;
const Sidebar = () => {
const leftSidebarWidth = useSelector((state) => state.app.leftSidebarWidth);
const leftMenuBarOpen = useSelector((state) => state.app.leftMenuBarOpen);
const [ preferencesOpen, setPreferencesOpen ] = useState(false);
const [asideWidth, setAsideWidth] = useState(leftSidebarWidth);
@ -76,16 +76,14 @@ const Sidebar = () => {
setAsideWidth(leftSidebarWidth);
}, [leftSidebarWidth]);
const leftMenuBarWidth = leftMenuBarOpen ? 48 : 0;
const collectionsWidth = asideWidth - leftMenuBarWidth;
return (
<StyledWrapper className="flex relative">
<aside>
<div className="flex flex-row h-full w-full">
{leftMenuBarOpen && <MenuBar />}
{preferencesOpen && <Preferences onClose={() => setPreferencesOpen(false)} />}
<div className="flex flex-col w-full" style={{width: collectionsWidth}}>
<div className="flex flex-col w-full" style={{width: asideWidth}}>
<div className="flex flex-col flex-grow">
<TitleBar />
<Collections />
@ -93,8 +91,7 @@ const Sidebar = () => {
<div className="footer flex px-1 py-2 items-center cursor-pointer select-none">
<div className="flex items-center ml-1 text-xs ">
{!leftMenuBarOpen && <IconChevronsRight size={24} strokeWidth={1.5} className="mr-2 hover:text-gray-700" onClick={() => dispatch(toggleLeftMenuBar())} />}
{/* <IconLayoutGrid size={20} strokeWidth={1.5} className="mr-2"/> */}
<IconSettings size={18} strokeWidth={1.5} className="mr-2 hover:text-gray-700" onClick={() => setPreferencesOpen(true)} />
</div>
<div className="pl-1" style={{position: 'relative', top: '3px'}}>
{storedTheme === 'dark' ? (

View File

@ -1,67 +0,0 @@
import React from 'react';
import { useFormik } from 'formik';
import * as Yup from 'yup';
import Modal from 'components/Modal/index';
import StyledWrapper from './StyledWrapper';
import { useTheme } from 'providers/Theme';
const SwitchTheme = ({ onClose }) => {
const { storedTheme, setStoredTheme } = useTheme();
const formik = useFormik({
enableReinitialize: true,
initialValues: {
theme: storedTheme
},
validationSchema: Yup.object({
theme: Yup.string().oneOf(['light', 'dark']).required('theme is required')
}),
onSubmit: (values) => {
setStoredTheme(values.theme);
}
});
return (
<StyledWrapper>
<Modal size="sm" title={'Switch Theme'} handleCancel={onClose} hideFooter={true}>
<div className='bruno-form'>
<div className="flex items-center mt-2">
<input
id="light-theme"
className="cursor-pointer"
type="radio"
name="theme"
onChange={(e) => {
formik.handleChange(e);
formik.handleSubmit()
}}
value="light"
checked={formik.values.theme === 'light'}
/>
<label htmlFor="light-theme" className="ml-1 cursor-pointer select-none">
Light
</label>
<input
id="dark-theme"
className="ml-4 cursor-pointer"
type="radio"
name="theme"
onChange={(e) => {
formik.handleChange(e);
formik.handleSubmit()
}}
value="dark"
checked={formik.values.theme === 'dark'}
/>
<label htmlFor="dark-theme" className="ml-1 cursor-pointer select-none">
Dark
</label>
</div>
</div>
</Modal>
</StyledWrapper>
);
};
export default SwitchTheme;

View File

@ -4,7 +4,6 @@ const initialState = {
isDragging: false,
idbConnectionReady: false,
leftSidebarWidth: 222,
leftMenuBarOpen: false,
screenWidth: 500,
showHomePage: false
};
@ -16,14 +15,6 @@ export const appSlice = createSlice({
idbConnectionReady: (state) => {
state.idbConnectionReady = true;
},
toggleLeftMenuBar: (state) => {
state.leftMenuBarOpen = !state.leftMenuBarOpen;
if(state.leftMenuBarOpen) {
state.leftSidebarWidth += 48;
} else {
state.leftSidebarWidth -= 48;
}
},
refreshScreenWidth: (state) => {
state.screenWidth = window.innerWidth;
},
@ -42,6 +33,6 @@ export const appSlice = createSlice({
}
});
export const { idbConnectionReady, toggleLeftMenuBar, refreshScreenWidth, updateLeftSidebarWidth, updateIsDragging, showHomePage, hideHomePage } = appSlice.actions;
export const { idbConnectionReady, refreshScreenWidth, updateLeftSidebarWidth, updateIsDragging, showHomePage, hideHomePage } = appSlice.actions;
export default appSlice.reducer;