app: html version almost done

This commit is contained in:
k
2024-09-10 09:39:06 +02:00
parent e206b40468
commit 5edb8111a2
40 changed files with 5900 additions and 1919 deletions
+1
View File
@@ -0,0 +1 @@
/ignore
-48
View File
@@ -1,48 +0,0 @@
merge = async (c1, c2) => {
function sleep(ms) {
return new Promise((resolve) => {
setTimeout(resolve, ms);
});
}
async function hexToOklch(c) {
hex.value = c;
hex.dispatchEvent(new Event("change"));
await sleep(1);
console.log(oklch.value);
const s = oklch.value.slice(6, -1).split(" ");
let [lightness, chroma, hue] = s;
lightness = Number(lightness.slice(0, -1));
chroma = Number(chroma);
hue = Number(hue);
return [lightness, chroma, hue];
}
function average(a, b) {
return (a + b) / 2;
}
const [lightness1, chroma1, hue1] = await hexToOklch(c1);
console.log(lightness1, chroma1, hue1);
const [lightness2, chroma2, hue2] = await hexToOklch(c2);
console.log(lightness2, chroma2, hue2);
const lightness = average(lightness1, lightness2);
const chroma = average(chroma1, chroma2);
const hue = average(hue1, hue2);
oklch.value = `oklch(${lightness}% ${chroma} ${hue})`;
console.log(oklch.value);
oklch.dispatchEvent(new Event("change"));
await sleep(10);
console.log(hex.value);
};
+1193 -123
View File
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -5,5 +5,5 @@
"target": "ESNext",
"module": "ESNext"
},
"exclude": ["assets", "libraries"]
"exclude": ["assets", "libraries", "ignore"]
}
+3
View File
@@ -0,0 +1,3 @@
URL + Version:
https://unpkg.com/browse/lightweight-charts@4.2.0/
File diff suppressed because one or more lines are too long
+241
View File
@@ -0,0 +1,241 @@
declare module "lean-qr" {
interface ImageDataLike {
readonly data: Uint8ClampedArray;
}
interface Context2DLike<DataT extends ImageDataLike> {
createImageData(width: number, height: number): DataT;
putImageData(data: DataT, x: number, y: number): void;
}
interface CanvasLike<DataT extends ImageDataLike> {
width: number;
height: number;
getContext(type: "2d"): Context2DLike<DataT> | null;
}
export type RGBA = readonly [number, number, number, number?];
export interface Bitmap1D {
push(value: number, bits: number): void;
}
export interface StringOptions {
on?: string;
off?: string;
lf?: string;
padX?: number;
padY?: number;
}
export interface ImageDataOptions {
on?: RGBA;
off?: RGBA;
padX?: number;
padY?: number;
}
export interface Bitmap2D {
readonly size: number;
get(x: number, y: number): boolean;
toString(options?: Readonly<StringOptions>): string;
toImageData<DataT extends ImageDataLike>(
context: Context2DLike<DataT>,
options?: Readonly<ImageDataOptions>,
): DataT;
toDataURL(
options?: Readonly<
ImageDataOptions & {
type?: `image/${string}`;
scale?: number;
}
>,
): string;
toCanvas(
canvas: CanvasLike<ImageDataLike>,
options?: Readonly<ImageDataOptions>,
): void;
}
export type Mask = 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7;
export type Mode = (data: Bitmap1D, version: number) => void;
export interface ModeFactory {
(value: string): Mode;
test(string: string): boolean;
est(value: string, version: number): number;
eci?: number;
}
interface ModeAutoOptions {
modes?: ReadonlyArray<ModeFactory>;
}
export const mode: Readonly<{
auto(value: string, options?: Readonly<ModeAutoOptions>): Mode;
multi(...modes: ReadonlyArray<Mode>): Mode;
eci(id: number): Mode;
numeric: ModeFactory;
alphaNumeric: ModeFactory;
bytes(data: Uint8Array | ReadonlyArray<number>): Mode;
ascii: ModeFactory;
iso8859_1: ModeFactory;
shift_jis: ModeFactory;
utf8: ModeFactory;
}>;
type Correction = number & { readonly _: unique symbol };
export const correction: Readonly<{
min: Correction;
L: Correction;
M: Correction;
Q: Correction;
H: Correction;
max: Correction;
}>;
export interface GenerateOptions extends ModeAutoOptions {
minCorrectionLevel?: Correction;
maxCorrectionLevel?: Correction;
minVersion?: number;
maxVersion?: number;
mask?: null | Mask;
trailer?: number;
}
export type GenerateFn = (
data: Mode | string,
options?: Readonly<GenerateOptions>,
) => Bitmap2D;
interface Generate extends GenerateFn {
with(...modes: ReadonlyArray<ModeFactory>): GenerateFn;
}
export const generate: Generate;
}
declare module "lean-qr/extras/svg" {
import type { Bitmap2D } from "lean-qr";
export interface SVGOptions {
on?: string;
off?: string;
padX?: number;
padY?: number;
width?: number | null;
height?: number | null;
scale?: number;
}
export const toSvgPath: (code: Bitmap2D) => string;
export const toSvg: (
code: Bitmap2D,
target: Document | SVGElement,
options?: Readonly<SVGOptions>,
) => SVGElement;
export const toSvgSource: (
code: Bitmap2D,
options?: Readonly<SVGOptions & { xmlDeclaration?: boolean }>,
) => string;
export type toSvgDataURLFn = (
code: Bitmap2D,
options?: Readonly<SVGOptions>,
) => string;
export const toSvgDataURL: toSvgDataURLFn;
}
declare module "lean-qr/extras/node_export" {
import type { RGBA, Bitmap2D } from "lean-qr";
export interface PNGOptions {
on?: RGBA;
off?: RGBA;
padX?: number;
padY?: number;
scale?: number;
}
export const toPngBuffer: (
code: Bitmap2D,
options?: Readonly<PNGOptions>,
) => Uint8Array;
export const toPngDataURL: (
code: Bitmap2D,
options?: Readonly<PNGOptions>,
) => string;
}
declare module "lean-qr/extras/react" {
import type { ImageDataOptions, GenerateOptions, GenerateFn } from "lean-qr";
import type { SVGOptions, toSvgDataURLFn } from "lean-qr/extras/svg";
export interface AsyncFramework<T> {
createElement: (
type: "canvas",
props: {
ref: any;
style: { imageRendering: "pixelated" };
className: string;
},
) => T;
useRef<T>(initialValue: T | null): { readonly current: T | null };
useEffect(fn: () => void | (() => void), deps: unknown[]): void;
}
interface QRComponentProps {
content: string;
className?: string;
}
export interface AsyncQRComponentProps
extends ImageDataOptions,
GenerateOptions,
QRComponentProps {}
export type AsyncQRComponent<T> = (
props: Readonly<AsyncQRComponentProps>,
) => T;
export const makeAsyncComponent: <T>(
framework: Readonly<AsyncFramework<T>>,
generate: GenerateFn,
defaultProps?: Readonly<Partial<AsyncQRComponentProps>>,
) => AsyncQRComponent<T>;
export interface SyncFramework<T> {
createElement: (
type: "img",
props: {
src: string;
style: { imageRendering: "pixelated" };
className: string;
},
) => T;
useMemo<T>(fn: () => T, deps: unknown[]): T;
}
export interface SyncQRComponentProps
extends SVGOptions,
GenerateOptions,
QRComponentProps {}
export type SyncQRComponent<T> = (props: Readonly<SyncQRComponentProps>) => T;
export const makeSyncComponent: <T>(
framework: Readonly<SyncFramework<T>>,
generate: GenerateFn,
toSvgDataURL: toSvgDataURLFn,
defaultProps?: Readonly<Partial<SyncQRComponentProps>>,
) => SyncQRComponent<T>;
}
declare module "lean-qr/extras/errors" {
export const readError: (error: unknown) => string;
}
@@ -0,0 +1,2 @@
TradingView Lightweight Charts™
Copyright (с) 2023 TradingView, Inc. https://www.tradingview.com/
@@ -0,0 +1,6 @@
URL:
https://github.com/leeoniya/ufuzzy/tree/main/dist
Head:
- SHA: 6bb27a8d8c41e4be5458844afc5c89f6c2399512
- Date: Feb 21, 2024
File diff suppressed because one or more lines are too long
@@ -0,0 +1,5 @@
Compiled version of: https://github.com/solidjs/signals
Head:
- SHA: 4d75d3f84ce22b560988f3b27a5065c0fd2e69a8
- Date: Apr 17, 2024
File diff suppressed because it is too large Load Diff
+10
View File
@@ -0,0 +1,10 @@
/**
* See https://dev.to/modderme123/super-charging-fine-grained-reactive-performance-47ph
* State clean corresponds to a node where all the sources are fully up to date
* State check corresponds to a node where some sources (including grandparents) may have changed
* State dirty corresponds to a node where the direct parents of a node has changed
*/
export declare const STATE_CLEAN = 0;
export declare const STATE_CHECK = 1;
export declare const STATE_DIRTY = 2;
export declare const STATE_DISPOSED = 3;
+143
View File
@@ -0,0 +1,143 @@
/**
* Nodes for constructing a graph of reactive values and reactive computations.
*
* - The graph is acyclic.
* - The user inputs new values into the graph by calling .write() on one more computation nodes.
* - The user retrieves computed results from the graph by calling .read() on one or more computation nodes.
* - The library is responsible for running any necessary computations so that .read() is up to date
* with all prior .write() calls anywhere in the graph.
* - We call the input nodes 'roots' and the output nodes 'leaves' of the graph here.
* - Changes flow from roots to leaves. It would be effective but inefficient to immediately
* propagate all changes from a root through the graph to descendant leaves. Instead, we defer
* change most change propagation computation until a leaf is accessed. This allows us to
* coalesce computations and skip altogether recalculating unused sections of the graph.
* - Each computation node tracks its sources and its observers (observers are other
* elements that have this node as a source). Source and observer links are updated automatically
* as observer computations re-evaluate and call get() on their sources.
* - Each node stores a cache state (clean/check/dirty) to support the change propagation algorithm:
*
* In general, execution proceeds in three passes:
*
* 1. write() propagates changes down the graph to the leaves
* direct children are marked as dirty and their deeper descendants marked as check
* (no computations are evaluated)
* 2. read() requests that parent nodes updateIfNecessary(), which proceeds recursively up the tree
* to decide whether the node is clean (parents unchanged) or dirty (parents changed)
* 3. updateIfNecessary() evaluates the computation if the node is dirty (the computations are
* executed in root to leaf order)
*/
import { type Flags } from './flags';
import { Owner } from './owner';
export interface SignalOptions<T> {
name?: string;
equals?: ((prev: T, next: T) => boolean) | false;
}
export interface MemoOptions<T> extends SignalOptions<T> {
initial?: T;
}
interface SourceType {
_observers: ObserverType[] | null;
_updateIfNecessary: () => void;
_stateFlags: Flags;
}
interface ObserverType {
_sources: SourceType[] | null;
_notify: (state: number) => void;
_handlerMask: Flags;
_notifyFlags: (mask: Flags, newFlags: Flags) => void;
}
/**
* Returns the current observer.
*/
export declare function getObserver(): ObserverType | null;
export declare const UNCHANGED: unique symbol;
export type UNCHANGED = typeof UNCHANGED;
export declare class Computation<T = any> extends Owner implements SourceType, ObserverType {
_sources: SourceType[] | null;
_observers: ObserverType[] | null;
_value: T | undefined;
_compute: null | (() => T);
_name: string | undefined;
_equals: false | ((a: T, b: T) => boolean);
/** Whether the computation is an error or has ancestors that are unresolved */
_stateFlags: number;
/** Which flags raised by sources are handled, vs. being passed through. */
_handlerMask: number;
_error: Computation<boolean> | null;
_loading: Computation<boolean> | null;
constructor(initialValue: T | undefined, compute: null | (() => T), options?: MemoOptions<T>);
_read(): T;
/**
* Return the current value of this computation
* Automatically re-executes the surrounding computation when the value changes
*/
read(): T;
/**
* Return the current value of this computation
* Automatically re-executes the surrounding computation when the value changes
*
* If the computation has any unresolved ancestors, this function waits for the value to resolve
* before continuing
*/
wait(): T;
/**
* Return true if the computation is the value is dependent on an unresolved promise
* Triggers re-execution of the computation when the loading state changes
*
* This is useful especially when effects want to re-execute when a computation's
* loading state changes
*/
loading(): boolean;
/**
* Return true if the computation is the computation threw an error
* Triggers re-execution of the computation when the error state changes
*/
error(): boolean;
/** Update the computation with a new value. */
write(value: T | ((currentValue: T) => T) | UNCHANGED, flags?: number, raw?: boolean): T;
/**
* Set the current node's state, and recursively mark all of this node's observers as STATE_CHECK
*/
_notify(state: number): void;
/**
* Notify the computation that one of its sources has changed flags.
*
* @param mask A bitmask for which flag(s) were changed.
* @param newFlags The source's new flags, masked to just the changed ones.
*/
_notifyFlags(mask: Flags, newFlags: Flags): void;
_setError(error: unknown): void;
/**
* This is the core part of the reactivity system, which makes sure that the values are updated
* before they are read. We've also adapted it to return the loading state of the computation,
* so that we can propagate that to the computation's observers.
*
* This function will ensure that the value and states we read from the computation are up to date
*/
_updateIfNecessary(): void;
/**
* Remove ourselves from the owner graph and the computation graph
*/
_disposeNode(): void;
}
/**
* Reruns a computation's _compute function, producing a new value and keeping track of dependencies.
*
* It handles the updating of sources and observers, disposal of previous executions,
* and error handling if the _compute function throws. It also sets the node as loading
* if it reads any parents that are currently loading.
*/
export declare function update<T>(node: Computation<T>): void;
export declare function isEqual<T>(a: T, b: T): boolean;
/**
* Returns the current value stored inside the given compute function without triggering any
* dependencies. Use `untrack` if you want to also disable owner tracking.
*/
export declare function untrack<T>(fn: () => T): T;
/**
* A convenient wrapper that calls `compute` with the `owner` and `observer` and is guaranteed
* to reset the global context after the computation is finished even if an error is thrown.
*/
export declare function compute<T>(owner: Owner | null, compute: (val: T) => T, observer: Computation<T>): T;
export declare function compute<T>(owner: Owner | null, compute: (val: undefined) => T, observer: null): T;
export {};
+25
View File
@@ -0,0 +1,25 @@
import { Computation, type MemoOptions } from './core';
/**
* By default, changes are batched on the microtask queue which is an async process. You can flush
* the queue synchronously to get the latest updates by calling `flushSync()`.
*/
export declare function flushSync(): void;
/**
* Effects are the leaf nodes of our reactive graph. When their sources change, they are
* automatically added to the queue of effects to re-execute, which will cause them to fetch their
* sources and recompute
*/
export declare class Effect<T = any> extends Computation<T> {
constructor(initialValue: T, compute: () => T, options?: MemoOptions<T>);
_notify(state: number): void;
write(value: T): T;
_setError(error: unknown): void;
}
export declare class RenderEffect<T = any> extends Computation<T> {
effect: (val: T) => void;
modified: boolean;
constructor(initialValue: T, compute: () => T, effect: (val: T) => void, options?: MemoOptions<T>);
_notify(state: number): void;
write(value: T): T;
_setError(error: unknown): void;
}
+11
View File
@@ -0,0 +1,11 @@
export declare class NotReadyError extends Error {
}
export declare class NoOwnerError extends Error {
constructor();
}
export declare class ContextNotFoundError extends Error {
constructor();
}
export interface ErrorHandler {
(error: unknown): void;
}
+8
View File
@@ -0,0 +1,8 @@
export type Flags = number;
export declare const ERROR_OFFSET = 0;
export declare const ERROR_BIT: number;
export declare const ERROR: unique symbol;
export declare const LOADING_OFFSET = 1;
export declare const LOADING_BIT: number;
export declare const LOADING: unique symbol;
export declare const DEFAULT_FLAGS: number;
+8
View File
@@ -0,0 +1,8 @@
export { ContextNotFoundError, NoOwnerError, NotReadyError, type ErrorHandler, } from './error';
export { Owner, createContext, getContext, setContext, hasContext, getOwner, setOwner, onCleanup, type Context, type ContextRecord, type Disposable, } from './owner';
export { Computation, compute, getObserver, isEqual, untrack, type MemoOptions, type SignalOptions, } from './core';
export { flushSync, Effect, RenderEffect } from './effect';
export { indexArray, mapArray, type Maybe } from './map';
export { createSelector, type SelectorOptions, type SelectorSignal, } from './selector';
export * from './signals';
export * from './store';
+26
View File
@@ -0,0 +1,26 @@
import type { Accessor } from './signals';
export type Maybe<T> = T | void | null | undefined | false;
/**
* Reactive map helper that caches each item by index to reduce unnecessary mapping on updates.
* It only runs the mapping function once per item and adds/removes as needed. In a non-keyed map
* like this the index is fixed but value can change (opposite of a keyed map).
*
* Prefer `mapArray` when referential checks are required.
*
* @see {@link https://github.com/solidjs/x-reactivity#indexarray}
*/
export declare function indexArray<Item, MappedItem>(list: Accessor<Maybe<readonly Item[]>>, map: (value: Accessor<Item>, index: number) => MappedItem, options?: {
name?: string;
}): Accessor<MappedItem[]>;
/**
* Reactive map helper that caches each list item by reference to reduce unnecessary mapping on
* updates. It only runs the mapping function once per item and then moves or removes it as needed.
* In a keyed map like this the value is fixed but the index changes (opposite of non-keyed map).
*
* Prefer `indexArray` when working with primitives to avoid unnecessary re-renders.
*
* @see {@link https://github.com/solidjs/x-reactivity#maparray}
*/
export declare function mapArray<Item, MappedItem>(list: Accessor<Maybe<readonly Item[]>>, map: (value: Item, index: Accessor<number>) => MappedItem, options?: {
name?: string;
}): Accessor<MappedItem[]>;
+88
View File
@@ -0,0 +1,88 @@
/**
* Owner tracking is used to enable nested tracking scopes with automatic cleanup.
* We also use owners to also keep track of which error handling context we are in.
*
* If you write the following
*
* const a = createOwner(() => {
* const b = createOwner(() => {});
*
* const c = createOwner(() => {
* const d = createOwner(() => {});
* });
*
* const e = createOwner(() => {});
* });
*
* The owner tree will look like this:
*
* a
* /|\
* b-c-e
* |
* d
*
* Following the _nextSibling pointers of each owner will first give you its children, and then its siblings (in reverse).
* a -> e -> c -> d -> b
*
* Note that the owner tree is largely orthogonal to the reactivity tree, and is much closer to the component tree.
*/
import { type ErrorHandler } from './error';
export type ContextRecord = Record<string | symbol, unknown>;
export interface Disposable {
(): void;
}
/**
* Returns the currently executing parent owner.
*/
export declare function getOwner(): Owner | null;
export declare function setOwner(owner: Owner | null): Owner | null;
export declare class Owner {
_parent: Owner | null;
_nextSibling: Owner | null;
_prevSibling: Owner | null;
_state: number;
_disposal: Disposable | Disposable[] | null;
_context: ContextRecord;
_handlers: ErrorHandler[] | null;
constructor(signal?: boolean);
append(child: Owner): void;
dispose(this: Owner, self?: boolean): void;
_disposeNode(): void;
emptyDisposal(): void;
handleError(error: unknown): void;
}
export interface Context<T> {
readonly id: symbol;
readonly defaultValue: T | undefined;
}
/**
* Context provides a form of dependency injection. It is used to save from needing to pass
* data as props through intermediate components. This function creates a new context object
* that can be used with `getContext` and `setContext`.
*
* A default value can be provided here which will be used when a specific value is not provided
* via a `setContext` call.
*/
export declare function createContext<T>(defaultValue?: T, description?: string): Context<T>;
/**
* Attempts to get a context value for the given key.
*
* @throws `NoOwnerError` if there's no owner at the time of call.
* @throws `ContextNotFoundError` if a context value has not been set yet.
*/
export declare function getContext<T>(context: Context<T>, owner?: Owner | null): T;
/**
* Attempts to set a context value on the parent scope with the given key.
*
* @throws `NoOwnerError` if there's no owner at the time of call.
*/
export declare function setContext<T>(context: Context<T>, value?: T, owner?: Owner | null): void;
/**
* Whether the given context is currently defined.
*/
export declare function hasContext(context: Context<any>, owner?: Owner | null): boolean;
/**
* Runs the given function when the parent owner computation is being disposed.
*/
export declare function onCleanup(disposable: Disposable): void;
+15
View File
@@ -0,0 +1,15 @@
import type { Accessor } from './signals';
export interface SelectorSignal<T> {
(key: T): Boolean;
}
export interface SelectorOptions<Key, Value> {
name?: string;
equals?: (key: Key, value: Value | undefined) => boolean;
}
/**
* Creates a signal that observes the given `source` and returns a new signal who only notifies
* observers when entering or exiting a specified key.
*
* @see {@link https://github.com/solidjs/x-reactivity#createselector}
*/
export declare function createSelector<Source, Key = Source>(source: Accessor<Source>, options?: SelectorOptions<Key, Source>): SelectorSignal<Key>;
+55
View File
@@ -0,0 +1,55 @@
import type { MemoOptions, SignalOptions } from './core';
import { Owner } from './owner';
export interface Accessor<T> {
(): T;
}
export interface Setter<T> {
(value: T | SetValue<T>): T;
}
export interface SetValue<T> {
(currentValue: T): T;
}
export type Signal<T> = [read: Accessor<T>, write: Setter<T>];
/**
* Wraps the given value into a signal. The signal will return the current value when invoked
* `fn()`, and provide a simple write API via `write()`. The value can now be observed
* when used inside other computations created with `computed` and `effect`.
*/
export declare function createSignal<T>(initialValue: T, options?: SignalOptions<T>): Signal<T>;
export declare function createAsync<T>(fn: () => Promise<T>, initial?: T, options?: SignalOptions<T>): Accessor<T>;
/**
* Creates a new computation whose value is computed and returned by the given function. The given
* compute function is _only_ re-run when one of it's dependencies are updated. Dependencies are
* are all signals that are read during execution.
*/
export declare function createMemo<T>(compute: () => T, initialValue?: T, options?: MemoOptions<T>): Accessor<T>;
/**
* Invokes the given function each time any of the signals that are read inside are updated
* (i.e., their value changes). The effect is immediately invoked on initialization.
*/
export declare function createEffect<T>(effect: () => T, initialValue?: T, options?: {
name?: string;
}): void;
/**
* Invokes the given function each time any of the signals that are read inside are updated
* (i.e., their value changes). The effect is immediately invoked on initialization.
*/
export declare function createRenderEffect<T>(compute: () => T, effect: (v: T) => T, initialValue?: T, options?: {
name?: string;
}): void;
/**
* Creates a computation root which is given a `dispose()` function to dispose of all inner
* computations.
*/
export declare function createRoot<T>(init: ((dispose: () => void) => T) | (() => T)): T;
/**
* Runs the given function in the given owner so that error handling and cleanups continue to work.
*
* Warning: Usually there are simpler ways of modeling a problem that avoid using this function
*/
export declare function runWithOwner<T>(owner: Owner | null, run: () => T): T | undefined;
/**
* Runs the given function when an error is thrown in a child owner. If the error is thrown again
* inside the error handler, it will trigger the next available parent owner handler.
*/
export declare function catchError<T>(fn: () => T, handler: (error: unknown) => void): void;
+22
View File
@@ -0,0 +1,22 @@
export type Store<T> = Readonly<T>;
export type StoreSetter<T> = (fn: (state: T) => void) => void;
export type StoreNode = Record<PropertyKey, any>;
export declare namespace SolidStore {
interface Unwrappable {
}
}
export type NotWrappable = string | number | bigint | symbol | boolean | Function | null | undefined | SolidStore.Unwrappable[keyof SolidStore.Unwrappable];
export declare function isWrappable<T>(obj: T | NotWrappable): obj is T;
/**
* Returns the underlying data in the store without a proxy.
* @param item store proxy object
* @example
* ```js
* const initial = {z...};
* const [state, setState] = createStore(initial);
* initial === state; // => false
* initial === unwrap(state); // => true
* ```
*/
export declare function unwrap<T>(item: T, set?: Set<unknown>): T;
export declare function createStore<T extends object = {}>(store: T | Store<T>): [get: Store<T>, set: StoreSetter<T>];
+1
View File
@@ -0,0 +1 @@
export declare function isUndefined(value: any): value is undefined;
+3
View File
@@ -0,0 +1,3 @@
URL + Version:
https://unpkg.com/browse/lean-qr@2.3.4/
+2 -2
View File
@@ -1,6 +1,6 @@
{
"name": "Satonomics",
"short_name": "Satonomics",
"name": "kibō",
"short_name": "kibō",
"description": "A better, FOSS, Bitcoin-only, self-hostable Glassnode",
"start_url": "/",
"display": "standalone",
+2833 -908
View File
File diff suppressed because it is too large Load Diff
-715
View File
@@ -1,715 +0,0 @@
/*
* Variables
*/
:root {
--default-font-family: "Satoshi";
--default-font-feature-settings: "normal";
--default-font-variation-settings: "normal";
--white: #ffffe3;
--black: #10100e;
--lighter-gray: #e8e8e8;
--light-gray: #c0c0ab;
--dark-gray: #666660;
--darker-gray: #30302b;
--orange: #f97315;
--background-color: var(--white);
--color: var(--black);
--off-color: var(--light-gray);
--border-color: var(--lighter-gray);
--font-size-2xs: 0.625rem; /* 10px */
--line-height-2xs: 1rem; /* 16px */
--font-size-xs: 0.75rem; /* 12px */
--line-height-xs: 1rem; /* 16px */
--font-size-sm: 0.875rem; /* 14px */
--line-height-sm: 1.25rem; /* 20px */
--font-size-base: 1rem /* 16px */;
--line-height-base: 1.5rem /* 24px */;
--font-size-lg: 1.125rem /* 18px */;
--line-height-lg: 1.75rem /* 28px */;
--font-weight-medium: 500;
}
/* https://dev.to/ananyaneogi/create-a-dark-light-mode-switch-with-css-variables-34l8 */
/* https://www.typescriptlang.org/docs/handbook/jsdoc-supported-types.html#link */
[data-theme="dark"] {
--background-color: var(--black);
--color: var(--white);
--off-color: var(--dark-gray);
--border-color: var(--darker-gray);
}
/*
* ---
* Base Tailwind
* ---
*/
*,
::after,
::before,
::backdrop,
::file-selector-button {
box-sizing: border-box;
margin: 0;
padding: 0;
border: 0 solid;
}
html,
:host {
line-height: 1.5;
-webkit-text-size-adjust: 100%;
tab-size: 4;
font-family: var(--default-font-family), ui-sans-serif, system-ui, sans-serif,
"Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
font-feature-settings: var(--default-font-feature-settings, normal);
font-variation-settings: var(--default-font-variation-settings, normal);
-webkit-tap-highlight-color: transparent;
}
body {
line-height: inherit;
}
hr {
height: 0;
color: inherit;
border-top-width: 1px;
}
abbr:where([title]) {
-webkit-text-decoration: underline dotted;
text-decoration: underline dotted;
}
h1,
h2,
h3,
h4,
h5,
h6 {
font-size: inherit;
font-weight: inherit;
}
a {
color: inherit;
-webkit-text-decoration: inherit;
text-decoration: inherit;
}
b,
strong {
font-weight: bolder;
}
code,
kbd,
samp,
pre {
font-family: var(
--default-mono-font-family,
ui-monospace,
SFMono-Regular,
Menlo,
Monaco,
Consolas,
"Liberation Mono",
"Courier New",
monospace
);
font-feature-settings: var(--default-mono-font-feature-settings, normal);
font-variation-settings: var(--default-mono-font-variation-settings, normal);
font-size: 1em;
}
small {
font-size: 80%;
}
sub,
sup {
font-size: 75%;
line-height: 0;
position: relative;
vertical-align: baseline;
}
sub {
bottom: -0.25em;
}
sup {
top: -0.5em;
}
table {
text-indent: 0;
border-color: inherit;
border-collapse: collapse;
}
button,
input,
optgroup,
select,
textarea,
::file-selector-button {
font: inherit;
font-feature-settings: inherit;
font-variation-settings: inherit;
letter-spacing: inherit;
color: inherit;
background: transparent;
}
input:where(:not([type="button"], [type="reset"], [type="submit"])),
select,
textarea {
border: 1px solid;
}
button,
input:where([type="button"], [type="reset"], [type="submit"]),
::file-selector-button {
appearance: button;
}
:-moz-focusring {
outline: auto;
}
:-moz-ui-invalid {
box-shadow: none;
}
progress {
vertical-align: baseline;
}
::-webkit-inner-spin-button,
::-webkit-outer-spin-button {
height: auto;
}
::-webkit-search-decoration {
-webkit-appearance: none;
}
summary {
display: list-item;
}
ol,
ul,
menu {
list-style: none;
}
textarea {
resize: vertical;
}
::placeholder {
opacity: 1;
color: color-mix(in srgb, currentColor 50%, transparent);
}
:disabled {
cursor: default;
}
img,
svg,
video,
canvas,
audio,
iframe,
embed,
object {
display: block;
vertical-align: middle;
}
img,
video {
max-width: 100%;
height: auto;
}
[hidden] {
display: none !important;
}
/*
* ---
* Custom
* ---
*/
/**
* @license
*
* Font Family: Satoshi
* Designed by: Deni Anggara
* URL: https://www.fontshare.com/fonts/satoshi
* © 2024 Indian Type Foundry
*
* This is a variable font
* You can control variable axes as shown below:
* font-variation-settings: wght 900.0;
*
* available axes: 'wght' (range from 300.0 to 900.0)
*/
@font-face {
font-family: "Satoshi";
src: url("./fonts/Satoshi.var.woff2") format("woff2");
font-weight: 100 900;
font-display: block;
font-style: normal;
}
@font-face {
font-family: "Satoshi Chart";
src: url("./fonts/Satoshi.var.woff2") format("woff2");
font-weight: 600 900;
font-display: block;
font-style: normal;
}
html {
background-color: var(--background-color);
color: var(--color);
scrollbar-color: var(--off-color) var(--background-color); /* Foreground, Background */
scrollbar-width: thin;
}
body {
font-size: var(--font-size-sm);
line-height: var(--line-height-sm);
}
a:hover {
color: var(--color);
}
button {
cursor: pointer;
background-color: var(--background-color);
}
hr {
width: 100%;
}
::marker {
color: var(--border-color);
}
button:hover,
button:hover .off,
nav > fieldset > label:hover,
summary:hover,
li:hover > label > span,
summary:hover::marker,
strong,
mark {
color: var(--orange);
}
* {
border-color: var(--border-color) !important;
border-style: solid !important;
}
*::selection {
color: var(--white);
background-color: var(--orange);
}
a {
display: inline-flex;
color: var(--color);
}
a:hover {
text-decoration-color: var(--orange);
text-decoration-line: underline;
text-decoration-style: wavy;
}
a:active,
button:active,
nav > fieldset > label:active {
transform: scaleX(0.95) scaleY(0.9);
}
nav > button,
nav > a,
p > a:has(svg),
nav > fieldset > label {
padding: 1rem;
}
svg {
width: 20px;
height: 20px;
color: var(--off-color);
fill: currentColor;
}
a:hover > svg,
button:hover > svg,
nav > fieldset > label:hover > svg,
label:has(input:checked) > svg {
color: currentColor;
}
button:disabled {
color: var(--off-color);
}
mark {
background-color: transparent;
padding: 0;
}
/* Hide scrollbar for Chrome, Safari and Opera */
.no-scrollbar::-webkit-scrollbar {
display: none;
}
/* Hide scrollbar for IE, Edge and Firefox */
.no-scrollbar {
-ms-overflow-style: none; /* IE and Edge */
scrollbar-width: none; /* Firefox */
}
section {
flex: 1 1 0%;
overflow-x: hidden;
overflow-y: auto;
padding: 1.5rem /* 24px */;
height: 100%;
}
section:not(#selected-frame) {
padding-bottom: 21vh;
}
section > * + * {
margin-top: 1.5rem; /* 24px */
}
fieldset label {
position: relative;
}
fieldset label span.absolute {
text-align: center;
position: absolute;
bottom: 0;
margin-bottom: -0.5rem;
font-size: var(--font-size-2xs);
line-height: var(--line-height-2xs);
overflow: visible;
left: 0;
right: 0;
color: var(--off-color);
}
@media (min-width: 768px) {
.md\:hidden {
display: none !important;
}
}
input {
border: 0;
width: 100%;
}
input:focus-visible {
outline: none;
}
input::placeholder {
color: var(--off-color);
}
.sr-only,
input[type="radio"] {
position: absolute;
width: 1px;
height: 1px;
padding: 0;
margin: -1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
white-space: nowrap;
border-width: 0;
}
h1,
h2,
h3 {
font-weight: 700;
font-size: var(--font-size-lg);
line-height: var(--line-height-lg);
}
h4 {
font-size: var(--font-size-base);
line-height: var(--line-height-base);
font-weight: 500;
}
@media (min-width: 768px) {
h1,
h2,
h3 {
font-size: 1.25rem /* 20px */;
}
}
p {
margin-top: 1rem;
}
section > header {
display: flex;
padding-top: 0.25rem /* 4px */;
white-space: nowrap;
overflow-x: auto;
padding-bottom: 1.5rem;
margin-bottom: -1.5rem;
padding-left: 1.5rem;
margin-left: -1.5rem;
padding-right: 1.5rem;
margin-right: -1.5rem;
}
header > div {
flex: 1 1 0%;
}
section > header small {
font-size: var(--font-size-base);
line-height: var(--line-height-base);
}
section:not(#settings-frame) > footer {
position: absolute;
bottom: 0;
right: 0;
display: flex;
padding: 1.5rem /* 24px */;
z-index: 10;
}
section:not(#settings-frame) > footer > * + * {
margin-left: 1rem /* 16px */;
}
section:not(#settings-frame) > footer > button {
box-shadow: 0 0 1rem 0.5rem var(--background-color);
border-radius: 9999px;
border-width: 1px;
padding: 0.75rem /* 12px */;
}
.field {
display: flex;
align-items: center;
font-size: var(--font-size-sm);
line-height: var(--line-height-sm);
}
.field > * + * {
margin-left: 1.5rem;
}
.field > div > * + * {
margin-left: 1rem !important;
}
.field label {
padding: 0.5rem;
margin: -0.5rem;
}
.field > div {
display: flex;
}
.tree {
font-weight: var(--font-weight-medium);
font-size: var(--font-size-sm);
line-height: var(--line-height-sm);
}
summary {
list-style: none;
display: flex;
align-items: center;
cursor: pointer;
}
label:has(input[type="radio"]) {
cursor: pointer;
display: flex;
flex-direction: column;
user-select: none;
font-weight: var(--font-weight-medium);
color: var(--off-color);
}
label:has(input[type="radio"]:checked) {
color: var(--color);
}
label:has(input[type="radio"]) > span.main {
display: flex;
align-items: center;
}
label:has(input[type="radio"]) > *:not(input[type="radio"]) {
width: 100%;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
label:has(input[type="radio"]) > *:not(input[type="radio"]) + * {
margin-top: -0.5rem /* -8px */;
}
label:has(input[type="radio"]) .emoji {
line-height: 0.9;
filter: grayscale(100%) brightness(60%) contrast(150%);
font-size: 1.0625rem;
}
label:has(input[type="radio"]:checked) .emoji,
label:has(input[type="radio"]):hover .emoji {
filter: sepia(90%) saturate(420%) hue-rotate(320deg) brightness(80%);
}
.tree label:has(input[type="radio"]),
.list label:has(input[type="radio"]) {
color: var(--color);
}
label:has(input[type="radio"]):hover,
label:has(input[type="radio"]):hover *,
.tree label:has(input[type="radio"]:checked),
.tree label:has(input[type="radio"]:checked) *,
.list label:has(input[type="radio"]:checked),
.list label:has(input[type="radio"]:checked) * {
color: var(--orange) !important;
}
summary:hover * {
color: var(--orange) !important;
}
summary::marker,
summary::-webkit-details-marker {
display: none;
}
span.name {
margin: 0.375rem /* 6px */;
flex: 1 1 0%;
width: 100%;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.tree .marker {
color: var(--border-color);
font-size: var(--font-size-xs);
line-height: var(--line-height-xs);
z-index: 10;
margin-left: -5px;
margin-bottom: 0.0625rem;
}
.main .new {
width: 0.375rem /* 6px */;
height: 0.375rem /* 6px */;
border-radius: 9999px;
background-color: var(--orange);
}
.tree li {
display: block;
position: relative;
padding-left: 12px;
border-left: 1px;
}
.tree li:last-child {
border-color: transparent !important;
}
.tree li::before {
content: "";
display: block;
position: absolute;
top: -12px;
left: -1px;
width: 9px;
height: 1.75rem;
border-color: var(--border-color);
border-width: 0 0 1px 1px;
border-radius: 0px 0px 0px 4px;
}
.tree summary > small {
margin-top: 0.125rem;
}
.list > * + * {
margin-top: 0.25rem;
}
/*
* History heading
*/
:root {
--history-heading-margin: calc(-1.5rem - 1px);
}
.list h4 {
position: sticky;
top: var(--history-heading-margin);
z-index: 10;
background-color: var(--background-color);
padding: 1rem;
padding-left: 0;
border-top-width: 1px;
border-bottom-width: 1px;
margin-bottom: 1rem;
margin-top: 2rem;
}
.list h4:first-child {
margin-top: var(--history-heading-margin);
}
small {
color: var(--off-color);
font-size: var(--font-size-xs);
line-height: var(--line-height-xs);
}
#leaderboard {
margin-top: 1rem;
color: var(--off-color);
margin-left: 1.375rem;
list-style-type: decimal;
font-size: var(--font-size-xs);
line-height: var(--line-height-xs);
}
#leaderboard ::marker {
color: var(--off-color);
}
#leaderboard a {
font-size: var(--font-size-sm);
line-height: var(--line-height-sm);
}
#leaderboard span {
color: var(--orange);
}
+3 -2
View File
@@ -3,7 +3,8 @@
"checkJs": true,
"strict": true,
"target": "ESNext",
"module": "ESNext"
"module": "ESNext",
"outDir": "/tmp/kibo"
},
"exclude": ["assets", "libraries"]
"exclude": ["assets", "libraries", "ignore"]
}
+73 -27
View File
@@ -1,5 +1,6 @@
type Scale = "date" | "height";
import { Accessor, Setter } from "../libraries/solid-signals/types/signals";
import {
DeepPartial,
BaselineStyleOptions,
@@ -10,33 +11,54 @@ import {
Time,
SingleValueData,
CandlestickData,
SeriesType,
IChartApi,
ISeriesApi,
} from "../libraries/lightweight-charts/types";
import { DatePath, HeightPath } from "./paths";
type Signal<T> = Accessor<T> & { set: Setter<T> };
type TimeRange = Range<Time | number>;
type DatasetPath<S extends Scale> = S extends "date" ? DatePath : HeightPath;
type AnyDatasetPath = import("./paths").DatePath | import("./paths").HeightPath;
type Color = string;
type Color = () => string;
type SeriesConfig = {
interface BaselineSpecificSeriesBlueprint {
type: "Baseline";
color?: Color;
options?: DeepPartial<BaselineStyleOptions & SeriesOptionsCommon>;
}
interface CandlestickSpecificSeriesBlueprint {
type: "Candlestick";
color?: undefined;
options?: DeepPartial<CandlestickStyleOptions & SeriesOptionsCommon>;
}
interface LineSpecificSeriesBlueprint {
type?: "Line";
color: Color;
options?: DeepPartial<LineStyleOptions & SeriesOptionsCommon>;
}
type AnySpecificSeriesBlueprint =
| BaselineSpecificSeriesBlueprint
| CandlestickSpecificSeriesBlueprint
| LineSpecificSeriesBlueprint;
type SpecificSeriesBlueprintWithChart<A extends AnySpecificSeriesBlueprint> = {
chart: IChartApi;
} & Omit<A, "type">;
type SeriesBlueprint = {
datasetPath: AnyDatasetPath;
title: string;
defaultVisible?: boolean;
} & (
| {
color?: Color;
seriesType: "Based";
options?: DeepPartial<BaselineStyleOptions & SeriesOptionsCommon>;
}
| {
seriesType: "Candlestick";
options?: DeepPartial<CandlestickStyleOptions & SeriesOptionsCommon>;
}
| {
seriesType?: "Line";
options?: DeepPartial<LineStyleOptions & SeriesOptionsCommon>;
}
);
defaultActive?: boolean;
} & AnySpecificSeriesBlueprint;
type Unit =
| "US Dollars"
@@ -55,19 +77,19 @@ type Unit =
| "Dollars / (PetaHash / Second)"
| "";
interface PresetParams {
top?: SeriesConfig[];
bottom?: SeriesConfig[];
interface PresetBlueprint {
top?: SeriesBlueprint[];
bottom?: SeriesBlueprint[];
}
type PartialPreset = {
interface PartialPreset extends PresetBlueprint {
scale: Scale;
icon: string;
name: string;
unit: Unit;
title: string;
description: string;
} & PresetParams;
}
interface PartialPresetFolder {
name: string;
@@ -107,13 +129,13 @@ interface OHLC {
interface ResourceDataset<
S extends Scale,
Type extends OHLC | number = number
Type extends OHLC | number = number,
> {
scale: S;
url: string;
fetch: (id: number) => void;
fetchedJSONs: FetchedResult<S, Type>[];
drop: VoidFunction;
// drop: VoidFunction;
}
type ValuedCandlestickData = CandlestickData & Valued;
@@ -125,7 +147,7 @@ interface FetchedResult<
SingleValueData | ValuedCandlestickData
> = DatasetValue<
Type extends number ? SingleValueData : ValuedCandlestickData
>
>,
> {
at: Date | null;
json: Signal<FetchedJSON<S, Type> | null>;
@@ -155,7 +177,7 @@ interface FetchedChunk {
type FetchedDataset<
S extends Scale,
Type extends number | OHLC
Type extends number | OHLC,
> = S extends "date" ? FetchedDateDataset<Type> : FetchedHeightDataset<Type>;
interface Versioned {
@@ -169,3 +191,27 @@ interface FetchedDateDataset<Type> extends Versioned {
interface FetchedHeightDataset<Type> extends Versioned {
map: Type[];
}
type PriceSeriesType = "Candlestick" | "Line";
interface Series {
id: string;
title: string;
chunks: Array<Accessor<ISeriesApi<SeriesType> | undefined>>;
color: Color | Color[];
disabled: Accessor<boolean>;
active: Signal<boolean>;
visible: Accessor<boolean>;
dataset: ResourceDataset<Scale, number>;
}
interface Marker {
weight: number;
time: Time;
value: number;
seriesChunk: ISeriesApi<any>;
}
interface Weighted {
weight: number;
}