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,111 @@
1
+ /*
2
+ * RailsPress Admin - Page Structure
3
+ * Page headers, titles, sections
4
+ */
5
+
6
+ .rp-page-header {
7
+ display: flex;
8
+ align-items: center;
9
+ justify-content: space-between;
10
+ gap: var(--rp-space-lg);
11
+ margin-bottom: var(--rp-space-xl);
12
+ }
13
+
14
+ .rp-page-title {
15
+ font-family: var(--rp-font-display);
16
+ font-size: 1.75rem;
17
+ font-weight: 700;
18
+ color: var(--rp-text);
19
+ letter-spacing: 0;
20
+ line-height: 1.2;
21
+ }
22
+
23
+ .rp-page-title--standalone {
24
+ margin-bottom: var(--rp-space-xl);
25
+ }
26
+
27
+ .rp-byline {
28
+ margin-top: var(--rp-space-xs);
29
+ font-size: 0.875rem;
30
+ color: var(--rp-text-muted);
31
+ }
32
+
33
+ .rp-page-actions {
34
+ display: flex;
35
+ gap: var(--rp-space-sm);
36
+ flex-shrink: 0;
37
+ }
38
+
39
+ .rp-section {
40
+ margin-bottom: var(--rp-space-xl);
41
+ }
42
+
43
+ .rp-section-header {
44
+ display: flex;
45
+ align-items: center;
46
+ gap: var(--rp-space-md);
47
+ margin-bottom: var(--rp-space-md);
48
+ padding-left: var(--rp-space-md);
49
+ border-left: 3px solid var(--rp-primary);
50
+ }
51
+
52
+ .rp-section-title {
53
+ font-family: var(--rp-font-body);
54
+ font-size: 0.9375rem;
55
+ font-weight: 600;
56
+ color: var(--rp-text);
57
+ letter-spacing: 0;
58
+ }
59
+
60
+ /* Post meta card */
61
+ .rp-post-meta-card {
62
+ display: flex;
63
+ flex-wrap: wrap;
64
+ gap: var(--rp-space-lg) var(--rp-space-xl);
65
+ padding: var(--rp-space-md) var(--rp-space-lg);
66
+ margin-bottom: var(--rp-space-xl);
67
+ background: var(--rp-bg-elevated);
68
+ border-radius: var(--rp-radius);
69
+ border: 1px solid var(--rp-border-light);
70
+ }
71
+
72
+ .rp-meta-item {
73
+ display: flex;
74
+ flex-direction: column;
75
+ gap: var(--rp-space-xs);
76
+ }
77
+
78
+ .rp-meta-row {
79
+ display: flex;
80
+ align-items: flex-start;
81
+ justify-content: space-between;
82
+ gap: var(--rp-space-xl);
83
+ flex-basis: 100%;
84
+ }
85
+
86
+ .rp-meta-item--tags {
87
+ align-items: flex-end;
88
+ }
89
+
90
+ .rp-meta-item--tags .rp-tag-list {
91
+ justify-content: flex-end;
92
+ }
93
+
94
+ .rp-meta-label {
95
+ font-size: 0.6875rem;
96
+ font-weight: 600;
97
+ text-transform: uppercase;
98
+ letter-spacing: 0.05em;
99
+ color: var(--rp-text-muted);
100
+ }
101
+
102
+ .rp-meta-value {
103
+ font-size: 0.875rem;
104
+ color: var(--rp-text);
105
+ }
106
+
107
+ .rp-meta-value--mono {
108
+ font-family: var(--rp-font-mono);
109
+ font-size: 0.8125rem;
110
+ color: var(--rp-text-muted);
111
+ }
@@ -0,0 +1,174 @@
1
+ /*
2
+ * RailsPress Admin - Responsive
3
+ * Media queries and breakpoint adjustments
4
+ */
5
+
6
+ @media (max-width: 1023px) {
7
+ .rp-stats-grid {
8
+ grid-template-columns: repeat(2, 1fr);
9
+ }
10
+
11
+ .rp-form-layout {
12
+ grid-template-columns: 1fr;
13
+ }
14
+
15
+ .rp-form-sidebar {
16
+ order: -1;
17
+ }
18
+
19
+ .rp-main {
20
+ padding: var(--rp-space-lg);
21
+ }
22
+ }
23
+
24
+ @media (max-width: 767px) {
25
+ :root {
26
+ --rp-sidebar-width: 280px;
27
+ }
28
+
29
+ .rp-sidebar {
30
+ transform: translateX(-100%);
31
+ width: var(--rp-sidebar-width);
32
+ }
33
+
34
+ .rp-sidebar--open {
35
+ transform: translateX(0);
36
+ }
37
+
38
+ .rp-sidebar-toggle {
39
+ display: none;
40
+ }
41
+
42
+ .rp-sidebar--collapsed {
43
+ width: var(--rp-sidebar-width);
44
+ }
45
+
46
+ .rp-sidebar--collapsed .rp-logo {
47
+ display: block;
48
+ }
49
+
50
+ .rp-sidebar--collapsed .rp-nav-text {
51
+ position: static;
52
+ width: auto;
53
+ height: auto;
54
+ margin: 0;
55
+ overflow: visible;
56
+ clip: auto;
57
+ }
58
+
59
+ .rp-mobile-header {
60
+ display: flex;
61
+ }
62
+
63
+ .rp-main {
64
+ margin-left: 0;
65
+ padding: var(--rp-space-md);
66
+ padding-top: calc(var(--rp-header-height) + var(--rp-space-lg));
67
+ }
68
+
69
+ .rp-admin-layout--sidebar-collapsed .rp-main {
70
+ margin-left: 0;
71
+ }
72
+
73
+ .rp-stats-grid {
74
+ grid-template-columns: 1fr;
75
+ }
76
+
77
+ .rp-stat-card {
78
+ display: flex;
79
+ align-items: center;
80
+ justify-content: space-between;
81
+ text-align: left;
82
+ padding: var(--rp-space-md);
83
+ }
84
+
85
+ .rp-stat-value {
86
+ font-size: 1.5rem;
87
+ order: 1;
88
+ }
89
+
90
+ .rp-stat-label {
91
+ order: 0;
92
+ }
93
+
94
+ .rp-page-header {
95
+ flex-direction: column;
96
+ align-items: stretch;
97
+ }
98
+
99
+ .rp-page-title {
100
+ font-size: 1.375rem;
101
+ }
102
+
103
+ .rp-page-actions {
104
+ flex-direction: column;
105
+ }
106
+
107
+ .rp-page-actions .rp-btn {
108
+ width: 100%;
109
+ }
110
+
111
+ .rp-form-row {
112
+ grid-template-columns: 1fr;
113
+ }
114
+
115
+ .rp-form-row--3 {
116
+ grid-template-columns: 1fr;
117
+ }
118
+
119
+ .rp-form-actions {
120
+ flex-direction: column;
121
+ }
122
+
123
+ .rp-form-actions .rp-btn {
124
+ width: 100%;
125
+ }
126
+
127
+ .rp-table th,
128
+ .rp-table td {
129
+ padding: var(--rp-space-sm);
130
+ }
131
+
132
+ .rp-list-item {
133
+ flex-direction: column;
134
+ align-items: flex-start;
135
+ gap: var(--rp-space-sm);
136
+ }
137
+ }
138
+
139
+ /* Touch devices */
140
+ @media (pointer: coarse) {
141
+ .rp-btn {
142
+ min-height: 44px;
143
+ }
144
+
145
+ .rp-nav-link {
146
+ min-height: 44px;
147
+ }
148
+
149
+ .rp-checkbox input,
150
+ .rp-radio input {
151
+ width: 20px;
152
+ height: 20px;
153
+ }
154
+ }
155
+
156
+ /* Print styles */
157
+ @media print {
158
+ .rp-sidebar,
159
+ .rp-mobile-header,
160
+ .rp-page-actions,
161
+ .rp-form-actions,
162
+ .rp-table-actions {
163
+ display: none !important;
164
+ }
165
+
166
+ .rp-main {
167
+ margin-left: 0;
168
+ }
169
+
170
+ .rp-card {
171
+ box-shadow: none;
172
+ border: 1px solid #ddd;
173
+ }
174
+ }
@@ -0,0 +1,43 @@
1
+ /*
2
+ * RailsPress Admin - Stats
3
+ * Dashboard stat cards
4
+ */
5
+
6
+ .rp-stats-grid {
7
+ display: grid;
8
+ grid-template-columns: repeat(3, 1fr);
9
+ gap: var(--rp-space-md);
10
+ margin-bottom: var(--rp-space-xl);
11
+ }
12
+
13
+ .rp-stat-card {
14
+ background: var(--rp-bg-elevated);
15
+ border-radius: var(--rp-radius);
16
+ box-shadow: var(--rp-shadow-md);
17
+ border: none;
18
+ padding: var(--rp-space-lg);
19
+ text-align: center;
20
+ transition: transform 0.2s ease, box-shadow 0.2s ease;
21
+ }
22
+
23
+ .rp-stat-card:hover {
24
+ transform: translateY(-2px);
25
+ box-shadow: var(--rp-shadow-lg);
26
+ }
27
+
28
+ .rp-stat-value {
29
+ font-family: var(--rp-font-body);
30
+ font-size: 2.25rem;
31
+ font-weight: 600;
32
+ color: var(--rp-text);
33
+ line-height: 1;
34
+ margin-bottom: var(--rp-space-xs);
35
+ }
36
+
37
+ .rp-stat-label {
38
+ font-size: 0.8125rem;
39
+ color: var(--rp-text-muted);
40
+ text-transform: uppercase;
41
+ letter-spacing: 0.04em;
42
+ font-weight: 500;
43
+ }
@@ -0,0 +1,163 @@
1
+ /*
2
+ * RailsPress Admin - Tables
3
+ * Data tables styling
4
+ */
5
+
6
+ .rp-table {
7
+ width: 100%;
8
+ border-collapse: collapse;
9
+ }
10
+
11
+ .rp-table th {
12
+ text-align: left;
13
+ padding: var(--rp-space-sm) var(--rp-space-md);
14
+ font-size: 0.75rem;
15
+ font-weight: 600;
16
+ text-transform: uppercase;
17
+ letter-spacing: 0.04em;
18
+ color: var(--rp-text-muted);
19
+ border-bottom: 1px solid var(--rp-border);
20
+ background: var(--rp-bg);
21
+ }
22
+
23
+ .rp-table td {
24
+ padding: var(--rp-space-md);
25
+ border-bottom: 1px solid var(--rp-border-light);
26
+ vertical-align: middle;
27
+ }
28
+
29
+ .rp-table tbody tr:hover {
30
+ background: var(--rp-bg);
31
+ }
32
+
33
+ .rp-table tbody tr:last-child td {
34
+ border-bottom: none;
35
+ }
36
+
37
+ .rp-table-primary {
38
+ font-weight: 500;
39
+ }
40
+
41
+ .rp-table-secondary {
42
+ color: var(--rp-text-muted);
43
+ font-size: 0.875rem;
44
+ }
45
+
46
+ .rp-table-actions {
47
+ text-align: right;
48
+ white-space: nowrap;
49
+ }
50
+
51
+ .rp-table-actions > * {
52
+ display: inline-flex;
53
+ vertical-align: middle;
54
+ }
55
+
56
+ .rp-table-actions > * + * {
57
+ margin-left: var(--rp-space-xs);
58
+ }
59
+
60
+ /* button_to generates forms - keep them inline-flex for vertical alignment */
61
+ .rp-table-actions form {
62
+ display: inline-flex;
63
+ }
64
+
65
+ .rp-table-actions .rp-link {
66
+ margin-left: var(--rp-space-md);
67
+ }
68
+
69
+ .rp-table-actions .rp-link:first-child {
70
+ margin-left: 0;
71
+ }
72
+
73
+ .rp-table--responsive {
74
+ overflow-x: auto;
75
+ }
76
+
77
+ /* Truncated text cell */
78
+ .rp-table-truncate {
79
+ max-width: 300px;
80
+ overflow: hidden;
81
+ text-overflow: ellipsis;
82
+ white-space: nowrap;
83
+ }
84
+
85
+ @media (max-width: 1023px) {
86
+ .rp-table-truncate {
87
+ max-width: 200px;
88
+ }
89
+ }
90
+
91
+ @media (max-width: 767px) {
92
+ .rp-table-truncate {
93
+ max-width: 120px;
94
+ }
95
+ }
96
+
97
+ /* Date display - show short on small screens */
98
+ .rp-table-date-full {
99
+ display: inline;
100
+ }
101
+
102
+ .rp-table-date-short {
103
+ display: none;
104
+ }
105
+
106
+ @media (max-width: 1023px) {
107
+ .rp-table-date-full {
108
+ display: none;
109
+ }
110
+
111
+ .rp-table-date-short {
112
+ display: inline;
113
+ }
114
+ }
115
+
116
+ /* Sortable column headers */
117
+ .rp-sortable {
118
+ color: var(--rp-text-muted);
119
+ text-decoration: none;
120
+ display: inline-flex;
121
+ align-items: center;
122
+ gap: 0.25em;
123
+ cursor: pointer;
124
+ transition: color 0.15s ease;
125
+ }
126
+
127
+ .rp-sortable:hover {
128
+ color: var(--rp-text);
129
+ }
130
+
131
+ .rp-sortable::after {
132
+ content: "";
133
+ display: inline-block;
134
+ width: 0;
135
+ height: 0;
136
+ border-left: 4px solid transparent;
137
+ border-right: 4px solid transparent;
138
+ border-bottom: 5px solid currentColor;
139
+ opacity: 0;
140
+ transition: opacity 0.15s ease, transform 0.15s ease;
141
+ }
142
+
143
+ .rp-sortable:hover::after {
144
+ opacity: 0.4;
145
+ }
146
+
147
+ .rp-sortable--active {
148
+ color: var(--rp-primary);
149
+ }
150
+
151
+ .rp-sortable--active::after {
152
+ opacity: 1;
153
+ }
154
+
155
+ .rp-sortable--active.rp-sortable--asc::after {
156
+ border-bottom: 5px solid currentColor;
157
+ border-top: none;
158
+ }
159
+
160
+ .rp-sortable--active.rp-sortable--desc::after {
161
+ border-top: 5px solid currentColor;
162
+ border-bottom: none;
163
+ }
@@ -0,0 +1,202 @@
1
+ /*
2
+ * RailsPress Admin - Utilities
3
+ * Helper classes, prose styling, SEO preview
4
+ */
5
+
6
+ /* Meta information */
7
+ .rp-meta {
8
+ display: flex;
9
+ align-items: center;
10
+ gap: var(--rp-space-sm);
11
+ font-size: 0.875rem;
12
+ color: var(--rp-text-muted);
13
+ margin-top: var(--rp-space-xs);
14
+ }
15
+
16
+ .rp-meta-separator {
17
+ color: var(--rp-text-light);
18
+ }
19
+
20
+ .rp-post-meta {
21
+ display: flex;
22
+ align-items: center;
23
+ gap: var(--rp-space-md);
24
+ font-size: 0.875rem;
25
+ color: var(--rp-text-muted);
26
+ margin-top: var(--rp-space-sm);
27
+ }
28
+
29
+ .rp-post-tags {
30
+ margin-bottom: var(--rp-space-xl);
31
+ }
32
+
33
+ /* Empty state */
34
+ .rp-empty-state {
35
+ text-align: center;
36
+ padding: var(--rp-space-2xl);
37
+ color: var(--rp-text-muted);
38
+ }
39
+
40
+ /* Divider */
41
+ .rp-divider {
42
+ height: 1px;
43
+ background: var(--rp-border-light);
44
+ margin: var(--rp-space-lg) 0;
45
+ }
46
+
47
+ /* Prose / Rich content */
48
+ .rp-prose {
49
+ font-family: var(--rp-font-body);
50
+ font-size: 1.0625rem;
51
+ line-height: 1.7;
52
+ }
53
+
54
+ .rp-prose p {
55
+ margin-bottom: var(--rp-space-md);
56
+ }
57
+
58
+ .rp-prose h2 {
59
+ font-size: 1.5rem;
60
+ margin: var(--rp-space-xl) 0 var(--rp-space-md);
61
+ }
62
+
63
+ .rp-prose h3 {
64
+ font-size: 1.25rem;
65
+ margin: var(--rp-space-lg) 0 var(--rp-space-sm);
66
+ }
67
+
68
+ .rp-prose code {
69
+ font-family: var(--rp-font-mono);
70
+ font-size: 0.875em;
71
+ background: var(--rp-bg);
72
+ padding: 2px 6px;
73
+ border-radius: 3px;
74
+ }
75
+
76
+ .rp-prose pre {
77
+ background: var(--rp-sidebar-bg);
78
+ color: var(--rp-sidebar-text-active);
79
+ padding: var(--rp-space-lg);
80
+ border-radius: var(--rp-radius);
81
+ overflow-x: auto;
82
+ margin-bottom: var(--rp-space-md);
83
+ }
84
+
85
+ .rp-prose pre code {
86
+ background: none;
87
+ padding: 0;
88
+ }
89
+
90
+ .rp-prose ul {
91
+ padding-left: var(--rp-space-md);
92
+ }
93
+
94
+ .rp-prose ol li{
95
+ margin-left: var(--rp-space-xs);
96
+ }
97
+
98
+ /* SEO Preview */
99
+ .rp-seo-preview {
100
+ margin-top: var(--rp-space-xl);
101
+ padding: var(--rp-space-md);
102
+ background: var(--rp-info-light);
103
+ border-radius: var(--rp-radius);
104
+ border: 1px solid #d8e8f0;
105
+ }
106
+
107
+ .rp-seo-preview-title {
108
+ font-size: 0.75rem;
109
+ font-weight: 600;
110
+ text-transform: uppercase;
111
+ letter-spacing: 0.04em;
112
+ color: var(--rp-text-muted);
113
+ margin-bottom: var(--rp-space-md);
114
+ }
115
+
116
+ .rp-seo-title {
117
+ font-size: 1.125rem;
118
+ font-weight: 500;
119
+ color: #1a0dab;
120
+ margin-bottom: var(--rp-space-xs);
121
+ }
122
+
123
+ .rp-seo-description {
124
+ font-size: 0.875rem;
125
+ color: var(--rp-text-muted);
126
+ line-height: 1.5;
127
+ }
128
+
129
+ /* Code block */
130
+ .rp-code-block {
131
+ background: var(--rp-sidebar-bg);
132
+ color: var(--rp-sidebar-text);
133
+ padding: var(--rp-space-md);
134
+ border-radius: var(--rp-radius);
135
+ font-family: var(--rp-font-mono);
136
+ font-size: 0.75rem;
137
+ line-height: 1.5;
138
+ overflow-x: auto;
139
+ white-space: pre;
140
+ }
141
+
142
+ .rp-code-block code {
143
+ background: none;
144
+ padding: 0;
145
+ }
146
+
147
+ /* Content preview */
148
+ .rp-content-preview {
149
+ padding: var(--rp-space-md);
150
+ background: var(--rp-bg-secondary);
151
+ border: 1px solid var(--rp-border);
152
+ border-radius: var(--rp-radius);
153
+ white-space: pre-wrap;
154
+ word-wrap: break-word;
155
+ line-height: 1.6;
156
+ font-size: 0.9375rem;
157
+ }
158
+
159
+ /* Text utilities */
160
+ .rp-text-danger {
161
+ color: var(--rp-danger);
162
+ }
163
+
164
+ /* Featured images */
165
+ .rp-featured-image {
166
+ margin-bottom: var(--rp-space-lg);
167
+ }
168
+
169
+ .rp-featured-image-full {
170
+ width: 100%;
171
+ max-height: 400px;
172
+ object-fit: cover;
173
+ border-radius: var(--rp-radius);
174
+ border: 1px solid var(--rp-border);
175
+ }
176
+
177
+ .rp-featured-image-preview {
178
+ margin-bottom: var(--rp-space-md);
179
+ }
180
+
181
+ .rp-featured-image-thumb {
182
+ max-width: 100%;
183
+ max-height: 200px;
184
+ object-fit: cover;
185
+ border-radius: var(--rp-radius);
186
+ border: 1px solid var(--rp-border);
187
+ }
188
+
189
+ /* Input with button */
190
+ .rp-input-with-button {
191
+ display: flex;
192
+ gap: var(--rp-space-sm);
193
+ align-items: center;
194
+ }
195
+
196
+ .rp-input-with-button .rp-input {
197
+ flex: 1;
198
+ }
199
+
200
+ .rp-input-with-button .rp-btn {
201
+ flex-shrink: 0;
202
+ }