mirror of
https://github.com/liyunze-coding/coworking-website.git
synced 2026-11-06 13:13:34 +00:00
website content done
This commit is contained in:
parent
3022207283
commit
304c08f132
28 changed files with 1231 additions and 1019 deletions
|
|
@ -22,7 +22,7 @@ This guide is intended to help you get started with the coworking streams! Wheth
|
|||
|
||||
I am a coworking streamer myself and I also made several open source widgets for the coworking streams.
|
||||
|
||||
Please feel free to drop by my <a href="https://www.twitch.tv/RyanPython" target="_blank">stream</a>!
|
||||
Please feel free to drop by my <a href="https://www.twitch.tv/RythonDev" target="_blank">stream</a>!
|
||||
|
||||
---
|
||||
|
||||
|
|
|
|||
|
|
@ -1,12 +1,13 @@
|
|||
import { defineConfig } from "astro/config";
|
||||
import tailwind from "@astrojs/tailwind";
|
||||
|
||||
import mdx from "@astrojs/mdx";
|
||||
|
||||
import react from "@astrojs/react";
|
||||
|
||||
// https://astro.build/config
|
||||
export default defineConfig({
|
||||
integrations: [tailwind(), mdx()],
|
||||
server: {
|
||||
port: 3000
|
||||
}
|
||||
integrations: [tailwind(), mdx(), react()],
|
||||
server: {
|
||||
port: 3000,
|
||||
},
|
||||
});
|
||||
284
package-lock.json
generated
284
package-lock.json
generated
|
|
@ -9,13 +9,23 @@
|
|||
"version": "2.0.0",
|
||||
"dependencies": {
|
||||
"@astrojs/mdx": "^2.1.1",
|
||||
"@astrojs/react": "^3.1.0",
|
||||
"@astrojs/tailwind": "^5.1.0",
|
||||
"@astrojs/ts-plugin": "^1.5.3",
|
||||
"@types/react": "^18.2.65",
|
||||
"@types/react-dom": "^18.2.22",
|
||||
"@vercel/analytics": "^1.0.1",
|
||||
"astro": "^4.4.1",
|
||||
"clsx": "^2.1.0",
|
||||
"framer-motion": "^11.0.12",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
"react-router-dom": "^6.22.3",
|
||||
"tailwind-merge": "^2.2.1",
|
||||
"tailwindcss": "^3.4.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/react-router-dom": "^5.3.3",
|
||||
"prettier": "^3.2.5",
|
||||
"prettier-plugin-tailwindcss": "^0.5.11"
|
||||
}
|
||||
|
|
@ -113,6 +123,24 @@
|
|||
"node": ">=18.14.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@astrojs/react": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@astrojs/react/-/react-3.1.0.tgz",
|
||||
"integrity": "sha512-KZhZyV+sUDZEjlrmPWNiPGeYowG9uq6/aMbCgVaeKEBlWT4Kg32TNwBOhZk6AcE4LY1l3mIwt3orUGE2JV96/g==",
|
||||
"dependencies": {
|
||||
"@vitejs/plugin-react": "^4.2.0",
|
||||
"ultrahtml": "^1.3.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18.14.1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/react": "^17.0.50 || ^18.0.21",
|
||||
"@types/react-dom": "^17.0.17 || ^18.0.6",
|
||||
"react": "^17.0.2 || ^18.0.0",
|
||||
"react-dom": "^17.0.2 || ^18.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@astrojs/tailwind": {
|
||||
"version": "5.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@astrojs/tailwind/-/tailwind-5.1.0.tgz",
|
||||
|
|
@ -459,6 +487,45 @@
|
|||
"@babel/core": "^7.0.0-0"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/plugin-transform-react-jsx-self": {
|
||||
"version": "7.23.3",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-self/-/plugin-transform-react-jsx-self-7.23.3.tgz",
|
||||
"integrity": "sha512-qXRvbeKDSfwnlJnanVRp0SfuWE5DQhwQr5xtLBzp56Wabyo+4CMosF6Kfp+eOD/4FYpql64XVJ2W0pVLlJZxOQ==",
|
||||
"dependencies": {
|
||||
"@babel/helper-plugin-utils": "^7.22.5"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@babel/core": "^7.0.0-0"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/plugin-transform-react-jsx-source": {
|
||||
"version": "7.23.3",
|
||||
"resolved": "https://registry.npmjs.org/@babel/plugin-transform-react-jsx-source/-/plugin-transform-react-jsx-source-7.23.3.tgz",
|
||||
"integrity": "sha512-91RS0MDnAWDNvGC6Wio5XYkyWI39FMFO+JK9+4AlgaTH+yWwVTsw7/sn6LK0lH7c5F+TFkpv/3LfCJ1Ydwof/g==",
|
||||
"dependencies": {
|
||||
"@babel/helper-plugin-utils": "^7.22.5"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@babel/core": "^7.0.0-0"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/runtime": {
|
||||
"version": "7.24.0",
|
||||
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.24.0.tgz",
|
||||
"integrity": "sha512-Chk32uHMg6TnQdvw2e9IlqPpFX/6NLuK0Ys2PqLb7/gL5uFn9mXvK715FGLlOLQrcO4qIkNHkvPGktzzXexsFw==",
|
||||
"dependencies": {
|
||||
"regenerator-runtime": "^0.14.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/template": {
|
||||
"version": "7.23.9",
|
||||
"resolved": "https://registry.npmjs.org/@babel/template/-/template-7.23.9.tgz",
|
||||
|
|
@ -1015,6 +1082,14 @@
|
|||
"node": ">=14"
|
||||
}
|
||||
},
|
||||
"node_modules/@remix-run/router": {
|
||||
"version": "1.15.3",
|
||||
"resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.15.3.tgz",
|
||||
"integrity": "sha512-Oy8rmScVrVxWZVOpEF57ovlnhpZ8CCPlnIIumVcV9nFdiSIrus99+Lw78ekXyGvVDlIsFJbSfmSovJUhCWYV3w==",
|
||||
"engines": {
|
||||
"node": ">=14.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@rollup/rollup-android-arm-eabi": {
|
||||
"version": "4.12.0",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.12.0.tgz",
|
||||
|
|
@ -1245,6 +1320,12 @@
|
|||
"@types/unist": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/history": {
|
||||
"version": "4.7.11",
|
||||
"resolved": "https://registry.npmjs.org/@types/history/-/history-4.7.11.tgz",
|
||||
"integrity": "sha512-qjDJRrmvBMiTx+jyLxvLfJU7UznFuokDv4f3WRuriHKERccVpFU+8XMQUAbDzoiJCsmexxRExQeMwwCdamSKDA==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@types/mdast": {
|
||||
"version": "4.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-4.0.3.tgz",
|
||||
|
|
@ -1286,6 +1367,55 @@
|
|||
"undici-types": "~5.26.4"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/prop-types": {
|
||||
"version": "15.7.11",
|
||||
"resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.11.tgz",
|
||||
"integrity": "sha512-ga8y9v9uyeiLdpKddhxYQkxNDrfvuPrlFb0N1qnZZByvcElJaXthF1UhvCh9TLWJBEHeNtdnbysW7Y6Uq8CVng=="
|
||||
},
|
||||
"node_modules/@types/react": {
|
||||
"version": "18.2.65",
|
||||
"resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.65.tgz",
|
||||
"integrity": "sha512-98TsY0aW4jqx/3RqsUXwMDZSWR1Z4CUlJNue8ueS2/wcxZOsz4xmW1X8ieaWVRHcmmQM3R8xVA4XWB3dJnWwDQ==",
|
||||
"dependencies": {
|
||||
"@types/prop-types": "*",
|
||||
"@types/scheduler": "*",
|
||||
"csstype": "^3.0.2"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/react-dom": {
|
||||
"version": "18.2.22",
|
||||
"resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.2.22.tgz",
|
||||
"integrity": "sha512-fHkBXPeNtfvri6gdsMYyW+dW7RXFo6Ad09nLFK0VQWR7yGLai/Cyvyj696gbwYvBnhGtevUG9cET0pmUbMtoPQ==",
|
||||
"dependencies": {
|
||||
"@types/react": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/react-router": {
|
||||
"version": "5.1.20",
|
||||
"resolved": "https://registry.npmjs.org/@types/react-router/-/react-router-5.1.20.tgz",
|
||||
"integrity": "sha512-jGjmu/ZqS7FjSH6owMcD5qpq19+1RS9DeVRqfl1FeBMxTDQAGwlMWOcs52NDoXaNKyG3d1cYQFMs9rCrb88o9Q==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@types/history": "^4.7.11",
|
||||
"@types/react": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/react-router-dom": {
|
||||
"version": "5.3.3",
|
||||
"resolved": "https://registry.npmjs.org/@types/react-router-dom/-/react-router-dom-5.3.3.tgz",
|
||||
"integrity": "sha512-kpqnYK4wcdm5UaWI3fLcELopqLrHgLqNsdpHauzlQktfkHL3npOSwtj1Uz9oKBAzs7lFtVkV8j83voAz2D8fhw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@types/history": "^4.7.11",
|
||||
"@types/react": "*",
|
||||
"@types/react-router": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/scheduler": {
|
||||
"version": "0.16.8",
|
||||
"resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.8.tgz",
|
||||
"integrity": "sha512-WZLiwShhwLRmeV6zH+GkbOFT6Z6VklCItrDioxUnv+u4Ll+8vKeFySoFyK/0ctcRpOmwAicELfmys1sDc/Rw+A=="
|
||||
},
|
||||
"node_modules/@types/unist": {
|
||||
"version": "3.0.2",
|
||||
"resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.2.tgz",
|
||||
|
|
@ -1301,6 +1431,24 @@
|
|||
"resolved": "https://registry.npmjs.org/@vercel/analytics/-/analytics-1.0.1.tgz",
|
||||
"integrity": "sha512-Ux0c9qUfkcPqng3vrR0GTrlQdqNJ2JREn/2ydrVuKwM3RtMfF2mWX31Ijqo1opSjNAq6rK76PwtANw6kl6TAow=="
|
||||
},
|
||||
"node_modules/@vitejs/plugin-react": {
|
||||
"version": "4.2.1",
|
||||
"resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-4.2.1.tgz",
|
||||
"integrity": "sha512-oojO9IDc4nCUUi8qIR11KoQm0XFFLIwsRBwHRR4d/88IWghn1y6ckz/bJ8GHDCsYEJee8mDzqtJxh15/cisJNQ==",
|
||||
"dependencies": {
|
||||
"@babel/core": "^7.23.5",
|
||||
"@babel/plugin-transform-react-jsx-self": "^7.23.3",
|
||||
"@babel/plugin-transform-react-jsx-source": "^7.23.3",
|
||||
"@types/babel__core": "^7.20.5",
|
||||
"react-refresh": "^0.14.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^14.18.0 || >=16.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"vite": "^4.2.0 || ^5.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@volar/language-core": {
|
||||
"version": "2.0.4",
|
||||
"resolved": "https://registry.npmjs.org/@volar/language-core/-/language-core-2.0.4.tgz",
|
||||
|
|
@ -2118,6 +2266,11 @@
|
|||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/csstype": {
|
||||
"version": "3.1.3",
|
||||
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz",
|
||||
"integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw=="
|
||||
},
|
||||
"node_modules/debug": {
|
||||
"version": "4.3.4",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
|
||||
|
|
@ -2568,6 +2721,30 @@
|
|||
"url": "https://github.com/sponsors/rawify"
|
||||
}
|
||||
},
|
||||
"node_modules/framer-motion": {
|
||||
"version": "11.0.12",
|
||||
"resolved": "https://registry.npmjs.org/framer-motion/-/framer-motion-11.0.12.tgz",
|
||||
"integrity": "sha512-1VW4pk+4EH8RwWHdqntWTwF9peranyHn/BczvMzF9TGh/FwMKxoRZzkig8Nak9BQA8GymfIyCGo5adXwRuXDXA==",
|
||||
"dependencies": {
|
||||
"tslib": "^2.4.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@emotion/is-prop-valid": "*",
|
||||
"react": "^18.0.0",
|
||||
"react-dom": "^18.0.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@emotion/is-prop-valid": {
|
||||
"optional": true
|
||||
},
|
||||
"react": {
|
||||
"optional": true
|
||||
},
|
||||
"react-dom": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/fs-constants": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz",
|
||||
|
|
@ -3425,6 +3602,17 @@
|
|||
"url": "https://github.com/sponsors/wooorm"
|
||||
}
|
||||
},
|
||||
"node_modules/loose-envify": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
|
||||
"integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==",
|
||||
"dependencies": {
|
||||
"js-tokens": "^3.0.0 || ^4.0.0"
|
||||
},
|
||||
"bin": {
|
||||
"loose-envify": "cli.js"
|
||||
}
|
||||
},
|
||||
"node_modules/lru-cache": {
|
||||
"version": "5.1.1",
|
||||
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz",
|
||||
|
|
@ -5451,6 +5639,67 @@
|
|||
"rc": "cli.js"
|
||||
}
|
||||
},
|
||||
"node_modules/react": {
|
||||
"version": "18.2.0",
|
||||
"resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz",
|
||||
"integrity": "sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==",
|
||||
"dependencies": {
|
||||
"loose-envify": "^1.1.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/react-dom": {
|
||||
"version": "18.2.0",
|
||||
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz",
|
||||
"integrity": "sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g==",
|
||||
"dependencies": {
|
||||
"loose-envify": "^1.1.0",
|
||||
"scheduler": "^0.23.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "^18.2.0"
|
||||
}
|
||||
},
|
||||
"node_modules/react-refresh": {
|
||||
"version": "0.14.0",
|
||||
"resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.14.0.tgz",
|
||||
"integrity": "sha512-wViHqhAd8OHeLS/IRMJjTSDHF3U9eWi62F/MledQGPdJGDhodXJ9PBLNGr6WWL7qlH12Mt3TyTpbS+hGXMjCzQ==",
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/react-router": {
|
||||
"version": "6.22.3",
|
||||
"resolved": "https://registry.npmjs.org/react-router/-/react-router-6.22.3.tgz",
|
||||
"integrity": "sha512-dr2eb3Mj5zK2YISHK++foM9w4eBnO23eKnZEDs7c880P6oKbrjz/Svg9+nxqtHQK+oMW4OtjZca0RqPglXxguQ==",
|
||||
"dependencies": {
|
||||
"@remix-run/router": "1.15.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": ">=16.8"
|
||||
}
|
||||
},
|
||||
"node_modules/react-router-dom": {
|
||||
"version": "6.22.3",
|
||||
"resolved": "https://registry.npmjs.org/react-router-dom/-/react-router-dom-6.22.3.tgz",
|
||||
"integrity": "sha512-7ZILI7HjcE+p31oQvwbokjk6OA/bnFxrhJ19n82Ex9Ph8fNAq+Hm/7KchpMGlTgWhUxRHMMCut+vEtNpWpowKw==",
|
||||
"dependencies": {
|
||||
"@remix-run/router": "1.15.3",
|
||||
"react-router": "6.22.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=14.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": ">=16.8",
|
||||
"react-dom": ">=16.8"
|
||||
}
|
||||
},
|
||||
"node_modules/read-cache": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz",
|
||||
|
|
@ -5491,6 +5740,11 @@
|
|||
"node": ">=8.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/regenerator-runtime": {
|
||||
"version": "0.14.1",
|
||||
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz",
|
||||
"integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw=="
|
||||
},
|
||||
"node_modules/rehype": {
|
||||
"version": "13.0.1",
|
||||
"resolved": "https://registry.npmjs.org/rehype/-/rehype-13.0.1.tgz",
|
||||
|
|
@ -6125,6 +6379,14 @@
|
|||
}
|
||||
]
|
||||
},
|
||||
"node_modules/scheduler": {
|
||||
"version": "0.23.0",
|
||||
"resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.0.tgz",
|
||||
"integrity": "sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw==",
|
||||
"dependencies": {
|
||||
"loose-envify": "^1.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/section-matter": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/section-matter/-/section-matter-1.0.0.tgz",
|
||||
|
|
@ -6545,6 +6807,18 @@
|
|||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/tailwind-merge": {
|
||||
"version": "2.2.1",
|
||||
"resolved": "https://registry.npmjs.org/tailwind-merge/-/tailwind-merge-2.2.1.tgz",
|
||||
"integrity": "sha512-o+2GTLkthfa5YUt4JxPfzMIpQzZ3adD1vLVkvKE1Twl9UAhGsEbIZhHHZVRttyW177S8PDJI3bTQNaebyofK3Q==",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.23.7"
|
||||
},
|
||||
"funding": {
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/dcastil"
|
||||
}
|
||||
},
|
||||
"node_modules/tailwindcss": {
|
||||
"version": "3.4.1",
|
||||
"resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.1.tgz",
|
||||
|
|
@ -6705,6 +6979,11 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"node_modules/tslib": {
|
||||
"version": "2.6.2",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz",
|
||||
"integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q=="
|
||||
},
|
||||
"node_modules/tunnel-agent": {
|
||||
"version": "0.6.0",
|
||||
"resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz",
|
||||
|
|
@ -6728,6 +7007,11 @@
|
|||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/ultrahtml": {
|
||||
"version": "1.5.3",
|
||||
"resolved": "https://registry.npmjs.org/ultrahtml/-/ultrahtml-1.5.3.tgz",
|
||||
"integrity": "sha512-GykOvZwgDWZlTQMtp5jrD4BVL+gNn2NVlVafjcFUJ7taY20tqYdwdoWBFy6GBJsNTZe1GkGPkSl5knQAjtgceg=="
|
||||
},
|
||||
"node_modules/undici-types": {
|
||||
"version": "5.26.5",
|
||||
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz",
|
||||
|
|
|
|||
10
package.json
10
package.json
|
|
@ -11,13 +11,23 @@
|
|||
},
|
||||
"dependencies": {
|
||||
"@astrojs/mdx": "^2.1.1",
|
||||
"@astrojs/react": "^3.1.0",
|
||||
"@astrojs/tailwind": "^5.1.0",
|
||||
"@astrojs/ts-plugin": "^1.5.3",
|
||||
"@types/react": "^18.2.65",
|
||||
"@types/react-dom": "^18.2.22",
|
||||
"@vercel/analytics": "^1.0.1",
|
||||
"astro": "^4.4.1",
|
||||
"clsx": "^2.1.0",
|
||||
"framer-motion": "^11.0.12",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
"react-router-dom": "^6.22.3",
|
||||
"tailwind-merge": "^2.2.1",
|
||||
"tailwindcss": "^3.4.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/react-router-dom": "^5.3.3",
|
||||
"prettier": "^3.2.5",
|
||||
"prettier-plugin-tailwindcss": "^0.5.11"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,47 +0,0 @@
|
|||
---
|
||||
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>
|
||||
47
src/components/blocks/BlogPostPreview.astro
Normal file
47
src/components/blocks/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>
|
||||
52
src/components/blocks/Hero.astro
Normal file
52
src/components/blocks/Hero.astro
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
---
|
||||
import { HoverEffect } from "../ui/card-hover-effect";
|
||||
import HeroTitle from "../ui/HeroTitle.astro";
|
||||
|
||||
const items = [
|
||||
{
|
||||
title: "Introduction",
|
||||
description:
|
||||
"What is Coworking? What are study streams? What's the purpose of it?",
|
||||
link: "/get-started/introduction",
|
||||
},
|
||||
{
|
||||
title: "Tips",
|
||||
description:
|
||||
"Learn some tips to enhance your stream and attract more viewers!",
|
||||
link: "/guide/general-tips",
|
||||
},
|
||||
{
|
||||
title: "Music and Audio",
|
||||
description:
|
||||
"Check out non-copyrighted playlists, non-music background audio and many more!",
|
||||
link: "/guide/music-and-audio",
|
||||
},
|
||||
{
|
||||
title: "Groups",
|
||||
description:
|
||||
"Check out some awesome communities related to coworking, studying and self-improvement!",
|
||||
link: "/groups",
|
||||
},
|
||||
{
|
||||
title: "Blog",
|
||||
description:
|
||||
"Take a look at some blog posts regarding the coworking community!",
|
||||
link: "/blog",
|
||||
},
|
||||
{
|
||||
title: "Credits",
|
||||
description: "Support the people behind this website! Drop them",
|
||||
link: "/credits",
|
||||
},
|
||||
];
|
||||
---
|
||||
|
||||
<div class="relative w-fit mt-20 z-50 ">
|
||||
<HeroTitle />
|
||||
|
||||
<div class="max-w-5xl mx-auto px-8 pt-10">
|
||||
<HoverEffect items={items} client:load />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style></style>
|
||||
154
src/components/blocks/navBar.astro
Normal file
154
src/components/blocks/navBar.astro
Normal file
|
|
@ -0,0 +1,154 @@
|
|||
---
|
||||
import VerticalNav from "./verticalNav.astro";
|
||||
---
|
||||
|
||||
<div
|
||||
transition:persist
|
||||
transition:name="navbar"
|
||||
class="w-full backdrop-blur fixed top-0 text-white bg-secondary/75 z-[60] text-lg py-3 border-b border-solid border-gray-800 h-[var(--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 z-30"
|
||||
transition:name="hamburger"
|
||||
>
|
||||
<button
|
||||
id="menu-toggle"
|
||||
type="button"
|
||||
class="text-white"
|
||||
transition:persist
|
||||
>
|
||||
<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-8" id="navbar-links">
|
||||
<a
|
||||
class="no-target-blank hover:text-black hover:bg-white rounded-md transition-colors duration-300 px-2 py-1 text-white hover:no-underline"
|
||||
href="/get-started/introduction">Get started</a
|
||||
>
|
||||
<a
|
||||
class="no-target-blank hover:text-black hover:bg-white rounded-md transition-colors duration-300 px-2 py-1 text-white hover:no-underline"
|
||||
href="/guide/general-tips">Guide</a
|
||||
>
|
||||
<a
|
||||
class="no-target-blank hover:text-black hover:bg-white rounded-md transition-colors duration-300 px-2 py-1 text-white hover:no-underline"
|
||||
href="/groups">Groups</a
|
||||
>
|
||||
<a
|
||||
class="no-target-blank hover:text-black hover:bg-white rounded-md transition-colors duration-300 px-2 py-1 text-white hover:no-underline"
|
||||
href="/blog">Blog</a
|
||||
>
|
||||
<a
|
||||
class="no-target-blank hover:text-black hover:bg-white rounded-md transition-colors duration-300 px-2 py-1 text-white hover:no-underline"
|
||||
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>
|
||||
<aside
|
||||
id="vertical-navbar"
|
||||
class="fixed block overflow-y-auto -translate-x-[200%] transition-transform duration-300 z-30 lg:hidden bg-[#151515] py-8 px-8 h-[calc(100vh-var(--header-height))] top-[--header-height]"
|
||||
transition:persist="vertical-nav-from-left"
|
||||
>
|
||||
<VerticalNav showHome={true} />
|
||||
</aside>
|
||||
|
||||
<script>
|
||||
// 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();
|
||||
// });
|
||||
// }
|
||||
|
||||
// JavaScript for toggling the menu
|
||||
document.addEventListener("DOMContentLoaded", function () {
|
||||
const menuToggle = document.querySelector("#menu-toggle");
|
||||
const verticalNavBar = document.querySelector("#vertical-navbar");
|
||||
if (menuToggle) {
|
||||
menuToggle.addEventListener("click", function () {
|
||||
if (verticalNavBar)
|
||||
verticalNavBar.classList.toggle("-translate-x-[200%]");
|
||||
});
|
||||
}
|
||||
|
||||
// Close the menu when a link is clicked
|
||||
const navbarLinks = document.querySelectorAll("#vertical-navbar a");
|
||||
navbarLinks.forEach((link) => {
|
||||
link.addEventListener("click", function () {
|
||||
if (verticalNavBar)
|
||||
verticalNavBar.classList.add("-translate-x-[200%]");
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
// window.onload = function () {
|
||||
// updateDarkModeIcon();
|
||||
// };
|
||||
</script>
|
||||
154
src/components/blocks/verticalNav.astro
Normal file
154
src/components/blocks/verticalNav.astro
Normal file
|
|
@ -0,0 +1,154 @@
|
|||
---
|
||||
type Navigation = Record<
|
||||
string,
|
||||
{ title: string; url: string; order: number }[]
|
||||
>;
|
||||
|
||||
const currentUrl = Astro.request.url;
|
||||
|
||||
const isCurrentUrl = (url: string) => currentUrl.includes(url);
|
||||
|
||||
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,
|
||||
};
|
||||
}
|
||||
|
||||
interface Props {
|
||||
showHome?: boolean | null;
|
||||
}
|
||||
|
||||
const { navigation } = await setup();
|
||||
const { showHome } = Astro.props;
|
||||
---
|
||||
|
||||
<div class="relative">
|
||||
<nav id="vertical-nav-component" class="flex flex-col">
|
||||
{
|
||||
showHome && (
|
||||
<div class="mb-2">
|
||||
<a
|
||||
href="/"
|
||||
class={`no-target-blank hover:no-underline hover:text-white text-lg mt-0
|
||||
${isCurrentUrl("/") ? "text-white" : "text-gray-400"}`}
|
||||
>
|
||||
Home
|
||||
</a>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
{
|
||||
Object.entries(navigation).map(([category, links]) => (
|
||||
<div class="mb-2">
|
||||
<div class="category no-target-blank text-lg font-bold mb-1 mt-0 text-white">
|
||||
{category}
|
||||
</div>
|
||||
<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 transition-colors duration-150 hover:no-underline hover:text-white ${isCurrentUrl(link.url) ? "text-white" : "text-gray-400"}`}
|
||||
>
|
||||
{link.title}
|
||||
</a>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
))
|
||||
}
|
||||
<div class="mb-2">
|
||||
<a
|
||||
href="/groups"
|
||||
class={`no-target-blank transition-colors duration-150 hover:no-underline hover:text-white text-lg mt-0
|
||||
${isCurrentUrl("/groups") ? "text-white" : "text-gray-400"}`}
|
||||
>
|
||||
Groups
|
||||
</a>
|
||||
</div>
|
||||
<div class="mb-2">
|
||||
<a
|
||||
href="/blog"
|
||||
class={`no-target-blank transition-colors duration-150 hover:no-underline hover:text-white text-lg mt-0
|
||||
${isCurrentUrl("/blog") ? "text-white" : "text-gray-400"}`}
|
||||
>
|
||||
Blog
|
||||
</a>
|
||||
</div>
|
||||
<div class="mb-2">
|
||||
<a
|
||||
href="/credits"
|
||||
class={`no-target-blank transition-colors duration-150 hover:no-underline hover:text-white text-lg mt-0
|
||||
${isCurrentUrl("/credits") ? "text-white" : "text-gray-400"}`}
|
||||
>
|
||||
Credits
|
||||
</a>
|
||||
</div>
|
||||
</nav>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
document.addEventListener("astro:page-load", () => {
|
||||
const currentUrl = window.location.pathname;
|
||||
|
||||
const isCurrentUrl = (url: string) => currentUrl === url;
|
||||
|
||||
const links = document.querySelectorAll(
|
||||
"#vertical-nav-component a:not(.category), #vertical-nav-component a > a:not(.category)"
|
||||
);
|
||||
|
||||
// add active class to current url
|
||||
links.forEach((link) => {
|
||||
if (isCurrentUrl(link.getAttribute("href")!)) {
|
||||
link.classList.add("text-white");
|
||||
link.classList.remove("text-gray-400");
|
||||
} else {
|
||||
link.classList.remove("text-white");
|
||||
link.classList.add("text-gray-400");
|
||||
}
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
|
@ -1,230 +0,0 @@
|
|||
<!-- <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"
|
||||
>
|
||||
<div
|
||||
class="lg:flex-1 flex items-center text-xl select-none"
|
||||
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>
|
||||
<div class="flex items-center gap-10">
|
||||
<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>
|
||||
<div
|
||||
class="flex lg:flex-1 justify-end"
|
||||
transition:name="display-toggle"
|
||||
>
|
||||
<button id="theme-toggle" type="button" class="">
|
||||
<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"></path>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script defer>
|
||||
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();
|
||||
};
|
||||
</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();
|
||||
};
|
||||
</script>
|
||||
26
src/components/ui/BlurBackground.astro
Normal file
26
src/components/ui/BlurBackground.astro
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
<div
|
||||
class="bg-[white] h-[34vmax] aspect-square absolute rounded-full bg-[linear-gradient(to_right,#FF7782,_mediumpurple)] animate-[rotate_20s_infinite] opacity-80 origin-center left-1/2 top-1/2"
|
||||
>
|
||||
</div>
|
||||
<div
|
||||
class="h-full flex-grow w-full absolute backdrop-filter backdrop-blur-[12vmax]"
|
||||
>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
@keyframes rotate {
|
||||
from {
|
||||
rotate: 0deg;
|
||||
translate: -50% -50%;
|
||||
}
|
||||
|
||||
50% {
|
||||
scale: 1 1.5;
|
||||
}
|
||||
|
||||
to {
|
||||
rotate: 360deg;
|
||||
translate: -50% -50%;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
15
src/components/ui/HeroTitle.astro
Normal file
15
src/components/ui/HeroTitle.astro
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
<div class="flex flex-col">
|
||||
<div class="text-center text-4xl lg:text-6xl font-bold">
|
||||
<span class="text-slate-200">Getting started with</span>
|
||||
<div
|
||||
class="bg-clip-text text-transparent bg-gradient-pink-cyan animate-gradient py-1 lg:py-3 bg-[length:300%]"
|
||||
>
|
||||
Coworking streams
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
class="mt-2 text-xl text-center flex flex-col justify-center items-center"
|
||||
>
|
||||
Brought to you by RythonDev x Coworking Crew
|
||||
</div>
|
||||
</div>
|
||||
115
src/components/ui/card-hover-effect.tsx
Normal file
115
src/components/ui/card-hover-effect.tsx
Normal file
|
|
@ -0,0 +1,115 @@
|
|||
import { cn } from "../../../utils/cn";
|
||||
import { AnimatePresence, motion } from "framer-motion";
|
||||
import { useState } from "react";
|
||||
|
||||
export const HoverEffect = ({
|
||||
items,
|
||||
className,
|
||||
}: {
|
||||
items: {
|
||||
title: string;
|
||||
description: string;
|
||||
link: string;
|
||||
}[];
|
||||
className?: string;
|
||||
}) => {
|
||||
let [hoveredIndex, setHoveredIndex] = useState<number | null>(null);
|
||||
|
||||
return (
|
||||
<div
|
||||
className={cn(
|
||||
"grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3",
|
||||
className,
|
||||
)}
|
||||
>
|
||||
{items.map((item, idx) => (
|
||||
<a
|
||||
href={item?.link}
|
||||
key={item?.link}
|
||||
className="no-target-blank group relative block h-full w-full p-2 hover:no-underline"
|
||||
onMouseEnter={() => setHoveredIndex(idx)}
|
||||
onMouseLeave={() => setHoveredIndex(null)}
|
||||
>
|
||||
<AnimatePresence>
|
||||
{hoveredIndex === idx && (
|
||||
<motion.span
|
||||
className="absolute inset-0 block h-full w-full rounded-3xl bg-neutral-200 dark:bg-cowo-pink"
|
||||
layoutId="hoverBackground"
|
||||
initial={{ opacity: 0 }}
|
||||
animate={{
|
||||
opacity: 1,
|
||||
transition: { duration: 0.15 },
|
||||
}}
|
||||
exit={{
|
||||
opacity: 0,
|
||||
transition: { duration: 0.15, delay: 0.2 },
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</AnimatePresence>
|
||||
<Card>
|
||||
<CardTitle>{item.title}</CardTitle>
|
||||
<CardDescription>{item.description}</CardDescription>
|
||||
</Card>
|
||||
</a>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export const Card = ({
|
||||
className,
|
||||
children,
|
||||
}: {
|
||||
className?: string;
|
||||
children: React.ReactNode;
|
||||
}) => {
|
||||
return (
|
||||
<div
|
||||
className={cn(
|
||||
"relative z-20 h-full w-full overflow-hidden rounded-2xl border border-transparent bg-[#232323] p-4 group-hover:border-slate-700 dark:border-white/[0.2]",
|
||||
className,
|
||||
)}
|
||||
>
|
||||
<div className="relative z-50">
|
||||
<div className="p-4">{children}</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
export const CardTitle = ({
|
||||
className,
|
||||
children,
|
||||
}: {
|
||||
className?: string;
|
||||
children: React.ReactNode;
|
||||
}) => {
|
||||
return (
|
||||
<h4
|
||||
className={cn(
|
||||
"mt-4 font-bold tracking-wide text-zinc-100",
|
||||
className,
|
||||
)}
|
||||
>
|
||||
{children}
|
||||
</h4>
|
||||
);
|
||||
};
|
||||
export const CardDescription = ({
|
||||
className,
|
||||
children,
|
||||
}: {
|
||||
className?: string;
|
||||
children: React.ReactNode;
|
||||
}) => {
|
||||
return (
|
||||
<p
|
||||
className={cn(
|
||||
"mt-5 text-sm leading-relaxed tracking-wide text-zinc-400",
|
||||
className,
|
||||
)}
|
||||
>
|
||||
{children}
|
||||
</p>
|
||||
);
|
||||
};
|
||||
|
|
@ -1,72 +0,0 @@
|
|||
---
|
||||
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>
|
||||
|
|
@ -104,6 +104,10 @@ Here are the listed pros and cons of using the "Coworking" category, which may o
|
|||
|
||||
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).
|
||||
|
||||
## Edit:
|
||||
|
||||
As of 15th March 2024, the "Coworking" game category has been removed from IGDB and Twitch.
|
||||
|
||||
---
|
||||
|
||||
by [RythonDev](https://twitch.tv/RythonDev)
|
||||
|
|
@ -1,156 +1,35 @@
|
|||
---
|
||||
import Layout from "./Layout.astro";
|
||||
import TableOfContent from "../components/TableOfContent.astro";
|
||||
import VerticalNav from "../components/verticalNav.astro";
|
||||
import TableOfContent from "../components/blocks/TableOfContent.astro";
|
||||
import VerticalNav from "../components/blocks/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>
|
||||
<div class="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 lg:translate-x-0 overflow-y-auto z-30 lg:block lg:sticky py-8 lg:px-4 lg:-mx-4 lg:max-h-[calc(100vh-var(--header-height))] lg:top-[--header-height]"
|
||||
>
|
||||
<VerticalNav />
|
||||
</aside>
|
||||
</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 hidden 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>
|
||||
</Layout>
|
||||
|
|
|
|||
|
|
@ -1,70 +1,21 @@
|
|||
---
|
||||
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();
|
||||
import VerticalNav from "../components/blocks/verticalNav.astro";
|
||||
---
|
||||
|
||||
<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="mx-auto 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 lg:translate-x-0 overflow-y-auto z-30 lg:block lg:sticky py-8 lg:px-4 lg:-mx-4 lg:max-h-[calc(100vh-var(--header-height))] lg:top-[--header-height]"
|
||||
>
|
||||
<VerticalNav />
|
||||
</aside>
|
||||
</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>
|
||||
|
|
@ -74,62 +25,22 @@ const { navigation } = await setup();
|
|||
<TableOfContent headings={headings} />
|
||||
</div>
|
||||
</div> -->
|
||||
<slot />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<slot />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style is:global>
|
||||
h1 {
|
||||
@apply text-4xl font-bold;
|
||||
}
|
||||
<style is:global>
|
||||
span.code-highlight {
|
||||
@apply rounded-md bg-[#323232] px-1 py-1 font-["Lucida_Console",monospace,courier-new] text-sm;
|
||||
}
|
||||
|
||||
h2 {
|
||||
@apply mt-5 scroll-mt-[calc(20px+var(--header-height))] text-3xl font-bold;
|
||||
}
|
||||
code {
|
||||
@apply rounded-md bg-[#323232] px-3 py-3;
|
||||
}
|
||||
|
||||
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 {
|
||||
/* img {
|
||||
@apply h-[100px] max-w-full;
|
||||
} */
|
||||
</style>
|
||||
</style>
|
||||
</Layout>
|
||||
|
|
|
|||
|
|
@ -1,148 +1,100 @@
|
|||
---
|
||||
import Layout from "./Layout.astro";
|
||||
import TableOfContent from "../components/TableOfContent.astro";
|
||||
import VerticalNav from "../components/verticalNav.astro";
|
||||
import TableOfContent from "../components/blocks/TableOfContent.astro";
|
||||
import VerticalNav from "../components/blocks/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.title} description={frontmatter.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">
|
||||
<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="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 -->
|
||||
<TableOfContent headings={headings} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mx-auto 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 lg:translate-x-0 overflow-y-auto z-30 lg:block lg:sticky py-8 lg:px-4 lg:-mx-4 lg:max-h-[calc(100vh-var(--header-height))] lg:top-[--header-height]"
|
||||
>
|
||||
<VerticalNav />
|
||||
</aside>
|
||||
</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-10 pt-8">
|
||||
<slot />
|
||||
</div>
|
||||
<div
|
||||
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 -->
|
||||
<TableOfContent headings={headings} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style is:global>
|
||||
h1 {
|
||||
@apply text-4xl font-bold;
|
||||
}
|
||||
<style is:global>
|
||||
h1 {
|
||||
@apply mb-2 text-4xl font-bold;
|
||||
}
|
||||
|
||||
h2 {
|
||||
@apply mt-5 scroll-mt-[calc(20px+var(--header-height))] text-3xl font-bold;
|
||||
}
|
||||
h2 {
|
||||
@apply mb-2 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;
|
||||
}
|
||||
h3 {
|
||||
@apply mb-2 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;
|
||||
}
|
||||
h4 {
|
||||
@apply mb-2 mt-5 scroll-mt-[calc(14px+var(--header-height))] text-xl font-bold;
|
||||
}
|
||||
|
||||
p {
|
||||
@apply mb-2 mt-2 font-[system-ui] leading-6;
|
||||
}
|
||||
p {
|
||||
@apply mb-2 mt-2 font-[system-ui] leading-6;
|
||||
}
|
||||
|
||||
hr {
|
||||
@apply my-10 border-gray-500;
|
||||
}
|
||||
hr {
|
||||
@apply my-10 border-gray-500;
|
||||
}
|
||||
|
||||
ul {
|
||||
@apply list-outside list-disc leading-7;
|
||||
}
|
||||
ul {
|
||||
@apply list-outside list-disc leading-7;
|
||||
}
|
||||
|
||||
blockquote {
|
||||
@apply my-4 border-l-4 border-gray-500 pl-4;
|
||||
}
|
||||
blockquote {
|
||||
@apply my-4 border-l-4 border-gray-500 pl-4;
|
||||
}
|
||||
|
||||
a {
|
||||
@apply inline-block text-blue-400 hover:underline;
|
||||
}
|
||||
a {
|
||||
@apply inline-block text-blue-400 hover:underline;
|
||||
}
|
||||
|
||||
ul ul {
|
||||
@apply mb-2 ml-5 list-[circle];
|
||||
}
|
||||
ul ul {
|
||||
@apply mb-2 ml-5 list-[circle];
|
||||
}
|
||||
|
||||
ul li {
|
||||
@apply mb-1 ml-5;
|
||||
}
|
||||
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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
code {
|
||||
@apply rounded-md bg-[#323232] px-3 py-3;
|
||||
}
|
||||
|
||||
/* img {
|
||||
/* img {
|
||||
@apply h-[100px] max-w-full;
|
||||
} */
|
||||
</style>
|
||||
</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>
|
||||
<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>
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
---
|
||||
import NavBar from "../components/navBar.astro";
|
||||
import NavBar from "../components/blocks/navBar.astro";
|
||||
import { ViewTransitions } from "astro:transitions";
|
||||
|
||||
export interface Props {
|
||||
title: string;
|
||||
description: string;
|
||||
title: string;
|
||||
description: string;
|
||||
}
|
||||
|
||||
const { title, description } = Astro.props;
|
||||
|
|
@ -12,201 +12,144 @@ const { title, description } = Astro.props;
|
|||
|
||||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="description" content={description} />
|
||||
<meta name="keywords" content="coworking, study, streams" />
|
||||
<meta name="author" content="RyanPython" />
|
||||
<meta name="theme-color" content="#2B2D31" />
|
||||
<meta name="viewport" content="width=device-width" />
|
||||
<link rel="icon" type="image/x-icon" href="/favicon.ico" />
|
||||
<script defer src="/_vercel/insights/script.js"></script>
|
||||
<ViewTransitions />
|
||||
<meta name="generator" content={Astro.generator} />
|
||||
<title>{title}</title>
|
||||
</head>
|
||||
<body>
|
||||
<NavBar />
|
||||
<slot />
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="description" content={description} />
|
||||
<meta name="keywords" content="coworking, study, streams" />
|
||||
<meta name="author" content="RythonDev" />
|
||||
<meta name="theme-color" content="#2B2D31" />
|
||||
<meta name="viewport" content="width=device-width" />
|
||||
<link rel="icon" type="image/x-icon" href="/favicon.ico" />
|
||||
<script is:inline src="/_vercel/insights/script.js"></script>
|
||||
<ViewTransitions />
|
||||
<meta name="generator" content={Astro.generator} />
|
||||
<title>{title}</title>
|
||||
</head>
|
||||
<body>
|
||||
<div class="pt-[var(--header-height)]">
|
||||
<NavBar />
|
||||
<slot />
|
||||
</div>
|
||||
|
||||
<style is:global>
|
||||
@font-face {
|
||||
font-family: "Fredoka";
|
||||
src: url("/fonts/Fredoka-Bold.ttf") format("truetype");
|
||||
font-weight: bold;
|
||||
font-style: normal;
|
||||
}
|
||||
<style is:global>
|
||||
:root {
|
||||
--header-height: 3.5rem;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "Fredoka";
|
||||
src: url("/fonts/Fredoka-Light.ttf") format("truetype");
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
}
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "Fredoka";
|
||||
src: url("/fonts/Fredoka-Medium.ttf") format("truetype");
|
||||
font-weight: 500;
|
||||
font-style: normal;
|
||||
}
|
||||
html {
|
||||
font-family: system-ui, sans-serif;
|
||||
background-color: #171717;
|
||||
color: rgb(255 255 255);
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "Fredoka";
|
||||
src: url("/fonts/Fredoka-Regular.ttf") format("truetype");
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
}
|
||||
html,
|
||||
body {
|
||||
min-height: 100%;
|
||||
/* smooth scroll */
|
||||
scroll-behavior: smooth;
|
||||
font-family: system-ui;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "Montserrat";
|
||||
src: url("/fonts/Montserrat-Bold.ttf") format("truetype");
|
||||
font-weight: bold;
|
||||
font-style: normal;
|
||||
}
|
||||
body {
|
||||
height: 100vh;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "Montserrat";
|
||||
src: url("/fonts/Montserrat-Light.ttf") format("truetype");
|
||||
font-weight: 300;
|
||||
font-style: normal;
|
||||
}
|
||||
code {
|
||||
font-family:
|
||||
Menlo,
|
||||
Monaco,
|
||||
Lucida Console,
|
||||
Liberation Mono,
|
||||
DejaVu Sans Mono,
|
||||
Bitstream Vera Sans Mono,
|
||||
Courier New,
|
||||
monospace;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "Montserrat";
|
||||
src: url("/fonts/Montserrat-Medium.ttf") format("truetype");
|
||||
font-weight: 500;
|
||||
font-style: normal;
|
||||
}
|
||||
nav {
|
||||
font-family: system-ui, sans-serif;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "Montserrat";
|
||||
src: url("/fonts/Montserrat-Regular.ttf") format("truetype");
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
}
|
||||
nav ul a {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "Montserrat";
|
||||
src: url("/fonts/Montserrat-SemiBold.ttf") format("truetype");
|
||||
font-weight: 600;
|
||||
font-style: normal;
|
||||
}
|
||||
a.preview {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "Poppins";
|
||||
src: url("/fonts/Poppins-Light.ttf") format("truetype");
|
||||
font-weight: 300;
|
||||
font-style: normal;
|
||||
}
|
||||
p code {
|
||||
word-break: break-all; /* This will allow the URL to break at any character */
|
||||
display: block; /* Ensures the entire URL is on its own line */
|
||||
width: 100%; /* Make sure the code element takes up the full width of its container */
|
||||
overflow-x: auto;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "Poppins";
|
||||
src: url("/fonts/Poppins-Medium.ttf") format("truetype");
|
||||
font-weight: 500;
|
||||
font-style: normal;
|
||||
}
|
||||
blockquote {
|
||||
@apply my-4 border-l-4 border-gray-500 pl-4;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "Poppins";
|
||||
src: url("/fonts/Poppins-Regular.ttf") format("truetype");
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
}
|
||||
a {
|
||||
@apply inline-block text-blue-400 hover:underline;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "Inter";
|
||||
src: url("/fonts/Inter-Regular.ttf") format("truetype");
|
||||
font-weight: normal;
|
||||
font-style: normal;
|
||||
}
|
||||
ul,
|
||||
ol {
|
||||
@apply list-outside leading-7;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "Inter";
|
||||
src: url("/fonts/Inter-Medium.ttf") format("truetype");
|
||||
font-weight: 500;
|
||||
font-style: normal;
|
||||
}
|
||||
ul {
|
||||
@apply list-disc;
|
||||
}
|
||||
|
||||
:root {
|
||||
--header-height: 3.5rem;
|
||||
}
|
||||
ul ul,
|
||||
ol ul {
|
||||
@apply mb-2 ml-5 list-[circle];
|
||||
}
|
||||
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
ul li,
|
||||
ol li {
|
||||
@apply mb-1 ml-5;
|
||||
}
|
||||
|
||||
html {
|
||||
font-family: system-ui, sans-serif;
|
||||
background-color: #171717;
|
||||
color: rgb(255 255 255);
|
||||
}
|
||||
ol {
|
||||
@apply ml-5 list-outside list-decimal leading-7;
|
||||
}
|
||||
</style>
|
||||
<script is:inline>
|
||||
const theme = (() => {
|
||||
if (
|
||||
typeof localStorage !== "undefined" &&
|
||||
localStorage.getItem("theme")
|
||||
) {
|
||||
return localStorage.getItem("theme");
|
||||
}
|
||||
if (window.matchMedia("(prefers-color-scheme: dark)").matches) {
|
||||
return "dark";
|
||||
}
|
||||
return "light";
|
||||
})();
|
||||
|
||||
html,
|
||||
body {
|
||||
min-height: 100%;
|
||||
/* smooth scroll */
|
||||
scroll-behavior: smooth;
|
||||
}
|
||||
if (theme === "light") {
|
||||
document.documentElement.classList.remove("dark");
|
||||
} else {
|
||||
document.documentElement.classList.add("dark");
|
||||
}
|
||||
window.localStorage.setItem("theme", theme);
|
||||
|
||||
body {
|
||||
height: 100vh;
|
||||
}
|
||||
|
||||
code {
|
||||
font-family:
|
||||
Menlo,
|
||||
Monaco,
|
||||
Lucida Console,
|
||||
Liberation Mono,
|
||||
DejaVu Sans Mono,
|
||||
Bitstream Vera Sans Mono,
|
||||
Courier New,
|
||||
monospace;
|
||||
}
|
||||
|
||||
nav {
|
||||
font-family: system-ui, sans-serif;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
nav ul a {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
a.preview {
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
p code {
|
||||
word-break: break-all; /* This will allow the URL to break at any character */
|
||||
display: block; /* Ensures the entire URL is on its own line */
|
||||
width: 100%; /* Make sure the code element takes up the full width of its container */
|
||||
overflow-x: auto;
|
||||
}
|
||||
</style>
|
||||
<script is:inline>
|
||||
const theme = (() => {
|
||||
if (
|
||||
typeof localStorage !== "undefined" &&
|
||||
localStorage.getItem("theme")
|
||||
) {
|
||||
return localStorage.getItem("theme");
|
||||
}
|
||||
if (window.matchMedia("(prefers-color-scheme: dark)").matches) {
|
||||
return "dark";
|
||||
}
|
||||
return "light";
|
||||
})();
|
||||
|
||||
if (theme === "light") {
|
||||
document.documentElement.classList.remove("dark");
|
||||
} else {
|
||||
document.documentElement.classList.add("dark");
|
||||
}
|
||||
window.localStorage.setItem("theme", theme);
|
||||
</script>
|
||||
</body>
|
||||
// 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>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
|||
|
|
@ -1,26 +1,26 @@
|
|||
---
|
||||
import BlogsLayout from "../../layouts/BlogsLayout.astro";
|
||||
import BlogPost from "../../components/BlogPostPreview.astro";
|
||||
import BlogPost from "../../components/blocks/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!"
|
||||
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>
|
||||
<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>
|
||||
|
|
|
|||
|
|
@ -16,6 +16,18 @@ Credits to the wonderful team of people behind this guide!
|
|||
|
||||
Main developer of the project
|
||||
|
||||
- [Twitch](https://twitch.tv/RythonDev)
|
||||
- [YouTube](https://youtube.com/@RythonDev)
|
||||
- [Website](https://rython.dev/)
|
||||
<div class="flex flex-row gap-2">
|
||||
|
||||
[](https://twitch.tv/RythonDev)
|
||||
|
||||
[](https://youtube.com/@RythonDev)
|
||||
|
||||
[](https://rython.dev/)
|
||||
|
||||
[](https://ko-fi.com/rython)
|
||||
|
||||
</div>
|
||||
|
||||
<!-- REFERENCES FOR BADGES/ICONS -->
|
||||
<!-- https://badges.pages.dev/ -->
|
||||
<!-- https://shields.io/badges -->
|
||||
|
|
@ -17,16 +17,33 @@ Useful bots to add to your stream!
|
|||
|
||||
<div class="flex flex-row gap-2">
|
||||
|
||||
Available on:
|
||||
|
||||

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

|
||||
</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!
|
||||

|
||||
|
||||
### [Nightbot 🔗](https://nightbot.tv/)
|
||||
|
||||
<div class="flex flex-row gap-2">
|
||||
|
||||
Available on:
|
||||
|
||||

|
||||
|
||||

|
||||
|
|
@ -34,16 +51,18 @@ Sery Bot is a moderation bot providing anti-hate raid and anti-follow bot protec
|
|||
|
||||
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)
|
||||
### [BotRix 🔗](https://botrix.live/)
|
||||
|
||||
<div class="flex flex-row gap-2">
|
||||
|
||||
Available on:
|
||||
|
||||

|
||||
|
||||

|
||||
</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!
|
||||

|
||||
BotRix is a chat bot that offers features and tools to enhance your community experience. You can use BotRix to moderate, send notifications, play minigames and more on Twitch, YouTube and Discord.
|
||||
|
||||
---
|
||||
|
||||
|
|
@ -53,27 +72,29 @@ MohCitrus is a translator bot made by [MohFocus (Twitch)](https://twitch.tv/MohF
|
|||
|
||||
<div class="flex flex-row gap-2">
|
||||
|
||||
Available on:
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||

|
||||
</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.
|
||||
Supercharge your livestream! Add advanced levels of interactivity to your streams with Streamer.bot.
|
||||
|
||||
### [Mix It Up bot 🔗](https://mixitupapp.com/)
|
||||
|
||||
<div class="flex flex-row gap-2">
|
||||
|
||||
Available on:
|
||||
|
||||

|
||||
|
||||

|
||||
</div>
|
||||
|
||||
- Windows only!
|
||||

|
||||
</div>
|
||||
|
||||
Mix It Up is a free, full featured, community driven, open-source stream bot developed by streamers for streamers.
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ order: 1
|
|||
|
||||
# Music and Audio
|
||||
|
||||
Every Coworking & Study stream has their vibe based on their stream audio!
|
||||
The vibe of a coworking stream is determined by the background music or audio!
|
||||
|
||||
---
|
||||
|
||||
|
|
@ -116,12 +116,17 @@ There you can have your different outputs for different programmes. For example,
|
|||
|
||||
### Complicated ways
|
||||
|
||||
- #### [VoicemeeterBanana](https://vb-audio.com/Voicemeeter/banana.htm) (Windows only!)
|
||||
- #### [VoicemeeterBanana](https://vb-audio.com/Voicemeeter/banana.htm)
|
||||

|
||||
|
||||
- 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!)
|
||||
|
||||
- #### [BlackHole audio](https://obsproject.com/forum/resources/mac-desktop-audio-using-blackhole.1191/)
|
||||

|
||||
- Free! Integrates with OBS
|
||||
- #### [GroundControl Caster](https://gingeraudio.com/groundcontrol-caster/) (Mac only!)
|
||||
|
||||
- #### [GroundControl Caster](https://gingeraudio.com/groundcontrol-caster/)
|
||||

|
||||
- Free! Integrates with Twitch, OBS, StreamLabs, Zoom, FaceTime etc.
|
||||
|
|
|
|||
|
|
@ -1,62 +1,17 @@
|
|||
---
|
||||
import Layout from "../layouts/Layout.astro";
|
||||
import Hero from "../components/blocks/Hero.astro";
|
||||
import BlurBackground from "../components/ui/BlurBackground.astro";
|
||||
---
|
||||
|
||||
<Layout
|
||||
title="Get started with Coworking streams"
|
||||
description="A guide for new and existing coworking streamers!"
|
||||
title="Get started with Coworking streams"
|
||||
description="A guide for new and existing coworking streamers!"
|
||||
>
|
||||
<div class="relative flex justify-center items-center h-screen">
|
||||
<div class="flex flex-col">
|
||||
<div
|
||||
class="text-center text-4xl font-bold font-['Inter'] leading-10"
|
||||
>
|
||||
<span class="mb-2">Getting started with</span>
|
||||
<div
|
||||
class="bg-clip-text text-transparent bg-gradient-pink-cyan py-2"
|
||||
>
|
||||
Coworking streams
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex mt-5 items-center gap-10">
|
||||
<a
|
||||
href="/get-started/introduction"
|
||||
class="bg-cowo-pink text-white
|
||||
text-lg
|
||||
px-5 py-2
|
||||
rounded-md font-medium
|
||||
duration-150
|
||||
hover:text-cowo-pink hover:bg-white"
|
||||
>
|
||||
Get started
|
||||
</a>
|
||||
<a
|
||||
href="/guide/general-tips"
|
||||
class="font-medium flex items-center text-lg
|
||||
hover:underline
|
||||
duration-150"
|
||||
>
|
||||
Check out our guide <svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke-width="1.5"
|
||||
stroke="currentColor"
|
||||
class="w-4 h-4"
|
||||
>
|
||||
<path
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
d="m8.25 4.5 7.5 7.5-7.5 7.5"></path>
|
||||
</svg>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
<!-- <div
|
||||
class="absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2"
|
||||
>
|
||||
</div> -->
|
||||
</div>
|
||||
<div class="relative overflow-hidden">
|
||||
<BlurBackground />
|
||||
<div class="flex justify-center items-start pb-10">
|
||||
<Hero />
|
||||
</div>
|
||||
</div>
|
||||
</Layout>
|
||||
|
||||
<style></style>
|
||||
|
|
|
|||
|
|
@ -4,10 +4,8 @@ module.exports = {
|
|||
theme: {
|
||||
extend: {
|
||||
backgroundImage: (theme) => ({
|
||||
"gradient-blob":
|
||||
"linear-gradient(to right, #FF7782, rgba(0,0,0,0))",
|
||||
"gradient-pink-cyan":
|
||||
"linear-gradient(to right, #FF7782, #8CC0DE)",
|
||||
"linear-gradient(to right, #FF7782, aquamarine)",
|
||||
}),
|
||||
keyframes: {
|
||||
rotate: {
|
||||
|
|
@ -15,14 +13,26 @@ module.exports = {
|
|||
"50%": { scale: "1 1.5" },
|
||||
"100%": { transform: "rotate(360deg)" },
|
||||
},
|
||||
gradient: {
|
||||
"0%": {
|
||||
"background-position": "0% 50%",
|
||||
},
|
||||
"50%": {
|
||||
"background-position": "100% 50%",
|
||||
},
|
||||
"100%": {
|
||||
"background-position": "0% 50%",
|
||||
},
|
||||
},
|
||||
},
|
||||
animation: {
|
||||
"spin-slow": "rotate 5s linear infinite",
|
||||
"spin-slow": "rotate 15s linear infinite",
|
||||
gradient: "gradient 15s ease infinite",
|
||||
},
|
||||
colors: {
|
||||
"cowo-pink": "#FF7782",
|
||||
"secondary": "#171717",
|
||||
"primary": "#fafafa",
|
||||
secondary: "#171717",
|
||||
primary: "#fafafa",
|
||||
},
|
||||
},
|
||||
},
|
||||
|
|
|
|||
|
|
@ -1,3 +1,7 @@
|
|||
{
|
||||
"extends": "astro/tsconfigs/strict"
|
||||
"extends": "astro/tsconfigs/strict",
|
||||
"compilerOptions": {
|
||||
"jsx": "react-jsx",
|
||||
"jsxImportSource": "react"
|
||||
}
|
||||
}
|
||||
7
utils/cn.ts
Normal file
7
utils/cn.ts
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
import type { ClassValue } from "clsx";
|
||||
import { clsx } from "clsx";
|
||||
import { twMerge } from "tailwind-merge";
|
||||
|
||||
export function cn(...inputs: ClassValue[]) {
|
||||
return twMerge(clsx(inputs));
|
||||
}
|
||||
Loading…
Reference in a new issue