ð€ããªãã§ã¿ã°ã¯ãªãã¯ã§ããªãã®ïŒïŒãããå§ãŸã£ãããã°UI倧æ¹é©ã®å¥è·¡
ãŠãŒã¶ããªãã£ã«åé¡ã ããã®ããã°ãµã€ãã1æéã§åçæ¹åïŒã¿ã°ã®ã¯ãªãã¯æ©èœããã³ãããããå€éšãªã³ã¯ã®å¥ã¿ã衚瀺ãã¹ã¯ããŒã«äœçœ®èšæ¶ãŸã§äžæ°ã«å®è£ ããæ¹åã®å šèšé²ã
ð€ããªãã§ã¿ã°ã¯ãªãã¯ã§ããªãã®ïŒïŒãããå§ãŸã£ãããã°UI倧æ¹é©ã®å¥è·¡
ããã«ã¡ã¯ïŒä»æ¥ã¯è¡ã®æ°ãåŒããããªãŠãŒã¶ããªãã£ã®åé¡ã1æéã§äžæ°ã«è§£æ±ºãã話ãã·ã§ã¢ãããŠãã ããã
ð¥ çºç«¯ïŒãŠãŒã¶ããªãã£ã®å°ççµµå³
ããã°ãµã€ãããã§ãã¯ããŠãããããããªåé¡ã ããã®ç¶æ³ã«æ°ã¥ããŠããŸããŸãã...
- ã¿ã°ãã¯ãªãã¯ã§ããªã ð±ïŒãªãã®æå³ãããã®...ïŒ
- å€éšãªã³ã¯ãåãã¿ãã§éã ð€ïŒæ»ãã®é¢åããïŒ
- ãã³ããããããªã ðïŒã©ãã«ãããããããïŒ
- æ»ããã¿ã³ã§ã¹ã¯ããŒã«äœçœ®ããªã»ãã ð¢ïŒèªãã§ããšãã©ãïŒïŒ
- æååããæ£èŠ ð€®ïŒçµµæåãå€ã«ãªã£ãŠãïŒ
ãããã¯...ãŠãŒã¶ãŒãå¯åæ³ãããããšæããå³åº§ã«æ¹åã«åãæãããŸããã
ð¯ å®è£ ããæ¹åæœç
1. ã¿ã°ãã¯ãªãã¯å¯èœãªãªã³ã¯ã«å€æŽ
åé¡: èšäºã®ã¿ã°ã衚瀺ãããŠããã ãã§ã¯ãªãã¯ã§ããªã
解決ç: spanãaã¿ã°ã«å€æŽããŠãããŒå¹æã远å
// Before: ã¯ãªãã¯ã§ããªãã¿ã°
<span className="px-4 py-2 bg-gradient-to-r from-blue-100 via-purple-100 to-blue-100 text-blue-800 rounded-full text-sm font-bold shadow-md border border-blue-200">
ð·ïž {tag}
</span>
// After: ã¯ãªãã¯å¯èœãªã¿ã°
<a
href={`/tag/${tag}`}
className="px-4 py-2 bg-gradient-to-r from-blue-100 via-purple-100 to-blue-100 text-blue-800 rounded-full text-sm font-bold shadow-md border border-blue-200 hover:from-blue-200 hover:via-purple-200 hover:to-blue-200 hover:shadow-lg transition-all"
>
ð·ïž {tag}
</a>
ãã€ã³ã: ãããŒæã®è²å€æŽãšã·ã£ããŠã®åŒ·åã§ã¯ãªãã¯å¯èœã§ããããšãèŠèŠçã«ç€ºã
2. ãã³ããããã²ãŒã·ã§ã³è¿œå
åé¡: ãŠãŒã¶ãŒããµã€ãå ã®ã©ãã«ãããããããªã
解決ç: ã»ãã³ãã£ãã¯ãªããã²ãŒã·ã§ã³æ§é ãå®è£
<nav className="mb-6" aria-label="ãã³ãã">
<ol className="flex items-center space-x-2 text-sm text-gray-600 mb-4">
<li>
<a href="/" className="text-blue-600 hover:text-blue-800 transition-colors">
ð ããŒã
</a>
</li>
<li className="flex items-center">
<svg className="w-4 h-4 mx-2 text-gray-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9 5l7 7-7 7" />
</svg>
<a href={`/category/${article.category}`} className="text-blue-600 hover:text-blue-800 transition-colors">
{article.category}
</a>
</li>
<li className="flex items-center">
<svg className="w-4 h-4 mx-2 text-gray-400" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9 5l7 7-7 7" />
</svg>
<span className="text-gray-500 truncate max-w-xs" title={article.title}>
{article.title}
</span>
</li>
</ol>
</nav>
ãã€ã³ã: aria-labelã§ã¢ã¯ã»ã·ããªãã£ãèæ
®ããéå±€æ§é ãæç¢ºã«è¡šç€º
3. å€éšãªã³ã¯ãå¥ã¿ãã§éãæ©èœ
åé¡: å€éšãªã³ã¯ãåãã¿ãã§éããŠå ã®ããŒãžã«æ»ãã«ãã
解決ç: ReactMarkdownã®ã«ã¹ã¿ã ã³ã³ããŒãã³ãã§å€éšãªã³ã¯å€å®
a: ({ href, children, ...props }: any) => {
// å€éšãªã³ã¯ã®å ŽåOGPã«ãŒã衚瀺
if (href && href.startsWith('http')) {
const ogpData = ogpDataMap.get(href);
// ãªã³ã¯ã®ããã¹ããURLãšåãå Žåã¯ã«ãŒã衚瀺
if (children?.toString() === href || children?.[0] === href) {
return <OGPLinkCard url={href} ogpData={ogpData} />;
}
// å€éšãªã³ã¯ã¯å¥ã¿ãã§éã
return (
<a
href={href}
{...props}
target="_blank"
rel="noopener noreferrer"
className="text-blue-600 hover:text-purple-600 font-medium underline decoration-blue-300 hover:decoration-purple-400 transition-colors"
>
{children}
<span className="ml-1 text-xs">ð</span>
</a>
);
}
// å
éšãªã³ã¯
return (
<a href={href} {...props} className="text-blue-600 hover:text-purple-600 font-medium underline decoration-blue-300 hover:decoration-purple-400 transition-colors">
{children}
</a>
);
}
ãã€ã³ã: ðã¢ã€ã³ã³ã§å€éšãªã³ã¯ã§ããããšãæç€ºããã»ãã¥ãªãã£ã®ããã«rel="noopener noreferrer"ã远å
4. ã¹ã¯ããŒã«äœçœ®èšæ¶æ©èœ
åé¡: æ»ããã¿ã³ã§å ã®ããŒãžã«æ»ã£ãŠãã¹ã¯ããŒã«äœçœ®ããªã»ããããã
解決ç: sessionStorageã䜿ã£ãäœçœ®èšæ¶ã·ã¹ãã
// ã¹ã¯ããŒã«äœçœ®ã®èšæ¶
useEffect(() => {
const scrollKey = `scroll-${article.slug}`;
const savedPosition = sessionStorage.getItem(scrollKey);
if (savedPosition) {
// å°ãé
ãããŠã¹ã¯ããŒã«äœçœ®ã埩å
setTimeout(() => {
window.scrollTo(0, parseInt(savedPosition, 10));
}, 100);
}
// ããŒãžãé¢ããæã«ã¹ã¯ããŒã«äœçœ®ãä¿å
const handleBeforeUnload = () => {
sessionStorage.setItem(scrollKey, window.scrollY.toString());
};
// æ»ããã¿ã³ã§ã®é·ç§»ãæ€ç¥ããŠã¹ã¯ããŒã«äœçœ®ãä¿å
const handleVisibilityChange = () => {
if (document.visibilityState === 'hidden') {
sessionStorage.setItem(scrollKey, window.scrollY.toString());
}
};
window.addEventListener('beforeunload', handleBeforeUnload);
document.addEventListener('visibilitychange', handleVisibilityChange);
return () => {
window.removeEventListener('beforeunload', handleBeforeUnload);
document.removeEventListener('visibilitychange', handleVisibilityChange);
};
}, [article.slug]);
ãã€ã³ã: è€æ°ã®ã€ãã³ããªã¹ããŒã§ç¢ºå®ã«ã¹ã¯ããŒã«äœçœ®ããã£ããããèšäºããšã«åå¥ã«ä¿å
5. æååãä¿®æ£
åé¡: æ¥æ¬èªæåãçµµæåãæååãããŠãã
解決ç: æ£ããUTF-8ãšã³ã³ãŒãã£ã³ã°ã§æååã眮æ
// Before
ð·ï¿œEᅵE{tag} // æååã
èšäºäžèŠ§ã«æ»ãE // æååã
ã³ãᅵEã«å€±æããŸãã // æååã
// After
ð·ïž {tag}
èšäºäžèŠ§ã«æ»ã
ã³ããŒã«å€±æããŸãã
ð æ¹åçµæ
ð ãŠãŒã¶ããªãã£ã®åçåäž
- ã¿ã°ããã²ãŒã·ã§ã³: 1ã¯ãªãã¯ã§é¢é£èšäºã«ç§»åå¯èœ
- ãµã€ãå ç§»å: ãã³ããã§ã©ãã«ãããäžç®çç¶
- å€éšãªã³ã¯äœéš: å¥ã¿ãã§éããŠå ããŒãžã倱ããªã
- ã¹ã¯ããŒã«èšæ¶: æ»ããã¿ã³ã§èªãã§ããç®æã«ç¬é埩垰
- èŠèŠçå質: æååããŒãã®ã¯ãªãŒã³ãªè¡šç€º
â¡ éçºå¹çã®åäž
- å®è£ æé: ããã1æéã§å šæ©èœå®è£
- ã³ãŒãå質: TypeScriptåå®å šæ§ãä¿æ
- ä¿å®æ§: åæ©èœãç¬ç«ããŠããŠä¿®æ£ãããã
ð¡ ä»ååŠãã ãŠãŒã¶ããªãã£ã®ãã€ã³ã
1. ãåœããåããçãå§¿å¢
ã¿ã°ã衚瀺ãããŠãããããŠãŒã¶ãŒã¯ãã¯ãªãã¯ã§ãããã®ãã ãšæããŸããã§ãå®è£ åŽã¯ã衚瀺ããã ããã§æºè¶³ããŠããŸãããšãå€ããã§ãã
2. å°ããªæ¹åã®ç©ã¿éã
äžã€ã²ãšã€ã¯å°ããªæ©èœã§ããçµã¿åããããšåçã«ãŠãŒã¶ãŒäœéšãåäžããŸãã
3. ã¢ã¯ã»ã·ããªãã£ãå¿ããã«
aria-labelãtitle屿§ã§ããã¹ãŠã®ãŠãŒã¶ãŒã䜿ãããããµã€ããå¿ãããŸããã
ð æ¬¡ã®ã¹ããã
ä»åã®æ¹åã§åºæ¬çãªããã²ãŒã·ã§ã³äœéšã¯å€§å¹ ã«åäžããŸãããæ¬¡ã¯ïŒ
- æ€çŽ¢æ©èœã®è¿œå
- ãæ°ã«å ¥ãæ©èœ
- ã³ã¡ã³ãæ©èœ
- èªäºæé衚瀺
ãªã©ãæ€èšããŠããŸãã
ð¯ ããªããžã®ã¡ãã»ãŒãž
ããããªãã®ãµã€ãã§ããªããã€ãã€ãã ãª...ããšæããéšåããã£ãããããã¯ãã£ãšæ¹åã®ãµã€ã³ã§ãã
ãŠãŒã¶ãŒã®ç«å Žã«ç«ã£ãŠãã¯ãªãã¯ããããªããã®ããè¿·ãã䜿ãããã®ããäœãããšã§ããã£ãšçŽ æŽããããµã€ãã«ãªãã¯ãã§ãã
äžç·ã«ãŠãŒã¶ãŒãã¡ãŒã¹ããªãµã€ããäœã£ãŠãããŸãããïŒ ð
ãã®èšäºãããªãã®Webéçºã®åèã«ãªãã°å¬ããã§ããäžç·ã«é 匵ããŸãããïŒ âš
ãã®èšäºã圹ã«ç«ã£ããã·ã§ã¢ããŠãã ãã
ð ããã°ã©ãã³ã°ã»éçº ã®é¢é£èšäº
ðãããã³ãŒãèªãŸãªããŠããïŒãAIãšãŒãžã§ã³ãéçºã§æ¿å€ããéçºçŸå Žã®è¡æäœéšè«
ãã«ãã¿ã¹ã¯å¯Ÿå¿AIãšãŒãžã§ã³ããéçºçŸå Žãæ ¹åºããå€ãããã³ãŒãèªè§£å°çããã®è§£æŸã䞊åéçºã®å§åçå¹çåããããŠéçºè ã®ç²åŽæ¿æžã®çã ããäœéšãé蟌ããŠèªããŸãã
ç¶ããèªãðãClaude Code CLI ã§EAäœæãã¹ã¿ãŒãã«ãªãããã®å®è·µçã³ããšèœãšã穎åé¿æ³
ãClaude Code䜿ã£ãŠããã©EAãããŸãäœããªã...ããããªããªããžïŒ2025å¹Žææ°ã®CLIæäœãã¯ããã¯ãå¹ççãªæç€ºåºãæ¹æ³ããããããã©ãã«è§£æ±ºæ³ãå®äœéšããŒã¹ã§å®å šè§£èª¬ãåå¿è ã§ãäžçŽè ã®ãããªEAãäœããç§å¯ã®ã³ãæããŸãã
ç¶ããèªãðããªãã§èšäºãåæ ãããžãã®ïŒïŒã3æéã®æ ŒéããçãŸãããããã€ã·ã¹ãã å®å šæ¹è¯èš
ãèšäºæžããã®ã«ãµã€ãã«åºãŠããªã...ããããªå°çããéãäžãã£ããè¡ãšæ±ãšæ¶ã®ãããã€ã·ã¹ãã æ¹è¯ãããžã§ã¯ããimportå°çããfetch倩åœãžã®éã®ããå šéšèŠããŸãã
ç¶ããèªã