Skip to content

Commit

Permalink
add dropdown menu (#190)
Browse files Browse the repository at this point in the history
* add dropdown menu

* lint

* fix test
  • Loading branch information
adrienpoly authored Sep 9, 2024
1 parent d14a5e4 commit ac9c7e8
Show file tree
Hide file tree
Showing 17 changed files with 261 additions and 72 deletions.
1 change: 1 addition & 0 deletions app/assets/stylesheets/application.css
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
@import "tailwindcss/components";
@import "tailwindcss/utilities";

@import "components/dropdown.css";
@import "components/form.css";
@import "components/markdown.css";
@import "components/nav.css";
Expand Down
5 changes: 5 additions & 0 deletions app/assets/stylesheets/components/dropdown.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
@layer components {
details > summary {
list-style: none;
}
}
48 changes: 16 additions & 32 deletions app/assets/stylesheets/components/nav.css
Original file line number Diff line number Diff line change
@@ -1,40 +1,24 @@
@layer components {
nav {
@apply flex justify-between bg-primary px-4 text-white md:px-4 xl:px-8;
}

nav ul {
@apply m-0 flex list-none items-center gap-8 p-0;
}
.desktop-menu {
@apply hidden gap-6 md:flex;

nav li,
nav title {
@apply m-0 inline-block py-2;
div {
@apply invisible border-b-2 border-solid border-white;
}
&.active {
@apply relative;
& > div {
view-transition-name: navbar-active;
@apply visible absolute bottom-0 w-full;
li,
title {
@apply m-0 inline-block;
div {
@apply invisible border-b-2 border-solid border-white;
}
&.active {
@apply relative;
& > div {
view-transition-name: navbar-active;
@apply visible absolute bottom-0 w-full;
}
}
}
}

title {
@apply text-2xl font-bold text-white;
}

nav a,
nav [role="link"] {
@apply m-0 inline-block rounded-none p-0 hover:no-underline focus:no-underline active:no-underline;
text-decoration: none;
}

nav button,
nav [role="button"] {
@apply bg-white text-base-content hover:no-underline focus:no-underline active:no-underline;
text-decoration: none;
.mobile-menu {
@apply flex md:hidden;
}
}
34 changes: 34 additions & 0 deletions app/components/ui/divider_component.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# frozen_string_literal: true

class Ui::DividerComponent < ApplicationComponent
KIND_MAPPING = {
horizontal: "divider-horizontal",
vertical: "divider-vertical"
}

param :text, optional: true
option :kind, type: Dry::Types["coercible.symbol"].enum(*KIND_MAPPING.keys), optional: true

def call
content_tag(:div, class: classes, **attributes.except(:class)) do
concat content
end
end

private

def classes
[component_classes, attributes[:class]].join(" ")
end

def component_classes
class_names(
"divider",
KIND_MAPPING[kind]
)
end

def content
text.presence || super
end
end
17 changes: 17 additions & 0 deletions app/components/ui/dropdown_component.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<%= content_tag :details, class: classes, **attributes do %>
<summary class="after:hidden">
<% if toggle_open? && toggle_close? %>
<div class="swap" data-dropdown-target="swap">
<div class="swap-on"><%= toggle_open %></div>
<div class="swap-off"><%= toggle_close %></div>
</div>
<% else %>
<%= content %>
<% end %>
</summary>
<%= content_tag :ul, class: content_classes do %>
<% menu_items.each do |menu_item| %>
<%= menu_item %>
<% end %>
<% end %>
<% end %>
62 changes: 62 additions & 0 deletions app/components/ui/dropdown_component.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
# frozen_string_literal: true

class Ui::DropdownComponent < ApplicationComponent
renders_many :menu_items, types: {
divider: lambda { render Ui::DividerComponent.new(class: "my-2") },
link_to: lambda { |*args, **attributes|
content_tag :li do
attributes[:class] = class_names("!whitespace-nowrap", attributes[:class])
concat link_to(*args, **attributes)
end
},
button_to: lambda { |*args, **attributes|
content_tag :li do
attributes[:class] = class_names("!whitespace-nowrap", attributes[:class])
concat button_to(*args, **attributes)
end
}
}

renders_one :toggle_open
renders_one :toggle_close

OPEN_FROM_MAPPING = {
left: "dropdown-left",
right: "dropdown-right",
top: "dropdown-top",
bottom: "dropdown-bottom"
}

ALIGN_MAPPING = {
end: "dropdown-end"
}

option :open, type: Dry::Types["strict.bool"], default: proc { false }
option :hover, type: Dry::Types["strict.bool"], default: proc { false }
option :align, type: Dry::Types["coercible.symbol"].enum(*ALIGN_MAPPING.keys), optional: true
option :open_from, type: Dry::Types["coercible.symbol"].enum(*OPEN_FROM_MAPPING.keys), optional: true

private

def before_render
attributes[:data] = {controller: "dropdown"}
end

def classes
[component_classes, attributes.delete(:class)].compact_blank.join(" ")
end

def component_classes
class_names(
"dropdown",
OPEN_FROM_MAPPING[open_from],
ALIGN_MAPPING[align],
"dropdown-hover": hover,
"dropdown-open": open
)
end

def content_classes
class_names("dropdown-content menu menu-smp-2 mt-4 w-max z-[1] rounded-lg shadow-2xl bg-white text-neutral", attributes.delete(:content_classes))
end
end
2 changes: 1 addition & 1 deletion app/controllers/sessions_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ def create

def destroy
@session.destroy
redirect_to(sessions_path, notice: "That session has been logged out")
redirect_to(root_path, notice: "That session has been logged out")
end

private
Expand Down
4 changes: 3 additions & 1 deletion app/helpers/view_component_helper.rb
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
module ViewComponentHelper
UI_HELPERS = {
badge: "Ui::BadgeComponent",
button: "Ui::ButtonComponent"
button: "Ui::ButtonComponent",
divider: "Ui::DividerComponent",
dropdown: "Ui::DropdownComponent"
}.freeze

UI_HELPERS.each do |name, component|
Expand Down
36 changes: 36 additions & 0 deletions app/javascript/controllers/dropdown_controller.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { Controller } from '@hotwired/stimulus'
import { useClickOutside } from 'stimulus-use'

export default class extends Controller {
static targets = ['summary', 'swap']

connect () {
useClickOutside(this)
this.element.addEventListener('toggle', this.toggle.bind(this))
}

disconnect () {
this.#close()
this.element.removeEventListener('toggle', this.toggle)
}

clickOutside (event) {
this.#close(event)
}

// Private

toggle (event) {
if (this.element.open) {
this.element.setAttribute('aria-expanded', true)
this.swapTarget.classList.add('swap-active')
} else {
this.element.setAttribute('aria-expanded', false)
this.swapTarget.classList.remove('swap-active')
}
}

#close (event) {
this.element.open = false
}
}
22 changes: 18 additions & 4 deletions app/javascript/controllers/index.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,20 @@
import { application } from './application'
import { registerControllers } from 'stimulus-vite-helpers'
// This file is auto-generated by ./bin/rails stimulus:manifest:update
// Run that command whenever you add a new controller or create them with
// ./bin/rails generate stimulus controllerName

const controllers = import.meta.glob('./**/*_controller.js', { eager: true })
import { application } from "./application"

registerControllers(application, controllers)
import AutoSubmitController from "./auto_submit_controller"
application.register("auto-submit", AutoSubmitController)

import DropdownController from "./dropdown_controller"
application.register("dropdown", DropdownController)

import PageTransitionMissingController from "./page_transition_missing_controller"
application.register("page-transition-missing", PageTransitionMissingController)

import TransitionController from "./transition_controller"
application.register("transition", TransitionController)

import VideoPlayerController from "./video_player_controller"
application.register("video-player", VideoPlayerController)
2 changes: 1 addition & 1 deletion app/views/page/home.html.erb
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<main class="container">
<div class="w-full flex flex-col items-center pt-20 pb-12 text-center">
<h1 class="text-5xl font-bold tracking-tight text-slate-700">On a mission to index all Ruby conferences</h1>
<p class="relative mt-6 text-xl leading-8 text-slate-600 sm:max-w-md lg:max-w-none"> So far we have indexed <span class="font-semibold"><%= @talks_count %></span> of those from <span class="font-semibold"><%= @speakers_count %></span> speakers</p>
<p class="mt-6 text-xl leading-8 text-slate-600 sm:max-w-md lg:max-w-none"> So far we have indexed <span class="font-semibold"><%= @talks_count %></span> of those from <span class="font-semibold"><%= @speakers_count %></span> speakers</p>
<div class="mt-10 flex items-center gap-x-6 flex-wrap gap-y-4">
<%= ui_button(url: talks_path, outline: true) do %>
Explore talks <span aria-hidden="true"><%= heroicon :arrow_long_right %></span>
Expand Down
52 changes: 25 additions & 27 deletions app/views/shared/_navbar.html.erb
Original file line number Diff line number Diff line change
@@ -1,30 +1,28 @@
<nav class="navbar">
<div class="navbar bg-primary text-white relative z-50">
<div class="container flex justify-between items-center">
<ul>
<li>
<%= link_to root_path, class: "font-serif text-white flex gap-4 items-center" do %>
<title>Ruby Video</title>
<div class="">
<%= link_to "Ruby Video", root_path, class: "text-left text-3xl font-serif" %>
</div>
<div class="items-center gap-6 hidden md:flex">
<ul class="desktop-menu">
<%= render "shared/navbar/link", link_title: "Talks", path: talks_path %>
<%= render "shared/navbar/link", link_title: "Speakers", path: speakers_path %>
<%= render "shared/navbar/link", link_title: "Events", path: events_path %>
<% if Current.user&.admin? %>
<%= render "shared/navbar/link", link_title: "Events", path: events_path %>
<%= render "shared/navbar/link", link_title: "Watch List", path: watch_lists_path %>
<%= render "shared/navbar/link", link_title: "Suggestions", path: admin_suggestions_path %>
<% end %>
</li>
</ul>
<ul class="hidden md:flex">
<%= render "shared/navbar/link", link_title: "Talks", path: talks_path %>
<%= render "shared/navbar/link", link_title: "Speakers", path: speakers_path %>
<%= render "shared/navbar/link", link_title: "Events", path: events_path %>
<% if Current.user&.admin? %>
<%= render "shared/navbar/link", link_title: "Topics", path: topics_path %>
<%= render "shared/navbar/link", link_title: "Watch List", path: watch_lists_path %>
<%= render "shared/navbar/link", link_title: "Suggestions", path: admin_suggestions_path %>
<% end %>
<li>
<%= link_to "https://github.com/adrienpoly/rubyvideo", target: "_blank", alt: "github repository for the Ruby video project" do %>
<%= icon "github", size: :lg %>
<% end %>
</li>
<li>
<%= ui_button "Contribute", kind: :secondary, target: "_blank", url: "https://github.com/adrienpoly/rubyvideo/blob/main/docs/contributing.md" %>
</li>
</ul>
<li>
<%= link_to "https://github.com/adrienpoly/rubyvideo", target: "_blank", alt: "github repository for the Ruby video project" do %>
<%= icon "github", size: :lg %>
<% end %>
</li>
</ul>
<%= render "shared/user_dropdown" %>
</div>
<div class="mobile-menu">
<%= render "shared/user_mobile_dropdown" %>
</div>
</div>
</nav>
</div>
16 changes: 16 additions & 0 deletions app/views/shared/_user_dropdown.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
<%= ui_dropdown align: :end, content_classes: "mt-5 shadow-xl", id: "user_navbar_toggle" do |c| %>
<% c.with_toggle_open do %>
<%= heroicon "x-mark", size: :lg, class: "text-white" %>
<% end %>
<% c.with_toggle_close do %>
<%= heroicon "bars-3", size: :lg, class: "text-white" %>
<% end %>
<% c.with_menu_item_link_to "Use", uses_path %>
<% c.with_menu_item_link_to "Analytics", analytics_dashboards_path %>
<% if Current.user %>
<% c.with_menu_item_divider %>
<% c.with_menu_item_button_to t("sign_out"), Current.session, method: :delete, id: :sign_out %>
<% c.with_menu_item_link_to t("admin"), avo_path, display: Current.user&.admin? %>
<% end %>
<% end %>
23 changes: 23 additions & 0 deletions app/views/shared/_user_mobile_dropdown.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<%= ui_dropdown align: :end, content_classes: "mt-5 shadow-xl min-w-32", id: "user_navbar_toggle" do |c| %>
<% c.with_toggle_open do %>
<%= heroicon "x-mark", size: :lg, class: "text-white" %>
<% end %>
<% c.with_toggle_close do %>
<%= heroicon "bars-3", size: :lg, class: "text-white" %>
<% end %>
<% c.with_menu_item_link_to "Talks", talks_path %>
<% c.with_menu_item_link_to "Speakers", speakers_path %>
<% c.with_menu_item_link_to "Events", events_path %>
<% c.with_menu_item_divider %>
<% c.with_menu_item_link_to "Use", uses_path %>
<% c.with_menu_item_link_to "Analytics", analytics_dashboards_path %>
<% if Current.user %>
<% c.with_menu_item_divider %>
<% c.with_menu_item_button_to t("sign_out"), Current.session, method: :delete, id: :sign_out %>
<% c.with_menu_item_link_to t("admin"), avo_path, display: Current.user&.admin? %>
<% end %>
<% end %>
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
"packageManager": "yarn@1.22.19",
"devDependencies": {
"autoprefixer": "^10.4.14",
"daisyui": "^4.12.2",
"daisyui": "^4.12.10",
"postcss": "^8.4.38",
"postcss-import": "^16.1.0",
"postcss-nested": "^6.0.1",
Expand Down
5 changes: 1 addition & 4 deletions test/controllers/sessions_controller_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,6 @@ class SessionsControllerTest < ActionDispatch::IntegrationTest
sign_in_as @user

delete session_url(@user.sessions.last)
assert_redirected_to sessions_url

follow_redirect!
assert_redirected_to sign_in_url
assert_redirected_to root_url
end
end
Loading

0 comments on commit ac9c7e8

Please sign in to comment.