shadcn-ui 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.editorconfig +10 -0
- data/.prettierignore +43 -0
- data/.prettierrc.json +28 -0
- data/.rspec +1 -0
- data/.ruby-version +1 -0
- data/.vscode/settings.json +11 -0
- data/CHANGELOG.md +6 -0
- data/CODE_OF_CONDUCT.md +113 -0
- data/LICENSE.md +18 -0
- data/Procfile.dev +2 -0
- data/README.md +90 -0
- data/Rakefile +12 -0
- data/app/assets/builds/.keep +0 -0
- data/app/assets/config/manifest.js +5 -0
- data/app/assets/images/.keep +0 -0
- data/app/assets/stylesheets/application.scss +42 -0
- data/app/assets/stylesheets/application.tailwind.css +92 -0
- data/app/assets/stylesheets/lambda.light.scss +136 -0
- data/app/channels/application_cable/channel.rb +4 -0
- data/app/channels/application_cable/connection.rb +4 -0
- data/app/controllers/application_controller.rb +8 -0
- data/app/controllers/components_controller.rb +7 -0
- data/app/controllers/concerns/.keep +0 -0
- data/app/helpers/application_helper.rb +2 -0
- data/app/helpers/components/accordion_helper.rb +5 -0
- data/app/helpers/components/alert_dialog_helper.rb +6 -0
- data/app/helpers/components/alert_helper.rb +11 -0
- data/app/helpers/components/badge_helper.rb +20 -0
- data/app/helpers/components/button_helper.rb +20 -0
- data/app/helpers/components/card_helper.rb +5 -0
- data/app/helpers/components/checkbox_helper.rb +5 -0
- data/app/helpers/components/collapsible_helper.rb +6 -0
- data/app/helpers/components/dialog_helper.rb +14 -0
- data/app/helpers/components/dropdown_menu_helper.rb +23 -0
- data/app/helpers/components/hover_card_helper.rb +15 -0
- data/app/helpers/components/popover_helper.rb +15 -0
- data/app/helpers/components/seperator_helper.rb +6 -0
- data/app/helpers/components/textarea_helper.rb +13 -0
- data/app/helpers/components/toast_helper.rb +5 -0
- data/app/helpers/components/toggle_helper.rb +6 -0
- data/app/helpers/components/tooltip_helper.rb +15 -0
- data/app/helpers/components_helper.rb +7 -0
- data/app/helpers/examples_helper.rb +41 -0
- data/app/javascript/application.js +3 -0
- data/app/javascript/controllers/application.js +9 -0
- data/app/javascript/controllers/hello_controller.js +7 -0
- data/app/javascript/controllers/highlight_controller.js +9 -0
- data/app/javascript/controllers/index.js +11 -0
- data/app/javascript/controllers/tabs_controller.js +72 -0
- data/app/javascript/controllers/ui/accordion_controller.js +128 -0
- data/app/javascript/controllers/ui/checkbox_controller.js +17 -0
- data/app/javascript/controllers/ui/collapsible_controller.js +28 -0
- data/app/javascript/controllers/ui/dialog_controller.js +92 -0
- data/app/javascript/controllers/ui/dropdown_controller.js +25 -0
- data/app/javascript/controllers/ui/hover-card_controller.js +39 -0
- data/app/javascript/controllers/ui/popover_controller.js +27 -0
- data/app/javascript/controllers/ui/toast_controller.js +43 -0
- data/app/javascript/controllers/ui/toggle_controller.js +15 -0
- data/app/javascript/controllers/ui/tooltip_controller.js +3 -0
- data/app/javascript/controllers/ui/transition_controller.js +8 -0
- data/app/jobs/application_job.rb +7 -0
- data/app/mailers/application_mailer.rb +4 -0
- data/app/models/application_record.rb +3 -0
- data/app/models/concerns/.keep +0 -0
- data/app/views/application/index.html.erb +0 -0
- data/app/views/components/ui/_accordion.html.erb +40 -0
- data/app/views/components/ui/_alert.html.erb +55 -0
- data/app/views/components/ui/_alert_dialog.html.erb +20 -0
- data/app/views/components/ui/_badge.html.erb +1 -0
- data/app/views/components/ui/_button.html.erb +11 -0
- data/app/views/components/ui/_card.html.erb +13 -0
- data/app/views/components/ui/_checkbox.html.erb +37 -0
- data/app/views/components/ui/_collapsible.html.erb +38 -0
- data/app/views/components/ui/_dialog.html.erb +69 -0
- data/app/views/components/ui/_dropdown_menu.html.erb +9 -0
- data/app/views/components/ui/_hover_card.html.erb +18 -0
- data/app/views/components/ui/_popover.html.erb +19 -0
- data/app/views/components/ui/_separator.html.erb +4 -0
- data/app/views/components/ui/_textarea.html.erb +9 -0
- data/app/views/components/ui/_toast.html.erb +34 -0
- data/app/views/components/ui/_toggle.html.erb +3 -0
- data/app/views/components/ui/_tooltip.html.erb +18 -0
- data/app/views/components/ui/shared/_dialog_background.html.erb +7 -0
- data/app/views/components/ui/shared/_menu_item.html.erb +6 -0
- data/app/views/examples/authentication/index.html.erb +148 -0
- data/app/views/examples/components/accordion.html.erb +17 -0
- data/app/views/examples/components/alert-dialog.html.erb +24 -0
- data/app/views/examples/components/alert.html.erb +22 -0
- data/app/views/examples/components/badge.html.erb +30 -0
- data/app/views/examples/components/button.html.erb +33 -0
- data/app/views/examples/components/card.html.erb +156 -0
- data/app/views/examples/components/checkbox.html.erb +8 -0
- data/app/views/examples/components/collapsible.html.erb +24 -0
- data/app/views/examples/components/dialog/_usage.html.erb +28 -0
- data/app/views/examples/components/dialog/code/form.erb +48 -0
- data/app/views/examples/components/dialog/code/notifications.erb +83 -0
- data/app/views/examples/components/dialog/code/preview.erb +14 -0
- data/app/views/examples/components/dialog/code/usage.erb +8 -0
- data/app/views/examples/components/dialog.html.erb +148 -0
- data/app/views/examples/components/dropdown-menu.html.erb +26 -0
- data/app/views/examples/components/hover-card.html.erb +24 -0
- data/app/views/examples/components/popover.html.erb +34 -0
- data/app/views/examples/components/separator.html.erb +33 -0
- data/app/views/examples/components/textarea.html.erb +12 -0
- data/app/views/examples/components/toast.html.erb +15 -0
- data/app/views/examples/components/toggle.html.erb +12 -0
- data/app/views/examples/components/tooltip.html.erb +23 -0
- data/app/views/layouts/_sidebar.html.erb +270 -0
- data/app/views/layouts/application.html.erb +33 -0
- data/app/views/layouts/component.html.erb +35 -0
- data/app/views/layouts/documentation/_breadcrumb.html.erb +17 -0
- data/app/views/layouts/documentation/_component_header.html.erb +11 -0
- data/app/views/layouts/documentation/_examples.html.erb +80 -0
- data/app/views/layouts/documentation/_preview.html.erb +90 -0
- data/app/views/layouts/mailer.html.erb +13 -0
- data/app/views/layouts/mailer.text.erb +1 -0
- data/app/views/layouts/shared/_header.html.erb +164 -0
- data/config/application.rb +37 -0
- data/config/boot.rb +4 -0
- data/config/cable.yml +11 -0
- data/config/credentials.yml.enc +1 -0
- data/config/database.yml +25 -0
- data/config/environment.rb +5 -0
- data/config/environments/development.rb +70 -0
- data/config/environments/production.rb +93 -0
- data/config/environments/test.rb +60 -0
- data/config/importmap.rb +13 -0
- data/config/initializers/assets.rb +12 -0
- data/config/initializers/content_security_policy.rb +25 -0
- data/config/initializers/filter_parameter_logging.rb +8 -0
- data/config/initializers/inflections.rb +16 -0
- data/config/initializers/permissions_policy.rb +11 -0
- data/config/locales/en.yml +33 -0
- data/config/puma.rb +43 -0
- data/config/render.yml +9 -0
- data/config/routes.rb +7 -0
- data/config/storage.yml +34 -0
- data/config/tailwind.config.js +86 -0
- data/config.ru +6 -0
- data/db/seeds.rb +7 -0
- data/lib/assets/.keep +0 -0
- data/lib/generators/shadcn_ui_generator.rb +32 -0
- data/lib/shadcn-ui/shadcn-ui.rb +8 -0
- data/lib/shadcn-ui/version.rb +3 -0
- data/lib/tasks/.keep +0 -0
- data/log/.keep +0 -0
- data/package-lock.json +1014 -0
- data/package.json +8 -0
- data/public/404.html +67 -0
- data/public/422.html +67 -0
- data/public/500.html +66 -0
- data/public/android-chrome-192x192.png +0 -0
- data/public/android-chrome-512x512.png +0 -0
- data/public/apple-touch-icon-precomposed.png +0 -0
- data/public/apple-touch-icon.png +0 -0
- data/public/favicon-16x16.png +0 -0
- data/public/favicon-32x32.png +0 -0
- data/public/favicon.ico +0 -0
- data/public/og.jpg +0 -0
- data/public/robots.txt +1 -0
- data/sig/shadcn-ui.rbs +4 -0
- data/storage/.keep +0 -0
- data/tmp/.keep +0 -0
- data/tmp/pids/.keep +0 -0
- data/tmp/storage/.keep +0 -0
- data/vendor/.keep +0 -0
- data/vendor/javascript/.keep +0 -0
- metadata +214 -0
@@ -0,0 +1,6 @@
|
|
1
|
+
module Components::AlertDialogHelper
|
2
|
+
def render_alert_dialog(trigger:, label:, description:, continue:, **options)
|
3
|
+
cancel = options[:cancel] || render_button("Cancel", class: "mt-2 sm:mt-0", data: {action: "ui--dialog#close"})
|
4
|
+
render "components/ui/alert_dialog", trigger:, label:, description:, continue:, cancel:, **options
|
5
|
+
end
|
6
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
module Components::AlertHelper
|
2
|
+
def render_alert(title:, description:, variant: :default)
|
3
|
+
alert_classes = case variant.to_sym
|
4
|
+
when :default
|
5
|
+
"[&>svg]:text-foreground bg-background text-foreground"
|
6
|
+
when :error, :danger, :alert, :destructive
|
7
|
+
"border-destructive/50 text-destructive dark:border-destructive [&>svg]:text-destructive"
|
8
|
+
end
|
9
|
+
render "components/ui/alert", title: title, description: description, alert_classes: alert_classes, variant: variant
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module Components::BadgeHelper
|
2
|
+
def render_badge(label = "", data: "", text: "", variant: :default, **options)
|
3
|
+
badge_classes = " inline-flex items-center rounded-full px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 "
|
4
|
+
varianet_classes = case variant.to_sym
|
5
|
+
when :default
|
6
|
+
ComponentsHelper::PRIMARY_CLASSES
|
7
|
+
when :secondary
|
8
|
+
ComponentsHelper::SECONDARY_CLASSES
|
9
|
+
when :error, :danger, :alert, :destructive
|
10
|
+
ComponentsHelper::DESTRUCTIVE_CLASSES
|
11
|
+
when :outline
|
12
|
+
ComponentsHelper::OUTLINE_CLASSES
|
13
|
+
when :ghost
|
14
|
+
ComponentsHelper::GHOST_CLASSES
|
15
|
+
end
|
16
|
+
badge_classes << " #{varianet_classes}"
|
17
|
+
text = label if label.present?
|
18
|
+
render "components/ui/badge", text:, badge_classes:, data:, **options
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module Components::ButtonHelper
|
2
|
+
def render_button(label = "", data: "", text: "", variant: :default, as: :button, href: nil, **options)
|
3
|
+
button_classes = " inline-flex items-center justify-center rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 h-10 px-4 py-2 "
|
4
|
+
varianet_classes = case variant.to_sym
|
5
|
+
when :default
|
6
|
+
" bg-primary text-primary-foreground hover:bg-primary/90 "
|
7
|
+
when :secondary
|
8
|
+
" bg-secondary text-secondary-foreground hover:bg-secondary/80 "
|
9
|
+
when :error, :danger, :alert, :destructive
|
10
|
+
" bg-destructive text-destructive-foreground hover:bg-destructive/90 "
|
11
|
+
when :outline
|
12
|
+
" border border-input bg-background hover:bg-accent hover:text-accent-foreground"
|
13
|
+
when :ghost
|
14
|
+
" hover:bg-accent hover:text-accent-foreground "
|
15
|
+
end
|
16
|
+
button_classes << " #{varianet_classes} #{options[:class]}"
|
17
|
+
text = label if label.present?
|
18
|
+
render "components/ui/button", text:, button_classes:, as:, href:, data:, **options
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module Components::DialogHelper
|
2
|
+
def render_dialog(**options, &block)
|
3
|
+
content = capture(&block) if block
|
4
|
+
render "components/ui/dialog", content: content, **options
|
5
|
+
end
|
6
|
+
|
7
|
+
def dialog_trigger(&block)
|
8
|
+
content_for :dialog_trigger, capture(&block), flush: true
|
9
|
+
end
|
10
|
+
|
11
|
+
def dialog_content(&block)
|
12
|
+
content_for :dialog_content, capture(&block), flush: true
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module Components::DropdownMenuHelper
|
2
|
+
def render_dropdown_menu(**options, &block)
|
3
|
+
content = capture(&block) if block
|
4
|
+
render "components/ui/dropdown_menu", content: content, **options
|
5
|
+
end
|
6
|
+
|
7
|
+
def dropdown_menu_trigger(&block)
|
8
|
+
content_for :dropdown_menu_trigger, capture(&block), flush: true
|
9
|
+
end
|
10
|
+
|
11
|
+
def dropdown_menu_label(label = nil, &block)
|
12
|
+
content_for :dropdown_menu_label, (label || capture(&block)), flush: true
|
13
|
+
end
|
14
|
+
|
15
|
+
def dropdown_menu_content(&block)
|
16
|
+
content_for :dropdown_menu_content, capture(&block), flush: true
|
17
|
+
end
|
18
|
+
|
19
|
+
def dropdown_menu_item(label = nil, **options, &block)
|
20
|
+
content = (label || capture(&block))
|
21
|
+
render "components/ui/shared/menu_item", content: content
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module Components::HoverCardHelper
|
2
|
+
def render_hover_card(**options, &block)
|
3
|
+
content = capture(&block) if block
|
4
|
+
render "components/ui/hover_card", content: content, **options
|
5
|
+
end
|
6
|
+
|
7
|
+
def hover_card_trigger(&block)
|
8
|
+
content_for :hover_card_trigger, capture(&block), flush: true
|
9
|
+
end
|
10
|
+
|
11
|
+
def hover_card_content(options = {}, &block)
|
12
|
+
content_for :hover_card_content_class, options[:class], flush: true
|
13
|
+
content_for :hover_card_content, capture(&block), flush: true
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module Components::PopoverHelper
|
2
|
+
def render_popover(**options, &block)
|
3
|
+
content = capture(&block) if block
|
4
|
+
render "components/ui/popover", content: content, **options
|
5
|
+
end
|
6
|
+
|
7
|
+
def popover_trigger(&block)
|
8
|
+
content_for :popover_trigger, capture(&block), flush: true
|
9
|
+
end
|
10
|
+
|
11
|
+
def popover_content(options = {}, &block)
|
12
|
+
content_for :popover_content_class, options[:class], flush: true
|
13
|
+
content_for :popover_content, capture(&block), flush: true
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
module Components::TextareaHelper
|
2
|
+
def render_textarea(name:, label: false, id: nil, value: nil, **options)
|
3
|
+
options.reverse_merge!(rows: 3, required: false, disabled: false,
|
4
|
+
readonly: false, class: "", label: false, placeholder: "Type here...")
|
5
|
+
render partial: "components/ui/textarea", locals: {
|
6
|
+
label:,
|
7
|
+
name:,
|
8
|
+
value:,
|
9
|
+
id:,
|
10
|
+
options: options
|
11
|
+
}
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module Components::TooltipHelper
|
2
|
+
def render_tooltip(**options, &block)
|
3
|
+
content = capture(&block) if block
|
4
|
+
render "components/ui/tooltip", content: content, **options
|
5
|
+
end
|
6
|
+
|
7
|
+
def tooltip_trigger(&block)
|
8
|
+
content_for :tooltip_trigger, capture(&block), flush: true
|
9
|
+
end
|
10
|
+
|
11
|
+
def tooltip_content(options = {}, &block)
|
12
|
+
content_for :tooltip_content_class, options[:class], flush: true
|
13
|
+
content_for :tooltip_content, capture(&block), flush: true
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,7 @@
|
|
1
|
+
module ComponentsHelper
|
2
|
+
PRIMARY_CLASSES = " bg-primary text-primary-foreground hover:bg-primary/80 "
|
3
|
+
SECONDARY_CLASSES = " bg-secondary text-secondary-foreground hover:bg-secondary/80 "
|
4
|
+
OUTLINE_CLASSES = " border border-input bg-background hover:bg-accent hover:text-accent-foreground "
|
5
|
+
GHOST_CLASSES = " hover:bg-accent hover:text-accent-foreground "
|
6
|
+
DESTRUCTIVE_CLASSES = " bg-destructive text-destructive-foreground hover:bg-destructive/90 "
|
7
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module ExamplesHelper
|
2
|
+
def render_component_header(title:, description:)
|
3
|
+
render "layouts/documentation/component_header", title:, description:
|
4
|
+
end
|
5
|
+
|
6
|
+
def render_example
|
7
|
+
render "layouts/documentation/examples"
|
8
|
+
end
|
9
|
+
|
10
|
+
def render_preview
|
11
|
+
render "layouts/documentation/preview"
|
12
|
+
end
|
13
|
+
|
14
|
+
def render_usage(name)
|
15
|
+
render "examples/components/#{name}/usage"
|
16
|
+
end
|
17
|
+
|
18
|
+
def code_partial(name, language)
|
19
|
+
content_tag :pre, class: "code-sample py-4 px-4", data: {controller: "highlight"} do
|
20
|
+
content_tag :code, class: "language-#{language}" do
|
21
|
+
html_escape(File.read(Rails.root.join("app", "views", "examples", "components", "#{name}.erb")))
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def code_sample(content = "", language:, &block)
|
27
|
+
content_tag :pre, class: "code-sample px-4 my-2 pb-5", data: {controller: "highlight"} do
|
28
|
+
content_tag :code, class: "language-#{language}" do
|
29
|
+
content
|
30
|
+
yield if block
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def inline_code(content = nil, &block)
|
36
|
+
content_tag :code, class: "relative rounded bg-muted px-[0.3rem] py-[0.2rem] font-mono font-semibold" do
|
37
|
+
content || yield(block)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
alias_method :code, :inline_code
|
41
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
// Import and register all your controllers from the importmap under controllers/*
|
2
|
+
|
3
|
+
import { application } from "controllers/application"
|
4
|
+
|
5
|
+
// Eager load all controllers defined in the import map under controllers/**/*_controller
|
6
|
+
import { eagerLoadControllersFrom } from "@hotwired/stimulus-loading"
|
7
|
+
eagerLoadControllersFrom("controllers", application)
|
8
|
+
|
9
|
+
// Lazy load controllers as they appear in the DOM (remember not to preload controllers in import map!)
|
10
|
+
// import { lazyLoadControllersFrom } from "@hotwired/stimulus-loading"
|
11
|
+
// lazyLoadControllersFrom("controllers", application)
|
@@ -0,0 +1,72 @@
|
|
1
|
+
// https://github.com/excid3/tailwindcss-stimulus-components/blob/master/src/tabs.js
|
2
|
+
import { Controller } from "@hotwired/stimulus";
|
3
|
+
import "@kanety/stimulus-static-actions";
|
4
|
+
|
5
|
+
export default class extends Controller {
|
6
|
+
static targets = ["tab", "panel"];
|
7
|
+
static actions = [["tab", "click->change"]];
|
8
|
+
|
9
|
+
connect() {
|
10
|
+
this.activeTabClasses = (this.data.get("activeTab") || "active").split(" ");
|
11
|
+
this.inactiveTabClasses = (this.data.get("inactiveTab") || "inactive").split(" ");
|
12
|
+
if (this.anchor) this.index = this.tabTargets.findIndex((tab) => tab.id === this.anchor);
|
13
|
+
this.showTab();
|
14
|
+
}
|
15
|
+
|
16
|
+
change(event) {
|
17
|
+
// If target specifies an index, use that
|
18
|
+
if (event.currentTarget.dataset.index) {
|
19
|
+
this.index = event.currentTarget.dataset.index;
|
20
|
+
|
21
|
+
// If target specifies an id, use that
|
22
|
+
} else if (event.currentTarget.dataset.id) {
|
23
|
+
this.index = this.tabTargets.findIndex((tab) => tab.id == event.currentTarget.dataset.id);
|
24
|
+
|
25
|
+
// Otherwise, use the index of the current target
|
26
|
+
} else {
|
27
|
+
this.index = this.tabTargets.indexOf(event.currentTarget);
|
28
|
+
}
|
29
|
+
|
30
|
+
window.dispatchEvent(new CustomEvent("tsc:tab-change"));
|
31
|
+
}
|
32
|
+
|
33
|
+
showTab() {
|
34
|
+
this.tabTargets.forEach((tab, index) => {
|
35
|
+
const panel = this.panelTargets[index];
|
36
|
+
|
37
|
+
if (index === this.index) {
|
38
|
+
panel.classList.remove("hidden");
|
39
|
+
tab.classList.remove(...this.inactiveTabClasses);
|
40
|
+
tab.classList.add(...this.activeTabClasses);
|
41
|
+
tab.dataset.state = "active";
|
42
|
+
panel.dataset.state = "active";
|
43
|
+
|
44
|
+
// Update URL with the tab ID if it has one
|
45
|
+
// This will be automatically selected on page load
|
46
|
+
// - Breaks any other anchors
|
47
|
+
// if (tab.id) {
|
48
|
+
// location.hash = tab.id;
|
49
|
+
// }
|
50
|
+
} else {
|
51
|
+
panel.classList.add("hidden");
|
52
|
+
tab.classList.remove(...this.activeTabClasses);
|
53
|
+
tab.classList.add(...this.inactiveTabClasses);
|
54
|
+
tab.dataset.state = "inactive";
|
55
|
+
panel.dataset.state = "inactive";
|
56
|
+
}
|
57
|
+
});
|
58
|
+
}
|
59
|
+
|
60
|
+
get index() {
|
61
|
+
return parseInt(this.data.get("index") || 0);
|
62
|
+
}
|
63
|
+
|
64
|
+
set index(value) {
|
65
|
+
this.data.set("index", value >= 0 ? value : 0);
|
66
|
+
this.showTab();
|
67
|
+
}
|
68
|
+
|
69
|
+
get anchor() {
|
70
|
+
return document.URL.split("#").length > 1 ? document.URL.split("#")[1] : null;
|
71
|
+
}
|
72
|
+
}
|
@@ -0,0 +1,128 @@
|
|
1
|
+
// Inspired by https://github.com/kanety/stimulus-accordion
|
2
|
+
import { Controller } from "@hotwired/stimulus";
|
3
|
+
|
4
|
+
export default class extends Controller {
|
5
|
+
get togglers() {
|
6
|
+
return this.context.bindingObserver.bindings
|
7
|
+
.filter((binding) => binding.action.methodName == "toggle")
|
8
|
+
.map((binding) => binding.action.element);
|
9
|
+
}
|
10
|
+
|
11
|
+
get openedTogglers() {
|
12
|
+
return this.togglers.filter((toggler) => this.isOpened(toggler));
|
13
|
+
}
|
14
|
+
|
15
|
+
get contents() {
|
16
|
+
return this.scope.findAllElements("[data-accordion-id]");
|
17
|
+
}
|
18
|
+
|
19
|
+
connect() {
|
20
|
+
this.init();
|
21
|
+
}
|
22
|
+
|
23
|
+
init() {
|
24
|
+
this.togglers.forEach((toggler) => {
|
25
|
+
let content = this.findContent(toggler);
|
26
|
+
if (this.isOpened(toggler)) {
|
27
|
+
this.show(toggler, content, false);
|
28
|
+
} else {
|
29
|
+
this.hide(toggler, content, false);
|
30
|
+
}
|
31
|
+
});
|
32
|
+
}
|
33
|
+
|
34
|
+
toggle(e) {
|
35
|
+
this.togglers.forEach((toggler) => {
|
36
|
+
if (toggler.contains(e.target)) {
|
37
|
+
if (this.isOpened(toggler)) {
|
38
|
+
this.close(toggler);
|
39
|
+
} else {
|
40
|
+
this.open(toggler);
|
41
|
+
}
|
42
|
+
} else if (this.isOpened(toggler)) {
|
43
|
+
this.close(toggler);
|
44
|
+
}
|
45
|
+
});
|
46
|
+
|
47
|
+
e.preventDefault();
|
48
|
+
}
|
49
|
+
|
50
|
+
open(toggler) {
|
51
|
+
let content = this.findContent(toggler);
|
52
|
+
this.show(toggler, content);
|
53
|
+
this.dispatch("opened", { detail: { toggler: toggler, content: content } });
|
54
|
+
}
|
55
|
+
|
56
|
+
close(toggler) {
|
57
|
+
let content = this.findContent(toggler);
|
58
|
+
this.hide(toggler, content);
|
59
|
+
this.dispatch("closed", { detail: { toggler: toggler, content: content } });
|
60
|
+
}
|
61
|
+
|
62
|
+
show(toggler, content, transition = true) {
|
63
|
+
if (transition) {
|
64
|
+
content.style.height = "0px";
|
65
|
+
content.removeEventListener("transitionend", this.transitionEnd);
|
66
|
+
content.addEventListener("transitionend", this.transitionEnd);
|
67
|
+
setTimeout(() => {
|
68
|
+
content.style.height = content.scrollHeight + "px";
|
69
|
+
});
|
70
|
+
}
|
71
|
+
|
72
|
+
this.toggleClass(toggler, content, true);
|
73
|
+
this.toggleText(toggler, true);
|
74
|
+
}
|
75
|
+
|
76
|
+
hide(toggler, content, transition = true) {
|
77
|
+
if (transition) {
|
78
|
+
content.style.height = content.scrollHeight + "px";
|
79
|
+
content.removeEventListener("transitionend", this.transitionEnd);
|
80
|
+
content.addEventListener("transitionend", this.transitionEnd);
|
81
|
+
setTimeout(() => {
|
82
|
+
content.style.height = "0px";
|
83
|
+
});
|
84
|
+
}
|
85
|
+
|
86
|
+
this.toggleClass(toggler, content, false);
|
87
|
+
this.toggleText(toggler, false);
|
88
|
+
}
|
89
|
+
|
90
|
+
transitionEnd(e) {
|
91
|
+
e.target.style.height = "";
|
92
|
+
}
|
93
|
+
|
94
|
+
toggleClass(toggler, content, opened) {
|
95
|
+
if (opened) {
|
96
|
+
toggler.classList.add("st-accordion__icon--opened");
|
97
|
+
content.classList.add("st-accordion__content--visible");
|
98
|
+
toggler.dataset.state = "open";
|
99
|
+
} else {
|
100
|
+
toggler.classList.remove("st-accordion__icon--opened");
|
101
|
+
content.classList.remove("st-accordion__content--visible");
|
102
|
+
toggler.dataset.state = "closed";
|
103
|
+
}
|
104
|
+
}
|
105
|
+
|
106
|
+
toggleText(toggler, opened) {
|
107
|
+
let text;
|
108
|
+
if (opened) {
|
109
|
+
text = toggler.getAttribute("data-accordion-opened-text-param");
|
110
|
+
} else {
|
111
|
+
text = toggler.getAttribute("data-accordion-closed-text-param");
|
112
|
+
}
|
113
|
+
if (text) toggler.innerHTML = text;
|
114
|
+
}
|
115
|
+
|
116
|
+
isOpened(toggler) {
|
117
|
+
return toggler.matches(".st-accordion__icon--opened");
|
118
|
+
}
|
119
|
+
|
120
|
+
findContent(toggler) {
|
121
|
+
let id = this.getID(toggler);
|
122
|
+
return this.scope.findElement(`[data-accordion-id="${id}"]`);
|
123
|
+
}
|
124
|
+
|
125
|
+
getID(toggler) {
|
126
|
+
return toggler.getAttribute("href").replace(/^#/, "");
|
127
|
+
}
|
128
|
+
}
|
@@ -0,0 +1,17 @@
|
|
1
|
+
import { Controller } from "@hotwired/stimulus";
|
2
|
+
export default class extends Controller {
|
3
|
+
connect() {
|
4
|
+
this.button = this.element.querySelector("button");
|
5
|
+
this.checkmark = this.button.querySelector("span");
|
6
|
+
}
|
7
|
+
|
8
|
+
toggle() {
|
9
|
+
if (this.checkmark.classList.contains("hidden")) {
|
10
|
+
this.checkmark.classList.remove("hidden");
|
11
|
+
this.button.dataset.state = "checked";
|
12
|
+
} else {
|
13
|
+
this.checkmark.classList.add("hidden");
|
14
|
+
this.button.dataset.state = "unchecked";
|
15
|
+
}
|
16
|
+
}
|
17
|
+
}
|
@@ -0,0 +1,28 @@
|
|
1
|
+
import { Controller } from "@hotwired/stimulus";
|
2
|
+
|
3
|
+
export default class extends Controller {
|
4
|
+
static targets = ["item"];
|
5
|
+
static classes = ["hidden"];
|
6
|
+
|
7
|
+
connect() {
|
8
|
+
this.class = this.hasHiddenClass ? this.hiddenClass : "hidden";
|
9
|
+
}
|
10
|
+
|
11
|
+
toggle() {
|
12
|
+
this.itemTargets.forEach((item) => {
|
13
|
+
item.classList.toggle(this.class);
|
14
|
+
});
|
15
|
+
}
|
16
|
+
|
17
|
+
show() {
|
18
|
+
this.itemTargets.forEach((item) => {
|
19
|
+
item.classList.remove(this.class);
|
20
|
+
});
|
21
|
+
}
|
22
|
+
|
23
|
+
hide() {
|
24
|
+
this.itemTargets.forEach((item) => {
|
25
|
+
item.classList.add(this.class);
|
26
|
+
});
|
27
|
+
}
|
28
|
+
}
|
@@ -0,0 +1,92 @@
|
|
1
|
+
// Inspired by https://github.com/kanety/stimulus-dialog
|
2
|
+
import { Controller } from "@hotwired/stimulus";
|
3
|
+
import "@kanety/stimulus-static-actions";
|
4
|
+
|
5
|
+
export default class extends Controller {
|
6
|
+
static targets = ["dialog", "modal", "focus", "drag", "backdrop", "closeButton"];
|
7
|
+
static actions = [
|
8
|
+
["element", "keydown@window->closeByKey"],
|
9
|
+
["modal", "click->closeByModal"],
|
10
|
+
["closeButton", "click->close"],
|
11
|
+
];
|
12
|
+
|
13
|
+
initialize() {}
|
14
|
+
connect() {}
|
15
|
+
open(e) {
|
16
|
+
this.openBy(e.target);
|
17
|
+
e.preventDefault();
|
18
|
+
}
|
19
|
+
|
20
|
+
close(e) {
|
21
|
+
this.closeBy(e.target);
|
22
|
+
e.preventDefault();
|
23
|
+
}
|
24
|
+
|
25
|
+
toggle(e) {
|
26
|
+
if (this.isVisible()) {
|
27
|
+
this.closeBy(e.target);
|
28
|
+
} else {
|
29
|
+
this.openBy(e.target);
|
30
|
+
}
|
31
|
+
e.preventDefault();
|
32
|
+
}
|
33
|
+
|
34
|
+
closeByKey(e) {
|
35
|
+
if (e.keyCode == 27) {
|
36
|
+
this.closeBy(e.target);
|
37
|
+
e.preventDefault();
|
38
|
+
}
|
39
|
+
}
|
40
|
+
|
41
|
+
closeByModal(e) {
|
42
|
+
if (!this.dialogTarget.contains(e.target)) {
|
43
|
+
this.closeBy(e.target);
|
44
|
+
}
|
45
|
+
}
|
46
|
+
|
47
|
+
isVisible() {
|
48
|
+
return this.dialogTarget.classList.contains("st-dialog--visible");
|
49
|
+
}
|
50
|
+
|
51
|
+
openBy(target) {
|
52
|
+
this.toggleClass(true);
|
53
|
+
|
54
|
+
if (this.hasFocusTarget) {
|
55
|
+
this.focusTarget.focus();
|
56
|
+
}
|
57
|
+
|
58
|
+
this.dispatch("opened", { detail: { target: target } });
|
59
|
+
}
|
60
|
+
|
61
|
+
closeBy(target) {
|
62
|
+
this.toggleClass(false);
|
63
|
+
|
64
|
+
this.dispatch("closed", { detail: { target: target } });
|
65
|
+
}
|
66
|
+
|
67
|
+
toggleClass(visible) {
|
68
|
+
if (visible) {
|
69
|
+
this.dialogTarget.classList.remove("hidden");
|
70
|
+
this.dialogTarget.dataset.state = "open";
|
71
|
+
if (this.hasBackdropTarget) {
|
72
|
+
this.backdropTarget.classList.remove("hidden");
|
73
|
+
this.backdropTarget.dataset.state = "open";
|
74
|
+
}
|
75
|
+
if (this.hasModalTarget) {
|
76
|
+
this.modalTarget.classList.remove("hidden");
|
77
|
+
this.modalTarget.dataset.state = "open";
|
78
|
+
}
|
79
|
+
} else {
|
80
|
+
this.dialogTarget.classList.add("hidden");
|
81
|
+
this.dialogTarget.dataset.state = "closed";
|
82
|
+
if (this.hasBackdropTarget) {
|
83
|
+
this.backdropTarget.classList.add("hidden");
|
84
|
+
this.backdropTarget.dataset.state = "closed";
|
85
|
+
}
|
86
|
+
if (this.hasModalTarget) {
|
87
|
+
this.modalTarget.classList.add("hidden");
|
88
|
+
this.modalTarget.dataset.state = "closed";
|
89
|
+
}
|
90
|
+
}
|
91
|
+
}
|
92
|
+
}
|