Compare commits
76 Commits
highlight
...
simplified
| Author | SHA1 | Date | |
|---|---|---|---|
| 8eb8c2c5e8 | |||
| ff3e5987a5 | |||
| f89122b65c | |||
| 7782fc9118 | |||
| b3d26f3a58 | |||
| ac2018468c | |||
| 760dfa6afc | |||
| 4a1c7cfbfb | |||
| ec11f7bb54 | |||
| e81b3af413 | |||
| c20b6aade0 | |||
| 2f43a5ca6b | |||
| 64d332a89b | |||
| 4ae505665f | |||
| 78cf96919d | |||
| 14041875a3 | |||
| 715aaed730 | |||
| f763b1ae70 | |||
| 3f02ccd080 | |||
| 22550a7afa | |||
| c50000feae | |||
| 8c8e048466 | |||
| 69b6133fb0 | |||
| 763786f5bf | |||
| 5193c400b4 | |||
| 6079272b8c | |||
| 2df8d27809 | |||
| 4e0436f3f2 | |||
| c22727adc7 | |||
| 1af1c17d2c | |||
| f51b65e13c | |||
| 64f03449b7 | |||
| 097496ff94 | |||
| dd13c8cfcc | |||
| f82c72ec24 | |||
| 340239f990 | |||
| 01fd965261 | |||
| cf2073ee70 | |||
| 1f10a73ecf | |||
| 7333cc31c8 | |||
| e7f08b8ff7 | |||
| 4be4395300 | |||
| baa5edf104 | |||
| 522728c0e4 | |||
| d04dfb16f5 | |||
| d235a73867 | |||
| adb852907a | |||
| ca9f5fecba | |||
| 2559410fb3 | |||
| a4d6196259 | |||
| 3bb5b66b2f | |||
| a6541cb62c | |||
| efac99eb98 | |||
| ba1256bdfe | |||
| ec6c20848f | |||
| 7d22c335fd | |||
| 92af7f9213 | |||
| 88f6919e73 | |||
| 65556ad238 | |||
| 2c1ce61529 | |||
| fb6b3465be | |||
| 4c78c777c6 | |||
| 66900162c5 | |||
| 45fce5fe76 | |||
| ff14276559 | |||
| 75baf0fdfd | |||
| 05fc21daa2 | |||
| ed1c796f49 | |||
| 449f1abd4d | |||
| e197ed4e28 | |||
| 4ec3c3eafa | |||
| 895501032e | |||
| e52390db7c | |||
| be5bb755c0 | |||
| 04d3b17d75 | |||
| 8b535c9bae |
3
.dockerignore
Normal file
@ -0,0 +1,3 @@
|
||||
.DS_Store
|
||||
node_modules
|
||||
dist
|
||||
24
.drone.yml
Normal file
@ -0,0 +1,24 @@
|
||||
---
|
||||
kind: pipeline
|
||||
name: default
|
||||
|
||||
steps:
|
||||
- name: build and publish docker image
|
||||
image: plugins/docker
|
||||
settings:
|
||||
repo: git.coopcloud.tech/rtm/rtmwebsite
|
||||
tags:
|
||||
- main
|
||||
- latest
|
||||
- 0.0.8
|
||||
platform: linux/amd64
|
||||
username:
|
||||
from_secret: USERNAME
|
||||
password:
|
||||
from_secret: PASSWORD
|
||||
registry: git.coopcloud.tech
|
||||
trigger:
|
||||
branch:
|
||||
- main
|
||||
event:
|
||||
- push
|
||||
6
.gitignore
vendored
@ -22,3 +22,9 @@ pnpm-debug.log*
|
||||
|
||||
# jetbrains setting folder
|
||||
.idea/
|
||||
|
||||
# Emacs
|
||||
*~
|
||||
|
||||
# Drone
|
||||
.drone.secrets
|
||||
11
Dockerfile
Normal file
@ -0,0 +1,11 @@
|
||||
FROM node:lts AS build
|
||||
WORKDIR /app
|
||||
COPY package*.json ./
|
||||
RUN npm install
|
||||
COPY . .
|
||||
RUN npm run build
|
||||
|
||||
FROM nginx:alpine AS runtime
|
||||
COPY ./nginx/nginx.conf /etc/nginx/nginx.conf
|
||||
COPY --from=build /app/dist /usr/share/nginx/html
|
||||
EXPOSE 8080
|
||||
43
README.md
@ -1,3 +1,5 @@
|
||||
[](https://build.coopcloud.tech/RTM/rtm-website)
|
||||
|
||||
# hello friends !
|
||||
|
||||
|
||||
@ -40,4 +42,43 @@ npx astro dev
|
||||
- [Astro](https://astro.build/) - The core framework
|
||||
- [React](https://reactjs.org/) - For interactive components
|
||||
- [Tailwind CSS](https://tailwindcss.com/) - For styling (find docs [here](https://tailwindcss.com/docs/installation/using-vite))
|
||||
- [TypeScript](https://www.typescriptlang.org/) - For type safety
|
||||
- [TypeScript](https://www.typescriptlang.org/) - For type safety
|
||||
|
||||
# To release a new version
|
||||
|
||||
## Build in the docker image (make sure you have Docker installed!)
|
||||
|
||||
Set the version to the next [semantic version](https://semver.org/) after the version posted at [our co-op cloud's packages site](https://git.coopcloud.tech/RTM/-/packages) under "rtmwebsite":
|
||||
|
||||
``` bash
|
||||
version=<specify-version>
|
||||
docker build --platform linux/amd64 -t git.coopcloud.tech/rtm/rtmwebsite:$version .
|
||||
```
|
||||
|
||||
## Push the image to gitea registry
|
||||
|
||||
Check out [this documentation](https://docs.gitea.com/next/usage/packages/container) for how to login with gitea registery.
|
||||
|
||||
``` bash
|
||||
# If not in the same terminal session, rerun `version=...` line from last step
|
||||
docker push git.coopcloud.tech/rtm/rtmwebsite:$version
|
||||
```
|
||||
|
||||
At [our co-op cloud's packages site](https://git.coopcloud.tech/RTM/-/packages), click on "rtmwebsite" and check that the version mentioned is the version you specified!
|
||||
|
||||
## Deploy changes to resisttechmonopolies.online
|
||||
|
||||
We use coop cloud tooling [private recipe](https://git.coopcloud.tech/RTM/rtm-astro-recipe) to deploy this website to our [fleet](https://git.coopcloud.tech/RTM/rtm-config) of lil cat-named machines.
|
||||
|
||||
Read the "Fleet Setup and access" collectives page on our RTM nextcloud to get the `rtm-config` repo set up with the `rtm-astro-recipe` submodule and install the `abra` command line tool!
|
||||
|
||||
Then, in your `rtm-config` repo update the RTM website image version to the one you just built and published by running:
|
||||
|
||||
``` bash
|
||||
$ abra app config resisttechmonopolies.online # Change VERSION to the docker image you just pushed
|
||||
$ abra app deploy -f resisttechmonopolies.online # Re-deploy the RTM website, now with your changes!
|
||||
$ git add abra/servers/laylotta.resisttechmonopolies.online/resisttechmonopolies.online
|
||||
$ git commit -m 'Updated website to x.x.x' # Publish this change to the rtm-config repo either via direct commit or a PR
|
||||
```
|
||||
|
||||
Done! Thank you for your contributions 🏋️⚡📖!
|
||||
BIN
computer.png
|
Before Width: | Height: | Size: 12 KiB |
31
nginx/nginx.conf
Normal file
@ -0,0 +1,31 @@
|
||||
worker_processes 1;
|
||||
|
||||
events {
|
||||
worker_connections 1024;
|
||||
}
|
||||
|
||||
http {
|
||||
server {
|
||||
listen 8080;
|
||||
server_name _;
|
||||
|
||||
root /usr/share/nginx/html;
|
||||
index index.html index.htm;
|
||||
include /etc/nginx/mime.types;
|
||||
|
||||
gzip on;
|
||||
gzip_min_length 1000;
|
||||
gzip_proxied expired no-cache no-store private auth;
|
||||
gzip_types text/plain text/css application/json application/javascript application/x-javascript text/xml application/xml application/xml+rss text/javascript;
|
||||
|
||||
error_page 404 /404.html;
|
||||
location = /404.html {
|
||||
root /usr/share/nginx/html;
|
||||
internal;
|
||||
}
|
||||
|
||||
location / {
|
||||
try_files $uri $uri/index.html =404;
|
||||
}
|
||||
}
|
||||
}
|
||||
29
package-lock.json
generated
@ -26,6 +26,7 @@
|
||||
"nanostores": "^0.11.3",
|
||||
"react": "^19.0.0",
|
||||
"react-dom": "^19.0.0",
|
||||
"react-pageflip": "^2.0.3",
|
||||
"tailwind-merge": "^2.5.5",
|
||||
"tailwindcss": "^3.4.17",
|
||||
"tailwindcss-animate": "^1.0.7",
|
||||
@ -5176,6 +5177,12 @@
|
||||
"resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz",
|
||||
"integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw=="
|
||||
},
|
||||
"node_modules/page-flip": {
|
||||
"version": "2.0.7",
|
||||
"resolved": "https://registry.npmjs.org/page-flip/-/page-flip-2.0.7.tgz",
|
||||
"integrity": "sha512-96lQFUUz7r/LZzEUZJ3yBIMEKU9+m8HMFDzTvTdD6P7Ag/wXINjp9n0W7b4wanwnDbQETo4uNUoL3zMqpFxwGA==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/parse-latin": {
|
||||
"version": "7.0.0",
|
||||
"resolved": "https://registry.npmjs.org/parse-latin/-/parse-latin-7.0.0.tgz",
|
||||
@ -5669,6 +5676,15 @@
|
||||
"react": "^19.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/react-pageflip": {
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmjs.org/react-pageflip/-/react-pageflip-2.0.3.tgz",
|
||||
"integrity": "sha512-k81mHhRvUM52y8jyzTCh5t4O0lepkLhp+XGSUzq2C3uD+iW99Cv0jfRlqFCjZbD5N3jKkIFr7/3giucoXKDP3Q==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"page-flip": "latest"
|
||||
}
|
||||
},
|
||||
"node_modules/react-refresh": {
|
||||
"version": "0.14.2",
|
||||
"resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.14.2.tgz",
|
||||
@ -10291,6 +10307,11 @@
|
||||
"resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz",
|
||||
"integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw=="
|
||||
},
|
||||
"page-flip": {
|
||||
"version": "2.0.7",
|
||||
"resolved": "https://registry.npmjs.org/page-flip/-/page-flip-2.0.7.tgz",
|
||||
"integrity": "sha512-96lQFUUz7r/LZzEUZJ3yBIMEKU9+m8HMFDzTvTdD6P7Ag/wXINjp9n0W7b4wanwnDbQETo4uNUoL3zMqpFxwGA=="
|
||||
},
|
||||
"parse-latin": {
|
||||
"version": "7.0.0",
|
||||
"resolved": "https://registry.npmjs.org/parse-latin/-/parse-latin-7.0.0.tgz",
|
||||
@ -10542,6 +10563,14 @@
|
||||
"scheduler": "^0.25.0"
|
||||
}
|
||||
},
|
||||
"react-pageflip": {
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmjs.org/react-pageflip/-/react-pageflip-2.0.3.tgz",
|
||||
"integrity": "sha512-k81mHhRvUM52y8jyzTCh5t4O0lepkLhp+XGSUzq2C3uD+iW99Cv0jfRlqFCjZbD5N3jKkIFr7/3giucoXKDP3Q==",
|
||||
"requires": {
|
||||
"page-flip": "latest"
|
||||
}
|
||||
},
|
||||
"react-refresh": {
|
||||
"version": "0.14.2",
|
||||
"resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.14.2.tgz",
|
||||
|
||||
@ -27,6 +27,7 @@
|
||||
"nanostores": "^0.11.3",
|
||||
"react": "^19.0.0",
|
||||
"react-dom": "^19.0.0",
|
||||
"react-pageflip": "^2.0.3",
|
||||
"tailwind-merge": "^2.5.5",
|
||||
"tailwindcss": "^3.4.17",
|
||||
"tailwindcss-animate": "^1.0.7",
|
||||
@ -40,4 +41,4 @@
|
||||
"prettier-plugin-organize-imports": "^4.1.0",
|
||||
"prettier-plugin-tailwindcss": "^0.6.9"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BIN
public/assets/book-club.jpg
Normal file
|
After Width: | Height: | Size: 373 KiB |
BIN
public/assets/calendar.png
Normal file
|
After Width: | Height: | Size: 28 KiB |
BIN
public/assets/computer.png
Normal file
|
After Width: | Height: | Size: 16 KiB |
|
Before Width: | Height: | Size: 45 KiB After Width: | Height: | Size: 45 KiB |
BIN
public/assets/pet-calendar-2026-cover.jpg
Normal file
|
After Width: | Height: | Size: 694 KiB |
BIN
public/assets/pihole.jpeg
Normal file
|
After Width: | Height: | Size: 146 KiB |
BIN
public/assets/zines-thumbnail.png
Normal file
|
After Width: | Height: | Size: 214 KiB |
|
After Width: | Height: | Size: 948 KiB |
|
After Width: | Height: | Size: 968 KiB |
|
After Width: | Height: | Size: 935 KiB |
|
After Width: | Height: | Size: 970 KiB |
|
After Width: | Height: | Size: 1.1 MiB |
|
After Width: | Height: | Size: 1007 KiB |
|
After Width: | Height: | Size: 961 KiB |
|
After Width: | Height: | Size: 1.1 MiB |
BIN
public/assets/zines/de-monopoly-discotech-101-japanese/cover.jpg
Normal file
|
After Width: | Height: | Size: 283 KiB |
|
After Width: | Height: | Size: 283 KiB |
|
After Width: | Height: | Size: 411 KiB |
|
After Width: | Height: | Size: 353 KiB |
|
After Width: | Height: | Size: 366 KiB |
|
After Width: | Height: | Size: 374 KiB |
|
After Width: | Height: | Size: 373 KiB |
|
After Width: | Height: | Size: 366 KiB |
|
After Width: | Height: | Size: 459 KiB |
BIN
public/assets/zines/de-monopoly-discotech-101/cover.jpg
Normal file
|
After Width: | Height: | Size: 279 KiB |
BIN
public/assets/zines/de-monopoly-discotech-101/page-1.jpg
Normal file
|
After Width: | Height: | Size: 279 KiB |
BIN
public/assets/zines/de-monopoly-discotech-101/page-2.jpg
Normal file
|
After Width: | Height: | Size: 388 KiB |
BIN
public/assets/zines/de-monopoly-discotech-101/page-3.jpg
Normal file
|
After Width: | Height: | Size: 319 KiB |
BIN
public/assets/zines/de-monopoly-discotech-101/page-4.jpg
Normal file
|
After Width: | Height: | Size: 378 KiB |
BIN
public/assets/zines/de-monopoly-discotech-101/page-5.jpg
Normal file
|
After Width: | Height: | Size: 355 KiB |
BIN
public/assets/zines/de-monopoly-discotech-101/page-6.jpg
Normal file
|
After Width: | Height: | Size: 379 KiB |
BIN
public/assets/zines/de-monopoly-discotech-101/page-7.jpg
Normal file
|
After Width: | Height: | Size: 362 KiB |
BIN
public/assets/zines/de-monopoly-discotech-101/page-8.jpg
Normal file
|
After Width: | Height: | Size: 426 KiB |
BIN
public/assets/zines/de-monopoly-discotech-101/printable.pdf
Normal file
BIN
public/assets/zines/internet-for-the-people/cover.jpg
Normal file
|
After Width: | Height: | Size: 214 KiB |
BIN
public/assets/zines/internet-for-the-people/page-1.jpg
Normal file
|
After Width: | Height: | Size: 214 KiB |
BIN
public/assets/zines/internet-for-the-people/page-2.jpg
Normal file
|
After Width: | Height: | Size: 452 KiB |
BIN
public/assets/zines/internet-for-the-people/page-3.jpg
Normal file
|
After Width: | Height: | Size: 471 KiB |
BIN
public/assets/zines/internet-for-the-people/page-4.jpg
Normal file
|
After Width: | Height: | Size: 418 KiB |
BIN
public/assets/zines/internet-for-the-people/page-5.jpg
Normal file
|
After Width: | Height: | Size: 470 KiB |
BIN
public/assets/zines/internet-for-the-people/page-6.jpg
Normal file
|
After Width: | Height: | Size: 452 KiB |
BIN
public/assets/zines/internet-for-the-people/page-7.jpg
Normal file
|
After Width: | Height: | Size: 469 KiB |
BIN
public/assets/zines/internet-for-the-people/page-8.jpg
Normal file
|
After Width: | Height: | Size: 422 KiB |
BIN
public/assets/zines/internet-for-the-people/printable.pdf
Normal file
BIN
public/assets/zines/signal-101/cover.jpg
Normal file
|
After Width: | Height: | Size: 62 KiB |
BIN
public/assets/zines/signal-101/page-1.jpg
Normal file
|
After Width: | Height: | Size: 101 KiB |
BIN
public/assets/zines/signal-101/page-2.jpg
Normal file
|
After Width: | Height: | Size: 89 KiB |
BIN
public/assets/zines/signal-101/page-3.jpg
Normal file
|
After Width: | Height: | Size: 108 KiB |
BIN
public/assets/zines/signal-101/page-4.jpg
Normal file
|
After Width: | Height: | Size: 96 KiB |
BIN
public/assets/zines/signal-101/page-5.jpg
Normal file
|
After Width: | Height: | Size: 105 KiB |
BIN
public/assets/zines/signal-101/page-6.jpg
Normal file
|
After Width: | Height: | Size: 87 KiB |
BIN
public/assets/zines/signal-101/page-7.jpg
Normal file
|
After Width: | Height: | Size: 90 KiB |
BIN
public/assets/zines/signal-101/printable.pdf
Normal file
@ -1 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" width="115" height="48"><path fill="#17191E" d="M7.77 36.35C6.4 35.11 6 32.51 6.57 30.62c.99 1.2 2.35 1.57 3.75 1.78 2.18.33 4.31.2 6.33-.78.23-.12.44-.27.7-.42.18.55.23 1.1.17 1.67a4.56 4.56 0 0 1-1.94 3.23c-.43.32-.9.61-1.34.91-1.38.94-1.76 2.03-1.24 3.62l.05.17a3.63 3.63 0 0 1-1.6-1.38 3.87 3.87 0 0 1-.63-2.1c0-.37 0-.74-.05-1.1-.13-.9-.55-1.3-1.33-1.32a1.56 1.56 0 0 0-1.63 1.26c0 .06-.03.12-.05.2Z"/><path fill="url(#a)" d="M7.77 36.35C6.4 35.11 6 32.51 6.57 30.62c.99 1.2 2.35 1.57 3.75 1.78 2.18.33 4.31.2 6.33-.78.23-.12.44-.27.7-.42.18.55.23 1.1.17 1.67a4.56 4.56 0 0 1-1.94 3.23c-.43.32-.9.61-1.34.91-1.38.94-1.76 2.03-1.24 3.62l.05.17a3.63 3.63 0 0 1-1.6-1.38 3.87 3.87 0 0 1-.63-2.1c0-.37 0-.74-.05-1.1-.13-.9-.55-1.3-1.33-1.32a1.56 1.56 0 0 0-1.63 1.26c0 .06-.03.12-.05.2Z"/><path fill="#17191E" d="M.02 30.31s4.02-1.95 8.05-1.95l3.04-9.4c.11-.45.44-.76.82-.76.37 0 .7.31.82.76l3.04 9.4c4.77 0 8.05 1.95 8.05 1.95L17 11.71c-.2-.56-.53-.91-.98-.91H7.83c-.44 0-.76.35-.97.9L.02 30.31Zm42.37-5.97c0 1.64-2.05 2.62-4.88 2.62-1.85 0-2.5-.45-2.5-1.41 0-1 .8-1.49 2.65-1.49 1.67 0 3.09.03 4.73.23v.05Zm.03-2.04a21.37 21.37 0 0 0-4.37-.36c-5.32 0-7.82 1.25-7.82 4.18 0 3.04 1.71 4.2 5.68 4.2 3.35 0 5.63-.84 6.46-2.92h.14c-.03.5-.05 1-.05 1.4 0 1.07.18 1.16 1.06 1.16h4.15a16.9 16.9 0 0 1-.36-4c0-1.67.06-2.93.06-4.62 0-3.45-2.07-5.64-8.56-5.64-2.8 0-5.9.48-8.26 1.19.22.93.54 2.83.7 4.06 2.04-.96 4.95-1.37 7.2-1.37 3.11 0 3.97.71 3.97 2.15v.57Zm11.37 3c-.56.07-1.33.07-2.12.07-.83 0-1.6-.03-2.12-.1l-.02.58c0 2.85 1.87 4.52 8.45 4.52 6.2 0 8.2-1.64 8.2-4.55 0-2.74-1.33-4.09-7.2-4.39-4.58-.2-4.99-.7-4.99-1.28 0-.66.59-1 3.65-1 3.18 0 4.03.43 4.03 1.35v.2a46.13 46.13 0 0 1 4.24.03l.02-.55c0-3.36-2.8-4.46-8.2-4.46-6.08 0-8.13 1.49-8.13 4.39 0 2.6 1.64 4.23 7.48 4.48 4.3.14 4.77.62 4.77 1.28 0 .7-.7 1.03-3.71 1.03-3.47 0-4.35-.48-4.35-1.47v-.13Zm19.82-12.05a17.5 17.5 0 0 1-6.24 3.48c.03.84.03 2.4.03 3.24l1.5.02c-.02 1.63-.04 3.6-.04 4.9 0 3.04 1.6 5.32 6.58 5.32 2.1 0 3.5-.23 5.23-.6a43.77 43.77 0 0 1-.46-4.13c-1.03.34-2.34.53-3.78.53-2 0-2.82-.55-2.82-2.13 0-1.37 0-2.65.03-3.84 2.57.02 5.13.07 6.64.11-.02-1.18.03-2.9.1-4.04-2.2.04-4.65.07-6.68.07l.07-2.93h-.16Zm13.46 6.04a767.33 767.33 0 0 1 .07-3.18H82.6c.07 1.96.07 3.98.07 6.92 0 2.95-.03 4.99-.07 6.93h5.18c-.09-1.37-.11-3.68-.11-5.65 0-3.1 1.26-4 4.12-4 1.33 0 2.28.16 3.1.46.03-1.16.26-3.43.4-4.43-.86-.25-1.81-.41-2.96-.41-2.46-.03-4.26.98-5.1 3.38l-.17-.02Zm22.55 3.65c0 2.5-1.8 3.66-4.64 3.66-2.81 0-4.61-1.1-4.61-3.66s1.82-3.52 4.61-3.52c2.82 0 4.64 1.03 4.64 3.52Zm4.71-.11c0-4.96-3.87-7.18-9.35-7.18-5.5 0-9.23 2.22-9.23 7.18 0 4.94 3.49 7.59 9.21 7.59 5.77 0 9.37-2.65 9.37-7.6Z"/><defs><linearGradient id="a" x1="6.33" x2="19.43" y1="40.8" y2="34.6" gradientUnits="userSpaceOnUse"><stop stop-color="#D83333"/><stop offset="1" stop-color="#F041FF"/></linearGradient></defs></svg>
|
||||
|
Before Width: | Height: | Size: 2.8 KiB |
@ -1 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="1440" height="1024" fill="none"><path fill="url(#a)" fill-rule="evenodd" d="M-217.58 475.75c91.82-72.02 225.52-29.38 341.2-44.74C240 415.56 372.33 315.14 466.77 384.9c102.9 76.02 44.74 246.76 90.31 366.31 29.83 78.24 90.48 136.14 129.48 210.23 57.92 109.99 169.67 208.23 155.9 331.77-13.52 121.26-103.42 264.33-224.23 281.37-141.96 20.03-232.72-220.96-374.06-196.99-151.7 25.73-172.68 330.24-325.85 315.72-128.6-12.2-110.9-230.73-128.15-358.76-12.16-90.14 65.87-176.25 44.1-264.57-26.42-107.2-167.12-163.46-176.72-273.45-10.15-116.29 33.01-248.75 124.87-320.79Z" clip-rule="evenodd" style="opacity:.154"/><path fill="url(#b)" fill-rule="evenodd" d="M1103.43 115.43c146.42-19.45 275.33-155.84 413.5-103.59 188.09 71.13 409 212.64 407.06 413.88-1.94 201.25-259.28 278.6-414.96 405.96-130 106.35-240.24 294.39-405.6 265.3-163.7-28.8-161.93-274.12-284.34-386.66-134.95-124.06-436-101.46-445.82-284.6-9.68-180.38 247.41-246.3 413.54-316.9 101.01-42.93 207.83 21.06 316.62 6.61Z" clip-rule="evenodd" style="opacity:.154"/><defs><linearGradient id="b" x1="373" x2="1995.44" y1="1100" y2="118.03" gradientUnits="userSpaceOnUse"><stop stop-color="#D83333"/><stop offset="1" stop-color="#F041FF"/></linearGradient><linearGradient id="a" x1="107.37" x2="1130.66" y1="1993.35" y2="1026.31" gradientUnits="userSpaceOnUse"><stop stop-color="#3245FF"/><stop offset="1" stop-color="#BC52EE"/></linearGradient></defs></svg>
|
||||
|
Before Width: | Height: | Size: 1.4 KiB |
24
src/components/Card.astro
Normal file
@ -0,0 +1,24 @@
|
||||
---
|
||||
export interface Props {
|
||||
title: string;
|
||||
bigTech: string;
|
||||
alternatives: Array<{ name: string; description: string; url: string }>;
|
||||
bgClass: string;
|
||||
}
|
||||
|
||||
const { title, bigTech, alternatives, bgClass } = Astro.props;
|
||||
---
|
||||
|
||||
<div class={`border rounded-lg p-6 shadow-md ${bgClass} text-gray-900`}>
|
||||
<h2 class="text-2xl font-semibold mb-4">{title}</h2>
|
||||
<p class="text-base mb-4"><span class="line-through">Big Tech Option: {bigTech}</span></p>
|
||||
<ul class="space-y-4">
|
||||
{alternatives.map(alt => (
|
||||
<li>
|
||||
<h3 class="text-lg font-bold underline">{alt.name}</h3>
|
||||
<p>{alt.description}</p>
|
||||
<a href={alt.url} class="text-blue-500 hover:text-blue-700">Website</a>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
@ -4,10 +4,10 @@ export default function Footer() {
|
||||
return (
|
||||
<div
|
||||
className={cn(
|
||||
"flex h-12 w-screen flex-col place-items-center justify-center bg-emerald-50",
|
||||
"flex h-12 w-screen flex-col place-items-center justify-center bg-white dark:bg-black dark:text-white",
|
||||
)}
|
||||
>
|
||||
<h2>Copyleft 2025</h2>
|
||||
<h2>Copyleft {new Date().getFullYear()}</h2>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@ -1,52 +1,62 @@
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
export default function Navbar() {
|
||||
interface NavbarProps {
|
||||
activePage?: string;
|
||||
}
|
||||
|
||||
export default function Navbar({ activePage = "" }: NavbarProps) {
|
||||
return (
|
||||
<>
|
||||
<div className={cn("flex flex-row justify-between pb-8 pl-4 pr-4 pt-8")}>
|
||||
<div>
|
||||
<strong className={cn("sm:text-2xl md:text-4xl")}>
|
||||
<a href="/">Resist Tech Monopolies</a>
|
||||
<a
|
||||
className={cn(
|
||||
activePage === "Home" && "border-b-2 border-black-500",
|
||||
)}
|
||||
href="/">Resist Tech Monopolies</a>
|
||||
</strong>
|
||||
</div>
|
||||
<strong className={cn("sm:text-1xl flex gap-4 md:text-4xl")}>
|
||||
<a href="/GetInvolved/" className={cn("text-blue-500")}>
|
||||
Get Involved
|
||||
</a>
|
||||
<a href="/PointsOfUnity/" className={cn("text-green-500")}>
|
||||
<strong className={cn("sm:text-1xl flex gap-10 md:text-4xl")}>
|
||||
|
||||
<a
|
||||
href="/PointsOfUnity/"
|
||||
className={cn(
|
||||
"rounded-full px-6 py-2 transition-colors",
|
||||
"bg-gray-200 text-green-700 hover:bg-gray-300",
|
||||
"dark:bg-gray-800 dark:text-green-400 dark:hover:bg-gray-700",
|
||||
activePage === "PointsOfUnity" && "ring-2 ring-green-500 ring-offset-2",
|
||||
)}
|
||||
>
|
||||
Points of Unity
|
||||
</a>
|
||||
<a href="/WhatWereWorkingOn/" className={cn("text-red-500")}>
|
||||
What We're Working On
|
||||
<a
|
||||
href="/projects/"
|
||||
className={cn(
|
||||
"rounded-full px-6 py-2 transition-colors",
|
||||
"bg-gray-200 text-red-700 hover:bg-gray-300",
|
||||
"dark:bg-gray-800 dark:text-red-400 dark:hover:bg-gray-700",
|
||||
activePage === "OurProjects" && "ring-2 ring-red-500 ring-offset-2",
|
||||
)}
|
||||
>
|
||||
Our Projects
|
||||
</a>
|
||||
</strong>
|
||||
</div>
|
||||
|
||||
<div className={cn("flex flex-row justify-between pb-8")}>
|
||||
{[
|
||||
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
|
||||
].map(() => (
|
||||
<>
|
||||
<a
|
||||
href="https://www.flaticon.com/free-icons/computer"
|
||||
title="computer icons"
|
||||
>
|
||||
<div className="w-full grid grid-flow-col">
|
||||
{Array.from({ length: 12 }).map((_, index) => (
|
||||
<div key={index} className="flex justify-center">
|
||||
<img
|
||||
src="/computer.png"
|
||||
alt="computer icon"
|
||||
src={index % 2 === 0 ? "/assets/computer.png" : "/assets/people.png"}
|
||||
alt={index % 2 === 0 ? "computer icon" : "people icon"}
|
||||
width="30"
|
||||
height="30"
|
||||
/>
|
||||
</a>
|
||||
|
||||
<a
|
||||
href="https://www.flaticon.com/free-icons/people"
|
||||
title="people icons"
|
||||
>
|
||||
<img src="/people.png" alt="people icon" width="30" height="30" />
|
||||
</a>
|
||||
</>
|
||||
))}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
|
||||
52
src/components/zines/ZineCard.tsx
Normal file
@ -0,0 +1,52 @@
|
||||
import { Download } from "lucide-react";
|
||||
import type { Zine } from "../../data/zines";
|
||||
import { Button } from "../ui/button";
|
||||
|
||||
interface ZineCardProps {
|
||||
zine: Zine;
|
||||
onClick: () => void;
|
||||
}
|
||||
|
||||
export function ZineCard({ zine, onClick }: ZineCardProps) {
|
||||
const handleDownload = (e: React.MouseEvent) => {
|
||||
e.stopPropagation();
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="flex flex-col items-center gap-2 rounded-lg border p-4">
|
||||
<button
|
||||
onClick={onClick}
|
||||
className="group flex flex-col items-center gap-2 transition-all focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2"
|
||||
>
|
||||
<div className="aspect-[3/4] w-48 overflow-hidden rounded bg-muted">
|
||||
<img
|
||||
src={zine.coverImage}
|
||||
alt={`Cover of ${zine.title}`}
|
||||
className="h-full w-full object-cover transition-transform group-hover:scale-105"
|
||||
/>
|
||||
</div>
|
||||
<h3 className="text-lg font-medium">{zine.title}</h3>
|
||||
{zine.description && (
|
||||
<p className="text-sm text-muted-foreground">{zine.description}</p>
|
||||
)}
|
||||
</button>
|
||||
|
||||
<div className="flex gap-2 mt-2">
|
||||
<Button variant="outline" size="sm" onClick={onClick}>
|
||||
Read Online
|
||||
</Button>
|
||||
<Button
|
||||
variant="outline"
|
||||
size="sm"
|
||||
asChild
|
||||
onClick={handleDownload}
|
||||
>
|
||||
<a href={zine.printablePdf} download>
|
||||
<Download className="h-4 w-4 mr-1" />
|
||||
Printable
|
||||
</a>
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
54
src/components/zines/ZineGrid.tsx
Normal file
@ -0,0 +1,54 @@
|
||||
import { useState } from "react";
|
||||
import { zines, type Zine } from "../../data/zines";
|
||||
import { ZineCard } from "./ZineCard";
|
||||
import { ZineViewer } from "./ZineViewer";
|
||||
import {
|
||||
Dialog,
|
||||
DialogContent,
|
||||
DialogTitle,
|
||||
DialogDescription,
|
||||
} from "../ui/dialog";
|
||||
import * as VisuallyHidden from "@radix-ui/react-visually-hidden";
|
||||
|
||||
export function ZineGrid() {
|
||||
const [selectedZine, setSelectedZine] = useState<Zine | null>(null);
|
||||
|
||||
const handleOpenZine = (zine: Zine) => {
|
||||
setSelectedZine(zine);
|
||||
};
|
||||
|
||||
const handleCloseZine = () => {
|
||||
setSelectedZine(null);
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="grid grid-cols-1 gap-6 sm:grid-cols-2 lg:grid-cols-3">
|
||||
{zines.map((zine) => (
|
||||
<ZineCard
|
||||
key={zine.id}
|
||||
zine={zine}
|
||||
onClick={() => handleOpenZine(zine)}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
|
||||
<Dialog open={selectedZine !== null} onOpenChange={handleCloseZine}>
|
||||
<DialogContent className="max-w-4xl">
|
||||
<VisuallyHidden.Root>
|
||||
<DialogTitle>{selectedZine?.title}</DialogTitle>
|
||||
<DialogDescription>
|
||||
Interactive flipbook viewer for {selectedZine?.title}
|
||||
</DialogDescription>
|
||||
</VisuallyHidden.Root>
|
||||
{selectedZine && (
|
||||
<ZineViewer
|
||||
pages={selectedZine.pages}
|
||||
title={selectedZine.title}
|
||||
/>
|
||||
)}
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
</>
|
||||
);
|
||||
}
|
||||
245
src/components/zines/ZineViewer.tsx
Normal file
@ -0,0 +1,245 @@
|
||||
import React, { useRef, useState, useCallback, forwardRef, useEffect } from "react";
|
||||
import HTMLFlipBook from "react-pageflip";
|
||||
import { ChevronLeft, ChevronRight, ZoomIn, ZoomOut, Minimize2 } from "lucide-react";
|
||||
import { Button } from "../ui/button";
|
||||
|
||||
interface PageProps {
|
||||
src: string;
|
||||
pageNumber: number;
|
||||
}
|
||||
|
||||
const Page = forwardRef<HTMLDivElement, PageProps>(({ src, pageNumber }, ref) => {
|
||||
return (
|
||||
<div ref={ref} className="page bg-white">
|
||||
<img
|
||||
src={src}
|
||||
alt={`Page ${pageNumber}`}
|
||||
className="h-full w-full object-contain"
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
});
|
||||
|
||||
Page.displayName = "Page";
|
||||
|
||||
interface ZineViewerProps {
|
||||
pages: string[];
|
||||
title: string;
|
||||
}
|
||||
|
||||
const MIN_ZOOM = 1;
|
||||
const MAX_ZOOM = 2.5;
|
||||
const ZOOM_STEP = 0.5;
|
||||
|
||||
export function ZineViewer({ pages, title }: ZineViewerProps) {
|
||||
const flipBookRef = useRef<any>(null);
|
||||
const [currentPage, setCurrentPage] = useState(0);
|
||||
const totalPages = pages.length;
|
||||
|
||||
const [zoom, setZoom] = useState(1);
|
||||
const [pan, setPan] = useState({ x: 0, y: 0 });
|
||||
const [isPanning, setIsPanning] = useState(false);
|
||||
const panStart = useRef({ x: 0, y: 0 });
|
||||
const panOffset = useRef({ x: 0, y: 0 });
|
||||
|
||||
const isZoomed = zoom > MIN_ZOOM;
|
||||
|
||||
const onFlip = useCallback((e: any) => {
|
||||
setCurrentPage(e.data);
|
||||
}, []);
|
||||
|
||||
const goToPrevPage = () => {
|
||||
flipBookRef.current?.pageFlip()?.flipPrev();
|
||||
};
|
||||
|
||||
const goToNextPage = () => {
|
||||
flipBookRef.current?.pageFlip()?.flipNext();
|
||||
};
|
||||
|
||||
const handleZoomIn = () => {
|
||||
setZoom((z) => Math.min(z + ZOOM_STEP, MAX_ZOOM));
|
||||
};
|
||||
|
||||
const handleZoomOut = () => {
|
||||
setZoom((z) => {
|
||||
const next = Math.max(z - ZOOM_STEP, MIN_ZOOM);
|
||||
if (next <= MIN_ZOOM) setPan({ x: 0, y: 0 });
|
||||
return next;
|
||||
});
|
||||
};
|
||||
|
||||
const handleZoomReset = () => {
|
||||
setZoom(MIN_ZOOM);
|
||||
setPan({ x: 0, y: 0 });
|
||||
};
|
||||
|
||||
const handlePointerDown = (e: React.PointerEvent) => {
|
||||
if (!isZoomed) return;
|
||||
setIsPanning(true);
|
||||
panStart.current = { x: e.clientX, y: e.clientY };
|
||||
panOffset.current = { x: pan.x, y: pan.y };
|
||||
(e.target as HTMLElement).setPointerCapture?.(e.pointerId);
|
||||
e.preventDefault();
|
||||
};
|
||||
|
||||
const handlePointerMove = (e: React.PointerEvent) => {
|
||||
if (!isPanning) return;
|
||||
const dx = (e.clientX - panStart.current.x) / zoom;
|
||||
const dy = (e.clientY - panStart.current.y) / zoom;
|
||||
setPan({
|
||||
x: panOffset.current.x + dx,
|
||||
y: panOffset.current.y + dy,
|
||||
});
|
||||
};
|
||||
|
||||
const handlePointerUp = () => {
|
||||
setIsPanning(false);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
const handleKeyDown = (e: KeyboardEvent) => {
|
||||
if (e.key === "ArrowLeft") {
|
||||
goToPrevPage();
|
||||
} else if (e.key === "ArrowRight") {
|
||||
goToNextPage();
|
||||
}
|
||||
};
|
||||
|
||||
window.addEventListener("keydown", handleKeyDown);
|
||||
return () => window.removeEventListener("keydown", handleKeyDown);
|
||||
}, []);
|
||||
|
||||
if (pages.length === 0) {
|
||||
return (
|
||||
<div className="flex h-64 items-center justify-center text-muted-foreground">
|
||||
No pages available
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="flex flex-col items-center gap-4">
|
||||
<h2 className="text-xl font-semibold">{title}</h2>
|
||||
|
||||
<div className="flex items-center gap-2">
|
||||
<Button
|
||||
variant="outline"
|
||||
size="icon"
|
||||
onClick={handleZoomOut}
|
||||
disabled={zoom <= MIN_ZOOM}
|
||||
aria-label="Zoom out"
|
||||
>
|
||||
<ZoomOut className="h-4 w-4" />
|
||||
</Button>
|
||||
<span className="text-sm text-muted-foreground w-12 text-center">
|
||||
{Math.round(zoom * 100)}%
|
||||
</span>
|
||||
<Button
|
||||
variant="outline"
|
||||
size="icon"
|
||||
onClick={handleZoomIn}
|
||||
disabled={zoom >= MAX_ZOOM}
|
||||
aria-label="Zoom in"
|
||||
>
|
||||
<ZoomIn className="h-4 w-4" />
|
||||
</Button>
|
||||
{isZoomed && (
|
||||
<Button
|
||||
variant="outline"
|
||||
size="icon"
|
||||
onClick={handleZoomReset}
|
||||
aria-label="Reset zoom"
|
||||
>
|
||||
<Minimize2 className="h-4 w-4" />
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div
|
||||
className="flipbook-container"
|
||||
style={{
|
||||
overflow: "hidden",
|
||||
cursor: isZoomed ? (isPanning ? "grabbing" : "grab") : "default",
|
||||
}}
|
||||
onPointerDown={handlePointerDown}
|
||||
onPointerMove={handlePointerMove}
|
||||
onPointerUp={handlePointerUp}
|
||||
onPointerCancel={handlePointerUp}
|
||||
>
|
||||
<div
|
||||
style={{
|
||||
transform: `scale(${zoom}) translate(${pan.x}px, ${pan.y}px)`,
|
||||
transformOrigin: "center center",
|
||||
transition: isPanning ? "none" : "transform 0.2s ease",
|
||||
pointerEvents: isZoomed ? "none" : "auto",
|
||||
}}
|
||||
>
|
||||
{/* @ts-ignore - react-pageflip types are incomplete */}
|
||||
<HTMLFlipBook
|
||||
ref={flipBookRef}
|
||||
width={350}
|
||||
height={500}
|
||||
size="stretch"
|
||||
minWidth={280}
|
||||
maxWidth={500}
|
||||
minHeight={400}
|
||||
maxHeight={700}
|
||||
maxShadowOpacity={0.5}
|
||||
showCover={true}
|
||||
mobileScrollSupport={!isZoomed}
|
||||
onFlip={onFlip}
|
||||
className="flipbook"
|
||||
style={{}}
|
||||
startPage={0}
|
||||
drawShadow={true}
|
||||
flippingTime={600}
|
||||
usePortrait={true}
|
||||
startZIndex={0}
|
||||
autoSize={true}
|
||||
clickEventForward={true}
|
||||
useMouseEvents={!isZoomed}
|
||||
swipeDistance={30}
|
||||
showPageCorners={!isZoomed}
|
||||
disableFlipByClick={false}
|
||||
>
|
||||
{pages.map((page, index) => (
|
||||
<Page key={index} src={page} pageNumber={index + 1} />
|
||||
))}
|
||||
</HTMLFlipBook>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex items-center gap-4">
|
||||
<Button
|
||||
variant="outline"
|
||||
size="icon"
|
||||
onClick={goToPrevPage}
|
||||
disabled={currentPage === 0}
|
||||
aria-label="Previous page"
|
||||
>
|
||||
<ChevronLeft className="h-4 w-4" />
|
||||
</Button>
|
||||
|
||||
<span className="text-sm text-muted-foreground">
|
||||
Page {currentPage + 1} of {totalPages}
|
||||
</span>
|
||||
|
||||
<Button
|
||||
variant="outline"
|
||||
size="icon"
|
||||
onClick={goToNextPage}
|
||||
disabled={currentPage >= totalPages - 1}
|
||||
aria-label="Next page"
|
||||
>
|
||||
<ChevronRight className="h-4 w-4" />
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
<p className="text-xs text-muted-foreground">
|
||||
{isZoomed
|
||||
? "Drag to pan. Use arrow buttons to turn pages"
|
||||
: "Click the page corners or use arrow buttons to turn pages"}
|
||||
</p>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
96
src/data/zines.ts
Normal file
@ -0,0 +1,96 @@
|
||||
export interface Zine {
|
||||
id: string;
|
||||
title: string;
|
||||
description: string;
|
||||
coverImage: string;
|
||||
pages: string[];
|
||||
printablePdf: string;
|
||||
}
|
||||
|
||||
export const zines: Zine[] = [
|
||||
{
|
||||
id: "internet-for-the-people",
|
||||
title: "Internet For the People",
|
||||
description: "",
|
||||
coverImage: "/assets/zines/internet-for-the-people/cover.jpg",
|
||||
pages: [
|
||||
"/assets/zines/internet-for-the-people/page-1.jpg",
|
||||
"/assets/zines/internet-for-the-people/page-2.jpg",
|
||||
"/assets/zines/internet-for-the-people/page-3.jpg",
|
||||
"/assets/zines/internet-for-the-people/page-4.jpg",
|
||||
"/assets/zines/internet-for-the-people/page-5.jpg",
|
||||
"/assets/zines/internet-for-the-people/page-6.jpg",
|
||||
"/assets/zines/internet-for-the-people/page-7.jpg",
|
||||
"/assets/zines/internet-for-the-people/page-8.jpg",
|
||||
],
|
||||
printablePdf: "/assets/zines/internet-for-the-people/printable.pdf",
|
||||
},
|
||||
{
|
||||
id: "de-monopoly-discotech-101",
|
||||
title: "De-Monopoly DiscoTech 101",
|
||||
description: "",
|
||||
coverImage: "/assets/zines/de-monopoly-discotech-101/cover.jpg",
|
||||
pages: [
|
||||
"/assets/zines/de-monopoly-discotech-101/page-1.jpg",
|
||||
"/assets/zines/de-monopoly-discotech-101/page-2.jpg",
|
||||
"/assets/zines/de-monopoly-discotech-101/page-3.jpg",
|
||||
"/assets/zines/de-monopoly-discotech-101/page-4.jpg",
|
||||
"/assets/zines/de-monopoly-discotech-101/page-5.jpg",
|
||||
"/assets/zines/de-monopoly-discotech-101/page-6.jpg",
|
||||
"/assets/zines/de-monopoly-discotech-101/page-7.jpg",
|
||||
"/assets/zines/de-monopoly-discotech-101/page-8.jpg",
|
||||
],
|
||||
printablePdf: "/assets/zines/de-monopoly-discotech-101/printable.pdf",
|
||||
},
|
||||
{
|
||||
id: "de-monopoly-discotech-101-japanese",
|
||||
title: "De-Monopoly DiscoTech 101 (Japanese)",
|
||||
description: "",
|
||||
coverImage: "/assets/zines/de-monopoly-discotech-101-japanese/cover.jpg",
|
||||
pages: [
|
||||
"/assets/zines/de-monopoly-discotech-101-japanese/page-1.jpg",
|
||||
"/assets/zines/de-monopoly-discotech-101-japanese/page-2.jpg",
|
||||
"/assets/zines/de-monopoly-discotech-101-japanese/page-3.jpg",
|
||||
"/assets/zines/de-monopoly-discotech-101-japanese/page-4.jpg",
|
||||
"/assets/zines/de-monopoly-discotech-101-japanese/page-5.jpg",
|
||||
"/assets/zines/de-monopoly-discotech-101-japanese/page-6.jpg",
|
||||
"/assets/zines/de-monopoly-discotech-101-japanese/page-7.jpg",
|
||||
"/assets/zines/de-monopoly-discotech-101-japanese/page-8.jpg",
|
||||
],
|
||||
printablePdf: "/assets/zines/de-monopoly-discotech-101-japanese/printable.pdf",
|
||||
},
|
||||
{
|
||||
id: "brief-notes-from-a-de-monopoly-discotech",
|
||||
title: "Brief Notes from a De-Monopoly DiscoTech",
|
||||
description: "",
|
||||
coverImage: "/assets/zines/brief-notes-from-a-de-monopoly-discotech/cover.jpg",
|
||||
pages: [
|
||||
"/assets/zines/brief-notes-from-a-de-monopoly-discotech/cover.jpg",
|
||||
"/assets/zines/brief-notes-from-a-de-monopoly-discotech/page-1.jpg",
|
||||
"/assets/zines/brief-notes-from-a-de-monopoly-discotech/page-2.jpg",
|
||||
"/assets/zines/brief-notes-from-a-de-monopoly-discotech/page-3.jpg",
|
||||
"/assets/zines/brief-notes-from-a-de-monopoly-discotech/page-4.jpg",
|
||||
"/assets/zines/brief-notes-from-a-de-monopoly-discotech/page-5.jpg",
|
||||
"/assets/zines/brief-notes-from-a-de-monopoly-discotech/page-6.jpg",
|
||||
"/assets/zines/brief-notes-from-a-de-monopoly-discotech/page-7.jpg",
|
||||
],
|
||||
printablePdf: "/assets/zines/brief-notes-from-a-de-monopoly-discotech/printable.pdf",
|
||||
},
|
||||
{
|
||||
id: "signal-101",
|
||||
title: "Signal 101",
|
||||
description: "",
|
||||
coverImage: "/assets/zines/signal-101/cover.jpg",
|
||||
pages: [
|
||||
"/assets/zines/signal-101/cover.jpg",
|
||||
"/assets/zines/signal-101/page-1.jpg",
|
||||
"/assets/zines/signal-101/page-2.jpg",
|
||||
"/assets/zines/signal-101/page-3.jpg",
|
||||
"/assets/zines/signal-101/page-4.jpg",
|
||||
"/assets/zines/signal-101/page-5.jpg",
|
||||
"/assets/zines/signal-101/page-6.jpg",
|
||||
"/assets/zines/signal-101/page-7.jpg",
|
||||
],
|
||||
printablePdf: "/assets/zines/signal-101/printable.pdf",
|
||||
},
|
||||
];
|
||||
@ -8,20 +8,11 @@ import "../styles/globals.css";
|
||||
<Layout>
|
||||
<main class="flex min-h-screen flex-col justify-between">
|
||||
<div>
|
||||
<Navbar />
|
||||
<Navbar client:load activePage="GetInvolved" />
|
||||
<div class="pl-4 pr-4">
|
||||
<h1 class="text-3xl font-semibold">Get Involved</h1>
|
||||
|
||||
<div class="my-8">
|
||||
<a
|
||||
href="https://shlink.resisttechmonopolies.online/HNrZG"
|
||||
class="px-6 py-3 bg-[#80aaff] text-white font-semibold rounded-md hover:bg-[#6090e0] transition-colors"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
Sign Up Here
|
||||
</a>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<Footer />
|
||||
|
||||
@ -8,33 +8,71 @@ import "../styles/globals.css";
|
||||
<Layout>
|
||||
<main class="flex min-h-screen flex-col justify-between">
|
||||
<div>
|
||||
<Navbar />
|
||||
<Navbar client:load activePage="PointsOfUnity" />
|
||||
<div class="pl-4 pr-4">
|
||||
<h1 class="text-3xl font-semibold">Points of Unity</h1>
|
||||
<p>
|
||||
We situate ourselves in our context - as Seattle residents and as
|
||||
users and creators of the technologies we aim to resist. We are seeing
|
||||
long-spanning rise of fascism within all levels of governance, from
|
||||
Seattle city council to national governments here and abroad. In
|
||||
parallel is the increasing power of tech companies over our lives
|
||||
through surveillance and the provisioning of everyday needs, from
|
||||
employment to how we get our internet utilities in the first place.
|
||||
There are rising income disparities across the nation, but also more
|
||||
specifically across everyone who can be considered a "tech worker":
|
||||
from a CEO to a software engineer to a contractor to a child slave
|
||||
mining cobalt in the Congo. Technology contributes to gentrification
|
||||
both through the tech-enabled financialization of real estate as well
|
||||
as the gentrifying waves of tech workers moving into cities. Increased
|
||||
technical sophisication of militaries and carceral systems have
|
||||
created the first "AI genocide" in Palestine; increased militarization
|
||||
of borders such as the US-Mexico and the surveillance of migrants;
|
||||
increased police brutality worldwide, all disparately impacting people
|
||||
of the global majority. All of these crises are enabled and worsened
|
||||
by technology companies. As tech workers of various kinds living in
|
||||
the imperial core, on stolen Coast Salish land covered by the broken
|
||||
Treaty of Point Elliot of 1855, we understand how our labor is
|
||||
contributing - directly or indirectly - to these oppressions, and seek
|
||||
to use our skills towards more liberatory ends.
|
||||
|
||||
<p class="mb-4">
|
||||
Our community agreements and decision-making process describe <em>how</em> we work together. The points of unity are the broader philosophies that we're working towards as a group. Perhaps people aren't 100% aligned individually, but this is what the group as a whole believes in when showing up to the work.
|
||||
</p>
|
||||
|
||||
<h2 class="text-2xl font-semibold mt-10 mb-2">Grounding</h2>
|
||||
|
||||
<p class="mb-4">
|
||||
We situate ourselves in our context - as Seattle residents and as users and creators of the technologies we aim to resist. We are seeing a long-spanning rise of fascism within national governments here and abroad. In parallel is the increasing power of tech companies over our lives through surveillance and the provisioning of everyday needs, from employment to how we get our internet utilities in the first place. There are rising income disparities across the nation, but also more specifically across everyone who can be considered a "tech worker": from a CEO, to a software engineer to a tech campus cafeteria worker to a child enslaved to mine cobalt in the Congo.
|
||||
</p>
|
||||
|
||||
<p class="mb-4">
|
||||
We know that technology intersects with and amplifies systems of oppression, from anti-Black racism to classism, ableism, cisheteropatriarchy, etc. Big tech permeates all aspects of life in Seattle, but to name a few ways:
|
||||
</p>
|
||||
|
||||
<ul class="list-disc pl-8 mb-4 space-y-2">
|
||||
<li>The rise of a <a href="https://stopsurveillancecity.wordpress.com/" class="font-bold underline hover:text-gray-600">Surveillance City</a> in Seattle facilitates the tracking of out-of-state people seeking abortions, the kidnapping of migrants, and the increased surveillance and criminalization of sex workers, the visibly unhoused, and poor and racialized communities.</li>
|
||||
<li>The <strong>environmental racism</strong> and community impacts of <strong>data centers</strong>, both from the AI bubble and the demand for more data processing that comes with surveillance capitalism.</li>
|
||||
<li><strong>The AI genocide</strong> in Palestine abetted by Google, Amazon, Boeing and Microsoft, all local Seattle employers.</li>
|
||||
<li>Rising <strong>gentrification</strong> and <strong>income inequality</strong> that comes from financialization of real estate and the gentrifying waves of tech workers moving into the city.</li>
|
||||
</ul>
|
||||
|
||||
<p class="mb-4">
|
||||
Some of us are employed by Big Tech companies, and we are all living on stolen Coast Salish land covered by the broken Treaty of Point Elliot of 1855; we understand that we are contributing - directly or indirectly - to these oppressions, and seek to use our skills towards more liberatory ends.
|
||||
</p>
|
||||
|
||||
<h2 class="text-2xl font-semibold mt-10 mb-2">Theory of Change</h2>
|
||||
|
||||
<p class="mb-4">
|
||||
We are committed to fostering our collective understanding of resisting tech monopolies and building a constellation of alternative technologies that exist outside of exploitative, oppressive systems. We seek out radical possibilities by building connections across our communities with others struggling to resist tech monopolies and reject work that expands the reach of these monopolies.
|
||||
</p>
|
||||
|
||||
<p class="mb-4">
|
||||
We don't need to passively wait around for somebody to come implement these solutions. Making improvements to our lives and our communities paves the way for collective liberation. Dismantling smaller elements of a system is practice for uprooting the whole and replacing it with a constellation of liberatory alternatives.
|
||||
</p>
|
||||
|
||||
<h2 class="text-2xl font-semibold mt-10 mb-2">Role of Technology</h2>
|
||||
|
||||
<p class="mb-4">
|
||||
"We believe our communities and organizing efforts can and should harness the possibilities of new technology." (<a href="https://mijente.net/our-dna/" class="underline hover:text-gray-600">Mijente</a>) However, we don't innovate for the sake of innovation, but aim to create with intention, listen to the perspectives of those we hope to serve (including ourselves), and hold each other accountable in this work.
|
||||
</p>
|
||||
|
||||
<h2 class="text-2xl font-semibold mt-10 mb-2">Our Position in the Movement</h2>
|
||||
|
||||
<p class="mb-4">
|
||||
We don't see ourselves as a vanguard organization - that is, we make no claims to being the sole authority on resisting tech monopolies and we will never tell a front-line community or group of tech users what they actually need. Everyone benefits from the work of resisting tech monopolies, and for that reason we do the work for ourselves as much as we do it for anybody we are in solidarity with.
|
||||
</p>
|
||||
|
||||
<p class="mb-4">
|
||||
However we also recognize our own privilege in being highly-skilled tech workers: because of this we center the voices of the people most vulnerable to various tech monopolies, and aim to share our expertise so that others can also become agents in co-creating technologies of liberation and resistance.
|
||||
</p>
|
||||
|
||||
<h2 class="text-2xl font-semibold mt-10 mb-2">Friendly Vibes</h2>
|
||||
|
||||
<p class="mb-4">
|
||||
Holding all of the above, we're also a group of friends here for the scrappy, hacky vibes. We don't take our work too seriously and we're here to work joyfully. This is first and foremost a community.
|
||||
</p>
|
||||
|
||||
<h2 class="text-2xl font-semibold mt-10 mb-2">Acknowledgments</h2>
|
||||
|
||||
<p class="mb-4">
|
||||
These points of unity were inspired by the Prison Library Solidarity Network, the Coalition of Anti-Racist Whites, Ruha Benjamin's work on Abolitionist Tech, and Mijente.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -1,19 +0,0 @@
|
||||
---
|
||||
import Navbar from "../components/Navbar";
|
||||
import Footer from "../components/Footer";
|
||||
import Layout from "../layouts/Layout.astro";
|
||||
import "../styles/globals.css";
|
||||
---
|
||||
|
||||
<Layout>
|
||||
<main class="flex min-h-screen flex-col justify-between">
|
||||
<div>
|
||||
<Navbar />
|
||||
<div class="pl-4 pr-4">
|
||||
<h1 class="text-3xl font-semibold">What We're Working On</h1>
|
||||
<p>Pihole Workshop</p>
|
||||
</div>
|
||||
</div>
|
||||
<Footer />
|
||||
</main>
|
||||
</Layout>
|
||||
@ -8,15 +8,26 @@ import "@/styles/globals.css";
|
||||
<Layout>
|
||||
<main class="flex min-h-screen flex-col justify-between">
|
||||
<div>
|
||||
<Navbar />
|
||||
<Navbar client:load activePage="Home" />
|
||||
|
||||
<div class="pl-4 pr-4">
|
||||
<div class="pl-4 pr-4 text-xl leading-[2]">
|
||||
<p>
|
||||
Do you believe technology can and should be used for good? Do you
|
||||
think a democratic internet could liberate us? Join us!
|
||||
</p>
|
||||
|
||||
<p>We share this vision, and we want to work together to achieve it.</p>
|
||||
|
||||
<div class="my-8">
|
||||
<a
|
||||
href="https://shlink.resisttechmonopolies.online/HNrZG"
|
||||
class="px-6 py-3 bg-[#80aaff] text-white font-semibold rounded-md hover:bg-[#6090e0] transition-colors"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
Fill Out Our Interest Form!
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
95
src/pages/projects.astro
Normal file
@ -0,0 +1,95 @@
|
||||
---
|
||||
import Navbar from "../components/Navbar";
|
||||
import Footer from "../components/Footer";
|
||||
import Layout from "../layouts/Layout.astro";
|
||||
import "../styles/globals.css";
|
||||
---
|
||||
|
||||
<Layout>
|
||||
<main class="flex min-h-screen flex-col justify-between">
|
||||
<div>
|
||||
<Navbar client:load activePage="OurProjects" />
|
||||
<div class="pl-4 pr-4">
|
||||
<h1 class="pb-4 pt-4 text-3xl font-semibold">Our Projects</h1>
|
||||
<div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-8">
|
||||
<!-- <div class="justify-items-center">
|
||||
<img
|
||||
src="/assets/calendar.png"
|
||||
alt="stack of books"
|
||||
width="250"
|
||||
class="border pb-4"
|
||||
/>
|
||||
|
||||
<a
|
||||
href="/projects/calendar/"
|
||||
class="underline decoration-solid">Calendar</a
|
||||
>
|
||||
</div> -->
|
||||
|
||||
<div class="justify-items-center">
|
||||
<img
|
||||
src="/assets/book-club.jpg"
|
||||
alt="stack of books"
|
||||
width="280"
|
||||
class="border"
|
||||
/>
|
||||
<a
|
||||
href="/projects/bookclub/"
|
||||
class="underline decoration-solid">Book Club</a
|
||||
>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<div class="justify-items-center">
|
||||
<img
|
||||
src="/assets/computer.png"
|
||||
alt="computer"
|
||||
width="250"
|
||||
class="border"
|
||||
/>
|
||||
<a href="/projects/alternatives/" class="underline decoration-solid">Big Tech Alternatives</a>
|
||||
</div>
|
||||
|
||||
<div class="justify-items-center">
|
||||
<img
|
||||
src="/assets/zines-thumbnail.png"
|
||||
alt="zines"
|
||||
width="250"
|
||||
class="border object-cover w-[250px] h-[250px]"
|
||||
/>
|
||||
<a href="/projects/zines/" class="underline decoration-solid">Zines</a>
|
||||
</div>
|
||||
|
||||
<div class="justify-items-center">
|
||||
<img
|
||||
src="/assets/pet-calendar-2026-cover.jpg"
|
||||
alt="photo collage of cats"
|
||||
width="500"
|
||||
class="border"
|
||||
/>
|
||||
<a
|
||||
href="/projects/PetCalendar/"
|
||||
class="underline decoration-solid">Pet Calendar</a
|
||||
>
|
||||
</div>
|
||||
|
||||
<div class="justify-items-center">
|
||||
<img
|
||||
src="/assets/pihole.jpeg"
|
||||
alt="pihole parts"
|
||||
width="250"
|
||||
class="border"
|
||||
/>
|
||||
<a
|
||||
href="/projects/pihole/"
|
||||
class="underline decoration-solid">Pihole Workshop</a
|
||||
>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<Footer />
|
||||
</main>
|
||||
</Layout>
|
||||
343
src/pages/projects/PetCalendar.astro
Normal file
@ -0,0 +1,343 @@
|
||||
---
|
||||
import Navbar from "../../components/Navbar";
|
||||
import Footer from "../../components/Footer";
|
||||
import Layout from "../../layouts/Layout.astro";
|
||||
import "../../styles/globals.css";
|
||||
---
|
||||
|
||||
<Layout>
|
||||
<main class="flex min-h-screen flex-col justify-between">
|
||||
<div>
|
||||
<Navbar client:load activePage="WhatWereWorkingOn" />
|
||||
<div class="pl-4 pr-4">
|
||||
<h1 class="pb-4 pt-4 text-3xl font-semibold">Pet Calendar</h1>
|
||||
<div>We created a pet calendar with 12 beautiful pictures of RTM's
|
||||
animal friends.
|
||||
<p class="pb-2">Each month, our pets will share with you with a different way you can
|
||||
Resist Big Tech Monopolies!</p>
|
||||
<p class="pb-2"> If you'd like to request a calendar, email us at besties@resisttechmonopolies.online</p>
|
||||
<div class="justify-items-center">
|
||||
<img
|
||||
src="/assets/pet-calendar-2026-cover.jpg"
|
||||
alt="pihole parts"
|
||||
width="500"
|
||||
class="border"
|
||||
/>
|
||||
|
||||
</div>
|
||||
<div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<h1 class="pb-4 pt-4 text-2xl font-semibold">2026 Monthly RTM Tutorials</h1>
|
||||
|
||||
<div class="flex flex-col gap-8">
|
||||
<div class="rounded-lg border p-6">
|
||||
<h2 class="mb-4 text-2xl font-semibold" id="January">January</h2>
|
||||
<div>
|
||||
<p class="mb-2"> Try out Mastadon for algorithmless social media that won't sell your data!</p>
|
||||
<a
|
||||
class="underline mb-2"
|
||||
href="https://joinmastodon.org/"
|
||||
>Join Mastadon!
|
||||
</a >
|
||||
|
||||
<p class="mb-2"> Difficulty rating: 🌶️/5
|
||||
</p>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div class="flex flex-col gap-8">
|
||||
<div class="rounded-lg border p-6">
|
||||
<h2 class="mb-4 text-2xl font-semibold" id="February">February</h2>
|
||||
<div>
|
||||
|
||||
|
||||
<p class="mb-2"> Learn about hosting your own instances of tech services to protect your data!</p>
|
||||
<a
|
||||
class="underline mb-2"
|
||||
href="https://www.xda-developers.com/tips-for-self-hosting-beginners/"
|
||||
>Beginner's Guide to Self-Hosting!
|
||||
</a >
|
||||
|
||||
<p class="mb-2"> Difficulty rating: 🌶️🌶️🌶️🌶️/5
|
||||
</p>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div class="flex flex-col gap-8">
|
||||
<div class="rounded-lg border p-6">
|
||||
<h2 class="mb-4 text-2xl font-semibold" id="March">March</h2>
|
||||
<div>
|
||||
<p class="mb-2"> Try out Calibre to read Amazon-free e-books!</p>
|
||||
<a
|
||||
class="underline mb-2"
|
||||
href="https://tutorials.mediaket.net/software-tutorials/calibre-how-to-use-it.html"
|
||||
>Get Started with Calibre!
|
||||
</a >
|
||||
|
||||
<p class="mb-2"> Difficulty rating: 🌶️🌶️/5
|
||||
</p>
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div class="flex flex-col gap-8">
|
||||
<div class="rounded-lg border p-6">
|
||||
<h2 class="mb-4 text-2xl font-semibold" id="April">April</h2>
|
||||
<div>
|
||||
<p class="mb-2"> Thinking of switching off Windows or MacOS? Try Linux
|
||||
for a super customizable, privacy-first operating system!
|
||||
</p>
|
||||
<a
|
||||
class="underline mb-2"
|
||||
href="https://www.geeksforgeeks.org/linux-unix/30-days-of-linux/"
|
||||
>30 Days of Linux for Beginners!
|
||||
</a >
|
||||
|
||||
<p class="mb-2"> Difficulty rating: 🌶️🌶️🌶️🌶️/5
|
||||
</p>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div class="flex flex-col gap-8">
|
||||
<div class="rounded-lg border p-6">
|
||||
<h2 class="mb-4 text-2xl font-semibold" id="May">May</h2>
|
||||
<div>
|
||||
<p class="mb-2"> Try going outside and repping some protest fashion this Spring!</p>
|
||||
<a
|
||||
class="underline mb-2"
|
||||
href="https://graziamagazine.com/me/articles/history-keffiyeh-palestine/"
|
||||
>Learn the history and meaning of the keffiyeh!
|
||||
</a >
|
||||
|
||||
<p class="mb-2"> Difficulty rating: 🌶️/5
|
||||
</p>
|
||||
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div class="flex flex-col gap-8">
|
||||
<div class="rounded-lg border p-6">
|
||||
<h2 class="mb-4 text-2xl font-semibold" id="June">June</h2>
|
||||
<div>
|
||||
<p class="mb-2"> Try out Ente for a privacy-friendly, open-source photos hosting platform!</p>
|
||||
<a
|
||||
class="underline mb-2"
|
||||
href="https://web.archive.org/web/20260108185516/https://www.androidauthority.com/ente-photos-hands-on-3542198/"
|
||||
>In-depth overeview of Ente Photos migration!
|
||||
</a >
|
||||
|
||||
<p class="mb-2"> Difficulty rating: 🌶️/5
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div class="flex flex-col gap-8">
|
||||
<div class="rounded-lg border p-6">
|
||||
<h2 class="mb-4 text-2xl font-semibold" id="July">July</h2>
|
||||
<div>
|
||||
<p class="mb-2"> Try installing your own Pi Hole on your home wifi network to block ad and malware servers!</p>
|
||||
<a
|
||||
class="underline mb-2"
|
||||
href="https://protasm.com/blogs/news/an-extensive-tutorial-on-how-to-setup-a-pi-hole"
|
||||
>Extensive PiHole Tutorial!
|
||||
</a >
|
||||
|
||||
<p class="mb-2"> Difficulty rating: 🌶️🌶️🌶️🌶️🌶️/5
|
||||
</p>
|
||||
|
||||
</div>
|
||||
<hr class="mb-4">
|
||||
<p class="mb-2"> Alternative: Install an adblocker!</p>
|
||||
<a
|
||||
class="underline mb-2"
|
||||
href="https://adblockplus.org/"
|
||||
>Install Adblock Plus!
|
||||
</a >
|
||||
|
||||
<p class="mb-2"> Difficulty rating: 🌶️/5
|
||||
</p>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div class="flex flex-col gap-8">
|
||||
<div class="rounded-lg border p-6">
|
||||
<h2 class="mb-4 text-2xl font-semibold" id="August">August</h2>
|
||||
<div>
|
||||
<p class="mb-2"> Try out DuckDuckGo as a privacy-friendly alternative to Google search and Chrome!</p>
|
||||
<a
|
||||
class="underline mb-2"
|
||||
href="https://duckduckgo.com/"
|
||||
>Download Duck Duck Go!
|
||||
</a >
|
||||
|
||||
<p class="mb-2"> Difficulty rating: 🌶️/5
|
||||
</p>
|
||||
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div class="flex flex-col gap-8">
|
||||
<div class="rounded-lg border p-6">
|
||||
<h2 class="mb-4 text-2xl font-semibold" id="September">September</h2>
|
||||
<div>
|
||||
<p class="mb-2"> Instead of relying on surveillance for safety, try making friends with your neighbors!</p>
|
||||
<a
|
||||
class="underline mb-2"
|
||||
href="https://www.youtube.com/watch?v=1-Xl6dhDV3Q"
|
||||
> How to Build Radical Community!
|
||||
</a >
|
||||
|
||||
<p class="mb-2"> Difficulty rating: 🌶️🌶️🌶️/5
|
||||
|
||||
</p>
|
||||
(hey making friends in Seattle is hard, okay?)
|
||||
|
||||
</div>
|
||||
<hr class="mb-4">
|
||||
<p class="mb-2"> Alternative: Neighbor Unions (buliding community power!)</p>
|
||||
<a
|
||||
class="underline mb-2"
|
||||
href="https://social-ecology.org/wp/neighbor-union-cohort/"
|
||||
>Learn about Neighbor Unions!
|
||||
</a >
|
||||
|
||||
<p class="mb-2"> Difficulty rating: 🌶️🌶️🌶️/5
|
||||
</p>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div class="flex flex-col gap-8">
|
||||
<div class="rounded-lg border p-6">
|
||||
<h2 class="mb-4 text-2xl font-semibold" id="October">October</h2>
|
||||
<div>
|
||||
<p class="mb-2"> Try out JellyFin to host your own media server
|
||||
and share with friends. You can break up with Netflix, Hulu, Disney+, and more!
|
||||
</p>
|
||||
<a
|
||||
class="underline mb-2"
|
||||
href="https://jellyfin.org/docs/general/quick-start/"
|
||||
>Quickstart for JellyFin!
|
||||
</a >
|
||||
|
||||
<p class="mb-2"> Difficulty rating: 🌶️🌶️🌶️🌶️/5
|
||||
</p>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div class="flex flex-col gap-8">
|
||||
<div class="rounded-lg border p-6">
|
||||
<h2 class="mb-4 text-2xl font-semibold" id="November">November</h2>
|
||||
<div>
|
||||
<p class="mb-2"> Try out Meet.coop as an open-source, privacy-friendly, and renewable energy-powered alternative to Zoom and Hangouts! </p>
|
||||
<a
|
||||
class="underline mb-2"
|
||||
href="https://www.meet.coop/"
|
||||
>Make a Meet.coop account!
|
||||
</a >
|
||||
|
||||
<p class="mb-2"> Difficulty rating: 🌶️🌶️/5
|
||||
</p>
|
||||
</div>
|
||||
<hr class="mb-4">
|
||||
|
||||
<p class="mb-2"> Free alternative: Jitsi</p>
|
||||
<a
|
||||
class="underline mb-2"
|
||||
href="https://meet.jit.si/"
|
||||
>Start a Meeting with Jitsi!
|
||||
</a >
|
||||
|
||||
<p class="mb-2"> Difficulty rating: 🌶️/5
|
||||
</p>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div class="flex flex-col gap-8">
|
||||
<div class="rounded-lg border p-6">
|
||||
<h2 class="mb-4 text-2xl font-semibold" id="December">December</h2>
|
||||
<div>
|
||||
<p class="mb-2"> Try out Radicale as a privacy-friendly, open-source alternative to Google Calendar and Outlook!</p>
|
||||
<a
|
||||
class="underline mb-2"
|
||||
href="https://radicale.org/master.html#simple-5-minute-setup"
|
||||
>Setting up Radicale Tutorial!
|
||||
</a >
|
||||
|
||||
<p class="mb-2"> Difficulty rating: 🌶️🌶️🌶️🌶️🌶️/5
|
||||
</p>
|
||||
|
||||
</div>
|
||||
|
||||
<hr class="mb-4">
|
||||
<p class="mb-2"> Alternative: Proton Calendar</p>
|
||||
<a
|
||||
class="underline mb-2"
|
||||
href="https://calendar.proton.me/"
|
||||
>Switch to Proton Calendar!
|
||||
</a >
|
||||
|
||||
<p class="mb-2"> Difficulty rating: 🌶️/5
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<Footer />
|
||||
</main>
|
||||
</Layout>
|
||||
99
src/pages/projects/alternatives.astro
Normal file
@ -0,0 +1,99 @@
|
||||
---
|
||||
import Navbar from "../../components/Navbar";
|
||||
import Footer from "../../components/Footer";
|
||||
import Layout from "../../layouts/Layout.astro";
|
||||
import "../../styles/globals.css";
|
||||
|
||||
|
||||
import Card from "../../components/Card.astro";
|
||||
|
||||
---
|
||||
|
||||
<Layout>
|
||||
<main class="flex min-h-screen flex-col justify-between">
|
||||
<div>
|
||||
<Navbar client:load activePage="OurProjects" />
|
||||
<div class="pl-4 pr-4">
|
||||
<h1 class="pb-4 pt-4 text-3xl font-semibold">Big Tech Alternatives</h1>
|
||||
<p class="mb-4">Explore open-source and privacy-focused alternatives to popular big tech software.</p>
|
||||
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-8">
|
||||
<Card
|
||||
title="Browsers"
|
||||
bigTech="Chrome (Google)"
|
||||
alternatives={[
|
||||
{ name: 'Firefox', description: 'Privacy-focused browser.', url: 'https://www.mozilla.org/firefox' },
|
||||
]}
|
||||
bgClass="bg-blue-50"
|
||||
/>
|
||||
|
||||
<Card
|
||||
title="Cloud Storage"
|
||||
bigTech="Google Drive"
|
||||
alternatives={[
|
||||
{ name: 'Nextcloud', description: 'Self-hosted file sync and share.', url: 'https://nextcloud.com' }
|
||||
]}
|
||||
bgClass="bg-indigo-50"
|
||||
/>
|
||||
|
||||
<Card
|
||||
title="Email"
|
||||
bigTech="Gmail (Google)"
|
||||
alternatives={[
|
||||
{ name: 'ProtonMail', description: 'Encrypted email.', url: 'https://protonmail.com' },
|
||||
]}
|
||||
bgClass="bg-yellow-50"
|
||||
/>
|
||||
|
||||
<Card
|
||||
title="Maps"
|
||||
bigTech="Google Maps"
|
||||
alternatives={[
|
||||
{ name: 'OpenStreetMap', description: 'Community-driven maps.', url: 'https://www.openstreetmap.org' }
|
||||
]}
|
||||
bgClass="bg-teal-50"
|
||||
/>
|
||||
|
||||
<Card
|
||||
title="Messaging"
|
||||
bigTech="WhatsApp (Meta), Slack"
|
||||
alternatives={[
|
||||
{ name: 'Signal', description: 'Encrypted messaging (alternative to WhatsApp).', url: 'https://signal.org' },
|
||||
{ name: 'Element', description: 'Matrix-based chat (alternative to Slack).', url: 'https://element.io' }
|
||||
]}
|
||||
bgClass="bg-red-50"
|
||||
/>
|
||||
|
||||
<Card
|
||||
title="Search Engines"
|
||||
bigTech="Google Search"
|
||||
alternatives={[
|
||||
{ name: 'DuckDuckGo', description: 'Privacy-protecting search.', url: 'https://duckduckgo.com' },
|
||||
]}
|
||||
bgClass="bg-green-50"
|
||||
/>
|
||||
|
||||
<Card
|
||||
title="Social Media"
|
||||
bigTech="Twitter (X), Facebook (Meta)"
|
||||
alternatives={[
|
||||
{ name: 'Mastodon', description: 'Decentralized social network (alternative to Twitter).', url: 'https://joinmastodon.org' },
|
||||
]}
|
||||
bgClass="bg-purple-50"
|
||||
/>
|
||||
|
||||
<Card
|
||||
title="Video Platforms"
|
||||
bigTech="YouTube (Google)"
|
||||
alternatives={[
|
||||
{ name: 'PeerTube', description: 'Decentralized video hosting.', url: 'https://joinpeertube.org' },
|
||||
]}
|
||||
bgClass="bg-pink-50"
|
||||
/>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<Footer />
|
||||
</main>
|
||||
</Layout>
|
||||
47
src/pages/projects/bookclub.astro
Normal file
@ -0,0 +1,47 @@
|
||||
---
|
||||
import Navbar from "../../components/Navbar";
|
||||
import Footer from "../../components/Footer";
|
||||
import Layout from "../../layouts/Layout.astro";
|
||||
import "../../styles/globals.css";
|
||||
---
|
||||
|
||||
<Layout>
|
||||
<main class="flex min-h-screen flex-col justify-between">
|
||||
<div>
|
||||
<Navbar client:load activePage="OurProjects" />
|
||||
<div class="px-4">
|
||||
<h1 class="pb-4 pt-4 text-3xl font-semibold">Book Club</h1>
|
||||
<p class="mb-4">
|
||||
We read and discuss books about technology, power, and resistance. If
|
||||
you have book suggestions, fill out the interest form on our <a
|
||||
href="/"
|
||||
class="underline">website homepage</a
|
||||
> and let us know when we get in contact with you!
|
||||
</p>
|
||||
|
||||
<div class="flex flex-col gap-8">
|
||||
<div class="rounded-lg border p-6">
|
||||
<h2 class="mb-4 text-2xl font-semibold">Current Book</h2>
|
||||
<div>
|
||||
Race After Technology - Ruha Benjamin (see <a
|
||||
class="underline"
|
||||
href="https://www.dropbox.com/scl/fi/jnzvtiry7jn3xrts2n703/RAT-Discussion-Guide.pdf?rlkey=pq6ovaeydhcm8yi2u7lzzmiuj&e=2&dl=0"
|
||||
>discussion guide
|
||||
</a>)
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="rounded-lg border p-6">
|
||||
<h2 class="mb-4 text-2xl font-semibold">Past Books</h2>
|
||||
<ul class="list-disc pl-6">
|
||||
<li>Race After Technology - Ruha Benjamin</li>
|
||||
<li>Common Circuits - Luis Felipe R. Murillo</li>
|
||||
<li>Internet for the People - Ben Tarnoff</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<Footer />
|
||||
</main>
|
||||
</Layout>
|
||||
21
src/pages/projects/calendar.astro
Normal file
@ -0,0 +1,21 @@
|
||||
---
|
||||
import Navbar from "../../components/Navbar";
|
||||
import Footer from "../../components/Footer";
|
||||
import Layout from "../../layouts/Layout.astro";
|
||||
import "../../styles/globals.css";
|
||||
---
|
||||
|
||||
<Layout>
|
||||
<main class="flex min-h-screen flex-col justify-between">
|
||||
<div>
|
||||
<Navbar client:load activePage="Calendar" />
|
||||
<div class="pl-4 pr-4">
|
||||
<h1 class="pb-4 pt-4 text-3xl font-semibold">Calendar</h1>
|
||||
<div class="flex flex-col gap-4">
|
||||
<p class="mb-4">See what we're doing next!</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<Footer />
|
||||
</main>
|
||||
</Layout>
|
||||
19
src/pages/projects/pihole.astro
Normal file
@ -0,0 +1,19 @@
|
||||
---
|
||||
import Navbar from "../../components/Navbar";
|
||||
import Footer from "../../components/Footer";
|
||||
import Layout from "../../layouts/Layout.astro";
|
||||
import "../../styles/globals.css";
|
||||
---
|
||||
|
||||
<Layout>
|
||||
<main class="flex min-h-screen flex-col justify-between">
|
||||
<div>
|
||||
<Navbar />
|
||||
<div class="pl-4 pr-4">
|
||||
<h1 class="text-3xl font-semibold">Pihole</h1>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<Footer />
|
||||
</main>
|
||||
</Layout>
|
||||
44
src/pages/projects/zines.astro
Normal file
@ -0,0 +1,44 @@
|
||||
---
|
||||
import Navbar from "../../components/Navbar";
|
||||
import Footer from "../../components/Footer";
|
||||
import Layout from "../../layouts/Layout.astro";
|
||||
import { ZineGrid } from "../../components/zines/ZineGrid";
|
||||
import "../../styles/globals.css";
|
||||
---
|
||||
|
||||
<Layout>
|
||||
<main class="flex min-h-screen flex-col justify-between">
|
||||
<div>
|
||||
<Navbar client:load activePage="OurProjects" />
|
||||
<div class="px-4">
|
||||
<h1 class="pb-4 pt-4 text-3xl font-semibold">Zines</h1>
|
||||
<p class="mb-6">
|
||||
We create and share zines about technology, power, and resistance. You are welcome to download the printable version to fold and distribute!
|
||||
</p>
|
||||
|
||||
<ZineGrid client:load />
|
||||
</div>
|
||||
</div>
|
||||
<Footer />
|
||||
</main>
|
||||
</Layout>
|
||||
|
||||
<style>
|
||||
:global(.flipbook-container) {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
min-height: 520px;
|
||||
}
|
||||
|
||||
:global(.flipbook) {
|
||||
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.3);
|
||||
}
|
||||
|
||||
:global(.page) {
|
||||
background-color: white;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
</style>
|
||||