Skip to content

Instantly share code, notes, and snippets.

View danecando's full-sized avatar
🔨

Dane Grant danecando

🔨
View GitHub Profile
import * as React from "react";
interface Props<T extends Promise<any>[]> {
promises: T;
children: (results: { [P in keyof T]: Awaited<T[P]> }) => React.ReactNode;
}
export function Awaiter<T extends Promise<any>[]>({ promises, children }: Props<T>) {
const results = React.use(Promise.all(promises));
return <>{children(results)}</>;
@danecando
danecando / policy.ts
Last active April 19, 2025 13:34
A simple TypeScript Policy library that can be shared between frontend and backend code
type Cond<Args extends any[], TReturn = boolean> = TReturn | ((...args: Args) => TReturn);
interface PolicyActionResult {
permission: boolean;
invariant: Error | undefined;
actionable: boolean;
}
interface PolicyActionFn<Args extends any[] = []> {
(...args: Args): PolicyActionResult;
@danecando
danecando / action.tsx
Created October 28, 2024 01:12
Sprinkle client side state/validation on server action form
"use server";
import { redirect } from "next/navigation";
import { z } from "zod";
let signUpSchema = z.object({
email: z.string().min(1, "Email is required").email("Please enter a valid email address"),
displayName: z.string().min(2, "Display name must be at least 2 characters"),
password: z.string().min(6, "Password must be at least 6 characters"),
confirmation: z.string().min(6, "Password confirmation must be at least 6 characters"),
@danecando
danecando / api-client-endpoints.ts
Created October 15, 2023 22:46
Type safety using json schemas from server to client application
import type { RecordResponse, ListResponse, PaginatedListResponse } from "@pkg/core/api";
import { UserMapper, type UserEntity } from "@pkg/core/user";
export type EntityIdResponse = RecordResponse<{ id: string }>;
/**
* start:users endpoints
*/
export type UserEntityResponse = RecordResponse<UserEntity>;
export type UserEntityListResponse = ListResponse<UserEntity>;
@danecando
danecando / tailwind-color-vars.js
Created September 5, 2022 13:09
A simple plugin that exposes all tailwind colors as css variables on :root
function ({ addBase, theme }) {
function extractColorVars(colorObj, colorGroup = '') {
return Object.keys(colorObj).reduce((vars, colorKey) => {
const value = colorObj[colorKey];
const newVars =
typeof value === 'string'
? { [`--color${colorGroup}-${colorKey}`]: value }
: extractColorVars(value, `-${colorKey}`);
@danecando
danecando / query.ts
Last active July 18, 2022 01:04
Meetings layout EdgeDB query experiment
type QueryResult = {
nextMeeting?: Meeting;
scheduledMeetings: {
items: Meeting[];
count: number;
hasMore: boolean;
};
attendedMeetings: {
items: MeetingFields[];
count: number;
@danecando
danecando / useAsyncState.ts
Last active July 14, 2022 14:50
A utility hook for managing async effects in a component
import * as React from 'react';
enum Async {
START,
SUCCESS,
FAILURE,
}
interface AsyncState<T> {
isLoading: boolean;
@danecando
danecando / useCurrentItemScroller.ts
Last active June 23, 2022 00:33
React hook for auto scrolling a list of children that have a aria-current attribute
import type {RefObject} from 'react';
import {useEffect} from 'react';
const defer = (fn: () => void) => setTimeout(fn, 0);
export function useCurrentItemScroller(containerRef: RefObject<HTMLElement>) {
useEffect(() => {
const containerEl = containerRef.current;
let observer: MutationObserver | undefined;
if (containerEl) {
@danecando
danecando / SerializeType.ts
Last active June 7, 2022 11:12
SerializeType utility for converting a type to JSON
// credit @colinhacks
// https://github.com/remix-run/remix/pull/1254
type JSONPrimitives = string | number | boolean | null;
type NonJSONPrimitives = undefined | Function | symbol;
export type SerializeType<T> = T extends JSONPrimitives
? T
: T extends undefined
? undefined
@danecando
danecando / fargate-copilot-deploy.yml
Created May 22, 2022 23:45
GitHub Action: Deploy AWS Fargate app with AWS Copilot
deploy:
name: 🚀 Deploy
runs-on: ubuntu-latest
steps:
- name: 🛑 Cancel Previous Runs
uses: styfle/[email protected]
- name: ⬇️ Checkout repo
uses: actions/checkout@v3