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
|
+
}
|