includio-cms 0.1.4 → 0.5.1

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 (310) hide show
  1. package/CHANGELOG.md +83 -0
  2. package/ROADMAP.md +26 -13
  3. package/dist/admin/api/accept-invite.js +1 -5
  4. package/dist/admin/api/invite.js +7 -16
  5. package/dist/admin/client/account/account-page.svelte +20 -50
  6. package/dist/admin/client/account/lang.d.ts +15 -23
  7. package/dist/admin/client/account/lang.js +51 -67
  8. package/dist/admin/client/account/preferences-section.svelte +26 -84
  9. package/dist/admin/client/account/profile-section.svelte +60 -40
  10. package/dist/admin/client/account/schema.d.ts +11 -3
  11. package/dist/admin/client/account/schema.js +25 -16
  12. package/dist/admin/client/account/security-section.svelte +139 -105
  13. package/dist/admin/client/account/sessions-section.svelte +35 -34
  14. package/dist/admin/client/admin/admin-after-login-layout-content.svelte +3 -5
  15. package/dist/admin/client/admin/admin-layout.svelte +3 -2
  16. package/dist/admin/client/admin/admin-preloader.svelte +36 -0
  17. package/dist/admin/client/admin/admin-preloader.svelte.d.ts +18 -0
  18. package/dist/admin/client/admin/dashboard-page.svelte +35 -67
  19. package/dist/admin/client/collection/a11y-score-cell.svelte +45 -0
  20. package/dist/admin/client/collection/a11y-score-cell.svelte.d.ts +6 -0
  21. package/dist/admin/client/collection/bulk-actions-bar.svelte +100 -0
  22. package/dist/admin/client/collection/bulk-actions-bar.svelte.d.ts +10 -0
  23. package/dist/admin/client/collection/collection-entries.svelte +277 -258
  24. package/dist/admin/client/collection/collection-view.svelte.d.ts +4 -3
  25. package/dist/admin/client/collection/collection-view.svelte.js +9 -5
  26. package/dist/admin/client/collection/collection.svelte +22 -12
  27. package/dist/admin/client/collection/data-table.svelte +50 -39
  28. package/dist/admin/client/collection/data-table.svelte.d.ts +1 -0
  29. package/dist/admin/client/collection/date-cell.svelte +7 -5
  30. package/dist/admin/client/collection/date-cell.svelte.d.ts +1 -1
  31. package/dist/admin/client/collection/empty-state.svelte +28 -0
  32. package/dist/admin/client/collection/empty-state.svelte.d.ts +9 -0
  33. package/dist/admin/client/collection/entry-link.svelte +10 -4
  34. package/dist/admin/client/collection/entry-link.svelte.d.ts +1 -0
  35. package/dist/admin/client/collection/grid-view.svelte +21 -23
  36. package/dist/admin/client/collection/grid-view.svelte.d.ts +1 -2
  37. package/dist/admin/client/collection/row-actions.svelte +69 -0
  38. package/dist/admin/client/collection/row-actions.svelte.d.ts +10 -0
  39. package/dist/admin/client/collection/status-badge.svelte +7 -8
  40. package/dist/admin/client/collection/table-pagination.svelte +122 -79
  41. package/dist/admin/client/collection/table-pagination.svelte.d.ts +1 -0
  42. package/dist/admin/client/collection/table-toolbar.svelte +108 -88
  43. package/dist/admin/client/collection/table-toolbar.svelte.d.ts +8 -9
  44. package/dist/admin/client/entry/entry-form.svelte +109 -1
  45. package/dist/admin/client/entry/entry-header.svelte +143 -37
  46. package/dist/admin/client/entry/entry-header.svelte.d.ts +8 -0
  47. package/dist/admin/client/entry/entry.svelte +272 -61
  48. package/dist/admin/client/entry/header/a11y-validator.d.ts +47 -0
  49. package/dist/admin/client/entry/header/a11y-validator.js +352 -0
  50. package/dist/admin/client/entry/header/publish-panel.svelte +531 -129
  51. package/dist/admin/client/entry/header/publish-panel.svelte.d.ts +4 -0
  52. package/dist/admin/client/entry/header/save-indicator.svelte +33 -23
  53. package/dist/admin/client/entry/header/schedule-popover.svelte +1 -1
  54. package/dist/admin/client/entry/header/status-badge.svelte +25 -118
  55. package/dist/admin/client/entry/header/version-history-sheet.svelte +322 -98
  56. package/dist/admin/client/form/form-submission/form-submission.svelte +271 -83
  57. package/dist/admin/client/form/form-submission/submission-field.svelte +12 -12
  58. package/dist/admin/client/form/form-submissions.svelte +421 -139
  59. package/dist/admin/client/form/submission-link.svelte +8 -2
  60. package/dist/admin/client/form/submission-link.svelte.d.ts +1 -0
  61. package/dist/admin/client/form/submission-status-badge.svelte +18 -4
  62. package/dist/admin/client/form/submission-status-badge.svelte.d.ts +1 -0
  63. package/dist/admin/client/login/lang.d.ts +32 -0
  64. package/dist/admin/client/login/lang.js +66 -2
  65. package/dist/admin/client/login/login-form.svelte +237 -95
  66. package/dist/admin/client/login/login-form.svelte.d.ts +2 -17
  67. package/dist/admin/client/login/login-page.svelte +34 -98
  68. package/dist/admin/client/login/reset-password-page.svelte +235 -0
  69. package/dist/admin/client/login/reset-password-page.svelte.d.ts +4 -0
  70. package/dist/admin/client/login/schema.d.ts +15 -0
  71. package/dist/admin/client/login/schema.js +21 -0
  72. package/dist/admin/client/users/accept-invite-page.svelte +166 -37
  73. package/dist/admin/client/users/create-user-dialog.svelte +15 -7
  74. package/dist/admin/client/users/delete-user-dialog.svelte +81 -16
  75. package/dist/admin/client/users/delete-user-dialog.svelte.d.ts +4 -1
  76. package/dist/admin/client/users/edit-user-dialog.svelte +3 -0
  77. package/dist/admin/client/users/invite-user-dialog.svelte +16 -3
  78. package/dist/admin/client/users/lang.d.ts +27 -0
  79. package/dist/admin/client/users/lang.js +64 -10
  80. package/dist/admin/client/users/pending-invitations.svelte +59 -23
  81. package/dist/admin/client/users/users-page.svelte +471 -72
  82. package/dist/admin/components/accessibility/accessibility-overview.svelte +2 -7
  83. package/dist/admin/components/dashboard/a11y-gauge.svelte +90 -0
  84. package/dist/admin/components/dashboard/a11y-gauge.svelte.d.ts +18 -0
  85. package/dist/admin/components/dashboard/accessibility-hub.svelte +13 -12
  86. package/dist/admin/components/dashboard/changelog-dialog.svelte +157 -0
  87. package/dist/admin/components/dashboard/changelog-dialog.svelte.d.ts +6 -0
  88. package/dist/admin/components/dashboard/form-submissions-widget.svelte +71 -113
  89. package/dist/admin/components/dashboard/index.d.ts +4 -2
  90. package/dist/admin/components/dashboard/index.js +4 -2
  91. package/dist/admin/components/dashboard/orphaned-entries-notice.svelte +240 -0
  92. package/dist/admin/components/dashboard/orphaned-entries-notice.svelte.d.ts +13 -0
  93. package/dist/admin/components/dashboard/recent-activity.svelte +53 -75
  94. package/dist/admin/components/dashboard/recent-entries.svelte +94 -0
  95. package/dist/admin/components/dashboard/recent-entries.svelte.d.ts +18 -0
  96. package/dist/admin/components/dashboard/stat-card.svelte +2 -2
  97. package/dist/admin/components/dashboard/tip-of-the-day.svelte +109 -0
  98. package/dist/admin/components/dashboard/tip-of-the-day.svelte.d.ts +3 -0
  99. package/dist/admin/components/dashboard/welcome-header.svelte +45 -0
  100. package/dist/admin/components/dashboard/welcome-header.svelte.d.ts +3 -0
  101. package/dist/admin/components/fields/{array-field.svelte → blocks-field.svelte} +4 -4
  102. package/dist/admin/components/fields/{array-field.svelte.d.ts → blocks-field.svelte.d.ts} +5 -5
  103. package/dist/admin/components/fields/content-field.svelte +27 -0
  104. package/dist/admin/components/fields/content-field.svelte.d.ts +31 -0
  105. package/dist/admin/components/fields/field-renderer.svelte +9 -7
  106. package/dist/admin/components/fields/image-field.svelte +2 -2
  107. package/dist/admin/components/fields/media-field.svelte +2 -2
  108. package/dist/admin/components/fields/seo-field.svelte +205 -25
  109. package/dist/admin/components/fields/simple-array-field.svelte +289 -0
  110. package/dist/admin/components/fields/simple-array-field.svelte.d.ts +30 -0
  111. package/dist/admin/components/fields/slug-field.svelte +3 -2
  112. package/dist/admin/components/fields/standalone-field-renderer.svelte +148 -0
  113. package/dist/admin/components/fields/standalone-field-renderer.svelte.d.ts +9 -0
  114. package/dist/admin/components/fields/text-field-wrapper.svelte +147 -3
  115. package/dist/admin/components/fields/text-field-wrapper.svelte.d.ts +2 -2
  116. package/dist/admin/components/fields/url-field.svelte +5 -4
  117. package/dist/admin/components/layout/app-sidebar.svelte +27 -24
  118. package/dist/admin/components/layout/lang.d.ts +6 -0
  119. package/dist/admin/components/layout/lang.js +13 -1
  120. package/dist/admin/components/layout/layout-renderer.svelte +352 -0
  121. package/dist/admin/components/layout/layout-renderer.svelte.d.ts +14 -0
  122. package/dist/admin/components/layout/nav-breadcrumbs.svelte +4 -4
  123. package/dist/admin/components/layout/nav-collections.svelte +65 -36
  124. package/dist/admin/components/layout/nav-footer.svelte +38 -0
  125. package/dist/admin/components/layout/nav-footer.svelte.d.ts +3 -0
  126. package/dist/admin/components/layout/nav-forms.svelte +55 -30
  127. package/dist/admin/components/layout/nav-main.svelte +14 -52
  128. package/dist/admin/components/layout/nav-search.svelte +4 -3
  129. package/dist/admin/components/layout/nav-singletons.svelte +59 -17
  130. package/dist/admin/components/layout/nav-singletons.svelte.d.ts +17 -8
  131. package/dist/admin/components/layout/site-header.svelte +74 -13
  132. package/dist/admin/components/media/alt-input.svelte +32 -22
  133. package/dist/admin/components/media/bulk-action-bar.svelte +139 -150
  134. package/dist/admin/components/media/file/file-details.svelte +299 -217
  135. package/dist/admin/components/media/file/file-miniature.svelte +54 -41
  136. package/dist/admin/components/media/file/file-miniature.svelte.d.ts +1 -0
  137. package/dist/admin/components/media/file/file-preview.svelte +1 -1
  138. package/dist/admin/components/media/file-upload.svelte +24 -26
  139. package/dist/admin/components/media/files-list.svelte +112 -40
  140. package/dist/admin/components/media/files-list.svelte.d.ts +2 -0
  141. package/dist/admin/components/media/focal-point-input.svelte +122 -26
  142. package/dist/admin/components/media/media-library.svelte +127 -70
  143. package/dist/admin/components/media/media-search.svelte +6 -6
  144. package/dist/admin/components/media/media-sort.svelte +3 -1
  145. package/dist/admin/components/media/multi-file-summary.svelte +88 -68
  146. package/dist/admin/components/media/tag-combobox.svelte +141 -66
  147. package/dist/admin/components/media/tag-combobox.svelte.d.ts +1 -0
  148. package/dist/admin/components/media/tag-sidebar.svelte +139 -121
  149. package/dist/admin/components/tiptap/FigureNodeView.svelte +144 -15
  150. package/dist/admin/components/tiptap/InlineBlockNodeView.svelte +254 -0
  151. package/dist/admin/components/tiptap/InlineBlockNodeView.svelte.d.ts +4 -0
  152. package/dist/admin/components/tiptap/SlashCommandPopup.svelte +212 -0
  153. package/dist/admin/components/tiptap/SlashCommandPopup.svelte.d.ts +8 -0
  154. package/dist/admin/components/tiptap/content-editor.svelte +280 -0
  155. package/dist/admin/components/tiptap/content-editor.svelte.d.ts +9 -0
  156. package/dist/admin/components/tiptap/editor-toolbar.svelte +230 -0
  157. package/dist/admin/components/tiptap/editor-toolbar.svelte.d.ts +16 -0
  158. package/dist/admin/components/tiptap/heading-a11y-plugin.d.ts +2 -0
  159. package/dist/admin/components/tiptap/heading-a11y-plugin.js +67 -0
  160. package/dist/admin/components/tiptap/image-dialog.svelte +172 -11
  161. package/dist/admin/components/tiptap/inline-block-node.d.ts +19 -0
  162. package/dist/admin/components/tiptap/inline-block-node.js +98 -0
  163. package/dist/admin/components/tiptap/link-dialog.svelte +9 -4
  164. package/dist/admin/components/tiptap/slash-command.d.ts +17 -0
  165. package/dist/admin/components/tiptap/slash-command.js +181 -0
  166. package/dist/admin/components/tiptap/structured-content-utils.d.ts +21 -0
  167. package/dist/admin/components/tiptap/structured-content-utils.js +150 -0
  168. package/dist/admin/components/tiptap/tiptap-editor.svelte +18 -190
  169. package/dist/admin/email/invite-template.d.ts +8 -0
  170. package/dist/admin/email/invite-template.js +99 -0
  171. package/dist/admin/email/reset-password-template.d.ts +7 -0
  172. package/dist/admin/email/reset-password-template.js +96 -0
  173. package/dist/admin/remote/ai.remote.d.ts +1 -0
  174. package/dist/admin/remote/ai.remote.js +4 -1
  175. package/dist/admin/remote/entry.remote.d.ts +9 -0
  176. package/dist/admin/remote/entry.remote.js +58 -8
  177. package/dist/admin/remote/preview.remote.js +2 -1
  178. package/dist/admin/shared/password-schema.d.ts +5 -0
  179. package/dist/admin/shared/password-schema.js +10 -0
  180. package/dist/admin/state/content-language.svelte.d.ts +3 -0
  181. package/dist/admin/state/content-language.svelte.js +8 -0
  182. package/dist/admin/styles/admin.css +1530 -151
  183. package/dist/admin/utils/formatDate.d.ts +1 -0
  184. package/dist/admin/utils/formatDate.js +8 -0
  185. package/dist/admin/utils/roleLabel.d.ts +2 -0
  186. package/dist/admin/utils/roleLabel.js +13 -0
  187. package/dist/admin/utils/translationStatus.d.ts +17 -0
  188. package/dist/admin/utils/translationStatus.js +134 -0
  189. package/dist/ai-claude/index.d.ts +2 -0
  190. package/dist/ai-claude/index.js +56 -0
  191. package/dist/cms/runtime/api.d.ts +6 -1
  192. package/dist/cms/runtime/api.js +3 -0
  193. package/dist/cms/runtime/schemas.d.ts +9 -1
  194. package/dist/cms/runtime/schemas.js +8 -0
  195. package/dist/cms/runtime/types.d.ts +82 -10
  196. package/dist/cms/runtime/types.js +4 -0
  197. package/dist/components/ui/accordion/accordion.stories.svelte +39 -0
  198. package/dist/components/ui/accordion/accordion.stories.svelte.d.ts +27 -0
  199. package/dist/components/ui/alert/alert.stories.svelte +53 -0
  200. package/dist/components/ui/alert/alert.stories.svelte.d.ts +27 -0
  201. package/dist/components/ui/alert/alert.svelte +5 -0
  202. package/dist/components/ui/alert/alert.svelte.d.ts +9 -0
  203. package/dist/components/ui/avatar/avatar.stories.svelte +16 -0
  204. package/dist/components/ui/avatar/avatar.stories.svelte.d.ts +27 -0
  205. package/dist/components/ui/badge/badge.stories.svelte +33 -0
  206. package/dist/components/ui/badge/badge.stories.svelte.d.ts +27 -0
  207. package/dist/components/ui/breadcrumb/breadcrumb.stories.svelte +33 -0
  208. package/dist/components/ui/breadcrumb/breadcrumb.stories.svelte.d.ts +27 -0
  209. package/dist/components/ui/button/button.stories.svelte +43 -0
  210. package/dist/components/ui/button/button.stories.svelte.d.ts +27 -0
  211. package/dist/components/ui/button/button.svelte +1 -2
  212. package/dist/components/ui/button/button.svelte.d.ts +0 -3
  213. package/dist/components/ui/button-group/button-group-separator.svelte.d.ts +1 -1
  214. package/dist/components/ui/card/card.stories.svelte +42 -0
  215. package/dist/components/ui/card/card.stories.svelte.d.ts +27 -0
  216. package/dist/components/ui/command/command.stories.svelte +51 -0
  217. package/dist/components/ui/command/command.stories.svelte.d.ts +27 -0
  218. package/dist/components/ui/dialog/dialog.stories.svelte +29 -0
  219. package/dist/components/ui/dialog/dialog.stories.svelte.d.ts +27 -0
  220. package/dist/components/ui/field/field-label.svelte.d.ts +1 -1
  221. package/dist/components/ui/field/field.stories.svelte +21 -0
  222. package/dist/components/ui/field/field.stories.svelte.d.ts +27 -0
  223. package/dist/components/ui/input/input.stories.svelte +40 -0
  224. package/dist/components/ui/input/input.stories.svelte.d.ts +27 -0
  225. package/dist/components/ui/input/input.svelte +2 -4
  226. package/dist/components/ui/item/item-separator.svelte.d.ts +1 -1
  227. package/dist/components/ui/label/label.stories.svelte +20 -0
  228. package/dist/components/ui/label/label.stories.svelte.d.ts +27 -0
  229. package/dist/components/ui/popover/popover.stories.svelte +29 -0
  230. package/dist/components/ui/popover/popover.stories.svelte.d.ts +27 -0
  231. package/dist/components/ui/select/select-group-heading.svelte.d.ts +1 -1
  232. package/dist/components/ui/select/select.stories.svelte +23 -0
  233. package/dist/components/ui/select/select.stories.svelte.d.ts +27 -0
  234. package/dist/components/ui/separator/separator.stories.svelte +24 -0
  235. package/dist/components/ui/separator/separator.stories.svelte.d.ts +27 -0
  236. package/dist/components/ui/sheet/sheet.stories.svelte +29 -0
  237. package/dist/components/ui/sheet/sheet.stories.svelte.d.ts +27 -0
  238. package/dist/components/ui/sidebar/sidebar-group.svelte +3 -3
  239. package/dist/components/ui/sidebar/sidebar-group.svelte.d.ts +2 -2
  240. package/dist/components/ui/sidebar/sidebar-menu-button.svelte +28 -30
  241. package/dist/components/ui/sidebar/sidebar-menu-button.svelte.d.ts +7 -7
  242. package/dist/components/ui/sidebar/sidebar-separator.svelte.d.ts +1 -1
  243. package/dist/components/ui/sidebar/sidebar-trigger.svelte +4 -4
  244. package/dist/components/ui/sonner/sonner.stories.svelte +22 -0
  245. package/dist/components/ui/sonner/sonner.stories.svelte.d.ts +26 -0
  246. package/dist/components/ui/sonner/sonner.svelte +8 -2
  247. package/dist/components/ui/sonner/toast-demo.svelte +29 -0
  248. package/dist/components/ui/sonner/toast-demo.svelte.d.ts +6 -0
  249. package/dist/components/ui/textarea/textarea.stories.svelte +22 -0
  250. package/dist/components/ui/textarea/textarea.stories.svelte.d.ts +27 -0
  251. package/dist/components/ui/textarea/textarea.svelte +0 -2
  252. package/dist/components/ui/toggle/toggle.stories.svelte +22 -0
  253. package/dist/components/ui/toggle/toggle.stories.svelte.d.ts +27 -0
  254. package/dist/components/ui/toggle-group/toggle-group.stories.svelte +17 -0
  255. package/dist/components/ui/toggle-group/toggle-group.stories.svelte.d.ts +27 -0
  256. package/dist/components/ui/tooltip/tooltip.stories.svelte +26 -0
  257. package/dist/components/ui/tooltip/tooltip.stories.svelte.d.ts +27 -0
  258. package/dist/core/fields/fieldSchemaToTs.d.ts +1 -0
  259. package/dist/core/fields/fieldSchemaToTs.js +133 -1
  260. package/dist/core/fields/layoutUtils.d.ts +17 -0
  261. package/dist/core/fields/layoutUtils.js +149 -0
  262. package/dist/core/fields/structuredToHtml.d.ts +9 -0
  263. package/dist/core/fields/structuredToHtml.js +161 -0
  264. package/dist/core/server/entries/operations/create.js +2 -1
  265. package/dist/core/server/entries/operations/get.js +10 -7
  266. package/dist/core/server/entries/operations/update.d.ts +3 -0
  267. package/dist/core/server/entries/operations/update.js +30 -2
  268. package/dist/core/server/fields/queryStructuredContent.d.ts +15 -0
  269. package/dist/core/server/fields/queryStructuredContent.js +65 -0
  270. package/dist/core/server/fields/resolveImageFields.js +51 -2
  271. package/dist/core/server/fields/resolveRelationFields.js +2 -2
  272. package/dist/core/server/fields/resolveRichtextLinks.js +80 -13
  273. package/dist/core/server/fields/resolveUrlFields.js +57 -6
  274. package/dist/core/server/fields/slugResolver.d.ts +10 -0
  275. package/dist/core/server/fields/slugResolver.js +34 -0
  276. package/dist/core/server/generator/fields.js +15 -4
  277. package/dist/core/server/generator/generator.js +3 -2
  278. package/dist/db-postgres/index.js +10 -6
  279. package/dist/files-local/index.js +126 -64
  280. package/dist/server/auth.d.ts +5 -0
  281. package/dist/server/auth.js +12 -1
  282. package/dist/sveltekit/components/structured-content.svelte +204 -0
  283. package/dist/sveltekit/components/structured-content.svelte.d.ts +21 -0
  284. package/dist/sveltekit/config.d.ts +13 -3
  285. package/dist/sveltekit/index.d.ts +3 -0
  286. package/dist/sveltekit/index.js +3 -0
  287. package/dist/sveltekit/server/handle.js +1 -0
  288. package/dist/types/config.d.ts +3 -0
  289. package/dist/types/entries.d.ts +3 -0
  290. package/dist/types/fields.d.ts +19 -2
  291. package/dist/types/index.d.ts +2 -0
  292. package/dist/types/index.js +2 -0
  293. package/dist/types/layout.d.ts +54 -0
  294. package/dist/types/layout.js +6 -0
  295. package/dist/types/structured-content.d.ts +63 -0
  296. package/dist/types/structured-content.js +1 -0
  297. package/dist/updates/0.1.5/index.d.ts +2 -0
  298. package/dist/updates/0.1.5/index.js +18 -0
  299. package/dist/updates/0.2.0/index.d.ts +2 -0
  300. package/dist/updates/0.2.0/index.js +11 -0
  301. package/dist/updates/0.2.2/index.d.ts +2 -0
  302. package/dist/updates/0.2.2/index.js +13 -0
  303. package/dist/updates/0.5.0/index.d.ts +2 -0
  304. package/dist/updates/0.5.0/index.js +14 -0
  305. package/dist/updates/0.5.1/index.d.ts +2 -0
  306. package/dist/updates/0.5.1/index.js +17 -0
  307. package/dist/updates/index.js +6 -1
  308. package/package.json +16 -9
  309. package/dist/admin/components/dashboard/updates-banner.svelte +0 -170
  310. package/dist/admin/components/dashboard/updates-banner.svelte.d.ts +0 -3
@@ -3,24 +3,32 @@
3
3
  import type { DbEntryVersion, EntryStatus, RawEntry } from '../../../../types/entries.js';
4
4
  import type { InterfaceLanguage } from '../../../../types/languages.js';
5
5
  import type { UpdateEntryVersionCommandType } from '../../../../core/server/entries/operations/update.js';
6
+ import type { Field } from '../../../../types/fields.js';
6
7
  import * as Sheet from '../../../../components/ui/sheet/index.js';
7
- import Badge from '../../../../components/ui/badge/badge.svelte';
8
8
  import Button from '../../../../components/ui/button/button.svelte';
9
- import { Input } from '../../../../components/ui/input/index.js';
10
9
  import SettingsIcon from '@tabler/icons-svelte/icons/settings';
11
10
  import CalendarClock from '@tabler/icons-svelte/icons/calendar-clock';
12
11
  import SquareCheckFilled from '@tabler/icons-svelte/icons/square-check-filled';
13
12
  import ClockFilled from '@tabler/icons-svelte/icons/clock-filled';
14
13
  import FileFilled from '@tabler/icons-svelte/icons/file-filled';
14
+ import AlertTriangle from '@tabler/icons-svelte/icons/alert-triangle';
15
+ import Archive from '@tabler/icons-svelte/icons/archive';
16
+ import InfoCircle from '@tabler/icons-svelte/icons/info-circle';
17
+ import Shield from '@tabler/icons-svelte/icons/shield';
18
+ import CircleCheck from '@tabler/icons-svelte/icons/circle-check';
15
19
  import { getEntryStatus } from '../utils.js';
20
+ import { validateA11y, a11yLangPl, a11yLangEn, type A11yIssue } from './a11y-validator.js';
21
+ import { getContentLanguage } from '../../../state/content-language.svelte.js';
22
+ import { computeTranslationStatus, type LangStatus } from '../../../utils/translationStatus.js';
23
+ import LanguageIcon from '@tabler/icons-svelte/icons/language';
16
24
 
17
25
  const lang: Record<
18
26
  InterfaceLanguage,
19
27
  {
20
28
  title: string;
29
+ description: string;
21
30
  status: string;
22
31
  statusLabels: Record<EntryStatus, string>;
23
- version: string;
24
32
  publishedAt: string;
25
33
  scheduledFor: string;
26
34
  schedulePublish: string;
@@ -31,14 +39,20 @@
31
39
  unpublish: string;
32
40
  cancelSchedule: string;
33
41
  archive: string;
34
- actions: string;
42
+ dangerZone: string;
35
43
  date: string;
36
44
  time: string;
37
45
  publishedVersion: string;
46
+ accessibility: string;
47
+ a11yHint: string;
48
+ translations: string;
49
+ translationsHint: string;
50
+ missingFieldsLabel: (lang: string) => string;
38
51
  }
39
52
  > = {
40
53
  en: {
41
54
  title: 'Publication',
55
+ description: 'Manage publication status, scheduling, and entry lifecycle',
42
56
  status: 'Status',
43
57
  statusLabels: {
44
58
  draft: 'Draft',
@@ -46,7 +60,6 @@
46
60
  scheduled: 'Scheduled',
47
61
  archived: 'Archived'
48
62
  },
49
- version: 'Version',
50
63
  publishedAt: 'Published at',
51
64
  scheduledFor: 'Scheduled for',
52
65
  schedulePublish: 'Schedule Publish',
@@ -56,22 +69,27 @@
56
69
  cancel: 'Cancel',
57
70
  unpublish: 'Unpublish',
58
71
  cancelSchedule: 'Cancel Schedule',
59
- archive: 'Archive',
60
- actions: 'Actions',
72
+ archive: 'Archive entry',
73
+ dangerZone: 'Danger Zone',
61
74
  date: 'Date',
62
75
  time: 'Time',
63
- publishedVersion: 'Published version'
76
+ publishedVersion: 'Published version',
77
+ accessibility: 'Accessibility',
78
+ a11yHint: 'Resolve issues before publishing',
79
+ translations: 'Translations',
80
+ translationsHint: 'Fill in missing fields to publish',
81
+ missingFieldsLabel: (lang: string) => `Missing fields (${lang.toUpperCase()})`
64
82
  },
65
83
  pl: {
66
84
  title: 'Publikacja',
85
+ description: 'Zarządzaj statusem publikacji, planowaniem i cyklem życia wpisu',
67
86
  status: 'Status',
68
87
  statusLabels: {
69
- draft: 'Szkic',
88
+ draft: 'Wersja robocza',
70
89
  published: 'Opublikowane',
71
90
  scheduled: 'Zaplanowane',
72
91
  archived: 'Zarchiwizowane'
73
92
  },
74
- version: 'Wersja',
75
93
  publishedAt: 'Opublikowano',
76
94
  scheduledFor: 'Zaplanowano na',
77
95
  schedulePublish: 'Zaplanuj publikację',
@@ -81,44 +99,51 @@
81
99
  cancel: 'Anuluj',
82
100
  unpublish: 'Cofnij publikację',
83
101
  cancelSchedule: 'Anuluj planowanie',
84
- archive: 'Zarchiwizuj',
85
- actions: 'Akcje',
102
+ archive: 'Archiwizuj wpis',
103
+ dangerZone: 'Strefa zagrożenia',
86
104
  date: 'Data',
87
105
  time: 'Czas',
88
- publishedVersion: 'Opublikowana wersja'
106
+ publishedVersion: 'Opublikowana wersja',
107
+ accessibility: 'Dostępność',
108
+ a11yHint: 'Rozwiąż problemy przed publikacją',
109
+ translations: 'Tłumaczenia',
110
+ translationsHint: 'Uzupełnij brakujące pola, żeby opublikować',
111
+ missingFieldsLabel: (lang: string) => `Brakujące pola (${lang.toUpperCase()})`
89
112
  }
90
113
  };
91
114
 
92
115
  const interfaceLanguage = useInterfaceLanguage();
116
+ const contentLanguage = getContentLanguage();
93
117
 
94
118
  type Props = {
95
119
  entry: RawEntry;
96
120
  version: DbEntryVersion;
121
+ fields?: Field[];
122
+ getFormData?: () => Record<string, unknown>;
97
123
  onSave: (type: UpdateEntryVersionCommandType, scheduledAt?: Date) => void;
98
124
  onArchive: () => void;
125
+ onScrollToIssue?: (fieldSlug: string, nodePos: number) => void;
99
126
  };
100
127
 
101
- let { entry, version, onSave, onArchive }: Props = $props();
128
+ let { entry, version, fields = [], getFormData, onSave, onArchive, onScrollToIssue }: Props = $props();
102
129
 
103
130
  let open = $state(false);
104
131
  let dateValue = $state('');
105
132
  let timeValue = $state('');
133
+ let a11yIssues = $state<A11yIssue[]>([]);
134
+ let translationStatus = $state<Record<string, LangStatus> | null>(null);
106
135
 
107
136
  const entryStatus = $derived(getEntryStatus(entry));
108
137
  const t = $derived(lang[interfaceLanguage.current]);
109
138
 
110
- const badgeClass = $derived.by(() => {
111
- switch (entryStatus) {
112
- case 'published':
113
- return 'bg-emerald-500/90 hover:bg-emerald-500 text-white border-emerald-600/20';
114
- case 'scheduled':
115
- return 'bg-amber-500/90 hover:bg-amber-500 text-white border-amber-600/20';
116
- case 'archived':
117
- return 'bg-purple-500/90 hover:bg-purple-500 text-white border-purple-600/20';
118
- default:
119
- return 'bg-slate-200/80 dark:bg-slate-700/80 text-slate-600 dark:text-slate-300';
120
- }
121
- });
139
+ const hasA11yWarnings = $derived(a11yIssues.some((i) => i.type === 'warning'));
140
+ const hasIncompleteTranslations = $derived(
141
+ translationStatus != null &&
142
+ Object.values(translationStatus).some((s) => s.status !== 'complete')
143
+ );
144
+ const showTranslationSection = $derived(
145
+ contentLanguage.all.length > 1 && translationStatus != null
146
+ );
122
147
 
123
148
  const scheduleLabel = $derived.by(() => {
124
149
  switch (entryStatus) {
@@ -194,9 +219,30 @@
194
219
  });
195
220
  }
196
221
 
222
+ function runA11yValidation() {
223
+ if (!fields.length) {
224
+ a11yIssues = [];
225
+ return;
226
+ }
227
+ const data = getFormData ? getFormData() : version.data;
228
+ const a11yLang = interfaceLanguage.current === 'pl' ? a11yLangPl : a11yLangEn;
229
+ a11yIssues = validateA11y(data, fields, a11yLang, contentLanguage.all);
230
+ }
231
+
232
+ function runTranslationCheck() {
233
+ if (contentLanguage.all.length <= 1 || !fields.length) {
234
+ translationStatus = null;
235
+ return;
236
+ }
237
+ const data = getFormData ? getFormData() : version.data;
238
+ translationStatus = computeTranslationStatus(data, fields, contentLanguage.all);
239
+ }
240
+
197
241
  $effect(() => {
198
242
  if (open) {
199
243
  setDefaultValues();
244
+ runA11yValidation();
245
+ runTranslationCheck();
200
246
  }
201
247
  });
202
248
  </script>
@@ -204,150 +250,506 @@
204
250
  <Sheet.Root bind:open>
205
251
  <Sheet.Trigger>
206
252
  {#snippet child({ props })}
207
- <Button variant="outline" size="icon" {...props}>
253
+ <Button variant="ghost" size="icon-sm" {...props}>
208
254
  <SettingsIcon class="size-4" />
209
- <span class="sr-only">{t.title}</span>
210
255
  </Button>
211
256
  {/snippet}
212
257
  </Sheet.Trigger>
213
- <Sheet.Content side="right" class="w-[400px] sm:max-w-[400px]">
258
+ <Sheet.Content side="right" class="publish-sheet w-[380px] sm:max-w-[380px]">
214
259
  <Sheet.Header>
215
260
  <Sheet.Title>{t.title}</Sheet.Title>
261
+ <Sheet.Description class="sr-only">{t.description}</Sheet.Description>
216
262
  </Sheet.Header>
217
263
 
218
- <div class="mt-6 space-y-6">
264
+ <div class="sheet-body">
219
265
  <!-- Status section -->
220
- <div class="space-y-3">
221
- <h3 class="text-xs font-medium text-muted-foreground uppercase tracking-wider">
266
+ <div class="sheet-section">
267
+ <div class="sheet-section-title">
268
+ <InfoCircle class="size-3.5" />
222
269
  {t.status}
223
- </h3>
224
-
225
- <div class="space-y-2 text-sm">
226
- <div class="flex items-center justify-between">
227
- <span class="text-muted-foreground">{t.status}</span>
228
- <Badge class="gap-1.5 {badgeClass}">
229
- {#if entryStatus === 'published'}
230
- <SquareCheckFilled class="size-3" />
231
- {:else if entryStatus === 'scheduled'}
232
- <ClockFilled class="size-3" />
233
- {:else}
234
- <FileFilled class="size-3" />
235
- {/if}
236
- {t.statusLabels[entryStatus]}
237
- </Badge>
270
+ </div>
271
+ <div class="publish-status-card">
272
+ <div class="publish-status-icon">
273
+ {#if entryStatus === 'published'}
274
+ <SquareCheckFilled class="size-[18px]" />
275
+ {:else if entryStatus === 'scheduled'}
276
+ <ClockFilled class="size-[18px]" />
277
+ {:else}
278
+ <FileFilled class="size-[18px]" />
279
+ {/if}
238
280
  </div>
281
+ <div class="publish-status-info">
282
+ <div class="publish-status-label">{t.statusLabels[entryStatus]}</div>
283
+ <div class="publish-status-meta">{formatDateTime(version.createdAt)}</div>
284
+ </div>
285
+ </div>
239
286
 
240
- <div class="flex items-center justify-between">
241
- <span class="text-muted-foreground">{t.version}</span>
242
- <span class="font-medium">v{version.versionNumber}</span>
287
+ {#if entryStatus === 'published' && entry.publishedAt}
288
+ <div class="publish-detail-row">
289
+ <span>{t.publishedAt}</span>
290
+ <span class="tabular-nums">{formatDateTime(entry.publishedAt)}</span>
243
291
  </div>
292
+ {/if}
244
293
 
245
- {#if entryStatus === 'published' && entry.publishedAt}
246
- <div class="flex items-center justify-between">
247
- <span class="text-muted-foreground">{t.publishedAt}</span>
248
- <span class="font-medium text-xs">{formatDateTime(entry.publishedAt)}</span>
249
- </div>
250
- {/if}
294
+ {#if entryStatus === 'scheduled' && entry.publishedAt}
295
+ <div class="publish-detail-row">
296
+ <span>{t.scheduledFor}</span>
297
+ <span class="tabular-nums">{formatDateTime(entry.publishedAt)}</span>
298
+ </div>
299
+ {/if}
251
300
 
252
- {#if entryStatus === 'scheduled' && entry.publishedAt}
253
- <div class="flex items-center justify-between">
254
- <span class="text-muted-foreground">{t.scheduledFor}</span>
255
- <span class="font-medium text-xs">{formatDateTime(entry.publishedAt)}</span>
256
- </div>
257
- {/if}
301
+ {#if entry.publishedVersion && entry.publishedVersion.id !== version.id}
302
+ <div class="publish-detail-row">
303
+ <span>{t.publishedVersion}</span>
304
+ <span class="tabular-nums">{formatDateTime(entry.publishedVersion.createdAt)}</span>
305
+ </div>
306
+ {/if}
307
+ </div>
258
308
 
259
- {#if entry.publishedVersion && entry.publishedVersion.id !== version.id}
260
- <div class="flex items-center justify-between">
261
- <span class="text-muted-foreground">{t.publishedVersion}</span>
262
- <span class="font-medium">v{entry.publishedVersion.versionNumber}</span>
309
+ <!-- Translation section -->
310
+ {#if showTranslationSection && translationStatus}
311
+ <div class="sheet-section">
312
+ <div class="sheet-section-title">
313
+ <LanguageIcon class="size-3.5" />
314
+ {t.translations}
315
+ </div>
316
+
317
+ {#each contentLanguage.all as lang}
318
+ {@const status = translationStatus[lang]}
319
+ {#if status}
320
+ <div class="translation-lang-row">
321
+ <div class="translation-lang-header">
322
+ <span class="translation-lang-label">{lang.toUpperCase()}</span>
323
+ <span class="translation-lang-pct {status.status === 'complete' ? 'complete' : status.status === 'partial' ? 'partial' : 'empty'}">
324
+ {#if status.status === 'complete'}&#10003;{:else}{status.percentage}%{/if}
325
+ </span>
326
+ </div>
327
+ <div class="translation-progress-track">
328
+ <div
329
+ class="translation-progress-fill {status.status === 'complete' ? 'complete' : status.status === 'partial' ? 'partial' : ''}"
330
+ style="width: {status.percentage}%"
331
+ ></div>
332
+ </div>
263
333
  </div>
264
334
  {/if}
265
- </div>
335
+ {/each}
336
+
337
+ {#if hasIncompleteTranslations}
338
+ {#each contentLanguage.all as lang}
339
+ {@const status = translationStatus[lang]}
340
+ {#if status && status.missingFields.length > 0}
341
+ <div class="translation-missing">
342
+ <div class="translation-missing-title">{t.missingFieldsLabel(lang)}</div>
343
+ {#each status.missingFields as field}
344
+ {#if onScrollToIssue}
345
+ <button
346
+ type="button"
347
+ class="a11y-item warning a11y-item-clickable"
348
+ onclick={() => {
349
+ contentLanguage.current = lang;
350
+ open = false;
351
+ setTimeout(() => onScrollToIssue!(field.slug, 0), 200);
352
+ }}
353
+ >
354
+ <div class="a11y-item-icon">
355
+ <AlertTriangle class="size-4" />
356
+ </div>
357
+ <span class="a11y-item-text">{field.label}</span>
358
+ </button>
359
+ {:else}
360
+ <div class="a11y-item warning">
361
+ <div class="a11y-item-icon">
362
+ <AlertTriangle class="size-4" />
363
+ </div>
364
+ <span class="a11y-item-text">{field.label}</span>
365
+ </div>
366
+ {/if}
367
+ {/each}
368
+ </div>
369
+ {/if}
370
+ {/each}
371
+ <p class="a11y-hint">{t.translationsHint}</p>
372
+ {/if}
266
373
  </div>
374
+ {/if}
267
375
 
268
- <!-- Schedule section -->
269
- <div class="space-y-3">
270
- <h3 class="text-xs font-medium text-muted-foreground uppercase tracking-wider flex items-center gap-1.5">
376
+ <!-- Schedule section -->
377
+ <div class="sheet-section">
378
+ <div class="sheet-section-title">
271
379
  <CalendarClock class="size-3.5" />
272
380
  {scheduleLabel}
273
- </h3>
274
-
275
- <div class="space-y-2">
276
- <div class="grid grid-cols-2 gap-2">
277
- <div>
278
- <label for="schedule-date" class="text-xs text-muted-foreground mb-1 block">{t.date}</label>
279
- <Input
280
- id="schedule-date"
281
- type="date"
282
- bind:value={dateValue}
283
- min={getMinDate()}
284
- class="w-full"
285
- />
286
- </div>
287
- <div>
288
- <label for="schedule-time" class="text-xs text-muted-foreground mb-1 block">{t.time}</label>
289
- <Input
290
- id="schedule-time"
291
- type="time"
292
- bind:value={timeValue}
293
- min={getMinTime()}
294
- class="w-full"
295
- />
296
- </div>
297
- </div>
298
- <Button
299
- size="sm"
300
- variant="gradient"
301
- class="w-full"
302
- onclick={handleSchedule}
303
- disabled={!dateValue || !timeValue}
304
- >
305
- {scheduleLabel}
306
- </Button>
307
381
  </div>
382
+ <div class="schedule-row">
383
+ <input
384
+ class="schedule-input"
385
+ type="date"
386
+ bind:value={dateValue}
387
+ min={getMinDate()}
388
+ aria-label={t.date}
389
+ />
390
+ <input
391
+ class="schedule-input"
392
+ type="time"
393
+ bind:value={timeValue}
394
+ min={getMinTime()}
395
+ aria-label={t.time}
396
+ />
397
+ </div>
398
+ <button
399
+ class="btn-schedule"
400
+ onclick={handleSchedule}
401
+ disabled={!dateValue || !timeValue}
402
+ >
403
+ {scheduleLabel}
404
+ </button>
308
405
  </div>
309
406
 
310
- <!-- Destructive actions -->
407
+ <!-- Accessibility section -->
408
+ {#if a11yIssues.length > 0}
409
+ <div class="sheet-section">
410
+ <div class="sheet-section-title">
411
+ <Shield class="size-3.5" />
412
+ {t.accessibility}
413
+ </div>
414
+ <div class="a11y-checklist">
415
+ {#each a11yIssues as issue}
416
+ {#if issue.type === 'warning' && issue.fieldSlug && issue.firstNodePos != null && onScrollToIssue}
417
+ <button
418
+ type="button"
419
+ class="a11y-item warning a11y-item-clickable"
420
+ onclick={() => {
421
+ open = false;
422
+ setTimeout(() => onScrollToIssue!(issue.fieldSlug!, issue.firstNodePos!), 200);
423
+ }}
424
+ >
425
+ <div class="a11y-item-icon">
426
+ <AlertTriangle class="size-4" />
427
+ </div>
428
+ <span class="a11y-item-text">{issue.message}</span>
429
+ </button>
430
+ {:else}
431
+ <div class="a11y-item {issue.type}">
432
+ <div class="a11y-item-icon">
433
+ {#if issue.type === 'warning'}
434
+ <AlertTriangle class="size-4" />
435
+ {:else}
436
+ <CircleCheck class="size-4" />
437
+ {/if}
438
+ </div>
439
+ <span class="a11y-item-text">{issue.message}</span>
440
+ </div>
441
+ {/if}
442
+ {/each}
443
+ </div>
444
+ {#if hasA11yWarnings}
445
+ <p class="a11y-hint">{t.a11yHint}</p>
446
+ {/if}
447
+ </div>
448
+ {/if}
449
+
450
+ <!-- Danger zone -->
311
451
  {#if entryStatus !== 'archived'}
312
- <div class="space-y-3">
313
- <h3 class="text-xs font-medium text-muted-foreground uppercase tracking-wider">
314
- {t.actions}
315
- </h3>
452
+ <div class="sheet-section">
453
+ <div class="danger-zone">
454
+ <div class="sheet-section-title danger">
455
+ <AlertTriangle class="size-3.5" />
456
+ {t.dangerZone}
457
+ </div>
316
458
 
317
- <div class="space-y-2">
318
459
  {#if entryStatus === 'published'}
319
- <Button
320
- variant="destructive"
321
- size="sm"
322
- class="w-full"
323
- onclick={handleUnpublish}
324
- >
460
+ <button class="btn-danger-outline" onclick={handleUnpublish}>
325
461
  {t.unpublish}
326
- </Button>
462
+ </button>
327
463
  {/if}
328
464
 
329
465
  {#if entryStatus === 'scheduled'}
330
- <Button
331
- variant="destructive"
332
- size="sm"
333
- class="w-full"
334
- onclick={handleCancelSchedule}
335
- >
466
+ <button class="btn-danger-outline" onclick={handleCancelSchedule}>
336
467
  {t.cancelSchedule}
337
- </Button>
468
+ </button>
338
469
  {/if}
339
470
 
340
- <Button
341
- variant="outline"
342
- size="sm"
343
- class="w-full text-destructive hover:text-destructive"
471
+ <button
472
+ class="btn-danger-outline archive"
344
473
  onclick={handleArchive}
345
474
  >
346
475
  {t.archive}
347
- </Button>
476
+ </button>
348
477
  </div>
349
478
  </div>
350
479
  {/if}
351
480
  </div>
352
481
  </Sheet.Content>
353
482
  </Sheet.Root>
483
+
484
+ <style>
485
+ .sheet-body {
486
+ padding: 18px 20px;
487
+ overflow-y: auto;
488
+ flex: 1;
489
+ min-height: 0;
490
+ }
491
+
492
+ .sheet-section {
493
+ margin-bottom: 22px;
494
+ }
495
+ .sheet-section:last-child {
496
+ margin-bottom: 0;
497
+ }
498
+
499
+ .sheet-section-title {
500
+ font-size: 12px;
501
+ font-weight: 700;
502
+ text-transform: uppercase;
503
+ letter-spacing: 0.05em;
504
+ color: var(--text-light);
505
+ margin-bottom: 10px;
506
+ display: flex;
507
+ align-items: center;
508
+ gap: 6px;
509
+ }
510
+ .sheet-section-title.danger {
511
+ color: var(--destructive);
512
+ }
513
+
514
+ /* Status card */
515
+ .publish-status-card {
516
+ padding: 12px 14px;
517
+ border-radius: 8px;
518
+ background: var(--muted);
519
+ display: flex;
520
+ align-items: center;
521
+ gap: 10px;
522
+ margin-bottom: 14px;
523
+ }
524
+ .publish-status-icon {
525
+ width: 34px;
526
+ height: 34px;
527
+ border-radius: 8px;
528
+ display: flex;
529
+ align-items: center;
530
+ justify-content: center;
531
+ background: var(--lavender-lighter);
532
+ color: var(--primary);
533
+ }
534
+ .publish-status-info {
535
+ flex: 1;
536
+ }
537
+ .publish-status-label {
538
+ font-size: 14px;
539
+ font-weight: 700;
540
+ color: var(--foreground);
541
+ }
542
+ .publish-status-meta {
543
+ font-size: 12px;
544
+ color: var(--text-light);
545
+ }
546
+ .publish-detail-row {
547
+ display: flex;
548
+ align-items: center;
549
+ justify-content: space-between;
550
+ padding: 6px 0;
551
+ font-size: 12px;
552
+ color: var(--muted-foreground);
553
+ }
554
+ .publish-detail-row span:last-child {
555
+ font-weight: 500;
556
+ }
557
+
558
+ /* Schedule */
559
+ .schedule-row {
560
+ display: grid;
561
+ grid-template-columns: 1fr 1fr;
562
+ gap: 8px;
563
+ margin-bottom: 10px;
564
+ }
565
+ .schedule-input {
566
+ padding: 7px 10px;
567
+ font-family: inherit;
568
+ font-size: 13px;
569
+ border: 1px solid var(--border);
570
+ border-radius: 6px;
571
+ color: var(--foreground);
572
+ outline: none;
573
+ background: var(--card);
574
+ transition: border-color 0.2s ease;
575
+ }
576
+ .schedule-input:focus {
577
+ border-color: var(--primary);
578
+ }
579
+ .btn-schedule {
580
+ width: 100%;
581
+ padding: 8px;
582
+ font-family: inherit;
583
+ font-size: 13px;
584
+ font-weight: 600;
585
+ color: var(--primary);
586
+ background: var(--lavender-lighter);
587
+ border: 1px solid var(--lavender-light);
588
+ border-radius: 8px;
589
+ cursor: pointer;
590
+ transition: background 0.2s ease;
591
+ }
592
+ .btn-schedule:hover {
593
+ background: var(--lavender-light);
594
+ }
595
+ .btn-schedule:disabled {
596
+ opacity: 0.5;
597
+ cursor: not-allowed;
598
+ }
599
+
600
+ /* A11y checklist */
601
+ .a11y-checklist {
602
+ display: flex;
603
+ flex-direction: column;
604
+ gap: 6px;
605
+ }
606
+ .a11y-item {
607
+ display: flex;
608
+ align-items: flex-start;
609
+ gap: 8px;
610
+ padding: 8px 10px;
611
+ border-radius: 8px;
612
+ }
613
+ .a11y-item.warning {
614
+ background: var(--warning-bg);
615
+ }
616
+ .a11y-item.success {
617
+ background: var(--success-bg);
618
+ }
619
+ .a11y-item-icon {
620
+ width: 18px;
621
+ height: 18px;
622
+ display: flex;
623
+ align-items: center;
624
+ justify-content: center;
625
+ flex-shrink: 0;
626
+ margin-top: 1px;
627
+ }
628
+ :global(.a11y-item.warning .a11y-item-icon) {
629
+ color: var(--warning);
630
+ }
631
+ :global(.a11y-item.success .a11y-item-icon) {
632
+ color: var(--success);
633
+ }
634
+ .a11y-item-text {
635
+ font-size: 13px;
636
+ font-weight: 500;
637
+ }
638
+ .a11y-item.warning .a11y-item-text {
639
+ color: #7a5520;
640
+ }
641
+ .a11y-item.success .a11y-item-text {
642
+ color: #2a6844;
643
+ }
644
+ .a11y-item-clickable {
645
+ cursor: pointer;
646
+ border: none;
647
+ width: 100%;
648
+ text-align: left;
649
+ font-family: inherit;
650
+ transition: opacity 0.15s;
651
+ }
652
+ .a11y-item-clickable:hover {
653
+ opacity: 0.8;
654
+ }
655
+ .a11y-hint {
656
+ font-size: 12px;
657
+ color: var(--text-light);
658
+ font-style: italic;
659
+ margin-top: 4px;
660
+ }
661
+
662
+ /* Danger zone */
663
+ .danger-zone {
664
+ padding-top: 14px;
665
+ border-top: 1px solid var(--border);
666
+ display: flex;
667
+ flex-direction: column;
668
+ gap: 8px;
669
+ }
670
+ .btn-danger-outline {
671
+ width: 100%;
672
+ padding: 8px;
673
+ font-family: inherit;
674
+ font-size: 13px;
675
+ font-weight: 600;
676
+ color: var(--destructive);
677
+ background: transparent;
678
+ border: 1px solid var(--destructive);
679
+ border-radius: 8px;
680
+ cursor: pointer;
681
+ opacity: 0.7;
682
+ transition: all 0.2s ease;
683
+ }
684
+ .btn-danger-outline:hover {
685
+ background: var(--error-bg);
686
+ opacity: 1;
687
+ }
688
+ .btn-danger-outline.archive {
689
+ color: var(--muted-foreground);
690
+ border-color: var(--border);
691
+ }
692
+ .btn-danger-outline.archive:hover {
693
+ color: var(--foreground);
694
+ background: var(--muted);
695
+ }
696
+
697
+ /* Translation section */
698
+ .translation-lang-row {
699
+ margin-bottom: 8px;
700
+ }
701
+ .translation-lang-header {
702
+ display: flex;
703
+ align-items: center;
704
+ justify-content: space-between;
705
+ margin-bottom: 4px;
706
+ }
707
+ .translation-lang-label {
708
+ font-size: 13px;
709
+ font-weight: 600;
710
+ color: var(--foreground);
711
+ }
712
+ .translation-lang-pct {
713
+ font-size: 12px;
714
+ font-weight: 600;
715
+ }
716
+ .translation-lang-pct.complete {
717
+ color: var(--success);
718
+ }
719
+ .translation-lang-pct.partial {
720
+ color: var(--warning);
721
+ }
722
+ .translation-lang-pct.empty {
723
+ color: var(--text-light);
724
+ }
725
+ .translation-progress-track {
726
+ height: 6px;
727
+ border-radius: 3px;
728
+ background: var(--muted);
729
+ overflow: hidden;
730
+ }
731
+ .translation-progress-fill {
732
+ height: 100%;
733
+ border-radius: 3px;
734
+ background: var(--text-light);
735
+ transition: width 0.3s ease;
736
+ }
737
+ .translation-progress-fill.complete {
738
+ background: var(--success);
739
+ }
740
+ .translation-progress-fill.partial {
741
+ background: var(--warning);
742
+ }
743
+ .translation-missing {
744
+ margin-top: 10px;
745
+ display: flex;
746
+ flex-direction: column;
747
+ gap: 4px;
748
+ }
749
+ .translation-missing-title {
750
+ font-size: 12px;
751
+ font-weight: 600;
752
+ color: var(--muted-foreground);
753
+ margin-bottom: 2px;
754
+ }
755
+ </style>