source: OpenWorkouts-current/ow/templates/profile.pt @ 39dc0a6

current
Last change on this file since 39dc0a6 was 39dc0a6, checked in by Borja Lopez <borja@…>, 5 years ago

(#7) Pass in the selector name for the calendar heatmap tooltip container
when building an "instance" of the calendar chart code.

(#7) Fixed a bug in the fade in/out of the heatmap tooltip (tooltip display
were queued so the tooltip keep fading in and out for a while after the
user did stop moving around on the chart)

  • Property mode set to 100644
File size: 23.4 KB
Line 
1<html xmlns="http://www.w3.org/1999/xhtml"
2      xml:lang="en"
3      xmlns:tal="http://xml.zope.org/namespaces/tal"
4      xmlns:metal="http://xml.zope.org/namespaces/metal"
5      xmlns:i18n="http://xml.zope.org/namespaces/i18n"
6      i18n:domain="OpenWorkouts"
7      metal:use-macro="load: base.pt"
8      tal:attributes="lang request.locale_name">
9
10  <metal:head-title metal:fill-slot="head-title">
11    <tal:t i18n:translate="">My profile</tal:t>
12  </metal:head-title>
13
14  <metal:css metal:fill-slot="css">
15    <link rel="stylesheet" href="${request.static_url('ow:static/components/jquery-dropdown/jquery.dropdown.css')}" />
16  </metal:css>
17
18  <metal:content metal:fill-slot="content">
19
20    <div class="user-profile">
21      <div class="user-profile-account">
22        <div>
23          <tal:c tal:condition="getattr(user, 'picture', None)">
24            <img tal:attributes="src request.resource_path(user, 'picture', query={'size': 200})"
25                 width="450" />
26          </tal:c>
27          <div>
28            <h2>
29              <tal:fullname tal:content="user.fullname"></tal:fullname>
30            </h2>
31            <p>
32              <tal:has-nickname tal:condition="user.nickname">
33                <a href=""
34                   tal:attributes="href request.resource_url(request.root, 'profile', user.nickname)"
35                   tal:content="request.resource_url(request.root, 'profile', user.nickname)">
36                </a> |
37              </tal:has-nickname>
38              <span><tal:email tal:content="user.email"></tal:email></span>
39            </p>
40            <div class="profile-bio">
41              <p tal:repeat="paragraph getattr(user, 'bio', '').split('\n')"
42                 tal:content="paragraph"></p>
43            </div>
44            <ul class="workout-options">
45              <li><a href=""
46                     tal:attributes="href request.resource_url(user, 'edit')"
47                     i18n:translate="">edit profile</a></li>
48              <li><a href=""
49                     tal:attributes="href request.resource_url(user, 'passwd')"
50                     i18n:translate="">change password</a></li>
51            </ul>
52          </div>
53          <div class="calendar-heatmap js-calendar-heatmap">
54          </div>
55          <div class="calendar-heatmap-tooltip js-ch-tooltip">
56            <ul class="profile-data">
57              <li>
58                <span class="js-ch-tooltip-date"></span>
59              </li>
60              <li>
61                <span><tal:t i18n:translate="">Workouts:</tal:t></span>
62                <span class="js-ch-tooltip-workouts"></span>
63              </li>
64              <li>
65                <span><tal:t i18n:translate="">Time:</tal:t></span>
66                <span class="js-ch-tooltip-time"></span>
67              </li>
68              <li>
69                <span><tal:t i18n:translate="">Distance:</tal:t></span>
70                <span class="js-ch-tooltip-distance"></span>
71              </li>
72              <li>
73                <span><tal:t i18n:translate="">Elevation:</tal:t></span>
74                <span class="js-ch-tooltip-elevation"></span>
75              </li>
76            </ul>
77          </div>
78        </div>
79
80      </div>
81
82      <div class="workout-content">
83        <div class="workout-list">
84          <div class="total-workouts">
85            <span>
86              <tal:w tal:replace="len(workouts)"></tal:w>
87              <tal:t i18n:translate="">workouts</tal:t>
88            </span>
89            <span>
90              <tal:hms tal:define="hms timedelta_to_hms(totals['time'])">
91                <tal:h tal:content="str(hms[0]).zfill(2)"></tal:h>
92                <tal:t i18n:translate="">hours</tal:t>,
93                <tal:h tal:content="str(hms[1]).zfill(2)"></tal:h>
94                <tal:t i18n:translate="">min.</tal:t>
95              </tal:hms>
96            </span>
97            <span>
98              <tal:w tal:replace="round(totals['distance'])"></tal:w>
99              <tal:t i18n:translate="">km</tal:t>
100            </span>
101            <span>
102              <tal:w tal:replace="round(totals['elevation'])"></tal:w>
103              <tal:t i18n:translate="">m</tal:t>
104            </span>
105          </div>
106
107          <div class="month-stats js-month-stats">
108            <div class="svg-content">
109              <svg width="900" height="180" viewBox="0 0 900 180"></svg>
110            </div>
111            <div class="center">
112              <ul class="workout-options filters js-filters">
113                <li><a href="#" class="js-distance is-active" i18n:translate="">distance</a></li>
114                <li><a href="#" class="js-time" i18n:translate="">time</a></li>
115                <li><a href="#" class="js-elevation" i18n:translate="">elevation</a></li>
116              </ul>
117
118              <ul class="workout-options switcher js-switcher"
119                  tal:define="weekly 'week' in request.GET">
120                <li>
121                  <a href="#" class="" i18n:translate=""
122                     tal:attributes="class 'js-weekly is-active' if weekly else 'js-weekly'">
123                    weekly</a></li>
124                <li>
125                  <a href="#" class="" i18n:translate=""
126                     tal:attributes="class 'js-monthly is-active' if not weekly else 'js-monthly'">
127                    monthly</a></li>
128              </ul>
129            </div>
130          </div>
131
132
133          <tal:r tal:repeat="workout workouts">
134
135            <article class="workout-resume">
136
137              <h2 class="workout-title">
138                <a href="" tal:content="workout.title"
139                   tal:attributes="href request.resource_url(workout)"></a>
140              </h2>
141
142              <ul class="workout-info">
143                <li>
144                  <tal:c tal:content="workout.start_in_timezone(user.timezone)"></tal:c>
145                </li>
146                <li>
147                  <!--! use the properly formatted duration instead of the timedelta object -->
148                  <tal:c tal:content="workout._duration"></tal:c>
149                </li>
150                <li tal:condition="workout.distance">
151                  <tal:c tal:content="workout.rounded_distance"></tal:c> km
152                </li>
153                <li tal:condition="workout.uphill">
154                  +<tal:c tal:content="workout.uphill"></tal:c> m
155                </li>
156              </ul>
157
158              <ul class="workout-info" tal:define="hr workout.hr; cad workout.cad">
159                <li tal:condition="hr">
160                  <span i18n:translate="">HR (bpm)</span>:
161                  <tal:c tal:content="hr['avg']"></tal:c>
162                  <tal:t i18n:translate="">Avg.</tal:t>,
163                  <tal:c tal:content="hr['max']"></tal:c>
164                  <tal:t i18n:translate="">Max.</tal:t>
165                </li>
166                <li tal:condition="cad">
167                  <span i18n:translate="">Cad</span>:
168                  <tal:c tal:content="cad['avg']"></tal:c>
169                  <tal:t i18n:translate="">Avg.</tal:t>,
170                  <tal:c tal:content="cad['max']"></tal:c>
171                  <tal:t i18n:translate="">Max.</tal:t>
172                </li>
173              </ul>
174
175              <div class="workout-intro">
176                <p tal:repeat="paragraph workout.trimmed_notes.split('\n')"
177                   tal:content="paragraph"></p>
178              </div>
179
180              <div class="workout-map" tal:condition="workout.has_gpx">
181                <a href="" tal:attributes="href request.resource_url(workout)">
182                  <tal:has-screenshot tal:condition="workout.map_screenshot is not None">
183                    <img src="" tal:attributes="src request.static_url(workout.map_screenshot);
184                              alt workout.title; title workout.title">
185                  </tal:has-screenshot>
186                  <tal:has-not-screenshot tal:condition="workout.map_screenshot is None">
187                    <img src="" tal:attributes="src request.static_url('ow:static/media/img/no_map.gif');
188                              alt workout.title; title workout.title; class 'js-needs-map'">
189                  </tal:has-not-screenshot>
190                </a>
191              </div>
192
193            </article>
194
195          </tal:r>
196        </div>
197
198        <div class="workout-aside">
199
200          <h3 i18n:translate="">Profile info</h3>
201
202          <ul class="profile-data">
203            <li>
204              <span><tal:t i18n:translate="">Gender:</tal:t></span>
205              <tal:c tal:content="user_gender"></tal:c>
206            </li>
207            <li tal:define="birth_date getattr(user, 'birth_date', None)">
208              <span><tal:t i18n:translate="">Birth date:</tal:t></span>
209              <tal:c tal:condition="birth_date"
210                     tal:content="birth_date.strftime('%d/%m/%Y')"></tal:c>
211              <tal:c tal:condition="birth_date is None">-</tal:c>
212            </li>
213            <li>
214              <span><tal:t i18n:translate="">Height:</tal:t></span>
215              <tal:c tal:content="getattr(user, 'height', '-')"></tal:c> meters
216            </li>
217            <li>
218              <span><tal:t i18n:translate="">Weight:</tal:t></span>
219              <tal:c tal:content="getattr(user, 'weight', '-')"></tal:c> kg
220            </li>
221          </ul>
222
223          <tal:has-workouts tal:condition="profile_stats['sports']">
224
225            <h3 i18n:translate="">Workout stats</h3>
226
227            <p>
228              <a href="" data-jq-dropdown="#jq-dropdown-sports"
229                 class="profile-dropdown-sports js-jq-dropdown-sel-sports">
230                <strong tal:content="profile_stats['current_sport']"></strong>
231                <i class="arrow down"></i>
232              </a>
233            </p>
234
235            <tal:sports tal:repeat="sport profile_stats['sports']">
236              <div class="" tal:attributes="class 'js-sport-stats js-' + sport">
237
238                <a href="" data-jq-dropdown=""
239                   tal:attributes="data-jq-dropdown '#jq-dropdown-' + sport;
240                         class 'profile-dropdown-years js-jq-dropdown-sel-' + sport">
241                  <strong tal:content="profile_stats['current_year']"></strong>
242                  <i class="arrow down"></i>
243                </a>
244
245                <tal:years tal:repeat="year profile_stats['years']">
246                  <div class="" tal:attributes="class 'js-year-stats js-' + sport + '-' + str(year)">
247                    <ul class="profile-data"
248                        tal:define="sport_totals user.sport_totals(sport, year)">
249                      <li>
250                        <span>
251                          <tal:t i18n:translate="">Workouts</tal:t>
252                        </span>
253                        <tal:w tal:replace="sport_totals['workouts']"></tal:w>
254                      </li>
255                      <li>
256                        <span>
257                          <tal:t i18n:translate="">Time</tal:t>
258                        </span>
259                        <tal:hms tal:define="hms timedelta_to_hms(sport_totals['time'])">
260                          <tal:h tal:content="str(hms[0]).zfill(2)"></tal:h>
261                          <tal:t i18n:translate="">hours</tal:t>,
262                          <tal:h tal:content="str(hms[1]).zfill(2)"></tal:h>
263                          <tal:t i18n:translate="">min.</tal:t>
264                        </tal:hms>
265                      </li>
266                      <li>
267                        <span>
268                          <tal:t i18n:translate="">Distance</tal:t>
269                        </span>
270                        <tal:w tal:replace="round(sport_totals['distance'])"></tal:w>
271                        <tal:t i18n:translate="">km</tal:t>
272                      </li>
273                      <li>
274                        <span>
275                          <tal:t i18n:translate="">Elevation</tal:t>
276                        </span>
277                        <tal:w tal:replace="round(sport_totals['elevation'])"></tal:w>
278                        <tal:t i18n:translate="">m</tal:t>
279                      </li>
280                      <li><span i18n:translate="">Single workout records:</span></li>
281                      <li>
282                        <span>
283                          <tal:t i18n:translate="">Farthest distance</tal:t>
284                        </span>
285                        <tal:has-wid tal:condition="sport_totals['max_distance_wid'] is not None">
286                          <a href="" tal:attributes="href request.resource_url(user[sport_totals['max_distance_wid']])">
287                            <tal:w tal:replace="round(sport_totals['max_distance'])"></tal:w>
288                            <tal:t i18n:translate="">km</tal:t>
289                          </a>
290                        </tal:has-wid>
291                        <tal:has-not-wid tal:condition="sport_totals['max_distance_wid'] is None">
292                          <tal:w tal:replace="round(sport_totals['max_distance'])"></tal:w>
293                          <tal:t i18n:translate="">km</tal:t>
294                        </tal:has-not-wid>
295                      </li>
296                      <li>
297                        <span>
298                          <tal:t i18n:translate="">Longer workout</tal:t>
299                        </span>
300                        <tal:has-wid tal:condition="sport_totals['max_time_wid'] is not None">
301                          <a href="" tal:attributes="href request.resource_url(user[sport_totals['max_time_wid']])">
302                            <tal:hms tal:define="hms timedelta_to_hms(sport_totals['max_time'])">
303                              <tal:h tal:content="str(hms[0]).zfill(2)"></tal:h>
304                              <tal:t i18n:translate="">hours</tal:t>,
305                              <tal:h tal:content="str(hms[1]).zfill(2)"></tal:h>
306                              <tal:t i18n:translate="">min.</tal:t>
307                            </tal:hms>
308                          </a>
309                        </tal:has-wid>
310                        <tal:has-not-wid tal:condition="sport_totals['max_time_wid'] is None">
311                          <tal:hms tal:define="hms timedelta_to_hms(sport_totals['max_time'])">
312                            <tal:h tal:content="str(hms[0]).zfill(2)"></tal:h>
313                            <tal:t i18n:translate="">hours</tal:t>,
314                            <tal:h tal:content="str(hms[1]).zfill(2)"></tal:h>
315                            <tal:t i18n:translate="">min.</tal:t>
316                          </tal:hms>
317                        </tal:has-not-wid>
318                      </li>
319                      <li>
320                        <span>
321                          <tal:t i18n:translate="">Higher elevation gain</tal:t>
322                        </span>
323                        <tal:has-wid tal:condition="sport_totals['max_elevation_wid'] is not None">
324                          <a href="" tal:attributes="href request.resource_url(user[sport_totals['max_elevation_wid']])">
325                            <tal:w tal:replace="round(sport_totals['max_elevation'])"></tal:w>
326                            <tal:t i18n:translate="">m</tal:t>
327                          </a>
328                        </tal:has-wid>
329                        <tal:has-not-wid tal:condition="sport_totals['max_elevation_wid'] is None">
330                          <tal:w tal:replace="round(sport_totals['max_elevation'])"></tal:w>
331                          <tal:t i18n:translate="">m</tal:t>
332                        </tal:has-not-wid>
333                      </li>
334                    </ul>
335                  </div>
336                </tal:years>
337
338                <strong i18n:translate="">All time</strong>
339                <ul class="profile-data"
340                    tal:define="sport_totals user.sport_totals(sport)">
341                  <li>
342                    <span>
343                      <tal:t i18n:translate="">Workouts</tal:t>
344                    </span>
345                    <tal:w tal:replace="sport_totals['workouts']"></tal:w>
346                  </li>
347                  <li>
348                    <span>
349                      <tal:t i18n:translate="">Time</tal:t>
350                    </span>
351                    <tal:hms tal:define="hms timedelta_to_hms(sport_totals['time'])">
352                      <tal:h tal:content="str(hms[0]).zfill(2)"></tal:h>
353                      <tal:t i18n:translate="">hours</tal:t>,
354                      <tal:h tal:content="str(hms[1]).zfill(2)"></tal:h>
355                      <tal:t i18n:translate="">min.</tal:t>
356                    </tal:hms>
357                  </li>
358                  <li>
359                    <span>
360                      <tal:t i18n:translate="">Distance</tal:t>
361                    </span>
362                    <tal:w tal:replace="round(sport_totals['distance'])"></tal:w>
363                    <tal:t i18n:translate="">km</tal:t>
364                  </li>
365                  <li>
366                    <span>
367                      <tal:t i18n:translate="">Elevation</tal:t>
368                    </span>
369                    <tal:w tal:replace="round(sport_totals['elevation'])"></tal:w>
370                    <tal:t i18n:translate="">m</tal:t>
371                  </li>
372                  <li><span i18n:translate="">Single workout records:</span></li>
373                  <li>
374                    <span>
375                      <tal:t i18n:translate="">Farthest distance</tal:t>
376                    </span>
377                    <tal:has-wid tal:condition="sport_totals['max_distance_wid'] is not None">
378                      <a href="" tal:attributes="href request.resource_url(user[sport_totals['max_distance_wid']])">
379                        <tal:w tal:replace="round(sport_totals['max_distance'])"></tal:w>
380                        <tal:t i18n:translate="">km</tal:t>
381                      </a>
382                    </tal:has-wid>
383                    <tal:has-not-wid tal:condition="sport_totals['max_distance_wid'] is None">
384                      <tal:w tal:replace="round(sport_totals['max_distance'])"></tal:w>
385                      <tal:t i18n:translate="">km</tal:t>
386                    </tal:has-not-wid>
387                  </li>
388                  <li>
389                    <span>
390                      <tal:t i18n:translate="">Longer workout</tal:t>
391                    </span>
392                    <tal:has-wid tal:condition="sport_totals['max_time_wid'] is not None">
393                      <a href="" tal:attributes="href request.resource_url(user[sport_totals['max_time_wid']])">
394                        <tal:hms tal:define="hms timedelta_to_hms(sport_totals['max_time'])">
395                          <tal:h tal:content="str(hms[0]).zfill(2)"></tal:h>
396                          <tal:t i18n:translate="">hours</tal:t>,
397                          <tal:h tal:content="str(hms[1]).zfill(2)"></tal:h>
398                          <tal:t i18n:translate="">min.</tal:t>
399                        </tal:hms>
400                      </a>
401                    </tal:has-wid>
402                    <tal:has-not-wid tal:condition="sport_totals['max_time_wid'] is None">
403                      <tal:hms tal:define="hms timedelta_to_hms(sport_totals['max_time'])">
404                        <tal:h tal:content="str(hms[0]).zfill(2)"></tal:h>
405                        <tal:t i18n:translate="">hours</tal:t>,
406                        <tal:h tal:content="str(hms[1]).zfill(2)"></tal:h>
407                        <tal:t i18n:translate="">min.</tal:t>
408                      </tal:hms>
409                    </tal:has-not-wid>
410                  </li>
411                  <li>
412                    <span>
413                      <tal:t i18n:translate="">Higher elevation gain</tal:t>
414                    </span>
415                    <tal:has-wid tal:condition="sport_totals['max_elevation_wid'] is not None">
416                      <a href="" tal:attributes="href request.resource_url(user[sport_totals['max_elevation_wid']])">
417                        <tal:w tal:replace="round(sport_totals['max_elevation'])"></tal:w>
418                        <tal:t i18n:translate="">m</tal:t>
419                      </a>
420                    </tal:has-wid>
421                    <tal:has-not-wid tal:condition="sport_totals['max_elevation_wid'] is None">
422                      <tal:w tal:replace="round(sport_totals['max_elevation'])"></tal:w>
423                      <tal:t i18n:translate="">m</tal:t>
424                    </tal:has-not-wid>
425                  </li>
426                </ul>
427              </div>
428            </tal:sports>
429
430          </tal:has-workouts>
431
432        </div>
433      </div>
434    </div>
435
436      <div id="jq-dropdown-sports" class="jq-dropdown jq-dropdown-tip">
437        <ul class="jq-dropdown-menu">
438          <tal:sports tal:repeat="sport profile_stats['sports']">
439            <li>
440              <a href="#" class="" tal:content="sport"
441                 tal:attributes="class 'js-choose-sport-stats js-' + sport">
442              </a>
443            </li>
444          </tal:sports>
445        </ul>
446      </div>
447
448
449    <tal:sports tal:repeat="sport profile_stats['sports']">
450      <div id="" class="jq-dropdown jq-dropdown-tip"
451           tal:attributes="id 'jq-dropdown-' + sport">
452        <ul class="jq-dropdown-menu">
453          <tal:years tal:repeat="year profile_stats['years']">
454            <li>
455              <a href="#" class="" tal:content="year"
456                 tal:attributes="class 'js-choose-year-stats js-' + sport + '-' + str(year)">
457              </a>
458            </li>
459          </tal:years>
460        </ul>
461      </div>
462    </tal:sports>
463
464
465  </metal:content>
466
467  <metal:body-js metal:fill-slot="body-js">
468
469    <script src="${request.static_url('ow:static/components/jquery-dropdown/jquery.dropdown.js')}"></script>
470    <script src="${request.static_url('ow:static/components/d3/d3.min.js')}"></script>
471    <script src="${request.static_url('ow:static/js/ow.js')}"></script>
472
473    <script type="text/javascript">
474     var map_shots = owjs.map_shots({
475         img_selector: 'img.js-needs-map',
476     })
477     map_shots.run();
478
479     var sport_stats = owjs.sport_stats({
480         link_selector: 'a.js-choose-sport-stats',
481         stats_selector: 'div.js-sport-stats',
482         selected: 'div.js-sport-stats.js-${profile_stats['current_sport']}',
483         dropdown_selector: 'a.js-jq-dropdown-sel-sports',
484         current_year: '${profile_stats['current_year']}',
485         year_link_selector: 'a.js-choose-year-stats.js-'
486     })
487     sport_stats.setup();
488
489     var heatmap_chart = owjs.calendar_heatmap_chart({
490         chart_selector: 'div.js-calendar-heatmap',
491         tooltip_selector: '.js-ch-tooltip',
492         url: "${request.resource_url(user, 'month')}",
493         // Trick to have all those shortened day names translated
494         day_names_list: "${_('Mo Tu We Th Fr Sa Su')}".split(' ')
495     });
496     heatmap_chart.render();
497
498     var year_stats = owjs.year_stats({
499         link_selector: 'a.js-choose-year-stats',
500         stats_selector: 'div.js-year-stats',
501         selected: 'div.js-year-stats.js-${profile_stats['current_sport']}-${profile_stats['current_year']}',
502         dropdown_selector: 'a.js-jq-dropdown-sel-'
503     })
504     year_stats.setup();
505
506     var y_axis_labels = {
507         "distance": "Kilometers",
508         "time": "Hours",
509         "elevation": "Meters"
510     };
511
512     var year_chart = owjs.year_chart({
513         chart_selector: '.js-month-stats svg',
514         filters_selector: '.js-month-stats .js-filters a',
515         switcher_selector: '.js-month-stats .js-switcher a',
516         is_active_class: 'is-active',
517         urls: {"monthly": "${request.resource_url(user, 'monthly')}",
518                "weekly": "${request.resource_url(user, 'weekly')}"},
519         current_month: "${current_month}",
520         current_week: "${current_week}",
521         y_axis_labels: y_axis_labels,
522         filter_by: "distance",
523         url: "${'monthly' if current_week is None else 'weekly'}",
524     });
525     year_chart.render("distance", "${'monthly' if current_week is None else 'weekly'}");
526     year_chart.filters_setup();
527     year_chart.switcher_setup();
528    </script>
529
530  </metal:body-js>
531
532</html>
Note: See TracBrowser for help on using the repository browser.