diff --git a/README.md b/README.md
index 54eb47e..5b4ecd7 100644
--- a/README.md
+++ b/README.md
@@ -1,12 +1,19 @@
# F# Tour
+
A guided interactive tour of the F# language.
## Development
+
+### Prerequisites
+* .NET 8.0
+* NodeJS (npm)
+
+### Running the Application
```
dotnet fsi build.fsx -- -p Setup
npm start
```
## Inspirations
-- [Fable REPL](https://github.com/fable-compiler/repl)
-- [Gleam Language Tour](https://tour.gleam.run)
\ No newline at end of file
+- Originally based on the [Gleam Language Tour](https://tour.gleam.run) and the [Kotlin Tour](https://kotlinlang.org/docs/kotlin-tour-welcome.html)
+- The core logic for compiling F# in the browser is based on the work done in the [Fable REPL](https://github.com/fable-compiler/repl).
\ No newline at end of file
diff --git a/index.html b/index.html
index 0c3da25..31dd5dd 100644
--- a/index.html
+++ b/index.html
@@ -6,23 +6,13 @@
F# Tour
-
-
+
+
-
+
diff --git a/package-lock.json b/package-lock.json
index caba1e2..e319af3 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -4,74 +4,75 @@
"requires": true,
"packages": {
"": {
+ "name": "fsharpforyou-tour",
"dependencies": {
- "@fable-org/fable-metadata": "^1.0.0",
- "@fable-org/fable-standalone": "^1.1.0",
+ "@fable-org/fable-metadata": "^1.1.0",
+ "@fable-org/fable-standalone": "^1.9.0",
"@monaco-editor/react": "^4.6.0",
+ "lz-string": "^1.5.0",
"monaco-editor": "^0.46.0",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-markdown": "^8.0.4",
- "react-syntax-highlighter": "^15.5.0",
"react-toastify": "^9.1.3",
"use-sync-external-store": "^1.2.0"
},
"devDependencies": {
- "@vitejs/plugin-react": "^4.2.1",
- "vite": "^5.0.12"
+ "@vitejs/plugin-react": "^4.3.1",
+ "vite": "^5.3.3"
}
},
"node_modules/@ampproject/remapping": {
- "version": "2.2.1",
- "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.1.tgz",
- "integrity": "sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg==",
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz",
+ "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==",
"dev": true,
"dependencies": {
- "@jridgewell/gen-mapping": "^0.3.0",
- "@jridgewell/trace-mapping": "^0.3.9"
+ "@jridgewell/gen-mapping": "^0.3.5",
+ "@jridgewell/trace-mapping": "^0.3.24"
},
"engines": {
"node": ">=6.0.0"
}
},
"node_modules/@babel/code-frame": {
- "version": "7.23.5",
- "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.23.5.tgz",
- "integrity": "sha512-CgH3s1a96LipHCmSUmYFPwY7MNx8C3avkq7i4Wl3cfa662ldtUe4VM1TPXX70pfmrlWTb6jLqTYrZyT2ZTJBgA==",
+ "version": "7.24.7",
+ "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.7.tgz",
+ "integrity": "sha512-BcYH1CVJBO9tvyIZ2jVeXgSIMvGZ2FDRvDdOIVQyuklNKSsx+eppDEBq/g47Ayw+RqNFE+URvOShmf+f/qwAlA==",
"dev": true,
"dependencies": {
- "@babel/highlight": "^7.23.4",
- "chalk": "^2.4.2"
+ "@babel/highlight": "^7.24.7",
+ "picocolors": "^1.0.0"
},
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/compat-data": {
- "version": "7.23.5",
- "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.23.5.tgz",
- "integrity": "sha512-uU27kfDRlhfKl+w1U6vp16IuvSLtjAxdArVXPa9BvLkrr7CYIsxH5adpHObeAGY/41+syctUWOZ140a2Rvkgjw==",
+ "version": "7.24.8",
+ "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.24.8.tgz",
+ "integrity": "sha512-c4IM7OTg6k1Q+AJ153e2mc2QVTezTwnb4VzquwcyiEzGnW0Kedv4do/TrkU98qPeC5LNiMt/QXwIjzYXLBpyZg==",
"dev": true,
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/core": {
- "version": "7.23.9",
- "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.23.9.tgz",
- "integrity": "sha512-5q0175NOjddqpvvzU+kDiSOAk4PfdO6FvwCWoQ6RO7rTzEe8vlo+4HVfcnAREhD4npMs0e9uZypjTwzZPCf/cw==",
+ "version": "7.24.8",
+ "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.24.8.tgz",
+ "integrity": "sha512-6AWcmZC/MZCO0yKys4uhg5NlxL0ESF3K6IAaoQ+xSXvPyPyxNWRafP+GDbI88Oh68O7QkJgmEtedWPM9U0pZNg==",
"dev": true,
"dependencies": {
"@ampproject/remapping": "^2.2.0",
- "@babel/code-frame": "^7.23.5",
- "@babel/generator": "^7.23.6",
- "@babel/helper-compilation-targets": "^7.23.6",
- "@babel/helper-module-transforms": "^7.23.3",
- "@babel/helpers": "^7.23.9",
- "@babel/parser": "^7.23.9",
- "@babel/template": "^7.23.9",
- "@babel/traverse": "^7.23.9",
- "@babel/types": "^7.23.9",
+ "@babel/code-frame": "^7.24.7",
+ "@babel/generator": "^7.24.8",
+ "@babel/helper-compilation-targets": "^7.24.8",
+ "@babel/helper-module-transforms": "^7.24.8",
+ "@babel/helpers": "^7.24.8",
+ "@babel/parser": "^7.24.8",
+ "@babel/template": "^7.24.7",
+ "@babel/traverse": "^7.24.8",
+ "@babel/types": "^7.24.8",
"convert-source-map": "^2.0.0",
"debug": "^4.1.0",
"gensync": "^1.0.0-beta.2",
@@ -87,14 +88,14 @@
}
},
"node_modules/@babel/generator": {
- "version": "7.23.6",
- "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.6.tgz",
- "integrity": "sha512-qrSfCYxYQB5owCmGLbl8XRpX1ytXlpueOb0N0UmQwA073KZxejgQTzAmJezxvpwQD9uGtK2shHdi55QT+MbjIw==",
+ "version": "7.24.8",
+ "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.24.8.tgz",
+ "integrity": "sha512-47DG+6F5SzOi0uEvK4wMShmn5yY0mVjVJoWTphdY2B4Rx9wHgjK7Yhtr0ru6nE+sn0v38mzrWOlah0p/YlHHOQ==",
"dev": true,
"dependencies": {
- "@babel/types": "^7.23.6",
- "@jridgewell/gen-mapping": "^0.3.2",
- "@jridgewell/trace-mapping": "^0.3.17",
+ "@babel/types": "^7.24.8",
+ "@jridgewell/gen-mapping": "^0.3.5",
+ "@jridgewell/trace-mapping": "^0.3.25",
"jsesc": "^2.5.1"
},
"engines": {
@@ -102,14 +103,14 @@
}
},
"node_modules/@babel/helper-compilation-targets": {
- "version": "7.23.6",
- "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.23.6.tgz",
- "integrity": "sha512-9JB548GZoQVmzrFgp8o7KxdgkTGm6xs9DW0o/Pim72UDjzr5ObUQ6ZzYPqA+g9OTS2bBQoctLJrky0RDCAWRgQ==",
+ "version": "7.24.8",
+ "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.24.8.tgz",
+ "integrity": "sha512-oU+UoqCHdp+nWVDkpldqIQL/i/bvAv53tRqLG/s+cOXxe66zOYLU7ar/Xs3LdmBihrUMEUhwu6dMZwbNOYDwvw==",
"dev": true,
"dependencies": {
- "@babel/compat-data": "^7.23.5",
- "@babel/helper-validator-option": "^7.23.5",
- "browserslist": "^4.22.2",
+ "@babel/compat-data": "^7.24.8",
+ "@babel/helper-validator-option": "^7.24.8",
+ "browserslist": "^4.23.1",
"lru-cache": "^5.1.1",
"semver": "^6.3.1"
},
@@ -118,62 +119,66 @@
}
},
"node_modules/@babel/helper-environment-visitor": {
- "version": "7.22.20",
- "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz",
- "integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==",
+ "version": "7.24.7",
+ "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.24.7.tgz",
+ "integrity": "sha512-DoiN84+4Gnd0ncbBOM9AZENV4a5ZiL39HYMyZJGZ/AZEykHYdJw0wW3kdcsh9/Kn+BRXHLkkklZ51ecPKmI1CQ==",
"dev": true,
+ "dependencies": {
+ "@babel/types": "^7.24.7"
+ },
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/helper-function-name": {
- "version": "7.23.0",
- "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz",
- "integrity": "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==",
+ "version": "7.24.7",
+ "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.24.7.tgz",
+ "integrity": "sha512-FyoJTsj/PEUWu1/TYRiXTIHc8lbw+TDYkZuoE43opPS5TrI7MyONBE1oNvfguEXAD9yhQRrVBnXdXzSLQl9XnA==",
"dev": true,
"dependencies": {
- "@babel/template": "^7.22.15",
- "@babel/types": "^7.23.0"
+ "@babel/template": "^7.24.7",
+ "@babel/types": "^7.24.7"
},
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/helper-hoist-variables": {
- "version": "7.22.5",
- "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz",
- "integrity": "sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==",
+ "version": "7.24.7",
+ "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.24.7.tgz",
+ "integrity": "sha512-MJJwhkoGy5c4ehfoRyrJ/owKeMl19U54h27YYftT0o2teQ3FJ3nQUf/I3LlJsX4l3qlw7WRXUmiyajvHXoTubQ==",
"dev": true,
"dependencies": {
- "@babel/types": "^7.22.5"
+ "@babel/types": "^7.24.7"
},
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/helper-module-imports": {
- "version": "7.22.15",
- "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.22.15.tgz",
- "integrity": "sha512-0pYVBnDKZO2fnSPCrgM/6WMc7eS20Fbok+0r88fp+YtWVLZrp4CkafFGIp+W0VKw4a22sgebPT99y+FDNMdP4w==",
+ "version": "7.24.7",
+ "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.24.7.tgz",
+ "integrity": "sha512-8AyH3C+74cgCVVXow/myrynrAGv+nTVg5vKu2nZph9x7RcRwzmh0VFallJuFTZ9mx6u4eSdXZfcOzSqTUm0HCA==",
"dev": true,
"dependencies": {
- "@babel/types": "^7.22.15"
+ "@babel/traverse": "^7.24.7",
+ "@babel/types": "^7.24.7"
},
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/helper-module-transforms": {
- "version": "7.23.3",
- "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.23.3.tgz",
- "integrity": "sha512-7bBs4ED9OmswdfDzpz4MpWgSrV7FXlc3zIagvLFjS5H+Mk7Snr21vQ6QwrsoCGMfNC4e4LQPdoULEt4ykz0SRQ==",
+ "version": "7.24.8",
+ "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.24.8.tgz",
+ "integrity": "sha512-m4vWKVqvkVAWLXfHCCfff2luJj86U+J0/x+0N3ArG/tP0Fq7zky2dYwMbtPmkc/oulkkbjdL3uWzuoBwQ8R00Q==",
"dev": true,
"dependencies": {
- "@babel/helper-environment-visitor": "^7.22.20",
- "@babel/helper-module-imports": "^7.22.15",
- "@babel/helper-simple-access": "^7.22.5",
- "@babel/helper-split-export-declaration": "^7.22.6",
- "@babel/helper-validator-identifier": "^7.22.20"
+ "@babel/helper-environment-visitor": "^7.24.7",
+ "@babel/helper-module-imports": "^7.24.7",
+ "@babel/helper-simple-access": "^7.24.7",
+ "@babel/helper-split-export-declaration": "^7.24.7",
+ "@babel/helper-validator-identifier": "^7.24.7"
},
"engines": {
"node": ">=6.9.0"
@@ -183,97 +188,98 @@
}
},
"node_modules/@babel/helper-plugin-utils": {
- "version": "7.22.5",
- "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz",
- "integrity": "sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==",
+ "version": "7.24.8",
+ "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.24.8.tgz",
+ "integrity": "sha512-FFWx5142D8h2Mgr/iPVGH5G7w6jDn4jUSpZTyDnQO0Yn7Ks2Kuz6Pci8H6MPCoUJegd/UZQ3tAvfLCxQSnWWwg==",
"dev": true,
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/helper-simple-access": {
- "version": "7.22.5",
- "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.22.5.tgz",
- "integrity": "sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w==",
+ "version": "7.24.7",
+ "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.24.7.tgz",
+ "integrity": "sha512-zBAIvbCMh5Ts+b86r/CjU+4XGYIs+R1j951gxI3KmmxBMhCg4oQMsv6ZXQ64XOm/cvzfU1FmoCyt6+owc5QMYg==",
"dev": true,
"dependencies": {
- "@babel/types": "^7.22.5"
+ "@babel/traverse": "^7.24.7",
+ "@babel/types": "^7.24.7"
},
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/helper-split-export-declaration": {
- "version": "7.22.6",
- "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz",
- "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==",
+ "version": "7.24.7",
+ "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.24.7.tgz",
+ "integrity": "sha512-oy5V7pD+UvfkEATUKvIjvIAH/xCzfsFVw7ygW2SI6NClZzquT+mwdTfgfdbUiceh6iQO0CHtCPsyze/MZ2YbAA==",
"dev": true,
"dependencies": {
- "@babel/types": "^7.22.5"
+ "@babel/types": "^7.24.7"
},
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/helper-string-parser": {
- "version": "7.23.4",
- "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.23.4.tgz",
- "integrity": "sha512-803gmbQdqwdf4olxrX4AJyFBV/RTr3rSmOj0rKwesmzlfhYNDEs+/iOcznzpNWlJlIlTJC2QfPFcHB6DlzdVLQ==",
+ "version": "7.24.8",
+ "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.24.8.tgz",
+ "integrity": "sha512-pO9KhhRcuUyGnJWwyEgnRJTSIZHiT+vMD0kPeD+so0l7mxkMT19g3pjY9GTnHySck/hDzq+dtW/4VgnMkippsQ==",
"dev": true,
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/helper-validator-identifier": {
- "version": "7.22.20",
- "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz",
- "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==",
+ "version": "7.24.7",
+ "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.7.tgz",
+ "integrity": "sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w==",
"dev": true,
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/helper-validator-option": {
- "version": "7.23.5",
- "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.23.5.tgz",
- "integrity": "sha512-85ttAOMLsr53VgXkTbkx8oA6YTfT4q7/HzXSLEYmjcSTJPMPQtvq1BD79Byep5xMUYbGRzEpDsjUf3dyp54IKw==",
+ "version": "7.24.8",
+ "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.24.8.tgz",
+ "integrity": "sha512-xb8t9tD1MHLungh/AIoWYN+gVHaB9kwlu8gffXGSt3FFEIT7RjS+xWbc2vUD1UTZdIpKj/ab3rdqJ7ufngyi2Q==",
"dev": true,
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/helpers": {
- "version": "7.23.9",
- "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.23.9.tgz",
- "integrity": "sha512-87ICKgU5t5SzOT7sBMfCOZQ2rHjRU+Pcb9BoILMYz600W6DkVRLFBPwQ18gwUVvggqXivaUakpnxWQGbpywbBQ==",
+ "version": "7.24.8",
+ "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.24.8.tgz",
+ "integrity": "sha512-gV2265Nkcz7weJJfvDoAEVzC1e2OTDpkGbEsebse8koXUJUXPsCMi7sRo/+SPMuMZ9MtUPnGwITTnQnU5YjyaQ==",
"dev": true,
"dependencies": {
- "@babel/template": "^7.23.9",
- "@babel/traverse": "^7.23.9",
- "@babel/types": "^7.23.9"
+ "@babel/template": "^7.24.7",
+ "@babel/types": "^7.24.8"
},
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/highlight": {
- "version": "7.23.4",
- "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.23.4.tgz",
- "integrity": "sha512-acGdbYSfp2WheJoJm/EBBBLh/ID8KDc64ISZ9DYtBmC8/Q204PZJLHyzeB5qMzJ5trcOkybd78M4x2KWsUq++A==",
+ "version": "7.24.7",
+ "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.7.tgz",
+ "integrity": "sha512-EStJpq4OuY8xYfhGVXngigBJRWxftKX9ksiGDnmlY3o7B/V7KIAc9X4oiK87uPJSc/vs5L869bem5fhZa8caZw==",
"dev": true,
"dependencies": {
- "@babel/helper-validator-identifier": "^7.22.20",
+ "@babel/helper-validator-identifier": "^7.24.7",
"chalk": "^2.4.2",
- "js-tokens": "^4.0.0"
+ "js-tokens": "^4.0.0",
+ "picocolors": "^1.0.0"
},
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/parser": {
- "version": "7.23.9",
- "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.9.tgz",
- "integrity": "sha512-9tcKgqKbs3xGJ+NtKF2ndOBBLVwPjl1SHxPQkd36r3Dlirw3xWUeGaTbqr7uGZcTaxkVNwc+03SVP7aCdWrTlA==",
+ "version": "7.24.8",
+ "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.24.8.tgz",
+ "integrity": "sha512-WzfbgXOkGzZiXXCqk43kKwZjzwx4oulxZi3nq2TYL9mOjQv6kYwul9mz6ID36njuL7Xkp6nJEfok848Zj10j/w==",
"dev": true,
"bin": {
"parser": "bin/babel-parser.js"
@@ -283,12 +289,12 @@
}
},
"node_modules/@babel/plugin-transform-react-jsx-self": {
- "version": "7.23.3",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.23.3.tgz",
- "integrity": "sha512-qXRvbeKDSfwnlJnanVRp0SfuWE5DQhwQr5xtLBzp56Wabyo+4CMosF6Kfp+eOD/4FYpql64XVJ2W0pVLlJZxOQ==",
+ "version": "7.24.7",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.24.7.tgz",
+ "integrity": "sha512-fOPQYbGSgH0HUp4UJO4sMBFjY6DuWq+2i8rixyUMb3CdGixs/gccURvYOAhajBdKDoGajFr3mUq5rH3phtkGzw==",
"dev": true,
"dependencies": {
- "@babel/helper-plugin-utils": "^7.22.5"
+ "@babel/helper-plugin-utils": "^7.24.7"
},
"engines": {
"node": ">=6.9.0"
@@ -298,12 +304,12 @@
}
},
"node_modules/@babel/plugin-transform-react-jsx-source": {
- "version": "7.23.3",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.23.3.tgz",
- "integrity": "sha512-91RS0MDnAWDNvGC6Wio5XYkyWI39FMFO+JK9+4AlgaTH+yWwVTsw7/sn6LK0lH7c5F+TFkpv/3LfCJ1Ydwof/g==",
+ "version": "7.24.7",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.24.7.tgz",
+ "integrity": "sha512-J2z+MWzZHVOemyLweMqngXrgGC42jQ//R0KdxqkIz/OrbVIIlhFI3WigZ5fO+nwFvBlncr4MGapd8vTyc7RPNQ==",
"dev": true,
"dependencies": {
- "@babel/helper-plugin-utils": "^7.22.5"
+ "@babel/helper-plugin-utils": "^7.24.7"
},
"engines": {
"node": ">=6.9.0"
@@ -312,45 +318,34 @@
"@babel/core": "^7.0.0-0"
}
},
- "node_modules/@babel/runtime": {
- "version": "7.23.9",
- "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.23.9.tgz",
- "integrity": "sha512-0CX6F+BI2s9dkUqr08KFrAIZgNFj75rdBU/DjCyYLIaV/quFjkk6T+EJ2LkZHyZTbEV4L5p97mNkUsHl2wLFAw==",
- "dependencies": {
- "regenerator-runtime": "^0.14.0"
- },
- "engines": {
- "node": ">=6.9.0"
- }
- },
"node_modules/@babel/template": {
- "version": "7.23.9",
- "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.23.9.tgz",
- "integrity": "sha512-+xrD2BWLpvHKNmX2QbpdpsBaWnRxahMwJjO+KZk2JOElj5nSmKezyS1B4u+QbHMTX69t4ukm6hh9lsYQ7GHCKA==",
+ "version": "7.24.7",
+ "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.24.7.tgz",
+ "integrity": "sha512-jYqfPrU9JTF0PmPy1tLYHW4Mp4KlgxJD9l2nP9fD6yT/ICi554DmrWBAEYpIelzjHf1msDP3PxJIRt/nFNfBig==",
"dev": true,
"dependencies": {
- "@babel/code-frame": "^7.23.5",
- "@babel/parser": "^7.23.9",
- "@babel/types": "^7.23.9"
+ "@babel/code-frame": "^7.24.7",
+ "@babel/parser": "^7.24.7",
+ "@babel/types": "^7.24.7"
},
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/traverse": {
- "version": "7.23.9",
- "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.9.tgz",
- "integrity": "sha512-I/4UJ9vs90OkBtY6iiiTORVMyIhJ4kAVmsKo9KFc8UOxMeUfi2hvtIBsET5u9GizXE6/GFSuKCTNfgCswuEjRg==",
- "dev": true,
- "dependencies": {
- "@babel/code-frame": "^7.23.5",
- "@babel/generator": "^7.23.6",
- "@babel/helper-environment-visitor": "^7.22.20",
- "@babel/helper-function-name": "^7.23.0",
- "@babel/helper-hoist-variables": "^7.22.5",
- "@babel/helper-split-export-declaration": "^7.22.6",
- "@babel/parser": "^7.23.9",
- "@babel/types": "^7.23.9",
+ "version": "7.24.8",
+ "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.24.8.tgz",
+ "integrity": "sha512-t0P1xxAPzEDcEPmjprAQq19NWum4K0EQPjMwZQZbHt+GiZqvjCHjj755Weq1YRPVzBI+3zSfvScfpnuIecVFJQ==",
+ "dev": true,
+ "dependencies": {
+ "@babel/code-frame": "^7.24.7",
+ "@babel/generator": "^7.24.8",
+ "@babel/helper-environment-visitor": "^7.24.7",
+ "@babel/helper-function-name": "^7.24.7",
+ "@babel/helper-hoist-variables": "^7.24.7",
+ "@babel/helper-split-export-declaration": "^7.24.7",
+ "@babel/parser": "^7.24.8",
+ "@babel/types": "^7.24.8",
"debug": "^4.3.1",
"globals": "^11.1.0"
},
@@ -359,13 +354,13 @@
}
},
"node_modules/@babel/types": {
- "version": "7.23.9",
- "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.9.tgz",
- "integrity": "sha512-dQjSq/7HaSjRM43FFGnv5keM2HsxpmyV1PfaSVm0nzzjwwTmjOe6J4bC8e3+pTEIgHaHj+1ZlLThRJ2auc/w1Q==",
+ "version": "7.24.8",
+ "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.24.8.tgz",
+ "integrity": "sha512-SkSBEHwwJRU52QEVZBmMBnE5Ux2/6WU1grdYyOhpbCNxbmJrDuDCphBzKZSO3taf0zztp+qkWlymE5tVL5l0TA==",
"dev": true,
"dependencies": {
- "@babel/helper-string-parser": "^7.23.4",
- "@babel/helper-validator-identifier": "^7.22.20",
+ "@babel/helper-string-parser": "^7.24.8",
+ "@babel/helper-validator-identifier": "^7.24.7",
"to-fast-properties": "^2.0.0"
},
"engines": {
@@ -373,9 +368,9 @@
}
},
"node_modules/@esbuild/aix-ppc64": {
- "version": "0.19.12",
- "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.19.12.tgz",
- "integrity": "sha512-bmoCYyWdEL3wDQIVbcyzRyeKLgk2WtWLTWz1ZIAZF/EGbNOwSA6ew3PftJ1PqMiOOGu0OyFMzG53L0zqIpPeNA==",
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz",
+ "integrity": "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==",
"cpu": [
"ppc64"
],
@@ -389,9 +384,9 @@
}
},
"node_modules/@esbuild/android-arm": {
- "version": "0.19.12",
- "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.19.12.tgz",
- "integrity": "sha512-qg/Lj1mu3CdQlDEEiWrlC4eaPZ1KztwGJ9B6J+/6G+/4ewxJg7gqj8eVYWvao1bXrqGiW2rsBZFSX3q2lcW05w==",
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.21.5.tgz",
+ "integrity": "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==",
"cpu": [
"arm"
],
@@ -405,9 +400,9 @@
}
},
"node_modules/@esbuild/android-arm64": {
- "version": "0.19.12",
- "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.19.12.tgz",
- "integrity": "sha512-P0UVNGIienjZv3f5zq0DP3Nt2IE/3plFzuaS96vihvD0Hd6H/q4WXUGpCxD/E8YrSXfNyRPbpTq+T8ZQioSuPA==",
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz",
+ "integrity": "sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==",
"cpu": [
"arm64"
],
@@ -421,9 +416,9 @@
}
},
"node_modules/@esbuild/android-x64": {
- "version": "0.19.12",
- "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.19.12.tgz",
- "integrity": "sha512-3k7ZoUW6Q6YqhdhIaq/WZ7HwBpnFBlW905Fa4s4qWJyiNOgT1dOqDiVAQFwBH7gBRZr17gLrlFCRzF6jFh7Kew==",
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.21.5.tgz",
+ "integrity": "sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==",
"cpu": [
"x64"
],
@@ -437,9 +432,9 @@
}
},
"node_modules/@esbuild/darwin-arm64": {
- "version": "0.19.12",
- "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.19.12.tgz",
- "integrity": "sha512-B6IeSgZgtEzGC42jsI+YYu9Z3HKRxp8ZT3cqhvliEHovq8HSX2YX8lNocDn79gCKJXOSaEot9MVYky7AKjCs8g==",
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz",
+ "integrity": "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==",
"cpu": [
"arm64"
],
@@ -453,9 +448,9 @@
}
},
"node_modules/@esbuild/darwin-x64": {
- "version": "0.19.12",
- "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.19.12.tgz",
- "integrity": "sha512-hKoVkKzFiToTgn+41qGhsUJXFlIjxI/jSYeZf3ugemDYZldIXIxhvwN6erJGlX4t5h417iFuheZ7l+YVn05N3A==",
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz",
+ "integrity": "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==",
"cpu": [
"x64"
],
@@ -469,9 +464,9 @@
}
},
"node_modules/@esbuild/freebsd-arm64": {
- "version": "0.19.12",
- "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.19.12.tgz",
- "integrity": "sha512-4aRvFIXmwAcDBw9AueDQ2YnGmz5L6obe5kmPT8Vd+/+x/JMVKCgdcRwH6APrbpNXsPz+K653Qg8HB/oXvXVukA==",
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz",
+ "integrity": "sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==",
"cpu": [
"arm64"
],
@@ -485,9 +480,9 @@
}
},
"node_modules/@esbuild/freebsd-x64": {
- "version": "0.19.12",
- "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.19.12.tgz",
- "integrity": "sha512-EYoXZ4d8xtBoVN7CEwWY2IN4ho76xjYXqSXMNccFSx2lgqOG/1TBPW0yPx1bJZk94qu3tX0fycJeeQsKovA8gg==",
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz",
+ "integrity": "sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==",
"cpu": [
"x64"
],
@@ -501,9 +496,9 @@
}
},
"node_modules/@esbuild/linux-arm": {
- "version": "0.19.12",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.19.12.tgz",
- "integrity": "sha512-J5jPms//KhSNv+LO1S1TX1UWp1ucM6N6XuL6ITdKWElCu8wXP72l9MM0zDTzzeikVyqFE6U8YAV9/tFyj0ti+w==",
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz",
+ "integrity": "sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==",
"cpu": [
"arm"
],
@@ -517,9 +512,9 @@
}
},
"node_modules/@esbuild/linux-arm64": {
- "version": "0.19.12",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.19.12.tgz",
- "integrity": "sha512-EoTjyYyLuVPfdPLsGVVVC8a0p1BFFvtpQDB/YLEhaXyf/5bczaGeN15QkR+O4S5LeJ92Tqotve7i1jn35qwvdA==",
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz",
+ "integrity": "sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==",
"cpu": [
"arm64"
],
@@ -533,9 +528,9 @@
}
},
"node_modules/@esbuild/linux-ia32": {
- "version": "0.19.12",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.19.12.tgz",
- "integrity": "sha512-Thsa42rrP1+UIGaWz47uydHSBOgTUnwBwNq59khgIwktK6x60Hivfbux9iNR0eHCHzOLjLMLfUMLCypBkZXMHA==",
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz",
+ "integrity": "sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==",
"cpu": [
"ia32"
],
@@ -549,9 +544,9 @@
}
},
"node_modules/@esbuild/linux-loong64": {
- "version": "0.19.12",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.19.12.tgz",
- "integrity": "sha512-LiXdXA0s3IqRRjm6rV6XaWATScKAXjI4R4LoDlvO7+yQqFdlr1Bax62sRwkVvRIrwXxvtYEHHI4dm50jAXkuAA==",
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz",
+ "integrity": "sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==",
"cpu": [
"loong64"
],
@@ -565,9 +560,9 @@
}
},
"node_modules/@esbuild/linux-mips64el": {
- "version": "0.19.12",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.19.12.tgz",
- "integrity": "sha512-fEnAuj5VGTanfJ07ff0gOA6IPsvrVHLVb6Lyd1g2/ed67oU1eFzL0r9WL7ZzscD+/N6i3dWumGE1Un4f7Amf+w==",
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz",
+ "integrity": "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==",
"cpu": [
"mips64el"
],
@@ -581,9 +576,9 @@
}
},
"node_modules/@esbuild/linux-ppc64": {
- "version": "0.19.12",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.19.12.tgz",
- "integrity": "sha512-nYJA2/QPimDQOh1rKWedNOe3Gfc8PabU7HT3iXWtNUbRzXS9+vgB0Fjaqr//XNbd82mCxHzik2qotuI89cfixg==",
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz",
+ "integrity": "sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==",
"cpu": [
"ppc64"
],
@@ -597,9 +592,9 @@
}
},
"node_modules/@esbuild/linux-riscv64": {
- "version": "0.19.12",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.19.12.tgz",
- "integrity": "sha512-2MueBrlPQCw5dVJJpQdUYgeqIzDQgw3QtiAHUC4RBz9FXPrskyyU3VI1hw7C0BSKB9OduwSJ79FTCqtGMWqJHg==",
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz",
+ "integrity": "sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==",
"cpu": [
"riscv64"
],
@@ -613,9 +608,9 @@
}
},
"node_modules/@esbuild/linux-s390x": {
- "version": "0.19.12",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.19.12.tgz",
- "integrity": "sha512-+Pil1Nv3Umes4m3AZKqA2anfhJiVmNCYkPchwFJNEJN5QxmTs1uzyy4TvmDrCRNT2ApwSari7ZIgrPeUx4UZDg==",
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz",
+ "integrity": "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==",
"cpu": [
"s390x"
],
@@ -629,9 +624,9 @@
}
},
"node_modules/@esbuild/linux-x64": {
- "version": "0.19.12",
- "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.19.12.tgz",
- "integrity": "sha512-B71g1QpxfwBvNrfyJdVDexenDIt1CiDN1TIXLbhOw0KhJzE78KIFGX6OJ9MrtC0oOqMWf+0xop4qEU8JrJTwCg==",
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz",
+ "integrity": "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==",
"cpu": [
"x64"
],
@@ -645,9 +640,9 @@
}
},
"node_modules/@esbuild/netbsd-x64": {
- "version": "0.19.12",
- "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.19.12.tgz",
- "integrity": "sha512-3ltjQ7n1owJgFbuC61Oj++XhtzmymoCihNFgT84UAmJnxJfm4sYCiSLTXZtE00VWYpPMYc+ZQmB6xbSdVh0JWA==",
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz",
+ "integrity": "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==",
"cpu": [
"x64"
],
@@ -661,9 +656,9 @@
}
},
"node_modules/@esbuild/openbsd-x64": {
- "version": "0.19.12",
- "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.19.12.tgz",
- "integrity": "sha512-RbrfTB9SWsr0kWmb9srfF+L933uMDdu9BIzdA7os2t0TXhCRjrQyCeOt6wVxr79CKD4c+p+YhCj31HBkYcXebw==",
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz",
+ "integrity": "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==",
"cpu": [
"x64"
],
@@ -677,9 +672,9 @@
}
},
"node_modules/@esbuild/sunos-x64": {
- "version": "0.19.12",
- "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.19.12.tgz",
- "integrity": "sha512-HKjJwRrW8uWtCQnQOz9qcU3mUZhTUQvi56Q8DPTLLB+DawoiQdjsYq+j+D3s9I8VFtDr+F9CjgXKKC4ss89IeA==",
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz",
+ "integrity": "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==",
"cpu": [
"x64"
],
@@ -693,9 +688,9 @@
}
},
"node_modules/@esbuild/win32-arm64": {
- "version": "0.19.12",
- "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.19.12.tgz",
- "integrity": "sha512-URgtR1dJnmGvX864pn1B2YUYNzjmXkuJOIqG2HdU62MVS4EHpU2946OZoTMnRUHklGtJdJZ33QfzdjGACXhn1A==",
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz",
+ "integrity": "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==",
"cpu": [
"arm64"
],
@@ -709,9 +704,9 @@
}
},
"node_modules/@esbuild/win32-ia32": {
- "version": "0.19.12",
- "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.19.12.tgz",
- "integrity": "sha512-+ZOE6pUkMOJfmxmBZElNOx72NKpIa/HFOMGzu8fqzQJ5kgf6aTGrcJaFsNiVMH4JKpMipyK+7k0n2UXN7a8YKQ==",
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz",
+ "integrity": "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==",
"cpu": [
"ia32"
],
@@ -725,9 +720,9 @@
}
},
"node_modules/@esbuild/win32-x64": {
- "version": "0.19.12",
- "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.19.12.tgz",
- "integrity": "sha512-T1QyPSDCyMXaO3pzBkF96E8xMkiRYbUEZADd29SyPGabqxMViNoii+NcK7eWJAEoU6RZyEm5lVSIjTmcdoB9HA==",
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz",
+ "integrity": "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==",
"cpu": [
"x64"
],
@@ -741,24 +736,27 @@
}
},
"node_modules/@fable-org/fable-metadata": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/@fable-org/fable-metadata/-/fable-metadata-1.0.0.tgz",
- "integrity": "sha512-O6xT43XenR1SjtaHtEFDL3DLPn8/JjVWyOYG1BFNBM30sF/mknIuIer1oy+iwNG2MJQiu8BtLrB0OMkGnt/2JQ=="
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/@fable-org/fable-metadata/-/fable-metadata-1.1.0.tgz",
+ "integrity": "sha512-ccDGXMAxnd+zmtjl7r/oxTr9g/xaO1o1PsCCWZYMyFa9lXgHMd8aXDGm4F5lIdWvF550rEVA0BC6rES50OWE4A==",
+ "dependencies": {
+ "dirname-filename-esm": "^1.1.1"
+ }
},
"node_modules/@fable-org/fable-standalone": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/@fable-org/fable-standalone/-/fable-standalone-1.1.0.tgz",
- "integrity": "sha512-/vasnCXt5DOKFhEa1DIhzwdLCpwXsz/VzTH8EudbBK9QbV5+bXVBc2LzWy9GV7k2eHbyHitB/xzx0OVdoKYYPg=="
+ "version": "1.9.0",
+ "resolved": "https://registry.npmjs.org/@fable-org/fable-standalone/-/fable-standalone-1.9.0.tgz",
+ "integrity": "sha512-U3uqxl+HeF18Y3uvMxxVT6pOOZKPf5agM539Vjh2wQirM4cRNLyK1hUyB+2gzes/vo7kJsw55qee6qLR8l/VFQ=="
},
"node_modules/@jridgewell/gen-mapping": {
- "version": "0.3.3",
- "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz",
- "integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==",
+ "version": "0.3.5",
+ "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz",
+ "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==",
"dev": true,
"dependencies": {
- "@jridgewell/set-array": "^1.0.1",
+ "@jridgewell/set-array": "^1.2.1",
"@jridgewell/sourcemap-codec": "^1.4.10",
- "@jridgewell/trace-mapping": "^0.3.9"
+ "@jridgewell/trace-mapping": "^0.3.24"
},
"engines": {
"node": ">=6.0.0"
@@ -774,24 +772,24 @@
}
},
"node_modules/@jridgewell/set-array": {
- "version": "1.1.2",
- "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz",
- "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==",
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz",
+ "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==",
"dev": true,
"engines": {
"node": ">=6.0.0"
}
},
"node_modules/@jridgewell/sourcemap-codec": {
- "version": "1.4.15",
- "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz",
- "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==",
+ "version": "1.5.0",
+ "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz",
+ "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==",
"dev": true
},
"node_modules/@jridgewell/trace-mapping": {
- "version": "0.3.22",
- "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.22.tgz",
- "integrity": "sha512-Wf963MzWtA2sjrNt+g18IAln9lKnlRp+K2eH4jjIoF1wYeq3aMREpG09xhlhdzS0EjwU7qmUJYangWa+151vZw==",
+ "version": "0.3.25",
+ "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz",
+ "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==",
"dev": true,
"dependencies": {
"@jridgewell/resolve-uri": "^3.1.0",
@@ -823,9 +821,9 @@
}
},
"node_modules/@rollup/rollup-android-arm-eabi": {
- "version": "4.9.6",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.9.6.tgz",
- "integrity": "sha512-MVNXSSYN6QXOulbHpLMKYi60ppyO13W9my1qogeiAqtjb2yR4LSmfU2+POvDkLzhjYLXz9Rf9+9a3zFHW1Lecg==",
+ "version": "4.22.4",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.22.4.tgz",
+ "integrity": "sha512-Fxamp4aEZnfPOcGA8KSNEohV8hX7zVHOemC8jVBoBUHu5zpJK/Eu3uJwt6BMgy9fkvzxDaurgj96F/NiLukF2w==",
"cpu": [
"arm"
],
@@ -836,9 +834,9 @@
]
},
"node_modules/@rollup/rollup-android-arm64": {
- "version": "4.9.6",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.9.6.tgz",
- "integrity": "sha512-T14aNLpqJ5wzKNf5jEDpv5zgyIqcpn1MlwCrUXLrwoADr2RkWA0vOWP4XxbO9aiO3dvMCQICZdKeDrFl7UMClw==",
+ "version": "4.22.4",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.22.4.tgz",
+ "integrity": "sha512-VXoK5UMrgECLYaMuGuVTOx5kcuap1Jm8g/M83RnCHBKOqvPPmROFJGQaZhGccnsFtfXQ3XYa4/jMCJvZnbJBdA==",
"cpu": [
"arm64"
],
@@ -849,9 +847,9 @@
]
},
"node_modules/@rollup/rollup-darwin-arm64": {
- "version": "4.9.6",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.9.6.tgz",
- "integrity": "sha512-CqNNAyhRkTbo8VVZ5R85X73H3R5NX9ONnKbXuHisGWC0qRbTTxnF1U4V9NafzJbgGM0sHZpdO83pLPzq8uOZFw==",
+ "version": "4.22.4",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.22.4.tgz",
+ "integrity": "sha512-xMM9ORBqu81jyMKCDP+SZDhnX2QEVQzTcC6G18KlTQEzWK8r/oNZtKuZaCcHhnsa6fEeOBionoyl5JsAbE/36Q==",
"cpu": [
"arm64"
],
@@ -862,9 +860,9 @@
]
},
"node_modules/@rollup/rollup-darwin-x64": {
- "version": "4.9.6",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.9.6.tgz",
- "integrity": "sha512-zRDtdJuRvA1dc9Mp6BWYqAsU5oeLixdfUvkTHuiYOHwqYuQ4YgSmi6+/lPvSsqc/I0Omw3DdICx4Tfacdzmhog==",
+ "version": "4.22.4",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.22.4.tgz",
+ "integrity": "sha512-aJJyYKQwbHuhTUrjWjxEvGnNNBCnmpHDvrb8JFDbeSH3m2XdHcxDd3jthAzvmoI8w/kSjd2y0udT+4okADsZIw==",
"cpu": [
"x64"
],
@@ -875,9 +873,22 @@
]
},
"node_modules/@rollup/rollup-linux-arm-gnueabihf": {
- "version": "4.9.6",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.9.6.tgz",
- "integrity": "sha512-oNk8YXDDnNyG4qlNb6is1ojTOGL/tRhbbKeE/YuccItzerEZT68Z9gHrY3ROh7axDc974+zYAPxK5SH0j/G+QQ==",
+ "version": "4.22.4",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.22.4.tgz",
+ "integrity": "sha512-j63YtCIRAzbO+gC2L9dWXRh5BFetsv0j0va0Wi9epXDgU/XUi5dJKo4USTttVyK7fGw2nPWK0PbAvyliz50SCQ==",
+ "cpu": [
+ "arm"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
+ "node_modules/@rollup/rollup-linux-arm-musleabihf": {
+ "version": "4.22.4",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.22.4.tgz",
+ "integrity": "sha512-dJnWUgwWBX1YBRsuKKMOlXCzh2Wu1mlHzv20TpqEsfdZLb3WoJW2kIEsGwLkroYf24IrPAvOT/ZQ2OYMV6vlrg==",
"cpu": [
"arm"
],
@@ -888,9 +899,9 @@
]
},
"node_modules/@rollup/rollup-linux-arm64-gnu": {
- "version": "4.9.6",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.9.6.tgz",
- "integrity": "sha512-Z3O60yxPtuCYobrtzjo0wlmvDdx2qZfeAWTyfOjEDqd08kthDKexLpV97KfAeUXPosENKd8uyJMRDfFMxcYkDQ==",
+ "version": "4.22.4",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.22.4.tgz",
+ "integrity": "sha512-AdPRoNi3NKVLolCN/Sp4F4N1d98c4SBnHMKoLuiG6RXgoZ4sllseuGioszumnPGmPM2O7qaAX/IJdeDU8f26Aw==",
"cpu": [
"arm64"
],
@@ -901,9 +912,9 @@
]
},
"node_modules/@rollup/rollup-linux-arm64-musl": {
- "version": "4.9.6",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.9.6.tgz",
- "integrity": "sha512-gpiG0qQJNdYEVad+1iAsGAbgAnZ8j07FapmnIAQgODKcOTjLEWM9sRb+MbQyVsYCnA0Im6M6QIq6ax7liws6eQ==",
+ "version": "4.22.4",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.22.4.tgz",
+ "integrity": "sha512-Gl0AxBtDg8uoAn5CCqQDMqAx22Wx22pjDOjBdmG0VIWX3qUBHzYmOKh8KXHL4UpogfJ14G4wk16EQogF+v8hmA==",
"cpu": [
"arm64"
],
@@ -913,10 +924,23 @@
"linux"
]
},
+ "node_modules/@rollup/rollup-linux-powerpc64le-gnu": {
+ "version": "4.22.4",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.22.4.tgz",
+ "integrity": "sha512-3aVCK9xfWW1oGQpTsYJJPF6bfpWfhbRnhdlyhak2ZiyFLDaayz0EP5j9V1RVLAAxlmWKTDfS9wyRyY3hvhPoOg==",
+ "cpu": [
+ "ppc64"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
"node_modules/@rollup/rollup-linux-riscv64-gnu": {
- "version": "4.9.6",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.9.6.tgz",
- "integrity": "sha512-+uCOcvVmFUYvVDr27aiyun9WgZk0tXe7ThuzoUTAukZJOwS5MrGbmSlNOhx1j80GdpqbOty05XqSl5w4dQvcOA==",
+ "version": "4.22.4",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.22.4.tgz",
+ "integrity": "sha512-ePYIir6VYnhgv2C5Xe9u+ico4t8sZWXschR6fMgoPUK31yQu7hTEJb7bCqivHECwIClJfKgE7zYsh1qTP3WHUA==",
"cpu": [
"riscv64"
],
@@ -926,10 +950,23 @@
"linux"
]
},
+ "node_modules/@rollup/rollup-linux-s390x-gnu": {
+ "version": "4.22.4",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.22.4.tgz",
+ "integrity": "sha512-GqFJ9wLlbB9daxhVlrTe61vJtEY99/xB3C8e4ULVsVfflcpmR6c8UZXjtkMA6FhNONhj2eA5Tk9uAVw5orEs4Q==",
+ "cpu": [
+ "s390x"
+ ],
+ "dev": true,
+ "optional": true,
+ "os": [
+ "linux"
+ ]
+ },
"node_modules/@rollup/rollup-linux-x64-gnu": {
- "version": "4.9.6",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.9.6.tgz",
- "integrity": "sha512-HUNqM32dGzfBKuaDUBqFB7tP6VMN74eLZ33Q9Y1TBqRDn+qDonkAUyKWwF9BR9unV7QUzffLnz9GrnKvMqC/fw==",
+ "version": "4.22.4",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.22.4.tgz",
+ "integrity": "sha512-87v0ol2sH9GE3cLQLNEy0K/R0pz1nvg76o8M5nhMR0+Q+BBGLnb35P0fVz4CQxHYXaAOhE8HhlkaZfsdUOlHwg==",
"cpu": [
"x64"
],
@@ -940,9 +977,9 @@
]
},
"node_modules/@rollup/rollup-linux-x64-musl": {
- "version": "4.9.6",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.9.6.tgz",
- "integrity": "sha512-ch7M+9Tr5R4FK40FHQk8VnML0Szi2KRujUgHXd/HjuH9ifH72GUmw6lStZBo3c3GB82vHa0ZoUfjfcM7JiiMrQ==",
+ "version": "4.22.4",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.22.4.tgz",
+ "integrity": "sha512-UV6FZMUgePDZrFjrNGIWzDo/vABebuXBhJEqrHxrGiU6HikPy0Z3LfdtciIttEUQfuDdCn8fqh7wiFJjCNwO+g==",
"cpu": [
"x64"
],
@@ -953,9 +990,9 @@
]
},
"node_modules/@rollup/rollup-win32-arm64-msvc": {
- "version": "4.9.6",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.9.6.tgz",
- "integrity": "sha512-VD6qnR99dhmTQ1mJhIzXsRcTBvTjbfbGGwKAHcu+52cVl15AC/kplkhxzW/uT0Xl62Y/meBKDZvoJSJN+vTeGA==",
+ "version": "4.22.4",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.22.4.tgz",
+ "integrity": "sha512-BjI+NVVEGAXjGWYHz/vv0pBqfGoUH0IGZ0cICTn7kB9PyjrATSkX+8WkguNjWoj2qSr1im/+tTGRaY+4/PdcQw==",
"cpu": [
"arm64"
],
@@ -966,9 +1003,9 @@
]
},
"node_modules/@rollup/rollup-win32-ia32-msvc": {
- "version": "4.9.6",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.9.6.tgz",
- "integrity": "sha512-J9AFDq/xiRI58eR2NIDfyVmTYGyIZmRcvcAoJ48oDld/NTR8wyiPUu2X/v1navJ+N/FGg68LEbX3Ejd6l8B7MQ==",
+ "version": "4.22.4",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.22.4.tgz",
+ "integrity": "sha512-SiWG/1TuUdPvYmzmYnmd3IEifzR61Tragkbx9D3+R8mzQqDBz8v+BvZNDlkiTtI9T15KYZhP0ehn3Dld4n9J5g==",
"cpu": [
"ia32"
],
@@ -979,9 +1016,9 @@
]
},
"node_modules/@rollup/rollup-win32-x64-msvc": {
- "version": "4.9.6",
- "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.9.6.tgz",
- "integrity": "sha512-jqzNLhNDvIZOrt69Ce4UjGRpXJBzhUBzawMwnaDAwyHriki3XollsewxWzOzz+4yOFDkuJHtTsZFwMxhYJWmLQ==",
+ "version": "4.22.4",
+ "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.22.4.tgz",
+ "integrity": "sha512-j8pPKp53/lq9lMXN57S8cFz0MynJk8OWNuUnXct/9KCpKU7DgU3bYMJhwWmcqC0UU29p8Lr0/7KEVcaM6bf47Q==",
"cpu": [
"x64"
],
@@ -1095,16 +1132,16 @@
"integrity": "sha512-IfYcSBWE3hLpBg8+X2SEa8LVkJdJEkT2Ese2aaLs3ptGdVtABxndrMaxuFlQ1qdFf9Q5rDvDpxI3WwgvKFAsQA=="
},
"node_modules/@vitejs/plugin-react": {
- "version": "4.2.1",
- "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.2.1.tgz",
- "integrity": "sha512-oojO9IDc4nCUUi8qIR11KoQm0XFFLIwsRBwHRR4d/88IWghn1y6ckz/bJ8GHDCsYEJee8mDzqtJxh15/cisJNQ==",
+ "version": "4.3.1",
+ "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.3.1.tgz",
+ "integrity": "sha512-m/V2syj5CuVnaxcUJOQRel/Wr31FFXRFlnOoq1TVtkCxsY5veGMTEmpWHndrhB2U8ScHtCQB1e+4hWYExQc6Lg==",
"dev": true,
"dependencies": {
- "@babel/core": "^7.23.5",
- "@babel/plugin-transform-react-jsx-self": "^7.23.3",
- "@babel/plugin-transform-react-jsx-source": "^7.23.3",
+ "@babel/core": "^7.24.5",
+ "@babel/plugin-transform-react-jsx-self": "^7.24.5",
+ "@babel/plugin-transform-react-jsx-source": "^7.24.1",
"@types/babel__core": "^7.20.5",
- "react-refresh": "^0.14.0"
+ "react-refresh": "^0.14.2"
},
"engines": {
"node": "^14.18.0 || >=16.0.0"
@@ -1135,9 +1172,9 @@
}
},
"node_modules/browserslist": {
- "version": "4.23.0",
- "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.23.0.tgz",
- "integrity": "sha512-QW8HiM1shhT2GuzkvklfjcKDiWFXHOeFCIA/huJPwHsslwcydgk7X+z2zXpEijP98UCY7HbubZt5J2Zgvf0CaQ==",
+ "version": "4.23.2",
+ "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.23.2.tgz",
+ "integrity": "sha512-qkqSyistMYdxAcw+CzbZwlBy8AGmS/eEWs+sEV5TnLRGDOL+C5M2EnH6tlZyg0YoAxGJAFKh61En9BR941GnHA==",
"dev": true,
"funding": [
{
@@ -1154,10 +1191,10 @@
}
],
"dependencies": {
- "caniuse-lite": "^1.0.30001587",
- "electron-to-chromium": "^1.4.668",
+ "caniuse-lite": "^1.0.30001640",
+ "electron-to-chromium": "^1.4.820",
"node-releases": "^2.0.14",
- "update-browserslist-db": "^1.0.13"
+ "update-browserslist-db": "^1.1.0"
},
"bin": {
"browserslist": "cli.js"
@@ -1167,9 +1204,9 @@
}
},
"node_modules/caniuse-lite": {
- "version": "1.0.30001588",
- "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001588.tgz",
- "integrity": "sha512-+hVY9jE44uKLkH0SrUTqxjxqNTOWHsbnQDIKjwkZ3lNTzUUVdBLBGXtj/q5Mp5u98r3droaZAewQuEDzjQdZlQ==",
+ "version": "1.0.30001641",
+ "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001641.tgz",
+ "integrity": "sha512-Phv5thgl67bHYo1TtMY/MurjkHhV4EDaCosezRXgZ8jzA/Ub+wjxAvbGvjoFENStinwi5kCyOYV3mi5tOGykwA==",
"dev": true,
"funding": [
{
@@ -1209,24 +1246,6 @@
"url": "https://github.com/sponsors/wooorm"
}
},
- "node_modules/character-entities-legacy": {
- "version": "1.1.4",
- "resolved": "https://registry.npmjs.org/character-entities-legacy/-/character-entities-legacy-1.1.4.tgz",
- "integrity": "sha512-3Xnr+7ZFS1uxeiUDvV02wQ+QDbc55o97tIV5zHScSPJpcLm/r0DFPcoY3tYRp+VZukxuMeKgXYmsXQHO05zQeA==",
- "funding": {
- "type": "github",
- "url": "https://github.com/sponsors/wooorm"
- }
- },
- "node_modules/character-reference-invalid": {
- "version": "1.1.4",
- "resolved": "https://registry.npmjs.org/character-reference-invalid/-/character-reference-invalid-1.1.4.tgz",
- "integrity": "sha512-mKKUkUbhPpQlCOfIuZkvSEgktjPFIsZKRRbC6KWVEMvlzblj3i3asQv5ODsrwt0N3pHAEvjP8KTQPHkp0+6jOg==",
- "funding": {
- "type": "github",
- "url": "https://github.com/sponsors/wooorm"
- }
- },
"node_modules/clsx": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/clsx/-/clsx-1.2.1.tgz",
@@ -1315,16 +1334,21 @@
"node": ">=0.3.1"
}
},
+ "node_modules/dirname-filename-esm": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/dirname-filename-esm/-/dirname-filename-esm-1.1.1.tgz",
+ "integrity": "sha512-BWBkv157Cf/z7Hjod2v2JS7vyC36Dk1QQolAtuLjpl8RBlv7Z92X7+Ufc2cjfR/B3iJUiK0QmGZkgtsmmLz0Tw=="
+ },
"node_modules/electron-to-chromium": {
- "version": "1.4.678",
- "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.678.tgz",
- "integrity": "sha512-NbdGC2p0O5Q5iVhLEsNBSfytaw7wbEFJlIvaF71wi6QDtLAph5/rVogjyOpf/QggJIt8hNK3KdwNJnc2bzckbw==",
+ "version": "1.4.825",
+ "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.825.tgz",
+ "integrity": "sha512-OCcF+LwdgFGcsYPYC5keEEFC2XT0gBhrYbeGzHCx7i9qRFbzO/AqTmc/C/1xNhJj+JA7rzlN7mpBuStshh96Cg==",
"dev": true
},
"node_modules/esbuild": {
- "version": "0.19.12",
- "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.19.12.tgz",
- "integrity": "sha512-aARqgq8roFBj054KvQr5f1sFu0D65G+miZRCuJyJ0G13Zwx7vRar5Zhn2tkQNzIXcBrNVsv/8stehpj+GAjgbg==",
+ "version": "0.21.5",
+ "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz",
+ "integrity": "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==",
"dev": true,
"hasInstallScript": true,
"bin": {
@@ -1334,29 +1358,29 @@
"node": ">=12"
},
"optionalDependencies": {
- "@esbuild/aix-ppc64": "0.19.12",
- "@esbuild/android-arm": "0.19.12",
- "@esbuild/android-arm64": "0.19.12",
- "@esbuild/android-x64": "0.19.12",
- "@esbuild/darwin-arm64": "0.19.12",
- "@esbuild/darwin-x64": "0.19.12",
- "@esbuild/freebsd-arm64": "0.19.12",
- "@esbuild/freebsd-x64": "0.19.12",
- "@esbuild/linux-arm": "0.19.12",
- "@esbuild/linux-arm64": "0.19.12",
- "@esbuild/linux-ia32": "0.19.12",
- "@esbuild/linux-loong64": "0.19.12",
- "@esbuild/linux-mips64el": "0.19.12",
- "@esbuild/linux-ppc64": "0.19.12",
- "@esbuild/linux-riscv64": "0.19.12",
- "@esbuild/linux-s390x": "0.19.12",
- "@esbuild/linux-x64": "0.19.12",
- "@esbuild/netbsd-x64": "0.19.12",
- "@esbuild/openbsd-x64": "0.19.12",
- "@esbuild/sunos-x64": "0.19.12",
- "@esbuild/win32-arm64": "0.19.12",
- "@esbuild/win32-ia32": "0.19.12",
- "@esbuild/win32-x64": "0.19.12"
+ "@esbuild/aix-ppc64": "0.21.5",
+ "@esbuild/android-arm": "0.21.5",
+ "@esbuild/android-arm64": "0.21.5",
+ "@esbuild/android-x64": "0.21.5",
+ "@esbuild/darwin-arm64": "0.21.5",
+ "@esbuild/darwin-x64": "0.21.5",
+ "@esbuild/freebsd-arm64": "0.21.5",
+ "@esbuild/freebsd-x64": "0.21.5",
+ "@esbuild/linux-arm": "0.21.5",
+ "@esbuild/linux-arm64": "0.21.5",
+ "@esbuild/linux-ia32": "0.21.5",
+ "@esbuild/linux-loong64": "0.21.5",
+ "@esbuild/linux-mips64el": "0.21.5",
+ "@esbuild/linux-ppc64": "0.21.5",
+ "@esbuild/linux-riscv64": "0.21.5",
+ "@esbuild/linux-s390x": "0.21.5",
+ "@esbuild/linux-x64": "0.21.5",
+ "@esbuild/netbsd-x64": "0.21.5",
+ "@esbuild/openbsd-x64": "0.21.5",
+ "@esbuild/sunos-x64": "0.21.5",
+ "@esbuild/win32-arm64": "0.21.5",
+ "@esbuild/win32-ia32": "0.21.5",
+ "@esbuild/win32-x64": "0.21.5"
}
},
"node_modules/escalade": {
@@ -1382,26 +1406,6 @@
"resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz",
"integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g=="
},
- "node_modules/fault": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/fault/-/fault-1.0.4.tgz",
- "integrity": "sha512-CJ0HCB5tL5fYTEA7ToAq5+kTwd++Borf1/bifxd9iT70QcXr4MRrO3Llf8Ifs70q+SJcGHFtnIE/Nw6giCtECA==",
- "dependencies": {
- "format": "^0.2.0"
- },
- "funding": {
- "type": "github",
- "url": "https://github.com/sponsors/wooorm"
- }
- },
- "node_modules/format": {
- "version": "0.2.2",
- "resolved": "https://registry.npmjs.org/format/-/format-0.2.2.tgz",
- "integrity": "sha512-wzsgA6WOq+09wrU1tsJ09udeR/YZRaeArL9e1wPbFg3GG2yDnC2ldKpxs4xunpFF9DgqCqOIra3bc1HWrJ37Ww==",
- "engines": {
- "node": ">=0.4.x"
- }
- },
"node_modules/fsevents": {
"version": "2.3.3",
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
@@ -1443,15 +1447,6 @@
"node": ">=4"
}
},
- "node_modules/hast-util-parse-selector": {
- "version": "2.2.5",
- "resolved": "https://registry.npmjs.org/hast-util-parse-selector/-/hast-util-parse-selector-2.2.5.tgz",
- "integrity": "sha512-7j6mrk/qqkSehsM92wQjdIgWM2/BW61u/53G6xmC8i1OmEdKLHbk419QKQUjz6LglWsfqoiHmyMRkP1BGjecNQ==",
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/unified"
- }
- },
"node_modules/hast-util-whitespace": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/hast-util-whitespace/-/hast-util-whitespace-2.0.1.tgz",
@@ -1461,79 +1456,11 @@
"url": "https://opencollective.com/unified"
}
},
- "node_modules/hastscript": {
- "version": "6.0.0",
- "resolved": "https://registry.npmjs.org/hastscript/-/hastscript-6.0.0.tgz",
- "integrity": "sha512-nDM6bvd7lIqDUiYEiu5Sl/+6ReP0BMk/2f4U/Rooccxkj0P5nm+acM5PrGJ/t5I8qPGiqZSE6hVAwZEdZIvP4w==",
- "dependencies": {
- "@types/hast": "^2.0.0",
- "comma-separated-tokens": "^1.0.0",
- "hast-util-parse-selector": "^2.0.0",
- "property-information": "^5.0.0",
- "space-separated-tokens": "^1.0.0"
- },
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/unified"
- }
- },
- "node_modules/hastscript/node_modules/comma-separated-tokens": {
- "version": "1.0.8",
- "resolved": "https://registry.npmjs.org/comma-separated-tokens/-/comma-separated-tokens-1.0.8.tgz",
- "integrity": "sha512-GHuDRO12Sypu2cV70d1dkA2EUmXHgntrzbpvOB+Qy+49ypNfGgFQIC2fhhXbnyrJRynDCAARsT7Ou0M6hirpfw==",
- "funding": {
- "type": "github",
- "url": "https://github.com/sponsors/wooorm"
- }
- },
- "node_modules/hastscript/node_modules/property-information": {
- "version": "5.6.0",
- "resolved": "https://registry.npmjs.org/property-information/-/property-information-5.6.0.tgz",
- "integrity": "sha512-YUHSPk+A30YPv+0Qf8i9Mbfe/C0hdPXk1s1jPVToV8pk8BQtpw10ct89Eo7OWkutrwqvT0eicAxlOg3dOAu8JA==",
- "dependencies": {
- "xtend": "^4.0.0"
- },
- "funding": {
- "type": "github",
- "url": "https://github.com/sponsors/wooorm"
- }
- },
- "node_modules/hastscript/node_modules/space-separated-tokens": {
- "version": "1.1.5",
- "resolved": "https://registry.npmjs.org/space-separated-tokens/-/space-separated-tokens-1.1.5.tgz",
- "integrity": "sha512-q/JSVd1Lptzhf5bkYm4ob4iWPjx0KiRe3sRFBNrVqbJkFaBm5vbbowy1mymoPNLRa52+oadOhJ+K49wsSeSjTA==",
- "funding": {
- "type": "github",
- "url": "https://github.com/sponsors/wooorm"
- }
- },
"node_modules/inline-style-parser": {
"version": "0.1.1",
"resolved": "https://registry.npmjs.org/inline-style-parser/-/inline-style-parser-0.1.1.tgz",
"integrity": "sha512-7NXolsK4CAS5+xvdj5OMMbI962hU/wvwoxk+LWR9Ek9bVtyuuYScDN6eS0rUm6TxApFpw7CX1o4uJzcd4AyD3Q=="
},
- "node_modules/is-alphabetical": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/is-alphabetical/-/is-alphabetical-1.0.4.tgz",
- "integrity": "sha512-DwzsA04LQ10FHTZuL0/grVDk4rFoVH1pjAToYwBrHSxcrBIGQuXrQMtD5U1b0U2XVgKZCTLLP8u2Qxqhy3l2Vg==",
- "funding": {
- "type": "github",
- "url": "https://github.com/sponsors/wooorm"
- }
- },
- "node_modules/is-alphanumerical": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/is-alphanumerical/-/is-alphanumerical-1.0.4.tgz",
- "integrity": "sha512-UzoZUr+XfVz3t3v4KyGEniVL9BDRoQtY7tOyrRybkVNjDFWyo1yhXNGrrBTQxp3ib9BLAWs7k2YKBQsFRkZG9A==",
- "dependencies": {
- "is-alphabetical": "^1.0.0",
- "is-decimal": "^1.0.0"
- },
- "funding": {
- "type": "github",
- "url": "https://github.com/sponsors/wooorm"
- }
- },
"node_modules/is-buffer": {
"version": "2.0.5",
"resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.5.tgz",
@@ -1556,24 +1483,6 @@
"node": ">=4"
}
},
- "node_modules/is-decimal": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/is-decimal/-/is-decimal-1.0.4.tgz",
- "integrity": "sha512-RGdriMmQQvZ2aqaQq3awNA6dCGtKpiDFcOzrTWrDAT2MiWrKQVPmxLGHl7Y2nNu6led0kEyoX0enY0qXYsv9zw==",
- "funding": {
- "type": "github",
- "url": "https://github.com/sponsors/wooorm"
- }
- },
- "node_modules/is-hexadecimal": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/is-hexadecimal/-/is-hexadecimal-1.0.4.tgz",
- "integrity": "sha512-gyPJuv83bHMpocVYoqof5VDiZveEoGoFL8m3BXNb2VW8Xs+rz9kqO8LOQ5DH6EsuvilT1ApazU0pyl+ytbPtlw==",
- "funding": {
- "type": "github",
- "url": "https://github.com/sponsors/wooorm"
- }
- },
"node_modules/is-plain-obj": {
"version": "4.1.0",
"resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz",
@@ -1633,27 +1542,6 @@
"loose-envify": "cli.js"
}
},
- "node_modules/lowlight": {
- "version": "1.20.0",
- "resolved": "https://registry.npmjs.org/lowlight/-/lowlight-1.20.0.tgz",
- "integrity": "sha512-8Ktj+prEb1RoCPkEOrPMYUN/nCggB7qAWe3a7OpMjWQkh3l2RD5wKRQ+o8Q8YuI9RG/xs95waaI/E6ym/7NsTw==",
- "dependencies": {
- "fault": "^1.0.0",
- "highlight.js": "~10.7.0"
- },
- "funding": {
- "type": "github",
- "url": "https://github.com/sponsors/wooorm"
- }
- },
- "node_modules/lowlight/node_modules/highlight.js": {
- "version": "10.7.3",
- "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-10.7.3.tgz",
- "integrity": "sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A==",
- "engines": {
- "node": "*"
- }
- },
"node_modules/lru-cache": {
"version": "5.1.1",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz",
@@ -1663,6 +1551,14 @@
"yallist": "^3.0.2"
}
},
+ "node_modules/lz-string": {
+ "version": "1.5.0",
+ "resolved": "https://registry.npmjs.org/lz-string/-/lz-string-1.5.0.tgz",
+ "integrity": "sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==",
+ "bin": {
+ "lz-string": "bin/bin.js"
+ }
+ },
"node_modules/mdast-util-definitions": {
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/mdast-util-definitions/-/mdast-util-definitions-5.1.2.tgz",
@@ -2202,42 +2098,16 @@
"node": ">=0.10.0"
}
},
- "node_modules/parse-entities": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/parse-entities/-/parse-entities-2.0.0.tgz",
- "integrity": "sha512-kkywGpCcRYhqQIchaWqZ875wzpS/bMKhz5HnN3p7wveJTkTtyAB/AlnS0f8DFSqYW1T82t6yEAkEcB+A1I3MbQ==",
- "dependencies": {
- "character-entities": "^1.0.0",
- "character-entities-legacy": "^1.0.0",
- "character-reference-invalid": "^1.0.0",
- "is-alphanumerical": "^1.0.0",
- "is-decimal": "^1.0.0",
- "is-hexadecimal": "^1.0.0"
- },
- "funding": {
- "type": "github",
- "url": "https://github.com/sponsors/wooorm"
- }
- },
- "node_modules/parse-entities/node_modules/character-entities": {
- "version": "1.2.4",
- "resolved": "https://registry.npmjs.org/character-entities/-/character-entities-1.2.4.tgz",
- "integrity": "sha512-iBMyeEHxfVnIakwOuDXpVkc54HijNgCyQB2w0VfGQThle6NXn50zU6V/u+LDhxHcDUPojn6Kpga3PTAD8W1bQw==",
- "funding": {
- "type": "github",
- "url": "https://github.com/sponsors/wooorm"
- }
- },
"node_modules/picocolors": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz",
- "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==",
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.0.tgz",
+ "integrity": "sha512-TQ92mBOW0l3LeMeyLV6mzy/kWr8lkd/hp3mTg7wYK7zJhuBStmGMBG0BdeDZS/dZx1IukaX6Bk11zcln25o1Aw==",
"dev": true
},
"node_modules/postcss": {
- "version": "8.4.33",
- "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.33.tgz",
- "integrity": "sha512-Kkpbhhdjw2qQs2O2DGX+8m5OVqEcbB9HRBvuYM9pgrjEFUg30A9LmXNlTAUj4S9kgtGyrMbTzVjH7E+s5Re2yg==",
+ "version": "8.4.47",
+ "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.47.tgz",
+ "integrity": "sha512-56rxCq7G/XfB4EkXq9Egn5GCqugWvDFjafDOThIdMBsI15iqPqR5r15TfSr1YPYeEI19YeaXMCbY6u88Y76GLQ==",
"dev": true,
"funding": [
{
@@ -2255,21 +2125,13 @@
],
"dependencies": {
"nanoid": "^3.3.7",
- "picocolors": "^1.0.0",
- "source-map-js": "^1.0.2"
+ "picocolors": "^1.1.0",
+ "source-map-js": "^1.2.1"
},
"engines": {
"node": "^10 || ^12 || >=14"
}
},
- "node_modules/prismjs": {
- "version": "1.29.0",
- "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.29.0.tgz",
- "integrity": "sha512-Kx/1w86q/epKcmte75LNrEoT+lX8pBpavuAbvJWRXar7Hz8jrtF+e3vY751p0R8H9HdArwaCTNDDzHg/ScJK1Q==",
- "engines": {
- "node": ">=6"
- }
- },
"node_modules/prop-types": {
"version": "15.8.1",
"resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz",
@@ -2353,37 +2215,14 @@
}
},
"node_modules/react-refresh": {
- "version": "0.14.0",
- "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.14.0.tgz",
- "integrity": "sha512-wViHqhAd8OHeLS/IRMJjTSDHF3U9eWi62F/MledQGPdJGDhodXJ9PBLNGr6WWL7qlH12Mt3TyTpbS+hGXMjCzQ==",
+ "version": "0.14.2",
+ "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.14.2.tgz",
+ "integrity": "sha512-jCvmsr+1IUSMUyzOkRcvnVbX3ZYC6g9TDrDbFuFmRDq7PD4yaGbLKNQL6k2jnArV8hjYxh7hVhAZB6s9HDGpZA==",
"dev": true,
"engines": {
"node": ">=0.10.0"
}
},
- "node_modules/react-syntax-highlighter": {
- "version": "15.5.0",
- "resolved": "https://registry.npmjs.org/react-syntax-highlighter/-/react-syntax-highlighter-15.5.0.tgz",
- "integrity": "sha512-+zq2myprEnQmH5yw6Gqc8lD55QHnpKaU8TOcFeC/Lg/MQSs8UknEA0JC4nTZGFAXC2J2Hyj/ijJ7NlabyPi2gg==",
- "dependencies": {
- "@babel/runtime": "^7.3.1",
- "highlight.js": "^10.4.1",
- "lowlight": "^1.17.0",
- "prismjs": "^1.27.0",
- "refractor": "^3.6.0"
- },
- "peerDependencies": {
- "react": ">= 0.14.0"
- }
- },
- "node_modules/react-syntax-highlighter/node_modules/highlight.js": {
- "version": "10.7.3",
- "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-10.7.3.tgz",
- "integrity": "sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A==",
- "engines": {
- "node": "*"
- }
- },
"node_modules/react-toastify": {
"version": "9.1.3",
"resolved": "https://registry.npmjs.org/react-toastify/-/react-toastify-9.1.3.tgz",
@@ -2396,33 +2235,6 @@
"react-dom": ">=16"
}
},
- "node_modules/refractor": {
- "version": "3.6.0",
- "resolved": "https://registry.npmjs.org/refractor/-/refractor-3.6.0.tgz",
- "integrity": "sha512-MY9W41IOWxxk31o+YvFCNyNzdkc9M20NoZK5vq6jkv4I/uh2zkWcfudj0Q1fovjUQJrNewS9NMzeTtqPf+n5EA==",
- "dependencies": {
- "hastscript": "^6.0.0",
- "parse-entities": "^2.0.0",
- "prismjs": "~1.27.0"
- },
- "funding": {
- "type": "github",
- "url": "https://github.com/sponsors/wooorm"
- }
- },
- "node_modules/refractor/node_modules/prismjs": {
- "version": "1.27.0",
- "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.27.0.tgz",
- "integrity": "sha512-t13BGPUlFDR7wRB5kQDG4jjl7XeuH6jbJGt11JHPL96qwsEHNX2+68tFXqc1/k+/jALsbSWJKUOT/hcYAZ5LkA==",
- "engines": {
- "node": ">=6"
- }
- },
- "node_modules/regenerator-runtime": {
- "version": "0.14.1",
- "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz",
- "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw=="
- },
"node_modules/remark-parse": {
"version": "10.0.2",
"resolved": "https://registry.npmjs.org/remark-parse/-/remark-parse-10.0.2.tgz",
@@ -2453,9 +2265,9 @@
}
},
"node_modules/rollup": {
- "version": "4.9.6",
- "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.9.6.tgz",
- "integrity": "sha512-05lzkCS2uASX0CiLFybYfVkwNbKZG5NFQ6Go0VWyogFTXXbR039UVsegViTntkk4OglHBdF54ccApXRRuXRbsg==",
+ "version": "4.22.4",
+ "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.22.4.tgz",
+ "integrity": "sha512-vD8HJ5raRcWOyymsR6Z3o6+RzfEPCnVLMFJ6vRslO1jt4LO6dUo5Qnpg7y4RkZFM2DMe3WUirkI5c16onjrc6A==",
"dev": true,
"dependencies": {
"@types/estree": "1.0.5"
@@ -2468,19 +2280,22 @@
"npm": ">=8.0.0"
},
"optionalDependencies": {
- "@rollup/rollup-android-arm-eabi": "4.9.6",
- "@rollup/rollup-android-arm64": "4.9.6",
- "@rollup/rollup-darwin-arm64": "4.9.6",
- "@rollup/rollup-darwin-x64": "4.9.6",
- "@rollup/rollup-linux-arm-gnueabihf": "4.9.6",
- "@rollup/rollup-linux-arm64-gnu": "4.9.6",
- "@rollup/rollup-linux-arm64-musl": "4.9.6",
- "@rollup/rollup-linux-riscv64-gnu": "4.9.6",
- "@rollup/rollup-linux-x64-gnu": "4.9.6",
- "@rollup/rollup-linux-x64-musl": "4.9.6",
- "@rollup/rollup-win32-arm64-msvc": "4.9.6",
- "@rollup/rollup-win32-ia32-msvc": "4.9.6",
- "@rollup/rollup-win32-x64-msvc": "4.9.6",
+ "@rollup/rollup-android-arm-eabi": "4.22.4",
+ "@rollup/rollup-android-arm64": "4.22.4",
+ "@rollup/rollup-darwin-arm64": "4.22.4",
+ "@rollup/rollup-darwin-x64": "4.22.4",
+ "@rollup/rollup-linux-arm-gnueabihf": "4.22.4",
+ "@rollup/rollup-linux-arm-musleabihf": "4.22.4",
+ "@rollup/rollup-linux-arm64-gnu": "4.22.4",
+ "@rollup/rollup-linux-arm64-musl": "4.22.4",
+ "@rollup/rollup-linux-powerpc64le-gnu": "4.22.4",
+ "@rollup/rollup-linux-riscv64-gnu": "4.22.4",
+ "@rollup/rollup-linux-s390x-gnu": "4.22.4",
+ "@rollup/rollup-linux-x64-gnu": "4.22.4",
+ "@rollup/rollup-linux-x64-musl": "4.22.4",
+ "@rollup/rollup-win32-arm64-msvc": "4.22.4",
+ "@rollup/rollup-win32-ia32-msvc": "4.22.4",
+ "@rollup/rollup-win32-x64-msvc": "4.22.4",
"fsevents": "~2.3.2"
}
},
@@ -2513,9 +2328,9 @@
}
},
"node_modules/source-map-js": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz",
- "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==",
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz",
+ "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==",
"dev": true,
"engines": {
"node": ">=0.10.0"
@@ -2673,9 +2488,9 @@
}
},
"node_modules/update-browserslist-db": {
- "version": "1.0.13",
- "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz",
- "integrity": "sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==",
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.0.tgz",
+ "integrity": "sha512-EdRAaAyk2cUE1wOf2DkEhzxqOQvFOoRJFNS6NeyJ01Gp2beMRpBAINjM2iDXE3KCuKhwnvHIQCJm6ThL2Z+HzQ==",
"dev": true,
"funding": [
{
@@ -2692,8 +2507,8 @@
}
],
"dependencies": {
- "escalade": "^3.1.1",
- "picocolors": "^1.0.0"
+ "escalade": "^3.1.2",
+ "picocolors": "^1.0.1"
},
"bin": {
"update-browserslist-db": "cli.js"
@@ -2756,14 +2571,14 @@
}
},
"node_modules/vite": {
- "version": "5.0.12",
- "resolved": "https://registry.npmjs.org/vite/-/vite-5.0.12.tgz",
- "integrity": "sha512-4hsnEkG3q0N4Tzf1+t6NdN9dg/L3BM+q8SWgbSPnJvrgH2kgdyzfVJwbR1ic69/4uMJJ/3dqDZZE5/WwqW8U1w==",
+ "version": "5.4.7",
+ "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.7.tgz",
+ "integrity": "sha512-5l2zxqMEPVENgvzTuBpHer2awaetimj2BGkhBPdnwKbPNOlHsODU+oiazEZzLK7KhAnOrO+XGYJYn4ZlUhDtDQ==",
"dev": true,
"dependencies": {
- "esbuild": "^0.19.3",
- "postcss": "^8.4.32",
- "rollup": "^4.2.0"
+ "esbuild": "^0.21.3",
+ "postcss": "^8.4.43",
+ "rollup": "^4.20.0"
},
"bin": {
"vite": "bin/vite.js"
@@ -2782,6 +2597,7 @@
"less": "*",
"lightningcss": "^1.21.0",
"sass": "*",
+ "sass-embedded": "*",
"stylus": "*",
"sugarss": "*",
"terser": "^5.4.0"
@@ -2799,6 +2615,9 @@
"sass": {
"optional": true
},
+ "sass-embedded": {
+ "optional": true
+ },
"stylus": {
"optional": true
},
@@ -2810,14 +2629,6 @@
}
}
},
- "node_modules/xtend": {
- "version": "4.0.2",
- "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz",
- "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==",
- "engines": {
- "node": ">=0.4"
- }
- },
"node_modules/yallist": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz",
diff --git a/package.json b/package.json
index ef7c383..d9ad1d0 100644
--- a/package.json
+++ b/package.json
@@ -5,19 +5,19 @@
"bundle": "dotnet fable src/App --outDir dist/ --run vite build"
},
"dependencies": {
- "@fable-org/fable-metadata": "^1.0.0",
- "@fable-org/fable-standalone": "^1.1.0",
+ "@fable-org/fable-metadata": "^1.1.0",
+ "@fable-org/fable-standalone": "^1.9.0",
"@monaco-editor/react": "^4.6.0",
+ "lz-string": "^1.5.0",
"monaco-editor": "^0.46.0",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-markdown": "^8.0.4",
- "react-syntax-highlighter": "^15.5.0",
"react-toastify": "^9.1.3",
"use-sync-external-store": "^1.2.0"
},
"devDependencies": {
- "@vitejs/plugin-react": "^4.2.1",
- "vite": "^5.0.12"
+ "@vitejs/plugin-react": "^4.3.1",
+ "vite": "^5.3.3"
}
-}
\ No newline at end of file
+}
diff --git a/public/css/pico.min.css b/public/css/pico.min.css
deleted file mode 100644
index 738a156..0000000
--- a/public/css/pico.min.css
+++ /dev/null
@@ -1,4 +0,0 @@
-@charset "UTF-8";/*!
- * Pico CSS ✨ v2.0.3 (https://picocss.com)
- * Copyright 2019-2024 - Licensed under MIT
- */:root{--pico-font-family-emoji:"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";--pico-font-family-sans-serif:system-ui,"Segoe UI",Roboto,Oxygen,Ubuntu,Cantarell,Helvetica,Arial,"Helvetica Neue",sans-serif,var(--pico-font-family-emoji);--pico-font-family-monospace:ui-monospace,SFMono-Regular,"SF Mono",Menlo,Consolas,"Liberation Mono",monospace,var(--pico-font-family-emoji);--pico-font-family:var(--pico-font-family-sans-serif);--pico-line-height:1.5;--pico-font-weight:400;--pico-font-size:100%;--pico-text-underline-offset:0.1rem;--pico-border-radius:0.25rem;--pico-border-width:0.0625rem;--pico-outline-width:0.125rem;--pico-transition:0.2s ease-in-out;--pico-spacing:1rem;--pico-typography-spacing-vertical:1rem;--pico-block-spacing-vertical:var(--pico-spacing);--pico-block-spacing-horizontal:var(--pico-spacing);--pico-grid-column-gap:var(--pico-spacing);--pico-grid-row-gap:var(--pico-spacing);--pico-form-element-spacing-vertical:0.75rem;--pico-form-element-spacing-horizontal:1rem;--pico-group-box-shadow:0 0 0 rgba(0, 0, 0, 0);--pico-group-box-shadow-focus-with-button:0 0 0 var(--pico-outline-width) var(--pico-primary-focus);--pico-group-box-shadow-focus-with-input:0 0 0 0.0625rem var(--pico-form-element-border-color);--pico-modal-overlay-backdrop-filter:blur(0.375rem);--pico-nav-element-spacing-vertical:1rem;--pico-nav-element-spacing-horizontal:0.5rem;--pico-nav-link-spacing-vertical:0.5rem;--pico-nav-link-spacing-horizontal:0.5rem;--pico-nav-breadcrumb-divider:">";--pico-icon-checkbox:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(255, 255, 255)' stroke-width='4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='20 6 9 17 4 12'%3E%3C/polyline%3E%3C/svg%3E");--pico-icon-minus:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(255, 255, 255)' stroke-width='4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cline x1='5' y1='12' x2='19' y2='12'%3E%3C/line%3E%3C/svg%3E");--pico-icon-chevron:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(136, 145, 164)' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'%3E%3C/polyline%3E%3C/svg%3E");--pico-icon-date:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(136, 145, 164)' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='3' y='4' width='18' height='18' rx='2' ry='2'%3E%3C/rect%3E%3Cline x1='16' y1='2' x2='16' y2='6'%3E%3C/line%3E%3Cline x1='8' y1='2' x2='8' y2='6'%3E%3C/line%3E%3Cline x1='3' y1='10' x2='21' y2='10'%3E%3C/line%3E%3C/svg%3E");--pico-icon-time:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(136, 145, 164)' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'%3E%3C/circle%3E%3Cpolyline points='12 6 12 12 16 14'%3E%3C/polyline%3E%3C/svg%3E");--pico-icon-search:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(136, 145, 164)' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='11' cy='11' r='8'%3E%3C/circle%3E%3Cline x1='21' y1='21' x2='16.65' y2='16.65'%3E%3C/line%3E%3C/svg%3E");--pico-icon-close:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(136, 145, 164)' stroke-width='3' stroke-linecap='round' stroke-linejoin='round'%3E%3Cline x1='18' y1='6' x2='6' y2='18'%3E%3C/line%3E%3Cline x1='6' y1='6' x2='18' y2='18'%3E%3C/line%3E%3C/svg%3E");--pico-icon-loading:url("data:image/svg+xml,%3Csvg fill='none' height='24' width='24' viewBox='0 0 24 24' xmlns='http://www.w3.org/2000/svg' %3E%3Cstyle%3E g %7B animation: rotate 2s linear infinite; transform-origin: center center; %7D circle %7B stroke-dasharray: 75,100; stroke-dashoffset: -5; animation: dash 1.5s ease-in-out infinite; stroke-linecap: round; %7D @keyframes rotate %7B 0%25 %7B transform: rotate(0deg); %7D 100%25 %7B transform: rotate(360deg); %7D %7D @keyframes dash %7B 0%25 %7B stroke-dasharray: 1,100; stroke-dashoffset: 0; %7D 50%25 %7B stroke-dasharray: 44.5,100; stroke-dashoffset: -17.5; %7D 100%25 %7B stroke-dasharray: 44.5,100; stroke-dashoffset: -62; %7D %7D %3C/style%3E%3Cg%3E%3Ccircle cx='12' cy='12' r='10' fill='none' stroke='rgb(136, 145, 164)' stroke-width='4' /%3E%3C/g%3E%3C/svg%3E")}@media (min-width:576px){:root{--pico-font-size:106.25%}}@media (min-width:768px){:root{--pico-font-size:112.5%}}@media (min-width:1024px){:root{--pico-font-size:118.75%}}@media (min-width:1280px){:root{--pico-font-size:125%}}@media (min-width:1536px){:root{--pico-font-size:131.25%}}a{--pico-text-decoration:underline}a.contrast,a.secondary{--pico-text-decoration:underline}small{--pico-font-size:0.875em}h1,h2,h3,h4,h5,h6{--pico-font-weight:700}h1{--pico-font-size:2rem;--pico-line-height:1.125;--pico-typography-spacing-top:3rem}h2{--pico-font-size:1.75rem;--pico-line-height:1.15;--pico-typography-spacing-top:2.625rem}h3{--pico-font-size:1.5rem;--pico-line-height:1.175;--pico-typography-spacing-top:2.25rem}h4{--pico-font-size:1.25rem;--pico-line-height:1.2;--pico-typography-spacing-top:1.874rem}h5{--pico-font-size:1.125rem;--pico-line-height:1.225;--pico-typography-spacing-top:1.6875rem}h6{--pico-font-size:1rem;--pico-line-height:1.25;--pico-typography-spacing-top:1.5rem}tfoot td,tfoot th,thead td,thead th{--pico-font-weight:600;--pico-border-width:0.1875rem}code,kbd,pre,samp{--pico-font-family:var(--pico-font-family-monospace)}kbd{--pico-font-weight:bolder}:where(select,textarea),input:not([type=submit],[type=button],[type=reset],[type=checkbox],[type=radio],[type=file]){--pico-outline-width:0.0625rem}[type=search]{--pico-border-radius:5rem}[type=checkbox],[type=radio]{--pico-border-width:0.125rem}[type=checkbox][role=switch]{--pico-border-width:0.1875rem}details.dropdown summary:not([role=button]){--pico-outline-width:0.0625rem}nav details.dropdown summary:focus-visible{--pico-outline-width:0.125rem}[role=search]{--pico-border-radius:5rem}[role=group]:has(button.secondary:focus,[type=submit].secondary:focus,[type=button].secondary:focus,[role=button].secondary:focus),[role=search]:has(button.secondary:focus,[type=submit].secondary:focus,[type=button].secondary:focus,[role=button].secondary:focus){--pico-group-box-shadow-focus-with-button:0 0 0 var(--pico-outline-width) var(--pico-secondary-focus)}[role=group]:has(button.contrast:focus,[type=submit].contrast:focus,[type=button].contrast:focus,[role=button].contrast:focus),[role=search]:has(button.contrast:focus,[type=submit].contrast:focus,[type=button].contrast:focus,[role=button].contrast:focus){--pico-group-box-shadow-focus-with-button:0 0 0 var(--pico-outline-width) var(--pico-contrast-focus)}[role=group] [role=button],[role=group] [type=button],[role=group] [type=submit],[role=group] button,[role=search] [role=button],[role=search] [type=button],[role=search] [type=submit],[role=search] button{--pico-form-element-spacing-horizontal:2rem}details summary[role=button]:not(.outline)::after{filter:brightness(0) invert(1)}[aria-busy=true]:not(input,select,textarea):is(button,[type=submit],[type=button],[type=reset],[role=button]):not(.outline)::before{filter:brightness(0) invert(1)}:root:not([data-theme=dark]),[data-theme=light]{--pico-background-color:#fff;--pico-color:#373c44;--pico-text-selection-color:rgba(2, 154, 232, 0.25);--pico-muted-color:#646b79;--pico-muted-border-color:#e7eaf0;--pico-primary:#0172ad;--pico-primary-background:#0172ad;--pico-primary-border:var(--pico-primary-background);--pico-primary-underline:rgba(1, 114, 173, 0.5);--pico-primary-hover:#015887;--pico-primary-hover-background:#02659a;--pico-primary-hover-border:var(--pico-primary-hover-background);--pico-primary-hover-underline:var(--pico-primary-hover);--pico-primary-focus:rgba(2, 154, 232, 0.5);--pico-primary-inverse:#fff;--pico-secondary:#5d6b89;--pico-secondary-background:#525f7a;--pico-secondary-border:var(--pico-secondary-background);--pico-secondary-underline:rgba(93, 107, 137, 0.5);--pico-secondary-hover:#48536b;--pico-secondary-hover-background:#48536b;--pico-secondary-hover-border:var(--pico-secondary-hover-background);--pico-secondary-hover-underline:var(--pico-secondary-hover);--pico-secondary-focus:rgba(93, 107, 137, 0.25);--pico-secondary-inverse:#fff;--pico-contrast:#181c25;--pico-contrast-background:#181c25;--pico-contrast-border:var(--pico-contrast-background);--pico-contrast-underline:rgba(24, 28, 37, 0.5);--pico-contrast-hover:#000;--pico-contrast-hover-background:#000;--pico-contrast-hover-border:var(--pico-contrast-hover-background);--pico-contrast-hover-underline:var(--pico-secondary-hover);--pico-contrast-focus:rgba(93, 107, 137, 0.25);--pico-contrast-inverse:#fff;--pico-box-shadow:0.0145rem 0.029rem 0.174rem rgba(129, 145, 181, 0.01698),0.0335rem 0.067rem 0.402rem rgba(129, 145, 181, 0.024),0.0625rem 0.125rem 0.75rem rgba(129, 145, 181, 0.03),0.1125rem 0.225rem 1.35rem rgba(129, 145, 181, 0.036),0.2085rem 0.417rem 2.502rem rgba(129, 145, 181, 0.04302),0.5rem 1rem 6rem rgba(129, 145, 181, 0.06),0 0 0 0.0625rem rgba(129, 145, 181, 0.015);--pico-h1-color:#2d3138;--pico-h2-color:#373c44;--pico-h3-color:#424751;--pico-h4-color:#4d535e;--pico-h5-color:#5c6370;--pico-h6-color:#646b79;--pico-mark-background-color:#fde7c0;--pico-mark-color:#0f1114;--pico-ins-color:#1d6a54;--pico-del-color:#883935;--pico-blockquote-border-color:var(--pico-muted-border-color);--pico-blockquote-footer-color:var(--pico-muted-color);--pico-button-box-shadow:0 0 0 rgba(0, 0, 0, 0);--pico-button-hover-box-shadow:0 0 0 rgba(0, 0, 0, 0);--pico-table-border-color:var(--pico-muted-border-color);--pico-table-row-stripped-background-color:rgba(111, 120, 135, 0.0375);--pico-code-background-color:#f3f5f7;--pico-code-color:#646b79;--pico-code-kbd-background-color:var(--pico-color);--pico-code-kbd-color:var(--pico-background-color);--pico-form-element-background-color:#fbfcfc;--pico-form-element-selected-background-color:#dfe3eb;--pico-form-element-border-color:#cfd5e2;--pico-form-element-color:#23262c;--pico-form-element-placeholder-color:var(--pico-muted-color);--pico-form-element-active-background-color:#fff;--pico-form-element-active-border-color:var(--pico-primary-border);--pico-form-element-focus-color:var(--pico-primary-border);--pico-form-element-disabled-opacity:0.5;--pico-form-element-invalid-border-color:#b86a6b;--pico-form-element-invalid-active-border-color:#c84f48;--pico-form-element-invalid-focus-color:var(--pico-form-element-invalid-active-border-color);--pico-form-element-valid-border-color:#4c9b8a;--pico-form-element-valid-active-border-color:#279977;--pico-form-element-valid-focus-color:var(--pico-form-element-valid-active-border-color);--pico-switch-background-color:#bfc7d9;--pico-switch-checked-background-color:var(--pico-primary-background);--pico-switch-color:#fff;--pico-switch-thumb-box-shadow:0 0 0 rgba(0, 0, 0, 0);--pico-range-border-color:#dfe3eb;--pico-range-active-border-color:#bfc7d9;--pico-range-thumb-border-color:var(--pico-background-color);--pico-range-thumb-color:var(--pico-secondary-background);--pico-range-thumb-active-color:var(--pico-primary-background);--pico-accordion-border-color:var(--pico-muted-border-color);--pico-accordion-active-summary-color:var(--pico-primary-hover);--pico-accordion-close-summary-color:var(--pico-color);--pico-accordion-open-summary-color:var(--pico-muted-color);--pico-card-background-color:var(--pico-background-color);--pico-card-border-color:var(--pico-muted-border-color);--pico-card-box-shadow:var(--pico-box-shadow);--pico-card-sectioning-background-color:#fbfcfc;--pico-dropdown-background-color:#fff;--pico-dropdown-border-color:#eff1f4;--pico-dropdown-box-shadow:var(--pico-box-shadow);--pico-dropdown-color:var(--pico-color);--pico-dropdown-hover-background-color:#eff1f4;--pico-loading-spinner-opacity:0.5;--pico-modal-overlay-background-color:rgba(232, 234, 237, 0.75);--pico-progress-background-color:#dfe3eb;--pico-progress-color:var(--pico-primary-background);--pico-tooltip-background-color:var(--pico-contrast-background);--pico-tooltip-color:var(--pico-contrast-inverse);--pico-icon-valid:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(76, 155, 138)' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='20 6 9 17 4 12'%3E%3C/polyline%3E%3C/svg%3E");--pico-icon-invalid:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(200, 79, 72)' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'%3E%3C/circle%3E%3Cline x1='12' y1='8' x2='12' y2='12'%3E%3C/line%3E%3Cline x1='12' y1='16' x2='12.01' y2='16'%3E%3C/line%3E%3C/svg%3E");color-scheme:light}:root:not([data-theme=dark]) input:is([type=submit],[type=button],[type=reset],[type=checkbox],[type=radio],[type=file]),[data-theme=light] input:is([type=submit],[type=button],[type=reset],[type=checkbox],[type=radio],[type=file]){--pico-form-element-focus-color:var(--pico-primary-focus)}@media only screen and (prefers-color-scheme:dark){:root:not([data-theme]){--pico-background-color:#13171f;--pico-color:#c2c7d0;--pico-text-selection-color:rgba(1, 170, 255, 0.1875);--pico-muted-color:#7b8495;--pico-muted-border-color:#202632;--pico-primary:#01aaff;--pico-primary-background:#0172ad;--pico-primary-border:var(--pico-primary-background);--pico-primary-underline:rgba(1, 170, 255, 0.5);--pico-primary-hover:#79c0ff;--pico-primary-hover-background:#017fc0;--pico-primary-hover-border:var(--pico-primary-hover-background);--pico-primary-hover-underline:var(--pico-primary-hover);--pico-primary-focus:rgba(1, 170, 255, 0.375);--pico-primary-inverse:#fff;--pico-secondary:#969eaf;--pico-secondary-background:#525f7a;--pico-secondary-border:var(--pico-secondary-background);--pico-secondary-underline:rgba(150, 158, 175, 0.5);--pico-secondary-hover:#b3b9c5;--pico-secondary-hover-background:#5d6b89;--pico-secondary-hover-border:var(--pico-secondary-hover-background);--pico-secondary-hover-underline:var(--pico-secondary-hover);--pico-secondary-focus:rgba(144, 158, 190, 0.25);--pico-secondary-inverse:#fff;--pico-contrast:#dfe3eb;--pico-contrast-background:#eff1f4;--pico-contrast-border:var(--pico-contrast-background);--pico-contrast-underline:rgba(223, 227, 235, 0.5);--pico-contrast-hover:#fff;--pico-contrast-hover-background:#fff;--pico-contrast-hover-border:var(--pico-contrast-hover-background);--pico-contrast-hover-underline:var(--pico-contrast-hover);--pico-contrast-focus:rgba(207, 213, 226, 0.25);--pico-contrast-inverse:#000;--pico-box-shadow:0.0145rem 0.029rem 0.174rem rgba(7, 9, 12, 0.01698),0.0335rem 0.067rem 0.402rem rgba(7, 9, 12, 0.024),0.0625rem 0.125rem 0.75rem rgba(7, 9, 12, 0.03),0.1125rem 0.225rem 1.35rem rgba(7, 9, 12, 0.036),0.2085rem 0.417rem 2.502rem rgba(7, 9, 12, 0.04302),0.5rem 1rem 6rem rgba(7, 9, 12, 0.06),0 0 0 0.0625rem rgba(7, 9, 12, 0.015);--pico-h1-color:#f0f1f3;--pico-h2-color:#e0e3e7;--pico-h3-color:#c2c7d0;--pico-h4-color:#b3b9c5;--pico-h5-color:#a4acba;--pico-h6-color:#8891a4;--pico-mark-background-color:#014063;--pico-mark-color:#fff;--pico-ins-color:#62af9a;--pico-del-color:#ce7e7b;--pico-blockquote-border-color:var(--pico-muted-border-color);--pico-blockquote-footer-color:var(--pico-muted-color);--pico-button-box-shadow:0 0 0 rgba(0, 0, 0, 0);--pico-button-hover-box-shadow:0 0 0 rgba(0, 0, 0, 0);--pico-table-border-color:var(--pico-muted-border-color);--pico-table-row-stripped-background-color:rgba(111, 120, 135, 0.0375);--pico-code-background-color:#1a1f28;--pico-code-color:#8891a4;--pico-code-kbd-background-color:var(--pico-color);--pico-code-kbd-color:var(--pico-background-color);--pico-form-element-background-color:#1c212c;--pico-form-element-selected-background-color:#2a3140;--pico-form-element-border-color:#2a3140;--pico-form-element-color:#e0e3e7;--pico-form-element-placeholder-color:#8891a4;--pico-form-element-active-background-color:#1a1f28;--pico-form-element-active-border-color:var(--pico-primary-border);--pico-form-element-focus-color:var(--pico-primary-border);--pico-form-element-disabled-opacity:0.5;--pico-form-element-invalid-border-color:#964a50;--pico-form-element-invalid-active-border-color:#b7403b;--pico-form-element-invalid-focus-color:var(--pico-form-element-invalid-active-border-color);--pico-form-element-valid-border-color:#2a7b6f;--pico-form-element-valid-active-border-color:#16896a;--pico-form-element-valid-focus-color:var(--pico-form-element-valid-active-border-color);--pico-switch-background-color:#333c4e;--pico-switch-checked-background-color:var(--pico-primary-background);--pico-switch-color:#fff;--pico-switch-thumb-box-shadow:0 0 0 rgba(0, 0, 0, 0);--pico-range-border-color:#202632;--pico-range-active-border-color:#2a3140;--pico-range-thumb-border-color:var(--pico-background-color);--pico-range-thumb-color:var(--pico-secondary-background);--pico-range-thumb-active-color:var(--pico-primary-background);--pico-accordion-border-color:var(--pico-muted-border-color);--pico-accordion-active-summary-color:var(--pico-primary-hover);--pico-accordion-close-summary-color:var(--pico-color);--pico-accordion-open-summary-color:var(--pico-muted-color);--pico-card-background-color:#181c25;--pico-card-border-color:var(--pico-card-background-color);--pico-card-box-shadow:var(--pico-box-shadow);--pico-card-sectioning-background-color:#1a1f28;--pico-dropdown-background-color:#181c25;--pico-dropdown-border-color:#202632;--pico-dropdown-box-shadow:var(--pico-box-shadow);--pico-dropdown-color:var(--pico-color);--pico-dropdown-hover-background-color:#202632;--pico-loading-spinner-opacity:0.5;--pico-modal-overlay-background-color:rgba(8, 9, 10, 0.75);--pico-progress-background-color:#202632;--pico-progress-color:var(--pico-primary-background);--pico-tooltip-background-color:var(--pico-contrast-background);--pico-tooltip-color:var(--pico-contrast-inverse);--pico-icon-valid:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(42, 123, 111)' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='20 6 9 17 4 12'%3E%3C/polyline%3E%3C/svg%3E");--pico-icon-invalid:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(150, 74, 80)' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'%3E%3C/circle%3E%3Cline x1='12' y1='8' x2='12' y2='12'%3E%3C/line%3E%3Cline x1='12' y1='16' x2='12.01' y2='16'%3E%3C/line%3E%3C/svg%3E");color-scheme:dark}:root:not([data-theme]) input:is([type=submit],[type=button],[type=reset],[type=checkbox],[type=radio],[type=file]){--pico-form-element-focus-color:var(--pico-primary-focus)}:root:not([data-theme]) details summary[role=button].contrast:not(.outline)::after{filter:brightness(0)}:root:not([data-theme]) [aria-busy=true]:not(input,select,textarea).contrast:is(button,[type=submit],[type=button],[type=reset],[role=button]):not(.outline)::before{filter:brightness(0)}}[data-theme=dark]{--pico-background-color:#13171f;--pico-color:#c2c7d0;--pico-text-selection-color:rgba(1, 170, 255, 0.1875);--pico-muted-color:#7b8495;--pico-muted-border-color:#202632;--pico-primary:#01aaff;--pico-primary-background:#0172ad;--pico-primary-border:var(--pico-primary-background);--pico-primary-underline:rgba(1, 170, 255, 0.5);--pico-primary-hover:#79c0ff;--pico-primary-hover-background:#017fc0;--pico-primary-hover-border:var(--pico-primary-hover-background);--pico-primary-hover-underline:var(--pico-primary-hover);--pico-primary-focus:rgba(1, 170, 255, 0.375);--pico-primary-inverse:#fff;--pico-secondary:#969eaf;--pico-secondary-background:#525f7a;--pico-secondary-border:var(--pico-secondary-background);--pico-secondary-underline:rgba(150, 158, 175, 0.5);--pico-secondary-hover:#b3b9c5;--pico-secondary-hover-background:#5d6b89;--pico-secondary-hover-border:var(--pico-secondary-hover-background);--pico-secondary-hover-underline:var(--pico-secondary-hover);--pico-secondary-focus:rgba(144, 158, 190, 0.25);--pico-secondary-inverse:#fff;--pico-contrast:#dfe3eb;--pico-contrast-background:#eff1f4;--pico-contrast-border:var(--pico-contrast-background);--pico-contrast-underline:rgba(223, 227, 235, 0.5);--pico-contrast-hover:#fff;--pico-contrast-hover-background:#fff;--pico-contrast-hover-border:var(--pico-contrast-hover-background);--pico-contrast-hover-underline:var(--pico-contrast-hover);--pico-contrast-focus:rgba(207, 213, 226, 0.25);--pico-contrast-inverse:#000;--pico-box-shadow:0.0145rem 0.029rem 0.174rem rgba(7, 9, 12, 0.01698),0.0335rem 0.067rem 0.402rem rgba(7, 9, 12, 0.024),0.0625rem 0.125rem 0.75rem rgba(7, 9, 12, 0.03),0.1125rem 0.225rem 1.35rem rgba(7, 9, 12, 0.036),0.2085rem 0.417rem 2.502rem rgba(7, 9, 12, 0.04302),0.5rem 1rem 6rem rgba(7, 9, 12, 0.06),0 0 0 0.0625rem rgba(7, 9, 12, 0.015);--pico-h1-color:#f0f1f3;--pico-h2-color:#e0e3e7;--pico-h3-color:#c2c7d0;--pico-h4-color:#b3b9c5;--pico-h5-color:#a4acba;--pico-h6-color:#8891a4;--pico-mark-background-color:#014063;--pico-mark-color:#fff;--pico-ins-color:#62af9a;--pico-del-color:#ce7e7b;--pico-blockquote-border-color:var(--pico-muted-border-color);--pico-blockquote-footer-color:var(--pico-muted-color);--pico-button-box-shadow:0 0 0 rgba(0, 0, 0, 0);--pico-button-hover-box-shadow:0 0 0 rgba(0, 0, 0, 0);--pico-table-border-color:var(--pico-muted-border-color);--pico-table-row-stripped-background-color:rgba(111, 120, 135, 0.0375);--pico-code-background-color:#1a1f28;--pico-code-color:#8891a4;--pico-code-kbd-background-color:var(--pico-color);--pico-code-kbd-color:var(--pico-background-color);--pico-form-element-background-color:#1c212c;--pico-form-element-selected-background-color:#2a3140;--pico-form-element-border-color:#2a3140;--pico-form-element-color:#e0e3e7;--pico-form-element-placeholder-color:#8891a4;--pico-form-element-active-background-color:#1a1f28;--pico-form-element-active-border-color:var(--pico-primary-border);--pico-form-element-focus-color:var(--pico-primary-border);--pico-form-element-disabled-opacity:0.5;--pico-form-element-invalid-border-color:#964a50;--pico-form-element-invalid-active-border-color:#b7403b;--pico-form-element-invalid-focus-color:var(--pico-form-element-invalid-active-border-color);--pico-form-element-valid-border-color:#2a7b6f;--pico-form-element-valid-active-border-color:#16896a;--pico-form-element-valid-focus-color:var(--pico-form-element-valid-active-border-color);--pico-switch-background-color:#333c4e;--pico-switch-checked-background-color:var(--pico-primary-background);--pico-switch-color:#fff;--pico-switch-thumb-box-shadow:0 0 0 rgba(0, 0, 0, 0);--pico-range-border-color:#202632;--pico-range-active-border-color:#2a3140;--pico-range-thumb-border-color:var(--pico-background-color);--pico-range-thumb-color:var(--pico-secondary-background);--pico-range-thumb-active-color:var(--pico-primary-background);--pico-accordion-border-color:var(--pico-muted-border-color);--pico-accordion-active-summary-color:var(--pico-primary-hover);--pico-accordion-close-summary-color:var(--pico-color);--pico-accordion-open-summary-color:var(--pico-muted-color);--pico-card-background-color:#181c25;--pico-card-border-color:var(--pico-card-background-color);--pico-card-box-shadow:var(--pico-box-shadow);--pico-card-sectioning-background-color:#1a1f28;--pico-dropdown-background-color:#181c25;--pico-dropdown-border-color:#202632;--pico-dropdown-box-shadow:var(--pico-box-shadow);--pico-dropdown-color:var(--pico-color);--pico-dropdown-hover-background-color:#202632;--pico-loading-spinner-opacity:0.5;--pico-modal-overlay-background-color:rgba(8, 9, 10, 0.75);--pico-progress-background-color:#202632;--pico-progress-color:var(--pico-primary-background);--pico-tooltip-background-color:var(--pico-contrast-background);--pico-tooltip-color:var(--pico-contrast-inverse);--pico-icon-valid:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(42, 123, 111)' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='20 6 9 17 4 12'%3E%3C/polyline%3E%3C/svg%3E");--pico-icon-invalid:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='rgb(150, 74, 80)' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Ccircle cx='12' cy='12' r='10'%3E%3C/circle%3E%3Cline x1='12' y1='8' x2='12' y2='12'%3E%3C/line%3E%3Cline x1='12' y1='16' x2='12.01' y2='16'%3E%3C/line%3E%3C/svg%3E");color-scheme:dark}[data-theme=dark] input:is([type=submit],[type=button],[type=reset],[type=checkbox],[type=radio],[type=file]){--pico-form-element-focus-color:var(--pico-primary-focus)}[data-theme=dark] details summary[role=button].contrast:not(.outline)::after{filter:brightness(0)}[data-theme=dark] [aria-busy=true]:not(input,select,textarea).contrast:is(button,[type=submit],[type=button],[type=reset],[role=button]):not(.outline)::before{filter:brightness(0)}[type=checkbox],[type=radio],[type=range],progress{accent-color:var(--pico-primary)}*,::after,::before{box-sizing:border-box;background-repeat:no-repeat}::after,::before{text-decoration:inherit;vertical-align:inherit}:where(:root){-webkit-tap-highlight-color:transparent;-webkit-text-size-adjust:100%;-moz-text-size-adjust:100%;text-size-adjust:100%;background-color:var(--pico-background-color);color:var(--pico-color);font-weight:var(--pico-font-weight);font-size:var(--pico-font-size);line-height:var(--pico-line-height);font-family:var(--pico-font-family);text-underline-offset:var(--pico-text-underline-offset);text-rendering:optimizeLegibility;overflow-wrap:break-word;-moz-tab-size:4;-o-tab-size:4;tab-size:4}body{width:100%;margin:0}main{display:block}body>footer,body>header,body>main{padding-block:var(--pico-block-spacing-vertical)}section{margin-bottom:var(--pico-block-spacing-vertical)}.container,.container-fluid{width:100%;margin-right:auto;margin-left:auto;padding-right:var(--pico-spacing);padding-left:var(--pico-spacing)}@media (min-width:576px){.container{max-width:510px;padding-right:0;padding-left:0}}@media (min-width:768px){.container{max-width:700px}}@media (min-width:1024px){.container{max-width:950px}}@media (min-width:1280px){.container{max-width:1200px}}@media (min-width:1536px){.container{max-width:1450px}}.grid{grid-column-gap:var(--pico-grid-column-gap);grid-row-gap:var(--pico-grid-row-gap);display:grid;grid-template-columns:1fr}@media (min-width:768px){.grid{grid-template-columns:repeat(auto-fit,minmax(0%,1fr))}}.grid>*{min-width:0}.overflow-auto{overflow:auto}b,strong{font-weight:bolder}sub,sup{position:relative;font-size:.75em;line-height:0;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}address,blockquote,dl,ol,p,pre,table,ul{margin-top:0;margin-bottom:var(--pico-typography-spacing-vertical);color:var(--pico-color);font-style:normal;font-weight:var(--pico-font-weight)}h1,h2,h3,h4,h5,h6{margin-top:0;margin-bottom:var(--pico-typography-spacing-vertical);color:var(--pico-color);font-weight:var(--pico-font-weight);font-size:var(--pico-font-size);line-height:var(--pico-line-height);font-family:var(--pico-font-family)}h1{--pico-color:var(--pico-h1-color)}h2{--pico-color:var(--pico-h2-color)}h3{--pico-color:var(--pico-h3-color)}h4{--pico-color:var(--pico-h4-color)}h5{--pico-color:var(--pico-h5-color)}h6{--pico-color:var(--pico-h6-color)}:where(article,address,blockquote,dl,figure,form,ol,p,pre,table,ul)~:is(h1,h2,h3,h4,h5,h6){margin-top:var(--pico-typography-spacing-top)}p{margin-bottom:var(--pico-typography-spacing-vertical)}hgroup{margin-bottom:var(--pico-typography-spacing-vertical)}hgroup>*{margin-top:0;margin-bottom:0}hgroup>:not(:first-child):last-child{--pico-color:var(--pico-muted-color);--pico-font-weight:unset;font-size:1rem}:where(ol,ul) li{margin-bottom:calc(var(--pico-typography-spacing-vertical) * .25)}:where(dl,ol,ul) :where(dl,ol,ul){margin:0;margin-top:calc(var(--pico-typography-spacing-vertical) * .25)}ul li{list-style:square}mark{padding:.125rem .25rem;background-color:var(--pico-mark-background-color);color:var(--pico-mark-color);vertical-align:baseline}blockquote{display:block;margin:var(--pico-typography-spacing-vertical) 0;padding:var(--pico-spacing);border-right:none;border-left:.25rem solid var(--pico-blockquote-border-color);border-inline-start:0.25rem solid var(--pico-blockquote-border-color);border-inline-end:none}blockquote footer{margin-top:calc(var(--pico-typography-spacing-vertical) * .5);color:var(--pico-blockquote-footer-color)}abbr[title]{border-bottom:1px dotted;text-decoration:none;cursor:help}ins{color:var(--pico-ins-color);text-decoration:none}del{color:var(--pico-del-color)}::-moz-selection{background-color:var(--pico-text-selection-color)}::selection{background-color:var(--pico-text-selection-color)}:where(a:not([role=button])),[role=link]{--pico-color:var(--pico-primary);--pico-background-color:transparent;--pico-underline:var(--pico-primary-underline);outline:0;background-color:var(--pico-background-color);color:var(--pico-color);-webkit-text-decoration:var(--pico-text-decoration);text-decoration:var(--pico-text-decoration);text-decoration-color:var(--pico-underline);text-underline-offset:0.125em;transition:background-color var(--pico-transition),color var(--pico-transition),box-shadow var(--pico-transition),-webkit-text-decoration var(--pico-transition);transition:background-color var(--pico-transition),color var(--pico-transition),text-decoration var(--pico-transition),box-shadow var(--pico-transition);transition:background-color var(--pico-transition),color var(--pico-transition),text-decoration var(--pico-transition),box-shadow var(--pico-transition),-webkit-text-decoration var(--pico-transition)}:where(a:not([role=button])):is([aria-current]:not([aria-current=false]),:hover,:active,:focus),[role=link]:is([aria-current]:not([aria-current=false]),:hover,:active,:focus){--pico-color:var(--pico-primary-hover);--pico-underline:var(--pico-primary-hover-underline);--pico-text-decoration:underline}:where(a:not([role=button])):focus-visible,[role=link]:focus-visible{box-shadow:0 0 0 var(--pico-outline-width) var(--pico-primary-focus)}:where(a:not([role=button])).secondary,[role=link].secondary{--pico-color:var(--pico-secondary);--pico-underline:var(--pico-secondary-underline)}:where(a:not([role=button])).secondary:is([aria-current]:not([aria-current=false]),:hover,:active,:focus),[role=link].secondary:is([aria-current]:not([aria-current=false]),:hover,:active,:focus){--pico-color:var(--pico-secondary-hover);--pico-underline:var(--pico-secondary-hover-underline)}:where(a:not([role=button])).contrast,[role=link].contrast{--pico-color:var(--pico-contrast);--pico-underline:var(--pico-contrast-underline)}:where(a:not([role=button])).contrast:is([aria-current]:not([aria-current=false]),:hover,:active,:focus),[role=link].contrast:is([aria-current]:not([aria-current=false]),:hover,:active,:focus){--pico-color:var(--pico-contrast-hover);--pico-underline:var(--pico-contrast-hover-underline)}a[role=button]{display:inline-block}button{margin:0;overflow:visible;font-family:inherit;text-transform:none}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button}[role=button],[type=button],[type=file]::file-selector-button,[type=reset],[type=submit],button{--pico-background-color:var(--pico-primary-background);--pico-border-color:var(--pico-primary-border);--pico-color:var(--pico-primary-inverse);--pico-box-shadow:var(--pico-button-box-shadow, 0 0 0 rgba(0, 0, 0, 0));padding:var(--pico-form-element-spacing-vertical) var(--pico-form-element-spacing-horizontal);border:var(--pico-border-width) solid var(--pico-border-color);border-radius:var(--pico-border-radius);outline:0;background-color:var(--pico-background-color);box-shadow:var(--pico-box-shadow);color:var(--pico-color);font-weight:var(--pico-font-weight);font-size:1rem;line-height:var(--pico-line-height);text-align:center;text-decoration:none;cursor:pointer;-webkit-user-select:none;-moz-user-select:none;user-select:none;transition:background-color var(--pico-transition),border-color var(--pico-transition),color var(--pico-transition),box-shadow var(--pico-transition)}[role=button]:is(:hover,:active,:focus),[role=button]:is([aria-current]:not([aria-current=false])),[type=button]:is(:hover,:active,:focus),[type=button]:is([aria-current]:not([aria-current=false])),[type=file]::file-selector-button:is(:hover,:active,:focus),[type=file]::file-selector-button:is([aria-current]:not([aria-current=false])),[type=reset]:is(:hover,:active,:focus),[type=reset]:is([aria-current]:not([aria-current=false])),[type=submit]:is(:hover,:active,:focus),[type=submit]:is([aria-current]:not([aria-current=false])),button:is(:hover,:active,:focus),button:is([aria-current]:not([aria-current=false])){--pico-background-color:var(--pico-primary-hover-background);--pico-border-color:var(--pico-primary-hover-border);--pico-box-shadow:var(--pico-button-hover-box-shadow, 0 0 0 rgba(0, 0, 0, 0));--pico-color:var(--pico-primary-inverse)}[role=button]:focus,[role=button]:is([aria-current]:not([aria-current=false])):focus,[type=button]:focus,[type=button]:is([aria-current]:not([aria-current=false])):focus,[type=file]::file-selector-button:focus,[type=file]::file-selector-button:is([aria-current]:not([aria-current=false])):focus,[type=reset]:focus,[type=reset]:is([aria-current]:not([aria-current=false])):focus,[type=submit]:focus,[type=submit]:is([aria-current]:not([aria-current=false])):focus,button:focus,button:is([aria-current]:not([aria-current=false])):focus{--pico-box-shadow:var(--pico-button-hover-box-shadow, 0 0 0 rgba(0, 0, 0, 0)),0 0 0 var(--pico-outline-width) var(--pico-primary-focus)}[type=button],[type=reset],[type=submit]{margin-bottom:var(--pico-spacing)}:is(button,[type=submit],[type=button],[role=button]).secondary,[type=file]::file-selector-button,[type=reset]{--pico-background-color:var(--pico-secondary-background);--pico-border-color:var(--pico-secondary-border);--pico-color:var(--pico-secondary-inverse);cursor:pointer}:is(button,[type=submit],[type=button],[role=button]).secondary:is([aria-current]:not([aria-current=false]),:hover,:active,:focus),[type=file]::file-selector-button:is([aria-current]:not([aria-current=false]),:hover,:active,:focus),[type=reset]:is([aria-current]:not([aria-current=false]),:hover,:active,:focus){--pico-background-color:var(--pico-secondary-hover-background);--pico-border-color:var(--pico-secondary-hover-border);--pico-color:var(--pico-secondary-inverse)}:is(button,[type=submit],[type=button],[role=button]).secondary:focus,:is(button,[type=submit],[type=button],[role=button]).secondary:is([aria-current]:not([aria-current=false])):focus,[type=file]::file-selector-button:focus,[type=file]::file-selector-button:is([aria-current]:not([aria-current=false])):focus,[type=reset]:focus,[type=reset]:is([aria-current]:not([aria-current=false])):focus{--pico-box-shadow:var(--pico-button-hover-box-shadow, 0 0 0 rgba(0, 0, 0, 0)),0 0 0 var(--pico-outline-width) var(--pico-secondary-focus)}:is(button,[type=submit],[type=button],[role=button]).contrast{--pico-background-color:var(--pico-contrast-background);--pico-border-color:var(--pico-contrast-border);--pico-color:var(--pico-contrast-inverse)}:is(button,[type=submit],[type=button],[role=button]).contrast:is([aria-current]:not([aria-current=false]),:hover,:active,:focus){--pico-background-color:var(--pico-contrast-hover-background);--pico-border-color:var(--pico-contrast-hover-border);--pico-color:var(--pico-contrast-inverse)}:is(button,[type=submit],[type=button],[role=button]).contrast:focus,:is(button,[type=submit],[type=button],[role=button]).contrast:is([aria-current]:not([aria-current=false])):focus{--pico-box-shadow:var(--pico-button-hover-box-shadow, 0 0 0 rgba(0, 0, 0, 0)),0 0 0 var(--pico-outline-width) var(--pico-contrast-focus)}:is(button,[type=submit],[type=button],[role=button]).outline,[type=reset].outline{--pico-background-color:transparent;--pico-color:var(--pico-primary);--pico-border-color:var(--pico-primary)}:is(button,[type=submit],[type=button],[role=button]).outline:is([aria-current]:not([aria-current=false]),:hover,:active,:focus),[type=reset].outline:is([aria-current]:not([aria-current=false]),:hover,:active,:focus){--pico-background-color:transparent;--pico-color:var(--pico-primary-hover);--pico-border-color:var(--pico-primary-hover)}:is(button,[type=submit],[type=button],[role=button]).outline.secondary,[type=reset].outline{--pico-color:var(--pico-secondary);--pico-border-color:var(--pico-secondary)}:is(button,[type=submit],[type=button],[role=button]).outline.secondary:is([aria-current]:not([aria-current=false]),:hover,:active,:focus),[type=reset].outline:is([aria-current]:not([aria-current=false]),:hover,:active,:focus){--pico-color:var(--pico-secondary-hover);--pico-border-color:var(--pico-secondary-hover)}:is(button,[type=submit],[type=button],[role=button]).outline.contrast{--pico-color:var(--pico-contrast);--pico-border-color:var(--pico-contrast)}:is(button,[type=submit],[type=button],[role=button]).outline.contrast:is([aria-current]:not([aria-current=false]),:hover,:active,:focus){--pico-color:var(--pico-contrast-hover);--pico-border-color:var(--pico-contrast-hover)}:where(button,[type=submit],[type=reset],[type=button],[role=button])[disabled],:where(fieldset[disabled]) :is(button,[type=submit],[type=button],[type=reset],[role=button]){opacity:.5;pointer-events:none}:where(table){width:100%;border-collapse:collapse;border-spacing:0;text-indent:0}td,th{padding:calc(var(--pico-spacing)/ 2) var(--pico-spacing);border-bottom:var(--pico-border-width) solid var(--pico-table-border-color);background-color:var(--pico-background-color);color:var(--pico-color);font-weight:var(--pico-font-weight);text-align:left;text-align:start}tfoot td,tfoot th{border-top:var(--pico-border-width) solid var(--pico-table-border-color);border-bottom:0}table.striped tbody tr:nth-child(odd) td,table.striped tbody tr:nth-child(odd) th{background-color:var(--pico-table-row-stripped-background-color)}:where(audio,canvas,iframe,img,svg,video){vertical-align:middle}audio,video{display:inline-block}audio:not([controls]){display:none;height:0}:where(iframe){border-style:none}img{max-width:100%;height:auto;border-style:none}:where(svg:not([fill])){fill:currentColor}svg:not(:root){overflow:hidden}code,kbd,pre,samp{font-size:.875em;font-family:var(--pico-font-family)}pre code{font-size:inherit;font-family:inherit}pre{-ms-overflow-style:scrollbar;overflow:auto}code,kbd,pre{border-radius:var(--pico-border-radius);background:var(--pico-code-background-color);color:var(--pico-code-color);font-weight:var(--pico-font-weight);line-height:initial}code,kbd{display:inline-block;padding:.375rem}pre{display:block;margin-bottom:var(--pico-spacing);overflow-x:auto}pre>code{display:block;padding:var(--pico-spacing);background:0 0;line-height:var(--pico-line-height)}kbd{background-color:var(--pico-code-kbd-background-color);color:var(--pico-code-kbd-color);vertical-align:baseline}figure{display:block;margin:0;padding:0}figure figcaption{padding:calc(var(--pico-spacing) * .5) 0;color:var(--pico-muted-color)}hr{height:0;margin:var(--pico-typography-spacing-vertical) 0;border:0;border-top:1px solid var(--pico-muted-border-color);color:inherit}[hidden],template{display:none!important}canvas{display:inline-block}input,optgroup,select,textarea{margin:0;font-size:1rem;line-height:var(--pico-line-height);font-family:inherit;letter-spacing:inherit}input{overflow:visible}select{text-transform:none}legend{max-width:100%;padding:0;color:inherit;white-space:normal}textarea{overflow:auto}[type=checkbox],[type=radio]{padding:0}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}[type=search]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}::-moz-focus-inner{padding:0;border-style:none}:-moz-focusring{outline:0}:-moz-ui-invalid{box-shadow:none}::-ms-expand{display:none}[type=file],[type=range]{padding:0;border-width:0}input:not([type=checkbox],[type=radio],[type=range]){height:calc(1rem * var(--pico-line-height) + var(--pico-form-element-spacing-vertical) * 2 + var(--pico-border-width) * 2)}fieldset{width:100%;margin:0;margin-bottom:var(--pico-spacing);padding:0;border:0}fieldset legend,label{display:block;margin-bottom:calc(var(--pico-spacing) * .375);color:var(--pico-color);font-weight:var(--pico-form-label-font-weight,var(--pico-font-weight))}fieldset legend{margin-bottom:calc(var(--pico-spacing) * .5)}button[type=submit],input:not([type=checkbox],[type=radio]),select,textarea{width:100%}input:not([type=checkbox],[type=radio],[type=range],[type=file]),select,textarea{-webkit-appearance:none;-moz-appearance:none;appearance:none;padding:var(--pico-form-element-spacing-vertical) var(--pico-form-element-spacing-horizontal)}input,select,textarea{--pico-background-color:var(--pico-form-element-background-color);--pico-border-color:var(--pico-form-element-border-color);--pico-color:var(--pico-form-element-color);--pico-box-shadow:none;border:var(--pico-border-width) solid var(--pico-border-color);border-radius:var(--pico-border-radius);outline:0;background-color:var(--pico-background-color);box-shadow:var(--pico-box-shadow);color:var(--pico-color);font-weight:var(--pico-font-weight);transition:background-color var(--pico-transition),border-color var(--pico-transition),color var(--pico-transition),box-shadow var(--pico-transition)}:where(select,textarea):not([readonly]):is(:active,:focus),input:not([type=submit],[type=button],[type=reset],[type=checkbox],[type=radio],[readonly]):is(:active,:focus){--pico-background-color:var(--pico-form-element-active-background-color)}:where(select,textarea):not([readonly]):is(:active,:focus),input:not([type=submit],[type=button],[type=reset],[role=switch],[readonly]):is(:active,:focus){--pico-border-color:var(--pico-form-element-active-border-color)}:where(select,textarea):not([readonly]):focus,input:not([type=submit],[type=button],[type=reset],[type=range],[type=file],[readonly]):focus{--pico-box-shadow:0 0 0 var(--pico-outline-width) var(--pico-form-element-focus-color)}:where(fieldset[disabled]) :is(input:not([type=submit],[type=button],[type=reset]),select,textarea),input:not([type=submit],[type=button],[type=reset])[disabled],label[aria-disabled=true],select[disabled],textarea[disabled]{opacity:var(--pico-form-element-disabled-opacity);pointer-events:none}label[aria-disabled=true] input[disabled]{opacity:1}:where(input,select,textarea):not([type=checkbox],[type=radio],[type=date],[type=datetime-local],[type=month],[type=time],[type=week],[type=range])[aria-invalid]{padding-right:calc(var(--pico-form-element-spacing-horizontal) + 1.5rem)!important;padding-left:var(--pico-form-element-spacing-horizontal);padding-inline-start:var(--pico-form-element-spacing-horizontal)!important;padding-inline-end:calc(var(--pico-form-element-spacing-horizontal) + 1.5rem)!important;background-position:center right .75rem;background-size:1rem auto;background-repeat:no-repeat}:where(input,select,textarea):not([type=checkbox],[type=radio],[type=date],[type=datetime-local],[type=month],[type=time],[type=week],[type=range])[aria-invalid=false]:not(select){background-image:var(--pico-icon-valid)}:where(input,select,textarea):not([type=checkbox],[type=radio],[type=date],[type=datetime-local],[type=month],[type=time],[type=week],[type=range])[aria-invalid=true]:not(select){background-image:var(--pico-icon-invalid)}:where(input,select,textarea)[aria-invalid=false]{--pico-border-color:var(--pico-form-element-valid-border-color)}:where(input,select,textarea)[aria-invalid=false]:is(:active,:focus){--pico-border-color:var(--pico-form-element-valid-active-border-color)!important}:where(input,select,textarea)[aria-invalid=false]:is(:active,:focus):not([type=checkbox],[type=radio]){--pico-box-shadow:0 0 0 var(--pico-outline-width) var(--pico-form-element-valid-focus-color)!important}:where(input,select,textarea)[aria-invalid=true]{--pico-border-color:var(--pico-form-element-invalid-border-color)}:where(input,select,textarea)[aria-invalid=true]:is(:active,:focus){--pico-border-color:var(--pico-form-element-invalid-active-border-color)!important}:where(input,select,textarea)[aria-invalid=true]:is(:active,:focus):not([type=checkbox],[type=radio]){--pico-box-shadow:0 0 0 var(--pico-outline-width) var(--pico-form-element-invalid-focus-color)!important}[dir=rtl] :where(input,select,textarea):not([type=checkbox],[type=radio]):is([aria-invalid],[aria-invalid=true],[aria-invalid=false]){background-position:center left .75rem}input::-webkit-input-placeholder,input::placeholder,select:invalid,textarea::-webkit-input-placeholder,textarea::placeholder{color:var(--pico-form-element-placeholder-color);opacity:1}input:not([type=checkbox],[type=radio]),select,textarea{margin-bottom:var(--pico-spacing)}select::-ms-expand{border:0;background-color:transparent}select:not([multiple],[size]){padding-right:calc(var(--pico-form-element-spacing-horizontal) + 1.5rem);padding-left:var(--pico-form-element-spacing-horizontal);padding-inline-start:var(--pico-form-element-spacing-horizontal);padding-inline-end:calc(var(--pico-form-element-spacing-horizontal) + 1.5rem);background-image:var(--pico-icon-chevron);background-position:center right .75rem;background-size:1rem auto;background-repeat:no-repeat}select[multiple] option:checked{background:var(--pico-form-element-selected-background-color)}[dir=rtl] select:not([multiple],[size]){background-position:center left .75rem}textarea{display:block;resize:vertical}textarea[aria-invalid]{--pico-icon-height:calc(1rem * var(--pico-line-height) + var(--pico-form-element-spacing-vertical) * 2 + var(--pico-border-width) * 2);background-position:top right .75rem!important;background-size:1rem var(--pico-icon-height)!important}:where(input,select,textarea,fieldset,.grid)+small{display:block;width:100%;margin-top:calc(var(--pico-spacing) * -.75);margin-bottom:var(--pico-spacing);color:var(--pico-muted-color)}:where(input,select,textarea,fieldset,.grid)[aria-invalid=false]+small{color:var(--pico-ins-color)}:where(input,select,textarea,fieldset,.grid)[aria-invalid=true]+small{color:var(--pico-del-color)}label>:where(input,select,textarea){margin-top:calc(var(--pico-spacing) * .25)}label:has([type=checkbox],[type=radio]){width:-moz-fit-content;width:fit-content;cursor:pointer}[type=checkbox],[type=radio]{-webkit-appearance:none;-moz-appearance:none;appearance:none;width:1.25em;height:1.25em;margin-top:-.125em;margin-inline-end:.5em;border-width:var(--pico-border-width);vertical-align:middle;cursor:pointer}[type=checkbox]::-ms-check,[type=radio]::-ms-check{display:none}[type=checkbox]:checked,[type=checkbox]:checked:active,[type=checkbox]:checked:focus,[type=radio]:checked,[type=radio]:checked:active,[type=radio]:checked:focus{--pico-background-color:var(--pico-primary-background);--pico-border-color:var(--pico-primary-border);background-image:var(--pico-icon-checkbox);background-position:center;background-size:.75em auto;background-repeat:no-repeat}[type=checkbox]~label,[type=radio]~label{display:inline-block;margin-bottom:0;cursor:pointer}[type=checkbox]~label:not(:last-of-type),[type=radio]~label:not(:last-of-type){margin-inline-end:1em}[type=checkbox]:indeterminate{--pico-background-color:var(--pico-primary-background);--pico-border-color:var(--pico-primary-border);background-image:var(--pico-icon-minus);background-position:center;background-size:.75em auto;background-repeat:no-repeat}[type=radio]{border-radius:50%}[type=radio]:checked,[type=radio]:checked:active,[type=radio]:checked:focus{--pico-background-color:var(--pico-primary-inverse);border-width:.35em;background-image:none}[type=checkbox][role=switch]{--pico-background-color:var(--pico-switch-background-color);--pico-color:var(--pico-switch-color);width:2.25em;height:1.25em;border:var(--pico-border-width) solid var(--pico-border-color);border-radius:1.25em;background-color:var(--pico-background-color);line-height:1.25em}[type=checkbox][role=switch]:not([aria-invalid]){--pico-border-color:var(--pico-switch-background-color)}[type=checkbox][role=switch]:before{display:block;width:calc(1.25em - var(--pico-border-width) * 2);height:100%;border-radius:50%;background-color:var(--pico-color);box-shadow:var(--pico-switch-thumb-box-shadow);content:"";transition:margin .1s ease-in-out}[type=checkbox][role=switch]:focus{--pico-background-color:var(--pico-switch-background-color);--pico-border-color:var(--pico-switch-background-color)}[type=checkbox][role=switch]:checked{--pico-background-color:var(--pico-switch-checked-background-color);--pico-border-color:var(--pico-switch-checked-background-color);background-image:none}[type=checkbox][role=switch]:checked::before{margin-inline-start:calc(1.125em - var(--pico-border-width))}[type=checkbox][role=switch][disabled]{--pico-background-color:var(--pico-border-color)}[type=checkbox][aria-invalid=false]:checked,[type=checkbox][aria-invalid=false]:checked:active,[type=checkbox][aria-invalid=false]:checked:focus,[type=checkbox][role=switch][aria-invalid=false]:checked,[type=checkbox][role=switch][aria-invalid=false]:checked:active,[type=checkbox][role=switch][aria-invalid=false]:checked:focus{--pico-background-color:var(--pico-form-element-valid-border-color)}[type=checkbox]:checked:active[aria-invalid=true],[type=checkbox]:checked:focus[aria-invalid=true],[type=checkbox]:checked[aria-invalid=true],[type=checkbox][role=switch]:checked:active[aria-invalid=true],[type=checkbox][role=switch]:checked:focus[aria-invalid=true],[type=checkbox][role=switch]:checked[aria-invalid=true]{--pico-background-color:var(--pico-form-element-invalid-border-color)}[type=checkbox][aria-invalid=false]:checked,[type=checkbox][aria-invalid=false]:checked:active,[type=checkbox][aria-invalid=false]:checked:focus,[type=checkbox][role=switch][aria-invalid=false]:checked,[type=checkbox][role=switch][aria-invalid=false]:checked:active,[type=checkbox][role=switch][aria-invalid=false]:checked:focus,[type=radio][aria-invalid=false]:checked,[type=radio][aria-invalid=false]:checked:active,[type=radio][aria-invalid=false]:checked:focus{--pico-border-color:var(--pico-form-element-valid-border-color)}[type=checkbox]:checked:active[aria-invalid=true],[type=checkbox]:checked:focus[aria-invalid=true],[type=checkbox]:checked[aria-invalid=true],[type=checkbox][role=switch]:checked:active[aria-invalid=true],[type=checkbox][role=switch]:checked:focus[aria-invalid=true],[type=checkbox][role=switch]:checked[aria-invalid=true],[type=radio]:checked:active[aria-invalid=true],[type=radio]:checked:focus[aria-invalid=true],[type=radio]:checked[aria-invalid=true]{--pico-border-color:var(--pico-form-element-invalid-border-color)}[type=color]::-webkit-color-swatch-wrapper{padding:0}[type=color]::-moz-focus-inner{padding:0}[type=color]::-webkit-color-swatch{border:0;border-radius:calc(var(--pico-border-radius) * .5)}[type=color]::-moz-color-swatch{border:0;border-radius:calc(var(--pico-border-radius) * .5)}input:not([type=checkbox],[type=radio],[type=range],[type=file]):is([type=date],[type=datetime-local],[type=month],[type=time],[type=week]){--pico-icon-position:0.75rem;--pico-icon-width:1rem;padding-right:calc(var(--pico-icon-width) + var(--pico-icon-position));background-image:var(--pico-icon-date);background-position:center right var(--pico-icon-position);background-size:var(--pico-icon-width) auto;background-repeat:no-repeat}input:not([type=checkbox],[type=radio],[type=range],[type=file])[type=time]{background-image:var(--pico-icon-time)}[type=date]::-webkit-calendar-picker-indicator,[type=datetime-local]::-webkit-calendar-picker-indicator,[type=month]::-webkit-calendar-picker-indicator,[type=time]::-webkit-calendar-picker-indicator,[type=week]::-webkit-calendar-picker-indicator{width:var(--pico-icon-width);margin-right:calc(var(--pico-icon-width) * -1);margin-left:var(--pico-icon-position);opacity:0}@-moz-document url-prefix(){[type=date],[type=datetime-local],[type=month],[type=time],[type=week]{padding-right:var(--pico-form-element-spacing-horizontal)!important;background-image:none!important}}[dir=rtl] :is([type=date],[type=datetime-local],[type=month],[type=time],[type=week]){text-align:right}[type=file]{--pico-color:var(--pico-muted-color);margin-left:calc(var(--pico-outline-width) * -1);padding:calc(var(--pico-form-element-spacing-vertical) * .5) 0;padding-left:var(--pico-outline-width);border:0;border-radius:0;background:0 0}[type=file]::file-selector-button{margin-right:calc(var(--pico-spacing)/ 2);padding:calc(var(--pico-form-element-spacing-vertical) * .5) var(--pico-form-element-spacing-horizontal)}[type=file]:is(:hover,:active,:focus)::file-selector-button{--pico-background-color:var(--pico-secondary-hover-background);--pico-border-color:var(--pico-secondary-hover-border)}[type=file]:focus::file-selector-button{--pico-box-shadow:var(--pico-button-hover-box-shadow, 0 0 0 rgba(0, 0, 0, 0)),0 0 0 var(--pico-outline-width) var(--pico-secondary-focus)}[type=range]{-webkit-appearance:none;-moz-appearance:none;appearance:none;width:100%;height:1.25rem;background:0 0}[type=range]::-webkit-slider-runnable-track{width:100%;height:.375rem;border-radius:var(--pico-border-radius);background-color:var(--pico-range-border-color);-webkit-transition:background-color var(--pico-transition),box-shadow var(--pico-transition);transition:background-color var(--pico-transition),box-shadow var(--pico-transition)}[type=range]::-moz-range-track{width:100%;height:.375rem;border-radius:var(--pico-border-radius);background-color:var(--pico-range-border-color);-moz-transition:background-color var(--pico-transition),box-shadow var(--pico-transition);transition:background-color var(--pico-transition),box-shadow var(--pico-transition)}[type=range]::-ms-track{width:100%;height:.375rem;border-radius:var(--pico-border-radius);background-color:var(--pico-range-border-color);-ms-transition:background-color var(--pico-transition),box-shadow var(--pico-transition);transition:background-color var(--pico-transition),box-shadow var(--pico-transition)}[type=range]::-webkit-slider-thumb{-webkit-appearance:none;width:1.25rem;height:1.25rem;margin-top:-.4375rem;border:2px solid var(--pico-range-thumb-border-color);border-radius:50%;background-color:var(--pico-range-thumb-color);cursor:pointer;-webkit-transition:background-color var(--pico-transition),transform var(--pico-transition);transition:background-color var(--pico-transition),transform var(--pico-transition)}[type=range]::-moz-range-thumb{-webkit-appearance:none;width:1.25rem;height:1.25rem;margin-top:-.4375rem;border:2px solid var(--pico-range-thumb-border-color);border-radius:50%;background-color:var(--pico-range-thumb-color);cursor:pointer;-moz-transition:background-color var(--pico-transition),transform var(--pico-transition);transition:background-color var(--pico-transition),transform var(--pico-transition)}[type=range]::-ms-thumb{-webkit-appearance:none;width:1.25rem;height:1.25rem;margin-top:-.4375rem;border:2px solid var(--pico-range-thumb-border-color);border-radius:50%;background-color:var(--pico-range-thumb-color);cursor:pointer;-ms-transition:background-color var(--pico-transition),transform var(--pico-transition);transition:background-color var(--pico-transition),transform var(--pico-transition)}[type=range]:active,[type=range]:focus-within{--pico-range-border-color:var(--pico-range-active-border-color);--pico-range-thumb-color:var(--pico-range-thumb-active-color)}[type=range]:active::-webkit-slider-thumb{transform:scale(1.25)}[type=range]:active::-moz-range-thumb{transform:scale(1.25)}[type=range]:active::-ms-thumb{transform:scale(1.25)}input:not([type=checkbox],[type=radio],[type=range],[type=file])[type=search]{padding-inline-start:calc(var(--pico-form-element-spacing-horizontal) + 1.75rem);background-image:var(--pico-icon-search);background-position:center left calc(var(--pico-form-element-spacing-horizontal) + .125rem);background-size:1rem auto;background-repeat:no-repeat}input:not([type=checkbox],[type=radio],[type=range],[type=file])[type=search][aria-invalid]{padding-inline-start:calc(var(--pico-form-element-spacing-horizontal) + 1.75rem)!important;background-position:center left 1.125rem,center right .75rem}input:not([type=checkbox],[type=radio],[type=range],[type=file])[type=search][aria-invalid=false]{background-image:var(--pico-icon-search),var(--pico-icon-valid)}input:not([type=checkbox],[type=radio],[type=range],[type=file])[type=search][aria-invalid=true]{background-image:var(--pico-icon-search),var(--pico-icon-invalid)}[dir=rtl] :where(input):not([type=checkbox],[type=radio],[type=range],[type=file])[type=search]{background-position:center right 1.125rem}[dir=rtl] :where(input):not([type=checkbox],[type=radio],[type=range],[type=file])[type=search][aria-invalid]{background-position:center right 1.125rem,center left .75rem}details{display:block;margin-bottom:var(--pico-spacing)}details summary{line-height:1rem;list-style-type:none;cursor:pointer;transition:color var(--pico-transition)}details summary:not([role]){color:var(--pico-accordion-close-summary-color)}details summary::-webkit-details-marker{display:none}details summary::marker{display:none}details summary::-moz-list-bullet{list-style-type:none}details summary::after{display:block;width:1rem;height:1rem;margin-inline-start:calc(var(--pico-spacing,1rem) * .5);float:right;transform:rotate(-90deg);background-image:var(--pico-icon-chevron);background-position:right center;background-size:1rem auto;background-repeat:no-repeat;content:"";transition:transform var(--pico-transition)}details summary:focus{outline:0}details summary:focus:not([role]){color:var(--pico-accordion-active-summary-color)}details summary:focus-visible:not([role]){outline:var(--pico-outline-width) solid var(--pico-primary-focus);outline-offset:calc(var(--pico-spacing,1rem) * 0.5);color:var(--pico-primary)}details summary[role=button]{width:100%;text-align:left}details summary[role=button]::after{height:calc(1rem * var(--pico-line-height,1.5))}details[open]>summary{margin-bottom:var(--pico-spacing)}details[open]>summary:not([role]):not(:focus){color:var(--pico-accordion-open-summary-color)}details[open]>summary::after{transform:rotate(0)}[dir=rtl] details summary{text-align:right}[dir=rtl] details summary::after{float:left;background-position:left center}article{margin-bottom:var(--pico-block-spacing-vertical);padding:var(--pico-block-spacing-vertical) var(--pico-block-spacing-horizontal);border-radius:var(--pico-border-radius);background:var(--pico-card-background-color);box-shadow:var(--pico-card-box-shadow)}article>footer,article>header{margin-right:calc(var(--pico-block-spacing-horizontal) * -1);margin-left:calc(var(--pico-block-spacing-horizontal) * -1);padding:calc(var(--pico-block-spacing-vertical) * .66) var(--pico-block-spacing-horizontal);background-color:var(--pico-card-sectioning-background-color)}article>header{margin-top:calc(var(--pico-block-spacing-vertical) * -1);margin-bottom:var(--pico-block-spacing-vertical);border-bottom:var(--pico-border-width) solid var(--pico-card-border-color);border-top-right-radius:var(--pico-border-radius);border-top-left-radius:var(--pico-border-radius)}article>footer{margin-top:var(--pico-block-spacing-vertical);margin-bottom:calc(var(--pico-block-spacing-vertical) * -1);border-top:var(--pico-border-width) solid var(--pico-card-border-color);border-bottom-right-radius:var(--pico-border-radius);border-bottom-left-radius:var(--pico-border-radius)}details.dropdown{position:relative;border-bottom:none}details.dropdown summary::after,details.dropdown>a::after,details.dropdown>button::after{display:block;width:1rem;height:calc(1rem * var(--pico-line-height,1.5));margin-inline-start:.25rem;float:right;transform:rotate(0) translateX(.2rem);background-image:var(--pico-icon-chevron);background-position:right center;background-size:1rem auto;background-repeat:no-repeat;content:""}nav details.dropdown{margin-bottom:0}details.dropdown summary:not([role]){height:calc(1rem * var(--pico-line-height) + var(--pico-form-element-spacing-vertical) * 2 + var(--pico-border-width) * 2);padding:var(--pico-form-element-spacing-vertical) var(--pico-form-element-spacing-horizontal);border:var(--pico-border-width) solid var(--pico-form-element-border-color);border-radius:var(--pico-border-radius);background-color:var(--pico-form-element-background-color);color:var(--pico-form-element-placeholder-color);line-height:inherit;cursor:pointer;-webkit-user-select:none;-moz-user-select:none;user-select:none;transition:background-color var(--pico-transition),border-color var(--pico-transition),color var(--pico-transition),box-shadow var(--pico-transition)}details.dropdown summary:not([role]):active,details.dropdown summary:not([role]):focus{border-color:var(--pico-form-element-active-border-color);background-color:var(--pico-form-element-active-background-color)}details.dropdown summary:not([role]):focus{box-shadow:0 0 0 var(--pico-outline-width) var(--pico-form-element-focus-color)}details.dropdown summary:not([role]):focus-visible{outline:0}details.dropdown summary:not([role])[aria-invalid=false]{--pico-form-element-border-color:var(--pico-form-element-valid-border-color);--pico-form-element-active-border-color:var(--pico-form-element-valid-focus-color);--pico-form-element-focus-color:var(--pico-form-element-valid-focus-color)}details.dropdown summary:not([role])[aria-invalid=true]{--pico-form-element-border-color:var(--pico-form-element-invalid-border-color);--pico-form-element-active-border-color:var(--pico-form-element-invalid-focus-color);--pico-form-element-focus-color:var(--pico-form-element-invalid-focus-color)}nav details.dropdown{display:inline;margin:calc(var(--pico-nav-element-spacing-vertical) * -1) 0}nav details.dropdown summary::after{transform:rotate(0) translateX(0)}nav details.dropdown summary:not([role]){height:calc(1rem * var(--pico-line-height) + var(--pico-nav-link-spacing-vertical) * 2);padding:calc(var(--pico-nav-link-spacing-vertical) - var(--pico-border-width) * 2) var(--pico-nav-link-spacing-horizontal)}nav details.dropdown summary:not([role]):focus-visible{box-shadow:0 0 0 var(--pico-outline-width) var(--pico-primary-focus)}details.dropdown summary+ul{display:flex;z-index:99;position:absolute;left:0;flex-direction:column;width:100%;min-width:-moz-fit-content;min-width:fit-content;margin:0;margin-top:var(--pico-outline-width);padding:0;border:var(--pico-border-width) solid var(--pico-dropdown-border-color);border-radius:var(--pico-border-radius);background-color:var(--pico-dropdown-background-color);box-shadow:var(--pico-dropdown-box-shadow);color:var(--pico-dropdown-color);white-space:nowrap;opacity:0;transition:opacity var(--pico-transition),transform 0s ease-in-out 1s}details.dropdown summary+ul[dir=rtl]{right:0;left:auto}details.dropdown summary+ul li{width:100%;margin-bottom:0;padding:calc(var(--pico-form-element-spacing-vertical) * .5) var(--pico-form-element-spacing-horizontal);list-style:none}details.dropdown summary+ul li:first-of-type{margin-top:calc(var(--pico-form-element-spacing-vertical) * .5)}details.dropdown summary+ul li:last-of-type{margin-bottom:calc(var(--pico-form-element-spacing-vertical) * .5)}details.dropdown summary+ul li a{display:block;margin:calc(var(--pico-form-element-spacing-vertical) * -.5) calc(var(--pico-form-element-spacing-horizontal) * -1);padding:calc(var(--pico-form-element-spacing-vertical) * .5) var(--pico-form-element-spacing-horizontal);overflow:hidden;border-radius:0;color:var(--pico-dropdown-color);text-decoration:none;text-overflow:ellipsis}details.dropdown summary+ul li a:active,details.dropdown summary+ul li a:focus,details.dropdown summary+ul li a:focus-visible,details.dropdown summary+ul li a:hover,details.dropdown summary+ul li a[aria-current]:not([aria-current=false]){background-color:var(--pico-dropdown-hover-background-color)}details.dropdown summary+ul li label{width:100%}details.dropdown summary+ul li:has(label):hover{background-color:var(--pico-dropdown-hover-background-color)}details.dropdown[open] summary{margin-bottom:0}details.dropdown[open] summary+ul{transform:scaleY(1);opacity:1;transition:opacity var(--pico-transition),transform 0s ease-in-out 0s}details.dropdown[open] summary::before{display:block;z-index:1;position:fixed;width:100vw;height:100vh;inset:0;background:0 0;content:"";cursor:default}label>details.dropdown{margin-top:calc(var(--pico-spacing) * .25)}[role=group],[role=search]{display:inline-flex;position:relative;width:100%;margin-bottom:var(--pico-spacing);border-radius:var(--pico-border-radius);box-shadow:var(--pico-group-box-shadow,0 0 0 transparent);vertical-align:middle;transition:box-shadow var(--pico-transition)}[role=group] input:not([type=checkbox],[type=radio]),[role=group] select,[role=group]>*,[role=search] input:not([type=checkbox],[type=radio]),[role=search] select,[role=search]>*{position:relative;flex:1 1 auto;margin-bottom:0}[role=group] input:not([type=checkbox],[type=radio]):not(:first-child),[role=group] select:not(:first-child),[role=group]>:not(:first-child),[role=search] input:not([type=checkbox],[type=radio]):not(:first-child),[role=search] select:not(:first-child),[role=search]>:not(:first-child){margin-left:0;border-top-left-radius:0;border-bottom-left-radius:0}[role=group] input:not([type=checkbox],[type=radio]):not(:last-child),[role=group] select:not(:last-child),[role=group]>:not(:last-child),[role=search] input:not([type=checkbox],[type=radio]):not(:last-child),[role=search] select:not(:last-child),[role=search]>:not(:last-child){border-top-right-radius:0;border-bottom-right-radius:0}[role=group] input:not([type=checkbox],[type=radio]):focus,[role=group] select:focus,[role=group]>:focus,[role=search] input:not([type=checkbox],[type=radio]):focus,[role=search] select:focus,[role=search]>:focus{z-index:2}[role=group] [role=button]:not(:first-child),[role=group] [type=button]:not(:first-child),[role=group] [type=reset]:not(:first-child),[role=group] [type=submit]:not(:first-child),[role=group] button:not(:first-child),[role=group] input:not([type=checkbox],[type=radio]):not(:first-child),[role=group] select:not(:first-child),[role=search] [role=button]:not(:first-child),[role=search] [type=button]:not(:first-child),[role=search] [type=reset]:not(:first-child),[role=search] [type=submit]:not(:first-child),[role=search] button:not(:first-child),[role=search] input:not([type=checkbox],[type=radio]):not(:first-child),[role=search] select:not(:first-child){margin-left:calc(var(--pico-border-width) * -1)}[role=group] [role=button],[role=group] [type=button],[role=group] [type=reset],[role=group] [type=submit],[role=group] button,[role=search] [role=button],[role=search] [type=button],[role=search] [type=reset],[role=search] [type=submit],[role=search] button{width:auto}@supports selector(:has(*)){[role=group]:has(button:focus,[type=submit]:focus,[type=button]:focus,[role=button]:focus),[role=search]:has(button:focus,[type=submit]:focus,[type=button]:focus,[role=button]:focus){--pico-group-box-shadow:var(--pico-group-box-shadow-focus-with-button)}[role=group]:has(button:focus,[type=submit]:focus,[type=button]:focus,[role=button]:focus) input:not([type=checkbox],[type=radio]),[role=group]:has(button:focus,[type=submit]:focus,[type=button]:focus,[role=button]:focus) select,[role=search]:has(button:focus,[type=submit]:focus,[type=button]:focus,[role=button]:focus) input:not([type=checkbox],[type=radio]),[role=search]:has(button:focus,[type=submit]:focus,[type=button]:focus,[role=button]:focus) select{border-color:transparent}[role=group]:has(input:not([type=submit],[type=button]):focus,select:focus),[role=search]:has(input:not([type=submit],[type=button]):focus,select:focus){--pico-group-box-shadow:var(--pico-group-box-shadow-focus-with-input)}[role=group]:has(input:not([type=submit],[type=button]):focus,select:focus) [role=button],[role=group]:has(input:not([type=submit],[type=button]):focus,select:focus) [type=button],[role=group]:has(input:not([type=submit],[type=button]):focus,select:focus) [type=submit],[role=group]:has(input:not([type=submit],[type=button]):focus,select:focus) button,[role=search]:has(input:not([type=submit],[type=button]):focus,select:focus) [role=button],[role=search]:has(input:not([type=submit],[type=button]):focus,select:focus) [type=button],[role=search]:has(input:not([type=submit],[type=button]):focus,select:focus) [type=submit],[role=search]:has(input:not([type=submit],[type=button]):focus,select:focus) button{--pico-button-box-shadow:0 0 0 var(--pico-border-width) var(--pico-primary-border);--pico-button-hover-box-shadow:0 0 0 var(--pico-border-width) var(--pico-primary-hover-border)}[role=group] [role=button]:focus,[role=group] [type=button]:focus,[role=group] [type=reset]:focus,[role=group] [type=submit]:focus,[role=group] button:focus,[role=search] [role=button]:focus,[role=search] [type=button]:focus,[role=search] [type=reset]:focus,[role=search] [type=submit]:focus,[role=search] button:focus{box-shadow:none}}[role=search]>:first-child{border-top-left-radius:5rem;border-bottom-left-radius:5rem}[role=search]>:last-child{border-top-right-radius:5rem;border-bottom-right-radius:5rem}[aria-busy=true]:not(input,select,textarea,html){white-space:nowrap}[aria-busy=true]:not(input,select,textarea,html)::before{display:inline-block;width:1em;height:1em;background-image:var(--pico-icon-loading);background-size:1rem auto;background-repeat:no-repeat;content:"";vertical-align:-.125em}[aria-busy=true]:not(input,select,textarea,html):not(:empty)::before{margin-inline-end:calc(var(--pico-spacing) * .5)}[aria-busy=true]:not(input,select,textarea,html):empty{text-align:center}[role=button][aria-busy=true],[type=button][aria-busy=true],[type=reset][aria-busy=true],[type=submit][aria-busy=true],a[aria-busy=true],button[aria-busy=true]{pointer-events:none}:root{--pico-scrollbar-width:0px}dialog{display:flex;z-index:999;position:fixed;top:0;right:0;bottom:0;left:0;align-items:center;justify-content:center;width:inherit;min-width:100%;height:inherit;min-height:100%;padding:0;border:0;-webkit-backdrop-filter:var(--pico-modal-overlay-backdrop-filter);backdrop-filter:var(--pico-modal-overlay-backdrop-filter);background-color:var(--pico-modal-overlay-background-color);color:var(--pico-color)}dialog article{width:100%;max-height:calc(100vh - var(--pico-spacing) * 2);margin:var(--pico-spacing);overflow:auto}@media (min-width:576px){dialog article{max-width:510px}}@media (min-width:768px){dialog article{max-width:700px}}dialog article>header>*{margin-bottom:0}dialog article>header .close,dialog article>header :is(a,button)[rel=prev]{margin:0;margin-left:var(--pico-spacing);padding:0;float:right}dialog article>footer{text-align:right}dialog article>footer [role=button],dialog article>footer button{margin-bottom:0}dialog article>footer [role=button]:not(:first-of-type),dialog article>footer button:not(:first-of-type){margin-left:calc(var(--pico-spacing) * .5)}dialog article .close,dialog article :is(a,button)[rel=prev]{display:block;width:1rem;height:1rem;margin-top:calc(var(--pico-spacing) * -1);margin-bottom:var(--pico-spacing);margin-left:auto;border:none;background-image:var(--pico-icon-close);background-position:center;background-size:auto 1rem;background-repeat:no-repeat;background-color:transparent;opacity:.5;transition:opacity var(--pico-transition)}dialog article .close:is([aria-current]:not([aria-current=false]),:hover,:active,:focus),dialog article :is(a,button)[rel=prev]:is([aria-current]:not([aria-current=false]),:hover,:active,:focus){opacity:1}dialog:not([open]),dialog[open=false]{display:none}.modal-is-open{padding-right:var(--pico-scrollbar-width,0);overflow:hidden;pointer-events:none;touch-action:none}.modal-is-open dialog{pointer-events:auto;touch-action:auto}:where(.modal-is-opening,.modal-is-closing) dialog,:where(.modal-is-opening,.modal-is-closing) dialog>article{animation-duration:.2s;animation-timing-function:ease-in-out;animation-fill-mode:both}:where(.modal-is-opening,.modal-is-closing) dialog{animation-duration:.8s;animation-name:modal-overlay}:where(.modal-is-opening,.modal-is-closing) dialog>article{animation-delay:.2s;animation-name:modal}.modal-is-closing dialog,.modal-is-closing dialog>article{animation-delay:0s;animation-direction:reverse}@keyframes modal-overlay{from{-webkit-backdrop-filter:none;backdrop-filter:none;background-color:transparent}}@keyframes modal{from{transform:translateY(-100%);opacity:0}}:where(nav li)::before{float:left;content:"​"}nav,nav ul{display:flex}nav{justify-content:space-between;overflow:visible}nav ol,nav ul{align-items:center;margin-bottom:0;padding:0;list-style:none}nav ol:first-of-type,nav ul:first-of-type{margin-left:calc(var(--pico-nav-element-spacing-horizontal) * -1)}nav ol:last-of-type,nav ul:last-of-type{margin-right:calc(var(--pico-nav-element-spacing-horizontal) * -1)}nav li{display:inline-block;margin:0;padding:var(--pico-nav-element-spacing-vertical) var(--pico-nav-element-spacing-horizontal)}nav li :where(a,[role=link]){display:inline-block;margin:calc(var(--pico-nav-link-spacing-vertical) * -1) calc(var(--pico-nav-link-spacing-horizontal) * -1);padding:var(--pico-nav-link-spacing-vertical) var(--pico-nav-link-spacing-horizontal);border-radius:var(--pico-border-radius)}nav li :where(a,[role=link]):not(:hover){text-decoration:none}nav li [role=button],nav li button,nav li input:not([type=checkbox],[type=radio],[type=range],[type=file]),nav li select{height:auto;margin-right:inherit;margin-bottom:0;margin-left:inherit;padding:calc(var(--pico-nav-link-spacing-vertical) - var(--pico-border-width) * 2) var(--pico-nav-link-spacing-horizontal)}nav[aria-label=breadcrumb]{align-items:center;justify-content:start}nav[aria-label=breadcrumb] ul li:not(:first-child){margin-inline-start:var(--pico-nav-link-spacing-horizontal)}nav[aria-label=breadcrumb] ul li a{margin:calc(var(--pico-nav-link-spacing-vertical) * -1) 0;margin-inline-start:calc(var(--pico-nav-link-spacing-horizontal) * -1)}nav[aria-label=breadcrumb] ul li:not(:last-child)::after{display:inline-block;position:absolute;width:calc(var(--pico-nav-link-spacing-horizontal) * 4);margin:0 calc(var(--pico-nav-link-spacing-horizontal) * -1);content:var(--pico-nav-breadcrumb-divider);color:var(--pico-muted-color);text-align:center;text-decoration:none;white-space:nowrap}nav[aria-label=breadcrumb] a[aria-current]:not([aria-current=false]){background-color:transparent;color:inherit;text-decoration:none;pointer-events:none}aside li,aside nav,aside ol,aside ul{display:block}aside li{padding:calc(var(--pico-nav-element-spacing-vertical) * .5) var(--pico-nav-element-spacing-horizontal)}aside li a{display:block}aside li [role=button]{margin:inherit}[dir=rtl] nav[aria-label=breadcrumb] ul li:not(:last-child) ::after{content:"\\"}progress{display:inline-block;vertical-align:baseline}progress{-webkit-appearance:none;-moz-appearance:none;display:inline-block;appearance:none;width:100%;height:.5rem;margin-bottom:calc(var(--pico-spacing) * .5);overflow:hidden;border:0;border-radius:var(--pico-border-radius);background-color:var(--pico-progress-background-color);color:var(--pico-progress-color)}progress::-webkit-progress-bar{border-radius:var(--pico-border-radius);background:0 0}progress[value]::-webkit-progress-value{background-color:var(--pico-progress-color);-webkit-transition:inline-size var(--pico-transition);transition:inline-size var(--pico-transition)}progress::-moz-progress-bar{background-color:var(--pico-progress-color)}@media (prefers-reduced-motion:no-preference){progress:indeterminate{background:var(--pico-progress-background-color) linear-gradient(to right,var(--pico-progress-color) 30%,var(--pico-progress-background-color) 30%) top left/150% 150% no-repeat;animation:progress-indeterminate 1s linear infinite}progress:indeterminate[value]::-webkit-progress-value{background-color:transparent}progress:indeterminate::-moz-progress-bar{background-color:transparent}}@media (prefers-reduced-motion:no-preference){[dir=rtl] progress:indeterminate{animation-direction:reverse}}@keyframes progress-indeterminate{0%{background-position:200% 0}100%{background-position:-200% 0}}[data-tooltip]{position:relative}[data-tooltip]:not(a,button,input){border-bottom:1px dotted;text-decoration:none;cursor:help}[data-tooltip]::after,[data-tooltip]::before,[data-tooltip][data-placement=top]::after,[data-tooltip][data-placement=top]::before{display:block;z-index:99;position:absolute;bottom:100%;left:50%;padding:.25rem .5rem;overflow:hidden;transform:translate(-50%,-.25rem);border-radius:var(--pico-border-radius);background:var(--pico-tooltip-background-color);content:attr(data-tooltip);color:var(--pico-tooltip-color);font-style:normal;font-weight:var(--pico-font-weight);font-size:.875rem;text-decoration:none;text-overflow:ellipsis;white-space:nowrap;opacity:0;pointer-events:none}[data-tooltip]::after,[data-tooltip][data-placement=top]::after{padding:0;transform:translate(-50%,0);border-top:.3rem solid;border-right:.3rem solid transparent;border-left:.3rem solid transparent;border-radius:0;background-color:transparent;content:"";color:var(--pico-tooltip-background-color)}[data-tooltip][data-placement=bottom]::after,[data-tooltip][data-placement=bottom]::before{top:100%;bottom:auto;transform:translate(-50%,.25rem)}[data-tooltip][data-placement=bottom]:after{transform:translate(-50%,-.3rem);border:.3rem solid transparent;border-bottom:.3rem solid}[data-tooltip][data-placement=left]::after,[data-tooltip][data-placement=left]::before{top:50%;right:100%;bottom:auto;left:auto;transform:translate(-.25rem,-50%)}[data-tooltip][data-placement=left]:after{transform:translate(.3rem,-50%);border:.3rem solid transparent;border-left:.3rem solid}[data-tooltip][data-placement=right]::after,[data-tooltip][data-placement=right]::before{top:50%;right:auto;bottom:auto;left:100%;transform:translate(.25rem,-50%)}[data-tooltip][data-placement=right]:after{transform:translate(-.3rem,-50%);border:.3rem solid transparent;border-right:.3rem solid}[data-tooltip]:focus::after,[data-tooltip]:focus::before,[data-tooltip]:hover::after,[data-tooltip]:hover::before{opacity:1}@media (hover:hover) and (pointer:fine){[data-tooltip]:focus::after,[data-tooltip]:focus::before,[data-tooltip]:hover::after,[data-tooltip]:hover::before{--pico-tooltip-slide-to:translate(-50%, -0.25rem);transform:translate(-50%,.75rem);animation-duration:.2s;animation-fill-mode:forwards;animation-name:tooltip-slide;opacity:0}[data-tooltip]:focus::after,[data-tooltip]:hover::after{--pico-tooltip-caret-slide-to:translate(-50%, 0rem);transform:translate(-50%,-.25rem);animation-name:tooltip-caret-slide}[data-tooltip][data-placement=bottom]:focus::after,[data-tooltip][data-placement=bottom]:focus::before,[data-tooltip][data-placement=bottom]:hover::after,[data-tooltip][data-placement=bottom]:hover::before{--pico-tooltip-slide-to:translate(-50%, 0.25rem);transform:translate(-50%,-.75rem);animation-name:tooltip-slide}[data-tooltip][data-placement=bottom]:focus::after,[data-tooltip][data-placement=bottom]:hover::after{--pico-tooltip-caret-slide-to:translate(-50%, -0.3rem);transform:translate(-50%,-.5rem);animation-name:tooltip-caret-slide}[data-tooltip][data-placement=left]:focus::after,[data-tooltip][data-placement=left]:focus::before,[data-tooltip][data-placement=left]:hover::after,[data-tooltip][data-placement=left]:hover::before{--pico-tooltip-slide-to:translate(-0.25rem, -50%);transform:translate(.75rem,-50%);animation-name:tooltip-slide}[data-tooltip][data-placement=left]:focus::after,[data-tooltip][data-placement=left]:hover::after{--pico-tooltip-caret-slide-to:translate(0.3rem, -50%);transform:translate(.05rem,-50%);animation-name:tooltip-caret-slide}[data-tooltip][data-placement=right]:focus::after,[data-tooltip][data-placement=right]:focus::before,[data-tooltip][data-placement=right]:hover::after,[data-tooltip][data-placement=right]:hover::before{--pico-tooltip-slide-to:translate(0.25rem, -50%);transform:translate(-.75rem,-50%);animation-name:tooltip-slide}[data-tooltip][data-placement=right]:focus::after,[data-tooltip][data-placement=right]:hover::after{--pico-tooltip-caret-slide-to:translate(-0.3rem, -50%);transform:translate(-.05rem,-50%);animation-name:tooltip-caret-slide}}@keyframes tooltip-slide{to{transform:var(--pico-tooltip-slide-to);opacity:1}}@keyframes tooltip-caret-slide{50%{opacity:0}to{transform:var(--pico-tooltip-caret-slide-to);opacity:1}}[aria-controls]{cursor:pointer}[aria-disabled=true],[disabled]{cursor:not-allowed}[aria-hidden=false][hidden]{display:initial}[aria-hidden=false][hidden]:not(:focus){clip:rect(0,0,0,0);position:absolute}[tabindex],a,area,button,input,label,select,summary,textarea{-ms-touch-action:manipulation}[dir=rtl]{direction:rtl}@media (prefers-reduced-motion:reduce){:not([aria-busy=true]),:not([aria-busy=true])::after,:not([aria-busy=true])::before{background-attachment:initial!important;animation-duration:1ms!important;animation-delay:-1ms!important;animation-iteration-count:1!important;scroll-behavior:auto!important;transition-delay:0s!important;transition-duration:0s!important}}
\ No newline at end of file
diff --git a/public/documentation/basics/conditional-expressions.fsx b/public/documentation/basics/conditional-expressions.fsx
deleted file mode 100644
index 87a5921..0000000
--- a/public/documentation/basics/conditional-expressions.fsx
+++ /dev/null
@@ -1,9 +0,0 @@
-let number = 20
-
-let fizzBuzz =
- if number % 15 = 0 then "FizzBuzz"
- elif number % 5 = 0 then "Buzz"
- elif number % 3 = 0 then "Fizz"
- else string number
-
-printfn "%s" fizzBuzz
diff --git a/public/documentation/basics/conditional-expressions.md b/public/documentation/basics/conditional-expressions.md
index a32d03d..5fa60f1 100644
--- a/public/documentation/basics/conditional-expressions.md
+++ b/public/documentation/basics/conditional-expressions.md
@@ -18,4 +18,6 @@ let fizzBuzz =
elif number % 5 = 0 then "Buzz"
elif number % 3 = 0 then "Fizz"
else string number
+
+printfn "%s" fizzBuzz
```
diff --git a/public/documentation/basics/expressions.fsx b/public/documentation/basics/expressions.fsx
deleted file mode 100644
index 51b8801..0000000
--- a/public/documentation/basics/expressions.fsx
+++ /dev/null
@@ -1,5 +0,0 @@
-let ten =
- let five = 5
- five + five
-
-let twenty = ten + ten
diff --git a/public/documentation/basics/expressions.md b/public/documentation/basics/expressions.md
index 7c7e6b0..03d0b16 100644
--- a/public/documentation/basics/expressions.md
+++ b/public/documentation/basics/expressions.md
@@ -1,6 +1,6 @@
# Expressions
-The primary piece of F# syntax is an expression. An expression is simply, a block of code that when evaluated, produces a value.
+The most fundamental construct in F# is an expression. An expression is a block of code that produces a value when evaluated.
_Let bindings_ allow you to bind the result of an expression to a name.
@@ -34,14 +34,11 @@ let ten = 10
The advantage of top-down evaluation is that the flow of your application's code is easier to reason about. Code is read and evaluated from top to bottom sequentially, from a higher to a lower level, from core components to specific implementation details. We can clearly understand and reason about our dependent modules, types, functions and their dependencies.
-This top-down evaluation also applies to the ordering of files within a project. You can only use functions, types, and modules defined in other files if the file is ordered above the current definition.
+This top-down evaluation also applies to the ordering of files within a project. You can only use functions, types, and modules defined in other files if the file is ordered above the current definition. Assuming you define a project with the structure of:
+ 1. Logic.fs
+ 2. Program.fs
-```
-1. Logic.fs
-2. Program.fs
-```
-
-Here, any code in `Program.fs` can access modules, types, functions, and bindings in `Logic.fs`, but not the other way around. This is because `Logic.fs` is ordered above `Program.fs`.
+Any code in `Program.fs` can access modules, types, functions, and bindings in `Logic.fs`, but not the other way around. This is because `Logic.fs` is ordered above `Program.fs`.
F# relies on the level of indentation to determine the beginning and end of an expression. You may be familiar with this if you've programmed in languages with syntatic indentation before. When writing an expression block, the level of indentation must be consistent for each expression within that block.
diff --git a/public/documentation/basics/hello-world.fsx b/public/documentation/basics/hello-world.fsx
deleted file mode 100644
index 70fa638..0000000
--- a/public/documentation/basics/hello-world.fsx
+++ /dev/null
@@ -1 +0,0 @@
-printfn "Hello, World!"
diff --git a/public/documentation/basics/hello-world.md b/public/documentation/basics/hello-world.md
index f27c004..0cbec8d 100644
--- a/public/documentation/basics/hello-world.md
+++ b/public/documentation/basics/hello-world.md
@@ -2,6 +2,10 @@
Here is a program that prints out the text `"Hello, World!"`.
+```fsharp
+printfn "Hello, World!"
+```
+
In a normal F# program, this would be executed by using the command `dotnet run` on the command line.
-Try changing the text being printed to `"Hello!"` and click the `Run` button at the top right to see what happens.
\ No newline at end of file
+Try changing the text being printed and click the `Compile` button to see what happens!
\ No newline at end of file
diff --git a/public/documentation/basics/operators.fsx b/public/documentation/basics/operators.fsx
deleted file mode 100644
index 4431b57..0000000
--- a/public/documentation/basics/operators.fsx
+++ /dev/null
@@ -1,17 +0,0 @@
-let ten = 5 + 5
-printfn "5 + 5 = %d" ten
-
-let four = 8 - 4
-printfn "8 - 4 = %d" four
-
-let five = 10 / 2
-printfn "10 / 2 = %d" five
-
-let twenty = 10 * 2
-printfn "10 * 2 = %d" twenty
-
-let remainder = 10 % 2
-printfn "10 %% 2 = %d" remainder
-
-let squared = 10.0 ** 2.0
-printfn "10.0 ** 2.0 = %f" squared
diff --git a/public/documentation/basics/patterns-and-match-expressions.fsx b/public/documentation/basics/patterns-and-match-expressions.fsx
deleted file mode 100644
index 010b11d..0000000
--- a/public/documentation/basics/patterns-and-match-expressions.fsx
+++ /dev/null
@@ -1,10 +0,0 @@
-let number = 15
-
-let fizzBuzz =
- match number with
- | number when number % 15 = 0 -> "FizzBuzz"
- | number when number % 5 = 0 -> "Buzz"
- | number when number % 3 = 0 -> "Fizz"
- | number -> string number
-
-printfn "%s" fizzBuzz
diff --git a/public/documentation/basics/patterns-and-match-expressions.md b/public/documentation/basics/patterns-and-match-expressions.md
index 8b82da4..2539fbb 100644
--- a/public/documentation/basics/patterns-and-match-expressions.md
+++ b/public/documentation/basics/patterns-and-match-expressions.md
@@ -4,7 +4,7 @@ Pattern matching allows you to match a value against patterns, which act as rule
To demonstrate pattern matching, let's get started with a pattern you're already familiar with: the _variable_ pattern. This pattern allows you to bind a value to a name like so: `let five = 5`. That's right, you've been using the variable pattern the whole time! Just like how everything on the right-hand side of the equals sign in a binding is an expression, the left-hand side is always a pattern.
-```fsharp
+```
let =
```
@@ -16,6 +16,8 @@ let result =
match number with
| 10 -> "The number is Ten"
| number -> $"The number is not ten, but instead: {number}"
+
+printfn "%s" result
```
Here you can see two patterns in action: the _constant_ and _variable_ patterns. The _constant_ pattern will match a value against a constant value like `10` or `"Hello, World!"`. This match expression is exhaustive as the last branch utilizes the _variable_ pattern which will always match against the value.
@@ -34,16 +36,20 @@ A branch in a match expression can also include a conditional expression. This i
```fsharp
let number = 10
+
let result =
match number with
| number when number % 2 = 0 -> $"{number} is even"
| number -> $"{number} is odd"
+
+printfn "%s" result
```
Two patterns can lead to the same expression being evaluated using the _OR_ pattern.
```fsharp
let number = 10
+
let result =
match number with
| pattern1
diff --git a/public/documentation/basics/primitive-types.fsx b/public/documentation/basics/primitive-types.fsx
deleted file mode 100644
index e9f5567..0000000
--- a/public/documentation/basics/primitive-types.fsx
+++ /dev/null
@@ -1,6 +0,0 @@
-let int = 10
-let float = 10.0
-let char = 'a'
-let string = "Hello, World!"
-let boolean = true
-let unit = ()
diff --git a/public/documentation/basics/primitive-types.md b/public/documentation/basics/primitive-types.md
index 15c3407..35bf713 100644
--- a/public/documentation/basics/primitive-types.md
+++ b/public/documentation/basics/primitive-types.md
@@ -13,10 +13,10 @@ What do these primitive types represent?
- `unit`, when passed to a function, means that function has no arguments. When returned from a function, it indicates that the function has no useful return value. Often used when a function e.g. prints to the screen and does nothing else.
```fsharp
-10 // int
-10.0 // float
-'a' // char
-"Hello, World!" // string
-true // bool
-() // unit
+let intValue: int = 10
+let floatValue: float = 10.0
+let charValue: char = 'a'
+let stringValue: string = "Hello, World!"
+let boolValue: bool = true
+let unitValue: unit = ()
```
diff --git a/public/documentation/basics/string-formatting.fsx b/public/documentation/basics/string-formatting.fsx
deleted file mode 100644
index 6fdba51..0000000
--- a/public/documentation/basics/string-formatting.fsx
+++ /dev/null
@@ -1,3 +0,0 @@
-let name = "John Doe"
-let greeting = $"Hello, {name}!"
-printfn "%s" greeting
diff --git a/public/documentation/basics/string-formatting.md b/public/documentation/basics/string-formatting.md
index 2ed04e6..80a4f15 100644
--- a/public/documentation/basics/string-formatting.md
+++ b/public/documentation/basics/string-formatting.md
@@ -4,7 +4,8 @@ String formatting is the process of integrating additional values into string li
```fsharp
let name = "John Doe"
-sprintf "Your name is %s" name // "Your name is John Doe"
+let nameDescription = sprintf "Your name is %s" name
+printfn "%s" nameDescription
```
Here, we specify that the string format contains a single string value, indicated by the `%s` format specifier.
@@ -26,12 +27,12 @@ Another method is to use interpolated strings which allow you to bake the values
```fsharp
let name = "John Doe"
-$"Your name is {name}" // "Your name is John Doe"
+printfn $"Your name is {name}"
```
These interpolated strings can also be type checked by providing a format before the template. This will result in a compiler error if the type of the value doesn't match the format specifier.
```fsharp
-$"Your name is %s{name}" // this works.
-$"Your name is %b{name}" // compiler error. %b = boolean
+printfn $"Your name is %s{name}" // this works.
+printfn $"Your name is %b{name}" // compiler error. %b = boolean
```
\ No newline at end of file
diff --git a/public/documentation/data-and-types/abbreviations.fsx b/public/documentation/data-and-types/abbreviations.fsx
deleted file mode 100644
index 7ba4947..0000000
--- a/public/documentation/data-and-types/abbreviations.fsx
+++ /dev/null
@@ -1,6 +0,0 @@
-type Logger = string -> unit
-
-let exclaim (logger: Logger) (value: string) = logger (sprintf "%s!!!" value)
-
-let logger: Logger = printfn "%s"
-exclaim logger "Hello"
diff --git a/public/documentation/data-and-types/abbreviations.md b/public/documentation/data-and-types/abbreviations.md
index 4983b63..54476ab 100644
--- a/public/documentation/data-and-types/abbreviations.md
+++ b/public/documentation/data-and-types/abbreviations.md
@@ -9,6 +9,8 @@ type Logger = string -> unit
Because the `Logger` type is just an abbreviation for the function signature `string -> unit` you can use the two interchangeably.
```fsharp
+type Logger = string -> unit
+
let exclaim (logger: Logger) (value: string) = logger (sprintf "%s!!!" value)
let logger: Logger = printfn "%s"
diff --git a/public/documentation/data-and-types/discriminated-unions.fsx b/public/documentation/data-and-types/discriminated-unions.fsx
deleted file mode 100644
index e6ce142..0000000
--- a/public/documentation/data-and-types/discriminated-unions.fsx
+++ /dev/null
@@ -1,11 +0,0 @@
-type ContactInfo =
- | EmailAddress of string
- | PhoneNumber of string
-
-let contact contactInfo =
- match contactInfo with
- | EmailAddress email -> sprintf "Sending an email to %s" email
- | PhoneNumber number -> sprintf "Sending a text message to %s" number
-
-let contactInfo = PhoneNumber "000-000-0000"
-printfn "%s" (contact contactInfo)
diff --git a/public/documentation/data-and-types/discriminated-unions.md b/public/documentation/data-and-types/discriminated-unions.md
index df114dc..d4b94db 100644
--- a/public/documentation/data-and-types/discriminated-unions.md
+++ b/public/documentation/data-and-types/discriminated-unions.md
@@ -7,35 +7,57 @@ type Color =
| Red
| Green
| Blue
- | RGB of int * int * int
+ | Rgb of int * int * int
```
The discriminated union defined above has four cases: `Red`, `Green`, `Blue`, and `Rgb`.
Only the `RGB` case has data associated with it. You can construct instances of these cases using the identifier and any data.
```fsharp
+type Color =
+ | Red
+ | Green
+ | Blue
+ | Rgb of int * int * int
+
let red = Red
-let black = RGB (0, 0, 0)
+let black = Rgb (0, 0, 0)
+printfn "%A" black
```
The case constructor for the `RGB` case is a function with the signature of `int * int * int -> Color`.
```fsharp
-let rgb: int * int * int -> Color = RGB
+type Color =
+ | Red
+ | Green
+ | Blue
+ | Rgb of int * int * int
+
+let rgb: int * int * int -> Color = Rgb
+let color: Color = rgb (255, 255, 255)
+printfn "%A" color
```
You can match against the cases of a discriminated union by using the _identifier_ pattern. The _identifier_ pattern allows you to match against the case by its identifier and additionally, supply a pattern for any data associated with it.
```fsharp
+type Color =
+ | Red
+ | Green
+ | Blue
+ | Rgb of int * int * int
+
let rgb color =
match color with
| Red -> 255, 0, 0
| Green -> 0, 255, 0
| Blue -> 0, 0, 255
- | RGB (r, g, b) -> r, g, b
+ | Rgb (r, g, b) -> r, g, b
let color = Red
let (r, g, b) = rgb color
+printfn "R: %d, G: %d, B: %d" r g b
```
When dealing with a case that has data in the form of a tuple, it can be difficult to discern which tuple value corresponds to which piece of the data. In these cases, it is good practice to include labels on tuple elements like so:
@@ -48,4 +70,20 @@ type Color =
| Rgb of r: int * g: int * b: int
let color = Rgb (r = 255, g = 255, b = 255)
+printfn "%A" color
+```
+
+Another common option is to use a record for a union case with multiple fields.
+
+```fsharp
+type RgbColor = { R: int; G: int; B: int }
+
+type Color =
+ | Red
+ | Green
+ | Blue
+ | Rgb of RgbColor
+
+let color = Rgb { R = 255; G = 255; B = 255 }
+printfn "%A" color
```
\ No newline at end of file
diff --git a/public/documentation/data-and-types/generic-types.fsx b/public/documentation/data-and-types/generic-types.fsx
deleted file mode 100644
index 5b54a61..0000000
--- a/public/documentation/data-and-types/generic-types.fsx
+++ /dev/null
@@ -1,3 +0,0 @@
-type Data<'a> = { Value: 'a }
-let data: Data = { Value = "Hello, World!" }
-printfn "%s" data.Value
diff --git a/public/documentation/data-and-types/generic-types.md b/public/documentation/data-and-types/generic-types.md
index 76dd14e..1869a02 100644
--- a/public/documentation/data-and-types/generic-types.md
+++ b/public/documentation/data-and-types/generic-types.md
@@ -6,7 +6,7 @@ For example, you can have an `int list`, a `string list`, or a `float list`. Eac
You can define a generic type parameter using an apostrophe followed by the name of the type parameter.
-```fsharp
+```
type Data<'a> = { Value: 'a }
```
@@ -15,13 +15,24 @@ The `'a` in the above definition denotes a generic type parameter. If you wanted
The `Value` property in the Data type can only contain a value of type `'a`. For `Data` the `Value` property must contain a `string` value.
```fsharp
+type Data<'a> = { Value: 'a }
+
let data: Data = { Value = "Hello, World!" }
let value: string = data.Value
+printfn "%s" value
+
+let data1: Data = { Value = 10 }
+let value1: int = data1.Value
+printfn "%d" value1
```
You can also define generic type parameters in functions and pass them to your desired type. Here we can accept a value of our generic `Data` type, passing a generic type parameter to it in the process.
```fsharp
-let printData (data: Data<'a>) =
- printfn "%A" data.Value
+type Data<'a> = { Value: 'a }
+
+let printData (data: Data<'a>) = printfn "%A" data.Value
+
+printData { Value = "Hello, World!" }
+printData { Value = 10 }
```
\ No newline at end of file
diff --git a/public/documentation/data-and-types/lists.fsx b/public/documentation/data-and-types/lists.fsx
deleted file mode 100644
index 75b43d9..0000000
--- a/public/documentation/data-and-types/lists.fsx
+++ /dev/null
@@ -1,3 +0,0 @@
-let numbers = [ 1; 2; 3 ]
-let numbersAsStrings = List.map string numbers
-printfn "%A" numbersAsStrings
diff --git a/public/documentation/data-and-types/lists.md b/public/documentation/data-and-types/lists.md
index f1d3b7a..6e30ea3 100644
--- a/public/documentation/data-and-types/lists.md
+++ b/public/documentation/data-and-types/lists.md
@@ -4,21 +4,25 @@ In F#, lists are an immutable series of elements of the same type implemented as
```fsharp
let numbers = [ 1; 2; 3 ]
+printfn "%A" numbers
```
There are two primary ways to add values to a list: You can prepend elements using the `::` operator, and concatenate two lists using the `@` operator.
```fsharp
+let numbers = [ 1; 2; 3 ]
let numbers2 = 0 :: numbers
let numbers3 = numbers2 @ [4; 5; 6]
+printfn "%A" numbers3
```
Each list has a `head` and a `tail`. The `head` is the first element of the list, and the `tail` is every subsequence element.
```fsharp
let numbers = [1; 2; 3]
-let head = List.head numbers // 1
-let tail = List.tail numbers // [2; 3]
+let head = List.head numbers
+let tail = List.tail numbers
+printfn "Head = %A, Tail = %A" head tail
```
There are two patterns that allow us to match against and deconstruct list values. The _list_ pattern and the _cons_ pattern.
@@ -26,11 +30,11 @@ There are two patterns that allow us to match against and deconstruct list value
The _list_ pattern allows you to supply a pattern for each value in a list.
```fsharp
-let numbers = [1; 2; 3]
+let numbers = [1]
match numbers with
-| [] -> "The list is empty"
-| [a] -> $"The list has one element: {a}"
-| ... -> ...
+| [] -> printfn "The list is empty"
+| [a] -> printfn $"The list has one element: {a}"
+| _ -> printfn "???"
```
The _cons_ pattern allows you to deconstruct a list into N elements and the tail.
@@ -38,8 +42,8 @@ The _cons_ pattern allows you to deconstruct a list into N elements and the tail
```fsharp
let numbers = [1; 2; 3]
match numbers with
-| [] -> "The list is empty"
-| head :: tail -> $"Head: {head}, Tail: {tail}"
+| [] -> printfn "The list is empty"
+| head :: tail -> printfn $"Head: {head}, Tail: {tail}"
```
The `head :: tail` pattern will deconstruct the list `[1; 2; 3]` into `head = 1` and `tail = [2; 3]`. This can also be done for N number of elements: `first :: second :: tail`. The `head :: tail` pattern will match against any list with a single element. While the `first :: second :: tail` pattern will match against any list with at least two elements, and so on.
@@ -53,6 +57,8 @@ let rec iter (f: 'a -> unit) (xs: 'a list) =
| x :: xs ->
f x
iter f xs
+
+iter (printfn "%d") [1; 2; 3]
```
The `List` module contains common functions for operating with lists. These functions include but are not limited to:
@@ -62,11 +68,10 @@ The `List` module contains common functions for operating with lists. These func
```fsharp
let isEven x = x % 2 = 0
-let numbers = [0; 1; 2; 3; 4; 5;]
+let square x = x * x
-let evenNumbersAsStrings =
- numbers // [0; 1; 2; 3; 4; 5;]
- |> List.filter isEven // [0; 2; 4]
- |> List.map string // ["0"; "2"; "4"]
- |> List.iter (printfn "%s")
+[0; 1; 2; 3; 4; 5;]
+|> List.filter isEven // only even numbers
+|> List.map square // square every number
+|> List.iter (printfn "%d") // print every number
```
\ No newline at end of file
diff --git a/public/documentation/data-and-types/records.fsx b/public/documentation/data-and-types/records.fsx
deleted file mode 100644
index d9bb38f..0000000
--- a/public/documentation/data-and-types/records.fsx
+++ /dev/null
@@ -1,7 +0,0 @@
-type Person = { FirstName: string; LastName: string }
-
-let johnDoe = { FirstName = "John"; LastName = "Doe" }
-printfn "%A" johnDoe
-
-let janeDoe = { johnDoe with FirstName = "Jane" }
-printfn "%A" janeDoe
diff --git a/public/documentation/data-and-types/records.md b/public/documentation/data-and-types/records.md
index 743f673..e1ff05a 100644
--- a/public/documentation/data-and-types/records.md
+++ b/public/documentation/data-and-types/records.md
@@ -33,9 +33,17 @@ As F# is evaluated from top to bottom, the instance of a record value will be in
type Person = { FirstName: string; LastName: string }
type Customer = { FirstName: string; LastName: string }
-let johnDoe = { FirstName = "John"; LastName = "Doe" } // Customer
-let johnDoe2: Person = { FirstName: string; LastName: string } // Person
-let johnDoe3 = { Person.FirstName = "John"; Person.LastName = "Doe" } // Person
+let displayPerson (person: Person) = printfn "Person = %A" person
+let displayCustomer (customer: Customer) = printfn "Customer = %A" customer
+
+let johnDoe = { FirstName = "John"; LastName = "Doe" }
+displayCustomer johnDoe
+
+let johnDoe2: Person = { FirstName = "John"; LastName = "Doe" }
+displayPerson johnDoe2
+
+let johnDoe3 = { Person.FirstName = "John"; Person.LastName = "Doe" }
+displayPerson johnDoe3
```
You can pattern match a record value using the _record pattern_. This pattern allows you to specify a pattern for one or more properties of a record.
@@ -48,4 +56,28 @@ let identify person =
| { FirstName = "John"; LastName = "Doe" }
| { FirstName = "Jane"; LastName = "Doe" } -> "Could not identify this person."
| { FirstName = firstName; LastName = lastName } -> $"Identified as: {firstName} {lastName}"
+```
+
+```fsharp
+type Person = { FirstName: string; LastName: string; Age: int }
+type Team = { Name: string; Members: Person list }
+
+let team = {
+ Name = "Developers";
+ Members = [
+ { FirstName = "John"; LastName = "Doe"; Age = 30 }
+ { FirstName = "Jane"; LastName = "Smith"; Age = 28 }
+ ]
+}
+
+let describeTeam team =
+ let memberDescriptions =
+ team.Members
+ |> List.map (fun person -> $"{person.FirstName} {person.LastName} ({person.Age} years old)")
+ |> String.concat ", "
+
+ $"Team: {team.Name}, Members: {memberDescriptions}"
+
+let teamDescription = describeTeam team
+printfn "%s" teamDescription
```
\ No newline at end of file
diff --git a/public/documentation/data-and-types/sequence-expressions.fsx b/public/documentation/data-and-types/sequence-expressions.fsx
deleted file mode 100644
index 569261e..0000000
--- a/public/documentation/data-and-types/sequence-expressions.fsx
+++ /dev/null
@@ -1,5 +0,0 @@
-let oneThroughTen = [ 1..10 ]
-printfn "%A" oneThroughTen
-
-let evenNumbers = [ 1..2..10 ]
-printfn "%A" evenNumbers
diff --git a/public/documentation/data-and-types/sequences.fsx b/public/documentation/data-and-types/sequences.fsx
deleted file mode 100644
index 4b06086..0000000
--- a/public/documentation/data-and-types/sequences.fsx
+++ /dev/null
@@ -1 +0,0 @@
-Seq.initInfinite (fun x -> x * 2) |> Seq.take 10 |> Seq.iter (printfn "%d")
diff --git a/public/documentation/data-and-types/the-option-type.fsx b/public/documentation/data-and-types/the-option-type.fsx
deleted file mode 100644
index 50c92d9..0000000
--- a/public/documentation/data-and-types/the-option-type.fsx
+++ /dev/null
@@ -1,8 +0,0 @@
-type User = { Id: int; Name: string }
-
-let tryFindUserById id users =
- List.tryFind (fun user -> user.Id = id) users
-
-let users = [ { Id = 1; Name = "John Doe" }; { Id = 2; Name = "Jane Doe" } ]
-let foundUser = tryFindUserById 1 users
-printfn "Found user: %A" foundUser
diff --git a/public/documentation/data-and-types/the-result-type.fsx b/public/documentation/data-and-types/the-result-type.fsx
deleted file mode 100644
index 9fd8b8e..0000000
--- a/public/documentation/data-and-types/the-result-type.fsx
+++ /dev/null
@@ -1,38 +0,0 @@
-type Account =
- { Username: string
- EmailAddress: string }
-
-type CreateAccountError =
- | UsernameNotAvailable
- | EmailAddressNotAvailable
-
-let ensureUsernameIsAvailable existingAccounts account =
- if List.exists (fun x -> x.Username = account.Username) existingAccounts then
- Error UsernameNotAvailable
- else
- Ok account
-
-let ensureEmailAddressIsAvailable existingAccounts account =
- if List.exists (fun x -> x.EmailAddress = account.EmailAddress) existingAccounts then
- Error EmailAddressNotAvailable
- else
- Ok account
-
-let createAccount existingAccounts account =
- account
- |> ensureUsernameIsAvailable existingAccounts
- |> Result.bind (ensureEmailAddressIsAvailable existingAccounts)
-
-let existingAcounts =
- [ { Username = "john"
- EmailAddress = "johndoe@site.com" }
- { Username = "jane"
- EmailAddress = "janedoe@site.com" } ]
-
-let accountToCreate =
- { Username = "chris"
- EmailAddress = "chris@site.com" }
-
-match createAccount existingAcounts accountToCreate with
-| Ok account -> printfn "Created account: %A" account
-| Error error -> printfn "Failed to create account: %A" error
diff --git a/public/documentation/data-and-types/tuples.fsx b/public/documentation/data-and-types/tuples.fsx
deleted file mode 100644
index 82031ac..0000000
--- a/public/documentation/data-and-types/tuples.fsx
+++ /dev/null
@@ -1,2 +0,0 @@
-let (firstName, lastName) = ("John", "Doe")
-printfn "Hello %s %s!" firstName lastName
diff --git a/public/documentation/data-and-types/units-of-measure.fsx b/public/documentation/data-and-types/units-of-measure.fsx
deleted file mode 100644
index 697cd1d..0000000
--- a/public/documentation/data-and-types/units-of-measure.fsx
+++ /dev/null
@@ -1,16 +0,0 @@
-[]
-type mile
-
-[]
-type kilometer
-
-let miles = 10
-let kilometers = 10
-
-let calculateDistanceBetween (startMile: int) (endMile: int) = endMile - startMile
-
-
-let startMile = 10
-let endMile = 20
-let distance = calculateDistanceBetween startMile endMile
-printfn "Distance = %d" distance
diff --git a/public/documentation/functions/currying-and-partial-application.fsx b/public/documentation/functions/currying-and-partial-application.fsx
deleted file mode 100644
index 1a52c90..0000000
--- a/public/documentation/functions/currying-and-partial-application.fsx
+++ /dev/null
@@ -1,9 +0,0 @@
-let add x y = x + y
-
-let addFive = add 5 // partially applied
-let fifteen = addFive 10
-printfn "%d" fifteen
-
-let criticalOperation (logger: string -> unit) (value: string) = logger $"{value}!!!"
-let criticalOperationWithConsoleLogger = criticalOperation (printfn "%s")
-criticalOperationWithConsoleLogger "Hello, World!"
diff --git a/public/documentation/functions/defining-functions.fsx b/public/documentation/functions/defining-functions.fsx
deleted file mode 100644
index 3599863..0000000
--- a/public/documentation/functions/defining-functions.fsx
+++ /dev/null
@@ -1,3 +0,0 @@
-let add x y = x + y
-let ten = add 5 5
-printfn "%d" ten
diff --git a/public/documentation/functions/functions-as-values.fsx b/public/documentation/functions/functions-as-values.fsx
deleted file mode 100644
index 5b801a8..0000000
--- a/public/documentation/functions/functions-as-values.fsx
+++ /dev/null
@@ -1,8 +0,0 @@
-let double x = x * 2
-let apply (f: int -> int) = f 5
-
-let ten = apply double
-printfn "5 * 2 = %d" ten
-
-let twentyFive = apply (fun value -> value * 5)
-printfn "5 * 5 = %d" twentyFive
diff --git a/public/documentation/functions/functions-as-values.md b/public/documentation/functions/functions-as-values.md
index 4a51e2f..cf3710f 100644
--- a/public/documentation/functions/functions-as-values.md
+++ b/public/documentation/functions/functions-as-values.md
@@ -2,20 +2,37 @@
In F#, all functions are values and can be passed around as such. These are called _higher order functions_ or functions that accept other functions as parameters.
-Let's define a `double` function which has a single parameter.
+Let's define a `double` and `half` function which has a single argument.
```fsharp
let double x = x * 2
+let half x = x / 2
+
+let fifty = double 25
+let twentyFive = half 50
+
+printfn "fifty = %d" fifty
+printfn "twentyFive = %d" twentyFive
```
-This function will have a signature of `int -> int`. If we wanted to define a function which takes the `double` function as a parameter, that parameter would have a type of `int -> int`.
+These function have a signature of `int -> int`. If we wanted to define a function which takes the `double` and `half` functions as parameter, that parameter would have a type of `int -> int`.
```fsharp
-let apply (f: int -> int) = f 5
+let double x = x * 2
+let half x = x / 2
+
+let apply (f: int -> int) (x: int) = f x
+let fifty = apply double 25
+let twentyFive = apply half 50
+
+printfn "fifty = %d" fifty
+printfn "twentyFive = %d" twentyFive
```
You don't need to pass named functions to `apply`. Anonymous functions, sometimes called lambda functions, allow you to pass an inline function as a parameter.
```fsharp
-apply (fun value -> value * 5)
-```
+let apply (f: int -> int) (x: int) = f x
+let fifty = apply (fun x -> x * 10) 5
+printfn "fifty = %d" fifty
+```
\ No newline at end of file
diff --git a/public/documentation/functions/pipelines-and-composition.fsx b/public/documentation/functions/pipelines-and-composition.fsx
deleted file mode 100644
index 8790c07..0000000
--- a/public/documentation/functions/pipelines-and-composition.fsx
+++ /dev/null
@@ -1,11 +0,0 @@
-let negative x = x * - 1
-let double x = x * 2
-
-3 |> negative |> double |> printfn "double(negative(3)) = %d"
-
-let add x y = x + y
-let multiply x y = x * y
-let operation = add 3 >> multiply 3
-
-let result = operation 5
-printfn "multiply 3 (add 3 5) = %d" result
diff --git a/public/documentation/functions/pipelines-and-composition.md b/public/documentation/functions/pipelines-and-composition.md
index 982f6a1..7d655cd 100644
--- a/public/documentation/functions/pipelines-and-composition.md
+++ b/public/documentation/functions/pipelines-and-composition.md
@@ -1,32 +1,53 @@
# Pipelines and Composition
-The pipeline operator `|>` is a very simple operator that allows you to pipe a value into a function. We can see this by defining our own version of it.
+## The Pipeline Operator: `|>`
+
+The pipeline operator `|>` allows you to easier pass a value to a function, making your code cleaner and more expressive. Let's start by defining our own version of the operator to see how it works.
```fsharp
let (|>) value f = f value
```
-With the pipe operator, the function application of `f(g(x))` can be replaced with `x |> g |> f`. First, the value of `x` is applied to the function `g` and the result is applied to the function `f`.
+Using the pipeline operator, you can rewrite nested function calls like `f(g(x))` in a more readable way: `x |> g |> f`. First, the value of `x` is applied to the function `g` and the result is then applied to the function `f`.
+
+```fsharp
+let square x = x * x
+let addOne x = x + 1
+
+let result =
+ 4
+ |> square
+ |> addOne
+
+printfn "Result = %d" result
+```
-As the pipeline operator applies a value to a single parameter function (all F# functions), often times it's used in conjunction with partial application.
+In this case, the numebr `4` is squared to get `16`, and then added to `1` to get the value of `17`.
+
+Because a single value is piped into a single argument function, which all F# functions are, the pipeline operator is often used in conjunction with partial application. Here's another example that demonstrates this:
```fsharp
-let add x y = x + y
+let formatCurrency amount = sprintf "$%.2f" amount
+let applyDiscount rate price = price - (price * rate)
+let applyTax rate price = price + (price * rate)
-// produces int -> int function (not what we want)
-5 |> add
+let finalPrice =
+ 100.0
+ |> applyDiscount 0.1
+ |> applyTax 0.05
-// `add 3` is evaluated - producing an int -> int function
-// 5 is piped into that function.
-5 |> add 3
+printfn "Final Price = %s" (formatCurrency finalPrice)
```
-You can also combine two or more functions into a single function with the composition operator: `>>`. Let's define our own version of it to see how it works.
+Pay attention to the order of arguments in the `applyDiscount` and `applyTax` functions. In F#, it's common for the most important argument to be placed last. This design choice enhances the composability of functions. By positioning the `price` argument last, we can partially apply the `rate` argument, resulting in a function of type `float -> float` that can then be piped into or composed with other functions easily.
+
+## Composing Functions With `>>`
+
+You can compose two functions into a single function using the composition operator `>>`. Let's define our own version to understand how it works:
```fsharp
-let (>>) function1 function2 =
- fun value ->
- function2(function1(value))
+let (>>) f g =
+ fun x -> g (f x)
```
As you can see, a value is passed into the left-hand function and the result is passed into the right-hand function as an input. The function definition of `let func x = f(g(x))` can be replaced with `let func = g >> f`.
@@ -34,11 +55,14 @@ As you can see, a value is passed into the left-hand function and the result is
As you may notice, this operator is also often used in conjunction with partial application. This operator will create an `a -> c` function from the usage `(a -> b) >> (b -> c)`
```fsharp
-let add x y = x + y
-let multiply x y = x * y
-let operation = add 3 >> multiply 3
-// equivalent to:
-// let operation x = multiply 3 (add 3 x)
+let formatCurrency amount = sprintf "$%.2f" amount
+let applyDiscount rate price = price - (price * rate)
+let applyTax rate price = price + (price * rate)
+
+let calculatePrice = applyDiscount 0.1 >> applyTax 0.05
+let finalPrice = calculatePrice 100.0
+
+printfn "Final Price = %s" (formatCurrency finalPrice)
```
-The expression `add 3 >> multiply 3` works because the function signature of each function is `int -> int`. This will result in a function with an implicit parameter that will first be passed into `add 3` and the resulting `int` value will be passed into `multiply 3`.
\ No newline at end of file
+The expression `applyDiscount 0.1 >> applyTax 0.05` works because the function signature of each function is `float -> float`. This will result in a function with an implicit parameter that will be applied to the function `applyDiscount 0.1` and the resulting `float` value will be applied to the function `applyTax 0.05`.
\ No newline at end of file
diff --git a/public/documentation/functions/recursive-functions.fsx b/public/documentation/functions/recursive-functions.fsx
deleted file mode 100644
index 5bc57ee..0000000
--- a/public/documentation/functions/recursive-functions.fsx
+++ /dev/null
@@ -1,4 +0,0 @@
-let rec fib n =
- if n <= 1 then n else fib (n - 1) + fib (n - 2)
-
-printfn "%d" (fib 10)
diff --git a/public/documentation/functions/recursive-functions.md b/public/documentation/functions/recursive-functions.md
index 2dd8d9d..37afbfb 100644
--- a/public/documentation/functions/recursive-functions.md
+++ b/public/documentation/functions/recursive-functions.md
@@ -7,9 +7,8 @@ let rec fib n =
if n <= 1
then n
else fib (n - 1) + fib (n - 2)
-// ^^^ ^^^
-// function is allowed to be recursive
-// as the `rec` keyword is present.
+
+printfn "fib 5 = %d" (fib 5)
```
Mutually recursive functions can be defined using the `and` keyword.
diff --git a/public/documentation/object-programming/abstract-classes-and-inheritance.fsx b/public/documentation/object-programming/abstract-classes-and-inheritance.fsx
deleted file mode 100644
index 94a3538..0000000
--- a/public/documentation/object-programming/abstract-classes-and-inheritance.fsx
+++ /dev/null
@@ -1,13 +0,0 @@
-[]
-type Drawable() =
- member _.Description = "A drawable shape."
- abstract member Draw: float * float -> unit
-
-type Square(size: int) =
- inherit Drawable()
-
- override this.Draw(x: float, y: float) =
- printfn $"Drawing a square @ X: {x}, Y: {y}"
-
-let square = Square(10)
-square.Draw(0, 0)
diff --git a/public/documentation/object-programming/interfaces.fsx b/public/documentation/object-programming/interfaces.fsx
deleted file mode 100644
index 9c2a5a7..0000000
--- a/public/documentation/object-programming/interfaces.fsx
+++ /dev/null
@@ -1,18 +0,0 @@
-type IShape =
- abstract member Name: string
-
-type IDrawable =
- inherit IShape
- abstract member Draw: float * float -> unit
-
-type Square(size: int) =
- interface IDrawable with
- member this.Name = "Square"
-
- member this.Draw(x: float, y: float) =
- printfn $"Drawing a square with a size of {size} @ X: {x}, Y: {y}"
-
-
-let drawableShape: IDrawable = Square(10)
-printfn $"Shape Name: {drawableShape.Name}"
-drawableShape.Draw(10, 20)
diff --git a/public/documentation/object-programming/object-expressions.fsx b/public/documentation/object-programming/object-expressions.fsx
deleted file mode 100644
index 8ab83b9..0000000
--- a/public/documentation/object-programming/object-expressions.fsx
+++ /dev/null
@@ -1,9 +0,0 @@
-type IDrawable =
- abstract member Draw: float * float -> unit
-
-let square =
- { new IDrawable with
- member this.Draw(x: float, y: float) =
- printfn $"Drawing a square @ X: {x}, Y: {y}" }
-
-square.Draw(0.0, 0.0)
diff --git a/public/documentation/object-programming/objects-and-members.fsx b/public/documentation/object-programming/objects-and-members.fsx
deleted file mode 100644
index 7550406..0000000
--- a/public/documentation/object-programming/objects-and-members.fsx
+++ /dev/null
@@ -1,12 +0,0 @@
-type Person(firstName: string, lastName: string) =
- member val FirstName = firstName with get
- member val LastName = lastName with get
-
- member this.Greet(?greeting: string, ?punctuation: string) =
- let greeting = Option.defaultValue "Hello" greeting
- let punctuation = Option.defaultValue "!" punctuation
- $"{greeting} {this.FirstName} {this.LastName}{punctuation}"
-
-let person = Person("John", "Doe")
-let greeting = person.Greet(greeting = "Greetings", punctuation = "!!!")
-printfn "%s" greeting
diff --git a/public/documentation/object-programming/type-extensions.fsx b/public/documentation/object-programming/type-extensions.fsx
deleted file mode 100644
index 768fdcd..0000000
--- a/public/documentation/object-programming/type-extensions.fsx
+++ /dev/null
@@ -1,11 +0,0 @@
-open System
-
-type String with
-
- member string.IsUpperCase() = string = string.ToUpper()
-
-let uppercaseString = "HELLO WORLD"
-let lowercaseStringValue = "hello world"
-
-printfn "uppercaseString.IsUpperCase() = %b" (uppercaseString.IsUpperCase())
-printfn "lowercaseStringValue.IsUpperCase() = %b" (lowercaseStringValue.IsUpperCase())
diff --git a/public/documentation/table-of-contents.json b/public/documentation/table-of-contents.json
index e57ed21..bf84f72 100644
--- a/public/documentation/table-of-contents.json
+++ b/public/documentation/table-of-contents.json
@@ -4,47 +4,40 @@
{
"title": "Basics",
"route_segment": "basics",
- "pages": [
+ "entries": [
{
"title": "Hello, World!",
"route_segment": "hello-world",
- "fsharp_file": "basics/hello-world.fsx",
"markdown_file": "basics/hello-world.md"
},
{
"title": "Expressions",
"route_segment": "expressions",
- "fsharp_file": "basics/expressions.fsx",
"markdown_file": "basics/expressions.md"
},
{
"title": "Primitive Types",
"route_segment": "primitive-types",
- "fsharp_file": "basics/primitive-types.fsx",
"markdown_file": "basics/primitive-types.md"
},
{
"title": "String Formatting",
"route_segment": "string-formatting",
- "fsharp_file": "basics/string-formatting.fsx",
"markdown_file": "basics/string-formatting.md"
},
{
"title": "Operators",
"route_segment": "operators",
- "fsharp_file": "basics/operators.fsx",
"markdown_file": "basics/operators.md"
},
{
"title": "Conditional Expressions",
"route_segment": "conditional-expressions",
- "fsharp_file": "basics/conditional-expressions.fsx",
"markdown_file": "basics/conditional-expressions.md"
},
{
"title": "Patterns and Match Expressions",
"route_segment": "pattern-matching",
- "fsharp_file": "basics/patterns-and-match-expressions.fsx",
"markdown_file": "basics/patterns-and-match-expressions.md"
}
]
@@ -52,35 +45,30 @@
{
"title": "Functions",
"route_segment": "functions",
- "pages": [
+ "entries": [
{
"title": "Defining Functions",
"route_segment": "definition",
- "fsharp_file": "functions/defining-functions.fsx",
"markdown_file": "functions/defining-functions.md"
},
{
"title": "Functions as Values",
"route_segment": "values",
- "fsharp_file": "functions/functions-as-values.fsx",
"markdown_file": "functions/functions-as-values.md"
},
{
"title": "Recursive Functions",
"route_segment": "recursive-functions",
- "fsharp_file": "functions/recursive-functions.fsx",
"markdown_file": "functions/recursive-functions.md"
},
{
"title": "Currying and Partial Application",
"route_segment": "currying-and-partial-application",
- "fsharp_file": "functions/currying-and-partial-application.fsx",
"markdown_file": "functions/currying-and-partial-application.md"
},
{
"title": "Pipelines and Composition",
"route_segment": "pipelines-and-composition",
- "fsharp_file": "functions/pipelines-and-composition.fsx",
"markdown_file": "functions/pipelines-and-composition.md"
}
]
@@ -88,71 +76,60 @@
{
"title": "Data and Types",
"route_segment": "data-and-types",
- "pages": [
+ "entries": [
{
"title": "Tuples",
"route_segment": "tuples",
- "fsharp_file": "data-and-types/tuples.fsx",
"markdown_file": "data-and-types/tuples.md"
},
{
"title": "Lists",
"route_segment": "lists",
- "fsharp_file": "data-and-types/lists.fsx",
"markdown_file": "data-and-types/lists.md"
},
{
"title": "Sequences",
"route_segment": "sequences",
- "fsharp_file": "data-and-types/sequences.fsx",
"markdown_file": "data-and-types/sequences.md"
},
{
"title": "Sequence Expressions",
"route_segment": "sequence-expressions",
- "fsharp_file": "data-and-types/sequence-expressions.fsx",
"markdown_file": "data-and-types/sequence-expressions.md"
},
{
"title": "Type Abbreviations",
"route_segment": "abbreviations",
- "fsharp_file": "data-and-types/abbreviations.fsx",
"markdown_file": "data-and-types/abbreviations.md"
},
{
"title": "Records",
"route_segment": "records",
- "fsharp_file": "data-and-types/records.fsx",
"markdown_file": "data-and-types/records.md"
},
{
"title": "Discriminated Unions",
"route_segment": "discriminated-unions",
- "fsharp_file": "data-and-types/discriminated-unions.fsx",
"markdown_file": "data-and-types/discriminated-unions.md"
},
{
"title": "Generic Types",
"route_segment": "generic-types",
- "fsharp_file": "data-and-types/generic-types.fsx",
"markdown_file": "data-and-types/generic-types.md"
},
{
"title": "The Option Type",
"route_segment": "options",
- "fsharp_file": "data-and-types/the-option-type.fsx",
"markdown_file": "data-and-types/the-option-type.md"
},
{
"title": "The Result Type",
"route_segment": "results",
- "fsharp_file": "data-and-types/the-result-type.fsx",
"markdown_file": "data-and-types/the-result-type.md"
},
{
"title": "Units of Measure",
"route_segment": "units-of-measure",
- "fsharp_file": "data-and-types/units-of-measure.fsx",
"markdown_file": "data-and-types/units-of-measure.md"
}
]
@@ -160,35 +137,30 @@
{
"title": "Object Programming",
"route_segment": "object-programming",
- "pages": [
+ "entries": [
{
"title": "Objects and Members",
"route_segment": "objects-and-members",
- "fsharp_file": "object-programming/objects-and-members.fsx",
"markdown_file": "object-programming/objects-and-members.md"
},
{
"title": "Interfaces",
"route_segment": "interfaces",
- "fsharp_file": "object-programming/interfaces.fsx",
"markdown_file": "object-programming/interfaces.md"
},
{
"title": "Abstract Classes and Inheritance",
"route_segment": "abstract-classes-and-inheritance",
- "fsharp_file": "object-programming/abstract-classes-and-inheritance.fsx",
"markdown_file": "object-programming/abstract-classes-and-inheritance.md"
},
{
"title": "Object Expressions",
"route_segment": "object-expressions",
- "fsharp_file": "object-programming/object-expressions.fsx",
"markdown_file": "object-programming/object-expressions.md"
},
{
"title": "Type Extensions",
"route_segment": "type-extensions",
- "fsharp_file": "object-programming/type-extensions.fsx",
"markdown_file": "object-programming/type-extensions.md"
}
]
diff --git a/src/App/App.fs b/src/App/App.fs
index 11f9333..8836228 100644
--- a/src/App/App.fs
+++ b/src/App/App.fs
@@ -15,66 +15,29 @@ open MonacoEditor
open System
open Feliz.UseMediaQuery
+let fsharpOptions = [|
+ "--define:FABLE_COMPILER"
+ "--define:FABLE_COMPILER_4"
+ "--define:FABLE_COMPILER_JAVASCRIPT"
+ "--langversion:preview"
+|]
+
+let monacoEditorOptions = {|
+ minimap = {| enabled = false |}
+ fontSize = 16
+ fontFamily = "JetBrains Mono"
+|}
+
importSideEffects "react-toastify/dist/ReactToastify.css"
importSideEffects "./monaco-vite.js"
-[]
-type LogLevel =
- | Log
- | Warn
- | Error
-
-[]
-module LogLevel =
- let toCssColor logLevel =
- match logLevel with
- | LogLevel.Log -> "inherit"
- | LogLevel.Warn -> "darkorange"
- | LogLevel.Error -> "red"
-
-type Model = {
- Logs: (string * LogLevel) list
- FSharpCode: string
- CompiledJavaScript: string
- Markdown: string
- IFrameUrl: string
- Worker: ObservableWorker
- TableOfContents: Documentation.TableOfContents
- CurrentPage: Navigation.Page
- DocEntryNavigation: DocEntryNavigation
- Editor: Monaco.Editor.IStandaloneCodeEditor
- Markers: Monaco.Editor.IMarkerData array
- Debouncer: Debouncer.State
-}
-
-type Msg =
- | Compile
- | SetIFrameUrl of string
- | SetFSharpCode of string
- | SetMarkdown of string
- | AddConsoleLog of LogLevel * string
- | Compiled of code: string * language: string * errors: Error array * stats: CompileStats
- | FetchedTableOfContents of Documentation.TableOfContents
- | FetchTableOfContentsExn of exn
- | SetUrl of string list
- | CalculateMarkdownAndCodeValues
- | CalculateDocEntryNavigation
- | SetMarkers of Monaco.Editor.IMarkerData array
- | SetEditor of Monaco.Editor.IStandaloneCodeEditor
- | DebouncerSelfMsg of Debouncer.SelfMessage
- | ParseCode
-
[]
-type SyntaxHighlighter =
- static member inline language(value: string) = Interop.mkAttr "language" value
- static member inline style(value: string) = Interop.mkAttr "style" value
- static member inline children(value: ReactElement seq) = Interop.mkAttr "children" value
+type LzString =
+ []
+ static member compressToEncodedURIComponent(input: string) : string = nativeOnly
- static member inline highlighter(properties: IReactProperty list) =
- Interop.reactApi.createElement (
- import "Prism as ReactSyntaxHighlighter" "react-syntax-highlighter",
- createObj !!properties
- )
+ []
+ static member decompressFromEncodedURIComponent(compressed: string) : string = nativeOnly
[]
type MonacoEditor =
@@ -85,23 +48,32 @@ type MonacoEditor =
static member inline width(value: string) = Interop.mkAttr "width" value
static member inline height(value: string) = Interop.mkAttr "height" value
+ static member inline options(value: obj) = Interop.mkAttr "options" value
+
static member inline onMount(f: System.Func) =
Interop.mkAttr "onMount" f
static member inline editor(properties: IReactProperty list) =
Interop.reactApi.createElement (import "Editor" "@monaco-editor/react", createObj !!properties)
+[]
module WebWorker =
- let create () = Worker.Create(Constants.worker)
+ open MonacoEditor.Monaco.Editor
- let command (worker: ObservableWorker<_>) =
+ let create () = Worker.Create Constants.worker
+
+ let command
+ (setMarkersMsg: IMarkerData array -> 'msg)
+ (compiledMsg: string * string * Error array * CompileStats -> 'msg)
+ (worker: ObservableWorker<_>)
+ =
let handler dispatch =
worker
|> Observable.add (function
| Loaded version -> ()
| LoadFailed -> ()
- | ParsedCode errors -> errors |> Editor.mapErrorToMarker |> SetMarkers |> dispatch
- | CompilationFinished(code, lang, errors, stats) -> dispatch (Compiled(code, lang, errors, stats))
+ | ParsedCode errors -> errors |> Editor.mapErrorToMarker |> setMarkersMsg |> dispatch
+ | CompilationFinished(code, lang, errors, stats) -> dispatch (compiledMsg (code, lang, errors, stats))
| CompilationsFinished(code, lang, errors, stats) -> ()
| CompilerCrashed msg -> ()
| FoundTooltip _ -> ()
@@ -110,376 +82,595 @@ module WebWorker =
[ handler ]
-let getCurrentPage tableOfContents url =
- let pages = Documentation.TableOfContents.allPages tableOfContents
- Page.fromUrl pages url
-
-let init () =
- let fsharpOptions = [| "--define:FABLE_COMPILER"; "--langversion:preview" |]
- let worker = ObservableWorker(WebWorker.create (), WorkerAnswer.Decoder, "MAIN APP")
-
- CreateChecker(Constants.metadata, [||], Some ".txt", fsharpOptions)
- |> worker.Post
-
- let cmd =
+[]
+module EditorUtils =
+ []
+ type LogLevel =
+ | Log
+ | Warn
+ | Error
+
+
+ type Model = {
+ Logs: (string * LogLevel) list
+ FSharpCode: string
+ CompiledJavaScript: string
+ IFrameIdentifier: string
+ IFrameUrl: string
+ PlaygroundUrl: string
+ Worker: ObservableWorker
+ Editor: Monaco.Editor.IStandaloneCodeEditor
+ Markers: Monaco.Editor.IMarkerData array
+ Debouncer: Debouncer.State
+ }
+
+ []
+ type Msg =
+ | Compile
+ | ParseCode
+ | Compiled of code: string * language: string * errors: Error array * stats: CompileStats
+ | AddConsoleLog of string * LogLevel
+ | SetIFrameUrl of string
+ | SetFSharpCode of string
+ | DebouncerSelfMsg of Debouncer.SelfMessage
+ | SetMarkers of Monaco.Editor.IMarkerData array
+ | SetEditor of Monaco.Editor.IStandaloneCodeEditor
+
+ // TODO: move this to navigation???
+ let playgroundUrlComponents fsharpCode =
+ let data = LzString.compressToEncodedURIComponent fsharpCode
+ [ "playground"; $"?data={data}" ]
+
+ let createPlaygroundUrl fsharpCode =
+ Router.format (playgroundUrlComponents fsharpCode)
+
+ []
+ module LogLevel =
+ let toCssColor logLevel =
+ match logLevel with
+ | LogLevel.Log -> "inherit"
+ | LogLevel.Warn -> "darkorange"
+ | LogLevel.Error -> "red"
+
+ let fromCompilerError (error: Error) =
+ if error.IsWarning then LogLevel.Warn else LogLevel.Error
+
+ let setModelMarkers (editor: Monaco.Editor.IStandaloneCodeEditor) (markers: Monaco.Editor.IMarkerData array) =
+ match editor.getModel () with
+ | None -> ()
+ | Some textModel -> Monaco.editor.setModelMarkers (textModel, "FSharpErrors", ResizeArray markers)
+
+ let toastNotificationFromErrors (errors: Error array) =
+ match errors with
+ | [||] -> Toastify.success "Compiled successfully."
+ | errors when errors |> Array.forall _.IsWarning -> Toastify.warn "Compiled with warnings."
+ | _ -> Toastify.error "Failed to compile."
+
+ let initialCommand model =
Cmd.batch [
- WebWorker.command worker
- Iframe.command {
- ConsoleLog = fun out -> AddConsoleLog(LogLevel.Log, out)
- ConsoleWarn = fun out -> AddConsoleLog(LogLevel.Warn, out)
- ConsoleError = fun out -> AddConsoleLog(LogLevel.Error, out)
+ WebWorker.command Msg.SetMarkers Msg.Compiled model.Worker
+ Iframe.command model.IFrameIdentifier {
+ ConsoleLog = fun text -> Msg.AddConsoleLog(text, LogLevel.Log)
+ ConsoleWarn = fun text -> Msg.AddConsoleLog(text, LogLevel.Warn)
+ ConsoleError = fun text -> Msg.AddConsoleLog(text, LogLevel.Error)
}
- Cmd.OfPromise.either Documentation.loadTableOfContents () FetchedTableOfContents FetchTableOfContentsExn
+ Cmd.ofMsg Msg.ParseCode
]
- let currentUrl = Router.currentUrl ()
- let tableOfContents = Documentation.emptyTableOfContents
- let currentPage = getCurrentPage tableOfContents currentUrl
-
- {
- Logs = []
- FSharpCode = ""
- CompiledJavaScript = ""
- Markdown = ""
- IFrameUrl = ""
- Worker = worker
- TableOfContents = tableOfContents
- CurrentPage = currentPage
- DocEntryNavigation = {
- PreviousEntry = None
- NextEntry = None
- }
- Editor = Unchecked.defaultof
- Markers = [||]
- Debouncer = Debouncer.create ()
- },
- cmd
-
-let compile model =
- let language = "javascript"
- let fsharpOptions = [||]
- CompileCode(model.FSharpCode, language, fsharpOptions) |> model.Worker.Post
-
-let helloWorldCode = "printfn \"Hello, World!\""
-
-let calculateMarkdownValue (tableOfContents: Documentation.TableOfContents) currentPage =
- match currentPage with
- | Page.DocPage docPage -> docPage.MarkdownDocumentation
- | Page.NotFound
- | Page.Homepage -> tableOfContents.RootMarkdown
- | Page.TableOfContents -> Documentation.TableOfContents.toMarkdownString tableOfContents
-
-let calculateFSharpCodeValue currentPage =
- match currentPage with
- | Page.DocPage docPage -> docPage.FSharpCode
- | Page.NotFound
- | Page.Homepage
- | Page.TableOfContents -> helloWorldCode
-
-let setModelMarkers (editor: Monaco.Editor.IStandaloneCodeEditor) (markers: Monaco.Editor.IMarkerData array) =
- match editor.getModel () with
- | None -> ()
- | Some textModel -> Monaco.editor.setModelMarkers (textModel, "FSharpErrors", ResizeArray markers)
-
-let errorToLogLevel (error: Error) =
- if error.IsWarning then LogLevel.Warn else LogLevel.Error
-
-let toastNotificationFromErrors (errors: Error array) =
- match errors with
- | [||] -> Toastify.success "Compiled Successfully."
- | _ -> Toastify.error "Failed to Compile."
-
-let scrollToTopOfMarkdown () =
- let markdownElement = document.getElementById "markdown-content"
- markdownElement.scrollTo (0, 0)
-
-let update msg model =
- match msg with
- | Compile -> { model with Logs = [] }, Cmd.ofEffect (fun _ -> compile model)
- | SetIFrameUrl url -> { model with IFrameUrl = url }, Cmd.none
- | SetMarkdown doc -> { model with Markdown = doc }, Cmd.none
- | SetEditor editor -> { model with Editor = editor }, Cmd.none
- | ParseCode -> model, Cmd.ofEffect (fun _ -> WorkerRequest.ParseCode(model.FSharpCode, [||]) |> model.Worker.Post)
- | SetFSharpCode code ->
- let (debouncerModel, debouncerCmd) =
- model.Debouncer
- |> Debouncer.bounce (TimeSpan.FromSeconds 1) "user_input" ParseCode
+ let compile model =
+ CompileCode(model.FSharpCode, "javascript", fsharpOptions) |> model.Worker.Post
+
+ let update msg model =
+ match msg with
+ | Msg.Compile -> { model with Logs = [] }, Cmd.ofEffect (fun _ -> compile model)
+ | Msg.ParseCode ->
+ model, Cmd.ofEffect (fun _ -> WorkerRequest.ParseCode(model.FSharpCode, fsharpOptions) |> model.Worker.Post)
+ | Msg.SetIFrameUrl url -> { model with IFrameUrl = url }, Cmd.none
+ | Msg.SetEditor editor -> { model with Editor = editor }, Cmd.none
+ | Msg.AddConsoleLog(logText, logLevel) ->
+ let logs = model.Logs @ [ (logText, logLevel) ]
+ { model with Logs = logs }, Cmd.none
+ | Msg.SetMarkers markers ->
+ let model = { model with Markers = markers }
+ let cmd = Cmd.ofEffect (fun _ -> setModelMarkers model.Editor model.Markers)
+ model, cmd
+ | Msg.SetFSharpCode code ->
+ let (debouncerModel, debouncerCmd) =
+ model.Debouncer
+ |> Debouncer.bounce (TimeSpan.FromSeconds 1) "user_input" Msg.ParseCode
+
+ {
+ model with
+ FSharpCode = code
+ PlaygroundUrl = createPlaygroundUrl code // TODO: ??? do we want to do this every time you type?
+ Debouncer = debouncerModel
+ },
+ Cmd.map Msg.DebouncerSelfMsg debouncerCmd
+ | Msg.Compiled(code, language, errors, stats) ->
+ let logs =
+ if errors.Length = 0 then
+ model.Logs
+ else
+ let errorLogs =
+ errors
+ |> Array.map (fun error -> error.Message, LogLevel.fromCompilerError error)
+ |> Array.toList
+
+ model.Logs @ errorLogs
+
+ let model = {
+ model with
+ CompiledJavaScript = code
+ Logs = logs
+ }
- {
- model with
- FSharpCode = code
- Debouncer = debouncerModel
- },
- Cmd.map DebouncerSelfMsg debouncerCmd
- | SetMarkers markers ->
- let model = { model with Markers = markers }
- let cmd = Cmd.ofEffect (fun _ -> setModelMarkers model.Editor model.Markers)
- model, cmd
- | AddConsoleLog(level, output) ->
- let logs = model.Logs @ [ (output, level) ]
- { model with Logs = logs }, Cmd.none
- | Compiled(code, _, errors, _) ->
- let logs =
- if errors.Length = 0 then
- model.Logs
- else
- let errorLogs =
- errors
- |> Array.map (fun error -> error.Message, errorToLogLevel error)
- |> Array.toList
-
- model.Logs @ errorLogs
-
- let model = {
- model with
- CompiledJavaScript = code
- Logs = logs
- }
-
- model,
- Cmd.batch [
- Cmd.ofEffect (fun _ -> toastNotificationFromErrors errors |> ignore)
- errors |> Editor.mapErrorToMarker |> SetMarkers |> Cmd.ofMsg
- Cmd.OfFunc.perform Iframe.generateHtmlBlobUrl model.CompiledJavaScript SetIFrameUrl
- ]
- | FetchedTableOfContents tableOfContents ->
- let url = Router.currentUrl ()
- let currentPage = getCurrentPage tableOfContents url
+ model,
+ Cmd.batch [
+ Cmd.ofEffect (fun _ -> toastNotificationFromErrors errors |> ignore)
+ errors |> Editor.mapErrorToMarker |> Msg.SetMarkers |> Cmd.ofMsg
+ Cmd.OfFunc.perform Iframe.generateHtmlBlobUrl model.CompiledJavaScript Msg.SetIFrameUrl
+ ]
+ | Msg.DebouncerSelfMsg debouncerMsg ->
+ let (debouncerModel, debouncerCmd) = Debouncer.update debouncerMsg model.Debouncer
+
+ {
+ model with
+ Debouncer = debouncerModel
+ },
+ debouncerCmd
+
+ let init initialFsharpCode =
+ fun () ->
+ let randomIdentifier = Guid.NewGuid().ToString()
+
+ let worker =
+ ObservableWorker(WebWorker.create (), WorkerAnswer.Decoder, randomIdentifier)
+
+ CreateChecker(Constants.metadata, [||], Some ".txt", fsharpOptions)
+ |> worker.Post
+
+ let model = {
+ Logs = []
+ FSharpCode = initialFsharpCode
+ CompiledJavaScript = ""
+ IFrameIdentifier = randomIdentifier
+ IFrameUrl = ""
+ PlaygroundUrl = createPlaygroundUrl initialFsharpCode
+ Worker = worker
+ Editor = Unchecked.defaultof<_>
+ Markers = [||]
+ Debouncer = Debouncer.create ()
+ }
- {
- model with
- CurrentPage = currentPage
- TableOfContents = tableOfContents
- },
- Cmd.batch [
- Cmd.ofMsg CalculateMarkdownAndCodeValues
- Cmd.ofMsg CalculateDocEntryNavigation
- ]
- | FetchTableOfContentsExn exn -> model, Cmd.none // TODO: this.
- | SetUrl url ->
- let currentPage = getCurrentPage model.TableOfContents url
+ model, Cmd.batch [ initialCommand model ]
- { model with CurrentPage = currentPage },
- Cmd.batch [
- Cmd.ofMsg CalculateMarkdownAndCodeValues
- Cmd.ofMsg CalculateDocEntryNavigation
+[]
+module Playground =
+ []
+ let Component editorTheme initialFSharpCode =
+ let model, dispatch =
+ React.useElmish (EditorUtils.init initialFSharpCode, EditorUtils.update)
+
+ Html.div [
+ prop.className "playground"
+ prop.children [
+ Html.aside [
+ prop.className "sidebar"
+ prop.children [
+ Html.button [
+ prop.onClick (fun _ -> dispatch EditorUtils.Msg.Compile)
+ prop.children [ Html.i [ prop.className "fa-solid fa-play" ] ]
+ ]
+ Html.button [
+ prop.onClick (fun _ ->
+ Router.nav
+ (EditorUtils.playgroundUrlComponents model.FSharpCode)
+ HistoryMode.PushState
+ RouteMode.Hash)
+ prop.children [ Html.i [ prop.className "fa-solid fa-share-from-square" ] ]
+ ]
+ // TODO: Implement this (clear playground)
+ Html.button [ Html.i [ prop.className "fa-solid fa-trash" ] ]
+ ]
+ ]
+ Html.section [
+ prop.className "editor-group"
+ prop.children [
+ MonacoEditor.editor [
+ MonacoEditor.height "1000px"
+ MonacoEditor.defaultLanguage "fsharp"
+ MonacoEditor.value model.FSharpCode
+ MonacoEditor.theme editorTheme
+ MonacoEditor.onChange (EditorUtils.Msg.SetFSharpCode >> dispatch)
+ MonacoEditor.options monacoEditorOptions
+ MonacoEditor.onMount (
+ Editor.onFSharpEditorDidMount model.Worker (EditorUtils.Msg.SetEditor >> dispatch)
+ )
+ ]
+ match model.Logs with
+ | [] -> Html.none
+ | logs ->
+ Html.article [
+ for (log, level) in logs do
+ Html.p [ prop.text log ]
+ ]
+ Html.iframe [ prop.id model.IFrameIdentifier; prop.src model.IFrameUrl ]
+ ]
+ ]
+ ]
]
- | CalculateMarkdownAndCodeValues ->
- let fsharpCode = calculateFSharpCodeValue model.CurrentPage
- let markdown = calculateMarkdownValue model.TableOfContents model.CurrentPage
- // clear the logs when we calculate new values.
- { model with Logs = [] },
- // this has useful side-effects like triggering an initial parse through the `SetFSharpCode` msg.
- Cmd.batch [
- Cmd.ofMsg (SetFSharpCode fsharpCode)
- Cmd.ofMsg (SetMarkdown markdown)
- Cmd.ofEffect (fun _ -> scrollToTopOfMarkdown ())
+
+[]
+module DocumentationEditorInstance =
+ []
+ let Component editorTheme initialFsharpCode =
+ let isOutputExpanded, setOutputExpanded = React.useState false
+
+ let model, dispatch =
+ React.useElmish (EditorUtils.init initialFsharpCode, EditorUtils.update)
+
+ Html.div [
+ prop.className "editor-group"
+ prop.children [
+ MonacoEditor.editor [
+ MonacoEditor.height "350px"
+ MonacoEditor.defaultLanguage "fsharp"
+ MonacoEditor.value model.FSharpCode
+ MonacoEditor.theme editorTheme
+ MonacoEditor.onChange (EditorUtils.Msg.SetFSharpCode >> dispatch)
+ MonacoEditor.options monacoEditorOptions
+ MonacoEditor.onMount (
+ Editor.onFSharpEditorDidMount model.Worker (EditorUtils.Msg.SetEditor >> dispatch)
+ )
+ ]
+ Html.div [
+ prop.className "output-group"
+ prop.children [
+ if isOutputExpanded && not (List.isEmpty model.Logs) then
+ Html.div [
+ prop.className "output-logs"
+ prop.children [
+ for (log, level) in model.Logs do
+ Html.p [
+ prop.className (
+ match level with
+ | EditorUtils.LogLevel.Log -> "log-level-success"
+ | EditorUtils.LogLevel.Warn -> "log-level-warning"
+ | EditorUtils.LogLevel.Error -> "log-level-error"
+ )
+ prop.text log
+ ]
+ ]
+ ]
+ else
+ Html.none
+
+ Html.div [
+ prop.className "output-controls"
+ prop.children [
+ Html.div [
+ Html.p "Output"
+ Html.i [
+ prop.className (
+ if isOutputExpanded then
+ "fa-solid fa-caret-down"
+ else
+ "fa-solid fa-caret-up"
+ )
+ prop.onClick (fun _ -> setOutputExpanded (not isOutputExpanded))
+ ]
+ ]
+ Html.div [
+ Html.button [
+ prop.text "Compile"
+ prop.onClick (fun _ ->
+ dispatch EditorUtils.Msg.Compile
+ setOutputExpanded true)
+ ]
+ Html.a [
+ prop.href (EditorUtils.createPlaygroundUrl model.FSharpCode)
+ prop.text "Open in Playground"
+ ]
+ ]
+ ]
+ ]
+ ]
+ ]
+
+ Html.iframe [ prop.id model.IFrameIdentifier; prop.src model.IFrameUrl ]
+ ]
]
- | CalculateDocEntryNavigation ->
- let allEntries = Documentation.TableOfContents.allPages model.TableOfContents
- let currentEntry =
- match model.CurrentPage with
- | Page.DocPage docPage -> Entry docPage
- | _ -> NotViewingEntry
+[]
+module Documentation =
+ []
+ type CurrentEntry =
+ | Root
+ | Entry of Documentation.Entry
- {
- model with
- DocEntryNavigation = getDocEntryNavigation currentEntry allEntries
- },
- Cmd.none
- | DebouncerSelfMsg debouncerMsg ->
- let (debouncerModel, debouncerCmd) = Debouncer.update debouncerMsg model.Debouncer
+ let private formatDocRoute (route: string list) = Router.format ("docs" :: route)
- {
- model with
- Debouncer = debouncerModel
- },
- debouncerCmd
-
-let (|DesktopSize|MobileSize|) (screenSize: ScreenSize) =
- match screenSize with
- | ScreenSize.Desktop
- | ScreenSize.WideScreen -> DesktopSize
- | ScreenSize.Tablet
- | ScreenSize.Mobile
- | ScreenSize.MobileLandscape -> MobileSize
-
-let mobileNavbar =
- Html.ul [ Html.li [ Html.a [ prop.href (Router.format []); prop.text "F# For You" ] ] ]
-
-let imageLink href src text =
- Html.a [
- prop.href href
- prop.target "_blank"
- prop.children [
- Html.img [
- prop.src src
- prop.width 40
- prop.height 40
- prop.style [ style.marginRight (length.px 5) ]
+ []
+ let Component editorTheme currentEntry tableOfContents =
+ let allEntries = Documentation.TableOfContents.allEntries tableOfContents
+
+ let markdownDocumentation, githubUrl, docEntryNavigation =
+ match currentEntry with
+ | CurrentEntry.Root ->
+ tableOfContents.RootMarkdown,
+ tableOfContents.RootGitHubUrl,
+ {
+ PreviousEntry = None
+ NextEntry = allEntries |> List.tryHead |> Option.map NavigationEntry.fromDocEntry
+ }
+ | CurrentEntry.Entry entry ->
+ let navigation =
+ match getDocEntryNavigation entry allEntries with
+ | {
+ PreviousEntry = None
+ NextEntry = nextEntry
+ } -> {
+ PreviousEntry = Some { Title = "Cover"; Route = [] }
+ NextEntry = nextEntry
+ }
+ | navigation -> navigation
+
+ entry.MarkdownDocumentation, entry.GitHubUrl, navigation
+
+ Html.div [
+ prop.className "documentation"
+ prop.children [
+ Html.aside [
+ prop.className "sidebar"
+ prop.children [
+ Html.nav [
+ for category in tableOfContents.Categories do
+ Html.details [
+ Html.summary [ Html.strong category.Title ]
+ Html.ul [
+ for entry in category.Entries do
+ Html.li [
+ Html.a [ prop.href (formatDocRoute entry.Route); prop.text entry.Title ]
+ ]
+ ]
+ ]
+ ]
+ ]
+ ]
+ Html.section [
+ prop.className "markdown-content"
+ prop.children [
+ Markdown.markdown [
+ markdown.children markdownDocumentation
+ markdown.components [
+ // Put the "edit on github" link below the title
+ markdown.components.h1 (fun props ->
+ React.fragment [
+ Html.h1 props.children
+ Html.span [
+ prop.className "edit-this-page"
+ prop.children [
+ Html.i [ prop.className "fa-brands fa-github" ]
+ Html.a [
+ prop.target.blank
+ prop.href githubUrl
+ prop.children [ Html.small "Edit This Page on GitHub" ]
+ ]
+ ]
+ ]
+ ])
+
+ markdown.components.pre (fun props -> React.fragment props.children) // This doesn't wrap our editor instance in a `pre`
+ markdown.components.code (fun props ->
+ if props.isInline then
+ Html.code props.children
+ elif props.className <> "language-fsharp" then
+ Html.pre [ Html.code props.children ]
+ else
+ // this is an interesting way to get the value of a code block
+ props.children
+ |> Seq.tryHead
+ |> Option.map (string >> DocumentationEditorInstance.Component editorTheme)
+ |> Option.defaultValue Html.none)
+ ]
+ ]
+
+ Html.nav [
+ Html.ul [
+ match docEntryNavigation.PreviousEntry with
+ | None -> Html.none
+ | Some entry ->
+ Html.li [
+ Html.a [ prop.href (formatDocRoute entry.Route); prop.text $"< {entry.Title}" ]
+ ]
+
+ match docEntryNavigation.NextEntry with
+ | None -> Html.none
+ | Some entry ->
+ Html.li [
+ Html.a [ prop.href (formatDocRoute entry.Route); prop.text $"{entry.Title} >" ]
+ ]
+ ]
+ ]
+ ]
+ ]
]
- Html.small (text: string)
]
- ]
-let desktopNavbar = [
- Html.ul [ Html.li [ imageLink (Router.format []) "img/fsharp.png" "F# For You!" ] ]
+[]
+module App =
+ []
+ type Theme =
+ | Light
+ | Dark
+
+ []
+ module Theme =
+ let toString theme =
+ match theme with
+ | Theme.Light -> "light"
+ | Theme.Dark -> "dark"
+
+ let fromLocalStorage () =
+ match localStorage.getItem "theme" with
+ | "light" -> Theme.Light
+ | "dark"
+ | _ -> Theme.Dark
+
+ let saveToLocalStorage theme =
+ localStorage.setItem ("theme", toString theme)
+
+ let apply theme =
+ document.documentElement.setAttribute ("data-theme", toString theme)
+
+ type Model = {
+ CurrentUrl: string list
+ CurrentPage: Navigation.Page
+ CurrentTheme: Theme
+ TableOfContents: Documentation.TableOfContents
+ }
+
+ []
+ type Msg =
+ | SetUrl of string list
+ | FetchedTableOfContents of Documentation.TableOfContents
+ | ToggleTheme
+
+ let getPageFromUrl tableOfContents url =
+ Page.fromUrl (Documentation.TableOfContents.allEntries tableOfContents) url
+
+ let init () =
+ let currentTheme = Theme.fromLocalStorage ()
+ let tableOfContents = Documentation.emptyTableOfContents
- Html.ul [
- Html.li [ imageLink "https://fable.io" "img/fable.png" "Powered by Fable" ]
- Html.li [
- imageLink "https://github.com/fsharpforyou/tour" "img/github.png" "View Source Code"
+ {
+ CurrentUrl = []
+ CurrentPage = Page.Homepage
+ CurrentTheme = currentTheme
+ TableOfContents = tableOfContents
+ },
+ Cmd.batch [
+ Cmd.ofEffect (fun _ -> Theme.apply currentTheme)
+ Cmd.OfPromise.perform Documentation.loadTableOfContents () Msg.FetchedTableOfContents
]
- ]
-]
-module View =
+ let update msg model =
+ match msg with
+ | Msg.SetUrl url ->
+ let currentPage = getPageFromUrl model.TableOfContents url
+
+ {
+ model with
+ CurrentUrl = url
+ CurrentPage = currentPage
+ },
+ Cmd.none
+ | Msg.FetchedTableOfContents tableOfContents ->
+ let currentPage = getPageFromUrl tableOfContents model.CurrentUrl
+
+ {
+ model with
+ CurrentPage = currentPage
+ TableOfContents = tableOfContents
+ },
+ Cmd.none
+ | Msg.ToggleTheme ->
+ let nextTheme =
+ match model.CurrentTheme with
+ | Theme.Light -> Theme.Dark
+ | Theme.Dark -> Theme.Light
+
+ { model with CurrentTheme = nextTheme },
+ Cmd.ofEffect (fun _ ->
+ Theme.saveToLocalStorage nextTheme
+ Theme.apply nextTheme)
+
[]
- let AppView () =
+ let Component () =
let model, dispatch = React.useElmish (init, update)
- let screenSize = React.useResponsive Breakpoints.defaults
+
+ let editorTheme =
+ match model.CurrentTheme with
+ | Theme.Light -> "vs"
+ | Theme.Dark -> "vs-dark"
React.router [
- router.onUrlChanged (SetUrl >> dispatch)
+ router.onUrlChanged (Msg.SetUrl >> dispatch)
router.children [
- Html.main [
- prop.style [
- style.display.grid
-
- match screenSize with
- | MobileSize ->
- style.gridTemplateAreas [| [| "header" |]; [| "markdown" |]; [| "editor" |] |]
- style.gridTemplateRows [| length.percent 10; length.auto; length.px 750 |]
- style.gridTemplateColumns [| length.percent 100 |]
- | DesktopSize ->
- style.height (length.percent 100)
- style.gridTemplateAreas [| [| "header"; "header" |]; [| "markdown"; "editor" |] |]
- style.gridTemplateRows [| length.percent 10; length.percent 90 |]
- style.gridTemplateColumns [| length.percent 50; length.percent 50 |]
- ]
- prop.children [
- Html.header [
- prop.style [ style.gridArea "header" ]
+ Html.header [
+ Html.nav [
+ Html.ul [
+ prop.className "branding"
prop.children [
- Html.nav [
- match screenSize with
- | MobileSize -> mobileNavbar
- | DesktopSize -> yield! desktopNavbar
-
- Html.ul [
- Html.button [ prop.text "Run"; prop.onClick (fun _ -> dispatch Compile) ]
- ]
+ Html.li [
+ Html.img [ prop.src "img/fsharp.png" ]
+ Html.a [ prop.href (Router.format []); prop.text "F# For You" ]
]
]
]
- Html.section [
- prop.id "markdown-content"
- prop.style [
- style.gridArea "markdown"
- style.custom ("text-wrap", "balance")
- style.overflowX.hidden
+ Html.ul [
+ Html.li [ Html.a [ prop.href (Router.format [ "docs" ]); prop.text "Docs" ] ]
+ Html.li [
+ Html.a [ prop.href (Router.format [ "playground" ]); prop.text "Playground" ]
]
- prop.children [
- Markdown.markdown [
- markdown.children model.Markdown
- markdown.components [
- markdown.components.code (fun props ->
- if props.isInline then
- Html.code props.children
- else
- let style =
- import "vs" "react-syntax-highlighter/dist/esm/styles/prism"
-
- let language = props.className.Replace("language-", "")
-
- SyntaxHighlighter.highlighter [
- SyntaxHighlighter.language language
- SyntaxHighlighter.style style
- SyntaxHighlighter.children props.children
- ])
- ]
- ]
-
- Html.nav [
- Html.ul [
- match model.DocEntryNavigation.PreviousEntry with
- | None -> Html.none
- | Some entry ->
- Html.li [
- Html.a [
- prop.href (Router.format entry.Route)
- prop.text $"< {entry.Title}"
- ]
- ]
- Html.li [
- Html.a [
- prop.href (Router.format [ "table-of-contents" ])
- prop.text "Table of Contents"
- ]
- ]
- match model.DocEntryNavigation.NextEntry with
- | None -> Html.none
- | Some entry ->
- Html.li [
- Html.a [
- prop.href (Router.format entry.Route)
- prop.text $"{entry.Title} >"
- ]
- ]
+ ]
+ Html.ul [
+ Html.li [
+ Html.button [
+ Html.a [
+ prop.target.blank
+ prop.href "https://github.com/fsharpforyou/tour"
+ prop.children [ Html.i [ prop.className "fa-brands fa-github" ] ]
]
]
]
- ]
- Html.section [
- prop.style [ style.gridArea "editor" ]
- prop.children [
- Html.section [
- prop.style [ style.height (length.percent 70) ]
+ Html.li [
+ Html.button [
+ prop.onClick (fun _ -> dispatch Msg.ToggleTheme)
prop.children [
- MonacoEditor.editor [
- MonacoEditor.defaultLanguage "fsharp"
- MonacoEditor.value model.FSharpCode
- MonacoEditor.theme "vs"
- MonacoEditor.onChange (SetFSharpCode >> dispatch)
- MonacoEditor.onMount (
- Editor.onFSharpEditorDidMount model.Worker (SetEditor >> dispatch)
+ Html.i [
+ prop.className (
+ match model.CurrentTheme with
+ | Theme.Light -> "fa-solid fa-moon"
+ | Theme.Dark -> "fa-solid fa-sun"
)
]
]
]
- Html.article [
- prop.style [ style.height (length.percent 30); style.overflow.scroll ]
- prop.children [
- Html.h4 "Output"
- for (log, level) in model.Logs do
- Html.p [
- prop.style [ style.color (LogLevel.toCssColor level) ]
- prop.text log
- ]
-
- Html.hr []
- ]
- ]
]
]
]
]
- Html.iframe [
- prop.src model.IFrameUrl
- prop.style [
- style.position.absolute
- style.width 0
- style.height 0
- style.border (0, borderStyle.hidden, "")
+ Html.main [
+ match model.CurrentPage with
+ | Page.Docs ->
+ Documentation.Component editorTheme Documentation.CurrentEntry.Root model.TableOfContents
+ | Page.DocsEntry entry ->
+ Documentation.Component
+ editorTheme
+ (Documentation.CurrentEntry.Entry entry)
+ model.TableOfContents
+ | Page.Homepage -> Html.p "Homepage"
+ | Page.Playground data ->
+ let initialCode =
+ data
+ |> Option.map LzString.decompressFromEncodedURIComponent
+ |> Option.defaultValue ""
+
+ Playground.Component editorTheme initialCode
+ | Page.NotFound -> Html.p "Not found"
+
+ Toastify.container [
+ ContainerOption.autoClose 2000
+ ContainerOption.position Position.BottomRight
+ ContainerOption.theme (
+ match model.CurrentTheme with
+ | Theme.Light -> Fable.ReactToastify.Theme.Light
+ | Theme.Dark -> Fable.ReactToastify.Theme.Dark
+ )
]
]
- Toastify.container [
- ContainerOption.autoClose 2000
- ContainerOption.position Position.BottomRight
- ContainerOption.theme Theme.Light
- ]
]
]
-ReactDOM.createRoot(document.getElementById "app").render (View.AppView())
+ReactDOM.createRoot(document.getElementById "app").render (App.Component())
diff --git a/src/App/Documentation.fs b/src/App/Documentation.fs
index 9c0ace6..3f944a8 100644
--- a/src/App/Documentation.fs
+++ b/src/App/Documentation.fs
@@ -4,58 +4,40 @@ module Documentation
open Feliz.Router
open Thoth.Json
-type Page = {
+type Entry = {
Title: string
Route: string list
- FSharpCode: string
MarkdownDocumentation: string
+ GitHubUrl: string
}
-type Category = { Title: string; Pages: Page list }
+type Category = { Title: string; Entries: Entry list }
type TableOfContents = {
RootMarkdown: string
+ RootGitHubUrl: string
Categories: Category list
}
+let makeGitHubUrl relativePath =
+ $"https://github.com/fsharpforyou/tour/tree/main/public/documentation/{relativePath}"
+
[]
module TableOfContents =
- let allPages tableOfContents =
- tableOfContents.Categories |> List.collect _.Pages
-
- let toMarkdownString tableOfContents =
- let bulletPoint value = $"* {value}"
- let createMarkdownLink value url = $"[{value}]({url})"
-
- let createHeading level value =
- let hashtags = String.replicate level "#"
- $"{hashtags} {value}"
-
- let createUrlForPage page = Router.format page.Route
-
- let categoryToPageUrls category =
- category.Pages
- |> List.map (fun page -> page |> createUrlForPage |> createMarkdownLink page.Title |> bulletPoint)
-
- let createMarkdownForCategory category =
- [ createHeading 2 category.Title ] @ categoryToPageUrls category
-
- [ createHeading 1 "Table of Contents" ]
- @ List.collect createMarkdownForCategory tableOfContents.Categories
- |> String.concat "\n"
+ let allEntries tableOfContents =
+ tableOfContents.Categories |> List.collect _.Entries
module private Json =
- type PageJson = {
+ type EntryJson = {
Title: string
RouteSegment: string
- FSharpFile: string
MarkdownFile: string
}
type CategoryJson = {
Title: string
RouteSegment: string
- Pages: PageJson list
+ Entries: EntryJson list
}
type TableOfContentsJson = {
@@ -63,11 +45,10 @@ module private Json =
Categories: CategoryJson list
}
- let pageDecoder =
+ let entryDecoder =
Decode.object (fun get -> {
Title = get.Required.Field "title" Decode.string
RouteSegment = get.Required.Field "route_segment" Decode.string
- FSharpFile = get.Required.Field "fsharp_file" Decode.string
MarkdownFile = get.Required.Field "markdown_file" Decode.string
})
@@ -75,7 +56,7 @@ module private Json =
Decode.object (fun get -> {
Title = get.Required.Field "title" Decode.string
RouteSegment = get.Required.Field "route_segment" Decode.string
- Pages = get.Required.Field "pages" (Decode.list pageDecoder)
+ Entries = get.Required.Field "entries" (Decode.list entryDecoder)
})
let tableOfContentsDecoder =
@@ -84,35 +65,39 @@ module private Json =
Categories = get.Required.Field "categories" (Decode.list categoryDecoder)
})
-let emptyTableOfContents = { RootMarkdown = ""; Categories = [] }
+let emptyTableOfContents = {
+ RootMarkdown = ""
+ RootGitHubUrl = ""
+ Categories = []
+}
+
let private documentationPath path = Constants.documentation + path
let private fetchAsString path =
Fetch.fetch path [] |> Promise.bind (fun res -> res.text ())
-let private loadPageFromJson (categoryJson: Json.CategoryJson) (pageJson: Json.PageJson) =
+let private loadEntryFromJson (categoryJson: Json.CategoryJson) (entryJson: Json.EntryJson) =
promise {
- let! fsharpCode = fetchAsString (documentationPath pageJson.FSharpFile)
- let! markdownDoc = fetchAsString (documentationPath pageJson.MarkdownFile)
+ let! markdownDoc = fetchAsString (documentationPath entryJson.MarkdownFile)
return {
- Title = pageJson.Title
- Route = [ categoryJson.RouteSegment; pageJson.RouteSegment ]
- FSharpCode = fsharpCode
+ Title = entryJson.Title
+ Route = [ categoryJson.RouteSegment; entryJson.RouteSegment ]
MarkdownDocumentation = markdownDoc
+ GitHubUrl = makeGitHubUrl entryJson.MarkdownFile
}
}
let private loadCategoryFromJson (categoryJson: Json.CategoryJson) =
promise {
- let! pages =
- categoryJson.Pages
- |> List.map (fun page -> loadPageFromJson categoryJson page)
+ let! entries =
+ categoryJson.Entries
+ |> List.map (fun entry -> loadEntryFromJson categoryJson entry)
|> Promise.all
return {
Title = categoryJson.Title
- Pages = Seq.toList pages
+ Entries = Seq.toList entries
}
}
@@ -123,6 +108,7 @@ let private loadTableOfContentsFromJson (tableOfContentsJson: Json.TableOfConten
return {
RootMarkdown = rootMarkdown
+ RootGitHubUrl = makeGitHubUrl tableOfContentsJson.RootMarkdownFile
Categories = Seq.toList categories
}
}
diff --git a/src/App/Editor.fs b/src/App/Editor.fs
index 6d0e59d..537d350 100644
--- a/src/App/Editor.fs
+++ b/src/App/Editor.fs
@@ -234,6 +234,7 @@ let createTooltipProvider getTooltip =
jsOptions (fun h ->
h.contents <-
lines
+ |> Seq.distinct // I'm not sure why this is required but I'm getting duplicate entries in the tooltip
|> Seq.map Tooltip.replaceXml
|> Seq.mapi (fun i line ->
{|
diff --git a/src/App/Iframe.fs b/src/App/Iframe.fs
index 0903634..faf0850 100644
--- a/src/App/Iframe.fs
+++ b/src/App/Iframe.fs
@@ -13,24 +13,28 @@ type MessageArgs<'msg> = {
ConsoleError: string -> 'msg
}
-let command (args: MessageArgs<'Msg>) =
+let command (iframeId: string) (args: MessageArgs<'Msg>) =
let handler dispatch =
window.addEventListener (
"message",
fun ev ->
- let iframeMessageDecoder =
- Decode.field "type" Decode.string
- |> Decode.option
- |> Decode.andThen (function
- | Some "console_log" -> Decode.field "content" Decode.string |> Decode.map args.ConsoleLog
- | Some "console_warn" -> Decode.field "content" Decode.string |> Decode.map args.ConsoleWarn
- | Some "console_error" -> Decode.field "content" Decode.string |> Decode.map args.ConsoleError
- | _ -> Decode.fail "Invalid message")
-
- Decode.fromValue "$" iframeMessageDecoder ev?data
- |> function
- | Error _ -> ()
- | Ok msg -> dispatch msg
+ let iframeElement = document.getElementById iframeId
+
+ if iframeElement <> null && ev?source = iframeElement?contentWindow then
+ let iframeMessageDecoder =
+ Decode.field "type" Decode.string
+ |> Decode.option
+ |> Decode.andThen (function
+ | Some "console_log" -> Decode.field "content" Decode.string |> Decode.map args.ConsoleLog
+ | Some "console_warn" -> Decode.field "content" Decode.string |> Decode.map args.ConsoleWarn
+ | Some "console_error" ->
+ Decode.field "content" Decode.string |> Decode.map args.ConsoleError
+ | _ -> Decode.fail "Invalid message")
+
+ Decode.fromValue "$" iframeMessageDecoder ev?data
+ |> function
+ | Error _ -> ()
+ | Ok msg -> dispatch msg
)
[ handler ]
diff --git a/src/App/Navigation.fs b/src/App/Navigation.fs
index 5f1234a..97eb5f3 100644
--- a/src/App/Navigation.fs
+++ b/src/App/Navigation.fs
@@ -1,49 +1,59 @@
module Navigation
+open Feliz.Router
+
[]
type Page =
| Homepage
- | TableOfContents
- | DocPage of Documentation.Page
+ | Docs
+ | DocsEntry of Documentation.Entry
+ | Playground of data: string option
| NotFound
[]
module Page =
- let fromUrl docPages url =
+ let fromUrl docEntries url =
match url with
| [] -> Page.Homepage
- | [ "table-of-contents" ] -> Page.TableOfContents
- | routeSegments ->
- docPages
- |> List.tryFind (fun (docPage: Documentation.Page) -> docPage.Route = routeSegments)
- |> Option.map Page.DocPage
- |> Option.defaultValue Page.NotFound
+ | [ "playground" ] -> Page.Playground None
+ | [ "playground"; Route.Query [ "data", dataUrl ] ] -> Page.Playground(Some dataUrl)
+ | "docs" :: routeSegments ->
+ match routeSegments with
+ | [] -> Page.Docs
+ | routeSegments ->
+ printfn "route segments %A" routeSegments
+
+ docEntries
+ |> List.tryFind (fun (entry: Documentation.Entry) -> entry.Route = routeSegments)
+ |> Option.map Page.DocsEntry
+ |> Option.defaultValue Page.NotFound
+ | _ -> Page.NotFound
+
+type NavigationEntry = { Title: string; Route: string list }
+
+[]
+module NavigationEntry =
+ let fromDocEntry (docEntry: Documentation.Entry) = {
+ Title = docEntry.Title
+ Route = docEntry.Route
+ }
-type CurrentEntry =
- | Entry of Documentation.Page
- | NotViewingEntry
type DocEntryNavigation = {
- PreviousEntry: Documentation.Page option
- NextEntry: Documentation.Page option
+ PreviousEntry: NavigationEntry option
+ NextEntry: NavigationEntry option
}
-let getDocEntryNavigation (currentEntry: CurrentEntry) (allEntries: Documentation.Page list) =
- let previous, next =
- match currentEntry with
- | NotViewingEntry ->
- let previous = None
- let next = List.tryItem 0 allEntries
+let getDocEntryNavigation (docPage: Documentation.Entry) (allEntries: Documentation.Entry list) =
+ let previousDocEntry, nextDocEntry =
+ match List.tryFindIndex (fun elem -> elem = docPage) allEntries with
+ | None -> None, None
+ | Some currentIndex ->
+ let previous = List.tryItem (currentIndex - 1) allEntries
+ let next = List.tryItem (currentIndex + 1) allEntries
previous, next
- | Entry entry ->
- match List.tryFindIndex (fun elem -> elem = entry) allEntries with
- | None -> None, None
- | Some currentIndex ->
- let previous = List.tryItem (currentIndex - 1) allEntries
- let next = List.tryItem (currentIndex + 1) allEntries
- previous, next
{
- PreviousEntry = previous
- NextEntry = next
+ PreviousEntry = previousDocEntry |> Option.map NavigationEntry.fromDocEntry
+ NextEntry = nextDocEntry |> Option.map NavigationEntry.fromDocEntry
}
diff --git a/styles.css b/styles.css
new file mode 100644
index 0000000..ddac53a
--- /dev/null
+++ b/styles.css
@@ -0,0 +1,249 @@
+/*
+https://blog.logrocket.com/css-utility-classes-library-extendable-styles/
+https://dev.to/ananyaneogi/create-a-dark-light-mode-switch-with-css-variables-34l8
+*/
+
+@import url('https://fonts.googleapis.com/css2?family=JetBrains+Mono:ital,wght@0,100..800;1,100..800&display=swap');
+
+:root {
+ --background-color: #fff;
+ --header-background-color: #fff;
+ --border-color: #cccccc;
+ --code-block-background-color: #dddddd;
+ --text-color: #000;
+}
+
+[data-theme="dark"] {
+ --background-color: #1e1e1e;
+ --header-background-color: #1e1e1e;
+ --border-color: #2d2d2d;
+ --code-block-background-color: #dddddd;
+ --text-color: #fff;
+}
+
+iframe {
+ position: absolute;
+ width: 0;
+ height: 0;
+ border: hidden;
+}
+
+body {
+ font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
+ background-color: var(--background-color);
+}
+
+a:visited {
+ color: inherit;
+}
+
+/* h1,
+h2,
+h3,
+h4,
+h5,
+h6,
+p,
+li,
+strong,
+small,
+a {
+ color: var(--text-color);
+} */
+
+nav ul,
+details ul {
+ list-style-type: none;
+}
+
+.edit-this-page {
+ display: flex;
+ align-items: center;
+ column-gap: 5px;
+}
+
+pre,
+code {
+ --padding: 0.25em;
+
+ border-radius: 0.25em;
+ background-color: var(--code-block-background-color);
+ padding-top: var(--padding);
+ padding-bottom: var(--padding);
+ padding-left: var(--padding);
+ padding-right: var(--padding);
+}
+
+pre>code {
+ all: unset;
+}
+
+header {
+ width: 100%;
+ border-bottom: 1px solid var(--border-color);
+ background-color: var(--header-background-color);
+}
+
+header nav a,
+details ul li a {
+ display: block;
+ text-decoration: none;
+ color: inherit;
+
+}
+
+header nav {
+ display: flex;
+ justify-content: space-between;
+}
+
+header nav ul {
+ display: flex;
+}
+
+.branding>li {
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ column-gap: 5px;
+}
+
+.branding>li>img {
+ height: 20px;
+ width: 20px;
+}
+
+header nav li {
+ padding-left: 0.25rem;
+ padding-right: 0.25rem;
+}
+
+header nav button {
+ background: none;
+ border: none;
+ /* border: 1px solid black;
+ border-radius: 0.25rem; */
+}
+
+/* button i {
+ font-size: 1.25em;
+} */
+
+.documentation {
+ display: grid;
+ grid-template-columns: 25% 75%;
+ grid-template-rows: 100%;
+ grid-template-areas: "sidebar markdown-content";
+}
+
+.documentation .sidebar {
+ grid-area: "sidebar";
+ padding-left: 0.5em;
+ padding-top: 0.5em;
+ background-color: var(--header-background-color);
+ border-right: 1px solid var(--border-color);
+}
+
+.documentation .sidebar li:hover {
+ background-color: #c3c3c3;
+}
+
+.documentation .markdown-content {
+ grid-area: "markdown-content";
+ padding-left: 25px;
+ padding-right: 25px;
+}
+
+.documentation .markdown-content nav ul {
+ display: flex;
+ justify-content: space-between;
+}
+
+.documentation .markdown-content nav ul li a {
+ text-decoration: none;
+}
+
+.documentation .editor-group {
+ border: solid 1px var(--border-color);
+}
+
+.documentation .output-group .output-logs {
+ border-top: 1px solid var(--border-color);
+ /* padding-left: 10px; */
+}
+
+.documentation .output-group .output-logs p {
+ padding-left: 10px;
+}
+
+.documentation .output-group .output-logs .log-level-success {
+ border-left: 10px solid green;
+}
+
+.documentation .output-group .output-logs .log-level-warning {
+ border-left: 10px solid yellow;
+}
+
+.documentation .output-group .output-logs .log-level-error {
+ border-left: 10px solid red;
+}
+
+.documentation .output-group .output-controls {
+ display: flex;
+ flex-direction: row;
+ justify-content: space-between;
+ align-items: center;
+
+ border-top: 1px solid var(--border-color);
+ /* background-color: white; */
+
+ padding-left: 1em;
+ padding-right: 1em;
+}
+
+.documentation .output-group .output-controls div {
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ column-gap: 10px;
+}
+
+/* .documentation .output-group .output-controls div button {
+ background: none;
+ border: none;
+ font-size: 1em;
+} */
+
+.documentation .output-group .output-controls div a {
+ /* text-decoration: none; */
+ color: inherit;
+ font-size: 1em;
+}
+
+.playground {
+ display: grid;
+ grid-template-columns: 5% 95%;
+ grid-template-rows: 100%;
+ grid-template-areas: "sidebar editor";
+}
+
+.playground .sidebar {
+ grid-area: "sidebar";
+ display: flex;
+ flex-direction: column;
+ row-gap: 0.5em;
+ padding-top: 10px;
+ background-color: var(--header-background-color);
+ border-right: 1px solid var(--border-color);
+}
+
+.playground .sidebar button {
+ background: none;
+ border: none;
+ /* border: 1px solid black; */
+ /* border-radius: 0.25em; */
+}
+
+.playground .editor-group {
+ grid-area: "editor";
+}
\ No newline at end of file