b4um_generators 0.1.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 (87) hide show
  1. checksums.yaml +7 -0
  2. data/.rspec +3 -0
  3. data/.rubocop.yml +28 -0
  4. data/CHANGELOG.md +5 -0
  5. data/LICENSE.txt +21 -0
  6. data/README.de.md +821 -0
  7. data/README.md +815 -0
  8. data/Rakefile +12 -0
  9. data/b4um_generators.gemspec +30 -0
  10. data/bin/console +11 -0
  11. data/bin/setup +8 -0
  12. data/lib/b4um_generators/version.rb +5 -0
  13. data/lib/b4um_generators.rb +8 -0
  14. data/lib/generators/b4um/bento/bento_generator.rb +81 -0
  15. data/lib/generators/b4um/bento/templates/_alternating.html.erb.tt +15 -0
  16. data/lib/generators/b4um/bento/templates/_bento.html.erb.tt +26 -0
  17. data/lib/generators/b4um/bento/templates/_grid.html.erb.tt +13 -0
  18. data/lib/generators/b4um/bento/templates/_list.html.erb.tt +15 -0
  19. data/lib/generators/b4um/comments/comments_generator.rb +259 -0
  20. data/lib/generators/b4um/comments/templates/_comments.html.erb.tt +63 -0
  21. data/lib/generators/b4um/comments/templates/comment.rb.tt +5 -0
  22. data/lib/generators/b4um/comments/templates/comments_controller.rb.tt +45 -0
  23. data/lib/generators/b4um/comments/templates/create_comments.rb.tt +14 -0
  24. data/lib/generators/b4um/controller/controller_generator.rb +397 -0
  25. data/lib/generators/b4um/help/help_generator.rb +755 -0
  26. data/lib/generators/b4um/infinite_scroll/infinite_scroll_generator.rb +199 -0
  27. data/lib/generators/b4um/infinite_scroll/templates/infinite_scroll_controller.js +61 -0
  28. data/lib/generators/b4um/install/install_generator.rb +492 -0
  29. data/lib/generators/b4um/install/templates/_cookie_consent.html.erb +27 -0
  30. data/lib/generators/b4um/install/templates/_footer.html.erb +17 -0
  31. data/lib/generators/b4um/install/templates/_hero.html.erb +33 -0
  32. data/lib/generators/b4um/install/templates/_navigation.html.erb +31 -0
  33. data/lib/generators/b4um/install/templates/_sitemap.html.erb +48 -0
  34. data/lib/generators/b4um/install/templates/_theme_switcher.html.erb +57 -0
  35. data/lib/generators/b4um/install/templates/b4um/badges.css +43 -0
  36. data/lib/generators/b4um/install/templates/b4um/base.css +42 -0
  37. data/lib/generators/b4um/install/templates/b4um/callouts.css +58 -0
  38. data/lib/generators/b4um/install/templates/b4um/cards.css +401 -0
  39. data/lib/generators/b4um/install/templates/b4um/comments.css +52 -0
  40. data/lib/generators/b4um/install/templates/b4um/cookie-consent.css +83 -0
  41. data/lib/generators/b4um/install/templates/b4um/empty-state.css +26 -0
  42. data/lib/generators/b4um/install/templates/b4um/flash.css +86 -0
  43. data/lib/generators/b4um/install/templates/b4um/footer.css +338 -0
  44. data/lib/generators/b4um/install/templates/b4um/forms.css +924 -0
  45. data/lib/generators/b4um/install/templates/b4um/hero.css +149 -0
  46. data/lib/generators/b4um/install/templates/b4um/layout.css +166 -0
  47. data/lib/generators/b4um/install/templates/b4um/lightbox.css +268 -0
  48. data/lib/generators/b4um/install/templates/b4um/navigation.css +257 -0
  49. data/lib/generators/b4um/install/templates/b4um/pagination.css +85 -0
  50. data/lib/generators/b4um/install/templates/b4um/resources.css +121 -0
  51. data/lib/generators/b4um/install/templates/b4um/search.css +41 -0
  52. data/lib/generators/b4um/install/templates/b4um/tables.css +67 -0
  53. data/lib/generators/b4um/install/templates/b4um/theme-switcher.css +178 -0
  54. data/lib/generators/b4um/install/templates/b4um/theme.css +132 -0
  55. data/lib/generators/b4um/install/templates/b4um.css +20 -0
  56. data/lib/generators/b4um/install/templates/b4um.yml +12 -0
  57. data/lib/generators/b4um/install/templates/b4um_helper.rb +27 -0
  58. data/lib/generators/b4um/install/templates/cookie_consent_controller.js +76 -0
  59. data/lib/generators/b4um/install/templates/dismissible_controller.js +7 -0
  60. data/lib/generators/b4um/install/templates/image_lightbox_controller.js +414 -0
  61. data/lib/generators/b4um/install/templates/image_preview_controller.js +85 -0
  62. data/lib/generators/b4um/install/templates/navigation_controller.js +25 -0
  63. data/lib/generators/b4um/install/templates/navigation_helper.rb +26 -0
  64. data/lib/generators/b4um/install/templates/sitemap_controller.js +35 -0
  65. data/lib/generators/b4um/install/templates/theme_controller.js +122 -0
  66. data/lib/generators/b4um/pagination/pagination_generator.rb +179 -0
  67. data/lib/generators/b4um/pagination/templates/_pagination.html.erb.tt +48 -0
  68. data/lib/generators/b4um/pagination/templates/pagination.rb +36 -0
  69. data/lib/generators/b4um/scaffold/scaffold_generator.rb +333 -0
  70. data/lib/generators/b4um/scaffold/templates/_bento.html.erb.tt +26 -0
  71. data/lib/generators/b4um/scaffold/templates/_form.html.erb.tt +218 -0
  72. data/lib/generators/b4um/scaffold/templates/_resource.html.erb.tt +144 -0
  73. data/lib/generators/b4um/scaffold/templates/_table.html.erb.tt +40 -0
  74. data/lib/generators/b4um/scaffold/templates/edit.html.erb.tt +21 -0
  75. data/lib/generators/b4um/scaffold/templates/index.html.erb.tt +24 -0
  76. data/lib/generators/b4um/scaffold/templates/new.html.erb.tt +17 -0
  77. data/lib/generators/b4um/scaffold/templates/show.html.erb.tt +31 -0
  78. data/lib/generators/b4um/search/search_generator.rb +165 -0
  79. data/lib/generators/b4um/search/templates/search.rb +34 -0
  80. data/lib/generators/b4um/search/templates/search_form.html.erb.tt +15 -0
  81. data/lib/generators/b4um/table/table_generator.rb +63 -0
  82. data/lib/generators/b4um/table/templates/_table.html.erb.tt +40 -0
  83. data/lib/generators/b4um/trix/templates/b4um_rich_text_helper.rb +58 -0
  84. data/lib/generators/b4um/trix/templates/b4um_trix.js +551 -0
  85. data/lib/generators/b4um/trix/trix_generator.rb +383 -0
  86. data/sig/b4um_generators.rbs +4 -0
  87. metadata +148 -0
@@ -0,0 +1,551 @@
1
+ /* -------------------------------------------------------------------------- */
2
+ /* b4um Trix */
3
+ /* -------------------------------------------------------------------------- */
4
+
5
+ const HEADING_LEVELS = [1, 2, 3, 4, 5, 6]
6
+
7
+ const ALIGNMENTS = {
8
+ alignLeft: 'left',
9
+ alignCenter: 'center',
10
+ alignRight: 'right'
11
+ }
12
+
13
+ const FOREGROUND_COLORS = [
14
+ 'rgb(136, 118, 38)',
15
+ 'rgb(185, 94, 6)',
16
+ 'rgb(207, 0, 0)',
17
+ 'rgb(216, 28, 170)',
18
+ 'rgb(144, 19, 254)',
19
+ 'rgb(5, 98, 185)',
20
+ 'rgb(17, 138, 15)',
21
+ 'rgb(148, 82, 22)',
22
+ 'rgb(102, 102, 102)'
23
+ ]
24
+
25
+ const BACKGROUND_COLORS = [
26
+ 'rgb(250, 247, 133)',
27
+ 'rgb(255, 240, 219)',
28
+ 'rgb(255, 229, 229)',
29
+ 'rgb(255, 228, 247)',
30
+ 'rgb(242, 237, 255)',
31
+ 'rgb(225, 239, 252)',
32
+ 'rgb(228, 248, 226)',
33
+ 'rgb(238, 226, 215)',
34
+ 'rgb(242, 242, 242)'
35
+ ]
36
+
37
+ Trix.config.dompurify.ADD_TAGS = ['align-left', 'align-center', 'align-right']
38
+ Trix.config.dompurify.ADD_ATTR = ['id']
39
+
40
+ allowB4umHtmlAttributes()
41
+
42
+ configureHeadingAttributes()
43
+ configureAlignmentAttributes()
44
+ configureContainerAttributes()
45
+ configureColorAttributes()
46
+ registerAlignmentElements()
47
+
48
+ document.addEventListener('trix-initialize', (event) => {
49
+ const editor = event.target
50
+
51
+ if (!(editor instanceof HTMLElement)) return
52
+
53
+ installB4umToolbar(editor)
54
+ })
55
+
56
+ document.addEventListener('trix-action-invoke', (event) => {
57
+ const editor = event.target.editor
58
+
59
+ if (!editor) return
60
+
61
+ if (event.actionName === 'x-horizontal-rule') {
62
+ const attachment = new Trix.Attachment({
63
+ content: '<hr>',
64
+ contentType: 'vnd.rubyonrails.horizontal-rule.html'
65
+ })
66
+
67
+ editor.insertAttachment(attachment)
68
+ return
69
+ }
70
+ })
71
+
72
+ function insertContainer(editor, tagName) {
73
+ const selectedRange = editor.getSelectedRange()
74
+
75
+ if (!selectedRange || selectedRange[0] === selectedRange[1]) {
76
+ window.alert('Bitte markieren Sie zuerst den Inhalt.')
77
+ return
78
+ }
79
+
80
+ const id = window.prompt('Bitte geben Sie die ID ein:')
81
+
82
+ if (id === null) return
83
+
84
+ const trimmedId = id.trim()
85
+
86
+ if (!trimmedId) {
87
+ window.alert('Bitte geben Sie eine ID ein.')
88
+ return
89
+ }
90
+
91
+ editor.recordUndoEntry(`Insert ${tagName.toUpperCase()} Container`)
92
+
93
+ editor.setSelectedRange(selectedRange)
94
+
95
+ const attributeName = tagName === 'div' ? 'b4umDiv' : tagName
96
+
97
+ editor.activateAttribute(attributeName)
98
+
99
+ editor.composition.setHTMLAtributeAtPosition(selectedRange[0], 'id', trimmedId)
100
+
101
+ editor.setSelectedRange(selectedRange)
102
+ }
103
+
104
+ /* -------------------------------------------------------------------------- */
105
+ /* Configuration */
106
+ /* -------------------------------------------------------------------------- */
107
+
108
+ function allowB4umHtmlAttributes() {
109
+ const originalSetHTML = Trix.HTMLSanitizer.setHTML
110
+
111
+ Trix.HTMLSanitizer.setHTML = function (element, html, options = {}) {
112
+ const allowedAttributes = [
113
+ 'style',
114
+ 'href',
115
+ 'src',
116
+ 'width',
117
+ 'height',
118
+ 'language',
119
+ 'class',
120
+ 'id',
121
+ ...(options.allowedAttributes || [])
122
+ ]
123
+
124
+ return originalSetHTML.call(this, element, html, {
125
+ ...options,
126
+ allowedAttributes: [...new Set(allowedAttributes)]
127
+ })
128
+ }
129
+ }
130
+
131
+ function configureHeadingAttributes() {
132
+ HEADING_LEVELS.forEach((level) => {
133
+ Trix.config.blockAttributes[`heading${level}`] = {
134
+ tagName: `h${level}`,
135
+ terminal: true,
136
+ breakOnReturn: true,
137
+ group: false
138
+ }
139
+ })
140
+ }
141
+
142
+ function configureAlignmentAttributes() {
143
+ Object.entries(ALIGNMENTS).forEach(([attribute, alignment]) => {
144
+ Trix.config.blockAttributes[attribute] = {
145
+ tagName: `align-${alignment}`,
146
+ parse: true,
147
+ nestable: false,
148
+ exclusive: true,
149
+ group: false
150
+ }
151
+ })
152
+ }
153
+
154
+ function configureContainerAttributes() {
155
+ Trix.config.blockAttributes.default.htmlAttributes = ['id']
156
+
157
+ Trix.config.blockAttributes.b4umDiv = {
158
+ tagName: 'div',
159
+ parse: true,
160
+ nestable: false,
161
+ exclusive: true,
162
+ group: false,
163
+ htmlAttributes: ['id'],
164
+ test(element) {
165
+ return element.hasAttribute('id')
166
+ }
167
+ }
168
+
169
+ Trix.config.blockAttributes.section = {
170
+ tagName: 'section',
171
+ parse: true,
172
+ nestable: false,
173
+ exclusive: true,
174
+ group: false,
175
+ htmlAttributes: ['id']
176
+ }
177
+
178
+ Trix.config.blockAttributes.article = {
179
+ tagName: 'article',
180
+ parse: true,
181
+ nestable: false,
182
+ exclusive: true,
183
+ group: false,
184
+ htmlAttributes: ['id']
185
+ }
186
+ }
187
+
188
+ function configureColorAttributes() {
189
+ FOREGROUND_COLORS.forEach((color, index) => {
190
+ Trix.config.textAttributes[`fgColor${index + 1}`] = {
191
+ style: { color },
192
+ inheritable: true,
193
+ parser: (element) => element.style.color === color
194
+ }
195
+ })
196
+
197
+ BACKGROUND_COLORS.forEach((color, index) => {
198
+ Trix.config.textAttributes[`bgColor${index + 1}`] = {
199
+ style: { backgroundColor: color },
200
+ inheritable: true,
201
+ parser: (element) => element.style.backgroundColor === color
202
+ }
203
+ })
204
+ }
205
+
206
+ function registerAlignmentElements() {
207
+ registerAlignmentElement('align-left', 'left')
208
+ registerAlignmentElement('align-center', 'center')
209
+ registerAlignmentElement('align-right', 'right')
210
+ }
211
+
212
+ function registerAlignmentElement(tagName, alignment) {
213
+ if (customElements.get(tagName)) return
214
+
215
+ customElements.define(
216
+ tagName,
217
+ class extends HTMLElement {
218
+ constructor() {
219
+ super()
220
+
221
+ const shadow = this.attachShadow({ mode: 'open' })
222
+
223
+ shadow.innerHTML = `
224
+ <style>
225
+ :host {
226
+ display: block;
227
+ width: 100%;
228
+ text-align: ${alignment};
229
+ }
230
+ </style>
231
+
232
+ <slot></slot>
233
+ `
234
+ }
235
+ }
236
+ )
237
+ }
238
+
239
+ /* -------------------------------------------------------------------------- */
240
+ /* Toolbar */
241
+ /* -------------------------------------------------------------------------- */
242
+
243
+ function installB4umToolbar(editor) {
244
+ const toolbar = editor.toolbarElement
245
+
246
+ if (!toolbar) return
247
+ if (toolbar.dataset.b4umTrixInitialized === 'true') return
248
+
249
+ toolbar.dataset.b4umTrixInitialized = 'true'
250
+
251
+ replaceHeadingButton(toolbar)
252
+ installHeadingDialog(toolbar)
253
+ installAlignmentButtons(toolbar)
254
+
255
+ installHorizontalRuleButton(toolbar)
256
+ installContainerButtons(toolbar)
257
+ installContainerButtonHandlers(editor, toolbar)
258
+ installColorButton(toolbar)
259
+
260
+ installColorDialog(toolbar)
261
+ }
262
+
263
+ function replaceHeadingButton(toolbar) {
264
+ const originalButton = toolbar.querySelector('[data-trix-attribute="heading1"]')
265
+
266
+ if (!originalButton) return
267
+
268
+ originalButton.insertAdjacentHTML('beforebegin', headingButtonTemplate())
269
+
270
+ originalButton.remove()
271
+ }
272
+
273
+ function installHeadingDialog(toolbar) {
274
+ const dialogs = toolbar.querySelector('[data-trix-dialogs]')
275
+
276
+ if (!dialogs) return
277
+ if (dialogs.querySelector('[data-trix-dialog="x-heading"]')) return
278
+
279
+ dialogs.insertAdjacentHTML('beforeend', headingDialogTemplate())
280
+ }
281
+
282
+ function installAlignmentButtons(toolbar) {
283
+ const blockTools = toolbar.querySelector('[data-trix-button-group="block-tools"]')
284
+
285
+ if (!blockTools) return
286
+ if (toolbar.querySelector('.trix-button-group--alignment-tools')) return
287
+
288
+ blockTools.insertAdjacentHTML('afterend', alignmentButtonsTemplate())
289
+ }
290
+
291
+ function installHorizontalRuleButton(toolbar) {
292
+ const quoteButton = toolbar.querySelector('[data-trix-attribute="quote"]')
293
+
294
+ if (!quoteButton) return
295
+ if (toolbar.querySelector('[data-trix-action="x-horizontal-rule"]')) return
296
+
297
+ quoteButton.insertAdjacentHTML('afterend', horizontalRuleButtonTemplate())
298
+ }
299
+
300
+ function installContainerButtons(toolbar) {
301
+ const blockTools = toolbar.querySelector('[data-trix-button-group="block-tools"]')
302
+
303
+ if (!blockTools) return
304
+ if (toolbar.querySelector('.trix-button-group--container-tools')) return
305
+
306
+ blockTools.insertAdjacentHTML('afterend', containerButtonsTemplate())
307
+ }
308
+
309
+ function installContainerButtonHandlers(editorElement, toolbar) {
310
+ const editor = editorElement.editor
311
+
312
+ if (!editor) return
313
+
314
+ toolbar
315
+ .querySelectorAll(
316
+ '[data-trix-attribute="b4umDiv"], [data-trix-attribute="section"], [data-trix-attribute="article"]'
317
+ )
318
+ .forEach((button) => {
319
+ if (button.dataset.b4umContainerHandler === 'true') return
320
+
321
+ button.dataset.b4umContainerHandler = 'true'
322
+
323
+ button.addEventListener(
324
+ 'mousedown',
325
+ (event) => {
326
+ const attributeName = button.dataset.trixAttribute
327
+
328
+ if (!attributeName) return
329
+
330
+ if (button.hasAttribute('data-trix-active')) {
331
+ return
332
+ }
333
+
334
+ event.preventDefault()
335
+ event.stopImmediatePropagation()
336
+
337
+ const tagName = attributeName === 'b4umDiv' ? 'div' : attributeName
338
+
339
+ insertContainer(editor, tagName)
340
+ },
341
+ true
342
+ )
343
+ })
344
+ }
345
+
346
+ function installColorButton(toolbar) {
347
+ const textTools = toolbar.querySelector('[data-trix-button-group="text-tools"]')
348
+
349
+ if (!textTools) return
350
+ if (toolbar.querySelector('[data-trix-action="x-color"]')) return
351
+
352
+ textTools.insertAdjacentHTML('beforeend', colorButtonTemplate())
353
+ }
354
+
355
+ function installColorDialog(toolbar) {
356
+ const dialogs = toolbar.querySelector('[data-trix-dialogs]')
357
+
358
+ if (!dialogs) return
359
+ if (dialogs.querySelector('[data-trix-dialog="x-color"]')) return
360
+
361
+ dialogs.insertAdjacentHTML('beforeend', colorDialogTemplate())
362
+ }
363
+
364
+ /* -------------------------------------------------------------------------- */
365
+ /* Templates */
366
+ /* -------------------------------------------------------------------------- */
367
+
368
+ function headingButtonTemplate() {
369
+ return `
370
+ <button
371
+ type="button"
372
+ class="trix-button trix-button--icon trix-button--icon-heading-1"
373
+ data-trix-action="x-heading"
374
+ title="Heading"
375
+ aria-label="Heading"
376
+ tabindex="-1">
377
+ Heading
378
+ </button>
379
+ `
380
+ }
381
+
382
+ function headingDialogTemplate() {
383
+ const buttons = HEADING_LEVELS.map((level) => {
384
+ return `
385
+ <button
386
+ type="button"
387
+ class="trix-button trix-button--dialog"
388
+ data-trix-attribute="heading${level}">
389
+ H${level}
390
+ </button>
391
+ `
392
+ }).join('')
393
+
394
+ return `
395
+ <div
396
+ class="trix-dialog trix-dialog--heading"
397
+ data-trix-dialog="x-heading"
398
+ data-trix-dialog-attribute="x-heading">
399
+
400
+ <div class="trix-dialog__link-fields">
401
+ <div class="trix-button-group">
402
+ ${buttons}
403
+ </div>
404
+ </div>
405
+ </div>
406
+ `
407
+ }
408
+
409
+ function alignmentButtonsTemplate() {
410
+ return `
411
+ <div class="trix-button-group trix-button-group--alignment-tools">
412
+ <button
413
+ type="button"
414
+ class="trix-button trix-button--icon trix-button--icon-align-left"
415
+ data-trix-attribute="alignLeft"
416
+ title="Align left"
417
+ aria-label="Align left"
418
+ tabindex="-1">
419
+ Align left
420
+ </button>
421
+
422
+ <button
423
+ type="button"
424
+ class="trix-button trix-button--icon trix-button--icon-align-center"
425
+ data-trix-attribute="alignCenter"
426
+ title="Align center"
427
+ aria-label="Align center"
428
+ tabindex="-1">
429
+ Align center
430
+ </button>
431
+
432
+ <button
433
+ type="button"
434
+ class="trix-button trix-button--icon trix-button--icon-align-right"
435
+ data-trix-attribute="alignRight"
436
+ title="Align right"
437
+ aria-label="Align right"
438
+ tabindex="-1">
439
+ Align right
440
+ </button>
441
+ </div>
442
+ `
443
+ }
444
+
445
+ function containerButtonsTemplate() {
446
+ return `
447
+ <span
448
+ class="trix-button-group trix-button-group--container-tools"
449
+ data-trix-button-group="container-tools">
450
+ <button
451
+ type="button"
452
+ class="trix-button"
453
+ data-trix-attribute="b4umDiv"
454
+ title="DIV"
455
+ aria-label="DIV"
456
+ tabindex="-1">
457
+ div
458
+ </button>
459
+ <button
460
+ type="button"
461
+ class="trix-button"
462
+ data-trix-attribute="section"
463
+ title="SECTION"
464
+ aria-label="SECTION"
465
+ tabindex="-1">
466
+ section
467
+ </button>
468
+ <button
469
+ type="button"
470
+ class="trix-button"
471
+ data-trix-attribute="article"
472
+ title="ARTICLE"
473
+ aria-label="ARTICLE"
474
+ tabindex="-1">
475
+ article
476
+ </button>
477
+ </span>
478
+ `
479
+ }
480
+
481
+ function horizontalRuleButtonTemplate() {
482
+ return `
483
+ <button
484
+ type="button"
485
+ class="trix-button trix-button--icon trix-button--icon-horizontal-rule"
486
+ data-trix-action="x-horizontal-rule"
487
+ title="Divider"
488
+ aria-label="Divider"
489
+ tabindex="-1">
490
+ Divider
491
+ </button>
492
+ `
493
+ }
494
+
495
+ function colorButtonTemplate() {
496
+ return `
497
+ <button
498
+ type="button"
499
+ class="trix-button trix-button--icon trix-button--icon-color"
500
+ data-trix-action="x-color"
501
+ title="Color"
502
+ aria-label="Color"
503
+ tabindex="-1">
504
+ Color
505
+ </button>
506
+ `
507
+ }
508
+
509
+ function colorDialogTemplate() {
510
+ const foregroundButtons = FOREGROUND_COLORS.map((color, index) => {
511
+ return `
512
+ <button
513
+ type="button"
514
+ class="trix-button trix-button--dialog"
515
+ data-trix-attribute="fgColor${index + 1}"
516
+ data-b4um-color="${color}"
517
+ aria-label="Text color ${index + 1}">
518
+ </button>
519
+ `
520
+ }).join('')
521
+
522
+ const backgroundButtons = BACKGROUND_COLORS.map((color, index) => {
523
+ return `
524
+ <button
525
+ type="button"
526
+ class="trix-button trix-button--dialog"
527
+ data-trix-attribute="bgColor${index + 1}"
528
+ data-b4um-background-color="${color}"
529
+ aria-label="Background color ${index + 1}">
530
+ </button>
531
+ `
532
+ }).join('')
533
+
534
+ return `
535
+ <div
536
+ class="trix-dialog trix-dialog--color"
537
+ data-trix-dialog="x-color"
538
+ data-trix-dialog-attribute="x-color">
539
+
540
+ <div class="trix-dialog__link-fields">
541
+ <div class="trix-button-group trix-button-group--foreground-colors">
542
+ ${foregroundButtons}
543
+ </div>
544
+
545
+ <div class="trix-button-group trix-button-group--background-colors">
546
+ ${backgroundButtons}
547
+ </div>
548
+ </div>
549
+ </div>
550
+ `
551
+ }