theme-ui#Themed TypeScript Examples
The following examples show how to use
theme-ui#Themed.
You can vote up the ones you like or vote down the ones you don't like,
and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: FeatureBar.tsx From nextjs-shopify with MIT License | 6 votes |
FeatureBar: React.FC<FeatureBarProps> = ({
title,
description,
action,
hide,
delay,
}) => {
const [delayPassed, setDelayPassed] = useState(false)
useEffect(() => {
const timeout = setTimeout(() => setDelayPassed(true), delay || 6000)
return () => clearTimeout(timeout)
})
return (
<CenterModal isOpen={delayPassed && !hide}>
<ModalTitle>{title}</ModalTitle>
{description}
<Themed.div sx={{ display: 'flex', justifyContent: 'center', p: [1, 2] }}>
{action && action}
</Themed.div>
</CenterModal>
)
}
Example #2
Source File: Sidebar.tsx From nextjs-shopify with MIT License | 6 votes |
Sidebar: FC<Props> = ({ children, open = false, onClose }) => {
const width = useResponsiveValue(['100%', 500])
return (
<BaseModal
isOpen={open}
onDismiss={onClose}
contentProps={{
style: {
width,
position: 'absolute',
top: 0,
right: 0,
height: '100%',
},
}}
contentTransition={{
from: { transform: 'translateX(100%)' },
enter: { transform: 'translateX(0)' },
leave: { transform: 'translateX(100%)' },
}}
>
<ModalCloseTarget>
<Themed.div
sx={{
display: 'flex',
justifyContent: 'space-between',
py: 1,
bg: 'text',
color: 'background',
}}
>
<Close />
</Themed.div>
</ModalCloseTarget>
{children}
</BaseModal>
)
}
Example #3
Source File: CollectionView.tsx From nextjs-shopify with MIT License | 5 votes |
CollectionPreview: FC<Props> = ({
collection: initialCollection,
productGridOptions,
renderSeo,
}) => {
const [collection, setCollection] = useState(initialCollection)
const [loading, setLoading] = useState(false)
useEffect(() => setCollection(initialCollection), [initialCollection])
useEffect(() => {
const fetchCollection = async () => {
setLoading(true)
const result = await getCollection(shopifyConfig, {
handle: collection,
})
setCollection(result)
setLoading(false)
}
if (typeof collection === 'string') {
fetchCollection()
}
}, [collection])
if (!collection || typeof collection === 'string' || loading) {
return <LoadingDots />
}
const { title, description, products } = collection
return (
<Themed.div
sx={{ display: 'flex', flexDirection: 'column' }}
key={collection.id}
>
{renderSeo && (
<NextSeo
title={collection.title}
description={collection.description}
openGraph={{
type: 'website',
title,
description,
}}
/>
)}
<div sx={{ display: 'flex', flexDirection: 'column' }}>
<span sx={{ mt: 0, mb: 2 }}>
<Themed.h1>{collection.title}</Themed.h1>
</span>
<div dangerouslySetInnerHTML={{ __html: collection.description! }} />
</div>
<Themed.div sx={{ p: 5 }}>
<ProductGrid {...productGridOptions} products={products} />
</Themed.div>
</Themed.div>
)
}
Example #4
Source File: ProductCard.tsx From nextjs-shopify with MIT License | 5 votes |
ProductCard: React.FC<ProductCardProps> = ({
product,
imgWidth,
imgHeight,
imgPriority,
imgLoading,
imgSizes,
imgLayout = 'responsive',
}) => {
const handle = (product as any).handle
const productVariant: any = product.variants[0]
const price = getPrice(
productVariant.priceV2.amount,
productVariant.priceV2.currencyCode
)
return (
<Card
sx={{
maxWidth: [700, imgWidth || 540],
p: 3,
display: 'flex',
flexDirection: 'column',
}}
>
<Link href={`/product/${handle}/`}>
<div sx={{ flexGrow: 1 }}>
<ImageCarousel
currentSlide={product.images ? product.images.length - 1 : 0}
width={imgWidth}
height={imgHeight}
priority={imgPriority}
loading={imgLoading}
layout={imgLayout}
sizes={imgSizes}
alt={product.title}
images={
product.images.length ? product.images : [{
src: `https://via.placeholder.com/${imgWidth}x${imgHeight}`,
}]
}
/>
</div>
<div sx={{ textAlign: 'center' }}>
<Themed.h2 sx={{ mt: 4, mb: 0, fontSize: 14 }}>
{product.title}
</Themed.h2>
<Text sx={{ fontSize: 12, mb: 2 }}>{price}</Text>
</div>
</Link>
</Card>
)
}
Example #5
Source File: Searchbar.tsx From nextjs-shopify with MIT License | 5 votes |
Searchbar: FC<Props> = () => {
const router = useRouter()
const { q } = router.query
const [isOpen, setIsOpen] = useState(false)
const buttonRef = useRef<HTMLDivElement>(null)
useEffect(() => {
setIsOpen(false)
}, [router.asPath.split('?')[0]])
return (
<React.Fragment>
<ExpandModal
transitionConfig={{}}
contentTransition={{}}
overlayProps={{
style: {
maxWidth: 1920,
left: '50%',
transform: 'translateX(-50%)',
overflow: 'auto',
top: (buttonRef.current?.getBoundingClientRect().bottom || 0) + 15,
},
}}
isOpen={isOpen}
>
<SearchModalContent
initialSearch={q && String(q)}
onSearch={(term: string) => {
const op = q ? 'replace' : 'push'
router[op]({
pathname: router.asPath.split('?')[0],
query: {
q: term,
},
})
}}
/>
</ExpandModal>
<Themed.div
ref={buttonRef}
as={Button}
mx={2}
onClick={() => setIsOpen(!isOpen)}
aria-label="Search"
>
{isOpen ? (
<Cross />
) : (
<svg
width="20"
height="22"
viewBox="0 0 20 22"
fill="none"
stroke="currentColor"
>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M8 4a4 4 0 100 8 4 4 0 000-8zM2 8a6 6 0 1110.89 3.476l4.817 4.817a1 1 0 01-1.414 1.414l-4.816-4.816A6 6 0 012 8z"
/>
</svg>
)}
</Themed.div>
</React.Fragment>
)
}
Example #6
Source File: Searchbar.tsx From nextjs-shopify with MIT License | 5 votes |
SearchModalContent = (props: {
initialSearch?: string
onSearch: (term: string) => any
}) => {
const [search, setSearch] = useState(
props.initialSearch && String(props.initialSearch)
)
const [products, setProducts] = useState([] as any[])
const [loading, setLoading] = useState(false)
const getProducts = async (searchTerm: string) => {
setLoading(true)
const results = await searchProducts(
shopifyConfig,
String(searchTerm),
)
setSearch(searchTerm)
setProducts(results)
setLoading(false)
if (searchTerm) {
props.onSearch(searchTerm)
}
}
useEffect(() => {
if (search) {
getProducts(search)
}
}, [])
const throttleSearch = useCallback(throttle(getProducts), [])
return (
<Themed.div
sx={{
display: 'flex',
flexDirection: 'column',
justifyContent: 'center',
p: [1, 2],
width: '100%',
}}
>
<Input
type="search"
sx={{ marginBottom: 15 }}
defaultValue={props.initialSearch}
placeholder="Search for products..."
onChange={(event) => throttleSearch(event.target.value)}
/>
{loading ? (
<LoadingDots />
) : products.length ? (
<>
<Label>
Search Results for "<strong>{search}</strong>"
</Label>
<ProductGrid
cardProps={{
imgHeight: 540,
imgWidth: 540,
imgPriority: false,
}}
products={products}
offset={0}
limit={products.length}
></ProductGrid>
</>
) : (
<span>
{search ? (
<>
There are no products that match "<strong>{search}</strong>"
</>
) : (
<> </>
)}
</span>
)}
</Themed.div>
)
}
Example #7
Source File: ImageCarousel.tsx From nextjs-shopify with MIT License | 5 votes |
LazyCarousel = dynamic(() => import('./LazyImageCarousel'), {
loading: () => <Themed.div sx={{ height: '100%', bg: 'muted' }} />,
ssr: false,
})
Example #8
Source File: ProductView.tsx From nextjs-shopify with MIT License | 4 votes |
ProductBox: React.FC<Props> = ({
product,
renderSeo,
description = product.description,
title = product.title,
}) => {
const [loading, setLoading] = useState(false)
const addItem = useAddItemToCart()
const colors: string[] | undefined = product?.options
?.find((option) => option?.name?.toLowerCase() === 'color')
?.values?.map((op) => op.value as string)
const sizes: string[] | undefined = product?.options
?.find((option) => option?.name?.toLowerCase() === 'size')
?.values?.map((op) => op.value as string)
const variants = useMemo(
() => prepareVariantsWithOptions(product?.variants),
[product?.variants]
)
const images = useMemo(() => prepareVariantsImages(variants, 'color'), [
variants,
])
const { openSidebar } = useUI()
const [variant, setVariant] = useState(variants[0] || {})
const [color, setColor] = useState(variant.color)
const [size, setSize] = useState(variant.size)
useEffect(() => {
const newVariant = variants.find((variant) => {
return (
(variant.size === size || !size) && (variant.color === color || !color)
)
})
if (variant.id !== newVariant?.id) {
setVariant(newVariant)
}
}, [size, color, variants, variant.id])
const addToCart = async () => {
setLoading(true)
try {
await addItem(variant.id, 1)
openSidebar()
setLoading(false)
} catch (err) {
setLoading(false)
}
}
const allImages = images
.map(({ src }) => ({ src: src.src }))
.concat(
product.images &&
product.images.filter(
({ src }) => !images.find((image) => image.src.src === src)
)
)
return (
<React.Fragment>
{renderSeo && (
<NextSeo
title={title}
description={description}
openGraph={{
type: 'website',
title: title,
description: description,
images: [
{
url: product.images?.[0]?.src!,
width: 800,
height: 600,
alt: title,
},
],
}}
/>
)}
<Grid gap={4} columns={[1, 2]}>
<div>
<div
sx={{
border: '1px solid gray',
padding: 2,
marginBottom: 2,
}}
>
<ImageCarousel
showZoom
alt={title}
width={1050}
height={1050}
priority
onThumbnailClick={(index) => {
if (images[index]?.color) {
setColor(images[index].color)
}
}}
images={allImages?.length > 0 ? allImages: [{
src: `https://via.placeholder.com/1050x1050`,
}]}
></ImageCarousel>
</div>
</div>
<div sx={{ display: 'flex', flexDirection: 'column' }}>
<span sx={{ mt: 0, mb: 2 }}>
<Themed.h1>{title}</Themed.h1>
<Themed.h4 aria-label="price" sx={{ mt: 0, mb: 2 }}>
{getPrice(variant.priceV2.amount, variant.priceV2.currencyCode)}
</Themed.h4>
</span>
<div dangerouslySetInnerHTML={{ __html: description! }} />
<div>
<Grid padding={2} columns={2}>
{colors?.length && (
<OptionPicker
key="Color"
name="Color"
options={colors}
selected={color}
onChange={(event) => setColor(event.target.value)}
/>
)}
{sizes?.length && (
<OptionPicker
key="Size"
name="Size"
options={sizes}
selected={size}
onChange={(event) => setSize(event.target.value)}
/>
)}
</Grid>
</div>
<Button
name="add-to-cart"
disabled={loading}
sx={{ margin: 2, display: 'block' }}
onClick={addToCart}
>
Add to Cart {loading && <LoadingDots />}
</Button>
</div>
</Grid>
</React.Fragment>
)
}
Example #9
Source File: ProductViewDemo.tsx From nextjs-shopify with MIT License | 4 votes |
ProductBox: React.FC<Props> = ({
product,
renderSeo = true,
description = product.body_html,
title = product.title,
}) => {
const variants = product.variants as any[]
const images = product.images
const variant = variants.find((v) => v.available) || variants[0]
const price = getPrice(variant.compare_at_price || variant.price, 'USD')
const [image, setImage] = useState(
variant.featured_image || product.images[0]
)
return (
<React.Fragment>
{renderSeo && (
<NextSeo
title={title}
description={description}
openGraph={{
type: 'website',
title: title,
description: description,
images: [
{
url: product.images?.[0]?.src!,
width: 800,
height: 600,
alt: title,
},
],
}}
/>
)}
<Grid gap={4} columns={[1, 2]}>
<div
sx={{
border: '1px solid gray',
padding: 2,
marginBottom: 2,
}}
>
<ImageCarousel
showZoom
alt={title}
width={1050}
height={1050}
priority
images={images}
></ImageCarousel>
</div>
<div sx={{ display: 'flex', flexDirection: 'column' }}>
<span sx={{ mt: 0, mb: 2 }}>
<Themed.h1>{title}</Themed.h1>
<Themed.h4 aria-label="price" sx={{ mt: 0, mb: 2 }}>
{price}
</Themed.h4>
</span>
<div dangerouslySetInnerHTML={{ __html: description }} />
<div>
<Grid padding={2} columns={2}>
{product.options.map((opt: any) => {
return (
<OptionPicker
key={opt.name}
name={opt.name}
options={opt.values}
/>
)
})}
</Grid>
</div>
<Button
disabled
name="add-to-cart"
sx={{ margin: 2, display: 'block' }}
>
Add to Cart
</Button>
</div>
</Grid>
</React.Fragment>
)
}
Example #10
Source File: CartItem.tsx From nextjs-shopify with MIT License | 4 votes |
CartItem = ({
item,
currencyCode,
}: {
item: /*ShopifyBuy.LineItem todo: check if updated types*/ any
currencyCode: string
}) => {
const updateItem = useUpdateItemQuantity()
const removeItem = useRemoveItemFromCart()
const [quantity, setQuantity] = useState(item.quantity)
const [removing, setRemoving] = useState(false)
const updateQuantity = async (quantity: number) => {
await updateItem(item.variant.id, quantity)
}
const handleQuantity = (e: ChangeEvent<HTMLInputElement>) => {
const val = Number(e.target.value)
if (Number.isInteger(val) && val >= 0) {
setQuantity(val)
}
}
const handleBlur = () => {
const val = Number(quantity)
if (val !== item.quantity) {
updateQuantity(val)
}
}
const increaseQuantity = (n = 1) => {
const val = Number(quantity) + n
if (Number.isInteger(val) && val >= 0) {
setQuantity(val)
updateQuantity(val)
}
}
const handleRemove = async () => {
setRemoving(true)
try {
// If this action succeeds then there's no need to do `setRemoving(true)`
// because the component will be removed from the view
await removeItem(item.variant.id)
} catch (error) {
console.error(error)
setRemoving(false)
}
}
useEffect(() => {
// Reset the quantity state if the item quantity changes
if (item.quantity !== Number(quantity)) {
setQuantity(item.quantity)
}
}, [item.quantity])
return (
<Grid gap={2} sx={{ width: '100%', m: 12 }} columns={[2]}>
<div
sx={{
padding: 1,
border: '1px solid gray',
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
}}
>
<Image
height={130}
width={130}
unoptimized
alt={item.variant.image.altText}
src={item.variant.image.src}
/>
</div>
<div>
<Themed.div
as={Link}
href={`/product/${item.variant.product.handle}/`}
sx={{ fontSize: 3, m: 0, fontWeight: 700 }}
>
<>
{item.title}
<Text
sx={{
fontSize: 4,
fontWeight: 700,
display: 'block',
marginLeft: 'auto',
}}
>
{getPrice(
item.variant.priceV2.amount,
item.variant.priceV2.currencyCode || 'USD'
)}
</Text>
</>
</Themed.div>
<Themed.ul sx={{ mt: 2, mb: 0, padding: 0, listStyle: 'none' }}>
<li>
<div sx={{ display: 'flex', justifyItems: 'center' }}>
<IconButton onClick={() => increaseQuantity(-1)}>
<Minus width={18} height={18} />
</IconButton>
<label>
<Input
sx={{
height: '100%',
textAlign: 'center',
}}
type="number"
max={99}
min={0}
value={quantity}
onChange={handleQuantity}
onBlur={handleBlur}
/>
</label>
<IconButton onClick={() => increaseQuantity(1)}>
<Plus width={18} height={18} />
</IconButton>
</div>
</li>
{item.variant.selectedOptions.map((option: any) => (
<li key={option.value}>
{option.name}:{option.value}
</li>
))}
</Themed.ul>
</div>
</Grid>
)
}
Example #11
Source File: CartSidebarView.tsx From nextjs-shopify with MIT License | 4 votes |
CartSidebarView: FC = () => {
const checkoutUrl = useCheckoutUrl()
const cart = useCart()
const subTotal = cart?.subtotalPrice
const total = ' - '
const items = cart?.lineItems ?? []
const isEmpty = items.length === 0
const [cartUpsell, setCartUpsell] = useState()
useEffect(() => {
async function fetchContent() {
const items = cart?.lineItems || []
const cartUpsellContent = await builder
.get('cart-upsell-sidebar', {
cacheSeconds: 120,
userAttributes: {
itemInCart: items.map((item: any) => item.variant.product.handle),
} as any,
})
.toPromise()
setCartUpsell(cartUpsellContent)
}
fetchContent()
}, [cart?.lineItems])
return (
<Themed.div
sx={{
height: '100%',
overflow: 'auto',
paddingBottom: 5,
bg: 'text',
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
px: 2,
color: 'background',
...(isEmpty && { justifyContent: 'center' }),
}}
>
{isEmpty ? (
<>
<Bag />
Your cart is empty
<Text>
Biscuit oat cake wafer icing ice cream tiramisu pudding cupcake.
</Text>
</>
) : (
<>
{items.map((item: any) => (
<CartItem
key={item.id}
item={item}
// todo update types
currencyCode={item.variant?.priceV2?.currencyCode || 'USD'}
/>
))}
<Card sx={{ marginLeft: 'auto', minWidth: '10rem', paddingLeft: 5 }}>
<Grid gap={1} columns={2} sx={{ my: 3 }}>
<Text>Subtotal:</Text>
<Text sx={{ marginLeft: 'auto' }}>{subTotal}</Text>
<Text>Shipping:</Text>
<Text sx={{ marginLeft: 'auto' }}> - </Text>
<Text>Tax: </Text>
<Text sx={{ marginLeft: 'auto' }}> - </Text>
</Grid>
<Divider />
<Grid gap={1} columns={2}>
<Text variant="bold">Estimated Total:</Text>
<Text variant="bold" sx={{ marginLeft: 'auto' }}>
{total}
</Text>
</Grid>
</Card>
<BuilderComponent content={cartUpsell} model="cart-upsell-sidebar" />
{checkoutUrl && (
<NavLink
variant="nav"
sx={{ width: '100%', m: 2, p: 12, textAlign: 'center' }}
href={checkoutUrl!}
>
Proceed to Checkout
</NavLink>
)}
</>
)}
</Themed.div>
)
}
Example #12
Source File: Navbar.tsx From nextjs-shopify with MIT License | 4 votes |
Navbar: FC = () => {
const [announcement, setAnnouncement] = useState()
const { theme } = useThemeUI()
const { navigationLinks, logo } = useUI()
const cart = useCart()
useEffect(() => {
async function fetchContent() {
const items = cart?.lineItems || []
const anouncementContent = await builder
.get('announcement-bar', {
cacheSeconds: 120,
userAttributes: {
itemInCart: items.map((item: any) => item.variant.product.handle),
} as any,
})
.toPromise()
setAnnouncement(anouncementContent)
}
fetchContent()
}, [cart?.lineItems])
return (
<React.Fragment>
<BuilderComponent
content={announcement}
data={{ theme }}
model="announcement-bar"
/>
<Themed.div
as="header"
sx={{
margin: `0 auto`,
maxWidth: 1920,
py: 2,
px: 2,
display: 'flex',
justifyContent: 'space-between',
alignItems: 'center',
position: 'relative',
}}
>
<Themed.div
sx={{
display: ['none', 'none', 'flex'],
flexBasis: 0,
minWidth: 240,
justifyContent: 'space-evenly',
}}
>
{navigationLinks?.map((link, index) => (
<Themed.a
key={index}
sx={{ padding: 10, minWidth: 90 }}
as={Link}
href={link.link}
>
{link.title}
</Themed.a>
))}
</Themed.div>
<Themed.div
sx={{
transform: 'translateX(-50%)',
left: '50%',
position: 'absolute',
}}
>
<Themed.h1
sx={{
fontSize: 20,
fontWeight: 'bold',
}}
>
{logo && logo.image && (
<Themed.a
as={Link}
href="/"
sx={{
letterSpacing: -1,
textDecoration: `none`,
paddingLeft: '5px',
}}
>
<Image
layout="fixed"
width={logo.width}
height={logo.height}
src={logo.image}
></Image>
</Themed.a>
)}
{logo && logo.text && !logo.image && (
<Themed.a
as={Link}
href="/"
sx={{
letterSpacing: -1,
textDecoration: `none`,
paddingLeft: '5px',
}}
>
{logo.text}
</Themed.a>
)}
</Themed.h1>
</Themed.div>
<Themed.div
sx={{
display: 'flex',
minWidth: 140,
width: '100%',
justifyContent: ['space-between', 'flex-end'],
}}
>
<Searchbar />
<UserNav />
</Themed.div>
</Themed.div>
</React.Fragment>
)
}
Example #13
Source File: ProductCardDemo.tsx From nextjs-shopify with MIT License | 4 votes |
ProductCardDemo: React.FC<ProductCardProps> = ({
product,
imgWidth,
imgHeight,
imgPriority,
imgLoading,
imgSizes,
imgLayout = 'responsive',
}) => {
const [showAlternate, setShowAlternate] = useState(false)
const [canToggle, setCanToggle] = useState(false)
const src = product.images[0].src
const handle = (product as any).handle
const productVariant: any = product.variants[0]
const price = getPrice(
productVariant.compare_at_price || productVariant.price,
'USD'
)
const alternateImage = product.images[1]?.src
return (
<Card
sx={{
maxWidth: [700, 500],
p: 3,
display: 'flex',
flexDirection: 'column',
}}
onMouseOut={() => setShowAlternate(false)}
onMouseOver={() => setShowAlternate(true)}
>
<Link href={`/product/${handle}/`}>
<div sx={{ flexGrow: 1 }}>
{alternateImage && (
<div
sx={{ display: showAlternate && canToggle ? 'block' : 'none' }}
>
<NoSSR>
<Image
quality="85"
src={alternateImage}
alt={product.title}
width={imgWidth || 540}
sizes={imgSizes}
height={imgHeight || 540}
layout={imgLayout}
onLoad={() => setCanToggle(true)}
loading="eager"
/>
</NoSSR>
</div>
)}
<div
sx={{
display:
canToggle && showAlternate && alternateImage ? 'none' : 'block',
}}
>
<Image
quality="85"
src={src}
alt={product.title}
width={imgWidth || 540}
sizes={imgSizes}
height={imgHeight || 540}
layout={imgLayout}
loading={imgLoading}
priority={imgPriority}
/>
</div>
</div>
<div sx={{ textAlign: 'center' }}>
<Themed.h2 sx={{ mt: 4, mb: 0, fontSize: 14 }}>
{product.title}
</Themed.h2>
<Text sx={{ fontSize: 12, mb: 2 }}>{price}</Text>
</div>
</Link>
</Card>
)
}