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", "name": "swabsite",
"image": "mcr.microsoft.com/devcontainers/base:ubuntu", "image": "mcr.microsoft.com/devcontainers/base:ubuntu",
"features": { "features": {
"ghcr.io/devcontainers/features/node": {} "ghcr.io/devcontainers-community/features/deno": {}
}, },
"containerUser": "vscode",
"containerEnv": { "containerEnv": {
"ASTRO_TELEMETRY_DISABLED": "true" "ASTRO_TELEMETRY_DISABLED": "true"
}, },
"postStartCommand": "deno task install",
"runArgs": ["--userns=keep-id", "--security-opt=label=disable"],
"customizations": { "customizations": {
"vscode": { "vscode": {
"extensions": [ "extensions": ["astro-build.astro-vscode"]
"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": [ "recommendations": [
"astro-build.astro-vscode" "astro-build.astro-vscode",
"denoland.vscode-deno"
] ]
} }

22
.vscode/tasks.json vendored
View file

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

View file

@ -1,13 +1,6 @@
FROM docker.io/library/node AS build FROM ghcr.io/swablab/documents:latest AS documents
WORKDIR /app
COPY . .
ENV ASTRO_TELEMETRY_DISABLED=true
RUN npm install
RUN npm run build
FROM git.swablab.de/swablab/documents AS documents FROM docker.io/nginxinc/nginx-unprivileged:latest
FROM docker.io/nginxinc/nginx-unprivileged:alpine-slim
COPY ./nginx.conf /etc/nginx/conf.d/default.conf COPY ./nginx.conf /etc/nginx/conf.d/default.conf
COPY --from=build /app/dist /usr/share/nginx/html COPY ./dist /usr/share/nginx/html
COPY --from=documents / /usr/share/nginx/html/docs 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 sitemap from "@astrojs/sitemap"
import tailwindcss from "@tailwindcss/vite" import tailwind from "@astrojs/tailwind"
import { defineConfig, passthroughImageService } from "astro/config" import { defineConfig, passthroughImageService } from "astro/config"
export default defineConfig({ export default defineConfig({
@ -8,14 +8,9 @@ export default defineConfig({
server: { server: {
host: true, host: true,
}, },
integrations: [sitemap()], integrations: [tailwind(), sitemap()],
image: { image: {
domains: ["directus.swablab.de", "files.mastodon.social"], domains: ["directus.swablab.de", "files.mastodon.social"],
service: passthroughImageService(), 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; internal;
} }
location /todo {
return 302 https://directus.swablab.de/admin/content/tasks_general;
}
location /discord { location /discord {
return 302 https://discord.gg/A4grfc5Vzm; return 301 https://discord.gg/sZbmJdGkMQ;
}
location /linux {
return 302 https://wiki.swablab.de/books/it/page/linux-installationsparty;
} }
location / { 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", "name": "@swablab/website",
"private": true, "private": true,
"scripts": { "scripts": {
"install": "deno install -q",
"check": "astro check", "check": "astro check",
"dev": "astro dev", "dev": "astro dev",
"build": "astro build", "build": "astro build",
@ -9,15 +10,18 @@
}, },
"dependencies": { "dependencies": {
"@astrojs/check": "^0.9.4", "@astrojs/check": "^0.9.4",
"@astrojs/sitemap": "^3.3.1", "@astrojs/sitemap": "^3.2.1",
"@fontsource-variable/ubuntu-sans": "^5.2.7", "@astrojs/tailwind": "^5.1.3",
"@iconify-json/ph": "^1.2.2", "@fontsource-variable/ubuntu-sans": "^5.1.0",
"@iconify/tailwind4": "^1.0.6", "@iconify-json/ph": "^1.2.1",
"@tailwindcss/typography": "^0.5.16", "@iconify/tailwind": "^1.1.3",
"@tailwindcss/vite": "^4.1.5", "@tailwindcss/typography": "^0.5.15",
"astro": "^5.7.12", "@types/alpinejs": "^3.13.11",
"daisyui": "^5.0.35", "alpinejs": "^3.14.6",
"tailwindcss": "^4.0.14" "astro": "^5.0.3",
"daisyui": "^4.12.14",
"tailwindcss": "^3.4.16",
"typescript": "^5.7.2"
}, },
"prettier": { "prettier": {
"tabWidth": 2, "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> <span class="card-title">{name}</span>
) )
} }
<p class="text-lg"> <p>
<slot /> <slot />
</p> </p>
</div> </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> </figure>
)} )}
<div class="card-body text-left text-lg"> <div class="card-body text-left">
<h2 class="card-title justify-between"> <h2 class="card-title justify-between">
<a href={post.url}>@swablab</a> <a href={post.url}>@swablab</a>
<time class="text-xs opacity-50"> <time class="text-xs opacity-50">

View file

@ -5,7 +5,6 @@ import DirectusImg from "./DirectusImg.astro"
type Member = { type Member = {
firstname: string firstname: string
image?: string image?: string
chairman?: boolean
} }
const members = await directus<Member[]>("items/members?sort=firstname") const members = await directus<Member[]>("items/members?sort=firstname")
--- ---
@ -25,43 +24,11 @@ const members = await directus<Member[]>("items/members?sort=firstname")
</div> </div>
</div> </div>
<div class="text-2xl md:text-4xl pt-8">Vorstand</div>
<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 members.map((member) => (
.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>
))
}
</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> <div>
<DirectusImg <DirectusImg
src={ src={

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"> <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"> <div class="text-3xl md:text-5xl">
<a href={"#" + jumpId}>{title}</a> <a href={"#" + jumpId}>{title}</a>
</div> </div>

View file

@ -1,7 +1,33 @@
export async function directus<T>(path: string): Promise<T> { const env = (import.meta as unknown as {
return await fetch(`https://directus.swablab.de/${path}`) 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.json())
.then((res) => res.data) .then((res) => {
if (res.errors) throw res.errors[0].message
return res.data
})
} }
export function formatDate( export function formatDate(
@ -32,3 +58,18 @@ export const documents = {
"Werkstatt-AGB": "/docs/werkstatt-agb.pdf", "Werkstatt-AGB": "/docs/werkstatt-agb.pdf",
"Werkstatt-Regeln": "/docs/werkstatt-regeln.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 { export interface Props {
title?: string title?: string;
description?: 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 = 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"> <html lang="de-DE" class="scroll-smooth">
@ -29,6 +29,13 @@ const description =
<title>{titleFull}</title> <title>{titleFull}</title>
<link rel="icon" type="image/x-icon" href="/favicon.ico" /> <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> </head>
<body class="min-h-screen flex flex-col"> <body class="min-h-screen flex flex-col">
<slot /> <slot />

View file

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

View file

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

View file

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

View file

@ -82,7 +82,7 @@ import Page from "../layouts/Page.astro"
], ],
[ [
"Sommer 2024", "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", "Herbst 2024",

View file

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

View file

@ -15,8 +15,7 @@ Telefon: [+49 15679 232971](tel:+4915679232971)
**Vertreten durch**\ **Vertreten durch**\
Fabian Haas\ Fabian Haas\
Manuel Knodel\ Manuel Knodel
Bastian Wittke
**Registereintrag**\ **Registereintrag**\
Amtsgericht Stuttgart\ 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> <span class="icon-[ph--arrow-circle-down-duotone] h-16 w-16"></span>
</a> </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"> <Section title="Offene Werkstatt?" jumpId="start">
<DirectusImg <DirectusImg
src="753d211b-8b28-42cb-8ddd-0777911b3511" src="753d211b-8b28-42cb-8ddd-0777911b3511"
@ -50,14 +61,6 @@ import Page from "../layouts/Page.astro"
</Text> </Text>
</Section> </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"> <Section title="Was interessiert dich?" jumpId="services">
<Card <Card
name="Über uns" name="Über uns"
@ -109,6 +112,14 @@ import Page from "../layouts/Page.astro"
</Card> </Card>
</Section> </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"> <div class="fixed bottom-4 left-4 flex">
<a <a
class="btn btn-square btn-ghost z-10 discord-left" 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: oder ihn an folgende Adresse schicken:
</Text> </Text>
<div class="stats shadow bg-base-300"> <div class="stats shadow">
<div class="stat"> <div class="stat">
<div class="stat-value">swablab e.V.</div> <div class="stat-value">swablab e.V.</div>
<div class="stat-title text-xl">Katharinenstr. 1</div> <div class="stat-title">Katharinenstr. 1</div>
<div class="stat-title text-xl">72250 Freudenstadt</div> <div class="stat-title">72250 Freudenstadt</div>
</div> </div>
</div> </div>
</Section> </Section>

View file

@ -1,9 +1,7 @@
--- ---
import Card from "../components/Card.astro" import Card from "../components/Card.astro"
import Collapse from "../components/Collapse.astro"
import Contact from "../components/Contact.astro" import Contact from "../components/Contact.astro"
import Gallery from "../components/Gallery.astro" import Gallery from "../components/Gallery.astro"
import Link from "../components/Link.astro"
import Map from "../components/Map.astro" import Map from "../components/Map.astro"
import Section from "../components/Section.astro" import Section from "../components/Section.astro"
import Text from "../components/Text.astro" import Text from "../components/Text.astro"
@ -93,32 +91,6 @@ import Page from "../layouts/Page.astro"
<Map /> <Map />
</Section> </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> <Contact>
<Text> <Text>
Egal, ob du an 3D-Druck, Elektronik, CNC-Arbeiten oder anderen Projekten 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"; input {
@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;
color-scheme: dark; 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-face {
font-family: "Ubuntu"; font-family: "Ubuntu";
font-style: normal; font-style: normal;
font-display: block; font-display: block;
font-weight: 100 800; 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: unicode-range:
U+0000-00FF, U+0000-00FF,
U+0131, U+0131,
@ -67,3 +30,7 @@
U+FEFF, U+FEFF,
U+FFFD; 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"),
],
}