diff --git a/e2e/pages/contact.spec.ts b/e2e/pages/contact.spec.ts index 8b4318d..3d2e4c9 100644 --- a/e2e/pages/contact.spec.ts +++ b/e2e/pages/contact.spec.ts @@ -96,9 +96,5 @@ test('bullet points in free text display well', async ({ page }) => { }); -home: contact list scrolls in screen, not off screen -home: clicking off contact list closes it -home: contact list is sorted ignoring case -home: contact list should scroll to current contact in center of view journal: bullet points don't display */ diff --git a/e2e/pages/home.spec.ts b/e2e/pages/home.spec.ts index 8ec39dd..2ab54f2 100644 --- a/e2e/pages/home.spec.ts +++ b/e2e/pages/home.spec.ts @@ -81,3 +81,21 @@ test('upcoming and recent show at least one birthday a week away', async ({ page await expect(page.locator('#upcoming').getByRole('link')).toHaveCount(4); await expect(page.locator('#recent').getByRole('link')).toHaveCount(4); }); + + +test('contact list scrolls (independently) to current contact in center of view', async ({ page }) => { + for (let count = 0; count < 30; count++) { + await verifyCreateUser(page, { names: [`Contact${count < 10 ? '0' + count : count}`] }); + } + + await page.goto('/contact/28'); + await expect(page.getByRole('navigation').getByRole('link', { name: /Contact28/ })).toBeVisible(); + expect(await page.locator('main').evaluate(e => e.scrollTop)).toEqual(0); + + await page.goto('/contact/16'); + await expect(page.locator('#nav-link-16')).toBeVisible(); + const linkPos: number = await page.locator('#nav-link-16').evaluate(e => e.getBoundingClientRect().y); + + // roughly centered is fine, not that fussy about headers and whatnot + expect(Math.abs(linkPos - (await page.evaluate('window.innerHeight/2') as number))).toBeLessThan(200); +}); diff --git a/src/web/contact/mod.rs b/src/web/contact/mod.rs index b99abdb..6b90020 100644 --- a/src/web/contact/mod.rs +++ b/src/web/contact/mod.rs @@ -61,6 +61,21 @@ fn human_delta(span: &jiff::Span) -> String { mod get { use super::*; + fn scroll_to(id: DbId) -> String { + format!( + "\ + const top = document\ + .getElementById('nav-link-{}')\ + ?.getBoundingClientRect()\ + ?.top;\ + console.log({{ top }});\ + top && document\ + .getElementById('contacts-sidebar')\ + .scrollTo({{top: top+window.innerHeight/2,left:0,behavior:'instant'}});", + id + ) + } + pub async fn contact( auth_session: AuthSession, State(state): State, @@ -125,7 +140,7 @@ mod get { html! { a href=(format!("/contact/{}/edit", contact_id)) { "Edit" } - div id="fields" { + div #fields x-init=(scroll_to(contact_id)) { label { @if contact.names.len() > 1 { "names" } @else { "name" }} div { @for name in &contact.names { @@ -249,7 +264,7 @@ mod get { div #error; } - #fields x-data=(json!({ "status": contact.status() })){ + #fields x-data=(json!({ "status": contact.status() })) x-init=(scroll_to(contact_id)) { label { @if contact.names.len() > 1 { "names" } @else { "name" }} div #names x-data=(format!("{{ names: {:?}, new_name: '' }}", &contact.names)) { template x-for="(name, idx) in names" { diff --git a/src/web/mod.rs b/src/web/mod.rs index a7f755d..3aa6b89 100644 --- a/src/web/mod.rs +++ b/src/web/mod.rs @@ -117,7 +117,7 @@ impl Layout { li { button hx-post="/contact/new" { "+ Add Contact" } } @for link in &self.contact_links { li { - a href=(format!("/contact/{}", link.contact_id)) { + a id=(format!("nav-link-{}", link.contact_id)) href=(format!("/contact/{}", link.contact_id)) { (link.name) } }