Files
medusa-store/packages/admin-next/dashboard/src/components/common/skeleton/skeleton.tsx
Kasper Fabricius Kristensen ef29981a54 fix(dashboard): Update API keys domains with new design (#7123)
**What**
- Adds new design
- Separates secret and publishable keys into two domains (re-uses the same code).
- Adds skeleton layout for loading state of details page.
- Adds toasts.
2024-04-22 20:03:28 +00:00

228 lines
5.3 KiB
TypeScript

import { Container, Heading, Text, clx } from "@medusajs/ui"
import { CSSProperties, ComponentPropsWithoutRef } from "react"
type SkeletonProps = {
className?: string
style?: CSSProperties
}
export const Skeleton = ({ className, style }: SkeletonProps) => {
return (
<div
aria-hidden
className={clx(
"bg-ui-bg-component h-3 w-3 animate-pulse rounded-[4px]",
className
)}
style={style}
/>
)
}
type TextSkeletonProps = {
size?: ComponentPropsWithoutRef<typeof Text>["size"]
leading?: ComponentPropsWithoutRef<typeof Text>["leading"]
characters?: number
}
type HeadingSkeletonProps = {
level?: ComponentPropsWithoutRef<typeof Heading>["level"]
characters?: number
}
export const HeadingSkeleton = ({
level = "h1",
characters = 10,
}: HeadingSkeletonProps) => {
let charWidth = 9
switch (level) {
case "h1":
charWidth = 11
break
case "h2":
charWidth = 10
break
case "h3":
charWidth = 9
break
}
return (
<Skeleton
className={clx({
"h-7": level === "h1",
"h-6": level === "h2",
"h-5": level === "h3",
})}
style={{
width: `${charWidth * characters}px`,
}}
/>
)
}
export const TextSkeleton = ({
size = "small",
leading = "compact",
characters = 10,
}: TextSkeletonProps) => {
let charWidth = 9
switch (size) {
case "xlarge":
charWidth = 13
break
case "large":
charWidth = 11
break
case "base":
charWidth = 10
break
case "small":
charWidth = 9
break
case "xsmall":
charWidth = 8
break
}
return (
<Skeleton
className={clx({
"h-5": size === "xsmall",
"h-6": size === "small",
"h-7": size === "base",
"h-8": size === "xlarge",
"!h-5": leading === "compact",
})}
style={{
width: `${charWidth * characters}px`,
}}
/>
)
}
export const IconButtonSkeleton = () => {
return <Skeleton className="h-7 w-7 rounded-md" />
}
type GeneralSectionSkeletonProps = {
rowCount?: number
}
export const GeneralSectionSkeleton = ({
rowCount,
}: GeneralSectionSkeletonProps) => {
const rows = Array.from({ length: rowCount ?? 0 }, (_, i) => i)
return (
<Container className="divide-y p-0" aria-hidden>
<div className="flex items-center justify-between px-6 py-4">
<HeadingSkeleton characters={16} />
<IconButtonSkeleton />
</div>
{rows.map((row) => (
<div
key={row}
className="grid grid-cols-2 items-center px-6 py-4"
aria-hidden
>
<TextSkeleton size="small" leading="compact" characters={12} />
<TextSkeleton size="small" leading="compact" characters={24} />
</div>
))}
</Container>
)
}
type TableSkeletonProps = {
rowCount?: number
search?: boolean
filters?: boolean
orderBy?: boolean
pagination?: boolean
layout?: "fit" | "fill"
}
export const TableSkeleton = ({
rowCount = 10,
search = true,
filters = true,
orderBy = true,
pagination = true,
layout = "fit",
}: TableSkeletonProps) => {
// Row count + header row
const totalRowCount = rowCount + 1
const rows = Array.from({ length: totalRowCount }, (_, i) => i)
const hasToolbar = search || filters || orderBy
return (
<div
aria-hidden
className={clx({
"flex h-full flex-col overflow-hidden": layout === "fill",
})}
>
{hasToolbar && (
<div className="flex items-center justify-between px-6 py-4">
{filters && <Skeleton className="h-7 w-full max-w-[135px]" />}
{(search || orderBy) && (
<div className="flex items-center gap-x-2">
{search && <Skeleton className="h-7 w-[160px]" />}
{orderBy && <Skeleton className="h-7 w-7" />}
</div>
)}
</div>
)}
<div className="flex flex-col divide-y border-y">
{rows.map((row) => (
<Skeleton key={row} className="h-10 w-full rounded-none" />
))}
</div>
{pagination && (
<div
className={clx("flex items-center justify-between p-4", {
"border-t": layout === "fill",
})}
>
<Skeleton className="h-7 w-[138px]" />
<div className="flex items-center gap-x-2">
<Skeleton className="h-7 w-24" />
<Skeleton className="h-7 w-11" />
<Skeleton className="h-7 w-11" />
</div>
</div>
)}
</div>
)
}
export const TableSectionSkeleton = (props: TableSkeletonProps) => {
return (
<Container className="divide-y p-0" aria-hidden>
<div className="flex items-center justify-between px-6 py-4" aria-hidden>
<HeadingSkeleton level="h2" characters={16} />
<IconButtonSkeleton />
</div>
<TableSkeleton {...props} />
</Container>
)
}
export const JsonViewSectionSkeleton = () => {
return (
<Container className="divide-y p-0" aria-hidden>
<div className="flex items-center justify-between px-6 py-4" aria-hidden>
<div aria-hidden className="flex items-center gap-x-4">
<HeadingSkeleton level="h2" characters={16} />
<Skeleton className="h-5 w-12 rounded-md" />
</div>
<IconButtonSkeleton />
</div>
</Container>
)
}