Skip to content

Commit

Permalink
Hammy template implements new design on static pages controller
Browse files Browse the repository at this point in the history
  • Loading branch information
martinemde committed Oct 11, 2024
1 parent 8a6e211 commit eeb28f3
Show file tree
Hide file tree
Showing 41 changed files with 1,018 additions and 161 deletions.
1 change: 1 addition & 0 deletions app/assets/config/manifest.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
//= link application.css
//= link hammy.css
//= link_tree ../../../vendor/assets/images
//= link_tree ../builds
//= link_tree ../../javascript .js
Expand Down
7 changes: 4 additions & 3 deletions app/assets/stylesheets/application.tailwind.css
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
@config "../../../config/tailwind.config.js";
@tailwind base;
@tailwind components;
@tailwind utilities;

@layer base {
@font-face {
font-family: "Titillium Web";
font-style: normal;
font-weight: 400;
font-display: swap;
src: url(/fonts/Roboto.woff2) format('woff2');
}

}

@tailwind components;
@tailwind utilities;
11 changes: 11 additions & 0 deletions app/assets/stylesheets/hammy.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
/*
* This is a manifest file that'll automatically include all the stylesheets available in this directory
* and any sub-directories. You're free to add application-wide styles to this file and they'll appear at
* the top of the compiled file, but it's generally better to create a new file per style scope.
*= require_self
*/

/* Default browser style adds a max width that is hard to override with tailwind directly */
dialog:modal {
max-width: 100vw;
}
9 changes: 9 additions & 0 deletions app/controllers/application_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,15 @@ def self.http_basic_authenticate_with(**options)
super
end

def breadcrumbs
@breadcrumbs ||= []
end
helper_method :breadcrumbs

def add_breadcrumb(name, link = nil)
breadcrumbs << [name, link]
end

protected

def http_basic_authentication_options_valid?(**options)
Expand Down
2 changes: 2 additions & 0 deletions app/controllers/dashboards_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ class DashboardsController < ApplicationController
before_action :redirect_to_settings_strong_mfa_required, if: :mfa_required_weak_level_enabled?

def show
add_breadcrumb t("breadcrumbs.dashboard"), dashboard_path

respond_to do |format|
format.html do
@my_gems = current_user.rubygems.with_versions.by_name.preload(:most_recent_version)
Expand Down
3 changes: 3 additions & 0 deletions app/controllers/pages_controller.rb
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
class PagesController < ApplicationController
before_action :find_page

layout "hammy"

def show
add_breadcrumb t("pages.#{@page}.title")
render @page
end

Expand Down
14 changes: 9 additions & 5 deletions app/helpers/application_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ def flash_message(name, msg)
msg
end

def rubygem_search_field(home: false)
def rubygem_search_field(home: false, **kwargs)
data = {
autocomplete_target: "query",
action: %w[
Expand All @@ -89,17 +89,21 @@ def rubygem_search_field(home: false)
blur->autocomplete#hide
].join(" ")
}
data[:nav_target] = "search" unless home
aria = { autocomplete: "list" }

data.merge!(kwargs.delete(:data)) if kwargs[:data]
aria.merge!(kwargs.delete(:aria)) if kwargs[:aria]

search_field_tag(
:query,
params[:query],
placeholder: t("layouts.application.header.search_gem_html"),
autofocus: current_page?(root_url),
class: home ? "home__search" : "header__search",
class: kwargs[:class],
autocomplete: "off",
aria: { autocomplete: "list" },
data: data
aria:,
data:,
**kwargs
)
end
end
9 changes: 9 additions & 0 deletions app/helpers/prose_helper.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
module ProseHelper

def prose(&)
base = "prose prose-neutral dark:prose-invert prose-lg lg:prose-xl max-w-prose mx-auto"
styles = "prose-headings:font-semibold"
tag.div class: "#{base} #{styles}", &
end

end
9 changes: 7 additions & 2 deletions app/javascript/controllers/autocomplete_controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ export default class extends Controller {
disconnect() { clear() }

clear() {
this.suggestionsTarget.classList.add('hidden');
this.suggestionsTarget.innerHTML = ""
this.suggestionsTarget.removeAttribute('tabindex');
this.suggestionsTarget.removeAttribute('aria-activedescendant');
Expand All @@ -25,12 +26,14 @@ export default class extends Controller {
}

next() {
if (this.suggestLength === 0) return;
this.indexNumber++;
if (this.indexNumber >= this.suggestLength) this.indexNumber = 0;
this.focusItem(this.itemTargets[this.indexNumber]);
}

prev() {
if (this.suggestLength === 0) return;
this.indexNumber--;
if (this.indexNumber < 0) this.indexNumber = this.suggestLength - 1;
this.focusItem(this.itemTargets[this.indexNumber]);
Expand Down Expand Up @@ -78,6 +81,7 @@ export default class extends Controller {
items.forEach((item, idx) => this.appendItem(item, idx));
this.suggestionsTarget.setAttribute('tabindex', 0);
this.suggestionsTarget.setAttribute('role', 'listbox');
this.suggestionsTarget.classList.remove('hidden');

this.suggestLength = items.length;
this.indexNumber = -1;
Expand All @@ -92,8 +96,9 @@ export default class extends Controller {
}

focusItem(el, change = true) {
this.itemTargets.forEach(el => el.classList.remove(this.selectedClass))
el.classList.add(this.selectedClass);
if (!el) { return; }
this.itemTargets.forEach(el => el.classList.remove(...this.selectedClasses))
el.classList.add(...this.selectedClasses);
this.suggestionsTarget.setAttribute('aria-activedescendant', el.id);
if (change) {
this.queryTarget.value = el.textContent;
Expand Down
23 changes: 23 additions & 0 deletions app/javascript/controllers/dialog_controller.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import Dialog from '@stimulus-components/dialog'

export default class extends Dialog {
static targets = ["dialog", "button"]

connect() {
super.connect()
}

open() {
super.open()
if (this.hasButtonTarget) {
this.buttonTarget.ariaExpanded = true
}
}

close() {
if (this.hasButtonTarget) {
this.buttonTarget.ariaExpanded = false
}
super.close()
}
}
44 changes: 44 additions & 0 deletions app/javascript/controllers/reveal_controller.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import Reveal from '@stimulus-components/reveal'

export default class extends Reveal {
static targets = ["item", "toggle", "button"]
static classes = ["hidden", "toggle"]

connect() {
super.connect()
if (this.hasButtonTarget) {
this.buttonTarget.ariaExpanded = false
}
}
toggle() {
super.toggle()
if (this.hasButtonTarget) {
this.buttonTarget.ariaExpanded = this.buttonTarget.ariaExpanded !== "true"
}
if (this.hasToggleTarget && this.hasToggleClass) {
this.toggleClasses.forEach((className) => {
this.toggleTarget.classList.toggle(className)
})
}
}

show() {
super.show()
if (this.hasButtonTarget) {
this.buttonTarget.ariaExpanded = true
}
if (this.hasToggleTarget && this.hasToggleClass) {
this.toggleTarget.classList.add(...this.toggleClasses)
}
}

hide() {
super.hide()
if (this.hasToggleTarget) {
this.buttonTarget.ariaExpanded = false
}
if (this.hasToggleTarget && this.hasToggleClass) {
this.toggleTarget.classList.add(...this.toggleClasses)
}
}
}
19 changes: 19 additions & 0 deletions app/javascript/controllers/reveal_search_controller.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import Reveal from './reveal_controller'

export default class extends Reveal {
static targets = ["item", "toggle", "button", "input"]

// There's nothing here because this is just a copy of the reveal controller
// with a different name. This saves us from a name conflict in the header.
toggle() {
super.toggle()
if (!this.itemTarget.classList.contains("hidden")) {
this.inputTarget.focus() // Auto focus the input when revealed
}
}

open() {
super.open()
this.inputTarget.focus()
}
}
72 changes: 72 additions & 0 deletions app/views/components/button_component.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
# frozen_string_literal: true

class ButtonComponent < ApplicationComponent
include Phlex::Rails::Helpers::LinkTo
include Phlex::Rails::Helpers::ButtonTo

attr_reader :text, :href, :type, :options, :color_css, :size_css

def initialize(text=nil, href: nil, type: :button, color: :primary, outline: false, size: :large, **options)
@text = text
@href = href
@type = type
@options = options
@options[:name] ||= nil
@color_css = button_color(color, outline)
@size_css = button_size(size)
end

def view_template(&)
css = "text-nowrap font-semibold no-underline " \
"rounded inline-flex border-box " \
"justify-content-center items-center hover:shadow-md " \
"transition duration-200 ease-in-out focus:outline-none " \
"#{color_css} #{size_css} #{options.delete(:class)}"

if type == :link
link_to text, href, class: css, **options, &
elsif href
button_to text, href, class: css, **options, &
else
button(class: css, type:, **options, &)
end
end

private

def button_color(color, outline)
color = color.to_sym
color = :orange if color == :primary
color = :orange2 if color == :secondary
@color_css = outline ? OUTLINE_BUTTON_COLOR[color] : FILL_BUTTON_COLOR[color]
end

def button_size(size)
case size
when :small # 36px height
"px-4 py-3 h-9 min-h-9 text-b3"
else # :large, 44px height
"px-4 py-3 h-12 min-h-12 text-b2" \
end
end

FILL_BUTTON_COLOR = {
orange: "text-white bg-orange-500 dark:bg-orange-500 hover:bg-orange-600 dark:hover:bg-orange-700 active:bg-orange-600 dark:active:bg-orange-700",
orange2: "text-neutral-800 dark:text-white bg-orange-200 dark:bg-orange-800 hover:bg-orange-300 dark:hover:bg-orange-900 active:bg-orange-300 dark:active:bg-orange-900",
yellow: "text-neutral-800 dark:text-white bg-yellow-500 dark:bg-yellow-500 hover:bg-yellow-600 dark:hover:bg-yellow-900 active:bg-yellow-600 dark:active:bg-yellow-900",
blue: "text-white bg-blue-500 dark:bg-blue-500 hover:bg-blue-600 dark:hover:bg-blue-700 active:bg-blue-600 dark:active:bg-blue-700",
green: "text-white bg-green-500 dark:bg-green-500 hover:bg-green-600 dark:hover:bg-green-700 active:bg-green-600 dark:active:bg-green-700",
red: "text-white bg-red-500 dark:bg-red-500 hover:bg-red-600 dark:hover:bg-red-700 active:bg-red-600 dark:active:bg-red-700",
neutral: "text-white bg-neutral-700 dark:bg-neutral-700 hover:bg-neutral-600 dark:hover:bg-neutral-700 active:bg-neutral-600 dark:active:bg-neutral-700",
}.freeze

OUTLINE_BUTTON_COLOR = {
orange: "border-2 border-orange-500 text-orange-500 dark:border-orange-500 dark:text-orange-500 hover:border-orange-600 hover:text-orange-600 active:border-orange-600 active:text-orange-600 dark:hover:border-orange-700 dark:hover:text-orange-700 dark:active:border-orange-700 dark:active:text-orange-700",
orange2: "border-2 border-orange-200 text-orange-200 dark:border-orange-800 dark:text-orange-800 hover:border-orange-300 hover:text-orange-300 active:border-orange-300 active:text-orange-300 dark:hover:border-orange-900 dark:hover:text-orange-900 dark:active:border-orange-900 dark:active:text-orange-900",
yellow: "border-2 border-yellow-500 text-yellow-500 dark:border-yellow-500 dark:text-yellow-500 hover:border-yellow-600 hover:text-yellow-600 active:border-yellow-600 active:text-yellow-600 dark:hover:border-yellow-900 dark:hover:text-yellow-900 dark:active:border-yellow-900 dark:active:text-yellow-900",
blue: "border-2 border-blue-500 text-blue-500 dark:border-blue-500 dark:text-blue-500 hover:border-blue-600 hover:text-blue-600 active:border-blue-600 active:text-blue-600 dark:hover:border-blue-700 dark:hover:text-blue-700 dark:active:border-blue-700 dark:active:text-blue-700",
green: "border-2 border-green-500 text-green-500 dark:border-green-500 dark:text-green-500 hover:border-green-600 hover:text-green-600 active:border-green-600 active:text-green-600 dark:hover:border-green-700 dark:hover:text-green-700 dark:active:border-green-700 dark:active:text-green-700",
red: "border-2 border-red-500 text-red-500 dark:border-red-500 dark:text-red-500 hover:border-red-600 hover:text-red-600 active:border-red-600 active:text-red-600 dark:hover:border-red-700 dark:hover:text-red-700 dark:active:border-red-700 dark:active:text-red-700",
neutral: "border-2 border-neutral-700 text-neutral-700 dark:border-neutral-700 dark:text-neutral-700 hover:border-neutral-600 hover:text-neutral-600 active:border-neutral-600 active:text-neutral-600 dark:hover:border-neutral-700 dark:hover:text-neutral-700 dark:active:border-neutral-700 dark:active:text-neutral-700",
}.freeze
end
43 changes: 43 additions & 0 deletions app/views/components/card_component.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
# frozen_string_literal: true

class CardComponent < ApplicationComponent
def view_template(&)
color = "bg-white dark:bg-black border border-neutral-400 dark:border-neutral-800 rounded-md shadow text-neutral-900 dark:text-neutral-100"
box = "w-full px-4 py-6 md:p-10"
article(**classes(color, box), &)
end

def head(title, icon: nil, url: nil, count: nil)
div(class: "flex justify-between items-center mb-8") do
h3(class: "flex items-center space-x-2 text-lg") do
render_icon(icon) if icon
span(class: "font-semibold") { title }
span(class: "font-light text-neutral-600") { count } if count
end

a(href: url, class: "text-sm text-orange-500 hover:underline") { t("view_all") } if url
end
end

def with_list(items, &)
ul(class: "mx-6 my-8") do
items.each do |item|
li(class: "flex justify-between items-center py-3 px-4 rounded-md border border-white dark:border-neutral-850 hover:border-neutral-700") do
yield(item)
end
end
end
end

def with_content(&)
div(class: "space-y-4", &)
end

private

def render_icon(name, width: 20, height: 20)
svg(class: "fill-orange", width:, height:) do
"<use href=\"/images/icons.svg##{name}\"/>".html_safe
end
end
end
25 changes: 25 additions & 0 deletions app/views/layouts/_breadcrumbs.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<div class="clear-both w-full bg-neutral-050 dark:bg-neutral-950 px-8 py-1 text-neutral-800 dark:text-white">
<div class="max-w-screen-xl mx-auto flex items-center">
<nav class="flex justify-start items-center text-b2" aria-label="Breadcrumb">
<!-- Home breadcrumb -->
<%= link_to root_path, class: "inline-block p-1 -ml-1 hover:text-neutral-600 dark:hover:text-neutral-400", title: t("breadcrumbs.home"), aria: { label: t("breadcrumbs.home") } do %>
<svg class="fill-current" height="24" width="24" role="graphics-symbol">
<title><%= t('breadcrumbs.home') %></title>
<use href="/images/icons.svg#house-siding"/>
</svg>
<% end %>
<% breadcrumbs.each do |name, link| %>
<svg class="fill-neutral-600 dark:fill-neutral-700 h-6 w-6" height="24" width="24" role="graphics-symbol" aria-hidden="true">
<use href="/images/icons.svg#chevron-right"/>
</svg>
<% if link %>
<%= link_to name, link, class: "inline-block p-1 hover:text-neutral-600 dark:hover:text-neutral-400" %>
<% else %>
<!-- Current page -->
<span class="inline-block p-1 text-black dark:text-white font-semibold" aria-current="page"><%= name %></span>
<% end %>
<% end %>
</nav>
</div>
</div>
Loading

0 comments on commit eeb28f3

Please sign in to comment.