irelia 0.0.1 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (74) hide show
  1. checksums.yaml +4 -4
  2. data/Rakefile +2 -0
  3. data/app/assets/config/irelia_manifest.js +2 -0
  4. data/app/frontend/components/application_view_component.rb +5 -0
  5. data/app/frontend/components/application_view_component_preview.rb +5 -0
  6. data/app/frontend/components/navbar/button/component.html.erb +8 -0
  7. data/app/frontend/components/navbar/button/component.rb +13 -0
  8. data/app/frontend/components/navbar/button/preview.rb +12 -0
  9. data/app/frontend/components/navbar/container/component.html.erb +5 -0
  10. data/app/frontend/components/navbar/container/component.rb +8 -0
  11. data/app/frontend/components/navbar/container/preview.rb +12 -0
  12. data/app/frontend/components/navbar/dark_mode_switcher/component.html.erb +4 -0
  13. data/app/frontend/components/navbar/dark_mode_switcher/component.rb +8 -0
  14. data/app/frontend/components/navbar/dark_mode_switcher/preview.rb +12 -0
  15. data/app/frontend/components/navbar/menu_items/component.html.erb +3 -0
  16. data/app/frontend/components/navbar/menu_items/component.rb +8 -0
  17. data/app/frontend/components/navbar/menu_items/preview.rb +12 -0
  18. data/app/frontend/components/navbar/navlink/component.html.erb +8 -0
  19. data/app/frontend/components/navbar/navlink/component.rb +13 -0
  20. data/app/frontend/components/navbar/navlink/preview.rb +12 -0
  21. data/app/frontend/components/navbar/right_section/component.html.erb +3 -0
  22. data/app/frontend/components/navbar/right_section/component.rb +8 -0
  23. data/app/frontend/components/navbar/right_section/preview.rb +12 -0
  24. data/app/frontend/components/navbar/select_account/component.html.erb +36 -0
  25. data/app/frontend/components/navbar/select_account/component.rb +6 -0
  26. data/app/frontend/components/navbar/select_account/preview.rb +9 -0
  27. data/app/frontend/components/navbar/separator/component.html.erb +1 -0
  28. data/app/frontend/components/navbar/separator/component.rb +7 -0
  29. data/app/frontend/components/navbar/separator/preview.rb +12 -0
  30. data/app/frontend/components/page/breadcrumbs/component.html.erb +16 -0
  31. data/app/frontend/components/page/breadcrumbs/component.rb +6 -0
  32. data/app/frontend/components/page/breadcrumbs/preview.rb +9 -0
  33. data/app/frontend/components/page/container/component.html.erb +3 -0
  34. data/app/frontend/components/page/container/component.rb +4 -0
  35. data/app/frontend/components/page/container/preview.rb +9 -0
  36. data/app/frontend/components/page/header/component.html.erb +12 -0
  37. data/app/frontend/components/page/header/component.rb +6 -0
  38. data/app/frontend/components/page/header/preview.rb +9 -0
  39. data/app/helpers/navbar_helper.rb +35 -0
  40. data/app/helpers/page_helper.rb +15 -0
  41. data/app/javascript/controllers/dark_mode_switcher_controller.js +20 -0
  42. data/app/javascript/controllers/dropdown_controller.js +3 -0
  43. data/app/views/devise/registrations/new.html.erb +21 -0
  44. data/app/views/devise/sessions/new.html.erb +18 -0
  45. data/app/views/layouts/application.html.erb +11 -0
  46. data/app/views/layouts/devise.html.erb +23 -0
  47. data/app/views/layouts/mailer.html.erb +13 -0
  48. data/app/views/layouts/mailer.text.erb +1 -0
  49. data/app/views/layouts/teamable.html.erb +31 -0
  50. data/app/views/shared/_head.html.erb +26 -0
  51. data/app/views/shared/_navbar.html.erb +30 -0
  52. data/app/views/shared/_navbar_logo.html.erb +3 -0
  53. data/app/views/teamable/accounts/new.html.erb +10 -0
  54. data/app/views/teamable/setup/new.html.erb +8 -0
  55. data/app/views/teamable/shared/_form.html.erb +4 -0
  56. data/config/importmap.rb +7 -0
  57. data/config/initializers/devise.rb +313 -0
  58. data/config/initializers/simple_form.rb +148 -0
  59. data/config/initializers/view_component.rb +18 -0
  60. data/lib/generators/irelia/install_generator.rb +19 -0
  61. data/lib/generators/templates/irelia.rb +14 -0
  62. data/lib/generators/view_component/USAGE +15 -0
  63. data/lib/generators/view_component/templates/component.html.erb.tt +1 -0
  64. data/lib/generators/view_component/templates/component.rb.tt +8 -0
  65. data/lib/generators/view_component/templates/component_system_test.rb.tt +13 -0
  66. data/lib/generators/view_component/templates/component_test.rb.tt +19 -0
  67. data/lib/generators/view_component/templates/preview.rb.tt +9 -0
  68. data/lib/generators/view_component/view_component_generator.rb +53 -0
  69. data/lib/irelia/engine.rb +16 -0
  70. data/lib/irelia/version.rb +1 -1
  71. data/lib/irelia.rb +26 -3
  72. metadata +202 -13
  73. data/config/routes.rb +0 -2
  74. data/lib/tasks/irelia_tasks.rake +0 -4
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: fca4b000ecd80c6029d5fcb6490a6032e9d9a454bc2a55569c208d803da2cf24
4
- data.tar.gz: 36706bbd38af5a8f5735448eabdba2d38a1f791b65c46e9388d0c7e8ba968cc3
3
+ metadata.gz: faa3b8e64532f3d512880ee2c611566d88e27606125ea7068bc491f40573fa91
4
+ data.tar.gz: 5208c6e42837909a6858bff761b7f1add4ace0110f3010e190a57fabada5b6c7
5
5
  SHA512:
6
- metadata.gz: 31f718e64ba4b0f760c4a29bc2f38a73b7169052b8a728ddde5c152e73ecffc91572360b20b3d93e72524fa40d0f8f0bf26298e8e1193d823a7d90440775d5bb
7
- data.tar.gz: 1f694a67c08bc294f734d5b5e13988a21d44c09a3913c6dd68f7ac009b5b85d20a9730276df89f1b0af3ecd14303d591696975cc95cba074d5a186dcbb417127
6
+ metadata.gz: e9e3f2cf4e9e68599369078e72ce71d7f515dc3ba660d81dadffac22b74c59a9ca0e47e42aead93e8ad24e134e3d6fe7a39926e6082a6f9a5a7a694fca7fae5d
7
+ data.tar.gz: ff3d6cb4b9770cd64469073ad6b9d62578fdfb36c20d9ee60f0ba346f00254c8f1222d87417ffed9faf8812a82ff48dd5d4f62ad72ad7fe1c167bb626fa98c59
data/Rakefile CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "bundler/setup"
2
4
 
3
5
  APP_RAKEFILE = File.expand_path("test/dummy/Rakefile", __dir__)
@@ -0,0 +1,2 @@
1
+ //= link_tree ../../javascript .js
2
+ //= link_tree ../../assets/images .svg
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ class ApplicationViewComponent < ViewComponentContrib::Base
4
+ extend Dry::Initializer
5
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ class ApplicationViewComponentPreview < ViewComponentContrib::Preview::Base
4
+ self.abstract_class = true
5
+ end
@@ -0,0 +1,8 @@
1
+ <%= button_to target, class: "inline-flex items-center gap-x-1 py-3 px-4 text-sm leading-3 justify-center rounded transition bg-white hover:bg-neutral-50 dark:bg-dark-900 dark:hover:bg-dark-800 dark:text-neutral-200 whitespace-nowrap cursor-pointer #{custom_class}", method: method do %>
2
+ <% if icon.present? %>
3
+ <i class="<%= icon %> w-3 h-3"></i>
4
+ <% end %>
5
+ <% if text.present? %>
6
+ <span class="ml-1"><%= text %></span>
7
+ <% end %>
8
+ <% end %>
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Navbar
4
+ module Button
5
+ class Component < ApplicationViewComponent
6
+ option :target # required
7
+ option :method, default: proc { :get }
8
+ option :icon, optional: true # FontAwesome icon class
9
+ option :text, optional: true
10
+ option :custom_class, optional: true
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Navbar
4
+ module Button
5
+ class Preview < ApplicationViewComponentPreview
6
+ # You can specify the container class for the default template
7
+ # self.container_class = "w-1/2 border border-gray-300"
8
+
9
+ def default; end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,5 @@
1
+ <section class="flex sticky left-0 right-0 top-0 z-50 h-[60px] relative bg-white dark:bg-dark-900 gap-x-8 z-40 items-center border-b dark:border-b-dark-700">
2
+ <div class="container max-w-[1200px] mx-auto px-8 flex items-center h-[60px] gap-x-8">
3
+ <%= content %>
4
+ </div>
5
+ </section>
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Navbar
4
+ module Container
5
+ class Component < ApplicationViewComponent
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Navbar
4
+ module Container
5
+ class Preview < ApplicationViewComponentPreview
6
+ # You can specify the container class for the default template
7
+ # self.container_class = "w-1/2 border border-gray-300"
8
+
9
+ def default; end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,4 @@
1
+ <button data-controller="dark-mode-switcher" data-action="click->dark-mode-switcher#toggle" class="inline-flex items-center gap-x-1 py-3 px-4 text-sm leading-3 justify-center rounded transition bg-white hover:bg-neutral-50 dark:bg-dark-900 dark:hover:bg-dark-800 dark:text-neutral-200 whitespace-nowrap cursor-pointer">
2
+ <i class="fa fa-lightbulb hidden dark:inline"></i>
3
+ <i class="fa fa-moon inline dark:hidden"></i>
4
+ </button>
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Navbar
4
+ module DarkModeSwitcher
5
+ class Component < ApplicationViewComponent
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Navbar
4
+ module DarkModeSwitcher
5
+ class Preview < ApplicationViewComponentPreview
6
+ # You can specify the container class for the default template
7
+ # self.container_class = "w-1/2 border border-gray-300"
8
+
9
+ def default; end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,3 @@
1
+ <nav class="flex items-center gap-x-8">
2
+ <%= content %>
3
+ </nav>
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Navbar
4
+ module MenuItems
5
+ class Component < ApplicationViewComponent
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Navbar
4
+ module MenuItems
5
+ class Preview < ApplicationViewComponentPreview
6
+ # You can specify the container class for the default template
7
+ # self.container_class = "w-1/2 border border-gray-300"
8
+
9
+ def default; end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,8 @@
1
+ <%= link_to target, class: "flex items-center px-2 text-sm h-[60px] border-y-2 border-transparent #{active ? "font-bold text-primary-700" : "hover:text-black dark:hover:text-white" } #{custom_class}" do %>
2
+ <% if icon.present? %>
3
+ <i class="<%= icon %> w-4 h-4 <%= "mr-3" if text %>"></i>
4
+ <% end %>
5
+ <% if text.present? %>
6
+ <span><%= text %></span>
7
+ <% end %>
8
+ <% end %>
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Navbar
4
+ module Navlink
5
+ class Component < ApplicationViewComponent
6
+ option :target # required
7
+ option :active, optional: true, default: false
8
+ option :text, optional: true
9
+ option :custom_class, optional: true
10
+ option :icon, optional: true
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Navbar
4
+ module Navlink
5
+ class Preview < ApplicationViewComponentPreview
6
+ # You can specify the container class for the default template
7
+ # self.container_class = "w-1/2 border border-gray-300"
8
+
9
+ def default; end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,3 @@
1
+ <div class="ml-auto flex items-center gap-x-4">
2
+ <%= content %>
3
+ </div>
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Navbar
4
+ module RightSection
5
+ class Component < ApplicationViewComponent
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Navbar
4
+ module RightSection
5
+ class Preview < ApplicationViewComponentPreview
6
+ # You can specify the container class for the default template
7
+ # self.container_class = "w-1/2 border border-gray-300"
8
+
9
+ def default; end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,36 @@
1
+ <div data-controller="dropdown" class="relative block text-sm min-w-[20px]">
2
+ <button class="flex w-full items-center text-left gap-x-4 cursor-pointer" data-action="dropdown#toggle click@window->dropdown#hide">
3
+ <img class="w-9 h-9 rounded" src="https://picsum.photos/50">
4
+ <div class="flex flex-col pr-4 gap-y-0.5">
5
+ <strong class="text-primary-600"><%= current_account.name %></strong>
6
+ <% if current_account.personal_account? %>
7
+ <span class="flex text-neutral-500 dark:text-neutral-300 items-center gap-x-1 text-xs">
8
+ <i class="fas fa-user"></i>
9
+ Personal account
10
+ </span>
11
+ <% else %>
12
+ <span class="flex text-neutral-500 dark:text-neutral-300 items-center gap-x-1 text-xs">
13
+ <i class="fas fa-users"></i>
14
+ Team account
15
+ </span>
16
+ <% end %>
17
+ </div>
18
+ <i class="fa-solid fa-caret-down mr-2 ml-auto"></i>
19
+ </button>
20
+ <div
21
+ class="hidden w-full transition z-50 text-xs bg-white dark:bg-zinc-800 divide-y absolute mt-4 right-0 border dark:border-zinc-700 dark:divide-zinc-700 dark:text-neutral-200 border-t-0 rounded-b whitespace-nowrap"
22
+ data-dropdown-target="menu"
23
+ data-transition-enter-from="opacity-0 scale-95"
24
+ data-transition-enter-to="opacity-100 scale-100"
25
+ data-transition-leave-from="opacity-100 scale-100"
26
+ data-transition-leave-to="opacity-0 scale-95">
27
+
28
+ <% User.find(current_user.id).accounts.each do |account| %>
29
+ <%= button_to switch_account_path(account), class: 'flex w-full p-3 px-4 gap-x-4 items-center hover:bg-neutral-100 hover:text-neutral-900 transition', method: :patch do %>
30
+ <i class="fas w-4 text-center <%= account.personal_account? ? "fa-user" : "fa-users" %>"></i> <%= account.name %>
31
+ <% end %>
32
+ <% end %>
33
+
34
+ <%= link_to 'Create a new team account' , new_account_path, class: 'flex w-full p-3 px-4 gap-x-4 items-center hover:bg-neutral-100 hover:text-neutral-900 transition', method: :delete %>
35
+ </div>
36
+ </div>
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Navbar::SelectAccount::Component < ApplicationViewComponent
4
+ option :current_user, required: true
5
+ option :current_account, required: true
6
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Navbar::SelectAccount::Preview < ApplicationViewComponentPreview
4
+ # You can specify the container class for the default template
5
+ # self.container_class = "w-1/2 border border-gray-300"
6
+
7
+ def default
8
+ end
9
+ end
@@ -0,0 +1 @@
1
+ <div class="w-[1px] h-10 bg-neutral-100 dark:bg-dark-700"></div>
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Navbar
4
+ module Separator
5
+ class Component < ApplicationViewComponent; end
6
+ end
7
+ end
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Navbar
4
+ module Separator
5
+ class Preview < ApplicationViewComponentPreview
6
+ # You can specify the container class for the default template
7
+ # self.container_class = "w-1/2 border border-gray-300"
8
+
9
+ def default; end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,16 @@
1
+ <% if breadcrumbs.any? %>
2
+ <nav aria-label="breadcrumb" class="bg-white dark:bg-dark-900 border-b dark:border-b-dark-700 text-sm">
3
+ <div class="container max-w-[1200px] font-semibold mx-auto p-8 py-4">
4
+ <ol class="flex gap-x-4 text-neutral-500 dark:text-neutral-400">
5
+ <% breadcrumbs.each do |crumb| %>
6
+ <% if crumb.current? %>
7
+ <li class="font-bold text-black dark:text-white"><%= crumb.name %></li>
8
+ <% else %>
9
+ <li><%= link_to crumb.name, crumb.url, (crumb.current? ? {"aria-current" => "page"} : {}) %></li>
10
+ <li><span class="text-neutral-300 dark:text-neutral-600"><i class="fa-solid fa-caret-right"></i></span></li>
11
+ <% end %>
12
+ <% end %>
13
+ </ol>
14
+ </div>
15
+ </nav>
16
+ <% end %>
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Page::Breadcrumbs::Component < ApplicationViewComponent
4
+ # with_collection_parameter :breadcrumbs
5
+ option :breadcrumbs
6
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Page::Breadcrumbs::Preview < ApplicationViewComponentPreview
4
+ # You can specify the container class for the default template
5
+ # self.container_class = "w-1/2 border border-gray-300"
6
+
7
+ def default
8
+ end
9
+ end
@@ -0,0 +1,3 @@
1
+ <div class="container max-w-[1200px] mx-auto p-8">
2
+ <%= content %>
3
+ </div>
@@ -0,0 +1,4 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Page::Container::Component < ApplicationViewComponent
4
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Page::Container::Preview < ApplicationViewComponentPreview
4
+ # You can specify the container class for the default template
5
+ # self.container_class = "w-1/2 border border-gray-300"
6
+
7
+ def default
8
+ end
9
+ end
@@ -0,0 +1,12 @@
1
+ <header class="flex mb-8 border-b-2 dark:border-b-dark-700 pb-6">
2
+ <div class="flex flex-1 flex-col gap-y-1">
3
+ <h1 class="text-lg font-bold uppercase"><%= title %></h1>
4
+ <% if subtitle.present? %>
5
+ <p class="text-neutral-400"><%= subtitle %></p>
6
+ <% end %>
7
+ </div>
8
+
9
+ <div class="flex items-center justify-center gap-x-3">
10
+ <%= content %>
11
+ </div>
12
+ </header>
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Page::Header::Component < ApplicationViewComponent
4
+ option :title
5
+ option :subtitle, optional: true
6
+ end
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Page::Header::Preview < ApplicationViewComponentPreview
4
+ # You can specify the container class for the default template
5
+ # self.container_class = "w-1/2 border border-gray-300"
6
+
7
+ def default
8
+ end
9
+ end
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ module NavbarHelper
4
+ def navbar(&block)
5
+ render(Navbar::Container::Component.new, &block)
6
+ end
7
+
8
+ def navbar_items(&block)
9
+ render(Navbar::MenuItems::Component.new, &block)
10
+ end
11
+
12
+ def navbar_right(&block)
13
+ render(Navbar::RightSection::Component.new, &block)
14
+ end
15
+
16
+ def navigation_item(text, target, options = {})
17
+ active = options[:active] || request.path == target
18
+ icon = options[:icon] || nil
19
+
20
+ render(Navbar::Navlink::Component.new(target:, text:, active:, icon:))
21
+ end
22
+
23
+ def navbar_button(text, target, options = {})
24
+ active = options[:active] || request.path == target
25
+ icon = options[:icon] || nil
26
+ method = options[:method] || :get
27
+ custom_class = options[:class] || nil
28
+
29
+ render(Navbar::Button::Component.new(target:, text:, icon:, method:, custom_class:))
30
+ end
31
+
32
+ def navbar_separator
33
+ render(Navbar::Separator::Component.new)
34
+ end
35
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module PageHelper
4
+ def container(&block)
5
+ render(Page::Container::Component.new, &block)
6
+ end
7
+
8
+ def page_header(**arguments)
9
+ render(Page::Header::Component.new(**arguments))
10
+ end
11
+
12
+ def breadcrumbs
13
+ render(Page::Breadcrumbs::Component.new(breadcrumbs: breadcrumb_trail))
14
+ end
15
+ end
@@ -0,0 +1,20 @@
1
+ import { Controller } from "@hotwired/stimulus"
2
+
3
+ export default class extends Controller {
4
+ initialize() {
5
+ if (localStorage.theme === 'dark' || (!('theme' in localStorage) && window.matchMedia('(prefers-color-scheme: dark)').matches)) {
6
+ document.documentElement.classList.add('dark')
7
+ } else {
8
+ document.documentElement.classList.remove('dark')
9
+ }
10
+ }
11
+
12
+ toggle() {
13
+ if (localStorage.theme === 'dark') {
14
+ localStorage.theme = 'light'
15
+ } else {
16
+ localStorage.theme = 'dark'
17
+ }
18
+ this.initialize()
19
+ }
20
+ }
@@ -0,0 +1,3 @@
1
+ import Dropdown from 'stimulus-dropdown'
2
+
3
+ export default class extends Dropdown { }
@@ -0,0 +1,21 @@
1
+ <% title "Create a new account" %>
2
+ <% content_for :header do %>
3
+ <h1 class="font-bold font-headings text-neutral-600 dark:text-neutral-100 text-2xl">Create your <strong class="text-primary-600">Irelia</strong> account</h1>
4
+ <p class="text-neutral-400">Enter your email address and a secure password.</p>
5
+ <% end %>
6
+
7
+ <main class="flex flex-col gap-4 w-full max-w-2xl">
8
+ <%= simple_form_for(resource, as: resource_name, url: registration_path(resource_name)) do |f| %>
9
+ <%= f.input :email, placeholder: "Enter a valid email address", required: true, autofocus: true, input_html: { autocomplete: "email" }%>
10
+
11
+ <div class="flex justify-between items-start gap-x-4">
12
+ <%= f.input :password, placeholder: "Create a secure password", required: true, hint: ("#{@minimum_password_length} characters minimum" if @minimum_password_length), input_html: { autocomplete: "new-password" } %>
13
+ <%= f.input :password_confirmation, placeholder: "Confirm your password", required: true, input_html: { autocomplete: "new-password" } %>
14
+ </div>
15
+
16
+ <div class="mt-4 flex justify-between items-center">
17
+ <%= f.button :submit, "Create your account" %>
18
+ <p class="dark:text-neutral-200">Already have an account? <%= link_to "Sign in!", new_user_session_path, class: "font-bold transition text-primary-600" %>
19
+ </div>
20
+ <% end %>
21
+ </main>
@@ -0,0 +1,18 @@
1
+ <% title "Sign in to your account" %>
2
+ <% content_for :header do %>
3
+ <h1 class="font-bold font-headings text-neutral-600 dark:text-neutral-100 text-2xl">Sign in to <strong class="text-primary-600">Irelia</strong></h1>
4
+ <p class="text-neutral-400 dark:text-neutral-200">Sign in with your email address and password or select any of the other available options below.</p>
5
+ <% end %>
6
+
7
+ <main class="flex flex-col gap-4 w-full max-w-xl">
8
+ <%= simple_form_for(resource, as: resource_name, url: session_path(resource_name)) do |f| %>
9
+ <%= f.input :email, placeholder: "Enter your email", required: true, autofocus: true, input_html: { autocomplete: "email" } %>
10
+ <%= f.input :password, placeholder: "Enter your password", required: true, input_html: { autocomplete: "current-password" } %>
11
+ <%= f.input :remember_me, as: :boolean, wrapper: :inline_checkbox if devise_mapping.rememberable? %>
12
+
13
+ <div class="flex justify-between items-center">
14
+ <%= f.button :submit, "Sign in" %>
15
+ <p class="dark:text-neutral-200">Don't have an account? <%= link_to "Sign up!", new_user_registration_path, class: "font-bold text-primary-600 transition" %></p>
16
+ </div>
17
+ <% end %>
18
+ </main>
@@ -0,0 +1,11 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <%= render "shared/head" %>
5
+ </head>
6
+ <body class="antialiased bg-neutral-50 text-neutral-700 dark:bg-dark-800 dark:text-neutral-100">
7
+ <%= render "shared/navbar" %>
8
+ <%= breadcrumbs %>
9
+ <%= yield %>
10
+ </body>
11
+ </html>
@@ -0,0 +1,23 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <%= render "shared/head" %>
5
+ </head>
6
+ <body class="h-screen relative flex justify-center items-center antialiased bg-neutral-50 text-neutral-700 dark:bg-dark-800 dark:text-neutral-100">
7
+ <div class="fixed top-4 right-4">
8
+ <%= render(Navbar::DarkModeSwitcher::Component.new) %>
9
+ </div>
10
+
11
+ <% flash.each do |key, value| %>
12
+ <%= content_tag :div, value, class: "flash #{key} fixed top-0 left-0 right-0 bg-white py-2 px-4 inline-block text-center w-full shadow" %>
13
+ <% end %>
14
+
15
+ <section class="flex flex-col gap-8 items-center justify-center w-full">
16
+ <header class="flex flex-col items-center gap-y-2 text-center max-w-lg">
17
+ <%= yield :header %>
18
+ </header>
19
+
20
+ <%= yield %>
21
+ </section>
22
+ </body>
23
+ </html>
@@ -0,0 +1,13 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
5
+ <style>
6
+ /* Email styles need to be inline */
7
+ </style>
8
+ </head>
9
+
10
+ <body>
11
+ <%= yield %>
12
+ </body>
13
+ </html>
@@ -0,0 +1 @@
1
+ <%= yield %>
@@ -0,0 +1,31 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <%= render "shared/head" %>
5
+ </head>
6
+ <body class="h-screen relative bg-neutral-50 text-neutral-700 dark:bg-dark-800 dark:text-neutral-100">
7
+ <%= render "shared/navbar" %>
8
+
9
+ <% flash.each do |key, value| %>
10
+ <%= content_tag :div, value, class: "flash #{key} fixed top-0 left-0 right-0 bg-white py-2 px-4 inline-block text-center w-full shadow" %>
11
+ <% end %>
12
+
13
+ <div class="h-screen -top-[60px] relative flex justify-center items-center antialiased">
14
+ <section class="flex flex-1 flex-col">
15
+ <div class="flex-1 flex items-center justify-center px-8">
16
+ <section class="flex flex-col gap-8 items-center justify-center w-full max-w-xl">
17
+ <header class="flex flex-col items-center">
18
+ <div class="flex flex-col gap-y-2 text-center">
19
+ <%= yield :header %>
20
+ </div>
21
+ </header>
22
+
23
+ <main class="flex flex-col gap-4 w-full">
24
+ <%= yield %>
25
+ </main>
26
+ </section>
27
+ </div>
28
+ </section>
29
+ </div>
30
+ </body>
31
+ </html>
@@ -0,0 +1,26 @@
1
+ <%= display_meta_tags site: Irelia.config.application_name, reverse: true, separator: "—" %>
2
+ <meta name="viewport" content="width=device-width,initial-scale=1">
3
+
4
+ <script>
5
+ if (localStorage.theme === 'dark' || (!('theme' in localStorage) && window.matchMedia('(prefers-color-scheme: dark)').matches)) {
6
+ document.documentElement.classList.add('dark')
7
+ }
8
+ </script>
9
+
10
+ <%= csrf_meta_tags %>
11
+ <%= csp_meta_tag %>
12
+ <%= stylesheet_link_tag "tailwind", "data-turbo-track": "reload" %>
13
+ <%= stylesheet_link_tag "application", "data-turbo-track": "reload" %>
14
+ <%= javascript_importmap_tags %>
15
+
16
+ <link rel="preconnect" href="https://fonts.googleapis.com" />
17
+ <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin="true" />
18
+ <link href="https://fonts.googleapis.com/css2?family=Poppins:wght@400;600;700&amp;display=swap" rel="stylesheet" />
19
+ <link href="https://fonts.googleapis.com/css2?family=Work+Sans:wght@300;400;500;600;700;800;900&amp;display=swap" rel="stylesheet" />
20
+ <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css" integrity="sha512-iecdLmaskl7CVkqkXNQ/ZH/XLlvWZOJyj7Yy7tcenmpD1ypASozpmT/E0iPtmFIB46ZmdtAc9eNBvH0H/ZpiBw==" crossorigin="anonymous" referrerpolicy="no-referrer" />
21
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/js/all.min.js" integrity="sha512-fD9DI5bZwQxOi7MhYWnnNPlvXdp/2Pj3XSTRrFs5FQa4mizyGLnJcN6tuvUS6LbmgN1ut+XGSABKvjN0H6Aoow==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
22
+
23
+ <style>
24
+ .valid .input-box { border: 1px green solid; }
25
+ .invalid .input-box { border: 1px red solid; }
26
+ </style>