tailwindcssでAdmin向けの管理画面レイアウトを作る
を参考にAdmin向けの管理画面レイアウトを作った。
レイアウトのみの完成形は以下。
セットアップ
ホットリロードを利用したいためtailwindcliではなくviteで構築をした。
fontsを設定する
inter fontの埋め込みコードを取得する。
themeにfontFamilyを追加することで、font-inter
クラスが利用できる。
/** @type {import('tailwindcss').Config} */
module.exports = {
content: ["index.html"],
theme: {
extend: {
+ fontFamily: {
+ 'inter': ['Inter', 'sans-serif'],
+ },
},
},
plugins: [],
}
サイドバーの作成
レイアウトの指定
fixed
クラスを利用して、サイドバーを画面上部にレイアウト固定する
<body class="text-gray-800 font-inter">
+ <!-- Sidebar -->
+ <div class="fixed left-0 top-0 w-64 h-full bg-gray-900">
+ </div>
</div>
ロゴの指定
ロゴデザイン用の検証にはplaceholdを利用する。
object-cover
はアスペクト比を維持したまま、コンテンツボックス全体を埋める。
<!-- Sidebar -->
<div class="fixed left-0 top-0 w-64 h-full bg-gray-900 p-4">
+ <div class="flex items-center">
+ <img src="https://placehold.co/40x40" alt="" class="w-10 h-10 rounded object-cover">
+ <span class="text-lg font-bold text-gray-200">Logo</span>
</div>
</div>
aタグに変更し、aタグの下にborderを配置する
<!-- Sidebar -->
<div class="fixed left-0 top-0 w-64 h-full bg-gray-900 p-4">
+ <a href="#" class="flex items-center pb-4 border-b border-gray-800">
<img src="https://placehold.co/32x32" alt="" class="w-8 h-8 rounded object-cover">
<span class="text-lg font-bold text-white ml-3">Logo</span>
+ </a>
</div>
サイドメニューの作成
メニューアイコンには、remixiconを利用する。
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
+ <link href="https://cdn.jsdelivr.net/npm/remixicon@4.5.0/fonts/remixicon.css" rel="stylesheet"/>
メニューアイコンをグループでまとめてアイコンを適用する。group
クラスにより、親の要素クラスの状態に基づいて、cssを適用する。
<!-- Sidebar -->
<div class="fixed left-0 top-0 w-64 h-full bg-gray-900 p-4">
<a href="#" class="flex items-center pb-4 border-b border-gray-800">
<img src="https://placehold.co/32x32" alt="" class="w-8 h-8 rounded object-cover">
<span class="text-lg font-bold text-white ml-3">Logo</span>
</a>
+ <ul class="mt-4">
+ <li class="mb-1 group active">
+ <a href="#" class="flex items-center py-2 px-4 text-gray-300 hover:bg-gray-950 rounded-md group-[.active]:text-white">
+ <i class="ri-home-2-line mr-3 text-lg"></i>
+ <span class="text-sm">Dashboard</span>
+ </a>
+ </li>
+ ...
+ </ul>
</div>
ネストメニューアイコンを作る
Ordersにネストメニューアイコンを作る
+ <li class="mb-1 group">
+ <a href="#" class="flex items-center py-2 px-4 text-gray-300 hover:bg-gray-950 rounded-md group-[.active]:text-white">
+ <i class="ri-instance-line mr-3 text-lg"></i>
+ <span class="text-sm">Orders</span>
+ </a>
+ <ul class="pl-7 mt-2">
+ <li class="mb-4">
+ <a href="#" class="text-gray-300 text-sm flex items-center before:content-[''] before:w-1 before:h-1 before:bg-gray-300 before:rounded-full before:mr-3">Active order</a>
+ </li>
矢印アイコンを設定する。
<li class="mb-1 group">
<a href="#" class="flex items-center py-2 px-4 text-gray-300 hover:bg-gray-950 rounded-md group-[.active]:text-white">
<i class="ri-instance-line mr-3 text-lg"></i>
<span class="text-sm">Orders</span>
+ <i class="ri-arrow-right-s-line ml-auto group-[.active]:rotate-90"></i>
</a>
jsによるサイドバーのドロップダウン制御
sidebarのdropdownをjsで制御する。
// Sidebar
document.querySelectorAll(".sidebar-dropdown-toggle").forEach((item) => {
item.addEventListener("click", (e) => {
e.preventDefault();
const parent = item.closest(".group");
if (parent.classList.contains("selected")) {
// 閉じる
parent.classList.remove("selected");
} else {
// 開く
document.querySelectorAll(".sidebar-dropdown-toggle").forEach((i) => {
i.closest(".group").classList.remove("selected");
});
parent.classList.add("selected");
}
});
});
サイドバーラップアップ
sidebarのtoggleに関しては、class addによる制御ではなくdata-属性の利用もできる。
classによるtoggleは存在しないクラス名を制御のため追加することになるので、アプリケーションの状態についてはdata-属性を利用するほうがいいかと思われる。
tailwind3.2で導入されたdata-attributes-variantsを使えば、cssではなく状態をdata-*
に記載することができる。
https://railsdesigner.com/data-attributes-magic/ を参考に実行してみた。
<li class="mb-1 group">
<a href="#" class="flex items-center py-2 px-4 text-gray-300 hover:bg-gray-950 hover:text-gray-100 rounded-md group-[.active]:bg-gray-800 group-[.active]:text-white group-data-[state-opened]:bg-gray-950 group-data-[state-opened]:text-gray-100 sidebar-dropdown-toggle">
<i class="ri-instance-line mr-3 text-lg"></i>
<span class="text-sm">Orders</span>
<i class="ri-arrow-right-s-line ml-auto group-data-[state-opened]:rotate-90"></i>
</a>
<ul class="pl-7 mt-2 hidden group-data-[state-opened]:block">
<li class="mb-4">
<a href="#" class="text-gray-300 text-sm flex items-center hover:text-gray-100 before:contents-[''] before:w-1 before:h-1 before:rounded-full before:bg-gray-300 before:mr-3">Active order</a>
</li>
<li class="mb-4">
<a href="#" class="text-gray-300 text-sm flex items-center hover:text-gray-100 before:contents-[''] before:w-1 before:h-1 before:rounded-full before:bg-gray-300 before:mr-3">Completed order</a>
</li>
<li class="mb-4">
<a href="#" class="text-gray-300 text-sm flex items-center hover:text-gray-100 before:contents-[''] before:w-1 before:h-1 before:rounded-full before:bg-gray-300 before:mr-3">Canceled order</a>
</li>
</ul>
</li>
// Sidebar
document.querySelectorAll(".sidebar-dropdown-toggle").forEach((item) => {
item.addEventListener("click", (e) => {
e.preventDefault();
const parent = item.closest(".group");
if (parent.hasAttribute("data-state-opened")) {
// 閉じる
parent.removeAttribute("data-state-opened");
} else {
// 開く
document.querySelectorAll(".sidebar-dropdown-toggle").forEach((i) => {
i.closest(".group").removeAttribute("data-state-opened");
});
parent.toggleAttribute("data-state-opened");
}
});
});
Mainコンテンツ
Mainコンテンツ枠を作る
+ <main class="w-[calc(100%-256px)] ml-64">
+ <div class="py-2 px-4 hg-white flex items-center">
+ Hi
+ </div>
+ </main>
Menuアイコンを指定する
shadow-black/5
で透明を5%に指定する。
パンくずの指定
<!-- Main -->
<main class="w-[calc(100%-256px)] ml-64 bg-gray-50 min-h-screen">
+ <div class="py-2 px-4 hg-white flex items-center shadow-md shadow-black/5">
+ <button type="button" class="text-lg text-gray-600">
+ <i class="ri-menu-line"></i>
+ </button>
+ <ul class="flex items-center ml-4">
+ <li class="mr-2">
+ <a href="#" class="text-gray-400 text-sm hover:text-gray-600">Dashboard</a>
+ </li>
+ <li class="text-gray-600 mr-2 font-medium">/</li>
+ <li class="text-gray-600 mr-2 font-medium">Analytics</li>
+ </ul>
</div>
</main>
Searchメニューアイコンを作る
ml-auto
で、利用可能なスペースをすべて左マージンとして利用するため、Searchメニューアイコンは右寄せになる。
+ <!-- ヘッダーの右側 -->
+ <ul class="ml-auto flex items-center">
+ <li>
+ <button type="button" class="text-gray-400 w-8 h-8 rounded flex items-center justify-center hover:bg-gray-50 hover:text-gray-600">
+ <i class="ri-search-line"></i>
+ </button>
+ </li>
+ <li>
+ <button type="button" class="text-gray-400 w-8 h-8 rounded flex items-center justify-center hover:bg-gray-50 hover:text-gray-600">
+ <i class="ri-notification-3-line"></i>
+ </button>
+ </li>
+ <li>
+ <button type="button">
+ <img src="https://placehold.co/32x32" alt="" class="w-8 h-8 rounded block object-cover align-middle">
+ </button>
+ </li>
+ </ul>
Dropdownメニューを作る
<button type="button" class="text-gray-400 w-8 h-8 rounded flex items-center justify-center hover:bg-gray-50 hover:text-gray-600">
<i class="ri-search-line"></i>
</button>
+ <div class="dropdown-menu absolute max-w-xs w-full bg-white rounded-md border border-gray-100">
+ <form action="" class="p-4">
+ <div class="relative w-full">
+ <input type="text" class="py-2 pr-4 pl-10 bg-gray-50 w-full outline-none border border-gray-100 rounded-md text-sm focus:border-blue-500" palceholder="Search...">
+ <i class="ri-search-line absolute top-1/2 left-4 -translate-y-1/2 text-gray-400"></i>
+ </div>
+ </form>
+ </div>
</li>
dropdownにpopperjsを適用する
<!-- ヘッダーの右側 -->
<ul class="ml-auto flex items-center">
- <li>
- <button type="button" class="text-gray-400 w-8 h-8 rounded flex items-center justify-center hover:bg-gray-50 hover:text-gray-600">
+ <li class="mr-1 dropdown">
+ <button type="button" class="dropdown-toggle text-gray-400 w-8 h-8 rounded flex items-center justify-center hover:bg-gray-50 hover:text-gray-600">
<i class="ri-search-line"></i>
</button>
- <div class="dropdown-menu absolute max-w-xs w-full bg-white rounded-md border border-gray-100">
- <form action="" class="p-4">
+ <div class="dropdown-menu hidden absolute max-w-xs w-full bg-white rounded-md border border-gray-100">
+ <form action="" class="p-4 border-b border-gray-100">
<div class="relative w-full">
<input type="text" class="py-2 pr-4 pl-10 bg-gray-50 w-full outline-none border border-gray-100 rounded-md text-sm focus:border-blue-500" palceholder="Search...">
<i class="ri-search-line absolute top-1/2 left-4 -translate-y-1/2 text-gray-400"></i>
</form>
</div>
</li>
- <li>
+ <li class="mr-1">
<button type="button" class="text-gray-400 w-8 h-8 rounded flex items-center justify-center hover:bg-gray-50 hover:text-gray-600">
<i class="ri-notification-3-line"></i>
</button>
</ul>
</div>
</main>
+ <script src="https://unpkg.com/@popperjs/core@2"></script>
<script src="/src/js/script.js"></script>
</body>
</html>
お知らせ枠の作成
truncate
クラスでテキストオーバーフロー時の挙動を設定する
</form>
+ <div class="mt-3 mb-2">
+ <div class="text-[13px] font-medium text-gray-400 ml-4 mb-2">Recent</div>
+ <ul class="max-h-64 overflow-y-auto">
+ <li>
+ <a href="#" class="py-2 px-4 flex items-center hover:bg-gray-50 group">
+ <img src="https://placehold.co/32x32" alt="" class="w-8 h-8 rounded block object-cover align-middle">
+ <div class="ml-2">
+ <div class="text-[13px] text-gray-600 font-medium truncate group-hover:text-blue-500">Create landing page</div>
+ <div class="text-[12px] text-gray-600">$345</div>
+ </div>
+ </a>
+ </li>
+ <li>
ラップアップ
管理画面レイアウトをtailwindcssを作って構築。サイドバーの構築やヘッダーの右寄せのやり方がわかった。ただ状態制御がcssを使って制御して、好みではなかったので途中離脱した。
他に管理画面レイアウトの作り方はshadcnを参考によりシンプルに実装できる気がする。
また、shadcnでもコンポーネントではなくブロックも公開されるようになっている。
Discussion