mirror of
https://github.com/blitzkit/blitzkit.git
synced 2026-10-21 18:57:03 +02:00
feat: dialog
This commit is contained in:
1 parent
3aafe4d9f1
commit
8373fb1b7a
5 files changed
+53
-22
No files matched your search
@@ -43,12 +43,16 @@ export class CatalogItemAccessor {
|
||||
return this;
|
||||
}
|
||||
|
||||
get<Type>(Message: MessageFns<Type>, component: string) {
|
||||
getOptional<Type>(Message: MessageFns<Type>, component: string) {
|
||||
if (component in this.components) {
|
||||
return Message.decode(this.components[component].value);
|
||||
}
|
||||
}
|
||||
|
||||
throw new Error(`Unknown component: ${component}`);
|
||||
get<Type>(Message: MessageFns<Type>, component: string) {
|
||||
const value = this.getOptional(Message, component);
|
||||
if (value === undefined) throw new Error(`Unknown component: ${component}`);
|
||||
return value;
|
||||
}
|
||||
|
||||
pack() {
|
||||
|
||||
@@ -1260,7 +1260,7 @@
|
||||
"seo_description": "All World of Tanks Blitz player profile avatars",
|
||||
"description": "Player profile avatars",
|
||||
|
||||
"unnamed_avatar": "Unnamed avatar",
|
||||
"unnamed_avatars": "Unnamed avatars",
|
||||
"search": {
|
||||
"hint": "Search avatars...",
|
||||
"results": "%s1 avatars"
|
||||
|
||||
@@ -1,29 +1,48 @@
|
||||
import type { ProfileAvatarComponent } from '@protos/blitz_static_profile_avatar_component';
|
||||
import type { SellableComponent } from '@protos/blitz_static_sellable_component';
|
||||
import type { StuffUIComponent } from '@protos/blitz_static_stuff_ui_component';
|
||||
import { Badge, Box, Flex, Text } from '@radix-ui/themes';
|
||||
import {
|
||||
Badge,
|
||||
Box,
|
||||
Dialog,
|
||||
Flex,
|
||||
Text,
|
||||
type FlexProps,
|
||||
} from '@radix-ui/themes';
|
||||
import { literals } from 'packages/i18n/src';
|
||||
import { Var } from '../../core/radix/var';
|
||||
import { useLocale } from '../../hooks/useLocale';
|
||||
|
||||
interface AvatarGroupProps {
|
||||
name: string;
|
||||
name?: string;
|
||||
avatars: {
|
||||
stuff: StuffUIComponent;
|
||||
avatar: ProfileAvatarComponent;
|
||||
sellable: SellableComponent;
|
||||
sellable?: SellableComponent;
|
||||
}[];
|
||||
}
|
||||
|
||||
const dx = '4px';
|
||||
const MAX_AVATARS_PREVIEW = 5;
|
||||
|
||||
export function AvatarGroup({ avatars, name }: AvatarGroupProps) {
|
||||
export function AvatarGroup({ name, avatars }: AvatarGroupProps) {
|
||||
return (
|
||||
<Dialog.Root>
|
||||
<Dialog.Trigger>
|
||||
<Content avatars={avatars} name={name} />
|
||||
</Dialog.Trigger>
|
||||
|
||||
<Dialog.Content>asd</Dialog.Content>
|
||||
</Dialog.Root>
|
||||
);
|
||||
}
|
||||
|
||||
function Content({ avatars, name, ...props }: FlexProps & AvatarGroupProps) {
|
||||
const { strings } = useLocale();
|
||||
const avatarsReduced = [...avatars].reverse().slice(0, MAX_AVATARS_PREVIEW);
|
||||
|
||||
return (
|
||||
<Flex direction="column" gap="3">
|
||||
<Flex direction="column" gap="3" style={{ cursor: 'pointer' }} {...props}>
|
||||
<Box width="100%" style={{ aspectRatio: '7 / 8' }} position="relative">
|
||||
{avatarsReduced.map((avatar, index) => (
|
||||
<Box
|
||||
@@ -35,7 +54,7 @@ export function AvatarGroup({ avatars, name }: AvatarGroupProps) {
|
||||
style={{
|
||||
filter: `brightness(${(index + 1) / avatarsReduced.length})`,
|
||||
borderRadius: Var('radius-2'),
|
||||
boxShadow: Var('shadow-3'),
|
||||
boxShadow: Var('shadow-2'),
|
||||
backgroundImage: `url(${avatar.avatar.avatar})`,
|
||||
backgroundSize: 'cover',
|
||||
backgroundPosition: 'center',
|
||||
@@ -69,9 +88,10 @@ export function AvatarGroup({ avatars, name }: AvatarGroupProps) {
|
||||
style={{
|
||||
overflow: 'hidden',
|
||||
textOverflow: 'ellipsis',
|
||||
fontStyle: name === undefined ? 'italic' : undefined,
|
||||
}}
|
||||
>
|
||||
{name}
|
||||
{name ?? strings.website.tools.avatars.unnamed_avatars}
|
||||
</Text>
|
||||
</Flex>
|
||||
);
|
||||
|
||||
@@ -41,30 +41,37 @@ function Content() {
|
||||
ProfileAvatarComponent,
|
||||
'profileAvatarComponent',
|
||||
);
|
||||
const sellable = item.get(SellableComponent, 'sellableComponent');
|
||||
const name =
|
||||
gameStrings[stuff.display_name] ??
|
||||
strings.website.tools.avatars.unnamed_avatar; // maybe move to dumb component?
|
||||
const sellable = item.getOptional(
|
||||
SellableComponent,
|
||||
'sellableComponent',
|
||||
);
|
||||
const name = gameStrings[stuff.display_name] as string | undefined;
|
||||
|
||||
return { avatar, name, stuff, sellable };
|
||||
})
|
||||
.sort((a, b) => a.stuff.grade - b.stuff.grade)
|
||||
.sort((a, b) => a.name.localeCompare(b.name));
|
||||
const groups: Record<string, typeof avatars> = {};
|
||||
.sort((a, b) =>
|
||||
a.name === undefined
|
||||
? 1
|
||||
: b.name === undefined
|
||||
? -1
|
||||
: a.name.localeCompare(b.name),
|
||||
);
|
||||
const groups = new Map<string | undefined, typeof avatars>();
|
||||
|
||||
for (const avatar of avatars) {
|
||||
if (avatar.name in groups) {
|
||||
groups[avatar.name].push(avatar);
|
||||
if (groups.has(avatar.name)) {
|
||||
groups.get(avatar.name)!.push(avatar);
|
||||
} else {
|
||||
groups[avatar.name] = [avatar];
|
||||
groups.set(avatar.name, [avatar]);
|
||||
}
|
||||
}
|
||||
|
||||
return Object.entries(groups);
|
||||
return [...groups];
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<PageWrapper>
|
||||
<PageWrapper color="gold">
|
||||
<Grid
|
||||
columns={{
|
||||
initial: 'repeat(auto-fill, minmax(6rem, 1fr))',
|
||||
|
||||
@@ -13,6 +13,6 @@ const gameStrings = await metadata.stringsPartial(locale, [
|
||||
]);
|
||||
---
|
||||
|
||||
<ToolLayout tool={avatarsTool} {locale}>
|
||||
<ToolLayout tool={avatarsTool} {locale} >
|
||||
<Page localeData={{ locale, gameStrings }} client:load />
|
||||
</ToolLayout>
|
||||
Reference in new issue
Block a user