支持 app.ini 配置与系统服务安装,并优化前端布局与无障碍体验。
引入类 Gitea 的 app.ini、Windows Service/systemd 控制;前端增加侧栏抽屉、回到顶部、标签输入与浮层 a11y。 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -1,5 +1,7 @@
|
||||
import { useRef } from 'react';
|
||||
import { Clock, MessageCircle, Flame } from 'lucide-react';
|
||||
import { cn } from '@/lib/utils';
|
||||
import { moveTabIndex } from '../hooks/useOverlayA11y';
|
||||
|
||||
export type FeedSort = 'latest' | 'reply' | 'hot';
|
||||
|
||||
@@ -38,14 +40,35 @@ export function feedSortLabel(sort: FeedSort): string {
|
||||
}
|
||||
|
||||
export default function FeedSortBar({ value, onChange, postTotal }: Props) {
|
||||
const listRef = useRef<HTMLDivElement>(null);
|
||||
const activeIndex = Math.max(0, SORT_OPTIONS.findIndex(o => o.key === value));
|
||||
|
||||
const onKeyDown = (e: React.KeyboardEvent) => {
|
||||
const next = moveTabIndex(e.key, activeIndex, SORT_OPTIONS.length);
|
||||
if (next == null) return;
|
||||
e.preventDefault();
|
||||
onChange(SORT_OPTIONS[next].key);
|
||||
requestAnimationFrame(() => {
|
||||
const tabs = listRef.current?.querySelectorAll<HTMLElement>('[role="tab"]');
|
||||
tabs?.[next]?.focus();
|
||||
});
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="feed-toolbar">
|
||||
<div className="feed-sort-bar" role="tablist" aria-label="帖子排序">
|
||||
{SORT_OPTIONS.map(({ key, label, hint, icon: Icon }) => (
|
||||
<div
|
||||
ref={listRef}
|
||||
className="feed-sort-bar"
|
||||
role="tablist"
|
||||
aria-label="帖子排序"
|
||||
onKeyDown={onKeyDown}
|
||||
>
|
||||
{SORT_OPTIONS.map(({ key, label, hint, icon: Icon }, i) => (
|
||||
<button
|
||||
key={key}
|
||||
type="button"
|
||||
role="tab"
|
||||
tabIndex={activeIndex === i ? 0 : -1}
|
||||
aria-selected={value === key}
|
||||
title={`${label} · ${hint}`}
|
||||
className={cn('feed-sort-tab', value === key && 'active')}
|
||||
|
||||
Reference in New Issue
Block a user