diff --git a/astro.config.mjs b/astro.config.mjs index 03ce4cd..be5ff35 100644 --- a/astro.config.mjs +++ b/astro.config.mjs @@ -8,6 +8,5 @@ import icon from "astro-icon"; // https://astro.build/config export default defineConfig({ site: 'https://fernandoarteaga.dev', - // site: 'https://fernandoarteaga.github.io', integrations: [mdx(), sitemap(), icon(), tailwind()] }); \ No newline at end of file diff --git a/package.json b/package.json index b1b18f2..cf3bccb 100644 --- a/package.json +++ b/package.json @@ -27,5 +27,8 @@ "daisyui": "^4.6.1", "tailwindcss": "^3.4.1", "typescript": "^5.3.3" + }, + "devDependencies": { + "@tailwindcss/typography": "^0.5.10" } } \ No newline at end of file diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 089a2f4..3ccd468 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -39,12 +39,16 @@ dependencies: specifier: ^5.3.3 version: 5.3.3 +devDependencies: + '@tailwindcss/typography': + specifier: ^0.5.10 + version: 0.5.10(tailwindcss@3.4.1) + packages: /@alloc/quick-lru@5.2.0: resolution: {integrity: sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==} engines: {node: '>=10'} - dev: false /@ampproject/remapping@2.2.1: resolution: {integrity: sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg==} @@ -716,7 +720,6 @@ packages: strip-ansi-cjs: /strip-ansi@6.0.1 wrap-ansi: 8.1.0 wrap-ansi-cjs: /wrap-ansi@7.0.0 - dev: false /@jridgewell/gen-mapping@0.3.3: resolution: {integrity: sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==} @@ -725,28 +728,23 @@ packages: '@jridgewell/set-array': 1.1.2 '@jridgewell/sourcemap-codec': 1.4.15 '@jridgewell/trace-mapping': 0.3.22 - dev: false /@jridgewell/resolve-uri@3.1.1: resolution: {integrity: sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==} engines: {node: '>=6.0.0'} - dev: false /@jridgewell/set-array@1.1.2: resolution: {integrity: sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==} engines: {node: '>=6.0.0'} - dev: false /@jridgewell/sourcemap-codec@1.4.15: resolution: {integrity: sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==} - dev: false /@jridgewell/trace-mapping@0.3.22: resolution: {integrity: sha512-Wf963MzWtA2sjrNt+g18IAln9lKnlRp+K2eH4jjIoF1wYeq3aMREpG09xhlhdzS0EjwU7qmUJYangWa+151vZw==} dependencies: '@jridgewell/resolve-uri': 3.1.1 '@jridgewell/sourcemap-codec': 1.4.15 - dev: false /@mdx-js/mdx@3.0.0: resolution: {integrity: sha512-Icm0TBKBLYqroYbNW3BPnzMGn+7mwpQOK310aZ7+fkCtiU3aqv2cdcX+nd0Ydo3wI5Rx8bX2Z2QmGb/XcAClCw==} @@ -784,12 +782,10 @@ packages: dependencies: '@nodelib/fs.stat': 2.0.5 run-parallel: 1.2.0 - dev: false /@nodelib/fs.stat@2.0.5: resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==} engines: {node: '>= 8'} - dev: false /@nodelib/fs.walk@1.2.8: resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} @@ -797,13 +793,11 @@ packages: dependencies: '@nodelib/fs.scandir': 2.1.5 fastq: 1.17.0 - dev: false /@pkgjs/parseargs@0.11.0: resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} engines: {node: '>=14'} requiresBuild: true - dev: false optional: true /@rollup/rollup-android-arm-eabi@4.9.6: @@ -910,6 +904,18 @@ packages: dev: false optional: true + /@tailwindcss/typography@0.5.10(tailwindcss@3.4.1): + resolution: {integrity: sha512-Pe8BuPJQJd3FfRnm6H0ulKIGoMEQS+Vq01R6M5aCrFB/ccR/shT+0kXLjouGC1gFLm9hopTFN+DMP0pfwRWzPw==} + peerDependencies: + tailwindcss: '>=3.0.0 || insiders' + dependencies: + lodash.castarray: 4.4.0 + lodash.isplainobject: 4.0.6 + lodash.merge: 4.6.2 + postcss-selector-parser: 6.0.10 + tailwindcss: 3.4.1 + dev: true + /@trysound/sax@0.2.0: resolution: {integrity: sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA==} engines: {node: '>=10.13.0'} @@ -1132,12 +1138,10 @@ packages: /ansi-regex@5.0.1: resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} engines: {node: '>=8'} - dev: false /ansi-regex@6.0.1: resolution: {integrity: sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==} engines: {node: '>=12'} - dev: false /ansi-styles@3.2.1: resolution: {integrity: sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==} @@ -1151,16 +1155,13 @@ packages: engines: {node: '>=8'} dependencies: color-convert: 2.0.1 - dev: false /ansi-styles@6.2.1: resolution: {integrity: sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==} engines: {node: '>=12'} - dev: false /any-promise@1.3.0: resolution: {integrity: sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==} - dev: false /anymatch@3.1.3: resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} @@ -1168,11 +1169,9 @@ packages: dependencies: normalize-path: 3.0.0 picomatch: 2.3.1 - dev: false /arg@5.0.2: resolution: {integrity: sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==} - dev: false /argparse@1.0.10: resolution: {integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==} @@ -1326,7 +1325,6 @@ packages: /balanced-match@1.0.2: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} - dev: false /base-64@1.0.0: resolution: {integrity: sha512-kwDPIFCGx0NZHog36dj+tHiwP4QMzsZ3AgMViUBKI0+V5n4U0ufTCUMhnQ04diaRI8EX/QcPfql7zlhZ7j4zgg==} @@ -1339,7 +1337,6 @@ packages: /binary-extensions@2.2.0: resolution: {integrity: sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==} engines: {node: '>=8'} - dev: false /bl@4.1.0: resolution: {integrity: sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==} @@ -1381,14 +1378,12 @@ packages: resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==} dependencies: balanced-match: 1.0.2 - dev: false /braces@3.0.2: resolution: {integrity: sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==} engines: {node: '>=8'} dependencies: fill-range: 7.0.1 - dev: false /browserslist@4.22.3: resolution: {integrity: sha512-UAp55yfwNv0klWNapjs/ktHoguxuQNGnOzxYmfnXIS+8AsRDZkSDxg7R1AX3GKzn078SBI5dzwzj/Yx0Or0e3A==} @@ -1424,7 +1419,6 @@ packages: /camelcase-css@2.0.1: resolution: {integrity: sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==} engines: {node: '>= 6'} - dev: false /camelcase@7.0.1: resolution: {integrity: sha512-xlx1yCK2Oc1APsPXDL2LdlNP6+uu8OCDdhOBSVT279M/S+y75O30C2VuD8T2ogdePBBl7PfPF4504tnLgX3zfw==} @@ -1506,7 +1500,6 @@ packages: readdirp: 3.6.0 optionalDependencies: fsevents: 2.3.3 - dev: false /chownr@1.1.4: resolution: {integrity: sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==} @@ -1575,7 +1568,6 @@ packages: engines: {node: '>=7.0.0'} dependencies: color-name: 1.1.4 - dev: false /color-name@1.1.3: resolution: {integrity: sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==} @@ -1584,7 +1576,6 @@ packages: /color-name@1.1.4: resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} requiresBuild: true - dev: false /color-string@1.9.1: resolution: {integrity: sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==} @@ -1612,7 +1603,6 @@ packages: /commander@4.1.1: resolution: {integrity: sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==} engines: {node: '>= 6'} - dev: false /commander@7.2.0: resolution: {integrity: sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==} @@ -1639,7 +1629,6 @@ packages: path-key: 3.1.1 shebang-command: 2.0.0 which: 2.0.2 - dev: false /css-select@5.1.0: resolution: {integrity: sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg==} @@ -1683,7 +1672,6 @@ packages: resolution: {integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==} engines: {node: '>=4'} hasBin: true - dev: false /csso@5.0.5: resolution: {integrity: sha512-0LrrStPOdJj+SPCCrGhzryycLjwcgUSHBtxNA8aIDxf0GLsRh1cKYhB00Gd1lDOS4yGH69+SNn13+TWbVHETFQ==} @@ -1796,7 +1784,6 @@ packages: /didyoumean@1.2.2: resolution: {integrity: sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==} - dev: false /diff@5.1.0: resolution: {integrity: sha512-D+mk+qE8VC/PAUrlAU34N+VfXev0ghe5ywmpqrawphmVZc1bEfn56uo9qpyGp1p4xpzOHkSW4ztBd6L7Xx4ACw==} @@ -1805,7 +1792,6 @@ packages: /dlv@1.1.3: resolution: {integrity: sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==} - dev: false /dom-serializer@2.0.0: resolution: {integrity: sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==} @@ -1841,7 +1827,6 @@ packages: /eastasianwidth@0.2.0: resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} - dev: false /electron-to-chromium@1.4.653: resolution: {integrity: sha512-wA2A2LQCqnEwQAvwADQq3KpMpNwgAUBnRmrFgRzHnPhbQUFArTR32Ab46f4p0MovDLcg4uqd4nCsN2hTltslpA==} @@ -1860,11 +1845,9 @@ packages: /emoji-regex@8.0.0: resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} - dev: false /emoji-regex@9.2.2: resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} - dev: false /end-of-stream@1.4.4: resolution: {integrity: sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==} @@ -2055,7 +2038,6 @@ packages: glob-parent: 5.1.2 merge2: 1.4.1 micromatch: 4.0.5 - dev: false /fast-xml-parser@4.3.4: resolution: {integrity: sha512-utnwm92SyozgA3hhH2I8qldf2lBqm6qHOICawRNRFu1qMe3+oqr+GcXjGqTmXTMGE5T4eC03kr/rlh5C1IRdZA==} @@ -2072,7 +2054,6 @@ packages: resolution: {integrity: sha512-zGygtijUMT7jnk3h26kUms3BkSDp4IfIKjmnqI2tvx6nuBfiF1UqOxbnLfzdv+apBy+53oaImsKtMw/xYbW+1w==} dependencies: reusify: 1.0.4 - dev: false /fd-slicer@1.1.0: resolution: {integrity: sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==} @@ -2085,7 +2066,6 @@ packages: engines: {node: '>=8'} dependencies: to-regex-range: 5.0.1 - dev: false /find-up@4.1.0: resolution: {integrity: sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==} @@ -2121,7 +2101,6 @@ packages: dependencies: cross-spawn: 7.0.3 signal-exit: 4.1.0 - dev: false /fraction.js@4.3.7: resolution: {integrity: sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==} @@ -2145,12 +2124,10 @@ packages: engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} os: [darwin] requiresBuild: true - dev: false optional: true /function-bind@1.1.2: resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} - dev: false /gensync@1.0.0-beta.2: resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} @@ -2199,14 +2176,12 @@ packages: engines: {node: '>= 6'} dependencies: is-glob: 4.0.3 - dev: false /glob-parent@6.0.2: resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} engines: {node: '>=10.13.0'} dependencies: is-glob: 4.0.3 - dev: false /glob@10.3.10: resolution: {integrity: sha512-fa46+tv1Ak0UPK1TOy/pZrIybNNt4HCv7SDzwyfiOZkvZLEbjsZkJBPtDHVshZjbecAoAGSC20MjLDG/qr679g==} @@ -2218,7 +2193,6 @@ packages: minimatch: 9.0.3 minipass: 5.0.0 path-scurry: 1.10.1 - dev: false /globals@11.12.0: resolution: {integrity: sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==} @@ -2249,7 +2223,6 @@ packages: engines: {node: '>= 0.4'} dependencies: function-bind: 1.1.2 - dev: false /hast-util-from-html@2.0.1: resolution: {integrity: sha512-RXQBLMl9kjKVNkJTIO6bZyb2n+cUH8LFaSSzo82jiLT6Tfc+Pt7VQCS+/h3YwG4jaNE2TA2sdJisGWR+aJrp0g==} @@ -2475,7 +2448,6 @@ packages: engines: {node: '>=8'} dependencies: binary-extensions: 2.2.0 - dev: false /is-buffer@2.0.5: resolution: {integrity: sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ==} @@ -2486,7 +2458,6 @@ packages: resolution: {integrity: sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==} dependencies: hasown: 2.0.0 - dev: false /is-decimal@2.0.1: resolution: {integrity: sha512-AAB9hiomQs5DXWcRB1rqsxGUstbRroFOPPVAomNk/3XHR5JyEZChOyTWe2oayKnsSsr/kcGqF+z6yuH6HHpN0A==} @@ -2506,19 +2477,16 @@ packages: /is-extglob@2.1.1: resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} engines: {node: '>=0.10.0'} - dev: false /is-fullwidth-code-point@3.0.0: resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} engines: {node: '>=8'} - dev: false /is-glob@4.0.3: resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} engines: {node: '>=0.10.0'} dependencies: is-extglob: 2.1.1 - dev: false /is-hexadecimal@2.0.1: resolution: {integrity: sha512-DgZQp241c8oO6cA1SbTEWiXeoxV42vlcJxgH+B3hi1AiqqKruZR3ZGF8In3fj4+/y/7rHvlOZLZtgJ/4ttYGZg==} @@ -2540,7 +2508,6 @@ packages: /is-number@7.0.0: resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} engines: {node: '>=0.12.0'} - dev: false /is-plain-obj@4.1.0: resolution: {integrity: sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==} @@ -2577,7 +2544,6 @@ packages: /isexe@2.0.0: resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} - dev: false /jackspeak@2.3.6: resolution: {integrity: sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ==} @@ -2586,12 +2552,10 @@ packages: '@isaacs/cliui': 8.0.2 optionalDependencies: '@pkgjs/parseargs': 0.11.0 - dev: false /jiti@1.21.0: resolution: {integrity: sha512-gFqAIbuKyyso/3G2qhiO2OM6shY6EPP/R0+mkDbyspxKazh8BXDC5FiFsUjlczgdNz/vfra0da2y+aHrusLG/Q==} hasBin: true - dev: false /js-tokens@4.0.0: resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} @@ -2654,16 +2618,13 @@ packages: /lilconfig@2.1.0: resolution: {integrity: sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==} engines: {node: '>=10'} - dev: false /lilconfig@3.0.0: resolution: {integrity: sha512-K2U4W2Ff5ibV7j7ydLr+zLAkIg5JJ4lPn1Ltsdt+Tz/IjQ8buJ55pZAxoP34lqIiwtF9iAvtLv3JGv7CAyAg+g==} engines: {node: '>=14'} - dev: false /lines-and-columns@1.2.4: resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} - dev: false /load-yaml-file@0.2.0: resolution: {integrity: sha512-OfCBkGEw4nN6JLtgRidPX6QxjBQGQf72q3si2uvqyFEMbycSFFHwAZeXx6cJgFM9wmLrf9zBwCP3Ivqa+LLZPw==} @@ -2702,9 +2663,16 @@ packages: p-locate: 5.0.0 dev: false + /lodash.castarray@4.4.0: + resolution: {integrity: sha512-aVx8ztPv7/2ULbArGJ2Y42bG1mEQ5mGjpdvrbJcJFU3TbYybe+QlLS4pst9zV52ymy2in1KpFPiZnAOATxD4+Q==} + dev: true + + /lodash.isplainobject@4.0.6: + resolution: {integrity: sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==} + dev: true + /lodash.merge@4.6.2: resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} - dev: false /log-symbols@5.1.0: resolution: {integrity: sha512-l0x2DvrW294C9uDCoQe1VSU4gf529FkSZ6leBl4TiqZH/e+0R7hSfHQBNut2mNygDgHwvYHfFLn6Oxb3VWj2rA==} @@ -2721,7 +2689,6 @@ packages: /lru-cache@10.2.0: resolution: {integrity: sha512-2bIM8x+VAf6JT4bKAljS1qUWgMsqZRPGJS6FSahIMPVvctcNhyVp7AJu7quxOW9jwkryBReKZY5tY5JYv2n/7Q==} engines: {node: 14 || >=16.14} - dev: false /lru-cache@5.1.1: resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} @@ -2983,7 +2950,6 @@ packages: /merge2@1.4.1: resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} engines: {node: '>= 8'} - dev: false /micromark-core-commonmark@2.0.0: resolution: {integrity: sha512-jThOz/pVmAYUtkroV3D5c1osFXAMv9e0ypGDOIZuCeAe91/sD6BoE2Sjzt30yuXtwOYUmySOhMas/PVyh02itA==} @@ -3325,7 +3291,6 @@ packages: dependencies: braces: 3.0.2 picomatch: 2.3.1 - dev: false /mime@3.0.0: resolution: {integrity: sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A==} @@ -3355,7 +3320,6 @@ packages: engines: {node: '>=16 || 14 >=14.17'} dependencies: brace-expansion: 2.0.1 - dev: false /minimist@1.2.8: resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} @@ -3378,7 +3342,6 @@ packages: /minipass@5.0.0: resolution: {integrity: sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==} engines: {node: '>=8'} - dev: false /minizlib@2.1.2: resolution: {integrity: sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==} @@ -3431,13 +3394,11 @@ packages: any-promise: 1.3.0 object-assign: 4.1.1 thenify-all: 1.6.0 - dev: false /nanoid@3.3.7: resolution: {integrity: sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==} engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} hasBin: true - dev: false /napi-build-utils@1.0.2: resolution: {integrity: sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg==} @@ -3485,7 +3446,6 @@ packages: /normalize-path@3.0.0: resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} engines: {node: '>=0.10.0'} - dev: false /normalize-range@0.1.2: resolution: {integrity: sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==} @@ -3515,12 +3475,10 @@ packages: /object-assign@4.1.1: resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} engines: {node: '>=0.10.0'} - dev: false /object-hash@3.0.0: resolution: {integrity: sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==} engines: {node: '>= 6'} - dev: false /once@1.4.0: resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} @@ -3657,7 +3615,6 @@ packages: /path-key@3.1.1: resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} engines: {node: '>=8'} - dev: false /path-key@4.0.0: resolution: {integrity: sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==} @@ -3666,7 +3623,6 @@ packages: /path-parse@1.0.7: resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} - dev: false /path-scurry@1.10.1: resolution: {integrity: sha512-MkhCqzzBEpPvxxQ71Md0b1Kk51W01lrYvlMzSUaIzNsODdd7mqhiimSZlr+VegAz5Z6Vzt9Xg2ttE//XBhH3EQ==} @@ -3674,7 +3630,6 @@ packages: dependencies: lru-cache: 10.2.0 minipass: 5.0.0 - dev: false /path-to-regexp@6.2.1: resolution: {integrity: sha512-JLyh7xT1kizaEvcaXOQwOc2/Yhw6KZOvPf1S8401UyLk86CU79LN3vl7ztXGm/pZ+YjoyAJ4rxmHwbkBXJX+yw==} @@ -3698,17 +3653,14 @@ packages: /picocolors@1.0.0: resolution: {integrity: sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==} - dev: false /picomatch@2.3.1: resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} engines: {node: '>=8.6'} - dev: false /pify@2.3.0: resolution: {integrity: sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==} engines: {node: '>=0.10.0'} - dev: false /pify@4.0.1: resolution: {integrity: sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==} @@ -3718,7 +3670,6 @@ packages: /pirates@4.0.6: resolution: {integrity: sha512-saLsH7WeYYPiD25LDuLRRY/i+6HaPYr6G1OUlN39otzkSTxKnubR9RTxS3/Kk50s1g2JTgFwWQDQyplC5/SHZg==} engines: {node: '>= 6'} - dev: false /pkg-dir@4.2.0: resolution: {integrity: sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==} @@ -3745,7 +3696,6 @@ packages: postcss-value-parser: 4.2.0 read-cache: 1.0.0 resolve: 1.22.8 - dev: false /postcss-js@4.0.1(postcss@8.4.33): resolution: {integrity: sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw==} @@ -3755,7 +3705,6 @@ packages: dependencies: camelcase-css: 2.0.1 postcss: 8.4.33 - dev: false /postcss-load-config@4.0.2(postcss@8.4.33): resolution: {integrity: sha512-bSVhyJGL00wMVoPUzAVAnbEoWyqRxkjv64tUl427SKnPrENtq6hJwUojroMz2VB+Q1edmi4IfrAPpami5VVgMQ==} @@ -3772,7 +3721,6 @@ packages: lilconfig: 3.0.0 postcss: 8.4.33 yaml: 2.3.4 - dev: false /postcss-nested@6.0.1(postcss@8.4.33): resolution: {integrity: sha512-mEp4xPMi5bSWiMbsgoPfcP74lsWLHkQbZc3sY+jWYd65CUwXrUaTp0fmNpa01ZcETKlIgUdFN/MpS2xZtqL9dQ==} @@ -3782,7 +3730,14 @@ packages: dependencies: postcss: 8.4.33 postcss-selector-parser: 6.0.15 - dev: false + + /postcss-selector-parser@6.0.10: + resolution: {integrity: sha512-IQ7TZdoaqbT+LCpShg46jnZVlhWD2w6iQYAcYXfHARZ7X1t/UGhhceQDs5X0cGqKvYlHNOuv7Oa1xmb0oQuA3w==} + engines: {node: '>=4'} + dependencies: + cssesc: 3.0.0 + util-deprecate: 1.0.2 + dev: true /postcss-selector-parser@6.0.15: resolution: {integrity: sha512-rEYkQOMUCEMhsKbK66tbEU9QVIxbhN18YiniAwA7XQYTVBqrBy+P2p5JcdqsHgKM2zWylp8d7J6eszocfds5Sw==} @@ -3790,11 +3745,9 @@ packages: dependencies: cssesc: 3.0.0 util-deprecate: 1.0.2 - dev: false /postcss-value-parser@4.2.0: resolution: {integrity: sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==} - dev: false /postcss@8.4.33: resolution: {integrity: sha512-Kkpbhhdjw2qQs2O2DGX+8m5OVqEcbB9HRBvuYM9pgrjEFUg30A9LmXNlTAUj4S9kgtGyrMbTzVjH7E+s5Re2yg==} @@ -3803,7 +3756,6 @@ packages: nanoid: 3.3.7 picocolors: 1.0.0 source-map-js: 1.0.2 - dev: false /prebuild-install@7.1.1: resolution: {integrity: sha512-jAXscXWMcCK8GgCoHOfIr0ODh5ai8mj63L2nWrjuAgXE6tDyYGnx4/8o/rCgU+B4JSyZBKbeZqzhtwtC3ovxjw==} @@ -3873,7 +3825,6 @@ packages: /queue-microtask@1.2.3: resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} - dev: false /queue-tick@1.0.1: resolution: {integrity: sha512-kJt5qhMxoszgU/62PLP1CJytzd2NKetjSRnyuj31fDd3Rlcz3fzlFdFLD1SItunPwyqEOkca6GbV612BWfaBag==} @@ -3897,7 +3848,6 @@ packages: resolution: {integrity: sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==} dependencies: pify: 2.3.0 - dev: false /readable-stream@3.6.2: resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==} @@ -3913,7 +3863,6 @@ packages: engines: {node: '>=8.10.0'} dependencies: picomatch: 2.3.1 - dev: false /rehype-parse@9.0.0: resolution: {integrity: sha512-WG7nfvmWWkCR++KEkZevZb/uw41E8TsH4DsY9UxsTbIXCVGbAs4S+r8FrQ+OtH5EEQAs+5UxKC42VinkmpA1Yw==} @@ -4024,7 +3973,6 @@ packages: is-core-module: 2.13.1 path-parse: 1.0.7 supports-preserve-symlinks-flag: 1.0.0 - dev: false /restore-cursor@4.0.0: resolution: {integrity: sha512-I9fPXU9geO9bHOt9pHHOhOkYerIMsmVaWB0rA2AI9ERh/+x/i7MV5HKBNrg+ljO5eoPVgCcnFuRjJ9uH6I/3eg==} @@ -4072,7 +4020,6 @@ packages: /reusify@1.0.4: resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==} engines: {iojs: '>=1.0.0', node: '>=0.10.0'} - dev: false /rollup@4.9.6: resolution: {integrity: sha512-05lzkCS2uASX0CiLFybYfVkwNbKZG5NFQ6Go0VWyogFTXXbR039UVsegViTntkk4OglHBdF54ccApXRRuXRbsg==} @@ -4101,7 +4048,6 @@ packages: resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} dependencies: queue-microtask: 1.2.3 - dev: false /safe-buffer@5.2.1: resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} @@ -4161,12 +4107,10 @@ packages: engines: {node: '>=8'} dependencies: shebang-regex: 3.0.0 - dev: false /shebang-regex@3.0.0: resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} engines: {node: '>=8'} - dev: false /shikiji-core@0.9.19: resolution: {integrity: sha512-AFJu/vcNT21t0e6YrfadZ+9q86gvPum6iywRyt1OtIPjPFe25RQnYJyxHQPMLKCCWA992TPxmEmbNcOZCAJclw==} @@ -4185,7 +4129,6 @@ packages: /signal-exit@4.1.0: resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} engines: {node: '>=14'} - dev: false /simple-concat@1.0.1: resolution: {integrity: sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==} @@ -4229,7 +4172,6 @@ packages: /source-map-js@1.0.2: resolution: {integrity: sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==} engines: {node: '>=0.10.0'} - dev: false /source-map@0.7.4: resolution: {integrity: sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==} @@ -4275,7 +4217,6 @@ packages: emoji-regex: 8.0.0 is-fullwidth-code-point: 3.0.0 strip-ansi: 6.0.1 - dev: false /string-width@5.1.2: resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==} @@ -4284,7 +4225,6 @@ packages: eastasianwidth: 0.2.0 emoji-regex: 9.2.2 strip-ansi: 7.1.0 - dev: false /string-width@6.1.0: resolution: {integrity: sha512-k01swCJAgQmuADB0YIc+7TuatfNvTBVOoaUWJjTB9R4VJzR5vNWzf5t42ESVZFPS8xTySF7CAdV4t/aaIm3UnQ==} @@ -4322,14 +4262,12 @@ packages: engines: {node: '>=8'} dependencies: ansi-regex: 5.0.1 - dev: false /strip-ansi@7.1.0: resolution: {integrity: sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==} engines: {node: '>=12'} dependencies: ansi-regex: 6.0.1 - dev: false /strip-bom-string@1.0.0: resolution: {integrity: sha512-uCC2VHvQRYu+lMh4My/sFNmF2klFymLX1wHJeXnbEJERpV/ZsVuonzerjfrGpIGF7LBVa1O7i9kjiWvJiFck8g==} @@ -4386,7 +4324,6 @@ packages: mz: 2.7.0 pirates: 4.0.6 ts-interface-checker: 0.1.13 - dev: false /supports-color@5.5.0: resolution: {integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==} @@ -4398,7 +4335,6 @@ packages: /supports-preserve-symlinks-flag@1.0.0: resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} engines: {node: '>= 0.4'} - dev: false /svgo@3.0.3: resolution: {integrity: sha512-X4UZvLhOglD5Xrp834HzGHf8RKUW0Ahigg/08yRO1no9t2NxffOkMiQ0WmaMIbaGlVTlSst2zWANsdhz5ybXgA==} @@ -4442,7 +4378,6 @@ packages: sucrase: 3.35.0 transitivePeerDependencies: - ts-node - dev: false /tar-fs@2.1.1: resolution: {integrity: sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==} @@ -4505,13 +4440,11 @@ packages: engines: {node: '>=0.8'} dependencies: thenify: 3.3.1 - dev: false /thenify@3.3.1: resolution: {integrity: sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==} dependencies: any-promise: 1.3.0 - dev: false /to-fast-properties@2.0.0: resolution: {integrity: sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==} @@ -4523,7 +4456,6 @@ packages: engines: {node: '>=8.0'} dependencies: is-number: 7.0.0 - dev: false /trim-lines@3.0.1: resolution: {integrity: sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg==} @@ -4535,7 +4467,6 @@ packages: /ts-interface-checker@0.1.13: resolution: {integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==} - dev: false /tsconfck@3.0.1(typescript@5.3.3): resolution: {integrity: sha512-7ppiBlF3UEddCLeI1JRx5m2Ryq+xk4JrZuq4EuYXykipebaq1dV0Fhgr1hb7CkmHt32QSgOZlcqVLEtHBG4/mg==} @@ -4710,7 +4641,6 @@ packages: /util-deprecate@1.0.2: resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} - dev: false /vfile-location@5.0.2: resolution: {integrity: sha512-NXPYyxyBSH7zB5U6+3uDdd6Nybz6o6/od9rk8bp9H8GR3L+cm/fC0uUTbqBmUTnMCUDslAGBOIKNfvvb+gGlDg==} @@ -4967,7 +4897,6 @@ packages: hasBin: true dependencies: isexe: 2.0.0 - dev: false /widest-line@4.0.1: resolution: {integrity: sha512-o0cyEG0e8GPzT4iGHphIOh0cJOV8fivsXxddQasHPHfoZf1ZexrfeA21w2NaEN1RHE+fXlfISmOE8R9N3u3Qig==} @@ -4983,7 +4912,6 @@ packages: ansi-styles: 4.3.0 string-width: 4.2.3 strip-ansi: 6.0.1 - dev: false /wrap-ansi@8.1.0: resolution: {integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==} @@ -4992,7 +4920,6 @@ packages: ansi-styles: 6.2.1 string-width: 5.1.2 strip-ansi: 7.1.0 - dev: false /wrappy@1.0.2: resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} @@ -5015,7 +4942,6 @@ packages: /yaml@2.3.4: resolution: {integrity: sha512-8aAvwVUSHpfEqTQ4w/KMlf3HcRdt50E5ODIQJBw1fQ5RL34xabzxtUlzTXVqc4rkZsPbvrXKWnABCD7kWSmocA==} engines: {node: '>= 14'} - dev: false /yargs-parser@21.1.1: resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==} diff --git a/public/blog-placeholder-3.jpg b/public/blog-placeholder-3.jpg deleted file mode 100644 index fbe2ac0..0000000 Binary files a/public/blog-placeholder-3.jpg and /dev/null differ diff --git a/public/blog-placeholder-4.jpg b/public/blog-placeholder-4.jpg deleted file mode 100644 index f4fc88e..0000000 Binary files a/public/blog-placeholder-4.jpg and /dev/null differ diff --git a/public/blog-placeholder-5.jpg b/public/blog-placeholder-5.jpg deleted file mode 100644 index c564674..0000000 Binary files a/public/blog-placeholder-5.jpg and /dev/null differ diff --git a/public/blog-placeholder-about.jpg b/public/blog-placeholder-about.jpg deleted file mode 100644 index cf5f685..0000000 Binary files a/public/blog-placeholder-about.jpg and /dev/null differ diff --git a/public/blog-placeholder-2.jpg b/public/blog-placeholder.jpg similarity index 100% rename from public/blog-placeholder-2.jpg rename to public/blog-placeholder.jpg diff --git a/public/resume-hero.jpeg b/public/resume-hero.jpeg new file mode 100644 index 0000000..e9c8743 Binary files /dev/null and b/public/resume-hero.jpeg differ diff --git a/src/components/FormattedDate.astro b/src/components/FormattedDate.astro index 1bcce73..b20d13d 100644 --- a/src/components/FormattedDate.astro +++ b/src/components/FormattedDate.astro @@ -13,5 +13,4 @@ const { date } = Astro.props; month: 'short', day: 'numeric', }) - } - + } diff --git a/src/components/ProjectCard.astro b/src/components/ProjectCard.astro new file mode 100644 index 0000000..13452d2 --- /dev/null +++ b/src/components/ProjectCard.astro @@ -0,0 +1,57 @@ +--- +import Icon from "$/components/Icon.astro"; +import { Project } from "../cv"; + +interface Props { + project: Project; +} + +const { name, description, status, url, repository, highlights } = Astro.props.project; + +const iconName = (url: string) => { + if (url && url != "") { + return url.includes("github") ? "github" : + url.includes("gitlab") ? "gitlab" : url.includes("bitbucket") ? "bitbucket" : ""; + } + return ""; +} +const icon = iconName(repository); +--- + +
+
+
+

+ { + url && url != "" ? {name} : name + } +

+
+ { + status == "active" ? ( +
+ ) : ( +
+ ) + } +
+ { + icon != "" && ( + + + + ) + } +
+

{description}

+
+ { + highlights.map((topic) => ( +
{topic}
+ )) + } +
+
+
\ No newline at end of file diff --git a/src/content/blog/psycopg-vs-asyncpg.mdx b/src/content/blog/psycopg-vs-asyncpg.mdx new file mode 100644 index 0000000..9027905 --- /dev/null +++ b/src/content/blog/psycopg-vs-asyncpg.mdx @@ -0,0 +1,369 @@ +--- +title: 'Psycopg 3 vs Asyncpg' +description: "Let's compare Psycopg 3 and Asyncpg, two popular PostgreSQL libraries for Python." +pubDate: 'Feb 08 2024' +topics: ['python', 'postgresql', 'asyncpg', 'psycopg3', 'fastapi'] +--- + +Nowadays, everyone talks about performance and how to make our applications faster, and one key factor is how we interact with our databases. +Sometimes we get overwhelmed by small but important decisions, like choosing the right library to work with our database. +Asking ourselves questions like: _"Should I use an ORM or a query builder?"_, _"Should I use a sync or async library?"_ or +_"Is this one faster than the other one?"_. +I know, it's a lot of questions, but don't worry, I'm here to help you with one of those questions. + +In the Python world, we have a lot of libraries to work with PostgreSQL, but two of the most popular are Psycopg 3 (Psycopg) and Asyncpg. +In this article, we will compare these two libraries and see which one is better for your project. + +## Setup + +We will use a simple [FastAPI](https://fastapi.tiangolo.com/) (v0.109.2) application with some endpoints that will interact with a +[PostgreSQL](https://www.postgresql.org/) (v16) database running in a Docker container. + +For connecting with the database, we will use two different libraries: [Psycopg 3](https://www.psycopg.org/psycopg3/docs/) (v3.1.18) +and [Asyncpg](https://magicstack.github.io/asyncpg/current/#) (v0.29.0). + +## Source code + +You can find the source code for this article in the [fernandoarteaga/fastapi-postgres-benchmark](https://github.com/FernandoArteaga/fastapi-postgres-benchmark) repository on GitHub. +In case you want to run the benchmarks yourself, you can follow the instructions in the repository's README file. + +import ProjectCard from '$/components/ProjectCard.astro'; + +
+ +
+ +## Benchmarks + +To evaluate the performance of the Psycopg 3 and Asyncpg libraries in handling various loads, we performed four different tests. +Each test focused on reading a different number of rows, and comparing the performance between **Psycopg sync**, **Psycopg async** and **Asyncpg**. + +The tests were performed using the [wrk](https://github.com/wg/wrk?tab=readme-ov-file) tool, with the same number of +requests, threads and duration for each test: + +* Threads: 12 +* Connections: 400 (total number of HTTP connections to keep open with each thread handling `N = connections/threads`) +* Duration: 2m + +### Read **50** users from the DB + +#### 🥉 psycopg sync connector + +Parameters: + +* Endpoint: `/psycopg/sync` +* Threads: 12 +* Connections: 400 (total number of HTTP connections to keep open with each thread handling `N = connections/threads`) +* Duration: 2m +* CLI command: `wrk -t12 -c400 -d2m http://localhost:7755/psycopg/sync` + +Results: + +| Thread Stats | Avg | Stdev | Max | +/- Stdev | +|--------------|----------|----------|----------|-----------| +| Latency | 304.00ms | 247.62ms | 967.04ms | 76.47% | +| Req/Sec | 80.18 | 74.86 | 333.00 | 76.60% | + +- 93656 requests in 2.00m, 126.21MB read +- Socket errors: connect 158, read 112, write 0, timeout 0 +- Requests/sec: 779.80 +- Transfer/sec: 1.05MB + +#### 🥈 psycopg async connector + +Parameters: + +* Endpoint: `/psycopg/async` +* Threads: 12 +* Connections: 400 (total number of HTTP connections to keep open with each thread handling `N = connections/threads`) +* Duration: 2m +* CLI command: `wrk -t12 -c400 -d2m http://localhost:7755/psycopg/async` + +Results: + +| Thread Stats | Avg | Stdev | Max | +/- Stdev | +|--------------|---------|--------|----------|-----------| +| Latency | 88.11ms | 8.72ms | 216.74ms | 90.14% | +| Req/Sec | 225.99 | 83.09 | 484.00 | 69.62% | + +- 324102 requests in 2.00m, 436.74MB read +- Socket errors: connect 158, read 106, write 0, timeout 0 +- Requests/sec: 2698.62 +- Transfer/sec: 3.64MB + +#### 🥇 asyncpg async connector + +Parameters: + +* Endpoint: `asyncpg/async` +* Threads: 12 +* Connections: 400 (total number of HTTP connections to keep open with each thread handling `N = connections/threads`) +* Duration: 2m +* CLI command: `wrk -t12 -c400 -d2m http://localhost:7755/asyncpg/async` + +Results: + +| Thread Stats | Avg | Stdev | Max | +/- Stdev | +|--------------|---------|---------|----------|-----------| +| Latency | 74.26ms | 41.51ms | 612.29ms | 74.61% | +| Req/Sec | 269.64 | 91.41 | 565.00 | 62.15% | + +- 386681 requests in 2.00m, 521.07MB read +- Socket errors: connect 158, read 106, write 0, timeout 0 +- Requests/sec: 3219.51 +- Transfer/sec: 4.34MB + +### Read **250** users from the DB + +#### 🥉 psycopg sync connector + +Parameters: + +* Endpoint: `/psycopg/sync` +* Threads: 12 +* Connections: 400 (total number of HTTP connections to keep open with each thread handling `N = connections/threads`) +* Duration: 2m +* CLI command: `wrk -t12 -c400 -d2m http://localhost:7755/psycopg/sync` + +Results: + +| Thread Stats | Avg | Stdev | Max | +/- Stdev | +|--------------|----------|----------|--------|-----------| +| Latency | 748.75ms | 205.02ms | 1.04s | 67.27% | +| Req/Sec | 28.07 | 18.80 | 150.00 | 76.28% | + +- 38006 requests in 2.00m, 236.68MB read +- Socket errors: connect 158, read 122, write 0, timeout 0 +- Requests/sec: 316.47 +- Transfer/sec: 1.97MB + +#### 🥈 psycopg async connector + +Parameters: + +* Endpoint: `/psycopg/async` +* Threads: 12 +* Connections: 400 (total number of HTTP connections to keep open with each thread handling `N = connections/threads`) +* Duration: 2m +* CLI command: `wrk -t12 -c400 -d2m http://localhost:7755/psycopg/async` + +Results: + +| Thread Stats | Avg | Stdev | Max | +/- Stdev | +|--------------|----------|--------|----------|-----------| +| Latency | 163.90ms | 7.67ms | 279.98ms | 89.62% | +| Req/Sec | 121.35 | 36.60 | 230.00 | 64.66% | + +- 174168 requests in 2.00m, 1.06GB read +- Socket errors: connect 158, read 102, write 0, timeout 0 +- Requests/sec: 1450.35 +- Transfer/sec: 9.03MB + +#### 🥇 asyncpg async connector + +Parameters: + +* Endpoint: `asyncpg/async` +* Threads: 12 +* Connections: 400 (total number of HTTP connections to keep open with each thread handling `N = connections/threads`) +* Duration: 2m +* CLI command: `wrk -t12 -c400 -d2m http://localhost:7755/asyncpg/async` + +Results: + +| Thread Stats | Avg | Stdev | Max | +/- Stdev | +|--------------|----------|---------|--------|-----------| +| Latency | 155.66ms | 88.66ms | 1.23s | 74.67% | +| Req/Sec | 128.67 | 59.72 | 333.00 | 65.48% | + +- 184649 requests in 2.00m, 1.12GB read +- Socket errors: connect 158, read 106, write 0, timeout 0 +- Requests/sec: 1537.50 +- Transfer/sec: 9.57MB + +### Read **1000** users from the DB + +#### 🥉 psycopg sync connector + +Parameters: + +* Endpoint: `/psycopg/sync` +* Threads: 12 +* Connections: 400 (total number of HTTP connections to keep open with each thread handling `N = connections/threads`) +* Duration: 2m +* CLI command: `wrk -t12 -c400 -d2m http://localhost:7755/psycopg/sync` + +Results: + +| Thread Stats | Avg | Stdev | Max | +/- Stdev | +|--------------|----------|---------|--------|-----------| +| Latency | 925.00ms | 73.91ms | 1.22s | 72.15% | +| Req/Sec | 28.07 | 18.80 | 150.00 | 76.28% | + +- 30764 requests in 2.00m, 755.09MB read +- Socket errors: connect 158, read 124, write 0, timeout 0 +- Requests/sec: 256.15 +- Transfer/sec: 6.29MB + +#### 🥇 psycopg async connector + +Parameters: + +* Endpoint: `/psycopg/async` +* Threads: 12 +* Connections: 400 (total number of HTTP connections to keep open with each thread handling `N = connections/threads`) +* Duration: 2m +* CLI command: `wrk -t12 -c400 -d2m http://localhost:7755/psycopg/async` + +Results: + +| Thread Stats | Avg | Stdev | Max | +/- Stdev | +|--------------|----------|---------|----------|-----------| +| Latency | 517.43ms | 35.68ms | 705.28ms | 74.58% | +| Req/Sec | 46.16 | 33.04 | 161.00 | 60.40% | + +- 55102 requests in 2.00m, 1.32GB read +- Socket errors: connect 158, read 98, write 0, timeout 0 +- Requests/sec: 458.79 +- Transfer/sec: 11.26MB + +#### 🥈 asyncpg async connector + +Parameters: + +* Endpoint: `asyncpg/async` +* Threads: 12 +* Connections: 400 (total number of HTTP connections to keep open with each thread handling `N = connections/threads`) +* Duration: 2m +* CLI command: `wrk -t12 -c400 -d2m http://localhost:7755/asyncpg/async` + +Results: + +| Thread Stats | Avg | Stdev | Max | +/- Stdev | +|--------------|----------|----------|--------|-----------| +| Latency | 516.99ms | 277.76ms | 2.00s | 73.42% | +| Req/Sec | 39.04 | 21.50 | 150.00 | 75.20% | + +- 55070 requests in 2.00m, 1.32GB read +- Socket errors: connect 158, read 103, write 0, timeout 27 +- Requests/sec: 458.63 +- Transfer/sec: 11.26MB + +### Read **5000** users from the DB + +#### 🥉 psycopg sync connector + +Parameters: + +* Endpoint: `/psycopg/sync` +* Threads: 12 +* Connections: 400 (total number of HTTP connections to keep open with each thread handling `N = connections/threads`) +* Duration: 2m +* CLI command: `wrk -t12 -c400 -d2m http://localhost:7755/psycopg/sync` + +Results: + +| Thread Stats | Avg | Stdev | Max | +/- Stdev | +|--------------|-------|----------|-------|-----------| +| Latency | 1.05s | 534.39ms | 1.97s | 60.14% | +| Req/Sec | 8.01 | 5.95 | 50.00 | 79.42% | + +- 8716 requests in 2.00m, 1.04GB read +- Socket errors: connect 158, read 133, write 0, timeout 8578 +- Requests/sec: 72.57 +- Transfer/sec: 8.87MB + +#### 🥇 psycopg async connector + +Parameters: + +* Endpoint: `/psycopg/async` +* Threads: 12 +* Connections: 400 (total number of HTTP connections to keep open with each thread handling `N = connections/threads`) +* Duration: 2m +* CLI command: `wrk -t12 -c400 -d2m http://localhost:7755/psycopg/async` + +Results: + +| Thread Stats | Avg | Stdev | Max | +/- Stdev | +|--------------|-------|----------|-------|-----------| +| Latency | 1.08s | 575.88ms | 2.00s | 57.81% | +| Req/Sec | 11.19 | 6.59 | 50.00 | 60.92% | + +- 13263 requests in 2.00m, 1.58GB read +- Socket errors: 158, read 104, write 0, timeout 13026 +- Requests/sec: 110.44 +- Transfer/sec: 13.50MB + +#### 🥈 asyncpg async connector + +Parameters: + +* Endpoint: `asyncpg/async` +* Threads: 12 +* Connections: 400 (total number of HTTP connections to keep open with each thread handling `N = connections/threads`) +* Duration: 2m +* CLI command: `wrk -t12 -c400 -d2m http://localhost:7755/asyncpg/async` + +Results: + +| Thread Stats | Avg | Stdev | Max | +/- Stdev | +|--------------|----------|----------|-------|-----------| +| Latency | 212.79ms | 344.99ms | 1.95s | 91.28% | +| Req/Sec | 11.42 | 8.74 | 80.00 | 82.07% | + +- 11376 requests in 2.00m, 1.36GB read +- Socket errors: connect 158, read 109, write 0, timeout 9851 +- Requests/sec: 94.74 +- Transfer/sec: 11.58MB + +## Conclusions + +In this benchmark study, we sought to unravel the performance characteristics of two prominent Python libraries, Psycopg 3 and Asyncpg, +when interacting with a PostgreSQL database in the context of a FastAPI application. Through a series of tests involving +the retrieval of 50, 250, 1000, and 5000 rows from the database, we gained valuable insights into the behaviors of both +synchronous and asynchronous connectors. + +#### Psycopg sync connector + +The synchronous implementation of Psycopg 3 exhibited commendable performance across all test scenarios. However, as +the volume of rows to be retrieved increased, a gradual increase in latency was observed. This indicates that while +Psycopg's synchronous connector is robust, it may face challenges in handling larger datasets efficiently. + +#### Psycopg async connector + +The asynchronous counterpart of Psycopg 3 showcased improved responsiveness, particularly evident in scenarios with larger +datasets. The reduction in latency and notable increase in requests per second make the asynchronous implementation a +favorable choice for applications requiring enhanced scalability and responsiveness during database interactions. +Async Psycopg demonstrates a tendency to better handle a larger number of rows, showcasing its potential for scenarios with increased data loads. + +#### Asyncpg async connector + +Asyncpg, a dedicated asynchronous library, emerged as the top performer in this benchmark. It consistently demonstrated +low latency and high-request throughput across all test cases. Its asynchronous nature proved especially advantageous +when dealing with increased data loads, solidifying its position as an optimal choice for projects demanding peak +performance in asynchronous database operations. + +### Key Takeaways + +1. **Scalability Matters:** As the dataset size grows, the choice of an asynchronous connector becomes increasingly critical. + Asynchronous implementation shines in scenarios with larger datasets, offering superior performance compared to synchronous alternatives. +2. **Application-Specific Considerations:** The selection between Psycopg and Asyncpg should be guided by the specific + requirements of your application. While Psycopg, both synchronous and asynchronous, presents robust performance, + Asyncpg stands out when it comes to handling increased concurrency and larger data volumes. +3. **Async Psycopg for Larger Datasets:** The benchmark results suggest that Async Psycopg exhibits a tendency to better +handle a larger number of rows, making it a promising choice for scenarios with extensive data retrieval requirements. +4. **Paginate Database Queries:** To avoid potential scenarios where a single request could block the entire database, +it is advisable to implement pagination for database queries. This ensures efficient data retrieval without risking performance bottlenecks. + +In conclusion, the choice between Psycopg 3 and Asyncpg should be tailored to the unique demands of your project. +By aligning your selection with the scale, concurrency, and responsiveness requirements of your application and implementing +best practices like query pagination, you can ensure optimal performance in database interactions, setting the foundation +for a fast and efficient FastAPI application. diff --git a/src/content/blog/using-mdx.mdx b/src/content/blog/using-mdx.mdx deleted file mode 100644 index 85bdb03..0000000 --- a/src/content/blog/using-mdx.mdx +++ /dev/null @@ -1,32 +0,0 @@ ---- -title: 'Using MDX' -description: 'Lorem ipsum dolor sit amet' -pubDate: 'Jul 02 2022' -heroImage: '/blog-placeholder-5.jpg' -topics: ['markdown'] ---- - -This theme comes with the [@astrojs/mdx](https://docs.astro.build/en/guides/integrations-guide/mdx/) integration installed and configured in your `astro.config.mjs` config file. If you prefer not to use MDX, you can disable support by removing the integration from your config file. - -## Why MDX? - -MDX is a special flavor of Markdown that supports embedded JavaScript & JSX syntax. This unlocks the ability to [mix JavaScript and UI Components into your Markdown content](https://docs.astro.build/en/guides/markdown-content/#mdx-features) for things like interactive charts or alerts. - -If you have existing content authored in MDX, this integration will hopefully make migrating to Astro a breeze. - -## Example - -Here is how you import and use a UI component inside of MDX. -When you open this page in the browser, you should see the clickable button below. - -import HeaderLink from '../../components/HeaderLink.astro'; - - - Embedded component in MDX - - -## More Links - -- [MDX Syntax Documentation](https://mdxjs.com/docs/what-is-mdx) -- [Astro Usage Documentation](https://docs.astro.build/en/guides/markdown-content/#markdown-and-mdx-pages) -- **Note:** [Client Directives](https://docs.astro.build/en/reference/directives-reference/#client-directives) are still required to create interactive components. Otherwise, all components in your MDX will render as static HTML (no JavaScript) by default. diff --git a/src/cv.d.ts b/src/cv.d.ts index e6ed624..e361b46 100644 --- a/src/cv.d.ts +++ b/src/cv.d.ts @@ -4,13 +4,13 @@ export interface CV { volunteer: Array education: Array awards: Array - certificates: Array - publications: Array - skills: Array + certificates: Array + publications: Array + skills: Array languages: Array interests: Array references: Array - projects: Array + projects: Array } interface Basics { @@ -60,7 +60,7 @@ interface Volunteer { highlights: Highlight } -interface Skills { +interface Skill { name: string level: string keywords: Array @@ -73,14 +73,14 @@ interface Awards { summary: string } -interface Certificates { +interface Certificate { name: string, date: string, issuer: string, url: string } -interface Publications { +interface Publication { name: string publisher: string releaseDate: string @@ -122,15 +122,17 @@ type Language = | "Bengali" | string -interface Projects { +interface Project { name: string description: string - status: "active" | "archived" + status: ProjectStatus highlights: Highlight url: string repository?: string } +export type ProjectStatus = "active" | "archived" + interface Interests { name: string keywords: Array diff --git a/src/layouts/BlogPost.astro b/src/layouts/BlogPost.astro index d2e7485..15893e5 100644 --- a/src/layouts/BlogPost.astro +++ b/src/layouts/BlogPost.astro @@ -1,8 +1,8 @@ --- import type { CollectionEntry } from 'astro:content'; import Layout from "$/layouts/Default.astro"; -import FormattedDate from '../components/FormattedDate.astro'; -import BlogBreadcrumb from "../components/BlogBreadcrumb.astro"; +import FormattedDate from "$/components/FormattedDate.astro"; +import BlogBreadcrumb from "$/components/BlogBreadcrumb.astro"; type Props = CollectionEntry<'blog'>['data']; @@ -20,20 +20,24 @@ const { title, description, pubDate, updatedDate, heroImage } = Astro.props;
+

{title}

+
{ updatedDate && ( -
- Last updated on -
+ + (updated on ) + ) }
-

{title}

+

{description}

- +
+ +
diff --git a/src/pages/blog/[...slug].astro b/src/pages/blog/[...slug].astro index 07dbce2..697f7be 100644 --- a/src/pages/blog/[...slug].astro +++ b/src/pages/blog/[...slug].astro @@ -1,6 +1,6 @@ --- import { type CollectionEntry, getCollection } from 'astro:content'; -import BlogPost from '../../layouts/BlogPost.astro'; +import BlogPost from '$/layouts/BlogPost.astro'; export async function getStaticPaths() { const posts = await getCollection('blog'); diff --git a/src/pages/blog/index.astro b/src/pages/blog/index.astro index b71357e..ae81d23 100644 --- a/src/pages/blog/index.astro +++ b/src/pages/blog/index.astro @@ -27,7 +27,9 @@ const isRecent = (date: Date): boolean => {
-
Blog picture
+ { + post.data.heroImage &&
Blog picture
+ }

{ post.data.title } @@ -42,14 +44,17 @@ const isRecent = (date: Date): boolean => { ) }

- - { - post.data.updatedDate && ( -

Last update: - -

- ) - } +

+ + { + post.data.updatedDate && ( + + (updated on ) + + ) + } +

+ { post.data.topics.length > 0 && (
diff --git a/src/pages/projects.astro b/src/pages/projects.astro index e9a565e..612cec7 100644 --- a/src/pages/projects.astro +++ b/src/pages/projects.astro @@ -1,64 +1,18 @@ --- -import resume from '$resume'; import { CV } from "$/cv"; -import Icon from "$/components/Icon.astro"; -import Layout from "../layouts/Default.astro"; +import resume from '$resume'; +import Layout from "$/layouts/Default.astro"; +import ProjectCard from "$/components/ProjectCard.astro"; const cv: CV = resume; ---
- { - cv.projects.map((project) => { - const buildATag = (url: string, name: string) => { - return url && url != "" ? {name} : name; - } - const statusBadge = project.status == "active" ? ( -
- ) : ( -
- ) - const repositoryIcon = (url: string) => { - if (url && url != "") { - const iconName = url.includes("github") ? "github" : - url.includes("gitlab") ? "gitlab" : url.includes("bitbucket") ? "bitbucket" : ""; - return ( - iconName && iconName != "" && ( - - - - ) - ) - } - } - - return ( -
-
-
-

- {buildATag(project.url, project.name)} -

-
- {statusBadge} -
- {repositoryIcon(project.repository)} -
-

{project.description}

-
- { - project.highlights.map((topic) => ( -
{topic}
- )) - } -
-
-
- ) - }) - } + { + cv.projects.map((project) => ( + + )) + }
diff --git a/src/pages/resume.astro b/src/pages/resume.astro index bb1fced..d866c16 100644 --- a/src/pages/resume.astro +++ b/src/pages/resume.astro @@ -16,7 +16,7 @@ const cv: CV = resume; profile-picture

{cv.basics.name}

diff --git a/tailwind.config.js b/tailwind.config.js index c5acea2..19ec197 100644 --- a/tailwind.config.js +++ b/tailwind.config.js @@ -9,7 +9,10 @@ export default { } }, }, - plugins: [require('daisyui')], + plugins: [ + require('daisyui'), + require('@tailwindcss/typography'), + ], daisyui: { styled: true, themes: [