166 lines
4.8 KiB
JavaScript
166 lines
4.8 KiB
JavaScript
import { siteConfig } from '@/lib/config'
|
||
import { useGlobal } from '@/lib/global'
|
||
import { useRouter } from 'next/router'
|
||
import { useEffect, useState } from 'react'
|
||
import CONFIG from '../config'
|
||
import BlogPostCard from './BlogPostCard'
|
||
import NavPostItem from './NavPostItem'
|
||
|
||
/**
|
||
* 部落格列表滾動分頁
|
||
* @param posts 所有文章
|
||
* @param tags 所有標籤
|
||
* @returns {JSX.Element}
|
||
* @constructor
|
||
*/
|
||
const NavPostList = props => {
|
||
const { filteredNavPages } = props
|
||
const { locale, currentSearch } = useGlobal()
|
||
const router = useRouter()
|
||
|
||
// 依分類將文章歸成資料夾
|
||
const categoryFolders = groupArticles(filteredNavPages)
|
||
|
||
// 存放被展開的群組
|
||
const [expandedGroups, setExpandedGroups] = useState([])
|
||
|
||
// 是否採用排他折疊,一次只展開一個資料夾
|
||
const GITBOOK_EXCLUSIVE_COLLAPSE = siteConfig(
|
||
'GITBOOK_EXCLUSIVE_COLLAPSE',
|
||
null,
|
||
CONFIG
|
||
)
|
||
|
||
useEffect(() => {
|
||
// 展開資料夾
|
||
setTimeout(() => {
|
||
const currentPath = decodeURIComponent(router.asPath.split('?')[0])
|
||
const defaultOpenIndex = getDefaultOpenIndexByPath(
|
||
categoryFolders,
|
||
currentPath
|
||
)
|
||
setExpandedGroups([defaultOpenIndex])
|
||
}, 500)
|
||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||
}, [router, filteredNavPages])
|
||
|
||
// 切換折疊項目,當陣列狀態改變時觸發
|
||
const toggleItem = index => {
|
||
let newExpandedGroups = [...expandedGroups] // 建立新的展開群組陣列
|
||
|
||
// 若 expandedGroups 中不存在則加入,存在則移除
|
||
if (expandedGroups.includes(index)) {
|
||
// 若 expandedGroups 中包含 index,則移除
|
||
newExpandedGroups = newExpandedGroups.filter(
|
||
expandedIndex => expandedIndex !== index
|
||
)
|
||
} else {
|
||
// 若 expandedGroups 中不含 index,則加入
|
||
newExpandedGroups.push(index)
|
||
}
|
||
// 是否排他
|
||
if (GITBOOK_EXCLUSIVE_COLLAPSE) {
|
||
// 若折疊選單為排他模式,僅保留目前群組其餘關閉
|
||
newExpandedGroups = newExpandedGroups.filter(
|
||
expandedIndex => expandedIndex === index
|
||
)
|
||
}
|
||
|
||
// 更新展開群組陣列
|
||
setExpandedGroups(newExpandedGroups)
|
||
}
|
||
|
||
// 無資料時
|
||
if (!categoryFolders || categoryFolders.length === 0) {
|
||
// 空白內容
|
||
return (
|
||
<div className='flex w-full items-center justify-center min-h-screen mx-auto md:-mt-20'>
|
||
<p className='text-gray-500 dark:text-gray-300'>
|
||
{locale.COMMON.NO_RESULTS_FOUND}{' '}
|
||
{currentSearch && <div>{currentSearch}</div>}
|
||
</p>
|
||
</div>
|
||
)
|
||
}
|
||
// 文章首頁對應路徑
|
||
const href = siteConfig('GITBOOK_INDEX_PAGE') + ''
|
||
|
||
const homePost = {
|
||
id: '-1',
|
||
title: siteConfig('DESCRIPTION'),
|
||
href: href.indexOf('/') !== 0 ? '/' + href : href
|
||
}
|
||
|
||
return (
|
||
<div
|
||
id='posts-wrapper'
|
||
className='w-full flex-grow space-y-0.5 pr-4 tracking-wider'>
|
||
{/* 當前文章 */}
|
||
<BlogPostCard className='mb-4' post={homePost} />
|
||
|
||
{/* 文章列表 */}
|
||
{categoryFolders?.map((group, index) => (
|
||
<NavPostItem
|
||
key={index}
|
||
group={group}
|
||
onHeightChange={props.onHeightChange}
|
||
expanded={expandedGroups.includes(index)} // 將展開狀態傳給子元件
|
||
toggleItem={() => toggleItem(index)} // 將切換函式傳給子元件
|
||
/>
|
||
))}
|
||
</div>
|
||
)
|
||
}
|
||
|
||
// 依分類將文章歸成資料夾
|
||
function groupArticles(filteredNavPages) {
|
||
if (!filteredNavPages) {
|
||
return []
|
||
}
|
||
const groups = []
|
||
const AUTO_SORT = siteConfig('GITBOOK_AUTO_SORT', true, CONFIG)
|
||
|
||
for (let i = 0; i < filteredNavPages.length; i++) {
|
||
const item = filteredNavPages[i]
|
||
const categoryName = item?.category ? item?.category : '' // 將 category 轉成字串
|
||
|
||
let existingGroup = null
|
||
// 啟用自動分組排序;會把相同分類歸到同一個資料夾,忽略 Notion 中的排序
|
||
if (AUTO_SORT) {
|
||
existingGroup = groups.find(group => group.category === categoryName) // 尋找同名的最後一個群組
|
||
} else {
|
||
existingGroup = groups[groups.length - 1] // 取得最後一個群組
|
||
}
|
||
|
||
// 新增資料
|
||
if (existingGroup && existingGroup.category === categoryName) {
|
||
existingGroup.items.push(item)
|
||
} else {
|
||
groups.push({ category: categoryName, items: [item] })
|
||
}
|
||
}
|
||
return groups
|
||
}
|
||
|
||
/**
|
||
* 查看當前路徑需要展開的選單索引
|
||
* 若皆不符合則回傳 0,即預設展開第一個
|
||
* @param {*} categoryFolders
|
||
* @param {*} path
|
||
* @returns {number} 需展開的選單索引
|
||
*/
|
||
function getDefaultOpenIndexByPath(categoryFolders, path) {
|
||
// 找出符合條件的第一個索引
|
||
const index = categoryFolders.findIndex(group => {
|
||
return group.items.some(post => path === post.href)
|
||
})
|
||
|
||
// 若找到符合條件的索引則回傳
|
||
if (index !== -1) {
|
||
return index
|
||
}
|
||
|
||
return 0
|
||
}
|
||
export default NavPostList
|