Skip to content

Instantly share code, notes, and snippets.

View danawoodman's full-sized avatar
👨‍🔬
Hacking away...

Dana Woodman danawoodman

👨‍🔬
Hacking away...
View GitHub Profile
@danawoodman
danawoodman / How to allow the file picker AND camera capture on Android.md
Last active December 9, 2025 10:16
How to allow the file picker AND camera capture on Android

Allow photo album AND the camera

On Android devices, if you want to create a file input that prompts the user to either choose an image from their photo album or take a picture with their camera, you'll need this basically undocumented capture attribute added to your input's accept property:

<input type="file" accept="image/*;capture=camera" />
@danawoodman
danawoodman / Raspberry Pi web page kiosk mode.md
Last active November 29, 2025 11:13
How to setup a Raspberry Pi to start up a web page in kiosk mode

Start a web page in kiosk mode on a Raspberry Pi

Install dependencies

Start by installing chromium and unclutter which will hide the cursor on the screen:

sudo apt install -y -no-install-recommends chromium-browser unclutter
@danawoodman
danawoodman / Deploying CloudFlare Workers via CloudFlare Pages in a Turborepo monorepo.md
Last active November 26, 2025 02:14
Deploying CloudFlare Workers via CloudFlare Pages in a Turborepo monorepo

Deploying Cloudflare Workers via Cloudflare Pages in a Turborepo monorepo

Whew, what a mouthful.

Cloudflare Workers is an excellent platform for deploying a variety of applications but it has some limitations compared to Cloudflare's other product, Pages.

Pages gives you git integration which gives you auto-deploying via git push as well as pull request preview deployment links so you can test out features before pushing to production.

However, it's not super clear how to deploy a bare worker to Cloudflare Pages as Pages is more tailored right now for apps (SvelteKit, Astro, Next, etc), that is why I wrote up this little guide.

@danawoodman
danawoodman / Rust-like "results" for TypeScript projects.md
Last active September 30, 2025 20:37
Rust-like "results" for TypeScript projects

Rust-like "results" for TypeScript projects

Handling errors in JavaScript/TypeScript kinda sucks. throwing breaks the control flow, is not "discoverable" (e.g. impossible to really know what will happen in error states), and it is generally more tricky to get well typed error responses.

Taking inspiration from Rust's Result type, we can implement something similar in TypeScript with a minimal amount of code and no dependencies. It's not as robust as Rust's of course, but it has been very useful for me on a variety of large projects.

Implementation

Save the following TypeScript in your project and import it to use the various result utils:

@danawoodman
danawoodman / Get bun.lock files to work with Cloudflare Workers CI.md
Last active August 27, 2025 20:09
Get bun.lock files to work with Cloudflare Workers CI

Get bun.lock files to work with Cloudflare Workers CI

As of the time of this writing, Cloudflare Workers CI does not work with the newer text-based bun.lock file and instead requires a bun.lockb file to build your app via their CI system.

This usually manifests itself with the following error when trying to deploy your apps using a bun.lock file:

13:48:54.691	Initializing build environment...
13:49:02.821	Success: Finished initializing build environment
13:49:03.776	Cloning repository...
@danawoodman
danawoodman / Using Golang templ with the Echo framework.md
Last active July 15, 2025 09:57
Using Golang templ with the Echo framework

Using Golang templ with the Echo framework

templ is a great view framework but there is no clear documentation (as of writing) showing how to use it with the Echo web framework. This short guide should show you how to set it up:

Install dependencies

Install templ and echo:

go get github.com/a-h/templ
@danawoodman
danawoodman / pdf.js
Created April 10, 2015 19:41
Example of using pdfkit in Node.js
var fs = require('fs');
var PDFDocument = require('pdfkit');
var pdf = new PDFDocument({
size: 'LEGAL', // See other page sizes here: https://github.com/devongovett/pdfkit/blob/d95b826475dd325fb29ef007a9c1bf7a527e9808/lib/page.coffee#L69
info: {
Title: 'Tile of File Here',
Author: 'Some Author',
}
});
@danawoodman
danawoodman / ESP32 Controlled Low-Voltage Path Lights.md
Last active February 5, 2025 03:18
ESP32 Controlled Low-Voltage Path Lights

ESP32 Controlled Low-Voltage Path Lights

Using an ESP32-C3 connected to HomeAssistant via ESPHome, control 12v yard path lights including configuring automations to turn lights on/off at sunset/sunrise and dimming.

This short guide will show you how to use HomeAssistant, and the ESPHome app for it, to control LED dimming. In this case I'm using this for low voltage yard path lights, but could be used for anything.

If you have HomeKit integrated with HomeAssistant than you can also control/dim your LEDs from your iPhone!

Parts

@danawoodman
danawoodman / Svelte action to auto-grow a textarea.md
Created January 14, 2025 19:44
Svelte action to auto-grow a textarea

Svelte action to auto-grow a textarea

A Svelte action that whena applied to a textaarea supports automatically growing or shrinking as content is added or removed.

Implementation

src/lib/actions/autogrow.ts:

export function autogrow(node: HTMLElement) {
@danawoodman
danawoodman / 1-react-websockets-reflux.md
Last active August 21, 2024 20:58
Using WebSockets with Reflux and React

WebSockets + Reflux + React

Using WebSockets, React and Reflux together can be a beautiful thing, but the intial setup can be a bit of a pain. The below examples attempt to offer one (arguably enjoyable) way to use these tools together.

Overview

This trifect works well if you think of things like so:

  1. Reflux Store: The store fetches, updates and persists data. A store can be a list of items or a single item. Most of the times you reach for this.state in react should instead live within stores. Stores can listen to other stores as well as to events being fired.
  2. Reflux Actions: Actions are triggered by components when the component wants to change the state of the store. A store listens to actions and can listen to more than one set of actions.