init starter package

This commit is contained in:
2025-10-16 17:29:57 +02:00
commit b7c67b5834
216 changed files with 37028 additions and 0 deletions
@@ -0,0 +1,30 @@
import { retrieveCart } from "@lib/data/cart"
import { retrieveCustomer } from "@lib/data/customer"
import PaymentWrapper from "@modules/checkout/components/payment-wrapper"
import CheckoutForm from "@modules/checkout/templates/checkout-form"
import CheckoutSummary from "@modules/checkout/templates/checkout-summary"
import { Metadata } from "next"
import { notFound } from "next/navigation"
export const metadata: Metadata = {
title: "Checkout",
}
export default async function Checkout() {
const cart = await retrieveCart()
if (!cart) {
return notFound()
}
const customer = await retrieveCustomer()
return (
<div className="grid grid-cols-1 small:grid-cols-[1fr_416px] content-container gap-x-40 py-12">
<PaymentWrapper cart={cart}>
<CheckoutForm cart={cart} customer={customer} />
</PaymentWrapper>
<CheckoutSummary cart={cart} />
</div>
)
}
@@ -0,0 +1,43 @@
import LocalizedClientLink from "@modules/common/components/localized-client-link"
import ChevronDown from "@modules/common/icons/chevron-down"
import MedusaCTA from "@modules/layout/components/medusa-cta"
export default function CheckoutLayout({
children,
}: {
children: React.ReactNode
}) {
return (
<div className="w-full bg-white relative small:min-h-screen">
<div className="h-16 bg-white border-b ">
<nav className="flex h-full items-center content-container justify-between">
<LocalizedClientLink
href="/cart"
className="text-small-semi text-ui-fg-base flex items-center gap-x-2 uppercase flex-1 basis-0"
data-testid="back-to-cart-link"
>
<ChevronDown className="rotate-90" size={16} />
<span className="mt-px hidden small:block txt-compact-plus text-ui-fg-subtle hover:text-ui-fg-base ">
Back to shopping cart
</span>
<span className="mt-px block small:hidden txt-compact-plus text-ui-fg-subtle hover:text-ui-fg-base">
Back
</span>
</LocalizedClientLink>
<LocalizedClientLink
href="/"
className="txt-compact-xlarge-plus text-ui-fg-subtle hover:text-ui-fg-base uppercase"
data-testid="store-link"
>
Medusa Store
</LocalizedClientLink>
<div className="flex-1 basis-0" />
</nav>
</div>
<div className="relative" data-testid="checkout-container">{children}</div>
<div className="py-4 w-full flex items-center justify-center">
<MedusaCTA />
</div>
</div>
)
}
@@ -0,0 +1,19 @@
import InteractiveLink from "@modules/common/components/interactive-link"
import { Metadata } from "next"
export const metadata: Metadata = {
title: "404",
description: "Something went wrong",
}
export default async function NotFound() {
return (
<div className="flex flex-col gap-4 items-center justify-center min-h-[calc(100vh-64px)]">
<h1 className="text-2xl-semi text-ui-fg-base">Page not found</h1>
<p className="text-small-regular text-ui-fg-base">
The page you tried to access does not exist.
</p>
<InteractiveLink href="/">Go to frontpage</InteractiveLink>
</div>
)
}
@@ -0,0 +1,38 @@
import { Metadata } from "next"
import { notFound } from "next/navigation"
import AddressBook from "@modules/account/components/address-book"
import { getRegion } from "@lib/data/regions"
import { retrieveCustomer } from "@lib/data/customer"
export const metadata: Metadata = {
title: "Addresses",
description: "View your addresses",
}
export default async function Addresses(props: {
params: Promise<{ countryCode: string }>
}) {
const params = await props.params
const { countryCode } = params
const customer = await retrieveCustomer()
const region = await getRegion(countryCode)
if (!customer || !region) {
notFound()
}
return (
<div className="w-full" data-testid="addresses-page-wrapper">
<div className="mb-8 flex flex-col gap-y-4">
<h1 className="text-2xl-semi">Shipping Addresses</h1>
<p className="text-base-regular">
View and update your shipping addresses, you can add as many as you
like. Saving your addresses will make them available during checkout.
</p>
</div>
<AddressBook customer={customer} region={region} />
</div>
)
}
@@ -0,0 +1,9 @@
import Spinner from "@modules/common/icons/spinner"
export default function Loading() {
return (
<div className="flex items-center justify-center w-full h-full text-ui-fg-base">
<Spinner size={36} />
</div>
)
}
@@ -0,0 +1,33 @@
import { retrieveOrder } from "@lib/data/orders"
import OrderDetailsTemplate from "@modules/order/templates/order-details-template"
import { Metadata } from "next"
import { notFound } from "next/navigation"
type Props = {
params: Promise<{ id: string }>
}
export async function generateMetadata(props: Props): Promise<Metadata> {
const params = await props.params
const order = await retrieveOrder(params.id).catch(() => null)
if (!order) {
notFound()
}
return {
title: `Order #${order.display_id}`,
description: `View your order`,
}
}
export default async function OrderDetailPage(props: Props) {
const params = await props.params
const order = await retrieveOrder(params.id).catch(() => null)
if (!order) {
notFound()
}
return <OrderDetailsTemplate order={order} />
}
@@ -0,0 +1,37 @@
import { Metadata } from "next"
import OrderOverview from "@modules/account/components/order-overview"
import { notFound } from "next/navigation"
import { listOrders } from "@lib/data/orders"
import Divider from "@modules/common/components/divider"
import TransferRequestForm from "@modules/account/components/transfer-request-form"
export const metadata: Metadata = {
title: "Orders",
description: "Overview of your previous orders.",
}
export default async function Orders() {
const orders = await listOrders()
if (!orders) {
notFound()
}
return (
<div className="w-full" data-testid="orders-page-wrapper">
<div className="mb-8 flex flex-col gap-y-4">
<h1 className="text-2xl-semi">Orders</h1>
<p className="text-base-regular">
View your previous orders and their status. You can also create
returns or exchanges for your orders if needed.
</p>
</div>
<div>
<OrderOverview orders={orders} />
<Divider className="my-16" />
<TransferRequestForm />
</div>
</div>
)
}
@@ -0,0 +1,22 @@
import { Metadata } from "next"
import Overview from "@modules/account/components/overview"
import { notFound } from "next/navigation"
import { retrieveCustomer } from "@lib/data/customer"
import { listOrders } from "@lib/data/orders"
export const metadata: Metadata = {
title: "Account",
description: "Overview of your account activity.",
}
export default async function OverviewTemplate() {
const customer = await retrieveCustomer().catch(() => null)
const orders = (await listOrders().catch(() => null)) || null
if (!customer) {
notFound()
}
return <Overview customer={customer} orders={orders} />
}
@@ -0,0 +1,54 @@
import { Metadata } from "next"
import ProfilePhone from "@modules/account//components/profile-phone"
import ProfileBillingAddress from "@modules/account/components/profile-billing-address"
import ProfileEmail from "@modules/account/components/profile-email"
import ProfileName from "@modules/account/components/profile-name"
import ProfilePassword from "@modules/account/components/profile-password"
import { notFound } from "next/navigation"
import { listRegions } from "@lib/data/regions"
import { retrieveCustomer } from "@lib/data/customer"
export const metadata: Metadata = {
title: "Profile",
description: "View and edit your Medusa Store profile.",
}
export default async function Profile() {
const customer = await retrieveCustomer()
const regions = await listRegions()
if (!customer || !regions) {
notFound()
}
return (
<div className="w-full" data-testid="profile-page-wrapper">
<div className="mb-8 flex flex-col gap-y-4">
<h1 className="text-2xl-semi">Profile</h1>
<p className="text-base-regular">
View and update your profile information, including your name, email,
and phone number. You can also update your billing address, or change
your password.
</p>
</div>
<div className="flex flex-col gap-y-8 w-full">
<ProfileName customer={customer} />
<Divider />
<ProfileEmail customer={customer} />
<Divider />
<ProfilePhone customer={customer} />
<Divider />
{/* <ProfilePassword customer={customer} />
<Divider /> */}
<ProfileBillingAddress customer={customer} regions={regions} />
</div>
</div>
)
}
const Divider = () => {
return <div className="w-full h-px bg-gray-200" />
}
;``
@@ -0,0 +1,12 @@
import { Metadata } from "next"
import LoginTemplate from "@modules/account/templates/login-template"
export const metadata: Metadata = {
title: "Sign in",
description: "Sign in to your Medusa Store account.",
}
export default function Login() {
return <LoginTemplate />
}
@@ -0,0 +1,20 @@
import { retrieveCustomer } from "@lib/data/customer"
import { Toaster } from "@medusajs/ui"
import AccountLayout from "@modules/account/templates/account-layout"
export default async function AccountPageLayout({
dashboard,
login,
}: {
dashboard?: React.ReactNode
login?: React.ReactNode
}) {
const customer = await retrieveCustomer().catch(() => null)
return (
<AccountLayout customer={customer}>
{customer ? dashboard : login}
<Toaster />
</AccountLayout>
)
}
@@ -0,0 +1,9 @@
import Spinner from "@modules/common/icons/spinner"
export default function Loading() {
return (
<div className="flex items-center justify-center w-full h-full text-ui-fg-base">
<Spinner size={36} />
</div>
)
}
@@ -0,0 +1,5 @@
import SkeletonCartPage from "@modules/skeletons/templates/skeleton-cart-page"
export default function Loading() {
return <SkeletonCartPage />
}
@@ -0,0 +1,21 @@
import { Metadata } from "next"
import InteractiveLink from "@modules/common/components/interactive-link"
export const metadata: Metadata = {
title: "404",
description: "Something went wrong",
}
export default function NotFound() {
return (
<div className="flex flex-col items-center justify-center min-h-[calc(100vh-64px)]">
<h1 className="text-2xl-semi text-ui-fg-base">Page not found</h1>
<p className="text-small-regular text-ui-fg-base">
The cart you tried to access does not exist. Clear your cookies and try
again.
</p>
<InteractiveLink href="/">Go to frontpage</InteractiveLink>
</div>
)
}
@@ -0,0 +1,21 @@
import { retrieveCart } from "@lib/data/cart"
import { retrieveCustomer } from "@lib/data/customer"
import CartTemplate from "@modules/cart/templates"
import { Metadata } from "next"
import { notFound } from "next/navigation"
export const metadata: Metadata = {
title: "Cart",
description: "View your cart",
}
export default async function Cart() {
const cart = await retrieveCart().catch((error) => {
console.error(error)
return notFound()
})
const customer = await retrieveCustomer()
return <CartTemplate cart={cart} customer={customer} />
}
@@ -0,0 +1,85 @@
import { Metadata } from "next"
import { notFound } from "next/navigation"
import { getCategoryByHandle, listCategories } from "@lib/data/categories"
import { listRegions } from "@lib/data/regions"
import { StoreRegion } from "@medusajs/types"
import CategoryTemplate from "@modules/categories/templates"
import { SortOptions } from "@modules/store/components/refinement-list/sort-products"
type Props = {
params: Promise<{ category: string[]; countryCode: string }>
searchParams: Promise<{
sortBy?: SortOptions
page?: string
}>
}
export async function generateStaticParams() {
const product_categories = await listCategories()
if (!product_categories) {
return []
}
const countryCodes = await listRegions().then((regions: StoreRegion[]) =>
regions?.map((r) => r.countries?.map((c) => c.iso_2)).flat()
)
const categoryHandles = product_categories.map(
(category: any) => category.handle
)
const staticParams = countryCodes
?.map((countryCode: string | undefined) =>
categoryHandles.map((handle: any) => ({
countryCode,
category: [handle],
}))
)
.flat()
return staticParams
}
export async function generateMetadata(props: Props): Promise<Metadata> {
const params = await props.params
try {
const productCategory = await getCategoryByHandle(params.category)
const title = productCategory.name + " | Medusa Store"
const description = productCategory.description ?? `${title} category.`
return {
title: `${title} | Medusa Store`,
description,
alternates: {
canonical: `${params.category.join("/")}`,
},
}
} catch (error) {
notFound()
}
}
export default async function CategoryPage(props: Props) {
const searchParams = await props.searchParams
const params = await props.params
const { sortBy, page } = searchParams
const productCategory = await getCategoryByHandle(params.category)
if (!productCategory) {
notFound()
}
return (
<CategoryTemplate
category={productCategory}
sortBy={sortBy}
page={page}
countryCode={params.countryCode}
/>
)
}
@@ -0,0 +1,90 @@
import { Metadata } from "next"
import { notFound } from "next/navigation"
import { getCollectionByHandle, listCollections } from "@lib/data/collections"
import { listRegions } from "@lib/data/regions"
import { StoreCollection, StoreRegion } from "@medusajs/types"
import CollectionTemplate from "@modules/collections/templates"
import { SortOptions } from "@modules/store/components/refinement-list/sort-products"
type Props = {
params: Promise<{ handle: string; countryCode: string }>
searchParams: Promise<{
page?: string
sortBy?: SortOptions
}>
}
export const PRODUCT_LIMIT = 12
export async function generateStaticParams() {
const { collections } = await listCollections({
fields: "*products",
})
if (!collections) {
return []
}
const countryCodes = await listRegions().then(
(regions: StoreRegion[]) =>
regions
?.map((r) => r.countries?.map((c) => c.iso_2))
.flat()
.filter(Boolean) as string[]
)
const collectionHandles = collections.map(
(collection: StoreCollection) => collection.handle
)
const staticParams = countryCodes
?.map((countryCode: string) =>
collectionHandles.map((handle: string | undefined) => ({
countryCode,
handle,
}))
)
.flat()
return staticParams
}
export async function generateMetadata(props: Props): Promise<Metadata> {
const params = await props.params
const collection = await getCollectionByHandle(params.handle)
if (!collection) {
notFound()
}
const metadata = {
title: `${collection.title} | Medusa Store`,
description: `${collection.title} collection`,
} as Metadata
return metadata
}
export default async function CollectionPage(props: Props) {
const searchParams = await props.searchParams
const params = await props.params
const { sortBy, page } = searchParams
const collection = await getCollectionByHandle(params.handle).then(
(collection: StoreCollection) => collection
)
if (!collection) {
notFound()
}
return (
<CollectionTemplate
collection={collection}
page={page}
sortBy={sortBy}
countryCode={params.countryCode}
/>
)
}
+45
View File
@@ -0,0 +1,45 @@
import { Metadata } from "next"
import { listCartOptions, retrieveCart } from "@lib/data/cart"
import { retrieveCustomer } from "@lib/data/customer"
import { getBaseURL } from "@lib/util/env"
import { StoreCartShippingOption } from "@medusajs/types"
import CartMismatchBanner from "@modules/layout/components/cart-mismatch-banner"
import Footer from "@modules/layout/templates/footer"
import Nav from "@modules/layout/templates/nav"
import FreeShippingPriceNudge from "@modules/shipping/components/free-shipping-price-nudge"
export const metadata: Metadata = {
metadataBase: new URL(getBaseURL()),
}
export default async function PageLayout(props: { children: React.ReactNode }) {
const customer = await retrieveCustomer()
const cart = await retrieveCart()
let shippingOptions: StoreCartShippingOption[] = []
if (cart) {
const { shipping_options } = await listCartOptions()
shippingOptions = shipping_options
}
return (
<>
<Nav />
{customer && cart && (
<CartMismatchBanner customer={customer} cart={cart} />
)}
{cart && (
<FreeShippingPriceNudge
variant="popup"
cart={cart}
shippingOptions={shippingOptions}
/>
)}
{props.children}
<Footer />
</>
)
}
@@ -0,0 +1,20 @@
import { Metadata } from "next"
import InteractiveLink from "@modules/common/components/interactive-link"
export const metadata: Metadata = {
title: "404",
description: "Something went wrong",
}
export default function NotFound() {
return (
<div className="flex flex-col gap-4 items-center justify-center min-h-[calc(100vh-64px)]">
<h1 className="text-2xl-semi text-ui-fg-base">Page not found</h1>
<p className="text-small-regular text-ui-fg-base">
The page you tried to access does not exist.
</p>
<InteractiveLink href="/">Go to frontpage</InteractiveLink>
</div>
)
}
@@ -0,0 +1,5 @@
import SkeletonOrderConfirmed from "@modules/skeletons/templates/skeleton-order-confirmed"
export default function Loading() {
return <SkeletonOrderConfirmed />
}
@@ -0,0 +1,23 @@
import { retrieveOrder } from "@lib/data/orders"
import OrderCompletedTemplate from "@modules/order/templates/order-completed-template"
import { Metadata } from "next"
import { notFound } from "next/navigation"
type Props = {
params: Promise<{ id: string }>
}
export const metadata: Metadata = {
title: "Order Confirmed",
description: "You purchase was successful",
}
export default async function OrderConfirmedPage(props: Props) {
const params = await props.params
const order = await retrieveOrder(params.id).catch(() => null)
if (!order) {
return notFound()
}
return <OrderCompletedTemplate order={order} />
}
@@ -0,0 +1,41 @@
import { acceptTransferRequest } from "@lib/data/orders"
import { Heading, Text } from "@medusajs/ui"
import TransferImage from "@modules/order/components/transfer-image"
export default async function TransferPage({
params,
}: {
params: { id: string; token: string }
}) {
const { id, token } = params
const { success, error } = await acceptTransferRequest(id, token)
return (
<div className="flex flex-col gap-y-4 items-start w-2/5 mx-auto mt-10 mb-20">
<TransferImage />
<div className="flex flex-col gap-y-6">
{success && (
<>
<Heading level="h1" className="text-xl text-zinc-900">
Order transfered!
</Heading>
<Text className="text-zinc-600">
Order {id} has been successfully transfered to the new owner.
</Text>
</>
)}
{!success && (
<>
<Text className="text-zinc-600">
There was an error accepting the transfer. Please try again.
</Text>
{error && (
<Text className="text-red-500">Error message: {error}</Text>
)}
</>
)}
</div>
</div>
)
}
@@ -0,0 +1,41 @@
import { declineTransferRequest } from "@lib/data/orders"
import { Heading, Text } from "@medusajs/ui"
import TransferImage from "@modules/order/components/transfer-image"
export default async function TransferPage({
params,
}: {
params: { id: string; token: string }
}) {
const { id, token } = params
const { success, error } = await declineTransferRequest(id, token)
return (
<div className="flex flex-col gap-y-4 items-start w-2/5 mx-auto mt-10 mb-20">
<TransferImage />
<div className="flex flex-col gap-y-6">
{success && (
<>
<Heading level="h1" className="text-xl text-zinc-900">
Order transfer declined!
</Heading>
<Text className="text-zinc-600">
Transfer of order {id} has been successfully declined.
</Text>
</>
)}
{!success && (
<>
<Text className="text-zinc-600">
There was an error declining the transfer. Please try again.
</Text>
{error && (
<Text className="text-red-500">Error message: {error}</Text>
)}
</>
)}
</div>
</div>
)
}
@@ -0,0 +1,38 @@
import { Heading, Text } from "@medusajs/ui"
import TransferActions from "@modules/order/components/transfer-actions"
import TransferImage from "@modules/order/components/transfer-image"
export default async function TransferPage({
params,
}: {
params: { id: string; token: string }
}) {
const { id, token } = params
return (
<div className="flex flex-col gap-y-4 items-start w-2/5 mx-auto mt-10 mb-20">
<TransferImage />
<div className="flex flex-col gap-y-6">
<Heading level="h1" className="text-xl text-zinc-900">
Transfer request for order {id}
</Heading>
<Text className="text-zinc-600">
You&#39;ve received a request to transfer ownership of your order ({id}).
If you agree to this request, you can approve the transfer by clicking
the button below.
</Text>
<div className="w-full h-px bg-zinc-200" />
<Text className="text-zinc-600">
If you accept, the new owner will take over all responsibilities and
permissions associated with this order.
</Text>
<Text className="text-zinc-600">
If you do not recognize this request or wish to retain ownership, no
further action is required.
</Text>
<div className="w-full h-px bg-zinc-200" />
<TransferActions id={id} token={token} />
</div>
</div>
)
}
+41
View File
@@ -0,0 +1,41 @@
import { Metadata } from "next"
import FeaturedProducts from "@modules/home/components/featured-products"
import Hero from "@modules/home/components/hero"
import { listCollections } from "@lib/data/collections"
import { getRegion } from "@lib/data/regions"
export const metadata: Metadata = {
title: "Medusa Next.js Starter Template",
description:
"A performant frontend ecommerce starter template with Next.js 15 and Medusa.",
}
export default async function Home(props: {
params: Promise<{ countryCode: string }>
}) {
const params = await props.params
const { countryCode } = params
const region = await getRegion(countryCode)
const { collections } = await listCollections({
fields: "id, handle, title",
})
if (!collections || !region) {
return null
}
return (
<>
<Hero />
<div className="py-12">
<ul className="flex flex-col gap-x-6">
<FeaturedProducts collections={collections} region={region} />
</ul>
</div>
</>
)
}
@@ -0,0 +1,106 @@
import { Metadata } from "next"
import { notFound } from "next/navigation"
import { listProducts } from "@lib/data/products"
import { getRegion, listRegions } from "@lib/data/regions"
import ProductTemplate from "@modules/products/templates"
type Props = {
params: Promise<{ countryCode: string; handle: string }>
}
export async function generateStaticParams() {
try {
const countryCodes = await listRegions().then((regions) =>
regions?.map((r) => r.countries?.map((c) => c.iso_2)).flat()
)
if (!countryCodes) {
return []
}
const promises = countryCodes.map(async (country) => {
const { response } = await listProducts({
countryCode: country,
queryParams: { limit: 100, fields: "handle" },
})
return {
country,
products: response.products,
}
})
const countryProducts = await Promise.all(promises)
return countryProducts
.flatMap((countryData) =>
countryData.products.map((product) => ({
countryCode: countryData.country,
handle: product.handle,
}))
)
.filter((param) => param.handle)
} catch (error) {
console.error(
`Failed to generate static paths for product pages: ${
error instanceof Error ? error.message : "Unknown error"
}.`
)
return []
}
}
export async function generateMetadata(props: Props): Promise<Metadata> {
const params = await props.params
const { handle } = params
const region = await getRegion(params.countryCode)
if (!region) {
notFound()
}
const product = await listProducts({
countryCode: params.countryCode,
queryParams: { handle },
}).then(({ response }) => response.products[0])
if (!product) {
notFound()
}
return {
title: `${product.title} | Medusa Store`,
description: `${product.title}`,
openGraph: {
title: `${product.title} | Medusa Store`,
description: `${product.title}`,
images: product.thumbnail ? [product.thumbnail] : [],
},
}
}
export default async function ProductPage(props: Props) {
const params = await props.params
const region = await getRegion(params.countryCode)
if (!region) {
notFound()
}
const pricedProduct = await listProducts({
countryCode: params.countryCode,
queryParams: { handle: params.handle },
}).then(({ response }) => response.products[0])
if (!pricedProduct) {
notFound()
}
return (
<ProductTemplate
product={pricedProduct}
region={region}
countryCode={params.countryCode}
/>
)
}
@@ -0,0 +1,33 @@
import { Metadata } from "next"
import { SortOptions } from "@modules/store/components/refinement-list/sort-products"
import StoreTemplate from "@modules/store/templates"
export const metadata: Metadata = {
title: "Store",
description: "Explore all of our products.",
}
type Params = {
searchParams: Promise<{
sortBy?: SortOptions
page?: string
}>
params: Promise<{
countryCode: string
}>
}
export default async function StorePage(props: Params) {
const params = await props.params;
const searchParams = await props.searchParams;
const { sortBy, page } = searchParams
return (
<StoreTemplate
sortBy={sortBy}
page={page}
countryCode={params.countryCode}
/>
)
}
+17
View File
@@ -0,0 +1,17 @@
import { getBaseURL } from "@lib/util/env"
import { Metadata } from "next"
import "styles/globals.css"
export const metadata: Metadata = {
metadataBase: new URL(getBaseURL()),
}
export default function RootLayout(props: { children: React.ReactNode }) {
return (
<html lang="en" data-mode="light">
<body>
<main className="relative">{props.children}</main>
</body>
</html>
)
}
+30
View File
@@ -0,0 +1,30 @@
import { ArrowUpRightMini } from "@medusajs/icons"
import { Text } from "@medusajs/ui"
import { Metadata } from "next"
import Link from "next/link"
export const metadata: Metadata = {
title: "404",
description: "Something went wrong",
}
export default function NotFound() {
return (
<div className="flex flex-col gap-4 items-center justify-center min-h-[calc(100vh-64px)]">
<h1 className="text-2xl-semi text-ui-fg-base">Page not found</h1>
<p className="text-small-regular text-ui-fg-base">
The page you tried to access does not exist.
</p>
<Link
className="flex gap-x-1 items-center group"
href="/"
>
<Text className="text-ui-fg-interactive">Go to frontpage</Text>
<ArrowUpRightMini
className="group-hover:rotate-45 ease-in-out duration-150"
color="var(--fg-interactive)"
/>
</Link>
</div>
)
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 229 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 229 KiB