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; }
|
||||
/* glify wewnątrz SVG dziedziczą monochromatyczny stack fontów (DAN-18) */
|
||||
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; }
|
||||
.row { display: flex; gap: .5rem; }
|
||||
.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
|
||||
we właściwym miejscu, bez przestawiania. #}
|
||||
<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>
|
||||
<body>
|
||||
<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