diff --git a/.gemini/settings.json b/.gemini/settings.json
deleted file mode 100644
index 3cc6af9..0000000
--- a/.gemini/settings.json
+++ /dev/null
@@ -1,12 +0,0 @@
-{
- "$schema": "https://raw.githubusercontent.com/google-gemini/gemini-cli/main/schemas/settings.schema.json",
- "mcpServers": {
- "svelte": {
- "command": "npx",
- "args": [
- "-y",
- "@sveltejs/mcp"
- ]
- }
- }
-}
diff --git a/.npmrc b/.npmrc
deleted file mode 100644
index b6f27f1..0000000
--- a/.npmrc
+++ /dev/null
@@ -1 +0,0 @@
-engine-strict=true
diff --git a/GEMINI.md b/GEMINI.md
deleted file mode 100644
index 56f8d27..0000000
--- a/GEMINI.md
+++ /dev/null
@@ -1,65 +0,0 @@
-# Project Context: Schreifuchs.ch
-
-## Overview
-
-This project is a personal portfolio website for "Schreifuchs", featuring sections for Photography (Fotos), Informatics (Informatik), Music (Musig), and Video. It is currently being transitioned from a static site to a dynamic Node.js site powered by Nextcloud via WebDAV.
-
-## Tech Stack
-
-- **Framework:** Svelte 5 (using Runes) & SvelteKit
-- **Language:** TypeScript
-- **Styling:** Tailwind CSS (with custom text-shadow plugin)
-- **Bundler:** Vite
-- **Adapter:** `@sveltejs/adapter-static` (SSG)
-- **Markdown:** `@ts-stack/markdown` for content rendering
-
-## Directory Structure
-
-- `src/routes/`: File-based routing.
- - `src/routes/fotos`, `informatik`, `musig`, `video`: Feature-specific pages.
-- `src/lib/`: Shared utilities and components.
- - `src/lib/components/`: Reusable UI components (`ImageTile`, `ImageLinkTile`, `Markdown`).
- - `src/lib/images/`: Local image assets imported in components.
-- `static/`: Static assets served as-is.
- - Contains Markdown content files (`Fotos.md`, etc.) and their associated attachments.
-
-## Key Conventions
-
-- **Svelte 5:** Use Runes (`$state`, `$derived`, `$props`, etc.) for reactivity.
-- **Styling:** Use Tailwind utility classes. The font family is configured to 'Outfit'.
-- **Content:** Content is largely driven by Markdown files located on Nextcloud which are fetched and parsed.
-
-## Development Scripts
-
-- `npm run dev`: Start development server.
-- `npm run build`: Build for production.
-- `npm run check`: Run Svelte and TypeScript checks.
-
----
-
-# Agent Instructions (Svelte MCP)
-
-You are able to use the Svelte MCP server, where you have access to comprehensive Svelte 5 and SvelteKit documentation. Here's how to use the available tools effectively:
-
-## Available MCP Tools:
-
-### 1. list-sections
-
-Use this FIRST to discover all available documentation sections. Returns a structured list with titles, use_cases, and paths.
-When asked about Svelte or SvelteKit topics, ALWAYS use this tool at the start of the chat to find relevant sections.
-
-### 2. get-documentation
-
-Retrieves full documentation content for specific sections. Accepts single or multiple sections.
-After calling the list-sections tool, you MUST analyze the returned documentation sections (especially the use_cases field) and then use the get-documentation tool to fetch ALL documentation sections that are relevant for the user's task.
-
-### 3. svelte-autofixer
-
-Analyzes Svelte code and returns issues and suggestions.
-You MUST use this tool whenever writing Svelte code before sending it to the user. Keep calling it until no issues or suggestions are returned.
-
-### 4. playground-link
-
-Generates a Svelte Playground link with the provided code.
-After completing the code, ask the user if they want a playground link. Only call this tool after user confirmation and NEVER if code was written to files in their project.
-
diff --git a/cmd/schreifuchs-ch/main.go b/cmd/schreifuchs-ch/main.go
new file mode 100644
index 0000000..dbdf234
--- /dev/null
+++ b/cmd/schreifuchs-ch/main.go
@@ -0,0 +1,20 @@
+package main
+
+import (
+ "log/slog"
+ "os"
+
+ "git.schreifuchs.ch/schreifuchs/schreifuchs.ch/internal/server"
+)
+
+func main() {
+ server := server.NewServer()
+
+ slog.Info("Server started", "addr", server.Addr)
+
+ err := server.ListenAndServe()
+ if err != nil {
+ slog.Error("Server failed to start", "error", err)
+ os.Exit(1)
+ }
+}
\ No newline at end of file
diff --git a/go.mod b/go.mod
new file mode 100644
index 0000000..c0385f5
--- /dev/null
+++ b/go.mod
@@ -0,0 +1,24 @@
+module git.schreifuchs.ch/schreifuchs/schreifuchs.ch
+
+go 1.25.7
+
+tool github.com/a-h/templ/cmd/templ
+
+require github.com/a-h/templ v0.3.977
+
+require (
+ github.com/a-h/parse v0.0.0-20250122154542-74294addb73e // indirect
+ github.com/andybalholm/brotli v1.1.0 // indirect
+ github.com/cenkalti/backoff/v4 v4.3.0 // indirect
+ github.com/cli/browser v1.3.0 // indirect
+ github.com/fatih/color v1.16.0 // indirect
+ github.com/fsnotify/fsnotify v1.7.0 // indirect
+ github.com/mattn/go-colorable v0.1.13 // indirect
+ github.com/mattn/go-isatty v0.0.20 // indirect
+ github.com/natefinch/atomic v1.0.1 // indirect
+ golang.org/x/mod v0.26.0 // indirect
+ golang.org/x/net v0.42.0 // indirect
+ golang.org/x/sync v0.16.0 // indirect
+ golang.org/x/sys v0.34.0 // indirect
+ golang.org/x/tools v0.35.0 // indirect
+)
diff --git a/go.sum b/go.sum
new file mode 100644
index 0000000..e7e087a
--- /dev/null
+++ b/go.sum
@@ -0,0 +1,43 @@
+github.com/a-h/parse v0.0.0-20250122154542-74294addb73e h1:HjVbSQHy+dnlS6C3XajZ69NYAb5jbGNfHanvm1+iYlo=
+github.com/a-h/parse v0.0.0-20250122154542-74294addb73e/go.mod h1:3mnrkvGpurZ4ZrTDbYU84xhwXW2TjTKShSwjRi2ihfQ=
+github.com/a-h/templ v0.3.977 h1:kiKAPXTZE2Iaf8JbtM21r54A8bCNsncrfnokZZSrSDg=
+github.com/a-h/templ v0.3.977/go.mod h1:oCZcnKRf5jjsGpf2yELzQfodLphd2mwecwG4Crk5HBo=
+github.com/andybalholm/brotli v1.1.0 h1:eLKJA0d02Lf0mVpIDgYnqXcUn0GqVmEFny3VuID1U3M=
+github.com/andybalholm/brotli v1.1.0/go.mod h1:sms7XGricyQI9K10gOSf56VKKWS4oLer58Q+mhRPtnY=
+github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8=
+github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
+github.com/cli/browser v1.3.0 h1:LejqCrpWr+1pRqmEPDGnTZOjsMe7sehifLynZJuqJpo=
+github.com/cli/browser v1.3.0/go.mod h1:HH8s+fOAxjhQoBUAsKuPCbqUuxZDhQ2/aD+SzsEfBTk=
+github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
+github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM=
+github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE=
+github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA=
+github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM=
+github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
+github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
+github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
+github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
+github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
+github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
+github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
+github.com/natefinch/atomic v1.0.1 h1:ZPYKxkqQOx3KZ+RsbnP/YsgvxWQPGxjC0oBt2AhwV0A=
+github.com/natefinch/atomic v1.0.1/go.mod h1:N/D/ELrljoqDyT3rZrsUmtsuzvHkeB/wWjHV22AZRbM=
+github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
+github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
+github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
+golang.org/x/mod v0.26.0 h1:EGMPT//Ezu+ylkCijjPc+f4Aih7sZvaAr+O3EHBxvZg=
+golang.org/x/mod v0.26.0/go.mod h1:/j6NAhSk8iQ723BGAUyoAcn7SlD7s15Dp9Nd/SfeaFQ=
+golang.org/x/net v0.42.0 h1:jzkYrhi3YQWD6MLBJcsklgQsoAcw89EcZbJw8Z614hs=
+golang.org/x/net v0.42.0/go.mod h1:FF1RA5d3u7nAYA4z2TkclSCKh68eSXtiFwcWQpPXdt8=
+golang.org/x/sync v0.16.0 h1:ycBJEhp9p4vXvUZNszeOq0kGTPghopOL8q0fq3vstxw=
+golang.org/x/sync v0.16.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
+golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.34.0 h1:H5Y5sJ2L2JRdyv7ROF1he/lPdvFsd0mJHFw2ThKHxLA=
+golang.org/x/sys v0.34.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
+golang.org/x/tools v0.35.0 h1:mBffYraMEf7aa0sB+NuKnuCy8qI/9Bughn8dC2Gu5r0=
+golang.org/x/tools v0.35.0/go.mod h1:NKdj5HkL/73byiZSJjqJgKn3ep7KjFkBOkR/Hps3VPw=
+gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
+gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
diff --git a/internal/handlers/handlehome/home.go b/internal/handlers/handlehome/home.go
new file mode 100644
index 0000000..4232330
--- /dev/null
+++ b/internal/handlers/handlehome/home.go
@@ -0,0 +1,12 @@
+package handler
+
+import (
+ "net/http"
+
+ "github.com/a-h/templ"
+ "git.schreifuchs.ch/schreifuchs/schreifuchs.ch/web/pages"
+)
+
+func Home() http.Handler {
+ return templ.Handler(pages.Index())
+}
diff --git a/internal/handlers/home.go b/internal/handlers/home.go
new file mode 100644
index 0000000..4232330
--- /dev/null
+++ b/internal/handlers/home.go
@@ -0,0 +1,12 @@
+package handler
+
+import (
+ "net/http"
+
+ "github.com/a-h/templ"
+ "git.schreifuchs.ch/schreifuchs/schreifuchs.ch/web/pages"
+)
+
+func Home() http.Handler {
+ return templ.Handler(pages.Index())
+}
diff --git a/internal/server/routes.go b/internal/server/routes.go
new file mode 100644
index 0000000..e63e2b1
--- /dev/null
+++ b/internal/server/routes.go
@@ -0,0 +1,33 @@
+package server
+
+import (
+ "log/slog"
+ "net/http"
+ "time"
+
+ "git.schreifuchs.ch/schreifuchs/schreifuchs.ch/internal/handler"
+ "git.schreifuchs.ch/schreifuchs/schreifuchs.ch/web"
+)
+
+func (s *Server) RegisterRoutes() http.Handler {
+ mux := http.NewServeMux()
+
+ fileServer := http.FileServer(http.FS(web.GetStaticFS()))
+ mux.Handle("/static/", http.StripPrefix("/static/", fileServer))
+
+ mux.Handle("/", handler.Home())
+
+ return s.loggingMiddleware(mux)
+}
+
+func (s *Server) loggingMiddleware(next http.Handler) http.Handler {
+ return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
+ start := time.Now()
+ next.ServeHTTP(w, r)
+ slog.Info("request",
+ "method", r.Method,
+ "path", r.URL.Path,
+ "duration", time.Since(start),
+ )
+ })
+}
diff --git a/internal/server/server.go b/internal/server/server.go
new file mode 100644
index 0000000..b2db09b
--- /dev/null
+++ b/internal/server/server.go
@@ -0,0 +1,34 @@
+package server
+
+import (
+ "fmt"
+ "net/http"
+ "os"
+ "strconv"
+ "time"
+)
+
+type Server struct {
+ port int
+}
+
+func NewServer() *http.Server {
+ port, _ := strconv.Atoi(os.Getenv("PORT"))
+ if port == 0 {
+ port = 8080
+ }
+ s := &Server{
+ port: port,
+ }
+
+ // Declare Server config
+ server := &http.Server{
+ Addr: fmt.Sprintf(":%d", s.port),
+ Handler: s.RegisterRoutes(),
+ IdleTimeout: time.Minute,
+ ReadTimeout: 10 * time.Second,
+ WriteTimeout: 30 * time.Second,
+ }
+
+ return server
+}
diff --git a/messages/de.json b/messages/de.json
deleted file mode 100644
index 9759149..0000000
--- a/messages/de.json
+++ /dev/null
@@ -1,8 +0,0 @@
-{
- "$schema": "https://inlang.com/schema/message-format-plugin",
- "hello_world": "Hallo Welt",
- "pfadi": "Pfadi",
- "site_title": "Schreifuchs.ch",
- "site_description": "Portfolio von Schreifuchs - Fotografie, Informatik und Musik."
-}
-
diff --git a/messages/en.json b/messages/en.json
deleted file mode 100644
index a769a1b..0000000
--- a/messages/en.json
+++ /dev/null
@@ -1,8 +0,0 @@
-{
- "$schema": "https://inlang.com/schema/message-format-plugin",
- "hello_world": "Hello World",
- "pfadi": "Scouts",
- "site_title": "Schreifuchs.ch",
- "site_description": "Portfolio of Schreifuchs - Photography, Informatics and Music ."
-}
-
diff --git a/package.json b/package.json
index 432f744..7921bad 100644
--- a/package.json
+++ b/package.json
@@ -1,38 +1,38 @@
{
- "name": "schreifuchs",
- "version": "0.0.1",
- "private": true,
- "scripts": {
- "dev": "vite dev",
- "build": "vite build",
- "preview": "vite preview",
- "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
- "check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch"
- },
- "devDependencies": {
- "@sveltejs/adapter-auto": "^3.0.0",
- "@sveltejs/adapter-node": "^5.5.1",
- "@sveltejs/kit": "^2.5.27",
- "@sveltejs/vite-plugin-svelte": "^4.0.0",
- "@types/mime-types": "^3.0.1",
- "@types/node": "^25.0.9",
- "autoprefixer": "^10.4.19",
- "postcss": "^8.4.38",
- "svelte": "^5.0.0",
- "svelte-check": "^4.0.0",
- "tailwindcss": "^3.4.3",
- "typescript": "^5.5.0",
- "vite": "^5.4.4"
- },
- "type": "module",
- "dependencies": {
- "@fontsource/outfit": "^5.0.13",
- "@inlang/paraglide-js": "^1.11.0",
- "@inlang/paraglide-sveltekit": "^0.16.1",
- "@ts-stack/markdown": "^1.5.0",
- "lru-cache": "^11.2.4",
- "mime-types": "^3.0.2",
- "svelte-preprocess": "^6.0.2",
- "webdav": "^5.8.0"
- }
+ "name": "schreifuchs",
+ "version": "0.0.1",
+ "private": true,
+ "scripts": {
+ "dev": "vite dev",
+ "build": "vite build",
+ "preview": "vite preview",
+ "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
+ "check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch"
+ },
+ "devDependencies": {
+ "@sveltejs/adapter-auto": "^3.0.0",
+ "@sveltejs/adapter-node": "^5.5.1",
+ "@sveltejs/kit": "^2.5.27",
+ "@sveltejs/vite-plugin-svelte": "^4.0.0",
+ "@types/mime-types": "^3.0.1",
+ "@types/node": "^25.0.9",
+ "autoprefixer": "^10.4.19",
+ "postcss": "^8.4.38",
+ "svelte": "^5.0.0",
+ "svelte-check": "^4.0.0",
+ "tailwindcss": "^3.4.3",
+ "typescript": "^5.5.0",
+ "vite": "^5.4.4"
+ },
+ "type": "module",
+ "dependencies": {
+ "@fontsource/outfit": "^5.0.13",
+ "@inlang/paraglide-js": "^1.11.0",
+ "@inlang/paraglide-sveltekit": "^0.16.1",
+ "@ts-stack/markdown": "^1.5.0",
+ "lru-cache": "^11.2.4",
+ "mime-types": "^3.0.2",
+ "svelte-preprocess": "^6.0.2",
+ "webdav": "^5.8.0"
+ }
}
diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml
deleted file mode 100644
index efc037a..0000000
--- a/pnpm-workspace.yaml
+++ /dev/null
@@ -1,2 +0,0 @@
-onlyBuiltDependencies:
- - esbuild
diff --git a/postcss.config.js b/postcss.config.js
deleted file mode 100644
index 2e7af2b..0000000
--- a/postcss.config.js
+++ /dev/null
@@ -1,6 +0,0 @@
-export default {
- plugins: {
- tailwindcss: {},
- autoprefixer: {},
- },
-}
diff --git a/project.inlang/.gitignore b/project.inlang/.gitignore
deleted file mode 100644
index 5e46596..0000000
--- a/project.inlang/.gitignore
+++ /dev/null
@@ -1 +0,0 @@
-cache
\ No newline at end of file
diff --git a/project.inlang/project_id b/project.inlang/project_id
deleted file mode 100644
index 136ed81..0000000
--- a/project.inlang/project_id
+++ /dev/null
@@ -1 +0,0 @@
-aa922b989658d017b7a6296093cef3dac23a39ddc1afa6cf7ea24c049a284b56
\ No newline at end of file
diff --git a/project.inlang/settings.json b/project.inlang/settings.json
deleted file mode 100644
index dcca6d2..0000000
--- a/project.inlang/settings.json
+++ /dev/null
@@ -1,14 +0,0 @@
-{
- "$schema": "https://inlang.com/schema/project-settings",
- "telemetry": "off",
- "sourceLanguageTag": "de",
- "languageTags": ["de", "en"],
- "modules": [
- "https://cdn.jsdelivr.net/npm/@inlang/plugin-m-function-matcher@latest/dist/index.js",
- "https://cdn.jsdelivr.net/npm/@inlang/plugin-message-format@latest/dist/index.js"
- ],
- "plugin.inlang.messageFormat": {
- "pathPattern": "./messages/{languageTag}.json"
- }
-}
-
diff --git a/src/app.css b/src/app.css
deleted file mode 100644
index 909c436..0000000
--- a/src/app.css
+++ /dev/null
@@ -1,5 +0,0 @@
-@import "@fontsource/outfit";
-
-@tailwind base;
-@tailwind components;
-@tailwind utilities;
diff --git a/src/app.d.ts b/src/app.d.ts
deleted file mode 100644
index 743f07b..0000000
--- a/src/app.d.ts
+++ /dev/null
@@ -1,13 +0,0 @@
-// See https://kit.svelte.dev/docs/types#app
-// for information about these interfaces
-declare global {
- namespace App {
- // interface Error {}
- // interface Locals {}
- // interface PageData {}
- // interface PageState {}
- // interface Platform {}
- }
-}
-
-export {};
diff --git a/src/app.html b/src/app.html
deleted file mode 100644
index 6c747a3..0000000
--- a/src/app.html
+++ /dev/null
@@ -1,22 +0,0 @@
-
-
-
-
-
-
-
- schreifuchs.ch
-
- %sveltekit.head%
-
-
- %sveltekit.body%
-
-
diff --git a/src/hooks.server.ts b/src/hooks.server.ts
deleted file mode 100644
index bd99bae..0000000
--- a/src/hooks.server.ts
+++ /dev/null
@@ -1,3 +0,0 @@
-import { i18n } from "$lib/i18n"
-
-export const handle = i18n.handle()
\ No newline at end of file
diff --git a/src/lib/components/ImageLinkTile.svelte b/src/lib/components/ImageLinkTile.svelte
deleted file mode 100644
index c917f15..0000000
--- a/src/lib/components/ImageLinkTile.svelte
+++ /dev/null
@@ -1,27 +0,0 @@
-
-
-
diff --git a/src/lib/components/ImageTile.svelte b/src/lib/components/ImageTile.svelte
deleted file mode 100644
index dfe8c74..0000000
--- a/src/lib/components/ImageTile.svelte
+++ /dev/null
@@ -1,50 +0,0 @@
-
-
-
-

{
- const img = e.currentTarget as HTMLImageElement;
- img.src = placeholder;
- // Clear srcset on error to avoid loading broken thumbnails
- img.srcset = "";
- }}
- />
-
- {@render children?.()}
-
-
diff --git a/src/lib/components/Markdown.svelte b/src/lib/components/Markdown.svelte
deleted file mode 100644
index ab1b8a2..0000000
--- a/src/lib/components/Markdown.svelte
+++ /dev/null
@@ -1,99 +0,0 @@
-
-
-
- {@html html}
-
-
-
diff --git a/src/lib/i18n.ts b/src/lib/i18n.ts
deleted file mode 100644
index 809c9f8..0000000
--- a/src/lib/i18n.ts
+++ /dev/null
@@ -1,11 +0,0 @@
-import { createI18n } from "@inlang/paraglide-sveltekit"
-import * as runtime from "$lib/paraglide/runtime"
-
-export const i18n = createI18n(runtime, {
- pathnames: {
- "/about": {
- en: "/about",
- de: "/ueber-uns"
- }
- }
-})
\ No newline at end of file
diff --git a/src/lib/images/fotos/sunne_untergang.webp b/src/lib/images/fotos/sunne_untergang.webp
deleted file mode 100644
index e2ade43..0000000
Binary files a/src/lib/images/fotos/sunne_untergang.webp and /dev/null differ
diff --git a/src/lib/images/home/console.webp b/src/lib/images/home/console.webp
deleted file mode 100644
index 7dec489..0000000
Binary files a/src/lib/images/home/console.webp and /dev/null differ
diff --git a/src/lib/images/home/drummachine.webp b/src/lib/images/home/drummachine.webp
deleted file mode 100644
index 64386c5..0000000
Binary files a/src/lib/images/home/drummachine.webp and /dev/null differ
diff --git a/src/lib/images/home/lauch.webp b/src/lib/images/home/lauch.webp
deleted file mode 100644
index c75260f..0000000
Binary files a/src/lib/images/home/lauch.webp and /dev/null differ
diff --git a/src/lib/images/home/mouse.webp b/src/lib/images/home/mouse.webp
deleted file mode 100644
index 937c70f..0000000
Binary files a/src/lib/images/home/mouse.webp and /dev/null differ
diff --git a/src/lib/images/home/scouts.webp b/src/lib/images/home/scouts.webp
deleted file mode 100644
index 1fe68d9..0000000
Binary files a/src/lib/images/home/scouts.webp and /dev/null differ
diff --git a/src/lib/images/informatik/monitor.webp b/src/lib/images/informatik/monitor.webp
deleted file mode 100644
index 461300c..0000000
Binary files a/src/lib/images/informatik/monitor.webp and /dev/null differ
diff --git a/src/lib/images/musig/plattespiler.webp b/src/lib/images/musig/plattespiler.webp
deleted file mode 100644
index cc3f680..0000000
Binary files a/src/lib/images/musig/plattespiler.webp and /dev/null differ
diff --git a/src/lib/images/niklas_nacht_pfadi.webp b/src/lib/images/niklas_nacht_pfadi.webp
deleted file mode 100644
index 6e45b39..0000000
Binary files a/src/lib/images/niklas_nacht_pfadi.webp and /dev/null differ
diff --git a/src/lib/images/video/jochen.webp b/src/lib/images/video/jochen.webp
deleted file mode 100644
index d0d6734..0000000
Binary files a/src/lib/images/video/jochen.webp and /dev/null differ
diff --git a/src/lib/images/video/niklas_bw.webp b/src/lib/images/video/niklas_bw.webp
deleted file mode 100644
index e2be9a9..0000000
Binary files a/src/lib/images/video/niklas_bw.webp and /dev/null differ
diff --git a/src/lib/index.ts b/src/lib/index.ts
deleted file mode 100644
index 856f2b6..0000000
--- a/src/lib/index.ts
+++ /dev/null
@@ -1 +0,0 @@
-// place files you want to import through the `$lib` alias in this folder.
diff --git a/src/lib/server/cache.ts b/src/lib/server/cache.ts
deleted file mode 100644
index 11c4b69..0000000
--- a/src/lib/server/cache.ts
+++ /dev/null
@@ -1,87 +0,0 @@
-import { LRUCache } from "lru-cache";
-
-// const cache = new Map();
-const DEFAULT_TTL = 1000 * 60 * 15; // 15 minutes default TTL
-const MAX_CACHE_SIZE = 1000 * 1000 * 750; // 750 MB
-
-const cache = new LRUCache({
- max: 100,
- // Maximum allowed size (in bytes)
- maxSize: MAX_CACHE_SIZE,
-
- // IMPORTANT: We must teach the cache how to calculate the size of an item.
- // We check for your specific image structure, generic buffers, or fallback to JSON length.
- sizeCalculation: (value) => {
- // 1. Check if it's our specific image object { buffer: ArrayBuffer, ... }
- if (value && typeof value === "object") {
- const obj = value as Record;
- if (obj.buffer instanceof ArrayBuffer) {
- return obj.buffer.byteLength;
- }
- }
-
- // 2. Handle raw ArrayBuffers or Node.js Buffers
- if (value instanceof ArrayBuffer) {
- return value.byteLength;
- }
-
- if (Buffer.isBuffer(value)) {
- return value.length;
- }
-
- // 3. Fallback for strings or JSON metadata
- try {
- const str = JSON.stringify(value);
- return str ? str.length : 1;
- } catch {
- return 1;
- }
- },
- ttl: DEFAULT_TTL,
-});
-
-/**
- * Caches the result of a promise-returning function.
- * @param key Unique key for the cache entry.
- * @param fetcher Function that returns a promise with the data to cache.
- * @param ttl Time to live in milliseconds. Defaults to 15 minutes.
- */
-export async function withCache(
- key: string,
- fetcher: () => Promise,
- ttl = DEFAULT_TTL,
-): Promise {
- const entry = cache.get(key);
-
- if (entry) {
- return entry as T;
- }
-
- try {
- const data = await fetcher();
- if (data) {
- cache.set(key, data, { ttl: ttl });
- }
- return data;
- } catch (error) {
- console.error(`Error fetching data for key ${key}:`, error);
- // If fetch fails but we have stale data, return it?
- // For now, let's bubble the error up so the page handles it (e.g. 404),
- // or maybe just re-throw.
- throw error;
- }
-}
-
-/**
- * Manually clears a specific cache key.
- */
-export function clearCache(key: string) {
- cache.delete(key);
-}
-
-/**
- * Clears the entire cache.
- */
-export function clearAllCache() {
- cache.clear();
-}
diff --git a/src/lib/server/nextcloud.ts b/src/lib/server/nextcloud.ts
deleted file mode 100644
index 4e57c6c..0000000
--- a/src/lib/server/nextcloud.ts
+++ /dev/null
@@ -1,124 +0,0 @@
-import { createClient } from "webdav";
-import { env } from "$env/dynamic/private";
-import { withCache } from "./cache";
-
-if (!env.NEXTCLOUD_URL || !env.NEXTCLOUD_USER || !env.NEXTCLOUD_PASSWORD) {
- console.warn(
- "Nextcloud environment variables are not fully set. WebDAV client might not work correctly.",
- );
-}
-
-// Construct the standard Nextcloud WebDAV URL: https://example.com/remote.php/dav/files/USERNAME/[BASE_DIR/]
-const getWebdavUrl = () => {
- if (!env.NEXTCLOUD_URL) return "";
-
- let url = env.NEXTCLOUD_URL.endsWith("/")
- ? env.NEXTCLOUD_URL
- : `${env.NEXTCLOUD_URL}/`;
- url += `remote.php/dav/files/${env.NEXTCLOUD_USER}/`;
-
- if (env.NEXTCLOUD_BASE_DIR) {
- // Remove leading/trailing slashes from base dir to ensure clean concatenation
- const baseDir = env.NEXTCLOUD_BASE_DIR.replace(/^\/+|\/+$/g, "");
- if (baseDir) {
- url += `${baseDir}/`;
- }
- }
-
- return url;
-};
-
-export const client = createClient(getWebdavUrl(), {
- username: env.NEXTCLOUD_USER || "",
- password: env.NEXTCLOUD_PASSWORD || "",
-});
-
-export async function getCoverImage(slug: string): Promise {
- return withCache(`cover:${slug}`, async () => {
- try {
- const contents = await client.getDirectoryContents("/" + slug);
- if (!Array.isArray(contents)) return null;
-
- const cover = contents.find(
- (item: any) =>
- item.type === "file" &&
- item.basename.match(/^cover\.(webp|jpg|jpeg|png)$/i),
- );
-
- return cover ? `/assets/${slug}/${cover.basename}` : null;
- } catch (e) {
- console.warn(`Failed to check cover image for ${slug}:`, e);
- return null;
- }
- });
-}
-
-export async function getPages(lang: string = 'de') {
- return withCache(`pages:${lang}`, async () => {
- try {
- const items = await client.getDirectoryContents("/");
-
- if (!Array.isArray(items)) {
- return [];
- }
-
- const directories = items.filter(
- (item: any) =>
- item.type === "directory" &&
- !item.basename.startsWith(".") &&
- !item.basename.startsWith("_"),
- );
-
- const pages = await Promise.all(
- directories.map(async (item: any) => {
- const slug = item.basename;
- const baseName = slug.charAt(0).toUpperCase() + slug.slice(1);
- const filename = lang === 'de' ? `${baseName}.md` : `${baseName}.${lang}.md`;
- const path = `/${slug}/${filename}`;
-
- let title = baseName;
- try {
- const content = await getPageContent(path);
- const headerMatch = content.match(/^#{1,6}\s+(.+)$/m);
- if (headerMatch) {
- title = headerMatch[1];
- }
- } catch (e) {
- // Fallback to German if English is missing
- if (lang !== 'de') {
- try {
- const fallbackContent = await getPageContent(`/${slug}/${baseName}.md`);
- const headerMatch = fallbackContent.match(/^#{1,6}\s+(.+)$/m);
- if (headerMatch) {
- title = headerMatch[1];
- }
- } catch (innerE) {
- console.warn(`Could not fetch fallback title for ${slug}`);
- }
- }
- }
-
- const coverImage = await getCoverImage(slug);
-
- return {
- slug,
- title,
- coverImage,
- };
- }),
- );
-
- return pages;
- } catch (e) {
- console.error("Failed to fetch pages from Nextcloud:", e);
- return [];
- }
- });
-}
-
-export async function getPageContent(path: string): Promise {
- return withCache(`content:${path}`, async () => {
- const content = await client.getFileContents(path, { format: "text" });
- return content as string;
- });
-}
diff --git a/src/params/lang.ts b/src/params/lang.ts
deleted file mode 100644
index 3eefba1..0000000
--- a/src/params/lang.ts
+++ /dev/null
@@ -1,5 +0,0 @@
-import type { ParamMatcher } from '@sveltejs/kit';
-
-export const match: ParamMatcher = (param) => {
- return ['de', 'en'].includes(param);
-};
diff --git a/src/routes/+layout.server.ts b/src/routes/+layout.server.ts
deleted file mode 100644
index fe36a9c..0000000
--- a/src/routes/+layout.server.ts
+++ /dev/null
@@ -1,9 +0,0 @@
-import type { LayoutServerLoad } from './$types';
-import { getPages } from '$lib/server/nextcloud';
-
-export const load: LayoutServerLoad = async ({ params }) => {
- const pages = await getPages(params.lang);
- return {
- pages
- };
-};
\ No newline at end of file
diff --git a/src/routes/+layout.svelte b/src/routes/+layout.svelte
deleted file mode 100644
index 31b175b..0000000
--- a/src/routes/+layout.svelte
+++ /dev/null
@@ -1,49 +0,0 @@
-
-
-
- {m.site_title()}
-
-
-
-
-
- {@render children?.()}
-
diff --git a/src/routes/+layout.ts b/src/routes/+layout.ts
deleted file mode 100644
index 9406451..0000000
--- a/src/routes/+layout.ts
+++ /dev/null
@@ -1,3 +0,0 @@
-// This can be false if you're using a fallback (i.e. SPA mode)
-// export const prerender = true;
-// export const trailingSlash = 'always';
diff --git a/src/routes/[[lang=lang]]/+page.svelte b/src/routes/[[lang=lang]]/+page.svelte
deleted file mode 100644
index 209b927..0000000
--- a/src/routes/[[lang=lang]]/+page.svelte
+++ /dev/null
@@ -1,50 +0,0 @@
-
-
-
- {#if data.pages}
- {#each data.pages as page}
-
-
- {page.title}
-
-
- {/each}
- {/if}
-
-
-
-
- {m.pfadi()}
-
-
-
-
diff --git a/src/routes/[[lang=lang]]/[slug]/+page.server.ts b/src/routes/[[lang=lang]]/[slug]/+page.server.ts
deleted file mode 100644
index dcaa1e9..0000000
--- a/src/routes/[[lang=lang]]/[slug]/+page.server.ts
+++ /dev/null
@@ -1,69 +0,0 @@
-import { getCoverImage, getPageContent } from "$lib/server/nextcloud";
-import type { PageServerLoad } from "./$types";
-import { error } from "@sveltejs/kit";
-
-export const load: PageServerLoad = async ({ params }) => {
- const { slug, lang } = params;
- const language = lang || 'de';
-
- // Try both the regular slug and the hidden (_slug) folder
- const slugsToTry = [slug, `_${slug}`];
- let rawContent = "";
- let finalSlug = slug;
- let baseName = "";
- let filename = "";
-
- for (const s of slugsToTry) {
- const cleanSlug = s.startsWith('_') ? s.slice(1) : s;
- baseName = cleanSlug.charAt(0).toUpperCase() + cleanSlug.slice(1);
-
- filename = language === 'de' ? `${baseName}.md` : `${baseName}.${language}.md`;
- const path = `/${s}/${filename}`;
-
- try {
- try {
- rawContent = await getPageContent(path);
- finalSlug = s;
- break; // Found it!
- } catch (e) {
- if (language !== 'de') {
- console.warn(`Localized content ${filename} not found in ${s}, falling back to German.`);
- rawContent = await getPageContent(`/${s}/${baseName}.md`);
- finalSlug = s;
- break; // Found fallback
- } else {
- throw e; // Try next slug variant
- }
- }
- } catch (e) {
- if (s === slugsToTry[slugsToTry.length - 1]) {
- console.error(`Error fetching page from Nextcloud for slug ${slug}`, e);
- throw error(404, "Page not found");
- }
- }
- }
-
- try {
- // Extract the first header (e.g., # Title or ## Title)
- const headerMatch = rawContent.match(/^#{1,6}\s+(.+)$/m);
- const title = headerMatch ? headerMatch[1] : (finalSlug.startsWith('_') ? finalSlug.slice(1) : finalSlug);
-
- // Remove the first header from content so it's not rendered twice
- const content = headerMatch
- ? rawContent.replace(headerMatch[0], "").trim()
- : rawContent;
-
- const coverImage = await getCoverImage(finalSlug);
-
- return {
- content,
- title,
- slug: finalSlug,
- coverImage,
- lang: language
- };
- } catch (e) {
- console.error(`Error processing content for ${finalSlug}`, e);
- throw error(404, "Page not found");
- }
-};
\ No newline at end of file
diff --git a/src/routes/[[lang=lang]]/[slug]/+page.svelte b/src/routes/[[lang=lang]]/[slug]/+page.svelte
deleted file mode 100644
index 7373213..0000000
--- a/src/routes/[[lang=lang]]/[slug]/+page.svelte
+++ /dev/null
@@ -1,46 +0,0 @@
-
-
-
- {data.title} - schreifuchs.ch
-
-
-
-
- {data.title}
-
-
-
-
-
-
\ No newline at end of file
diff --git a/src/routes/assets/[...path]/+server.ts b/src/routes/assets/[...path]/+server.ts
deleted file mode 100644
index c58be55..0000000
--- a/src/routes/assets/[...path]/+server.ts
+++ /dev/null
@@ -1,136 +0,0 @@
-// src/routes/assets/[...path]/+server.ts
-import { client } from "$lib/server/nextcloud";
-import { error } from "@sveltejs/kit";
-import type { RequestHandler } from "./$types";
-import mime from "mime-types";
-import { env } from "$env/dynamic/private";
-import { withCache } from "$lib/server/cache";
-
-const DEFAULT_TTL = 1000 * 60 * 15; // 15min
-const EXTENDED_TTL = 1000 * 60 * 60 * 24 * 7; // 1 week
-
-// Define what we are storing in the cache
-type CachedAsset = {
- buffer: ArrayBuffer;
- contentType: string;
-};
-
-export const GET: RequestHandler = async ({ params, url }) => {
- const { path } = params;
- const width = url.searchParams.get("w");
- const height = url.searchParams.get("h");
-
- if (!path) {
- throw error(400, "Path is required");
- }
-
- // 1. Create a unique cache key for this specific asset variation
- const cacheKey = `asset:${path}?w=${width ?? ""}&h=${height ?? ""}`;
-
- const ttl = path.toString().includes("cover") ? DEFAULT_TTL : EXTENDED_TTL;
-
- try {
- // 2. Use withCache to wrap the fetching logic
- const cachedData = await withCache(
- cacheKey,
- async () => {
- // --- START OF FETCH LOGIC ---
- // This function only runs if the data is NOT in the cache
-
- const pathsToTry = [path];
- if (!path.startsWith("_")) {
- pathsToTry.push(`_${path}`);
- }
- let lastError: any = null;
-
- for (const currentPath of pathsToTry) {
- try {
- // A. Try Nextcloud Preview (Resizing)
- if (width || height) {
- const baseUrl = env.NEXTCLOUD_URL?.endsWith("/")
- ? env.NEXTCLOUD_URL
- : `${env.NEXTCLOUD_URL}/`;
-
- let fullPath = currentPath;
- if (env.NEXTCLOUD_BASE_DIR) {
- const baseDir = env.NEXTCLOUD_BASE_DIR.replace(
- /^\/+|\/+$/g,
- "",
- );
- fullPath = baseDir ? `${baseDir}/${currentPath}` : currentPath;
- }
-
- const isJpg = fullPath.match(/\.(jpg|jpeg)$/i);
- const previewExtension = isJpg ? "jpg" : "png";
- const previewUrl = new URL(
- `${baseUrl}index.php/core/preview.${previewExtension}`,
- );
-
- const fileParam = fullPath.startsWith("/")
- ? fullPath
- : `/${fullPath}`;
- previewUrl.searchParams.set("file", fileParam);
- if (width) previewUrl.searchParams.set("x", width);
- if (height) previewUrl.searchParams.set("y", height);
- previewUrl.searchParams.set("forceIcon", "0");
-
- const auth = Buffer.from(
- `${env.NEXTCLOUD_USER}:${env.NEXTCLOUD_PASSWORD}`,
- ).toString("base64");
-
- console.log(
- `Fetching preview: ${previewUrl.toString()} for file: ${fullPath}`,
- );
-
- const ncResponse = await fetch(previewUrl.toString(), {
- headers: { Authorization: `Basic ${auth}` },
- });
-
- if (ncResponse.ok) {
- const buffer = await ncResponse.arrayBuffer();
- const contentType =
- ncResponse.headers.get("Content-Type") || "image/png";
-
- // Return the raw data to be cached
- return { buffer, contentType };
- } else {
- console.warn(
- `Nextcloud preview failed (${ncResponse.status}) for ${fullPath}.`,
- );
- }
- }
-
- // B. Try WebDAV (Original)
- console.log(`Fetching original file via WebDAV: /${currentPath}`);
- const data = await client.getFileContents("/" + currentPath);
- const buffer = data as ArrayBuffer;
- const contentType =
- mime.lookup(currentPath) || "application/octet-stream";
-
- // Return the raw data to be cached
- return { buffer, contentType };
- } catch (e) {
- lastError = e;
- continue; // Try next path variant
- }
- }
-
- throw lastError || new Error("Asset not found");
- // --- END OF FETCH LOGIC ---
- },
- ttl,
- );
-
- // 3. Construct a fresh Response using the cached data
- return new Response(cachedData.buffer, {
- headers: {
- "Content-Type": cachedData.contentType,
- "Cache-Control": "public, max-age=86400", // Browser cache
- Vary: "Accept-Encoding",
- },
- });
- } catch (e) {
- console.error(`Error fetching asset: ${path}`, e);
- throw error(404, "Asset not found");
- }
-};
diff --git a/svelte.config.js b/svelte.config.js
deleted file mode 100644
index 302933d..0000000
--- a/svelte.config.js
+++ /dev/null
@@ -1,11 +0,0 @@
-import adapter from '@sveltejs/adapter-node';
-import { sveltePreprocess } from 'svelte-preprocess';
-import { vitePreprocess } from '@sveltejs/vite-plugin-svelte';
-/** @type {import('@sveltejs/kit').Config} */
-const config = {
- kit: {
- adapter: adapter()
- },
- preprocess: [vitePreprocess(), sveltePreprocess({})]
-};
-export default config;
diff --git a/tailwind.config.js b/tailwind.config.js
deleted file mode 100644
index 96955a6..0000000
--- a/tailwind.config.js
+++ /dev/null
@@ -1,29 +0,0 @@
-import plugin from "tailwindcss/plugin"
-/** @type {import('tailwindcss').Config} */
-export default {
- content: ['./src/**/*.{html,js,svelte,ts}'],
- theme: {
- extend: {
- fontFamily: {
- sans: ['Outfit', 'outfit', 'sans-serif']
- },
- textShadow: {
- sm: '0 1px 2px #000',
- DEFAULT: '0 2px 4px #000',
- lg: '0px 0px 20px #000',
- },
- },
- },
- plugins: [
- plugin(function({ matchUtilities, theme }) {
- matchUtilities(
- {
- 'text-shadow': (value) => ({
- textShadow: value,
- }),
- },
- { values: theme('textShadow') }
- )
- }),
- ],
-}
diff --git a/tmp/build-errors.log b/tmp/build-errors.log
new file mode 100644
index 0000000..dbbb0bf
--- /dev/null
+++ b/tmp/build-errors.log
@@ -0,0 +1 @@
+exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1
\ No newline at end of file
diff --git a/tmp/main b/tmp/main
new file mode 100755
index 0000000..bd6daeb
Binary files /dev/null and b/tmp/main differ
diff --git a/vite.config.js b/vite.config.js
deleted file mode 100644
index e2a48e7..0000000
--- a/vite.config.js
+++ /dev/null
@@ -1,13 +0,0 @@
-import { paraglide } from '@inlang/paraglide-sveltekit/vite';
-import { sveltekit } from '@sveltejs/kit/vite';
-import { defineConfig } from 'vite';
-
-export default defineConfig({
- plugins: [
- paraglide({
- project: './project.inlang',
- outdir: './src/lib/paraglide'
- }),
- sveltekit()
- ]
-});
diff --git a/web/components/hello.templ b/web/components/hello.templ
new file mode 100644
index 0000000..e124443
--- /dev/null
+++ b/web/components/hello.templ
@@ -0,0 +1,5 @@
+package components
+
+templ Hello() {
+ Hello World
+}
diff --git a/web/components/hello_templ.go b/web/components/hello_templ.go
new file mode 100644
index 0000000..165fd99
--- /dev/null
+++ b/web/components/hello_templ.go
@@ -0,0 +1,40 @@
+// Code generated by templ - DO NOT EDIT.
+
+// templ: version: v0.3.977
+package components
+
+//lint:file-ignore SA4006 This context is only used if a nested component is present.
+
+import "github.com/a-h/templ"
+import templruntime "github.com/a-h/templ/runtime"
+
+func Hello() templ.Component {
+ return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
+ templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
+ if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
+ return templ_7745c5c3_CtxErr
+ }
+ templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
+ if !templ_7745c5c3_IsBuffer {
+ defer func() {
+ templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
+ if templ_7745c5c3_Err == nil {
+ templ_7745c5c3_Err = templ_7745c5c3_BufErr
+ }
+ }()
+ }
+ ctx = templ.InitializeContext(ctx)
+ templ_7745c5c3_Var1 := templ.GetChildren(ctx)
+ if templ_7745c5c3_Var1 == nil {
+ templ_7745c5c3_Var1 = templ.NopComponent
+ }
+ ctx = templ.ClearChildren(ctx)
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 1, "Hello World
")
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ return nil
+ })
+}
+
+var _ = templruntime.GeneratedTemplate
diff --git a/web/layouts/base.templ b/web/layouts/base.templ
new file mode 100644
index 0000000..7d4840b
--- /dev/null
+++ b/web/layouts/base.templ
@@ -0,0 +1,18 @@
+package layouts
+
+templ Base(title string) {
+
+
+
+
+
+ { title }
+
+
+
+
+ { children... }
+
+
+
+}
diff --git a/web/layouts/base_templ.go b/web/layouts/base_templ.go
new file mode 100644
index 0000000..9e6e862
--- /dev/null
+++ b/web/layouts/base_templ.go
@@ -0,0 +1,61 @@
+// Code generated by templ - DO NOT EDIT.
+
+// templ: version: v0.3.977
+package layouts
+
+//lint:file-ignore SA4006 This context is only used if a nested component is present.
+
+import "github.com/a-h/templ"
+import templruntime "github.com/a-h/templ/runtime"
+
+func Base(title string) templ.Component {
+ return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
+ templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
+ if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
+ return templ_7745c5c3_CtxErr
+ }
+ templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
+ if !templ_7745c5c3_IsBuffer {
+ defer func() {
+ templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
+ if templ_7745c5c3_Err == nil {
+ templ_7745c5c3_Err = templ_7745c5c3_BufErr
+ }
+ }()
+ }
+ ctx = templ.InitializeContext(ctx)
+ templ_7745c5c3_Var1 := templ.GetChildren(ctx)
+ if templ_7745c5c3_Var1 == nil {
+ templ_7745c5c3_Var1 = templ.NopComponent
+ }
+ ctx = templ.ClearChildren(ctx)
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 1, "")
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ var templ_7745c5c3_Var2 string
+ templ_7745c5c3_Var2, templ_7745c5c3_Err = templ.JoinStringErrs(title)
+ if templ_7745c5c3_Err != nil {
+ return templ.Error{Err: templ_7745c5c3_Err, FileName: `layouts/base.templ`, Line: 9, Col: 17}
+ }
+ _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var2))
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 2, "")
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ templ_7745c5c3_Err = templ_7745c5c3_Var1.Render(ctx, templ_7745c5c3_Buffer)
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 3, "")
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ return nil
+ })
+}
+
+var _ = templruntime.GeneratedTemplate
diff --git a/web/pages/index.templ b/web/pages/index.templ
new file mode 100644
index 0000000..5303e34
--- /dev/null
+++ b/web/pages/index.templ
@@ -0,0 +1,12 @@
+package pages
+
+import (
+ "git.schreifuchs.ch/schreifuchs/schreifuchs.ch/web/layouts"
+ "git.schreifuchs.ch/schreifuchs/schreifuchs.ch/web/components"
+)
+
+templ Index() {
+ @layouts.Base("Home") {
+ @components.Hello()
+ }
+}
diff --git a/web/pages/index_templ.go b/web/pages/index_templ.go
new file mode 100644
index 0000000..aa2c421
--- /dev/null
+++ b/web/pages/index_templ.go
@@ -0,0 +1,63 @@
+// Code generated by templ - DO NOT EDIT.
+
+// templ: version: v0.3.977
+package pages
+
+//lint:file-ignore SA4006 This context is only used if a nested component is present.
+
+import "github.com/a-h/templ"
+import templruntime "github.com/a-h/templ/runtime"
+
+import (
+ "git.schreifuchs.ch/schreifuchs/schreifuchs.ch/web/components"
+ "git.schreifuchs.ch/schreifuchs/schreifuchs.ch/web/layouts"
+)
+
+func Index() templ.Component {
+ return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
+ templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
+ if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
+ return templ_7745c5c3_CtxErr
+ }
+ templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
+ if !templ_7745c5c3_IsBuffer {
+ defer func() {
+ templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
+ if templ_7745c5c3_Err == nil {
+ templ_7745c5c3_Err = templ_7745c5c3_BufErr
+ }
+ }()
+ }
+ ctx = templ.InitializeContext(ctx)
+ templ_7745c5c3_Var1 := templ.GetChildren(ctx)
+ if templ_7745c5c3_Var1 == nil {
+ templ_7745c5c3_Var1 = templ.NopComponent
+ }
+ ctx = templ.ClearChildren(ctx)
+ templ_7745c5c3_Var2 := templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
+ templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
+ templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
+ if !templ_7745c5c3_IsBuffer {
+ defer func() {
+ templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
+ if templ_7745c5c3_Err == nil {
+ templ_7745c5c3_Err = templ_7745c5c3_BufErr
+ }
+ }()
+ }
+ ctx = templ.InitializeContext(ctx)
+ templ_7745c5c3_Err = components.Hello().Render(ctx, templ_7745c5c3_Buffer)
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ return nil
+ })
+ templ_7745c5c3_Err = layouts.Base("Home").Render(templ.WithChildren(ctx, templ_7745c5c3_Var2), templ_7745c5c3_Buffer)
+ if templ_7745c5c3_Err != nil {
+ return templ_7745c5c3_Err
+ }
+ return nil
+ })
+}
+
+var _ = templruntime.GeneratedTemplate
diff --git a/web/resource.go b/web/resource.go
new file mode 100644
index 0000000..55eced8
--- /dev/null
+++ b/web/resource.go
@@ -0,0 +1,19 @@
+//go:generate go tool templ generate
+package web
+
+import (
+ "embed"
+ "io/fs"
+)
+
+//go:embed static/*
+var Static embed.FS
+
+func GetStaticFS() fs.FS {
+ // fs.Sub returns an fs.FS corresponding to the subtree rooted at "static"
+ f, err := fs.Sub(Static, "static")
+ if err != nil {
+ panic(err)
+ }
+ return f
+}
diff --git a/static/favicon.png b/web/static/favicon.png
similarity index 100%
rename from static/favicon.png
rename to web/static/favicon.png
diff --git a/static/robots.txt b/web/static/robots.txt
similarity index 100%
rename from static/robots.txt
rename to web/static/robots.txt