railspress-engine 0.1.2 → 1.2.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 (140) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE +20 -0
  3. data/README.md +195 -25
  4. data/app/assets/javascripts/railspress/admin.js +39 -0
  5. data/app/assets/javascripts/railspress/markdown_mode.js +343 -0
  6. data/app/assets/stylesheets/application.css +0 -0
  7. data/app/assets/stylesheets/railspress/admin/badges.css +70 -0
  8. data/app/assets/stylesheets/railspress/admin/base.css +25 -0
  9. data/app/assets/stylesheets/railspress/admin/buttons.css +140 -0
  10. data/app/assets/stylesheets/railspress/admin/cards.css +52 -0
  11. data/app/assets/stylesheets/railspress/admin/components/exports.css +55 -0
  12. data/app/assets/stylesheets/railspress/admin/components/focal_point.css +801 -0
  13. data/app/assets/stylesheets/railspress/admin/components/imports.css +144 -0
  14. data/app/assets/stylesheets/railspress/admin/components/lexxy.css +156 -0
  15. data/app/assets/stylesheets/railspress/admin/filters.css +73 -0
  16. data/app/assets/stylesheets/railspress/admin/flash.css +26 -0
  17. data/app/assets/stylesheets/railspress/admin/forms.css +459 -0
  18. data/app/assets/stylesheets/railspress/admin/layout.css +256 -0
  19. data/app/assets/stylesheets/railspress/admin/lists.css +24 -0
  20. data/app/assets/stylesheets/railspress/admin/page.css +111 -0
  21. data/app/assets/stylesheets/railspress/admin/responsive.css +174 -0
  22. data/app/assets/stylesheets/railspress/admin/stats.css +43 -0
  23. data/app/assets/stylesheets/railspress/admin/tables.css +163 -0
  24. data/app/assets/stylesheets/railspress/admin/utilities.css +202 -0
  25. data/app/assets/stylesheets/railspress/admin/variables.css +58 -0
  26. data/app/assets/stylesheets/railspress/application.css +44 -13
  27. data/app/controllers/railspress/admin/base_controller.rb +6 -3
  28. data/app/controllers/railspress/admin/categories_controller.rb +1 -1
  29. data/app/controllers/railspress/admin/cms_transfers_controller.rb +49 -0
  30. data/app/controllers/railspress/admin/content_element_versions_controller.rb +12 -0
  31. data/app/controllers/railspress/admin/content_elements_controller.rb +143 -0
  32. data/app/controllers/railspress/admin/content_groups_controller.rb +69 -0
  33. data/app/controllers/railspress/admin/dashboard_controller.rb +6 -0
  34. data/app/controllers/railspress/admin/entities_controller.rb +157 -0
  35. data/app/controllers/railspress/admin/exports_controller.rb +55 -0
  36. data/app/controllers/railspress/admin/focal_points_controller.rb +100 -0
  37. data/app/controllers/railspress/admin/imports_controller.rb +63 -0
  38. data/app/controllers/railspress/admin/posts_controller.rb +58 -4
  39. data/app/controllers/railspress/admin/prototypes_controller.rb +30 -0
  40. data/app/controllers/railspress/admin/tags_controller.rb +1 -1
  41. data/app/controllers/railspress/application_controller.rb +1 -0
  42. data/app/helpers/railspress/admin_helper.rb +733 -0
  43. data/app/helpers/railspress/application_helper.rb +23 -0
  44. data/app/helpers/railspress/cms_helper.rb +319 -0
  45. data/app/javascript/railspress/controllers/cms_inline_editor_controller.js +147 -0
  46. data/app/javascript/railspress/controllers/content_element_form_controller.js +15 -0
  47. data/app/javascript/railspress/controllers/crop_controller.js +224 -0
  48. data/app/javascript/railspress/controllers/dropzone_controller.js +261 -0
  49. data/app/javascript/railspress/controllers/focal_point_controller.js +124 -0
  50. data/app/javascript/railspress/controllers/image_section_controller.js +94 -0
  51. data/app/javascript/railspress/controllers/index.js +37 -0
  52. data/app/javascript/railspress/index.js +62 -0
  53. data/app/jobs/railspress/export_posts_job.rb +16 -0
  54. data/app/jobs/railspress/import_posts_job.rb +44 -0
  55. data/app/models/concerns/railspress/has_focal_point.rb +242 -0
  56. data/app/models/concerns/railspress/soft_deletable.rb +23 -0
  57. data/app/models/concerns/railspress/taggable.rb +23 -0
  58. data/app/models/railspress/content_element.rb +103 -0
  59. data/app/models/railspress/content_element_version.rb +32 -0
  60. data/app/models/railspress/content_group.rb +39 -0
  61. data/app/models/railspress/export.rb +67 -0
  62. data/app/models/railspress/focal_point.rb +70 -0
  63. data/app/models/railspress/import.rb +65 -0
  64. data/app/models/railspress/post.rb +102 -15
  65. data/app/models/railspress/post_export_processor.rb +162 -0
  66. data/app/models/railspress/post_import_processor.rb +382 -0
  67. data/app/models/railspress/tag.rb +10 -3
  68. data/app/models/railspress/tagging.rb +11 -0
  69. data/app/services/railspress/content_export_service.rb +122 -0
  70. data/app/services/railspress/content_import_service.rb +228 -0
  71. data/app/views/action_text/attachables/_remote_image.html.erb +8 -0
  72. data/app/views/active_storage/blobs/_blob.html.erb +1 -1
  73. data/app/views/layouts/railspress/admin.html.erb +3 -1
  74. data/app/views/railspress/admin/categories/index.html.erb +11 -15
  75. data/app/views/railspress/admin/cms_transfers/show.html.erb +167 -0
  76. data/app/views/railspress/admin/content_element_versions/show.html.erb +42 -0
  77. data/app/views/railspress/admin/content_elements/_form.html.erb +71 -0
  78. data/app/views/railspress/admin/content_elements/_inline_form.html.erb +32 -0
  79. data/app/views/railspress/admin/content_elements/_inline_form_frame.html.erb +6 -0
  80. data/app/views/railspress/admin/content_elements/edit.html.erb +6 -0
  81. data/app/views/railspress/admin/content_elements/index.html.erb +74 -0
  82. data/app/views/railspress/admin/content_elements/new.html.erb +6 -0
  83. data/app/views/railspress/admin/content_elements/show.html.erb +124 -0
  84. data/app/views/railspress/admin/content_groups/_form.html.erb +9 -0
  85. data/app/views/railspress/admin/content_groups/edit.html.erb +6 -0
  86. data/app/views/railspress/admin/content_groups/index.html.erb +42 -0
  87. data/app/views/railspress/admin/content_groups/new.html.erb +6 -0
  88. data/app/views/railspress/admin/content_groups/show.html.erb +92 -0
  89. data/app/views/railspress/admin/dashboard/index.html.erb +36 -1
  90. data/app/views/railspress/admin/entities/_form.html.erb +53 -0
  91. data/app/views/railspress/admin/entities/edit.html.erb +4 -0
  92. data/app/views/railspress/admin/entities/index.html.erb +74 -0
  93. data/app/views/railspress/admin/entities/new.html.erb +4 -0
  94. data/app/views/railspress/admin/entities/show.html.erb +117 -0
  95. data/app/views/railspress/admin/exports/show.html.erb +62 -0
  96. data/app/views/railspress/admin/imports/_instructions.html.erb +56 -0
  97. data/app/views/railspress/admin/imports/show.html.erb +137 -0
  98. data/app/views/railspress/admin/posts/_form.html.erb +102 -28
  99. data/app/views/railspress/admin/posts/_post_row.html.erb +40 -0
  100. data/app/views/railspress/admin/posts/index.html.erb +47 -36
  101. data/app/views/railspress/admin/posts/show.html.erb +55 -19
  102. data/app/views/railspress/admin/prototypes/image_section.html.erb +42 -0
  103. data/app/views/railspress/admin/shared/_dropzone.html.erb +84 -0
  104. data/app/views/railspress/admin/shared/_focal_point_editor.html.erb +102 -0
  105. data/app/views/railspress/admin/shared/_image_section.html.erb +159 -0
  106. data/app/views/railspress/admin/shared/_image_section_compact.html.erb +90 -0
  107. data/app/views/railspress/admin/shared/_image_section_editor.html.erb +171 -0
  108. data/app/views/railspress/admin/shared/_image_section_v2.html.erb +205 -0
  109. data/app/views/railspress/admin/shared/_sidebar.html.erb +73 -5
  110. data/app/views/railspress/admin/tags/index.html.erb +12 -16
  111. data/config/brakeman.ignore +18 -0
  112. data/config/importmap.rb +23 -0
  113. data/config/routes.rb +62 -1
  114. data/db/migrate/20241218000004_create_railspress_post_tags.rb +1 -1
  115. data/db/migrate/20241218000005_create_railspress_imports.rb +21 -0
  116. data/db/migrate/20241218000006_create_railspress_exports.rb +20 -0
  117. data/db/migrate/20241218000007_create_railspress_taggings.rb +20 -0
  118. data/db/migrate/20241218000008_drop_railspress_post_tags.rb +14 -0
  119. data/db/migrate/20241218000010_add_reading_time_to_railspress_posts.rb +5 -0
  120. data/db/migrate/20250105000002_create_railspress_focal_points.rb +20 -0
  121. data/db/migrate/20260206000001_create_railspress_content_groups.rb +18 -0
  122. data/db/migrate/20260206000002_create_railspress_content_elements.rb +21 -0
  123. data/db/migrate/20260206000003_create_railspress_content_element_versions.rb +20 -0
  124. data/db/migrate/20260207000001_add_unique_index_to_content_elements.rb +11 -0
  125. data/db/migrate/20260211112812_add_image_hint_to_railspress_content_elements.rb +7 -0
  126. data/db/migrate/20260211154040_add_required_to_railspress_content_elements.rb +5 -0
  127. data/lib/generators/railspress/entity/entity_generator.rb +89 -0
  128. data/lib/generators/railspress/entity/templates/migration.rb.tt +13 -0
  129. data/lib/generators/railspress/entity/templates/model.rb.tt +21 -0
  130. data/lib/generators/railspress/install/install_generator.rb +51 -40
  131. data/lib/generators/railspress/install/templates/initializer.rb +29 -0
  132. data/lib/railspress/engine.rb +38 -0
  133. data/lib/railspress/entity.rb +239 -0
  134. data/lib/railspress/version.rb +1 -1
  135. data/lib/railspress.rb +198 -8
  136. data/lib/tasks/railspress_tasks.rake +49 -4
  137. metadata +215 -21
  138. data/MIT-LICENSE +0 -20
  139. data/app/assets/stylesheets/railspress/admin.css +0 -1207
  140. data/app/models/railspress/post_tag.rb +0 -8
@@ -0,0 +1,801 @@
1
+ /**
2
+ * Focal Point Editor Styles
3
+ * =========================
4
+ * Styles for the image focal point picker, dropzone, and image section components.
5
+ */
6
+
7
+ /* =================================
8
+ Screen Reader Only (Utility)
9
+ ================================= */
10
+
11
+ .rp-sr-only {
12
+ position: absolute;
13
+ width: 1px;
14
+ height: 1px;
15
+ padding: 0;
16
+ margin: -1px;
17
+ overflow: hidden;
18
+ clip: rect(0, 0, 0, 0);
19
+ white-space: nowrap;
20
+ border: 0;
21
+ }
22
+
23
+ /* =================================
24
+ Image Section
25
+ ================================= */
26
+
27
+ .rp-image-section {
28
+ margin-bottom: var(--rp-space-lg);
29
+ }
30
+
31
+ /* When inside a card wrapper, remove margin and let card provide styling */
32
+ .rp-image-section-card .rp-image-section {
33
+ margin-bottom: 0;
34
+ }
35
+
36
+ .rp-image-section-card .rp-image-section__details {
37
+ background: none;
38
+ box-shadow: none;
39
+ border-radius: 0;
40
+ }
41
+
42
+ .rp-image-section__label {
43
+ margin-bottom: var(--rp-space-sm);
44
+ }
45
+
46
+ .rp-image-section__label .rp-label {
47
+ margin-bottom: 0;
48
+ }
49
+
50
+ /* Compact view - card with full-width image preview */
51
+ .rp-image-section__details {
52
+ background: var(--rp-bg-elevated);
53
+ border-radius: var(--rp-radius);
54
+ box-shadow: var(--rp-shadow-md);
55
+ overflow: hidden;
56
+ }
57
+
58
+ .rp-image-section__compact {
59
+ position: relative;
60
+ display: block;
61
+ cursor: pointer;
62
+ }
63
+
64
+ /* Full-width image preview */
65
+ .rp-image-section__preview {
66
+ position: relative;
67
+ width: 100%;
68
+ aspect-ratio: 16 / 9;
69
+ overflow: hidden;
70
+ background: #1a1a1a;
71
+ }
72
+
73
+ .rp-image-section__preview img {
74
+ width: 100%;
75
+ height: 100%;
76
+ object-fit: cover;
77
+ }
78
+
79
+ /* Hover overlay with Edit button */
80
+ .rp-image-section__overlay {
81
+ position: absolute;
82
+ inset: 0;
83
+ display: flex;
84
+ align-items: center;
85
+ justify-content: center;
86
+ background: rgba(0, 0, 0, 0.5);
87
+ opacity: 0;
88
+ transition: opacity 0.15s ease;
89
+ }
90
+
91
+ .rp-image-section__compact:hover .rp-image-section__overlay {
92
+ opacity: 1;
93
+ }
94
+
95
+ .rp-image-section__overlay .rp-btn {
96
+ background: white;
97
+ color: var(--rp-text);
98
+ border: none;
99
+ }
100
+
101
+ .rp-image-section__overlay .rp-btn:hover {
102
+ background: var(--rp-bg-hover);
103
+ }
104
+
105
+ /* Focal point indicator below image */
106
+ .rp-image-section__footer {
107
+ padding: var(--rp-space-sm) var(--rp-space-md);
108
+ display: flex;
109
+ align-items: center;
110
+ justify-content: space-between;
111
+ border-top: 1px solid var(--rp-border);
112
+ }
113
+
114
+ /* Legacy styles - kept for compatibility */
115
+ .rp-image-section__thumb {
116
+ width: 120px;
117
+ height: 80px;
118
+ border-radius: calc(var(--rp-radius) - 2px);
119
+ overflow: hidden;
120
+ background: #1a1a1a;
121
+ flex-shrink: 0;
122
+ }
123
+
124
+ .rp-image-section__thumb img {
125
+ width: 100%;
126
+ height: 100%;
127
+ object-fit: cover;
128
+ }
129
+
130
+ .rp-image-section__info {
131
+ flex: 1;
132
+ display: flex;
133
+ flex-direction: column;
134
+ justify-content: center;
135
+ gap: var(--rp-space-xs);
136
+ }
137
+
138
+ .rp-image-section__filename {
139
+ font-weight: 500;
140
+ color: var(--rp-text);
141
+ font-size: 0.875rem;
142
+ }
143
+
144
+ .rp-image-section__meta {
145
+ font-size: 0.75rem;
146
+ color: var(--rp-text-muted);
147
+ }
148
+
149
+ .rp-image-section__focal-indicator {
150
+ display: inline-flex;
151
+ align-items: center;
152
+ gap: var(--rp-space-xs);
153
+ font-size: 0.75rem;
154
+ color: var(--rp-primary);
155
+ margin-top: var(--rp-space-xs);
156
+ }
157
+
158
+ .rp-image-section__focal-indicator svg {
159
+ flex-shrink: 0;
160
+ }
161
+
162
+ .rp-image-section__toggle {
163
+ display: flex;
164
+ flex-direction: column;
165
+ justify-content: center;
166
+ }
167
+
168
+ /* Editor panel */
169
+ .rp-image-section__editor {
170
+ background: var(--rp-bg-elevated);
171
+ }
172
+
173
+ .rp-image-section__editor-header {
174
+ display: flex;
175
+ align-items: center;
176
+ justify-content: space-between;
177
+ flex-wrap: wrap;
178
+ gap: var(--rp-space-sm);
179
+ padding: var(--rp-space-md) var(--rp-space-lg);
180
+ background: var(--rp-bg);
181
+ border-bottom: 1px solid var(--rp-border);
182
+ }
183
+
184
+ .rp-image-section__editor-title {
185
+ font-weight: 600;
186
+ font-size: 0.9375rem;
187
+ color: var(--rp-text);
188
+ }
189
+
190
+ .rp-image-section__editor-actions {
191
+ display: flex;
192
+ gap: var(--rp-space-sm);
193
+ }
194
+
195
+ .rp-image-section__editor-body {
196
+ padding: var(--rp-space-lg);
197
+ }
198
+
199
+ /* =================================
200
+ Focal Point Editor
201
+ ================================= */
202
+
203
+ .rp-focal-editor__layout {
204
+ display: grid;
205
+ grid-template-columns: 1fr 280px;
206
+ gap: var(--rp-space-lg);
207
+ }
208
+
209
+ @media (max-width: 900px) {
210
+ .rp-focal-editor__layout {
211
+ grid-template-columns: 1fr;
212
+ }
213
+ }
214
+
215
+ .rp-focal-editor__source {
216
+ position: relative;
217
+ }
218
+
219
+ .rp-focal-editor__image-wrap {
220
+ position: relative;
221
+ border-radius: var(--rp-radius);
222
+ overflow: hidden;
223
+ cursor: crosshair;
224
+ background: #1a1a1a;
225
+ }
226
+
227
+ .rp-focal-editor__image-wrap:focus {
228
+ outline: 2px solid var(--rp-primary);
229
+ outline-offset: 2px;
230
+ }
231
+
232
+ .rp-focal-editor__image {
233
+ display: block;
234
+ width: 100%;
235
+ height: auto;
236
+ }
237
+
238
+ .rp-focal-editor__crosshair {
239
+ position: absolute;
240
+ width: 28px;
241
+ height: 28px;
242
+ margin-left: -14px;
243
+ margin-top: -14px;
244
+ pointer-events: none;
245
+ transition: left 0.1s ease, top 0.1s ease;
246
+ }
247
+
248
+ .rp-focal-editor__crosshair::before {
249
+ content: "";
250
+ position: absolute;
251
+ inset: 0;
252
+ border: 2px solid white;
253
+ border-radius: 50%;
254
+ box-shadow: 0 0 0 2px rgba(0, 0, 0, 0.4), inset 0 0 0 2px rgba(0, 0, 0, 0.2);
255
+ }
256
+
257
+ .rp-focal-editor__crosshair::after {
258
+ content: "";
259
+ position: absolute;
260
+ left: 50%;
261
+ top: 50%;
262
+ width: 6px;
263
+ height: 6px;
264
+ margin: -3px;
265
+ background: white;
266
+ border-radius: 50%;
267
+ box-shadow: 0 0 4px rgba(0, 0, 0, 0.5);
268
+ }
269
+
270
+ .rp-focal-editor__hint {
271
+ display: flex;
272
+ align-items: center;
273
+ justify-content: space-between;
274
+ margin-top: var(--rp-space-sm);
275
+ font-size: 0.8125rem;
276
+ color: var(--rp-text-muted);
277
+ }
278
+
279
+ .rp-focal-editor__coords {
280
+ font-family: var(--rp-font-mono);
281
+ font-size: 0.75rem;
282
+ padding: 2px 6px;
283
+ background: var(--rp-bg);
284
+ border-radius: 3px;
285
+ }
286
+
287
+ .rp-focal-editor__actions {
288
+ display: flex;
289
+ gap: var(--rp-space-sm);
290
+ margin-top: var(--rp-space-md);
291
+ }
292
+
293
+ /* Preview column */
294
+ .rp-focal-editor__previews {
295
+ display: flex;
296
+ flex-direction: column;
297
+ gap: var(--rp-space-md);
298
+ }
299
+
300
+ .rp-focal-editor__previews-title {
301
+ font-size: 0.75rem;
302
+ font-weight: 600;
303
+ text-transform: uppercase;
304
+ letter-spacing: 0.05em;
305
+ color: var(--rp-text-muted);
306
+ }
307
+
308
+ .rp-focal-editor__preview {
309
+ background: var(--rp-bg);
310
+ border: 1px solid var(--rp-border);
311
+ border-radius: var(--rp-radius);
312
+ overflow: hidden;
313
+ }
314
+
315
+ .rp-focal-editor__preview-image {
316
+ background: #1a1a1a;
317
+ overflow: hidden;
318
+ }
319
+
320
+ .rp-focal-editor__preview-image img {
321
+ display: block;
322
+ width: 100%;
323
+ height: 100%;
324
+ object-fit: cover;
325
+ transition: object-position 0.1s ease;
326
+ }
327
+
328
+ .rp-focal-editor__preview-label {
329
+ display: flex;
330
+ align-items: center;
331
+ justify-content: space-between;
332
+ padding: var(--rp-space-xs) var(--rp-space-sm);
333
+ font-size: 0.75rem;
334
+ }
335
+
336
+ .rp-focal-editor__preview-name {
337
+ font-weight: 500;
338
+ color: var(--rp-text);
339
+ }
340
+
341
+ .rp-focal-editor__preview-ratio {
342
+ color: var(--rp-text-muted);
343
+ font-family: var(--rp-font-mono);
344
+ }
345
+
346
+ /* =================================
347
+ Dropzone
348
+ ================================= */
349
+
350
+ .rp-dropzone {
351
+ position: relative;
352
+ background: transparent;
353
+ }
354
+
355
+ .rp-dropzone__area {
356
+ text-align: center;
357
+ }
358
+
359
+ .rp-dropzone--dragging {
360
+ border-color: var(--rp-primary);
361
+ background: var(--rp-primary-light);
362
+ }
363
+
364
+ .rp-dropzone__icon {
365
+ width: 40px;
366
+ height: 40px;
367
+ margin: 0 auto var(--rp-space-sm);
368
+ color: var(--rp-text-muted);
369
+ }
370
+
371
+ .rp-dropzone__prompt {
372
+ font-size: 0.875rem;
373
+ color: var(--rp-text-muted);
374
+ margin: 0 0 var(--rp-space-xs);
375
+ }
376
+
377
+ .rp-dropzone__prompt strong {
378
+ color: var(--rp-primary);
379
+ }
380
+
381
+ .rp-dropzone__hint {
382
+ font-size: 0.75rem;
383
+ color: var(--rp-text-muted);
384
+ margin: 0;
385
+ }
386
+
387
+ .rp-dropzone__preview {
388
+ position: relative;
389
+ border: 1px solid var(--rp-border);
390
+ border-radius: var(--rp-radius);
391
+ overflow: hidden;
392
+ background: #1a1a1a;
393
+ }
394
+
395
+ .rp-dropzone__preview-image {
396
+ display: block;
397
+ width: 100%;
398
+ height: auto;
399
+ max-height: 200px;
400
+ object-fit: contain;
401
+ }
402
+
403
+ .rp-dropzone__remove {
404
+ position: absolute;
405
+ top: var(--rp-space-sm);
406
+ right: var(--rp-space-sm);
407
+ background: rgba(0, 0, 0, 0.7);
408
+ color: white;
409
+ }
410
+
411
+ .rp-dropzone__remove:hover {
412
+ background: rgba(0, 0, 0, 0.9);
413
+ }
414
+
415
+ .rp-dropzone__progress {
416
+ display: flex;
417
+ align-items: center;
418
+ gap: var(--rp-space-sm);
419
+ padding: var(--rp-space-md) 0 0;
420
+ }
421
+
422
+ .rp-dropzone__progress[hidden] {
423
+ display: none;
424
+ }
425
+
426
+ .rp-dropzone__progress-bar {
427
+ flex: 1;
428
+ height: 6px;
429
+ background: var(--rp-border);
430
+ border-radius: 3px;
431
+ overflow: hidden;
432
+ position: relative;
433
+ }
434
+
435
+ .rp-dropzone__progress-bar::after {
436
+ content: "";
437
+ position: absolute;
438
+ left: 0;
439
+ top: 0;
440
+ height: 100%;
441
+ width: var(--progress, 0%);
442
+ background: var(--rp-primary);
443
+ transition: width 0.2s ease;
444
+ }
445
+
446
+ .rp-dropzone__progress-text {
447
+ font-size: 0.75rem;
448
+ font-family: var(--rp-font-mono);
449
+ color: var(--rp-text-muted);
450
+ min-width: 3em;
451
+ text-align: right;
452
+ }
453
+
454
+ .rp-dropzone__error {
455
+ padding: var(--rp-space-sm) var(--rp-space-md);
456
+ background: var(--rp-danger-light);
457
+ color: var(--rp-danger);
458
+ border-radius: var(--rp-radius);
459
+ font-size: 0.875rem;
460
+ margin-top: var(--rp-space-sm);
461
+ }
462
+
463
+ /* =================================
464
+ Advanced Section
465
+ ================================= */
466
+
467
+ .rp-advanced-section {
468
+ margin-top: var(--rp-space-lg);
469
+ border-top: 1px solid var(--rp-border);
470
+ padding-top: var(--rp-space-md);
471
+ }
472
+
473
+ .rp-advanced-toggle {
474
+ display: flex;
475
+ align-items: center;
476
+ gap: var(--rp-space-sm);
477
+ font-size: 0.8125rem;
478
+ color: var(--rp-text-muted);
479
+ cursor: pointer;
480
+ list-style: none;
481
+ }
482
+
483
+ .rp-advanced-toggle::-webkit-details-marker {
484
+ display: none;
485
+ }
486
+
487
+ .rp-advanced-toggle:hover {
488
+ color: var(--rp-text);
489
+ }
490
+
491
+ .rp-advanced-toggle svg {
492
+ transition: transform 0.2s ease;
493
+ }
494
+
495
+ .rp-advanced-section[open] .rp-advanced-toggle svg {
496
+ transform: rotate(180deg);
497
+ }
498
+
499
+ .rp-advanced-content {
500
+ padding: var(--rp-space-md) 0;
501
+ }
502
+
503
+ /* Context overrides grid */
504
+ .rp-context-overrides {
505
+ display: grid;
506
+ grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
507
+ gap: var(--rp-space-md);
508
+ margin-top: var(--rp-space-md);
509
+ }
510
+
511
+ .rp-context-override {
512
+ padding: var(--rp-space-md);
513
+ background: var(--rp-bg);
514
+ border: 1px solid var(--rp-border);
515
+ border-radius: var(--rp-radius);
516
+ }
517
+
518
+ .rp-context-override__header {
519
+ display: flex;
520
+ align-items: center;
521
+ justify-content: space-between;
522
+ margin-bottom: var(--rp-space-sm);
523
+ }
524
+
525
+ .rp-context-override__name {
526
+ font-weight: 500;
527
+ font-size: 0.875rem;
528
+ }
529
+
530
+ .rp-context-override__badge {
531
+ font-size: 0.6875rem;
532
+ padding: 2px 6px;
533
+ border-radius: 3px;
534
+ background: var(--rp-primary-light);
535
+ color: var(--rp-primary);
536
+ }
537
+
538
+ .rp-context-override__badge--custom {
539
+ background: var(--rp-success-light);
540
+ color: var(--rp-success);
541
+ }
542
+
543
+ .rp-context-override__preview {
544
+ background: #1a1a1a;
545
+ border-radius: calc(var(--rp-radius) - 2px);
546
+ overflow: hidden;
547
+ margin-bottom: var(--rp-space-sm);
548
+ }
549
+
550
+ .rp-context-override__preview img {
551
+ display: block;
552
+ width: 100%;
553
+ object-fit: cover;
554
+ }
555
+
556
+ .rp-context-override__actions {
557
+ display: flex;
558
+ gap: var(--rp-space-xs);
559
+ }
560
+
561
+ /* =================================
562
+ Checkbox Inline (for remove button)
563
+ ================================= */
564
+
565
+ .rp-checkbox-inline {
566
+ display: inline-flex;
567
+ align-items: center;
568
+ gap: var(--rp-space-xs);
569
+ cursor: pointer;
570
+ }
571
+
572
+ .rp-checkbox-inline input[type="checkbox"] {
573
+ width: auto;
574
+ margin: 0;
575
+ }
576
+
577
+ /* =================================
578
+ Inline Form (for Change button)
579
+ ================================= */
580
+
581
+ .rp-inline-form {
582
+ display: inline;
583
+ }
584
+
585
+ /* =================================
586
+ Danger Button Variant (Outline)
587
+ ================================= */
588
+
589
+ .rp-btn--outline.rp-btn--danger {
590
+ color: var(--rp-danger, #dc2626);
591
+ border-color: var(--rp-danger, #dc2626);
592
+ background: transparent;
593
+ }
594
+
595
+ .rp-btn--outline.rp-btn--danger:hover {
596
+ background: var(--rp-danger, #dc2626);
597
+ color: white;
598
+ }
599
+
600
+ /* =================================
601
+ Image Section V2
602
+ ================================= */
603
+
604
+ .rp-image-section-v2 {
605
+ background: var(--rp-bg);
606
+ border: 1px solid var(--rp-border);
607
+ border-radius: var(--rp-radius);
608
+ margin-bottom: var(--rp-space-lg);
609
+ overflow: hidden;
610
+ }
611
+
612
+ .rp-image-section-v2__header {
613
+ display: flex;
614
+ align-items: center;
615
+ justify-content: space-between;
616
+ padding: var(--rp-space-sm) var(--rp-space-md);
617
+ border-bottom: 1px solid var(--rp-border);
618
+ background: var(--rp-bg-elevated);
619
+ }
620
+
621
+ .rp-image-section-v2__header .rp-label {
622
+ margin-bottom: 0;
623
+ font-size: 0.875rem;
624
+ }
625
+
626
+ /* Compact view */
627
+ .rp-image-section-v2__compact {
628
+ display: flex;
629
+ gap: var(--rp-space-md);
630
+ padding: var(--rp-space-md);
631
+ cursor: pointer;
632
+ transition: background-color 0.15s ease;
633
+ }
634
+
635
+ .rp-image-section-v2__compact:hover {
636
+ background: var(--rp-bg-hover, rgba(0, 0, 0, 0.02));
637
+ }
638
+
639
+ .rp-image-section-v2__thumb {
640
+ width: 120px;
641
+ height: 80px;
642
+ border-radius: calc(var(--rp-radius) - 2px);
643
+ overflow: hidden;
644
+ background: #1a1a1a;
645
+ flex-shrink: 0;
646
+ }
647
+
648
+ .rp-image-section-v2__thumb img {
649
+ width: 100%;
650
+ height: 100%;
651
+ object-fit: cover;
652
+ }
653
+
654
+ .rp-image-section-v2__info {
655
+ flex: 1;
656
+ display: flex;
657
+ flex-direction: column;
658
+ justify-content: center;
659
+ gap: var(--rp-space-xs);
660
+ }
661
+
662
+ .rp-image-section-v2__filename {
663
+ font-weight: 500;
664
+ color: var(--rp-text);
665
+ font-size: 0.875rem;
666
+ }
667
+
668
+ .rp-image-section-v2__meta {
669
+ font-size: 0.75rem;
670
+ color: var(--rp-text-muted);
671
+ }
672
+
673
+ .rp-image-section-v2__focal-indicator {
674
+ display: inline-flex;
675
+ align-items: center;
676
+ gap: var(--rp-space-xs);
677
+ font-size: 0.75rem;
678
+ color: var(--rp-primary);
679
+ margin-top: var(--rp-space-xs);
680
+ }
681
+
682
+ .rp-image-section-v2__focal-indicator svg {
683
+ flex-shrink: 0;
684
+ }
685
+
686
+ /* Editor panel */
687
+ .rp-image-section-v2__editor {
688
+ background: var(--rp-bg-elevated);
689
+ }
690
+
691
+ .rp-image-section-v2__editor--entering {
692
+ animation: rp-slide-down 0.2s ease-out;
693
+ }
694
+
695
+ @keyframes rp-slide-down {
696
+ from {
697
+ opacity: 0;
698
+ transform: translateY(-8px);
699
+ }
700
+ to {
701
+ opacity: 1;
702
+ transform: translateY(0);
703
+ }
704
+ }
705
+
706
+ .rp-image-section-v2__editor-header {
707
+ display: flex;
708
+ align-items: center;
709
+ justify-content: space-between;
710
+ flex-wrap: wrap;
711
+ gap: var(--rp-space-sm);
712
+ padding: var(--rp-space-md) var(--rp-space-lg);
713
+ background: var(--rp-bg);
714
+ border-bottom: 1px solid var(--rp-border);
715
+ }
716
+
717
+ .rp-image-section-v2__editor-title {
718
+ font-weight: 600;
719
+ font-size: 0.9375rem;
720
+ color: var(--rp-text);
721
+ }
722
+
723
+ .rp-image-section-v2__editor-actions {
724
+ display: flex;
725
+ gap: var(--rp-space-sm);
726
+ }
727
+
728
+ .rp-image-section-v2__editor-body {
729
+ padding: var(--rp-space-lg);
730
+ }
731
+
732
+ /* Dropzone */
733
+ .rp-image-section-v2__dropzone {
734
+ display: flex;
735
+ flex-direction: column;
736
+ align-items: center;
737
+ justify-content: center;
738
+ padding: var(--rp-space-2xl);
739
+ text-align: center;
740
+ cursor: pointer;
741
+ transition: background-color 0.2s ease;
742
+ }
743
+
744
+ .rp-image-section-v2__dropzone:hover {
745
+ background: var(--rp-primary-light);
746
+ }
747
+
748
+ .rp-image-section-v2__dropzone-icon {
749
+ width: 48px;
750
+ height: 48px;
751
+ margin-bottom: var(--rp-space-md);
752
+ color: var(--rp-text-muted);
753
+ }
754
+
755
+ .rp-image-section-v2__dropzone-text {
756
+ font-size: 0.875rem;
757
+ color: var(--rp-text-muted);
758
+ margin: 0;
759
+ line-height: 1.6;
760
+ }
761
+
762
+ .rp-image-section-v2__dropzone-text strong {
763
+ color: var(--rp-primary);
764
+ }
765
+
766
+ /* Expanded state modifier */
767
+ .rp-image-section-v2--expanded {
768
+ box-shadow: var(--rp-shadow-md);
769
+ }
770
+
771
+ /* Mobile responsive */
772
+ @media (max-width: 768px) {
773
+ .rp-image-section-v2__compact {
774
+ flex-direction: column;
775
+ }
776
+
777
+ .rp-image-section-v2__thumb {
778
+ width: 100%;
779
+ height: 120px;
780
+ }
781
+
782
+ .rp-image-section-v2__editor-header {
783
+ flex-direction: column;
784
+ align-items: stretch;
785
+ gap: var(--rp-space-md);
786
+ }
787
+
788
+ .rp-image-section-v2__editor-actions {
789
+ flex-wrap: wrap;
790
+ }
791
+
792
+ .rp-image-section-v2__editor-actions .rp-btn {
793
+ flex: 1;
794
+ min-width: 80px;
795
+ }
796
+
797
+ /* Hide third preview on mobile */
798
+ .rp-image-section-v2 .rp-focal-editor__preview:nth-child(n+4) {
799
+ display: none;
800
+ }
801
+ }