updated content, added markdown to html converter
|
|
@ -1,7 +1,12 @@
|
|||
import { defineConfig } from "astro/config";
|
||||
import tailwind from "@astrojs/tailwind";
|
||||
|
||||
import mdx from "@astrojs/mdx";
|
||||
|
||||
// https://astro.build/config
|
||||
export default defineConfig({
|
||||
integrations: [tailwind()]
|
||||
integrations: [tailwind(), mdx()],
|
||||
server: {
|
||||
port: 3000
|
||||
}
|
||||
});
|
||||
BIN
md-to-html.exe
Normal file
674
package-lock.json
generated
|
|
@ -8,7 +8,9 @@
|
|||
"name": "coworking-guide",
|
||||
"version": "2.0.0",
|
||||
"dependencies": {
|
||||
"@astrojs/mdx": "^2.1.1",
|
||||
"@astrojs/tailwind": "^5.1.0",
|
||||
"@astrojs/ts-plugin": "^1.5.3",
|
||||
"@vercel/analytics": "^1.0.1",
|
||||
"astro": "^4.4.1",
|
||||
"tailwindcss": "^3.4.1"
|
||||
|
|
@ -72,6 +74,34 @@
|
|||
"vfile": "^6.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@astrojs/mdx": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/@astrojs/mdx/-/mdx-2.1.1.tgz",
|
||||
"integrity": "sha512-AgGFdE7HOGmoFooGvMSatkA9FiSKwyVW7ImHot/bXJ6uAbFfu6iG2ht18Cf1pT22Hda/6iSCGWusFvBv0/EnKQ==",
|
||||
"dependencies": {
|
||||
"@astrojs/markdown-remark": "4.2.1",
|
||||
"@mdx-js/mdx": "^3.0.0",
|
||||
"acorn": "^8.11.2",
|
||||
"es-module-lexer": "^1.4.1",
|
||||
"estree-util-visit": "^2.0.0",
|
||||
"github-slugger": "^2.0.0",
|
||||
"gray-matter": "^4.0.3",
|
||||
"hast-util-to-html": "^9.0.0",
|
||||
"kleur": "^4.1.4",
|
||||
"rehype-raw": "^7.0.0",
|
||||
"remark-gfm": "^4.0.0",
|
||||
"remark-smartypants": "^2.0.0",
|
||||
"source-map": "^0.7.4",
|
||||
"unist-util-visit": "^5.0.0",
|
||||
"vfile": "^6.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18.14.1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"astro": "^4.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@astrojs/prism": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@astrojs/prism/-/prism-3.0.0.tgz",
|
||||
|
|
@ -128,6 +158,19 @@
|
|||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/@astrojs/ts-plugin": {
|
||||
"version": "1.5.3",
|
||||
"resolved": "https://registry.npmjs.org/@astrojs/ts-plugin/-/ts-plugin-1.5.3.tgz",
|
||||
"integrity": "sha512-exMHUWAa+JxJ1GaOw6TrC/znZMSwuFMaZrtGxjqfdsMnBAVR4WzJbs9560JNAJCxG7HMqpIfVcjqHdQe2oJ9LA==",
|
||||
"dependencies": {
|
||||
"@astrojs/compiler": "^2.4.0",
|
||||
"@jridgewell/sourcemap-codec": "^1.4.15",
|
||||
"@volar/language-core": "~2.0.4",
|
||||
"@volar/typescript": "~2.0.4",
|
||||
"semver": "^7.3.8",
|
||||
"vscode-languageserver-textdocument": "^1.0.11"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/code-frame": {
|
||||
"version": "7.23.5",
|
||||
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.23.5.tgz",
|
||||
|
|
@ -892,6 +935,40 @@
|
|||
"resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz",
|
||||
"integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw=="
|
||||
},
|
||||
"node_modules/@mdx-js/mdx": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@mdx-js/mdx/-/mdx-3.0.1.tgz",
|
||||
"integrity": "sha512-eIQ4QTrOWyL3LWEe/bu6Taqzq2HQvHcyTMaOrI95P2/LmJE7AsfPfgJGuFLPVqBUE1BC1rik3VIhU+s9u72arA==",
|
||||
"dependencies": {
|
||||
"@types/estree": "^1.0.0",
|
||||
"@types/estree-jsx": "^1.0.0",
|
||||
"@types/hast": "^3.0.0",
|
||||
"@types/mdx": "^2.0.0",
|
||||
"collapse-white-space": "^2.0.0",
|
||||
"devlop": "^1.0.0",
|
||||
"estree-util-build-jsx": "^3.0.0",
|
||||
"estree-util-is-identifier-name": "^3.0.0",
|
||||
"estree-util-to-js": "^2.0.0",
|
||||
"estree-walker": "^3.0.0",
|
||||
"hast-util-to-estree": "^3.0.0",
|
||||
"hast-util-to-jsx-runtime": "^2.0.0",
|
||||
"markdown-extensions": "^2.0.0",
|
||||
"periscopic": "^3.0.0",
|
||||
"remark-mdx": "^3.0.0",
|
||||
"remark-parse": "^11.0.0",
|
||||
"remark-rehype": "^11.0.0",
|
||||
"source-map": "^0.7.0",
|
||||
"unified": "^11.0.0",
|
||||
"unist-util-position-from-estree": "^2.0.0",
|
||||
"unist-util-stringify-position": "^4.0.0",
|
||||
"unist-util-visit": "^5.0.0",
|
||||
"vfile": "^6.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/unified"
|
||||
}
|
||||
},
|
||||
"node_modules/@medv/finder": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@medv/finder/-/finder-3.1.0.tgz",
|
||||
|
|
@ -1094,6 +1171,14 @@
|
|||
"win32"
|
||||
]
|
||||
},
|
||||
"node_modules/@types/acorn": {
|
||||
"version": "4.0.6",
|
||||
"resolved": "https://registry.npmjs.org/@types/acorn/-/acorn-4.0.6.tgz",
|
||||
"integrity": "sha512-veQTnWP+1D/xbxVrPC3zHnCZRjSrKfhbMUlEA43iMZLu7EsnTtkJklIuwrCPbOi8YkvDQAiW05VQQFvvz9oieQ==",
|
||||
"dependencies": {
|
||||
"@types/estree": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/babel__core": {
|
||||
"version": "7.20.5",
|
||||
"resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz",
|
||||
|
|
@ -1144,6 +1229,14 @@
|
|||
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz",
|
||||
"integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw=="
|
||||
},
|
||||
"node_modules/@types/estree-jsx": {
|
||||
"version": "1.0.5",
|
||||
"resolved": "https://registry.npmjs.org/@types/estree-jsx/-/estree-jsx-1.0.5.tgz",
|
||||
"integrity": "sha512-52CcUVNFyfb1A2ALocQw/Dd1BQFNmSdkuC3BkZ6iqhdMfQz7JWOFRuJFloOzjk+6WijU56m9oKXFAXc7o3Towg==",
|
||||
"dependencies": {
|
||||
"@types/estree": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/hast": {
|
||||
"version": "3.0.4",
|
||||
"resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.4.tgz",
|
||||
|
|
@ -1160,6 +1253,11 @@
|
|||
"@types/unist": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/mdx": {
|
||||
"version": "2.0.11",
|
||||
"resolved": "https://registry.npmjs.org/@types/mdx/-/mdx-2.0.11.tgz",
|
||||
"integrity": "sha512-HM5bwOaIQJIQbAYfax35HCKxx7a3KrK3nBtIqJgSOitivTD1y3oW9P3rxY9RkXYPUk7y/AjAohfHKmFpGE79zw=="
|
||||
},
|
||||
"node_modules/@types/ms": {
|
||||
"version": "0.7.34",
|
||||
"resolved": "https://registry.npmjs.org/@types/ms/-/ms-0.7.34.tgz",
|
||||
|
|
@ -1203,6 +1301,31 @@
|
|||
"resolved": "https://registry.npmjs.org/@vercel/analytics/-/analytics-1.0.1.tgz",
|
||||
"integrity": "sha512-Ux0c9qUfkcPqng3vrR0GTrlQdqNJ2JREn/2ydrVuKwM3RtMfF2mWX31Ijqo1opSjNAq6rK76PwtANw6kl6TAow=="
|
||||
},
|
||||
"node_modules/@volar/language-core": {
|
||||
"version": "2.0.4",
|
||||
"resolved": "https://registry.npmjs.org/@volar/language-core/-/language-core-2.0.4.tgz",
|
||||
"integrity": "sha512-VhC8i03P0x9LKGLTBi81xNTNWm40yxQ/Iba8IpH+LFr+Yb7c/D7fF90Cvf31MzPDM4G5rjIOlCfs+eQKPBkwQw==",
|
||||
"dependencies": {
|
||||
"@volar/source-map": "2.0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/@volar/source-map": {
|
||||
"version": "2.0.4",
|
||||
"resolved": "https://registry.npmjs.org/@volar/source-map/-/source-map-2.0.4.tgz",
|
||||
"integrity": "sha512-BbxUinEMoJZqrHsSj1aBa0boCBnN3BoXnf7j9IBwjxosxGXOhCvqmH2L9raJemadaKjeVR8ZQLhV7AOhyoHt/Q==",
|
||||
"dependencies": {
|
||||
"muggle-string": "^0.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@volar/typescript": {
|
||||
"version": "2.0.4",
|
||||
"resolved": "https://registry.npmjs.org/@volar/typescript/-/typescript-2.0.4.tgz",
|
||||
"integrity": "sha512-KF7yh7GIo4iWuAQOKf/ONeFHdQA+wFriitW8LtGZB4iOOT6MdlRlYNsRL8do7XxmXvsBKcs4jTMtGn+uZRwlWg==",
|
||||
"dependencies": {
|
||||
"@volar/language-core": "2.0.4",
|
||||
"path-browserify": "^1.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/acorn": {
|
||||
"version": "8.11.3",
|
||||
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz",
|
||||
|
|
@ -1214,6 +1337,14 @@
|
|||
"node": ">=0.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/acorn-jsx": {
|
||||
"version": "5.3.2",
|
||||
"resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz",
|
||||
"integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==",
|
||||
"peerDependencies": {
|
||||
"acorn": "^6.0.0 || ^7.0.0 || ^8.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/ansi-align": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-3.0.1.tgz",
|
||||
|
|
@ -1325,6 +1456,14 @@
|
|||
"url": "https://github.com/sponsors/wooorm"
|
||||
}
|
||||
},
|
||||
"node_modules/astring": {
|
||||
"version": "1.8.6",
|
||||
"resolved": "https://registry.npmjs.org/astring/-/astring-1.8.6.tgz",
|
||||
"integrity": "sha512-ISvCdHdlTDlH5IpxQJIex7BWBywFWgjJSVdwst+/iQCoEYnyOaQ95+X1JGshuBjGp6nxKUy1jMgE3zPqN7fQdg==",
|
||||
"bin": {
|
||||
"astring": "bin/astring"
|
||||
}
|
||||
},
|
||||
"node_modules/astro": {
|
||||
"version": "4.4.1",
|
||||
"resolved": "https://registry.npmjs.org/astro/-/astro-4.4.1.tgz",
|
||||
|
|
@ -1758,6 +1897,15 @@
|
|||
"url": "https://github.com/sponsors/wooorm"
|
||||
}
|
||||
},
|
||||
"node_modules/character-reference-invalid": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/character-reference-invalid/-/character-reference-invalid-2.0.1.tgz",
|
||||
"integrity": "sha512-iBZ4F4wRbyORVsu0jPV7gXkOsGYjGHPmAyv+HiHG8gi5PtC9KI2j1+v8/tlibRvjoWX027ypmG/n0HtO5t7unw==",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/wooorm"
|
||||
}
|
||||
},
|
||||
"node_modules/chokidar": {
|
||||
"version": "3.5.3",
|
||||
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz",
|
||||
|
|
@ -1848,6 +1996,15 @@
|
|||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/collapse-white-space": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/collapse-white-space/-/collapse-white-space-2.1.0.tgz",
|
||||
"integrity": "sha512-loKTxY1zCOuG4j9f6EPnuyyYkf58RnhhWTvRoZEokgB+WbdXehfjFviyOVYkqzEWz1Q5kRiZdBYS5SwxbQYwzw==",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/wooorm"
|
||||
}
|
||||
},
|
||||
"node_modules/color": {
|
||||
"version": "4.2.3",
|
||||
"resolved": "https://registry.npmjs.org/color/-/color-4.2.3.tgz",
|
||||
|
|
@ -2189,6 +2346,69 @@
|
|||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/estree-util-attach-comments": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/estree-util-attach-comments/-/estree-util-attach-comments-3.0.0.tgz",
|
||||
"integrity": "sha512-cKUwm/HUcTDsYh/9FgnuFqpfquUbwIqwKM26BVCGDPVgvaCl/nDCCjUfiLlx6lsEZ3Z4RFxNbOQ60pkaEwFxGw==",
|
||||
"dependencies": {
|
||||
"@types/estree": "^1.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/unified"
|
||||
}
|
||||
},
|
||||
"node_modules/estree-util-build-jsx": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/estree-util-build-jsx/-/estree-util-build-jsx-3.0.1.tgz",
|
||||
"integrity": "sha512-8U5eiL6BTrPxp/CHbs2yMgP8ftMhR5ww1eIKoWRMlqvltHF8fZn5LRDvTKuxD3DUn+shRbLGqXemcP51oFCsGQ==",
|
||||
"dependencies": {
|
||||
"@types/estree-jsx": "^1.0.0",
|
||||
"devlop": "^1.0.0",
|
||||
"estree-util-is-identifier-name": "^3.0.0",
|
||||
"estree-walker": "^3.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/unified"
|
||||
}
|
||||
},
|
||||
"node_modules/estree-util-is-identifier-name": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/estree-util-is-identifier-name/-/estree-util-is-identifier-name-3.0.0.tgz",
|
||||
"integrity": "sha512-hFtqIDZTIUZ9BXLb8y4pYGyk6+wekIivNVTcmvk8NoOh+VeRn5y6cEHzbURrWbfp1fIqdVipilzj+lfaadNZmg==",
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/unified"
|
||||
}
|
||||
},
|
||||
"node_modules/estree-util-to-js": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/estree-util-to-js/-/estree-util-to-js-2.0.0.tgz",
|
||||
"integrity": "sha512-WDF+xj5rRWmD5tj6bIqRi6CkLIXbbNQUcxQHzGysQzvHmdYG2G7p/Tf0J0gpxGgkeMZNTIjT/AoSvC9Xehcgdg==",
|
||||
"dependencies": {
|
||||
"@types/estree-jsx": "^1.0.0",
|
||||
"astring": "^1.8.0",
|
||||
"source-map": "^0.7.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/unified"
|
||||
}
|
||||
},
|
||||
"node_modules/estree-util-visit": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/estree-util-visit/-/estree-util-visit-2.0.0.tgz",
|
||||
"integrity": "sha512-m5KgiH85xAhhW8Wta0vShLcUvOsh3LLPI2YVwcbio1l7E09NTLL1EyMZFM1OyWowoH0skScNbhOPl4kcBgzTww==",
|
||||
"dependencies": {
|
||||
"@types/estree-jsx": "^1.0.0",
|
||||
"@types/unist": "^3.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/unified"
|
||||
}
|
||||
},
|
||||
"node_modules/estree-walker": {
|
||||
"version": "3.0.3",
|
||||
"resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz",
|
||||
|
|
@ -2586,6 +2806,33 @@
|
|||
"url": "https://opencollective.com/unified"
|
||||
}
|
||||
},
|
||||
"node_modules/hast-util-to-estree": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/hast-util-to-estree/-/hast-util-to-estree-3.1.0.tgz",
|
||||
"integrity": "sha512-lfX5g6hqVh9kjS/B9E2gSkvHH4SZNiQFiqWS0x9fENzEl+8W12RqdRxX6d/Cwxi30tPQs3bIO+aolQJNp1bIyw==",
|
||||
"dependencies": {
|
||||
"@types/estree": "^1.0.0",
|
||||
"@types/estree-jsx": "^1.0.0",
|
||||
"@types/hast": "^3.0.0",
|
||||
"comma-separated-tokens": "^2.0.0",
|
||||
"devlop": "^1.0.0",
|
||||
"estree-util-attach-comments": "^3.0.0",
|
||||
"estree-util-is-identifier-name": "^3.0.0",
|
||||
"hast-util-whitespace": "^3.0.0",
|
||||
"mdast-util-mdx-expression": "^2.0.0",
|
||||
"mdast-util-mdx-jsx": "^3.0.0",
|
||||
"mdast-util-mdxjs-esm": "^2.0.0",
|
||||
"property-information": "^6.0.0",
|
||||
"space-separated-tokens": "^2.0.0",
|
||||
"style-to-object": "^0.4.0",
|
||||
"unist-util-position": "^5.0.0",
|
||||
"zwitch": "^2.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/unified"
|
||||
}
|
||||
},
|
||||
"node_modules/hast-util-to-html": {
|
||||
"version": "9.0.0",
|
||||
"resolved": "https://registry.npmjs.org/hast-util-to-html/-/hast-util-to-html-9.0.0.tgz",
|
||||
|
|
@ -2609,6 +2856,45 @@
|
|||
"url": "https://opencollective.com/unified"
|
||||
}
|
||||
},
|
||||
"node_modules/hast-util-to-jsx-runtime": {
|
||||
"version": "2.3.0",
|
||||
"resolved": "https://registry.npmjs.org/hast-util-to-jsx-runtime/-/hast-util-to-jsx-runtime-2.3.0.tgz",
|
||||
"integrity": "sha512-H/y0+IWPdsLLS738P8tDnrQ8Z+dj12zQQ6WC11TIM21C8WFVoIxcqWXf2H3hiTVZjF1AWqoimGwrTWecWrnmRQ==",
|
||||
"dependencies": {
|
||||
"@types/estree": "^1.0.0",
|
||||
"@types/hast": "^3.0.0",
|
||||
"@types/unist": "^3.0.0",
|
||||
"comma-separated-tokens": "^2.0.0",
|
||||
"devlop": "^1.0.0",
|
||||
"estree-util-is-identifier-name": "^3.0.0",
|
||||
"hast-util-whitespace": "^3.0.0",
|
||||
"mdast-util-mdx-expression": "^2.0.0",
|
||||
"mdast-util-mdx-jsx": "^3.0.0",
|
||||
"mdast-util-mdxjs-esm": "^2.0.0",
|
||||
"property-information": "^6.0.0",
|
||||
"space-separated-tokens": "^2.0.0",
|
||||
"style-to-object": "^1.0.0",
|
||||
"unist-util-position": "^5.0.0",
|
||||
"vfile-message": "^4.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/unified"
|
||||
}
|
||||
},
|
||||
"node_modules/hast-util-to-jsx-runtime/node_modules/inline-style-parser": {
|
||||
"version": "0.2.2",
|
||||
"resolved": "https://registry.npmjs.org/inline-style-parser/-/inline-style-parser-0.2.2.tgz",
|
||||
"integrity": "sha512-EcKzdTHVe8wFVOGEYXiW9WmJXPjqi1T+234YpJr98RiFYKHV3cdy1+3mkTE+KHTHxFFLH51SfaGOoUdW+v7ViQ=="
|
||||
},
|
||||
"node_modules/hast-util-to-jsx-runtime/node_modules/style-to-object": {
|
||||
"version": "1.0.5",
|
||||
"resolved": "https://registry.npmjs.org/style-to-object/-/style-to-object-1.0.5.tgz",
|
||||
"integrity": "sha512-rDRwHtoDD3UMMrmZ6BzOW0naTjMsVZLIjsGleSKS/0Oz+cgCfAPRspaqJuE8rDzpKha/nEvnM0IF4seEAZUTKQ==",
|
||||
"dependencies": {
|
||||
"inline-style-parser": "0.2.2"
|
||||
}
|
||||
},
|
||||
"node_modules/hast-util-to-parse5": {
|
||||
"version": "8.0.0",
|
||||
"resolved": "https://registry.npmjs.org/hast-util-to-parse5/-/hast-util-to-parse5-8.0.0.tgz",
|
||||
|
|
@ -2721,6 +3007,33 @@
|
|||
"integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==",
|
||||
"optional": true
|
||||
},
|
||||
"node_modules/inline-style-parser": {
|
||||
"version": "0.1.1",
|
||||
"resolved": "https://registry.npmjs.org/inline-style-parser/-/inline-style-parser-0.1.1.tgz",
|
||||
"integrity": "sha512-7NXolsK4CAS5+xvdj5OMMbI962hU/wvwoxk+LWR9Ek9bVtyuuYScDN6eS0rUm6TxApFpw7CX1o4uJzcd4AyD3Q=="
|
||||
},
|
||||
"node_modules/is-alphabetical": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/is-alphabetical/-/is-alphabetical-2.0.1.tgz",
|
||||
"integrity": "sha512-FWyyY60MeTNyeSRpkM2Iry0G9hpr7/9kD40mD/cGQEuilcZYS4okz8SN2Q6rLCJ8gbCt6fN+rC+6tMGS99LaxQ==",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/wooorm"
|
||||
}
|
||||
},
|
||||
"node_modules/is-alphanumerical": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/is-alphanumerical/-/is-alphanumerical-2.0.1.tgz",
|
||||
"integrity": "sha512-hmbYhX/9MUMF5uh7tOXyK/n0ZvWpad5caBA17GsC6vyuCqaWliRG5K1qS9inmUhEMaOBIW7/whAnSwveW/LtZw==",
|
||||
"dependencies": {
|
||||
"is-alphabetical": "^2.0.0",
|
||||
"is-decimal": "^2.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/wooorm"
|
||||
}
|
||||
},
|
||||
"node_modules/is-arrayish": {
|
||||
"version": "0.3.2",
|
||||
"resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz",
|
||||
|
|
@ -2771,6 +3084,15 @@
|
|||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/is-decimal": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/is-decimal/-/is-decimal-2.0.1.tgz",
|
||||
"integrity": "sha512-AAB9hiomQs5DXWcRB1rqsxGUstbRroFOPPVAomNk/3XHR5JyEZChOyTWe2oayKnsSsr/kcGqF+z6yuH6HHpN0A==",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/wooorm"
|
||||
}
|
||||
},
|
||||
"node_modules/is-docker": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/is-docker/-/is-docker-3.0.0.tgz",
|
||||
|
|
@ -2820,6 +3142,15 @@
|
|||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/is-hexadecimal": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/is-hexadecimal/-/is-hexadecimal-2.0.1.tgz",
|
||||
"integrity": "sha512-DgZQp241c8oO6cA1SbTEWiXeoxV42vlcJxgH+B3hi1AiqqKruZR3ZGF8In3fj4+/y/7rHvlOZLZtgJ/4ttYGZg==",
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/wooorm"
|
||||
}
|
||||
},
|
||||
"node_modules/is-inside-container": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/is-inside-container/-/is-inside-container-1.0.0.tgz",
|
||||
|
|
@ -2867,6 +3198,14 @@
|
|||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/is-reference": {
|
||||
"version": "3.0.2",
|
||||
"resolved": "https://registry.npmjs.org/is-reference/-/is-reference-3.0.2.tgz",
|
||||
"integrity": "sha512-v3rht/LgVcsdZa3O2Nqs+NMowLOxeOm7Ay9+/ARQ2F+qEoANRcqrjAZKGN0v8ymUetZGgkp26LTnGT7H0Qo9Pg==",
|
||||
"dependencies": {
|
||||
"@types/estree": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/is-stream": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz",
|
||||
|
|
@ -3105,6 +3444,17 @@
|
|||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/markdown-extensions": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/markdown-extensions/-/markdown-extensions-2.0.0.tgz",
|
||||
"integrity": "sha512-o5vL7aDWatOTX8LzaS1WMoaoxIiLRQJuIKKe2wAw6IeULDHaqbiqiggmx+pKvZDb1Sj+pE46Sn1T7lCqfFtg1Q==",
|
||||
"engines": {
|
||||
"node": ">=16"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/markdown-table": {
|
||||
"version": "3.0.3",
|
||||
"resolved": "https://registry.npmjs.org/markdown-table/-/markdown-table-3.0.3.tgz",
|
||||
|
|
@ -3272,6 +3622,80 @@
|
|||
"url": "https://opencollective.com/unified"
|
||||
}
|
||||
},
|
||||
"node_modules/mdast-util-mdx": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/mdast-util-mdx/-/mdast-util-mdx-3.0.0.tgz",
|
||||
"integrity": "sha512-JfbYLAW7XnYTTbUsmpu0kdBUVe+yKVJZBItEjwyYJiDJuZ9w4eeaqks4HQO+R7objWgS2ymV60GYpI14Ug554w==",
|
||||
"dependencies": {
|
||||
"mdast-util-from-markdown": "^2.0.0",
|
||||
"mdast-util-mdx-expression": "^2.0.0",
|
||||
"mdast-util-mdx-jsx": "^3.0.0",
|
||||
"mdast-util-mdxjs-esm": "^2.0.0",
|
||||
"mdast-util-to-markdown": "^2.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/unified"
|
||||
}
|
||||
},
|
||||
"node_modules/mdast-util-mdx-expression": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/mdast-util-mdx-expression/-/mdast-util-mdx-expression-2.0.0.tgz",
|
||||
"integrity": "sha512-fGCu8eWdKUKNu5mohVGkhBXCXGnOTLuFqOvGMvdikr+J1w7lDJgxThOKpwRWzzbyXAU2hhSwsmssOY4yTokluw==",
|
||||
"dependencies": {
|
||||
"@types/estree-jsx": "^1.0.0",
|
||||
"@types/hast": "^3.0.0",
|
||||
"@types/mdast": "^4.0.0",
|
||||
"devlop": "^1.0.0",
|
||||
"mdast-util-from-markdown": "^2.0.0",
|
||||
"mdast-util-to-markdown": "^2.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/unified"
|
||||
}
|
||||
},
|
||||
"node_modules/mdast-util-mdx-jsx": {
|
||||
"version": "3.1.1",
|
||||
"resolved": "https://registry.npmjs.org/mdast-util-mdx-jsx/-/mdast-util-mdx-jsx-3.1.1.tgz",
|
||||
"integrity": "sha512-Di63TQEHbiApe6CFp/qQXCORHMHnmW2JFdr5PYH57LuEIPjijRHicAmL5wQu+B0/Q4p0qJaEOE1EkhiwxiNmAQ==",
|
||||
"dependencies": {
|
||||
"@types/estree-jsx": "^1.0.0",
|
||||
"@types/hast": "^3.0.0",
|
||||
"@types/mdast": "^4.0.0",
|
||||
"@types/unist": "^3.0.0",
|
||||
"ccount": "^2.0.0",
|
||||
"devlop": "^1.1.0",
|
||||
"mdast-util-from-markdown": "^2.0.0",
|
||||
"mdast-util-to-markdown": "^2.0.0",
|
||||
"parse-entities": "^4.0.0",
|
||||
"stringify-entities": "^4.0.0",
|
||||
"unist-util-remove-position": "^5.0.0",
|
||||
"unist-util-stringify-position": "^4.0.0",
|
||||
"vfile-message": "^4.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/unified"
|
||||
}
|
||||
},
|
||||
"node_modules/mdast-util-mdxjs-esm": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/mdast-util-mdxjs-esm/-/mdast-util-mdxjs-esm-2.0.1.tgz",
|
||||
"integrity": "sha512-EcmOpxsZ96CvlP03NghtH1EsLtr0n9Tm4lPUJUBccV9RwUOneqSycg19n5HGzCf+10LozMRSObtVr3ee1WoHtg==",
|
||||
"dependencies": {
|
||||
"@types/estree-jsx": "^1.0.0",
|
||||
"@types/hast": "^3.0.0",
|
||||
"@types/mdast": "^4.0.0",
|
||||
"devlop": "^1.0.0",
|
||||
"mdast-util-from-markdown": "^2.0.0",
|
||||
"mdast-util-to-markdown": "^2.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/unified"
|
||||
}
|
||||
},
|
||||
"node_modules/mdast-util-phrasing": {
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/mdast-util-phrasing/-/mdast-util-phrasing-4.1.0.tgz",
|
||||
|
|
@ -3529,6 +3953,103 @@
|
|||
"url": "https://opencollective.com/unified"
|
||||
}
|
||||
},
|
||||
"node_modules/micromark-extension-mdx-expression": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/micromark-extension-mdx-expression/-/micromark-extension-mdx-expression-3.0.0.tgz",
|
||||
"integrity": "sha512-sI0nwhUDz97xyzqJAbHQhp5TfaxEvZZZ2JDqUo+7NvyIYG6BZ5CPPqj2ogUoPJlmXHBnyZUzISg9+oUmU6tUjQ==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "GitHub Sponsors",
|
||||
"url": "https://github.com/sponsors/unifiedjs"
|
||||
},
|
||||
{
|
||||
"type": "OpenCollective",
|
||||
"url": "https://opencollective.com/unified"
|
||||
}
|
||||
],
|
||||
"dependencies": {
|
||||
"@types/estree": "^1.0.0",
|
||||
"devlop": "^1.0.0",
|
||||
"micromark-factory-mdx-expression": "^2.0.0",
|
||||
"micromark-factory-space": "^2.0.0",
|
||||
"micromark-util-character": "^2.0.0",
|
||||
"micromark-util-events-to-acorn": "^2.0.0",
|
||||
"micromark-util-symbol": "^2.0.0",
|
||||
"micromark-util-types": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/micromark-extension-mdx-jsx": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/micromark-extension-mdx-jsx/-/micromark-extension-mdx-jsx-3.0.0.tgz",
|
||||
"integrity": "sha512-uvhhss8OGuzR4/N17L1JwvmJIpPhAd8oByMawEKx6NVdBCbesjH4t+vjEp3ZXft9DwvlKSD07fCeI44/N0Vf2w==",
|
||||
"dependencies": {
|
||||
"@types/acorn": "^4.0.0",
|
||||
"@types/estree": "^1.0.0",
|
||||
"devlop": "^1.0.0",
|
||||
"estree-util-is-identifier-name": "^3.0.0",
|
||||
"micromark-factory-mdx-expression": "^2.0.0",
|
||||
"micromark-factory-space": "^2.0.0",
|
||||
"micromark-util-character": "^2.0.0",
|
||||
"micromark-util-symbol": "^2.0.0",
|
||||
"micromark-util-types": "^2.0.0",
|
||||
"vfile-message": "^4.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/unified"
|
||||
}
|
||||
},
|
||||
"node_modules/micromark-extension-mdx-md": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/micromark-extension-mdx-md/-/micromark-extension-mdx-md-2.0.0.tgz",
|
||||
"integrity": "sha512-EpAiszsB3blw4Rpba7xTOUptcFeBFi+6PY8VnJ2hhimH+vCQDirWgsMpz7w1XcZE7LVrSAUGb9VJpG9ghlYvYQ==",
|
||||
"dependencies": {
|
||||
"micromark-util-types": "^2.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/unified"
|
||||
}
|
||||
},
|
||||
"node_modules/micromark-extension-mdxjs": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/micromark-extension-mdxjs/-/micromark-extension-mdxjs-3.0.0.tgz",
|
||||
"integrity": "sha512-A873fJfhnJ2siZyUrJ31l34Uqwy4xIFmvPY1oj+Ean5PHcPBYzEsvqvWGaWcfEIr11O5Dlw3p2y0tZWpKHDejQ==",
|
||||
"dependencies": {
|
||||
"acorn": "^8.0.0",
|
||||
"acorn-jsx": "^5.0.0",
|
||||
"micromark-extension-mdx-expression": "^3.0.0",
|
||||
"micromark-extension-mdx-jsx": "^3.0.0",
|
||||
"micromark-extension-mdx-md": "^2.0.0",
|
||||
"micromark-extension-mdxjs-esm": "^3.0.0",
|
||||
"micromark-util-combine-extensions": "^2.0.0",
|
||||
"micromark-util-types": "^2.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/unified"
|
||||
}
|
||||
},
|
||||
"node_modules/micromark-extension-mdxjs-esm": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/micromark-extension-mdxjs-esm/-/micromark-extension-mdxjs-esm-3.0.0.tgz",
|
||||
"integrity": "sha512-DJFl4ZqkErRpq/dAPyeWp15tGrcrrJho1hKK5uBS70BCtfrIFg81sqcTVu3Ta+KD1Tk5vAtBNElWxtAa+m8K9A==",
|
||||
"dependencies": {
|
||||
"@types/estree": "^1.0.0",
|
||||
"devlop": "^1.0.0",
|
||||
"micromark-core-commonmark": "^2.0.0",
|
||||
"micromark-util-character": "^2.0.0",
|
||||
"micromark-util-events-to-acorn": "^2.0.0",
|
||||
"micromark-util-symbol": "^2.0.0",
|
||||
"micromark-util-types": "^2.0.0",
|
||||
"unist-util-position-from-estree": "^2.0.0",
|
||||
"vfile-message": "^4.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/unified"
|
||||
}
|
||||
},
|
||||
"node_modules/micromark-factory-destination": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/micromark-factory-destination/-/micromark-factory-destination-2.0.0.tgz",
|
||||
|
|
@ -3570,6 +4091,31 @@
|
|||
"micromark-util-types": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/micromark-factory-mdx-expression": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/micromark-factory-mdx-expression/-/micromark-factory-mdx-expression-2.0.1.tgz",
|
||||
"integrity": "sha512-F0ccWIUHRLRrYp5TC9ZYXmZo+p2AM13ggbsW4T0b5CRKP8KHVRB8t4pwtBgTxtjRmwrK0Irwm7vs2JOZabHZfg==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "GitHub Sponsors",
|
||||
"url": "https://github.com/sponsors/unifiedjs"
|
||||
},
|
||||
{
|
||||
"type": "OpenCollective",
|
||||
"url": "https://opencollective.com/unified"
|
||||
}
|
||||
],
|
||||
"dependencies": {
|
||||
"@types/estree": "^1.0.0",
|
||||
"devlop": "^1.0.0",
|
||||
"micromark-util-character": "^2.0.0",
|
||||
"micromark-util-events-to-acorn": "^2.0.0",
|
||||
"micromark-util-symbol": "^2.0.0",
|
||||
"micromark-util-types": "^2.0.0",
|
||||
"unist-util-position-from-estree": "^2.0.0",
|
||||
"vfile-message": "^4.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/micromark-factory-space": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/micromark-factory-space/-/micromark-factory-space-2.0.0.tgz",
|
||||
|
|
@ -3761,6 +4307,31 @@
|
|||
}
|
||||
]
|
||||
},
|
||||
"node_modules/micromark-util-events-to-acorn": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/micromark-util-events-to-acorn/-/micromark-util-events-to-acorn-2.0.2.tgz",
|
||||
"integrity": "sha512-Fk+xmBrOv9QZnEDguL9OI9/NQQp6Hz4FuQ4YmCb/5V7+9eAh1s6AYSvL20kHkD67YIg7EpE54TiSlcsf3vyZgA==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "GitHub Sponsors",
|
||||
"url": "https://github.com/sponsors/unifiedjs"
|
||||
},
|
||||
{
|
||||
"type": "OpenCollective",
|
||||
"url": "https://opencollective.com/unified"
|
||||
}
|
||||
],
|
||||
"dependencies": {
|
||||
"@types/acorn": "^4.0.0",
|
||||
"@types/estree": "^1.0.0",
|
||||
"@types/unist": "^3.0.0",
|
||||
"devlop": "^1.0.0",
|
||||
"estree-util-visit": "^2.0.0",
|
||||
"micromark-util-symbol": "^2.0.0",
|
||||
"micromark-util-types": "^2.0.0",
|
||||
"vfile-message": "^4.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/micromark-util-html-tag-name": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/micromark-util-html-tag-name/-/micromark-util-html-tag-name-2.0.0.tgz",
|
||||
|
|
@ -3971,6 +4542,11 @@
|
|||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
|
||||
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
|
||||
},
|
||||
"node_modules/muggle-string": {
|
||||
"version": "0.4.1",
|
||||
"resolved": "https://registry.npmjs.org/muggle-string/-/muggle-string-0.4.1.tgz",
|
||||
"integrity": "sha512-VNTrAak/KhO2i8dqqnqnAHOa3cYBwXEZe9h+D5h/1ZqFSTEFHdM65lR7RoIqq3tBBYavsOXV84NoHXZ0AkPyqQ=="
|
||||
},
|
||||
"node_modules/mz": {
|
||||
"version": "2.7.0",
|
||||
"resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz",
|
||||
|
|
@ -4255,6 +4831,30 @@
|
|||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/parse-entities": {
|
||||
"version": "4.0.1",
|
||||
"resolved": "https://registry.npmjs.org/parse-entities/-/parse-entities-4.0.1.tgz",
|
||||
"integrity": "sha512-SWzvYcSJh4d/SGLIOQfZ/CoNv6BTlI6YEQ7Nj82oDVnRpwe/Z/F1EMx42x3JAOwGBlCjeCH0BRJQbQ/opHL17w==",
|
||||
"dependencies": {
|
||||
"@types/unist": "^2.0.0",
|
||||
"character-entities": "^2.0.0",
|
||||
"character-entities-legacy": "^3.0.0",
|
||||
"character-reference-invalid": "^2.0.0",
|
||||
"decode-named-character-reference": "^1.0.0",
|
||||
"is-alphanumerical": "^2.0.0",
|
||||
"is-decimal": "^2.0.0",
|
||||
"is-hexadecimal": "^2.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/wooorm"
|
||||
}
|
||||
},
|
||||
"node_modules/parse-entities/node_modules/@types/unist": {
|
||||
"version": "2.0.10",
|
||||
"resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.10.tgz",
|
||||
"integrity": "sha512-IfYcSBWE3hLpBg8+X2SEa8LVkJdJEkT2Ese2aaLs3ptGdVtABxndrMaxuFlQ1qdFf9Q5rDvDpxI3WwgvKFAsQA=="
|
||||
},
|
||||
"node_modules/parse-latin": {
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/parse-latin/-/parse-latin-5.0.1.tgz",
|
||||
|
|
@ -4280,6 +4880,11 @@
|
|||
"url": "https://github.com/inikulin/parse5?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/path-browserify": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-1.0.1.tgz",
|
||||
"integrity": "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g=="
|
||||
},
|
||||
"node_modules/path-exists": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
|
||||
|
|
@ -4329,6 +4934,16 @@
|
|||
"resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-6.2.1.tgz",
|
||||
"integrity": "sha512-JLyh7xT1kizaEvcaXOQwOc2/Yhw6KZOvPf1S8401UyLk86CU79LN3vl7ztXGm/pZ+YjoyAJ4rxmHwbkBXJX+yw=="
|
||||
},
|
||||
"node_modules/periscopic": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/periscopic/-/periscopic-3.1.0.tgz",
|
||||
"integrity": "sha512-vKiQ8RRtkl9P+r/+oefh25C3fhybptkHKCZSPlcXiJux2tJF55GnEj3BVn4A5gKfq9NWWXXrxkHBwVPUfH0opw==",
|
||||
"dependencies": {
|
||||
"@types/estree": "^1.0.0",
|
||||
"estree-walker": "^3.0.0",
|
||||
"is-reference": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/picocolors": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz",
|
||||
|
|
@ -4950,6 +5565,19 @@
|
|||
"url": "https://opencollective.com/unified"
|
||||
}
|
||||
},
|
||||
"node_modules/remark-mdx": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/remark-mdx/-/remark-mdx-3.0.1.tgz",
|
||||
"integrity": "sha512-3Pz3yPQ5Rht2pM5R+0J2MrGoBSrzf+tJG94N+t/ilfdh8YLyyKYtidAYwTveB20BoHAcwIopOUqhcmh2F7hGYA==",
|
||||
"dependencies": {
|
||||
"mdast-util-mdx": "^3.0.0",
|
||||
"micromark-extension-mdxjs": "^3.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/unified"
|
||||
}
|
||||
},
|
||||
"node_modules/remark-parse": {
|
||||
"version": "11.0.0",
|
||||
"resolved": "https://registry.npmjs.org/remark-parse/-/remark-parse-11.0.0.tgz",
|
||||
|
|
@ -5664,6 +6292,14 @@
|
|||
"resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz",
|
||||
"integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg=="
|
||||
},
|
||||
"node_modules/source-map": {
|
||||
"version": "0.7.4",
|
||||
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz",
|
||||
"integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==",
|
||||
"engines": {
|
||||
"node": ">= 8"
|
||||
}
|
||||
},
|
||||
"node_modules/source-map-js": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz",
|
||||
|
|
@ -5858,6 +6494,14 @@
|
|||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/style-to-object": {
|
||||
"version": "0.4.4",
|
||||
"resolved": "https://registry.npmjs.org/style-to-object/-/style-to-object-0.4.4.tgz",
|
||||
"integrity": "sha512-HYNoHZa2GorYNyqiCaBgsxvcJIn7OHq6inEga+E6Ke3m5JkoqpQbnFssk4jwe+K7AhGa2fcha4wSOf1Kn01dMg==",
|
||||
"dependencies": {
|
||||
"inline-style-parser": "0.1.1"
|
||||
}
|
||||
},
|
||||
"node_modules/sucrase": {
|
||||
"version": "3.35.0",
|
||||
"resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.35.0.tgz",
|
||||
|
|
@ -6160,6 +6804,31 @@
|
|||
"url": "https://opencollective.com/unified"
|
||||
}
|
||||
},
|
||||
"node_modules/unist-util-position-from-estree": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/unist-util-position-from-estree/-/unist-util-position-from-estree-2.0.0.tgz",
|
||||
"integrity": "sha512-KaFVRjoqLyF6YXCbVLNad/eS4+OfPQQn2yOd7zF/h5T/CSL2v8NpN6a5TPvtbXthAGw5nG+PuTtq+DdIZr+cRQ==",
|
||||
"dependencies": {
|
||||
"@types/unist": "^3.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/unified"
|
||||
}
|
||||
},
|
||||
"node_modules/unist-util-remove-position": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/unist-util-remove-position/-/unist-util-remove-position-5.0.0.tgz",
|
||||
"integrity": "sha512-Hp5Kh3wLxv0PHj9m2yZhhLt58KzPtEYKQQ4yxfYFEO7EvHwzyDYnduhHnY1mDxoqr7VUwVuHXk9RXKIiYS1N8Q==",
|
||||
"dependencies": {
|
||||
"@types/unist": "^3.0.0",
|
||||
"unist-util-visit": "^5.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/unified"
|
||||
}
|
||||
},
|
||||
"node_modules/unist-util-stringify-position": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-4.0.0.tgz",
|
||||
|
|
@ -6357,6 +7026,11 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"node_modules/vscode-languageserver-textdocument": {
|
||||
"version": "1.0.11",
|
||||
"resolved": "https://registry.npmjs.org/vscode-languageserver-textdocument/-/vscode-languageserver-textdocument-1.0.11.tgz",
|
||||
"integrity": "sha512-X+8T3GoiwTVlJbicx/sIAF+yuJAqz8VvwJyoMVhwEMoEKE/fkDmrqUgDMyBECcM2A2frVZIUj5HI/ErRXCfOeA=="
|
||||
},
|
||||
"node_modules/web-namespaces": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/web-namespaces/-/web-namespaces-2.0.1.tgz",
|
||||
|
|
|
|||
|
|
@ -3,14 +3,16 @@
|
|||
"type": "module",
|
||||
"version": "2.0.0",
|
||||
"scripts": {
|
||||
"dev": "astro dev",
|
||||
"dev": "astro dev --open",
|
||||
"start": "astro dev",
|
||||
"build": "astro build",
|
||||
"preview": "astro preview",
|
||||
"astro": "astro"
|
||||
},
|
||||
"dependencies": {
|
||||
"@astrojs/mdx": "^2.1.1",
|
||||
"@astrojs/tailwind": "^5.1.0",
|
||||
"@astrojs/ts-plugin": "^1.5.3",
|
||||
"@vercel/analytics": "^1.0.1",
|
||||
"astro": "^4.4.1",
|
||||
"tailwindcss": "^3.4.1"
|
||||
|
|
|
|||
BIN
public/images/blogs/coworking-category/coworking-category.webp
Normal file
|
After Width: | Height: | Size: 59 KiB |
BIN
public/images/bots/mohcitrus.webp
Normal file
|
After Width: | Height: | Size: 5.7 KiB |
BIN
public/images/credits/rythondev.webp
Normal file
|
After Width: | Height: | Size: 5.3 KiB |
BIN
public/images/groups/CEOgang.webp
Normal file
|
After Width: | Height: | Size: 5.5 KiB |
BIN
public/images/groups/YOUthversity.webp
Normal file
|
After Width: | Height: | Size: 3.1 KiB |
BIN
public/images/groups/coworkingcrew.webp
Normal file
|
After Width: | Height: | Size: 11 KiB |
BIN
public/images/groups/erudita.webp
Normal file
|
After Width: | Height: | Size: 1.9 KiB |
BIN
public/images/groups/selfdev.webp
Normal file
|
After Width: | Height: | Size: 2.9 KiB |
BIN
public/images/introduction/ellyskey.webp
Normal file
|
After Width: | Height: | Size: 14 KiB |
BIN
public/images/introduction/petition.webp
Normal file
|
After Width: | Height: | Size: 17 KiB |
BIN
public/images/introduction/rythondev.webp
Normal file
|
After Width: | Height: | Size: 13 KiB |
BIN
public/images/introduction/seijisoldier.webp
Normal file
|
After Width: | Height: | Size: 14 KiB |
BIN
public/images/moderation-and-trolls/donation-settings.webp
Normal file
|
After Width: | Height: | Size: 5.7 KiB |
BIN
public/images/moderation-and-trolls/donation-troll.webp
Normal file
|
After Width: | Height: | Size: 4.6 KiB |
BIN
public/images/music-and-audio/6klabs.webp
Normal file
|
After Width: | Height: | Size: 3 KiB |
BIN
public/images/music-and-audio/audio_settings.webp
Normal file
|
After Width: | Height: | Size: 12 KiB |
BIN
public/images/music-and-audio/pixelchat.webp
Normal file
|
After Width: | Height: | Size: 2.2 KiB |
BIN
public/images/widgets/mayuko-pomo.webp
Normal file
|
After Width: | Height: | Size: 2.4 KiB |
BIN
public/images/widgets/moh-minimal-timer.webp
Normal file
|
After Width: | Height: | Size: 1.5 KiB |
BIN
public/images/widgets/multitask.webp
Normal file
|
After Width: | Height: | Size: 7.1 KiB |
BIN
public/images/widgets/pomofocus.webp
Normal file
|
After Width: | Height: | Size: 3.5 KiB |
BIN
public/images/widgets/rythontaskbot.webp
Normal file
|
After Width: | Height: | Size: 4.9 KiB |
BIN
public/images/widgets/supersweetbot.webp
Normal file
|
After Width: | Height: | Size: 3.5 KiB |
47
src/components/BlogPostPreview.astro
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
---
|
||||
function timeAgo(date: Date) {
|
||||
const dateObject = new Date(date);
|
||||
const seconds = Math.floor(
|
||||
(new Date().getTime() - dateObject.getTime()) / 1000,
|
||||
);
|
||||
let interval = Math.floor(seconds / 31536000);
|
||||
|
||||
if (interval >= 1) {
|
||||
return interval + (interval === 1 ? " year ago" : " years ago");
|
||||
}
|
||||
interval = Math.floor(seconds / 2592000);
|
||||
if (interval >= 1) {
|
||||
return interval + (interval === 1 ? " month ago" : " months ago");
|
||||
}
|
||||
interval = Math.floor(seconds / 86400);
|
||||
if (interval >= 1) {
|
||||
return interval + (interval === 1 ? " day ago" : " days ago");
|
||||
}
|
||||
interval = Math.floor(seconds / 3600);
|
||||
if (interval >= 1) {
|
||||
return interval + (interval === 1 ? " hour ago" : " hours ago");
|
||||
}
|
||||
interval = Math.floor(seconds / 60);
|
||||
if (interval > 1) {
|
||||
return interval + (interval === 1 ? " minute ago" : " minutes ago");
|
||||
}
|
||||
return (
|
||||
Math.floor(seconds) + (seconds === 1 ? " second ago" : " seconds ago")
|
||||
);
|
||||
}
|
||||
|
||||
const { title, tagline, pubDate, url } = Astro.props;
|
||||
---
|
||||
|
||||
<a
|
||||
href={url}
|
||||
class="hover:no-underline hover:-translate-y-1 shadow-xl transition-all duration-300"
|
||||
>
|
||||
<div class="bg-[#303338] text-white
|
||||
px-5 py-3
|
||||
rounded-xl">
|
||||
<h1 class="text-2xl font-bold">{title}</h1>
|
||||
<p class="text-base">{tagline}</p>
|
||||
<p class="text-sm text-gray-400">{timeAgo(new Date(pubDate))}</p>
|
||||
</div>
|
||||
</a>
|
||||
|
|
@ -1,12 +0,0 @@
|
|||
---
|
||||
import { Prism } from "@astrojs/prism";
|
||||
const props = Astro.props;
|
||||
---
|
||||
|
||||
<!-- Code block, include copy button -->
|
||||
<pre
|
||||
class="language-js">
|
||||
<code class="language-js">
|
||||
<slot />
|
||||
</code>
|
||||
</pre>
|
||||
31
src/components/TableOfContent.astro
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
---
|
||||
type Heading = {
|
||||
depth: number;
|
||||
text: string;
|
||||
slug: string;
|
||||
};
|
||||
|
||||
const { headings } = Astro.props;
|
||||
---
|
||||
|
||||
<h3 class="text-lg font-bold mb-2 mt-0" transition:name="Table of Content">
|
||||
Table of Contents
|
||||
</h3>
|
||||
<div class="text-sm">
|
||||
{
|
||||
headings.map((heading: Heading, index: number) => {
|
||||
if (heading.depth === 1) return;
|
||||
const margin = `${heading.depth - 1.5}rem`;
|
||||
return (
|
||||
<div style={{ marginLeft: margin }} class="mb-2 pl-0">
|
||||
<a
|
||||
href={`#${heading.slug}`}
|
||||
class="no-target-blank text-white hover:no-underline hover:text-blue-400 transition-colors duration-150 line-clamp-1"
|
||||
>
|
||||
{heading.text.replace("🔗", "")}
|
||||
</a>
|
||||
</div>
|
||||
);
|
||||
})
|
||||
}
|
||||
</div>
|
||||
|
|
@ -1,10 +1,10 @@
|
|||
<div
|
||||
<!-- <div
|
||||
transition:persist
|
||||
transition:name="navbar"
|
||||
class="w-full fixed text-white bg-secondary z-50 text-lg py-3 font-['Inter'] border-b border-solid border-gray-800 h-[--header-height]"
|
||||
>
|
||||
<div
|
||||
class="mx-auto relative lg:px-8 max-w-7xl flex flex-row justify-between items-center gap-3"
|
||||
class="mx-auto relative px-3 lg:px-8 max-w-7xl flex flex-row justify-between items-center gap-3"
|
||||
>
|
||||
<div
|
||||
class="lg:flex-1 flex items-center text-xl select-none"
|
||||
|
|
@ -26,12 +26,12 @@
|
|||
class="no-target-blank hover:underline text-white"
|
||||
href="/guide/general-tips">Guide</a
|
||||
>
|
||||
<a class="no-target-blank hover:underline text-white" href="/blog"
|
||||
>Blog</a
|
||||
>
|
||||
<a class="no-target-blank hover:underline text-white" href="/groups"
|
||||
>Groups</a
|
||||
>
|
||||
<a class="no-target-blank hover:underline text-white" href="/blog"
|
||||
>Blog</a
|
||||
>
|
||||
<a
|
||||
class="no-target-blank hover:underline text-white"
|
||||
href="/credits">Credits</a
|
||||
|
|
@ -103,6 +103,127 @@
|
|||
});
|
||||
}
|
||||
|
||||
window.onload = function () {
|
||||
updateDarkModeIcon();
|
||||
};
|
||||
</script> -->
|
||||
<div
|
||||
transition:persist
|
||||
transition:name="navbar"
|
||||
class="w-full fixed text-white bg-secondary z-50 text-lg py-3 font-['Inter'] border-b border-solid border-gray-800 h-[--header-height]"
|
||||
>
|
||||
<div
|
||||
class="mx-auto relative px-3 lg:px-8 max-w-7xl flex flex-row justify-between items-center gap-3"
|
||||
>
|
||||
<!-- Hamburger Icon -->
|
||||
<div class="lg:hidden flex items-center fixed">
|
||||
<button id="menu-toggle" type="button" class="text-white">
|
||||
<svg
|
||||
viewBox="0 0 100 80"
|
||||
width="30"
|
||||
height="30"
|
||||
fill="currentColor"
|
||||
>
|
||||
<rect width="100" height="15" rx="6" ry="6"></rect>
|
||||
<rect y="30" width="100" height="15" rx="6" ry="6"></rect>
|
||||
<rect y="60" width="100" height="15" rx="6" ry="6"></rect>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
<!-- Logo -->
|
||||
<div
|
||||
class="flex-1 flex items-center text-xl select-none ml-10 lg:ml-0"
|
||||
transition:name="cowo-logo"
|
||||
>
|
||||
<a
|
||||
href="/"
|
||||
class="no-target-blank no-underline text-white hover:no-underline"
|
||||
>
|
||||
Coworking <span class="font-bold">Guide</span>
|
||||
</a>
|
||||
</div>
|
||||
<!-- Navigation Links -->
|
||||
<div class="hidden lg:flex items-center gap-10" id="navbar-links">
|
||||
<a
|
||||
class="no-target-blank hover:underline text-white"
|
||||
href="/get-started/introduction">Get started</a
|
||||
>
|
||||
<a
|
||||
class="no-target-blank hover:underline text-white"
|
||||
href="/guide/general-tips">Guide</a
|
||||
>
|
||||
<a class="no-target-blank hover:underline text-white" href="/groups"
|
||||
>Groups</a
|
||||
>
|
||||
<a class="no-target-blank hover:underline text-white" href="/blog"
|
||||
>Blog</a
|
||||
>
|
||||
<a
|
||||
class="no-target-blank hover:underline text-white"
|
||||
href="/credits">Credits</a
|
||||
>
|
||||
</div>
|
||||
<!-- Theme Toggle (COMING SOON) -->
|
||||
<div class="flex lg:flex-1 justify-end">
|
||||
<!-- <button id="theme-toggle" type="button" class=""></button> -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script defer>
|
||||
// JavaScript for toggling the menu
|
||||
document.addEventListener("DOMContentLoaded", function () {
|
||||
const menuToggle = document.querySelector("#menu-toggle");
|
||||
const navLinks = document.querySelector("#vertical-navbar");
|
||||
menuToggle.addEventListener("click", function () {
|
||||
navLinks.classList.toggle("hidden");
|
||||
});
|
||||
});
|
||||
|
||||
function updateDarkModeIcon() {
|
||||
const darkModeToggle = document.querySelector("#theme-toggle");
|
||||
const isDarkMode = localStorage.getItem("theme") === "dark";
|
||||
const moonSVG = `
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" class="w-6 h-6">
|
||||
<path fill-rule="evenodd" d="M9.528 1.718a.75.75 0 0 1 .162.819A8.97 8.97 0 0 0 9 6a9 9 0 0 0 9 9 8.97 8.97 0 0 0 3.463-.69.75.75 0 0 1 .981.98 10.503 10.503 0 0 1-9.694 6.46c-5.799 0-10.5-4.7-10.5-10.5 0-4.368 2.667-8.112 6.46-9.694a.75.75 0 0 1 .818.162Z" clip-rule="evenodd" />
|
||||
</svg>
|
||||
`;
|
||||
const sunSVG = `
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" class="w-6 h-6">
|
||||
<path d="M12 2.25a.75.75 0 0 1 .75.75v2.25a.75.75 0 0 1-1.5 0V3a.75.75 0 0 1 .75-.75ZM7.5 12a4.5 4.5 0 1 1 9 0 4.5 4.5 0 0 1-9 0ZM18.894 6.166a.75.75 0 0 0-1.06-1.06l-1.591 1.59a.75.75 0 1 0 1.06 1.061l1.591-1.59ZM21.75 12a.75.75 0 0 1-.75.75h-2.25a.75.75 0 0 1 0-1.5H21a.75.75 0 0 1 .75.75ZM17.834 18.894a.75.75 0 0 0 1.06-1.06l-1.59-1.591a.75.75 0 1 0-1.061 1.06l1.59 1.591ZM12 18a.75.75 0 0 1 .75.75V21a.75.75 0 0 1-1.5 0v-2.25A.75.75 0 0 1 12 18ZM7.758 17.303a.75.75 0 0 0-1.061-1.06l-1.591 1.59a.75.75 0 0 0 1.06 1.061l1.591-1.59ZM6 12a.75.75 0 0 1-.75.75H3a.75.75 0 0 1 0-1.5h2.25A.75.75 0 0 1 6 12ZM6.697 7.757a.75.75 0 0 0 1.06-1.06l-1.59-1.591a.75.75 0 0 0-1.061 1.06l1.59 1.591Z" />
|
||||
</svg>
|
||||
`;
|
||||
|
||||
if (darkModeToggle) {
|
||||
if (isDarkMode) {
|
||||
darkModeToggle.innerHTML = moonSVG;
|
||||
} else {
|
||||
darkModeToggle.innerHTML = sunSVG;
|
||||
}
|
||||
}
|
||||
}
|
||||
const darkModeToggle = document.querySelector("#theme-toggle");
|
||||
|
||||
if (!localStorage.getItem("theme")) {
|
||||
localStorage.setItem("theme", "dark");
|
||||
}
|
||||
|
||||
if (darkModeToggle) {
|
||||
darkModeToggle.addEventListener("click", () => {
|
||||
const isDarkMode = localStorage.getItem("theme") === "dark";
|
||||
|
||||
if (isDarkMode) {
|
||||
localStorage.setItem("theme", "light");
|
||||
document.documentElement.classList.remove("dark");
|
||||
} else {
|
||||
localStorage.setItem("theme", "dark");
|
||||
document.documentElement.classList.add("dark");
|
||||
}
|
||||
|
||||
updateDarkModeIcon();
|
||||
});
|
||||
}
|
||||
|
||||
window.onload = function () {
|
||||
updateDarkModeIcon();
|
||||
};
|
||||
|
|
|
|||
72
src/components/verticalNav.astro
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
---
|
||||
type Navigation = Record<
|
||||
string,
|
||||
{ title: string; url: string; order: number }[]
|
||||
>;
|
||||
|
||||
const navigation = Astro.props.navigation as Navigation;
|
||||
const currentUrl = Astro.request.url;
|
||||
|
||||
const isCurrentUrl = (url: string) => currentUrl.includes(url);
|
||||
---
|
||||
|
||||
<aside
|
||||
id="vertical-nav"
|
||||
class="hidden -translate-x-full lg:translate-x-0 overflow-y-auto lg:block lg:sticky py-8 lg:px-4 lg:-mx-4 lg:max-h-[calc(100vh-var(--header-height))] lg:top-[--header-height]"
|
||||
>
|
||||
<div class="relative">
|
||||
<nav class="flex flex-col">
|
||||
{
|
||||
Object.entries(navigation).map(([category, links]) => (
|
||||
<div class="mb-2">
|
||||
<a
|
||||
class="no-target-blank text-lg font-bold mb-1 mt-0 text-white"
|
||||
href={links[0].url}
|
||||
>
|
||||
{category}
|
||||
</a>
|
||||
<ul class="list-disc list-outside font-normal">
|
||||
{links.map((link) => (
|
||||
<li class="mb-1 pl-0">
|
||||
<a
|
||||
href={link.url}
|
||||
class={`no-target-blank hover:underline ${isCurrentUrl(link.url) ? "text-blue-400" : "text-white"}`}
|
||||
>
|
||||
{link.title}
|
||||
</a>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
))
|
||||
}
|
||||
<div class="mb-2">
|
||||
<a
|
||||
href="/groups"
|
||||
class={`no-target-blank hover:underline text-lg font-bold mt-0
|
||||
${isCurrentUrl("/groups") ? "text-blue-400" : "text-white"}`}
|
||||
>
|
||||
Groups
|
||||
</a>
|
||||
</div>
|
||||
<div class="mb-2">
|
||||
<a
|
||||
href="/blog"
|
||||
class={`no-target-blank hover:underline text-lg font-bold mt-0
|
||||
${isCurrentUrl("/blog") ? "text-blue-400" : "text-white"}`}
|
||||
>
|
||||
Blog
|
||||
</a>
|
||||
</div>
|
||||
<div class="mb-2">
|
||||
<a
|
||||
href="/credits"
|
||||
class={`no-target-blank hover:underline text-lg font-bold mt-0
|
||||
${isCurrentUrl("/credits") ? "text-blue-400" : "text-white"}`}
|
||||
>
|
||||
Credits
|
||||
</a>
|
||||
</div>
|
||||
</nav>
|
||||
</div>
|
||||
</aside>
|
||||
23
src/content/config.ts
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
// Import utilities from `astro:content`
|
||||
import { z, defineCollection } from "astro:content";
|
||||
// Define a `type` and `schema` for each collection
|
||||
const postsCollection = defineCollection({
|
||||
type: "content",
|
||||
schema: z.object({
|
||||
heading: z.string(),
|
||||
subheading: z.string(),
|
||||
pubDate: z.string(),
|
||||
author: z.string(),
|
||||
image: z
|
||||
.object({
|
||||
url: z.string(),
|
||||
alt: z.string(),
|
||||
})
|
||||
?.optional(),
|
||||
tags: z.array(z.string())?.optional(),
|
||||
}),
|
||||
});
|
||||
// Export a single `collections` object to register your collection(s)
|
||||
export const collections = {
|
||||
posts: postsCollection,
|
||||
};
|
||||
109
src/content/posts/1-coworking-category.md
Normal file
|
|
@ -0,0 +1,109 @@
|
|||
---
|
||||
heading: Unofficial Coworking Category, Yay or Nay?
|
||||
subheading: Recent unofficial coworking category has sparked an intense discussion amongst the community
|
||||
author: RythonDev
|
||||
slug: unofficial-coworking-category
|
||||
pubDate: 2024-03-10 15:13
|
||||
image: {
|
||||
url: "/images/blogs/coworking-category/coworking-category.webp",
|
||||
alt: "Coworking Category"
|
||||
}
|
||||
---
|
||||
|
||||
## How it started
|
||||
|
||||
On 27th February 2024, a "Coworking" category appeared on Twitch. However, this is not an official category from Twitch, rather a "small, distraction game" as listed in IGDB (Internet Game Database), the database Twitch uses to provide gaming categories.
|
||||
|
||||
As a result, a significant number of coworking and study streamers use this category as a way to improve their discoverability since it is less saturated compared to the "Just Chatting" category.
|
||||
|
||||
As of writing, the intention behind publishing the "Coworking" category still remains unclear.
|
||||
|
||||
---
|
||||
|
||||
## Productivity streamers started using it
|
||||
|
||||
The coworking & study community has been [petitioning for a Coworking and Study category](https://twitch.uservoice.com/forums/310210-discover/suggestions/46004791-coworking) since late 2022, stating that it would improve discoverability for productivity streamers.
|
||||
|
||||
Once this "Coworking" category came out, coworking and study streamers became aware of it and started using it as a makeshift category to improve discoverability of their streams. It also clarifies that it's a productivity stream rather than a regular Just Chatting stream (from a following feed, as an example).
|
||||
|
||||
While some of these streamers may be aware that it's a "game category", quite a number of them are not.
|
||||
|
||||
---
|
||||
|
||||
## Why many streamers decided against using it
|
||||
|
||||
Many experienced coworking streamers have shown disinterest with the new "Coworking" category because it is a game and has little viewers compared to Just Chatting. Since it has a much smaller audience compared to Just Chatting, it may lead to reduced chances of being discovered by potential viewers.
|
||||
|
||||
A member of the coworking community said:
|
||||
|
||||
> (Basically, because) I'm trying to hit partner, and if I use a non-Just Chatting category right now, I'd only be limiting my exposure to new viewers
|
||||
|
||||
The official Coworking Crew team has also made a statement regarding this topic:
|
||||
|
||||
> As a Coworking Crew Team, we believe it might affect individual streamers' discoverability and could give Twitch the wrong idea about our satisfaction with not having an officially endorsed category.
|
||||
|
||||
There are other discussions about the cons of using the "Coworking" category:
|
||||
|
||||
- Low chance of being in the "Reading, Studying and Coworking" collection on the front page
|
||||
- Subjected to be in violation of Twitch TOS about "miscategorizing" since you're not playing the game.
|
||||
- Causing a significant divide in algorithm from those productivity streamers using "Just Chatting" as their category
|
||||
- May reduce likelihood of Twitch actually implementing an official Coworking category, due to concerns of conflicts in the algorithm (Twitch may think: A lot of people are streaming "coworking", implementing a "coworking & study" category will just mess things up)
|
||||
|
||||
### But "I'm Only Sleeping" streamers are misusing the game category
|
||||
|
||||
The coworking community is more passionate and dedicated to have their own space on the platform, compared to "I'm Only Sleeping" streamers who don't bother about having an official "sleeping" category.
|
||||
|
||||
In the end, misusing the game category is still against Twitch's Terms of Service and doing so may lead to warnings, suspensions or a permanent strike on your channel.
|
||||
|
||||
---
|
||||
|
||||
## How does the new category affect the Twitch algorithm?
|
||||
|
||||
As mentioned several times, the "coworking" category is a game. This means that Twitch's algorithm will:
|
||||
|
||||
- Register streamers in that category as "playing a game"
|
||||
- Users who watch "Coworking" for a long period of time as avid gaming stream viewers
|
||||
|
||||
As a result, Twitch's recommendation algorithm may:
|
||||
- Recommend "Coworking" category streamers to avid gaming viewers
|
||||
- Recommend gaming streams to productivity viewers
|
||||
|
||||
Although Twitch's recommendation algorithm remain a mystery to the general public, companies that use data analytics tend to follow similar patterns.
|
||||
|
||||
---
|
||||
|
||||
## Pros and Cons
|
||||
|
||||
Here are the listed pros and cons of using the "Coworking" category, which may or may not include what has been elaborated before:
|
||||
|
||||
### Pros of using "Coworking" category:
|
||||
|
||||
1. Less competition than "Just Chatting".
|
||||
|
||||
2. More discoverability from people searching by the category.
|
||||
|
||||
3. Allow users to know when it's a productivity stream, rather than a regular Just Chatting stream (from a following feed, for example).
|
||||
|
||||
### Cons of using "Coworking" category:
|
||||
|
||||
1. Twitch thinks you're playing a game.
|
||||
|
||||
2. (Speculation) Users who watch the "Coworking" category may be misunderstood by the algorithm, leading to more game recommendations.
|
||||
|
||||
3. (Speculation) Streamers using the "Coworking" category may have a significant divide from those who are using the "Just Chatting" category by the Twitch algorithm (in terms of user recommendations).
|
||||
|
||||
4. You're less likely to be on the "Reading, Studying, and Coworking" list on the front page.
|
||||
|
||||
5. Subjected to be in violation of Twitch TOS about "miscategorizing" since you're not playing the game.
|
||||
|
||||
6. (Speculation) May reduce likelihood of Twitch actually implementing an official Coworking category, due to concerns of conflicts in the algorithm (Twitch may think: A lot of people are streaming "coworking", implementing a "coworking & study" category will just mess things up).
|
||||
|
||||
---
|
||||
|
||||
## Conclusion
|
||||
|
||||
The purpose of this post is not to persuade people to "pick a side", rather it is meant to inform and show the bigger picture of this "Coworking" category. Please do not pressure nor target any streamers regarding this topic, and don't forget to [VOTE for an official Coworking and Study category](https://twitch.uservoice.com/forums/310210-discover/suggestions/46004791-coworking).
|
||||
|
||||
---
|
||||
|
||||
by [RythonDev](https://twitch.tv/RythonDev)
|
||||
156
src/layouts/BlogPostLayout.astro
Normal file
|
|
@ -0,0 +1,156 @@
|
|||
---
|
||||
import Layout from "./Layout.astro";
|
||||
import TableOfContent from "../components/TableOfContent.astro";
|
||||
import VerticalNav from "../components/verticalNav.astro";
|
||||
|
||||
type Navigation = Record<
|
||||
string,
|
||||
{ title: string; url: string; order: number }[]
|
||||
>;
|
||||
|
||||
export function formatTitle(title: string): string {
|
||||
return title
|
||||
.split("-")
|
||||
.map((word) => word.charAt(0).toUpperCase() + word.slice(1))
|
||||
.join(" ");
|
||||
}
|
||||
|
||||
export async function setup() {
|
||||
// setup navigation
|
||||
const getStartedFiles = await Astro.glob("../pages/get-started/*.md");
|
||||
const guideFiles = await Astro.glob("../pages/guide/*.md");
|
||||
const markdownFiles = [...getStartedFiles, ...guideFiles];
|
||||
const navigation: Navigation = {};
|
||||
|
||||
for (const file of markdownFiles) {
|
||||
const filePath = file.url;
|
||||
const [_, category] = filePath!.split("/");
|
||||
const formattedCategory = formatTitle(category);
|
||||
const formattedTitle = file.frontmatter.title;
|
||||
const order = file.frontmatter.order ?? 0;
|
||||
|
||||
if (!navigation[formattedCategory]) {
|
||||
navigation[formattedCategory] = [];
|
||||
}
|
||||
|
||||
navigation[formattedCategory].push({
|
||||
title: formattedTitle,
|
||||
url: filePath || "",
|
||||
order,
|
||||
});
|
||||
}
|
||||
|
||||
// sort by "order"
|
||||
const sortedNavigation: Navigation = {};
|
||||
Object.keys(navigation)
|
||||
.sort()
|
||||
.forEach((key) => {
|
||||
sortedNavigation[key] = navigation[key].sort(
|
||||
(a, b) => a.order - b.order,
|
||||
);
|
||||
});
|
||||
|
||||
return {
|
||||
navigation: sortedNavigation,
|
||||
};
|
||||
}
|
||||
const { frontmatter, headings } = Astro.props;
|
||||
const { navigation } = await setup();
|
||||
---
|
||||
|
||||
<Layout title={frontmatter.heading} description={frontmatter.subheading}>
|
||||
<div class="pt-14 mx-auto px-4 sm:px-6 max-w-7xl">
|
||||
<div class="flex flex-col lg:grid lg:grid-cols-10">
|
||||
<!-- vertical navbar -->
|
||||
<div class="lg:col-span-2" transition:name="vertical-navbar">
|
||||
<VerticalNav navigation={navigation} />
|
||||
</div>
|
||||
<div class="lg:col-span-8">
|
||||
<div class="flex flex-col lg:grid lg:grid-cols-10">
|
||||
<div class="col-span-8 pr-10 pb-20 pt-8">
|
||||
<slot />
|
||||
</div>
|
||||
<div
|
||||
class="col-span-2 pt-8 lg:block lg:sticky lg:px-4 lg:-mx-4 lg:max-h-[calc(100vh-var(--header-height))] lg:top-[--header-height]"
|
||||
>
|
||||
<!-- TOC -->
|
||||
<TableOfContent headings={headings} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style is:global>
|
||||
h1 {
|
||||
@apply text-4xl font-bold;
|
||||
}
|
||||
|
||||
h2 {
|
||||
@apply mt-5 scroll-mt-[calc(20px+var(--header-height))] text-3xl font-bold;
|
||||
}
|
||||
|
||||
h3 {
|
||||
@apply mt-5 scroll-mt-[calc(17px+var(--header-height))] text-2xl font-bold;
|
||||
}
|
||||
|
||||
h4 {
|
||||
@apply mt-5 scroll-mt-[calc(14px+var(--header-height))] text-xl font-bold;
|
||||
}
|
||||
|
||||
p {
|
||||
@apply mb-2 mt-2 font-[system-ui] leading-6;
|
||||
}
|
||||
|
||||
hr {
|
||||
@apply my-10 border-gray-500;
|
||||
}
|
||||
|
||||
ul {
|
||||
@apply list-outside list-disc leading-7;
|
||||
}
|
||||
|
||||
blockquote {
|
||||
@apply my-4 border-l-4 border-gray-500 pl-4;
|
||||
}
|
||||
|
||||
a {
|
||||
@apply inline-block text-blue-400 hover:underline;
|
||||
}
|
||||
|
||||
ul ul {
|
||||
@apply mb-2 ml-5 list-[circle];
|
||||
}
|
||||
|
||||
ul li {
|
||||
@apply mb-1 ml-5;
|
||||
}
|
||||
|
||||
ol {
|
||||
@apply list-outside list-decimal leading-7;
|
||||
}
|
||||
|
||||
ol li {
|
||||
@apply mb-1 ml-5;
|
||||
}
|
||||
|
||||
span.code-highlight {
|
||||
@apply rounded-md bg-[#323232] px-1 py-1 font-["Lucida_Console",monospace,courier-new] text-sm;
|
||||
}
|
||||
|
||||
code {
|
||||
@apply rounded-md bg-[#323232] px-3 py-3;
|
||||
}
|
||||
|
||||
/* img {
|
||||
@apply h-[100px] max-w-full;
|
||||
} */
|
||||
</style>
|
||||
|
||||
<script is:inline>
|
||||
// make all <a> attributes have target="_blank" except for Table of Contents
|
||||
document.querySelectorAll("a:not(.no-target-blank)").forEach((el) => {
|
||||
el.setAttribute("target", "_blank");
|
||||
});
|
||||
</script>
|
||||
</Layout>
|
||||
135
src/layouts/BlogsLayout.astro
Normal file
|
|
@ -0,0 +1,135 @@
|
|||
---
|
||||
import Layout from "./Layout.astro";
|
||||
import VerticalNav from "../components/verticalNav.astro";
|
||||
|
||||
type Navigation = Record<
|
||||
string,
|
||||
{ title: string; url: string; order: number }[]
|
||||
>;
|
||||
|
||||
export function formatTitle(title: string): string {
|
||||
return title
|
||||
.split("-")
|
||||
.map((word) => word.charAt(0).toUpperCase() + word.slice(1))
|
||||
.join(" ");
|
||||
}
|
||||
|
||||
export async function setup() {
|
||||
// setup navigation
|
||||
const getStartedFiles = await Astro.glob("../pages/get-started/*.md");
|
||||
const guideFiles = await Astro.glob("../pages/guide/*.md");
|
||||
const markdownFiles = [...getStartedFiles, ...guideFiles];
|
||||
const navigation: Navigation = {};
|
||||
|
||||
for (const file of markdownFiles) {
|
||||
const filePath = file.url;
|
||||
const [_, category] = filePath!.split("/");
|
||||
const formattedCategory = formatTitle(category);
|
||||
const formattedTitle = file.frontmatter.title;
|
||||
const order = file.frontmatter.order ?? 0;
|
||||
|
||||
if (!navigation[formattedCategory]) {
|
||||
navigation[formattedCategory] = [];
|
||||
}
|
||||
|
||||
navigation[formattedCategory].push({
|
||||
title: formattedTitle,
|
||||
url: filePath || "",
|
||||
order,
|
||||
});
|
||||
}
|
||||
|
||||
// sort by "order"
|
||||
const sortedNavigation: Navigation = {};
|
||||
Object.keys(navigation)
|
||||
.sort()
|
||||
.forEach((key) => {
|
||||
sortedNavigation[key] = navigation[key].sort(
|
||||
(a, b) => a.order - b.order,
|
||||
);
|
||||
});
|
||||
|
||||
return {
|
||||
navigation: sortedNavigation,
|
||||
};
|
||||
}
|
||||
const { navigation } = await setup();
|
||||
---
|
||||
|
||||
<Layout title={Astro.props.title} description={Astro.props.description}>
|
||||
<div class="pt-14 mx-auto px-4 sm:px-6 max-w-7xl">
|
||||
<div class="flex flex-col lg:grid lg:grid-cols-10">
|
||||
<!-- vertical navbar -->
|
||||
<div class="lg:col-span-2" transition:name="vertical-navbar">
|
||||
<VerticalNav navigation={navigation} />
|
||||
</div>
|
||||
<div class="lg:col-span-8 pt-8">
|
||||
<!-- <div class="flex flex-col lg:grid lg:grid-cols-10">
|
||||
<div class="col-span-8 pr-10 pb-10 pt-8">
|
||||
<slot />
|
||||
</div>
|
||||
<div
|
||||
class="col-span-2 pt-8 lg:block lg:sticky lg:px-4 lg:-mx-4 lg:max-h-[calc(100vh-var(--header-height))] lg:top-[--header-height]"
|
||||
>
|
||||
<TableOfContent headings={headings} />
|
||||
</div>
|
||||
</div> -->
|
||||
<slot />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style is:global>
|
||||
h1 {
|
||||
@apply text-4xl font-bold;
|
||||
}
|
||||
|
||||
h2 {
|
||||
@apply mt-5 scroll-mt-[calc(20px+var(--header-height))] text-3xl font-bold;
|
||||
}
|
||||
|
||||
h3 {
|
||||
@apply mt-5 scroll-mt-[calc(17px+var(--header-height))] text-2xl font-bold;
|
||||
}
|
||||
|
||||
h4 {
|
||||
@apply mt-5 scroll-mt-[calc(14px+var(--header-height))] text-xl font-bold;
|
||||
}
|
||||
|
||||
p {
|
||||
@apply mb-2 mt-2 font-[system-ui] leading-6;
|
||||
}
|
||||
|
||||
hr {
|
||||
@apply my-10 border-gray-500;
|
||||
}
|
||||
|
||||
ul {
|
||||
@apply list-outside list-disc leading-7;
|
||||
}
|
||||
|
||||
blockquote {
|
||||
@apply my-4 border-l-4 border-gray-500 pl-4;
|
||||
}
|
||||
|
||||
ul ul {
|
||||
@apply mb-2 ml-5 list-[circle];
|
||||
}
|
||||
|
||||
ul li {
|
||||
@apply mb-1 ml-5;
|
||||
}
|
||||
|
||||
span.code-highlight {
|
||||
@apply rounded-md bg-[#323232] px-1 py-1 font-["Lucida_Console",monospace,courier-new] text-sm;
|
||||
}
|
||||
|
||||
code {
|
||||
@apply rounded-md bg-[#323232] px-3 py-3;
|
||||
}
|
||||
|
||||
/* img {
|
||||
@apply h-[100px] max-w-full;
|
||||
} */
|
||||
</style>
|
||||
</Layout>
|
||||
|
|
@ -1,12 +1,12 @@
|
|||
---
|
||||
import Layout from "./Layout.astro";
|
||||
import TableOfContent from "../components/TableOfContent.astro";
|
||||
import VerticalNav from "../components/verticalNav.astro";
|
||||
|
||||
type Navigation = Record<string, { title: string; url: string }[]>;
|
||||
type Heading = {
|
||||
depth: number;
|
||||
text: string;
|
||||
slug: string;
|
||||
};
|
||||
type Navigation = Record<
|
||||
string,
|
||||
{ title: string; url: string; order: number }[]
|
||||
>;
|
||||
|
||||
export function formatTitle(title: string): string {
|
||||
return title
|
||||
|
|
@ -17,7 +17,9 @@ export function formatTitle(title: string): string {
|
|||
|
||||
export async function setup() {
|
||||
// setup navigation
|
||||
const markdownFiles = await Astro.glob("../pages/**/*.md");
|
||||
const getStartedFiles = await Astro.glob("../pages/get-started/*.md");
|
||||
const guideFiles = await Astro.glob("../pages/guide/*.md");
|
||||
const markdownFiles = [...getStartedFiles, ...guideFiles];
|
||||
const navigation: Navigation = {};
|
||||
|
||||
for (const file of markdownFiles) {
|
||||
|
|
@ -25,6 +27,7 @@ export async function setup() {
|
|||
const [_, category] = filePath!.split("/");
|
||||
const formattedCategory = formatTitle(category);
|
||||
const formattedTitle = file.frontmatter.title;
|
||||
const order = file.frontmatter.order ?? 0;
|
||||
|
||||
if (!navigation[formattedCategory]) {
|
||||
navigation[formattedCategory] = [];
|
||||
|
|
@ -33,69 +36,34 @@ export async function setup() {
|
|||
navigation[formattedCategory].push({
|
||||
title: formattedTitle,
|
||||
url: filePath || "",
|
||||
order,
|
||||
});
|
||||
}
|
||||
|
||||
// sort, make Get Started first, Guide second
|
||||
// sort by "order"
|
||||
const sortedNavigation: Navigation = {};
|
||||
Object.keys(navigation)
|
||||
.sort((a, b) => {
|
||||
if (a === "Get Started") return -1;
|
||||
if (b === "Get Started") return 1;
|
||||
if (a === "Guide") return -1;
|
||||
if (b === "Guide") return 1;
|
||||
return 0;
|
||||
})
|
||||
.sort()
|
||||
.forEach((key) => {
|
||||
sortedNavigation[key] = navigation[key];
|
||||
sortedNavigation[key] = navigation[key].sort(
|
||||
(a, b) => a.order - b.order,
|
||||
);
|
||||
});
|
||||
|
||||
return {
|
||||
navigation: sortedNavigation,
|
||||
markdownFiles,
|
||||
};
|
||||
}
|
||||
|
||||
const { frontmatter, headings } = Astro.props;
|
||||
const { navigation } = await setup();
|
||||
---
|
||||
|
||||
<Layout title={frontmatter.title} description={frontmatter.description}>
|
||||
<div class="pt-20 mx-auto px-4 sm:px-6 max-w-7xl">
|
||||
<div class="pt-14 mx-auto px-4 sm:px-6 max-w-7xl">
|
||||
<div class="flex flex-col lg:grid lg:grid-cols-10">
|
||||
<!-- vertical navbar -->
|
||||
<div class="lg:col-span-2" transition:name="vertical-navbar">
|
||||
<aside
|
||||
class="hidden overflow-y-auto lg:block lg:sticky py-8 lg:px-4 lg:-mx-4 lg:max-h-[calc(100vh-var(--header-height))] lg:top-[--header-height]"
|
||||
>
|
||||
<div class="relative">
|
||||
<nav class="flex flex-col">
|
||||
{
|
||||
Object.entries(navigation).map(
|
||||
([category, links]) => (
|
||||
<div class="mb-4">
|
||||
<h3 class="text-lg font-bold mb-1 mt-0">
|
||||
{category}
|
||||
</h3>
|
||||
<ul class="list-disc list-inside">
|
||||
{links.map((link) => (
|
||||
<li class="mb-2 pl-0">
|
||||
<a
|
||||
href={link.url}
|
||||
class="no-target-blank text-white hover:underline"
|
||||
>
|
||||
{link.title}
|
||||
</a>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
),
|
||||
)
|
||||
}
|
||||
</nav>
|
||||
</div>
|
||||
</aside>
|
||||
<VerticalNav navigation={navigation} />
|
||||
</div>
|
||||
<div class="lg:col-span-8">
|
||||
<div class="flex flex-col lg:grid lg:grid-cols-10">
|
||||
|
|
@ -103,38 +71,10 @@ const { navigation } = await setup();
|
|||
<slot />
|
||||
</div>
|
||||
<div
|
||||
class="col-span-2 pt-8 lg:block lg:sticky lg:px-4 lg:-mx-4 lg:max-h-[calc(100vh-var(--header-height))] lg:top-[--header-height]"
|
||||
class="hidden col-span-2 pt-8 lg:block lg:sticky lg:px-4 lg:-mx-4 lg:max-h-[calc(100vh-var(--header-height))] lg:top-[--header-height]"
|
||||
>
|
||||
<!-- TOC -->
|
||||
<h3
|
||||
class="text-lg font-bold mb-2 mt-0"
|
||||
transition:name="Table of Content"
|
||||
>
|
||||
Table of Contents
|
||||
</h3>
|
||||
<ul class="list-outside list-disc text-sm">
|
||||
{
|
||||
headings.map(
|
||||
(heading: Heading, index: number) => {
|
||||
if (heading.depth === 1) return;
|
||||
const margin = `${(heading.depth - 1) * 2}rem`;
|
||||
return (
|
||||
<li
|
||||
style={{ marginLeft: margin }}
|
||||
class="mb-2 pl-0"
|
||||
>
|
||||
<a
|
||||
href={`#${heading.slug}`}
|
||||
class="no-target-blank text-white hover:underline"
|
||||
>
|
||||
{heading.text}
|
||||
</a>
|
||||
</li>
|
||||
);
|
||||
},
|
||||
)
|
||||
}
|
||||
</ul>
|
||||
<TableOfContent headings={headings} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -143,15 +83,19 @@ const { navigation } = await setup();
|
|||
|
||||
<style is:global>
|
||||
h1 {
|
||||
@apply text-3xl font-bold;
|
||||
@apply text-4xl font-bold;
|
||||
}
|
||||
|
||||
h2 {
|
||||
@apply mt-5 scroll-mt-[calc(20px+var(--header-height))] text-2xl font-bold;
|
||||
@apply mt-5 scroll-mt-[calc(20px+var(--header-height))] text-3xl font-bold;
|
||||
}
|
||||
|
||||
h3 {
|
||||
@apply mt-5 scroll-mt-[calc(17px+var(--header-height))] text-xl font-bold;
|
||||
@apply mt-5 scroll-mt-[calc(17px+var(--header-height))] text-2xl font-bold;
|
||||
}
|
||||
|
||||
h4 {
|
||||
@apply mt-5 scroll-mt-[calc(14px+var(--header-height))] text-xl font-bold;
|
||||
}
|
||||
|
||||
p {
|
||||
|
|
@ -171,7 +115,7 @@ const { navigation } = await setup();
|
|||
}
|
||||
|
||||
a {
|
||||
@apply text-blue-400 hover:underline;
|
||||
@apply inline-block text-blue-400 hover:underline;
|
||||
}
|
||||
|
||||
ul ul {
|
||||
|
|
@ -179,12 +123,20 @@ const { navigation } = await setup();
|
|||
}
|
||||
|
||||
ul li {
|
||||
@apply mb-1;
|
||||
@apply mb-1 ml-5;
|
||||
}
|
||||
|
||||
span.code-highlight {
|
||||
@apply rounded-md bg-[#323232] px-1 py-1 font-["Lucida_Console",monospace,courier-new] text-sm;
|
||||
}
|
||||
|
||||
code {
|
||||
@apply mb-4 rounded-lg bg-[#303030] p-4;
|
||||
@apply rounded-md bg-[#323232] px-3 py-3;
|
||||
}
|
||||
|
||||
/* img {
|
||||
@apply h-[100px] max-w-full;
|
||||
} */
|
||||
</style>
|
||||
|
||||
<script is:inline>
|
||||
|
|
|
|||
26
src/pages/blog/index.astro
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
---
|
||||
import BlogsLayout from "../../layouts/BlogsLayout.astro";
|
||||
import BlogPost from "../../components/BlogPostPreview.astro";
|
||||
import { getCollection } from "astro:content";
|
||||
|
||||
const allPosts = await getCollection("posts");
|
||||
---
|
||||
|
||||
<BlogsLayout
|
||||
title="Blog Posts"
|
||||
description="A collection of blog posts, related to coworking, studying, streaming and many more!"
|
||||
>
|
||||
<h1 class="mb-5">Blog Posts</h1>
|
||||
<div>
|
||||
{
|
||||
allPosts.map((post) => (
|
||||
<BlogPost
|
||||
url={`blog/posts/${post.slug}/`}
|
||||
title={post.data.heading}
|
||||
tagline={post.data.subheading}
|
||||
pubDate={post.data.pubDate}
|
||||
/>
|
||||
))
|
||||
}
|
||||
</div>
|
||||
</BlogsLayout>
|
||||
70
src/pages/blog/posts/[...slug].astro
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
---
|
||||
import { getCollection } from "astro:content";
|
||||
import BlogPostLayout from "../../../layouts/BlogPostLayout.astro";
|
||||
import { Image } from "astro:assets";
|
||||
|
||||
function timeAgo(date: Date) {
|
||||
const dateObject = new Date(date);
|
||||
const seconds = Math.floor(
|
||||
(new Date().getTime() - dateObject.getTime()) / 1000,
|
||||
);
|
||||
let interval = Math.floor(seconds / 31536000);
|
||||
|
||||
if (interval >= 1) {
|
||||
return interval + (interval === 1 ? " year ago" : " years ago");
|
||||
}
|
||||
interval = Math.floor(seconds / 2592000);
|
||||
if (interval >= 1) {
|
||||
return interval + (interval === 1 ? " month ago" : " months ago");
|
||||
}
|
||||
interval = Math.floor(seconds / 86400);
|
||||
if (interval >= 1) {
|
||||
return interval + (interval === 1 ? " day ago" : " days ago");
|
||||
}
|
||||
interval = Math.floor(seconds / 3600);
|
||||
if (interval >= 1) {
|
||||
return interval + (interval === 1 ? " hour ago" : " hours ago");
|
||||
}
|
||||
interval = Math.floor(seconds / 60);
|
||||
if (interval > 1) {
|
||||
return interval + (interval === 1 ? " minute ago" : " minutes ago");
|
||||
}
|
||||
return (
|
||||
Math.floor(seconds) + (seconds === 1 ? " second ago" : " seconds ago")
|
||||
);
|
||||
}
|
||||
|
||||
export async function getStaticPaths() {
|
||||
const blogEntries = await getCollection("posts");
|
||||
return blogEntries.map((entry) => ({
|
||||
params: { slug: entry.slug },
|
||||
props: { entry },
|
||||
}));
|
||||
}
|
||||
|
||||
const { entry } = Astro.props;
|
||||
const { Content, headings } = await entry.render();
|
||||
---
|
||||
|
||||
<BlogPostLayout frontmatter={entry.data} headings={headings}>
|
||||
<h1>{entry.data.heading}</h1>
|
||||
<h2 class="font-normal text-lg">{entry.data.subheading}</h2>
|
||||
<p class="text-base font-normal text-gray-400">by {entry.data.author}</p>
|
||||
<p class="text-base font-normal text-gray-400">
|
||||
Published {timeAgo(new Date(entry.data.pubDate))}
|
||||
</p>
|
||||
|
||||
{
|
||||
entry.data.image && (
|
||||
<Image
|
||||
src={entry.data.image.url}
|
||||
alt={entry.data.image.alt}
|
||||
class="mt-5 mb-5"
|
||||
width="700"
|
||||
height="400"
|
||||
loading="eager"
|
||||
/>
|
||||
)
|
||||
}
|
||||
<Content />
|
||||
</BlogPostLayout>
|
||||
3
src/pages/blog/posts/index.astro
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
---
|
||||
Astro.redirect("../../");
|
||||
---
|
||||
21
src/pages/credits/index.md
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
---
|
||||
title: Credits
|
||||
layout: "../../layouts/GuideLayout.astro"
|
||||
description: Credits to the people behind this website!
|
||||
---
|
||||
|
||||
# Credits
|
||||
|
||||
Credits to the wonderful team of people behind this guide!
|
||||
|
||||
---
|
||||
|
||||
<img src="/images/credits/rythondev.webp" alt="RythonDev" class="rounded-lg" width="300">
|
||||
|
||||
## RythonDev
|
||||
|
||||
Main developer of the project
|
||||
|
||||
- [Twitch](https://twitch.tv/RythonDev)
|
||||
- [YouTube](https://youtube.com/@RythonDev)
|
||||
- [Website](https://rython.dev/)
|
||||
|
|
@ -2,6 +2,7 @@
|
|||
title: Introduction
|
||||
layout: "../../layouts/GuideLayout.astro"
|
||||
description: Introduction to coworking streams!
|
||||
order: 0
|
||||
---
|
||||
|
||||
# Introduction
|
||||
|
|
@ -12,7 +13,101 @@ A brief introduction to coworking streams! Let's keep each other accountable ^^
|
|||
|
||||
## What are coworking streams?
|
||||
|
||||

|
||||
|
||||
Image source: [RythonDev (Twitch)](https://twitch.tv/RythonDev)
|
||||
|
||||
> Coworking (or study) streaming is an opportunity to share a virtual, productive, space with others and to connect based on interests and studies - in some ways replicating the in-person office, library, or cafe. Often, study streaming follows a pomodoro counter so that streamers can focus on working for a set amount of time and then converse with chat during another set amount of time for break.
|
||||
|
||||
Many viewers like to watch coworking streams because it provides motivation and accountability, which is especially hard if you're trying to focus at home. In the light of Covid, where working from home is becoming more common, it can nice to find an environment with like-minded people. Plus, the sense of community attracts many people - often coworking streams are very welcoming and supportive!
|
||||
|
||||
---
|
||||
|
||||
## What is a "pomodoro"?
|
||||
|
||||
<img src="/images/introduction/ellyskey.webp" alt="Ellyskey" loading="lazy" />
|
||||
|
||||
Image source: [Ellyskey (Twitch)](https://twitch.tv/Ellyskey)
|
||||
|
||||
The Pomodoro Technique is a time management method where you work in focused intervals called pomodoros separated by short breaks. This helps you stay concentrated, avoid burnout, and tackle big tasks by breaking them into manageable chunks.
|
||||
|
||||
Coworking streamers tend to use 50 minutes of work and 10 minutes of break (50/10) for their streams for optimal balance of being able to get work done and be able to chat with viewers.
|
||||
|
||||
---
|
||||
|
||||
## How do people enjoy these streams?
|
||||
|
||||
<img src="/images/introduction/seijisoldier.webp" alt="SeijiSoldier" loading="lazy" />
|
||||
|
||||
Image source: [SeijiSoldier (Twitch)](https://twitch.tv/SeijiSoldier)
|
||||
|
||||
> ### What are your thoughts on co-working streams?
|
||||
|
||||
> I'm not saying I dislike them, but I just want to understand how people enjoy these streams. It's mostly just the streamer doing their work while their cam is facing in front of them. There's nothing much to watch as it's not display captured (understandable since work is confidential).
|
||||
>
|
||||
> Sometimes, when I chat with them they don't even reply back. They usually have a timer in their overlay and after the timer ends they talk to chat again.
|
||||
>
|
||||
> Maybe I'm a boomer, but can anyone shed light on why these streams are a thing on Twitch?
|
||||
|
||||
Source: [Archived Reddit post](https://www.reddit.com/r/Twitch/comments/t66g15/what_are_your_thoughts_on_coworking_streams/)
|
||||
|
||||
Although might seem unconventional to watch someone else work, there are several reasons why viewers enjoy these streams:
|
||||
|
||||
- **Accountability and Focus**
|
||||
|
||||
Working from home can be isolating and lead to procrastination. Co-working streams provide a virtual study buddy or colleague, fostering a sense of accountability that viewers can leverage to stay on task. Seeing the streamer working diligently can motivate viewers to do the same.
|
||||
|
||||
- **Community and Support**
|
||||
|
||||
The chat function in these streams creates a sense of community. Viewers can discuss their work, ask questions, or simply enjoy the company of others while working. This social interaction can be a welcome change from the solitary nature of remote work.
|
||||
|
||||
- **Background Noise and Ambience**
|
||||
|
||||
Some viewers find background noise, like music or light chatter, helpful for concentration. Co-working streams can provide this calming ambience without the distractions of traditional co-working spaces.
|
||||
|
||||
- **Learning and Inspiration**
|
||||
|
||||
By watching a streamer work, viewers might pick up new productivity techniques or software shortcuts. Seeing someone else tackle similar tasks can be inspiring and motivating.
|
||||
|
||||
It's understandable that the lack of direct interaction or display capture might be unfamiliar. Streamers typically prioritize focusing on their work during these periods, addressing chat messages during breaks or using timers to dedicate time for interaction.
|
||||
|
||||
Ultimately, co-working streams cater to a specific need for some viewers. They offer a unique blend of productivity, community, and a supportive atmosphere that traditional work environments might lack.
|
||||
|
||||
---
|
||||
|
||||
## What is a task widget?
|
||||
|
||||
<a href="../guide/widgets#task-widgets" class="no-target-blank"><img src="/images/widgets/multitask.webp" alt="Multi Task Widget" loading="lazy"></a>
|
||||
|
||||
If you want to add a task widget to your own stream, check it out in the <a href="../guide/widgets#task-widgets" class="no-target-blank">Widgets section</a>!
|
||||
|
||||
A task widget is a widget where users can use commands such as:
|
||||
- !task [current task]
|
||||
- !todo [current task]
|
||||
|
||||
in chat to add their task(s) to the widget, to remind themselves about what they need to focus on at the moment.
|
||||
|
||||
Task widgets offer an extra layer of accountability for the streamer and chatters to focus on their current task(s).
|
||||
|
||||
---
|
||||
|
||||
## How can I find these streams?
|
||||
|
||||
The recommended way of searching for coworking streams are using the tags!
|
||||
|
||||
- [Coworking tag](https://www.twitch.tv/directory/all/tags/coworking)
|
||||
- ["Study with me" tag](https://www.twitch.tv/directory/all/tags/studywithme)
|
||||
|
||||
### [Coworking category petition 🔗](https://twitch.uservoice.com/forums/310210-discover/suggestions/46004791-coworking)
|
||||
|
||||
<img src="/images/introduction/petition.webp" alt="Coworking and Study category petition" loading="lazy" />
|
||||
|
||||
As of March 2024, there isn't an official category. So we want YOU to [SIGN THE PETITION](https://twitch.uservoice.com/forums/310210-discover/suggestions/46004791-coworking) for a "Coworking and Study" category!
|
||||
|
||||
An official coworking category will be beneficial for the community in the following ways:
|
||||
|
||||
- Allow coworking and study streamers to stream away from Just Chatting and stream in a less saturated category.
|
||||
- Improve discoverability of productivity streamers (big and small creators!)
|
||||
- Improve the algorithm to recommend more productivity related streams to users who are interested.
|
||||
|
||||
---
|
||||
|
|
@ -2,6 +2,7 @@
|
|||
title: Pre-requisites
|
||||
layout: "../../layouts/GuideLayout.astro"
|
||||
description: Pre-requisites for coworking streams!
|
||||
order: 1
|
||||
---
|
||||
|
||||
# Pre-requisites
|
||||
|
|
@ -49,3 +50,5 @@ Usually, streamers who stream from their phone would use their laptop device to
|
|||
|
||||
- **Twitch / YouTube app**
|
||||
- Depending on which platform you intend to stream on.
|
||||
|
||||
---
|
||||
52
src/pages/groups/index.md
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
---
|
||||
title: Stream groups
|
||||
layout: "../../layouts/GuideLayout.astro"
|
||||
description: Groups you should definitely checkout!
|
||||
order: 0
|
||||
---
|
||||
|
||||
# Groups
|
||||
|
||||
Communities provide a great way to connect with other streamers and viewers!
|
||||
|
||||
---
|
||||
|
||||
[](https://www.twitch.tv/team/coworkingcrew/)
|
||||
|
||||
## [Coworking Crew 🔗](https://www.twitch.tv/team/coworkingcrew/)
|
||||
|
||||
The Coworking Crew is a group of co-working streamers who aim to create supportive and motivational live streams for people who are working or studying at home. As a group we help each other out, collaborate on stream, and ultimately find new friends.
|
||||
|
||||
---
|
||||
|
||||
[](https://erudita.me/)
|
||||
|
||||
## [Erudita 🔗](https://erudita.me/)
|
||||
|
||||
An educational platform suitable for those seeking knowledge. In the community, you have the opportunity to learn alongside others or apply for Erudita membership and share your expertise and passions.
|
||||
|
||||
---
|
||||
|
||||
<a href="https://www.youthversity.org/"><img src="/images/groups/YOUthversity.webp" alt="YOUthversity" loading="lazy" /></a>
|
||||
|
||||
## [YOUthversity 🔗](https://www.youthversity.org/)
|
||||
|
||||
YOUthversity is not only an online space to study together but is dedicated to the exchange of resources, dialogue, peer-to-peer support, and development.
|
||||
|
||||
---
|
||||
|
||||
<a href="https://theselfdev.com/"><img src="/images/groups/selfdev.webp" alt="self dev" loading="lazy" /></a>
|
||||
|
||||
## [self.dev 🔗](https://theselfdev.com/)
|
||||
|
||||
Self.dev is a community of various individuals from different fields come together to share knowledge and grow together. They focus on supporting each other by sharing and creating valuable resources to help each other grow individually.
|
||||
|
||||
---
|
||||
|
||||
<a href="https://studytme.com/"><img src="/images/groups/CEOgang.webp" alt="CEO gang" loading="lazy" /></a>
|
||||
|
||||
## [CEO Gang 🔗](https://studytme.com/)
|
||||
|
||||
The right place for ambitious people working together and supporting each other! Make friends, learn and work remote!
|
||||
|
||||
---
|
||||
80
src/pages/guide/bots.md
Normal file
|
|
@ -0,0 +1,80 @@
|
|||
---
|
||||
title: Stream Bots
|
||||
layout: "../../layouts/GuideLayout.astro"
|
||||
description: Stream bots for your coworking streams!
|
||||
order: 2
|
||||
---
|
||||
|
||||
# Stream Bots
|
||||
|
||||
Useful bots to add to your stream!
|
||||
|
||||
---
|
||||
|
||||
## Cloud-hosted bots
|
||||
|
||||
### [Sery Bot 🔗](https://serycodes.carrd.co/)
|
||||
|
||||
<div class="flex flex-row gap-2">
|
||||
|
||||

|
||||
|
||||
</div>
|
||||
|
||||
Sery Bot is a moderation bot providing anti-hate raid and anti-follow bot protections, and other safety features and tools to streamers.
|
||||
|
||||
### [Nightbot 🔗](https://nightbot.tv/)
|
||||
|
||||
<div class="flex flex-row gap-2">
|
||||
|
||||

|
||||
|
||||

|
||||
</div>
|
||||
|
||||
Nightbot is a chatbot that you can use to manage your chat. It has a lot of features and is easy to use. You can also use it to create custom commands for your stream.
|
||||
|
||||
### [MohCitrus 🔗](https://www.twitch.tv/MohCitrus/about)
|
||||
|
||||
<div class="flex flex-row gap-2">
|
||||
|
||||

|
||||
</div>
|
||||
|
||||
|
||||
MohCitrus is a translator bot made by [MohFocus (Twitch)](https://twitch.tv/MohFocus)! It can translate messages of viewers to any language via commands!
|
||||

|
||||
|
||||
---
|
||||
|
||||
## Local bots
|
||||
|
||||
### [Streamer.bot 🔗](https://streamer.bot/)
|
||||
|
||||
<div class="flex flex-row gap-2">
|
||||
|
||||

|
||||
|
||||

|
||||
</div>
|
||||
|
||||
- Windows only!
|
||||
|
||||
Streamer.bot is a local bot, meaning all connections are made directly from your local PC to any configured external services, such as Twitch, YouTube, etc.
|
||||
|
||||
This means you have full ownership and control of any data stored in Streamer.bot, and your bot does not depend on a central 3rd party service to continue operating.
|
||||
|
||||
### [Mix It Up bot 🔗](https://mixitupapp.com/)
|
||||
|
||||
<div class="flex flex-row gap-2">
|
||||
|
||||

|
||||
|
||||

|
||||
</div>
|
||||
|
||||
- Windows only!
|
||||
|
||||
Mix It Up is a free, full featured, community driven, open-source stream bot developed by streamers for streamers.
|
||||
|
||||
---
|
||||
31
src/pages/guide/emotes.md
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
---
|
||||
title: Emotes
|
||||
layout: "../../layouts/GuideLayout.astro"
|
||||
description: Learn how to add emotes to your streams!
|
||||
order: 4
|
||||
---
|
||||
|
||||
# Emotes
|
||||
|
||||
Stream emotes are like custom emojis specific to a channel, acting as a fun and engaging way for viewers to express emotions, inside jokes, and reactions during a livestream, fostering a sense of community and shared experience.
|
||||
|
||||
---
|
||||
|
||||
## Channel emotes (Twitch)
|
||||
|
||||
When you reach the Twitch Affiliate goal, you can add emotes to your channel for subscribers to use! However, Follower emotes are only available if you have [Instant Upload Privilege](https://help.twitch.tv/s/article/emote-guidelines?language=en_US#instantupload)
|
||||
|
||||
## Emote extensions
|
||||
|
||||
Don’t understand when your chat says in ‘KEKW’? It’s a common third party Twitch emote! You can add extensions to your channel to add more emotes for your viewers to use. Some popular ones include BetterTTV, FrankerFaceZ and 7TV.
|
||||
|
||||
### Browser Extensions
|
||||
- [Download BetterTTV](https://betterttv.com/)
|
||||
- [Download FrankerFaceZ](https://www.frankerfacez.com/)
|
||||
- [Download 7TV](https://7tv.app/)
|
||||
|
||||
You won’t run into any issues using all three extensions at once!
|
||||
|
||||
However, if you only want to use one Emote extension, [FrankerFaceZ](https://www.frankerfacez.com/) is probably the best one to go for! It is stable, has special addons through the extension itself for BTTV and 7TV emotes, and has the best customization for twitch as a site!
|
||||
|
||||
---
|
||||
|
|
@ -2,6 +2,7 @@
|
|||
title: General Tips
|
||||
layout: "../../layouts/GuideLayout.astro"
|
||||
description: General tips for your coworking streams!
|
||||
order: 0
|
||||
---
|
||||
|
||||
# General Tips
|
||||
|
|
@ -18,6 +19,12 @@ Most streamers mute themselves during the work sessions because it makes it easi
|
|||
|
||||
Chat commands are very useful since you won't be chatting much during the work timer. Some common chat commands you may see include ones that introduce your stream, provide a brief introduction to the pomodoro method (if you use it), or a muted command that may explain why you may be muted (e.g: !welcome !timer !pomo !muted). You may also like to add a command to tell your viewers what you're working on that day (!today !work !study) - this adds a nice personal touch and you can use it to encourage other's to talk about what they're working on too.
|
||||
|
||||
## Closed Captions
|
||||
|
||||
[MAXIMIZE Your Reach on Twitch with Live Captions](https://youtu.be/cQzJL9uoIbg)
|
||||
|
||||
Closed captions open your stream to a wider audience by including viewers who are deaf or hard of hearing, and can even benefit viewers in noisy environments who might miss some dialogue.
|
||||
|
||||
---
|
||||
|
||||
## Do's
|
||||
|
|
@ -26,7 +33,7 @@ Chat commands are very useful since you won't be chatting much during the work t
|
|||
|
||||
`https://dashboard.twitch.tv/popout/u/{{channel}}/stream-manager/streamer-ads-manager-panel`
|
||||
|
||||
If you're using OBS, you can add the link above as a dock to your OBS (remember to replace "{{channel}}" with your actual channel name). This way, you can easily run ads without having to go to the Twitch dashboard.
|
||||
If you're using OBS, you can add the link above as a dock to your OBS (remember to replace "{{channel}}" with your actual channel name). This way, you can easily run ads and view when your next ad break is without having to go to the Twitch dashboard.
|
||||
|
||||
- ### Have a consistent stream schedule
|
||||
|
||||
|
|
@ -64,7 +71,7 @@ Hopping on chat and mention anything about your own stream is considered self-pr
|
|||
|
||||
- ### Don't worry about view count
|
||||
|
||||
Just focus on your work
|
||||
Just focus on your work.
|
||||
|
||||
- ### Avoid using Display Capture
|
||||
|
||||
|
|
@ -72,3 +79,4 @@ Some coworking streamers may have Display Capture source on their primary pomodo
|
|||
|
||||
It is recommended to blur it, or make your Display Capture source very small until no text content is readable.
|
||||
|
||||
---
|
||||
61
src/pages/guide/moderation-and-trolls.md
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
---
|
||||
title: Moderation and Trolls
|
||||
layout: "../../layouts/GuideLayout.astro"
|
||||
description: Learn how to moderate your coworking streams!
|
||||
order: 5
|
||||
---
|
||||
|
||||
# Moderation and Trolls
|
||||
|
||||
---
|
||||
|
||||
## Moderation
|
||||
|
||||
Having a good moderation team is important for coworking streamers, since most of the time we are focused on our own work and not chat! This is why it's particularly important to have a good moderation team to help you out so you don't get distracted.
|
||||
|
||||
Consider these three main things when choosing your mods:
|
||||
|
||||
- How well do they all get along with each other?
|
||||
- What is their availability?
|
||||
- Are they good at staying calm and being reasonable?
|
||||
|
||||
As well as this, it is ideal if mods are welcoming and active in your community - you can't always be there to say hi to everyone while your working so it's great to have a friendly mod team to welcome new people and answer questions!
|
||||
|
||||
> How you invite your mods is a personal choice! And don't feel bad if you ask someone and they say no - not everyone is up for the job! If you know someone you'd like as a mod you could DM them with a personal invite, otherwise you could create an application form if that suits you and your community better!
|
||||
|
||||
---
|
||||
|
||||
## Bots and trolls
|
||||
|
||||
As with any social media platform, you may encounter trolls and bots while you stream. If this happens, it is best to stay calm and work with your mods to resolve the situation; most of the time it is just annoying and won't result in anything serious. The following section is not an exhaustive list and this only meant as friendly advice. Please make sure you have read twitch TOS and only do what makes you feel comfortable and safe.
|
||||
|
||||
- ### Generic Trolls
|
||||
|
||||
For trolls that enter your chat and immediately send very inappropriate messages (e.g. hateful/sexual content) it is best to ignore them, ban them straightaway and move on. Giving them attention may create a negative atmosphere in your stream and make others feel unsafe. Try not to take these comments personally - it is unlikely to be targeted and they probably just want to get a reaction out of you.
|
||||
|
||||
- ### Promotional bots
|
||||
|
||||
This is when several bot accounts post in your chat with the same message, usually advertising a "get famous quick" scam. To stop this, you can put your chat in follower only mode by typing <span class="code-highlight">/followers</span> in your chat. Usually they will go away quickly and you can type <span class="code-highlight">/followersoff</span> to change it back.
|
||||
|
||||
You can also make use of the AutoMod feature by banning phrases like "bigfollow", so their messages get automatically removed. You can find this in your Dashboard Settings → Moderation. If you would like, you can also block hyperlinks in the same page or a stream bot (NightBot, StreamElements, etc.)
|
||||
|
||||
- ### Follow bots/raids
|
||||
|
||||
This is when several bot accounts follow your channel all at the same time. It can be anywhere from 10-10k. If this happens, stay calm, and turn off follower alerts to stop the alert spam. Sometimes the bots will also send messages all at once so you put your chat in subscriber mode to prevent this if you wish (type <span class="code-highlight">/subscribers</span> in your chat).
|
||||
|
||||
To get rid of bots, you can use [CommanderRoot's follower removal tool](https://twitch-tools.rootonline.de/follower_remover.php). Follow the instructions on his home page to remove accounts between a certain timeframe (you'll need to know what time the bots followed to avoid removing real people). Alternatively, you can just wait and Twitch will delete the accounts after a few days. Your follower count will drop suddenly but this is good - you don't want bots following you!
|
||||
|
||||
- ### Donation trolls
|
||||
|
||||
These are particularly nasty trolls. They donate money, anywhere from $10-$200 or more, maybe repeatedly, and will not talk very much in the chat, aside from making some request in exchange for the money they just donated. They then will ask for a chargeback (if youre using paypal). You can try and fight the case but there is a good change you will not win, and if you lose you have to pay $14 chargeback fee each time. This can add up over time. If you suspect someone is a Dono troll, you can block them from donating:
|
||||
|
||||
Go to your [donation page](https://streamlabs.com/dashboard#/donations). There should be a list of names and donations:
|
||||
|
||||
<img src="/images/moderation-and-trolls/donation-troll.webp" alt="Donation troll" loading="lazy" />
|
||||
|
||||
<br>
|
||||
Also in Settings > Donation settings, make sure you've ticked "Login Required":
|
||||
|
||||
<img src="/images/moderation-and-trolls/donation-settings.webp" alt="Donation settings" loading="lazy" />
|
||||
|
||||
---
|
||||
|
|
@ -2,6 +2,7 @@
|
|||
title: Music and Audio
|
||||
layout: "../../layouts/GuideLayout.astro"
|
||||
description: Learn how to add music or audio for your coworking streams!
|
||||
order: 1
|
||||
---
|
||||
|
||||
# Music and Audio
|
||||
|
|
@ -10,6 +11,117 @@ Every Coworking & Study stream has their vibe based on their stream audio!
|
|||
|
||||
---
|
||||
|
||||
## how about this
|
||||
## Non-DMCA Playlists
|
||||
|
||||
test
|
||||
> DMCA: Digital Millenium Copyright Act
|
||||
|
||||
Non-copyrighted music playlists for you to listen on stream!
|
||||
|
||||
### Lofi Girl
|
||||
|
||||
- [Spotify](https://open.spotify.com/playlist/0vvXsWCC9xrXsKd4FyS8kM?si=65d4b951673847a2)
|
||||
- [YouTube (playlist)](https://www.youtube.com/watch?v=CMNyHBx1gak&list=PL6NdkXsPL07KN01gH2vucrHCEyyNmVEx4)
|
||||
- [SoundCloud](https://soundcloud.com/lofi_girl)
|
||||
|
||||
### Lofi Boy (Synthwave)
|
||||
|
||||
- [Spotify](https://open.spotify.com/playlist/1YIe34rcmLjCYpY9wJoM2p?si=f5115c5c9b644871)
|
||||
- [YouTube (video)](https://youtu.be/TlWYgGyNnJo)
|
||||
|
||||
### Chillhop
|
||||
|
||||
- [Spotify](https://open.spotify.com/user/chillhopmusic?si=b9c63cbb27db45ab&nd=1&dlsi=477657d953294e71)
|
||||
- [YouTube (playlist)](https://www.youtube.com/watch?v=XuW2hx3h7sE&list=PLt7bG0K25iXgkGK9PLhP3yryqc7S8uHds)
|
||||
- [SoundCloud](https://soundcloud.com/chillhopdotcom)
|
||||
|
||||
### Lud and Schlatts Musical Emporium - Classical
|
||||
|
||||
- [YouTube (playlist)](https://youtu.be/VBSP75pr2bg?list=PL2LwrpMfls5K1DVyG5ii_mEGKqzK9EGlr)
|
||||
|
||||
---
|
||||
|
||||
## How to Display 'Now Playing'
|
||||
|
||||
### [6K Labs 🔗](https://6klabs.com/)
|
||||
|
||||
<a href="https://6klabs.com/"><img src="/images/music-and-audio/6klabs.webp" alt="6K Labs widget" loading="lazy" /></a>
|
||||
|
||||
- Easy to implement
|
||||
- Available for YouTube Music and Spotify
|
||||
- Has many design choices and settings:
|
||||
- Dark/Light mode
|
||||
- Tint colour options
|
||||
- Different aesthetic choices:
|
||||
- Compact
|
||||
- macOS
|
||||
- Linux Shell
|
||||
- And many more!
|
||||
|
||||
### [Pixel Chat 🔗](https://pixelchat.tv/)
|
||||
|
||||
<a href="https://pixelchat.tv/"><img src="/images/music-and-audio/pixelchat.webp" alt="Pixel Chat widget" loading="lazy" /></a>
|
||||
|
||||
- Shows what you're playing via Spotify, Apple Music etc.
|
||||
- Includes other widgets for shoutouts, captions and counters
|
||||
|
||||
---
|
||||
|
||||
## Non-music options
|
||||
|
||||
Don't like listening to music? Still worried about DMCA? Want other forms of background audio to stand out amongst other streamers? Don't worry! Here are a few suggestions for your background ambience that doesn't involve music!
|
||||
|
||||
The following websites allow you to download audio files, so you can add to your streaming application (e.g. OBS) as a Media Source.
|
||||
|
||||
**Note: Please be careful when downloading any files onto your computer.**
|
||||
|
||||
- ### [Coffee Shop Ambience 🔗](https://pixabay.com/sound-effects/search/coffee%20shop/)
|
||||
|
||||
The low hum of conversation and coffee shop bustle can provide a focused ambience that aids studying.
|
||||
|
||||
- ### [Forest Ambience 🔗](https://pixabay.com/sound-effects/search/forest%20ambience/)
|
||||
|
||||
The calming sounds of nature in a forest ambience can create a peaceful and focused atmosphere.
|
||||
|
||||
- ### [Rain Ambience 🔗](https://pixabay.com/sound-effects/search/rain/)
|
||||
|
||||
The steady pitter-patter of rain ambience offers a soothing and concentration-boosting backdrop for studying.
|
||||
|
||||
- ### [Ocean Ambience 🔗](https://pixabay.com/sound-effects/search/ocean%20ambience/)
|
||||
|
||||
With its rhythmic waves, provides a calming yet stimulating soundscape that can enhance focus.
|
||||
|
||||
- ### [Fireplace Ambience 🔗](https://pixabay.com/sound-effects/search/fireplace/)
|
||||
|
||||
The crackle and warmth of a fireplace ambience create a cozy and concentration-promoting environment for studying.
|
||||
|
||||
---
|
||||
|
||||
## How to Separate Audio for Twitch VOD
|
||||
|
||||
[How to SEPARATE AUDIO for Twitch VOD with OBS studio (NO Voicemeeter) 🔗](https://www.youtube.com/watch?v=0Lj5rkqSp48)
|
||||
|
||||
If you’re streaming on Twitch using OBS, you can easily avoid getting your VODs muted by separating audio tracks into VOD audio tracks and stream audio tracks. This way, you can listen to music on your stream without worrying about getting muted.
|
||||
|
||||
---
|
||||
|
||||
## How to Separate your Audio for meetings/classes
|
||||
|
||||
### Easy way (have two different outputs)
|
||||
|
||||
<img src="/images/music-and-audio/audio_settings.webp" alt="Audio settings" loading="lazy" />
|
||||
|
||||
To do this, you'll need to have two different audio outputs (i.e. two headphones/speakers). For windows users, go to sound settings --> advance sound options --> app volume device preferences (or if you can't find it, search "sound mixer options" in your start) then you should see this:
|
||||
|
||||
There you can have your different outputs for different programmes. For example, one pair of headphones is used for zoom, and the other for everything else. In your streaming software, make sure the output is selected for the correct pair of headphones in your mixer!
|
||||
|
||||
### Complicated ways
|
||||
|
||||
- #### [VoicemeeterBanana](https://vb-audio.com/Voicemeeter/banana.htm) (Windows only!)
|
||||
|
||||
- Download Voicemeeter Banana (software to route audio sources) and set all the audio sources/inputs you don't want to include on stream into a Voicemeeter input/output source separate from the main routing.
|
||||
- The outputs will show up separately in your Audio Mixer, which you can adjust/mute
|
||||
- Tutorial: [Separate Game Audio, Discord, Music in OBS! (A Voicemeeter Tutorial for Beginners)](https://www.youtube.com/watch?v=XD9sWOjITYU&t=376s)
|
||||
- #### [BlackHole audio](https://obsproject.com/forum/resources/mac-desktop-audio-using-blackhole.1191/) (Mac only!)
|
||||
- Free! Integrates with OBS
|
||||
- #### [GroundControl Caster](https://gingeraudio.com/groundcontrol-caster/) (Mac only!)
|
||||
- Free! Integrates with Twitch, OBS, StreamLabs, Zoom, FaceTime etc.
|
||||
|
|
|
|||
108
src/pages/guide/widgets.md
Normal file
|
|
@ -0,0 +1,108 @@
|
|||
---
|
||||
title: Stream Widgets
|
||||
layout: "../../layouts/GuideLayout.astro"
|
||||
description: Stream widgets for your coworking streams!
|
||||
order: 3
|
||||
---
|
||||
|
||||
# Stream widgets
|
||||
|
||||
Widgets to add to your stream!
|
||||
|
||||
---
|
||||
|
||||
## Pomodoro timer
|
||||
|
||||
A pomodoro timer is a great way to keep track of your work sessions. It’s also a great way to let your viewers know when you’re taking a break. You can use a pomodoro timer widget to display the current work session and break time.
|
||||
|
||||
### Browser Sources
|
||||
|
||||
#### [MohFocus' Minimal Pomo Timer 🔗](https://github.com/mohamed-tayeh/Minimal-Pomo-Timer)
|
||||
|
||||
[](https://github.com/mohamed-tayeh/Minimal-Pomo-Timer)
|
||||
|
||||
- Twitch only
|
||||
- Easy to setup and customize
|
||||
- Called through commands in Twitch chat
|
||||
- Optionally post break time notifications to Discord
|
||||
|
||||
#### [Mayuko's Pomodoro Countdown Timer 🔗](https://github.com/hellomayuko/Pomodoro-Countdown)
|
||||
|
||||
<a href="https://github.com/hellomayuko/Pomodoro-Countdown"><img src="/images/widgets/mayuko-pomo.webp" alt="Mayuko Pomodoro Countdown Timer" loading="lazy" /></a>
|
||||
|
||||
- Easy to setup and customize
|
||||
- Interactive through OBS
|
||||
|
||||
### Window Capture
|
||||
|
||||
#### [Pomofocus 🔗](https://pomofocus.io/)
|
||||
|
||||
<a href="https://pomofocus.io/"><img src="/images/widgets/pomofocus.webp" alt="pomofocus" loading="lazy" /></a>
|
||||
|
||||
- You can also add tasks to do on the web page
|
||||
|
||||
---
|
||||
|
||||
## Task widgets
|
||||
|
||||
A task list widget is a great way to keep track of your tasks along with your chatters!
|
||||
|
||||
### [Rython Task Bot 🔗](https://github.com/liyunze-coding/chat-task-tic-overlay-infinity)
|
||||
|
||||
<a href="https://github.com/liyunze-coding/chat-task-tic-overlay-infinity"><img src="/images/widgets/rythontaskbot.webp" alt="Rython Task Bot" loading="lazy" /></a>
|
||||
|
||||
- Free and open source
|
||||
- Easy to use, setup and customize
|
||||
- Horizontal version available
|
||||
- Used by 100+ streamers
|
||||
- Handles only one incomplete task per user
|
||||
|
||||
### [Multi-task Widget 🔗](https://ko-fi.com/s/94e7e8dc81)
|
||||
|
||||
<a href="https://ko-fi.com/s/94e7e8dc81"><img src="/images/widgets/multitask.webp" alt="Multi Task Widget" loading="lazy" /></a>
|
||||
|
||||
- $50 USD on ko-fi
|
||||
- Easy to use, setup and customize
|
||||
- Several versions to choose from:
|
||||
- Original version
|
||||
- Streamer bot version (Windows only, stream to YouTube and Twitch!)
|
||||
- Horizontal version
|
||||
|
||||
### [Super Sweet Bot 🔗](https://www.patreon.com/super_sweet_bot)
|
||||
|
||||
<a href="https://www.patreon.com/super_sweet_bot"><img src="/images/widgets/supersweetbot.webp" alt="Super Sweet Bot" loading="lazy" /></a>
|
||||
|
||||
- €3 / month
|
||||
- Comes with a Pomo Timer
|
||||
- Colors are customizable
|
||||
- Hosted on a cloud server
|
||||
|
||||
---
|
||||
|
||||
## Music Widgets
|
||||
|
||||
Display what you're playing on Spotify or YouTube Music!
|
||||
|
||||
### [6K Labs 🔗](https://6klabs.com/)
|
||||
|
||||
<a href="https://6klabs.com/"><img src="/images/music-and-audio/6klabs.webp" alt="6K Labs widget" loading="lazy" /></a>
|
||||
|
||||
- Easy to implement
|
||||
- Available for YouTube Music and Spotify
|
||||
- Has many design choices and settings:
|
||||
- Dark/Light mode
|
||||
- Tint colour options
|
||||
- Different aesthetic choices:
|
||||
- Compact
|
||||
- macOS
|
||||
- Linux Shell
|
||||
- And many more!
|
||||
|
||||
### [Pixel Chat 🔗](https://pixelchat.tv/)
|
||||
|
||||
<a href="https://pixelchat.tv/"><img src="/images/music-and-audio/pixelchat.webp" alt="Pixel Chat widget" loading="lazy" /></a>
|
||||
|
||||
- Shows what you're playing via Spotify, Apple Music etc.
|
||||
- Includes other widgets for shoutouts, captions and counters
|
||||
|
||||
---
|
||||