moduler 0.2.0 → 0.4.0

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.
Files changed (125) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/builds/moduler/tailwind.css +2103 -1
  3. data/app/assets/javascripts/moduler/application.js +1 -0
  4. data/app/assets/javascripts/moduler/controllers/flash_controller.js +19 -0
  5. data/app/assets/javascripts/moduler/controllers/wysiwyg_controller.js +126 -0
  6. data/app/assets/javascripts/moduler/vendor/marked.esm.js +77 -0
  7. data/app/assets/stylesheets/moduler/tailwind.css +3 -0
  8. data/app/components/moduler/administration/page_component.html.erb +7 -0
  9. data/app/components/moduler/administration/page_component.rb +6 -0
  10. data/app/components/moduler/badge_component.html.erb +8 -0
  11. data/app/components/moduler/badge_component.rb +10 -0
  12. data/app/components/moduler/button_component.html.erb +7 -0
  13. data/app/components/moduler/button_component.rb +19 -0
  14. data/app/components/moduler/button_link_component.html.erb +5 -0
  15. data/app/components/moduler/button_link_component.rb +15 -0
  16. data/app/components/moduler/filter_component.html.erb +12 -0
  17. data/app/components/moduler/filter_component.rb +15 -0
  18. data/app/components/moduler/form/base_error_component.html.erb +1 -0
  19. data/app/components/moduler/form/base_error_component.rb +9 -0
  20. data/app/components/moduler/form/email_component.html.erb +14 -0
  21. data/app/components/moduler/form/email_component.rb +11 -0
  22. data/app/components/moduler/form/password_component.html.erb +14 -0
  23. data/app/components/moduler/form/password_component.rb +11 -0
  24. data/app/components/moduler/form/section_component.html.erb +5 -0
  25. data/app/components/moduler/form/section_component.rb +14 -0
  26. data/app/components/moduler/form/select_component.html.erb +14 -0
  27. data/app/components/moduler/form/select_component.rb +12 -0
  28. data/app/components/moduler/form/submit_component.html.erb +3 -0
  29. data/app/components/moduler/form/submit_component.rb +10 -0
  30. data/app/components/moduler/form/text_component.html.erb +14 -0
  31. data/app/components/moduler/form/text_component.rb +11 -0
  32. data/app/components/moduler/form/textarea_component.html.erb +14 -0
  33. data/app/components/moduler/form/textarea_component.rb +11 -0
  34. data/app/components/moduler/form/wysiwyg_component.html.erb +30 -0
  35. data/app/components/moduler/form/wysiwyg_component.rb +62 -0
  36. data/app/components/moduler/list_component.html.erb +15 -0
  37. data/app/components/moduler/list_component.rb +18 -0
  38. data/app/components/moduler/list_item_component.html.erb +23 -0
  39. data/app/components/moduler/list_item_component.rb +14 -0
  40. data/app/components/moduler/page_header_component.html.erb +16 -0
  41. data/app/components/moduler/page_header_component.rb +12 -0
  42. data/app/components/moduler/sidebar_action_component.html.erb +5 -0
  43. data/app/components/moduler/sidebar_action_component.rb +15 -0
  44. data/app/controllers/concerns/moduler/authentication.rb +10 -2
  45. data/app/controllers/moduler/administration/application_controller.rb +7 -0
  46. data/app/controllers/moduler/administration/articles_controller.rb +57 -0
  47. data/app/controllers/moduler/administration/home_controller.rb +9 -0
  48. data/app/controllers/moduler/administration/sessions_controller.rb +34 -0
  49. data/app/controllers/moduler/administration/users_controller.rb +56 -0
  50. data/app/controllers/moduler/application_controller.rb +15 -0
  51. data/app/controllers/moduler/articles_controller.rb +15 -0
  52. data/app/controllers/moduler/profile/sessions/revocation_controller.rb +14 -0
  53. data/app/controllers/moduler/profile/sessions_controller.rb +21 -0
  54. data/app/controllers/moduler/profile_controller.rb +27 -0
  55. data/app/controllers/moduler/sessions_controller.rb +8 -1
  56. data/app/controllers/moduler/users_controller.rb +7 -0
  57. data/app/filters/application_filter.rb +41 -0
  58. data/app/filters/query_filter.rb +18 -0
  59. data/app/lib/moduler/form_builder.rb +2 -2
  60. data/app/models/moduler/article.rb +25 -0
  61. data/app/models/moduler/session.rb +12 -0
  62. data/app/models/moduler/user.rb +9 -0
  63. data/app/policies/moduler/administration/article_policy.rb +29 -0
  64. data/app/policies/moduler/administration/base_policy.rb +11 -0
  65. data/app/policies/moduler/administration/home_policy.rb +9 -0
  66. data/app/policies/moduler/administration/session_policy.rb +13 -0
  67. data/app/policies/moduler/administration/user_policy.rb +25 -0
  68. data/app/policies/moduler/application_policy.rb +38 -0
  69. data/app/views/kaminari/_gap.html.erb +1 -0
  70. data/app/views/kaminari/_next_page.html.erb +1 -0
  71. data/app/views/kaminari/_page.html.erb +3 -0
  72. data/app/views/kaminari/_paginator.html.erb +13 -0
  73. data/app/views/kaminari/_prev_page.html.erb +1 -0
  74. data/app/views/layouts/moduler/application.html.erb +5 -6
  75. data/app/views/layouts/moduler/articles.html.erb +18 -0
  76. data/app/views/moduler/administration/articles/_article.html.erb +13 -0
  77. data/app/views/moduler/administration/articles/_form.html.erb +18 -0
  78. data/app/views/moduler/administration/articles/edit.html.erb +1 -0
  79. data/app/views/moduler/administration/articles/index.html.erb +13 -0
  80. data/app/views/moduler/administration/articles/new.html.erb +1 -0
  81. data/app/views/moduler/administration/home/index.html.erb +6 -0
  82. data/app/views/moduler/administration/sessions/_session.html.erb +30 -0
  83. data/app/views/moduler/administration/sessions/index.html.erb +9 -0
  84. data/app/views/moduler/administration/users/_user.html.erb +13 -0
  85. data/app/views/moduler/administration/users/edit.html.erb +14 -0
  86. data/app/views/moduler/administration/users/index.html.erb +13 -0
  87. data/app/views/moduler/administration/users/new.html.erb +18 -0
  88. data/app/views/moduler/articles/_article.html.erb +16 -0
  89. data/app/views/moduler/articles/index.html.erb +15 -0
  90. data/app/views/moduler/articles/show.html.erb +21 -0
  91. data/app/views/moduler/common/_flash.html.erb +16 -0
  92. data/app/views/moduler/common/_header.html.erb +12 -3
  93. data/app/views/moduler/common/_sidebar.html.erb +7 -0
  94. data/app/views/moduler/common/administration/_sidebar.html.erb +12 -0
  95. data/app/views/moduler/common/profile/_sidebar.html.erb +6 -0
  96. data/app/views/moduler/home/index.html.erb +6 -0
  97. data/app/views/moduler/profile/edit.html.erb +28 -0
  98. data/app/views/moduler/profile/sessions/_session.html.erb +52 -0
  99. data/app/views/moduler/profile/sessions/index.html.erb +26 -0
  100. data/app/views/moduler/sessions/new.html.erb +4 -18
  101. data/app/views/moduler/users/new.html.erb +5 -32
  102. data/config/importmap.rb +3 -0
  103. data/config/locales/moduler/administration/articles/en.yml +37 -0
  104. data/config/locales/moduler/administration/sessions/en.yml +24 -0
  105. data/config/locales/moduler/administration/users/en.yml +43 -0
  106. data/config/locales/moduler/articles/en.yml +13 -0
  107. data/config/locales/moduler/common/en.yml +12 -0
  108. data/config/locales/moduler/components/en.yml +27 -0
  109. data/config/locales/moduler/en.yml +4 -0
  110. data/config/locales/moduler/profile/en.yml +26 -0
  111. data/config/locales/moduler/profile/sessions/en.yml +25 -0
  112. data/config/locales/moduler/sessions/en.yml +1 -0
  113. data/config/locales/moduler/users/en.yml +7 -1
  114. data/config/routes.rb +18 -1
  115. data/db/migrate/20261015171504_add_role_to_moduler_users.rb +5 -0
  116. data/db/migrate/20261020191709_enable_pg_trgm.rb +5 -0
  117. data/db/migrate/20261026203827_create_moduler_articles.rb +15 -0
  118. data/lib/moduler/engine.rb +2 -0
  119. data/lib/moduler/version.rb +1 -1
  120. data/lib/moduler.rb +7 -0
  121. data/lib/tasks/moduler_tasks.rake +2 -4
  122. metadata +202 -5
  123. data/app/assets/javascripts/moduler/controllers/hello_controller.js +0 -6
  124. data/app/controllers/moduler/hello_controller.rb +0 -5
  125. data/app/views/moduler/hello/index.html.erb +0 -5
@@ -0,0 +1,52 @@
1
+ <% current = session == Moduler::Current.session %>
2
+ <% mobile = session.user_agent.to_s.match?(/Mobile|Android|iPhone|iPad/) %>
3
+
4
+ <li id="<%= dom_id(session) %>" class="flex items-center justify-between gap-4 px-4 py-4 sm:px-5 <%= "bg-slate-50/60" unless session.active? %>">
5
+ <div class="flex min-w-0 items-start gap-4">
6
+ <div class="flex size-10 shrink-0 items-center justify-center rounded-full <%= session.active? ? "bg-slate-100 text-slate-600" : "bg-slate-100/60 text-slate-400" %>">
7
+ <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round" class="size-5" aria-hidden="true">
8
+ <% if mobile %>
9
+ <rect x="7" y="2.5" width="10" height="19" rx="2" />
10
+ <path d="M11 18.5h2" />
11
+ <% else %>
12
+ <rect x="3" y="4" width="18" height="12" rx="1.5" />
13
+ <path d="M8 20h8M12 16v4" />
14
+ <% end %>
15
+ </svg>
16
+ </div>
17
+
18
+ <div class="min-w-0">
19
+ <div class="flex flex-wrap items-center gap-2">
20
+ <p class="text-sm font-semibold <%= session.active? ? "text-gray-900" : "text-slate-500" %>">
21
+ <%= session.ip_address.presence || t(".unknown_ip") %>
22
+ </p>
23
+
24
+ <% if current %>
25
+ <span class="inline-flex items-center rounded-full bg-emerald-50 px-2 py-0.5 text-xs font-medium text-emerald-700 ring-1 ring-inset ring-emerald-600/20"><%= t(".status.current") %></span>
26
+ <% elsif session.active? %>
27
+ <span class="inline-flex items-center rounded-full bg-slate-50 px-2 py-0.5 text-xs font-medium text-slate-600 ring-1 ring-inset ring-slate-500/20"><%= t(".status.active") %></span>
28
+ <% else %>
29
+ <span class="inline-flex items-center rounded-full px-2 py-0.5 text-xs font-medium text-slate-400 ring-1 ring-inset ring-slate-200"><%= t(".status.signed_out") %></span>
30
+ <% end %>
31
+ </div>
32
+
33
+ <p class="mt-1 truncate text-xs text-slate-500" title="<%= session.user_agent %>">
34
+ <%= session.user_agent.presence || t(".unknown_device") %>
35
+ </p>
36
+
37
+ <p class="mt-1 text-xs text-slate-400">
38
+ <%= time_tag session.signed_in_at, t(".signed_in", time: time_ago_in_words(session.signed_in_at)), title: l(session.signed_in_at, format: :long) %>
39
+ <% if session.signed_out_at %>
40
+ <span aria-hidden="true">&middot;</span>
41
+ <%= time_tag session.signed_out_at, t(".signed_out", time: time_ago_in_words(session.signed_out_at)), title: l(session.signed_out_at, format: :long) %>
42
+ <% end %>
43
+ </p>
44
+ </div>
45
+ </div>
46
+
47
+ <% if session.active? %>
48
+ <%= button_to t(".action.destroy"), moduler.profile_session_path(session), method: :delete,
49
+ class: "cursor-pointer rounded-md bg-white px-2.5 py-1 text-sm font-medium text-slate-600 shadow-sm ring-1 ring-inset ring-slate-300 hover:bg-slate-50 hover:text-red-600",
50
+ form: { class: "shrink-0", data: { turbo_confirm: t(current ? ".confirmation.destroy_current" : ".confirmation.destroy") } } %>
51
+ <% end %>
52
+ </li>
@@ -0,0 +1,26 @@
1
+ <main class="mx-auto flex w-full flex-1 max-w-[120rem] flex-col gap-4 px-4 md:flex-row md:gap-8 md:pl-0 md:pr-6">
2
+ <%= render "moduler/common/profile/sidebar" %>
3
+
4
+ <div class="flex min-w-0 flex-1 flex-col pb-4 md:mt-8">
5
+ <div class="mb-6 flex flex-col gap-4 sm:flex-row sm:items-start sm:justify-between">
6
+ <div>
7
+ <h1 class="text-base font-semibold text-gray-900"><%= t(".title") %></h1>
8
+ <p class="mt-1 text-sm text-slate-500"><%= t(".description") %></p>
9
+ </div>
10
+
11
+ <%= button_to t(".action.revoke_all"), moduler.profile_sessions_revocation_path, method: :delete,
12
+ class: "cursor-pointer whitespace-nowrap rounded-md bg-white px-3 py-1.5 text-sm/6 font-semibold text-red-600 shadow-sm ring-1 ring-inset ring-slate-300 hover:bg-red-50 hover:ring-red-200 focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-red-600",
13
+ form: { class: "shrink-0", data: { turbo_confirm: t(".confirmation.revoke") } } %>
14
+ </div>
15
+
16
+ <div class="flex-1">
17
+ <ul id="sessions" role="list" class="divide-y divide-slate-100 rounded-lg border border-slate-200 bg-white">
18
+ <%= render partial: "moduler/profile/sessions/session", collection: @sessions %>
19
+ </ul>
20
+ </div>
21
+
22
+ <div class="mt-4 flex justify-end">
23
+ <%= paginate @sessions %>
24
+ </div>
25
+ </div>
26
+ </main>
@@ -18,25 +18,11 @@
18
18
 
19
19
  <div>
20
20
  <%= form_for @user, url: moduler.session_path, class: "space-y-6", data: { turbo: false } do |form| %>
21
- <%= form.full_error :base, class: "my-2 text-sm text-red-600" %>
21
+ <%= render(::Moduler::Form::BaseErrorComponent.new(form)) %>
22
22
 
23
- <div class="mt-2">
24
- <label for="email" class="block text-sm/6 font-medium text-gray-900"><%= t(".label.email_address") %></label>
25
- <div class="mt-2">
26
- <%= form.email_field :email_address, autofocus: true, placeholder: t(".placeholder.email_address"), value: params[:email_address], class: "block w-full rounded-md bg-white px-3 py-1.5 text-base text-gray-900 outline outline-1 -outline-offset-1 outline-gray-300 placeholder:text-gray-400 focus:outline focus:outline-2 focus:-outline-offset-2 focus:outline-custom sm:text-sm/6" %>
27
- </div>
28
- </div>
29
-
30
- <div class="mt-2">
31
- <label for="password" class="block text-sm/6 font-medium text-gray-900"><%= t(".label.password") %></label>
32
- <div class="mt-2">
33
- <%= form.password_field :password, placeholder: t(".placeholder.password"), class: "block w-full rounded-md bg-white px-3 py-1.5 text-base text-gray-900 outline outline-1 -outline-offset-1 outline-gray-300 placeholder:text-gray-400 focus:outline focus:outline-2 focus:-outline-offset-2 focus:outline-custom sm:text-sm/6" %>
34
- </div>
35
- </div>
36
-
37
- <div class="mt-4">
38
- <button type="submit" class="cursor-pointer flex w-full justify-center rounded-md bg-custom px-3 py-1.5 text-sm/6 font-semibold text-white shadow-sm hover:bg-custom focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-custom"><%= t(".action.sign_in") %></button>
39
- </div>
23
+ <%= render(::Moduler::Form::EmailComponent.new(form, :email_address, label: t(".label.email_address"), placeholder: t(".placeholder.email_address"))) %>
24
+ <%= render(::Moduler::Form::PasswordComponent.new(form, :password, label: t(".label.password"), placeholder: t(".placeholder.password"))) %>
25
+ <%= render(::Moduler::Form::SubmitComponent.new(form, text: t(".action.sign_in"))) %>
40
26
  <% end %>
41
27
  </div>
42
28
  </div>
@@ -12,39 +12,12 @@
12
12
  <div class="mt-10">
13
13
  <div>
14
14
  <%= form_for @user, url: moduler.user_path, class: "space-y-6", data: { turbo: false } do |form| %>
15
- <div class="mt-2">
16
- <label for="email" class="block text-sm/6 font-medium text-gray-900"><%= t(".label.email_address") %></label>
17
- <div class="mt-2">
18
- <%= form.email_field :email_address, autofocus: true, placeholder: t(".placeholder.email_address"), class: "block w-full rounded-md bg-white px-3 py-1.5 text-base text-gray-900 outline outline-1 -outline-offset-1 outline-gray-300 placeholder:text-gray-400 focus:outline focus:outline-2 focus:-outline-offset-2 focus:outline-custom sm:text-sm/6" %>
19
- </div>
20
- <% if form.error?(:email_address) %>
21
- <%= form.error(:email_address, class: "text-red-500 text-sm mt-1") %>
22
- <% end %>
23
- </div>
15
+ <%= render(::Moduler::Form::BaseErrorComponent.new(form)) %>
24
16
 
25
- <div class="mt-2">
26
- <label for="password" class="block text-sm/6 font-medium text-gray-900"><%= t(".label.password") %></label>
27
- <div class="mt-2">
28
- <%= form.password_field :password, placeholder: t(".placeholder.password"), class: "block w-full rounded-md bg-white px-3 py-1.5 text-base text-gray-900 outline outline-1 -outline-offset-1 outline-gray-300 placeholder:text-gray-400 focus:outline focus:outline-2 focus:-outline-offset-2 focus:outline-custom sm:text-sm/6" %>
29
- </div>
30
- <% if form.error?(:password) %>
31
- <%= form.error(:password, class: "text-red-500 text-sm mt-1") %>
32
- <% end %>
33
- </div>
34
-
35
- <div class="mt-2">
36
- <label for="password_confirmation" class="block text-sm/6 font-medium text-gray-900"><%= t(".label.password_confirmation") %></label>
37
- <div class="mt-2">
38
- <%= form.password_field :password_confirmation, placeholder: t(".placeholder.password_confirmation"), class: "block w-full rounded-md bg-white px-3 py-1.5 text-base text-gray-900 outline outline-1 -outline-offset-1 outline-gray-300 placeholder:text-gray-400 focus:outline focus:outline-2 focus:-outline-offset-2 focus:outline-custom sm:text-sm/6" %>
39
- </div>
40
- <% if form.error?(:password_confirmation) %>
41
- <%= form.error(:password_confirmation, class: "text-red-500 text-sm mt-1") %>
42
- <% end %>
43
- </div>
44
-
45
- <div class="mt-4">
46
- <button type="submit" class="cursor-pointer flex w-full justify-center rounded-md bg-custom px-3 py-1.5 text-sm/6 font-semibold text-white shadow-sm hover:bg-custom focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-custom"><%= t(".action.sign_up") %></button>
47
- </div>
17
+ <%= render(::Moduler::Form::EmailComponent.new(form, :email_address, label: t(".label.email_address"), placeholder: t(".placeholder.email_address"))) %>
18
+ <%= render(::Moduler::Form::PasswordComponent.new(form, :password, label: t(".label.password"), placeholder: t(".placeholder.password"), description: t(".description.password"))) %>
19
+ <%= render(::Moduler::Form::PasswordComponent.new(form, :password_confirmation, placeholder: t(".placeholder.password_confirmation"))) %>
20
+ <%= render(::Moduler::Form::SubmitComponent.new(form, text: t(".action.sign_up"))) %>
48
21
  <% end %>
49
22
  </div>
50
23
  </div>
data/config/importmap.rb CHANGED
@@ -1,4 +1,7 @@
1
1
  pin "moduler/application"
2
+ pin "@hotwired/turbo-rails", to: "turbo.min.js"
2
3
  pin "@hotwired/stimulus", to: "stimulus.min.js"
3
4
  pin "@hotwired/stimulus-loading", to: "stimulus-loading.js"
4
5
  pin_all_from File.expand_path("../app/assets/javascripts/moduler/controllers", __dir__), under: "moduler/controllers"
6
+ pin "marked", to: "moduler/vendor/marked.esm.js"
7
+ pin "@rails/activestorage", to: "activestorage.esm.js"
@@ -0,0 +1,37 @@
1
+ en:
2
+ moduler:
3
+ administration:
4
+ articles:
5
+ index:
6
+ title: Articles
7
+ description: Posts published on your own public site
8
+ empty: No articles found
9
+ action:
10
+ new: Create
11
+ article:
12
+ created: Created %{time} ago
13
+ action:
14
+ edit: Edit
15
+ destroy: Destroy
16
+ confirmation:
17
+ destroy: Are you sure?
18
+ create:
19
+ notice: Article has been created
20
+ update:
21
+ notice: Article has been updated
22
+ destroy:
23
+ notice: Article has been deleted
24
+ form:
25
+ title: Article
26
+ label:
27
+ title: Title
28
+ path: Path
29
+ description: Description
30
+ keywords: Keywords
31
+ content: Content
32
+ description:
33
+ path: The article's URL -- letters, numbers, and hyphens only.
34
+ description: Shown in search results and social previews.
35
+ keywords: Comma-separated, for search results and social previews.
36
+ action:
37
+ save: Save
@@ -0,0 +1,24 @@
1
+ en:
2
+ moduler:
3
+ administration:
4
+ sessions:
5
+ index:
6
+ title: Sessions
7
+ description: Sessions of all users. Search sessions by email address, IP address or device and revoke any of them.
8
+ empty: No sessions found.
9
+ destroy:
10
+ notice: Session has been revoked
11
+ session:
12
+ action:
13
+ destroy: Revoke
14
+ status:
15
+ active: Active
16
+ signed_out: Signed out
17
+ current: This device
18
+ signed_in: Signed in %{time} ago
19
+ signed_out: Signed out %{time} ago
20
+ unknown_ip: Unknown IP address
21
+ unknown_device: Unknown device
22
+ confirmation:
23
+ destroy: The user will be signed out of this session. Are you sure?
24
+ destroy_current: You will be signed out of this device. Are you sure?
@@ -0,0 +1,43 @@
1
+ en:
2
+ moduler:
3
+ administration:
4
+ users:
5
+ roles:
6
+ member: Member
7
+ administrator: Administrator
8
+ index:
9
+ title: Users
10
+ description: Manage user accounts and their roles. Search users by email address.
11
+ empty: No users found.
12
+ action:
13
+ new: Create
14
+ new:
15
+ title: New user
16
+ label:
17
+ email_address: Email address
18
+ role: Role
19
+ password: Password
20
+ description:
21
+ password: Use at least 8 characters.
22
+ section:
23
+ data: User data
24
+ password: Password
25
+ action:
26
+ create: Create
27
+ create:
28
+ notice: User has been created
29
+ edit:
30
+ title: Edit user
31
+ label:
32
+ email_address: Email address
33
+ role: Role
34
+ section:
35
+ data: User data
36
+ action:
37
+ save: Save
38
+ update:
39
+ notice: User has been updated
40
+ user:
41
+ action:
42
+ edit: Edit
43
+ created: Created %{time} ago
@@ -0,0 +1,13 @@
1
+ en:
2
+ moduler:
3
+ articles:
4
+ index:
5
+ title: Articles
6
+ description: Read the latest articles.
7
+ empty: No articles have been published yet.
8
+ article:
9
+ action:
10
+ show: Read more
11
+ show:
12
+ action:
13
+ index: "← All articles"
@@ -1,8 +1,20 @@
1
1
  en:
2
2
  moduler:
3
3
  common:
4
+ administration:
5
+ sidebar:
6
+ action:
7
+ users: Users
8
+ sessions: Sessions
9
+ articles: Articles
10
+ profile:
11
+ sidebar:
12
+ action:
13
+ profile: Profile
14
+ sessions: Sessions
4
15
  header:
5
16
  nav:
17
+ administration: Administration
6
18
  home: Home
7
19
  action:
8
20
  sign_out: Sign out
@@ -0,0 +1,27 @@
1
+ en:
2
+ moduler:
3
+ components:
4
+ filter:
5
+ placeholder:
6
+ query: Search...
7
+ action:
8
+ filter: Filter
9
+ clear: Clear
10
+ list:
11
+ empty: No results found.
12
+ form:
13
+ wysiwyg:
14
+ action:
15
+ bold: B
16
+ italic: I
17
+ h1: H1
18
+ h2: H2
19
+ h3: H3
20
+ quote: Quote
21
+ code: Code
22
+ ul: List
23
+ ol: 1. List
24
+ fenced_code: "</>"
25
+ link: Link
26
+ image: Image
27
+ upload: Upload
@@ -0,0 +1,4 @@
1
+ en:
2
+ moduler:
3
+ flash:
4
+ not_authorized: You are not authorized to perform this action.
@@ -0,0 +1,26 @@
1
+ en:
2
+ moduler:
3
+ profile:
4
+ edit:
5
+ title: Profile
6
+ label:
7
+ email_address: Email address
8
+ password: New password
9
+ password_confirmation: Confirm new password
10
+ password_challenge: Current password
11
+ description:
12
+ password_confirmation: Leave blank to keep your current password. Changing it signs out your other active sessions.
13
+ password_challenge: Required to save changes to password.
14
+ action:
15
+ save: Save
16
+ section:
17
+ data: Your data
18
+ password: Change password
19
+ current_password: Confirm changes
20
+ sidebar:
21
+ profile: Profile
22
+ notifications: Notifications
23
+ security: Security
24
+ billing: Billing
25
+ update:
26
+ notice: Your profile has been updated
@@ -0,0 +1,25 @@
1
+ en:
2
+ moduler:
3
+ profile:
4
+ sessions:
5
+ index:
6
+ title: Sessions
7
+ description: Devices where you are signed in to your account. Revoke any session you don't recognize.
8
+ action:
9
+ revoke_all: Revoke all
10
+ confirmation:
11
+ revoke: You will be signed out of all sessions, including this one. Are you sure?
12
+ session:
13
+ action:
14
+ destroy: Revoke
15
+ status:
16
+ active: Active
17
+ signed_out: Signed out
18
+ current: This device
19
+ signed_in: Signed in %{time} ago
20
+ signed_out: Signed out %{time} ago
21
+ unknown_ip: Unknown IP address
22
+ unknown_device: Unknown device
23
+ confirmation:
24
+ destroy: Are you sure?
25
+ destroy_current: You will be signed out of this device. Are you sure?
@@ -15,3 +15,4 @@ en:
15
15
  password: Enter your password
16
16
  create:
17
17
  invalid_credentials: Invalid credentials
18
+ rate_limited: Too many sign-in attempts. Please try again in a few minutes.
@@ -7,9 +7,15 @@ en:
7
7
  action:
8
8
  sign_in: "Sign in"
9
9
  sign_up: "Sign up"
10
+ label:
11
+ email_address: "Email address"
12
+ password: "Password"
10
13
  placeholder:
11
14
  email_address: "Email address"
12
15
  password: "Password"
13
- password_confirmation: "Password confirmation"
16
+ password_confirmation: "Confirm password"
17
+ description:
18
+ password: "Use at least 8 characters containing at least 1 number and 1 lowercase letter"
14
19
  create:
15
20
  success: "User created successfully."
21
+ rate_limited: "Too many sign-up attempts. Please try again in a few minutes."
data/config/routes.rb CHANGED
@@ -1,8 +1,25 @@
1
1
  Moduler::Engine.routes.draw do
2
+ resources :articles, only: %i[ index show ], param: :path
3
+
2
4
  resource :session, only: %i[new create destroy]
3
5
  resource :user, only: %i[new create]
4
6
 
5
- get "/hello", to: "hello#index"
7
+ resource :profile, only: %i[ edit update ], controller: :profile
8
+ namespace :profile do
9
+ namespace :sessions do
10
+ resource :revocation, only: :destroy, controller: :revocation
11
+ end
12
+ resources :sessions, only: %i[ index destroy ]
13
+ end
14
+
15
+ namespace :administration do
16
+ resources :users, only: %i[ index new create edit update ]
17
+ resources :sessions, only: %i[ index destroy ]
18
+
19
+ resources :articles
20
+
21
+ root "home#index"
22
+ end
6
23
 
7
24
  root "home#index"
8
25
  end
@@ -0,0 +1,5 @@
1
+ class AddRoleToModulerUsers < ActiveRecord::Migration[8.1]
2
+ def change
3
+ add_column :moduler_users, :role, :integer, default: 0
4
+ end
5
+ end
@@ -0,0 +1,5 @@
1
+ class EnablePgTrgm < ActiveRecord::Migration[8.1]
2
+ def change
3
+ enable_extension "pg_trgm"
4
+ end
5
+ end
@@ -0,0 +1,15 @@
1
+ class CreateModulerArticles < ActiveRecord::Migration[8.1]
2
+ def change
3
+ create_table :moduler_articles do |t|
4
+ t.string :path, null: false
5
+ t.string :title, null: false
6
+ t.string :description, null: false
7
+ t.string :keywords, null: false
8
+ t.text :content, null: false
9
+
10
+ t.timestamps null: false
11
+ end
12
+
13
+ add_index :moduler_articles, :path, unique: true
14
+ end
15
+ end
@@ -1,6 +1,8 @@
1
1
  require "importmap-rails"
2
2
  require "stimulus-rails"
3
+ require "turbo-rails"
3
4
  require "tailwindcss-rails"
5
+ require "kaminari"
4
6
 
5
7
  module Moduler
6
8
  class Engine < ::Rails::Engine
@@ -1,3 +1,3 @@
1
1
  module Moduler
2
- VERSION = "0.2.0"
2
+ VERSION = "0.4.0"
3
3
  end
data/lib/moduler.rb CHANGED
@@ -1,3 +1,10 @@
1
+ require "view_component"
2
+ require "pg_search"
3
+ require "pundit"
4
+ require "active_storage/engine"
5
+ require "active_storage_validations"
6
+ require "redcarpet"
7
+
1
8
  require "moduler/version"
2
9
  require "moduler/engine"
3
10
  require "moduler/configuration"
@@ -12,8 +12,7 @@ namespace :moduler do
12
12
  command = [
13
13
  Tailwindcss::Ruby.executable,
14
14
  "--input", input_path,
15
- "--output", output_path,
16
- "--minify"
15
+ "--output", output_path
17
16
  ]
18
17
 
19
18
  Dir.chdir(Moduler::Engine.root) do
@@ -32,8 +31,7 @@ namespace :moduler do
32
31
  Tailwindcss::Ruby.executable,
33
32
  "--input", input_path,
34
33
  "--output", output_path,
35
- "--watch",
36
- "--minify"
34
+ "--watch"
37
35
  ]
38
36
 
39
37
  Dir.chdir(Moduler::Engine.root) do