]> gitweb.michael.orlitzky.com - charm-bypass.git/blob - index.html.in
src/index.html.in: move out of src
[charm-bypass.git] / index.html.in
1 <!doctype html>
2 <html lang="en-US">
3 <head>
4 <meta name="viewport" content="width=device-width, initial-scale=1" />
5
6 <title>
7 CharmBypass.
8 </title>
9
10 <style>
11 /*
12 * Reset styles for the html and body elements, the only two HTML
13 * elements we use. */
14 html, body {
15 margin: 0;
16 padding: 0;
17 border: 0;
18 font-weight: normal;
19 font-style: inherit;
20 font-size: 100%;
21 line-height: 1.5;
22 font-family: inherit;
23 text-align: inherit;
24 text-decoration: none;
25 vertical-align: baseline;
26 background: transparent;
27 }
28
29 html, body {
30 /* To create our "window" onto the scene, we're going to slide the
31 * SVG off the left-hand side of the screen, and we don't want
32 * scroll bars to appear. */
33 overflow: hidden;
34 }
35
36 svg {
37 /* Set the height to 100% of the screen, which we'll keep; and the
38 * initial position to (0,0), which we're going to change
39 * every time the window is resized, because the exact amount
40 * that we have to slide the SVG to the left to get the ticket
41 * into the center will change. */
42 position: fixed;
43 top: 0;
44 left: 0;
45 height: 100%;
46 }
47
48 /* The blinking fade in/out animation for the ticket date and time */
49 @keyframes blink {
50 25% {
51 opacity: 0.5;
52 }
53 50% {
54 opacity: 0;
55 }
56 75% {
57 opacity: 0.5;
58 }
59 }
60
61 #tickettime, #ticketdate {
62 animation: blink 2s linear infinite;
63 }
64
65 /* Define, load, and specify the custom font we use for the ticket
66 * date, time, and service name. */
67 @font-face {
68 font-family: "CharmBypass Regular";
69 src:
70 url("data:font/woff2;base64,@CBPREGULAR@") format("woff2")
71 }
72
73 #servicename, #tickettime, #ticketdate {
74 font-family: "CharmBypass Regular";
75 }
76
77 @font-face {
78 font-family: "CharmBypass Bold";
79 src:
80 url("data:font/woff2;base64,@CBPBOLD@") format("woff2")
81 }
82
83 #serviceletter {
84 font-family: "CharmBypass Bold";
85 }
86
87 /************************/
88 /* Scrolling animations */
89 /************************/
90
91 /* Bus */
92 @keyframes busroll {
93 from {
94 transform: translateX(0%);
95 }
96 to {
97 transform: translateX(100%);
98 }
99 }
100
101 #bus {
102 animation: busroll 23s linear infinite;
103 }
104
105
106 /* Tram */
107 @keyframes tramroll {
108 from {
109 transform: translateX(0%);
110 }
111 to {
112 transform: translateX(100%);
113 }
114 }
115
116 #tram {
117 animation: tramroll 17s linear infinite;
118 }
119
120
121 /* Tram */
122 @keyframes trainroll {
123 from {
124 transform: translateX(0%);
125 }
126 to {
127 transform: translateX(100%);
128 }
129 }
130
131 #train {
132 animation: trainroll 11s linear infinite;
133 }
134
135
136 /* Clouds */
137 @keyframes cloudsfloat {
138 from {
139 transform: translateX(0%);
140 }
141 to {
142 transform: translateX(-50%);
143 }
144 }
145
146 #clouds {
147 animation: cloudsfloat 40s linear infinite;
148 }
149
150 @keyframes cloudscopyfloat {
151 from {
152 transform: translateX(0%);
153 }
154 to {
155 transform: translateX(-50%);
156 }
157 }
158
159 #cloudscopy {
160 animation: cloudscopyfloat 40s linear infinite;
161 }
162
163
164 /* Trees */
165 @keyframes treespass {
166 from {
167 transform: translateX(0%);
168 }
169 to {
170 transform: translateX(-50%);
171 }
172 }
173
174 #trees {
175 /* The trees move a little faster than the clouds */
176 animation: treespass 30s linear infinite;
177 }
178
179 @keyframes treescopypass {
180 from {
181 transform: translateX(0%);
182 }
183 to {
184 transform: translateX(-50%);
185 }
186 }
187
188 #treescopy {
189 /* The trees move a little faster than the clouds */
190 animation: treescopypass 30s linear infinite;
191 }
192
193
194 /* City skyline */
195 @keyframes cityscroll {
196 from {
197 transform: translateX(0%);
198 }
199 to {
200 transform: translateX(-50%);
201 }
202 }
203
204 #city {
205 /* The city moves faster than the clouds but slower
206 * than the trees */
207 animation: cityscroll 35s linear infinite;
208 }
209
210 @keyframes citycopyscroll {
211 from {
212 transform: translateX(0%);
213 }
214 to {
215 transform: translateX(-50%);
216 }
217 }
218
219 #citycopy {
220 /* The city moves faster than the clouds but slower
221 * than the trees */
222 animation: citycopyscroll 35s linear infinite;
223 }
224 </style>
225 </head>
226
227 <body>
228 @SVGDATA@
229
230 <script>
231 /******************************************/
232 /* First, set up the ticket date and time */
233 /******************************************/
234
235 /* There are two parameters, time and date, that we store in one
236 * underlying "date" variable. Default both to an hour from now. This
237 * is sensible because the date/time shown on your ticket is its
238 * EXPIRATION time, and tickets are valid for two hours. Having it
239 * show one hour in the future means that you didn't just use your
240 * ticket a second ago (if you just got caught on the light rail, for
241 * example) but also means that it's not expiring for a while.
242 */
243 const date = new Date();
244
245 /* Add an hour. We use the low-level get/setTime to change the number
246 * of milliseconds since the epoch that this date represents. Obviously
247 * correct, and avoids all suspicious corner cases (well, for a few more
248 * decades). */
249 date.setTime(date.getTime() + (60*60*1000));
250
251 /* All <text> elements produced by inkscape contain a single <tspan>
252 * that itself contains the actual text. */
253 tt = document.getElementById("tickettime");
254 tt.firstChild.textContent = date.toLocaleTimeString();
255
256 const td = document.getElementById("ticketdate");
257 const dateopts = {
258 day: "2-digit",
259 month: "2-digit",
260 year: "2-digit"
261 };
262 td.firstChild.textContent = date.toLocaleDateString("en-US", dateopts);
263
264
265 /************************************************************/
266 /* Second, add the onclick handler for the night/day switch */
267 /************************************************************/
268
269 /* We always start in "day" mode */
270 is_day = true;
271
272 function set_day() {
273 sky.style.fill = "#efb02f";
274 }
275
276 function set_night() {
277 sky.style.fill = "#143b66";
278 }
279
280 function swap_colors() {
281 if (is_day) {
282 set_night();
283 is_day = false;
284 }
285 else {
286 set_day();
287 is_day = true;
288 }
289 }
290
291 document.body.addEventListener("click", swap_colors);
292
293
294 /*************************************************/
295 /* Finally, center the ticket within the browser */
296 /*************************************************/
297 function center_ticket() {
298 /* We're relying on the SVG being the full height of the
299 * viewport already, and on the aspect ratio being
300 * preserved. First, find the center of the ticket. */
301 const r = document.getElementById("ticket").getBoundingClientRect();
302 const c = r.left + (r.width / 2);
303
304 /* That's the center-line of the ticket. We want to move it to
305 * the center-line of the viewport. */
306 const vc = document.documentElement.clientWidth / 2;
307
308 /* This is how much we need to translate the SVG */
309 const delta = vc - c;
310
311 /* But before we can set the absolute left-coordinate of the
312 * SVG, we need to know where it is now. Note: without the
313 * "px" this doesn't default to pixels like CSS does. */
314 const svg = document.querySelector("svg");
315 svg.style.left = (svg.getBoundingClientRect().left + delta) + "px";
316 }
317
318 /* Re-center it when the window is resized */
319 window.addEventListener("resize", center_ticket);
320
321 /* Center it once when the page has loaded, too */
322 window.addEventListener("load", center_ticket);
323 </script>
324 </body>
325 </html>