LoginSignup
2
0

More than 1 year has passed since last update.

Contributorsのプロフィールを改善しました

Last updated at Posted at 2021-12-16

ぱっと見ていたところContributorのプロフィールが気になったので色々調整してみました。

アイコンがない

下記のようにContributorsのアイコンが歯抜けになっています。

image.png

GitHubのリンクが設定されているContributorはAPIでアイコンを取ってきているようなのですが、それ以外のユーザーはアイコンがありません。なので埋めることにしました。

こんな感じでアイコンがない人用の画像を準備しておき

export const avatars: string[] = [
  "1447555445.png",
  "1446262260.png",
  "1454668491.png",
  "1478953496.png",
  "1522414407.png",
  "1449057230.png",
  "1479466248.png",
  "1524969274.png",
  "1507063429.png",
  "1522154395.png",
  "1520346636.png",
  "1450533682.png",
  "1461581760.png",
  "1476945442.png",
  "1478445108.png",
  "1503360665.png",
];

あとはなんやかんやアイコンがない人の数を調べてアイコンを順に使うようにして…

  const getDefaultAvatarUrl = useCallback((contributor: Contributor) => {
    const index = contributors.findIndex((c) => c.slug === contributor.slug);
    const noIconCount = contributors
      .slice(0, index)
      .filter((c) => !getGitHubIconUrl(c)).length;
    const avatarIndex = noIconCount % avatars.length;
    return `/images/avatars/${avatars[avatarIndex]}`;
  }, []);

ちゃんと全員表示されるようになりました。

image.png

プロフィール詳細ページではちゃんと大きく表示されます。

image.png

みんなかっこよくなりましたね!!!

GitHubリンクを設定しなければ表示されるのでこのアバターを試したい人はわざと抜いて楽しみにしてみてください。

アイコンをキャッシュ

上記を実装している途中で気づきましたがアイコンを表示するために毎回GitHubのAPIが呼び出されているのでせめてそのセッション中は何度も呼ばないようキャッシュするようにしておきました。ちなみに対応中にuseEffectの無限ループでAPIを呼びすぎてRate Limitにひっかかったのは内緒です

まずアイコン用のカスタムフックを作成しました。キャッシュの保存にはRecoilを使っています。

const avatarUrlsState = atom<{ [key: string]: string }>({
  key: "contributors/avatarUrls",
  default: {},
});

export const useContributors = () => {
  const [avatarUrls, setAvatarUrls] = useRecoilState(avatarUrlsState);

  const loadAvatarUrl = useCallback(
    async (contributor: Contributor) => {
      if (avatarUrls[contributor.slug]) {
        return;
      }

      const githubUrl = getGitHubIconUrl(contributor);
      if (!githubUrl) {
        setAvatarUrls((avatarUrls) => ({
          ...avatarUrls,
          [contributor.slug]: getDefaultAvatarUrl(contributor),
        }));
        return;
      }

      const user = await getGitHubUser({ githubUrl });
      setAvatarUrls((avatarUrls) => ({
        ...avatarUrls,
        [contributor.slug]: user.avatar_url as string,
      }));
    },
    [Object.keys(avatarUrls).length]
  );

  const getAvatarUrl = useCallback(
    (contributor?: Contributor) => {
      if (!contributor) {
        return undefined;
      }
      return avatarUrls[contributor.slug];
    },
    [Object.keys(avatarUrls).length]
  );

  return { getAvatarUrl, loadAvatarUrl };
};

ちなみにみんな思い思いに色々導入しているので_app.tsxはこんな事になっています。Chakra UIを入れようかと思いましたがやめときました。

function MyApp({ Component, pageProps }: Props) {
  const { layout = (page) => page } = Component;
  return (
    <SessionProvider session={pageProps.session}>
      <VFXProvider>
        <Provider store={store}>
          <RecoilRoot>
            <StyletronProvider value={styletron}>
              <BaseProvider theme={LightTheme}>
                <SnowfallLayout>
                  {layout(<Component {...pageProps} />)}
                </SnowfallLayout>
              </BaseProvider>
            </StyletronProvider>
          </RecoilRoot>
        </Provider>
      </VFXProvider>
    </SessionProvider>
  );
}

アイコンを表示している箇所はトップの一覧とプロフィール詳細の2箇所ありますので、このカスタムフックを使えばどちらでも同様のキャッシュを利用できるようになりました。全体として各々のユーザーごとに1回までしかAPIを呼ばないようにできました。

relを調整

下記のようになっていたので

<a target="_blank" rel="noreferer noreferrer" href={link.url}>

下記に調整しました。

  <a
    target="_blank"
    rel="nofollow noreferrer noopener me"
    href={link.url}
  >

まとめ

以上、良いContributionライフを!

↓ マージされたら反映されます。

2
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0