mirror of
https://github.com/vercel/commerce.git
synced 2025-06-07 16:56:59 +00:00
allow users to add their own theme config and logo
This commit is contained in:
parent
27fd18ad9f
commit
9479e9bc5b
19
README.md
19
README.md
@ -98,6 +98,25 @@ For example: Turning `cart` off will disable Cart capabilities.
|
||||
- Turn `wishlist` on by setting `wishlist` to `true`.
|
||||
- Run the app and the wishlist functionality should be back on.
|
||||
|
||||
#### Customizing the theme
|
||||
|
||||
You can customize the theme by providing some configuration in `theme.json`
|
||||
|
||||
- open `theme.json`
|
||||
- You'll see a config file like this:
|
||||
|
||||
```json
|
||||
{
|
||||
"features": {
|
||||
"logo": false // => switch to true to enable logo
|
||||
},
|
||||
"theme": {
|
||||
"logoSrc": "replace with the path in `public` your logo ex: /assets/logo.svg",
|
||||
"logoAlt": "Replace with your logo alt text"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### How to create a new provider
|
||||
|
||||
Follow our docs for [Adding a new Commerce Provider](packages/commerce/new-provider.md).
|
||||
|
@ -1,15 +1,11 @@
|
||||
import { FC, useEffect, useState, useCallback } from 'react'
|
||||
import { validate } from 'email-validator'
|
||||
import { useUI } from '@components/ui/context'
|
||||
import { AcmeLogo, Button, Input } from '@components/ui'
|
||||
import { useCommerce } from '@framework'
|
||||
import { Logo, Button, Input } from '@components/ui'
|
||||
|
||||
interface Props {}
|
||||
|
||||
const ForgotPassword: FC<Props> = () => {
|
||||
// @ts-ignore
|
||||
const { brand = {} } = useCommerce()
|
||||
const { Logo = AcmeLogo } = brand
|
||||
// Form State
|
||||
const [email, setEmail] = useState('')
|
||||
const [loading, setLoading] = useState(false)
|
||||
|
@ -1,14 +1,11 @@
|
||||
import { FC, useEffect, useState, useCallback } from 'react'
|
||||
import { AcmeLogo, Button, Input } from '@components/ui'
|
||||
import { Logo, Button, Input } from '@components/ui'
|
||||
import useLogin from '@framework/auth/use-login'
|
||||
import { useUI } from '@components/ui/context'
|
||||
import { validate } from 'email-validator'
|
||||
import { useCommerce } from '@framework'
|
||||
|
||||
const LoginView: React.FC = () => {
|
||||
// @ts-ignore
|
||||
const { brand = {} } = useCommerce()
|
||||
const { Logo = AcmeLogo } = brand
|
||||
// Form State
|
||||
const [email, setEmail] = useState('')
|
||||
const [password, setPassword] = useState('')
|
||||
|
@ -2,15 +2,12 @@ import { FC, useEffect, useState, useCallback } from 'react'
|
||||
import { validate } from 'email-validator'
|
||||
import { Info } from '@components/icons'
|
||||
import { useUI } from '@components/ui/context'
|
||||
import { AcmeLogo, Button, Input } from '@components/ui'
|
||||
import { Button, Input, Logo } from '@components/ui'
|
||||
import useSignup from '@framework/auth/use-signup'
|
||||
|
||||
interface Props {}
|
||||
|
||||
const SignUpView: FC<Props> = () => {
|
||||
// @ts-ignore
|
||||
const { brand = {} } = useCommerce()
|
||||
const { Logo = AcmeLogo } = brand
|
||||
// Form State
|
||||
const [email, setEmail] = useState('')
|
||||
const [password, setPassword] = useState('')
|
||||
|
@ -5,7 +5,7 @@ import { useRouter } from 'next/router'
|
||||
import type { Page } from '@commerce/types/page'
|
||||
import getSlug from '@lib/get-slug'
|
||||
import { Github, Vercel } from '@components/icons'
|
||||
import { AcmeLogo, Container } from '@components/ui'
|
||||
import { Logo, Container } from '@components/ui'
|
||||
import { I18nWidget } from '@components/common'
|
||||
import s from './Footer.module.css'
|
||||
import { useCommerce } from '@framework'
|
||||
@ -26,9 +26,6 @@ const links = [
|
||||
const Footer: FC<Props> = ({ className, pages }) => {
|
||||
const { sitePages } = usePages(pages)
|
||||
const rootClassName = cn(s.root, className)
|
||||
// @ts-ignore
|
||||
const { brand = {} } = useCommerce()
|
||||
const { Logo = AcmeLogo } = brand
|
||||
|
||||
return (
|
||||
<footer className={rootClassName}>
|
||||
|
@ -2,7 +2,7 @@ import { FC } from 'react'
|
||||
import Link from 'next/link'
|
||||
import s from './Navbar.module.css'
|
||||
import NavbarRoot from './NavbarRoot'
|
||||
import { AcmeLogo, Container } from '@components/ui'
|
||||
import { Logo, Container } from '@components/ui'
|
||||
import { Searchbar, UserNav } from '@components/common'
|
||||
import { useCommerce } from '@framework'
|
||||
|
||||
@ -16,9 +16,6 @@ interface NavbarProps {
|
||||
}
|
||||
|
||||
const Navbar: FC<NavbarProps> = ({ links }) => {
|
||||
// @ts-ignore
|
||||
const { brand = {} } = useCommerce()
|
||||
const { Logo = AcmeLogo } = brand
|
||||
return (
|
||||
<NavbarRoot>
|
||||
<Container clean className="mx-auto max-w-8xl px-6">
|
||||
|
@ -1,4 +1,8 @@
|
||||
const AcmeLogo = ({ className = '', ...props }) => (
|
||||
import { useCommerce } from '@framework'
|
||||
import Image from 'next/image'
|
||||
import { useUI } from '../context'
|
||||
|
||||
const DefaultLogo = ({ className = '', ...props }) => (
|
||||
<svg
|
||||
width="32"
|
||||
height="32"
|
||||
@ -18,4 +22,26 @@ const AcmeLogo = ({ className = '', ...props }) => (
|
||||
</svg>
|
||||
)
|
||||
|
||||
export default AcmeLogo
|
||||
const Logo = ({ className = '', ...props }) => {
|
||||
const { theme } = useUI()
|
||||
console.log(theme)
|
||||
// @ts-ignore
|
||||
const { brand = {} } = useCommerce()
|
||||
const { Logo = DefaultLogo } = brand
|
||||
|
||||
if (theme.logoSrc && theme.logoAlt) {
|
||||
return (
|
||||
<Image
|
||||
src={theme.logoSrc}
|
||||
alt={theme.logoAlt}
|
||||
{...props}
|
||||
height={32}
|
||||
width={32}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
return <Logo />
|
||||
}
|
||||
|
||||
export default Logo
|
||||
|
@ -1,6 +1,8 @@
|
||||
import React, { FC, useCallback, useMemo } from 'react'
|
||||
import { ThemeProvider } from 'next-themes'
|
||||
|
||||
import { features, theme } from 'config/theme.json'
|
||||
|
||||
export interface State {
|
||||
displaySidebar: boolean
|
||||
displayDropdown: boolean
|
||||
@ -17,6 +19,9 @@ const initialState = {
|
||||
modalView: 'LOGIN_VIEW',
|
||||
sidebarView: 'CART_VIEW',
|
||||
userAvatar: '',
|
||||
theme: {
|
||||
...(features.logo && { logoSrc: theme.logoSrc, logoAlt: theme.logoAlt }),
|
||||
},
|
||||
}
|
||||
|
||||
type Action =
|
||||
@ -198,6 +203,8 @@ export const UIProvider: FC = (props) => {
|
||||
[state]
|
||||
)
|
||||
|
||||
console.log(value)
|
||||
|
||||
return <UIContext.Provider value={value} {...props} />
|
||||
}
|
||||
|
||||
@ -209,6 +216,14 @@ export const useUI = () => {
|
||||
return context
|
||||
}
|
||||
|
||||
export const useTheme = () => {
|
||||
const context = React.useContext(UIContext)
|
||||
if (context === undefined) {
|
||||
throw new Error(`useTheme must be used within a UIProvider`)
|
||||
}
|
||||
return context.theme
|
||||
}
|
||||
|
||||
export const ManagedUIContext: FC = ({ children }) => (
|
||||
<UIProvider>
|
||||
<ThemeProvider>{children}</ThemeProvider>
|
||||
|
@ -1,5 +1,5 @@
|
||||
export { default as Hero } from './Hero'
|
||||
export { default as AcmeLogo } from './Logo'
|
||||
export { default as Logo } from './Logo'
|
||||
export { default as Grid } from './Grid'
|
||||
export { default as Button } from './Button'
|
||||
export { default as Sidebar } from './Sidebar'
|
||||
|
9
site/config/theme.json
Normal file
9
site/config/theme.json
Normal file
@ -0,0 +1,9 @@
|
||||
{
|
||||
"features": {
|
||||
"logo": false
|
||||
},
|
||||
"theme": {
|
||||
"logoSrc": "replace with the path in `public` your logo ex: /assets/logo.svg",
|
||||
"logoAlt": "Replace with your logo alt text"
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user