b4um_generators 0.1.1 → 0.2.8

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.
@@ -417,12 +417,20 @@
417
417
 
418
418
  .form-field--rich-text {
419
419
  display: grid;
420
- grid-template-columns: 1fr;
420
+ grid-template-columns: minmax(0, 1fr);
421
+
422
+ width: 100%;
423
+ min-width: 0;
424
+ max-width: 100%;
421
425
  }
422
426
 
423
427
  .form-field--rich-text trix-toolbar {
424
428
  grid-row: 1;
425
429
 
430
+ width: 100%;
431
+ min-width: 0;
432
+ max-width: 100%;
433
+
426
434
  position: sticky;
427
435
  top: 61px;
428
436
  z-index: 10;
@@ -496,6 +504,15 @@
496
504
  color: var(--b4um-text);
497
505
  }
498
506
 
507
+ .form-field--rich-text .form-textarea,
508
+ .form-field--rich-text trix-editor {
509
+ width: 100%;
510
+ min-width: 0;
511
+ max-width: 100%;
512
+
513
+ box-sizing: border-box;
514
+ }
515
+
499
516
  .form-field--rich-text .form-textarea {
500
517
  grid-row: 2;
501
518
  }
@@ -686,6 +703,18 @@
686
703
  border-radius: var(--b4um-radius);
687
704
  }
688
705
 
706
+ /* -------------------------------------------------------
707
+ Rich Text Attachments – responsive
708
+ ------------------------------------------------------- */
709
+
710
+ @media (max-width: 700px) {
711
+ .trix-content .attachment-gallery,
712
+ .trix-content .attachment-gallery--2,
713
+ .trix-content .attachment-gallery--4 {
714
+ grid-template-columns: 1fr;
715
+ }
716
+ }
717
+
689
718
  .trix-content action-text-attachment[content-type='vnd.rubyonrails.horizontal-rule.html'] {
690
719
  display: block;
691
720
  width: 100%;
@@ -922,3 +951,134 @@
922
951
 
923
952
  opacity: 1;
924
953
  }
954
+ /* -------------------------------------------------------
955
+ Responsive Rich Text
956
+ ------------------------------------------------------- */
957
+
958
+ @media (max-width: 640px) {
959
+ .form-field--rich-text trix-toolbar {
960
+ overflow: visible;
961
+ }
962
+
963
+ /*
964
+ * Nur die Button-Zeile scrollt horizontal.
965
+ * Die Dialoge liegen außerhalb dieses Scrollcontainers
966
+ * und können deshalb vollständig sichtbar werden.
967
+ */
968
+ .form-field--rich-text trix-toolbar .trix-button-row {
969
+ display: flex;
970
+ flex-wrap: nowrap;
971
+ align-items: center;
972
+ justify-content: flex-start;
973
+
974
+ width: 100%;
975
+ max-width: 100%;
976
+
977
+ gap: 4px;
978
+
979
+ overflow-x: auto;
980
+ overflow-y: hidden;
981
+
982
+ -webkit-overflow-scrolling: touch;
983
+ scrollbar-width: none;
984
+ }
985
+
986
+ .form-field--rich-text trix-toolbar .trix-button-row::-webkit-scrollbar {
987
+ display: none;
988
+ }
989
+
990
+ .form-field--rich-text trix-toolbar .trix-button-group {
991
+ flex: 0 0 auto;
992
+
993
+ margin: 0;
994
+ }
995
+
996
+ .form-field--rich-text trix-toolbar .trix-button {
997
+ flex: 0 0 auto;
998
+
999
+ margin: 0;
1000
+ }
1001
+
1002
+ /*
1003
+ * Trix-Dialoge gehören NICHT zum horizontalen
1004
+ * Scrollbereich der Buttons.
1005
+ */
1006
+ .form-field--rich-text trix-toolbar .trix-dialogs {
1007
+ position: relative;
1008
+
1009
+ width: 100%;
1010
+
1011
+ overflow: visible;
1012
+ }
1013
+
1014
+ .form-field--rich-text trix-toolbar .trix-dialog {
1015
+ left: 0;
1016
+ right: auto;
1017
+
1018
+ max-width: 100%;
1019
+
1020
+ box-sizing: border-box;
1021
+ }
1022
+
1023
+ /*
1024
+ * Link-Dialog nutzt auf kleinen Displays
1025
+ * die komplette verfügbare Toolbarbreite.
1026
+ */
1027
+ .form-field--rich-text trix-toolbar .trix-dialog--link {
1028
+ width: 100%;
1029
+ }
1030
+
1031
+ /*
1032
+ * H1–H6 bleiben kompakt nebeneinander.
1033
+ */
1034
+ .form-field--rich-text trix-toolbar .trix-dialog--heading {
1035
+ width: max-content;
1036
+ max-width: 100%;
1037
+
1038
+ margin-left: 0;
1039
+ }
1040
+
1041
+ .form-field--rich-text trix-toolbar .trix-dialog--heading .trix-dialog__link-fields {
1042
+ width: auto;
1043
+ }
1044
+
1045
+ .form-field--rich-text trix-toolbar .trix-dialog--heading .trix-button-group {
1046
+ display: flex;
1047
+ flex-wrap: nowrap;
1048
+
1049
+ width: auto;
1050
+ margin: 0;
1051
+ }
1052
+
1053
+ /*
1054
+ * Farbpalette ebenfalls vollständig innerhalb
1055
+ * der verfügbaren Breite darstellen.
1056
+ */
1057
+ .form-field--rich-text trix-toolbar .trix-dialog--color {
1058
+ width: max-content;
1059
+ max-width: 100%;
1060
+ }
1061
+
1062
+ .form-field--rich-text trix-editor .attachment-gallery,
1063
+ .form-field--rich-text trix-editor .attachment-gallery--2,
1064
+ .form-field--rich-text trix-editor .attachment-gallery--4 {
1065
+ grid-template-columns: 1fr;
1066
+ }
1067
+ }
1068
+
1069
+ .form-field--rich-text trix-toolbar .trix-button--icon {
1070
+ height: 1.98em;
1071
+ }
1072
+
1073
+ .form-field--rich-text trix-toolbar .trix-button-group--container-tools .trix-button {
1074
+ height: 2.6em;
1075
+ display: inline-flex;
1076
+ align-items: center;
1077
+ justify-content: center;
1078
+ }
1079
+
1080
+ @media (max-width: 768px) {
1081
+ trix-toolbar .trix-button--icon {
1082
+ height: 2em;
1083
+ }
1084
+ }
@@ -48,15 +48,28 @@
48
48
  .navigation__link {
49
49
  position: relative;
50
50
  padding: 0.5rem 0;
51
+
52
+ border: 0;
53
+ background: transparent;
54
+
51
55
  color: var(--b4um-text);
56
+ font: inherit;
52
57
  font-weight: 500;
53
58
  text-decoration: none;
59
+
60
+ cursor: pointer;
61
+
54
62
  transition:
55
63
  color 0.18s ease,
56
64
  background-color 0.18s ease,
57
65
  transform 0.18s ease;
58
66
  }
59
67
 
68
+ .navigation__form {
69
+ margin: 0;
70
+ padding: 0;
71
+ }
72
+
60
73
  .navigation__link:visited {
61
74
  color: var(--b4um-text);
62
75
  }
@@ -119,3 +119,21 @@
119
119
  .resource-list-item:last-child {
120
120
  border-bottom: none;
121
121
  }
122
+
123
+ /* -------------------------------------------------------
124
+ Responsive resource details
125
+ ------------------------------------------------------- */
126
+
127
+ @media (max-width: 768px) {
128
+ .resource-field {
129
+ grid-template-columns: minmax(0, 1fr);
130
+ row-gap: 0.5rem;
131
+ column-gap: 0;
132
+ }
133
+
134
+ .resource-label,
135
+ .resource-value {
136
+ min-width: 0;
137
+ width: 100%;
138
+ }
139
+ }
@@ -1,3 +1,16 @@
1
+ /*
2
+ * B4UM stylesheet imports
3
+ *
4
+ * Rails 8 loads all stylesheets in app/assets/stylesheets automatically
5
+ * when using:
6
+ *
7
+ * <%= stylesheet_link_tag :app, "data-turbo-track": "reload" %>
8
+ *
9
+ * Therefore these imports are disabled by default.
10
+ * Uncomment them if your application's asset setup requires explicit imports.
11
+ */
12
+
13
+ /*
1
14
  @import 'b4um/theme.css';
2
15
  @import 'b4um/base.css';
3
16
  @import 'b4um/layout.css';
@@ -18,3 +31,4 @@
18
31
  @import 'b4um/footer.css';
19
32
  @import 'b4um/cookie-consent.css';
20
33
  @import 'b4um/theme-switcher.css';
34
+ */
@@ -23,4 +23,17 @@ module NavigationHelper
23
23
  data: { action: "click->navigation#close" }
24
24
  )
25
25
  end
26
+
27
+ def navigation_button_to(name, path, method:)
28
+ button_to(
29
+ name,
30
+ path,
31
+ method: method,
32
+ class: "navigation__link",
33
+ form: {
34
+ class: "navigation__form",
35
+ data: { action: "click->navigation#close" }
36
+ }
37
+ )
38
+ end
26
39
  end
@@ -0,0 +1,77 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "rails/generators"
4
+ require "rails/generators/named_base"
5
+
6
+ module B4um
7
+ module Generators
8
+ class ReadableGenerator < Rails::Generators::NamedBase
9
+ argument :attribute,
10
+ type: :string,
11
+ required: true,
12
+ banner: "ATTRIBUTE"
13
+
14
+ class << self
15
+ def desc(_description = nil)
16
+ "Adds a readable URL parameter to an existing model."
17
+ end
18
+ end
19
+
20
+ def validate_model
21
+ return if File.exist?(model_path)
22
+
23
+ raise Thor::Error,
24
+ "Model not found: app/models/#{file_name}.rb"
25
+ end
26
+
27
+ def validate_attribute
28
+ return if model_class.column_names.include?(attribute)
29
+
30
+ raise Thor::Error,
31
+ "Attribute not found: #{class_name}##{attribute}"
32
+ end
33
+
34
+ def add_readable_param
35
+ model_content = File.read(model_path)
36
+
37
+ if model_content.match?(/^\s*def\s+to_param\b/)
38
+ raise Thor::Error,
39
+ "#{class_name} already defines to_param."
40
+ end
41
+
42
+ inject_into_class(
43
+ model_path,
44
+ class_name,
45
+ <<~RUBY
46
+ def to_param
47
+ "\#{id} \#{#{attribute}}".parameterize
48
+ end
49
+ RUBY
50
+ )
51
+
52
+ say_status(
53
+ :readable,
54
+ "#{class_name} URLs now use #{attribute}",
55
+ :green
56
+ )
57
+ end
58
+
59
+ private
60
+
61
+ def model_path
62
+ File.join(
63
+ destination_root,
64
+ "app/models",
65
+ "#{file_name}.rb"
66
+ )
67
+ end
68
+
69
+ def model_class
70
+ class_name.constantize
71
+ rescue NameError
72
+ raise Thor::Error,
73
+ "Could not load model: #{class_name}"
74
+ end
75
+ end
76
+ end
77
+ end
@@ -137,6 +137,64 @@ module B4um
137
137
  )
138
138
  end
139
139
 
140
+ def update_empty_state
141
+ view_file = File.join(
142
+ destination_root,
143
+ index_view_path
144
+ )
145
+
146
+ view_content = File.read(view_file)
147
+
148
+ return if view_content.include?(
149
+ "<% if params[:q].present? %>"
150
+ )
151
+
152
+ title = file_name.pluralize.humanize.downcase
153
+ singular = file_name.humanize.downcase
154
+
155
+ empty_state_pattern = %r{
156
+ (?<indent>[ \t]*)
157
+ <section\ class="b4um-empty-state">\s*
158
+ <h2\ class="b4um-empty-state__title">\s*
159
+ No\ #{Regexp.escape(title)}\ yet\.\s*
160
+ </h2>\s*
161
+ <p\ class="b4um-empty-state__text">\s*
162
+ Create\ your\ first\ #{Regexp.escape(singular)}\ to\ get\ started\.\s*
163
+ </p>\s*
164
+ </section>
165
+ }x
166
+
167
+ return unless view_content.match?(empty_state_pattern)
168
+
169
+ new_empty_state = <<~ERB.chomp
170
+ <section class="b4um-empty-state">
171
+ <% if params[:q].present? %>
172
+ <h2 class="b4um-empty-state__title">
173
+ No #{title} found.
174
+ </h2>
175
+
176
+ <p class="b4um-empty-state__text">
177
+ Try a different search term.
178
+ </p>
179
+ <% else %>
180
+ <h2 class="b4um-empty-state__title">
181
+ No #{title} yet.
182
+ </h2>
183
+
184
+ <p class="b4um-empty-state__text">
185
+ Create your first #{singular} to get started.
186
+ </p>
187
+ <% end %>
188
+ </section>
189
+ ERB
190
+
191
+ gsub_file(
192
+ index_view_path,
193
+ empty_state_pattern,
194
+ new_empty_state
195
+ )
196
+ end
197
+
140
198
  private
141
199
 
142
200
  def model_path
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: b4um_generators
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.2.8
5
5
  platform: ruby
6
6
  authors:
7
7
  - Alexander Baum
8
8
  bindir: exe
9
9
  cert_chain: []
10
- date: 2026-09-26 00:00:00.000000000 Z
10
+ date: 2026-09-28 00:00:00.000000000 Z
11
11
  dependencies:
12
12
  - !ruby/object:Gem::Dependency
13
13
  name: railties
@@ -49,6 +49,10 @@ files:
49
49
  - bin/setup
50
50
  - lib/b4um_generators.rb
51
51
  - lib/b4um_generators/version.rb
52
+ - lib/generators/b4um/attachment/attachment_generator.rb
53
+ - lib/generators/b4um/authentication/authentication_generator.rb
54
+ - lib/generators/b4um/authentication/templates/new.html.erb.tt
55
+ - lib/generators/b4um/authentication/templates/sessions_controller.rb.tt
52
56
  - lib/generators/b4um/bento/bento_generator.rb
53
57
  - lib/generators/b4um/bento/templates/_alternating.html.erb.tt
54
58
  - lib/generators/b4um/bento/templates/_bento.html.erb.tt
@@ -104,6 +108,7 @@ files:
104
108
  - lib/generators/b4um/pagination/pagination_generator.rb
105
109
  - lib/generators/b4um/pagination/templates/_pagination.html.erb.tt
106
110
  - lib/generators/b4um/pagination/templates/pagination.rb
111
+ - lib/generators/b4um/readable/readable_generator.rb
107
112
  - lib/generators/b4um/scaffold/scaffold_generator.rb
108
113
  - lib/generators/b4um/scaffold/templates/_bento.html.erb.tt
109
114
  - lib/generators/b4um/scaffold/templates/_form.html.erb.tt