Skip to content

Commit e0103e0

Browse files
committed
fix(settings): soften section jump indicator
1 parent b9c1885 commit e0103e0

2 files changed

Lines changed: 79 additions & 32 deletions

File tree

src/features/settings/ui/SettingsUI.ts

Lines changed: 39 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -129,25 +129,59 @@ export class SettingsUI {
129129
button.title = label;
130130
button.setAttribute('aria-label', label);
131131

132+
const sectionScrollTop = (section: HTMLElement | undefined) =>
133+
Math.min(
134+
Math.max(0, page.scrollHeight - page.clientHeight),
135+
Math.max(0, (section?.offsetTop ?? 0) - page.offsetTop),
136+
);
137+
const getTopScroll = () => sectionScrollTop(sections[0]);
138+
const getAgentScroll = () => sectionScrollTop(sections[1]);
139+
const getIsAgentSection = () => page.scrollTop >= (getTopScroll() + getAgentScroll()) / 2;
140+
const syncButtonPosition = () => {
141+
button.style.top = `${page.scrollTop + page.clientHeight - 48}px`;
142+
};
143+
132144
const update = () => {
133-
const isAgentSection = page.scrollTop > Math.max(48, page.clientHeight * 0.25);
145+
const isAgentSection = getIsAgentSection();
134146
button.classList.toggle('is-up', isAgentSection);
147+
syncButtonPosition();
135148
};
136149

137-
const handleClick = () => {
138-
const isAgentSection = button.classList.contains('is-up');
139-
sections[isAgentSection ? 0 : 1]?.scrollIntoView({
150+
const scrollToSection = (toTop: boolean) => {
151+
page.scrollTo({
152+
top: toTop ? getTopScroll() : getAgentScroll(),
140153
behavior: 'smooth',
141-
block: 'start',
142154
});
155+
requestAnimationFrame(update);
156+
};
157+
158+
const handleClick = () => {
159+
scrollToSection(getIsAgentSection());
160+
};
161+
162+
let wheelLocked = false;
163+
const handleWheel = (event: WheelEvent) => {
164+
if (Math.abs(event.deltaY) < 8 || wheelLocked) {
165+
return;
166+
}
167+
event.preventDefault();
168+
wheelLocked = true;
169+
scrollToSection(event.deltaY < 0);
170+
globalThis.setTimeout(() => {
171+
wheelLocked = false;
172+
}, 420);
143173
};
144174

145175
page.addEventListener('scroll', update, { passive: true });
176+
page.addEventListener('wheel', handleWheel, { passive: false });
177+
globalThis.addEventListener('resize', update);
146178
button.addEventListener('click', handleClick);
147179
update();
148180

149181
this._sectionJumpUnlisten = () => {
150182
page.removeEventListener('scroll', update);
183+
page.removeEventListener('wheel', handleWheel);
184+
globalThis.removeEventListener('resize', update);
151185
button.removeEventListener('click', handleClick);
152186
};
153187
}

src/styles/features/settings-page.css

Lines changed: 40 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -15,18 +15,26 @@
1515
#page-settings {
1616
overflow-y: auto;
1717
overflow-x: hidden;
18-
padding: var(--content-padding-top) 1.5rem 1.5rem 1.5rem;
18+
padding: 0 1.5rem;
1919
align-items: stretch;
2020
position: relative;
2121
background: transparent;
2222
scroll-snap-type: y mandatory;
23-
scroll-padding-top: var(--content-padding-top);
23+
scroll-padding-top: 0;
2424
scroll-behavior: smooth;
25+
scrollbar-width: none;
26+
-ms-overflow-style: none;
27+
}
28+
29+
#page-settings::-webkit-scrollbar {
30+
width: 0;
31+
height: 0;
2532
}
2633

2734
.settings-wrapper {
2835
width: 100%;
2936
max-width: 1240px;
37+
height: 100%;
3038
min-height: 100%;
3139
margin: 0 auto;
3240
padding: 0;
@@ -36,63 +44,68 @@
3644
}
3745

3846
.settings-section-jump {
39-
position: sticky;
40-
bottom: 1rem;
41-
justify-self: center;
47+
position: absolute;
48+
left: 50%;
49+
top: calc(100% - 3rem);
4250
z-index: 30;
43-
width: 2.55rem;
44-
height: 2.55rem;
45-
margin-top: -3.55rem;
46-
border: 1px solid rgba(255, 255, 255, 0.06);
47-
border-radius: var(--radius-md);
48-
background: rgba(30, 30, 35, 0.82);
49-
box-shadow:
50-
0 10px 24px rgba(0, 0, 0, 0.28),
51-
inset 0 1px 0 rgba(255, 255, 255, 0.05);
52-
color: rgba(248, 246, 252, 0.88);
51+
width: 2rem;
52+
height: 2rem;
53+
margin: 0;
54+
border: 1px solid transparent;
55+
border-radius: 8px;
56+
background: transparent;
57+
box-shadow: none;
58+
color: rgba(248, 246, 252, 0.72);
5359
cursor: pointer;
5460
display: flex;
5561
align-items: center;
5662
justify-content: center;
57-
opacity: 0.78;
63+
opacity: 0.34;
5864
transition:
5965
opacity 0.16s ease,
6066
background 0.16s ease,
6167
border-color 0.16s ease,
6268
transform 0.16s ease;
69+
transform: translateX(-50%);
6370
}
6471

6572
.settings-section-jump::before {
6673
content: '';
67-
width: 0.62rem;
68-
height: 0.62rem;
69-
border-right: 2px solid currentColor;
70-
border-bottom: 2px solid currentColor;
71-
transform: translateY(-0.12rem) rotate(45deg);
74+
width: 4px;
75+
height: 4px;
76+
background: transparent;
77+
box-shadow:
78+
-8px -4px 0 currentColor,
79+
8px -4px 0 currentColor,
80+
-4px 0 0 currentColor,
81+
4px 0 0 currentColor,
82+
0 4px 0 currentColor;
83+
image-rendering: pixelated;
84+
transform: translateY(1px);
7285
transition: transform 0.18s ease;
7386
}
7487

7588
.settings-section-jump.is-up::before {
76-
transform: translateY(0.12rem) rotate(225deg);
89+
transform: translateY(-1px) rotate(180deg);
7790
}
7891

7992
.settings-section-jump:hover,
8093
.settings-section-jump:focus-visible {
81-
opacity: 1;
82-
background: rgba(255, 255, 255, 0.12);
83-
border-color: rgba(255, 255, 255, 0.1);
94+
opacity: 0.72;
95+
background: rgba(255, 255, 255, 0.035);
96+
border-color: rgba(255, 255, 255, 0.035);
8497
}
8598

8699
.settings-section-jump:active {
87-
transform: translateY(1px);
100+
transform: translateX(-50%) translateY(1px);
88101
}
89102

90103
#page-settings.active .settings-wrapper {
91104
animation: settings-content-rise 0.3s cubic-bezier(0.22, 1, 0.36, 1);
92105
}
93106

94107
.settings-section {
95-
min-height: calc(100dvh - var(--content-padding-top) - 1.5rem);
108+
min-height: 100%;
96109
scroll-snap-align: start;
97110
scroll-snap-stop: always;
98111
display: flex;

0 commit comments

Comments
 (0)