From 6c331ee827473fe74812cb2731e7568c2496e6d1 Mon Sep 17 00:00:00 2001 From: Ben Kurtovic Date: Thu, 29 Dec 2016 23:52:08 -0500 Subject: [PATCH] Add more nuanced/cleaner styling for campaign summaries. --- calefaction/format.py | 66 ++++++++++++++++++++++++ calefaction/modules/campaigns/update.py | 2 + static/main.css | 90 ++++++++++++++++++++++++++++++++- static/main.js | 19 +++++++ templates/campaigns/campaign.mako | 10 ++-- templates/campaigns/renderers.mako | 70 ++++++++++++++++++------- 6 files changed, 234 insertions(+), 23 deletions(-) create mode 100644 calefaction/format.py diff --git a/calefaction/format.py b/calefaction/format.py new file mode 100644 index 0000000..8c4c6bd --- /dev/null +++ b/calefaction/format.py @@ -0,0 +1,66 @@ +from datetime import datetime, timedelta + +import humanize + +__all__ = ["format_isk", "format_isk_compact", "format_utctime", + "format_utctime_compact"] + +def format_isk(value): + """Nicely format an ISK value.""" + if value < 10**6: + return "{:,.2f}".format(value) + return humanize.intword(value, "%.2f") + +def format_isk_compact(value): + """Nicely format an ISK value compactly.""" + # Based on humanize.intword(). + powers = [10 ** x for x in [3, 6, 9, 12, 15]] + letters = ["k", "m", "b", "t", "q"] + + if value < powers[0]: + return "{:,.2f}".format(value) + for ordinal, power in enumerate(powers[1:], 1): + if value < power: + chopped = value / float(powers[ordinal - 1]) + return "{:,.2f}{}".format(chopped, letters[ordinal - 1]) + return str(value) + +def format_utctime(value): + """Format a UTC timestamp.""" + return humanize.naturaltime(datetime.utcnow() - value) + +def _format_compact_delta(delta): + """Return a snippet of formatting for a time delta.""" + # Based on humanize.naturaldelta(). + seconds = abs(delta.seconds) + days = abs(delta.days) + years = days // 365 + days = days % 365 + months = int(days // 30.5) + + if years == 0 and days < 1: + if seconds < 60: + return "{}s".format(seconds) + if seconds < 3600: + minutes = seconds // 60 + return "{}m".format(minutes) + hours = seconds // 3600 + return "{}h".format(hours) + if years == 0: + if months == 0: + return "{}d".format(days) + return "{}mo".format(months) + if years == 1: + if months == 0: + if days == 0: + return "1y" + return "1y {}d".format(days) + return "1y {}mo".format(months) + return "{}y".format(years) + +def format_utctime_compact(value): + """Format a UTC timestamp compactly.""" + delta = datetime.utcnow() - value + if delta < timedelta(seconds=1): + return "just now" + return "{} ago".format(_format_compact_delta(delta)) diff --git a/calefaction/modules/campaigns/update.py b/calefaction/modules/campaigns/update.py index 3091da6..f19e2a4 100644 --- a/calefaction/modules/campaigns/update.py +++ b/calefaction/modules/campaigns/update.py @@ -87,6 +87,8 @@ def _update_collection_operations(cname, opnames): operation = campaign["operations"][opname] show_isk = operation.get("isk", True) + # store per-user counts; update for all users in corp who have fresh + # API keys and leave other data stale ... primary = __import__("random").randint(10, 99) secondary = __import__("random").randint(10000000, 5000000000) / 100 \ diff --git a/static/main.css b/static/main.css index 0a51d32..fdc101f 100644 --- a/static/main.css +++ b/static/main.css @@ -31,6 +31,11 @@ h2, h3 { margin: 0.5em 0; } +abbr[title], acronym[title] { + border-bottom: 1px dotted #555; + text-decoration: none; +} + .understate { font-weight: normal; } @@ -393,13 +398,88 @@ h2 .disabled-info { font-size: 150%; } +.operation .secondary { + font-size: 105%; +} + .operation .unit { font-style: italic; } +.operation .summary .head { + margin-top: 1em; + font-size: 14px; +} + +.operation .summary .contents { + position: relative; + margin-top: 0.5em; + border: 1px solid #282828; + font-size: 14px; +} + +.operation .killboard { + border-spacing: 0; + border-collapse: collapse; + text-align: left; +} + +.operation .killboard:not(.expanded) tr:nth-child(2n) { + background-color: #181818; +} + +.operation .killboard:not(.expanded) tr:nth-child(2n+1) { + background-color: #0A0A0A; +} + +.operation .killboard td { + padding: 0.25em 0; +} + +.operation .killboard td:first-child { + padding-left: 1em; +} + +.operation .killboard td:last-child { + padding-right: 1em; +} + +.operation .killboard .fluid { + padding-right: 0.5em; +} + +.operation .killboard .icon { + width: 46px; +} + +.operation .killboard.expanded { + position: absolute; + z-index: 1; + transition: clip-path 0.5s cubic-bezier(0.25, 0.46, 0.45, 0.94); + clip-path: inset(0 100% 0 0); +} + +.operation .killboard:not(.expanded) .extra { + display: none; +} + +.operation .killboard.expanded .spacer { + display: none; +} + +.operation .killboard img { + width: 42px; + height: 42px; + vertical-align: middle; +} + +.operation .killboard abbr { + border-bottom: none; +} + @media (min-width: 800px) { #operations { - margin: 1em 2em; + margin: 1em 0; } #operations section { @@ -429,6 +509,10 @@ h2 .disabled-info { margin: 0.5em 0; } + .operation .overview { + margin-left: 1em; + } + .operation .primary, .operation .primary .unit { display: inline-block; } @@ -436,6 +520,10 @@ h2 .disabled-info { .operation .unit { margin-left: 0.15em; } + + .operation .killboard:not(.expanded) { + width: 100%; + } } /* -------------------------------- Members -------------------------------- */ diff --git a/static/main.js b/static/main.js index a26ea39..ba498ab 100644 --- a/static/main.js +++ b/static/main.js @@ -64,4 +64,23 @@ $(function() { this.form.submit(); }); $('#campaigns-select input[type="submit"]').hide(); + + //Campaigns: selectively reveal operation summary details: + $(".operation .killboard tr").mouseenter(function() { + var div = $("", {addClass: "killboard expanded"}) + .css($(this).position()) + .css("background-color", $(this).css("background-color")) + .css("position", "fixed") + .append($("").html($(this).html())) + .mouseleave(function() { $(this).remove(); }); + div.find(".spacer").remove(); + $(this).closest(".summary").find(".expanded").remove(); + $(this).closest(".contents").prepend(div); + div.css("width", Math.max(div.width(), $(this).width())); + div.css("position", ""); + div.css("clip-path", "inset(0 0% 0 0)"); + }); + $(".operation .summary").mouseleave(function() { + $(this).find(".expanded").remove(); + }); }); diff --git a/templates/campaigns/campaign.mako b/templates/campaigns/campaign.mako index 3a5c9c9..1150ce2 100644 --- a/templates/campaigns/campaign.mako +++ b/templates/campaigns/campaign.mako @@ -1,4 +1,6 @@ -<%! import humanize %> +<%! + from calefaction.format import format_isk +%> <%inherit file="../_default.mako"/> <%namespace file="renderers.mako" import="render_summary"/> <%block name="title"> @@ -37,14 +39,16 @@ % if secondary is not None:
- ${humanize.intword(secondary) | h} + ${format_isk(secondary) | h} ${sunit}
% endif % if summary: - ${render_summary(renderer, summary)} +
+ ${render_summary(renderer, summary)} +
% endif % endfor diff --git a/templates/campaigns/renderers.mako b/templates/campaigns/renderers.mako index 47d96c7..055ed58 100644 --- a/templates/campaigns/renderers.mako +++ b/templates/campaigns/renderers.mako @@ -1,25 +1,57 @@ -<%! import humanize %> +<%! + from calefaction.format import format_isk_compact, format_utctime_compact +%> +<%def name="_killboard_kill(kill)"> + <% victim = kill["victim"] %> + + + + + + + + + % if not victim["alliance_id"] and not victim["faction_id"]: + + % endif + + <%def name="_killboard_recent(summary)"> - +
Most recent kills:
+
+
+ + ${format_utctime_compact(kill["date"]) | h}
+ ${format_isk_compact(kill["value"]) | h} +
+
+ + ${kill["system"]} 0.3
+ Region +
+
+ <!-- ... --> + + <!-- ... --> + + <!-- ... --> + + % if victim["alliance_id"]: + <!-- ... --> + % endif + + % if victim["faction_id"]: + <!-- ... --> + % endif +
+ % for kill in summary: + ${_killboard_kill(kill)} + % endfor +
+ - <%def name="render_summary(renderer, summary)"><% if renderer == "killboard_recent": return _killboard_recent(summary) - else: - raise RuntimeError("Unknown renderer: %s" % renderer) + raise RuntimeError("Unknown renderer: %s" % renderer) %>