Feature/faq (#546)

* feat(web): add FAQ page with search, sidebar, and i18n integration; update navigation and routes; include user feedback analysis docs (faq.md)
* docs: add filled frontend PR template for FAQ feature (PR_FRONTEND_FAQ.md)
* docs(web): add Contributing & Tasks FAQ category near top with guidance on using GitHub Projects and PR contribution standards
* feat(web,api): dynamically embed GitHub Projects roadmap in FAQ via /api/roadmap and RoadmapWidget; add env vars for GitHub token/org/project
* chore(docker): pass GitHub roadmap env vars into backend container
* docs(web): update FAQ with fork-based PR workflow, yellow links to roadmap/task dashboard, and contribution incentives; remove dynamic roadmap embed\n\nchore(api,docker): remove /api/roadmap endpoint and related env wiring
* chore: revert unintended changes (.env.example, api/server.go, docker-compose.yml); remove local-only files (PR_FRONTEND_FAQ.md, web/faq.md) from PR
* feat: 添加对重置密码页面的路由支持
This commit is contained in:
Ember
2025-11-05 22:39:42 +08:00
committed by GitHub
parent 22731189bd
commit c633a782ae
9 changed files with 1628 additions and 40 deletions

View File

@@ -0,0 +1,83 @@
import { t, type Language } from '../../i18n/translations'
import type { FAQCategory } from '../../data/faqData'
interface FAQSidebarProps {
categories: FAQCategory[]
activeItemId: string | null
language: Language
onItemClick: (categoryId: string, itemId: string) => void
}
export function FAQSidebar({
categories,
activeItemId,
language,
onItemClick,
}: FAQSidebarProps) {
return (
<nav
className="sticky top-24 h-[calc(100vh-120px)] overflow-y-auto pr-4"
style={{
scrollbarWidth: 'thin',
scrollbarColor: '#2B3139 #1E2329',
}}
>
<div className="space-y-6">
{categories.map((category) => (
<div key={category.id}>
{/* Category Title */}
<div className="flex items-center gap-2 mb-3 px-3">
<category.icon className="w-5 h-5" style={{ color: '#F0B90B' }} />
<h3
className="text-sm font-bold uppercase tracking-wide"
style={{ color: '#F0B90B' }}
>
{t(category.titleKey, language)}
</h3>
</div>
{/* Category Items */}
<ul className="space-y-1">
{category.items.map((item) => {
const isActive = activeItemId === item.id
return (
<li key={item.id}>
<button
onClick={() => onItemClick(category.id, item.id)}
className="w-full text-left px-3 py-2 rounded-lg text-sm transition-all"
style={{
background: isActive
? 'rgba(240, 185, 11, 0.1)'
: 'transparent',
color: isActive ? '#F0B90B' : '#848E9C',
borderLeft: isActive
? '3px solid #F0B90B'
: '3px solid transparent',
paddingLeft: isActive ? '9px' : '12px',
}}
onMouseEnter={(e) => {
if (!isActive) {
e.currentTarget.style.background =
'rgba(240, 185, 11, 0.05)'
e.currentTarget.style.color = '#EAECEF'
}
}}
onMouseLeave={(e) => {
if (!isActive) {
e.currentTarget.style.background = 'transparent'
e.currentTarget.style.color = '#848E9C'
}
}}
>
{t(item.questionKey, language)}
</button>
</li>
)
})}
</ul>
</div>
))}
</div>
</nav>
)
}