Fix settings navigation routing
Replace hash links in the settings side navigation with button-driven in-page scrolling so the hash router does not leave the settings page.
This commit is contained in:
@@ -37,7 +37,9 @@ describe('SettingsPanel', () => {
|
|||||||
expect(html).toContain('MoA 참조 모델');
|
expect(html).toContain('MoA 참조 모델');
|
||||||
expect(html).toContain('패스트 모드');
|
expect(html).toContain('패스트 모드');
|
||||||
expect(html).toContain('Codex 실험 기능');
|
expect(html).toContain('Codex 실험 기능');
|
||||||
expect(html).toContain('href="#settings-codex"');
|
expect(html).toContain('data-settings-target="settings-codex"');
|
||||||
|
expect(html).toContain('aria-controls="settings-codex"');
|
||||||
|
expect(html).not.toContain('href="#settings-codex"');
|
||||||
expect(html).toContain('/goal');
|
expect(html).toContain('/goal');
|
||||||
expect(html).toContain('변경 적용');
|
expect(html).toContain('변경 적용');
|
||||||
expect(html).toContain('불러오는 중');
|
expect(html).toContain('불러오는 중');
|
||||||
|
|||||||
@@ -32,31 +32,15 @@ interface AccountData {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const SETTINGS_NAV_ITEMS = [
|
const SETTINGS_NAV_ITEMS = [
|
||||||
|
{ targetId: 'settings-general', title: '일반', detail: '표시 · 언어' },
|
||||||
{
|
{
|
||||||
href: '#settings-general',
|
targetId: 'settings-models',
|
||||||
title: '일반',
|
|
||||||
detail: '표시 · 언어',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
href: '#settings-models',
|
|
||||||
title: '모델',
|
title: '모델',
|
||||||
detail: 'owner · reviewer · arbiter',
|
detail: 'owner · reviewer · arbiter',
|
||||||
},
|
},
|
||||||
{
|
{ targetId: 'settings-moa', title: 'MoA', detail: '참조 모델 · 연결 테스트' },
|
||||||
href: '#settings-moa',
|
{ targetId: 'settings-codex', title: 'Codex', detail: 'fast mode · /goal' },
|
||||||
title: 'MoA',
|
{ targetId: 'settings-accounts', title: '계정', detail: 'Claude · Codex' },
|
||||||
detail: '참조 모델 · 연결 테스트',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
href: '#settings-codex',
|
|
||||||
title: 'Codex',
|
|
||||||
detail: 'fast mode · /goal',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
href: '#settings-accounts',
|
|
||||||
title: '계정',
|
|
||||||
detail: 'Claude · Codex',
|
|
||||||
},
|
|
||||||
] as const;
|
] as const;
|
||||||
|
|
||||||
export interface SettingsPanelProps {
|
export interface SettingsPanelProps {
|
||||||
@@ -171,13 +155,25 @@ function SettingsHero() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function SettingsNav() {
|
function SettingsNav() {
|
||||||
|
const scrollToSection = (targetId: string) => {
|
||||||
|
document
|
||||||
|
.getElementById(targetId)
|
||||||
|
?.scrollIntoView({ behavior: 'smooth', block: 'start' });
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<aside className="settings-nav" aria-label="설정 섹션">
|
<aside className="settings-nav" aria-label="설정 섹션">
|
||||||
{SETTINGS_NAV_ITEMS.map((item) => (
|
{SETTINGS_NAV_ITEMS.map((item) => (
|
||||||
<a href={item.href} key={item.href}>
|
<button
|
||||||
|
aria-controls={item.targetId}
|
||||||
|
data-settings-target={item.targetId}
|
||||||
|
key={item.targetId}
|
||||||
|
onClick={() => scrollToSection(item.targetId)}
|
||||||
|
type="button"
|
||||||
|
>
|
||||||
<strong>{item.title}</strong>
|
<strong>{item.title}</strong>
|
||||||
<small>{item.detail}</small>
|
<small>{item.detail}</small>
|
||||||
</a>
|
</button>
|
||||||
))}
|
))}
|
||||||
</aside>
|
</aside>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -734,14 +734,17 @@ button:disabled {
|
|||||||
box-shadow: var(--card-shadow);
|
box-shadow: var(--card-shadow);
|
||||||
}
|
}
|
||||||
|
|
||||||
.settings-nav a {
|
.settings-nav button {
|
||||||
display: grid;
|
display: grid;
|
||||||
gap: 2px;
|
gap: 2px;
|
||||||
padding: 10px 12px;
|
padding: 10px 12px;
|
||||||
border: 1px solid transparent;
|
border: 1px solid transparent;
|
||||||
border-radius: 12px;
|
border-radius: 12px;
|
||||||
|
background: transparent;
|
||||||
color: var(--muted);
|
color: var(--muted);
|
||||||
text-decoration: none;
|
font: inherit;
|
||||||
|
text-align: left;
|
||||||
|
cursor: pointer;
|
||||||
transition:
|
transition:
|
||||||
background 140ms ease,
|
background 140ms ease,
|
||||||
border-color 140ms ease,
|
border-color 140ms ease,
|
||||||
@@ -749,13 +752,19 @@ button:disabled {
|
|||||||
transform 140ms ease;
|
transform 140ms ease;
|
||||||
}
|
}
|
||||||
|
|
||||||
.settings-nav a:hover {
|
.settings-nav button:hover,
|
||||||
|
.settings-nav button:focus-visible {
|
||||||
transform: translateX(2px);
|
transform: translateX(2px);
|
||||||
border-color: rgba(214, 130, 88, 0.24);
|
border-color: rgba(214, 130, 88, 0.24);
|
||||||
background: rgba(214, 130, 88, 0.08);
|
background: rgba(214, 130, 88, 0.08);
|
||||||
color: var(--bg-ink);
|
color: var(--bg-ink);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.settings-nav button:focus-visible {
|
||||||
|
outline: 2px solid rgba(214, 130, 88, 0.34);
|
||||||
|
outline-offset: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
.settings-nav strong {
|
.settings-nav strong {
|
||||||
color: currentColor;
|
color: currentColor;
|
||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
|
|||||||
Reference in New Issue
Block a user