From 4b92961c7759bb7b58a3959411ef644b7935cdfe Mon Sep 17 00:00:00 2001 From: Daylin Morgan Date: Wed, 22 Nov 2023 23:43:36 -0600 Subject: [PATCH] refactor: more pages -> more power! --- .gitignore | 9 +- config.nims | 14 +- nimpkgs.nimble | 12 +- package.json | 13 +- pnpm-lock.yaml | 339 +++++++++++++++------------ site/img/logo-wide.svg | 82 +++++++ site/index.html | 6 +- src/app.nim | 30 +++ src/{nimpkgs.nim.cfg => app.nim.cfg} | 0 src/{ => components}/button.nim | 8 +- src/components/footer.nim | 29 +++ src/components/header.nim | 27 +++ src/components/package.nim | 87 +++++++ src/components/search.nim | 73 ++++++ src/components/tag.nim | 46 ++++ src/context.nim | 33 +++ src/nimpkgs.nim | 250 -------------------- src/packages.nim | 105 +++++---- src/pages/index.nim | 21 ++ src/pages/metrics.nim | 101 ++++++++ src/pages/notfound.nim | 8 + src/pages/package.nim | 82 +++++++ src/pages/pages.nim | 2 + src/pages/search.nim | 106 +++++++++ src/style.nim | 25 ++ src/utils.nim | 31 +++ unocss.config.ts | 45 +++- 27 files changed, 1087 insertions(+), 497 deletions(-) create mode 100644 site/img/logo-wide.svg create mode 100644 src/app.nim rename src/{nimpkgs.nim.cfg => app.nim.cfg} (100%) rename src/{ => components}/button.nim (81%) create mode 100644 src/components/footer.nim create mode 100644 src/components/header.nim create mode 100644 src/components/package.nim create mode 100644 src/components/search.nim create mode 100644 src/components/tag.nim create mode 100644 src/context.nim delete mode 100644 src/nimpkgs.nim create mode 100644 src/pages/index.nim create mode 100644 src/pages/metrics.nim create mode 100644 src/pages/notfound.nim create mode 100644 src/pages/package.nim create mode 100644 src/pages/pages.nim create mode 100644 src/pages/search.nim create mode 100644 src/style.nim create mode 100644 src/utils.nim diff --git a/.gitignore b/.gitignore index 3c61b85..ab7a93f 100644 --- a/.gitignore +++ b/.gitignore @@ -133,7 +133,10 @@ dist ## *.workspace +nim.cfg site/uno.css -site/nimpkgs.js -src/nim.cfg -src/packages +site/app.js +src/*.js + +# for debugging +site/nimpkgs.json diff --git a/config.nims b/config.nims index b18fea5..d311cdf 100644 --- a/config.nims +++ b/config.nims @@ -1,20 +1,12 @@ -import std/[strutils, strformat] - -proc getCommitInfo*(): (string, string) = - if not dirExists "src/packages": - echo "cloning nim-lang/packages" - discard staticExec "git clone https://github.com/nim-lang/packages.git src/packages" - let output = (staticExec "git -C src/packages show -q --format='%h %H'").split() - return (output[0], output[1]) +switch("backend","js") task setup, "run atlas init": exec "atlas init --deps=.workspace" exec "atlas install" task build, "build": - let (short,long) = getCommitInfo() - selfExec fmt"js -o:site/nimpkgs.js -d:packagesHash:{long} -d:packagesHashAbbr:{short} -d:release src/nimpkgs.nim" + selfExec "js -o:site/app.js -d:release src/app.nim" exec "pnpm run build" task watch, "rebuild on change": - exec "watchexec -w src nim js -d:packagesHash:master -o:site/nimpkgs.js src/nimpkgs.nim" + exec "watchexec -w src nim js -d:packagesHash:master -o:site/app.js src/app.nim" diff --git a/nimpkgs.nimble b/nimpkgs.nimble index f21ad89..0ea1833 100644 --- a/nimpkgs.nimble +++ b/nimpkgs.nimble @@ -1,17 +1,7 @@ -# Package - -version = "2023.1001" -author = "Daylin Morgan" -description = "nim-lang packages alternate ui" -license = "MIT" -srcDir = "src" -bin = @["nimpkgs"] - - # Dependencies - requires "nim >= 2.0.0" requires "karax" requires "jsony" + diff --git a/package.json b/package.json index 88e7eba..745a369 100644 --- a/package.json +++ b/package.json @@ -4,22 +4,23 @@ "server": "http-server ./site", "watch": "nim watch", "build": "pnpm run uno:prd && pnpm run minify", - "minify": "esbuild --minify --outdir=site --allow-overwrite site/nimpkgs.js site/uno.css", + "minify": "esbuild --minify --outdir=site --allow-overwrite site/app.js site/uno.css", "uno:dev": "unocss \"./site/**/*.html\" \"./src/**/*.nim\" --out-file site/uno.css -w", "uno:prd": "unocss \"./site/**/*.html\" \"./src/**/*.nim\" --out-file site/uno.css" }, "author": "Daylin Morgan", "license": "MIT", - "dependencies": { + "devDependencies": { "@catppuccin/palette": "^0.2.0", + "@iconify-json/mdi": "^1.1.55", + "@iconify-json/simple-icons": "^1.1.79", "@types/promise-fs": "^2.1.5", "@unocss/cli": "^0.57.3", + "@unocss/preset-icons": "^0.57.7", "@unocss/reset": "^0.57.3", - "unocss": "^0.57.3" - }, - "devDependencies": { "concurrently": "^8.2.2", "esbuild": "^0.19.5", - "http-server": "^14.1.1" + "http-server": "^14.1.1", + "unocss": "^0.57.3" } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index ad71a65..07d5c56 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -4,24 +4,28 @@ settings: autoInstallPeers: true excludeLinksFromLockfile: false -dependencies: +devDependencies: '@catppuccin/palette': specifier: ^0.2.0 version: 0.2.0 + '@iconify-json/mdi': + specifier: ^1.1.55 + version: 1.1.55 + '@iconify-json/simple-icons': + specifier: ^1.1.79 + version: 1.1.79 '@types/promise-fs': specifier: ^2.1.5 version: 2.1.5 '@unocss/cli': specifier: ^0.57.3 version: 0.57.3 + '@unocss/preset-icons': + specifier: ^0.57.7 + version: 0.57.7 '@unocss/reset': specifier: ^0.57.3 version: 0.57.3 - unocss: - specifier: ^0.57.3 - version: 0.57.3(postcss@8.4.31)(vite@4.5.0) - -devDependencies: concurrently: specifier: ^8.2.2 version: 8.2.2 @@ -31,6 +35,9 @@ devDependencies: http-server: specifier: ^14.1.1 version: 14.1.1 + unocss: + specifier: ^0.57.3 + version: 0.57.3(postcss@8.4.31)(vite@4.5.0) packages: @@ -40,18 +47,18 @@ packages: dependencies: '@jridgewell/gen-mapping': 0.3.3 '@jridgewell/trace-mapping': 0.3.20 - dev: false + dev: true /@antfu/install-pkg@0.1.1: resolution: {integrity: sha512-LyB/8+bSfa0DFGC06zpCEfs89/XoWZwws5ygEa5D+Xsm3OfI+aXQ86VgVG7Acyef+rSZ5HE7J8rrxzrQeM3PjQ==} dependencies: execa: 5.1.1 find-up: 5.0.0 - dev: false + dev: true /@antfu/utils@0.7.6: resolution: {integrity: sha512-pvFiLP2BeOKA/ZOS6jxx4XhKzdVLHDhGlFEaZ2flWWYf2xOqVniqpk38I04DFRyz+L0ASggl7SkItTc+ZLju4w==} - dev: false + dev: true /@babel/runtime@7.23.2: resolution: {integrity: sha512-mM8eg4yl5D6i3lu2QKPuPH4FArvJ8KhTofbE7jwMUv9KX5mBvwPAqnV3MlyBNqdp9RyRKP6Yck8TrfYrPvX3bg==} @@ -62,7 +69,7 @@ packages: /@catppuccin/palette@0.2.0: resolution: {integrity: sha512-PoAMQMEbL8fBEO80eusB+XQg+1i2kxQHw6COwBRC4bVWxWuRroZjm3K6bOdqPHNHKikDIV7wLi9hSG4NoD1FEQ==} - dev: false + dev: true /@esbuild/android-arm64@0.18.20: resolution: {integrity: sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ==} @@ -70,7 +77,7 @@ packages: cpu: [arm64] os: [android] requiresBuild: true - dev: false + dev: true optional: true /@esbuild/android-arm64@0.19.5: @@ -88,7 +95,7 @@ packages: cpu: [arm] os: [android] requiresBuild: true - dev: false + dev: true optional: true /@esbuild/android-arm@0.19.5: @@ -106,7 +113,7 @@ packages: cpu: [x64] os: [android] requiresBuild: true - dev: false + dev: true optional: true /@esbuild/android-x64@0.19.5: @@ -124,7 +131,7 @@ packages: cpu: [arm64] os: [darwin] requiresBuild: true - dev: false + dev: true optional: true /@esbuild/darwin-arm64@0.19.5: @@ -142,7 +149,7 @@ packages: cpu: [x64] os: [darwin] requiresBuild: true - dev: false + dev: true optional: true /@esbuild/darwin-x64@0.19.5: @@ -160,7 +167,7 @@ packages: cpu: [arm64] os: [freebsd] requiresBuild: true - dev: false + dev: true optional: true /@esbuild/freebsd-arm64@0.19.5: @@ -178,7 +185,7 @@ packages: cpu: [x64] os: [freebsd] requiresBuild: true - dev: false + dev: true optional: true /@esbuild/freebsd-x64@0.19.5: @@ -196,7 +203,7 @@ packages: cpu: [arm64] os: [linux] requiresBuild: true - dev: false + dev: true optional: true /@esbuild/linux-arm64@0.19.5: @@ -214,7 +221,7 @@ packages: cpu: [arm] os: [linux] requiresBuild: true - dev: false + dev: true optional: true /@esbuild/linux-arm@0.19.5: @@ -232,7 +239,7 @@ packages: cpu: [ia32] os: [linux] requiresBuild: true - dev: false + dev: true optional: true /@esbuild/linux-ia32@0.19.5: @@ -250,7 +257,7 @@ packages: cpu: [loong64] os: [linux] requiresBuild: true - dev: false + dev: true optional: true /@esbuild/linux-loong64@0.19.5: @@ -268,7 +275,7 @@ packages: cpu: [mips64el] os: [linux] requiresBuild: true - dev: false + dev: true optional: true /@esbuild/linux-mips64el@0.19.5: @@ -286,7 +293,7 @@ packages: cpu: [ppc64] os: [linux] requiresBuild: true - dev: false + dev: true optional: true /@esbuild/linux-ppc64@0.19.5: @@ -304,7 +311,7 @@ packages: cpu: [riscv64] os: [linux] requiresBuild: true - dev: false + dev: true optional: true /@esbuild/linux-riscv64@0.19.5: @@ -322,7 +329,7 @@ packages: cpu: [s390x] os: [linux] requiresBuild: true - dev: false + dev: true optional: true /@esbuild/linux-s390x@0.19.5: @@ -340,7 +347,7 @@ packages: cpu: [x64] os: [linux] requiresBuild: true - dev: false + dev: true optional: true /@esbuild/linux-x64@0.19.5: @@ -358,7 +365,7 @@ packages: cpu: [x64] os: [netbsd] requiresBuild: true - dev: false + dev: true optional: true /@esbuild/netbsd-x64@0.19.5: @@ -376,7 +383,7 @@ packages: cpu: [x64] os: [openbsd] requiresBuild: true - dev: false + dev: true optional: true /@esbuild/openbsd-x64@0.19.5: @@ -394,7 +401,7 @@ packages: cpu: [x64] os: [sunos] requiresBuild: true - dev: false + dev: true optional: true /@esbuild/sunos-x64@0.19.5: @@ -412,7 +419,7 @@ packages: cpu: [arm64] os: [win32] requiresBuild: true - dev: false + dev: true optional: true /@esbuild/win32-arm64@0.19.5: @@ -430,7 +437,7 @@ packages: cpu: [ia32] os: [win32] requiresBuild: true - dev: false + dev: true optional: true /@esbuild/win32-ia32@0.19.5: @@ -448,7 +455,7 @@ packages: cpu: [x64] os: [win32] requiresBuild: true - dev: false + dev: true optional: true /@esbuild/win32-x64@0.19.5: @@ -460,9 +467,21 @@ packages: dev: true optional: true + /@iconify-json/mdi@1.1.55: + resolution: {integrity: sha512-ycnFub+EQx+3D/aDCg6iC7sjexOUa5GzxUNIZFFl0Pq7aDxbmhIludoyYnguEO3REyWf9FcOOmvVcQkdtwKHTw==} + dependencies: + '@iconify/types': 2.0.0 + dev: true + + /@iconify-json/simple-icons@1.1.79: + resolution: {integrity: sha512-QayoZelr/QyYn0ALkOoBQDEseUGeNAZoQ9i25qfCeKxc7HEdvUU8cUc4/V/1n3FxohAtdi3oPdyILIhR5T1TVw==} + dependencies: + '@iconify/types': 2.0.0 + dev: true + /@iconify/types@2.0.0: resolution: {integrity: sha512-+wluvCrRhXrhyOmRDJ3q8mux9JkKy5SJ/v8ol2tu4FVjyYvtEzkc/3pK15ET6RKg4b4w4BmTk1+gsCUhf21Ykg==} - dev: false + dev: true /@iconify/utils@2.1.11: resolution: {integrity: sha512-M/w3PkN8zQYXi8N6qK/KhnYMfEbbb6Sk8RZVn8g+Pmmu5ybw177RpsaGwpziyHeUsu4etrexYSWq3rwnIqzYCg==} @@ -475,7 +494,7 @@ packages: local-pkg: 0.4.3 transitivePeerDependencies: - supports-color - dev: false + dev: true /@jridgewell/gen-mapping@0.3.3: resolution: {integrity: sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==} @@ -484,28 +503,28 @@ packages: '@jridgewell/set-array': 1.1.2 '@jridgewell/sourcemap-codec': 1.4.15 '@jridgewell/trace-mapping': 0.3.20 - dev: false + dev: true /@jridgewell/resolve-uri@3.1.1: resolution: {integrity: sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==} engines: {node: '>=6.0.0'} - dev: false + dev: true /@jridgewell/set-array@1.1.2: resolution: {integrity: sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==} engines: {node: '>=6.0.0'} - dev: false + dev: true /@jridgewell/sourcemap-codec@1.4.15: resolution: {integrity: sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==} - dev: false + dev: true /@jridgewell/trace-mapping@0.3.20: resolution: {integrity: sha512-R8LcPeWZol2zR8mmH3JeKQ6QRCFb7XgUhV9ZlGhHLGyg4wpPiPZNQOOWhFZhxKw8u//yTbNGI42Bx/3paXEQ+Q==} dependencies: '@jridgewell/resolve-uri': 3.1.1 '@jridgewell/sourcemap-codec': 1.4.15 - dev: false + dev: true /@nodelib/fs.scandir@2.1.5: resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} @@ -513,12 +532,12 @@ packages: dependencies: '@nodelib/fs.stat': 2.0.5 run-parallel: 1.2.0 - dev: false + dev: true /@nodelib/fs.stat@2.0.5: resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==} engines: {node: '>= 8'} - dev: false + dev: true /@nodelib/fs.walk@1.2.8: resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} @@ -526,11 +545,11 @@ packages: dependencies: '@nodelib/fs.scandir': 2.1.5 fastq: 1.15.0 - dev: false + dev: true /@polka/url@1.0.0-next.23: resolution: {integrity: sha512-C16M+IYz0rgRhWZdCmK+h58JMv8vijAA61gmz2rspCSwKwzBebpdcsiUmwrtJRdphuY30i6BSLEOP8ppbNLyLg==} - dev: false + dev: true /@rollup/pluginutils@5.0.5: resolution: {integrity: sha512-6aEYR910NyP73oHiJglti74iRyOwgFU4x3meH/H8OJx6Ry0j6cOVZ5X/wTvub7G7Ao6qaHBEaNsV3GLJkSsF+Q==} @@ -544,23 +563,23 @@ packages: '@types/estree': 1.0.5 estree-walker: 2.0.2 picomatch: 2.3.1 - dev: false + dev: true /@types/estree@1.0.5: resolution: {integrity: sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==} - dev: false + dev: true /@types/node@20.9.0: resolution: {integrity: sha512-nekiGu2NDb1BcVofVcEKMIwzlx4NjHlcjhoxxKBNLtz15Y1z7MYf549DFvkHSId02Ax6kGwWntIBPC3l/JZcmw==} dependencies: undici-types: 5.26.5 - dev: false + dev: true /@types/promise-fs@2.1.5: resolution: {integrity: sha512-C8bi4Xh6HlixkGspIDaX/zFA+r1+UHUuXYJCCqi6oBlVjxF870kPv38aJlSRo0u1j+2YBi0PLP7PGMZIBbCQ6Q==} dependencies: '@types/node': 20.9.0 - dev: false + dev: true /@unocss/astro@0.57.3(vite@4.5.0): resolution: {integrity: sha512-Kwu/k8iGNVrMtOuzJ7jKOvjYZFZz3recSxd7ceDp5Hi5SMsmjvXXHzkQ1Iypj1g0nczWcX4U+krROr2EH0GlnA==} @@ -576,7 +595,7 @@ packages: vite: 4.5.0 transitivePeerDependencies: - rollup - dev: false + dev: true /@unocss/cli@0.57.3: resolution: {integrity: sha512-F5k0IjkbHFlZDcGAUr7UTa2xehxobfqWzooDL0tU9PtvAk6S4Edf5Iq0HymAcVK1k9yO17i7Pvg6dw7gOM0TIg==} @@ -598,7 +617,7 @@ packages: perfect-debounce: 1.0.0 transitivePeerDependencies: - rollup - dev: false + dev: true /@unocss/config@0.57.3: resolution: {integrity: sha512-jrjvmcrrdiHHLqp6LBpHWs7VAnumFK3fEdMH7celRe+99CTOvRn73caUThyD2Ftt8rDIMejmteR1hqVBH51kug==} @@ -606,17 +625,21 @@ packages: dependencies: '@unocss/core': 0.57.3 unconfig: 0.3.11 - dev: false + dev: true /@unocss/core@0.57.3: resolution: {integrity: sha512-o6snDo5vwAenIqA+wjjI6BUsftJXXSqrPHYqplb+QX5bLfxW/OU1xhBRlnhiP0BOGGZXqgGEETU1ym8MM9bLwA==} - dev: false + dev: true + + /@unocss/core@0.57.7: + resolution: {integrity: sha512-1d36M0CV3yC80J0pqOa5rH1BX6g2iZdtKmIb3oSBN4AWnMCSrrJEPBrUikyMq2TEQTrYWJIVDzv5A9hBUat3TA==} + dev: true /@unocss/extractor-arbitrary-variants@0.57.3: resolution: {integrity: sha512-OmF+2TjJ97i7KOCR8wPgZK/pkp8Rcfo4tzqT/4jBUIi7rfDGZx/eE3aZKFpZSZlUuTH5cdReaKxymXQmJ4dibA==} dependencies: '@unocss/core': 0.57.3 - dev: false + dev: true /@unocss/inspector@0.57.3: resolution: {integrity: sha512-Oj5cUbuwx+4/rckW3mfpdKMWzhOOSehXChzuJ7x7tMDDB5ywdHwnDsxtK07Y+5UwKHC322T3I3VtLolOfsdlCA==} @@ -625,7 +648,7 @@ packages: '@unocss/rule-utils': 0.57.3 gzip-size: 6.0.0 sirv: 2.0.3 - dev: false + dev: true /@unocss/postcss@0.57.3(postcss@8.4.31): resolution: {integrity: sha512-rYXQ2/iXeF59/g8xbvoyYJ9EClQCBcWj2oeJCt85dykOYyQJCWJT+LoYF0s/kvg7m+x5ovdNQfXtAACLYBqh9g==} @@ -640,13 +663,13 @@ packages: fast-glob: 3.3.2 magic-string: 0.30.5 postcss: 8.4.31 - dev: false + dev: true /@unocss/preset-attributify@0.57.3: resolution: {integrity: sha512-leX9jxM2PnqvZn42thDb2rPdE0nq6WtIr98pvdnkRZKt5gLwtOJCANXH/gVP6tPdRRf6FiZstA8jvAxVGL1sIA==} dependencies: '@unocss/core': 0.57.3 - dev: false + dev: true /@unocss/preset-icons@0.57.3: resolution: {integrity: sha512-cG7gaFQzSidHS+nHPV9HEB3aaUVs/PjZywxMl5jwkJIWHuFMU/SQZXMorH6avU2jH8PoYkRZfjLdRWA+h/+fPA==} @@ -656,7 +679,17 @@ packages: ofetch: 1.3.3 transitivePeerDependencies: - supports-color - dev: false + dev: true + + /@unocss/preset-icons@0.57.7: + resolution: {integrity: sha512-s3AelKCS9CL1ArP1GanYv0XxxPrcFi+XOuQoQCwCRHDo2CiBEq3fLLMIhaUCFEWGtIy7o7wLeL5BRjMvJ2QnMg==} + dependencies: + '@iconify/utils': 2.1.11 + '@unocss/core': 0.57.7 + ofetch: 1.3.3 + transitivePeerDependencies: + - supports-color + dev: true /@unocss/preset-mini@0.57.3: resolution: {integrity: sha512-2KFxbbxRqhc+0fyWNYSiRGGr+3jp4jEQIRnjT8sv5uAMo1OaUmUTwz2qzYhSc3sCM8ZEofblZY2BOcqJwZ5yxA==} @@ -664,20 +697,20 @@ packages: '@unocss/core': 0.57.3 '@unocss/extractor-arbitrary-variants': 0.57.3 '@unocss/rule-utils': 0.57.3 - dev: false + dev: true /@unocss/preset-tagify@0.57.3: resolution: {integrity: sha512-GXs5Hu6XtHcIRLexPghHkfb6ekSodh4Xs8895xrvP5H7Tm/+wEIHALXkW762Rujl1Rtq+xzxAeCoeFxW+y9eLw==} dependencies: '@unocss/core': 0.57.3 - dev: false + dev: true /@unocss/preset-typography@0.57.3: resolution: {integrity: sha512-C/pIfRY56wxBuV4bTIeZMZYMmYc0gD8DU+sJSPWiZJP1JHiLc3FzSnc51BYcT/Dqdx0fDWhJyP2qqo9000VFKQ==} dependencies: '@unocss/core': 0.57.3 '@unocss/preset-mini': 0.57.3 - dev: false + dev: true /@unocss/preset-uno@0.57.3: resolution: {integrity: sha512-dLZrFc6GrE5J0zAZMFXk/c4WKq7fmU0jCgHvbDXLGdKdJ7zpByslhc2YTPqkLW40F6+73SCN7DlARInSh2fa4g==} @@ -686,14 +719,14 @@ packages: '@unocss/preset-mini': 0.57.3 '@unocss/preset-wind': 0.57.3 '@unocss/rule-utils': 0.57.3 - dev: false + dev: true /@unocss/preset-web-fonts@0.57.3: resolution: {integrity: sha512-W/voQjgo98oj/D/oGrhL4xAS0XsR6fF9yULu3xf4nWrUkdkZq/64/rOM5uLBgUFSmkulW524Dsjd1INYmPzz8w==} dependencies: '@unocss/core': 0.57.3 ofetch: 1.3.3 - dev: false + dev: true /@unocss/preset-wind@0.57.3: resolution: {integrity: sha512-LymBZtNK86qEpLpbH5eOAiHNFvkIAjfL+Jlok5xI/yO/GCqjnTiw1QAxu2vxLUnQlqlvu7IykOx+Hk1nNvkSaA==} @@ -701,11 +734,11 @@ packages: '@unocss/core': 0.57.3 '@unocss/preset-mini': 0.57.3 '@unocss/rule-utils': 0.57.3 - dev: false + dev: true /@unocss/reset@0.57.3: resolution: {integrity: sha512-E6Q8jucQlVLOM+d+F5DKGi/8GVc8KDwAQnbcpbrGL/1iix4IM3emRkPmujgTLWS+HIRRcWcEvT6sNwnd9r6H2A==} - dev: false + dev: true /@unocss/rule-utils@0.57.3: resolution: {integrity: sha512-koWXeRJHFt/SJdb3m7s/2+NrBCcUtl67SX7rSHJc99Z+dwZgIsPUfdfRKM4mZD43MayybvDrd1Wue2LNQg5R/g==} @@ -713,29 +746,29 @@ packages: dependencies: '@unocss/core': 0.57.3 magic-string: 0.30.5 - dev: false + dev: true /@unocss/scope@0.57.3: resolution: {integrity: sha512-hL0Gjd5getA6ziiOvu1M2Jw5e+FnD9rzu+t+4SnxWcpP+bZtu+LBrt5FeqrizwUHfE/723iuEvg16W5hjhGLQA==} - dev: false + dev: true /@unocss/transformer-attributify-jsx-babel@0.57.3: resolution: {integrity: sha512-b5esljHAz274tv0sXe8GmHew7FXzwkRQrod6NdR9pyFlPQ9gn7gxi0MIsvIV0U8PdSz3HOHOuT0tU/zphjaJDA==} dependencies: '@unocss/core': 0.57.3 - dev: false + dev: true /@unocss/transformer-attributify-jsx@0.57.3: resolution: {integrity: sha512-OgejFNN7AcCgudh/HGe2BS00TbRv7Bi+siWeUS7AEGEG+p7cQZn92XljCFZGqIyvgfVWypb6/xve9H4oY3/E+w==} dependencies: '@unocss/core': 0.57.3 - dev: false + dev: true /@unocss/transformer-compile-class@0.57.3: resolution: {integrity: sha512-DqmRTQujqAdk4uSrqy+t9xSVmKM9E3yW9PCwDxI1evva0/qTFexzjoR42glq8x7LSn0ZmFyflXcQoeXmwjsBrg==} dependencies: '@unocss/core': 0.57.3 - dev: false + dev: true /@unocss/transformer-directives@0.57.3: resolution: {integrity: sha512-GXedqnb0PB+XkjdfNEInuLxxLjPbaCQLCUhSvTcw67+kalGgX2Mn/hYwpSHmDMLe+Uld5n0vcJRu2a8chBdAwA==} @@ -743,13 +776,13 @@ packages: '@unocss/core': 0.57.3 '@unocss/rule-utils': 0.57.3 css-tree: 2.3.1 - dev: false + dev: true /@unocss/transformer-variant-group@0.57.3: resolution: {integrity: sha512-PpKtnwyb4ncjDhsTm/PtiL0RUdmaee+07W0AzSEz29IFFwyrueIP6WHmD6agKmgDPoaw5Ywebt6DdkSbnfYHzw==} dependencies: '@unocss/core': 0.57.3 - dev: false + dev: true /@unocss/vite@0.57.3(vite@4.5.0): resolution: {integrity: sha512-SX2wtxRFLka0CgMwqokKuhaBUptj8vcpmLObVRRgV+7dSdx6GMbZcjZfQfibMKhJY3d5iSAylcfyW2JqTX2F+g==} @@ -769,13 +802,13 @@ packages: vite: 4.5.0 transitivePeerDependencies: - rollup - dev: false + dev: true /acorn@8.11.2: resolution: {integrity: sha512-nc0Axzp/0FILLEVsm4fNwLCwMttvhEI263QtVPQcbpfZZ3ts0hLsZGOpE6czNlid7CJ9MlyH8reXkpsf3YUY4w==} engines: {node: '>=0.4.0'} hasBin: true - dev: false + dev: true /ansi-regex@5.0.1: resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} @@ -795,7 +828,7 @@ packages: dependencies: normalize-path: 3.0.0 picomatch: 2.3.1 - dev: false + dev: true /async@2.6.4: resolution: {integrity: sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA==} @@ -813,19 +846,19 @@ packages: /binary-extensions@2.2.0: resolution: {integrity: sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==} engines: {node: '>=8'} - dev: false + dev: true /braces@3.0.2: resolution: {integrity: sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==} engines: {node: '>=8'} dependencies: fill-range: 7.0.1 - dev: false + dev: true /cac@6.7.14: resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==} engines: {node: '>=8'} - dev: false + dev: true /call-bind@1.0.5: resolution: {integrity: sha512-C3nQxfFZxFRVoJoGKKI8y3MOEo129NQ+FgQ08iye+Mk4zNZZGdjfs06bVTr+DBSlA66Q2VEcMki/cUCP4SercQ==} @@ -856,7 +889,7 @@ packages: readdirp: 3.6.0 optionalDependencies: fsevents: 2.3.3 - dev: false + dev: true /cliui@8.0.1: resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==} @@ -880,7 +913,7 @@ packages: /colorette@2.0.20: resolution: {integrity: sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==} - dev: false + dev: true /concurrently@8.2.2: resolution: {integrity: sha512-1dP4gpXFhei8IOtlXRE/T/4H88ElHgTiUzh71YUmtjTEHMSRS2Z/fgOxHSxxusGHogsRfxNq1vyAwxSC+EVyDg==} @@ -901,7 +934,7 @@ packages: /consola@3.2.3: resolution: {integrity: sha512-I5qxpzLv+sJhTVEoLYNcTW+bThDCPsit0vLNKShZx6rLtpilNpmmeTPaeqJb9ZE9dV3DGaeby6Vuhrw38WjeyQ==} engines: {node: ^14.18.0 || >=16.10.0} - dev: false + dev: true /corser@2.0.1: resolution: {integrity: sha512-utCYNzRSQIZNPIcGZdQc92UVJYAhtGAteCFg0yRaFm8f0P+CPtyGyHXJcGXnffjCybUCEx3FQ2G7U3/o9eIkVQ==} @@ -915,7 +948,7 @@ packages: path-key: 3.1.1 shebang-command: 2.0.0 which: 2.0.2 - dev: false + dev: true /css-tree@2.3.1: resolution: {integrity: sha512-6Fv1DV/TYw//QF5IzQdqsNDjx/wc8TrMBZsqjL9eW01tWb7R7k/mq+/VXfJCl7SoD5emsJop9cOByJZfs8hYIw==} @@ -923,7 +956,7 @@ packages: dependencies: mdn-data: 2.0.30 source-map-js: 1.0.2 - dev: false + dev: true /date-fns@2.30.0: resolution: {integrity: sha512-fnULvOpxnC5/Vg3NCiWelDsLiUc9bRwAPs/+LfTLNvetFCtCTN+yQz15C/fs4AwX1R9K5GLtLfn8QW+dWisaAw==} @@ -953,7 +986,7 @@ packages: optional: true dependencies: ms: 2.1.2 - dev: false + dev: true /define-data-property@1.1.1: resolution: {integrity: sha512-E7uGkTzkk1d0ByLeSc6ZsFS79Axg+m1P/VsgYsxHgiuc3tFSj+MjMIwe90FC4lOAZzNBdY7kkO2P2wKdsQ1vgQ==} @@ -966,15 +999,15 @@ packages: /defu@6.1.3: resolution: {integrity: sha512-Vy2wmG3NTkmHNg/kzpuvHhkqeIx3ODWqasgCRbKtbXEN0G+HpEEv9BtJLp7ZG1CZloFaC41Ah3ZFbq7aqCqMeQ==} - dev: false + dev: true /destr@2.0.2: resolution: {integrity: sha512-65AlobnZMiCET00KaFFjUefxDX0khFA/E4myqZ7a6Sq1yZtR8+FVIvilVX66vF2uobSumxooYZChiRPCKNqhmg==} - dev: false + dev: true /duplexer@0.1.2: resolution: {integrity: sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==} - dev: false + dev: true /emoji-regex@8.0.0: resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} @@ -1008,7 +1041,7 @@ packages: '@esbuild/win32-arm64': 0.18.20 '@esbuild/win32-ia32': 0.18.20 '@esbuild/win32-x64': 0.18.20 - dev: false + dev: true /esbuild@0.19.5: resolution: {integrity: sha512-bUxalY7b1g8vNhQKdB24QDmHeY4V4tw/s6Ak5z+jJX9laP5MoQseTOMemAr0gxssjNcH0MCViG8ONI2kksvfFQ==} @@ -1047,7 +1080,7 @@ packages: /estree-walker@2.0.2: resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==} - dev: false + dev: true /eventemitter3@4.0.7: resolution: {integrity: sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==} @@ -1066,7 +1099,7 @@ packages: onetime: 5.1.2 signal-exit: 3.0.7 strip-final-newline: 2.0.0 - dev: false + dev: true /fast-glob@3.3.2: resolution: {integrity: sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==} @@ -1077,20 +1110,20 @@ packages: glob-parent: 5.1.2 merge2: 1.4.1 micromatch: 4.0.5 - dev: false + dev: true /fastq@1.15.0: resolution: {integrity: sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==} dependencies: reusify: 1.0.4 - dev: false + dev: true /fill-range@7.0.1: resolution: {integrity: sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==} engines: {node: '>=8'} dependencies: to-regex-range: 5.0.1 - dev: false + dev: true /find-up@5.0.0: resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} @@ -1098,7 +1131,7 @@ packages: dependencies: locate-path: 6.0.0 path-exists: 4.0.0 - dev: false + dev: true /follow-redirects@1.15.3: resolution: {integrity: sha512-1VzOtuEM8pC9SFU1E+8KfTjZyMztRsgEfwQl44z8A25uy13jSzTj6dyK2Df52iV0vgHCfBwLhDWevLn95w5v6Q==} @@ -1115,7 +1148,7 @@ packages: engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} os: [darwin] requiresBuild: true - dev: false + dev: true optional: true /function-bind@1.1.2: @@ -1139,14 +1172,14 @@ packages: /get-stream@6.0.1: resolution: {integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==} engines: {node: '>=10'} - dev: false + dev: true /glob-parent@5.1.2: resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} engines: {node: '>= 6'} dependencies: is-glob: 4.0.3 - dev: false + dev: true /gopd@1.0.1: resolution: {integrity: sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==} @@ -1159,7 +1192,7 @@ packages: engines: {node: '>=10'} dependencies: duplexer: 0.1.2 - dev: false + dev: true /has-flag@4.0.0: resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} @@ -1238,7 +1271,7 @@ packages: /human-signals@2.1.0: resolution: {integrity: sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==} engines: {node: '>=10.17.0'} - dev: false + dev: true /iconv-lite@0.6.3: resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==} @@ -1252,12 +1285,12 @@ packages: engines: {node: '>=8'} dependencies: binary-extensions: 2.2.0 - dev: false + dev: true /is-extglob@2.1.1: resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} engines: {node: '>=0.10.0'} - dev: false + dev: true /is-fullwidth-code-point@3.0.0: resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} @@ -1269,46 +1302,46 @@ packages: engines: {node: '>=0.10.0'} dependencies: is-extglob: 2.1.1 - dev: false + dev: true /is-number@7.0.0: resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} engines: {node: '>=0.12.0'} - dev: false + dev: true /is-stream@2.0.1: resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==} engines: {node: '>=8'} - dev: false + dev: true /isexe@2.0.0: resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} - dev: false + dev: true /jiti@1.21.0: resolution: {integrity: sha512-gFqAIbuKyyso/3G2qhiO2OM6shY6EPP/R0+mkDbyspxKazh8BXDC5FiFsUjlczgdNz/vfra0da2y+aHrusLG/Q==} hasBin: true - dev: false + dev: true /jsonc-parser@3.2.0: resolution: {integrity: sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==} - dev: false + dev: true /kolorist@1.8.0: resolution: {integrity: sha512-Y+60/zizpJ3HRH8DCss+q95yr6145JXZo46OTpFvDZWLfRCE4qChOyk1b26nMaNpfHHgxagk9dXT5OP0Tfe+dQ==} - dev: false + dev: true /local-pkg@0.4.3: resolution: {integrity: sha512-SFppqq5p42fe2qcZQqqEOiVRXl+WCP1MdT6k7BDEW1j++sp5fIY+/fdRQitvKgB5BrBcmrs5m/L0v2FrU5MY1g==} engines: {node: '>=14'} - dev: false + dev: true /locate-path@6.0.0: resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} engines: {node: '>=10'} dependencies: p-locate: 5.0.0 - dev: false + dev: true /lodash@4.17.21: resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} @@ -1319,20 +1352,20 @@ packages: engines: {node: '>=12'} dependencies: '@jridgewell/sourcemap-codec': 1.4.15 - dev: false + dev: true /mdn-data@2.0.30: resolution: {integrity: sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==} - dev: false + dev: true /merge-stream@2.0.0: resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==} - dev: false + dev: true /merge2@1.4.1: resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} engines: {node: '>= 8'} - dev: false + dev: true /micromatch@4.0.5: resolution: {integrity: sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==} @@ -1340,7 +1373,7 @@ packages: dependencies: braces: 3.0.2 picomatch: 2.3.1 - dev: false + dev: true /mime@1.6.0: resolution: {integrity: sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==} @@ -1351,7 +1384,7 @@ packages: /mimic-fn@2.1.0: resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==} engines: {node: '>=6'} - dev: false + dev: true /minimist@1.2.8: resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} @@ -1371,16 +1404,16 @@ packages: pathe: 1.1.1 pkg-types: 1.0.3 ufo: 1.3.1 - dev: false + dev: true /mrmime@1.0.1: resolution: {integrity: sha512-hzzEagAgDyoU1Q6yg5uI+AorQgdvMCur3FcKf7NhMKWsaYg+RnbTyHRa/9IlLF9rf455MOCtcqqrQQ83pPP7Uw==} engines: {node: '>=10'} - dev: false + dev: true /ms@2.1.2: resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==} - dev: false + dev: true /ms@2.1.3: resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} @@ -1390,23 +1423,23 @@ packages: resolution: {integrity: sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==} engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} hasBin: true - dev: false + dev: true /node-fetch-native@1.4.1: resolution: {integrity: sha512-NsXBU0UgBxo2rQLOeWNZqS3fvflWePMECr8CoSWoSTqCqGbVVsvl9vZu1HfQicYN0g5piV9Gh8RTEvo/uP752w==} - dev: false + dev: true /normalize-path@3.0.0: resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} engines: {node: '>=0.10.0'} - dev: false + dev: true /npm-run-path@4.0.1: resolution: {integrity: sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==} engines: {node: '>=8'} dependencies: path-key: 3.1.1 - dev: false + dev: true /object-inspect@1.13.1: resolution: {integrity: sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==} @@ -1418,14 +1451,14 @@ packages: destr: 2.0.2 node-fetch-native: 1.4.1 ufo: 1.3.1 - dev: false + dev: true /onetime@5.1.2: resolution: {integrity: sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==} engines: {node: '>=6'} dependencies: mimic-fn: 2.1.0 - dev: false + dev: true /opener@1.5.2: resolution: {integrity: sha512-ur5UIdyw5Y7yEj9wLzhqXiy6GZ3Mwx0yGI+5sMn2r0N0v3cKJvUmFH5yPP+WXh9e0xfyzyJX95D8l088DNFj7A==} @@ -1437,41 +1470,41 @@ packages: engines: {node: '>=10'} dependencies: yocto-queue: 0.1.0 - dev: false + dev: true /p-locate@5.0.0: resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} engines: {node: '>=10'} dependencies: p-limit: 3.1.0 - dev: false + dev: true /path-exists@4.0.0: resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} engines: {node: '>=8'} - dev: false + dev: true /path-key@3.1.1: resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} engines: {node: '>=8'} - dev: false + dev: true /pathe@1.1.1: resolution: {integrity: sha512-d+RQGp0MAYTIaDBIMmOfMwz3E+LOZnxx1HZd5R18mmCZY0QBlK0LDZfPc8FW8Ed2DlvsuE6PRjroDY+wg4+j/Q==} - dev: false + dev: true /perfect-debounce@1.0.0: resolution: {integrity: sha512-xCy9V055GLEqoFaHoC1SoLIaLmWctgCUaBaWxDZ7/Zx4CTyX7cJQLJOok/orfjZAh9kEYpjJa4d0KcJmCbctZA==} - dev: false + dev: true /picocolors@1.0.0: resolution: {integrity: sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==} - dev: false + dev: true /picomatch@2.3.1: resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} engines: {node: '>=8.6'} - dev: false + dev: true /pkg-types@1.0.3: resolution: {integrity: sha512-nN7pYi0AQqJnoLPC9eHFQ8AcyaixBUOwvqc5TDnIKCMEE6I0y8P7OKA7fPexsXGCGxQDl/cmrLAp26LhcwxZ4A==} @@ -1479,7 +1512,7 @@ packages: jsonc-parser: 3.2.0 mlly: 1.4.2 pathe: 1.1.1 - dev: false + dev: true /portfinder@1.0.32: resolution: {integrity: sha512-on2ZJVVDXRADWE6jnQaX0ioEylzgBpQk8r55NE4wjXW1ZxO+BgDlY6DXwj20i0V8eB4SenDQ00WEaxfiIQPcxg==} @@ -1499,7 +1532,7 @@ packages: nanoid: 3.3.7 picocolors: 1.0.0 source-map-js: 1.0.2 - dev: false + dev: true /qs@6.11.2: resolution: {integrity: sha512-tDNIz22aBzCDxLtVH++VnTfzxlfeK5CbqohpSqpJgj1Wg/cQbStNAz3NuqCs5vV+pjBsK4x4pN9HlVh7rcYRiA==} @@ -1510,14 +1543,14 @@ packages: /queue-microtask@1.2.3: resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} - dev: false + dev: true /readdirp@3.6.0: resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} engines: {node: '>=8.10.0'} dependencies: picomatch: 2.3.1 - dev: false + dev: true /regenerator-runtime@0.14.0: resolution: {integrity: sha512-srw17NI0TUWHuGa5CFGGmhfNIeja30WMBfbslPNhf6JrqQlLN5gcrvig1oqPxiVaXb0oW0XRKtH6Nngs5lKCIA==} @@ -1535,7 +1568,7 @@ packages: /reusify@1.0.4: resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==} engines: {iojs: '>=1.0.0', node: '>=0.10.0'} - dev: false + dev: true /rollup@3.29.4: resolution: {integrity: sha512-oWzmBZwvYrU0iJHtDmhsm662rC15FRXmcjCk1xD771dFDx5jJ02ufAQQTn0etB2emNk4J9EZg/yWKpsn9BWGRw==} @@ -1543,13 +1576,13 @@ packages: hasBin: true optionalDependencies: fsevents: 2.3.3 - dev: false + dev: true /run-parallel@1.2.0: resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} dependencies: queue-microtask: 1.2.3 - dev: false + dev: true /rxjs@7.8.1: resolution: {integrity: sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==} @@ -1584,12 +1617,12 @@ packages: engines: {node: '>=8'} dependencies: shebang-regex: 3.0.0 - dev: false + dev: true /shebang-regex@3.0.0: resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} engines: {node: '>=8'} - dev: false + dev: true /shell-quote@1.8.1: resolution: {integrity: sha512-6j1W9l1iAs/4xYBI1SYOVZyFcCis9b4KCLQ8fgAGG07QvzaRLVVRQvAy85yNmmZSjYjg4MWh4gNvlPujU/5LpA==} @@ -1605,7 +1638,7 @@ packages: /signal-exit@3.0.7: resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==} - dev: false + dev: true /sirv@2.0.3: resolution: {integrity: sha512-O9jm9BsID1P+0HOi81VpXPoDxYP374pkOLzACAoyUQ/3OUVndNpsz6wMnY2z+yOxzbllCKZrM+9QrWsv4THnyA==} @@ -1614,12 +1647,12 @@ packages: '@polka/url': 1.0.0-next.23 mrmime: 1.0.1 totalist: 3.0.1 - dev: false + dev: true /source-map-js@1.0.2: resolution: {integrity: sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==} engines: {node: '>=0.10.0'} - dev: false + dev: true /spawn-command@0.0.2: resolution: {integrity: sha512-zC8zGoGkmc8J9ndvml8Xksr1Amk9qBujgbF0JAIWO7kXr43w0h/0GJNM/Vustixu+YE8N/MTrQ7N31FvHUACxQ==} @@ -1644,7 +1677,7 @@ packages: /strip-final-newline@2.0.0: resolution: {integrity: sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==} engines: {node: '>=6'} - dev: false + dev: true /supports-color@7.2.0: resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} @@ -1665,12 +1698,12 @@ packages: engines: {node: '>=8.0'} dependencies: is-number: 7.0.0 - dev: false + dev: true /totalist@3.0.1: resolution: {integrity: sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==} engines: {node: '>=6'} - dev: false + dev: true /tree-kill@1.2.2: resolution: {integrity: sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==} @@ -1683,7 +1716,7 @@ packages: /ufo@1.3.1: resolution: {integrity: sha512-uY/99gMLIOlJPwATcMVYfqDSxUR9//AUcgZMzwfSTJPDKzA1S8mX4VLqa+fiAtveraQUBCz4FFcwVZBGbwBXIw==} - dev: false + dev: true /unconfig@0.3.11: resolution: {integrity: sha512-bV/nqePAKv71v3HdVUn6UefbsDKQWRX+bJIkiSm0+twIds6WiD2bJLWWT3i214+J/B4edufZpG2w7Y63Vbwxow==} @@ -1692,11 +1725,11 @@ packages: defu: 6.1.3 jiti: 1.21.0 mlly: 1.4.2 - dev: false + dev: true /undici-types@5.26.5: resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==} - dev: false + dev: true /union@0.5.0: resolution: {integrity: sha512-N6uOhuW6zO95P3Mel2I2zMsbsanvvtgn6jVqJv4vbVcz/JN0OkL9suomjQGmWtxJQXOCqUJvquc1sMeNz/IwlA==} @@ -1742,7 +1775,7 @@ packages: - postcss - rollup - supports-color - dev: false + dev: true /url-join@4.0.1: resolution: {integrity: sha512-jk1+QP6ZJqyOiuEI9AEWQfju/nB2Pw466kbA0LEZljHwKeMgd9WrAEgEGxjPDD2+TNbbb37rTyhEfrCXfuKXnA==} @@ -1781,7 +1814,7 @@ packages: rollup: 3.29.4 optionalDependencies: fsevents: 2.3.3 - dev: false + dev: true /whatwg-encoding@2.0.0: resolution: {integrity: sha512-p41ogyeMUrw3jWclHWTQg1k05DSVXPLcVxRTYsXUk+ZooOCZLcoYgPZ/HL/D/N+uQPOtcp1me1WhBEaX02mhWg==} @@ -1796,7 +1829,7 @@ packages: hasBin: true dependencies: isexe: 2.0.0 - dev: false + dev: true /wrap-ansi@7.0.0: resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} @@ -1833,4 +1866,4 @@ packages: /yocto-queue@0.1.0: resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} engines: {node: '>=10'} - dev: false + dev: true diff --git a/site/img/logo-wide.svg b/site/img/logo-wide.svg new file mode 100644 index 0000000..34381a0 --- /dev/null +++ b/site/img/logo-wide.svg @@ -0,0 +1,82 @@ + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + diff --git a/site/index.html b/site/index.html index fc63e2e..0a43563 100644 --- a/site/index.html +++ b/site/index.html @@ -3,7 +3,7 @@ - + nimpkgs - +
- + diff --git a/src/app.nim b/src/app.nim new file mode 100644 index 0000000..6fe8d8b --- /dev/null +++ b/src/app.nim @@ -0,0 +1,30 @@ +import std/strutils +import karax/[karax, karaxdsl, vdom] + +import components/[header, button, footer] +import pages/pages +import context +import jsconsole + +proc render(data: RouterData): VNode = + console.log ctx + result = buildHtml(tdiv(class = "lg:w-3/4 max-w-[90%] mx-auto md:text-lg text-sm min-h-screen flex flex-col")): + headerBar() + tdiv(class = "mb-5"): + if not ctx.loaded: + tdiv(class = "flex h-50"): + tdiv(class = "mx-auto my-auto lds-dual-ring") + else: + case data.hashPart + of "#/index", "": index.render() + of "#/search": search.render() + of "#/metrics": metrics.render() + else: + if ($data.hashPart).startswith("#/pkg/"): + package.render(($data.hashPart).replace("#/pkg/", "")) + else: + notfound.render() + footerBar() + scrollToTopButton() + +setRenderer render diff --git a/src/nimpkgs.nim.cfg b/src/app.nim.cfg similarity index 100% rename from src/nimpkgs.nim.cfg rename to src/app.nim.cfg diff --git a/src/button.nim b/src/components/button.nim similarity index 81% rename from src/button.nim rename to src/components/button.nim index 42d8e0a..fe3aec7 100644 --- a/src/button.nim +++ b/src/components/button.nim @@ -1,7 +1,5 @@ import std/[dom, sugar] - -include karax/prelude -import karax/vstyles +import karax/[karax, karaxdsl, vdom, vstyles] proc showScrollToTop() = # TODO: only show button when scrolling up @@ -18,14 +16,14 @@ proc scrollToTop*() = document.body.scrollTop = 0 document.documentElement.scrollTop = 0 -document.addEventListener("scroll", (e: Event) => showScrollToTop()) +document.addEventListener("scroll", (e: dom.Event) => showScrollToTop()) proc scrollToTopButton*(): VNode = result = buildHtml(tdiv): button( class = - " absolute fixed md:bottom-10 md:right-10 bottom-2 right-2 " & + " absolute fixed md:bottom-10 right-10 bottom-2 " & " md:p-5 p-2 cursor-pointer z-99 rounded " & " bg-ctp-rosewater hover:bg-ctp-mauve text-ctp-mantle ", `id` = "scrollBtn", diff --git a/src/components/footer.nim b/src/components/footer.nim new file mode 100644 index 0000000..93614fe --- /dev/null +++ b/src/components/footer.nim @@ -0,0 +1,29 @@ +import std/[times] +import karax/[kbase, karaxdsl, vdom, jstrutils] + +import ../[context, style] + +const packagesGitUrlBase = "https://github.com/nim-lang/packages/blob/".kstring + +proc footerBar*(): VNode = + var links: seq[(kstring, kstring)] + if ctx.loaded: + let packagesAbbr = ($ctx.nimpkgs.packagesHash)[0..8].kstring + links.add ( + packagesGitUrlBase & ctx.nimpkgs.packagesHash & "/packages.json".kstring, + "nim-lang/packages:" & packagesAbbr + ) + links.add ("http://github.com/daylinmorgan/nimpkgs".kstring, "source".kstring) + result = buildHtml(footer(class = "mt-auto md:mx-10 flex flex-col md:flex-row md:justify-between md:items-center mb-5")): + if ctx.loaded: + tdiv(class = "text-xs text-ctp-subtextzero px-1"): + text "updated: " & ctx.nimpkgs.updated.format("yyyy-MM-ddZZZ") + tdiv(): + ul(class = "md:flex items-center"): + for (url, msg) in links: + li(class = "px-1 hover:bg-ctp-mantle rounded text-sm flex items-center space-x-1"): + tdiv(class = "i-mdi-github") + a(href = url, class = accent): + text msg + + diff --git a/src/components/header.nim b/src/components/header.nim new file mode 100644 index 0000000..f457f5b --- /dev/null +++ b/src/components/header.nim @@ -0,0 +1,27 @@ +import karax/[kbase, karaxdsl, vdom] + +import ../style + +proc headerBar*(): VNode = + result = buildHtml(tdiv(class = "md:m-5 m-1 flex flex-wrap")): + a(href = "/#", class = " no-underline"): + img(src = "img/logo-wide.svg", class = "inline md:h-4rem h-3rem px-1") + tdiv(class = "grow") + label(`for` = "menu-toggle", + class = "cursor-pointer lg:hidden flex items-center px-3 py-2" + ): + text "menu" + input(class = "hidden", type = "checkbox", `id` = "menu-toggle") + tdiv(class = "lg:flex lg:items-center lg:justify-between hidden w-full lg:w-auto justify-end", + `id` = "menu"): + nav(class = "flex justify-end"): + ul(class = "lg:flex items-center"): + for (url, msg) in [ + ("/#/search", "search"), + ("/#/metrics", "metrics"), + ]: + li(class = "p-2 hover:bg-ctp-mantle rounded text-sm md:text-lg"): + a(href = url.kstring, class = accent): + text msg + + diff --git a/src/components/package.nim b/src/components/package.nim new file mode 100644 index 0000000..7476a35 --- /dev/null +++ b/src/components/package.nim @@ -0,0 +1,87 @@ +import std/[algorithm, strutils, sequtils, jsconsole, uri, random] + +import karax/[kbase, karax, karaxdsl, vdom, jstrutils, ] + +import ../[packages, style, context] +import ../components/tag +import ../utils + +randomize() +proc authorRepo(uri: Uri, hostname = false): kstring = + var name = + if hostname: uri.hostname & uri.path.replace(".git") + else: uri.path[1..^1].replace(".git") + if name[^1] == '/': + name = name[0..^2] + return name.jss + +proc projectUrl*(pkg: NimPackage): VNode = + let uri = parseUri($pkg.url) + let icon = + case uri.hostname: + of "github.com": "i-mdi-github" + of "gitlab.com": "i-mdi-gitlab" + of "git.sr.ht": "i-simple-icons-sourcehut" + of "codeberg.org": "i-simple-icons-codeberg" + of "bitbucket.org": "i-simple-icons-bitbucket" + else: "i-mdi-git" + let repoName = uri.authorRepo(hostname = (icon == "i-mdi-git")) + + buildHtml: + tdiv(class = "flex items-center space-x-2"): + tdiv(class = icon.jss) + a(href = pkg.url, class = if pkg.deleted: "line-through text-ctp-red" else: ""): + text repoName.jss + + +proc card*(pkg: NimPackage): VNode = + result = buildHtml(tdiv(class = "flex flex-col bg-ctp-crust rounded-xl my-5 p-5")): + tdiv(class = "flex flex-col md:flex-row md:justify-between"): + a(href = "/#/pkg/" & pkg.name): + h2(class = (textStyle & "font-black md:text-2xl text-lg font-casual").kstring): + text pkg.name + if not pkg.isAlias: + pkg.projectUrl + if pkg.isAlias: + tdiv: + text "alias for: " + span(onClick = setSearchUrl("name:" & pkg.alias), + class = "link"): + text pkg.alias + else: + span(class = "md:text-xl my-2"): text pkg.description + tdiv(class = "flex flex-col text-xs md:text-lg overflow-x-scroll"): + tdiv(class = "flex flex-wrap"): + for t in pkg.tags: + tdiv( + onClick = setSearchUrl("tag:" & t.replace(" ", "-")), + class = "link"): + t.renderTag + +proc getRecentReleases(ctx: Context): seq[NimPackage] = + var pkgs: seq[NimPackage] + for pkg in ctx.nimpkgs.packages.values(): + if pkg.versions.len > 0: + pkgs.add pkg + + pkgs.sort(sortVersion, order = Descending) + return pkgs[0..20] + +proc recentPackageVersionList*(ctx: Context): VNode = + let pkgs = ctx.getRecentReleases + result = buildHtml(tdiv(class = "flex flex-wrap")): + for pkg in pkgs: + a(class = borderStyle & "p-2 m-1 space-x-1 no-underline text-ctp-text", + href = "/#/pkg/" & pkg.name): + span(class = textStyle & "font-bold font-mono-casual"): text pkg.name + span(class = "italic"): text pkg.versions[0].tag + span: + text " (" & (getTime() - pkg.versions[0].time).inDays.jss & " days ago)" + +proc randomPackage*(ctx: Context): VNode = + let pkgName = ctx.nimpkgs.packages.keys().toSeq().sample() + console.log pkgName.jss + result = buildHtml(tdiv(class = borderStyle & "my-2 m-1 p-2")): + a(href = "/#/pkg/" & pkgName.jss, class = "flex items-center text-ctp-text no-underline"): + tdiv(class = "i-mdi-dice-6") + span(class = "font-ctp-text"): text "random" diff --git a/src/components/search.nim b/src/components/search.nim new file mode 100644 index 0000000..49a3da2 --- /dev/null +++ b/src/components/search.nim @@ -0,0 +1,73 @@ +import std/[strutils, sequtils, dom, uri] + +import karax/[kbase, karax, karaxdsl, vdom, jstrutils, kdom] + +import ../[packages, style, context] +# import ../components/package +import ../utils + +type + Query* = object + all, name, tag, license = "".kstring + +proc parseQuery*(s: kstring): Query = + result = Query() + if ":" notin s: + result.all = s; return + + let parts = s.split(" ") + for part in parts: + if ":" in part: + let + subparts = part.split(":") + k = subparts[0] + v = subparts[1] + case k: + of "name": + result.name = v + of "tag": + result.tag = v.replace("-") + of "license": + result.license = v + else: discard + else: + result.all &= part + + +proc searchPackages*(q: Query): seq[NimPackage] = + if q == Query(): + result = ctx.nimpkgs.packages.values.toSeq() + return + + for name, pkg in ctx.nimpkgs.packages: + let searchStr = ((pkg.url & " " & pkg.name & " " & pkg.description & " " & ( + pkg.tags).join(" ").kstring)) + if (q.name notin pkg.name) or + (q.license notin pkg.license) or + (q.tag != "".kstring and (q.tag notin pkg.tags)): continue + + if q.all in searchStr: + result.add pkg + +proc getSearchFromUri*(): kstring = + var url = initUri() + parseUri($window.location.href, url) + if url.query == "": return "" + for k, v in decodeQuery(url.query): + if k == "query": + return v.kstring + +proc getSearchInput*() = + let searchInput = getVNodeById("search").getInputText + setSearchUrl(searchInput)() + +proc searchBar*(value = jss""): Vnode = + buildHtml(tdiv(class = "flex flex-row my-2 grow")): + input(`type` = "text", class = "bg-ctp-crust md:mx-3 mx-1 p-2 grow".kstring & borderStyle, `id` = "search", + placeholder = "query", value = value, + onChange = getSearchInput) + button(`type` = "button", class = borderStyle & "p-2 flex items-center", + onClick = getSearchInput): + tdiv(class = "i-mdi-magnify") + text "search" + diff --git a/src/components/tag.nim b/src/components/tag.nim new file mode 100644 index 0000000..907f156 --- /dev/null +++ b/src/components/tag.nim @@ -0,0 +1,46 @@ +import std/[uri, tables, random] +import karax/[kbase, karaxdsl, vdom, jstrutils] + +import ../[packages, style, context, utils] + +randomize() + +proc renderTag*(tag: kstring): VNode = + buildHtml: + tdiv(class = "link md:p-2 p-1 m-1" & borderStyle): + text tag + +proc renderTags*(tags: seq[kstring]): VNode = + buildHtml: + tdiv(class = "flex flex-wrap"): + for i, tag in tags: + let query = encodeQuery({"query": $("tag:" & tag)}) + a( + href = ("/?" & query & "#/search").jss, + class = "no-underline" + ): + tag.renderTag + +proc selectRandomTags*(ctx: Context): seq[kstring] = + var tagCounts: CountTable[kstring] + for pkg in ctx.nimpkgs.packages.values(): + for tag in pkg.tags: + tagCounts.inc tag + + var tags: seq[kstring] + for tag, cnt in tagCounts: + if cnt > 3: tags.add tag + + while result.len < 5: + let tag = tags.sample() + if tag notin result: + result.add tag + +proc randomTags*(ctx: Context): VNode = + let tags = ctx.selectRandomTags() + buildHtml(tdiv): + tags.renderTags + + + + diff --git a/src/context.nim b/src/context.nim new file mode 100644 index 0000000..ac5e12f --- /dev/null +++ b/src/context.nim @@ -0,0 +1,33 @@ +import std/[ + asyncjs, jsconsole, jsfetch, sugar, tables +] + +import karax/[kbase, karax] +import jsony + +import packages, utils + +export tables + +type + Context* = object + nimpkgs*: NimPkgs + loaded*: bool + +let nimpkgsUrl = + when defined(debug): "http://localhost:8080/nimpkgs.json" + else: "https://raw.githubusercontent.com/nimpkgs/nimpkgs/main/nimpkgs.json" + + +proc fetchPackages*(ctx: var Context){.async.} = + await fetch(nimpkgsUrl.jss) + .then((r: Response) => r.text()) + .then(proc(txt: kstring) = + ctx.nimpkgs = fromJson($txt, NimPkgs) + ctx.loaded = true + redraw() + ) + .catch((err: Error) => console.log err + ) +var ctx* = Context() +discard ctx.fetchPackages diff --git a/src/nimpkgs.nim b/src/nimpkgs.nim deleted file mode 100644 index 5f51ed3..0000000 --- a/src/nimpkgs.nim +++ /dev/null @@ -1,250 +0,0 @@ -import std/[strutils, sets, sequtils, random] -include karax / prelude - -import packages, button - -type - Query = object - all, name, tag, license = "".kstring - -randomize() - - -var - filteredPackages: seq[Package] = allPackages - searchInput: kstring = "".kstring -const - packagesGitUrl = "https://github.com/nim-lang/packages/blob/" & packagesHash & "/packages.json" - numPackages = allPackages.len - numTags = allTags.len - colors = [ - "flamingo", - "pink", - "mauve", - "red", - "maroon", - "peach", - "yellow", - "green", - "teal", - "sky", - "sapphire", - "blue", - "lavender" - ] -let - accent = (" " & colors.sample() & " ").kstring - textStyle = (" text-ctp-" & accent & " ").kstring - borderStyle = (" b-ctp-" & accent & " ").kstring - randomPkgIndices = [ - rand(numPackages-1), rand(numPackages-1), rand(numPackages-1), - rand(numPackages-1), rand(numPackages-1), rand(numPackages-1), - rand(numPackages-1), rand(numPackages-1), rand(numPackages-1), - rand(numPackages-1)] - randomTagIndices = [ - rand(numTags-1), rand(numTags-1), rand(numTags-1), - rand(numTags-1), rand(numTags-1), rand(numTags-1) - ] - - - -proc parseQuery(s: kstring): Query = - result = Query() - if ":" notin s: - result.all = s; return - - let parts = s.split(" ") - for part in parts: - if ":" in part: - let - subparts = part.split(":") - k = subparts[0] - v = subparts[1] - case k: - of "name": - result.name = v - of "tag": - result.tag = v - of "license": - result.license = v - else: discard - else: - result.all &= part - -proc searchPackages(q: Query) = - filteredPackages = @[] - if q == Query(): - filteredPackages = allPackages - return - for pkg in allPackages: - let searchStr = ((pkg.name & " " & pkg.description & " " & (pkg.tags).join(" ").kstring)) - if (q.name notin pkg.name) or - (q.license notin pkg.license) or - (q.tag != "".kstring and (q.tag notin pkg.tags)): continue - - if q.all in searchStr: - - filteredPackages.add pkg - -proc setSearch(v: kstring): proc () = - result = proc() = - searchInput = v - searchPackages(parseQuery(v)) - redraw() - -proc fieldToDom(s: kstring): VNode = - result = buildHtml(tdiv(class = "font-black basis-1/4 sm:basis-1/6 shrink-0")): - text s & ":" - -proc noProtocol(s: kstring): kstring = kstring(($s).replace("http://", - "").replace("https://", "")) - -proc toDom(pkg: Package): VNode = - result = buildHtml(tdiv(class = "flex flex-col bg-ctp-crust rounded-xl my-5 p-5")): - h2(class = (textStyle & "font-black md:text-2xl text-lg font-casual").kstring): - text ("# " & pkg.name).kstring - if pkg.alias != "": - tdiv: - text "alias for: " - span(onClick = setSearch("name:" & pkg.alias), - class = "hover:text-ctp-mauve"): - text pkg.alias - else: - text pkg.description - tdiv(class = "flex flex-col text-xs md:text-lg overflow-x-scroll"): - tdiv(class = "flex flex-row"): - fieldToDom("project") - a(href = pkg.url): - text pkg.url.noProtocol - tdiv(class = "flex flex-row"): - fieldToDom("web") - a(href = pkg.web): text pkg.web.noProtocol - if pkg.doc != "": - tdiv(class = "flex flex-row"): - fieldToDom("doc") - a(href = pkg.doc): text pkg.doc.noProtocol - tdiv(class = "flex flex-row"): - fieldToDom("license") - span: text pkg.license - tdiv(class = "flex flex-row"): - fieldToDom("tags") - tdiv(): - for t in pkg.tags: - span(onClick = setSearch("tag:" & t), - class = "hover:text-ctp-mauve"): - text t - text "; " - - # tdiv(class="bg-ctp-mantle rounded my-2 p-2"): - # text "nimble install " & p.name - # br() - # text "atlas use " & p.name - -proc startChar(p: Package): char = p.name[0].toLowerAscii - -proc toDom(pkgs: seq[Package]): VNode = - var l = 'a' - result = buildHtml(tdiv): - if pkgs[0].startChar == l: tdiv(id = ($l).kstring) - for pkg in pkgs: - let startC = pkg.name[0].toLowerAscii - if l != startC: - while l != startC: inc l - tdiv(id = ($l).kstring) - pkg.toDom - -proc getSearchInput() = - searchInput = getVNodeById("search").getInputText - searchPackages(parseQuery(searchInput)) - -proc render(t: Tag): VNode = - result = buildHtml(tdiv(class = "bg-ctp-mantle m-1 p-1 rounded hover:text-ctp-mauve")): - tdiv(onClick = setSearch("tag:" & t.name)): - text t.name & "|" & kstring($t.packages) - -proc searchBar(): Vnode = - result = buildHtml(tdiv(class = "flex flex-col md:flex-row md:items-center md:my-5")): - tdiv(class = "flex flex-row my-2"): - input(`type` = "text", class = "border-1 bg-ctp-crust rounded mx-3 p-2".kstring & borderStyle, `id` = "search", - placeholder = "query", value = searchInput, - onChange = getSearchInput) - button(`type` = "button", class = "border-1 rounded p-2".kstring & - borderStyle, onClick = getSearchInput): - text "search" - #[ - tdiv(class = "md:mx-5 flex flex-col items-center"): - tdiv: text "examples: " - tdiv(class="flex flex-col"): - for msg in ["tag:database sqlite","license:MIT javascript"]: - span(class = "bg-ctp-mantle rounded text-ctp-subtextone m-1 p-1 text-xs"): - text msg - ]# - tdiv(class = "flex flex-col mx-5"): - tdiv: text "explore tags:" - tdiv(class = "flex flex-wrap text-sm"): - for idx in randomTagIndices: - allTags[idx].render - - -proc headerBar(): VNode = - result = buildHtml(tdiv(class = "mt-5 mx-5 flex flex-wrap")): - tdiv(class = "flex items-center my-3 grow"): - img(src = "img/logo.svg", class = "inline h-1em md:h-2em px-1") - span(class = "font-bold md:text-4xl text-lg font-casual"): - text "pkgs" - label(`for` = "menu-toggle", - class = "cursor-pointer lg:hidden flex items-center px-3 py-2" - ): - text "menu" - input(class = "hidden", type = "checkbox", `id` = "menu-toggle") - tdiv(class = "lg:flex lg:items-center justify-between hidden w-full lg:w-auto", - `id` = "menu"): - nav: - ul(class = "md:flex items-center"): - for (url, msg) in [ - (packagesGitUrl, "nim-lang/packages:" & packagesHashAbbr), - ("http://github.com/daylinmorgan/nimpkgs", "source") - ]: - li(class = "p-2 hover:bg-ctp-mantle rounded text-sm"): - a(href = url.kstring, class = accent): - text msg - -proc includedLinks(pkgs: seq[Package]): HashSet[char] = - pkgs.mapIt(it.startChar).toHashSet - -proc letterlink(): VNode = - let activeLinks = includedLinks(filteredPackages) - result = buildHtml(tdiv(class = "flex flex-wrap md:text-xl text-lg capitalize w-full justify-evenly gap-x-2 md:gap-x-auto")): - for l in LowercaseLetters: - tdiv(class = "w-5"): - if l in activeLinks: - a(href = "#" & ($l).kstring): - text $l - else: - span(class = "text-ctp-crust"): - text $l - -proc filteredPackagesDom(): VNode = - if filteredPackages.len > 0: - result = filteredPackages.toDom - else: - result = buildHtml(): - text "no match...try a different query" - - -proc createDom(): VNode = - result = buildHtml(tdiv(class = "md:w-3/4 max-w-[95%] md:mx-auto mx-5 md:text-lg text-sm")): - headerBar() - searchBar() - letterlink() - tdiv(class = "text-ctp-surfacetwo"): - text ($filteredPackages.len & "/" & $allPackages.len) & " packages" - if searchInput == "": - tdiv(): - for idx in randomPkgIndices: - allPackages[idx].toDom - hr() - filteredPackagesDom() - scrollToTopButton() - -setRenderer createDom diff --git a/src/packages.nim b/src/packages.nim index e6a2e1f..949a404 100644 --- a/src/packages.nim +++ b/src/packages.nim @@ -1,56 +1,71 @@ -import std/[algorithm, strutils, tables] -import karax/kbase - +import std/[ + algorithm, asyncjs, + strutils, sugar, tables, times +] +import karax/[kbase] import jsony -type - Package* = object - name*, url*, `method`*, description*, license*, web*, doc*, alias*: kstring - tags*: seq[kstring] - Tag* = object - name*: kstring - packages*: int +export algorithm, tables, times, asyncjs, sugar proc parseHook*(s: string, i: var int, v: var kstring) = var str: string parseHook(s, i, str) v = cstring(str) -proc cmpPkgs(a, b: Package): int = - cmp(toLowerAscii($a.name), toLowerAscii($b.name)) +type + Version* = object + tag*, hash*: kstring + time*: Time -proc getPackages(): seq[Package] = - const packagesJsonStr = slurp "./packages/packages.json" - result = packagesJsonStr.fromJson(seq[Package]) - result.sort(cmpPkgs) + NimPackage* = object + name*, url*, `method`*, description*, + license*, web*, doc*, alias*: kstring + lastCommitHash*: kstring + lastCommitTime*: Time + versions*: seq[Version] + tags*: seq[kstring] + deleted*: bool + + NimPkgs* = object + updated*: Time + packagesHash*: kstring + packages*: OrderedTable[string, NimPackage] + +proc newHook*(p: var NimPackage) = + p.url = "" + p.alias = "" + p.`method` = "" + p.license = "" + p.web = "" + p.doc = "" + p.description = "" + p.alias = "" + p.tags = @[] + +proc newHook*(nimpkgs: var NimPkgs) = + nimpkgs.packagesHash = "" + +proc parseHook*(s: string, i: var int, v: var Time) = + var num: int + parseHook(s, i, num) + v = fromUnix(num) + +proc sortCommit*(a, b: NimPackage): int = + cmp(a.lastCommitTime, b.lastCommitTime) + +proc sortAlphabetical*(a, b: NimPackage): int = + cmp(a.name, b.name) + +proc sortVersion*(a, b: NimPackage): int = + let lengths = (a.versions.len, b.versions.len) + if lengths[0] > 0 and lengths[1] > 0: + result = cmp(a.versions[0].time, b.versions[0].time) + elif lengths[0] == 0 and lengths[1] == 0: + result = sortCommit(a, b) + elif lengths[0] == 0: + result = -1 + else: + result = 1 -#[ -import strutils, tables, heapqueue, algorithm -iterator topN[T](h: CountTable[T]|Table[T, int], n=10): - tuple[cnt: int; key: T] = - var q = initHeapQueue[tuple[cnt: int; key: T]]() - for key, cnt in h: - if q.len < n: - q.push((cnt, key)) - elif cnt > q[0].cnt: # retain 1st seen on tied cnt - discard q.replace((cnt, key)) - while q.len > 0: # q now has top n entries - yield q.pop -]# - -proc getTags(pkgs: seq[Package]): seq[Tag] = - const minPackageCutoff = 10 - var tags: seq[kstring] - for pkg in pkgs: - for tag in pkg.tags: - tags.add tag - for key, cnt in tags.toCountTable: - if cnt > minPackageCutoff: - result.add Tag(name: key, packages: cnt) - -const - packagesHash* {.strdefine.} = "master" - packagesHashAbbr* {.strdefine.} = "master" - allPackages* = getPackages() - allTags* = allPackages.getTags() +proc isAlias*(p: NimPackage): bool {.inline.} = p.alias != "" diff --git a/src/pages/index.nim b/src/pages/index.nim new file mode 100644 index 0000000..9890a53 --- /dev/null +++ b/src/pages/index.nim @@ -0,0 +1,21 @@ +import karax/[karaxdsl, vdom] + +import ../components/[search, tag, package] +import ../context + +proc render*(): VNode = + result = buildHtml(tdiv(class = "justify-center")): + tdiv(class = "flex flex-col space-y-5"): + tdiv(class = "grow md:w-4/5 mx-auto"): + tdiv(class = "flex flex-col md:flex-row grow"): + searchBar() + # ctx.randomPackage() + tdiv(): + tdiv(): + text "explore tags:" + ctx.randomTags() + tdiv(): + tdiv(): + text "recently released versions:" + ctx.recentPackageVersionList + diff --git a/src/pages/metrics.nim b/src/pages/metrics.nim new file mode 100644 index 0000000..8220c76 --- /dev/null +++ b/src/pages/metrics.nim @@ -0,0 +1,101 @@ +import std/[algorithm, sequtils, tables, uri, strutils, times] +import karax/[kbase, karaxdsl, vdom, jstrutils] + +import ../[context, packages, style, utils] + +type + Metrics = object + total: int + isDeleted: int + isAlias: int + isVersioned: int + commitMonth: int + commitYear: int + tags, domains, authors, license, : seq[(string, int)] + + +proc sortCounts(x, y: (string, int)): int = + cmp(x[1], y[1]) + +proc calculateMetics(ctx: Context): Metrics = + let currentTime = getTime() + var + tags: CountTable[string] + domains: CountTable[string] + authors: CountTable[string] + license: CountTable[string] + + result.total = ctx.nimpkgs.packages.len + for pkg in ctx.nimpkgs.packages.values(): + let timeSinceLastCommit = (currentTime - pkg.lastCommitTime) + + if pkg.versions.len > 0: inc result.isVersioned + if pkg.isAlias: inc result.isAlias + if pkg.deleted: inc result.isDeleted + if pkg.license != "": license.inc $pkg.license + if timeSinceLastCommit < initDuration(weeks = 52): + inc result.commitYear + if timeSinceLastCommit < initDuration(days = 30): + inc result.commitMonth + if pkg.url != "": + let u = parseUri($pkg.url) + domains.inc u.hostname + authors.inc u.path.split("/")[1] + if pkg.tags.len > 0: + for tag in pkg.tags: + tags.inc $tag + + result.tags = tags.pairs.toSeq() + result.domains = domains.pairs.toSeq() + result.authors = authors.pairs.toSeq() + result.license = license.pairs.toSeq() + result.tags.sort(sortCounts, order = Descending) + result.domains.sort(sortCounts, order = Descending) + result.authors.sort(sortCounts, order = Descending) + result.license.sort(sortCounts, order = Descending) + + +proc totalsTable(metrics: Metrics): VNode = + let cellClass = "border md:px-10 px-5" & borderStyle + buildHtml(tdiv(class = "my-10")): + tdiv: + h2(class = "text-2xl"): text "totals" + table(class = "bg-ctp-mantle"): + tr: + th(class = cellClass): text "category" + th(class = cellClass): text "number" + for (msg, metric) in [ + ("total", metrics.total), + ("authors/orgs", metrics.authors.len), + ("deleted", metrics.isDeleted), + ("alias", metrics.isAlias), + ("versioned", metrics.isVersioned), + ("last commit (< 1 year)", metrics.commitYear), + ("last commit (< 30 days)", metrics.commitMonth), + ]: + tr: + td(class = cellClass): text msg + td(class = cellClass): text metric.jss + + +proc blockCountList(itemList: seq[(string, int)], title: string): VNode = + buildHtml(tdiv(class = "border-t-1 border-dashed my-5 py-5")): + h2(class = "text-2xl"): text title.jss + for (item, cnt) in itemList: + tdiv(class = "inline-block p-2 m-1 border rounded space-x-2" & borderStyle): + span: text item.kstring & ":" + span: text kstring($cnt) + + +proc render*(): VNode = + let metrics = ctx.calculateMetics() + result = buildHtml(tdiv): + h2(class = "text-4xl"): + text "metrics" + tdiv(class = "my-1"): + text "a small collection of metrics from the current nim-lang/packages" + metrics.totalsTable + blockCountList(metrics.tags[0..20], title = "tags (top 20)") + blockCountList(metrics.authors[0..20], title = "authors (top 20)") + blockCountList(metrics.license[0..20], title = "licenses (top 20)") + blockCountList(metrics.domains, title = "domains") diff --git a/src/pages/notfound.nim b/src/pages/notfound.nim new file mode 100644 index 0000000..e62fda2 --- /dev/null +++ b/src/pages/notfound.nim @@ -0,0 +1,8 @@ +import karax/[karaxdsl, vdom] + +proc render*(): VNode = + result = buildHtml: + tdiv(class = "mx-auto text-center"): + span(class = "text-9xl lg:text-[25rem] font-black my-5"): + text "404" + diff --git a/src/pages/package.nim b/src/pages/package.nim new file mode 100644 index 0000000..073b3b4 --- /dev/null +++ b/src/pages/package.nim @@ -0,0 +1,82 @@ +import std/[algorithm, sugar] +import karax/[karaxdsl, vdom, jstrutils] + +import ../[context, packages, style] +import ../components/[tag, package] +import ../utils +import notfound + +proc versionTable(pkg: NimPackage): VNode = + var versions = pkg.versions + versions.sort((a, b: Version) => cmp(a.time, b.time), order = Descending) + + buildHtml(tdiv(class = "my-5 p-10 bg-ctp-crust rounded")): + table(class = "table-auto w-full text-center"): + tr: + th: text "version" + th: text "release" + th: text "hash" + for version in versions: + tr: + td: text version.tag + td: text version.time.format("yyyy-MM-dd") + td: text ($version.hash)[0..8] + +proc renderAlias(pkg: NimPackage): VNode = buildHtml: + tdiv: + text pkg.name & "is alias for " + a(href = "#/pkg/" & pkg.alias): + text pkg.alias + +proc renderLinks(pkg: NimPackage): VNode = buildHtml(tdiv): + tdiv: text "links:" + tdiv: + pkg.projectUrl + if pkg.web != "" and pkg.web != pkg.url: + tdiv(): + a(href = pkg.web, class = "flex items-center space-x-2"): + tdiv(class = "i-mdi-web inline-block") + span: text pkg.web.noProtocol + if pkg.doc != "": + tdiv(): + a(href = pkg.doc, class = "flex items-center space-x-2"): + tdiv(class = "i-mdi-file-outline inline-block") + span: text pkg.doc.noProtocol + + +proc renderPkgInfo(pkg: NimPackage): VNode = + buildHtml: + tdiv(class = "space-y-5 text-2xl"): + tdiv(class = "md:text-4xl text-xl"): + text pkg.description + pkg.renderLinks + tdiv: + tdiv: text "license:" + text pkg.license.jss + tdiv: + tdiv: text "tags:" + pkg.tags.renderTags + tdiv: + tdiv: text "usage:" + tdiv(class = "bg-ctp-surfacezero rounded my-2 mx-3 p-2 w-auto"): + pre: + text "nimble install " & pkg.name + pre: + text "atlas use " & pkg.name + +proc render*(packageName: string): VNode = + if packageName notin ctx.nimpkgs.packages: return notfound.render() + let pkg = ctx.nimpkgs.packages[packageName] + result = buildHtml(tdiv(class = "flex flex-col")): + if pkg.deleted: + tdiv(class = "md:text-5xl text-2xl text-ctp-red my-5 "): + tdiv(class = "flex items-center md:text-5xl text-2xl font-mono-casual font-black"): + tdiv(class = "i-mdi-alert inline-block") + span: text "WARNING!" + text "The provided url for this package is unreachable, it may have been deleted." + tdiv(class = "bg-ctp-mantle rounded p-5"): + h2(class = textStyle & "text-3xl md:text-6xl font-bold font-mono-casual my-2"): + text pkg.name + if pkg.isAlias: pkg.renderAlias + else: pkg.renderPkgInfo + if pkg.versions.len > 0: pkg.versionTable diff --git a/src/pages/pages.nim b/src/pages/pages.nim new file mode 100644 index 0000000..c88bdff --- /dev/null +++ b/src/pages/pages.nim @@ -0,0 +1,2 @@ +import index, search, package, notfound, metrics +export index, search, package, notfound, metrics diff --git a/src/pages/search.nim b/src/pages/search.nim new file mode 100644 index 0000000..ef5b4a3 --- /dev/null +++ b/src/pages/search.nim @@ -0,0 +1,106 @@ +import std/[algorithm, strutils, sequtils, dom] + +import karax/[kbase, karax, karaxdsl, vdom, jstrutils, kdom] + +import ../[packages, context] +import ../components/[package, search] +import ../utils + +type + SortMethod = enum + smAlphabetical, smCommitAge, smVersionAge + PageContext = object + sortMethod: SortMethod = smAlphabetical + filteredPackages: seq[NimPackage] + search: kstring + +var pgCtx = PageContext() + +proc scrollToAnchor(a: string): proc() = + result = proc() = + let d = getVNodeById(a) + scrollIntoView(d.dom) + +proc letterlink(activeLinks: seq[char]): VNode = buildHtml: + tdiv( + class = "flex flex-wrap md:text-xl text-lg capitalize w-full justify-evenly gap-x-2 md:gap-x-auto" + ): + for l in LowercaseLetters: + tdiv(class = "w-5"): + if l in activeLinks: + span( + class = "link underline decoration-dotted", + onClick = scrollToAnchor($l) + ): text l.jss + else: span(class = "text-ctp-crust"): text l.jss + +proc startChar(p: NimPackage): char = + p.name[0].toLowerAscii + +proc alphabeticalPackageList(pkgs: seq[NimPackage]): VNode = + var charPackages: OrderedTable[char, seq[NimPackage]] + for pkg in pkgs: + let c = pkg.startChar + if c in charPackages: + charPackages[c].add pkg + else: + charPackages[c] = @[pkg] + result = buildHtml(tdiv): + letterlink(charPackages.keys.toSeq) + for c, packages in charPackages: + tdiv(`id` = c.jss) + for pkg in packages: + pkg.card + +proc selectSortMethod() = + let v = getVNodeById("sort-select").getInputText + pgCtx.sortMethod = SortMethod(parseInt(v)) + +proc sortSelector(): VNode = + buildHtml(tdiv(class = "flex items-center")): + label(`for` = "sort-select"): text "sort:" + select(class = "bg-ctp-crust rounded p-3", name = "sort", + `id` = "sort-select", onChange = selectSortMethod): + for i, msg in ["alphabetical", "recent commit", "recent version"]: + if i == ord(pgCtx.sortMethod): + option(value = ($i).cstring, selected = ""): text msg + else: + option(value = ($i).cstring): text msg + +proc filteredPackagesDom(): VNode = + if pgCtx.filteredPackages.len == 0: + return buildHtml(): text "no match...try a different query" + else: + case pgCtx.sortMethod: + of smAlphabetical: + pgCtx.filteredPackages.sort(sortAlphabetical) + of smCommitAge: + pgCtx.filteredPackages.sort(sortCommit, order = Descending) + of smVersionAge: + pgCtx.filteredPackages.sort(sortVersion, order = Descending) + + result = buildHtml(tdiv): + tdiv(class = "text-ctp-surfacetwo"): + text ($pgCtx.filteredPackages.len & "/" & $ctx.nimpkgs.packages.len) & " packages" + case pgCtx.sortMethod: + of smAlphabetical: + pgCtx.filteredPackages.alphabeticalPackageList + else: + for pkg in pgCtx.filteredPackages: + pkg.card + +proc update(pgCtx: var PageContext) = + pgCtx.filteredPackages = ctx.nimpkgs.packages.values().toSeq() + pgCtx.search = getSearchFromUri() + pgCtx.filteredPackages = searchPackages(parseQuery(pgCtx.search)) + +proc render*(): VNode = + pgCtx.update + result = + buildHtml(tdiv): + tdiv(class = "flex md:flex-row md: space-x-5"): + searchBar(value = pgCtx.search) + sortSelector() + filteredPackagesDom() + + diff --git a/src/style.nim b/src/style.nim new file mode 100644 index 0000000..f665f51 --- /dev/null +++ b/src/style.nim @@ -0,0 +1,25 @@ +import std/random +import karax/[kbase, jstrutils] + +randomize() + +const colors = [ + "flamingo", + "pink", + "mauve", + "red", + "maroon", + "peach", + "yellow", + "green", + "teal", + "sky", + "sapphire", + "blue", + "lavender" + ] +let + accent* = (colors.sample() & " ").kstring + textStyle* = (" text-ctp-" & accent & " ").kstring + borderStyle* = (" border rounded b-ctp-" & accent & " ").kstring + diff --git a/src/utils.nim b/src/utils.nim new file mode 100644 index 0000000..ef90799 --- /dev/null +++ b/src/utils.nim @@ -0,0 +1,31 @@ +import std/[strutils, uri] +import std/jsffi except `&` +import jsconsole +export jsconsole + +import karax/[kbase, karax, vdom, kdom] + +proc jss*[T](arg: T): kstring = ($arg).kstring +proc jss*(arg: kstring): kstring = arg + +proc noProtocol*(s: kstring): kstring = + ($s) + .replace("http://", "") + .replace("https://", "") + .jss + + +func replace*(c: kstring, sub: string, by = " "): kstring = + ($c).replace(sub, by).jss + +proc setSearchUrl*(searchQuery: kstring): proc() = + proc() = + var url = parseUri($window.location.href) + url.anchor = "/search" + url = url ? {"query": $searchQuery} + window.history.pushState(js{}, "".jss, url.jss) + let d = getVNodeById("search") + let node = d.dom + scrollIntoView(node) + redraw() + diff --git a/unocss.config.ts b/unocss.config.ts index 513c20b..da38413 100644 --- a/unocss.config.ts +++ b/unocss.config.ts @@ -1,9 +1,9 @@ import fs from "fs/promises"; import { variants } from "@catppuccin/palette"; -import { defineConfig, presetUno } from "unocss"; +import { defineConfig, presetUno, presetIcons } from "unocss"; -const generatePalette = () => { - const colors = {}; +const generatePalette = (): { [key: string]: string } => { + const colors: { [key: string]: string } = {}; Object.keys(variants.mocha).forEach((colorName) => { const sanitizedName = colorName @@ -27,7 +27,7 @@ export default defineConfig({ }, { layer: "mycss", - getCSS: ({ theme }) => ` + getCSS: () => ` body { font-family: 'Recursive', monospace; font-variation-settings: 'MONO' 1; @@ -37,28 +37,53 @@ export default defineConfig({ } a { text-decoration: underline dotted; - color: ${theme.colors.ctp.rosewater}; + color: ${catppuccinColors.rosewater}; } a:hover { - color: ${theme.colors.ctp.mauve}; + color: ${catppuccinColors.mauve}; + cursor: pointer; + } + // loading animation + .lds-dual-ring { + display: inline-block; + width: 80px; + height: 80px; + } + .lds-dual-ring:after { + content: " "; + display: block; + width: 64px; + height: 64px; + margin: 8px; + border-radius: 50%; + border: 6px solid #fff; + border-color: #fff transparent #fff transparent; + animation: lds-dual-ring 1.2s linear infinite; + } + @keyframes lds-dual-ring { + 0% { + transform: rotate(0deg); + } + 100% { + transform: rotate(360deg); + } } `, }, ], // accent color is dynamically generated safelist: Object.keys(catppuccinColors).flatMap((key: string) => [`text-ctp-${key}`, `b-ctp-${key}`]), - presets: [presetUno()], + presets: [presetUno(), presetIcons()], rules: [ ["font-casual", { "font-variation-settings": "'CASL' 1;" }], ["font-mono-casual", { "font-variation-settings": "'MONO' 1, 'CASL' 1;" }], ], shortcuts: { - btn: "border-1 border-solid rounded border-ctp-mauve flex flex-row hover:border-ctp-sky hover:text-ctp-rosewater m-2", - // link: "underline text-ctp-rosewater" + link: "cursor-pointer text-ctp-rosewater hover:text-ctp-mauve", }, theme: { colors: { - ctp: generatePalette(), + ctp: catppuccinColors, }, }, layers: {