feat: discord plug

This commit is contained in:
tresabhi committed 2025-04-02 17:48:51 -05:00
1 parent 8ef355c574
commit 3d940f4b47
7 files changed
+250 -4

No files matched your search

+6
View File
@@ -824,6 +824,12 @@
},
"home": {
"discord": {
"join_short": "Join cool people!",
"join_long": "Join super duper cool people!",
"action": "Discord"
},
"hero": {
"credit": "By %s1 ❤️"
},
@@ -13,7 +13,7 @@ export function BlitzKitTheme({
}: BlitzKitThemeProps) {
return (
<Theme
style={{ minHeight: 'unset', ...style }}
style={{ minHeight: 'unset', display: 'contents', ...style }}
className={`blitzkit-theme ${className}`}
grayColor="mauve"
appearance="dark"
@@ -0,0 +1,21 @@
:root {
--scroll-time: 80s;
}
.scroller-0 {
animation: move-1 var(--scroll-time) linear infinite;
}
.scroller-1 {
animation-delay: var(--scroll-time);
animation: move-1 var(--scroll-time) linear infinite;
}
@keyframes move-1 {
from {
transform: translateY(0);
}
to {
transform: translateY(-100%);
}
}
@@ -0,0 +1,199 @@
import { assertSecret } from '@blitzkit/core';
import { CaretRightIcon } from '@radix-ui/react-icons';
import { Box, Button, Flex, Link, Text } from '@radix-ui/themes';
import { times } from 'lodash-es';
import { getStrings } from '../../core/i18n/getStrings';
import { Var } from '../../core/radix/var';
import type { LocaleAcceptorProps } from '../../hooks/useLocale';
import './index.css';
export interface DiscordWidget {
id: string;
name: string;
instant_invite: string;
channels: any[];
members: Member[];
presence_count: number;
}
export interface Member {
id: string;
username: string;
discriminator: string;
avatar: null;
status: Status;
avatar_url: string;
game?: Game;
}
export interface Game {
name: string;
}
export enum Status {
DND = 'dnd',
Idle = 'idle',
Online = 'online',
}
const COLUMN_COUNT = 3;
const discordServerId = assertSecret(import.meta.env.PUBLIC_DISCORD_SERVER_ID);
const widget = await fetch(
`https://discord.com/api/guilds/${discordServerId}/widget.json`,
).then((response) => response.json() as Promise<DiscordWidget>);
const filteredMembers = widget.members
.filter((member) => {
const isPrivateUsername =
member.username.length === 4 && member.username.endsWith('...');
return !isPrivateUsername;
})
.sort(() => Math.random() - 0.5);
const columnSize = Math.floor(filteredMembers.length / COLUMN_COUNT);
const columns = times(COLUMN_COUNT, (index) => {
const start = index * columnSize;
const end = start + columnSize;
return filteredMembers.slice(start, end);
});
function Member({ id, avatar_url, username, status }: Member) {
let statusColor: string;
switch (status) {
case Status.DND:
statusColor = Var('red-9');
break;
case Status.Idle:
statusColor = Var('amber-9');
break;
case Status.Online:
statusColor = Var('jade-9');
break;
}
return (
<Text
style={{
maxWidth: '8rem',
whiteSpace: 'nowrap',
overflow: 'hidden',
textOverflow: 'ellipsis',
flexShrink: 0,
}}
color="gray"
>
<Flex key={id} align="center" gap="2" flexShrink="0">
<Box width="1.5em" height="1.5em" flexShrink="0" position="relative">
<img
src={avatar_url}
alt={`${username} profile picture`}
style={{ width: '100%', height: '100%', borderRadius: '50%' }}
/>
<Box
width="0.5em"
height="0.5em"
position="absolute"
bottom="0"
right="0"
style={{ borderRadius: '50%', backgroundColor: statusColor }}
/>
</Box>
{username}
</Flex>
</Text>
);
}
function Scroller({ index }: { index: number }) {
return (
<Flex gap="6" className={`scroller-${index}`} pt="2">
{columns.map((column) => (
<Flex direction="column" gap="2">
{column.map((member) => (
<Member key={member.id} {...member} />
))}
</Flex>
))}
</Flex>
);
}
export function DiscordPlug({ locale }: LocaleAcceptorProps) {
const strings = getStrings(locale);
return (
<Flex justify="center" flexGrow="1" flexShrink="0">
<Link
style={{ display: 'contents' }}
href="https://discord.gg/nDt7AjGJQH"
target="_blank"
>
<Flex
direction="column"
maxWidth="26rem"
overflow="hidden"
style={{
borderRadius: Var('radius-2'),
}}
>
<Box
height="5rem"
style={{
perspective: '32rem',
background: `linear-gradient(90deg, ${Var('indigo-2')}, ${Var('blue-2')}, ${Var('purple-2')})`,
}}
position="relative"
overflow="hidden"
>
<Flex
top="-250%"
position="absolute"
direction="column"
width="fit-content"
height="32rem"
flexGrow="1"
overflow="hidden"
style={{
transform: 'rotateX(60deg) rotateZ(-20deg)',
}}
>
<Scroller index={0} />
<Scroller index={1} />
</Flex>
</Box>
<Flex
align="center"
justify="between"
p="3"
gap="4"
style={{
background: `linear-gradient(90deg, ${Var('indigo-3')}, ${Var('blue-3')}, ${Var('purple-3')})`,
}}
>
<Box display={{ initial: 'block', xs: 'none' }}>
<Text color="gray" highContrast>
{strings.website.home.discord.join_short}
</Text>
</Box>
<Box display={{ initial: 'none', xs: 'block' }}>
<Text color="gray" highContrast>
{strings.website.home.discord.join_long}
</Text>
</Box>
<Button color="iris">
{strings.website.home.discord.action}
<CaretRightIcon />
</Button>
</Flex>
</Flex>
</Link>
</Flex>
);
}
@@ -10,7 +10,14 @@ export function HomeLocaleSwitcher({
}: LocaleAcceptorProps) {
return (
<BlitzKitTheme>
<Flex justify="center" mt="4" py="6" align="center" gap="3">
<Flex
flexGrow="2"
flexShrink="0"
justify="center"
mt="4"
align="center"
gap="3"
>
<Text size="5" trim="end" color="gray">
<GlobeIcon width="1em" height="1em" />
</Text>
@@ -83,7 +83,7 @@ function Content() {
const { locale, strings } = useLocale();
return (
<Flex direction="column" pt="4" pb="8">
<Flex direction="column" pt="4">
<Heading align="center" size="5">
{strings.website.home.hot_tanks.title}
</Heading>
@@ -5,6 +5,7 @@ import { literals } from '@blitzkit/i18n/src/literals';
import { Box, Flex, Heading, Link } from '@radix-ui/themes';
import type { GetStaticPaths } from 'astro';
import { AesonPlug } from '../../components/AesonPlug';
import { DiscordPlug } from '../../components/Discord';
import { HomeLocaleSwitcher } from '../../components/Home/HomeLocaleSwitcher';
import HomeHero from '../../components/HomeHero.astro';
import { HomePageHotTanks } from '../../components/HomePageHotTanks';
@@ -45,7 +46,19 @@ export const getStaticPaths = (() => {
<BaseLayout>
<HomeHero />
<HomeLocaleSwitcher {locale} client:load />
<Flex justify="center" py="6" px="4" justify="center">
<Flex
wrap="wrap"
justify="between"
maxWidth="64rem"
gap="6"
align="center"
flexGrow="1"
>
<HomeLocaleSwitcher {locale} client:load />
<DiscordPlug {locale} />
</Flex>
</Flex>
{
locale !== DEFAULT_LOCALE && (