moduler 0.1.0 → 0.2.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 (38) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/builds/moduler/tailwind.css +2 -0
  3. data/app/assets/config/moduler/manifest.js +2 -0
  4. data/app/assets/javascripts/moduler/application.js +8 -0
  5. data/app/assets/javascripts/moduler/controllers/hello_controller.js +6 -0
  6. data/app/assets/stylesheets/moduler/tailwind.css +18 -0
  7. data/app/controllers/concerns/moduler/authentication.rb +54 -0
  8. data/app/controllers/moduler/application_controller.rb +3 -0
  9. data/app/controllers/moduler/hello_controller.rb +5 -0
  10. data/app/controllers/moduler/home_controller.rb +5 -0
  11. data/app/controllers/moduler/sessions_controller.rb +32 -0
  12. data/app/controllers/moduler/users_controller.rb +29 -0
  13. data/app/helpers/moduler/application_helper.rb +4 -0
  14. data/app/lib/moduler/form_builder.rb +23 -0
  15. data/app/models/moduler/current.rb +6 -0
  16. data/app/models/moduler/session.rb +5 -0
  17. data/app/models/moduler/user.rb +9 -0
  18. data/app/views/layouts/moduler/application.html.erb +17 -10
  19. data/app/views/moduler/common/_header.html.erb +9 -0
  20. data/app/views/moduler/hello/index.html.erb +5 -0
  21. data/app/views/moduler/home/index.html.erb +0 -0
  22. data/app/views/moduler/sessions/new.html.erb +45 -0
  23. data/app/views/moduler/users/new.html.erb +53 -0
  24. data/config/importmap.rb +4 -0
  25. data/config/locales/moduler/common/en.yml +8 -0
  26. data/config/locales/moduler/sessions/en.yml +17 -0
  27. data/config/locales/moduler/users/en.yml +15 -0
  28. data/config/routes.rb +6 -0
  29. data/db/migrate/20260322152259_create_moduler_users.rb +12 -0
  30. data/db/migrate/20260322153744_create_moduler_sessions.rb +13 -0
  31. data/lib/moduler/configuration.rb +12 -0
  32. data/lib/moduler/engine.rb +18 -0
  33. data/lib/moduler/router.rb +10 -0
  34. data/lib/moduler/routing.rb +11 -0
  35. data/lib/moduler/version.rb +1 -1
  36. data/lib/moduler.rb +8 -1
  37. data/lib/tasks/moduler_tasks.rake +44 -4
  38. metadata +104 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ee9c915a15de92bab4f81a1aa61b7764bb5b22e6feab16344bfdbf0aeef7b3ac
4
- data.tar.gz: 6b94903f147505eba8e636d75fb9e6cad9d91a4211a3225c178fe05f4637ad7b
3
+ metadata.gz: 0e1a62fb57e31767df2806f00e1fe698722d1fd9426ba661310802db4ae177e7
4
+ data.tar.gz: 5bac3084f0ef2badc614d4c135773507d226c1e2b512b9b3730711b358ca2891
5
5
  SHA512:
6
- metadata.gz: e174f8c8d23ae87f652192b1cb9cdbed3d3caeefb9b7c0715424a84a3a379fe601aedb277802d3c717656c9efbca6be5d210795d4c5884f3b8979fd9ec2b5647
7
- data.tar.gz: ad9422ca7d3a1413760986d8fec2ca2813a2aa076008107b8c523638a0805bcd573162a3072fbf837dad8874808220307e4291ec9a5e1146ab121f138c0315f4
6
+ metadata.gz: 990a53932e2a4b33aede460d8da344bddabfd37fa509262e20ab129f12499eaa0bd3f7c52eaa468cda7a8f60aac940a8a1c03ac617550f2e5108f906dc8769ff
7
+ data.tar.gz: c756262071e39bcde10b9d91d8ef676b81fba2e36dc4eeea36e16041b013fb148072774e32e37e2c5bcb893ef9103683b9e393e9bcc3214d545cd6c99cf682b0
@@ -0,0 +1,2 @@
1
+ /*! tailwindcss v4.2.1 | MIT License | https://tailwindcss.com */
2
+ @layer properties{@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-space-y-reverse:0;--tw-border-style:solid;--tw-font-weight:initial;--tw-tracking:initial;--tw-shadow:0 0 #0000;--tw-shadow-color:initial;--tw-shadow-alpha:100%;--tw-inset-shadow:0 0 #0000;--tw-inset-shadow-color:initial;--tw-inset-shadow-alpha:100%;--tw-ring-color:initial;--tw-ring-shadow:0 0 #0000;--tw-inset-ring-color:initial;--tw-inset-ring-shadow:0 0 #0000;--tw-ring-inset:initial;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-offset-shadow:0 0 #0000;--tw-outline-style:solid}}}@layer theme{:root,:host{--font-sans:ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";--font-mono:ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;--color-red-100:oklch(93.6% .032 17.717);--color-red-500:oklch(63.7% .237 25.331);--color-red-600:oklch(57.7% .245 27.325);--color-yellow-100:oklch(97.3% .071 103.193);--color-green-100:oklch(96.2% .044 156.743);--color-green-600:oklch(62.7% .194 149.214);--color-gray-50:oklch(98.5% .002 247.839);--color-gray-200:oklch(92.8% .006 264.531);--color-gray-300:oklch(87.2% .01 258.338);--color-gray-400:oklch(70.7% .022 261.325);--color-gray-500:oklch(55.1% .027 264.364);--color-gray-900:oklch(21% .034 264.665);--color-white:#fff;--spacing:.25rem;--container-sm:24rem;--container-2xl:42rem;--container-7xl:80rem;--text-sm:.875rem;--text-sm--line-height:calc(1.25 / .875);--text-base:1rem;--text-base--line-height:calc(1.5 / 1);--text-2xl:1.5rem;--text-4xl:2.25rem;--text-4xl--line-height:calc(2.5 / 2.25);--text-6xl:3.75rem;--text-6xl--line-height:1;--font-weight-medium:500;--font-weight-semibold:600;--font-weight-bold:700;--tracking-tight:-.025em;--radius-md:.375rem;--default-font-family:var(--font-sans);--default-mono-font-family:var(--font-mono);--color-custom:#000}}@layer base{*,:after,:before,::backdrop{box-sizing:border-box;border:0 solid;margin:0;padding:0}::file-selector-button{box-sizing:border-box;border:0 solid;margin:0;padding:0}html,:host{-webkit-text-size-adjust:100%;tab-size:4;line-height:1.5;font-family:var(--default-font-family,ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji");font-feature-settings:var(--default-font-feature-settings,normal);font-variation-settings:var(--default-font-variation-settings,normal);-webkit-tap-highlight-color:transparent}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:var(--default-mono-font-family,ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace);font-feature-settings:var(--default-mono-font-feature-settings,normal);font-variation-settings:var(--default-mono-font-variation-settings,normal);font-size:1em}small{font-size:80%}sub,sup{vertical-align:baseline;font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}:-moz-focusring{outline:auto}progress{vertical-align:baseline}summary{display:list-item}ol,ul,menu{list-style:none}img,svg,video,canvas,audio,iframe,embed,object{vertical-align:middle;display:block}img,video{max-width:100%;height:auto}button,input,select,optgroup,textarea{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}::file-selector-button{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}:where(select:is([multiple],[size])) optgroup{font-weight:bolder}:where(select:is([multiple],[size])) optgroup option{padding-inline-start:20px}::file-selector-button{margin-inline-end:4px}::placeholder{opacity:1}@supports (not ((-webkit-appearance:-apple-pay-button))) or (contain-intrinsic-size:1px){::placeholder{color:currentColor}@supports (color:color-mix(in lab, red, red)){::placeholder{color:color-mix(in oklab, currentcolor 50%, transparent)}}}textarea{resize:vertical}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-date-and-time-value{min-height:1lh;text-align:inherit}::-webkit-datetime-edit{padding-block:0}::-webkit-datetime-edit-year-field{padding-block:0}::-webkit-datetime-edit-month-field{padding-block:0}::-webkit-datetime-edit-day-field{padding-block:0}::-webkit-datetime-edit-hour-field{padding-block:0}::-webkit-datetime-edit-minute-field{padding-block:0}::-webkit-datetime-edit-second-field{padding-block:0}::-webkit-datetime-edit-millisecond-field{padding-block:0}::-webkit-datetime-edit-meridiem-field{padding-block:0}::-webkit-calendar-picker-indicator{line-height:1}:-moz-ui-invalid{box-shadow:none}button,input:where([type=button],[type=reset],[type=submit]){appearance:button}::file-selector-button{appearance:button}::-webkit-inner-spin-button{height:auto}::-webkit-outer-spin-button{height:auto}[hidden]:where(:not([hidden=until-found])){display:none!important}input:where([type=text]),input:where(:not([type])),input:where([type=email]),input:where([type=url]),input:where([type=password]),input:where([type=number]),input:where([type=date]),input:where([type=datetime-local]),input:where([type=month]),input:where([type=search]),input:where([type=tel]),input:where([type=time]),input:where([type=week]),select:where([multiple]),textarea,select{appearance:none;--tw-shadow:0 0 #0000;background-color:#fff;border-width:1px;border-color:oklch(55.1% .027 264.364);border-radius:0;padding:.5rem .75rem;font-size:1rem;line-height:1.5rem}:is(input:where([type=text]),input:where(:not([type])),input:where([type=email]),input:where([type=url]),input:where([type=password]),input:where([type=number]),input:where([type=date]),input:where([type=datetime-local]),input:where([type=month]),input:where([type=search]),input:where([type=tel]),input:where([type=time]),input:where([type=week]),select:where([multiple]),textarea,select):focus{outline-offset:2px;--tw-ring-inset:var(--tw-empty, );--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:oklch(54.6% .245 262.881);--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);border-color:oklch(54.6% .245 262.881);outline:2px solid #0000}input::placeholder,textarea::placeholder{color:oklch(55.1% .027 264.364);opacity:1}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-date-and-time-value{min-height:1.5em}::-webkit-date-and-time-value{text-align:inherit}::-webkit-datetime-edit{display:inline-flex}::-webkit-datetime-edit{padding-top:0;padding-bottom:0}::-webkit-datetime-edit-year-field{padding-top:0;padding-bottom:0}::-webkit-datetime-edit-month-field{padding-top:0;padding-bottom:0}::-webkit-datetime-edit-day-field{padding-top:0;padding-bottom:0}::-webkit-datetime-edit-hour-field{padding-top:0;padding-bottom:0}::-webkit-datetime-edit-minute-field{padding-top:0;padding-bottom:0}::-webkit-datetime-edit-second-field{padding-top:0;padding-bottom:0}::-webkit-datetime-edit-millisecond-field{padding-top:0;padding-bottom:0}::-webkit-datetime-edit-meridiem-field{padding-top:0;padding-bottom:0}select{-webkit-print-color-adjust:exact;print-color-adjust:exact;background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 20 20'%3e%3cpath stroke='oklch(55.1%25 0.027 264.364)' stroke-linecap='round' stroke-linejoin='round' stroke-width='1.5' d='M6 8l4 4 4-4'/%3e%3c/svg%3e");background-position:right .5rem center;background-repeat:no-repeat;background-size:1.5em 1.5em;padding-right:2.5rem}select:where([multiple]),select:where([size]:not([size="1"])){background-image:initial;background-position:initial;background-repeat:unset;background-size:initial;print-color-adjust:unset;padding-right:.75rem}input:where([type=checkbox]),input:where([type=radio]){appearance:none;-webkit-print-color-adjust:exact;print-color-adjust:exact;vertical-align:middle;-webkit-user-select:none;user-select:none;color:oklch(54.6% .245 262.881);--tw-shadow:0 0 #0000;background-color:#fff;background-origin:border-box;border-width:1px;border-color:oklch(55.1% .027 264.364);flex-shrink:0;width:1rem;height:1rem;padding:0;display:inline-block}input:where([type=checkbox]){border-radius:0}input:where([type=radio]){border-radius:100%}input:where([type=checkbox]):focus,input:where([type=radio]):focus{outline-offset:2px;--tw-ring-inset:var(--tw-empty, );--tw-ring-offset-width:2px;--tw-ring-offset-color:#fff;--tw-ring-color:oklch(54.6% .245 262.881);--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow);outline:2px solid #0000}input:where([type=checkbox]):checked,input:where([type=radio]):checked{background-color:currentColor;background-position:50%;background-repeat:no-repeat;background-size:100% 100%;border-color:#0000}input:where([type=checkbox]):checked{background-image:url("data:image/svg+xml,%3csvg viewBox='0 0 16 16' fill='white' xmlns='http://www.w3.org/2000/svg'%3e%3cpath d='M12.207 4.793a1 1 0 010 1.414l-5 5a1 1 0 01-1.414 0l-2-2a1 1 0 011.414-1.414L6.5 9.086l4.293-4.293a1 1 0 011.414 0z'/%3e%3c/svg%3e")}@media (forced-colors:active){input:where([type=checkbox]):checked{appearance:auto}}input:where([type=radio]):checked{background-image:url("data:image/svg+xml,%3csvg viewBox='0 0 16 16' fill='white' xmlns='http://www.w3.org/2000/svg'%3e%3ccircle cx='8' cy='8' r='3'/%3e%3c/svg%3e")}@media (forced-colors:active){input:where([type=radio]):checked{appearance:auto}}input:where([type=checkbox]):checked:hover,input:where([type=checkbox]):checked:focus,input:where([type=radio]):checked:hover,input:where([type=radio]):checked:focus{background-color:currentColor;border-color:#0000}input:where([type=checkbox]):indeterminate{background-color:currentColor;background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 16 16'%3e%3cpath stroke='white' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M4 8h8'/%3e%3c/svg%3e");background-position:50%;background-repeat:no-repeat;background-size:100% 100%;border-color:#0000}@media (forced-colors:active){input:where([type=checkbox]):indeterminate{appearance:auto}}input:where([type=checkbox]):indeterminate:hover,input:where([type=checkbox]):indeterminate:focus{background-color:currentColor;border-color:#0000}input:where([type=file]){background:unset;border-color:inherit;font-size:unset;line-height:inherit;border-width:0;border-radius:0;padding:0}input:where([type=file]):focus{outline:1px solid buttontext;outline:1px auto -webkit-focus-ring-color}}@layer components;@layer utilities{.start{inset-inline-start:var(--spacing)}.end{inset-inline-end:var(--spacing)}.mx-auto{margin-inline:auto}.my-2{margin-block:calc(var(--spacing) * 2)}.mt-1{margin-top:calc(var(--spacing) * 1)}.mt-2{margin-top:calc(var(--spacing) * 2)}.mt-4{margin-top:calc(var(--spacing) * 4)}.mt-8{margin-top:calc(var(--spacing) * 8)}.mt-10{margin-top:calc(var(--spacing) * 10)}.block{display:block}.flex{display:flex}.inline{display:inline}.h-16{height:calc(var(--spacing) * 16)}.min-h-full{min-height:100%}.w-full{width:100%}.max-w-2xl{max-width:var(--container-2xl)}.max-w-7xl{max-width:var(--container-7xl)}.max-w-sm{max-width:var(--container-sm)}.flex-1{flex:1}.cursor-pointer{cursor:pointer}.flex-col{flex-direction:column}.items-center{align-items:center}.justify-between{justify-content:space-between}.justify-center{justify-content:center}.gap-8{gap:calc(var(--spacing) * 8)}:where(.space-y-6>:not(:last-child)){--tw-space-y-reverse:0;margin-block-start:calc(calc(var(--spacing) * 6) * var(--tw-space-y-reverse));margin-block-end:calc(calc(var(--spacing) * 6) * calc(1 - var(--tw-space-y-reverse)))}.rounded-md{border-radius:var(--radius-md)}.border-b{border-bottom-style:var(--tw-border-style);border-bottom-width:1px}.border-gray-200{border-color:var(--color-gray-200)}.bg-custom{background-color:var(--color-custom)}.bg-green-100{background-color:var(--color-green-100)}.bg-red-100{background-color:var(--color-red-100)}.bg-white{background-color:var(--color-white)}.bg-yellow-100{background-color:var(--color-yellow-100)}.px-3{padding-inline:calc(var(--spacing) * 3)}.px-4{padding-inline:calc(var(--spacing) * 4)}.px-6{padding-inline:calc(var(--spacing) * 6)}.py-1\.5{padding-block:calc(var(--spacing) * 1.5)}.py-12{padding-block:calc(var(--spacing) * 12)}.py-24{padding-block:calc(var(--spacing) * 24)}.text-center{text-align:center}.text-2xl\/9{font-size:var(--text-2xl);line-height:calc(var(--spacing) * 9)}.text-4xl{font-size:var(--text-4xl);line-height:var(--tw-leading,var(--text-4xl--line-height))}.text-base{font-size:var(--text-base);line-height:var(--tw-leading,var(--text-base--line-height))}.text-sm{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height))}.text-sm\/6{font-size:var(--text-sm);line-height:calc(var(--spacing) * 6)}.font-bold{--tw-font-weight:var(--font-weight-bold);font-weight:var(--font-weight-bold)}.font-medium{--tw-font-weight:var(--font-weight-medium);font-weight:var(--font-weight-medium)}.font-semibold{--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold)}.tracking-tight{--tw-tracking:var(--tracking-tight);letter-spacing:var(--tracking-tight)}.text-custom{color:var(--color-custom)}.text-gray-500{color:var(--color-gray-500)}.text-gray-900{color:var(--color-gray-900)}.text-green-600{color:var(--color-green-600)}.text-red-500{color:var(--color-red-500)}.text-red-600{color:var(--color-red-600)}.text-white{color:var(--color-white)}.shadow-sm{--tw-shadow:0 1px 3px 0 var(--tw-shadow-color,#0000001a), 0 1px 2px -1px var(--tw-shadow-color,#0000001a);box-shadow:var(--tw-inset-shadow), var(--tw-inset-ring-shadow), var(--tw-ring-offset-shadow), var(--tw-ring-shadow), var(--tw-shadow)}.outline,.outline-1{outline-style:var(--tw-outline-style);outline-width:1px}.-outline-offset-1{outline-offset:calc(1px * -1)}.outline-gray-300{outline-color:var(--color-gray-300)}.placeholder\:text-gray-400::placeholder{color:var(--color-gray-400)}@media (hover:hover){.hover\:bg-custom:hover{background-color:var(--color-custom)}.hover\:bg-gray-50:hover{background-color:var(--color-gray-50)}.hover\:text-custom:hover{color:var(--color-custom)}}.focus\:outline:focus{outline-style:var(--tw-outline-style);outline-width:1px}.focus\:outline-2:focus{outline-style:var(--tw-outline-style);outline-width:2px}.focus\:-outline-offset-2:focus{outline-offset:calc(2px * -1)}.focus\:outline-custom:focus{outline-color:var(--color-custom)}.focus-visible\:outline:focus-visible{outline-style:var(--tw-outline-style);outline-width:1px}.focus-visible\:outline-2:focus-visible{outline-style:var(--tw-outline-style);outline-width:2px}.focus-visible\:outline-offset-2:focus-visible{outline-offset:2px}.focus-visible\:outline-custom:focus-visible{outline-color:var(--color-custom)}@media (min-width:40rem){.sm\:px-6{padding-inline:calc(var(--spacing) * 6)}.sm\:py-32{padding-block:calc(var(--spacing) * 32)}.sm\:text-6xl{font-size:var(--text-6xl);line-height:var(--tw-leading,var(--text-6xl--line-height))}.sm\:text-sm\/6{font-size:var(--text-sm);line-height:calc(var(--spacing) * 6)}}@media (min-width:64rem){.lg\:w-96{width:calc(var(--spacing) * 96)}.lg\:flex-none{flex:none}.lg\:px-8{padding-inline:calc(var(--spacing) * 8)}.lg\:px-20{padding-inline:calc(var(--spacing) * 20)}}@media (min-width:80rem){.xl\:px-24{padding-inline:calc(var(--spacing) * 24)}}}.prose-100{max-width:100%}@property --tw-space-y-reverse{syntax:"*";inherits:false;initial-value:0}@property --tw-border-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-font-weight{syntax:"*";inherits:false}@property --tw-tracking{syntax:"*";inherits:false}@property --tw-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-shadow-color{syntax:"*";inherits:false}@property --tw-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-inset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-shadow-color{syntax:"*";inherits:false}@property --tw-inset-shadow-alpha{syntax:"<percentage>";inherits:false;initial-value:100%}@property --tw-ring-color{syntax:"*";inherits:false}@property --tw-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-ring-color{syntax:"*";inherits:false}@property --tw-inset-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-ring-inset{syntax:"*";inherits:false}@property --tw-ring-offset-width{syntax:"<length>";inherits:false;initial-value:0}@property --tw-ring-offset-color{syntax:"*";inherits:false;initial-value:#fff}@property --tw-ring-offset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-outline-style{syntax:"*";inherits:false;initial-value:solid}
@@ -0,0 +1,2 @@
1
+ //= link_tree ../../javascripts/moduler .js
2
+ //= link_tree ../../builds/moduler .css
@@ -0,0 +1,8 @@
1
+ import { Application } from "@hotwired/stimulus"
2
+ import { eagerLoadControllersFrom } from "@hotwired/stimulus-loading"
3
+
4
+ const application = Application.start()
5
+ application.debug = false
6
+ window.Stimulus = application
7
+
8
+ eagerLoadControllersFrom("moduler/controllers", application)
@@ -0,0 +1,6 @@
1
+ import { Controller } from "@hotwired/stimulus";
2
+ export default class extends Controller {
3
+ connect() {
4
+ this.element.textContent = "Moduler 🔥";
5
+ }
6
+ }
@@ -0,0 +1,18 @@
1
+ @import "tailwindcss";
2
+ @import "tailwindcss/utilities";
3
+ @plugin "@tailwindcss/forms";
4
+ @plugin "@tailwindcss/aspect-ratio";
5
+ @plugin "@tailwindcss/typography";
6
+
7
+ @source inline('bg-yellow-100');
8
+ @source inline('bg-red-100');
9
+ @source inline('bg-green-100');
10
+
11
+ @theme {
12
+ --color-custom: #000;
13
+ --font-custom: "Arial", sans-serif;
14
+ }
15
+
16
+ .prose-100 {
17
+ max-width: 100%;
18
+ }
@@ -0,0 +1,54 @@
1
+ module Moduler
2
+ module Authentication
3
+ extend ActiveSupport::Concern
4
+
5
+ included do
6
+ before_action :require_authentication
7
+ helper_method :authenticated?
8
+ end
9
+
10
+ class_methods do
11
+ def allow_unauthenticated_access(**options)
12
+ skip_before_action :require_authentication, **options
13
+ end
14
+ end
15
+
16
+ private
17
+
18
+ def authenticated?
19
+ resume_session
20
+ end
21
+
22
+ def require_authentication
23
+ resume_session || request_authentication
24
+ end
25
+
26
+ def resume_session
27
+ Current.session ||= find_session_by_cookie
28
+ end
29
+
30
+ def find_session_by_cookie
31
+ Session.find_by(id: cookies.signed[:session_id], signed_out_at: nil) if cookies.signed[:session_id]
32
+ end
33
+
34
+ def request_authentication
35
+ redirect_to moduler.new_session_path
36
+ end
37
+
38
+ def after_authentication_url
39
+ moduler.root_path
40
+ end
41
+
42
+ def start_new_session_for(user)
43
+ user.sessions.create!(user_agent: request.user_agent, ip_address: request.remote_ip, signed_in_at: Time.current).tap do |session|
44
+ Current.session = session
45
+ cookies.signed.permanent[:session_id] = { value: session.id, httponly: true, same_site: :lax }
46
+ end
47
+ end
48
+
49
+ def terminate_session
50
+ Current.session.touch(:signed_out_at)
51
+ cookies.delete(:session_id)
52
+ end
53
+ end
54
+ end
@@ -1,4 +1,7 @@
1
1
  module Moduler
2
2
  class ApplicationController < ActionController::Base
3
+ include Authentication
4
+
5
+ default_form_builder FormBuilder
3
6
  end
4
7
  end
@@ -0,0 +1,5 @@
1
+ module Moduler
2
+ class HelloController < ApplicationController
3
+ def index; end
4
+ end
5
+ end
@@ -0,0 +1,5 @@
1
+ module Moduler
2
+ class HomeController < ApplicationController
3
+ def index; end
4
+ end
5
+ end
@@ -0,0 +1,32 @@
1
+ module Moduler
2
+ class SessionsController < ApplicationController
3
+ allow_unauthenticated_access only: %i[ new create ]
4
+
5
+ def new
6
+ if authenticated?
7
+ redirect_to after_authentication_url
8
+ end
9
+
10
+ @user = User.new
11
+ end
12
+
13
+ def create
14
+ if user = User.authenticate_by(params.require(:user).permit(:email_address, :password))
15
+ start_new_session_for user
16
+
17
+ redirect_to after_authentication_url
18
+ else
19
+ @user = User.new.tap do |user|
20
+ user.errors.add(:base, t("moduler.sessions.create.invalid_credentials"))
21
+ end
22
+
23
+ render :new
24
+ end
25
+ end
26
+
27
+ def destroy
28
+ terminate_session
29
+ redirect_to moduler.new_session_path
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,29 @@
1
+ module Moduler
2
+ class UsersController < ApplicationController
3
+ allow_unauthenticated_access only: %i[ new create ]
4
+
5
+ def new
6
+ if authenticated?
7
+ redirect_to after_authentication_url
8
+ end
9
+
10
+ @user = User.new
11
+ end
12
+
13
+ def create
14
+ @user = User.new(permitted_parameters)
15
+
16
+ if @user.save
17
+ redirect_to moduler.new_session_path, notice: t("moduler.users.create.success")
18
+ else
19
+ render :new
20
+ end
21
+ end
22
+
23
+ private
24
+
25
+ def permitted_parameters
26
+ params.require(:user).permit(:email_address, :password, :password_confirmation)
27
+ end
28
+ end
29
+ end
@@ -1,4 +1,8 @@
1
1
  module Moduler
2
2
  module ApplicationHelper
3
+ def stylesheet_link_tags_if_exist(*sources, **options)
4
+ existing = sources.select { |source| Rails.application.assets.load_path.find("#{source}.css") }
5
+ stylesheet_link_tag(*existing, **options) if existing.any?
6
+ end
3
7
  end
4
8
  end
@@ -0,0 +1,23 @@
1
+ module Moduler
2
+ class FormBuilder < ActionView::Helpers::FormBuilder
3
+ def error(field, options = {})
4
+ return unless error?(field)
5
+
6
+ @template.content_tag :div, **options do
7
+ @object.errors[field].first
8
+ end.html_safe
9
+ end
10
+
11
+ def full_error(field, options = {})
12
+ return unless error?(field)
13
+
14
+ @template.content_tag :div, **options do
15
+ @object.errors.full_messages_for(field).first
16
+ end.html_safe
17
+ end
18
+
19
+ def error?(field)
20
+ @object && @object.errors[field].try(:any?)
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,6 @@
1
+ module Moduler
2
+ class Current < ActiveSupport::CurrentAttributes
3
+ attribute :session
4
+ delegate :user, to: :session, allow_nil: true
5
+ end
6
+ end
@@ -0,0 +1,5 @@
1
+ module Moduler
2
+ class Session < ApplicationRecord
3
+ belongs_to :user, class_name: "Moduler::User", foreign_key: "moduler_user_id"
4
+ end
5
+ end
@@ -0,0 +1,9 @@
1
+ module Moduler
2
+ class User < ApplicationRecord
3
+ has_many :sessions, class_name: "Moduler::Session", foreign_key: "moduler_user_id", dependent: :destroy
4
+
5
+ has_secure_password
6
+
7
+ validates :email_address, presence: true, uniqueness: true, format: { with: URI::MailTo::EMAIL_REGEXP }
8
+ end
9
+ end
@@ -1,17 +1,24 @@
1
1
  <!DOCTYPE html>
2
2
  <html>
3
- <head>
4
- <title>Moduler</title>
5
- <%= csrf_meta_tags %>
6
- <%= csp_meta_tag %>
3
+ <head>
4
+ <title>Moduler</title>
5
+ <%= csrf_meta_tags %>
6
+ <%= csp_meta_tag %>
7
7
 
8
- <%= yield :head %>
8
+ <%= yield :head %>
9
9
 
10
- <%= stylesheet_link_tag "moduler/application", media: "all" %>
11
- </head>
12
- <body>
10
+ <%= stylesheet_link_tags_if_exist "moduler/tailwind", "moduler/application", media: "all" %>
13
11
 
14
- <%= yield %>
12
+ <%# Include host application stylesheets %>
13
+ <%= stylesheet_link_tags_if_exist "tailwind", "application", media: "all" %>
15
14
 
16
- </body>
15
+ <%= javascript_importmap_tags "moduler/application" %>
16
+ </head>
17
+ <body>
18
+ <div class="min-h-full">
19
+ <%= render "moduler/common/header" %>
20
+
21
+ <%= yield %>
22
+ </div>
23
+ </body>
17
24
  </html>
@@ -0,0 +1,9 @@
1
+ <nav class="border-b border-gray-200 bg-white">
2
+ <div class="mx-auto flex h-16 max-w-7xl items-center justify-between px-4 sm:px-6 lg:px-8">
3
+ <div class="flex items-center gap-8">
4
+ <%= link_to t(".nav.home"), moduler.root_path, class: "text-sm/6 font-semibold text-gray-900 hover:text-custom" %>
5
+ </div>
6
+
7
+ <%= button_to t(".action.sign_out"), moduler.session_path, method: :delete, class: "cursor-pointer rounded-md px-3 py-1.5 text-sm/6 font-semibold text-gray-900 hover:bg-gray-50" %>
8
+ </div>
9
+ </nav>
@@ -0,0 +1,5 @@
1
+ <div class="bg-white px-6 py-24 sm:py-32 lg:px-8">
2
+ <div class="mx-auto max-w-2xl text-center">
3
+ <h2 class="text-4xl font-bold tracking-tight text-custom sm:text-6xl"><div data-controller="hello"></div></h2>
4
+ </div>
5
+ </div>
File without changes
@@ -0,0 +1,45 @@
1
+ <div class="flex min-h-full">
2
+ <div class="flex flex-1 flex-col justify-center px-4 py-12 sm:px-6 lg:flex-none lg:px-20 xl:px-24">
3
+ <div class="mx-auto w-full max-w-sm lg:w-96">
4
+ <div>
5
+ <h2 class="mt-8 text-2xl/9 font-bold tracking-tight text-gray-900"><%= t(".title") %></h2>
6
+ <p class="mt-2 text-sm/6 text-gray-500">
7
+ <%= t(".subtitle") %>
8
+ <%= link_to t(".action.sign_up"), moduler.new_user_path, class: "font-semibold text-custom hover:text-custom" %>
9
+ </p>
10
+ </div>
11
+
12
+ <div class="mt-10">
13
+ <% flash.each do |type, message| %>
14
+ <div class="my-2 text-sm text-green-600">
15
+ <%= message %>
16
+ </div>
17
+ <% end %>
18
+
19
+ <div>
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" %>
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>
40
+ <% end %>
41
+ </div>
42
+ </div>
43
+ </div>
44
+ </div>
45
+ </div>
@@ -0,0 +1,53 @@
1
+ <div class="flex min-h-full">
2
+ <div class="flex flex-1 flex-col justify-center px-4 py-12 sm:px-6 lg:flex-none lg:px-20 xl:px-24">
3
+ <div class="mx-auto w-full max-w-sm lg:w-96">
4
+ <div>
5
+ <h2 class="mt-8 text-2xl/9 font-bold tracking-tight text-gray-900"><%= t(".title") %></h2>
6
+ <p class="mt-2 text-sm/6 text-gray-500">
7
+ <%= t(".subtitle") %>
8
+ <%= link_to t(".action.sign_in"), moduler.new_session_path, class: "font-semibold text-custom hover:text-custom" %>
9
+ </p>
10
+ </div>
11
+
12
+ <div class="mt-10">
13
+ <div>
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>
24
+
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>
48
+ <% end %>
49
+ </div>
50
+ </div>
51
+ </div>
52
+ </div>
53
+ </div>
@@ -0,0 +1,4 @@
1
+ pin "moduler/application"
2
+ pin "@hotwired/stimulus", to: "stimulus.min.js"
3
+ pin "@hotwired/stimulus-loading", to: "stimulus-loading.js"
4
+ pin_all_from File.expand_path("../app/assets/javascripts/moduler/controllers", __dir__), under: "moduler/controllers"
@@ -0,0 +1,8 @@
1
+ en:
2
+ moduler:
3
+ common:
4
+ header:
5
+ nav:
6
+ home: Home
7
+ action:
8
+ sign_out: Sign out
@@ -0,0 +1,17 @@
1
+ en:
2
+ moduler:
3
+ sessions:
4
+ new:
5
+ title: Sign in to your account
6
+ subtitle: Enter your email and password to sign in.
7
+ action:
8
+ sign_in: Sign in
9
+ sign_up: Sign up
10
+ label:
11
+ email_address: Email address
12
+ password: Password
13
+ placeholder:
14
+ email_address: Enter your email address
15
+ password: Enter your password
16
+ create:
17
+ invalid_credentials: Invalid credentials
@@ -0,0 +1,15 @@
1
+ en:
2
+ moduler:
3
+ users:
4
+ new:
5
+ title: "Create an account"
6
+ subtitle: "Already have an account?"
7
+ action:
8
+ sign_in: "Sign in"
9
+ sign_up: "Sign up"
10
+ placeholder:
11
+ email_address: "Email address"
12
+ password: "Password"
13
+ password_confirmation: "Password confirmation"
14
+ create:
15
+ success: "User created successfully."
data/config/routes.rb CHANGED
@@ -1,2 +1,8 @@
1
1
  Moduler::Engine.routes.draw do
2
+ resource :session, only: %i[new create destroy]
3
+ resource :user, only: %i[new create]
4
+
5
+ get "/hello", to: "hello#index"
6
+
7
+ root "home#index"
2
8
  end
@@ -0,0 +1,12 @@
1
+ class CreateModulerUsers < ActiveRecord::Migration[8.1]
2
+ def change
3
+ create_table :moduler_users, id: :uuid do |t|
4
+ t.string :email_address, null: false
5
+ t.string :password_digest
6
+
7
+ t.timestamps null: false
8
+ end
9
+
10
+ add_index :moduler_users, :email_address, unique: true
11
+ end
12
+ end
@@ -0,0 +1,13 @@
1
+ class CreateModulerSessions < ActiveRecord::Migration[8.1]
2
+ def change
3
+ create_table :moduler_sessions, id: :uuid do |t|
4
+ t.references :moduler_user, null: false, foreign_key: true, type: :uuid
5
+ t.string :ip_address
6
+ t.string :user_agent
7
+ t.datetime :signed_in_at
8
+ t.datetime :signed_out_at
9
+
10
+ t.timestamps null: false
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,12 @@
1
+ module Moduler
2
+ class Configuration
3
+ extend Forwardable
4
+
5
+ def_delegator :@configuration, :[]
6
+ def_delegator :@configuration, :dig
7
+
8
+ def initialize
9
+ @configuration = Rails.application.config_for(:moduler)
10
+ end
11
+ end
12
+ end
@@ -1,5 +1,23 @@
1
+ require "importmap-rails"
2
+ require "stimulus-rails"
3
+ require "tailwindcss-rails"
4
+
1
5
  module Moduler
2
6
  class Engine < ::Rails::Engine
3
7
  isolate_namespace Moduler
8
+
9
+ initializer "moduler.importmap", before: "importmap" do |app|
10
+ app.config.importmap.paths += [ Engine.root.join("config/importmap.rb") ]
11
+ end
12
+
13
+ initializer "moduler.assets" do |app|
14
+ app.config.assets.precompile += %w[moduler/manifest.js]
15
+ end
16
+
17
+ initializer "moduler.routes" do
18
+ Engine.routes.append do
19
+ instance_exec(&Moduler.router.routes) if Moduler.router&.routes
20
+ end
21
+ end
4
22
  end
5
23
  end
@@ -0,0 +1,10 @@
1
+ module Moduler
2
+ class Router
3
+ def initialize(path, routes)
4
+ @path = path
5
+ @routes = routes
6
+ end
7
+
8
+ attr_reader :path, :routes
9
+ end
10
+ end
@@ -0,0 +1,11 @@
1
+ module Moduler
2
+ mattr_accessor :router
3
+
4
+ module Routing
5
+ def moduler(path, &block)
6
+ Moduler.router = Router.new(path, block)
7
+
8
+ mount Moduler::Engine => path, as: :moduler
9
+ end
10
+ end
11
+ end
@@ -1,3 +1,3 @@
1
1
  module Moduler
2
- VERSION = "0.1.0"
2
+ VERSION = "0.2.0"
3
3
  end
data/lib/moduler.rb CHANGED
@@ -1,6 +1,13 @@
1
1
  require "moduler/version"
2
2
  require "moduler/engine"
3
+ require "moduler/configuration"
4
+ require "moduler/router"
5
+ require "moduler/routing"
3
6
 
4
7
  module Moduler
5
- # Your code goes here...
8
+ def self.configuration
9
+ @configuration ||= Configuration.new
10
+ end
6
11
  end
12
+
13
+ ActionDispatch::Routing::Mapper.include Moduler::Routing
@@ -1,4 +1,44 @@
1
- # desc "Explaining what the task does"
2
- # task :moduler do
3
- # # Task goes here
4
- # end
1
+ require "tailwindcss-rails"
2
+
3
+ namespace :moduler do
4
+ namespace :tailwindcss do
5
+ desc "Build Tailwind CSS for Moduler Engine"
6
+ task :build do
7
+ input_path = "app/assets/stylesheets/moduler/tailwind.css"
8
+ output_path = "app/assets/builds/moduler/tailwind.css"
9
+
10
+ FileUtils.mkdir_p(Moduler::Engine.root.join("app/assets/builds/moduler"))
11
+
12
+ command = [
13
+ Tailwindcss::Ruby.executable,
14
+ "--input", input_path,
15
+ "--output", output_path,
16
+ "--minify"
17
+ ]
18
+
19
+ Dir.chdir(Moduler::Engine.root) do
20
+ system(*command, exception: true)
21
+ end
22
+ end
23
+
24
+ desc "Watch and build Tailwind CSS for Moduler Engine"
25
+ task :watch do
26
+ input_path = "app/assets/stylesheets/moduler/tailwind.css"
27
+ output_path = "app/assets/builds/moduler/tailwind.css"
28
+
29
+ FileUtils.mkdir_p(Moduler::Engine.root.join("app/assets/builds/moduler"))
30
+
31
+ command = [
32
+ Tailwindcss::Ruby.executable,
33
+ "--input", input_path,
34
+ "--output", output_path,
35
+ "--watch",
36
+ "--minify"
37
+ ]
38
+
39
+ Dir.chdir(Moduler::Engine.root) do
40
+ system(*command, exception: true)
41
+ end
42
+ end
43
+ end
44
+ end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: moduler
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tomasz Kowalewski
8
8
  bindir: bin
9
9
  cert_chain: []
10
- date: 2026-03-19 00:00:00.000000000 Z
10
+ date: 2026-09-27 00:00:00.000000000 Z
11
11
  dependencies:
12
12
  - !ruby/object:Gem::Dependency
13
13
  name: rails
@@ -29,6 +29,80 @@ dependencies:
29
29
  - - ">="
30
30
  - !ruby/object:Gem::Version
31
31
  version: 8.1.2
32
+ - !ruby/object:Gem::Dependency
33
+ name: importmap-rails
34
+ requirement: !ruby/object:Gem::Requirement
35
+ requirements:
36
+ - - "~>"
37
+ - !ruby/object:Gem::Version
38
+ version: '2.2'
39
+ - - ">="
40
+ - !ruby/object:Gem::Version
41
+ version: 2.2.3
42
+ type: :runtime
43
+ prerelease: false
44
+ version_requirements: !ruby/object:Gem::Requirement
45
+ requirements:
46
+ - - "~>"
47
+ - !ruby/object:Gem::Version
48
+ version: '2.2'
49
+ - - ">="
50
+ - !ruby/object:Gem::Version
51
+ version: 2.2.3
52
+ - !ruby/object:Gem::Dependency
53
+ name: stimulus-rails
54
+ requirement: !ruby/object:Gem::Requirement
55
+ requirements:
56
+ - - "~>"
57
+ - !ruby/object:Gem::Version
58
+ version: '1.3'
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: 1.3.4
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '1.3'
69
+ - - ">="
70
+ - !ruby/object:Gem::Version
71
+ version: 1.3.4
72
+ - !ruby/object:Gem::Dependency
73
+ name: tailwindcss-rails
74
+ requirement: !ruby/object:Gem::Requirement
75
+ requirements:
76
+ - - "~>"
77
+ - !ruby/object:Gem::Version
78
+ version: '4.4'
79
+ type: :runtime
80
+ prerelease: false
81
+ version_requirements: !ruby/object:Gem::Requirement
82
+ requirements:
83
+ - - "~>"
84
+ - !ruby/object:Gem::Version
85
+ version: '4.4'
86
+ - !ruby/object:Gem::Dependency
87
+ name: bcrypt
88
+ requirement: !ruby/object:Gem::Requirement
89
+ requirements:
90
+ - - "~>"
91
+ - !ruby/object:Gem::Version
92
+ version: '3.1'
93
+ - - ">="
94
+ - !ruby/object:Gem::Version
95
+ version: 3.1.22
96
+ type: :runtime
97
+ prerelease: false
98
+ version_requirements: !ruby/object:Gem::Requirement
99
+ requirements:
100
+ - - "~>"
101
+ - !ruby/object:Gem::Version
102
+ version: '3.1'
103
+ - - ">="
104
+ - !ruby/object:Gem::Version
105
+ version: 3.1.22
32
106
  email:
33
107
  - me@tkowalewski.pl
34
108
  executables: []
@@ -38,16 +112,44 @@ files:
38
112
  - MIT-LICENSE
39
113
  - README.md
40
114
  - Rakefile
115
+ - app/assets/builds/moduler/tailwind.css
116
+ - app/assets/config/moduler/manifest.js
117
+ - app/assets/javascripts/moduler/application.js
118
+ - app/assets/javascripts/moduler/controllers/hello_controller.js
41
119
  - app/assets/stylesheets/moduler/application.css
120
+ - app/assets/stylesheets/moduler/tailwind.css
121
+ - app/controllers/concerns/moduler/authentication.rb
42
122
  - app/controllers/moduler/application_controller.rb
123
+ - app/controllers/moduler/hello_controller.rb
124
+ - app/controllers/moduler/home_controller.rb
125
+ - app/controllers/moduler/sessions_controller.rb
126
+ - app/controllers/moduler/users_controller.rb
43
127
  - app/helpers/moduler/application_helper.rb
44
128
  - app/jobs/moduler/application_job.rb
129
+ - app/lib/moduler/form_builder.rb
45
130
  - app/mailers/moduler/application_mailer.rb
46
131
  - app/models/moduler/application_record.rb
132
+ - app/models/moduler/current.rb
133
+ - app/models/moduler/session.rb
134
+ - app/models/moduler/user.rb
47
135
  - app/views/layouts/moduler/application.html.erb
136
+ - app/views/moduler/common/_header.html.erb
137
+ - app/views/moduler/hello/index.html.erb
138
+ - app/views/moduler/home/index.html.erb
139
+ - app/views/moduler/sessions/new.html.erb
140
+ - app/views/moduler/users/new.html.erb
141
+ - config/importmap.rb
142
+ - config/locales/moduler/common/en.yml
143
+ - config/locales/moduler/sessions/en.yml
144
+ - config/locales/moduler/users/en.yml
48
145
  - config/routes.rb
146
+ - db/migrate/20260322152259_create_moduler_users.rb
147
+ - db/migrate/20260322153744_create_moduler_sessions.rb
49
148
  - lib/moduler.rb
149
+ - lib/moduler/configuration.rb
50
150
  - lib/moduler/engine.rb
151
+ - lib/moduler/router.rb
152
+ - lib/moduler/routing.rb
51
153
  - lib/moduler/version.rb
52
154
  - lib/tasks/moduler_tasks.rake
53
155
  homepage: https://github.com/tkowalewski/moduler