diff options
author | Aurélien Bompard <aurelien@bompard.org> | 2013-11-20 10:14:51 -0800 |
---|---|---|
committer | Aurélien Bompard <aurelien@bompard.org> | 2013-11-20 10:14:51 -0800 |
commit | c8ef5f4be18890bfee301df3bfd41e4f0434451e (patch) | |
tree | 243ce6eac57d016569bd2dc014f4da40ab724a36 | |
parent | f38e0d666c86220089a6d5afe940aabb762a0a21 (diff) | |
parent | 174ab43c1c2bca4d01626a73379d0f2aed23b2d9 (diff) | |
download | hyperkitty-c8ef5f4be18890bfee301df3bfd41e4f0434451e.tar.gz hyperkitty-c8ef5f4be18890bfee301df3bfd41e4f0434451e.tar.xz hyperkitty-c8ef5f4be18890bfee301df3bfd41e4f0434451e.zip |
Merge pull request #10 from mairin/master
List overview redesign
-rw-r--r-- | doc/database.rst | 3 | ||||
-rw-r--r-- | hyperkitty/static/hyperkitty/css/hyperkitty-common.css | 7 | ||||
-rw-r--r-- | hyperkitty/static/hyperkitty/css/hyperkitty-overview.css | 189 | ||||
-rw-r--r-- | hyperkitty/static/hyperkitty/css/hyperkitty-threadslist.css | 7 | ||||
-rw-r--r-- | hyperkitty/static/hyperkitty/js/hyperkitty-overview.js | 200 | ||||
-rw-r--r-- | hyperkitty/templates/overview.html | 139 | ||||
-rw-r--r-- | hyperkitty/templates/threads/summary_thread.html | 20 | ||||
-rw-r--r-- | hyperkitty/templatetags/storm.py | 4 |
8 files changed, 461 insertions, 108 deletions
diff --git a/doc/database.rst b/doc/database.rst index c71162f..ade71f9 100644 --- a/doc/database.rst +++ b/doc/database.rst @@ -61,7 +61,8 @@ where: ``django-admin`` command) * ``NAME`` is the fully-qualified list name (including the ``@`` sign and the domain name) -* The ``mbox_file`` arguments are the existing archives to import. +* The ``mbox_file`` arguments are the existing archives to import. Make sure you point +at the *.txt version of the files and not the *.gz. If the previous archives aren't available locally, you need to download them from your current Mailman 2.1 installation. The ``kittystore-download21`` diff --git a/hyperkitty/static/hyperkitty/css/hyperkitty-common.css b/hyperkitty/static/hyperkitty/css/hyperkitty-common.css index dab65bb..c262308 100644 --- a/hyperkitty/static/hyperkitty/css/hyperkitty-common.css +++ b/hyperkitty/static/hyperkitty/css/hyperkitty-common.css @@ -325,4 +325,9 @@ a.thread-new strong { display: none; /* Displayed manually */ } - +h1 { + margin-top: 0px; + font-size: 28px !important; /* override bootstrap */ + line-height: 32px; + margin-bottom: 0.5em; +} diff --git a/hyperkitty/static/hyperkitty/css/hyperkitty-overview.css b/hyperkitty/static/hyperkitty/css/hyperkitty-overview.css index a54c281..c91ea36 100644 --- a/hyperkitty/static/hyperkitty/css/hyperkitty-overview.css +++ b/hyperkitty/static/hyperkitty/css/hyperkitty-overview.css @@ -1,53 +1,62 @@ /* Summary page */ -#overview h2 { - font-size: 22px; - line-height: 32px; - margin-bottom: 0.5em; - text-align: center; +#overview h2 #breadcrumb { + font-weight: normal; + font-size: 12px; } #overview h3 { - font-size: 20px; + font-size: 14px; line-height: 28px; margin-bottom: 0.5em; margin-top: 0; - text-align: center; } -#graph h2 { - text-align: center; -} -#graph rect { +#chart-data rect { cursor: pointer; } -#fig { +#fig, #chart-data { position: relative; margin: auto; - width: 540px; - height: 300px; + font-size: 8pt; + font-family: "Droid Sans", sans-serf; + font-color: #777; } -#fig .axis path, #fig .axis line { + +#fig .axis path, #fig .axis line, +#chart-data .axis path, #chart-data .axis line { +/* fill: none; - stroke: #000; + stroke: #bbb; shape-rendering: geometricPrecision; +*/ + display: none; } -#fig .area { +#fig .area, +#chart-data .bars rect { fill: steelBlue; } -#overview .list-stats { - text-align: center; -} -#overview p.thread-new { - text-align: center; +/* Next 2 blocks for grid lines */ + +/* +#fig .grid .tick, +#chart-data .grid .tick { + stroke: lightgrey; + opacity: 0.3; } +#fig .grid path, +#chart-data .grid path { + stroke-width: 0; +} +*/ +/* #overview .widget { padding: 1em; border: 1px solid #ddd; @@ -56,6 +65,7 @@ border-radius: 10px; margin: 1em 0; } +*/ #overview .thread { margin: 1.5em 0 0 0; @@ -107,7 +117,7 @@ font-weight: bold; font-size: 115%; vertical-align: top; - padding-right: 20px; + padding-right: 3px; } .maker .gravatar { @@ -140,3 +150,136 @@ #discussion-by-category .thread .category { display: none; } + + +section#title h2 { + + margin-bottom: 0px; +} + + +section#title #description { + font-size: 12pt; + font-weight: normal; +} + +section#title svg { + padding-top: 3px; + border: 1px solid #bbb; +} + +section#title #chart { + margin-top: 2em; +} + +section#title p.thread-new { + text-align: left; + margin-top: 1em; +} + +section#statistics { + color: #555; +} + +section#statistics .caption { + font-size: x-small; + color: #aaa; + margin-top: -.5%; + margin-left: .25em; + margin-bottom: 0px; +} + +section#statistics ul { + list-style-type: none; + margin-left: 0px; +} + +section#statistics li { + font-size: small; +} + +section#statistics h3 { + margin-bottom: .5em; + margin-top: 3em; +} + +#overview h3 { + color: #999; + text-transform: uppercase; + font-size: small; + font-weight: normal; +} + + +#title { + float: left; + width: 23%; + min-width: 20%; + margin-right: 2%; +} + +#discussions { + margin-top: 3em; + padding-left: 1%; + float: right; + width: 74%; +} + +/* this needs to be integrated into hyperkitty-threadslist.css eventually */ +div.thread { + border: 1px solid #e5e5e5; + padding: 1%; + margin: .5% !important; +} + +.thread { + min-height: 1.2em; +} + +.widget { + clear: both; + margin-bottom: 2em; +} + +.thread ul.inline-block { + width: 28%; +} + +.thread ul.inline-block li, +.thread ul.inline-block span { + text-align: left; + min-width: 6.5%; +} + +.thread-title { + width: 68%; + float: left; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + margin-right: 2%; +} + + +.maker-name, .maker-id { + font-size: small; +} + +.maker-id { + color: #aaa; +} + +.thread-id { + float: left; +} + +.maker-name { + display: block !important; + max-width: 152px !important; + word-wrap: break-word !important; +} + +.maker .gravatar { + padding-right: 5px; +} + diff --git a/hyperkitty/static/hyperkitty/css/hyperkitty-threadslist.css b/hyperkitty/static/hyperkitty/css/hyperkitty-threadslist.css index a2e49ad..6effca1 100644 --- a/hyperkitty/static/hyperkitty/css/hyperkitty-threadslist.css +++ b/hyperkitty/static/hyperkitty/css/hyperkitty-threadslist.css @@ -53,7 +53,6 @@ .thread-title { font-weight: bold; - font-size: 125%; } .thread-date { @@ -74,6 +73,12 @@ float: left; } +.thread-title .category { + width: 15%; + text-align: center; + margin-right: 1%; +} + .thread-info .tags { display: inline; margin-right: 1em; diff --git a/hyperkitty/static/hyperkitty/js/hyperkitty-overview.js b/hyperkitty/static/hyperkitty/js/hyperkitty-overview.js index bf88118..e020554 100644 --- a/hyperkitty/static/hyperkitty/js/hyperkitty-overview.js +++ b/hyperkitty/static/hyperkitty/js/hyperkitty-overview.js @@ -21,8 +21,9 @@ /* - * Recent activity graph + * Recent activity graph (area graph) */ + function activity_graph(elem_id, dates, counts, baseurl) { function merge(dates, counts) { result = [] @@ -34,13 +35,30 @@ function activity_graph(elem_id, dates, counts, baseurl) { } return result; } + + /* Function for grid lines, for x-axis */ + function make_x_axis() { + return d3.svg.axis() + .scale(x) + .orient("bottom") + .ticks(d3.time.days, 1) + } + + /* Function for grid lines, for y-axis */ + function make_y_axis() { + return d3.svg.axis() + .scale(y) + .orient("left") + .ticks(5) + } + var data = merge(dates, counts); - var margin = {top: 20, right: 20, bottom: 100, left: 50}, - width = 540 - margin.left - margin.right, - height = 330 - margin.top - margin.bottom; + var margin = {top: 20, right: 20, bottom: 50, left: 40}, + width = 350 - margin.left - margin.right, + height = 150 - margin.top - margin.bottom; var format_in = d3.time.format("%Y-%m-%d"); - var format_out = d3.time.format("%m-%d"); + var format_out = d3.time.format(""); var x = d3.time.scale() .range([0, width]); @@ -51,16 +69,19 @@ function activity_graph(elem_id, dates, counts, baseurl) { var xAxis = d3.svg.axis() .scale(x) .orient("bottom") + .tickSize(2,2) .tickFormat(format_out) - .ticks(d3.time.days, 2); - + .ticks(d3.time.days, 1); + var yAxis = d3.svg.axis() .scale(y) .orient("left") - .ticks(5) + .tickSize(4,3) + .ticks(2) .tickSubdivide(1); var area = d3.svg.area() + .interpolate("monotone") .x(function(d) { return x(d.date); }) .y0(height) .y1(function(d) { return y(d.count); }); @@ -78,6 +99,23 @@ function activity_graph(elem_id, dates, counts, baseurl) { x.domain(d3.extent(data, function(d) { return d.date; })); y.domain([0, d3.max(data, function(d) { return d.count; })]); + + /* Draw the grid lines, for x-axis */ + svg.append("g") + .attr("class", "grid") + .attr("Transform", "translate(0, " + height + ")") + .call(make_x_axis() + .tickSize(height, 0, 0) + .tickFormat("") + ) + + /* Draw the grid lines, for y-axis */ + svg.append("g") + .attr("class", "grid") + .call(make_y_axis() + .tickSize(-width, 0, 0) + .tickFormat("") + ) svg.append("path") .datum(data) @@ -95,13 +133,153 @@ function activity_graph(elem_id, dates, counts, baseurl) { return "rotate(-90)" }); + /* Y-axis label */ svg.append("g") .attr("class", "y axis") .call(yAxis) .append("text") .attr("transform", "rotate(-90)") - .attr("y", 6) - .attr("dy", ".71em") - .style("text-anchor", "end") + .attr("y", 0) + .attr("x", 0 - height/2) + .attr("dy", "-3em") + .style("text-anchor", "middle") + .style("fill", "#777") .text("Messages"); + +} + + +/* + * Recent activity bar chart + */ +function chart(elem_id, dates, counts, baseurl) { + function merge(dates, counts) { + result = [] + for(i = 0; i < dates.length; i++) { + result.push({ + "date": dates[i], + "count": counts[i] + }) + } + return result; + } + + /* Function for grid lines, for x-axis */ + function make_x_axis() { + return d3.svg.axis() + .scale(x) + .orient("bottom") + .ticks(d3.time.days, 1) + } + + /* Function for grid lines, for y-axis */ + function make_y_axis() { + return d3.svg.axis() + .scale(y) + .orient("left") + .ticks(5) + } + + var data = merge(dates, counts); + var margin = {top: 0, right: 0, bottom: 0, left: 0}, + width = 200 - margin.left - margin.right, + height = 50 - margin.top - margin.bottom; + + var w = 5; + + var format_in = d3.time.format("%Y-%m-%d"); + var format_out = d3.time.format(""); + + var x = d3.time.scale() + .range([0, width]); + + var y = d3.scale.linear() + .range([height, 0]); + + var xAxis = d3.svg.axis() + .scale(x) + .orient("bottom") + .tickSize(0,0) // change to 2,2 for ticks + .tickFormat(format_out) + .ticks(d3.time.days, 1); + + var yAxis = d3.svg.axis() + .scale(y) + .orient("left") + .tickSize(0,0) // change to 4,3 for ticks + .ticks("") // change to 2 for y-axis tick labels + .tickSubdivide(1); + + var area = d3.svg.area() + .x(function(d) { return x(d.date); }) + // .y0(height) + .y(function(d) { return y(d.count); }); + + var svg = d3.select(elem_id).append("svg") + .attr("id", "chart-data") + .attr("width", width + margin.left + margin.right) + .attr("height", height + margin.top + margin.bottom) + .append("g") + .attr("transform", "translate(" + margin.left + "," + margin.top + ")"); + + data.forEach(function(d) { + d.date = format_in.parse(d.date); + d.count = parseInt(d.count); + }); + + x.domain(d3.extent(data, function(d) { return d.date; })); + y.domain([0, d3.max(data, function(d) { return d.count; })]); + + + /* Draw the grid lines, for x-axis */ + svg.append("g") + .attr("class", "grid") + .attr("Transform", "translate(0, " + height + ")") + .call(make_x_axis() + .tickSize(height, 0, 0) + .tickFormat("") + ) + + /* Draw the grid lines, for y-axis */ + svg.append("g") + .attr("class", "grid") + .call(make_y_axis() + .tickSize(-width, 0, 0) + .tickFormat("") + ) + + svg.append("g").attr("class","bars").selectAll("rect") + .data(data) + .enter().append("rect") + .attr("x", function(d) { return x(d.date); }) + //.attr("y0", height) + .attr("y", function(d) { return y(d.count); }) + .attr("width", w) + .attr("height", function(d) { return height - y(d.count); }); + + /* draw x-axis */ + svg.append("g") + .attr("class", "x axis") + .attr("transform", "translate(0," + height + ")") + .call(xAxis) + /*.selectAll("text") + .attr("y", -5) + .attr("x", -30) + .attr("transform", function(d) { + return "rotate(-90)" + });*/ + + /* Y-axis label */ + svg.append("g") + .attr("class", "y axis") + .call(yAxis) + /*.append("text") + .attr("transform", "rotate(-90)") + .attr("y", 0) + .attr("x", 0 - height/2) + .attr("dy", "-3em") + .style("text-anchor", "middle") + .style("fill", "#777") + .text("Messages"); */ + } diff --git a/hyperkitty/templates/overview.html b/hyperkitty/templates/overview.html index 8d521a6..098e609 100644 --- a/hyperkitty/templates/overview.html +++ b/hyperkitty/templates/overview.html @@ -18,66 +18,71 @@ {% include 'threads/month_list.html' %} <section id="overview" class="span10"> - - <section id="graph"> - <h2>Activities on the list over the last 30 days</h2> - <ul class="list-stats inline"> - <li><span class="participant">{{ num_participants }} participants</span></li> - <li><span class="discussion">{{ num_threads }} discussions</span></li> - </ul> - - <div id="fig" /> - </section> - - <p class="thread-new"> - <a href="{% url "message_new" mlist_fqdn=mlist.name %}" - class="thread-new btn{% if not user.is_authenticated %} disabled" title="You must be logged-in to create a thread.{% endif %}" - ><strong>+</strong> Start a new thread</a> - </p> - - <div class="row-fluid"> - <div class="span6"> <!-- Column 1 --> - - <section id="most-active" class="widget"> - <h3>Recently active discussions</h3> - {% for thread in most_active_threads %} - {% include "threads/summary_thread.html" with counter=forloop.counter %} - {% endfor %} - </section> - - <section id="popular-threads" class="widget"> - <h3>Most popular discussions</h3> - {% for thread in pop_threads %} - {% include "threads/summary_thread.html" with counter=forloop.counter %} - {% empty %} - <p>No vote has been cast this month (yet).</p> - {% endfor %} - </section> - - <section id="discussion-maker" class="widget"> - <h3>Most active posters</h3> - {% for poster in top_posters %} - <div class="maker"> - <div class="inline-block maker-id"> - #{{forloop.counter}} - </div> - <div class="inline-block gravatar"> - {% gravatar poster.email 40 %} - <br /> - </div> - <div class="inline-block"> - <span class="maker-name">{{ poster.name }}</span> - <br /> - <span class="score">{{ poster.count }}</span> posts - </div> - </div> - {% endfor %} - </section> - - </div> - <div class="span6"> <!-- Column 2 --> - - <section id="top-discussion" class="widget"> + + <section id="title"> + <h2>{{ mlist.display_name }}</h2> + <p id="description">{{ mlist.description}}</p> + + <section id="statistics"> + + <div id="chart"></div> + <p class="caption">Post volume over the past <strong>30</strong> days.</p> + + <p class="thread-new"> + <a href="{% url "message_new" mlist_fqdn=mlist.name %}" + class="thread-new btn{% if not user.is_authenticated %} disabled" title="You must be logged-in to create a thread.{% endif %}"> + <strong>+</strong> Start a new thread</a> + </p> + + <h3>Activity Summary</h3> + <p>The following statistics are from the past <strong>30</strong> days:</p> + <ul class="list-stats"> + <li><span class="participant">{{ num_participants }} participants</span></li> + <li><span class="discussion">{{ num_threads }} discussions</span></li> + </ul> + + <section id="discussion-maker" class="widget"> + <h3>Most active posters</h3> + {% for poster in top_posters %} + <div class="maker"> + <div class="inline-block maker-id"> + #{{forloop.counter}} + </div> + <div class="inline-block gravatar"> + {% gravatar poster.email 40 %} + <br /> + </div> + <div class="inline-block"> + <span class="maker-name">{{ poster.name }}</span> + <span class="score">{{ poster.count }}</span> posts + </div> + </div> + {% endfor %} + </section> + + <!-- <div id="fig"></div> --> + </section> + </section> + + <section id="discussions"> + + <section id="most-active" class="widget"> + <h3>Recently active discussions</h3> + {% for thread in most_active_threads %} + {% include "threads/summary_thread.html" %} <!-- cut - with counter=forloop.counter --> + {% endfor %} + </section> + + <section id="popular-threads" class="widget"> + <h3>Most popular discussions</h3> + {% for thread in pop_threads %} + {% include "threads/summary_thread.html" with counter=forloop.counter %} + {% empty %} + <p>No vote has been cast this month (yet).</p> + {% endfor %} + </section> + + <section id="top-discussion" class="widget"> <h3>Most active discussions</h3> {% for thread in top_threads %} {% include "threads/summary_thread.html" with counter=forloop.counter %} @@ -129,8 +134,7 @@ </section> {% endif %} - </div> - </div> + </section> </section> @@ -141,6 +145,7 @@ {% block additionaljs %} <script type="text/javascript" > +/* $(function() { activity_graph( "#fig", @@ -149,6 +154,16 @@ "{{ archives_baseurl }}" ) }); +*/ + + $(function() { + chart( + "#chart", + ["{{days|join:'","'}}"], + {{evolution}}, + "{{ archives_baseurl }}" + ) + }); </script> {% endblock %} diff --git a/hyperkitty/templates/threads/summary_thread.html b/hyperkitty/templates/threads/summary_thread.html index 2176936..e9b2b1f 100644 --- a/hyperkitty/templates/threads/summary_thread.html +++ b/hyperkitty/templates/threads/summary_thread.html @@ -3,21 +3,23 @@ {% load storm %} <div class="thread"> - {% if counter %}<span class="thread-id">#{{counter}}</span>{% endif %} - <span class="thread-title"><a name="{{thread.thread_id}}" + <span class="thread-title"> + {% if counter %}<span class="thread-id">#{{counter}}</span>{% endif %} + <a name="{{thread.thread_id}}" href="{% url 'thread' threadid=thread.thread_id mlist_fqdn=mlist.name %}" - >{{ thread.subject|strip_subject:mlist }}</a> - {% if thread.unread %} + > + {% if thread.category %} + <span class="label category" style="background-color:{{thread.category.color}}"> + {{ thread.category.name|upper }} + </span> + {% endif %} + {% if thread.unread %} <i class="unread icon-eye-close" title="New messages in this thread"></i> {% endif %} + {{ thread.subject|strip_subject:mlist }}</a> </span> <div class="thread-stats"> <ul class="inline-block"> - {% if thread.category %} - <span class="label category" style="background-color:{{thread.category.color}}"> - {{ thread.category.name|upper }} - </span> - {% endif %} <li class="participant"> {{ thread.participants|length }} </li> diff --git a/hyperkitty/templatetags/storm.py b/hyperkitty/templatetags/storm.py index b2112d2..0195dc7 100644 --- a/hyperkitty/templatetags/storm.py +++ b/hyperkitty/templatetags/storm.py @@ -33,3 +33,7 @@ def count(expr): @register.filter(name="strip_subject") def strip_subject(subject, mlist): return stripped_subject(mlist, subject) + +@register.filter(name="shorten_list_name") +def shorten_list_name(mlist): + return mlist.name.title().split('@')[0] |