forked from crowetic/commerce
Footer theme switcher (#894)
* Footer theme switcher * Remove lazy loading & change rotation animation * Changes * Update ThemeSwitcher.tsx * Requested style changes * Update ThemeSwitcher.tsx * Fix alignment * Update ThemeSwitcher.tsx
This commit is contained in:
parent
6bc223adb3
commit
6d783eae35
@ -7,6 +7,7 @@ import getSlug from '@lib/get-slug'
|
||||
import { Github, Vercel } from '@components/icons'
|
||||
import { Logo, Container } from '@components/ui'
|
||||
import { I18nWidget } from '@components/common'
|
||||
import ThemeSwitcher from '@components/ui/ThemeSwitcher'
|
||||
import s from './Footer.module.css'
|
||||
|
||||
interface Props {
|
||||
@ -40,7 +41,7 @@ const Footer: FC<Props> = ({ className, pages }) => {
|
||||
</a>
|
||||
</Link>
|
||||
</div>
|
||||
<div className="col-span-1 lg:col-span-8">
|
||||
<div className="col-span-1 lg:col-span-7">
|
||||
<div className="grid md:grid-rows-4 md:grid-cols-3 md:grid-flow-col">
|
||||
{[...links, ...sitePages].map((page) => (
|
||||
<span key={page.url} className="py-3 md:py-0 md:pb-4">
|
||||
@ -53,8 +54,10 @@ const Footer: FC<Props> = ({ className, pages }) => {
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
<div className="col-span-1 lg:col-span-2 flex items-start lg:justify-end text-primary">
|
||||
<div className="flex space-x-6 items-center h-10">
|
||||
<div className="col-span-1 lg:col-span-3 flex items-start lg:justify-end text-primary">
|
||||
<div className="flex space-x-4 items-center h-10">
|
||||
<ThemeSwitcher />
|
||||
<I18nWidget />
|
||||
<a
|
||||
className={s.link}
|
||||
aria-label="Github Repository"
|
||||
@ -62,7 +65,6 @@ const Footer: FC<Props> = ({ className, pages }) => {
|
||||
>
|
||||
<Github />
|
||||
</a>
|
||||
<I18nWidget />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -3,7 +3,7 @@
|
||||
}
|
||||
|
||||
.button {
|
||||
@apply h-10 px-2 rounded-md border border-accent-2 flex items-center justify-center transition-colors ease-linear;
|
||||
@apply h-10 pl-2 pr-1 rounded-md border border-accent-2 flex items-center justify-center transition-colors ease-linear;
|
||||
}
|
||||
|
||||
.button:hover {
|
||||
@ -32,7 +32,7 @@
|
||||
}
|
||||
|
||||
.icon.active {
|
||||
transform: rotate(180deg);
|
||||
transform: rotate(90deg);
|
||||
}
|
||||
|
||||
@screen lg {
|
||||
|
@ -3,7 +3,7 @@ import Link from 'next/link'
|
||||
import { FC, useState } from 'react'
|
||||
import { useRouter } from 'next/router'
|
||||
import s from './I18nWidget.module.css'
|
||||
import { Cross, ChevronUp } from '@components/icons'
|
||||
import { Cross, ChevronRight } from '@components/icons'
|
||||
import ClickOutside from '@lib/click-outside'
|
||||
import Image from 'next/image'
|
||||
interface LOCALE_DATA {
|
||||
@ -54,14 +54,14 @@ const I18nWidget: FC = () => {
|
||||
<Image
|
||||
width="20"
|
||||
height="20"
|
||||
className="block mr-2 w-5"
|
||||
className="block w-5"
|
||||
src={`/${LOCALES_MAP[currentLocale].img.filename}`}
|
||||
alt={LOCALES_MAP[currentLocale].img.alt}
|
||||
unoptimized
|
||||
/>
|
||||
{options && (
|
||||
<span className="cursor-pointer">
|
||||
<ChevronUp className={cn(s.icon, { [s.active]: display })} />
|
||||
<span className="cursor-pointer ml-1">
|
||||
<ChevronRight className={cn(s.icon, { [s.active]: display })} />
|
||||
</span>
|
||||
)}
|
||||
</button>
|
||||
|
19
site/components/icons/System.tsx
Normal file
19
site/components/icons/System.tsx
Normal file
@ -0,0 +1,19 @@
|
||||
const System = ({ ...props }) => (
|
||||
<svg
|
||||
data-testid="geist-icon"
|
||||
fill="none"
|
||||
height="16"
|
||||
shapeRendering="geometricPrecision"
|
||||
stroke="currentColor"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
strokeWidth="1.5"
|
||||
viewBox="0 0 24 24"
|
||||
className="text-current"
|
||||
{...props}
|
||||
>
|
||||
<path d="M2 13.381h20M8.66 19.05V22m6.84-2.95V22m-8.955 0h10.932M4 19.05h16a2 2 0 002-2V4a2 2 0 00-2-2H4a2 2 0 00-2 2v13.05a2 2 0 002 2z"></path>
|
||||
</svg>
|
||||
)
|
||||
|
||||
export default System
|
@ -11,6 +11,7 @@ export { default as Cross } from './Cross'
|
||||
export { default as Minus } from './Minus'
|
||||
export { default as Check } from './Check'
|
||||
export { default as Github } from './Github'
|
||||
export { default as System } from './System'
|
||||
export { default as Vercel } from './Vercel'
|
||||
export { default as MapPin } from './MapPin'
|
||||
export { default as ArrowLeft } from './ArrowLeft'
|
||||
|
22
site/components/ui/ThemeSwitcher/ThemeIcon.tsx
Normal file
22
site/components/ui/ThemeSwitcher/ThemeIcon.tsx
Normal file
@ -0,0 +1,22 @@
|
||||
import { Moon, Sun, System } from '@components/icons'
|
||||
|
||||
interface ThemeIconProps {
|
||||
theme?: string
|
||||
width: number
|
||||
height: number
|
||||
}
|
||||
|
||||
const ThemeIcon = ({ theme, ...props }: ThemeIconProps) => {
|
||||
switch (theme) {
|
||||
case 'light':
|
||||
return <Sun {...props} />
|
||||
|
||||
case 'dark':
|
||||
return <Moon {...props} />
|
||||
|
||||
default:
|
||||
return <System {...props} />
|
||||
}
|
||||
}
|
||||
|
||||
export default ThemeIcon
|
80
site/components/ui/ThemeSwitcher/ThemeSwitcher.tsx
Normal file
80
site/components/ui/ThemeSwitcher/ThemeSwitcher.tsx
Normal file
@ -0,0 +1,80 @@
|
||||
import { useState } from 'react'
|
||||
import { ChevronRight, Cross } from '@components/icons'
|
||||
import { useToggleTheme } from '@lib/hooks/useToggleTheme'
|
||||
import cn from 'clsx'
|
||||
import ClickOutside from '@lib/click-outside'
|
||||
import ThemeIcon from './ThemeIcon'
|
||||
|
||||
const ThemeSwitcher = () => {
|
||||
const [display, setDisplay] = useState(false)
|
||||
const { theme, themes, setTheme } = useToggleTheme()
|
||||
|
||||
return (
|
||||
<ClickOutside active={display} onClick={() => setDisplay(false)}>
|
||||
<div className="relative">
|
||||
<div
|
||||
className="flex items-center relative"
|
||||
onClick={() => setDisplay(!display)}
|
||||
>
|
||||
<button
|
||||
className={
|
||||
'w-[125px] h-10 pl-2 pr-1 rounded-md border border-accent-2 flex items-center justify-between transition-colors ease-linear hover:border-accent-3 hover:shadow-sm'
|
||||
}
|
||||
aria-label="Theme Switcher"
|
||||
>
|
||||
<span className="flex flex-shrink items-center">
|
||||
<ThemeIcon width={20} height={20} theme={theme} />
|
||||
<span className={cn('capitalize leading-none ml-2')}>
|
||||
{theme}
|
||||
</span>
|
||||
</span>
|
||||
<span className="cursor-pointer">
|
||||
<ChevronRight
|
||||
className={cn('transition duration-300', {
|
||||
['rotate-90']: display,
|
||||
})}
|
||||
/>
|
||||
</span>
|
||||
</button>
|
||||
</div>
|
||||
<div className="absolute top-0 right-0">
|
||||
{themes.length && display ? (
|
||||
<div
|
||||
className={
|
||||
'fixed shadow-lg right-0 top-12 mt-2 origin-top-right w-full h-full outline-none bg-accent-0 z-40 lg:absolute lg:border lg:border-accent-1 lg:shadow-lg lg:w-56 lg:h-auto'
|
||||
}
|
||||
>
|
||||
<div className="flex flex-row justify-end px-6">
|
||||
<button
|
||||
className="md:hidden"
|
||||
onClick={() => setDisplay(false)}
|
||||
aria-label="Close panel"
|
||||
>
|
||||
<Cross className="h-6 w-6" />
|
||||
</button>
|
||||
</div>
|
||||
<ul>
|
||||
{themes.map((t: string) => (
|
||||
<li key={t}>
|
||||
<button
|
||||
className="flex w-full capitalize cursor-pointer px-6 py-3 transition ease-in-out duration-150 text-primary leading-6 font-medium items-center hover:bg-accent-1"
|
||||
role={'link'}
|
||||
onClick={() => {
|
||||
setTheme(t)
|
||||
setDisplay(false)
|
||||
}}
|
||||
>
|
||||
{t}
|
||||
</button>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
) : null}
|
||||
</div>
|
||||
</div>
|
||||
</ClickOutside>
|
||||
)
|
||||
}
|
||||
|
||||
export default ThemeSwitcher
|
1
site/components/ui/ThemeSwitcher/index.ts
Normal file
1
site/components/ui/ThemeSwitcher/index.ts
Normal file
@ -0,0 +1 @@
|
||||
export { default } from './ThemeSwitcher'
|
11
site/lib/hooks/useToggleTheme.ts
Normal file
11
site/lib/hooks/useToggleTheme.ts
Normal file
@ -0,0 +1,11 @@
|
||||
import { useTheme } from 'next-themes'
|
||||
import { useEffect, useState } from 'react'
|
||||
|
||||
export const useToggleTheme = () => {
|
||||
const { theme, themes, setTheme } = useTheme()
|
||||
const [themeValue, setThemeValue] = useState<string>('system')
|
||||
|
||||
useEffect(() => setThemeValue(theme), [theme])
|
||||
|
||||
return { theme: themeValue, setTheme, themes }
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user