mirror of
https://github.com/blitzkit/blitzkit.git
synced 2026-10-25 03:29:51 +01:00
feat: skeleton
This commit is contained in:
1 parent
f7c6fdd861
commit
b50c47b744
11 files changed
+88
-28
No files matched your search
@@ -17,6 +17,13 @@
|
||||
|
||||
background-size: cover;
|
||||
background-position: center;
|
||||
|
||||
&.skeleton {
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.count {
|
||||
@@ -31,5 +38,10 @@
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
width: 100%;
|
||||
|
||||
.skeleton {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,10 @@
|
||||
import { literals } from "@blitzkit/i18n";
|
||||
import { useStrings } from "../../hooks/useStrings";
|
||||
import type { Avatar } from "../../protos/avatar";
|
||||
import type { SkeletonProps } from "../../types/SkeletonProps";
|
||||
import type { PropsWithSkeleton } from "../../types/propsWithSkeleton";
|
||||
import { Badge } from "../Badge";
|
||||
import { InlineSkeleton } from "../InlineSkeleton";
|
||||
import { Skeleton } from "../Skeleton";
|
||||
import { Text } from "../Text";
|
||||
import "./index.css";
|
||||
|
||||
@@ -14,13 +16,13 @@ interface Props {
|
||||
const MAX_CARDS = 3;
|
||||
const CARD_TRIM = "var(--space-3)";
|
||||
|
||||
export function AvatarCard(props: SkeletonProps<Props>) {
|
||||
export function AvatarCard(props: PropsWithSkeleton<Props>) {
|
||||
return (
|
||||
<div className="avatar-card">
|
||||
{!props.skeleton && <Series avatars={props.avatars} />}
|
||||
<Series skeleton={props.skeleton} {...props} />
|
||||
|
||||
<Text align="center" className="avatar-label">
|
||||
{props.skeleton ? "LOADING" : props.name}
|
||||
{props.skeleton ? <InlineSkeleton /> : props.name}
|
||||
</Text>
|
||||
</div>
|
||||
);
|
||||
@@ -30,32 +32,35 @@ interface SeriesProps {
|
||||
avatars: Avatar[];
|
||||
}
|
||||
|
||||
function Series({ avatars }: SeriesProps) {
|
||||
const count = Math.min(avatars.length, MAX_CARDS);
|
||||
function Series(props: PropsWithSkeleton<SeriesProps>) {
|
||||
const count = Math.min(props.skeleton ? 0 : props.avatars.length, MAX_CARDS);
|
||||
const strings = useStrings();
|
||||
|
||||
return (
|
||||
<div className="avatar-series">
|
||||
{avatars.slice(-MAX_CARDS).map((avatar, index) => (
|
||||
<div
|
||||
key={avatar.name}
|
||||
className="avatar-entry"
|
||||
style={{
|
||||
filter: `brightness(${(index + 1) / count})`,
|
||||
top: `calc(${index} * ${CARD_TRIM})`,
|
||||
left: `calc(${index} * ${CARD_TRIM})`,
|
||||
width: `calc(100% - ${CARD_TRIM} * ${count - 1})`,
|
||||
height: `calc(100% - ${CARD_TRIM} * ${count - 1})`,
|
||||
backgroundImage: `url(/api/avatars/${avatar.name}.webp)`,
|
||||
}}
|
||||
/>
|
||||
))}
|
||||
{!props.skeleton &&
|
||||
props.avatars.slice(-MAX_CARDS).map((avatar, index) => (
|
||||
<div
|
||||
key={avatar.name}
|
||||
className="avatar-entry"
|
||||
style={{
|
||||
filter: `brightness(${(index + 1) / count})`,
|
||||
top: `calc(${index} * ${CARD_TRIM})`,
|
||||
left: `calc(${index} * ${CARD_TRIM})`,
|
||||
width: `calc(100% - ${CARD_TRIM} * ${count - 1})`,
|
||||
height: `calc(100% - ${CARD_TRIM} * ${count - 1})`,
|
||||
backgroundImage: `url(/api/avatars/${avatar.name}.webp)`,
|
||||
}}
|
||||
/>
|
||||
))}
|
||||
|
||||
{avatars.length > 1 && (
|
||||
{!props.skeleton && props.avatars.length > 1 && (
|
||||
<Badge color="gray" highContrast className="count">
|
||||
{literals(strings.units.x, { value: avatars.length })}
|
||||
{literals(strings.units.x, { value: props.avatars.length })}
|
||||
</Badge>
|
||||
)}
|
||||
|
||||
{props.skeleton && <Skeleton className="avatar-entry" />}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in new issue
Block a user