A calm place to write long-form, and publish it to the open social web. skypress.blog/
0

Configure Feed

Select the types of activity you want to include in your feed.

Editor: inline self-contained styles so embed preview renders in the SandBox iframe

+48 -2
+19
src/lib/editor/embed-preview.test.ts
··· 18 18 expect( preview!.html ).toContain( 'hello' ); 19 19 } ); 20 20 21 + it( 'inlines self-contained styles so the card renders inside the embed SandBox iframe', async () => { 22 + // core/embed renders preview.html in a sandboxed iframe with no access to 23 + // the editor's stylesheet (or the site theme tokens). The styles must travel 24 + // inside the html, using literal colors rather than `var(--token)`. 25 + const fetchImpl = vi.fn().mockResolvedValue( 26 + jsonResponse( { 27 + posts: [ { uri: 'at://did:plc:a/app.bsky.feed.post/b', author: { handle: 'a.bsky.social' }, record: { text: 'hi' } } ], 28 + } ) 29 + ); 30 + const atproto = await buildEmbedPreview( 'https://bsky.app/profile/did:plc:a/post/b', fetchImpl ); 31 + expect( atproto!.html ).toContain( '<style>' ); 32 + expect( atproto!.html ).toContain( '.skypress-embed' ); 33 + expect( atproto!.html ).not.toContain( 'var(--' ); 34 + 35 + const video = await buildEmbedPreview( 'https://youtu.be/dQw4w9WgXcQ', vi.fn() ); 36 + expect( video!.html ).toContain( '<style>' ); 37 + expect( video!.html ).toContain( '.skypress-embed' ); 38 + } ); 39 + 21 40 it( 'returns a placeholder for a youtube URL (no network)', async () => { 22 41 const fetchImpl = vi.fn(); 23 42 const preview = await buildEmbedPreview( 'https://youtu.be/dQw4w9WgXcQ', fetchImpl );
+29 -2
src/lib/editor/embed-preview.ts
··· 24 24 vimeo: 'Vimeo', 25 25 }; 26 26 27 + /** 28 + * Self-contained card styles for the editor preview. `core/embed` renders the 29 + * preview html inside a sandboxed iframe (`<SandBox>`) that has no access to the 30 + * editor's stylesheet OR the site's theme tokens, so these must be inlined with 31 + * the html and use literal colors (not `var(--token)`). Kept roughly in sync with 32 + * `src/styles/embeds.css` — the reader uses that external stylesheet (themed), 33 + * this is only the in-editor preview approximation. 34 + */ 35 + const PREVIEW_STYLES = 36 + 'body{margin:0;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,sans-serif;color:#1a1a1a}' + 37 + '.skypress-embed{margin:0;border:1px solid #e6e3dd;border-radius:10px;overflow:hidden;background:#faf9f6}' + 38 + '.skypress-embed--atproto .skypress-embed__link{display:block;padding:1rem 1.2rem;text-decoration:none;color:#1a1a1a}' + 39 + '.skypress-embed__head{display:flex;align-items:center;gap:.5rem;margin-bottom:.5rem}' + 40 + '.skypress-embed__avatar{width:32px;height:32px;border-radius:50%;object-fit:cover}' + 41 + '.skypress-embed__author{font-weight:600}' + 42 + '.skypress-embed__handle{color:#6b6b6b;font-size:.92rem}' + 43 + '.skypress-embed__text{display:block;white-space:pre-wrap;line-height:1.5}' + 44 + '.skypress-embed__media{display:grid;gap:.4rem;margin-top:.75rem}' + 45 + '.skypress-embed__image{width:100%;border-radius:8px}' + 46 + '.skypress-embed__footer{display:block;margin-top:.75rem;font-size:.88rem;color:#6b6b6b}' + 47 + '.skypress-embed--placeholder .skypress-embed__text{padding:1rem 1.2rem;color:#6b6b6b}'; 48 + 49 + /** Prepend the inline preview styles so the card renders styled inside the SandBox iframe. */ 50 + function withPreviewStyles( html: string ): string { 51 + return `<style>${ PREVIEW_STYLES }</style>${ html }`; 52 + } 53 + 27 54 function placeholder( label: string ): string { 28 55 return ( 29 56 `<figure class="wp-block-embed skypress-embed skypress-embed--placeholder">` + ··· 54 81 if ( ! card ) { 55 82 return null; 56 83 } 57 - return { type: 'rich', version: '1.0', provider_name: 'Bluesky', html: renderEmbedCard( card ) }; 84 + return { type: 'rich', version: '1.0', provider_name: 'Bluesky', html: withPreviewStyles( renderEmbedCard( card ) ) }; 58 85 } 59 86 return { 60 87 type: 'rich', 61 88 version: '1.0', 62 89 provider_name: PROVIDER_LABEL[ match.kind ], 63 - html: placeholder( PROVIDER_LABEL[ match.kind ] ), 90 + html: withPreviewStyles( placeholder( PROVIDER_LABEL[ match.kind ] ) ), 64 91 }; 65 92 } 66 93