commit 364ffa15dee8e7f7b49c3ceed656a6d3fd554b8d Author: prettysunflower Date: Thu May 22 18:08:15 2025 +0200 Initial commit diff --git a/.gitea/workflows/docker_build.yaml b/.gitea/workflows/docker_build.yaml new file mode 100644 index 0000000..abfa6ea --- /dev/null +++ b/.gitea/workflows/docker_build.yaml @@ -0,0 +1,33 @@ +name: Build Docker images + +on: + workflow_dispatch: + push: + branches: [ "main" ] + tags: [ "*" ] + +jobs: + acls: + runs-on: ubuntu-latest + + steps: + - + name: Checkout + uses: actions/checkout@v4 + - + name: Setup Go + uses: actions/setup-go@v5 + with: + go-version: '1.24.3' + + - uses: ko-build/setup-ko@v0.8 + with: + version: v0.18.0 + env: + KO_DOCKER_REPO: git.prettysunflower.moe/prettysunflower + + - env: + auth_token: ${{ secrets.HUB_TOKEN }} + run: | + echo "${auth_token}" | ko login git.prettysunflower.moe --username ${{ vars.HUB_USERNAME }} --password-stdin + ko build -B \ No newline at end of file diff --git a/.gitea/workflows/static_docker_build.yaml b/.gitea/workflows/static_docker_build.yaml new file mode 100644 index 0000000..57bbcb0 --- /dev/null +++ b/.gitea/workflows/static_docker_build.yaml @@ -0,0 +1,45 @@ +name: Build Docker images for static folder + +on: + workflow_dispatch: + push: + branches: [ "main" ] + tags: [ "*" ] + +defaults: + run: + working-directory: static + +jobs: + acls: + runs-on: ubuntu-latest + + steps: + - + name: Docker meta + id: meta + uses: docker/metadata-action@v5 + with: + images: git.prettysunflower.moe/prettysunflower/website-static + - + name: Login to Gitea Container Hub + uses: docker/login-action@v3 + with: + registry: git.prettysunflower.moe + username: ${{ vars.HUB_USERNAME }} + password: ${{ secrets.HUB_TOKEN }} + - + name: Set up QEMU + uses: docker/setup-qemu-action@v3 + - + name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + - + name: Build and push + uses: docker/build-push-action@v6 + with: + context: "{{defaultContext}}:static" + push: ${{ gitea.event_name != 'pull_request' }} + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + platforms: linux/amd64,linux/arm64 \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..bd7f139 --- /dev/null +++ b/.gitignore @@ -0,0 +1,26 @@ +# If you prefer the allow list template instead of the deny list, see community template: +# https://github.com/github/gitignore/blob/main/community/Golang/Go.AllowList.gitignore +# +# Binaries for programs and plugins +*.exe +*.exe~ +*.dll +*.so +*.dylib +build/ + +# Test binary, built with `go test -c` +*.test + +# Output of the go coverage tool, specifically when used with LiteIDE +*.out + +# Dependency directories (remove the comment below to include it) +# vendor/ + +# Go workspace file +go.work +go.work.sum + +# env file +.env \ No newline at end of file diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..13566b8 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,8 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Editor-based HTTP Client requests +/httpRequests/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..c351cd0 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/.idea/prettysunflower-website.iml b/.idea/prettysunflower-website.iml new file mode 100644 index 0000000..5e764c4 --- /dev/null +++ b/.idea/prettysunflower-website.iml @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.ko.yaml b/.ko.yaml new file mode 100644 index 0000000..e5b8ac7 --- /dev/null +++ b/.ko.yaml @@ -0,0 +1,11 @@ +defaultBaseImage: cgr.dev/chainguard/static +defaultPlatforms: + - linux/arm64 + - linux/amd64 + - linux/arm/v7 + +builds: + - id: website + main: . + ldflags: + - -s -w \ No newline at end of file diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..169f7e0 --- /dev/null +++ b/go.mod @@ -0,0 +1,3 @@ +module prettysunflower-website + +go 1.24 diff --git a/keys/init.go b/keys/init.go new file mode 100644 index 0000000..2894291 --- /dev/null +++ b/keys/init.go @@ -0,0 +1,28 @@ +package keys + +import ( + "io" + "net/http" +) + +func InitHttpHandlers() { + http.HandleFunc("/ssh/", sshKey) + http.HandleFunc("/age/", ageKey) + http.HandleFunc("/gpg/", gpgKey) + http.HandleFunc("/gpg/koumbit/", gpgKey) +} + +func sshKey(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Content-Type", "text/plain") + _, _ = io.WriteString(w, SSH_KEY) +} + +func ageKey(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Content-Type", "text/plain") + _, _ = io.WriteString(w, AGE_KEY) +} + +func gpgKey(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Content-Type", "text/plain") + _, _ = io.WriteString(w, GPG_KEY) +} diff --git a/keys/keys.go b/keys/keys.go new file mode 100644 index 0000000..49e9e15 --- /dev/null +++ b/keys/keys.go @@ -0,0 +1,28 @@ +package keys + +const SSH_KEY = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIKK/ydi3HD1cHP40hlYP3EU+h55rAj+nHkLhzcClHStj me@prettysunflower.moe" +const AGE_KEY = "age1r0tjhg6uexyj0p7fp0ftv5h7r7e3ptzkk2797pznfvrvsm576u0s37yyaw" +const GPG_KEY = `-----BEGIN PGP PUBLIC KEY BLOCK----- +Comment: 13EE 61FF 762C 86C7 FC92 71A4 ED9D 604F 0092 91F4 +Comment: Remilia Da Costa Faro +Comment: Remilia Da Costa Faro + +xjMEZ3w3SBYJKwYBBAHaRw8BAQdAcIpRU4WrTXDfljp/1PSE1fgPDAbOG/Fj/Dqb +hLYx1orNK1JlbWlsaWEgRGEgQ29zdGEgRmFybyA8cmVtaWxpYUBrb3VtYml0Lm9y +Zz7CjwQTFggANwUJBaOagAIbAwQLCQgHBRUICQoLBRYCAwEAFiEEE+5h/3Yshsf8 +knGk7Z1gTwCSkfQFAmf+RF0ACgkQ7Z1gTwCSkfT4OQD+KetHdN1L/M7TmFZ+Nbhz +a5XBOmeYT3vpq8aKg0lcG+EA/RVwKvvzgqTzd1zBmgP7gqvFaFXZMlo0VVfsSrCJ +9uANwo8EExYIADcWIQQT7mH/diyGx/yScaTtnWBPAJKR9AUCZ3w3SAUJBaOagAIb +AwQLCQgHBRUICQoLBRYCAwEAAAoJEO2dYE8AkpH0nFgBAPW5fDQxAH8/Pr8ByvAs +CNoCqPIKqvre3U6+JgvsQ/gFAP0arX0+IOjpfFiXCvnYEWMiL2RLi9T45DHrMN1V +n341Bs0qUmVtaWxpYSBEYSBDb3N0YSBGYXJvIDxyZW1pbGlhQHJlbWlsaWEuY2g+ +wpwEExYKAEQCGwMFCQWjmoAFCwkIBwICIgIGFQoJCAsCBBYCAwECHgcCF4AWIQQT +7mH/diyGx/yScaTtnWBPAJKR9AUCZ/5EXQIZAQAKCRDtnWBPAJKR9N/jAP9C9Lci +uRCwd9WxWbXlQBCdZI8h/0GFlnkOdY4O5nPzLQD/dz2raMl7pp9H7KL5r3ashOYo +wwdGr1H1EEYyDFR9UAnOOARnfDdIEgorBgEEAZdVAQUBAQdAzUl/nTzragxZUHQ3 +HmmT0XfGgaNWKXuS1FAOI3KP6jkDAQgHwn4EGBYIACYWIQQT7mH/diyGx/yScaTt +nWBPAJKR9AUCZ3w3SAUJBaOagAIbDAAKCRDtnWBPAJKR9MEaAP9TBEiI63CLyIr1 +6qhFwlEsiPOQS/hIYOoHJG1OPUZMfQEA3IvzRpZzFIb/pR4VvF+Zpddm1GD8yh0r +IvOz2WQApgI= +=mMXG +-----END PGP PUBLIC KEY BLOCK-----` diff --git a/main.go b/main.go new file mode 100644 index 0000000..e5d6f64 --- /dev/null +++ b/main.go @@ -0,0 +1,18 @@ +package main + +import ( + "net/http" + "prettysunflower-website/keys" + "prettysunflower-website/pages" + "prettysunflower-website/radio" + "prettysunflower-website/static" +) + +func main() { + pages.InitHttpHandlers() + radio.InitHttpHandlers() + static.InitHttpHandlers() + keys.InitHttpHandlers() + + _ = http.ListenAndServe(":3334", nil) +} diff --git a/pages/email_autoconfig.go b/pages/email_autoconfig.go new file mode 100644 index 0000000..435ca34 --- /dev/null +++ b/pages/email_autoconfig.go @@ -0,0 +1,38 @@ +package pages + +import ( + "html/template" + "net/http" +) + +type EmailAutoconfigTemplateData struct { + Domain string + DisplayName string + ShortDisplayName string + ImapServer string + PopServer string + SmtpServer string +} + +func emailAutoconfig(w http.ResponseWriter, r *http.Request) { + templateFile := "templates/email_autoconfig.tmpl" + files, err := template.New(templateFile).ParseFS(content, templateFile) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + + err = files.ExecuteTemplate(w, "email_autoconfig.tmpl", EmailAutoconfigTemplateData{ + Domain: "prettysunflower.moe", + DisplayName: "prettysunflower's mail server", + ShortDisplayName: "prettysunflower", + ImapServer: "mail.prettysunflower.moe", + PopServer: "mail.prettysunflower.moe", + SmtpServer: "mail.prettysunflower.moe", + }) + + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } +} diff --git a/pages/init.go b/pages/init.go new file mode 100644 index 0000000..84ba77c --- /dev/null +++ b/pages/init.go @@ -0,0 +1,32 @@ +package pages + +import ( + "embed" + "html/template" + "net/http" +) + +//go:embed templates/* +var content embed.FS + +func InitHttpHandlers() { + http.HandleFunc("/{$}", homepage) + http.HandleFunc("/.well-known/autoconfig/mail/config-v1.1.xml", emailAutoconfig) + http.HandleFunc("/mail/config-v1.1.xml", emailAutoconfig) +} + +func homepage(w http.ResponseWriter, r *http.Request) { + templateFile := "templates/homepage.tmpl" + files, err := template.New(templateFile).ParseFS(content, templateFile) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + + err = files.ExecuteTemplate(w, "homepage.tmpl", nil) + + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } +} diff --git a/pages/templates/email_autoconfig.tmpl b/pages/templates/email_autoconfig.tmpl new file mode 100644 index 0000000..3e6c9b4 --- /dev/null +++ b/pages/templates/email_autoconfig.tmpl @@ -0,0 +1,28 @@ + + + {{ .Domain }} + {{ .DisplayName }} + {{ .ShortDisplayName }} + + {{ .ImapServer }} + 993 + SSL + password-cleartext + %EMAILADDRESS% + + + {{ .PopServer }} + 995 + SSL + password-cleartext + %EMAILADDRESS% + + + {{ .SmtpServer }} + 587 + STARTTLS + password-cleartext + %EMAILADDRESS% + + + \ No newline at end of file diff --git a/pages/templates/homepage.tmpl b/pages/templates/homepage.tmpl new file mode 100644 index 0000000..1ad6052 --- /dev/null +++ b/pages/templates/homepage.tmpl @@ -0,0 +1,78 @@ + + + + + + prettysunflower + + + +
+
+ Avatar of prettysunflower + +
+

prettysunflower

+

+ Nyallo! We're Remilia, Xeon, and Takeno! +

+

+ We're a system of 3, we're software and website developers at + the Réseau Koumbit, we're Touhou and Factorio players, + and we're your local trans women/enby/plural person wishing you a good day! +

+
+
+
+ +
+
+
+

Our pronouns 🏳️‍⚧

+ +

+ Remilia: they/them and she/her
+ Xeon: they/them
+ Takeno: she/her +

+
+ +
+

The ways to contact us

+

+ me@prettysunflower.moe
+ Bluesky
+ Fediverse +

+
+ +
+

Our code

+

+ Gitea
+ GitHub +

+
+
+ +
+ +
+

Our main projects

+ +
+ + +
+

Kakigoori

+

+ Kakigoori is an picture distribution system to publish images on the web. + Upload it once, and Kakigoori will create versions of the image + optimized for the web (AVIF, WebP). +

+
+
+
+
+ + \ No newline at end of file diff --git a/radio/init.go b/radio/init.go new file mode 100644 index 0000000..5d40c33 --- /dev/null +++ b/radio/init.go @@ -0,0 +1,15 @@ +package radio + +import ( + "embed" + "fmt" + "net/http" +) + +//go:embed templates/* +var content embed.FS + +func InitHttpHandlers() { + prefix := "/radio/" + http.HandleFunc(fmt.Sprint(prefix, "trains"), trains) +} diff --git a/radio/playlist.go b/radio/playlist.go new file mode 100644 index 0000000..54abfa1 --- /dev/null +++ b/radio/playlist.go @@ -0,0 +1,130 @@ +package radio + +import ( + "encoding/json" + "fmt" + "io" + "net/http" + "net/url" + "os" + "time" +) + +type YoutubeChannel struct { + Id string + Name string +} + +type PlaylistItem struct { + Etag string + Id string + PublishedAt time.Time + Channel YoutubeChannel + VideoId string + Title string + Description string + ThumbnailUrl string + Position int +} + +type PlaylistResponseSnippet struct { + PublishedAt string `json:"publishedAt"` + VideoOwnerChannelId string `json:"videoOwnerChannelId"` + VideoOwnerChannelTitle string `json:"videoOwnerChannelTitle"` + ResourceId PlaylistResponseResourceId `json:"resourceId"` + Title string `json:"title"` + Description string `json:"description"` + Position int `json:"position"` +} + +type PlaylistResponseItem struct { + Etag string `json:"etag"` + Id string `json:"id"` + Snippet PlaylistResponseSnippet `json:"snippet"` +} + +type PlaylistResponseResourceId struct { + VideoId string `json:"videoId"` +} + +type PlaylistResponse struct { + Items []PlaylistResponseItem `json:"items"` + NextPageToken string `json:"nextPageToken"` +} + +func requestYouTubePlaylist(playlistId string, pageToken string) ([]PlaylistItem, string) { + apiUrl, err := url.Parse("https://www.googleapis.com/youtube/v3/playlistItems") + if err != nil { + panic(err) + } + + q := apiUrl.Query() + q.Add("key", os.Getenv("GOOGLE_API_KEY")) + q.Add("playlistId", playlistId) + q.Add("part", "id,snippet,contentDetails,status") + q.Add("maxResults", "50") + + if pageToken != "" { + q.Add("pageToken", pageToken) + } + + apiUrl.RawQuery = q.Encode() + + response, err := http.Get(apiUrl.String()) + if err != nil { + return nil, "" + } + + body, err := io.ReadAll(response.Body) + if err != nil { + return nil, "" + } + + //type playlistResponse PlaylistResponse + var playlistItems PlaylistResponse + err = json.Unmarshal(body, &playlistItems) + if err != nil { + return nil, "" + } + + var items []PlaylistItem + for _, item := range playlistItems.Items { + publishedAt, err := time.Parse(time.RFC3339, item.Snippet.PublishedAt) + if err != nil { + panic(err) + } + + items = append(items, PlaylistItem{ + Etag: item.Etag, + Id: item.Id, + PublishedAt: publishedAt, + VideoId: item.Snippet.ResourceId.VideoId, + Title: item.Snippet.Title, + Description: item.Snippet.Description, + ThumbnailUrl: fmt.Sprint("https://youtubethumbnails.prettysunflower.moe/", item.Snippet.ResourceId.VideoId), + Position: item.Snippet.Position, + Channel: YoutubeChannel{ + Id: item.Snippet.VideoOwnerChannelId, + Name: item.Snippet.VideoOwnerChannelTitle, + }, + }) + } + + return items, playlistItems.NextPageToken +} + +func getPlaylistOfVideos(playlistId string) []PlaylistItem { + var playlistItems []PlaylistItem + nextPageToken := "" + + for { + newItems, newNextPageToken := requestYouTubePlaylist(playlistId, nextPageToken) + playlistItems = append(playlistItems, newItems...) + + if newNextPageToken == "" { + return playlistItems + } + + nextPageToken = newNextPageToken + } +} diff --git a/radio/templates/trains.tmpl b/radio/templates/trains.tmpl new file mode 100644 index 0000000..39556bd --- /dev/null +++ b/radio/templates/trains.tmpl @@ -0,0 +1,56 @@ + + + + + + prettysunflower - The trains radio + + + +
+ +
+ +

The trains radio

+ +
+ {{ range .PlaylistItems }} + + {{ end }} +
+ + + + \ No newline at end of file diff --git a/radio/trains.go b/radio/trains.go new file mode 100644 index 0000000..2c6f1aa --- /dev/null +++ b/radio/trains.go @@ -0,0 +1,34 @@ +package radio + +import ( + "html/template" + "math/rand" + "net/http" +) + +type TrainsTemplateData struct { + PlaylistItems []PlaylistItem +} + +func trains(w http.ResponseWriter, r *http.Request) { + trainsPlaylist := getPlaylistOfVideos("PLZoWUOSrw9RfbTAwQ1pTg3rZD-jZJHd9S") + rand.Shuffle(len(trainsPlaylist), func(i, j int) { + trainsPlaylist[i], trainsPlaylist[j] = trainsPlaylist[j], trainsPlaylist[i] + }) + + templateFile := "templates/trains.tmpl" + files, err := template.New(templateFile).ParseFS(content, templateFile) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + + err = files.ExecuteTemplate(w, "trains.tmpl", TrainsTemplateData{ + PlaylistItems: trainsPlaylist, + }) + + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } +} diff --git a/static/Caddyfile b/static/Caddyfile new file mode 100644 index 0000000..2683efa --- /dev/null +++ b/static/Caddyfile @@ -0,0 +1,4 @@ +:8001 { + root * /srv/ + file_server +} \ No newline at end of file diff --git a/static/Dockerfile b/static/Dockerfile new file mode 100644 index 0000000..5fb1bf5 --- /dev/null +++ b/static/Dockerfile @@ -0,0 +1,4 @@ +FROM caddy:latest + +COPY Caddyfile /etc/caddy/Caddyfile +COPY static/ /srv/ \ No newline at end of file diff --git a/static/noStatic.go b/static/noStatic.go new file mode 100644 index 0000000..6840801 --- /dev/null +++ b/static/noStatic.go @@ -0,0 +1,5 @@ +//go:build !serveStatic + +package static + +func InitHttpHandlers() {} diff --git a/static/serveStatic.go b/static/serveStatic.go new file mode 100644 index 0000000..dd172c3 --- /dev/null +++ b/static/serveStatic.go @@ -0,0 +1,16 @@ +//go:build serveStatic + +package static + +import ( + "embed" + "net/http" +) + +//go:embed static/* +var staticFS embed.FS + +func InitHttpHandlers() { + fs := http.FileServerFS(staticFS) + http.Handle("/static/", http.StripPrefix("/static", fs)) +} diff --git a/static/static/css/body.scss b/static/static/css/body.scss new file mode 100644 index 0000000..0ba60f9 --- /dev/null +++ b/static/static/css/body.scss @@ -0,0 +1,8 @@ +@use "fonts"; +@use "colors"; + +body { + font-family: fonts.$font-stack; + background-color: colors.$background-color; + margin: 0; +} \ No newline at end of file diff --git a/static/static/css/colors.scss b/static/static/css/colors.scss new file mode 100644 index 0000000..b5e3178 --- /dev/null +++ b/static/static/css/colors.scss @@ -0,0 +1 @@ +$background-color: oklch(0.97 0.0261 90.1); \ No newline at end of file diff --git a/static/static/css/fonts.scss b/static/static/css/fonts.scss new file mode 100644 index 0000000..7cfb64d --- /dev/null +++ b/static/static/css/fonts.scss @@ -0,0 +1,3 @@ +@import url('https://fonts.googleapis.com/css2?family=Open+Sans:ital,wght@0,300..800;1,300..800&display=swap'); + +$font-stack: "Open Sans", apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"; \ No newline at end of file diff --git a/static/static/css/index.scss b/static/static/css/index.scss new file mode 100644 index 0000000..aecb19c --- /dev/null +++ b/static/static/css/index.scss @@ -0,0 +1,48 @@ +@use "layout"; + +.page-index { + header { + width: 100%; + height: 75vh; + background-image: url('https://kakigoori.dev/c152e805-b859-4ad0-817c-4d671e5f15ad/auto'); + background-size: cover; + background-position: top center; + display: flex; + justify-content: center; + align-items: center; + + & > div { + display: flex; + justify-content: center; + align-items: center; + gap: 2rem; + width: min(80%, 800px); + margin: 0 auto; + padding: 2rem; + background-color: rgba(255, 255, 255, 0.5); + backdrop-filter: blur(15px); + border-radius: 1rem; + } + + img { + height: 200px; + border-radius: 50%; + } + } + + hr { + @include layout.light-hr; + } + + .columns { + h2 { + text-align: center; + } + } + + .main-projects { + & > div { + display: flex; + } + } +} \ No newline at end of file diff --git a/static/static/css/layout.scss b/static/static/css/layout.scss new file mode 100644 index 0000000..51ee906 --- /dev/null +++ b/static/static/css/layout.scss @@ -0,0 +1,10 @@ +.columns { + display: flex; + flex-wrap: wrap; + gap: 1rem; + justify-content: space-evenly; +} + +@mixin light-hr($height: .5px, $color: oklch(75% 0 0deg)) { + border: $height solid $color; +} \ No newline at end of file diff --git a/static/static/css/radio.scss b/static/static/css/radio.scss new file mode 100644 index 0000000..e3929ce --- /dev/null +++ b/static/static/css/radio.scss @@ -0,0 +1,60 @@ +@use "colors"; + +.page-radio-trains { + .video-zone { + display: flex; + justify-content: center; + align-items: center; + padding: 1rem; + + #video-player { + aspect-ratio: 16 / 9; + max-width: 80%; + max-height: 50vh; + width: 100%; + } + } + + h1 { + padding: 0 1rem; + text-align: center; + } + + main { + display: grid; + gap: 1rem; + padding: 1rem; + grid-template-columns: repeat(4, 1fr); + + & > div { + img { + width: 100%; + } + + &.active { + background-color: oklch(from colors.$background-color calc(l - 0.05) c h); + } + + p { + margin: .5em; + + a { + text-decoration: none; + color: black; + } + } + } + + @media screen and (max-width: 992px) { + grid-template-columns: repeat(3, 1fr); + } + + @media screen and (max-width: 768px) { + grid-template-columns: repeat(2, 1fr); + } + + @media screen and (max-width: 576px) { + grid-template-columns: 1fr; + } + } +} \ No newline at end of file diff --git a/static/static/css/style.css b/static/static/css/style.css new file mode 100644 index 0000000..026e0eb --- /dev/null +++ b/static/static/css/style.css @@ -0,0 +1,102 @@ +@import url("https://fonts.googleapis.com/css2?family=Open+Sans:ital,wght@0,300..800;1,300..800&display=swap"); +.columns { + display: flex; + flex-wrap: wrap; + gap: 1rem; + justify-content: space-evenly; +} + +body { + font-family: "Open Sans", apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"; + background-color: oklch(97% 0.0261 90.1deg); + margin: 0; +} + +.page-index header { + width: 100%; + height: 75vh; + background-image: url("https://kakigoori.dev/c152e805-b859-4ad0-817c-4d671e5f15ad/auto"); + background-size: cover; + background-position: top center; + display: flex; + justify-content: center; + align-items: center; +} +.page-index header > div { + display: flex; + justify-content: center; + align-items: center; + gap: 2rem; + width: min(80%, 800px); + margin: 0 auto; + padding: 2rem; + background-color: rgba(255, 255, 255, 0.5); + backdrop-filter: blur(15px); + border-radius: 1rem; +} +.page-index header img { + height: 200px; + border-radius: 50%; +} +.page-index hr { + border: 0.5px solid oklch(75% 0 0deg); +} +.page-index .columns h2 { + text-align: center; +} +.page-index .main-projects > div { + display: flex; +} + +.page-radio-trains .video-zone { + display: flex; + justify-content: center; + align-items: center; + padding: 1rem; +} +.page-radio-trains .video-zone #video-player { + aspect-ratio: 16/9; + max-width: 80%; + max-height: 50vh; + width: 100%; +} +.page-radio-trains h1 { + padding: 0 1rem; + text-align: center; +} +.page-radio-trains main { + display: grid; + gap: 1rem; + padding: 1rem; + grid-template-columns: repeat(4, 1fr); +} +.page-radio-trains main > div img { + width: 100%; +} +.page-radio-trains main > div.active { + background-color: oklch(from oklch(97% 0.0261 90.1deg) calc(l - 0.05) c h); +} +.page-radio-trains main > div p { + margin: 0.5em; +} +.page-radio-trains main > div p a { + text-decoration: none; + color: black; +} +@media screen and (max-width: 992px) { + .page-radio-trains main { + grid-template-columns: repeat(3, 1fr); + } +} +@media screen and (max-width: 768px) { + .page-radio-trains main { + grid-template-columns: repeat(2, 1fr); + } +} +@media screen and (max-width: 576px) { + .page-radio-trains main { + grid-template-columns: 1fr; + } +} + +/*# sourceMappingURL=style.css.map */ diff --git a/static/static/css/style.css.map b/static/static/css/style.css.map new file mode 100644 index 0000000..ff51d6f --- /dev/null +++ b/static/static/css/style.css.map @@ -0,0 +1 @@ +{"version":3,"sourceRoot":"","sources":["fonts.scss","layout.scss","body.scss","colors.scss","index.scss","radio.scss"],"names":[],"mappings":"AAAQ;ACAR;EACI;EACA;EACA;EACA;;;ACDJ;EACI,aFFS;EEGT,kBCLe;EDMf;;;AEHA;EACI;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AAEA;EACI;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;AAGJ;EACI;EACA;;AAIR;EHxBA;;AG6BI;EACI;;AAKJ;EACI;;;ACzCR;EACI;EACA;EACA;EACA;;AAEA;EACI;EACA;EACA;EACA;;AAIR;EACI;EACA;;AAGJ;EACI;EACA;EACA;EACA;;AAGI;EACI;;AAGJ;EACI;;AAGJ;EACI;;AAEA;EACI;EACA;;AAKZ;EAzBJ;IA0BQ;;;AAGJ;EA7BJ;IA8BQ;;;AAGJ;EAjCJ;IAkCQ","file":"style.css"} \ No newline at end of file diff --git a/static/static/css/style.scss b/static/static/css/style.scss new file mode 100644 index 0000000..2aa1512 --- /dev/null +++ b/static/static/css/style.scss @@ -0,0 +1,4 @@ +@use "layout"; +@use "body"; +@use "index"; +@use "radio"; \ No newline at end of file