diff --git a/packages/content-handler/src/newsletters/substack-handler.ts b/packages/content-handler/src/newsletters/substack-handler.ts index e0c87a159..f94267171 100644 --- a/packages/content-handler/src/newsletters/substack-handler.ts +++ b/packages/content-handler/src/newsletters/substack-handler.ts @@ -120,7 +120,10 @@ export class SubstackHandler extends ContentHandler { // elements (style will be handled in the reader) recurse(tweet, (n: Element) => { const className = n.className - if (className.startsWith('tweet-')) { + if ( + className.startsWith('tweet-') || + className.startsWith('quote-tweet') + ) { n.className = preClassName + className } n.removeAttribute('style') diff --git a/packages/content-handler/test/data/substack-static-quote-tweet.html b/packages/content-handler/test/data/substack-static-quote-tweet.html new file mode 100644 index 000000000..146025f25 --- /dev/null +++ b/packages/content-handler/test/data/substack-static-quote-tweet.html @@ -0,0 +1,1688 @@ +How to use ChatGPT in your PM work
Real-life examples (and actual prompts) of how PMs are already using ChatGPT day-to-day + ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌ ‌
Open in app or online

Below is a peek at today’s paid subscriber-only post. +Subscribe today and get access to this issue—and every issue.


How to use ChatGPT in your PM work

Real-life +examples (and actual prompts) of how PMs are already using ChatGPT day-to-day

👋 Hey, I’m Lenny and welcome to +a 🔒 subscriber-only edition 🔒 of my weekly newsletter. Each week I tackle +reader questions about building product, driving growth, and accelerating your career.


Are PMs +actually using ChatGPT/GPT-4 for getting real work done, and if so, how?

Let this idea sink in:

Though I don’t believe PMs will be displaced by GPT-4/5/6/n, I +do believe that, as with most knowledge work, learning to work alongside AI will quickly become table stakes. Just like Grammarly became for writing, Copilot for engineers, and Firefly, Runway, Midjourney, and others are becoming for designers. It’s +scary and confusing, but also exciting. When was the last time there was a transformative new tool for product management? +Never?

Importantly, as Dan Shipper suggested in +his recent guest post on building the Lenny Chatbot, +“the best way to prepare for this fast-approaching future is to dive in and get your hands +dirty.” So to help you roll up your sleeves and get started, I polled Twitter for concrete examples of how PMs are already +using ChatGPT day-to-day. Honestly, I was shocked by how common (and useful) it has already become for people. Below, I’ve +collected a dozen of my favorite use cases of how you can integrate ChatGPT into your work today—with actual prompts you can +play with.

To follow along, +go sign up for ChatGPT (seriously, go do that now), and try at +least one prompt you find below. Even if you don’t find it useful today, it’ll plant a seed.

Also, a pro tip: You can ask ChatGPT for advice on how to +best phrase your prompt. It’s very meta and very cool.

For example:

Here’s what it +suggested when I did this:

The future is coming fast.

12 ways to use ChatGPT in your PM work

1. Collect and summarize user feedback and usage data

Synthesize survey results:

Find feature ideas and +bugs from app store reviews:

Extract insights from +raw usage metrics:

Do sensitivity analysis:

2. Come up with product name +suggestions

3. Strengthen your argument

Come up with critical questions your audience may +ask:

Identify gaps and hidden assumptions in your +thinking:

Highlight edge cases +and counterarguments:

4. Inspire roadmap +ideas...

Subscribe to Lenny's +Newsletter to read the rest.

Become a paying subscriber of Lenny's Newsletter to get access to this post +and other subscriber-only content.

A subscription gets you:

Every issue of the newsletter
Access to a private Slack community
Access to a curated collection of Lenny’s favorite reads and listens
diff --git a/packages/content-handler/test/newsletter.test.ts b/packages/content-handler/test/newsletter.test.ts index a515cf486..ac40c139c 100644 --- a/packages/content-handler/test/newsletter.test.ts +++ b/packages/content-handler/test/newsletter.test.ts @@ -249,6 +249,30 @@ describe('Newsletter email test', () => { expect(tweets.length).to.eq(7) }) + it('fixes up static quote tweets in Substack newsletters', async () => { + const url = + 'https://www.lennysnewsletter.com/p/how-to-use-chatgpt-in-your-pm-work' + const html = load('./test/data/substack-static-quote-tweet.html') + const handler = await getNewsletterHandler({ + html, + from: '', + headers: {}, + }) + expect(handler).to.be.instanceOf(SubstackHandler) + + const dom = parseHTML(html).document + expect(handler?.shouldPreParse(url, dom)).to.be.true + + const preparsed = await handler?.preParse(url, dom) + const tweets = Array.from( + preparsed?.querySelectorAll( + 'div[class="_omnivore-static-quote-tweet"]' + ) ?? [] + ) + + expect(tweets.length).to.eq(1) + }) + it('returns BeehiivHandler for beehiiv.com newsletter', async () => { const handler = await getNewsletterHandler({ html: '', diff --git a/packages/web/styles/articleInnerStyling.css b/packages/web/styles/articleInnerStyling.css index ec8f77551..a16425fba 100644 --- a/packages/web/styles/articleInnerStyling.css +++ b/packages/web/styles/articleInnerStyling.css @@ -380,6 +380,40 @@ on smaller screens we display the note icon -webkit-font-smoothing: subpixel-antialiased; } +.article-inner-css ._omnivore-static-tweet ._omnivore-static-quote-tweet { + display: flex; + flex-direction: column; + gap: 8px; + border: 1px solid #e0e0e0; + border-radius: 8px; + padding: 12px; + font-size: 14px; + line-height: 20px; +} + +.article-inner-css ._omnivore-static-tweet ._omnivore-static-quote-tweet-header { + display: flex; + flex-direction: row; + gap: 9px; + align-items: center; + justify-content: flex-start; +} + +.article-inner-css ._omnivore-static-tweet ._omnivore-static-quote-tweet-header-avatar { + width: 20px; + height: 20px; + border-radius: 50%; + margin: unset !important; +} + +.article-inner-css ._omnivore-static-tweet ._omnivore-static-quote-tweet-header-text { + display: flex; + flex-direction: row; + gap: 4px; + font-size: 14px; + line-height: 20px; +} + ._omnivore-static-tweet ._omnivore-static-tweet-header { display: flex; align-items: center;