Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions app/assets/stylesheets/application.scss
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,4 @@
@import 'components/modal';
@import 'components/autocomplete';
@import 'components/animated_badge';
@import 'components/command_list';
27 changes: 27 additions & 0 deletions app/assets/stylesheets/components/_command_list.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
.command-list {
.command-list-button {
min-width: 170px;
}

.modal-dialog {
--bs-modal-width: 600px;
--bs-modal-margin: 5rem;
--bs-modal-padding: 1.5rem;
}
Comment on lines +6 to +10
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we need so much custom css here? Also doesn't look good on mobile with so much margin.

I'd also have a look at the rest of this file's classes if we really need them. (some probably yes)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

also pretty sure there are provided classes for there, like modal-sm


.list-group-item {
color: $navbar-light-color;

&.active {
color: white;
}
}

.command-list-footer {
color: $navbar-light-color;
}

.command-list-icon {
border: 1px outset $navbar-light-color;
}
}
12 changes: 12 additions & 0 deletions app/components/previews/command_list_component_preview.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# frozen_string_literal: true

# frozen_literal_string: true

class CommandListComponentPreview < Lookbook::Preview
include LookbookHelper

# @source ../../../app/views/components/command_lists/_themes.html.erb
def themes
render 'components/command_lists/themes'
end
end
88 changes: 88 additions & 0 deletions app/javascript/controllers/command_list_controller.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
import { Controller } from "@hotwired/stimulus"

export default class CommandListController extends Controller {
static targets = ['list', 'metaKey', "searchField", "listGroup", "listItem"];

connect() {
this.modal = new bootstrap.Modal(this.listTarget, {})
this.children = Array.from(this.listGroupTargets[0].children);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not

Suggested change
this.children = Array.from(this.listGroupTargets[0].children);
this.children = Array.from(this.listGroupTarget.children);

If it's just one target as far as I see

if (this.listItemTargets.length > 0) {
this.switchActive(this.listItemTargets[0]);
}
this.metaKeyTarget.innerText = this.getMetaKey()

document.addEventListener("keydown", this.handleKeydown.bind(this));
}

disconnect() {
document.removeEventListener("keydown", this.handleKeydown.bind(this));
}

handleKeydown(event) {
console.log('handling keydown', event.metaKey, event.key);
if ((event.metaKey) && event.key === "k") {
this.openModal();
}
}

openModal() {
this.modal.show();
this.searchField().focus();
}

performCommand(event) {
event.preventDefault();
const searchParts = this.searchField().value.split(',').map(part => part.trim());
const command = this.activeCommand.dataset.command
.replace('_1_', searchParts[0])
.replace('_2_', searchParts[1])
.replace('_3_', searchParts[2]);
if (this.activeCommand.dataset.target == "_blank") {
window.open(command, '_blank');
} else {
Turbo.visit(command);
}
}

getMetaKey() {
const userAgent = window.navigator.userAgent.toLowerCase();
if (userAgent.includes(' mac ')) {
return '⌘';
} else {
return 'CTRL';
}
}

switchActive(element) {
if (this.activeCommand) {
this.activeCommand.classList.remove('active');
}
element.classList.add('active');
this.activeCommand = element;
this.searchField().placeholder = element.dataset.placeholder ?? '';
}

selectCommand(event) {
event.preventDefault();
this.switchActive(event.currentTarget);
this.searchField().focus()
}

previousItem() {
const previous = this.listItemTargets[this.listItemTargets.indexOf(this.activeCommand) - 1];
if (previous) {
this.switchActive(previous)
}
}

nextItem() {
const next = this.listItemTargets[this.listItemTargets.indexOf(this.activeCommand) + 1];
if (next) {
this.switchActive(next)
}
}

searchField() {
return this.searchFieldTarget
}
}
75 changes: 75 additions & 0 deletions app/views/components/command_lists/_themes.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
<div class="alert alert-warning">
Since this page is an iframe, you need to click here first, and then press the shortcut.
</div>
<%

command_list_actions = [
{ label: 'Search on Google',
command: 'https://www.google.com/search?q=_1_',
placeholder: 'Search text',
category: 'search',
target: '_blank' },
{ label: 'Go to component',
command: '/lookbook/inspect/_1_/themes',
placeholder: 'badge, button, avatar, etc.',
category: 'link' },
].group_by { |action| action[:category] }

%>
<div data-controller="command-list" class="command-list">
<a href="#" class="nav-item me-3 p-1 text-decoration-none">
<div class="input-group command-list-button ms-2" data-bs-toggle="modal" data-bs-target="#command-list-modal">
<span class="input-group-text" id="basic-addon1"><i class="fa fa-search"></i></span>
<div class="form-control form-control-sm text-center py-2">
<%= t('command_list.press') %>
<kbd class="command-list-icon" data-command-list-target="metaKey"></kbd> + <kbd class="command-list-icon">K</kbd>
</div>
</div>
</a>

<div id="command-list-modal" class="modal" tabindex="-1" data-command-list-target="list">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-body">
<div class="input-group mb-3">
<span class="input-group-text" id="basic-addon1"><i class="fa fa-search"></i></span>
<input autocomplete="off"
type="text"
class="form-control"
data-command-list-target="searchField"
data-action="keydown.up->command-list#previousItem
keydown.enter->command-list#performCommand
keydown.down->command-list#nextItem">
</div>

<div class="list-group" data-command-list-target="listGroup">
<% command_list_actions.each do |category, actions| %>
<div class="form-label mt-2 fw-medium"><%= t("command_list.#{category}") %></div>
<% actions.each do |action| %>
<a class="list-group-item" href="#"
data-action="click->command-list#selectCommand"
data-command-list-target="listItem"
data-placeholder="<%= action[:placeholder] || '' %>"
data-command="<%= action[:command] %>"
data-target="<%= action[:target] || '' %>">
<%= action[:label] %>
</a>
<% end %>
<% end %>
</div>

</div>
<div class="modal-footer d-flex command-list-footer">
<small class="pe-1"><kbd class="command-list-icon">⏎</kbd> <%= t('command_list.to_select') %></small>
<small class="pe-1">
<kbd class="command-list-icon">↑</kbd>
<kbd class="command-list-icon">↓</kbd>
<%= t('command_list.to_navigate') %>
</small>
<small class="pe-1"><kbd class="command-list-icon">ESC</kbd> <%= t('command_list.to_exit') %></small>
</div>
</div>
</div>
</div>

</div>
4 changes: 4 additions & 0 deletions test/system/pages_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,10 @@ def visit_preview_page(page) = visit("/lookbook/preview/#{page}")
assert_selector 'button', text: 'Confirm'
end

test 'visit the command_list page' do
visit_preview_page('command_list/themes')

assert_selector 'div.command-list'
test 'visit the modal default page' do
visit_preview_page('modal/default')

Expand Down