mirror of
https://github.com/nexu-io/open-design.git
synced 2026-10-27 09:51:12 +01:00
Reset home scroll on plugin use (#3757)
This commit is contained in:
@@ -438,6 +438,7 @@ export function EntryShell({
|
||||
useState<CreateTab>('prototype');
|
||||
const [integrationTab, setIntegrationTab] = useState<IntegrationTab>(integrationInitialTab);
|
||||
const [homePromptHandoff, setHomePromptHandoff] = useState<HomePromptHandoff | null>(null);
|
||||
const entryMainScrollRef = useRef<HTMLElement | null>(null);
|
||||
const analytics = useAnalytics();
|
||||
const discordOnlineLabel = discordPresence
|
||||
? t('entry.discordOnlineLabel', {
|
||||
@@ -476,6 +477,21 @@ export function EntryShell({
|
||||
changeView('home');
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
if (view !== 'home' || !homePromptHandoff) return;
|
||||
const frame = window.requestAnimationFrame(() => {
|
||||
const scrollContainer = entryMainScrollRef.current;
|
||||
if (!scrollContainer) return;
|
||||
if (typeof scrollContainer.scrollTo === 'function') {
|
||||
scrollContainer.scrollTo({ top: 0, left: 0 });
|
||||
return;
|
||||
}
|
||||
scrollContainer.scrollTop = 0;
|
||||
scrollContainer.scrollLeft = 0;
|
||||
});
|
||||
return () => window.cancelAnimationFrame(frame);
|
||||
}, [homePromptHandoff?.id, view]);
|
||||
|
||||
useEffect(() => {
|
||||
setIntegrationTab(integrationInitialTab);
|
||||
}, [integrationInitialTab]);
|
||||
@@ -638,7 +654,7 @@ export function EntryShell({
|
||||
open={railOpen}
|
||||
onClose={() => setRailOpen(false)}
|
||||
/>
|
||||
<main className="entry-main entry-main--scroll">
|
||||
<main className="entry-main entry-main--scroll" ref={entryMainScrollRef}>
|
||||
<div className="entry-main__topbar">
|
||||
<button
|
||||
type="button"
|
||||
|
||||
@@ -317,9 +317,22 @@ export function HomeView({
|
||||
});
|
||||
}, [pendingReplacement, analytics.track]);
|
||||
const inputRef = useRef<HomeHeroHandle | null>(null);
|
||||
const homeViewRef = useRef<HTMLDivElement | null>(null);
|
||||
const consumedHandoffIdRef = useRef<number | null>(null);
|
||||
const pendingPromptFocusEndRef = useRef(false);
|
||||
const activePluginApplyRequestRef = useRef(0);
|
||||
const scrollHomeToTop = useCallback(() => {
|
||||
requestAnimationFrame(() => {
|
||||
const scrollContainer = homeViewRef.current?.closest('.entry-main--scroll');
|
||||
if (!(scrollContainer instanceof HTMLElement)) return;
|
||||
if (typeof scrollContainer.scrollTo === 'function') {
|
||||
scrollContainer.scrollTo({ top: 0, left: 0 });
|
||||
} else {
|
||||
scrollContainer.scrollTop = 0;
|
||||
scrollContainer.scrollLeft = 0;
|
||||
}
|
||||
});
|
||||
}, []);
|
||||
const importSkillId = useMemo(() => {
|
||||
const prototypeSkills = skills.filter((skill) => skill.mode === 'prototype');
|
||||
return prototypeSkills.find((skill) => skill.defaultFor.includes('prototype'))?.id
|
||||
@@ -459,6 +472,7 @@ export function HomeView({
|
||||
if (promptHandoff.focus) {
|
||||
focusPromptAtEnd();
|
||||
}
|
||||
scrollHomeToTop();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -478,7 +492,8 @@ export function HomeView({
|
||||
setPendingAuthoringInputs(promptHandoff.inputs);
|
||||
setPendingAuthoringChipId('create-plugin');
|
||||
setPendingChipId('create-plugin');
|
||||
}, [promptHandoff]);
|
||||
scrollHomeToTop();
|
||||
}, [promptHandoff, scrollHomeToTop]);
|
||||
|
||||
const activeContextItemCount = useMemo(
|
||||
() =>
|
||||
@@ -847,6 +862,7 @@ export function HomeView({
|
||||
setError(null);
|
||||
setDetailsRecord(null);
|
||||
if (shouldFocusOnly) focusPromptAtEnd();
|
||||
scrollHomeToTop();
|
||||
}
|
||||
|
||||
function runWithReplacementConfirmation(
|
||||
@@ -1438,7 +1454,7 @@ export function HomeView({
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="home-view" data-testid="home-view">
|
||||
<div className="home-view" data-testid="home-view" ref={homeViewRef}>
|
||||
<HomeHero
|
||||
ref={inputRef}
|
||||
prompt={prompt}
|
||||
|
||||
@@ -87,16 +87,20 @@ describe('HomeView plugin i18n', () => {
|
||||
});
|
||||
vi.stubGlobal('fetch', fetchMock);
|
||||
|
||||
render(
|
||||
const view = render(
|
||||
<I18nProvider initial="zh-CN">
|
||||
<HomeView
|
||||
projects={[]}
|
||||
onSubmit={() => undefined}
|
||||
onOpenProject={() => undefined}
|
||||
onViewAllProjects={() => undefined}
|
||||
/>
|
||||
<div className="entry-main--scroll">
|
||||
<HomeView
|
||||
projects={[]}
|
||||
onSubmit={() => undefined}
|
||||
onOpenProject={() => undefined}
|
||||
onViewAllProjects={() => undefined}
|
||||
/>
|
||||
</div>
|
||||
</I18nProvider>,
|
||||
);
|
||||
const scrollContainer = view.container.querySelector('.entry-main--scroll') as HTMLElement;
|
||||
scrollContainer.scrollTop = 240;
|
||||
|
||||
fireEvent.click(await waitFor(() => screen.getByTestId('plugins-home-use-localized-plugin')));
|
||||
|
||||
@@ -114,6 +118,9 @@ describe('HomeView plugin i18n', () => {
|
||||
await screen.findByTestId('home-hero-input');
|
||||
expect(homeHeroPromptText().trim()).toBe('');
|
||||
expect(fetchMock.mock.calls.some(([url]) => String(url).includes('/apply'))).toBe(false);
|
||||
await waitFor(() => {
|
||||
expect(scrollContainer.scrollTop).toBe(0);
|
||||
});
|
||||
});
|
||||
|
||||
it('hydrates the Home prompt with the localized plugin query', async () => {
|
||||
|
||||
Reference in New Issue
Block a user