Skip to content

Instantly share code, notes, and snippets.

@matoni109
Created January 28, 2022 20:31
Show Gist options
  • Save matoni109/355358c15a0d3a5aa1a7d0aedca6fe4e to your computer and use it in GitHub Desktop.
Save matoni109/355358c15a0d3a5aa1a7d0aedca6fe4e to your computer and use it in GitHub Desktop.
import { Controller } from 'stimulus';
export default class extends Controller {
static targets = ['menu', 'button'];
static values = { open: Boolean };
connect() {
this.toggleClass = this.data.get('class') || 'hidden';
this.visibleClass = this.data.get('visibleClass') || null;
this.invisibleClass = this.data.get('invisibleClass') || null;
this.activeClass = this.data.get('activeClass') || null;
this.enteringClass = this.data.get('enteringClass') || null;
this.leavingClass = this.data.get('leavingClass') || null;
if (this.hasButtonTarget) {
this.buttonTarget.addEventListener('keydown', this._onMenuButtonKeydown);
}
this.element.setAttribute('aria-haspopup', 'true');
}
disconnect() {
if (this.hasButtonTarget) {
this.buttonTarget.removeEventListener(
'keydown',
this._onMenuButtonKeydown
);
}
}
toggle() {
this.openValue = !this.openValue;
}
openValueChanged() {
if (this.openValue) {
this._show();
} else {
this._hide();
}
}
_show(cb) {
setTimeout(() => {
this.menuTarget.classList.remove(this.toggleClass);
this.element.setAttribute('aria-expanded', 'true');
this._enteringClassList[0].forEach(klass => {
this.menuTarget.classList.add(klass);
});
this._activeClassList[0].forEach(klass => {
this.activeTarget.classList.add(klass);
});
this._invisibleClassList[0].forEach(klass =>
this.menuTarget.classList.remove(klass)
);
this._visibleClassList[0].forEach(klass => {
this.menuTarget.classList.add(klass);
});
setTimeout(() => {
this._enteringClassList[0].forEach(klass =>
this.menuTarget.classList.remove(klass)
);
}, this.enterTimeout[0]);
if (typeof cb === 'function') cb();
});
}
_hide(cb) {
setTimeout(() => {
this.element.setAttribute('aria-expanded', 'false');
this._invisibleClassList[0].forEach(klass =>
this.menuTarget.classList.add(klass)
);
this._visibleClassList[0].forEach(klass =>
this.menuTarget.classList.remove(klass)
);
this._activeClassList[0].forEach(klass =>
this.activeTarget.classList.remove(klass)
);
this._leavingClassList[0].forEach(klass =>
this.menuTarget.classList.add(klass)
);
setTimeout(() => {
this._leavingClassList[0].forEach(klass =>
this.menuTarget.classList.remove(klass)
);
if (typeof cb === 'function') cb();
this.menuTarget.classList.add(this.toggleClass);
}, this.leaveTimeout[0]);
});
}
_onMenuButtonKeydown = event => {
switch (event.keyCode) {
case 13: // enter
case 32: // space
event.preventDefault();
this.toggle();
break;
default:
// do nothing
}
};
show() {
this.openValue = true;
}
hide(event) {
if (this.element.contains(event.target) === false && this.openValue) {
this.openValue = false;
}
}
get activeTarget() {
return this.data.has('activeTarget')
? document.querySelector(this.data.get('activeTarget'))
: this.element;
}
get _activeClassList() {
return !this.activeClass
? [[], []]
: this.activeClass.split(',').map(classList => classList.split(' '));
}
get _visibleClassList() {
return !this.visibleClass
? [[], []]
: this.visibleClass.split(',').map(classList => classList.split(' '));
}
get _invisibleClassList() {
return !this.invisibleClass
? [[], []]
: this.invisibleClass.split(',').map(classList => classList.split(' '));
}
get _enteringClassList() {
return !this.enteringClass
? [[], []]
: this.enteringClass.split(',').map(classList => classList.split(' '));
}
get _leavingClassList() {
return !this.leavingClass
? [[], []]
: this.leavingClass.split(',').map(classList => classList.split(' '));
}
get enterTimeout() {
const timeout = this.data.get('enterTimeout') || '0,0';
return timeout.split(',').map(t => parseInt(t));
}
get leaveTimeout() {
const timeout = this.data.get('leaveTimeout') || '0,0';
return timeout.split(',').map(t => parseInt(t));
}
}
module.exports = {
purge: {
content: [
'./app/components/*.html.erb',
'./app/views/wheelhouse/**/*.html.erb',
'./app/views/layouts/wheelhouse/*.html.erb',
'./app/webpack/controllers/*.js',
'./app/webpack/packs/*.js',
'./app/assets/javascript/**/*.js'
]
},
darkMode: false, // or 'media' or 'class'
mode: 'jit',
theme: {
extend: {}
},
variants: {
extend: {}
},
plugins: []
};
# Note: You must restart bin/webpack-dev-server for changes to take effect
default: &default
source_path: app/webpack
source_entry_path: packs
public_output_path: packs
public_root_path: public
cache_path: tmp/cache/webpacker
check_yarn_integrity: false
webpack_compile_output: false
# Additional paths webpack should lookup modules
# ['app/assets', 'engine/foo/app/assets']
resolved_paths: []
additional_paths: ['app/components']
# Reload manifest.json on all requests so we reload latest compiled packs
cache_manifest: false
# Extract and emit a css file
extract_css: true
static_assets_extensions:
- .jpg
- .jpeg
- .png
- .gif
- .tiff
- .ico
- .svg
- .eot
- .otf
- .ttf
- .woff
- .woff2
extensions:
- .jsx
- .js
- .mjs
- .sass
- .scss
- .css
- .module.sass
- .module.scss
- .module.css
- .png
- .svg
- .gif
- .jpeg
- .jpg
development:
<<: *default
compile: true
check_yarn_integrity: true
# Reference: https://webpack.js.org/configuration/dev-server/
dev_server:
https: false
host: localhost
port: 3035
public: localhost:3035
hmr: false
# Inline should be set to true if using HMR
inline: true
overlay: true
compress: true
disable_host_check: true
use_local_ip: false
quiet: false
headers:
'Access-Control-Allow-Origin': '*'
watch_options:
ignored: '**/node_modules/**'
test:
<<: *default
compile: true
# Compile test packs to a separate directory
public_output_path: packs-test
production:
<<: *default
# Production depends on precompilation of packs prior to booting for performance.
compile: false
# Extract and emit a css file
extract_css: true
# Cache manifest.json for performance
cache_manifest: true
<!DOCTYPE html>
<html class="h-full bg-gray-100">
<head>
<title>Wheelhouse</title>
<%= javascript_pack_tag 'wheelhouse' %>
<%= stylesheet_pack_tag 'wheelhouse' %>
<%# <script src="https://cdn.tailwindcss.com"></script> %>
</head>
<body class="h-full">
<!-- This example requires Tailwind CSS v2.0+ -->
<div class="min-h-full">
<nav class="bg-white shadow-sm">
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<div class="flex justify-between h-16">
<div class="flex">
<div class="flex-shrink-0 flex items-center">
Wheelhouse
</div>
</div>
<div class="hidden sm:ml-6 sm:flex sm:items-center">
<!-- Profile dropdown --->
<div class="inline-block text-sm px-4 py-2 leading-none rounded no-underline text-gray hover:text-gray-900 hover:bg-white mt-4 lg:mt-0">
<div class="relative" data-controller="dropdown" data-dropdown-invisible-class="opacity-0 scale-95"
data-dropdown-visible-class="opacity-100 scale-100"
data-dropdown-entering-class="ease-out duration-300"
data-dropdown-enter-timeout="300"
data-dropdown-leaving-class="ease-in duration-300"
data-dropdown-leave-timeout="300">
<div data-action="click->dropdown#toggle click@window->dropdown#hide" role="button" data-dropdown-target="button" tabindex="0" class="inline-block select-none bg-white rounded-full flex text-sm focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500" id="user-menu-button" aria-expanded="false" aria-haspopup="true" >
<span class="appearance-none flex items-center inline-block text-gray-700">
<%= image_tag "https://images.unsplash.com/photo-1472099645785-5658abf4ff4e?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=facearea&facepad=2&w=256&h=256&q=80", class: "rounded-full h-8 w-8 align-middle" %>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20" class="h-4 w-4"><path d="M9.293 12.95l.707.707L15.657 8l-1.414-1.414L10 10.828 5.757 6.586 4.343 8z"></path></svg>
</span>
</div>
<div data-dropdown-target="menu" class="absolute right-0 mt-2 hidden">
<div class="bg-white shadow rounded border overflow-hidden">
<%= link_to 'Profile', root_path, data: {action: "click->dropdown#toggle"}, class: 'no-underline block pl-8 py-3 text-gray-900 bg-white hover:bg-gray-300 whitespace-nowrap' %>
<%= link_to 'Password', root_path, data: {action: "click->dropdown#toggle"}, class: 'no-underline block px-8 py-3 text-gray-900 bg-white hover:bg-gray-300 whitespace-nowrap' %>
<%= link_to 'Accounts', root_path, data: {action: "click->dropdown#toggle"}, class: 'no-underline block px-8 py-3 text-gray-900 bg-white hover:bg-gray-300 whitespace-nowrap' %>
<%= link_to 'Billing', root_path, data: {action: "click->dropdown#toggle"} ,class: 'no-underline block px-8 py-3 text-gray-900 bg-white hover:bg-gray-300 whitespace-nowrap' %>
<%= link_to 'Sign Out', root_path, data: {action: "click->dropdown#toggle"}, method: :delete, class: 'no-underline block px-8 py-3 border-t text-gray-900 bg-white hover:bg-gray-300 whitespace-nowrap' %>
</div>
</div>
</div>
</div>
<!-- Profile dropdown End --->
</div>
</div>
</div>
</nav>
<div class="py-10">
<main>
<div class="max-w-7xl mx-auto sm:px-6 lg:px-8">
<div data-controller="hello">
</div>
<%= yield %>
</div>
</main>
</div>
</div>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment