Strona fotografa ma niewygodne zadanie. Powinna mieć własny charakter, ale nie na tyle wyrazisty, żeby konkurować ze zdjęciami. Musi sprawiać wrażenie skończonej, a jednocześnie pozostać łatwa do zmiany. Ma zachęcić do zatrzymania się, a potem zejść z drogi.
Przebudowałem tę stronę, bo poprzednia wersja dobrze pokazywała zdjęcia, ale jej rozwijanie wymagało coraz więcej powtórzeń. Dodanie projektu oznaczało zmianę kilku plików. Wersje polska i angielska mogły zacząć się różnić. Zdjęcie mogło już należeć do projektu, a mimo to trzeba było osobno dopisać je do strony głównej i archiwum.
Widoczny rezultat nadal jest celowo prosty. Pod spodem zmieniło się prawie wszystko.
Jeden układ, dwa języki
Pierwsza wersja strony powstała jako ręcznie pisany HTML. Na początku ta bezpośredniość była przydatna: otworzyć plik, zmienić kod, odświeżyć stronę. Oznaczała też, że każdy powtarzający się element stawał się kolejnym miejscem do pilnowania.
Przeniosłem stronę do Astro i sprowadziłem każdą podstronę do cienkiej warstwy prowadzącej do jednego współdzielonego komponentu. Angielska wersja działa pod głównymi adresami, polska pod /pl/, ale nie są to dwie osobne strony. Obie korzystają z tego samego układu, nawigacji i zachowania. Teksty interfejsu mieszkają w jednym dwujęzycznym słowniku, a linki wewnętrzne przechodzą przez ten sam mechanizm pilnujący języka.
Na zrzucie ekranu nie ma w tym nic ekscytującego. Ekscytujące staje się dopiero wtedy, gdy zmianę w projekcie trzeba zrobić raz zamiast dwa razy.
Side Quests działają według tej samej zasady. Wpis ma jeden adres i jedną datę publikacji, a wersje polska i angielska podróżują razem. Build odmawia publikacji, jeśli brakuje któregoś języka. Wolę głośny błąd przed wdrożeniem niż cichą, przetłumaczoną w połowie stronę po nim.
Zdjęcie powinno istnieć raz
Ważniejsze uproszczenie dotyczyło samych fotografii.
W pewnym momencie strona główna, archiwum i lista projektów korzystały z osobnych zestawów danych. Opisywały zachodzące na siebie fragmenty tej samej pracy, więc mogły sobie przeczyć. Poprawienie jednego widoku nie musiało poprawić pozostałych.
Teraz projekt zawiera uporządkowany zestaw klatek. Każda klatka przechowuje plik zdjęcia, etykietę, tekst alternatywny i kilka decyzji redakcyjnych: pokaż na stronie głównej, dodaj do archiwum, użyj jako okładki projektu. Wszystkie siatki powstają na podstawie tych wyborów.
Brzmi jak decyzja dotycząca modelu danych, bo nią jest. To również decyzja dotycząca edycji. Kiedy dodaję nowe zdjęcie, od razu obok niego określam, gdzie ma się pojawić. Nie muszę później pamiętać o osobnym indeksie.
Plik źródłowy przechodzi przez mechanizm optymalizacji obrazów Astro, który tworzy wersje w odpowiednich rozmiarach, zamiast wszędzie wysyłać oryginał. Rzeczywiste proporcje zdjęcia wyznaczają jego ramę. Dopóki fotografia nie jest gotowa, strona może pokazać podpisane miejsce albo mały stan wywoływania filmu, zamiast zapadać się w pusty układ.
Strona może być jeszcze nieukończona, nie wyglądając na zepsutą.
Ruch, który ma powód
Większość interfejsu tworzą typografia, odstępy i zdjęcia. DM Sans wykonuje szeroką pracę redakcyjną, a DM Mono obsługuje małe etykiety i metadane. Paleta to ciepła czerń, papierowa biel i jeden czerwony akcent. Na większych ekranach pojawia się delikatne ziarno — tylko tyle, żeby powierzchnia nie była zbyt kliniczna.
Jest też ruch, ale zawsze ma konkretne zadanie.
Nawigacja znika, gdy przewijam stronę w dół, i wraca po zmianie kierunku. Otwarcie projektu pozwala okładce rozszerzyć się w pierwszy kadr. Kliknięcie fotografii otwiera lightbox dokładnie z jej miejsca w siatce. Zdjęcia pojawiają się dopiero po załadowaniu i zdekodowaniu przez przeglądarkę, żeby pusty prostokąt nie odgrywał animacji, zanim fotografia mignie na swoim miejscu.
Żaden z tych efektów nie może stać się pułapką. Galeria działa jak dostępne okno dialogowe, po zamknięciu oddaje fokus i zachowuje w kodzie zwykłe linki jako plan awaryjny. Jeśli system prosi o ograniczenie ruchu, przejścia i płynne przewijanie ustępują.
Detale są małe, bo strona nie jest głównym wydarzeniem.
Statyczna, dopóki nie musi być inaczej
Publiczna część strony jest budowana jako statyczne pliki i serwowana z Cloudflare. Dzięki temu najczęstsza ścieżka pozostaje prosta: otwarcie podstrony nie budzi serwera aplikacji i nie wysyła zapytania do bazy danych.
Jest jeden świadomy wyjątek. Formularz rezerwacji musi coś wysłać.
Mały Worker odbiera wiadomość, sprawdza jej poprawność i rozmiar, ogranicza serię powtarzających się zgłoszeń oraz używa ukrytego pola-pułapki do odrzucania prostych botów. Następnie wysyła do mnie zwykły e-mail przez usługę Cloudflare. Nie zakłada konta, nie zapisuje zapytania w bazie i nie dokłada osobnej platformy do obsługi klientów.
Ta granica ma dla mnie znaczenie. Dynamiczny kod istnieje tam, gdzie wymaga go interakcja, a nie dlatego, że reszta strony przypadkiem korzysta z frameworka.
CMS, który zostaje w domu
Chciałem wygodnie edytować projekty i Side Quests, ale nie chciałem, żeby działanie publicznej strony zależało od CMS-a.
Keystatic uruchamia się wyłącznie lokalnie podczas pracy. Dostaję formularze do wgrywania klatek, pisania dwujęzycznych tekstów i wybierania miejsc, w których mają pojawić się fotografie. Po zapisaniu powstają zwykłe pliki YAML i Markdoc w repozytorium. Git pozostaje historią, kopią zapasową i źródłem prawdy. Produkcyjna wersja nie zawiera panelu administracyjnego.
To pożyteczny kompromis: wizualny edytor, kiedy go potrzebuję, i zwykłe pliki, kiedy chcę dokładnie zrozumieć, co się zmieniło.
Zbudowana w rozmowie, sprawdzona w rzeczywistości
Duża część przebudowy powstała w rozmowie z agentami programistycznymi. Mogłem opisać zachowanie, sprawdzić implementację, uruchomić stronę i doprecyzować oczekiwania. Dzięki temu duże zmiany strukturalne dało się wykonać szybko — szczególnie przejście od powielonych list do jednego modelu treści.
Szybkość ułatwiła również tworzenie przekonujących błędów.
Strona może się kompilować, a mimo to chować nawigację w złym momencie. CMS może zapisywać plik, którego system treści nigdy nie zobaczy. Animacja może być technicznie płynna, a jednocześnie sprawiać, że każde zdjęcie miga dwa razy. To nie były teoretyczne przypadki brzegowe. Takie problemy wychodziły dopiero podczas korzystania z całości.
Dlatego repozytorium sprawdza dziś reguły treści, dwujęzyczne publikowanie, endpoint rezerwacji, kontrakty dostępności i produkcyjny build. Później i tak otwieram strony, zmieniam język, skaluję okno, używam klawiatury i patrzę na fotografie. Automatyczne testy świetnie chronią podjęte wcześniej decyzje. Nie zdecydują, czy strona jest wystarczająco cicha.
Co właściwie budowałem
Portfolio łatwo potraktować jak skończony przedmiot. Opublikować, ogłosić i przejść dalej. Działająca strona fotograficzna bardziej przypomina stykówkę: zmienia się razem z pracą, a jej struktura musi ułatwiać następną edycję.
Najlepsze decyzje w tej przebudowie są więc prawie niewidoczne. Zdjęcie ma jedno miejsce w danych. Tłumaczenie nie może zniknąć bez ostrzeżenia. Edytor nie staje się częścią infrastruktury produkcyjnej. Formularz rezerwacji nie zmienia się w bazę klientów. Ruch czeka na zdjęcie i ustępuje, kiedy zostanie o to poproszony.
Strona ma własny punkt widzenia, ale wie, co oprawia.