If you want the union type of all the types of the values in another type in typescript you can use the keyof operator.
type Thing = {
foo: string;
bar: boolean;
}
type ThingTypes = Thing[keyof Thing];
// string | boolean
Small victories worth celebrating because they make the journey worthwhile.
If you want the union type of all the types of the values in another type in typescript you can use the keyof operator.
type Thing = {
foo: string;
bar: boolean;
}
type ThingTypes = Thing[keyof Thing];
// string | boolean
If you have force pushed changes to a git branch on the remote and want to pull that branch into your local you can do it in two commands.
git fetch && git reset --hard @{u}
This will fetch the latest changes then reset the current branch with the latest of that same branch from the origin.
The other day I learned a neat trick. Note this will work in many other editors as well.
I needed to remove the type case at the end of an object in TypeScript (JavaScript) so I
created a regex to find what I wanted, an export default {, then whatever including line breaks,
then } as Meta. I grouped the part before the as Meta and used the group identifier $1 in
the VSCode replace box to replace all occurrences of my regex with everything before the as Meta.
Here's my find:
(export default \{(.|\n)*\})( as Meta)
Notice the parentheses around the whole first part separating it from the as Meta.
Then in the replace just put $1 to replace all occurrences with the content of the first group.
The other day I was looking through a repo and stumbled across someone using Vercel's open graph image generator, something I had no idea existed. I was able to set it up and replace my own implementation of something similar on my blog in an evening. My implementation involved generating images at build time with Gatsby, why I ever thought that was a good idea is beyond me.
This allows you generate unique open graph images for each one of your blog posts or pages and set it in meta tags. The meta tag in my blog posts now looks like this:
<meta
property='og:image'
content={OpenGraph.generateImageUrl(post.frontmatter.title)}
/>
Small tip here is to fork and deploy your own version of this repo so you can
change the default image. Change this line:
if (!images[0].startsWith('https://assets.vercel.com/') && !images[0].startsWith('https://assets.zeit.co/')) {
in api/_lib/parser.ts.
P.S. Also a friendly reminder that this will not work if your pages are not viewable server-side meaning you're using straight Vue or React to render your entire site. Each page needs to have a viewable html file stored, this is static generation or server side generation.
Sometimes you have single digit numbers that your want to add a leading 0 to for whatever reason. For example if you're dealing with dates and aren't using a date library with formatting.
This simple script will take the index of the month you have (where January = 0) and return '01' instead of '1' and will ignore numbers with 2 digits.
const twoDigitMonth = ("0" + (monthIndex + 1)).slice(-2);
Effectively this adds a 0 at the beginning of the string and returns 2 characters starting from the end of the string.
This last weekend I learned how window balancers work. My windows are Anderson brand but I think it's similar for most other windows. The problem was the pane continualy falling down when I tried to open them. For years I've just been opening the top window since the bottom wouldn't stay open. I finally was able to remove both panes, slide the little cover down to expose the balancer inside the sash, and reconnect the string on the balancer to the balance shoe (the thing that slides up and down that the window sash sits in). Somehow the string had become disconnected so the spring in the balancer wasn't doing anything to hold the windows up. It was a bit of a pain but didn't take too long. Just surprised there was very little documentation on this online. Pretty sure I have Anderson 400 Series Tile-Wash double hung windows.
This picture shows the string connecting to the balance shoe.

This video gives a good visual of what I'm talking about although isn't really the problem I had: https://youtu.be/kjJ50qKMaqw
import Link from 'gatsby-link';
I was gonna write this here but then just made a blog post,
Click here to readRecently learned you can view up to 49 people silmultaneously in Google Meet. Click the three dots in the bottom right corner and click "Change Layout". In that modal click "Tiled" and move the slider all the way to the right. Now you can look at everyone picking their nose at the same time!
I was having issues running Puppeteer on my new M1 Apple Mac. Turns out I was using an old version of Node and Puppeteer. Upgrading to Node >v16 and Puppeteer >v9 fixed the issue.
Thanks to David Bailey for the fix.
If you're using Obsidian for editing markdown files there's a sweet keyboard
shortcut for checking checkboxes in the edit mode. You can also use this to
check multiple checkboxes at the same time instead of entering an x in each
[ ].
Just place your cursor on the line you want to check in edit mode and type
Cmd + Enter. To check multiple items highlight multiple lines before hitting
Cmd + Enter.
So the other day I was updating my personal site to Node v16 and I noticed I
couldn't install node-sass. I thought it was an m1 issue so was googling down
that path but learned that people use a package called sass now instead of
node-sass. So if you're having troubles with node-sass make the switch.
sass doesn't rely on building native C code.
Learned today that you can skip items when destructuring an array by using commas and leaving the index you want to skip over blank. This can be really helpful for certain api responses that are structured in an array, but you only want the second item.
For example:
const response = [responseInfo, body, error];
const [, body] = response;
In this destructuring we only want the second item from the array. Doing this will avoid linting errors from unused variables just to get to the index you wanted.
Sometimes you want to strip off gmail + additions from an email. You probably don't want to store it this way because people should definitely be allowed to use + emails for filtering etc. but you may want to remove it to check for duplicates or other use cases. Here's the regex for doing that.
const regex = /\+(.*)(?=@)/gm;
const strippedEmail = email.replace(regex, '');
I upgraded Gatsby to V3 on my personal site and am now using the new gatsby-image-plugin. Upgrade wasn't too bad 😃 took maybe an hour total. Maybe a little more including the new gatsby image plugin initial research.
The new image plugin is pretty intuitive and I like the move to StaticImage and DynamicImage. Use one if your image isn't based on dynamic data and the other if it is. There hasn't been a more clearly named component 🔥
I love that instead of doing this:
.container {
display: flex;
& > .mat-card {
flex: 1;
margin-right: 30px;
&:last-of-type {
margin-right: 0;
}
}
}
I can just do this:
.container {
display: grid;
gap: 30px;
grid-template-columns: repeat(3, 1fr);
}
If you're using NextJS you're probably using the getStaticProps function or the
getServerSideProps function on your pages to fetch data to populate your page
props. Something I discovered the other day is that you can't pass some types in
your props object to your React component including the Date type. In my
particular application I'm using Prisma to get objects from my database that
include createdAt and updatedAt dates.
My code looks a little something like this:
export const getStaticProps: GetStaticProps = async () => {
const users = await prisma.user.findMany();
return { props: { users }, revalidate: 1 };
};
However, this was a problem because getStaticProps serializes the returned
object and Date (along with a few other types) can't be serialized. You'll get
an error like
("[object Date]") cannot be serialized as JSON. Please only return JSON serializable data type.
So I found this discussion on the topic
https://github.com/vercel/next.js/discussions/11498. I ended up installing a
package called babel-plugin-superjson-next and superjson and added a
.babelrc file with these contents:
{
"presets": ["next/babel"],
"plugins": ["superjson-next"]
}
This just fixes the issue as described in their docs: https://github.com/blitz-js/superjson#using-with-nextjs.
Should also note here you could fix this by manually handling each Date type in your getStaticProps method. You could map over each returned object and convert the Date to a string before returning that array.
Learned that finding a simple (~free) Postgres hosted solution is kinda hard. Heroku kinda works but for a Vercel-hosted NextJS app it was running out of connections. Finally set up a Docker VM on Google Cloud (GCE) and that worked pretty well even though it ended up being about $4/mo. Seems there might be some autoscaling spin down to 0 options that might work too.
Added webmention counts to my blog posts and tiny wins.
Sometimes you have content in a before element that you want to appear on top of a background image but behind other elements on the page. In my situation I had an image with a css triangle used as a mask over the image but wanted text to be able to appear on top of the triangle.
The image below shows what I was going for. There is a white triangle masking
the image and the text is visible on top of the triangle even though it is
position absolute. The key here is making sure the :before element has
z-index: 0 and any of the text elements are either in a flex container or
have position: relative with z-index: 1.

<div class="body-wrapper">
<h1 class="heading">@itwasmattgregg</h1>
</div>
.body-wrapper {
background-image: url('https://codegregg.com/images/matt.jpg');
background-size: contain;
background-position: right;
background-repeat: no-repeat;
height: 600px;
position: relative;
}
.body-wrapper::before {
content: '';
position: absolute;
top: 0;
height: 0;
width: 0;
z-index: 0;
right: 440px;
border-top: 600px solid #fff;
border-right: 160px solid transparent;
}
.heading {
z-index: 1;
position: relative;
}
Was having troubles with my functions redirect rule in netlify.toml file with my Gatsby site. Originally it looked like this:
[[redirects]]
from = "/api/*"
to = "/.netlify/functions/:splat"
status = 200
But gatsby was taking over and serving a 404 for this route. But if you add the force key to the redirect everything works fine. Add it like this:
[[redirects]]
from = "/api/*"
to = "/.netlify/functions/:splat"
status = 200
force = true
Spent the all of today creating social cards that are generated at build time
for my Gatsby blog. Most of my frustration came with trying to load a custom
font into my template loaded by puppeteer. Finally figured out that .otf fonts
don't like being base64 encoded as much as .woff fonts do. I should have turned
off my local font file sooner to debug this 🤦♂. The other frustration was with
the facebook debugger which was returning a 404 for the pages I was testing.
Turns out you don't get the path variable in gatsby template files at the
server rendered phase. Had to switch to using the useLocation() hook to concat
with siteUrl for my og:url tag.
Will write a full blog post tutorial at some point.
Learned how to add partials to emotion styled components with props. This way you can add a bunch of css if a prop is true. Boy is React cool.
import styled from '@emotion/styled';
import { css } from '@emotion/core';
const isAchievementPartial = (props: any) =>
props.isAchievement &&
css`
padding: 20px 5px 5px 5px;
border: 2px solid rgb(36, 234, 182);
border-radius: 11px;
position: relative;
overflow: hidden;
&:before {
content: 'Achievement';
position: absolute;
top: 0;
left: 0;
background: rgb(36, 234, 182);
font-size: 12px;
padding: 1px 6px;
font-weight: bold;
}
`;
const Message = styled.div<any>`
display: flex;
margin-bottom: 10px;
${isAchievementPartial}
`;
<Message isAchievement={true} />
Made an awesome React SVG circle gauge with emotion props.
const SkillGauge = styled.svg`
width: 120px;
height: 120px;
grid-column: 1/1;
grid-row: 1/1;
`;
const SkillGaugeCircle = styled.circle`
stroke-width: 4px;
transform: rotate(-90deg);
transform-origin: 50% 50%;
stroke-dasharray: ${props => props.circumference} ${props =>
props.circumference};
stroke-dashoffset: ${props => props.offset};
stroke-linecap: 'round';
`;
const radius = 58;
const circumference = radius * 2 * Math.PI;
const offset = circumference - (xp / 100) * circumference;
const gaugeColor = xp => {
if (xp <= 33) {
return '#afb6c0';
} else if (xp > 33 && xp < 66) {
return '#637184';
} else {
return '#1a344d';
}
};
<SkillGauge>
<SkillGaugeCircle
stroke={gaugeColor(xp)}
fill='transparent'
r={radius}
circumference={circumference}
offset={offset}
cx='60'
cy='60'
/>
</SkillGauge>;
Just got my old wedding website up at http://gregg-wedding.herokuapp.com/. I forgot how easy Laravel is to use. Especially making models, using factories to generate fake seeding in the db, and passing data to views. It's seriously a joy and took me almost no time at all to dive back in.
Wrote an awesome VS Code snippet for starting new tiny win files in mdx. This snippet takes the filename and capitalizes words as well as removes hyphens and replaces them with spaces. It also inserts the current date and time for frontmatter.
{
"tiny wins": {
"prefix": "tinywin",
"body": [
"---",
" title: '${1:${TM_FILENAME_BASE/(([\\w]*)([^\\w\\s]*)*(\\-)*)/${2:/capitalize}${3:+ }/g}}'",
" date: '$CURRENT_YEAR-$CURRENT_MONTH-${CURRENT_DATE}T$CURRENT_HOUR:$CURRENT_MINUTE:00Z'",
"---",
"",
"$0"
],
"description": "Create a new tiny wins mdx file"
}
}
Implemented basic search in django using SearchFilter. You can add something
this simple to a ViewSet to make fields searchable the search with
/apiEndpoint/?search=searchterm
filter_backends = [filters.SearchFilter]
search_fields = ['username', 'email']
Successfully made it through my third bone marrow biopsy. It's painful and weird but thankfully not too painful. I just have such an aversion to them for some reason.
I found a hidden issue in a python API. My backend dev for this project has been on PTO lately so I've had to take over for him. I feel accomplished in being able to handle some small backend tasks when it's something I haven't really done in ages.
So I might not know all the depths of how caching works... who does? But I did figure out how to run cron jobs, edit entities, and flush memcache in Google App Engine. For a front ender that was a lot for one day.
I made my first Github action to deploy a static VueJS site to Firebase hosting.
I solved a nasty bug in django I was having with getting the site_url for transactional email. I didn't realize this site_url came from the Site object stored in the database and set via the admin panel. I had it set to the production url even though it was the UAT site.
I learned how to split different filesystem sources in gatsby and use childMdx to get the transformed mdx child node.
Built a puppeteer scraper for allergy data.
Transformed it into a serverless function that proxies the request.
Got my first public PR approved and merged
Got invited to consult with a startup called Beingful by one of their board members.
Accepted VP of Tech role.
Shipped my first piece of open source software, a Gatsby theme