Compare commits

..

No commits in common. "main" and "main" have entirely different histories.
main ... main

40 changed files with 3793 additions and 7086 deletions

View file

@ -2,16 +2,17 @@
"name": "swabsite",
"image": "mcr.microsoft.com/devcontainers/base:ubuntu",
"features": {
"ghcr.io/devcontainers/features/node": {}
"ghcr.io/devcontainers-community/features/deno": {}
},
"containerUser": "vscode",
"containerEnv": {
"ASTRO_TELEMETRY_DISABLED": "true"
},
"postStartCommand": "deno task install",
"runArgs": ["--userns=keep-id", "--security-opt=label=disable"],
"customizations": {
"vscode": {
"extensions": [
"astro-build.astro-vscode"
]
"extensions": ["astro-build.astro-vscode"]
}
}
}
}

View file

@ -1,34 +0,0 @@
name: deploy
on:
push:
branches:
- main
workflow_dispatch:
env:
repo: website
git: git.swablab.de
url: git.swablab.de/${{ github.repository }}
token: ${{ secrets.SWABLAB_ORGA_PACKAGE_TOKEN }}
ASTRO_TELEMETRY_DISABLED: true
jobs:
deploy:
name: deploy
runs-on: docker
container:
image: docker:cli
env:
DOCKER_HOST: tcp://172.17.0.1:2375
steps:
- name: download
run: wget -O- https://${{ env.url }}/archive/main.tar.gz | tar -xz
- name: build
run: docker buildx build -f ${{ env.repo }}/Containerfile -t ${{ env.url }}:latest ${{ env.repo }}
- name: login
run: docker login -u token -p ${{ env.token }} ${{ env.git }}
- name: push
run: docker push ${{ env.git }}/${{ github.repository }}:latest

View file

@ -0,0 +1,53 @@
name: Build Astro
on: [push, workflow_dispatch]
env:
ASTRO_TELEMETRY_DISABLED: true
jobs:
check:
name: 🧪 Astro check
runs-on: docker
container:
image: node:lts
steps:
- uses: https://github.com/actions/checkout@v4
- uses: https://github.com/denoland/setup-deno@v2
with:
deno-version: v2.x
- run: deno task install
- run: deno task check
deploy:
name: 🚢 Deploy
runs-on: docker
container:
image: node:lts
if: github.ref == 'refs/heads/main'
needs: [check]
steps:
- uses: https://github.com/actions/checkout@v4
- uses: https://github.com/denoland/setup-deno@v2
with:
deno-version: v2.x
- run: deno task install
- run: deno task build
- name: build containerfile
id: build-image
uses: https://github.com/redhat-actions/buildah-build@v2
with:
image: website
tags: latest
containerfiles: |
./Containerfile
- name: Push to registry
uses: https://github.com/redhat-actions/push-to-registry@v2
with:
image: ${{ steps.build-image.outputs.image }}
tags: ${{ steps.build-image.outputs.tags }}
username: token
password: ${{ secrets.GITHUB_TOKEN }}
registry: ${{ github.server_url }}/${{ github.repository }}

View file

@ -1,5 +1,6 @@
{
"recommendations": [
"astro-build.astro-vscode"
"astro-build.astro-vscode",
"denoland.vscode-deno"
]
}
}

24
.vscode/tasks.json vendored
View file

@ -2,43 +2,35 @@
"version": "2.0.0",
"tasks": [
{
"label": "install",
"command": "npm install",
"type": "shell",
"problemMatcher": []
},
{
"label": "update",
"command": "npm update -S",
"label": "install/update",
"command": "deno task install",
"type": "shell",
"problemMatcher": []
},
{
"label": "dev",
"command": "npm run dev",
"command": "deno task dev",
"type": "shell",
"problemMatcher": []
},
{
"label": "check",
"command": "npm run check",
"command": "deno task check",
"type": "shell",
"problemMatcher": []
},
{
"label": "preview",
"command": "npm run preview",
"command": "deno task preview",
"type": "shell",
"problemMatcher": [],
"dependsOn": [
"build"
]
"dependsOn": ["build"]
},
{
"label": "build",
"command": "npm run build",
"command": "deno task build",
"type": "shell",
"problemMatcher": []
}
]
}
}

View file

@ -1,13 +1,6 @@
FROM docker.io/library/node AS build
WORKDIR /app
COPY . .
ENV ASTRO_TELEMETRY_DISABLED=true
RUN npm install
RUN npm run build
FROM ghcr.io/swablab/documents:latest AS documents
FROM git.swablab.de/swablab/documents AS documents
FROM docker.io/nginxinc/nginx-unprivileged:alpine-slim
FROM docker.io/nginxinc/nginx-unprivileged:latest
COPY ./nginx.conf /etc/nginx/conf.d/default.conf
COPY --from=build /app/dist /usr/share/nginx/html
COPY --from=documents / /usr/share/nginx/html/docs
COPY ./dist /usr/share/nginx/html
COPY --from=documents / /usr/share/nginx/html/docs

16
README.md Normal file
View file

@ -0,0 +1,16 @@
# swablab.de
[![Build Astro CI](https://github.com/swablab/website/actions/workflows/main.yml/badge.svg?branch=main)](https://github.com/swablab/website/actions/workflows/main.yml)
These are the source files for the page published at https://swablab.de.
Powered by [Astro](https://astro.build)
# Installation
We recommend [deno](https://deno.com/) as the package manager. To install all
required packages, execute `deno task install`.
Afterwards, you can develop with `deno task dev` and build with
`deno task build`. It is recommended to use VSCode as your editor, as all tasks
can be executed easily within VSCode.

View file

@ -1,5 +1,5 @@
import sitemap from "@astrojs/sitemap"
import tailwindcss from "@tailwindcss/vite"
import tailwind from "@astrojs/tailwind"
import { defineConfig, passthroughImageService } from "astro/config"
export default defineConfig({
@ -8,14 +8,9 @@ export default defineConfig({
server: {
host: true,
},
integrations: [sitemap()],
integrations: [tailwind(), sitemap()],
image: {
domains: ["directus.swablab.de", "files.mastodon.social"],
service: passthroughImageService(),
},
vite: {
plugins: [
tailwindcss(),
],
},
})

8
deno.json Normal file
View file

@ -0,0 +1,8 @@
{
"fmt": {
"options": {
"semiColons": false,
"indentWidth": 2
}
}
}

3023
deno.lock generated Normal file

File diff suppressed because it is too large Load diff

View file

@ -17,14 +17,8 @@ server {
internal;
}
location /todo {
return 302 https://directus.swablab.de/admin/content/tasks_general;
}
location /discord {
return 302 https://discord.gg/A4grfc5Vzm;
}
location /linux {
return 302 https://wiki.swablab.de/books/it/page/linux-installationsparty;
return 301 https://discord.gg/sZbmJdGkMQ;
}
location / {

6770
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -2,6 +2,7 @@
"name": "@swablab/website",
"private": true,
"scripts": {
"install": "deno install -q",
"check": "astro check",
"dev": "astro dev",
"build": "astro build",
@ -9,15 +10,18 @@
},
"dependencies": {
"@astrojs/check": "^0.9.4",
"@astrojs/sitemap": "^3.3.1",
"@fontsource-variable/ubuntu-sans": "^5.2.7",
"@iconify-json/ph": "^1.2.2",
"@iconify/tailwind4": "^1.0.6",
"@tailwindcss/typography": "^0.5.16",
"@tailwindcss/vite": "^4.1.5",
"astro": "^5.7.12",
"daisyui": "^5.0.35",
"tailwindcss": "^4.0.14"
"@astrojs/sitemap": "^3.2.1",
"@astrojs/tailwind": "^5.1.3",
"@fontsource-variable/ubuntu-sans": "^5.1.0",
"@iconify-json/ph": "^1.2.1",
"@iconify/tailwind": "^1.1.3",
"@tailwindcss/typography": "^0.5.15",
"@types/alpinejs": "^3.13.11",
"alpinejs": "^3.14.6",
"astro": "^5.0.3",
"daisyui": "^4.12.14",
"tailwindcss": "^3.4.16",
"typescript": "^5.7.2"
},
"prettier": {
"tabWidth": 2,

View file

Before

Width:  |  Height:  |  Size: 6 KiB

After

Width:  |  Height:  |  Size: 6 KiB

50
public/logo_color.svg Normal file
View file

@ -0,0 +1,50 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg width="100%" height="100%" viewBox="0 0 1080 1080" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" xmlns:serif="http://www.serif.com/" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:2.5;">
<g transform="matrix(1,0,0,1,-2281.57,-1257.11)">
<g id="Lightmode-no-text" serif:id="Lightmode no text" transform="matrix(1,0,0,1,-4466.43,123.108)">
<rect x="6748" y="1134" width="1080" height="1080" style="fill:none;"/>
<g transform="matrix(1.24839,0,0,1.24839,-749.242,-387.363)">
<g transform="matrix(1,0,0,1,-849.9,42.4178)">
<path d="M7200.48,1795.34C7204.27,1796.68 7207.24,1799.68 7208.55,1803.48C7214.69,1821.27 7232.49,1872.93 7241.19,1898.18C7244.23,1907 7251.7,1913.55 7260.84,1915.4C7279.24,1919.13 7310.73,1925.52 7330.82,1929.6C7341.98,1931.86 7353.33,1926.66 7358.9,1916.72C7366.21,1903.67 7376.32,1885.62 7383.58,1872.65C7389.62,1861.86 7393.28,1849.91 7394.31,1837.59C7394.99,1829.36 7395.8,1819.69 7396.49,1811.36C7397.42,1800.24 7406.61,1791.61 7417.77,1791.39C7431.82,1791.12 7448.27,1790.8 7448.27,1790.8C7473.78,1772.72 7496.06,1750.44 7514.14,1724.92L7506.91,1678.37C7513.47,1665.76 7518.92,1652.6 7523.2,1639.04L7561.23,1611.24C7566.49,1580.41 7566.49,1548.91 7561.23,1518.08L7523.2,1490.27C7518.92,1476.72 7513.47,1463.56 7506.91,1450.94L7514.14,1404.39C7496.06,1378.87 7473.78,1356.6 7448.27,1338.52L7401.72,1345.75C7389.1,1339.19 7375.94,1333.74 7362.39,1329.45L7334.58,1291.43C7303.75,1286.17 7272.25,1286.17 7241.42,1291.43L7213.61,1329.45C7200.06,1333.74 7186.9,1339.19 7174.28,1345.75L7127.73,1338.52C7102.22,1356.6 7079.94,1378.87 7061.86,1404.39L7069.09,1450.94C7062.53,1463.56 7057.08,1476.72 7052.8,1490.27L7014.77,1518.08C7009.51,1548.91 7009.51,1580.41 7014.77,1611.24L7052.8,1639.04C7057.08,1652.6 7062.53,1665.76 7069.09,1678.37L7061.86,1724.92C7079.94,1750.44 7102.22,1772.72 7127.73,1790.8L7174.28,1783.57C7184.89,1789.08 7190.81,1792 7200.48,1795.34ZM7288,1439.49C7357.71,1439.49 7414.3,1496.09 7414.3,1565.79C7414.3,1635.5 7357.71,1692.09 7288,1692.09C7218.29,1692.09 7161.7,1635.5 7161.7,1565.79C7161.7,1496.09 7218.29,1439.49 7288,1439.49Z" style="fill:rgb(163,255,241);"/>
</g>
<g transform="matrix(1,0,0,1,-849.728,-3.45885)">
<path d="M7260.8,1855.8L7347.85,1876.46" style="fill:none;stroke:rgb(61,61,61);stroke-width:22.36px;"/>
</g>
<g transform="matrix(1,0,0,1,-847.9,0)">
<path d="M7276.11,1906.48L7323.66,1917.98" style="fill:none;stroke:rgb(61,61,61);stroke-width:22.36px;stroke-linejoin:miter;"/>
</g>
<g transform="matrix(1,0,0,1,2474.6,-129.288)">
<circle cx="3963.5" cy="1737.5" r="126.3" style="fill:none;stroke:rgb(61,61,61);stroke-width:22.31px;stroke-miterlimit:1.5;"/>
</g>
<g transform="matrix(1,0,0,1,2474.6,-129.288)">
<path d="M4021.69,1896.02C4032.02,1892.93 4043.63,1887.14 4052.61,1880.39L4089.23,1906.33C4105.61,1894.13 4120.13,1879.61 4132.33,1863.23L4106.39,1826.61C4116.21,1810.87 4123.36,1793.6 4127.55,1775.53L4171.78,1767.98C4174.74,1747.77 4174.74,1727.23 4171.78,1707.02L4127.55,1699.48C4123.36,1681.4 4116.21,1664.13 4106.39,1648.39L4132.33,1611.77C4120.13,1595.39 4105.61,1580.87 4089.23,1568.67L4052.61,1594.61C4036.87,1584.79 4019.6,1577.64 4001.53,1573.45L3993.98,1529.22C3973.77,1526.26 3953.23,1526.26 3933.02,1529.22L3925.47,1573.45C3907.4,1577.64 3890.13,1584.79 3874.39,1594.61L3837.77,1568.67C3821.39,1580.87 3806.87,1595.39 3794.67,1611.77L3820.61,1648.39C3810.79,1664.13 3803.64,1681.4 3799.45,1699.48L3755.22,1707.02C3752.26,1727.23 3752.26,1747.77 3755.22,1767.98L3799.45,1775.53C3803.64,1793.6 3810.79,1810.87 3820.61,1826.61L3794.67,1863.23C3806.87,1879.61 3821.39,1894.13 3837.77,1906.33L3874.39,1880.39C3883.06,1884.99 3896.11,1891.64 3904.67,1893.84L3921.92,1925.54L4026.94,1949.95" style="fill:none;stroke:rgb(61,61,61);stroke-width:22.31px;stroke-miterlimit:1.5;"/>
</g>
</g>
<g transform="matrix(0.418992,0,0,0.466271,4240.37,-631.785)">
<g transform="matrix(1.22943,0,0,1.10477,-1501.56,-441.15)">
<path d="M7070.03,4727.19C7062.51,4730.97 7054.03,4733.09 7045.06,4733.09C7014.28,4733.09 6989.29,4708.1 6989.29,4677.32C6989.29,4646.54 7014.28,4621.55 7045.06,4621.55C7070.73,4621.55 7092.37,4638.93 7098.85,4662.55C7081.1,4674.79 7069.46,4695.26 7069.46,4718.42C7069.46,4721.39 7069.65,4724.32 7070.03,4727.19Z" style="fill:rgb(102,102,102);"/>
</g>
<g transform="matrix(1.22943,0,0,1.10477,-1501.56,-441.15)">
<path d="M7102.94,4776.9L7102.91,4780.95C7102.91,4780.95 7080.42,4787.8 7063.75,4804.47C7052.4,4815.81 7032.47,4841.04 7032.47,4874.18C7032.47,4899.4 7032.47,4879.97 7032.47,4879.97C6988.12,4878.21 6952.83,4866.44 6952.83,4866.44C6952.83,4866.44 6952.83,4842.95 6952.83,4816.79C6952.83,4798.22 6960.21,4780.42 6973.34,4767.29C6986.46,4754.16 7004.27,4746.79 7022.83,4746.79C7037.39,4746.79 7052.73,4746.79 7067.28,4746.79C7070.18,4746.79 7073.07,4746.97 7075.92,4747.32C7081.76,4759.69 7091.23,4770 7102.94,4776.9Z" style="fill:rgb(102,102,102);"/>
</g>
</g>
<g transform="matrix(0.418992,0,0,0.466271,4240.37,-631.785)">
<g transform="matrix(-1.22943,0,0,1.10477,16049,-441.15)">
<path d="M7102.94,4776.9L7102.91,4780.95C7102.91,4780.95 7080.42,4787.8 7063.75,4804.47C7052.4,4815.81 7032.47,4841.04 7032.47,4874.18C7032.47,4899.4 7032.47,4879.97 7032.47,4879.97C6988.12,4878.21 6952.83,4866.44 6952.83,4866.44C6952.83,4866.44 6952.83,4842.95 6952.83,4816.79C6952.83,4798.22 6960.21,4780.42 6973.34,4767.29C6986.46,4754.16 7004.27,4746.79 7022.83,4746.79C7037.39,4746.79 7052.73,4746.79 7067.28,4746.79C7070.18,4746.79 7073.07,4746.97 7075.92,4747.32C7081.76,4759.69 7091.23,4770 7102.94,4776.9Z" style="fill:rgb(102,102,102);"/>
</g>
<g transform="matrix(1.22943,0,0,1.10477,-1501.56,-441.15)">
<path d="M7175.79,4662.61C7182.25,4638.96 7203.91,4621.55 7229.6,4621.55C7260.38,4621.55 7285.37,4646.54 7285.37,4677.32C7285.37,4708.1 7260.38,4733.09 7229.6,4733.09C7220.59,4733.09 7212.07,4730.95 7204.54,4727.15C7204.9,4724.29 7205.09,4721.38 7205.09,4718.42C7205.09,4695.29 7193.49,4674.86 7175.79,4662.61Z" style="fill:rgb(102,102,102);"/>
</g>
</g>
<g transform="matrix(0.418992,0,0,0.466271,4240.37,-631.785)">
<g transform="matrix(1.29452,0,0,1.16326,-3371.22,3043.8)">
<circle cx="8222.71" cy="1485.33" r="52.965" style="fill:rgb(128,128,128);"/>
</g>
<g transform="matrix(1.22943,0,0,0.993178,-2937.04,3274.16)">
<path d="M8397.09,1687.6C8397.09,1660.4 8387.38,1634.31 8370.08,1615.07C8352.79,1595.83 8329.33,1585.02 8304.88,1585.02L8304.87,1585.02C8280.41,1585.02 8256.95,1595.83 8239.66,1615.07C8222.37,1634.31 8212.65,1660.4 8212.65,1687.6L8212.65,1718.12C8212.65,1718.12 8255.69,1733.08 8304.87,1733.08C8354.06,1733.08 8397.09,1718.12 8397.09,1718.12L8397.09,1687.6Z" style="fill:rgb(128,128,128);"/>
</g>
</g>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 7.4 KiB

5
public/test/me Normal file
View file

@ -0,0 +1,5 @@
{
"data": {
"id": "user1"
}
}

7
public/test/presence Normal file
View file

@ -0,0 +1,7 @@
{
"data": {
"id": 1,
"last": "2024-05-08T18:00:00",
"next": "2024-05-08T18:00:00"
}
}

25
public/test/task Normal file
View file

@ -0,0 +1,25 @@
{
"data": {
"id": "task",
"status": "in_progress",
"title": "title 1",
"date_due": "2024-01-01T12:00:00",
"labels": [
"label1"
],
"description": "description 1",
"priority": "high",
"responsibles": [
{
"directus_users_id": {
"id": "user1"
}
},
{
"directus_users_id": {
"id": "user2"
}
}
]
}
}

37
public/test/tasks_general Normal file
View file

@ -0,0 +1,37 @@
{
"data": [
{
"id": "task",
"status": "in_progress",
"title": "title1",
"date_due": "2024-01-01T12:00:00",
"labels": [
"label1"
],
"description": "description1",
"priority": "high",
"responsibles": [
{
"directus_users_id": {
"id": "user1"
}
},
{
"directus_users_id": {
"id": "user2"
}
}
]
},
{
"id": "task",
"status": "in_progress",
"title": "title2",
"date_due": null,
"labels": [],
"description": "description2",
"priority": "medium",
"responsibles": []
}
]
}

12
public/test/users Normal file
View file

@ -0,0 +1,12 @@
{
"data": [
{
"id": "user1",
"first_name": "first_name1"
},
{
"id": "user2",
"first_name": "first_name2"
}
]
}

View file

@ -34,7 +34,7 @@ const { name, image, link, small } = Astro.props
<span class="card-title">{name}</span>
)
}
<p class="text-lg">
<p>
<slot />
</p>
</div>

View file

@ -1,18 +0,0 @@
---
export interface Props {
title: string
icon: string
}
const { title, icon }: Props = Astro.props
---
<div class="collapse collapse-arrow join-item border-base-300 border">
<input type="radio" name="collapse" />
<div class="collapse-title font-semibold text-left">
<span class={icon + " align-middle"}></span>
<span class="ml-1">{title}</span>
</div>
<div class="collapse-content text-left">
<slot />
</div>
</div>

View file

@ -71,7 +71,7 @@ function replaceEmojis(content: string) {
</figure>
)}
<div class="card-body text-left text-lg">
<div class="card-body text-left">
<h2 class="card-title justify-between">
<a href={post.url}>@swablab</a>
<time class="text-xs opacity-50">

View file

@ -5,7 +5,6 @@ import DirectusImg from "./DirectusImg.astro"
type Member = {
firstname: string
image?: string
chairman?: boolean
}
const members = await directus<Member[]>("items/members?sort=firstname")
---
@ -25,59 +24,27 @@ const members = await directus<Member[]>("items/members?sort=firstname")
</div>
</div>
<div class="text-2xl md:text-4xl pt-8">Vorstand</div>
<div
class="flex flex-row flex-wrap gap-6 justify-evenly sm:justify-center text-base"
class="flex flex-row flex-wrap gap-6 justify-evenly sm:justify-center text-base pt-8"
>
{
members
.filter((m) => m.chairman)
.map((member) => (
<div>
<DirectusImg
src={
member.image != null
? member.image
: "a8f48962-9f0e-40e6-abd2-e932aa9dea2e"
}
widths={[200]}
format="webp"
alt={"Profilbild von " + member.firstname}
class="rounded-full w-[100px] h-[100px]"
/>
members.map((member) => (
<div>
<DirectusImg
src={
member.image != null
? member.image
: "a8f48962-9f0e-40e6-abd2-e932aa9dea2e"
}
widths={[200]}
format="webp"
alt={"Profilbild von " + member.firstname}
class="rounded-full w-[100px] h-[100px]"
/>
<p>{member.firstname}</p>
</div>
))
}
</div>
<div class="text-2xl md:text-4xl pt-8">Mitglieder</div>
<div
class="flex flex-row flex-wrap gap-6 justify-evenly sm:justify-center text-base"
>
{
members
.filter((m) => !m.chairman)
.map((member) => (
<div>
<DirectusImg
src={
member.image != null
? member.image
: "a8f48962-9f0e-40e6-abd2-e932aa9dea2e"
}
widths={[200]}
format="webp"
alt={"Profilbild von " + member.firstname}
class="rounded-full w-[100px] h-[100px]"
/>
<p>{member.firstname}</p>
</div>
))
<p>{member.firstname}</p>
</div>
))
}
<div>

View file

@ -7,7 +7,7 @@ const { title, jumpId }: Props = Astro.props
---
<div class="text-center p-8 space-y-8 even:bg-base-200">
<a class="invisible relative -top-24" id={jumpId}></a>
<a hidden class="block invisible relative -top-20" id={jumpId}></a>
<div class="text-3xl md:text-5xl">
<a href={"#" + jumpId}>{title}</a>
</div>

View file

@ -1,7 +1,33 @@
export async function directus<T>(path: string): Promise<T> {
return await fetch(`https://directus.swablab.de/${path}`)
const env = (import.meta as unknown as {
env: {
DEV: boolean
SSR: boolean
}
}).env
export async function directus<T>(
path: string,
method: string = "GET",
body: string | null = null,
): Promise<T> {
return await fetch(
env.DEV && !env.SSR
? `/test/${path.split("/").at(-1)}`
: `https://directus.swablab.de/${path}`,
{
method,
credentials: "include",
headers: {
"Content-Type": "application/json",
},
body,
},
)
.then((res) => res.json())
.then((res) => res.data)
.then((res) => {
if (res.errors) throw res.errors[0].message
return res.data
})
}
export function formatDate(
@ -32,3 +58,18 @@ export const documents = {
"Werkstatt-AGB": "/docs/werkstatt-agb.pdf",
"Werkstatt-Regeln": "/docs/werkstatt-regeln.pdf",
}
export type Task = {
id: string | undefined
title: string
status: string
date_due?: string
priority: string
description: string
responsibles: {
directus_users_id: {
id: string
first_name: string
}
}[]
}

View file

@ -1,16 +1,16 @@
---
import "../style.css"
import "../style.css";
export interface Props {
title?: string
description?: string
title?: string;
description?: string;
}
const { title } = Astro.props
const { title } = Astro.props;
const titleFull = title == null ? "swablab e.V." : title + " | swablab e.V."
const titleFull = title == null ? "swablab e.V." : title + " | swablab e.V.";
const description =
"swablab e.V. in Freudenstadt - die offene Werkstatt für alle ambitionierten Hobby-Schreiner, Bastler, Tüftler, Elektroniker und vieles mehr."
"swablab e.V. in Freudenstadt - die offene Werkstatt für alle ambitionierten Hobby-Schreiner, Bastler, Tüftler, Elektroniker und vieles mehr.";
---
<html lang="de-DE" class="scroll-smooth">
@ -29,6 +29,13 @@ const description =
<title>{titleFull}</title>
<link rel="icon" type="image/x-icon" href="/favicon.ico" />
<script
is:inline
defer
data-domain="swablab.de"
src="https://analytics.swablab.de/js/plausible.outbound-links.js"
></script>
</head>
<body class="min-h-screen flex flex-col">
<slot />

View file

@ -28,9 +28,9 @@ const social = [
"https://www.printables.com/social/103546-swablab-ev/about",
),
entry(
"Forgejo",
"icon-[ph--git-branch]",
"https://git.swablab.de/explore/repos",
"GitHub",
"icon-[ph--github-logo-duotone]",
"https://github.com/swablab",
),
]
@ -47,25 +47,6 @@ const downloads = [
documents.Mitgliedsantrag,
),
]
const contact = [
entry(
"Friedrichstr. 17, 72250 Freudenstadt",
"icon-[ph--house-line-duotone]",
"https://swablab.de/lab",
),
entry(
"Katharinenstr. 1, 72250 Freudenstadt",
"icon-[ph--mailbox-duotone]",
"https://swablab.de/imprint",
),
entry(
"info@swablab.de",
"icon-[ph--envelope-simple-duotone]",
"mailto:info@swablab.de",
),
entry("+49 15679 232971", "icon-[ph--phone-duotone]", "tel:+4915679232971"),
]
---
<div class="bg-base-200 border-t border-base-300">
@ -103,17 +84,24 @@ const contact = [
</nav>
<nav class="w-full">
<header class="footer-title border-b w-full">Kontakt</header>
{
contact.map((e) => (
<a
class="link link-hover link-primary flex gap-1 items-center"
href={e.link}
>
<span class={e.icon} />
{e.name}
</a>
))
}
<div class="flex gap-1 items-center">
<span class="icon-[ph--map-pin-duotone]"></span>
Katharinenstr. 1, 72250 Freudenstadt
</div>
<a
class="link link-hover link-primary flex gap-1 items-center"
href="mailto:info@swablab.de"
>
<span class="icon-[ph--envelope-simple-duotone]"></span>
info@swablab.de
</a>
<a
class="link link-hover link-primary flex gap-1 items-center"
href="tel:+4915679232971"
>
<span class="icon-[ph--phone-duotone]"></span>
+49 15679 232971
</a>
</nav>
</footer>

View file

@ -1,5 +1,4 @@
---
import Logo from "./Logo.svg"
import Presence from "./Presence.astro"
const links = [
@ -15,14 +14,10 @@ const links = [
<nav class="fixed top-0 navbar z-30 glass bg-base-100/30">
<div class="navbar-start">
<ul class="menu menu-horizontal p-0">
<li>
<a class="text-xl" href="/">
<Logo class="w-8 h-8" />
<span>swablab</span>
</a>
</li>
</ul>
<a class="btn btn-ghost text-xl font-normal" href="/">
<img class="w-8 h-8" src="/logo.svg" alt="swablab logo" />
<span>swablab</span></a
>
</div>
<div class="navbar-center hidden lg:flex">
<ul class="menu menu-horizontal p-0">
@ -39,12 +34,6 @@ const links = [
</li>
))
}
<li>
<a class="text-black bg-primary" href="https://wiki.swablab.de">
<span class="w-5 h-5 icon-[ph--notebook-duotone]"></span>
wiki
</a>
</li>
</ul>
</div>
<div class="navbar-end">
@ -61,12 +50,6 @@ const links = [
</li>
))
}
<li>
<a class="text-primary" href="https://wiki.swablab.de">
<span class="w-5 h-5 icon-[ph--notebook-duotone]"></span>
wiki
</a>
</li>
</ul>
</details>
</div>

View file

@ -1,13 +1,13 @@
<div id="presence" class="hidden">
<div class="xl:hidden">
<div class="md:hidden">
<div class="tooltip tooltip-left">
<button class="btn btn-square">
<button class="btn btn-square font-normal">
<span class="icon-[ph--door-open-duotone] w-6 h-6"></span>
</button>
</div>
</div>
<div class="hidden xl:flex">
<button class="btn">
<div class="hidden md:flex">
<button class="btn font-normal">
<span id="presence-text"></span>
<span class="icon-[ph--door-open-duotone] w-6 h-6"></span>
</button>

View file

@ -82,7 +82,7 @@ import Page from "../layouts/Page.astro"
],
[
"Sommer 2024",
`Neben unserem Instagram-Account werden jetzt Neuigkeiten und Projekte auch auf Mastodon (@swablab@mastodon.social) geposted.`,
`Neben unserem Instagram-Account werden jetzt Neuigkeiten und Projekte auch auf Mastodon (@swablab) geposted.`,
],
[
"Herbst 2024",

View file

@ -14,11 +14,11 @@ import Page from "../layouts/Page.astro"
kannst du an folgendes Konto deinen Spendenbeitrag überweisen:
</Text>
<div class="stats shadow bg-base-300">
<div class="stats shadow">
<div class="stat">
<div class="stat-title text-xl">IBAN: DE18 6039 1310 0125 6340 05</div>
<div class="stat-title text-xl">BIC: GENODES1VBH</div>
<div class="stat-title text-xl">Bank: Volksbank in der Region</div>
<div class="stat-title">IBAN: DE18 6039 1310 0125 6340 05</div>
<div class="stat-title">BIC: GENODES1VBH</div>
<div class="stat-title">Bank: Volksbank in der Region</div>
</div>
</div>

View file

@ -15,8 +15,7 @@ Telefon: [+49 15679 232971](tel:+4915679232971)
**Vertreten durch**\
Fabian Haas\
Manuel Knodel\
Bastian Wittke
Manuel Knodel
**Registereintrag**\
Amtsgericht Stuttgart\

View file

@ -24,6 +24,17 @@ import Page from "../layouts/Page.astro"
<span class="icon-[ph--arrow-circle-down-duotone] h-16 w-16"></span>
</a>
<div class="text-center p-8 space-y-8 bg-secondary">
<div class="text-3xl md:text-5xl">Info für Besucher!</div>
<div class="max-w-4xl mx-auto flex flex-col gap-4">
Wir sind umgezogen! Du findest uns jetzt in der
<Link
text="Friedrichstraße 17 in Freudenstadt!"
href="https://www.openstreetmap.org/node/12119224010"
/>
</div>
</div>
<Section title="Offene Werkstatt?" jumpId="start">
<DirectusImg
src="753d211b-8b28-42cb-8ddd-0777911b3511"
@ -50,14 +61,6 @@ import Page from "../layouts/Page.astro"
</Text>
</Section>
<Section title="Was gibt's neues?" jumpId="news">
<Mastodon />
</Section>
<Section title="Unsere Sponsoren" jumpId="sponsors">
<Sponsors />
</Section>
<Section title="Was interessiert dich?" jumpId="services">
<Card
name="Über uns"
@ -109,6 +112,14 @@ import Page from "../layouts/Page.astro"
</Card>
</Section>
<Section title="Was gibt's neues?" jumpId="news">
<Mastodon />
</Section>
<Section title="Unsere Sponsoren" jumpId="sponsors">
<Sponsors />
</Section>
<div class="fixed bottom-4 left-4 flex">
<a
class="btn btn-square btn-ghost z-10 discord-left"

View file

@ -24,11 +24,11 @@ import Page from "../layouts/Page.astro"
oder ihn an folgende Adresse schicken:
</Text>
<div class="stats shadow bg-base-300">
<div class="stats shadow">
<div class="stat">
<div class="stat-value">swablab e.V.</div>
<div class="stat-title text-xl">Katharinenstr. 1</div>
<div class="stat-title text-xl">72250 Freudenstadt</div>
<div class="stat-title">Katharinenstr. 1</div>
<div class="stat-title">72250 Freudenstadt</div>
</div>
</div>
</Section>

View file

@ -1,9 +1,7 @@
---
import Card from "../components/Card.astro"
import Collapse from "../components/Collapse.astro"
import Contact from "../components/Contact.astro"
import Gallery from "../components/Gallery.astro"
import Link from "../components/Link.astro"
import Map from "../components/Map.astro"
import Section from "../components/Section.astro"
import Text from "../components/Text.astro"
@ -93,32 +91,6 @@ import Page from "../layouts/Page.astro"
<Map />
</Section>
<Section title="Anreise" jumpId="trips">
<div class="join join-vertical bg-base-100">
<Collapse title="per Auto" icon="icon-[ph--car-duotone]">
Parken kannst du in den benachbarten Straßen auf ausgewiesenen
Parkplätzen sowie auf dem Kasernenplatz vor dem Rathaus (dort gibt es
auch E-Ladestationen). Einige Parkplätze sind Montag bis Freitag bis 19
Uhr kostenpflichtig.
</Collapse>
<Collapse title="per Bus/Bahn" icon="icon-[ph--train-duotone]">
Die Bushaltestelle der Martin-Luther-Straße ist zwei Straßen weiter,
sonst ist auch der ZOB in der Nähe. Direkt neben dem ZOB befindet sich
der Freudenstädter Stadtbahnhof.
</Collapse>
<Collapse title="per Fahrrad" icon="icon-[ph--bicycle-duotone]">
Fahrradständer sind vor dem Intersport Glaser sowie auf dem
Kasernenplatz vor dem Rathaus.
</Collapse>
<Collapse title="per Flugzeug" icon="icon-[ph--airplane-duotone]">
Hierfür empfehlen wir die <Link
text="Anreise-Seite von Freudenstadt"
href="https://www.freudenstadt.de/anfahrt"
/>.
</Collapse>
</div>
</Section>
<Contact>
<Text>
Egal, ob du an 3D-Druck, Elektronik, CNC-Arbeiten oder anderen Projekten

207
src/pages/todo-edit.astro Normal file
View file

@ -0,0 +1,207 @@
---
import Base from "../layouts/Base.astro"
const statuses = [
{ id: "not_started", title: "Nicht gestartet" },
{ id: "in_progress", title: "In Arbeit" },
{ id: "hold", title: "Wartend" },
{ id: "done", title: "Abgeschlossen" },
]
const priorities = [
{ id: "low", title: "Niedrig" },
{ id: "normal", title: "Normal" },
{ id: "high", title: "Hoch" },
]
---
<Base title="Todo">
<div x-data="task" x-cloak>
<div class="navbar glass">
<div class="navbar-start">
<a class="btn btn-ghost text-xl">todo</a>
</div>
<div class="navbar-end space-x-2">
<a class="btn btn-success btn-square" x-on:click="submit()">
<span class="icon-[ph--floppy-disk] w-6 h-6"></span>
</a>
<a class="btn btn-error btn-square" href="/todo">
<span class="icon-[ph--x] w-6 h-6"></span>
</a>
</div>
</div>
<div x-show="error" class="p-4 flex flex-col space-y-4">
<div
x-show="!error.includes('permission to access collection')"
class="alert alert-error"
>
<span x-text="error"></span>
</div>
<a
x-show="error.includes('permission to access collection')"
class="btn btn-primary"
href="https://directus.swablab.de/auth/login/zitadel?redirect=https://swablab.de/todo"
>
Klicke hier, um dich anzumelden
</a>
</div>
<div class="drawer">
<input id="drawer" type="checkbox" class="drawer-toggle" />
<div class="drawer-content">
<div class="p-4 grid md:grid-cols-3 gap-4">
<input x-model="title" class="input input-bordered md:col-span-3" />
<label class="form-control">
<div class="label">Status</div>
<select x-model="status" class="select select-bordered">
{
statuses.map((status) => (
<option value={status.id}>{status.title}</option>
))
}
</select>
</label>
<label class="form-control">
<div class="label">Priorität</div>
<select x-model="priority" class="select select-bordered">
{
priorities.map((prio) => (
<option value={prio.id}>{prio.title}</option>
))
}
</select>
</label>
<label class="form-control">
<div class="label">Fälligkeitdatum</div>
<input
x-model="date_due"
class="input input-bordered"
type="date"
/>
</label>
<div class="form-control md:col-span-3">
<div class="label space-x-2 justify-start">
<span>Verantwortliche</span>
<label for="drawer" class="btn btn-sm btn-primary btn-square">
+
</label>
</div>
<div class="flex space-x-2">
<template x-for="res in responsibles">
<button
class="btn"
x-on:click="responsibles = responsibles.filter(x => x != res)"
x-text="users.find(u => u.id == res)?.first_name ?? res"
>
</button>
</template>
</div>
</div>
<label class="form-control md:col-span-3 h-64">
<div class="label">Beschreibung</div>
<textarea
x-model="description"
class="textarea textarea-bordered md:col-span-3 h-64"
>
</textarea>
</label>
</div>
</div>
<div class="drawer-side">
<label for="drawer" class="drawer-overlay"></label>
<ul class="menu p-4 w-80 min-h-full bg-base-200 text-base-content">
<template x-for="user in users">
<li>
<a
x-on:click="responsibles.indexOf(user.id) == -1 && responsibles.push(user.id)"
x-text="user.first_name"
>
</a>
</li>
</template>
</ul>
</div>
</div>
</div>
</Base>
<script>
import Alpine from "alpinejs"
import { directus, Task } from "../helper"
Alpine.data("task", () => ({
id: globalThis.location.search.replace("?", ""),
title: "",
status: "not_started",
date_due: "",
priority: "normal",
description: "",
responsibles: [],
users: [],
error: "",
init() {
directus<{ id: string; first_name: string }[]>(
`users?fields=id,first_name&filter[provider][_neq]=default`,
).then(
(res) =>
(this.users = res.sort((a, b) =>
a.first_name.localeCompare(b.first_name),
)),
)
if (this.id != "") {
directus<Task>(
`items/tasks_general/${this.id}?fields=*,responsibles.directus_users_id.id`,
)
.then((res) => {
this.title = res.title
this.status = res.status
this.date_due = res.date_due?.substring(0, 10) ?? ""
this.priority = res.priority
this.description = res.description
this.responsibles = res.responsibles.map(
(x) => x.directus_users_id.id,
)
})
.catch((err) => (this.error = err))
}
},
submit() {
const task = {
id: this.id,
title: this.title,
status: this.status,
date_due: this.date_due != "" ? this.date_due : null,
priority: this.priority,
description: this.description,
responsibles: this.responsibles.map(
(r: { directus_users_id: string }) => ({
directus_users_id: r,
}),
),
}
if (this.id != "") {
directus(
`items/tasks_general/${this.id}`,
"PATCH",
JSON.stringify(task),
).then((_) => (document.location.href = "/todo"))
} else {
directus(`items/tasks_general`, "POST", JSON.stringify(task)).then(
(_) => (document.location.href = "/todo"),
)
}
},
}))
Alpine.start()
</script>

133
src/pages/todo.astro Normal file
View file

@ -0,0 +1,133 @@
---
import Base from "../layouts/Base.astro"
const statuses = [
{ id: "not_started", title: "Nicht gestartet" },
{ id: "in_progress", title: "In Arbeit" },
{ id: "hold", title: "Wartend" },
]
---
<Base title="Todo">
<div x-data="kanban" x-cloak>
<div class="navbar glass">
<div class="navbar-start">
<a class="btn btn-ghost text-xl">todo</a>
</div>
<div class="navbar-end">
<a class="btn btn-primary btn-square" href="/todo-edit">
<span class="icon-[ph--plus] w-6 h-6"></span>
</a>
</div>
</div>
<div x-show="error" class="p-4 flex flex-col space-y-4">
<div
x-show="!error.includes('permission to access collection')"
class="alert alert-error"
>
<span x-text="error"></span>
</div>
<a
x-show="error.includes('permission to access collection')"
class="btn btn-primary"
href="https://directus.swablab.de/auth/login/zitadel?redirect=https://swablab.de/todo"
>
Klicke hier, um dich anzumelden
</a>
</div>
<div class="p-4 flex flex-col space-y-2" x-show="!error">
<div class="join">
<input
class="input input-primary w-full join-item"
placeholder="Suchen nach Titel oder Mitglied..."
x-model="search"
/>
<button
class="btn btn-primary join-item"
x-on:click="search = `id:${me}`"
>
Nur meine Aufgaben
</button>
</div>
<ul class="menu grid lg:grid-cols-3 w-full bg-base-200 rounded-box">
{
statuses.map((status) => (
<li x-data={"tasklist('" + status.id + "')"} class="flex-auto">
<a class="pointer-events-none">{status.title}</a>
<ul>
<template x-for="task in sortedTasks()">
<li>
<a x-bind:href="`/todo-edit?${task.id}`">
<span
x-show="task.responsibles.find(x => x.directus_users_id.id == me)"
class="badge badge-xs badge-info"
/>
<span
x-bind:class="{'text-secondary': task.priority == 'high','text-neutral-500': task.priority == 'low'}"
x-text="task.title"
/>
<span
class="badge badge-xs"
x-bind:class="new Date(task.date_due ?? 0) < new Date() ? `badge-error`: `badge-ghost`"
x-show="task.date_due != null"
x-text="formatDate(task.date_due, `short`)"
/>
</a>
</li>
</template>
</ul>
</li>
))
}
</ul>
</div>
</div>
</Base>
<script>
import Alpine from "alpinejs"
import { directus, formatDate, Task } from "../helper"
Alpine.data("kanban", () => ({
me: "",
search: "",
error: "",
init() {
directus<{ id: string }>("users/me?fields=id")
.then((res) => (this.me = res.id))
.catch((err) => (this.error = err))
},
}))
Alpine.data("tasklist", (status: string) => ({
tasks: [],
formatDate: formatDate,
init() {
directus<Task[]>(
`items/tasks_general?filter[status][_eq]=${status}&fields=*,responsibles.directus_users_id.id,responsibles.directus_users_id.first_name`,
)
.then((res) => (this.tasks = res))
.catch((err) => (this.error = err))
},
sortedTasks() {
return (this.tasks as Task[])
.filter(
(a) =>
a.title.toLowerCase().includes(this.search.toLowerCase()) ||
a.responsibles
.map(
(x) =>
`${x.directus_users_id.first_name}|id:${x.directus_users_id.id}`,
)
.join("|")
.toLowerCase()
.includes(this.search.toLowerCase()),
)
.sort((a, b) => a.title.localeCompare(b.title))
.sort((a, b) => (a.date_due ?? "z").localeCompare(b.date_due ?? "z"))
},
}))
Alpine.start()
</script>

View file

@ -1,50 +1,13 @@
@import "tailwindcss";
@plugin "@tailwindcss/typography";
@theme {
--font-sans: "Ubuntu", "sans-serif";
--font-serif: "Ubuntu", "sans-serif";
--font-mono: "Ubuntu Mono", "monospace";
}
@plugin "@iconify/tailwind4";
@plugin "daisyui" {}
@plugin "daisyui/theme" {
name: "swablab";
default: true;
prefersdark: true;
input {
color-scheme: dark;
--color-base-content: white;
--color-base-100: "#171717";
--color-base-200: "#262626";
--color-base-300: "#404040";
--color-primary: "#A3FFF1";
--color-primary-content: black;
--color-secondary: "#FF7F50";
--color-primary-content: black;
--color-neutral: "#404040";
--radius-selector: 1rem;
--radius-field: 0.25rem;
--radius-box: 0.5rem;
--size-selector: 0.25rem;
--size-field: 0.25rem;
--border: 1px;
--depth: 0;
--noise: 0;
--glass-reflect-opacity: 0.001;
}
@font-face {
font-family: "Ubuntu";
font-style: normal;
font-display: block;
font-weight: 100 800;
src: url(@fontsource-variable/ubuntu-sans/files/ubuntu-sans-latin-wght-normal.woff2) format("woff2-variations");
src: url(@fontsource-variable/ubuntu-sans/files/ubuntu-sans-latin-wght-normal.woff2)
format("woff2-variations");
unicode-range:
U+0000-00FF,
U+0131,
@ -66,4 +29,8 @@
U+2215,
U+FEFF,
U+FFFD;
}
}
[x-cloak] {
display: none !important;
}

38
tailwind.config.ts Normal file
View file

@ -0,0 +1,38 @@
module.exports = {
content: ["./src/**/*"],
theme: {
extend: {
colors: {
primary: "#A3FFF1",
secondary: "#FF7F50",
},
fontFamily: {
sans: ["Ubuntu", "sans-serif"],
serif: ["Ubuntu", "sans-serif"],
mono: ["Ubuntu Mono", "monospace"],
},
},
},
daisyui: {
themes: [
{
swablab: {
primary: "#A3FFF1",
secondary: "#FF7F50",
neutral: "#404040",
"base-100": "#171717",
"base-200": "#262626",
"base-300": "#404040",
"--glass-reflex-opacity": "0.001",
},
},
],
logs: false,
},
plugins: [
require("@tailwindcss/typography"),
require("@iconify/tailwind").addDynamicIconSelectors(),
require("daisyui"),
],
}