This commit is contained in:
Lokimorty 2025-12-11 23:27:32 -08:00 committed by GitHub
commit d4b4230f69
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 43 additions and 10 deletions

View file

@ -13,6 +13,7 @@ import { X } from 'lucide-react';
import { Avatar } from '@/components/common/Avatar';
import { LoadingPanel } from '@/components/common/LoadingPanel';
import { useMessages, useWebsiteSessionQuery } from '@/components/hooks';
import { isLikelyBot } from '@/lib/botDetection';
import { SessionActivity } from './SessionActivity';
import { SessionData } from './SessionData';
import { SessionInfo } from './SessionInfo';
@ -51,7 +52,7 @@ export function SessionProfile({
)}
<Column gap="6">
<Row justifyContent="center" alignItems="center" gap="6">
<Avatar seed={data?.id} size={128} />
<Avatar seed={data?.id} size={128} isBot={isLikelyBot(data)} />
<Column width="360px">
<TextField label="ID" value={data?.id} allowCopy />
</Column>

View file

@ -4,6 +4,7 @@ import { Avatar } from '@/components/common/Avatar';
import { DateDistance } from '@/components/common/DateDistance';
import { TypeIcon } from '@/components/common/TypeIcon';
import { useFormat, useMessages, useNavigation } from '@/components/hooks';
import { isLikelyBot } from '@/lib/botDetection';
export function SessionsTable(props: DataTableProps) {
const { formatMessage, labels } = useMessages();
@ -15,7 +16,7 @@ export function SessionsTable(props: DataTableProps) {
<DataColumn id="id" label={formatMessage(labels.session)} width="100px">
{(row: any) => (
<Link href={updateParams({ session: row.id })}>
<Avatar seed={row.id} size={32} />
<Avatar seed={row.id} size={32} isBot={isLikelyBot(row)} />
</Link>
)}
</DataColumn>

View file

@ -1,21 +1,27 @@
import { lorelei } from '@dicebear/collection';
import { createAvatar } from '@dicebear/core';
import { bottts, lorelei } from '@dicebear/collection';
import { createAvatar, type Style } from '@dicebear/core';
import { useMemo } from 'react';
import { getColor, getPastel } from '@/lib/colors';
const lib = lorelei;
export function Avatar({ seed, size = 128, ...props }: { seed: string; size?: number }) {
export function Avatar({
seed,
size = 128,
isBot = false,
}: {
seed: string;
size?: number;
isBot?: boolean;
}) {
const backgroundColor = getPastel(getColor(seed), 4);
const style = (isBot ? bottts : lorelei) as Style<object>;
const avatar = useMemo(() => {
return createAvatar(lib, {
...props,
return createAvatar(style, {
seed,
size,
backgroundColor: [backgroundColor],
}).toDataUri();
}, []);
}, [seed, isBot]);
return <img src={avatar} alt="Avatar" style={{ borderRadius: '100%', width: size }} />;
}

25
src/lib/botDetection.ts Normal file
View file

@ -0,0 +1,25 @@
const BOT_CITIES = [
'Council Bluffs',
'North Richland Hills',
'Santa Clara',
'Ashburn',
'The Dalles',
'Boardman',
'Quincy',
];
export function isLikelyBot(session: {
city?: string;
firstAt?: string | Date;
lastAt?: string | Date;
}): boolean {
const cityMatch =
session.city && BOT_CITIES.some(botCity => session.city?.toLowerCase() === botCity.toLowerCase());
const zeroDuration =
session.firstAt &&
session.lastAt &&
new Date(session.firstAt).getTime() === new Date(session.lastAt).getTime();
return !!(cityMatch && zeroDuration);
}