1
0

Migrate from Vue2 to React with modern tech stack

- Replace Vue2 + Vue CLI with Vite + React 18 + TypeScript
- Add Tailwind CSS for efficient styling
- Implement clean component architecture:
  - Split 1000+ line Vue component into focused React components
  - Add proper type safety with TypeScript
  - Use React Query for efficient data fetching
- Update GitHub Actions for React build pipeline
- Maintain existing functionality and design
- Support Node.js 23 with .nvmrc

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2025-07-18 13:44:54 +09:00
parent 980e9c1259
commit e7f39a1894
23 changed files with 1064 additions and 22 deletions

View File

@@ -0,0 +1,79 @@
import type { User, Card } from '../../types';
interface UserProfileProps {
user: User;
cards: Card[];
}
export default function UserProfile({ user, cards }: UserProfileProps) {
return (
<div className="bg-white rounded-lg p-6 mb-8">
<h3 className="text-2xl font-bold mb-4 flex items-center gap-2">
<span>{user.username}</span>
{/* Badges */}
<span className="text-yellow-500">
<span className="icon-ai"></span>
</span>
{cards.find(c => c.card === 65) && (
<span className="text-yellow-400">
<span className="icon-ai"></span>
</span>
)}
{user.aiten >= 70000000 && (
<span className="text-yellow-500">
<span className="icon-power"></span>
</span>
)}
</h3>
<div className="grid grid-cols-2 md:grid-cols-4 gap-4 text-sm">
<div>
<strong>ID:</strong> {user.id}
</div>
<div className="flex items-center gap-1">
<span className="icon-power"></span>
{user.aiten?.toLocaleString()}
</div>
<div className="flex items-center gap-1">
<i className="fa-solid fa-cube"></i>
{cards.filter(c => c.skill === 'lost').length}
</div>
<div className="flex items-center gap-1">
<span className="icon-ai"></span>
{cards.filter(c => c.card >= 96 && c.card <= 121).length}
</div>
{user.planet && (
<div className="flex items-center gap-1">
<i className="fa-solid fa-earth-americas"></i>
{user.planet}
</div>
)}
</div>
{/* Badge Images */}
<div className="flex gap-2 mt-4">
{cards.find(c => c.card === 18) && (
<img src="/card/badge_1.png" alt="Badge 1" className="w-6 h-6" />
)}
{cards.find(c => c.card === 41) && (
<img src="/card/badge_2.png" alt="Badge 2" className="w-6 h-6" />
)}
{cards.find(c => c.card === 45) && (
<img src="/card/badge_3.png" alt="Badge 3" className="w-6 h-6" />
)}
{cards.find(c => c.card === 75) && (
<img src="/card/badge_4.png" alt="Badge 4" className="w-6 h-6" />
)}
{cards.find(c => c.card === 94) && (
<img src="/card/badge_5.png" alt="Badge 5" className="w-6 h-6" />
)}
{cards.filter(c => c.card >= 96 && c.card <= 121).length === 26 && (
<img src="/card/badge_6.png" alt="Badge 6" className="w-6 h-6" />
)}
</div>
</div>
);
}