mirror of
https://github.com/bitcoinresearchkit/brk.git
synced 2026-06-10 15:03:32 -07:00
website: redesign part 26
This commit is contained in:
@@ -59,6 +59,11 @@
|
||||
}
|
||||
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
html {
|
||||
--transition-duration: 0ms;
|
||||
--reveal-duration: 0ms;
|
||||
}
|
||||
|
||||
body::before {
|
||||
transition: none;
|
||||
}
|
||||
|
||||
@@ -40,62 +40,50 @@ main.learn {
|
||||
|
||||
span {
|
||||
display: block;
|
||||
padding: 0.25rem;
|
||||
border-radius: 0.25rem;
|
||||
color: var(--gray);
|
||||
}
|
||||
|
||||
label:hover span {
|
||||
color: var(--black);
|
||||
background: var(--white);
|
||||
}
|
||||
|
||||
label:has(:checked):not(:hover) span {
|
||||
color: var(--black);
|
||||
background: var(--gray);
|
||||
}
|
||||
|
||||
label:active span {
|
||||
color: var(--black);
|
||||
background: var(--orange);
|
||||
}
|
||||
|
||||
label:has(:focus-visible) span {
|
||||
outline: 1px solid var(--orange);
|
||||
outline-offset: 0.125rem;
|
||||
}
|
||||
}
|
||||
|
||||
button[data-chart="fullscreen"] {
|
||||
padding: 0.25rem;
|
||||
border: 0;
|
||||
border-radius: 0.25rem;
|
||||
color: var(--gray);
|
||||
background: none;
|
||||
font: inherit;
|
||||
line-height: inherit;
|
||||
text-transform: uppercase;
|
||||
cursor: pointer;
|
||||
|
||||
&:hover {
|
||||
color: var(--black);
|
||||
background: var(--white);
|
||||
}
|
||||
|
||||
&[aria-pressed="true"] {
|
||||
color: var(--black);
|
||||
background: var(--green);
|
||||
}
|
||||
}
|
||||
|
||||
&:active {
|
||||
color: var(--black);
|
||||
background: var(--orange);
|
||||
}
|
||||
:is(label > span, button[data-chart="fullscreen"]) {
|
||||
padding: 0.25rem;
|
||||
border-radius: 0.25rem;
|
||||
color: var(--gray);
|
||||
}
|
||||
|
||||
&:focus-visible {
|
||||
outline: 1px solid var(--orange);
|
||||
outline-offset: 0.125rem;
|
||||
}
|
||||
:is(label:hover span, button[data-chart="fullscreen"]:hover) {
|
||||
color: var(--black);
|
||||
background: var(--white);
|
||||
}
|
||||
|
||||
:is(label:active span, button[data-chart="fullscreen"]:active) {
|
||||
color: var(--black);
|
||||
background: var(--orange);
|
||||
}
|
||||
|
||||
:is(
|
||||
label:has(:focus-visible) span,
|
||||
button[data-chart="fullscreen"]:focus-visible
|
||||
) {
|
||||
outline: 1px solid var(--orange);
|
||||
outline-offset: 0.125rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,45 +1,134 @@
|
||||
const suffixes = ["M", "B", "T", "P", "E", "Z", "Y"];
|
||||
const numberFormats = [0, 1, 2, 3].map(
|
||||
(digits) =>
|
||||
new Intl.NumberFormat("en-US", {
|
||||
maximumFractionDigits: digits,
|
||||
minimumFractionDigits: digits,
|
||||
}),
|
||||
);
|
||||
const percentFormat = new Intl.NumberFormat("en-US", {
|
||||
maximumFractionDigits: 2,
|
||||
minimumFractionDigits: 2,
|
||||
});
|
||||
const compactBase = 1_000_000;
|
||||
const compactStep = 1_000;
|
||||
const compactMax = 1e27;
|
||||
const maxLength = 7;
|
||||
const tinyDigits = [3, 2, 1, 0];
|
||||
const smallDigits = [2, 1, 0];
|
||||
const mediumDigits = [1, 0];
|
||||
const integerDigits = [0];
|
||||
const numberFormats = createNumberFormats(true);
|
||||
const ungroupedNumberFormats = createNumberFormats(false);
|
||||
|
||||
/** @param {boolean} useGrouping */
|
||||
function createNumberFormats(useGrouping) {
|
||||
return [0, 1, 2, 3].map(
|
||||
(digits) =>
|
||||
new Intl.NumberFormat("en-US", {
|
||||
maximumFractionDigits: digits,
|
||||
minimumFractionDigits: digits,
|
||||
useGrouping,
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {number} value
|
||||
* @param {number} digits
|
||||
* @param {boolean} [useGrouping]
|
||||
*/
|
||||
function formatNumber(value, digits) {
|
||||
return numberFormats[digits].format(value);
|
||||
function formatNumber(value, digits, useGrouping = true) {
|
||||
return (useGrouping ? numberFormats : ungroupedNumberFormats)[digits].format(
|
||||
value,
|
||||
);
|
||||
}
|
||||
|
||||
/** @param {number} value */
|
||||
export function formatNumberValue(value) {
|
||||
/** @param {string} value */
|
||||
function parseFormattedNumber(value) {
|
||||
return Number(value.replaceAll(",", ""));
|
||||
}
|
||||
|
||||
/** @param {number} index */
|
||||
function getCompactFactor(index) {
|
||||
return compactBase * compactStep ** index;
|
||||
}
|
||||
|
||||
/** @param {number} absolute */
|
||||
function getCompactIndex(absolute) {
|
||||
return Math.max(
|
||||
0,
|
||||
Math.min(
|
||||
suffixes.length - 1,
|
||||
Math.floor(Math.log10(absolute / compactBase) / 3),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/** @param {number} absolute */
|
||||
function getPlainDigits(absolute) {
|
||||
if (absolute < 10) return tinyDigits;
|
||||
if (absolute < 1_000) return smallDigits;
|
||||
if (absolute < 10_000) return mediumDigits;
|
||||
return integerDigits;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {number} value
|
||||
* @param {number} index
|
||||
* @param {number} length
|
||||
* @param {boolean} useGrouping
|
||||
*/
|
||||
function formatCompact(value, index, length, useGrouping) {
|
||||
for (let suffixIndex = index; suffixIndex < suffixes.length; suffixIndex += 1) {
|
||||
const suffix = suffixes[suffixIndex];
|
||||
const scaled = value / getCompactFactor(suffixIndex);
|
||||
|
||||
for (let digits = 3; digits >= 0; digits -= 1) {
|
||||
const formatted = formatNumber(scaled, digits, useGrouping);
|
||||
|
||||
if (
|
||||
Math.abs(parseFormattedNumber(formatted)) >= compactStep &&
|
||||
suffixIndex < suffixes.length - 1
|
||||
) break;
|
||||
|
||||
if (`${formatted}${suffix}`.length <= length) {
|
||||
return `${formatted}${suffix}`;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return "Inf.";
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {number} value
|
||||
* @param {number} length
|
||||
* @param {boolean} useGrouping
|
||||
*/
|
||||
function formatPlain(value, length, useGrouping) {
|
||||
const absolute = Math.abs(value);
|
||||
|
||||
for (const digit of getPlainDigits(absolute)) {
|
||||
const formatted = formatNumber(value, digit, useGrouping);
|
||||
|
||||
if (formatted.length <= length) return formatted;
|
||||
}
|
||||
|
||||
return formatCompact(value, 0, length, useGrouping);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {number} value
|
||||
* @param {number} length
|
||||
* @param {boolean} [useGrouping]
|
||||
*/
|
||||
function formatValue(value, length, useGrouping = true) {
|
||||
if (value === 0) return "0";
|
||||
|
||||
const absolute = Math.abs(value);
|
||||
|
||||
if (absolute < 10) return formatNumber(value, 3);
|
||||
if (absolute < 1_000) return formatNumber(value, 2);
|
||||
if (absolute < 10_000) return formatNumber(value, 1);
|
||||
if (absolute < 1_000_000) return formatNumber(value, 0);
|
||||
if (absolute >= 1e27) return "Inf.";
|
||||
if (absolute >= compactMax) return "Inf.";
|
||||
if (absolute < compactBase) return formatPlain(value, length, useGrouping);
|
||||
|
||||
const log = Math.floor(Math.log10(absolute) - 6);
|
||||
const suffixIndex = Math.floor(log / 3);
|
||||
const digits = 3 - (log % 3);
|
||||
const scaled = value / (1_000_000 * 1_000 ** suffixIndex);
|
||||
return formatCompact(value, getCompactIndex(absolute), length, useGrouping);
|
||||
}
|
||||
|
||||
return `${formatNumber(scaled, digits)}${suffixes[suffixIndex]}`;
|
||||
/** @param {number} value */
|
||||
export function formatNumberValue(value) {
|
||||
return formatValue(value, maxLength);
|
||||
}
|
||||
|
||||
/** @param {number} value */
|
||||
export function formatPercentValue(value) {
|
||||
return value === 0 ? "0%" : `${percentFormat.format(value)}%`;
|
||||
return `${formatValue(value, maxLength - 1, false)}%`;
|
||||
}
|
||||
|
||||
@@ -25,10 +25,12 @@ import {
|
||||
} from "./views.js";
|
||||
import { FALLBACK_VIEWBOX_HEIGHT, VIEWBOX_WIDTH } from "./viewbox.js";
|
||||
|
||||
/** @param {Chart} chart */
|
||||
export function createChart(chart) {
|
||||
/**
|
||||
* @param {Chart} chart
|
||||
* @param {string} chartKey
|
||||
*/
|
||||
export function createChart(chart, chartKey) {
|
||||
const figure = document.createElement("figure");
|
||||
const chartKey = chart.title;
|
||||
/** @type {ReturnType<typeof createChartRenderer> | undefined} */
|
||||
let renderer;
|
||||
|
||||
|
||||
@@ -19,11 +19,11 @@ main.learn {
|
||||
}
|
||||
|
||||
time {
|
||||
color: var(--off-color);
|
||||
color: var(--gray);
|
||||
}
|
||||
|
||||
span:is([data-chart="unit"], [data-chart="separator"]) {
|
||||
color: var(--off-color);
|
||||
color: var(--gray);
|
||||
}
|
||||
|
||||
menu {
|
||||
|
||||
@@ -23,7 +23,7 @@ main.learn {
|
||||
}
|
||||
|
||||
li + li {
|
||||
margin-top: 0.25rem;
|
||||
margin-block-start: 0.25rem;
|
||||
}
|
||||
|
||||
a {
|
||||
@@ -31,11 +31,10 @@ main.learn {
|
||||
scroll-margin-block: var(--offset);
|
||||
color: inherit;
|
||||
text-decoration: none;
|
||||
margin-right: 1rem;
|
||||
margin-block: -0.25rem;
|
||||
margin-left: -0.5rem;
|
||||
margin-inline: -0.5rem 1rem;
|
||||
padding: 0.25rem;
|
||||
padding-left: 0.5rem;
|
||||
padding-inline-start: 0.5rem;
|
||||
|
||||
&::before {
|
||||
opacity: 0.5;
|
||||
@@ -61,6 +60,15 @@ main.learn {
|
||||
}
|
||||
}
|
||||
|
||||
ol ol {
|
||||
margin-block-start: 0.25rem;
|
||||
margin-inline-start: 1rem;
|
||||
}
|
||||
|
||||
ol ol ol ol {
|
||||
margin-inline-start: 0.5rem;
|
||||
}
|
||||
|
||||
> ol {
|
||||
> li {
|
||||
counter-reset: content-topic;
|
||||
@@ -79,9 +87,6 @@ main.learn {
|
||||
}
|
||||
|
||||
> ol {
|
||||
margin-top: 0.25rem;
|
||||
margin-left: 1rem;
|
||||
|
||||
> li {
|
||||
counter-increment: content-topic;
|
||||
counter-reset: content-detail;
|
||||
@@ -91,9 +96,6 @@ main.learn {
|
||||
}
|
||||
|
||||
> ol {
|
||||
margin-top: 0.25rem;
|
||||
margin-left: 1rem;
|
||||
|
||||
> li {
|
||||
counter-increment: content-detail;
|
||||
counter-reset: content-subtopic;
|
||||
@@ -103,9 +105,6 @@ main.learn {
|
||||
}
|
||||
|
||||
> ol {
|
||||
margin-top: 0.25rem;
|
||||
margin-left: 0.5rem;
|
||||
|
||||
> li {
|
||||
counter-increment: content-subtopic;
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { createCohortSeries } from "./cohort-series.js";
|
||||
import { colors } from "../../utils/colors.js";
|
||||
|
||||
export const rollingWindows = /** @type {const} */ ([
|
||||
const rollingWindows = /** @type {const} */ ([
|
||||
["24h", "_24h", colors.sky],
|
||||
["1w", "_1w", colors.cyan],
|
||||
["1m", "_1m", colors.blue],
|
||||
|
||||
@@ -26,7 +26,7 @@ function createSection(section, path = []) {
|
||||
heading.append(anchor);
|
||||
description.append(section.description);
|
||||
element.append(heading, description);
|
||||
if (section.chart) element.append(createDataChart(section.chart));
|
||||
if (section.chart) element.append(createDataChart(section.chart, id));
|
||||
|
||||
for (const child of children) {
|
||||
element.append(createSection(child, sectionPath));
|
||||
|
||||
@@ -79,21 +79,58 @@ main.learn {
|
||||
margin-top: 8rem;
|
||||
}
|
||||
|
||||
> section > section {
|
||||
counter-increment: topic;
|
||||
counter-reset: detail;
|
||||
scroll-margin-top: var(--offset);
|
||||
section[id] {
|
||||
> :is(h1, h2, h3, h4) {
|
||||
a {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
color: var(--white);
|
||||
text-decoration: none;
|
||||
|
||||
&::before {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
right: 100%;
|
||||
translate: 0 -50%;
|
||||
opacity: 0;
|
||||
user-select: none;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
&:hover::before {
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
text-decoration: underline;
|
||||
text-decoration-thickness: 1px;
|
||||
text-underline-offset: 0.125em;
|
||||
}
|
||||
|
||||
&:active {
|
||||
color: var(--orange);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
> section > section > section {
|
||||
counter-increment: detail;
|
||||
counter-reset: subtopic;
|
||||
scroll-margin-top: var(--offset);
|
||||
}
|
||||
> section {
|
||||
> section {
|
||||
counter-increment: topic;
|
||||
counter-reset: detail;
|
||||
scroll-margin-top: var(--offset);
|
||||
|
||||
> section > section > section > section {
|
||||
counter-increment: subtopic;
|
||||
scroll-margin-top: var(--offset);
|
||||
> section {
|
||||
counter-increment: detail;
|
||||
counter-reset: subtopic;
|
||||
scroll-margin-top: var(--offset);
|
||||
|
||||
> section {
|
||||
counter-increment: subtopic;
|
||||
scroll-margin-top: var(--offset);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
section[id]:not([data-numbered="false"]) {
|
||||
@@ -153,7 +190,7 @@ main.learn {
|
||||
|
||||
> p {
|
||||
margin-top: 1rem;
|
||||
color: var(--dark-white);
|
||||
color: var(--white);
|
||||
font-size: var(--font-size-sm);
|
||||
line-height: var(--line-height-sm);
|
||||
}
|
||||
@@ -164,40 +201,5 @@ main.learn {
|
||||
font-size: var(--font-size-xs);
|
||||
}
|
||||
}
|
||||
|
||||
section[id] {
|
||||
> :is(h1, h2, h3, h4) {
|
||||
a {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
color: var(--white);
|
||||
text-decoration: none;
|
||||
|
||||
&::before {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
right: 100%;
|
||||
translate: 0 -50%;
|
||||
opacity: 0;
|
||||
user-select: none;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
&:hover::before {
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
text-decoration: underline;
|
||||
text-decoration-thickness: 1px;
|
||||
text-underline-offset: 0.125em;
|
||||
}
|
||||
|
||||
&:active {
|
||||
color: var(--orange);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@ body {
|
||||
/* 7. Inherit fonts for form controls */
|
||||
input,
|
||||
button,
|
||||
textarea,
|
||||
select {
|
||||
font: inherit;
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
color-scheme: dark;
|
||||
|
||||
--white: oklch(95% 0 0);
|
||||
--dark-white: oklch(92.5% 0 0);
|
||||
--gray: oklch(55% 0 0);
|
||||
--black: oklch(15% 0 0);
|
||||
--red: oklch(0.607 0.241 26.328);
|
||||
@@ -23,7 +22,6 @@
|
||||
--fuchsia: oklch(0.629 0.294 322.523);
|
||||
--pink: oklch(0.624 0.245 357.444);
|
||||
--rose: oklch(0.6155 0.2495 17.012);
|
||||
--off-color: var(--gray);
|
||||
|
||||
--font-size-xs: 0.75rem;
|
||||
--line-height-xs: calc(1 / 0.75);
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* @param {Event} event
|
||||
* @param {string} selector
|
||||
*/
|
||||
export function getEventTarget(event, selector) {
|
||||
function getEventTarget(event, selector) {
|
||||
const target = event.target;
|
||||
|
||||
return target instanceof Element ? target.closest(selector) : null;
|
||||
|
||||
Reference in New Issue
Block a user