feat(prezentacja): kliknięcie powiększa kosmogram na pełne okno (PRE-25) #29
Binary file not shown.
@@ -50,6 +50,24 @@ td.glyph { color: var(--accent); white-space: nowrap; }
|
|||||||
.wheel-fig figcaption { margin-top: .4rem; }
|
.wheel-fig figcaption { margin-top: .4rem; }
|
||||||
/* glify wewnątrz SVG dziedziczą monochromatyczny stack fontów (DAN-18) */
|
/* glify wewnątrz SVG dziedziczą monochromatyczny stack fontów (DAN-18) */
|
||||||
svg.wheel text.glyph { font-size: inherit; }
|
svg.wheel text.glyph { font-size: inherit; }
|
||||||
|
|
||||||
|
/* Powiększenie na pełne okno (PRE-25). Kliknięcie rozciąga wykres na cały ekran,
|
||||||
|
ponowne wraca. z-index 1100 CELOWO pomiędzy: ponad kontrolki Leafleta (1000),
|
||||||
|
ale PONIŻEJ okna postępu (1200) — gdy trwa pisanie horoskopu, log operacji ma
|
||||||
|
zostać na wierzchu. */
|
||||||
|
.wheel-fig svg.wheel { cursor: zoom-in; }
|
||||||
|
.wheel-fig svg.wheel:focus-visible { outline: 2px solid var(--accent); outline-offset: 4px; }
|
||||||
|
.wheel-fig.zoomed {
|
||||||
|
position: fixed; inset: 0; z-index: 1100; margin: 0;
|
||||||
|
display: flex; flex-direction: column; align-items: center; justify-content: center;
|
||||||
|
gap: .5rem; padding: 1rem; background: var(--bg);
|
||||||
|
}
|
||||||
|
/* min() po obu wymiarach: koło jest kwadratowe, więc ograniczamy je krótszym
|
||||||
|
bokiem okna — inaczej na szerokim ekranie wystawałoby w pionie. */
|
||||||
|
.wheel-fig.zoomed svg.wheel {
|
||||||
|
max-width: min(96vw, 92vh); width: min(96vw, 92vh); height: auto; cursor: zoom-out;
|
||||||
|
}
|
||||||
|
body.wheel-zoom-open { overflow: hidden; } /* nie przewijaj treści pod spodem */
|
||||||
form { background: var(--panel); border: 1px solid var(--line); border-radius: 12px; padding: 1.25rem; }
|
form { background: var(--panel); border: 1px solid var(--line); border-radius: 12px; padding: 1.25rem; }
|
||||||
.row { display: flex; gap: .5rem; }
|
.row { display: flex; gap: .5rem; }
|
||||||
.row input[type=text] { flex: 1; }
|
.row input[type=text] { flex: 1; }
|
||||||
|
|||||||
@@ -0,0 +1,60 @@
|
|||||||
|
// Powiększanie kosmogramu na pełne okno (PRE-25).
|
||||||
|
//
|
||||||
|
// Koło rysujemy w kolumnie tekstu, więc na małym ekranie glify i stopnie robią
|
||||||
|
// się nieczytelne. Kliknięcie rozciąga wykres na całe okno, ponowne wraca do
|
||||||
|
// strony. SVG skaluje się bez utraty jakości, więc nie potrzeba drugiej wersji
|
||||||
|
// rysunku ani żadnej biblioteki.
|
||||||
|
//
|
||||||
|
// Podpięte globalnie i osłonięte sprawdzeniem, czy koło w ogóle jest na stronie
|
||||||
|
// — dzięki temu zadziała też na przyszłej zakładce „Skompiluj", bez zmian tutaj.
|
||||||
|
(function () {
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
var ZOOMED = 'zoomed';
|
||||||
|
|
||||||
|
function ready(fn) {
|
||||||
|
if (document.readyState !== 'loading') fn();
|
||||||
|
else document.addEventListener('DOMContentLoaded', fn);
|
||||||
|
}
|
||||||
|
|
||||||
|
ready(function () {
|
||||||
|
var figures = document.querySelectorAll('.wheel-fig');
|
||||||
|
if (!figures.length) return;
|
||||||
|
|
||||||
|
Array.prototype.forEach.call(figures, function (fig) {
|
||||||
|
var svg = fig.querySelector('svg.wheel');
|
||||||
|
if (!svg) return;
|
||||||
|
|
||||||
|
// Klawiatura ma działać tak samo jak mysz — to nie jest ozdobnik, tylko
|
||||||
|
// jedyny sposób na obejrzenie szczegółów wykresu.
|
||||||
|
svg.setAttribute('tabindex', '0');
|
||||||
|
svg.setAttribute('role', 'button');
|
||||||
|
svg.setAttribute('aria-label', 'Kosmogram — kliknij, aby powiększyć na całe okno');
|
||||||
|
|
||||||
|
function toggle() {
|
||||||
|
var on = fig.classList.toggle(ZOOMED);
|
||||||
|
// Blokujemy przewijanie strony pod spodem: inaczej scroll „przecieka"
|
||||||
|
// na treść, której i tak nie widać.
|
||||||
|
document.body.classList.toggle('wheel-zoom-open', on);
|
||||||
|
svg.setAttribute('aria-label', on
|
||||||
|
? 'Kosmogram powiększony — kliknij lub naciśnij Esc, aby wrócić'
|
||||||
|
: 'Kosmogram — kliknij, aby powiększyć na całe okno');
|
||||||
|
if (on) svg.focus();
|
||||||
|
}
|
||||||
|
|
||||||
|
svg.addEventListener('click', toggle);
|
||||||
|
svg.addEventListener('keydown', function (e) {
|
||||||
|
if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); toggle(); }
|
||||||
|
});
|
||||||
|
|
||||||
|
// Klik w tło (poza samym rysunkiem) też zamyka — naturalne dla nakładki.
|
||||||
|
fig.addEventListener('click', function (e) {
|
||||||
|
if (e.target === fig && fig.classList.contains(ZOOMED)) toggle();
|
||||||
|
});
|
||||||
|
|
||||||
|
document.addEventListener('keydown', function (e) {
|
||||||
|
if (e.key === 'Escape' && fig.classList.contains(ZOOMED)) toggle();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
})();
|
||||||
@@ -10,6 +10,9 @@
|
|||||||
odtworzyć współrzędne, ZANIM geo.js zbuduje mapę — mapa startuje od razu
|
odtworzyć współrzędne, ZANIM geo.js zbuduje mapę — mapa startuje od razu
|
||||||
we właściwym miejscu, bez przestawiania. #}
|
we właściwym miejscu, bez przestawiania. #}
|
||||||
<script defer src="/static/formsync.js"></script>
|
<script defer src="/static/formsync.js"></script>
|
||||||
|
{# Powiększanie kosmogramu (PRE-25) — globalnie, bo koło pojawi się też na
|
||||||
|
zakładce „Skompiluj"; skrypt sam sprawdza, czy jest co powiększać. #}
|
||||||
|
<script defer src="/static/wheelzoom.js"></script>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<main>
|
<main>
|
||||||
|
|||||||
@@ -0,0 +1,64 @@
|
|||||||
|
"""Powiększanie kosmogramu na pełne okno (PRE-25).
|
||||||
|
|
||||||
|
Test strukturalny, jak przy pozostałych rzeczach żyjących w JS/CSS. Osobno
|
||||||
|
pilnujemy warstwy nakładki: to jedyna liczba w tym pliku, którą łatwo zmienić
|
||||||
|
bez zastanowienia i zepsuć coś, czego się nie widzi na pierwszy rzut oka.
|
||||||
|
"""
|
||||||
|
import pathlib
|
||||||
|
import re
|
||||||
|
|
||||||
|
APP = pathlib.Path(__file__).resolve().parents[1] / "app"
|
||||||
|
JS = (APP / "static" / "wheelzoom.js").read_text(encoding="utf-8")
|
||||||
|
CSS = (APP / "static" / "styles.css").read_text(encoding="utf-8")
|
||||||
|
BASE = (APP / "templates" / "base.html").read_text(encoding="utf-8")
|
||||||
|
|
||||||
|
|
||||||
|
def test_script_is_loaded_globally():
|
||||||
|
"""Ładowane w base.html, bo koło pojawi się też na zakładce Skompiluj."""
|
||||||
|
assert "wheelzoom.js" in BASE
|
||||||
|
|
||||||
|
|
||||||
|
def test_toggles_on_click():
|
||||||
|
assert "addEventListener('click'" in JS
|
||||||
|
assert "classList.toggle" in JS
|
||||||
|
|
||||||
|
|
||||||
|
def test_closes_with_escape():
|
||||||
|
assert "'Escape'" in JS
|
||||||
|
|
||||||
|
|
||||||
|
def test_reachable_from_keyboard():
|
||||||
|
"""Bez tego jedyny sposób na obejrzenie szczegółów wykresu wymagałby myszy."""
|
||||||
|
assert "tabindex" in JS
|
||||||
|
assert "'Enter'" in JS
|
||||||
|
|
||||||
|
|
||||||
|
def test_page_scroll_is_locked_while_zoomed():
|
||||||
|
"""Inaczej przewijanie „przecieka" na treść pod spodem, której i tak nie widać."""
|
||||||
|
assert "wheel-zoom-open" in JS
|
||||||
|
assert re.search(r"body\.wheel-zoom-open\s*\{[^}]*overflow:\s*hidden", CSS)
|
||||||
|
|
||||||
|
|
||||||
|
def test_zoomed_layer_sits_above_map_but_below_progress():
|
||||||
|
"""Warstwy: kontrolki Leafleta 1000 < kosmogram < okno postępu 1200.
|
||||||
|
Gdy trwa pisanie horoskopu, log operacji ma zostać na wierzchu."""
|
||||||
|
zoom = re.search(r"\.wheel-fig\.zoomed\s*\{[^}]*z-index:\s*(\d+)", CSS)
|
||||||
|
progress = re.search(r"\.progress-overlay\s*\{[^}]*z-index:\s*(\d+)", CSS)
|
||||||
|
assert zoom and progress, "nie znaleziono warstw w CSS"
|
||||||
|
assert 1000 < int(zoom.group(1)) < int(progress.group(1))
|
||||||
|
|
||||||
|
|
||||||
|
def test_zoomed_wheel_is_bounded_by_shorter_window_side():
|
||||||
|
"""Koło jest kwadratowe — ograniczamy je krótszym bokiem okna, inaczej na
|
||||||
|
szerokim ekranie wystawałoby w pionie."""
|
||||||
|
block = re.search(r"\.wheel-fig\.zoomed svg\.wheel\s*\{[^}]*\}", CSS)
|
||||||
|
assert block and "vh" in block.group(0) and "vw" in block.group(0)
|
||||||
|
|
||||||
|
|
||||||
|
def test_cursor_signals_the_affordance():
|
||||||
|
assert "zoom-in" in CSS and "zoom-out" in CSS
|
||||||
|
|
||||||
|
|
||||||
|
def test_does_nothing_without_a_wheel():
|
||||||
|
"""Na zakładkach bez kosmogramu skrypt ma po prostu wyjść."""
|
||||||
|
assert "if (!figures.length) return;" in JS
|
||||||
Reference in New Issue
Block a user