mirror of
https://github.com/bitcoinresearchkit/brk.git
synced 2026-04-26 07:39:59 -07:00
general: snapshot
This commit is contained in:
@@ -1,31 +1,52 @@
|
||||
export const priceToUSLocale = (price: number, compact = true) => {
|
||||
const absolutePrice = Math.abs(price);
|
||||
const lessThan100 = absolutePrice < 100;
|
||||
const lessThan1000 = absolutePrice < 1_000;
|
||||
const biggerThanMillion = absolutePrice >= 1_000_000;
|
||||
const suffices = ["M", "B", "T", "Q"];
|
||||
|
||||
return numberToUSLocale(
|
||||
price,
|
||||
lessThan1000 ? (lessThan100 ? 2 : 1) : biggerThanMillion ? 3 : 0,
|
||||
biggerThanMillion && compact
|
||||
? {
|
||||
notation: "compact",
|
||||
compactDisplay: "short",
|
||||
}
|
||||
: undefined,
|
||||
);
|
||||
};
|
||||
export function valueToString(value: number) {
|
||||
const absoluteValue = Math.abs(value);
|
||||
|
||||
export const percentageToUSLocale = (percentage: number) =>
|
||||
numberToUSLocale(percentage, 1);
|
||||
// value = absoluteValue;
|
||||
|
||||
const numberToUSLocale = (
|
||||
if (isNaN(value)) {
|
||||
return "";
|
||||
// } else if (value === 0) {
|
||||
// return "0";
|
||||
} else if (absoluteValue < 10) {
|
||||
return numberToUSLocale(value, 3);
|
||||
} else if (absoluteValue < 100) {
|
||||
return numberToUSLocale(value, 2);
|
||||
} else if (absoluteValue < 1_000) {
|
||||
return numberToUSLocale(value, 1);
|
||||
} else if (absoluteValue < 100_000) {
|
||||
return numberToUSLocale(value, 0);
|
||||
} else if (absoluteValue < 1_000_000) {
|
||||
return `${numberToUSLocale(value / 1_000, 1)}K`;
|
||||
} else if (absoluteValue >= 1_000_000_000_000_000_000) {
|
||||
return "Inf.";
|
||||
}
|
||||
|
||||
const log = Math.floor(Math.log10(absoluteValue) - 6);
|
||||
|
||||
const letterIndex = Math.floor(log / 3);
|
||||
const letter = suffices[letterIndex];
|
||||
|
||||
const modulused = log % 3;
|
||||
|
||||
if (modulused === 0) {
|
||||
return `${numberToUSLocale(value / (1_000_000 * 1_000 ** letterIndex), 3)}${letter}`;
|
||||
} else if (modulused === 1) {
|
||||
return `${numberToUSLocale(value / (1_000_000 * 1_000 ** letterIndex), 2)}${letter}`;
|
||||
} else {
|
||||
return `${numberToUSLocale(value / (1_000_000 * 1_000 ** letterIndex), 1)}${letter}`;
|
||||
}
|
||||
}
|
||||
|
||||
function numberToUSLocale(
|
||||
value: number,
|
||||
digits: number,
|
||||
digits?: number,
|
||||
options?: Intl.NumberFormatOptions | undefined,
|
||||
) =>
|
||||
value.toLocaleString("en-us", {
|
||||
) {
|
||||
return value.toLocaleString("en-us", {
|
||||
...options,
|
||||
minimumFractionDigits: digits,
|
||||
maximumFractionDigits: digits,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { createRWS } from "/src/solid/rws";
|
||||
|
||||
export const createSelectableList = <T, L extends T[] = T[]>(
|
||||
list: L,
|
||||
export const createDynamicList = <T, L extends T[] = T[]>(
|
||||
l: L,
|
||||
parameters?: {
|
||||
selected?: L[number];
|
||||
selectedIndex?: number | null;
|
||||
@@ -10,10 +10,10 @@ export const createSelectableList = <T, L extends T[] = T[]>(
|
||||
const selected = createRWS<L[number] | null>(null);
|
||||
const selectedIndex = createRWS<number | null>(null);
|
||||
|
||||
const selectableList: SelectableList<L[number], L> = {
|
||||
const list: DynamicList<L[number], L> = {
|
||||
selected,
|
||||
selectedIndex,
|
||||
list: createRWS(list, {
|
||||
list: createRWS(l, {
|
||||
equals: false,
|
||||
}),
|
||||
select(s) {
|
||||
@@ -83,10 +83,10 @@ export const createSelectableList = <T, L extends T[] = T[]>(
|
||||
toJSON<TJSON, LJSON extends TJSON[] = TJSON[]>(
|
||||
transform: (value: T) => TJSON,
|
||||
filter?: (value: T) => boolean,
|
||||
): JSONSelectableList<TJSON, LJSON> {
|
||||
): JSONDynamicList<TJSON, LJSON> {
|
||||
return {
|
||||
version: 1,
|
||||
selectedIndex: getIndexOfSelectedInSelectableList(this),
|
||||
selectedIndex: getIndexOfSelectedInDynamicList(this),
|
||||
list: (filter ? this.list().filter(filter) : this.list()).map((value) =>
|
||||
transform(value),
|
||||
) as LJSON,
|
||||
@@ -95,18 +95,18 @@ export const createSelectableList = <T, L extends T[] = T[]>(
|
||||
};
|
||||
|
||||
if (parameters?.selected !== undefined) {
|
||||
selectableList.select(parameters.selected);
|
||||
list.select(parameters.selected);
|
||||
} else if (parameters?.selectedIndex !== undefined) {
|
||||
selectableList.selectIndex(parameters.selectedIndex);
|
||||
list.selectIndex(parameters.selectedIndex);
|
||||
}
|
||||
|
||||
return selectableList;
|
||||
return list;
|
||||
};
|
||||
|
||||
export const createSL = createSelectableList;
|
||||
export const createDSL = createDynamicList;
|
||||
|
||||
export const getIndexOfSelectedInSelectableList = <T, L extends T[] = T[]>(
|
||||
sl: SelectableList<L[number], L>,
|
||||
export const getIndexOfSelectedInDynamicList = <T, L extends T[] = T[]>(
|
||||
sl: DynamicList<L[number], L>,
|
||||
) => {
|
||||
const selected = sl.selected();
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
// JSON
|
||||
// ---
|
||||
|
||||
interface JSONSelectableList<T, L extends T[] = T[]> {
|
||||
interface JSONDynamicList<T, L extends T[] = T[]> {
|
||||
readonly version: 1;
|
||||
selectedIndex: number | null;
|
||||
readonly list: L;
|
||||
@@ -12,7 +12,7 @@ interface JSONSelectableList<T, L extends T[] = T[]> {
|
||||
// Object
|
||||
// ---
|
||||
|
||||
interface SelectableList<T, L extends T[] = T[]> {
|
||||
interface DynamicList<T, L extends T[] = T[]> {
|
||||
readonly selected: Accessor<T | null>;
|
||||
readonly selectedIndex: Accessor<number | null>;
|
||||
readonly list: RWS<L>;
|
||||
@@ -29,5 +29,5 @@ interface SelectableList<T, L extends T[] = T[]> {
|
||||
readonly toJSON: <TJSON, LJSON extends TJSON[] = TJSON[]>(
|
||||
transform: (value: T) => LJSON[number],
|
||||
filter?: (value: T) => boolean,
|
||||
) => JSONSelectableList<TJSON, LJSON>;
|
||||
) => JSONDynamicList<TJSON, LJSON>;
|
||||
}
|
||||
140
app/src/scripts/utils/selectableList/static/index.ts
Normal file
140
app/src/scripts/utils/selectableList/static/index.ts
Normal file
@@ -0,0 +1,140 @@
|
||||
import { createRWS } from "/src/solid/rws";
|
||||
|
||||
import { run } from "../../run";
|
||||
|
||||
export const createStaticList = <T, L extends T[] = T[]>(
|
||||
l: L,
|
||||
parameters: {
|
||||
selected?: L[number];
|
||||
selectedIndex?: number;
|
||||
saveable?: {
|
||||
mode: "localStorage" | "URLParams" | "both";
|
||||
key: string;
|
||||
};
|
||||
defaultValue?: L[number];
|
||||
defaultIndex?: number;
|
||||
},
|
||||
) => {
|
||||
if (
|
||||
!l.length ||
|
||||
(parameters.saveable === undefined &&
|
||||
parameters.selected === undefined &&
|
||||
parameters.selectedIndex === undefined)
|
||||
) {
|
||||
throw Error("not possible");
|
||||
}
|
||||
|
||||
const selected = createRWS<L[number]>(
|
||||
run(() => {
|
||||
let savedIndex: number | undefined;
|
||||
|
||||
if (parameters.saveable) {
|
||||
if (parameters.saveable.mode !== "localStorage") {
|
||||
throw Error("unsupported");
|
||||
}
|
||||
|
||||
const savedRaw = localStorage.getItem(parameters.saveable.key);
|
||||
|
||||
if (savedRaw) {
|
||||
savedIndex = Number(savedRaw);
|
||||
}
|
||||
}
|
||||
|
||||
if (parameters.selected) {
|
||||
const found = l.find((v) => v === parameters.selected);
|
||||
|
||||
if (!found) {
|
||||
throw Error("unreachable");
|
||||
}
|
||||
|
||||
return found;
|
||||
} else {
|
||||
return (
|
||||
l.at(savedIndex ?? parameters.selectedIndex!) ??
|
||||
parameters.defaultValue ??
|
||||
l[parameters.defaultIndex || 0]
|
||||
);
|
||||
}
|
||||
}),
|
||||
);
|
||||
|
||||
const selectedIndex = createRWS<number>(
|
||||
run(() => {
|
||||
if (
|
||||
parameters.selectedIndex !== null &&
|
||||
parameters.selectedIndex !== undefined
|
||||
) {
|
||||
const found = l.at(parameters.selectedIndex);
|
||||
|
||||
if (!found) {
|
||||
throw Error("unreachable");
|
||||
}
|
||||
|
||||
return parameters.selectedIndex;
|
||||
} else {
|
||||
return l.indexOf(selected());
|
||||
}
|
||||
}),
|
||||
);
|
||||
|
||||
createEffect(() => {
|
||||
if (parameters.saveable) {
|
||||
localStorage.setItem(parameters.saveable.key, String(selectedIndex()));
|
||||
}
|
||||
});
|
||||
|
||||
const list: StaticList<L[number], L> = {
|
||||
selected,
|
||||
selectedIndex,
|
||||
list: createRWS(l, {
|
||||
equals: false,
|
||||
}),
|
||||
select(s) {
|
||||
if (this.selected() !== s) {
|
||||
batch(() => {
|
||||
selected.set(() => s);
|
||||
this.selectIndex(this.list().indexOf(s));
|
||||
});
|
||||
}
|
||||
},
|
||||
selectIndex(i) {
|
||||
if (i && (i < 0 || i >= this.list().length)) {
|
||||
throw new Error(
|
||||
`SelectableList: selectIndex: ${i} is incorrect ! (has ${
|
||||
this.list().length
|
||||
} elements)`,
|
||||
);
|
||||
}
|
||||
|
||||
if (i !== this.selectedIndex()) {
|
||||
selectedIndex.set(i);
|
||||
|
||||
const value = this.list().at(i);
|
||||
|
||||
if (value === undefined) {
|
||||
throw Error("unreachable");
|
||||
}
|
||||
|
||||
this.select(value);
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
if (parameters?.selected !== undefined) {
|
||||
list.select(parameters.selected);
|
||||
} else if (parameters?.selectedIndex !== undefined) {
|
||||
list.selectIndex(parameters.selectedIndex);
|
||||
}
|
||||
|
||||
return list;
|
||||
};
|
||||
|
||||
export const createSL = createStaticList;
|
||||
|
||||
export const getIndexOfSelectedInStaticList = <T, L extends T[] = T[]>(
|
||||
sl: StaticList<L[number], L>,
|
||||
) => {
|
||||
const selected = sl.selected();
|
||||
|
||||
return selected ? sl.list().indexOf(selected) : null;
|
||||
};
|
||||
9
app/src/scripts/utils/selectableList/static/types.d.ts
vendored
Normal file
9
app/src/scripts/utils/selectableList/static/types.d.ts
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
interface StaticList<T, L extends T[] = T[]> {
|
||||
readonly selected: Accessor<T>;
|
||||
readonly selectedIndex: Accessor<number>;
|
||||
readonly list: RWS<L>;
|
||||
readonly select: <S extends L[number] = L[number]>(s: S) => void;
|
||||
readonly selectIndex: (index: number) => void;
|
||||
}
|
||||
|
||||
type SL<T, L extends T[] = T[]> = StaticList<T, L>;
|
||||
Reference in New Issue
Block a user