diff --git a/browser/e2e/playwright.config.ts b/browser/e2e/playwright.config.ts index c398f74f..50872b29 100644 --- a/browser/e2e/playwright.config.ts +++ b/browser/e2e/playwright.config.ts @@ -9,6 +9,15 @@ const config: PlaywrightTestConfig = { timezoneId: 'Europe/Amsterdam', actionTimeout: 5000, trace: 'retain-on-failure', + storageState: { + cookies: [], + origins: [ + { + origin: 'http://localhost:5173', + localStorage: [{ name: 'viewTransitionsDisabled', value: 'true' }], + }, + ], + }, }, reporter: [ [ diff --git a/browser/e2e/tests/test-utils.ts b/browser/e2e/tests/test-utils.ts index 86ba75ac..79451b7c 100644 --- a/browser/e2e/tests/test-utils.ts +++ b/browser/e2e/tests/test-utils.ts @@ -73,19 +73,8 @@ export async function setTitle(page: Page, title: string) { await waiter; } -export async function disableViewTransition(page: Page) { - await page.getByRole('link', { name: 'Settings' }).click(); - const checkbox = page.getByLabel('Disable page transition animations'); - - await expect(checkbox).toBeVisible(); - - await checkbox.check(); - await page.goBack(); -} - /** Signs in using an AtomicData.dev test user */ export async function signIn(page: Page) { - await disableViewTransition(page); await page.click('text=Login'); await expect(page.locator('text=edit data and sign Commits')).toBeVisible(); // If there are any issues with this agent, try creating a new one https://atomicdata.dev/invites/1 diff --git a/lib/src/plugins/bookmark.rs b/lib/src/plugins/bookmark.rs index e804c2c0..ffe6861c 100644 --- a/lib/src/plugins/bookmark.rs +++ b/lib/src/plugins/bookmark.rs @@ -135,39 +135,37 @@ impl Parser { pub fn get_meta(&self) -> SiteMeta { let document = parse_html().one(self.internal_html.clone()); - let mut title = None; - let mut description = None; - let mut image = None; - if let Ok(title_element) = document.select_first("title") { - title = Some(title_element.text_contents()); - } + let title = document + .select_first("title") + .ok() + .map(|element| element.text_contents()); - if let Ok(description_element) = - document.select_first("meta[name='description'], meta[property='og:description']") - { - description = Some( - description_element + let description = document + .select_first("meta[name='description'], meta[property='og:description']") + .ok() + .map(|element| { + element .attributes .borrow() .get("content") .unwrap_or("") - .to_string(), - ); - } - - if let Ok(image_element) = - document.select_first("meta[property='og:image'], meta[name='twitter:image']") - { - image = Some( - image_element + .to_string() + }); + + let image = document + .select_first("meta[property='og:image'], meta[name='twitter:image']") + .ok() + .map(|element| { + let image_url = element .attributes .borrow() .get("content") .unwrap_or("") - .to_string(), - ); - } + .to_string(); + + self.relative_to_absolute_url(&image_url) + }); SiteMeta { title, @@ -184,6 +182,34 @@ impl Parser { Ok(self.internal_html.clone()) } + fn relative_to_absolute_url(&self, url: &str) -> String { + if url.starts_with('/') { + // If it starts with //, it's protocol-relative + if url.starts_with("//") { + return format!("https:{}", url); + } + // Get the base URL (scheme + authority) + let base = format!( + "{}://{}", + self.url.scheme(), + self.url.host_str().unwrap_or("") + ); + + return format!("{}{}", base, url); + } + + if !url.contains("://") { + // Handle relative URLs without leading slash + return self + .url + .join(url) + .map(|u| u.to_string()) + .unwrap_or(url.to_string()); + } + + url.to_string() + } + fn resolve_url(&self, url: &str) -> String { if Url::parse(url).is_err() { return self.url.join(url).unwrap().as_str().to_string();