feat(web): 页头滚动信息、移除返回按钮、面包屑左侧可点、侧栏加首页
- 页头中间信息改为无缝滚动 ticker(3 份拼接,24s 线性,尊重 reduced-motion) - 去掉分区 / 条目 / 文章三处「返回」「返回首页」按钮 - 面包屑移到左侧,中间项可点击并通过 onNavigate 走 SPA 路由 - 侧栏新增「首页」,首页时高亮,点击回首页
This commit is contained in:
+56
-12
@@ -69,9 +69,60 @@
|
||||
letter-spacing: 0.04em;
|
||||
}
|
||||
|
||||
.header-info {
|
||||
/* ---------- 页头滚动信息 ---------- */
|
||||
|
||||
.header-ticker {
|
||||
flex: 1;
|
||||
justify-content: center;
|
||||
min-width: 0;
|
||||
overflow: hidden;
|
||||
mask-image: linear-gradient(
|
||||
90deg,
|
||||
transparent 0,
|
||||
#000 32px,
|
||||
#000 calc(100% - 32px),
|
||||
transparent 100%
|
||||
);
|
||||
}
|
||||
|
||||
.header-ticker-track {
|
||||
display: flex;
|
||||
width: max-content;
|
||||
animation: header-ticker 24s linear infinite;
|
||||
}
|
||||
|
||||
/* 每组占满整条轨道宽度:任何时候只看到一份信息,滚动时下一份从右侧进入 */
|
||||
.header-ticker-group {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: space-evenly;
|
||||
gap: var(--su-space-8);
|
||||
min-width: 100%;
|
||||
}
|
||||
|
||||
.header-ticker-item {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: var(--su-space-2);
|
||||
font-size: var(--su-font-size-sm);
|
||||
line-height: var(--su-line-height-sm);
|
||||
color: var(--su-text-sub);
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
@keyframes header-ticker {
|
||||
from {
|
||||
transform: translateX(0);
|
||||
}
|
||||
|
||||
to {
|
||||
transform: translateX(calc(-100% / 3));
|
||||
}
|
||||
}
|
||||
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
.header-ticker-track {
|
||||
animation: none;
|
||||
}
|
||||
}
|
||||
|
||||
.header-actions {
|
||||
@@ -335,19 +386,12 @@
|
||||
.detail-nav {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 12px var(--su-space-5);
|
||||
}
|
||||
|
||||
.detail-back {
|
||||
color: var(--su-color-primary);
|
||||
font-size: var(--su-font-size-md);
|
||||
font-weight: var(--su-font-weight-bold);
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.detail-back:hover {
|
||||
text-decoration: underline;
|
||||
/* 面包屑在左侧,12px(与旧版 breadcrumb 一致) */
|
||||
.detail-breadcrumb {
|
||||
font-size: var(--su-font-size-xs);
|
||||
}
|
||||
|
||||
.detail-nav > * {
|
||||
|
||||
+16
-15
@@ -28,7 +28,7 @@ import {
|
||||
import { useProjects } from './useProjects'
|
||||
import { useCatalog } from './useCatalog'
|
||||
import { useViewRoute } from './useViewRoute'
|
||||
import type { ItemRoute, View } from './data/view'
|
||||
import { parseViewPath, viewPath, type View } from './data/view'
|
||||
import './App.css'
|
||||
|
||||
export default function App() {
|
||||
@@ -37,7 +37,7 @@ export default function App() {
|
||||
const catalog = useCatalog()
|
||||
const [keyword, setKeyword] = useState('')
|
||||
// 当前视图由地址栏决定:刷新 / 收藏 / 前进后退都回到同一页(见 useViewRoute.ts)
|
||||
const { view, go, back } = useViewRoute()
|
||||
const { view, go } = useViewRoute()
|
||||
const [scrolled, setScrolled] = useState(false)
|
||||
const searchRef = useRef<HTMLInputElement>(null)
|
||||
|
||||
@@ -169,15 +169,6 @@ export default function App() {
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* 条目详情的「返回」目标:优先回到该条目所在的分组,
|
||||
* 没有分组(海报 / 图文)时回到分区,走和侧栏一样的展示块规则。
|
||||
*/
|
||||
const detailTargetFor = (item: ItemRoute): View =>
|
||||
item.groupId === undefined
|
||||
? detailViewFor(item.categoryId)
|
||||
: { type: 'detail', categoryId: item.categoryId, groupId: item.groupId }
|
||||
|
||||
/**
|
||||
* 侧栏导航:带分组时直接打开那个分组;
|
||||
* 点分区本身时,交给 openDetail 按展示块落到对应节点。
|
||||
@@ -193,6 +184,9 @@ export default function App() {
|
||||
|
||||
const goHome = () => go({ type: 'home' })
|
||||
|
||||
/** 面包屑点击:把 href 解析回视图再跳转(保持 SPA 不刷新) */
|
||||
const navigateHref = (href: string) => go(parseViewPath(href))
|
||||
|
||||
const searching = keyword.trim() !== ''
|
||||
|
||||
const viewCategoryId = detailView?.categoryId ?? itemView?.categoryId
|
||||
@@ -224,8 +218,9 @@ export default function App() {
|
||||
return (
|
||||
<ArticleDetailView
|
||||
article={article}
|
||||
categoryId={itemCategory.id}
|
||||
categoryTitle={itemCategory.title}
|
||||
onBack={() => back(detailTargetFor(itemView))}
|
||||
onNavigate={navigateHref}
|
||||
/>
|
||||
)
|
||||
}
|
||||
@@ -236,10 +231,14 @@ export default function App() {
|
||||
|
||||
return (
|
||||
<ItemDetailView
|
||||
breadcrumb={`${itemCategory.title} / ${detailModel.title}`}
|
||||
crumbs={[
|
||||
{ label: '首页', href: '/' },
|
||||
{ label: itemCategory.title, href: viewPath({ type: 'detail', categoryId: itemCategory.id }) },
|
||||
{ label: detailModel.title },
|
||||
]}
|
||||
model={detailModel}
|
||||
related={relatedItems}
|
||||
onBack={() => back(detailTargetFor(itemView))}
|
||||
onNavigate={navigateHref}
|
||||
onOpenItem={(itemId) => openItem(itemCategory.id, itemId)}
|
||||
/>
|
||||
)
|
||||
@@ -283,7 +282,9 @@ export default function App() {
|
||||
onRefresh={refresh}
|
||||
activeCategoryId={viewCategoryId}
|
||||
activeGroupId={detailView?.groupId}
|
||||
homeActive={view.type === 'home'}
|
||||
onNavigate={navigate}
|
||||
onHome={goHome}
|
||||
/>
|
||||
}
|
||||
>
|
||||
@@ -335,7 +336,7 @@ export default function App() {
|
||||
<DetailView
|
||||
category={detailCategory}
|
||||
groupId={detailView.groupId}
|
||||
onBack={goHome}
|
||||
onNavigate={navigateHref}
|
||||
onOpenItem={(itemId) => openItem(detailCategory.id, itemId)}
|
||||
/>
|
||||
)}
|
||||
|
||||
@@ -1,34 +1,39 @@
|
||||
import { Card, Paragraph, Space, Text, Title } from '@stash/ui'
|
||||
import { Breadcrumb, Card, Paragraph, Text, Title } from '@stash/ui'
|
||||
import type { ArticleItem } from '../../data/types'
|
||||
import { viewPath } from '../../data/view'
|
||||
import { ArticleBody } from './ArticleBody'
|
||||
|
||||
/**
|
||||
* 文章详情页(对应模板图二):
|
||||
* 大标题 + [编辑] + 元信息行 + 白色正文卡。
|
||||
* 面包屑 + 大标题 + [编辑] + 元信息行 + 白色正文卡。
|
||||
*
|
||||
* 正文是一整段 Markdown,交给 ArticleBody 解析渲染;
|
||||
* 渲染细节(支持哪些语法)都收在那一个组件里。
|
||||
*/
|
||||
type ArticleDetailViewProps = {
|
||||
article: ArticleItem
|
||||
categoryId: string
|
||||
categoryTitle: string
|
||||
onBack: () => void
|
||||
onNavigate: (href: string) => void
|
||||
}
|
||||
|
||||
export function ArticleDetailView({ article, categoryTitle, onBack }: ArticleDetailViewProps) {
|
||||
export function ArticleDetailView({
|
||||
article,
|
||||
categoryId,
|
||||
categoryTitle,
|
||||
onNavigate,
|
||||
}: ArticleDetailViewProps) {
|
||||
const meta = article.meta ?? ['2 年前', categoryTitle]
|
||||
const crumbs = [
|
||||
{ label: '首页', href: '/' },
|
||||
{ label: categoryTitle, href: viewPath({ type: 'detail', categoryId }) },
|
||||
{ label: '文章' },
|
||||
]
|
||||
|
||||
return (
|
||||
<div className="detail-view article-view">
|
||||
<Card padding="none" className="detail-nav">
|
||||
<Space justify="between" wrap>
|
||||
<button type="button" className="detail-back" onClick={onBack}>
|
||||
返回
|
||||
</button>
|
||||
<Text size="xs" tone="muted">
|
||||
{categoryTitle} / 文章
|
||||
</Text>
|
||||
</Space>
|
||||
<Breadcrumb className="detail-breadcrumb" items={crumbs} onNavigate={onNavigate} />
|
||||
</Card>
|
||||
|
||||
<header className="article-head">
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
import { Breadcrumb, Card, Empty, Space, Title } from '@stash/ui'
|
||||
import { categoryCount, type Category } from '../../data/types'
|
||||
import { viewPath } from '../../data/view'
|
||||
import { AppGrid } from './AppGrid'
|
||||
import { CesCardGrid } from './CesCardGrid'
|
||||
import { GroupBlock } from './GroupBlock'
|
||||
import { PosterGrid } from './PosterGrid'
|
||||
|
||||
/**
|
||||
* 分类明细视图:返回条 + 面包屑 + hero(图标 / 标题 / 数量)+ 内容区。
|
||||
* 分类明细视图:面包屑 + hero(图标 / 标题 / 数量)+ 内容区。
|
||||
*
|
||||
* 内容区按分类类型切换:
|
||||
* - apps:指定分组时只渲染该组,否则单组扁平渲染、多组带小标题分组渲染;
|
||||
@@ -17,12 +18,13 @@ type DetailViewProps = {
|
||||
category: Category
|
||||
/** 从侧栏子菜单进入时指定的分组 */
|
||||
groupId?: string
|
||||
onBack: () => void
|
||||
/** 点击面包屑中间项(SPA 路由) */
|
||||
onNavigate: (href: string) => void
|
||||
/** 点击卡片 / 海报进入条目详情 */
|
||||
onOpenItem: (itemId: string) => void
|
||||
}
|
||||
|
||||
export function DetailView({ category, groupId, onBack, onOpenItem }: DetailViewProps) {
|
||||
export function DetailView({ category, groupId, onNavigate, onOpenItem }: DetailViewProps) {
|
||||
const groups = category.kind === 'apps' ? category.groups : []
|
||||
const activeGroup =
|
||||
groupId !== undefined ? groups.find((group) => group.id === groupId) : undefined
|
||||
@@ -33,10 +35,13 @@ export function DetailView({ category, groupId, onBack, onOpenItem }: DetailView
|
||||
activeGroup !== undefined
|
||||
? [
|
||||
{ label: '首页', href: '/' },
|
||||
{ label: category.title },
|
||||
{ label: category.title, href: viewPath({ type: 'detail', categoryId: category.id }) },
|
||||
{ label: activeGroup.name },
|
||||
]
|
||||
: [{ label: '首页', href: '/' }, { label: category.title }]
|
||||
: [
|
||||
{ label: '首页', href: '/' },
|
||||
{ label: category.title, href: viewPath({ type: 'detail', categoryId: category.id }) },
|
||||
]
|
||||
|
||||
function renderBody() {
|
||||
if (category.kind === 'posters') {
|
||||
@@ -71,12 +76,11 @@ export function DetailView({ category, groupId, onBack, onOpenItem }: DetailView
|
||||
return (
|
||||
<div className="detail-view">
|
||||
<Card padding="none" className="detail-nav">
|
||||
<Space justify="between" wrap>
|
||||
<button type="button" className="detail-back" onClick={onBack}>
|
||||
返回首页
|
||||
</button>
|
||||
<Breadcrumb items={crumbs} />
|
||||
</Space>
|
||||
<Breadcrumb
|
||||
className="detail-breadcrumb"
|
||||
items={crumbs}
|
||||
onNavigate={onNavigate}
|
||||
/>
|
||||
</Card>
|
||||
|
||||
<div className="detail-hero">
|
||||
|
||||
@@ -1,4 +1,15 @@
|
||||
import { Card, Icon, IconButton, Paragraph, Space, Tag, Text, Title } from '@stash/ui'
|
||||
import {
|
||||
Breadcrumb,
|
||||
Card,
|
||||
Icon,
|
||||
IconButton,
|
||||
Paragraph,
|
||||
Space,
|
||||
Tag,
|
||||
Text,
|
||||
Title,
|
||||
type BreadcrumbItem,
|
||||
} from '@stash/ui'
|
||||
import type { ItemDetailModel } from '../../data/detail'
|
||||
import type { RelatedItem } from '../../data/types'
|
||||
import { RelatedList } from './RelatedList'
|
||||
@@ -6,38 +17,29 @@ import { RelatedList } from './RelatedList'
|
||||
/**
|
||||
* 条目详情页:应用与电影共用。
|
||||
*
|
||||
* 版式:标题 + 主图(方形头像 / 竖版海报)+ 标签行 + 一句话评价 + 正文
|
||||
* 版式:面包屑 + 标题 + 主图(方形头像 / 竖版海报)+ 标签行 + 一句话评价 + 正文
|
||||
* + 操作条(浏览 / 点赞 / 分享 / 跳转)+ 可选横幅 + 「推荐阅读」。
|
||||
* 具体形态由 ItemDetailModel 决定,这里不判断条目类型。
|
||||
*/
|
||||
type ItemDetailViewProps = {
|
||||
breadcrumb: string
|
||||
crumbs: BreadcrumbItem[]
|
||||
model: ItemDetailModel
|
||||
related: RelatedItem[]
|
||||
onBack: () => void
|
||||
onNavigate: (href: string) => void
|
||||
onOpenItem: (itemId: string) => void
|
||||
}
|
||||
|
||||
export function ItemDetailView({
|
||||
breadcrumb,
|
||||
crumbs,
|
||||
model,
|
||||
related,
|
||||
onBack,
|
||||
onNavigate,
|
||||
onOpenItem,
|
||||
}: ItemDetailViewProps) {
|
||||
return (
|
||||
<div className="detail-view item-view">
|
||||
<Card padding="none" className="detail-nav">
|
||||
<Space justify="between" wrap>
|
||||
<button type="button" className="detail-back" onClick={onBack}>
|
||||
返回
|
||||
</button>
|
||||
<span className="detail-breadcrumb">
|
||||
<Text size="xs" tone="muted">
|
||||
{breadcrumb}
|
||||
</Text>
|
||||
</span>
|
||||
</Space>
|
||||
<Breadcrumb className="detail-breadcrumb" items={crumbs} onNavigate={onNavigate} />
|
||||
</Card>
|
||||
|
||||
<Card padding="none" className="item-card">
|
||||
|
||||
@@ -1,29 +0,0 @@
|
||||
import { Space, Tag, Text } from '@stash/ui'
|
||||
import type { ReactNode } from 'react'
|
||||
|
||||
/**
|
||||
* 顶栏中间的一条信息,形如「[标签] 文本」。
|
||||
* 标签用组件库的 Tag(success / primary 两种语气)。
|
||||
*/
|
||||
type HeaderInfoItemProps = {
|
||||
/** 可选的前缀标签 */
|
||||
tag?: string
|
||||
/** 标签配色:默认蓝色,状态类用绿色 */
|
||||
tone?: 'blue' | 'green'
|
||||
children: ReactNode
|
||||
}
|
||||
|
||||
export function HeaderInfoItem({ tag, tone = 'blue', children }: HeaderInfoItemProps) {
|
||||
return (
|
||||
<Space gap="sm">
|
||||
{tag !== undefined && (
|
||||
<Tag tone={tone === 'green' ? 'success' : 'primary'} shape="rounded">
|
||||
{tag}
|
||||
</Tag>
|
||||
)}
|
||||
<Text size="sm" tone="sub">
|
||||
{children}
|
||||
</Text>
|
||||
</Space>
|
||||
)
|
||||
}
|
||||
@@ -1,8 +1,7 @@
|
||||
import { Icon, IconButton, Space } from '@stash/ui'
|
||||
import { HeaderInfoItem } from './HeaderInfoItem'
|
||||
import { Icon, IconButton, Tag } from '@stash/ui'
|
||||
|
||||
/**
|
||||
* 顶部栏:左品牌、中间运行信息、右侧操作图标。
|
||||
* 顶部栏:左品牌、中间滚动信息、右侧操作图标。
|
||||
* 外层 <header> 由 Layout 提供,这里只渲染栏内的内容。
|
||||
*/
|
||||
type SiteHeaderProps = {
|
||||
@@ -13,6 +12,40 @@ type SiteHeaderProps = {
|
||||
onFocusSearch: () => void
|
||||
}
|
||||
|
||||
type InfoGroupProps = Omit<SiteHeaderProps, 'onFocusSearch'> & {
|
||||
'aria-hidden'?: boolean
|
||||
}
|
||||
|
||||
/** 运行信息:同一份内容渲染两遍,轨道平移 50% 形成无缝滚动 */
|
||||
function InfoGroup({
|
||||
projectCount,
|
||||
sampleProject,
|
||||
live,
|
||||
'aria-hidden': ariaHidden,
|
||||
}: InfoGroupProps) {
|
||||
return (
|
||||
<span className="header-ticker-group" aria-hidden={ariaHidden}>
|
||||
<span className="header-ticker-item">共 {projectCount} 个本地应用</span>
|
||||
|
||||
{sampleProject !== undefined && (
|
||||
<span className="header-ticker-item">
|
||||
<Tag tone="primary" shape="rounded">
|
||||
本地
|
||||
</Tag>
|
||||
{sampleProject}
|
||||
</span>
|
||||
)}
|
||||
|
||||
<span className="header-ticker-item">
|
||||
<Tag tone={live ? 'success' : 'neutral'} shape="rounded">
|
||||
状态
|
||||
</Tag>
|
||||
{live ? '实时同步已连接' : '等待服务连接'}
|
||||
</span>
|
||||
</span>
|
||||
)
|
||||
}
|
||||
|
||||
export function SiteHeader({ projectCount, sampleProject, live, onFocusSearch }: SiteHeaderProps) {
|
||||
return (
|
||||
<div className="site-header-inner">
|
||||
@@ -23,19 +56,26 @@ export function SiteHeader({ projectCount, sampleProject, live, onFocusSearch }:
|
||||
<span className="site-brand-name">STASH</span>
|
||||
</a>
|
||||
|
||||
<Space gap="lg" className="header-info">
|
||||
<HeaderInfoItem>共 {projectCount} 个本地应用</HeaderInfoItem>
|
||||
<div className="header-ticker" role="status" aria-label="运行状态">
|
||||
<div className="header-ticker-track">
|
||||
<InfoGroup projectCount={projectCount} sampleProject={sampleProject} live={live} />
|
||||
<InfoGroup
|
||||
projectCount={projectCount}
|
||||
sampleProject={sampleProject}
|
||||
live={live}
|
||||
// 后两份只用于视觉无缝,读屏忽略
|
||||
aria-hidden
|
||||
/>
|
||||
<InfoGroup
|
||||
projectCount={projectCount}
|
||||
sampleProject={sampleProject}
|
||||
live={live}
|
||||
aria-hidden
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{sampleProject !== undefined && (
|
||||
<HeaderInfoItem tag="本地">{sampleProject}</HeaderInfoItem>
|
||||
)}
|
||||
|
||||
<HeaderInfoItem tag="状态" tone={live ? 'green' : 'blue'}>
|
||||
{live ? '实时同步已连接' : '等待服务连接'}
|
||||
</HeaderInfoItem>
|
||||
</Space>
|
||||
|
||||
<Space gap="sm" className="header-actions">
|
||||
<div className="header-actions">
|
||||
<IconButton
|
||||
label="聚焦搜索框(Ctrl+K)"
|
||||
icon={<Icon name="search_3_line" />}
|
||||
@@ -43,7 +83,7 @@ export function SiteHeader({ projectCount, sampleProject, live, onFocusSearch }:
|
||||
/>
|
||||
{/* TODO(auth): 后端登录接口就绪后接上,目前仅作入口占位 */}
|
||||
<IconButton label="登录" icon={<Icon name="user_3_line" />} />
|
||||
</Space>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -16,9 +16,14 @@ type CategoryNavProps = {
|
||||
/** 当前明细视图的分类 / 分组,用于高亮 */
|
||||
activeCategoryId?: string
|
||||
activeGroupId?: string
|
||||
/** 是否在首页(高亮「首页」项) */
|
||||
homeActive?: boolean
|
||||
onNavigate: (target: NavTarget) => void
|
||||
/** 点击「首页」 */
|
||||
onHome: () => void
|
||||
}
|
||||
|
||||
const HOME_KEY = 'home'
|
||||
const categoryKey = (id: string) => `cat:${id}`
|
||||
const groupKey = (categoryId: string, groupId: string) => `group:${categoryId}:${groupId}`
|
||||
|
||||
@@ -26,35 +31,46 @@ export function CategoryNav({
|
||||
categories,
|
||||
activeCategoryId,
|
||||
activeGroupId,
|
||||
homeActive = false,
|
||||
onNavigate,
|
||||
onHome,
|
||||
}: CategoryNavProps) {
|
||||
const items: MenuItem[] = categories.map((category) => {
|
||||
const groups =
|
||||
category.kind === 'apps'
|
||||
? category.groups.filter((group) => group.showInSidebar !== false)
|
||||
: []
|
||||
const items: MenuItem[] = [
|
||||
{ key: HOME_KEY, label: '首页' },
|
||||
...categories.map((category) => {
|
||||
const groups =
|
||||
category.kind === 'apps'
|
||||
? category.groups.filter((group) => group.showInSidebar !== false)
|
||||
: []
|
||||
|
||||
return {
|
||||
key: categoryKey(category.id),
|
||||
label: category.title,
|
||||
children:
|
||||
groups.length > 0
|
||||
? groups.map((group) => ({
|
||||
key: groupKey(category.id, group.id),
|
||||
label: group.name,
|
||||
}))
|
||||
: undefined,
|
||||
}
|
||||
})
|
||||
return {
|
||||
key: categoryKey(category.id),
|
||||
label: category.title,
|
||||
children:
|
||||
groups.length > 0
|
||||
? groups.map((group) => ({
|
||||
key: groupKey(category.id, group.id),
|
||||
label: group.name,
|
||||
}))
|
||||
: undefined,
|
||||
}
|
||||
}),
|
||||
]
|
||||
|
||||
const activeKey =
|
||||
activeCategoryId === undefined
|
||||
const activeKey = homeActive
|
||||
? HOME_KEY
|
||||
: activeCategoryId === undefined
|
||||
? undefined
|
||||
: activeGroupId !== undefined
|
||||
? groupKey(activeCategoryId, activeGroupId)
|
||||
: categoryKey(activeCategoryId)
|
||||
|
||||
const handleSelect = (key: string) => {
|
||||
if (key === HOME_KEY) {
|
||||
onHome()
|
||||
return
|
||||
}
|
||||
|
||||
if (key.startsWith('group:')) {
|
||||
const [, categoryId, groupId] = key.split(':')
|
||||
onNavigate({ categoryId, groupId })
|
||||
|
||||
@@ -18,7 +18,11 @@ type SidebarProps = {
|
||||
onRefresh: () => void
|
||||
activeCategoryId?: string
|
||||
activeGroupId?: string
|
||||
/** 是否在首页 */
|
||||
homeActive?: boolean
|
||||
onNavigate: (target: NavTarget) => void
|
||||
/** 点击「首页」 */
|
||||
onHome: () => void
|
||||
}
|
||||
|
||||
export function Sidebar({
|
||||
@@ -29,7 +33,9 @@ export function Sidebar({
|
||||
onRefresh,
|
||||
activeCategoryId,
|
||||
activeGroupId,
|
||||
homeActive = false,
|
||||
onNavigate,
|
||||
onHome,
|
||||
}: SidebarProps) {
|
||||
return (
|
||||
<div className="sidebar">
|
||||
@@ -46,7 +52,9 @@ export function Sidebar({
|
||||
categories={categories}
|
||||
activeCategoryId={activeCategoryId}
|
||||
activeGroupId={activeGroupId}
|
||||
homeActive={homeActive}
|
||||
onNavigate={onNavigate}
|
||||
onHome={onHome}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user