Skip to content

[Cleanup] Unify TeamCard and TeamHubCard into shared card shell #341

@samzong

Description

@samzong

Problem

TeamCard.tsx (84 lines) and TeamHubCard.tsx (65 lines) share nearly identical structure:

  • Same motion.div + motionPresets.listItem wrapper
  • Same surface-card flex w-full cursor-pointer flex-col items-start gap-3 rounded-xl p-5 className
  • Same emoji icon layout: h-10 w-10 rounded-lg bg-[var(--bg-tertiary)]
  • Same description: type-body text-[var(--text-secondary)] line-clamp-2
  • Same member count row: type-meta flex items-center gap-1.5 text-[var(--text-muted)]

Only the action buttons differ (chat/edit/delete vs install).

Location

Files:

  • packages/desktop/src/renderer/layouts/TeamsPanel/TeamCard.tsx
  • packages/desktop/src/renderer/layouts/TeamsPanel/TeamHubCard.tsx

Fix Approach

Extract a TeamCardShell component:

interface TeamCardShellProps {
  emoji: string;
  name: string;
  subtitle?: ReactNode;
  description?: string;
  memberCount: number;
  actions: ReactNode;
  topRight?: ReactNode;
  onClick: () => void;
}

function TeamCardShell({ emoji, name, subtitle, description, memberCount, actions, topRight, onClick }: TeamCardShellProps) {
  const { t } = useTranslation();
  return (
    <motion.div {...motionPresets.listItem} onClick={onClick}
      className={cn('surface-card flex w-full cursor-pointer flex-col items-start gap-3 rounded-xl p-5', ...)}>
      <div className="flex w-full items-center justify-between">
        <div className="flex items-center gap-3 min-w-0">
          <span className="flex h-10 w-10 flex-shrink-0 items-center justify-center rounded-lg bg-[var(--bg-tertiary)]">
            <span className="emoji-lg">{emoji}</span>
          </span>
          <div className="min-w-0"><h3 ...>{name}</h3>{subtitle}</div>
        </div>
        {topRight}
      </div>
      {description && <p className="type-body text-[var(--text-secondary)] line-clamp-2">{description}</p>}
      <div className="flex w-full items-center justify-between">
        <div className="type-meta flex items-center gap-1.5 text-[var(--text-muted)]">
          <Users size={13} className="opacity-60" />
          <span>{t('teams.memberCount', { count: memberCount })}</span>
        </div>
        {actions}
      </div>
    </motion.div>
  );
}

Then TeamCard and TeamHubCard become thin wrappers (~15 lines each).

Verification

  1. Run pnpm check — must pass
  2. Visually verify both cards in Teams panel and Hub still render correctly

Context

  • WG: UI & Design System
  • Priority: Low
  • Estimated effort: ~25 minutes

Metadata

Metadata

Assignees

No one assigned

    Labels

    area/uiUI & Design System WGkind/cleanupCategorizes issue or PR as related to code cleanup

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions