feat: static pages
This commit is contained in:
parent
96bff400e8
commit
5f43e417d1
34 changed files with 409 additions and 1567 deletions
654
package-lock.json
generated
654
package-lock.json
generated
|
@ -1,12 +1,12 @@
|
|||
{
|
||||
"name": "coryd.dev",
|
||||
"version": "2.9.0",
|
||||
"version": "3.0.0",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "coryd.dev",
|
||||
"version": "2.9.0",
|
||||
"version": "3.0.0",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@11ty/eleventy-fetch": "4.0.1",
|
||||
|
@ -19,16 +19,14 @@
|
|||
"devDependencies": {
|
||||
"@11ty/eleventy": "v3.0.0",
|
||||
"@11ty/eleventy-plugin-syntaxhighlight": "^5.0.0",
|
||||
"@cdransf/eleventy-plugin-tabler-icons": "^2.1.1",
|
||||
"@cdransf/eleventy-plugin-tabler-icons": "^2.2.0",
|
||||
"@supabase/supabase-js": "^2.46.1",
|
||||
"autoprefixer": "^10.4.20",
|
||||
"cssnano": "^7.0.6",
|
||||
"dotenv-flow": "^4.1.0",
|
||||
"express": "4.21.1",
|
||||
"fast-xml-parser": "^4.5.0",
|
||||
"html-minifier-terser": "^7.2.0",
|
||||
"html-to-text": "^9.0.5",
|
||||
"http-proxy-middleware": "3.0.3",
|
||||
"i18n-iso-countries": "7.13.0",
|
||||
"ics": "^3.8.1",
|
||||
"linkedom": "0.18.5",
|
||||
|
@ -37,7 +35,7 @@
|
|||
"markdown-it-anchor": "^9.2.0",
|
||||
"markdown-it-footnote": "^4.0.0",
|
||||
"markdown-it-prism": "^2.3.0",
|
||||
"postcss": "^8.4.48",
|
||||
"postcss": "^8.4.49",
|
||||
"postcss-import": "^16.1.0",
|
||||
"postcss-import-ext-glob": "^2.1.1",
|
||||
"rimraf": "^6.0.1",
|
||||
|
@ -398,9 +396,9 @@
|
|||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@cdransf/eleventy-plugin-tabler-icons": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@cdransf/eleventy-plugin-tabler-icons/-/eleventy-plugin-tabler-icons-2.1.1.tgz",
|
||||
"integrity": "sha512-KCP2sT0xzZNc6PiMhu8JsMRumk+ee9ysWbQ2UTyhgovzl7RZ0Io0KdmBJ3IzeYcXRJOwWSsHg/e2Yv3Lgzs8xg==",
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/@cdransf/eleventy-plugin-tabler-icons/-/eleventy-plugin-tabler-icons-2.2.0.tgz",
|
||||
"integrity": "sha512-z/OjYyBD7MUUwSkAqQi3k4U76yhrJ152wu8aM4be5TK5fi1hRIAw3MRrYWwmhjTPRVYEQGAgHc8EZXFliCKg9g==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
|
@ -685,16 +683,6 @@
|
|||
"node": ">=10.13.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/http-proxy": {
|
||||
"version": "1.17.15",
|
||||
"resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.15.tgz",
|
||||
"integrity": "sha512-25g5atgiVNTIv0LBDTg1H74Hvayx0ajtJPLLcYE3whFv75J0pWNtOBzaXJQgDTmrX1bx5U9YC2w/n65BN1HwRQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/linkify-it": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/linkify-it/-/linkify-it-5.0.0.tgz",
|
||||
|
@ -757,20 +745,6 @@
|
|||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/accepts": {
|
||||
"version": "1.3.8",
|
||||
"resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz",
|
||||
"integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"mime-types": "~2.1.34",
|
||||
"negotiator": "0.6.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/acorn": {
|
||||
"version": "8.14.0",
|
||||
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.0.tgz",
|
||||
|
@ -854,13 +828,6 @@
|
|||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/array-flatten": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
|
||||
"integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/array-union": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz",
|
||||
|
@ -1000,48 +967,6 @@
|
|||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/body-parser": {
|
||||
"version": "1.20.3",
|
||||
"resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz",
|
||||
"integrity": "sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"bytes": "3.1.2",
|
||||
"content-type": "~1.0.5",
|
||||
"debug": "2.6.9",
|
||||
"depd": "2.0.0",
|
||||
"destroy": "1.2.0",
|
||||
"http-errors": "2.0.0",
|
||||
"iconv-lite": "0.4.24",
|
||||
"on-finished": "2.4.1",
|
||||
"qs": "6.13.0",
|
||||
"raw-body": "2.5.2",
|
||||
"type-is": "~1.6.18",
|
||||
"unpipe": "1.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.8",
|
||||
"npm": "1.2.8000 || >= 1.4.16"
|
||||
}
|
||||
},
|
||||
"node_modules/body-parser/node_modules/debug": {
|
||||
"version": "2.6.9",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
|
||||
"integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"ms": "2.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/body-parser/node_modules/ms": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
|
||||
"integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/boolbase": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz",
|
||||
|
@ -1112,16 +1037,6 @@
|
|||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/bytes": {
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz",
|
||||
"integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/call-bind": {
|
||||
"version": "1.0.7",
|
||||
"resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz",
|
||||
|
@ -1315,46 +1230,6 @@
|
|||
"integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/content-disposition": {
|
||||
"version": "0.5.4",
|
||||
"resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz",
|
||||
"integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"safe-buffer": "5.2.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/content-type": {
|
||||
"version": "1.0.5",
|
||||
"resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz",
|
||||
"integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/cookie": {
|
||||
"version": "0.7.1",
|
||||
"resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.1.tgz",
|
||||
"integrity": "sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/cookie-signature": {
|
||||
"version": "1.0.6",
|
||||
"resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
|
||||
"integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/cross-spawn": {
|
||||
"version": "7.0.5",
|
||||
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.5.tgz",
|
||||
|
@ -1799,9 +1674,9 @@
|
|||
"license": "MIT"
|
||||
},
|
||||
"node_modules/electron-to-chromium": {
|
||||
"version": "1.5.55",
|
||||
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.55.tgz",
|
||||
"integrity": "sha512-6maZ2ASDOTBtjt9FhqYPRnbvKU5tjG0IN9SztUOWYw2AzNDNpKJYLJmlK0/En4Hs/aiWnB+JZ+gW19PIGszgKg==",
|
||||
"version": "1.5.57",
|
||||
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.57.tgz",
|
||||
"integrity": "sha512-xS65H/tqgOwUBa5UmOuNSLuslDo7zho0y/lgQw35pnrqiZh7UOWHCeL/Bt6noJATbA6tpQJGCifsFsIRZj1Fqg==",
|
||||
"dev": true,
|
||||
"license": "ISC"
|
||||
},
|
||||
|
@ -1964,114 +1839,6 @@
|
|||
"integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/express": {
|
||||
"version": "4.21.1",
|
||||
"resolved": "https://registry.npmjs.org/express/-/express-4.21.1.tgz",
|
||||
"integrity": "sha512-YSFlK1Ee0/GC8QaO91tHcDxJiE/X4FbpAyQWkxAvG6AXCuR65YzK8ua6D9hvi/TzUfZMpc+BwuM1IPw8fmQBiQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"accepts": "~1.3.8",
|
||||
"array-flatten": "1.1.1",
|
||||
"body-parser": "1.20.3",
|
||||
"content-disposition": "0.5.4",
|
||||
"content-type": "~1.0.4",
|
||||
"cookie": "0.7.1",
|
||||
"cookie-signature": "1.0.6",
|
||||
"debug": "2.6.9",
|
||||
"depd": "2.0.0",
|
||||
"encodeurl": "~2.0.0",
|
||||
"escape-html": "~1.0.3",
|
||||
"etag": "~1.8.1",
|
||||
"finalhandler": "1.3.1",
|
||||
"fresh": "0.5.2",
|
||||
"http-errors": "2.0.0",
|
||||
"merge-descriptors": "1.0.3",
|
||||
"methods": "~1.1.2",
|
||||
"on-finished": "2.4.1",
|
||||
"parseurl": "~1.3.3",
|
||||
"path-to-regexp": "0.1.10",
|
||||
"proxy-addr": "~2.0.7",
|
||||
"qs": "6.13.0",
|
||||
"range-parser": "~1.2.1",
|
||||
"safe-buffer": "5.2.1",
|
||||
"send": "0.19.0",
|
||||
"serve-static": "1.16.2",
|
||||
"setprototypeof": "1.2.0",
|
||||
"statuses": "2.0.1",
|
||||
"type-is": "~1.6.18",
|
||||
"utils-merge": "1.0.1",
|
||||
"vary": "~1.1.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/express/node_modules/debug": {
|
||||
"version": "2.6.9",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
|
||||
"integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"ms": "2.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/express/node_modules/debug/node_modules/ms": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
|
||||
"integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/express/node_modules/mime": {
|
||||
"version": "1.6.0",
|
||||
"resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz",
|
||||
"integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"bin": {
|
||||
"mime": "cli.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/express/node_modules/send": {
|
||||
"version": "0.19.0",
|
||||
"resolved": "https://registry.npmjs.org/send/-/send-0.19.0.tgz",
|
||||
"integrity": "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"debug": "2.6.9",
|
||||
"depd": "2.0.0",
|
||||
"destroy": "1.2.0",
|
||||
"encodeurl": "~1.0.2",
|
||||
"escape-html": "~1.0.3",
|
||||
"etag": "~1.8.1",
|
||||
"fresh": "0.5.2",
|
||||
"http-errors": "2.0.0",
|
||||
"mime": "1.6.0",
|
||||
"ms": "2.1.3",
|
||||
"on-finished": "2.4.1",
|
||||
"range-parser": "~1.2.1",
|
||||
"statuses": "2.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.8.0"
|
||||
}
|
||||
},
|
||||
"node_modules/express/node_modules/send/node_modules/encodeurl": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
|
||||
"integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/extend-shallow": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
|
||||
|
@ -2258,27 +2025,6 @@
|
|||
"integrity": "sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==",
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/follow-redirects": {
|
||||
"version": "1.15.9",
|
||||
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.9.tgz",
|
||||
"integrity": "sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
"type": "individual",
|
||||
"url": "https://github.com/sponsors/RubenVerborgh"
|
||||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=4.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"debug": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/foreground-child": {
|
||||
"version": "3.3.0",
|
||||
"resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.0.tgz",
|
||||
|
@ -2296,16 +2042,6 @@
|
|||
"url": "https://github.com/sponsors/isaacs"
|
||||
}
|
||||
},
|
||||
"node_modules/forwarded": {
|
||||
"version": "0.2.0",
|
||||
"resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz",
|
||||
"integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/fraction.js": {
|
||||
"version": "4.3.7",
|
||||
"resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.3.7.tgz",
|
||||
|
@ -2675,39 +2411,6 @@
|
|||
"node": ">= 0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/http-proxy": {
|
||||
"version": "1.18.1",
|
||||
"resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz",
|
||||
"integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"eventemitter3": "^4.0.0",
|
||||
"follow-redirects": "^1.0.0",
|
||||
"requires-port": "^1.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/http-proxy-middleware": {
|
||||
"version": "3.0.3",
|
||||
"resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-3.0.3.tgz",
|
||||
"integrity": "sha512-usY0HG5nyDUwtqpiZdETNbmKtw3QQ1jwYFZ9wi5iHzX2BcILwQKtYDJPo7XHTsu5Z0B2Hj3W9NNnbd+AjFWjqg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/http-proxy": "^1.17.15",
|
||||
"debug": "^4.3.6",
|
||||
"http-proxy": "^1.18.1",
|
||||
"is-glob": "^4.0.3",
|
||||
"is-plain-object": "^5.0.0",
|
||||
"micromatch": "^4.0.8"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^14.15.0 || ^16.10.0 || >=18.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/i18n-iso-countries": {
|
||||
"version": "7.13.0",
|
||||
"resolved": "https://registry.npmjs.org/i18n-iso-countries/-/i18n-iso-countries-7.13.0.tgz",
|
||||
|
@ -2721,19 +2424,6 @@
|
|||
"node": ">= 12"
|
||||
}
|
||||
},
|
||||
"node_modules/iconv-lite": {
|
||||
"version": "0.4.24",
|
||||
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
|
||||
"integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"safer-buffer": ">= 2.1.2 < 3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/ics": {
|
||||
"version": "3.8.1",
|
||||
"resolved": "https://registry.npmjs.org/ics/-/ics-3.8.1.tgz",
|
||||
|
@ -2763,16 +2453,6 @@
|
|||
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/ipaddr.js": {
|
||||
"version": "1.9.1",
|
||||
"resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz",
|
||||
"integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.10"
|
||||
}
|
||||
},
|
||||
"node_modules/is-alphabetical": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/is-alphabetical/-/is-alphabetical-2.0.1.tgz",
|
||||
|
@ -2899,16 +2579,6 @@
|
|||
"node": ">=0.12.0"
|
||||
}
|
||||
},
|
||||
"node_modules/is-plain-object": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz",
|
||||
"integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/isexe": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
|
||||
|
@ -3244,26 +2914,6 @@
|
|||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/media-typer": {
|
||||
"version": "0.3.0",
|
||||
"resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
|
||||
"integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/merge-descriptors": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz",
|
||||
"integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/merge2": {
|
||||
"version": "1.4.1",
|
||||
"resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz",
|
||||
|
@ -3274,16 +2924,6 @@
|
|||
"node": ">= 8"
|
||||
}
|
||||
},
|
||||
"node_modules/methods": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz",
|
||||
"integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/micromatch": {
|
||||
"version": "4.0.8",
|
||||
"resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz",
|
||||
|
@ -3311,29 +2951,6 @@
|
|||
"node": ">=10.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/mime-db": {
|
||||
"version": "1.52.0",
|
||||
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
|
||||
"integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/mime-types": {
|
||||
"version": "2.1.35",
|
||||
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
|
||||
"integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"mime-db": "1.52.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/minimatch": {
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
|
||||
|
@ -3427,16 +3044,6 @@
|
|||
"node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/negotiator": {
|
||||
"version": "0.6.3",
|
||||
"resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz",
|
||||
"integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/no-case": {
|
||||
"version": "3.0.4",
|
||||
"resolved": "https://registry.npmjs.org/no-case/-/no-case-3.0.4.tgz",
|
||||
|
@ -3556,19 +3163,6 @@
|
|||
"node": ">= 6"
|
||||
}
|
||||
},
|
||||
"node_modules/object-inspect": {
|
||||
"version": "1.13.3",
|
||||
"resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.3.tgz",
|
||||
"integrity": "sha512-kDCGIbxkDSXE3euJZZXzc6to7fCrKHNI/hSRQnRuQ+BWjFNzZwiFF8fj/6o2t2G9/jTj8PSIYTfCLelLZEeRpA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/object-keys": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz",
|
||||
|
@ -3796,13 +3390,6 @@
|
|||
"url": "https://github.com/sponsors/isaacs"
|
||||
}
|
||||
},
|
||||
"node_modules/path-to-regexp": {
|
||||
"version": "0.1.10",
|
||||
"resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.10.tgz",
|
||||
"integrity": "sha512-7lf7qcQidTku0Gu3YDPc8DJ1q7OOucfa/BSsIwjuh56VU7katFvuM8hULfkwB3Fns/rsVF7PwPKVw1sl5KQS9w==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/peberminta": {
|
||||
"version": "0.9.0",
|
||||
"resolved": "https://registry.npmjs.org/peberminta/-/peberminta-0.9.0.tgz",
|
||||
|
@ -3854,9 +3441,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/postcss": {
|
||||
"version": "8.4.48",
|
||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.48.tgz",
|
||||
"integrity": "sha512-GCRK8F6+Dl7xYniR5a4FYbpBzU8XnZVeowqsQFYdcXuSbChgiks7qybSkbvnaeqv0G0B+dd9/jJgH8kkLDQeEA==",
|
||||
"version": "8.4.49",
|
||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.49.tgz",
|
||||
"integrity": "sha512-OCVPnIObs4N29kxTjzLfUryOkvZEq+pf8jTF0lg8E7uETuWHA+v7j3c/xJmiqpX450191LlmZfUKkXxkTry7nA==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
|
@ -4543,20 +4130,6 @@
|
|||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/proxy-addr": {
|
||||
"version": "2.0.7",
|
||||
"resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz",
|
||||
"integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"forwarded": "0.2.0",
|
||||
"ipaddr.js": "1.9.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.10"
|
||||
}
|
||||
},
|
||||
"node_modules/prr": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz",
|
||||
|
@ -4574,22 +4147,6 @@
|
|||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/qs": {
|
||||
"version": "6.13.0",
|
||||
"resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz",
|
||||
"integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==",
|
||||
"dev": true,
|
||||
"license": "BSD-3-Clause",
|
||||
"dependencies": {
|
||||
"side-channel": "^1.0.6"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=0.6"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/queue-microtask": {
|
||||
"version": "1.2.3",
|
||||
"resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
|
||||
|
@ -4621,22 +4178,6 @@
|
|||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/raw-body": {
|
||||
"version": "2.5.2",
|
||||
"resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz",
|
||||
"integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"bytes": "3.1.2",
|
||||
"http-errors": "2.0.0",
|
||||
"iconv-lite": "0.4.24",
|
||||
"unpipe": "1.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/read-cache": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz",
|
||||
|
@ -4670,13 +4211,6 @@
|
|||
"node": ">= 0.10"
|
||||
}
|
||||
},
|
||||
"node_modules/requires-port": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz",
|
||||
"integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/resolve": {
|
||||
"version": "1.22.8",
|
||||
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz",
|
||||
|
@ -4757,34 +4291,6 @@
|
|||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/safe-buffer": {
|
||||
"version": "5.2.1",
|
||||
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
|
||||
"integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
|
||||
"dev": true,
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/feross"
|
||||
},
|
||||
{
|
||||
"type": "patreon",
|
||||
"url": "https://www.patreon.com/feross"
|
||||
},
|
||||
{
|
||||
"type": "consulting",
|
||||
"url": "https://feross.org/support"
|
||||
}
|
||||
],
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/safer-buffer": {
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
|
||||
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/section-matter": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/section-matter/-/section-matter-1.0.0.tgz",
|
||||
|
@ -4887,87 +4393,6 @@
|
|||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/serve-static": {
|
||||
"version": "1.16.2",
|
||||
"resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.2.tgz",
|
||||
"integrity": "sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"encodeurl": "~2.0.0",
|
||||
"escape-html": "~1.0.3",
|
||||
"parseurl": "~1.3.3",
|
||||
"send": "0.19.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.8.0"
|
||||
}
|
||||
},
|
||||
"node_modules/serve-static/node_modules/debug": {
|
||||
"version": "2.6.9",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
|
||||
"integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"ms": "2.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/serve-static/node_modules/debug/node_modules/ms": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
|
||||
"integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/serve-static/node_modules/mime": {
|
||||
"version": "1.6.0",
|
||||
"resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz",
|
||||
"integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"bin": {
|
||||
"mime": "cli.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/serve-static/node_modules/send": {
|
||||
"version": "0.19.0",
|
||||
"resolved": "https://registry.npmjs.org/send/-/send-0.19.0.tgz",
|
||||
"integrity": "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"debug": "2.6.9",
|
||||
"depd": "2.0.0",
|
||||
"destroy": "1.2.0",
|
||||
"encodeurl": "~1.0.2",
|
||||
"escape-html": "~1.0.3",
|
||||
"etag": "~1.8.1",
|
||||
"fresh": "0.5.2",
|
||||
"http-errors": "2.0.0",
|
||||
"mime": "1.6.0",
|
||||
"ms": "2.1.3",
|
||||
"on-finished": "2.4.1",
|
||||
"range-parser": "~1.2.1",
|
||||
"statuses": "2.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.8.0"
|
||||
}
|
||||
},
|
||||
"node_modules/serve-static/node_modules/send/node_modules/encodeurl": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
|
||||
"integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/set-function-length": {
|
||||
"version": "1.2.2",
|
||||
"resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz",
|
||||
|
@ -5016,25 +4441,6 @@
|
|||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/side-channel": {
|
||||
"version": "1.0.6",
|
||||
"resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz",
|
||||
"integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"call-bind": "^1.0.7",
|
||||
"es-errors": "^1.3.0",
|
||||
"get-intrinsic": "^1.2.4",
|
||||
"object-inspect": "^1.13.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/signal-exit": {
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz",
|
||||
|
@ -5415,20 +4821,6 @@
|
|||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/type-is": {
|
||||
"version": "1.6.18",
|
||||
"resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz",
|
||||
"integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"media-typer": "0.3.0",
|
||||
"mime-types": "~2.1.24"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/uc.micro": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-2.1.0.tgz",
|
||||
|
@ -5505,26 +4897,6 @@
|
|||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/utils-merge": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz",
|
||||
"integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/vary": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
|
||||
"integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/webidl-conversions": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
|
||||
|
|
13
package.json
13
package.json
|
@ -1,15 +1,14 @@
|
|||
{
|
||||
"name": "coryd.dev",
|
||||
"version": "2.9.0",
|
||||
"version": "3.0.0",
|
||||
"description": "The source for my personal site. Built using 11ty (and other tools).",
|
||||
"type": "module",
|
||||
"engines": {
|
||||
"node": "22.x"
|
||||
},
|
||||
"scripts": {
|
||||
"start": "node server.js",
|
||||
"start:eleventy": "eleventy --serve",
|
||||
"start:eleventy:quick": "eleventy --serve --incremental --ignore-initial",
|
||||
"start": "eleventy --serve",
|
||||
"start:quick": "eleventy --serve --incremental --ignore-initial",
|
||||
"build": "ELEVENTY_PRODUCTION=true eleventy",
|
||||
"debug": "DEBUG=Eleventy* npx @11ty/eleventy --serve",
|
||||
"update:deps": "npm upgrade && ncu",
|
||||
|
@ -36,16 +35,14 @@
|
|||
"devDependencies": {
|
||||
"@11ty/eleventy": "v3.0.0",
|
||||
"@11ty/eleventy-plugin-syntaxhighlight": "^5.0.0",
|
||||
"@cdransf/eleventy-plugin-tabler-icons": "^2.1.1",
|
||||
"@cdransf/eleventy-plugin-tabler-icons": "^2.2.0",
|
||||
"@supabase/supabase-js": "^2.46.1",
|
||||
"autoprefixer": "^10.4.20",
|
||||
"cssnano": "^7.0.6",
|
||||
"dotenv-flow": "^4.1.0",
|
||||
"express": "4.21.1",
|
||||
"fast-xml-parser": "^4.5.0",
|
||||
"html-minifier-terser": "^7.2.0",
|
||||
"html-to-text": "^9.0.5",
|
||||
"http-proxy-middleware": "3.0.3",
|
||||
"i18n-iso-countries": "7.13.0",
|
||||
"ics": "^3.8.1",
|
||||
"linkedom": "0.18.5",
|
||||
|
@ -54,7 +51,7 @@
|
|||
"markdown-it-anchor": "^9.2.0",
|
||||
"markdown-it-footnote": "^4.0.0",
|
||||
"markdown-it-prism": "^2.3.0",
|
||||
"postcss": "^8.4.48",
|
||||
"postcss": "^8.4.49",
|
||||
"postcss-import": "^16.1.0",
|
||||
"postcss-import-ext-glob": "^2.1.1",
|
||||
"rimraf": "^6.0.1",
|
||||
|
|
133
server.js
133
server.js
|
@ -1,133 +0,0 @@
|
|||
import express from "express";
|
||||
import { createProxyMiddleware } from "http-proxy-middleware";
|
||||
import path from "path";
|
||||
import { fileURLToPath } from "url";
|
||||
import { spawn } from "child_process";
|
||||
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = path.dirname(__filename);
|
||||
const PORT = 8080;
|
||||
const ELEVENTY_PORT = 8081;
|
||||
const WORKER_PORT = 8787;
|
||||
const WORKER_ENTRY = "./workers/dynamic-pages/index.js";
|
||||
|
||||
const startProcess = (command, args, name) => {
|
||||
console.log(`Starting ${name}...`);
|
||||
const process = spawn(command, args, { stdio: "inherit" });
|
||||
|
||||
process.on("error", (err) => {
|
||||
console.error(`${name} error: ${err.message}`);
|
||||
process.exit(1);
|
||||
});
|
||||
|
||||
process.on("exit", (code) => {
|
||||
console.log(`${name} exited with code ${code}`);
|
||||
if (code !== 0) process.exit(code);
|
||||
});
|
||||
|
||||
return process;
|
||||
};
|
||||
|
||||
const startEleventy = () =>
|
||||
startProcess(
|
||||
"npx",
|
||||
["eleventy", "--serve", "--port", ELEVENTY_PORT],
|
||||
"Eleventy"
|
||||
);
|
||||
const startWorker = () =>
|
||||
startProcess(
|
||||
"npx",
|
||||
["wrangler", "dev", WORKER_ENTRY, "--port", WORKER_PORT],
|
||||
"Wrangler Worker"
|
||||
);
|
||||
|
||||
const app = express();
|
||||
|
||||
const setContentType = (req, res) => {
|
||||
const contentTypeMap = {
|
||||
".css": "text/css",
|
||||
".js": "application/javascript",
|
||||
".json": "application/json",
|
||||
"/api/": "application/json",
|
||||
"/feeds/all": "application/xml",
|
||||
"/feeds/books": "application/xml",
|
||||
"/feeds/links": "application/xml",
|
||||
"/feeds/movies": "application/xml",
|
||||
"/feeds/posts": "application/xml",
|
||||
"/feeds/syndication": "application/xml",
|
||||
};
|
||||
|
||||
for (const [key, value] of Object.entries(contentTypeMap)) {
|
||||
if (req.path.endsWith(key) || req.path.startsWith(key)) {
|
||||
res.setHeader("Content-Type", value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
app.use((req, res, next) => {
|
||||
setContentType(req, res);
|
||||
next();
|
||||
});
|
||||
|
||||
app.use(
|
||||
express.static(path.join(__dirname, "dist"), { extensions: ["html"] })
|
||||
);
|
||||
|
||||
const proxy = createProxyMiddleware({
|
||||
target: `http://localhost:${WORKER_PORT}`,
|
||||
changeOrigin: true,
|
||||
ws: true,
|
||||
pathRewrite: (path, req) => req.originalUrl,
|
||||
onError: (err, req, res) => {
|
||||
console.error(`Proxy error: ${err.message}`);
|
||||
res.status(504).send("Worker timeout or unreachable");
|
||||
},
|
||||
});
|
||||
|
||||
app.use(
|
||||
[
|
||||
"/watching/movies",
|
||||
"/watching/shows",
|
||||
"/music/artists",
|
||||
"/music/genres",
|
||||
"/books",
|
||||
],
|
||||
proxy
|
||||
);
|
||||
|
||||
app.use((req, res) => {
|
||||
res.status(404).sendFile(path.join(__dirname, "dist", "404.html"), (err) => {
|
||||
if (err) res.status(404).send("Page not found");
|
||||
});
|
||||
});
|
||||
|
||||
const startServer = () => {
|
||||
const server = app.listen(PORT, () => {
|
||||
console.log(`Server running at http://localhost:${PORT}`);
|
||||
});
|
||||
|
||||
const shutdown = () => {
|
||||
console.log("Shutting down...");
|
||||
server.close(() => {
|
||||
console.log("Express server closed");
|
||||
process.exit(0);
|
||||
});
|
||||
};
|
||||
|
||||
process.on("SIGINT", shutdown);
|
||||
process.on("SIGTERM", shutdown);
|
||||
};
|
||||
|
||||
const initialize = async () => {
|
||||
try {
|
||||
startEleventy();
|
||||
startWorker();
|
||||
startServer();
|
||||
} catch (err) {
|
||||
console.error(`Initialization error: ${err.message}`);
|
||||
process.exit(1);
|
||||
}
|
||||
};
|
||||
|
||||
initialize();
|
|
@ -427,7 +427,7 @@ td:first-of-type,
|
|||
.default-wrapper {
|
||||
padding-top: var(--spacing-2xl);
|
||||
|
||||
& h2:first-of-type {
|
||||
h2.page-title {
|
||||
margin-top: 0;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -32,7 +32,7 @@ const fetchAlbumReleases = async () => {
|
|||
})
|
||||
.sort((a, b) => a["timestamp"] - b["timestamp"]);
|
||||
|
||||
const upcoming = all.filter((album) => album["release_timestamp"] > today);
|
||||
const upcoming = all.filter((album) => album["release_timestamp"] > today && album['total_plays'] === 0);
|
||||
|
||||
return { all, upcoming };
|
||||
};
|
||||
|
|
|
@ -3,7 +3,7 @@ title: Blogroll
|
|||
permalink: /blogroll.html
|
||||
description: These are awesome blogs that I enjoy and you may enjoy too.
|
||||
---
|
||||
<h2>{{ title }}</h2>
|
||||
<h2 class="page-title">{{ title }}</h2>
|
||||
<p>You can <a href="/blogroll.opml" class="plausible-event-name=Blogroll+OPML+download">download an OPML file</a> containing all of these feeds and import them into your RSS reader.</p>
|
||||
<table>
|
||||
<tr>
|
||||
|
|
70
src/pages/books/book.html
Normal file
70
src/pages/books/book.html
Normal file
|
@ -0,0 +1,70 @@
|
|||
---
|
||||
pagination:
|
||||
data: books.all
|
||||
size: 1
|
||||
alias: book
|
||||
permalink: "{{ book.url }}/index.html"
|
||||
schema: book
|
||||
---
|
||||
{%- capture alt -%}
|
||||
{{ book.title }}{% if book.author %} by {{ book.author }}{% endif %}
|
||||
{%- endcapture -%}
|
||||
<a class="back-link" href="/books" title="Go back to the books index page">{% tablericon "arrow-left" %} Back to books</a>
|
||||
<article class="book-focus">
|
||||
<div class="book-display">
|
||||
<img
|
||||
srcset="
|
||||
{{ globals.cdn_url }}{{ book.image }}?class=verticalsm&type=webp 200w,
|
||||
{{ globals.cdn_url }}{{ book.image }}?class=verticalmd&type=webp 400w,
|
||||
{{ globals.cdn_url }}{{ book.image }}?class=verticalbase&type=webp 800w
|
||||
"
|
||||
sizes="(max-width: 450px) 203px,
|
||||
(max-width: 850px) 406px,
|
||||
(max-width: 1000px) 812px,
|
||||
812px"
|
||||
src="{{ globals.cdn_url }}{{ book.image }}?class=verticalsm&type=webp"
|
||||
alt="{{ alt | replaceQuotes }}"
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
width="200"
|
||||
height="307"
|
||||
/>
|
||||
<div class="media-meta">
|
||||
<span class="title"><strong>{{ book.title }}</strong></span>
|
||||
{% if book.rating %}<span>{{ book.rating }}</span>{% endif %}
|
||||
{% if book.author %}
|
||||
<span class="sub-meta">By {{ book.author }}</span>
|
||||
{% endif %}
|
||||
{%- if book.favorite -%}
|
||||
<span class="sub-meta favorite">{% tablericon "heart" %} This is one of my favorite books!</span>
|
||||
{%- endif -%}
|
||||
{%- if book.tattoo -%}
|
||||
<span class="sub-meta tattoo">{% tablericon "needle" %} I have a tattoo inspired by this book!</span>
|
||||
{%- endif -%}
|
||||
{% if book.status == 'finished' %}
|
||||
<span class="sub-meta">Finished on: <strong class="highlight-text">{{ book.date_finished | date: "%B %e, %Y" }}</strong></span>
|
||||
{% endif %}
|
||||
{% if book.status == 'started' %}
|
||||
{%- assign percentage = book.progress | append: '%' -%}
|
||||
{% render "media/progress-bar.liquid", percentage:percentage %}
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{% if book.review %}
|
||||
{% render "blocks/banners/warning.liquid", text: "There are probably spoilers after this banner — this is a warning about them." %}
|
||||
<h2>My thoughts</h2>
|
||||
{{ book.review | markdown }}
|
||||
{% endif %}
|
||||
{% render "blocks/associated-media.liquid",
|
||||
artists: book.artists,
|
||||
books: book.related_books,
|
||||
genres: book.genres,
|
||||
movies: book.movies,
|
||||
posts: book.posts,
|
||||
shows: book.shows
|
||||
%}
|
||||
{% if book.description %}
|
||||
<h2>Overview</h2>
|
||||
{{ book.description | markdown }}
|
||||
{% endif %}
|
||||
</article>
|
|
@ -8,7 +8,7 @@ schema: books
|
|||
{%- assign currentYear = 'now' | date: "%Y" -%}
|
||||
{%- assign bookData = books.all | filterBooksByStatus: 'started' | reverse -%}
|
||||
{%- assign currentBookCount = books.currentYear | size -%}
|
||||
<h2>Currently reading</h2>
|
||||
<h2 class="page-title">Currently reading</h2>
|
||||
<p>Here's what I'm reading at the moment. I've finished <strong class="highlight-text">{{ currentBookCount }} books</strong> this year.</p>
|
||||
<p>{{ books.years | bookYearLinks }}</p>
|
||||
{% render "blocks/banners/rss.liquid", url: "/feeds/books", text: "Subscribe to my books feed or follow along on this page" %}
|
||||
|
|
|
@ -13,7 +13,7 @@ schema: books-year
|
|||
{%- assign yearString = year.value | append: '' -%}
|
||||
{%- assign currentYearString = currentYear | append: '' -%}
|
||||
<a href="/books" class="back-link">{% tablericon "arrow-left" %} Back to books</a>
|
||||
<h2>{{ year.value }} / Books</h2>
|
||||
<h2 class="page-title">{{ year.value }} / Books</h2>
|
||||
{% if yearString == currentYearString %}
|
||||
<p>I've finished <strong class="highlight-text">{{ bookData.size }} books</strong> this year.{%- if favoriteBooks %} Among my favorites are {{ favoriteBooks }}.{%- endif -%}</p>
|
||||
{% else %}
|
||||
|
|
|
@ -7,7 +7,7 @@ pagination:
|
|||
permalink: "/links/{% if pagination.pageNumber > 0 %}{{ pagination.pageNumber }}/{% endif %}index.html"
|
||||
---
|
||||
{% if pagination.pageNumber == 0 %}
|
||||
<h2>Links</h2>
|
||||
<h2 class="page-title">Links</h2>
|
||||
<p>These are links I've liked or otherwise found interesting. They're all added manually, after having been read and, I suppose, properly considered.</p>
|
||||
{% render "blocks/banners/rss.liquid", url: "/feeds/links", text: "Subscribe to my links feed or follow along on this page" %}
|
||||
<hr />
|
||||
|
|
114
src/pages/music/artist.html
Normal file
114
src/pages/music/artist.html
Normal file
|
@ -0,0 +1,114 @@
|
|||
---
|
||||
pagination:
|
||||
data: artists
|
||||
size: 1
|
||||
alias: artist
|
||||
permalink: "{{ artist.url }}/index.html"
|
||||
updated: "now"
|
||||
schema: artist
|
||||
---
|
||||
{%- capture alt -%}
|
||||
{{ artist.name }} / {{ artist.country }}
|
||||
{%- endcapture -%}
|
||||
{%- capture playLabel -%}
|
||||
{%- if artist.total_plays == 1 -%}
|
||||
play
|
||||
{%- else -%}
|
||||
plays
|
||||
{%- endif -%}
|
||||
{%- endcapture -%}
|
||||
<noscript><style>[data-toggle-content].text-toggle-hidden {height: unset !important;overflow: unset !important;margin-bottom: unset !important;}[data-toggle-content].text-toggle-hidden::after {display: none !important;}</style></noscript>
|
||||
<a class="back-link" href="/music" title="Go back to the music index page">{% tablericon "arrow-left" %} Back to music</a>
|
||||
<article class="artist-focus">
|
||||
<div class="artist-display">
|
||||
<img
|
||||
srcset="
|
||||
{{ globals.cdn_url }}{{ artist.image }}?class=w200&type=webp 200w,
|
||||
{{ globals.cdn_url }}{{ artist.image }}?class=w600&type=webp 400w,
|
||||
{{ globals.cdn_url }}{{ artist.image }}?class=w800&type=webp 800w
|
||||
"
|
||||
sizes="(max-width: 450px) 200px,
|
||||
(max-width: 850px) 400px,
|
||||
800px"
|
||||
src="{{ globals.cdn_url }}{{ artist.image }}?class=w200&type=webp"
|
||||
alt="{{ alt | replaceQuotes }}"
|
||||
loading="eager"
|
||||
decoding="async"
|
||||
width="200"
|
||||
height="200"
|
||||
/>
|
||||
<div class="media-meta">
|
||||
<span class="title"><strong>{{ artist.name }}</strong></span>
|
||||
<span class="sub-meta country">{% tablericon "map-pin" %} {{ artist.country }}</span>
|
||||
{%- if artist.favorite -%}
|
||||
<span class="sub-meta favorite">{% tablericon "heart" %} This is one of my favorite artists!</span>
|
||||
{%- endif -%}
|
||||
{%- if artist.tattoo -%}
|
||||
<span class="sub-meta tattoo">{% tablericon "needle" %} I have a tattoo inspired by this artist!</span>
|
||||
{%- endif -%}
|
||||
{%- if artist.total_plays > 0 -%}
|
||||
<span class="sub-meta"><strong class="highlight-text">{{ artist.total_plays }} {{ playLabel }}</strong></span>
|
||||
{%- endif -%}
|
||||
<span class="sub-meta">
|
||||
<a href="{{ artist.genre.url }}" title="Learn more about {{ artist.genre.name | escape }}">
|
||||
{{ artist.genre.name }}
|
||||
</a>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
{% render "blocks/associated-media.liquid",
|
||||
artists: artist.related_artists,
|
||||
books: artist.books,
|
||||
genres: artist.genres,
|
||||
movies: artist.movies,
|
||||
posts: artist.posts,
|
||||
shows: artist.shows
|
||||
%}
|
||||
{%- if artist.description -%}
|
||||
<h2>Overview</h2>
|
||||
<div data-toggle-content class="text-toggle-hidden">{{ artist.description | markdown }}</div>
|
||||
<button data-toggle-button>Show more</button>
|
||||
{%- endif -%}
|
||||
{%- if artist.concerts -%}
|
||||
<p id="concerts" class="concerts">
|
||||
{% tablericon "device-speaker" %}
|
||||
I've seen this artist live!
|
||||
</p>
|
||||
<ul>
|
||||
{% for concert in artist.concerts %}
|
||||
{%- capture venue -%}
|
||||
{% if concert.venue_name %}
|
||||
{% if concert.venue_latitude and concert.venue_longitude %}
|
||||
<a href="https://www.openstreetmap.org/?mlat={{ concert.venue_latitude }}&mlon={{ concert.venue_longitude }}#map=18/{{ concert.venue_latitude }}/{{ concert.venue_longitude }}">{{ concert.venue_name_short }}</a>
|
||||
{% else %}
|
||||
{{ concert.venue_name_short }}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{%- endcapture -%}
|
||||
<li>
|
||||
On <strong class="highlight-text">{{ concert.date | date: "%B %e, %Y" }}</strong>
|
||||
{% if venue %} at {{ venue }}{% endif %}
|
||||
{%- if concert.notes -%}
|
||||
{% assign notes = concert.notes | prepend: "### Notes\n" | markdown %}
|
||||
{% render "blocks/modal.liquid", label:"Concert info", icon:"info-circle", content:notes, id:concert.id %}
|
||||
{%- endif -%}
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
{%- endif -%}
|
||||
<table>
|
||||
<tr>
|
||||
<th>Album</th>
|
||||
<th>Plays</th>
|
||||
<th>Year</th>
|
||||
</tr>
|
||||
{% for album in artist.albums %}
|
||||
<tr>
|
||||
<td>{{ album.name }}</td>
|
||||
<td>{{ album.total_plays }}</td>
|
||||
<td>{{ album.release_year }}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
<p><em>These are the albums by this artist that are in my collection, not necessarily a comprehensive discography.</em></p>
|
||||
</article>
|
|
@ -7,7 +7,7 @@ pagination:
|
|||
permalink: "/music/concerts/{% if pagination.pageNumber > 0 %}{{ pagination.pageNumber }}/{% endif %}index.html"
|
||||
---
|
||||
{%- if pagination.pageNumber == 0 -%}
|
||||
<h2>Concerts</h2>
|
||||
<h2 class="page-title">Concerts</h2>
|
||||
<p>These are concerts I've attended (not all of them — just the ones I could remember or glean from emails, photo metadata et al). I've been to at least <strong class="highlight-text">{{ concerts | size }}</strong> shows. <a href="/music">You can also take a look at the music I've been listening to lately</a>.</p>
|
||||
<hr />
|
||||
{%- endif -%}
|
||||
|
|
41
src/pages/music/genre.html
Normal file
41
src/pages/music/genre.html
Normal file
|
@ -0,0 +1,41 @@
|
|||
---
|
||||
pagination:
|
||||
data: genres
|
||||
size: 1
|
||||
alias: genre
|
||||
permalink: "{{ genre.url }}/index.html"
|
||||
updated: "now"
|
||||
schema: genre
|
||||
---
|
||||
{% assign artistCount = genre.artists.size %}
|
||||
{%- capture connectingWords -%}
|
||||
{% if artistCount > 1 %}
|
||||
artists are
|
||||
{% else %}
|
||||
artist is
|
||||
{% endif %}
|
||||
{%- endcapture -%}
|
||||
{%- assign mediaLinks = genre.artists | mediaLinks: "artist", 5 -%}
|
||||
<noscript><style>[data-toggle-content].text-toggle-hidden {height: unset !important;overflow: unset !important;margin-bottom: unset !important;}[data-toggle-content].text-toggle-hidden::after {display: none !important;}</style></noscript>
|
||||
<a class="back-link" href="/music" title="Go back to the music index page">{% tablericon "arrow-left" %} Back to music</a>
|
||||
<h2>{{ genre.name }}</h2>
|
||||
<article class="genre-focus">
|
||||
{%- if mediaLinks -%}
|
||||
<p>My top <strong class="highlight-text">{{ genre.name }}</strong> {{ connectingWords }} {{ mediaLinks }}. I've listened to <strong class="highlight-text">{{ genre.total_plays }}</strong> tracks form this genre.</p>
|
||||
<hr />
|
||||
{%- endif -%}
|
||||
{% render "blocks/associated-media.liquid",
|
||||
books: genre.books,
|
||||
movies: genre.movies,
|
||||
posts: genre.posts,
|
||||
%}
|
||||
{%- if genre.description -%}
|
||||
<h3>Overview</h3>
|
||||
<div data-toggle-content class="text-toggle-hidden">
|
||||
{{ genre.description | markdown }}
|
||||
<p><a href="{{ genre.wiki_link }}">Continue reading at Wikipedia.</a></p>
|
||||
<p><em>Wikipedia content provided under the terms of the <a href="https://creativecommons.org/licenses/by-sa/3.0/">Creative Commons BY-SA license</a></em></p>
|
||||
</div>
|
||||
<button data-toggle-button>Show more</button>
|
||||
{%- endif -%}
|
||||
</article>
|
|
@ -5,7 +5,7 @@ permalink: "/music.html"
|
|||
updated: "now"
|
||||
schema: music-index
|
||||
---
|
||||
<h2>{{ title }}</h2>
|
||||
<h2 class="page-title">{{ title }}</h2>
|
||||
<p>I've listened to <strong class="highlight-text">{{ music.week.artists.size }} artists</strong>, <strong class="highlight-text">{{ music.week.albums.size }} albums</strong> and <strong class="highlight-text">{{ music.week.totalTracks }} tracks</strong> this week. Most of that has been {{ music.week.genres | mediaLinks: "genre", 5 }}.</p>
|
||||
<p><strong class="highlight-text">Take a look at what I've listened to</strong> <a href="/music/this-month">this month</a> or <a href="/music/concerts">check out the concerts I've been to.</a></p>
|
||||
<p class="music">{% render "blocks/now-playing.liquid", nowPlaying:nowPlaying.content %}</p>
|
||||
|
|
|
@ -6,7 +6,7 @@ updated: "now"
|
|||
image: music.month.artists[0].image
|
||||
schema: music-period
|
||||
---
|
||||
<h2>{{ title }}</h2>
|
||||
<h2 class="page-title">{{ title }}</h2>
|
||||
<p>I've listened to <strong class="highlight-text">{{ music.month.artists.size }} artists</strong>, <strong class="highlight-text">{{ music.month.albums.size }} albums</strong> and <strong class="highlight-text">{{ music.month.totalTracks }} tracks</strong> this month. Most of that has been {{ music.month.genres | mediaLinks: "genre", 5 }}.</p>
|
||||
<p><strong class="highlight-text">Take a look at what I've listened to</strong> <a href="/music">this week</a> or <a href="/music/concerts">check out the concerts I've been to.</a></p>
|
||||
<hr />
|
||||
|
|
|
@ -9,7 +9,7 @@ schema: favorite-movies
|
|||
---
|
||||
<a href="/watching" class="back-link">{% tablericon "arrow-left" %} Back to watching</a>
|
||||
{% if pagination.pageNumber == 0 %}
|
||||
<h2 class="watching">{{ title }}</h2>
|
||||
<h2 class="page-title">{{ title }}</h2>
|
||||
<p>These are my favorite movies. There are many like them, but these are mine.</p>
|
||||
<hr />
|
||||
{% endif %}
|
||||
|
|
|
@ -9,7 +9,7 @@ schema: favorite-shows
|
|||
---
|
||||
<a href="/watching" class="back-link">{% tablericon "arrow-left" %} Back to watching</a>
|
||||
{% if pagination.pageNumber == 0 %}
|
||||
<h2 class="watching">{{ title }}</h2>
|
||||
<h2 class="page-title">{{ title }}</h2>
|
||||
<p>These are my favorite shows. There are many like them, but these are mine.</p>
|
||||
<hr />
|
||||
{% endif %}
|
||||
|
|
|
@ -6,7 +6,7 @@ updated: "now"
|
|||
schema: watching
|
||||
---
|
||||
{%- assign featuredMovie = movies.recentlyWatched | shuffleArray | first -%}
|
||||
<h2 class="watching">{{ title }}</h2>
|
||||
<h2 class="page-title">{{ title }}</h2>
|
||||
{% render "media/watching/hero.liquid", globals:globals, movie:featuredMovie %}
|
||||
<p>Here's all of the TV and movies I've been watching presented in what is (hopefully) an organized fashion.</p>
|
||||
{% render "blocks/banners/rss.liquid", url: "/feeds/movies", text: "Subscribe to my movies feed or follow along on this page" %}
|
||||
|
|
69
src/pages/watching/movie.html
Normal file
69
src/pages/watching/movie.html
Normal file
|
@ -0,0 +1,69 @@
|
|||
---
|
||||
pagination:
|
||||
data: movies.movies
|
||||
size: 1
|
||||
alias: movie
|
||||
permalink: "{{ movie.url }}/index.html"
|
||||
schema: movie
|
||||
---
|
||||
{%- capture alt -%}
|
||||
{{ movie.title }} / {{ movie.year }}{% if move.rating %} ({{ movie.rating }}){% endif %}
|
||||
{%- endcapture -%}
|
||||
<a class="back-link" href="/watching" title="Go back to the watching index page">{% tablericon "arrow-left" %} Back to watching</a>
|
||||
<article class="watching focus">
|
||||
<img
|
||||
srcset="
|
||||
{{ globals.cdn_url }}{{ movie.backdrop }}?class=bannersm&type=webp 256w,
|
||||
{{ globals.cdn_url }}{{ movie.backdrop }}?class=bannermd&type=webp 512w,
|
||||
{{ globals.cdn_url }}{{ movie.backdrop }}?class=bannerbase&type=webp 1024w
|
||||
"
|
||||
sizes="(max-width: 450px) 256px,
|
||||
(max-width: 850px) 512px,
|
||||
1024px"
|
||||
src="{{ globals.cdn_url }}{{ movie.backdrop }}?class=bannersm&type=webp"
|
||||
alt="{{ alt | replaceQuotes }}"
|
||||
class="image-banner"
|
||||
loading="eager"
|
||||
decoding="async"
|
||||
width="256"
|
||||
height="180"
|
||||
/>
|
||||
<div class="media-meta">
|
||||
<span class="title"><strong>{{ movie.title }}</strong>{%- if movie.year and not movie.rating %} ({{ movie.year }}){%- endif -%}</span>
|
||||
{%- if movie.rating -%}
|
||||
<span>
|
||||
{{ movie.rating }}
|
||||
{%- if movie.year %}
|
||||
({{ movie.year }})
|
||||
{%- endif -%}
|
||||
</span>
|
||||
{% endif -%}
|
||||
{%- if movie.favorite -%}
|
||||
<span class="sub-meta favorite">{% tablericon "heart" %} This is one of my favorite movies!</span>
|
||||
{%- endif -%}
|
||||
{%- if movie.tattoo -%}
|
||||
<span class="sub-meta tattoo">{% tablericon "needle" %} I have a tattoo inspired by this movie!</span>
|
||||
{%- endif -%}
|
||||
{%- if movie.collected -%}
|
||||
<span class="sub-meta collected">{% tablericon "circle-check" %} This movie is in my collection!</span>
|
||||
{%- endif -%}
|
||||
{%- if movie.lastWatched -%}<span class="sub-meta">Last watched on {{ movie.lastWatched | date: "%B %e, %Y" }}.</span>{%- endif -%}
|
||||
</div>
|
||||
{% if movie.review %}
|
||||
{% render "blocks/banners/warning.liquid", text: "There are probably spoilers after this banner — this is a warning about them." %}
|
||||
<h2>My thoughts</h2>
|
||||
{{ movie.review | markdown }}
|
||||
{% endif %}
|
||||
{% render "blocks/associated-media.liquid",
|
||||
artists: movie.artists,
|
||||
books: movie.books,
|
||||
genres: movie.genres,
|
||||
movies: movie.related_movies,
|
||||
posts: movie.posts,
|
||||
shows: movie.shows
|
||||
%}
|
||||
{% if movie.description %}
|
||||
<h2>Overview</h2>
|
||||
{{ movie.description | markdown }}
|
||||
{% endif %}
|
||||
</article>
|
66
src/pages/watching/show.html
Normal file
66
src/pages/watching/show.html
Normal file
|
@ -0,0 +1,66 @@
|
|||
---
|
||||
pagination:
|
||||
data: tv.shows
|
||||
size: 1
|
||||
alias: show
|
||||
permalink: "{{ show.url }}/index.html"
|
||||
schema: show
|
||||
---
|
||||
{%- capture alt -%}
|
||||
{{ show.title }} / {{ show.year }}
|
||||
{%- endcapture -%}
|
||||
<a class="back-link" href="/watching" title="Go back to the watching index page">{% tablericon "arrow-left" %} Back to watching</a>
|
||||
<article class="watching focus">
|
||||
<img
|
||||
srcset="
|
||||
{{ globals.cdn_url }}{{ show.backdrop }}?class=bannersm&type=webp 256w,
|
||||
{{ globals.cdn_url }}{{ show.backdrop }}?class=bannermd&type=webp 512w,
|
||||
{{ globals.cdn_url }}{{ show.backdrop }}?class=bannerbase&type=webp 1024w
|
||||
"
|
||||
sizes="(max-width: 450px) 256px,
|
||||
(max-width: 850px) 512px,
|
||||
1024px"
|
||||
src="{{ globals.cdn_url }}{{ show.backdrop }}?class=bannersm&type=webp"
|
||||
alt="{{ alt | replaceQuotes }}"
|
||||
class="image-banner"
|
||||
loading="eager"
|
||||
decoding="async"
|
||||
width="256"
|
||||
height="180"
|
||||
/>
|
||||
<div class="media-meta">
|
||||
<span class="title"><strong>{{ show.title }}</strong>{%- if show.year %} ({{ show.year }}){%- endif -%}</span>
|
||||
{%- if show.favorite -%}
|
||||
<span class="sub-meta favorite">{% tablericon "heart" %} This is one of my favorite shows!</span>
|
||||
{%- endif -%}
|
||||
{%- if show.tattoo -%}
|
||||
<span class="sub-meta tattoo">{% tablericon "needle" %} I have a tattoo inspired by this show!</span>
|
||||
{%- endif -%}
|
||||
{%- if show.collected -%}
|
||||
<span class="sub-meta collected">{% tablericon "circle-check" %} This show is in my collection!</span>
|
||||
{%- endif -%}
|
||||
{%- if show.episode.formatted_episode -%}
|
||||
{%- capture lastWatchedText -%}
|
||||
I last watched <strong class="highlight-text">{{ show.episode.formatted_episode }}</strong> on {{ show.episode.last_watched_at | date: "%B %e, %Y" }}.
|
||||
{%- endcapture -%}
|
||||
<span class="sub-meta">{{ lastWatchedText }}</span>
|
||||
{%- endif -%}
|
||||
</div>
|
||||
{% if show.review %}
|
||||
{% render "blocks/banners/warning.liquid", text: "There are probably spoilers after this banner — this is a warning about them." %}
|
||||
<h2>My thoughts</h2>
|
||||
{{ show.review | markdown }}
|
||||
{% endif %}
|
||||
{% render "blocks/associated-media.liquid",
|
||||
artists: show.artists,
|
||||
books: show.books,
|
||||
genres: show.genres,
|
||||
movies: show.movies,
|
||||
posts: show.posts,
|
||||
shows: show.related_shows
|
||||
%}
|
||||
{% if show.description %}
|
||||
<h2>Overview</h2>
|
||||
{{ show.description | markdown }}
|
||||
{% endif %}
|
||||
</article>
|
|
@ -17,18 +17,16 @@ function sanitizeMediaString(str) {
|
|||
|
||||
export default {
|
||||
async fetch(request, env) {
|
||||
const directusUrl = env["DIRECTUS_URL"];
|
||||
const directusToken = env["DIRECTUS_API_TOKEN"];
|
||||
const artistImportToken = env["ARTIST_IMPORT_TOKEN"];
|
||||
const artistFlowID = env["ARTIST_FLOW_ID"];
|
||||
const albumFlowID = env["ALBUM_FLOW_ID"];
|
||||
const directusUrl = env.DIRECTUS_URL;
|
||||
const directusToken = env.DIRECTUS_API_TOKEN;
|
||||
const artistImportToken = env.ARTIST_IMPORT_TOKEN;
|
||||
const artistFlowID = env.ARTIST_FLOW_ID;
|
||||
const albumFlowID = env.ALBUM_FLOW_ID;
|
||||
const placeholderImageId = "4cef75db-831f-4f5d-9333-79eaa5bb55ee";
|
||||
const requestUrl = new URL(request["url"]);
|
||||
const providedToken = requestUrl.searchParams.get("token");
|
||||
|
||||
if (!providedToken || providedToken !== artistImportToken) {
|
||||
return new Response("Unauthorized", { status: 401 });
|
||||
}
|
||||
if (!providedToken || providedToken !== artistImportToken) return new Response("Unauthorized", { status: 401 });
|
||||
|
||||
async function saveToDirectus(endpoint, payload) {
|
||||
const response = await fetch(`${directusUrl}/items/${endpoint}`, {
|
||||
|
|
|
@ -36,8 +36,8 @@ export default {
|
|||
return new Response("Invalid input", { status: 400 });
|
||||
|
||||
const emailDomain = email.split("@")[1].toLowerCase();
|
||||
const supabaseUrl = env.SUPABASE_URL || process.env.SUPABASE_URL;
|
||||
const supabaseKey = env.SUPABASE_KEY || process.env.SUPABASE_KEY;
|
||||
const supabaseUrl = env.SUPABASE_URL;
|
||||
const supabaseKey = env.SUPABASE_KEY;
|
||||
const supabase = createClient(supabaseUrl, supabaseKey);
|
||||
const { data: blockedDomains, error: domainError } = await supabase
|
||||
.from("blocked_domains")
|
||||
|
|
|
@ -1,80 +0,0 @@
|
|||
import { createClient } from "@supabase/supabase-js";
|
||||
import { fetchDataByUrl, fetchGlobals } from "./utils/fetchers.js";
|
||||
import { minifyHTML } from "./utils/formatters.js";
|
||||
import {
|
||||
generateArtistHTML,
|
||||
generateBookHTML,
|
||||
generateGenreHTML,
|
||||
generateMetadata,
|
||||
generateWatchingHTML,
|
||||
} from "./utils/generators.js";
|
||||
import { updateDynamicContent } from "./utils/updaters.js";
|
||||
|
||||
const BASE_URL = "https://coryd.dev";
|
||||
const NOT_FOUND_URL = `${BASE_URL}/404`;
|
||||
|
||||
export default {
|
||||
async fetch(request, env) {
|
||||
const url = new URL(request.url);
|
||||
const path = url.pathname.replace(/\/$/, "");
|
||||
const supabaseUrl = env.SUPABASE_URL || process.env.SUPABASE_URL;
|
||||
const supabaseKey = env.SUPABASE_KEY || process.env.SUPABASE_KEY;
|
||||
const supabase = createClient(supabaseUrl, supabaseKey);
|
||||
let data, type;
|
||||
|
||||
if (path === "/books" || path === "/books/")
|
||||
return fetch(`${BASE_URL}/books/`);
|
||||
if (path.startsWith("/books/years/")) return fetch(`${BASE_URL}${path}`);
|
||||
|
||||
if (path.startsWith("/watching/movies/")) {
|
||||
data = await fetchDataByUrl(supabase, "optimized_movies", path);
|
||||
type = "movie";
|
||||
} else if (path.startsWith("/watching/shows/")) {
|
||||
data = await fetchDataByUrl(supabase, "optimized_shows", path);
|
||||
type = "show";
|
||||
} else if (path.startsWith("/music/artists/")) {
|
||||
data = await fetchDataByUrl(supabase, "optimized_artists", path);
|
||||
type = "artist";
|
||||
} else if (path.startsWith("/music/genres/")) {
|
||||
data = await fetchDataByUrl(supabase, "optimized_genres", path);
|
||||
type = "genre";
|
||||
} else if (path.startsWith("/books/")) {
|
||||
data = await fetchDataByUrl(supabase, "optimized_books", path);
|
||||
type = "book";
|
||||
} else {
|
||||
return Response.redirect(NOT_FOUND_URL, 302);
|
||||
}
|
||||
|
||||
if (!data) return Response.redirect(NOT_FOUND_URL, 302);
|
||||
|
||||
const globals = await fetchGlobals(supabase);
|
||||
let mediaHtml;
|
||||
|
||||
switch (type) {
|
||||
case "artist":
|
||||
mediaHtml = generateArtistHTML(data, globals);
|
||||
break;
|
||||
case "genre":
|
||||
mediaHtml = generateGenreHTML(data, globals);
|
||||
break;
|
||||
case "book":
|
||||
mediaHtml = generateBookHTML(data, globals);
|
||||
break;
|
||||
default:
|
||||
mediaHtml = generateWatchingHTML(data, globals, type);
|
||||
break;
|
||||
}
|
||||
|
||||
const templateResponse = await fetch(`${BASE_URL}/dynamic`);
|
||||
const template = await templateResponse.text();
|
||||
const metadata = generateMetadata(data, type, globals);
|
||||
const html = minifyHTML(updateDynamicContent(template, metadata, mediaHtml));
|
||||
const headers = new Headers({
|
||||
"Content-Type": "text/html",
|
||||
"Cache-Control":
|
||||
"public, max-age=3600, s-maxage=3600, stale-while-revalidate=86400",
|
||||
});
|
||||
|
||||
return new Response(html, { headers });
|
||||
},
|
||||
};
|
|
@ -1,14 +0,0 @@
|
|||
const regionNames = new Intl.DisplayNames(["en"], { type: "region" });
|
||||
const getCountryName = (countryCode) =>
|
||||
regionNames.of(countryCode.trim()) || countryCode.trim();
|
||||
|
||||
export const parseCountryField = (countryField) => {
|
||||
if (!countryField) return null;
|
||||
const delimiters = [",", "/", "&", "and"];
|
||||
let countries = [countryField];
|
||||
delimiters.forEach(
|
||||
(delimiter) =>
|
||||
(countries = countries.flatMap((country) => country.split(delimiter)))
|
||||
);
|
||||
return countries.map(getCountryName).join(", ");
|
||||
};
|
|
@ -1,26 +0,0 @@
|
|||
export const fetchDataByUrl = async (supabase, table, url) => {
|
||||
const { data, error } = await supabase
|
||||
.from(table)
|
||||
.select("*")
|
||||
.eq("url", url)
|
||||
.single();
|
||||
|
||||
if (error) {
|
||||
console.error(`Error fetching from ${table}:`, error);
|
||||
return null;
|
||||
}
|
||||
|
||||
return data;
|
||||
};
|
||||
|
||||
export const fetchGlobals = async (supabase) => {
|
||||
const { data, error } = await supabase
|
||||
.from("optimized_globals")
|
||||
.select("*")
|
||||
.single();
|
||||
if (error) {
|
||||
console.error("Error fetching globals:", error);
|
||||
return {};
|
||||
}
|
||||
return data;
|
||||
};
|
|
@ -1,26 +0,0 @@
|
|||
import markdownIt from "markdown-it";
|
||||
import markdownItAnchor from "markdown-it-anchor";
|
||||
import markdownItFootnote from "markdown-it-footnote";
|
||||
|
||||
export const formatDate = (date) =>
|
||||
new Date(date).toLocaleDateString("en-US", {
|
||||
year: "numeric",
|
||||
month: "long",
|
||||
day: "numeric",
|
||||
});
|
||||
|
||||
export const md = markdownIt({ html: true, linkify: true });
|
||||
|
||||
md.use(markdownItAnchor, {
|
||||
level: [1, 2],
|
||||
permalink: markdownItAnchor.permalink.headerLink({
|
||||
safariReaderFix: true,
|
||||
}),
|
||||
});
|
||||
md.use(markdownItFootnote);
|
||||
|
||||
export const minifyHTML = (html) =>
|
||||
html
|
||||
.replace(/\n\s+/g, "")
|
||||
.replace(/>\s+</g, "><")
|
||||
.replace(/<!--.*?-->/g, "");
|
|
@ -1,521 +0,0 @@
|
|||
import truncateHtml from "truncate-html";
|
||||
import { convert } from "html-to-text";
|
||||
import { parseCountryField } from "./countries.js";
|
||||
import { formatDate, md } from "./formatters.js";
|
||||
import { ICON_MAP } from "./icons.js";
|
||||
|
||||
const warningBanner = `<div class="banner warning"><p>${ICON_MAP["alertTriangle"]}There are probably spoilers after this banner — this is a warning about them.</p></div>`;
|
||||
|
||||
export const generateMetadata = (data, type, globals) => {
|
||||
let title = globals["site_name"];
|
||||
let description = data["description"] || globals["site_description"];
|
||||
const canonicalUrl = data["url"]
|
||||
? `${globals["url"]}${data["url"]}`
|
||||
: globals["url"];
|
||||
const ogImage = `${globals["cdn_url"]}${(data["backdrop"] ? data["backdrop"] : data["image"]) || globals["avatar"]}?class=w800`;
|
||||
|
||||
description = convert(
|
||||
truncateHtml(md.render(description), 100, {
|
||||
byWords: true,
|
||||
ellipsis: "...",
|
||||
}),
|
||||
{
|
||||
wordwrap: false,
|
||||
selectors: [
|
||||
{ selector: "a", options: { ignoreHref: true } },
|
||||
{ selector: "h1", options: { uppercase: false } },
|
||||
{ selector: "h2", options: { uppercase: false } },
|
||||
{ selector: "h3", options: { uppercase: false } },
|
||||
{ selector: "*", format: "block" },
|
||||
],
|
||||
}
|
||||
)
|
||||
.replace(/\s+/g, " ")
|
||||
.trim();
|
||||
|
||||
switch (type) {
|
||||
case "artist":
|
||||
title = `Artists / ${data["name"]} / ${globals["site_name"]}`;
|
||||
break;
|
||||
case "genre":
|
||||
title = `Genre / ${data["name"]} / ${globals["site_name"]}`;
|
||||
break;
|
||||
case "book":
|
||||
title = `Books / ${data["title"]} by ${data["author"]} / ${globals["site_name"]}`;
|
||||
break;
|
||||
case "movie":
|
||||
title = `Movies / ${data["title"]} (${data["year"]}) / ${globals["site_name"]}`;
|
||||
break;
|
||||
case "show":
|
||||
title = `Shows / ${data["title"]} / ${globals["site_name"]}`;
|
||||
break;
|
||||
default:
|
||||
title = `${data["title"] || globals["site_name"]}`;
|
||||
}
|
||||
|
||||
return {
|
||||
title,
|
||||
description,
|
||||
"og:title": title,
|
||||
"og:description": description,
|
||||
"og:image": ogImage,
|
||||
"og:url": canonicalUrl,
|
||||
canonical: canonicalUrl,
|
||||
};
|
||||
};
|
||||
|
||||
const generateAssociatedMediaHTML = (data, isGenre = false) => {
|
||||
const sections = [
|
||||
{
|
||||
key: "artists",
|
||||
icon: "headphones",
|
||||
category: "music",
|
||||
title: "Related Artist(s)",
|
||||
},
|
||||
{
|
||||
key: "related_artists",
|
||||
icon: "headphones",
|
||||
category: "music",
|
||||
title: "Related Artist(s)",
|
||||
},
|
||||
{
|
||||
key: "genres",
|
||||
icon: "headphones",
|
||||
category: "music",
|
||||
title: "Related Genre(s)",
|
||||
},
|
||||
{
|
||||
key: "movies",
|
||||
icon: "film",
|
||||
category: "movies",
|
||||
title: "Related Movie(s)",
|
||||
},
|
||||
{
|
||||
key: "related_movies",
|
||||
icon: "film",
|
||||
category: "movies",
|
||||
title: "Related Movie(s)",
|
||||
},
|
||||
{
|
||||
key: "shows",
|
||||
icon: "deviceTvOld",
|
||||
category: "tv",
|
||||
title: "Related Show(s)",
|
||||
},
|
||||
{
|
||||
key: "related_shows",
|
||||
icon: "deviceTvOld",
|
||||
category: "tv",
|
||||
title: "Related Show(s)",
|
||||
},
|
||||
{
|
||||
key: "posts",
|
||||
icon: "article",
|
||||
category: "article",
|
||||
title: "Related Post(s)",
|
||||
},
|
||||
{
|
||||
key: "books",
|
||||
icon: "books",
|
||||
category: "books",
|
||||
title: "Related Book(s)",
|
||||
},
|
||||
{
|
||||
key: "related_books",
|
||||
icon: "books",
|
||||
category: "books",
|
||||
title: "Related Book(s)",
|
||||
},
|
||||
];
|
||||
|
||||
return sections
|
||||
.filter(({ key }) => !(isGenre && key === "artists"))
|
||||
.map(({ key, category, icon, title }) => {
|
||||
const items = data[key];
|
||||
if (!items || items.length === 0) return "";
|
||||
|
||||
return `
|
||||
<div class="associated-media">
|
||||
<span class="${category}">${ICON_MAP[icon]} ${title}</span>
|
||||
<ul>
|
||||
${items
|
||||
.map((item) => {
|
||||
const name = item.name || item.title;
|
||||
const url = item.url;
|
||||
const year = item.year ? ` (${item.year})` : "";
|
||||
const author = item.author ? ` by ${item.author}` : "";
|
||||
const totalPlays = item.total_plays
|
||||
? ` <strong class="highlight-text">${item.total_plays} ${
|
||||
item.total_plays === 1 ? "play" : "plays"
|
||||
}</strong>`
|
||||
: "";
|
||||
|
||||
let listItemContent = name;
|
||||
|
||||
if (key === "artists" || key === "related_artists") {
|
||||
return `<li><a href="${url}">${name}</a>${totalPlays}</li>`;
|
||||
} else if (
|
||||
key === "movies" ||
|
||||
key === "related_movies" ||
|
||||
key === "shows" ||
|
||||
key === "related_shows"
|
||||
) {
|
||||
listItemContent = `${name}${year}`;
|
||||
} else if (key === "books" || key === "related_books") {
|
||||
listItemContent = `${name}${author}`;
|
||||
}
|
||||
|
||||
return `<li><a href="${url}">${listItemContent}</a></li>`;
|
||||
})
|
||||
.join("")}
|
||||
</ul>
|
||||
</div>`;
|
||||
})
|
||||
.join("");
|
||||
};
|
||||
|
||||
const generateMediaLinks = (data, type, count = 10) => {
|
||||
if (!data || !type) return "";
|
||||
|
||||
const dataSlice = data.slice(0, count);
|
||||
if (dataSlice.length === 0) return null;
|
||||
|
||||
const buildLink = (item) => {
|
||||
switch (type) {
|
||||
case "genre":
|
||||
return `<a href="${item["genre_url"]}">${item["genre_name"]}</a>`;
|
||||
case "artist":
|
||||
return `<a href="${item["url"]}">${item["name"]}</a>`;
|
||||
case "book":
|
||||
return `<a href="${item["url"]}">${item["title"]}</a>`;
|
||||
default:
|
||||
return "";
|
||||
}
|
||||
};
|
||||
|
||||
if (dataSlice.length === 1) return buildLink(dataSlice[0]);
|
||||
|
||||
const links = dataSlice.map(buildLink);
|
||||
const allButLast = links.slice(0, -1).join(", ");
|
||||
const last = links[links.length - 1];
|
||||
|
||||
return `${allButLast} and ${last}`;
|
||||
};
|
||||
|
||||
export const generateArtistHTML = (artist, globals) => {
|
||||
const playLabel = artist?.["total_plays"] === 1 ? "play" : "plays";
|
||||
const concertsList = artist["concerts"]?.length
|
||||
? `<hr />
|
||||
<span id="concerts" class="concerts">
|
||||
${ICON_MAP["deviceSpeaker"]}
|
||||
I've seen this artist live!
|
||||
</span>
|
||||
<ul>${artist["concerts"].map(generateConcertModal).join("")}</ul>`
|
||||
: "";
|
||||
const albumsTable = artist["albums"]?.length
|
||||
? `<table>
|
||||
<tr><th>Album</th><th>Plays</th><th>Year</th></tr>
|
||||
${artist["albums"]
|
||||
.map(
|
||||
(album) => `
|
||||
<tr>
|
||||
<td>${album["name"]}</td>
|
||||
<td>${album["total_plays"] || 0}</td>
|
||||
<td>${album["release_year"]}</td>
|
||||
</tr>`
|
||||
)
|
||||
.join("")}
|
||||
</table>
|
||||
<p><em>These are the albums by this artist that are in my collection, not necessarily a comprehensive discography.</em></p>
|
||||
`
|
||||
: "";
|
||||
|
||||
return `
|
||||
<a href="/music" class="back-link">${ICON_MAP.arrowLeft} Back to music</a>
|
||||
<article class="artist-focus">
|
||||
<div class="artist-display">
|
||||
<img
|
||||
srcset="
|
||||
${globals["cdn_url"]}${artist["image"]}?class=w200&type=webp 200w,
|
||||
${globals["cdn_url"]}${artist["image"]}?class=w600&type=webp 400w,
|
||||
${globals["cdn_url"]}${artist["image"]}?class=w800&type=webp 800w
|
||||
"
|
||||
sizes="(max-width: 450px) 200px,
|
||||
(max-width: 850px) 400px,
|
||||
800px"
|
||||
src="${globals["cdn_url"]}${artist["image"]}?class=w200&type=webp"
|
||||
alt="${artist["name"]} / ${artist["country"]}"
|
||||
loading="eager"
|
||||
decoding="async"
|
||||
width="200"
|
||||
height="200"
|
||||
/>
|
||||
<div class="media-meta">
|
||||
<span class="title"><strong>${artist["name"]}</strong></span>
|
||||
<span class="sub-meta country">${ICON_MAP["mapPin"]} ${parseCountryField(
|
||||
artist["country"]
|
||||
)}</span>
|
||||
${
|
||||
artist["favorite"]
|
||||
? `<span class="sub-meta favorite">${ICON_MAP["heart"]} This is one of my favorite artists!</span>`
|
||||
: ""
|
||||
}
|
||||
${
|
||||
artist["tattoo"]
|
||||
? `<span class="sub-meta tattoo">${ICON_MAP["needle"]} I have a tattoo inspired by this artist!</span>`
|
||||
: ""
|
||||
}
|
||||
${
|
||||
artist["total_plays"]
|
||||
? `<span class="sub-meta"><strong class="highlight-text">${artist["total_plays"]} ${playLabel}</strong></span>`
|
||||
: ""
|
||||
}
|
||||
<span class="sub-meta">${
|
||||
artist["genre"]
|
||||
? `<a href="${artist["genre"]["url"]}">${artist["genre"]["name"]}</a>`
|
||||
: ""
|
||||
}</span>
|
||||
</div>
|
||||
</div>
|
||||
${generateAssociatedMediaHTML(artist)}
|
||||
${
|
||||
artist["description"]
|
||||
? `
|
||||
<h2>Overview</h2>
|
||||
<div data-toggle-content class="text-toggle-hidden">${md.render(
|
||||
artist["description"]
|
||||
)}</div>
|
||||
<button data-toggle-button>Show more</button>`
|
||||
: ""
|
||||
}
|
||||
${concertsList}
|
||||
${albumsTable}
|
||||
</article>
|
||||
`;
|
||||
};
|
||||
|
||||
export const generateBookHTML = (book, globals) => {
|
||||
const alt = `${book["title"]}${
|
||||
book["author"] ? ` by ${book["author"]}` : ""
|
||||
}`;
|
||||
const percentage = book["progress"] ? `${book["progress"]}%` : "";
|
||||
const status =
|
||||
book["status"] === "finished"
|
||||
? `<span class="sub-meta">Finished on <strong class="highlight-text">${formatDate(
|
||||
book["date_finished"]
|
||||
)}</strong></span>`
|
||||
: percentage
|
||||
? `<div class="progress-bar-wrapper" title="${percentage}">
|
||||
<div class="progress-bar" style="width:${percentage}"></div>
|
||||
</div>`
|
||||
: "";
|
||||
|
||||
return `
|
||||
<a href="/books" class="back-link">${
|
||||
ICON_MAP["arrowLeft"]
|
||||
} Back to books</a>
|
||||
<article class="book-focus">
|
||||
<div class="book-display">
|
||||
<img
|
||||
srcset="
|
||||
${globals["cdn_url"]}${
|
||||
book["image"]
|
||||
}?class=verticalsm&type=webp 200w,
|
||||
${globals["cdn_url"]}${
|
||||
book["image"]
|
||||
}?class=verticalmd&type=webp 400w,
|
||||
${globals["cdn_url"]}${
|
||||
book["image"]
|
||||
}?class=verticalbase&type=webp 800w
|
||||
"
|
||||
sizes="(max-width: 450px) 203px, (max-width: 850px) 406px, 812px"
|
||||
src="${globals["cdn_url"]}${book["image"]}?class=verticalsm&type=webp"
|
||||
alt="${alt}"
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
width="200"
|
||||
height="307"
|
||||
/>
|
||||
<div class="media-meta">
|
||||
<span class="title"><strong>${book["title"]}</strong></span>
|
||||
${book["rating"] ? `<span>${book["rating"]}</span>` : ""}
|
||||
${
|
||||
book["author"] ? `<span class="sub-meta">By ${book["author"]}</span>` : ""
|
||||
}
|
||||
${
|
||||
book["favorite"]
|
||||
? `<span class="sub-meta favorite">${ICON_MAP["heart"]} This is one of my favorite books!</span>`
|
||||
: ""
|
||||
}
|
||||
${
|
||||
book["tattoo"]
|
||||
? `<span class="sub-meta tattoo">${ICON_MAP["needle"]} I have a tattoo inspired by this book!</span>`
|
||||
: ""
|
||||
}
|
||||
${status ? status : ""}
|
||||
</div>
|
||||
</div>
|
||||
${
|
||||
book["review"]
|
||||
? `${warningBanner}<h2>My thoughts</h2><p>${md.render(book["review"])}</p>`
|
||||
: ""
|
||||
}
|
||||
${generateAssociatedMediaHTML(book)}
|
||||
<h2>Overview</h2>
|
||||
<p>${md.render(book["description"])}</p>
|
||||
</article>
|
||||
`;
|
||||
};
|
||||
|
||||
export const generateGenreHTML = (genre) => {
|
||||
const artistCount = genre["artists"]?.length || 0;
|
||||
const connectingWords = artistCount > 1 ? "artists are" : "artist is";
|
||||
const mediaLinks = generateMediaLinks(genre["artists"], "artist", 5);
|
||||
|
||||
return `
|
||||
<a href="/music" class="back-link">${
|
||||
ICON_MAP["arrowLeft"]
|
||||
} Back to music</a>
|
||||
<h2>${genre["name"]}</h2>
|
||||
<article class="genre-focus">
|
||||
${
|
||||
mediaLinks
|
||||
? `
|
||||
<p>My top <strong class="highlight-text">${genre["name"]}</strong> ${connectingWords} ${mediaLinks}. I've listened to <strong class="highlight-text">${genre["total_plays"]}</strong> tracks from this genre.</p>
|
||||
<hr />`
|
||||
: ""
|
||||
}
|
||||
${generateAssociatedMediaHTML(genre, true)}
|
||||
${
|
||||
genre["description"]
|
||||
? `
|
||||
<h3>Overview</h3>
|
||||
<div data-toggle-content class="text-toggle-hidden">
|
||||
${md.render(genre["description"])}
|
||||
<p><a href="${
|
||||
genre["wiki_link"]
|
||||
}">Continue reading at Wikipedia.</a></p>
|
||||
<p><em>Wikipedia content provided under the terms of the <a href="https://creativecommons.org/licenses/by-sa/3.0/">Creative Commons BY-SA license</a>.</em></p>
|
||||
</div>
|
||||
<button data-toggle-button>Show more</button>`
|
||||
: ""
|
||||
}
|
||||
</article>
|
||||
`;
|
||||
};
|
||||
|
||||
export const generateWatchingHTML = (media, globals, type) => {
|
||||
const isShow = type === "show";
|
||||
const label = isShow ? "show" : "movie";
|
||||
const lastWatched =
|
||||
media["last_watched"] || (isShow && media["episode"]?.["last_watched_at"]);
|
||||
|
||||
return `
|
||||
<a href="/watching" class="back-link">${
|
||||
ICON_MAP.arrowLeft
|
||||
} Back to watching</a>
|
||||
<article class="watching focus">
|
||||
<img
|
||||
srcset="
|
||||
${globals["cdn_url"]}${
|
||||
media["backdrop"]
|
||||
}?class=bannersm&type=webp 256w,
|
||||
${globals["cdn_url"]}${
|
||||
media["backdrop"]
|
||||
}?class=bannermd&type=webp 512w,
|
||||
${globals["cdn_url"]}${
|
||||
media["backdrop"]
|
||||
}?class=bannerbase&type=webp 1024w
|
||||
"
|
||||
sizes="(max-width: 450px) 256px,
|
||||
(max-width: 850px) 512px,
|
||||
1024px"
|
||||
src="${globals["cdn_url"]}${media["backdrop"]}?class=bannersm&type=webp"
|
||||
alt="${media["title"]} / ${media["year"]}"
|
||||
class="image-banner"
|
||||
loading="eager"
|
||||
decoding="async"
|
||||
width="256"
|
||||
height="180"
|
||||
/>
|
||||
<div class="media-meta">
|
||||
<span class="title"><strong>${media["title"]}</strong> (${
|
||||
media["year"]
|
||||
})</span>
|
||||
${media["rating"] ? `<span>${media["rating"]}</span>` : ""}
|
||||
${
|
||||
media["favorite"]
|
||||
? `<span class="sub-meta favorite">${ICON_MAP["heart"]} This is one of my favorite ${label}s!</span>`
|
||||
: ""
|
||||
}
|
||||
${
|
||||
media["tattoo"]
|
||||
? `<span class="sub-meta tattoo">${ICON_MAP["needle"]} I have a tattoo inspired by this ${label}!</span>`
|
||||
: ""
|
||||
}
|
||||
${
|
||||
media["collected"]
|
||||
? `<span class="sub-meta collected">${ICON_MAP["circleCheck"]} This ${label} is in my collection!</span>`
|
||||
: ""
|
||||
}
|
||||
${
|
||||
lastWatched
|
||||
? `<span class="sub-meta">Last watched on <strong class="highlight-text">${formatDate(
|
||||
lastWatched
|
||||
)}</strong>.</span>`
|
||||
: ""
|
||||
}
|
||||
</div>
|
||||
${
|
||||
media["review"]
|
||||
? `${warningBanner}<h2>My thoughts</h2><p>${md.render(
|
||||
media["review"]
|
||||
)}</p>`
|
||||
: ""
|
||||
}
|
||||
${generateAssociatedMediaHTML(media)}
|
||||
${
|
||||
media["description"]
|
||||
? `<h2>Overview</h2><p>${md.render(media["description"])}</p>`
|
||||
: ""
|
||||
}
|
||||
</article>
|
||||
`;
|
||||
};
|
||||
|
||||
export const generateConcertModal = (concert) => {
|
||||
const venue = concert["venue_name"]
|
||||
? concert["venue_latitude"] && concert["venue_longitude"]
|
||||
? `<a href="https://www.openstreetmap.org/?mlat=${concert["venue_latitude"]}&mlon=${concert["venue_longitude"]}#map=18/${concert["venue_latitude"]}/${concert["venue_longitude"]}">${concert["venue_name_short"]}</a>`
|
||||
: concert["venue_name_short"]
|
||||
: "";
|
||||
|
||||
const notesModal = concert["notes"]
|
||||
? `<input class="modal-input" id="${
|
||||
concert["id"]
|
||||
}" type="checkbox" tabindex="0" />
|
||||
<label class="modal-toggle" for="${concert["id"]}">${
|
||||
ICON_MAP["infoCircle"]
|
||||
}</label>
|
||||
<div class="modal-wrapper">
|
||||
<div class="modal-body">
|
||||
<label class="modal-close" for="${concert["id"]}">${
|
||||
ICON_MAP["circleX"]
|
||||
}</label>
|
||||
<div>
|
||||
<h3>Notes</h3>
|
||||
${md.render(concert["notes"])}
|
||||
</div>
|
||||
</div>
|
||||
</div>`
|
||||
: "";
|
||||
|
||||
return `
|
||||
<li>
|
||||
<strong class="highlight-text">${formatDate(
|
||||
concert["date"]
|
||||
)}</strong> at ${venue}
|
||||
${notesModal}
|
||||
</li>
|
||||
`;
|
||||
};
|
|
@ -1,18 +0,0 @@
|
|||
export const ICON_MAP = {
|
||||
alertTriangle: `<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="icon icon-tabler icons-tabler-outline icon-tabler-alert-triangle"><path stroke="none" d="M0 0h24v24H0z" fill="none"/><path d="M12 9v4" /><path d="M10.363 3.591l-8.106 13.534a1.914 1.914 0 0 0 1.636 2.871h16.214a1.914 1.914 0 0 0 1.636 -2.87l-8.106 -13.536a1.914 1.914 0 0 0 -3.274 0z" /><path d="M12 16h.01" /></svg>`,
|
||||
arrowLeft: `<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="icon icon-tabler icons-tabler-outline icon-tabler-arrow-left"><path stroke="none" d="M0 0h24v24H0z" fill="none"/><path d="M5 12l14 0"/><path d="M5 12l6 6"/><path d="M5 12l6 -6"/></svg>`,
|
||||
article: `<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="icon icon-tabler icons-tabler-outline icon-tabler-article"><path stroke="none" d="M0 0h24v24H0z" fill="none"/><path d="M3 4m0 2a2 2 0 0 1 2 -2h14a2 2 0 0 1 2 2v12a2 2 0 0 1 -2 2h-14a2 2 0 0 1 -2 -2z" /><path d="M7 8h10" /><path d="M7 12h10" /><path d="M7 16h10" /></svg>`,
|
||||
books: `<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="icon icon-tabler icons-tabler-outline icon-tabler-books"><path stroke="none" d="M0 0h24v24H0z" fill="none"/><path d="M5 4m0 1a1 1 0 0 1 1 -1h2a1 1 0 0 1 1 1v14a1 1 0 0 1 -1 1h-2a1 1 0 0 1 -1 -1z" /><path d="M9 4m0 1a1 1 0 0 1 1 -1h2a1 1 0 0 1 1 1v14a1 1 0 0 1 -1 1h-2a1 1 0 0 1 -1 -1z" /><path d="M5 8h4" /><path d="M9 16h4" /><path d="M13.803 4.56l2.184 -.53c.562 -.135 1.133 .19 1.282 .732l3.695 13.418a1.02 1.02 0 0 1 -.634 1.219l-.133 .041l-2.184 .53c-.562 .135 -1.133 -.19 -1.282 -.732l-3.695 -13.418a1.02 1.02 0 0 1 .634 -1.219l.133 -.041z" /><path d="M14 9l4 -1" /><path d="M16 16l3.923 -.98" /></svg>`,
|
||||
circleCheck: `<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="icon icon-tabler icons-tabler-outline icon-tabler-circle-check"><path stroke="none" d="M0 0h24v24H0z" fill="none"/><path d="M12 12m-9 0a9 9 0 1 0 18 0a9 9 0 1 0 -18 0"/><path d="M9 12l2 2l4 -4"/></svg>`,
|
||||
circleX: `<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="icon icon-tabler icons-tabler-outline icon-tabler-circle-x"><path stroke="none" d="M0 0h24v24H0z" fill="none"/><path d="M12 12m-9 0a9 9 0 1 0 18 0a9 9 0 1 0 -18 0" /><path d="M10 10l4 4m0 -4l-4 4" /></svg>`,
|
||||
deviceSpeaker: `<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="icon icon-tabler icons-tabler-outline icon-tabler-device-speaker"><path stroke="none" d="M0 0h24v24H0z" fill="none"/><path d="M5 3m0 2a2 2 0 0 1 2 -2h10a2 2 0 0 1 2 2v14a2 2 0 0 1 -2 2h-10a2 2 0 0 1 -2 -2z" /><path d="M12 14m-3 0a3 3 0 1 0 6 0a3 3 0 1 0 -6 0" /><path d="M12 7l0 .01" /></svg>`,
|
||||
deviceTvOld: `<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="icon icon-tabler icons-tabler-outline icon-tabler-device-tv-old"><path stroke="none" d="M0 0h24v24H0z" fill="none"/><path d="M3 7m0 2a2 2 0 0 1 2 -2h14a2 2 0 0 1 2 2v9a2 2 0 0 1 -2 2h-14a2 2 0 0 1 -2 -2z" /><path d="M16 3l-4 4l-4 -4" /><path d="M15 7v13" /><path d="M18 15v.01" /><path d="M18 12v.01" /></svg>`,
|
||||
film: `<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="icon icon-tabler icons-tabler-outline icon-tabler-movie"><path stroke="none" d="M0 0h24v24H0z" fill="none"/><path d="M4 4m0 2a2 2 0 0 1 2 -2h12a2 2 0 0 1 2 2v12a2 2 0 0 1 -2 2h-12a2 2 0 0 1 -2 -2z" /><path d="M8 4l0 16" /><path d="M16 4l0 16" /><path d="M4 8l4 0" /><path d="M4 16l4 0" /><path d="M4 12l16 0" /><path d="M16 8l4 0" /><path d="M16 16l4 0" /></svg>`,
|
||||
headphones: `<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="icon icon-tabler icons-tabler-outline icon-tabler-headphones"><path stroke="none" d="M0 0h24v24H0z" fill="none"/><path d="M4 13m0 2a2 2 0 0 1 2 -2h1a2 2 0 0 1 2 2v3a2 2 0 0 1 -2 2h-1a2 2 0 0 1 -2 -2z" /><path d="M15 13m0 2a2 2 0 0 1 2 -2h1a2 2 0 0 1 2 2v3a2 2 0 0 1 -2 2h-1a2 2 0 0 1 -2 -2z" /><path d="M4 15v-3a8 8 0 0 1 16 0v3" /></svg>`,
|
||||
heart: `<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="icon icon-tabler icons-tabler-outline icon-tabler-heart"><path stroke="none" d="M0 0h24v24H0z" fill="none"/><path d="M19.5 12.572l-7.5 7.428l-7.5 -7.428a5 5 0 1 1 7.5 -6.566a5 5 0 1 1 7.5 6.572"/></svg>`,
|
||||
infoCircle: `<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="icon icon-tabler icons-tabler-outline icon-tabler-info-circle"><path stroke="none" d="M0 0h24v24H0z" fill="none"/><path d="M3 12a9 9 0 1 0 18 0a9 9 0 0 0 -18 0" /><path d="M12 9h.01" /><path d="M11 12h1v4h1" /></svg>`,
|
||||
link: `<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="icon icon-tabler icons-tabler-outline icon-tabler-link"><path stroke="none" d="M0 0h24v24H0z" fill="none"/><path d="M9 15l6 -6" /><path d="M11 6l.463 -.536a5 5 0 0 1 7.071 7.072l-.534 .464" /><path d="M13 18l-.397 .534a5.068 5.068 0 0 1 -7.127 0a4.972 4.972 0 0 1 0 -7.071l.524 -.463" /></svg>`,
|
||||
mapPin: `<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="icon icon-tabler icons-tabler-outline icon-tabler-map-pin"><path stroke="none" d="M0 0h24v24H0z" fill="none"/><path d="M9 11a3 3 0 1 0 6 0a3 3 0 0 0 -6 0" /><path d="M17.657 16.657l-4.243 4.243a2 2 0 0 1 -2.827 0l-4.244 -4.243a8 8 0 1 1 11.314 0z" /></svg>`,
|
||||
needle: `<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="icon icon-tabler icons-tabler-outline icon-tabler-needle"><path stroke="none" d="M0 0h24v24H0z" fill="none"/><path d="M3 21c-.667 -.667 3.262 -6.236 11.785 -16.709a3.5 3.5 0 1 1 5.078 4.791c-10.575 8.612 -16.196 12.585 -16.863 11.918z"/><path d="M17.5 6.5l-1 1"/></svg>`,
|
||||
movie: `<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="icon icon-tabler icons-tabler-outline icon-tabler-movie"><path stroke="none" d="M0 0h24v24H0z" fill="none"/><path d="M4 6h16M4 12h16M4 18h16M10 4v2M14 4v2M10 12v2M14 12v2M10 18v2M14 18v2"/></svg>`,
|
||||
};
|
|
@ -1,49 +0,0 @@
|
|||
import { parseHTML } from "linkedom";
|
||||
|
||||
export const updateDynamicContent = (html, metadata, mediaHtml) => {
|
||||
const { document } = parseHTML(html);
|
||||
|
||||
const titleTag = document.querySelector('title[data-dynamic="title"]');
|
||||
if (titleTag) titleTag["textContent"] = metadata["title"];
|
||||
|
||||
const dynamicMetaSelectors = [
|
||||
{
|
||||
selector: 'meta[data-dynamic="description"]',
|
||||
attribute: "content",
|
||||
value: metadata["description"],
|
||||
},
|
||||
{
|
||||
selector: 'meta[data-dynamic="og:title"]',
|
||||
attribute: "content",
|
||||
value: metadata["og:title"],
|
||||
},
|
||||
{
|
||||
selector: 'meta[data-dynamic="og:description"]',
|
||||
attribute: "content",
|
||||
value: metadata["og:description"],
|
||||
},
|
||||
{
|
||||
selector: 'meta[data-dynamic="og:image"]',
|
||||
attribute: "content",
|
||||
value: metadata["og:image"],
|
||||
},
|
||||
{
|
||||
selector: 'meta[data-dynamic="og:url"]',
|
||||
attribute: "content",
|
||||
value: metadata["canonical"],
|
||||
},
|
||||
];
|
||||
|
||||
dynamicMetaSelectors.forEach(({ selector, attribute, value }) => {
|
||||
const element = document.querySelector(selector);
|
||||
if (element) element.setAttribute(attribute, value);
|
||||
});
|
||||
|
||||
const canonicalLink = document.querySelector('link[rel="canonical"]');
|
||||
if (canonicalLink) canonicalLink.setAttribute("href", metadata["canonical"]);
|
||||
|
||||
const pageElement = document.querySelector('[data-dynamic="page"]');
|
||||
if (pageElement) pageElement.innerHTML = mediaHtml;
|
||||
|
||||
return document.toString();
|
||||
};
|
|
@ -1,19 +0,0 @@
|
|||
name = "dynamic-media-worker"
|
||||
main = "./index.js"
|
||||
compatibility_date = "2023-01-01"
|
||||
|
||||
account_id = "${CF_ACCOUNT_ID}"
|
||||
workers_dev = true
|
||||
|
||||
[observability]
|
||||
enabled = true
|
||||
|
||||
[env.production]
|
||||
name = "dynamic-media-worker-production"
|
||||
routes = [
|
||||
{ pattern = "https://coryd.dev/watching/movies/*", zone_id = "${CF_ZONE_ID}" },
|
||||
{ pattern = "https://coryd.dev/watching/shows/*", zone_id = "${CF_ZONE_ID}" },
|
||||
{ pattern = "https://coryd.dev/music/artists/*", zone_id = "${CF_ZONE_ID}" },
|
||||
{ pattern = "https://coryd.dev/music/genres/*", zone_id = "${CF_ZONE_ID}" },
|
||||
{ pattern = "https://coryd.dev/books/*", zone_id = "${CF_ZONE_ID}" },
|
||||
]
|
|
@ -5,7 +5,7 @@ import { createClient } from "@supabase/supabase-js";
|
|||
const BASE_URL = "https://coryd.dev";
|
||||
|
||||
export default {
|
||||
async scheduled(event, env, ctx) {
|
||||
async scheduled(event, env) {
|
||||
await handleMastodonPost(env);
|
||||
},
|
||||
};
|
||||
|
@ -14,8 +14,8 @@ async function handleMastodonPost(env) {
|
|||
const mastodonApiUrl = "https://follow.coryd.dev/api/v1/statuses";
|
||||
const accessToken = env.MASTODON_ACCESS_TOKEN;
|
||||
const rssFeedUrl = "https://coryd.dev/feeds/syndication";
|
||||
const supabaseUrl = env.SUPABASE_URL || process.env.SUPABASE_URL;
|
||||
const supabaseKey = env.SUPABASE_KEY || process.env.SUPABASE_KEY;
|
||||
const supabaseUrl = env.SUPABASE_URL;
|
||||
const supabaseKey = env.SUPABASE_KEY;
|
||||
const supabase = createClient(supabaseUrl, supabaseKey);
|
||||
|
||||
try {
|
||||
|
@ -56,7 +56,6 @@ async function handleMastodonPost(env) {
|
|||
accessToken,
|
||||
content
|
||||
);
|
||||
|
||||
const timestamp = new Date().toISOString();
|
||||
|
||||
await env.RSS_TO_MASTODON_NAMESPACE.put(link, timestamp);
|
||||
|
@ -101,6 +100,8 @@ function truncateContent(title, description, link, maxLength) {
|
|||
.slice(0, -1)
|
||||
.join(" ") + "...";
|
||||
|
||||
truncatedDescription = truncatedDescription.replace(/\s+([.,!?;:])/g, "$1");
|
||||
|
||||
return `${title}\n\n${truncatedDescription}\n\n${link}`;
|
||||
}
|
||||
|
||||
|
|
|
@ -2,8 +2,8 @@ import { createClient } from "@supabase/supabase-js";
|
|||
|
||||
export default {
|
||||
async fetch(request, env) {
|
||||
const supabaseUrl = env.SUPABASE_URL || process.env.SUPABASE_URL;
|
||||
const supabaseKey = env.SUPABASE_KEY || process.env.SUPABASE_KEY;
|
||||
const supabaseUrl = env.SUPABASE_URL;
|
||||
const supabaseKey = env.SUPABASE_KEY;
|
||||
const supabase = createClient(supabaseUrl, supabaseKey);
|
||||
|
||||
const { data, error } = await supabase
|
||||
|
|
|
@ -67,8 +67,8 @@ const sendEmail = async (subject, text, authHeader, maxRetries = 3) => {
|
|||
|
||||
export default {
|
||||
async fetch(request, env) {
|
||||
const supabaseUrl = env.SUPABASE_URL || process.env.SUPABASE_URL;
|
||||
const supabaseKey = env.SUPABASE_KEY || process.env.SUPABASE_KEY;
|
||||
const supabaseUrl = env.SUPABASE_URL;
|
||||
const supabaseKey = env.SUPABASE_KEY;
|
||||
const FORWARDEMAIL_API_KEY = env.FORWARDEMAIL_API_KEY;
|
||||
const ACCOUNT_ID_PLEX = env.ACCOUNT_ID_PLEX;
|
||||
const supabase = createClient(supabaseUrl, supabaseKey);
|
||||
|
|
|
@ -2,8 +2,8 @@ import { createClient } from "@supabase/supabase-js";
|
|||
|
||||
export default {
|
||||
async fetch(request, env) {
|
||||
const supabaseUrl = env.SUPABASE_URL || process.env.SUPABASE_URL;
|
||||
const supabaseKey = env.SUPABASE_KEY || process.env.SUPABASE_KEY;
|
||||
const supabaseUrl = env.SUPABASE_URL;
|
||||
const supabaseKey = env.SUPABASE_KEY;
|
||||
const supabase = createClient(supabaseUrl, supabaseKey);
|
||||
|
||||
try {
|
||||
|
|
Reference in a new issue