collavre 0.21.0 → 0.23.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 (200) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -0
  3. data/app/assets/stylesheets/collavre/actiontext.css +251 -90
  4. data/app/assets/stylesheets/collavre/code_highlight.css +7 -201
  5. data/app/assets/stylesheets/collavre/comments_popup.css +169 -64
  6. data/app/assets/stylesheets/collavre/creatives.css +11 -2
  7. data/app/assets/stylesheets/collavre/modal_dialog.css +32 -0
  8. data/app/assets/stylesheets/collavre/popup.css +148 -0
  9. data/app/assets/stylesheets/collavre/tables.css +91 -0
  10. data/app/channels/collavre/agent_channel.rb +205 -0
  11. data/app/channels/collavre/inbox_badge_channel.rb +30 -0
  12. data/app/controllers/collavre/admin/integrations_controller.rb +16 -5
  13. data/app/controllers/collavre/api/v1/agents_controller.rb +777 -0
  14. data/app/controllers/collavre/api/v1/base_controller.rb +46 -0
  15. data/app/controllers/collavre/api/v1/mobile/agent_events_controller.rb +224 -0
  16. data/app/controllers/collavre/api/v1/mobile/base_controller.rb +95 -0
  17. data/app/controllers/collavre/api/v1/mobile/devices_controller.rb +31 -0
  18. data/app/controllers/collavre/api/v1/mobile/voice_commands_controller.rb +25 -0
  19. data/app/controllers/collavre/attachments_controller.rb +30 -2
  20. data/app/controllers/collavre/comments_controller.rb +1 -1
  21. data/app/controllers/collavre/creatives/attachments_controller.rb +79 -0
  22. data/app/controllers/collavre/creatives_controller.rb +107 -6
  23. data/app/controllers/collavre/tasks_controller.rb +21 -4
  24. data/app/controllers/collavre/topics_controller.rb +64 -1
  25. data/app/controllers/collavre/typo_corrections_controller.rb +39 -0
  26. data/app/controllers/concerns/collavre/comments/approval_actions.rb +57 -14
  27. data/app/controllers/concerns/collavre/users_controller/profile_and_settings.rb +16 -1
  28. data/app/controllers/concerns/collavre/users_controller/registration.rb +41 -1
  29. data/app/helpers/collavre/application_helper.rb +1 -0
  30. data/app/javascript/collavre.js +2 -0
  31. data/app/javascript/components/ImageResizer.jsx +9 -3
  32. data/app/javascript/components/InlineLexicalEditor.jsx +196 -96
  33. data/app/javascript/components/creative_tree_row.js +20 -3
  34. data/app/javascript/components/plugins/attachment_cleanup_plugin.jsx +3 -0
  35. data/app/javascript/components/plugins/image_upload_plugin.jsx +12 -0
  36. data/app/javascript/components/plugins/list_tab_indent_plugin.jsx +16 -0
  37. data/app/javascript/components/plugins/table_hover_actions_plugin.jsx +405 -0
  38. data/app/javascript/controllers/__tests__/inbox_badge_controller.test.js +73 -0
  39. data/app/javascript/controllers/__tests__/link_creative_controller.test.js +447 -0
  40. data/app/javascript/controllers/comment_controller.js +11 -5
  41. data/app/javascript/controllers/comment_version_controller.js +2 -1
  42. data/app/javascript/controllers/comments/__tests__/form_controller_double_submit.test.js +159 -0
  43. data/app/javascript/controllers/comments/__tests__/presence_controller.test.js +111 -2
  44. data/app/javascript/controllers/comments/__tests__/topics_controller_delete.test.js +94 -0
  45. data/app/javascript/controllers/comments/form_controller.js +21 -5
  46. data/app/javascript/controllers/comments/list_controller.js +35 -19
  47. data/app/javascript/controllers/comments/presence_controller.js +58 -6
  48. data/app/javascript/controllers/comments/topics_controller.js +14 -8
  49. data/app/javascript/controllers/creatives/__tests__/tree_controller.test.js +150 -0
  50. data/app/javascript/controllers/creatives/import_controller.js +2 -1
  51. data/app/javascript/controllers/creatives/select_mode_controller.js +2 -1
  52. data/app/javascript/controllers/creatives/tree_controller.js +142 -1
  53. data/app/javascript/controllers/image_lightbox_controller.js +2 -1
  54. data/app/javascript/controllers/inbox_badge_controller.js +33 -0
  55. data/app/javascript/controllers/index.js +4 -1
  56. data/app/javascript/controllers/link_creative_controller.js +451 -29
  57. data/app/javascript/controllers/share_modal_controller.js +4 -3
  58. data/app/javascript/controllers/topic_search_controller.js +2 -1
  59. data/app/javascript/creatives/drag_drop/event_handlers.js +14 -5
  60. data/app/javascript/creatives/topic_move_members_popup.js +156 -0
  61. data/app/javascript/creatives/tree_renderer.js +11 -0
  62. data/app/javascript/lib/__tests__/turbo_confirm.test.js +81 -0
  63. data/app/javascript/lib/__tests__/typo_correction.test.js +192 -0
  64. data/app/javascript/lib/api/__tests__/api_error.test.js +96 -0
  65. data/app/javascript/lib/api/__tests__/queue_manager.test.js +88 -1
  66. data/app/javascript/lib/api/api_error.js +108 -0
  67. data/app/javascript/lib/api/creatives.js +13 -0
  68. data/app/javascript/lib/api/queue_manager.js +38 -4
  69. data/app/javascript/lib/common_popup.js +18 -5
  70. data/app/javascript/lib/editor/__tests__/code_edit_view_token_parity.test.js +121 -0
  71. data/app/javascript/lib/editor/__tests__/code_language_roundtrip.test.js +152 -0
  72. data/app/javascript/lib/editor/__tests__/code_languages.test.js +93 -0
  73. data/app/javascript/lib/editor/code_languages.js +173 -0
  74. data/app/javascript/lib/editor/code_token_theme.js +41 -0
  75. data/app/javascript/lib/lexical/__tests__/color_import.test.js +318 -0
  76. data/app/javascript/lib/lexical/__tests__/image_focus.test.js +139 -0
  77. data/app/javascript/lib/lexical/__tests__/list_tab_indent.test.js +633 -0
  78. data/app/javascript/lib/lexical/__tests__/markdown_serialize.test.js +627 -0
  79. data/app/javascript/lib/lexical/__tests__/minimize_html.test.js +278 -0
  80. data/app/javascript/lib/lexical/__tests__/selection_boundary.test.js +88 -0
  81. data/app/javascript/lib/lexical/__tests__/table_transformer.test.js +163 -0
  82. data/app/javascript/lib/lexical/__tests__/trailing_paragraph.test.js +104 -0
  83. data/app/javascript/lib/lexical/color_import.js +186 -0
  84. data/app/javascript/lib/lexical/list_tab_indent.js +210 -0
  85. data/app/javascript/lib/lexical/markdown_serialize.js +320 -0
  86. data/app/javascript/lib/lexical/minimize_html.js +182 -0
  87. data/app/javascript/lib/lexical/selection_boundary.js +58 -0
  88. data/app/javascript/lib/lexical/table_transformer.js +182 -0
  89. data/app/javascript/lib/lexical/trailing_paragraph.js +29 -0
  90. data/app/javascript/lib/lexical/video_node.jsx +96 -0
  91. data/app/javascript/lib/turbo_confirm.js +46 -0
  92. data/app/javascript/lib/typo_correction.js +146 -0
  93. data/app/javascript/lib/utils/__tests__/confirm_dialog.test.js +88 -0
  94. data/app/javascript/lib/utils/__tests__/dialog.test.js +92 -0
  95. data/app/javascript/lib/utils/__tests__/markdown.test.js +153 -0
  96. data/app/javascript/lib/utils/__tests__/sanitize_description.test.js +68 -0
  97. data/app/javascript/lib/utils/__tests__/table_download.test.js +93 -0
  98. data/app/javascript/lib/utils/confirm_dialog.js +10 -0
  99. data/app/javascript/lib/utils/dialog.js +300 -0
  100. data/app/javascript/lib/utils/markdown.js +154 -67
  101. data/app/javascript/lib/utils/sanitize_description.js +31 -0
  102. data/app/javascript/lib/utils/table_download.js +15 -0
  103. data/app/javascript/modules/__tests__/typo_corrector.test.js +365 -0
  104. data/app/javascript/modules/creative_row_editor.js +110 -70
  105. data/app/javascript/modules/export_to_markdown.js +2 -1
  106. data/app/javascript/modules/lexical_inline_editor.jsx +2 -1
  107. data/app/javascript/modules/slide_view.js +11 -2
  108. data/app/javascript/modules/typo_corrector.js +534 -0
  109. data/app/jobs/collavre/ai_agent_job.rb +92 -3
  110. data/app/jobs/collavre/cancel_offline_delegated_tasks_job.rb +134 -0
  111. data/app/jobs/collavre/claude_channel_presence_job.rb +91 -0
  112. data/app/jobs/collavre/compress_job.rb +6 -2
  113. data/app/models/collavre/agent_subscription.rb +52 -0
  114. data/app/models/collavre/comment/broadcastable.rb +46 -7
  115. data/app/models/collavre/comment/claude_channel_permission.rb +145 -0
  116. data/app/models/collavre/comment/notifiable.rb +14 -4
  117. data/app/models/collavre/comment.rb +124 -11
  118. data/app/models/collavre/creative/describable.rb +220 -4
  119. data/app/models/collavre/creative_share.rb +1 -0
  120. data/app/models/collavre/task.rb +49 -5
  121. data/app/models/collavre/topic.rb +5 -0
  122. data/app/models/collavre/user.rb +61 -1
  123. data/app/services/collavre/agent_session_abort.rb +28 -0
  124. data/app/services/collavre/ai_agent/claude_channel_adapter.rb +79 -0
  125. data/app/services/collavre/ai_agent/response_finalizer.rb +4 -2
  126. data/app/services/collavre/ai_agent_service.rb +68 -49
  127. data/app/services/collavre/ai_client.rb +28 -10
  128. data/app/services/collavre/attachment_backfill.rb +26 -0
  129. data/app/services/collavre/auto_theme_generator.rb +1 -1
  130. data/app/services/collavre/creatives/breadcrumb_resolver.rb +91 -0
  131. data/app/services/collavre/creatives/filter_pipeline.rb +26 -42
  132. data/app/services/collavre/creatives/filters/search_filter.rb +12 -2
  133. data/app/services/collavre/creatives/index_query.rb +195 -24
  134. data/app/services/collavre/creatives/permission_filter.rb +50 -0
  135. data/app/services/collavre/creatives/reveal_path_resolver.rb +118 -0
  136. data/app/services/collavre/creatives/tree_builder.rb +2 -1
  137. data/app/services/collavre/crons/recurring_task_arguments.rb +28 -0
  138. data/app/services/collavre/gemini_parent_recommender.rb +1 -1
  139. data/app/services/collavre/inbox_reply_service.rb +5 -0
  140. data/app/services/collavre/markdown_converter.rb +13 -3
  141. data/app/services/collavre/mobile/event_summarizer.rb +40 -0
  142. data/app/services/collavre/orchestration/agent_orchestrator.rb +33 -7
  143. data/app/services/collavre/orchestration/arbiter.rb +16 -0
  144. data/app/services/collavre/orchestration/matcher.rb +79 -4
  145. data/app/services/collavre/orchestration/policy_resolver.rb +4 -3
  146. data/app/services/collavre/orchestration/stuck_detector.rb +146 -19
  147. data/app/services/collavre/tools/creative_attach_files_service.rb +29 -63
  148. data/app/services/collavre/tools/creative_batch_service.rb +3 -2
  149. data/app/services/collavre/tools/creative_create_service.rb +8 -8
  150. data/app/services/collavre/tools/creative_remove_attachment_service.rb +7 -5
  151. data/app/services/collavre/tools/creative_update_service.rb +23 -8
  152. data/app/services/collavre/tools/cron_list_service.rb +1 -14
  153. data/app/services/collavre/topics/orphaned_cron_notifier.rb +68 -0
  154. data/app/services/collavre/typo_corrector.rb +188 -0
  155. data/app/views/collavre/admin/integrations/_category.html.erb +1 -1
  156. data/app/views/collavre/admin/integrations/_setting_row.html.erb +27 -11
  157. data/app/views/collavre/comments/_comment.html.erb +15 -1
  158. data/app/views/collavre/comments/_comments_popup.html.erb +18 -3
  159. data/app/views/collavre/creatives/_inline_edit_form.html.erb +1 -0
  160. data/app/views/collavre/creatives/_topic_move_members_modal.html.erb +42 -0
  161. data/app/views/collavre/creatives/index.html.erb +14 -1
  162. data/app/views/collavre/creatives/slide_view.html.erb +1 -1
  163. data/app/views/collavre/shared/_link_creative_modal.html.erb +6 -2
  164. data/app/views/collavre/users/show.html.erb +3 -0
  165. data/app/views/collavre/users/typo_correction.html.erb +50 -0
  166. data/app/views/layouts/collavre/slide.html.erb +1 -0
  167. data/config/locales/channels.en.yml +2 -0
  168. data/config/locales/channels.ko.yml +2 -0
  169. data/config/locales/claude_channel.en.yml +16 -0
  170. data/config/locales/claude_channel.ko.yml +16 -0
  171. data/config/locales/comments.en.yml +18 -0
  172. data/config/locales/comments.ko.yml +18 -0
  173. data/config/locales/creatives.en.yml +2 -0
  174. data/config/locales/creatives.ko.yml +2 -0
  175. data/config/locales/integrations.en.yml +13 -2
  176. data/config/locales/integrations.ko.yml +13 -2
  177. data/config/locales/mobile.en.yml +16 -0
  178. data/config/locales/mobile.ko.yml +16 -0
  179. data/config/locales/orchestration.en.yml +1 -0
  180. data/config/locales/orchestration.ko.yml +1 -0
  181. data/config/locales/users.en.yml +15 -0
  182. data/config/locales/users.ko.yml +15 -0
  183. data/config/routes.rb +25 -0
  184. data/db/migrate/20260609000000_drop_action_text_rich_texts.rb +20 -0
  185. data/db/migrate/20260609005000_add_session_id_to_topics.rb +16 -0
  186. data/db/migrate/20260609010000_create_agent_subscriptions.rb +19 -0
  187. data/db/migrate/20260609020000_add_last_seen_at_to_agent_subscriptions.rb +23 -0
  188. data/db/migrate/20260609030000_add_session_id_to_agent_subscriptions.rb +17 -0
  189. data/db/migrate/20260609190659_backfill_creative_files_into_description.rb +24 -0
  190. data/db/migrate/20260612000000_add_topic_concurrency_defer_to_comments.rb +38 -0
  191. data/db/migrate/20260617090000_add_typo_correction_settings_to_users.rb +18 -0
  192. data/db/seeds.rb +51 -0
  193. data/lib/collavre/engine.rb +0 -1
  194. data/lib/collavre/integration_settings/key_definition.rb +6 -0
  195. data/lib/collavre/integration_settings/registry.rb +7 -2
  196. data/lib/collavre/version.rb +1 -1
  197. data/lib/generators/collavre/install/install_generator.rb +1 -0
  198. metadata +85 -3
  199. data/app/services/collavre/openclaw_abort_service.rb +0 -45
  200. data/app/services/collavre/tools/description_normalizable.rb +0 -16
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f24eeb18d0272f998210dbfd04bd15a5ac4bf9fab0a61c400ac64298b17cdf3c
4
- data.tar.gz: dd4c2d977abfb6831b971f6c9ed8a7343329a48af8cff04674502a2840bd0f37
3
+ metadata.gz: 6f4893a3f3e45871df84841cc2d16c81e9f0f3805f8cbfe5f40b4dac85ca9e89
4
+ data.tar.gz: 8032ab111bea535825ddbcfa1b0be5b7469e586e05b00ad9117e3f69b373b990
5
5
  SHA512:
6
- metadata.gz: 55aa0ac2253e57cf0b4ac5d3de3a8028aa254b1b9d0b02fce88f4ac5cc3ab532588e574aebf1392bc40328f24061b1e75c74a3576f48ebc5b24d0aa5d3beebef
7
- data.tar.gz: 97d1c389fdd7d00635a4ce87c5b3c9b4f0238f4c69f94e794dcbf42284da51994d35d9821da7f04f91d58857cef4ee697a128df54e914743be31d15a70d52c9b
6
+ metadata.gz: 4b1585a65d7385ebfca1c6b9c5ca4f76f6c5c37454b5a8b9ce550b4d11a1a10445a314202b01b958928d2093bf012d057c549d013c7ea4c94699dbe2cba494df
7
+ data.tar.gz: fce204b25581ce93e72abf20dd076a8af40624d9fd49d3728d4e6c9932e5e7abd8cc345d0d87e3ffe2b35053ebf05736b93db93ddc06f4c2b6c7f909fe0c86d0
data/README.md CHANGED
@@ -90,6 +90,7 @@ Add to your application layout:
90
90
  <%= stylesheet_link_tag "collavre/actiontext" %>
91
91
  <%= stylesheet_link_tag "collavre/activity_logs" %>
92
92
  <%= stylesheet_link_tag "collavre/comments_popup" %>
93
+ <%= stylesheet_link_tag "collavre/tables" %>
93
94
  <%= stylesheet_link_tag "collavre/dark_mode" %>
94
95
  <%= stylesheet_link_tag "collavre/mention_menu" %>
95
96
  <%= stylesheet_link_tag "collavre/popup" %>
@@ -273,30 +273,157 @@
273
273
  top: 0.6rem;
274
274
  }
275
275
 
276
- .lexical-paragraph {
276
+ /* Tables: editor theme classes plus the matching display tags, mirroring the
277
+ pattern used for the other .lexical-* rules below. */
278
+ .lexical-table-wrapper {
279
+ overflow-x: auto;
280
+ margin: 0.75rem 0;
281
+ }
282
+
283
+ .lexical-table,
284
+ .creative-content table {
285
+ border-collapse: collapse;
286
+ table-layout: fixed;
287
+ width: 100%;
288
+ margin: 0.75rem 0;
289
+ }
290
+
291
+ .lexical-table-cell,
292
+ .creative-content th,
293
+ .creative-content td {
294
+ border: 1px solid var(--border-color);
295
+ padding: 0.35rem 0.5rem;
296
+ min-width: 4.5rem;
297
+ vertical-align: top;
298
+ text-align: start;
299
+ position: relative;
300
+ word-break: break-word;
301
+ }
302
+
303
+ .lexical-table-cell-header,
304
+ .creative-content th {
305
+ background-color: var(--surface-hover);
306
+ font-weight: var(--weight-6);
307
+ }
308
+
309
+ .lexical-table-selected {
310
+ outline: 2px solid var(--color-link);
311
+ outline-offset: -1px;
312
+ }
313
+
314
+ .lexical-table-selection *::selection {
315
+ background-color: transparent;
316
+ }
317
+
318
+ /* Cell-boundary add-row / add-column buttons (portaled to <body>). */
319
+ .lexical-table-add-rows,
320
+ .lexical-table-add-columns {
321
+ position: absolute;
322
+ z-index: 5;
323
+ border: 1px solid var(--border-color);
324
+ background-color: var(--surface-section);
325
+ cursor: pointer;
326
+ padding: 0;
327
+ }
328
+
329
+ .lexical-table-add-rows::after,
330
+ .lexical-table-add-columns::after {
331
+ content: "+";
332
+ display: flex;
333
+ align-items: center;
334
+ justify-content: center;
335
+ width: 100%;
336
+ height: 100%;
337
+ color: var(--text-muted);
338
+ font-size: 0.9rem;
339
+ line-height: 1;
340
+ }
341
+
342
+ .lexical-table-add-rows:hover,
343
+ .lexical-table-add-columns:hover {
344
+ background-color: var(--surface-hover);
345
+ }
346
+
347
+ /* Cell-gutter delete-row / delete-column buttons. Shown on cell hover in the
348
+ hovered row's left gutter / column's top gutter (mousemove-driven, same proven
349
+ mechanism as the "+" buttons — no focus/selection dependency). */
350
+ .lexical-table-delete-rows,
351
+ .lexical-table-delete-columns {
352
+ position: absolute;
353
+ z-index: 5;
354
+ border: 1px solid var(--border-color);
355
+ background-color: var(--surface-section);
356
+ cursor: pointer;
357
+ padding: 0;
358
+ }
359
+
360
+ .lexical-table-delete-rows::after,
361
+ .lexical-table-delete-columns::after {
362
+ content: "×";
363
+ display: flex;
364
+ align-items: center;
365
+ justify-content: center;
366
+ width: 100%;
367
+ height: 100%;
368
+ color: var(--text-muted);
369
+ font-size: 0.9rem;
370
+ line-height: 1;
371
+ }
372
+
373
+ .lexical-table-delete-rows:hover,
374
+ .lexical-table-delete-columns:hover {
375
+ background-color: var(--danger-surface, var(--surface-hover));
376
+ color: var(--danger-text, var(--text-primary));
377
+ }
378
+
379
+ /* The .lexical-* classes are the editor theme (contenteditable). Markdown is now
380
+ the canonical persisted/displayed form, so .creative-content renders plain
381
+ semantic tags without those classes — mirror each rule onto the matching
382
+ element so the display view matches the editor. .lexical-* kept for the
383
+ editor and for legacy class-bearing HTML saved before the markdown switch.
384
+ .creative-title-content is the title (h1) display of the same description HTML,
385
+ so it needs the identical mirror — otherwise a markdown title renders a plain
386
+ <p> with the browser-default margin and the single-line title style breaks. */
387
+ .lexical-paragraph,
388
+ .creative-content p,
389
+ .creative-title-content p {
277
390
  margin: 0 0 0 0;
278
391
  }
279
392
 
280
393
  .lexical-heading-h1,
281
394
  .lexical-heading-h2,
282
- .lexical-heading-h3 {
395
+ .lexical-heading-h3,
396
+ .creative-content h1,
397
+ .creative-content h2,
398
+ .creative-content h3,
399
+ .creative-title-content h1,
400
+ .creative-title-content h2,
401
+ .creative-title-content h3 {
283
402
  font-weight: var(--weight-6);
284
403
  margin: 0 0 var(--space-2) 0;
285
404
  }
286
405
 
287
- .lexical-heading-h1 {
406
+ .lexical-heading-h1,
407
+ .creative-content h1,
408
+ .creative-title-content h1 {
288
409
  font-size: 1.35rem;
289
410
  }
290
411
 
291
- .lexical-heading-h2 {
412
+ .lexical-heading-h2,
413
+ .creative-content h2,
414
+ .creative-title-content h2 {
292
415
  font-size: 1.2rem;
293
416
  }
294
417
 
295
- .lexical-heading-h3 {
418
+ .lexical-heading-h3,
419
+ .creative-content h3,
420
+ .creative-title-content h3 {
296
421
  font-size: 1.1rem;
297
422
  }
298
423
 
299
- .lexical-quote {
424
+ .lexical-quote,
425
+ .creative-content blockquote,
426
+ .creative-title-content blockquote {
300
427
  border-left: var(--space-1) solid var(--border-color);
301
428
  color: var(--text-muted);
302
429
  margin: 0 0 0.75rem 0;
@@ -304,34 +431,65 @@
304
431
  }
305
432
 
306
433
  .lexical-list-ul,
307
- .lexical-list-ol {
434
+ .lexical-list-ol,
435
+ .creative-content ul,
436
+ .creative-content ol,
437
+ .creative-title-content ul,
438
+ .creative-title-content ol {
308
439
  margin: 0 0 0.75rem 1.25rem;
309
440
  padding: 0;
310
441
  }
311
442
 
312
- .lexical-list-item {
443
+ .lexical-list-item,
444
+ .creative-content li,
445
+ .creative-title-content li {
313
446
  margin: 0.35rem 0;
314
447
  }
315
448
 
316
- .lexical-link {
449
+ /* The wrapper <li> Lexical emits for a nested list holds no text of its own;
450
+ hiding its marker prevents a stray bullet from appearing above the sub-list. */
451
+ .lexical-nested-list-item {
452
+ list-style-type: none;
453
+ }
454
+
455
+ /* Content links only — the clickable creative-row anchor is an ancestor of
456
+ .creative-content, not a descendant, so this never restyles the row wrapper.
457
+ a[download] is excluded: attachment chips carry their own .lexical-attachment style. */
458
+ .lexical-link,
459
+ .creative-content a:not([download]),
460
+ .creative-title-content a:not([download]) {
317
461
  color: var(--color-link);
318
462
  text-decoration: underline;
319
463
  text-decoration-thickness: 1px;
320
464
  }
321
465
 
322
- .lexical-text-bold {
466
+ .lexical-text-bold,
467
+ .creative-content strong,
468
+ .creative-content b,
469
+ .creative-title-content strong,
470
+ .creative-title-content b {
323
471
  font-weight: var(--weight-6);
324
472
  }
325
473
 
326
- .lexical-text-italic {
474
+ .lexical-text-italic,
475
+ .creative-content em,
476
+ .creative-content i,
477
+ .creative-title-content em,
478
+ .creative-title-content i {
327
479
  font-style: italic;
328
480
  }
329
481
 
330
- .lexical-text-underline {
482
+ .lexical-text-underline,
483
+ .creative-content u,
484
+ .creative-title-content u {
331
485
  text-decoration: underline;
332
486
  }
333
487
 
334
- .lexical-text-strike {
488
+ .lexical-text-strike,
489
+ .creative-content s,
490
+ .creative-content del,
491
+ .creative-title-content s,
492
+ .creative-title-content del {
335
493
  text-decoration: line-through;
336
494
  }
337
495
 
@@ -343,18 +501,23 @@
343
501
  padding: 0.1em 0.3em;
344
502
  }
345
503
 
504
+ /* Match the rendered/preview/comment code-block container in code_highlight.css
505
+ * (.creative-content pre et al.) exactly — same font, size, line-height, padding,
506
+ * border — so a code block looks identical in the editor and every rendered surface.
507
+ * Token colors are already shared via the global `.lexical-token-*` rules; this
508
+ * aligns the box so edit mode and view mode no longer diverge in font/size. */
346
509
  .lexical-code-block {
347
510
  display: block;
348
511
  background: var(--color-code-bg);
349
- border: 1px solid var(--border-color);
512
+ border: var(--border-1) solid var(--border-color);
350
513
  border-radius: var(--radius-2);
351
514
  color: var(--color-code-text);
352
- font-family: ui-monospace, SFMono-Regular, SFMono, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
353
- font-size: 0.9em;
354
- line-height: 1.5;
355
- margin: 0 0 0.75rem 0;
515
+ font-family: var(--font-mono);
516
+ font-size: var(--text-0);
517
+ line-height: var(--leading-3);
518
+ margin: var(--space-2) 0;
356
519
  overflow-x: auto;
357
- padding: 0.75rem;
520
+ padding: var(--space-2) var(--space-3);
358
521
  white-space: pre;
359
522
  }
360
523
 
@@ -368,101 +531,99 @@
368
531
  white-space: inherit;
369
532
  }
370
533
 
371
- /* stylelint-disable color-no-hex -- syntax highlight theme colors are intentionally hardcoded */
372
- :root {
373
- --lexical-token-comment: #6a737d;
374
- --lexical-token-punctuation: #393a34;
375
- --lexical-token-property: #b31d28;
376
- --lexical-token-string: #1a7f37;
377
- --lexical-token-operator: #9a6e3a;
378
- --lexical-token-keyword: #0550ae;
379
- --lexical-token-function: #bc4c00;
380
- --lexical-token-regex: #1a7f37;
381
- }
382
-
383
- body.dark-mode {
384
- --lexical-token-comment: #8b949e;
385
- --lexical-token-punctuation: #c9d1d9;
386
- --lexical-token-property: #ff7b72;
387
- --lexical-token-string: #7ee787;
388
- --lexical-token-operator: #ffa657;
389
- --lexical-token-keyword: #79c0ff;
390
- --lexical-token-function: #d2a8ff;
391
- --lexical-token-regex: #7ee787;
392
- }
393
-
394
- @media (prefers-color-scheme: dark) {
395
- body:not(.light-mode):not(.dark-mode) {
396
- --lexical-token-comment: #8b949e;
397
- --lexical-token-punctuation: #c9d1d9;
398
- --lexical-token-property: #ff7b72;
399
- --lexical-token-string: #7ee787;
400
- --lexical-token-operator: #ffa657;
401
- --lexical-token-keyword: #79c0ff;
402
- --lexical-token-function: #d2a8ff;
403
- --lexical-token-regex: #7ee787;
404
- }
405
- }
406
- /* stylelint-enable color-no-hex */
407
-
534
+ /*
535
+ * Code block syntax highlighting inside the Lexical editor.
536
+ *
537
+ * The editor tokenizes code with Prism (@lexical/code) and tags each token
538
+ * with a `.lexical-token-*` class, while the persisted/rendered creative is
539
+ * highlighted with highlight.js (`.hljs-*`, see code_highlight.css). To keep
540
+ * the editing view identical to the rendered view, both surfaces share the
541
+ * single GitHub-style palette defined as `--syntax-*` in code_highlight.css
542
+ * (loaded alongside this sheet via collavre_stylesheets). Each Prism token
543
+ * below maps to the same `--syntax-*` color its highlight.js equivalent uses,
544
+ * so light/dark/auto themes stay in sync with one source of truth — no
545
+ * duplicate `--lexical-token-*` variables to drift.
546
+ */
408
547
  .lexical-token-comment,
409
548
  .lexical-token-prolog,
410
549
  .lexical-token-doctype,
411
550
  .lexical-token-cdata {
412
- color: var(--lexical-token-comment);
551
+ color: var(--syntax-comment);
552
+ font-style: italic;
413
553
  }
414
554
 
415
- .lexical-token-punctuation {
416
- color: var(--lexical-token-punctuation);
555
+ .lexical-token-keyword,
556
+ .lexical-token-atrule,
557
+ .lexical-token-namespace {
558
+ color: var(--syntax-keyword);
417
559
  }
418
560
 
419
- .lexical-token-property,
420
- .lexical-token-tag,
421
- .lexical-token-constant,
422
- .lexical-token-symbol,
423
- .lexical-token-deleted,
561
+ .lexical-token-string,
562
+ .lexical-token-char,
563
+ .lexical-token-url {
564
+ color: var(--syntax-string);
565
+ }
566
+
567
+ .lexical-token-number,
424
568
  .lexical-token-boolean,
425
- .lexical-token-number {
426
- color: var(--lexical-token-property);
569
+ .lexical-token-constant,
570
+ .lexical-token-symbol {
571
+ color: var(--syntax-number);
572
+ }
573
+
574
+ .lexical-token-builtin {
575
+ color: var(--syntax-builtin);
576
+ }
577
+
578
+ .lexical-token-function,
579
+ .lexical-token-class,
580
+ .lexical-token-classname {
581
+ color: var(--syntax-title);
427
582
  }
428
583
 
429
- .lexical-token-selector,
430
584
  .lexical-token-attr,
431
- .lexical-token-string,
432
- .lexical-token-char,
433
- .lexical-token-builtin,
434
- .lexical-token-inserted {
435
- color: var(--lexical-token-string);
585
+ .lexical-token-property {
586
+ color: var(--syntax-attr);
436
587
  }
437
588
 
438
- .lexical-token-operator,
439
- .lexical-token-entity,
440
- .lexical-token-url,
441
589
  .lexical-token-variable {
442
- color: var(--lexical-token-operator);
590
+ color: var(--syntax-variable);
443
591
  }
444
592
 
445
- .lexical-token-atrule,
446
- .lexical-token-keyword,
447
- .lexical-token-class,
448
- .lexical-token-classname,
449
- .lexical-token-namespace {
450
- color: var(--lexical-token-keyword);
593
+ .lexical-token-regex {
594
+ color: var(--syntax-regexp);
451
595
  }
452
596
 
453
- .lexical-token-function,
597
+ .lexical-token-tag {
598
+ color: var(--syntax-tag);
599
+ }
600
+
601
+ .lexical-token-selector {
602
+ color: var(--syntax-selector);
603
+ }
604
+
605
+ /* highlight.js renders `.hljs-meta` (CSS !important) with color only, no
606
+ bold — match that so the editor doesn't diverge from the rendered view. */
454
607
  .lexical-token-important {
455
- color: var(--lexical-token-function);
608
+ color: var(--syntax-meta);
456
609
  }
457
610
 
458
- .lexical-token-regex {
459
- color: var(--lexical-token-regex);
611
+ /* highlight.js leaves operators and punctuation at the default code color;
612
+ match that here instead of the old custom operator hue. */
613
+ .lexical-token-punctuation,
614
+ .lexical-token-operator,
615
+ .lexical-token-entity {
616
+ color: var(--color-code-text);
460
617
  }
461
618
 
462
- .lexical-token-tag,
463
- .lexical-token-selector,
464
- .lexical-token-keyword {
465
- font-weight: var(--weight-6);
619
+ .lexical-token-deleted {
620
+ color: var(--syntax-deletion-text);
621
+ background: var(--syntax-deletion-bg);
622
+ }
623
+
624
+ .lexical-token-inserted {
625
+ color: var(--syntax-addition-text);
626
+ background: var(--syntax-addition-bg);
466
627
  }
467
628
 
468
629
  .lexical-attachment {
@@ -2,11 +2,14 @@
2
2
  * Code Syntax Highlighting Theme
3
3
  *
4
4
  * Uses Collavre design tokens (--color-code-bg, --color-code-text, --font-mono).
5
- * Syntax color tokens defined as CSS variables overridden per theme context.
6
- * Based on GitHub-style highlighting.
5
+ * Defines the GitHub-style `--syntax-*` color variables (overridden per theme
6
+ * context) plus the code-block container and inline-code styling. The per-token
7
+ * color rules live in actiontext.css keyed on the `.lexical-token-*` classes that
8
+ * every surface now emits (editor + rendered creative + preview + comments all
9
+ * tokenize with the same Prism), and consume these `--syntax-*` variables.
7
10
  *
8
- * Scoped to the markdown rendering surfaces so they share container,
9
- * inline-code, and syntax-token styles:
11
+ * Scoped to the markdown rendering surfaces so they share container and
12
+ * inline-code styles:
10
13
  * .comment-content — chat / comments
11
14
  * .markdown-preview — creative inline editor live preview
12
15
  * .creative-content — persisted creative description in the tree view
@@ -144,200 +147,3 @@ body.dark-mode {
144
147
  font-family: var(--font-mono);
145
148
  font-size: 0.9em;
146
149
  }
147
-
148
- /* ============================================================================
149
- * SYNTAX HIGHLIGHTING RULES (token-based, theme-agnostic)
150
- * ============================================================================ */
151
- .comment-content .hljs-comment,
152
- .comment-content .hljs-quote,
153
- .markdown-preview .hljs-comment,
154
- .markdown-preview .hljs-quote,
155
- .creative-content .hljs-comment,
156
- .creative-content .hljs-quote,
157
- .creative-title-content .hljs-comment,
158
- .creative-title-content .hljs-quote {
159
- color: var(--syntax-comment);
160
- font-style: italic;
161
- }
162
-
163
- .comment-content .hljs-keyword,
164
- .comment-content .hljs-selector-tag,
165
- .comment-content .hljs-type,
166
- .markdown-preview .hljs-keyword,
167
- .markdown-preview .hljs-selector-tag,
168
- .markdown-preview .hljs-type,
169
- .creative-content .hljs-keyword,
170
- .creative-content .hljs-selector-tag,
171
- .creative-content .hljs-type,
172
- .creative-title-content .hljs-keyword,
173
- .creative-title-content .hljs-selector-tag,
174
- .creative-title-content .hljs-type {
175
- color: var(--syntax-keyword);
176
- }
177
-
178
- .comment-content .hljs-string,
179
- .markdown-preview .hljs-string,
180
- .creative-content .hljs-string,
181
- .creative-title-content .hljs-string {
182
- color: var(--syntax-string);
183
- }
184
-
185
- .comment-content .hljs-number,
186
- .comment-content .hljs-literal,
187
- .markdown-preview .hljs-number,
188
- .markdown-preview .hljs-literal,
189
- .creative-content .hljs-number,
190
- .creative-content .hljs-literal,
191
- .creative-title-content .hljs-number,
192
- .creative-title-content .hljs-literal {
193
- color: var(--syntax-number);
194
- }
195
-
196
- .comment-content .hljs-built_in,
197
- .comment-content .hljs-builtin-name,
198
- .markdown-preview .hljs-built_in,
199
- .markdown-preview .hljs-builtin-name,
200
- .creative-content .hljs-built_in,
201
- .creative-content .hljs-builtin-name,
202
- .creative-title-content .hljs-built_in,
203
- .creative-title-content .hljs-builtin-name {
204
- color: var(--syntax-builtin);
205
- }
206
-
207
- .comment-content .hljs-title,
208
- .comment-content .hljs-title.function_,
209
- .markdown-preview .hljs-title,
210
- .markdown-preview .hljs-title.function_,
211
- .creative-content .hljs-title,
212
- .creative-content .hljs-title.function_,
213
- .creative-title-content .hljs-title,
214
- .creative-title-content .hljs-title.function_ {
215
- color: var(--syntax-title);
216
- }
217
-
218
- .comment-content .hljs-attr,
219
- .comment-content .hljs-attribute,
220
- .markdown-preview .hljs-attr,
221
- .markdown-preview .hljs-attribute,
222
- .creative-content .hljs-attr,
223
- .creative-content .hljs-attribute,
224
- .creative-title-content .hljs-attr,
225
- .creative-title-content .hljs-attribute {
226
- color: var(--syntax-attr);
227
- }
228
-
229
- .comment-content .hljs-variable,
230
- .comment-content .hljs-template-variable,
231
- .markdown-preview .hljs-variable,
232
- .markdown-preview .hljs-template-variable,
233
- .creative-content .hljs-variable,
234
- .creative-content .hljs-template-variable,
235
- .creative-title-content .hljs-variable,
236
- .creative-title-content .hljs-template-variable {
237
- color: var(--syntax-variable);
238
- }
239
-
240
- .comment-content .hljs-params,
241
- .markdown-preview .hljs-params,
242
- .creative-content .hljs-params,
243
- .creative-title-content .hljs-params {
244
- color: var(--color-code-text);
245
- }
246
-
247
- .comment-content .hljs-regexp,
248
- .markdown-preview .hljs-regexp,
249
- .creative-content .hljs-regexp,
250
- .creative-title-content .hljs-regexp {
251
- color: var(--syntax-regexp);
252
- }
253
-
254
- .comment-content .hljs-tag,
255
- .markdown-preview .hljs-tag,
256
- .creative-content .hljs-tag,
257
- .creative-title-content .hljs-tag {
258
- color: var(--syntax-tag);
259
- }
260
-
261
- .comment-content .hljs-name,
262
- .markdown-preview .hljs-name,
263
- .creative-content .hljs-name,
264
- .creative-title-content .hljs-name {
265
- color: var(--syntax-name);
266
- }
267
-
268
- .comment-content .hljs-selector-class,
269
- .comment-content .hljs-selector-id,
270
- .markdown-preview .hljs-selector-class,
271
- .markdown-preview .hljs-selector-id,
272
- .creative-content .hljs-selector-class,
273
- .creative-content .hljs-selector-id,
274
- .creative-title-content .hljs-selector-class,
275
- .creative-title-content .hljs-selector-id {
276
- color: var(--syntax-selector);
277
- }
278
-
279
- .comment-content .hljs-selector-attr,
280
- .comment-content .hljs-selector-pseudo,
281
- .markdown-preview .hljs-selector-attr,
282
- .markdown-preview .hljs-selector-pseudo,
283
- .creative-content .hljs-selector-attr,
284
- .creative-content .hljs-selector-pseudo,
285
- .creative-title-content .hljs-selector-attr,
286
- .creative-title-content .hljs-selector-pseudo {
287
- color: var(--syntax-attr);
288
- }
289
-
290
- .comment-content .hljs-symbol,
291
- .comment-content .hljs-bullet,
292
- .markdown-preview .hljs-symbol,
293
- .markdown-preview .hljs-bullet,
294
- .creative-content .hljs-symbol,
295
- .creative-content .hljs-bullet,
296
- .creative-title-content .hljs-symbol,
297
- .creative-title-content .hljs-bullet {
298
- color: var(--syntax-number);
299
- }
300
-
301
- .comment-content .hljs-meta,
302
- .markdown-preview .hljs-meta,
303
- .creative-content .hljs-meta,
304
- .creative-title-content .hljs-meta {
305
- color: var(--syntax-meta);
306
- }
307
-
308
- .comment-content .hljs-punctuation,
309
- .markdown-preview .hljs-punctuation,
310
- .creative-content .hljs-punctuation,
311
- .creative-title-content .hljs-punctuation {
312
- color: var(--color-code-text);
313
- }
314
-
315
- .comment-content .hljs-deletion,
316
- .markdown-preview .hljs-deletion,
317
- .creative-content .hljs-deletion,
318
- .creative-title-content .hljs-deletion {
319
- color: var(--syntax-deletion-text);
320
- background: var(--syntax-deletion-bg);
321
- }
322
-
323
- .comment-content .hljs-addition,
324
- .markdown-preview .hljs-addition,
325
- .creative-content .hljs-addition,
326
- .creative-title-content .hljs-addition {
327
- color: var(--syntax-addition-text);
328
- background: var(--syntax-addition-bg);
329
- }
330
-
331
- .comment-content .hljs-emphasis,
332
- .markdown-preview .hljs-emphasis,
333
- .creative-content .hljs-emphasis,
334
- .creative-title-content .hljs-emphasis {
335
- font-style: italic;
336
- }
337
-
338
- .comment-content .hljs-strong,
339
- .markdown-preview .hljs-strong,
340
- .creative-content .hljs-strong,
341
- .creative-title-content .hljs-strong {
342
- font-weight: var(--weight-7);
343
- }