Skip to content

Instantly share code, notes, and snippets.

View stephenjwatkins's full-sized avatar

Stephen Watkins stephenjwatkins

View GitHub Profile
@stephenjwatkins
stephenjwatkins / replace_smartobject_psd_placeembedded.jsx
Created July 21, 2025 13:54
Photoshop script to replace a Smart Object within a PSD using "Place Embedded" with specified image and saves result as a JPG. Preserves transformations.
// Photoshop script to replace a Smart Object within a PSD using "Place Embedded" with specified image and saves result as a JPG. Preserves transformations.
// 2025. Use at your own risk
// Can be run in an automated fashion on Mac via AppleScript:
// osascript -e "tell application \"Adobe Photoshop 2025\" to activate do javascript of file \"replace_smartobject_psd_placeembedded.jsx\""
#target photoshop
var mockupFilePath = "~/mockup.psd";
var designFilePath = "~/design.png";
@stephenjwatkins
stephenjwatkins / josh-comeau-css-reset.css
Created April 15, 2023 21:04
Josh Comeau's CSS reset
/*
1. Use a more-intuitive box-sizing model.
*/
*,
*::before,
*::after {
box-sizing: border-box;
}
/*
@stephenjwatkins
stephenjwatkins / onFontLoaded.js
Created February 25, 2021 21:46
Detect when a font loads.
function onFontLoaded(fontFamily) {
const font = `1rem ${fontFamily}`;
return new Promise((resolve, reject) => {
const isFontAvailable = document.fonts.check(font);
if (isFontAvailable) {
resolve();
} else {
document.fonts.ready
.then(() => {
if (document.fonts.check(font)) {
@stephenjwatkins
stephenjwatkins / runPromiseForMinimumTime.js
Last active December 22, 2018 21:33
Simple faux loader that runs a promise for a minimum time.
// This function will return a promise that runs the passed in promise, but
// for at least the time specified. This is helpful for UI interactions
// that should look like they're processing something.
//
// By design, if an error occurs, it'll still wait for the time specified
// before throwing.
async function runPromiseForMinimumTime(promise, minimumTime = 500) {
let error;
const [, result] = await Promise.all([
new Promise(r => setTimeout(r, minimumTime)),
@stephenjwatkins
stephenjwatkins / cleanmodules.sh
Created August 27, 2018 16:00
Clean node_modules recursively.
find . -name 'node_modules' -type d -prune -exec rm -rf '{}' +
@stephenjwatkins
stephenjwatkins / Lifecycles.js
Created August 9, 2018 20:11
Generic Lifecycles component for React.
import React from "react";
import isFunction from "lodash/isFunction";
class Lifecycles extends React.Component {
async componentDidMount() {
if (this.props.didMount) {
await this.props.didMount({ props: this.props });
}
}
@stephenjwatkins
stephenjwatkins / State.js
Created August 9, 2018 20:10
Generic State component for React.
import React from "react";
import isFunction from "lodash/isFunction";
class State extends React.Component {
constructor(...args) {
super(...args);
this.boundSetState = this.setState.bind(this);
this.state = isFunction(this.props.initialState)
@stephenjwatkins
stephenjwatkins / ModalLayout.js
Created August 9, 2018 20:05
Modals that support nesting.
/*
<ModalContainer>
<ModalBackdrop />
<ModalFrames>
<ModalFrame>
<ModalGutter />
<ModalWindow>
<ModalHeader />
<ModalBody />
<ModalFooter />
@stephenjwatkins
stephenjwatkins / string.js
Created August 8, 2018 20:15
String utility functions.
const upperCaseFirstLetter = string => {
return string.charAt(0).toUpperCase() + string.slice(1);
};
const lowerCaseFirstLetter = string => {
return string.charAt(0).toLowerCase() + string.slice(1);
};
const camelToDashCase = string => {
return lowerCaseFirstLetter(string).replace(
@stephenjwatkins
stephenjwatkins / searchParams.js
Last active August 8, 2018 20:14
Utilities for working with search params (without needing to polyfill URLSearchParams).
function getAllSearchParamsFromSearch(search) {
let massagedSearch = search;
if (massagedSearch.charAt(0) === "?") {
massagedSearch = massagedSearch.substring(1);
}
// Filter out the search parameters that have been passed in
return massagedSearch.split("&").map(part => {
return part.split("=");