Merge pull request #1 from liyunze-coding/UI-change

New look for the website
This commit is contained in:
RythonDev 2024-04-18 20:27:23 +08:00 committed by GitHub
commit 1866a3a73a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
80 changed files with 11218 additions and 8104 deletions

5
.gitignore vendored
View file

@ -19,3 +19,8 @@ pnpm-debug.log*
# macOS-specific files
.DS_Store
# PageFind
public/pagefind
md-to-html.exe

4
.prettierrc Normal file
View file

@ -0,0 +1,4 @@
{
"plugins": ["prettier-plugin-tailwindcss"],
"tabWidth": 4
}

201
LICENSE Normal file
View file

@ -0,0 +1,201 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright 2024 Coworking Crew
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

120
README.md
View file

@ -1,6 +1,22 @@
<div align="center">
# Coworking Guide
![Coworking website](public/assets/cowo.webp)
[![Coworking website](public/assets/coworking-website-preview.webp)](https://coworking-guide.vercel.app/)
</div>
<div align="center">
![Astro Badge](https://img.shields.io/badge/Astro-BC52EE?logo=astro&logoColor=fff&style=for-the-badge)
![TypeScript Badge](https://img.shields.io/badge/TypeScript-3178C6?logo=typescript&logoColor=fff&style=for-the-badge)
![React Badge](https://img.shields.io/badge/React-61DAFB?logo=react&logoColor=000&style=for-the-badge)
![Tailwind CSS Badge](https://img.shields.io/badge/Tailwind%20CSS-06B6D4?logo=tailwindcss&logoColor=fff&style=for-the-badge)
![remark Badge](https://img.shields.io/badge/remark-000?logo=remark&logoColor=fff&style=for-the-badge)
</div>
---
@ -8,51 +24,93 @@
- [Coworking Guide](#coworking-guide)
- [Table of Contents](#table-of-contents)
- [Introduction](#introduction)
- [How I made this website](#how-i-made-this-website)
- [Frameworks and Tools](#frameworks-and-tools)
- [Deployment](#deployment)
- [References and Credits](#references-and-credits)
- [Contributing](#contributing)
- [Directive Components](#directive-components)
- [Frontmatter](#frontmatter)
- [Guide Content](#guide-content)
- [Independent Pages](#independent-pages)
- [Blog Post](#blog-post)
---
## Introduction
## Contributing
This guide is intended to help you get started with the coworking streams! Whether you're a new or existing coworking streamer, we hope you find this guide useful.
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>!
Guidelines: TBA
---
## How I made this website
## Directive Components
### Frameworks and Tools
```
:::warn
This is a warning!
:::
- Astro (https://astro.build)
:::note
Note this down
:::
Astro is a static site generator that supports server-side rendering. It supports Markdown which I used for most of the content on this website.
:::success
this was successful!
:::
- Tailwind CSS (https://tailwindcss.com)
:::danger
It could go very wrong
:::
Tailwind CSS is a utility-first CSS framework. It's very easy to use and it's very powerful. I used it to style this website on top of Astro, including the Markdown content!
:::tip
This is a cool tip!
:::
```
- Markdown (https://www.markdownguide.org)
## Frontmatter
Markdown is a lightweight markup language that you can use to add formatting elements to plaintext text documents. I used Markdown to write most of the content on this website.
### Deployment
This website is deployed on <a href="https://vercel.com/">Vercel</a>, which is a cloud platform for static sites and serverless functions. It automatically updates the website whenever I push changes to the GitHub repository.
### Guide Content
```
---
title:
layout: "../../layouts/GuideLayout.astro"
description:
order: 0
---
```
## References and Credits
- `title`: Page title
- `layout`: Path to layout file
- `description`: Description of the content
- `order`: The order in which it displays on the left bar
<ul>
<li><a href="https://www.twitch.tv/team/coworkingcrew">Coworking Crew</a> for providing resources</li>
<li><a href="https://third-stinger-20a.notion.site/A-Coworking-Streamer-Cheat-Sheet-01ee1e5ff006410d84c339069ea6546c" target="_blank">A Coworking Streamer Cheat Sheet</a> as an amazing resource</li>
<li><a href="https://www.twitch.tv/MohFocus">MohFocus</a> for the resources (bots and widgets)</li>
<li><a href="https://www.twitch.tv/ryanpython">RyanPython</a> for building the website</li>
</ul>
### Independent Pages
```
---
title:
layout: "../../layouts/GuideLayout.astro"
description:
---
```
- `title`: Page title
- `layout`: Path to layout file
- `description`: Description of the content
### Blog Post
```
---
heading:
subheading:
author:
slug: spirit-city
pubDate: 1970-01-01T0:00:00
---
```
- `heading`: the main title
- `subheading`: the tagline of the blog post
- `author`: name / username of author
- `slug`: desired URL slug
- `pubDate`: Published date (ISO 8601)
---

View file

@ -1,11 +1,25 @@
import { defineConfig } from "astro/config";
import tailwind from "@astrojs/tailwind";
import mdx from "@astrojs/mdx";
import react from "@astrojs/react";
import expressiveCode from "astro-expressive-code";
import remarkDirective from "remark-directive";
import remarkCalloutDirectives from "./src/assets/plugins/remark-callout-directives-customized.js";
// https://astro.build/config
export default defineConfig({
integrations: [tailwind()],
experimental: {
viewTransitions: true,
},
integrations: [
tailwind(),
expressiveCode(),
mdx({
remarkPlugins: [remarkDirective, remarkCalloutDirectives],
}),
react(),
],
server: {
port: 4321,
},
markdown: {
remarkPlugins: [remarkDirective, remarkCalloutDirectives],
},
});

BIN
md-to-html.exe Normal file

Binary file not shown.

14743
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -1,19 +1,36 @@
{
"name": "coworking-guide",
"type": "module",
"version": "1.0.0",
"scripts": {
"dev": "astro dev",
"start": "astro dev",
"build": "astro build",
"preview": "astro preview",
"astro": "astro"
},
"dependencies": {
"@astrojs/tailwind": "^3.1.3",
"@vercel/analytics": "^1.0.1",
"astro": "^2.10.7",
"caniuse-lite": "^1.0.30001576",
"tailwindcss": "^3.3.2"
}
"name": "coworking-guide",
"type": "module",
"version": "2.0.0",
"scripts": {
"dev": "astro dev --open",
"start": "astro dev",
"build": "astro build && pagefind --site dist",
"preview": "astro preview",
"astro": "astro"
},
"dependencies": {
"@astrojs/mdx": "^2.1.1",
"@astrojs/react": "^3.1.0",
"@astrojs/tailwind": "^5.1.0",
"@astrojs/ts-plugin": "^1.5.3",
"@types/react": "^18.2.65",
"@types/react-dom": "^18.2.22",
"@vercel/analytics": "^1.0.1",
"astro": "^4.4.1",
"astro-expressive-code": "^0.33.5",
"clsx": "^2.1.0",
"framer-motion": "^11.0.12",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"remark-directive": "^3.0.0",
"tailwind-merge": "^2.2.1",
"tailwindcss": "^3.4.1",
"typescript": "^5.4.3"
},
"devDependencies": {
"pagefind": "^1.0.4",
"prettier": "^3.2.5",
"prettier-plugin-tailwindcss": "^0.5.11"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 59 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

View file

@ -0,0 +1,116 @@
/* taken from MIT Licensed https://github.com/Microflash/remark-callout-directives */
import { visit } from "unist-util-visit";
import { fromMarkdown } from "mdast-util-from-markdown";
import { h } from "hastscript";
function generate(title, children, hint) {
const indicators = [];
if (hint) {
indicators.push({
type: "html",
value: hint,
});
}
const titleNode = fromMarkdown(title).children[0];
if (titleNode.type === "paragraph") {
titleNode.data = {
hName: "div",
hProperties: { className: ["callout-title"] },
};
} else {
titleNode.data = {
hProperties: { className: ["callout-title"] },
};
}
indicators.push(titleNode);
return [
{
type: "paragraph",
data: {
hName: "div",
hProperties: { className: ["callout-indicator"] },
},
children: indicators,
},
{
type: "paragraph",
data: {
hName: "div",
hProperties: { className: ["callout-content"] },
},
children,
},
];
}
const callouts = {
note: {
title: "Note",
hint: `<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" aria-hidden="true"><path d="M12 8h.01M12 12v4"/><circle cx="12" cy="12" r="10"/></svg>`,
},
success: {
title: "Success",
hint: `<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" aria-hidden="true"><path d="m8 12 2.7 2.7L16 9.3"/><circle cx="12" cy="12" r="10"/></svg>`,
},
warn: {
title: "Warning",
hint: `<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" aria-hidden="true"><path d="M12 9v4m0 4h.01M8.681 4.082C9.351 2.797 10.621 2 12 2s2.649.797 3.319 2.082l6.203 11.904a4.28 4.28 0 0 1-.046 4.019C20.793 21.241 19.549 22 18.203 22H5.797c-1.346 0-2.59-.759-3.273-1.995a4.28 4.28 0 0 1-.046-4.019L8.681 4.082Z"/></svg>`,
},
danger: {
title: "Danger",
hint: `<svg viewBox="0 0 24 24" width="24" height="24" fill="currentColor" aria-hidden="true"><path d="M12 7C11.7348 7 11.4804 7.10536 11.2929 7.29289C11.1054 7.48043 11 7.73478 11 8V12C11 12.2652 11.1054 12.5196 11.2929 12.7071C11.4804 12.8946 11.7348 13 12 13C12.2652 13 12.5196 12.8946 12.7071 12.7071C12.8946 12.5196 13 12.2652 13 12V8C13 7.73478 12.8946 7.48043 12.7071 7.29289C12.5196 7.10536 12.2652 7 12 7ZM12 15C11.8022 15 11.6089 15.0586 11.4444 15.1685C11.28 15.2784 11.1518 15.4346 11.0761 15.6173C11.0004 15.8 10.9806 16.0011 11.0192 16.1951C11.0578 16.3891 11.153 16.5673 11.2929 16.7071C11.4327 16.847 11.6109 16.9422 11.8049 16.9808C11.9989 17.0194 12.2 16.9996 12.3827 16.9239C12.5654 16.8482 12.7216 16.72 12.8315 16.5556C12.9414 16.3911 13 16.1978 13 16C13 15.7348 12.8946 15.4804 12.7071 15.2929C12.5196 15.1054 12.2652 15 12 15ZM21.71 7.56L16.44 2.29C16.2484 2.10727 15.9948 2.00368 15.73 2H8.27C8.00523 2.00368 7.75163 2.10727 7.56 2.29L2.29 7.56C2.10727 7.75163 2.00368 8.00523 2 8.27V15.73C2.00368 15.9948 2.10727 16.2484 2.29 16.44L7.56 21.71C7.75163 21.8927 8.00523 21.9963 8.27 22H15.73C15.9948 21.9963 16.2484 21.8927 16.44 21.71L21.71 16.44C21.8927 16.2484 21.9963 15.9948 22 15.73V8.27C21.9963 8.00523 21.8927 7.75163 21.71 7.56ZM20 15.31L15.31 20H8.69L4 15.31V8.69L8.69 4H15.31L20 8.69V15.31Z"></path></svg>`,
},
tip: {
title: "Tip",
hint: `<svg viewBox="0 0 16 16" width="24" height="24" aria-hidden="true" fill="currentColor"><path d="M8 1.5c-2.363 0-4 1.69-4 3.75 0 .984.424 1.625.984 2.304l.214.253c.223.264.47.556.673.848.284.411.537.896.621 1.49a.75.75 0 0 1-1.484.211c-.04-.282-.163-.547-.37-.847a8.456 8.456 0 0 0-.542-.68c-.084-.1-.173-.205-.268-.32C3.201 7.75 2.5 6.766 2.5 5.25 2.5 2.31 4.863 0 8 0s5.5 2.31 5.5 5.25c0 1.516-.701 2.5-1.328 3.259-.095.115-.184.22-.268.319-.207.245-.383.453-.541.681-.208.3-.33.565-.37.847a.751.751 0 0 1-1.485-.212c.084-.593.337-1.078.621-1.489.203-.292.45-.584.673-.848.075-.088.147-.173.213-.253.561-.679.985-1.32.985-2.304 0-2.06-1.637-3.75-4-3.75ZM5.75 12h4.5a.75.75 0 0 1 0 1.5h-4.5a.75.75 0 0 1 0-1.5ZM6 15.25a.75.75 0 0 1 .75-.75h2.5a.75.75 0 0 1 0 1.5h-2.5a.75.75 0 0 1-.75-.75Z"></path></svg>`,
},
};
/**
* adds callouts/admonitions
* ```
* :::warn{title="example"}
* example warning
* :::
* ```
*
* supports: warn, note, success, danger, tip
* @see {@link callouts} to edit icons
*/
export default function remarkCalloutDirectives() {
return (tree) => {
visit(tree, (node) => {
if (node.type === "containerDirective") {
if (!callouts[node.name]) {
return;
}
const callout = callouts[node.name];
const data = node.data || (node.data = {});
const { title, ...attributes } = node.attributes;
node.attributes = {
...attributes,
class:
"class" in attributes
? `callout callout-${node.name} ${attributes.class}`
: `callout callout-${node.name}`,
};
node.children = generate(
title || callout.title,
node.children,
callout.hint,
);
const tagName = callout.tagName || "aside";
const hast = h(tagName, node.attributes);
data.hName = hast.tagName;
data.hProperties = hast.properties;
}
});
};
}

View file

@ -0,0 +1,103 @@
/* This is taken from @microflash/remark-callout-directives/themes/github/index.css and modified. Modified to work with tailwind darkMode: class, among other things */
/* html {
--callout-headingFontColor-note: hsl(235, 76%, 29%);
--callout-bg-note: hsl(236, 77%, 90%);
--callout-border-note: hsl(235, 82%, 59%);
--callout-headingFontColor-success: hsl(137, 72%, 24%);
--callout-bg-success: hsl(96, 79%, 91%);
--callout-border-success: hsl(137, 66%, 30%);
--callout-headingFontColor-tip: hsl(277, 76%, 31%);
--callout-bg-tip: hsl(276, 70%, 90%);
--callout-border-tip: hsl(277, 81%, 60%);
--callout-headingFontColor-warn: hsl(41, 57%, 27%);
--callout-bg-warn: hsl(43, 80%, 88%);
--callout-border-warn: hsl(41, 80%, 63%);
--callout-headingFontColor-danger: hsl(342, 62%, 31%);
--callout-bg-danger: hsl(338, 57%, 89%);
--callout-border-danger: hsl(341, 72%, 60%);
} */
html {
--callout-headingFontColor-note: hsl(235, 86%, 86%);
--callout-bg-note: hsl(235, 50%, 20%);
--callout-border-note: hsl(235, 90%, 59%);
--callout-headingFontColor-success: hsl(96, 77%, 81%);
--callout-bg-success: hsl(95, 33%, 23%);
--callout-border-success: hsl(96, 77%, 81%);
--callout-headingFontColor-tip: hsl(276, 72%, 89%);
--callout-bg-tip: hsl(276, 36%, 22%);
--callout-border-tip: hsl(277, 81%, 60%);
--callout-headingFontColor-warn: hsl(42, 72%, 87%);
--callout-bg-warn: hsl(43, 33%, 22%);
--callout-border-warn: hsl(42, 72%, 65%);
--callout-headingFontColor-danger: hsl(338, 61%, 86%);
--callout-bg-danger: hsl(339, 32%, 21%);
--callout-border-danger: hsl(340, 64%, 62%);
}
.callout {
--calloutheadingFontColor: var(--callout-headingFontColor);
--callout-bg: var(--callout-bg);
--callout-border: var(--callout-border);
border-left: 0.25em solid var(--callout-border);
padding: 0.5rem 1rem;
color: inherit;
background-color: var(--callout-bg);
margin: 2rem 0;
}
.callout-indicator {
display: flex;
align-items: center;
line-height: 1;
margin-bottom: 16px;
color: var(--calloutheadingFontColor);
}
.callout-title {
font-weight: 600;
font-size: 18px;
letter-spacing: 0.025em;
}
.callout-indicator > svg:first-of-type {
margin-right: 0.5rem;
}
.callout-content:first-child,
.callout-content:only-child {
margin-block-start: 0;
}
.callout-content:last-child,
.callout-content:only-child {
margin-block-end: 0;
}
.callout-note {
--callout-headingFontColor: var(--callout-headingFontColor-note);
--callout-bg: var(--callout-bg-note);
--callout-border: var(--callout-border-note);
}
.callout-success {
--callout-headingFontColor: var(--callout-headingFontColor-success);
--callout-bg: var(--callout-bg-success);
--callout-border: var(--callout-border-success);
}
.callout-warn {
--callout-headingFontColor: var(--callout-headingFontColor-warn);
--callout-bg: var(--callout-bg-warn);
--callout-border: var(--callout-border-warn);
}
.callout-danger {
--callout-headingFontColor: var(--callout-headingFontColor-danger);
--callout-bg: var(--callout-bg-danger);
--callout-border: var(--callout-border-danger);
}
.callout-tip {
--callout-headingFontColor: var(--callout-headingFontColor-tip);
--callout-bg: var(--callout-bg-tip);
--callout-border: var(--callout-border-tip);
}

View file

@ -0,0 +1,48 @@
---
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="no-target-blank hover:no-underline hover:-translate-y-1 shadow-xl transition-all duration-300 w-full"
>
<div class="bg-[#303338] text-white
px-5 py-3
w-full
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>

View file

@ -0,0 +1,75 @@
---
const currentUrl = Astro.url.pathname;
---
<ul class="list-none text-sm">
<li class="ml-[0.5rem] my-2">
<a
href={`https://github.com/liyunze-coding/coworking-website/edit/main/src/pages${currentUrl}`}
class="inline-flex gap-2 transition-colors duration-150 text-white hover:no-underline hover:text-blue-400"
>
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
stroke-width="1.5"
stroke="currentColor"
class="w-6 h-6"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
d="m16.862 4.487 1.687-1.688a1.875 1.875 0 1 1 2.652 2.652L10.582 16.07a4.5 4.5 0 0 1-1.897 1.13L6 18l.8-2.685a4.5 4.5 0 0 1 1.13-1.897l8.932-8.931Zm0 0L19.5 7.125M18 14v4.75A2.25 2.25 0 0 1 15.75 21H5.25A2.25 2.25 0 0 1 3 18.75V8.25A2.25 2.25 0 0 1 5.25 6H10"
></path>
</svg>
Edit this page</a
>
</li>
<li class="ml-[0.5rem] my-2">
<a
href="https://discord.gg/C6e4ztakds"
class="inline-flex gap-2 transition-colors duration-150 text-white hover:no-underline hover:text-blue-400"
>
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
stroke-width="1.5"
stroke="currentColor"
class="w-6 h-6"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
d="M8.625 9.75a.375.375 0 1 1-.75 0 .375.375 0 0 1 .75 0Zm0 0H8.25m4.125 0a.375.375 0 1 1-.75 0 .375.375 0 0 1 .75 0Zm0 0H12m4.125 0a.375.375 0 1 1-.75 0 .375.375 0 0 1 .75 0Zm0 0h-.375m-13.5 3.01c0 1.6 1.123 2.994 2.707 3.227 1.087.16 2.185.283 3.293.369V21l4.184-4.183a1.14 1.14 0 0 1 .778-.332 48.294 48.294 0 0 0 5.83-.498c1.585-.233 2.708-1.626 2.708-3.228V6.741c0-1.602-1.123-2.995-2.707-3.228A48.394 48.394 0 0 0 12 3c-2.392 0-4.744.175-7.043.513C3.373 3.746 2.25 5.14 2.25 6.741v6.018Z"
></path>
</svg>
Chat on Discord</a
>
</li>
<li class="ml-[0.5rem] my-2">
<a
href="https://ko-fi.com/rython"
class="inline-flex gap-2 transition-colors duration-150 text-white hover:no-underline hover:text-blue-400"
>
<svg
xmlns="http://www.w3.org/2000/svg"
fill="none"
viewBox="0 0 24 24"
stroke-width="1.5"
stroke="currentColor"
class="w-6 h-6"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
d="M21 11.25v8.25a1.5 1.5 0 0 1-1.5 1.5H5.25a1.5 1.5 0 0 1-1.5-1.5v-8.25M12 4.875A2.625 2.625 0 1 0 9.375 7.5H12m0-2.625V7.5m0-2.625A2.625 2.625 0 1 1 14.625 7.5H12m0 0V21m-8.625-9.75h18c.621 0 1.125-.504 1.125-1.125v-1.5c0-.621-.504-1.125-1.125-1.125h-18c-.621 0-1.125.504-1.125 1.125v1.5c0 .621.504 1.125 1.125 1.125Z"
></path>
</svg>
Become a Sponsor</a
>
</li>
</ul>

View file

@ -0,0 +1,53 @@
---
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 a follow and show some support 🙌",
link: "/credits",
},
];
---
<div class="relative w-fit mt-20 z-50" data-pagefind-ignore>
<HeroTitle />
<div class="max-w-5xl mx-auto px-8 pt-10">
<HoverEffect items={items} client:load />
</div>
</div>
<style></style>

View file

@ -0,0 +1,39 @@
---
import CommunityLinks from "./CommunityLinks.astro";
type Heading = {
depth: number;
text: string;
slug: string;
};
const { headings } = Astro.props;
---
<h3 class="text-lg font-bold mb-2 mt-0" transition:name="Table of Content">
Table of Contents
</h3>
<ul class="text-sm list-none">
{
headings.map((heading: Heading, index: number) => {
// if (heading.depth === 1) return;
const margin = `${heading.depth - 0.8}rem`;
return (
<li
style={{ marginLeft: margin }}
class="mb-2 pl-0"
data-pagefind-ignore
>
<a
href={`#${heading.slug}`}
class="no-target-blank text-white hover:no-underline hover:text-blue-400 transition-colors duration-150 line-clamp-1"
>
{heading.text.replace("🔗", "")}
</a>
</li>
);
})
}
</ul>
<hr class="my-4" />
<CommunityLinks />

View file

@ -0,0 +1,141 @@
---
import VerticalNav from "./verticalNav.astro";
import SearchModal from "../ui/SearchModal.astro";
---
<div
class="w-full backdrop-blur fixed top-0 text-white bg-secondary/75 z-[60] text-lg py-3 h-[var(--header-height)]"
data-pagefind-ignore
>
<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"
transition:persist
>
<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"
transition:persist
transition:name="navbar"
>
<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>
<!-- Search bar -->
<div class="flex lg:flex-1 justify-end relative">
<SearchModal id="dialog" open="Open modal" />
</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>
<style is:global>
:root {
--pagefind-ui-scale: 1;
--pagefind-ui-primary: #fff;
--pagefind-ui-text: #fff;
--pagefind-ui-background: #272727;
--pagefind-ui-border: #505050;
--pagefind-ui-tag: #fff;
--pagefind-ui-border-width: 1px;
--pagefind-ui-border-radius: 10px;
--pagefind-ui-image-border-radius: 2px;
--pagefind-ui-image-box-ratio: 2 / 1;
--pagefind-ui-font: system-ui;
}
</style>
<script>
// 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%]");
});
});
});
// comment this out if you don't want the search modal
window.addEventListener("DOMContentLoaded", (event) => {
// @ts-ignore
new PagefindUI({
element: "#search",
showSubResults: false,
showEmptyFilters: false,
debounceTimeoutMs: 0,
showImages: false,
autofocus: false,
});
});
</script>

View file

@ -0,0 +1,158 @@
---
type Navigation = Record<
string,
{ title: string; url: string; order: number }[]
>;
const currentUrl = Astro.url.pathname;
const isCurrentUrl = (url: string) => currentUrl === 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/*");
const guideFiles = await Astro.glob("../../pages/guide/*");
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;
}
// setup navigation
const { navigation } = await setup();
// show Home link in vertical navbar only on mobile
const { showHome } = Astro.props;
---
<div class="relative">
<nav id="vertical-nav-component" class="flex flex-col" data-pagefind-ignore>
{
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>

View file

@ -1,257 +0,0 @@
<div transition:persist class="w-full">
<label
class="fixed flex hamburger-menu bg-primary border-2 border-solid border-gray-100 p-2 rounded-lg"
aria-label="Menu"
>
<span class="top-bun"></span>
<input type="checkbox" aria-label="Toggle menu" />
<span class="bottom-bun"></span>
</label>
<aside class="sidebar flex z-20">
<nav class="flex flex-col capitalize" role="navigation">
<a
class="sidebar-url px-5 py-2 mt-10 text-center rounded-md hover:text-gray-600 hover:bg-gray-100 transition-colors duration-500"
href="/"
title="Go to the home page">home</a
>
<a
class="sidebar-url px-5 py-2 mt-2 text-center rounded-md hover:text-gray-600 hover:bg-gray-100 transition-colors duration-500"
href="/about"
title="Go to the about page">about</a
>
<a
class="sidebar-url px-5 py-2 mt-2 text-center rounded-md hover:text-gray-600 hover:bg-gray-100 transition-colors duration-500"
href="/tips"
title="Go to the tips page">tips</a
>
<a
class="sidebar-url px-5 py-2 mt-2 text-center rounded-md hover:text-gray-600 hover:bg-gray-100 transition-colors duration-500"
href="/specs"
title="Go to the specs page">specs</a
>
<a
class="sidebar-url px-5 py-2 mt-2 text-center rounded-md hover:text-gray-600 hover:bg-gray-100 transition-colors duration-500"
href="/bots"
title="Go to the bots page">bots</a
>
<a
class="sidebar-url px-5 py-2 mt-2 text-center rounded-md hover:text-gray-600 hover:bg-gray-100 transition-colors duration-500"
href="/widgets"
title="Go to the widgets page">widgets</a
>
<a
class="sidebar-url px-5 py-2 mt-2 text-center rounded-md hover:text-gray-600 hover:bg-gray-100 transition-colors duration-500"
href="/groups"
title="Go to the widgets page">groups</a
>
</nav>
</aside>
<div
id="navbar"
class="absolute top-0 w-full hidden md:flex justify-center bg-gray-800 shadow-md shadow-gray-900"
>
<div
id="navbar-div"
class="pt-2 mr-5 capitalize w-full pb-1 flex flex-row justify-center text-lg"
>
<a
class="px-3 mx-2 py-1 text-white hover:bg-gray-200 hover:text-black transition-colors duration-500 rounded-md"
href="/">home</a
>
<a
class="px-3 mx-2 py-1 text-white hover:bg-gray-200 hover:text-black transition-colors duration-500 rounded-md"
href="/about">about</a
>
<a
class="px-3 mx-2 py-1 text-white hover:bg-gray-200 hover:text-black transition-colors duration-500 rounded-md"
href="/tips">tips</a
>
<a
class="px-3 mx-2 py-1 text-white hover:bg-gray-200 hover:text-black transition-colors duration-500 rounded-md"
href="/specs">specs</a
>
<a
class="px-3 mx-2 py-1 text-white hover:bg-gray-200 hover:text-black transition-colors duration-500 rounded-md"
href="/bots">bots</a
>
<a
class="px-3 mx-2 py-1 text-white hover:bg-gray-200 hover:text-black transition-colors duration-500 rounded-md"
href="/widgets">widgets</a
>
<a
class="px-3 mx-2 py-1 text-white hover:bg-gray-200 hover:text-black transition-colors duration-500 rounded-md"
href="/groups">groups</a
>
</div>
</div>
</div>
<style>
:root {
--bar-width: 30px;
--bar-height: 4px;
--hamburger-gap: 6px;
--foreground: #111827;
--background: white;
--hamburger-margin: 20px;
--animation-timing: 200ms ease-in-out;
--hamburger-height: calc(
var(--bar-height) * 3 + var(--hamburger-gap) * 2
);
}
.hamburger-menu {
--x-width: calc(var(--hamburger-height) * 1.41421356237);
translate: 0 -200px;
flex-direction: column;
gap: var(--hamburger-gap);
width: max-content;
top: var(--hamburger-margin);
right: var(--hamburger-margin);
z-index: 30;
cursor: pointer;
background: var(--foreground);
rotate: 180deg;
transition: translate var(--animation-timing);
}
.hamburger-menu input:focus-visible {
border: 1px solid var(--background);
box-shadow: 0 0 0 1px var(--foreground);
}
.hamburger-menu input,
.hamburger-menu span {
content: "";
width: var(--bar-width);
height: var(--bar-height);
background-color: white;
border-radius: 9999px;
transform-origin: left center;
transition: opacity var(--animation-timing),
width var(--animation-timing), rotate var(--animation-timing),
translate var(--animation-timing),
background-color var(--animation-timing);
}
.hamburger-menu input {
appearance: none;
padding: 0;
margin: 0;
outline: none;
pointer-events: none;
}
.hamburger-menu .top-bun.active {
rotate: 45deg;
width: var(--x-width);
translate: 0 calc(var(--bar-height) / -2);
}
.hamburger-menu .bottom-bun.active {
rotate: -45deg;
width: var(--x-width);
translate: 0 calc(var(--bar-height) / 2);
}
.hamburger-menu input:checked {
opacity: 0;
width: 0;
}
.sidebar {
position: fixed;
top: 0;
right: 0;
transition: translate var(--animation-timing);
translate: 100%;
padding: 0.5rem 1rem;
padding-top: calc(
var(--hamburger-height) + var(--hamburger-margin) + 1rem
);
background-color: var(--foreground);
color: var(--background);
max-width: 10rem;
min-height: 100vh;
}
</style>
<script defer is:inline>
const sidebar = document.querySelectorAll(".sidebar-url");
const hamburger = document.querySelector(".hamburger-menu");
const checkbox = document.querySelector("input");
const topBun = document.querySelector(".top-bun");
const bottomBun = document.querySelector(".bottom-bun");
const openSideBar = () => {
checkbox.checked = true;
document.querySelector(".sidebar").style.translate = "0";
topBun.classList.add("active");
bottomBun.classList.add("active");
};
const closeSideBar = () => {
checkbox.checked = false;
document.querySelector(".sidebar").style.translate = "100%";
topBun.classList.remove("active");
bottomBun.classList.remove("active");
};
// for each sidebar url, if clicked on, uncheck the checkbox
sidebar.forEach((url) => {
url.addEventListener("click", () => {
closeSideBar();
});
});
if (window.innerWidth < 768) {
hamburger.style.translate = "0 0";
}
window.addEventListener("scroll", () => {
if (window.scrollY > 50 || window.innerWidth < 768) {
hamburger.style.translate = "0 0";
} else {
hamburger.style.translate = "0 -200px";
closeSideBar();
}
});
// if clicked outside of the hamburger menu, close the sidebar
window.addEventListener("click", (e) => {
if (
e.target !== hamburger &&
e.target !== topBun &&
e.target !== bottomBun &&
e.target !== checkbox &&
e.target !== document.querySelector(".sidebar") &&
e.target !== document.querySelector(".sidebar nav")
) {
closeSideBar();
}
});
// if window is resized, check if it's less than 768px
window.addEventListener("resize", () => {
if (window.innerWidth < 768) {
hamburger.style.translate = "0 0";
} else {
hamburger.style.translate = "0 -200px";
closeSideBar();
}
});
// if checked, translate the sidebar
checkbox.addEventListener("change", () => {
if (checkbox.checked) {
openSideBar();
} else {
closeSideBar();
}
});
</script>

View file

@ -0,0 +1,28 @@
<div
class="bg-[white] h-[34vmax] aspect-square absolute rounded-full bg-[linear-gradient(to_right,#88D47D,#3F84D8)] 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%;
scale: 1.5 1;
}
50% {
scale: 1 1.5;
}
to {
rotate: 360deg;
translate: -50% -50%;
scale: 1.5 1;
}
}
</style>

View 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-hero-gradient 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
</div>
</div>

View file

@ -0,0 +1,55 @@
---
const { id } = Astro.props;
---
<style>
dialog::backdrop {
position: fixed;
top: 0px;
right: 0px;
bottom: 0px;
left: 0px;
background: rgba(0, 0, 0, 0.5);
}
</style>
<button
onclick={`window.${id}.showModal()`}
class="text-sm flex bg-[#101010] w-60 px-2 py-2 border border-gray-600 border-solid text-left rounded-lg group"
>
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 20 20"
fill="currentColor"
class="w-5 h-5"
>
<path
fill-rule="evenodd"
d="M9 3.5a5.5 5.5 0 1 0 0 11 5.5 5.5 0 0 0 0-11ZM2 9a7 7 0 1 1 12.452 4.391l3.328 3.329a.75.75 0 1 1-1.06 1.06l-3.329-3.328A7 7 0 0 1 2 9Z"
clip-rule="evenodd"></path>
</svg>
<span class="ml-3 text-gray-400 group-hover:text-white">Search...</span>
</button>
<dialog
id=`${id}`
class="fixed left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2 bg-[#202020] border-2 border-solid border-[#505050] text-white rounded-lg w-1/2 h-5/6 px-10 py-10 animate-fadeIn"
>
<form method="dialog">
<button class="absolute top-3 right-3"
><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="M5.47 5.47a.75.75 0 0 1 1.06 0L12 10.94l5.47-5.47a.75.75 0 1 1 1.06 1.06L13.06 12l5.47 5.47a.75.75 0 1 1-1.06 1.06L12 13.06l-5.47 5.47a.75.75 0 0 1-1.06-1.06L10.94 12 5.47 6.53a.75.75 0 0 1 0-1.06Z"
clip-rule="evenodd"></path>
</svg>
</button>
</form>
<div id="search" class="mt-2" transition:name="search" transition:persist>
</div>
</dialog>

View 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-[#8DECB4]"
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>
);
};

23
src/content/config.ts Normal file
View file

@ -0,0 +1,23 @@
// Import utilities from `astro:content`
import { z, defineCollection } from "astro:content";
// Define a `type` and `schema` for each collection
const postsCollection = defineCollection({
type: "content",
schema: z.object({
heading: z.string(),
subheading: z.string()?.optional(),
pubDate: z.date(),
author: z.string(),
image: z
.object({
url: z.string(),
alt: z.string(),
})
?.optional(),
tags: z.array(z.string())?.optional(),
}),
});
// Export a single `collections` object to register your collection(s)
export const collections = {
posts: postsCollection,
};

View file

@ -0,0 +1,44 @@
---
heading: "Spirit City: Lofi Sessions"
subheading: Where Productivity Meets Cozy Vibes
author: RythonDev
slug: spirit-city
pubDate: 2024-04-18T4:10:00
---
In the ever-growing world of productivity apps and techniques, Spirit City: Lofi Sessions offers a unique and delightful twist. Forget the harsh red timers and sterile to-do lists. Here, you cultivate focus amidst a charming virtual world bathed in calming lo-fi beats and populated by friendly spirits.
## A Gamified Oasis for Focus
Developed by Mooncube Games, Spirit City: Lofi Sessions isn't your typical productivity tool. It's a gamified experience, transforming the act of getting things done into a visually appealing and engaging adventure. Imagine a cozy room, customizable to your heart's content, where you can unwind and tackle your tasks simultaneously. This is your haven in Spirit City.
## Unleash Your Inner Decorator
The room is your canvas. Spruce it up with a variety of furniture, plants, and decorations. Want a minimalist aesthetic conducive to intense concentration? Done. Craving a vibrant and playful space to spark creativity? No problem. The options cater to diverse preferences, allowing you to personalize your environment for maximum focus flow.
## Meet Your Spirit Companions
One of the most captivating aspects of Spirit City is the presence of adorable, collectable spirits. These ethereal companions aren't just cute additions to your room; they provide a sense of purpose within the game's focus-driven framework. As you complete tasks in the real world, your spirits level up, unlocking new customization options and deepening the connection between your virtual and actual productivity.
## Beyond the Aesthetics: Practical Tools for Productivity
While the visuals and atmosphere are undeniably captivating, Spirit City offers a robust toolkit for actual productivity, such as:
* **Task Management:** Create and manage to-do lists directly within the game, seamlessly integrating your virtual and real-world tasks.
* **Focus Timers:** Utilize built-in focus timers to structure your workday and prevent procrastination.
* **Pomodoro Technique Integration:** For fans of the Pomodoro Technique, Spirit City provides a gamified version of this popular time management method.
* **Background Ambience:** The ever-present (non-copyrighted) lo-fi soundtrack creates a calming and focused atmosphere, perfect for drowning out distractions and promoting concentration.
## A Community of Focused Folks
Spirit City fosters a community of like-minded individuals striving for productivity. Follow productivity streamers playing the game to connect with others who share your goals. Sharing tips, celebrating accomplishments, and holding each other accountable can significantly boost your overall motivation.
## Is Spirit City Right for You?
If you're tired of traditional productivity apps and yearn for a more engaging and stress-free approach to getting things done, then Spirit City: Lofi Sessions might be the game-changer you've been looking for. It offers a unique blend of customization, gamification, and a focus-oriented environment, all wrapped in a charming and visually appealing package. So, put on your headphones, fire up Spirit City, and embark on a productivity adventure unlike any other.
<div class="mt-10">
by [RythonDev](https://twitch.tv/RythonDev)
</div>

1
src/env.d.ts vendored
View file

@ -1 +1,2 @@
/// <reference path="../.astro/types.d.ts" />
/// <reference types="astro/client" />

View file

@ -0,0 +1,35 @@
---
import Layout from "./Layout.astro";
import TableOfContent from "../components/blocks/TableOfContent.astro";
import VerticalNav from "../components/blocks/verticalNav.astro";
const { frontmatter, headings } = Astro.props;
---
<Layout title={frontmatter.heading} description={frontmatter.subheading}>
<div class="mx-auto px-4 sm:px-6 max-w-7xl">
<div class="flex flex-col lg:grid lg:grid-cols-10">
<!-- vertical navbar -->
<div class="lg:col-span-2" transition:name="vertical-navbar">
<aside
class="hidden lg:translate-x-0 overflow-y-auto z-30 lg:block lg:sticky py-8 lg:px-4 lg:-mx-4 lg:max-h-[calc(100vh-var(--header-height))] lg:top-[--header-height]"
>
<VerticalNav />
</aside>
</div>
<div class="lg:col-span-8">
<div class="flex flex-col lg:grid lg:grid-cols-10">
<div class="col-span-8 pr-10 pb-20 pt-8">
<slot />
</div>
<div
class="col-span-2 pt-8 hidden lg:block lg:sticky lg:px-4 lg:-mx-4 lg:max-h-[calc(100vh-var(--header-height))] lg:top-[--header-height]"
>
<!-- TOC -->
<TableOfContent headings={headings} />
</div>
</div>
</div>
</div>
</div>
</Layout>

View file

@ -0,0 +1,22 @@
---
import Layout from "./Layout.astro";
import VerticalNav from "../components/blocks/verticalNav.astro";
---
<Layout title={Astro.props.title} description={Astro.props.description}>
<div class="mx-auto px-6 max-w-7xl">
<div class="flex flex-col lg:grid lg:grid-cols-10">
<!-- vertical navbar -->
<div class="lg:col-span-2" transition:name="vertical-navbar">
<aside
class="hidden lg:translate-x-0 overflow-y-auto z-30 lg:block lg:sticky py-8 lg:px-4 lg:-mx-4 lg:max-h-[calc(100vh-var(--header-height))] lg:top-[--header-height]"
>
<VerticalNav />
</aside>
</div>
<div class="lg:col-span-8 pt-8">
<slot />
</div>
</div>
</div>
</Layout>

View file

@ -0,0 +1,42 @@
---
import Layout from "./Layout.astro";
import TableOfContent from "../components/blocks/TableOfContent.astro";
import VerticalNav from "../components/blocks/verticalNav.astro";
import "../assets/styles/remark-callout-directives.css";
const { frontmatter, headings } = Astro.props;
---
<Layout title={frontmatter.title} description={frontmatter.description}>
<div class="mx-auto px-6 max-w-7xl">
<div class="flex flex-col lg:grid lg:grid-cols-10">
<!-- vertical navbar -->
<div class="lg:col-span-2" transition:name="vertical-navbar">
<aside
class="hidden lg:translate-x-0 overflow-y-auto z-30 lg:block lg:sticky py-8 lg:px-4 lg:-mx-4 lg:max-h-[calc(100vh-var(--header-height))] lg:top-[--header-height]"
>
<VerticalNav />
</aside>
</div>
<div class="lg:col-span-8">
<div class="flex flex-col lg:grid lg:grid-cols-10">
<div class="col-span-8 pr-10 pb-10 pt-8">
<slot />
</div>
<div
class="hidden col-span-2 pt-8 lg:block lg:sticky lg:px-4 lg:-mx-4 lg:max-h-[calc(100vh-var(--header-height))] lg:top-[--header-height]"
>
<!-- TOC -->
<TableOfContent headings={headings} />
</div>
</div>
</div>
</div>
</div>
<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>

View file

@ -1,5 +1,5 @@
---
import NavBar from "../components/navBar.astro";
import NavBar from "../components/blocks/navBar.astro";
import { ViewTransitions } from "astro:transitions";
export interface Props {
@ -10,108 +10,40 @@ export interface Props {
const { title, description } = Astro.props;
---
<!DOCTYPE html>
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="description" content={description} />
<meta name="keywords" content="coworking, study, streams" />
<meta name="author" content="RyanPython" />
<meta name="author" content="RythonDev" />
<meta name="theme-color" content="#2B2D31" />
<meta name="viewport" content="width=device-width" />
<link rel="icon" type="image/x-icon" href="/favicon.ico" />
<script defer src="/_vercel/insights/script.js"></script>
<link href="/pagefind/pagefind-ui.css" rel="stylesheet" />
<script src="/pagefind/pagefind-ui.js" is:inline></script>
<script is:inline src="/_vercel/insights/script.js"></script>
<ViewTransitions />
<meta name="generator" content={Astro.generator} />
<title>{title}</title>
</head>
<body>
<NavBar />
<slot />
<div class="pt-[var(--header-height)]">
<NavBar />
<slot />
</div>
<script>
// 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>
<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;
:root {
--header-height: 3.5rem;
}
* {
@ -121,28 +53,33 @@ const { title, description } = Astro.props;
}
html {
font-family: "Montserrat", system-ui, sans-serif;
background-color: #29233f;
font-family: system-ui, sans-serif;
background-color: #171717;
color: rgb(255 255 255);
}
html,
body {
min-height: 100%;
}
body {
height: 100vh;
font-family: "Montserrat", system-ui, sans-serif;
/* smooth scroll */
scroll-behavior: smooth;
font-family: system-ui;
}
code {
font-family: Menlo, Monaco, Lucida Console, Liberation Mono,
DejaVu Sans Mono, Bitstream Vera Sans Mono, Courier New,
font-family:
Menlo,
Monaco,
Lucida Console,
Liberation Mono,
DejaVu Sans Mono,
Bitstream Vera Sans Mono,
Courier New,
monospace;
}
nav {
font-family: "Montserrat", system-ui, sans-serif;
font-family: system-ui, sans-serif;
font-weight: 500;
}
@ -154,11 +91,67 @@ const { title, description } = Astro.props;
text-decoration: none;
}
p code {
word-break: break-all; /* This will allow the URL to break at any character */
display: block; /* Ensures the entire URL is on its own line */
width: 100%; /* Make sure the code element takes up the full width of its container */
overflow-x: auto;
blockquote {
@apply my-4 border-l-4 border-gray-500 pl-4;
}
a {
@apply inline-block text-blue-400 hover:underline;
}
h1 {
@apply mb-2 text-4xl font-bold;
}
h2 {
@apply mb-2 mt-5 scroll-mt-[calc(20px+var(--header-height))] text-3xl font-bold;
}
h3 {
@apply mb-2 mt-5 scroll-mt-[calc(17px+var(--header-height))] text-2xl font-bold;
}
h4 {
@apply mb-2 mt-5 scroll-mt-[calc(14px+var(--header-height))] text-xl font-bold;
}
p {
@apply mb-2 mt-2 font-[system-ui] leading-6;
}
hr {
@apply my-10 border-gray-500;
}
ul {
@apply list-outside list-disc leading-7;
}
code {
@apply rounded-md bg-[#323232] px-1 py-1 font-["Lucida_Console",monospace,courier-new] text-sm;
}
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>
</body>

View file

@ -1,89 +0,0 @@
---
import Layout from "./Layout.astro";
export interface Props {
frontmatter: {
title: string;
description: string;
};
}
const { frontmatter } = Astro.props;
---
<Layout title={frontmatter.title} description={frontmatter.description}>
<div class="pt-12 w-full flex flex-col justify-center items-center">
<article class="w-5/6 md:w-3/4 lg:w-2/3 py-10">
<slot />
</article>
</div>
</Layout>
<style is:global>
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
html {
font-family: "Montserrat", system-ui, sans-serif;
color: #fff;
background-color: #29233f;
}
html,
body {
min-height: 100%;
}
body {
height: 100vh;
font-family: "Montserrat", system-ui, sans-serif;
}
code {
font-family: Menlo, Monaco, Lucida Console, Liberation Mono,
DejaVu Sans Mono, Bitstream Vera Sans Mono, Courier New, monospace;
}
nav {
font-family: "Montserrat", system-ui, sans-serif;
font-weight: 500;
}
nav ul a {
text-decoration: none;
}
summary {
@apply font-bold text-2xl py-2 cursor-pointer;
-webkit-touch-callout: none; /* iOS Safari */
-webkit-user-select: none; /* Safari */
-khtml-user-select: none; /* Konqueror HTML */
-moz-user-select: none; /* Old versions of Firefox */
-ms-user-select: none; /* Internet Explorer/Edge */
user-select: none; /* Non-prefixed version, currently
supported by Chrome, Edge, Opera and Firefox */
}
details {
@apply my-4;
}
ul li a {
@apply underline underline-offset-2 decoration-1 hover:text-blue-400;
}
.hyperlink {
font-family: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI",
Roboto, Oxygen, Ubuntu, Cantarell, "Open Sans", "Helvetica Neue",
sans-serif;
}
ul ul {
list-style-position: inside;
padding-left: 1rem;
}
</style>

View file

@ -1,83 +0,0 @@
---
import Layout from "../layouts/Layout.astro";
// plans:
// - what is coworking
// - how the overlays benefit
// - why did I open source
---
<Layout title="About" description="About the creator of this website + FAQ">
<div class="h-full flex flex-col text-white">
<div class="w-full h-full flex flex-col justify-center items-center">
<div
class="w-4/5 lg:w-2/3 flex flex-col justify-center items-center text-center"
>
<img
src="/assets/circle_logo.webp"
alt="ryan logo"
width="200"
class="mb-10"
/>
<h1 class="text-5xl font-bold">About</h1>
<p class="mt-5 text-lg mb-5">
Hello, I'm <span class="font-bold">Ryan</span>, a computer
science student based in Malaysia. The objective of this
website is to offer valuable resources to aspiring
streamers, helping them enhance their streaming experience!
</p>
<p>
If you want to learn more about me, check out my <a
href="https://ryanpython.me"
target="_blank"
class="underline underline-offset-2 transition-colors duration-500 hover:text-blue-500"
>website</a
> or my <a
href="https://www.twitch.tv/RythonDev"
target="_blank"
class="underline underline-offset-2 transition-colors duration-500 hover:text-blue-500"
>stream</a
>!
</p>
</div>
</div>
</div>
<div class="w-full h-full flex flex-col text-white">
<div
class="w-full h-fit py-5 sm:py-0 sm:h-1/3 bg-gray-900 flex flex-col justify-center items-center text-center"
>
<h2 class="font-bold text-2xl mb-5">
What are Coworking & Study streams?
</h2>
<p class="w-4/5 lg:w-1/2">
Coworking and study streams are a type of stream where people
work or study together. It's a great way to stay motivated and
productive, especially if you're working!
</p>
</div>
<div
class="w-full h-fit py-5 sm:py-0 sm:h-1/3 flex flex-col justify-center items-center text-center"
>
<h2 class="font-bold text-2xl mb-5">
How can this guide benefit me?
</h2>
<p class="w-4/5 lg:w-1/2">
This guide has been created to help out coworking and study
streamers by providing tips and resources to enhance the
streaming experience!
</p>
</div>
<div
class="w-full h-fit py-5 sm:py-0 sm:h-1/3 bg-gray-900 flex flex-col justify-center items-center text-center"
>
<h2 class="font-bold text-2xl mb-5">
Why should I stream myself working?
</h2>
<p class="w-4/5 lg:w-1/2">
Streaming yourself working is a great way to stay accountable
and productive. It's also a great way to grow your following and
meet new people!
</p>
</div>
</div>
</Layout>

View file

@ -0,0 +1,26 @@
---
import BlogsLayout from "../../layouts/BlogsLayout.astro";
import BlogPost from "../../components/blocks/BlogPostPreview.astro";
import { getCollection } from "astro:content";
const allPosts = await getCollection("posts");
---
<BlogsLayout
title="Blog Posts"
description="A collection of blog posts, related to coworking, studying, streaming and many more!"
>
<h1 class="mb-5">Blog Posts</h1>
<div>
{
allPosts.map((post) => (
<BlogPost
url={`/blog/posts/${post.slug}/`}
title={post.data.heading}
tagline={post.data.subheading}
pubDate={post.data.pubDate}
/>
))
}
</div>
</BlogsLayout>

View file

@ -0,0 +1,74 @@
---
import { getCollection } from "astro:content";
import BlogPostLayout from "../../../layouts/BlogPostLayout.astro";
import { Image } from "astro:assets";
function timeAgo(date: Date) {
const dateObject = new Date(date);
const seconds = Math.floor(
(new Date().getTime() - dateObject.getTime()) / 1000
);
let interval = Math.floor(seconds / 31536000);
if (interval >= 1) {
return interval + (interval === 1 ? " year ago" : " years ago");
}
interval = Math.floor(seconds / 2592000);
if (interval >= 1) {
return interval + (interval === 1 ? " month ago" : " months ago");
}
interval = Math.floor(seconds / 86400);
if (interval >= 1) {
return interval + (interval === 1 ? " day ago" : " days ago");
}
interval = Math.floor(seconds / 3600);
if (interval >= 1) {
return interval + (interval === 1 ? " hour ago" : " hours ago");
}
interval = Math.floor(seconds / 60);
if (interval > 1) {
return interval + (interval === 1 ? " minute ago" : " minutes ago");
}
return (
Math.floor(seconds) + (seconds === 1 ? " second ago" : " seconds ago")
);
}
export async function getStaticPaths() {
const blogEntries = await getCollection("posts");
return blogEntries.map((entry) => ({
params: { slug: entry.slug },
props: { entry },
}));
}
const { entry } = Astro.props;
const { Content, headings } = await entry.render();
---
<BlogPostLayout frontmatter={entry.data} headings={headings}>
<h1>{entry.data.heading}</h1>
<h2 class="font-normal text-lg">{entry.data.subheading}</h2>
<div class="flex justify-start items-start gap-3">
<p class="text-base font-normal text-gray-200">
By {entry.data.author}
</p>
<p class="text-base font-normal text-gray-400">
Published {timeAgo(new Date(entry.data.pubDate))}
</p>
</div>
{
entry.data.image && (
<Image
src={entry.data.image.url}
alt={entry.data.image.alt}
class="mt-5 mb-5"
width="700"
height="400"
loading="eager"
/>
)
}
<Content />
</BlogPostLayout>

View file

@ -0,0 +1,3 @@
---
Astro.redirect("../../");
---

View file

@ -1,37 +0,0 @@
---
title: Bots
layout: "../layouts/Markdown.astro"
description: Find out the bots you can use for your stream!
---
# Twitch Bots
Twitch bots are a great way to increase engagement for your viewers and improve your streaming experience. They can also help you manage your stream and chat more effectively. Here are some bots you can use for your stream!
\(All of these bots are free to use!\)
---
<a href="https://nightbot.tv/" target="_blank" class="font-bold text-2xl hover:underline">Nightbot 🔗</a>
<a href="https://nightbot.tv/" target="_blank" class="hover:underline">Nightbot</a> 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.
---
<a href="https://serycodes.carrd.co/" target="_blank" class="font-bold text-2xl hover:underline">Sery Bot 🔗</a>
<a href="https://serycodes.carrd.co/" target="_blank" class="hover:underline">Sery Bot</a> is a moderation bot providing anti-hate raid and anti-follow bot protections, and other safety features and tools to streamers.
---
<a href="https://twitch.tv/MohCitrus/about" target="_blank" class="font-bold text-2xl hover:underline">MohCitrus 🔗</a>
<img src="/assets/mohcitrus.webp" width="300" class="mb-1">
<a href="https://twitch.tv/MohCitrus/about" target="_blank" class="hover:underline">MohCitrus</a> is a translator bot made by <a href="https://twitch.tv/MohFocus" target="_blank" class="underline hover:text-blue-400">MohFocus</a>! It can translate messages of viewers to any language via commands!
---
## Custom bots
Interested in making your own bot? Want to look for a programming project to work on? Check out <a href="https://github.com/instafluff/comfyjs" target="_blank" class="underline">Comfy.JS</a> made by Instafluff!

View file

@ -0,0 +1,41 @@
---
title: Credits
layout: "../../layouts/GuideLayout.astro"
description: Credits to the people behind this website!
---
# Credits
Credits to the wonderful team of people behind this guide!
---
<img src="/images/credits/rythondev.webp" alt="RythonDev" class="rounded-lg" width="300" />
## RythonDev
Main developer of the project
<div class="flex flex-row gap-2">
[![Twitch Badge](https://img.shields.io/twitch/status/rythondev?color=9146FF&label=Twitch&logo=twitch&logoColor=white&style=for-the-badge)](https://twitch.tv/RythonDev)
[![YouTube Badge](https://img.shields.io/badge/YouTube-F00?logo=youtube&logoColor=fff&style=for-the-badge)](https://youtube.com/@RythonDev)
[![Website](https://img.shields.io/badge/Website-fff?logoColor=000&style=for-the-badge)](https://rython.dev/)
[![Ko-fi Badge](https://img.shields.io/badge/Ko--fi-FF5E5B?logo=kofi&logoColor=fff&style=for-the-badge)](https://ko-fi.com/rython)
</div>
## Coworking Crew Cheat Sheet
![Coworking Crew](/images/groups/coworkingcrew.webp)
An amazing resource for this guide!
[![Website](https://img.shields.io/badge/Website-fc626f?logoColor=000&style=for-the-badge)](https://third-stinger-20a.notion.site/A-Coworking-Streamer-Cheat-Sheet-01ee1e5ff006410d84c339069ea6546c/)
<!-- REFERENCES FOR BADGES/ICONS -->
<!-- https://badges.pages.dev/ -->
<!-- https://shields.io/badges -->

View file

@ -0,0 +1,113 @@
---
title: Introduction
layout: "../../layouts/GuideLayout.astro"
description: Introduction to coworking streams!
order: 0
---
# Introduction
A brief introduction to coworking streams! Let's keep each other accountable ^^
---
## What are coworking streams?
![RythonDev](/images/introduction/rythondev.webp)
Image source: [RythonDev (Twitch)](https://twitch.tv/RythonDev)
> Coworking (or study) streaming is an opportunity to share a virtual, productive, space with others and to connect based on interests and studies - in some ways replicating the in-person office, library, or cafe. Often, study streaming follows a pomodoro counter so that streamers can focus on working for a set amount of time and then converse with chat during another set amount of time for break.
Many viewers like to watch coworking streams because it provides motivation and accountability, which is especially hard if you're trying to focus at home. In the light of Covid, where working from home is becoming more common, it can nice to find an environment with like-minded people. Plus, the sense of community attracts many people - often coworking streams are very welcoming and supportive!
---
## What is a "pomodoro"?
<img src="/images/introduction/ellyskey.webp" alt="Ellyskey" loading="lazy" />
Image source: [Ellyskey (Twitch)](https://twitch.tv/Ellyskey)
The Pomodoro Technique is a time management method where you work in focused intervals called pomodoros separated by short breaks. This helps you stay concentrated, avoid burnout, and tackle big tasks by breaking them into manageable chunks.
Coworking streamers tend to use 50 minutes of work and 10 minutes of break (50/10) for their streams for optimal balance of being able to get work done and be able to chat with viewers.
---
## How do people enjoy these streams?
<img src="/images/introduction/seijisoldier.webp" alt="SeijiSoldier" loading="lazy" />
Image source: [SeijiSoldier (Twitch)](https://twitch.tv/SeijiSoldier)
> ### What are your thoughts on co-working streams?
> I'm not saying I dislike them, but I just want to understand how people enjoy these streams. It's mostly just the streamer doing their work while their cam is facing in front of them. There's nothing much to watch as it's not display captured (understandable since work is confidential).
>
> Sometimes, when I chat with them they don't even reply back. They usually have a timer in their overlay and after the timer ends they talk to chat again.
>
> Maybe I'm a boomer, but can anyone shed light on why these streams are a thing on Twitch?
Source: [Archived Reddit post](https://www.reddit.com/r/Twitch/comments/t66g15/what_are_your_thoughts_on_coworking_streams/)
Although might seem unconventional to watch someone else work, there are several reasons why viewers enjoy these streams:
- **Accountability and Focus**
Working from home can be isolating and lead to procrastination. Co-working streams provide a virtual study buddy or colleague, fostering a sense of accountability that viewers can leverage to stay on task. Seeing the streamer working diligently can motivate viewers to do the same.
- **Community and Support**
The chat function in these streams creates a sense of community. Viewers can discuss their work, ask questions, or simply enjoy the company of others while working. This social interaction can be a welcome change from the solitary nature of remote work.
- **Background Noise and Ambience**
Some viewers find background noise, like music or light chatter, helpful for concentration. Co-working streams can provide this calming ambience without the distractions of traditional co-working spaces.
- **Learning and Inspiration**
By watching a streamer work, viewers might pick up new productivity techniques or software shortcuts. Seeing someone else tackle similar tasks can be inspiring and motivating.
It's understandable that the lack of direct interaction or display capture might be unfamiliar. Streamers typically prioritize focusing on their work during these periods, addressing chat messages during breaks or using timers to dedicate time for interaction.
Ultimately, co-working streams cater to a specific need for some viewers. They offer a unique blend of productivity, community, and a supportive atmosphere that traditional work environments might lack.
---
## What is a task widget?
<a href="../guide/stream-widgets#task-widgets" class="no-target-blank"><img src="/images/widgets/multitask.webp" alt="Multi Task Widget" loading="lazy"></a>
If you want to add a task widget to your own stream, check it out in the <a href="../guide/stream-widgets#task-widgets" class="no-target-blank">Widgets section</a>!
A task widget is a widget where users can use commands such as:
- !task [current task]
- !todo [current task]
in chat to add their task(s) to the widget, to remind themselves about what they need to focus on at the moment.
Task widgets offer an extra layer of accountability for the streamer and chatters to focus on their current task(s).
---
## How can I find these streams?
The recommended way of searching for coworking streams are using the tags!
- [Coworking tag](https://www.twitch.tv/directory/all/tags/coworking)
- ["Study with me" tag](https://www.twitch.tv/directory/all/tags/studywithme)
### [Coworking category petition 🔗](https://twitch.uservoice.com/forums/310210-discover/suggestions/46004791-coworking)
<img src="/images/introduction/petition.webp" alt="Coworking and Study category petition" loading="lazy" />
As of March 2024, there isn't an official category. So we want YOU to [SIGN THE PETITION](https://twitch.uservoice.com/forums/310210-discover/suggestions/46004791-coworking) for a "Coworking and Study" category!
An official coworking category will be beneficial for the community in the following ways:
- Allow coworking and study streamers to stream away from Just Chatting and stream in a less saturated category.
- Improve discoverability of productivity streamers (big and small creators!)
- Improve the algorithm to recommend more productivity related streams to users who are interested.
---

View file

@ -0,0 +1,54 @@
---
title: Pre-requisites
layout: "../../layouts/GuideLayout.astro"
description: Pre-requisites for coworking streams!
order: 1
---
# Pre-requisites
Get ready for coworking streams!
---
## Pre-requisites (Computer)
Pre-requisites for starting coworking streams on your desktop computer or laptop.
### Software
- [OBS](https://obsproject.com/) : Free and open source software for video recording and live streaming.
### Hardware
- **Internet Capacity (bitrate)**
- There are some online calculators you can use to determine the ideal bitrate based off your computer specs and preferred output (screen resolution, frames per second).
- Check out this [in depth guide from Reddit](https://www.reddit.com/r/Twitch/comments/2dz7ru/bitrates_resolutions_and_quality/) to learn more!
- **RAM**
- The more RAM a computer has, the better it is at multitasking.
- Minimum 8GB, 16GB or more is recommended.
- **CPU**
- The better the CPU, the faster the computer can process data and instructions.
- clock speed of 3.0 GHz or higher, such as an Intel Core i5 or AMD Ryzen 5.
- **GPU**
- The better the GPU, the better the image quality and the higher the frame rate.
- A dedicated GPU is not required for streaming, but it is recommended for a better viewing experience.
- A dedicated graphics card with at least 4GB of VRAM, such as an NVIDIA GeForce GTX 1050 or AMD Radeon RX 560.
---
## Pre-requisites (Mobile)
Usually, streamers who stream from their phone would use their laptop device to interact with chat!
### Hardware
- **Camera**
- Having a camera pointed towards your direction is effective for accountability!
### Software
- **Twitch / YouTube app**
- Depending on which platform you intend to stream on.
---

View file

@ -1,61 +0,0 @@
---
title: Groups
layout: "../layouts/Markdown.astro"
description: Find new communities to join!
---
# Groups
I recommend the following communities to join! They provide a great way to connect with other streamers and viewers!
---
<a href="https://www.twitch.tv/team/coworkingcrew/" target="_blank" class="font-bold text-2xl hover:underline">Coworking Crew 🔗</a>
<a href="https://www.twitch.tv/team/coworkingcrew" target="_blank" class="inline-block mt-2 mb-5">
<img src="/assets/coworkingcrew.webp" alt="coworking crew" width="300" class="rounded-md">
</a>
The Coworking Crew is a group of co-working streamers who aim to create supportive and motivational live streams for people who are working or studying at home. As a group we help each other out, collaborate on stream, and ultimately find new friends.
---
<a href="https://theselfdev.com/" target="_blank" class="font-bold text-2xl hover:underline">Self.dev 🔗</a>
<a href="https://theselfdev.com/" target="_blank" class="inline-block mt-2 mb-5">
<img src="/assets/selfdev_logo.webp" alt="self dev" width="300" class="rounded-md">
</a>
Self.dev is a community of various individuals from different fields come together to share knowledge and grow together. They focus on supporting each other by sharing and creating valuable resources to help each other grow individually.
---
<a href="https://www.youthversity.org/" target="_blank" class="font-bold text-2xl hover:underline">YOUthversity 🔗</a>
<a href="https://www.youthversity.org/" target="_blank" class="inline-block mt-2 mb-5">
<img src="/assets/youthversity.webp" alt="youthversity" width="300" class="rounded-md">
</a>
YOUthversity is not only an online space to study together but is dedicated to the exchange of resources, dialogue, peer-to-peer support, and development.
---
<a href="https://erudita.me/" target="_blank" class="font-bold text-2xl hover:underline">Erudita 🔗</a>
<a href="https://erudita.me/" target="_blank" class="inline-block mt-2 mb-5">
<img src="/assets/erudita.webp" alt="erudita" width="300" class="rounded-md">
</a>
An educational platform suitable for those seeking knowledge. In the community, you have the opportunity to learn alongside others or apply for Erudita membership and share your expertise and passions.
---
<a href="https://studytme.com/" target="_blank" class="font-bold text-2xl hover:underline">CEO Gang 🔗</a>
<a href="https://studytme.com/" target="_blank" class="inline-block mt-2 mb-5">
<img src="/assets/ceogang.webp" alt="ceo gang" width="300" class="rounded-md">
</a>
The right place for ambitious people working together and supporting each other! Make friends, learn and work remote!
---

52
src/pages/groups/index.md Normal file
View file

@ -0,0 +1,52 @@
---
title: Stream groups
layout: "../../layouts/GuideLayout.astro"
description: Groups you should definitely checkout!
order: 0
---
# Groups
Communities provide a great way to connect with other streamers and viewers!
---
[![Coworking Crew](/images/groups/coworkingcrew.webp)](https://www.twitch.tv/team/coworkingcrew/)
## [Coworking Crew 🔗](https://www.twitch.tv/team/coworkingcrew/)
The Coworking Crew is a group of co-working streamers who aim to create supportive and motivational live streams for people who are working or studying at home. As a group we help each other out, collaborate on stream, and ultimately find new friends.
---
[![Erudita](/images/groups/erudita.webp)](https://erudita.me/)
## [Erudita 🔗](https://erudita.me/)
An educational platform suitable for those seeking knowledge. In the community, you have the opportunity to learn alongside others or apply for Erudita membership and share your expertise and passions.
---
<a href="https://www.youthversity.org/"><img src="/images/groups/YOUthversity.webp" alt="YOUthversity" loading="lazy" /></a>
## [YOUthversity 🔗](https://www.youthversity.org/)
YOUthversity is not only an online space to study together but is dedicated to the exchange of resources, dialogue, peer-to-peer support, and development.
---
<a href="https://theselfdev.com/"><img src="/images/groups/selfdev.webp" alt="self dev" loading="lazy" /></a>
## [self.dev 🔗](https://theselfdev.com/)
Self.dev is a community of various individuals from different fields come together to share knowledge and grow together. They focus on supporting each other by sharing and creating valuable resources to help each other grow individually.
---
<a href="https://studytme.com/"><img src="/images/groups/CEOgang.webp" alt="CEO gang" loading="lazy" /></a>
## [CEO Gang 🔗](https://studytme.com/)
The right place for ambitious people working together and supporting each other! Make friends, learn and work remote!
---

31
src/pages/guide/emotes.md Normal file
View file

@ -0,0 +1,31 @@
---
title: Emotes
layout: "../../layouts/GuideLayout.astro"
description: Learn how to add emotes to your streams!
order: 5
---
# Emotes
Stream emotes are like custom emojis specific to a channel, acting as a fun and engaging way for viewers to express emotions, inside jokes, and reactions during a livestream, fostering a sense of community and shared experience.
---
## Channel emotes (Twitch)
When you reach the Twitch Affiliate goal, you can add emotes to your channel for subscribers to use! However, Follower emotes are only available if you have [Instant Upload Privilege](https://help.twitch.tv/s/article/emote-guidelines?language=en_US#instantupload)
## Emote extensions
Don’t understand when your chat says in ‘KEKW’? It’s a common third party Twitch emote! You can add extensions to your channel to add more emotes for your viewers to use. Some popular ones include BetterTTV, FrankerFaceZ and 7TV.
### Browser Extensions
- [Download BetterTTV](https://betterttv.com/)
- [Download FrankerFaceZ](https://www.frankerfacez.com/)
- [Download 7TV](https://7tv.app/)
You won’t run into any issues using all three extensions at once!
However, if you only want to use one Emote extension, [FrankerFaceZ](https://www.frankerfacez.com/) is probably the best one to go for! It is stable, has special addons through the extension itself for BTTV and 7TV emotes, and has the best customization for twitch as a site!
---

View file

@ -0,0 +1,84 @@
---
title: General Tips
layout: "../../layouts/GuideLayout.astro"
description: General tips for your coworking streams!
order: 0
---
# General Tips
General tips for your coworking streams!
---
## Should I mute?
Most streamers mute themselves during the work sessions because it makes it easier for the viewers to focus. However it’s also possible to leave the mic on for keyboard asmr and general “office noise” which many people enjoy - ask your community what they prefer!
## Chat commands for coworking streams
Chat commands are very useful since you won't be chatting much during the work timer. Some common chat commands you may see include ones that introduce your stream, provide a brief introduction to the pomodoro method (if you use it), or a muted command that may explain why you may be muted (e.g: !welcome !timer !pomo !muted). You may also like to add a command to tell your viewers what you're working on that day (!today !work !study) - this adds a nice personal touch and you can use it to encourage other's to talk about what they're working on too.
## Closed Captions
[MAXIMIZE Your Reach on Twitch with Live Captions](https://youtu.be/cQzJL9uoIbg)
Closed captions open your stream to a wider audience by including viewers who are deaf or hard of hearing, and can even benefit viewers in noisy environments who might miss some dialogue.
---
## Do's
- ### Have control of your ad timings
```
https://dashboard.twitch.tv/popout/u/{{channel}}/stream-manager/streamer-ads-manager-panel
```
If you're using OBS, you can add the link above as a dock to your OBS (remember to replace "\{\{channel\}\}" with your actual channel name). This way, you can easily run ads and view when your next ad break is without having to go to the Twitch dashboard.
- ### Have a consistent stream schedule
A regular stream schedule lets your viewers know exactly when to expect you to go live. When viewers can anticipate your streams, they are more likely to make time to watch, increasing the chances of them tuning in and engaging with your content.
Regularly scheduled streams also help you attract and retain viewers. When new viewers find your stream, they are more likely to follow if they see a consistent schedule. Additionally, existing followers are more likely to continue watching if they know when to catch your streams.
- ### Social Media Marketing
Having good social media marketing allows you to reach a broader audience beyond your live streams. Utilizing platforms like Instagram and YouTube (even YouTube Shorts!) enables you to promote your content, engage with potential viewers and build a loyal following, increasing visibility and attracting new members to your community.
- ### Use stream layouts that make your stream stand out
On Twitch, people would go through the browse section with a frame of your stream as the thumbnail. If you want to increase the chances of people clicking onto your stream, you should make your stream more attractive.
- ### Interact with Chat
Interacting with your chat is crucial to grow your community because it fosters a sense of engagement and connection with your audience. By acknowledging and responding to viewers, you create a welcoming and inclusive atmosphere, encouraging viewers to stay, become regulars, and invite others, ultimately leading to organic community growth.
- ### Network with other streamers
Having good networking opens up collaboration opportunities, cross-promotion, and exposure to each other’s audiences. By forming connections within the streaming community, you can tap into a larger pool of viewers, gain credibility, and foster a supportive environment that encourages mutual growth and success.
---
## Don'ts
- ### Don't get distracted by chat
One concern for many new coworking streamers is that they are worried about ignoring chat. This is the hard part! It's important (and very tempting) to interact with your community but it's also important you are able to get your work done. That's the point after all!. Remember you're there to work so try not to feel guilty about ignoring new people - it's useful to have mods who can do this for you instead. And you can always chat with them in your breaktime! If you're too busy to answer questions, it can be useful to have a command like !muted to let new people know that you are trying to focus and will chat later.
- ### Don't self promote
Hopping on chat and mention anything about your own stream is considered self-promotion and can be considered rude, especially when no permission was granted.
- ### Don't worry about view count
Just focus on your work.
- ### Avoid using Display Capture
Some coworking streamers may have Display Capture source on their primary pomodoro scene for extra accountability. However, this may leak sensitive information such as Email, full name, credentials etc.
It is recommended to blur it, or make your Display Capture source very small until no text content is readable.
---

View file

@ -0,0 +1,64 @@
---
title: Moderation and Trolls
layout: "../../layouts/GuideLayout.astro"
description: Learn how to moderate your coworking streams!
order: 6
---
# Moderation and Trolls
---
## Moderation
Having a good moderation team is important for coworking streamers, since most of the time we are focused on our own work and not chat! This is why it's particularly important to have a good moderation team to help you out so you don't get distracted.
Consider these three main things when choosing your mods:
- How well do they all get along with each other?
- What is their availability?
- Are they good at staying calm and being reasonable?
As well as this, it is ideal if mods are welcoming and active in your community - you can't always be there to say hi to everyone while your working so it's great to have a friendly mod team to welcome new people and answer questions!
:::note
How you invite your mods is a personal choice! And don't feel bad if you ask someone and they say no - not everyone is up for the job! If you know someone you'd like as a mod you could DM them with a personal invite, otherwise you could create an application form if that suits you and your community better!
:::
---
## Bots and trolls
As with any social media platform, you may encounter trolls and bots while you stream. If this happens, it is best to stay calm and work with your mods to resolve the situation; most of the time it is just annoying and won't result in anything serious. The following section is not an exhaustive list and this only meant as friendly advice. Please make sure you have read twitch TOS and only do what makes you feel comfortable and safe.
- ### Generic Trolls
For trolls that enter your chat and immediately send very inappropriate messages (e.g. hateful/sexual content) it is best to ignore them, ban them straightaway and move on. Giving them attention may create a negative atmosphere in your stream and make others feel unsafe. Try not to take these comments personally - it is unlikely to be targeted and they probably just want to get a reaction out of you.
- ### Promotional bots
This is when several bot accounts post in your chat with the same message, usually advertising a "get famous quick" scam. To stop this, you can put your chat in follower only mode by typing `/followers` in your chat. Usually they will go away quickly and you can type `/followersoff` to change it back.
You can also make use of the AutoMod feature by banning phrases like "bigfollow", so their messages get automatically removed. You can find this in your Dashboard Settings → Moderation. If you would like, you can also block hyperlinks in the same page or a stream bot (NightBot, StreamElements, etc.)
- ### Follow bots/raids
This is when several bot accounts follow your channel all at the same time. It can be anywhere from 10-10k. If this happens, stay calm, and turn off follower alerts to stop the alert spam. Sometimes the bots will also send messages all at once so you put your chat in subscriber mode to prevent this if you wish (type <span class="code-highlight">/subscribers</span> in your chat).
To get rid of bots, you can use [CommanderRoot's follower removal tool](https://twitch-tools.rootonline.de/follower_remover.php). Follow the instructions on his home page to remove accounts between a certain timeframe (you'll need to know what time the bots followed to avoid removing real people). Alternatively, you can just wait and Twitch will delete the accounts after a few days. Your follower count will drop suddenly but this is good - you don't want bots following you!
- ### Donation trolls
These are particularly nasty trolls. They donate money, anywhere from $10-$200 or more, maybe repeatedly, and will not talk very much in the chat, aside from making some request in exchange for the money they just donated. They then will ask for a chargeback (if youre using paypal). You can try and fight the case but there is a good change you will not win, and if you lose you have to pay $14 chargeback fee each time. This can add up over time. If you suspect someone is a Dono troll, you can block them from donating:
Go to your [donation page](https://streamlabs.com/dashboard#/donations). There should be a list of names and donations:
<img src="/images/moderation-and-trolls/donation-troll.webp" alt="Donation troll" loading="lazy" />
<br>
Also in Settings > Donation settings, make sure you've ticked "Login Required":
<img src="/images/moderation-and-trolls/donation-settings.webp" alt="Donation settings" loading="lazy" />
---

View file

@ -0,0 +1,132 @@
---
title: Music and Audio
layout: "../../layouts/GuideLayout.astro"
description: Learn how to add music or audio for your coworking streams!
order: 1
---
# Music and Audio
The vibe of a coworking stream is determined by the background music or audio!
---
## Non-DMCA Playlists
> DMCA: Digital Millenium Copyright Act
Non-copyrighted music playlists for you to listen on stream!
### Lofi Girl
- [Spotify](https://open.spotify.com/playlist/0vvXsWCC9xrXsKd4FyS8kM?si=65d4b951673847a2)
- [YouTube (playlist)](https://www.youtube.com/watch?v=CMNyHBx1gak&list=PL6NdkXsPL07KN01gH2vucrHCEyyNmVEx4)
- [SoundCloud](https://soundcloud.com/lofi_girl)
### Lofi Boy (Synthwave)
- [Spotify](https://open.spotify.com/playlist/1YIe34rcmLjCYpY9wJoM2p?si=f5115c5c9b644871)
- [YouTube (video)](https://youtu.be/TlWYgGyNnJo)
### Chillhop
- [Spotify](https://open.spotify.com/user/chillhopmusic?si=b9c63cbb27db45ab&nd=1&dlsi=477657d953294e71)
- [YouTube (playlist)](https://www.youtube.com/watch?v=XuW2hx3h7sE&list=PLt7bG0K25iXgkGK9PLhP3yryqc7S8uHds)
- [SoundCloud](https://soundcloud.com/chillhopdotcom)
### Lud and Schlatts Musical Emporium - Classical
- [YouTube (playlist)](https://youtu.be/VBSP75pr2bg?list=PL2LwrpMfls5K1DVyG5ii_mEGKqzK9EGlr)
---
## How to Display 'Now Playing'
### [6K Labs 🔗](https://6klabs.com/)
<a href="https://6klabs.com/"><img src="/images/music-and-audio/6klabs.webp" alt="6K Labs widget" loading="lazy" /></a>
- Easy to implement
- Available for YouTube Music and Spotify
- Has many design choices and settings:
- Dark/Light mode
- Tint colour options
- Different aesthetic choices:
- Compact
- macOS
- Linux Shell
- And many more!
### [Pixel Chat 🔗](https://pixelchat.tv/)
<a href="https://pixelchat.tv/"><img src="/images/music-and-audio/pixelchat.webp" alt="Pixel Chat widget" loading="lazy" /></a>
- Shows what you're playing via Spotify, Apple Music etc.
- Includes other widgets for shoutouts, captions and counters
---
## Non-music options
Don't like listening to music? Still worried about DMCA? Want other forms of background audio to stand out amongst other streamers? Don't worry! Here are a few suggestions for your background ambience that doesn't involve music!
The following websites allow you to download audio files, so you can add to your streaming application (e.g. OBS) as a Media Source.
**Note: Please be careful when downloading any files onto your computer.**
- ### [Coffee Shop Ambience 🔗](https://pixabay.com/sound-effects/search/coffee%20shop/)
The low hum of conversation and coffee shop bustle can provide a focused ambience that aids studying.
- ### [Forest Ambience 🔗](https://pixabay.com/sound-effects/search/forest%20ambience/)
The calming sounds of nature in a forest ambience can create a peaceful and focused atmosphere.
- ### [Rain Ambience 🔗](https://pixabay.com/sound-effects/search/rain/)
The steady pitter-patter of rain ambience offers a soothing and concentration-boosting backdrop for studying.
- ### [Ocean Ambience 🔗](https://pixabay.com/sound-effects/search/ocean%20ambience/)
With its rhythmic waves, provides a calming yet stimulating soundscape that can enhance focus.
- ### [Fireplace Ambience 🔗](https://pixabay.com/sound-effects/search/fireplace/)
The crackle and warmth of a fireplace ambience create a cozy and concentration-promoting environment for studying.
---
## How to Separate Audio for Twitch VOD
[How to SEPARATE AUDIO for Twitch VOD with OBS studio (NO Voicemeeter) 🔗](https://www.youtube.com/watch?v=0Lj5rkqSp48)
If you’re streaming on Twitch using OBS, you can easily avoid getting your VODs muted by separating audio tracks into VOD audio tracks and stream audio tracks. This way, you can listen to music on your stream without worrying about getting muted.
---
## How to Separate your Audio for meetings/classes
### Easy way (have two different outputs)
<img src="/images/music-and-audio/audio_settings.webp" alt="Audio settings" loading="lazy" />
To do this, you'll need to have two different audio outputs (i.e. two headphones/speakers). For windows users, go to sound settings --> advance sound options --> app volume device preferences (or if you can't find it, search "sound mixer options" in your start) then you should see this:
There you can have your different outputs for different programmes. For example, one pair of headphones is used for zoom, and the other for everything else. In your streaming software, make sure the output is selected for the correct pair of headphones in your mixer!
### Complicated ways
- #### [VoicemeeterBanana](https://vb-audio.com/Voicemeeter/banana.htm)
![Windows Badge](https://img.shields.io/badge/Windows-0078D4?logo=windows&logoColor=fff&style=for-the-badge)
- Download Voicemeeter Banana (software to route audio sources) and set all the audio sources/inputs you don't want to include on stream into a Voicemeeter input/output source separate from the main routing.
- The outputs will show up separately in your Audio Mixer, which you can adjust/mute
- Tutorial: [Separate Game Audio, Discord, Music in OBS! (A Voicemeeter Tutorial for Beginners)](https://www.youtube.com/watch?v=XD9sWOjITYU&t=376s)
- #### [BlackHole audio](https://obsproject.com/forum/resources/mac-desktop-audio-using-blackhole.1191/)
![macOS Badge](https://img.shields.io/badge/macOS-fff?logo=macos&logoColor=000&style=for-the-badge)
- Free! Integrates with OBS
- #### [GroundControl Caster](https://gingeraudio.com/groundcontrol-caster/)
![macOS Badge](https://img.shields.io/badge/macOS-fff?logo=macos&logoColor=000&style=for-the-badge)
- Free! Integrates with Twitch, OBS, StreamLabs, Zoom, FaceTime etc.

View file

@ -0,0 +1,101 @@
---
title: Stream Bots
layout: "../../layouts/GuideLayout.astro"
description: Stream bots for your coworking streams!
order: 3
---
# Stream Bots
Useful bots to add to your stream!
---
## Cloud-hosted bots
### [Sery Bot 🔗](https://serycodes.carrd.co/)
<div class="flex flex-row gap-2">
Available on:
![Twitch Badge](https://img.shields.io/badge/Twitch-9146FF?logo=twitch&logoColor=fff&style=for-the-badge)
</div>
Sery Bot is a moderation bot providing anti-hate raid and anti-follow bot protections, and other safety features and tools to streamers.
### [MohCitrus 🔗](https://www.twitch.tv/MohCitrus/about)
<div class="flex flex-row gap-2">
Available on:
![Twitch Badge](https://img.shields.io/badge/Twitch-9146FF?logo=twitch&logoColor=fff&style=for-the-badge)
</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!
![MohCitrus](/images/bots/mohcitrus.webp)
### [Nightbot 🔗](https://nightbot.tv/)
<div class="flex flex-row gap-2">
Available on:
![Twitch Badge](https://img.shields.io/badge/Twitch-9146FF?logo=twitch&logoColor=fff&style=for-the-badge)
![YouTube Badge](https://img.shields.io/badge/YouTube-F00?logo=youtube&logoColor=fff&style=for-the-badge)
</div>
Nightbot is a chatbot that you can use to manage your chat. It has a lot of features and is easy to use. You can also use it to create custom commands for your stream.
### [BotRix 🔗](https://botrix.live/)
<div class="flex flex-row gap-2">
Available on:
![Twitch Badge](https://img.shields.io/badge/Twitch-9146FF?logo=twitch&logoColor=fff&style=for-the-badge)
![YouTube Badge](https://img.shields.io/badge/YouTube-F00?logo=youtube&logoColor=fff&style=for-the-badge)
</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.
---
## Local bots
### [Streamer.bot 🔗](https://streamer.bot/)
<div class="flex flex-row gap-2">
Available on:
![Twitch Badge](https://img.shields.io/badge/Twitch-9146FF?logo=twitch&logoColor=fff&style=for-the-badge)
![YouTube Badge](https://img.shields.io/badge/YouTube-F00?logo=youtube&logoColor=fff&style=for-the-badge)
![Windows Badge](https://img.shields.io/badge/Windows-0078D4?logo=windows&logoColor=fff&style=for-the-badge)
</div>
Supercharge your livestream! Add advanced levels of interactivity to your streams with Streamer.bot.
### [Mix It Up bot 🔗](https://mixitupapp.com/)
<div class="flex flex-row gap-2">
Available on:
![Twitch Badge](https://img.shields.io/badge/Twitch-9146FF?logo=twitch&logoColor=fff&style=for-the-badge)
![YouTube Badge](https://img.shields.io/badge/YouTube-F00?logo=youtube&logoColor=fff&style=for-the-badge)
![Windows Badge](https://img.shields.io/badge/Windows-0078D4?logo=windows&logoColor=fff&style=for-the-badge)
</div>
Mix It Up is a free, full featured, community driven, open-source stream bot developed by streamers for streamers.
---

View file

@ -0,0 +1,76 @@
---
title: Stream Layouts
layout: "../../layouts/GuideLayout.astro"
description: Learn how to moderate your coworking streams!
order: 2
---
# Stream Layouts
An organized layout structures information effectively, allowing viewers to easily find the elements they need, such as timers, chat windows, and your work area.
---
## [Canva 🔗](https://www.canva.com/)
Canva is a free graphic design platform that is fairly intuitive to use and quick to pick up on! You can use this site to build any layout or to get inspired with templates. You can upload this into your software as a image or gif.
---
## [Figma 🔗](https://www.figma.com/)
Figma is a collaborative web application for interface design, with additional offline features enabled by desktop applications for macOS and Windows.
---
## Royalty free images & icons
### [Pexels 🔗](https://www.pexels.com/license/)
Pexels provides high quality and completely free stock photos licensed under the Pexels license. All photos are nicely tagged, searchable and also easy to discover through our discover pages.
### [The Noun Project 🔗](https://thenounproject.com/)
The Noun Project is a website that aggregates and catalogs symbols that are created and uploaded by graphic designers around the world.
---
## Fonts
### [DaFont 🔗](https://www.dafont.com/)
DaFont is a popular online platform where you can download fonts for various purposes. Whether you’re working on a design project, creating digital art, or just want to add a unique touch to your documents.
### [Google Fonts 🔗](https://fonts.google.com/)
Google Fonts is a service provided by Google that offers a wide selection of high-quality web fonts for use in web projects.
---
## Principles of Grouping
The principles of grouping explain how our brains see patterns. We naturally group things that are close together, look similar, or are connected. This helps us make sense of the visual world around us.
There are five main principles of grouping:
- **Proximity**: Objects close together are perceived as being related. Imagine scattered stars. We tend to see groups or constellations based on closeness, even if the stars aren't truly connected.
- **Similarity**: Objects that look similar are seen as belonging together. A row of red balls amongst yellow ones will likely be perceived as a separate group.
- **Continuity**: Elements arranged along a line or curve are perceived as following a path and being related. Think of stepping stones leading across a stream.
- **Closure**: We tend to fill in gaps to create a complete whole. A broken circle can still be recognized as a circle despite the missing portion.
- **Connectedness**: Elements linked by lines or shapes are seen as a unit. Imagine overlapping squares – our brains will likely group them based on the connection.
These principles are used extensively in various fields like design, art, and advertising. By understanding how we group things visually, designers can create layouts that are clear, organized, and engaging.
---
## Videos
Some cool YouTube videos on this topic if you want some inspiration!
- [How-to: Easy "Graphic Design" on Google Slides (for VTubers and Streamers)](https://youtu.be/VoF-Qk_tWgU)
- [How to Make an Overlay for Streaming! Tips for Artists and Gamers!](https://youtu.be/OBXK9qi4j8E)
- [Create Minimal Stream Overlays From Scratch! (Without Photoshop!)](https://youtu.be/Rs75ovA7Fvo)

View file

@ -0,0 +1,108 @@
---
title: Stream Widgets
layout: "../../layouts/GuideLayout.astro"
description: Stream widgets for your coworking streams!
order: 4
---
# Stream widgets
Widgets to add to your stream!
---
## Pomodoro timer
A pomodoro timer is a great way to keep track of your work sessions. It’s also a great way to let your viewers know when you’re taking a break. You can use a pomodoro timer widget to display the current work session and break time.
### Browser Sources
#### [MohFocus' Minimal Pomo Timer 🔗](https://github.com/mohamed-tayeh/Minimal-Pomo-Timer)
[![Minimal Pomo Timer](/images/widgets/moh-minimal-timer.webp)](https://github.com/mohamed-tayeh/Minimal-Pomo-Timer)
- Twitch only
- Easy to setup and customize
- Called through commands in Twitch chat
- Optionally post break time notifications to Discord
#### [Mayuko's Pomodoro Countdown Timer 🔗](https://github.com/hellomayuko/Pomodoro-Countdown)
<a href="https://github.com/hellomayuko/Pomodoro-Countdown"><img src="/images/widgets/mayuko-pomo.webp" alt="Mayuko Pomodoro Countdown Timer" loading="lazy" /></a>
- Easy to setup and customize
- Interactive through OBS
### Window Capture
#### [Pomofocus 🔗](https://pomofocus.io/)
<a href="https://pomofocus.io/"><img src="/images/widgets/pomofocus.webp" alt="pomofocus" loading="lazy" /></a>
- You can also add tasks to do on the web page
---
## Task widgets
A task list widget is a great way to keep track of your tasks along with your chatters!
### [Rython Task Bot 🔗](https://github.com/liyunze-coding/chat-task-tic-overlay-infinity)
<a href="https://github.com/liyunze-coding/chat-task-tic-overlay-infinity"><img src="/images/widgets/rythontaskbot.webp" alt="Rython Task Bot" loading="lazy" /></a>
- Free and open source
- Easy to use, setup and customize
- Horizontal version available
- Used by 100+ streamers
- Handles only one incomplete task per user
### [Multi-task Widget 🔗](https://ko-fi.com/s/94e7e8dc81)
<a href="https://ko-fi.com/s/94e7e8dc81"><img src="/images/widgets/multitask.webp" alt="Multi Task Widget" loading="lazy" /></a>
- $50 USD on ko-fi
- Easy to use, setup and customize
- Several versions to choose from:
- Original version
- Streamer bot version (Windows only, stream to YouTube and Twitch!)
- Horizontal version
### [Super Sweet Bot 🔗](https://www.patreon.com/super_sweet_bot)
<a href="https://www.patreon.com/super_sweet_bot"><img src="/images/widgets/supersweetbot.webp" alt="Super Sweet Bot" loading="lazy" /></a>
- €3 / month
- Comes with a Pomo Timer
- Colors are customizable
- Hosted on a cloud server
---
## Music Widgets
Display what you're playing on Spotify or YouTube Music!
### [6K Labs 🔗](https://6klabs.com/)
<a href="https://6klabs.com/"><img src="/images/music-and-audio/6klabs.webp" alt="6K Labs widget" loading="lazy" /></a>
- Easy to implement
- Available for YouTube Music and Spotify
- Has many design choices and settings:
- Dark/Light mode
- Tint colour options
- Different aesthetic choices:
- Compact
- macOS
- Linux Shell
- And many more!
### [Pixel Chat 🔗](https://pixelchat.tv/)
<a href="https://pixelchat.tv/"><img src="/images/music-and-audio/pixelchat.webp" alt="Pixel Chat widget" loading="lazy" /></a>
- Shows what you're playing via Spotify, Apple Music etc.
- Includes other widgets for shoutouts, captions and counters
---

View file

@ -1,854 +1,17 @@
---
import Layout from "../layouts/Layout.astro";
import Hero from "../components/blocks/Hero.astro";
import BlurBackground from "../components/ui/BlurBackground.astro";
---
<Layout
title="Get started with Coworking streams"
title="Coworking Stream Guide"
description="A guide for new and existing coworking streamers!"
>
<div
class="flex flex-col lg:flex-row justify-center items-center text-gray-100 sm:flex-col h-fit min-h-screen"
>
<div
class="w-full lg:w-2/3 flex flex-col justify-center items-center mt-40 lg:mt-0 mb-10 lg:mb-0"
>
<div
class="flex flex-col justify-center items-center lg:items-start text-center lg:text-left"
>
<p class="text-xl mb-1 mt-24 lg:mt-0">
How to get started with
</p>
<h1 class="text-2xl lg:text-4xl font-bold">
Coworking Streams
</h1>
<p class="text-lg lg:text-xl mt-2">
For coworking & study streamers on Twitch
</p>
<p class="text-lg mt-0 md:hidden">
Click on the navigation icon on the top right to get
started!
</p>
<p class="text-lg mt-0 hidden md:block">
Click on the navigation bar above to get started!
</p>
</div>
</div>
<div
class="w-full lg:w-1/3 h-full flex flex-col justify-center items-center"
>
<a
href="/widgets#task-list-widget"
class="preview w-full flex items-center justify-center"
>
<div
class="task-list w-5/6 flex flex-col rounded-md overflow-hidden mb-10 lg:mb-0 border border-solid border-white hover:shadow-gray-200 hover:shadow-lg transition duration-300 ease-in-out"
>
<div
class="task-list-header text-2xl flex flex-row justify-between bg-gray-900 px-5 py-3 rounded-md z-10 border border-solid border-b-white"
>
<div id="widget-title" class="font-bold">!taskhelp</div>
<div>1/65</div>
</div>
<div class="task-list-body px-1">
<div
class="flex flex-row justify-start items-start bg-gray-700 px-5 py-2 rounded-md mt-1"
>
<div
class="font-bold max-w-[45%] overflow-hidden overflow-ellipsis text-pink-400"
>
RyanPython
</div>
<div class="mr-1">:</div>
<span class="line-through">build this website</span>
</div>
<div
class="flex flex-row justify-start items-start bg-gray-700 px-5 py-2 rounded-md mt-1"
>
<div
class="font-bold max-w-[45%] overflow-hidden overflow-ellipsis text-blue-500"
>
MohFocus
</div>
<div class="mr-1">:</div>
<span>resolve merge conflict</span>
</div>
<div
class="flex flex-row justify-start items-start bg-gray-700 px-5 py-2 rounded-md mt-1"
>
<div
class="font-bold max-w-[45%] overflow-hidden overflow-ellipsis text-green-400"
>
j3dg
</div>
<div class="mr-1">:</div>
<span>spin class</span>
</div>
<div
class="flex flex-row justify-start items-start bg-gray-700 px-5 py-2 rounded-md mt-1"
>
<div
class="font-bold max-w-[45%] overflow-hidden overflow-ellipsis text-purple-400"
>
berryspace
</div>
<div class="mr-1">:</div>
<span>setup coworking stream</span>
</div>
<div
class="flex flex-row justify-start items-start bg-gray-700 px-5 py-2 rounded-md mt-1"
>
<div
class="font-bold max-w-[45%] overflow-hidden overflow-ellipsis text-yellow-600"
>
CloudyDayzzz
</div>
<div class="mr-1">:</div>
<span>interpret sign language</span>
</div>
<div
class="flex flex-row justify-start items-start bg-gray-700 px-5 py-2 rounded-md mt-1"
>
<div
class="font-bold max-w-[45%] overflow-hidden overflow-ellipsis text-yellow-600"
>
pcc_lanezzz
</div>
<div class="mr-1">:</div>
<span>torture Poco</span>
</div>
<div
class="flex flex-row justify-start items-start bg-gray-700 px-5 py-2 rounded-md mt-1"
>
<div
class="font-bold max-w-[45%] overflow-hidden overflow-ellipsis text-pink-400"
>
lala_xitlali
</div>
<div class="mr-1">:</div>
<span>buy more fabric</span>
</div>
<div
class="flex flex-row justify-start items-start bg-gray-700 px-5 py-2 rounded-md mt-1"
>
<div
class="font-bold max-w-[45%] overflow-hidden overflow-ellipsis text-green-600"
>
xeno_hiraeth
</div>
<div class="mr-1">:</div>
<span>diagnose patients</span>
</div>
<div
class="flex flex-row justify-start items-start bg-gray-700 px-5 py-2 rounded-md mt-1"
>
<div
class="font-bold max-w-[45%] overflow-hidden overflow-ellipsis text-purple-400"
>
opoemperdernida
</div>
<div class="mr-1">:</div>
<span>rutina de la mañana</span>
</div>
<div
class="flex flex-row justify-start items-start bg-gray-700 px-5 py-2 rounded-md mt-1"
>
<div
class="font-bold max-w-[45%] overflow-hidden overflow-ellipsis text-pink-300"
>
4l1c3_0
</div>
<div class="mr-1">:</div>
<span>mental breakdance</span>
</div>
<div
class="flex flex-row justify-start items-start bg-gray-700 px-5 py-2 rounded-md mt-1"
>
<div
class="font-bold max-w-[45%] overflow-hidden overflow-ellipsis text-gray-200"
>
studywithjojo
</div>
<div class="mr-1">:</div>
<span>get into NHS</span>
</div>
<div
class="flex flex-row justify-start items-start bg-gray-700 px-5 py-2 rounded-md mt-1"
>
<div
class="font-bold max-w-[45%] overflow-hidden overflow-ellipsis text-purple-400"
>
StudyPaws
</div>
<div class="mr-1">:</div>
<span>identify cow breeds</span>
</div>
<div
class="flex flex-row justify-start items-start bg-gray-700 px-5 py-2 rounded-md mt-1"
>
<div
class="font-bold max-w-[45%] overflow-hidden overflow-ellipsis text-blue-500"
>
mikewhatwhere
</div>
<div class="mr-1">:</div>
<span>become a dietician</span>
</div>
<div
class="flex flex-row justify-start items-start bg-gray-700 px-5 py-2 rounded-md mt-1"
>
<div
class="font-bold max-w-[45%] overflow-hidden overflow-ellipsis text-red-500"
>
AuspexOneGaming
</div>
<div class="mr-1">:</div>
<span>grade papers</span>
</div>
<div
class="flex flex-row justify-start items-start bg-gray-700 px-5 py-2 rounded-md mt-1"
>
<div
class="font-bold max-w-[45%] overflow-hidden overflow-ellipsis text-red-500"
>
BossOnCamera
</div>
<div class="mr-1">:</div>
<span>get into Kyoto University</span>
</div>
<div
class="flex flex-row justify-start items-start bg-gray-700 px-5 py-2 rounded-md mt-1"
>
<div
class="font-bold max-w-[45%] overflow-hidden overflow-ellipsis text-pink-400"
>
samkitkat
</div>
<div class="mr-1">:</div>
<span>codewars exercises</span>
</div>
<div
class="flex flex-row justify-start items-start bg-gray-700 px-5 py-2 rounded-md mt-1"
>
<div
class="font-bold max-w-[45%] overflow-hidden overflow-ellipsis text-green-300"
>
euphie___
</div>
<div class="mr-1">:</div>
<span>be a cinnamon roll</span>
</div>
<div
class="flex flex-row justify-start items-start bg-gray-700 px-5 py-2 rounded-md mt-1"
>
<div
class="font-bold max-w-[45%] overflow-hidden overflow-ellipsis text-purple-400"
>
charliosaurus
</div>
<div class="mr-1">:</div>
<span>praise the lord Jesus Christ</span>
</div>
<div
class="flex flex-row justify-start items-start bg-gray-700 px-5 py-2 rounded-md mt-1"
>
<div
class="font-bold max-w-[45%] overflow-hidden overflow-ellipsis text-orange-600"
>
unknownnie
</div>
<div class="mr-1">:</div>
<span>grow a sprout</span>
</div>
<div
class="flex flex-row justify-start items-start bg-gray-700 px-5 py-2 rounded-md mt-1"
>
<div
class="font-bold max-w-[45%] overflow-hidden overflow-ellipsis text-gray-200"
>
imJamJams
</div>
<div class="mr-1">:</div>
<span>feed the mods</span>
</div>
<div
class="flex flex-row justify-start items-start bg-gray-700 px-5 py-2 rounded-md mt-1"
>
<div
class="font-bold max-w-[45%] overflow-hidden overflow-ellipsis text-blue-500"
>
itsbrandonut
</div>
<div class="mr-1">:</div>
<span>music stream</span>
</div>
<div
class="flex flex-row justify-start items-start bg-gray-700 px-5 py-2 rounded-md mt-1"
>
<div
class="font-bold max-w-[45%] overflow-hidden overflow-ellipsis text-blue-500"
>
nihnesyo
</div>
<div class="mr-1">:</div>
<span>release new Lofi EP</span>
</div>
<div
class="flex flex-row justify-start items-start bg-gray-700 px-5 py-2 rounded-md mt-1"
>
<div
class="font-bold max-w-[45%] overflow-hidden overflow-ellipsis text-purple-400"
>
warpyn
</div>
<div class="mr-1">:</div>
<span>release new song cover</span>
</div>
<div
class="flex flex-row justify-start items-start bg-gray-700 px-5 py-2 rounded-md mt-1"
>
<div
class="font-bold max-w-[45%] overflow-hidden overflow-ellipsis text-gray-200"
>
shadygepril
</div>
<div class="mr-1">:</div>
<span>studying for A-Levels</span>
</div>
<div
class="flex flex-row justify-start items-start bg-gray-700 px-5 py-2 rounded-md mt-1"
>
<div
class="font-bold max-w-[45%] overflow-hidden overflow-ellipsis text-yellow-300"
>
Extelso
</div>
<div class="mr-1 max-w-[55%]">:</div>
<span>show off stream layout</span>
</div>
<div
class="flex flex-row justify-start items-start bg-gray-700 px-5 py-2 rounded-md mt-1"
>
<div
class="font-bold max-w-[45%] overflow-hidden overflow-ellipsis text-blue-400"
>
Bubxmicn
</div>
<div class="mr-1">:</div>
<span>drive a truck</span>
</div>
<div
class="flex flex-row justify-start items-start bg-gray-700 px-5 py-2 rounded-md mt-1"
>
<div
class="font-bold max-w-[45%] overflow-hidden overflow-ellipsis text-pink-400"
>
theyolotato
</div>
<div class="mr-1">:</div>
<span>read smut</span>
</div>
<div
class="flex flex-row justify-start items-start bg-gray-700 px-5 py-2 rounded-md mt-1"
>
<div
class="font-bold max-w-[45%] overflow-hidden overflow-ellipsis text-orange-400"
>
sneakymoon_
</div>
<div class="mr-1">:</div>
<span>edit YouTube vlogs</span>
</div>
<div
class="flex flex-row justify-start items-start bg-gray-700 px-5 py-2 rounded-md mt-1"
>
<div
class="font-bold max-w-[45%] overflow-hidden overflow-ellipsis text-pink-400"
>
nanakitchen
</div>
<div class="mr-1">:</div>
<span>annoy sneakymoon_</span>
</div>
<div
class="flex flex-row justify-start items-start bg-gray-700 px-5 py-2 rounded-md mt-1"
>
<div
class="font-bold max-w-[45%] overflow-hidden overflow-ellipsis text-orange-600"
>
pinsaregood
</div>
<div class="mr-1">:</div>
<span>be an instagram influencer</span>
</div>
<div
class="flex flex-row justify-start items-start bg-gray-700 px-5 py-2 rounded-md mt-1"
>
<div
class="font-bold max-w-[45%] overflow-hidden overflow-ellipsis text-blue-500"
>
wasmishtaken_
</div>
<div class="mr-1">:</div>
<span>simp for levi</span>
</div>
<div
class="flex flex-row justify-start items-start bg-gray-700 px-5 py-2 rounded-md mt-1"
>
<div
class="font-bold max-w-[45%] overflow-hidden overflow-ellipsis text-yellow-300"
>
Jutstreams
</div>
<div class="mr-1">:</div>
<span>play geoguessr</span>
</div>
<div
class="flex flex-row justify-start items-start bg-gray-700 px-5 py-2 rounded-md mt-1"
>
<div
class="font-bold max-w-[45%] overflow-hidden overflow-ellipsis text-gray-200"
>
GuluTwitch
</div>
<div class="mr-1">:</div>
<span>take care of Gulu</span>
</div>
<div
class="flex flex-row justify-start items-start bg-gray-700 px-5 py-2 rounded-md mt-1"
>
<div
class="font-bold max-w-[45%] overflow-hidden overflow-ellipsis text-purple-400"
>
j2modest
</div>
<div class="mr-1">:</div>
<span>penetration testing</span>
</div>
<div
class="flex flex-row justify-start items-start bg-gray-700 px-5 py-2 rounded-md mt-1"
>
<div
class="font-bold max-w-[45%] overflow-hidden overflow-ellipsis text-yellow-200"
>
nachoburrit0
</div>
<div class="mr-1">:</div>
<span>play Apex for charity</span>
</div>
<div
class="flex flex-row justify-start items-start bg-gray-700 px-5 py-2 rounded-md mt-1"
>
<div
class="font-bold max-w-[45%] overflow-hidden overflow-ellipsis text-yellow-500"
>
clarissawrites
</div>
<div class="mr-1">:</div>
<span>10,000 words essay</span>
</div>
<div
class="flex flex-row justify-start items-start bg-gray-700 px-5 py-2 rounded-md mt-1"
>
<div
class="font-bold max-w-[45%] overflow-hidden overflow-ellipsis text-[#aae2cd]"
>
PottleLive
</div>
<div class="mr-1">:</div>
<span class="max-w-[75%]"
>Promote Erudita and protest the french
government</span
>
</div>
<div
class="flex flex-row justify-start items-start bg-gray-700 px-5 py-2 rounded-md mt-1"
>
<div
class="font-bold max-w-[45%] overflow-hidden overflow-ellipsis text-gray-200"
>
long1nteger
</div>
<div class="mr-1">:</div>
<span class="max-w-[65%]"
>work on the next AI project for self.dev</span
>
</div>
<div
class="flex flex-row justify-start items-start bg-gray-700 px-5 py-2 rounded-md mt-1"
>
<div
class="font-bold max-w-[45%] overflow-hidden overflow-ellipsis text-red-400"
>
Elly78456
</div>
<div class="mr-1">:</div>
<span>sell merch</span>
</div>
<div
class="flex flex-row justify-start items-start bg-gray-700 px-5 py-2 rounded-md mt-1"
>
<div
class="font-bold max-w-[45%] overflow-hidden overflow-ellipsis text-yellow-400"
>
sunfflawer
</div>
<div class="mr-1">:</div>
<span>be clingy</span>
</div>
<div
class="flex flex-row justify-start items-start bg-gray-700 px-5 py-2 rounded-md mt-1"
>
<div
class="font-bold max-w-[45%] overflow-hidden overflow-ellipsis text-gray-100"
>
xhumming
</div>
<div class="mr-1">:</div>
<span>feed Emmy</span>
</div>
<div
class="flex flex-row justify-start items-start bg-gray-700 px-5 py-2 rounded-md mt-1"
>
<div
class="font-bold max-w-[45%] overflow-hidden overflow-ellipsis text-blue-500"
>
arcaneXVIII
</div>
<div class="mr-1">:</div>
<span>babysit</span>
</div>
<div
class="flex flex-row justify-start items-start bg-gray-700 px-5 py-2 rounded-md mt-1"
>
<div
class="font-bold max-w-[45%] overflow-hidden overflow-ellipsis text-purple-400"
>
OOPmarie
</div>
<div class="mr-1">:</div>
<span>React project</span>
</div>
<div
class="flex flex-row justify-start items-start bg-gray-700 px-5 py-2 rounded-md mt-1"
>
<div
class="font-bold max-w-[45%] overflow-hidden overflow-ellipsis text-indigo-400"
>
Seijisoldier
</div>
<div class="mr-1">:</div>
<span>Be the tallest in the room</span>
</div>
<div
class="flex flex-row justify-start items-start bg-gray-700 px-5 py-2 rounded-md mt-1"
>
<div
class="font-bold max-w-[45%] overflow-hidden overflow-ellipsis text-pink-400"
>
StudySmrt
</div>
<div class="mr-1">:</div>
<span>be the youngest in the room</span>
</div>
<div
class="flex flex-row justify-start items-start bg-gray-700 px-5 py-2 rounded-md mt-1"
>
<div
class="font-bold max-w-[45%] overflow-hidden overflow-ellipsis text-purple-400"
>
anchigaming
</div>
<div class="mr-1">:</div>
<span>love kirby</span>
</div>
<div
class="flex flex-row justify-start items-start bg-gray-700 px-5 py-2 rounded-md mt-1"
>
<div
class="font-bold max-w-[45%] overflow-hidden overflow-ellipsis text-green-500"
>
brisim_claimhte
</div>
<div class="mr-1">:</div>
<span>love kiki</span>
</div>
<div
class="flex flex-row justify-start items-start bg-gray-700 px-5 py-2 rounded-md mt-1"
>
<div
class="font-bold max-w-[45%] overflow-hidden overflow-ellipsis text-pink-400"
>
Chieysse
</div>
<div class="mr-1">:</div>
<span>play Valorant</span>
</div>
<div
class="flex flex-row justify-start items-start bg-gray-700 px-5 py-2 rounded-md mt-1"
>
<div
class="font-bold max-w-[45%] overflow-hidden overflow-ellipsis text-yellow-400"
>
lyricalclove
</div>
<div class="mr-1">:</div>
<span>commit arson with Calcifer</span>
</div>
<div
class="flex flex-row justify-start items-start bg-gray-700 px-5 py-2 rounded-md mt-1"
>
<div
class="font-bold max-w-[45%] overflow-hidden overflow-ellipsis text-pink-200"
>
hillabunny
</div>
<div class="mr-1">:</div>
<span>play Valorant</span>
</div>
<div
class="flex flex-row justify-start items-start bg-gray-700 px-5 py-2 rounded-md mt-1"
>
<div
class="font-bold max-w-[45%] overflow-hidden overflow-ellipsis text-gray-200"
>
StudyStreamKen
</div>
<div class="mr-1">:</div>
<span>be drunk</span>
</div>
<div
class="flex flex-row justify-start items-start bg-gray-700 px-5 py-2 rounded-md mt-1"
>
<div
class="font-bold max-w-[75%] overflow-hidden overflow-ellipsis text-orange-400"
>
Supernaturalwriter
</div>
<div class="mr-1">:</div>
<span>be the fittest in the DnD group</span>
</div>
<div
class="flex flex-row justify-start items-start bg-gray-700 px-5 py-2 rounded-md mt-1"
>
<div
class="font-bold max-w-[45%] overflow-hidden overflow-ellipsis text-purple-500"
>
KhrowV
</div>
<div class="mr-1">:</div>
<span>caw caw</span>
</div>
<div
class="flex flex-row justify-start items-start bg-gray-700 px-5 py-2 rounded-md mt-1"
>
<div
class="font-bold max-w-[45%] overflow-hidden overflow-ellipsis text-indigo-400"
>
michiimiya
</div>
<div class="mr-1">:</div>
<span>be a cult leader</span>
</div>
<div
class="flex flex-row justify-start items-start bg-gray-700 px-5 py-2 rounded-md mt-1"
>
<div
class="font-bold max-w-[45%] overflow-hidden overflow-ellipsis text-pink-400"
>
Chiichyan
</div>
<div class="mr-1">:</div>
<span>practice piano</span>
</div>
<div
class="flex flex-row justify-start items-start bg-gray-700 px-5 py-2 rounded-md mt-1"
>
<div
class="font-bold max-w-[45%] overflow-hidden overflow-ellipsis text-pink-400"
>
mindiigo
</div>
<div class="mr-1">:</div>
<span>hit Ascendant in Valorant</span>
</div>
<div
class="flex flex-row justify-start items-start bg-gray-700 px-5 py-2 rounded-md mt-1"
>
<div
class="font-bold max-w-[45%] overflow-hidden overflow-ellipsis text-pink-400"
>
RosieDream_
</div>
<div class="mr-1">:</div>
<span>be a lawyer</span>
</div>
<div
class="flex flex-row justify-start items-start bg-gray-700 px-5 py-2 rounded-md mt-1"
>
<div
class="font-bold max-w-[45%] overflow-hidden overflow-ellipsis text-blue-400"
>
MemouriArt
</div>
<div class="mr-1">:</div>
<span>design T-shirts</span>
</div>
<div
class="flex flex-row justify-start items-start bg-gray-700 px-5 py-2 rounded-md mt-1"
>
<div
class="font-bold max-w-[75%] overflow-hidden overflow-ellipsis text-purple-400"
>
study_with_flowergirl
</div>
<div class="mr-1">:</div>
<span>be a flower</span>
</div>
<div
class="flex flex-row justify-start items-start bg-gray-700 px-5 py-2 rounded-md mt-1"
>
<div
class="font-bold max-w-[45%] overflow-hidden overflow-ellipsis text-blue-400"
>
sunnyblue_
</div>
<div class="mr-1">:</div>
<span>mod for Ranboo</span>
</div>
<div
class="flex flex-row justify-start items-start bg-gray-700 px-5 py-2 rounded-md mt-1"
>
<div
class="font-bold max-w-[45%] overflow-hidden overflow-ellipsis text-orange-500"
>
SquaredMo
</div>
<div class="mr-1">:</div>
<span>play Valorant deathmatch</span>
</div>
<div
class="flex flex-row justify-start items-start bg-gray-700 px-5 py-2 rounded-md mt-1"
>
<div
class="font-bold max-w-[45%] overflow-hidden overflow-ellipsis text-gray-200"
>
triplefattypatty
</div>
<div class="mr-1">:</div>
<span>travel around the world</span>
</div>
<div
class="flex flex-row justify-start items-start bg-gray-700 px-5 py-2 rounded-md mt-1"
>
<div
class="font-bold max-w-[45%] overflow-hidden overflow-ellipsis text-orange-600"
>
JettesHus
</div>
<div class="mr-1">:</div>
<span>Furniture restoration</span>
</div>
<div
class="flex flex-row justify-start items-start bg-gray-700 px-5 py-2 rounded-md mt-1"
>
<div
class="font-bold max-w-[55%] overflow-hidden overflow-ellipsis text-blue-400"
>
Bli_FlowState
</div>
<div class="mr-1">:</div>
<span>Make productivity youtube videos</span>
</div>
<div
class="flex flex-row justify-start items-start bg-gray-700 px-5 py-2 rounded-md mt-1"
>
<div
class="font-bold max-w-[45%] overflow-hidden overflow-ellipsis text-purple-400"
>
wafflesdot025
</div>
<div class="mr-1">:</div>
<span>skip class</span>
</div>
</div>
</div>
</a>
<div class="relative overflow-hidden h-fit min-h-screen">
<BlurBackground />
<div class="flex justify-center items-start pb-10">
<Hero />
</div>
</div>
</Layout>
<style>
.task-list {
font-family: "Poppins", sans-serif;
height: 500px;
}
.task-list-header {
font-family: "Fredoka", sans-serif;
}
/* scroll up and down automatically keyframes*/
@keyframes scroll {
0% {
transform: translateY(0);
}
10% {
transform: translateY(0);
}
90% {
transform: translateY(calc(-100% + 435px));
}
100% {
transform: translateY(calc(-100% + 435px));
}
}
.task-list-header {
height: 80px;
}
.task-list-body {
animation: scroll 30s linear alternate infinite;
}
#widget-title {
transition: all 1s ease-in-out;
}
.fade {
animation: fade 1s ease-in-out;
}
@keyframes fade {
0% {
opacity: 0;
}
100% {
opacity: 1;
}
}
</style>
<script defer is:inline>
const taskListTitles = ["Click here!", "!taskhelp"];
const widgetTitle = document.querySelector("#widget-title");
let index = 0;
setInterval(() => {
widgetTitle.classList.add("fade");
setTimeout(() => {
widgetTitle.classList.remove("fade");
}, 1000);
widgetTitle.textContent = taskListTitles[index];
index++;
if (index === taskListTitles.length) {
index = 0;
}
}, 5000);
</script>

View file

@ -1,97 +0,0 @@
---
title: Specifications
layout: "../layouts/Markdown.astro"
description: Find out the minimum computer specification requirements for coworking streams!
---
<!--
https://help.twitch.tv/s/article/broadcasting-guidelines?language=en_US
https://third-stinger-20a.notion.site/A-Coworking-Streamer-Cheat-Sheet-01ee1e5ff006410d84c339069ea6546c
-->
# Specifications
In this section, we will discuss the minimum computer specification requirements for coworking streams. The minimum specifications should be suffice for a comfortable streaming and viewing experience.
Note: Some smaller study streamers use their smartphones to stream. This is a great option for those who are just starting out, but it is not recommended for long-term streaming, due to limited settings and limited interactivity with viewers.
<details>
<summary>CPU</summary>
The CPU (Central Processing Unit) is the brain of the computer. The better the CPU, the faster the computer can process data and instructions.
**The ideal CPU for streaming**: A quad-core processor, preferably with a clock speed of 3.0 GHz or higher, such as an Intel Core i5 or AMD Ryzen 5.
</details>
<details>
<summary>GPU (optional)</summary>
The GPU (Graphics Processing Unit) is the component that renders images on the screen. The better the GPU, the better the image quality and the higher the frame rate. A dedicated GPU is not required for streaming, but it is recommended for a better viewing experience.
**The ideal GPU for streaming**: A dedicated graphics card with at least 4GB of VRAM, such as an NVIDIA GeForce GTX 1050 or AMD Radeon RX 560.
</details>
<details>
<summary>RAM</summary>
RAM (Random Access Memory) is the component that stores data and instructions for the CPU to process. The more RAM a computer has, the better it is at multitasking.
**The ideal RAM for streaming**: At least 8GB of RAM, preferably 16GB or more.
</details>
<details>
<summary>Storage</summary>
Storage is the component that stores data and instructions for the CPU to process. The more storage a computer has, the more data and instructions it can store at once.
**The ideal storage for streaming**: At least 256GB of SSD storage, preferably 512GB or more.
</details>
<details>
<summary>Internet speed</summary>
The better the internet connection, the better the streaming experience. You can check your internet speed at <a href="https://www.speedtest.net" target="_blank" class="underline hover:text-blue-400">speedtest.net</a>.
**The ideal internet for streaming**: At least 5 Mbps upload speed, preferably 10 Mbps or more.
</details>
<details>
<summary>Peripherals</summary>
Peripherals are the components that connect to the computer to provide additional functionality.
**The ideal peripherals for streaming**: A webcam, a microphone, and a headset.
Note: A smartphone can be used as a webcam, however it is recommended to keep it charging while you stream.
</details>
<details>
<summary>Bitrate</summary>
There are some online calculators you can use to determine the ideal bitrate based off your computer specs and preferred output (screen resolution, frames per second)
Check out this <a href="https://www.reddit.com/r/Twitch/comments/2dz7ru/bitrates_resolutions_and_quality/" target="_blank" class="underline hover:text-blue-400">in depth guide from Reddit</a> to learn more!
</details>
<details>
<summary>Streaming software</summary>
There are many streaming software options available, but the most popular one is <a href="https://obsproject.com/" target="_blank" class="underline hover:text-blue-400">OBS Studio</a>!
Check out this <a href="https://youtu.be/9idPREZzWpE" target="_blank" class="underline hover:text-blue-400">YouTube video made by Hammer Dance</a> on how to setup OBS!
If you're using macOS and you're struggling with Desktop Audio issues, check out this <a href="https://www.youtube.com/watch?v=H4VPbMvBuLg" target="_blank" class="underline hover:text-blue-400">video</a> on how to setup BlackHole Audio!
If you're streaming on mobile, the Twitch mobile app has a built-in streaming feature!
</details>

View file

@ -1,164 +0,0 @@
---
title: Tips
layout: "../layouts/Markdown.astro"
description: Tips for coworking streamers
---
# Tips
Here are some tips for coworking streamers!
## Table of Contents
- [Tips](#tips)
- [Table of Contents](#table-of-contents)
- [How to get noticed as a new streamer?](#how-to-get-noticed-as-a-new-streamer)
- [Have a consistent stream schedule](#have-a-consistent-stream-schedule)
- [Use stream tags to its full potential](#use-stream-tags-to-its-full-potential)
- [Social Media Marketing](#social-media-marketing)
- [Use stream layouts that make your stream stand out](#use-stream-layouts-that-make-your-stream-stand-out)
- [Disable pre-roll advertisements](#disable-pre-roll-advertisements)
- [Interact with chat](#interact-with-chat)
- [Networking](#networking)
- [Other notes](#other-notes)
- [To mute or not to mute?](#to-mute-or-not-to-mute)
- [Should I leave chat opened while working?](#should-i-leave-chat-opened-while-working)
- [Fixed schedule](#fixed-schedule)
- [Social media](#social-media)
- [Chat commands for coworking streams](#chat-commands-for-coworking-streams)
- [How to listen to music without getting VOD muted?](#how-to-listen-to-music-without-getting-vod-muted)
- [Emotes](#emotes)
- [Channel emotes](#channel-emotes)
- [Emote extensions](#emote-extensions)
- [Browser Extensions](#browser-extensions)
- [Other tips](#other-tips)
- [References](#references)
---
## How to get noticed as a new streamer?
### Have a consistent stream schedule
A regular stream schedule lets your viewers know exactly when to expect you to go live. When viewers can anticipate your streams, they are more likely to make time to watch, increasing the chances of them tuning in and engaging with your content.
Regularly scheduled streams also help you attract and retain viewers. When new viewers find your stream, they are more likely to follow if they see a consistent schedule. Additionally, existing followers are more likely to continue watching if they know when to catch your streams.
### Use stream tags to its full potential
The most common way to get noticed is if you set a "coworking" tag into your stream tags. Other variations include "study" and "studywithme". The community has been struggling to discover new streamers through this method due to the variety of "coworking" tags, hence it has been suggested to Twitch that the <a href="https://twitch.uservoice.com/forums/310210-discover/suggestions/46004791-coworking" target="_blank" class="underline font-bold hover:text-blue-400">Coworking and Study category</a> should be built into Twitch's list of categories. Please leave a vote to support this suggestion!
### Social Media Marketing
Having good social media marketing allows you to reach a broader audience beyond your live streams. Utilizing platforms like Instagram and YouTube (even YouTube Shorts!) enables you to promote your content, engage with potential viewers and build a loyal following, increasing visibility and attracting new members to your community.
### Use stream layouts that make your stream stand out
On Twitch, people would go through the browse section with a frame of your stream as the thumbnail. If you want to increase the chances of people clicking onto your stream, you should make your stream aesthetic.
### Disable pre-roll advertisements
It's annoying that when you want to check out a streamer you never watched before and you're greeted with an advertisement lasting 30 seconds long.
After being a Twitch affiliate, your streams will have advertisements. If you disable mid-roll ads, pre-roll ads will be given to your viewers when they hop on your stream at all times.
However if you have mid-roll ads enabled, your viewers may only get pre-roll ads near when the mid-roll ads are about to happen.
It is recommended to add Ads Manager to your OBS deck:
`https://dashboard.twitch.tv/popout/u/{{channel}}/stream-manager/streamer-ads-manager-panel`
With the OBS deck, you can manually control when the advertisements start and be notified when the stream advertisement is in progress.
### Interact with chat
Interacting with your chat is crucial to grow your community because it fosters a sense of engagement and connection with your audience. By acknowledging and responding to viewers, you create a welcoming and inclusive atmosphere, encouraging viewers to stay, become regulars, and invite others, ultimately leading to organic community growth.
### Networking
Having good networking opens up collaboration opportunities, cross-promotion, and exposure to each other's audiences. By forming connections within the streaming community, you can tap into a larger pool of viewers, gain credibility, and foster a supportive environment that encourages mutual growth and success.
### Other notes
Even if you follow these tips, it is not a 100% guarantee that you will become a successful streamer.
There are other factors that you have little to no control over, such as luck and entertaining personality.
---
## To mute or not to mute?
Most streamers mute themselves during the work sessions because it makes it easier for the viewers to focus. However it's also possible to leave the mic on for keyboard asmr and general "office noise" which many people enjoy - ask your community what they prefer!
---
## Should I leave chat opened while working?
Many new coworking streamers often worry about neglecting chat. It's a tough balancing act! On one hand, you want to engage with your community. But on the other hand, you need to focus on your work. After all, that's the whole point of streaming while coworking! So, try not to feel guilty about not always responding to new people immediately. It's actually quite helpful to have mods who can handle the chat interactions for you. And hey, don't forget that you can always have a nice chat with them during your break time!
Having commands such as "!muted" or "!speak" can come in handy. It lets newcomers know that you're currently focused and will catch up with them later. Trust me, as time goes by, you'll attract viewers who are also there to work, so the pressure to chat constantly during work hours will naturally ease up. So hang in there!
---
## Fixed schedule
It is often recommended that streamers in general stick to a regular schedule because it allows your community to know when to join your channel. While it's definitely beneficial, it's not a requirement and it's totally fine to be flexible with your streams. If you do have irregular stream times, you might want to think about posting on social media to let your followers know you're live.
---
## Social media
Speaking of social media, it's a great way to let your followers know when you're live! You can also use it to post about your upcoming streams, share your work, and interact with your community. It's a good idea to have a Discord server for your community as well. It's a great way to keep in touch with your viewers and get to know them better!
---
## Chat commands for coworking streams
Chat commands are very useful since you won't be chatting much during the work timer. Some common chat commands you may see include ones that introduce your stream, provide a brief introduction to the pomodoro method (if you use it), or a muted command that may explain why you may be muted (e.g: !welcome !timer !pomo !muted). You may also like to add a command to tell your viewers what you're working on that day (!today !work !study) - this adds a nice personal touch and you can use it to encourage other's to talk about what they're working on too.
---
## How to listen to music without getting VOD muted?
If you're streaming on Twitch using OBS, you can easily avoid getting your VODs muted by separating audio tracks into VOD audio tracks and stream audio tracks. This way, you can listen to music on your stream without worrying about getting muted. Here's a <a href="https://youtu.be/0Lj5rkqSp48/" target="_blank" class="underline hover:text-blue-400">video</a> that explains how to do it! (NO VOICEMEETER REQUIRED)
---
## Emotes
### Channel emotes
When you reach the Twitch Affiliate goal, you can add emotes to your channel for subscribers to use! However, Follower emotes are only available if you have <a href="https://help.twitch.tv/s/article/emote-guidelines?language=en_US#instantupload" target="_blank" class="underline hover:text-blue-400">Instant Upload Privilege</a>!
### Emote extensions
Don't understand when your chat says in 'KEKW'? It's a common third party Twitch emote! You can add extensions to your channel to add more emotes for your viewers to use. Some popular ones include BetterTTV, FrankerFaceZ and 7TV.
### Browser Extensions
<ul>
<li><a href="https://betterttv.com/" target="_blank" class="underline hover:text-blue-400">Download BetterTTV</a></li>
<li><a href="https://www.frankerfacez.com/" target="_blank" class="underline hover:text-blue-400">Download FrankerFaceZ</a></li>
<li><a href="https://7tv.app/" target="_blank" class="underline hover:text-blue-400">Download 7TV</a></li>
</ul>
You won't run into any issues using all three extensions at once!
Only want to use one extension? <a href="https://www.frankerfacez.com/" target="_blank" class="underline hover:text-blue-400">FrankerFaceZ</a> is probably the best one to go for! It is stable, has special addons through the extension itself for BTTV and 7TV emotes, and has the best customization for twitch as a site!
---
## Other tips
- Don't promote yourself in other people's channels without permission. It's rude and will likely get you banned.
- Don't worry about view count, just focus on your work and the rest will follow.
- Avoid spending money on your stream setup until you're sure you want to stick with it.
- Avoid using Display/Screen Capture where you may accidentally leak personal information. It is recommended to keep the Display Capture window small enough or to blur it, so that the text content is not readable.
- Consider using Application Capture Audio instead of Desktop Audio. This will prevent your viewers from hearing your notifications or other unwanted noise.
- For macOS users, if you are struggling with Desktop Audio issues on OBS, consider watching this <a href="https://www.youtube.com/watch?v=H4VPbMvBuLg" target="_blank" class="underline hover:text-blue-400">video</a> on how to setup BlackHole Audio!
---
## References
Please take a look at <a href="https://third-stinger-20a.notion.site/A-Coworking-Streamer-Cheat-Sheet-01ee1e5ff006410d84c339069ea6546c" target="_blank" class="underline underline-offset-2 hover:text-blue-400">A Coworking Streamer Cheat Sheet</a> for more information!

View file

@ -1,145 +0,0 @@
---
title: Widgets
layout: "../layouts/Markdown.astro"
description: Find out the widgets you can use to enhance your stream!
---
# Widgets
These widgets can be useful for coworking streamers to increase engagement for their viewers!
---
## Pomodoro timer
A pomodoro timer is a great way to keep track of your work sessions. It's also a great way to let your viewers know when you're taking a break. You can use a pomodoro timer widget to display the current work session and break time.
### Browser Source
<ul>
<li>
<a href="https://github.com/mohamed-tayeh/Minimal-Pomo-Timer" target="_blank" class="hyperlink">https://github.com/mohamed-tayeh/Minimal-Pomo-Timer</a> *
</li>
<li>
<a href="https://github.com/njallam/stream-pomodoro" target="_blank" class="hyperlink">https://github.com/njallam/stream-pomodoro</a>
</li>
<li>
<a href="https://ecard.enter-media.org/widgets/" target="_blank" class="hyperlink">https://ecard.enter-media.org/widgets/</a>
</li>
<li>
<a href="https://github.com/hellomayuko/Pomodoro-Countdown" target="_blank" class="hyperlink">https://github.com/hellomayuko/Pomodoro-Countdown</a>
</li>
<li>
<a href="https://pixelchat.tv/" target="_blank" class="hyperlink">https://pixelchat.tv/</a> *
</li>
<li>
<a href="https://github.com/liyunze-coding/streamodoro" target="_blank" class="hyperlink">https://github.com/liyunze-coding/streamodoro</a> *
</li>
</ul>
\* can be called through commands in chat
### Window Capture
You can also add timers by using 3rd part websites and then using _window capture_ on your streaming programme!
<ul>
<li>
<a href="https://pomofocus.io/" target="_blank" class="hyperlink">https://pomofocus.io/</a>
</li>
<li>
<a href="https://www.timeanddate.com/timer/" target="_blank" class="hyperlink">https://www.timeanddate.com/timer/</a>
</li>
<li>
<a href="https://pomodor.app/timer" target="_blank" class="hyperlink">https://pomodor.app/timer</a>
</li>
<li>
<a href="https://tomato-timer.com/" target="_blank" class="hyperlink">https://tomato-timer.com/</a>
</li>
<li>
<a href="https://pomodoro-tracker.com/" target="_blank" class="hyperlink">https://pomodoro-tracker.com/</a>
</li>
</ul>
Do check beforehand the volumes for the alarms, as sometimes they may be startling or distracting for viewers if not expected!
---
## Task list widget
<div class="flex flex-col sm:flex-row mb-5">
<img src="/assets/moh-task-list.webp" class="rounded-md mr-5 w-56 h-56 mb-5 sm:mb-0">
<img src="/assets/ryanpython-task-list.webp" class="rounded-md w-60 h-56">
</div>
A task list widget is a great way to keep track of your tasks along with your viewers! For these widgets, you may only add 1 incomplete task at a time. You may only add another task once the previous task is completed.
### Browser Source
<ul>
<li>
<a href="https://youtu.be/-5EdJcvDuFQ" target="_blank" class="hyperlink">
https://youtu.be/-5EdJcvDuFQ
</a>
</li>
<li>
<a href="https://github.com/liyunze-coding/chat-task-tic-overlay-infinity" target="_blank" class="hyperlink">
https://github.com/liyunze-coding/Chat-Task-Tic-Overlay-Infinity
</a>
</li>
<li>
<a href="https://github.com/liyunze-coding/Chat-Task-Tic-Overlay-Horizontal" target="_blank" class="hyperlink">
https://github.com/liyunze-coding/Chat-Task-Tic-Overlay-Horizontal
</a>
</li>
<li>
<a href="https://github.com/mohamed-tayeh/Task-List" target="_blank" class="hyperlink">
https://github.com/mohamed-tayeh/Task-List
</a>
</li>
</ul>
<img src="/assets/multi-task.webp" class="rounded-md mb-5 mt-10 w-68 h-56">
If you're interested in a task list widget that allows you to add multiple tasks at a time, check out <a href="https://www.twitch.tv/RythonDev" target="_blank" class="underline hover:text-blue-400">RythonDev's stream</a> and learn more about the multi-task widget <a href="https://github.com/liyunze-coding/Chat-Task-Tic-Overlay/blob/main/MultiTask.md" target="_blank" class="underline hover:text-blue-400">here</a>! Note: This widget is behind a paywall.
---
## Spotify widget
A Spotify widget is a great way to let your viewers know what you're listening to!
### Browser Source:
<a href="https://6klabs.com/" target="_blank" class="font-bold underline hover:text-blue-400">6K Labs</a>: A widget that shows what you're playing via Spotify or YouTube music. Many customization options provided for free.
<a href="https://6klabs.com/" target="_blank" class="block w-fit"><img src="/assets/6kLabs.webp" width="300" class="mb-10"></a>
<a href="https://pixelchat.tv/" target="_blank" class="font-bold underline hover:text-blue-400">Pixel Chat</a>: An easy-to-implement widget that shows what you're playing via Spotify, Apple Music, etc. Bonus: includes other widgets like one for shout outs, captions, and counters.
<a href="https://pixelchat.tv/" target="_blank" class="block w-fit"><img src="/assets/pixelchat.webp" width="500" class="mb-10"></a>
<a href="https://spotify.aidenwallis.co.uk/" target="_blank" class="font-bold underline hover:text-blue-400">Aiden Wallis</a>: A widget that shows what you're playing via Spotify. Bonus: you can add a command like !song to your bot (Nightbot) that outputs the current song.
<a href="https://pixelchat.tv/" target="_blank" class="block w-fit"><img src="/assets/aidenwallis.webp" width="500" class="mb-10"></a>
### Software:
<a href="https://github.com/dlrudie/Snip/releases" target="_blank" class="font-bold underline hover:text-blue-400">Snip</a>: Captures music from iTunes or Spotify and saves the current song as a text and png file that you can add into your streaming software.
<a href="https://github.com/dlrudie/Snip/releases" target="_blank" class="block w-fit"><img src="/assets/snip.webp" width="500" class="mb-10"></a>
---
## Other
You can use Twitch Alerts that can be found in your <a href="https://dashboard.twitch.tv/" target="_blank" class="underline hover:text-blue-400">Twitch Dashboard</a>!
Want to make your own widget? Check out <a href="https://github.com/instafluff/comfyjs" target="_blank" class="underline">Comfy.JS</a> made by Instafluff!
P.S. It requires some knowledge of Javascript, HTML and CSS
---
Once again, thanks to the creators of the <a href="https://third-stinger-20a.notion.site/A-Coworking-Streamer-Cheat-Sheet-01ee1e5ff006410d84c339069ea6546c" target="_blank" class="underline underline-offset-2 hover:text-blue-400">Coworking Streamer Cheat Sheet</a> for the reference!

View file

@ -1,41 +1,65 @@
/** @type {import('tailwindcss').Config} */
module.exports = {
content: ["./src/**/*.{astro,html,js,jsx,md,mdx,svelte,ts,tsx,vue}"],
theme: {
extend: {},
},
plugins: [
function ({ addComponents, theme }) {
addComponents({
h1: {
fontSize: theme("fontSize.3xl"),
fontWeight: theme("fontWeight.bold"),
marginBottom: theme("margin.2"),
},
h2: {
fontSize: theme("fontSize.2xl"),
fontWeight: theme("fontWeight.bold"),
marginBottom: theme("margin.1"),
},
h3: {
fontSize: theme("fontSize.xl"),
fontWeight: theme("fontWeight.bold"),
marginBottom: theme("margin.1"),
},
ul: {
listStyleType: "disc",
listStylePosition: "inside",
marginBottom: theme("margin.2"),
},
p: {
marginBottom: theme("margin.6"),
lineHeight: theme("lineHeight.7"),
},
hr: {
marginTop: theme("margin.6"),
marginBottom: theme("margin.6"),
},
});
},
],
content: ["./src/**/*.{astro,html,js,jsx,md,mdx,svelte,ts,tsx,vue}"],
theme: {
extend: {
backgroundImage: (theme) => ({
"hero-gradient":
"linear-gradient(to right, #3F84D8, aquamarine, #C65BCF)",
}),
keyframes: {
rotate: {
"0%": { transform: "rotate(0deg)" },
"50%": { scale: "1 1.5" },
"100%": { transform: "rotate(360deg)" },
},
gradient: {
"0%": {
"background-position": "0% 50%",
},
"50%": {
"background-position": "100% 50%",
},
"100%": {
"background-position": "0% 50%",
},
},
fadeIn: {
from: {
opacity: "0",
},
to: {
opacity: "1",
},
},
scaleIn: {
from: {
transform: "scale(0)",
},
to: {
transform: "scale(1)",
},
},
},
animation: {
"spin-slow": "rotate 15s linear infinite",
gradient: "gradient 15s ease infinite",
fadeIn: "fadeIn 0.3s ease-in-out forwards",
scaleIn: "scaleIn 0.3s ease-in-out forwards",
},
colors: {
"cowo-pink": "#FF7782",
secondary: "#171717",
primary: "#fafafa",
"primary-green": "#88D47D",
"primary-blue": "#3F84D8",
},
},
},
variants: {
extend: {
backgroundImage: ["responsive", "hover", "focus", "active"],
},
},
plugins: [],
};

View file

@ -1,3 +1,13 @@
{
"extends": "astro/tsconfigs/strict"
"extends": "astro/tsconfigs/strict",
"compilerOptions": {
"jsx": "react-jsx",
"jsxImportSource": "react",
"baseUrl": ".",
"paths": {
"@/*": [
"./src/*"
]
}
}
}

7
utils/cn.ts Normal file
View 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));
}