| -rw-r--r-- | Dockerfile | 6 | ||||
| -rw-r--r-- | internal/frontmatter/parser.go | 1 | ||||
| -rw-r--r-- | main.go | 13 | ||||
| -rw-r--r-- | static/input.css | 32 | ||||
| -rw-r--r-- | static/output.css | 59 | ||||
| -rw-r--r-- | views/index.html | 51 | ||||
| -rw-r--r-- | views/layouts/blog-page.html | 68 |
7 files changed, 181 insertions, 49 deletions
@@ -6,9 +6,13 @@ RUN go build -o sayana-demo . FROM alpine:3.22.1 AS runtime-stage +ENV B2_KEY_ID="" +ENV B2_APPLICATION_KEY="" + WORKDIR /app COPY --from=build-stage /builddir/sayana-demo /app/sayana-demo COPY --from=build-stage /builddir/static /app/static COPY --from=build-stage /builddir/views /app/views +COPY --from=build-stage /builddir/config/config.yaml /app/config.yaml -ENTRYPOINT [ "/app/sayana-demo" ] +ENTRYPOINT [ "/app/sayana-demo", "-c", "/app/config.yaml" ] diff --git a/internal/frontmatter/parser.go b/internal/frontmatter/parser.go index 6cc3ee8..1a521c0 100644 --- a/internal/frontmatter/parser.go +++ b/internal/frontmatter/parser.go @@ -15,6 +15,7 @@ type Metadata struct { PublishedTime time.Time `yaml:"publishedTime"` Thumbnail string `yaml:"thumbnail"` Tags []string `yaml:"tags"` + Geolocation string `yaml:"geolocation"` } func ParseFrontmatter(content []byte) (metadata *Metadata, markdown []byte, err error) { @@ -101,12 +101,25 @@ func main() { return c.Status(fiber.ErrNotFound.Code).SendString(fmt.Sprintf("failed to find '%s' post", c.Params("title"))) } + geolocationParts := strings.Split(metadata.Geolocation, " ") + var x, y, areaError string + if len(geolocationParts) >= 2 { + x = geolocationParts[0] + y = geolocationParts[1] + } + if len(geolocationParts) >= 3 { + areaError = geolocationParts[2] + } + return c.Render("layouts/blog-page", fiber.Map{ "Title": metadata.Title, "PublishedDate": metadata.PublishedTime.Format("2006-01-02 15:04:05 -07:00"), "PublishedYear": strconv.Itoa(metadata.PublishedTime.Year()), "ParsedMarkdownDesktop": template.HTML(parsedMarkdownDesktop), "ParsedMarkdownMobile": template.HTML(parsedMarkdownMobile), + "MapLocationX": x, + "MapLocationY": y, + "MapLocationAreaMeters": areaError, }) }) diff --git a/static/input.css b/static/input.css index dfa9219..c105d8f 100644 --- a/static/input.css +++ b/static/input.css @@ -27,7 +27,7 @@ --secondary-color: var(--main-light-color); --interlocked-hexagons-background: url('https://f003.backblazeb2.com/file/sayana-static/themes/olive/interlocked-hexagons.svg'); --interlocked-hexagons-background-repeat: repeat; - --interlocked-hexagons-background-size: 10vw; + --interlocked-hexagons-background-size: 10vh; --squares-and-triangles-background: url('https://f003.backblazeb2.com/file/sayana-static/themes/olive/squares-and-triangles.svg'); --squares-and-triangles-background-repeat: repeat; } @@ -43,7 +43,7 @@ --secondary-color: var(--main-medium-color); --interlocked-hexagons-background: url('https://f003.backblazeb2.com/file/sayana-static/themes/lettuce/interlocked-hexagons.svg'); --interlocked-hexagons-background-repeat: repeat; - --interlocked-hexagons-background-size: 10vw; + --interlocked-hexagons-background-size: 10vh; --squares-and-triangles-background: url('https://f003.backblazeb2.com/file/sayana-static/themes/lettuce/squares-and-triangles.svg'); --squares-and-triangles-background-repeat: repeat; } @@ -227,14 +227,34 @@ width: 90vw; } -.h-vh90 { - height: 90vh; +.w-p60 { + width: 60%; } .w-p80 { width: 80%; } +.w-p100 { + width: 100%; +} + +.w-vmax4 { + width: 4vmax; +} + +.h-vh40 { + height: 40vh; +} + +.h-vh90 { + height: 90vh; +} + +.h-vmax4 { + height: 4vmax; +} + .mt-vmin0-8 { margin-top: 0.8vmin; } @@ -280,6 +300,10 @@ padding-right: 1.2vmin; } +.p-vmin0-8 { + padding: 0.8vmin; +} + .p-vmin2-4 { padding: 2.4vmin; } diff --git a/static/output.css b/static/output.css index 2ba01ad..b07fd94 100644 --- a/static/output.css +++ b/static/output.css @@ -12,8 +12,6 @@ --color-sky-200: oklch(90.1% 0.058 230.902); --color-sky-300: oklch(82.8% 0.111 230.318); --spacing: 0.25rem; - --text-4xl: 2.25rem; - --text-4xl--line-height: calc(2.5 / 2.25); --font-weight-medium: 500; --font-weight-bold: 700; --font-weight-extrabold: 800; @@ -222,9 +220,6 @@ .my-auto { margin-block: auto; } - .mt-2 { - margin-top: calc(var(--spacing) * 2); - } .mt-auto { margin-top: auto; } @@ -234,9 +229,6 @@ .mr-auto { margin-right: auto; } - .mb-4 { - margin-bottom: calc(var(--spacing) * 4); - } .mb-auto { margin-bottom: auto; } @@ -249,30 +241,12 @@ .flex { display: flex; } - .h-4\/12 { - height: calc(4/12 * 100%); - } - .h-16 { - height: calc(var(--spacing) * 16); - } .h-auto { height: auto; } .h-screen { height: 100vh; } - .min-h-16 { - min-height: calc(var(--spacing) * 16); - } - .w-6\/12 { - width: calc(6/12 * 100%); - } - .w-10\/12 { - width: calc(10/12 * 100%); - } - .w-16 { - width: calc(var(--spacing) * 16); - } .max-w-full { max-width: 100%; } @@ -285,6 +259,9 @@ .flex-5 { flex: 5; } + .flex-none { + flex: none; + } .flex-grow { flex-grow: 1; } @@ -394,10 +371,6 @@ .font-spectral { font-family: var(--font-spectral); } - .text-4xl { - font-size: var(--text-4xl); - line-height: var(--tw-leading, var(--text-4xl--line-height)); - } .font-bold { --tw-font-weight: var(--font-weight-bold); font-weight: var(--font-weight-bold); @@ -455,7 +428,7 @@ --secondary-color: var(--main-light-color); --interlocked-hexagons-background: url('https://f003.backblazeb2.com/file/sayana-static/themes/olive/interlocked-hexagons.svg'); --interlocked-hexagons-background-repeat: repeat; - --interlocked-hexagons-background-size: 10vw; + --interlocked-hexagons-background-size: 10vh; --squares-and-triangles-background: url('https://f003.backblazeb2.com/file/sayana-static/themes/olive/squares-and-triangles.svg'); --squares-and-triangles-background-repeat: repeat; } @@ -470,7 +443,7 @@ --secondary-color: var(--main-medium-color); --interlocked-hexagons-background: url('https://f003.backblazeb2.com/file/sayana-static/themes/lettuce/interlocked-hexagons.svg'); --interlocked-hexagons-background-repeat: repeat; - --interlocked-hexagons-background-size: 10vw; + --interlocked-hexagons-background-size: 10vh; --squares-and-triangles-background: url('https://f003.backblazeb2.com/file/sayana-static/themes/lettuce/squares-and-triangles.svg'); --squares-and-triangles-background-repeat: repeat; } @@ -614,12 +587,27 @@ .w-vw90 { width: 90vw; } -.h-vh90 { - height: 90vh; +.w-p60 { + width: 60%; } .w-p80 { width: 80%; } +.w-p100 { + width: 100%; +} +.w-vmax4 { + width: 4vmax; +} +.h-vh40 { + height: 40vh; +} +.h-vh90 { + height: 90vh; +} +.h-vmax4 { + height: 4vmax; +} .mt-vmin0-8 { margin-top: 0.8vmin; } @@ -654,6 +642,9 @@ .pr-vmin1-2 { padding-right: 1.2vmin; } +.p-vmin0-8 { + padding: 0.8vmin; +} .p-vmin2-4 { padding: 2.4vmin; } diff --git a/views/index.html b/views/index.html index cff3826..ce80db6 100644 --- a/views/index.html +++ b/views/index.html @@ -9,9 +9,42 @@ <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin> <link href="https://fonts.googleapis.com/css2?family=Spectral:ital,wght@0,200;0,300;0,400;0,500;0,600;0,700;0,800;1,200;1,300;1,400;1,500;1,600;1,700;1,800&family=Patua+One&display=swap" rel="stylesheet"> <link href="/output.css" rel="stylesheet"> + <style> + .menu-outer-body { + border-radius: 10%; + width: 60vw; + height: 40vh; + } + + .menu-inner-body { + width: 85%; + } + + @media (max-aspect-ratio: 1.2/1) { + .menu-outer-body { + border-radius: 5%; + } + + .menu-inner-body { + width: 92.5%; + } + } + + @media (max-aspect-ratio: 0.8/1) { + .menu-outer-body { + width: 100vw; + height: 80vh; + border-radius: 0; + } + + .menu-inner-body { + width: 100%; + } + } + </style> </head> -<body data-theme="night" class="font-spectral text-main-dark overflow-hidden bg-interlocked-hexagons h-screen flex flex-col"> +<body data-theme="night" class="font-spectral text-main-dark text-vmax1-5 overflow-hidden bg-interlocked-hexagons h-screen flex flex-col"> <div class="absolute star z-0">*</div> <div class="absolute star z-0">*</div> @@ -57,22 +90,22 @@ switchTheme(savedTheme); </script> - <div class="p-4 w-6/12 h-4/12 z-1 rounded-4xl bg-background-dark flex flex-col mx-auto my-auto opacity-70"> - <p class="font-patua mx-auto text-4xl mt-2 mb-4">saya.today</p> - <div class="w-10/12 grow bg-background-light flex flex-col mx-auto mb-4 overflow-y-auto opacity-100"> + <div class="menu-outer-body p-4 z-1 bg-background-dark flex flex-col mx-auto my-auto opacity-70"> + <p class="font-patua mx-auto text-vmax2-5 mt-vmin0-8 mb-vmin1-6">saya.today</p> + <div class="menu-inner-body grow bg-background-light flex flex-col mx-auto mb-vmin1-6 overflow-y-auto opacity-100"> {{- range .BlogPages }} - <div class="m-2 min-h-16 flex flex-row justify-center justify-items-center gap-4"> - <img style="flex-grow: 0;" class="flex-1 object-cover w-16 h-16 rounded-4xl select-none" src="https://f003.backblazeb2.com/file/sayana-photos/thumbnails/{{ .Thumbnail }}.webp"> + <div class="m-2 flex flex-row justify-center justify-items-center gap-4"> + <img onclick="location.href='/blog/{{ .Link }}';" style="flex-grow: 0;" class="flex-1 cursor-pointer object-cover rounded-4xl select-none w-vmax4 h-vmax4" src="https://f003.backblazeb2.com/file/sayana-photos/thumbnails/{{ .Thumbnail }}.webp"> <div class="flex-5 justify-self-center flex-col border-r-1 border-dashed border-opacity-50 border-main-medium"> <a href="/blog/{{ .Link }}" class="block font-extrabold">{{ .Title }}</a> - <a href="/blog/{{ .Link }}" class="block italic text-secondary">{{ .ActionDate }}</a> + <a href="/blog/{{ .Link }}" class="block italic text-vmax1 text-secondary">{{ .ActionDate }}</a> <p>{{ .ShortDescription }}</p> </div> <div class="flex-3 justify-self-center flex flex-col text-right"> - <p class="grow"> + <p class="grow text-vmax1"> Тэги: {{ .Tags }} </p> - <p class="italic text-secondary"> + <p class="italic text-secondary text-vmax1"> {{ .PublishedTime }} </p> </div> diff --git a/views/layouts/blog-page.html b/views/layouts/blog-page.html index 6ee7d85..c52e0e4 100644 --- a/views/layouts/blog-page.html +++ b/views/layouts/blog-page.html @@ -8,13 +8,23 @@ <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/lightgallery/2.8.3/css/lightgallery.min.css"> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/lightgallery/2.8.3/css/lg-zoom.min.css"> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/lightgallery/2.8.3/css/lg-thumbnail.min.css"> +{{- if .MapLocationX }} + <link rel="stylesheet" href="https://f003.backblazeb2.com/file/sayana-static/libs/leaflet/1.9.4/leaflet.css"> +{{- end }} <link rel="preconnect" href="https://fonts.googleapis.com"> <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin> <link href="https://fonts.googleapis.com/css2?family=Spectral:ital,wght@0,200;0,300;0,400;0,500;0,600;0,700;0,800;1,200;1,300;1,400;1,500;1,600;1,700;1,800&family=Patua+One&display=swap" rel="stylesheet"> <link href="/output.css" rel="stylesheet"> + + <style> + .map-container .leaflet-container { + width: 100% !important; + height: 100% !important; + } + </style> </head> -<body data-theme="olive" class="font-spectral text-main-dark overflow-hidden bg-interlocked-hexagons bg-repeat bg-pattern-body h-screen flex"> +<body data-theme="olive" class="font-spectral text-main-dark overflow-hidden bg-interlocked-hexagons h-screen flex"> <script> function switchTheme(theme) { @@ -60,6 +70,11 @@ <div class="bg-background-light flex flex-col flex-1 overflow-y-auto inset-shadow p-vmin2-4"> {{ .ParsedMarkdownDesktop }} + {{- if .MapLocationX }} + <hr class="border-t-4 border-dotted border-main-dark mt-vmin0-8 mb-vmin0-8 w-p80 ml-auto mr-auto"> + <div id="location-map-desktop" class="relative p-vmin0-8 flex-none ml-auto mr-auto w-p60 h-vh40"></div> + <hr class="border-t-4 border-dotted border-main-dark mt-vmin0-8 mb-vmin0-8 w-p80 ml-auto mr-auto"> + {{- end }} </div> <div class="flex flex-row mt-vmin0-8 mb-vmin0-4"> @@ -103,6 +118,11 @@ <div class="bg-background-light flex flex-col flex-1 overflow-y-auto inset-shadow p-vmin2-4"> {{ .ParsedMarkdownMobile }} + {{- if .MapLocationX }} + <hr class="border-t-4 border-dotted border-main-dark mt-vmin0-8 mb-vmin0-8 w-p80 ml-auto mr-auto"> + <div id="location-map-mobile" class="relative p-vmin0-8 flex-none ml-auto mr-auto w-p100 h-vh40"></div> + <hr class="border-t-4 border-dotted border-main-dark mt-vmin0-8 mb-vmin0-8 w-p80 ml-auto mr-auto"> + {{- end }} </div> <div class="flex flex-row mt-vmin0-8 mb-vmin0-4"> @@ -123,6 +143,52 @@ <script src="https://f003.backblazeb2.com/file/sayana-static/libs/lightgallery/2.8.3/lightgallery.min.js"></script> <script src="https://f003.backblazeb2.com/file/sayana-static/libs/lightgallery/2.8.3/plugins/lg-zoom.min.js"></script> <script src="https://f003.backblazeb2.com/file/sayana-static/libs/lightgallery/2.8.3/plugins/lg-thumbnail.min.js"></script> +{{- if .MapLocationX }} + <script src="https://f003.backblazeb2.com/file/sayana-static/libs/leaflet/1.9.4/leaflet.js"></script> + + <script> + function initLocationMap(id, x, y, relativeErrorMeters = 0) { + var map = L.map(id).setView([x, y], 13); + + L.tileLayer('https://tile.openstreetmap.org/{z}/{x}/{y}.png', { + maxZoom: 19, + attribution: '© <a href="http://www.openstreetmap.org/copyright">OpenStreetMap</a>' + }).addTo(map); + + if (relativeErrorMeters != 0) { + var circle = L.circle([x, y], { + color: '#8a9d8a', + fillColor: '#8a9d8a', + fillOpacity: 0.15, + radius: relativeErrorMeters + }).addTo(map); + } + + var marker = L.marker([x, y]).addTo(map); + } + + document.addEventListener('DOMContentLoaded', () => {initLocationMap( + 'location-map-desktop', + {{ .MapLocationX }}, + {{ .MapLocationY }}, + {{ .MapLocationAreaMeters }} + )}); + + document.addEventListener('DOMContentLoaded', () => {initLocationMap( + 'location-map-mobile', + {{ .MapLocationX }}, + {{ .MapLocationY }}, + {{ .MapLocationAreaMeters }} + )}); + + window.addEventListener('resize', function() { + setTimeout(() => { + if (window.location-map-desktop) window.location-map-desktop.invalidateSize(); + if (window.location-map-mobile) window.location-map-mobile.invalidateSize(); + }, 100); + }); + </script> +{{- end }} </body> </html> |