chuijs 4.0.3 → 4.0.4

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 (258) hide show
  1. package/CHANGELOG.md +536 -0
  2. package/framework/appLayout/default/chui_app_layout.js +361 -303
  3. package/framework/appLayout/default/global_style.css +243 -89
  4. package/framework/appLayout/default/main_theme_style.css +188 -101
  5. package/framework/components/chui_accordion/accordion.js +17 -17
  6. package/framework/components/chui_accordion/styles.css +7 -7
  7. package/framework/components/chui_action_sheet/action_sheet.js +35 -32
  8. package/framework/components/chui_action_sheet/styles.css +10 -4
  9. package/framework/components/chui_actions_bar/actions_bar.js +338 -0
  10. package/framework/components/chui_actions_bar/styles.css +139 -0
  11. package/framework/components/chui_affix/affix.js +4 -4
  12. package/framework/components/chui_affix/styles.css +5 -0
  13. package/framework/components/chui_alert/alert.js +11 -5
  14. package/framework/components/chui_alert/styles.css +7 -0
  15. package/framework/components/chui_avatar/avatar.js +13 -13
  16. package/framework/components/chui_avatar/styles.css +1 -1
  17. package/framework/components/chui_avatar_group/avatar_group.js +4 -4
  18. package/framework/components/chui_avatar_group/styles.css +1 -1
  19. package/framework/components/chui_backtop/backtop.js +25 -2
  20. package/framework/components/chui_backtop/styles.css +21 -0
  21. package/framework/components/chui_badge/badge.js +15 -15
  22. package/framework/components/chui_badge/styles.css +6 -6
  23. package/framework/components/chui_banner/banner.js +222 -0
  24. package/framework/components/chui_banner/styles.css +170 -0
  25. package/framework/components/chui_breadcrumb/styles.css +1 -1
  26. package/framework/components/chui_button/button.js +24 -28
  27. package/framework/components/chui_button/styles.css +5 -5
  28. package/framework/components/chui_calendar/calendar.js +6 -6
  29. package/framework/components/chui_card/card.js +14 -14
  30. package/framework/components/chui_card_scroll/card_scroll.js +169 -0
  31. package/framework/components/chui_card_scroll/styles.css +86 -0
  32. package/framework/components/chui_chat/chat.js +73 -51
  33. package/framework/components/chui_chat/styles.css +18 -7
  34. package/framework/components/chui_clipboard_history/clipboard_history.js +25 -20
  35. package/framework/components/chui_clipboard_history/styles.css +10 -8
  36. package/framework/components/chui_code/code.js +8 -8
  37. package/framework/components/chui_code/styles.css +2 -2
  38. package/framework/components/chui_code_editor/code_editor.js +26 -26
  39. package/framework/components/chui_code_editor/styles.css +3 -3
  40. package/framework/components/chui_command_palette/command_palette.js +29 -29
  41. package/framework/components/chui_command_palette/styles.css +5 -5
  42. package/framework/components/chui_console/console.js +9 -9
  43. package/framework/components/chui_console/styles.css +5 -2
  44. package/framework/components/chui_content_block/content_block.js +2 -2
  45. package/framework/components/chui_context_menu/context_menu.js +162 -54
  46. package/framework/components/chui_context_menu/styles.css +82 -8
  47. package/framework/components/chui_custom_element/custom_element.js +11 -11
  48. package/framework/components/chui_data_grid/data_grid.js +268 -268
  49. package/framework/components/chui_data_grid/styles.css +14 -14
  50. package/framework/components/chui_descriptions/styles.css +1 -1
  51. package/framework/components/chui_details/details.js +12 -12
  52. package/framework/components/chui_details/styles.css +7 -7
  53. package/framework/components/chui_diff_viewer/diff_viewer.js +88 -88
  54. package/framework/components/chui_diff_viewer/styles.css +9 -9
  55. package/framework/components/chui_divider/divider.js +6 -6
  56. package/framework/components/chui_divider/styles.css +2 -2
  57. package/framework/components/chui_drawer/drawer.js +37 -14
  58. package/framework/components/chui_drawer/styles.css +18 -4
  59. package/framework/components/chui_drop_zone/drop_zone.js +6 -6
  60. package/framework/components/chui_drop_zone/styles.css +10 -6
  61. package/framework/components/chui_fieldset/fieldset.js +6 -6
  62. package/framework/components/chui_fieldset/styles.css +5 -5
  63. package/framework/components/chui_file_explorer/file_explorer.js +115 -115
  64. package/framework/components/chui_file_explorer/styles.css +6 -6
  65. package/framework/components/chui_form/form.js +11 -11
  66. package/framework/components/chui_gantt/gantt.js +41 -41
  67. package/framework/components/chui_gantt/styles.css +5 -5
  68. package/framework/components/chui_graphs/graphs.js +82 -46
  69. package/framework/components/chui_graphs/styles.css +26 -5
  70. package/framework/components/chui_hero/hero.js +63 -20
  71. package/framework/components/chui_hero/styles.css +176 -7
  72. package/framework/components/chui_html_block/html_block.js +5 -5
  73. package/framework/components/chui_html_block/styles.css +1 -1
  74. package/framework/components/chui_hx/styles.css +2 -2
  75. package/framework/components/chui_icons/icons.js +7 -7
  76. package/framework/components/chui_icons/styles.css +2 -1
  77. package/framework/components/chui_inputs/chui_check_box/styles.css +12 -3
  78. package/framework/components/chui_inputs/chui_chips/chips.js +92 -31
  79. package/framework/components/chui_inputs/chui_chips/styles.css +28 -5
  80. package/framework/components/chui_inputs/chui_color_picker/color_picker.js +20 -15
  81. package/framework/components/chui_inputs/chui_color_picker/styles.css +7 -7
  82. package/framework/components/chui_inputs/chui_combo_box/combo_box.js +58 -58
  83. package/framework/components/chui_inputs/chui_combo_box/styles.css +9 -9
  84. package/framework/components/chui_inputs/chui_date/date.js +93 -95
  85. package/framework/components/chui_inputs/chui_date/styles.css +8 -8
  86. package/framework/components/chui_inputs/chui_date_range/date_range.js +22 -22
  87. package/framework/components/chui_inputs/chui_date_range/styles.css +3 -3
  88. package/framework/components/chui_inputs/chui_datetime/datetime.js +12 -12
  89. package/framework/components/chui_inputs/chui_datetime/styles.css +3 -3
  90. package/framework/components/chui_inputs/chui_email/email.js +10 -10
  91. package/framework/components/chui_inputs/chui_email/styles.css +6 -6
  92. package/framework/components/chui_inputs/chui_file/file.js +8 -8
  93. package/framework/components/chui_inputs/chui_file/styles.css +12 -9
  94. package/framework/components/chui_inputs/chui_hotkey/hotkey.js +39 -39
  95. package/framework/components/chui_inputs/chui_hotkey/styles.css +6 -6
  96. package/framework/components/chui_inputs/chui_masked/masked.js +44 -44
  97. package/framework/components/chui_inputs/chui_masked/styles.css +5 -5
  98. package/framework/components/chui_inputs/chui_mention/mention.js +13 -13
  99. package/framework/components/chui_inputs/chui_mention/styles.css +14 -8
  100. package/framework/components/chui_inputs/chui_multi_combo_box/multi_combo_box.js +147 -137
  101. package/framework/components/chui_inputs/chui_multi_combo_box/styles.css +14 -8
  102. package/framework/components/chui_inputs/chui_number/number.js +42 -45
  103. package/framework/components/chui_inputs/chui_number/styles.css +6 -6
  104. package/framework/components/chui_inputs/chui_otp/otp.js +32 -32
  105. package/framework/components/chui_inputs/chui_otp/styles.css +5 -5
  106. package/framework/components/chui_inputs/chui_password/password.js +30 -36
  107. package/framework/components/chui_inputs/chui_password/styles.css +7 -7
  108. package/framework/components/chui_inputs/chui_radio_button/styles.css +2 -2
  109. package/framework/components/chui_inputs/chui_rating/rating.js +28 -28
  110. package/framework/components/chui_inputs/chui_rating/styles.css +3 -3
  111. package/framework/components/chui_inputs/chui_select_box/select_box.js +54 -54
  112. package/framework/components/chui_inputs/chui_select_box/styles.css +10 -10
  113. package/framework/components/chui_inputs/chui_slider/slider.js +14 -14
  114. package/framework/components/chui_inputs/chui_slider/styles.css +5 -4
  115. package/framework/components/chui_inputs/chui_text/styles.css +7 -7
  116. package/framework/components/chui_inputs/chui_text/text.js +13 -17
  117. package/framework/components/chui_inputs/chui_text_area/styles.css +8 -8
  118. package/framework/components/chui_inputs/chui_text_area/text_area.js +23 -23
  119. package/framework/components/chui_inputs/chui_time/styles.css +13 -17
  120. package/framework/components/chui_inputs/chui_time/time.js +35 -24
  121. package/framework/components/chui_inputs/chui_toggle/styles.css +10 -3
  122. package/framework/components/chui_inputs/chui_toggle/toggle.js +16 -16
  123. package/framework/components/chui_json_editor/json_editor.js +87 -87
  124. package/framework/components/chui_json_editor/styles.css +5 -5
  125. package/framework/components/chui_json_viewer/json_viewer.js +80 -80
  126. package/framework/components/chui_json_viewer/styles.css +6 -6
  127. package/framework/components/chui_kanban/kanban.js +27 -27
  128. package/framework/components/chui_kanban/styles.css +8 -4
  129. package/framework/components/chui_kbd/styles.css +1 -1
  130. package/framework/components/chui_label/label.js +17 -17
  131. package/framework/components/chui_label/styles.css +1 -1
  132. package/framework/components/chui_link/link.js +9 -9
  133. package/framework/components/chui_link/styles.css +11 -4
  134. package/framework/components/chui_list/list.js +11 -11
  135. package/framework/components/chui_list/styles.css +2 -2
  136. package/framework/components/chui_markdown_editor/markdown_editor.js +66 -66
  137. package/framework/components/chui_markdown_editor/styles.css +5 -5
  138. package/framework/components/chui_media/audio.js +240 -246
  139. package/framework/components/chui_media/audio_styles.css +41 -23
  140. package/framework/components/chui_media/image.js +49 -46
  141. package/framework/components/chui_media/image_compare.js +35 -35
  142. package/framework/components/chui_media/image_compare_styles.css +5 -5
  143. package/framework/components/chui_media/image_styles.css +1 -1
  144. package/framework/components/chui_media/video.js +148 -148
  145. package/framework/components/chui_media/video_styles.css +27 -11
  146. package/framework/components/chui_menu_bar/menu_bar.js +54 -54
  147. package/framework/components/chui_menu_bar/styles.css +10 -10
  148. package/framework/components/chui_message_bar/message_bar.js +551 -0
  149. package/framework/components/chui_message_bar/styles.css +248 -0
  150. package/framework/components/chui_modal/modal.js +37 -13
  151. package/framework/components/chui_notification/notification.js +76 -54
  152. package/framework/components/chui_notification/notification_download.js +26 -81
  153. package/framework/components/chui_notification/notification_download_card.js +115 -0
  154. package/framework/components/chui_notification/notification_download_progress.css +2 -2
  155. package/framework/components/chui_notification/notification_download_progress.js +70 -108
  156. package/framework/components/chui_notification/notification_update.js +31 -31
  157. package/framework/components/chui_notification/status_plate.css +3 -3
  158. package/framework/components/chui_notification/styles.css +6 -1
  159. package/framework/components/chui_notification/styles_download.css +1 -1
  160. package/framework/components/chui_notification/styles_update.css +2 -2
  161. package/framework/components/chui_org_chart/org_chart.js +29 -29
  162. package/framework/components/chui_org_chart/styles.css +2 -2
  163. package/framework/components/chui_pagination/pagination.js +3 -3
  164. package/framework/components/chui_pagination/styles.css +1 -1
  165. package/framework/components/chui_paragraph/styles.css +2 -2
  166. package/framework/components/chui_popover/popover.js +29 -23
  167. package/framework/components/chui_popover/styles.css +1 -1
  168. package/framework/components/chui_popups/popups.js +124 -124
  169. package/framework/components/chui_popups/styles.css +5 -5
  170. package/framework/components/chui_print_button/print_button.js +15 -10
  171. package/framework/components/chui_progress_bar/progress_bar.js +34 -12
  172. package/framework/components/chui_progress_bar/styles.css +4 -4
  173. package/framework/components/chui_progress_ring/progress_ring.js +15 -15
  174. package/framework/components/chui_progress_ring/styles.css +1 -1
  175. package/framework/components/chui_qrcode/qrcode.js +12 -12
  176. package/framework/components/chui_query_builder/query_builder.js +46 -46
  177. package/framework/components/chui_query_builder/styles.css +4 -4
  178. package/framework/components/chui_radio_group/styles.css +1 -1
  179. package/framework/components/chui_result/result.js +15 -15
  180. package/framework/components/chui_result/styles.css +3 -3
  181. package/framework/components/chui_scheduler/scheduler.js +74 -74
  182. package/framework/components/chui_scheduler/styles.css +5 -5
  183. package/framework/components/chui_screen_spinner/screen_spinner.js +167 -0
  184. package/framework/components/chui_screen_spinner/styles.css +49 -0
  185. package/framework/components/chui_segmented_control/segmented_control.js +63 -6
  186. package/framework/components/chui_segmented_control/styles.css +32 -6
  187. package/framework/components/chui_settings/settings.js +45 -46
  188. package/framework/components/chui_settings/styles.css +4 -4
  189. package/framework/components/chui_shortcut_help/shortcut_help.js +32 -34
  190. package/framework/components/chui_sidebar_nav/sidebar_nav.js +98 -29
  191. package/framework/components/chui_sidebar_nav/styles.css +9 -3
  192. package/framework/components/chui_slideshow/slideshow.js +85 -85
  193. package/framework/components/chui_slideshow/styles.css +6 -6
  194. package/framework/components/chui_spinner/spinner.js +10 -10
  195. package/framework/components/chui_split_button/split_button.js +30 -12
  196. package/framework/components/chui_split_button/styles.css +21 -5
  197. package/framework/components/chui_splitter/splitter.js +11 -11
  198. package/framework/components/chui_splitter/styles.css +2 -2
  199. package/framework/components/chui_statistic/statistic.js +47 -47
  200. package/framework/components/chui_status_bar/styles.css +2 -2
  201. package/framework/components/chui_stepper/stepper.js +202 -31
  202. package/framework/components/chui_stepper/styles.css +79 -14
  203. package/framework/components/chui_sticky_bar/sticky_bar.js +44 -13
  204. package/framework/components/chui_sticky_bar/styles.css +10 -8
  205. package/framework/components/chui_tabs/chui_tabs.js +74 -26
  206. package/framework/components/chui_tabs/styles.css +40 -12
  207. package/framework/components/chui_text_editor/styles.css +7 -7
  208. package/framework/components/chui_text_editor/text_editor.js +56 -56
  209. package/framework/components/chui_text_editor/text_editor_panel.js +173 -174
  210. package/framework/components/chui_theme_toggle/theme_toggle.js +21 -5
  211. package/framework/components/chui_timeline/styles.css +3 -1
  212. package/framework/components/chui_toast_queue/styles.css +11 -11
  213. package/framework/components/chui_toast_queue/toast_queue.js +30 -27
  214. package/framework/components/chui_toolbar/styles.css +2 -2
  215. package/framework/components/chui_tooltip/styles.css +2 -2
  216. package/framework/components/chui_tooltip/tooltip.js +3 -3
  217. package/framework/components/chui_tour/styles.css +8 -8
  218. package/framework/components/chui_tour/tour.js +72 -72
  219. package/framework/components/chui_transfer/styles.css +6 -6
  220. package/framework/components/chui_transfer/transfer.js +93 -106
  221. package/framework/components/chui_tree_table/styles.css +4 -4
  222. package/framework/components/chui_tree_table/tree_table.js +45 -45
  223. package/framework/components/chui_tree_view/styles.css +10 -8
  224. package/framework/components/chui_tree_view/tree_view.js +185 -183
  225. package/framework/components/chui_user_bar/styles.css +145 -0
  226. package/framework/components/chui_user_bar/user_bar.js +402 -0
  227. package/framework/components/chui_user_list_bar/styles.css +173 -0
  228. package/framework/components/chui_user_list_bar/user_list_bar.js +485 -0
  229. package/framework/components/chui_watermark/watermark.js +17 -17
  230. package/framework/components/chui_webview/webview.js +9 -9
  231. package/framework/components/chui_write_bar/styles.css +172 -0
  232. package/framework/components/chui_write_bar/write_bar.js +320 -0
  233. package/framework/main_window.js +1234 -0
  234. package/framework/modules/chui_a11y/chui_a11y.js +78 -79
  235. package/framework/modules/chui_animations/animations.js +77 -15
  236. package/framework/modules/chui_animations/motion.js +120 -0
  237. package/framework/modules/chui_animations/styles.css +36 -3
  238. package/framework/modules/chui_functions.js +31 -27
  239. package/framework/modules/chui_highlight/styles.css +13 -10
  240. package/framework/modules/chui_i18n/chui_i18n.js +3 -3
  241. package/framework/modules/chui_i18n/locales/feedback.js +62 -0
  242. package/framework/modules/chui_i18n/locales/navigation.js +4 -0
  243. package/framework/modules/chui_json/chui_json.js +2 -2
  244. package/framework/modules/chui_logger/chui_logger.js +23 -8
  245. package/framework/modules/chui_page/page.js +10 -10
  246. package/framework/modules/chui_palette/palette.js +61 -0
  247. package/framework/modules/chui_qr/chui_qr.js +23 -23
  248. package/framework/modules/chui_scrollbar/chui_scrollbar.js +45 -45
  249. package/framework/modules/chui_scrollbar/styles.css +3 -3
  250. package/framework/modules/chui_services/chui_services.js +8 -8
  251. package/framework/modules/chui_services/desktop.js +77 -71
  252. package/framework/modules/chui_sortable/chui_sortable.js +17 -17
  253. package/framework/modules/chui_validate/chui_validate.js +3 -3
  254. package/framework/tray_bar/chui_menu_items.js +2 -2
  255. package/index.d.ts +266 -34
  256. package/index.js +20 -1168
  257. package/package.json +6 -4
  258. package/framework/components/telegram_bot/chui_telegram_bot.js +0 -191
@@ -1,97 +1,42 @@
1
- const { Animation } = require("../../modules/chui_animations/animations");
2
- const { setStyles, getTime, optionOr } = require("../../modules/chui_functions");
3
- const { LAYOUT_ROLE, requireLayoutNode } = require("../../modules/chui_layout/chui_layout");
1
+ const { optionOr } = require("../../modules/chui_functions");
4
2
  const { Icons } = require("../chui_icons/icons");
5
- // Плашка значка — общая на всё семейство карточек уведомлений
6
- const { createStatusPlate, setStatusPlate } = require("./status_plate");
3
+ // Каркас карточки загрузки — общий с `DownloadProgressNotification` (см. модуль)
4
+ const { createDownloadCard, showDownloadCard, finishDownloadCard } = require("./notification_download_card");
7
5
 
6
+ /**
7
+ * Уведомление о загрузке файла: название, текст хода и итог (`done`/`error`).
8
+ *
9
+ * Тело — одна строка текста, поэтому в общий каркас она не входит: у карточки с прогрессом
10
+ * тело другое (дорожка и счётчик), и общим остаётся только каркас с шапкой и статусом.
11
+ */
8
12
  class DownloadNotification {
9
- #id = require("randomstring").generate();
10
- #download_notification = document.createElement(`download_notification`);
11
- #download_notification_icon = undefined;
12
- #download_notification_content = document.createElement("download_notification_content");
13
- #download_notification_header = document.createElement("download_notification_header");
14
- #download_notification_title = document.createElement("download_notification_title");
15
- #download_notification_date = document.createElement("download_notification_date");
16
- #download_notification_body = document.createElement("download_notification_body");
17
- #download_notification_text = document.createElement("download_notification_text");
13
+ #card;
14
+ #text = document.createElement("download_notification_text");
18
15
  constructor(options = { title: String(), text: String(), type: String() }) {
19
- setStyles(__dirname + "/styles_download.css", "chUiJS_downloadNotification");
20
- this.#download_notification.id = this.#id;
21
- // Ход загрузки объявляется вежливо; итог с ошибкой меняет роль в `#renderTest()`
22
- this.#download_notification.setAttribute("role", "status");
23
- // Пустая заготовка опции равносильна отсутствующей: пустое уведомление не собирается
24
- const title = optionOr(options.title, undefined);
16
+ this.#card = createDownloadCard({
17
+ tag: "download_notification",
18
+ styles: { file: "styles_download.css", id: "chUiJS_downloadNotification" },
19
+ glyph: Icons.FILE.DOWNLOAD_FOR_OFFLINE,
20
+ title: options.title,
21
+ });
22
+ // Пустая заготовка опции равносильна отсутствующей: текст хода обязателен
25
23
  const text = optionOr(options.text, undefined);
26
- if (title !== undefined) {
27
- this.#download_notification_title.innerText = title;
28
- } else {
29
- throw new Error("Должна быть установлена опция title");
30
- }
31
- this.#download_notification_body.style.width = "-webkit-fill-available";
32
- this.#download_notification_date.innerHTML = getTime();
33
- if (text !== undefined) {
34
- this.#download_notification_text.innerText = text;
35
- } else {
36
- throw new Error("Должна быть установлена опция text");
37
- }
38
- this.#download_notification_header.appendChild(this.#download_notification_title);
39
- this.#download_notification_header.appendChild(this.#download_notification_date);
40
- this.#download_notification_content.appendChild(this.#download_notification_header);
41
- this.#download_notification_body.appendChild(this.#download_notification_text);
42
- this.#download_notification_content.appendChild(this.#download_notification_body);
43
- // Значок состояния — в плашке слева, как у Notification
44
- this.#download_notification_icon = createStatusPlate(undefined, Icons.FILE.DOWNLOAD_FOR_OFFLINE);
45
- this.#download_notification.appendChild(this.#download_notification_icon);
46
- this.#download_notification.appendChild(this.#download_notification_content);
24
+ if (text === undefined) throw new Error("Должна быть установлена опция text");
25
+ this.#text.innerText = text;
26
+ this.#card.body.appendChild(this.#text);
47
27
  }
48
28
  update(title = String(), text = String()) {
49
- this.#download_notification_title.innerText = title;
50
- this.#download_notification_text.innerText = text;
29
+ this.#card.title.innerText = title;
30
+ this.#text.innerText = text;
51
31
  }
52
32
  show() {
53
- // Панель и ящик — части layout'а: у каждого окна свои
54
- const panel = requireLayoutNode(LAYOUT_ROLE.NOTIFICATION_PANEL, this.#download_notification);
55
- panel.appendChild(this.#download_notification);
56
- new Animation(this.#download_notification).slideRightIn();
57
- this.#download_notification.addEventListener("click", () =>
58
- this.#hideNotification(this.#download_notification)
59
- );
33
+ showDownloadCard(this.#card);
60
34
  }
61
35
  done() {
62
- this.#renderTest("download_notification_success", "success");
36
+ finishDownloadCard(this.#card, "success");
63
37
  }
64
38
  error() {
65
- this.#renderTest("download_notification_error", "error");
66
- }
67
- /** Итог загрузки: цвет статуса несут класс карточки и плашка значка */
68
- #renderTest(className, status) {
69
- const notification = this.#download_notification;
70
- notification.className = className;
71
- // Ошибку объявляем сразу, успех — вежливо (как у `Toast`)
72
- notification.setAttribute("role", status === "error" ? "alert" : "status");
73
- setStatusPlate(this.#download_notification_icon, status);
74
- setTimeout(() => this.#hideNotification(notification), 2000);
75
- }
76
- #hideNotification(notification) {
77
- new Animation(notification).slideRightOutAndRemove();
78
- notification.addEventListener("animationend", () => {
79
- // Точечный сброс следов анимации вместо стирания всего атрибута `style`
80
- notification.style.removeProperty("animation-name");
81
- notification.style.removeProperty("transition");
82
- notification.style.display = "flex";
83
- notification.style.width = "-webkit-fill-available";
84
- notification.style.opacity = "0";
85
- notification.style.transform = "translateX(100%)";
86
- let box = requireLayoutNode(LAYOUT_ROLE.NOTIFICATION_BOX_MAIN, notification);
87
- // В истории запись плоская и без курсора: класс снимает стекло, тень и отклик на наведение
88
- notification.classList.add("notification_in_box");
89
- box.appendChild(notification);
90
- setTimeout(() => {
91
- notification.style.opacity = "1";
92
- notification.style.transform = "translateX(0)";
93
- }, 500);
94
- });
39
+ finishDownloadCard(this.#card, "error");
95
40
  }
96
41
  }
97
42
 
@@ -0,0 +1,115 @@
1
+ const { Animation } = require("../../modules/chui_animations/animations");
2
+ const { setStyles, getTime, optionOr } = require("../../modules/chui_functions");
3
+ const { LAYOUT_ROLE, requireLayoutNode } = require("../../modules/chui_layout/chui_layout");
4
+ // Плашка значка — общая на всё семейство карточек уведомлений
5
+ const { createStatusPlate, setStatusPlate } = require("./status_plate");
6
+
7
+ /**
8
+ * Каркас карточки загрузки: шапка, плашка значка и жизненный цикл (`show`, `done`, `error`,
9
+ * уход в историю). Одно решение на две карточки — `DownloadNotification` и
10
+ * `DownloadProgressNotification`: тела у них разные (строка текста против дорожки прогресса)
11
+ * и таблицы стилей свои, а шапка с датой, статус и поведение совпадают.
12
+ *
13
+ * Прежде это были две почти дословные копии (`diff` находил только имя экспорта), из-за чего
14
+ * правка в одной не доходила до второй: `update(title, text)` и `update(title, text, value, max)`
15
+ * разошлись, а статус с уходом в историю пришлось бы править дважды.
16
+ *
17
+ * Карточка — обычный объект с узлами, а не класс с наследованием: приватные поля базового
18
+ * класса наследнику не видны, и ради узлов, которые компонент всё равно строит сам, пришлось бы
19
+ * открывать наружу геттеры. По той же причине рядом живёт модуль плашки (`status_plate.js`).
20
+ */
21
+ function createDownloadCard(options = { tag: String(), styles: Object(), glyph: undefined, title: String() }) {
22
+ setStyles(__dirname + "/" + options.styles.file, options.styles.id);
23
+ // Пустая заготовка опции равносильна отсутствующей: карточка без названия не собирается
24
+ const title = optionOr(options.title, undefined);
25
+ if (title === undefined) throw new Error("Должна быть установлена опция title");
26
+
27
+ const root = document.createElement(options.tag);
28
+ root.id = require("randomstring").generate();
29
+ // Ход загрузки объявляется вежливо; итог с ошибкой меняет роль в `finishDownloadCard()`
30
+ root.setAttribute("role", "status");
31
+
32
+ const content = document.createElement("download_notification_content");
33
+ const header = document.createElement("download_notification_header");
34
+ const titleNode = document.createElement("download_notification_title");
35
+ const body = document.createElement("download_notification_body");
36
+ titleNode.innerText = title;
37
+ body.style.width = "-webkit-fill-available";
38
+ header.appendChild(titleNode);
39
+ header.appendChild(createDateNode());
40
+ content.appendChild(header);
41
+ content.appendChild(body);
42
+ // Значок состояния — в плашке слева, как у Notification
43
+ const plate = createStatusPlate(undefined, options.glyph);
44
+ root.appendChild(plate);
45
+ root.appendChild(content);
46
+ return { root, body, title: titleNode, plate };
47
+ }
48
+
49
+ /** Дата карточки в истории: время постановки в очередь загрузок */
50
+ function createDateNode() {
51
+ const date = document.createElement("download_notification_date");
52
+ date.innerHTML = getTime();
53
+ return date;
54
+ }
55
+
56
+ /** Показать карточку в панели уведомлений; клик по карточке убирает её */
57
+ function showDownloadCard(card = Object()) {
58
+ // Панель и ящик — части layout'а: у каждого окна свои
59
+ const panel = requireLayoutNode(LAYOUT_ROLE.NOTIFICATION_PANEL, card.root);
60
+ panel.appendChild(card.root);
61
+ new Animation(card.root).slideRightIn();
62
+ card.root.addEventListener("click", () => hideDownloadCard(card.root));
63
+ }
64
+
65
+ /**
66
+ * Итог загрузки: цвет статуса несут класс карточки и плашка значка. Класс собирается из статуса
67
+ * (`download_notification_success` / `download_notification_error`) — прежде он приходил
68
+ * отдельным первым аргументом, хотя всегда был его же производной.
69
+ */
70
+ function finishDownloadCard(card = Object(), status = String()) {
71
+ const notification = card.root;
72
+ notification.className = `download_notification_${status}`;
73
+ // Ошибку объявляем сразу, успех — вежливо (как у `Toast`)
74
+ notification.setAttribute("role", status === "error" ? "alert" : "status");
75
+ setStatusPlate(card.plate, status);
76
+ setTimeout(() => hideDownloadCard(notification), 2000);
77
+ }
78
+
79
+ /** Убрать карточку: она уезжает в ящик уведомлений плоской записью истории */
80
+ function hideDownloadCard(notification = undefined) {
81
+ new Animation(notification).slideRightOutAndRemove();
82
+ // Въезд в ящик — событие одноразовое: сняв себя после своего кадра, обработчик не трогает
83
+ // карточку дальше. Иначе он ловил бы любой конец кадра — включая кадр уборки — и переселял бы
84
+ // запись в начало списка, начиная её кадр заново
85
+ const land = (event) => {
86
+ if (event.target !== notification) return;
87
+ notification.removeEventListener("animationend", land);
88
+ // Точечный сброс следов анимации вместо стирания всего атрибута `style`:
89
+ // вид ухода держит конечное состояние, а инлайновое имя кадра перебило бы следующий
90
+ notification.style.removeProperty("animation-name");
91
+ notification.removeAttribute("data-motion");
92
+ notification.style.removeProperty("transition");
93
+ const box = requireLayoutNode(LAYOUT_ROLE.NOTIFICATION_BOX_MAIN, notification);
94
+ // В истории запись плоская и без курсора: класс снимает стекло, тень и отклик на наведение
95
+ notification.classList.add("notification_in_box");
96
+ box.appendChild(notification);
97
+ // Запись встаёт на место кадром прихода — тем же, каким въехала в панель
98
+ new Animation(notification).slideRightIn();
99
+ notification.addEventListener(
100
+ "animationend",
101
+ (event) => {
102
+ if (event.target !== notification) return;
103
+ notification.style.removeProperty("animation-name");
104
+ notification.removeAttribute("data-motion");
105
+ },
106
+ { once: true }
107
+ );
108
+ };
109
+ notification.addEventListener("animationend", land);
110
+ }
111
+
112
+ exports.createDownloadCard = createDownloadCard;
113
+ exports.showDownloadCard = showDownloadCard;
114
+ exports.finishDownloadCard = finishDownloadCard;
115
+ exports.hideDownloadCard = hideDownloadCard;
@@ -8,7 +8,7 @@ notification_download_progress {
8
8
  box-sizing: border-box;
9
9
  /* Тот же материал и ритм, что у карточки Notification */
10
10
  border-radius: var(--radius_md);
11
- margin: var(--margin);
11
+ margin: var(--block_margin);
12
12
  font-size: var(--font_default_size);
13
13
  padding: 12px 14px;
14
14
  background: var(--header_background);
@@ -130,7 +130,7 @@ download_progress_count {
130
130
  }
131
131
 
132
132
  .download_progress_bar::-webkit-progress-bar {
133
- background: var(--ap_main_background);
133
+ background: var(--player_background);
134
134
  border-radius: var(--radius_pill);
135
135
  border: none;
136
136
  }
@@ -1,122 +1,84 @@
1
- const { Animation } = require("../../modules/chui_animations/animations");
2
- const { setStyles, getTime, optionOr } = require("../../modules/chui_functions");
3
- const { LAYOUT_ROLE, requireLayoutNode } = require("../../modules/chui_layout/chui_layout");
4
1
  const { I18n } = require("../../modules/chui_i18n/chui_i18n");
5
2
  const { Icons } = require("../chui_icons/icons");
6
- // Плашка значка — общая на всё семейство карточек уведомлений
7
- const { createStatusPlate, setStatusPlate } = require("./status_plate");
3
+ // Каркас карточки загрузки — общий с `DownloadNotification` (см. модуль)
4
+ const { createDownloadCard, showDownloadCard, finishDownloadCard } = require("./notification_download_card");
8
5
 
9
- class DownloadProgressNotification {
10
- #id = require("randomstring").generate();
11
- #download_notification = document.createElement(`notification_download_progress`);
12
- #download_notification_icon = undefined;
13
- #download_notification_content = document.createElement("download_notification_content");
14
- #download_notification_header = document.createElement("download_notification_header");
15
- #id_download_notification_title = require("randomstring").generate();
16
- #download_notification_title = document.createElement("download_notification_title");
17
- #download_notification_date = document.createElement("download_notification_date");
18
- #download_notification_body = document.createElement("download_notification_body");
19
- //
20
- #id_progress = require("randomstring").generate();
21
- #ProgressBar = document.createElement(`progress`);
22
- #main = document.createElement("download_progress_block");
23
- #progress_text_block = document.createElement("download_progress_text_block");
24
- #id_progress_count = require("randomstring").generate();
25
- #progress_count = document.createElement("download_progress_count");
26
- #id_progress_text = require("randomstring").generate();
27
- #progress_text = document.createElement("download_progress_text");
28
- constructor(options = { title: String(), text: String(), type: String() }) {
29
- setStyles(__dirname + "/notification_download_progress.css", "chUiJS_downloadProgressNotification");
30
- this.#download_notification.id = this.#id;
31
- // Ход загрузки объявляется вежливо; итог с ошибкой меняет роль в `#renderTest()`
32
- this.#download_notification.setAttribute("role", "status");
33
- this.#download_notification_title.id = this.#id_download_notification_title;
34
- // Пустая заготовка опции равносильна отсутствующей
35
- if (optionOr(options.title, undefined) !== undefined) {
36
- this.#download_notification_title.innerText = options.title;
37
- } else {
38
- throw new Error("Должна быть установлена опция title");
39
- }
40
- this.#download_notification_body.style.width = "-webkit-fill-available";
41
- this.#download_notification_date.innerHTML = getTime();
42
- this.#download_notification_header.appendChild(this.#download_notification_title);
43
- this.#download_notification_header.appendChild(this.#download_notification_date);
44
- this.#download_notification_content.appendChild(this.#download_notification_header);
45
- this.#download_notification_content.appendChild(this.#download_notification_body);
46
- // Значок состояния — в плашке слева, как у Notification
47
- this.#download_notification_icon = createStatusPlate(undefined, Icons.FILE.DOWNLOADING);
48
- this.#download_notification.appendChild(this.#download_notification_icon);
49
- this.#download_notification.appendChild(this.#download_notification_content);
50
-
51
- //
52
- if (options.max !== undefined) this.#ProgressBar.max = options.max;
53
- this.#ProgressBar.id = this.#id_progress;
54
- this.#ProgressBar.className = "download_progress_bar";
55
- this.#progress_count.id = this.#id_progress_count;
56
- this.#progress_count.setAttribute("for", this.#id_progress);
57
- this.#progress_text.id = this.#id_progress_text;
58
- this.#progress_text.setAttribute("for", this.#id_progress);
59
- this.#progress_text_block.appendChild(this.#progress_text);
60
- this.#progress_text_block.appendChild(this.#progress_count);
6
+ /**
7
+ * Число для дорожки прогресса. `<progress>` не принимает `NaN` (бросает `TypeError`), а в счётчике
8
+ * он печатался бы как «NaN из NaN». Поэтому нечисловое значение читается как «не передали»:
9
+ * шкала и счётчик остаются на прежнем месте.
10
+ */
11
+ function countValue(raw = undefined) {
12
+ const value = Number(raw);
13
+ return Number.isFinite(value) ? value : undefined;
14
+ }
61
15
 
62
- this.#main.appendChild(this.#progress_text_block);
63
- this.#main.appendChild(this.#ProgressBar);
64
- //
65
- this.#main.style.width = "-webkit-fill-available";
66
- this.#progress_text.innerText = "...";
67
- this.#progress_count.innerText = I18n.t("feedback.progressCount", { value: 0, max: 0 });
68
- this.#ProgressBar.value = 0;
69
- this.#download_notification_body.appendChild(this.#main);
16
+ /**
17
+ * Уведомление о загрузке с дорожкой прогресса: название, текст, счётчик «N из M» и итог.
18
+ *
19
+ * Тело — дорожка со счётчиком, поэтому оно не входит в общий каркас: у карточек общими
20
+ * остаются шапка с датой, статус и уход в историю (см. `notification_download_card.js`).
21
+ */
22
+ class DownloadProgressNotification {
23
+ #card;
24
+ #progress = document.createElement("progress");
25
+ #text = document.createElement("download_progress_text");
26
+ #count = document.createElement("download_progress_count");
27
+ constructor(options = { title: String(), text: String(), type: String(), max: Number() }) {
28
+ this.#card = createDownloadCard({
29
+ tag: "notification_download_progress",
30
+ styles: { file: "notification_download_progress.css", id: "chUiJS_downloadProgressNotification" },
31
+ glyph: Icons.FILE.DOWNLOADING,
32
+ title: options.title,
33
+ });
34
+ // Шкала объявляет себя скринридеру сама; подписи связаны с ней по `for`
35
+ this.#progress.id = require("randomstring").generate();
36
+ this.#progress.className = "download_progress_bar";
37
+ const max = countValue(options.max);
38
+ if (max !== undefined && max > 0) this.#progress.max = max;
39
+ this.#text.id = require("randomstring").generate();
40
+ this.#text.setAttribute("for", this.#progress.id);
41
+ this.#count.id = require("randomstring").generate();
42
+ this.#count.setAttribute("for", this.#progress.id);
43
+ this.#text.innerText = "...";
44
+ this.#count.innerText = I18n.t("feedback.progressCount", { value: 0, max: 0 });
45
+ this.#progress.value = 0;
46
+ const textBlock = document.createElement("download_progress_text_block");
47
+ textBlock.appendChild(this.#text);
48
+ textBlock.appendChild(this.#count);
49
+ const block = document.createElement("download_progress_block");
50
+ block.appendChild(textBlock);
51
+ block.appendChild(this.#progress);
52
+ block.style.width = "-webkit-fill-available";
53
+ this.#card.body.appendChild(block);
70
54
  }
71
- update(title = String(), text = String(), value = Number(), max = Number()) {
72
- this.#download_notification_title.innerText = title;
73
- this.#progress_text.innerText = text;
74
- this.#progress_count.innerText = I18n.t("feedback.progressCount", { value: value, max: max });
75
- this.#ProgressBar.value = value;
76
- this.#ProgressBar.max = max;
55
+ /**
56
+ * Обновление хода загрузки.
57
+ *
58
+ * Числа могут не прийти (загрузка без известного размера) или быть нечисловыми — тогда
59
+ * шкала и счётчик остаются на прежнем месте. Прежде умолчаниями стояли `Number()`: вызов
60
+ * `update(title, text)` обнулял шкалу и менял `max` (ноль браузер молча заменяет единицей),
61
+ * а нечисловое значение бросало `TypeError` прямо в обработчике хода загрузки.
62
+ */
63
+ update(title = String(), text = String(), value = undefined, max = undefined) {
64
+ this.#card.title.innerText = title;
65
+ this.#text.innerText = text;
66
+ const total = countValue(max);
67
+ const done = countValue(value);
68
+ if (total !== undefined && total > 0) this.#progress.max = total;
69
+ if (done !== undefined) this.#progress.value = Math.max(0, done);
70
+ if (done !== undefined && total !== undefined) {
71
+ this.#count.innerText = I18n.t("feedback.progressCount", { value: done, max: total });
72
+ }
77
73
  }
78
74
  show() {
79
- const panel = requireLayoutNode(LAYOUT_ROLE.NOTIFICATION_PANEL, this.#download_notification);
80
- panel.appendChild(this.#download_notification);
81
- new Animation(this.#download_notification).slideRightIn();
82
- this.#download_notification.addEventListener("click", () =>
83
- this.#hideNotification(this.#download_notification)
84
- );
75
+ showDownloadCard(this.#card);
85
76
  }
86
77
  done() {
87
- this.#renderTest("download_notification_success", "success");
78
+ finishDownloadCard(this.#card, "success");
88
79
  }
89
80
  error() {
90
- this.#renderTest("download_notification_error", "error");
91
- }
92
- /** Итог загрузки: цвет статуса несут класс карточки и плашка значка */
93
- #renderTest(className, status) {
94
- const notification = this.#download_notification;
95
- notification.className = className;
96
- // Ошибку объявляем сразу, успех — вежливо (как у `Toast`)
97
- notification.setAttribute("role", status === "error" ? "alert" : "status");
98
- setStatusPlate(this.#download_notification_icon, status);
99
- setTimeout(() => this.#hideNotification(notification), 2000);
100
- }
101
- #hideNotification(notification) {
102
- new Animation(notification).slideRightOutAndRemove();
103
- notification.addEventListener("animationend", () => {
104
- // Точечный сброс следов анимации вместо стирания всего атрибута `style`
105
- notification.style.removeProperty("animation-name");
106
- notification.style.removeProperty("transition");
107
- notification.style.display = "flex";
108
- notification.style.width = "-webkit-fill-available";
109
- notification.style.opacity = "0";
110
- notification.style.transform = "translateX(100%)";
111
- let box = requireLayoutNode(LAYOUT_ROLE.NOTIFICATION_BOX_MAIN, notification);
112
- // В истории запись плоская и без курсора: класс снимает стекло, тень и отклик на наведение
113
- notification.classList.add("notification_in_box");
114
- box.appendChild(notification);
115
- setTimeout(() => {
116
- notification.style.opacity = "1";
117
- notification.style.transform = "translateX(0)";
118
- }, 500);
119
- });
81
+ finishDownloadCard(this.#card, "error");
120
82
  }
121
83
  }
122
84
 
@@ -8,76 +8,76 @@ const { createStatusPlate } = require("./status_plate");
8
8
 
9
9
  class UpdateNotification {
10
10
  #id = require("randomstring").generate();
11
- #update_notification = document.createElement(`update_notification`);
12
- #update_notification_icon = undefined;
13
- #update_notification_content = document.createElement("update_notification_content");
14
- #update_notification_header = document.createElement("update_notification_header");
15
- #update_notification_title = document.createElement("update_notification_title");
16
- #update_notification_date = document.createElement("update_notification_date");
17
- #update_notification_body = document.createElement("update_notification_body");
18
- #update_notification_text = document.createElement("update_notification_text");
11
+ #updateNotification = document.createElement(`update_notification`);
12
+ #updateNotificationIcon = undefined;
13
+ #updateNotificationContent = document.createElement("update_notification_content");
14
+ #updateNotificationHeader = document.createElement("update_notification_header");
15
+ #updateNotificationTitle = document.createElement("update_notification_title");
16
+ #updateNotificationDate = document.createElement("update_notification_date");
17
+ #updateNotificationBody = document.createElement("update_notification_body");
18
+ #updateNotificationText = document.createElement("update_notification_text");
19
19
  constructor(options = { title: String(), text: String(), spinner: Boolean() }) {
20
20
  setStyles(__dirname + "/styles_update.css", "chUiJS_UpdateNotification");
21
- this.#update_notification.id = this.#id;
21
+ this.#updateNotification.id = this.#id;
22
22
  // Карточка обновления живёт в ящике и меняется на месте — объявляем вежливо
23
- this.#update_notification.setAttribute("role", "status");
23
+ this.#updateNotification.setAttribute("role", "status");
24
24
  // Пустая заготовка опции равносильна отсутствующей: пустое уведомление не собирается
25
25
  const title = optionOr(options.title, undefined);
26
26
  const text = optionOr(options.text, undefined);
27
27
  // Стили заголовка уведомления
28
28
  if (title !== undefined) {
29
- this.#update_notification_title.innerText = title;
29
+ this.#updateNotificationTitle.innerText = title;
30
30
  } else {
31
31
  throw new Error("Должна быть установлена опция title");
32
32
  }
33
33
  // Стили текста уведомления
34
34
  if (text !== undefined) {
35
- this.#update_notification_text.innerText = text;
35
+ this.#updateNotificationText.innerText = text;
36
36
  } else {
37
37
  throw new Error("Должна быть установлена опция text");
38
38
  }
39
- this.#update_notification_date.innerHTML = getTime();
39
+ this.#updateNotificationDate.innerHTML = getTime();
40
40
  //
41
- this.#update_notification_header.appendChild(this.#update_notification_title);
42
- this.#update_notification_header.appendChild(this.#update_notification_date);
41
+ this.#updateNotificationHeader.appendChild(this.#updateNotificationTitle);
42
+ this.#updateNotificationHeader.appendChild(this.#updateNotificationDate);
43
43
  //
44
- this.#update_notification_content.appendChild(this.#update_notification_header);
44
+ this.#updateNotificationContent.appendChild(this.#updateNotificationHeader);
45
45
  // Значок и спиннер делят одно место — плашку слева: карточка остаётся ровной,
46
46
  // а текст не отъезжает вбок под вращающимся кольцом
47
- this.#update_notification_icon = createStatusPlate(undefined, Icons.NOTIFICATION.SYSTEM_UPDATE);
47
+ this.#updateNotificationIcon = createStatusPlate(undefined, Icons.NOTIFICATION.SYSTEM_UPDATE);
48
48
  if (options.spinner) {
49
49
  // Под кольцом заливки нет: плашка держит только место значка, иначе серая подложка
50
50
  // читалась вторым фоном вокруг тонкого индикатора
51
- this.#update_notification_icon.classList.add("notification_icon_plain");
52
- this.#update_notification_icon.innerHTML = "";
53
- this.#update_notification_icon.appendChild(new Spinner(Spinner.SIZE.V_SMALL, "0").set());
51
+ this.#updateNotificationIcon.classList.add("notification_icon_plain");
52
+ this.#updateNotificationIcon.innerHTML = "";
53
+ this.#updateNotificationIcon.appendChild(new Spinner(Spinner.SIZE.V_SMALL, "0").set());
54
54
  }
55
- this.#update_notification_body.appendChild(this.#update_notification_text);
56
- this.#update_notification_content.appendChild(this.#update_notification_body);
57
- this.#update_notification.appendChild(this.#update_notification_icon);
58
- this.#update_notification.appendChild(this.#update_notification_content);
55
+ this.#updateNotificationBody.appendChild(this.#updateNotificationText);
56
+ this.#updateNotificationContent.appendChild(this.#updateNotificationBody);
57
+ this.#updateNotification.appendChild(this.#updateNotificationIcon);
58
+ this.#updateNotification.appendChild(this.#updateNotificationContent);
59
59
  }
60
60
  show(showOnSystem = Boolean()) {
61
- const panel = requireLayoutNode(LAYOUT_ROLE.NOTIFICATION_PANEL, this.#update_notification);
62
- panel.appendChild(this.#update_notification);
63
- new Animation(this.#update_notification).slideRightIn();
61
+ const panel = requireLayoutNode(LAYOUT_ROLE.NOTIFICATION_PANEL, this.#updateNotification);
62
+ panel.appendChild(this.#updateNotification);
63
+ new Animation(this.#updateNotification).slideRightIn();
64
64
  //notification.addEventListener("click", () => this.hide(notification));
65
65
  if (showOnSystem)
66
66
  require("electron").ipcRenderer.send(
67
67
  "show_system_notification",
68
- this.#update_notification_title.innerText,
69
- this.#update_notification_text.innerText
68
+ this.#updateNotificationTitle.innerText,
69
+ this.#updateNotificationText.innerText
70
70
  );
71
71
  }
72
72
  hide() {
73
- const notification = this.#update_notification;
73
+ const notification = this.#updateNotification;
74
74
  // Карточка обновления не уезжает в ящик истории: после анимации её убираем совсем.
75
75
  // Без этого невидимый узел копился в панели уведомлений на каждое объявление
76
76
  notification.addEventListener("animationend", (event) => {
77
77
  if (event.target !== notification) return;
78
78
  notification.remove();
79
79
  });
80
- new Animation(this.#update_notification).slideRightOutAndRemove();
80
+ new Animation(this.#updateNotification).slideRightOutAndRemove();
81
81
  // Карточку ещё не показывали — анимации не будет, но узел в панели остался бы висеть
82
82
  if (notification.style.animationName === "" && document.body.contains(notification)) notification.remove();
83
83
  }
@@ -22,17 +22,17 @@ notification_icon chui_icon {
22
22
  }
23
23
 
24
24
  notification_icon.notification_icon_success {
25
- background: var(--badge_success_back);
25
+ background: var(--badge_success_background);
26
26
  color: var(--badge_success_text);
27
27
  }
28
28
 
29
29
  notification_icon.notification_icon_warning {
30
- background: var(--badge_warning_back);
30
+ background: var(--badge_warning_background);
31
31
  color: var(--badge_warning_text);
32
32
  }
33
33
 
34
34
  notification_icon.notification_icon_error {
35
- background: var(--badge_error_back);
35
+ background: var(--badge_error_background);
36
36
  color: var(--badge_error_text);
37
37
  }
38
38
 
@@ -9,7 +9,7 @@ notification {
9
9
  Статус несёт не акцентная полоса слева (устаревший приём «предупредительной
10
10
  рамки»), а плашка значка и цветной волосяной край `border-color` ниже. */
11
11
  border-radius: var(--radius_md);
12
- margin: var(--margin);
12
+ margin: var(--block_margin);
13
13
  font-size: var(--font_default_size);
14
14
  padding: 12px 14px;
15
15
  background: var(--header_background);
@@ -128,7 +128,12 @@ notification_progress {
128
128
 
129
129
  /* Плоская поверхность списка: записи истории не «всплывают» над панелью и не размывают её */
130
130
  .notification_in_box {
131
+ /* Вид записи истории и показывает карточку: вне ящика `notification` скрыт (`display: none`),
132
+ поэтому запись показывает себя сама — инлайновый `display` из JS ушёл вместе с ручной
133
+ уборкой следов кадра */
134
+ display: flex;
131
135
  /* в списке истории карточка тянется по ширине ящика, а не держит ширину тоста */
136
+ width: -webkit-fill-available;
132
137
  min-width: 0;
133
138
  max-width: -webkit-fill-available;
134
139
  margin: 4px 2px;
@@ -7,7 +7,7 @@ download_notification {
7
7
  box-sizing: border-box;
8
8
  /* Тот же материал и ритм, что у карточки Notification */
9
9
  border-radius: var(--radius_md);
10
- margin: var(--margin);
10
+ margin: var(--block_margin);
11
11
  font-size: var(--font_default_size);
12
12
  padding: 12px 14px;
13
13
  background: var(--header_background);
@@ -8,7 +8,7 @@ update_notification {
8
8
  /* Тот же материал и тот же ритм, что у карточки Notification: стеклянная
9
9
  поверхность, радиус, волосяной край и отступы 12/14 */
10
10
  border-radius: var(--radius_md);
11
- margin: var(--margin);
11
+ margin: var(--block_margin);
12
12
  font-size: var(--font_default_size);
13
13
  padding: 12px 14px;
14
14
  background: var(--header_background);
@@ -27,7 +27,7 @@ update_notification_body {
27
27
  display: flex;
28
28
  flex-direction: row;
29
29
  align-items: center;
30
- gap: var(--margin);
30
+ gap: var(--block_margin);
31
31
  }
32
32
 
33
33
  update_notification_content {