Skip to content

Commit

Permalink
Merge pull request #398 from rubytoolbox/co-compare
Browse files Browse the repository at this point in the history
Project display modes
  • Loading branch information
colszowka committed Jan 31, 2019
2 parents c3f299e + ace8b9b commit 0c24b1e
Show file tree
Hide file tree
Showing 34 changed files with 408 additions and 70 deletions.
4 changes: 4 additions & 0 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ gem "webpacker", require: false

gem "font-awesome-rails", "~> 4.7"

gem "addressable"

# Use ActiveStorage variant
# gem 'mini_magick', '~> 4.8'

Expand All @@ -47,6 +49,8 @@ gem "forgery"
gem "rack-canonical-host"
gem "rack-ssl-enforcer"

gem "browser"

gem "github_webhook"

gem "high_voltage"
Expand Down
3 changes: 3 additions & 0 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ GEM
bindex (0.5.0)
bootsnap (1.3.2)
msgpack (~> 1.0)
browser (2.5.3)
builder (3.2.3)
byebug (10.0.2)
capybara (3.13.2)
Expand Down Expand Up @@ -403,8 +404,10 @@ PLATFORMS
ruby

DEPENDENCIES
addressable
appsignal
bootsnap (>= 1.1.0)
browser
byebug
capybara (>= 2.15, < 4.0)
chromedriver-helper
Expand Down
7 changes: 7 additions & 0 deletions app/assets/javascripts/application.js
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,13 @@ document.addEventListener("turbolinks:load", function () {
});
});

document.querySelectorAll(".project-display-picker .button").forEach(function(button) {
button.classList.remove("is-loading");
button.addEventListener("click", function() {
button.classList.add("is-loading");
});
});

// See above, just for the custom project order dropdown
document.querySelectorAll(".project-order-dropdown .dropdown-content a").forEach(function(button) {
document.querySelectorAll(".project-order-dropdown button").forEach(function(dropdown) {
Expand Down
Empty file.
4 changes: 4 additions & 0 deletions app/assets/stylesheets/components/category_card.sass
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,10 @@
width: auto
display: inline-block
margin: 10px
&:first-child
margin-left: 0
&:last-child
margin-right: 0
.card-content
flex: 1
footer
Expand Down
26 changes: 26 additions & 0 deletions app/assets/stylesheets/components/project.sass
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
align-self: flex-end
margin-bottom: 0


.metric
@extend .column, .is-3-tablet, .is-6-mobile
// Align content to bottom
Expand All @@ -29,12 +30,37 @@
color: $black-ter

.heading
font-weight: bold
a
color: $grey-darker

&.compact
.metric
@extend .is-half, .is-one-third-desktop

.project-links
a.button
transition: color 100ms linear

&:hover
color: $primary


.project-compact-cards
@extend .columns, .is-multiline
.item
@extend .column, .is-full, .is-half-tablet
// When displayed next to each other, the wrapping box should
// stretch to equal height to its row sibling
display: flex
.project
width: 100%
// When displayed in a row next to each other the description
// row should stretch to the full height so metrics in equal-
// height siblings are bottom-aligned
display: flex
flex-direction: column
align-items: stretch
align-content: stretch
.stretch
flex: 1
42 changes: 42 additions & 0 deletions app/assets/stylesheets/components/project_comparison.sass
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
.project-comparison
overflow: auto
table
@extend .table, .is-fullwidth
.heading
@extend .is-size-7
white-space: nowrap

thead
th
@extend .has-text-right

tbody
td
@extend .has-text-right
font-weight: bold
white-space: nowrap

th.sticky
position: sticky
left: 0
// Black magic... https://stackoverflow.com/a/45042852
&:after
content: ""
position: absolute
right: 0
top: 0
bottom: 0
border-right: 1px solid #dbdbdb

// Bulma sets the striped background on the tr by default,
// which conflicts with the sticky project cells column on the left
tr
td, th
background: white
tr:nth-child(even)
td, th
background: #fafafa

tbody td, thead th
a
color: $dark
4 changes: 4 additions & 0 deletions app/assets/stylesheets/components/project_display_picker.sass
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
.project-display-picker
@extend .field, .has-addons
a
@extend .button
6 changes: 6 additions & 0 deletions app/controllers/categories_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,17 @@ def index

def show
@category = Category.find_for_show! params[:id], order: current_order
@display_mode = display_mode
redirect_to @category if @category.permalink != params[:id]
end

private

def display_mode
default = browser.device.mobile? ? "compact" : "full"
DisplayMode.new params[:display], default: default
end

def current_order
@current_order ||= Project::Order.new order: params[:order]
end
Expand Down
9 changes: 7 additions & 2 deletions app/controllers/searches_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,19 @@ def show
@query = params[:q].presence
return unless @query

@search = Search.new(@query, order: current_order, show_forks: show_forks?)
@projects = @search.projects.page(params[:page])
perform_search

redirect_to_search_with_forks_included if should_redirect_to_included_forks?
end

private

def perform_search
@search = Search.new @query, order: current_order, show_forks: show_forks?
@projects = @search.projects.page params[:page]
@display_mode = DisplayMode.new params[:display], default: "compact"
end

# If a user searches for some query but that search does not
# yield any project results we automatically redirect to the
# search with bugfix forks included. However this must only
Expand Down
30 changes: 27 additions & 3 deletions app/helpers/application_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -13,21 +13,21 @@ def metric_label(metric)
end

# This should be refactored...
# rubocop:disable Metrics/MethodLength, Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
# rubocop:disable Metrics/MethodLength, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
def pretty_metric_value(value)
if value.is_a?(Float) || value.is_a?(BigDecimal)
number_with_delimiter(value.floor) + "%"
elsif value.is_a? Integer
number_with_delimiter value
elsif value.is_a?(Date) || value.is_a?(Time)
content_tag "time", "#{time_ago_in_words(value)} ago", datetime: value.iso8601, title: l(value)
l value.to_date
elsif value.is_a? Array
value.to_sentence
else
value
end
end
# rubocop:enable Metrics/MethodLength, Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
# rubocop:enable Metrics/MethodLength, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity

#
# A little utility method for displaying project rankings like most downloaded gems
Expand Down Expand Up @@ -70,6 +70,30 @@ def markdown(text)
).render(text).html_safe # rubocop:disable Rails/OutputSafety
end

#
# Creates a link to the current page respecting all display mode & search query
# url arguments available in project listings (mode, order, search query, bugfix forks)
#
# This logic depends on too much implicit state by gathering bits & pieces
# from various assumed assigned variables, maybe extraction to some wrapping
# object might make sense...
#
def link_with_preserved_display_settings(**args)
addressable = Addressable::URI.new.tap do |uri|
uri.query_values = default_display_settings.merge(args).compact
end
"#{request.path}?#{addressable.query}"
end

def default_display_settings
{
order: try(:current_order)&.ordered_by,
q: @search&.query,
show_forks: @search&.show_forks,
display: @display_mode&.current,
}
end

# why
# https://rails.lighthouseapp.com/projects/8994/tickets/4334-to_param-and-resource_path-escapes-forward-slashes
# https://github.com/rails/rails/issues/16058
Expand Down
20 changes: 14 additions & 6 deletions app/helpers/component_helpers.rb
Original file line number Diff line number Diff line change
Expand Up @@ -14,16 +14,16 @@ def category_card(category, compact: false, inline: false)
render "components/category_card", locals
end

def render_project(project, show_categories: false)
render "components/project", project: project, show_categories: show_categories
def render_project(project, show_categories: false, compact: false)
render "components/project", project: project, show_categories: show_categories, compact: compact
end

def project_links(project)
render "components/project/links", project: project
def project_links(project, compact: false)
render "components/project/links", project: project, compact: compact
end

def project_metrics(project, expanded_view: false)
render "components/project/metrics", project: project, expanded_view: expanded_view
def project_metrics(project, expanded_view: false, compact: false)
render "components/project/metrics", project: project, expanded_view: expanded_view, compact: compact
end

def metrics_row(project, *metrics)
Expand Down Expand Up @@ -59,10 +59,18 @@ def project_order_dropdown(order)
render "components/project_order_dropdown", order: order
end

def project_comparison(projects)
render "components/project_comparison", projects: projects
end

def section_heading(title, description: nil, &block)
render "components/section_heading", title: title, description: description, &block
end

def project_display_picker(display_mode)
render "components/project_display_picker", display_mode: display_mode
end

def line_chart(data, scale: "logarithmic")
render "components/line_chart",
keys: data.keys,
Expand Down
22 changes: 22 additions & 0 deletions app/models/display_mode.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# frozen_string_literal: true

#
# A little utility class for picking a display mode based on given param,
# falling back to a customizible default
#
class DisplayMode
attr_accessor :requested, :default, :available
private :requested=, :default=, :available=

def initialize(requested = nil, default: "full")
self.requested = requested.to_s
self.default = default.to_s
self.available = %w[full compact table]
end

def current
return requested if available.include? requested

available.find { |mode| mode == default } || available.first
end
end
3 changes: 3 additions & 0 deletions app/views/application/_search_form.html.slim
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
= form_tag search_path, method: :get, class: "search-form" do
- if @display_mode
input type="hidden" name="display" value=@display_mode.current

.field.has-addons.has-addons-centered
.control.is-expanded
input.input placeholder="Search for libraries" type="text" name="q" value=@query
Expand Down
10 changes: 5 additions & 5 deletions app/views/categories/show.html.slim
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,10 @@
= bar_chart @category.projects.first(10).map {|p| [p.permalink, p.score]}.to_h, small: true

section.section: .container
.level.is-mobile
.level
.level-left
.level-right: .level-item= project_order_dropdown current_order
.level-right
.level-item= project_display_picker @display_mode
.level-item= project_order_dropdown current_order

.columns: .column.projects
- @category.projects.each do |project|
= render_project project
= render "projects/listing", projects: @category.projects, show_categories: false, display_mode: @display_mode
33 changes: 24 additions & 9 deletions app/views/components/_project.html.slim
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
= project.permalink

.level-right
- if local_assigns[:show_categories] and project.categories.any?
- if show_categories and project.categories.any? and not compact
.level-item.categories.is-hidden-touch
- project.categories.each do |category|
= category_card category, compact: true, inline: true
Expand All @@ -17,16 +17,31 @@
i.fa class=metric_icon(:score)
span= project.score

.columns: .column= project_health_tags project
- if show_categories and project.categories.any?
.columns class=(compact ? "" : "is-hidden-desktop")
.column
- project.categories.each do |category|
= category_card category, compact: true, inline: true

- if local_assigns[:show_categories] and project.categories.any?
.columns.is-hidden-desktop: .column
- project.categories.each do |category|
= category_card category, compact: true, inline: true
.columns: .column= project_health_tags project

.columns: .links.column
= project_links project
= project_links project, compact: compact

.columns.stretch: .description.column
- if local_assigns[:compact]
= truncate project.description, length: 300
- else
= project.description


- if local_assigns[:compact]
.metrics.compact= metrics_row project, :rubygem_downloads, :github_repo_stargazers_count, :rubygem_current_version, :rubygem_releases_count, :rubygem_first_release_on, :rubygem_latest_release_on

.columns: .description.column= project.description
.columns: .column.has-text-right
a.button.is-outlined href="/projects/#{project.permalink}"
span.icon: i.fa.fa-plus
span Show more project details

= project_metrics project
- else
= project_metrics project, compact: compact
Loading

0 comments on commit 0c24b1e

Please sign in to comment.