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
@@ -1,1207 +0,0 @@
1
- /*
2
- * RailsPress Admin Styles
3
- * Vanilla CSS with rp- prefix for isolation
4
- * Minimal footprint for easy engine mounting
5
- */
6
-
7
- /* ============================================
8
- CSS Variables
9
- ============================================ */
10
-
11
- :root {
12
- /* Typography */
13
- --rp-font-display: 'Source Serif 4', Georgia, serif;
14
- --rp-font-body: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
15
- --rp-font-mono: 'SF Mono', Consolas, monospace;
16
-
17
- /* Colors - Warm Neutrals */
18
- --rp-sidebar-bg: #1a1d21;
19
- --rp-sidebar-hover: #2a2e33;
20
- --rp-sidebar-text: #a8adb3;
21
- --rp-sidebar-text-active: #ffffff;
22
-
23
- --rp-bg: #f8f7f5;
24
- --rp-bg-elevated: #ffffff;
25
- --rp-border: #e5e2dc;
26
- --rp-border-light: #f0ede8;
27
-
28
- --rp-text: #2c2a27;
29
- --rp-text-muted: #6b6860;
30
- --rp-text-light: #9a958c;
31
-
32
- /* Accents */
33
- --rp-primary: #3d5a80;
34
- --rp-primary-hover: #2c4a6e;
35
- --rp-primary-light: #e8eef4;
36
-
37
- --rp-success: #4a7c59;
38
- --rp-success-light: #e8f2eb;
39
-
40
- --rp-danger: #a63d40;
41
- --rp-danger-light: #f9ebeb;
42
-
43
- --rp-info-light: #f0f7fb;
44
-
45
- /* Spacing */
46
- --rp-space-xs: 0.25rem;
47
- --rp-space-sm: 0.5rem;
48
- --rp-space-md: 1rem;
49
- --rp-space-lg: 1.5rem;
50
- --rp-space-xl: 2rem;
51
- --rp-space-2xl: 3rem;
52
-
53
- /* Sizing */
54
- --rp-sidebar-width: 240px;
55
- --rp-header-height: 56px;
56
- --rp-radius: 6px;
57
-
58
- /* Shadows - Enhanced for depth */
59
- --rp-shadow-sm: 0 1px 3px rgba(44, 42, 39, 0.06), 0 1px 2px rgba(44, 42, 39, 0.04);
60
- --rp-shadow-md: 0 4px 16px rgba(44, 42, 39, 0.1), 0 2px 4px rgba(44, 42, 39, 0.06);
61
- --rp-shadow-lg: 0 8px 24px rgba(44, 42, 39, 0.12), 0 4px 8px rgba(44, 42, 39, 0.08);
62
- }
63
-
64
- /* ============================================
65
- Base
66
- ============================================ */
67
-
68
- @import url('https://fonts.googleapis.com/css2?family=Source+Serif+4:wght@600;700&display=swap');
69
-
70
- *, *::before, *::after {
71
- box-sizing: border-box;
72
- margin: 0;
73
- padding: 0;
74
- }
75
-
76
- html {
77
- font-size: 16px;
78
- -webkit-font-smoothing: antialiased;
79
- }
80
-
81
- body {
82
- font-family: var(--rp-font-body);
83
- font-size: 0.9375rem;
84
- line-height: 1.5;
85
- color: var(--rp-text);
86
- background: var(--rp-bg);
87
- }
88
-
89
- /* ============================================
90
- Layout
91
- ============================================ */
92
-
93
- .rp-admin-layout {
94
- display: flex;
95
- min-height: 100vh;
96
- }
97
-
98
- .rp-sidebar {
99
- position: fixed;
100
- top: 0;
101
- left: 0;
102
- width: var(--rp-sidebar-width);
103
- height: 100vh;
104
- background: var(--rp-sidebar-bg);
105
- z-index: 100;
106
- transition: transform 0.25s ease;
107
- overflow-y: auto;
108
- }
109
-
110
- .rp-sidebar-content {
111
- padding: var(--rp-space-lg);
112
- }
113
-
114
- .rp-logo {
115
- font-family: var(--rp-font-display);
116
- font-size: 1.375rem;
117
- font-weight: 700;
118
- color: var(--rp-sidebar-text-active);
119
- margin-bottom: var(--rp-space-2xl);
120
- letter-spacing: -0.01em;
121
- }
122
-
123
- .rp-nav {
124
- display: flex;
125
- flex-direction: column;
126
- gap: 2px;
127
- }
128
-
129
- .rp-nav-link {
130
- display: flex;
131
- align-items: center;
132
- gap: var(--rp-space-md);
133
- padding: 10px 12px;
134
- color: var(--rp-sidebar-text);
135
- text-decoration: none;
136
- font-size: 0.9375rem;
137
- font-weight: 500;
138
- border-radius: var(--rp-radius);
139
- transition: all 0.15s ease;
140
- }
141
-
142
- .rp-nav-link:hover {
143
- background: var(--rp-sidebar-hover);
144
- color: var(--rp-sidebar-text-active);
145
- }
146
-
147
- .rp-nav-link--active {
148
- background: var(--rp-sidebar-hover);
149
- color: var(--rp-sidebar-text-active);
150
- }
151
-
152
- .rp-nav-icon {
153
- width: 18px;
154
- height: 18px;
155
- opacity: 0.7;
156
- flex-shrink: 0;
157
- }
158
-
159
- .rp-nav-link:hover .rp-nav-icon,
160
- .rp-nav-link--active .rp-nav-icon {
161
- opacity: 1;
162
- }
163
-
164
- .rp-main {
165
- flex: 1;
166
- margin-left: var(--rp-sidebar-width);
167
- padding: var(--rp-space-xl) var(--rp-space-2xl);
168
- min-width: 0;
169
- }
170
-
171
- /* Mobile Header */
172
- .rp-mobile-header {
173
- display: none;
174
- position: fixed;
175
- top: 0;
176
- left: 0;
177
- right: 0;
178
- height: var(--rp-header-height);
179
- background: var(--rp-sidebar-bg);
180
- z-index: 90;
181
- padding: 0 var(--rp-space-md);
182
- align-items: center;
183
- justify-content: space-between;
184
- }
185
-
186
- .rp-hamburger {
187
- display: flex;
188
- flex-direction: column;
189
- justify-content: center;
190
- gap: 5px;
191
- width: 44px;
192
- height: 44px;
193
- background: transparent;
194
- border: none;
195
- cursor: pointer;
196
- padding: 10px;
197
- }
198
-
199
- .rp-hamburger span {
200
- display: block;
201
- width: 22px;
202
- height: 2px;
203
- background: var(--rp-sidebar-text-active);
204
- border-radius: 1px;
205
- }
206
-
207
- .rp-mobile-logo {
208
- font-family: var(--rp-font-display);
209
- font-size: 1.125rem;
210
- font-weight: 700;
211
- color: var(--rp-sidebar-text-active);
212
- }
213
-
214
- .rp-overlay {
215
- display: none;
216
- position: fixed;
217
- inset: 0;
218
- background: rgba(26, 29, 33, 0.5);
219
- z-index: 95;
220
- }
221
-
222
- .rp-overlay--visible {
223
- display: block;
224
- }
225
-
226
- /* ============================================
227
- Page Structure
228
- ============================================ */
229
-
230
- .rp-page-header {
231
- display: flex;
232
- align-items: center;
233
- justify-content: space-between;
234
- gap: var(--rp-space-lg);
235
- margin-bottom: var(--rp-space-xl);
236
- }
237
-
238
- .rp-page-title {
239
- font-family: var(--rp-font-display);
240
- font-size: 1.75rem;
241
- font-weight: 700;
242
- color: var(--rp-text);
243
- letter-spacing: 0;
244
- line-height: 1.2;
245
- }
246
-
247
- .rp-page-title--standalone {
248
- margin-bottom: var(--rp-space-xl);
249
- }
250
-
251
- .rp-page-actions {
252
- display: flex;
253
- gap: var(--rp-space-sm);
254
- flex-shrink: 0;
255
- }
256
-
257
- .rp-section {
258
- margin-bottom: var(--rp-space-xl);
259
- }
260
-
261
- .rp-section-header {
262
- display: flex;
263
- align-items: center;
264
- gap: var(--rp-space-md);
265
- margin-bottom: var(--rp-space-md);
266
- padding-left: var(--rp-space-md);
267
- border-left: 3px solid var(--rp-primary);
268
- }
269
-
270
- .rp-section-title {
271
- font-family: var(--rp-font-body);
272
- font-size: 0.9375rem;
273
- font-weight: 600;
274
- color: var(--rp-text);
275
- letter-spacing: 0;
276
- }
277
-
278
- /* ============================================
279
- Cards
280
- ============================================ */
281
-
282
- .rp-card {
283
- background: var(--rp-bg-elevated);
284
- border-radius: var(--rp-radius);
285
- box-shadow: var(--rp-shadow-md);
286
- border: none;
287
- }
288
-
289
- .rp-card--padded {
290
- padding: var(--rp-space-xl);
291
- }
292
-
293
- /* ============================================
294
- Stats
295
- ============================================ */
296
-
297
- .rp-stats-grid {
298
- display: grid;
299
- grid-template-columns: repeat(3, 1fr);
300
- gap: var(--rp-space-md);
301
- margin-bottom: var(--rp-space-xl);
302
- }
303
-
304
- .rp-stat-card {
305
- background: var(--rp-bg-elevated);
306
- border-radius: var(--rp-radius);
307
- box-shadow: var(--rp-shadow-md);
308
- border: none;
309
- padding: var(--rp-space-lg);
310
- text-align: center;
311
- transition: transform 0.2s ease, box-shadow 0.2s ease;
312
- }
313
-
314
- .rp-stat-card:hover {
315
- transform: translateY(-2px);
316
- box-shadow: var(--rp-shadow-lg);
317
- }
318
-
319
- .rp-stat-value {
320
- font-family: var(--rp-font-body);
321
- font-size: 2.25rem;
322
- font-weight: 600;
323
- color: var(--rp-text);
324
- line-height: 1;
325
- margin-bottom: var(--rp-space-xs);
326
- }
327
-
328
- .rp-stat-label {
329
- font-size: 0.8125rem;
330
- color: var(--rp-text-muted);
331
- text-transform: uppercase;
332
- letter-spacing: 0.04em;
333
- font-weight: 500;
334
- }
335
-
336
- /* ============================================
337
- Tables
338
- ============================================ */
339
-
340
- .rp-table {
341
- width: 100%;
342
- border-collapse: collapse;
343
- }
344
-
345
- .rp-table th {
346
- text-align: left;
347
- padding: var(--rp-space-sm) var(--rp-space-md);
348
- font-size: 0.75rem;
349
- font-weight: 600;
350
- text-transform: uppercase;
351
- letter-spacing: 0.04em;
352
- color: var(--rp-text-muted);
353
- border-bottom: 1px solid var(--rp-border);
354
- background: var(--rp-bg);
355
- }
356
-
357
- .rp-table td {
358
- padding: var(--rp-space-md);
359
- border-bottom: 1px solid var(--rp-border-light);
360
- vertical-align: middle;
361
- }
362
-
363
- .rp-table tbody tr:hover {
364
- background: var(--rp-bg);
365
- }
366
-
367
- .rp-table tbody tr:last-child td {
368
- border-bottom: none;
369
- }
370
-
371
- .rp-table-primary {
372
- font-weight: 500;
373
- }
374
-
375
- .rp-table-secondary {
376
- color: var(--rp-text-muted);
377
- font-size: 0.875rem;
378
- }
379
-
380
- .rp-table-actions {
381
- text-align: right;
382
- white-space: nowrap;
383
- }
384
-
385
- .rp-table-actions .rp-link {
386
- margin-left: var(--rp-space-md);
387
- }
388
-
389
- .rp-table-actions .rp-link:first-child {
390
- margin-left: 0;
391
- }
392
-
393
- .rp-table--responsive {
394
- overflow-x: auto;
395
- }
396
-
397
- /* ============================================
398
- Forms - Core
399
- ============================================ */
400
-
401
- .rp-form {
402
- display: flex;
403
- flex-direction: column;
404
- }
405
-
406
- .rp-form--narrow {
407
- max-width: 560px;
408
- }
409
-
410
- .rp-form-layout {
411
- display: grid;
412
- grid-template-columns: 1fr 280px;
413
- gap: var(--rp-space-2xl);
414
- align-items: start;
415
- }
416
-
417
- .rp-form-main {
418
- display: flex;
419
- flex-direction: column;
420
- gap: var(--rp-space-lg);
421
- }
422
-
423
- .rp-form-sidebar {
424
- display: flex;
425
- flex-direction: column;
426
- gap: var(--rp-space-md);
427
- }
428
-
429
- .rp-form-group {
430
- display: flex;
431
- flex-direction: column;
432
- gap: 6px;
433
- }
434
-
435
- .rp-form-row {
436
- display: grid;
437
- grid-template-columns: repeat(2, 1fr);
438
- gap: var(--rp-space-md);
439
- }
440
-
441
- .rp-form-row--3 {
442
- grid-template-columns: repeat(3, 1fr);
443
- }
444
-
445
- .rp-form-actions {
446
- display: flex;
447
- gap: var(--rp-space-sm);
448
- padding-top: var(--rp-space-xl);
449
- margin-top: var(--rp-space-xl);
450
- border-top: 1px solid var(--rp-border-light);
451
- }
452
-
453
- .rp-form-errors {
454
- background: var(--rp-danger-light);
455
- border: 1px solid var(--rp-danger);
456
- border-radius: var(--rp-radius);
457
- padding: var(--rp-space-md);
458
- color: var(--rp-danger);
459
- font-size: 0.875rem;
460
- }
461
-
462
- .rp-form-errors ul {
463
- margin: 0;
464
- padding-left: var(--rp-space-lg);
465
- }
466
-
467
- /* Labels */
468
- .rp-label {
469
- font-size: 0.875rem;
470
- font-weight: 600;
471
- color: var(--rp-text);
472
- }
473
-
474
- .rp-label--lg {
475
- font-size: 1rem;
476
- }
477
-
478
- .rp-label--required::after {
479
- content: ' *';
480
- color: var(--rp-danger);
481
- }
482
-
483
- /* Inputs */
484
- .rp-input {
485
- width: 100%;
486
- padding: 10px 12px;
487
- font-family: var(--rp-font-body);
488
- font-size: 0.9375rem;
489
- color: var(--rp-text);
490
- background: var(--rp-bg-elevated);
491
- border: 1px solid var(--rp-border);
492
- border-radius: var(--rp-radius);
493
- transition: border-color 0.15s, box-shadow 0.15s;
494
- }
495
-
496
- .rp-input:focus {
497
- outline: none;
498
- border-color: var(--rp-primary);
499
- box-shadow: 0 0 0 3px var(--rp-primary-light);
500
- }
501
-
502
- .rp-input::placeholder {
503
- color: var(--rp-text-light);
504
- }
505
-
506
- .rp-input--sm {
507
- padding: 6px 10px;
508
- font-size: 0.875rem;
509
- }
510
-
511
- .rp-input--lg {
512
- padding: 14px 16px;
513
- font-size: 1.125rem;
514
- }
515
-
516
- .rp-input--title {
517
- font-family: var(--rp-font-display);
518
- font-size: 1.5rem;
519
- font-weight: 600;
520
- padding: 12px 14px;
521
- letter-spacing: -0.01em;
522
- }
523
-
524
- .rp-input--mono {
525
- font-family: var(--rp-font-mono);
526
- font-size: 0.875rem;
527
- }
528
-
529
- textarea.rp-input {
530
- min-height: 100px;
531
- resize: vertical;
532
- line-height: 1.5;
533
- }
534
-
535
- /* Select */
536
- .rp-select {
537
- width: 100%;
538
- padding: 10px 12px;
539
- padding-right: 36px;
540
- font-family: var(--rp-font-body);
541
- font-size: 0.9375rem;
542
- color: var(--rp-text);
543
- background: var(--rp-bg-elevated) url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'%3E%3Cpath fill='%236b6860' d='M6 8L1 3h10z'/%3E%3C/svg%3E") no-repeat right 12px center;
544
- border: 1px solid var(--rp-border);
545
- border-radius: var(--rp-radius);
546
- appearance: none;
547
- cursor: pointer;
548
- transition: border-color 0.15s, box-shadow 0.15s;
549
- }
550
-
551
- .rp-select:focus {
552
- outline: none;
553
- border-color: var(--rp-primary);
554
- box-shadow: 0 0 0 3px var(--rp-primary-light);
555
- }
556
-
557
- .rp-select--sm {
558
- padding: 6px 10px;
559
- padding-right: 32px;
560
- font-size: 0.875rem;
561
- }
562
-
563
- /* Checkbox & Radio */
564
- .rp-checkbox,
565
- .rp-radio {
566
- display: flex;
567
- align-items: flex-start;
568
- gap: var(--rp-space-sm);
569
- cursor: pointer;
570
- }
571
-
572
- .rp-checkbox input,
573
- .rp-radio input {
574
- width: 18px;
575
- height: 18px;
576
- margin: 0;
577
- flex-shrink: 0;
578
- cursor: pointer;
579
- accent-color: var(--rp-primary);
580
- }
581
-
582
- .rp-checkbox-label,
583
- .rp-radio-label {
584
- font-size: 0.9375rem;
585
- color: var(--rp-text);
586
- line-height: 1.4;
587
- }
588
-
589
- .rp-checkbox-description,
590
- .rp-radio-description {
591
- font-size: 0.8125rem;
592
- color: var(--rp-text-muted);
593
- margin-top: 2px;
594
- }
595
-
596
- .rp-checkbox-group,
597
- .rp-radio-group {
598
- display: flex;
599
- flex-direction: column;
600
- gap: var(--rp-space-sm);
601
- }
602
-
603
- .rp-checkbox-group--inline,
604
- .rp-radio-group--inline {
605
- flex-direction: row;
606
- flex-wrap: wrap;
607
- gap: var(--rp-space-lg);
608
- }
609
-
610
- /* Fieldset */
611
- .rp-fieldset {
612
- border: 1px solid var(--rp-border-light);
613
- border-radius: var(--rp-radius);
614
- padding: var(--rp-space-lg);
615
- background: var(--rp-bg);
616
- }
617
-
618
- .rp-fieldset-legend {
619
- font-size: 0.875rem;
620
- font-weight: 600;
621
- color: var(--rp-text);
622
- padding: 0 var(--rp-space-sm);
623
- margin-left: -var(--rp-space-sm);
624
- }
625
-
626
- /* Hint & Help */
627
- .rp-hint {
628
- font-size: 0.8125rem;
629
- color: var(--rp-text-muted);
630
- margin-top: 4px;
631
- }
632
-
633
- .rp-input-wrapper {
634
- position: relative;
635
- }
636
-
637
- .rp-input-prefix,
638
- .rp-input-suffix {
639
- position: absolute;
640
- top: 50%;
641
- transform: translateY(-50%);
642
- color: var(--rp-text-muted);
643
- font-size: 0.9375rem;
644
- pointer-events: none;
645
- }
646
-
647
- .rp-input-prefix {
648
- left: 12px;
649
- }
650
-
651
- .rp-input-suffix {
652
- right: 12px;
653
- }
654
-
655
- .rp-input--has-prefix {
656
- padding-left: 36px;
657
- }
658
-
659
- .rp-input--has-suffix {
660
- padding-right: 36px;
661
- }
662
-
663
- /* Rich text placeholder */
664
- .rp-rich-text {
665
- min-height: 670px;
666
- border: 1px solid var(--rp-border);
667
- border-radius: var(--rp-radius);
668
- background: var(--rp-bg-elevated);
669
- padding: var(--rp-space-md);
670
- }
671
-
672
- /* Sidebar sections */
673
- .rp-sidebar-section {
674
- background: var(--rp-info-light);
675
- border-radius: var(--rp-radius);
676
- padding: var(--rp-space-md);
677
- border: 1px solid #d8e8f0;
678
- }
679
-
680
- .rp-sidebar-section .rp-form-group {
681
- margin-bottom: var(--rp-space-md);
682
- }
683
-
684
- .rp-sidebar-section .rp-form-group:last-child {
685
- margin-bottom: 0;
686
- }
687
-
688
- .rp-sidebar-title {
689
- font-size: 0.6875rem;
690
- font-weight: 600;
691
- text-transform: uppercase;
692
- letter-spacing: 0.05em;
693
- color: var(--rp-text-muted);
694
- margin-bottom: var(--rp-space-md);
695
- }
696
-
697
- /* ============================================
698
- Buttons
699
- ============================================ */
700
-
701
- .rp-btn {
702
- display: inline-flex;
703
- align-items: center;
704
- justify-content: center;
705
- gap: var(--rp-space-sm);
706
- padding: 10px 20px;
707
- font-family: var(--rp-font-body);
708
- font-size: 0.875rem;
709
- font-weight: 600;
710
- text-decoration: none;
711
- border-radius: var(--rp-radius);
712
- border: 1px solid transparent;
713
- cursor: pointer;
714
- transition: all 0.15s;
715
- white-space: nowrap;
716
- }
717
-
718
- .rp-btn:focus {
719
- outline: none;
720
- box-shadow: 0 0 0 3px var(--rp-primary-light);
721
- }
722
-
723
- .rp-btn--primary {
724
- background: var(--rp-primary);
725
- color: white;
726
- box-shadow: 0 2px 6px rgba(61, 90, 128, 0.25);
727
- transition: all 0.15s ease;
728
- }
729
-
730
- .rp-btn--primary:hover {
731
- background: var(--rp-primary-hover);
732
- box-shadow: 0 4px 10px rgba(61, 90, 128, 0.35);
733
- transform: translateY(-1px);
734
- }
735
-
736
- .rp-btn--secondary {
737
- background: var(--rp-bg-elevated);
738
- color: var(--rp-text);
739
- border-color: var(--rp-border);
740
- }
741
-
742
- .rp-btn--secondary:hover {
743
- background: var(--rp-bg);
744
- border-color: var(--rp-text-muted);
745
- }
746
-
747
- .rp-btn--danger {
748
- background: var(--rp-danger);
749
- color: white;
750
- }
751
-
752
- .rp-btn--danger:hover {
753
- background: #8f3436;
754
- }
755
-
756
- .rp-btn--sm {
757
- padding: 6px 12px;
758
- font-size: 0.8125rem;
759
- }
760
-
761
- .rp-btn--lg {
762
- padding: 14px 28px;
763
- font-size: 1rem;
764
- }
765
-
766
- /* ============================================
767
- Links
768
- ============================================ */
769
-
770
- .rp-link {
771
- color: var(--rp-primary);
772
- text-decoration: none;
773
- font-weight: 500;
774
- }
775
-
776
- .rp-link:hover {
777
- text-decoration: underline;
778
- }
779
-
780
- .rp-link--danger {
781
- color: var(--rp-danger);
782
- background: none;
783
- border: none;
784
- padding: 0;
785
- font: inherit;
786
- cursor: pointer;
787
- }
788
-
789
- /* ============================================
790
- Badges & Tags
791
- ============================================ */
792
-
793
- .rp-badge {
794
- display: inline-flex;
795
- align-items: center;
796
- padding: 2px 10px;
797
- font-size: 0.6875rem;
798
- font-weight: 600;
799
- text-transform: uppercase;
800
- letter-spacing: 0.03em;
801
- border-radius: 999px;
802
- }
803
-
804
- .rp-badge--draft {
805
- background: var(--rp-bg);
806
- color: var(--rp-text-muted);
807
- border: 1px solid var(--rp-border);
808
- }
809
-
810
- .rp-badge--published {
811
- background: var(--rp-success-light);
812
- color: var(--rp-success);
813
- }
814
-
815
- .rp-tag {
816
- display: inline-flex;
817
- padding: 2px 8px;
818
- font-size: 0.75rem;
819
- font-weight: 500;
820
- background: var(--rp-primary-light);
821
- color: var(--rp-primary);
822
- border-radius: 4px;
823
- }
824
-
825
- .rp-tag-list {
826
- display: flex;
827
- flex-wrap: wrap;
828
- gap: var(--rp-space-xs);
829
- margin-top: var(--rp-space-xs);
830
- }
831
-
832
- /* ============================================
833
- Lists
834
- ============================================ */
835
-
836
- .rp-list {
837
- list-style: none;
838
- }
839
-
840
- .rp-list-item {
841
- display: flex;
842
- align-items: center;
843
- justify-content: space-between;
844
- padding: var(--rp-space-md);
845
- border-bottom: 1px solid var(--rp-border-light);
846
- }
847
-
848
- .rp-list-item:hover {
849
- background: var(--rp-bg);
850
- }
851
-
852
- .rp-list-item:last-child {
853
- border-bottom: none;
854
- }
855
-
856
- /* ============================================
857
- Flash Messages
858
- ============================================ */
859
-
860
- .rp-flash {
861
- padding: var(--rp-space-md) var(--rp-space-lg);
862
- border-radius: var(--rp-radius);
863
- margin-bottom: var(--rp-space-lg);
864
- font-weight: 500;
865
- display: flex;
866
- align-items: center;
867
- gap: var(--rp-space-sm);
868
- }
869
-
870
- .rp-flash--notice {
871
- background: var(--rp-success-light);
872
- color: var(--rp-success);
873
- border: 1px solid var(--rp-success);
874
- }
875
-
876
- .rp-flash--alert {
877
- background: var(--rp-danger-light);
878
- color: var(--rp-danger);
879
- border: 1px solid var(--rp-danger);
880
- }
881
-
882
- /* ============================================
883
- Utilities
884
- ============================================ */
885
-
886
- .rp-meta {
887
- display: flex;
888
- align-items: center;
889
- gap: var(--rp-space-sm);
890
- font-size: 0.875rem;
891
- color: var(--rp-text-muted);
892
- margin-top: var(--rp-space-xs);
893
- }
894
-
895
- .rp-meta-separator {
896
- color: var(--rp-text-light);
897
- }
898
-
899
- .rp-post-meta {
900
- display: flex;
901
- align-items: center;
902
- gap: var(--rp-space-md);
903
- font-size: 0.875rem;
904
- color: var(--rp-text-muted);
905
- margin-top: var(--rp-space-sm);
906
- }
907
-
908
- .rp-post-tags {
909
- margin-bottom: var(--rp-space-xl);
910
- }
911
-
912
- .rp-empty-state {
913
- text-align: center;
914
- padding: var(--rp-space-2xl);
915
- color: var(--rp-text-muted);
916
- }
917
-
918
- .rp-divider {
919
- height: 1px;
920
- background: var(--rp-border-light);
921
- margin: var(--rp-space-lg) 0;
922
- }
923
-
924
- .rp-prose {
925
- font-family: var(--rp-font-display);
926
- font-size: 1.0625rem;
927
- line-height: 1.7;
928
- }
929
-
930
- .rp-prose p {
931
- margin-bottom: var(--rp-space-md);
932
- }
933
-
934
- .rp-prose h2 {
935
- font-size: 1.5rem;
936
- margin: var(--rp-space-xl) 0 var(--rp-space-md);
937
- }
938
-
939
- .rp-prose h3 {
940
- font-size: 1.25rem;
941
- margin: var(--rp-space-lg) 0 var(--rp-space-sm);
942
- }
943
-
944
- .rp-prose code {
945
- font-family: var(--rp-font-mono);
946
- font-size: 0.875em;
947
- background: var(--rp-bg);
948
- padding: 2px 6px;
949
- border-radius: 3px;
950
- }
951
-
952
- .rp-prose pre {
953
- background: var(--rp-sidebar-bg);
954
- color: var(--rp-sidebar-text-active);
955
- padding: var(--rp-space-lg);
956
- border-radius: var(--rp-radius);
957
- overflow-x: auto;
958
- margin-bottom: var(--rp-space-md);
959
- }
960
-
961
- .rp-prose pre code {
962
- background: none;
963
- padding: 0;
964
- }
965
-
966
- /* SEO Preview */
967
- .rp-seo-preview {
968
- margin-top: var(--rp-space-xl);
969
- padding: var(--rp-space-md);
970
- background: var(--rp-info-light);
971
- border-radius: var(--rp-radius);
972
- border: 1px solid #d8e8f0;
973
- }
974
-
975
- .rp-seo-preview-title {
976
- font-size: 0.75rem;
977
- font-weight: 600;
978
- text-transform: uppercase;
979
- letter-spacing: 0.04em;
980
- color: var(--rp-text-muted);
981
- margin-bottom: var(--rp-space-md);
982
- }
983
-
984
- .rp-seo-title {
985
- font-size: 1.125rem;
986
- font-weight: 500;
987
- color: #1a0dab;
988
- margin-bottom: var(--rp-space-xs);
989
- }
990
-
991
- .rp-seo-description {
992
- font-size: 0.875rem;
993
- color: var(--rp-text-muted);
994
- line-height: 1.5;
995
- }
996
-
997
- /* ============================================
998
- Responsive
999
- ============================================ */
1000
-
1001
- @media (max-width: 1023px) {
1002
- .rp-stats-grid {
1003
- grid-template-columns: repeat(2, 1fr);
1004
- }
1005
-
1006
- .rp-form-layout {
1007
- grid-template-columns: 1fr;
1008
- }
1009
-
1010
- .rp-form-sidebar {
1011
- order: -1;
1012
- }
1013
-
1014
- .rp-main {
1015
- padding: var(--rp-space-lg);
1016
- }
1017
- }
1018
-
1019
- @media (max-width: 767px) {
1020
- :root {
1021
- --rp-sidebar-width: 280px;
1022
- }
1023
-
1024
- .rp-sidebar {
1025
- transform: translateX(-100%);
1026
- }
1027
-
1028
- .rp-sidebar--open {
1029
- transform: translateX(0);
1030
- }
1031
-
1032
- .rp-mobile-header {
1033
- display: flex;
1034
- }
1035
-
1036
- .rp-main {
1037
- margin-left: 0;
1038
- padding: var(--rp-space-md);
1039
- padding-top: calc(var(--rp-header-height) + var(--rp-space-lg));
1040
- }
1041
-
1042
- .rp-stats-grid {
1043
- grid-template-columns: 1fr;
1044
- }
1045
-
1046
- .rp-stat-card {
1047
- display: flex;
1048
- align-items: center;
1049
- justify-content: space-between;
1050
- text-align: left;
1051
- padding: var(--rp-space-md);
1052
- }
1053
-
1054
- .rp-stat-value {
1055
- font-size: 1.5rem;
1056
- order: 1;
1057
- }
1058
-
1059
- .rp-stat-label {
1060
- order: 0;
1061
- }
1062
-
1063
- .rp-page-header {
1064
- flex-direction: column;
1065
- align-items: stretch;
1066
- }
1067
-
1068
- .rp-page-title {
1069
- font-size: 1.375rem;
1070
- }
1071
-
1072
- .rp-page-actions {
1073
- flex-direction: column;
1074
- }
1075
-
1076
- .rp-page-actions .rp-btn {
1077
- width: 100%;
1078
- }
1079
-
1080
- .rp-form-row {
1081
- grid-template-columns: 1fr;
1082
- }
1083
-
1084
- .rp-form-row--3 {
1085
- grid-template-columns: 1fr;
1086
- }
1087
-
1088
- .rp-form-actions {
1089
- flex-direction: column;
1090
- }
1091
-
1092
- .rp-form-actions .rp-btn {
1093
- width: 100%;
1094
- }
1095
-
1096
- .rp-table th,
1097
- .rp-table td {
1098
- padding: var(--rp-space-sm);
1099
- }
1100
-
1101
- .rp-list-item {
1102
- flex-direction: column;
1103
- align-items: flex-start;
1104
- gap: var(--rp-space-sm);
1105
- }
1106
- }
1107
-
1108
- @media (pointer: coarse) {
1109
- .rp-btn {
1110
- min-height: 44px;
1111
- }
1112
-
1113
- .rp-nav-link {
1114
- min-height: 44px;
1115
- }
1116
-
1117
- .rp-checkbox input,
1118
- .rp-radio input {
1119
- width: 20px;
1120
- height: 20px;
1121
- }
1122
- }
1123
-
1124
- @media print {
1125
- .rp-sidebar,
1126
- .rp-mobile-header,
1127
- .rp-page-actions,
1128
- .rp-form-actions,
1129
- .rp-table-actions {
1130
- display: none !important;
1131
- }
1132
-
1133
- .rp-main {
1134
- margin-left: 0;
1135
- }
1136
-
1137
- .rp-card {
1138
- box-shadow: none;
1139
- border: 1px solid #ddd;
1140
- }
1141
- }
1142
-
1143
- /* ============================================
1144
- Header Images
1145
- ============================================ */
1146
-
1147
- .rp-header-image {
1148
- margin-bottom: var(--rp-space-lg);
1149
- }
1150
-
1151
- .rp-header-image-full {
1152
- width: 100%;
1153
- max-height: 400px;
1154
- object-fit: cover;
1155
- border-radius: var(--rp-radius);
1156
- border: 1px solid var(--rp-border);
1157
- }
1158
-
1159
- .rp-header-image-preview {
1160
- margin-bottom: var(--rp-space-md);
1161
- }
1162
-
1163
- .rp-header-image-thumb {
1164
- max-width: 100%;
1165
- max-height: 200px;
1166
- object-fit: cover;
1167
- border-radius: var(--rp-radius);
1168
- border: 1px solid var(--rp-border);
1169
- }
1170
-
1171
- .rp-file-input {
1172
- width: 100%;
1173
- padding: var(--rp-space-sm);
1174
- border: 1px dashed var(--rp-border);
1175
- border-radius: var(--rp-radius);
1176
- background: var(--rp-bg);
1177
- cursor: pointer;
1178
- }
1179
-
1180
- .rp-file-input:hover {
1181
- border-color: var(--rp-primary);
1182
- background: var(--rp-primary-light);
1183
- }
1184
-
1185
- .rp-checkbox-label {
1186
- display: flex;
1187
- align-items: center;
1188
- gap: var(--rp-space-sm);
1189
- font-size: var(--rp-text-sm);
1190
- color: var(--rp-text-muted);
1191
- cursor: pointer;
1192
- margin-top: var(--rp-space-sm);
1193
- }
1194
-
1195
- .rp-checkbox-label input[type="checkbox"] {
1196
- width: 16px;
1197
- height: 16px;
1198
- cursor: pointer;
1199
- }
1200
-
1201
- /* ============================================
1202
- Lexxy
1203
- ============================================ */
1204
-
1205
- :where(lexxy-toolbar){
1206
- margin-bottom: 20px;
1207
- }