mirror of
https://github.com/blitzkit/blitzkit.git
synced 2026-10-24 03:59:50 +02:00
feat: groups
This commit is contained in:
1 parent
a7f93698a6
commit
c0c6a21e43
4 files changed
+91
-42
No files matched your search
@@ -4,15 +4,20 @@
|
||||
align-items: center;
|
||||
gap: var(--space-4);
|
||||
|
||||
.avatar-image {
|
||||
.avatar-series {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
aspect-ratio: 7 / 8;
|
||||
border-radius: var(--space-3);
|
||||
|
||||
background-size: cover;
|
||||
background-position: center;
|
||||
.avatar-entry {
|
||||
position: absolute;
|
||||
|
||||
box-shadow: var(--shadow-interactive), var(--shadow-aggressive);
|
||||
border-radius: var(--space-3);
|
||||
box-shadow: var(--shadow-interactive), var(--shadow-aggressive);
|
||||
|
||||
background-size: cover;
|
||||
background-position: center;
|
||||
}
|
||||
}
|
||||
|
||||
.avatar-label {
|
||||
|
||||
@@ -1,27 +1,50 @@
|
||||
import { useGameStrings } from "../../hooks/useGameStrings";
|
||||
import type { Avatar } from "../../protos/avatar";
|
||||
import type { SkeletonProps } from "../../types/SkeletonProps";
|
||||
import { Text } from "../Text";
|
||||
import "./index.css";
|
||||
|
||||
export function AvatarCard(props: SkeletonProps<Avatar>) {
|
||||
const profileAvatarEntityStrings = useGameStrings("ProfileAvatarEntity");
|
||||
interface Props {
|
||||
name: string;
|
||||
avatars: Avatar[];
|
||||
}
|
||||
|
||||
const MAX_CARDS = 3;
|
||||
const CARD_TRIM = "var(--space-3)";
|
||||
|
||||
export function AvatarCard(props: SkeletonProps<Props>) {
|
||||
return (
|
||||
<div className="avatar-card">
|
||||
<div
|
||||
className="avatar-image"
|
||||
style={{
|
||||
backgroundImage: props.skeleton
|
||||
? undefined
|
||||
: `url(/api/avatars/${props.name}.webp)`,
|
||||
}}
|
||||
/>
|
||||
{!props.skeleton && <Series avatars={props.avatars} />}
|
||||
|
||||
<Text align="center" className="avatar-label">
|
||||
{props.skeleton
|
||||
? "LOADING"
|
||||
: profileAvatarEntityStrings[props.stuff_ui!.display_name]}
|
||||
{props.skeleton ? "LOADING" : props.name}
|
||||
</Text>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
interface SeriesProps {
|
||||
avatars: Avatar[];
|
||||
}
|
||||
|
||||
function Series({ avatars }: SeriesProps) {
|
||||
const count = Math.min(avatars.length, MAX_CARDS);
|
||||
|
||||
return (
|
||||
<div className="avatar-series">
|
||||
{avatars.slice(-MAX_CARDS).map((avatar, index) => (
|
||||
<div
|
||||
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)`,
|
||||
}}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -5,9 +5,10 @@ import "./index.css";
|
||||
|
||||
export interface IncrementalLoaderProps<Props> {
|
||||
initial: number;
|
||||
skeleton: number;
|
||||
intermediate: number;
|
||||
rate?: number;
|
||||
|
||||
skeleton?: boolean;
|
||||
data: Props[];
|
||||
Component: (props: SkeletonProps<Props>) => ReactNode;
|
||||
}
|
||||
@@ -17,6 +18,7 @@ export function IncrementalLoader<Props>({
|
||||
rate = 2,
|
||||
data,
|
||||
skeleton,
|
||||
intermediate,
|
||||
Component,
|
||||
}: IncrementalLoaderProps<Props>) {
|
||||
const [count, setCount] = useState(initial);
|
||||
@@ -24,15 +26,19 @@ export function IncrementalLoader<Props>({
|
||||
|
||||
return (
|
||||
<>
|
||||
{sliced.map((item, index) => (
|
||||
<Component key={index} {...item} />
|
||||
))}
|
||||
{!skeleton &&
|
||||
sliced.map((item, index) => <Component key={index} {...item} />)}
|
||||
|
||||
{times(Math.min(skeleton, data.length - count), (index) => (
|
||||
<Item key={index} rate={rate} setCount={setCount}>
|
||||
<Component skeleton />
|
||||
</Item>
|
||||
))}
|
||||
{times(
|
||||
skeleton
|
||||
? initial + intermediate
|
||||
: Math.min(intermediate, data.length - count),
|
||||
(index) => (
|
||||
<Item key={index} rate={rate} setCount={setCount}>
|
||||
<Component skeleton />
|
||||
</Item>
|
||||
)
|
||||
)}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user