diff --git a/generate/build.tsx b/generate/build.tsx
index bab9dc0..b938b45 100644
--- a/generate/build.tsx
+++ b/generate/build.tsx
@@ -8,6 +8,7 @@ import exec from "child_process";
import Base from "./templates/Base";
import Header from "./templates/Header";
import YearPhotos from "./templates/YearPhotos";
+import Tags from "./templates/Tags";
const log = new Log();
@@ -123,6 +124,7 @@ Object.keys(items).forEach((year) => {
const html = renderToString(
+
{Object.keys(items).sort().reverse().map((year) => (
=16.0.0" } }, "sha512-ey8Ls/+Di31eqzUxC46h8MksNuGx/n0AAC8uKpwFau4RPDYLuE3EXTp8N8G2vX2N7UC/+IXeNUnlWBGGcAG+Ig=="],
+
"proto3-json-serializer": ["proto3-json-serializer@2.0.2", "", { "dependencies": { "protobufjs": "^7.2.5" } }, "sha512-SAzp/O4Yh02jGdRc+uIrGoe87dkN/XtwxfZ4ZyafJHymd79ozp5VG5nyZ7ygqPM5+cpLDjjGnYFUkngonyDPOQ=="],
"protobufjs": ["protobufjs@7.4.0", "", { "dependencies": { "@protobufjs/aspromise": "^1.1.2", "@protobufjs/base64": "^1.1.2", "@protobufjs/codegen": "^2.0.4", "@protobufjs/eventemitter": "^1.1.0", "@protobufjs/fetch": "^1.1.0", "@protobufjs/float": "^1.0.2", "@protobufjs/inquire": "^1.1.0", "@protobufjs/path": "^1.1.2", "@protobufjs/pool": "^1.1.0", "@protobufjs/utf8": "^1.1.0", "@types/node": ">=13.7.0", "long": "^5.0.0" } }, "sha512-mRUWCc3KUU4w1jU8sGxICXH/gNS94DvI1gxqDvBzhj1JpcsimQkYiOJfwsPUykUI5ZaspFbSgmBLER8IrQ3tqw=="],
@@ -539,6 +546,8 @@
"stubs": ["stubs@3.0.0", "", {}, "sha512-PdHt7hHUJKxvTCgbKX9C1V/ftOcjJQgz8BZwNfV5c4B6dcGqlpelTbJ999jBGZ2jYiPAwcX5dP6oBwVlBlUbxw=="],
+ "tailwind-scrollbar": ["tailwind-scrollbar@4.0.0", "", { "dependencies": { "prism-react-renderer": "^2.4.1" }, "peerDependencies": { "tailwindcss": "4.x" } }, "sha512-elqx9m09VHY8gkrMiyimFO09JlS3AyLFXT0eaLaWPi7ImwHlbZj1ce/AxSis2LtR+ewBGEyUV7URNEMcjP1Z2w=="],
+
"tailwindcss": ["tailwindcss@4.0.7", "", {}, "sha512-yH5bPPyapavo7L+547h3c4jcBXcrKwybQRjwdEIVAd9iXRvy/3T1CC6XSQEgZtRySjKfqvo3Cc0ZF1DTheuIdA=="],
"tapable": ["tapable@2.2.1", "", {}, "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ=="],
diff --git a/generate/package.json b/generate/package.json
index 117fd03..48f3a66 100644
--- a/generate/package.json
+++ b/generate/package.json
@@ -20,6 +20,7 @@
"picocolors": "^1.1.1",
"react": "^19.0.0",
"react-dom": "^19.0.0",
+ "tailwind-scrollbar": "^4.0.0",
"tailwindcss": "^4.0.7",
"ws": "^8.18.0"
}
diff --git a/generate/static/css/tailwind.css b/generate/static/css/tailwind.css
index 5f772da..cdbd03d 100644
--- a/generate/static/css/tailwind.css
+++ b/generate/static/css/tailwind.css
@@ -521,11 +521,8 @@
.collapse {
visibility: collapse;
}
- .absolute {
- position: absolute;
- }
- .fixed {
- position: fixed;
+ .invisible {
+ visibility: hidden;
}
.relative {
position: relative;
@@ -533,12 +530,6 @@
.static {
position: static;
}
- .\[grid-column\:span_2\] {
- grid-column: span 2;
- }
- .\[grid-row\:span_2\] {
- grid-row: span 2;
- }
.container {
width: 100%;
@media (width >= 40rem) {
@@ -563,6 +554,27 @@
.mb-4 {
margin-bottom: calc(var(--spacing) * 4);
}
+ .scrollbar-thin {
+ &::-webkit-scrollbar-track {
+ background-color: var(--scrollbar-track);
+ border-radius: var(--scrollbar-track-radius);
+ }
+ &::-webkit-scrollbar-thumb {
+ background-color: var(--scrollbar-thumb);
+ border-radius: var(--scrollbar-thumb-radius);
+ }
+ &::-webkit-scrollbar-corner {
+ background-color: var(--scrollbar-corner);
+ border-radius: var(--scrollbar-corner-radius);
+ }
+ scrollbar-width: thin;
+ scrollbar-color: var(--scrollbar-thumb, initial) var(--scrollbar-track, initial);
+ &::-webkit-scrollbar {
+ display: block;
+ width: 8px;
+ height: 8px;
+ }
+ }
.block {
display: block;
}
@@ -575,9 +587,6 @@
.hidden {
display: none;
}
- .inline-block {
- display: inline-block;
- }
.inline-flex {
display: inline-flex;
}
@@ -587,12 +596,6 @@
.table {
display: table;
}
- .aspect-\[1\/2\] {
- aspect-ratio: 1/2;
- }
- .aspect-\[2\/1\] {
- aspect-ratio: 2/1;
- }
.aspect-square {
aspect-ratio: 1 / 1;
}
@@ -620,33 +623,9 @@
.grid-flow-row-dense {
grid-auto-flow: row dense;
}
- .\[grid-template-columns\:repeat\(auto-fill\,minmax\(256px\,1fr\)\)\] {
- grid-template-columns: repeat(auto-fill,minmax(256px,1fr));
- }
- .grid-cols-1 {
- grid-template-columns: repeat(1, minmax(0, 1fr));
- }
.grid-cols-2 {
grid-template-columns: repeat(2, minmax(0, 1fr));
}
- .grid-cols-3 {
- grid-template-columns: repeat(3, minmax(0, 1fr));
- }
- .grid-cols-4 {
- grid-template-columns: repeat(4, minmax(0, 1fr));
- }
- .grid-cols-5 {
- grid-template-columns: repeat(5, minmax(0, 1fr));
- }
- .grid-cols-6 {
- grid-template-columns: repeat(6, minmax(0, 1fr));
- }
- .grid-cols-7 {
- grid-template-columns: repeat(7, minmax(0, 1fr));
- }
- .grid-cols-8 {
- grid-template-columns: repeat(8, minmax(0, 1fr));
- }
.flex-col {
flex-direction: column;
}
@@ -659,8 +638,11 @@
.gap-4 {
gap: calc(var(--spacing) * 4);
}
- .gap-8 {
- gap: calc(var(--spacing) * 8);
+ .overflow-x-auto {
+ overflow-x: auto;
+ }
+ .rounded-full {
+ border-radius: calc(infinity * 1px);
}
.rounded-lg {
border-radius: var(--radius-lg);
@@ -682,16 +664,38 @@
.bg-\[\#FF478B\] {
background-color: #FF478B;
}
+ .bg-gray-600 {
+ background-color: var(--color-gray-600);
+ }
+ .bg-gray-800 {
+ background-color: var(--color-gray-800);
+ }
.object-cover {
object-fit: cover;
}
.p-4 {
padding: calc(var(--spacing) * 4);
}
+ .px-3 {
+ padding-inline: calc(var(--spacing) * 3);
+ }
+ .px-8 {
+ padding-inline: calc(var(--spacing) * 8);
+ }
+ .py-1 {
+ padding-block: calc(var(--spacing) * 1);
+ }
+ .py-2 {
+ padding-block: calc(var(--spacing) * 2);
+ }
.text-2xl {
font-size: var(--text-2xl);
line-height: var(--tw-leading, var(--text-2xl--line-height));
}
+ .text-sm {
+ font-size: var(--text-sm);
+ line-height: var(--tw-leading, var(--text-sm--line-height));
+ }
.font-bold {
--tw-font-weight: var(--font-weight-bold);
font-weight: var(--font-weight-bold);
@@ -702,107 +706,34 @@
.underline {
text-decoration-line: underline;
}
- .antialiased {
- -webkit-font-smoothing: antialiased;
- -moz-osx-font-smoothing: grayscale;
- }
.outline {
outline-style: var(--tw-outline-style);
outline-width: 1px;
}
- .blur {
- --tw-blur: blur(8px);
- filter: var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,);
- }
- .grayscale {
- --tw-grayscale: grayscale(100%);
- filter: var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,);
- }
.filter {
filter: var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,);
}
- .backdrop-filter {
- -webkit-backdrop-filter: var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,);
- backdrop-filter: var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,);
+ .scrollbar-thumb-gray-700 {
+ --scrollbar-thumb: oklch(0.373 0.034 259.733);
}
- .transition {
- transition-property: color, background-color, border-color, outline-color, text-decoration-color, fill, stroke, --tw-gradient-from, --tw-gradient-via, --tw-gradient-to, opacity, box-shadow, transform, translate, scale, rotate, filter, -webkit-backdrop-filter, backdrop-filter;
- transition-timing-function: var(--tw-ease, var(--default-transition-timing-function));
- transition-duration: var(--tw-duration, var(--default-transition-duration));
- }
- .ease-in {
- --tw-ease: var(--ease-in);
- transition-timing-function: var(--ease-in);
- }
- .ease-out {
- --tw-ease: var(--ease-out);
- transition-timing-function: var(--ease-out);
- }
- .sm\:\[grid-column\:span_2\] {
- @media (width >= 40rem) {
- grid-column: span 2;
- }
- }
- .sm\:\[grid-template-columns\:repeat\(auto-fill\,minmax\(256px\,1fr\)\)\] {
- @media (width >= 40rem) {
- grid-template-columns: repeat(auto-fill,minmax(256px,1fr));
- }
- }
- .md\:\[grid-column\:span_2\] {
- @media (width >= 48rem) {
- grid-column: span 2;
- }
+ .scrollbar-track-gray-900 {
+ --scrollbar-track: oklch(0.21 0.034 264.665);
}
.lg\:\[grid-column\:span_2\] {
@media (width >= 64rem) {
grid-column: span 2;
}
}
- .lg\:grid-cols-3 {
- @media (width >= 64rem) {
- grid-template-columns: repeat(3, minmax(0, 1fr));
- }
- }
- .lg\:grid-cols-4 {
- @media (width >= 64rem) {
- grid-template-columns: repeat(4, minmax(0, 1fr));
- }
- }
.lg\:grid-cols-5 {
@media (width >= 64rem) {
grid-template-columns: repeat(5, minmax(0, 1fr));
}
}
- .xl\:\[grid-column\:span_2\] {
- @media (width >= 80rem) {
- grid-column: span 2;
- }
- }
- .xl\:\[grid-template-columns\:repeat\(auto-fill\,minmax\(128px\,1fr\)\)\] {
- @media (width >= 80rem) {
- grid-template-columns: repeat(auto-fill,minmax(128px,1fr));
- }
- }
- .xl\:\[grid-template-columns\:repeat\(auto-fill\,minmax\(200px\,1fr\)\)\] {
- @media (width >= 80rem) {
- grid-template-columns: repeat(auto-fill,minmax(200px,1fr));
- }
- }
- .xl\:\[grid-template-columns\:repeat\(auto-fill\,minmax\(512px\,1fr\)\)\] {
- @media (width >= 80rem) {
- grid-template-columns: repeat(auto-fill,minmax(512px,1fr));
- }
- }
.xl\:grid-cols-7 {
@media (width >= 80rem) {
grid-template-columns: repeat(7, minmax(0, 1fr));
}
}
- .xl\:grid-cols-8 {
- @media (width >= 80rem) {
- grid-template-columns: repeat(8, minmax(0, 1fr));
- }
- }
.xl\:text-3xl {
@media (width >= 80rem) {
font-size: var(--text-3xl);
@@ -822,6 +753,12 @@
font-weight: 600;
font-style: normal;
}
+@layer base {
+ * {
+ scrollbar-color: initial;
+ scrollbar-width: initial;
+ }
+}
@keyframes spin {
to {
transform: rotate(360deg);
@@ -927,43 +864,3 @@
syntax: "*";
inherits: false;
}
-@property --tw-backdrop-blur {
- syntax: "*";
- inherits: false;
-}
-@property --tw-backdrop-brightness {
- syntax: "*";
- inherits: false;
-}
-@property --tw-backdrop-contrast {
- syntax: "*";
- inherits: false;
-}
-@property --tw-backdrop-grayscale {
- syntax: "*";
- inherits: false;
-}
-@property --tw-backdrop-hue-rotate {
- syntax: "*";
- inherits: false;
-}
-@property --tw-backdrop-invert {
- syntax: "*";
- inherits: false;
-}
-@property --tw-backdrop-opacity {
- syntax: "*";
- inherits: false;
-}
-@property --tw-backdrop-saturate {
- syntax: "*";
- inherits: false;
-}
-@property --tw-backdrop-sepia {
- syntax: "*";
- inherits: false;
-}
-@property --tw-ease {
- syntax: "*";
- inherits: false;
-}
diff --git a/generate/static/js/initGalleries.js b/generate/static/js/initGalleries.js
index 348a0b3..c96180c 100644
--- a/generate/static/js/initGalleries.js
+++ b/generate/static/js/initGalleries.js
@@ -1,17 +1,103 @@
+const url = new URL(window.location.href);
+let tags = url.searchParams.get("tag") || "";
+if (tags.length > 0) {
+ tags = tags.split(",");
+} else {
+ tags = [];
+}
+let availableTags = [];
+
const galleries = document.querySelectorAll('[data-type="gallery"]');
+let tagsButtons = document.querySelectorAll('[data-type="tag"]');
+let allTagsButton = document.querySelector('[data-type="tag"][data-tag="all"]');
+let Images = document.querySelectorAll('[data-type="image"]');
+
+Images.forEach((item) => {
+ const imTags = item.dataset.tags.split(",") || [];
+ const foundTags = [];
+
+ for (let i = 0; i < imTags.length; i++) {
+ if (tags.includes(imTags[i]) || tags.length == 0) {
+ foundTags.push(imTags[i]);
+ }
+ }
+
+ if (foundTags.length == 0 || foundTags.length < tags.length) {
+ item.remove();
+ } else {
+ item.classList.remove("hidden");
+ for (let i = 0; i < imTags.length; i++) {
+ if (!availableTags.includes(imTags[i])) {
+ availableTags.push(imTags[i]);
+ }
+ }
+ }
+});
+
+allTagsButton.addEventListener("click", () => {
+ removeTags();
+});
+
+if (tags.length == 0) {
+ allTagsButton.classList.remove("bg-gray-800");
+ allTagsButton.classList.add("bg-gray-600");
+}
+
+tagsButtons.forEach((item) => {
+ if (item.dataset.tag != "all") {
+ item.addEventListener("click", () => {
+ toggleTag(item.dataset.tag);
+ });
+ }
+ if (tags.includes(item.dataset.tag)) {
+ item.classList.remove("bg-gray-800");
+ item.classList.add("bg-gray-600");
+ }
+ if (!availableTags.includes(item.dataset.tag) && item.dataset.tag != "all") {
+ item.remove();
+ } else {
+ item.classList.remove("hidden");
+ }
+});
+
+function removeTags() {
+ const url = new URL(window.location.href);
+ url.searchParams.delete("tag");
+ window.history.pushState({}, "", url);
+ window.location.reload();
+}
+
+function toggleTag(tag) {
+ if (tags.includes(tag)) {
+ tags = tags.filter((item) => item !== tag);
+ } else {
+ tags.push(tag);
+ }
+
+ tags = tags.join(",");
+ url.searchParams.set("tag", tags);
+ window.history.pushState({}, "", url);
+ window.location.reload();
+}
galleries.forEach((item, idx) => {
- lightGallery(item, {
- plugins: [lgThumbnail, lgHash, lgShare, lgFullscreen, lgZoom],
- speed: 500,
- thumbnail: true,
- download: true,
- animateThumb: true,
- zoomFromOrigin: false,
- toggleThumb: false,
- galleryId: Number(item.getAttribute('data-year')),
- hash: true,
- customSlideName: true,
- mobileSettings: { controls: true, showCloseIcon: true, download: true }
- });
+ if (item.children.length == 0) {
+ item.parentElement.remove();
+ } else {
+ item.parentElement.classList.remove("hidden");
+
+ lightGallery(item, {
+ plugins: [lgThumbnail, lgHash, lgShare, lgFullscreen, lgZoom],
+ speed: 500,
+ thumbnail: true,
+ download: true,
+ animateThumb: true,
+ zoomFromOrigin: false,
+ toggleThumb: false,
+ galleryId: Number(item.getAttribute("data-year")),
+ hash: true,
+ customSlideName: true,
+ mobileSettings: { controls: true, showCloseIcon: true, download: true },
+ });
+ }
});
diff --git a/generate/static_dev/input.css b/generate/static_dev/input.css
index c29fd2c..bb1e1d4 100644
--- a/generate/static_dev/input.css
+++ b/generate/static_dev/input.css
@@ -1,4 +1,5 @@
@import "tailwindcss";
+@plugin 'tailwind-scrollbar';
.inter-semibold {
font-family: "Inter", serif;
diff --git a/generate/templates/Tags.tsx b/generate/templates/Tags.tsx
new file mode 100644
index 0000000..b00999f
--- /dev/null
+++ b/generate/templates/Tags.tsx
@@ -0,0 +1,26 @@
+export default function Tags({ tags }: { tags: string[] }) {
+ return (
+
+
+
+ {tags.map((tag) => (
+
+ ))}
+
+
+ );
+}
diff --git a/generate/templates/YearPhotos.tsx b/generate/templates/YearPhotos.tsx
index e22d5ac..5b47eee 100644
--- a/generate/templates/YearPhotos.tsx
+++ b/generate/templates/YearPhotos.tsx
@@ -7,7 +7,7 @@ interface YearPhotosProps {
export default function YearPhotos({ year, images }: YearPhotosProps) {
return (
-