<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Astro | Nerdpress.org</title>
	<atom:link href="https://nerdpress.org/tag/astro/feed/" rel="self" type="application/rss+xml" />
	<link>https://nerdpress.org</link>
	<description>...dev, tech problems and solutions.</description>
	<lastBuildDate>Sat, 28 Feb 2026 14:46:50 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.9.4</generator>
	<item>
		<title>A WordPress-like More Tag in Astro</title>
		<link>https://nerdpress.org/2026/02/28/a-wordpress-like-more-tag-in-astro/</link>
		
		<dc:creator><![CDATA[Ivo Bathke]]></dc:creator>
		<pubDate>Sat, 28 Feb 2026 14:46:49 +0000</pubDate>
				<category><![CDATA[Astro]]></category>
		<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[Wordpress]]></category>
		<guid isPermaLink="false">https://nerdpress.org/?p=3470</guid>

					<description><![CDATA[<p>When migrating from WordPress to Astro, one encounters various challenges.One is handling the WordPress &#8220;More&#8221; tag, which originates from the More Element in the WordPress Block Editor. After converting the WordPress export to Markdown, you will find `&#60;!&#8211; more &#8211;>` tags in your content. These tags serve as delimiters in WordPress, allowing you to define &#8230; </p>
<p class="link-more"><a href="https://nerdpress.org/2026/02/28/a-wordpress-like-more-tag-in-astro/" class="more-link">Continue reading<span class="screen-reader-text"> "A WordPress-like More Tag in Astro"</span></a></p>
The post <a href="https://nerdpress.org/2026/02/28/a-wordpress-like-more-tag-in-astro/">A WordPress-like More Tag in Astro</a> first appeared on <a href="https://nerdpress.org">Nerdpress.org</a>.]]></description>
										<content:encoded><![CDATA[<p>When migrating from WordPress to Astro, one encounters various challenges.<br />One is handling the WordPress &#8220;More&#8221; tag, which originates from the More Element in the WordPress Block Editor.</p>



<p>After converting the WordPress export to Markdown, you will find `&lt;!&#8211; more &#8211;>` tags in your content. These tags serve as delimiters in WordPress, allowing you to define where the excerpt ends on listing pages.</p>



<span id="more-3470"></span>



<h2 class="wp-block-heading"><strong>The Challenge</strong></h2>



<p>Astro does not provide a built-in mechanism to handle these tags. I also could not find a suitable plugin that would manage this functionality.</p>



<p>My first approach was to use a Remark plugin like <a href="https://www.npmjs.com/package/remark-excerpt" target="_blank" rel="noopener" title="">remark-excerpt</a>. However, this did not work as expected. Instead of adding an Excerpt property to the frontmatter or to the data object of the content collection, it simply replaced the Content with the Excerpt.</p>



<p>Writing a custom Remark plugin proved challenging as well. While extracting the excerpt markdown is straightforward, rendering it to HTML is not. Since Astro does not expose its renderer (yet*), you would need to create your own renderer or use Astro&#8217;s internal `astrojs/markdown-remark`. Both approaches are rather hacky and not really recommended.</p>



<p>* <em>There are ongoing discussions about making the renderer API public: <a href="https://github.com/withastro/roadmap/discussions/1094" target="_blank" rel="noopener" title="">Astro Roadmap Discussion #1094.</a></em></p>



<h2 class="wp-block-heading"><strong>The Solution</strong></h2>



<p>The current best way to handle the WordPress More Tag in Astro is to split the rendered HTML content directly.</p>



<p>On the list page where you want to display the excerpt, you can map over the entries, split the rendered HTML at the <code>&lt;!--more--></code> tag, and add the excerpt to the return object:</p>


<pre class="wp-block-code"><span><code class="hljs language-javascript"><span class="hljs-keyword">const</span> previewPosts = <span class="hljs-keyword">await</span> <span class="hljs-built_in">Promise</span>.all(
	posts.map(<span class="hljs-keyword">async</span> (post) =&gt; {
		<span class="hljs-keyword">const</span> fullHtml = post.rendered?.html || <span class="hljs-string">''</span>;
		<span class="hljs-keyword">const</span> moreIndex = fullHtml.indexOf(<span class="hljs-string">'&lt;!--more--&gt;'</span>);
		<span class="hljs-keyword">const</span> excerptHtml = moreIndex !== <span class="hljs-number">-1</span> ? fullHtml.slice(<span class="hljs-number">0</span>, moreIndex) : fullHtml;
		<span class="hljs-keyword">const</span> hasMore = moreIndex !== <span class="hljs-number">-1</span>;
		<span class="hljs-keyword">return</span> { post, hasMore, excerptHtml };
	}),
);

{previewPosts.map(<span class="hljs-function">(<span class="hljs-params">{ post, hasMore, Content }</span>) =&gt;</span> (
	<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"preview-content"</span>&gt;</span>
		<span class="hljs-tag">&lt;<span class="hljs-name">Content</span> /&gt;</span>
	<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span>
	{hasMore &amp;&amp; <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">p</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"read-more"</span>&gt;</span>Read more...<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span></span>}
))}</code></span></pre>


<p>Straightforward and effective :)</p>



<p></p>The post <a href="https://nerdpress.org/2026/02/28/a-wordpress-like-more-tag-in-astro/">A WordPress-like More Tag in Astro</a> first appeared on <a href="https://nerdpress.org">Nerdpress.org</a>.]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Dynamic OpenGraph Images in Astro</title>
		<link>https://nerdpress.org/2025/12/23/dynamic-opengraph-images-in-astro/</link>
		
		<dc:creator><![CDATA[Ivo Bathke]]></dc:creator>
		<pubDate>Tue, 23 Dec 2025 13:13:06 +0000</pubDate>
				<category><![CDATA[Astro]]></category>
		<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[OpenGraph]]></category>
		<guid isPermaLink="false">https://nerdpress.org/?p=3457</guid>

					<description><![CDATA[<p>If you&#8217;ve ever shared a link on social media, you know how critical OpenGraph (OG) images are. They&#8217;re the first thing people see &#8211; often before they even click.Static OG images are fine as a start, but what if you want custom images for every blog post or content collection item? For Astro there is &#8230; </p>
<p class="link-more"><a href="https://nerdpress.org/2025/12/23/dynamic-opengraph-images-in-astro/" class="more-link">Continue reading<span class="screen-reader-text"> "Dynamic OpenGraph Images in Astro"</span></a></p>
The post <a href="https://nerdpress.org/2025/12/23/dynamic-opengraph-images-in-astro/">Dynamic OpenGraph Images in Astro</a> first appeared on <a href="https://nerdpress.org">Nerdpress.org</a>.]]></description>
										<content:encoded><![CDATA[<p>If you&#8217;ve ever shared a link on social media, you know how critical OpenGraph (OG) images are. They&#8217;re the first thing people see &#8211; often before they even click.<br />Static OG images are fine as a start, but what if you want <strong>custom images for every blog post or content collection item</strong>?</p>



<p>For Astro there is <a href="https://github.com/delucis/astro-og-canvas" target="_blank" rel="noopener" title="">astro-og-canvas</a>, a nice and useful Astro plugin that utilizes Canvas to create dynamic OG images.</p>



<p>In this post, I&#8217;ll walk you through how to generate dynamic OG images for your Astro site, inspired by <a href="https://aidankinzett.com/blog/astro-open-graph-image/" target="_blank" rel="noopener" title="">Aidan Kinzett&#8217;s excellent post</a>.<br />I&#8217;ll also share some odds and learned lessons.</p>



<span id="more-3457"></span>



<p><strong>Step 1: Set Up `astro-og-canvas`</strong></p>



<p>First, install the package:</p>



<p><code>npm install astro-og-canvas</code></p>



<p>Create a new file at <code>src/pages/og/[...routes].ts</code>.<br />This will dynamically generate images for your content.<br />Here&#8217;s how I set it up for my newsletter collection:</p>


<pre class="wp-block-code"><span><code class="hljs language-typescript"><span class="hljs-keyword">import</span> { OGImageRoute } <span class="hljs-keyword">from</span> <span class="hljs-string">"astro-og-canvas"</span>;
<span class="hljs-keyword">import</span> { getCollection } <span class="hljs-keyword">from</span> <span class="hljs-string">"astro:content"</span>;

<span class="hljs-comment">// Fetch all newsletter entries</span>
<span class="hljs-keyword">const</span> newsletters = <span class="hljs-keyword">await</span> getCollection(<span class="hljs-string">"newsletter"</span>);

<span class="hljs-comment">// Map newsletters to OG image configurations</span>
<span class="hljs-keyword">const</span> pages = {
  ...Object.fromEntries(
    newsletters.map(<span class="hljs-function">(<span class="hljs-params"><span class="hljs-params">newsletter</span></span>) =&gt;</span> &#91;
      newsletter.data.slug,
      {
        data: {
          title: newsletter.data.title,
          description: newsletter.data.newsletter.parts
            .map(<span class="hljs-function">(<span class="hljs-params"><span class="hljs-params">part</span></span>) =&gt;</span> <span class="hljs-string">`<span class="hljs-subst">${part.emoji.icon}</span> <span class="hljs-subst">${part.title}</span>`</span>)
            .join(<span class="hljs-string">" • "</span>),
        },
        slug: newsletter.data.slug,
      },
    ])
  ),
};

<span class="hljs-keyword">export</span> <span class="hljs-keyword">const</span> { getStaticPaths, GET } = OGImageRoute({
  param: <span class="hljs-string">"route"</span>,
  pages,
  getImageOptions: <span class="hljs-keyword">async</span> (_, { data, slug }) =&gt; ({
    title: <span class="hljs-string">`Ivo's Ecotainment Newsletter: <span class="hljs-subst">${data.title}</span>`</span>,
    description: data.description,
    bgGradient: &#91;
      &#91;<span class="hljs-number">255</span>, <span class="hljs-number">221</span>, <span class="hljs-number">0</span>], <span class="hljs-comment">// Yellow (from logo)</span>
      &#91;<span class="hljs-number">255</span>, <span class="hljs-number">255</span>, <span class="hljs-number">255</span>], <span class="hljs-comment">// White</span>
    ],
    logo: {
      path: <span class="hljs-string">"./public/Ivos-Ecotainment-Newsletter_Salamander.png"</span>,
      size: &#91;<span class="hljs-number">1080</span>],
    },
    border: {
      color: &#91;<span class="hljs-number">83</span>, <span class="hljs-number">174</span>, <span class="hljs-number">90</span>], <span class="hljs-comment">// Green accent</span>
      width: <span class="hljs-number">2</span>,
      side: <span class="hljs-string">"inline-start"</span>,
    },
    font: {
      title: {
        size: <span class="hljs-number">42</span>,
        weight: <span class="hljs-string">"Bold"</span>,
        families: &#91;<span class="hljs-string">"Noto Sans"</span>, <span class="hljs-string">"Noto Color Emoji"</span>],
        color: &#91;<span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>],
      },
      description: {
        size: <span class="hljs-number">20</span>,
        weight: <span class="hljs-string">"Normal"</span>,
        families: &#91;<span class="hljs-string">"Noto Sans"</span>, <span class="hljs-string">"Noto Color Emoji"</span>],
        color: &#91;<span class="hljs-number">0</span>, <span class="hljs-number">0</span>, <span class="hljs-number">0</span>],
        lineHeight: <span class="hljs-number">1.4</span>,
      },
    },
    fonts: &#91;
      <span class="hljs-string">"./public/fonts/Noto_Sans/NotoSans-VariableFont_wdth,wght.ttf"</span>,
      <span class="hljs-string">"./public/fonts/Noto_Color_Emoji/NotoColorEmoji-Regular.ttf"</span>,
    ],
    padding: <span class="hljs-number">50</span>,
  }),
});</code></span></pre>


<p><br /><strong>Some learned lessons:</strong><br />1. Logos: SVGs won&#8217;t work here. Use PNGs instead.<br />2. Fonts: Add font files, if you use fonts.<br />3. Emojis: If you use emojis in your content, include an emoji font (like &#8220;Noto Color Emoji&#8221;) to ensure they render correctly.</p>



<p><strong>Step 2: Integrate with astro-seo</strong></p>



<p>I use the <a href="https://github.com/jonasmerlin/astro-seo" target="_blank" rel="noopener" title="">astro-seo</a> component in my main Layout component to handle SEO metadata.</p>



<p>For the OG image I add a prop to be passed from the respective page:</p>


<pre class="wp-block-code"><span><code class="hljs language-typescript"><span class="hljs-keyword">const</span> { title, description, ogImage } = Astro.props;

&lt;SEO
  title={title}
  description={description}
  openGraph={{
    basic: {
      title,
      <span class="hljs-keyword">type</span>: <span class="hljs-string">"website"</span>,
      image: ogImage || <span class="hljs-string">`<span class="hljs-subst">${Astro.site}</span>Ivos-Ecotainment-Newsletter_big.png`</span>, <span class="hljs-comment">// Fallback</span>
    },
  }}
/&gt;</code></span></pre>


<p><strong>In Your Content Pages</strong>:<br />Construct the OG image path and pass it to your layout:</p>


<pre class="wp-block-code"><span><code class="hljs language-typescript"><span class="hljs-keyword">const</span> ogImage = <span class="hljs-string">`<span class="hljs-subst">${Astro.site?.href || <span class="hljs-string">""</span>}</span>og/<span class="hljs-subst">${entry.data.slug}</span>.png`</span>;

&lt;Layout title={entry.data.title} description={description} ogImage={ogImage}&gt;
  {<span class="hljs-comment">/* Post content */</span>}
&lt;<span class="hljs-regexp">/Layout&gt;</span></code></span></pre>


<p><strong>Astro Odds</strong>:</p>



<p>A bit odd is if your <code>astro.config.mjs</code> has <code>trailingSlash: "always"</code>, you&#8217;ll need to add a trailing slash to OG image URLs <strong>in development</strong>:<br /><code>http://localhost:4321/og/${entry.data.slug}.png/</code></p>



<p>In prod (no trailing slash needed) so you can just pass it as: <code>http://localhost:4321/og/${entry.data.slug}.png</code></p>



<p></p>



<p><strong>3. Testing OG Images</strong></p>



<p>As recommend in the Blog post of Aidan Kinzett: Use <a href="https://www.opengraph.xyz" target="_blank" rel="noopener" title="">opengraph.xyz</a>  to preview your OG images before sharing links.<br />Very good tool!</p>



<p>Here is how the OG image looks like with logo, title and description with emojis:</p>



<figure class="wp-block-image size-large"><a href="https://ivos-ecotainment-newsletter.info/archiv/pt58-party-parrot/"><img fetchpriority="high" decoding="async" width="1024" height="538" src="https://nerdpress.org/wp-content/uploads/2025/12/pt58-party-parrot-1024x538.png" alt="" class="wp-image-3462" srcset="https://nerdpress.org/wp-content/uploads/2025/12/pt58-party-parrot-1024x538.png 1024w, https://nerdpress.org/wp-content/uploads/2025/12/pt58-party-parrot-300x158.png 300w, https://nerdpress.org/wp-content/uploads/2025/12/pt58-party-parrot-768x403.png 768w, https://nerdpress.org/wp-content/uploads/2025/12/pt58-party-parrot.png 1200w" sizes="(max-width: 767px) 89vw, (max-width: 1000px) 54vw, (max-width: 1071px) 543px, 580px" /></a></figure>



<p>Happy hacking!</p>



<p></p>The post <a href="https://nerdpress.org/2025/12/23/dynamic-opengraph-images-in-astro/">Dynamic OpenGraph Images in Astro</a> first appeared on <a href="https://nerdpress.org">Nerdpress.org</a>.]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>ObfuscateLink Web Component in Astro</title>
		<link>https://nerdpress.org/2025/02/07/obfuscatelink-web-component-in-astro/</link>
		
		<dc:creator><![CDATA[Ivo Bathke]]></dc:creator>
		<pubDate>Fri, 07 Feb 2025 09:36:02 +0000</pubDate>
				<category><![CDATA[Astro]]></category>
		<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[Web components]]></category>
		<guid isPermaLink="false">https://nerdpress.org/?p=3393</guid>

					<description><![CDATA[<p>Using Web Components in Astro wasn&#8217;t as straightforward as expected. Here&#8217;s an example showing how to integrate the obfuscate-link web component into an Astro project.&#160; First, add the Obfuscate-Link web component to the project: Now register ObfuscateLink with customElements:&#160; This occurs in the Layout.astro component, making it available across all pages. The registration happens within &#8230; </p>
<p class="link-more"><a href="https://nerdpress.org/2025/02/07/obfuscatelink-web-component-in-astro/" class="more-link">Continue reading<span class="screen-reader-text"> "ObfuscateLink Web Component in Astro"</span></a></p>
The post <a href="https://nerdpress.org/2025/02/07/obfuscatelink-web-component-in-astro/">ObfuscateLink Web Component in Astro</a> first appeared on <a href="https://nerdpress.org">Nerdpress.org</a>.]]></description>
										<content:encoded><![CDATA[<p>Using Web Components in <a href="https://astro.build/" title="">Astro</a> wasn&#8217;t as straightforward as expected. Here&#8217;s an example showing how to integrate the <a href="https://github.com/ivoba/obfuscate-wc" title="">obfuscate-link</a> web component into an Astro project.&nbsp;</p>



<p>First, add the Obfuscate-Link web component to the project:</p>


<pre class="wp-block-code"><span><code class="hljs">npm install obfuscate-link-web-component</code></span></pre>


<span id="more-3393"></span>



<p>Now register ObfuscateLink with customElements:&nbsp;</p>


<pre class="wp-block-code"><span><code class="hljs language-xml"><span class="hljs-tag">&lt;<span class="hljs-name">body</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">slot</span> /&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">script</span>&gt;</span><span class="javascript">
      <span class="hljs-keyword">import</span> { ObfuscateLink } <span class="hljs-keyword">from</span> <span class="hljs-string">'obfuscate-link-web-component'</span>;
      <span class="hljs-comment">// Only define the custom element if it hasn't been defined yet</span>
      <span class="hljs-keyword">if</span> (!customElements.get(<span class="hljs-string">'obfuscate-link'</span>)) {
        customElements.define(<span class="hljs-string">'obfuscate-link'</span>, ObfuscateLink);
      }
    </span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">body</span>&gt;</span></code></span></pre>


<p>This occurs in the Layout.astro component, making it available across all pages. The registration happens within a script tag in the HTML to execute only on the client side, avoiding it execution while SSR rendering performed by Astro beforehand.</p>



<p>Next, create an Astro component that wraps the web-component and handles the obfuscation by encoding the passed prop.</p>


<pre class="wp-block-code"><span><code class="hljs language-javascript">---
type BaseProps = {
  id?: string;
}
type EmailProps = BaseProps &amp; {
  <span class="hljs-attr">email</span>: string;
  tel?: never;
  sms?: never;
  facetime?: never;
  href?: never;
}
type TelProps = BaseProps &amp; {
  email?: never;
  tel: string;
  sms?: never;
  facetime?: never;
  href?: never;
}
type SmsProps = BaseProps &amp; {
  email?: never;
  tel?: never;
  sms: string;
  facetime?: never;
  href?: never;
}
type FacetimeProps = BaseProps &amp; {
  email?: never;
  tel?: never;
  sms?: never;
  facetime: string;
  href?: never;
}
type HrefProps = BaseProps &amp; {
  email?: never;
  tel?: never;
  sms?: never;
  facetime?: never;
  href: string;
}
<span class="hljs-keyword">export</span> type Props = EmailProps | TelProps | SmsProps | FacetimeProps | HrefProps;
<span class="hljs-keyword">const</span> props = Astro.props;
<span class="hljs-keyword">const</span> { id } = props;
<span class="hljs-comment">// Find the active prop (email, tel, sms, facetime, or href)</span>
<span class="hljs-keyword">const</span> activeProp = <span class="hljs-built_in">Object</span>.entries(props).find(<span class="hljs-function">(<span class="hljs-params">&#91;key, value]</span>) =&gt;</span> 
  key !== <span class="hljs-string">'id'</span> &amp;&amp; value !== <span class="hljs-literal">undefined</span>
);
<span class="hljs-keyword">let</span> attribute = <span class="hljs-string">''</span>;
<span class="hljs-keyword">let</span> value = <span class="hljs-string">''</span>;
<span class="hljs-keyword">if</span> (activeProp) {
  &#91;attribute, value] = activeProp;
  <span class="hljs-keyword">const</span> orgValue = value;
  value = Buffer.from(value).toString(<span class="hljs-string">'base64'</span>);
}
---

<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">obfuscate-link</span>
  <span class="hljs-attr">id</span>=<span class="hljs-string">{id}</span>
  {<span class="hljs-attr">...</span>{&#91;<span class="hljs-attr">attribute</span>]<span class="hljs-attr">:</span> <span class="hljs-attr">value</span>}}
&gt;</span><span class="hljs-tag">&lt;<span class="hljs-name">slot</span> /&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">obfuscate-link</span>&gt;</span></span></code></span></pre>


<p>Finally, you can utilize both the Astro component and the Web component throughout your Astro project.</p>


<pre class="wp-block-code"><span><code class="hljs language-javascript">
---
<span class="hljs-keyword">import</span> ObfuscateLink <span class="hljs-keyword">from</span> <span class="hljs-string">'./ObfuscateLink.astro'</span>;
---

<span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">class</span>=<span class="hljs-string">"card"</span>&gt;</span>
  <span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>
    Email: <span class="hljs-tag">&lt;<span class="hljs-name">ObfuscateLink</span> <span class="hljs-attr">email</span>=<span class="hljs-string">"info@example.com"</span> /&gt;</span>
  <span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span></span></code></span></pre>


<p>The complete code can be seen in this Gist: </p>



<p><a href="https://gist.github.com/ivoba/222d5a49ad4542392772195c5e5ad032" target="_blank" rel="noopener" title="">https://gist.github.com/ivoba/222d5a49ad4542392772195c5e5ad032</a></p>The post <a href="https://nerdpress.org/2025/02/07/obfuscatelink-web-component-in-astro/">ObfuscateLink Web Component in Astro</a> first appeared on <a href="https://nerdpress.org">Nerdpress.org</a>.]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Astro component for DarkMode Switcher for PicoCSS</title>
		<link>https://nerdpress.org/2024/01/07/astro-component-for-darkmode-switcher-for-picocss/</link>
		
		<dc:creator><![CDATA[Ivo Bathke]]></dc:creator>
		<pubDate>Sun, 07 Jan 2024 12:54:26 +0000</pubDate>
				<category><![CDATA[Astro]]></category>
		<category><![CDATA[PicoCSS]]></category>
		<guid isPermaLink="false">https://nerdpress.org/?p=3289</guid>

					<description><![CDATA[<p>I am currently evaluating PicoCss V2 in Astro project. PicoCss is a CSS / SCSS framework I used for some of my projects because it is small and brings sufficient styling for most HTML Elements. It has integrated light and dark mode, but no theme switcher. So i was looking for one and found this &#8230; </p>
<p class="link-more"><a href="https://nerdpress.org/2024/01/07/astro-component-for-darkmode-switcher-for-picocss/" class="more-link">Continue reading<span class="screen-reader-text"> "Astro component for DarkMode Switcher for PicoCSS"</span></a></p>
The post <a href="https://nerdpress.org/2024/01/07/astro-component-for-darkmode-switcher-for-picocss/">Astro component for DarkMode Switcher for PicoCSS</a> first appeared on <a href="https://nerdpress.org">Nerdpress.org</a>.]]></description>
										<content:encoded><![CDATA[<p>I am currently evaluating <a href="https://v2.picocss.com/" target="_blank" rel="noopener" title="">PicoCss V2</a> in <a href="https://astro.build/" target="_blank" rel="noopener" title="">Astro</a> project. PicoCss is a CSS / SCSS framework I used for some of my projects because it is small and brings sufficient styling for most HTML Elements. It has integrated light and dark mode, but no theme switcher. <br />So i was looking for one and found this one for Pico V1: <br /><a href="https://github.com/RWDevelopment/theme_switch" target="_blank" rel="noopener" title="">https://github.com/RWDevelopment/theme_switch</a></p>



<span id="more-3289"></span>



<p>I adjusted it to Pico V2 in a Astro component, ready to use in a Astro project with Pico V2 as CSS framework. <br />Since the component is just one file i just a made a gist: <a href="https://gist.github.com/ivoba/f3e0a8d7423faf318ce2217f5af9c510">https://gist.github.com/ivoba/f3e0a8d7423faf318ce2217f5af9c510</a></p>



<p>Here is how to use it, f.e. in your navigation:</p>


<pre class="wp-block-code"><span><code class="hljs language-javascript">---
<span class="hljs-keyword">import</span> ThemeSwitcher <span class="hljs-keyword">from</span> <span class="hljs-string">"./ThemeSwitcher.astro"</span>;
---

...
  
&lt;li&gt;
  <span class="xml"><span class="hljs-tag">&lt;<span class="hljs-name">ThemeSwitcher</span> /&gt;</span></span>
&lt;<span class="hljs-regexp">/li&gt;</span></code></span></pre>


<p><strong>Update:</strong><br />I added a persistence layer for localStorage to the Gist.<br />So the selected theme is remembered between pages.</p>The post <a href="https://nerdpress.org/2024/01/07/astro-component-for-darkmode-switcher-for-picocss/">Astro component for DarkMode Switcher for PicoCSS</a> first appeared on <a href="https://nerdpress.org">Nerdpress.org</a>.]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>Obfuscate Web Component</title>
		<link>https://nerdpress.org/2023/12/08/obfuscate-web-component/</link>
		
		<dc:creator><![CDATA[Ivo Bathke]]></dc:creator>
		<pubDate>Fri, 08 Dec 2023 17:21:01 +0000</pubDate>
				<category><![CDATA[Astro]]></category>
		<category><![CDATA[Web components]]></category>
		<guid isPermaLink="false">https://nerdpress.org/?p=3281</guid>

					<description><![CDATA[<p>Typically, when integrating emails into websites, I obfuscate the email address to prevent spam bots from collecting them. For React, there were already components that handled this task; however, without React, I couldn&#8217;t find a suitable solution. Therefore, I created a web component: obfuscate-wc that now provides an HTML element capable of obfuscating your email &#8230; </p>
<p class="link-more"><a href="https://nerdpress.org/2023/12/08/obfuscate-web-component/" class="more-link">Continue reading<span class="screen-reader-text"> "Obfuscate Web Component"</span></a></p>
The post <a href="https://nerdpress.org/2023/12/08/obfuscate-web-component/">Obfuscate Web Component</a> first appeared on <a href="https://nerdpress.org">Nerdpress.org</a>.]]></description>
										<content:encoded><![CDATA[<p>Typically, when integrating emails into websites, I obfuscate the email address to prevent spam bots from collecting them. For React, there were already components that handled this task; however, without React, I couldn&#8217;t find a suitable solution.</p>



<p>Therefore, I created a web component: <a href="https://github.com/ivoba/obfuscate-wc" target="_blank" rel="noopener" title="">obfuscate-wc</a> that now provides an HTML element capable of obfuscating your email (and some other contact data).</p>


<pre class="wp-block-code"><span><code class="hljs language-xml"> <span class="hljs-tag">&lt;<span class="hljs-name">obfuscate-link</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"obfuscate"</span> <span class="hljs-attr">email</span>=<span class="hljs-string">"aXZvQGxvY2FsLmRldg=="</span>&gt;</span>custom link<span class="hljs-tag">&lt;/<span class="hljs-name">obfuscate-link</span>&gt;</span></code></span></pre>


<span id="more-3281"></span>



<p>The component accepts an encoded email address, rendering it human-readable after events that typically align with human browsing behavior. <br />Custom decoders can be configured, with the default set to base64. <br />While sophisticated spam crawlers may still manage to decode the email, the likelihood decreases as you customize your encoder/decoder. It&#8217;s worth noting that the decoder could also be crawled, but the assumption is that this presents too much effort for the crawlers.</p>



<p>Using the web component itself is already blocking spammer that just look for mailto links.</p>



<p>How did I get there?</p>



<p>When using React I took this React component: <a href="https://github.com/coston/react-obfuscate" target="_blank" rel="noopener" title="">https://github.com/coston/react-obfuscate</a></p>



<p>In a new project, I began using <a href="https://astro.build/" target="_blank" rel="noopener" title="">Astro</a>, and React became unnecessary. However, I found myself missing the obfuscation component. Consequently, I chose to create a web component with similar functionality. This endeavor also served as a valuable exploration into web components. Web components, native to the browser, enable you to define your own HTML tags with specific functionality within the component.</p>



<p>Since the API of the web components is not the nicest, let&#8217;s say.<br />I took <a href="https://stenciljs.com/" target="_blank" rel="noopener" title="">StencilJs</a> which is a framework for Web Component development.<br />It also comes with nice tooling like Typescript support, tests and builds helpers.</p>



<p>I crafted it with Stencil, learned the process of building the component&#8211;admittedly, this was a bit cumbersome&#8211;but now it&#8217;s ready for use in any web application.</p>The post <a href="https://nerdpress.org/2023/12/08/obfuscate-web-component/">Obfuscate Web Component</a> first appeared on <a href="https://nerdpress.org">Nerdpress.org</a>.]]></content:encoded>
					
		
		
			</item>
		<item>
		<title>10 reasons to replace your CMS with Astro</title>
		<link>https://nerdpress.org/2023/03/23/10-reasons-to-replace-your-cms-with-astro/</link>
		
		<dc:creator><![CDATA[Ivo Bathke]]></dc:creator>
		<pubDate>Thu, 23 Mar 2023 16:45:57 +0000</pubDate>
				<category><![CDATA[Uncategorized]]></category>
		<category><![CDATA[Astro]]></category>
		<category><![CDATA[static site generator]]></category>
		<guid isPermaLink="false">https://nerdpress.org/?p=3234</guid>

					<description><![CDATA[<p>I replaced another CMS powered site with an Astro powered static site the other day.Here is why: This is based on of a twitter thread of mine and crossposted here for the sake of owning my content. :)</p>
The post <a href="https://nerdpress.org/2023/03/23/10-reasons-to-replace-your-cms-with-astro/">10 reasons to replace your CMS with Astro</a> first appeared on <a href="https://nerdpress.org">Nerdpress.org</a>.]]></description>
										<content:encoded><![CDATA[<p>I replaced another CMS powered site with an <a href="https://astro.build/" target="_blank" rel="noopener" title="">Astro</a> powered static site the other day.<br />Here is why:</p>



<span id="more-3234"></span>



<ol class="wp-block-list">
<li>Content changed rarely and when, authors forgot how to do it and asked me anyway.</li>



<li>Content is now part of development. <br />The &#8220;paid&#8221; support time is now rather spent for adding content than for helping the authors adding their content.<br />They will just send me an email.</li>



<li>Content is now versioned in git.</li>



<li>Hosting is cheaper, no need for the PHP Mysql package.</li>



<li>A static site is easier to host. No forced PHP updates by the hoster.</li>



<li>No security attack vectors on the site. Try this with WordPress ;)</li>



<li><a href="https://astro.build" target="_blank" rel="noopener" title="">Astro</a> comes with topnotch frontend tooling and green lighthouse audit by default. Try this with your CMS ;)</li>



<li>Contact forms are overrated. Mailto links work. If a contact form is your only dynamic requirement, ditch it and consider to go static.</li>



<li>A static site loads faster and does not need to run the compute cycles of a dynamic language or a database.</li>



<li>Last but not least: A static site presumably has a lower carbon footprint out of the box because of less computing and optimized frontend tooling.</li>
</ol>



<p>This is based on of a <a href="https://twitter.com/ivobathke/status/1632665077307305986" target="_blank" rel="noopener" title="">twitter thread</a> of mine and crossposted here for the sake of owning my content. :)</p>The post <a href="https://nerdpress.org/2023/03/23/10-reasons-to-replace-your-cms-with-astro/">10 reasons to replace your CMS with Astro</a> first appeared on <a href="https://nerdpress.org">Nerdpress.org</a>.]]></content:encoded>
					
		
		
			</item>
	</channel>
</rss>
