Paco Coursey

Follow this blog

macOS Color Picker

After trying many apps, my favorite macOS color picker remains the built in utility. It's only shown while editing in specific applications though, so here's how you can turn it into a dedicated app. Open Script Editor and create a new document Enter choose color Save as an Application in your Applications folder Launch your new Color Picker application. I use the second tab with RGB Sliders to easily copy the hex code. Pressing escape closes the app. That's it. No installation necessary, the colors are always accurate, and you can even save a few favorites to the grid at the bottom.

SVG Caching with

I had an idea for caching SVG paths. Not the usual kind of async request caching of remote SVGs, but local re-use of DOM elements that have already rendered. SVG's <use> element allows re-use of an existing DOM element, without manually duplicating the node. It works like this: <!-- Add an id to the element --> <svg> <circle id="circle" cx="5" r="5" fill="black" /> </svg> <!-- Pass the id as href to <use> --> <svg> <use href="#circle" /> </svg> <!-- The same SVG renders twice --> Setup When using an icon set like Feather in React, I prefer to use a higher-order component (HOC) and a generic Icon component to render each icon with consistent properties. We'll use this HOC to demonstrate SVG caching: import { memo } from 'react' const withIcon = (icon, opts) => { const Icon = props => { const { size = 24, color = 'currentColor' } = props return ( <svg viewBox="0 0 24 24" width={size} height={size} stroke="currentColor" style={{ color }} dangerouslySetInnerHTML={{ __html: icon }} /> ) } return memo(Icon) } export default withIcon Each icon is simply the SVG contents wrapped with the HOC: const ArrowLeft = withIcon('<path d="M21 12H3m0 0l6.146-6M3 12l6.146 6" />') Caching We'll use React context to add an icon cache. First, create a new context and the appropriate hook to access it: export const IconCache = React.createContext(null) export const useIconCache = () => React.useContext(IconCache) Setup the provider at the application root. The cache will be a plain, empty object where each key is the icon string and each value is the cached id. const App = () => ( <IconCache.Provider value={{}}>{/* ... */}</IconCache.Provider> ) Inside of Icon, read the cache from context and check if this icon has a cached id. If not, generate the new id and add it to the cache: const cache = useIconCache() let cachedId = cache[icon] if (!cachedId) { cachedId = `icon-` + hash(icon).toString(16) cache[icon] = cachedId } Generate a stable id by hashing the icon using the fnv1a 1 algorithm (commonly used in CSS-in-JS libraries) and then converting it to hexadecimal for a smaller string: import hash from 'fnv1a' If we have a cached id, we can render the <use> tag instead of inserting the entire icon again. If this icon has not rendered before, wrap it in a group tag and attach the unique id. return ( <svg viewBox="0 0 24 24" width={size} height={size} stroke="currentColor" style={{ color }} dangerouslySetInnerHTML={{ __html: cachedId ? `<use href="#${cachedId}" />` : `<g id="${id}">${icon}</g>` }} /> ) Conclusion Here's our new withIcon HOC with caching: import { memo } from 'react' import hash from 'fnv1a' export const IconCache = React.createContext({}) export const useIconCache = () => React.useContext(IconCache) const withIcon = icon => { const Icon = props => { const { size = 24, color = 'currentColor' } = props const cache = useIconCache() const cachedId = cache[icon] let id if (!cachedId) { id = 'icon-' + hash(icon).toString(16) cache[icon] = id } return ( <svg viewBox="0 0 24 24" width={size} height={size} stroke="currentColor" style={{ color }} dangerouslySetInnerHTML={{ __html: cachedId ? `<use href="#${cachedId}" />` : `<g id="${id}">${icon}</g>` }} /> ) } return memo(Icon) } export default withIcon Rendering the same icon multiple times will reuse existing DOM elements, decreasing the size of your HTML: /* React */ <IconCache.Provider value={{}}> <ArrowLeft /> <ArrowLeft /> <ArrowLeft /> </IconCache.Provider> /* HTML Output: <svg> <g id="icon-dacb5a47"><path d="M21 12H3m0 0l6.146-6M3 12l6.146 6" /></g> </svg> <svg> <use href="#icon-dacb5a47" /> </svg> <svg> <use href="#icon-dacb5a47" /> </svg> */ In this example, the cached version is about 40% fewer characters! You can still customize each icon, because the props apply to the outer svg element and don't involve the inner elements at all: <ArrowLeft /> <ArrowLeft size={30} color="blue" /> <ArrowLeft size={50} color="red" /> Here's a live demo and the demo source code. You don't have to use fnv1a, any stable id generation technique will work. Just make sure it's consistent between server and client to avoid hydration mismatch.

Custom CSS via Serverless Proxy

If you want to add custom CSS to a website without using a browser extension, you can proxy the site using a serverless function and inject a new stylesheet. I love Aaron Swartz's blog, but the font size is tiny, the content is not centered, and the colors aren't late-night friendly. Let's improve it. Create api/index.js and add a server-side fetching library like node-fetch: const fetch = require('node-fetch') module.exports = (req, res) => { res.end() } Fetch the HTML of the actual site: module.exports = (req, res) => { const html = ( await (await fetch('http://aaronsw.com' + req.url)).text() ) res.end() } Add a link tag to the head: const html = ( await (await fetch('http://aaronsw.com' + req.url)).text() ).replace( '</head>', '<link media="all" href="/custom.css" rel="stylesheet" /></head>" ) Return the modified HTML. Use .send instead of passing the string to .end so that the correct content headers are set. res.send(html) If the website content you're proxying doesn't update frequently, you should add caching of your serverless function's response. Aaron passed away a few years ago, so his blog isn't updated anymore. The final function looks like this: const fetch = require('node-fetch') module.exports = async (req, res) => { const html = ( await (await fetch('http://aaronsw.com' + req.url)).text() ).replace( '</head>', '<link media="all" href="/custom.css" rel="stylesheet" /></head>' ) // 1 year res.setHeader('Cache-Control', 'max-age=0, s-maxage=31536000') res.send(html) res.end() } Add your custom CSS in a custom.css file. Deploy Create a vercel.json configuration file that rewrites all requests to your deployment through our api/index serverless function: { "rewrites": [{ "source": "/(.*)", "destination": "/api" }] } Deploy with Vercel: $ vercel Visit your deployment to see the proxy in action. My Aaron Swartz blog proxy is available here: aaronsw.now.sh/weblog/archive.

Shared Hook State with SWR

SWR is a React hook for data fetching that features a cache for requests. This is generally used to share the response from API calls and deduplicate requests, but SWR is flexible enough to support another use case: shared hook state. 1 Let's look at an example of a useUsername hook: const useUsername = () => { return useState('') } const UsernameInput = () => { const [username, setUsername] = useUsername() return ( <div> <input value={username} onChange={setUsername} /> </div> ) } const DisplayUsername = () => { const [username] = useUsername() return ( <span>Username: {username}</span> ) } This won't work, because each time we call useUsername, we receive a new instance of state. Updating the input won't affect what our DisplayUsername component renders. Solving with Context With React context, we typically lift the username state to the highest level and useContext to read the value in our components: const UsernameContext = createContext() const App = () => ( <UsernameProvider> {/* ... */} </UsernameProvider> ) const UsernameProvider = ({ children }) => { const [username, setUsername] = useState('') return ( <UsernameContext.Provider value={[username, setUsername]}> {children} </UsernameContext.Provider> ) } const DisplayUsername = () => { const [username] = useContext(UsernameContext) return ( <span>Username: {username} ) } This will work, but in big applications you'll end up with a lot of context. Solving with SWR We can simulate useState with SWR by using the mutate function as our setState, and the config.initialData option the initial state. Now when we call mutate, the updated data will be reflected everywhere the hook is used. import useSWR from 'swr' const useUsername = () => { const { data: username, mutate: setUsername } = useSWR('username', { initialData: '' }) return [username, setUsername] } It works, no context required. Every useUsername will share the same state, and calling setUsername will update the state across all uses of the hook. useSharedState We can go one step further and build a shared addition to useState: const useSharedState = (key, initial) => { const { data: state, mutate: setState } = useSWR(key, { initialData: initial }) return [state, setState] } Use it like useState, but pass a key as the first argument: const [username, setUsername] = useSharedState('username', 'paco') const [os, setOS] = useSharedState('os', 'macos') SWR is mainly used to manage remote data requests, but it also provides a powerful cache and API that you can use to share local state between hooks. Kudos to Shu for his excellent work! Two components using the same React hook don't share state by default. SWR uses a client-side only cache, so your data won't persist between sessions or windows unless you keep external state like localStorage, at which point SWR may not be useful.

CSS Previous Sibling Selector

There is no previous sibling selector in CSS. Instead, we can achieve the same behavior by using flexbox and the order property. Let's say you're adding a prefix to an input, and would like to style the prefix when the input is focused. If you read from left to right and top to bottom (English), you likely structure your DOM like that too: <div class="container"> <div class="prefix">https://</div> <input type="text" /> </div> https:// In this markup, there's no way to target the .prefix class using input:focus, because we have no preceding selector. Instead, we can rewrite the DOM structure so that prefix appears after the input: <div class="container"> <input type="text" /> <div class="prefix">https://</div> </div> And use flexbox to change the order of appearance: .container { display: flex; } .container input { order: 1; } .container .prefix { order: 2; } Now you can select the prefix using the sibling selector: .container input:focus + .prefix { /* Focus styles... */ } https:// In the case of an input, the simple solution is to use :focus-within, which has good browser support but is still experimental. Maybe you have other use cases for this trick though, let me know! This post is inspired by my own work on inputs, and this paragraph: Unfortunately, trying to use :focus limits what you can do: you can style the input or siblings that come after the input… but that’s it. — Initializing focus state in React .example { border-radius: var(--radius); background: var(--lighter-gray); display: flex; align-items: center; justify-content: center; padding: var(--gap); } .example .container { display: flex; align-items: center; } .example input { height: 2.5rem; font-size: 1rem; border-radius: 0 var(--inline-radius) var(--inline-radius) 0; background: var(--bg); color: var(--fg); border: 1px solid var(--light-gray); padding: 0 var(--gap-half); outline: none; transition: border-color var(--transition); display: flex; align-items: center; justify-content: center; margin: 0; } .example input:focus { border-color: var(--gray); } .example .prefix { background: var(--lightest-gray); border-radius: var(--inline-radius) 0 0 var(--inline-radius); padding: 0 var(--gap-half); height: 2.5rem; font-size: 1rem; line-height: normal; display: flex; align-items: center; justify-content: center; border: 1px solid var(--light-gray); border-right: 0; user-select: none; color: var(--gray); transition: color var(--transition); margin: 0; } .example .container.fixed input { order: 1; } .example .container.fixed .prefix { order: 0; } .example .container.fixed input:focus + .prefix { color: var(--fg); }

Disable transitions on theme toggle

It's difficult to transition between themes smoothly. Adding a CSS transition to every element negatively impacts rendering performance, and it also won't work for images, icons, and CSS properties that don't support transitions. Instead, we can temporarily remove transitions from all elements so that toggling themes feels snappy and consistent. We'll manually create a stylesheet that disables transitions: const css = document.createElement('style') css.type = 'text/css' css.appendChild( document.createTextNode( `* { -webkit-transition: none !important; -moz-transition: none !important; -o-transition: none !important; -ms-transition: none !important; transition: none !important; }` ) ) document.head.appendChild(css) Note that we need to manually specify browser prefixes, as this CSS isn't run through any preprocessing. After changing the theme (usually this involves toggling a class on <body>), we force a browser repaint and remove the stylesheet: // Toggle the theme here... // Calling getComputedStyle forces the browser to redraw const _ = window.getComputedStyle(css).opacity document.head.removeChild(css) Calling requestAnimationFrame before removing the stylesheet seemed to work at first, but it was unreliable and elements still transitioned. Using getComputedStyle works reliably on every major browser, because it forcibly applies all active stylesheets. Before: After (or press t to try it yourself): Thanks to Guillermo for the idea!

Better Next.js Imports

Nine days after first writing this post, the Next.js team landed support for paths in tsconfig.json and jsconfig.json by default! In Next.js 9.4 and onwards, you only need to specify a baseURL in your config file to support absolute imports: // tsconfig.json or jsconfig.json { compilerOptions: { "baseURL": "." } } // import Button from 'components/button' To use a custom prefix, add a paths configuration: { compilerOptions: { "baseURL": ".", "paths": { "@components/*": ["components/*"] } } } // import Button from '@components/button' Editors like VSCode automatically support the config in jsconfig.json, so Command+Click to jump to the source of a file will work as usual. Atom and IntelliJ also have support for rewrites. The original post, using a babel plugin. Relative import statements are a pain. To avoid ../ chains, improve code portability, and type less, I've started using babel-plugin-module-resolver in my Next.js projects. The goal is to transform verbose import statements like this: import Button from '../../../../components/button' into absolute import statements that work anywhere in your project: import Button from '@components/button' Let's do it. Install the babel plugin as a devDependency: $ yarn add babel-plugin-module-resolver -D In the root of your Next.js project, create a .babelrc.json file and add the module-resolver plugin: module.exports = { presets: ['next/babel'], plugins: [ [ 'module-resolver', { alias: { '@components': './components' } } ] ] } Create a jsconfig.json (or tsconfig.json if you're using TypeScript) and add the paths property: { "compilerOptions": { "baseUrl": ".", "paths": { "@components/*": ["components/*"] } } } Note that the syntax is slightly different than the babel config. If you're using a mixed JS/TS codebase, you should include JS files in your tsconfig.json: { "include": ["**/*.ts", "**/*.tsx", "**/*.js", "**/*.jsx"] } Now you can update your import statements to use the new syntax!

Custom text underlines

The text-decoration: underline CSS property provides insufficient control over the underline styling and position. While we wait for the CSS Text Decoration Module specification to become standard, we must rely on custom implementations. My favorite approach is to use a linear-gradient to create an underline: background-image: linear-gradient(gray, gray); background-size: 100% 1px; background-position: left bottom; background-repeat: no-repeat; Day by day, what you do is what you become. Position Position the underline by changing the vertical value of background-position: background-position: left 1.05em; Day by day, what you do is what you become. Descenders You'll notice that the underline overlaps the descenders of the text. By adding a text-shadow with a small offset to the right and left with the color of the background, you can hide the underline around descenders. text-shadow: 0.1em 0 var(--background), -0.1em 0 var(--background); Day by day, what you do is what you become. Remember to set text-shadow: none in your ::selection rules. Weight Change the height of the background to increase the underline weight: background-size: 100% 0.25em; Day by day, what you do is what you become. Dashes By using a repeating-linear-gradient and leaving half the gradient transparent, you can customize a dashed underline: background-image: repeating-linear-gradient( to right, var(--gray) 0%, var(--gray) 50%, transparent 50%, transparent 100% ); background-size: 1ch 1px; Day by day, what you do is what you become. Change the horizontal value of background-size to modify the dash width: background-size: 5ch 1px; Day by day, what you do is what you become. The ch unit is equal to the width of the "0" glyph in the current font, which can be useful for natural alignment. Wrapping Lastly, this approach also supports multi-line text: Day by day, what you do is what you become. Let me know if you end up using this, or read more about other approaches in "Crafting link underlines on Medium." Thanks to Franco for reminding me about this technique! .l { background: var(--lighter-gray); width: 100%; height: 100px; display: flex; justify-content: center; align-items: center; border-radius: var(--radius); font-size: 1.25rem; color: var(--fg); text-align: center; } .l span { background-image: linear-gradient(var(--gray), var(--gray)); background-size: 100% 1px; background-position: left bottom; background-repeat: no-repeat; } .l._2 span { background-position: left 1.05em; } .l._3 span { text-shadow: 0.1em 0 var(--lighter-gray), -0.1em 0 var(--lighter-gray); } .l._4 span { background-size: 100% 0.25em; } .l._5 span { background: repeating-linear-gradient( to right, var(--gray) 0%, var(--gray) 50%, transparent 50%, transparent 100% ); background-repeat: repeat-x; background-size: 1ch 1px; background-position: bottom left; } .l._6 span { background-size: 2ch 1px; }

Thoughtless

I have trouble falling asleep. Too many ideas and thoughts from a day with too little activity, I suspect. Writing down my thoughts helps me clear my mind. Thoughtless is an experiment, created on a sleepless night, to help me note my thoughts without interruption. By making each typed word disappear, there is no overediting or obsessing over sentence structure. Record your raw thoughts — no going back. When you finish, copy and paste your writing somewhere safe and sleep well.

Styled System with styled-jsx

Styled System is an excellent alternative to writing ad-hoc style declarations in your React components. By giving components standardized props like bg and fontSize, it's easier to build custom UI that respects your system constraints. That's because you can quickly specify your design tokens and use them in real code: // theme.js colors: { blue: '#0070F3' } // your React code <Box color="blue" /> Styled System's responsive syntax is impressively concise, too: // 16px on mobile, 14px on tablet, 12px on desktop <Box fontSize={[16, 14, 12]} /> These two features make it extremely easy to scaffold new components. I want to use Styled System with styled-jsx, because styled-jsx is included with Next.js, and I use Next.js for everything React. But all the Styled System tooling I found was for styled-components or Emotion, so I made my own. styled-jsx-system styled-jsx-system lets you use Styled System with styled-jsx. $ yarn add styled-jsx-system Wrap your components with the provided HOC and accept a className prop: import withStyledSystem from 'styled-jsx-system' import { color } from 'styled-system' const Box = ({ className, children }) => { return ( <div className={className}> {children} <style jsx>{` div { padding: 8px; } `}</style> </div> ) } export default withStyledSystem(Box, [color]) That's it! You can now use Styled System props with your Box component: <Box color={['#000', '#666', '#fff']}>Hello</Box> Other Styled System features like compose, system, and themeing are supported too. Check out the repository for more information. Cool. Let me know if you end up using it. Thanks to jxnblk for Styled System and all his cool CSS experiments, and thanks to Giuseppe, JJ, and Shu for help with compiling and publishing!

Write it down

My crappy superpower is solving difficult problems as I'm falling asleep. Doesn't sound too bad, right? Here's the catch: I always convince myself I don't need to write the solution down. It's 1:18 AM. I just figured it out. The answer is so simple, I can't believe it took me this long. Do I blind myself opening my phone to write it down? No, I can finally sleep now! There's no way I'll forget. It's 8:32 AM. I can't believe I've done this again. I have a new policy: write it down. Every single time. No matter if the idea comes to me in the shower, the middle of a dream, or in a conversation. Most of my ideas are bad. But this way I'll never miss an opportunity.

On Gaming

A favorite quote from an old friend. I really admire that there are people of all ages that are able to get along, without awkwardness, without serious fighting, and share a common interest, whilst in completely different parts of the world. I mean, isn't it just amazing that we all have a different background, a different upbringing, a different future, and yet we all united at this point in time to share an interest, as futile as it may seem, and be passionate about it? What a life! — Giles

Good Code

I find great satisfaction in writing beautiful code. Very few will ever see this effort and appreciate it, but it is deeply gratifying. We can tell whether our code is high quality. We can predict how often and when it will need to be revisited, whether our coworkers can easily understand it, whether it is easy to use and extend, and whether it meets our personal standards of completeness and correctness. This type of creative output is quickly becoming more important to me. It is a different type of aesthetic, less superficial and more fulfilling. I like to think of good code as the walls on which many coats of paint will be applied. Good code should outlast us, when many designs will not. It's almost ethical — deeply considering how we leave the codebase for our future selves or others.

Good Writers

Have you noticed that some people write extremely well? Take Aaron Swartz' article "Believe you can change": Carol Dweck was obsessed with failure. What an amazing first sentence. I'm immediately glued to this article. Who is Carol Dweck? What's wrong with her? If I were writing that, I'd start with the immediately boring: Carol Dweck is a Professor of Psychology at Stanford, studying the behavior of children and how they deal with failure. Because I have a lot of practice writing in this dull manner that meets school requirements. But I'm already bored reading it. I'm learning to recognize good writing, and I'm fascinated. We all use the same set of words, but some writers are so much better at using them.

Creative Output

I am consistently unhappy with my creative output. My job title includes designer, but I'm not good at designing something from scratch. None of work I create matches up to the work of designers that I admire. At a minimum, I want to feel more comfortable designing work that meets my own minimum expectations of quality. Impostor Syndrome probably plays a big part (especially working with such talented colleagues!) but maybe I simply need practice. Creativity is not my strong suit. I'm logical. Building on past experience to improve future work is something I am good at. Creating something new is not. That's why it feels like everything I create is a remix of my past work, or the work of others. Does this still count as my creative output, though? I'd argue that anything new in design is just old stuff reworked in new ways. Buried in sarcasm, Mark Dalgleish explains that step in the design process: If you're a developer who finds design difficult, you're probably skipping the "inspiration" phase—which, in non-designer speak, roughly translates to "look at other designs and rip off all the good ideas". This is a totally valid way to work. It's probably the most efficient. You're not the first person working on your problems, so use what other people have already discovered. But to what degree can we claim this work as our own?

Persistent Custom App Icons

I created Dusk to make my dock look more visually harmonious. LiteIcon does a great job of automating the icon changing process, but every time I opened Discord, the dock icon reverted back to default. Not cool. It happens to other Electron applications (Hyper, VSCode) over time. Even Safari reverts back occasionally. It's frustratingly ugly. Let's fix it. Find the application in Finder and right click to "Show Package Contents". Navigate to Contents/Resources/. Here, electron.icns is the culprit. Let's replace it with our custom icon. We'll need to convert our custom .png icon from Dusk (or anywhere else) to an .icns file. MacOS ships with the command line tool sips to help with this. Run the following from the command line, replacing ICON as needed. sips -s format icns ICON.png --out ICON.icns Move your new .icns file into the previously opened Resources/ folder. I like to save the old icon by renaming it, just in case I have to revert later. Rename your new file to match the old (in this case, electron.icns). Restart the app, and your custom application icon should persist!

Understanding package.json

I began my Computer Science degree with an intensive introduction course in C. We used makefiles to compile and run each of our assignments. When I started learning modern web development in early 2018, I had no idea what Node.js or NPM was. My idea of building website involved writing HTML, CSS, and occasionally including a script tag. A year or so later, I'm finally comfortable with modern techniques. A major source of confusion for me was package.json. In short, package.json is a makefile for the JavaScript environment, with some caveats. Package Scripts Package managers like Yarn and NPM also serve as script runners for JavaScript projects. Unlike makefiles, scripts in package.json run in a special environment. Packages in node_modules that define an executable will have that executable appended to the environment PATH before running any scripts. This can be confusing. Let's see an example: "devDependencies": { "eslint": "1.0.0" }, "scripts": { "lint": "eslint ." } Running yarn lint will work correctly. However, just running eslint . from the command line will fail!1 This was extremely confusing at first, did I have ESLint installed or not? The package script will work because Yarn recognizes that the ESLint dependency includes an executable, and appends it to the environment PATH when running any scripts. This is a great advantage of the modular nature of the JavaScript ecosystem. You don't have to install any global scripts or clutter up your PATH to work with JavaScript projects, just yarn install. Unless you have installed ESLint globally, which does add the executable to your PATH (yarn global add eslint)