From 00184e674ff469e4ccf25d38f05f73f5159844c7 Mon Sep 17 00:00:00 2001
From: cond0r <1243434+cond0r@users.noreply.github.com>
Date: Tue, 29 Nov 2022 20:07:16 +0200
Subject: [PATCH] Footer theme switcher

---
 site/components/common/Footer/Footer.tsx      | 17 +++-
 site/components/icons/System.tsx              | 19 +++++
 site/components/icons/index.ts                |  1 +
 .../components/ui/ThemeSwitcher/ThemeIcon.tsx | 22 ++++++
 .../ui/ThemeSwitcher/ThemeSwitcher.tsx        | 77 +++++++++++++++++++
 site/components/ui/ThemeSwitcher/index.ts     |  1 +
 6 files changed, 133 insertions(+), 4 deletions(-)
 create mode 100644 site/components/icons/System.tsx
 create mode 100644 site/components/ui/ThemeSwitcher/ThemeIcon.tsx
 create mode 100644 site/components/ui/ThemeSwitcher/ThemeSwitcher.tsx
 create mode 100644 site/components/ui/ThemeSwitcher/index.ts

diff --git a/site/components/common/Footer/Footer.tsx b/site/components/common/Footer/Footer.tsx
index 18e9b4027..b2447f0cd 100644
--- a/site/components/common/Footer/Footer.tsx
+++ b/site/components/common/Footer/Footer.tsx
@@ -1,6 +1,7 @@
 import { FC } from 'react'
 import cn from 'clsx'
 import Link from 'next/link'
+import dynamic from 'next/dynamic'
 import { useRouter } from 'next/router'
 import type { Page } from '@commerce/types/page'
 import getSlug from '@lib/get-slug'
@@ -9,6 +10,13 @@ import { Logo, Container } from '@components/ui'
 import { I18nWidget } from '@components/common'
 import s from './Footer.module.css'
 
+const ThemeSwitcher = dynamic(() => import('@components/ui/ThemeSwitcher'), {
+  ssr: false,
+  loading: () => (
+    <div className="w-24 h-10 rounded-md bg-accent-2 animate-pulse" />
+  ),
+})
+
 interface Props {
   className?: string
   children?: any
@@ -40,7 +48,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 +61,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 +72,6 @@ const Footer: FC<Props> = ({ className, pages }) => {
               >
                 <Github />
               </a>
-              <I18nWidget />
             </div>
           </div>
         </div>
diff --git a/site/components/icons/System.tsx b/site/components/icons/System.tsx
new file mode 100644
index 000000000..bb7367c7a
--- /dev/null
+++ b/site/components/icons/System.tsx
@@ -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
diff --git a/site/components/icons/index.ts b/site/components/icons/index.ts
index 12e0cc202..72a65494c 100644
--- a/site/components/icons/index.ts
+++ b/site/components/icons/index.ts
@@ -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'
diff --git a/site/components/ui/ThemeSwitcher/ThemeIcon.tsx b/site/components/ui/ThemeSwitcher/ThemeIcon.tsx
new file mode 100644
index 000000000..ae998602c
--- /dev/null
+++ b/site/components/ui/ThemeSwitcher/ThemeIcon.tsx
@@ -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
diff --git a/site/components/ui/ThemeSwitcher/ThemeSwitcher.tsx b/site/components/ui/ThemeSwitcher/ThemeSwitcher.tsx
new file mode 100644
index 000000000..55671afc9
--- /dev/null
+++ b/site/components/ui/ThemeSwitcher/ThemeSwitcher.tsx
@@ -0,0 +1,77 @@
+import { useState } from 'react'
+import { useTheme } from 'next-themes'
+import { ChevronUp, Cross } from '@components/icons'
+
+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 } = useTheme()
+
+  return (
+    <ClickOutside active={display} onClick={() => setDisplay(false)}>
+      <nav className="relative">
+        <div
+          className="flex items-center relative"
+          onClick={() => setDisplay(!display)}
+        >
+          <button
+            className={
+              'h-10 px-2 rounded-md border border-accent-2 flex items-center justify-center transition-colors ease-linear space-x-2 hover:border-accent-3 hover:shadow-sm'
+            }
+            aria-label="Theme Switcher"
+          >
+            <ThemeIcon width={20} height={20} theme={theme} />
+            <span className="capitalize">{theme}</span>
+            <span className="cursor-pointer">
+              <ChevronUp
+                className={cn('transition duration-300', {
+                  ['rotate-180']: 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>
+      </nav>
+    </ClickOutside>
+  )
+}
+
+export default ThemeSwitcher
diff --git a/site/components/ui/ThemeSwitcher/index.ts b/site/components/ui/ThemeSwitcher/index.ts
new file mode 100644
index 000000000..2b4931135
--- /dev/null
+++ b/site/components/ui/ThemeSwitcher/index.ts
@@ -0,0 +1 @@
+export { default } from './ThemeSwitcher'