Skip to content

Commit 6a3bbd4

Browse files
committed
feat: photo section
Signed-off-by: Matt Gleich <[email protected]>
1 parent 91b82ef commit 6a3bbd4

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

43 files changed

+430
-101
lines changed

.vscode/settings.json

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"cSpell.words": ["blurdata"]
3+
}

scripts/photos/go.mod

+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
module go.mattglei.ch/mattglei.ch/scripts/photos
2+
3+
go 1.24.1
4+
5+
require go.mattglei.ch/timber v1.2.3
6+
7+
require (
8+
github.com/atotto/clipboard v0.1.4 // indirect
9+
github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect
10+
github.com/buckket/go-blurhash v1.1.0 // indirect
11+
github.com/charmbracelet/colorprofile v0.2.3-0.20250311203215-f60798e515dc // indirect
12+
github.com/charmbracelet/lipgloss v1.1.0 // indirect
13+
github.com/charmbracelet/x/ansi v0.8.0 // indirect
14+
github.com/charmbracelet/x/cellbuf v0.0.13 // indirect
15+
github.com/charmbracelet/x/term v0.2.1 // indirect
16+
github.com/kolesa-team/go-webp v1.0.4 // indirect
17+
github.com/lucasb-eyer/go-colorful v1.2.0 // indirect
18+
github.com/mattn/go-isatty v0.0.20 // indirect
19+
github.com/mattn/go-runewidth v0.0.16 // indirect
20+
github.com/muesli/termenv v0.16.0 // indirect
21+
github.com/rivo/uniseg v0.4.7 // indirect
22+
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect
23+
golang.org/x/sys v0.31.0 // indirect
24+
)

scripts/photos/go.sum

+47
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
github.com/atotto/clipboard v0.1.4 h1:EH0zSVneZPSuFR11BlR9YppQTVDbh5+16AmcJi4g1z4=
2+
github.com/atotto/clipboard v0.1.4/go.mod h1:ZY9tmq7sm5xIbd9bOK4onWV4S6X0u6GY7Vn0Yu86PYI=
3+
github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k=
4+
github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8=
5+
github.com/buckket/go-blurhash v1.1.0 h1:X5M6r0LIvwdvKiUtiNcRL2YlmOfMzYobI3VCKCZc9Do=
6+
github.com/buckket/go-blurhash v1.1.0/go.mod h1:aT2iqo5W9vu9GpyoLErKfTHwgODsZp3bQfXjXJUxNb8=
7+
github.com/charmbracelet/colorprofile v0.2.3-0.20250311203215-f60798e515dc h1:4pZI35227imm7yK2bGPcfpFEmuY1gc2YSTShr4iJBfs=
8+
github.com/charmbracelet/colorprofile v0.2.3-0.20250311203215-f60798e515dc/go.mod h1:X4/0JoqgTIPSFcRA/P6INZzIuyqdFY5rm8tb41s9okk=
9+
github.com/charmbracelet/lipgloss v1.1.0 h1:vYXsiLHVkK7fp74RkV7b2kq9+zDLoEU4MZoFqR/noCY=
10+
github.com/charmbracelet/lipgloss v1.1.0/go.mod h1:/6Q8FR2o+kj8rz4Dq0zQc3vYf7X+B0binUUBwA0aL30=
11+
github.com/charmbracelet/x/ansi v0.8.0 h1:9GTq3xq9caJW8ZrBTe0LIe2fvfLR/bYXKTx2llXn7xE=
12+
github.com/charmbracelet/x/ansi v0.8.0/go.mod h1:wdYl/ONOLHLIVmQaxbIYEC/cRKOQyjTkowiI4blgS9Q=
13+
github.com/charmbracelet/x/cellbuf v0.0.13 h1:/KBBKHuVRbq1lYx5BzEHBAFBP8VcQzJejZ/IA3iR28k=
14+
github.com/charmbracelet/x/cellbuf v0.0.13/go.mod h1:xe0nKWGd3eJgtqZRaN9RjMtK7xUYchjzPr7q6kcvCCs=
15+
github.com/charmbracelet/x/term v0.2.1 h1:AQeHeLZ1OqSXhrAWpYUtZyX1T3zVxfpZuEQMIQaGIAQ=
16+
github.com/charmbracelet/x/term v0.2.1/go.mod h1:oQ4enTYFV7QN4m0i9mzHrViD7TQKvNEEkHUMCmsxdUg=
17+
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
18+
github.com/kolesa-team/go-webp v1.0.4 h1:wQvU4PLG/X7RS0vAeyhiivhLRoxfLVRlDq4I3frdxIQ=
19+
github.com/kolesa-team/go-webp v1.0.4/go.mod h1:oMvdivD6K+Q5qIIkVC2w4k2ZUnI1H+MyP7inwgWq9aA=
20+
github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY=
21+
github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
22+
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
23+
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
24+
github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc=
25+
github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
26+
github.com/muesli/termenv v0.16.0 h1:S5AlUN9dENB57rsbnkPyfdGuWIlkmzJjbFf0Tf5FWUc=
27+
github.com/muesli/termenv v0.16.0/go.mod h1:ZRfOIKPFDYQoDFF4Olj7/QJbW60Ol/kL1pU3VfY/Cnk=
28+
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
29+
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
30+
github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ=
31+
github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
32+
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
33+
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
34+
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e h1:JVG44RsyaB9T2KIHavMF/ppJZNG9ZpyihvCd0w101no=
35+
github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e/go.mod h1:RbqR21r5mrJuqunuUZ/Dhy/avygyECGrLceyNeo4LiM=
36+
go.mattglei.ch/timber v1.2.3 h1:q+b+R836ct5mk6bx3XBJ/WeSby/4XmKNnMRiPlDQLH0=
37+
go.mattglei.ch/timber v1.2.3/go.mod h1:p1yxBQ4rxRxttRdcWy3mOYsKNjBn3w+JViMY+gcTOFk=
38+
golang.org/x/exp v0.0.0-20220909182711-5c715a9e8561 h1:MDc5xs78ZrZr3HMQugiXOAkSZtfTpbJLDr/lwfgO53E=
39+
golang.org/x/exp v0.0.0-20220909182711-5c715a9e8561/go.mod h1:cyybsKvd6eL0RnXn6p/Grxp8F5bW7iYuBgsNCOHpMYE=
40+
golang.org/x/image v0.0.0-20210628002857-a66eb6448b8d/go.mod h1:023OzeP/+EPmXeapQh35lcL3II3LrY8Ic+EFFKVhULM=
41+
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
42+
golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik=
43+
golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
44+
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
45+
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
46+
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
47+
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

scripts/photos/main.go

+129
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
package main
2+
3+
import (
4+
"bytes"
5+
"encoding/base64"
6+
"fmt"
7+
_ "image/jpeg"
8+
"image/png"
9+
"os"
10+
"path/filepath"
11+
"strings"
12+
"time"
13+
14+
"github.com/atotto/clipboard"
15+
"github.com/buckket/go-blurhash"
16+
"github.com/kolesa-team/go-webp/webp"
17+
"go.mattglei.ch/timber"
18+
)
19+
20+
const PHOTOS_FOLDER = "../../static/photos"
21+
22+
var files = []string{
23+
"ritracing.webp",
24+
"a4.webp",
25+
"quinn.webp",
26+
"clarkson.webp",
27+
"eye.webp",
28+
"spider.webp",
29+
"up.webp",
30+
"cadillac.webp",
31+
"ladybug.webp",
32+
"rocky8.webp",
33+
"mtb2.webp",
34+
"motorcycle.webp",
35+
"mtb1.webp",
36+
"nyc.webp",
37+
"hayhay.webp",
38+
"pete.webp",
39+
"eggBeach.webp",
40+
"fox.webp",
41+
"flower.webp",
42+
"fog.webp",
43+
"boat.webp",
44+
"pete2.webp",
45+
"bug.webp",
46+
"porsche.webp",
47+
}
48+
49+
type photo struct {
50+
name string
51+
filename string
52+
path string
53+
blurdata string
54+
width int
55+
height int
56+
}
57+
58+
func main() {
59+
timber.Timezone(time.Local)
60+
timber.TimeFormat("03:04:05")
61+
62+
photos := []photo{}
63+
for _, file := range files {
64+
reader, err := os.Open(filepath.Join(PHOTOS_FOLDER, file))
65+
if err != nil {
66+
timber.Fatal(err, "failed to read image:", file)
67+
}
68+
defer reader.Close()
69+
70+
parsedJPG, err := webp.Decode(reader, nil)
71+
if err != nil {
72+
timber.Fatal(err, "parsing JPEG failed for", file)
73+
}
74+
width := parsedJPG.Bounds().Dx()
75+
height := parsedJPG.Bounds().Dy()
76+
blurData, err := blurhash.Encode(4, 3, parsedJPG)
77+
if err != nil {
78+
timber.Fatal(err, "creating blur data for", file, "failed")
79+
}
80+
81+
scaleDownFactor := 200
82+
blurImage, err := blurhash.Decode(
83+
blurData,
84+
width/scaleDownFactor,
85+
height/scaleDownFactor,
86+
1,
87+
)
88+
if err != nil {
89+
timber.Fatal(err, "Encoding blurhash data to img failed for", file)
90+
}
91+
blurImageOut := new(bytes.Buffer)
92+
err = png.Encode(blurImageOut, blurImage)
93+
if err != nil {
94+
timber.Fatal(err, "Writing data to PNG failed", file)
95+
}
96+
base64BlurData := base64.StdEncoding.EncodeToString(blurImageOut.Bytes())
97+
98+
photos = append(
99+
photos, photo{
100+
filename: file,
101+
name: strings.TrimSuffix(file, ".webp"),
102+
path: fmt.Sprintf("/photos/%s", file),
103+
blurdata: base64BlurData,
104+
height: height,
105+
width: width,
106+
},
107+
)
108+
timber.Done("processed", file)
109+
}
110+
111+
code := "const photoData: Photo[] = ["
112+
for _, photo := range photos {
113+
code = fmt.Sprintf(
114+
"%s{src:'/photos/%s',alt:'%s',placeholder:'data:image/png;base64,%s', width:%d,height:%d},",
115+
code,
116+
photo.filename,
117+
photo.name,
118+
photo.blurdata,
119+
photo.width,
120+
photo.height,
121+
)
122+
}
123+
code = fmt.Sprintf("%s];", strings.TrimRight(code, ","))
124+
err := clipboard.WriteAll(code)
125+
if err != nil {
126+
timber.Fatal(err, "failed to write code to clipboard")
127+
}
128+
timber.Done("code copied to clipboard")
129+
}

src/lib/dynamic-head.svelte

+27-25
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,12 @@
22
const {
33
title,
44
description,
5-
opengraphImage,
5+
opengraphImage = { url: 'https://mattglei.ch/opengraph.png', width: '1200', height: '630' },
66
keywords = []
77
}: {
88
title: string;
99
description: string;
10-
opengraphImage: OpenGraphImage;
10+
opengraphImage?: OpenGraphImage;
1111
keywords?: string[];
1212
} = $props();
1313
@@ -40,29 +40,31 @@
4040
const siteURL = `https://${siteName}`;
4141
</script>
4242

43-
<title>{title}</title>
44-
<meta name="description" content={description} />
43+
<svelte:head>
44+
<title>{title}</title>
45+
<meta name="description" content={description} />
4546

46-
<link rel="author" href={siteURL} />
47-
<meta name="author" content={name} />
48-
<meta name="keywords" content={keywords.join(',')} />
47+
<link rel="author" href={siteURL} />
48+
<meta name="author" content={name} />
49+
<meta name="keywords" content={keywords.join(',')} />
4950

50-
<!-- opengraph -->
51-
<meta property="og:title" content={title} />
52-
<meta property="og:description" content={title} />
53-
<meta property="og:url" content={siteURL} />
54-
<meta property="og:site_name" content={siteName} />
55-
<meta property="og:locale" content="en-US" />
56-
<meta property="og:image" content={opengraphImage.url} />
57-
<meta property="og:image:width" content={opengraphImage.width} />
58-
<meta property="og:image:height" content={opengraphImage.height} />
59-
<meta property="og:type" content="website" />
51+
<!-- opengraph -->
52+
<meta property="og:title" content={title} />
53+
<meta property="og:description" content={title} />
54+
<meta property="og:url" content={siteURL} />
55+
<meta property="og:site_name" content={siteName} />
56+
<meta property="og:locale" content="en-US" />
57+
<meta property="og:image" content={opengraphImage.url} />
58+
<meta property="og:image:width" content={opengraphImage.width} />
59+
<meta property="og:image:height" content={opengraphImage.height} />
60+
<meta property="og:type" content="website" />
6061

61-
<!-- twitter -->
62-
<meta property="twitter:card" content="summary_large_image" />
63-
<meta property="twitter:creator" content="@matt_gleich" />
64-
<meta property="twitter:title" content={title} />
65-
<meta property="twitter:description" content={description} />
66-
<meta property="twitter:image" content={opengraphImage.url} />
67-
<meta property="twitter:image:width" content={opengraphImage.width} />
68-
<meta property="twitter:image:height" content={opengraphImage.height} />
62+
<!-- twitter -->
63+
<meta property="twitter:card" content="summary_large_image" />
64+
<meta property="twitter:creator" content="@matt_gleich" />
65+
<meta property="twitter:title" content={title} />
66+
<meta property="twitter:description" content={description} />
67+
<meta property="twitter:image" content={opengraphImage.url} />
68+
<meta property="twitter:image:width" content={opengraphImage.width} />
69+
<meta property="twitter:image:height" content={opengraphImage.height} />
70+
</svelte:head>

src/lib/image.svelte

+1
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
width: 100%;
3434
height: 100%;
3535
background-size: cover;
36+
object-fit: cover;
3637
background-position: center;
3738
background-repeat: no-repeat;
3839
display: block;

src/lib/index/section.svelte

+3
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,9 @@
153153
padding: 10px;
154154
padding-top: 10px;
155155
padding-bottom: 10px;
156+
display: flex;
157+
flex-direction: column;
158+
gap: 10px;
156159
}
157160
158161
.updated-container {

src/lib/index/sections/photos.svelte

+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
<script>
2+
import PhotoGallery from '$lib/photo-gallery.svelte';
3+
import Section from '../section.svelte';
4+
</script>
5+
6+
<Section name="Photos">
7+
<p>
8+
I've been really into photography for about seven years now. Starting with nature photography,
9+
mainly landscapes and macro, I've recently delved into automotive photography, especially during
10+
my time college with the RIT car club. I primarily use Nikon gear, with my current camera being
11+
a Nikon Z7II. Here is a few of my favorite photo's I've taken over the years:
12+
</p>
13+
<PhotoGallery count={6} />
14+
<a href="/photos"><button> View More </button></a>
15+
</Section>
16+
17+
<style>
18+
button {
19+
width: 100%;
20+
padding: 5px 0;
21+
}
22+
</style>

0 commit comments

Comments
 (0)