6
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

RCC (立命館コンピュータークラブ)Advent Calendar 2024

Day 2

【React/Next.js】Hover で形が変わる通知付きメールアイコンの作り方

Posted at

はじめに

友人との共同開発時に使用したホバー時に形が変わるメールアイコンを作成したので、その作り方を紹介します。この方法を覚えれば、メールアイコン以外にもホバー時に変化させることができます。

実装

準備

Iconには Lucide Icon を使用しました。以下のコマンドでインストールしてください。

pnpm install lucide-react

Lucide の詳しい使い方はこちらをご覧ください。

要件定義

  • ホバーするとメールが開くような演出
  • 通知の数がわかるように左上に赤丸の数字
  • サイズとカウントを Props として渡せるようにする

コード

'use client'

import React, { useState } from 'react';
import { Mail, MailOpen } from 'lucide-react';

interface MailIconProps {
    count?: number;
    size?: number;
}

export const MailIcon = (p: MailIconProps) => {
    const [hovered, setHovered] = useState(false);
    const count = p.count || 0;
    const iconSize = p.size || 24;
    const badgeSize = Math.max(iconSize * 0.45, 16);
    const fontSize = Math.max(iconSize * 0.25, 10);
    const offset = Math.max(iconSize * 0.2, 6);
    return (
        <div>
            <div
                style={{ position: 'relative', display: 'inline-block' }}
                onMouseEnter={() => setHovered(true)}
                onMouseLeave={() => setHovered(false)}
            >
                {hovered ? (
                    <MailOpen size={iconSize} />
                ) : (
                    <Mail size={iconSize} />
                )}
                {count > 0 && (
                    <div
                        style={{
                            position: 'absolute',
                            top: -offset,
                            right: -offset,
                            backgroundColor: '#E74C3C',
                            color: 'white',
                            borderRadius: '50%',
                            padding: '2px',
                            fontSize: `${fontSize}px`,
                            minWidth: `${badgeSize}px`,
                            height: `${badgeSize}px`,
                            lineHeight: `${badgeSize - 4}px`,
                            textAlign: 'center'
                        }}
                    >
                        {count >= 100 ? '99+' : count}
                    </div>
                )}
            </div>
        </div>
    );
};

コードの説明

  1. コンポーネントの入力の定義

    メール数とアイコンサイズを定義します。?はオプショナルといい、入力があってもなくてもいいことを示します。

    interface MailIconProps {
        count?: number;  // メール数
        size?: number;   // アイコンサイズ
    }
    

  2. 状態管理

    ホバー状態の管理や、カウント・サイズの初期値設定を行います。

    const [hovered, setHovered] = useState(false);  // ホバー状態の管理
    const count = p.count || 0;                     // カウント未指定時は0
    const iconSize = p.size || 24;                  // サイズ未指定時は24px
    

  3. サイズ計算

    通知バッジのサイズ計算をします。

    const badgeSize = Math.max(iconSize * 0.45, 16);  // バッジの大きさ(最小16px)
    const fontSize = Math.max(iconSize * 0.25, 10);   // フォントサイズ(最小10px)
    const offset = Math.max(iconSize * 0.2, 6);       // オフセット(最小6px)
    

  4. アイコンのレンダリング

    React での hover 管理は onMouseEnter がホバーされた時の動作で、onMouseLeave はホバーが離れた時の動作を表します。

    <div
        style={{ position: 'relative', display: 'inline-block' }}
        onMouseEnter={() => setHovered(true)}
        onMouseLeave={() => setHovered(false)}
    >
        {hovered ? (
            <MailOpen size={iconSize} />
        ) : (
            <Mail size={iconSize} />
        )}
    

  5. 通知バッジのレンダリング

    メールがある時だけバッジを表示し、100 以上は '99+' と表示してスタイルを崩さないようにしています。

    {count > 0 && (  // カウントが0より大きい時だけバッジを表示
        <div
            style={{
                position: 'absolute',
                top: -offset,         // 上方向にオフセット
                right: -offset,       // 右方向にオフセット
                backgroundColor: '#E74C3C',  // 赤色背景
                color: 'white',       // 白文字
                borderRadius: '50%',  // 円形に
                padding: '4px',
                fontSize: `${fontSize}px`,
                minWidth: `${badgeSize}px`,
                height: `${badgeSize}px`,
                lineHeight: `${badgeSize - 8}px`,  // 縦方向の中央揃えpadding分の8px
                textAlign: 'center'   // 横方向の中央揃え
            }}
        >
            {count >= 100 ? '99+' : count}  // 100以上の場合は'99+'と表示
        </div>
    )}
    

  6. コンポーネントの使用例

    <MailIcon count={5} size={32} />
    

    また、このようにすると画面遷移のアイコンとして利用できます。

    <a href="/mail">
        <MailIcon count={ notificationNumber } size={ iconSize }/>
    </a>
    

結果

画面収録 2024-12-02 15.43.02.gif

99 以上の場合:
image.png

まとめ

今回は、ホバー時に形が変わる通知付きのメールアイコンの作り方を紹介しました。細かい点ではありますが、少しでもアニメーションがあると楽しくなりますよね。メールアイコン以外にも、同様の手法が使えると思います。

それでは、みなさんよいエンジニアライフを〜👋

6
4
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
6
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?