mirror of
https://github.com/vercel/commerce.git
synced 2025-06-08 01:06: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`.
|
- Turn `wishlist` on by setting `wishlist` to `true`.
|
||||||
- Run the app and the wishlist functionality should be back on.
|
- 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
|
### How to create a new provider
|
||||||
|
|
||||||
Follow our docs for [Adding a new Commerce Provider](packages/commerce/new-provider.md).
|
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 { FC, useEffect, useState, useCallback } from 'react'
|
||||||
import { validate } from 'email-validator'
|
import { validate } from 'email-validator'
|
||||||
import { useUI } from '@components/ui/context'
|
import { useUI } from '@components/ui/context'
|
||||||
import { AcmeLogo, Button, Input } from '@components/ui'
|
import { Logo, Button, Input } from '@components/ui'
|
||||||
import { useCommerce } from '@framework'
|
|
||||||
|
|
||||||
interface Props {}
|
interface Props {}
|
||||||
|
|
||||||
const ForgotPassword: FC<Props> = () => {
|
const ForgotPassword: FC<Props> = () => {
|
||||||
// @ts-ignore
|
|
||||||
const { brand = {} } = useCommerce()
|
|
||||||
const { Logo = AcmeLogo } = brand
|
|
||||||
// Form State
|
// Form State
|
||||||
const [email, setEmail] = useState('')
|
const [email, setEmail] = useState('')
|
||||||
const [loading, setLoading] = useState(false)
|
const [loading, setLoading] = useState(false)
|
||||||
|
@ -1,14 +1,11 @@
|
|||||||
import { FC, useEffect, useState, useCallback } from 'react'
|
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 useLogin from '@framework/auth/use-login'
|
||||||
import { useUI } from '@components/ui/context'
|
import { useUI } from '@components/ui/context'
|
||||||
import { validate } from 'email-validator'
|
import { validate } from 'email-validator'
|
||||||
import { useCommerce } from '@framework'
|
import { useCommerce } from '@framework'
|
||||||
|
|
||||||
const LoginView: React.FC = () => {
|
const LoginView: React.FC = () => {
|
||||||
// @ts-ignore
|
|
||||||
const { brand = {} } = useCommerce()
|
|
||||||
const { Logo = AcmeLogo } = brand
|
|
||||||
// Form State
|
// Form State
|
||||||
const [email, setEmail] = useState('')
|
const [email, setEmail] = useState('')
|
||||||
const [password, setPassword] = useState('')
|
const [password, setPassword] = useState('')
|
||||||
|
@ -2,15 +2,12 @@ import { FC, useEffect, useState, useCallback } from 'react'
|
|||||||
import { validate } from 'email-validator'
|
import { validate } from 'email-validator'
|
||||||
import { Info } from '@components/icons'
|
import { Info } from '@components/icons'
|
||||||
import { useUI } from '@components/ui/context'
|
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'
|
import useSignup from '@framework/auth/use-signup'
|
||||||
|
|
||||||
interface Props {}
|
interface Props {}
|
||||||
|
|
||||||
const SignUpView: FC<Props> = () => {
|
const SignUpView: FC<Props> = () => {
|
||||||
// @ts-ignore
|
|
||||||
const { brand = {} } = useCommerce()
|
|
||||||
const { Logo = AcmeLogo } = brand
|
|
||||||
// Form State
|
// Form State
|
||||||
const [email, setEmail] = useState('')
|
const [email, setEmail] = useState('')
|
||||||
const [password, setPassword] = useState('')
|
const [password, setPassword] = useState('')
|
||||||
|
@ -5,7 +5,7 @@ import { useRouter } from 'next/router'
|
|||||||
import type { Page } from '@commerce/types/page'
|
import type { Page } from '@commerce/types/page'
|
||||||
import getSlug from '@lib/get-slug'
|
import getSlug from '@lib/get-slug'
|
||||||
import { Github, Vercel } from '@components/icons'
|
import { Github, Vercel } from '@components/icons'
|
||||||
import { AcmeLogo, Container } from '@components/ui'
|
import { Logo, Container } from '@components/ui'
|
||||||
import { I18nWidget } from '@components/common'
|
import { I18nWidget } from '@components/common'
|
||||||
import s from './Footer.module.css'
|
import s from './Footer.module.css'
|
||||||
import { useCommerce } from '@framework'
|
import { useCommerce } from '@framework'
|
||||||
@ -26,9 +26,6 @@ const links = [
|
|||||||
const Footer: FC<Props> = ({ className, pages }) => {
|
const Footer: FC<Props> = ({ className, pages }) => {
|
||||||
const { sitePages } = usePages(pages)
|
const { sitePages } = usePages(pages)
|
||||||
const rootClassName = cn(s.root, className)
|
const rootClassName = cn(s.root, className)
|
||||||
// @ts-ignore
|
|
||||||
const { brand = {} } = useCommerce()
|
|
||||||
const { Logo = AcmeLogo } = brand
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<footer className={rootClassName}>
|
<footer className={rootClassName}>
|
||||||
|
@ -2,7 +2,7 @@ import { FC } from 'react'
|
|||||||
import Link from 'next/link'
|
import Link from 'next/link'
|
||||||
import s from './Navbar.module.css'
|
import s from './Navbar.module.css'
|
||||||
import NavbarRoot from './NavbarRoot'
|
import NavbarRoot from './NavbarRoot'
|
||||||
import { AcmeLogo, Container } from '@components/ui'
|
import { Logo, Container } from '@components/ui'
|
||||||
import { Searchbar, UserNav } from '@components/common'
|
import { Searchbar, UserNav } from '@components/common'
|
||||||
import { useCommerce } from '@framework'
|
import { useCommerce } from '@framework'
|
||||||
|
|
||||||
@ -16,9 +16,6 @@ interface NavbarProps {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const Navbar: FC<NavbarProps> = ({ links }) => {
|
const Navbar: FC<NavbarProps> = ({ links }) => {
|
||||||
// @ts-ignore
|
|
||||||
const { brand = {} } = useCommerce()
|
|
||||||
const { Logo = AcmeLogo } = brand
|
|
||||||
return (
|
return (
|
||||||
<NavbarRoot>
|
<NavbarRoot>
|
||||||
<Container clean className="mx-auto max-w-8xl px-6">
|
<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
|
<svg
|
||||||
width="32"
|
width="32"
|
||||||
height="32"
|
height="32"
|
||||||
@ -18,4 +22,26 @@ const AcmeLogo = ({ className = '', ...props }) => (
|
|||||||
</svg>
|
</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 React, { FC, useCallback, useMemo } from 'react'
|
||||||
import { ThemeProvider } from 'next-themes'
|
import { ThemeProvider } from 'next-themes'
|
||||||
|
|
||||||
|
import { features, theme } from 'config/theme.json'
|
||||||
|
|
||||||
export interface State {
|
export interface State {
|
||||||
displaySidebar: boolean
|
displaySidebar: boolean
|
||||||
displayDropdown: boolean
|
displayDropdown: boolean
|
||||||
@ -17,6 +19,9 @@ const initialState = {
|
|||||||
modalView: 'LOGIN_VIEW',
|
modalView: 'LOGIN_VIEW',
|
||||||
sidebarView: 'CART_VIEW',
|
sidebarView: 'CART_VIEW',
|
||||||
userAvatar: '',
|
userAvatar: '',
|
||||||
|
theme: {
|
||||||
|
...(features.logo && { logoSrc: theme.logoSrc, logoAlt: theme.logoAlt }),
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
type Action =
|
type Action =
|
||||||
@ -198,6 +203,8 @@ export const UIProvider: FC = (props) => {
|
|||||||
[state]
|
[state]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
console.log(value)
|
||||||
|
|
||||||
return <UIContext.Provider value={value} {...props} />
|
return <UIContext.Provider value={value} {...props} />
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -209,6 +216,14 @@ export const useUI = () => {
|
|||||||
return context
|
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 }) => (
|
export const ManagedUIContext: FC = ({ children }) => (
|
||||||
<UIProvider>
|
<UIProvider>
|
||||||
<ThemeProvider>{children}</ThemeProvider>
|
<ThemeProvider>{children}</ThemeProvider>
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
export { default as Hero } from './Hero'
|
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 Grid } from './Grid'
|
||||||
export { default as Button } from './Button'
|
export { default as Button } from './Button'
|
||||||
export { default as Sidebar } from './Sidebar'
|
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