improved post view (more code highlight, visual improvements)

This commit is contained in:
Daniel Bulant 2023-03-04 19:23:18 +01:00
parent 0d2af70319
commit 4b6ee107e8
20 changed files with 1067 additions and 135 deletions

View file

@ -27,6 +27,7 @@
},
"type": "module",
"dependencies": {
"@atomiks/mdx-pretty-code": "^0.1.0",
"@elastic/apm-rum": "^5.12.0",
"@sentry/browser": "^7.40.0",
"@sveltejs/pancake": "^0.0.18",
@ -43,8 +44,10 @@
"remark-math": "2.0.1",
"remark-parse": "10.0.1",
"remark-twemoji": "0.1.1",
"shiki": "^0.14.1",
"twemoji": "13.1.0",
"unified": "^10.1.2",
"unist-util-visit": "^4.1.2",
"vite": "^4.1.4",
"xterm": "4.18.0"
}

View file

@ -1,6 +1,7 @@
lockfileVersion: 5.4
specifiers:
'@atomiks/mdx-pretty-code': ^0.1.0
'@dimforge/rapier3d-compat': ^0.10.0
'@elastic/apm-rum': ^5.12.0
'@sentry/browser': ^7.40.0
@ -29,16 +30,19 @@ specifiers:
remark-math: 2.0.1
remark-parse: 10.0.1
remark-twemoji: 0.1.1
shiki: ^0.14.1
svelte: 3.55.1
svelte-sequential-preprocessor: ^0.0.7
three: ^0.148.0
twemoji: 13.1.0
unified: ^10.1.2
unist-util-visit: ^4.1.2
vite: ^4.1.4
vite-plugin-windicss: ^1.8.10
xterm: 4.18.0
dependencies:
'@atomiks/mdx-pretty-code': 0.1.0_shiki@0.14.1
'@elastic/apm-rum': 5.12.0
'@sentry/browser': 7.40.0
'@sveltejs/pancake': 0.0.18
@ -55,8 +59,10 @@ dependencies:
remark-math: 2.0.1
remark-parse: 10.0.1
remark-twemoji: 0.1.1_twemoji@13.1.0
shiki: 0.14.1
twemoji: 13.1.0
unified: 10.1.2
unist-util-visit: 4.1.2
vite: 4.1.4
xterm: 4.18.0
@ -84,6 +90,22 @@ packages:
resolution: {integrity: sha512-vy9fM3pIxZmX07dL+VX1aZe7ynZ+YyB0jY+jE6r3hOK6GNY2t6W8rzpFC4tgpbXUYABkFQwgJq2XYXlxbXAI0g==}
dev: true
/@atomiks/mdx-pretty-code/0.1.0_shiki@0.14.1:
resolution: {integrity: sha512-s6L3XBgqE9J9MlNQWbETxY5srrv4rN2B+c46o5KHg7W8+VrAAu0NInci1F6AwcEzaV+/vlc6WO6lPSucCwpngA==}
peerDependencies:
shiki: '*'
dependencies:
jsdom: 19.0.0
parse-numeric-range: 1.3.0
sanitize-html: 2.10.0
shiki: 0.14.1
transitivePeerDependencies:
- bufferutil
- canvas
- supports-color
- utf-8-validate
dev: false
/@dimforge/rapier3d-compat/0.10.0:
resolution: {integrity: sha512-3SPxyAnPQz9P3cIhgF8VncwJwrqyAW2xsNEYgXbxDhvB2IaIG63eTX7rNIJUnec5FDYqgvVo/nqY1XarzT5T2Q==}
dev: true
@ -457,6 +479,11 @@ packages:
resolution: {integrity: sha512-Pu8wwEOmzJ3Dqs1h2SeEUQG3lyg4M3ppRj/TGONijTSAchprfY4kTXBI1hZz1k6mn2c2FNY13HsiAjwQJnMWug==}
dev: true
/@tootallnate/once/2.0.0:
resolution: {integrity: sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==}
engines: {node: '>= 10'}
dev: false
/@types/cookie/0.5.1:
resolution: {integrity: sha512-COUnqfB2+ckwXXSFInsFdOAWQzCCx+a5hq2ruyj+Vjund94RJQd4LG2u9hnvJrTgunKAaax7ancBYlDrNYxA0g==}
dev: true
@ -520,6 +547,47 @@ packages:
- supports-color
dev: true
/abab/2.0.6:
resolution: {integrity: sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==}
dev: false
/acorn-globals/6.0.0:
resolution: {integrity: sha512-ZQl7LOWaF5ePqqcX4hLuv/bLXYQNfNWw2c0/yX/TsPRKamzHcTGQnlCjHT3TsmkOUVEPS3crCxiPfdzE/Trlhg==}
dependencies:
acorn: 7.4.1
acorn-walk: 7.2.0
dev: false
/acorn-walk/7.2.0:
resolution: {integrity: sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==}
engines: {node: '>=0.4.0'}
dev: false
/acorn/7.4.1:
resolution: {integrity: sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==}
engines: {node: '>=0.4.0'}
hasBin: true
dev: false
/acorn/8.8.2:
resolution: {integrity: sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==}
engines: {node: '>=0.4.0'}
hasBin: true
dev: false
/agent-base/6.0.2:
resolution: {integrity: sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==}
engines: {node: '>= 6.0.0'}
dependencies:
debug: 4.3.4
transitivePeerDependencies:
- supports-color
dev: false
/ansi-sequence-parser/1.1.0:
resolution: {integrity: sha512-lEm8mt52to2fT8GhciPCGeCXACSz2UwIN4X2e2LJSnZ5uAbn2/dsYdOmUXq0AtWS5cpAupysIneExOgH0Vd2TQ==}
dev: false
/assert/2.0.0:
resolution: {integrity: sha512-se5Cd+js9dXJnu6Ag2JFc00t+HmHOen+8Q+L7O9zI0PqQXr20uk2J0XQqMxZEeo5U50o8Nvmmx7dZrl+Ufr35A==}
dependencies:
@ -529,6 +597,10 @@ packages:
util: 0.12.5
dev: false
/asynckit/0.4.0:
resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==}
dev: false
/available-typed-arrays/1.0.5:
resolution: {integrity: sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==}
engines: {node: '>= 0.4'}
@ -559,6 +631,10 @@ packages:
fill-range: 7.0.1
dev: true
/browser-process-hrtime/1.0.0:
resolution: {integrity: sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow==}
dev: false
/busboy/1.6.0:
resolution: {integrity: sha512-8SFQbg/0hQ9xy3UNTB0YEnsNBbWfhf7RtnzpL7TkBiTBRfrQ9Fxcnz7VJsleJpyp6rVLvXiuORqjlHi5q+PYuA==}
engines: {node: '>=10.16.0'}
@ -581,6 +657,13 @@ packages:
resolution: {integrity: sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ==}
dev: false
/combined-stream/1.0.8:
resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==}
engines: {node: '>= 0.8'}
dependencies:
delayed-stream: 1.0.0
dev: false
/comma-separated-tokens/1.0.8:
resolution: {integrity: sha512-GHuDRO12Sypu2cV70d1dkA2EUmXHgntrzbpvOB+Qy+49ypNfGgFQIC2fhhXbnyrJRynDCAARsT7Ou0M6hirpfw==}
dev: false
@ -603,6 +686,30 @@ packages:
resolution: {integrity: sha512-HYPSb7y/Z7BNDCOrakL4raGO2zltZkbeXyAd6Tg9obzix6QhzxCotdBl6VT0Dv4vZfJGVz3WL/xaEI9Ly3ul0g==}
dev: false
/cssom/0.3.8:
resolution: {integrity: sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==}
dev: false
/cssom/0.5.0:
resolution: {integrity: sha512-iKuQcq+NdHqlAcwUY0o/HL69XQrUaQdMjmStJ8JFmUaiiQErlhrmuigkg/CU4E2J0IyUKUrMAgl36TvN67MqTw==}
dev: false
/cssstyle/2.3.0:
resolution: {integrity: sha512-AZL67abkUzIuvcHqk7c09cezpGNcxUxU4Ioi/05xHk4DQeTkWmGYftIE6ctU6AEt+Gn4n1lDStOtj7FKycP71A==}
engines: {node: '>=8'}
dependencies:
cssom: 0.3.8
dev: false
/data-urls/3.0.2:
resolution: {integrity: sha512-Jy/tj3ldjZJo63sVAvg6LHt2mHvl4V6AgRAmNDtLdm7faqtsx+aJG42rsyCo9JCoRVKwPFzKlIPx3DIibwSIaQ==}
engines: {node: '>=12'}
dependencies:
abab: 2.0.6
whatwg-mimetype: 3.0.0
whatwg-url: 11.0.0
dev: false
/debug/4.3.4:
resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==}
engines: {node: '>=6.0'}
@ -614,16 +721,23 @@ packages:
dependencies:
ms: 2.1.2
/decimal.js/10.4.3:
resolution: {integrity: sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA==}
dev: false
/decode-named-character-reference/1.0.2:
resolution: {integrity: sha512-O8x12RzrUF8xyVcY0KJowWsmaJxQbmy0/EtnNtHRpsOcT7dFk5W598coHqBVpmWo1oQQfsCqfCmkZN5DJrZVdg==}
dependencies:
character-entities: 2.0.2
dev: false
/deep-is/0.1.4:
resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==}
dev: false
/deepmerge/4.3.0:
resolution: {integrity: sha512-z2wJZXrmeHdvYJp/Ux55wIjqo81G5Bp4c+oELTW+7ar6SogWHajt5a9gO3s3IDaGSAXjDk0vlQKN3rms8ab3og==}
engines: {node: '>=0.10.0'}
dev: true
/define-properties/1.2.0:
resolution: {integrity: sha512-xvqAVKGfT1+UAvPwKTVw/njhdQ8ZhXK4lI0bCIuCMrp2up9nPnaDftrLtmpTazqd1o+UY4zgzU+avtMbDP+ldA==}
@ -633,6 +747,11 @@ packages:
object-keys: 1.1.1
dev: false
/delayed-stream/1.0.0:
resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==}
engines: {node: '>=0.4.0'}
dev: false
/dequal/2.0.3:
resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==}
engines: {node: '>=6'}
@ -652,6 +771,45 @@ packages:
hasBin: true
dev: false
/dom-serializer/2.0.0:
resolution: {integrity: sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==}
dependencies:
domelementtype: 2.3.0
domhandler: 5.0.3
entities: 4.4.0
dev: false
/domelementtype/2.3.0:
resolution: {integrity: sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==}
dev: false
/domexception/4.0.0:
resolution: {integrity: sha512-A2is4PLG+eeSfoTMA95/s4pvAoSo2mKtiM5jlHkAVewmiO8ISFTFKZjH7UAM1Atli/OT/7JHOrJRJiMKUZKYBw==}
engines: {node: '>=12'}
dependencies:
webidl-conversions: 7.0.0
dev: false
/domhandler/5.0.3:
resolution: {integrity: sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==}
engines: {node: '>= 4'}
dependencies:
domelementtype: 2.3.0
dev: false
/domutils/3.0.1:
resolution: {integrity: sha512-z08c1l761iKhDFtfXO04C7kTdPBLi41zwOZl00WS8b5eiaebNpY00HKbztwBq+e3vyqWNwWF3mP9YLUeqIrF+Q==}
dependencies:
dom-serializer: 2.0.0
domelementtype: 2.3.0
domhandler: 5.0.3
dev: false
/entities/4.4.0:
resolution: {integrity: sha512-oYp7156SP8LkeGD0GF85ad1X9Ai79WtRsZ2gxJqtBuzH+98YUV6jkHEKlZkMbcrjJjIVJNIDP/3WL9wQkoPbWA==}
engines: {node: '>=0.12'}
dev: false
/error-stack-parser/1.3.6:
resolution: {integrity: sha512-xhuSYd8wLgOXwNgjcPeXMPL/IiiA1Huck+OPvClpJViVNNlJVtM41o+1emp7bPvlCJwCatFX2DWc05/DgfbWzA==}
dependencies:
@ -691,15 +849,49 @@ packages:
'@esbuild/win32-ia32': 0.16.17
'@esbuild/win32-x64': 0.16.17
/escape-string-regexp/4.0.0:
resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==}
engines: {node: '>=10'}
dev: false
/escape-string-regexp/5.0.0:
resolution: {integrity: sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==}
engines: {node: '>=12'}
dev: false
/escodegen/2.0.0:
resolution: {integrity: sha512-mmHKys/C8BFUGI+MAWNcSYoORYLMdPzjrknd2Vc+bUsjN5bXcr8EhrNB+UTqfL1y3I9c4fw2ihgtMPQLBRiQxw==}
engines: {node: '>=6.0'}
hasBin: true
dependencies:
esprima: 4.0.1
estraverse: 5.3.0
esutils: 2.0.3
optionator: 0.8.3
optionalDependencies:
source-map: 0.6.1
dev: false
/esm-env/1.0.0:
resolution: {integrity: sha512-Cf6VksWPsTuW01vU9Mk/3vRue91Zevka5SjyNf3nEpokFRuqt/KjUQoGAwq9qMmhpLTHmXzSIrFRw8zxWzmFBA==}
dev: true
/esprima/4.0.1:
resolution: {integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==}
engines: {node: '>=4'}
hasBin: true
dev: false
/estraverse/5.3.0:
resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==}
engines: {node: '>=4.0'}
dev: false
/esutils/2.0.3:
resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==}
engines: {node: '>=0.10.0'}
dev: false
/extend/3.0.2:
resolution: {integrity: sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==}
dev: false
@ -715,6 +907,10 @@ packages:
micromatch: 4.0.5
dev: true
/fast-levenshtein/2.0.6:
resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==}
dev: false
/fastq/1.15.0:
resolution: {integrity: sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==}
dependencies:
@ -734,6 +930,15 @@ packages:
is-callable: 1.2.7
dev: false
/form-data/4.0.0:
resolution: {integrity: sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==}
engines: {node: '>= 6'}
dependencies:
asynckit: 0.4.0
combined-stream: 1.0.8
mime-types: 2.1.35
dev: false
/fs-extra/8.1.0:
resolution: {integrity: sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==}
engines: {node: '>=6 <7 || >=8'}
@ -876,6 +1081,50 @@ packages:
resolution: {integrity: sha512-I5GTdSfhYfAPNztx2xJRQpG8cuDSNt599/7YUn7Gx/WxNMsG+a835k97TDkFgk123cwjfwINaZknkKkphx/f2A==}
dev: false
/html-encoding-sniffer/3.0.0:
resolution: {integrity: sha512-oWv4T4yJ52iKrufjnyZPkrN0CH3QnrUqdB6In1g5Fe1mia8GmF36gnfNySxoZtxD5+NmYw1EElVXiBk93UeskA==}
engines: {node: '>=12'}
dependencies:
whatwg-encoding: 2.0.0
dev: false
/htmlparser2/8.0.1:
resolution: {integrity: sha512-4lVbmc1diZC7GUJQtRQ5yBAeUCL1exyMwmForWkRLnwyzWBFxN633SALPMGYaWZvKe9j1pRZJpauvmxENSp/EA==}
dependencies:
domelementtype: 2.3.0
domhandler: 5.0.3
domutils: 3.0.1
entities: 4.4.0
dev: false
/http-proxy-agent/5.0.0:
resolution: {integrity: sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==}
engines: {node: '>= 6'}
dependencies:
'@tootallnate/once': 2.0.0
agent-base: 6.0.2
debug: 4.3.4
transitivePeerDependencies:
- supports-color
dev: false
/https-proxy-agent/5.0.1:
resolution: {integrity: sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==}
engines: {node: '>= 6'}
dependencies:
agent-base: 6.0.2
debug: 4.3.4
transitivePeerDependencies:
- supports-color
dev: false
/iconv-lite/0.6.3:
resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==}
engines: {node: '>=0.10.0'}
dependencies:
safer-buffer: 2.1.2
dev: false
/inherits/2.0.4:
resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==}
dev: false
@ -940,6 +1189,15 @@ packages:
engines: {node: '>=12'}
dev: false
/is-plain-object/5.0.0:
resolution: {integrity: sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==}
engines: {node: '>=0.10.0'}
dev: false
/is-potential-custom-element-name/1.0.1:
resolution: {integrity: sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==}
dev: false
/is-typed-array/1.1.10:
resolution: {integrity: sha512-PJqgEHiWZvMpaFZ3uTc8kHPM4+4ADTlDniuQL7cU/UDA0Ql7F70yGfHph3cLNe+c9toaigv+DFzTJKhc2CtO6A==}
engines: {node: '>= 0.4'}
@ -956,6 +1214,52 @@ packages:
hasBin: true
dev: true
/jsdom/19.0.0:
resolution: {integrity: sha512-RYAyjCbxy/vri/CfnjUWJQQtZ3LKlLnDqj+9XLNnJPgEGeirZs3hllKR20re8LUZ6o1b1X4Jat+Qd26zmP41+A==}
engines: {node: '>=12'}
peerDependencies:
canvas: ^2.5.0
peerDependenciesMeta:
canvas:
optional: true
dependencies:
abab: 2.0.6
acorn: 8.8.2
acorn-globals: 6.0.0
cssom: 0.5.0
cssstyle: 2.3.0
data-urls: 3.0.2
decimal.js: 10.4.3
domexception: 4.0.0
escodegen: 2.0.0
form-data: 4.0.0
html-encoding-sniffer: 3.0.0
http-proxy-agent: 5.0.0
https-proxy-agent: 5.0.1
is-potential-custom-element-name: 1.0.1
nwsapi: 2.2.2
parse5: 6.0.1
saxes: 5.0.1
symbol-tree: 3.2.4
tough-cookie: 4.1.2
w3c-hr-time: 1.0.2
w3c-xmlserializer: 3.0.0
webidl-conversions: 7.0.0
whatwg-encoding: 2.0.0
whatwg-mimetype: 3.0.0
whatwg-url: 10.0.0
ws: 8.12.1
xml-name-validator: 4.0.0
transitivePeerDependencies:
- bufferutil
- supports-color
- utf-8-validate
dev: false
/jsonc-parser/3.2.0:
resolution: {integrity: sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==}
dev: false
/jsonfile/4.0.0:
resolution: {integrity: sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==}
optionalDependencies:
@ -992,6 +1296,14 @@ packages:
resolution: {integrity: sha512-ymToLHqL02udwVdbkowNpzjFd6UzozMtshPQKVi5k1EjKRqKqBrOnE9QbLEb0/pV76SAiIT13hdL8R6suc+f3g==}
dev: true
/levn/0.3.0:
resolution: {integrity: sha512-0OO4y2iOHix2W6ujICbKIaEQXvFQHue65vUG3pb5EUomzPI90z9hsA1VsO/dbIIpC53J8gxM9Q4Oho0jrCM/yA==}
engines: {node: '>= 0.8.0'}
dependencies:
prelude-ls: 1.1.2
type-check: 0.3.2
dev: false
/lodash-es/4.17.21:
resolution: {integrity: sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==}
dev: true
@ -1470,6 +1782,18 @@ packages:
picomatch: 2.3.1
dev: true
/mime-db/1.52.0:
resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==}
engines: {node: '>= 0.6'}
dev: false
/mime-types/2.1.35:
resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==}
engines: {node: '>= 0.6'}
dependencies:
mime-db: 1.52.0
dev: false
/mime/3.0.0:
resolution: {integrity: sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A==}
engines: {node: '>=10.0.0'}
@ -1503,6 +1827,10 @@ packages:
boolbase: 1.0.0
dev: false
/nwsapi/2.2.2:
resolution: {integrity: sha512-90yv+6538zuvUMnN+zCr8LuV6bPFdq50304114vJYJ8RDyK8D5O9Phpbd6SZWgI7PwzmmfN1upeOJlvybDSgCw==}
dev: false
/object-is/1.1.5:
resolution: {integrity: sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw==}
engines: {node: '>= 0.4'}
@ -1521,6 +1849,30 @@ packages:
engines: {node: '>=0.10'}
dev: false
/optionator/0.8.3:
resolution: {integrity: sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==}
engines: {node: '>= 0.8.0'}
dependencies:
deep-is: 0.1.4
fast-levenshtein: 2.0.6
levn: 0.3.0
prelude-ls: 1.1.2
type-check: 0.3.2
word-wrap: 1.2.3
dev: false
/parse-numeric-range/1.3.0:
resolution: {integrity: sha512-twN+njEipszzlMJd4ONUYgSfZPDxgHhT9Ahed5uTigpQn90FggW4SA/AIPq/6a149fTbE9qBEcSwE3FAEp6wQQ==}
dev: false
/parse-srcset/1.0.2:
resolution: {integrity: sha512-/2qh0lav6CmI15FzA3i/2Bzk2zCgQhGMkvhOhKNcBVQ1ldgpbfiNTVslmooUmWJcADi1f1kIeynbDRVzNlfR6Q==}
dev: false
/parse5/6.0.1:
resolution: {integrity: sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==}
dev: false
/path-parse/1.0.7:
resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==}
@ -1540,6 +1892,11 @@ packages:
picocolors: 1.0.0
source-map-js: 1.0.2
/prelude-ls/1.1.2:
resolution: {integrity: sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w==}
engines: {node: '>= 0.8.0'}
dev: false
/prism-svelte/0.4.7:
resolution: {integrity: sha512-yABh19CYbM24V7aS7TuPYRNMqthxwbvx6FF/Rw920YbyBWO3tnyPIqRMgHuSVsLmuHkkBS1Akyof463FVdkeDQ==}
dev: true
@ -1559,6 +1916,19 @@ packages:
xtend: 4.0.2
dev: false
/psl/1.9.0:
resolution: {integrity: sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==}
dev: false
/punycode/2.3.0:
resolution: {integrity: sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==}
engines: {node: '>=6'}
dev: false
/querystringify/2.2.0:
resolution: {integrity: sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==}
dev: false
/queue-microtask/1.2.3:
resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==}
dev: true
@ -1655,6 +2025,10 @@ packages:
engines: {node: '>=0.10.0'}
dev: true
/requires-port/1.0.0:
resolution: {integrity: sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==}
dev: false
/resolve/1.22.1:
resolution: {integrity: sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==}
hasBin: true
@ -1687,10 +2061,41 @@ packages:
dependencies:
mri: 1.2.0
/safer-buffer/2.1.2:
resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==}
dev: false
/sanitize-html/2.10.0:
resolution: {integrity: sha512-JqdovUd81dG4k87vZt6uA6YhDfWkUGruUu/aPmXLxXi45gZExnt9Bnw/qeQU8oGf82vPyaE0vO4aH0PbobB9JQ==}
dependencies:
deepmerge: 4.3.0
escape-string-regexp: 4.0.0
htmlparser2: 8.0.1
is-plain-object: 5.0.0
parse-srcset: 1.0.2
postcss: 8.4.21
dev: false
/saxes/5.0.1:
resolution: {integrity: sha512-5LBh1Tls8c9xgGjw3QrMwETmTMVk0oFgvrFSvWx62llR2hcEInrKNZ2GZCCuuy2lvWrdl5jhbpeqc5hRYKFOcw==}
engines: {node: '>=10'}
dependencies:
xmlchars: 2.2.0
dev: false
/set-cookie-parser/2.5.1:
resolution: {integrity: sha512-1jeBGaKNGdEq4FgIrORu/N570dwoPYio8lSoYLWmX7sQ//0JY08Xh9o5pBcgmHQ/MbsYp/aZnOe1s1lIsbLprQ==}
dev: true
/shiki/0.14.1:
resolution: {integrity: sha512-+Jz4nBkCBe0mEDqo1eKRcCdjRtrCjozmcbTUjbPTX7OOJfEbTZzlUWlZtGe3Gb5oV1/jnojhG//YZc3rs9zSEw==}
dependencies:
ansi-sequence-parser: 1.1.0
jsonc-parser: 3.2.0
vscode-oniguruma: 1.7.0
vscode-textmate: 8.0.0
dev: false
/sirv/2.0.2:
resolution: {integrity: sha512-4Qog6aE29nIjAOKe/wowFTxOdmbEZKb+3tsLljaBRzJwtqto0BChD2zzH0LhgCSXiI+V7X+Y45v14wBZQ1TK3w==}
engines: {node: '>= 10'}
@ -1704,6 +2109,13 @@ packages:
resolution: {integrity: sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==}
engines: {node: '>=0.10.0'}
/source-map/0.6.1:
resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==}
engines: {node: '>=0.10.0'}
requiresBuild: true
dev: false
optional: true
/space-separated-tokens/1.1.5:
resolution: {integrity: sha512-q/JSVd1Lptzhf5bkYm4ob4iWPjx0KiRe3sRFBNrVqbJkFaBm5vbbowy1mymoPNLRa52+oadOhJ+K49wsSeSjTA==}
dev: false
@ -1743,6 +2155,10 @@ packages:
engines: {node: '>= 8'}
dev: true
/symbol-tree/3.2.4:
resolution: {integrity: sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==}
dev: false
/three/0.148.0:
resolution: {integrity: sha512-8uzVV+qhTPi0bOFs/3te3RW6hb3urL8jYEl6irjCWo/l6sr8MPNMcClFev/MMYeIxr0gmDcoXTy/8LXh/LXkfw==}
dev: true
@ -1766,6 +2182,23 @@ packages:
engines: {node: '>=6'}
dev: true
/tough-cookie/4.1.2:
resolution: {integrity: sha512-G9fqXWoYFZgTc2z8Q5zaHy/vJMjm+WV0AkAeHxVCQiEB1b+dGvWzFW6QV07cY5jQ5gRkeid2qIkzkxUnmoQZUQ==}
engines: {node: '>=6'}
dependencies:
psl: 1.9.0
punycode: 2.3.0
universalify: 0.2.0
url-parse: 1.5.10
dev: false
/tr46/3.0.0:
resolution: {integrity: sha512-l7FvfAHlcmulp8kr+flpQZmVwtu7nfRV7NZujtN0OqES8EL4O4e0qqzL0DC5gAvx/ZC/9lk6rhcUwYvkBnBnYA==}
engines: {node: '>=12'}
dependencies:
punycode: 2.3.0
dev: false
/trim-lines/3.0.1:
resolution: {integrity: sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg==}
dev: false
@ -1819,6 +2252,13 @@ packages:
universalify: 0.1.2
dev: false
/type-check/0.3.2:
resolution: {integrity: sha512-ZCmOJdvOWDBYJlzAoFkC+Q0+bUyEOS1ltgp1MGU03fqHG+dbi9tBFU2Rd9QKiDZFAYrhPh2JUf7rZRIuHRKtOg==}
engines: {node: '>= 0.8.0'}
dependencies:
prelude-ls: 1.1.2
dev: false
/undici/5.20.0:
resolution: {integrity: sha512-J3j60dYzuo6Eevbawwp1sdg16k5Tf768bxYK4TUJRH7cBM4kFCbf3mOnM/0E3vQYXvpxITbbWmBafaDbxLDz3g==}
engines: {node: '>=12.18'}
@ -1927,6 +2367,18 @@ packages:
engines: {node: '>= 4.0.0'}
dev: false
/universalify/0.2.0:
resolution: {integrity: sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==}
engines: {node: '>= 4.0.0'}
dev: false
/url-parse/1.5.10:
resolution: {integrity: sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==}
dependencies:
querystringify: 2.2.0
requires-port: 1.0.0
dev: false
/util/0.12.5:
resolution: {integrity: sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA==}
dependencies:
@ -2028,10 +2480,65 @@ packages:
vite: 4.1.4
dev: true
/vscode-oniguruma/1.7.0:
resolution: {integrity: sha512-L9WMGRfrjOhgHSdOYgCt/yRMsXzLDJSL7BPrOZt73gU0iWO4mpqzqQzOz5srxqTvMBaR0XZTSrVWo4j55Rc6cA==}
dev: false
/vscode-textmate/8.0.0:
resolution: {integrity: sha512-AFbieoL7a5LMqcnOF04ji+rpXadgOXnZsxQr//r83kLPr7biP7am3g9zbaZIaBGwBRWeSvoMD4mgPdX3e4NWBg==}
dev: false
/w3c-hr-time/1.0.2:
resolution: {integrity: sha512-z8P5DvDNjKDoFIHK7q8r8lackT6l+jo/Ye3HOle7l9nICP9lf1Ci25fy9vHd0JOWewkIFzXIEig3TdKT7JQ5fQ==}
deprecated: Use your platform's native performance.now() and performance.timeOrigin.
dependencies:
browser-process-hrtime: 1.0.0
dev: false
/w3c-xmlserializer/3.0.0:
resolution: {integrity: sha512-3WFqGEgSXIyGhOmAFtlicJNMjEps8b1MG31NCA0/vOF9+nKMUW1ckhi9cnNHmf88Rzw5V+dwIwsm2C7X8k9aQg==}
engines: {node: '>=12'}
dependencies:
xml-name-validator: 4.0.0
dev: false
/webgl-sdf-generator/1.1.1:
resolution: {integrity: sha512-9Z0JcMTFxeE+b2x1LJTdnaT8rT8aEp7MVxkNwoycNmJWwPdzoXzMh0BjJSh/AEFP+KPYZUli814h8bJZFIZ2jA==}
dev: true
/webidl-conversions/7.0.0:
resolution: {integrity: sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==}
engines: {node: '>=12'}
dev: false
/whatwg-encoding/2.0.0:
resolution: {integrity: sha512-p41ogyeMUrw3jWclHWTQg1k05DSVXPLcVxRTYsXUk+ZooOCZLcoYgPZ/HL/D/N+uQPOtcp1me1WhBEaX02mhWg==}
engines: {node: '>=12'}
dependencies:
iconv-lite: 0.6.3
dev: false
/whatwg-mimetype/3.0.0:
resolution: {integrity: sha512-nt+N2dzIutVRxARx1nghPKGv1xHikU7HKdfafKkLNLindmPU/ch3U31NOCGGA/dmPcmb1VlofO0vnKAcsm0o/Q==}
engines: {node: '>=12'}
dev: false
/whatwg-url/10.0.0:
resolution: {integrity: sha512-CLxxCmdUby142H5FZzn4D8ikO1cmypvXVQktsgosNy4a4BHrDHeciBBGZhb0bNoR5/MltoCatso+vFjjGx8t0w==}
engines: {node: '>=12'}
dependencies:
tr46: 3.0.0
webidl-conversions: 7.0.0
dev: false
/whatwg-url/11.0.0:
resolution: {integrity: sha512-RKT8HExMpoYx4igMiVMY83lN6UeITKJlBQ+vR/8ZJ8OCdSiN3RwCq+9gH0+Xzj0+5IrM6i4j/6LuvzbZIQgEcQ==}
engines: {node: '>=12'}
dependencies:
tr46: 3.0.0
webidl-conversions: 7.0.0
dev: false
/which-typed-array/1.1.9:
resolution: {integrity: sha512-w9c4xkx6mPidwp7180ckYWfMmvxpjlZuIudNtDf4N/tTAUB8VJbX25qZoAsrtGuYNnGw3pa0AXgbGKRB8/EceA==}
engines: {node: '>= 0.4'}
@ -2050,6 +2557,33 @@ packages:
hasBin: true
dev: true
/word-wrap/1.2.3:
resolution: {integrity: sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==}
engines: {node: '>=0.10.0'}
dev: false
/ws/8.12.1:
resolution: {integrity: sha512-1qo+M9Ba+xNhPB+YTWUlK6M17brTut5EXbcBaMRN5pH5dFrXz7lzz1ChFSUq3bOUl8yEvSenhHmYUNJxFzdJew==}
engines: {node: '>=10.0.0'}
peerDependencies:
bufferutil: ^4.0.1
utf-8-validate: '>=5.0.2'
peerDependenciesMeta:
bufferutil:
optional: true
utf-8-validate:
optional: true
dev: false
/xml-name-validator/4.0.0:
resolution: {integrity: sha512-ICP2e+jsHvAj2E2lIHxa5tjXRlKDJo4IdvPvCXbXQGdzSfmSpNVyIKMvoZHjDY9DP0zV17iI85o90vRFXNccRw==}
engines: {node: '>=12'}
dev: false
/xmlchars/2.2.0:
resolution: {integrity: sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==}
dev: false
/xtend/4.0.2:
resolution: {integrity: sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==}
engines: {node: '>=0.4'}

42
remark/code.js Normal file
View file

@ -0,0 +1,42 @@
import { createRemarkPlugin } from "@atomiks/mdx-pretty-code";
import fs from "fs";
export const prettyCode = createRemarkPlugin({
// Options passed to shiki.getHighlighter()
shikiOptions: {
// Link to your VS Code theme JSON file
theme: JSON.parse(
fs.readFileSync("./shiki/themes/OneDark.json", "utf-8")
),
},
// These are hooks which allow you to style the node. `node` is an element
// using JSDOM, so you can apply any CSS.
onVisitLine(node) {
// Style a line node.
node.innerHTML = node.innerHTML
.replace(/{/g, "&#123;")
.replace(/}/g, "&#125;");
// console.log(node.innerHTML);
// console.log(node.innerHTML
// .replace(/{/g, "&#123;")
// .replace(/}/g, "&#125;"));
Object.assign(node.style, {
margin: "0 -1.5rem",
padding: "0 1.5rem",
});
},
onVisitHighlightedLine(node) {
// Style a highlighted line node.
Object.assign(node.style, {
backgroundColor: "rgba(0,0,0,0.1)",
});
},
onVisitHighlightedWord(node) {
// Style a highlighted word node.
Object.assign(node.style, {
backgroundColor: "rgba(0,0,0,0.5)",
padding: "0.25rem",
borderRadius: "0.25rem",
});
},
});

View file

@ -0,0 +1,67 @@
import { visit } from "unist-util-visit"
export function remarkUnescapeHighlight() {
return (tree, file) => {
console.log(1, file.filename, tree);
visit(tree, ["code"], (node) => {
node.value = node.value
.replace(/&#123;/g, "{")
.replace(/&#125;/g, "}")
.replace(/&gt;/g, ">")
.replace(/&lt;/g, "<")
});
visit(tree, ["inlineCode"], (node) => {
node.value = node.value
.replace(/&#123;/g, "{")
.replace(/&#125;/g, "}")
.replace(/&gt;/g, ">")
.replace(/&lt;/g, "<")
});
}
}
export function remarkEscapeInlineCode() {
return (tree, file) => {
console.log(2, file.filename, tree);
visit(tree, ["inlineCode"], (node) => {
node.value = node.value
.replace(/{/g, "&#123;")
.replace(/}/g, "&#125;")
.replace(/>/g, "&gt;")
.replace(/</g, "&lt;")
});
}
}
export function rehypeEscapeHighlight() {
function visit(node) {
if(
(node.type === "raw" && node.value.startsWith("<pre><code")) ||
(node.type === "element" && node.tagName === "Components.code") ||
(node.type === "raw" && node.value.startsWith("<span data-mdx-pretty-code"))) {
if(node.value) {
node.value = node.value
.replace(/{/g, "&#123;")
.replace(/}/g, "&#125;")
} else {
node.children.forEach((child) => {
if(child.value) {
child.value = child.value
.replace(/{/g, "&#123;")
.replace(/}/g, "&#125;")
}
})
}
} else if(node.children) node.children.forEach(visit)
if (node.type === "raw") {
node.value = node.value
.replace(/<span style="color:#ABB2BF"> <\/span>/g , " ");
}
}
return (tree, file) => {
console.log(3, file.filename, tree);
visit(tree);
}
}

File diff suppressed because one or more lines are too long

View file

@ -5,7 +5,6 @@
<script data-goatcounter="https://danbulant.goatcounter.com/count" async src="//gc.zgo.at/count.js"></script>
<link rel="icon" href="%sveltekit.assets%/favicon.png" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="stylesheet" href="%sveltekit.assets%/prism/dark.css" />
<link rel="stylesheet" href="%sveltekit.assets%/global.css" />
%sveltekit.head%
</head>

46
src/lib/color.ts Normal file
View file

@ -0,0 +1,46 @@
/**
* Calculate brightness value by RGB or HEX color.
* @param color (String) The color value in RGB or HEX (for example: #000000 || #000 || rgb(0,0,0) || rgba(0,0,0,0))
* @returns (Number) The brightness value (dark) 0 ... 1 (light)
*/
export function brightnessByColor(color: string | number[]) {
const [r, g, b] = parseColor(color);
// @ts-ignore
if (typeof r != "undefined") return (r * 299 + g * 587 + b * 114) / 1000 / 255;
}
export function hexToRgb(color: string) {
const hasFullSpec = color.length == 7;
var m = color.substr(1).match(hasFullSpec ? /(\S{2})/g : /(\S{1})/g);
const r = parseInt(m[0] + (hasFullSpec ? "" : m[0]), 16);
const g = parseInt(m[1] + (hasFullSpec ? "" : m[1]), 16);
const b = parseInt(m[2] + (hasFullSpec ? "" : m[2]), 16);
const a = hasFullSpec && m[3] ? parseInt(m[3], 16) : 1;
return [r, g, b, a];
}
export function parseRgb(color: string) {
const hasAlpha = color.indexOf("rgba") == 0;
var m = color.match(/(\d+){3}(\.\d+)?/g);
const r = parseInt(m[0]);
const g = parseInt(m[1]);
const b = parseInt(m[2]);
const a = hasAlpha ? parseFloat(m[3]) : 1;
return [r, g, b, a];
}
export function parseColor(color: string | number[]) {
if (typeof color == "object") return color;
if (color.indexOf("#") == 0) return hexToRgb(color);
if (color.indexOf("rgb") == 0) return parseRgb(color);
return [0, 0, 0, 0];
}
export function mix(color: string, another: string) {
var base = parseColor(color);
var added = parseColor(another);
var mix = [];
mix[3] = 1 - (1 - added[3]) * (1 - base[3]); // alpha
mix[0] = Math.round((added[0] * added[3] / mix[3]) + (base[0] * base[3] * (1 - added[3]) / mix[3])); // red
mix[1] = Math.round((added[1] * added[3] / mix[3]) + (base[1] * base[3] * (1 - added[3]) / mix[3])); // green
mix[2] = Math.round((added[2] * added[3] / mix[3]) + (base[2] * base[3] * (1 - added[3]) / mix[3])); // blue
return mix;
}

View file

@ -3,21 +3,22 @@
export var href = "";
export var text = false;
export var blur = false;
let className;
export { className as class };
</script>
{#if href}
<a href={href} tabindex="0" class="button {className}" class:text class:dark={$darkmode}><slot /></a>
<a href={href} class:blur tabindex="0" class="button {className}" class:text class:dark={$darkmode}><slot /></a>
{:else}
<button class="button {className}" on:click class:text class:dark={$darkmode}><slot /></button>
<button class="button {className}" class:blur on:click class:text class:dark={$darkmode}><slot /></button>
{/if}
<style>
.button {
@apply backdrop-blur bg-black/50 rounded;
@apply bg-black/50 rounded;
padding: 10px 15px;
color: white;
cursor: pointer;
@ -25,6 +26,9 @@
border: 1px solid transparent;
transition: border-color .2s;
}
.blur {
@apply backdrop-blur;
}
.text {
background: transparent;

View file

@ -1,11 +1,59 @@
<script>
export var href;
export var title;
$: domain = new URL(href, typeof window !== "undefined" && window.location || "https://danbulant.eu").hostname;
let blacklist = [
"localhost",
"danbulant.eu",
"danbulant.cloud",
typeof window !== "undefined" && window.location.hostname
];
let newtitle = "";
let options = new Map;
$: defaultfavicon = `https://filthy-cyan-otter.faviconkit.com/${domain}/32`;
let favicon = defaultfavicon;
$: {
// extract key=value options from title
if(title && title.includes("=")) {
let titleparts = title.split("=");
for (let i = 0; i < titleparts.length; i+=2) {
options.set(titleparts[i], titleparts[i+1]);
}
newtitle = options.get("title") || "";
favicon = options.get("favicon") || defaultfavicon;
console.log(options);
} else {
newtitle = title;
favicon = defaultfavicon;
}
}
</script>
<a {href}><slot /></a>
<!-- svelte-ignore a11y-missing-attribute -->
<a {...$$props} title={newtitle}>
{#if !blacklist.includes(domain) && favicon}
<img src="{favicon}" width=32 height=32 alt="">
{/if}
<span>
<slot />
</span>
</a>
<style>
img {
height: 1em;
width: 1em;
display: inline;
}
a {
color: aqua;
text-decoration: none;
}
span {
text-decoration: underline;
}
</style>

View file

@ -1,15 +1,62 @@
<script>
import darkmode from "$lib/stores/darkmode";
import { brightnessByColor, mix } from "../../color";
export var color;
export var closed = false;
export var closable = closed;
export var minimal = false;
function toggle() {
if (closable) {
closed = !closed;
}
}
let brightness = 0;
$: brightness = brightnessByColor(mix(color, $darkmode ? "#000" : "#fff", 0.5));
$: console.log(brightness, color);
let isDark = false;
$: isDark = brightness < 0.5;
</script>
<!-- A simple callout with header and slot body. Header background colored according to color, and the whole callout has a left border colored as well. -->
<div class="w-full rounded border-l border-l-4 my-2" style="border-left-color: {color}">
<div class="rounded-tr-lg p-4" style="background-color: {color}40">
<h1 class="text-big text-white p-0 m-0">
<div class:minimal class:closed class:closable class="w-full rounded border-l border-l-4 my-6 color-shadow" style:border-left-color={color} style:--shadow-color="{color}0D">
<div on:click={toggle} on:keydown={toggle} class="header rounded-tr-lg" style:background-color="{color}40" class:dark-bg={isDark}>
<h1 class="text-big p-0 m-0">
<slot name="title"/>
</h1>
</div>
<div class="rounded-br-lg p-4 bg-gray-500/10">
<div class="content rounded-br-lg p-4 backdrop-blur -mt-1 pt-5">
<slot />
</div>
</div>
</div>
<style>
.color-shadow {
box-shadow: 0 0 1rem 0.25rem var(--shadow-color), -4px 0 1rem 0.25rem var(--shadow-color);
}
.closed .content {
@apply hidden;
}
.closable .header {
@apply cursor-pointer select-none;
}
.closed .header {
@apply rounded-br-lg;
}
.minimal .header {
@apply p-0.5 pl-4;
}
.header {
@apply text-black p-4;
}
.header.dark-bg {
@apply text-white;
}
.dark .content {
@apply bg-dark-300/40;
}
</style>

View file

@ -0,0 +1,8 @@
<script>
</script>
{#if $$props["data-mdx-pretty-code"]}
<code data-theme={$$props["data-theme"]} style:color={$$props["data-color"]}><slot /></code>
{:else}
<code {...$$props}><slot /></code>
{/if}

View file

@ -1,44 +1,29 @@
<script>
import darkmode from "$lib/stores/darkmode";
import Callout from "./callout.svelte";
export var title = "Result";
export var nopadding = false;
$: color = $darkmode ? "#000000" : "#AAAAAA";
</script>
<div class="outer" class:dark={$darkmode}>
{#if title || $$slots.title}
<div class="title">
<Callout {color}>
<div slot="title">
{#if title || $$slots.title}
<slot name="title" />
{title}
</div>
{/if}
{/if}
</div>
<div class="inner" class:nopadding>
<slot />
</div>
</div>
</Callout>
<style>
.outer {
border: 1px solid black;
border-radius: 5px;
transition: .3s border-color;
}
.outer.dark {
border-color: white;
}
.inner {
padding: 10px;
@apply p-2;
}
.inner.nopadding {
padding: 0;
}
.title {
width: calc(100% - 20px);
padding: 10px 10px 0;
height: 35px;
font-size: 18px;
background-color: rgb(218, 218, 218);
}
.dark .title {
background-color: rgb(49, 49, 49);
}
</style>

View file

@ -0,0 +1,8 @@
<script>
</script>
{#if $$props["data-mdx-pretty-code"]}
<code data-theme={$$props["data-theme"]} style:color={$$props["data-color"]}><slot /></code>
{:else}
<span {...$$props}><slot /></span>
{/if}

View file

@ -1,3 +1,10 @@
<script context="module">
import span from "../components/posts/span.svelte";
import code from "../components/posts/code.svelte";
import a from "../components/posts/a.svelte";
export { span, code, a };
</script>
<script>
import darkmode from "$lib/stores/darkmode";
import { DateTime } from "luxon";
@ -69,8 +76,12 @@
color: rgb(2, 218, 218);
}
:global(body .post-layout table) {
@apply rounded;
border-spacing: 0;
}
:global(body .post-layout table thead, body .post-layout table thead tr) {
@apply rounded;
}
:global(body .post-layout table thead tr th:first-child) {
border-top-left-radius: 5px;
}
@ -139,7 +150,13 @@
@apply inline;
}
:global(body .post-layout pre) {
@apply rounded-lg bg-dark-400;
@apply rounded-lg bg-dark-400 p-4 my-4 max-w-full overflow-auto;
}
:global(.dark .post-layout code) {
@apply rounded-lg bg-dark-400 p-1;
}
:global(body .post-layout code) {
@apply rounded-lg bg-dark-400/03 p-1 transition-colors duration-300;
}
:global(body .post-layout ul) {
@apply list-disc list-inside;

View file

@ -70,7 +70,7 @@ Has a policy that egress shouldn't be higher than the stored amount. Consider us
| Class B ops | 2500/day | $4 / 10 million |
| Class C ops | 2500/day | $4 / 1 million |
Free egress when using one of the '[Bandwidth alliance](https://www.cloudflare.com/bandwidth-alliance/)' services - for example when using free Cloudflare proxy (which is free even for small businesses, unless you're moving tens/hundreds of terabytes of data each day).
Free egress when using one of the `[Bandwidth alliance](https://www.cloudflare.com/bandwidth-alliance/)' services - for example when using free Cloudflare proxy (which is free even for small businesses, unless you're moving tens/hundreds of terabytes of data each day).
<details>
<summary>Details</summary>
@ -88,7 +88,7 @@ Free egress when using one of the '[Bandwidth alliance](https://www.cloudflare.c
Copy, Create bucket, CORS bucket management, bucket information, listing.
</details>
[Home page](https://backblaze.com) | [Pricing page](https://www.backblaze.com/b2/cloud-storage-pricing.html)
[Home page](https://backblaze.com "favicon=https://backblaze.com/favicon.ico") | [Pricing page](https://www.backblaze.com/b2/cloud-storage-pricing.html "favicon=https://backblaze.com/favicon.ico")
## DigitalOcean Spaces

View file

@ -10,6 +10,8 @@ description: Rust is a fast memory-safe low level programming language. And here
---
<script>
import Callout from "$lib/components/posts/callout.svelte";
var story = true;
</script>
@ -19,7 +21,7 @@ description: Rust is a fast memory-safe low level programming language. And here
<input type="checkbox" style="padding: 0; margin: 0;" bind:checked={story} id="enable_story">
</div>
> I really do enjoy reading blog posts like these, so I figured I'd try writing few of my own as well. I hope you'll enjoy it, if so, leave a comment below. I don't have any analytics except for basic limited access logs, where I don't even store the IP address.
> I really do enjoy reading blog posts like these, so I figured I'd try writing few of my own as well. I hope you'll enjoy it, if so, leave a comment below.
{#if story}
I first started programming with PHP. Some of it's syntax felt clunky and unnatural, sometimes plainly annoying (why do I have to prefix each variable with `$` when it understands constants without `$` just fine?). I don't really like the language now after learning other languages, but I do like some parts of it, like how it's easy to loop over an array or that it has multiple programming paradigms, from functional to OOP to traits (which I learnt about much later after I stopped using PHP).
@ -52,7 +54,7 @@ description: Rust is a fast memory-safe low level programming language. And here
Here's a list of resources I found useful:
- [rust book](https://doc.rust-lang.org/book/) - an online book with short chapters about common things people want to do with Rust
- [A gentle intro to Rust](https://stevedonovan.github.io/rust-gentle-intro/) - A short ``book'' that can be read in an hour or two, with a day or two worth of examples if you try them locally. Much more in-depth than this post, but still easy to grasp.
- [A gentle intro to Rust](https://stevedonovan.github.io/rust-gentle-intro/ "favicon=https://stevedonovan.github.io/rust-gentle-intro/favicon.png") - A short ``book'' that can be read in an hour or two, with a day or two worth of examples if you try them locally. Much more in-depth than this post, but still easy to grasp.
- [r/rust](https://reddit.com/r/rust) - The well-moderated reddit community (quick to search. If you have a problem that will take longer than a single Discord message, post it here so that others are able to find it as well).
- [The discord community](https://discord.gg/rust) - A simple way to quickly ask other developers
- [rust by example](https://doc.rust-lang.org/rust-by-example/index.html) - The sort of thing I'd be going about in here as well, but this is just a quick short intro, that should be your go-to book if you want to learn even more.
@ -70,51 +72,53 @@ Also, I recommend using CLion with the Rust extension. VSCode does have Rust ext
#### Everything is scoped
Not just variables, but you can also nest functions and `use`s inside functions and traits. Those won't be accessible outside, and won't be in the code if they're not used. *I think*.
Not just variables, but you can also nest functions and `use{:rust}`s inside functions and traits. Those won't be accessible outside, and won't be in the code if they're not used. *Usually*.
#### Naming scheme is enforced
Variables and functions/methods need to be only lowercase letters (and numbers, but cannot start with one) with underscore (i.e. snake_case).
Structs (and other types), enums (including enum values) and traits (but not their functions/methods) need to start with uppercase letters and cannot contain any underscore.
It's not forcibly enforced everywhere - the program will usually run, but you'll get a warning, and you generally want to avoid those (warnings are there for a reason).
#### There's no increment operator
Actually, there is: `i += 1`. Use that. In the same way as assignment, this also returns the value post-assignment (i.e. sets i to i + 1, and then returns i).
Actually, there is: `i += 1{:rust}`. Use that. In the same way as assignment, this also returns the value post-assignment (i.e. sets i to i + 1, and then returns i).
The reason for not having fancy `i++` (or it's siblings `++i`, `i--` and `--i`) is that it's confusing.
The reason for not having fancy `i++{:js}` (or it's siblings `++i{:js}`, `i--{:js}` and `--i{:js}`) is that it's confusing.
Can you reliably tell what this does (especially when language is not specified)?
```c
```js
a[i++ + ++i] = i++ + ++i + a[++i]
```
The thing is, until recently (or maybe even now? I just read that on SO), the actual behaviour of this was undefined, meaning it could change between different compilers (or maybe even versions of the same compiler).
To combat that and improve readability of code (that's a big thing in Rust, often values readability and verbosity over saving keytypes), Rust only has `i += 1`, which nearly everyone can tell will increment the variable `i` and return it's final statement.
So you don't have to know that `i++` actually returns the original value, not the new one, and increments.
To combat that and improve readability of code (that's a big thing in Rust, often values readability and verbosity over saving keytypes), Rust only has `i += 1{:rust}`, which nearly everyone can tell will increment the variable `i` and return it's final statement.
So you don't have to know that `i++{:js}` actually returns the original value, not the new one, and increments.
Oh and also, operator overloads are a thing using traits (for those wondering if they exist, one of the things I miss with JS). We won't get to that here though.
#### Nearly everything is an expression
Not just function calls, but [`if`](#ifs)s, [`while`](#while)s, [`match`](#match)s and [`for`](#for)s as well.
Not just function calls, but [`if{:rust}`](#ifs)s, [`while{:rust}`](#while)s, [`match{:rust}`](#match)s and [`for{:rust}`](#for)s as well.
Instead of the usual ternary operator common in other languages, you can just use [`if`](#ifs) directly:
Instead of the usual ternary operator common in other languages, you can just use [`if{:rust}`](#ifs) directly:
```rust
let var = if something { 1 } else { 2 };
```
Loops (`loop`) return based on `break` call. You can use that to retry an operation until it succeeds.
Loops (`loop{:rust}`) return based on `break{:rust}` call. You can use that to retry an operation until it succeeds.
### Variables
Variables are declared using `let` and are scoped. Type is optional, Rust is exceptional at infering the type (much better so than Typescript).
Variables are declared using `let{:rust}` and are scoped. Type is optional, Rust is exceptional at infering the type (it's much better at it than Typescript).
```rust
let var: usize = 1;
```
Will define `var` of type `usize` (`usize` is a 32 or 64 bit number, depending on architecture).
Will define `var{:rust}` of type `usize{:rust}` (`usize{:rust}` is an unsigned integer with 32 or 64 bits, depending on architecture).
You can redeclare variables, in which case the previous variable will be dropped (unless referenced, in which case there'd be only the reference and not the original variable available), and the type of the variable will be changed.
@ -123,11 +127,12 @@ let var = 1;
let var = "something";
```
Variables are immutable by default. If you want to change them later, use the `mut` keyword after `let`.
Variables are immutable by default. If you want to change them later, use the `mut{:rust}` keyword after `let{:rust}`.
```rust
let var = 1;
var = 2; // error! cannot borrow variable muttable (i.e. immutable variable cannot be mutated)
var = 2; // error! cannot borrow variable muttable
// (i.e. immutable variable cannot be mutated)
```
```rust
@ -146,9 +151,9 @@ fn main(arg: u8) -> u8 {
Functions behave nearly identical to how I'm used to when working in JS, just that they're not actual data types (you can use lambdas for that) and have slightly different syntax.
Arguments work Similarly to Typescript, in that it's `key: type`. Returns type is specified with `->`.
Arguments work Similarly to Typescript, in that it's `key: type{:rust}`. Returns type is specified with `->`.
What's interesting to note is that although Rust requires semicolons, if you don't put a semicolon for the last expression, it will be used as return (even without the `return` keyword).
What's interesting to note is that although Rust requires semicolons, if you don't put a semicolon for the last expression, it will be used as return (even without the `return{:rust}` keyword).
### Ifs
@ -163,7 +168,7 @@ if something {
```
Ifs are pretty basic, I don't think there's that much to explain.
One interesting thing is that using parentheses when they're not needed is actually na error. You can still use them for explicit execution order:
One interesting thing is that using parentheses when they're not needed is actually an error. You can still use them for explicit execution order:
```rust
if (something || something_else) && something_other {}
@ -177,6 +182,14 @@ let var = if something { 1 } else { 2 };
The curly braces are required.
You can combine this (stating the obvious):
```rust
fn fun(arg: bool) -> u8 {
if arg { 1 } else { 0 }
}
```
### Types
Types are either primitives (like numbers and str) or structs (String).
@ -195,52 +208,54 @@ Stack:
- faster
- smaller
Primitives and basic [`struct`](#declaring-structs)s are stored on the stack. To get values onto heap, you can use [`Box<T>`](#boxlttgt). [`Vec<T>`](#veclttgt) also puts it's values onto heap.
Primitives and basic [`struct{:rust}`](#declaring-structs)s are stored on the stack. To get values onto heap, you can use [`Box<T>{:rust}`](#boxlttgt). [`Vec<T>{:rust}`](#veclttgt) also puts it's values onto heap.
You may need to use heap if you're using a bit more RAM or if you need to use [`enum`](#enums)s with values in structs.
If you see a stackoverflow, you're using too much stack memory. Try [`box`](#boxlttgt)ing some bigger (and perhaps rarely used) values.
You may need to use heap if you're using a bit more RAM or if you need to use [`enum{:rust}`](#enums)s with values in structs (basically, if rust complains that a size is unknown at compile time, easiest option is to somehow put it onto heap).
If you see a stackoverflow, you're using too much stack memory. Try [`box{:rust}`](#boxlttgt)ing some bigger (and perhaps rarely used) values. Note that while heap is slower, it's still plenty fast (as for example almost all JS values are stored on heap, it will always be faster with rust).
#### Common primitives
Numbers:
- `i8`, `i16`, `i32`, `i64`, `i128` - signed **i**ntegers. Whole numbers, including negative one's. The number indicates it's size in bits.
- `u8`, `u16`, `u32`, `u64`, `u128` - **u**nsigned integers. Whole numbers, starting with zero. Their maximum capacity is doubled, as there's one extra bit available (normally used for sign). The number indicates it's size in bits.
- `f32` and `f64` are for floats. This is what `number` is in the javascript world.
- `i8{:rust}`, `i16{:rust}`, `i32{:rust}`, `i64{:rust}`, `i128{:rust}` - signed **i**ntegers. Whole numbers, including negative one's. The number indicates it's size in bits.
- `u8{:rust}`, `u16{:rust}`, `u32{:rust}`, `u64{:rust}`, `u128{:rust}` - **u**nsigned integers. Whole numbers, starting with zero. Their maximum capacity is doubled, as there's one extra bit available (normally used for sign). The number indicates it's size in bits.
- `f32{:rust}` and `f64{:rust}` are for floats. This is what `number{:.entity.name.class}` is in the javascript world.
Strings:
- `str` - a simple primitive UTF-8 string (all Rust strings are UTF-8. Invalid UTF-8 strings cannot be used and will throw/panic). Usually used as a pointer (i.e. `&str`)
- `String` - a more complex type (technically not a primitive), stored on the heap.
- `str{:rust}` - a simple primitive UTF-8 string (all Rust strings are UTF-8. Invalid UTF-8 strings cannot be used and will throw/panic). Usually used as a pointer (i.e. `&str{:rust}`)
- `String{:rust}` - a more complex type (technically not a primitive), stored on the heap.
Main difference is that you can manipulate `String{:rust}`s but not `str{:rust}`s.
Arrays:
- `T[]` - arrays have a fixed length (they can have fewer elements if you use `Option<T>` type).
- `T[]{:rust}` - arrays have a fixed length (they can have fewer elements if you use `Option<T>{:rust}` type).
#### Tuples
Tuples can be used to have multiple values with different types (basically an array with multiple types and fixed size).
Unlike array, they're accesssed directly by the dot notation, i.e. `tuple.0` will get the first item, and tuples don't have methods like `.len()`.
Unlike array, they're accesssed directly by the dot notation, i.e. `tuple.0{:rust}` will get the first item, and tuples don't have methods like `.len(){:rust}`.
```rust
let var = (1, "str");
```
An interesting quirk is that you can use `()` (empty tuple) to return "void". Functions that don't have a `return` statement and don't return a value return `()`.
An interesting quirk is that you can use `(){:rust}` (empty tuple) to return "void". Functions that don't have a `return{:rust}` statement and don't return a value return `(){:rust}`.
#### Common structs
##### Option&amp;lt;T&amp;gt;
Is an enum (we'll get to how `enum`s work later. They're kind of different from other languages) with either **`Some(T)` or `None`** values.
To get the value, you can use **[`match`](#match)** like with other enums, or use **`.unwrap()`** (which will panic if it's `None`).
Is an enum (we'll get to how `enum{:rust}`s work later. They're kind of different from other languages) with either **`Some(T){:rust}` or `None{:rust}`** values.
To get the value, you can use **[`match{:rust}`](#match)** like with other enums, or use **`.unwrap(){:rust}`** (which will panic if it's `None{:rust}`).
See also [Declaring enums](#declaring-enums).
##### Result&amp;lt;T, E&amp;gt;
Similar to `Option`, but used to handle errors (commonly returned by <abbr title="Input Output">IO</abbr> methods).
It's values are either `Ok(T)` or `Err(E)`.
To get the value, you can again use **[`match`](#match) block or `.unwrap()`**.
Similar to `Option{:rust}`, but used to handle errors (commonly returned by <abbr title="Input Output">IO</abbr> methods).
It's values are either `Ok(T){:rust}` or `Err(E){:rust}`.
To get the value, you can again use **[`match{:rust}`](#match) block or `.unwrap(){:rust}`**.
For easier use, when a function returns `Result<T, E>`, it can use `?` after calling methods that can return `Result<T, E>` (where `E` must be of compatible type) to return the error `E` (similar to using `.unwrap()`, but instead of panic makes the function return the error).
For easier use, when a function returns `Result<T, E>{:rust}`, it can use `?` after calling methods that can return `Result<T, E>{:rust}` (where `E{:rust}` must be of compatible type) to return the error `E{:rust}` (similar to using `.unwrap(){:rust}`, but instead of panic makes the function return the error, in a sort of bubbling manner similar to other programming languages).
```rust
fn example() -> Result<(), Error> { // An Error type. For simplicity, you can use String, or you can define your own enum.
@ -249,11 +264,17 @@ fn example() -> Result<(), Error> { // An Error type. For simplicity, you can us
}
```
If a function can error out, use `Result{:rust}` instead of `panic{:rust}`s - `panic{:rust}` cannot be easily handled and should only be used for catastrophic irrecoverable errors (or when your too lazy to implement proper error handling using `Result{:rust}` for pet projects).
##### Vec&amp;lt;T&amp;gt;
`Vec`tors are growable arrays stored on the heap.
`Vec{:rust}`tors are growable arrays whose values are stored on the heap.
Common methods like `.push()`, `.pop()` etc. are available. See [rust doc](https://doc.rust-lang.org/std/vec/struct.Vec.html).
Common methods like `.push(){:rust}`, `.pop(){:rust}` etc. are available. See [rust doc](https://doc.rust-lang.org/std/vec/struct.Vec.html).
Javascript arrays behave sort of like `Vec{:rust}` - they have a set limit, and when you reach the limit, it grows (usually doubles the size) the array. The growing usually works by reserving new memory for the array size, copying all elements, and then `free{:rust}`ing the old memory (or `drop{:rust}` in rust terms).
`Vec` stores it's current size, it's reserved size, and an array of pointers to `Box{:rust}`ed values. Meaning, there's no need (and in fact hurts performance) to do `Vec<Box<T>>{:rust}`.
##### Box&amp;lt;T&amp;gt;
@ -287,7 +308,7 @@ struct Something {
struct Something = u8; // a single value
```
As stated earlier, `struct` **sizes are static**. This means you cannot use [`enum`s](#enums) with self-referencing (recursive) values directly in `structs`.
As stated earlier, `struct` **sizes are static**. This means you cannot use [`enum{:rust}`s](#enums) with self-referencing (recursive) values directly in `struct{:rust}`s.
One of possible ``workarounds'' is to use the [heap](#heap-vs-stack) for actually storing the values, for example by using [Box&amp;lt;T&amp;gt;](#boxlttgt).
```rust
@ -296,7 +317,7 @@ struct Something {
}
```
Possible reason for this is when you try to create an `enum` whose value can be the struct defined, but then mention the `enum` (directly or indirectly) in the struct.
Possible reason for this is when you try to create an `enum{:rust}` whose value can be the struct defined, but then mention the `enum{:rust}` (directly or indirectly) in the struct.
```rust
struct MaybeRecursive {
@ -347,21 +368,22 @@ enum EnumName {
}
```
You can ``extract'' the values using [`match`](#match).
You can "extract" the values using [`match{:rust}`](#match).
### Match
*one of the most powerful features of Rust*
Matches are switches on steroids. You can use them as normal switches, with the only exception that (to prevent common bugs), all cases must be covered.
Matches are switches on steroids. You can use them as normal switches, with the only exception that (to prevent common bugs) all cases must be covered.
```rust
let var = 1;
match var {
1 => println!("it's 1"),
2 => println!("it's 2"),
// following required if the list is not exhaustive
// following required if the list is not exhaustive.
// - from type inference `var` will be u8 which has a tad more values
_ => println!("it's not 1 or 2")
}
```
@ -371,11 +393,12 @@ You can also match ranges
```rust
match var {
1..=2 => println("it's between 1 and 2 (both inclusive)"),
3..5 => println!("it's between 3 and 4 (inclusive; .. means up to the value on right)"),
_ => println!("it's something else")
}
```
You can also do nothing
You can also do nothing (brackets are also used for multiline code in `match{:rust}`)
```rust
match var {
@ -383,7 +406,7 @@ match var {
}
```
You can use this to safely `unwrap` [`Result<T, E>`](#resultltt-egt)s and [`Option<T>`](#optionlttgt)s, and to get values from other enums
You can use this to safely `unwrap{:rust}` [`Result<T, E>{:rust}`](#resultltt-egt)s and [`Option<T>{:rust}`](#optionlttgt)s, and to get values from other enums
```rust
let option: Option<u8> = Some(1);
@ -394,7 +417,7 @@ match option {
}
```
Rust will complain if you don't use `i` (or the other values). You can simply use `_` in their place.
Rust will complain if you don't use `i{:rust}` (or the other values). You can simply use `_{:rust}` in their place.
```rust
match option {
@ -414,12 +437,12 @@ let surely = match option {
println!("{surely}");
```
Although, maybe try looking into the documentation for [`Option`](https://doc.rust-lang.org/std/option/) (or view your IDEs completions for available traits/methods).
You might notice that you can use `.unwrap_or(val)` instead of typing this (the above match is identical to `.unwrap_or(0)`).
Although, maybe try looking into the documentation for [`Option{:rust}`](https://doc.rust-lang.org/std/option/) (or view your IDEs completions for available traits/methods) -
you might notice that you can use `.unwrap_or(val){:rust}` instead of typing this (the above match is identical to `.unwrap_or(0){:rust}`).
### Loops
The simplest of all the loops. Just use `loop`.
The simplest of all the loops. Just use `loop{:rust}`.
```rust
loop {
@ -427,11 +450,11 @@ loop {
}
```
It will run the code until `break` is used (or `return` which also returns from the parent function).
It will run the code until `break{:rust}` is used (or `return{:rust}` which also returns from the parent function).
### For
The fanciest of the loops. There's no classic `for` loop like in other languages, but it's so easy to write something like that, yet easier to understand.
The fanciest of the loops. There's no classic `for{:rust}` loop like in other languages (you can do it yourself with `while{:rust}`), but it's so easy to write something like that, yet easier to understand.
```rust
for i in 1..3 {} // for(let i = 1; i < 3; i++) // i++ is not a thing, see things to note
@ -440,13 +463,13 @@ for i in 1..=var {} // for(let i = 1; i <= var; i++)
for i in array_or_vec {} // for(let i of array_or_vec) in JS
// again, as most other things, uses a trait, here named "iterator"
// for some types, you need to call `.iter()` or `.into_iter()`.
// Rust Compiler will usually tell you this.
// Rust compiler will usually tell you this.
for i in something.iter() {}
```
### While
Quite simple loop. Unlike other languages, there's no `do ... while`, only the basic `while`.
Quite simple loop. Unlike other languages, there's no `do ... while{:rust}`, only the basic `while{:rust}`.
```rust
while condition {
@ -456,19 +479,64 @@ while condition {
Syntax is the same as for [if](#ifs), just that the contents are looped.
<Callout color="#139ab4" closed>
<span slot="title">There is a <span style="color:#C678DD">`do ... while`</span> pattern</span>
You can (ab)use Rusts syntax to have the pattern of `do ... while{:rust}`:
```rust
while {
println!("doing while true");
i -= 1;
i < 5
} {}
```
This uses the fact that `{}` code blocks are in fact expressions.
And when you don't have `;` at the last line, it's used as the result value of the expression.
So, this all runs in the "check" phase of while, but only the last line is used as a boolean whether to run it again.
The actual code of while loop is empty - so it will just run the check again.
This has a slight issue with using `break{:rust}` or `continue{:rust}`, in that you can't use them.
But fear not! You can abuse the syntax even more:
```rust
while ({|| {
printn!("while with continue/break");
if should_break { return false };
if should_continue { return true };
something();
check()
})() {}
```
`||` is a lambda (ha I didn't get to those in the original blog post at all) definition. Add a couple of brackets to run the lambda inline.
You can read more about them in the rust book - for a JS dev, the following is equivalent:
| js | rust |
| -- | ---- |
| `() => {}{:js}` | `|| {}{:rust}` |
| `() => 1{:js}` | `|| 1{:rust}` |
| `a => a{:js}` | `|a| a{:rust}`|
Please not that I don't recommend using this syntax as it's kinda confusing. Use `loop{:rust}` with `if{:rust}` instead.
</Callout>
### Printing
For printing, you can use `print!` and `println!`.
The `!` means it's a macro (i.e. a shortcut that expands to something), but you don't really need to think about that much. Another common macro is `vec![]` which creates a [`Vec<T>`](#veclttgt) from an array (values between `[]`).
For printing, you can use `print!{:rust}` and `println!{:rust}`.
The `!{:.entity.name.function}` means it's a macro (i.e. a shortcut that expands to something), but you don't really need to think about that much. Another common macro is `vec![]{:rust}` which creates a [`Vec<T>{:rust}`](#veclttgt) from an array (values between `[]{:rust}`).
Those macros have a simple template system.
- To simply print a new line, write `println!()`.
- To print a single static string, write `print!("something")`. `ln` in `println!` means line, so it adds a newline (`\n`) symbol. `console.log` adds that newline by default.
- To print a variable which implements the `Display` trait (most primitives do so), use `print!("{variable}")`.
- To print a variable which implements the `Debug` trait (can be derived more easily than Display), use `print!("{variable:?}")`.
- To print something more complex which implements `Display` trait, use `print!("{}", variable)`.
- To print something more complex which implements `Debug` trait, use `print!("{:?}", variable)`.
- To simply print a new line, write `println!(){:rust}`.
- To print a single static string, write `print!("something"){:rust}`. `ln{:.entity.name.function}` in `println!{:rust}` means line, so it adds a newline (`\n`) symbol. `console.log(){:js}` adds that newline by default.
- To print a variable which implements the `Display{:rust}` trait (most primitives do so), use `print!("{variable}"){:rust}`.
- To print a variable which implements the `Debug{:rust}` trait (can be derived more easily than Display), use `print!("{variable:?}"){:rust}`.
- To print something more complex which implements `Display{:rust}` trait, use `print!("{}", variable){:rust}`.
- To print something more complex which implements `Debug{:rust}` trait, use `print!("{:?}", variable){:rust}`.
### Traits
@ -476,7 +544,7 @@ Oh, the holy trait system.
*Wait even [PHP has this](https://www.php.net/manual/en/language.oop5.traits.php)?*
Traits are one of the hardest ideas in Rust to grasp, yet one of the most powerful ones.
Instead of being inheritance based (like <abbr title="Object Oriented Programming">OOP</abbr>, or JavaScript's prototype oriented programming), Rust throws it all out and instead embraces duck typing (i.e. if it quacks it's a duck).
Instead of being inheritance based (like [<abbr title="Object Oriented Programming">OOP</abbr>](https://www.wikipedia.com/en/Object-oriented_programming), or JavaScript's prototype oriented programming), Rust throws it all out and instead embraces [duck typing](https://www.wikipedia.com/en/Duck_typing) (i.e. if it quacks it's a duck).
For every type, there can be exactly one 'default' (or nameless) trait, which can be implemented only in the same module. Those are usually unique methods for that type.
For everything else, there are named traits. Example:
@ -506,9 +574,9 @@ dog.quack();
```
First, we define the trait (Interface from the <abbr title="Object Oriented Programming">OOP</abbr> language, except only methods/functions).
Then we can implement the trait for the given type (`Dog` in our case).
Then we can implement the trait for the given type (`Dog{:rust}` in our case).
Some traits can be implemented automatically for you. Common example is `Display` and `Debug` traits. Their requirement is that the types used in the struct have to implement `Display` and `Debug` respectively.
Some traits can be implemented automatically for you. Common example is `Display{:rust}` and `Debug{:rust}` traits. Their requirement is that the types used in the struct have to implement `Display{:rust}` and `Debug{:rust}` respectively.
```rust
#[derive(Display,Debug)]
@ -521,18 +589,18 @@ println!("{:?}", Something { var: 1 });
#### Scopes
Traits are scoped, and are scoped independently of the type it implements. Meaning you can use a type, but not a trait implementation (for example if said implementation is coming from another library than the type itself). You can then `use` the implementation.
Traits are scoped, and are scoped independently of the type it implements. Meaning you can use a type, but not a trait implementation (for example if said implementation is coming from another library than the type itself). You can then `use{:rust}` the implementation.
#### The self
`self` in traits refers to the type it implements.
**`&self` is an alias to `self: &Self`**, where **`Self` refers to the type** (so `self: &Dog` in the case above).
`self` is also an alias to `self: Self`, but the difference is that this moves the variable (consumes it, and the variable is no longer available outside).
`self{:rust}` in traits refers to the type it implements.
**`&self{:rust}` is an alias to `self: &Self{:rust}`**, where **`Self{:rust}` refers to the type** (so `self: &Dog{:rust}` in the case above).
`self{:rust}` is also an alias to `self: Self{:rust}`, but the difference is that this moves the variable (consumes it, and the variable is no longer available outside).
When there function definiton doesn't start with `self`, `&self` or `&mut self` (`&mut self` is the same as `&self` except with mutable reference), it's considered a static method.
When there function definiton doesn't start with `self{:rust}`, `&self{:rust}` or `&mut self{:rust}` (`&mut self{:rust}` is the same as `&self{:rust}` except with mutable reference), it's considered a static method.
Traits can still define and implement static methods like any other methods.
A common static method is `new`, which is used to create a new instance of the type/struct:
A common static method is `new{:rust}`, which is used to create a new instance of the type/struct:
```rust
impl Something {
@ -554,7 +622,7 @@ See also [Declaring structs](#declaring-structs)
Pointers are actually pretty easy to understand, even if coming from higher level languages. I still do make mistakes with them, a lot.
`&A` points to `A`, and I can use it quite similarly, I just have to make sure that `A` exists for as long as `&A` exists, since a pointer to nowhere is not a good idea.
`&A{:rust}` points to `A{:rust}`, and I can use it quite similarly, I just have to make sure that `A{:rust}` exists for as long as `&A{:rust}` exists, since a pointer to nowhere is not a good idea.
Rust prevents that by statically checking at compile time if the use is valid. It automatically frees variables that are out of scope, and doesn't allow pointers to outlive the original variable.
Another safety guarantee is that **only one mutable pointer can exist (and no other pointer can exist)** at a time.
@ -569,8 +637,8 @@ c = 1;
```
That's kinda all there is to it. Just that the **original variable must always be in scope for the pointers to be accessible**.
Using pointers in structs are kind of problematic as the compiler generally doesn't like it (because structs often outlive the original variable). I usually just either **transfer ownership or clone** (`.clone()`, part of `Clone` trait. Can be `derived`.).
Sometimes, some functions require only pointers and not transfers. You can just prepend the value with `&` (or `&mut`) to make it work.
Using pointers in structs are kind of problematic as the compiler generally doesn't like it (because structs often outlive the original variable). I usually just either **transfer ownership or clone** (`.clone(){:rust}`, part of `Clone{:rust}` trait. Can be `derived{:rust}`.).
Sometimes, some functions require only pointers and not ownership. You can just prepend the value with `&{:rust}` (or `&mut{:rust}`) to make it work.
```rust
something(&a);
@ -606,7 +674,7 @@ To select multiple "namespaces", you can use `{}` notation, like:
use std::env::{args, var};
```
You can also repeat the `use` keyword freely
You can also repeat the `use{:rust}` keyword freely
```rust
use std::env;
@ -616,7 +684,7 @@ env::var();
args()
```
Another thing of interest is that you can also use `use` inside functions. Then the library won't be imported if it's not used (i.e. if the function doesn't appear in the code path, for example if you use a mock library for tests and `use` only in tests, it won't be imported when building normally).
Another thing of interest is that you can also use `use{:rust}` inside functions. Then the library won't be imported if it's not used (i.e. if the function doesn't appear in the code path, for example if you use a mock library for tests and `use{:rust}` only in tests, it won't be imported when building normally).
```rust
fn test() {
@ -625,7 +693,7 @@ fn test() {
}
```
I don't recommend using that for normal code paths though, use global imports instead.
I don't recommend using that for normal code paths though, use global imports instead for readability.
### Publicity
@ -638,7 +706,7 @@ Essentially, everything's private by default to the file it's created in.
- functions
- trait implementations depend on the trait and struct it implements, i.e. if both of them are public then it's public as well.
To make them public (i.e. accessible outside the file), use `pub` keyword.
To make them public (i.e. accessible outside the file), use `pub{:rust}` keyword.
```rust
pub struct Something {
@ -650,9 +718,9 @@ pub fn method() {}
### Using multiple files
Oh well, I do sometimes miss the ol' `require("./file")`.
Oh well, I do sometimes miss the ol' `require("./file"){:js}`.
To ``import'' a file, use the `mod` directive. Crates downloaded via `cargo` are imported automatically.
To "import" a file, use the `mod{:rust}` directive. Crates downloaded via `cargo` are imported automatically.
`main.rs`
```rust
@ -672,7 +740,7 @@ pub fn function() {
}
```
You can also re-export a file using `pub mod`. Most existing rust code does this to support folders:
You can also re-export a file using `pub mod{:rust}`. Most existing rust code does this to support folders:
`main.rs`
```rust
@ -696,12 +764,13 @@ pub fn function() {
}
```
For how `println!` works, see [printing](#printing).
For how `println!{:rust}` works, see [printing](#printing).
### Writing documentation
To write documentation, simply use three `/`. In some IDEs, they'll get highlighted differently (my CLion setup has it slightly brighter).
Works kind of similarly to JSDoc, except that types cannot be annotated explicitly, as they're set in code anyway.
Works kind of similarly to JSDoc, except that types cannot be annotated explicitly, as they're set in code anyway.
They must preceed the thing you want to document. You can have multiple lines.
```rust
/// a description of var
@ -710,6 +779,6 @@ let var = "something";
---
Thanks for reading this {story ? "little story (with some documentation)" : "post"}. Hope that you learned something (which I did, even during writing the post).
Thanks for reading this {story ? "little story (with some documentation)" : "post"}. Hope that you learned something (which I did, even during writing of this post).
*no crabs were harmed in the making of this post. I'm not affiliated with any of the mentioned products or companies.*

View file

@ -45,7 +45,18 @@ I created a new project simply by using
```bash
pnpm init svelte@next
```
*(side note: I'm using [pnpm](https://pnpm.io) as it's a faster alternative to npm which also saves disk space)*
<Callout color="#139ab4" closed minimal>
<span slot="title">
*(side note: I'm using [pnpm](https://pnpm.io) as it's a faster alternative to npm which also saves disk space)*
</span>
[pnpm](https://pnpm.io) uses [symlinks](https://en.wikipedia.org/wiki/Symbolic_link) to store each dependency exactly once on disk
(symlinks, symbolic links, are a sort of alias to files), which makes it use less storage. In addition, it's faster and has better
monorepo support.
</Callout>
This creates a new [Svelte Kit](https://kit.svelte.dev) project, by first asking for configuration (i.e. if you want typescript, ESLint and/or prettifier) and then initalizing from a template.
@ -77,6 +88,8 @@ An example component:
<h1>Hello {name}</h1>
<input type=text bind:value={name}>
<!-- Styles hidden for readability -->
```
<ExampleWrapper title="Interactive example">
@ -142,7 +155,7 @@ After a while (*oh wait it's already a year*) I wanted to write some blog posts.
The design from Carl was only a single page, but it did include some list of posts there (see the home page, also reused in the posts page), and I felt confident enough that I could code at least a text-first website without a design.
To more easily write blog posts without writing HTML, I decided to use <img src="/tech/markdown.png" alt="" aria-hidden="true" style="height: 20px"> [Markdown](https://www.markdownguide.org/basic-syntax/).
To more easily write blog posts without writing HTML, I decided to use [Markdown](https://www.markdownguide.org/basic-syntax/).
To add more to that, I found [mdsvex](https://mdsvex.pngwn.io/), which allows one to use markdown from svelte, and use svelte from markdown.
Their website only specifies how to use it on classic Svelte (via rollup or webpack), but Svelte Kit hides this configuration (in addition to using vite in dev mode).
@ -266,12 +279,10 @@ First iteration of this new design wasn't actually Svelte Kit, but only ``plain'
This meant that the page was only client side, and the server only pre-compiled JS and sent only minimal HTML markup (which mostly just linked JS which did everything else). This meant the page didn't work without JS and took a bit to load.
To fix that, I later moved it into Svelte Kit page (Svelte does support SSR, but it's easier to use Svelte Kit) and used the `static` adapter which meant that all the pages are now prerendered and work without JS. This also means it's fast to load (especially when using CDN, such as <img src="/tech/cloudflare.png" alt="" aria-hidden="true" style="height: 20px"> [Cloudflare](https://cloudflare.com), which this website does use. Not affiliated with them).
To fix that, I later moved it into Svelte Kit page (Svelte does support SSR, but it's easier to use Svelte Kit) and used the `static` adapter which meant that all the pages are now prerendered and work without JS. This also means it's fast to load (especially when using CDN, such as [Cloudflare](https://cloudflare.com), which this website does use. Not affiliated with them).
If you use the `adapter-auto`, deploying to Cloudflare pages should work nearly as is, you just need to set `NODE_VERSION` environment variable to `14` or `16`, as it's by default set to `12` which is too old for Svelte kit to work.
## Wrapping up
Thanks for reading, hope you learnt something new - as I did when I wrote this blog post, after spending an hour to update the website with new styles and functionality.
If you did enjoy reading this, consider sharing a link here on any social media you use.
Thanks for reading, hope you learnt something new - as I did when I wrote this blog post, after spending an hour to update this site with new styles and functionality.

View file

@ -1,7 +1,27 @@
<script>
import darkmode from "$lib/stores/darkmode";
var name = "world";
</script>
<input type=text bind:value={name} class="text-black">
<input class:dark={$darkmode} type=text bind:value={name} class="text-black">
<input type=text bind:value={name} class="text-black">
&lt;=>
<input class:dark={$darkmode} type=text bind:value={name} class="text-black">
<style>
input {
@apply p-2 bg-transparent backdrop-blur my-2 transition-colors duration-150;
border: none;
border-bottom: 1px solid rgba(0,0,0, 0.3);
}
input:focus {
@apply outline-none border-b-black/70;
}
input.dark {
@apply border-b-white/30 text-white;
}
input.dark:focus {
@apply border-b-white/70;
}
</style>

View file

@ -1,15 +1,31 @@
<script>
import darkmode from "$lib/stores/darkmode";
var name = "world";
let funny = { "amogus": "ඞ", "AMOGUS": "sussy baka", "discord": "proprietary matrix", "never gonna give you up": "never gonna let you down" };
let funny = { "amogus": "ඞ", "AMOGUS": "sussy baka", "discord": "proprietary matrix", "never gonna give you up": "never gonna let you down", "wysi": "727", "727": "wysi" };
</script>
<h1>Hello {funny[name] || name}</h1>
<input type=text class="text-black" bind:value={name}>
<input class:dark={$darkmode} type=text class="text-black" bind:value={name}>
<style>
h1 {
padding-top: 0;
@apply p-0 m-0 text-xl font-bold;
}
input {
@apply p-2 bg-transparent backdrop-blur my-2 transition-colors duration-150;
border: none;
border-bottom: 1px solid rgba(0,0,0, 0.3);
}
input:focus {
@apply outline-none border-b-black/70;
}
input.dark {
@apply border-b-white/30 text-white;
}
input.dark:focus {
@apply border-b-white/70;
}
</style>

View file

@ -7,6 +7,8 @@ import remarkTwemoji from 'remark-twemoji';
import remarkGfm from 'remark-gfm';
import remarkExtendedTable from 'remark-extended-table';
import rehypeKatexSvelte from "rehype-katex-svelte";
import { prettyCode } from './remark/code.js';
import { rehypeEscapeHighlight, remarkEscapeInlineCode, remarkUnescapeHighlight } from './remark/unescapehighlight.js';
/** @type {import('@sveltejs/kit').Config} */
const config = {
@ -30,16 +32,21 @@ const config = {
quotes: false,
backticks: "all"
},
highlight: false,
rehypePlugins: [
rehypeSlug,
rehypeAutolinkHeadings,
rehypeKatexSvelte
rehypeKatexSvelte,
rehypeEscapeHighlight
],
remarkPlugins: [
remarkGfm,
remarkMath,
remarkTwemoji,
remarkExtendedTable
remarkExtendedTable,
remarkUnescapeHighlight,
prettyCode,
remarkEscapeInlineCode
]
})
]