breeze_cms 0.9.5 → 0.9.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (43) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +8 -13
  3. data/app/assets/images/breeze/breeze_logo.png +0 -0
  4. data/app/assets/images/breeze/home.jpg +0 -0
  5. data/app/assets/stylesheets/breeze/breeze.css +25 -18
  6. data/app/assets/stylesheets/breeze/breeze.email.css +0 -22
  7. data/app/controllers/breeze/translations_controller.rb +6 -3
  8. data/app/controllers/breeze/view_controller.rb +2 -0
  9. data/app/helpers/breeze/breeze_helper.rb +1 -1
  10. data/app/helpers/breeze/options_helper.rb +7 -0
  11. data/app/helpers/breeze/view_helper.rb +9 -2
  12. data/app/models/breeze/card.rb +4 -6
  13. data/app/models/breeze/section.rb +0 -6
  14. data/app/models/breeze/translation.rb +76 -60
  15. data/app/models/breeze/view_base.rb +1 -21
  16. data/app/views/breeze/changes/index.haml +2 -2
  17. data/app/views/breeze/styles/index.haml +2 -6
  18. data/app/views/breeze/translations/_row.haml +11 -18
  19. data/app/views/breeze/translations/show.haml +34 -14
  20. data/app/views/breeze/view/_form_section.haml +6 -2
  21. data/app/views/breeze/view/_section_cards.haml +0 -3
  22. data/app/views/breeze/view/_section_full_up.haml +0 -3
  23. data/app/views/breeze/view/_section_half_image.haml +0 -3
  24. data/app/views/breeze/view/_section_large_image.haml +0 -3
  25. data/app/views/breeze/view/_section_slider.haml +0 -3
  26. data/app/views/breeze/view/_section_small_image.haml +0 -3
  27. data/app/views/breeze/view/_section_spacer.haml +2 -1
  28. data/app/views/breeze/view/_section_text.haml +0 -3
  29. data/app/views/breeze/view/cards/_card_gap_square.haml +0 -2
  30. data/app/views/breeze/view/cards/_card_normal_round.haml +1 -1
  31. data/app/views/breeze/view/cards/_card_normal_square.haml +0 -2
  32. data/app/views/breeze/view/cards/_card_wide_square.haml +0 -2
  33. data/app/views/layouts/_plausible.haml +38 -0
  34. data/config/breeze/card_styles.yml +2 -6
  35. data/config/breeze/option_definitions.yml +5 -5
  36. data/config/breeze/section_styles.yml +4 -8
  37. data/config/locales/breeze_en.yml +3 -0
  38. data/config/routes.rb +2 -1
  39. data/config/tailwind.config.js +1 -0
  40. data/lib/breeze/engine.rb +1 -1
  41. data/lib/breeze/version.rb +1 -1
  42. data/lib/breeze_cms.rb +3 -0
  43. metadata +22 -5
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f646a90e3dbdb8190f71e362c939f2f03b994a762e0299b7114d34145895b6ee
4
- data.tar.gz: 983233a8a60d560dafd3cc04ada3dfda851d52d4cd1b55a58e3e2941185cc9be
3
+ metadata.gz: 67734e6d1c8022a40abd64558f959d817527f34c67580899c85c40aa113c22ba
4
+ data.tar.gz: e4eaea667b42541e13e80dba9042579eec0def4ff796ba7cd27e60903b65d570
5
5
  SHA512:
6
- metadata.gz: 769fe59c952a682a0706611024b440160ab0381cc5e172991f89fd38c049ae139485ef35d0f4885f42f002fbaec05519cce8fff5db253b6f1449c040f6329e1d
7
- data.tar.gz: 3f1e414a8c90510ad4cf8447414a03d6f7eff1d261224ae73387ba24626e7b868ebaa9a870885b5a295ebca77165f8d4b99fa2e766de5c5077d2a9d56e330193
6
+ metadata.gz: 1049c6a06a1813e2473144b8ef1c400ab7f23ecb5a0e9f15b0ab0f2e9fc9ce6152ce4288f0e73b6c57214e236739aba4f905da900157026b86d8da35622ef660
7
+ data.tar.gz: d892c28e6a490cc8e0e21352bd41510a57a04b411a9a1d12a1dc459a3eca408878582c8b64351c76eb9953aaeac9c481163328e80fdb0e475f1f70d902e3757a
data/README.md CHANGED
@@ -1,24 +1,19 @@
1
- # Breeze
1
+ # Breeze CMS
2
2
 
3
- A CMS that integrates into the rails workflow. Ie it is file based
4
- not db based.
3
+ Breeze, the tailwind based, developers CMS
5
4
 
6
- Changes propagate in the normal development cycle, with git, possible
7
- branches, possible staging, possible reviews and controlled deploys.
5
+ Breeze renders pages, that are made up of sections, that may include cards.
6
+ Breeze also manages images, even lets you edit them, and manages translations when you go international.
7
+
8
+ All data is stored in yaml files, images as assets. Breeze makes commits for changes which developers upstream in a very rails sort of way.
8
9
 
9
10
  ## Usage
10
11
 
11
12
  Breeze is designed for developers to give limited editing facilities
12
13
  to users. As with rails, there is great flexibility how this can be
13
- achieved, see wiki for more details.
14
-
15
- ## Installation
16
-
17
- And more info see the wiki
18
-
19
- ## Contributing
14
+ achieved, see homepage for more details.
20
15
 
21
- Ask first.
16
+ [breeze.codeberg.page](https://breeze.codeberg.page/)
22
17
 
23
18
  ## License
24
19
  The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
Binary file
@@ -1360,6 +1360,10 @@ select {
1360
1360
  border-width: 0;
1361
1361
  }
1362
1362
 
1363
+ .visible {
1364
+ visibility: visible;
1365
+ }
1366
+
1363
1367
  .fixed {
1364
1368
  position: fixed;
1365
1369
  }
@@ -1712,6 +1716,10 @@ select {
1712
1716
  height: 0.75rem;
1713
1717
  }
1714
1718
 
1719
+ .h-32 {
1720
+ height: 8rem;
1721
+ }
1722
+
1715
1723
  .h-4 {
1716
1724
  height: 1rem;
1717
1725
  }
@@ -1720,6 +1728,10 @@ select {
1720
1728
  height: 10rem;
1721
1729
  }
1722
1730
 
1731
+ .h-48 {
1732
+ height: 12rem;
1733
+ }
1734
+
1723
1735
  .h-56 {
1724
1736
  height: 14rem;
1725
1737
  }
@@ -1732,6 +1744,10 @@ select {
1732
1744
  height: 15rem;
1733
1745
  }
1734
1746
 
1747
+ .h-64 {
1748
+ height: 16rem;
1749
+ }
1750
+
1735
1751
  .h-72 {
1736
1752
  height: 18rem;
1737
1753
  }
@@ -2399,6 +2415,10 @@ select {
2399
2415
  object-fit: cover;
2400
2416
  }
2401
2417
 
2418
+ .p-1 {
2419
+ padding: 0.25rem;
2420
+ }
2421
+
2402
2422
  .p-2 {
2403
2423
  padding: 0.5rem;
2404
2424
  }
@@ -2510,10 +2530,6 @@ select {
2510
2530
  padding-bottom: 1rem;
2511
2531
  }
2512
2532
 
2513
- .pb-6 {
2514
- padding-bottom: 1.5rem;
2515
- }
2516
-
2517
2533
  .pr-12 {
2518
2534
  padding-right: 3rem;
2519
2535
  }
@@ -2744,6 +2760,11 @@ select {
2744
2760
  box-shadow: var(--tw-ring-offset-shadow, 0 0 #0000), var(--tw-ring-shadow, 0 0 #0000), var(--tw-shadow);
2745
2761
  }
2746
2762
 
2763
+ .invert {
2764
+ --tw-invert: invert(100%);
2765
+ filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow);
2766
+ }
2767
+
2747
2768
  .filter {
2748
2769
  filter: var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow);
2749
2770
  }
@@ -3379,11 +3400,6 @@ select {
3379
3400
  text-align: center;
3380
3401
  }
3381
3402
 
3382
- .sm\:text-2xl {
3383
- font-size: 1.5rem;
3384
- line-height: 2rem;
3385
- }
3386
-
3387
3403
  .sm\:text-4xl {
3388
3404
  font-size: 2.25rem;
3389
3405
  line-height: 2.5rem;
@@ -3468,11 +3484,6 @@ select {
3468
3484
  padding-bottom: 2.5rem;
3469
3485
  }
3470
3486
 
3471
- .md\:text-2xl {
3472
- font-size: 1.5rem;
3473
- line-height: 2rem;
3474
- }
3475
-
3476
3487
  .md\:text-4xl {
3477
3488
  font-size: 2.25rem;
3478
3489
  line-height: 2.5rem;
@@ -3515,10 +3526,6 @@ select {
3515
3526
  margin-top: 0px;
3516
3527
  }
3517
3528
 
3518
- .lg\:mt-8 {
3519
- margin-top: 2rem;
3520
- }
3521
-
3522
3529
  .lg\:h-96 {
3523
3530
  height: 24rem;
3524
3531
  }
@@ -350,10 +350,6 @@
350
350
  height: 5rem;
351
351
  }
352
352
 
353
- .h-24 {
354
- height: 6rem;
355
- }
356
-
357
353
  .h-40 {
358
354
  height: 10rem;
359
355
  }
@@ -758,10 +754,6 @@
758
754
  padding-bottom: 1rem;
759
755
  }
760
756
 
761
- .pb-6 {
762
- padding-bottom: 1.5rem;
763
- }
764
-
765
757
  .pr-16 {
766
758
  padding-right: 4rem;
767
759
  }
@@ -1104,11 +1096,6 @@
1104
1096
  text-align: center;
1105
1097
  }
1106
1098
 
1107
- .sm\:text-2xl {
1108
- font-size: 1.5rem;
1109
- line-height: 2rem;
1110
- }
1111
-
1112
1099
  .sm\:text-4xl {
1113
1100
  font-size: 2.25rem;
1114
1101
  line-height: 2.5rem;
@@ -1188,11 +1175,6 @@
1188
1175
  padding-bottom: 2.5rem;
1189
1176
  }
1190
1177
 
1191
- .md\:text-2xl {
1192
- font-size: 1.5rem;
1193
- line-height: 2rem;
1194
- }
1195
-
1196
1178
  .md\:text-4xl {
1197
1179
  font-size: 2.25rem;
1198
1180
  line-height: 2.5rem;
@@ -1235,10 +1217,6 @@
1235
1217
  margin-top: 0px;
1236
1218
  }
1237
1219
 
1238
- .lg\:mt-8 {
1239
- margin-top: 2rem;
1240
- }
1241
-
1242
1220
  .lg\:h-96 {
1243
1221
  height: 24rem;
1244
1222
  }
@@ -30,8 +30,11 @@ module Breeze
30
30
  # PATCH/PUT /translations/1
31
31
  def update
32
32
  respond_to do |format|
33
- @translation.update(params[:translation] , "user")
34
- format.html { redirect_to(@translation, :notice => 'User was successfully updated.') }
33
+ @translation.update(translation_params , current_member_email )
34
+ format.html {
35
+ redirect_to(translation_path(@translation.object.page.id),
36
+ :notice => 'Translation was successfully updated.')
37
+ }
35
38
  format.json { render status: 200, json: {} }
36
39
  end
37
40
  end
@@ -45,7 +48,7 @@ module Breeze
45
48
  private
46
49
  # Use callbacks to share common setup or constraints between actions.
47
50
  def set_translation
48
- @translation = Translation.find(params[:id])
51
+ @translation = Translation.find(params[:id] || params[:translation_id])
49
52
  end
50
53
 
51
54
  # Only allow a list of trusted parameters through.
@@ -2,6 +2,8 @@ module Breeze
2
2
  class ViewController < ::ApplicationController
3
3
 
4
4
  def page
5
+ locale = params[:lang] || I18n.default_locale
6
+ I18n.locale = locale
5
7
  @page = Page.find_by_name(params[:id])
6
8
  redirect_to "/" , alert: "No page #{params[:id]}" unless @page
7
9
  end
@@ -26,7 +26,7 @@ module Breeze
26
26
  last = ChangeSet.current.last
27
27
  return 10 unless last
28
28
  last = (Time.now - last).to_i
29
- return 10 if ( last >= 600 )
29
+ return 9 if ( last >= 600 )
30
30
  digit = last / 60
31
31
  digit
32
32
  end
@@ -115,6 +115,13 @@ module Breeze
115
115
  {class: clazz }
116
116
  end
117
117
 
118
+ def height_option( section , clazz = "" )
119
+ if section.has_option?("height")
120
+ clazz += " " + (section.option("height") || "")
121
+ end
122
+ {class: clazz }
123
+ end
124
+
118
125
 
119
126
  end
120
127
  end
@@ -38,6 +38,12 @@ module Breeze
38
38
  "inline-block rounded-lg px-3 py-2 text-base font-medium border border-gray-500 hover:border-black"
39
39
  end
40
40
 
41
+ def get_button_text(element)
42
+ text = element.option("button_text")
43
+ return text unless text.include?("_")
44
+ I18n.t( text )
45
+ end
46
+
41
47
  def view_button(element , extra_classes = "")
42
48
  return "" unless element.has_option?("button_link")
43
49
  ["<button class='#{button_classes} ",
@@ -46,7 +52,7 @@ module Breeze
46
52
  "<a href='" ,
47
53
  element.option("button_link") ,
48
54
  "'>" ,
49
- element.option("button_text") ,
55
+ get_button_text(element) ,
50
56
  "</a>",
51
57
  " </button>"].join.html_safe
52
58
  end
@@ -57,8 +63,9 @@ module Breeze
57
63
  return nil unless blog
58
64
  blog.sections.last
59
65
  end
66
+
60
67
  def last_blog
61
- PagesHelper.last_blog
68
+ ViewHelper.last_blog
62
69
  end
63
70
 
64
71
  def header_list
@@ -20,6 +20,10 @@ module Breeze
20
20
  sum
21
21
  end
22
22
 
23
+ def page
24
+ section.page
25
+ end
26
+
23
27
  def move_up
24
28
  swap_index_with(previous_card)
25
29
  end
@@ -65,7 +69,6 @@ module Breeze
65
69
  end
66
70
 
67
71
  def delete(editor)
68
- delete_translations(editor)
69
72
  delete_save!(editor)
70
73
  end
71
74
 
@@ -81,10 +84,5 @@ module Breeze
81
84
  card
82
85
  end
83
86
 
84
- def self.reload
85
- res = super()
86
- self.fix_translations
87
- end
88
-
89
87
  end
90
88
  end
@@ -93,7 +93,6 @@ module Breeze
93
93
 
94
94
  def delete(editor)
95
95
  cards.each {|card| card.delete(editor) }
96
- delete_translations(editor)
97
96
  delete_save!(editor)
98
97
  end
99
98
 
@@ -128,10 +127,5 @@ module Breeze
128
127
  nil
129
128
  end
130
129
 
131
- def self.reload
132
- res = super()
133
- self.fix_translations
134
- end
135
-
136
130
  end
137
131
  end
@@ -1,83 +1,99 @@
1
1
  module Breeze
2
- class Translation < ActiveBase
2
+ # gives a handle on the translations
3
+ #
4
+ # actual translations are stored in the object (section/card)
5
+ # but dealing with hashes of hashes quickly gets unwieldy, hence this class
6
+ #
7
+ # Strings are written lasily into the object, ie no translation, no text
3
8
 
4
- set_root_path Rails.root.join(Breeze.data_dir)
9
+ class Translation
5
10
 
6
- fields :id
7
- fields :objectid , :object_type # poly: card or section (id without _, no association)
8
- fields :language # the language for which the is a translation
9
- fields :text , :header, :sub_header #actual text fields
11
+ # fields :objectid , :object_type # poly: card or section (id without _, no association)
12
+ # fields :language # the language for which the is a translation
13
+ # fields :text , :header, :sub_header #actual text fields
10
14
 
11
- def initialize(data)
12
- super(data)
13
- raise "no object type" unless self.object_type
14
- raise "no object id" unless lang = self.objectid
15
- raise "no language" unless lang = self.language
16
- raise "not configured language #{lang}" unless Breeze.has_language(lang)
15
+ attr :object , :language
16
+
17
+ def initialize(object , language)
18
+ @object = object
19
+ @language = language
20
+ raise "no object type" unless object.object_type
21
+ raise "not configured language #{language}" unless Breeze.has_language(language)
17
22
  end
18
23
 
19
- def object
20
- clazz = "Breeze::#{object_type}".constantize
21
- clazz.find( objectid )
24
+ def id
25
+ "#{object.object_type}-#{language}-#{object.id}"
22
26
  end
23
27
 
24
- def is_old?
25
- return true unless self.updated_at
26
- object.updated_at > self.updated_at
28
+ def text
29
+ t = get_text
30
+ return t unless t.blank?
31
+ return object.text
27
32
  end
28
33
 
29
- def change_name
30
- "Translation: #{object.change_name}"
34
+ def header
35
+ t = get_header
36
+ return t unless t.blank?
37
+ return object.header
31
38
  end
32
39
 
33
- def update(hash , user)
34
- return unless hash
35
- [:text , :header ].each do |key|
36
- data[key] = hash[key] if hash.has_key?(key)
37
- end
38
- add_save(user)
40
+ def get_text
41
+ return "" unless data = object.data[language]
42
+ data[:text] || ""
39
43
  end
40
44
 
41
- class << self
45
+ def set_text(text)
46
+ object.data[language] = {} unless object.data[language]
47
+ object.data[language][:updated_at] = Time.now
48
+ object.data[language][:text] = text
49
+ end
42
50
 
43
- def fill_data(object, data = {})
44
- data[:text] = object.text
45
- data[:header] = object.header
46
- data[:objectid] = object.id
47
- data[:object_type] = object.object_type
48
- data
49
- end
51
+ def get_header
52
+ return "" unless data = object.data[language]
53
+ data[:header] || ""
54
+ end
50
55
 
51
- def find_translation(objectid , object_type, language)
52
- find_all(:objectid, objectid).each do |o|
53
- return o if (objectid == o.objectid ) &&
54
- (object_type == o.object_type) &&
55
- (language == o.language)
56
- end
57
- nil
58
- end
56
+ def set_header(header)
57
+ object.data[language] = {} unless object.data[language]
58
+ object.data[language][:updated_at] = Time.now
59
+ object.data[language][:header] = header
60
+ end
59
61
 
60
- def ensure_translation(object , language)
61
- found = self.find_translation(object.id , object.object_type , language)
62
- return nil if found
63
- data = fill_data(object)
64
- data[:updated_at] = object.updated_at - 1.day
65
- data[:language] = language
66
- data[:id] = "#{object.object_type}_#{object.id}"
67
- data
68
- end
62
+ def is_old?
63
+ return false if(text.blank? and header.blank?)
64
+ return true unless self.updated_at
65
+ object.updated_at > self.updated_at
66
+ end
69
67
 
70
- def new_object_translation(object, data)
71
- self.fill_data(object,data)
72
- self.new_translation(data)
73
- end
68
+ def updated_at
69
+ return nil unless object.data[language]
70
+ object.data[language][:updated_at]
71
+ end
74
72
 
75
- # append data and create new object.
76
- def new_translation( data )
77
- new_id = Translation.append(data)
78
- Translation.new(data)
79
- end
73
+ def update(hash , editor)
74
+ return unless hash
75
+ set_text(hash[:text]) if hash.has_key?(:text)
76
+ set_header(hash[:header]) if hash.has_key?(:header)
77
+ object.data[language][:updated_by] = editor
78
+ object.data[language][:updated_at] = Time.now
80
79
 
80
+ ChangeSet.current.add(self.class.name , "#{language}:#{object.change_name}", editor)
81
+ object.class.save_all
82
+ end
83
+
84
+ # find according to id, ie class_num
85
+ def self.find(id)
86
+ clazz , lang , num = id.split("-")
87
+ num = num.to_i
88
+ case clazz
89
+ when "Section"
90
+ object = Section.find(num)
91
+ when "Card"
92
+ object = Card.find( num )
93
+ else
94
+ raise "clazz not recognized #{clazz}"
95
+ end
96
+ object.get_translation(lang)
81
97
  end
82
98
  end
83
99
  end
@@ -107,27 +107,7 @@ module Breeze
107
107
  end
108
108
 
109
109
  def get_translation(lang)
110
- Translation.find_translation(self.id , self.object_type , lang)
111
- end
112
-
113
- def delete_translations(editor)
114
- Breeze.language_strings.each do |lang|
115
- trans = Translation.find_translation(self.id, self.object_type , lang)
116
- trans.delete_save!(editor) if trans
117
- end
118
- end
119
-
120
- def self.fix_translations
121
- create = []
122
- Breeze.language_strings.each do |lang|
123
- self.all.each do |object|
124
- data = Translation.ensure_translation(object , lang)
125
- (create << data) unless data.nil?
126
- end
127
- end
128
- #puts "#{self.name} create #{create.length} Translations"
129
- create.each{ |data| Translation.new_translation(data) }
130
- Translation.save_all
110
+ Translation.new( self , lang)
131
111
  end
132
112
 
133
113
  end
@@ -18,7 +18,7 @@
18
18
  %th.whitespace-nowrap.px-4.py-2.text-left.font-medium.text-gray-900
19
19
  .flex.items-center.gap-2
20
20
  Change
21
- -[:Page , :Section , :Card , :Image].each do |element|
21
+ -[:Page , :Section , :Card , :Image , :Translation].each do |element|
22
22
  %th.whitespace-nowrap.px-4.py-2.text-left.font-medium.text-gray-900
23
23
  .flex.items-center.gap-2
24
24
  =element
@@ -27,7 +27,7 @@
27
27
  %tr
28
28
  %td.whitespace-nowrap.px-4.py-2.text-gray-700
29
29
  = type.to_s.capitalize
30
- -[:Page , :Section , :Card , :Image].each do |element|
30
+ -[:Page , :Section , :Card , :Image, :Translation].each do |element|
31
31
  %td.px-4.py-2.text-gray-700
32
32
  - changeset(type , element).each do |name|
33
33
  =name.last
@@ -1,10 +1,6 @@
1
1
  .mx-6.md:mx-12.mx-20.flex.h-16.items-center.gap-16
2
- .text-xl.font-bold
3
- Page styles
4
- .text-xl.font-bold
5
- =link_to "Section styles" , "#section_styles"
6
- .text-xl.font-bold
7
- =link_to "Card styles" , "#cards_styles"
2
+ .text-4xl.font-bold
3
+ This is a list of all available styles
8
4
 
9
5
  .flex.bg-cyan-100
10
6
  .px-4.py-8.mx-auto.text-center
@@ -1,29 +1,22 @@
1
1
  .flex.gap-10.mt-2.pt-4.bg-neutral-50.mx-10.border-b-2{class: language_bg(trans.language)}
2
- .basis-10.ml-3
2
+ .basis-10.ml-3.p-1.rounded{ class: ("bg-orange-200" if trans.is_old?) ,
3
+ id: "#{trans.id}_idfield" }
3
4
  %h3.text-lg.font-bold.text-center
4
- = trans.object.index_name
5
- = trans.language
5
+ %button{onclick: "button_ok(event)" , id: "#{trans.id}_idbutton"}
6
+ = trans.object.index_name
7
+ = trans.language
6
8
  .grow
7
- .text{id: "#{trans.id}_header_text" ,
8
- onclick: "text_to_form(event)" ,
9
- class: ("bg-orange-200" if trans.is_old?) }
9
+ .text{id: "#{trans.id}_headerfield" , onclick: "text_to_form(event)"}
10
10
  = trans.header
11
- .hidden.form{id: "#{trans.id}_header_form"}
12
- %input.mt-1.w-full.rounded-md.border-gray-200.bg-white.text-sm.text-gray-800.shadow-sm{ id: "#{trans.id}_header", type: "text" , value: trans.header}
13
- %button.button.change.mt-4{type: :submit ,
14
- id: "#{trans.id}_header_button" ,
15
- onclick: "submit_switch(event)" }
16
- Update Texts
17
11
  .grow
18
- .text{id: "#{trans.id}_text_text" ,
19
- onclick: "text_to_form(event)" ,
20
- class: ("bg-orange-200" if trans.is_old?) }
12
+ .text{id: "#{trans.id}_textfield" , onclick: "text_to_form(event)" }
21
13
  = trans.text
22
- .hidden.form{id: "#{trans.id}_text_form"}
14
+ .hidden.form{id: "#{trans.id}_form"}
15
+ %input.mt-1.w-full.rounded-md.border-gray-200.bg-white.text-sm.text-gray-800.shadow-sm{ id: "#{trans.id}_header", type: "text" , value: trans.header}
23
16
  %textarea.mt-2.w-full.rounded-lg.border-gray-200.align-top.shadow-sm.sm:text-sm{ cols: 100 ,
24
17
  id: "#{trans.id}_text" , rows: rows(trans.text) }
25
- =trans.text
18
+ = trans.text
26
19
  %button.button.change.mt-4{type: :submit ,
27
- id: "#{trans.id}_text_button" ,
20
+ id: "#{trans.id}_button" ,
28
21
  onclick: "submit_switch(event)"}
29
22
  Update Texts
@@ -28,7 +28,7 @@
28
28
 
29
29
  // change visibility id_text /id_form according to param 2/3
30
30
  function toggle_vis(id , text_visability , form_visability){
31
- var text_id = id + "_text";
31
+ var text_id = id + "_textfield";
32
32
  var text = document.getElementById(text_id);
33
33
  text.style.display = text_visability;
34
34
  var form_id = id + "_form";
@@ -38,14 +38,17 @@
38
38
  }
39
39
 
40
40
 
41
- function form_submit(trans_id , field ){
42
- var input_id = trans_id + "_" + field
43
- var input = document.getElementById(input_id);
41
+ function form_submit(trans_id ){
42
+ var text_id = trans_id + "_text"
43
+ var text = document.getElementById(text_id);
44
+ var header_id = trans_id + "_header"
45
+ var header = document.getElementById(header_id);
44
46
 
45
47
  var postObj = {
46
- authenticity_token: "#{form_authenticity_token}"
48
+ authenticity_token: "#{form_authenticity_token}" ,
49
+ header: header.value ,
50
+ text: text.value ,
47
51
  }
48
- postObj[field] = input.value ;
49
52
  const url = "/breeze/translations/" + trans_id
50
53
  fetch(url, {
51
54
  method: 'put', body: JSON.stringify(postObj),
@@ -53,27 +56,44 @@
53
56
  }).then((response) => {
54
57
  return response.json()
55
58
  }).then((res) => {
56
- console.log(input_id + " updated")
59
+ console.log(trans_id + " updated")
57
60
  }).catch((error) => {
58
61
  console.log(error)
59
62
  })
60
- var text = toggle_vis( input_id , "block", "none")
61
- text.innerHTML = input.value ;
62
- text.classList.remove("bg-orange-200");
63
+ toggle_vis( trans_id , "block", "none")
64
+ document.getElementById(trans_id + "_headerfield").innerHTML = header.value ;
65
+ document.getElementById(trans_id + "_textfield").innerHTML = text.value ;
66
+ document.getElementById(trans_id + "_idfield").classList.remove("bg-orange-200");
63
67
  }
64
68
 
65
-
66
69
  function submit_switch(event){
67
70
  var input_id = event.target.id; // eg 123_header
68
71
  console.log("switch " + input_id)
69
72
  var parts = input_id.split("_")
70
- form_submit( parts[0] , parts[1] );
73
+ form_submit( parts[0] );
71
74
  }
72
75
 
73
-
74
76
  function text_to_form(event) {
75
77
  var text_id = event.target.id; // eg 123_header_text
76
78
  console.log("text2form " + text_id)
77
79
  var parts = text_id.split("_");
78
- toggle_vis( parts[0] + "_" + parts[1] , "none" , "block")
80
+ toggle_vis( parts[0] , "none" , "block")
81
+ }
82
+
83
+ function button_ok(event) {
84
+ var idbutton = event.target;
85
+ var parts = idbutton.id.split("_");
86
+ document.getElementById(parts[0] + "_idfield").classList.remove("bg-orange-200");
87
+ var postObj = { authenticity_token: "#{form_authenticity_token}" }
88
+ const url = "/breeze/translations/" + parts[0]
89
+ fetch(url, {
90
+ method: 'put', body: JSON.stringify(postObj),
91
+ headers: { 'Accept': 'application/json', 'Content-Type': 'application/json'}
92
+ }).then((response) => {
93
+ return response.json()
94
+ }).then((res) => {
95
+ console.log(parts[0] + " updated")
96
+ }).catch((error) => {
97
+ console.log(error)
98
+ })
79
99
  }
@@ -17,5 +17,9 @@
17
17
  .grid.gap-6.md:grid-cols-2
18
18
  .relative.z-0.mt-10
19
19
  %input.peer.block.w-full.appearance-none.border-0.border-b.border-gray-500.bg-transparent.px-0.text-sm.text-gray-900.focus:border-blue-600.focus:outline-none.focus:ring-0{:class => "py-2.5", :name => "challenge", :placeholder => " ", :type => "text"}
20
- %label.absolute.top-3.-z-10.-translate-y-6.scale-75.transform.text-sm.text-gray-500.duration-300.peer-placeholder-shown:translate-y-0.peer-placeholder-shown:scale-100.peer-focus:left-0.peer-focus:-translate-y-6.peer-focus:scale-75.peer-focus:text-blue-600.peer-focus:dark:text-blue-500{:class => "origin-[0]"}Anti bot question: #{challenge} + #{challenge + 1} is
21
- %button.mt-10.rounded-md.bg-cyan-700.px-20.py-2.text-white{:type => "submit"} Send
20
+ %label.absolute.top-3.-z-10.-translate-y-6.scale-75.transform.text-sm.text-gray-500.duration-300.peer-placeholder-shown:translate-y-0.peer-placeholder-shown:scale-100.peer-focus:left-0.peer-focus:-translate-y-6.peer-focus:scale-75.peer-focus:text-blue-600.peer-focus:dark:text-blue-500{:class => "origin-[0]"}
21
+ = I18n.t("anti_bot")
22
+ = challenge
23
+ +
24
+ = challenge + 1
25
+ %button.mt-10.rounded-md.bg-cyan-700.px-20.py-2.text-white{:type => "submit"}= I18n.t("form_send")
@@ -5,9 +5,6 @@
5
5
  - unless section.header.blank?
6
6
  %h1.section_header.text-2xl.font-bold.tracking-tight.sm:text-4xl
7
7
  = section.header_text(current_lang)
8
- - if section.has_option?("subheader")
9
- %h2.text-xl.pt-10.font-bold.tracking-tight.sm:text-2xl
10
- = section.option("subheader")
11
8
  - unless section.text.blank?
12
9
  .section_text.text-lg.pt-10{ prose_classes }
13
10
  = markdown(section , current_lang)
@@ -3,9 +3,6 @@
3
3
  .px-4.py-4.md:py-10.lg:py-16.mx-5.md:mx-12.lg:mx-20{options(section , :text_align , :text_color)}
4
4
  %h1.section_header.text-2xl.font-bold.tracking-tight.sm:text-4xl
5
5
  = section.header_text(current_lang)
6
- -if section.has_option?("subheader")
7
- %h4.text-xl.mt-10.md:text-2xl
8
- = section.option("subheader")
9
6
  .section_text.mt-4.text-lg.pt-10{ prose_classes }
10
7
  = markdown(section,current_lang)
11
8
  =view_button(section , "my-2")
@@ -5,9 +5,6 @@
5
5
  .mx-auto.max-w-xl{options(section , :text_align , :text_color)}
6
6
  %h2.section_header.text-2xl.font-bold.md:text-4xl
7
7
  = section.header_text(current_lang)
8
- -if section.has_option?("subheader")
9
- %h4.text-xl.mt-10.md:text-2xl
10
- = section.option("subheader")
11
8
  .section_text.mt-8{ prose_classes }
12
9
  = markdown(section,current_lang)
13
10
  =view_button(section , "my-2")
@@ -5,9 +5,6 @@
5
5
  .flex-1{text_color_option(section)}
6
6
  .text-center
7
7
  %h2.section_header.text-4xl.font-bold.text-center.mb-4.lg:mb-8= section.header_text(current_lang)
8
- -if section.has_option?("subheader")
9
- %h4.text-xl.mt-4.lg:mt-8.md:text-2xl
10
- = section.option("subheader")
11
8
  .section_text.mt-3{ prose_classes }
12
9
  = markdown(section,current_lang)
13
10
  =view_button(section , "my-2")
@@ -4,9 +4,6 @@
4
4
  .px-4.py-4.md:py-10.lg:py-16.mx-5.md:mx-12.lg:mx-20{options(section , :text_align , :text_color)}
5
5
  %h1.section_header.text-2xl.font-bold.tracking-tight.sm:text-4xl
6
6
  = section.header_text(current_lang)
7
- -if section.has_option?("subheader")
8
- %h4.text-xl.mt-10.md:text-2xl
9
- = section.option("subheader")
10
7
  .section_text.mt-4.text-lg.pt-10{ prose_classes }
11
8
  = markdown(section,current_lang)
12
9
  =view_button(section , "my-2")
@@ -3,9 +3,6 @@
3
3
  = image_for(section ,"object-cover")
4
4
  .columns-1.md:columns-2.max-w-full.items-center.w-full.max-w.px-6.mx-auto.mt-6.lg:mt-0{text_color_option(section, "lg:w-2/3")}
5
5
  %h2.section_header.text-4xl.font-bold.text-left.mb-4.lg:mb-8{text_align_option(section)}= section.header_text(current_lang)
6
- -if section.has_option?("subheader")
7
- %h4.text-xl.mt-4.lg:mt-8.md:text-2xl{text_align_option(card)}
8
- = section.option("subheader")
9
6
  .section_text.mt-3{ prose_classes }
10
7
  = markdown(section,current_lang)
11
8
  =view_button(section , "my-2")
@@ -1 +1,2 @@
1
- .h-24
1
+ %section{ options(section , :background , :margin) , id: section.type_id}
2
+ %div{options(section, :height)}
@@ -4,9 +4,6 @@
4
4
  - if !section.header_text(current_lang).blank?
5
5
  %h1.section_header.mb-10.text-2xl.font-bold.tracking-tight.sm:text-4xl
6
6
  = section.header_text(current_lang)
7
- -if section.has_option?("subheader")
8
- .section_text.text-xl.pb-6{ prose_classes }
9
- = section.option("subheader")
10
7
 
11
8
  .max-w-full.mt-4.gap-16{ options(section , :text_columns , :prose ) }
12
9
  = markdown_image(section,current_lang)
@@ -3,8 +3,6 @@
3
3
  = image_for( card , "h-full w-full object-cover")
4
4
  .grid.h-70{options(card , :text_align , :text_color , :background )}
5
5
  %h3.card_header.p-4.mt-10.text-3xl.font-bold= card.header_text(current_lang)
6
- -if card.has_option?("subheader")
7
- %h4.p-4.text-xl= card.option("subheader")
8
6
  .m-6{options(card , :background , :text_color ) }
9
7
  .card_text{ prose_classes }
10
8
  = markdown(card,current_lang)
@@ -1,5 +1,5 @@
1
1
  .fex.flex-col.overflow-hidden.rounded-lg.border.border-gray-100.shadow-sm{ id: card.type_id}
2
- = image_for( card , class: "h-full w-full object-cover")
2
+ = image_for( card )
3
3
  %h3.card_header.p-5.text-2xl.bg-gray-100.text-black.font-bold{ text_align_option(card)}= card.header_text(current_lang)
4
4
  %div.h-full{background_option(card)}
5
5
  .p-5{options(card , :text_align , :text_color)}
@@ -3,7 +3,5 @@
3
3
  = image_for( card , "h-full w-full object-cover")
4
4
  .m-6{options(card , :text_align , :text_color )}
5
5
  %h3.card_header.p-4.text-2xl.font-bold= card.header_text(current_lang)
6
- -if card.has_option?("subheader")
7
- %h4.p-4.text-xl= card.option("subheader")
8
6
  .card_text.mt-2.p-4{prose_classes}= markdown(card,current_lang)
9
7
  =view_button(card)
@@ -2,7 +2,5 @@
2
2
  = image_for( card , "object-cover lg:w-3/5")
3
3
  .ml-0.lg:ml-10.mt-6.lg:mt0{options(card , :text_align , :text_color , :order , "lg:w-2/5")}
4
4
  %h3.card_header.text-2xl.font-bold= card.header_text(current_lang)
5
- -if card.has_option?("subheader")
6
- %h4.py-4.text-xl= card.option("subheader")
7
5
  .card_text.py-4{prose_classes}= markdown(card,current_lang)
8
6
  =view_button(card , "mb-2")
@@ -0,0 +1,38 @@
1
+ :javascript
2
+ function plausible(domain) {
3
+ "use strict";
4
+ var a = window.location,
5
+ r = window.document,
6
+ o = r.currentScript,
7
+ l = "https://plausible.feenix.community/api/event";
8
+
9
+ function s(t, e) {
10
+ t && console.warn("Ignoring Event: " + t), e && e.callback && e.callback()
11
+ }
12
+
13
+ function t(t, e) {
14
+ if (/^localhost$|^127(\.[0-9]+){0,2}\.[0-9]+$|^\[::1?\]$/.test(a.hostname) || "file:" === a.protocol) return s("localhost", e);
15
+ if (window._phantom || window.__nightmare || window.navigator.webdriver || window.Cypress) return s(null, e);
16
+ try {
17
+ if ("true" === window.localStorage.plausible_ignore) return s("localStorage flag", e)
18
+ } catch (t) {}
19
+ var n = {},
20
+ i = (n.n = t, n.u = a.href, n.d = domain, n.r = r.referrer || null, e && e.meta && (n.m = JSON.stringify(e.meta)), e && e.props && (n.p = e.props), new XMLHttpRequest);
21
+ i.open("POST", l, !0), i.setRequestHeader("Content-Type", "text/plain"), i.send(JSON.stringify(n)), i.onreadystatechange = function() {
22
+ 4 === i.readyState && e && e.callback && e.callback()
23
+ }
24
+ }
25
+ var e = window.plausible && window.plausible.q || [];
26
+ window.plausible = t;
27
+ for (var n, i = 0; i < e.length; i++) t.apply(this, e[i]);
28
+
29
+ function p() {
30
+ n !== a.pathname && (n = a.pathname, t("pageview"))
31
+ }
32
+ var c, w = window.history;
33
+ w.pushState && (c = w.pushState, w.pushState = function() {
34
+ c.apply(this, arguments), p()
35
+ }, window.addEventListener("popstate", p)), "prerender" === r.visibilityState ? r.addEventListener("visibilitychange", function() {
36
+ n || "visible" !== r.visibilityState || p()
37
+ }) : p()
38
+ };
@@ -24,7 +24,7 @@
24
24
  - text_align
25
25
  - :template: card_gap_square
26
26
  :header: Narrow card with up down section
27
- :text: Smaller image, large margins, possible subheader
27
+ :text: Smaller image, large margins
28
28
  Order turns it upside down, image bottom
29
29
  Images can be wide or square, for 2 column 800 wide,
30
30
  3 column 600 , 4 column 400
@@ -36,12 +36,10 @@
36
36
  - text_color
37
37
  - order
38
38
  - text_align
39
- - subheader
40
39
  - :template: card_normal_square
41
40
  :header: Standard card with square image
42
41
  :text: Image, header, text, normal stuff. No margin between image and text.
43
- Possible subheader. Text alignment option. Also option to turn upside
44
- down with order.
42
+ Text alignment option. Also option to turn upside down with order.
45
43
  Images can be wide or square, for 2 column 800 wide,
46
44
  3 column 600 , 4 column 400
47
45
  :fields:
@@ -51,7 +49,6 @@
51
49
  - background
52
50
  - text_color
53
51
  - text_align
54
- - subheader
55
52
  - order
56
53
  - button_link
57
54
  - button_text
@@ -69,7 +66,6 @@
69
66
  - background
70
67
  - text_color
71
68
  - text_align
72
- - subheader
73
69
  - order
74
70
  - button_link
75
71
  - button_text
@@ -50,11 +50,6 @@
50
50
  :values:
51
51
  :default:
52
52
  :id: 9
53
- - :name: subheader
54
- :description: Smaller header between Header and text
55
- :values:
56
- :default:
57
- :id: 10
58
53
  - :name: text
59
54
  :description: Second text. Just a second paragraph
60
55
  :values:
@@ -127,3 +122,8 @@
127
122
  :values: 1 2 3 4
128
123
  :default: 1
129
124
  :id: 23
125
+ - :name: height
126
+ :description: Height of element in rem
127
+ :values: h-8 h-16 h-24 h-32 h-40 h-48 h-64 h-96
128
+ :default: h-24
129
+ :id: 24
@@ -10,7 +10,6 @@
10
10
  :options:
11
11
  - background
12
12
  - columns
13
- - subheader
14
13
  - text_color
15
14
  - text_align
16
15
  - :template: section_slider
@@ -27,7 +26,6 @@
27
26
  - background
28
27
  - text_color
29
28
  - margin
30
- - subheader
31
29
  - text_align
32
30
  - item_align
33
31
  - button_link
@@ -44,7 +42,6 @@
44
42
  :options:
45
43
  - background
46
44
  - columns
47
- - subheader
48
45
  - text_color
49
46
  - text_align
50
47
  - :template: section_full_up
@@ -57,7 +54,6 @@
57
54
  - background
58
55
  - text_color
59
56
  - margin
60
- - subheader
61
57
  - text_align
62
58
  - item_align
63
59
  - button_link
@@ -89,7 +85,6 @@
89
85
  - background
90
86
  - text_color
91
87
  - margin
92
- - subheader
93
88
  - text_align
94
89
  - button_link
95
90
  - button_text
@@ -106,7 +101,6 @@
106
101
  - order
107
102
  - background
108
103
  - text_color
109
- - subheader
110
104
  - text_align
111
105
  - button_link
112
106
  - button_text
@@ -140,7 +134,6 @@
140
134
  - header
141
135
  - text
142
136
  :options:
143
- - subheader
144
137
  - margin
145
138
  - order
146
139
  - text_color
@@ -158,7 +151,6 @@
158
151
  - header
159
152
  - text
160
153
  :options:
161
- - subheader
162
154
  - margin
163
155
  - order
164
156
  - text_color
@@ -170,6 +162,10 @@
170
162
  :header: Spacer
171
163
  :text: Just for extra padding
172
164
  :fields:
165
+ :options:
166
+ - background
167
+ - margin
168
+ - height
173
169
  - :template: form_section
174
170
  :header: Contact or other form
175
171
  :text: Flexible form, with input fields as "cards". Only choose form_field
@@ -0,0 +1,3 @@
1
+ en:
2
+ form_send: Send
3
+ anti_bot: Anti bot challenge
data/config/routes.rb CHANGED
@@ -36,5 +36,6 @@ Breeze::Engine.routes.draw do
36
36
  post :scale
37
37
  end
38
38
 
39
- resources :translations
39
+ resources :translations
40
+
40
41
  end
@@ -6,6 +6,7 @@ module.exports = {
6
6
  './app/**/*.rb',
7
7
  './lib/**/*.rb',
8
8
  './config/initializers/breeze.rb' ,
9
+ './config/breeze/*' ,
9
10
  './app/javascript/**/*.js',
10
11
  './app/views/**/*.{erb,haml,html,slim}'
11
12
  ],
data/lib/breeze/engine.rb CHANGED
@@ -28,7 +28,7 @@ module Breeze
28
28
 
29
29
  initializer "after_initialize" do |app|
30
30
  ActiveSupport::Reloader.to_prepare do
31
- [Translation, Section, Card, Page, Image, PageStyle,
31
+ [Section, Card, Page, Image, PageStyle,
32
32
  SectionStyle, CardStyle, OptionDefinition].each do |clazz|
33
33
  clazz.reload
34
34
  end
@@ -1,3 +1,3 @@
1
1
  module Breeze
2
- VERSION = "0.9.5"
2
+ VERSION = "0.9.6"
3
3
  end
data/lib/breeze_cms.rb ADDED
@@ -0,0 +1,3 @@
1
+ # breeze_cms is loaded because the gem is breeze_cms
2
+ # the name is breeze_cms because breeze was taken
3
+ require "breeze"
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: breeze_cms
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.9.5
4
+ version: 0.9.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Torsten
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-02-26 00:00:00.000000000 Z
11
+ date: 2024-03-31 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -24,6 +24,20 @@ dependencies:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
26
  version: '7.0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '13.0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '13.0'
27
41
  - !ruby/object:Gem::Dependency
28
42
  name: haml-rails
29
43
  requirement: !ruby/object:Gem::Requirement
@@ -185,7 +199,7 @@ dependencies:
185
199
  - !ruby/object:Gem::Version
186
200
  version: '0.15'
187
201
  description: |-
188
- Breeze renders pages, that are made up of sections, that may include cards. Breeze also manages images, even lets you edit them, and manages translations when you go international.
202
+ Breeze is a tailwind based CMS for developers. It renders pages, that are made up of sections, that may include cards. Breeze also manages images, even lets you edit them, and manages translations when you go international.
189
203
  All data is stored in yaml files, images as assets.
190
204
  Breeze makes commits for changes which developers upstream in a very rails sort of way.
191
205
  email: torsten@feenix.community
@@ -317,6 +331,7 @@ files:
317
331
  - app/views/breeze/view/cards/_form_field.haml
318
332
  - app/views/breeze/view/elements/_button.haml
319
333
  - app/views/breeze/view/page.haml
334
+ - app/views/layouts/_plausible.haml
320
335
  - app/views/layouts/breeze/_header.haml
321
336
  - app/views/layouts/breeze/_messages.haml
322
337
  - app/views/layouts/breeze/application.haml
@@ -329,6 +344,7 @@ files:
329
344
  - config/initializers/breeze.rb
330
345
  - config/initializers/rabl.rb
331
346
  - config/initializers/simple_form.rb
347
+ - config/locales/breeze_en.yml
332
348
  - config/routes.rb
333
349
  - config/tailwind.config.js
334
350
  - config/tailwind.email.js
@@ -336,6 +352,7 @@ files:
336
352
  - lib/breeze/engine.rb
337
353
  - lib/breeze/shared_helper.rb
338
354
  - lib/breeze/version.rb
355
+ - lib/breeze_cms.rb
339
356
  - lib/generators/breeze/install/install_generator.rb
340
357
  - lib/generators/breeze/install/templates/empty.yml
341
358
  - lib/generators/breeze/install/templates/initializer.rb
@@ -348,7 +365,7 @@ licenses:
348
365
  metadata:
349
366
  homepage_uri: https://breeze.codeberg.page
350
367
  source_code_uri: https://codeberg.org/breeze/breeze
351
- changelog_uri: https://codeberg.org/breeze/breeze
368
+ changelog_uri: https://codeberg.org/breeze/breeze/src/branch/main/CHANGELOG.md
352
369
  post_install_message:
353
370
  rdoc_options: []
354
371
  require_paths:
@@ -357,7 +374,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
357
374
  requirements:
358
375
  - - ">="
359
376
  - !ruby/object:Gem::Version
360
- version: '0'
377
+ version: 2.7.0
361
378
  required_rubygems_version: !ruby/object:Gem::Requirement
362
379
  requirements:
363
380
  - - ">="