diff --git a/src/bpp/newsfragments/autodetekcja-jezyka-kod-bcp47.bugfix.rst b/src/bpp/newsfragments/autodetekcja-jezyka-kod-bcp47.bugfix.rst new file mode 100644 index 000000000..3130d147e --- /dev/null +++ b/src/bpp/newsfragments/autodetekcja-jezyka-kod-bcp47.bugfix.rst @@ -0,0 +1,8 @@ +Importer publikacji podpowiada teraz język pracy również dla angielskiego +i pozostałych języków z danych referencyjnych BPP. Dotąd dopasowanie szło +wyłącznie przez pole „Skrót nazwy języka wg API CrossRef", które wypełnione +jest tylko dla polskiego — więc import pracy z ``language="en"`` zostawiał +pole „Język" puste. Teraz, gdy to pole jest niewypełnione, importer sięga po +kod BCP 47 języka (uzupełniony dla polskiego, angielskiego, niemieckiego, +francuskiego, hiszpańskiego, rosyjskiego i włoskiego), pomijając oznaczenie +regionu. Ta sama poprawka dotyczy języka streszczeń. diff --git a/src/bpp/newsfragments/importer-wstecz-stary-uklad.bugfix.rst b/src/bpp/newsfragments/importer-wstecz-stary-uklad.bugfix.rst new file mode 100644 index 000000000..84bdbd1fc --- /dev/null +++ b/src/bpp/newsfragments/importer-wstecz-stary-uklad.bugfix.rst @@ -0,0 +1,6 @@ +Przycisk „Wstecz" w importerze publikacji nie przywraca już nieaktualnego +układu kroku 1 (wybór źródła przyciskami radio i lista sesji pod spodem). +Przeglądarki, które odwiedziły importer przed wprowadzeniem kafelków, +trzymały jego zrzut w pamięci podręcznej historii HTMX-a — a że nowa wersja +strony celowo nic już tam nie zapisuje, nieaktualny zrzut nie miał jak +zostać nadpisany. Strona kasuje go teraz przy wejściu. diff --git a/src/bpp/newsfragments/kafelki-importera-wyglad.bugfix.rst b/src/bpp/newsfragments/kafelki-importera-wyglad.bugfix.rst new file mode 100644 index 000000000..8099185e4 --- /dev/null +++ b/src/bpp/newsfragments/kafelki-importera-wyglad.bugfix.rst @@ -0,0 +1,6 @@ +Kafelki wyboru źródła danych w importerze publikacji wyglądają teraz tak +samo jak kafelki kreatora „Zgłoś publikację": ikona, pogrubiony tytuł i opis +zwykłą czcionką. Wcześniej globalna reguła dla linków w ramkach ``callout`` +pogrubiała cały kafelek i podkreślała po najechaniu myszą każdą linię jego +tekstu. Kafelki na obu ekranach unoszą się teraz delikatnie pod kursorem +(z poszanowaniem ustawienia „ogranicz ruch" w systemie). diff --git a/src/bpp/static/scss/_wizard_forms.scss b/src/bpp/static/scss/_wizard_forms.scss index 57154b2b6..96bab7180 100644 --- a/src/bpp/static/scss/_wizard_forms.scss +++ b/src/bpp/static/scss/_wizard_forms.scss @@ -58,13 +58,17 @@ padding: 1.5rem; cursor: pointer; text-align: center; - transition: border-color 0.2s, box-shadow 0.2s; + transition: border-color 0.2s, box-shadow 0.2s, transform 0.2s; background: #fff; &:hover { text-decoration: none; border-color: $primary-color; box-shadow: 0 2px 8px rgba(0,0,0,0.1); + // Delikatne uniesienie — ten sam sygnał „to jest klikalne", co na + // pozostałych kafelkowych ekranach BPP. Wyłączane niżej przy + // `prefers-reduced-motion`. + transform: translateY(-3px); } &:focus { @@ -89,6 +93,7 @@ display: block; font-size: 3rem; line-height: 1.2; + color: $primary-color; } .tile-title { @@ -121,6 +126,46 @@ } } +// Kafel-LINK w calloutcie: zdejmij z niego globalne style linków. +// +// Kafle importera publikacji to `` stojące wewnątrz +// `.callout`, więc łapie je globalna reguła z `flash_messages.css`: +// +// .callout a:not(.close-button) { font-weight: bolder; … } +// .callout a:not(.close-button):hover { text-decoration: underline; } +// +// Efekt uboczny: pogrubiony CAŁY kafel (razem z opisem, który ma być zwykłą +// czcionką) i podkreślenie wszystkich linii tekstu po najechaniu myszą. +// Kafle kreatora zgłoszeń tego nie mają, bo są `` — +// i to jest wygląd docelowy dla obu ekranów. +// +// Specyficzność musi wyjść REMISOWA (0,2,1) z regułą wyżej — samo +// `.tile-card` (0,1,0) by przegrało. Remis rozstrzyga kolejność w pliku +// wynikowym, a `wizard_forms` jest importowane po `common` (czyli po +// `flash_messages`) we WSZYSTKICH motywach — patrz `app-*.scss`. +.callout a.tile-card { + font-weight: normal; + color: $body-font-color; + + &:hover, + &:focus { + color: $body-font-color; + text-decoration: none; + } +} + +// Uniesienie kafla to dekoracja — przy `prefers-reduced-motion` zostaje sama +// zmiana obramowania i cienia (nadal czytelny stan hover, bez ruchu). +@media (prefers-reduced-motion: reduce) { + .tile-card { + transition: border-color 0.2s, box-shadow 0.2s; + + &:hover { + transform: none; + } + } +} + .wizard-nav { display: grid; grid-template-columns: 1fr 1fr; diff --git a/src/importer_publikacji/static/importer_publikacji/js/history_cache.js b/src/importer_publikacji/static/importer_publikacji/js/history_cache.js new file mode 100644 index 000000000..d59620daa --- /dev/null +++ b/src/importer_publikacji/static/importer_publikacji/js/history_cache.js @@ -0,0 +1,84 @@ +// Sprzątanie NIEŚWIEŻYCH snapshotów HTMX dla stron importera publikacji. +// +// Dlaczego to w ogóle istnieje +// ---------------------------- +// `index.html` ma `hx-history="false"` na `#importer-wizard`, więc HTMX nigdy +// NIE ZAPISZE snapshotu tej strony do localStorage — przy Back/Forward pyta +// serwer o pełną stronę (patrz `_is_htmx_partial` w views/helpers.py). +// +// Problem: `restoreHistory()` w HTMX czyta cache BEZ oglądania się na +// `hx-history` — ta flaga blokuje tylko ZAPIS (`saveCurrentPageToHistory`). +// Wpisy zapisane ZANIM flaga się pojawiła (układ kroku 1 sprzed kafelków: +// radiowy wybór źródła + lista sesji pod spodem) siedzą w localStorage +// przeglądarki bezterminowo i to je HTMX przywraca po naciśnięciu „Wstecz". +// Użytkownik widzi wtedy layout, którego nie ma już nawet w kodzie. +// +// Samo się to nie naprawi: skoro zapisu nigdy nie będzie, nic tych wpisów nie +// nadpisze (HTMX podmienia wpis o tym samym URL-u dopiero przy zapisie), a +// LRU wyrzuci je dopiero po 10 innych stronach z HTMX-em. Dlatego kasujemy je +// jawnie przy każdym wejściu na stronę importera. +(function (window) { + "use strict"; + + var KLUCZ = "htmx-history-cache"; + + // Usuń z cache HTMX-a wpisy, których URL zaczyna się od `prefiks`. + // Zwraca liczbę usuniętych wpisów (0 gdy nie było czego usuwać). + function usunWpisy(storage, prefiks) { + var surowe = storage.getItem(KLUCZ); + if (!surowe) { + return 0; + } + + var cache; + try { + cache = JSON.parse(surowe); + } catch (e) { + // Uszkodzony JSON (obcy kod pisał pod ten klucz, przerwany zapis). + // HTMX sam traktuje taki cache jak pusty (`parseJSON` zwraca null), + // więc kasujemy wpis w całości — inaczej zostawilibyśmy śmieć, + // którego i tak nikt nie odczyta. + storage.removeItem(KLUCZ); + return 0; + } + + if (!Array.isArray(cache)) { + storage.removeItem(KLUCZ); + return 0; + } + + var zostaje = cache.filter(function (wpis) { + return !( + wpis && + typeof wpis.url === "string" && + wpis.url.indexOf(prefiks) === 0 + ); + }); + + var usuniete = cache.length - zostaje.length; + if (usuniete > 0) { + storage.setItem(KLUCZ, JSON.stringify(zostaje)); + } + return usuniete; + } + + window.bppImporterHistoryCache = { usunWpisy: usunWpisy, KLUCZ: KLUCZ }; + + // Auto-start: prefiks URL-a importera wstrzykuje szablon (`data-prefiks`), + // żeby nie zaszywać tu ścieżki na sztywno. + var skrypt = window.document.currentScript; + if (!skrypt) { + return; + } + var prefiks = skrypt.getAttribute("data-prefiks"); + if (!prefiks) { + return; + } + try { + usunWpisy(window.localStorage, prefiks); + } catch (e) { + // localStorage niedostępny (tryb prywatny, zablokowane dane witryn) — + // wtedy HTMX też go nie odczyta, więc nieświeży snapshot nie ma jak + // się pojawić i nie ma czego sprzątać. Strona działa normalnie. + } +})(window); diff --git a/src/importer_publikacji/templates/importer_publikacji/index.html b/src/importer_publikacji/templates/importer_publikacji/index.html index 15b73ce13..b9f84fa48 100644 --- a/src/importer_publikacji/templates/importer_publikacji/index.html +++ b/src/importer_publikacji/templates/importer_publikacji/index.html @@ -49,6 +49,12 @@ animation: wizardFadeIn 0.3s ease-out; } + {# Kasuje nieświeże snapshoty HTMX-a dla stron importera z localStorage. #} + {# Musi pójść PRZED htmx.min.js: `restoreHistory()` czyta cache mimo #} + {# `hx-history="false"` (ta flaga blokuje tylko zapis), więc bez tego #} + {# „Wstecz" przywracał układ kroku 1 sprzed kafelków. Szczegóły w pliku. #} + {# HTMX self-hostowany — bez zależności od zewnętrznego CDN-a. #}