/* * Copyright (C) 2026 Fluxer Contributors * * This file is part of Fluxer. * * Fluxer is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Fluxer is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with Fluxer. If not, see . */ /** @jsxRuntime automatic */ /** @jsxImportSource hono/jsx */ import type {GuildChannel, GuildLookupResult, GuildRole} from '@fluxer/admin/src/api/Guilds'; import {Badge} from '@fluxer/admin/src/components/ui/Badge'; import {EmptyState} from '@fluxer/admin/src/components/ui/EmptyState'; import {HStack} from '@fluxer/admin/src/components/ui/Layout/HStack'; import {VStack} from '@fluxer/admin/src/components/ui/Layout/VStack'; import {Heading, Text} from '@fluxer/admin/src/components/ui/Typography'; import type {AdminConfig as Config} from '@fluxer/admin/src/types/Config'; import {FLUXER_EPOCH} from '@fluxer/constants/src/Core'; import {Button} from '@fluxer/ui/src/components/Button'; import {Card} from '@fluxer/ui/src/components/Card'; import {CsrfInput} from '@fluxer/ui/src/components/CsrfInput'; import {InfoGrid, InfoItem} from '@fluxer/ui/src/components/Layout'; import { getGuildBannerUrl, getGuildEmbedSplashUrl, getGuildIconUrl, getGuildSplashUrl, } from '@fluxer/ui/src/utils/FormatUser'; import type {FC} from 'hono/jsx'; function getCurrentSnowflake(): string { const now = Date.now(); const timestampOffset = now - FLUXER_EPOCH; const snowflake = BigInt(timestampOffset) * 4_194_304n; return snowflake.toString(); } function channelTypeToString(type: number): string { switch (type) { case 0: return 'Text'; case 2: return 'Voice'; case 4: return 'Category'; default: return `Unknown (${type})`; } } function intToHex(i: number): string { if (i === 0) return '000000'; const r = Math.floor(i / 65536) % 256; const g = Math.floor(i / 256) % 256; const b = i % 256; return byteToHex(r) + byteToHex(g) + byteToHex(b); } function byteToHex(byte: number): string { const hexDigits = '0123456789ABCDEF'; const high = Math.floor(byte / 16); const low = byte % 16; return (hexDigits[high] ?? '0') + (hexDigits[low] ?? '0'); } interface OverviewTabProps { config: Config; guild: GuildLookupResult; csrfToken: string; } const RenderChannel: FC<{config: Config; channel: GuildChannel}> = ({config, channel}) => { const currentSnowflake = getCurrentSnowflake(); return ( {channel.name} {channel.id} {channelTypeToString(channel.type)} ); }; const RenderRole: FC<{role: GuildRole}> = ({role}) => { const colorHex = intToHex(role.color); return (
{role.name} {role.id} {role.hoist && Hoisted} {role.mentionable && Mentionable} ); }; const RenderSearchIndexButton: FC<{ config: Config; guildId: string; title: string; indexType: string; csrfToken: string; }> = ({config, guildId, title, indexType, csrfToken}) => { return (
); }; const AssetPreview: FC<{ label: string; url: string | null; hash: string | null; variant: 'square' | 'wide'; }> = ({label, url, hash, variant}) => { const imageClass = variant === 'square' ? 'h-24 w-24 rounded bg-neutral-100 object-cover' : 'h-36 w-full rounded bg-neutral-100 object-cover'; return ( {label} {url ? ( {`${label} ) : (
Not set
)} Hash: {hash ?? 'null'}
); }; export function OverviewTab({config, guild, csrfToken}: OverviewTabProps) { const sortedChannels = [...guild.channels].sort((a, b) => a.position - b.position); const sortedRoles = [...guild.roles].sort((a, b) => b.position - a.position); const iconUrl = getGuildIconUrl(config.mediaEndpoint, guild.id, guild.icon, true); const bannerUrl = getGuildBannerUrl(config.mediaEndpoint, guild.id, guild.banner, true); const splashUrl = getGuildSplashUrl(config.mediaEndpoint, guild.id, guild.splash); const embedSplashUrl = getGuildEmbedSplashUrl(config.mediaEndpoint, guild.id, guild.embed_splash); return ( Assets
Guild Information Owner ID {guild.owner_id} Features {guild.features.length === 0 ? ( No features enabled ) : ( {guild.features.map((feature) => ( {feature} ))} )} Channels ({guild.channels.length}) {guild.channels.length === 0 ? ( No channels ) : ( {sortedChannels.map((channel) => ( ))} )} Roles ({guild.roles.length}) {guild.roles.length === 0 ? ( No roles ) : ( {sortedRoles.map((role) => ( ))} )} Search Index Management Refresh search indexes for this guild.
); }