atproto pastebin service: https://plonk.li

Compare changes

Choose any two refs to compare.

+2 -2
flake.nix
··· 81 81 description = "Port to run plonk on"; 82 82 }; 83 83 cookie_secret = mkOption { 84 - type = types.string; 84 + type = types.str; 85 85 default = "00000000000000000000000000000000"; 86 86 description = "Cookie secret"; 87 87 }; ··· 104 104 PLONK_PORT = "${toString config.services.plonk.port}"; 105 105 PLONK_NODE_ENV = "production"; 106 106 PLONK_HOST = "localhost"; 107 - PLONK_PUBLIC_URL = "plonk.li"; 107 + PLONK_PUBLIC_URL = "https://plonk.li"; 108 108 PLONK_DB_PATH = "plonk.db"; 109 109 PLONK_COOKIE_SECRET = config.services.plonk.cookie_secret; 110 110 };
+523
package-lock.json
··· 26 26 "multiformats": "^9.9.0", 27 27 "pino": "^9.3.2", 28 28 "pug": "^3.0.3", 29 + "shiki": "^3.4.2", 29 30 "uhtml": "^4.5.9" 30 31 }, 31 32 "devDependencies": { ··· 1484 1485 "win32" 1485 1486 ] 1486 1487 }, 1488 + "node_modules/@shikijs/core": { 1489 + "version": "3.4.2", 1490 + "resolved": "https://registry.npmjs.org/@shikijs/core/-/core-3.4.2.tgz", 1491 + "integrity": "sha512-AG8vnSi1W2pbgR2B911EfGqtLE9c4hQBYkv/x7Z+Kt0VxhgQKcW7UNDVYsu9YxwV6u+OJrvdJrMq6DNWoBjihQ==", 1492 + "license": "MIT", 1493 + "dependencies": { 1494 + "@shikijs/types": "3.4.2", 1495 + "@shikijs/vscode-textmate": "^10.0.2", 1496 + "@types/hast": "^3.0.4", 1497 + "hast-util-to-html": "^9.0.5" 1498 + } 1499 + }, 1500 + "node_modules/@shikijs/engine-javascript": { 1501 + "version": "3.4.2", 1502 + "resolved": "https://registry.npmjs.org/@shikijs/engine-javascript/-/engine-javascript-3.4.2.tgz", 1503 + "integrity": "sha512-1/adJbSMBOkpScCE/SB6XkjJU17ANln3Wky7lOmrnpl+zBdQ1qXUJg2GXTYVHRq+2j3hd1DesmElTXYDgtfSOQ==", 1504 + "license": "MIT", 1505 + "dependencies": { 1506 + "@shikijs/types": "3.4.2", 1507 + "@shikijs/vscode-textmate": "^10.0.2", 1508 + "oniguruma-to-es": "^4.3.3" 1509 + } 1510 + }, 1511 + "node_modules/@shikijs/engine-oniguruma": { 1512 + "version": "3.4.2", 1513 + "resolved": "https://registry.npmjs.org/@shikijs/engine-oniguruma/-/engine-oniguruma-3.4.2.tgz", 1514 + "integrity": "sha512-zcZKMnNndgRa3ORja6Iemsr3DrLtkX3cAF7lTJkdMB6v9alhlBsX9uNiCpqofNrXOvpA3h6lHcLJxgCIhVOU5Q==", 1515 + "license": "MIT", 1516 + "dependencies": { 1517 + "@shikijs/types": "3.4.2", 1518 + "@shikijs/vscode-textmate": "^10.0.2" 1519 + } 1520 + }, 1521 + "node_modules/@shikijs/langs": { 1522 + "version": "3.4.2", 1523 + "resolved": "https://registry.npmjs.org/@shikijs/langs/-/langs-3.4.2.tgz", 1524 + "integrity": "sha512-H6azIAM+OXD98yztIfs/KH5H4PU39t+SREhmM8LaNXyUrqj2mx+zVkr8MWYqjceSjDw9I1jawm1WdFqU806rMA==", 1525 + "license": "MIT", 1526 + "dependencies": { 1527 + "@shikijs/types": "3.4.2" 1528 + } 1529 + }, 1530 + "node_modules/@shikijs/themes": { 1531 + "version": "3.4.2", 1532 + "resolved": "https://registry.npmjs.org/@shikijs/themes/-/themes-3.4.2.tgz", 1533 + "integrity": "sha512-qAEuAQh+brd8Jyej2UDDf+b4V2g1Rm8aBIdvt32XhDPrHvDkEnpb7Kzc9hSuHUxz0Iuflmq7elaDuQAP9bHIhg==", 1534 + "license": "MIT", 1535 + "dependencies": { 1536 + "@shikijs/types": "3.4.2" 1537 + } 1538 + }, 1539 + "node_modules/@shikijs/types": { 1540 + "version": "3.4.2", 1541 + "resolved": "https://registry.npmjs.org/@shikijs/types/-/types-3.4.2.tgz", 1542 + "integrity": "sha512-zHC1l7L+eQlDXLnxvM9R91Efh2V4+rN3oMVS2swCBssbj2U/FBwybD1eeLaq8yl/iwT+zih8iUbTBCgGZOYlVg==", 1543 + "license": "MIT", 1544 + "dependencies": { 1545 + "@shikijs/vscode-textmate": "^10.0.2", 1546 + "@types/hast": "^3.0.4" 1547 + } 1548 + }, 1549 + "node_modules/@shikijs/vscode-textmate": { 1550 + "version": "10.0.2", 1551 + "resolved": "https://registry.npmjs.org/@shikijs/vscode-textmate/-/vscode-textmate-10.0.2.tgz", 1552 + "integrity": "sha512-83yeghZ2xxin3Nj8z1NMd/NCuca+gsYXswywDy5bHvwlWL8tpTQmzGeUuHd9FC3E/SBEMvzJRwWEOz5gGes9Qg==", 1553 + "license": "MIT" 1554 + }, 1487 1555 "node_modules/@ts-morph/common": { 1488 1556 "version": "0.17.0", 1489 1557 "resolved": "https://registry.npmjs.org/@ts-morph/common/-/common-0.17.0.tgz", ··· 1602 1670 "@types/send": "*" 1603 1671 } 1604 1672 }, 1673 + "node_modules/@types/hast": { 1674 + "version": "3.0.4", 1675 + "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.4.tgz", 1676 + "integrity": "sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==", 1677 + "license": "MIT", 1678 + "dependencies": { 1679 + "@types/unist": "*" 1680 + } 1681 + }, 1605 1682 "node_modules/@types/http-errors": { 1606 1683 "version": "2.0.4", 1607 1684 "resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.4.tgz", 1608 1685 "integrity": "sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA==", 1609 1686 "dev": true, 1610 1687 "license": "MIT" 1688 + }, 1689 + "node_modules/@types/mdast": { 1690 + "version": "4.0.4", 1691 + "resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-4.0.4.tgz", 1692 + "integrity": "sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==", 1693 + "license": "MIT", 1694 + "dependencies": { 1695 + "@types/unist": "*" 1696 + } 1611 1697 }, 1612 1698 "node_modules/@types/mime": { 1613 1699 "version": "1.3.5", ··· 1662 1748 "@types/node": "*", 1663 1749 "@types/send": "*" 1664 1750 } 1751 + }, 1752 + "node_modules/@types/unist": { 1753 + "version": "3.0.3", 1754 + "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", 1755 + "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==", 1756 + "license": "MIT" 1757 + }, 1758 + "node_modules/@ungap/structured-clone": { 1759 + "version": "1.3.0", 1760 + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.0.tgz", 1761 + "integrity": "sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==", 1762 + "license": "ISC" 1665 1763 }, 1666 1764 "node_modules/@webreflection/signal": { 1667 1765 "version": "2.1.2", ··· 2095 2193 "cborg": "cli.js" 2096 2194 } 2097 2195 }, 2196 + "node_modules/ccount": { 2197 + "version": "2.0.1", 2198 + "resolved": "https://registry.npmjs.org/ccount/-/ccount-2.0.1.tgz", 2199 + "integrity": "sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==", 2200 + "license": "MIT", 2201 + "funding": { 2202 + "type": "github", 2203 + "url": "https://github.com/sponsors/wooorm" 2204 + } 2205 + }, 2098 2206 "node_modules/chalk": { 2099 2207 "version": "4.1.2", 2100 2208 "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", ··· 2110 2218 }, 2111 2219 "funding": { 2112 2220 "url": "https://github.com/chalk/chalk?sponsor=1" 2221 + } 2222 + }, 2223 + "node_modules/character-entities-html4": { 2224 + "version": "2.1.0", 2225 + "resolved": "https://registry.npmjs.org/character-entities-html4/-/character-entities-html4-2.1.0.tgz", 2226 + "integrity": "sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA==", 2227 + "license": "MIT", 2228 + "funding": { 2229 + "type": "github", 2230 + "url": "https://github.com/sponsors/wooorm" 2231 + } 2232 + }, 2233 + "node_modules/character-entities-legacy": { 2234 + "version": "3.0.0", 2235 + "resolved": "https://registry.npmjs.org/character-entities-legacy/-/character-entities-legacy-3.0.0.tgz", 2236 + "integrity": "sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ==", 2237 + "license": "MIT", 2238 + "funding": { 2239 + "type": "github", 2240 + "url": "https://github.com/sponsors/wooorm" 2113 2241 } 2114 2242 }, 2115 2243 "node_modules/character-parser": { ··· 2189 2317 "node": ">= 0.8" 2190 2318 } 2191 2319 }, 2320 + "node_modules/comma-separated-tokens": { 2321 + "version": "2.0.3", 2322 + "resolved": "https://registry.npmjs.org/comma-separated-tokens/-/comma-separated-tokens-2.0.3.tgz", 2323 + "integrity": "sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==", 2324 + "license": "MIT", 2325 + "funding": { 2326 + "type": "github", 2327 + "url": "https://github.com/sponsors/wooorm" 2328 + } 2329 + }, 2192 2330 "node_modules/commander": { 2193 2331 "version": "9.5.0", 2194 2332 "resolved": "https://registry.npmjs.org/commander/-/commander-9.5.0.tgz", ··· 2361 2499 "node": ">= 0.8" 2362 2500 } 2363 2501 }, 2502 + "node_modules/dequal": { 2503 + "version": "2.0.3", 2504 + "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", 2505 + "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", 2506 + "license": "MIT", 2507 + "engines": { 2508 + "node": ">=6" 2509 + } 2510 + }, 2364 2511 "node_modules/destroy": { 2365 2512 "version": "1.2.0", 2366 2513 "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", ··· 2378 2525 "license": "Apache-2.0", 2379 2526 "engines": { 2380 2527 "node": ">=8" 2528 + } 2529 + }, 2530 + "node_modules/devlop": { 2531 + "version": "1.1.0", 2532 + "resolved": "https://registry.npmjs.org/devlop/-/devlop-1.1.0.tgz", 2533 + "integrity": "sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==", 2534 + "license": "MIT", 2535 + "dependencies": { 2536 + "dequal": "^2.0.0" 2537 + }, 2538 + "funding": { 2539 + "type": "github", 2540 + "url": "https://github.com/sponsors/wooorm" 2381 2541 } 2382 2542 }, 2383 2543 "node_modules/diff": { ··· 3043 3203 "node": ">= 0.4" 3044 3204 } 3045 3205 }, 3206 + "node_modules/hast-util-to-html": { 3207 + "version": "9.0.5", 3208 + "resolved": "https://registry.npmjs.org/hast-util-to-html/-/hast-util-to-html-9.0.5.tgz", 3209 + "integrity": "sha512-OguPdidb+fbHQSU4Q4ZiLKnzWo8Wwsf5bZfbvu7//a9oTYoqD/fWpe96NuHkoS9h0ccGOTe0C4NGXdtS0iObOw==", 3210 + "license": "MIT", 3211 + "dependencies": { 3212 + "@types/hast": "^3.0.0", 3213 + "@types/unist": "^3.0.0", 3214 + "ccount": "^2.0.0", 3215 + "comma-separated-tokens": "^2.0.0", 3216 + "hast-util-whitespace": "^3.0.0", 3217 + "html-void-elements": "^3.0.0", 3218 + "mdast-util-to-hast": "^13.0.0", 3219 + "property-information": "^7.0.0", 3220 + "space-separated-tokens": "^2.0.0", 3221 + "stringify-entities": "^4.0.0", 3222 + "zwitch": "^2.0.4" 3223 + }, 3224 + "funding": { 3225 + "type": "opencollective", 3226 + "url": "https://opencollective.com/unified" 3227 + } 3228 + }, 3229 + "node_modules/hast-util-whitespace": { 3230 + "version": "3.0.0", 3231 + "resolved": "https://registry.npmjs.org/hast-util-whitespace/-/hast-util-whitespace-3.0.0.tgz", 3232 + "integrity": "sha512-88JUN06ipLwsnv+dVn+OIYOvAuvBMy/Qoi6O7mQHxdPXpjy+Cd6xRkWwux7DKO+4sYILtLBRIKgsdpS2gQc7qw==", 3233 + "license": "MIT", 3234 + "dependencies": { 3235 + "@types/hast": "^3.0.0" 3236 + }, 3237 + "funding": { 3238 + "type": "opencollective", 3239 + "url": "https://opencollective.com/unified" 3240 + } 3241 + }, 3046 3242 "node_modules/help-me": { 3047 3243 "version": "5.0.0", 3048 3244 "resolved": "https://registry.npmjs.org/help-me/-/help-me-5.0.0.tgz", ··· 3056 3252 "integrity": "sha512-RuMffC89BOWQoY0WKGpIhn5gX3iI54O6nRA0yC124NYVtzjmFWBIiFd8M0x+ZdX0P9R4lADg1mgP8C7PxGOWuQ==", 3057 3253 "license": "MIT" 3058 3254 }, 3255 + "node_modules/html-void-elements": { 3256 + "version": "3.0.0", 3257 + "resolved": "https://registry.npmjs.org/html-void-elements/-/html-void-elements-3.0.0.tgz", 3258 + "integrity": "sha512-bEqo66MRXsUGxWHV5IP0PUiAWwoEjba4VCzg0LjFJBpchPaTfyfCKTG6bc5F8ucKec3q5y6qOdGyYTSBEvhCrg==", 3259 + "license": "MIT", 3260 + "funding": { 3261 + "type": "github", 3262 + "url": "https://github.com/sponsors/wooorm" 3263 + } 3264 + }, 3059 3265 "node_modules/htmlparser2": { 3060 3266 "version": "9.1.0", 3061 3267 "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-9.1.0.tgz", ··· 3404 3610 "dev": true, 3405 3611 "license": "ISC" 3406 3612 }, 3613 + "node_modules/mdast-util-to-hast": { 3614 + "version": "13.2.0", 3615 + "resolved": "https://registry.npmjs.org/mdast-util-to-hast/-/mdast-util-to-hast-13.2.0.tgz", 3616 + "integrity": "sha512-QGYKEuUsYT9ykKBCMOEDLsU5JRObWQusAolFMeko/tYPufNkRffBAQjIE+99jbA87xv6FgmjLtwjh9wBWajwAA==", 3617 + "license": "MIT", 3618 + "dependencies": { 3619 + "@types/hast": "^3.0.0", 3620 + "@types/mdast": "^4.0.0", 3621 + "@ungap/structured-clone": "^1.0.0", 3622 + "devlop": "^1.0.0", 3623 + "micromark-util-sanitize-uri": "^2.0.0", 3624 + "trim-lines": "^3.0.0", 3625 + "unist-util-position": "^5.0.0", 3626 + "unist-util-visit": "^5.0.0", 3627 + "vfile": "^6.0.0" 3628 + }, 3629 + "funding": { 3630 + "type": "opencollective", 3631 + "url": "https://opencollective.com/unified" 3632 + } 3633 + }, 3407 3634 "node_modules/media-typer": { 3408 3635 "version": "0.3.0", 3409 3636 "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", ··· 3441 3668 "node": ">= 0.6" 3442 3669 } 3443 3670 }, 3671 + "node_modules/micromark-util-character": { 3672 + "version": "2.1.1", 3673 + "resolved": "https://registry.npmjs.org/micromark-util-character/-/micromark-util-character-2.1.1.tgz", 3674 + "integrity": "sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==", 3675 + "funding": [ 3676 + { 3677 + "type": "GitHub Sponsors", 3678 + "url": "https://github.com/sponsors/unifiedjs" 3679 + }, 3680 + { 3681 + "type": "OpenCollective", 3682 + "url": "https://opencollective.com/unified" 3683 + } 3684 + ], 3685 + "license": "MIT", 3686 + "dependencies": { 3687 + "micromark-util-symbol": "^2.0.0", 3688 + "micromark-util-types": "^2.0.0" 3689 + } 3690 + }, 3691 + "node_modules/micromark-util-encode": { 3692 + "version": "2.0.1", 3693 + "resolved": "https://registry.npmjs.org/micromark-util-encode/-/micromark-util-encode-2.0.1.tgz", 3694 + "integrity": "sha512-c3cVx2y4KqUnwopcO9b/SCdo2O67LwJJ/UyqGfbigahfegL9myoEFoDYZgkT7f36T0bLrM9hZTAaAyH+PCAXjw==", 3695 + "funding": [ 3696 + { 3697 + "type": "GitHub Sponsors", 3698 + "url": "https://github.com/sponsors/unifiedjs" 3699 + }, 3700 + { 3701 + "type": "OpenCollective", 3702 + "url": "https://opencollective.com/unified" 3703 + } 3704 + ], 3705 + "license": "MIT" 3706 + }, 3707 + "node_modules/micromark-util-sanitize-uri": { 3708 + "version": "2.0.1", 3709 + "resolved": "https://registry.npmjs.org/micromark-util-sanitize-uri/-/micromark-util-sanitize-uri-2.0.1.tgz", 3710 + "integrity": "sha512-9N9IomZ/YuGGZZmQec1MbgxtlgougxTodVwDzzEouPKo3qFWvymFHWcnDi2vzV1ff6kas9ucW+o3yzJK9YB1AQ==", 3711 + "funding": [ 3712 + { 3713 + "type": "GitHub Sponsors", 3714 + "url": "https://github.com/sponsors/unifiedjs" 3715 + }, 3716 + { 3717 + "type": "OpenCollective", 3718 + "url": "https://opencollective.com/unified" 3719 + } 3720 + ], 3721 + "license": "MIT", 3722 + "dependencies": { 3723 + "micromark-util-character": "^2.0.0", 3724 + "micromark-util-encode": "^2.0.0", 3725 + "micromark-util-symbol": "^2.0.0" 3726 + } 3727 + }, 3728 + "node_modules/micromark-util-symbol": { 3729 + "version": "2.0.1", 3730 + "resolved": "https://registry.npmjs.org/micromark-util-symbol/-/micromark-util-symbol-2.0.1.tgz", 3731 + "integrity": "sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==", 3732 + "funding": [ 3733 + { 3734 + "type": "GitHub Sponsors", 3735 + "url": "https://github.com/sponsors/unifiedjs" 3736 + }, 3737 + { 3738 + "type": "OpenCollective", 3739 + "url": "https://opencollective.com/unified" 3740 + } 3741 + ], 3742 + "license": "MIT" 3743 + }, 3744 + "node_modules/micromark-util-types": { 3745 + "version": "2.0.2", 3746 + "resolved": "https://registry.npmjs.org/micromark-util-types/-/micromark-util-types-2.0.2.tgz", 3747 + "integrity": "sha512-Yw0ECSpJoViF1qTU4DC6NwtC4aWGt1EkzaQB8KPPyCRR8z9TWeV0HbEFGTO+ZY1wB22zmxnJqhPyTpOVCpeHTA==", 3748 + "funding": [ 3749 + { 3750 + "type": "GitHub Sponsors", 3751 + "url": "https://github.com/sponsors/unifiedjs" 3752 + }, 3753 + { 3754 + "type": "OpenCollective", 3755 + "url": "https://opencollective.com/unified" 3756 + } 3757 + ], 3758 + "license": "MIT" 3759 + }, 3444 3760 "node_modules/micromatch": { 3445 3761 "version": "4.0.8", 3446 3762 "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", ··· 3671 3987 "wrappy": "1" 3672 3988 } 3673 3989 }, 3990 + "node_modules/oniguruma-parser": { 3991 + "version": "0.12.1", 3992 + "resolved": "https://registry.npmjs.org/oniguruma-parser/-/oniguruma-parser-0.12.1.tgz", 3993 + "integrity": "sha512-8Unqkvk1RYc6yq2WBYRj4hdnsAxVze8i7iPfQr8e4uSP3tRv0rpZcbGUDvxfQQcdwHt/e9PrMvGCsa8OqG9X3w==", 3994 + "license": "MIT" 3995 + }, 3996 + "node_modules/oniguruma-to-es": { 3997 + "version": "4.3.3", 3998 + "resolved": "https://registry.npmjs.org/oniguruma-to-es/-/oniguruma-to-es-4.3.3.tgz", 3999 + "integrity": "sha512-rPiZhzC3wXwE59YQMRDodUwwT9FZ9nNBwQQfsd1wfdtlKEyCdRV0avrTcSZ5xlIvGRVPd/cx6ZN45ECmS39xvg==", 4000 + "license": "MIT", 4001 + "dependencies": { 4002 + "oniguruma-parser": "^0.12.1", 4003 + "regex": "^6.0.1", 4004 + "regex-recursion": "^6.0.2" 4005 + } 4006 + }, 3674 4007 "node_modules/p-finally": { 3675 4008 "version": "1.0.0", 3676 4009 "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", ··· 3972 4305 "asap": "~2.0.3" 3973 4306 } 3974 4307 }, 4308 + "node_modules/property-information": { 4309 + "version": "7.1.0", 4310 + "resolved": "https://registry.npmjs.org/property-information/-/property-information-7.1.0.tgz", 4311 + "integrity": "sha512-TwEZ+X+yCJmYfL7TPUOcvBZ4QfoT5YenQiJuX//0th53DE6w0xxLEtfK3iyryQFddXuvkIk51EEgrJQ0WJkOmQ==", 4312 + "license": "MIT", 4313 + "funding": { 4314 + "type": "github", 4315 + "url": "https://github.com/sponsors/wooorm" 4316 + } 4317 + }, 3975 4318 "node_modules/proxy-addr": { 3976 4319 "version": "2.0.7", 3977 4320 "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", ··· 4284 4627 "node": ">= 12.13.0" 4285 4628 } 4286 4629 }, 4630 + "node_modules/regex": { 4631 + "version": "6.0.1", 4632 + "resolved": "https://registry.npmjs.org/regex/-/regex-6.0.1.tgz", 4633 + "integrity": "sha512-uorlqlzAKjKQZ5P+kTJr3eeJGSVroLKoHmquUj4zHWuR+hEyNqlXsSKlYYF5F4NI6nl7tWCs0apKJ0lmfsXAPA==", 4634 + "license": "MIT", 4635 + "dependencies": { 4636 + "regex-utilities": "^2.3.0" 4637 + } 4638 + }, 4639 + "node_modules/regex-recursion": { 4640 + "version": "6.0.2", 4641 + "resolved": "https://registry.npmjs.org/regex-recursion/-/regex-recursion-6.0.2.tgz", 4642 + "integrity": "sha512-0YCaSCq2VRIebiaUviZNs0cBz1kg5kVS2UKUfNIx8YVs1cN3AV7NTctO5FOKBA+UT2BPJIWZauYHPqJODG50cg==", 4643 + "license": "MIT", 4644 + "dependencies": { 4645 + "regex-utilities": "^2.3.0" 4646 + } 4647 + }, 4648 + "node_modules/regex-utilities": { 4649 + "version": "2.3.0", 4650 + "resolved": "https://registry.npmjs.org/regex-utilities/-/regex-utilities-2.3.0.tgz", 4651 + "integrity": "sha512-8VhliFJAWRaUiVvREIiW2NXXTmHs4vMNnSzuJVhscgmGav3g9VDxLrQndI3dZZVVdp0ZO/5v0xmX516/7M9cng==", 4652 + "license": "MIT" 4653 + }, 4287 4654 "node_modules/resolve": { 4288 4655 "version": "1.22.8", 4289 4656 "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", ··· 4564 4931 "node": ">=8" 4565 4932 } 4566 4933 }, 4934 + "node_modules/shiki": { 4935 + "version": "3.4.2", 4936 + "resolved": "https://registry.npmjs.org/shiki/-/shiki-3.4.2.tgz", 4937 + "integrity": "sha512-wuxzZzQG8kvZndD7nustrNFIKYJ1jJoWIPaBpVe2+KHSvtzMi4SBjOxrigs8qeqce/l3U0cwiC+VAkLKSunHQQ==", 4938 + "license": "MIT", 4939 + "dependencies": { 4940 + "@shikijs/core": "3.4.2", 4941 + "@shikijs/engine-javascript": "3.4.2", 4942 + "@shikijs/engine-oniguruma": "3.4.2", 4943 + "@shikijs/langs": "3.4.2", 4944 + "@shikijs/themes": "3.4.2", 4945 + "@shikijs/types": "3.4.2", 4946 + "@shikijs/vscode-textmate": "^10.0.2", 4947 + "@types/hast": "^3.0.4" 4948 + } 4949 + }, 4567 4950 "node_modules/side-channel": { 4568 4951 "version": "1.0.6", 4569 4952 "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz", ··· 4660 5043 }, 4661 5044 "engines": { 4662 5045 "node": ">= 8" 5046 + } 5047 + }, 5048 + "node_modules/space-separated-tokens": { 5049 + "version": "2.0.2", 5050 + "resolved": "https://registry.npmjs.org/space-separated-tokens/-/space-separated-tokens-2.0.2.tgz", 5051 + "integrity": "sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==", 5052 + "license": "MIT", 5053 + "funding": { 5054 + "type": "github", 5055 + "url": "https://github.com/sponsors/wooorm" 4663 5056 } 4664 5057 }, 4665 5058 "node_modules/split2": { ··· 4753 5146 "node": ">=8" 4754 5147 } 4755 5148 }, 5149 + "node_modules/stringify-entities": { 5150 + "version": "4.0.4", 5151 + "resolved": "https://registry.npmjs.org/stringify-entities/-/stringify-entities-4.0.4.tgz", 5152 + "integrity": "sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg==", 5153 + "license": "MIT", 5154 + "dependencies": { 5155 + "character-entities-html4": "^2.0.0", 5156 + "character-entities-legacy": "^3.0.0" 5157 + }, 5158 + "funding": { 5159 + "type": "github", 5160 + "url": "https://github.com/sponsors/wooorm" 5161 + } 5162 + }, 4756 5163 "node_modules/strip-ansi": { 4757 5164 "version": "7.1.0", 4758 5165 "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", ··· 5042 5449 "license": "MIT", 5043 5450 "bin": { 5044 5451 "tree-kill": "cli.js" 5452 + } 5453 + }, 5454 + "node_modules/trim-lines": { 5455 + "version": "3.0.1", 5456 + "resolved": "https://registry.npmjs.org/trim-lines/-/trim-lines-3.0.1.tgz", 5457 + "integrity": "sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg==", 5458 + "license": "MIT", 5459 + "funding": { 5460 + "type": "github", 5461 + "url": "https://github.com/sponsors/wooorm" 5045 5462 } 5046 5463 }, 5047 5464 "node_modules/ts-interface-checker": { ··· 5752 6169 "dev": true, 5753 6170 "license": "MIT" 5754 6171 }, 6172 + "node_modules/unist-util-is": { 6173 + "version": "6.0.0", 6174 + "resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-6.0.0.tgz", 6175 + "integrity": "sha512-2qCTHimwdxLfz+YzdGfkqNlH0tLi9xjTnHddPmJwtIG9MGsdbutfTc4P+haPD7l7Cjxf/WZj+we5qfVPvvxfYw==", 6176 + "license": "MIT", 6177 + "dependencies": { 6178 + "@types/unist": "^3.0.0" 6179 + }, 6180 + "funding": { 6181 + "type": "opencollective", 6182 + "url": "https://opencollective.com/unified" 6183 + } 6184 + }, 6185 + "node_modules/unist-util-position": { 6186 + "version": "5.0.0", 6187 + "resolved": "https://registry.npmjs.org/unist-util-position/-/unist-util-position-5.0.0.tgz", 6188 + "integrity": "sha512-fucsC7HjXvkB5R3kTCO7kUjRdrS0BJt3M/FPxmHMBOm8JQi2BsHAHFsy27E0EolP8rp0NzXsJ+jNPyDWvOJZPA==", 6189 + "license": "MIT", 6190 + "dependencies": { 6191 + "@types/unist": "^3.0.0" 6192 + }, 6193 + "funding": { 6194 + "type": "opencollective", 6195 + "url": "https://opencollective.com/unified" 6196 + } 6197 + }, 6198 + "node_modules/unist-util-stringify-position": { 6199 + "version": "4.0.0", 6200 + "resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-4.0.0.tgz", 6201 + "integrity": "sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==", 6202 + "license": "MIT", 6203 + "dependencies": { 6204 + "@types/unist": "^3.0.0" 6205 + }, 6206 + "funding": { 6207 + "type": "opencollective", 6208 + "url": "https://opencollective.com/unified" 6209 + } 6210 + }, 6211 + "node_modules/unist-util-visit": { 6212 + "version": "5.0.0", 6213 + "resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-5.0.0.tgz", 6214 + "integrity": "sha512-MR04uvD+07cwl/yhVuVWAtw+3GOR/knlL55Nd/wAdblk27GCVt3lqpTivy/tkJcZoNPzTwS1Y+KMojlLDhoTzg==", 6215 + "license": "MIT", 6216 + "dependencies": { 6217 + "@types/unist": "^3.0.0", 6218 + "unist-util-is": "^6.0.0", 6219 + "unist-util-visit-parents": "^6.0.0" 6220 + }, 6221 + "funding": { 6222 + "type": "opencollective", 6223 + "url": "https://opencollective.com/unified" 6224 + } 6225 + }, 6226 + "node_modules/unist-util-visit-parents": { 6227 + "version": "6.0.1", 6228 + "resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-6.0.1.tgz", 6229 + "integrity": "sha512-L/PqWzfTP9lzzEa6CKs0k2nARxTdZduw3zyh8d2NVBnsyvHjSX4TWse388YrrQKbvI8w20fGjGlhgT96WwKykw==", 6230 + "license": "MIT", 6231 + "dependencies": { 6232 + "@types/unist": "^3.0.0", 6233 + "unist-util-is": "^6.0.0" 6234 + }, 6235 + "funding": { 6236 + "type": "opencollective", 6237 + "url": "https://opencollective.com/unified" 6238 + } 6239 + }, 5755 6240 "node_modules/unpipe": { 5756 6241 "version": "1.0.0", 5757 6242 "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", ··· 5796 6281 "license": "MIT", 5797 6282 "engines": { 5798 6283 "node": ">= 0.8" 6284 + } 6285 + }, 6286 + "node_modules/vfile": { 6287 + "version": "6.0.3", 6288 + "resolved": "https://registry.npmjs.org/vfile/-/vfile-6.0.3.tgz", 6289 + "integrity": "sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q==", 6290 + "license": "MIT", 6291 + "dependencies": { 6292 + "@types/unist": "^3.0.0", 6293 + "vfile-message": "^4.0.0" 6294 + }, 6295 + "funding": { 6296 + "type": "opencollective", 6297 + "url": "https://opencollective.com/unified" 6298 + } 6299 + }, 6300 + "node_modules/vfile-message": { 6301 + "version": "4.0.2", 6302 + "resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-4.0.2.tgz", 6303 + "integrity": "sha512-jRDZ1IMLttGj41KcZvlrYAaI3CfqpLpfpf+Mfig13viT6NKvRzWZ+lXz0Y5D60w6uJIBAOGq9mSHf0gktF0duw==", 6304 + "license": "MIT", 6305 + "dependencies": { 6306 + "@types/unist": "^3.0.0", 6307 + "unist-util-stringify-position": "^4.0.0" 6308 + }, 6309 + "funding": { 6310 + "type": "opencollective", 6311 + "url": "https://opencollective.com/unified" 5799 6312 } 5800 6313 }, 5801 6314 "node_modules/void-elements": { ··· 6003 6516 "license": "MIT", 6004 6517 "funding": { 6005 6518 "url": "https://github.com/sponsors/colinhacks" 6519 + } 6520 + }, 6521 + "node_modules/zwitch": { 6522 + "version": "2.0.4", 6523 + "resolved": "https://registry.npmjs.org/zwitch/-/zwitch-2.0.4.tgz", 6524 + "integrity": "sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==", 6525 + "license": "MIT", 6526 + "funding": { 6527 + "type": "github", 6528 + "url": "https://github.com/sponsors/wooorm" 6006 6529 } 6007 6530 } 6008 6531 }
+3 -1
package.json
··· 30 30 "multiformats": "^9.9.0", 31 31 "pino": "^9.3.2", 32 32 "pug": "^3.0.3", 33 + "shiki": "^3.4.2", 33 34 "uhtml": "^4.5.9" 34 35 }, 35 36 "devDependencies": { ··· 50 51 "!src/**/*.test.*" 51 52 ], 52 53 "loader": { 53 - ".pug": "copy" 54 + ".pug": "copy", 55 + ".woff2": "copy" 54 56 }, 55 57 "splitting": false, 56 58 "sourcemap": true,
src/assets/NerdIosevka-Regular.woff2

This is a binary file and will not be displayed.

+1 -1
src/auth/client.ts
··· 12 12 client_name: "plonk.li", 13 13 client_id: publicUrl 14 14 ? `${url}/client-metadata.json` 15 - : `http://localhost?redirect_uri=${enc(`${url}/oauth/callback`)}&scope=${enc("atproto transition:generic")}`, 15 + : `http://${env.PLONK_HOST}?redirect_uri=${enc(`${url}/oauth/callback`)}&scope=${enc("atproto transition:generic")}`, 16 16 client_uri: url, 17 17 redirect_uris: [`${url}/oauth/callback`], 18 18 scope: "atproto transition:generic",
+48
src/lib/highlight.ts
··· 1 + import { createHighlighter, HighlighterGeneric, BundledLanguage, BundledTheme } from 'shiki' 2 + import type { Element } from 'hast' 3 + 4 + let highlighter: HighlighterGeneric<BundledLanguage, BundledTheme> | null = null 5 + 6 + export async function getHighlighterInstance() { 7 + if (!highlighter) { 8 + highlighter = await createHighlighter({ 9 + themes: ['catppuccin-latte', 'catppuccin-mocha'], 10 + langs: [ 11 + 'javascript', 'typescript', 'python', 'java', 'rust', 12 + 'go', 'c', 'cpp', 'csharp', 'php', 'ruby', 'cobol', 13 + 'plaintext', 'txt', 'bash', 'nix' 14 + ] 15 + }) 16 + } 17 + return highlighter 18 + } 19 + 20 + export async function highlightCode(code: string, lang: string) { 21 + const highlighter = await getHighlighterInstance() 22 + 23 + try { 24 + return highlighter.codeToHtml(code, { 25 + lang: lang, 26 + themes: { 27 + light: 'catppuccin-latte', 28 + dark: 'catppuccin-mocha' 29 + }, 30 + transformers: [ 31 + { 32 + line(node: Element, line: number) { 33 + node.properties['code-line'] = line 34 + } 35 + } 36 + ] 37 + }) 38 + } catch (error) { 39 + console.warn(`Language "${lang}" not supported by Shiki, falling back to plaintext`) 40 + return highlighter.codeToHtml(code, { 41 + lang: 'txt', 42 + themes: { 43 + light: 'catppuccin-latte', 44 + dark: 'catppuccin-mocha' 45 + } 46 + }) 47 + } 48 + }
+9
src/mixins/footer.pug
··· 1 + mixin footer() 2 + hr 3 + div.footer 4 + div.left-side 5 + div.right-side 6 + p 7 + | made by 8 + a(href="https://bsky.app/profile/oppi.li") @oppi.li 9 +
+1 -1
src/mixins/head.pug
··· 2 2 head 3 3 meta(name="viewport" content="width=device-width, initial-scale=1.0") 4 4 meta(charset='UTF-8') 5 - title #{title} 5 + title #{title} ยท plonk.li 6 6 link(rel="stylesheet", href="/styles.css") 7 7 link(rel="preconnect" href="https://rsms.me/") 8 8 link(rel="stylesheet" href="https://rsms.me/inter/inter.css")
-2
src/mixins/header.pug
··· 1 1 mixin header(ownDid, didHandleMap) 2 2 div.header 3 3 div.left-side 4 - if ownDid 5 - | logged in as @#{didHandleMap[ownDid]} 6 4 div.right-side 7 5 p 8 6 a(href="/") home
+3 -2
src/mixins/post.pug
··· 1 1 mixin post(paste, handle, did) 2 2 div.post 3 3 p 4 - a(href=`/p/${paste.shortUrl}`) 4 + a(href=`/p/${paste.shortUrl}`).post-link 5 5 | #{paste.title} 6 6 p.post-info 7 7 | by ··· 13 13 | #{paste.lang} 14 14 | ยท 15 15 | #{paste.code.split('\n').length} loc 16 - 16 + | ยท&nbsp; 17 + a(href=`/p/${paste.shortUrl}/#comments`) #{paste.commentCount} #{pluralize(paste.commentCount, 'comment')}
+4
src/mixins/utils.pug
··· 2 2 function randInt(min, max) { 3 3 return Math.floor(Math.random() * (max - min + 1)) + min; 4 4 } 5 + - 6 + function pluralize(count, noun) { 7 + return count==1?noun:`${noun}s`; 8 + } 5 9 - 6 10 function timeDifference(current, previous) { 7 11 if (!current || !previous) {
+134 -5
src/public/styles.css
··· 1 - @import url('https://fonts.googleapis.com/css2?family=IBM+Plex+Mono:ital,wght@0,100;0,200;0,300;0,400;0,500;0,600;0,700;1,100;1,200;1,300;1,400;1,500;1,600;1,700&display=swap'); 1 + @font-face { 2 + font-family: 'NerdIosevka'; 3 + src: url('../assets/NerdIosevka-Regular.woff2') format('woff2'); 4 + font-weight: normal; 5 + font-style: monospace; 6 + } 7 + 8 + @media (prefers-color-scheme: dark) { 9 + .shiki, 10 + .shiki span { 11 + color: var(--shiki-dark) !important; 12 + background-color: var(--shiki-dark-bg) !important; 13 + font-style: var(--shiki-dark-font-style) !important; 14 + font-weight: var(--shiki-dark-font-weight) !important; 15 + text-decoration: var(--shiki-dark-text-decoration) !important; 16 + } 17 + } 2 18 3 19 :root { 4 20 /* Light mode colors */ ··· 28 44 } 29 45 30 46 * { 31 - font-family: 'IBM Plex Mono', monospace; 47 + font-family: 'NerdIosevka', monospace; 48 + font-size: 0.9rem; 32 49 } 33 50 34 51 body { ··· 52 69 } 53 70 54 71 pre { 55 - background-color: var(--bg-color-muted); 56 72 padding: 1rem; 57 73 overflow-x: auto; 58 74 } 59 75 76 + .comment-body { 77 + background-color: var(--bg-color); 78 + padding: 0; 79 + margin-top: 0.1rem; 80 + } 81 + 82 + .comment-info { 83 + margin-bottom: 0; 84 + } 85 + 60 86 input, textarea, select, button { 61 87 border: none; 62 88 padding: 1rem; ··· 93 119 hr { 94 120 border: none; 95 121 border-top: 1px solid var(--bg-color-muted); 96 - padding: 1rem; 97 122 } 98 123 99 124 .post-form { ··· 127 152 align-self: flex-end; 128 153 } 129 154 155 + .post-link { 156 + color: var(--text-color); 157 + text-decoration: none; 158 + } 159 + .post-link:hover { 160 + text-decoration: underline; 161 + } 162 + .post-link:visited { 163 + color: var(--text-color-muted); 164 + } 165 + 166 + .post-info { 167 + margin-top: 0; 168 + } 169 + 170 + .post-info, .comment-info { 171 + color: var(--text-color-muted); 172 + } 173 + .post-info a, .comment-info a { 174 + color: var(--text-color-muted); 175 + text-decoration: none; 176 + } 177 + .post-info a:visited, .comment-info a:visited { 178 + color: var(--text-color-muted); 179 + } 180 + .post-info a:hover, .comment-info a:hover { 181 + text-decoration: underline; 182 + } 183 + 130 184 .timeline, .comments { 131 185 display: flex; 132 186 flex-direction: column; 133 187 gap: 1rem; 188 + padding-bottom: 1rem; 134 189 } 135 190 136 191 .login-input-title { ··· 141 196 flex: 1 142 197 } 143 198 144 - .header { 199 + .header, .footer { 145 200 display: flex; 146 201 flex-direction: row; 147 202 justify-content: space-between; ··· 154 209 text-indent: 1px; 155 210 text-overflow: ''; 156 211 } 212 + 213 + .code-line { 214 + display: flex; 215 + } 216 + 217 + .code-line-num { 218 + white-space: pre; 219 + -webkit-user-select: none; 220 + user-select: none; 221 + margin-right: 0.4em; 222 + padding: 0 0.4em 0 0.4em; 223 + color: var(--text-color-muted); 224 + text-align: right; 225 + } 226 + 227 + .code-line-content { 228 + color: var(--text-color); 229 + } 230 + 231 + .header, .footer { 232 + color: var(--text-color); 233 + } 234 + 235 + .header a, .header a:visited, 236 + .footer a, .footer a:visited { 237 + color: var(--link-color); 238 + text-decoration: none; 239 + } 240 + 241 + .header a:hover, 242 + .footer a:hover { 243 + text-decoration: underline; 244 + } 245 + 246 + .highlighted-code { 247 + margin: 1rem 0; 248 + counter-reset: step; 249 + counter-increment: step calc(var(--start, 1) - 1); 250 + } 251 + 252 + .highlighted-code pre { 253 + padding: 1rem; 254 + overflow-x: auto; 255 + border-radius: 4px; 256 + } 257 + 258 + code .line::before { 259 + content: counter(step); 260 + counter-increment: step; 261 + width: 1rem; 262 + margin-right: 1.5rem; 263 + display: inline-block; 264 + text-align: right; 265 + color: rgba(115,138,148,.4) 266 + } 267 + 268 + #copy-btn { 269 + background: none; 270 + border: none; 271 + padding: 0; 272 + color: var(--text-color-muted); 273 + cursor: pointer; 274 + text-decoration: none; 275 + font-family: inherit; 276 + font-size: inherit; 277 + } 278 + 279 + #copy-btn:hover { 280 + text-decoration: underline; 281 + } 282 + 283 + #copy-btn:focus { 284 + outline: 1px solid var(--accent); 285 + }
+44 -12
src/routes.ts
··· 11 11 12 12 import * as Paste from "#/lexicons/types/li/plonk/paste"; 13 13 import * as Comment from "#/lexicons/types/li/plonk/comment"; 14 + import { highlightCode } from "#/lib/highlight"; 14 15 15 16 type Session = { 16 17 did: string; ··· 49 50 export const createRouter = (ctx: Ctx) => { 50 51 const router = express.Router(); 51 52 53 + router.use("/assets", express.static(path.join(__dirname, "assets"))); 52 54 // OAuth metadata 53 55 router.get("/client-metadata.json", async (_req, res) => { 54 56 return res.json(ctx.oauthClient.clientMetadata); ··· 104 106 const agent = await getSessionAgent(req, res, ctx); 105 107 const pastes = await ctx.db 106 108 .selectFrom("paste") 107 - .selectAll() 108 - .orderBy("indexedAt", "desc") 109 + .leftJoin("comment", "comment.pasteUri", "paste.uri") 110 + .select([ 111 + "paste.uri", 112 + "paste.shortUrl", 113 + "paste.authorDid", 114 + "paste.code", 115 + "paste.lang", 116 + "paste.title", 117 + "paste.createdAt", 118 + "paste.indexedAt as pasteIndexedAt", 119 + ctx.db.fn.count("comment.uri").as("commentCount") 120 + ]) 121 + .groupBy("paste.uri") 122 + .orderBy("pasteIndexedAt", "desc") 109 123 .limit(25) 110 124 .execute(); 111 125 ··· 129 143 const { authorDid } = req.params; 130 144 const pastes = await ctx.db 131 145 .selectFrom("paste") 132 - .selectAll() 133 - .where("authorDid", "=", authorDid) 146 + .leftJoin("comment", "comment.pasteUri", "paste.uri") 147 + .select([ 148 + "paste.uri", 149 + "paste.shortUrl", 150 + "paste.authorDid as pasteAuthorDid", 151 + "paste.code", 152 + "paste.lang", 153 + "paste.title", 154 + "paste.createdAt as pasteCreatedAt", 155 + "paste.indexedAt as pasteIndexedAt", 156 + ctx.db.fn.count("comment.uri").as("commentCount") 157 + ]) 158 + .groupBy("paste.uri") 159 + .where("pasteAuthorDid", "=", authorDid) 160 + .orderBy("pasteCreatedAt", "desc") 134 161 .execute(); 135 162 let didHandleMap: Record<string, string> = {}; 136 163 didHandleMap[authorDid] = await ctx.resolver.resolveDidToHandle(authorDid); ··· 183 210 ), 184 211 ); 185 212 213 + const highlightedCode = await highlightCode(pasteCode, pasteLang); 214 + 186 215 const paste = { 187 216 uri: pasteUri, 188 217 code: pasteCode, 218 + highlightedCode, 189 219 title: pasteTitle, 190 220 lang: pasteLang, 191 221 shortUrl, ··· 193 223 authorDid: pasteAuthorDid, 194 224 }; 195 225 196 - const comments = ret.map((row) => { 197 - return { 198 - uri: row.commentUri, 199 - authorDid: row.commentAuthorDid, 200 - body: row.commentBody, 201 - createdAt: row.commentCreatedAt, 202 - }; 203 - }); 226 + const comments = ret 227 + .filter((row) => row.commentUri) 228 + .map((row) => { 229 + return { 230 + uri: row.commentUri, 231 + authorDid: row.commentAuthorDid, 232 + body: row.commentBody, 233 + createdAt: row.commentCreatedAt, 234 + }; 235 + }); 204 236 205 237 const ownAgent = await getSessionAgent(req, res, ctx); 206 238 if (!ownAgent) {
+6
src/views/index.pug
··· 1 1 include ../mixins/mkPost 2 2 include ../mixins/head 3 3 include ../mixins/header 4 + include ../mixins/footer 4 5 include ../mixins/utils 5 6 include ../mixins/post 6 7 ··· 8 9 - 9 10 var langs = ["plaintext"] 10 11 .concat([ 12 + "bash", 11 13 "javascript", 12 14 "typescript", 13 15 "java", ··· 19 21 "c", 20 22 "c#", 21 23 "c++", 24 + "cobol", 25 + "nix", 22 26 ].toSorted()) 23 27 doctype html 24 28 html ··· 34 38 each paste in pastes 35 39 - var handle = didHandleMap[paste.authorDid] 36 40 +post(paste, handle, paste.authorDid) 41 + 42 + +footer()
+5 -8
src/views/login.pug
··· 1 + include ../mixins/head 2 + include ../mixins/footer 3 + 1 4 doctype html 2 5 html 3 - head 4 - meta(name="viewport" content="width=device-width, initial-scale=1.0") 5 - meta(charset='UTF-8') 6 - title login 7 - link(rel="stylesheet", href="/styles.css") 8 - link(rel="preconnect" href="https://rsms.me/") 9 - link(rel="stylesheet" href="https://rsms.me/inter/inter.css") 10 - script(src="https://cdn.dashjs.org/latest/dash.all.min.js") 6 + +head("login") 11 7 body 12 8 main#content 13 9 h1 login ··· 15 11 div.login-row 16 12 input(type="text" name="handle" placeholder="enter handle" required).login-input-title 17 13 button(type="submit").login-submit-button login 14 + +footer()
+55 -19
src/views/paste.pug
··· 1 1 - var now = new Date() 2 2 include ../mixins/head 3 3 include ../mixins/header 4 + include ../mixins/footer 4 5 include ../mixins/utils 5 6 doctype html 6 7 html 7 - +head(paste.title) 8 + +head(`${paste.title} ยท ${didHandleMap[paste.authorDid]}`) 8 9 body 9 10 main#content 10 11 +header(ownDid, didHandleMap) 11 12 h1 #{paste.title} 12 - p 13 - | by @#{didHandleMap[paste.authorDid]} ยท 13 + p.post-info 14 + | @#{didHandleMap[paste.authorDid]} ยท 14 15 | #{timeDifference(now, Date.parse(paste.createdAt))} ago ยท 15 16 | #{paste.lang} ยท 16 17 | #{paste.code.split('\n').length} loc ยท 17 18 a(href=`/r/${paste.shortUrl}`) raw 18 - pre 19 - | #{paste.code} 19 + | &nbsp;ยท&nbsp; 20 + button#copy-btn(type="button" onclick="copyToClipboard()" data-code=paste.code) copy 21 + | &nbsp;ยท 22 + | #{comments.length} #{pluralize(comments.length, 'comment')} 23 + div.highlighted-code !{paste.highlightedCode} 20 24 hr 21 25 22 - div.comments 23 - each comment in comments 24 - div.comment(id=`${encodeURIComponent(comment.uri)}`) 25 - p 26 - | by @#{didHandleMap[comment.authorDid]} ยท 27 - | #{timeDifference(now, Date.parse(paste.createdAt))} ago 28 - p 29 - | #{comment.body} 30 - hr 26 + if comments.length != 0 27 + h1(id="comments") comments 28 + div.comments 29 + each comment in comments 30 + div.comment(id=`${encodeURIComponent(comment.uri)}`) 31 + p.comment-info 32 + a(href=`/u/${comment.authorDid}`) 33 + | @#{didHandleMap[comment.authorDid]} 34 + | &nbsp;ยท 35 + | #{timeDifference(now, Date.parse(paste.createdAt))} ago 36 + pre.comment-body #{comment.body} 31 37 32 - form(action=`/${encodeURIComponent(paste.uri)}/comment` method="post").post-form 33 - div.post-row 34 - textarea#code(name="comment" rows="5" placeholder="add a comment" required).post-input-code 38 + if ownDid 39 + form(action=`/${encodeURIComponent(paste.uri)}/comment` method="post").post-form 40 + div.post-row 41 + textarea#code(name="comment" rows="5" placeholder="add a comment" required).post-input-code 35 42 36 - div.post-submit-row 37 - button(type="submit").post-input-submit zonk! 43 + div.post-submit-row 44 + button(type="submit").post-input-submit zonk! 45 + else 46 + p 47 + a(href="/login") login 48 + |&nbsp;to post a comment 49 + 50 + +footer() 51 + script. 52 + async function copyToClipboard() { 53 + const copyBtn = document.getElementById('copy-btn'); 54 + const originalText = copyBtn.textContent; 55 + 56 + try { 57 + const code = copyBtn.dataset.code; 58 + await navigator.clipboard.writeText(code); 59 + copyBtn.textContent = 'copied!'; 60 + copyBtn.style.color = 'var(--accent)'; 61 + 62 + setTimeout(() => { 63 + copyBtn.textContent = originalText; 64 + copyBtn.style.color = ''; 65 + }, 1500); 66 + } catch (err) { 67 + console.error('Failed to copy: ', err); 68 + copyBtn.textContent = 'copy failed'; 69 + setTimeout(() => { 70 + copyBtn.textContent = originalText; 71 + }, 1500); 72 + } 73 + }
+3
src/views/user.pug
··· 2 2 - var handle = didHandleMap[authorDid] 3 3 include ../mixins/head 4 4 include ../mixins/header 5 + include ../mixins/footer 5 6 include ../mixins/utils 6 7 include ../mixins/post 7 8 doctype html ··· 14 15 div.timeline 15 16 each paste in pastes 16 17 +post(paste, handle, authorDid) 18 + 19 + +footer()