301 status code means that the requested resource has been permanently moved to a new URL. All future requests should use the new address.
The browser will automatically redirect the user to the new address, and search engines will update their indexes.
200 status code is a standard successful HTTP server response. It means that the client’s request (e.g., from a browser) was successfully processed, and the server is delivering the requested data.
The user receives content without errors, and the page or application functions properly. If Code 200 is accompanied by data, the browser or program processes and displays it to the user.
GET / HTTP/1.1 Host: asuh.com Accept: */* User-Agent: Mozilla/5.0 AppleWebKit/537.36 (KHTML, like Gecko; compatible; ClaudeBot/1.0; [email protected])
<!DOCTYPE html> <html lang="en-US"> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>asuh.com | change is inevitable</title> <meta name='robots' content='noindex, nofollow' /> <style>img:is([sizes="auto" i], [sizes^="auto," i]) { contain-intrinsic-size: 3000px 1500px }</style> <!-- The SEO Framework by Sybre Waaijer --> <link rel="canonical" href="https://asuh.com/" /> <link rel="next" href="https://asuh.com/page/2/" /> <meta name="description" content="change is inevitable" /> <meta property="og:type" content="website" /> <meta property="og:locale" content="en_US" /> <meta property="og:site_name" content="asuh.com" /> <meta property="og:title" content="asuh.com | change is inevitable" /> <meta property="og:description" content="change is inevitable" /> <meta property="og:url" content="https://asuh.com/" /> <meta name="twitter:card" content="summary_large_image" /> <meta name="twitter:site" content="@asuh" /> <meta name="twitter:title" content="asuh.com | change is inevitable" /> <meta name="twitter:description" content="change is inevitable" /> <script type="application/ld+json">{"@context":"https://schema.org","@graph":[{"@type":"WebSite","@id":"https://asuh.com/#/schema/WebSite","url":"https://asuh.com/","name":"asuh.com","description":"change is inevitable","inLanguage":"en-US","potentialAction":{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https://asuh.com/search/{search_term_string}/"},"query-input":"required name=search_term_string"},"publisher":{"@id":"https://asuh.com/#/schema/Organization"}},{"@type":"WebPage","@id":"https://asuh.com/","url":"https://asuh.com/","name":"asuh.com | change is inevitable","description":"change is inevitable","inLanguage":"en-US","isPartOf":{"@id":"https://asuh.com/#/schema/WebSite"},"breadcrumb":{"@type":"BreadcrumbList","@id":"https://asuh.com/#/schema/BreadcrumbList","itemListElement":{"@type":"ListItem","position":1,"name":"asuh.com"}},"about":{"@id":"https://asuh.com/#/schema/Organization"}},{"@type":"Organization","@id":"https://asuh.com/#/schema/Organization","name":"asuh.com","url":"https://asuh.com/"}]}</script> <!-- / The SEO Framework by Sybre Waaijer | 15.18ms meta | 5.32ms boot --> <link rel="alternate" type="application/rss+xml" title="asuh.com » Feed" href="https://asuh.com/feed/" /> <link rel="stylesheet" href="/wp/wp-content/mmr/fd5264f7-1747154968.min.css"><style id='akismet-widget-style-inline-css' type='text/css'> .a-stats { --akismet-color-mid-green: #357b49; --akismet-color-white: #fff; --akismet-color-light-grey: #f6f7f7; max-width: 350px; width: auto; } .a-stats * { all: unset; box-sizing: border-box; } .a-stats strong { font-weight: 600; } .a-stats a.a-stats__link, .a-stats a.a-stats__link:visited, .a-stats a.a-stats__link:active { background: var(--akismet-color-mid-green); border: none; box-shadow: none; border-radius: 8px; color: var(--akismet-color-white); cursor: pointer; display: block; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen-Sans', 'Ubuntu', 'Cantarell', 'Helvetica Neue', sans-serif; font-weight: 500; padding: 12px; text-align: center; text-decoration: none; transition: all 0.2s ease; } /* Extra specificity to deal with TwentyTwentyOne focus style */ .widget .a-stats a.a-stats__link:focus { background: var(--akismet-color-mid-green); color: var(--akismet-color-white); text-decoration: none; } .a-stats a.a-stats__link:hover { filter: brightness(110%); box-shadow: 0 4px 12px rgba(0, 0, 0, 0.06), 0 0 2px rgba(0, 0, 0, 0.16); } .a-stats .count { color: var(--akismet-color-white); display: block; font-size: 1.5em; line-height: 1.4; padding: 0 13px; white-space: nowrap; } </style> <link rel="stylesheet" href="/wp/wp-content/mmr/55fe079a-1740171417.min.css"><script src="/wp/wp-content/mmr/538d0768-1724856854.min.js"></script> <style type="text/css"> ol.footnotes>li {list-style-type:decimal;} ol.footnotes { color:#666666; } ol.footnotes li { font-size:80%; } </style> <link rel="indieauth-metadata" href="https://asuh.com/wp-json/indieauth/1.0/metadata" /> <link rel="authorization_endpoint" href="https://asuh.com/wp-json/indieauth/1.0/auth" /> <link rel="token_endpoint" href="https://asuh.com/wp-json/indieauth/1.0/token" /> <link rel="friends-base-url" href="https://asuh.com/wp-json/friends/v1" /> <link rel="me" href="https://github.com/asuh" /> <link rel="me" href="https://twitter.com/asuh" /> <link rel="me" href="https://www.facebook.com/micasuh" /> <link rel="me" href="https://www.instagram.com/micasuh" /> <link rel="me" href="https://www.flickr.com/people/asuh" /> <link rel="me" href="https://bsky.app/profile/asuh.com" /> <link rel="me" href="https://reddit.com/user/asuh" /> <link rel="me" href="https://mastodon.social/@asuh" /> <script>var _activityPubOptions = {"namespace":"activitypub\/1.0","defaultAvatarUrl":"https:\/\/asuh.com\/wp\/wp-content\/plugins\/activitypub\/assets\/img\/mp.jpg","enabled":{"site":false,"users":true}};</script><link rel="micropub_media" href="https://asuh.com/wp-json/micropub/1.0/media" /> <link rel="micropub" href="https://asuh.com/wp-json/micropub/1.0/endpoint" /> <meta name="fediverse:creator" content="@[email protected]"> </head> <body class="home blog wp-embed-responsive wp-theme-forageresources"> <a class="visuallyhidden" href="#main"> Skip to content </a> <header class="banner"> <h1 class="site-title"><a class="brand u-url" href="https://asuh.com/">asuh.com</a></h1> <nav class="nav-primary" aria-label="Primary Navigation"> <button class="toggle-button" type="button" aria-expanded="false" aria-controls="nav-primary">Menu</button> <ul id="nav-primary" class="nav-list"><li class="active menu-item menu-home"><a href="https://asuh.com/" aria-current="page">home</a></li> <li class="menu-item menu-about"><a href="https://asuh.com/about/">about</a></li> <li class="menu-item menu-work"><a href="https://asuh.com/work/">work</a></li> <li class="menu-item menu-tech"><a href="https://asuh.com/tech/">tech</a></li> <li class="menu-item menu-contact"><a href="https://asuh.com/contact/">contact</a></li> </ul> </nav> </header> <div class="h-card vcard"> <a class="u-url u-uid" rel="author" href="https://asuh.com/"> <img alt='' src='https://secure.gravatar.com/avatar/c10a787bcb536f8ee912c6ee5cf20b0a46063dd4bf825b60f6471cece699fcef?s=96&d=mm&r=x' srcset='https://secure.gravatar.com/avatar/c10a787bcb536f8ee912c6ee5cf20b0a46063dd4bf825b60f6471cece699fcef?s=192&d=mm&r=x 2x' class='avatar avatar-96 photo u-photo' height='96' width='96' loading='lazy' decoding='async'/> <span class="p-name fn"> <span class="p-given-name">Micah</span> <span class="screen-reader-text p-family-name">Cambre</span> </span> </a> </div> <main class="main" id="main"> <article class="post-2397 post type-post status-publish format-standard category-asuhcom category-personal kind-article h-entry hentry"> <header class="post-header"> <h2 class="entry-title"><a class="p-name u-url" href="https://asuh.com/thinking/">thinking…</a></h2> </header> <div class="main-content e-content"> <p>If you’re seeing this, you’re subscribed to the RSS feed or you’ve figured out how to see into my archives.</p> <p><del datetime="2025-04-02T19:04:40+00:00">Today, I added a mostly blank <code class="language-html">index.html</code> file on asuh.com so that this post isn’t directly accessible on the homepage.</del></p> <p>UPDATE 04/2025: I took the file down, still thinking…</p> <p>I need to think about the value of this site as a personal vessel of data. Part of me is ready to wipe a lot of my digital presence from existence since everything here is basically used to train all the immoral AI and populate LLMs from these companies who didn’t ask for my permission.</p> <p>I don’t know what I’ll do next. I’m slowly deleting old accounts and data from other online places since it’s unnecessary for them to exist.</p> <p>I’m not finding joy in writing publicly, either. It’s personal and public documentation, maybe others benefit from time to time, but ultimately it’s my personal value that mainly benefits me.</p> <p>Let’s see how I feel in the coming days and weeks.</p> </div><!-- .main-content --> <div class="entry-meta"> <span class="posted-on"> <a class="u-url" href="https://asuh.com/thinking/"> <svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" class="hyperlink" viewBox="0 0 32 32"><path fill="currentColor" d="M13.8 19.9a1.6 1.6 0 0 1-1.2-.5c-3-3-3-7.8 0-10.8l6-6a7.6 7.6 0 0 1 10.8 0c3 3 3 7.8 0 10.8L26.6 16a1.6 1.6 0 1 1-2.2-2.3l2.7-2.7a4.4 4.4 0 0 0 0-6.2 4.3 4.3 0 0 0-6.2 0l-6 6a4.4 4.4 0 0 0 0 6.2 1.6 1.6 0 0 1-1.1 2.8z"/><path fill="currentColor" d="M8 31.6a7.6 7.6 0 0 1-5.4-2.2c-3-3-3-7.8 0-10.8L5.4 16a1.6 1.6 0 1 1 2.2 2.3L5 20.9a4.4 4.4 0 0 0 0 6.2 4.3 4.3 0 0 0 6.2 0l6-6a4.4 4.4 0 0 0 0-6.2 1.6 1.6 0 1 1 2.3-2.3c3 3 3 7.8 0 10.8l-6 6A7.6 7.6 0 0 1 8 31.6z"/></svg><time class="entry-date dt-published" datetime="2025-02-02T09:03:02-08:00"><span class="date-month-day">February 2nd</span> <span class="date-year">2025</span></time> </a> </span> <span class="comments-link"> </span> </div><!-- .entry-meta --> </article> <article class="post-2355 post type-post status-publish format-standard category-portfolio category-web-development kind-article h-entry hentry"> <header class="post-header"> <h2 class="entry-title"><a class="p-name u-url" href="https://asuh.com/defensive-fetch-response/">defensive fetch response</a></h2> </header> <div class="main-content e-content"> <p>In 2023, while deep in the trenches of my engineering manager role, I decided to purchase a license to access <a href="https://react.gg/">react.gg, “The interactive way to master modern React”</a>. I followed <a href="https://ui.dev/">ui.dev</a> team’s work for the last few years, and they often released material that’s been quite helpful to learn <a href="https://react.dev/">React</a> and <a href="https://javascript.info/">modern Javascript</a>. This course is just another perspective for brushing up on what I know and pushing myself to learn more.</p> <p>In the course, I came across a comment reply made showing a good way to use <a href="https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch"><code class="language-">fetch()</code></a>. The following was initially asked:</p> <blockquote><p>I am flummoxed by the assertion that this code is not wise:</p> <pre><code class="language-javascript">function getGithubProfile(username) { return fetch( `https://api.github.com/users/${username}` ).then((res) => res.json()); }</code></pre> <p>What is the correct way to obtain data from an external source? In other languages, I’ve been using functions for decades to retrieve data from external sources.</p></blockquote> <p>His response included a defensive approach to fetching data:</p> <pre><code class="language-javascript line-numbers">async function getGithubProfile(username) { let response; try { response = await fetch(`https://api.github.com/users/${username}`); } catch (error) { throw new Error(`Network error: ${error.message}`); } if (!response.ok) { const message = `HTTP error! status: ${response.status}`; throw new Error(message); } let data; try { data = await response.json(); } catch (error) { throw new Error(`API response error: ${error.message}`); } if (!data || typeof data !== 'object') { throw new Error('Invalid response format from the API'); } return data; }</code></pre> <p>While I’ve used and seen plenty of snippets from this function in various places, this was the first time I saw it constructed like this. Using fetch like this is one of a few ways that this function could be written, but it’s also very readable and easy to understand.</p> <p>Here are the four things this structure is doing:</p> <ol> <li>Using asynchronous code to fetch data and return a Promise using <code class="language-js">async/await</code></li> <li>Using <code class="language-js">try...catch</code> statement to allow the fetch and catch responses or error</li> <li>Throw errors for Network issues, response status issues, API issues, or response formatting issues</li> <li>Safely returns the data fetched from the URL or API</li> </ol> <p>Now, let me attempt to destructure this defensive code block.</p> <h2>try…catch</h2> <p>First, we need to fetch some data, so we’ll access an external URL, this example from Github.</p> <pre data-line="1-6"><code class="language-javascript line-numbers">async function getGithubProfile(username) { let response; try { response = await fetch(`https://api.github.com/users/${username}`); } catch (error) { throw new Error(`Network error: ${error.message}`); } /* more code below */ }</code></pre> <p>First, we declare a variable called <code class="language-js">response</code> that’ll be referenced and reassigned throughout the function. This might seem kind of redundant considering it’s called almost immediately inside of the <code class="language-js">try</code> block. Interestingly enough, <a href="https://developer.mozilla.org/en-US/docs/Glossary/Scope">we have to declare <code class="language-js">response</code> outside of the <code class="language-js">try</code> block because of block scoping</a>, which applies to using <code class="language-js">const</code> and <code class="language-js">let</code>. If we declared <code class="language-js">var response</code> inside of <code class="language-js">try {}</code>, because of <a href="https://developer.mozilla.org/en-US/docs/Glossary/Hoisting">hoisting</a>, it would actually work in the function. <a href="https://youtu.be/Ppj0j-5v0Qg">Theo (t3.gg) made a video going more in depth about the constraints of the <code class="language-js">try</code> block</a>.</p> <p>The first call of <code class="language-js">response</code> is in the above referenced <code class="language-js">try...catch</code> syntax construct containing the code to fetch the data or return a network error. Using both <code class="language-js">async</code> to convert the function to be asynchronous Promise as well as the <code class="language-js">await</code> expression to suspend execution until the returned promise is fulfilled or rejected is one of the best modern features of Javascript. If the response does not work properly, an error will display to let the user know there’s an issue.</p> <h2>validate the data</h2> <p>Before we even work continue to work with a response containing data, let’s make sure the fetch request was okay by <a href="https://developer.mozilla.org/en-US/docs/Web/API/Response/status">returning a HTTP status code</a> of 200, representing a successful response.</p> <pre data-line="3-6"><code class="language-javascript line-numbers">async function getGithubProfile(username) { /* fetch the data */ if (!response.ok) { const message = `HTTP error! status: ${response.status}`; throw new Error(message); } /* more code below */ }</code></pre> <p>If the response was anything but okay, this conditional will throw an error with the status code.</p> <h2>json the data</h2> <p>Time to convert the response to a readable format for Javascript</p> <pre data-line="5-10"><code class="language-javascript line-numbers">async function getGithubProfile(username) { /* fetch the data */ /* response validation */ let data; try { data = await response.json(); } catch (error) { throw new Error(`API response error: ${error.message}`); } /* more code below */ }</code></pre> <p>After setting a new variable for the data, we resolve the <a href="https://developer.mozilla.org/en-US/docs/Web/API/Response/json">response to a JavaScript object. This object could be anything that can be represented by JSON — an object, an array, a string, a number, etc.</a> Now the fetched data is ready to be used by javascript. </p> <p>On the other hand, if there’s an error with the returned data for any reason, such as malformed JSON, it’ll once again throw a new error.</p> <p><em>Note: It’s also here that you might need a different resolve type. For example, there are cases where you’re working with a string response that isn’t or doesn’t need to be JSON formatted data. In that case, your response could be returned using <code class="language-js">await response.text()</code> to return a string. There are several other method types that can be applied here as well.</em></p> <h2>type validation</h2> <p>What happens if we get through everything but the data itself doesn’t actually resolve to a valid object or the data is just plain corrupt? This is an often forgotten step in fetching data where we should do one last check to make sure we’re actually returning a valid data type, object in our case, or just making sure the data is still available. If not, throw an API error.</p> <pre data-line="7-9"><code class="language-javascript line-numbers">async function getGithubProfile(username) { /* fetch the data */ /* response validation */ /* resolve data type */ if (!data || typeof data !== 'object') { throw new Error('Invalid response format from the API'); } /* more code below */ }</code></pre> <h2>return the data</h2> <p>At this point, the data has survived multiple check stops to make sure the result of the data is exactly what we need. So, all we have to do is return the data.</p> <pre><code class="language-js">return data;</code></pre> <p>Voila! Now we have a fully functioning and very safe function to fetch data for our site or application. </p> <p>For React, this type of function can either stand alone outside of a component to be invoked in the Component, or it can also exist directly in <code class="language-js">React.useEffect()</code> to grab the data when the component mounts or updates based on a state change.</p> <h2>fetch promise</h2> <p>By default, <code class="language-javascript">fetch()</code> is really a promise, allowing you to cover a lot of these checks that are located inside of the multiple <code class="language-js">try...catch</code> blocks. Here’s an alternative syntax, often referred to as <code class="language-javascript">then/catch</code> for fetching:</p> <pre><code class="language-js">fetch('https://api.github.com/users/${username}') .then((response) => { if (response.ok) { return response.json(); } else { throw 'Error getting users list' } }).then((data) => { /* handle data */ }).catch((error) => { /* handle errors */ });</code></pre> <p>Both methods are Promise chains, both handle responses and errors in similar ways. There’s nothing wrong with using the above, it’s perfectly valid! Why use <code class="language-js">try...catch</code> over <code class="language-javascript">then/catch</code> built-in promise syntax? </p> <p>The primary difference is the addition of the <code class="language-javascript">async/await</code> in ES2017. Ultimately, using this syntax offers a cleaner to read, easier to understand method to retrieve the data. There’s no nesting of <code class="language-javascript">then/catch</code> methods, which can be common in <code class="language-javascript">then/catch</code> blocks.</p> <p><a href="https://www.smashingmagazine.com/2020/11/comparison-async-await-versus-then-catch/">Here’s a great Smashing Magazine article going over examples between <code class="language-js">try...catch</code> over <code class="language-javascript">then/catch</code></a>.</p> <p>Happy fetching!</p> <h4>Updates</h4> <ul> <li>August 14, 2024 – Added additional context around the <code class="language-js">try</code> block and a video link to YouTube</li> </ul> </div><!-- .main-content --> <div class="entry-meta"> <span class="posted-on"> <a class="u-url" href="https://asuh.com/defensive-fetch-response/"> <svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" class="hyperlink" viewBox="0 0 32 32"><path fill="currentColor" d="M13.8 19.9a1.6 1.6 0 0 1-1.2-.5c-3-3-3-7.8 0-10.8l6-6a7.6 7.6 0 0 1 10.8 0c3 3 3 7.8 0 10.8L26.6 16a1.6 1.6 0 1 1-2.2-2.3l2.7-2.7a4.4 4.4 0 0 0 0-6.2 4.3 4.3 0 0 0-6.2 0l-6 6a4.4 4.4 0 0 0 0 6.2 1.6 1.6 0 0 1-1.1 2.8z"/><path fill="currentColor" d="M8 31.6a7.6 7.6 0 0 1-5.4-2.2c-3-3-3-7.8 0-10.8L5.4 16a1.6 1.6 0 1 1 2.2 2.3L5 20.9a4.4 4.4 0 0 0 0 6.2 4.3 4.3 0 0 0 6.2 0l6-6a4.4 4.4 0 0 0 0-6.2 1.6 1.6 0 1 1 2.3-2.3c3 3 3 7.8 0 10.8l-6 6A7.6 7.6 0 0 1 8 31.6z"/></svg><time class="entry-date dt-published" datetime="2024-08-07T17:53:23-07:00"><span class="date-month-day">August 7th</span> <span class="date-year">2024</span></time> </a> </span> <span class="comments-link"> </span> </div><!-- .entry-meta --> </article> <article class="post-2326 post type-post status-publish format-standard category-personal category-portfolio category-web-development kind-article h-entry hentry"> <header class="post-header"> <h2 class="entry-title"><a class="p-name u-url" href="https://asuh.com/popover-modals/">all in on popover modals</a></h2> </header> <div class="main-content e-content"> <p>Let’s talk about the new popover feature added to HTML. I decided to create a few versions of a modal that contains a search form, just to both get experience as well as prove that this is a good new use of a popover. I am biased but I’m completely on board!</p> <p>Because responsive websites have so many features that need to work from small to large devices, sometimes we have to make decisions that universally provide necessary features but don’t add too much complexity for users. One of those is a search field that can fit on all devices, and it’s this feature that led me in the direction of a modal.</p> <p>Yeah, I know, modals are overused. They distract from the main content, take focus away from the important parts of site. However, adding a search form to a modal provides a much used feature with minimal impact on mobile layout structure, allowing for more components in a small area.</p> <figure id="attachment_2328" aria-describedby="caption-attachment-2328" style="width: 358px" class="wp-caption alignnone"><img decoding="async" class="size-full wp-image-2328" src="/wp/wp-content/uploads/2024/08/mobile-header.webp" alt="Screenshot of mobile header for stopthethyroidmadness.com" width="358" height="71" srcset="/wp/wp-content/uploads/2024/08/mobile-header.webp 358w, /wp/wp-content/uploads/2024/08/mobile-header-300x59.webp 300w" sizes="(max-width: 358px) 100vw, 358px" /><figcaption id="caption-attachment-2328" class="wp-caption-text">This is an example of a search component on a mobile sized device with a minimal footprint</figcaption></figure> <p>To activate the search form, the magnifying glass icon is a button and requires to be pressed or tapped. A search form appears inside of a modal that overlays the screen, blurring the background.</p> <figure id="attachment_2336" aria-describedby="caption-attachment-2336" style="width: 352px" class="wp-caption alignnone"><img fetchpriority="high" decoding="async" class="size-full wp-image-2336" src="/wp/wp-content/uploads/2024/08/mobile-search-open.webp" alt="Screenshot of mobile search modal that's open on stopthethyroidmadness.com" width="352" height="285" srcset="/wp/wp-content/uploads/2024/08/mobile-search-open.webp 352w, /wp/wp-content/uploads/2024/08/mobile-search-open-300x243.webp 300w" sizes="(max-width: 352px) 100vw, 352px" /><figcaption id="caption-attachment-2336" class="wp-caption-text">The search form appears in a modal on top of the content</figcaption></figure> <p>Since spring of 2024, we have a new feature of HTML, using an attribute, called <a href="https://web.dev/blog/popover-api"><code class="language-html">popover</code></a>. This new addition to the language provides some really great superpowers:</p> <ul> <li>No javascript required!</li> <li>Automatic overlay, highest z-index</li> <li>Light dismiss (clicking/tapping outside of the popover element)</li> <li>Default focus management</li> <li>Keyboard binding for improved accessibility support</li> <li>Support for <code class="language-html">::backfill</code> pseudo element (wanna blur the background without extra code!)</li> </ul> <p>If I was talking to my 2000s web designer self, he would describe this as magic! Because, well, it really is so simple and easy.</p> <p>Here’s a CodePen of my first version of this:</p> <p><iframe allowfullscreen="true" allowpaymentrequest="true" allowtransparency="true" class="cp_embed_iframe" frameborder="0" height="500" name="cp_embed_1" scrolling="no" src="https://codepen.io/asuh/embed/jOojyJB?height=500&theme-id=0&slug-hash=jOojyJB&default-tab=result&animations=run&editable=&embed-version=2&user=asuh&name=cp_embed_1" style="width: 100%; overflow:hidden; display:block;" title="CodePen Embed" loading="lazy" id="cp_embed_'jOojyJB'"></iframe></p> <p>The best thing about the above component is that you can try it out on all the modern browsers with success… unless you’re using Safari on iOS. With the help of <a href="https://mastodon.social/@[email protected]/112825745581748393">Luke Warlow</a>, he found and <a href="https://bugs.webkit.org/show_bug.cgi?id=276864">reported a Webkit bug that the light dismiss behavior doesn’t work</a>.</p> <p>Because of the above bug, in order to have universal support, I created another version that includes a button inside of the popover that mostly duplicates the button trigger that opens the popover, but instead this one closes and dismisses the popover.</p> <p><iframe allowfullscreen="true" allowpaymentrequest="true" allowtransparency="true" class="cp_embed_iframe" frameborder="0" height="500" name="cp_embed_1" scrolling="no" src="https://codepen.io/asuh/embed/RwzoWMY?height=500&theme-id=0&slug-hash=RwzoWMY&default-tab=result&animations=run&editable=&embed-version=2&user=asuh&name=cp_embed_1" style="width: 100%; overflow:hidden; display:block;" title="CodePen Embed" loading="lazy" id="cp_embed_'jOojyJB'"></iframe></p> <p>Just to fun, I took one more try at making a version that uses the <code class="language-html">dialog</code> element, which has been available since 2022. The main reason I did not go this route was to attempt a new, accessible element with no javascript. Buttons that open dialogs have at least one inline <code class="language-javascripot">onclick="dialog.showModal()"</code> attribute that’s required for the dialog to appear. Adding light dismiss also requires a little script, as you can see in the CodePen example. Additionally, the dialogs don’t need any additional code for focus to just work right, which is very nice.</p> <p><iframe allowfullscreen="true" allowpaymentrequest="true" allowtransparency="true" class="cp_embed_iframe" frameborder="0" height="500" name="cp_embed_1" scrolling="no" src="https://codepen.io/asuh/embed/YzoZNEV?height=500&theme-id=0&slug-hash=YzoZNEV&default-tab=result&animations=run&editable=&embed-version=2&user=asuh&name=cp_embed_1" style="width: 100%; overflow:hidden; display:block;" title="CodePen Embed" loading="lazy" id="cp_embed_'jOojyJB'"></iframe></p> <p>You have your choice in these examples so feel free to borrow or steal whatever you want!</p> </div><!-- .main-content --> <div class="entry-meta"> <span class="posted-on"> <a class="u-url" href="https://asuh.com/popover-modals/"> <svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" class="hyperlink" viewBox="0 0 32 32"><path fill="currentColor" d="M13.8 19.9a1.6 1.6 0 0 1-1.2-.5c-3-3-3-7.8 0-10.8l6-6a7.6 7.6 0 0 1 10.8 0c3 3 3 7.8 0 10.8L26.6 16a1.6 1.6 0 1 1-2.2-2.3l2.7-2.7a4.4 4.4 0 0 0 0-6.2 4.3 4.3 0 0 0-6.2 0l-6 6a4.4 4.4 0 0 0 0 6.2 1.6 1.6 0 0 1-1.1 2.8z"/><path fill="currentColor" d="M8 31.6a7.6 7.6 0 0 1-5.4-2.2c-3-3-3-7.8 0-10.8L5.4 16a1.6 1.6 0 1 1 2.2 2.3L5 20.9a4.4 4.4 0 0 0 0 6.2 4.3 4.3 0 0 0 6.2 0l6-6a4.4 4.4 0 0 0 0-6.2 1.6 1.6 0 1 1 2.3-2.3c3 3 3 7.8 0 10.8l-6 6A7.6 7.6 0 0 1 8 31.6z"/></svg><time class="entry-date dt-published" datetime="2024-08-01T12:09:36-07:00"><span class="date-month-day">August 1st</span> <span class="date-year">2024</span></time> </a> </span> <span class="comments-link"> </span> <ul class="relsyn"><li><a aria-label="mastodon" class="u-syndication syn-link" href="https://mastodon.social/@asuh/112888354584048794"> <span class="syndication-link-icon svg-mastodon" style="display: inline-block; max-width: 1rem; margin: 2px;" aria-hidden="true" aria-label="Mastodon" title="Mastodon" ><svg role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><title>Mastodon</title><path d="M23.268 5.313c-.35-2.578-2.617-4.61-5.304-5.004C17.51.242 15.792 0 11.813 0h-.03c-3.98 0-4.835.242-5.288.309C3.882.692 1.496 2.518.917 5.127.64 6.412.61 7.837.661 9.143c.074 1.874.088 3.745.26 5.611.118 1.24.325 2.47.62 3.68.55 2.237 2.777 4.098 4.96 4.857 2.336.792 4.849.923 7.256.38.265-.061.527-.132.786-.213.585-.184 1.27-.39 1.774-.753a.057.057 0 0 0 .023-.043v-1.809a.052.052 0 0 0-.02-.041.053.053 0 0 0-.046-.01 20.282 20.282 0 0 1-4.709.545c-2.73 0-3.463-1.284-3.674-1.818a5.593 5.593 0 0 1-.319-1.433.053.053 0 0 1 .066-.054c1.517.363 3.072.546 4.632.546.376 0 .75 0 1.125-.01 1.57-.044 3.224-.124 4.768-.422.038-.008.077-.015.11-.024 2.435-.464 4.753-1.92 4.989-5.604.008-.145.03-1.52.03-1.67.002-.512.167-3.63-.024-5.545zm-3.748 9.195h-2.561V8.29c0-1.309-.55-1.976-1.67-1.976-1.23 0-1.846.79-1.846 2.35v3.403h-2.546V8.663c0-1.56-.617-2.35-1.848-2.35-1.112 0-1.668.668-1.67 1.977v6.218H4.822V8.102c0-1.31.337-2.35 1.011-3.12.696-.77 1.608-1.164 2.74-1.164 1.311 0 2.302.5 2.962 1.498l.638 1.06.638-1.06c.66-.999 1.65-1.498 2.96-1.498 1.13 0 2.043.395 2.74 1.164.675.77 1.012 1.81 1.012 3.12z"/></svg></span></a></li><li><a aria-label="bluesky" class="u-syndication syn-link" href="https://bsky.app/profile/asuh.com/post/3kyok5ifm2w2y"> <span class="syndication-link-icon svg-bluesky" style="display: inline-block; max-width: 1rem; margin: 2px;" aria-hidden="true" aria-label="Bluesky" title="Bluesky" ><svg role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><title>Bluesky</title><path d="M12 10.8c-1.087-2.114-4.046-6.053-6.798-7.995C2.566.944 1.561 1.266.902 1.565.139 1.908 0 3.08 0 3.768c0 .69.378 5.65.624 6.479.815 2.736 3.713 3.66 6.383 3.364.136-.02.275-.039.415-.056-.138.022-.276.04-.415.056-3.912.58-7.387 2.005-2.83 7.078 5.013 5.19 6.87-1.113 7.823-4.308.953 3.195 2.05 9.271 7.733 4.308 4.267-4.308 1.172-6.498-2.74-7.078a8.741 8.741 0 0 1-.415-.056c.14.017.279.036.415.056 2.67.297 5.568-.628 6.383-3.364.246-.828.624-5.79.624-6.478 0-.69-.139-1.861-.902-2.206-.659-.298-1.664-.62-4.3 1.24C16.046 4.748 13.087 8.687 12 10.8Z"/></svg></span></a></li></ul> </div><!-- .entry-meta --> </article> <article class="post-2310 post type-post status-publish format-standard category-web-development tag-css tag-safari kind-article h-entry hentry"> <header class="post-header"> <h2 class="entry-title"><a class="p-name u-url" href="https://asuh.com/come-on-safari/">come on, safari</a></h2> </header> <div class="main-content e-content"> <p>I’m nearing the end of the first phase of a website redesign, teaching myself new CSS, and sprinkling in some JS. Of the things I’m learning, I’m also rediscovering some old Safari linear-gradient issues and seeing some new Safari positioning bugs.</p> <p>You can follow along if you view <a href="https://codepen.io/asuh/pen/LYKRJYg">the CodePen titled “color-scheme, light-dark, Safari bug”</a>.</p> <p>The original point of the above pen is to verify linear gradient issues with Safari.</p> <p>Webkit-based linear-gradient issues are <a href="https://stackoverflow.com/questions/38391457/linear-gradient-to-transparent-bug-in-latest-safari">well documented</a>, they behave differently because of the <code class="language-css">transparent</code> color values. You can see this by switching the theme mode from light to dark, or dark to light. I keep running into linear gradient issues in Safari because I infrequently use them with transparent values and forget they’re still an issue.</p> <figure id="attachment_2313" aria-describedby="caption-attachment-2313" style="width: 1024px" class="wp-caption aligncenter"><img decoding="async" class="wp-image-2313 size-large" src="/wp/wp-content/uploads/2024/07/safari-dark-mode-switch-1024x567.webp" alt="CodePen screenshot after switching pen from light mode to dark mode, showing linear gradients that are not ideal" width="1024" height="567" srcset="/wp/wp-content/uploads/2024/07/safari-dark-mode-switch-1024x567.webp 1024w, /wp/wp-content/uploads/2024/07/safari-dark-mode-switch-300x166.webp 300w, /wp/wp-content/uploads/2024/07/safari-dark-mode-switch-768x425.webp 768w, /wp/wp-content/uploads/2024/07/safari-dark-mode-switch.webp 1050w" sizes="(max-width: 1024px) 100vw, 1024px" /><figcaption id="caption-attachment-2313" class="wp-caption-text">CodePen screenshot after switching the theme mode from light to dark, showing linear gradients that are not ideal. It also shows that the aspect ratio isn’t a square as it should be.</figcaption></figure> <p>Try the above pen in Firefox or any Chromium browser and the linear gradients are consistently working when switching between dark and light mode.</p> <p>I found 3 more issues having created this:</p> <ol> <li>In <code class="language-css">.square</code>, Webkit doesn’t seem to center things consistently using just <code class="language-css">place-items: center</code>. I am forced to add <code class="language-css">place-content: center</code> to make the content “<em>this is a square</em>” center consistently with the other modern browsers</li> <li><code class="language-css">aspect-radio: 1 / 1</code> doesn’t actually work right for the content area of <code class="language-css">.square</code>. It’s elongated into a rectangle.</li> <li>Adding <code class="language-css">position: fixed</code> to <code class="language-css">.square</code>, which is already centered using the <code class="language-css">place-*</code> rules breaks the positioning only on Webkit. I am forced to use older positioning methods, i.e. <code class="language-css">left</code>, <code class="language-css">top</code>, and <code class="language-css">transform</code>.</li> </ol> </div><!-- .main-content --> <div class="entry-meta"> <span class="posted-on"> <a class="u-url" href="https://asuh.com/come-on-safari/"> <svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" class="hyperlink" viewBox="0 0 32 32"><path fill="currentColor" d="M13.8 19.9a1.6 1.6 0 0 1-1.2-.5c-3-3-3-7.8 0-10.8l6-6a7.6 7.6 0 0 1 10.8 0c3 3 3 7.8 0 10.8L26.6 16a1.6 1.6 0 1 1-2.2-2.3l2.7-2.7a4.4 4.4 0 0 0 0-6.2 4.3 4.3 0 0 0-6.2 0l-6 6a4.4 4.4 0 0 0 0 6.2 1.6 1.6 0 0 1-1.1 2.8z"/><path fill="currentColor" d="M8 31.6a7.6 7.6 0 0 1-5.4-2.2c-3-3-3-7.8 0-10.8L5.4 16a1.6 1.6 0 1 1 2.2 2.3L5 20.9a4.4 4.4 0 0 0 0 6.2 4.3 4.3 0 0 0 6.2 0l6-6a4.4 4.4 0 0 0 0-6.2 1.6 1.6 0 1 1 2.3-2.3c3 3 3 7.8 0 10.8l-6 6A7.6 7.6 0 0 1 8 31.6z"/></svg><time class="entry-date dt-published" datetime="2024-07-25T11:12:16-07:00"><span class="date-month-day">July 25th</span> <span class="date-year">2024</span></time> </a> </span> <span class="comments-link"> </span> <ul class="relsyn"><li><a aria-label="mastodon" class="u-syndication syn-link" href="https://mastodon.social/@asuh/112848479576654705"> <span class="syndication-link-icon svg-mastodon" style="display: inline-block; max-width: 1rem; margin: 2px;" aria-hidden="true" aria-label="Mastodon" title="Mastodon" ><svg role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><title>Mastodon</title><path d="M23.268 5.313c-.35-2.578-2.617-4.61-5.304-5.004C17.51.242 15.792 0 11.813 0h-.03c-3.98 0-4.835.242-5.288.309C3.882.692 1.496 2.518.917 5.127.64 6.412.61 7.837.661 9.143c.074 1.874.088 3.745.26 5.611.118 1.24.325 2.47.62 3.68.55 2.237 2.777 4.098 4.96 4.857 2.336.792 4.849.923 7.256.38.265-.061.527-.132.786-.213.585-.184 1.27-.39 1.774-.753a.057.057 0 0 0 .023-.043v-1.809a.052.052 0 0 0-.02-.041.053.053 0 0 0-.046-.01 20.282 20.282 0 0 1-4.709.545c-2.73 0-3.463-1.284-3.674-1.818a5.593 5.593 0 0 1-.319-1.433.053.053 0 0 1 .066-.054c1.517.363 3.072.546 4.632.546.376 0 .75 0 1.125-.01 1.57-.044 3.224-.124 4.768-.422.038-.008.077-.015.11-.024 2.435-.464 4.753-1.92 4.989-5.604.008-.145.03-1.52.03-1.67.002-.512.167-3.63-.024-5.545zm-3.748 9.195h-2.561V8.29c0-1.309-.55-1.976-1.67-1.976-1.23 0-1.846.79-1.846 2.35v3.403h-2.546V8.663c0-1.56-.617-2.35-1.848-2.35-1.112 0-1.668.668-1.67 1.977v6.218H4.822V8.102c0-1.31.337-2.35 1.011-3.12.696-.77 1.608-1.164 2.74-1.164 1.311 0 2.302.5 2.962 1.498l.638 1.06.638-1.06c.66-.999 1.65-1.498 2.96-1.498 1.13 0 2.043.395 2.74 1.164.675.77 1.012 1.81 1.012 3.12z"/></svg></span></a></li><li><a aria-label="bluesky" class="u-syndication syn-link" href="https://bsky.app/profile/asuh.com/post/3ky4tf7nr2j2j"> <span class="syndication-link-icon svg-bluesky" style="display: inline-block; max-width: 1rem; margin: 2px;" aria-hidden="true" aria-label="Bluesky" title="Bluesky" ><svg role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><title>Bluesky</title><path d="M12 10.8c-1.087-2.114-4.046-6.053-6.798-7.995C2.566.944 1.561 1.266.902 1.565.139 1.908 0 3.08 0 3.768c0 .69.378 5.65.624 6.479.815 2.736 3.713 3.66 6.383 3.364.136-.02.275-.039.415-.056-.138.022-.276.04-.415.056-3.912.58-7.387 2.005-2.83 7.078 5.013 5.19 6.87-1.113 7.823-4.308.953 3.195 2.05 9.271 7.733 4.308 4.267-4.308 1.172-6.498-2.74-7.078a8.741 8.741 0 0 1-.415-.056c.14.017.279.036.415.056 2.67.297 5.568-.628 6.383-3.364.246-.828.624-5.79.624-6.478 0-.69-.139-1.861-.902-2.206-.659-.298-1.664-.62-4.3 1.24C16.046 4.748 13.087 8.687 12 10.8Z"/></svg></span></a></li></ul> </div><!-- .entry-meta --> </article> <article class="post-2294 post type-post status-publish format-standard category-personal category-web-development tag-css tag-wordpress kind-quote h-entry hentry"> <header class="post-header"> <h2 class="entry-title"><a class="p-name u-url" href="https://asuh.com/sad-twentytwentyfive/">sad twentytwentyfive</a></h2> </header> <div class="main-content e-content"> <section class="h-cite response u-quotation-of "> <header> <span class="svg-icon svg-quote" aria-label="Quote" title="Quote" style="display: inline-block; max-height: 1rem; margin-right: 0.5rem"><span aria-hidden="true"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path d="M512 80v128c0 137.018-63.772 236.324-193.827 271.172-15.225 4.08-30.173-7.437-30.173-23.199v-33.895c0-10.057 6.228-19.133 15.687-22.55C369.684 375.688 408 330.054 408 256h-72c-26.51 0-48-21.49-48-48V80c0-26.51 21.49-48 48-48h128c26.51 0 48 21.49 48 48zM176 32H48C21.49 32 0 53.49 0 80v128c0 26.51 21.49 48 48 48h72c0 74.054-38.316 119.688-104.313 143.528C6.228 402.945 0 412.021 0 422.078v33.895c0 15.762 14.948 27.279 30.173 23.199C160.228 444.324 224 345.018 224 208V80c0-26.51-21.49-48-48-48z"/></svg></span></span><span class="kind-display-text">Quoted</span> <a href="https://github.com/WordPress/twentytwentyfive/tree/4c237755c1768da844f6f342a0f7c25729725d31?tab=readme-ov-file#about" class="p-name u-url">GitHub – WordPress/twentytwentyfive</a> by <span class="h-card p-author">WordPress</span><em> (<span class="p-publication">GitHub</span>)</em></header> <blockquote class="e-summary"><p>Twenty Twenty-Five is built as a block theme. The theme aims to ship with as little CSS as possible: our goal is for all theme styles to be configured through <code class="language-bash">theme.json</code> and editable through Global Styles.</p></blockquote> </section> <p>This makes me sad.</p> <p>In a different system, a configuration file like <code class="language-bash">theme.json</code> would be considered a <a href="https://design-tokens.github.io/community-group/format/">design token</a> where a design system will automatically generate a JSON file full of tokens to be used in a component library or website. The potential for design tokens are quite high, but sadly they’re less practical without tools that are configured to both generate the design token file or system and give easy access for developers to use them. Right now, it’s still piecemeal and there’s not a great workflow in many systems.</p> <p>Modern WordPress development is abstracting a subset of CSS to a JSON file, for the ease of builders and publishers. The developers who build Block Themes are kind of being forced against the grain of the web in the development phase. Developers consumed by a Javascript-centric system, this might make a lot more sense. But, for those of us who want to build using the technology that browsers provide, this is very unappealing and backwards.</p> <p>This is just another reason I can’t see how much longer WordPress will be serious going forward. Maybe the update to React 19 in Gutenberg will change things, considering that it makes Web Components a first class integration, also considering the possibility of using React Server Components. But, I haven’t seen anything that gives me an indication either of these are being really thought out.</p> <p>This quote was from the <a href="https://github.com/WordPress/twentytwentyfive/tree/4c237755c1768da844f6f342a0f7c25729725d31?tab=readme-ov-file#about">TwentyTwentyFive Github Repo</a>.</p> <p><a original-href="/tag/wordpress/" rel="tag" class="hashtag u-tag u-category" href="/friends/tag/wordpress/">#wordpress</a> <a original-href="/tag/css/" rel="tag" class="hashtag u-tag u-category" href="/friends/tag/css/">#css</a></p> </div><!-- .main-content --> <div class="entry-meta"> <span class="posted-on"> <a class="u-url" href="https://asuh.com/sad-twentytwentyfive/"> <svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" class="hyperlink" viewBox="0 0 32 32"><path fill="currentColor" d="M13.8 19.9a1.6 1.6 0 0 1-1.2-.5c-3-3-3-7.8 0-10.8l6-6a7.6 7.6 0 0 1 10.8 0c3 3 3 7.8 0 10.8L26.6 16a1.6 1.6 0 1 1-2.2-2.3l2.7-2.7a4.4 4.4 0 0 0 0-6.2 4.3 4.3 0 0 0-6.2 0l-6 6a4.4 4.4 0 0 0 0 6.2 1.6 1.6 0 0 1-1.1 2.8z"/><path fill="currentColor" d="M8 31.6a7.6 7.6 0 0 1-5.4-2.2c-3-3-3-7.8 0-10.8L5.4 16a1.6 1.6 0 1 1 2.2 2.3L5 20.9a4.4 4.4 0 0 0 0 6.2 4.3 4.3 0 0 0 6.2 0l6-6a4.4 4.4 0 0 0 0-6.2 1.6 1.6 0 1 1 2.3-2.3c3 3 3 7.8 0 10.8l-6 6A7.6 7.6 0 0 1 8 31.6z"/></svg><time class="entry-date dt-published" datetime="2024-07-07T13:38:21-07:00"><span class="date-month-day">July 7th</span> <span class="date-year">2024</span></time> </a> </span> <span class="comments-link"> 4 replies </span> <ul class="relsyn"><li><a aria-label="mastodon" class="u-syndication syn-link" href="https://mastodon.social/@asuh/112747256143810309"> <span class="syndication-link-icon svg-mastodon" style="display: inline-block; max-width: 1rem; margin: 2px;" aria-hidden="true" aria-label="Mastodon" title="Mastodon" ><svg role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><title>Mastodon</title><path d="M23.268 5.313c-.35-2.578-2.617-4.61-5.304-5.004C17.51.242 15.792 0 11.813 0h-.03c-3.98 0-4.835.242-5.288.309C3.882.692 1.496 2.518.917 5.127.64 6.412.61 7.837.661 9.143c.074 1.874.088 3.745.26 5.611.118 1.24.325 2.47.62 3.68.55 2.237 2.777 4.098 4.96 4.857 2.336.792 4.849.923 7.256.38.265-.061.527-.132.786-.213.585-.184 1.27-.39 1.774-.753a.057.057 0 0 0 .023-.043v-1.809a.052.052 0 0 0-.02-.041.053.053 0 0 0-.046-.01 20.282 20.282 0 0 1-4.709.545c-2.73 0-3.463-1.284-3.674-1.818a5.593 5.593 0 0 1-.319-1.433.053.053 0 0 1 .066-.054c1.517.363 3.072.546 4.632.546.376 0 .75 0 1.125-.01 1.57-.044 3.224-.124 4.768-.422.038-.008.077-.015.11-.024 2.435-.464 4.753-1.92 4.989-5.604.008-.145.03-1.52.03-1.67.002-.512.167-3.63-.024-5.545zm-3.748 9.195h-2.561V8.29c0-1.309-.55-1.976-1.67-1.976-1.23 0-1.846.79-1.846 2.35v3.403h-2.546V8.663c0-1.56-.617-2.35-1.848-2.35-1.112 0-1.668.668-1.67 1.977v6.218H4.822V8.102c0-1.31.337-2.35 1.011-3.12.696-.77 1.608-1.164 2.74-1.164 1.311 0 2.302.5 2.962 1.498l.638 1.06.638-1.06c.66-.999 1.65-1.498 2.96-1.498 1.13 0 2.043.395 2.74 1.164.675.77 1.012 1.81 1.012 3.12z"/></svg></span></a></li></ul> </div><!-- .entry-meta --> </article> <article class="post-2285 post type-post status-publish format-standard category-web-development tag-726 tag-ccc kind-article h-entry hentry"> <header class="post-header"> <h2 class="entry-title"><a class="p-name u-url" href="https://asuh.com/svg-background-images-to-inherit-light-dark-value/">svg background images to inherit light-dark value</a></h2> </header> <div class="main-content e-content"> <p>With the spirit of using new widely supported, <a href="https://developer.mozilla.org/en-US/blog/baseline-evolution-on-mdn/">Baseline</a> CSS rules, I’m implementing <a href="https://caniuse.com/?search=light-dark"><code class="language-css">light-dark()</code></a> as a simplified method to allow light and dark mode on a website. This function is a game changer, very simple to apply color modes for websites, so I’m a big fan already. That said, using SVG images as background images exposes an edge case that took me down a rabbit hole leading me to <a href="https://developer.mozilla.org/en-US/docs/Web/CSS/mask">CSS masks</a>.</p> <p>Let’s apply <a href="https://daverupert.com/2024/05/light-dark-experiment/">light-dark using color-scheme</a> for the site.</p> <pre><code class="language-css">:root { /* NOTE: Use @supports for <= Safari 17.4 (2024-05) */ @supports (color: light-dark(black, white)) { color-scheme: light dark; --surface-color: light-dark( #ccc, #333 ); --text-color: light-dark( #333, #ccc ); } }</code></pre> <p>I’m applying carets to navigation menu item links, which look like this:</p> <p><img loading="lazy" decoding="async" class="alignnone wp-image-2287 size-full" src="/wp/wp-content/uploads/2024/07/navigation-item-link.webp" alt="navigation item link named "Resources" with down-pointing caret on the right of the link" width="110" height="38" /></p> <p>So that chevron or caret on the right side of <strong>Resources</strong>, which is pointing down, is applied to the anchor element as a background image.</p> <pre><code class="language-css">a { background-image: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' width='24' height='24' fill='currentColor' [...]"); }</code></pre> <p>Why am I adding an SVG as a background image here? Wouldn’t it be easier to add SVG to the source code? Well, yes, but this is WordPress, and since I’m pulling in the navigation menu from an API, the markup is auto-generated and formatted so it’s not easy to add in additional markup into the API results. I’m sure we’ve all faced similar limitations on generated code from an API, so I was determined to attack this problem and find a solution.</p> <p>Additionally, I’m not referencing an additional file as a way to save an HTTP request, one of the many micro-optimizations for better performance. This also gives us the ability to easily cache the image, or if I decide to use an SVG sprite in the future, this saves multiple requests.</p> <p>Back to the code above, see that <code class="language-css">fill='currentColor'</code> rule? It doesn’t work as you would expect because, regardless of the SVG being added a background image, <a href="https://stackoverflow.com/a/76006610">the SVG is being treated as an external resource</a>. Considering this, we can’t apply the <code class="language-css">currentColor</code> value to inherit the anchor’s color.</p> <p>In the Stackoverflow I just linked to above, there’s a reference to <a href="https://codepen.io/noahblon/post/coloring-svgs-in-css-background-images">Coloring SVGs in CSS Background Images</a>, which provided me a big clue to solve this, which is using CSS masks. It worked… kinda!</p> <p>I converted everything from <code class="language-css">background</code> to be <code class="language-css">mask</code>, because the syntax is mostly identical, and added a background color for the mask to work correctly. Well, that actually hid the text of the anchor element, so while I was now able to see the background caret with the correct color mode text color, the actual text was hidden. To this point, I’ve purposely been trying to not use <code class="language-css">::after</code> pseudo-elements out of principle, just to make things a little simpler. Time to break through the ego and add back that pseudo-element!</p> <p>The final code that works for me:</p> <pre><code class="language-css">a::after { background-color: var(--text-color); content: ""; height: 100%; mask-image: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' width='24' height='24' fill='currentColor' aria-hidden='true' viewBox='0 0 20 20'><path fill-rule='evenodd' d='M5.23 7.21a.75.75 0 011.06.02L10 11.168l3.71-3.938a.75.75 0 111.08 1.04l-4.25 4.5a.75.75 0 01-1.08 0l-4.25-4.5a.75.75 0 01.02-1.06z' clip-rule='evenodd'/></svg>"); mask-position: left 17%; mask-repeat: no-repeat; mask-size: 0.9rem; position: absolute; width: 100%; }</code></pre> <p>Problem solved!</p> </div><!-- .main-content --> <div class="entry-meta"> <span class="posted-on"> <a class="u-url" href="https://asuh.com/svg-background-images-to-inherit-light-dark-value/"> <svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" class="hyperlink" viewBox="0 0 32 32"><path fill="currentColor" d="M13.8 19.9a1.6 1.6 0 0 1-1.2-.5c-3-3-3-7.8 0-10.8l6-6a7.6 7.6 0 0 1 10.8 0c3 3 3 7.8 0 10.8L26.6 16a1.6 1.6 0 1 1-2.2-2.3l2.7-2.7a4.4 4.4 0 0 0 0-6.2 4.3 4.3 0 0 0-6.2 0l-6 6a4.4 4.4 0 0 0 0 6.2 1.6 1.6 0 0 1-1.1 2.8z"/><path fill="currentColor" d="M8 31.6a7.6 7.6 0 0 1-5.4-2.2c-3-3-3-7.8 0-10.8L5.4 16a1.6 1.6 0 1 1 2.2 2.3L5 20.9a4.4 4.4 0 0 0 0 6.2 4.3 4.3 0 0 0 6.2 0l6-6a4.4 4.4 0 0 0 0-6.2 1.6 1.6 0 1 1 2.3-2.3c3 3 3 7.8 0 10.8l-6 6A7.6 7.6 0 0 1 8 31.6z"/></svg><time class="entry-date dt-published" datetime="2024-07-05T11:29:22-07:00"><span class="date-month-day">July 5th</span> <span class="date-year">2024</span></time> </a> </span> <span class="comments-link"> </span> </div><!-- .entry-meta --> </article> <article class="post-2282 post type-post status-publish format-standard category-web-development kind-article h-entry hentry"> <header class="post-header"> <h2 class="entry-title"><a class="p-name u-url" href="https://asuh.com/search-form-popover-api/">search form + popover api</a></h2> </header> <div class="main-content e-content"> <p>Wresting with whether or not I should move forward using the <a href="https://web.dev/blog/popover-api">Popover API</a> for a search form, almost solely to delete the javascript code for the same type of interaction.</p> <p>I’m hung up on default focus *not* going to the search field. I discovered that it’s only a tap of the tab key away, which is very helpful, but that default focus would be the clincher for me.</p> <p>This probably won’t improve accessibility either.</p> <p>This is so tempting!</p> <p>The following Codepen link is a demo of what I’m considering. It’s really, really cool to see this work so easily with two new attributes! Mindblowing.</p> <p><a class="status-link unhandled-link" title="https://codepen.io/asuh/pen/jOojyJB" translate="no" href="https://codepen.io/asuh/pen/jOojyJB" target="_blank" rel="nofollow noopener noreferrer"><span class="invisible">https://</span><span class="">codepen.io/asuh/pen/jOojyJB</span></a></p> </div><!-- .main-content --> <div class="entry-meta"> <span class="posted-on"> <a class="u-url" href="https://asuh.com/search-form-popover-api/"> <svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" class="hyperlink" viewBox="0 0 32 32"><path fill="currentColor" d="M13.8 19.9a1.6 1.6 0 0 1-1.2-.5c-3-3-3-7.8 0-10.8l6-6a7.6 7.6 0 0 1 10.8 0c3 3 3 7.8 0 10.8L26.6 16a1.6 1.6 0 1 1-2.2-2.3l2.7-2.7a4.4 4.4 0 0 0 0-6.2 4.3 4.3 0 0 0-6.2 0l-6 6a4.4 4.4 0 0 0 0 6.2 1.6 1.6 0 0 1-1.1 2.8z"/><path fill="currentColor" d="M8 31.6a7.6 7.6 0 0 1-5.4-2.2c-3-3-3-7.8 0-10.8L5.4 16a1.6 1.6 0 1 1 2.2 2.3L5 20.9a4.4 4.4 0 0 0 0 6.2 4.3 4.3 0 0 0 6.2 0l6-6a4.4 4.4 0 0 0 0-6.2 1.6 1.6 0 1 1 2.3-2.3c3 3 3 7.8 0 10.8l-6 6A7.6 7.6 0 0 1 8 31.6z"/></svg><time class="entry-date dt-published" datetime="2024-06-29T17:42:40-07:00"><span class="date-month-day">June 29th</span> <span class="date-year">2024</span></time> </a> </span> <span class="comments-link"> 2 replies </span> <ul class="relsyn"><li><a aria-label="mastodon" class="u-syndication syn-link" href="https://mastodon.social/@asuh/112702773778987946"> <span class="syndication-link-icon svg-mastodon" style="display: inline-block; max-width: 1rem; margin: 2px;" aria-hidden="true" aria-label="Mastodon" title="Mastodon" ><svg role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><title>Mastodon</title><path d="M23.268 5.313c-.35-2.578-2.617-4.61-5.304-5.004C17.51.242 15.792 0 11.813 0h-.03c-3.98 0-4.835.242-5.288.309C3.882.692 1.496 2.518.917 5.127.64 6.412.61 7.837.661 9.143c.074 1.874.088 3.745.26 5.611.118 1.24.325 2.47.62 3.68.55 2.237 2.777 4.098 4.96 4.857 2.336.792 4.849.923 7.256.38.265-.061.527-.132.786-.213.585-.184 1.27-.39 1.774-.753a.057.057 0 0 0 .023-.043v-1.809a.052.052 0 0 0-.02-.041.053.053 0 0 0-.046-.01 20.282 20.282 0 0 1-4.709.545c-2.73 0-3.463-1.284-3.674-1.818a5.593 5.593 0 0 1-.319-1.433.053.053 0 0 1 .066-.054c1.517.363 3.072.546 4.632.546.376 0 .75 0 1.125-.01 1.57-.044 3.224-.124 4.768-.422.038-.008.077-.015.11-.024 2.435-.464 4.753-1.92 4.989-5.604.008-.145.03-1.52.03-1.67.002-.512.167-3.63-.024-5.545zm-3.748 9.195h-2.561V8.29c0-1.309-.55-1.976-1.67-1.976-1.23 0-1.846.79-1.846 2.35v3.403h-2.546V8.663c0-1.56-.617-2.35-1.848-2.35-1.112 0-1.668.668-1.67 1.977v6.218H4.822V8.102c0-1.31.337-2.35 1.011-3.12.696-.77 1.608-1.164 2.74-1.164 1.311 0 2.302.5 2.962 1.498l.638 1.06.638-1.06c.66-.999 1.65-1.498 2.96-1.498 1.13 0 2.043.395 2.74 1.164.675.77 1.012 1.81 1.012 3.12z"/></svg></span></a></li><li><a aria-label="bluesky" class="u-syndication syn-link" href="https://bsky.app/profile/asuh.com/post/3kw453br6g52z"> <span class="syndication-link-icon svg-bluesky" style="display: inline-block; max-width: 1rem; margin: 2px;" aria-hidden="true" aria-label="Bluesky" title="Bluesky" ><svg role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><title>Bluesky</title><path d="M12 10.8c-1.087-2.114-4.046-6.053-6.798-7.995C2.566.944 1.561 1.266.902 1.565.139 1.908 0 3.08 0 3.768c0 .69.378 5.65.624 6.479.815 2.736 3.713 3.66 6.383 3.364.136-.02.275-.039.415-.056-.138.022-.276.04-.415.056-3.912.58-7.387 2.005-2.83 7.078 5.013 5.19 6.87-1.113 7.823-4.308.953 3.195 2.05 9.271 7.733 4.308 4.267-4.308 1.172-6.498-2.74-7.078a8.741 8.741 0 0 1-.415-.056c.14.017.279.036.415.056 2.67.297 5.568-.628 6.383-3.364.246-.828.624-5.79.624-6.478 0-.69-.139-1.861-.902-2.206-.659-.298-1.664-.62-4.3 1.24C16.046 4.748 13.087 8.687 12 10.8Z"/></svg></span></a></li></ul> </div><!-- .entry-meta --> </article> <article class="post-2279 post type-post status-publish format-standard category-asuhcom category-web-development kind-note h-entry hentry"> <header class="post-header"> <h2 class="entry-title"><a class="p-name u-url" href="https://asuh.com/updated-the-site-again/">updated the site again</a></h2> </header> <div class="main-content e-content"> <div class="status__content" tabindex="0"> <div class="status__content__text status__content__text--visible translate" lang="en"> <p>Reached a stopping point to update asuh.com using the new Forage theme I put together.</p> <p><a class="status-link unhandled-link" title="https://github.com/asuh/forage/" translate="no" href="https://github.com/asuh/forage/" target="_blank" rel="nofollow noopener noreferrer"><span class="invisible">https://</span><span class="">github.com/asuh/forage/</span></a></p> <p>It’s nice to remove so much <a original-href="https://mastodon.social/tags/css" class="mention hashtag status-link" href="/friends/tag/css/" rel="tag">#css</a> from my previous iteration and simply things with some modern CSS.</p> <p>Forage is such a great tool for <a original-href="https://mastodon.social/tags/wordpress" class="mention hashtag status-link" href="/friends/tag/wordpress/" rel="tag">#wordpress</a> classic theme developers and I should continue improving it where I can.</p> <p>Next, I’m going to probably update another site with Forage that uses Gutenberg and see how that goes. I believe it’ll be a hybrid block theme this way.</p> </div> </div> </div><!-- .main-content --> <div class="entry-meta"> <span class="posted-on"> <a class="u-url" href="https://asuh.com/updated-the-site-again/"> <svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" class="hyperlink" viewBox="0 0 32 32"><path fill="currentColor" d="M13.8 19.9a1.6 1.6 0 0 1-1.2-.5c-3-3-3-7.8 0-10.8l6-6a7.6 7.6 0 0 1 10.8 0c3 3 3 7.8 0 10.8L26.6 16a1.6 1.6 0 1 1-2.2-2.3l2.7-2.7a4.4 4.4 0 0 0 0-6.2 4.3 4.3 0 0 0-6.2 0l-6 6a4.4 4.4 0 0 0 0 6.2 1.6 1.6 0 0 1-1.1 2.8z"/><path fill="currentColor" d="M8 31.6a7.6 7.6 0 0 1-5.4-2.2c-3-3-3-7.8 0-10.8L5.4 16a1.6 1.6 0 1 1 2.2 2.3L5 20.9a4.4 4.4 0 0 0 0 6.2 4.3 4.3 0 0 0 6.2 0l6-6a4.4 4.4 0 0 0 0-6.2 1.6 1.6 0 1 1 2.3-2.3c3 3 3 7.8 0 10.8l-6 6A7.6 7.6 0 0 1 8 31.6z"/></svg><time class="entry-date dt-published" datetime="2024-06-18T08:26:44-07:00"><span class="date-month-day">June 18th</span> <span class="date-year">2024</span></time> </a> </span> <span class="comments-link"> </span> <ul class="relsyn"><li><a aria-label="mastodon" class="u-syndication syn-link" href="https://mastodon.social/@asuh/112638315877135308"> <span class="syndication-link-icon svg-mastodon" style="display: inline-block; max-width: 1rem; margin: 2px;" aria-hidden="true" aria-label="Mastodon" title="Mastodon" ><svg role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><title>Mastodon</title><path d="M23.268 5.313c-.35-2.578-2.617-4.61-5.304-5.004C17.51.242 15.792 0 11.813 0h-.03c-3.98 0-4.835.242-5.288.309C3.882.692 1.496 2.518.917 5.127.64 6.412.61 7.837.661 9.143c.074 1.874.088 3.745.26 5.611.118 1.24.325 2.47.62 3.68.55 2.237 2.777 4.098 4.96 4.857 2.336.792 4.849.923 7.256.38.265-.061.527-.132.786-.213.585-.184 1.27-.39 1.774-.753a.057.057 0 0 0 .023-.043v-1.809a.052.052 0 0 0-.02-.041.053.053 0 0 0-.046-.01 20.282 20.282 0 0 1-4.709.545c-2.73 0-3.463-1.284-3.674-1.818a5.593 5.593 0 0 1-.319-1.433.053.053 0 0 1 .066-.054c1.517.363 3.072.546 4.632.546.376 0 .75 0 1.125-.01 1.57-.044 3.224-.124 4.768-.422.038-.008.077-.015.11-.024 2.435-.464 4.753-1.92 4.989-5.604.008-.145.03-1.52.03-1.67.002-.512.167-3.63-.024-5.545zm-3.748 9.195h-2.561V8.29c0-1.309-.55-1.976-1.67-1.976-1.23 0-1.846.79-1.846 2.35v3.403h-2.546V8.663c0-1.56-.617-2.35-1.848-2.35-1.112 0-1.668.668-1.67 1.977v6.218H4.822V8.102c0-1.31.337-2.35 1.011-3.12.696-.77 1.608-1.164 2.74-1.164 1.311 0 2.302.5 2.962 1.498l.638 1.06.638-1.06c.66-.999 1.65-1.498 2.96-1.498 1.13 0 2.043.395 2.74 1.164.675.77 1.012 1.81 1.012 3.12z"/></svg></span></a></li><li><a aria-label="bluesky" class="u-syndication syn-link" href="https://bsky.app/profile/asuh.com/post/3kv7ixncsl42e"> <span class="syndication-link-icon svg-bluesky" style="display: inline-block; max-width: 1rem; margin: 2px;" aria-hidden="true" aria-label="Bluesky" title="Bluesky" ><svg role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><title>Bluesky</title><path d="M12 10.8c-1.087-2.114-4.046-6.053-6.798-7.995C2.566.944 1.561 1.266.902 1.565.139 1.908 0 3.08 0 3.768c0 .69.378 5.65.624 6.479.815 2.736 3.713 3.66 6.383 3.364.136-.02.275-.039.415-.056-.138.022-.276.04-.415.056-3.912.58-7.387 2.005-2.83 7.078 5.013 5.19 6.87-1.113 7.823-4.308.953 3.195 2.05 9.271 7.733 4.308 4.267-4.308 1.172-6.498-2.74-7.078a8.741 8.741 0 0 1-.415-.056c.14.017.279.036.415.056 2.67.297 5.568-.628 6.383-3.364.246-.828.624-5.79.624-6.478 0-.69-.139-1.861-.902-2.206-.659-.298-1.664-.62-4.3 1.24C16.046 4.748 13.087 8.687 12 10.8Z"/></svg></span></a></li></ul> </div><!-- .entry-meta --> </article> <article class="post-2275 post type-post status-publish format-standard category-portfolio category-technology category-web-development kind-issue h-entry hentry"> <header class="post-header"> <h2 class="entry-title"><a class="p-name u-url" href="https://asuh.com/laravel-blade-php/">laravel blade > php?</a></h2> </header> <div class="main-content e-content"> <section class="response p-in-reply-to h-cite"> <header> <span class="svg-icon svg-issue" aria-label="Issue" title="Issue" style="display: inline-block; max-height: 1rem; margin-right: 0.5rem"><span aria-hidden="true"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path d="M504 256c0 136.997-111.043 248-248 248S8 392.997 8 256C8 119.083 119.043 8 256 8s248 111.083 248 248zm-248 50c-25.405 0-46 20.595-46 46s20.595 46 46 46 46-20.595 46-46-20.595-46-46-46zm-43.673-165.346l7.418 136c.347 6.364 5.609 11.346 11.982 11.346h48.546c6.373 0 11.635-4.982 11.982-11.346l7.418-136c.375-6.874-5.098-12.654-11.982-12.654h-63.383c-6.884 0-12.356 5.78-11.981 12.654z"/></svg></span></span><span class="kind-display-text">Filed an Issue</span> <span class="p-name"> </span></header> <blockquote class="e-summary"></blockquote> </section> <p>This is mostly reproduced from a <a href="https://github.com/asuh/forage/issues/8">Github issue I created for the new Forage WordPress theme</a> I created. I’m thinking out loud whether or not to support a new branch with plain ‘ole PHP instead of the Blade syntax.</p> <hr /> <p><a href="https://laravel.com/docs/11.x/blade">Laravel Blade</a> has some notable features that help PHP developers move faster. Here are a few reasons to keep using it:</p> <p>(quickly generated by ChatGPT, with edits and additions by me)</p> <ul> <li><strong>Layout Components</strong>: Blade offers the <code class="language-php">@component</code> directive for defining reusable components, such as navigation menus, alerts, or forms. This promotes encapsulation and reusability for components containing HTML, CSS, and JS.</li> <li><strong>Escaping by Default</strong>: Blade automatically escapes output by default, helping to prevent XSS (Cross-Site Scripting) attacks. This enhances the security of your application by reducing the risk of injecting malicious code into your HTML. While PHP provides functions for escaping output, Blade handles this automatically, reducing the likelihood of accidental omissions.</li> <li><strong>Template Inheritance</strong>: allows you to define a base layout with placeholders that child views can fill in with their own content. This enables a more structured and modular approach to building views, reducing duplication and promoting code reusability.In other words, PHP would require explicit includes everywhere for PHP files to work with each other. Blade uses hooks like <code class="language-php">@yield</code> as placeholders to work with various functions like <code class="language-php">@section</code>.<code class="language-php">@yield('content")</code> in the base file would render <code class="language-php">@section('content") in the child view file, such as </code>page.blade.php`.</li> <li><strong>Control Directives</strong>: Blade provides convenient directives for common control structures, making it easier to express conditional logic and iterate over data.Example<code class="language-php">@if ()</code> as plain PHP would need PHP tags, looking like <code class="language-php"><?php if () ?></code>. Essentially, it’s more verbose to use plain PHP.</li> <li><strong>Concise Syntax</strong>: Blade offers a concise and readable syntax for common tasks such as echoing variables <code class="language-php">({{ $variable }})</code>, control structures (<code class="language-php">@if</code>, <code class="language-php">@else</code>, <code class="language-php">@endif</code>, etc.), loops (<code class="language-php">@foreach</code>, <code class="language-php">@for</code>, <code class="language-php">@while</code>), and more. This makes Blade templates easier to write, understand, and maintain compared to raw PHP embedded within HTML.</li> <li><strong>Template Comments</strong>: using <code class="language-php">{{-- This is a Blade comment --}}</code>, which is not rendered in the final output.</li> <li><strong>Include Statements</strong>: In addition to <code class="language-php">@include</code>, which mostly mirrors plain PHP, Blade also provides the <code class="language-php">@includeWhen</code> and <code class="language-php">@includeFirst</code> directives for conditional inclusion of templates.</li> </ul> <p>I attempted to order the above in the order of importance, with the top few being quite more efficient than plain PHP.</p> <p>My overall observation is that Blade should truly be considered if you can think of good use cases for adding components rendered by PHP. At some point, it might be less useful as Web Components find their way into the WordPress ecosystem.</p> <p>Additionally, the auto-escape and inheritance for Blade is pretty great for efficiency. The benefits of these features are quite convenient.</p> <p>The rest are just nice little sprinkles to clean up PHP. Nice, but not necessary.</p> <p>If I review everything I’ve used with Blade, I really don’t think I have any real needs yet for PHP driven components. All the rest of the bullet points could easily have been regular PHP in my own personal work flow, but I’m really only using themes on smaller sites that don’t have a lot of complexity.</p> <p>If Blade is removed from any project, you likely have the option to completely remove a dependency on Composer as well as some application methods to render the Blade syntax into PHP. I can also see this argument for those who prefer to stay as close to the original languages as possible.</p> <p>At some point in the near future, decisions to support Laravel Blade might come down to whether or not you want a build step to compile a language. There’s a potential future approaching where the browser contains so much power that build steps can once again become optional. That’s a very interesting future!</p> </div><!-- .main-content --> <div class="entry-meta"> <span class="posted-on"> <a class="u-url" href="https://asuh.com/laravel-blade-php/"> <svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" class="hyperlink" viewBox="0 0 32 32"><path fill="currentColor" d="M13.8 19.9a1.6 1.6 0 0 1-1.2-.5c-3-3-3-7.8 0-10.8l6-6a7.6 7.6 0 0 1 10.8 0c3 3 3 7.8 0 10.8L26.6 16a1.6 1.6 0 1 1-2.2-2.3l2.7-2.7a4.4 4.4 0 0 0 0-6.2 4.3 4.3 0 0 0-6.2 0l-6 6a4.4 4.4 0 0 0 0 6.2 1.6 1.6 0 0 1-1.1 2.8z"/><path fill="currentColor" d="M8 31.6a7.6 7.6 0 0 1-5.4-2.2c-3-3-3-7.8 0-10.8L5.4 16a1.6 1.6 0 1 1 2.2 2.3L5 20.9a4.4 4.4 0 0 0 0 6.2 4.3 4.3 0 0 0 6.2 0l6-6a4.4 4.4 0 0 0 0-6.2 1.6 1.6 0 1 1 2.3-2.3c3 3 3 7.8 0 10.8l-6 6A7.6 7.6 0 0 1 8 31.6z"/></svg><time class="entry-date dt-published" datetime="2024-06-13T12:21:29-07:00"><span class="date-month-day">June 13th</span> <span class="date-year">2024</span></time> </a> </span> <span class="comments-link"> </span> <ul class="relsyn"><li><a aria-label="github" class="u-syndication syn-link" href="https://github.com/asuh/forage/issues/8"> <span class="syndication-link-icon svg-github" style="display: inline-block; max-width: 1rem; margin: 2px;" aria-hidden="true" aria-label="GitHub" title="GitHub" ><svg role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><title>GitHub</title><path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12"/></svg></span></a></li><li><a aria-label="mastodon" class="u-syndication syn-link" href="https://mastodon.social/@asuh/112611140265574449"> <span class="syndication-link-icon svg-mastodon" style="display: inline-block; max-width: 1rem; margin: 2px;" aria-hidden="true" aria-label="Mastodon" title="Mastodon" ><svg role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><title>Mastodon</title><path d="M23.268 5.313c-.35-2.578-2.617-4.61-5.304-5.004C17.51.242 15.792 0 11.813 0h-.03c-3.98 0-4.835.242-5.288.309C3.882.692 1.496 2.518.917 5.127.64 6.412.61 7.837.661 9.143c.074 1.874.088 3.745.26 5.611.118 1.24.325 2.47.62 3.68.55 2.237 2.777 4.098 4.96 4.857 2.336.792 4.849.923 7.256.38.265-.061.527-.132.786-.213.585-.184 1.27-.39 1.774-.753a.057.057 0 0 0 .023-.043v-1.809a.052.052 0 0 0-.02-.041.053.053 0 0 0-.046-.01 20.282 20.282 0 0 1-4.709.545c-2.73 0-3.463-1.284-3.674-1.818a5.593 5.593 0 0 1-.319-1.433.053.053 0 0 1 .066-.054c1.517.363 3.072.546 4.632.546.376 0 .75 0 1.125-.01 1.57-.044 3.224-.124 4.768-.422.038-.008.077-.015.11-.024 2.435-.464 4.753-1.92 4.989-5.604.008-.145.03-1.52.03-1.67.002-.512.167-3.63-.024-5.545zm-3.748 9.195h-2.561V8.29c0-1.309-.55-1.976-1.67-1.976-1.23 0-1.846.79-1.846 2.35v3.403h-2.546V8.663c0-1.56-.617-2.35-1.848-2.35-1.112 0-1.668.668-1.67 1.977v6.218H4.822V8.102c0-1.31.337-2.35 1.011-3.12.696-.77 1.608-1.164 2.74-1.164 1.311 0 2.302.5 2.962 1.498l.638 1.06.638-1.06c.66-.999 1.65-1.498 2.96-1.498 1.13 0 2.043.395 2.74 1.164.675.77 1.012 1.81 1.012 3.12z"/></svg></span></a></li><li><a aria-label="x" class="u-syndication syn-link" href="https://twitter.com/asuh/status/1801347544435306796"> <span class="syndication-link-icon svg-x" style="display: inline-block; max-width: 1rem; margin: 2px;" aria-hidden="true" aria-label="X" title="X" ><svg role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><title>X</title><path d="M18.901 1.153h3.68l-8.04 9.19L24 22.846h-7.406l-5.8-7.584-6.638 7.584H.474l8.6-9.83L0 1.154h7.594l5.243 6.932ZM17.61 20.644h2.039L6.486 3.24H4.298Z"/></svg></span></a></li><li><a aria-label="bluesky" class="u-syndication syn-link" href="https://bsky.app/profile/asuh.com/post/3kutgmtw7222d"> <span class="syndication-link-icon svg-bluesky" style="display: inline-block; max-width: 1rem; margin: 2px;" aria-hidden="true" aria-label="Bluesky" title="Bluesky" ><svg role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><title>Bluesky</title><path d="M12 10.8c-1.087-2.114-4.046-6.053-6.798-7.995C2.566.944 1.561 1.266.902 1.565.139 1.908 0 3.08 0 3.768c0 .69.378 5.65.624 6.479.815 2.736 3.713 3.66 6.383 3.364.136-.02.275-.039.415-.056-.138.022-.276.04-.415.056-3.912.58-7.387 2.005-2.83 7.078 5.013 5.19 6.87-1.113 7.823-4.308.953 3.195 2.05 9.271 7.733 4.308 4.267-4.308 1.172-6.498-2.74-7.078a8.741 8.741 0 0 1-.415-.056c.14.017.279.036.415.056 2.67.297 5.568-.628 6.383-3.364.246-.828.624-5.79.624-6.478 0-.69-.139-1.861-.902-2.206-.659-.298-1.664-.62-4.3 1.24C16.046 4.748 13.087 8.687 12 10.8Z"/></svg></span></a></li></ul> </div><!-- .entry-meta --> </article> <article class="post-2259 post type-post status-publish format-standard category-technology category-web-development tag-wordpress kind-article h-entry hentry"> <header class="post-header"> <h2 class="entry-title"><a class="p-name u-url" href="https://asuh.com/forage/">forage, my last wordpress theme</a></h2> </header> <div class="main-content e-content"> <p data-wp-editing="1"><img loading="lazy" decoding="async" class="aligncenter wp-image-2260" src="/wp/wp-content/uploads/2024/06/screenshot-1024x768.png" alt="forage" width="768" height="576" srcset="/wp/wp-content/uploads/2024/06/screenshot-1024x768.png 1024w, /wp/wp-content/uploads/2024/06/screenshot-300x225.png 300w, /wp/wp-content/uploads/2024/06/screenshot-768x576.png 768w, /wp/wp-content/uploads/2024/06/screenshot.png 1200w" sizes="auto, (max-width: 768px) 100vw, 768px" /></p> <p>Introducing <a href="https://github.com/asuh/forage">Forage</a>, my new hybrid starter theme joining <a href="https://github.com/roots/sage">Roots Sage</a> and <a href="https://github.com/przemekhernik/footmate.pro">FootMATE</a>. This is a project of love, giving me an opportunity to learn new technologies and simplify the WordPress theme I was using. While this might not technically be the last theme I apply to my personal site, WordPress is moving into a new direction of lots of Javascript to drive a WordPress block theme.</p> <h2>Why Forage?</h2> <p>I think the mushroom kingdom that we live among is quite interesting, and the act of foraging mushrooms feels like what I do when I’m writing code: I’m always looking for something to consume and use.</p> <h2>Features</h2> <p>Forage is a starter theme. This means that when you install it, no styling or interactive behavior is added to the front-end. This gives you complete flexibility to create the theme you want with minimal opinionated code.</p> <ul> <li><a href="https://laravel.com/docs/10.x/blade">Laravel Blade</a> as a templating engine</li> <li><a href="https://vitejs.dev/" rel="nofollow">Vite</a> for compiling assets, concatenating, and minifying files</li> <li><a href="https://biomejs.dev/" rel="nofollow">Biome</a> for linting and formatting both CSS and JS</li> <li>Modern CSS & JavaScript – No preprocessors, libraries, or frameworks</li> <li><a href="https://tentyp.dev/blog/wordpress/dochooks-sugar-syntax-for-hooking-system/" rel="nofollow">DocHooks</a> provide new functionality of class method DocBlock as hooks into WordPress API</li> <li><a href="https://indieweb.org/">IndieWeb</a> out of the box</li> </ul> <h3>Laravel Blade</h3> <p>Sage was my real introduction to Laravel, back in the days when PHP just landed in the version 7 era, so I was mostly used to older PHP 5.2-5.4. While I tend toward wanting pure forms of HTML, CSS, and JS, I found Laravel Blade to be an interesting abstraction of PHP. In the last few years, PHP has come of age in so many great ways. PHP 7 and PHP 8, and all point releases, added superpowers for functional programming and types, among many other features. Modern PHP and TypeScript, less so even modern Javascript, have a lot in common today. In many ways, it’s impressive where PHP is today.</p> <p>Laravel Blade is a modern approach to templating PHP. In a similar way that TypeScript is also Javascript, all blade files are PHP files as well which makes it convenient to get started. The main benefits of using a blade file is the cleaner looking syntax and custom components. Not <a href="https://spacema-dev.com/understanding-laravel-blade-and-how-to-use-it/">Here’s a great overview of all the strengths of Blade</a>.</p> <h3>Vite</h3> <p>I first used Vite via <a href="https://astro.build/">Astro</a>, and as a build tool, it felt so easy and simple. I’ve used many other build tools over the years, from grunt and gulp to webpack. I tried others here and there, but nothing stuck. Vite, however, makes a lot of sense for WordPress classic theme development.</p> <p>The instance of Vite used for this theme is so lightly integrated that you wonder how it’s really doing all that magic so easily. The biggest difference? I don’t need to have two environments to see live reloads anymore. If I’m using https://example.local/ to work on WordPress locally on my computer, Vite will use the same environment for live reloading. No need to switch to a different URL like https://localhost:3000! Truly, I’ve been annoyed by this for more than a decade about Webpack! No more!</p> <h3>Biome</h3> <p>This project feels like a game changer for linting. We’ve seen several come and go, with the most popular ones being ESLint, Prettify, and Stylelint in 2024. However, Biome is positioning itself to be one tool to lint it all.</p> <p><a href="https://biomejs.dev/blog/annoucing-biome/">The background is interesting</a> and <a href="https://biomejs.dev/blog/biome-wins-prettier-challenge/">having won a contest set up by the Prettier folks</a>, Biome has a strong position going forward. I expect some breaking features as it continues to mature, but it’s also stable enough for a large majority of linting rules that I already don’t miss ESLint. As of June 2024, the CSS linting is in its first public beta release, so it’ll be some time before that’s mature enough to replace Stylelint, but I fully intend to migrate over when it’s stable.</p> <h4>Vite and Biome Node Packages</h4> <p>The most exciting thing about both Vite and Biome is reduced complexity. Just by replacing Webpack and ESLint with Vite and Biome, respectively, <code class="language-json">/node_modules/</code> was reduced by more than 50%. In fact, I think even more packages were removed from the project overall. This is a big win.</p> <p>Once CSS linting is stable, this is what <code class="language-json">devDependencies</code> looks like in <code class="language-json">package.json</code>:</p> <pre><code class="language-json"> "devDependencies": { "@biomejs/biome": "^1.8.0", "glob": "^10.4.1", "vite": "^5.2.12" }</code></pre> <p>That’s refreshing!</p> <h3>Modern CSS & JavaScript</h3> <p>I have purposely included no libraries, frameworks, or packages to abstract CSS or Javascript. This might be considered silly or naive, but if you review both CSS and JS in 2024, the languages are powerful enough that the need for additional state management or other helpers and shortcuts is far less than before. I expect sometime in 2025 that so much will be supported across all browsers that we’re going to see some significant paradigm shifts in the need to use large frameworks or libraries.</p> <p>In fact, for my own site, I’ve removed Sass completely. Because nesting is widely supported in modern browsers, all I did was convert Sass variables to native CSS Custom Properties and everything just worked. Having reviewed the site in non-supporting browsers that don’t have modern CSS syntax features, progressive enhancement is the winner because all content and functionality is still available even if it doesn’t look as pretty.</p> <p>Regardless, it’s quite easy to just <code class="language-bash">yarn add svelte</code> or any other library if you need it.</p> <h3>DocHooks</h3> <p>From the FootMATE creator, DocHooks are an interesting syntactic sugar for functions and methods to the WordPress APIs using DocBlocks.</p> <pre><code class="language-php"> /** * Loads default theme supports * @action after_setup_theme */ public function addThemeSupport() { /* add logic here */ }</code></pre> <p>The part that says <code class="language-php">@action after_setup_theme</code> is the same as writing <code class="language-php">add_action( 'after_setup_theme', 'addThemeSupport, 10, 3 );</code>. It’s a big cleaner and easier to parse the functions this way.</p> <p>Currently, DocHooks only support adding to the API. If you need to remove, you still have to write <code class="language-php">remove_action('after_setup_theme', 'addThemeSupport');</code></p> <h3>IndieWeb</h3> <p>I’ve added as much Microformats2 syntax to the markup as I could so that you add a few plugins and it’ll be indieweb compatible almost immediately after setting up the pieces. We should own as much of our own content as we can.</p> <h2>Background</h2> <p dir="auto">The Roots Sage project provided an excellent philosophy and approaches for a progressively developed WordPress theme, but after version 9, Sage had too many interconnected pieces, new dependencies, and legacy to keep up with. Additionally, having focused on so many other returning to an old version of Sage left much to be desired, as well as plenty of broken services or packages.</p> <p dir="auto">I found FootMATE in spring of 2024 looking for an alternative. Strangely, it follows enough of a paradigm similar to Sage that it feels like a younger cousin. Also, the author decided to integrate Vite instead of Webpack, and that’s a huge win for productivity and DX.</p> <p dir="auto">The combination of the two themes satisfies my desire for good file architecture and modern tooling without much bloat or dependencies. It just works.</p> <p dir="auto">WordPress’ direction towards full-site editing and Gutenberg leaves much to be desired for developers working on WordPress. This theme, while starting from a basis of the classic theme structure, has a lot of flexibility between the two worlds of classic and modern WordPress theme development.</p> <h2 dir="auto">The Future</h2> <p>I’m going to continue development on this theme indefinitely, as both FootMATE and Sage deliver new updates that make sense for this theme. Additionally, I already have a <a href="https://github.com/asuh/forage/issues">number of Github issues</a> that I hope to resolve or bring into the theme.</p> <p>Ultimately, I’ll probably slow down on development for this theme soon and maintain things as time goes on. Who knows, I might support this for several years to come. I don’t have all the experience or expertise for some of the integrations I am questioning or interested in, so community help will be desired where possible. That said, I’ll keep an open mind about how to continue on with this starter theme.</p> <p>I’m eager to hear any feedback or comments on the direction this theme is going and how to make it better. It solves my personal needs here on asuh.com but it’ll be interesting to see what appeal it has outside of what I needed.</p> <p>Thanks for your support and eyeballs on this post!</p> </div><!-- .main-content --> <div class="entry-meta"> <span class="posted-on"> <a class="u-url" href="https://asuh.com/forage/"> <svg xmlns="http://www.w3.org/2000/svg" width="12" height="12" class="hyperlink" viewBox="0 0 32 32"><path fill="currentColor" d="M13.8 19.9a1.6 1.6 0 0 1-1.2-.5c-3-3-3-7.8 0-10.8l6-6a7.6 7.6 0 0 1 10.8 0c3 3 3 7.8 0 10.8L26.6 16a1.6 1.6 0 1 1-2.2-2.3l2.7-2.7a4.4 4.4 0 0 0 0-6.2 4.3 4.3 0 0 0-6.2 0l-6 6a4.4 4.4 0 0 0 0 6.2 1.6 1.6 0 0 1-1.1 2.8z"/><path fill="currentColor" d="M8 31.6a7.6 7.6 0 0 1-5.4-2.2c-3-3-3-7.8 0-10.8L5.4 16a1.6 1.6 0 1 1 2.2 2.3L5 20.9a4.4 4.4 0 0 0 0 6.2 4.3 4.3 0 0 0 6.2 0l6-6a4.4 4.4 0 0 0 0-6.2 1.6 1.6 0 1 1 2.3-2.3c3 3 3 7.8 0 10.8l-6 6A7.6 7.6 0 0 1 8 31.6z"/></svg><time class="entry-date dt-published" datetime="2024-06-07T08:52:15-07:00"><span class="date-month-day">June 7th</span> <span class="date-year">2024</span></time> </a> </span> <span class="comments-link"> </span> <ul class="relsyn"><li><a aria-label="mastodon" class="u-syndication syn-link" href="https://mastodon.social/@asuh/112576138407041583"> <span class="syndication-link-icon svg-mastodon" style="display: inline-block; max-width: 1rem; margin: 2px;" aria-hidden="true" aria-label="Mastodon" title="Mastodon" ><svg role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><title>Mastodon</title><path d="M23.268 5.313c-.35-2.578-2.617-4.61-5.304-5.004C17.51.242 15.792 0 11.813 0h-.03c-3.98 0-4.835.242-5.288.309C3.882.692 1.496 2.518.917 5.127.64 6.412.61 7.837.661 9.143c.074 1.874.088 3.745.26 5.611.118 1.24.325 2.47.62 3.68.55 2.237 2.777 4.098 4.96 4.857 2.336.792 4.849.923 7.256.38.265-.061.527-.132.786-.213.585-.184 1.27-.39 1.774-.753a.057.057 0 0 0 .023-.043v-1.809a.052.052 0 0 0-.02-.041.053.053 0 0 0-.046-.01 20.282 20.282 0 0 1-4.709.545c-2.73 0-3.463-1.284-3.674-1.818a5.593 5.593 0 0 1-.319-1.433.053.053 0 0 1 .066-.054c1.517.363 3.072.546 4.632.546.376 0 .75 0 1.125-.01 1.57-.044 3.224-.124 4.768-.422.038-.008.077-.015.11-.024 2.435-.464 4.753-1.92 4.989-5.604.008-.145.03-1.52.03-1.67.002-.512.167-3.63-.024-5.545zm-3.748 9.195h-2.561V8.29c0-1.309-.55-1.976-1.67-1.976-1.23 0-1.846.79-1.846 2.35v3.403h-2.546V8.663c0-1.56-.617-2.35-1.848-2.35-1.112 0-1.668.668-1.67 1.977v6.218H4.822V8.102c0-1.31.337-2.35 1.011-3.12.696-.77 1.608-1.164 2.74-1.164 1.311 0 2.302.5 2.962 1.498l.638 1.06.638-1.06c.66-.999 1.65-1.498 2.96-1.498 1.13 0 2.043.395 2.74 1.164.675.77 1.012 1.81 1.012 3.12z"/></svg></span></a></li><li><a aria-label="bluesky" class="u-syndication syn-link" href="https://bsky.app/profile/asuh.com/post/3kudvtoexpc2m"> <span class="syndication-link-icon svg-bluesky" style="display: inline-block; max-width: 1rem; margin: 2px;" aria-hidden="true" aria-label="Bluesky" title="Bluesky" ><svg role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><title>Bluesky</title><path d="M12 10.8c-1.087-2.114-4.046-6.053-6.798-7.995C2.566.944 1.561 1.266.902 1.565.139 1.908 0 3.08 0 3.768c0 .69.378 5.65.624 6.479.815 2.736 3.713 3.66 6.383 3.364.136-.02.275-.039.415-.056-.138.022-.276.04-.415.056-3.912.58-7.387 2.005-2.83 7.078 5.013 5.19 6.87-1.113 7.823-4.308.953 3.195 2.05 9.271 7.733 4.308 4.267-4.308 1.172-6.498-2.74-7.078a8.741 8.741 0 0 1-.415-.056c.14.017.279.036.415.056 2.67.297 5.568-.628 6.383-3.364.246-.828.624-5.79.624-6.478 0-.69-.139-1.861-.902-2.206-.659-.298-1.664-.62-4.3 1.24C16.046 4.748 13.087 8.687 12 10.8Z"/></svg></span></a></li><li><a aria-label="x" class="u-syndication syn-link" href="https://twitter.com/asuh/status/1799108439773512051"> <span class="syndication-link-icon svg-x" style="display: inline-block; max-width: 1rem; margin: 2px;" aria-hidden="true" aria-label="X" title="X" ><svg role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><title>X</title><path d="M18.901 1.153h3.68l-8.04 9.19L24 22.846h-7.406l-5.8-7.584-6.638 7.584H.474l8.6-9.83L0 1.154h7.594l5.243 6.932ZM17.61 20.644h2.039L6.486 3.24H4.298Z"/></svg></span></a></li></ul> </div><!-- .entry-meta --> </article> <nav class="navigation posts-navigation" aria-label="Posts"> <h2 class="screen-reader-text">Posts navigation</h2> <div class="nav-links"><div class="nav-previous"><a href="/page/2/" >Older</a></div></div> </nav> </main> <footer class="content-info"> <section class="container"> <div class="copyright"> <p>© <a href="https://asuh.com/" rel="me">asuh.com</a></p> </div> <script> window.onload = function() { setTimeout(function() { window.performance = window.performance || window.mozPerformance || window.msPerformance || window.webkitPerformance || {}; const t = performance.timing || {}; if (!t) { return; } const loadTime = (t.loadEventEnd - t.navigationStart) / 1000; const markup = `This page loaded in <b>${loadTime}</b> seconds`; const copyright = document.querySelector('.copyright'); const p = document.createElement('small'); p.innerHTML = markup; copyright.appendChild(p); }, 0); }; </script> <div> <a href="https://xn--sr8hvo.ws/%E2%AC%86%EF%B8%8F%F0%9F%8D%AF%F0%9F%8F%8E/previous">←</a> An IndieWeb Webring 🕸💍 <a href="https://xn--sr8hvo.ws/%E2%AC%86%EF%B8%8F%F0%9F%8D%AF%F0%9F%8F%8E/next">→</a> </div> </section> </footer> <script type="speculationrules"> {"prefetch":[{"source":"document","where":{"and":[{"href_matches":"\/*"},{"not":{"href_matches":["\/wp\/wp-*.php","\/wp\/wp-admin\/*","\/wp\/wp-content\/uploads\/*","\/wp\/wp-content\/*","\/wp\/wp-content\/plugins\/*","\/wp\/wp-content\/themes\/forage\/resources\/*","\/*\\?(.+)"]}},{"not":{"selector_matches":"a[rel~=\"nofollow\"]"}},{"not":{"selector_matches":".no-prefetch, .no-prefetch a"}}]},"eagerness":"conservative"}]} </script> <script src="/wp/wp-content/mmr/a8a16f78-1743619603.min.js"></script> </body> </html> <!-- Dynamic page generated in 1.059 seconds. --> <!-- Cached page generated by WP-Super-Cache on 2025-05-15 11:56:11 --> <!-- Super Cache dynamic page detected but late init not set. See the readme.txt for further details. --> <!-- Dynamic Super Cache -->