Skip to content

Instantly share code, notes, and snippets.

View suhaotian's full-sized avatar
🎯
Focusing

su suhaotian

🎯
Focusing
View GitHub Profile
@suhaotian
suhaotian / get-bundle-size.sh
Last active March 14, 2025 12:04
Get your lib bundle size with bun
#!/bin/bash
# Create a temporary file
TMP_FILE=$(mktemp)
# Build and save output to temp file
bun build dist/index.mjs --minify > "$TMP_FILE"
# Get original size
SIZE=$(cat "$TMP_FILE" | wc -c | awk '{comp=$1/1024; printf "%.2f", comp}')
@suhaotian
suhaotian / qs-stringify.lite.ts
Last active July 9, 2024 09:15
Lightweight `qs.stringify` implementation
/** Ref: https://github.com/suhaotian/xior/blob/main/src/utils.ts#L8 */
export function encodeParams<T = any>(
params: T,
encodeURI = true,
parentKey: string | null = null,
options?: {
allowDots?: boolean;
serializeDate?: (value: Date) => string;
arrayFormat?: 'indices' | 'repeat' | 'brackets';
@suhaotian
suhaotian / refresh-token.ts
Last active April 28, 2024 03:34
Automatically refreshing access token with fetch(xior)
import xior, { XiorError as AxiosError, XiorInstance, XiorResponse } from 'xior';
import errorRetry from 'xior/plugins/error-retry';
const http = xior.create();
http.plugins.use(
errorRetry({
enableRetry: (config, error) => {
if (error.response && shouldRefreshToken(error.response)) {
return true;
@suhaotian
suhaotian / lfs-auto-track.mjs
Created January 31, 2024 11:47
git lfs auto track
import fs from 'fs';
import path from 'path';
import { execSync } from 'child_process';
const cwd = process.cwd();
console.log(process.argv, cwd);
const files = process.argv.slice(3);
const conditions = process.argv[2];
@suhaotian
suhaotian / CaptchaWidget.tsx
Last active December 31, 2024 02:26
Cloudflare turnstile for next.js
'use client';
import Script from 'next/script';
import { useEffect, useRef, useState } from 'react';
const scriptLink = 'https://challenges.cloudflare.com/turnstile/v0/api.js?render=explicit';
type TurnstileRenderParameters = Turnstile.RenderParameters;
export default function Captcha(
@suhaotian
suhaotian / Echart.tsx
Created November 17, 2021 08:57
echarts with typescript
import React, { useState, useRef, useEffect, useMemo, useLayoutEffect, useImperativeHandle, forwardRef, Ref } from 'react'
import echarts, { ECOption } from './echarts-ref';
export type EchartProp = {
option: ECOption,
style?: {
width: string,
height: string
}
className?: string
@suhaotian
suhaotian / bilibili-auto-answer.js
Created August 19, 2020 12:07
B站注册自动答题脚本
setInterval(() => {
[].slice
.call(document.querySelectorAll(".answer-outer"))
.forEach((item, i) => {
setTimeout(() => {
item.click();
}, 1500 * i);
});
}, 6 * 1000);
@suhaotian
suhaotian / floaty.tsx
Last active November 23, 2019 17:46
floating menu ball like iOS
import React, { useState, useRef } from 'react';
import { useSpring, animated } from 'react-spring';
import { useDrag } from 'react-use-gesture';
import { useWindowSize } from 'react-use';
function calcMinDirection(
x: number,
y: number,
w: number,
h: number,
{"_id":"5ca7693589cf3854f7eeb019","c":45,"domNodesVersion":22,"nodes":[{"_id":"5ca7693589cf38199feeb01a","tag":"body","classes":[],"children":["7d78c574-1e03-124f-3c24-dcfff1c895fb","1b33902b-afb7-4c69-56ea-cc27759a8221","1f485dcd-93c5-1c4b-acf7-c00daba17509"],"type":"Body"},{"_id":"7d78c574-1e03-124f-3c24-dcfff1c895fb","tag":"div","classes":["1c6a91d8-0dc2-a413-3dfe-af070a940403"],"children":["84c8acb6-06ec-a537-cdf9-78691902d127","899afc7a-862c-47f8-c987-3c447aae9332","2f7ac40f-af8f-5d37-0813-ec454e423745"],"data":{"tag":"div","grid":{"type":"container"}},"type":"Container"},{"_id":"84c8acb6-06ec-a537-cdf9-78691902d127","tag":"h1","classes":[],"children":["84c8acb6-06ec-a537-cdf9-78691902d128"],"data":{"tag":"h1","style":{"base":{"main":{"noPseudo":{"gridColumnStart":1,"gridColumnEnd":2,"gridRowStart":1,"gridRowEnd":2}}}}},"type":"Heading"},{"_id":"84c8acb6-06ec-a537-cdf9-78691902d128","text":true,"v":"Heading"},{"_id":"899afc7a-862c-47f8-c987-3c447aae9332","tag":"p","classes":[],"children":["899afc7a-862c-
@suhaotian
suhaotian / chunk.js
Created September 14, 2017 02:31
chunk func
function chunk(array, chunkSize) {
if (!chunkSize) throw new Error('chunkSize must be greater than 0')
return array.reduce((chunked, value, i) => {
if (!(i % chunkSize)) chunked.push([])
chunked[chunked.length - 1].push(value)
return chunked
}, [])
}