27d2ab0f0d
v1.0 Phase 1.1 — repo-wide lint/format baseline. - eslint.config.mjs (flat config) lints server, client, shared - .prettierrc.json, .prettierignore, .editorconfig, .nvmrc - Root package.json holds shared devDeps; per-package scripts keep their typecheck + test runners - Fix 7 lint issues surfaced by the baseline run: - TicketDetail.tsx: replace ternary-with-side-effects with if/else - admin/Users.tsx: escape apostrophe in JSX - errorHandler.ts: typed err as unknown with ErrorLike refinement - users.ts: Prisma.UserUpdateInput instead of Record<string, any> - seed.ts: drop unused goddard binding - Run prettier across tracked sources for a clean formatting baseline
51 lines
1000 B
TypeScript
51 lines
1000 B
TypeScript
const PALETTE = [
|
|
'#ef4444',
|
|
'#f97316',
|
|
'#f59e0b',
|
|
'#10b981',
|
|
'#06b6d4',
|
|
'#3b82f6',
|
|
'#8b5cf6',
|
|
'#ec4899',
|
|
];
|
|
|
|
function nameToColor(name: string): string {
|
|
let hash = 0;
|
|
for (let i = 0; i < name.length; i++) {
|
|
hash = name.charCodeAt(i) + ((hash << 5) - hash);
|
|
}
|
|
return PALETTE[Math.abs(hash) % PALETTE.length];
|
|
}
|
|
|
|
function initials(name: string): string {
|
|
return name
|
|
.split(' ')
|
|
.slice(0, 2)
|
|
.map((n) => n[0])
|
|
.join('')
|
|
.toUpperCase();
|
|
}
|
|
|
|
const SIZES = {
|
|
sm: 'w-6 h-6 text-xs',
|
|
md: 'w-8 h-8 text-sm',
|
|
lg: 'w-10 h-10 text-base',
|
|
};
|
|
|
|
interface AvatarProps {
|
|
name: string;
|
|
size?: keyof typeof SIZES;
|
|
}
|
|
|
|
export default function Avatar({ name, size = 'md' }: AvatarProps) {
|
|
return (
|
|
<div
|
|
className={`${SIZES[size]} rounded-full flex items-center justify-center font-semibold text-white flex-shrink-0 select-none`}
|
|
style={{ backgroundColor: nameToColor(name) }}
|
|
title={name}
|
|
>
|
|
{initials(name)}
|
|
</div>
|
|
);
|
|
}
|