diff --git a/CHANGELOG.md b/CHANGELOG.md
index 63b4be485..62fcf8c1b 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -25,12 +25,13 @@
- Added `Hash Price Min`
- Added `Hash Price Rebound`
- Removed all year datasets (25) in favor for epoch datasets (5), the former was too granular to be really useful
-- Removed datasets split by liquidity for all datasets already split by any address kind, while fun to have, they took time to compute, ram, and space to store and no one was actually checking them
+- Removed datasets split by liquidity for all datasets **already split by any address kind**, while fun to have, they took time to compute, ram, and space to store and no one was actually checking them
- Fixed a lot of values in split by liquidity datasets
## Website
-- ~Added a dashboard~ Added the latest values to the tree next to each option (in "Folders") instead, while less values are visible at a time, it's much more readable and organised
+- Updated the design yet again which made the website even easier on the eyes
+- ~Added a dashboard~ Added the latest values to the tree next to each option instead, while less values are visible at a time, it's much more readable and organised
- Added a library of PDFs
- Fixed service worker not passing 304 (not modified) response and instead serving cached responses
- Fixed history not being properly registered
@@ -50,7 +51,7 @@
- Added `--recompute_computed true` argument, to allow recomputation of computed datasets in case of a bug
- Fixed not saved arguments, not being processed properly
- Fixed bug in `generic_map.multi_insert_simple_average`
-- Added defragmentation of databases to save space
+- Added defragmentation option `--first-defragment true` of databases to save space (which can save up to 50%)
## Server
diff --git a/README.md b/README.md
index d1d63ac23..46330146b 100644
--- a/README.md
+++ b/README.md
@@ -14,9 +14,9 @@
## Description
-*TLDR*: **A better, FOSS, Bitcoin-only, self-hostable Glassnode**
+_TLDR_: **A better, FOSS, Bitcoin-only, self-hostable Glassnode**
-**kibō** (*hope* in japanese) is a suite of tools that aims to help you understand Bitcoin's various dynamics. To do that, there is a wide number of charts and datasets with a scale by date but also by height free for you to explore. Which allows you to verify an incredible number of things, from the number of UTXOs to the repartition of the supply between different groups over time, with many things in between and it's all made possible thanks to Bitcoin's transparency. Whether you're an enthusiast, a researcher, a miner, an analyst, a trader, a skeptic or just curious, there is something new to learn for everyone !
+**kibō** (_hope_ in japanese) is a suite of tools that aims to help you understand Bitcoin's various dynamics. To do that, there is a wide number of charts and datasets with a scale by date but also by height free for you to explore. Which allows you to verify an incredible number of things, from the number of UTXOs to the repartition of the supply between different groups over time, with many things in between and it's all made possible thanks to Bitcoin's transparency. Whether you're an enthusiast, a researcher, a miner, an analyst, a trader, a skeptic or just curious, there is something new to learn for everyone !
While it's not the first tool trying to solve this problem, it's the first that is completely free, open-source and self-hostable. Which is very important as, just like for Bitcoin itself, I strongly believe that everyone should have access to this kind of data.
@@ -36,7 +36,7 @@ So if you find this project useful, [please send some sats](https://geyser.fund/
If you're a potential sponsor, feel free to contact me in Nostr !
-Bitcoin address: bc1q950q4ukpxxm6wjjkv6cpq8jzpazaxrrwftctkt
+Bitcoin address: [bc1q950q4ukpxxm6wjjkv6cpq8jzpazaxrrwftctkt](bitcoin:bc1q950q4ukpxxm6wjjkv6cpq8jzpazaxrrwftctkt)
Lightning address: lnurl1dp68gurn8ghj7ampd3kx2ar0veekzar0wd5xjtnrdakj7tnhv4kxctttdehhwm30d3h82unvwqhkxmmww3jkuar8d35kgetj8yuq363hv4
@@ -48,11 +48,11 @@ This project is still in an early stage. Until more people look at the code and
## Instances
-| URL | Type | Version | Status | Last Height | Up Time Ratio |
-| --- | --- | --- | --- | --- | --- |
-| [kibo.money](https://kibo.money) | Main |  |  |  |  |
-| [backup.kibo.money](https://backup.kibo.money) | Backup |  |  |  |  |
-| [preview.kibo.money](https://preview.kibo.money) | Dev |  |  |  |  |
+| URL | Type | Version | Status | Last Height | Up Time Ratio |
+| ------------------------------------------------ | ------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------ |
+| [kibo.money](https://kibo.money) | Main |  |  |  |  |
+| [backup.kibo.money](https://backup.kibo.money) | Backup |  |  |  |  |
+| [preview.kibo.money](https://preview.kibo.money) | Dev |  |  |  |  |
Please open an issue if you want to add another instance
@@ -107,7 +107,7 @@ Working on it
### Manual
-*Mac OS and Linux only, Windows is unsupported*
+_Mac OS and Linux only, Windows is unsupported_
First we need to install Rust (https://www.rust-lang.org/tools/install)
@@ -122,6 +122,7 @@ rustup update
```
> If you're on Ubuntu you'll probably also need to install `open-ssl` with
+>
> ```bash
> sudo apt install libssl-dev pkg-config
> ```
@@ -153,11 +154,13 @@ cd ???/kibo/parser
Now we can finally start by running the parser, you need to use the `./run.sh` script instead of `cargo run -r` as we need to set various system variables for the program to run smoothly
For the first launch, the parser will need several information such as:
+
- `--datadir`: which is bitcoin data directory path, prefer `$HOME` to `~` as the latter might not work
- `--rpcuser`: the username of the RPC credentials to talk to the bitcoin server
- `--rpcpassword`: the password of the RPC credentials
Optionally you can also specify:
+
- `--rpcconnect`: if the bitcoin core server's IP is different than `localhost`
- `--rpcport`: if the port is different than `8332`
@@ -196,21 +199,3 @@ Formerly Satonomics
The dove (borrowed from [svgrepo](https://www.svgrepo.com/svg/351969/dove) for now) is known to represent hope in many cultures.
The orange background is a wink to Bitcoin and when in a circle, it also represents the sun, which means that while it's our hope for a better future, we still have to be careful with our collective goals and actions, to not end up like Icarus.
-
-## Infrastructure
-
-Here's the current infrastructure of the main instance and its backup.
-
-It uses 2 servers, a full and a light one without the parser running but with still datasets syncronized via Syncthing.
-
-Cloudflare is used for their tunnel + CDN services.
-
-Though it's recommended to change to default **Browser Cache TTL** configuration from `4 Hours` to `Respect Existing Headers` (in `Websites / YOUR_DOMAIN / Caching / Configuration / Browser Cache TTL`) and activate `Always use https`.
-
-
-
-
-
-
-
-
diff --git a/assets/infrastructure-dark.svg b/assets/infrastructure-dark.svg
deleted file mode 100644
index a1dec79be..000000000
--- a/assets/infrastructure-dark.svg
+++ /dev/null
@@ -1,13 +0,0 @@
-
-
-
-
-
-
-
- Main instance (MBP M3 Pro) Backup instance (Mac Mini M1) Synchronization (Syncthing) CDN, DNS, Proxy (Cloudflare) Services: - Server Services: - Parser - Server backup.kibo.money kibo.money Tunnel (cloudflared) Tunnel (cloudflared) Internet
\ No newline at end of file
diff --git a/assets/infrastructure-light.svg b/assets/infrastructure-light.svg
deleted file mode 100644
index fd2563925..000000000
--- a/assets/infrastructure-light.svg
+++ /dev/null
@@ -1,13 +0,0 @@
-
-
-
-
-
-
-
- Main instance (MBP M3 Pro) Backup instance (Mac Mini M1) Synchronization (Syncthing) CDN, DNS, Proxy (Cloudflare) Services: - Server Services: - Parser - Server backup.kibo.money kibo.money Tunnel (cloudflared) Tunnel (cloudflared) Internet
\ No newline at end of file
diff --git a/assets/infrastructure.excalidraw b/assets/infrastructure.excalidraw
deleted file mode 100644
index 6b8cdfe04..000000000
--- a/assets/infrastructure.excalidraw
+++ /dev/null
@@ -1,1061 +0,0 @@
-{
- "type": "excalidraw",
- "version": 2,
- "source": "https://excalidraw.com",
- "elements": [
- {
- "type": "rectangle",
- "version": 351,
- "versionNonce": 642218538,
- "index": "a1",
- "isDeleted": false,
- "id": "4l5Cnq81N-N8HWbMPgOfm",
- "fillStyle": "solid",
- "strokeWidth": 2,
- "strokeStyle": "solid",
- "roughness": 1,
- "opacity": 100,
- "angle": 0,
- "x": 365.86486603966756,
- "y": 534.9494905328866,
- "strokeColor": "#1e1e1e",
- "backgroundColor": "transparent",
- "width": 184.9297887916521,
- "height": 85.19094049738938,
- "seed": 350356010,
- "groupIds": [],
- "frameId": null,
- "roundness": {
- "type": 3
- },
- "boundElements": [
- {
- "type": "text",
- "id": "LfdDNULnkLxM4LrR-Ey2y"
- },
- {
- "id": "CbJ4u9h-uaIrTzsEExVo7",
- "type": "arrow"
- },
- {
- "id": "-1w44Xvh1ZmtarGuufckU",
- "type": "arrow"
- }
- ],
- "updated": 1726489097527,
- "link": null,
- "locked": false
- },
- {
- "type": "text",
- "version": 360,
- "versionNonce": 1888531050,
- "index": "a1V",
- "isDeleted": false,
- "id": "LfdDNULnkLxM4LrR-Ey2y",
- "fillStyle": "solid",
- "strokeWidth": 2,
- "strokeStyle": "solid",
- "roughness": 1,
- "opacity": 100,
- "angle": 0,
- "x": 388.80980193939985,
- "y": 552.5449607815813,
- "strokeColor": "#1e1e1e",
- "backgroundColor": "transparent",
- "width": 139.0399169921875,
- "height": 50,
- "seed": 218559926,
- "groupIds": [],
- "frameId": null,
- "roundness": null,
- "boundElements": [],
- "updated": 1726495547033,
- "link": null,
- "locked": false,
- "fontSize": 20,
- "fontFamily": 5,
- "text": "Main instance\n(MBP M3 Pro)",
- "textAlign": "center",
- "verticalAlign": "middle",
- "containerId": "4l5Cnq81N-N8HWbMPgOfm",
- "originalText": "Main instance\n(MBP M3 Pro)",
- "autoResize": true,
- "lineHeight": 1.25
- },
- {
- "type": "rectangle",
- "version": 723,
- "versionNonce": 1818928362,
- "index": "a3",
- "isDeleted": false,
- "id": "9565AiaaW5P2onZJsxM5X",
- "fillStyle": "solid",
- "strokeWidth": 2,
- "strokeStyle": "solid",
- "roughness": 1,
- "opacity": 100,
- "angle": 0,
- "x": 929.3589198932772,
- "y": 533.3447074509686,
- "strokeColor": "#1e1e1e",
- "backgroundColor": "transparent",
- "width": 187.13198652163655,
- "height": 88.40050666122548,
- "seed": 161587242,
- "groupIds": [],
- "frameId": null,
- "roundness": {
- "type": 3
- },
- "boundElements": [
- {
- "type": "text",
- "id": "xEhd36k7qSdZORzI5BYDC"
- },
- {
- "id": "CbJ4u9h-uaIrTzsEExVo7",
- "type": "arrow"
- },
- {
- "id": "gaJmg3DF-UOKWKTiDcUQS",
- "type": "arrow"
- }
- ],
- "updated": 1726489097527,
- "link": null,
- "locked": false
- },
- {
- "type": "text",
- "version": 745,
- "versionNonce": 1908295850,
- "index": "a4",
- "isDeleted": false,
- "id": "xEhd36k7qSdZORzI5BYDC",
- "fillStyle": "solid",
- "strokeWidth": 2,
- "strokeStyle": "solid",
- "roughness": 1,
- "opacity": 100,
- "angle": 0,
- "x": 944.2449891428649,
- "y": 552.5449607815814,
- "strokeColor": "#1e1e1e",
- "backgroundColor": "transparent",
- "width": 157.35984802246094,
- "height": 50,
- "seed": 1838156522,
- "groupIds": [],
- "frameId": null,
- "roundness": null,
- "boundElements": [],
- "updated": 1726495550428,
- "link": null,
- "locked": false,
- "fontSize": 20,
- "fontFamily": 5,
- "text": "Backup instance\n(Mac Mini M1)",
- "textAlign": "center",
- "verticalAlign": "middle",
- "containerId": "9565AiaaW5P2onZJsxM5X",
- "originalText": "Backup instance\n(Mac Mini M1)",
- "autoResize": true,
- "lineHeight": 1.25
- },
- {
- "type": "arrow",
- "version": 554,
- "versionNonce": 1113225130,
- "index": "a7",
- "isDeleted": false,
- "id": "CbJ4u9h-uaIrTzsEExVo7",
- "fillStyle": "solid",
- "strokeWidth": 2,
- "strokeStyle": "solid",
- "roughness": 1,
- "opacity": 100,
- "angle": 0,
- "x": 551.7946548313197,
- "y": 577.8108949212098,
- "strokeColor": "#1e1e1e",
- "backgroundColor": "transparent",
- "width": 374.2744229755049,
- "height": 0.5318682792568552,
- "seed": 1412467498,
- "groupIds": [],
- "frameId": null,
- "roundness": {
- "type": 2
- },
- "boundElements": [
- {
- "type": "text",
- "id": "-xyotiDxrIvGpHihaNTMw"
- }
- ],
- "updated": 1726489097527,
- "link": null,
- "locked": false,
- "startBinding": {
- "elementId": "4l5Cnq81N-N8HWbMPgOfm",
- "focus": 0.053987925025335816,
- "gap": 1,
- "fixedPoint": null
- },
- "endBinding": {
- "elementId": "9565AiaaW5P2onZJsxM5X",
- "focus": -0.06637645925445641,
- "gap": 1.9594774360632248,
- "fixedPoint": null
- },
- "lastCommittedPoint": null,
- "startArrowhead": null,
- "endArrowhead": "arrow",
- "points": [
- [
- 0,
- 0
- ],
- [
- 374.2744229755049,
- -0.5318682792568552
- ]
- ],
- "elbowed": false
- },
- {
- "type": "text",
- "version": 24,
- "versionNonce": 1622013622,
- "index": "a7V",
- "isDeleted": false,
- "id": "-xyotiDxrIvGpHihaNTMw",
- "fillStyle": "solid",
- "strokeWidth": 2,
- "strokeStyle": "solid",
- "roughness": 1,
- "opacity": 100,
- "angle": 0,
- "x": 663.5995146712901,
- "y": 553.6137138980424,
- "strokeColor": "#1e1e1e",
- "backgroundColor": "transparent",
- "width": 152.0398712158203,
- "height": 50,
- "seed": 1240678698,
- "groupIds": [],
- "frameId": null,
- "roundness": null,
- "boundElements": [],
- "updated": 1726489097527,
- "link": null,
- "locked": false,
- "fontSize": 20,
- "fontFamily": 5,
- "text": "Synchronization\n(Syncthing)",
- "textAlign": "center",
- "verticalAlign": "middle",
- "containerId": "CbJ4u9h-uaIrTzsEExVo7",
- "originalText": "Synchronization\n(Syncthing)",
- "autoResize": true,
- "lineHeight": 1.25
- },
- {
- "type": "ellipse",
- "version": 889,
- "versionNonce": 1695926463,
- "index": "a9",
- "isDeleted": false,
- "id": "4Kf-4nPmAC4H6JYuOWgKz",
- "fillStyle": "solid",
- "strokeWidth": 2,
- "strokeStyle": "solid",
- "roughness": 1,
- "opacity": 100,
- "angle": 0,
- "x": 674.688026887862,
- "y": -113.87511038919328,
- "strokeColor": "#1e1e1e",
- "backgroundColor": "transparent",
- "width": 114.13321104184153,
- "height": 83.7807552220783,
- "seed": 1864324918,
- "groupIds": [],
- "frameId": null,
- "roundness": {
- "type": 2
- },
- "boundElements": [],
- "updated": 1726523088164,
- "link": null,
- "locked": false
- },
- {
- "type": "ellipse",
- "version": 956,
- "versionNonce": 1989633713,
- "index": "aA",
- "isDeleted": false,
- "id": "R4QUoIsp_Y1_gsH3uowyA",
- "fillStyle": "solid",
- "strokeWidth": 2,
- "strokeStyle": "solid",
- "roughness": 1,
- "opacity": 100,
- "angle": 0,
- "x": 751.5605318882301,
- "y": -89.26982658383659,
- "strokeColor": "#1e1e1e",
- "backgroundColor": "transparent",
- "width": 114.13321104184153,
- "height": 83.7807552220783,
- "seed": 1029607658,
- "groupIds": [],
- "frameId": null,
- "roundness": {
- "type": 2
- },
- "boundElements": [
- {
- "id": "5dcU1IErPCDiUG3gflg8R",
- "type": "arrow"
- }
- ],
- "updated": 1726523088164,
- "link": null,
- "locked": false
- },
- {
- "type": "ellipse",
- "version": 1145,
- "versionNonce": 1845254367,
- "index": "aB",
- "isDeleted": false,
- "id": "sCBhvSDPsRkhW05eEeRy5",
- "fillStyle": "solid",
- "strokeWidth": 2,
- "strokeStyle": "solid",
- "roughness": 1,
- "opacity": 100,
- "angle": 0,
- "x": 609.0037967435512,
- "y": -83.9664057764262,
- "strokeColor": "#1e1e1e",
- "backgroundColor": "transparent",
- "width": 164.9744518534024,
- "height": 86.58639076795106,
- "seed": 1345460918,
- "groupIds": [],
- "frameId": null,
- "roundness": {
- "type": 2
- },
- "boundElements": [
- {
- "id": "Xp-UFM8oBcOEj_8Scy4Ma",
- "type": "arrow"
- },
- {
- "id": "5dcU1IErPCDiUG3gflg8R",
- "type": "arrow"
- }
- ],
- "updated": 1726523088164,
- "link": null,
- "locked": false
- },
- {
- "type": "ellipse",
- "version": 1148,
- "versionNonce": 1094281361,
- "index": "aC",
- "isDeleted": false,
- "id": "XkaKAKq7arG2a4-xuVxc_",
- "fillStyle": "solid",
- "strokeWidth": 2,
- "strokeStyle": "solid",
- "roughness": 1,
- "opacity": 100,
- "angle": 0,
- "x": 755.5420699957402,
- "y": -105.29203456400774,
- "strokeColor": "#1e1e1e",
- "backgroundColor": "transparent",
- "width": 53.21063017191969,
- "height": 42.38188857636974,
- "seed": 1023165930,
- "groupIds": [],
- "frameId": null,
- "roundness": {
- "type": 2
- },
- "boundElements": [],
- "updated": 1726523088164,
- "link": null,
- "locked": false
- },
- {
- "type": "rectangle",
- "version": 1536,
- "versionNonce": 634564330,
- "index": "aE",
- "isDeleted": false,
- "id": "KDdwlG7bsCvMQxoGRy8Xc",
- "fillStyle": "solid",
- "strokeWidth": 2,
- "strokeStyle": "solid",
- "roughness": 1,
- "opacity": 100,
- "angle": 0,
- "x": 293.13116655589124,
- "y": 202.16187544969688,
- "strokeColor": "#1e1e1e",
- "backgroundColor": "transparent",
- "width": 893.9941536837997,
- "height": 144.9329694976395,
- "seed": 1917949750,
- "groupIds": [],
- "frameId": null,
- "roundness": {
- "type": 3
- },
- "boundElements": [
- {
- "type": "text",
- "id": "rqWH83jhOa4ihfEdsTYEt"
- },
- {
- "id": "gaJmg3DF-UOKWKTiDcUQS",
- "type": "arrow"
- },
- {
- "id": "-1w44Xvh1ZmtarGuufckU",
- "type": "arrow"
- }
- ],
- "updated": 1726495617856,
- "link": null,
- "locked": false
- },
- {
- "type": "text",
- "version": 1506,
- "versionNonce": 555245354,
- "index": "aF",
- "isDeleted": false,
- "id": "rqWH83jhOa4ihfEdsTYEt",
- "fillStyle": "solid",
- "strokeWidth": 2,
- "strokeStyle": "solid",
- "roughness": 1,
- "opacity": 100,
- "angle": 0,
- "x": 657.8582729956695,
- "y": 249.62836019851665,
- "strokeColor": "#1e1e1e",
- "backgroundColor": "transparent",
- "width": 164.5399408042431,
- "height": 50,
- "seed": 1304772726,
- "groupIds": [],
- "frameId": null,
- "roundness": null,
- "boundElements": [],
- "updated": 1726495617857,
- "link": null,
- "locked": false,
- "fontSize": 20,
- "fontFamily": 5,
- "text": "CDN, DNS, Proxy\n(Cloudflare)",
- "textAlign": "center",
- "verticalAlign": "middle",
- "containerId": "KDdwlG7bsCvMQxoGRy8Xc",
- "originalText": "CDN, DNS, Proxy\n(Cloudflare)",
- "autoResize": true,
- "lineHeight": 1.25
- },
- {
- "type": "arrow",
- "version": 960,
- "versionNonce": 1215820095,
- "index": "aN",
- "isDeleted": false,
- "id": "Xp-UFM8oBcOEj_8Scy4Ma",
- "fillStyle": "solid",
- "strokeWidth": 2,
- "strokeStyle": "solid",
- "roughness": 1,
- "opacity": 100,
- "angle": 0,
- "x": 459.16617750823536,
- "y": 246.47593943435749,
- "strokeColor": "#1e1e1e",
- "backgroundColor": "transparent",
- "width": 199.39664159505958,
- "height": 244.9843279773636,
- "seed": 1968881974,
- "groupIds": [],
- "frameId": null,
- "roundness": {
- "type": 2
- },
- "boundElements": [],
- "updated": 1726523088164,
- "link": null,
- "locked": false,
- "startBinding": {
- "elementId": "q5zgtaduyEFWvWtLqdo4u",
- "focus": -0.29520668458161897,
- "gap": 7.468651206465225,
- "fixedPoint": null
- },
- "endBinding": {
- "elementId": "sCBhvSDPsRkhW05eEeRy5",
- "focus": -0.015501021013443951,
- "gap": 2.4489688039538677,
- "fixedPoint": null
- },
- "lastCommittedPoint": null,
- "startArrowhead": "arrow",
- "endArrowhead": "arrow",
- "points": [
- [
- 0,
- 0
- ],
- [
- 199.39664159505958,
- -244.9843279773636
- ]
- ],
- "elbowed": false
- },
- {
- "type": "arrow",
- "version": 994,
- "versionNonce": 1236482129,
- "index": "aO",
- "isDeleted": false,
- "id": "5dcU1IErPCDiUG3gflg8R",
- "fillStyle": "solid",
- "strokeWidth": 2,
- "strokeStyle": "solid",
- "roughness": 1,
- "opacity": 100,
- "angle": 0,
- "x": 830.1001802364694,
- "y": -0.5385166255382927,
- "strokeColor": "#1e1e1e",
- "backgroundColor": "transparent",
- "width": 188.17952290562857,
- "height": 239.22427486491006,
- "seed": 2106058986,
- "groupIds": [],
- "frameId": null,
- "roundness": {
- "type": 2
- },
- "boundElements": [],
- "updated": 1726523088164,
- "link": null,
- "locked": false,
- "startBinding": {
- "elementId": "R4QUoIsp_Y1_gsH3uowyA",
- "focus": 0.23329021524550242,
- "gap": 7.753664430702663,
- "fixedPoint": null
- },
- "endBinding": {
- "elementId": "pglywLWx0DKRfK57PIrUI",
- "focus": 0.17814510531398206,
- "gap": 9.491520721779693,
- "fixedPoint": null
- },
- "lastCommittedPoint": null,
- "startArrowhead": "arrow",
- "endArrowhead": "arrow",
- "points": [
- [
- 0,
- 0
- ],
- [
- 188.17952290562857,
- 239.22427486491006
- ]
- ],
- "elbowed": false
- },
- {
- "type": "text",
- "version": 201,
- "versionNonce": 1806017514,
- "index": "aP",
- "isDeleted": false,
- "id": "lS9tbqIzGDn_EHnkA1-z9",
- "fillStyle": "solid",
- "strokeWidth": 2,
- "strokeStyle": "solid",
- "roughness": 1,
- "opacity": 100,
- "angle": 0,
- "x": 980.6673500907636,
- "y": 625.9948603740997,
- "strokeColor": "#1e1e1e",
- "backgroundColor": "transparent",
- "width": 83.75991821289062,
- "height": 50,
- "seed": 1098959798,
- "groupIds": [],
- "frameId": null,
- "roundness": null,
- "boundElements": [],
- "updated": 1726489102346,
- "link": null,
- "locked": false,
- "fontSize": 20,
- "fontFamily": 5,
- "text": "Services:\n- Server",
- "textAlign": "left",
- "verticalAlign": "top",
- "containerId": null,
- "originalText": "Services:\n- Server",
- "autoResize": true,
- "lineHeight": 1.25
- },
- {
- "type": "text",
- "version": 339,
- "versionNonce": 874481386,
- "index": "aR",
- "isDeleted": false,
- "id": "w8Pc4lZIzMJfQlLbzQX9w",
- "fillStyle": "solid",
- "strokeWidth": 2,
- "strokeStyle": "solid",
- "roughness": 1,
- "opacity": 100,
- "angle": 0,
- "x": 416.4498013290483,
- "y": 625.9510491610656,
- "strokeColor": "#1e1e1e",
- "backgroundColor": "transparent",
- "width": 83.75991821289062,
- "height": 75,
- "seed": 1853359990,
- "groupIds": [],
- "frameId": null,
- "roundness": null,
- "boundElements": [],
- "updated": 1726489101018,
- "link": null,
- "locked": false,
- "fontSize": 20,
- "fontFamily": 5,
- "text": "Services:\n- Parser\n- Server",
- "textAlign": "left",
- "verticalAlign": "top",
- "containerId": null,
- "originalText": "Services:\n- Parser\n- Server",
- "autoResize": true,
- "lineHeight": 1.25
- },
- {
- "type": "ellipse",
- "version": 793,
- "versionNonce": 569869290,
- "index": "aS",
- "isDeleted": false,
- "id": "pglywLWx0DKRfK57PIrUI",
- "fillStyle": "solid",
- "strokeWidth": 2,
- "strokeStyle": "solid",
- "roughness": 1,
- "opacity": 100,
- "angle": 0,
- "x": 880.0025282056731,
- "y": 249.22675692415476,
- "strokeColor": "#1e1e1e",
- "backgroundColor": "transparent",
- "width": 285.84476989684487,
- "height": 58.423940951345934,
- "seed": 1773150518,
- "groupIds": [],
- "frameId": null,
- "roundness": {
- "type": 2
- },
- "boundElements": [
- {
- "type": "text",
- "id": "-iVMi_RkcWUQIt6Z2Mlrh"
- },
- {
- "id": "gaJmg3DF-UOKWKTiDcUQS",
- "type": "arrow"
- },
- {
- "id": "5dcU1IErPCDiUG3gflg8R",
- "type": "arrow"
- }
- ],
- "updated": 1726489062551,
- "link": null,
- "locked": false
- },
- {
- "type": "text",
- "version": 752,
- "versionNonce": 748078710,
- "index": "aSV",
- "isDeleted": false,
- "id": "-iVMi_RkcWUQIt6Z2Mlrh",
- "fillStyle": "solid",
- "strokeWidth": 2,
- "strokeStyle": "solid",
- "roughness": 1,
- "opacity": 100,
- "angle": 0,
- "x": 936.4035939616971,
- "y": 265.78274498465817,
- "strokeColor": "#1e1e1e",
- "backgroundColor": "transparent",
- "width": 172.91986322402954,
- "height": 25,
- "seed": 1414430634,
- "groupIds": [],
- "frameId": null,
- "roundness": null,
- "boundElements": [],
- "updated": 1726489062551,
- "link": null,
- "locked": false,
- "fontSize": 20,
- "fontFamily": 5,
- "text": "backup.kibo.money",
- "textAlign": "center",
- "verticalAlign": "middle",
- "containerId": "pglywLWx0DKRfK57PIrUI",
- "originalText": "backup.kibo.money",
- "autoResize": true,
- "lineHeight": 1.25
- },
- {
- "type": "ellipse",
- "version": 621,
- "versionNonce": 284391082,
- "index": "aU",
- "isDeleted": false,
- "id": "q5zgtaduyEFWvWtLqdo4u",
- "fillStyle": "solid",
- "strokeWidth": 2,
- "strokeStyle": "solid",
- "roughness": 1,
- "opacity": 100,
- "angle": 0,
- "x": 361.7468186507642,
- "y": 248.99504540515608,
- "strokeColor": "#1e1e1e",
- "backgroundColor": "transparent",
- "width": 193.16588356945877,
- "height": 58.88736398934328,
- "seed": 1828238890,
- "groupIds": [],
- "frameId": null,
- "roundness": {
- "type": 2
- },
- "boundElements": [
- {
- "type": "text",
- "id": "L2XYk3PmFoutUXTAiwF_e"
- },
- {
- "id": "-1w44Xvh1ZmtarGuufckU",
- "type": "arrow"
- },
- {
- "id": "Xp-UFM8oBcOEj_8Scy4Ma",
- "type": "arrow"
- }
- ],
- "updated": 1726489062551,
- "link": null,
- "locked": false
- },
- {
- "type": "text",
- "version": 450,
- "versionNonce": 1042450358,
- "index": "aUV",
- "isDeleted": false,
- "id": "L2XYk3PmFoutUXTAiwF_e",
- "fillStyle": "solid",
- "strokeWidth": 2,
- "strokeStyle": "solid",
- "roughness": 1,
- "opacity": 100,
- "angle": 0,
- "x": 407.4253380048505,
- "y": 266.11890019829514,
- "strokeColor": "#1e1e1e",
- "backgroundColor": "transparent",
- "width": 102.21993869543076,
- "height": 25,
- "seed": 1196969142,
- "groupIds": [],
- "frameId": null,
- "roundness": null,
- "boundElements": [],
- "updated": 1726489062551,
- "link": null,
- "locked": false,
- "fontSize": 20,
- "fontFamily": 5,
- "text": "kibo.money",
- "textAlign": "center",
- "verticalAlign": "middle",
- "containerId": "q5zgtaduyEFWvWtLqdo4u",
- "originalText": "kibo.money",
- "autoResize": true,
- "lineHeight": 1.25
- },
- {
- "type": "arrow",
- "version": 446,
- "versionNonce": 716143722,
- "index": "aW",
- "isDeleted": false,
- "id": "-1w44Xvh1ZmtarGuufckU",
- "fillStyle": "solid",
- "strokeWidth": 2,
- "strokeStyle": "solid",
- "roughness": 1,
- "opacity": 100,
- "angle": 0,
- "x": 458.32304516667847,
- "y": 354.8010802865273,
- "strokeColor": "#1e1e1e",
- "backgroundColor": "transparent",
- "width": 0.17852313722704594,
- "height": 175.64875971698473,
- "seed": 1204452650,
- "groupIds": [],
- "frameId": null,
- "roundness": null,
- "boundElements": [
- {
- "type": "text",
- "id": "6sYDgHoTWAbEIl_FWrDuW"
- }
- ],
- "updated": 1726495617857,
- "link": null,
- "locked": false,
- "startBinding": {
- "elementId": "KDdwlG7bsCvMQxoGRy8Xc",
- "focus": 0.6301546827835128,
- "gap": 7.706235339190897,
- "fixedPoint": null
- },
- "endBinding": {
- "elementId": "4l5Cnq81N-N8HWbMPgOfm",
- "focus": 0.000038110225611944457,
- "gap": 2.8605229475869627,
- "fixedPoint": null
- },
- "lastCommittedPoint": null,
- "startArrowhead": "arrow",
- "endArrowhead": "arrow",
- "points": [
- [
- 0,
- 0
- ],
- [
- -0.17852313722704594,
- 175.64875971698473
- ]
- ],
- "elbowed": false
- },
- {
- "type": "text",
- "version": 5,
- "versionNonce": 412947894,
- "index": "aX",
- "isDeleted": false,
- "id": "6sYDgHoTWAbEIl_FWrDuW",
- "fillStyle": "solid",
- "strokeWidth": 2,
- "strokeStyle": "solid",
- "roughness": 1,
- "opacity": 100,
- "angle": 0,
- "x": 399.3979196785064,
- "y": 417.0359387414294,
- "strokeColor": "#1e1e1e",
- "backgroundColor": "transparent",
- "width": 123.13990783691406,
- "height": 50,
- "seed": 655331882,
- "groupIds": [],
- "frameId": null,
- "roundness": null,
- "boundElements": [],
- "updated": 1726489073730,
- "link": null,
- "locked": false,
- "fontSize": 20,
- "fontFamily": 5,
- "text": "Tunnel\n(cloudflared)",
- "textAlign": "center",
- "verticalAlign": "middle",
- "containerId": "-1w44Xvh1ZmtarGuufckU",
- "originalText": "Tunnel\n(cloudflared)",
- "autoResize": true,
- "lineHeight": 1.25
- },
- {
- "type": "arrow",
- "version": 594,
- "versionNonce": 1714504106,
- "index": "aY",
- "isDeleted": false,
- "id": "gaJmg3DF-UOKWKTiDcUQS",
- "fillStyle": "solid",
- "strokeWidth": 2,
- "strokeStyle": "solid",
- "roughness": 1,
- "opacity": 100,
- "angle": 0,
- "x": 1023.4143216413406,
- "y": 356.5618164758373,
- "strokeColor": "#1e1e1e",
- "backgroundColor": "transparent",
- "width": 0.6658822477554622,
- "height": 160.10179451385454,
- "seed": 818854890,
- "groupIds": [],
- "frameId": null,
- "roundness": null,
- "boundElements": [
- {
- "type": "text",
- "id": "uTkD7W1DyHBhxilhBEtJv"
- }
- ],
- "updated": 1726495617857,
- "link": null,
- "locked": false,
- "startBinding": {
- "elementId": "KDdwlG7bsCvMQxoGRy8Xc",
- "focus": -0.6340885693917432,
- "gap": 9.46697152850092,
- "fixedPoint": null
- },
- "endBinding": {
- "elementId": "9565AiaaW5P2onZJsxM5X",
- "focus": 0.03896054889278365,
- "gap": 16.71544096114612,
- "fixedPoint": null
- },
- "lastCommittedPoint": null,
- "startArrowhead": "arrow",
- "endArrowhead": "arrow",
- "points": [
- [
- 0,
- 0
- ],
- [
- -0.6658822477554622,
- 160.10179451385454
- ]
- ],
- "elbowed": false
- },
- {
- "type": "text",
- "version": 5,
- "versionNonce": 1065203830,
- "index": "aZ",
- "isDeleted": false,
- "id": "uTkD7W1DyHBhxilhBEtJv",
- "fillStyle": "solid",
- "strokeWidth": 2,
- "strokeStyle": "solid",
- "roughness": 1,
- "opacity": 100,
- "angle": 0,
- "x": 949.6087413031642,
- "y": 419.85938650996854,
- "strokeColor": "#1e1e1e",
- "backgroundColor": "transparent",
- "width": 123.13990783691406,
- "height": 50,
- "seed": 477996650,
- "groupIds": [],
- "frameId": null,
- "roundness": null,
- "boundElements": [],
- "updated": 1726489079014,
- "link": null,
- "locked": false,
- "fontSize": 20,
- "fontFamily": 5,
- "text": "Tunnel\n(cloudflared)",
- "textAlign": "center",
- "verticalAlign": "middle",
- "containerId": "gaJmg3DF-UOKWKTiDcUQS",
- "originalText": "Tunnel\n(cloudflared)",
- "autoResize": true,
- "lineHeight": 1.25
- },
- {
- "type": "text",
- "version": 166,
- "versionNonce": 1379200287,
- "index": "aa",
- "isDeleted": false,
- "id": "l00BoaAvHhgy_wRaOndRf",
- "fillStyle": "solid",
- "strokeWidth": 2,
- "strokeStyle": "solid",
- "roughness": 1,
- "opacity": 100,
- "angle": 0,
- "x": 698.1576166043603,
- "y": 12.645887676558857,
- "strokeColor": "#1e1e1e",
- "backgroundColor": "transparent",
- "width": 83.77993774414062,
- "height": 25,
- "seed": 1234467574,
- "groupIds": [],
- "frameId": null,
- "roundness": null,
- "boundElements": [],
- "updated": 1726523088164,
- "link": null,
- "locked": false,
- "fontSize": 20,
- "fontFamily": 5,
- "text": "Internet",
- "textAlign": "left",
- "verticalAlign": "top",
- "containerId": null,
- "originalText": "Internet",
- "autoResize": true,
- "lineHeight": 1.25
- }
- ],
- "appState": {
- "gridSize": 20,
- "gridStep": 5,
- "gridModeEnabled": false,
- "viewBackgroundColor": "#ffffff"
- },
- "files": {}
-}
\ No newline at end of file
diff --git a/parser/src/actions/iter_blocks.rs b/parser/src/actions/iter_blocks.rs
index 7778596e4..aaf46e35e 100644
--- a/parser/src/actions/iter_blocks.rs
+++ b/parser/src/actions/iter_blocks.rs
@@ -18,7 +18,7 @@ use crate::{
};
pub fn iter_blocks(
- config: &Config,
+ config: &mut Config,
rpc: &biter::bitcoincore_rpc::Client,
approx_block_count: usize,
exit: Exit,
@@ -33,6 +33,7 @@ pub fn iter_blocks(
if config.first_defragment() {
databases.defragment(&exit);
+ config.disable_defragment();
}
log("Imported databases");
diff --git a/parser/src/main.rs b/parser/src/main.rs
index 39426ca5e..a95380569 100644
--- a/parser/src/main.rs
+++ b/parser/src/main.rs
@@ -8,7 +8,7 @@ fn main() -> color_eyre::Result<()> {
reset_logs();
- let config = Config::import()?;
+ let mut config = Config::import()?;
let rpc = create_rpc(&config).unwrap();
@@ -19,7 +19,7 @@ fn main() -> color_eyre::Result<()> {
log(&format!("{block_count} blocks found."));
- iter_blocks(&config, &rpc, block_count, exit.clone())?;
+ iter_blocks(&mut config, &rpc, block_count, exit.clone())?;
if let Some(delay) = config.delay {
sleep(Duration::from_secs(delay))
diff --git a/parser/src/structs/config.rs b/parser/src/structs/config.rs
index 179126ef9..bf88dca8b 100644
--- a/parser/src/structs/config.rs
+++ b/parser/src/structs/config.rs
@@ -171,4 +171,8 @@ impl Config {
pub fn first_defragment(&self) -> bool {
self.first_defragment.is_some_and(|b| b)
}
+
+ pub fn disable_defragment(&mut self) {
+ self.first_defragment.take();
+ }
}
diff --git a/website/index.html b/website/index.html
index ca34bf7a2..7ed4aa1dd 100644
--- a/website/index.html
+++ b/website/index.html
@@ -72,8 +72,6 @@
a {
color: inherit;
- -webkit-text-decoration: inherit;
- text-decoration: inherit;
}
b,
@@ -221,6 +219,8 @@
@@ -1207,32 +969,29 @@
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
-
-
-
-
-
-
-
- If you can't think of anything, you might want to try to
- open a random page
-
-
-
-
-
-
-
-
- General
-
-
- Options for the application's color scheme
-
-
-
-
- Donations
-
-
- A massive thank you to everybody who sent their hard earned sats. This
- project, by being completely free, is very dependent and only founded
- by the goodwill of fellow ₿itcoiners.
-
-
-
- And everybody else !
-
-
-
-
-
-
+
-
-
-
-
- Charts are displayed via
-
- Trading View
-
- 's
-
- Lightweight Charts™
-
- library
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
-
+
-
-
-
-
-
-
- All time
- 1 Week
- 1 Month
- 3 Months
- 6 Months
- Year To Date
- 1 Year
- 2 Years
- 3 Years
- 4 Years
- 6 Years
- 8 Years
- 2024
- 2023
- 2022
- 2021
- 2020
- 2019
- 2018
- 2017
- 2016
- 2015
- 2014
- 2013
- 2012
- 2011
- 2010
- 2009
-
-
- ≤900k
- ≤850k
- ≤800k
- ≤750k
- ≤700k
- ≤650k
- ≤600k
- ≤550k
- ≤500k
- ≤450k
- ≤400k
- ≤350k
- ≤300k
- ≤250k
- ≤200k
- ≤150k
- ≤100k
- ≤50k
-
-
-
diff --git a/website/packages/solid-signals/2024-04-17/script.js b/website/packages/solid-signals/2024-04-17/script.js
deleted file mode 100644
index 3d726e17b..000000000
--- a/website/packages/solid-signals/2024-04-17/script.js
+++ /dev/null
@@ -1,1010 +0,0 @@
-// @ts-nocheck
-
-// src/error.ts
-var NotReadyError = class extends Error {};
-var NoOwnerError = class extends Error {
- constructor() {
- super("");
- }
-};
-var ContextNotFoundError = class extends Error {
- constructor() {
- super("");
- }
-};
-
-// src/constants.ts
-var STATE_CLEAN = 0;
-var STATE_CHECK = 1;
-var STATE_DIRTY = 2;
-var STATE_DISPOSED = 3;
-
-// src/utils.ts
-function isUndefined(value) {
- return typeof value === "undefined";
-}
-
-// src/owner.ts
-var currentOwner = null;
-var defaultContext = {};
-function getOwner() {
- return currentOwner;
-}
-function setOwner(owner) {
- const out = currentOwner;
- currentOwner = owner;
- return out;
-}
-var Owner = class {
- // We flatten the owner tree into a linked list so that we don't need a pointer to .firstChild
- // However, the children are actually added in reverse creation order
- // See comment at the top of the file for an example of the _nextSibling traversal
- o = null;
- k = null;
- n = null;
- a = STATE_CLEAN;
- f = null;
- l = defaultContext;
- g = null;
- constructor(signal = false) {
- if (currentOwner && !signal) currentOwner.append(this);
- }
- append(child) {
- child.o = this;
- child.n = this;
- if (this.k) this.k.n = child;
- child.k = this.k;
- this.k = child;
- if (child.l !== this.l) {
- child.l = { ...this.l, ...child.l };
- }
- if (this.g) {
- child.g = !child.g ? this.g : [...child.g, ...this.g];
- }
- }
- dispose(self = true) {
- if (this.a === STATE_DISPOSED) return;
- let head = self ? this.n || this.o : this,
- current = this.k,
- next = null;
- while (current && current.o === this) {
- current.dispose(true);
- current.t();
- next = current.k;
- current.k = null;
- current = next;
- }
- if (self) this.t();
- if (current) current.n = !self ? this : this.n;
- if (head) head.k = current;
- }
- t() {
- if (this.n) this.n.k = null;
- this.o = null;
- this.n = null;
- this.l = defaultContext;
- this.g = null;
- this.a = STATE_DISPOSED;
- this.emptyDisposal();
- }
- emptyDisposal() {
- if (!this.f) return;
- if (Array.isArray(this.f)) {
- for (let i = 0; i < this.f.length; i++) {
- const callable = this.f[i];
- callable.call(callable);
- }
- } else {
- this.f.call(this.f);
- }
- this.f = null;
- }
- handleError(error) {
- if (!this.g) throw error;
- let i = 0,
- len = this.g.length;
- for (i = 0; i < len; i++) {
- try {
- this.g[i](error);
- break;
- } catch (e) {
- error = e;
- }
- }
- if (i === len) throw error;
- }
-};
-function createContext(defaultValue, description) {
- return { id: Symbol(description), defaultValue };
-}
-function getContext(context, owner = currentOwner) {
- if (!owner) {
- throw new NoOwnerError();
- }
- const value = hasContext(context, owner)
- ? owner.l[context.id]
- : context.defaultValue;
- if (isUndefined(value)) {
- throw new ContextNotFoundError();
- }
- return value;
-}
-function setContext(context, value, owner = currentOwner) {
- if (!owner) {
- throw new NoOwnerError();
- }
- owner.l = {
- ...owner.l,
- [context.id]: isUndefined(value) ? context.defaultValue : value,
- };
-}
-function hasContext(context, owner = currentOwner) {
- return !isUndefined(owner?.l[context.id]);
-}
-function onCleanup(disposable) {
- if (!currentOwner) return;
- const node = currentOwner;
- if (!node.f) {
- node.f = disposable;
- } else if (Array.isArray(node.f)) {
- node.f.push(disposable);
- } else {
- node.f = [node.f, disposable];
- }
-}
-
-// src/flags.ts
-var ERROR_OFFSET = 0;
-var ERROR_BIT = 1 << ERROR_OFFSET;
-var LOADING_OFFSET = 1;
-var LOADING_BIT = 1 << LOADING_OFFSET;
-var DEFAULT_FLAGS = ERROR_BIT;
-
-// src/core.ts
-var currentObserver = null;
-var currentMask = DEFAULT_FLAGS;
-var newSources = null;
-var newSourcesIndex = 0;
-var newFlags = 0;
-function getObserver() {
- return currentObserver;
-}
-var UNCHANGED = Symbol(0);
-var Computation = class extends Owner {
- c = null;
- b = null;
- j;
- v;
- // Used in __DEV__ mode, hopefully removed in production
- D;
- // Using false is an optimization as an alternative to _equals: () => false
- // which could enable more efficient DIRTY notification
- w = isEqual;
- /** Whether the computation is an error or has ancestors that are unresolved */
- m = 0;
- /** Which flags raised by sources are handled, vs. being passed through. */
- u = DEFAULT_FLAGS;
- x = null;
- y = null;
- constructor(initialValue, compute2, options) {
- super(compute2 === null);
- this.v = compute2;
- this.a = compute2 ? STATE_DIRTY : STATE_CLEAN;
- this.j = initialValue;
- if (options?.equals !== void 0) this.w = options.equals;
- }
- B() {
- if (this.v) this.p();
- track(this);
- newFlags |= this.m & ~currentMask;
- if (this.m & ERROR_BIT) {
- throw this.j;
- } else {
- return this.j;
- }
- }
- /**
- * Return the current value of this computation
- * Automatically re-executes the surrounding computation when the value changes
- */
- read() {
- return this.B();
- }
- /**
- * 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() {
- if (this.loading()) {
- throw new NotReadyError();
- }
- return this.B();
- }
- /**
- * 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() {
- if (this.y === null) {
- this.y = loadingState(this);
- }
- return this.y.read();
- }
- /**
- * Return true if the computation is the computation threw an error
- * Triggers re-execution of the computation when the error state changes
- */
- error() {
- if (this.x === null) {
- this.x = errorState(this);
- }
- return this.x.read();
- }
- /** Update the computation with a new value. */
- write(value, flags = 0, raw = false) {
- const newValue =
- !raw && typeof value === "function" ? value(this.j) : value;
- const valueChanged =
- newValue !== UNCHANGED &&
- (!!(flags & ERROR_BIT) || this.w === false || !this.w(this.j, newValue));
- if (valueChanged) this.j = newValue;
- const changedFlagsMask = this.m ^ flags,
- changedFlags = changedFlagsMask & flags;
- this.m = flags;
- if (this.b) {
- for (let i = 0; i < this.b.length; i++) {
- if (valueChanged) {
- this.b[i].q(STATE_DIRTY);
- } else if (changedFlagsMask) {
- this.b[i].C(changedFlagsMask, changedFlags);
- }
- }
- }
- return this.j;
- }
- /**
- * Set the current node's state, and recursively mark all of this node's observers as STATE_CHECK
- */
- q(state) {
- if (this.a >= state) return;
- this.a = state;
- if (this.b) {
- for (let i = 0; i < this.b.length; i++) {
- this.b[i].q(STATE_CHECK);
- }
- }
- }
- /**
- * 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.
- */
- C(mask, newFlags2) {
- if (this.a >= STATE_DIRTY) return;
- if (mask & this.u) {
- this.q(STATE_DIRTY);
- return;
- }
- if (this.a >= STATE_CHECK) return;
- const prevFlags = this.m & mask;
- const deltaFlags = prevFlags ^ newFlags2;
- if (newFlags2 === prevFlags);
- else if (deltaFlags & prevFlags & mask) {
- this.q(STATE_CHECK);
- } else {
- this.m ^= deltaFlags;
- if (this.b) {
- for (let i = 0; i < this.b.length; i++) {
- this.b[i].C(mask, newFlags2);
- }
- }
- }
- }
- z(error) {
- this.write(error, this.m | ERROR_BIT);
- }
- /**
- * 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
- */
- p() {
- if (this.a === STATE_DISPOSED) {
- throw new Error("Tried to read a disposed computation");
- }
- if (this.a === STATE_CLEAN) {
- return;
- }
- let observerFlags = 0;
- if (this.a === STATE_CHECK) {
- for (let i = 0; i < this.c.length; i++) {
- this.c[i].p();
- observerFlags |= this.c[i].m;
- if (this.a === STATE_DIRTY) {
- break;
- }
- }
- }
- if (this.a === STATE_DIRTY) {
- update(this);
- } else {
- this.write(UNCHANGED, observerFlags);
- this.a = STATE_CLEAN;
- }
- }
- /**
- * Remove ourselves from the owner graph and the computation graph
- */
- t() {
- if (this.a === STATE_DISPOSED) return;
- if (this.c) removeSourceObservers(this, 0);
- super.t();
- }
-};
-function loadingState(node) {
- const prevOwner = setOwner(node.o);
- const options = void 0;
- const computation = new Computation(
- void 0,
- () => {
- track(node);
- node.p();
- return !!(node.m & LOADING_BIT);
- },
- options,
- );
- computation.u = ERROR_BIT | LOADING_BIT;
- setOwner(prevOwner);
- return computation;
-}
-function errorState(node) {
- const prevOwner = setOwner(node.o);
- const options = void 0;
- const computation = new Computation(
- void 0,
- () => {
- track(node);
- node.p();
- return !!(node.m & ERROR_BIT);
- },
- options,
- );
- computation.u = ERROR_BIT;
- setOwner(prevOwner);
- return computation;
-}
-function track(computation) {
- if (currentObserver) {
- if (
- !newSources &&
- currentObserver.c &&
- currentObserver.c[newSourcesIndex] === computation
- ) {
- newSourcesIndex++;
- } else if (!newSources) newSources = [computation];
- else if (computation !== newSources[newSources.length - 1]) {
- newSources.push(computation);
- }
- }
-}
-function update(node) {
- const prevSources = newSources,
- prevSourcesIndex = newSourcesIndex,
- prevFlags = newFlags;
- newSources = null;
- newSourcesIndex = 0;
- newFlags = 0;
- try {
- node.dispose(false);
- node.emptyDisposal();
- const result = compute(node, node.v, node);
- node.write(result, newFlags, true);
- } catch (error) {
- if (error instanceof NotReadyError) {
- node.write(UNCHANGED, newFlags | LOADING_BIT);
- } else {
- node.z(error);
- }
- } finally {
- if (newSources) {
- if (node.c) removeSourceObservers(node, newSourcesIndex);
- if (node.c && newSourcesIndex > 0) {
- node.c.length = newSourcesIndex + newSources.length;
- for (let i = 0; i < newSources.length; i++) {
- node.c[newSourcesIndex + i] = newSources[i];
- }
- } else {
- node.c = newSources;
- }
- let source;
- for (let i = newSourcesIndex; i < node.c.length; i++) {
- source = node.c[i];
- if (!source.b) source.b = [node];
- else source.b.push(node);
- }
- } else if (node.c && newSourcesIndex < node.c.length) {
- removeSourceObservers(node, newSourcesIndex);
- node.c.length = newSourcesIndex;
- }
- newSources = prevSources;
- newSourcesIndex = prevSourcesIndex;
- newFlags = prevFlags;
- node.a = STATE_CLEAN;
- }
-}
-function removeSourceObservers(node, index) {
- let source;
- let swap;
- for (let i = index; i < node.c.length; i++) {
- source = node.c[i];
- if (source.b) {
- swap = source.b.indexOf(node);
- source.b[swap] = source.b[source.b.length - 1];
- source.b.pop();
- }
- }
-}
-function isEqual(a, b) {
- return a === b;
-}
-function untrack(fn) {
- if (currentObserver === null) return fn();
- return compute(getOwner(), fn, null);
-}
-function compute(owner, compute2, observer) {
- const prevOwner = setOwner(owner),
- prevObserver = currentObserver,
- prevMask = currentMask;
- currentObserver = observer;
- currentMask = observer?.u ?? DEFAULT_FLAGS;
- try {
- return compute2(observer ? observer.j : void 0);
- } finally {
- setOwner(prevOwner);
- currentObserver = prevObserver;
- currentMask = prevMask;
- }
-}
-
-// src/effect.ts
-var scheduledEffects = false;
-var runningEffects = false;
-var renderEffects = [];
-var effects = [];
-function flushSync() {
- if (!runningEffects) runEffects();
-}
-function flushEffects() {
- scheduledEffects = true;
- queueMicrotask(runEffects);
-}
-function runTop(node) {
- const ancestors = [];
- for (let current = node; current !== null; current = current.o) {
- if (current.a !== STATE_CLEAN) {
- ancestors.push(current);
- }
- }
- for (let i = ancestors.length - 1; i >= 0; i--) {
- if (ancestors[i].a !== STATE_DISPOSED) ancestors[i].p();
- }
-}
-function runEffects() {
- if (!effects.length) {
- scheduledEffects = false;
- return;
- }
- runningEffects = true;
- try {
- for (let i = 0; i < renderEffects.length; i++) {
- if (renderEffects[i].a !== STATE_CLEAN) {
- renderEffects[i].p();
- }
- }
- for (let i = 0; i < renderEffects.length; i++) {
- if (renderEffects[i].modified) {
- renderEffects[i].effect(renderEffects[i].j);
- renderEffects[i].modified = false;
- }
- }
- for (let i = 0; i < effects.length; i++) {
- if (effects[i].a !== STATE_CLEAN) {
- runTop(effects[i]);
- }
- }
- } finally {
- effects = [];
- renderEffects = [];
- scheduledEffects = false;
- runningEffects = false;
- }
-}
-var Effect = class extends Computation {
- constructor(initialValue, compute2, options) {
- super(initialValue, compute2, options);
- effects.push(this);
- flushEffects();
- }
- q(state) {
- if (this.a >= state) return;
- if (this.a === STATE_CLEAN) {
- effects.push(this);
- if (!scheduledEffects) flushEffects();
- }
- this.a = state;
- }
- write(value) {
- this.j = value;
- return value;
- }
- z(error) {
- this.handleError(error);
- }
-};
-var RenderEffect = class extends Computation {
- effect;
- modified = false;
- constructor(initialValue, compute2, effect, options) {
- super(initialValue, compute2, options);
- this.effect = effect;
- this.p();
- }
- q(state) {
- if (this.a >= state) return;
- if (this.a === STATE_CLEAN) {
- renderEffects.push(this);
- if (!scheduledEffects) flushEffects();
- }
- this.a = state;
- }
- write(value) {
- this.j = value;
- this.modified = true;
- return value;
- }
- z(error) {
- this.handleError(error);
- }
-};
-
-// src/signals.ts
-function createSignal(initialValue, options) {
- const node = new Computation(initialValue, null, options);
- return [node.read.bind(node), node.write.bind(node)];
-}
-function createAsync(fn, initial, options) {
- const lhs = new Computation(void 0, () => {
- const promise = Promise.resolve(fn());
- const signal = new Computation(initial, null, options);
- signal.write(UNCHANGED, LOADING_BIT);
- promise.then(
- (value) => {
- signal.write(value, 0);
- },
- (error) => {
- signal.write(error, ERROR_BIT);
- },
- );
- return signal;
- });
- const rhs = new Computation(void 0, () => lhs.read().wait(), options);
- return () => rhs.wait();
-}
-function createMemo(compute2, initialValue, options) {
- const node = new Computation(initialValue, compute2, options);
- return node.read.bind(node);
-}
-function createEffect(effect, initialValue, options) {
- void new Effect(initialValue, effect, void 0);
-}
-function createRenderEffect(compute2, effect, initialValue, options) {
- void new RenderEffect(initialValue, compute2, effect, void 0);
-}
-function createRoot(init) {
- const owner = new Owner();
- return compute(
- owner,
- !init.length ? init : () => init(() => owner.dispose()),
- null,
- );
-}
-function runWithOwner(owner, run) {
- try {
- return compute(owner, run, null);
- } catch (error) {
- owner?.handleError(error);
- return void 0;
- }
-}
-function catchError(fn, handler) {
- const owner = new Owner();
- owner.g = owner.g ? [handler, ...owner.g] : [handler];
- try {
- compute(owner, fn, null);
- } catch (error) {
- owner.handleError(error);
- }
-}
-
-// src/map.ts
-function indexArray(list, map, options) {
- return Computation.prototype.read.bind(
- new Computation(
- [],
- updateMap.bind({
- r: new Owner(),
- i: 0,
- A: list,
- h: [],
- s: map,
- d: [],
- e: [],
- }),
- options,
- ),
- );
-}
-function updateMap() {
- let i = 0,
- newItems = this.A() || [],
- mapper = () => this.s(Computation.prototype.read.bind(this.e[i]), i);
- runWithOwner(this.r, () => {
- if (newItems.length === 0) {
- if (this.i !== 0) {
- this.r.dispose(false);
- this.h = [];
- this.d = [];
- this.i = 0;
- this.e = [];
- }
- return;
- }
- for (i = 0; i < newItems.length; i++) {
- if (i < this.h.length && this.h[i] !== newItems[i]) {
- this.e[i].write(newItems[i]);
- } else if (i >= this.h.length) {
- this.d[i] = compute(
- (this.e[i] = new Computation(newItems[i], null)),
- mapper,
- null,
- );
- }
- }
- for (; i < this.h.length; i++) this.e[i].dispose();
- this.i = this.e.length = newItems.length;
- this.h = newItems.slice(0);
- this.d = this.d.slice(0, this.i);
- });
- return this.d;
-}
-function mapArray(list, map, options) {
- return Computation.prototype.read.bind(
- new Computation(
- [],
- updateKeyedMap.bind({
- r: new Owner(),
- i: 0,
- A: list,
- h: [],
- s: map,
- d: [],
- e: [],
- }),
- options,
- ),
- );
-}
-function updateKeyedMap() {
- const newItems = this.A() || [],
- indexed = this.s.length > 1;
- runWithOwner(this.r, () => {
- let newLen = newItems.length,
- i,
- j,
- mapper = indexed
- ? () => this.s(newItems[j], Computation.prototype.read.bind(this.e[j]))
- : () => this.s(newItems[j]);
- if (newLen === 0) {
- if (this.i !== 0) {
- this.r.dispose(false);
- this.e = [];
- this.h = [];
- this.d = [];
- this.i = 0;
- }
- } else if (this.i === 0) {
- this.d = new Array(newLen);
- for (j = 0; j < newLen; j++) {
- this.h[j] = newItems[j];
- this.d[j] = compute(
- (this.e[j] = new Computation(j, null)),
- mapper,
- null,
- );
- }
- this.i = newLen;
- } else {
- let start,
- end,
- newEnd,
- item,
- newIndices,
- newIndicesNext,
- temp = new Array(newLen),
- tempNodes = new Array(newLen);
- for (
- start = 0, end = Math.min(this.i, newLen);
- start < end && this.h[start] === newItems[start];
- start++
- );
- for (
- end = this.i - 1, newEnd = newLen - 1;
- end >= start && newEnd >= start && this.h[end] === newItems[newEnd];
- end--, newEnd--
- ) {
- temp[newEnd] = this.d[end];
- tempNodes[newEnd] = this.e[end];
- }
- newIndices = /* @__PURE__ */ new Map();
- newIndicesNext = new Array(newEnd + 1);
- for (j = newEnd; j >= start; j--) {
- item = newItems[j];
- i = newIndices.get(item);
- newIndicesNext[j] = i === void 0 ? -1 : i;
- newIndices.set(item, j);
- }
- for (i = start; i <= end; i++) {
- item = this.h[i];
- j = newIndices.get(item);
- if (j !== void 0 && j !== -1) {
- temp[j] = this.d[i];
- tempNodes[j] = this.e[i];
- j = newIndicesNext[j];
- newIndices.set(item, j);
- } else this.e[i].dispose();
- }
- for (j = start; j < newLen; j++) {
- if (j in temp) {
- this.d[j] = temp[j];
- this.e[j] = tempNodes[j];
- this.e[j].write(j);
- } else {
- this.d[j] = compute(
- (this.e[j] = new Computation(j, null)),
- mapper,
- null,
- );
- }
- }
- this.d = this.d.slice(0, (this.i = newLen));
- this.h = newItems.slice(0);
- }
- });
- return this.d;
-}
-
-// src/selector.ts
-function createSelector(source, options) {
- let prevSource,
- subs = /* @__PURE__ */ new Map(),
- equals = options?.equals ?? isEqual;
- const node = new Effect(
- void 0,
- () => {
- const newSource = source();
- for (const [key, val] of subs) {
- if (equals(key, newSource) !== equals(key, prevSource)) {
- for (const c of val.values()) {
- c.q(STATE_DIRTY);
- }
- }
- }
- return (prevSource = newSource);
- },
- void 0,
- );
- return function observeSelector(key) {
- const observer = getObserver();
- if (observer) {
- let l;
- if ((l = subs.get(key))) l.add(observer);
- else subs.set(key, (l = /* @__PURE__ */ new Set([observer])));
- onCleanup(() => {
- l.delete(observer);
- !l.size && subs.delete(key);
- });
- }
- return equals(key, node.read());
- };
-}
-
-// src/store.ts
-var $RAW = Symbol(0);
-var $TRACK = Symbol(0);
-var $PROXY = Symbol(0);
-var PROXIES = /* @__PURE__ */ new WeakMap();
-var NODES = [/* @__PURE__ */ new WeakMap(), /* @__PURE__ */ new WeakMap()];
-function wrap(value) {
- let p = PROXIES.get(value);
- if (!p) PROXIES.set(value, (p = new Proxy(value, proxyTraps)));
- return p;
-}
-function isWrappable(obj) {
- let proto;
- return (
- obj != null &&
- typeof obj === "object" &&
- (PROXIES.has(obj) ||
- !(proto = Object.getPrototypeOf(obj)) ||
- proto === Object.prototype ||
- Array.isArray(obj))
- );
-}
-function unwrap(item, set = /* @__PURE__ */ new Set()) {
- let result, unwrapped, v, prop;
- if ((result = item != null && item[$RAW])) return result;
- if (!isWrappable(item) || set.has(item)) return item;
- if (Array.isArray(item)) {
- if (Object.isFrozen(item)) item = item.slice(0);
- else set.add(item);
- for (let i = 0, l = item.length; i < l; i++) {
- v = item[i];
- if ((unwrapped = unwrap(v, set)) !== v) item[i] = unwrapped;
- }
- } else {
- if (Object.isFrozen(item)) item = Object.assign({}, item);
- else set.add(item);
- const keys = Object.keys(item);
- for (let i = 0, l = keys.length; i < l; i++) {
- prop = keys[i];
- const desc = Object.getOwnPropertyDescriptor(item, prop);
- if (desc.get) continue;
- v = item[prop];
- if ((unwrapped = unwrap(v, set)) !== v) item[prop] = unwrapped;
- }
- }
- return item;
-}
-function getNodes(target, type) {
- let nodes = NODES[type].get(target);
- if (!nodes)
- NODES[type].set(target, (nodes = /* @__PURE__ */ Object.create(null)));
- return nodes;
-}
-function getNode(nodes, property, value) {
- if (nodes[property]) return nodes[property];
- return (nodes[property] = new Computation(value, null, {
- equals: false,
- }));
-}
-function proxyDescriptor(target, property) {
- const desc = Reflect.getOwnPropertyDescriptor(target, property);
- if (!desc || desc.get || !desc.configurable || property === $PROXY)
- return desc;
- delete desc.value;
- delete desc.writable;
- desc.get = () => PROXIES.get(target)[property];
- return desc;
-}
-function trackSelf(target) {
- getObserver() && getNode(getNodes(target, 0), $TRACK).read();
-}
-function ownKeys(target) {
- trackSelf(target);
- return Reflect.ownKeys(target);
-}
-var Writing = false;
-var proxyTraps = {
- get(target, property, receiver) {
- if (property === $RAW) return target;
- if (property === $PROXY) return receiver;
- if (property === $TRACK) {
- trackSelf(target);
- return receiver;
- }
- const desc = Object.getOwnPropertyDescriptor(target, property);
- if (desc && desc.get) return desc.get.call(receiver);
- const nodes = getNodes(target, 0);
- const tracked = nodes[property];
- let value = tracked ? nodes[property].read() : target[property];
- if (
- !tracked &&
- getObserver() &&
- (typeof value !== "function" || target.hasOwnProperty(property))
- )
- value = getNode(nodes, property, value).read();
- return isWrappable(value) ? wrap(value) : value;
- },
- has(target, property) {
- if (
- property === $RAW ||
- property === $PROXY ||
- property === $TRACK ||
- property === "__proto__"
- )
- return true;
- getObserver() && getNode(getNodes(target, 1), property).read();
- return property in target;
- },
- set(target, property, value) {
- Writing && setProperty(target, property, unwrap(value));
- return true;
- },
- deleteProperty(target, property) {
- Writing && setProperty(target, property, void 0, true);
- return true;
- },
- ownKeys,
- getOwnPropertyDescriptor: proxyDescriptor,
-};
-function setProperty(state, property, value, deleting = false) {
- if (!deleting && state[property] === value) return;
- const prev = state[property];
- const len = state.length;
- if (deleting) delete state[property];
- else state[property] = value;
- const nodes = getNodes(state, 0);
- let node;
- if ((node = getNode(nodes, property, prev))) node.write(value);
- if (Array.isArray(state) && state.length !== len)
- (node = getNode(nodes, "length", len)) && node.write(state.length);
- (node = nodes[$TRACK]) && node.write(void 0);
-}
-function createStore(store) {
- const unwrappedStore = unwrap(store);
- const wrappedStore = wrap(unwrappedStore);
- const setStore = (fn) => {
- try {
- Writing = true;
- fn(wrappedStore);
- } finally {
- Writing = false;
- }
- };
- return [wrappedStore, setStore];
-}
-
-export {
- Computation,
- ContextNotFoundError,
- Effect,
- NoOwnerError,
- NotReadyError,
- Owner,
- RenderEffect,
- catchError,
- compute,
- createAsync,
- createContext,
- createEffect,
- createMemo,
- createRenderEffect,
- createRoot,
- createSelector,
- createSignal,
- createStore,
- flushSync,
- getContext,
- getObserver,
- getOwner,
- hasContext,
- indexArray,
- isEqual,
- isWrappable,
- mapArray,
- onCleanup,
- runWithOwner,
- setContext,
- setOwner,
- untrack,
- unwrap,
-};
diff --git a/website/packages/solid-signals/2024-04-17/types/effect.d.ts b/website/packages/solid-signals/2024-04-17/types/effect.d.ts
deleted file mode 100644
index 6b6a7e4c8..000000000
--- a/website/packages/solid-signals/2024-04-17/types/effect.d.ts
+++ /dev/null
@@ -1,25 +0,0 @@
-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 extends Computation {
- constructor(initialValue: T, compute: () => T, options?: MemoOptions);
- _notify(state: number): void;
- write(value: T): T;
- _setError(error: unknown): void;
-}
-export declare class RenderEffect extends Computation {
- effect: (val: T) => void;
- modified: boolean;
- constructor(initialValue: T, compute: () => T, effect: (val: T) => void, options?: MemoOptions);
- _notify(state: number): void;
- write(value: T): T;
- _setError(error: unknown): void;
-}
diff --git a/website/packages/solid-signals/2024-04-17/types/index.d.ts b/website/packages/solid-signals/2024-04-17/types/index.d.ts
deleted file mode 100644
index 5366727b0..000000000
--- a/website/packages/solid-signals/2024-04-17/types/index.d.ts
+++ /dev/null
@@ -1,8 +0,0 @@
-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';
diff --git a/website/packages/solid-signals/2024-04-17/types/map.d.ts b/website/packages/solid-signals/2024-04-17/types/map.d.ts
deleted file mode 100644
index 43d4b52b8..000000000
--- a/website/packages/solid-signals/2024-04-17/types/map.d.ts
+++ /dev/null
@@ -1,26 +0,0 @@
-import type { Accessor } from './signals';
-export type Maybe = 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- (list: Accessor
>, map: (value: Accessor- , index: number) => MappedItem, options?: {
- name?: string;
-}): Accessor
;
-/**
- * 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- (list: Accessor
>, map: (value: Item, index: Accessor) => MappedItem, options?: {
- name?: string;
-}): Accessor;
diff --git a/website/packages/solid-signals/2024-04-17/types/selector.d.ts b/website/packages/solid-signals/2024-04-17/types/selector.d.ts
deleted file mode 100644
index 9119d60d5..000000000
--- a/website/packages/solid-signals/2024-04-17/types/selector.d.ts
+++ /dev/null
@@ -1,15 +0,0 @@
-import type { Accessor } from './signals';
-export interface SelectorSignal {
- (key: T): Boolean;
-}
-export interface SelectorOptions {
- 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: Accessor, options?: SelectorOptions): SelectorSignal;
diff --git a/website/packages/solid-signals/2024-10-28/types/index.d.ts b/website/packages/solid-signals/2024-10-28/types/index.d.ts
deleted file mode 100644
index 53b9c5a00..000000000
--- a/website/packages/solid-signals/2024-10-28/types/index.d.ts
+++ /dev/null
@@ -1,6 +0,0 @@
-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, hasUpdated, type SignalOptions, } from './core';
-export { Effect, RenderEffect } from './effect';
-export { flushSync } from './scheduler';
-export * from './signals';
diff --git a/website/packages/solid-signals/2024-10-28/script.js b/website/packages/solid-signals/2024-11-02/script.js
similarity index 72%
rename from website/packages/solid-signals/2024-10-28/script.js
rename to website/packages/solid-signals/2024-11-02/script.js
index 1c7f14b5b..3e997d89d 100644
--- a/website/packages/solid-signals/2024-10-28/script.js
+++ b/website/packages/solid-signals/2024-11-02/script.js
@@ -1,28 +1,33 @@
-// src/error.ts
-var NotReadyError = class extends Error {};
+// src/core/error.ts
+var NotReadyError = class extends Error {
+};
var NoOwnerError = class extends Error {
constructor() {
- super("");
+ super(
+ ""
+ );
}
};
var ContextNotFoundError = class extends Error {
constructor() {
- super("");
+ super(
+ ""
+ );
}
};
-// src/constants.ts
-var STATE_CLEAN = 0;
-var STATE_CHECK = 1;
-var STATE_DIRTY = 2;
-var STATE_DISPOSED = 3;
-
// src/utils.ts
function isUndefined(value) {
return typeof value === "undefined";
}
-// src/owner.ts
+// src/core/constants.ts
+var STATE_CLEAN = 0;
+var STATE_CHECK = 1;
+var STATE_DIRTY = 2;
+var STATE_DISPOSED = 3;
+
+// src/core/owner.ts
var currentOwner = null;
var defaultContext = {};
function getOwner() {
@@ -37,7 +42,7 @@ var Owner = class {
// We flatten the owner tree into a linked list so that we don't need a pointer to .firstChild
// However, the children are actually added in reverse creation order
// See comment at the top of the file for an example of the _nextSibling traversal
- k = null;
+ l = null;
g = null;
j = null;
a = STATE_CLEAN;
@@ -45,12 +50,14 @@ var Owner = class {
h = defaultContext;
f = null;
constructor(signal = false) {
- if (currentOwner && !signal) currentOwner.append(this);
+ if (currentOwner && !signal)
+ currentOwner.append(this);
}
append(child) {
- child.k = this;
+ child.l = this;
child.j = this;
- if (this.g) this.g.j = child;
+ if (this.g)
+ this.g.j = child;
child.g = this.g;
this.g = child;
if (child.h !== this.h) {
@@ -61,24 +68,27 @@ var Owner = class {
}
}
dispose(self = true) {
- if (this.a === STATE_DISPOSED) return;
- let head = self ? this.j || this.k : this,
- current = this.g,
- next = null;
- while (current && current.k === this) {
+ if (this.a === STATE_DISPOSED)
+ return;
+ let head = self ? this.j || this.l : this, current = this.g, next = null;
+ while (current && current.l === this) {
current.dispose(true);
current.n();
next = current.g;
current.g = null;
current = next;
}
- if (self) this.n();
- if (current) current.j = !self ? this : this.j;
- if (head) head.g = current;
+ if (self)
+ this.n();
+ if (current)
+ current.j = !self ? this : this.j;
+ if (head)
+ head.g = current;
}
n() {
- if (this.j) this.j.g = null;
- this.k = null;
+ if (this.j)
+ this.j.g = null;
+ this.l = null;
this.j = null;
this.h = defaultContext;
this.f = null;
@@ -86,7 +96,8 @@ var Owner = class {
this.emptyDisposal();
}
emptyDisposal() {
- if (!this.e) return;
+ if (!this.e)
+ return;
if (Array.isArray(this.e)) {
for (let i = 0; i < this.e.length; i++) {
const callable = this.e[i];
@@ -98,9 +109,9 @@ var Owner = class {
this.e = null;
}
handleError(error) {
- if (!this.f) throw error;
- let i = 0,
- len = this.f.length;
+ if (!this.f)
+ throw error;
+ let i = 0, len = this.f.length;
for (i = 0; i < len; i++) {
try {
this.f[i](error);
@@ -109,7 +120,8 @@ var Owner = class {
error = e;
}
}
- if (i === len) throw error;
+ if (i === len)
+ throw error;
}
};
function createContext(defaultValue, description) {
@@ -119,9 +131,7 @@ function getContext(context, owner = currentOwner) {
if (!owner) {
throw new NoOwnerError();
}
- const value = hasContext(context, owner)
- ? owner.h[context.id]
- : context.defaultValue;
+ const value = hasContext(context, owner) ? owner.h[context.id] : context.defaultValue;
if (isUndefined(value)) {
throw new ContextNotFoundError();
}
@@ -133,14 +143,15 @@ function setContext(context, value, owner = currentOwner) {
}
owner.h = {
...owner.h,
- [context.id]: isUndefined(value) ? context.defaultValue : value,
+ [context.id]: isUndefined(value) ? context.defaultValue : value
};
}
function hasContext(context, owner = currentOwner) {
return !isUndefined(owner?.h[context.id]);
}
function onCleanup(disposable) {
- if (!currentOwner) return;
+ if (!currentOwner)
+ return;
const node = currentOwner;
if (!node.e) {
node.e = disposable;
@@ -151,36 +162,39 @@ function onCleanup(disposable) {
}
}
-// src/flags.ts
+// src/core/flags.ts
var ERROR_OFFSET = 0;
var ERROR_BIT = 1 << ERROR_OFFSET;
var LOADING_OFFSET = 1;
var LOADING_BIT = 1 << LOADING_OFFSET;
var DEFAULT_FLAGS = ERROR_BIT;
-// src/scheduler.ts
+// src/core/scheduler.ts
var scheduled = false;
var runningScheduled = false;
var Computations = [];
var RenderEffects = [];
var Effects = [];
function flushSync() {
- if (!runningScheduled) runScheduled();
+ if (!runningScheduled)
+ runScheduled();
}
function flushQueue() {
- if (scheduled) return;
+ if (scheduled)
+ return;
scheduled = true;
queueMicrotask(runScheduled);
}
function runTop(node) {
const ancestors = [];
- for (let current = node; current !== null; current = current.k) {
+ for (let current = node; current !== null; current = current.l) {
if (current.a !== STATE_CLEAN) {
ancestors.push(current);
}
}
for (let i = ancestors.length - 1; i >= 0; i--) {
- if (ancestors[i].a !== STATE_DISPOSED) ancestors[i].l();
+ if (ancestors[i].a !== STATE_DISPOSED)
+ ancestors[i].m();
}
}
function runScheduled() {
@@ -208,7 +222,8 @@ function runScheduled() {
}
function runPureQueue(queue) {
for (let i = 0; i < queue.length; i++) {
- if (queue[i].a !== STATE_CLEAN) runTop(queue[i]);
+ if (queue[i].a !== STATE_CLEAN)
+ runTop(queue[i]);
}
}
function runEffectQueue(queue) {
@@ -221,13 +236,14 @@ function runEffectQueue(queue) {
}
}
-// src/core.ts
+// src/core/core.ts
var currentObserver = null;
var currentMask = DEFAULT_FLAGS;
var newSources = null;
var newSourcesIndex = 0;
var newFlags = 0;
var clock = 0;
+var syncResolve = false;
var updateCheck = null;
function getObserver() {
return currentObserver;
@@ -259,12 +275,16 @@ var Computation2 = class extends Owner {
this.s = compute2;
this.a = compute2 ? STATE_DIRTY : STATE_CLEAN;
this.d = initialValue;
- if (options?.equals !== void 0) this.t = options.equals;
- if (options?.unobserved) this.x = options?.unobserved;
+ if (options?.equals !== void 0)
+ this.t = options.equals;
+ if (options?.unobserved)
+ this.x = options?.unobserved;
}
y() {
- if (this.s) this.l();
- if (!this.b || this.b.length) track(this);
+ if (this.s)
+ this.m();
+ if (!this.b || this.b.length)
+ track(this);
newFlags |= this.i & ~currentMask;
if (this.i & ERROR_BIT) {
throw this.d;
@@ -287,7 +307,7 @@ var Computation2 = class extends Owner {
* before continuing
*/
wait() {
- if (this.loading()) {
+ if (!syncResolve && this.loading()) {
throw new NotReadyError();
}
return this.y();
@@ -317,20 +337,17 @@ var Computation2 = class extends Owner {
}
/** Update the computation with a new value. */
write(value, flags = 0, raw = false) {
- const newValue =
- !raw && typeof value === "function" ? value(this.d) : value;
- const valueChanged =
- newValue !== UNCHANGED &&
- (!!(flags & ERROR_BIT) || this.t === false || !this.t(this.d, newValue));
- if (valueChanged) this.d = newValue;
- const changedFlagsMask = this.i ^ flags,
- changedFlags = changedFlagsMask & flags;
+ const newValue = !raw && typeof value === "function" ? value(this.d) : value;
+ const valueChanged = newValue !== UNCHANGED && (!!(flags & ERROR_BIT) || this.t === false || !this.t(this.d, newValue));
+ if (valueChanged)
+ this.d = newValue;
+ const changedFlagsMask = this.i ^ flags, changedFlags = changedFlagsMask & flags;
this.i = flags;
this.w = clock + 1;
if (this.c) {
for (let i = 0; i < this.c.length; i++) {
if (valueChanged) {
- this.c[i].m(STATE_DIRTY);
+ this.c[i].k(STATE_DIRTY);
} else if (changedFlagsMask) {
this.c[i].z(changedFlagsMask, changedFlags);
}
@@ -341,12 +358,13 @@ var Computation2 = class extends Owner {
/**
* Set the current node's state, and recursively mark all of this node's observers as STATE_CHECK
*/
- m(state) {
- if (this.a >= state) return;
+ k(state) {
+ if (this.a >= state)
+ return;
this.a = state;
if (this.c) {
for (let i = 0; i < this.c.length; i++) {
- this.c[i].m(STATE_CHECK);
+ this.c[i].k(STATE_CHECK);
}
}
}
@@ -357,17 +375,18 @@ var Computation2 = class extends Owner {
* @param newFlags The source's new flags, masked to just the changed ones.
*/
z(mask, newFlags2) {
- if (this.a >= STATE_DIRTY) return;
+ if (this.a >= STATE_DIRTY)
+ return;
if (mask & this.p) {
- this.m(STATE_DIRTY);
+ this.k(STATE_DIRTY);
return;
}
- if (this.a >= STATE_CHECK) return;
+ if (this.a >= STATE_CHECK)
+ return;
const prevFlags = this.i & mask;
const deltaFlags = prevFlags ^ newFlags2;
- if (newFlags2 === prevFlags);
- else if (deltaFlags & prevFlags & mask) {
- this.m(STATE_CHECK);
+ if (newFlags2 === prevFlags) ; else if (deltaFlags & prevFlags & mask) {
+ this.k(STATE_CHECK);
} else {
this.i ^= deltaFlags;
if (this.c) {
@@ -387,7 +406,7 @@ var Computation2 = class extends Owner {
*
* This function will ensure that the value and states we read from the computation are up to date
*/
- l() {
+ m() {
if (this.a === STATE_DISPOSED) {
throw new Error("Tried to read a disposed computation");
}
@@ -397,7 +416,7 @@ var Computation2 = class extends Owner {
let observerFlags = 0;
if (this.a === STATE_CHECK) {
for (let i = 0; i < this.b.length; i++) {
- this.b[i].l();
+ this.b[i].m();
observerFlags |= this.b[i].i;
if (this.a === STATE_DIRTY) {
break;
@@ -415,38 +434,40 @@ var Computation2 = class extends Owner {
* Remove ourselves from the owner graph and the computation graph
*/
n() {
- if (this.a === STATE_DISPOSED) return;
- if (this.b) removeSourceObservers(this, 0);
+ if (this.a === STATE_DISPOSED)
+ return;
+ if (this.b)
+ removeSourceObservers(this, 0);
super.n();
}
};
function loadingState(node) {
- const prevOwner = setOwner(node.k);
+ const prevOwner = setOwner(node.l);
const options = void 0;
const computation = new Computation2(
void 0,
() => {
track(node);
- node.l();
+ node.m();
return !!(node.i & LOADING_BIT);
},
- options,
+ options
);
computation.p = ERROR_BIT | LOADING_BIT;
setOwner(prevOwner);
return computation;
}
function errorState(node) {
- const prevOwner = setOwner(node.k);
+ const prevOwner = setOwner(node.l);
const options = void 0;
const computation = new Computation2(
void 0,
() => {
track(node);
- node.l();
+ node.m();
return !!(node.i & ERROR_BIT);
},
- options,
+ options
);
computation.p = ERROR_BIT;
setOwner(prevOwner);
@@ -454,13 +475,10 @@ function errorState(node) {
}
function track(computation) {
if (currentObserver) {
- if (
- !newSources &&
- currentObserver.b &&
- currentObserver.b[newSourcesIndex] === computation
- ) {
+ if (!newSources && currentObserver.b && currentObserver.b[newSourcesIndex] === computation) {
newSourcesIndex++;
- } else if (!newSources) newSources = [computation];
+ } else if (!newSources)
+ newSources = [computation];
else if (computation !== newSources[newSources.length - 1]) {
newSources.push(computation);
}
@@ -470,9 +488,7 @@ function track(computation) {
}
}
function update(node) {
- const prevSources = newSources,
- prevSourcesIndex = newSourcesIndex,
- prevFlags = newFlags;
+ const prevSources = newSources, prevSourcesIndex = newSourcesIndex, prevFlags = newFlags;
newSources = null;
newSourcesIndex = 0;
newFlags = 0;
@@ -489,7 +505,8 @@ function update(node) {
}
} finally {
if (newSources) {
- if (node.b) removeSourceObservers(node, newSourcesIndex);
+ if (node.b)
+ removeSourceObservers(node, newSourcesIndex);
if (node.b && newSourcesIndex > 0) {
node.b.length = newSourcesIndex + newSources.length;
for (let i = 0; i < newSources.length; i++) {
@@ -501,8 +518,10 @@ function update(node) {
let source;
for (let i = newSourcesIndex; i < node.b.length; i++) {
source = node.b[i];
- if (!source.c) source.c = [node];
- else source.c.push(node);
+ if (!source.c)
+ source.c = [node];
+ else
+ source.c.push(node);
}
} else if (node.b && newSourcesIndex < node.b.length) {
removeSourceObservers(node, newSourcesIndex);
@@ -523,7 +542,8 @@ function removeSourceObservers(node, index) {
swap = source.c.indexOf(node);
source.c[swap] = source.c[source.c.length - 1];
source.c.pop();
- if (!source.c.length) source.x?.();
+ if (!source.c.length)
+ source.x?.();
}
}
}
@@ -531,7 +551,8 @@ function isEqual(a, b) {
return a === b;
}
function untrack(fn) {
- if (currentObserver === null) return fn();
+ if (currentObserver === null)
+ return fn();
return compute(getOwner(), fn, null);
}
function hasUpdated(fn) {
@@ -544,10 +565,27 @@ function hasUpdated(fn) {
updateCheck = current;
}
}
+function isPending(fn) {
+ try {
+ fn();
+ return false;
+ } catch (e) {
+ return e instanceof NotReadyError;
+ }
+}
+function latest(fn) {
+ const prevFlags = newFlags;
+ syncResolve = true;
+ try {
+ return fn();
+ } catch {
+ } finally {
+ newFlags = prevFlags;
+ syncResolve = false;
+ }
+}
function compute(owner, compute2, observer) {
- const prevOwner = setOwner(owner),
- prevObserver = currentObserver,
- prevMask = currentMask;
+ const prevOwner = setOwner(owner), prevObserver = currentObserver, prevMask = currentMask;
currentObserver = observer;
currentMask = observer?.p ?? DEFAULT_FLAGS;
try {
@@ -561,20 +599,21 @@ function compute(owner, compute2, observer) {
var EagerComputation = class extends Computation2 {
constructor(initialValue, compute2, options) {
super(initialValue, compute2, options);
- this.l();
+ this.m();
Computations.push(this);
}
- m(state) {
- if (this.a >= state) return;
+ k(state) {
+ if (this.a >= state)
+ return;
if (this.a === STATE_CLEAN) {
Computations.push(this);
flushQueue();
}
- this.a = state;
+ super.k(state);
}
};
-// src/effect.ts
+// src/core/effect.ts
var BaseEffect = class extends Computation2 {
r;
q = false;
@@ -585,7 +624,8 @@ var BaseEffect = class extends Computation2 {
this.o = initialValue;
}
write(value) {
- if (value === UNCHANGED) return this.d;
+ if (value === UNCHANGED)
+ return this.d;
this.d = value;
this.q = true;
return value;
@@ -605,8 +645,9 @@ var Effect = class extends BaseEffect {
Effects.push(this);
flushQueue();
}
- m(state) {
- if (this.a >= state) return;
+ k(state) {
+ if (this.a >= state)
+ return;
if (this.a === STATE_CLEAN) {
Effects.push(this);
flushQueue();
@@ -617,11 +658,12 @@ var Effect = class extends BaseEffect {
var RenderEffect = class extends BaseEffect {
constructor(initialValue, compute2, effect, options) {
super(initialValue, compute2, effect, options);
- this.l();
+ this.m();
RenderEffects.push(this);
}
- m(state) {
- if (this.a >= state) return;
+ k(state) {
+ if (this.a >= state)
+ return;
if (this.a === STATE_CLEAN) {
RenderEffects.push(this);
flushQueue();
@@ -637,7 +679,7 @@ function createSignal(first, second, third) {
const node2 = new Computation2(
first(p ? untrack(p[0]) : second),
null,
- third,
+ third
);
return [node2.read.bind(node2), node2.write.bind(node2)];
});
@@ -647,44 +689,52 @@ function createSignal(first, second, third) {
return [node.read.bind(node), node.write.bind(node)];
}
function createAsync(fn, initial, options) {
- const lhs = new EagerComputation(void 0, () => {
- const source = fn(initial);
- const isPromise = source instanceof Promise;
- const iterator = source[Symbol.asyncIterator];
- if (!isPromise && !iterator) {
- return {
- wait() {
- return source;
- },
- };
- }
- const signal = new Computation2(initial, null, options);
- signal.write(UNCHANGED, LOADING_BIT);
- if (isPromise) {
- source.then(
- (value) => {
- signal.write(value, 0);
- },
- (error) => {
- signal.write(error, ERROR_BIT);
- },
- );
- } else {
- let abort = false;
- onCleanup(() => (abort = true));
- (async () => {
- try {
- for await (let value of source) {
- if (abort) return;
- signal.write(value, 0);
+ const lhs = new EagerComputation(
+ {
+ d: initial
+ },
+ (p) => {
+ const value = p?.d;
+ const source = fn(value);
+ const isPromise = source instanceof Promise;
+ const iterator = source[Symbol.asyncIterator];
+ if (!isPromise && !iterator) {
+ return {
+ wait() {
+ return source;
+ },
+ d: source
+ };
+ }
+ const signal = new Computation2(value, null, options);
+ signal.write(UNCHANGED, LOADING_BIT);
+ if (isPromise) {
+ source.then(
+ (value2) => {
+ signal.write(value2, 0);
+ },
+ (error) => {
+ signal.write(error, ERROR_BIT);
}
- } catch (error) {
- signal.write(error, ERROR_BIT);
- }
- })();
+ );
+ } else {
+ let abort = false;
+ onCleanup(() => abort = true);
+ (async () => {
+ try {
+ for await (let value2 of source) {
+ if (abort)
+ return;
+ signal.write(value2, 0);
+ }
+ } catch (error) {
+ signal.write(error, ERROR_BIT);
+ }
+ })();
+ }
+ return signal;
}
- return signal;
- });
+ );
return () => lhs.wait().wait();
}
function createMemo(compute2, initialValue, options) {
@@ -693,24 +743,31 @@ function createMemo(compute2, initialValue, options) {
return () => {
if (node) {
value = node.wait();
- if (!node.b?.length) node = void 0;
+ if (!node.b?.length)
+ node = void 0;
}
return value;
};
}
function createEffect(compute2, effect, initialValue, options) {
- void new Effect(initialValue, compute2, effect, void 0);
+ void new Effect(
+ initialValue,
+ compute2,
+ effect,
+ void 0
+ );
}
function createRenderEffect(compute2, effect, initialValue, options) {
- void new RenderEffect(initialValue, compute2, effect, void 0);
+ void new RenderEffect(
+ initialValue,
+ compute2,
+ effect,
+ void 0
+ );
}
function createRoot(init) {
const owner = new Owner();
- return compute(
- owner,
- !init.length ? init : () => init(() => owner.dispose()),
- null,
- );
+ return compute(owner, !init.length ? init : () => init(() => owner.dispose()), null);
}
function runWithOwner(owner, run) {
try {
@@ -730,33 +787,4 @@ function catchError(fn, handler) {
}
}
-export {
- Computation2 as Computation,
- ContextNotFoundError,
- Effect,
- NoOwnerError,
- NotReadyError,
- Owner,
- RenderEffect,
- catchError,
- compute,
- createAsync,
- createContext,
- createEffect,
- createMemo,
- createRenderEffect,
- createRoot,
- createSignal,
- flushSync,
- getContext,
- getObserver,
- getOwner,
- hasContext,
- hasUpdated,
- isEqual,
- onCleanup,
- runWithOwner,
- setContext,
- setOwner,
- untrack,
-};
+export { Computation2 as Computation, ContextNotFoundError, NoOwnerError, NotReadyError, Owner, catchError, createAsync, createContext, createEffect, createMemo, createRenderEffect, createRoot, createSignal, flushSync, getContext, getObserver, getOwner, hasContext, hasUpdated, isEqual, isPending, latest, onCleanup, runWithOwner, setContext, untrack };
diff --git a/website/packages/solid-signals/2024-04-17/types/constants.d.ts b/website/packages/solid-signals/2024-11-02/types/core/constants.d.ts
similarity index 100%
rename from website/packages/solid-signals/2024-04-17/types/constants.d.ts
rename to website/packages/solid-signals/2024-11-02/types/core/constants.d.ts
diff --git a/website/packages/solid-signals/2024-10-28/types/core.d.ts b/website/packages/solid-signals/2024-11-02/types/core/core.d.ts
similarity index 91%
rename from website/packages/solid-signals/2024-10-28/types/core.d.ts
rename to website/packages/solid-signals/2024-11-02/types/core/core.d.ts
index c2554cf5a..0c11181b6 100644
--- a/website/packages/solid-signals/2024-10-28/types/core.d.ts
+++ b/website/packages/solid-signals/2024-11-02/types/core/core.d.ts
@@ -26,8 +26,8 @@
* 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';
+import { type Flags } from "./flags.js";
+import { Owner } from "./owner.js";
export interface SignalOptions {
name?: string;
equals?: ((prev: T, next: T) => boolean) | false;
@@ -58,7 +58,7 @@ export declare class Computation extends Owner implements SourceType, O
_sources: SourceType[] | null;
_observers: ObserverType[] | null;
_value: T | undefined;
- _compute: null | (() => T);
+ _compute: null | ((p?: T) => T);
_name: string | undefined;
_equals: false | ((a: T, b: T) => boolean);
_unobserved: (() => void) | undefined;
@@ -69,7 +69,7 @@ export declare class Computation extends Owner implements SourceType, O
_error: Computation | null;
_loading: Computation | null;
_time: number;
- constructor(initialValue: T | undefined, compute: null | (() => T), options?: SignalOptions);
+ constructor(initialValue: T | undefined, compute: null | ((p?: T) => T), options?: SignalOptions);
_read(): T;
/**
* Return the current value of this computation
@@ -138,7 +138,16 @@ export declare function isEqual(a: T, b: T): boolean;
* dependencies. Use `untrack` if you want to also disable owner tracking.
*/
export declare function untrack(fn: () => T): T;
-export declare function hasUpdated(fn: () => any): Boolean;
+/**
+ * Returns true if the given functinon contains signals that have been updated since the last time
+ * the parent computation was run.
+ */
+export declare function hasUpdated(fn: () => any): boolean;
+/**
+ * Returns true if the given function contains async signals that are not ready yet.
+ */
+export declare function isPending(fn: () => any): boolean;
+export declare function latest(fn: () => T): T | undefined;
/**
* 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.
diff --git a/website/packages/solid-signals/2024-10-28/types/effect.d.ts b/website/packages/solid-signals/2024-11-02/types/core/effect.d.ts
similarity index 94%
rename from website/packages/solid-signals/2024-10-28/types/effect.d.ts
rename to website/packages/solid-signals/2024-11-02/types/core/effect.d.ts
index 7e44c88cb..618740acf 100644
--- a/website/packages/solid-signals/2024-10-28/types/effect.d.ts
+++ b/website/packages/solid-signals/2024-11-02/types/core/effect.d.ts
@@ -1,4 +1,4 @@
-import { Computation, type SignalOptions } from './core';
+import { Computation, type SignalOptions } from "./core.js";
/**
* 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
diff --git a/website/packages/solid-signals/2024-04-17/types/error.d.ts b/website/packages/solid-signals/2024-11-02/types/core/error.d.ts
similarity index 100%
rename from website/packages/solid-signals/2024-04-17/types/error.d.ts
rename to website/packages/solid-signals/2024-11-02/types/core/error.d.ts
diff --git a/website/packages/solid-signals/2024-04-17/types/flags.d.ts b/website/packages/solid-signals/2024-11-02/types/core/flags.d.ts
similarity index 100%
rename from website/packages/solid-signals/2024-04-17/types/flags.d.ts
rename to website/packages/solid-signals/2024-11-02/types/core/flags.d.ts
diff --git a/website/packages/solid-signals/2024-11-02/types/core/index.d.ts b/website/packages/solid-signals/2024-11-02/types/core/index.d.ts
new file mode 100644
index 000000000..4a2fe21a3
--- /dev/null
+++ b/website/packages/solid-signals/2024-11-02/types/core/index.d.ts
@@ -0,0 +1,6 @@
+export { ContextNotFoundError, NoOwnerError, NotReadyError, type ErrorHandler } from "./error.js";
+export { Owner, createContext, getContext, setContext, hasContext, getOwner, onCleanup, type Context, type ContextRecord, type Disposable } from "./owner.js";
+export { Computation, EagerComputation, getObserver, isEqual, untrack, hasUpdated, isPending, latest, UNCHANGED, compute, type SignalOptions } from "./core.js";
+export { Effect, RenderEffect } from "./effect.js";
+export { flushSync } from "./scheduler.js";
+export * from "./flags.js";
diff --git a/website/packages/solid-signals/2024-04-17/types/owner.d.ts b/website/packages/solid-signals/2024-11-02/types/core/owner.d.ts
similarity index 98%
rename from website/packages/solid-signals/2024-04-17/types/owner.d.ts
rename to website/packages/solid-signals/2024-11-02/types/core/owner.d.ts
index 96e76dbe1..0d5371f56 100644
--- a/website/packages/solid-signals/2024-04-17/types/owner.d.ts
+++ b/website/packages/solid-signals/2024-11-02/types/core/owner.d.ts
@@ -27,7 +27,7 @@
*
* 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';
+import { type ErrorHandler } from "./error.js";
export type ContextRecord = Record;
export interface Disposable {
(): void;
diff --git a/website/packages/solid-signals/2024-10-28/types/scheduler.d.ts b/website/packages/solid-signals/2024-11-02/types/core/scheduler.d.ts
similarity index 79%
rename from website/packages/solid-signals/2024-10-28/types/scheduler.d.ts
rename to website/packages/solid-signals/2024-11-02/types/core/scheduler.d.ts
index 091a4feea..2ba7596b1 100644
--- a/website/packages/solid-signals/2024-10-28/types/scheduler.d.ts
+++ b/website/packages/solid-signals/2024-11-02/types/core/scheduler.d.ts
@@ -1,5 +1,5 @@
-import { Computation } from './core';
-import type { Effect, RenderEffect } from './effect';
+import type { Effect, RenderEffect } from "./effect.js";
+import { Computation } from "./core.js";
export declare let Computations: Computation[], RenderEffects: RenderEffect[], Effects: Effect[];
/**
* By default, changes are batched on the microtask queue which is an async process. You can flush
diff --git a/website/packages/solid-signals/2024-11-02/types/index.d.ts b/website/packages/solid-signals/2024-11-02/types/index.d.ts
new file mode 100644
index 000000000..ce1cb0c07
--- /dev/null
+++ b/website/packages/solid-signals/2024-11-02/types/index.d.ts
@@ -0,0 +1,4 @@
+export { Computation, ContextNotFoundError, NoOwnerError, NotReadyError, Owner, createContext, getContext, setContext, hasContext, getOwner, onCleanup, getObserver, isEqual, untrack, hasUpdated, isPending, latest } from "./core/index.js";
+export type { ErrorHandler, SignalOptions, Context, ContextRecord, Disposable } from "./core/index.js";
+export { flushSync } from "./core/scheduler.js";
+export * from "./signals.js";
diff --git a/website/packages/solid-signals/2024-10-28/types/map.d.ts b/website/packages/solid-signals/2024-11-02/types/map.d.ts
similarity index 91%
rename from website/packages/solid-signals/2024-10-28/types/map.d.ts
rename to website/packages/solid-signals/2024-11-02/types/map.d.ts
index b42a53237..d6a650658 100644
--- a/website/packages/solid-signals/2024-10-28/types/map.d.ts
+++ b/website/packages/solid-signals/2024-11-02/types/map.d.ts
@@ -1,4 +1,4 @@
-import type { Accessor } from './signals';
+import type { Accessor } from "./signals.js";
export type Maybe = T | void | null | undefined | false;
/**
* Reactive map helper that caches each list item by reference to reduce unnecessary mapping on
diff --git a/website/packages/solid-signals/2024-10-28/types/signals.d.ts b/website/packages/solid-signals/2024-11-02/types/signals.d.ts
similarity index 96%
rename from website/packages/solid-signals/2024-10-28/types/signals.d.ts
rename to website/packages/solid-signals/2024-11-02/types/signals.d.ts
index 3e706dcb5..206e5879e 100644
--- a/website/packages/solid-signals/2024-10-28/types/signals.d.ts
+++ b/website/packages/solid-signals/2024-11-02/types/signals.d.ts
@@ -1,5 +1,5 @@
-import type { SignalOptions } from './core';
-import { Owner } from './owner';
+import type { SignalOptions } from "./core/index.js";
+import { Owner } from "./core/index.js";
export interface Accessor {
(): T;
}
diff --git a/website/packages/solid-signals/2024-11-02/types/store/index.d.ts b/website/packages/solid-signals/2024-11-02/types/store/index.d.ts
new file mode 100644
index 000000000..d5a0b1b9d
--- /dev/null
+++ b/website/packages/solid-signals/2024-11-02/types/store/index.d.ts
@@ -0,0 +1 @@
+export * from "./store.js";
diff --git a/website/packages/solid-signals/2024-10-28/types/store.d.ts b/website/packages/solid-signals/2024-11-02/types/store/store.d.ts
similarity index 100%
rename from website/packages/solid-signals/2024-10-28/types/store.d.ts
rename to website/packages/solid-signals/2024-11-02/types/store/store.d.ts
diff --git a/website/packages/solid-signals/2024-04-17/types/utils.d.ts b/website/packages/solid-signals/2024-11-02/types/utils.d.ts
similarity index 100%
rename from website/packages/solid-signals/2024-04-17/types/utils.d.ts
rename to website/packages/solid-signals/2024-11-02/types/utils.d.ts
diff --git a/website/packages/solid-signals/2024-11-08/script.js b/website/packages/solid-signals/2024-11-08/script.js
new file mode 100644
index 000000000..445256f2e
--- /dev/null
+++ b/website/packages/solid-signals/2024-11-08/script.js
@@ -0,0 +1,779 @@
+// src/core/error.ts
+var NotReadyError = class extends Error {
+};
+var NoOwnerError = class extends Error {
+ constructor() {
+ super(
+ ""
+ );
+ }
+};
+var ContextNotFoundError = class extends Error {
+ constructor() {
+ super(
+ ""
+ );
+ }
+};
+
+// src/utils.ts
+function isUndefined(value) {
+ return typeof value === "undefined";
+}
+
+// src/core/constants.ts
+var STATE_CLEAN = 0;
+var STATE_CHECK = 1;
+var STATE_DIRTY = 2;
+var STATE_DISPOSED = 3;
+
+// src/core/owner.ts
+var currentOwner = null;
+var defaultContext = {};
+function getOwner() {
+ return currentOwner;
+}
+function setOwner(owner) {
+ const out = currentOwner;
+ currentOwner = owner;
+ return out;
+}
+var Owner = class {
+ // We flatten the owner tree into a linked list so that we don't need a pointer to .firstChild
+ // However, the children are actually added in reverse creation order
+ // See comment at the top of the file for an example of the _nextSibling traversal
+ k = null;
+ g = null;
+ j = null;
+ a = STATE_CLEAN;
+ e = null;
+ h = defaultContext;
+ f = null;
+ constructor(signal = false) {
+ if (currentOwner && !signal)
+ currentOwner.append(this);
+ }
+ append(child) {
+ child.k = this;
+ child.j = this;
+ if (this.g)
+ this.g.j = child;
+ child.g = this.g;
+ this.g = child;
+ if (child.h !== this.h) {
+ child.h = { ...this.h, ...child.h };
+ }
+ if (this.f) {
+ child.f = !child.f ? this.f : [...child.f, ...this.f];
+ }
+ }
+ dispose(self = true) {
+ if (this.a === STATE_DISPOSED)
+ return;
+ let head = self ? this.j || this.k : this, current = this.g, next = null;
+ while (current && current.k === this) {
+ current.dispose(true);
+ current.n();
+ next = current.g;
+ current.g = null;
+ current = next;
+ }
+ if (self)
+ this.n();
+ if (current)
+ current.j = !self ? this : this.j;
+ if (head)
+ head.g = current;
+ }
+ n() {
+ if (this.j)
+ this.j.g = null;
+ this.k = null;
+ this.j = null;
+ this.h = defaultContext;
+ this.f = null;
+ this.a = STATE_DISPOSED;
+ this.emptyDisposal();
+ }
+ emptyDisposal() {
+ if (!this.e)
+ return;
+ if (Array.isArray(this.e)) {
+ for (let i = 0; i < this.e.length; i++) {
+ const callable = this.e[i];
+ callable.call(callable);
+ }
+ } else {
+ this.e.call(this.e);
+ }
+ this.e = null;
+ }
+ handleError(error) {
+ if (!this.f)
+ throw error;
+ let i = 0, len = this.f.length;
+ for (i = 0; i < len; i++) {
+ try {
+ this.f[i](error);
+ break;
+ } catch (e) {
+ error = e;
+ }
+ }
+ if (i === len)
+ throw error;
+ }
+};
+function createContext(defaultValue, description) {
+ return { id: Symbol(description), defaultValue };
+}
+function getContext(context, owner = currentOwner) {
+ if (!owner) {
+ throw new NoOwnerError();
+ }
+ const value = hasContext(context, owner) ? owner.h[context.id] : context.defaultValue;
+ if (isUndefined(value)) {
+ throw new ContextNotFoundError();
+ }
+ return value;
+}
+function setContext(context, value, owner = currentOwner) {
+ if (!owner) {
+ throw new NoOwnerError();
+ }
+ owner.h = {
+ ...owner.h,
+ [context.id]: isUndefined(value) ? context.defaultValue : value
+ };
+}
+function hasContext(context, owner = currentOwner) {
+ return !isUndefined(owner?.h[context.id]);
+}
+function onCleanup(disposable) {
+ if (!currentOwner)
+ return;
+ const node = currentOwner;
+ if (!node.e) {
+ node.e = disposable;
+ } else if (Array.isArray(node.e)) {
+ node.e.push(disposable);
+ } else {
+ node.e = [node.e, disposable];
+ }
+}
+
+// src/core/flags.ts
+var ERROR_OFFSET = 0;
+var ERROR_BIT = 1 << ERROR_OFFSET;
+var LOADING_OFFSET = 1;
+var LOADING_BIT = 1 << LOADING_OFFSET;
+var DEFAULT_FLAGS = ERROR_BIT;
+
+// src/core/scheduler.ts
+var scheduled = false;
+var runningScheduled = false;
+var Computations = [];
+var RenderEffects = [];
+var Effects = [];
+function flushSync() {
+ if (!runningScheduled)
+ runScheduled();
+}
+function flushQueue() {
+ if (scheduled)
+ return;
+ scheduled = true;
+ queueMicrotask(runScheduled);
+}
+function runTop(node) {
+ const ancestors = [];
+ for (let current = node; current !== null; current = current.k) {
+ if (current.a !== STATE_CLEAN) {
+ ancestors.push(current);
+ }
+ }
+ for (let i = ancestors.length - 1; i >= 0; i--) {
+ if (ancestors[i].a !== STATE_DISPOSED)
+ ancestors[i].l();
+ }
+}
+function runScheduled() {
+ if (!Effects.length && !RenderEffects.length && !Computations.length) {
+ scheduled = false;
+ return;
+ }
+ runningScheduled = true;
+ try {
+ runPureQueue(Computations);
+ runPureQueue(RenderEffects);
+ runPureQueue(Effects);
+ } finally {
+ const renderEffects = RenderEffects;
+ const effects = Effects;
+ Computations = [];
+ Effects = [];
+ RenderEffects = [];
+ scheduled = false;
+ runningScheduled = false;
+ incrementClock();
+ runEffectQueue(renderEffects);
+ runEffectQueue(effects);
+ }
+}
+function runPureQueue(queue) {
+ for (let i = 0; i < queue.length; i++) {
+ if (queue[i].a !== STATE_CLEAN)
+ runTop(queue[i]);
+ }
+}
+function runEffectQueue(queue) {
+ for (let i = 0; i < queue.length; i++) {
+ if (queue[i].q && queue[i].a !== STATE_DISPOSED) {
+ queue[i].r(queue[i].d, queue[i].o);
+ queue[i].q = false;
+ queue[i].o = queue[i].d;
+ }
+ }
+}
+
+// src/core/core.ts
+var currentObserver = null;
+var currentMask = DEFAULT_FLAGS;
+var newSources = null;
+var newSourcesIndex = 0;
+var newFlags = 0;
+var clock = 0;
+var syncResolve = false;
+var updateCheck = null;
+function getObserver() {
+ return currentObserver;
+}
+function incrementClock() {
+ clock++;
+}
+var UNCHANGED = Symbol(0);
+var Computation2 = class extends Owner {
+ b = null;
+ c = null;
+ d;
+ s;
+ // Used in __DEV__ mode, hopefully removed in production
+ C;
+ // Using false is an optimization as an alternative to _equals: () => false
+ // which could enable more efficient DIRTY notification
+ t = isEqual;
+ y;
+ /** Whether the computation is an error or has ancestors that are unresolved */
+ i = 0;
+ /** Which flags raised by sources are handled, vs. being passed through. */
+ p = DEFAULT_FLAGS;
+ u = null;
+ v = null;
+ w = -1;
+ constructor(initialValue, compute2, options) {
+ super(compute2 === null);
+ this.s = compute2;
+ this.a = compute2 ? STATE_DIRTY : STATE_CLEAN;
+ this.d = initialValue;
+ if (options?.equals !== void 0)
+ this.t = options.equals;
+ if (options?.unobserved)
+ this.y = options?.unobserved;
+ }
+ z() {
+ if (this.s)
+ this.l();
+ if (!this.b || this.b.length)
+ track(this);
+ newFlags |= this.i & ~currentMask;
+ if (this.i & ERROR_BIT) {
+ throw this.d;
+ } else {
+ return this.d;
+ }
+ }
+ /**
+ * Return the current value of this computation
+ * Automatically re-executes the surrounding computation when the value changes
+ */
+ read() {
+ return this.z();
+ }
+ /**
+ * 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() {
+ if (!syncResolve && this.loading()) {
+ throw new NotReadyError();
+ }
+ return this.z();
+ }
+ /**
+ * 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() {
+ if (this.v === null) {
+ this.v = loadingState(this);
+ }
+ return this.v.read();
+ }
+ /**
+ * Return true if the computation is the computation threw an error
+ * Triggers re-execution of the computation when the error state changes
+ */
+ error() {
+ if (this.u === null) {
+ this.u = errorState(this);
+ }
+ return this.u.read();
+ }
+ /** Update the computation with a new value. */
+ write(value, flags = 0, raw = false) {
+ const newValue = !raw && typeof value === "function" ? value(this.d) : value;
+ const valueChanged = newValue !== UNCHANGED && (!!(flags & ERROR_BIT) || this.t === false || !this.t(this.d, newValue));
+ if (valueChanged)
+ this.d = newValue;
+ const changedFlagsMask = this.i ^ flags, changedFlags = changedFlagsMask & flags;
+ this.i = flags;
+ this.w = clock + 1;
+ if (this.c) {
+ for (let i = 0; i < this.c.length; i++) {
+ if (valueChanged) {
+ this.c[i].m(STATE_DIRTY);
+ } else if (changedFlagsMask) {
+ this.c[i].A(changedFlagsMask, changedFlags);
+ }
+ }
+ }
+ return this.d;
+ }
+ /**
+ * Set the current node's state, and recursively mark all of this node's observers as STATE_CHECK
+ */
+ m(state) {
+ if (this.a >= state)
+ return;
+ this.a = state;
+ if (this.c) {
+ for (let i = 0; i < this.c.length; i++) {
+ this.c[i].m(STATE_CHECK);
+ }
+ }
+ }
+ /**
+ * 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.
+ */
+ A(mask, newFlags2) {
+ if (this.a >= STATE_DIRTY)
+ return;
+ if (mask & this.p) {
+ this.m(STATE_DIRTY);
+ return;
+ }
+ if (this.a >= STATE_CHECK)
+ return;
+ const prevFlags = this.i & mask;
+ const deltaFlags = prevFlags ^ newFlags2;
+ if (newFlags2 === prevFlags) ; else if (deltaFlags & prevFlags & mask) {
+ this.m(STATE_CHECK);
+ } else {
+ this.i ^= deltaFlags;
+ if (this.c) {
+ for (let i = 0; i < this.c.length; i++) {
+ this.c[i].A(mask, newFlags2);
+ }
+ }
+ }
+ }
+ B(error) {
+ this.write(error, this.i | ERROR_BIT);
+ }
+ /**
+ * 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
+ */
+ l() {
+ if (this.a === STATE_DISPOSED) {
+ throw new Error("Tried to read a disposed computation");
+ }
+ if (this.a === STATE_CLEAN) {
+ return;
+ }
+ let observerFlags = 0;
+ if (this.a === STATE_CHECK) {
+ for (let i = 0; i < this.b.length; i++) {
+ this.b[i].l();
+ observerFlags |= this.b[i].i;
+ if (this.a === STATE_DIRTY) {
+ break;
+ }
+ }
+ }
+ if (this.a === STATE_DIRTY) {
+ update(this);
+ } else {
+ this.write(UNCHANGED, observerFlags);
+ this.a = STATE_CLEAN;
+ }
+ }
+ /**
+ * Remove ourselves from the owner graph and the computation graph
+ */
+ n() {
+ if (this.a === STATE_DISPOSED)
+ return;
+ if (this.b)
+ removeSourceObservers(this, 0);
+ super.n();
+ }
+};
+function loadingState(node) {
+ const prevOwner = setOwner(node.k);
+ const options = void 0;
+ const computation = new Computation2(
+ void 0,
+ () => {
+ track(node);
+ node.l();
+ return !!(node.i & LOADING_BIT);
+ },
+ options
+ );
+ computation.p = ERROR_BIT | LOADING_BIT;
+ setOwner(prevOwner);
+ return computation;
+}
+function errorState(node) {
+ const prevOwner = setOwner(node.k);
+ const options = void 0;
+ const computation = new Computation2(
+ void 0,
+ () => {
+ track(node);
+ node.l();
+ return !!(node.i & ERROR_BIT);
+ },
+ options
+ );
+ computation.p = ERROR_BIT;
+ setOwner(prevOwner);
+ return computation;
+}
+function track(computation) {
+ if (currentObserver) {
+ if (!newSources && currentObserver.b && currentObserver.b[newSourcesIndex] === computation) {
+ newSourcesIndex++;
+ } else if (!newSources)
+ newSources = [computation];
+ else if (computation !== newSources[newSources.length - 1]) {
+ newSources.push(computation);
+ }
+ if (updateCheck) {
+ updateCheck.d = computation.w > currentObserver.w;
+ }
+ }
+}
+function update(node) {
+ const prevSources = newSources, prevSourcesIndex = newSourcesIndex, prevFlags = newFlags;
+ newSources = null;
+ newSourcesIndex = 0;
+ newFlags = 0;
+ try {
+ node.dispose(false);
+ node.emptyDisposal();
+ const result = compute(node, node.s, node);
+ node.write(result, newFlags, true);
+ } catch (error) {
+ if (error instanceof NotReadyError) {
+ node.write(UNCHANGED, newFlags | LOADING_BIT);
+ } else {
+ node.B(error);
+ }
+ } finally {
+ if (newSources) {
+ if (node.b)
+ removeSourceObservers(node, newSourcesIndex);
+ if (node.b && newSourcesIndex > 0) {
+ node.b.length = newSourcesIndex + newSources.length;
+ for (let i = 0; i < newSources.length; i++) {
+ node.b[newSourcesIndex + i] = newSources[i];
+ }
+ } else {
+ node.b = newSources;
+ }
+ let source;
+ for (let i = newSourcesIndex; i < node.b.length; i++) {
+ source = node.b[i];
+ if (!source.c)
+ source.c = [node];
+ else
+ source.c.push(node);
+ }
+ } else if (node.b && newSourcesIndex < node.b.length) {
+ removeSourceObservers(node, newSourcesIndex);
+ node.b.length = newSourcesIndex;
+ }
+ newSources = prevSources;
+ newSourcesIndex = prevSourcesIndex;
+ newFlags = prevFlags;
+ node.a = STATE_CLEAN;
+ }
+}
+function removeSourceObservers(node, index) {
+ let source;
+ let swap;
+ for (let i = index; i < node.b.length; i++) {
+ source = node.b[i];
+ if (source.c) {
+ swap = source.c.indexOf(node);
+ source.c[swap] = source.c[source.c.length - 1];
+ source.c.pop();
+ if (!source.c.length)
+ source.y?.();
+ }
+ }
+}
+function isEqual(a, b) {
+ return a === b;
+}
+function untrack(fn) {
+ if (currentObserver === null)
+ return fn();
+ return compute(getOwner(), fn, null);
+}
+function hasUpdated(fn) {
+ const current = updateCheck;
+ updateCheck = { d: false };
+ try {
+ fn();
+ return updateCheck.d;
+ } finally {
+ updateCheck = current;
+ }
+}
+function isPending(fn) {
+ try {
+ fn();
+ return false;
+ } catch (e) {
+ return e instanceof NotReadyError;
+ }
+}
+function latest(fn) {
+ const prevFlags = newFlags;
+ syncResolve = true;
+ try {
+ return fn();
+ } catch {
+ } finally {
+ newFlags = prevFlags;
+ syncResolve = false;
+ }
+}
+function compute(owner, compute2, observer) {
+ const prevOwner = setOwner(owner), prevObserver = currentObserver, prevMask = currentMask;
+ currentObserver = observer;
+ currentMask = observer?.p ?? DEFAULT_FLAGS;
+ try {
+ return compute2(observer ? observer.d : void 0);
+ } finally {
+ setOwner(prevOwner);
+ currentObserver = prevObserver;
+ currentMask = prevMask;
+ }
+}
+var EagerComputation = class extends Computation2 {
+ constructor(initialValue, compute2, options) {
+ super(initialValue, compute2, options);
+ this.l();
+ Computations.push(this);
+ }
+ m(state) {
+ if (this.a >= state)
+ return;
+ if (this.a === STATE_CLEAN) {
+ Computations.push(this);
+ flushQueue();
+ }
+ super.m(state);
+ }
+};
+
+// src/core/effect.ts
+var USER_EFFECT = 0;
+var RENDER_EFFECT = 1;
+var Effect = class extends Computation2 {
+ r;
+ q = false;
+ o;
+ x;
+ constructor(initialValue, compute2, effect, options) {
+ super(initialValue, compute2, options);
+ this.r = effect;
+ this.o = initialValue;
+ this.l();
+ this.x = options?.render ? RENDER_EFFECT : USER_EFFECT;
+ (this.x ? RenderEffects : Effects).push(this);
+ }
+ write(value) {
+ if (value === UNCHANGED)
+ return this.d;
+ this.d = value;
+ this.q = true;
+ return value;
+ }
+ m(state) {
+ if (this.a >= state)
+ return;
+ if (this.a === STATE_CLEAN) {
+ (this.x ? RenderEffects : Effects).push(this);
+ flushQueue();
+ }
+ this.a = state;
+ }
+ B(error) {
+ this.handleError(error);
+ }
+ n() {
+ this.r = void 0;
+ this.o = void 0;
+ super.n();
+ }
+};
+
+// src/signals.ts
+function createSignal(first, second, third) {
+ if (typeof first === "function") {
+ const memo = createMemo((p) => {
+ const node2 = new Computation2(
+ first(p ? untrack(p[0]) : second),
+ null,
+ third
+ );
+ return [node2.read.bind(node2), node2.write.bind(node2)];
+ });
+ return [() => memo()[0](), (value) => memo()[1](value)];
+ }
+ const node = new Computation2(first, null, second);
+ return [node.read.bind(node), node.write.bind(node)];
+}
+function createAsync(fn, initial, options) {
+ const lhs = new EagerComputation(
+ {
+ d: initial
+ },
+ (p) => {
+ const value = p?.d;
+ const source = fn(value);
+ const isPromise = source instanceof Promise;
+ const iterator = source[Symbol.asyncIterator];
+ if (!isPromise && !iterator) {
+ return {
+ wait() {
+ return source;
+ },
+ d: source
+ };
+ }
+ const signal = new Computation2(value, null, options);
+ signal.write(UNCHANGED, LOADING_BIT);
+ if (isPromise) {
+ source.then(
+ (value2) => {
+ signal.write(value2, 0);
+ },
+ (error) => {
+ signal.write(error, ERROR_BIT);
+ }
+ );
+ } else {
+ let abort = false;
+ onCleanup(() => abort = true);
+ (async () => {
+ try {
+ for await (let value2 of source) {
+ if (abort)
+ return;
+ signal.write(value2, 0);
+ }
+ } catch (error) {
+ signal.write(error, ERROR_BIT);
+ }
+ })();
+ }
+ return signal;
+ }
+ );
+ return () => lhs.wait().wait();
+}
+function createMemo(compute2, initialValue, options) {
+ let node = new Computation2(
+ initialValue,
+ compute2,
+ options
+ );
+ let value;
+ return () => {
+ if (node) {
+ value = node.wait();
+ if (!node.b?.length)
+ node = void 0;
+ }
+ return value;
+ };
+}
+function createEffect(compute2, effect, initialValue, options) {
+ void new Effect(
+ initialValue,
+ compute2,
+ effect,
+ void 0
+ );
+}
+function createRenderEffect(compute2, effect, initialValue, options) {
+ void new Effect(initialValue, compute2, effect, {
+ render: true,
+ ...void 0
+ });
+}
+function createRoot(init) {
+ const owner = new Owner();
+ return compute(
+ owner,
+ !init.length ? init : () => init(() => owner.dispose()),
+ null
+ );
+}
+function runWithOwner(owner, run) {
+ try {
+ return compute(owner, run, null);
+ } catch (error) {
+ owner?.handleError(error);
+ return void 0;
+ }
+}
+function catchError(fn, handler) {
+ const owner = new Owner();
+ owner.f = owner.f ? [handler, ...owner.f] : [handler];
+ try {
+ compute(owner, fn, null);
+ } catch (error) {
+ owner.handleError(error);
+ }
+}
+
+export { Computation2 as Computation, ContextNotFoundError, NoOwnerError, NotReadyError, Owner, catchError, createAsync, createContext, createEffect, createMemo, createRenderEffect, createRoot, createSignal, flushSync, getContext, getObserver, getOwner, hasContext, hasUpdated, isEqual, isPending, latest, onCleanup, runWithOwner, setContext, untrack };
diff --git a/website/packages/solid-signals/2024-10-28/types/constants.d.ts b/website/packages/solid-signals/2024-11-08/types/core/constants.d.ts
similarity index 100%
rename from website/packages/solid-signals/2024-10-28/types/constants.d.ts
rename to website/packages/solid-signals/2024-11-08/types/core/constants.d.ts
diff --git a/website/packages/solid-signals/2024-04-17/types/core.d.ts b/website/packages/solid-signals/2024-11-08/types/core/core.d.ts
similarity index 86%
rename from website/packages/solid-signals/2024-04-17/types/core.d.ts
rename to website/packages/solid-signals/2024-11-08/types/core/core.d.ts
index fd1a586a9..0c11181b6 100644
--- a/website/packages/solid-signals/2024-04-17/types/core.d.ts
+++ b/website/packages/solid-signals/2024-11-08/types/core/core.d.ts
@@ -26,46 +26,50 @@
* 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';
+import { type Flags } from "./flags.js";
+import { Owner } from "./owner.js";
export interface SignalOptions {
name?: string;
equals?: ((prev: T, next: T) => boolean) | false;
-}
-export interface MemoOptions extends SignalOptions {
- initial?: T;
+ unobserved?: () => void;
}
interface SourceType {
_observers: ObserverType[] | null;
+ _unobserved?: () => void;
_updateIfNecessary: () => void;
_stateFlags: Flags;
+ _time: number;
}
interface ObserverType {
_sources: SourceType[] | null;
_notify: (state: number) => void;
_handlerMask: Flags;
_notifyFlags: (mask: Flags, newFlags: Flags) => void;
+ _time: number;
}
/**
* Returns the current observer.
*/
export declare function getObserver(): ObserverType | null;
+export declare function incrementClock(): void;
export declare const UNCHANGED: unique symbol;
export type UNCHANGED = typeof UNCHANGED;
export declare class Computation extends Owner implements SourceType, ObserverType {
_sources: SourceType[] | null;
_observers: ObserverType[] | null;
_value: T | undefined;
- _compute: null | (() => T);
+ _compute: null | ((p?: T) => T);
_name: string | undefined;
_equals: false | ((a: T, b: T) => boolean);
+ _unobserved: (() => void) | undefined;
/** 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 | null;
_loading: Computation | null;
- constructor(initialValue: T | undefined, compute: null | (() => T), options?: MemoOptions);
+ _time: number;
+ constructor(initialValue: T | undefined, compute: null | ((p?: T) => T), options?: SignalOptions);
_read(): T;
/**
* Return the current value of this computation
@@ -134,10 +138,24 @@ export declare function isEqual(a: T, b: T): boolean;
* dependencies. Use `untrack` if you want to also disable owner tracking.
*/
export declare function untrack(fn: () => T): T;
+/**
+ * Returns true if the given functinon contains signals that have been updated since the last time
+ * the parent computation was run.
+ */
+export declare function hasUpdated(fn: () => any): boolean;
+/**
+ * Returns true if the given function contains async signals that are not ready yet.
+ */
+export declare function isPending(fn: () => any): boolean;
+export declare function latest(fn: () => T): T | undefined;
/**
* 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(owner: Owner | null, compute: (val: T) => T, observer: Computation): T;
export declare function compute(owner: Owner | null, compute: (val: undefined) => T, observer: null): T;
+export declare class EagerComputation extends Computation {
+ constructor(initialValue: T, compute: () => T, options?: SignalOptions);
+ _notify(state: number): void;
+}
export {};
diff --git a/website/packages/solid-signals/2024-11-08/types/core/effect.d.ts b/website/packages/solid-signals/2024-11-08/types/core/effect.d.ts
new file mode 100644
index 000000000..49b8c73dd
--- /dev/null
+++ b/website/packages/solid-signals/2024-11-08/types/core/effect.d.ts
@@ -0,0 +1,19 @@
+import { Computation, type SignalOptions } from "./core.js";
+/**
+ * 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 extends Computation {
+ _effect: (val: T, prev: T | undefined) => void;
+ _modified: boolean;
+ _prevValue: T | undefined;
+ _type: 0 | 1;
+ constructor(initialValue: T, compute: () => T, effect: (val: T, prev: T | undefined) => void, options?: SignalOptions & {
+ render?: boolean;
+ });
+ write(value: T): T;
+ _notify(state: number): void;
+ _setError(error: unknown): void;
+ _disposeNode(): void;
+}
diff --git a/website/packages/solid-signals/2024-10-28/types/error.d.ts b/website/packages/solid-signals/2024-11-08/types/core/error.d.ts
similarity index 100%
rename from website/packages/solid-signals/2024-10-28/types/error.d.ts
rename to website/packages/solid-signals/2024-11-08/types/core/error.d.ts
diff --git a/website/packages/solid-signals/2024-10-28/types/flags.d.ts b/website/packages/solid-signals/2024-11-08/types/core/flags.d.ts
similarity index 100%
rename from website/packages/solid-signals/2024-10-28/types/flags.d.ts
rename to website/packages/solid-signals/2024-11-08/types/core/flags.d.ts
diff --git a/website/packages/solid-signals/2024-11-08/types/core/index.d.ts b/website/packages/solid-signals/2024-11-08/types/core/index.d.ts
new file mode 100644
index 000000000..74b746ec3
--- /dev/null
+++ b/website/packages/solid-signals/2024-11-08/types/core/index.d.ts
@@ -0,0 +1,6 @@
+export { ContextNotFoundError, NoOwnerError, NotReadyError, type ErrorHandler } from "./error.js";
+export { Owner, createContext, getContext, setContext, hasContext, getOwner, onCleanup, type Context, type ContextRecord, type Disposable } from "./owner.js";
+export { Computation, EagerComputation, getObserver, isEqual, untrack, hasUpdated, isPending, latest, UNCHANGED, compute, type SignalOptions } from "./core.js";
+export { Effect } from "./effect.js";
+export { flushSync } from "./scheduler.js";
+export * from "./flags.js";
diff --git a/website/packages/solid-signals/2024-10-28/types/owner.d.ts b/website/packages/solid-signals/2024-11-08/types/core/owner.d.ts
similarity index 98%
rename from website/packages/solid-signals/2024-10-28/types/owner.d.ts
rename to website/packages/solid-signals/2024-11-08/types/core/owner.d.ts
index 96e76dbe1..0d5371f56 100644
--- a/website/packages/solid-signals/2024-10-28/types/owner.d.ts
+++ b/website/packages/solid-signals/2024-11-08/types/core/owner.d.ts
@@ -27,7 +27,7 @@
*
* 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';
+import { type ErrorHandler } from "./error.js";
export type ContextRecord = Record;
export interface Disposable {
(): void;
diff --git a/website/packages/solid-signals/2024-11-08/types/core/scheduler.d.ts b/website/packages/solid-signals/2024-11-08/types/core/scheduler.d.ts
new file mode 100644
index 000000000..92fde85d2
--- /dev/null
+++ b/website/packages/solid-signals/2024-11-08/types/core/scheduler.d.ts
@@ -0,0 +1,9 @@
+import type { Effect } from "./effect.js";
+import { Computation } from "./core.js";
+export declare let Computations: Computation[], RenderEffects: Effect[], Effects: Effect[];
+/**
+ * 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;
+export declare function flushQueue(): void;
diff --git a/website/packages/solid-signals/2024-11-08/types/index.d.ts b/website/packages/solid-signals/2024-11-08/types/index.d.ts
new file mode 100644
index 000000000..ce1cb0c07
--- /dev/null
+++ b/website/packages/solid-signals/2024-11-08/types/index.d.ts
@@ -0,0 +1,4 @@
+export { Computation, ContextNotFoundError, NoOwnerError, NotReadyError, Owner, createContext, getContext, setContext, hasContext, getOwner, onCleanup, getObserver, isEqual, untrack, hasUpdated, isPending, latest } from "./core/index.js";
+export type { ErrorHandler, SignalOptions, Context, ContextRecord, Disposable } from "./core/index.js";
+export { flushSync } from "./core/scheduler.js";
+export * from "./signals.js";
diff --git a/website/packages/solid-signals/2024-11-08/types/map.d.ts b/website/packages/solid-signals/2024-11-08/types/map.d.ts
new file mode 100644
index 000000000..d6a650658
--- /dev/null
+++ b/website/packages/solid-signals/2024-11-08/types/map.d.ts
@@ -0,0 +1,12 @@
+import type { Accessor } from "./signals.js";
+export type Maybe = T | void | null | undefined | false;
+/**
+ * Reactive map helper that caches each list item by reference to reduce unnecessary mapping on
+ * updates.
+ *
+ * @see {@link https://github.com/solidjs/x-reactivity#maparray}
+ */
+export declare function mapArray- (list: Accessor
>, map: (value: Accessor- , index: Accessor
) => MappedItem, options?: {
+ keyed?: boolean | ((item: Item) => any);
+ name?: string;
+}): Accessor;
diff --git a/website/packages/solid-signals/2024-04-17/types/signals.d.ts b/website/packages/solid-signals/2024-11-08/types/signals.d.ts
similarity index 71%
rename from website/packages/solid-signals/2024-04-17/types/signals.d.ts
rename to website/packages/solid-signals/2024-11-08/types/signals.d.ts
index 60bbc8823..1b757a7d7 100644
--- a/website/packages/solid-signals/2024-04-17/types/signals.d.ts
+++ b/website/packages/solid-signals/2024-11-08/types/signals.d.ts
@@ -1,5 +1,5 @@
-import type { MemoOptions, SignalOptions } from './core';
-import { Owner } from './owner';
+import type { SignalOptions } from './core/index.js';
+import { Owner } from './core/index.js';
export interface Accessor {
(): T;
}
@@ -15,26 +15,27 @@ export type Signal = [read: Accessor, write: Setter];
* `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(initialValue: T, options?: SignalOptions): Signal;
-export declare function createAsync(fn: () => Promise, initial?: T, options?: SignalOptions): Accessor;
+export declare function createSignal(initialValue: Exclude, options?: SignalOptions): Signal;
+export declare function createSignal(fn: (prev?: T) => T, initialValue?: T, options?: SignalOptions): Signal;
+export declare function createAsync(fn: (prev?: T) => Promise | AsyncIterable | T, initial?: T, options?: SignalOptions): Accessor;
/**
* 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(compute: () => T, initialValue?: T, options?: MemoOptions): Accessor;
+export declare function createMemo(compute: (prev?: T) => T, initialValue?: T, options?: SignalOptions): Accessor;
/**
* 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(effect: () => T, initialValue?: T, options?: {
+export declare function createEffect(compute: () => T, effect: (v: T) => (() => void) | void, 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(compute: () => T, effect: (v: T) => T, initialValue?: T, options?: {
+export declare function createRenderEffect(compute: () => T, effect: (v: T) => (() => void) | void, initialValue?: T, options?: {
name?: string;
}): void;
/**
diff --git a/website/packages/solid-signals/2024-11-08/types/store/index.d.ts b/website/packages/solid-signals/2024-11-08/types/store/index.d.ts
new file mode 100644
index 000000000..d5a0b1b9d
--- /dev/null
+++ b/website/packages/solid-signals/2024-11-08/types/store/index.d.ts
@@ -0,0 +1 @@
+export * from "./store.js";
diff --git a/website/packages/solid-signals/2024-04-17/types/store.d.ts b/website/packages/solid-signals/2024-11-08/types/store/store.d.ts
similarity index 66%
rename from website/packages/solid-signals/2024-04-17/types/store.d.ts
rename to website/packages/solid-signals/2024-11-08/types/store/store.d.ts
index 727336238..4e05cd1d8 100644
--- a/website/packages/solid-signals/2024-04-17/types/store.d.ts
+++ b/website/packages/solid-signals/2024-11-08/types/store/store.d.ts
@@ -1,5 +1,7 @@
export type Store = Readonly;
export type StoreSetter = (fn: (state: T) => void) => void;
+declare const $TRACK: unique symbol, $PROXY: unique symbol;
+export { $PROXY, $TRACK };
export type StoreNode = Record;
export declare namespace SolidStore {
interface Unwrappable {
@@ -20,3 +22,10 @@ export declare function isWrappable(obj: T | NotWrappable): obj is T;
*/
export declare function unwrap(item: T, set?: Set): T;
export declare function createStore(store: T | Store): [get: Store, set: StoreSetter];
+export declare function createStore(fn: (store: T) => void, store: T | Store): [get: Store, set: StoreSetter];
+/**
+ * Creates a mutable derived value
+ *
+ * @see {@link https://github.com/solidjs/x-reactivity#createprojection}
+ */
+export declare function createProjection(fn: (draft: T) => void, initialValue: T): Readonly;
diff --git a/website/packages/solid-signals/2024-10-28/types/utils.d.ts b/website/packages/solid-signals/2024-11-08/types/utils.d.ts
similarity index 100%
rename from website/packages/solid-signals/2024-10-28/types/utils.d.ts
rename to website/packages/solid-signals/2024-11-08/types/utils.d.ts
diff --git a/website/scripts/chart.js b/website/scripts/chart.js
index 6eabf9014..7d3e8d363 100644
--- a/website/scripts/chart.js
+++ b/website/scripts/chart.js
@@ -372,12 +372,11 @@ export function init({
elements.legend.prepend(div);
- const { input, label, spanMain } = utils.dom.createComplexLabeledInput({
+ const { input, label } = utils.dom.createLabeledInput({
inputId: `legend-${series.title}`,
inputName: `selected-${series.title}${name}`,
inputValue: "value",
labelTitle: "Click to toggle",
- name: series.title,
onClick: (event) => {
event.preventDefault();
event.stopPropagation();
@@ -385,6 +384,14 @@ export function init({
series.active.set(input.checked);
},
});
+
+ const spanMain = window.document.createElement("span");
+ spanMain.classList.add("main");
+ label.append(spanMain);
+
+ const spanName = utils.dom.createSpanName(series.title);
+ spanMain.append(spanName);
+
div.append(label);
label.addEventListener("mouseover", () => {
const hovered = hoveredLegend();
@@ -492,8 +499,7 @@ export function init({
const anchor = window.document.createElement("a");
anchor.href = series.dataset.url;
- anchor.innerHTML = ` `;
- anchor.target = "_target";
+ anchor.target = "_blank";
anchor.rel = "noopener noreferrer";
div.append(anchor);
}
@@ -894,17 +900,17 @@ export function init({
});
});
}
- initGoToButtons(elements.timeScaleDateButtons);
- initGoToButtons(elements.timeScaleHeightButtons);
+ // initGoToButtons(elements.timeScaleDateButtons);
+ // initGoToButtons(elements.timeScaleHeightButtons);
- function createScaleButtonsToggleEffect() {
- const isDate = signals.createMemo(() => scale() === "date");
- signals.createEffect(isDate, (isDate) => {
- elements.timeScaleDateButtons.hidden = !isDate;
- elements.timeScaleHeightButtons.hidden = isDate;
- });
- }
- createScaleButtonsToggleEffect();
+ // function createScaleButtonsToggleEffect() {
+ // const isDate = signals.createMemo(() => scale() === "date");
+ // signals.createEffect(isDate, (isDate) => {
+ // elements.timeScaleDateButtons.hidden = !isDate;
+ // elements.timeScaleHeightButtons.hidden = isDate;
+ // });
+ // }
+ // createScaleButtonsToggleEffect();
}
initTimeScaleElement();
diff --git a/website/scripts/main.js b/website/scripts/main.js
index 582dd48b7..8baa0abd3 100644
--- a/website/scripts/main.js
+++ b/website/scripts/main.js
@@ -1,19 +1,19 @@
// @ts-check
/**
- * @import { Option, ResourceDataset, TimeScale, SerializedHistory, TimeRange, Unit, Marker, Weighted, DatasetPath, OHLC, FetchedJSON, DatasetValue, FetchedResult, AnyDatasetPath, SeriesBlueprint, BaselineSpecificSeriesBlueprint, CandlestickSpecificSeriesBlueprint, LineSpecificSeriesBlueprint, SpecificSeriesBlueprintWithChart, Signal, Color, SettingsTheme, DatasetCandlestickData, FoldersFilter, PartialChartOption, ChartOption, AnyPartialOption, ProcessedOptionAddons, OptionsTree, AnyPath, SimulationOption } from "./types/self"
+ * @import { Option, ResourceDataset, TimeScale, TimeRange, Unit, Marker, Weighted, DatasetPath, OHLC, FetchedJSON, DatasetValue, FetchedResult, AnyDatasetPath, SeriesBlueprint, BaselineSpecificSeriesBlueprint, CandlestickSpecificSeriesBlueprint, LineSpecificSeriesBlueprint, SpecificSeriesBlueprintWithChart, Signal, Color, DatasetCandlestickData, PartialChartOption, ChartOption, AnyPartialOption, ProcessedOptionAddons, OptionsTree, AnyPath, SimulationOption } from "./types/self"
* @import {createChart as CreateClassicChart, createChartEx as CreateCustomChart, LineStyleOptions} from "../packages/lightweight-charts/v4.2.0/types";
* @import * as _ from "../packages/ufuzzy/v1.0.14/types"
* @import { DeepPartial, ChartOptions, IChartApi, IHorzScaleBehavior, WhitespaceData, SingleValueData, ISeriesApi, Time, LogicalRange, SeriesMarker, CandlestickData, SeriesType, BaselineStyleOptions, SeriesOptionsCommon } from "../packages/lightweight-charts/v4.2.0/types"
* @import { DatePath, HeightPath, LastPath } from "./types/paths";
- * @import { SignalOptions } from "../packages/solid-signals/2024-11-01/types/core/core"
- * @import { getOwner as GetOwner, onCleanup as OnCleanup, Owner } from "../packages/solid-signals/2024-11-01/types/core/owner"
- * @import { createSignal as CreateSignal, createEffect as CreateEffect, Accessor, Setter, createMemo as CreateMemo, createRoot as CreateRoot, runWithOwner as RunWithOwner } from "../packages/solid-signals/2024-11-01/types/signals";
+ * @import { SignalOptions } from "../packages/solid-signals/2024-11-02/types/core/core"
+ * @import { getOwner as GetOwner, onCleanup as OnCleanup, Owner } from "../packages/solid-signals/2024-11-02/types/core/owner"
+ * @import { createSignal as CreateSignal, createEffect as CreateEffect, Accessor, Setter, createMemo as CreateMemo, createRoot as CreateRoot, runWithOwner as RunWithOwner } from "../packages/solid-signals/2024-11-02/types/signals";
*/
function initPackages() {
async function importSignals() {
- return import("../packages/solid-signals/2024-11-01/script.js").then(
+ return import("../packages/solid-signals/2024-11-02/script.js").then(
(_signals) => {
const signals = {
createSolidSignal: /** @type {CreateSignal} */ (
@@ -227,7 +227,7 @@ function initPackages() {
autoSize: true,
layout: {
fontFamily: "Satoshi Chart",
- // fontSize: 13,
+ fontSize: 13,
background: { color: "transparent" },
attributionLogo: false,
},
@@ -640,22 +640,6 @@ const utils = {
yield() {
return this.sleep(0);
},
- array: {
- /**
- * @template T
- * @param {T[]} array
- */
- getRandomIndex(array) {
- return Math.floor(Math.random() * array.length);
- },
- /**
- * @template T
- * @param {T[]} array
- */
- getRandomElement(array) {
- return array[this.getRandomIndex(array)];
- },
- },
dom: {
/**
* @param {string} id
@@ -724,6 +708,52 @@ const utils = {
return spanName;
},
+ /**
+ * @param {Object} arg
+ * @param {string} arg.href
+ * @param {string} [arg.text]
+ * @param {boolean} [arg.blank]
+ * @param {VoidFunction} [arg.onClick]
+ * @param {boolean} [arg.preventDefault]
+ */
+ createAnchorElement({ text, href, blank, onClick, preventDefault }) {
+ const anchor = window.document.createElement("a");
+ anchor.href = href;
+
+ if (text) {
+ anchor.innerText = text;
+ }
+
+ if (blank) {
+ anchor.target = "_blank";
+ anchor.rel = "noopener noreferrer";
+ }
+
+ if (onClick || preventDefault) {
+ if (onClick) {
+ anchor.addEventListener("click", (event) => {
+ event.preventDefault();
+ onClick();
+ });
+ }
+ }
+
+ return anchor;
+ },
+ /**
+ * @param {Object} arg
+ * @param {string} arg.text
+ * @param {VoidFunction} arg.onClick
+ */
+ createButtonElement({ text, onClick }) {
+ const button = window.document.createElement("button");
+
+ button.innerHTML = text;
+
+ button.addEventListener("click", onClick);
+
+ return button;
+ },
/**
* @param {Object} args
* @param {string} args.inputName
@@ -765,70 +795,6 @@ const utils = {
input,
};
},
- /**
- * @param {Object} args
- * @param {string} args.name
- * @param {string} args.inputName
- * @param {string} args.inputId
- * @param {string} args.inputValue
- * @param {string} args.labelTitle
- * @param {string} [args.href]
- * @param {(event: MouseEvent) => void} args.onClick
- */
- createComplexLabeledInput({
- inputId,
- inputName,
- inputValue,
- labelTitle,
- name,
- onClick,
- href,
- }) {
- const { label, input } = this.createLabeledInput({
- inputId,
- inputName,
- inputValue,
- labelTitle,
- onClick,
- });
-
- const spanMain = window.document.createElement("span");
- spanMain.classList.add("main");
- label.append(spanMain);
-
- const spanName = this.createSpanName(name);
-
- if (href) {
- const anchor = window.document.createElement("a");
- anchor.href = href;
- anchor.append(spanName);
- spanMain.append(anchor);
-
- if (href.includes(".")) {
- anchor.target = "_target";
- anchor.rel = "noopener noreferrer";
-
- anchor.addEventListener("click", (event) => {
- event.stopPropagation();
- // event.preventDefault();
- });
- } else {
- anchor.addEventListener("click", (event) => {
- // event.stopPropagation();
- event.preventDefault();
- });
- }
- } else {
- spanMain.append(spanName);
- }
-
- return {
- label,
- input,
- spanMain,
- spanName,
- };
- },
/**
* @param {HTMLElement} parent
* @param {HTMLElement} child
@@ -1322,8 +1288,7 @@ const consts = createConstants();
const ids = /** @type {const} */ ({
selectedId: `selected-id`,
- selectedFrameSelectorLabel: `selected-frame-selector-label`,
- foldersFilter: "folders-filter",
+ asideSelectorLabel: `aside-selector-label`,
chartRange: "chart-range",
from: "from",
to: "to",
@@ -1348,15 +1313,13 @@ const elements = {
body: window.document.body,
main: utils.dom.getElementById("main"),
aside: utils.dom.getElementById("aside"),
- selectedLabel: utils.dom.getElementById(ids.selectedFrameSelectorLabel),
- foldersLabel: utils.dom.getElementById(`folders-frame-selector-label`),
- searchLabel: utils.dom.getElementById(`search-frame-selector-label`),
- searchFrame: utils.dom.getElementById("search-frame"),
- historyFrame: utils.dom.getElementById("history-frame"),
- settingsFrame: utils.dom.getElementById("settings-frame"),
- foldersFrame: utils.dom.getElementById("folders-frame"),
+ asideLabel: utils.dom.getElementById(ids.asideSelectorLabel),
+ navLabel: utils.dom.getElementById(`nav-selector-label`),
+ searchLabel: utils.dom.getElementById(`search-selector-label`),
+ search: utils.dom.getElementById("search"),
+ nav: utils.dom.getElementById("nav"),
+ navHeader: utils.dom.getElementById("nav-header"),
selectedFrame: utils.dom.getElementById("selected-frame"),
- historyList: utils.dom.getElementById("history-list"),
searchInput: /** @type {HTMLInputElement} */ (
utils.dom.getElementById("search-input")
),
@@ -1365,38 +1328,24 @@ const elements = {
selectedTitle: utils.dom.getElementById("selected-title"),
selectedDescription: utils.dom.getElementById("selected-description"),
selectors: utils.dom.getElementById("frame-selectors"),
- foldersFilterAllCount: utils.dom.getElementById("folders-filter-all-count"),
- foldersFilterFavoritesCount: utils.dom.getElementById(
- "folders-filter-favorites-count",
- ),
- foldersFilterNewCount: utils.dom.getElementById("folders-filter-new-count"),
chartList: utils.dom.getElementById("chart-list"),
legend: utils.dom.getElementById("legend"),
style: getComputedStyle(window.document.documentElement),
- buttonFavorite: utils.dom.getElementById("button-favorite"),
- timeScaleDateButtons: utils.dom.getElementById("timescale-date-buttons"),
- timeScaleHeightButtons: utils.dom.getElementById("timescale-height-buttons"),
+ // timeScaleDateButtons: utils.dom.getElementById("timescale-date-buttons"),
+ // timeScaleHeightButtons: utils.dom.getElementById("timescale-height-buttons"),
selectedHeader: utils.dom.getElementById("selected-header"),
- selectedHr: utils.dom.getElementById("selected-hr"),
- home: utils.dom.getElementById("home"),
charts: utils.dom.getElementById("charts"),
simulation: utils.dom.getElementById("simulation"),
};
/** @typedef {typeof elements} Elements */
-const savedSelectedId = localStorage.getItem(ids.selectedId);
-const isFirstTime = !savedSelectedId;
const urlSelected = utils.url.pathnameToSelectedId();
function initFrameSelectors() {
- let selectedFrameLabel = localStorage.getItem(ids.checkedFrameSelectorLabel);
-
- const selectors = elements.selectors;
-
- const children = Array.from(selectors.children);
+ const children = Array.from(elements.selectors.children);
/** @type {HTMLElement | undefined} */
- let focusedSection = undefined;
+ let focusedFrame = undefined;
for (let i = 0; i < children.length; i++) {
const element = children[i];
@@ -1404,66 +1353,70 @@ function initFrameSelectors() {
switch (element.tagName) {
case "LABEL": {
element.addEventListener("click", () => {
- const id = element.id;
+ const inputId = element.getAttribute("for");
- selectedFrameLabel = id;
- localStorage.setItem(ids.checkedFrameSelectorLabel, id);
-
- const sectionId = element.id.split("-").splice(0, 2).join("-"); // Remove -selector
-
- const section = window.document.getElementById(sectionId);
-
- if (!section) {
- console.log(sectionId, section);
- throw "Section should exist";
+ if (!inputId) {
+ console.log(element, element.getAttribute("for"));
+ throw "Input id in label not found";
}
- if (section === focusedSection) {
+ const input = window.document.getElementById(inputId);
+
+ if (!input || !("value" in input)) {
+ throw "Not input or no value";
+ }
+
+ const frame = window.document.getElementById(
+ /** @type {string} */ (input.value),
+ );
+
+ if (!frame) {
+ console.log(input.value);
+ throw "Frame element doesn't exist";
+ }
+
+ if (frame === focusedFrame) {
return;
}
- section.hidden = false;
- if (focusedSection) {
- focusedSection.hidden = true;
+ frame.hidden = false;
+ if (focusedFrame) {
+ focusedFrame.hidden = true;
}
- focusedSection = section;
+ focusedFrame = frame;
});
break;
}
}
}
- if (selectedFrameLabel && (!urlSelected || urlSelected === savedSelectedId)) {
- const frameLabel = window.document.getElementById(selectedFrameLabel);
- if (!frameLabel) throw "Frame should exist";
- frameLabel.click();
- } else {
- elements.selectedLabel.click();
- }
+ elements.asideLabel.click();
- // When going from mobile view to desktop view, if selected frame was open, go to the folders frame
+ // When going from mobile view to desktop view, if selected frame was open, go to the nav frame
new IntersectionObserver((entries) => {
for (let i = 0; i < entries.length; i++) {
if (
!entries[i].isIntersecting &&
- entries[i].target === elements.selectedLabel &&
- selectedFrameLabel === ids.selectedFrameSelectorLabel
+ entries[i].target === elements.asideLabel &&
+ focusedFrame == elements.aside
) {
- elements.foldersLabel.click();
+ elements.navLabel.click();
}
}
- }).observe(elements.selectedLabel);
+ }).observe(elements.asideLabel);
- function setSelectedFrameParent() {
+ function setAsideParent() {
const { clientWidth } = window.document.documentElement;
if (clientWidth >= consts.MEDIUM_WIDTH) {
- elements.aside.append(elements.selectedFrame);
+ elements.body.append(elements.aside);
} else {
- elements.main.append(elements.selectedFrame);
+ elements.main.append(elements.aside);
}
}
- setSelectedFrameParent();
- window.addEventListener("resize", setSelectedFrameParent);
+
+ setAsideParent();
+
+ window.addEventListener("resize", setAsideParent);
}
initFrameSelectors();
@@ -1473,7 +1426,7 @@ function createKeyDownEventListener() {
case "Escape": {
event.stopPropagation();
event.preventDefault();
- elements.foldersLabel.click();
+ elements.navLabel.click();
break;
}
case "/": {
@@ -1578,14 +1531,21 @@ function createColors(dark) {
return dark() ? tailwindRose900 : tailwindRose100;
}
+ /**
+ * @param {string} property
+ */
+ function getLightDarkValue(property) {
+ const value = elements.style.getPropertyValue(property);
+ const [light, _dark] = value.slice(11, -1).split(", ");
+ return dark() ? _dark : light;
+ }
+
function off() {
- const _ = dark();
- return elements.style.getPropertyValue("--off-color");
+ return getLightDarkValue("--off-color");
}
function textColor() {
- const _ = dark();
- return elements.style.getPropertyValue("--color");
+ return getLightDarkValue("--color");
}
return {
@@ -2200,7 +2160,22 @@ function initWebSockets(signals) {
packages.signals().then((signals) =>
options.then(({ initOptions }) => {
- const dark = signals.createSignal(true);
+ function initDark() {
+ const preferredColorSchemeMatchMedia = window.matchMedia(
+ "(prefers-color-scheme: dark)",
+ );
+ const dark = signals.createSignal(preferredColorSchemeMatchMedia.matches);
+ preferredColorSchemeMatchMedia.addEventListener(
+ "change",
+ ({ matches }) => {
+ dark.set(matches);
+ },
+ );
+ return dark;
+ }
+ const dark = initDark();
+
+ const qrcode = signals.createSignal(/** @type {string | null} */ (null));
function createLastHeightResource() {
const lastHeight = signals.createSignal(0);
@@ -2253,6 +2228,7 @@ packages.signals().then((signals) =>
signals,
utils,
webSockets,
+ qrcode,
});
function initSelected() {
@@ -2288,7 +2264,6 @@ packages.signals().then((signals) =>
const hideTop = option.kind === "home" || option.kind === "pdf";
elements.selectedHeader.hidden = hideTop;
- elements.selectedHr.hidden = hideTop;
elements.selectedTitle.innerHTML = option.title;
elements.selectedDescription.innerHTML = option.serializedPath;
@@ -2297,10 +2272,10 @@ packages.signals().then((signals) =>
let element;
switch (option.kind) {
- case "home": {
- element = elements.home;
- break;
- }
+ // case "home": {
+ // element = elements.home;
+ // break;
+ // }
case "chart": {
element = elements.charts;
@@ -2382,88 +2357,13 @@ packages.signals().then((signals) =>
});
}
createApplyOptionEffect();
-
- function initFavoriteButton() {
- elements.buttonFavorite.addEventListener("click", () => {
- const option = options.selected();
-
- option.isFavorite.set((f) => {
- const newState = !f;
-
- const localStorageKey = options.optionToFavoriteKey(option);
- if (newState) {
- localStorage.setItem(localStorageKey, "1");
- } else {
- localStorage.removeItem(localStorageKey);
- }
-
- return newState;
- });
- });
-
- signals.createEffect(
- () => options.selected().isFavorite(),
- (isFavorite) => {
- if (isFavorite) {
- elements.buttonFavorite.dataset.highlight = "";
- } else {
- delete elements.buttonFavorite.dataset.highlight;
- }
- },
- );
- }
- initFavoriteButton();
-
- function initShareButton() {
- const shareDiv = utils.dom.getElementById("share-div");
- const shareContentDiv = utils.dom.getElementById("share-content-div");
-
- shareDiv.addEventListener("click", () => {
- shareDiv.hidden = true;
- });
-
- shareContentDiv.addEventListener("click", (event) => {
- event.stopPropagation();
- event.preventDefault();
- });
-
- packages.leanQr().then(({ generate }) => {
- const imgQrcode = /** @type {HTMLImageElement} */ (
- utils.dom.getElementById("share-img")
- );
-
- const anchor = /** @type {HTMLAnchorElement} */ (
- utils.dom.getElementById("share-anchor")
- );
-
- utils.dom
- .getElementById("button-share")
- .addEventListener("click", () => {
- const href = window.location.href;
- anchor.href = href;
- anchor.innerHTML = href;
-
- const qrcode = generate(
- /** @type {any} */ (window.document.location.href),
- )?.toDataURL({
- // @ts-ignore
- padX: 0,
- padY: 0,
- });
- imgQrcode.src = qrcode || "";
-
- shareDiv.hidden = false;
- });
- });
- }
- initShareButton();
}
function createMobileSwitchEffect() {
let firstRun = true;
signals.createEffect(options.selected, () => {
- if (!firstRun && !utils.dom.isHidden(elements.selectedLabel)) {
- elements.selectedLabel.click();
+ if (!firstRun && !utils.dom.isHidden(elements.asideLabel)) {
+ elements.asideLabel.click();
}
firstRun = false;
});
@@ -2474,90 +2374,65 @@ packages.signals().then((signals) =>
}
initSelected();
+ function initShare() {
+ const shareDiv = utils.dom.getElementById("share-div");
+ const shareContentDiv = utils.dom.getElementById("share-content-div");
+
+ shareDiv.addEventListener("click", () => {
+ qrcode.set(null);
+ });
+
+ shareContentDiv.addEventListener("click", (event) => {
+ event.stopPropagation();
+ event.preventDefault();
+ });
+
+ packages.leanQr().then(({ generate }) => {
+ const imgQrcode = /** @type {HTMLImageElement} */ (
+ utils.dom.getElementById("share-img")
+ );
+
+ const anchor = /** @type {HTMLAnchorElement} */ (
+ utils.dom.getElementById("share-anchor")
+ );
+
+ signals.createEffect(qrcode, (qrcode) => {
+ if (!qrcode) {
+ shareDiv.hidden = true;
+ return;
+ }
+
+ const href = qrcode;
+ anchor.href = href;
+ anchor.innerText =
+ (href.startsWith("http")
+ ? href.split("//").at(-1)
+ : href.split(":").at(-1)) || "";
+
+ imgQrcode.src =
+ generate(/** @type {any} */ (href))?.toDataURL({
+ // @ts-ignore
+ padX: 0,
+ padY: 0,
+ }) || "";
+
+ shareDiv.hidden = false;
+ });
+ });
+ }
+ initShare();
+
function initFolders() {
function initTreeElement() {
options.treeElement.set(() => {
const treeElement = window.document.createElement("div");
treeElement.classList.add("tree");
- elements.foldersFrame.append(treeElement);
+ elements.navHeader.after(treeElement);
return treeElement;
});
}
- function createCountersDomUpdateEffect() {
- elements.foldersFilterAllCount.innerHTML =
- options.list.length.toLocaleString();
-
- signals.createEffect(options.counters.favorites, (counterFavorites) => {
- elements.foldersFilterFavoritesCount.innerHTML =
- counterFavorites.toLocaleString();
- });
-
- signals.createEffect(options.counters.new, (counterNew) => {
- elements.foldersFilterNewCount.innerHTML =
- counterNew.toLocaleString();
- });
- }
-
- function initFilters() {
- const filterAllInput = /** @type {HTMLInputElement} */ (
- utils.dom.getElementById("folders-filter-all")
- );
- const filterFavoritesInput = /** @type {HTMLInputElement} */ (
- utils.dom.getElementById("folders-filter-favorites")
- );
- const filterNewInput = /** @type {HTMLInputElement} */ (
- utils.dom.getElementById("folders-filter-new")
- );
-
- filterAllInput.addEventListener("change", () => {
- options.filter.set("all");
- });
- filterFavoritesInput.addEventListener("change", () => {
- options.filter.set("favorites");
- });
- filterNewInput.addEventListener("change", () => {
- options.filter.set("new");
- });
-
- signals.createEffect(options.filter, (f) => {
- localStorage.setItem(ids.foldersFilter, f);
- switch (f) {
- case "all": {
- filterAllInput.checked = true;
- break;
- }
- case "favorites": {
- filterFavoritesInput.checked = true;
- break;
- }
- case "new": {
- filterNewInput.checked = true;
- break;
- }
- }
- });
- }
-
- function initCloseAllButton() {
- utils.dom
- .getElementById("button-close-all-folders")
- .addEventListener("click", () => {
- options.details.forEach((details) => (details.open = false));
- });
- }
-
- function initScrollToSelectedButton() {
- utils.dom
- .getElementById("scroll-go-to-selected")
- .addEventListener("click", () => {
- scrollToSelected();
- });
- }
-
async function scrollToSelected() {
- options.filter.set("all");
-
if (!options.selected()) throw "Selected should be set by now";
const selectedId = options.selected().id;
@@ -2579,59 +2454,23 @@ packages.signals().then((signals) =>
await utils.yield();
- utils.dom
- .getElementById(`${selectedId}-folders-selector`)
- .scrollIntoView({
- behavior: "instant",
- block: "center",
- });
+ utils.dom.getElementById(`${selectedId}-nav-selector`).scrollIntoView({
+ behavior: "instant",
+ block: "center",
+ });
}
- utils.dom.onFirstIntersection(elements.foldersFrame, () => {
- console.log("folders: init");
+ utils.dom.onFirstIntersection(elements.nav, () => {
+ console.log("nav: init");
initTreeElement();
- createCountersDomUpdateEffect();
- initFilters();
- initCloseAllButton();
- initScrollToSelectedButton();
- if (isFirstTime) {
- scrollToSelected();
- }
+ scrollToSelected();
});
}
initFolders();
function initSearch() {
- function initNoInputButton() {
- utils.dom
- .getElementById("search-no-input-text-button")
- .addEventListener("click", () => {
- options.selected.set(utils.array.getRandomElement(options.list));
- });
- }
-
- /**
- * @param {string} [value = '']
- */
- function setInputValue(value = "") {
- elements.searchInput.focus();
- elements.searchInput.value = value;
- elements.searchInput.dispatchEvent(new Event("input"));
- }
-
- function initResetSearchButton() {
- const resetSearchButton = utils.dom.getElementById("reset-search");
- resetSearchButton.addEventListener("click", () => {
- setInputValue();
- });
- }
-
function initSearchFrame() {
console.log("search: init");
- initNoInputButton();
- initResetSearchButton();
-
- const localStorageSearchKey = "search";
const haystack = options.list.map(
(option) => `${option.title}\t${option.serializedPath}`,
@@ -2662,35 +2501,16 @@ packages.signals().then((signals) =>
list = Array(maxIndex - minIndex + 1);
- if (info && order) {
- for (let i = minIndex; i <= maxIndex; i++) {
- let infoIdx = order[i];
+ for (let i = minIndex; i <= maxIndex; i++) {
+ let index = indexes[i];
- const [title, path] = ufuzzy
- .highlight(
- haystack[info.idx[infoIdx]],
- info.ranges[infoIdx],
- )
- .split("\t");
+ const [title, path] = haystack[index].split("\t");
- list[i % 100] = {
- option: options.list[info.idx[infoIdx]],
- path,
- title,
- };
- }
- } else {
- for (let i = minIndex; i <= maxIndex; i++) {
- let index = indexes[i];
-
- const [title, path] = haystack[index].split("\t");
-
- list[i % 100] = {
- option: options.list[index],
- path,
- title,
- };
- }
+ list[i % 100] = {
+ option: options.list[index],
+ path,
+ title,
+ };
}
}
@@ -2731,8 +2551,6 @@ packages.signals().then((signals) =>
signals.createRoot((_dispose) => {
const needle = /** @type {string} */ (elements.searchInput.value);
- utils.storage.write(localStorageSearchKey, needle);
-
dispose?.();
dispose = _dispose;
@@ -2813,14 +2631,17 @@ packages.signals().then((signals) =>
const li = window.document.createElement("li");
elements.searchResults.appendChild(li);
- const label = options.createOptionLabeledInput({
+ const element = options.createOptionElement({
option,
frame: "search",
name: title,
top: path,
+ qrcode,
});
- li.append(label);
+ if (element) {
+ li.append(element);
+ }
});
});
}
@@ -2831,513 +2652,11 @@ packages.signals().then((signals) =>
elements.searchInput.addEventListener("input", inputEvent);
});
-
- setInputValue(localStorage.getItem(localStorageSearchKey) || "");
}
- utils.dom.onFirstIntersection(elements.searchFrame, initSearchFrame);
+ utils.dom.onFirstIntersection(elements.search, initSearchFrame);
}
initSearch();
- function initHistory() {
- const LOCAL_STORAGE_HISTORY_KEY = "history";
- const MAX_HISTORY_LENGTH = 1_000;
-
- const history = /** @type {SerializedHistory} */ (
- JSON.parse(localStorage.getItem(LOCAL_STORAGE_HISTORY_KEY) || "[]")
- ).flatMap(([optionId, timestamp]) => {
- const option = options.list.find((option) => option.id === optionId);
- return option ? [{ option, date: new Date(timestamp) }] : [];
- });
-
- /** @param {Date} date */
- function dateToTestedString(date) {
- return date.toLocaleString().split(",")[0];
- }
-
- function createUnshiftHistoryEffect() {
- signals.createEffect(options.selected, (option) => {
- const head = history.at(0);
- if (
- head &&
- head.option === option &&
- dateToTestedString(new Date()) === dateToTestedString(head.date)
- ) {
- return;
- }
-
- history.unshift({
- date: new Date(),
- option,
- });
-
- utils.runWhenIdle(() => {
- /** @type {SerializedHistory} */
- const serializedHistory = history.map(({ option, date }) => [
- option.id,
- date.getTime(),
- ]);
-
- if (serializedHistory.length > MAX_HISTORY_LENGTH) {
- serializedHistory.length = MAX_HISTORY_LENGTH;
- }
-
- const jsonHistory = JSON.stringify(serializedHistory);
-
- localStorage.setItem(LOCAL_STORAGE_HISTORY_KEY, jsonHistory);
- });
- });
- }
- createUnshiftHistoryEffect();
-
- function initHistoryFrame() {
- console.log("history: init");
-
- const owner = signals.getOwner();
-
- /** @param {Date} date */
- function dateToDisplayedString(date) {
- const formattedDate = dateToTestedString(date);
-
- const now = new Date();
- if (dateToTestedString(now) === formattedDate) {
- return "Today";
- }
-
- now.setUTCDate(now.getUTCDate() - 1);
-
- if (dateToTestedString(now) === formattedDate) {
- return "Yesterday";
- }
-
- return date.toLocaleDateString(undefined, {
- weekday: "long",
- year: "numeric",
- month: "long",
- day: "numeric",
- });
- }
-
- const grouped = history.reduce((grouped, { option, date }) => {
- grouped[dateToTestedString(date)] ||= [];
- grouped[dateToTestedString(date)].push({ option, date });
- return grouped;
- }, /** @type {Record} */ ({}));
-
- /** @type {[string|undefined, string|undefined]} */
- const firstTwo = [undefined, undefined];
-
- function initHistoryListInDom() {
- Object.entries(grouped).forEach(([key, tuples], index) => {
- if (index < 2) {
- firstTwo[index] = key;
- }
-
- const heading = window.document.createElement("h4");
- heading.id = key;
- heading.innerHTML = dateToDisplayedString(tuples[0].date);
- elements.historyList.append(heading);
-
- tuples.forEach(({ option, date }) => {
- elements.historyList.append(
- options.createOptionLabeledInput({
- option,
- frame: "history",
- name: option.title,
- id: date.valueOf().toString(),
- top: date.toLocaleTimeString(),
- owner,
- }),
- );
- });
- });
- }
- initHistoryListInDom();
-
- function createUpdateHistoryEffect() {
- signals.createEffect(options.selected, (option) => {
- const date = new Date();
- const testedString = dateToTestedString(date);
-
- const label = options.createOptionLabeledInput({
- option,
- frame: "history",
- name: option.title,
- id: date.valueOf().toString(),
- top: date.toLocaleTimeString(),
- owner,
- });
-
- const li = window.document.createElement("li");
- li.append(label);
-
- if (testedString === firstTwo[0]) {
- if (options.selected() === grouped[testedString].at(0)?.option) {
- return;
- }
-
- grouped[testedString].unshift({ option, date });
- utils.dom.getElementById(testedString).after(li);
- } else {
- const [first, second] = firstTwo;
- /** @param {string | undefined} id */
- function updateHeading(id) {
- if (!id) return;
- utils.dom.getElementById(id).innerHTML = dateToDisplayedString(
- grouped[id][0].date,
- );
- }
-
- updateHeading(first);
- updateHeading(second);
-
- const heading = window.document.createElement("h4");
- heading.innerHTML = dateToDisplayedString(date);
- heading.id = testedString;
-
- elements.historyList.prepend(li);
- elements.historyList.prepend(heading);
-
- grouped[testedString] = [{ option, date }];
-
- firstTwo[1] = firstTwo[0];
- firstTwo[0] = testedString;
- }
- });
- }
- createUpdateHistoryEffect();
- }
- utils.dom.onFirstIntersection(elements.historyFrame, initHistoryFrame);
- }
- initHistory();
-
- function initSettings() {
- function initSettingsFrame() {
- console.log("settings: init");
-
- function initTheme() {
- const inputLight = /** @type {HTMLInputElement} */ (
- utils.dom.getElementById("settings-theme-light-input")
- );
- const inputDark = /** @type {HTMLInputElement} */ (
- utils.dom.getElementById("settings-theme-dark-input")
- );
- const inputSystem = /** @type {HTMLInputElement} */ (
- utils.dom.getElementById("settings-theme-system-input")
- );
-
- const settingsThemeLocalStorageKey = "settings-theme";
-
- let savedTheme = /** @type {SettingsTheme} */ (
- localStorage.getItem(settingsThemeLocalStorageKey)
- );
-
- switch (savedTheme) {
- case "dark": {
- inputDark.checked = true;
- break;
- }
- case "light": {
- inputLight.checked = true;
- break;
- }
- default:
- case "system": {
- inputSystem.checked = true;
- savedTheme = "system";
- break;
- }
- }
-
- const theme = signals.createSignal(savedTheme);
-
- const preferredColorSchemeMatchMedia = window.matchMedia(
- "(prefers-color-scheme: dark)",
- );
-
- /**
- * @param {boolean} shouldBeDark
- */
- function updateTheme(shouldBeDark) {
- dark.set(shouldBeDark);
-
- if (shouldBeDark) {
- window.document.documentElement.dataset.theme = "dark";
- } else {
- delete window.document.documentElement.dataset.theme;
- }
-
- const backgroundColor = getComputedStyle(
- window.document.documentElement,
- ).getPropertyValue("--background-color");
- const meta = utils.dom.queryOrCreateMetaElement("theme-color");
- meta.content = backgroundColor;
- }
-
- function createUpdateDataThemeEffect() {
- signals.createEffect(theme, (theme) => {
- localStorage.setItem(settingsThemeLocalStorageKey, theme);
- updateTheme(
- theme === "dark" ||
- (theme === "system" &&
- preferredColorSchemeMatchMedia.matches),
- );
- });
- }
- createUpdateDataThemeEffect();
-
- preferredColorSchemeMatchMedia.addEventListener("change", (media) => {
- if (theme() === "system") {
- updateTheme(media.matches);
- }
- });
-
- utils.dom
- .getElementById("settings-theme-field")
- .addEventListener("change", (event) => {
- const newTheme = /** @type {SettingsTheme | string} */ (
- // @ts-ignore
- event.target?.value
- );
- switch (newTheme) {
- case "dark":
- case "light":
- case "system": {
- theme.set(newTheme);
- break;
- }
- default: {
- throw "Bad theme";
- }
- }
- });
- }
- initTheme();
-
- function initLeaderboard() {
- const leaderboard = utils.dom.getElementById("leaderboard");
-
- const donations = [
- {
- name: "_Checkɱate",
- // url: "https://xcancel.com/_Checkmatey_",
- url: "https://primal.net/p/npub1qh5sal68c8swet6ut0w5evjmj6vnw29x3k967h7atn45unzjyeyq6ceh9r",
- amount: 500_000,
- },
- {
- name: "avvi |",
- url: "https://primal.net/p/npub1md2q6fexrtmd5hx9gw2p5640vg662sjlpxyz3tdmu4j4g8hhkm6scn6hx3",
- amount: 5_000,
- },
- {
- name: "mutatrum",
- url: "https://primal.net/p/npub1hklphk7fkfdgmzwclkhshcdqmnvr0wkfdy04j7yjjqa9lhvxuflsa23u2k",
- amount: 5_000,
- },
- {
- name: "Gunnar",
- url: "https://primal.net/p/npub1rx9wg2d5lhah45xst3580sajcld44m0ll9u5dqhu2t74p6xwufaqwghtd4",
- amount: 1_000,
- },
- {
- name: "Blokchain Boog",
- url: "https://xcancel.com/BlokchainB",
- amount: 1_500 + 1590,
- },
- {
- name: "Josh",
- url: "https://primal.net/p/npub1pc57ls4rad5kvsp733suhzl2d4u9y7h4upt952a2pucnalc59teq33dmza",
- amount: 1_000,
- },
- {
- name: "Alp",
- url: "https://primal.net/p/npub175nul9cvufswwsnpy99lvyhg7ad9nkccxhkhusznxfkr7e0zxthql9g6w0",
- amount: 1_000,
- },
- {
- name: "Ulysses",
- url: "https://primal.net/p/npub1n7n3dssm90hfsfjtamwh2grpzwjlvd2yffae9pqgg99583lxdypsnn9gtv",
- amount: 1_000,
- },
- {
- name: "btcschellingpt",
- url: "https://primal.net/p/npub1nvfgglea9zlcs58tcqlc6j26rt50ngkgdk7699wfq4txrx37aqcsz4e7zd",
- amount: 1_000 + 1_000,
- },
- {
- name: "Coinatra",
- url: "https://primal.net/p/npub1eut9kcejweegwp9waq3a4g03pvprdzkzvjjvl8fvj2a2wlx030eswzfna8",
- amount: 1_000,
- },
- {
- name: "Printer Go Brrrr",
- url: "https://primal.net/p/npub1l5pxvjzhw77h86tu0sml2gxg8jpwxch7fsj6d05n7vuqpq75v34syk4q0n",
- amount: 1_000,
- },
- {
- name: "b81776c32d7b",
- url: "https://primal.net/p/npub1hqthdsed0wpg57sqsc5mtyqxxgrh3s7493ja5h49v23v2nhhds4qk4w0kz",
- amount: 17_509,
- },
- {
- name: "DerGigi",
- url: "https://primal.net/p/npub1dergggklka99wwrs92yz8wdjs952h2ux2ha2ed598ngwu9w7a6fsh9xzpc",
- amount: 6001,
- },
- {
- name: "Adarnit",
- url: "https://primal.net/p/npub17armdveqy42uhuuuwjc5m2dgjkz7t7epgvwpuccqw8jusm8m0g4sn86n3s",
- amount: 17_726,
- },
- {
- name: "Auburn Citadel",
- url: "https://primal.net/p/npub1730y5k2s9u82w9snx3hl37r8gpsrmqetc2y3xyx9h65yfpf28rtq0y635y",
- amount: 17_471,
- },
- {
- name: "anon",
- amount: 210_000,
- },
- {
- name: "Daniel ∞/21M",
- url: "https://twitter.com/DanielAngelovBG",
- amount: 21_000,
- },
- {
- name: "Ivo",
- url: "https://primal.net/p/npub1mnwjn40hr042rsmzu64rsnwsw07uegg4tjkv620c94p6e797wkvq3qeujc",
- amount: 5_000,
- },
- {
- name: "lassdas",
- url: "https://primal.net/p/npub1gmhctt2hmjqz8ay2x8h5f8fl3h4fpfcezwqneal3usu3u65qca4s8094ea",
- amount: 210_000,
- },
- {
- name: "anon",
- amount: 21_000,
- },
- {
- name: "xplbzx",
- url: "https://primal.net/p/npub1e0f808a350rxrhppu4zylzljt3arfpvrrpqdg6ft78xy6u49kq5slf0g92",
- amount: 12_110,
- },
- {
- name: "SoundMoney=Prosperity4ALL",
- url: "https://xcancel.com/SoundmoneyP",
- amount: 420_000,
- },
- {
- name: "Johan",
- url: "https://primal.net/p/npub1a4sd4cprrucfkvkfq9zs99ur4xe7lxw3uhhgvuzx6nqxhnpa2yyqlsa26u",
- amount: 500_000,
- },
- {
- name: "highperfocused",
- url: "https://primal.net/p/npub1fq8vrf63vsrqjrwqgtwlvauqauc0yme6se8g8dqhcpf6tfs3equqntmzut",
- amount: 4620,
- },
- {
- name: "ClearMined",
- url: "https://primal.net/p/npub1dj8zwktp3eyktfhs5mjlw8v0v2838xlquxr7ddsanayhcw98fcks8ddrq9",
- amount: 300_000,
- },
- ];
-
- donations.sort((a, b) =>
- b.amount !== a.amount
- ? b.amount - a.amount
- : a.name.localeCompare(b.name),
- );
-
- donations.slice(0, 21).forEach(({ name, url, amount }) => {
- const li = window.document.createElement("li");
- leaderboard.append(li);
-
- const a = window.document.createElement("a");
- a.href = url || "";
- a.target = "_blank";
- a.rel = "noopener noreferrer";
- a.innerHTML = name;
- li.append(a);
-
- li.append(" — ");
-
- const small = window.document.createElement("small");
- small.classList.add("sats");
- small.innerHTML = `${amount.toLocaleString("en-us")} sats`;
- li.append(small);
- });
- }
- initLeaderboard();
-
- function initInstallInstructions() {
- if (
- !env.standalone &&
- env.safariOnly &&
- (env.macOS || env.ipad || env.iphone)
- ) {
- const installInstructionsElement = utils.dom.getElementById(
- "settings-install-instructions",
- );
- installInstructionsElement.hidden = false;
-
- const hr = window.document.createElement("hr");
- installInstructionsElement.before(hr);
-
- const heading = window.document.createElement("h4");
- heading.innerHTML = "Install";
- installInstructionsElement.append(heading);
-
- const p = window.document.createElement("p");
- installInstructionsElement.append(p);
-
- if (env.macOS) {
- p.innerHTML = `This app can be installed by clicking on the File tab on the menu bar and then on Add to dock .`;
- } else {
- p.innerHTML = `This app can be installed by tapping on the Share button tab of Safari and then on Add to Home Screen .`;
- }
- }
- }
- initInstallInstructions();
-
- function initMobileNav() {
- const anchorApi = /** @type {HTMLAnchorElement} */ (
- utils.dom.getElementById("anchor-api").cloneNode(true)
- );
-
- const anchorGit = /** @type {HTMLAnchorElement} */ (
- utils.dom.getElementById("anchor-git").cloneNode(true)
- );
-
- const anchorNostr = /** @type {HTMLAnchorElement} */ (
- utils.dom.getElementById("anchor-nostr").cloneNode(true)
- );
-
- const anchorGeyser = /** @type {HTMLAnchorElement} */ (
- utils.dom.getElementById("anchor-geyser").cloneNode(true)
- );
-
- if (!anchorApi || !anchorGit || !anchorNostr || !anchorGeyser)
- throw "Anchors should exist by now";
-
- anchorApi.id = "";
- anchorGit.id = "";
- anchorNostr.id = "";
- anchorGeyser.id = "";
-
- const nav = utils.dom.getElementById("settings-nav");
-
- nav.append(anchorApi);
- nav.append(anchorGit);
- nav.append(anchorNostr);
- nav.append(anchorGeyser);
- }
- initMobileNav();
- }
- utils.dom.onFirstIntersection(elements.settingsFrame, initSettingsFrame);
- }
- initSettings();
-
function initDesktopResizeBar() {
const resizeBar = utils.dom.getElementById("resize-bar");
let resize = false;
diff --git a/website/scripts/options.js b/website/scripts/options.js
index e73811a01..b8a6f5979 100644
--- a/website/scripts/options.js
+++ b/website/scripts/options.js
@@ -1,5 +1,5 @@
/**
- * @import { AnySpecificSeriesBlueprint, CohortOption, CohortOptions, Color, DefaultCohortOption, DefaultCohortOptions, OptionPath, OptionsGroup, PartialChartOption, PartialOptionsGroup, PartialOptionsTree, RatioOption, RatioOptions, Series, SeriesBlueprint, SeriesBlueprintParam, SeriesBluePrintType, TimeScale } from "./types/self"
+ * @import { AnySpecificSeriesBlueprint, CohortOption, CohortOptions, Color, DefaultCohortOption, DefaultCohortOptions, OptionPath, OptionsGroup, PartialChartOption, PartialOptionsGroup, PartialOptionsTree, RatioOption, RatioOptions, Series, SeriesBlueprint, SeriesBlueprintParam, SeriesBluePrintType, Signal, TimeScale } from "./types/self"
*/
const DATE_TO_PREFIX = "date-to-";
@@ -618,7 +618,6 @@ function createPartialOptions(colors) {
? [
{
scale,
- icon: "➕",
name: "Daily Sum",
title: `${title} Daily Sum`,
description: "",
@@ -637,7 +636,6 @@ function createPartialOptions(colors) {
? [
{
scale,
- icon: "🌊",
name: "Daily Average",
title: `${title} Daily Average`,
description: "",
@@ -656,7 +654,6 @@ function createPartialOptions(colors) {
? [
{
scale,
- icon: "%",
name: "Daily Percentiles",
title: `${title} Daily Percentiles`,
description: "",
@@ -733,7 +730,6 @@ function createPartialOptions(colors) {
? [
{
scale,
- icon: "⬆️",
name: "Daily Max",
title: `${title} Daily Max`,
description: "",
@@ -752,7 +748,6 @@ function createPartialOptions(colors) {
? [
{
scale,
- icon: "9️⃣",
name: "Daily 90th Percentile",
title: `${title} Daily 90th Percentile`,
description: "",
@@ -771,7 +766,6 @@ function createPartialOptions(colors) {
? [
{
scale,
- icon: "7️⃣",
name: "Daily 75th Percentile",
title: `${title} Size 75th Percentile`,
description: "",
@@ -790,7 +784,6 @@ function createPartialOptions(colors) {
? [
{
scale,
- icon: "5️⃣",
name: "Daily Median",
title: `${title} Daily Median`,
description: "",
@@ -809,7 +802,6 @@ function createPartialOptions(colors) {
? [
{
scale,
- icon: "2️⃣",
name: "Daily 25th Percentile",
title: `${title} Daily 25th Percentile`,
description: "",
@@ -828,7 +820,6 @@ function createPartialOptions(colors) {
? [
{
scale,
- icon: "1️⃣",
name: "Daily 10th Percentile",
title: `${title} Daily 10th Percentile`,
description: "",
@@ -847,7 +838,6 @@ function createPartialOptions(colors) {
? [
{
scale,
- icon: "⬇️",
name: "Daily Min",
title: `${title} Daily Min`,
description: "",
@@ -896,7 +886,6 @@ function createPartialOptions(colors) {
{
scale,
name: "Basic",
- icon: "➗",
title: `Market Price To ${title} Ratio`,
unit: "Ratio",
description: "",
@@ -930,7 +919,6 @@ function createPartialOptions(colors) {
scale,
name: "Averages",
description: "",
- icon: "〰️",
unit: "Ratio",
title: `Market Price To ${title} Ratio Averages`,
top: [
@@ -982,7 +970,6 @@ function createPartialOptions(colors) {
title: `Market Price To ${title} Ratio 1Y SMA Momentum Oscillator`,
description: "",
unit: "Ratio",
- icon: "🔀",
top: toList(arg).map(
({ title, color, valueDatasetPath: datasetPath }) => ({
title: toLegendName(arg, title, ""),
@@ -1012,7 +999,6 @@ function createPartialOptions(colors) {
{
scale,
name: "Percentiles",
- icon: "✈️",
title: `Market Price To ${title} Ratio Top Percentiles`,
description: "",
unit: "Ratio",
@@ -1058,7 +1044,6 @@ function createPartialOptions(colors) {
{
scale,
name: "All",
- icon: "🚀",
title: `${title} Top Prices`,
description: "",
unit: "US Dollars",
@@ -1087,7 +1072,6 @@ function createPartialOptions(colors) {
{
scale,
name: "99%",
- icon: "🚀",
title: `${title} Top 99% Price`,
description: "",
unit: "US Dollars",
@@ -1102,7 +1086,6 @@ function createPartialOptions(colors) {
{
scale,
name: "99.5%",
- icon: "🚀",
title: `${title} Top 99.5% Price`,
description: "",
unit: "US Dollars",
@@ -1117,7 +1100,6 @@ function createPartialOptions(colors) {
{
scale,
name: "99.9%",
- icon: "🚀",
title: `${title} Top 99.9% Price`,
description: "",
unit: "US Dollars",
@@ -1141,7 +1123,6 @@ function createPartialOptions(colors) {
{
scale,
name: "Percentiles",
- icon: "🤿",
title: `Market Price To ${title} Ratio Bottom Percentiles`,
description: "",
unit: "Ratio",
@@ -1187,7 +1168,6 @@ function createPartialOptions(colors) {
{
scale,
name: "All",
- icon: "🚇",
title: `${title} Bottom Prices`,
description: "",
unit: "US Dollars",
@@ -1216,7 +1196,6 @@ function createPartialOptions(colors) {
{
scale,
name: "1%",
- icon: "🚇",
title: `${title} Bottom 1% Price`,
description: "",
unit: "US Dollars",
@@ -1231,7 +1210,6 @@ function createPartialOptions(colors) {
{
scale,
name: "0.5%",
- icon: "🚇",
title: `${title} Bottom 0.5% Price`,
description: "",
unit: "US Dollars",
@@ -1246,7 +1224,6 @@ function createPartialOptions(colors) {
{
scale,
name: "0.1%",
- icon: "🚇",
title: `${title} Bottom 0.1% Price`,
description: "",
unit: "US Dollars",
@@ -1281,7 +1258,6 @@ function createPartialOptions(colors) {
tree: [
{
scale,
- icon: "🔝",
name: "Value",
title: "All Time High",
description: "",
@@ -1296,7 +1272,6 @@ function createPartialOptions(colors) {
},
{
scale,
- icon: "🏂",
name: "Drawdown",
title: "All Time High Drawdown",
description: "",
@@ -1320,7 +1295,6 @@ function createPartialOptions(colors) {
? /** @type {PartialChartOption[]} */ ([
{
scale,
- icon: "🗓️",
name: "Days Since",
title: "Days Since All Time High",
description: "",
@@ -1338,7 +1312,6 @@ function createPartialOptions(colors) {
tree: [
{
scale,
- icon: "📆",
name: "Days",
title: "Max Number Of Days Between All Time Highs",
shortTitle: "Max Days Between",
@@ -1355,7 +1328,6 @@ function createPartialOptions(colors) {
},
{
scale,
- icon: "📆",
name: "Years",
title: "Max Number Of Years Between All Time Highs",
shortTitle: "Max Years Between",
@@ -1387,7 +1359,6 @@ function createPartialOptions(colors) {
tree: [
{
scale,
- icon: "🌊",
name: "All",
title: "All Moving Averages",
description: "",
@@ -1431,7 +1402,6 @@ function createPartialOptions(colors) {
title,
description: "",
unit: "US Dollars",
- icon: "~",
top: [
{
title: `SMA`,
@@ -1501,7 +1471,6 @@ function createPartialOptions(colors) {
scale,
name,
description: "",
- icon: "🧾",
title: `${title} Return`,
unit: "Percentage",
bottom: [
@@ -1533,7 +1502,6 @@ function createPartialOptions(colors) {
tree: [
{
scale,
- icon: "💵",
name: "Dollars Per Bitcoin",
title: "Dollars Per Bitcoin",
description: "",
@@ -1541,7 +1509,6 @@ function createPartialOptions(colors) {
},
{
scale,
- icon: "🍊",
name: "Sats Per Dollar",
title: "Satoshis Per Dollar",
description: "",
@@ -1558,7 +1525,6 @@ function createPartialOptions(colors) {
},
{
scale,
- icon: "♾️",
name: "Capitalization",
title: "Market Capitalization",
description: "",
@@ -1592,7 +1558,6 @@ function createPartialOptions(colors) {
? /** @type {PartialOptionsTree} */ ([
{
scale,
- icon: "🧱",
name: "Height",
title: "Block Height",
description: "",
@@ -1611,7 +1576,6 @@ function createPartialOptions(colors) {
tree: [
{
scale,
- icon: "D",
name: "Daily Sum",
title: "Daily Sum Of Blocks Mined",
description: "",
@@ -1646,7 +1610,6 @@ function createPartialOptions(colors) {
},
{
scale,
- icon: "W",
name: "Weekly Sum",
title: "Weekly Sum Of Blocks Mined",
description: "",
@@ -1669,7 +1632,6 @@ function createPartialOptions(colors) {
},
{
scale,
- icon: "M",
name: "Monthly Sum",
title: "Monthly Sum Of Blocks Mined",
description: "",
@@ -1692,7 +1654,6 @@ function createPartialOptions(colors) {
},
{
scale,
- icon: "Y",
name: "Yearly Sum",
title: "Yearly Sum Of Blocks Mined",
description: "",
@@ -1715,7 +1676,6 @@ function createPartialOptions(colors) {
},
{
scale,
- icon: "🧱",
name: "Total",
title: "Total Blocks Mined",
description: "",
@@ -1736,7 +1696,6 @@ function createPartialOptions(colors) {
tree: [
{
scale,
- icon: "📏",
name: "Cumulative",
title: "Cumulative Block Size",
description: "",
@@ -1824,7 +1783,6 @@ function createPartialOptions(colors) {
: /** @type {PartialOptionsTree} */ ([
{
scale,
- icon: "📏",
name: "Size",
title: "Block Size",
description: "",
@@ -1839,7 +1797,6 @@ function createPartialOptions(colors) {
},
{
scale,
- icon: "🏋️",
name: "Weight",
title: "Block Weight",
description: "",
@@ -1854,7 +1811,6 @@ function createPartialOptions(colors) {
},
{
scale,
- icon: "👾",
name: "VBytes",
title: "Block VBytes",
description: "",
@@ -1869,7 +1825,6 @@ function createPartialOptions(colors) {
},
{
scale,
- icon: "⏰",
name: "Interval",
title: "Block Interval",
description: "",
@@ -1900,48 +1855,12 @@ function createPartialOptions(colors) {
tree: [
...(scale === "date"
? /** @satisfies {PartialOptionsTree} */ ([
- {
- name: "Last",
- tree: [
- {
- scale,
- icon: "🍊",
- name: "In Bitcoin",
- title: "Last Coinbase In Bitcoin",
- description: "",
- unit: "US Dollars",
- bottom: [
- {
- title: "Last",
- color: colors.bitcoin,
- datasetPath: `${scale}-to-last-coinbase`,
- },
- ],
- },
- {
- scale,
- icon: "💵",
- name: "In Dollars",
- title: "Last Coinbase In Dollars",
- description: "",
- unit: "US Dollars",
- bottom: [
- {
- title: "Last",
- color: colors.dollars,
- datasetPath: `${scale}-to-last-coinbase-in-dollars`,
- },
- ],
- },
- ],
- },
{
scale,
name: "Daily Sum",
tree: [
{
scale,
- icon: "🍊",
name: "In Bitcoin",
title: "Daily Sum Of Coinbases In Bitcoin",
description: "",
@@ -1956,7 +1875,6 @@ function createPartialOptions(colors) {
},
{
scale,
- icon: "💵",
name: "In Dollars",
title: "Daily Sum Of Coinbases In Dollars",
description: "",
@@ -1977,7 +1895,6 @@ function createPartialOptions(colors) {
tree: [
{
scale,
- icon: "🍊",
name: "In Bitcoin",
title: "Yearly Sum Of Coinbases In Bitcoin",
description: "",
@@ -1992,7 +1909,6 @@ function createPartialOptions(colors) {
},
{
scale,
- icon: "💵",
name: "In Dollars",
title: "Yearly Sum Of Coinbases In Dollars",
description: "",
@@ -2013,7 +1929,6 @@ function createPartialOptions(colors) {
tree: [
{
scale,
- icon: "🍊",
name: "In Bitcoin",
title: "Cumulative Coinbases In Bitcoin",
description: "",
@@ -2028,7 +1943,6 @@ function createPartialOptions(colors) {
},
{
scale,
- icon: "💵",
name: "In Dollars",
title: "Cumulative Coinbases In Dollars",
description: "",
@@ -2043,6 +1957,39 @@ function createPartialOptions(colors) {
},
],
},
+ {
+ name: "Last Block",
+ tree: [
+ {
+ scale,
+ name: "In Bitcoin",
+ title: "Last Coinbase In Bitcoin",
+ description: "",
+ unit: "US Dollars",
+ bottom: [
+ {
+ title: "Last",
+ color: colors.bitcoin,
+ datasetPath: `${scale}-to-last-coinbase`,
+ },
+ ],
+ },
+ {
+ scale,
+ name: "In Dollars",
+ title: "Last Coinbase In Dollars",
+ description: "",
+ unit: "US Dollars",
+ bottom: [
+ {
+ title: "Last",
+ color: colors.dollars,
+ datasetPath: `${scale}-to-last-coinbase-in-dollars`,
+ },
+ ],
+ },
+ ],
+ },
])
: []),
],
@@ -2053,48 +2000,12 @@ function createPartialOptions(colors) {
tree: [
...(scale === "date"
? /** @type {PartialOptionsTree} */ ([
- {
- name: "Last",
- tree: [
- {
- scale,
- icon: "🍊",
- name: "In Bitcoin",
- title: "Last Subsidy In Bitcoin",
- description: "",
- unit: "Bitcoin",
- bottom: [
- {
- title: "Last",
- color: colors.bitcoin,
- datasetPath: `${scale}-to-last-subsidy`,
- },
- ],
- },
- {
- scale,
- icon: "💵",
- name: "In Dollars",
- title: "Last Subsidy In Dollars",
- description: "",
- unit: "US Dollars",
- bottom: [
- {
- title: "Last",
- color: colors.dollars,
- datasetPath: `${scale}-to-last-subsidy-in-dollars`,
- },
- ],
- },
- ],
- },
{
scale,
name: "Daily Sum",
tree: [
{
scale,
- icon: "🍊",
name: "In Bitcoin",
title: "Daily Sum Of Subsidies In Bitcoin",
description: "",
@@ -2109,7 +2020,6 @@ function createPartialOptions(colors) {
},
{
scale,
- icon: "💵",
name: "In Dollars",
title: "Daily Sum Of Subsidies In Dollars",
description: "",
@@ -2130,7 +2040,6 @@ function createPartialOptions(colors) {
tree: [
{
scale,
- icon: "🍊",
name: "In Bitcoin",
title: "Yearly Sum Of Subsidies In Bitcoin",
description: "",
@@ -2145,7 +2054,6 @@ function createPartialOptions(colors) {
},
{
scale,
- icon: "💵",
name: "In Dollars",
title: "Yearly Sum Of Subsidies In Dollars",
description: "",
@@ -2167,7 +2075,6 @@ function createPartialOptions(colors) {
tree: [
{
scale,
- icon: "🍊",
name: "In Bitcoin",
title: "Cumulative Subsidies In Bitcoin",
description: "",
@@ -2182,7 +2089,6 @@ function createPartialOptions(colors) {
},
{
scale,
- icon: "💵",
name: "In Dollars",
title: "Cumulative Subsidies In Dollars",
description: "",
@@ -2197,6 +2103,39 @@ function createPartialOptions(colors) {
},
],
},
+ {
+ name: "Last Block",
+ tree: [
+ {
+ scale,
+ name: "In Bitcoin",
+ title: "Last Subsidy In Bitcoin",
+ description: "",
+ unit: "Bitcoin",
+ bottom: [
+ {
+ title: "Last",
+ color: colors.bitcoin,
+ datasetPath: `${scale}-to-last-subsidy`,
+ },
+ ],
+ },
+ {
+ scale,
+ name: "In Dollars",
+ title: "Last Subsidy In Dollars",
+ description: "",
+ unit: "US Dollars",
+ bottom: [
+ {
+ title: "Last",
+ color: colors.dollars,
+ datasetPath: `${scale}-to-last-subsidy-in-dollars`,
+ },
+ ],
+ },
+ ],
+ },
])
: []),
],
@@ -2207,48 +2146,12 @@ function createPartialOptions(colors) {
tree: [
...(scale === "date"
? /** @type {PartialOptionsTree} */ ([
- {
- name: "Last",
- tree: [
- {
- scale,
- icon: "🍊",
- name: "In Bitcoin",
- title: "Last Fees In Bitcoin",
- description: "",
- unit: "Bitcoin",
- bottom: [
- {
- title: "Last",
- color: colors.bitcoin,
- datasetPath: `${scale}-to-last-fees`,
- },
- ],
- },
- {
- scale,
- icon: "💵",
- name: "In Dollars",
- title: "Last Fees In Dollars",
- description: "",
- unit: "US Dollars",
- bottom: [
- {
- title: "Last",
- color: colors.dollars,
- datasetPath: `${scale}-to-last-fees-in-dollars`,
- },
- ],
- },
- ],
- },
{
scale,
name: "Daily Sum",
tree: [
{
scale,
- icon: "🍊",
name: "In Bitcoin",
title: "Daily Sum Of Fees In Bitcoin",
description: "",
@@ -2263,7 +2166,6 @@ function createPartialOptions(colors) {
},
{
scale,
- icon: "💵",
name: "In Dollars",
title: "Daily Sum Of Fees In Dollars",
description: "",
@@ -2284,7 +2186,6 @@ function createPartialOptions(colors) {
tree: [
{
scale,
- icon: "🍊",
name: "In Bitcoin",
title: "Yearly Sum Of Fees In Bitcoin",
description: "",
@@ -2299,7 +2200,6 @@ function createPartialOptions(colors) {
},
{
scale,
- icon: "💵",
name: "In Dollars",
title: "Yearly Sum Of Fees In Dollars",
description: "",
@@ -2320,7 +2220,6 @@ function createPartialOptions(colors) {
tree: [
{
scale,
- icon: "🍊",
name: "In Bitcoin",
title: "Cumulative Fees In Bitcoin",
description: "",
@@ -2335,7 +2234,6 @@ function createPartialOptions(colors) {
},
{
scale,
- icon: "💵",
name: "In Dollars",
title: "Cumulative Fees In Dollars",
description: "",
@@ -2350,6 +2248,39 @@ function createPartialOptions(colors) {
},
],
},
+ {
+ name: "Last Block",
+ tree: [
+ {
+ scale,
+ name: "In Bitcoin",
+ title: "Last Fees In Bitcoin",
+ description: "",
+ unit: "Bitcoin",
+ bottom: [
+ {
+ title: "Last",
+ color: colors.bitcoin,
+ datasetPath: `${scale}-to-last-fees`,
+ },
+ ],
+ },
+ {
+ scale,
+ name: "In Dollars",
+ title: "Last Fees In Dollars",
+ description: "",
+ unit: "US Dollars",
+ bottom: [
+ {
+ title: "Last",
+ color: colors.dollars,
+ datasetPath: `${scale}-to-last-fees-in-dollars`,
+ },
+ ],
+ },
+ ],
+ },
])
: []),
],
@@ -2357,7 +2288,6 @@ function createPartialOptions(colors) {
{
scale,
- icon: "⚔️",
name: "Subsidy V. Fees",
title: "Subsidy V. Fees",
description: "",
@@ -2386,7 +2316,6 @@ function createPartialOptions(colors) {
? /** @type {PartialOptionsTree} */ ([
{
scale,
- icon: "🧮",
name: "Puell Multiple",
title: "Puell Multiple",
description: "",
@@ -2405,7 +2334,6 @@ function createPartialOptions(colors) {
tree: [
{
scale,
- icon: "⛏️",
name: "Rate",
title: "Hash Rate",
description: "",
@@ -2430,7 +2358,6 @@ function createPartialOptions(colors) {
},
{
scale,
- icon: "🎗️",
name: "Ribbon",
title: "Hash Ribbon",
description: "",
@@ -2453,7 +2380,6 @@ function createPartialOptions(colors) {
tree: [
{
scale,
- icon: "🏷️",
name: "Price",
title: "Hash Price",
description: "",
@@ -2468,7 +2394,6 @@ function createPartialOptions(colors) {
},
{
scale,
- icon: "😢",
name: "Min",
title: "Min Hash Price",
description: "",
@@ -2483,7 +2408,6 @@ function createPartialOptions(colors) {
},
{
scale,
- icon: "🤞",
name: "Rebound",
title: "Hash Price Rebound",
description: "",
@@ -2505,7 +2429,6 @@ function createPartialOptions(colors) {
{
scale,
- icon: "🏋️",
name: "Difficulty",
title: "Difficulty",
description: "",
@@ -2523,7 +2446,6 @@ function createPartialOptions(colors) {
? /** @type {PartialOptionsTree} */ ([
{
scale,
- icon: "📊",
name: "Difficulty Adjustment",
title: "Difficulty Adjustment",
description: "",
@@ -2539,7 +2461,6 @@ function createPartialOptions(colors) {
},
{
scale,
- icon: "🏭",
name: "Annualized Issuance",
title: "Annualized Issuance",
description: "",
@@ -2557,8 +2478,7 @@ function createPartialOptions(colors) {
tree: [
{
scale,
- icon: "🏗️",
- name: "Normal",
+ name: "Today",
title: "Inflation Rate",
description: "",
unit: "Percentage",
@@ -2572,7 +2492,6 @@ function createPartialOptions(colors) {
},
{
scale,
- icon: "🏗️",
name: "Yearly",
title: "Yearly Inflation Rate",
description: "",
@@ -2603,7 +2522,6 @@ function createPartialOptions(colors) {
tree: [
{
scale,
- icon: "🖐️",
name: "Count",
title: "Transaction Count",
description: "",
@@ -2642,7 +2560,6 @@ function createPartialOptions(colors) {
tree: [
{
scale,
- icon: "🍊",
name: "In Bitcoin",
title: "Transaction Volume",
description: "",
@@ -2676,7 +2593,6 @@ function createPartialOptions(colors) {
},
{
scale,
- icon: "💵",
name: "In Dollars",
title: "Transaction Volume In Dollars",
description: "",
@@ -2718,7 +2634,6 @@ function createPartialOptions(colors) {
tree: [
{
scale,
- icon: "🍊",
name: "In Bitcoin",
title: "Annualized Transaction Volume",
description: "",
@@ -2733,7 +2648,6 @@ function createPartialOptions(colors) {
},
{
scale,
- icon: "💵",
name: "In Dollars",
title: "Annualized Transaction Volume In Dollars",
description: "",
@@ -2750,7 +2664,6 @@ function createPartialOptions(colors) {
},
{
scale,
- icon: "💨",
name: "Velocity",
title: "Transactions Velocity",
description: "",
@@ -2767,7 +2680,6 @@ function createPartialOptions(colors) {
: []),
{
scale,
- icon: "⏰",
name: "Per Second",
title: "Transactions Per Second",
description: "",
@@ -2877,10 +2789,9 @@ function createPartialOptions(colors) {
{
scale,
name: `Count`,
- title: `${title} Unspent Transaction Outputs Count`,
+ title: `Number Of ${title} Unspent Transaction Outputs`,
description: "",
unit: "Count",
- icon: "🎫",
bottom: cohortOptionOrOptions.toSeriesBlueprints(arg, {
title: "Count",
genPath: (id, scale) =>
@@ -2908,8 +2819,12 @@ function createPartialOptions(colors) {
return {
scale,
color: arg.color,
- ratioDatasetPath: `${scale}-to-market-price-to-${datasetIdToPrefix(arg.datasetId)}realized-price-ratio`,
- valueDatasetPath: `${scale}-to-${datasetIdToPrefix(arg.datasetId)}realized-price`,
+ ratioDatasetPath: `${scale}-to-market-price-to-${datasetIdToPrefix(
+ arg.datasetId,
+ )}realized-price-ratio`,
+ valueDatasetPath: `${scale}-to-${datasetIdToPrefix(
+ arg.datasetId,
+ )}realized-price`,
title: `${arg.title} Realized Price`,
};
}
@@ -2923,7 +2838,6 @@ function createPartialOptions(colors) {
title: `${title} Realized Price`,
description: "",
unit: "US Dollars",
- icon: "🏷️",
top: cohortOptionOrOptions.toSeriesBlueprints(arg, {
title: "Realized Price",
genPath: (id, scale) =>
@@ -2946,7 +2860,6 @@ function createPartialOptions(colors) {
title: `${title} Realized Capitalization`,
description: "",
unit: "US Dollars",
- icon: "💰",
bottom: [
...cohortOptionOrOptions.toSeriesBlueprints(
arg,
@@ -2977,7 +2890,6 @@ function createPartialOptions(colors) {
title: `${title} Realized Capitalization 1 Month Net Change`,
description: "",
unit: "US Dollars",
- icon: "🔀",
bottom: [
...cohortOptionOrOptions.toSeriesBlueprints(
arg,
@@ -2986,7 +2898,9 @@ function createPartialOptions(colors) {
title: "Net Change",
type: "Baseline",
genPath: (id, scale) =>
- `${scale}-to-${datasetIdToPrefix(id)}realized-cap-1m-net-change`,
+ `${scale}-to-${datasetIdToPrefix(
+ id,
+ )}realized-cap-1m-net-change`,
},
),
bases[0](scale),
@@ -2998,7 +2912,6 @@ function createPartialOptions(colors) {
title: `${title} Realized Profit`,
description: "",
unit: "US Dollars",
- icon: "🎉",
bottom: cohortOptionOrOptions.toSeriesBlueprints(arg, {
title: "Realized Profit",
singleColor: colors.profit,
@@ -3016,7 +2929,6 @@ function createPartialOptions(colors) {
title: `${title} Realized Loss`,
description: "",
unit: "US Dollars",
- icon: "⚰️",
bottom: cohortOptionOrOptions.toSeriesBlueprints(arg, {
title: "Realized Loss",
singleColor: colors.loss,
@@ -3035,7 +2947,6 @@ function createPartialOptions(colors) {
title: `${title} Realized Profit And Loss`,
description: "",
unit: "US Dollars",
- icon: "⚖️",
bottom: [
{
title: "Profit",
@@ -3065,7 +2976,6 @@ function createPartialOptions(colors) {
title: `${title} Net Realized Profit And Loss`,
description: "",
unit: "US Dollars",
- icon: "⚖️",
bottom: [
...cohortOptionOrOptions.toSeriesBlueprints(arg, {
title: "Net PNL",
@@ -3087,13 +2997,14 @@ function createPartialOptions(colors) {
title: `${title} Net Realized Profit And Loss Relative To Market Capitalization`,
description: "",
unit: "Percentage",
- icon: "➗",
bottom: [
...cohortOptionOrOptions.toSeriesBlueprints(arg, {
title: "Net",
type: "Baseline",
genPath: (id) =>
- `${scale}-to-${datasetIdToPrefix(id)}net-realized-profit-and-loss-to-market-cap-ratio`,
+ `${scale}-to-${datasetIdToPrefix(
+ id,
+ )}net-realized-profit-and-loss-to-market-cap-ratio`,
}),
bases[0](scale),
],
@@ -3108,12 +3019,13 @@ function createPartialOptions(colors) {
title: `${title} Cumulative Realized Profit`,
description: "",
unit: "US Dollars",
- icon: "🎊",
bottom: cohortOptionOrOptions.toSeriesBlueprints(arg, {
title: "Cumulative Realized Profit",
singleColor: colors.profit,
genPath: (id, scale) =>
- `${scale}-to-${datasetIdToPrefix(id)}cumulative-realized-profit`,
+ `${scale}-to-${datasetIdToPrefix(
+ id,
+ )}cumulative-realized-profit`,
}),
},
{
@@ -3122,12 +3034,13 @@ function createPartialOptions(colors) {
title: `${title} Cumulative Realized Loss`,
description: "",
unit: "US Dollars",
- icon: "☠️",
bottom: cohortOptionOrOptions.toSeriesBlueprints(arg, {
title: "Cumulative Realized Loss",
singleColor: colors.loss,
genPath: (id, scale) =>
- `${scale}-to-${datasetIdToPrefix(id)}cumulative-realized-loss`,
+ `${scale}-to-${datasetIdToPrefix(
+ id,
+ )}cumulative-realized-loss`,
}),
},
{
@@ -3136,13 +3049,14 @@ function createPartialOptions(colors) {
title: `${title} Cumulative Net Realized Profit And Loss`,
description: "",
unit: "US Dollars",
- icon: "➕",
bottom: [
...cohortOptionOrOptions.toSeriesBlueprints(arg, {
title: "Cumulative Net Realized PNL",
type: "Baseline",
genPath: (id, scale) =>
- `${scale}-to-${datasetIdToPrefix(id)}cumulative-net-realized-profit-and-loss`,
+ `${scale}-to-${datasetIdToPrefix(
+ id,
+ )}cumulative-net-realized-profit-and-loss`,
}),
bases[0](scale),
],
@@ -3153,13 +3067,14 @@ function createPartialOptions(colors) {
title: `${title} Cumulative Net Realized Profit And Loss 30 Day Change`,
description: "",
unit: "US Dollars",
- icon: "🗓️",
bottom: [
...cohortOptionOrOptions.toSeriesBlueprints(arg, {
title: "Cumulative Net Realized PNL 30d Change",
type: "Baseline",
genPath: (id, scale) =>
- `${scale}-to-${datasetIdToPrefix(id)}cumulative-net-realized-profit-and-loss-1m-net-change`,
+ `${scale}-to-${datasetIdToPrefix(
+ id,
+ )}cumulative-net-realized-profit-and-loss-1m-net-change`,
}),
bases[0](scale),
],
@@ -3172,7 +3087,6 @@ function createPartialOptions(colors) {
title: `${title} Profit To Loss Ratio`,
description: "",
unit: "Ratio",
- icon: "∶",
bottom: [
...cohortOptionOrOptions.toSeriesBlueprints(arg, {
title: "Ratio",
@@ -3201,7 +3115,6 @@ function createPartialOptions(colors) {
title: `${title} Spent Output Profit Ratio`,
description: "",
unit: "Percentage",
- icon: "➗",
bottom: [
...cohortOptionOrOptions.toSeriesBlueprints(arg, {
title: "SOPR",
@@ -3212,7 +3125,9 @@ function createPartialOptions(colors) {
},
},
genPath: (id, scale) =>
- `${scale}-to-${datasetIdToPrefix(id)}spent-output-profit-ratio`,
+ `${scale}-to-${datasetIdToPrefix(
+ id,
+ )}spent-output-profit-ratio`,
}),
bases[1](scale),
],
@@ -3223,7 +3138,6 @@ function createPartialOptions(colors) {
title: `${title} Adjusted Spent Output Profit Ratio`,
description: "",
unit: "Percentage",
- icon: "➗",
bottom: [
...cohortOptionOrOptions.toSeriesBlueprints(arg, {
title: "aSOPR",
@@ -3234,7 +3148,9 @@ function createPartialOptions(colors) {
},
},
genPath: (id, scale) =>
- `${scale}-to-${datasetIdToPrefix(id)}adjusted-spent-output-profit-ratio`,
+ `${scale}-to-${datasetIdToPrefix(
+ id,
+ )}adjusted-spent-output-profit-ratio`,
}),
bases[1](scale),
],
@@ -3253,7 +3169,6 @@ function createPartialOptions(colors) {
title: `${title} Value Created`,
description: "",
unit: "US Dollars",
- icon: "➕",
bottom: cohortOptionOrOptions.toSeriesBlueprints(arg, {
title: "Value",
singleColor: colors.profit,
@@ -3271,7 +3186,6 @@ function createPartialOptions(colors) {
title: `${title} Adjusted Value Created`,
description: "",
unit: "US Dollars",
- icon: "➕",
bottom: cohortOptionOrOptions.toSeriesBlueprints(arg, {
title: "Adjusted Value",
singleColor: colors.profit,
@@ -3294,7 +3208,6 @@ function createPartialOptions(colors) {
title: `${title} Value Destroyed`,
description: "",
unit: "US Dollars",
- icon: "☄️",
bottom: cohortOptionOrOptions.toSeriesBlueprints(arg, {
title: "Value",
singleColor: colors.loss,
@@ -3312,7 +3225,6 @@ function createPartialOptions(colors) {
title: `${title} Adjusted Value Destroyed`,
description: "",
unit: "US Dollars",
- icon: "☄️",
bottom: cohortOptionOrOptions.toSeriesBlueprints(arg, {
title: "Adjusted Value",
singleColor: colors.loss,
@@ -3335,7 +3247,6 @@ function createPartialOptions(colors) {
title: `${title} Sell Side Risk Ratio`,
description: "",
unit: "Percentage",
- icon: "🥵",
bottom: cohortOptionOrOptions.toSeriesBlueprints(arg, {
title: "Ratio",
genPath: (id) =>
@@ -3363,7 +3274,6 @@ function createPartialOptions(colors) {
title: `${title} Unrealized Profit`,
description: "",
unit: "US Dollars",
- icon: "🤑",
bottom: cohortOptionOrOptions.toSeriesBlueprints(arg, {
title: "Profit",
genPath: (id) =>
@@ -3377,7 +3287,6 @@ function createPartialOptions(colors) {
title: `${title} Unrealized Loss`,
description: "",
unit: "US Dollars",
- icon: "😭",
bottom: cohortOptionOrOptions.toSeriesBlueprints(arg, {
title: "Loss",
genPath: (id) =>
@@ -3392,7 +3301,6 @@ function createPartialOptions(colors) {
title: `${title} Unrealized Profit And Loss`,
description: "",
unit: "US Dollars",
- icon: "🤔",
bottom: [
{
title: "Profit",
@@ -3416,12 +3324,13 @@ function createPartialOptions(colors) {
title: `${title} Net Unrealized Profit And Loss`,
description: "",
unit: "US Dollars",
- icon: "⚖️",
bottom: [
...cohortOptionOrOptions.toSeriesBlueprints(arg, {
title: "Net Unrealized PNL",
genPath: (id) =>
- `${scale}-to-${datasetIdToPrefix(id)}net-unrealized-profit-and-loss`,
+ `${scale}-to-${datasetIdToPrefix(
+ id,
+ )}net-unrealized-profit-and-loss`,
type: "Baseline",
}),
bases[0](scale),
@@ -3433,12 +3342,13 @@ function createPartialOptions(colors) {
title: `${title} Net Unrealized Profit And Loss Relative To Total Market Capitalization - NUPL`,
description: "",
unit: "Percentage",
- icon: "➗",
bottom: [
...cohortOptionOrOptions.toSeriesBlueprints(arg, {
title: "Relative Net Unrealized PNL",
genPath: (id) =>
- `${scale}-to-${datasetIdToPrefix(id)}net-unrealized-profit-and-loss-to-market-cap-ratio`,
+ `${scale}-to-${datasetIdToPrefix(
+ id,
+ )}net-unrealized-profit-and-loss-to-market-cap-ratio`,
type: "Baseline",
}),
bases[0](scale),
@@ -3466,7 +3376,6 @@ function createPartialOptions(colors) {
scale,
name: "All",
title: `${title} Profit And Loss`,
- icon: "❌",
description: "",
unit: "US Dollars",
bottom: [
@@ -3500,7 +3409,6 @@ function createPartialOptions(colors) {
scale,
name: `Total`,
title: `${title} Total supply`,
- icon: "∑",
description: "",
unit: "Bitcoin",
bottom: cohortOptionOrOptions.toSeriesBlueprints(arg, {
@@ -3514,7 +3422,6 @@ function createPartialOptions(colors) {
title: `${title} Supply In Profit`,
description: "",
unit: "Bitcoin",
- icon: "📈",
bottom: cohortOptionOrOptions.toSeriesBlueprints(arg, {
title: "Supply",
singleColor: colors.profit,
@@ -3528,7 +3435,6 @@ function createPartialOptions(colors) {
title: `${title} Supply In Loss`,
description: "",
unit: "Bitcoin",
- icon: "📉",
bottom: cohortOptionOrOptions.toSeriesBlueprints(arg, {
title: "Supply",
singleColor: colors.loss,
@@ -3548,7 +3454,6 @@ function createPartialOptions(colors) {
title: `${title} Profit And Loss Relative To Circulating Supply`,
description: "",
unit: "Percentage",
- icon: "🔀",
bottom: [
{
title: "In Profit",
@@ -3582,11 +3487,12 @@ function createPartialOptions(colors) {
title: `${title} Total supply Relative To Circulating Supply`,
description: "",
unit: "Percentage",
- icon: "∑",
bottom: cohortOptionOrOptions.toSeriesBlueprints(arg, {
title: "Supply",
genPath: (id) =>
- `${scale}-to-${datasetIdToPrefix(id)}supply-to-circulating-supply-ratio`,
+ `${scale}-to-${datasetIdToPrefix(
+ id,
+ )}supply-to-circulating-supply-ratio`,
}),
},
{
@@ -3595,12 +3501,13 @@ function createPartialOptions(colors) {
title: `${title} Supply In Profit Relative To Circulating Supply`,
description: "",
unit: "Percentage",
- icon: "📈",
bottom: cohortOptionOrOptions.toSeriesBlueprints(arg, {
title: "Supply",
singleColor: colors.profit,
genPath: (id) =>
- `${scale}-to-${datasetIdToPrefix(id)}supply-in-profit-to-circulating-supply-ratio`,
+ `${scale}-to-${datasetIdToPrefix(
+ id,
+ )}supply-in-profit-to-circulating-supply-ratio`,
}),
},
{
@@ -3609,12 +3516,13 @@ function createPartialOptions(colors) {
title: `${title} Supply In Loss Relative To Circulating Supply`,
description: "",
unit: "Percentage",
- icon: "📉",
bottom: cohortOptionOrOptions.toSeriesBlueprints(arg, {
title: "Supply",
singleColor: colors.loss,
genPath: (id) =>
- `${scale}-to-${datasetIdToPrefix(id)}supply-in-loss-to-circulating-supply-ratio`,
+ `${scale}-to-${datasetIdToPrefix(
+ id,
+ )}supply-in-loss-to-circulating-supply-ratio`,
}),
},
],
@@ -3629,7 +3537,6 @@ function createPartialOptions(colors) {
title: `${title} Supply In Profit And Loss Relative To Own Supply`,
description: "",
unit: "Percentage",
- icon: "🔀",
bottom: [
{
title: "In Profit",
@@ -3667,12 +3574,13 @@ function createPartialOptions(colors) {
title: `${title} Supply In Profit Relative To Own Supply`,
description: "",
unit: "Percentage",
- icon: "📈",
bottom: cohortOptionOrOptions.toSeriesBlueprints(arg, {
title: "Supply",
singleColor: colors.profit,
genPath: (id) =>
- `${scale}-to-${datasetIdToPrefix(id)}supply-in-profit-to-own-supply-ratio`,
+ `${scale}-to-${datasetIdToPrefix(
+ id,
+ )}supply-in-profit-to-own-supply-ratio`,
}),
},
{
@@ -3681,12 +3589,13 @@ function createPartialOptions(colors) {
title: `${title} Supply In Loss Relative To Own Supply`,
description: "",
unit: "Percentage",
- icon: "📉",
bottom: cohortOptionOrOptions.toSeriesBlueprints(arg, {
title: "Supply",
singleColor: colors.loss,
genPath: (id) =>
- `${scale}-to-${datasetIdToPrefix(id)}supply-in-loss-to-own-supply-ratio`,
+ `${scale}-to-${datasetIdToPrefix(
+ id,
+ )}supply-in-loss-to-own-supply-ratio`,
}),
},
],
@@ -3729,7 +3638,6 @@ function createPartialOptions(colors) {
title: `${title} Average Price Paid - Realized Price`,
description: "",
unit: "US Dollars",
- icon: "~",
top: cohortOptionOrOptions.toSeriesBlueprints(arg, {
title: "Average",
genPath: (id) =>
@@ -3741,7 +3649,6 @@ function createPartialOptions(colors) {
scale,
name: `Deciles`,
title: `${title} deciles`,
- icon: "🌗",
description: "",
unit: "US Dollars",
top: groups.percentiles
@@ -3767,7 +3674,6 @@ function createPartialOptions(colors) {
title: `${title} ${percentile.title}`,
description: "",
unit: /** @type {const} */ ("US Dollars"),
- icon: "🌓",
top: cohortOptionOrOptions.toSeriesBlueprints(arg, {
title: "Relative Net Unrealized PNL",
genPath: (id) =>
@@ -3800,10 +3706,10 @@ function createPartialOptions(colors) {
* @param {TimeScale} scale
* @returns {PartialOptionsGroup}
*/
- function createLiquidityOptions(scale) {
+ function createAddressLiquidityOptions(scale) {
return createAddressCohortOptionGroups({
scale,
- name: `Split By Liquidity`,
+ name: `By Liquidity`,
list: groups.liquidities.map(({ name, id, key }) => ({
name,
title: name,
@@ -3910,12 +3816,6 @@ function createPartialOptions(colors) {
};
}
- // * @param {Object} args
- // * @param {TimeScale} args.scale
- // * @param {string} args.name
- // * @param {string} args.title
- // * @param {AddressCohortId | LiquidityId} args.datasetId
- // * @param {Color} args.color
/**
* @param {CohortOption | CohortOptions} arg
* @returns {PartialChartOption}
@@ -3929,7 +3829,6 @@ function createPartialOptions(colors) {
title: `${title} Address Count`,
description: "",
unit: "Count",
- icon: "📕",
bottom: cohortOptionOrOptions.toSeriesBlueprints(arg, {
title: "Address Count",
genPath: (id) => `${scale}-to-${id}-address-count`,
@@ -3995,7 +3894,6 @@ function createPartialOptions(colors) {
title: `Total Non Empty Address`,
description: "",
unit: "Count",
- icon: "💳",
bottom: [
{
title: `Total Non Empty Address`,
@@ -4010,7 +3908,6 @@ function createPartialOptions(colors) {
title: `New Addresses`,
description: "",
unit: "Count",
- icon: "🏡",
bottom: [
{
title: `New Addresses`,
@@ -4025,7 +3922,6 @@ function createPartialOptions(colors) {
title: `Total Addresses Created`,
description: "",
unit: "Count",
- icon: "🏠",
bottom: [
{
title: `Total Addresses Created`,
@@ -4040,7 +3936,6 @@ function createPartialOptions(colors) {
title: `Total Empty Addresses`,
description: "",
unit: "Count",
- icon: "🗑️",
bottom: [
{
title: `Total Empty Addresses`,
@@ -4074,6 +3969,7 @@ function createPartialOptions(colors) {
datasetId: key,
})),
}),
+ createAddressLiquidityOptions(scale),
],
};
}
@@ -4091,7 +3987,6 @@ function createPartialOptions(colors) {
tree: [
{
scale,
- icon: "🔀",
name: "All",
title: "All Cointime Prices",
description: "",
@@ -4129,7 +4024,6 @@ function createPartialOptions(colors) {
tree: [
{
scale,
- icon: "❤️",
name: "Price",
title: "Active Price",
description: "",
@@ -4156,7 +4050,6 @@ function createPartialOptions(colors) {
tree: [
{
scale,
- icon: "🏦",
name: "Price",
title: "Vaulted Price",
description: "",
@@ -4183,7 +4076,6 @@ function createPartialOptions(colors) {
tree: [
{
scale,
- icon: "〰️",
name: "Price",
title: "True Market Mean",
description: "",
@@ -4210,7 +4102,6 @@ function createPartialOptions(colors) {
tree: [
{
scale,
- icon: "⏱️",
name: "Price",
title: "Cointime Price",
description: "",
@@ -4239,7 +4130,6 @@ function createPartialOptions(colors) {
tree: [
{
scale,
- icon: "🔀",
name: "All",
title: "Cointime Capitalizations",
description: "",
@@ -4269,7 +4159,6 @@ function createPartialOptions(colors) {
},
{
scale,
- icon: "⛏️",
name: "Thermo Cap",
title: "Thermo Cap",
description: "",
@@ -4284,7 +4173,6 @@ function createPartialOptions(colors) {
},
{
scale,
- icon: "🧑💼",
name: "Investor Cap",
title: "Investor Cap",
description: "",
@@ -4299,7 +4187,6 @@ function createPartialOptions(colors) {
},
{
scale,
- icon: "➗",
name: "Thermo Cap To Investor Cap Ratio",
title: "Thermo Cap To Investor Cap Ratio",
description: "",
@@ -4319,7 +4206,6 @@ function createPartialOptions(colors) {
tree: [
{
scale,
- icon: "🧱",
name: "All",
title: "All Coinblocks",
description: "",
@@ -4353,7 +4239,6 @@ function createPartialOptions(colors) {
},
{
scale,
- icon: "🧊",
name: "Created",
title: "Coinblocks Created",
description: "",
@@ -4371,7 +4256,6 @@ function createPartialOptions(colors) {
},
{
scale,
- icon: "⛓️💥",
name: "Destroyed",
title: "Coinblocks Destroyed",
description: "",
@@ -4389,7 +4273,6 @@ function createPartialOptions(colors) {
},
{
scale,
- icon: "🗄️",
name: "Stored",
title: "Coinblocks Stored",
description: "",
@@ -4412,7 +4295,6 @@ function createPartialOptions(colors) {
tree: [
{
scale,
- icon: "🔀",
name: "All",
title: "All Cumulative Coinblocks",
description: "",
@@ -4437,7 +4319,6 @@ function createPartialOptions(colors) {
},
{
scale,
- icon: "🧊",
name: "Created",
title: "Cumulative Coinblocks Created",
description: "",
@@ -4452,7 +4333,6 @@ function createPartialOptions(colors) {
},
{
scale,
- icon: "⛓️💥",
name: "Destroyed",
title: "Cumulative Coinblocks Destroyed",
description: "",
@@ -4467,7 +4347,6 @@ function createPartialOptions(colors) {
},
{
scale,
- icon: "🗄️",
name: "Stored",
title: "Cumulative Coinblocks Stored",
description: "",
@@ -4487,7 +4366,6 @@ function createPartialOptions(colors) {
tree: [
{
scale,
- icon: "❤️",
name: "Liveliness - Activity",
title: "Liveliness (Activity)",
description: "",
@@ -4502,7 +4380,6 @@ function createPartialOptions(colors) {
},
{
scale,
- icon: "🏦",
name: "Vaultedness",
title: "Vaultedness",
description: "",
@@ -4517,7 +4394,6 @@ function createPartialOptions(colors) {
},
{
scale,
- icon: "⚔️",
name: "Versus",
title: "Liveliness V. Vaultedness",
description: "",
@@ -4537,7 +4413,6 @@ function createPartialOptions(colors) {
},
{
scale,
- icon: "➗",
name: "Activity To Vaultedness Ratio",
title: "Activity To Vaultedness Ratio",
description: "",
@@ -4554,7 +4429,6 @@ function createPartialOptions(colors) {
? /** @satisfies {PartialOptionsTree} */ ([
{
scale,
- icon: "❤️",
name: "Concurrent Liveliness - Supply Adjusted Coindays Destroyed",
title:
"Concurrent Liveliness - Supply Adjusted Coindays Destroyed",
@@ -4575,7 +4449,6 @@ function createPartialOptions(colors) {
},
{
scale,
- icon: "📊",
name: "Liveliness Incremental Change",
title: "Liveliness Incremental Change",
description: "",
@@ -4605,7 +4478,6 @@ function createPartialOptions(colors) {
tree: [
{
scale,
- icon: "🏦",
name: "Vaulted",
title: "Vaulted Supply",
description: "",
@@ -4620,7 +4492,6 @@ function createPartialOptions(colors) {
},
{
scale,
- icon: "❤️",
name: "Active",
title: "Active Supply",
description: "",
@@ -4635,7 +4506,6 @@ function createPartialOptions(colors) {
},
{
scale,
- icon: "⚔️",
name: "Vaulted V. Active",
title: "Vaulted V. Active",
description: "",
@@ -4661,7 +4531,6 @@ function createPartialOptions(colors) {
// TODO: Fix, Bad data
// {
// id: 'asymptomatic-supply-regions',
- // icon: IconTablerDirections,
// name: 'Asymptomatic Supply Regions',
// title: 'Asymptomatic Supply Regions',
// description: '',
@@ -4690,7 +4559,6 @@ function createPartialOptions(colors) {
// },
{
scale,
- icon: "🏦",
name: "Vaulted Net Change",
title: "Vaulted Supply Net Change",
description: "",
@@ -4705,7 +4573,6 @@ function createPartialOptions(colors) {
},
{
scale,
- icon: "❤️",
name: "Active Net Change",
title: "Active Supply Net Change",
description: "",
@@ -4720,7 +4587,6 @@ function createPartialOptions(colors) {
},
{
scale,
- icon: "⚔️",
name: "Active VS. Vaulted 90D Net Change",
title: "Active VS. Vaulted 90 Day Supply Net Change",
description: "",
@@ -4744,7 +4610,6 @@ function createPartialOptions(colors) {
// TODO: Fix, Bad data
// {
// id: 'vaulted-supply-annualized-net-change',
- // icon: IconTablerBuildingBank,
// name: 'Vaulted Annualized Net Change',
// title: 'Vaulted Supply Annualized Net Change',
// description: '',
@@ -4770,7 +4635,6 @@ function createPartialOptions(colors) {
// TODO: Fix, Bad data
// {
// id: 'vaulting-rate',
- // icon: IconTablerBuildingBank,
// name: 'Vaulting Rate',
// title: 'Vaulting Rate',
// description: '',
@@ -4801,7 +4665,6 @@ function createPartialOptions(colors) {
// TODO: Fix, Bad data
// {
// id: 'active-supply-net-change-decomposition',
- // icon: IconTablerArrowsCross,
// name: 'Active Supply Net Change Decomposition (90D)',
// title: 'Active Supply Net 90 Day Change Decomposition',
// description: '',
@@ -4841,7 +4704,6 @@ function createPartialOptions(colors) {
{
scale,
- icon: "📈",
name: "In Profit",
title: "Cointime Supply In Profit",
description: "",
@@ -4866,7 +4728,6 @@ function createPartialOptions(colors) {
},
{
scale,
- icon: "📉",
name: "In Loss",
title: "Cointime Supply In Loss",
description: "",
@@ -4898,7 +4759,6 @@ function createPartialOptions(colors) {
tree: [
{
scale,
- icon: "🏭",
name: "Normal",
title: "Cointime Yearly Inflation Rate",
description: "",
@@ -4918,7 +4778,6 @@ function createPartialOptions(colors) {
},
{
scale,
- icon: "🏭",
name: "Yearly",
title: "Cointime-Adjusted Yearly Inflation Rate",
description: "",
@@ -4941,7 +4800,6 @@ function createPartialOptions(colors) {
{
scale,
- icon: "💨",
name: "Cointime Velocity",
title: "Cointime-Adjusted Transactions Velocity",
description: "",
@@ -4965,6 +4823,17 @@ function createPartialOptions(colors) {
};
}
+ /**
+ * @param {TimeScale} scale
+ * @returns {PartialOptionsGroup}
+ */
+ function createResearchOptions(scale) {
+ return {
+ name: "Research",
+ tree: [createCointimeOptions(scale)],
+ };
+ }
+
return [
{
name: "Charts",
@@ -4985,8 +4854,7 @@ function createPartialOptions(colors) {
}),
createHodlersOptions("date"),
createAddressesOptions("date"),
- createLiquidityOptions("date"),
- createCointimeOptions("date"),
+ createResearchOptions("date"),
],
},
{
@@ -5005,8 +4873,7 @@ function createPartialOptions(colors) {
}),
createHodlersOptions("height"),
createAddressesOptions("height"),
- createLiquidityOptions("height"),
- createCointimeOptions("height"),
+ createResearchOptions("height"),
],
},
],
@@ -5015,7 +4882,6 @@ function createPartialOptions(colors) {
name: "Simulations",
tree: [
{
- icon: "💰",
kind: "simulation",
title: "Simulation: Save In Bitcoin",
name: "Save In Bitcoin",
@@ -5029,9 +4895,8 @@ function createPartialOptions(colors) {
name: "Satoshi Nakamoto",
tree: [
{
- icon: "📄",
name: "Whitepaper",
- file: "satoshi-nakamoto/whitepaper.pdf",
+ pdf: "satoshi-nakamoto/whitepaper.pdf",
},
],
},
@@ -5039,9 +4904,8 @@ function createPartialOptions(colors) {
name: "Nydig",
tree: [
{
- icon: "⚖️",
name: "Bitcoin's Protection Under The First Amendment",
- file: "nydig/protection-under-first-amendment.pdf",
+ pdf: "nydig/protection-under-first-amendment.pdf",
},
],
},
@@ -5049,9 +4913,8 @@ function createPartialOptions(colors) {
name: "Nakamoto Project",
tree: [
{
- icon: "🇺🇸",
name: "Understanding Bitcoin Adoption In The United States",
- file: "nakamoto-project/understanding-bitcoin-adoption-in-the-united-states.pdf",
+ pdf: "nakamoto-project/understanding-bitcoin-adoption-in-the-united-states.pdf",
},
],
},
@@ -5059,9 +4922,8 @@ function createPartialOptions(colors) {
name: "Block",
tree: [
{
- icon: "🤔",
name: "Knowledge And Perceptions - 2022 Report",
- file: "block/2022-report.pdf",
+ pdf: "block/2022-report.pdf",
},
],
},
@@ -5069,9 +4931,8 @@ function createPartialOptions(colors) {
name: "Square",
tree: [
{
- icon: "⚡️",
name: "Clean Energy Initiative - 2021 Report",
- file: "square/2021-bitcoin-clean-energy-initiative.pdf",
+ pdf: "square/2021-bitcoin-clean-energy-initiative.pdf",
},
],
},
@@ -5079,9 +4940,8 @@ function createPartialOptions(colors) {
name: "Braiins",
tree: [
{
- icon: "🦀",
name: "Building Bitcoin In Rust",
- file: "braiins/building-bitcoin-in-rust.pdf",
+ pdf: "braiins/building-bitcoin-in-rust.pdf",
},
],
},
@@ -5089,14 +4949,59 @@ function createPartialOptions(colors) {
name: "Glassnode",
tree: [
{
- icon: "🏦",
name: "Cointime Economics",
- file: "glassnode/cointime-economics.pdf",
+ pdf: "glassnode/cointime-economics.pdf",
},
],
},
],
},
+ {
+ name: "Donations",
+ tree: [
+ {
+ name: "Donate on-chain",
+ qrcode: true,
+ url: () => "bitcoin:bc1q950q4ukpxxm6wjjkv6cpq8jzpazaxrrwftctkt",
+ },
+ {
+ name: "Donate lightning",
+ qrcode: true,
+ url: () =>
+ "lightning:lnurl1dp68gurn8ghj7ampd3kx2ar0veekzar0wd5xjtnrdakj7tnhv4kxctttdehhwm30d3h82unvwqhkxmmww3jkuar8d35kgetj8yuq363hv4",
+ },
+ {
+ name: "Fundraiser",
+ url: () => "https://geyser.fund/project/kibo",
+ },
+ {
+ name: "Goals",
+ url: () => "https://geyser.fund/project/kibo/goals",
+ },
+ {
+ name: "Leaderboard",
+ url: () => "https://geyser.fund/project/kibo/leaderboard",
+ },
+ ],
+ },
+ {
+ name: "Share",
+ qrcode: true,
+ url: () => window.location.href,
+ },
+ {
+ name: "Social",
+ url: () =>
+ "https://primal.net/p/npub1jagmm3x39lmwfnrtvxcs9ac7g300y3dusv9lgzhk2e4x5frpxlrqa73v44",
+ },
+ {
+ name: "Source",
+ url: () => "https://github.com/kibo-money/kibo",
+ },
+ {
+ name: "API",
+ url: () => "/api",
+ },
];
}
@@ -5109,6 +5014,7 @@ function createPartialOptions(colors) {
* @param {Utilities} args.utils
* @param {Signal | null>} args.lastValues
* @param {WebSockets} args.webSockets
+ * @param {Signal} args.qrcode
*/
export function initOptions({
colors,
@@ -5118,6 +5024,7 @@ export function initOptions({
utils,
lastValues,
webSockets,
+ qrcode,
}) {
const urlSelected = utils.url.pathnameToSelectedId();
const savedSelectedId = localStorage.getItem(ids.selectedId);
@@ -5133,49 +5040,6 @@ export function initOptions({
/** @type {HTMLDetailsElement[]} */
const detailsList = [];
- const filter = signals.createSignal(
- /** @type {FoldersFilter} */ (
- localStorage.getItem(ids.foldersFilter) || "all"
- ),
- );
-
- function initCounters() {
- const favoritesCount = signals.createSignal(0);
- const newCount = signals.createSignal(0);
-
- /** @param {Option} option */
- function createCountersEffects(option) {
- let firstFavoritesRun = true;
-
- signals.createEffect(option.isFavorite, (favorite) => {
- if (favorite) {
- favoritesCount.set((c) => c + 1);
- } else if (!firstFavoritesRun) {
- favoritesCount.set((c) => c - 1);
- }
- firstFavoritesRun = false;
- });
-
- let firstNewRun = true;
-
- signals.createEffect(option.visited, (visited) => {
- if (!visited) {
- newCount.set((c) => c + 1);
- } else if (!firstNewRun) {
- newCount.set((c) => c - 1);
- }
- firstNewRun = false;
- });
- }
-
- return {
- favorites: favoritesCount,
- new: newCount,
- createEffects: createCountersEffects,
- };
- }
- const counters = initCounters();
-
const treeElement = signals.createSignal(
/** @type {HTMLDivElement | null} */ (null),
);
@@ -5183,20 +5047,6 @@ export function initOptions({
/** @type {string[] | undefined} */
const optionsIds = env.localhost ? [] : undefined;
- /**
- * @param {Option} option
- */
- function optionToVisitedKey(option) {
- return `${option.id}-visited`;
- }
-
- /**
- * @param {Option} option
- */
- function optionToFavoriteKey(option) {
- return `${option.id}-favorite`;
- }
-
/**
* @param {SeriesBlueprint[]} array
*/
@@ -5263,131 +5113,151 @@ export function initOptions({
* @param {Object} args
* @param {Option} args.option
* @param {string} args.frame
+ * @param {Signal} args.qrcode
* @param {string} [args.name]
* @param {string} [args.top]
* @param {string} [args.id]
* @param {Owner | null} [args.owner]
*/
- function createOptionLabeledInput({ option, frame, name, top, id, owner }) {
- const { input, label, spanMain } = utils.dom.createComplexLabeledInput({
- inputId: `${option.id}-${frame}${id || ""}-selector`,
- inputValue: option.id,
- inputName: `option-${frame}${id || ""}`,
- labelTitle: option.title,
- name: name || option.name,
- onClick: () => {
- selected.set(option);
- },
- href: `/${option.kind === "pdf" ? option.file : option.id}`,
- });
+ function createOptionElement({
+ option,
+ frame,
+ name,
+ top,
+ id,
+ owner,
+ qrcode,
+ }) {
+ switch (option.kind) {
+ case "pdf": {
+ return utils.dom.createAnchorElement({
+ href: option.pdf,
+ blank: true,
+ text: option.name,
+ });
+ }
+ case "url": {
+ const href = option.url();
- if (top) {
- const small = window.document.createElement("small");
- small.innerHTML = top;
- label.insertBefore(small, spanMain);
- }
-
- const spanEmoji = window.document.createElement("span");
- spanEmoji.classList.add("emoji");
- spanEmoji.innerHTML = option.icon;
- spanMain.prepend(spanEmoji);
-
- if (option.kind === "chart") {
- const spanValue = window.document.createElement("span");
- spanValue.classList.add("value");
- spanMain.append(spanValue);
-
- if (!option.top?.length && !option.bottom?.length) {
- signals.createEffect(
- () => webSockets.krakenCandle.latest()?.close ?? lastValues()?.close,
- (close) => {
- if (close) {
- spanValue.innerHTML = formatValue(close, "US Dollars");
- }
- },
- );
- } else if (option.bottom?.length) {
- const bottom = option.bottom;
- const id = getMainIdFromBlueprints(bottom);
-
- if (id) {
- signals.createEffect(lastValues, (lastValues) => {
- if (lastValues) {
- spanValue.innerHTML = formatValue(lastValues[id], option.unit);
- }
+ if (option.qrcode) {
+ return utils.dom.createButtonElement({
+ text: option.name,
+ onClick: () => {
+ qrcode.set(option.url);
+ },
});
- }
- } else if (option.top?.length) {
- const top = option.top;
- const id = getMainIdFromBlueprints(top);
-
- if (id) {
- signals.createEffect(lastValues, (lastValues) => {
- if (lastValues) {
- spanValue.innerHTML = formatValue(lastValues[id], option.unit);
- }
+ } else {
+ return utils.dom.createAnchorElement({
+ href,
+ blank: true,
+ text: option.name,
});
}
}
- }
+ default: {
+ const { input, label } = utils.dom.createLabeledInput({
+ inputId: `${option.id}-${frame}${id || ""}-selector`,
+ inputValue: option.id,
+ inputName: `option-${frame}${id || ""}`,
+ labelTitle: option.title,
+ // name: name || option.name,
+ onClick: () => {
+ selected.set(option);
+ },
+ });
- /** @type {HTMLSpanElement | undefined} */
- let spanNew;
+ const anchor = utils.dom.createAnchorElement({
+ href: `/${option.id}`,
+ text: name || option.name,
+ onClick: () => {},
+ });
- if (!option.visited()) {
- spanNew = window.document.createElement("span");
- spanNew.classList.add("new");
- spanMain.append(spanNew);
- }
+ label.append(anchor);
- function createFavoriteEffect() {
- let wasFavorite = false;
- /** @type {HTMLElement | undefined} */
- let iconFavorite = undefined;
- signals.createEffect(
- option.isFavorite,
- (isFavorite) => {
- if (!wasFavorite && isFavorite) {
- iconFavorite = window.document.createElement("svg");
- spanMain.append(iconFavorite);
- iconFavorite.outerHTML =
- ' ';
- } else if (wasFavorite && !isFavorite) {
- iconFavorite?.remove();
- iconFavorite = undefined;
+ if (top) {
+ const small = window.document.createElement("small");
+ small.innerHTML = top;
+ label.insertBefore(small, anchor);
+ }
+
+ if (option.kind === "chart") {
+ const valueElement = window.document.createElement("small");
+ valueElement.classList.add("value");
+
+ if (!option.top?.length && !option.bottom?.length) {
+ anchor.append(valueElement);
+
+ signals.createEffect(
+ () =>
+ webSockets.krakenCandle.latest()?.close ?? lastValues()?.close,
+ (close) => {
+ if (close) {
+ valueElement.innerHTML = formatValue(close, "US Dollars");
+ }
+ },
+ );
+ } else if (option.bottom?.length) {
+ const bottom = option.bottom;
+ const id = getMainIdFromBlueprints(bottom);
+
+ if (id) {
+ anchor.append(valueElement);
+
+ console.log("a", lastValues());
+
+ signals.createEffect(lastValues, (lastValues) => {
+ console.log(lastValues);
+ if (lastValues) {
+ valueElement.innerHTML = formatValue(
+ lastValues[id],
+ option.unit,
+ );
+ }
+ });
+ }
+ } else if (option.top?.length) {
+ const top = option.top;
+ const id = getMainIdFromBlueprints(top);
+
+ if (id) {
+ anchor.append(valueElement);
+
+ signals.createEffect(lastValues, (lastValues) => {
+ if (lastValues) {
+ valueElement.innerHTML = formatValue(
+ lastValues[id],
+ option.unit,
+ );
+ }
+ });
+ }
}
- wasFavorite = isFavorite;
- },
- false,
- );
- }
+ function createCheckEffect() {
+ signals.createEffect(selected, (selected) => {
+ if (selected?.id === option.id) {
+ input.checked = true;
+ localStorage.setItem(ids.selectedId, option.id);
+ } else if (input.checked) {
+ input.checked = false;
+ }
+ });
+ }
- function createCheckEffect() {
- signals.createEffect(selected, (selected) => {
- if (selected?.id === option.id) {
- input.checked = true;
- spanNew?.remove();
- option.visited.set(true);
- localStorage.setItem(optionToVisitedKey(option), "1");
- localStorage.setItem(ids.selectedId, option.id);
- } else if (input.checked) {
- input.checked = false;
+ if (owner !== undefined) {
+ signals.runWithOwner(owner, () => {
+ createCheckEffect();
+ });
+ } else {
+ createCheckEffect();
+ }
+
+ return label;
+ } else {
+ console.log(option);
}
- });
+ }
}
-
- if (owner !== undefined) {
- signals.runWithOwner(owner, () => {
- createCheckEffect();
- createFavoriteEffect();
- });
- } else {
- createCheckEffect();
- createFavoriteEffect();
- }
-
- return label;
}
/**
@@ -5488,37 +5358,27 @@ export function initOptions({
});
const details = window.document.createElement("details");
- const folderOpenLocalStorageKey = `${folderId}-open`;
- details.open = !!localStorage.getItem(folderOpenLocalStorageKey);
details.id = folderId;
detailsList.push(details);
li.appendChild(details);
const summary = window.document.createElement("summary");
- details.appendChild(summary);
-
- const spanMarker = window.document.createElement("span");
- spanMarker.classList.add("marker");
- summary.append(spanMarker);
-
- const spanName = utils.dom.createSpanName(anyPartial.name);
- summary.append(spanName);
+ details.append(summary);
+ summary.append(anyPartial.name);
const supCount = window.document.createElement("sup");
+ summary.append(supCount);
signals.createEffect(childOptionsCount, (childOptionsCount) => {
supCount.innerHTML = childOptionsCount.toLocaleString();
});
- spanName.append(supCount);
details.addEventListener("toggle", () => {
const open = details.open;
if (open) {
- localStorage.setItem(folderOpenLocalStorageKey, "1");
passedDetails.set(details);
} else {
- localStorage.removeItem(folderOpenLocalStorageKey);
passedDetails.set(null);
}
});
@@ -5542,11 +5402,15 @@ export function initOptions({
kind = anyPartial.kind;
id = anyPartial.kind;
title = anyPartial.title;
- } else if ("file" in anyPartial) {
+ } else if ("pdf" in anyPartial) {
kind = "pdf";
id = `${ids.fromString(anyPartial.name)}-pdf`;
title = anyPartial.name;
- anyPartial.file = `assets/pdfs/${anyPartial.file}`;
+ anyPartial.pdf = `/assets/pdfs/${anyPartial.pdf}`;
+ } else if ("url" in anyPartial) {
+ kind = "url";
+ id = `${ids.fromString(anyPartial.name)}-url`;
+ title = anyPartial.name;
} else if ("scale" in anyPartial) {
kind = "chart";
id = `chart-${anyPartial.scale}-to-${ids.fromString(
@@ -5569,11 +5433,10 @@ export function initOptions({
...(path || []).map(({ name }) => name),
anyPartial.name,
].join(" / ")}`,
- isFavorite: signals.createSignal(false),
- visited: signals.createSignal(false),
+ title,
};
- Object.assign(anyPartial, optionAddons, { kind, title });
+ Object.assign(anyPartial, optionAddons, { kind });
const option = /** @type {Option} */ (anyPartial);
@@ -5583,52 +5446,9 @@ export function initOptions({
selected.set(option);
}
- option.isFavorite.set(
- !!localStorage.getItem(optionToFavoriteKey(option)),
- );
- option.visited.set(!!localStorage.getItem(optionToVisitedKey(option)));
-
- counters.createEffects(option);
-
list.push(option);
optionsIds?.push(option.id);
- const hidden = signals.createSignal(true);
-
- function createHiddenEffect() {
- signals.createEffect(
- () => ({
- filter: filter(),
- favorite: option.isFavorite(),
- visited: option.visited(),
- }),
- ({ filter, favorite, visited }) => {
- switch (filter) {
- case "all": {
- hidden.set(false);
- break;
- }
- case "favorites": {
- hidden.set(!favorite);
- break;
- }
- case "new": {
- hidden.set(visited);
- break;
- }
- }
- },
- );
- }
- createHiddenEffect();
-
- function createRenderLiEffect() {
- signals.createEffect(hidden, (hidden) => {
- renderLi.set(!hidden);
- });
- }
- createRenderLiEffect();
-
signals.createEffect(li, (li) => {
if (!li) {
return;
@@ -5642,17 +5462,18 @@ export function initOptions({
}
});
- const label = createOptionLabeledInput({
+ const element = createOptionElement({
option,
- frame: "folders",
+ frame: "nav",
+ qrcode,
});
- li.append(label);
+ if (element) {
+ li.append(element);
+ }
});
- const memo = signals.createMemo(() => (hidden() ? 0 : 1));
-
- listForSum.push(memo);
+ listForSum.push(() => 1);
}
});
@@ -5698,12 +5519,8 @@ export function initOptions({
list,
details: detailsList,
tree: /** @type {OptionsTree} */ (partialOptions),
- counters,
- filter,
treeElement,
- optionToVisitedKey,
- createOptionLabeledInput,
- optionToFavoriteKey,
+ createOptionElement,
/**
* @param {Option} option
* @param {Series | SeriesBlueprint} series
diff --git a/website/scripts/service-worker.js b/website/scripts/service-worker.js
index 1f86d6079..35e78fd55 100644
--- a/website/scripts/service-worker.js
+++ b/website/scripts/service-worker.js
@@ -17,9 +17,11 @@ self.addEventListener("install", (_event) => {
"/scripts/options.js",
"/scripts/chart.js",
"/styles/chart.css",
+ "/scripts/simulation.js",
+ "/styles/simulation.css",
"/packages/lean-qr/v2.3.4/script.js",
"/packages/lightweight-charts/v4.2.0/script.js",
- "/packages/solid-signals/2024-11-01/script.js",
+ "/packages/solid-signals/2024-11-02/script.js",
"/packages/ufuzzy/v1.0.14/script.js",
]);
}),
diff --git a/website/scripts/types/self.d.ts b/website/scripts/types/self.d.ts
index 84f954efa..93be593e6 100644
--- a/website/scripts/types/self.d.ts
+++ b/website/scripts/types/self.d.ts
@@ -1,7 +1,7 @@
import {
Accessor,
Setter,
-} from "../../packages/solid-signals/2024-11-01/types/signals";
+} from "../../packages/solid-signals/2024-11-02/types/signals";
import {
DeepPartial,
BaselineStyleOptions,
@@ -17,7 +17,7 @@ import {
ISeriesApi,
} from "../../packages/lightweight-charts/v4.2.0/types";
import { DatePath, HeightPath, LastPath } from "./paths";
-import { Owner } from "../../packages/solid-signals/2024-11-01/types/core/owner";
+import { Owner } from "../../packages/solid-signals/2024-11-02/types/core/owner";
import { AnyPossibleCohortId } from "../options";
type GrowToSize = A["length"] extends N
@@ -28,9 +28,6 @@ type FixedArray = GrowToSize;
type Signal = Accessor & { set: Setter };
-type SettingsTheme = "system" | "dark" | "light";
-type FoldersFilter = "all" | "favorites" | "new";
-
type TimeScale = "date" | "height";
type TimeRange = Range;
@@ -104,7 +101,7 @@ type Unit =
| "Weight";
interface PartialOption {
- icon: string;
+ // icon: string;
name: string;
}
@@ -135,7 +132,12 @@ interface PartialSimulationOption extends PartialOption {
}
interface PartialPdfOption extends PartialOption {
- file: string;
+ pdf: string;
+}
+
+interface PartialUrlOption extends PartialOption {
+ qrcode?: true;
+ url: () => string;
}
interface PartialOptionsGroup {
@@ -147,7 +149,8 @@ type AnyPartialOption =
| PartialHomeOption
| PartialChartOption
| PartialSimulationOption
- | PartialPdfOption;
+ | PartialPdfOption
+ | PartialUrlOption;
type PartialOptionsTree = (AnyPartialOption | PartialOptionsGroup)[];
@@ -155,8 +158,7 @@ interface ProcessedOptionAddons {
id: string;
path: OptionPath;
serializedPath: string;
- isFavorite: Signal;
- visited: Signal;
+ title: string;
}
type OptionPath = {
@@ -169,14 +171,22 @@ type SimulationOption = PartialSimulationOption & ProcessedOptionAddons;
interface PdfOption extends PartialPdfOption, ProcessedOptionAddons {
kind: "pdf";
- title: string;
+}
+
+interface UrlOption extends PartialUrlOption, ProcessedOptionAddons {
+ kind: "url";
}
interface ChartOption extends PartialChartOption, ProcessedOptionAddons {
kind: "chart";
}
-type Option = HomeOption | PdfOption | ChartOption | SimulationOption;
+type Option =
+ | HomeOption
+ | PdfOption
+ | UrlOption
+ | ChartOption
+ | SimulationOption;
type OptionsTree = (Option | OptionsGroup)[];
@@ -185,8 +195,6 @@ interface OptionsGroup extends PartialOptionsGroup {
tree: OptionsTree;
}
-type SerializedHistory = [string, number][];
-
interface OHLC {
open: number;
high: number;
diff --git a/website/styles/chart.css b/website/styles/chart.css
index b8456078d..e63f7db6c 100644
--- a/website/styles/chart.css
+++ b/website/styles/chart.css
@@ -8,8 +8,8 @@
display: flex;
align-items: center;
gap: 1.5rem;
- margin: -1rem -1.5rem;
- padding: 1rem 1.5rem;
+ margin: -1rem var(--negative-main-padding);
+ padding: 1rem var(--main-padding);
overflow-x: auto;
min-width: 0;
@@ -26,7 +26,6 @@
color: var(--off-color);
> span.main > span.name {
- text-decoration-style: wavy;
text-decoration-thickness: 1.5px;
text-decoration-color: var(--color);
text-decoration-line: line-through;
@@ -61,8 +60,8 @@
> #chart-list {
margin-top: 1rem;
position: relative;
- margin-left: -1.5rem /* -24px */;
- margin-right: -2rem /* -32px */;
+ margin-left: var(--negative-main-padding);
+ margin-right: calc(var(--negative-main-padding) - 0.5rem);
display: flex;
flex-direction: column;
flex: 1;
@@ -88,17 +87,38 @@
z-index: 10;
display: flex;
align-items: center;
- padding-left: 1.5rem /* 24px */;
- padding-right: 1.5rem /* 24px */;
+ padding-left: var(--main-padding);
+ padding-right: var(--main-padding);
font-size: var(--font-size-xs);
line-height: var(--line-height-xs);
+ gap: 0.5rem;
+ color: var(--off-color);
- > * + * {
- margin-left: 0.5rem; /* 8px */
- }
+ > div.field {
+ display: flex;
+ align-items: center;
+ font-size: var(--font-size-xs);
+ line-height: var(--line-height-xs);
+ gap: 1rem;
- > * + span {
- color: var(--off-color);
+ > legend,
+ > div {
+ flex-shrink: 0;
+ }
+
+ > hr {
+ min-width: 1rem;
+ }
+
+ label {
+ padding: 0.5rem;
+ margin: -0.5rem;
+ }
+
+ > div {
+ display: flex;
+ gap: 0.5rem;
+ }
}
}
@@ -108,37 +128,4 @@
}
}
}
-
- > hr {
- margin-top: 1rem;
- }
-
- > #timescale {
- > #timescale-date-buttons,
- > #timescale-height-buttons {
- display: flex;
- overflow-x: auto;
- display: flex;
- overflow-x: auto;
- margin-bottom: -0.5rem;
- padding: 0.5rem 0.5rem;
- padding-top: 0.5rem;
- margin-left: -1.5rem;
- margin-right: -1.5rem;
-
- > button {
- color: var(--off-color);
- flex-shrink: 0;
- flex-grow: 1;
- padding: 0.5rem;
- white-space: nowrap;
- min-width: 5rem;
- }
-
- @media (max-width: 767px) {
- margin-bottom: -1.5rem;
- padding-top: 0.5rem;
- }
- }
- }
}