mirror of
https://github.com/blitzkit/blitzkit.git
synced 2026-10-21 18:57:03 +02:00
feat: code split
This commit is contained in:
1 parent
2c2c3687c7
commit
3aafe4d9f1
6 files changed
+179
-83
No files matched your search
File renamed without changes.
@@ -0,0 +1,78 @@
|
||||
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 { literals } from 'packages/i18n/src';
|
||||
import { Var } from '../../core/radix/var';
|
||||
import { useLocale } from '../../hooks/useLocale';
|
||||
|
||||
interface AvatarGroupProps {
|
||||
name: string;
|
||||
avatars: {
|
||||
stuff: StuffUIComponent;
|
||||
avatar: ProfileAvatarComponent;
|
||||
sellable: SellableComponent;
|
||||
}[];
|
||||
}
|
||||
|
||||
const dx = '4px';
|
||||
const MAX_AVATARS_PREVIEW = 5;
|
||||
|
||||
export function AvatarGroup({ avatars, name }: AvatarGroupProps) {
|
||||
const { strings } = useLocale();
|
||||
const avatarsReduced = [...avatars].reverse().slice(0, MAX_AVATARS_PREVIEW);
|
||||
|
||||
return (
|
||||
<Flex direction="column" gap="3">
|
||||
<Box width="100%" style={{ aspectRatio: '7 / 8' }} position="relative">
|
||||
{avatarsReduced.map((avatar, index) => (
|
||||
<Box
|
||||
position="absolute"
|
||||
top={`calc(${dx} * ${index})`}
|
||||
left={`calc(${dx} * ${index})`}
|
||||
width={`calc(100% - ${dx} * ${avatarsReduced.length - 1})`}
|
||||
height={`calc(100% - ${dx} * ${avatarsReduced.length - 1})`}
|
||||
style={{
|
||||
filter: `brightness(${(index + 1) / avatarsReduced.length})`,
|
||||
borderRadius: Var('radius-2'),
|
||||
boxShadow: Var('shadow-3'),
|
||||
backgroundImage: `url(${avatar.avatar.avatar})`,
|
||||
backgroundSize: 'cover',
|
||||
backgroundPosition: 'center',
|
||||
}}
|
||||
>
|
||||
{avatars.length > 1 && (
|
||||
<Box
|
||||
width="100%"
|
||||
height="100%"
|
||||
style={{
|
||||
background: `linear-gradient(-45deg, ${Var('black-a9')} 25%, ${Var('black-a1')} 50%)`,
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</Box>
|
||||
))}
|
||||
|
||||
{avatars.length > 1 && (
|
||||
<Box position="absolute" bottom="1" right="1">
|
||||
<Badge variant="solid" color="gray" highContrast size="2">
|
||||
{literals(strings.common.units.times, [`${avatars.length}`])}
|
||||
</Badge>
|
||||
</Box>
|
||||
)}
|
||||
</Box>
|
||||
|
||||
<Text
|
||||
size="2"
|
||||
wrap="nowrap"
|
||||
align="center"
|
||||
style={{
|
||||
overflow: 'hidden',
|
||||
textOverflow: 'ellipsis',
|
||||
}}
|
||||
>
|
||||
{name}
|
||||
</Text>
|
||||
</Flex>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
---
|
||||
import { AstroSeo } from '@astrolib/seo';
|
||||
import { type Tool } from '../constants/tools';
|
||||
import { getStrings } from '../core/i18n/getStrings';
|
||||
|
||||
interface Props {
|
||||
tool: Tool;
|
||||
locale: string;
|
||||
}
|
||||
|
||||
const { tool, locale } = Astro.props;
|
||||
const strings = await getStrings(locale);
|
||||
const toolStrings =
|
||||
strings.website.tools[
|
||||
(tool.strings ?? tool.id) as keyof typeof strings.website.tools
|
||||
];
|
||||
---
|
||||
|
||||
<AstroSeo
|
||||
title={toolStrings.name}
|
||||
description={toolStrings.seo_description}
|
||||
canonical={Astro.url.href}
|
||||
openGraph={{
|
||||
url: Astro.url.href,
|
||||
images: [
|
||||
{ url: `${Astro.url.origin}/assets/images/tools/${tool.id}.webp` },
|
||||
],
|
||||
title: toolStrings.name,
|
||||
description: toolStrings.seo_description,
|
||||
site_name: 'BlitzKit',
|
||||
}}
|
||||
twitter={{ cardType: 'summary_large_image' }}
|
||||
/>
|
||||
@@ -0,0 +1,45 @@
|
||||
---
|
||||
import { Box, Flex, Heading, Text } from '@radix-ui/themes';
|
||||
import ToolOpenGraph from '../components/ToolOpenGraph.astro';
|
||||
import { type Tool } from '../constants/tools';
|
||||
import { getStrings } from '../core/i18n/getStrings';
|
||||
import BaseLayout from './BaseLayout.astro';
|
||||
|
||||
interface Props {
|
||||
tool: Tool;
|
||||
locale: string;
|
||||
}
|
||||
|
||||
const { tool, locale } = Astro.props;
|
||||
const strings = await getStrings(locale);
|
||||
const toolStrings =
|
||||
strings.website.tools[
|
||||
(tool.strings ?? tool.id) as keyof typeof strings.website.tools
|
||||
];
|
||||
---
|
||||
|
||||
<ToolOpenGraph {locale} tool={tool} />
|
||||
|
||||
<BaseLayout {locale}>
|
||||
<Box
|
||||
style={{
|
||||
backgroundImage: `url(/assets/tool-backgrounds/${tool.id}.webp)`,
|
||||
backgroundSize: 'cover',
|
||||
}}
|
||||
>
|
||||
<Flex
|
||||
direction="column"
|
||||
align="center"
|
||||
py="6"
|
||||
style={{
|
||||
backdropFilter: 'blur(4rem)',
|
||||
WebkitBackdropFilter: 'blur(4rem)',
|
||||
}}
|
||||
>
|
||||
<Heading size="7">{toolStrings.name}</Heading>
|
||||
<Text>{toolStrings.description}</Text>
|
||||
</Flex>
|
||||
</Box>
|
||||
|
||||
<slot />
|
||||
</BaseLayout>
|
||||
@@ -1,12 +1,12 @@
|
||||
import { ProfileAvatarComponent } from '@protos/blitz_static_profile_avatar_component';
|
||||
import { SellableComponent } from '@protos/blitz_static_sellable_component';
|
||||
import { StuffUIComponent } from '@protos/blitz_static_stuff_ui_component';
|
||||
import { BlitzkitAllAvatarsComponent } from '@protos/blitzkit_static_all_avatars_component';
|
||||
import { Badge, Box, Flex, Grid, Text } from '@radix-ui/themes';
|
||||
import { Grid } from '@radix-ui/themes';
|
||||
import { CatalogItemAccessor } from 'packages/core/src/blitz/catalogItemAccessor';
|
||||
import { literals } from 'packages/i18n/src';
|
||||
import { AvatarGroup } from 'packages/website-ue/src/components/Avatars/Group';
|
||||
import { PageWrapper } from 'packages/website-ue/src/components/PageWrapper';
|
||||
import { metadata } from 'packages/website-ue/src/core/blitz/metadata';
|
||||
import { Var } from 'packages/website-ue/src/core/radix/var';
|
||||
import {
|
||||
LocaleProvider,
|
||||
useLocale,
|
||||
@@ -30,27 +30,25 @@ export function Page({ localeData }: LocaleAcceptorProps) {
|
||||
);
|
||||
}
|
||||
|
||||
const dx = '4px';
|
||||
const MAX_AVATARS_PREVIEW = 5;
|
||||
|
||||
function Content() {
|
||||
const { gameStrings, strings } = useLocale();
|
||||
const groups = useMemo(() => {
|
||||
const avatars = allAvatars
|
||||
.map((avatar) => {
|
||||
const item = new CatalogItemAccessor(avatar);
|
||||
const stuffComponent = item.get(StuffUIComponent, 'UIComponent');
|
||||
const avatarComponent = item.get(
|
||||
.map((id) => {
|
||||
const item = new CatalogItemAccessor(id);
|
||||
const stuff = item.get(StuffUIComponent, 'UIComponent');
|
||||
const avatar = item.get(
|
||||
ProfileAvatarComponent,
|
||||
'profileAvatarComponent',
|
||||
);
|
||||
const sellable = item.get(SellableComponent, 'sellableComponent');
|
||||
const name =
|
||||
gameStrings[stuffComponent.display_name] ??
|
||||
strings.website.tools.avatars.unnamed_avatar;
|
||||
gameStrings[stuff.display_name] ??
|
||||
strings.website.tools.avatars.unnamed_avatar; // maybe move to dumb component?
|
||||
|
||||
return { avatar, name, stuffComponent, avatarComponent };
|
||||
return { avatar, name, stuff, sellable };
|
||||
})
|
||||
.sort((a, b) => a.stuffComponent.grade - b.stuffComponent.grade)
|
||||
.sort((a, b) => a.stuff.grade - b.stuff.grade)
|
||||
.sort((a, b) => a.name.localeCompare(b.name));
|
||||
const groups: Record<string, typeof avatars> = {};
|
||||
|
||||
@@ -68,77 +66,18 @@ function Content() {
|
||||
return (
|
||||
<PageWrapper>
|
||||
<Grid
|
||||
columns="repeat(auto-fill, minmax(8rem, 1fr))"
|
||||
columns={{
|
||||
initial: 'repeat(auto-fill, minmax(6rem, 1fr))',
|
||||
xs: 'repeat(auto-fill, minmax(8rem, 1fr))',
|
||||
}}
|
||||
flow="dense"
|
||||
gapX="4"
|
||||
gapY="6"
|
||||
flexGrow="1"
|
||||
>
|
||||
{groups.map(([name, avatars]) => {
|
||||
const avatarsReduced = [...avatars]
|
||||
.reverse()
|
||||
.slice(0, MAX_AVATARS_PREVIEW);
|
||||
|
||||
return (
|
||||
<Flex direction="column" gap="3" key={name}>
|
||||
<Box
|
||||
width="100%"
|
||||
style={{ aspectRatio: '7 / 8' }}
|
||||
position="relative"
|
||||
>
|
||||
{avatarsReduced.map((avatar, index) => (
|
||||
<Box
|
||||
position="absolute"
|
||||
top={`calc(${dx} * ${index})`}
|
||||
left={`calc(${dx} * ${index})`}
|
||||
width={`calc(100% - ${dx} * ${avatarsReduced.length - 1})`}
|
||||
height={`calc(100% - ${dx} * ${avatarsReduced.length - 1})`}
|
||||
style={{
|
||||
filter: `brightness(${(index + 1) / avatarsReduced.length})`,
|
||||
borderRadius: Var('radius-2'),
|
||||
boxShadow: Var('shadow-3'),
|
||||
backgroundImage: `url(${avatar.avatarComponent.avatar})`,
|
||||
backgroundSize: 'cover',
|
||||
backgroundPosition: 'center',
|
||||
}}
|
||||
>
|
||||
{avatars.length > 1 && (
|
||||
<Box
|
||||
width="100%"
|
||||
height="100%"
|
||||
style={{
|
||||
background: `linear-gradient(-45deg, ${Var('black-a9')} 25%, ${Var('black-a1')} 50%)`,
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</Box>
|
||||
))}
|
||||
|
||||
{avatars.length > 1 && (
|
||||
<Box position="absolute" bottom="1" right="1">
|
||||
<Badge variant="solid" color="gray" highContrast size="3">
|
||||
{literals(strings.common.units.times, [
|
||||
`${avatars.length}`,
|
||||
])}
|
||||
</Badge>
|
||||
</Box>
|
||||
)}
|
||||
</Box>
|
||||
|
||||
<Text
|
||||
size="2"
|
||||
wrap="nowrap"
|
||||
align="center"
|
||||
style={{
|
||||
overflow: 'hidden',
|
||||
textOverflow: 'ellipsis',
|
||||
}}
|
||||
>
|
||||
{name}
|
||||
</Text>
|
||||
</Flex>
|
||||
);
|
||||
})}
|
||||
{groups.map(([name, avatars]) => (
|
||||
<AvatarGroup key={name} name={name} avatars={avatars} />
|
||||
))}
|
||||
</Grid>
|
||||
</PageWrapper>
|
||||
);
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
---
|
||||
import { avatarsTool } from 'packages/website-ue/src/constants/tools';
|
||||
import { metadata } from 'packages/website-ue/src/core/blitz/metadata';
|
||||
import BaseLayout from 'packages/website-ue/src/layouts/BaseLayout.astro';
|
||||
import ToolLayout from 'packages/website-ue/src/layouts/ToolLayout.astro';
|
||||
import { Page } from './_index';
|
||||
|
||||
export { getStaticPaths } from '../index.astro';
|
||||
@@ -12,6 +13,6 @@ const gameStrings = await metadata.stringsPartial(locale, [
|
||||
]);
|
||||
---
|
||||
|
||||
<BaseLayout {locale}>
|
||||
<ToolLayout tool={avatarsTool} {locale}>
|
||||
<Page localeData={{ locale, gameStrings }} client:load />
|
||||
</BaseLayout>
|
||||
</ToolLayout>
|
||||
Reference in new issue
Block a user