Change map
[wolnelektury.git] / src / references / templates / references / onepager.html
1 <!DOCTYPE html>
2
3 {% load l10n %}
4
5 <html lang="pl">
6 <head>
7 <meta charset="UTF-8">
8 <title>Karta obiektu — {{ entity.label }}</title>
9 <meta name="viewport" content="width=device-width, initial-scale=1">
10 <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.9.4/leaflet.min.css" />
11 <script src="https://cdnjs.cloudflare.com/ajax/libs/leaflet/1.9.4/leaflet.min.js"></script>
12 <script src="https://cdnjs.cloudflare.com/ajax/libs/qrcodejs/1.0.0/qrcode.min.js"></script>
13
14 <link rel="preconnect" href="https://fonts.googleapis.com">
15 <link href="https://fonts.googleapis.com/css2?family=Newsreader:ital,opsz,wght@0,6..72,400;0,6..72,500;0,6..72,600;1,6..72,400&family=Courier+Prime:wght@400;700&display=swap" rel="stylesheet">
16
17 <style>
18   *{ box-sizing:border-box; }
19
20   html,body{
21     margin:0; padding:0;
22     background:#fff;
23     font-family:'Newsreader', serif;
24     color:#000;
25   }
26
27   /* ---------- PAGE / PRINT ---------- */
28   @page{ size:A4; margin:0; }
29
30   .page{
31     width:210mm;
32     margin:0 auto;
33     background:#fff;
34     padding:16mm 16mm 12mm 16mm;
35     position:relative;
36   }
37
38   /* ---------- HEADER ---------- */
39   .header{
40     display:flex;
41     justify-content:space-between;
42     align-items:flex-start;
43     border-bottom:1.5px solid #000;
44     padding-bottom:5mm;
45     margin-bottom:6mm;
46     gap:8mm;
47   }
48
49   .title-block .kicker{
50     font-family:'Courier Prime', monospace;
51     font-size:10px;
52     letter-spacing:.18em;
53     text-transform:uppercase;
54     color:#000;
55     margin-bottom:2mm;
56   }
57   .title-block h1{
58     margin:0;
59     font-size:40px;
60     line-height:1;
61     font-weight:600;
62   }
63
64   /* pieczęć z kodem QR do Wikipedii — obrazek dostarczony przez serwer */
65   .stamp{
66     flex:0 0 auto;
67     width:28mm;
68     text-align:center;
69   }
70   .stamp .seal-ring{
71     width:26mm; height:26mm;
72     border-radius:50%;
73     border:1.4px solid #000;
74     outline:1px dashed #000;
75     outline-offset:2px;
76     display:flex; align-items:center; justify-content:center;
77     padding:2mm;
78   }
79   .stamp .seal-ring img{
80     width:100%; height:100%;
81     display:block;
82   }
83   .qr img{
84     position:relative;
85     z-index:1;
86   }
87   .stamp .cap{
88     margin-top:1.5mm;
89     font-family:'Courier Prime', monospace;
90     font-size:8.5px;
91     letter-spacing:.1em;
92     text-transform:uppercase;
93     color:#000;
94   }
95
96   /* ---------- MAPA + ZDJĘCIA ---------- */
97   .visuals{
98     display:grid;
99     grid-template-columns:1.1fr 0.9fr;
100     gap:7mm;
101     margin-bottom:6mm;
102   }
103
104
105   @media print {
106       .leaflet-control {
107           display: none;
108       }
109   }
110   /* gdy nie ma mapy: zdjęcia zajmują całą szerokość */
111   .page.no-map .visuals{
112     grid-template-columns:1fr;
113   }
114   .page.no-map .illustrations{
115     column-count:4;
116   }
117
118   .map-frame .label,
119   .illustrations .label{
120     font-family:'Courier Prime', monospace;
121     font-size:9px;
122     letter-spacing:.12em;
123     text-transform:uppercase;
124     color:#000;
125     margin-bottom:4mm;
126     column-span:all;
127   }
128   #map{
129     width:100%;
130     height:62mm;
131     border:1px solid #000;
132   }
133   .coords{
134     margin-top:1.5mm;
135     font-family:'Courier Prime', monospace;
136     font-size:9px;
137     color:#000;
138   }
139
140   /* zdjęcia "przyklejone", dowolne proporcje — CSS columns robi
141      naturalny układ pod różne wysokości (portrait/landscape mix) */
142   .illustrations{
143     column-count:2;
144     column-gap:4mm;
145   }
146   .illu{
147     break-inside:avoid;
148     margin-bottom:5mm;
149     position:relative;
150     background:#fff;
151     padding:2mm 2mm 5mm 2mm;
152     box-shadow:0 2px 6px rgba(0,0,0,.22);
153     border:1px solid #000;
154   }
155   .illu:nth-child(odd){ transform:rotate(-2deg); }
156   .illu:nth-child(even){ transform:rotate(1.6deg); }
157   .illu .tape{
158     position:absolute; top:-2mm; left:50%; transform:translateX(-50%) rotate(-2deg);
159     width:14mm; height:5mm;
160     background:rgba(0,0,0,.35);
161     border:1px solid rgba(0,0,0,.5);
162   }
163   .illu img{
164     width:100%; height:auto; display:block; /* naturalne proporcje, bez cropu */
165   }
166   .illu .cap{
167     margin-top:1.5mm;
168     font-family:'Courier Prime', monospace;
169     font-size:7px;
170     color:#000;
171     text-align:center;
172   }
173
174   /* ---------- PRZERWA ---------- */
175   .tear{
176     display:flex; align-items:center; gap:2mm;
177     margin:0 0 6mm 0;
178   }
179   .tear .dots{ flex:1; border-top:2px dashed #000; }
180   .tear .txt{
181     font-family:'Courier Prime', monospace;
182     font-size:8.5px;
183     letter-spacing:.2em;
184     text-transform:uppercase;
185     color:#000;
186   }
187
188   /* ---------- FRAGMENTY (bilety) ---------- */
189   .fragment{
190     display:grid;
191     grid-template-columns:16mm 1fr 22mm;
192     gap:4mm;
193     align-items:center;
194     padding:3mm 0;
195     border-bottom:1px dotted #000;
196     break-inside:avoid;
197   }
198   .fragment:last-child{ border-bottom:none; }
199
200   .cover{
201     width:16mm; height:22mm;
202     border:1px solid #000;
203     box-shadow:0 2px 5px rgba(0,0,0,.28);
204     overflow:hidden;
205   }
206   .cover img{ width:100%; height:100%; object-fit:cover; display:block; }
207
208   .frag-text .book{
209     font-family:'Courier Prime', monospace;
210     font-size:9.5px;
211     color:#000;
212     margin-bottom:.8mm;
213   }
214   .frag-text .book b{ color:#000; font-weight:700; }
215   .frag-text .quote{
216     font-style:italic;
217     font-size:13px;
218     line-height:1.35;
219   }
220   .frag-text .where{
221     margin-top:1mm;
222     font-family:'Courier Prime', monospace;
223     font-size:8px;
224     color:#000;
225   }
226
227   .qr-mini{ width:22mm; text-align:center; }
228   .qr-mini .box{
229     width:20mm; height:20mm;
230     margin:0 auto;
231   }
232   .qr-mini .box img{ width:100%; height:100%; display:block; }
233   .qr-mini .cap{
234     margin-top:1mm;
235     font-family:'Courier Prime', monospace;
236     font-size:6.5px;
237     letter-spacing:.06em;
238     text-transform:uppercase;
239     color:#000;
240   }
241
242 </style>
243 </head>
244 <body>
245
246 <div class="page {% if not entity.lat %}no-map{% endif %}" id="page">
247   <div class="header">
248     <div class="title-block">
249       <div class="kicker">Mapa Wolnych Lektur</div>
250       <h1>{{ entity.label }}</h1>
251     </div>
252     {% if entity.wikipedia_link %}
253     <div class="stamp">
254       <div class="seal-ring qr" data-qr="{{ entity.wikipedia_link }}">
255       </div>
256       <div class="cap">Wikipedia →</div>
257     </div>
258     {% endif %}
259   </div>
260
261   <div class="visuals">
262
263     {% if entity.lon %}
264     <div class="map-frame">
265       <div class="label">Lokalizacja</div>
266       {% localize off %}
267       <div id="map" data-lat="{{ entity.lat }}" data-lon="{{ entity.lon }}"></div>
268       {% endlocalize %}
269       <div class="coords">{{ coords_label }}</div>
270     </div>
271     {% endif %}
272
273     {% if entity.get_images %}
274     <div class="illustrations">
275       <div class="label">Ilustracje</div>
276       {% for illu in entity.get_images|slice:":4" %}
277       <div class="illu">
278         <div class="tape"></div>
279         <img src="{{ illu.url }}">
280         <div class="cap">{{ illu.caption }}</div>
281       </div>
282       {% endfor %}
283     </div>
284     {% endif %}
285   </div>
286
287   <div class="tear"><div class="dots"></div><div class="txt">fragmenty tekstu</div><div class="dots"></div></div>
288
289   <div class="fragments">
290     {% for ref in entity.reference_set.all|slice:":3" %}
291     <div class="fragment">
292       <div class="cover">
293         <img src="{{ ref.book.cover_clean.url }}" alt="Okładka: {{ ref.book.pretty_title }}">
294       </div>
295       <div class="frag-text">
296         <div class="book"><b>
297             {% for author in ref.book.authors %}
298             {{ author.name }}{% if not forloop.last %}, {% endif %}
299             {% endfor %}
300           </b> — {{ ref.book.title }}</div>
301         {% for occ in ref.occurence_set.all|slice:":3" %}
302         <div class="quote">{{ occ.html|safe }}</div>
303         {% endfor %}
304       </div>
305       {% with occ=ref.occurence_set.all.first %}
306       <div class="qr-mini">
307         <div class="box qr" data-qr="https://wolnelektury.pl/katalog/lektura/{{ ref.book.slug }}.html#sec{{ occ.section }}">
308         </div>
309         <div class="cap">zobacz w treści</div>
310       </div>
311       {% endwith %}
312     </div>
313     {% endfor %}
314   </div>
315 </div>
316
317 <script>
318   // Jedyny JS w tym pliku: inicjalizacja mapy, jeśli jest obecna.
319   const mapEl = document.getElementById('map');
320   if (mapEl) {
321     const lat = parseFloat(mapEl.dataset.lat);
322     const lon = parseFloat(mapEl.dataset.lon);
323     const map = L.map(mapEl, {
324         attributionControl:false,
325     }).setView([lat, lon], 11);
326     L.tileLayer('https://tile.thunderforest.com/atlas/{z}/{x}/{y}@2x.png?apikey=a8a97f0ae5134403ac38c1a075b03e15').addTo(map);
327     L.marker([lat, lon]).addTo(map);
328     setTimeout(() => map.invalidateSize(), 200);
329   }
330
331
332   for (let e of document.getElementsByClassName('qr')) {
333       new QRCode(e, {
334           text: e.dataset.qr,
335           width: 160, height: 160,
336           colorDark: "#000000", colorLight: "#ffffff",
337           correctLevel: QRCode.CorrectLevel.M
338       });
339   }
340
341
342 </script>
343
344 </body>
345 </html>