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.
|
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 { defineConfig } from "astro/config";
|
||||||
import tailwind from "@astrojs/tailwind";
|
import tailwind from "@astrojs/tailwind";
|
||||||
|
|
||||||
import mdx from "@astrojs/mdx";
|
import mdx from "@astrojs/mdx";
|
||||||
|
|
||||||
|
import react from "@astrojs/react";
|
||||||
|
|
||||||
// https://astro.build/config
|
// https://astro.build/config
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
integrations: [tailwind(), mdx()],
|
integrations: [tailwind(), mdx(), react()],
|
||||||
server: {
|
server: {
|
||||||
port: 3000
|
port: 3000,
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
284
package-lock.json
generated
284
package-lock.json
generated
|
|
@ -9,13 +9,23 @@
|
||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@astrojs/mdx": "^2.1.1",
|
"@astrojs/mdx": "^2.1.1",
|
||||||
|
"@astrojs/react": "^3.1.0",
|
||||||
"@astrojs/tailwind": "^5.1.0",
|
"@astrojs/tailwind": "^5.1.0",
|
||||||
"@astrojs/ts-plugin": "^1.5.3",
|
"@astrojs/ts-plugin": "^1.5.3",
|
||||||
|
"@types/react": "^18.2.65",
|
||||||
|
"@types/react-dom": "^18.2.22",
|
||||||
"@vercel/analytics": "^1.0.1",
|
"@vercel/analytics": "^1.0.1",
|
||||||
"astro": "^4.4.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"
|
"tailwindcss": "^3.4.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@types/react-router-dom": "^5.3.3",
|
||||||
"prettier": "^3.2.5",
|
"prettier": "^3.2.5",
|
||||||
"prettier-plugin-tailwindcss": "^0.5.11"
|
"prettier-plugin-tailwindcss": "^0.5.11"
|
||||||
}
|
}
|
||||||
|
|
@ -113,6 +123,24 @@
|
||||||
"node": ">=18.14.1"
|
"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": {
|
"node_modules/@astrojs/tailwind": {
|
||||||
"version": "5.1.0",
|
"version": "5.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/@astrojs/tailwind/-/tailwind-5.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/@astrojs/tailwind/-/tailwind-5.1.0.tgz",
|
||||||
|
|
@ -459,6 +487,45 @@
|
||||||
"@babel/core": "^7.0.0-0"
|
"@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": {
|
"node_modules/@babel/template": {
|
||||||
"version": "7.23.9",
|
"version": "7.23.9",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/template/-/template-7.23.9.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/template/-/template-7.23.9.tgz",
|
||||||
|
|
@ -1015,6 +1082,14 @@
|
||||||
"node": ">=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": {
|
"node_modules/@rollup/rollup-android-arm-eabi": {
|
||||||
"version": "4.12.0",
|
"version": "4.12.0",
|
||||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.12.0.tgz",
|
"resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.12.0.tgz",
|
||||||
|
|
@ -1245,6 +1320,12 @@
|
||||||
"@types/unist": "*"
|
"@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": {
|
"node_modules/@types/mdast": {
|
||||||
"version": "4.0.3",
|
"version": "4.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-4.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/@types/mdast/-/mdast-4.0.3.tgz",
|
||||||
|
|
@ -1286,6 +1367,55 @@
|
||||||
"undici-types": "~5.26.4"
|
"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": {
|
"node_modules/@types/unist": {
|
||||||
"version": "3.0.2",
|
"version": "3.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.2.tgz",
|
"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",
|
"resolved": "https://registry.npmjs.org/@vercel/analytics/-/analytics-1.0.1.tgz",
|
||||||
"integrity": "sha512-Ux0c9qUfkcPqng3vrR0GTrlQdqNJ2JREn/2ydrVuKwM3RtMfF2mWX31Ijqo1opSjNAq6rK76PwtANw6kl6TAow=="
|
"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": {
|
"node_modules/@volar/language-core": {
|
||||||
"version": "2.0.4",
|
"version": "2.0.4",
|
||||||
"resolved": "https://registry.npmjs.org/@volar/language-core/-/language-core-2.0.4.tgz",
|
"resolved": "https://registry.npmjs.org/@volar/language-core/-/language-core-2.0.4.tgz",
|
||||||
|
|
@ -2118,6 +2266,11 @@
|
||||||
"node": ">=4"
|
"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": {
|
"node_modules/debug": {
|
||||||
"version": "4.3.4",
|
"version": "4.3.4",
|
||||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
|
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
|
||||||
|
|
@ -2568,6 +2721,30 @@
|
||||||
"url": "https://github.com/sponsors/rawify"
|
"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": {
|
"node_modules/fs-constants": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz",
|
||||||
|
|
@ -3425,6 +3602,17 @@
|
||||||
"url": "https://github.com/sponsors/wooorm"
|
"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": {
|
"node_modules/lru-cache": {
|
||||||
"version": "5.1.1",
|
"version": "5.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz",
|
||||||
|
|
@ -5451,6 +5639,67 @@
|
||||||
"rc": "cli.js"
|
"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": {
|
"node_modules/read-cache": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz",
|
||||||
|
|
@ -5491,6 +5740,11 @@
|
||||||
"node": ">=8.10.0"
|
"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": {
|
"node_modules/rehype": {
|
||||||
"version": "13.0.1",
|
"version": "13.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/rehype/-/rehype-13.0.1.tgz",
|
"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": {
|
"node_modules/section-matter": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/section-matter/-/section-matter-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/section-matter/-/section-matter-1.0.0.tgz",
|
||||||
|
|
@ -6545,6 +6807,18 @@
|
||||||
"url": "https://github.com/sponsors/ljharb"
|
"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": {
|
"node_modules/tailwindcss": {
|
||||||
"version": "3.4.1",
|
"version": "3.4.1",
|
||||||
"resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.1.tgz",
|
"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": {
|
"node_modules/tunnel-agent": {
|
||||||
"version": "0.6.0",
|
"version": "0.6.0",
|
||||||
"resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz",
|
"resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz",
|
||||||
|
|
@ -6728,6 +7007,11 @@
|
||||||
"url": "https://github.com/sponsors/sindresorhus"
|
"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": {
|
"node_modules/undici-types": {
|
||||||
"version": "5.26.5",
|
"version": "5.26.5",
|
||||||
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz",
|
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz",
|
||||||
|
|
|
||||||
10
package.json
10
package.json
|
|
@ -11,13 +11,23 @@
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@astrojs/mdx": "^2.1.1",
|
"@astrojs/mdx": "^2.1.1",
|
||||||
|
"@astrojs/react": "^3.1.0",
|
||||||
"@astrojs/tailwind": "^5.1.0",
|
"@astrojs/tailwind": "^5.1.0",
|
||||||
"@astrojs/ts-plugin": "^1.5.3",
|
"@astrojs/ts-plugin": "^1.5.3",
|
||||||
|
"@types/react": "^18.2.65",
|
||||||
|
"@types/react-dom": "^18.2.22",
|
||||||
"@vercel/analytics": "^1.0.1",
|
"@vercel/analytics": "^1.0.1",
|
||||||
"astro": "^4.4.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"
|
"tailwindcss": "^3.4.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@types/react-router-dom": "^5.3.3",
|
||||||
"prettier": "^3.2.5",
|
"prettier": "^3.2.5",
|
||||||
"prettier-plugin-tailwindcss": "^0.5.11"
|
"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).
|
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)
|
by [RythonDev](https://twitch.tv/RythonDev)
|
||||||
|
|
@ -1,69 +1,21 @@
|
||||||
---
|
---
|
||||||
import Layout from "./Layout.astro";
|
import Layout from "./Layout.astro";
|
||||||
import TableOfContent from "../components/TableOfContent.astro";
|
import TableOfContent from "../components/blocks/TableOfContent.astro";
|
||||||
import VerticalNav from "../components/verticalNav.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 { frontmatter, headings } = Astro.props;
|
||||||
const { navigation } = await setup();
|
|
||||||
---
|
---
|
||||||
|
|
||||||
<Layout title={frontmatter.heading} description={frontmatter.subheading}>
|
<Layout title={frontmatter.heading} description={frontmatter.subheading}>
|
||||||
<div class="pt-14 mx-auto px-4 sm:px-6 max-w-7xl">
|
<div class="mx-auto px-4 sm:px-6 max-w-7xl">
|
||||||
<div class="flex flex-col lg:grid lg:grid-cols-10">
|
<div class="flex flex-col lg:grid lg:grid-cols-10">
|
||||||
<!-- vertical navbar -->
|
<!-- vertical navbar -->
|
||||||
<div class="lg:col-span-2" transition:name="vertical-navbar">
|
<div class="lg:col-span-2" transition:name="vertical-navbar">
|
||||||
<VerticalNav navigation={navigation} />
|
<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>
|
||||||
<div class="lg:col-span-8">
|
<div class="lg:col-span-8">
|
||||||
<div class="flex flex-col lg:grid lg:grid-cols-10">
|
<div class="flex flex-col lg:grid lg:grid-cols-10">
|
||||||
|
|
@ -71,7 +23,7 @@ const { navigation } = await setup();
|
||||||
<slot />
|
<slot />
|
||||||
</div>
|
</div>
|
||||||
<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="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 -->
|
<!-- TOC -->
|
||||||
<TableOfContent headings={headings} />
|
<TableOfContent headings={headings} />
|
||||||
|
|
@ -80,77 +32,4 @@ const { navigation } = await setup();
|
||||||
</div>
|
</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>
|
</Layout>
|
||||||
|
|
|
||||||
|
|
@ -1,67 +1,18 @@
|
||||||
---
|
---
|
||||||
import Layout from "./Layout.astro";
|
import Layout from "./Layout.astro";
|
||||||
import VerticalNav from "../components/verticalNav.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 { navigation } = await setup();
|
|
||||||
---
|
---
|
||||||
|
|
||||||
<Layout title={Astro.props.title} description={Astro.props.description}>
|
<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="mx-auto px-6 max-w-7xl">
|
||||||
<div class="flex flex-col lg:grid lg:grid-cols-10">
|
<div class="flex flex-col lg:grid lg:grid-cols-10">
|
||||||
<!-- vertical navbar -->
|
<!-- vertical navbar -->
|
||||||
<div class="lg:col-span-2" transition:name="vertical-navbar">
|
<div class="lg:col-span-2" transition:name="vertical-navbar">
|
||||||
<VerticalNav navigation={navigation} />
|
<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>
|
||||||
<div class="lg:col-span-8 pt-8">
|
<div class="lg:col-span-8 pt-8">
|
||||||
<!-- <div class="flex flex-col lg:grid lg:grid-cols-10">
|
<!-- <div class="flex flex-col lg:grid lg:grid-cols-10">
|
||||||
|
|
@ -80,46 +31,6 @@ const { navigation } = await setup();
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<style is:global>
|
<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 {
|
span.code-highlight {
|
||||||
@apply rounded-md bg-[#323232] px-1 py-1 font-["Lucida_Console",monospace,courier-new] text-sm;
|
@apply rounded-md bg-[#323232] px-1 py-1 font-["Lucida_Console",monospace,courier-new] text-sm;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,69 +1,21 @@
|
||||||
---
|
---
|
||||||
import Layout from "./Layout.astro";
|
import Layout from "./Layout.astro";
|
||||||
import TableOfContent from "../components/TableOfContent.astro";
|
import TableOfContent from "../components/blocks/TableOfContent.astro";
|
||||||
import VerticalNav from "../components/verticalNav.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 { frontmatter, headings } = Astro.props;
|
||||||
const { navigation } = await setup();
|
|
||||||
---
|
---
|
||||||
|
|
||||||
<Layout title={frontmatter.title} description={frontmatter.description}>
|
<Layout title={frontmatter.title} description={frontmatter.description}>
|
||||||
<div class="pt-14 mx-auto px-4 sm:px-6 max-w-7xl">
|
<div class="mx-auto px-6 max-w-7xl">
|
||||||
<div class="flex flex-col lg:grid lg:grid-cols-10">
|
<div class="flex flex-col lg:grid lg:grid-cols-10">
|
||||||
<!-- vertical navbar -->
|
<!-- vertical navbar -->
|
||||||
<div class="lg:col-span-2" transition:name="vertical-navbar">
|
<div class="lg:col-span-2" transition:name="vertical-navbar">
|
||||||
<VerticalNav navigation={navigation} />
|
<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>
|
||||||
<div class="lg:col-span-8">
|
<div class="lg:col-span-8">
|
||||||
<div class="flex flex-col lg:grid lg:grid-cols-10">
|
<div class="flex flex-col lg:grid lg:grid-cols-10">
|
||||||
|
|
@ -83,19 +35,19 @@ const { navigation } = await setup();
|
||||||
|
|
||||||
<style is:global>
|
<style is:global>
|
||||||
h1 {
|
h1 {
|
||||||
@apply text-4xl font-bold;
|
@apply mb-2 text-4xl font-bold;
|
||||||
}
|
}
|
||||||
|
|
||||||
h2 {
|
h2 {
|
||||||
@apply mt-5 scroll-mt-[calc(20px+var(--header-height))] text-3xl font-bold;
|
@apply mb-2 mt-5 scroll-mt-[calc(20px+var(--header-height))] text-3xl font-bold;
|
||||||
}
|
}
|
||||||
|
|
||||||
h3 {
|
h3 {
|
||||||
@apply mt-5 scroll-mt-[calc(17px+var(--header-height))] text-2xl font-bold;
|
@apply mb-2 mt-5 scroll-mt-[calc(17px+var(--header-height))] text-2xl font-bold;
|
||||||
}
|
}
|
||||||
|
|
||||||
h4 {
|
h4 {
|
||||||
@apply mt-5 scroll-mt-[calc(14px+var(--header-height))] text-xl font-bold;
|
@apply mb-2 mt-5 scroll-mt-[calc(14px+var(--header-height))] text-xl font-bold;
|
||||||
}
|
}
|
||||||
|
|
||||||
p {
|
p {
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
---
|
---
|
||||||
import NavBar from "../components/navBar.astro";
|
import NavBar from "../components/blocks/navBar.astro";
|
||||||
import { ViewTransitions } from "astro:transitions";
|
import { ViewTransitions } from "astro:transitions";
|
||||||
|
|
||||||
export interface Props {
|
export interface Props {
|
||||||
|
|
@ -16,118 +16,22 @@ const { title, description } = Astro.props;
|
||||||
<meta charset="UTF-8" />
|
<meta charset="UTF-8" />
|
||||||
<meta name="description" content={description} />
|
<meta name="description" content={description} />
|
||||||
<meta name="keywords" content="coworking, study, streams" />
|
<meta name="keywords" content="coworking, study, streams" />
|
||||||
<meta name="author" content="RyanPython" />
|
<meta name="author" content="RythonDev" />
|
||||||
<meta name="theme-color" content="#2B2D31" />
|
<meta name="theme-color" content="#2B2D31" />
|
||||||
<meta name="viewport" content="width=device-width" />
|
<meta name="viewport" content="width=device-width" />
|
||||||
<link rel="icon" type="image/x-icon" href="/favicon.ico" />
|
<link rel="icon" type="image/x-icon" href="/favicon.ico" />
|
||||||
<script defer src="/_vercel/insights/script.js"></script>
|
<script is:inline src="/_vercel/insights/script.js"></script>
|
||||||
<ViewTransitions />
|
<ViewTransitions />
|
||||||
<meta name="generator" content={Astro.generator} />
|
<meta name="generator" content={Astro.generator} />
|
||||||
<title>{title}</title>
|
<title>{title}</title>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
<div class="pt-[var(--header-height)]">
|
||||||
<NavBar />
|
<NavBar />
|
||||||
<slot />
|
<slot />
|
||||||
|
</div>
|
||||||
|
|
||||||
<style is:global>
|
<style is:global>
|
||||||
@font-face {
|
|
||||||
font-family: "Fredoka";
|
|
||||||
src: url("/fonts/Fredoka-Bold.ttf") format("truetype");
|
|
||||||
font-weight: bold;
|
|
||||||
font-style: normal;
|
|
||||||
}
|
|
||||||
|
|
||||||
@font-face {
|
|
||||||
font-family: "Fredoka";
|
|
||||||
src: url("/fonts/Fredoka-Light.ttf") format("truetype");
|
|
||||||
font-weight: normal;
|
|
||||||
font-style: normal;
|
|
||||||
}
|
|
||||||
|
|
||||||
@font-face {
|
|
||||||
font-family: "Fredoka";
|
|
||||||
src: url("/fonts/Fredoka-Medium.ttf") format("truetype");
|
|
||||||
font-weight: 500;
|
|
||||||
font-style: normal;
|
|
||||||
}
|
|
||||||
|
|
||||||
@font-face {
|
|
||||||
font-family: "Fredoka";
|
|
||||||
src: url("/fonts/Fredoka-Regular.ttf") format("truetype");
|
|
||||||
font-weight: normal;
|
|
||||||
font-style: normal;
|
|
||||||
}
|
|
||||||
|
|
||||||
@font-face {
|
|
||||||
font-family: "Montserrat";
|
|
||||||
src: url("/fonts/Montserrat-Bold.ttf") format("truetype");
|
|
||||||
font-weight: bold;
|
|
||||||
font-style: normal;
|
|
||||||
}
|
|
||||||
|
|
||||||
@font-face {
|
|
||||||
font-family: "Montserrat";
|
|
||||||
src: url("/fonts/Montserrat-Light.ttf") format("truetype");
|
|
||||||
font-weight: 300;
|
|
||||||
font-style: normal;
|
|
||||||
}
|
|
||||||
|
|
||||||
@font-face {
|
|
||||||
font-family: "Montserrat";
|
|
||||||
src: url("/fonts/Montserrat-Medium.ttf") format("truetype");
|
|
||||||
font-weight: 500;
|
|
||||||
font-style: normal;
|
|
||||||
}
|
|
||||||
|
|
||||||
@font-face {
|
|
||||||
font-family: "Montserrat";
|
|
||||||
src: url("/fonts/Montserrat-Regular.ttf") format("truetype");
|
|
||||||
font-weight: normal;
|
|
||||||
font-style: normal;
|
|
||||||
}
|
|
||||||
|
|
||||||
@font-face {
|
|
||||||
font-family: "Montserrat";
|
|
||||||
src: url("/fonts/Montserrat-SemiBold.ttf") format("truetype");
|
|
||||||
font-weight: 600;
|
|
||||||
font-style: normal;
|
|
||||||
}
|
|
||||||
|
|
||||||
@font-face {
|
|
||||||
font-family: "Poppins";
|
|
||||||
src: url("/fonts/Poppins-Light.ttf") format("truetype");
|
|
||||||
font-weight: 300;
|
|
||||||
font-style: normal;
|
|
||||||
}
|
|
||||||
|
|
||||||
@font-face {
|
|
||||||
font-family: "Poppins";
|
|
||||||
src: url("/fonts/Poppins-Medium.ttf") format("truetype");
|
|
||||||
font-weight: 500;
|
|
||||||
font-style: normal;
|
|
||||||
}
|
|
||||||
|
|
||||||
@font-face {
|
|
||||||
font-family: "Poppins";
|
|
||||||
src: url("/fonts/Poppins-Regular.ttf") format("truetype");
|
|
||||||
font-weight: normal;
|
|
||||||
font-style: normal;
|
|
||||||
}
|
|
||||||
|
|
||||||
@font-face {
|
|
||||||
font-family: "Inter";
|
|
||||||
src: url("/fonts/Inter-Regular.ttf") format("truetype");
|
|
||||||
font-weight: normal;
|
|
||||||
font-style: normal;
|
|
||||||
}
|
|
||||||
|
|
||||||
@font-face {
|
|
||||||
font-family: "Inter";
|
|
||||||
src: url("/fonts/Inter-Medium.ttf") format("truetype");
|
|
||||||
font-weight: 500;
|
|
||||||
font-style: normal;
|
|
||||||
}
|
|
||||||
|
|
||||||
:root {
|
:root {
|
||||||
--header-height: 3.5rem;
|
--header-height: 3.5rem;
|
||||||
}
|
}
|
||||||
|
|
@ -149,6 +53,7 @@ const { title, description } = Astro.props;
|
||||||
min-height: 100%;
|
min-height: 100%;
|
||||||
/* smooth scroll */
|
/* smooth scroll */
|
||||||
scroll-behavior: smooth;
|
scroll-behavior: smooth;
|
||||||
|
font-family: system-ui;
|
||||||
}
|
}
|
||||||
|
|
||||||
body {
|
body {
|
||||||
|
|
@ -186,6 +91,37 @@ const { title, description } = Astro.props;
|
||||||
width: 100%; /* Make sure the code element takes up the full width of its container */
|
width: 100%; /* Make sure the code element takes up the full width of its container */
|
||||||
overflow-x: auto;
|
overflow-x: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
blockquote {
|
||||||
|
@apply my-4 border-l-4 border-gray-500 pl-4;
|
||||||
|
}
|
||||||
|
|
||||||
|
a {
|
||||||
|
@apply inline-block text-blue-400 hover:underline;
|
||||||
|
}
|
||||||
|
|
||||||
|
ul,
|
||||||
|
ol {
|
||||||
|
@apply list-outside leading-7;
|
||||||
|
}
|
||||||
|
|
||||||
|
ul {
|
||||||
|
@apply list-disc;
|
||||||
|
}
|
||||||
|
|
||||||
|
ul ul,
|
||||||
|
ol ul {
|
||||||
|
@apply mb-2 ml-5 list-[circle];
|
||||||
|
}
|
||||||
|
|
||||||
|
ul li,
|
||||||
|
ol li {
|
||||||
|
@apply mb-1 ml-5;
|
||||||
|
}
|
||||||
|
|
||||||
|
ol {
|
||||||
|
@apply ml-5 list-outside list-decimal leading-7;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
<script is:inline>
|
<script is:inline>
|
||||||
const theme = (() => {
|
const theme = (() => {
|
||||||
|
|
@ -207,6 +143,13 @@ const { title, description } = Astro.props;
|
||||||
document.documentElement.classList.add("dark");
|
document.documentElement.classList.add("dark");
|
||||||
}
|
}
|
||||||
window.localStorage.setItem("theme", theme);
|
window.localStorage.setItem("theme", theme);
|
||||||
|
|
||||||
|
// 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>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
---
|
---
|
||||||
import BlogsLayout from "../../layouts/BlogsLayout.astro";
|
import BlogsLayout from "../../layouts/BlogsLayout.astro";
|
||||||
import BlogPost from "../../components/BlogPostPreview.astro";
|
import BlogPost from "../../components/blocks/BlogPostPreview.astro";
|
||||||
import { getCollection } from "astro:content";
|
import { getCollection } from "astro:content";
|
||||||
|
|
||||||
const allPosts = await getCollection("posts");
|
const allPosts = await getCollection("posts");
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,18 @@ Credits to the wonderful team of people behind this guide!
|
||||||
|
|
||||||
Main developer of the project
|
Main developer of the project
|
||||||
|
|
||||||
- [Twitch](https://twitch.tv/RythonDev)
|
<div class="flex flex-row gap-2">
|
||||||
- [YouTube](https://youtube.com/@RythonDev)
|
|
||||||
- [Website](https://rython.dev/)
|
[](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">
|
<div class="flex flex-row gap-2">
|
||||||
|
|
||||||
|
Available on:
|
||||||
|
|
||||||

|

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

|

|
||||||
|
|
||||||
|

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

|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
@ -53,27 +72,29 @@ MohCitrus is a translator bot made by [MohFocus (Twitch)](https://twitch.tv/MohF
|
||||||
|
|
||||||
<div class="flex flex-row gap-2">
|
<div class="flex flex-row gap-2">
|
||||||
|
|
||||||
|
Available on:
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
|

|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
- Windows only!
|
Supercharge your livestream! Add advanced levels of interactivity to your streams with Streamer.bot.
|
||||||
|
|
||||||
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/)
|
### [Mix It Up bot 🔗](https://mixitupapp.com/)
|
||||||
|
|
||||||
<div class="flex flex-row gap-2">
|
<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.
|
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
|
# 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
|
### 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.
|
- 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
|
- 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)
|
- 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
|
- 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.
|
- Free! Integrates with Twitch, OBS, StreamLabs, Zoom, FaceTime etc.
|
||||||
|
|
|
||||||
|
|
@ -1,62 +1,17 @@
|
||||||
---
|
---
|
||||||
import Layout from "../layouts/Layout.astro";
|
import Layout from "../layouts/Layout.astro";
|
||||||
|
import Hero from "../components/blocks/Hero.astro";
|
||||||
|
import BlurBackground from "../components/ui/BlurBackground.astro";
|
||||||
---
|
---
|
||||||
|
|
||||||
<Layout
|
<Layout
|
||||||
title="Get started with Coworking streams"
|
title="Get started with Coworking streams"
|
||||||
description="A guide for new and existing coworking streamers!"
|
description="A guide for new and existing coworking streamers!"
|
||||||
>
|
>
|
||||||
<div class="relative flex justify-center items-center h-screen">
|
<div class="relative overflow-hidden">
|
||||||
<div class="flex flex-col">
|
<BlurBackground />
|
||||||
<div
|
<div class="flex justify-center items-start pb-10">
|
||||||
class="text-center text-4xl font-bold font-['Inter'] leading-10"
|
<Hero />
|
||||||
>
|
|
||||||
<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>
|
</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>
|
|
||||||
</Layout>
|
</Layout>
|
||||||
|
|
||||||
<style></style>
|
|
||||||
|
|
|
||||||
|
|
@ -4,10 +4,8 @@ module.exports = {
|
||||||
theme: {
|
theme: {
|
||||||
extend: {
|
extend: {
|
||||||
backgroundImage: (theme) => ({
|
backgroundImage: (theme) => ({
|
||||||
"gradient-blob":
|
|
||||||
"linear-gradient(to right, #FF7782, rgba(0,0,0,0))",
|
|
||||||
"gradient-pink-cyan":
|
"gradient-pink-cyan":
|
||||||
"linear-gradient(to right, #FF7782, #8CC0DE)",
|
"linear-gradient(to right, #FF7782, aquamarine)",
|
||||||
}),
|
}),
|
||||||
keyframes: {
|
keyframes: {
|
||||||
rotate: {
|
rotate: {
|
||||||
|
|
@ -15,14 +13,26 @@ module.exports = {
|
||||||
"50%": { scale: "1 1.5" },
|
"50%": { scale: "1 1.5" },
|
||||||
"100%": { transform: "rotate(360deg)" },
|
"100%": { transform: "rotate(360deg)" },
|
||||||
},
|
},
|
||||||
|
gradient: {
|
||||||
|
"0%": {
|
||||||
|
"background-position": "0% 50%",
|
||||||
|
},
|
||||||
|
"50%": {
|
||||||
|
"background-position": "100% 50%",
|
||||||
|
},
|
||||||
|
"100%": {
|
||||||
|
"background-position": "0% 50%",
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
animation: {
|
animation: {
|
||||||
"spin-slow": "rotate 5s linear infinite",
|
"spin-slow": "rotate 15s linear infinite",
|
||||||
|
gradient: "gradient 15s ease infinite",
|
||||||
},
|
},
|
||||||
colors: {
|
colors: {
|
||||||
"cowo-pink": "#FF7782",
|
"cowo-pink": "#FF7782",
|
||||||
"secondary": "#171717",
|
secondary: "#171717",
|
||||||
"primary": "#fafafa",
|
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