better roadmap styling?

This commit is contained in:
Jeremy Kauffman 2016-08-21 23:08:15 -04:00
parent dfa6e1a06b
commit 7453aa9e4b
14 changed files with 302 additions and 156 deletions

View file

@ -116,9 +116,10 @@ class ContentActions extends Actions
public static function executeRoadmap()
{
$items = array_merge(Github::listRoadmapChangesets(), Asana::listRoadmapTasks());
return ['content/roadmap', [
'tasks' => Asana::listRoadmapTasks(),
'changesets' => Github::listRoadmapChangesets()
'closedGroups' => ['0.1', '0.2'], //should be dynamic
'items' => $items
]];
}

View file

@ -5,7 +5,7 @@ class Curl
const GET = 'GET',
POST = 'POST',
PUT = 'PUT',
DEFAULT_CACHE = 60000;
DEFAULT_CACHE = 600000;
public static function get($url, $params = [], $options = [])
{

View file

@ -62,45 +62,50 @@ class Asana
158602294500214 => ['Other', null]
];
$tasks = [
'ongoing' => [],
'upcoming' => []
];
$groupCategories = ['ongoing', 'upcoming'];
$tasks = [];
$categories = array_keys($tasks);
foreach($projects as $projectId => $projectTuple)
{
list($projectName, $projectUrl) = $projectTuple;
$projectTasks = static::get('/tasks?' . http_build_query(['completed_since' => 'now', 'project' => $projectId]));
$key = null;
$group = null;
foreach ($projectTasks as $task)
{
if (mb_substr($task['name'], -1) === ':') //if task ends with ":", it is a category heading so switch the active key
{
$key = array_reduce($categories, function($carry, $category) use($task) {
return $carry ?: (strcasecmp($task['name'], $category . ':') === 0 ? $category : null);
$group = array_reduce($groupCategories, function($carry, $candidate) use($task) {
return $carry ?: (strcasecmp($task['name'], $candidate . ':') === 0 ? $candidate : null);
});
}
elseif ($key && $task['name'])
elseif ($group && $task['name'])
{
$fullTask = static::get('/tasks/' . $task['id']);
$tasks[$key][] = array_intersect_key($fullTask, ['name' => null, 'due_on' => null]) + [
$tasks[$group][] = array_intersect_key($fullTask, ['name' => null]) + [
'project' => $projectName,
'date' => $fullTask['due_on'] ?? null,
'body' => $fullTask['notes'],
'url' => $projectUrl,
'group' => $group,
'assignee' => $fullTask['assignee'] ? ucwords($fullTask['assignee']['name']) : ''
];
}
}
}
foreach($tasks as &$taskSet)
foreach($tasks as &$groupTasks)
{
usort($taskSet, function($tA, $tB) {
if ($tA['due_on'] xor $tB['due_on'])
usort($groupTasks, function ($tA, $tB)
{
if ($tA['group'] != $tB['group'])
{
return $tA['due_on'] ? -1 : 1;
return $tA['group'] <= $tB['group'] ? -1 : 1;
}
return $tA['due_on'] < $tB['due_on'] ? -1 : 1;
if ($tA['date'] xor $tB['date'])
{
return $tA['date'] ? -1 : 1;
}
return $tA['date'] < $tB['date'] ? -1 : 1;
});
}

View file

@ -32,7 +32,7 @@ class Github
public static function get($endpoint)
{
return Curl::get('https://api.github.com' . $endpoint, [], ['user_agent' => 'LBRY', 'json_response' => true, 'cache' => false]);
return Curl::get('https://api.github.com' . $endpoint, [], ['user_agent' => 'LBRY', 'json_response' => true, 'cache' => true]);
}
public static function listRoadmapChangesets()
@ -46,26 +46,62 @@ class Github
{
$releases = static::get('/repos/lbryio/lbry/releases?page=' . $page);
$page++;
$allReleases = array_merge($allReleases, $releases);
$allReleases = array_merge($allReleases, array_filter($releases, function($release) {
return isset($release['tag_name']) && isset($release['published_at']) && $release['published_at'];
}));
} while (count($releases) >= 30);
usort($allReleases, function($rA, $rB) {
if ($rA['prerelease'] xor $rB['prerelease'])
{
return $rA['prerelease'] ? -1 : 1;
}
return $rA['tag_name'] < $rB['tag_name'];
});
// echo '<pre>';
// print_r($allReleases);
// echo '</pre>';
// die();
foreach($allReleases as $release)
{
// static::get('/repos/lbryio/lbry/releases')
$sets[$release['tag_name']] = array_intersect_key($release, ['prerelease' => null]) + [
'published_at' => date('Y-m-d', strtotime($release['published_at'])),
'body' => ParsedownExtra::instance()->text($release['body'])
];
$group = null;
$matches = null;
if (isset($release['tag_name']) && preg_match('/v(\d+)\.(\d+).?(\d+)?/', $release['tag_name'], $matches))
{
$group = $matches[1] . '.' . $matches[2];
}
if ($group)
{
$sets[$group][] = array_intersect_key($release, ['prerelease' => null, 'tag_name' => null, 'published_at' => null]) + [
'date' => date('Y-m-d', strtotime($release['created_at'])), //I thought published_at, but GitHub displays created_at and published_at is out of sync sometimes (0.3.2, 0.3.3)
'name' => $release['name'] ?: $release['tag_name'],
'major_version' => $matches[1],
'minor_version' => $matches[2],
'patch_version' => isset($matches[3]) ? $matches[3] : null,
'body' => ParsedownExtra::instance()->text($release['body'])
];
}
}
uasort($sets, function($sA, $sB) {
if ($sA[0]['major_version'] != $sB[0]['major_version'])
{
return $sA[0]['major_version'] < $sB[0]['major_version'] ? -1 : 1;
}
return $sA[0]['minor_version'] < $sB[0]['minor_version'] ? -1 : 1;
});
foreach($sets as $group => &$groupSet)
{
usort($groupSet, function($rA, $rB) {
if ($rA['major_version'] != $rB['major_version'])
{
return $rA['major_version'] < $rB['major_version'] ? -1 : 1;
}
if ($rA['minor_version'] != $rB['minor_version'])
{
return $rA['minor_version'] < $rB['minor_version'] ? -1 : 1;
}
return $rA['patch_version'] < $rB['patch_version'] ? -1 : 1;
});
}
return $sets;
}
}

View file

@ -1,13 +1,48 @@
<?php Response::setMetaDescription('roadmap.description') ?>
<?php Response::addJsAsset('/js/roadmap.js') ?>
<?php NavActions::setNavUri('/learn') ?>
<?php echo View::render('nav/_header', ['isDark' => false]) ?>
<?php js_start() ?>
lbry.roadmap('#project-roadmap');
<?php js_end() ?>
<main>
<div class="content content-light spacer2">
<h1>{{roadmap.title}}</h1>
<div class="help spacer2">
Recent, ongoing and upcoming changes to LBRY.
<div class="hero hero-quote hero-img hero-img-short spacer1" title="Here Be Dragons" style="background-image: url(/img/here-be-dragons.jpg)">
<div class="hero-content-wrapper">
<div class="hero-content text-center">
<h1 class="cover-title">{{roadmap.title}}</h1>
<h2 class="cover-subtitle">Past successes and future plans for the journey into the land of dragons.</h2>
</div>
</div>
</div>
<div style="max-width: 800px; margin: 0 auto">
<div class="roadmap-container" id="project-roadmap">
<div class="text-center"><a href="javascript:;" class="link-primary show-all-releases">Show Earlier Releases</a></div>
<?php foreach($items as $group => $groupItems): ?>
<h2 class="roadmap-group-title" <?php echo in_array($group, $closedGroups) ? 'style="display: none"' : '' ?>">
<span class="roadmap-group-title-label"><?php echo $group ?></span>
</h2>
<div class="roadmap-group <?php echo in_array($group, $closedGroups) ? 'roadmap-group-closed' : '' ?>">
<?php foreach($groupItems as $item): ?>
<div class="roadmap-item roadmap-item-closed">
<a href="javascript:;" class="roadmap-item-header">
<h3 class="roadmap-item-title"><?php echo $item['name'] ?></h3>
</a>
<div class="roadmap-item-date">
<?php echo $item['date'] ?>
</div>
<div class="roadmap-item-content">
<?php echo $item['body'] ?>
</div>
</div>
<?php endforeach ?>
</div>
<?php endforeach ?>
</div>
</div>
</main>
<?php /*
<div class="content content-light spacer2">
<section class="spacer2">
<h2>Recent Changes</h2>
<table class="content full-table" id="changeset-table">
@ -45,35 +80,34 @@
});
<?php js_end() ?>
</section>
<?php foreach($tasks as $category => $categoryTasks): ?>
<section class="spacer2">
<h2><?php echo ucfirst($category) ?> Changes</h2>
<table class="content full-table">
<thead>
<th>Item</th>
<th>Date</th>
<th>Component</th>
<th>Owner</th>
</thead>
<?php foreach($categoryTasks as $task): ?>
<tr>
<td><?php echo $task['name'] ?></td>
<td style="width: 15%"><?php echo $task['due_on'] ?></td>
<td style="width: 20%">
<?php if ($task['url']): ?>
<a href="<?php echo $task['url'] ?>" class="link-primary"><?php echo $task['project'] ?></a>
<?php else: ?>
<?php echo $task['project'] ?>
<?php endif ?>
</td>
<td style="width: 20%">
<?php echo $task['assignee'] ?: '<em>unassigned</em>' ?>
</td>
</tr>
<?php endforeach ?>
</table>
</section>
<?php endforeach ?>
<section class="spacer2">
<h2>Upcoming Changes</h2>
<table class="content full-table">
<thead>
<th>Item</th>
<th>Date</th>
<th>Component</th>
<th>Owner</th>
</thead>
<?php foreach($items as $task): ?>
<tr>
<td><?php echo $task['name'] ?></td>
<td style="width: 15%"><?php echo $task['due_on'] ?></td>
<td style="width: 20%">
<?php if ($task['url']): ?>
<a href="<?php echo $task['url'] ?>" class="link-primary"><?php echo $task['project'] ?></a>
<?php else: ?>
<?php echo $task['project'] ?>
<?php endif ?>
</td>
<td style="width: 20%">
<?php echo $task['assignee'] ?: '<em>unassigned</em>' ?>
</td>
</tr>
<?php endforeach ?>
</table>
</section>
</div>
</main>
<?php echo View::render('nav/_footer') ?>
<?php echo View::render('nav/_footer') ?>
*/ ?>

View file

@ -10,28 +10,6 @@
<h1 class="cover-title">{{global.tagline}}</h1>
<h2 class="cover-subtitle" style="max-width: 600px; margin-left: auto; margin-right: auto">{{global.sentence}}</h2>
</div>
<?php /*
<?php $labels = [
__('making history'),
__('empowering artists'),
__('spreading knowledge'),
__('sharing sustainably'),
__('protecting speech'),
__('building tomorrow'),
__('eliminating middlemen'),
__('furthering education'),
] ?>
<?php shuffle($labels) ?>
<div class="sale-call ">
<span class="sale-call-verb"><?php echo __('Join') ?></span>
<span class="sale-call-total-people"><?php echo number_format($totalPeople) ?></span>
<span class="sale-call-prep">others in</span>
<span class="sale-ctas label-cycle" data-cycle-interval="5000">
<span class="sale-cta"><?php echo implode('</span><span class="sale-cta">', $labels) ?></span>
</span>
</div>
*/ ?>
<div class="control-group spacer2 text-center">
<div class="control-item">
<a href="/get" class="btn-primary">{{global.get}}</a>

BIN
web/img/here-be-dragons.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 414 KiB

View file

@ -19,8 +19,7 @@ jQuery.fn.extend({
});
$(document).ready(function() {
var body = $('body'),
labelCycles = body.find('.label-cycle'); //should use better pattern but we have so little JS right now
var body = $('body');
body.on('click', 'a', onAnchorClick);
@ -32,22 +31,6 @@ $(document).ready(function() {
window.fbAsyncInit = function()
{
window.FB.Event.subscribe('edge.create', onFacebookLike);
};
//$(window).scroll(onBodyScroll);
if (labelCycles.length)
{
setInterval(refreshLabelCycles,5000);
labelCycles.each(function() {
var labelCycle = $(this),
maxHeight = Math.max.apply(Math, labelCycles.find('> *').map(function(){ return $(this).height(); }).get());
if (maxHeight)
{
labelCycle.height(maxHeight);
}
labelCycle.addClass('label-cycle-init');
});
}
function onAnchorClick()
@ -80,24 +63,6 @@ $(document).ready(function() {
}
}
function onBodyScroll()
{
var header = $('.header');
if (header.hasClass('header-scroll'))
{
if (window.scrollY <= 1)
{
header.removeClass('header-light');
header.addClass('header-dark');
}
else
{
header.removeClass('header-dark');
header.addClass('header-light');
}
}
}
function resizeVideo(iframe)
{
var maxWidth = Math.min(iframe.offsetParent().width(), iframe.data('maxWidth')),
@ -149,17 +114,4 @@ $(document).ready(function() {
resizeVideo($(this));
})
});
function refreshLabelCycles()
{
labelCycles.each(function() {
var labelCycle = $(this),
activeLabel = labelCycle.find(':first-child');
activeLabel.fadeOut(function() {
labelCycle.append(activeLabel);
labelCycle.find(':first-child').fadeIn();
});
});
}
});

14
web/js/roadmap.js Normal file
View file

@ -0,0 +1,14 @@
lbry.roadmap = function(selector)
{
var roadmap = $(selector);
roadmap.on('click', '.show-all-releases', function() {
roadmap.find('.roadmap-group-title').show();
$(this).remove();
});
roadmap.on('click', '.roadmap-group-title', function() {
$(this).next('.roadmap-group').toggleClass('roadmap-group-closed').toggleClass('roadmap-group-open');
});
roadmap.on('click', '.roadmap-item-header', function() {
$(this).closest('.roadmap-item').toggleClass('roadmap-item-open').toggleClass('roadmap-item-closed');
});
}

View file

@ -42,10 +42,10 @@ h1, h2, h3, h4
margin-bottom: $spacing-vertical / 2;
margin-top: $spacing-vertical / 2;
}
h1 { font-size: 2.4em; }
h2 { font-size: 2.0em; }
h3 { font-size: 1.75em; }
h4 { font-size: 1.4em; }
h1 { font-size: $font-size-h1; }
h2 { font-size: $font-size-h2; }
h3 { font-size: $font-size-h3; }
h4 { font-size: $font-size-h4; }
nav
{
font-size: 1.1em;

View file

@ -7,6 +7,7 @@ $color-light-alt: hsl(hue($color-primary), 15, 85);
$color-text-dark: #000;
$color-money: #216C2A;
$color-meta-light: #505050;
$color-meta-lighter: #999999;
$color-info-bg: #3a779d;
$font-size: 16px;
@ -19,6 +20,11 @@ $max-post-content-width: 800px;
$font-header: 'Raleway', sans-serif;
$font-body: 'Raleway', sans-serif;
$font-size-h1: 2.4em;
$font-size-h2: 2.0em;
$font-size-h3: 1.75em;
$font-size-h4: 1.4em;
$content-side-padding: 15px;
@mixin anchor($color)

132
web/scss/_roadmap.scss Normal file
View file

@ -0,0 +1,132 @@
@import "global";
$color-roadmap-border: $color-primary;
$width-roadmap: 4px;
$width-roadmap-item: $width-roadmap - 1;
$width-date: 120px;
.roadmap-container
{
border-left: $width-roadmap solid $color-roadmap-border;
margin: $spacing-vertical 0 $spacing-vertical $width-date;
&:before, &:after
{
background: $color-roadmap-border;
content: "";
display: block;
position: relative;
height: $width-roadmap;
left: -2 * ($width-roadmap + 1);
width: $width-roadmap * 4;
}
&:before
{
top: -1 * ($width-roadmap);
}
&:after
{
bottom: -1 * ($width-roadmap);
}
}
.show-all-releases
{
display: inline-block;
margin: $spacing-vertical 0 0;
}
.roadmap-group-closed
{
display: none;
}
.roadmap-group-title
{
&:before
{
border-top: $width-roadmap solid $color-roadmap-border;
content: "";
display: inline-block;
height: $width-roadmap;
margin-right: 10px;
vertical-align: middle;
width: 8 * $width-roadmap;
}
cursor: pointer;
font-weight: 400;
margin: $spacing-vertical * 1.5 0 $spacing-vertical * 1.5 0;
padding: 0;
}
.roadmap-group-title-label
{
background: $color-roadmap-border;
@include border-radius(10px);
color: rgba(255, 255, 255, 0.85);
display: inline-block;
letter-spacing: 0;
padding: 0 10px;
text-align: center;
}
.roadmap-item
{
margin-bottom: $spacing-vertical;
position: relative;
}
.roadmap-item-date
{
display: inline-block;
position: absolute;
top: 0;
left: -1 * $width-date;
color: $color-meta-lighter;
line-height: 42px;
}
.roadmap-item-header
{
display: block;
padding-left: 20px;
position: relative;
&:before {
border-top: $width-roadmap-item solid $color-roadmap-border;
content: "";
position: absolute;
left: 0;
top: 0.5 * ($font-size-h3);
display: inline-block;
margin-top: $width-roadmap-item / 2;
height: $width-roadmap-item;
width: 10px;
}
}
.roadmap-item-title
{
display: inline-block;
margin: 0;
}
.roadmap-item-content
{
margin-left: 40px;
margin-bottom: $spacing-vertical * 1.5;
}
.roadmap-item-closed .roadmap-item-content
{
display: none;
}
.roadmap-item-open
{
.roadmap-item-title
{
font-size: $font-size-h3 * 1.2;
}
.roadmap-item-header
{
margin-bottom: $spacing-vertical / 2;
}
}

View file

@ -58,19 +58,6 @@
margin: 10px $spacing-vertical / 2 0 $spacing-vertical / 4;
}
}
.label-cycle
{
visibility: hidden;
display: block;
&.label-cycle-init
{
visibility: visible;
:not(:first-child)
{
display: none;
}
}
}
.sale-level
{

View file

@ -13,4 +13,5 @@
@import "sale";
@import "code";
@import "blog";
@import "bounty";
@import "bounty";
@import "roadmap";