一键导入
sitemap-search
Webサイトのサイトマップページとサイト内検索機能を実装する。サイトマップ、サイト内検索、ページ一覧、ナビゲーション、検索機能、困った人向けナビ、コンテキストナビを追加したい時に使用。
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
Webサイトのサイトマップページとサイト内検索機能を実装する。サイトマップ、サイト内検索、ページ一覧、ナビゲーション、検索機能、困った人向けナビ、コンテキストナビを追加したい時に使用。
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
基于 SOC 职业分类
学習指導案(細案・略案)を、学習指導要領に基づいた構成で自動作成するスキル。 Use when: 指導案作成、授業設計、学習指導案、単元計画、細案、略案、本時案
学習指導案を自動生成するスキル。文部科学省の学習指導要領(3観点評価)に完全準拠し、Word/Excel形式への出力指示も行います。 Use when: 指導案、授業計画、単元計画、本時の展開、授業準備、学習指導案を作りたい時、研究授業の準備
学習指導案を作成するスキル。文部科学省の学習指導要領に準拠。 Use when: 指導案、授業計画、単元計画、本時の展開、授業準備、学習指導案を作りたい時。
GAS Webアプリ開発スキル(HIG準拠版)。 Use when: GASでWebアプリを作成、doGet、スプレッドシート連携Webアプリ、HIG準拠、GASウェブアプリ、gas-webapp、Apps Script Webアプリ、Googleサービス連携、Gemini API連携の時。
保護者向けのお便り・連絡文書を作成するスキル。 Use when: 保護者への手紙、お便り、学級通信、連絡文書、案内文、お知らせを作成したい時。
通知表の所見・コメントを作成するスキル。 Use when: 通知表、所見、コメント、成績、評価コメント、学期末の評価を書きたい時。
| name | sitemap-search |
| description | Webサイトのサイトマップページとサイト内検索機能を実装する。サイトマップ、サイト内検索、ページ一覧、ナビゲーション、検索機能、困った人向けナビ、コンテキストナビを追加したい時に使用。 |
| user-invocable | true |
| argument-hint | [framework: react|next|vanilla] [--tags] [--keyboard] [--context-nav] |
Webサイトにサイトマップページとサイト内検索機能を実装するスキル。 ユーザーが目的のページを素早く見つけられるナビゲーション体験を提供。
サイトマップの本来の目的は「困っている人を助ける」こと。 単なるページ一覧だけでは、どのページに行けばいいかわからない。
ユースケースベースでページを案内する:
const contextNavItems = [
{
icon: "🚀",
title: "はじめて使う",
description: "初めての方はこちら",
links: [
{ title: "環境構築", href: "/setup" },
{ title: "チュートリアル", href: "/tutorial" },
]
},
{
icon: "🔧",
title: "うまく動かない",
description: "トラブルシューティング",
links: [
{ title: "よくある問題", href: "/faq" },
{ title: "エラー対処法", href: "/troubleshooting" },
]
},
{
icon: "📚",
title: "もっと学びたい",
description: "応用的な使い方",
links: [
{ title: "ベストプラクティス", href: "/best-practices" },
{ title: "応用例", href: "/examples" },
]
},
{
icon: "🎯",
title: "特定のことをしたい",
description: "目的別ガイド",
links: [
{ title: "〇〇を作りたい", href: "/create-xxx" },
{ title: "△△したい", href: "/do-yyy" },
]
},
];
<section className="py-12">
<h2 className="text-2xl font-bold mb-2">困りごとから探す</h2>
<p className="text-neutral-500 mb-6">何を探せばいいかわからない方はこちら</p>
<div className="grid md:grid-cols-2 lg:grid-cols-3 gap-4">
{contextNavItems.map((item) => (
<div
key={item.title}
className="p-5 bg-white dark:bg-neutral-900 rounded-xl border hover:shadow-lg transition"
>
<div className="flex items-center gap-3 mb-3">
<span className="text-2xl">{item.icon}</span>
<div>
<h3 className="font-bold">{item.title}</h3>
<p className="text-xs text-neutral-500">{item.description}</p>
</div>
</div>
<ul className="space-y-2">
{item.links.map((link) => (
<li key={link.href}>
<a href={link.href} className="text-sm text-indigo-500 hover:underline">
→ {link.title}
</a>
</li>
))}
</ul>
</div>
))}
</div>
</section>
サイトマップページ
├── ヘッダー
├── 困りごとから探す(コンテキストナビ)← 最初に配置!
├── 検索バー
├── カテゴリ別一覧
└── フッター
interface SearchItem {
title: string;
description: string;
href: string;
category: string;
keywords: string[];
}
export const searchData: SearchItem[] = [
{
title: "環境構築",
description: "インストールと初期設定",
href: "/setup",
category: "はじめに",
keywords: ["インストール", "設定", "セットアップ"],
},
];
function searchItems(query: string, items: SearchItem[]): SearchItem[] {
const normalized = query.toLowerCase().trim();
if (!normalized) return [];
return items
.map(item => {
let score = 0;
// タイトル完全一致: 100点
if (item.title.toLowerCase() === normalized) score += 100;
// タイトル前方一致: 80点
else if (item.title.toLowerCase().startsWith(normalized)) score += 80;
// タイトル部分一致: 60点
else if (item.title.toLowerCase().includes(normalized)) score += 60;
// キーワード一致: 50点
if (item.keywords.some(kw => kw.toLowerCase().includes(normalized))) score += 50;
// 説明文一致: 40点
if (item.description.toLowerCase().includes(normalized)) score += 40;
return { ...item, score };
})
.filter(item => item.score > 0)
.sort((a, b) => b.score - a.score)
.slice(0, 10);
}
useEffect(() => {
const handleKeyDown = (e: KeyboardEvent) => {
if ((e.metaKey || e.ctrlKey) && e.key === 'k') {
e.preventDefault();
setIsSearchOpen(true);
}
if (e.key === 'Escape') {
setIsSearchOpen(false);
}
};
document.addEventListener('keydown', handleKeyDown);
return () => document.removeEventListener('keydown', handleKeyDown);
}, []);
const [isComposing, setIsComposing] = useState(false);
<input
onCompositionStart={() => setIsComposing(true)}
onCompositionEnd={() => setIsComposing(false)}
onChange={(e) => {
if (!isComposing) search(e.target.value);
}}
/>
実装前に確認:
ユーザーの困りごと
サイト構造
検索要件
role="dialog", aria-modal="true"| ページ数 | 推奨 |
|---|---|
| ~100 | クライアントサイド |
| 100-1000 | Fuse.js |
| 1000+ | Algolia |