🙌

ポケモンカードをReactで実装してみた

2025/01/20に公開2

はじめに

ポケポケやってますか?

課金額850億円以上で業績大幅上昇見込みということで、流石にこれは触ってみないといけないと思い、触ってみたらUIが凄すぎて感動しました

https://game.watch.impress.co.jp/docs/news/1651226.html

こんなUIを私も実装できたらいいなと感じたので、今回自分の自己紹介サイトにポケモンカードを実装してみました

https://my-dq-portfolio.vercel.app/portfolio

https://github.com/developerhost/my-dq-portfolio

(良かったらスターくれると嬉しいです!)

実装詳細

こちらのリポジトリを参考にReactとtailwindcssで実装しました

https://github.com/simeydotme/pokemon-cards-css

作成するファイルは以下の3つです

  • src/components/pokemon/cards.ts (カードの情報をおいておく)
  • src/components/pokemon/PokemonCard.tsx (カード一つの見た目のコンポーネント)
  • src/components/pokemon/PokemonCardList.tsx (複数のカードの見た目のコンポーネント)

カード情報

ここには好きなポケモンを配置してください

https://poke-holo.simey.me/

私はここのサイトから開発者ツールを開いて画像のurlを取得してきてそれを表示しています

src/components/pokemon/cards.ts

export const pokemonCards = [
  {
    id: '1',
    name: 'ミュウ',
    description: '釣り竿で釣ることができる',
    img: 'https://images.pokemontcg.io/swsh8/269_hires.png',
    back: 'https://tcg.pokemon.com/assets/img/global/tcg-card-back-2x.jpg',
  },
  {
    id: '2',
    name: 'ミュウツー',
    description: 'ミュウの遺伝子から生み出された',
    img: 'https://images.pokemontcg.io/swshp/SWSH229_hires.png',
    back: 'https://tcg.pokemon.com/assets/img/global/tcg-card-back-2x.jpg',
  },
  {
    id: '3',
    name: 'ゲンガー',
    description:
      '暗闇で遭難した人の命を狙い、影に潜り込んでチャンスをうかがう。様々な都市伝説がある。',
    img: 'https://images.pokemontcg.io/swsh1/85_hires.png',
    back: 'https://tcg.pokemon.com/assets/img/global/tcg-card-back-2x.jpg',
  },
  // 他のカードを追加
];

カード一つのコンポーネントです

src/components/pokemon/PokemonCard.tsx

import { useState } from 'react';

type PokemonCardProps = {
  back: string;
  description: string;
  id: string;
  img: string;
  name: string;
};

const PokemonCard = ({ card }: { card: PokemonCardProps }) => {
  const [isHovered, setIsHovered] = useState(false);

  return (
    <div
      className={`relative w-72 h-96 border rounded-lg shadow-lg overflow-hidden transform transition-transform duration-300 ${
        isHovered ? 'scale-105' : ''
      }`}
      onMouseEnter={() => setIsHovered(true)}
      onMouseLeave={() => setIsHovered(false)}
    >
      {/* カードの表面 */}
      <div className="absolute inset-0 bg-black">
        <img
          alt={card.name}
          className="w-full h-full object-cover"
          src={card.img}
        />
      </div>
      {/* カードの裏面 */}
      <div
        className={`absolute inset-0 bg-gradient-to-br from-gray-800 to-gray-600 flex items-center justify-center ${
          isHovered ? 'opacity-0' : 'opacity-100'
        } transition-opacity duration-300`}
      >
        <img alt="Pokémon Card Back" className="w-2/3 h-auto" src={card.back} />
      </div>
      {/* カード情報 */}
      {isHovered && (
        <div className="absolute bottom-0 left-0 right-0 bg-black bg-opacity-75 text-white p-4">
          <h2 className="text-lg font-bold">{card.name}</h2>
          <p className="text-sm">{card.description}</p>
        </div>
      )}
    </div>
  );
};

export default PokemonCard;

複数のカードを表示するコンポーネントです

src/components/pokemon/PokemonCardList.tsx

import PokemonCard from './PokemonCard';

type PokemonCardListProps = {
  cards: {
    back: string;
    description: string;
    id: string;
    img: string;
    name: string;
  }[];
};

const PokemonCardList = ({ cards }: PokemonCardListProps) => {
  return (
    <div className="grid grid-cols-1 sm:grid-cols-2 md:grid-cols-3 lg:grid-cols-4 gap-6 mb-4">
      {cards.map((card) => (
        <PokemonCard card={card} key={card.id} />
      ))}
    </div>
  );
};

export default PokemonCardList;

これをportfolioページにおいています

src/routes/portfolio/index.lazy.tsx

import { pokemonCards } from '@/components/pokemon/cards';
import PokemonCardList from '@/components/pokemon/PokemonCardList';

<PokemonCardList cards={pokemonCards} />

最後に

元のリポジトリはsvelteで書かれていたので、React, tailwindcssに書き直して実装しました
ポケポケは今後さらに盛り上がっていくと思いますので、エコシステムといいますか、有志が作るツールみたいなものも盛り上がったら良いなと感じます

私の自己紹介サイトに実装しています。スターいただけるととても励みになるので、リポジトリへのスターとこの記事へのいいね、共有、コメントなどありましたらすごく嬉しいです。

https://github.com/developerhost/my-dq-portfolio

また、ブラウザゲームも作っているので、そちらも良かったらみてください

https://1-infinity.vercel.app

このポケモンカードは3Dアニメーションも実装できるので、もしこの記事の反響が大きければカードが動くように実装方法を追記しようと思います

ここまで見ていただきありがとうございました

参考

https://github.com/simeydotme/pokemon-cards-css

https://pokemontcg.io/

追記

GPL3.0ライセンス情報を追記しました

https://github.com/developerhost/my-dq-portfolio/blob/main/LICENSE

この紹介をしようと思った動機

  • 参考に貼ったリポジトリを発見したので、実際にポケモンカードのUIを実装できるのか技術的検証をしたかった。リポジトリがsveltで書かれていたので、Reactで実装してみたかった
  • 非公式だとしても、そのコミュニティ自体盛り上げるためのツールを有志が作ることは悪だとは思っていません。結果的にユーザーが増えることはクリエイターにも利益になると思うので、こういう記事を書くことでポケポケ全体が盛り上がれば良いと感じています

Discussion

Koya IWAMURAKoya IWAMURA

素敵なサイトですね!

1点気になったことがありまして、

https://images.pokemontcg.io/xxx
https://tcg.pokemon.com/xxx

等、ポケモンカード公式サイトから画像のリンクを持ってきていると思うのですが、今回作成したサイトに対しアクセスが集中した場合に公式サイトのほうにも負荷が掛かる可能性があるので、こちら側でキャッシュとして画像を保持しておく&保持しても大丈夫か公式サイトに利用許諾を取ってあると良さそうだなと思いました!

橋田至橋田至

コメント頂きありがとうございます!
やります!