kern 0.7.0 → 0.8.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 (34) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile.lock +13 -4
  3. data/README.md +1 -0
  4. data/Rakefile +1 -1
  5. data/app/assets/builds/tailwind.kern.css +31 -39
  6. data/app/controllers/concerns/authentication.rb +4 -0
  7. data/app/controllers/concerns/authentication.rb.tt +4 -0
  8. data/app/controllers/concerns/layouts.rb +22 -0
  9. data/app/controllers/kern/application_controller.rb +7 -0
  10. data/app/controllers/kern/passwords_controller.rb +1 -1
  11. data/app/controllers/kern/sessions_controller.rb +1 -1
  12. data/app/controllers/kern/signups_controller.rb +6 -2
  13. data/app/controllers/kern/signups_controller.rb.tt +1 -1
  14. data/app/models/billing_profile/subscription.rb +1 -1
  15. data/app/models/workspace/members.rb +6 -0
  16. data/app/views/components/_heading.html.erb +1 -1
  17. data/app/views/components/_section.html.erb +12 -0
  18. data/app/views/components/flash/_message.html.erb +2 -2
  19. data/app/views/kern/pages/welcome.html.erb +2 -15
  20. data/app/views/kern/passwords/new.html.erb +2 -0
  21. data/app/views/kern/sessions/new.html.erb +2 -4
  22. data/app/views/kern/signups/new.html.erb +1 -3
  23. data/app/views/layouts/kern/application.html.erb +1 -1
  24. data/app/views/layouts/kern/application.html.erb.tt +5 -3
  25. data/app/views/layouts/kern/auth.html.erb +3 -0
  26. data/app/views/layouts/kern/auth.html.erb.tt +46 -0
  27. data/app/webhooks/stripe/base.rb +1 -1
  28. data/lib/generators/kern/layouts/layouts_generator.rb +1 -1
  29. data/lib/kern/engine.rb +4 -0
  30. data/lib/kern/form_builder/input.rb +9 -11
  31. data/lib/kern/form_builder/styles.rb +35 -0
  32. data/lib/kern/form_builder.rb +17 -4
  33. data/lib/kern/version.rb +1 -1
  34. metadata +5 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d18817224e28d4f7ed96d2d6c805ee1a9a5ab6afc6c6b052ed661d0ac35949bc
4
- data.tar.gz: 4261479514032c6e87caccd6b59c9e7d5fbfa3ab68a9a903d808f0021121e4a1
3
+ metadata.gz: 6e5939e78f0c9a8ed8f74d2108f04e1a7d1a6b57464d85770a513e3bc8186582
4
+ data.tar.gz: 2b6ffa3d55e045514e9d19fff2a378c354bc1efd8af39caca8cc79e9bac813d2
5
5
  SHA512:
6
- metadata.gz: b68dd99d028916c30b5b44f5b85a7890cfade3185bb4ec6ca26a061f3d6027ddede1476b41cbc1189bd15df2d24d1aa6852731a4d702558e5c1807e85b54d977
7
- data.tar.gz: 2d00f1333f735d2ef44d10f72d9a560b2cd074596527f3fb67a074f23b46ba9c5cb8574defb555ca2844f3a590dfb9d00d50814d85326d94d6cc158c73ac41e8
6
+ metadata.gz: 53f4f292112352c6c980b7d9f7a6ce0bb7f69d02247bb0f2d504778d72aed6141cd18c3a51d5b1082dbe2c387ec0580e3a5205a3e0cb33763498fab9ba06de87
7
+ data.tar.gz: bb31cce5665edc407bfafcd4fefddfc9dff1a888f22152f0c03aed30450457f2e209362a7729a0f77bcee94a491b28d8c576c2ca85d51b1479dd54f26b2e5094
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- kern (0.7.0)
4
+ kern (0.8.0)
5
5
  rails (>= 8.0.0)
6
6
 
7
7
  GEM
@@ -120,6 +120,7 @@ GEM
120
120
  net-smtp
121
121
  marcel (1.1.0)
122
122
  mini_mime (1.1.5)
123
+ mini_portile2 (2.8.9)
123
124
  minitest (5.26.2)
124
125
  net-imap (0.5.12)
125
126
  date
@@ -131,6 +132,9 @@ GEM
131
132
  net-smtp (0.5.1)
132
133
  net-protocol
133
134
  nio4r (2.7.5)
135
+ nokogiri (1.18.10)
136
+ mini_portile2 (~> 2.8.2)
137
+ racc (~> 1.4)
134
138
  nokogiri (1.18.10-aarch64-linux-gnu)
135
139
  racc (~> 1.4)
136
140
  nokogiri (1.18.10-aarch64-linux-musl)
@@ -235,6 +239,8 @@ GEM
235
239
  rubocop-ast (>= 1.47.1, < 2.0)
236
240
  ruby-progressbar (1.13.0)
237
241
  securerandom (0.4.1)
242
+ sqlite3 (2.8.1)
243
+ mini_portile2 (~> 2.8.0)
238
244
  sqlite3 (2.8.1-aarch64-linux-gnu)
239
245
  sqlite3 (2.8.1-aarch64-linux-musl)
240
246
  sqlite3 (2.8.1-arm-linux-gnu)
@@ -279,7 +285,7 @@ GEM
279
285
  concurrent-ruby (~> 1.0)
280
286
  unicode-display_width (3.2.0)
281
287
  unicode-emoji (~> 4.1)
282
- unicode-emoji (4.1.0)
288
+ unicode-emoji (4.2.0)
283
289
  uri (1.1.1)
284
290
  useragent (0.16.11)
285
291
  websocket-driver (0.8.0)
@@ -345,7 +351,7 @@ CHECKSUMS
345
351
  io-console (0.8.1) sha256=1e15440a6b2f67b6ea496df7c474ed62c860ad11237f29b3bd187f054b925fcb
346
352
  irb (1.15.3) sha256=4349edff1efa7ff7bfd34cb9df74a133a588ba88c2718098b3b4468b81184aaa
347
353
  json (2.17.1) sha256=e0e4824541336a44915436f53e7ea74c687314fb8f88080fa1456f6a34ead92e
348
- kern (0.7.0)
354
+ kern (0.8.0)
349
355
  language_server-protocol (3.17.0.5) sha256=fd1e39a51a28bf3eec959379985a72e296e9f9acfce46f6a79d31ca8760803cc
350
356
  lint_roller (1.1.0) sha256=2c0c845b632a7d172cb849cc90c1bce937a28c5c8ccccb50dfd46a485003cc87
351
357
  logger (1.7.0) sha256=196edec7cc44b66cfb40f9755ce11b392f21f7967696af15d274dde7edff0203
@@ -353,12 +359,14 @@ CHECKSUMS
353
359
  mail (2.9.0) sha256=6fa6673ecd71c60c2d996260f9ee3dd387d4673b8169b502134659ece6d34941
354
360
  marcel (1.1.0) sha256=fdcfcfa33cc52e93c4308d40e4090a5d4ea279e160a7f6af988260fa970e0bee
355
361
  mini_mime (1.1.5) sha256=8681b7e2e4215f2a159f9400b5816d85e9d8c6c6b491e96a12797e798f8bccef
362
+ mini_portile2 (2.8.9) sha256=0cd7c7f824e010c072e33f68bc02d85a00aeb6fce05bb4819c03dfd3c140c289
356
363
  minitest (5.26.2) sha256=f021118a6185b9ba9f5af71f2ba103ad770c75afde9f2ab8da512677c550cde3
357
364
  net-imap (0.5.12) sha256=cb8cd05bd353fcc19b6cbc530a9cb06b577a969ea10b7ddb0f37787f74be4444
358
365
  net-pop (0.1.2) sha256=848b4e982013c15b2f0382792268763b748cce91c9e91e36b0f27ed26420dff3
359
366
  net-protocol (0.2.2) sha256=aa73e0cba6a125369de9837b8d8ef82a61849360eba0521900e2c3713aa162a8
360
367
  net-smtp (0.5.1) sha256=ed96a0af63c524fceb4b29b0d352195c30d82dd916a42f03c62a3a70e5b70736
361
368
  nio4r (2.7.5) sha256=6c90168e48fb5f8e768419c93abb94ba2b892a1d0602cb06eef16d8b7df1dca1
369
+ nokogiri (1.18.10) sha256=d5cc0731008aa3b3a87b361203ea3d19b2069628cb55e46ac7d84a0445e69cc1
362
370
  nokogiri (1.18.10-aarch64-linux-gnu) sha256=7fb87235d729c74a2be635376d82b1d459230cc17c50300f8e4fcaabc6195344
363
371
  nokogiri (1.18.10-aarch64-linux-musl) sha256=7e74e58314297cc8a8f1b533f7212d1999dbe2639a9ee6d97b483ea2acc18944
364
372
  nokogiri (1.18.10-arm-linux-gnu) sha256=51f4f25ab5d5ba1012d6b16aad96b840a10b067b93f35af6a55a2c104a7ee322
@@ -395,6 +403,7 @@ CHECKSUMS
395
403
  rubocop-performance (1.26.1) sha256=cd19b936ff196df85829d264b522fd4f98b6c89ad271fa52744a8c11b8f71834
396
404
  ruby-progressbar (1.13.0) sha256=80fc9c47a9b640d6834e0dc7b3c94c9df37f08cb072b7761e4a71e22cff29b33
397
405
  securerandom (0.4.1) sha256=cc5193d414a4341b6e225f0cb4446aceca8e50d5e1888743fac16987638ea0b1
406
+ sqlite3 (2.8.1) sha256=acd0ac7912a4d92b2484b5befb6faa8d496497eb1e38bdbe8d7818fb8d05d726
398
407
  sqlite3 (2.8.1-aarch64-linux-gnu) sha256=9bce166d3e3595a42fc92c28d986ea11d499b55be8bd1cd491be04af30029543
399
408
  sqlite3 (2.8.1-aarch64-linux-musl) sha256=34912f6acf3e9c43c7998c6f99ba3146708e654cf9716b2983e260315cdeed72
400
409
  sqlite3 (2.8.1-arm-linux-gnu) sha256=9118d6abb5ca7ea4f1b50a6c42c763e612670f5eb673bbdf12e8d3bd63339bde
@@ -423,7 +432,7 @@ CHECKSUMS
423
432
  turbo-rails (2.0.20) sha256=cbcbb4dd3ce59f6471c9f911b1655b2c721998cc8303959d982da347f374ea95
424
433
  tzinfo (2.0.6) sha256=8daf828cc77bcf7d63b0e3bdb6caa47e2272dcfaf4fbfe46f8c3a9df087a829b
425
434
  unicode-display_width (3.2.0) sha256=0cdd96b5681a5949cdbc2c55e7b420facae74c4aaf9a9815eee1087cb1853c42
426
- unicode-emoji (4.1.0) sha256=4997d2d5df1ed4252f4830a9b6e86f932e2013fbff2182a9ce9ccabda4f325a5
435
+ unicode-emoji (4.2.0) sha256=519e69150f75652e40bf736106cfbc8f0f73aa3fb6a65afe62fefa7f80b0f80f
427
436
  uri (1.1.1) sha256=379fa58d27ffb1387eaada68c749d1426738bd0f654d812fcc07e7568f5c57c6
428
437
  useragent (0.16.11) sha256=700e6413ad4bb954bb63547fa098dddf7b0ebe75b40cc6f93b8d54255b173844
429
438
  websocket-driver (0.8.0) sha256=ed0dba4b943c22f17f9a734817e808bc84cdce6a7e22045f5315aa57676d4962
data/README.md CHANGED
@@ -138,6 +138,7 @@ Pulled from [Rails Designer's Components](https://railsdesigner.com/components/)
138
138
  Some basic components are included like:
139
139
 
140
140
  - container; keep all your app's content in check
141
+ - section; easily divide up your screens in sections
141
142
  - heading; have consistent headings for each screen
142
143
  - enhanced dialog element (works with Turbo Frames and, includes `centered` or a `drawer` variants)
143
144
  - flash messages (notifiy your users from the bottom-right)
data/Rakefile CHANGED
@@ -16,7 +16,7 @@ namespace :assets do
16
16
  desc "Build Tailwind CSS for distribution"
17
17
  task :precompile do
18
18
  Dir.chdir("test/dummy") do
19
- sh "bundle exec tailwindcss -i app/assets/tailwind/application.css -o app/assets/builds/tailwind.kern.css"
19
+ sh "bundle exec tailwindcss -i app/assets/tailwind/application.kern.css -o app/assets/builds/tailwind.kern.css"
20
20
 
21
21
  FileUtils.mkdir_p "../../app/assets/builds"
22
22
  FileUtils.cp(
@@ -25,8 +25,6 @@
25
25
  --color-blue-800: oklch(42.4% 0.199 265.638);
26
26
  --color-blue-900: oklch(37.9% 0.146 265.522);
27
27
  --color-blue-950: oklch(28.2% 0.091 267.935);
28
- --color-pink-200: oklch(89.9% 0.061 343.231);
29
- --color-pink-800: oklch(45.9% 0.187 3.815);
30
28
  --color-slate-50: oklch(98.4% 0.003 247.858);
31
29
  --color-slate-100: oklch(96.8% 0.007 247.896);
32
30
  --color-slate-200: oklch(92.9% 0.013 255.508);
@@ -78,6 +76,7 @@
78
76
  --radius-lg: 0.5rem;
79
77
  --radius-xl: 0.75rem;
80
78
  --ease-in-out: cubic-bezier(0.4, 0, 0.2, 1);
79
+ --blur-sm: 8px;
81
80
  --blur-md: 12px;
82
81
  --default-transition-duration: 150ms;
83
82
  --default-transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
@@ -739,6 +738,9 @@
739
738
  .text-white {
740
739
  color: var(--color-white);
741
740
  }
741
+ .no-underline {
742
+ text-decoration-line: none;
743
+ }
742
744
  .antialiased {
743
745
  -webkit-font-smoothing: antialiased;
744
746
  -moz-osx-font-smoothing: grayscale;
@@ -793,6 +795,11 @@
793
795
  -webkit-backdrop-filter: var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,);
794
796
  backdrop-filter: var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,);
795
797
  }
798
+ .backdrop-blur-sm {
799
+ --tw-backdrop-blur: blur(var(--blur-sm));
800
+ -webkit-backdrop-filter: var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,);
801
+ backdrop-filter: var(--tw-backdrop-blur,) var(--tw-backdrop-brightness,) var(--tw-backdrop-contrast,) var(--tw-backdrop-grayscale,) var(--tw-backdrop-hue-rotate,) var(--tw-backdrop-invert,) var(--tw-backdrop-opacity,) var(--tw-backdrop-saturate,) var(--tw-backdrop-sepia,);
802
+ }
796
803
  .transition {
797
804
  transition-property: color, background-color, border-color, outline-color, text-decoration-color, fill, stroke, --tw-gradient-from, --tw-gradient-via, --tw-gradient-to, opacity, box-shadow, transform, translate, scale, rotate, filter, -webkit-backdrop-filter, backdrop-filter, display, content-visibility, overlay, pointer-events;
798
805
  transition-timing-function: var(--tw-ease, var(--default-transition-timing-function));
@@ -896,20 +903,6 @@
896
903
  }
897
904
  }
898
905
  }
899
- .selection\:bg-pink-200\/40 {
900
- & *::selection {
901
- background-color: color-mix(in srgb, oklch(89.9% 0.061 343.231) 40%, transparent);
902
- @supports (color: color-mix(in lab, red, red)) {
903
- background-color: color-mix(in oklab, var(--color-pink-200) 40%, transparent);
904
- }
905
- }
906
- &::selection {
907
- background-color: color-mix(in srgb, oklch(89.9% 0.061 343.231) 40%, transparent);
908
- @supports (color: color-mix(in lab, red, red)) {
909
- background-color: color-mix(in oklab, var(--color-pink-200) 40%, transparent);
910
- }
911
- }
912
- }
913
906
  .selection\:text-blue-800\/70 {
914
907
  & *::selection {
915
908
  color: color-mix(in srgb, oklch(42.4% 0.199 265.638) 70%, transparent);
@@ -924,20 +917,6 @@
924
917
  }
925
918
  }
926
919
  }
927
- .selection\:text-pink-800\/70 {
928
- & *::selection {
929
- color: color-mix(in srgb, oklch(45.9% 0.187 3.815) 70%, transparent);
930
- @supports (color: color-mix(in lab, red, red)) {
931
- color: color-mix(in oklab, var(--color-pink-800) 70%, transparent);
932
- }
933
- }
934
- &::selection {
935
- color: color-mix(in srgb, oklch(45.9% 0.187 3.815) 70%, transparent);
936
- @supports (color: color-mix(in lab, red, red)) {
937
- color: color-mix(in oklab, var(--color-pink-800) 70%, transparent);
938
- }
939
- }
940
- }
941
920
  .file\:mr-2 {
942
921
  &::file-selector-button {
943
922
  margin-right: calc(var(--spacing) * 2);
@@ -991,6 +970,11 @@
991
970
  display: block;
992
971
  }
993
972
  }
973
+ .empty\:hidden {
974
+ &:empty {
975
+ display: none;
976
+ }
977
+ }
994
978
  .hover\:scale-105 {
995
979
  &:hover {
996
980
  @media (hover: hover) {
@@ -1032,13 +1016,6 @@
1032
1016
  }
1033
1017
  }
1034
1018
  }
1035
- .hover\:text-gray-500 {
1036
- &:hover {
1037
- @media (hover: hover) {
1038
- color: var(--color-gray-500);
1039
- }
1040
- }
1041
- }
1042
1019
  .hover\:underline {
1043
1020
  &:hover {
1044
1021
  @media (hover: hover) {
@@ -1142,6 +1119,11 @@
1142
1119
  margin-inline: calc(var(--spacing) * 4);
1143
1120
  }
1144
1121
  }
1122
+ .md\:flex-row {
1123
+ @media (width >= 48rem) {
1124
+ flex-direction: row;
1125
+ }
1126
+ }
1145
1127
  .md\:gap-8 {
1146
1128
  @media (width >= 48rem) {
1147
1129
  gap: calc(var(--spacing) * 8);
@@ -1219,6 +1201,16 @@
1219
1201
  width: calc(var(--spacing) * 60);
1220
1202
  }
1221
1203
  }
1204
+ .lg\:max-w-1\/4 {
1205
+ @media (width >= 64rem) {
1206
+ max-width: calc(1/4 * 100%);
1207
+ }
1208
+ }
1209
+ .lg\:max-w-3\/4 {
1210
+ @media (width >= 64rem) {
1211
+ max-width: calc(3/4 * 100%);
1212
+ }
1213
+ }
1222
1214
  .lg\:px-6 {
1223
1215
  @media (width >= 64rem) {
1224
1216
  padding-inline: calc(var(--spacing) * 6);
@@ -1268,9 +1260,9 @@
1268
1260
  translate: var(--tw-translate-x) var(--tw-translate-y);
1269
1261
  }
1270
1262
  }
1271
- .\[\&\>input\]\:mt-\[0\.15em\] {
1263
+ .\[\&\>input\]\:mt-\[0\.17em\] {
1272
1264
  &>input {
1273
- margin-top: 0.15em;
1265
+ margin-top: 0.17em;
1274
1266
  }
1275
1267
  }
1276
1268
  .\[\&\[data-slot\=\'field\'\]\+\[data-slot\=\'field\'\]\]\:mt-4 {
@@ -40,6 +40,10 @@ module Authentication
40
40
  session.delete(:return_to_after_authenticating) || root_url
41
41
  end
42
42
 
43
+ def redirect_to_root
44
+ redirect_to root_url || kern.root_url
45
+ end
46
+
43
47
  def start_new_session_for(user)
44
48
  user.sessions.create!(user_agent: request.user_agent.presence || "[No User Agent]", ip_address: request.remote_ip).tap do |session|
45
49
  Current.session = session
@@ -40,6 +40,10 @@ module Authentication
40
40
  session.delete(:return_to_after_authenticating) || root_url
41
41
  end
42
42
 
43
+ def redirect_to_root
44
+ redirect_to root_url || kern.root_url
45
+ end
46
+
43
47
  def start_new_session_for(user)
44
48
  user.sessions.create!(user_agent: request.user_agent.presence || "[No User Agent]", ip_address: request.remote_ip).tap do |session|
45
49
  Current.session = session
@@ -0,0 +1,22 @@
1
+ module Layouts
2
+ extend ActiveSupport::Concern
3
+
4
+ class_methods do
5
+ def define_layout(layout_name, namespace: "kern")
6
+ layout -> { resolve(layout_name, namespace) }
7
+ end
8
+ end
9
+
10
+ private
11
+
12
+ def resolve(layout_name, namespace)
13
+ layout_name = layout_name.to_s
14
+
15
+ return layout_name if lookup_context.exists?(layout_name, ["layouts"])
16
+
17
+ namespaced = "#{namespace}/#{layout_name}"
18
+ return namespaced if lookup_context.exists?(namespaced, ["layouts"])
19
+
20
+ false
21
+ end
22
+ end
@@ -1,7 +1,14 @@
1
1
  module Kern
2
2
  class ApplicationController < ActionController::Base
3
3
  include Authentication
4
+ include Layouts
5
+
6
+ define_layout :application
4
7
 
5
8
  default_form_builder Kern::FormBuilder
9
+
10
+ private
11
+
12
+ def _prefixes = [controller_name] + super
6
13
  end
7
14
  end
@@ -5,7 +5,7 @@ module Kern
5
5
  before_action :redirect_to_root, if: -> { authenticated? }, only: %w[new create]
6
6
  before_action :set_user_by_token, only: %w[edit update]
7
7
 
8
- layout "kern/auth"
8
+ define_layout :auth
9
9
 
10
10
  def new
11
11
  end
@@ -6,7 +6,7 @@ module Kern
6
6
 
7
7
  rate_limit to: 10, within: 3.minutes, only: :create, with: -> { redirect_to new_session_url, alert: "Try again later" }
8
8
 
9
- layout "kern/auth"
9
+ define_layout :auth
10
10
 
11
11
  def new
12
12
  end
@@ -4,7 +4,7 @@ module Kern
4
4
 
5
5
  before_action :redirect_to_root, if: -> { authenticated? }, only: %w[new create]
6
6
 
7
- layout "kern/auth"
7
+ define_layout :auth
8
8
 
9
9
  def new
10
10
  @signup = Signup.new
@@ -16,7 +16,11 @@ module Kern
16
16
  if @signup.save
17
17
  start_new_session_for @signup.user
18
18
 
19
- redirect_to root_url
19
+ begin
20
+ redirect_to main_app.root_url
21
+ rescue
22
+ redirect_to root_url
23
+ end
20
24
  else
21
25
  render :new, status: :unprocessable_entity
22
26
  end
@@ -16,7 +16,7 @@ module Kern
16
16
  if @signup.save
17
17
  start_new_session_for @signup.user
18
18
 
19
- redirect_to root_path
19
+ redirect_to root_url
20
20
  else
21
21
  render :new, status: :unprocessable_entity
22
22
  end
@@ -1,4 +1,4 @@
1
- module BillingProfile
1
+ class BillingProfile
2
2
  class Subscription < ApplicationRecord
3
3
  include Sluggable
4
4
 
@@ -5,8 +5,14 @@ class Workspace
5
5
  included do
6
6
  has_many :members, dependent: :destroy
7
7
  has_many :users, through: :members
8
+
9
+ after_destroy_commit :purge_orphaned_users!
8
10
  end
9
11
 
10
12
  def add_member(to:, role: nil) = Member::Setup.new(workspace: self, user: to, role: role).save
13
+
14
+ private
15
+
16
+ def purge_orphaned_users! = User.left_joins(:members).where(members: {id: nil}).destroy_all
11
17
  end
12
18
  end
@@ -1,4 +1,4 @@
1
- <%# locals: (level: :h1, breadcrumbs: [], actions: [], css: class_names("flex items-center gap-x-1 h-8 font-sans font-bold text-gray-950 *:inline-block", {"text-base font-bold tracking-tight md:text-lg": level == :h1, "text-sm font-semibold md:text-base": level == :h2, "text-xs font-medium md:text-sm": level == :h3})) %>
1
+ <%# locals: (level: :h1, breadcrumbs: [], actions: [], css: class_names("flex items-center gap-x-1 h-8 font-sans font-bold text-gray-950 *:inline-block", {"text-base font-bold tracking-tight md:text-lg": level == :h1, "text-sm font-bold md:text-base": level == :h2, "text-xs font-medium md:text-sm": level == :h3})) %>
2
2
  <%= tag.header id: "heading", class: class_names("flex items-center justify-between", {"px-4 py-5 border-b border-gray-200/50": level == :h1}) do %>
3
3
  <%= tag.send(level, class: css) do %>
4
4
  <%= safe_join(breadcrumbs.map.with_index {|it, index| tag.span(link_to(it[:label], it[:href], class: "hover:underline", id: "header_part_link_#{index}") + tag.span("/", class: "ml-1 font-normal text-gray-400"), id: "header_part_#{index}")}) if level == :h1 %>
@@ -0,0 +1,12 @@
1
+ <%# locals: (direction: :vertical, heading: nil, description: nil, **options) %>
2
+ <%= tag.section class: class_names("flex pt-4 border-t border-gray-100", {"flex-col gap-2": direction == :vertical, "flex-col gap-4 md:flex-row": direction == :horizontal}) do %>
3
+ <div class="w-full lg:max-w-1/4">
4
+ <%= component("heading", level: :h2) { heading } %>
5
+
6
+ <%= tag.p description, class: "text-sm text-gray-700 md:text-base" if description.present? %>
7
+ </div>
8
+
9
+ <div class="<%= class_names("w-full", {"lg:max-w-3/4": direction == :horizontal}) %>">
10
+ <%= yield %>
11
+ </div>
12
+ <% end %>
@@ -1,4 +1,4 @@
1
- <%# locals: (type:, message:, icon: "check-circle", icon_css: class_names("size-3.5 shrink-0", {"text-emerald-300": type == "notice", "text-red-400": type == "alert"}), css: class_names("flex items-center gap-x-1.5 bg-gradient-to-b from-gray-900/80 to-gray-900 px-3 py-1.5 text-xs font-normal text-white ring ring-gray-700/90 rounded-md shadow-lg transition-all")) %>
2
- <li class="translate-x-0 opacity-100 transition-all duration-300 ease-in-out starting:translate-x-4 starting:opacity-0">
1
+ <%# locals: (type:, message:, icon: "check-circle", icon_css: class_names("size-3.5 shrink-0", {"text-emerald-300": type == "notice", "text-red-400": type == "alert"}), css: class_names("flex items-center gap-x-1.5 px-3 py-1.5 text-xs font-normal text-white bg-gradient-to-b from-gray-900/80 to-gray-900 backdrop-blur-sm ring ring-gray-700/90 rounded-md shadow-lg transition-all")) %>
2
+ <li data-action="element#remove:mounted" data-remove-delay="7000" class="translate-x-0 opacity-100 transition-all duration-300 ease-in-out starting:translate-x-4 starting:opacity-0">
3
3
  <%= tag.p safe_join([(icon(icon, class: icon_css) rescue nil), message]), aria: {live: :polite}, class: css %>
4
4
  </li>
@@ -22,25 +22,12 @@
22
22
  </li>
23
23
 
24
24
  <li>
25
- override any views by running <code class="select-all">bin/rails g kern:views</code>
25
+ override any feature by running <code class="select-all">bin/rails generate kern:feature FEATURE FEATURE</code>
26
26
  </li>
27
27
 
28
28
  <li>
29
- override any feature by running <code class="select-all">bin/rals g kern:feature</code>
30
- </li>
31
-
32
- <li>
33
- check out <%= link_to "Rails Designer's UI Components", "https://railsdesigner.com/components/" %>
34
- </li>
35
-
36
- <li>
37
- build your SaaS
38
- </li>
39
-
40
- <li>
41
- profit 🤑
29
+ override layouts by running <code class="select-all">bin/rails generate kern:layouts</code>
42
30
  </li>
43
31
  </ul>
44
-
45
32
  </section>
46
33
  </main>
@@ -8,3 +8,5 @@
8
8
  <%= form.submit "Continue", class: "btn-primary" %>
9
9
  </div>
10
10
  <% end %>
11
+
12
+ <%= content_for(:alternative_action) { link_to "I remember my password again…", new_session_path, class: "block text-center text-sm font-medium text-gray-500 hover:underline" } %>
@@ -4,13 +4,11 @@
4
4
  <%= form_with url: session_path, class: "px-2 md:px-4" do |form| %>
5
5
  <%= form.input :email_address, type: :email, required: true, autofocus: true, autocomplete: "username", value: params[:email_address] %>
6
6
 
7
- <%= form.input :password, required: true, autocomplete: "current-password", maxlength: 72, label_suffix: link_to("Forgot password?", new_password_path, class: "font-normal text-gray-400 hover:text-gray-500") %>
7
+ <%= form.input :password, required: true, autocomplete: "current-password", maxlength: 72, label_suffix: link_to("Forgot password?", new_password_path, class: "no-underline") %>
8
8
 
9
9
  <div class="buttons">
10
10
  <%= form.submit "Log in", data: {turbo_submits_with: "Logging in…"}, class: "btn-primary" %>
11
11
  </div>
12
12
  <% end %>
13
13
 
14
- <p class="px-2 pt-4 pb-2 border-t border-gray-100 md:pb-4">
15
- <%= link_to "No account yet?", new_signup_path, class: "block text-center text-sm text-gray-500 hover:underline" %>
16
- </p>
14
+ <%= content_for(:alternative_action) { link_to "No account yet?", new_signup_path, class: "block text-center text-sm text-gray-500 hover:underline" } %>
@@ -13,6 +13,4 @@
13
13
  </div>
14
14
  <% end %>
15
15
 
16
- <p class="px-2 pt-4 pb-2 border-t border-gray-100 md:pb-4">
17
- <%= link_to "Already have an account?", new_session_path, class: "block text-center text-sm font-medium text-gray-500 hover:underline" %>
18
- </p>
16
+ <%= content_for(:alternative_action) { link_to "Already have an account??", new_session_path, class: "block text-center text-sm font-medium text-gray-500 hover:underline" } %>
@@ -9,7 +9,7 @@
9
9
  <%= csp_meta_tag %>
10
10
 
11
11
  <%= stylesheet_link_tag "tailwind.kern", "data-turbo-track": "reload" %>
12
- <script defer src="https://cdn.jsdelivr.net/npm/attractivejs@0.9.0"></script>
12
+ <script defer src="https://cdn.jsdelivr.net/npm/attractivejs@0.11.0"></script>
13
13
  </head>
14
14
 
15
15
  <body class="<%= class_names("antialiased bg-white selection:bg-blue-200/40 selection:text-blue-800/70", yield(:body_class)) %>">
@@ -9,12 +9,13 @@
9
9
  <%%= csp_meta_tag %>
10
10
 
11
11
  <%%= stylesheet_link_tag "tailwind.kern", "data-turbo-track": "reload" %>
12
- <script defer src="https://cdn.jsdelivr.net/npm/attractivejs@0.9.0"></script>
12
+ <%%= stylesheet_link_tag "tailwind", "data-turbo-track": "reload" %>
13
+ <script defer src="https://cdn.jsdelivr.net/npm/attractivejs@0.11.0"></script>
13
14
  </head>
14
15
 
15
- <body class="<%%= class_names("antialiased bg-white selection:bg-pink-200/40 selection:text-pink-800/70", yield(:body_class)) %>">
16
+ <body class="<%%= class_names("antialiased bg-white selection:bg-blue-200/40 selection:text-blue-800/70", yield(:body_class)) %>">
16
17
  <div class="flex">
17
- <%%= render partial: "layouts/kern/application/navigation",
18
+ <%%= render partial: "layouts/application/navigation",
18
19
  locals: {
19
20
  links: [
20
21
  {label: "Home", href: root_path, icon: "house-line"},
@@ -28,5 +29,6 @@
28
29
  </div>
29
30
 
30
31
  <%%= component "flash" %>
32
+ <%%= component "dialog" %>
31
33
  </body>
32
34
  </html>
@@ -10,6 +10,7 @@
10
10
  <%= csp_meta_tag %>
11
11
 
12
12
  <%= stylesheet_link_tag "tailwind.kern", "data-turbo-track": "reload" %>
13
+ <script defer src="https://cdn.jsdelivr.net/npm/attractivejs@0.11.0"></script>
13
14
  </head>
14
15
 
15
16
  <body class="relative overflow-clip antialiased bg-white selection:bg-blue-200/40 selection:text-blue-800/70">
@@ -32,6 +33,8 @@
32
33
  <%= tag.h1 yield(:page_title), class: "mx-2 mt-8 font-sans text-center text-base font-bold text-gray-800 md:mx-4" %>
33
34
 
34
35
  <%= yield %>
36
+
37
+ <%= tag.p yield(:alternative_action), class: "px-2 pt-4 pb-2 border-t border-gray-100 empty:hidden md:pb-4" %>
35
38
  </section>
36
39
  </div>
37
40
  </div>
@@ -0,0 +1,46 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <title>
5
+ <%%= content_for?(:title)? "#{yield(:title)} - #{Rails.application.name.humanize}" : Rails.application.name.humanize %>
6
+ </title>
7
+ <meta name="viewport" content="width=device-width,initial-scale=1">
8
+ <meta name="robots" content="noindex, nofollow">
9
+ <%%= csrf_meta_tags %>
10
+ <%%= csp_meta_tag %>
11
+
12
+ <%%= stylesheet_link_tag "tailwind.kern", "data-turbo-track": "reload" %>
13
+ <%%= stylesheet_link_tag "tailwind", "data-turbo-track": "reload" %>
14
+ <script defer src="https://cdn.jsdelivr.net/npm/attractivejs@0.11.0"></script>
15
+ </head>
16
+
17
+ <body class="relative overflow-clip antialiased bg-white selection:bg-blue-200/40 selection:text-blue-800/70">
18
+ <svg viewBox="0 0 200 200" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" class="absolute -top-[400px] -left-[350px] size-[800px] text-brand-500">
19
+ <path fill="currentColor" d="M42.9,-43.4C60.9,-36,84.8,-27.6,92.2,-12.2C99.8,3.1,91.2,25.4,76.1,37C61.1,48.5,39.7,49.3,21.9,52.7C4,56.1,-10.4,62,-26.6,61.1C-42.9,60.3,-61.1,52.9,-61.9,41C-62.6,28.8,-46,12.1,-42.2,-7C-38.4,-25.9,-47.4,-46.5,-42.5,-56.1C-37.6,-65.8,-18.8,-64.5,-3.2,-60.7C12.4,-57,24.9,-50.8,42.9,-43.4Z" transform="translate(100 100)" />
20
+ </svg>
21
+
22
+ <svg viewBox="0 0 200 200" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" class="absolute -bottom-[450px] -right-[300px] size-[800px] rotate-32 text-cyan-400">
23
+ <path fill="currentColor" d="M42.9,-43.4C60.9,-36,84.8,-27.6,92.2,-12.2C99.8,3.1,91.2,25.4,76.1,37C61.1,48.5,39.7,49.3,21.9,52.7C4,56.1,-10.4,62,-26.6,61.1C-42.9,60.3,-61.1,52.9,-61.9,41C-62.6,28.8,-46,12.1,-42.2,-7C-38.4,-25.9,-47.4,-46.5,-42.5,-56.1C-37.6,-65.8,-18.8,-64.5,-3.2,-60.7C12.4,-57,24.9,-50.8,42.9,-43.4Z" transform="translate(100 100)" />
24
+ </svg>
25
+
26
+ <main class="grid place-items-center h-screen">
27
+ <div class="w-full max-w-xl">
28
+ <%%= link_to Config::Urls.site, class: "flex justify-center items-center size-6 mx-auto text-brand-500 rounded-full transition ease-in-out hover:text-brand-800 hover:bg-brand-50 hover:scale-105" do %>
29
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 256 256" fill="currentColor" class="size-5 shrink-0 fill-brand-400"><path d="M223.85,47.12a16,16,0,0,0-15-15c-12.58-.75-44.73.4-71.41,27.07L132.69,64H74.36A15.91,15.91,0,0,0,63,68.68L28.7,103a16,16,0,0,0,9.07,27.16l38.47,5.37,44.21,44.21,5.37,38.49a15.94,15.94,0,0,0,10.78,12.92,16.11,16.11,0,0,0,5.1.83A15.91,15.91,0,0,0,153,227.3L187.32,193A15.91,15.91,0,0,0,192,181.64V123.31l4.77-4.77C223.45,91.86,224.6,59.71,223.85,47.12ZM74.36,80h42.33L77.16,119.52,40,114.34Zm74.41-9.45a76.65,76.65,0,0,1,59.11-22.47,76.46,76.46,0,0,1-22.42,59.16L128,164.68,91.32,128ZM176,181.64,141.67,216l-5.19-37.17L176,139.31Zm-74.16,9.5C97.34,201,82.29,224,40,224a8,8,0,0,1-8-8c0-42.29,23-57.34,32.86-61.85a8,8,0,0,1,6.64,14.56c-6.43,2.93-20.62,12.36-23.12,38.91,26.55-2.5,36-16.69,38.91-23.12a8,8,0,1,1,14.56,6.64Z"/></svg>
30
+ <%% end %>
31
+
32
+ <div class="w-full mt-6 p-2 ring ring-gray-200/50 bg-white/50 backdrop-blur-md md:rounded-xl md:shadow-lg">
33
+ <section class="flex flex-col gap-y-5 bg-white ring-gray-200/60 md:ring md:rounded-md md:shadow-lg">
34
+ <%%= tag.h1 yield(:page_title), class: "mx-2 mt-8 font-sans text-center text-base font-bold text-gray-800 md:mx-4" %>
35
+
36
+ <%%= yield %>
37
+
38
+ <%%= tag.p yield(:alternative_action), class: "px-2 pt-4 pb-2 border-t border-gray-100 empty:hidden md:pb-4" %>
39
+ </section>
40
+ </div>
41
+ </div>
42
+ </main>
43
+
44
+ <%%= component "flash" %>
45
+ </body>
46
+ </html>
@@ -1,5 +1,5 @@
1
1
  module Stripe
2
- class Base < Fuik::Event
2
+ class Base < (defined?(Fuik::Event) ? Fuik::Event : Object)
3
3
  def self.verify!(request)
4
4
  secret = Rails.application.credentials.dig(:stripe, :signing_secret)
5
5
  signature = request.headers["Stripe-Signature"]
@@ -6,7 +6,7 @@ module Kern
6
6
  template "layouts/kern/application.html.erb.tt", "app/views/layouts/application.html.erb"
7
7
  copy_file "layouts/kern/application/_navigation.html.erb", "app/views/layouts/application/_navigation.html.erb"
8
8
 
9
- copy_file "layouts/kern/auth.html.erb", "app/views/layouts/auth.html.erb"
9
+ template "layouts/kern/auth.html.erb.tt", "app/views/layouts/auth.html.erb"
10
10
  end
11
11
  end
12
12
  end
data/lib/kern/engine.rb CHANGED
@@ -8,6 +8,10 @@ module Kern
8
8
  Kern::Config.load!
9
9
  end
10
10
 
11
+ config.to_prepare do
12
+ Kern::FormBuilder.load_styles
13
+ end
14
+
11
15
  initializer "kern.helpers" do
12
16
  ActiveSupport.on_load(:action_controller_base) do
13
17
  helper Kern::Engine.helpers
@@ -13,6 +13,7 @@ module Kern
13
13
  password: :password_field,
14
14
  url: :url_field,
15
15
  text: :text_area,
16
+ file: :file_field,
16
17
  integer: :number_field,
17
18
  float: :number_field,
18
19
  decimal: :number_field,
@@ -29,8 +30,8 @@ module Kern
29
30
 
30
31
  @template.safe_join([
31
32
  (if label_suffix
32
- @template.content_tag(:div, class: "flex items-center justify-between") do
33
- @template.safe_join([label_html, @template.content_tag(:span, label_suffix.html_safe, class: "text-xs font-medium text-gray-500")].compact)
33
+ @template.content_tag(:div, class: label_suffix_wrapper_css) do
34
+ @template.safe_join([label_html, @template.content_tag(:span, label_suffix.html_safe, class: label_suffix_css)].compact)
34
35
  end
35
36
  end),
36
37
 
@@ -38,7 +39,7 @@ module Kern
38
39
 
39
40
  input_field(attribute, options),
40
41
 
41
- (@template.content_tag(:p, hint.html_safe, class: "flex items-center gap-x-1 mt-0.5 px-0.5 text-xs font-light text-gray-500") if hint)
42
+ (@template.content_tag(:p, hint.html_safe, class: hint_css) if hint)
42
43
  ].compact)
43
44
  end
44
45
  end
@@ -48,13 +49,13 @@ module Kern
48
49
  label_options = options[:label] || {}
49
50
  field_errors = @object&.errors&.where(attribute)
50
51
 
51
- label_options[:class] = class_names("flex items-center gap-1 text-sm font-medium", {"text-gray-700": field_errors&.none?, "text-red-600": field_errors&.any?})
52
+ label_options[:class] = label_css(has_errors: field_errors&.any?)
52
53
  label_text = text || I18n.t("labels.#{attribute}", default: attribute.to_s.humanize)
53
54
 
54
55
  super(attribute, label_options) do
55
56
  safe_join([
56
57
  begin
57
- icon("warning-circle", class: "size-3.5 scale-100 transition ml-0 ease-in-out duration-300 starting:ml-3.5 starting:scale-0") if field_errors&.any?
58
+ icon("warning-circle", class: label_icon_css) if field_errors&.any?
58
59
  rescue
59
60
  nil
60
61
  end,
@@ -63,12 +64,8 @@ module Kern
63
64
  end
64
65
  end
65
66
 
66
- def toggle_wrapper(&block)
67
- content_tag(:div, yield, data: {slot: "toggle-field"}, class: "flex items-start gap-x-2 [&>input]:mt-[0.15em]")
68
- end
69
-
70
- def toggle_label(method, text)
71
- label(method, text.html_safe, class: toggle_label_css)
67
+ def toggle_label(id, text)
68
+ @template.label_tag(id, text.html_safe, class: toggle_label_css)
72
69
  end
73
70
 
74
71
  private
@@ -83,6 +80,7 @@ module Kern
83
80
  return :email if attribute.to_s.end_with?("email")
84
81
  return :password if attribute.to_s.include?("password")
85
82
  return :url if attribute.match?(/url|website|site/)
83
+ return :file if attribute.match?(/hero|image|avatar/)
86
84
  return :string unless valid?(attribute)
87
85
 
88
86
  @object.type_for_attribute(attribute.to_s).type
@@ -5,6 +5,41 @@ module Kern
5
5
  "w-full [&[data-slot='field']+[data-slot='field']]:mt-4"
6
6
  end
7
7
 
8
+ def label_css(has_errors: false)
9
+ base = <<~CSS
10
+ flex items-center gap-1 text-sm font-medium
11
+ CSS
12
+
13
+ class_names(base, has_errors ? "text-red-600" : "text-gray-700")
14
+ end
15
+
16
+ def label_icon_css
17
+ <<~CSS
18
+ size-3.5
19
+ scale-100 transition ml-0 ease-in-out duration-300
20
+ starting:ml-3.5 starting:scale-0
21
+ CSS
22
+ end
23
+
24
+ def label_suffix_wrapper_css
25
+ <<~CSS
26
+ flex items-center justify-between
27
+ CSS
28
+ end
29
+
30
+ def label_suffix_css
31
+ <<~CSS
32
+ text-xs font-medium text-gray-500
33
+ CSS
34
+ end
35
+
36
+ def hint_css
37
+ <<~CSS
38
+ flex items-center gap-x-1 mt-0.5 px-0.5
39
+ text-xs font-light text-gray-500
40
+ CSS
41
+ end
42
+
8
43
  def input_css
9
44
  <<~CSS
10
45
  w-full px-2.5 py-1.5
@@ -1,4 +1,3 @@
1
- require "kern/form_builder/styles"
2
1
  require "kern/form_builder/input"
3
2
 
4
3
  module Kern
@@ -6,7 +5,15 @@ module Kern
6
5
  include ActionView::Helpers::TagHelper
7
6
 
8
7
  include Input
9
- include Styles
8
+
9
+ def self.load_styles
10
+ if defined?(::FormBuilder::Styles)
11
+ include ::FormBuilder::Styles
12
+ else
13
+ require "kern/form_builder/styles"
14
+ include Styles
15
+ end
16
+ end
10
17
 
11
18
  %w[
12
19
  text_field email_field password_field
@@ -31,9 +38,10 @@ module Kern
31
38
  def check_box(method, options = {}, checked_value = "1", unchecked_value = "0", &block)
32
39
  field_classes(options, toggle_input_css)
33
40
  label_text = block ? @template.capture(&block) : method.to_s.humanize
41
+ custom_id = options[:id] || method
34
42
 
35
43
  toggle_wrapper do
36
- super(method, options, checked_value, unchecked_value) + label(method, label_text)
44
+ super(method, options, checked_value, unchecked_value) + label(custom_id, label_text)
37
45
  end
38
46
  end
39
47
  alias_method :checkbox, :check_box
@@ -41,9 +49,10 @@ module Kern
41
49
  def radio_button(method, tag_value, options = {}, &block)
42
50
  field_classes(options, toggle_input_css)
43
51
  label_text = block ? @template.capture(&block) : tag_value.to_s.humanize
52
+ custom_id = options[:id] || "#{method}_#{tag_value}"
44
53
 
45
54
  toggle_wrapper do
46
- super(method, tag_value, options) + toggle_label("#{method}_#{tag_value}", label_text)
55
+ super(method, tag_value, options) + toggle_label(custom_id, label_text)
47
56
  end
48
57
  end
49
58
 
@@ -97,5 +106,9 @@ module Kern
97
106
  options[:class] = options[:class].presence || class_names(base_css, *additional_classes, options[:additional_class])
98
107
  options.delete(:additional_class)
99
108
  end
109
+
110
+ def toggle_wrapper(&block)
111
+ content_tag(:div, yield, data: {slot: "field"}, class: "flex items-start gap-x-2 [&>input]:mt-[0.17em]")
112
+ end
100
113
  end
101
114
  end
data/lib/kern/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Kern
2
- VERSION = "0.7.0"
2
+ VERSION = "0.8.0"
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: kern
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.7.0
4
+ version: 0.8.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Rails Designer
@@ -38,6 +38,7 @@ files:
38
38
  - app/assets/builds/tailwind.kern.css
39
39
  - app/controllers/concerns/authentication.rb
40
40
  - app/controllers/concerns/authentication.rb.tt
41
+ - app/controllers/concerns/layouts.rb
41
42
  - app/controllers/kern/application_controller.rb
42
43
  - app/controllers/kern/billing_profiles/subscriptions_controller.rb
43
44
  - app/controllers/kern/billing_profiles/subscriptions_controller.rb.tt
@@ -77,6 +78,7 @@ files:
77
78
  - app/views/components/_dialog.html.erb
78
79
  - app/views/components/_flash.html.erb
79
80
  - app/views/components/_heading.html.erb
81
+ - app/views/components/_section.html.erb
80
82
  - app/views/components/flash/_message.html.erb
81
83
  - app/views/kern/pages/welcome.html.erb
82
84
  - app/views/kern/passwords/edit.html.erb
@@ -96,6 +98,7 @@ files:
96
98
  - app/views/layouts/kern/application.html.erb.tt
97
99
  - app/views/layouts/kern/application/_navigation.html.erb
98
100
  - app/views/layouts/kern/auth.html.erb
101
+ - app/views/layouts/kern/auth.html.erb.tt
99
102
  - app/webhooks/stripe/base.rb
100
103
  - app/webhooks/stripe/checkout_session_completed.rb
101
104
  - app/webhooks/stripe/customer_subscription_deleted.rb
@@ -155,7 +158,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
155
158
  - !ruby/object:Gem::Version
156
159
  version: '0'
157
160
  requirements: []
158
- rubygems_version: 3.6.9
161
+ rubygems_version: 4.0.3
159
162
  specification_version: 4
160
163
  summary: Rails engine with auth, billing, and common components for SaaS apps
161
164
  test_files: []