decidim-notify 0.3

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 (94) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE-AGPLv3.txt +661 -0
  3. data/README.md +160 -0
  4. data/Rakefile +40 -0
  5. data/app/assets/config/decidim_notify_manifest.css +2 -0
  6. data/app/assets/config/decidim_notify_manifest.js +3 -0
  7. data/app/assets/images/decidim/notify/icon.svg +1 -0
  8. data/app/assets/javascripts/cable.js +13 -0
  9. data/app/assets/javascripts/channels/decidim/notify/conversations.js +90 -0
  10. data/app/assets/javascripts/decidim/notify/conversations.js.es6 +70 -0
  11. data/app/assets/javascripts/decidim/notify/select2.js.es6 +100 -0
  12. data/app/assets/stylesheets/decidim/notify/_hexagon.scss +126 -0
  13. data/app/assets/stylesheets/decidim/notify/admin.scss +25 -0
  14. data/app/assets/stylesheets/decidim/notify/notify.scss +220 -0
  15. data/app/cells/decidim/notify/chapter/show.erb +35 -0
  16. data/app/cells/decidim/notify/chapter_cell.rb +43 -0
  17. data/app/cells/decidim/notify/note/show.erb +20 -0
  18. data/app/cells/decidim/notify/note_cell.rb +38 -0
  19. data/app/cells/decidim/notify/participant/show.erb +9 -0
  20. data/app/cells/decidim/notify/participant_cell.rb +26 -0
  21. data/app/channels/decidim/notify/chapters_channel.rb +17 -0
  22. data/app/channels/decidim/notify/connection.rb +17 -0
  23. data/app/channels/decidim/notify/notes_channel.rb +17 -0
  24. data/app/channels/decidim/notify/participants_channel.rb +17 -0
  25. data/app/commands/decidim/notify/admin/create_chapter.rb +51 -0
  26. data/app/commands/decidim/notify/admin/destroy_chapter.rb +30 -0
  27. data/app/commands/decidim/notify/admin/update_chapter.rb +52 -0
  28. data/app/commands/decidim/notify/admin/update_config.rb +71 -0
  29. data/app/commands/decidim/notify/create_note.rb +52 -0
  30. data/app/commands/decidim/notify/delete_chapter.rb +28 -0
  31. data/app/commands/decidim/notify/delete_note.rb +28 -0
  32. data/app/commands/decidim/notify/update_chapter.rb +35 -0
  33. data/app/commands/decidim/notify/update_note.rb +51 -0
  34. data/app/controllers/concerns/decidim/notify/broadcasts.rb +56 -0
  35. data/app/controllers/concerns/decidim/notify/needs_ajax_rescue.rb +25 -0
  36. data/app/controllers/decidim/notify/admin/application_controller.rb +18 -0
  37. data/app/controllers/decidim/notify/admin/chapters_controller.rb +90 -0
  38. data/app/controllers/decidim/notify/admin/conversations_controller.rb +61 -0
  39. data/app/controllers/decidim/notify/application_controller.rb +16 -0
  40. data/app/controllers/decidim/notify/chapters_controller.rb +41 -0
  41. data/app/controllers/decidim/notify/conversations_controller.rb +105 -0
  42. data/app/forms/decidim/notify/admin/chapter_form.rb +14 -0
  43. data/app/forms/decidim/notify/admin/notify_config_form.rb +14 -0
  44. data/app/forms/decidim/notify/chapter_form.rb +13 -0
  45. data/app/forms/decidim/notify/note_form.rb +16 -0
  46. data/app/helpers/decidim/notify/application_helper.rb +10 -0
  47. data/app/models/concerns/decidim/notify/belongs_to_notify_component.rb +31 -0
  48. data/app/models/decidim/notify/application_record.rb +10 -0
  49. data/app/models/decidim/notify/author.rb +29 -0
  50. data/app/models/decidim/notify/chapter.rb +22 -0
  51. data/app/models/decidim/notify/note.rb +23 -0
  52. data/app/permissions/decidim/notify/admin/permissions.rb +23 -0
  53. data/app/permissions/decidim/notify/permissions.rb +45 -0
  54. data/app/views/decidim/notify/admin/chapters/_form.html.erb +20 -0
  55. data/app/views/decidim/notify/admin/chapters/edit.html.erb +7 -0
  56. data/app/views/decidim/notify/admin/chapters/index.html.erb +52 -0
  57. data/app/views/decidim/notify/admin/chapters/new.html.erb +7 -0
  58. data/app/views/decidim/notify/admin/conversations/_form.html.erb +27 -0
  59. data/app/views/decidim/notify/admin/conversations/index.html.erb +27 -0
  60. data/app/views/decidim/notify/conversations/_chapter.html.erb +1 -0
  61. data/app/views/decidim/notify/conversations/_form.html.erb +9 -0
  62. data/app/views/decidim/notify/conversations/_note.html.erb +1 -0
  63. data/app/views/decidim/notify/conversations/_participant.html.erb +1 -0
  64. data/app/views/decidim/notify/conversations/_script.js.erb +7 -0
  65. data/app/views/decidim/notify/conversations/index.html.erb +48 -0
  66. data/app/views/decidim/notify/conversations/private.html.erb +11 -0
  67. data/config/i18n-tasks.yml +35 -0
  68. data/config/locales/ca.yml +110 -0
  69. data/config/locales/cs.yml +110 -0
  70. data/config/locales/en.yml +110 -0
  71. data/config/locales/es.yml +110 -0
  72. data/db/migrate/20200504071404_create_notify_notes.rb +11 -0
  73. data/db/migrate/20200505061547_create_notify_authors.rb +17 -0
  74. data/db/migrate/20200505061640_add_notify_notes_references.rb +9 -0
  75. data/db/migrate/20200505195918_add_notify_author_admin.rb +7 -0
  76. data/db/migrate/20200507103034_change_notify_notes_authors.rb +15 -0
  77. data/db/migrate/20200514144040_add_notify_note_chapters.rb +15 -0
  78. data/lib/decidim/notify.rb +57 -0
  79. data/lib/decidim/notify/admin.rb +10 -0
  80. data/lib/decidim/notify/admin_engine.rb +25 -0
  81. data/lib/decidim/notify/component.rb +135 -0
  82. data/lib/decidim/notify/engine.rb +39 -0
  83. data/lib/decidim/notify/seeds/avatar1.png +0 -0
  84. data/lib/decidim/notify/seeds/avatar2.png +0 -0
  85. data/lib/decidim/notify/seeds/avatar3.png +0 -0
  86. data/lib/decidim/notify/seeds/avatar4.png +0 -0
  87. data/lib/decidim/notify/seeds/avatar5.png +0 -0
  88. data/lib/decidim/notify/test/factories.rb +48 -0
  89. data/lib/decidim/notify/test/shared_examples/component_examples.rb +23 -0
  90. data/lib/decidim/notify/version.rb +9 -0
  91. data/vendor/assets/javascripts/select2.js +6147 -0
  92. data/vendor/assets/stylesheets/select2-foundation-theme.css +249 -0
  93. data/vendor/assets/stylesheets/select2.css +515 -0
  94. metadata +177 -0
@@ -0,0 +1,126 @@
1
+ @mixin responsive_hexagon() {
2
+ @include hexagon(71px);
3
+ @media only screen and (max-width: 596px) {
4
+ @include hexagon(35px, 1px);
5
+ .code {
6
+ font-size: 0.8em;
7
+ padding-top: 1px;
8
+ }
9
+ }
10
+ }
11
+
12
+ @mixin hexagon($width: 71px, $borderWidth: 2px, $borderColor: #000, $shadow: 0 0 10px rgba(0,0,0,0.5), $color: #fff) {
13
+ // $width works best with even numbers - browser rounding effs up with odds
14
+
15
+ //calculated values
16
+ $root2: 1.41421356237;
17
+ $root3: 1.73205080757;
18
+ $scaleFactor: 0.57735026919; // = tan(30deg) *this smushes a square into a 60deg/120deg rhombus:
19
+ $scaleFactor1: 1/$scaleFactor;
20
+
21
+ $height: $width/$root3;
22
+ $capWidth: $width/$root2; // caps = the top and bottom triangles
23
+ $capBorderWidth: $borderWidth*$root2;
24
+ $capBorderHeight: $borderWidth*2/$root3; //needed to offset bg pos
25
+ $border: solid $borderWidth $borderColor;
26
+ $capBorder: solid $capBorderWidth $borderColor;
27
+ $coverWidth: $width - $borderWidth*2; //the cover up rectangle
28
+ $coverHeight: $height - $borderWidth*$scaleFactor*2;
29
+ $capHeight: $height - $capBorderHeight;
30
+ $bgHeight: $capHeight*2;
31
+ $bgHeight: $height*2 - ($capBorderHeight*2);
32
+ $bgHeight: $height*2 - ($borderWidth*2/$root3)*2;
33
+ $bgHeight: $height*2 - ($borderWidth/$root3)*4;
34
+ $translateBG: -$height/2 + $capBorderHeight/2;
35
+
36
+ position: relative;
37
+ width: $width;
38
+ height: $height;
39
+ margin: $height/2 auto;
40
+ background-color: $color;
41
+ background-size: auto $bgHeight; //fit to total height, minus borders
42
+ background-position: center;
43
+ border-left: $border;
44
+ border-right: $border;
45
+ box-shadow: $shadow;
46
+ text-align:left;
47
+
48
+ .hex1,
49
+ .hex2 {
50
+ position: absolute;
51
+ z-index: 1;
52
+ width: $capWidth;
53
+ height: $capWidth;
54
+ box-shadow: $shadow;
55
+ overflow: hidden;
56
+ transform: scaleY($scaleFactor) rotate(-45deg);
57
+ background: inherit;
58
+ left: ($width - $capWidth)/2 - $borderWidth; //offset by half the difference in
59
+ }
60
+
61
+ //counter transform the bg image on the caps
62
+ .hex1:after,
63
+ .hex2:after {
64
+ content: "";
65
+ position: absolute;
66
+ width: $coverWidth;
67
+ height: $capHeight;
68
+ transform: rotate(45deg) scaleY($scaleFactor1) translateY($translateBG);
69
+ transform-origin: 0 0;
70
+ background: inherit;
71
+ //not sure why but this 1px correction seems necessary:(
72
+ // margin-left: 1px;
73
+ }
74
+
75
+ //send top to top and bottom to bottom
76
+ .hex1 {
77
+ top: -$width/$root2/2; //half the rhombus height
78
+ border-top: $capBorder;
79
+ border-right: $capBorder;
80
+
81
+ &:after {
82
+ background-position: center top;
83
+ }
84
+ }
85
+
86
+ .hex2 {
87
+ bottom: -$width/$root2/2; //half the rhombus height
88
+ border-bottom: $capBorder;
89
+ border-left: $capBorder;
90
+
91
+ &:after {
92
+ background-position: center bottom;
93
+ }
94
+ }
95
+
96
+ //cover up extra shadows
97
+ &:after {
98
+ content: "";
99
+ position: absolute;
100
+ top: $borderWidth*$scaleFactor;
101
+ left: 0;
102
+ width: $coverWidth;
103
+ height: $coverHeight;
104
+ z-index: 2;
105
+ background: inherit;
106
+ }
107
+
108
+ // Role
109
+ .code {
110
+ z-index: 10;
111
+ bottom:-$width/4;
112
+ right:-$width/6;
113
+ position: absolute;
114
+ width: $width/2;
115
+ height: $width/2;
116
+ border-radius:$width/2;
117
+ background-color: rgba(200,200,200,0.9);
118
+ color:#000;
119
+ font-size: 1.2em;
120
+ text-align: center;
121
+ padding-top: 7px;
122
+ line-height: 1;
123
+ font-weight: 600;
124
+ border: 1px solid #999;
125
+ }
126
+ }
@@ -0,0 +1,25 @@
1
+ @import "select2";
2
+ @import "select2-foundation-theme";
3
+
4
+ .multiusers-select-container {
5
+ form label {
6
+ margin-bottom: 1rem;
7
+ }
8
+
9
+ .switch-paddle {
10
+ display: inline-block;
11
+ vertical-align: middle;
12
+ margin-right: 1em;
13
+ }
14
+ }
15
+
16
+ .select2-container--foundation .select2-selection--multiple .select2-selection__choice {
17
+ display: inline-block;
18
+ float: none;
19
+ font-weight: normal;
20
+ }
21
+
22
+ .form-conversations-submit {
23
+ margin-top: 2rem;
24
+ }
25
+
@@ -0,0 +1,220 @@
1
+ @import 'decidim/variables';
2
+ @import 'decidim/utils/settings';
3
+ @import "select2";
4
+ @import "select2-foundation-theme";
5
+ @import "hexagon";
6
+
7
+ // we need to hide the original select otherwise focus is lost
8
+ .select2-hidden-accessible {
9
+ display: none;
10
+ }
11
+ .select2-container--foundation {
12
+ .select2-dropdown {
13
+ border-radius: 4px;
14
+ }
15
+ .select2-search--dropdown .select2-search__field {
16
+ border-radius: 4px;
17
+ &:focus {
18
+ border-color:#333;
19
+ }
20
+ }
21
+ .select2-selection {
22
+ border-radius: 4px;
23
+ }
24
+ .select2-results__option--highlighted[aria-selected] {
25
+ background-color: rgba(var(--secondary-rgb), 0.5);
26
+ }
27
+ .select2-result-repository {
28
+ display: flex;
29
+ &__avatar {
30
+ @include responsive_hexagon();
31
+ }
32
+ &__meta {
33
+ flex: 1;
34
+ align-self: center;
35
+ margin-left: 1rem;
36
+ color: black;
37
+ font-weight: bold;
38
+ word-wrap: break-word;
39
+ line-height: 1.1;
40
+ margin-bottom: 4px;
41
+ }
42
+ }
43
+ .select2-selection--single .select2-selection__clear,
44
+ .selection .select2-selection--single .select2-selection__clear {
45
+ margin-right: 20px;
46
+ background: #ddd;
47
+ border-radius: 50%;
48
+ line-height: 1;
49
+ height: 20px;
50
+ width: 20px;
51
+ }
52
+ }
53
+
54
+
55
+
56
+ .notify-container {
57
+ .hexagon {
58
+ @include responsive_hexagon();
59
+ }
60
+ .notify-participant {
61
+ display: inline-block;
62
+ margin: 0.5rem;
63
+ }
64
+
65
+ .card--notes-editor {
66
+ background: #eee;
67
+ border: #cacaca solid 1px;
68
+ textarea {
69
+ border: 1px solid #cacaca;
70
+ border-radius: 4px;
71
+ }
72
+ }
73
+ input, textarea {
74
+ &::placeholder {
75
+ color: #333;
76
+ }
77
+ }
78
+ .form-conversations-submit {
79
+ display: flex;
80
+ justify-content: flex-start;
81
+ align-items: baseline;
82
+
83
+ .info {
84
+ margin-left: 1rem;
85
+ display: none;
86
+ }
87
+ }
88
+ .form-conversations-reset {
89
+ margin-top: 0.5rem;
90
+ }
91
+
92
+ .by-note-taker {
93
+ background-color:rgba(var(--primary-rgb), 0.1);
94
+ }
95
+
96
+ .notify-chapter {
97
+ h3 {
98
+ display: flex;
99
+ width: 100%;
100
+ justify-content: center;
101
+ align-items: center;
102
+ text-align: center;
103
+ margin:1rem 0 1rem 0;
104
+ text-transform: uppercase;
105
+ &::before,&::after {
106
+ content: '';
107
+ border-top: 2px solid;
108
+ margin: 0 1rem 0 0;
109
+ flex: 1 0 1rem;
110
+ }
111
+ &:after {
112
+ margin: 0 0 0 1rem;
113
+ }
114
+ &.active {
115
+ color: var(--primary);
116
+ }
117
+ &:empty {
118
+ &::before,&::after {
119
+ margin:0;
120
+ }
121
+ }
122
+
123
+ >button {
124
+ font-size: 1rem;
125
+ color: var(--primary);
126
+ display: inline-block;
127
+ margin: 0 -0.5rem 0 0.5rem;
128
+ }
129
+ >.dropdown-pane {
130
+ font-family: $body-font-family;
131
+ margin-left: -3em;
132
+ border: 1px solid #333;
133
+ box-shadow: #999 0px 0px 15px;
134
+ text-align: left;
135
+
136
+ .button {
137
+ margin-bottom: 0;
138
+ }
139
+ .delete {
140
+ color: var(--primary);
141
+ position: absolute;
142
+ bottom: 1em;
143
+ right: 1rem;
144
+ }
145
+ }
146
+ }
147
+
148
+ .notify-chapter-notes {
149
+ padding:0.5rem;
150
+ .notify-note {
151
+ padding: 0.5rem;
152
+ border-radius: 4px;
153
+ }
154
+
155
+ &:empty, &.empty {
156
+ &::before {
157
+ content: attr(data-empty);
158
+ font-style: italic;
159
+ font-size: 0.9rem;
160
+ color: #888;
161
+ }
162
+ }
163
+ }
164
+ }
165
+
166
+ .media-object {
167
+ display: flex;
168
+
169
+ h4, p, em{
170
+ font-size: 1rem;
171
+ line-height: 1.1rem;
172
+ margin-bottom: 0.5rem;
173
+ display: block;
174
+ }
175
+ em {
176
+ font-size: 0.8rem;
177
+ color: #999;
178
+ }
179
+ h4 {
180
+ font-weight: 600;
181
+ b {
182
+ font-weight: 700;
183
+ }
184
+ }
185
+ img {
186
+ max-width: 100%;
187
+ }
188
+ }
189
+ .media-object-section {
190
+ .thumbnail {
191
+ width: 70px;
192
+ }
193
+ &.main-section {
194
+ flex: 1;
195
+ p {
196
+ white-space: pre-line;
197
+ }
198
+ }
199
+
200
+ }
201
+
202
+ .notify-note {
203
+ button {
204
+ &.tiny {
205
+ padding-left: 0.5rem;
206
+ padding-right: 0.5rem;
207
+ }
208
+ &.delete {
209
+ svg {
210
+ fill: var(--alert);
211
+ }
212
+ }
213
+ &.edit {
214
+ svg {
215
+ fill: var(--secondary);
216
+ }
217
+ }
218
+ }
219
+ }
220
+ }
@@ -0,0 +1,35 @@
1
+ <div class="notify-chapter" id="notify-chapter-<%= id %>">
2
+ <% if title %>
3
+ <h3 class="<%= " active" if active %>">
4
+ <span class="chapter-title"><%= title %></span>
5
+ <% if note_taker? %>
6
+ <button type="button" data-toggle="chapter-dropdown-<%= id %>"><%= icon "pencil" %></button>
7
+
8
+ <div class="dropdown-pane" id="chapter-dropdown-<%= id %>" data-position="bottom" data-alignment="center" data-dropdown data-auto-focus="true" data-close-on-click="true">
9
+ <h4><%= t("edit", scope: "decidim.notify.chapter") %></h4>
10
+ <%= form_for(@form, url: update_path, method: :patch, remote: true, html: { class: "form" }, id: "notify_edit_chapter_form-#{id}" ) do |form| %>
11
+ <%= form.text_field :title, placeholder: t("placeholders.statement", scope: "decidim.notify.conversations"), label: false %>
12
+
13
+ <div class="switch tiny toggle-chapter-active switch-with-label">
14
+ <label for="chapter_active-<%= id %>">
15
+ <%= form.check_box :active, label: false, class: "switch-input", id: "chapter_active-#{id}", checked: active %>
16
+ <span class="switch-paddle"></span>
17
+ <span class="switch-label"><%= t("active", scope: "decidim.notify.chapter") %></span>
18
+ </label>
19
+ </div>
20
+
21
+ <%= form.submit t("update", scope: "decidim.notify.chapter"), class: "button small" %>
22
+ <% end %>
23
+ <%= button_to update_path, method: :delete, remote: true, class: "delete", title: t("delete", scope: "decidim.notify.chapter"), data: { confirm: t("destroy.sure", scope: "decidim.notify.chapter") } do %>
24
+ <%= icon "trash" %>
25
+ <% end %>
26
+ </div>
27
+ <% end %>
28
+ </h3>
29
+ <% else %>
30
+ <h3></h3>
31
+ <% end %>
32
+ <div class="card">
33
+ <div class="card-section notify-chapter-notes" id="notify-chapter-notes-<%= id %>" data-empty="<%= t("empty", scope: "decidim.notify.chapter") %>"><%= cell "decidim/notify/note", collection: notes %></div>
34
+ </div>
35
+ </div>
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Decidim
4
+ module Notify
5
+ # This cell renders the card for an instance of a Notify Chapter
6
+ class ChapterCell < Decidim::ViewModel
7
+ include Decidim::LayoutHelper
8
+
9
+ property :title
10
+
11
+ def show
12
+ @form = Decidim::Notify::ChapterForm.from_params(title: title)
13
+ render
14
+ end
15
+
16
+ def id
17
+ return "unclassified" unless model&.id
18
+
19
+ model.id
20
+ end
21
+
22
+ def note_taker?
23
+ return unless current_user
24
+
25
+ Author.for(model.component).note_takers.find_by(user: current_user)
26
+ end
27
+
28
+ def notes
29
+ return [] unless model&.notes
30
+
31
+ model.notes
32
+ end
33
+
34
+ def active
35
+ model&.active
36
+ end
37
+
38
+ def update_path
39
+ EngineRouter.main_proxy(model.component).chapter_path(model.id)
40
+ end
41
+ end
42
+ end
43
+ end