mirror of
https://github.com/blitzkit/blitzkit.git
synced 2026-10-21 18:57:03 +02:00
feat: discord plug
This commit is contained in:
1 parent
8ef355c574
commit
3d940f4b47
7 files changed
+250
-4
No files matched your search
@@ -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 && (
|
||||
|
||||
Reference in new issue
Block a user