mirror of
https://github.com/bitcoinresearchkit/brk.git
synced 2026-05-29 23:19:28 -07:00
app: add chart scroll buttons
This commit is contained in:
14
app/pnpm-lock.yaml
generated
14
app/pnpm-lock.yaml
generated
@@ -2507,7 +2507,7 @@ packages:
|
||||
postcss: ^8.1.0
|
||||
dependencies:
|
||||
browserslist: 4.23.2
|
||||
caniuse-lite: 1.0.30001642
|
||||
caniuse-lite: 1.0.30001643
|
||||
fraction.js: 4.3.7
|
||||
normalize-range: 0.1.2
|
||||
picocolors: 1.0.1
|
||||
@@ -2634,9 +2634,9 @@ packages:
|
||||
engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7}
|
||||
hasBin: true
|
||||
dependencies:
|
||||
caniuse-lite: 1.0.30001642
|
||||
caniuse-lite: 1.0.30001643
|
||||
electron-to-chromium: 1.4.832
|
||||
node-releases: 2.0.17
|
||||
node-releases: 2.0.18
|
||||
update-browserslist-db: 1.1.0(browserslist@4.23.2)
|
||||
dev: true
|
||||
|
||||
@@ -2694,8 +2694,8 @@ packages:
|
||||
engines: {node: '>=6'}
|
||||
dev: true
|
||||
|
||||
/caniuse-lite@1.0.30001642:
|
||||
resolution: {integrity: sha512-3XQ0DoRgLijXJErLSl+bLnJ+Et4KqV1PY6JJBGAFlsNsz31zeAIncyeZfLCabHK/jtSh+671RM9YMldxjUPZtA==}
|
||||
/caniuse-lite@1.0.30001643:
|
||||
resolution: {integrity: sha512-ERgWGNleEilSrHM6iUz/zJNSQTP8Mr21wDWpdgvRwcTXGAq6jMtOUPP4dqFPTdKqZ2wKTdtB+uucZ3MRpAUSmg==}
|
||||
dev: true
|
||||
|
||||
/capnp-ts@0.7.0:
|
||||
@@ -4381,8 +4381,8 @@ packages:
|
||||
engines: {node: '>= 6.13.0'}
|
||||
dev: true
|
||||
|
||||
/node-releases@2.0.17:
|
||||
resolution: {integrity: sha512-Ww6ZlOiEQfPfXM45v17oabk77Z7mg5bOt7AjDyzy7RjK9OrLrLC8dyZQoAPEOtFX9SaNf1Tdvr5gRJWdTJj7GA==}
|
||||
/node-releases@2.0.18:
|
||||
resolution: {integrity: sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g==}
|
||||
dev: true
|
||||
|
||||
/nopt@7.2.1:
|
||||
|
||||
@@ -4,6 +4,7 @@ export function Box({
|
||||
flex = true,
|
||||
absolute,
|
||||
padded = true,
|
||||
spaced = true,
|
||||
children,
|
||||
dark,
|
||||
classes,
|
||||
@@ -11,6 +12,7 @@ export function Box({
|
||||
flex?: boolean;
|
||||
absolute?: "top" | "bottom";
|
||||
padded?: boolean;
|
||||
spaced?: boolean;
|
||||
dark?: boolean;
|
||||
classes?: string;
|
||||
} & ParentProps) {
|
||||
@@ -39,7 +41,8 @@ export function Box({
|
||||
>
|
||||
<div
|
||||
class={classPropToString([
|
||||
flex && "flex w-full space-x-2",
|
||||
flex && "flex w-full",
|
||||
spaced && "space-x-2",
|
||||
padded && "p-1.5",
|
||||
])}
|
||||
>
|
||||
|
||||
@@ -1,10 +1,16 @@
|
||||
import { ONE_DAY_IN_MS } from "/src/scripts/utils/time";
|
||||
import { classPropToString } from "/src/solid/classes";
|
||||
import { createRWS } from "/src/solid/rws";
|
||||
|
||||
import { GENESIS_DAY } from "../../../../../scripts/lightweightCharts/whitespace";
|
||||
import { Box } from "../../box";
|
||||
import { Scrollable } from "../../scrollable";
|
||||
|
||||
const MULTIPLIER = 0.002;
|
||||
const DELAY = 10;
|
||||
const LEFT = -1;
|
||||
const RIGHT = 1;
|
||||
|
||||
export function TimeScale({
|
||||
scale,
|
||||
charts,
|
||||
@@ -16,30 +22,82 @@ export function TimeScale({
|
||||
|
||||
const disabled = createMemo(() => charts().length === 0);
|
||||
|
||||
const scrollDirection = createRWS(0);
|
||||
|
||||
const timeScale = createMemo(() => {
|
||||
const chart = charts().at(0);
|
||||
if (!chart) return undefined;
|
||||
return chart.timeScale();
|
||||
});
|
||||
|
||||
const interval = setInterval(() => {
|
||||
const time = timeScale();
|
||||
|
||||
if (!time) return;
|
||||
|
||||
const direction = scrollDirection();
|
||||
|
||||
if (!direction) return;
|
||||
|
||||
const range = time.getVisibleLogicalRange();
|
||||
|
||||
if (!range) return;
|
||||
|
||||
const speed = (range.to - range.from) * MULTIPLIER * direction;
|
||||
|
||||
// @ts-ignore
|
||||
range.from += speed;
|
||||
// @ts-ignore
|
||||
range.to += speed;
|
||||
|
||||
time.setVisibleLogicalRange(range);
|
||||
}, DELAY);
|
||||
|
||||
onCleanup(() => clearInterval(interval));
|
||||
|
||||
return (
|
||||
<Box dark padded={false} classes="short:hidden">
|
||||
<Box dark padded={false} spaced={false} classes="short:hidden">
|
||||
<div class="flex items-center p-1.5">
|
||||
<Button
|
||||
square
|
||||
disabled={disabled}
|
||||
onClick={() => scrollDirection.set((v) => (v === LEFT ? 0 : LEFT))}
|
||||
>
|
||||
<Show
|
||||
when={scrollDirection() === LEFT}
|
||||
fallback={<IconTablerPlayerTrackPrevFilled />}
|
||||
>
|
||||
<IconTablerPlayerPauseFilled />
|
||||
</Show>
|
||||
</Button>
|
||||
</div>
|
||||
<div class="border-lighter border-l" />
|
||||
<Scrollable classes="p-1.5 space-x-2">
|
||||
<Switch>
|
||||
<Match when={scale() === "date"}>
|
||||
<Button
|
||||
minWidth
|
||||
disabled={disabled}
|
||||
onClick={() => setTimeScale({ scale: scale(), charts })}
|
||||
>
|
||||
All Time
|
||||
</Button>
|
||||
<Button
|
||||
minWidth
|
||||
disabled={disabled}
|
||||
onClick={() => setTimeScale({ scale: scale(), charts, days: 7 })}
|
||||
>
|
||||
1 Week
|
||||
</Button>
|
||||
<Button
|
||||
minWidth
|
||||
disabled={disabled}
|
||||
onClick={() => setTimeScale({ scale: scale(), charts, days: 30 })}
|
||||
>
|
||||
1 Month
|
||||
</Button>
|
||||
<Button
|
||||
minWidth
|
||||
disabled={disabled}
|
||||
onClick={() =>
|
||||
setTimeScale({ scale: scale(), charts, days: 3 * 30 })
|
||||
@@ -48,6 +106,7 @@ export function TimeScale({
|
||||
3 Months
|
||||
</Button>
|
||||
<Button
|
||||
minWidth
|
||||
disabled={disabled}
|
||||
onClick={() =>
|
||||
setTimeScale({ scale: scale(), charts, days: 6 * 30 })
|
||||
@@ -56,6 +115,7 @@ export function TimeScale({
|
||||
6 Months
|
||||
</Button>
|
||||
<Button
|
||||
minWidth
|
||||
disabled={disabled}
|
||||
onClick={() =>
|
||||
setTimeScale({
|
||||
@@ -72,6 +132,7 @@ export function TimeScale({
|
||||
Year To Date
|
||||
</Button>
|
||||
<Button
|
||||
minWidth
|
||||
disabled={disabled}
|
||||
onClick={() =>
|
||||
setTimeScale({ scale: scale(), charts, days: 365 })
|
||||
@@ -80,6 +141,7 @@ export function TimeScale({
|
||||
1 Year
|
||||
</Button>
|
||||
<Button
|
||||
minWidth
|
||||
disabled={disabled}
|
||||
onClick={() =>
|
||||
setTimeScale({ scale: scale(), charts, days: 2 * 365 })
|
||||
@@ -88,6 +150,7 @@ export function TimeScale({
|
||||
2 Years
|
||||
</Button>
|
||||
<Button
|
||||
minWidth
|
||||
disabled={disabled}
|
||||
onClick={() =>
|
||||
setTimeScale({ scale: scale(), charts, days: 4 * 365 })
|
||||
@@ -96,6 +159,7 @@ export function TimeScale({
|
||||
4 Years
|
||||
</Button>
|
||||
<Button
|
||||
minWidth
|
||||
disabled={disabled}
|
||||
onClick={() =>
|
||||
setTimeScale({ scale: scale(), charts, days: 8 * 365 })
|
||||
@@ -113,6 +177,7 @@ export function TimeScale({
|
||||
>
|
||||
{(year) => (
|
||||
<Button
|
||||
minWidth
|
||||
disabled={disabled}
|
||||
onClick={() => setTimeScale({ scale: scale(), charts, year })}
|
||||
>
|
||||
@@ -122,10 +187,10 @@ export function TimeScale({
|
||||
</For>
|
||||
</Match>
|
||||
<Match when={scale() === "height"}>
|
||||
<Button disabled={() => true} onClick={() => {}}>
|
||||
<Button minWidth disabled={() => true} onClick={() => {}}>
|
||||
24h
|
||||
</Button>
|
||||
<Button disabled={() => true} onClick={() => {}}>
|
||||
<Button minWidth disabled={() => true} onClick={() => {}}>
|
||||
48h
|
||||
</Button>
|
||||
<For
|
||||
@@ -136,6 +201,7 @@ export function TimeScale({
|
||||
>
|
||||
{(i) => (
|
||||
<Button
|
||||
minWidth
|
||||
disabled={disabled}
|
||||
onClick={() =>
|
||||
setTimeScale({
|
||||
@@ -155,6 +221,21 @@ export function TimeScale({
|
||||
</Match>
|
||||
</Switch>
|
||||
</Scrollable>
|
||||
<div class="border-lighter border-l" />
|
||||
<div class="flex items-center p-1.5">
|
||||
<Button
|
||||
square
|
||||
disabled={disabled}
|
||||
onClick={() => scrollDirection.set((v) => (v === RIGHT ? 0 : RIGHT))}
|
||||
>
|
||||
<Show
|
||||
when={scrollDirection() === RIGHT}
|
||||
fallback={<IconTablerPlayerTrackNextFilled />}
|
||||
>
|
||||
<IconTablerPlayerPauseFilled />
|
||||
</Show>
|
||||
</Button>
|
||||
</div>
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
@@ -163,17 +244,26 @@ function Button({
|
||||
onClick,
|
||||
disabled,
|
||||
children,
|
||||
}: ParentProps & { onClick: VoidFunction; disabled: Accessor<boolean> }) {
|
||||
minWidth,
|
||||
square,
|
||||
}: ParentProps & {
|
||||
onClick: VoidFunction;
|
||||
disabled?: Accessor<boolean>;
|
||||
minWidth?: boolean;
|
||||
square?: boolean;
|
||||
}) {
|
||||
return (
|
||||
<button
|
||||
class={classPropToString([
|
||||
disabled()
|
||||
minWidth && "min-w-20",
|
||||
square ? "p-2" : "px-2 py-1.5",
|
||||
disabled?.()
|
||||
? "text-low-contrast"
|
||||
: "hover:bg-orange-50/20 active:scale-95",
|
||||
"min-w-20 flex-shrink-0 flex-grow whitespace-nowrap rounded-lg px-2 py-1.5",
|
||||
"flex-shrink-0 flex-grow whitespace-nowrap rounded-lg",
|
||||
])}
|
||||
onClick={onClick}
|
||||
disabled={disabled()}
|
||||
disabled={disabled?.()}
|
||||
>
|
||||
{children}
|
||||
</button>
|
||||
|
||||
8
app/src/types/auto-imports.d.ts
vendored
8
app/src/types/auto-imports.d.ts
vendored
@@ -193,8 +193,12 @@ declare global {
|
||||
const IconTablerPigMoney: typeof import('~icons/tabler/pig-money.jsx')['default']
|
||||
const IconTablerPlay: (typeof import("~icons/tabler/play.jsx"))["default"]
|
||||
const IconTablerPlayCard: typeof import('~icons/tabler/play-card.jsx')['default']
|
||||
const IconTablerPlayerPauseFilled: (typeof import("~icons/tabler/player-pause-filled.jsx"))["default"]
|
||||
const IconTablerPlayerPlayFilled: (typeof import("~icons/tabler/player-play-filled.jsx"))["default"]
|
||||
const IconTablerPlayerPauseFilled: typeof import('~icons/tabler/player-pause-filled.jsx')['default']
|
||||
const IconTablerPlayerPlayFilled: typeof import('~icons/tabler/player-play-filled.jsx')['default']
|
||||
const IconTablerPlayerTrackNext: typeof import('~icons/tabler/player-track-next.jsx')['default']
|
||||
const IconTablerPlayerTrackNextFilled: typeof import('~icons/tabler/player-track-next-filled.jsx')['default']
|
||||
const IconTablerPlayerTrackPrev: typeof import('~icons/tabler/player-track-prev.jsx')['default']
|
||||
const IconTablerPlayerTrackPrevFilled: typeof import('~icons/tabler/player-track-prev-filled.jsx')['default']
|
||||
const IconTablerPlus: typeof import('~icons/tabler/plus.jsx')['default']
|
||||
const IconTablerQrCode: typeof import('~icons/tabler/qr-code.jsx')['default']
|
||||
const IconTablerQrcode: typeof import('~icons/tabler/qrcode.jsx')['default']
|
||||
|
||||
Reference in New Issue
Block a user