From 07768a2793e1a664b88dee9fa25843c0831e52c1 Mon Sep 17 00:00:00 2001 From: limengnan <420004014@qq.com> Date: Tue, 17 Jun 2025 10:35:33 +0800 Subject: [PATCH] =?UTF-8?q?=E6=8F=90=E4=BA=A4=E5=89=8D=E7=AB=AF=E4=BB=A3?= =?UTF-8?q?=E7=A0=81=E3=80=82=E6=AD=A3=E5=A5=BDgisbi=E5=8F=AF=E8=A7=86?= =?UTF-8?q?=E5=8C=96=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/auto-imports.d.ts | 8 + frontend/components.d.ts | 63 + frontend/frontend.code-workspace | 7 + frontend/package.json | 52 +- frontend/public/dataease.svg | 9 + frontend/public/images/code.png | Bin 0 -> 316 bytes frontend/public/images/loginbg.png | Bin 0 -> 364960 bytes frontend/public/images/loginbtn.png | Bin 0 -> 688 bytes frontend/public/images/loginform.png | Bin 0 -> 9394 bytes frontend/public/images/navbg.png | Bin 0 -> 4129 bytes frontend/public/images/navmenu.png | Bin 0 -> 373 bytes frontend/public/images/navmenucheck.png | Bin 0 -> 370 bytes frontend/public/images/password.png | Bin 0 -> 268 bytes frontend/public/images/splitline1.png | Bin 0 -> 124 bytes frontend/public/images/splitline2.png | Bin 0 -> 120 bytes frontend/public/images/titleline.png | Bin 0 -> 234 bytes frontend/public/images/username.png | Bin 0 -> 332 bytes frontend/public/svg/icon_dashboard.svg | 5 + .../public/svg/icon_data-visualization.svg | 6 + frontend/public/svg/icon_database.svg | 4 + frontend/public/svg/icon_dataset.svg | 11 + frontend/public/svg/relation-dataset.svg | 13 + frontend/public/svg/relation-ds.svg | 18 + frontend/public/svg/relation-panel.svg | 6 + frontend/public/svg/relation-screen.svg | 8 + .../tinymce-dataease-private/langs/zh_CN.js | 423 ++ .../tinymce-dataease-private/langs/zh_TW.js | 419 ++ .../skins/content/dark/content.css | 84 + .../skins/content/dark/content.min.css | 7 + .../skins/content/default/content.css | 73 + .../skins/content/default/content.min.css | 7 + .../skins/content/document/content.css | 83 + .../skins/content/document/content.min.css | 7 + .../skins/content/writer/content.css | 79 + .../skins/content/writer/content.min.css | 7 + .../skins/ui/oxide-dark/content.css | 849 +++ .../skins/ui/oxide-dark/content.inline.css | 861 +++ .../ui/oxide-dark/content.inline.min.css | 7 + .../skins/ui/oxide-dark/content.min.css | 7 + .../skins/ui/oxide-dark/content.mobile.css | 34 + .../ui/oxide-dark/content.mobile.min.css | 7 + .../ui/oxide-dark/fonts/tinymce-mobile.woff | Bin 0 -> 4624 bytes .../skins/ui/oxide-dark/skin.css | 3616 +++++++++++++ .../skins/ui/oxide-dark/skin.min.css | 7 + .../skins/ui/oxide-dark/skin.mobile.css | 798 +++ .../skins/ui/oxide-dark/skin.mobile.min.css | 7 + .../skins/ui/oxide-dark/skin.shadowdom.css | 42 + .../ui/oxide-dark/skin.shadowdom.min.css | 7 + .../skins/ui/oxide/content.css | 869 +++ .../skins/ui/oxide/content.inline.css | 861 +++ .../skins/ui/oxide/content.inline.min.css | 7 + .../skins/ui/oxide/content.min.css | 7 + .../skins/ui/oxide/content.mobile.css | 34 + .../skins/ui/oxide/content.mobile.min.css | 7 + .../skins/ui/oxide/fonts/tinymce-mobile.woff | Bin 0 -> 4624 bytes .../skins/ui/oxide/skin.css | 3616 +++++++++++++ .../skins/ui/oxide/skin.min.css | 7 + .../skins/ui/oxide/skin.mobile.css | 798 +++ .../skins/ui/oxide/skin.mobile.min.css | 7 + .../skins/ui/oxide/skin.shadowdom.css | 42 + .../skins/ui/oxide/skin.shadowdom.min.css | 7 + frontend/public/vite.svg | 1 + .../src/{data-visualization => }/api/chart.ts | 0 frontend/src/api/data-visualization/chart.ts | 124 + .../src/api/data-visualization/dataset.ts | 368 ++ frontend/src/api/data-visualization/map.ts | 53 + .../api/data-visualization/staticResource.ts | 33 + frontend/src/api/data-visualization/user.ts | 3 + .../visualization/dataVisualization.ts | 135 + .../visualization/linkJump.ts | 57 + .../visualization/linkage.ts | 17 + frontend/src/assets/img/error.png | Bin 0 -> 3459 bytes frontend/src/assets/img/none.png | Bin 0 -> 1683 bytes frontend/src/assets/img/nothing-input.png | Bin 0 -> 3061 bytes .../src/assets/img/nothing-none-black.png | Bin 0 -> 2179 bytes frontend/src/assets/img/nothing-select.png | Bin 0 -> 3354 bytes frontend/src/assets/img/nothing-table.png | Bin 0 -> 2585 bytes frontend/src/assets/img/nothing-tree.png | Bin 0 -> 2330 bytes frontend/src/assets/svg/401.svg | 29 + frontend/src/assets/svg/403.svg | 20 + frontend/src/assets/svg/API-ds.svg | 13 + frontend/src/assets/svg/Apache Hive.svg | 38 + frontend/src/assets/svg/Checkbox.svg | 4 + frontend/src/assets/svg/DM.svg | 7 + frontend/src/assets/svg/DataEase.svg | 17 + frontend/src/assets/svg/DataEase1.svg | 17 + frontend/src/assets/svg/Elasticsearch.svg | 8 + frontend/src/assets/svg/Excel-ds.svg | 3 + frontend/src/assets/svg/Frame.svg | 6 + frontend/src/assets/svg/KingBase.svg | 9 + frontend/src/assets/svg/Kylin.svg | 20 + frontend/src/assets/svg/Maxcompute.svg | 11 + frontend/src/assets/svg/PDF.svg | 1 + frontend/src/assets/svg/Presto.svg | 23 + frontend/src/assets/svg/StarRocks-ds.svg | 14 + frontend/src/assets/svg/TiDB-ds.svg | 5 + .../src/assets/svg/active-btn_copilot.svg | 14 + frontend/src/assets/svg/add.svg | 1 + frontend/src/assets/svg/add_white.svg | 6 + frontend/src/assets/svg/adds.svg | 6 + frontend/src/assets/svg/all-msg.svg | 3 + frontend/src/assets/svg/appearance.svg | 3 + frontend/src/assets/svg/area-dark.svg | 5 + frontend/src/assets/svg/area-origin.svg | 4 + frontend/src/assets/svg/area-stack-dark.svg | 7 + frontend/src/assets/svg/area-stack-origin.svg | 4 + frontend/src/assets/svg/area-stack.svg | 7 + frontend/src/assets/svg/area.svg | 5 + frontend/src/assets/svg/association.svg | 6 + frontend/src/assets/svg/auth.svg | 3 + frontend/src/assets/svg/authentication.svg | 4 + frontend/src/assets/svg/bar-dark.svg | 7 + frontend/src/assets/svg/bar-group-dark.svg | 7 + frontend/src/assets/svg/bar-group-origin.svg | 3 + .../src/assets/svg/bar-group-stack-dark.svg | 11 + .../src/assets/svg/bar-group-stack-origin.svg | 3 + frontend/src/assets/svg/bar-group-stack.svg | 11 + frontend/src/assets/svg/bar-group.svg | 7 + .../src/assets/svg/bar-horizontal-dark.svg | 7 + .../src/assets/svg/bar-horizontal-origin.svg | 3 + frontend/src/assets/svg/bar-horizontal.svg | 7 + frontend/src/assets/svg/bar-origin.svg | 3 + frontend/src/assets/svg/bar-range-dark.svg | 7 + frontend/src/assets/svg/bar-range-origin.svg | 7 + frontend/src/assets/svg/bar-range.svg | 7 + frontend/src/assets/svg/bar-stack-dark.svg | 11 + .../assets/svg/bar-stack-horizontal-dark.svg | 11 + .../svg/bar-stack-horizontal-origin.svg | 3 + .../src/assets/svg/bar-stack-horizontal.svg | 11 + frontend/src/assets/svg/bar-stack-origin.svg | 3 + frontend/src/assets/svg/bar-stack.svg | 11 + frontend/src/assets/svg/bar.svg | 7 + .../src/assets/svg/bidirectional-bar-dark.svg | 11 + .../assets/svg/bidirectional-bar-origin.svg | 11 + frontend/src/assets/svg/bidirectional-bar.svg | 11 + frontend/src/assets/svg/board_1.svg | 10 + frontend/src/assets/svg/board_2.svg | 1 + frontend/src/assets/svg/board_3.svg | 2 + frontend/src/assets/svg/board_4.svg | 2 + frontend/src/assets/svg/board_5.svg | 2 + frontend/src/assets/svg/board_6.svg | 2 + frontend/src/assets/svg/board_7.svg | 2 + frontend/src/assets/svg/board_8.svg | 2 + frontend/src/assets/svg/board_9.svg | 2 + frontend/src/assets/svg/btn_copilot.svg | 4 + frontend/src/assets/svg/btn_oidc.svg | 17 + frontend/src/assets/svg/bubble-map-dark.svg | 1 + frontend/src/assets/svg/bubble-map-origin.svg | 1 + frontend/src/assets/svg/bubble-map.svg | 1 + frontend/src/assets/svg/button_right.svg | 2 + frontend/src/assets/svg/calculate.svg | 1 + frontend/src/assets/svg/cancel_release.svg | 1 + frontend/src/assets/svg/chart-download.svg | 3 + frontend/src/assets/svg/chart-mix-dark.svg | 9 + .../assets/svg/chart-mix-dual-line-dark.svg | 7 + .../assets/svg/chart-mix-dual-line-origin.svg | 4 + .../src/assets/svg/chart-mix-dual-line.svg | 5 + .../src/assets/svg/chart-mix-group-dark.svg | 8 + .../src/assets/svg/chart-mix-group-origin.svg | 8 + frontend/src/assets/svg/chart-mix-group.svg | 8 + frontend/src/assets/svg/chart-mix-origin.svg | 4 + .../src/assets/svg/chart-mix-stack-dark.svg | 12 + .../src/assets/svg/chart-mix-stack-origin.svg | 12 + frontend/src/assets/svg/chart-mix-stack.svg | 12 + frontend/src/assets/svg/chart-mix.svg | 8 + frontend/src/assets/svg/chart-table.svg | 3 + .../src/assets/svg/circle-packing-dark.svg | 16 + .../src/assets/svg/circle-packing-origin.svg | 15 + frontend/src/assets/svg/circle-packing.svg | 15 + frontend/src/assets/svg/ck-ds.svg | 8 + frontend/src/assets/svg/clock.svg | 4 + frontend/src/assets/svg/combinationpage.svg | 6 + frontend/src/assets/svg/copilot.svg | 92 + frontend/src/assets/svg/custom_sort.svg | 3 + frontend/src/assets/svg/dark_1.svg | 2 + frontend/src/assets/svg/dashboard.svg | 1 + frontend/src/assets/svg/data-reference.svg | 4 + frontend/src/assets/svg/database.svg | 1 + frontend/src/assets/svg/dataset-outline.svg | 3 + frontend/src/assets/svg/dataset-task.svg | 1 + frontend/src/assets/svg/dataset_params.svg | 4 + frontend/src/assets/svg/datasource.svg | 1 + .../src/assets/svg/datasoure_add_dataset.svg | 6 + frontend/src/assets/svg/datasoure_details.svg | 6 + frontend/src/assets/svg/db-de.svg | 3 + frontend/src/assets/svg/db-more-web.svg | 1 + frontend/src/assets/svg/db2-ds.svg | 3 + frontend/src/assets/svg/de-api-new.svg | 6 + frontend/src/assets/svg/de-copy.svg | 3 + frontend/src/assets/svg/de-db-new.svg | 3 + frontend/src/assets/svg/de-delete.svg | 3 + frontend/src/assets/svg/de-ds-error.svg | 13 + frontend/src/assets/svg/de-ds-move.svg | 3 + frontend/src/assets/svg/de-ds-rename.svg | 4 + frontend/src/assets/svg/de-ds-trash.svg | 3 + frontend/src/assets/svg/de-ds-warning.svg | 13 + frontend/src/assets/svg/de-excel-new.svg | 3 + frontend/src/assets/svg/de-json.svg | 1 + frontend/src/assets/svg/de-move.svg | 3 + frontend/src/assets/svg/de-search.svg | 3 + frontend/src/assets/svg/de-sql-new.svg | 6 + frontend/src/assets/svg/de-union-new.svg | 3 + frontend/src/assets/svg/de_pwd_invisible.svg | 3 + frontend/src/assets/svg/de_pwd_visible.svg | 3 + frontend/src/assets/svg/default_avatar.svg | 19 + frontend/src/assets/svg/delete.svg | 1 + frontend/src/assets/svg/display-setting.svg | 1 + frontend/src/assets/svg/doc.svg | 1 + frontend/src/assets/svg/docs.svg | 1 + frontend/src/assets/svg/doris-ds.svg | 5 + frontend/src/assets/svg/drag.svg | 1 + frontend/src/assets/svg/driver-de.svg | 5 + frontend/src/assets/svg/ds-api.svg | 11 + frontend/src/assets/svg/ds-custom.svg | 1 + frontend/src/assets/svg/ds-db.svg | 4 + frontend/src/assets/svg/ds-excel.svg | 4 + frontend/src/assets/svg/ds-sql.svg | 11 + frontend/src/assets/svg/ds-union.svg | 4 + frontend/src/assets/svg/dv-ai-window-max.svg | 1 + frontend/src/assets/svg/dv-ai-window-min.svg | 1 + frontend/src/assets/svg/dv-ai.svg | 15 + frontend/src/assets/svg/dv-bar-enlarge.svg | 1 + frontend/src/assets/svg/dv-bar-unLinkage.svg | 1 + frontend/src/assets/svg/dv-batch.svg | 3 + frontend/src/assets/svg/dv-batch_white.svg | 3 + frontend/src/assets/svg/dv-copy-dark.svg | 3 + frontend/src/assets/svg/dv-copy.svg | 3 + .../assets/svg/dv-dashboard-spine-mobile.svg | 7 + .../src/assets/svg/dv-dashboard-spine.svg | 4 + frontend/src/assets/svg/dv-dashboard.svg | 4 + .../src/assets/svg/dv-dashboard_white.svg | 4 + frontend/src/assets/svg/dv-delete.svg | 3 + frontend/src/assets/svg/dv-details.svg | 3 + frontend/src/assets/svg/dv-drag-tips.svg | 123 + frontend/src/assets/svg/dv-edit.svg | 3 + frontend/src/assets/svg/dv-empty.svg | 10 + frontend/src/assets/svg/dv-expand-down.svg | 3 + frontend/src/assets/svg/dv-expand-right.svg | 3 + frontend/src/assets/svg/dv-eye-close.svg | 3 + frontend/src/assets/svg/dv-filter-show.svg | 3 + frontend/src/assets/svg/dv-filter.svg | 3 + frontend/src/assets/svg/dv-folder.svg | 4 + frontend/src/assets/svg/dv-head-more.svg | 3 + frontend/src/assets/svg/dv-hidden.svg | 1 + frontend/src/assets/svg/dv-info.svg | 12 + frontend/src/assets/svg/dv-link-target.svg | 3 + frontend/src/assets/svg/dv-lock.svg | 3 + frontend/src/assets/svg/dv-material.svg | 4 + frontend/src/assets/svg/dv-max.svg | 10 + frontend/src/assets/svg/dv-media.svg | 3 + frontend/src/assets/svg/dv-min.svg | 3 + frontend/src/assets/svg/dv-more-com.svg | 6 + .../src/assets/svg/dv-more-time-clock.svg | 1 + frontend/src/assets/svg/dv-more.svg | 3 + frontend/src/assets/svg/dv-move.svg | 3 + frontend/src/assets/svg/dv-new-folder.svg | 5 + frontend/src/assets/svg/dv-new.svg | 3 + frontend/src/assets/svg/dv-no-img.svg | 1 + frontend/src/assets/svg/dv-nothing.svg | 14 + frontend/src/assets/svg/dv-params.svg | 3 + frontend/src/assets/svg/dv-picture-real.svg | 3 + frontend/src/assets/svg/dv-picture-show.svg | 3 + frontend/src/assets/svg/dv-picture.svg | 3 + .../src/assets/svg/dv-preview-download.svg | 4 + frontend/src/assets/svg/dv-preview-inner.svg | 3 + frontend/src/assets/svg/dv-preview-outer.svg | 3 + frontend/src/assets/svg/dv-preview.svg | 3 + frontend/src/assets/svg/dv-rename.svg | 4 + frontend/src/assets/svg/dv-reposition.svg | 4 + frontend/src/assets/svg/dv-richText.svg | 3 + frontend/src/assets/svg/dv-ruler.svg | 1 + frontend/src/assets/svg/dv-screen-new.svg | 5 + frontend/src/assets/svg/dv-screen-spine.svg | 4 + frontend/src/assets/svg/dv-scroll-text.svg | 1 + frontend/src/assets/svg/dv-share.svg | 3 + frontend/src/assets/svg/dv-show.svg | 3 + frontend/src/assets/svg/dv-sort-asc.svg | 6 + frontend/src/assets/svg/dv-sort-desc.svg | 6 + .../src/assets/svg/dv-style-activeFont.svg | 1 + .../assets/svg/dv-style-activeFontSize.svg | 1 + .../assets/svg/dv-style-backgroundColor.svg | 1 + frontend/src/assets/svg/dv-style-blur.svg | 12 + .../src/assets/svg/dv-style-borderColor.svg | 1 + .../src/assets/svg/dv-style-borderRadius.svg | 1 + .../src/assets/svg/dv-style-borderSize.svg | 1 + .../src/assets/svg/dv-style-borderStyle.svg | 1 + frontend/src/assets/svg/dv-style-color.svg | 1 + .../src/assets/svg/dv-style-fontFamily.svg | 1 + frontend/src/assets/svg/dv-style-fontSize.svg | 1 + .../src/assets/svg/dv-style-fontWeight.svg | 1 + .../svg/dv-style-headBorderActiveColor.svg | 1 + .../assets/svg/dv-style-headBorderColor.svg | 1 + .../svg/dv-style-headFontActiveColor.svg | 1 + .../src/assets/svg/dv-style-headFontColor.svg | 1 + .../svg/dv-style-headHorizontalPosition.svg | 1 + .../src/assets/svg/dv-style-letterSpacing.svg | 1 + .../src/assets/svg/dv-style-lineHeight.svg | 1 + frontend/src/assets/svg/dv-style-opacity.svg | 1 + .../src/assets/svg/dv-style-scroll-speed.svg | 1 + frontend/src/assets/svg/dv-style-tab-head.svg | 1 + .../src/assets/svg/dv-style-textAlign.svg | 1 + frontend/src/assets/svg/dv-tab-show.svg | 3 + frontend/src/assets/svg/dv-tab.svg | 3 + frontend/src/assets/svg/dv-text.svg | 3 + frontend/src/assets/svg/dv-unlock.svg | 3 + frontend/src/assets/svg/dv-up-arrow.svg | 1 + frontend/src/assets/svg/dv-use-template.svg | 3 + frontend/src/assets/svg/dv-video.svg | 3 + frontend/src/assets/svg/dv-view.svg | 4 + frontend/src/assets/svg/dv_mobile_layout.svg | 5 + frontend/src/assets/svg/edit-done.svg | 3 + frontend/src/assets/svg/edit-in.svg | 1 + frontend/src/assets/svg/edit.svg | 1 + frontend/src/assets/svg/email-task.svg | 1 + frontend/src/assets/svg/embedded.svg | 4 + frontend/src/assets/svg/es-ds.svg | 1 + frontend/src/assets/svg/example.svg | 1 + frontend/src/assets/svg/exclamationmark.svg | 1 + frontend/src/assets/svg/exclamationmark2.svg | 1 + frontend/src/assets/svg/exit-fullscreen.svg | 1 + frontend/src/assets/svg/eye-open.svg | 1 + frontend/src/assets/svg/eye.svg | 3 + frontend/src/assets/svg/field_location.svg | 1 + frontend/src/assets/svg/field_text.svg | 1 + frontend/src/assets/svg/field_time.svg | 1 + frontend/src/assets/svg/field_url.svg | 1 + frontend/src/assets/svg/field_value.svg | 1 + frontend/src/assets/svg/filter-center.svg | 4 + frontend/src/assets/svg/filter-h-center.svg | 5 + frontend/src/assets/svg/filter-h-left.svg | 4 + frontend/src/assets/svg/filter-h-right.svg | 4 + frontend/src/assets/svg/filter-params.svg | 3 + frontend/src/assets/svg/filter-top.svg | 4 + frontend/src/assets/svg/filter.svg | 1 + frontend/src/assets/svg/flow-map-dark.svg | 1 + frontend/src/assets/svg/flow-map-origin.svg | 1 + frontend/src/assets/svg/flow-map.svg | 1 + frontend/src/assets/svg/folder.svg | 1 + frontend/src/assets/svg/form.svg | 1 + frontend/src/assets/svg/fullscreen.svg | 1 + frontend/src/assets/svg/funnel-dark.svg | 6 + frontend/src/assets/svg/funnel-origin.svg | 3 + frontend/src/assets/svg/funnel.svg | 6 + frontend/src/assets/svg/gauge-dark.svg | 4 + frontend/src/assets/svg/gauge-origin.svg | 4 + frontend/src/assets/svg/gauge.svg | 4 + .../src/assets/svg/graphical-circular.svg | 1 + frontend/src/assets/svg/graphical-rect.svg | 1 + .../src/assets/svg/graphical-triangle.svg | 1 + frontend/src/assets/svg/group-3400.svg | 23 + frontend/src/assets/svg/group.svg | 1 + frontend/src/assets/svg/heat-map-dark.svg | 1 + frontend/src/assets/svg/heat-map-origin.svg | 1 + frontend/src/assets/svg/heat-map.svg | 1 + frontend/src/assets/svg/icon-alarmclock.svg | 3 + frontend/src/assets/svg/icon-contacts.svg | 3 + frontend/src/assets/svg/icon-draft.svg | 3 + frontend/src/assets/svg/icon-filter.svg | 3 + frontend/src/assets/svg/icon-group.svg | 3 + frontend/src/assets/svg/icon-image-upload.svg | 1 + frontend/src/assets/svg/icon-image.svg | 1 + frontend/src/assets/svg/icon-laser.svg | 4 + frontend/src/assets/svg/icon-lock.svg | 3 + frontend/src/assets/svg/icon-maybe.svg | 3 + .../src/assets/svg/icon-maybe_outlined.svg | 3 + frontend/src/assets/svg/icon-more.svg | 3 + frontend/src/assets/svg/icon-quicksetting.svg | 3 + frontend/src/assets/svg/icon-setting.svg | 3 + frontend/src/assets/svg/icon-stream.svg | 3 + frontend/src/assets/svg/icon-video.svg | 3 + frontend/src/assets/svg/icon/ctrl/close.svg | 3 + .../assets/svg/icon/outline/notification.svg | 3 + .../src/assets/svg/icon_Batch_outlined.svg | 3 + .../src/assets/svg/icon_Invalid_colorful.svg | 13 + .../svg/icon_add-dictionary_outlined.svg | 4 + .../assets/svg/icon_add-entry_outlined.svg | 6 + .../assets/svg/icon_add-folder_outlined.svg | 5 + .../src/assets/svg/icon_add_outlined-1.svg | 3 + frontend/src/assets/svg/icon_add_outlined.svg | 3 + .../assets/svg/icon_adjustment_outlined.svg | 7 + .../src/assets/svg/icon_admin_outlined.svg | 4 + frontend/src/assets/svg/icon_api-outlined.svg | 7 + frontend/src/assets/svg/icon_api.svg | 13 + frontend/src/assets/svg/icon_app_outlined.svg | 3 + .../assets/svg/icon_arrow-right_outlined.svg | 3 + .../src/assets/svg/icon_assigned_outlined.svg | 9 + .../assets/svg/icon_attachment_outlined.svg | 3 + .../src/assets/svg/icon_bold_outlined.svg | 3 + .../assets/svg/icon_bottom-align_outlined.svg | 4 + .../icon_calendar-calculated_outlined-1.svg | 7 + .../svg/icon_calendar-calculated_outlined.svg | 7 + .../src/assets/svg/icon_calendar_outlined.svg | 4 + frontend/src/assets/svg/icon_cancel_store.svg | 1 + .../src/assets/svg/icon_card_outlined.svg | 6 + .../svg/icon_center-alignment_outlined.svg | 5 + frontend/src/assets/svg/icon_chart-line-c.svg | 4 + frontend/src/assets/svg/icon_chart-line.svg | 4 + .../src/assets/svg/icon_clear_outlined.svg | 3 + frontend/src/assets/svg/icon_close_filled.svg | 4 + .../src/assets/svg/icon_close_outlined.svg | 3 + .../src/assets/svg/icon_collect_filled.svg | 3 + .../assets/svg/icon_collection_outlined.svg | 3 + frontend/src/assets/svg/icon_copy_filled.svg | 3 + .../src/assets/svg/icon_copy_outlined.svg | 3 + frontend/src/assets/svg/icon_customize.svg | 6 + frontend/src/assets/svg/icon_dashboard.svg | 5 + .../assets/svg/icon_dashboard_outlined-c.svg | 3 + .../assets/svg/icon_dashboard_outlined.svg | 3 + .../assets/svg/icon_data-visualization.svg | 6 + .../assets/svg/icon_database-alert_filled.svg | 6 + .../assets/svg/icon_database-fail_filled.svg | 4 + frontend/src/assets/svg/icon_database.svg | 4 + .../src/assets/svg/icon_database_outlined.svg | 3 + frontend/src/assets/svg/icon_dataset.svg | 11 + .../src/assets/svg/icon_dataset_outlined.svg | 5 + frontend/src/assets/svg/icon_db_filled.svg | 3 + .../assets/svg/icon_delete-trash_outlined.svg | 3 + .../src/assets/svg/icon_describe_outlined.svg | 3 + .../src/assets/svg/icon_dialpad_outlined.svg | 11 + .../assets/svg/icon_disorde-list_outlined.svg | 3 + .../src/assets/svg/icon_divider_outlined.svg | 3 + .../assets/svg/icon_doc-replace_outlined.svg | 7 + .../src/assets/svg/icon_done_outlined.svg | 5 + .../assets/svg/icon_down-right_outlined.svg | 4 + .../src/assets/svg/icon_down_outlined-1.svg | 3 + .../src/assets/svg/icon_down_outlined.svg | 3 + .../src/assets/svg/icon_download_outlined.svg | 3 + .../src/assets/svg/icon_drag_outlined.svg | 3 + .../src/assets/svg/icon_drilling_outlined.svg | 3 + frontend/src/assets/svg/icon_drive_filled.svg | 5 + .../src/assets/svg/icon_edit_outlined.svg | 3 + .../src/assets/svg/icon_effects_outlined.svg | 4 + frontend/src/assets/svg/icon_excel.svg | 11 + .../src/assets/svg/icon_excel_outlined.svg | 3 + .../assets/svg/icon_expand-down_filled.svg | 3 + .../assets/svg/icon_expand-left_filled.svg | 5 + .../assets/svg/icon_expand-right_filled.svg | 3 + .../src/assets/svg/icon_file-add_outlined.svg | 6 + .../src/assets/svg/icon_file-doc_colorful.svg | 5 + .../assets/svg/icon_file-excel_colorful.svg | 5 + .../assets/svg/icon_file-font_colorful.svg | 5 + .../src/assets/svg/icon_folder_filled.svg | 3 + .../assets/svg/icon_font-color_outlined.svg | 4 + frontend/src/assets/svg/icon_font.svg | 4 + .../src/assets/svg/icon_form_outlined.svg | 3 + .../assets/svg/icon_form_outlined_white.svg | 3 + frontend/src/assets/svg/icon_free.svg | 4 + .../src/assets/svg/icon_full-association.svg | 7 + .../assets/svg/icon_functions_outlined.svg | 3 + frontend/src/assets/svg/icon_graphical.svg | 1 + .../assets/svg/icon_gridlines_outlined.svg | 11 + frontend/src/assets/svg/icon_h1_outlined.svg | 3 + frontend/src/assets/svg/icon_h2_outlined.svg | 3 + frontend/src/assets/svg/icon_h3_outlined.svg | 3 + frontend/src/assets/svg/icon_hn_outlined.svg | 3 + .../svg/icon_horizontal-align_outlined.svg | 5 + .../src/assets/svg/icon_info_colorful.svg | 11 + frontend/src/assets/svg/icon_info_filled.svg | 5 + .../src/assets/svg/icon_info_outlined.svg | 12 + frontend/src/assets/svg/icon_intersect.svg | 6 + .../assets/svg/icon_into-item_outlined.svg | 3 + .../assets/svg/icon_invisible_outlined.svg | 5 + .../src/assets/svg/icon_italic_outlined.svg | 3 + .../assets/svg/icon_left-align_outlined.svg | 4 + .../svg/icon_left-alignment_outlined.svg | 5 + .../src/assets/svg/icon_left-association.svg | 6 + .../src/assets/svg/icon_left_outlined.svg | 3 + .../svg/icon_letter-spacing_outlined.svg | 5 + .../svg/icon_link-calculated_outlined-1.svg | 6 + .../svg/icon_link-calculated_outlined.svg | 6 + frontend/src/assets/svg/icon_link-record.svg | 11 + .../svg/icon_link-record_outlined-1.svg | 3 + .../assets/svg/icon_link-record_outlined.svg | 3 + .../src/assets/svg/icon_loading_outlined.svg | 3 + .../svg/icon_local-calculated_outlined-1.svg | 5 + .../svg/icon_local-calculated_outlined.svg | 5 + frontend/src/assets/svg/icon_local.svg | 3 + .../src/assets/svg/icon_local_outlined.svg | 3 + .../src/assets/svg/icon_logs_outlined-1.svg | 3 + .../src/assets/svg/icon_logs_outlined.svg | 3 + .../src/assets/svg/icon_magnify_outlined.svg | 3 + .../assets/svg/icon_member-add_outlined.svg | 5 + .../src/assets/svg/icon_member_filled.svg | 8 + frontend/src/assets/svg/icon_mfa_reset.svg | 6 + .../src/assets/svg/icon_minify_outlined.svg | 3 + .../svg/icon_moments-categories_outlined.svg | 4 + .../svg/icon_more-vertical_outlined.svg | 5 + .../svg/icon_more-vertical_outlined_white.svg | 5 + .../src/assets/svg/icon_more_outlined.svg | 3 + frontend/src/assets/svg/icon_msg_fill.svg | 1 + .../assets/svg/icon_multi-line_outlined.svg | 11 + .../src/assets/svg/icon_new-item_outlined.svg | 5 + .../assets/svg/icon_notification_filled.svg | 3 + .../assets/svg/icon_notification_outlined.svg | 3 + .../svg/icon_number-calculated_outlined-1.svg | 4 + .../svg/icon_number-calculated_outlined.svg | 4 + .../src/assets/svg/icon_number_outlined.svg | 3 + .../svg/icon_operation-analysis_outlined.svg | 5 + .../assets/svg/icon_orde-list_outlined.svg | 3 + .../assets/svg/icon_organization_outlined.svg | 3 + .../src/assets/svg/icon_params_setting.svg | 1 + .../src/assets/svg/icon_pc_fullscreen.svg | 1 + frontend/src/assets/svg/icon_pc_outlined.svg | 3 + .../src/assets/svg/icon_pc_outlined_copy.svg | 3 + .../src/assets/svg/icon_phone_outlined.svg | 5 + .../src/assets/svg/icon_pie_outlined-c.svg | 4 + .../src/assets/svg/icon_play-round_filled.svg | 3 + .../assets/svg/icon_play-round_outlined.svg | 3 + .../svg/icon_play_round_outlined_white.svg | 3 + .../src/assets/svg/icon_plugin_outlined.svg | 3 + .../assets/svg/icon_preferences_outlined.svg | 3 + .../assets/svg/icon_pull-left_outlined.svg | 3 + .../assets/svg/icon_pull-right_outlined.svg | 3 + frontend/src/assets/svg/icon_qr_outlined.svg | 5 + .../src/assets/svg/icon_radio_outlined.svg | 11 + .../src/assets/svg/icon_redo_outlined.svg | 3 + .../src/assets/svg/icon_refresh_outlined.svg | 3 + .../src/assets/svg/icon_rename_outlined.svg | 4 + .../src/assets/svg/icon_replace_outlined.svg | 8 + .../src/assets/svg/icon_reset_outlined.svg | 3 + .../src/assets/svg/icon_resetpassword.svg | 3 + .../assets/svg/icon_right-align_outlined.svg | 4 + .../svg/icon_right-alignment_outlined.svg | 5 + .../src/assets/svg/icon_right-association.svg | 6 + .../src/assets/svg/icon_right_outlined.svg | 3 + .../src/assets/svg/icon_scroll_filled.svg | 4 + .../svg/icon_search-outline_outlined.svg | 3 + frontend/src/assets/svg/icon_search.svg | 1 + frontend/src/assets/svg/icon_security.svg | 1 + .../assets/svg/icon_share-label_filled.svg | 3 + .../assets/svg/icon_share-label_outlined.svg | 3 + .../assets/svg/icon_side-expand_outlined.svg | 4 + .../assets/svg/icon_side-fold_outlined.svg | 4 + .../assets/svg/icon_single-line_outlined.svg | 11 + .../assets/svg/icon_sort-a-to-z_outlined.svg | 6 + .../assets/svg/icon_sort-z-to-a_outlined.svg | 6 + .../src/assets/svg/icon_sort_outlined.svg | 10 + .../src/assets/svg/icon_sort_priority.svg | 1 + frontend/src/assets/svg/icon_sql.svg | 18 + frontend/src/assets/svg/icon_sql_outlined.svg | 6 + .../src/assets/svg/icon_sql_outlined_1.svg | 13 + .../src/assets/svg/icon_stretch_outlined.svg | 3 + .../assets/svg/icon_style-set_outlined.svg | 3 + .../src/assets/svg/icon_succeed_colorful.svg | 4 + .../src/assets/svg/icon_succeed_filled.svg | 10 + .../src/assets/svg/icon_switch_outlined.svg | 5 + .../svg/icon_sync-play-round_filled.svg | 4 + .../svg/icon_sync-play-round_outlined.svg | 4 + .../svg/icon_sync_close_log_details.svg | 3 + .../src/assets/svg/icon_sync_datasource.svg | 16 + frontend/src/assets/svg/icon_sync_free.svg | 3 + .../src/assets/svg/icon_sync_log_number.svg | 17 + .../assets/svg/icon_sync_logs_outlined.svg | 3 + .../src/assets/svg/icon_sync_progress.svg | 10 + .../svg/icon_sync_target_to_datasource.svg | 3 + .../src/assets/svg/icon_sync_task_number.svg | 17 + .../assets/svg/icon_take-action_outlined.svg | 4 + .../src/assets/svg/icon_team-add_outlined.svg | 11 + frontend/src/assets/svg/icon_template.svg | 3 + .../src/assets/svg/icon_template_colorful.svg | 7 + .../src/assets/svg/icon_template_outlined.svg | 3 + .../src/assets/svg/icon_text-box_outlined.svg | 4 + .../svg/icon_text-calculated_outlined-1.svg | 4 + .../svg/icon_text-calculated_outlined.svg | 4 + .../src/assets/svg/icon_text_outlined.svg | 3 + .../src/assets/svg/icon_time_outlined.svg | 4 + .../svg/icon_title-left-align_outlined.svg | 4 + .../svg/icon_title-top-align_outlined.svg | 4 + .../src/assets/svg/icon_todo_outlined.svg | 3 + .../assets/svg/icon_top-align_outlined.svg | 4 + .../src/assets/svg/icon_undo_outlined.svg | 3 + .../src/assets/svg/icon_up-left_outlined.svg | 4 + .../src/assets/svg/icon_upload_outlined.svg | 3 + frontend/src/assets/svg/icon_url_outlined.svg | 1 + .../svg/icon_vertical-align_outlined.svg | 5 + .../assets/svg/icon_view-list_outlined.svg | 3 + .../assets/svg/icon_viewinchat_outlined.svg | 3 + .../src/assets/svg/icon_visible_outlined.svg | 3 + .../src/assets/svg/icon_warning_colorful.svg | 12 + .../assets/svg/icon_warning_colorful_red.svg | 12 + .../src/assets/svg/icon_warning_filled.svg | 5 + frontend/src/assets/svg/icon_webhook.svg | 3 + frontend/src/assets/svg/icon_yes_outlined.svg | 3 + frontend/src/assets/svg/iconfont.svg | 71 + frontend/src/assets/svg/impala-ds.svg | 19 + frontend/src/assets/svg/indicator-dark.svg | 6 + frontend/src/assets/svg/indicator-origin.svg | 6 + frontend/src/assets/svg/indicator.svg | 6 + frontend/src/assets/svg/inner-join.svg | 5 + frontend/src/assets/svg/international.svg | 1 + frontend/src/assets/svg/join-join.svg | 3 + frontend/src/assets/svg/label.svg | 2 + frontend/src/assets/svg/language.svg | 1 + frontend/src/assets/svg/left-join.svg | 7 + frontend/src/assets/svg/line-dark.svg | 7 + frontend/src/assets/svg/line-origin.svg | 4 + frontend/src/assets/svg/line.svg | 5 + frontend/src/assets/svg/link-back.svg | 1 + frontend/src/assets/svg/link-down.svg | 1 + frontend/src/assets/svg/link.svg | 1 + frontend/src/assets/svg/liquid-dark.svg | 5 + frontend/src/assets/svg/liquid-origin.svg | 4 + frontend/src/assets/svg/liquid.svg | 5 + frontend/src/assets/svg/lock_closed.svg | 3 + .../src/assets/svg/lock_closed_switch.svg | 1 + frontend/src/assets/svg/lock_open.svg | 4 + frontend/src/assets/svg/lock_open_back.svg | 1 + frontend/src/assets/svg/lock_other_open.svg | 4 + frontend/src/assets/svg/log.svg | 3 + frontend/src/assets/svg/logo.svg | 20 + frontend/src/assets/svg/logo1.svg | 21 + frontend/src/assets/svg/logo_cas.svg | 16 + frontend/src/assets/svg/logo_dingtalk.svg | 5 + frontend/src/assets/svg/logo_lark.svg | 20 + frontend/src/assets/svg/logo_ldap.svg | 14 + frontend/src/assets/svg/logo_oauth.svg | 3 + frontend/src/assets/svg/logo_wechat-work.svg | 64 + frontend/src/assets/svg/map-dark.svg | 1 + frontend/src/assets/svg/map-origin.svg | 1 + frontend/src/assets/svg/map.svg | 1 + frontend/src/assets/svg/map_mini.svg | 1 + frontend/src/assets/svg/map_old.svg | 1 + frontend/src/assets/svg/mariadb-ds.svg | 14 + frontend/src/assets/svg/market-expand.svg | 31 + frontend/src/assets/svg/market-retract.svg | 19 + frontend/src/assets/svg/menu.svg | 1 + .../assets/svg/menuconfig_treeadd_white.svg | 6 + frontend/src/assets/svg/mobile-checkbox.svg | 4 + .../svg/mobile/icon_dashboard_filled.svg | 3 + .../svg/mobile/icon_dashboard_outlined.svg | 3 + .../assets/svg/mobile/icon_home_filled.svg | 3 + .../assets/svg/mobile/icon_home_outlined.svg | 3 + .../assets/svg/mobile/icon_member_filled.svg | 4 + .../svg/mobile/icon_member_outlined.svg | 3 + frontend/src/assets/svg/mongo-ds.svg | 5 + frontend/src/assets/svg/more_v.svg | 1 + frontend/src/assets/svg/move.svg | 1 + frontend/src/assets/svg/msg-fill.svg | 1 + frontend/src/assets/svg/msg-notice.svg | 1 + frontend/src/assets/svg/msg-setting.svg | 1 + frontend/src/assets/svg/mysql-ds.svg | 3 + frontend/src/assets/svg/mysql-frame.svg | 10 + frontend/src/assets/svg/nested.svg | 1 + frontend/src/assets/svg/no-join.svg | 1 + frontend/src/assets/svg/no_result.svg | 14 + frontend/src/assets/svg/non-existent.svg | 2 + frontend/src/assets/svg/none_select.svg | 5 + frontend/src/assets/svg/notification.svg | 1 + frontend/src/assets/svg/oracle-ds.svg | 10 + frontend/src/assets/svg/org.svg | 3 + frontend/src/assets/svg/other_material.svg | 1 + .../src/assets/svg/other_material_board.svg | 4 + .../src/assets/svg/other_material_icon.svg | 3 + frontend/src/assets/svg/other_media.svg | 1 + frontend/src/assets/svg/other_setting.svg | 1 + frontend/src/assets/svg/other_text.svg | 1 + .../src/assets/svg/outer-params-filter.svg | 3 + frontend/src/assets/svg/page-line.svg | 3 + .../src/assets/svg/panel-mobile-publish.svg | 18 + .../svg/panel-mobile-unpublished-back.svg | 19 + .../assets/svg/panel-mobile-unpublished.svg | 18 + frontend/src/assets/svg/panel-publish.svg | 1 + .../src/assets/svg/panel-unpublished-back.svg | 10 + frontend/src/assets/svg/panel-unpublished.svg | 9 + frontend/src/assets/svg/panel.svg | 1 + frontend/src/assets/svg/people.svg | 3 + frontend/src/assets/svg/peoples.svg | 3 + .../assets/svg/percentage-bar-stack-dark.svg | 11 + .../percentage-bar-stack-horizontal-dark.svg | 11 + ...percentage-bar-stack-horizontal-origin.svg | 3 + .../svg/percentage-bar-stack-horizontal.svg | 11 + .../svg/percentage-bar-stack-origin.svg | 3 + .../src/assets/svg/percentage-bar-stack.svg | 11 + .../src/assets/svg/perission_role_blue.svg | 17 + .../src/assets/svg/permission_del_blue.svg | 6 + .../src/assets/svg/permission_del_white.svg | 6 + .../src/assets/svg/permission_edit_blue.svg | 6 + .../src/assets/svg/permission_edit_white.svg | 6 + .../assets/svg/permission_table_del_blue.svg | 6 + .../assets/svg/permission_table_edit_blue.svg | 6 + frontend/src/assets/svg/pg-ds.svg | 13 + .../src/assets/svg/picture-group-dark.svg | 4 + .../src/assets/svg/picture-group-origin.svg | 4 + frontend/src/assets/svg/picture-group.svg | 4 + frontend/src/assets/svg/pie-dark.svg | 4 + frontend/src/assets/svg/pie-donut-dark.svg | 4 + frontend/src/assets/svg/pie-donut-origin.svg | 3 + .../src/assets/svg/pie-donut-rose-dark.svg | 1 + .../src/assets/svg/pie-donut-rose-origin.svg | 3 + frontend/src/assets/svg/pie-donut-rose.svg | 1 + frontend/src/assets/svg/pie-donut.svg | 4 + frontend/src/assets/svg/pie-origin.svg | 4 + frontend/src/assets/svg/pie-rose-dark.svg | 10 + frontend/src/assets/svg/pie-rose-origin.svg | 10 + frontend/src/assets/svg/pie-rose.svg | 10 + frontend/src/assets/svg/pie.svg | 4 + frontend/src/assets/svg/platform.svg | 3 + frontend/src/assets/svg/plugin-3dmap.svg | 1 + frontend/src/assets/svg/plugin-3dpie.svg | 16 + frontend/src/assets/svg/plugin-dameng.svg | 9 + frontend/src/assets/svg/plugin-default.svg | 3 + frontend/src/assets/svg/plugin.svg | 3 + frontend/src/assets/svg/plugins-new.svg | 3 + frontend/src/assets/svg/plugins.svg | 1 + frontend/src/assets/svg/progress-bar-dark.svg | 11 + .../src/assets/svg/progress-bar-origin.svg | 11 + frontend/src/assets/svg/progress-bar.svg | 11 + frontend/src/assets/svg/pwd_invisible.svg | 3 + frontend/src/assets/svg/pwd_visible.svg | 3 + frontend/src/assets/svg/quadrant-dark.svg | 12 + frontend/src/assets/svg/quadrant-origin.svg | 12 + frontend/src/assets/svg/quadrant.svg | 12 + frontend/src/assets/svg/radar-dark.svg | 6 + frontend/src/assets/svg/radar-origin.svg | 4 + frontend/src/assets/svg/radar.svg | 6 + frontend/src/assets/svg/read-msg.svg | 1 + frontend/src/assets/svg/redshift-ds.svg | 9 + frontend/src/assets/svg/reference-field.svg | 4 + frontend/src/assets/svg/reference-play.svg | 10 + .../assets/svg/reference-setting-white.svg | 3 + frontend/src/assets/svg/reference-setting.svg | 3 + frontend/src/assets/svg/reference-table.svg | 3 + .../src/assets/svg/relation_arrow_icon.svg | 3 + frontend/src/assets/svg/release.svg | 1 + frontend/src/assets/svg/report.svg | 7 + .../src/assets/svg/reset_password_blue.svg | 6 + frontend/src/assets/svg/rich-text-dark.svg | 3 + frontend/src/assets/svg/rich-text-origin.svg | 3 + frontend/src/assets/svg/rich-text.svg | 3 + frontend/src/assets/svg/richTextView.svg | 2 + frontend/src/assets/svg/right-join.svg | 7 + frontend/src/assets/svg/role.svg | 3 + frontend/src/assets/svg/round_play.svg | 3 + frontend/src/assets/svg/sankey-dark.svg | 5 + frontend/src/assets/svg/sankey-origin.svg | 5 + frontend/src/assets/svg/sankey.svg | 5 + frontend/src/assets/svg/scatter-dark.svg | 11 + frontend/src/assets/svg/scatter-origin.svg | 7 + frontend/src/assets/svg/scatter.svg | 11 + frontend/src/assets/svg/scatterpage.svg | 6 + frontend/src/assets/svg/scene.svg | 3 + frontend/src/assets/svg/scroll-text.svg | 1 + frontend/src/assets/svg/size.svg | 1 + frontend/src/assets/svg/sort-asc.svg | 1 + frontend/src/assets/svg/sort-desc.svg | 1 + frontend/src/assets/svg/sqlServer-ds.svg | 14 + frontend/src/assets/svg/stock-line-dark.svg | 11 + frontend/src/assets/svg/stock-line-origin.svg | 11 + frontend/src/assets/svg/stock-line.svg | 11 + frontend/src/assets/svg/style-underline.svg | 1 + frontend/src/assets/svg/symbolic-map-dark.svg | 1 + .../src/assets/svg/symbolic-map-origin.svg | 1 + frontend/src/assets/svg/symbolic-map.svg | 1 + frontend/src/assets/svg/sync.svg | 3 + frontend/src/assets/svg/sys-param.svg | 1 + frontend/src/assets/svg/sys-parameter.svg | 4 + frontend/src/assets/svg/sys-relationship.svg | 1 + frontend/src/assets/svg/sys-setting.svg | 3 + frontend/src/assets/svg/sys-tools.svg | 3 + frontend/src/assets/svg/system.svg | 1 + frontend/src/assets/svg/t-heatmap-dark.svg | 18 + frontend/src/assets/svg/t-heatmap-origin.svg | 18 + frontend/src/assets/svg/t-heatmap.svg | 18 + frontend/src/assets/svg/tab-title.svg | 1 + frontend/src/assets/svg/table-info-dark.svg | 12 + frontend/src/assets/svg/table-info-origin.svg | 3 + frontend/src/assets/svg/table-info.svg | 12 + frontend/src/assets/svg/table-normal-dark.svg | 7 + .../src/assets/svg/table-normal-origin.svg | 3 + frontend/src/assets/svg/table-normal.svg | 7 + frontend/src/assets/svg/table-pivot-dark.svg | 12 + .../src/assets/svg/table-pivot-origin.svg | 3 + frontend/src/assets/svg/table-pivot.svg | 12 + frontend/src/assets/svg/table.svg | 1 + frontend/src/assets/svg/task.svg | 4 + frontend/src/assets/svg/text-dark.svg | 6 + frontend/src/assets/svg/text.svg | 6 + frontend/src/assets/svg/threshold.svg | 3 + frontend/src/assets/svg/threshold_full.svg | 8 + frontend/src/assets/svg/title-bold.svg | 3 + frontend/src/assets/svg/title-center.svg | 5 + frontend/src/assets/svg/title-italic.svg | 3 + frontend/src/assets/svg/title-left.svg | 5 + frontend/src/assets/svg/title-right.svg | 5 + frontend/src/assets/svg/title-v-bottom.svg | 4 + frontend/src/assets/svg/title-v-center.svg | 5 + frontend/src/assets/svg/title-v-top.svg | 4 + frontend/src/assets/svg/toolbox-data_fill.svg | 5 + .../src/assets/svg/toolbox-icon_template.svg | 7 + frontend/src/assets/svg/toolbox-log.svg | 6 + frontend/src/assets/svg/top-doc-default.svg | 5 + .../src/assets/svg/top-enterprise-trial.svg | 5 + frontend/src/assets/svg/top-help-doc.svg | 5 + frontend/src/assets/svg/top-product-bbs.svg | 4 + frontend/src/assets/svg/top-tech-video.svg | 3 + frontend/src/assets/svg/top-technology.svg | 4 + frontend/src/assets/svg/tree.svg | 1 + frontend/src/assets/svg/treemap-dark.svg | 6 + frontend/src/assets/svg/treemap-origin.svg | 6 + frontend/src/assets/svg/treemap.svg | 6 + frontend/src/assets/svg/unlock.svg | 1 + frontend/src/assets/svg/unpublished.svg | 2 + frontend/src/assets/svg/unread-msg.svg | 1 + frontend/src/assets/svg/user-img.svg | 18 + frontend/src/assets/svg/user-reci.svg | 3 + frontend/src/assets/svg/user.svg | 1 + .../src/assets/svg/user_connect_white.svg | 1 + frontend/src/assets/svg/variable.svg | 1 + frontend/src/assets/svg/visual-star.svg | 3 + frontend/src/assets/svg/warn-tree.svg | 1 + frontend/src/assets/svg/waterfall-dark.svg | 7 + frontend/src/assets/svg/waterfall-origin.svg | 3 + frontend/src/assets/svg/waterfall.svg | 7 + frontend/src/assets/svg/watermark.svg | 4 + frontend/src/assets/svg/web-msg.svg | 1 + frontend/src/assets/svg/wizard_enterprise.svg | 81 + frontend/src/assets/svg/wizard_help.svg | 44 + .../src/assets/svg/wizard_main_bg_inner.svg | 266 + .../src/assets/svg/wizard_quick_start.svg | 47 + frontend/src/assets/svg/word-cloud-dark.svg | 18 + frontend/src/assets/svg/word-cloud-origin.svg | 4 + frontend/src/assets/svg/word-cloud.svg | 18 + frontend/src/data-collect/index.es.js | 25 +- frontend/src/data-public/Dashboard.vue | 14 +- .../src/data-public/FormCreateDesigner.vue | 4 + frontend/src/data-visualization/DvPreview.vue | 110 + .../data-visualization/canvas/DeCanvas.vue | 365 ++ .../editor/common/ChartTemplateInfo.vue | 45 + .../components/editor/common/TableTooltip.vue | 80 + .../components/editor/util/StringUtils.ts | 56 + .../chart/components/editor/util/chart.ts | 1759 +++++++ .../editor/util/dataVisualization.ts | 142 + .../chart/components/js/extremumUitl.ts | 392 ++ .../chart/components/js/formatter.ts | 107 + .../components/js/panel/charts/bar/bar.ts | 691 +++ .../js/panel/charts/bar/bidirectional-bar.ts | 582 +++ .../components/js/panel/charts/bar/common.ts | 84 + .../js/panel/charts/bar/horizontal-bar.ts | 501 ++ .../js/panel/charts/bar/progress-bar.ts | 389 ++ .../js/panel/charts/bar/range-bar.ts | 434 ++ .../js/panel/charts/bar/waterfall.ts | 337 ++ .../components/js/panel/charts/line/area.ts | 396 ++ .../components/js/panel/charts/line/common.ts | 74 + .../components/js/panel/charts/line/line.ts | 377 ++ .../js/panel/charts/line/stock-line.ts | 718 +++ .../js/panel/charts/liquid/liquid.ts | 221 + .../js/panel/charts/map/bubble-map.ts | 514 ++ .../components/js/panel/charts/map/common.ts | 56 + .../js/panel/charts/map/flow-map.ts | 411 ++ .../js/panel/charts/map/heat-map.ts | 186 + .../components/js/panel/charts/map/map.ts | 617 +++ .../js/panel/charts/map/symbolic-map.ts | 645 +++ .../js/panel/charts/map/tooltip-carousel.ts | 657 +++ .../panel/charts/others/chart-mix-common.ts | 119 + .../js/panel/charts/others/chart-mix.ts | 1006 ++++ .../js/panel/charts/others/circle-packing.ts | 279 + .../js/panel/charts/others/funnel.ts | 215 + .../js/panel/charts/others/gauge.ts | 350 ++ .../js/panel/charts/others/indicator.ts | 76 + .../js/panel/charts/others/picture-group.ts | 29 + .../js/panel/charts/others/quadrant.ts | 488 ++ .../js/panel/charts/others/radar.ts | 306 ++ .../js/panel/charts/others/rich-text.ts | 37 + .../js/panel/charts/others/sankey-common.ts | 40 + .../js/panel/charts/others/sankey.ts | 285 + .../js/panel/charts/others/scatter.ts | 298 ++ .../js/panel/charts/others/treemap.ts | 246 + .../js/panel/charts/others/word-cloud.ts | 184 + .../components/js/panel/charts/pie/common.ts | 63 + .../components/js/panel/charts/pie/pie.ts | 356 ++ .../components/js/panel/charts/pie/rose.ts | 285 + .../js/panel/charts/table/common.ts | 58 + .../js/panel/charts/table/t-heatmap.ts | 362 ++ .../js/panel/charts/table/table-info.ts | 510 ++ .../js/panel/charts/table/table-normal.ts | 300 ++ .../js/panel/charts/table/table-pivot.ts | 1003 ++++ .../components/js/panel/common/common_antv.ts | 1963 +++++++ .../js/panel/common/common_table.ts | 2021 +++++++ .../chart/components/js/panel/index.ts | 32 + .../components/js/panel/types/impl/g2plot.ts | 207 + .../components/js/panel/types/impl/l7.ts | 143 + .../components/js/panel/types/impl/l7plot.ts | 95 + .../components/js/panel/types/impl/s2.ts | 169 + .../chart/components/js/panel/types/index.ts | 128 + .../chart/components/js/util.ts | 1209 +++++ .../views/components/ChartComponentG2Plot.vue | 737 +++ .../views/components/ChartComponentS2.vue | 831 +++ .../views/components/ChartEmptyInfo.vue | 49 + .../views/components/ChartError.vue | 67 + .../components/views/components/DrillPath.vue | 131 + .../chart/components/views/index.vue | 1283 +++++ .../chart/components/views/util/util.ts | 5 + .../components/collapse-switch-item/index.ts | 2 + .../src/CollapseSwitchItem.vue | 88 + .../components/config-global/index.ts | 3 + .../config-global/src/ConfigGlobal.vue | 16 + .../components/data-visualization/DeGrid.vue | 92 + .../data-visualization/DeGridScreen.vue | 71 + .../data-visualization/canvas/Area.vue | 44 + .../data-visualization/canvas/CanvasCore.vue | 1761 +++++++ .../canvas/ComponentWrapper.vue | 478 ++ .../data-visualization/canvas/ComposeShow.vue | 60 + .../data-visualization/canvas/ContextMenu.vue | 33 + .../canvas/ContextMenuAsideDetails.vue | 21 + .../canvas/ContextMenuDetails.vue | 411 ++ .../data-visualization/canvas/DePreview.vue | 533 ++ .../data-visualization/canvas/DragShadow.vue | 64 + .../data-visualization/canvas/MarkLine.vue | 261 + .../data-visualization/canvas/PGrid.vue | 48 + .../data-visualization/canvas/PointShadow.vue | 72 + .../data-visualization/canvas/Shape.vue | 1321 +++++ .../components/de-board/Board.vue | 65 + .../components/empty-background/index.ts | 3 + .../empty-background/src/EmptyBackground.vue | 66 + .../components/icon-custom/index.ts | 9 + .../components/icon-custom/src/Icon.vue | 45 + .../components/icon-group/board-list.ts | 22 + .../components/icon-group/chart-dark-list.ts | 95 + .../components/icon-group/chart-list.ts | 101 + .../components/icon-group/datasource-list.ts | 36 + .../icon-group/field-calculated-list.ts | 33 + .../components/icon-group/field-list.ts | 14 + .../components/plugin/index.ts | 4 + .../components/plugin/src/PluginComponent.vue | 157 + .../components/plugin/src/convert.js | 88 + .../components/plugin/src/index.vue | 39 + .../components/plugin/src/nolic.vue | 13 + .../visualization/CanvasBaseSetting.vue | 145 + .../visualization/CanvasCacheDialog.vue | 91 + .../components/visualization/CanvasOptBar.vue | 107 + .../visualization/ComponentButton.vue | 90 + .../visualization/ComponentButtonLabel.vue | 79 + .../visualization/ComponentEditBar.vue | 730 +++ .../visualization/ComponentGroup.vue | 49 + .../visualization/ComponentSelector.vue | 43 + .../visualization/DatasetParamsComponent.vue | 144 + .../DatasetParamsSettingDialog.vue | 110 + .../visualization/DePreviewPopDialog.vue | 93 + .../components/visualization/DvSidebar.vue | 596 +++ .../components/visualization/EditMenu.vue | 52 + .../components/visualization/FieldsList.vue | 60 + .../visualization/HyperlinksDialog.vue | 110 + .../JumpSetOuterContentEditor.vue | 92 + .../components/visualization/LinkJumpSet.vue | 1623 ++++++ .../components/visualization/LinkageSet.vue | 1019 ++++ .../visualization/LinkageSetOption.vue | 83 + .../visualization/OuterParamsSet.vue | 1203 +++++ .../components/visualization/SettingMenu.vue | 388 ++ .../visualization/StreamMediaLinks.vue | 163 + .../visualization/TabCarouselDialog.vue | 110 + .../visualization/UserViewEnlarge.vue | 585 +++ .../components/visualization/ViewTrackBar.vue | 94 + .../common/ComponentPosition.vue | 245 + .../visualization/common/DeFullscreen.vue | 68 + .../visualization/common/DeUpload.vue | 258 + .../visualization/common/DragInfo.vue | 58 + .../component-background/BackgroundItem.vue | 146 + .../BackgroundItemOverall.vue | 140 + .../BackgroundOverallCommon.vue | 588 +++ .../component-background/BoardItem.vue | 73 + .../BorderOptionPrefix.vue | 41 + .../component-background/CanvasBackground.vue | 412 ++ .../components/watermark/watermark.ts | 241 + .../data-visualization/config/axios/config.ts | 46 + .../data-visualization/config/axios/index.ts | 36 + .../config/axios/refresh.ts | 88 + .../config/axios/service.ts | 248 + .../custom-component/ImgViewDialog.vue | 110 + .../custom-component/canvas-board/Attr.vue | 47 + .../canvas-board/Component.vue | 27 + .../custom-component/canvas-icon/Attr.vue | 43 + .../canvas-icon/Component.vue | 36 + .../custom-component/circle-shape/Attr.vue | 13 + .../circle-shape/Component.vue | 30 + .../common/AsideCloseButton.vue | 39 + .../custom-component/common/CanvasGroup.vue | 92 + .../common/CarouselSetting.vue | 104 + .../custom-component/common/CommonAttr.vue | 443 ++ .../common/CommonBorderSetting.vue | 218 + .../custom-component/common/CommonEvent.vue | 138 + .../common/CommonStyleSet.vue | 780 +++ .../common/ComponentConfig.ts | 211 + .../custom-component/common/DeInputNum.vue | 58 + .../custom-component/common/DeRuler.vue | 237 + .../common/DeRulerVertical.vue | 144 + .../custom-component/component-list.ts | 631 +++ .../custom-component/de-frame/Attr.vue | 33 + .../de-frame/ComponentFrame.vue | 136 + .../custom-component/de-frame/FrameLinks.vue | 146 + .../custom-component/de-graphical/Attr.vue | 172 + .../de-graphical/Component.vue | 23 + .../custom-component/de-stream-media/Attr.vue | 36 + .../de-stream-media/Component.vue | 166 + .../de-stream-media/StreamMediaLinks.vue | 179 + .../custom-component/de-tabs/Attr.vue | 68 + .../custom-component/de-tabs/Component.vue | 752 +++ .../de-tabs/CustomTabsSort.vue | 129 + .../custom-component/de-tabs/DeCustomTab.vue | 194 + .../custom-component/de-tabs/DeFullTabs.vue | 97 + .../de-tabs/TabBackgroundOverall.vue | 108 + .../custom-component/de-tabs/types.ts | 8 + .../custom-component/de-time-clock/Attr.vue | 184 + .../de-time-clock/Component.vue | 14 + .../de-time-clock/CustomAttr.vue | 132 + .../de-time-clock/TimeClockFormat.vue | 82 + .../de-time-clock/TimeDefault.vue | 60 + .../custom-component/de-video/Attr.vue | 34 + .../custom-component/de-video/Component.vue | 104 + .../custom-component/de-video/VideoLinks.vue | 172 + .../custom-component/group-area/Attr.vue | 13 + .../custom-component/group-area/Component.vue | 13 + .../group-area/ComponentShadow.vue | 16 + .../custom-component/group/Attr.vue | 44 + .../custom-component/group/Component.vue | 143 + .../custom-component/group/GroupPreview.vue | 112 + .../indicator/DeIndicator.vue | 397 ++ .../custom-component/picture-group/Attr.vue | 88 + .../picture-group/Component.vue | 286 + .../PictureGroupDatasetSelect.vue | 222 + .../picture-group/PictureGroupThreshold.vue | 239 + .../picture-group/PictureGroupUploadAttr.vue | 333 ++ .../picture-group/PictureItem.vue | 65 + .../picture-group/PictureOptionPrefix.vue | 31 + .../custom-component/picture/Attr.vue | 364 ++ .../custom-component/picture/Component.vue | 83 + .../custom-component/pop-area/Attr.vue | 13 + .../custom-component/pop-area/Component.vue | 224 + .../custom-component/rect-shape/Attr.vue | 13 + .../custom-component/rect-shape/Component.vue | 31 + .../rich-text/DeRichEditor.vue | 155 + .../rich-text/DeRichTextView.vue | 854 +++ .../custom-component/rich-text/FieldsList.vue | 59 + .../rich-text/plugins/index.ts | 11 + .../rich-text/plugins/vertical-content.ts | 87 + .../custom-component/scroll-text/Attr.vue | 56 + .../scroll-text/Component.vue | 240 + .../custom-component/svgs/svg-star/Attr.vue | 13 + .../svgs/svg-star/Component.vue | 99 + .../svgs/svg-triangle/Attr.vue | 13 + .../svgs/svg-triangle/Component.vue | 94 + .../custom-component/user-view/Attr.vue | 22 + .../custom-component/user-view/Component.vue | 123 + .../custom-component/v-query/Attr.vue | 30 + .../custom-component/v-query/Component.vue | 1065 ++++ .../v-query/ConditionDefaultConfiguration.vue | 920 ++++ .../v-query/CustomSortFilter.vue | 104 + .../custom-component/v-query/DynamicTime.vue | 179 + .../v-query/DynamicTimeFiltering.vue | 141 + .../v-query/DynamicTimeForViewFilter.vue | 143 + .../v-query/DynamicTimeRange.vue | 183 + .../v-query/DynamicTimeRangeFiltering.vue | 161 + .../custom-component/v-query/FilterTime.vue | 579 ++ .../custom-component/v-query/NumberInput.vue | 114 + .../custom-component/v-query/QueryCascade.vue | 391 ++ .../v-query/QueryConditionConfiguration.vue | 3944 ++++++++++++++ .../v-query/RangeFilterTime.vue | 610 +++ .../custom-component/v-query/Select.vue | 708 +++ .../custom-component/v-query/StyleInject.vue | 74 + .../custom-component/v-query/TextSearch.vue | 242 + .../custom-component/v-query/Time.vue | 537 ++ .../custom-component/v-query/Tree.vue | 297 ++ .../v-query/TreeFieldDialog.vue | 170 + .../custom-component/v-query/com-info.ts | 74 + .../custom-component/v-query/options.ts | 80 + .../custom-component/v-query/shortcuts.ts | 124 + .../v-query/time-format-dayjs.ts | 65 + .../custom-component/v-query/time-format.ts | 272 + .../custom-component/v-text/Attr.vue | 56 + .../custom-component/v-text/Component.vue | 164 + frontend/src/data-visualization/guid/util.ts | 172 + .../data-visualization/hooks/web/useCache.ts | 17 + .../data-visualization/hooks/web/useEmitt.ts | 23 + .../data-visualization/hooks/web/useI18n.ts | 52 + frontend/src/data-visualization/index.vue | 9 +- frontend/src/data-visualization/locales/en.ts | 4643 +++++++++++++++++ frontend/src/data-visualization/locales/tw.ts | 4501 ++++++++++++++++ .../src/data-visualization/locales/zh-CN.ts | 4507 ++++++++++++++++ .../plugins/element-plus/index.ts | 26 + .../plugins/vue-i18n/helper.ts | 3 + .../plugins/vue-i18n/index.ts | 52 + .../src/data-visualization/store/index.ts | 10 + .../data-visualization/store/modules/app.ts | 91 + .../store/modules/appearance.ts | 192 + .../modules/data-visualization/common.ts | 71 + .../modules/data-visualization/compose.ts | 290 + .../modules/data-visualization/contextmenu.ts | 29 + .../store/modules/data-visualization/copy.ts | 230 + .../modules/data-visualization/dvMain.ts | 1356 +++++ .../store/modules/data-visualization/layer.ts | 102 + .../store/modules/data-visualization/lock.ts | 32 + .../modules/data-visualization/snapshot.ts | 223 + .../store/modules/embedded.ts | 223 + .../data-visualization/store/modules/link.ts | 28 + .../store/modules/locale.ts | 86 + .../data-visualization/store/modules/map.ts | 29 + .../data-visualization/store/modules/user.ts | 115 + .../data-visualization/style/custom-theme.css | 225 + .../src/data-visualization/style/index.less | 698 +++ .../src/data-visualization/style/mixin.less | 49 + .../data-visualization/style/variable.less | 17 + .../data-visualization/utils/DeShortcutKey.ts | 279 + .../src/data-visualization/utils/ModelUtil.ts | 7 + frontend/src/data-visualization/utils/attr.ts | 118 + .../calculateComponentPositionAndSize.ts | 403 ++ .../data-visualization/utils/canvasStyle.ts | 567 ++ .../data-visualization/utils/canvasUtils.ts | 1019 ++++ .../utils/changeComponentsSizeWithScale.ts | 161 + .../data-visualization/utils/components.ts | 92 + .../utils/decomposeComponent.ts | 13 + .../src/data-visualization/utils/dvMain.ts | 1596 ++++++ .../src/data-visualization/utils/eventBus.ts | 4 + .../data-visualization/utils/generateID.ts | 7 + .../src/data-visualization/utils/imgUtils.ts | 187 + .../src/data-visualization/utils/propTypes.ts | 27 + .../src/data-visualization/utils/style.ts | 333 ++ .../data-visualization/utils/timeUitils.ts | 110 + .../src/data-visualization/utils/translate.ts | 142 + .../data-visualization/utils/treeSortUtils.ts | 41 + frontend/src/data-visualization/utils/url.ts | 5 + .../src/data-visualization/utils/utils.ts | 206 + .../src/data-visualization/utils/viewUtils.ts | 35 + frontend/src/locales/en.ts | 4643 +++++++++++++++++ frontend/src/locales/tw.ts | 4501 ++++++++++++++++ frontend/src/locales/zh-CN.ts | 4507 ++++++++++++++++ frontend/src/main.ts | 1 + frontend/src/router/index.ts | 8 + frontend/src/types/form-create.d.ts | 11 + frontend/src/utils/attr.ts | 118 + frontend/tsconfig.json | 9 +- frontend/types/data-visualization/base.d.ts | 4 + frontend/types/global.d.ts | 58 + frontend/types/localeDropdown.d.ts | 10 + frontend/types/router.d.ts | 49 + frontend/types/vite-env.d.ts | 2 + frontend/vite.config.js | 55 +- 1135 files changed, 122658 insertions(+), 30 deletions(-) create mode 100644 frontend/auto-imports.d.ts create mode 100644 frontend/components.d.ts create mode 100644 frontend/frontend.code-workspace create mode 100644 frontend/public/dataease.svg create mode 100644 frontend/public/images/code.png create mode 100644 frontend/public/images/loginbg.png create mode 100644 frontend/public/images/loginbtn.png create mode 100644 frontend/public/images/loginform.png create mode 100644 frontend/public/images/navbg.png create mode 100644 frontend/public/images/navmenu.png create mode 100644 frontend/public/images/navmenucheck.png create mode 100644 frontend/public/images/password.png create mode 100644 frontend/public/images/splitline1.png create mode 100644 frontend/public/images/splitline2.png create mode 100644 frontend/public/images/titleline.png create mode 100644 frontend/public/images/username.png create mode 100644 frontend/public/svg/icon_dashboard.svg create mode 100644 frontend/public/svg/icon_data-visualization.svg create mode 100644 frontend/public/svg/icon_database.svg create mode 100644 frontend/public/svg/icon_dataset.svg create mode 100644 frontend/public/svg/relation-dataset.svg create mode 100644 frontend/public/svg/relation-ds.svg create mode 100644 frontend/public/svg/relation-panel.svg create mode 100644 frontend/public/svg/relation-screen.svg create mode 100644 frontend/public/tinymce-dataease-private/langs/zh_CN.js create mode 100644 frontend/public/tinymce-dataease-private/langs/zh_TW.js create mode 100644 frontend/public/tinymce-dataease-private/skins/content/dark/content.css create mode 100644 frontend/public/tinymce-dataease-private/skins/content/dark/content.min.css create mode 100644 frontend/public/tinymce-dataease-private/skins/content/default/content.css create mode 100644 frontend/public/tinymce-dataease-private/skins/content/default/content.min.css create mode 100644 frontend/public/tinymce-dataease-private/skins/content/document/content.css create mode 100644 frontend/public/tinymce-dataease-private/skins/content/document/content.min.css create mode 100644 frontend/public/tinymce-dataease-private/skins/content/writer/content.css create mode 100644 frontend/public/tinymce-dataease-private/skins/content/writer/content.min.css create mode 100644 frontend/public/tinymce-dataease-private/skins/ui/oxide-dark/content.css create mode 100644 frontend/public/tinymce-dataease-private/skins/ui/oxide-dark/content.inline.css create mode 100644 frontend/public/tinymce-dataease-private/skins/ui/oxide-dark/content.inline.min.css create mode 100644 frontend/public/tinymce-dataease-private/skins/ui/oxide-dark/content.min.css create mode 100644 frontend/public/tinymce-dataease-private/skins/ui/oxide-dark/content.mobile.css create mode 100644 frontend/public/tinymce-dataease-private/skins/ui/oxide-dark/content.mobile.min.css create mode 100644 frontend/public/tinymce-dataease-private/skins/ui/oxide-dark/fonts/tinymce-mobile.woff create mode 100644 frontend/public/tinymce-dataease-private/skins/ui/oxide-dark/skin.css create mode 100644 frontend/public/tinymce-dataease-private/skins/ui/oxide-dark/skin.min.css create mode 100644 frontend/public/tinymce-dataease-private/skins/ui/oxide-dark/skin.mobile.css create mode 100644 frontend/public/tinymce-dataease-private/skins/ui/oxide-dark/skin.mobile.min.css create mode 100644 frontend/public/tinymce-dataease-private/skins/ui/oxide-dark/skin.shadowdom.css create mode 100644 frontend/public/tinymce-dataease-private/skins/ui/oxide-dark/skin.shadowdom.min.css create mode 100644 frontend/public/tinymce-dataease-private/skins/ui/oxide/content.css create mode 100644 frontend/public/tinymce-dataease-private/skins/ui/oxide/content.inline.css create mode 100644 frontend/public/tinymce-dataease-private/skins/ui/oxide/content.inline.min.css create mode 100644 frontend/public/tinymce-dataease-private/skins/ui/oxide/content.min.css create mode 100644 frontend/public/tinymce-dataease-private/skins/ui/oxide/content.mobile.css create mode 100644 frontend/public/tinymce-dataease-private/skins/ui/oxide/content.mobile.min.css create mode 100644 frontend/public/tinymce-dataease-private/skins/ui/oxide/fonts/tinymce-mobile.woff create mode 100644 frontend/public/tinymce-dataease-private/skins/ui/oxide/skin.css create mode 100644 frontend/public/tinymce-dataease-private/skins/ui/oxide/skin.min.css create mode 100644 frontend/public/tinymce-dataease-private/skins/ui/oxide/skin.mobile.css create mode 100644 frontend/public/tinymce-dataease-private/skins/ui/oxide/skin.mobile.min.css create mode 100644 frontend/public/tinymce-dataease-private/skins/ui/oxide/skin.shadowdom.css create mode 100644 frontend/public/tinymce-dataease-private/skins/ui/oxide/skin.shadowdom.min.css create mode 100644 frontend/public/vite.svg rename frontend/src/{data-visualization => }/api/chart.ts (100%) create mode 100644 frontend/src/api/data-visualization/chart.ts create mode 100644 frontend/src/api/data-visualization/dataset.ts create mode 100644 frontend/src/api/data-visualization/map.ts create mode 100644 frontend/src/api/data-visualization/staticResource.ts create mode 100644 frontend/src/api/data-visualization/user.ts create mode 100644 frontend/src/api/data-visualization/visualization/dataVisualization.ts create mode 100644 frontend/src/api/data-visualization/visualization/linkJump.ts create mode 100644 frontend/src/api/data-visualization/visualization/linkage.ts create mode 100644 frontend/src/assets/img/error.png create mode 100644 frontend/src/assets/img/none.png create mode 100644 frontend/src/assets/img/nothing-input.png create mode 100644 frontend/src/assets/img/nothing-none-black.png create mode 100644 frontend/src/assets/img/nothing-select.png create mode 100644 frontend/src/assets/img/nothing-table.png create mode 100644 frontend/src/assets/img/nothing-tree.png create mode 100644 frontend/src/assets/svg/401.svg create mode 100644 frontend/src/assets/svg/403.svg create mode 100644 frontend/src/assets/svg/API-ds.svg create mode 100644 frontend/src/assets/svg/Apache Hive.svg create mode 100644 frontend/src/assets/svg/Checkbox.svg create mode 100644 frontend/src/assets/svg/DM.svg create mode 100644 frontend/src/assets/svg/DataEase.svg create mode 100644 frontend/src/assets/svg/DataEase1.svg create mode 100644 frontend/src/assets/svg/Elasticsearch.svg create mode 100644 frontend/src/assets/svg/Excel-ds.svg create mode 100644 frontend/src/assets/svg/Frame.svg create mode 100644 frontend/src/assets/svg/KingBase.svg create mode 100644 frontend/src/assets/svg/Kylin.svg create mode 100644 frontend/src/assets/svg/Maxcompute.svg create mode 100644 frontend/src/assets/svg/PDF.svg create mode 100644 frontend/src/assets/svg/Presto.svg create mode 100644 frontend/src/assets/svg/StarRocks-ds.svg create mode 100644 frontend/src/assets/svg/TiDB-ds.svg create mode 100644 frontend/src/assets/svg/active-btn_copilot.svg create mode 100644 frontend/src/assets/svg/add.svg create mode 100644 frontend/src/assets/svg/add_white.svg create mode 100644 frontend/src/assets/svg/adds.svg create mode 100644 frontend/src/assets/svg/all-msg.svg create mode 100644 frontend/src/assets/svg/appearance.svg create mode 100644 frontend/src/assets/svg/area-dark.svg create mode 100644 frontend/src/assets/svg/area-origin.svg create mode 100644 frontend/src/assets/svg/area-stack-dark.svg create mode 100644 frontend/src/assets/svg/area-stack-origin.svg create mode 100644 frontend/src/assets/svg/area-stack.svg create mode 100644 frontend/src/assets/svg/area.svg create mode 100644 frontend/src/assets/svg/association.svg create mode 100644 frontend/src/assets/svg/auth.svg create mode 100644 frontend/src/assets/svg/authentication.svg create mode 100644 frontend/src/assets/svg/bar-dark.svg create mode 100644 frontend/src/assets/svg/bar-group-dark.svg create mode 100644 frontend/src/assets/svg/bar-group-origin.svg create mode 100644 frontend/src/assets/svg/bar-group-stack-dark.svg create mode 100644 frontend/src/assets/svg/bar-group-stack-origin.svg create mode 100644 frontend/src/assets/svg/bar-group-stack.svg create mode 100644 frontend/src/assets/svg/bar-group.svg create mode 100644 frontend/src/assets/svg/bar-horizontal-dark.svg create mode 100644 frontend/src/assets/svg/bar-horizontal-origin.svg create mode 100644 frontend/src/assets/svg/bar-horizontal.svg create mode 100644 frontend/src/assets/svg/bar-origin.svg create mode 100644 frontend/src/assets/svg/bar-range-dark.svg create mode 100644 frontend/src/assets/svg/bar-range-origin.svg create mode 100644 frontend/src/assets/svg/bar-range.svg create mode 100644 frontend/src/assets/svg/bar-stack-dark.svg create mode 100644 frontend/src/assets/svg/bar-stack-horizontal-dark.svg create mode 100644 frontend/src/assets/svg/bar-stack-horizontal-origin.svg create mode 100644 frontend/src/assets/svg/bar-stack-horizontal.svg create mode 100644 frontend/src/assets/svg/bar-stack-origin.svg create mode 100644 frontend/src/assets/svg/bar-stack.svg create mode 100644 frontend/src/assets/svg/bar.svg create mode 100644 frontend/src/assets/svg/bidirectional-bar-dark.svg create mode 100644 frontend/src/assets/svg/bidirectional-bar-origin.svg create mode 100644 frontend/src/assets/svg/bidirectional-bar.svg create mode 100644 frontend/src/assets/svg/board_1.svg create mode 100644 frontend/src/assets/svg/board_2.svg create mode 100644 frontend/src/assets/svg/board_3.svg create mode 100644 frontend/src/assets/svg/board_4.svg create mode 100644 frontend/src/assets/svg/board_5.svg create mode 100644 frontend/src/assets/svg/board_6.svg create mode 100644 frontend/src/assets/svg/board_7.svg create mode 100644 frontend/src/assets/svg/board_8.svg create mode 100644 frontend/src/assets/svg/board_9.svg create mode 100644 frontend/src/assets/svg/btn_copilot.svg create mode 100644 frontend/src/assets/svg/btn_oidc.svg create mode 100644 frontend/src/assets/svg/bubble-map-dark.svg create mode 100644 frontend/src/assets/svg/bubble-map-origin.svg create mode 100644 frontend/src/assets/svg/bubble-map.svg create mode 100644 frontend/src/assets/svg/button_right.svg create mode 100644 frontend/src/assets/svg/calculate.svg create mode 100644 frontend/src/assets/svg/cancel_release.svg create mode 100644 frontend/src/assets/svg/chart-download.svg create mode 100644 frontend/src/assets/svg/chart-mix-dark.svg create mode 100644 frontend/src/assets/svg/chart-mix-dual-line-dark.svg create mode 100644 frontend/src/assets/svg/chart-mix-dual-line-origin.svg create mode 100644 frontend/src/assets/svg/chart-mix-dual-line.svg create mode 100644 frontend/src/assets/svg/chart-mix-group-dark.svg create mode 100644 frontend/src/assets/svg/chart-mix-group-origin.svg create mode 100644 frontend/src/assets/svg/chart-mix-group.svg create mode 100644 frontend/src/assets/svg/chart-mix-origin.svg create mode 100644 frontend/src/assets/svg/chart-mix-stack-dark.svg create mode 100644 frontend/src/assets/svg/chart-mix-stack-origin.svg create mode 100644 frontend/src/assets/svg/chart-mix-stack.svg create mode 100644 frontend/src/assets/svg/chart-mix.svg create mode 100644 frontend/src/assets/svg/chart-table.svg create mode 100644 frontend/src/assets/svg/circle-packing-dark.svg create mode 100644 frontend/src/assets/svg/circle-packing-origin.svg create mode 100644 frontend/src/assets/svg/circle-packing.svg create mode 100644 frontend/src/assets/svg/ck-ds.svg create mode 100644 frontend/src/assets/svg/clock.svg create mode 100644 frontend/src/assets/svg/combinationpage.svg create mode 100644 frontend/src/assets/svg/copilot.svg create mode 100644 frontend/src/assets/svg/custom_sort.svg create mode 100644 frontend/src/assets/svg/dark_1.svg create mode 100644 frontend/src/assets/svg/dashboard.svg create mode 100644 frontend/src/assets/svg/data-reference.svg create mode 100644 frontend/src/assets/svg/database.svg create mode 100644 frontend/src/assets/svg/dataset-outline.svg create mode 100644 frontend/src/assets/svg/dataset-task.svg create mode 100644 frontend/src/assets/svg/dataset_params.svg create mode 100644 frontend/src/assets/svg/datasource.svg create mode 100644 frontend/src/assets/svg/datasoure_add_dataset.svg create mode 100644 frontend/src/assets/svg/datasoure_details.svg create mode 100644 frontend/src/assets/svg/db-de.svg create mode 100644 frontend/src/assets/svg/db-more-web.svg create mode 100644 frontend/src/assets/svg/db2-ds.svg create mode 100644 frontend/src/assets/svg/de-api-new.svg create mode 100644 frontend/src/assets/svg/de-copy.svg create mode 100644 frontend/src/assets/svg/de-db-new.svg create mode 100644 frontend/src/assets/svg/de-delete.svg create mode 100644 frontend/src/assets/svg/de-ds-error.svg create mode 100644 frontend/src/assets/svg/de-ds-move.svg create mode 100644 frontend/src/assets/svg/de-ds-rename.svg create mode 100644 frontend/src/assets/svg/de-ds-trash.svg create mode 100644 frontend/src/assets/svg/de-ds-warning.svg create mode 100644 frontend/src/assets/svg/de-excel-new.svg create mode 100644 frontend/src/assets/svg/de-json.svg create mode 100644 frontend/src/assets/svg/de-move.svg create mode 100644 frontend/src/assets/svg/de-search.svg create mode 100644 frontend/src/assets/svg/de-sql-new.svg create mode 100644 frontend/src/assets/svg/de-union-new.svg create mode 100644 frontend/src/assets/svg/de_pwd_invisible.svg create mode 100644 frontend/src/assets/svg/de_pwd_visible.svg create mode 100644 frontend/src/assets/svg/default_avatar.svg create mode 100644 frontend/src/assets/svg/delete.svg create mode 100644 frontend/src/assets/svg/display-setting.svg create mode 100644 frontend/src/assets/svg/doc.svg create mode 100644 frontend/src/assets/svg/docs.svg create mode 100644 frontend/src/assets/svg/doris-ds.svg create mode 100644 frontend/src/assets/svg/drag.svg create mode 100644 frontend/src/assets/svg/driver-de.svg create mode 100644 frontend/src/assets/svg/ds-api.svg create mode 100644 frontend/src/assets/svg/ds-custom.svg create mode 100644 frontend/src/assets/svg/ds-db.svg create mode 100644 frontend/src/assets/svg/ds-excel.svg create mode 100644 frontend/src/assets/svg/ds-sql.svg create mode 100644 frontend/src/assets/svg/ds-union.svg create mode 100644 frontend/src/assets/svg/dv-ai-window-max.svg create mode 100644 frontend/src/assets/svg/dv-ai-window-min.svg create mode 100644 frontend/src/assets/svg/dv-ai.svg create mode 100644 frontend/src/assets/svg/dv-bar-enlarge.svg create mode 100644 frontend/src/assets/svg/dv-bar-unLinkage.svg create mode 100644 frontend/src/assets/svg/dv-batch.svg create mode 100644 frontend/src/assets/svg/dv-batch_white.svg create mode 100644 frontend/src/assets/svg/dv-copy-dark.svg create mode 100644 frontend/src/assets/svg/dv-copy.svg create mode 100644 frontend/src/assets/svg/dv-dashboard-spine-mobile.svg create mode 100644 frontend/src/assets/svg/dv-dashboard-spine.svg create mode 100644 frontend/src/assets/svg/dv-dashboard.svg create mode 100644 frontend/src/assets/svg/dv-dashboard_white.svg create mode 100644 frontend/src/assets/svg/dv-delete.svg create mode 100644 frontend/src/assets/svg/dv-details.svg create mode 100644 frontend/src/assets/svg/dv-drag-tips.svg create mode 100644 frontend/src/assets/svg/dv-edit.svg create mode 100644 frontend/src/assets/svg/dv-empty.svg create mode 100644 frontend/src/assets/svg/dv-expand-down.svg create mode 100644 frontend/src/assets/svg/dv-expand-right.svg create mode 100644 frontend/src/assets/svg/dv-eye-close.svg create mode 100644 frontend/src/assets/svg/dv-filter-show.svg create mode 100644 frontend/src/assets/svg/dv-filter.svg create mode 100644 frontend/src/assets/svg/dv-folder.svg create mode 100644 frontend/src/assets/svg/dv-head-more.svg create mode 100644 frontend/src/assets/svg/dv-hidden.svg create mode 100644 frontend/src/assets/svg/dv-info.svg create mode 100644 frontend/src/assets/svg/dv-link-target.svg create mode 100644 frontend/src/assets/svg/dv-lock.svg create mode 100644 frontend/src/assets/svg/dv-material.svg create mode 100644 frontend/src/assets/svg/dv-max.svg create mode 100644 frontend/src/assets/svg/dv-media.svg create mode 100644 frontend/src/assets/svg/dv-min.svg create mode 100644 frontend/src/assets/svg/dv-more-com.svg create mode 100644 frontend/src/assets/svg/dv-more-time-clock.svg create mode 100644 frontend/src/assets/svg/dv-more.svg create mode 100644 frontend/src/assets/svg/dv-move.svg create mode 100644 frontend/src/assets/svg/dv-new-folder.svg create mode 100644 frontend/src/assets/svg/dv-new.svg create mode 100644 frontend/src/assets/svg/dv-no-img.svg create mode 100644 frontend/src/assets/svg/dv-nothing.svg create mode 100644 frontend/src/assets/svg/dv-params.svg create mode 100644 frontend/src/assets/svg/dv-picture-real.svg create mode 100644 frontend/src/assets/svg/dv-picture-show.svg create mode 100644 frontend/src/assets/svg/dv-picture.svg create mode 100644 frontend/src/assets/svg/dv-preview-download.svg create mode 100644 frontend/src/assets/svg/dv-preview-inner.svg create mode 100644 frontend/src/assets/svg/dv-preview-outer.svg create mode 100644 frontend/src/assets/svg/dv-preview.svg create mode 100644 frontend/src/assets/svg/dv-rename.svg create mode 100644 frontend/src/assets/svg/dv-reposition.svg create mode 100644 frontend/src/assets/svg/dv-richText.svg create mode 100644 frontend/src/assets/svg/dv-ruler.svg create mode 100644 frontend/src/assets/svg/dv-screen-new.svg create mode 100644 frontend/src/assets/svg/dv-screen-spine.svg create mode 100644 frontend/src/assets/svg/dv-scroll-text.svg create mode 100644 frontend/src/assets/svg/dv-share.svg create mode 100644 frontend/src/assets/svg/dv-show.svg create mode 100644 frontend/src/assets/svg/dv-sort-asc.svg create mode 100644 frontend/src/assets/svg/dv-sort-desc.svg create mode 100644 frontend/src/assets/svg/dv-style-activeFont.svg create mode 100644 frontend/src/assets/svg/dv-style-activeFontSize.svg create mode 100644 frontend/src/assets/svg/dv-style-backgroundColor.svg create mode 100644 frontend/src/assets/svg/dv-style-blur.svg create mode 100644 frontend/src/assets/svg/dv-style-borderColor.svg create mode 100644 frontend/src/assets/svg/dv-style-borderRadius.svg create mode 100644 frontend/src/assets/svg/dv-style-borderSize.svg create mode 100644 frontend/src/assets/svg/dv-style-borderStyle.svg create mode 100644 frontend/src/assets/svg/dv-style-color.svg create mode 100644 frontend/src/assets/svg/dv-style-fontFamily.svg create mode 100644 frontend/src/assets/svg/dv-style-fontSize.svg create mode 100644 frontend/src/assets/svg/dv-style-fontWeight.svg create mode 100644 frontend/src/assets/svg/dv-style-headBorderActiveColor.svg create mode 100644 frontend/src/assets/svg/dv-style-headBorderColor.svg create mode 100644 frontend/src/assets/svg/dv-style-headFontActiveColor.svg create mode 100644 frontend/src/assets/svg/dv-style-headFontColor.svg create mode 100644 frontend/src/assets/svg/dv-style-headHorizontalPosition.svg create mode 100644 frontend/src/assets/svg/dv-style-letterSpacing.svg create mode 100644 frontend/src/assets/svg/dv-style-lineHeight.svg create mode 100644 frontend/src/assets/svg/dv-style-opacity.svg create mode 100644 frontend/src/assets/svg/dv-style-scroll-speed.svg create mode 100644 frontend/src/assets/svg/dv-style-tab-head.svg create mode 100644 frontend/src/assets/svg/dv-style-textAlign.svg create mode 100644 frontend/src/assets/svg/dv-tab-show.svg create mode 100644 frontend/src/assets/svg/dv-tab.svg create mode 100644 frontend/src/assets/svg/dv-text.svg create mode 100644 frontend/src/assets/svg/dv-unlock.svg create mode 100644 frontend/src/assets/svg/dv-up-arrow.svg create mode 100644 frontend/src/assets/svg/dv-use-template.svg create mode 100644 frontend/src/assets/svg/dv-video.svg create mode 100644 frontend/src/assets/svg/dv-view.svg create mode 100644 frontend/src/assets/svg/dv_mobile_layout.svg create mode 100644 frontend/src/assets/svg/edit-done.svg create mode 100644 frontend/src/assets/svg/edit-in.svg create mode 100644 frontend/src/assets/svg/edit.svg create mode 100644 frontend/src/assets/svg/email-task.svg create mode 100644 frontend/src/assets/svg/embedded.svg create mode 100644 frontend/src/assets/svg/es-ds.svg create mode 100644 frontend/src/assets/svg/example.svg create mode 100644 frontend/src/assets/svg/exclamationmark.svg create mode 100644 frontend/src/assets/svg/exclamationmark2.svg create mode 100644 frontend/src/assets/svg/exit-fullscreen.svg create mode 100644 frontend/src/assets/svg/eye-open.svg create mode 100644 frontend/src/assets/svg/eye.svg create mode 100644 frontend/src/assets/svg/field_location.svg create mode 100644 frontend/src/assets/svg/field_text.svg create mode 100644 frontend/src/assets/svg/field_time.svg create mode 100644 frontend/src/assets/svg/field_url.svg create mode 100644 frontend/src/assets/svg/field_value.svg create mode 100644 frontend/src/assets/svg/filter-center.svg create mode 100644 frontend/src/assets/svg/filter-h-center.svg create mode 100644 frontend/src/assets/svg/filter-h-left.svg create mode 100644 frontend/src/assets/svg/filter-h-right.svg create mode 100644 frontend/src/assets/svg/filter-params.svg create mode 100644 frontend/src/assets/svg/filter-top.svg create mode 100644 frontend/src/assets/svg/filter.svg create mode 100644 frontend/src/assets/svg/flow-map-dark.svg create mode 100644 frontend/src/assets/svg/flow-map-origin.svg create mode 100644 frontend/src/assets/svg/flow-map.svg create mode 100644 frontend/src/assets/svg/folder.svg create mode 100644 frontend/src/assets/svg/form.svg create mode 100644 frontend/src/assets/svg/fullscreen.svg create mode 100644 frontend/src/assets/svg/funnel-dark.svg create mode 100644 frontend/src/assets/svg/funnel-origin.svg create mode 100644 frontend/src/assets/svg/funnel.svg create mode 100644 frontend/src/assets/svg/gauge-dark.svg create mode 100644 frontend/src/assets/svg/gauge-origin.svg create mode 100644 frontend/src/assets/svg/gauge.svg create mode 100644 frontend/src/assets/svg/graphical-circular.svg create mode 100644 frontend/src/assets/svg/graphical-rect.svg create mode 100644 frontend/src/assets/svg/graphical-triangle.svg create mode 100644 frontend/src/assets/svg/group-3400.svg create mode 100644 frontend/src/assets/svg/group.svg create mode 100644 frontend/src/assets/svg/heat-map-dark.svg create mode 100644 frontend/src/assets/svg/heat-map-origin.svg create mode 100644 frontend/src/assets/svg/heat-map.svg create mode 100644 frontend/src/assets/svg/icon-alarmclock.svg create mode 100644 frontend/src/assets/svg/icon-contacts.svg create mode 100644 frontend/src/assets/svg/icon-draft.svg create mode 100644 frontend/src/assets/svg/icon-filter.svg create mode 100644 frontend/src/assets/svg/icon-group.svg create mode 100644 frontend/src/assets/svg/icon-image-upload.svg create mode 100644 frontend/src/assets/svg/icon-image.svg create mode 100644 frontend/src/assets/svg/icon-laser.svg create mode 100644 frontend/src/assets/svg/icon-lock.svg create mode 100644 frontend/src/assets/svg/icon-maybe.svg create mode 100644 frontend/src/assets/svg/icon-maybe_outlined.svg create mode 100644 frontend/src/assets/svg/icon-more.svg create mode 100644 frontend/src/assets/svg/icon-quicksetting.svg create mode 100644 frontend/src/assets/svg/icon-setting.svg create mode 100644 frontend/src/assets/svg/icon-stream.svg create mode 100644 frontend/src/assets/svg/icon-video.svg create mode 100644 frontend/src/assets/svg/icon/ctrl/close.svg create mode 100644 frontend/src/assets/svg/icon/outline/notification.svg create mode 100644 frontend/src/assets/svg/icon_Batch_outlined.svg create mode 100644 frontend/src/assets/svg/icon_Invalid_colorful.svg create mode 100644 frontend/src/assets/svg/icon_add-dictionary_outlined.svg create mode 100644 frontend/src/assets/svg/icon_add-entry_outlined.svg create mode 100644 frontend/src/assets/svg/icon_add-folder_outlined.svg create mode 100644 frontend/src/assets/svg/icon_add_outlined-1.svg create mode 100644 frontend/src/assets/svg/icon_add_outlined.svg create mode 100644 frontend/src/assets/svg/icon_adjustment_outlined.svg create mode 100644 frontend/src/assets/svg/icon_admin_outlined.svg create mode 100644 frontend/src/assets/svg/icon_api-outlined.svg create mode 100644 frontend/src/assets/svg/icon_api.svg create mode 100644 frontend/src/assets/svg/icon_app_outlined.svg create mode 100644 frontend/src/assets/svg/icon_arrow-right_outlined.svg create mode 100644 frontend/src/assets/svg/icon_assigned_outlined.svg create mode 100644 frontend/src/assets/svg/icon_attachment_outlined.svg create mode 100644 frontend/src/assets/svg/icon_bold_outlined.svg create mode 100644 frontend/src/assets/svg/icon_bottom-align_outlined.svg create mode 100644 frontend/src/assets/svg/icon_calendar-calculated_outlined-1.svg create mode 100644 frontend/src/assets/svg/icon_calendar-calculated_outlined.svg create mode 100644 frontend/src/assets/svg/icon_calendar_outlined.svg create mode 100644 frontend/src/assets/svg/icon_cancel_store.svg create mode 100644 frontend/src/assets/svg/icon_card_outlined.svg create mode 100644 frontend/src/assets/svg/icon_center-alignment_outlined.svg create mode 100644 frontend/src/assets/svg/icon_chart-line-c.svg create mode 100644 frontend/src/assets/svg/icon_chart-line.svg create mode 100644 frontend/src/assets/svg/icon_clear_outlined.svg create mode 100644 frontend/src/assets/svg/icon_close_filled.svg create mode 100644 frontend/src/assets/svg/icon_close_outlined.svg create mode 100644 frontend/src/assets/svg/icon_collect_filled.svg create mode 100644 frontend/src/assets/svg/icon_collection_outlined.svg create mode 100644 frontend/src/assets/svg/icon_copy_filled.svg create mode 100644 frontend/src/assets/svg/icon_copy_outlined.svg create mode 100644 frontend/src/assets/svg/icon_customize.svg create mode 100644 frontend/src/assets/svg/icon_dashboard.svg create mode 100644 frontend/src/assets/svg/icon_dashboard_outlined-c.svg create mode 100644 frontend/src/assets/svg/icon_dashboard_outlined.svg create mode 100644 frontend/src/assets/svg/icon_data-visualization.svg create mode 100644 frontend/src/assets/svg/icon_database-alert_filled.svg create mode 100644 frontend/src/assets/svg/icon_database-fail_filled.svg create mode 100644 frontend/src/assets/svg/icon_database.svg create mode 100644 frontend/src/assets/svg/icon_database_outlined.svg create mode 100644 frontend/src/assets/svg/icon_dataset.svg create mode 100644 frontend/src/assets/svg/icon_dataset_outlined.svg create mode 100644 frontend/src/assets/svg/icon_db_filled.svg create mode 100644 frontend/src/assets/svg/icon_delete-trash_outlined.svg create mode 100644 frontend/src/assets/svg/icon_describe_outlined.svg create mode 100644 frontend/src/assets/svg/icon_dialpad_outlined.svg create mode 100644 frontend/src/assets/svg/icon_disorde-list_outlined.svg create mode 100644 frontend/src/assets/svg/icon_divider_outlined.svg create mode 100644 frontend/src/assets/svg/icon_doc-replace_outlined.svg create mode 100644 frontend/src/assets/svg/icon_done_outlined.svg create mode 100644 frontend/src/assets/svg/icon_down-right_outlined.svg create mode 100644 frontend/src/assets/svg/icon_down_outlined-1.svg create mode 100644 frontend/src/assets/svg/icon_down_outlined.svg create mode 100644 frontend/src/assets/svg/icon_download_outlined.svg create mode 100644 frontend/src/assets/svg/icon_drag_outlined.svg create mode 100644 frontend/src/assets/svg/icon_drilling_outlined.svg create mode 100644 frontend/src/assets/svg/icon_drive_filled.svg create mode 100644 frontend/src/assets/svg/icon_edit_outlined.svg create mode 100644 frontend/src/assets/svg/icon_effects_outlined.svg create mode 100644 frontend/src/assets/svg/icon_excel.svg create mode 100644 frontend/src/assets/svg/icon_excel_outlined.svg create mode 100644 frontend/src/assets/svg/icon_expand-down_filled.svg create mode 100644 frontend/src/assets/svg/icon_expand-left_filled.svg create mode 100644 frontend/src/assets/svg/icon_expand-right_filled.svg create mode 100644 frontend/src/assets/svg/icon_file-add_outlined.svg create mode 100644 frontend/src/assets/svg/icon_file-doc_colorful.svg create mode 100644 frontend/src/assets/svg/icon_file-excel_colorful.svg create mode 100644 frontend/src/assets/svg/icon_file-font_colorful.svg create mode 100644 frontend/src/assets/svg/icon_folder_filled.svg create mode 100644 frontend/src/assets/svg/icon_font-color_outlined.svg create mode 100644 frontend/src/assets/svg/icon_font.svg create mode 100644 frontend/src/assets/svg/icon_form_outlined.svg create mode 100644 frontend/src/assets/svg/icon_form_outlined_white.svg create mode 100644 frontend/src/assets/svg/icon_free.svg create mode 100644 frontend/src/assets/svg/icon_full-association.svg create mode 100644 frontend/src/assets/svg/icon_functions_outlined.svg create mode 100644 frontend/src/assets/svg/icon_graphical.svg create mode 100644 frontend/src/assets/svg/icon_gridlines_outlined.svg create mode 100644 frontend/src/assets/svg/icon_h1_outlined.svg create mode 100644 frontend/src/assets/svg/icon_h2_outlined.svg create mode 100644 frontend/src/assets/svg/icon_h3_outlined.svg create mode 100644 frontend/src/assets/svg/icon_hn_outlined.svg create mode 100644 frontend/src/assets/svg/icon_horizontal-align_outlined.svg create mode 100644 frontend/src/assets/svg/icon_info_colorful.svg create mode 100644 frontend/src/assets/svg/icon_info_filled.svg create mode 100644 frontend/src/assets/svg/icon_info_outlined.svg create mode 100644 frontend/src/assets/svg/icon_intersect.svg create mode 100644 frontend/src/assets/svg/icon_into-item_outlined.svg create mode 100644 frontend/src/assets/svg/icon_invisible_outlined.svg create mode 100644 frontend/src/assets/svg/icon_italic_outlined.svg create mode 100644 frontend/src/assets/svg/icon_left-align_outlined.svg create mode 100644 frontend/src/assets/svg/icon_left-alignment_outlined.svg create mode 100644 frontend/src/assets/svg/icon_left-association.svg create mode 100644 frontend/src/assets/svg/icon_left_outlined.svg create mode 100644 frontend/src/assets/svg/icon_letter-spacing_outlined.svg create mode 100644 frontend/src/assets/svg/icon_link-calculated_outlined-1.svg create mode 100644 frontend/src/assets/svg/icon_link-calculated_outlined.svg create mode 100644 frontend/src/assets/svg/icon_link-record.svg create mode 100644 frontend/src/assets/svg/icon_link-record_outlined-1.svg create mode 100644 frontend/src/assets/svg/icon_link-record_outlined.svg create mode 100644 frontend/src/assets/svg/icon_loading_outlined.svg create mode 100644 frontend/src/assets/svg/icon_local-calculated_outlined-1.svg create mode 100644 frontend/src/assets/svg/icon_local-calculated_outlined.svg create mode 100644 frontend/src/assets/svg/icon_local.svg create mode 100644 frontend/src/assets/svg/icon_local_outlined.svg create mode 100644 frontend/src/assets/svg/icon_logs_outlined-1.svg create mode 100644 frontend/src/assets/svg/icon_logs_outlined.svg create mode 100644 frontend/src/assets/svg/icon_magnify_outlined.svg create mode 100644 frontend/src/assets/svg/icon_member-add_outlined.svg create mode 100644 frontend/src/assets/svg/icon_member_filled.svg create mode 100644 frontend/src/assets/svg/icon_mfa_reset.svg create mode 100644 frontend/src/assets/svg/icon_minify_outlined.svg create mode 100644 frontend/src/assets/svg/icon_moments-categories_outlined.svg create mode 100644 frontend/src/assets/svg/icon_more-vertical_outlined.svg create mode 100644 frontend/src/assets/svg/icon_more-vertical_outlined_white.svg create mode 100644 frontend/src/assets/svg/icon_more_outlined.svg create mode 100644 frontend/src/assets/svg/icon_msg_fill.svg create mode 100644 frontend/src/assets/svg/icon_multi-line_outlined.svg create mode 100644 frontend/src/assets/svg/icon_new-item_outlined.svg create mode 100644 frontend/src/assets/svg/icon_notification_filled.svg create mode 100644 frontend/src/assets/svg/icon_notification_outlined.svg create mode 100644 frontend/src/assets/svg/icon_number-calculated_outlined-1.svg create mode 100644 frontend/src/assets/svg/icon_number-calculated_outlined.svg create mode 100644 frontend/src/assets/svg/icon_number_outlined.svg create mode 100644 frontend/src/assets/svg/icon_operation-analysis_outlined.svg create mode 100644 frontend/src/assets/svg/icon_orde-list_outlined.svg create mode 100644 frontend/src/assets/svg/icon_organization_outlined.svg create mode 100644 frontend/src/assets/svg/icon_params_setting.svg create mode 100644 frontend/src/assets/svg/icon_pc_fullscreen.svg create mode 100644 frontend/src/assets/svg/icon_pc_outlined.svg create mode 100644 frontend/src/assets/svg/icon_pc_outlined_copy.svg create mode 100644 frontend/src/assets/svg/icon_phone_outlined.svg create mode 100644 frontend/src/assets/svg/icon_pie_outlined-c.svg create mode 100644 frontend/src/assets/svg/icon_play-round_filled.svg create mode 100644 frontend/src/assets/svg/icon_play-round_outlined.svg create mode 100644 frontend/src/assets/svg/icon_play_round_outlined_white.svg create mode 100644 frontend/src/assets/svg/icon_plugin_outlined.svg create mode 100644 frontend/src/assets/svg/icon_preferences_outlined.svg create mode 100644 frontend/src/assets/svg/icon_pull-left_outlined.svg create mode 100644 frontend/src/assets/svg/icon_pull-right_outlined.svg create mode 100644 frontend/src/assets/svg/icon_qr_outlined.svg create mode 100644 frontend/src/assets/svg/icon_radio_outlined.svg create mode 100644 frontend/src/assets/svg/icon_redo_outlined.svg create mode 100644 frontend/src/assets/svg/icon_refresh_outlined.svg create mode 100644 frontend/src/assets/svg/icon_rename_outlined.svg create mode 100644 frontend/src/assets/svg/icon_replace_outlined.svg create mode 100644 frontend/src/assets/svg/icon_reset_outlined.svg create mode 100644 frontend/src/assets/svg/icon_resetpassword.svg create mode 100644 frontend/src/assets/svg/icon_right-align_outlined.svg create mode 100644 frontend/src/assets/svg/icon_right-alignment_outlined.svg create mode 100644 frontend/src/assets/svg/icon_right-association.svg create mode 100644 frontend/src/assets/svg/icon_right_outlined.svg create mode 100644 frontend/src/assets/svg/icon_scroll_filled.svg create mode 100644 frontend/src/assets/svg/icon_search-outline_outlined.svg create mode 100644 frontend/src/assets/svg/icon_search.svg create mode 100644 frontend/src/assets/svg/icon_security.svg create mode 100644 frontend/src/assets/svg/icon_share-label_filled.svg create mode 100644 frontend/src/assets/svg/icon_share-label_outlined.svg create mode 100644 frontend/src/assets/svg/icon_side-expand_outlined.svg create mode 100644 frontend/src/assets/svg/icon_side-fold_outlined.svg create mode 100644 frontend/src/assets/svg/icon_single-line_outlined.svg create mode 100644 frontend/src/assets/svg/icon_sort-a-to-z_outlined.svg create mode 100644 frontend/src/assets/svg/icon_sort-z-to-a_outlined.svg create mode 100644 frontend/src/assets/svg/icon_sort_outlined.svg create mode 100644 frontend/src/assets/svg/icon_sort_priority.svg create mode 100644 frontend/src/assets/svg/icon_sql.svg create mode 100644 frontend/src/assets/svg/icon_sql_outlined.svg create mode 100644 frontend/src/assets/svg/icon_sql_outlined_1.svg create mode 100644 frontend/src/assets/svg/icon_stretch_outlined.svg create mode 100644 frontend/src/assets/svg/icon_style-set_outlined.svg create mode 100644 frontend/src/assets/svg/icon_succeed_colorful.svg create mode 100644 frontend/src/assets/svg/icon_succeed_filled.svg create mode 100644 frontend/src/assets/svg/icon_switch_outlined.svg create mode 100644 frontend/src/assets/svg/icon_sync-play-round_filled.svg create mode 100644 frontend/src/assets/svg/icon_sync-play-round_outlined.svg create mode 100644 frontend/src/assets/svg/icon_sync_close_log_details.svg create mode 100644 frontend/src/assets/svg/icon_sync_datasource.svg create mode 100644 frontend/src/assets/svg/icon_sync_free.svg create mode 100644 frontend/src/assets/svg/icon_sync_log_number.svg create mode 100644 frontend/src/assets/svg/icon_sync_logs_outlined.svg create mode 100644 frontend/src/assets/svg/icon_sync_progress.svg create mode 100644 frontend/src/assets/svg/icon_sync_target_to_datasource.svg create mode 100644 frontend/src/assets/svg/icon_sync_task_number.svg create mode 100644 frontend/src/assets/svg/icon_take-action_outlined.svg create mode 100644 frontend/src/assets/svg/icon_team-add_outlined.svg create mode 100644 frontend/src/assets/svg/icon_template.svg create mode 100644 frontend/src/assets/svg/icon_template_colorful.svg create mode 100644 frontend/src/assets/svg/icon_template_outlined.svg create mode 100644 frontend/src/assets/svg/icon_text-box_outlined.svg create mode 100644 frontend/src/assets/svg/icon_text-calculated_outlined-1.svg create mode 100644 frontend/src/assets/svg/icon_text-calculated_outlined.svg create mode 100644 frontend/src/assets/svg/icon_text_outlined.svg create mode 100644 frontend/src/assets/svg/icon_time_outlined.svg create mode 100644 frontend/src/assets/svg/icon_title-left-align_outlined.svg create mode 100644 frontend/src/assets/svg/icon_title-top-align_outlined.svg create mode 100644 frontend/src/assets/svg/icon_todo_outlined.svg create mode 100644 frontend/src/assets/svg/icon_top-align_outlined.svg create mode 100644 frontend/src/assets/svg/icon_undo_outlined.svg create mode 100644 frontend/src/assets/svg/icon_up-left_outlined.svg create mode 100644 frontend/src/assets/svg/icon_upload_outlined.svg create mode 100644 frontend/src/assets/svg/icon_url_outlined.svg create mode 100644 frontend/src/assets/svg/icon_vertical-align_outlined.svg create mode 100644 frontend/src/assets/svg/icon_view-list_outlined.svg create mode 100644 frontend/src/assets/svg/icon_viewinchat_outlined.svg create mode 100644 frontend/src/assets/svg/icon_visible_outlined.svg create mode 100644 frontend/src/assets/svg/icon_warning_colorful.svg create mode 100644 frontend/src/assets/svg/icon_warning_colorful_red.svg create mode 100644 frontend/src/assets/svg/icon_warning_filled.svg create mode 100644 frontend/src/assets/svg/icon_webhook.svg create mode 100644 frontend/src/assets/svg/icon_yes_outlined.svg create mode 100644 frontend/src/assets/svg/iconfont.svg create mode 100644 frontend/src/assets/svg/impala-ds.svg create mode 100644 frontend/src/assets/svg/indicator-dark.svg create mode 100644 frontend/src/assets/svg/indicator-origin.svg create mode 100644 frontend/src/assets/svg/indicator.svg create mode 100644 frontend/src/assets/svg/inner-join.svg create mode 100644 frontend/src/assets/svg/international.svg create mode 100644 frontend/src/assets/svg/join-join.svg create mode 100644 frontend/src/assets/svg/label.svg create mode 100644 frontend/src/assets/svg/language.svg create mode 100644 frontend/src/assets/svg/left-join.svg create mode 100644 frontend/src/assets/svg/line-dark.svg create mode 100644 frontend/src/assets/svg/line-origin.svg create mode 100644 frontend/src/assets/svg/line.svg create mode 100644 frontend/src/assets/svg/link-back.svg create mode 100644 frontend/src/assets/svg/link-down.svg create mode 100644 frontend/src/assets/svg/link.svg create mode 100644 frontend/src/assets/svg/liquid-dark.svg create mode 100644 frontend/src/assets/svg/liquid-origin.svg create mode 100644 frontend/src/assets/svg/liquid.svg create mode 100644 frontend/src/assets/svg/lock_closed.svg create mode 100644 frontend/src/assets/svg/lock_closed_switch.svg create mode 100644 frontend/src/assets/svg/lock_open.svg create mode 100644 frontend/src/assets/svg/lock_open_back.svg create mode 100644 frontend/src/assets/svg/lock_other_open.svg create mode 100644 frontend/src/assets/svg/log.svg create mode 100644 frontend/src/assets/svg/logo.svg create mode 100644 frontend/src/assets/svg/logo1.svg create mode 100644 frontend/src/assets/svg/logo_cas.svg create mode 100644 frontend/src/assets/svg/logo_dingtalk.svg create mode 100644 frontend/src/assets/svg/logo_lark.svg create mode 100644 frontend/src/assets/svg/logo_ldap.svg create mode 100644 frontend/src/assets/svg/logo_oauth.svg create mode 100644 frontend/src/assets/svg/logo_wechat-work.svg create mode 100644 frontend/src/assets/svg/map-dark.svg create mode 100644 frontend/src/assets/svg/map-origin.svg create mode 100644 frontend/src/assets/svg/map.svg create mode 100644 frontend/src/assets/svg/map_mini.svg create mode 100644 frontend/src/assets/svg/map_old.svg create mode 100644 frontend/src/assets/svg/mariadb-ds.svg create mode 100644 frontend/src/assets/svg/market-expand.svg create mode 100644 frontend/src/assets/svg/market-retract.svg create mode 100644 frontend/src/assets/svg/menu.svg create mode 100644 frontend/src/assets/svg/menuconfig_treeadd_white.svg create mode 100644 frontend/src/assets/svg/mobile-checkbox.svg create mode 100644 frontend/src/assets/svg/mobile/icon_dashboard_filled.svg create mode 100644 frontend/src/assets/svg/mobile/icon_dashboard_outlined.svg create mode 100644 frontend/src/assets/svg/mobile/icon_home_filled.svg create mode 100644 frontend/src/assets/svg/mobile/icon_home_outlined.svg create mode 100644 frontend/src/assets/svg/mobile/icon_member_filled.svg create mode 100644 frontend/src/assets/svg/mobile/icon_member_outlined.svg create mode 100644 frontend/src/assets/svg/mongo-ds.svg create mode 100644 frontend/src/assets/svg/more_v.svg create mode 100644 frontend/src/assets/svg/move.svg create mode 100644 frontend/src/assets/svg/msg-fill.svg create mode 100644 frontend/src/assets/svg/msg-notice.svg create mode 100644 frontend/src/assets/svg/msg-setting.svg create mode 100644 frontend/src/assets/svg/mysql-ds.svg create mode 100644 frontend/src/assets/svg/mysql-frame.svg create mode 100644 frontend/src/assets/svg/nested.svg create mode 100644 frontend/src/assets/svg/no-join.svg create mode 100644 frontend/src/assets/svg/no_result.svg create mode 100644 frontend/src/assets/svg/non-existent.svg create mode 100644 frontend/src/assets/svg/none_select.svg create mode 100644 frontend/src/assets/svg/notification.svg create mode 100644 frontend/src/assets/svg/oracle-ds.svg create mode 100644 frontend/src/assets/svg/org.svg create mode 100644 frontend/src/assets/svg/other_material.svg create mode 100644 frontend/src/assets/svg/other_material_board.svg create mode 100644 frontend/src/assets/svg/other_material_icon.svg create mode 100644 frontend/src/assets/svg/other_media.svg create mode 100644 frontend/src/assets/svg/other_setting.svg create mode 100644 frontend/src/assets/svg/other_text.svg create mode 100644 frontend/src/assets/svg/outer-params-filter.svg create mode 100644 frontend/src/assets/svg/page-line.svg create mode 100644 frontend/src/assets/svg/panel-mobile-publish.svg create mode 100644 frontend/src/assets/svg/panel-mobile-unpublished-back.svg create mode 100644 frontend/src/assets/svg/panel-mobile-unpublished.svg create mode 100644 frontend/src/assets/svg/panel-publish.svg create mode 100644 frontend/src/assets/svg/panel-unpublished-back.svg create mode 100644 frontend/src/assets/svg/panel-unpublished.svg create mode 100644 frontend/src/assets/svg/panel.svg create mode 100644 frontend/src/assets/svg/people.svg create mode 100644 frontend/src/assets/svg/peoples.svg create mode 100644 frontend/src/assets/svg/percentage-bar-stack-dark.svg create mode 100644 frontend/src/assets/svg/percentage-bar-stack-horizontal-dark.svg create mode 100644 frontend/src/assets/svg/percentage-bar-stack-horizontal-origin.svg create mode 100644 frontend/src/assets/svg/percentage-bar-stack-horizontal.svg create mode 100644 frontend/src/assets/svg/percentage-bar-stack-origin.svg create mode 100644 frontend/src/assets/svg/percentage-bar-stack.svg create mode 100644 frontend/src/assets/svg/perission_role_blue.svg create mode 100644 frontend/src/assets/svg/permission_del_blue.svg create mode 100644 frontend/src/assets/svg/permission_del_white.svg create mode 100644 frontend/src/assets/svg/permission_edit_blue.svg create mode 100644 frontend/src/assets/svg/permission_edit_white.svg create mode 100644 frontend/src/assets/svg/permission_table_del_blue.svg create mode 100644 frontend/src/assets/svg/permission_table_edit_blue.svg create mode 100644 frontend/src/assets/svg/pg-ds.svg create mode 100644 frontend/src/assets/svg/picture-group-dark.svg create mode 100644 frontend/src/assets/svg/picture-group-origin.svg create mode 100644 frontend/src/assets/svg/picture-group.svg create mode 100644 frontend/src/assets/svg/pie-dark.svg create mode 100644 frontend/src/assets/svg/pie-donut-dark.svg create mode 100644 frontend/src/assets/svg/pie-donut-origin.svg create mode 100644 frontend/src/assets/svg/pie-donut-rose-dark.svg create mode 100644 frontend/src/assets/svg/pie-donut-rose-origin.svg create mode 100644 frontend/src/assets/svg/pie-donut-rose.svg create mode 100644 frontend/src/assets/svg/pie-donut.svg create mode 100644 frontend/src/assets/svg/pie-origin.svg create mode 100644 frontend/src/assets/svg/pie-rose-dark.svg create mode 100644 frontend/src/assets/svg/pie-rose-origin.svg create mode 100644 frontend/src/assets/svg/pie-rose.svg create mode 100644 frontend/src/assets/svg/pie.svg create mode 100644 frontend/src/assets/svg/platform.svg create mode 100644 frontend/src/assets/svg/plugin-3dmap.svg create mode 100644 frontend/src/assets/svg/plugin-3dpie.svg create mode 100644 frontend/src/assets/svg/plugin-dameng.svg create mode 100644 frontend/src/assets/svg/plugin-default.svg create mode 100644 frontend/src/assets/svg/plugin.svg create mode 100644 frontend/src/assets/svg/plugins-new.svg create mode 100644 frontend/src/assets/svg/plugins.svg create mode 100644 frontend/src/assets/svg/progress-bar-dark.svg create mode 100644 frontend/src/assets/svg/progress-bar-origin.svg create mode 100644 frontend/src/assets/svg/progress-bar.svg create mode 100644 frontend/src/assets/svg/pwd_invisible.svg create mode 100644 frontend/src/assets/svg/pwd_visible.svg create mode 100644 frontend/src/assets/svg/quadrant-dark.svg create mode 100644 frontend/src/assets/svg/quadrant-origin.svg create mode 100644 frontend/src/assets/svg/quadrant.svg create mode 100644 frontend/src/assets/svg/radar-dark.svg create mode 100644 frontend/src/assets/svg/radar-origin.svg create mode 100644 frontend/src/assets/svg/radar.svg create mode 100644 frontend/src/assets/svg/read-msg.svg create mode 100644 frontend/src/assets/svg/redshift-ds.svg create mode 100644 frontend/src/assets/svg/reference-field.svg create mode 100644 frontend/src/assets/svg/reference-play.svg create mode 100644 frontend/src/assets/svg/reference-setting-white.svg create mode 100644 frontend/src/assets/svg/reference-setting.svg create mode 100644 frontend/src/assets/svg/reference-table.svg create mode 100644 frontend/src/assets/svg/relation_arrow_icon.svg create mode 100644 frontend/src/assets/svg/release.svg create mode 100644 frontend/src/assets/svg/report.svg create mode 100644 frontend/src/assets/svg/reset_password_blue.svg create mode 100644 frontend/src/assets/svg/rich-text-dark.svg create mode 100644 frontend/src/assets/svg/rich-text-origin.svg create mode 100644 frontend/src/assets/svg/rich-text.svg create mode 100644 frontend/src/assets/svg/richTextView.svg create mode 100644 frontend/src/assets/svg/right-join.svg create mode 100644 frontend/src/assets/svg/role.svg create mode 100644 frontend/src/assets/svg/round_play.svg create mode 100644 frontend/src/assets/svg/sankey-dark.svg create mode 100644 frontend/src/assets/svg/sankey-origin.svg create mode 100644 frontend/src/assets/svg/sankey.svg create mode 100644 frontend/src/assets/svg/scatter-dark.svg create mode 100644 frontend/src/assets/svg/scatter-origin.svg create mode 100644 frontend/src/assets/svg/scatter.svg create mode 100644 frontend/src/assets/svg/scatterpage.svg create mode 100644 frontend/src/assets/svg/scene.svg create mode 100644 frontend/src/assets/svg/scroll-text.svg create mode 100644 frontend/src/assets/svg/size.svg create mode 100644 frontend/src/assets/svg/sort-asc.svg create mode 100644 frontend/src/assets/svg/sort-desc.svg create mode 100644 frontend/src/assets/svg/sqlServer-ds.svg create mode 100644 frontend/src/assets/svg/stock-line-dark.svg create mode 100644 frontend/src/assets/svg/stock-line-origin.svg create mode 100644 frontend/src/assets/svg/stock-line.svg create mode 100644 frontend/src/assets/svg/style-underline.svg create mode 100644 frontend/src/assets/svg/symbolic-map-dark.svg create mode 100644 frontend/src/assets/svg/symbolic-map-origin.svg create mode 100644 frontend/src/assets/svg/symbolic-map.svg create mode 100644 frontend/src/assets/svg/sync.svg create mode 100644 frontend/src/assets/svg/sys-param.svg create mode 100644 frontend/src/assets/svg/sys-parameter.svg create mode 100644 frontend/src/assets/svg/sys-relationship.svg create mode 100644 frontend/src/assets/svg/sys-setting.svg create mode 100644 frontend/src/assets/svg/sys-tools.svg create mode 100644 frontend/src/assets/svg/system.svg create mode 100644 frontend/src/assets/svg/t-heatmap-dark.svg create mode 100644 frontend/src/assets/svg/t-heatmap-origin.svg create mode 100644 frontend/src/assets/svg/t-heatmap.svg create mode 100644 frontend/src/assets/svg/tab-title.svg create mode 100644 frontend/src/assets/svg/table-info-dark.svg create mode 100644 frontend/src/assets/svg/table-info-origin.svg create mode 100644 frontend/src/assets/svg/table-info.svg create mode 100644 frontend/src/assets/svg/table-normal-dark.svg create mode 100644 frontend/src/assets/svg/table-normal-origin.svg create mode 100644 frontend/src/assets/svg/table-normal.svg create mode 100644 frontend/src/assets/svg/table-pivot-dark.svg create mode 100644 frontend/src/assets/svg/table-pivot-origin.svg create mode 100644 frontend/src/assets/svg/table-pivot.svg create mode 100644 frontend/src/assets/svg/table.svg create mode 100644 frontend/src/assets/svg/task.svg create mode 100644 frontend/src/assets/svg/text-dark.svg create mode 100644 frontend/src/assets/svg/text.svg create mode 100644 frontend/src/assets/svg/threshold.svg create mode 100644 frontend/src/assets/svg/threshold_full.svg create mode 100644 frontend/src/assets/svg/title-bold.svg create mode 100644 frontend/src/assets/svg/title-center.svg create mode 100644 frontend/src/assets/svg/title-italic.svg create mode 100644 frontend/src/assets/svg/title-left.svg create mode 100644 frontend/src/assets/svg/title-right.svg create mode 100644 frontend/src/assets/svg/title-v-bottom.svg create mode 100644 frontend/src/assets/svg/title-v-center.svg create mode 100644 frontend/src/assets/svg/title-v-top.svg create mode 100644 frontend/src/assets/svg/toolbox-data_fill.svg create mode 100644 frontend/src/assets/svg/toolbox-icon_template.svg create mode 100644 frontend/src/assets/svg/toolbox-log.svg create mode 100644 frontend/src/assets/svg/top-doc-default.svg create mode 100644 frontend/src/assets/svg/top-enterprise-trial.svg create mode 100644 frontend/src/assets/svg/top-help-doc.svg create mode 100644 frontend/src/assets/svg/top-product-bbs.svg create mode 100644 frontend/src/assets/svg/top-tech-video.svg create mode 100644 frontend/src/assets/svg/top-technology.svg create mode 100644 frontend/src/assets/svg/tree.svg create mode 100644 frontend/src/assets/svg/treemap-dark.svg create mode 100644 frontend/src/assets/svg/treemap-origin.svg create mode 100644 frontend/src/assets/svg/treemap.svg create mode 100644 frontend/src/assets/svg/unlock.svg create mode 100644 frontend/src/assets/svg/unpublished.svg create mode 100644 frontend/src/assets/svg/unread-msg.svg create mode 100644 frontend/src/assets/svg/user-img.svg create mode 100644 frontend/src/assets/svg/user-reci.svg create mode 100644 frontend/src/assets/svg/user.svg create mode 100644 frontend/src/assets/svg/user_connect_white.svg create mode 100644 frontend/src/assets/svg/variable.svg create mode 100644 frontend/src/assets/svg/visual-star.svg create mode 100644 frontend/src/assets/svg/warn-tree.svg create mode 100644 frontend/src/assets/svg/waterfall-dark.svg create mode 100644 frontend/src/assets/svg/waterfall-origin.svg create mode 100644 frontend/src/assets/svg/waterfall.svg create mode 100644 frontend/src/assets/svg/watermark.svg create mode 100644 frontend/src/assets/svg/web-msg.svg create mode 100644 frontend/src/assets/svg/wizard_enterprise.svg create mode 100644 frontend/src/assets/svg/wizard_help.svg create mode 100644 frontend/src/assets/svg/wizard_main_bg_inner.svg create mode 100644 frontend/src/assets/svg/wizard_quick_start.svg create mode 100644 frontend/src/assets/svg/word-cloud-dark.svg create mode 100644 frontend/src/assets/svg/word-cloud-origin.svg create mode 100644 frontend/src/assets/svg/word-cloud.svg create mode 100644 frontend/src/data-visualization/DvPreview.vue create mode 100644 frontend/src/data-visualization/canvas/DeCanvas.vue create mode 100644 frontend/src/data-visualization/chart/components/editor/common/ChartTemplateInfo.vue create mode 100644 frontend/src/data-visualization/chart/components/editor/common/TableTooltip.vue create mode 100644 frontend/src/data-visualization/chart/components/editor/util/StringUtils.ts create mode 100644 frontend/src/data-visualization/chart/components/editor/util/chart.ts create mode 100644 frontend/src/data-visualization/chart/components/editor/util/dataVisualization.ts create mode 100644 frontend/src/data-visualization/chart/components/js/extremumUitl.ts create mode 100644 frontend/src/data-visualization/chart/components/js/formatter.ts create mode 100644 frontend/src/data-visualization/chart/components/js/panel/charts/bar/bar.ts create mode 100644 frontend/src/data-visualization/chart/components/js/panel/charts/bar/bidirectional-bar.ts create mode 100644 frontend/src/data-visualization/chart/components/js/panel/charts/bar/common.ts create mode 100644 frontend/src/data-visualization/chart/components/js/panel/charts/bar/horizontal-bar.ts create mode 100644 frontend/src/data-visualization/chart/components/js/panel/charts/bar/progress-bar.ts create mode 100644 frontend/src/data-visualization/chart/components/js/panel/charts/bar/range-bar.ts create mode 100644 frontend/src/data-visualization/chart/components/js/panel/charts/bar/waterfall.ts create mode 100644 frontend/src/data-visualization/chart/components/js/panel/charts/line/area.ts create mode 100644 frontend/src/data-visualization/chart/components/js/panel/charts/line/common.ts create mode 100644 frontend/src/data-visualization/chart/components/js/panel/charts/line/line.ts create mode 100644 frontend/src/data-visualization/chart/components/js/panel/charts/line/stock-line.ts create mode 100644 frontend/src/data-visualization/chart/components/js/panel/charts/liquid/liquid.ts create mode 100644 frontend/src/data-visualization/chart/components/js/panel/charts/map/bubble-map.ts create mode 100644 frontend/src/data-visualization/chart/components/js/panel/charts/map/common.ts create mode 100644 frontend/src/data-visualization/chart/components/js/panel/charts/map/flow-map.ts create mode 100644 frontend/src/data-visualization/chart/components/js/panel/charts/map/heat-map.ts create mode 100644 frontend/src/data-visualization/chart/components/js/panel/charts/map/map.ts create mode 100644 frontend/src/data-visualization/chart/components/js/panel/charts/map/symbolic-map.ts create mode 100644 frontend/src/data-visualization/chart/components/js/panel/charts/map/tooltip-carousel.ts create mode 100644 frontend/src/data-visualization/chart/components/js/panel/charts/others/chart-mix-common.ts create mode 100644 frontend/src/data-visualization/chart/components/js/panel/charts/others/chart-mix.ts create mode 100644 frontend/src/data-visualization/chart/components/js/panel/charts/others/circle-packing.ts create mode 100644 frontend/src/data-visualization/chart/components/js/panel/charts/others/funnel.ts create mode 100644 frontend/src/data-visualization/chart/components/js/panel/charts/others/gauge.ts create mode 100644 frontend/src/data-visualization/chart/components/js/panel/charts/others/indicator.ts create mode 100644 frontend/src/data-visualization/chart/components/js/panel/charts/others/picture-group.ts create mode 100644 frontend/src/data-visualization/chart/components/js/panel/charts/others/quadrant.ts create mode 100644 frontend/src/data-visualization/chart/components/js/panel/charts/others/radar.ts create mode 100644 frontend/src/data-visualization/chart/components/js/panel/charts/others/rich-text.ts create mode 100644 frontend/src/data-visualization/chart/components/js/panel/charts/others/sankey-common.ts create mode 100644 frontend/src/data-visualization/chart/components/js/panel/charts/others/sankey.ts create mode 100644 frontend/src/data-visualization/chart/components/js/panel/charts/others/scatter.ts create mode 100644 frontend/src/data-visualization/chart/components/js/panel/charts/others/treemap.ts create mode 100644 frontend/src/data-visualization/chart/components/js/panel/charts/others/word-cloud.ts create mode 100644 frontend/src/data-visualization/chart/components/js/panel/charts/pie/common.ts create mode 100644 frontend/src/data-visualization/chart/components/js/panel/charts/pie/pie.ts create mode 100644 frontend/src/data-visualization/chart/components/js/panel/charts/pie/rose.ts create mode 100644 frontend/src/data-visualization/chart/components/js/panel/charts/table/common.ts create mode 100644 frontend/src/data-visualization/chart/components/js/panel/charts/table/t-heatmap.ts create mode 100644 frontend/src/data-visualization/chart/components/js/panel/charts/table/table-info.ts create mode 100644 frontend/src/data-visualization/chart/components/js/panel/charts/table/table-normal.ts create mode 100644 frontend/src/data-visualization/chart/components/js/panel/charts/table/table-pivot.ts create mode 100644 frontend/src/data-visualization/chart/components/js/panel/common/common_antv.ts create mode 100644 frontend/src/data-visualization/chart/components/js/panel/common/common_table.ts create mode 100644 frontend/src/data-visualization/chart/components/js/panel/index.ts create mode 100644 frontend/src/data-visualization/chart/components/js/panel/types/impl/g2plot.ts create mode 100644 frontend/src/data-visualization/chart/components/js/panel/types/impl/l7.ts create mode 100644 frontend/src/data-visualization/chart/components/js/panel/types/impl/l7plot.ts create mode 100644 frontend/src/data-visualization/chart/components/js/panel/types/impl/s2.ts create mode 100644 frontend/src/data-visualization/chart/components/js/panel/types/index.ts create mode 100644 frontend/src/data-visualization/chart/components/js/util.ts create mode 100644 frontend/src/data-visualization/chart/components/views/components/ChartComponentG2Plot.vue create mode 100644 frontend/src/data-visualization/chart/components/views/components/ChartComponentS2.vue create mode 100644 frontend/src/data-visualization/chart/components/views/components/ChartEmptyInfo.vue create mode 100644 frontend/src/data-visualization/chart/components/views/components/ChartError.vue create mode 100644 frontend/src/data-visualization/chart/components/views/components/DrillPath.vue create mode 100644 frontend/src/data-visualization/chart/components/views/index.vue create mode 100644 frontend/src/data-visualization/chart/components/views/util/util.ts create mode 100644 frontend/src/data-visualization/components/collapse-switch-item/index.ts create mode 100644 frontend/src/data-visualization/components/collapse-switch-item/src/CollapseSwitchItem.vue create mode 100644 frontend/src/data-visualization/components/config-global/index.ts create mode 100644 frontend/src/data-visualization/components/config-global/src/ConfigGlobal.vue create mode 100644 frontend/src/data-visualization/components/data-visualization/DeGrid.vue create mode 100644 frontend/src/data-visualization/components/data-visualization/DeGridScreen.vue create mode 100644 frontend/src/data-visualization/components/data-visualization/canvas/Area.vue create mode 100644 frontend/src/data-visualization/components/data-visualization/canvas/CanvasCore.vue create mode 100644 frontend/src/data-visualization/components/data-visualization/canvas/ComponentWrapper.vue create mode 100644 frontend/src/data-visualization/components/data-visualization/canvas/ComposeShow.vue create mode 100644 frontend/src/data-visualization/components/data-visualization/canvas/ContextMenu.vue create mode 100644 frontend/src/data-visualization/components/data-visualization/canvas/ContextMenuAsideDetails.vue create mode 100644 frontend/src/data-visualization/components/data-visualization/canvas/ContextMenuDetails.vue create mode 100644 frontend/src/data-visualization/components/data-visualization/canvas/DePreview.vue create mode 100644 frontend/src/data-visualization/components/data-visualization/canvas/DragShadow.vue create mode 100644 frontend/src/data-visualization/components/data-visualization/canvas/MarkLine.vue create mode 100644 frontend/src/data-visualization/components/data-visualization/canvas/PGrid.vue create mode 100644 frontend/src/data-visualization/components/data-visualization/canvas/PointShadow.vue create mode 100644 frontend/src/data-visualization/components/data-visualization/canvas/Shape.vue create mode 100644 frontend/src/data-visualization/components/de-board/Board.vue create mode 100644 frontend/src/data-visualization/components/empty-background/index.ts create mode 100644 frontend/src/data-visualization/components/empty-background/src/EmptyBackground.vue create mode 100644 frontend/src/data-visualization/components/icon-custom/index.ts create mode 100644 frontend/src/data-visualization/components/icon-custom/src/Icon.vue create mode 100644 frontend/src/data-visualization/components/icon-group/board-list.ts create mode 100644 frontend/src/data-visualization/components/icon-group/chart-dark-list.ts create mode 100644 frontend/src/data-visualization/components/icon-group/chart-list.ts create mode 100644 frontend/src/data-visualization/components/icon-group/datasource-list.ts create mode 100644 frontend/src/data-visualization/components/icon-group/field-calculated-list.ts create mode 100644 frontend/src/data-visualization/components/icon-group/field-list.ts create mode 100644 frontend/src/data-visualization/components/plugin/index.ts create mode 100644 frontend/src/data-visualization/components/plugin/src/PluginComponent.vue create mode 100644 frontend/src/data-visualization/components/plugin/src/convert.js create mode 100644 frontend/src/data-visualization/components/plugin/src/index.vue create mode 100644 frontend/src/data-visualization/components/plugin/src/nolic.vue create mode 100644 frontend/src/data-visualization/components/visualization/CanvasBaseSetting.vue create mode 100644 frontend/src/data-visualization/components/visualization/CanvasCacheDialog.vue create mode 100644 frontend/src/data-visualization/components/visualization/CanvasOptBar.vue create mode 100644 frontend/src/data-visualization/components/visualization/ComponentButton.vue create mode 100644 frontend/src/data-visualization/components/visualization/ComponentButtonLabel.vue create mode 100644 frontend/src/data-visualization/components/visualization/ComponentEditBar.vue create mode 100644 frontend/src/data-visualization/components/visualization/ComponentGroup.vue create mode 100644 frontend/src/data-visualization/components/visualization/ComponentSelector.vue create mode 100644 frontend/src/data-visualization/components/visualization/DatasetParamsComponent.vue create mode 100644 frontend/src/data-visualization/components/visualization/DatasetParamsSettingDialog.vue create mode 100644 frontend/src/data-visualization/components/visualization/DePreviewPopDialog.vue create mode 100644 frontend/src/data-visualization/components/visualization/DvSidebar.vue create mode 100644 frontend/src/data-visualization/components/visualization/EditMenu.vue create mode 100644 frontend/src/data-visualization/components/visualization/FieldsList.vue create mode 100644 frontend/src/data-visualization/components/visualization/HyperlinksDialog.vue create mode 100644 frontend/src/data-visualization/components/visualization/JumpSetOuterContentEditor.vue create mode 100644 frontend/src/data-visualization/components/visualization/LinkJumpSet.vue create mode 100644 frontend/src/data-visualization/components/visualization/LinkageSet.vue create mode 100644 frontend/src/data-visualization/components/visualization/LinkageSetOption.vue create mode 100644 frontend/src/data-visualization/components/visualization/OuterParamsSet.vue create mode 100644 frontend/src/data-visualization/components/visualization/SettingMenu.vue create mode 100644 frontend/src/data-visualization/components/visualization/StreamMediaLinks.vue create mode 100644 frontend/src/data-visualization/components/visualization/TabCarouselDialog.vue create mode 100644 frontend/src/data-visualization/components/visualization/UserViewEnlarge.vue create mode 100644 frontend/src/data-visualization/components/visualization/ViewTrackBar.vue create mode 100644 frontend/src/data-visualization/components/visualization/common/ComponentPosition.vue create mode 100644 frontend/src/data-visualization/components/visualization/common/DeFullscreen.vue create mode 100644 frontend/src/data-visualization/components/visualization/common/DeUpload.vue create mode 100644 frontend/src/data-visualization/components/visualization/common/DragInfo.vue create mode 100644 frontend/src/data-visualization/components/visualization/component-background/BackgroundItem.vue create mode 100644 frontend/src/data-visualization/components/visualization/component-background/BackgroundItemOverall.vue create mode 100644 frontend/src/data-visualization/components/visualization/component-background/BackgroundOverallCommon.vue create mode 100644 frontend/src/data-visualization/components/visualization/component-background/BoardItem.vue create mode 100644 frontend/src/data-visualization/components/visualization/component-background/BorderOptionPrefix.vue create mode 100644 frontend/src/data-visualization/components/visualization/component-background/CanvasBackground.vue create mode 100644 frontend/src/data-visualization/components/watermark/watermark.ts create mode 100644 frontend/src/data-visualization/config/axios/config.ts create mode 100644 frontend/src/data-visualization/config/axios/index.ts create mode 100644 frontend/src/data-visualization/config/axios/refresh.ts create mode 100644 frontend/src/data-visualization/config/axios/service.ts create mode 100644 frontend/src/data-visualization/custom-component/ImgViewDialog.vue create mode 100644 frontend/src/data-visualization/custom-component/canvas-board/Attr.vue create mode 100644 frontend/src/data-visualization/custom-component/canvas-board/Component.vue create mode 100644 frontend/src/data-visualization/custom-component/canvas-icon/Attr.vue create mode 100644 frontend/src/data-visualization/custom-component/canvas-icon/Component.vue create mode 100644 frontend/src/data-visualization/custom-component/circle-shape/Attr.vue create mode 100644 frontend/src/data-visualization/custom-component/circle-shape/Component.vue create mode 100644 frontend/src/data-visualization/custom-component/common/AsideCloseButton.vue create mode 100644 frontend/src/data-visualization/custom-component/common/CanvasGroup.vue create mode 100644 frontend/src/data-visualization/custom-component/common/CarouselSetting.vue create mode 100644 frontend/src/data-visualization/custom-component/common/CommonAttr.vue create mode 100644 frontend/src/data-visualization/custom-component/common/CommonBorderSetting.vue create mode 100644 frontend/src/data-visualization/custom-component/common/CommonEvent.vue create mode 100644 frontend/src/data-visualization/custom-component/common/CommonStyleSet.vue create mode 100644 frontend/src/data-visualization/custom-component/common/ComponentConfig.ts create mode 100644 frontend/src/data-visualization/custom-component/common/DeInputNum.vue create mode 100644 frontend/src/data-visualization/custom-component/common/DeRuler.vue create mode 100644 frontend/src/data-visualization/custom-component/common/DeRulerVertical.vue create mode 100644 frontend/src/data-visualization/custom-component/component-list.ts create mode 100644 frontend/src/data-visualization/custom-component/de-frame/Attr.vue create mode 100644 frontend/src/data-visualization/custom-component/de-frame/ComponentFrame.vue create mode 100644 frontend/src/data-visualization/custom-component/de-frame/FrameLinks.vue create mode 100644 frontend/src/data-visualization/custom-component/de-graphical/Attr.vue create mode 100644 frontend/src/data-visualization/custom-component/de-graphical/Component.vue create mode 100644 frontend/src/data-visualization/custom-component/de-stream-media/Attr.vue create mode 100644 frontend/src/data-visualization/custom-component/de-stream-media/Component.vue create mode 100644 frontend/src/data-visualization/custom-component/de-stream-media/StreamMediaLinks.vue create mode 100644 frontend/src/data-visualization/custom-component/de-tabs/Attr.vue create mode 100644 frontend/src/data-visualization/custom-component/de-tabs/Component.vue create mode 100644 frontend/src/data-visualization/custom-component/de-tabs/CustomTabsSort.vue create mode 100644 frontend/src/data-visualization/custom-component/de-tabs/DeCustomTab.vue create mode 100644 frontend/src/data-visualization/custom-component/de-tabs/DeFullTabs.vue create mode 100644 frontend/src/data-visualization/custom-component/de-tabs/TabBackgroundOverall.vue create mode 100644 frontend/src/data-visualization/custom-component/de-tabs/types.ts create mode 100644 frontend/src/data-visualization/custom-component/de-time-clock/Attr.vue create mode 100644 frontend/src/data-visualization/custom-component/de-time-clock/Component.vue create mode 100644 frontend/src/data-visualization/custom-component/de-time-clock/CustomAttr.vue create mode 100644 frontend/src/data-visualization/custom-component/de-time-clock/TimeClockFormat.vue create mode 100644 frontend/src/data-visualization/custom-component/de-time-clock/TimeDefault.vue create mode 100644 frontend/src/data-visualization/custom-component/de-video/Attr.vue create mode 100644 frontend/src/data-visualization/custom-component/de-video/Component.vue create mode 100644 frontend/src/data-visualization/custom-component/de-video/VideoLinks.vue create mode 100644 frontend/src/data-visualization/custom-component/group-area/Attr.vue create mode 100644 frontend/src/data-visualization/custom-component/group-area/Component.vue create mode 100644 frontend/src/data-visualization/custom-component/group-area/ComponentShadow.vue create mode 100644 frontend/src/data-visualization/custom-component/group/Attr.vue create mode 100644 frontend/src/data-visualization/custom-component/group/Component.vue create mode 100644 frontend/src/data-visualization/custom-component/group/GroupPreview.vue create mode 100644 frontend/src/data-visualization/custom-component/indicator/DeIndicator.vue create mode 100644 frontend/src/data-visualization/custom-component/picture-group/Attr.vue create mode 100644 frontend/src/data-visualization/custom-component/picture-group/Component.vue create mode 100644 frontend/src/data-visualization/custom-component/picture-group/PictureGroupDatasetSelect.vue create mode 100644 frontend/src/data-visualization/custom-component/picture-group/PictureGroupThreshold.vue create mode 100644 frontend/src/data-visualization/custom-component/picture-group/PictureGroupUploadAttr.vue create mode 100644 frontend/src/data-visualization/custom-component/picture-group/PictureItem.vue create mode 100644 frontend/src/data-visualization/custom-component/picture-group/PictureOptionPrefix.vue create mode 100644 frontend/src/data-visualization/custom-component/picture/Attr.vue create mode 100644 frontend/src/data-visualization/custom-component/picture/Component.vue create mode 100644 frontend/src/data-visualization/custom-component/pop-area/Attr.vue create mode 100644 frontend/src/data-visualization/custom-component/pop-area/Component.vue create mode 100644 frontend/src/data-visualization/custom-component/rect-shape/Attr.vue create mode 100644 frontend/src/data-visualization/custom-component/rect-shape/Component.vue create mode 100644 frontend/src/data-visualization/custom-component/rich-text/DeRichEditor.vue create mode 100644 frontend/src/data-visualization/custom-component/rich-text/DeRichTextView.vue create mode 100644 frontend/src/data-visualization/custom-component/rich-text/FieldsList.vue create mode 100644 frontend/src/data-visualization/custom-component/rich-text/plugins/index.ts create mode 100644 frontend/src/data-visualization/custom-component/rich-text/plugins/vertical-content.ts create mode 100644 frontend/src/data-visualization/custom-component/scroll-text/Attr.vue create mode 100644 frontend/src/data-visualization/custom-component/scroll-text/Component.vue create mode 100644 frontend/src/data-visualization/custom-component/svgs/svg-star/Attr.vue create mode 100644 frontend/src/data-visualization/custom-component/svgs/svg-star/Component.vue create mode 100644 frontend/src/data-visualization/custom-component/svgs/svg-triangle/Attr.vue create mode 100644 frontend/src/data-visualization/custom-component/svgs/svg-triangle/Component.vue create mode 100644 frontend/src/data-visualization/custom-component/user-view/Attr.vue create mode 100644 frontend/src/data-visualization/custom-component/user-view/Component.vue create mode 100644 frontend/src/data-visualization/custom-component/v-query/Attr.vue create mode 100644 frontend/src/data-visualization/custom-component/v-query/Component.vue create mode 100644 frontend/src/data-visualization/custom-component/v-query/ConditionDefaultConfiguration.vue create mode 100644 frontend/src/data-visualization/custom-component/v-query/CustomSortFilter.vue create mode 100644 frontend/src/data-visualization/custom-component/v-query/DynamicTime.vue create mode 100644 frontend/src/data-visualization/custom-component/v-query/DynamicTimeFiltering.vue create mode 100644 frontend/src/data-visualization/custom-component/v-query/DynamicTimeForViewFilter.vue create mode 100644 frontend/src/data-visualization/custom-component/v-query/DynamicTimeRange.vue create mode 100644 frontend/src/data-visualization/custom-component/v-query/DynamicTimeRangeFiltering.vue create mode 100644 frontend/src/data-visualization/custom-component/v-query/FilterTime.vue create mode 100644 frontend/src/data-visualization/custom-component/v-query/NumberInput.vue create mode 100644 frontend/src/data-visualization/custom-component/v-query/QueryCascade.vue create mode 100644 frontend/src/data-visualization/custom-component/v-query/QueryConditionConfiguration.vue create mode 100644 frontend/src/data-visualization/custom-component/v-query/RangeFilterTime.vue create mode 100644 frontend/src/data-visualization/custom-component/v-query/Select.vue create mode 100644 frontend/src/data-visualization/custom-component/v-query/StyleInject.vue create mode 100644 frontend/src/data-visualization/custom-component/v-query/TextSearch.vue create mode 100644 frontend/src/data-visualization/custom-component/v-query/Time.vue create mode 100644 frontend/src/data-visualization/custom-component/v-query/Tree.vue create mode 100644 frontend/src/data-visualization/custom-component/v-query/TreeFieldDialog.vue create mode 100644 frontend/src/data-visualization/custom-component/v-query/com-info.ts create mode 100644 frontend/src/data-visualization/custom-component/v-query/options.ts create mode 100644 frontend/src/data-visualization/custom-component/v-query/shortcuts.ts create mode 100644 frontend/src/data-visualization/custom-component/v-query/time-format-dayjs.ts create mode 100644 frontend/src/data-visualization/custom-component/v-query/time-format.ts create mode 100644 frontend/src/data-visualization/custom-component/v-text/Attr.vue create mode 100644 frontend/src/data-visualization/custom-component/v-text/Component.vue create mode 100644 frontend/src/data-visualization/guid/util.ts create mode 100644 frontend/src/data-visualization/hooks/web/useCache.ts create mode 100644 frontend/src/data-visualization/hooks/web/useEmitt.ts create mode 100644 frontend/src/data-visualization/hooks/web/useI18n.ts create mode 100644 frontend/src/data-visualization/locales/en.ts create mode 100644 frontend/src/data-visualization/locales/tw.ts create mode 100644 frontend/src/data-visualization/locales/zh-CN.ts create mode 100644 frontend/src/data-visualization/plugins/element-plus/index.ts create mode 100644 frontend/src/data-visualization/plugins/vue-i18n/helper.ts create mode 100644 frontend/src/data-visualization/plugins/vue-i18n/index.ts create mode 100644 frontend/src/data-visualization/store/index.ts create mode 100644 frontend/src/data-visualization/store/modules/app.ts create mode 100644 frontend/src/data-visualization/store/modules/appearance.ts create mode 100644 frontend/src/data-visualization/store/modules/data-visualization/common.ts create mode 100644 frontend/src/data-visualization/store/modules/data-visualization/compose.ts create mode 100644 frontend/src/data-visualization/store/modules/data-visualization/contextmenu.ts create mode 100644 frontend/src/data-visualization/store/modules/data-visualization/copy.ts create mode 100644 frontend/src/data-visualization/store/modules/data-visualization/dvMain.ts create mode 100644 frontend/src/data-visualization/store/modules/data-visualization/layer.ts create mode 100644 frontend/src/data-visualization/store/modules/data-visualization/lock.ts create mode 100644 frontend/src/data-visualization/store/modules/data-visualization/snapshot.ts create mode 100644 frontend/src/data-visualization/store/modules/embedded.ts create mode 100644 frontend/src/data-visualization/store/modules/link.ts create mode 100644 frontend/src/data-visualization/store/modules/locale.ts create mode 100644 frontend/src/data-visualization/store/modules/map.ts create mode 100644 frontend/src/data-visualization/store/modules/user.ts create mode 100644 frontend/src/data-visualization/style/custom-theme.css create mode 100644 frontend/src/data-visualization/style/index.less create mode 100644 frontend/src/data-visualization/style/mixin.less create mode 100644 frontend/src/data-visualization/style/variable.less create mode 100644 frontend/src/data-visualization/utils/DeShortcutKey.ts create mode 100644 frontend/src/data-visualization/utils/ModelUtil.ts create mode 100644 frontend/src/data-visualization/utils/attr.ts create mode 100644 frontend/src/data-visualization/utils/calculateComponentPositionAndSize.ts create mode 100644 frontend/src/data-visualization/utils/canvasStyle.ts create mode 100644 frontend/src/data-visualization/utils/canvasUtils.ts create mode 100644 frontend/src/data-visualization/utils/changeComponentsSizeWithScale.ts create mode 100644 frontend/src/data-visualization/utils/components.ts create mode 100644 frontend/src/data-visualization/utils/decomposeComponent.ts create mode 100644 frontend/src/data-visualization/utils/dvMain.ts create mode 100644 frontend/src/data-visualization/utils/eventBus.ts create mode 100644 frontend/src/data-visualization/utils/generateID.ts create mode 100644 frontend/src/data-visualization/utils/imgUtils.ts create mode 100644 frontend/src/data-visualization/utils/propTypes.ts create mode 100644 frontend/src/data-visualization/utils/style.ts create mode 100644 frontend/src/data-visualization/utils/timeUitils.ts create mode 100644 frontend/src/data-visualization/utils/translate.ts create mode 100644 frontend/src/data-visualization/utils/treeSortUtils.ts create mode 100644 frontend/src/data-visualization/utils/url.ts create mode 100644 frontend/src/data-visualization/utils/utils.ts create mode 100644 frontend/src/data-visualization/utils/viewUtils.ts create mode 100644 frontend/src/locales/en.ts create mode 100644 frontend/src/locales/tw.ts create mode 100644 frontend/src/locales/zh-CN.ts create mode 100644 frontend/src/types/form-create.d.ts create mode 100644 frontend/src/utils/attr.ts create mode 100644 frontend/types/data-visualization/base.d.ts create mode 100644 frontend/types/global.d.ts create mode 100644 frontend/types/localeDropdown.d.ts create mode 100644 frontend/types/router.d.ts create mode 100644 frontend/types/vite-env.d.ts diff --git a/frontend/auto-imports.d.ts b/frontend/auto-imports.d.ts new file mode 100644 index 0000000..918aad8 --- /dev/null +++ b/frontend/auto-imports.d.ts @@ -0,0 +1,8 @@ +/* eslint-disable */ +/* prettier-ignore */ +// @ts-nocheck +// Generated by unplugin-auto-import +export {} +declare global { + +} diff --git a/frontend/components.d.ts b/frontend/components.d.ts new file mode 100644 index 0000000..d8da8b6 --- /dev/null +++ b/frontend/components.d.ts @@ -0,0 +1,63 @@ +/* eslint-disable */ +/* prettier-ignore */ +// @ts-nocheck +// Generated by unplugin-vue-components +// Read more: https://github.com/vuejs/core/pull/3399 +import '@vue/runtime-core' + +export {} + +declare module '@vue/runtime-core' { + export interface GlobalComponents { + ElBreadcrumb: typeof import('element-plus-secondary/es')['ElBreadcrumb'] + ElBreadcrumbItem: typeof import('element-plus-secondary/es')['ElBreadcrumbItem'] + ElButton: typeof import('element-plus-secondary/es')['ElButton'] + ElCard: typeof import('element-plus-secondary/es')['ElCard'] + ElCheckbox: typeof import('element-plus-secondary/es')['ElCheckbox'] + ElCheckboxGroup: typeof import('element-plus-secondary/es')['ElCheckboxGroup'] + ElCol: typeof import('element-plus-secondary/es')['ElCol'] + ElCollapse: typeof import('element-plus-secondary/es')['ElCollapse'] + ElCollapseItem: typeof import('element-plus-secondary/es')['ElCollapseItem'] + ElColorPicker: typeof import('element-plus-secondary/es')['ElColorPicker'] + ElContainer: typeof import('element-plus-secondary/es')['ElContainer'] + ElDatePicker: typeof import('element-plus-secondary/es')['ElDatePicker'] + ElDialog: typeof import('element-plus-secondary/es')['ElDialog'] + ElDivider: typeof import('element-plus-secondary/es')['ElDivider'] + ElDropdown: typeof import('element-plus-secondary/es')['ElDropdown'] + ElDropdownItem: typeof import('element-plus-secondary/es')['ElDropdownItem'] + ElDropdownMenu: typeof import('element-plus-secondary/es')['ElDropdownMenu'] + ElEmpty: typeof import('element-plus-secondary/es')['ElEmpty'] + ElForm: typeof import('element-plus-secondary/es')['ElForm'] + ElFormItem: typeof import('element-plus-secondary/es')['ElFormItem'] + ElHeader: typeof import('element-plus-secondary/es')['ElHeader'] + ElIcon: typeof import('element-plus-secondary/es')['ElIcon'] + ElInput: typeof import('element-plus-secondary/es')['ElInput'] + ElInputNumber: typeof import('element-plus-secondary/es')['ElInputNumber'] + ElMain: typeof import('element-plus-secondary/es')['ElMain'] + ElOption: typeof import('element-plus-secondary/es')['ElOption'] + ElOptionGroup: typeof import('element-plus-secondary/es')['ElOptionGroup'] + ElPopover: typeof import('element-plus-secondary/es')['ElPopover'] + ElRadio: typeof import('element-plus-secondary/es')['ElRadio'] + ElRadioGroup: typeof import('element-plus-secondary/es')['ElRadioGroup'] + ElRow: typeof import('element-plus-secondary/es')['ElRow'] + ElScrollbar: typeof import('element-plus-secondary/es')['ElScrollbar'] + ElSelect: typeof import('element-plus-secondary/es')['ElSelect'] + ElSelectV2: typeof import('element-plus-secondary/es')['ElSelectV2'] + ElSpace: typeof import('element-plus-secondary/es')['ElSpace'] + ElSwitch: typeof import('element-plus-secondary/es')['ElSwitch'] + ElTabPane: typeof import('element-plus-secondary/es')['ElTabPane'] + ElTabs: typeof import('element-plus-secondary/es')['ElTabs'] + ElTimeline: typeof import('element-plus-secondary/es')['ElTimeline'] + ElTimelineItem: typeof import('element-plus-secondary/es')['ElTimelineItem'] + ElTimePicker: typeof import('element-plus-secondary/es')['ElTimePicker'] + ElTooltip: typeof import('element-plus-secondary/es')['ElTooltip'] + ElTree: typeof import('element-plus-secondary/es')['ElTree'] + ElTreeSelect: typeof import('element-plus-secondary/es')['ElTreeSelect'] + ElUpload: typeof import('element-plus-secondary/es')['ElUpload'] + RouterLink: typeof import('vue-router')['RouterLink'] + RouterView: typeof import('vue-router')['RouterView'] + } + export interface ComponentCustomProperties { + vLoading: typeof import('element-plus-secondary/es')['ElLoadingDirective'] + } +} diff --git a/frontend/frontend.code-workspace b/frontend/frontend.code-workspace new file mode 100644 index 0000000..362d7c2 --- /dev/null +++ b/frontend/frontend.code-workspace @@ -0,0 +1,7 @@ +{ + "folders": [ + { + "path": "." + } + ] +} \ No newline at end of file diff --git a/frontend/package.json b/frontend/package.json index 8f1d584..d982475 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -11,27 +11,73 @@ "format": "prettier --write src/" }, "dependencies": { + "video.js": "^7.21.6", + "@videojs-player/vue": "^1.0.0", + "@vueuse/core": "^9.13.0", + "@npkg/tinymce-plugins": "^0.0.7", + "dayjs": "^1.11.9", + "flv.js": "^1.6.2", + "html2canvas": "^1.4.1", + "jspdf": "^2.5.1", + "html-to-image": "^1.11.11", + "echarts": "^5.5.1", + "file-saver": "^2.0.5", + "lodash": "^4.17.21", + "lodash-es": "^4.17.21", + "mathjs": "^11.6.0", + "@antv/g2plot": "^2.4.29", + "@antv/l7": "^2.22.0", + "@antv/l7plot": "^0.5.5", + "@antv/s2": "^1.49.0", + "vue-i18n": "^9.2.2", "@element-plus/icons-vue": "^2.3.1", "@form-create/designer": "^1.1.9", "@form-create/element-ui": "^3.2.22", "@form-create/vant": "^3.2.24", + "@turf/centroid": "^7.0.0", + "@tinymce/tinymce-vue": "^5.1.0", + "tinymce": "^5.8.2", "axios": "^1.6.0", + "consola": "^3.4.2", "element-plus": "^2.4.4", + "element-plus-secondary": "^0.6.8", + "element-resize-detector": "^1.2.4", + "vuedraggable": "^4.1.0", + "exceljs": "^4.4.0", + "js-base64": "^3.7.5", + "mitt": "^3.0.0", + "path": "^0.12.7", "pinia": "^2.1.7", + "qs": "^6.11.0", + "screenfull": "^6.0.2", + "snowflake-id": "^1.1.0", "vant": "^4.9.19", - "vue": "^3.4.0", - "vue-router": "^4.2.5" + "vue": "^3.3.4", + "vue-router": "^4.2.5", + "web-storage-cache": "^1.1.1", + "vue-types": "^5.0.2" }, "devDependencies": { + + "@intlify/unplugin-vue-i18n": "^0.8.2", "@rushstack/eslint-patch": "^1.3.3", "@vitejs/plugin-vue": "^4.5.2", + "@vitejs/plugin-vue-jsx": "^4.2.0", "@vue/eslint-config-prettier": "^8.0.0", + "less": "^4.1.3", + "jquery": "^3.6.4", "eslint": "^8.49.0", "eslint-plugin-vue": "^9.17.0", "prettier": "^3.0.3", "sass": "^1.89.0", "sass-loader": "^16.0.5", - "vite": "^5.0.8" + "typescript": "^5.8.3", + "unplugin-auto-import": "^0.15.1", + "unplugin-vue-components-secondary": "^0.24.6", + "vite": "^5.0.8", + "vite-plugin-style-import-secondary": "^2.0.0", + "consola": "^2.15.3", + "vite-svg-loader": "^5.1.0" }, "engines": { "node": ">=16.0.0", diff --git a/frontend/public/dataease.svg b/frontend/public/dataease.svg new file mode 100644 index 0000000..741ca75 --- /dev/null +++ b/frontend/public/dataease.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/frontend/public/images/code.png b/frontend/public/images/code.png new file mode 100644 index 0000000000000000000000000000000000000000..33e52dd92359b7b59e47524a9c112643503873a0 GIT binary patch literal 316 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%0D&7LZttGF>m{70oMK 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

*5J%fZDLyHgU;EbeVnjiO6!CDfz(-edtTN`I;Jg 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%0AV4D$Zm{ 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 literal 0 HcmV?d00001 diff --git a/frontend/public/images/loginform.png b/frontend/public/images/loginform.png new file mode 100644 index 0000000000000000000000000000000000000000..143299e4be131e3ec1d06749a03e48b468e6e141 GIT binary patch literal 9394 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 Cbok-` literal 0 HcmV?d00001 diff --git a/frontend/public/images/navbg.png b/frontend/public/images/navbg.png new file mode 100644 index 0000000000000000000000000000000000000000..5fd47ac4e02cf6835811d62dfec4025a9e61a2de GIT binary patch literal 4129 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 b$8Ws08CH8$CYdGz!;!($)z4*}Q$iB}+%%-2 literal 0 HcmV?d00001 diff --git a/frontend/public/images/navmenucheck.png b/frontend/public/images/navmenucheck.png new file mode 100644 index 0000000000000000000000000000000000000000..43b0e9c01a9afec1f9645fc4647a9952bb35a6ca GIT binary patch literal 370 zcmeAS@N?(olHy`uVBq!ia0vp^@jxuk!3HE7MFeL8Db50q$YKTtZXpn6ymYtj4+8_E zil>WXNJit^TN}L&2Qaig{I6zSTAb^l&*XV@(cxIW{}VJHF4D-GY5B6`({7W$2gFi$m)UjgPQ5vM zKkud-){6YP;OsA1&sRt6zo~ip^JxirDY+|Z)nBL2Sf07jZtlJ{PKI2GYoe|S^>2Qz z_Ca*Ts`LjE60gj*o|C-be?|M&nUAe9@h34nJa0`Jj~eHJz+2FqS77%cG3&p?quJ91 zP87-)u!l^FIKU`-;YI}uTf(mZ&sp2ug04tie0J|vYNA1+{>kXwlH%XEtc7{Hj~e(* zx^+f2ZF%0B_tTf9$IR|L+_r)zt?CX(3jbo2cu%PY?hg^J``Xz34(wICd$su4M`;-W zhUvD)oYI4@{gXK-FJ?An>8!0+mP|Rf;3=* z^*mi1Lo9mVp4-UFpuoYf;n9EbiZvCioGL!C(la?9S#exDSY{C-<*}!9k1U^RU6{a{ V*(ahJ9szYSc)I$ztaD0e0szw^B254Q literal 0 HcmV?d00001 diff --git a/frontend/public/images/splitline2.png b/frontend/public/images/splitline2.png new file mode 100644 index 0000000000000000000000000000000000000000..a7571060400d9f629b155648527433c71527f071 GIT binary patch literal 120 zcmeAS@N?(olHy`uVBq!ia0y~yU;3=* zwLD!MLo9le|NQ@N&n#k~bg^ggAH|dMJb4RL<=OrzKMeeL;Tb=hdB9YDhUC1)|3yox R;()psJYD@<);T3K0RW>7BDDYj literal 0 HcmV?d00001 diff --git a/frontend/public/images/titleline.png b/frontend/public/images/titleline.png new file mode 100644 index 0000000000000000000000000000000000000000..68928bc085f195cec1c272af69297c1dfce9aed2 GIT binary patch literal 234 zcmeAS@N?(olHy`uVBq!ia0y~yV4MhKvv9BhN&ml0!a$0%z$3Dlfq`2Hgc&d0t@{HM zoa5=@7!uL?cIrjW1_K_K_@j<@j)cnG?0wbly5vF_%ju=h>ZB%p{-o8^C}Ez!DZsou ztJF&V>e@B;tliFSJ+p2?_RLtt>qfhs)}?-vywNb#SYcV@+Pt&(tE%5f++2Mu`78nl z&%ST#vm-`t`suGh#v7LJ`m+4w?@ImpWmm#)7#h6~x4!c3=BZElTlwF|zq{Fe{g(C4 a5{AtpwzqTkiHZQ-$>8bg=d#Wzp$PyZ6=YTb literal 0 HcmV?d00001 diff --git a/frontend/public/images/username.png b/frontend/public/images/username.png new file mode 100644 index 0000000000000000000000000000000000000000..00dc875a1ee3dec5b27616c5270cf3d292218b4a GIT binary patch literal 332 zcmV-S0ki&zP)5lc90LKoCWrJqBSG3=|BDN)QbbNC9rZGcG|TWKw}j z2n=)yf`+Ofxv;Qr;5~c2lI&z>b|l^XcX#{uw2;I^6u=Yk03_f5{Ek$TV!mk{Nzx{2 z=fJ_lwWQWyNowZc(t$--v~qKk@WuqYiBgc%*?g79mahELp8b@Az~IaTxPmj(%)m|1 zjSS1iL}yzY-`{e(aqa2N{ob{!^!imeS_S+7Yv9>3&JX7=Tcrp)wASOC-Q_^);;}zm zO|i$m*Lj0B!?mk%4)hl(Sw8w*>pNg{{&gWKar$#g{uTxB4ZJVS+2N-AI#PaF0bAhn eA27fR@O1<=L<+XMRjUU80000 + + + + diff --git a/frontend/public/svg/icon_data-visualization.svg b/frontend/public/svg/icon_data-visualization.svg new file mode 100644 index 0000000..8303575 --- /dev/null +++ b/frontend/public/svg/icon_data-visualization.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/frontend/public/svg/icon_database.svg b/frontend/public/svg/icon_database.svg new file mode 100644 index 0000000..b07810e --- /dev/null +++ b/frontend/public/svg/icon_database.svg @@ -0,0 +1,4 @@ + + + + diff --git a/frontend/public/svg/icon_dataset.svg b/frontend/public/svg/icon_dataset.svg new file mode 100644 index 0000000..da26700 --- /dev/null +++ b/frontend/public/svg/icon_dataset.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/frontend/public/svg/relation-dataset.svg b/frontend/public/svg/relation-dataset.svg new file mode 100644 index 0000000..c31cfd3 --- /dev/null +++ b/frontend/public/svg/relation-dataset.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/frontend/public/svg/relation-ds.svg b/frontend/public/svg/relation-ds.svg new file mode 100644 index 0000000..d5073da --- /dev/null +++ b/frontend/public/svg/relation-ds.svg @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + diff --git a/frontend/public/svg/relation-panel.svg b/frontend/public/svg/relation-panel.svg new file mode 100644 index 0000000..090c1f4 --- /dev/null +++ b/frontend/public/svg/relation-panel.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/frontend/public/svg/relation-screen.svg b/frontend/public/svg/relation-screen.svg new file mode 100644 index 0000000..5b302b4 --- /dev/null +++ b/frontend/public/svg/relation-screen.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/frontend/public/tinymce-dataease-private/langs/zh_CN.js b/frontend/public/tinymce-dataease-private/langs/zh_CN.js new file mode 100644 index 0000000..64f2997 --- /dev/null +++ b/frontend/public/tinymce-dataease-private/langs/zh_CN.js @@ -0,0 +1,423 @@ +tinymce.addI18n('zh_CN', { + "Redo": "\u91cd\u505a", + "Undo": "\u64a4\u9500", + "Cut": "\u526a\u5207", + "Copy": "\u590d\u5236", + "Paste": "\u7c98\u8d34", + "Select all": "\u5168\u9009", + "New document": "\u65b0\u6587\u4ef6", + "Ok": "\u786e\u5b9a", + "Cancel": "\u53d6\u6d88", + "Visual aids": "\u7f51\u683c\u7ebf", + "Bold": "\u7c97\u4f53", + "Italic": "\u659c\u4f53", + "Underline": "\u4e0b\u5212\u7ebf", + "Strikethrough": "\u5220\u9664\u7ebf", + "Superscript": "\u4e0a\u6807", + "Subscript": "\u4e0b\u6807", + "Clear formatting": "\u6e05\u9664\u683c\u5f0f", + "Align left": "\u5de6\u8fb9\u5bf9\u9f50", + "Align center": "\u4e2d\u95f4\u5bf9\u9f50", + "Align right": "\u53f3\u8fb9\u5bf9\u9f50", + "Justify": "\u4e24\u7aef\u5bf9\u9f50", + "Bullet list": "\u9879\u76ee\u7b26\u53f7", + "Numbered list": "\u7f16\u53f7\u5217\u8868", + "Decrease indent": "\u51cf\u5c11\u7f29\u8fdb", + "Increase indent": "\u589e\u52a0\u7f29\u8fdb", + "Close": "\u5173\u95ed", + "Formats": "\u683c\u5f0f", + "Your browser doesn't support direct access to the clipboard. Please use the Ctrl+X\/C\/V keyboard shortcuts instead.": "\u4f60\u7684\u6d4f\u89c8\u5668\u4e0d\u652f\u6301\u6253\u5f00\u526a\u8d34\u677f\uff0c\u8bf7\u4f7f\u7528Ctrl+X\/C\/V\u7b49\u5feb\u6377\u952e\u3002", + "Headers": "\u6807\u9898", + "Header 1": "\u6807\u98981", + "Header 2": "\u6807\u98982", + "Header 3": "\u6807\u98983", + "Header 4": "\u6807\u98984", + "Header 5": "\u6807\u98985", + "Header 6": "\u6807\u98986", + "Headings": "\u6807\u9898", + "Heading 1": "\u6807\u98981", + "Heading 2": "\u6807\u98982", + "Heading 3": "\u6807\u98983", + "Heading 4": "\u6807\u98984", + "Heading 5": "\u6807\u98985", + "Heading 6": "\u6807\u98986", + "Preformatted": "\u9884\u5148\u683c\u5f0f\u5316\u7684", + "Div": "Div", + "Pre": "Pre", + "Code": "\u4ee3\u7801", + "Paragraph": "\u6bb5\u843d", + "Blockquote": "\u5f15\u6587\u533a\u5757", + "Inline": "\u6587\u672c", + "Blocks": "\u57fa\u5757", + "Paste is now in plain text mode. Contents will now be pasted as plain text until you toggle this option off.": "\u5f53\u524d\u4e3a\u7eaf\u6587\u672c\u7c98\u8d34\u6a21\u5f0f\uff0c\u518d\u6b21\u70b9\u51fb\u53ef\u4ee5\u56de\u5230\u666e\u901a\u7c98\u8d34\u6a21\u5f0f\u3002", + "Fonts": "\u5b57\u4f53", + "Font Sizes": "\u5b57\u53f7", + "Class": "\u7c7b\u578b", + "Browse for an image": "\u6d4f\u89c8\u56fe\u50cf", + "OR": "\u6216", + "Drop an image here": "\u62d6\u653e\u4e00\u5f20\u56fe\u50cf\u81f3\u6b64", + "Upload": "\u4e0a\u4f20", + "Block": "\u5757", + "Align": "\u5bf9\u9f50", + "Default": "\u9ed8\u8ba4", + "Circle": "\u7a7a\u5fc3\u5706", + "Disc": "\u5b9e\u5fc3\u5706", + "Square": "\u65b9\u5757", + "Lower Alpha": "\u5c0f\u5199\u82f1\u6587\u5b57\u6bcd", + "Lower Greek": "\u5c0f\u5199\u5e0c\u814a\u5b57\u6bcd", + "Lower Roman": "\u5c0f\u5199\u7f57\u9a6c\u5b57\u6bcd", + "Upper Alpha": "\u5927\u5199\u82f1\u6587\u5b57\u6bcd", + "Upper Roman": "\u5927\u5199\u7f57\u9a6c\u5b57\u6bcd", + "Anchor...": "\u951a\u70b9...", + "Name": "\u540d\u79f0", + "Id": "\u6807\u8bc6\u7b26", + "Id should start with a letter, followed only by letters, numbers, dashes, dots, colons or underscores.": "\u6807\u8bc6\u7b26\u5e94\u8be5\u4ee5\u5b57\u6bcd\u5f00\u5934\uff0c\u540e\u8ddf\u5b57\u6bcd\u3001\u6570\u5b57\u3001\u7834\u6298\u53f7\u3001\u70b9\u3001\u5192\u53f7\u6216\u4e0b\u5212\u7ebf\u3002", + "You have unsaved changes are you sure you want to navigate away?": "\u4f60\u8fd8\u6709\u6587\u6863\u5c1a\u672a\u4fdd\u5b58\uff0c\u786e\u5b9a\u8981\u79bb\u5f00\uff1f", + "Restore last draft": "\u6062\u590d\u4e0a\u6b21\u7684\u8349\u7a3f", + "Special character...": "\u7279\u6b8a\u5b57\u7b26...", + "Source code": "\u6e90\u4ee3\u7801", + "Insert\/Edit code sample": "\u63d2\u5165\/\u7f16\u8f91\u4ee3\u7801\u793a\u4f8b", + "Language": "\u8bed\u8a00", + "Code sample...": "\u793a\u4f8b\u4ee3\u7801...", + "Color Picker": "\u9009\u8272\u5668", + "R": "R", + "G": "G", + "B": "B", + "Left to right": "\u4ece\u5de6\u5230\u53f3", + "Right to left": "\u4ece\u53f3\u5230\u5de6", + "Emoticons...": "\u8868\u60c5\u7b26\u53f7...", + "Metadata and Document Properties": "\u5143\u6570\u636e\u548c\u6587\u6863\u5c5e\u6027", + "Title": "\u6807\u9898", + "Keywords": "\u5173\u952e\u8bcd", + "Description": "\u63cf\u8ff0", + "Robots": "\u673a\u5668\u4eba", + "Author": "\u4f5c\u8005", + "Encoding": "\u7f16\u7801", + "Fullscreen": "\u5168\u5c4f", + "Action": "\u64cd\u4f5c", + "Shortcut": "\u5feb\u6377\u952e", + "Help": "\u5e2e\u52a9", + "Address": "\u5730\u5740", + "Focus to menubar": "\u79fb\u52a8\u7126\u70b9\u5230\u83dc\u5355\u680f", + "Focus to toolbar": "\u79fb\u52a8\u7126\u70b9\u5230\u5de5\u5177\u680f", + "Focus to element path": "\u79fb\u52a8\u7126\u70b9\u5230\u5143\u7d20\u8def\u5f84", + "Focus to contextual toolbar": "\u79fb\u52a8\u7126\u70b9\u5230\u4e0a\u4e0b\u6587\u83dc\u5355", + "Insert link (if link plugin activated)": "\u63d2\u5165\u94fe\u63a5 (\u5982\u679c\u94fe\u63a5\u63d2\u4ef6\u5df2\u6fc0\u6d3b)", + "Save (if save plugin activated)": "\u4fdd\u5b58(\u5982\u679c\u4fdd\u5b58\u63d2\u4ef6\u5df2\u6fc0\u6d3b)", + "Find (if searchreplace plugin activated)": "\u67e5\u627e(\u5982\u679c\u67e5\u627e\u66ff\u6362\u63d2\u4ef6\u5df2\u6fc0\u6d3b)", + "Plugins installed ({0}):": "\u5df2\u5b89\u88c5\u63d2\u4ef6 ({0}):", + "Premium plugins:": "\u4f18\u79c0\u63d2\u4ef6\uff1a", + "Learn more...": "\u4e86\u89e3\u66f4\u591a...", + "You are using {0}": "\u4f60\u6b63\u5728\u4f7f\u7528 {0}", + "Plugins": "\u63d2\u4ef6", + "Handy Shortcuts": "\u5feb\u6377\u952e", + "Horizontal line": "\u6c34\u5e73\u5206\u5272\u7ebf", + "Insert\/edit image": "\u63d2\u5165\/\u7f16\u8f91\u56fe\u7247", + "Image description": "\u56fe\u7247\u63cf\u8ff0", + "Source": "\u5730\u5740", + "Dimensions": "\u5927\u5c0f", + "Constrain proportions": "\u4fdd\u6301\u7eb5\u6a2a\u6bd4", + "General": "\u666e\u901a", + "Advanced": "\u9ad8\u7ea7", + "Style": "\u6837\u5f0f", + "Vertical space": "\u5782\u76f4\u8fb9\u8ddd", + "Horizontal space": "\u6c34\u5e73\u8fb9\u8ddd", + "Border": "\u8fb9\u6846", + "Insert image": "\u63d2\u5165\u56fe\u7247", + "Image...": "\u56fe\u7247...", + "Image list": "\u56fe\u7247\u5217\u8868", + "Rotate counterclockwise": "\u9006\u65f6\u9488\u65cb\u8f6c", + "Rotate clockwise": "\u987a\u65f6\u9488\u65cb\u8f6c", + "Flip vertically": "\u5782\u76f4\u7ffb\u8f6c", + "Flip horizontally": "\u6c34\u5e73\u7ffb\u8f6c", + "Edit image": "\u7f16\u8f91\u56fe\u7247", + "Image options": "\u56fe\u7247\u9009\u9879", + "Zoom in": "\u653e\u5927", + "Zoom out": "\u7f29\u5c0f", + "Crop": "\u88c1\u526a", + "Resize": "\u8c03\u6574\u5927\u5c0f", + "Orientation": "\u65b9\u5411", + "Brightness": "\u4eae\u5ea6", + "Sharpen": "\u9510\u5316", + "Contrast": "\u5bf9\u6bd4\u5ea6", + "Color levels": "\u989c\u8272\u5c42\u6b21", + "Gamma": "\u4f3d\u9a6c\u503c", + "Invert": "\u53cd\u8f6c", + "Apply": "\u5e94\u7528", + "Back": "\u540e\u9000", + "Insert date\/time": "\u63d2\u5165\u65e5\u671f\/\u65f6\u95f4", + "Date\/time": "\u65e5\u671f\/\u65f6\u95f4", + "Insert\/Edit Link": "\u63d2\u5165\/\u7f16\u8f91\u94fe\u63a5", + "Insert\/edit link": "\u63d2\u5165\/\u7f16\u8f91\u94fe\u63a5", + "Text to display": "\u663e\u793a\u6587\u5b57", + "Url": "\u5730\u5740", + "Open link in...": "\u94fe\u63a5\u6253\u5f00\u4f4d\u7f6e...", + "Current window": "\u5f53\u524d\u7a97\u53e3", + "None": "\u65e0", + "New window": "\u5728\u65b0\u7a97\u53e3\u6253\u5f00", + "Remove link": "\u5220\u9664\u94fe\u63a5", + "Anchors": "\u951a\u70b9", + "Link...": "\u94fe\u63a5...", + "Paste or type a link": "\u7c98\u8d34\u6216\u8f93\u5165\u94fe\u63a5", + "The URL you entered seems to be an email address. Do you want to add the required mailto: prefix?": "\u4f60\u6240\u586b\u5199\u7684URL\u5730\u5740\u4e3a\u90ae\u4ef6\u5730\u5740\uff0c\u9700\u8981\u52a0\u4e0amailto:\u524d\u7f00\u5417\uff1f", + "The URL you entered seems to be an external link. Do you want to add the required http:\/\/ prefix?": "\u4f60\u6240\u586b\u5199\u7684URL\u5730\u5740\u5c5e\u4e8e\u5916\u90e8\u94fe\u63a5\uff0c\u9700\u8981\u52a0\u4e0ahttp:\/\/:\u524d\u7f00\u5417\uff1f", + "Link list": "\u94fe\u63a5\u5217\u8868", + "Insert video": "\u63d2\u5165\u89c6\u9891", + "Insert\/edit video": "\u63d2\u5165\/\u7f16\u8f91\u89c6\u9891", + "Insert\/edit media": "\u63d2\u5165\/\u7f16\u8f91\u5a92\u4f53", + "Alternative source": "\u955c\u50cf", + "Alternative source URL": "\u66ff\u4ee3\u6765\u6e90\u7f51\u5740", + "Media poster (Image URL)": "\u5c01\u9762(\u56fe\u7247\u5730\u5740)", + "Paste your embed code below:": "\u5c06\u5185\u5d4c\u4ee3\u7801\u7c98\u8d34\u5728\u4e0b\u9762:", + "Embed": "\u5185\u5d4c", + "Media...": "\u591a\u5a92\u4f53...", + "Nonbreaking space": "\u4e0d\u95f4\u65ad\u7a7a\u683c", + "Page break": "\u5206\u9875\u7b26", + "Paste as text": "\u7c98\u8d34\u4e3a\u6587\u672c", + "Preview": "\u9884\u89c8", + "Print...": "\u6253\u5370...", + "Save": "\u4fdd\u5b58", + "Find": "\u67e5\u627e", + "Replace with": "\u66ff\u6362\u4e3a", + "Replace": "\u66ff\u6362", + "Replace all": "\u5168\u90e8\u66ff\u6362", + "Previous": "\u4e0a\u4e00\u4e2a", + "Next": "\u4e0b\u4e00\u4e2a", + "Find and replace...": "\u67e5\u627e\u5e76\u66ff\u6362...", + "Could not find the specified string.": "\u672a\u627e\u5230\u641c\u7d22\u5185\u5bb9.", + "Match case": "\u533a\u5206\u5927\u5c0f\u5199", + "Find whole words only": "\u5168\u5b57\u5339\u914d", + "Spell check": "\u62fc\u5199\u68c0\u67e5", + "Ignore": "\u5ffd\u7565", + "Ignore all": "\u5168\u90e8\u5ffd\u7565", + "Finish": "\u5b8c\u6210", + "Add to Dictionary": "\u6dfb\u52a0\u5230\u5b57\u5178", + "Insert table": "\u63d2\u5165\u8868\u683c", + "Table properties": "\u8868\u683c\u5c5e\u6027", + "Delete table": "\u5220\u9664\u8868\u683c", + "Cell": "\u5355\u5143\u683c", + "Row": "\u884c", + "Column": "\u5217", + "Cell properties": "\u5355\u5143\u683c\u5c5e\u6027", + "Merge cells": "\u5408\u5e76\u5355\u5143\u683c", + "Split cell": "\u62c6\u5206\u5355\u5143\u683c", + "Insert row before": "\u5728\u4e0a\u65b9\u63d2\u5165", + "Insert row after": "\u5728\u4e0b\u65b9\u63d2\u5165", + "Delete row": "\u5220\u9664\u884c", + "Row properties": "\u884c\u5c5e\u6027", + "Cut row": "\u526a\u5207\u884c", + "Copy row": "\u590d\u5236\u884c", + "Paste row before": "\u7c98\u8d34\u5230\u4e0a\u65b9", + "Paste row after": "\u7c98\u8d34\u5230\u4e0b\u65b9", + "Insert column before": "\u5728\u5de6\u4fa7\u63d2\u5165", + "Insert column after": "\u5728\u53f3\u4fa7\u63d2\u5165", + "Delete column": "\u5220\u9664\u5217", + "Cols": "\u5217", + "Rows": "\u884c", + "Width": "\u5bbd", + "Height": "\u9ad8", + "Cell spacing": "\u5355\u5143\u683c\u5916\u95f4\u8ddd", + "Cell padding": "\u5355\u5143\u683c\u5185\u8fb9\u8ddd", + "Show caption": "\u663e\u793a\u6807\u9898", + "Left": "\u5de6\u5bf9\u9f50", + "Center": "\u5c45\u4e2d", + "Right": "\u53f3\u5bf9\u9f50", + "Cell type": "\u5355\u5143\u683c\u7c7b\u578b", + "Scope": "\u8303\u56f4", + "Alignment": "\u5bf9\u9f50\u65b9\u5f0f", + "H Align": "\u6c34\u5e73\u5bf9\u9f50", + "V Align": "\u5782\u76f4\u5bf9\u9f50", + "Top": "\u9876\u90e8\u5bf9\u9f50", + "Middle": "\u5782\u76f4\u5c45\u4e2d", + "Bottom": "\u5e95\u90e8\u5bf9\u9f50", + "Header cell": "\u8868\u5934\u5355\u5143\u683c", + "Row group": "\u884c\u7ec4", + "Column group": "\u5217\u7ec4", + "Row type": "\u884c\u7c7b\u578b", + "Header": "\u8868\u5934", + "Body": "\u8868\u4f53", + "Footer": "\u8868\u5c3e", + "Border color": "\u8fb9\u6846\u989c\u8272", + "Insert template...": "\u63d2\u5165\u6a21\u677f...", + "Templates": "\u6a21\u677f", + "Template": "\u6a21\u677f", + "Text color": "\u6587\u5b57\u989c\u8272", + "Background color": "\u80cc\u666f\u8272", + "Custom...": "\u81ea\u5b9a\u4e49...", + "Custom color": "\u81ea\u5b9a\u4e49\u989c\u8272", + "No color": "\u65e0", + "Remove color": "\u79fb\u9664\u989c\u8272", + "Table of Contents": "\u5185\u5bb9\u5217\u8868", + "Show blocks": "\u663e\u793a\u533a\u5757\u8fb9\u6846", + "Show invisible characters": "\u663e\u793a\u4e0d\u53ef\u89c1\u5b57\u7b26", + "Word count": "\u5b57\u6570", + "Count": "\u8ba1\u6570", + "Document": "\u6587\u6863", + "Selection": "\u9009\u62e9", + "Words": "\u5355\u8bcd", + "Words: {0}": "\u5b57\u6570\uff1a{0}", + "{0} words": "{0} \u5b57", + "File": "\u6587\u4ef6", + "Edit": "\u7f16\u8f91", + "Insert": "\u63d2\u5165", + "View": "\u89c6\u56fe", + "Format": "\u683c\u5f0f", + "Table": "\u8868\u683c", + "Tools": "\u5de5\u5177", + "Powered by {0}": "\u7531{0}\u9a71\u52a8", + "Rich Text Area. Press ALT-F9 for menu. Press ALT-F10 for toolbar. Press ALT-0 for help": "\u5728\u7f16\u8f91\u533a\u6309ALT-F9\u6253\u5f00\u83dc\u5355\uff0c\u6309ALT-F10\u6253\u5f00\u5de5\u5177\u680f\uff0c\u6309ALT-0\u67e5\u770b\u5e2e\u52a9", + "Image title": "\u56fe\u7247\u6807\u9898", + "Border width": "\u8fb9\u6846\u5bbd\u5ea6", + "Border style": "\u8fb9\u6846\u6837\u5f0f", + "Error": "\u9519\u8bef", + "Warn": "\u8b66\u544a", + "Valid": "\u6709\u6548", + "To open the popup, press Shift+Enter": "\u6309Shitf+Enter\u952e\u6253\u5f00\u5bf9\u8bdd\u6846", + "Rich Text Area. Press ALT-0 for help.": "\u7f16\u8f91\u533a\u3002\u6309Alt+0\u952e\u6253\u5f00\u5e2e\u52a9\u3002", + "System Font": "\u7cfb\u7edf\u5b57\u4f53", + "Failed to upload image: {0}": "\u56fe\u7247\u4e0a\u4f20\u5931\u8d25: {0}", + "Failed to load plugin: {0} from url {1}": "\u63d2\u4ef6\u52a0\u8f7d\u5931\u8d25: {0} \u6765\u81ea\u94fe\u63a5 {1}", + "Failed to load plugin url: {0}": "\u63d2\u4ef6\u52a0\u8f7d\u5931\u8d25 \u94fe\u63a5: {0}", + "Failed to initialize plugin: {0}": "\u63d2\u4ef6\u521d\u59cb\u5316\u5931\u8d25: {0}", + "example": "\u793a\u4f8b", + "Search": "\u641c\u7d22", + "All": "\u5168\u90e8", + "Currency": "\u8d27\u5e01", + "Text": "\u6587\u5b57", + "Quotations": "\u5f15\u7528", + "Mathematical": "\u6570\u5b66", + "Extended Latin": "\u62c9\u4e01\u8bed\u6269\u5145", + "Symbols": "\u7b26\u53f7", + "Arrows": "\u7bad\u5934", + "User Defined": "\u81ea\u5b9a\u4e49", + "dollar sign": "\u7f8e\u5143\u7b26\u53f7", + "currency sign": "\u8d27\u5e01\u7b26\u53f7", + "euro-currency sign": "\u6b27\u5143\u7b26\u53f7", + "colon sign": "\u5192\u53f7", + "cruzeiro sign": "\u514b\u9c81\u8d5b\u7f57\u5e01\u7b26\u53f7", + "french franc sign": "\u6cd5\u90ce\u7b26\u53f7", + "lira sign": "\u91cc\u62c9\u7b26\u53f7", + "mill sign": "\u5bc6\u5c14\u7b26\u53f7", + "naira sign": "\u5948\u62c9\u7b26\u53f7", + "peseta sign": "\u6bd4\u585e\u5854\u7b26\u53f7", + "rupee sign": "\u5362\u6bd4\u7b26\u53f7", + "won sign": "\u97e9\u5143\u7b26\u53f7", + "new sheqel sign": "\u65b0\u8c22\u514b\u5c14\u7b26\u53f7", + "dong sign": "\u8d8a\u5357\u76fe\u7b26\u53f7", + "kip sign": "\u8001\u631d\u57fa\u666e\u7b26\u53f7", + "tugrik sign": "\u56fe\u683c\u91cc\u514b\u7b26\u53f7", + "drachma sign": "\u5fb7\u62c9\u514b\u9a6c\u7b26\u53f7", + "german penny symbol": "\u5fb7\u56fd\u4fbf\u58eb\u7b26\u53f7", + "peso sign": "\u6bd4\u7d22\u7b26\u53f7", + "guarani sign": "\u74dc\u62c9\u5c3c\u7b26\u53f7", + "austral sign": "\u6fb3\u5143\u7b26\u53f7", + "hryvnia sign": "\u683c\u91cc\u592b\u5c3c\u4e9a\u7b26\u53f7", + "cedi sign": "\u585e\u5730\u7b26\u53f7", + "livre tournois sign": "\u91cc\u5f17\u5f17\u5c14\u7b26\u53f7", + "spesmilo sign": "spesmilo\u7b26\u53f7", + "tenge sign": "\u575a\u6208\u7b26\u53f7", + "indian rupee sign": "\u5370\u5ea6\u5362\u6bd4", + "turkish lira sign": "\u571f\u8033\u5176\u91cc\u62c9", + "nordic mark sign": "\u5317\u6b27\u9a6c\u514b", + "manat sign": "\u9a6c\u7eb3\u7279\u7b26\u53f7", + "ruble sign": "\u5362\u5e03\u7b26\u53f7", + "yen character": "\u65e5\u5143\u5b57\u6837", + "yuan character": "\u4eba\u6c11\u5e01\u5143\u5b57\u6837", + "yuan character, in hong kong and taiwan": "\u5143\u5b57\u6837\uff08\u6e2f\u53f0\u5730\u533a\uff09", + "yen\/yuan character variant one": "\u5143\u5b57\u6837\uff08\u5927\u5199\uff09", + "Loading emoticons...": "\u52a0\u8f7d\u8868\u60c5\u7b26\u53f7...", + "Could not load emoticons": "\u4e0d\u80fd\u52a0\u8f7d\u8868\u60c5\u7b26\u53f7", + "People": "\u4eba\u7c7b", + "Animals and Nature": "\u52a8\u7269\u548c\u81ea\u7136", + "Food and Drink": "\u98df\u7269\u548c\u996e\u54c1", + "Activity": "\u6d3b\u52a8", + "Travel and Places": "\u65c5\u6e38\u548c\u5730\u70b9", + "Objects": "\u7269\u4ef6", + "Flags": "\u65d7\u5e1c", + "Characters": "\u5b57\u7b26", + "Characters (no spaces)": "\u5b57\u7b26(\u65e0\u7a7a\u683c)", + "{0} characters": "{0} \u4e2a\u5b57\u7b26", + "Error: Form submit field collision.": "\u9519\u8bef: \u8868\u5355\u63d0\u4ea4\u5b57\u6bb5\u51b2\u7a81\u3002", + "Error: No form element found.": "\u9519\u8bef: \u6ca1\u6709\u8868\u5355\u63a7\u4ef6\u3002", + "Update": "\u66f4\u65b0", + "Color swatch": "\u989c\u8272\u6837\u672c", + "Turquoise": "\u9752\u7eff\u8272", + "Green": "\u7eff\u8272", + "Blue": "\u84dd\u8272", + "Purple": "\u7d2b\u8272", + "Navy Blue": "\u6d77\u519b\u84dd", + "Dark Turquoise": "\u6df1\u84dd\u7eff\u8272", + "Dark Green": "\u6df1\u7eff\u8272", + "Medium Blue": "\u4e2d\u84dd\u8272", + "Medium Purple": "\u4e2d\u7d2b\u8272", + "Midnight Blue": "\u6df1\u84dd\u8272", + "Yellow": "\u9ec4\u8272", + "Orange": "\u6a59\u8272", + "Red": "\u7ea2\u8272", + "Light Gray": "\u6d45\u7070\u8272", + "Gray": "\u7070\u8272", + "Dark Yellow": "\u6697\u9ec4\u8272", + "Dark Orange": "\u6df1\u6a59\u8272", + "Dark Red": "\u6df1\u7ea2\u8272", + "Medium Gray": "\u4e2d\u7070\u8272", + "Dark Gray": "\u6df1\u7070\u8272", + "Light Green": "\u6d45\u7eff\u8272", + "Light Yellow": "\u6d45\u9ec4\u8272", + "Light Red": "\u6d45\u7ea2\u8272", + "Light Purple": "\u6d45\u7d2b\u8272", + "Light Blue": "\u6d45\u84dd\u8272", + "Dark Purple": "\u6df1\u7d2b\u8272", + "Dark Blue": "\u6df1\u84dd\u8272", + "Black": "\u9ed1\u8272", + "White": "\u767d\u8272", + "Switch to or from fullscreen mode": "\u5207\u6362\u5168\u5c4f\u6a21\u5f0f", + "Open help dialog": "\u6253\u5f00\u5e2e\u52a9\u5bf9\u8bdd\u6846", + "history": "\u5386\u53f2", + "styles": "\u6837\u5f0f", + "formatting": "\u683c\u5f0f\u5316", + "alignment": "\u5bf9\u9f50", + "indentation": "\u7f29\u8fdb", + "permanent pen": "\u8bb0\u53f7\u7b14", + "comments": "\u5907\u6ce8", + "Format Painter": "\u683c\u5f0f\u5237", + "Insert\/edit iframe": "\u63d2\u5165\/\u7f16\u8f91\u6846\u67b6", + "Capitalization": "\u5927\u5199", + "lowercase": "\u5c0f\u5199", + "UPPERCASE": "\u5927\u5199", + "Title Case": "\u9996\u5b57\u6bcd\u5927\u5199", + "Permanent Pen Properties": "\u6c38\u4e45\u7b14\u5c5e\u6027", + "Permanent pen properties...": "\u6c38\u4e45\u7b14\u5c5e\u6027...", + "Font": "\u5b57\u4f53", + "Size": "\u5b57\u53f7", + "More...": "\u66f4\u591a...", + "Spellcheck Language": "\u62fc\u5199\u68c0\u67e5\u8bed\u8a00", + "Select...": "\u9009\u62e9...", + "Preferences": "\u9996\u9009\u9879", + "Yes": "\u662f", + "No": "\u5426", + "Keyboard Navigation": "\u952e\u76d8\u6307\u5f15", + "Version": "\u7248\u672c", + "Anchor": "\u951a\u70b9", + "Special character": "\u7279\u6b8a\u7b26\u53f7", + "Code sample": "\u4ee3\u7801\u793a\u4f8b", + "Color": "\u989c\u8272", + "Emoticons": "\u8868\u60c5", + "Document properties": "\u6587\u6863\u5c5e\u6027", + "Image": "\u56fe\u7247", + "Insert link": "\u63d2\u5165\u94fe\u63a5", + "Target": "\u6253\u5f00\u65b9\u5f0f", + "Link": "\u94fe\u63a5", + "Poster": "\u5c01\u9762", + "Media": "\u5a92\u4f53", + "Print": "\u6253\u5370", + "Prev": "\u4e0a\u4e00\u4e2a", + "Find and replace": "\u67e5\u627e\u548c\u66ff\u6362", + "Whole words": "\u5168\u5b57\u5339\u914d", + "Spellcheck": "\u62fc\u5199\u68c0\u67e5", + "Caption": "\u6807\u9898", + "Insert template": "\u63d2\u5165\u6a21\u677f", + "Cut column": "\u526a\u5207\u5217", + "Copy column": "\u590d\u5236\u5217", + "Paste column before": "\u7c98\u8d34\u5230\u524d\u65b9", + "Paste column after": "\u7c98\u8d34\u5230\u540e\u65b9" +}); diff --git a/frontend/public/tinymce-dataease-private/langs/zh_TW.js b/frontend/public/tinymce-dataease-private/langs/zh_TW.js new file mode 100644 index 0000000..b306e0a --- /dev/null +++ b/frontend/public/tinymce-dataease-private/langs/zh_TW.js @@ -0,0 +1,419 @@ +tinymce.addI18n('zh_TW', { + "Redo": "\u91cd\u505a", + "Undo": "\u64a4\u92b7", + "Cut": "\u526a\u4e0b", + "Copy": "\u8907\u88fd", + "Paste": "\u8cbc\u4e0a", + "Select all": "\u5168\u9078", + "New document": "\u65b0\u6587\u4ef6", + "Ok": "\u78ba\u5b9a", + "Cancel": "\u53d6\u6d88", + "Visual aids": "\u5c0f\u5e6b\u624b", + "Bold": "\u7c97\u9ad4", + "Italic": "\u659c\u9ad4", + "Underline": "\u4e0b\u5283\u7dda", + "Strikethrough": "\u522a\u9664\u7dda", + "Superscript": "\u4e0a\u6a19", + "Subscript": "\u4e0b\u6a19", + "Clear formatting": "\u6e05\u9664\u683c\u5f0f", + "Align left": "\u5de6\u908a\u5c0d\u9f4a", + "Align center": "\u4e2d\u9593\u5c0d\u9f4a", + "Align right": "\u53f3\u908a\u5c0d\u9f4a", + "Justify": "\u5de6\u53f3\u5c0d\u9f4a", + "Bullet list": "\u9805\u76ee\u6e05\u55ae", + "Numbered list": "\u6578\u5b57\u6e05\u55ae", + "Decrease indent": "\u6e1b\u5c11\u7e2e\u6392", + "Increase indent": "\u589e\u52a0\u7e2e\u6392", + "Close": "\u95dc\u9589", + "Formats": "\u683c\u5f0f", + "Your browser doesn't support direct access to the clipboard. Please use the Ctrl+X\/C\/V keyboard shortcuts instead.": "\u60a8\u7684\u700f\u89bd\u5668\u4e0d\u652f\u63f4\u5b58\u53d6\u526a\u8cbc\u7c3f\uff0c\u53ef\u4ee5\u4f7f\u7528\u5feb\u901f\u9375 Ctrl + X\/C\/V \u4ee3\u66ff\u526a\u4e0b\u3001\u8907\u88fd\u8207\u8cbc\u4e0a\u3002", + "Headers": "\u6a19\u984c", + "Header 1": "\u6a19\u984c 1", + "Header 2": "\u6a19\u984c 2", + "Header 3": "\u6a19\u984c 3", + "Header 4": "\u6a19\u984c 4", + "Header 5": "\u6a19\u984c 5", + "Header 6": "\u6a19\u984c 6", + "Headings": "\u6a19\u984c", + "Heading 1": "\u6a19\u984c1", + "Heading 2": "\u6a19\u984c2", + "Heading 3": "\u6a19\u984c3", + "Heading 4": "\u6a19\u984c4", + "Heading 5": "\u6a19\u984c5", + "Heading 6": "\u6a19\u984c6", + "Preformatted": "\u9810\u5148\u683c\u5f0f\u5316\u7684", + "Div": "Div", + "Pre": "Pre", + "Code": "\u4ee3\u78bc", + "Paragraph": "\u6bb5\u843d", + "Blockquote": "\u5f15\u6587\u5340\u584a", + "Inline": "\u5167\u806f", + "Blocks": "\u57fa\u584a", + "Paste is now in plain text mode. Contents will now be pasted as plain text until you toggle this option off.": "\u76ee\u524d\u5c07\u4ee5\u7d14\u6587\u5b57\u7684\u6a21\u5f0f\u8cbc\u4e0a\uff0c\u60a8\u53ef\u4ee5\u518d\u9ede\u9078\u4e00\u6b21\u53d6\u6d88\u3002", + "Fonts": "\u5b57\u578b", + "Font Sizes": "\u5b57\u578b\u5927\u5c0f", + "Class": "\u985e\u578b", + "Browse for an image": "\u5f9e\u5716\u7247\u4e2d\u700f\u89bd", + "OR": "\u6216", + "Drop an image here": "\u62d6\u66f3\u5716\u7247\u81f3\u6b64", + "Upload": "\u4e0a\u50b3", + "Block": "\u5340\u584a", + "Align": "\u5c0d\u9f4a", + "Default": "\u9810\u8a2d", + "Circle": "\u7a7a\u5fc3\u5713", + "Disc": "\u5be6\u5fc3\u5713", + "Square": "\u6b63\u65b9\u5f62", + "Lower Alpha": "\u5c0f\u5beb\u82f1\u6587\u5b57\u6bcd", + "Lower Greek": "\u5e0c\u81d8\u5b57\u6bcd", + "Lower Roman": "\u5c0f\u5beb\u7f85\u99ac\u6578\u5b57", + "Upper Alpha": "\u5927\u5beb\u82f1\u6587\u5b57\u6bcd", + "Upper Roman": "\u5927\u5beb\u7f85\u99ac\u6578\u5b57", + "Anchor...": "\u9328\u9ede...", + "Name": "\u540d\u7a31", + "Id": "Id", + "Id should start with a letter, followed only by letters, numbers, dashes, dots, colons or underscores.": "Id\u61c9\u4ee5\u5b57\u6bcd\u958b\u982d\uff0c\u5f8c\u9762\u63a5\u8457\u5b57\u6bcd\uff0c\u6578\u5b57\uff0c\u7834\u6298\u865f\uff0c\u9ede\u6578\uff0c\u5192\u865f\u6216\u4e0b\u5283\u7dda\u3002", + "You have unsaved changes are you sure you want to navigate away?": "\u7de8\u8f2f\u5c1a\u672a\u88ab\u5132\u5b58\uff0c\u4f60\u78ba\u5b9a\u8981\u96e2\u958b\uff1f", + "Restore last draft": "\u8f09\u5165\u4e0a\u4e00\u6b21\u7de8\u8f2f\u7684\u8349\u7a3f", + "Special character...": "\u7279\u6b8a\u5b57\u5143......", + "Source code": "\u539f\u59cb\u78bc", + "Insert\/Edit code sample": "\u63d2\u5165\/\u7de8\u8f2f \u7a0b\u5f0f\u78bc\u7bc4\u4f8b", + "Language": "\u8a9e\u8a00", + "Code sample...": "\u7a0b\u5f0f\u78bc\u7bc4\u4f8b...", + "Color Picker": "\u9078\u8272\u5668", + "R": "\u7d05", + "G": "\u7da0", + "B": "\u85cd", + "Left to right": "\u5f9e\u5de6\u5230\u53f3", + "Right to left": "\u5f9e\u53f3\u5230\u5de6", + "Emoticons...": "\u8868\u60c5\u7b26\u865f\u2026", + "Metadata and Document Properties": "\u5f8c\u8a2d\u8cc7\u6599\u8207\u6587\u4ef6\u5c6c\u6027", + "Title": "\u6a19\u984c", + "Keywords": "\u95dc\u9375\u5b57", + "Description": "\u63cf\u8ff0", + "Robots": "\u6a5f\u5668\u4eba", + "Author": "\u4f5c\u8005", + "Encoding": "\u7de8\u78bc", + "Fullscreen": "\u5168\u87a2\u5e55", + "Action": "\u52d5\u4f5c", + "Shortcut": "\u5feb\u901f\u9375", + "Help": "\u5e6b\u52a9", + "Address": "\u5730\u5740", + "Focus to menubar": "\u8df3\u81f3\u9078\u55ae\u5217", + "Focus to toolbar": "\u8df3\u81f3\u5de5\u5177\u5217", + "Focus to element path": "\u8df3\u81f3HTML\u5143\u7d20\u5217", + "Focus to contextual toolbar": "\u8df3\u81f3\u5feb\u6377\u9078\u55ae", + "Insert link (if link plugin activated)": "\u65b0\u589e\u6377\u5f91 (\u6377\u5f91\u5916\u639b\u555f\u7528\u6642)", + "Save (if save plugin activated)": "\u5132\u5b58 (\u5132\u5b58\u5916\u639b\u555f\u7528\u6642)", + "Find (if searchreplace plugin activated)": "\u5c0b\u627e (\u5c0b\u627e\u53d6\u4ee3\u5916\u639b\u555f\u7528\u6642)", + "Plugins installed ({0}):": "({0}) \u500b\u5916\u639b\u5df2\u5b89\u88dd\uff1a", + "Premium plugins:": "\u52a0\u503c\u5916\u639b\uff1a", + "Learn more...": "\u4e86\u89e3\u66f4\u591a...", + "You are using {0}": "\u60a8\u6b63\u5728\u4f7f\u7528 {0}", + "Plugins": "\u5916\u639b", + "Handy Shortcuts": "\u5feb\u901f\u9375", + "Horizontal line": "\u6c34\u5e73\u7dda", + "Insert\/edit image": "\u63d2\u5165\/\u7de8\u8f2f \u5716\u7247", + "Image description": "\u5716\u7247\u63cf\u8ff0", + "Source": "\u5716\u7247\u7db2\u5740", + "Dimensions": "\u5c3a\u5bf8", + "Constrain proportions": "\u7b49\u6bd4\u4f8b\u7e2e\u653e", + "General": "\u4e00\u822c", + "Advanced": "\u9032\u968e", + "Style": "\u6a23\u5f0f", + "Vertical space": "\u9ad8\u5ea6", + "Horizontal space": "\u5bec\u5ea6", + "Border": "\u908a\u6846", + "Insert image": "\u63d2\u5165\u5716\u7247", + "Image...": "\u5716\u7247......", + "Image list": "\u5716\u7247\u6e05\u55ae", + "Rotate counterclockwise": "\u9006\u6642\u91dd\u65cb\u8f49", + "Rotate clockwise": "\u9806\u6642\u91dd\u65cb\u8f49", + "Flip vertically": "\u5782\u76f4\u7ffb\u8f49", + "Flip horizontally": "\u6c34\u5e73\u7ffb\u8f49", + "Edit image": "\u7de8\u8f2f\u5716\u7247", + "Image options": "\u5716\u7247\u9078\u9805", + "Zoom in": "\u653e\u5927", + "Zoom out": "\u7e2e\u5c0f", + "Crop": "\u88c1\u526a", + "Resize": "\u8abf\u6574\u5927\u5c0f", + "Orientation": "\u65b9\u5411", + "Brightness": "\u4eae\u5ea6", + "Sharpen": "\u92b3\u5316", + "Contrast": "\u5c0d\u6bd4", + "Color levels": "\u984f\u8272\u5c64\u6b21", + "Gamma": "\u4f3d\u99ac\u503c", + "Invert": "\u53cd\u8f49", + "Apply": "\u61c9\u7528", + "Back": "\u5f8c\u9000", + "Insert date\/time": "\u63d2\u5165 \u65e5\u671f\/\u6642\u9593", + "Date\/time": "\u65e5\u671f\/\u6642\u9593", + "Insert\/Edit Link": "\u63d2\u5165\/\u7de8\u8f2f\u9023\u7d50", + "Insert\/edit link": "\u63d2\u5165\/\u7de8\u8f2f\u9023\u7d50", + "Text to display": "\u986f\u793a\u6587\u5b57", + "Url": "\u7db2\u5740", + "Open link in...": "\u958b\u555f\u9023\u7d50\u65bc...", + "Current window": "\u76ee\u524d\u8996\u7a97", + "None": "\u7121", + "New window": "\u53e6\u958b\u8996\u7a97", + "Remove link": "\u79fb\u9664\u9023\u7d50", + "Anchors": "\u52a0\u5165\u9328\u9ede", + "Link...": "\u9023\u7d50...", + "Paste or type a link": "\u8cbc\u4e0a\u6216\u8f38\u5165\u9023\u7d50", + "The URL you entered seems to be an email address. Do you want to add the required mailto: prefix?": "\u4f60\u6240\u586b\u5beb\u7684URL\u70ba\u96fb\u5b50\u90f5\u4ef6\uff0c\u9700\u8981\u52a0\u4e0amailto:\u524d\u7db4\u55ce\uff1f", + "The URL you entered seems to be an external link. Do you want to add the required http:\/\/ prefix?": "\u4f60\u6240\u586b\u5beb\u7684URL\u5c6c\u65bc\u5916\u90e8\u93c8\u63a5\uff0c\u9700\u8981\u52a0\u4e0ahttp:\/\/:\u524d\u7db4\u55ce\uff1f", + "Link list": "\u9023\u7d50\u6e05\u55ae", + "Insert video": "\u63d2\u5165\u5f71\u97f3", + "Insert\/edit video": "\u63d2\u4ef6\/\u7de8\u8f2f \u5f71\u97f3", + "Insert\/edit media": "\u63d2\u5165\/\u7de8\u8f2f \u5a92\u9ad4", + "Alternative source": "\u66ff\u4ee3\u5f71\u97f3", + "Alternative source URL": "\u66ff\u4ee3\u4f86\u6e90URL", + "Media poster (Image URL)": "\u5a92\u9ad4\u6d77\u5831\uff08\u5f71\u50cfImage URL\uff09", + "Paste your embed code below:": "\u8acb\u5c07\u60a8\u7684\u5d4c\u5165\u5f0f\u7a0b\u5f0f\u78bc\u8cbc\u5728\u4e0b\u9762:", + "Embed": "\u5d4c\u5165\u78bc", + "Media...": "\u5a92\u9ad4...", + "Nonbreaking space": "\u4e0d\u5206\u884c\u7684\u7a7a\u683c", + "Page break": "\u5206\u9801", + "Paste as text": "\u4ee5\u7d14\u6587\u5b57\u8cbc\u4e0a", + "Preview": "\u9810\u89bd", + "Print...": "\u5217\u5370...", + "Save": "\u5132\u5b58", + "Find": "\u641c\u5c0b", + "Replace with": "\u66f4\u63db", + "Replace": "\u66ff\u63db", + "Replace all": "\u66ff\u63db\u5168\u90e8", + "Previous": "\u4e0a\u4e00\u500b", + "Next": "\u4e0b\u4e00\u500b", + "Find and replace...": "\u5c0b\u627e\u53ca\u53d6\u4ee3...", + "Could not find the specified string.": "\u7121\u6cd5\u67e5\u8a62\u5230\u6b64\u7279\u5b9a\u5b57\u4e32", + "Match case": "\u76f8\u5339\u914d\u6848\u4ef6", + "Find whole words only": "\u50c5\u627e\u51fa\u5b8c\u6574\u5b57\u532f", + "Spell check": "\u62fc\u5beb\u6aa2\u67e5", + "Ignore": "\u5ffd\u7565", + "Ignore all": "\u5ffd\u7565\u6240\u6709", + "Finish": "\u5b8c\u6210", + "Add to Dictionary": "\u52a0\u5165\u5b57\u5178\u4e2d", + "Insert table": "\u63d2\u5165\u8868\u683c", + "Table properties": "\u8868\u683c\u5c6c\u6027", + "Delete table": "\u522a\u9664\u8868\u683c", + "Cell": "\u5132\u5b58\u683c", + "Row": "\u5217", + "Column": "\u884c", + "Cell properties": "\u5132\u5b58\u683c\u5c6c\u6027", + "Merge cells": "\u5408\u4f75\u5132\u5b58\u683c", + "Split cell": "\u5206\u5272\u5132\u5b58\u683c", + "Insert row before": "\u63d2\u5165\u5217\u5728...\u4e4b\u524d", + "Insert row after": "\u63d2\u5165\u5217\u5728...\u4e4b\u5f8c", + "Delete row": "\u522a\u9664\u5217", + "Row properties": "\u5217\u5c6c\u6027", + "Cut row": "\u526a\u4e0b\u5217", + "Copy row": "\u8907\u88fd\u5217", + "Paste row before": "\u8cbc\u4e0a\u5217\u5728...\u4e4b\u524d", + "Paste row after": "\u8cbc\u4e0a\u5217\u5728...\u4e4b\u5f8c", + "Insert column before": "\u63d2\u5165\u6b04\u4f4d\u5728...\u4e4b\u524d", + "Insert column after": "\u63d2\u5165\u6b04\u4f4d\u5728...\u4e4b\u5f8c", + "Delete column": "\u522a\u9664\u884c", + "Cols": "\u6b04\u4f4d\u6bb5", + "Rows": "\u5217", + "Width": "\u5bec\u5ea6", + "Height": "\u9ad8\u5ea6", + "Cell spacing": "\u5132\u5b58\u683c\u5f97\u9593\u8ddd", + "Cell padding": "\u5132\u5b58\u683c\u7684\u908a\u8ddd", + "Show caption": "\u986f\u793a\u6a19\u984c", + "Left": "\u5de6\u908a", + "Center": "\u4e2d\u9593", + "Right": "\u53f3\u908a", + "Cell type": "\u5132\u5b58\u683c\u7684\u985e\u578b", + "Scope": "\u7bc4\u570d", + "Alignment": "\u5c0d\u9f4a", + "H Align": "\u6c34\u5e73\u4f4d\u7f6e", + "V Align": "\u5782\u76f4\u4f4d\u7f6e", + "Top": "\u7f6e\u9802", + "Middle": "\u7f6e\u4e2d", + "Bottom": "\u7f6e\u5e95", + "Header cell": "\u6a19\u982d\u5132\u5b58\u683c", + "Row group": "\u5217\u7fa4\u7d44", + "Column group": "\u6b04\u4f4d\u7fa4\u7d44", + "Row type": "\u884c\u7684\u985e\u578b", + "Header": "\u6a19\u982d", + "Body": "\u4e3b\u9ad4", + "Footer": "\u9801\u5c3e", + "Border color": "\u908a\u6846\u984f\u8272", + "Insert template...": "\u63d2\u5165\u6a23\u7248...", + "Templates": "\u6a23\u7248", + "Template": "\u6a23\u677f", + "Text color": "\u6587\u5b57\u984f\u8272", + "Background color": "\u80cc\u666f\u984f\u8272", + "Custom...": "\u81ea\u8a02", + "Custom color": "\u81ea\u8a02\u984f\u8272", + "No color": "No color", + "Remove color": "\u79fb\u9664\u984f\u8272", + "Table of Contents": "\u76ee\u9304", + "Show blocks": "\u986f\u793a\u5340\u584a\u8cc7\u8a0a", + "Show invisible characters": "\u986f\u793a\u96b1\u85cf\u5b57\u5143", + "Word count": "\u8a08\u7b97\u5b57\u6578", + "Count": "\u8a08\u7b97", + "Document": "\u6587\u4ef6", + "Selection": "\u9078\u9805", + "Words": "\u5b57\u6578", + "Words: {0}": "\u5b57\u6578\uff1a{0}", + "{0} words": "{0} \u5b57\u5143", + "File": "\u6a94\u6848", + "Edit": "\u7de8\u8f2f", + "Insert": "\u63d2\u5165", + "View": "\u6aa2\u8996", + "Format": "\u683c\u5f0f", + "Table": "\u8868\u683c", + "Tools": "\u5de5\u5177", + "Powered by {0}": "\u7531 {0} \u63d0\u4f9b", + "Rich Text Area. Press ALT-F9 for menu. Press ALT-F10 for toolbar. Press ALT-0 for help": "\u8c50\u5bcc\u7684\u6587\u672c\u5340\u57df\u3002\u6309ALT-F9\u524d\u5f80\u4e3b\u9078\u55ae\u3002\u6309ALT-F10\u547c\u53eb\u5de5\u5177\u6b04\u3002\u6309ALT-0\u5c0b\u6c42\u5e6b\u52a9", + "Image title": "\u5716\u7247\u6a19\u984c", + "Border width": "\u6846\u7dda\u5bec\u5ea6", + "Border style": "\u6846\u7dda\u6a23\u5f0f", + "Error": "\u932f\u8aa4", + "Warn": "\u8b66\u544a", + "Valid": "\u6709\u6548", + "To open the popup, press Shift+Enter": "\u8981\u958b\u555f\u5f48\u51fa\u8996\u7a97\uff0c\u8acb\u6309Shift+Enter", + "Rich Text Area. Press ALT-0 for help.": "\u5bcc\u6587\u672c\u5340\u57df\u3002\u8acb\u6309ALT-0\u5c0b\u6c42\u5354\u52a9\u3002", + "System Font": "\u7cfb\u7d71\u5b57\u578b", + "Failed to upload image: {0}": "\u7121\u6cd5\u4e0a\u50b3\u5f71\u50cf\uff1a{0}", + "Failed to load plugin: {0} from url {1}": "\u7121\u6cd5\u4e0a\u50b3\u63d2\u4ef6\uff1a{0}\u81eaurl{1}", + "Failed to load plugin url: {0}": "\u7121\u6cd5\u4e0a\u50b3\u63d2\u4ef6\uff1a{0}", + "Failed to initialize plugin: {0}": "\u7121\u6cd5\u555f\u52d5\u63d2\u4ef6\uff1a{0}", + "example": "\u7bc4\u4f8b", + "Search": "\u641c\u7d22", + "All": "\u5168\u90e8", + "Currency": "\u8ca8\u5e63", + "Text": "\u6587\u672c", + "Quotations": "\u5f15\u7528", + "Mathematical": "\u6578\u5b78", + "Extended Latin": "\u62c9\u4e01\u5b57\u6bcd\u64f4\u5145", + "Symbols": "\u7b26\u865f", + "Arrows": "\u7bad\u982d", + "User Defined": "\u4f7f\u7528\u8005\u5df2\u5b9a\u7fa9", + "dollar sign": "\u7f8e\u5143\u7b26\u865f", + "currency sign": "\u8ca8\u5e63\u7b26\u865f", + "euro-currency sign": "\u6b50\u5143\u7b26\u865f", + "colon sign": "\u79d1\u6717\u7b26\u865f", + "cruzeiro sign": "\u514b\u9b6f\u8cfd\u7f85\u7b26\u865f", + "french franc sign": "\u6cd5\u6717\u7b26\u865f", + "lira sign": "\u91cc\u62c9\u7b26\u865f", + "mill sign": "\u6587\u7b26\u865f", + "naira sign": "\u5948\u62c9\u7b26\u865f", + "peseta sign": "\u6bd4\u585e\u5854\u7b26\u865f", + "rupee sign": "\u76e7\u6bd4\u7b26\u865f", + "won sign": "\u97d3\u571c\u7b26\u865f", + "new sheqel sign": "\u65b0\u8b1d\u514b\u723e\u7b26\u865f", + "dong sign": "\u8d8a\u5357\u76fe\u7b26\u865f", + "kip sign": "\u8001\u64be\u5e63\u7b26\u865f", + "tugrik sign": "\u8499\u53e4\u5e63\u7b26\u865f", + "drachma sign": "\u5fb7\u514b\u62c9\u99ac\u7b26\u865f", + "german penny symbol": "\u5fb7\u570b\u5206\u7b26\u865f", + "peso sign": "\u62ab\u7d22\u7b26\u865f", + "guarani sign": "\u5df4\u62c9\u572d\u5e63\u7b26\u865f", + "austral sign": "\u963f\u6839\u5ef7\u5e63\u7b26\u865f", + "hryvnia sign": "\u70cf\u514b\u862d\u5e63\u7b26\u865f", + "cedi sign": "\u8fe6\u7d0d\u5e63\u7b26\u865f", + "livre tournois sign": "\u91cc\u5f17\u723e\u7b26\u865f", + "spesmilo sign": "\u570b\u969b\u5e63\u7b26\u865f", + "tenge sign": "\u54c8\u85a9\u514b\u5e63\u7b26\u865f", + "indian rupee sign": "\u5370\u5ea6\u76e7\u6bd4\u7b26\u865f", + "turkish lira sign": "\u571f\u8033\u5176\u91cc\u62c9\u7b26\u865f", + "nordic mark sign": "\u5317\u6b50\u99ac\u514b\u7b26\u865f", + "manat sign": "\u4e9e\u585e\u62dc\u7136\u5e63\u7b26\u865f", + "ruble sign": "\u76e7\u5e03\u7b26\u865f", + "yen character": "\u65e5\u5713\u7b26\u865f", + "yuan character": "\u4eba\u6c11\u5e63\u7b26\u865f", + "yuan character, in hong kong and taiwan": "\u6e2f\u5143\u8207\u53f0\u5e63\u7b26\u865f", + "yen\/yuan character variant one": "\u65e5\u5713\/\u4eba\u6c11\u5e63\u7b26\u865f\u8b8a\u5316\u578b", + "Loading emoticons...": "\u8f09\u5165\u8868\u60c5\u7b26\u865f\u2026", + "Could not load emoticons": "\u7121\u6cd5\u8f09\u5165\u8868\u60c5\u7b26\u865f", + "People": "\u4eba", + "Animals and Nature": "\u52d5\u7269\u8207\u81ea\u7136", + "Food and Drink": "\u98f2\u98df", + "Activity": "\u6d3b\u52d5", + "Travel and Places": "\u65c5\u884c\u8207\u5730\u9ede", + "Objects": "\u7269\u4ef6", + "Flags": "\u65d7\u6a19", + "Characters": "\u5b57\u5143", + "Characters (no spaces)": "\u5b57\u5143\uff08\u7121\u7a7a\u683c\uff09", + "{0} characters": "{0}\u5b57\u5143", + "Error: Form submit field collision.": "\u932f\u8aa4\uff1a\u8868\u683c\u905e\u4ea4\u6b04\u4f4d\u885d\u7a81\u3002", + "Error: No form element found.": "\u932f\u8aa4\uff1a\u627e\u4e0d\u5230\u8868\u683c\u5143\u7d20\u3002", + "Update": "\u66f4\u65b0", + "Color swatch": "\u8272\u5f69\u6a23\u672c", + "Turquoise": "\u571f\u8033\u5176\u85cd", + "Green": "\u7da0\u8272", + "Blue": "\u85cd\u8272", + "Purple": "\u7d2b\u8272", + "Navy Blue": "\u6df1\u85cd\u8272", + "Dark Turquoise": "\u6df1\u571f\u8033\u5176\u85cd", + "Dark Green": "\u6df1\u7da0\u8272", + "Medium Blue": "\u4e2d\u85cd\u8272", + "Medium Purple": "\u4e2d\u7d2b\u8272", + "Midnight Blue": "\u9ed1\u85cd\u8272", + "Yellow": "\u9ec3\u8272", + "Orange": "\u6a59\u8272", + "Red": "\u7d05\u8272", + "Light Gray": "\u6dfa\u7070\u8272", + "Gray": "\u7070\u8272", + "Dark Yellow": "\u6df1\u9ec3\u8272", + "Dark Orange": "\u6df1\u6a59\u8272", + "Dark Red": "\u6697\u7d05\u8272", + "Medium Gray": "\u4e2d\u7070\u8272", + "Dark Gray": "\u6df1\u7070\u8272", + "Light Green": "\u6de1\u7da0\u8272", + "Light Yellow": "\u6dfa\u9ec3\u8272", + "Light Red": "\u6dfa\u7d05\u8272", + "Light Purple": "\u6dfa\u7d2b\u8272", + "Light Blue": "\u6dfa\u85cd\u8272", + "Dark Purple": "\u6df1\u7d2b\u8272", + "Dark Blue": "\u6df1\u85cd\u8272", + "Black": "\u9ed1\u8272", + "White": "\u767d\u8272", + "Switch to or from fullscreen mode": "\u8f49\u63db\u81ea\/\u81f3\u5168\u87a2\u5e55\u6a21\u5f0f", + "Open help dialog": "\u958b\u555f\u5354\u52a9\u5c0d\u8a71", + "history": "\u6b77\u53f2", + "styles": "\u6a23\u5f0f", + "formatting": "\u683c\u5f0f", + "alignment": "\u5c0d\u9f4a", + "indentation": "\u7e2e\u6392", + "permanent pen": "\u6c38\u4e45\u6027\u7b46", + "comments": "\u8a3b\u89e3", + "Format Painter": "\u8907\u88fd\u683c\u5f0f", + "Insert\/edit iframe": "\u63d2\u5165\/\u7de8\u8f2fiframe", + "Capitalization": "\u5927\u5beb", + "lowercase": "\u5c0f\u5beb", + "UPPERCASE": "\u5927\u5beb", + "Title Case": "\u5b57\u9996\u5927\u5beb", + "Permanent Pen Properties": "\u6c38\u4e45\u6a19\u8a18\u5c6c\u6027", + "Permanent pen properties...": "\u6c38\u4e45\u6a19\u8a18\u5c6c\u6027......", + "Font": "\u5b57\u578b", + "Size": "\u5b57\u5f62\u5927\u5c0f", + "More...": "\u66f4\u591a\u8cc7\u8a0a......", + "Spellcheck Language": "\u62fc\u5beb\u8a9e\u8a00", + "Select...": "\u9078\u64c7......", + "Preferences": "\u9996\u9078\u9805", + "Yes": "\u662f", + "No": "\u5426", + "Keyboard Navigation": "\u9375\u76e4\u5c0e\u822a", + "Version": "\u7248\u672c", + "Anchor": "\u52a0\u5165\u9328\u9ede", + "Special character": "\u7279\u6b8a\u5b57\u5143", + "Code sample": "\u7a0b\u5f0f\u78bc\u7bc4\u4f8b", + "Color": "\u984f\u8272", + "Emoticons": "\u8868\u60c5", + "Document properties": "\u6587\u4ef6\u7684\u5c6c\u6027", + "Image": "\u5716\u7247", + "Insert link": "\u63d2\u5165\u9023\u7d50", + "Target": "\u958b\u555f\u65b9\u5f0f", + "Link": "\u9023\u7d50", + "Poster": "\u9810\u89bd\u5716\u7247", + "Media": "\u5a92\u9ad4", + "Print": "\u5217\u5370", + "Prev": "\u4e0a\u4e00\u500b", + "Find and replace": "\u5c0b\u627e\u53ca\u53d6\u4ee3", + "Whole words": "\u6574\u500b\u55ae\u5b57", + "Spellcheck": "\u62fc\u5b57\u6aa2\u67e5", + "Caption": "\u8868\u683c\u6a19\u984c", + "Insert template": "\u63d2\u5165\u6a23\u7248" +}); diff --git a/frontend/public/tinymce-dataease-private/skins/content/dark/content.css b/frontend/public/tinymce-dataease-private/skins/content/dark/content.css new file mode 100644 index 0000000..3919f03 --- /dev/null +++ b/frontend/public/tinymce-dataease-private/skins/content/dark/content.css @@ -0,0 +1,84 @@ +/** + * Copyright (c) Tiny Technologies, Inc. All rights reserved. + * Licensed under the LGPL or a commercial license. + * For LGPL see License.txt in the project root for license information. + * For commercial licenses see https://www.tiny.cloud/ + */ +body { + background-color: #2f3742; + color: #dfe0e4; + font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif; + line-height: 1.4; + margin: 1rem; +} + +a { + color: #4099ff; +} + +table { + border-collapse: collapse; +} + +/* Apply a default padding if legacy cellpadding attribute is missing */ +table:not([cellpadding]) th, +table:not([cellpadding]) td { + padding: 0.4rem; +} + +/* Set default table styles if a table has a positive border attribute + and no inline css */ +table[border]:not([border="0"]):not([style*="border-width"]) th, +table[border]:not([border="0"]):not([style*="border-width"]) td { + border-width: 1px; +} + +/* Set default table styles if a table has a positive border attribute + and no inline css */ +table[border]:not([border="0"]):not([style*="border-style"]) th, +table[border]:not([border="0"]):not([style*="border-style"]) td { + border-style: solid; +} + +/* Set default table styles if a table has a positive border attribute + and no inline css */ +table[border]:not([border="0"]):not([style*="border-color"]) th, +table[border]:not([border="0"]):not([style*="border-color"]) td { + border-color: #6d737b; +} + +figure { + display: table; + margin: 1rem auto; +} + +figure figcaption { + color: #8a8f97; + display: block; + margin-top: 0.25rem; + text-align: center; +} + +hr { + border-color: #6d737b; + border-style: solid; + border-width: 1px 0 0 0; +} + +code { + background-color: #6d737b; + border-radius: 3px; + padding: 0.1rem 0.2rem; +} + +.mce-content-body:not([dir=rtl]) blockquote { + border-left: 2px solid #6d737b; + margin-left: 1.5rem; + padding-left: 1rem; +} + +.mce-content-body[dir=rtl] blockquote { + border-right: 2px solid #6d737b; + margin-right: 1.5rem; + padding-right: 1rem; +} diff --git a/frontend/public/tinymce-dataease-private/skins/content/dark/content.min.css b/frontend/public/tinymce-dataease-private/skins/content/dark/content.min.css new file mode 100644 index 0000000..07d40c2 --- /dev/null +++ b/frontend/public/tinymce-dataease-private/skins/content/dark/content.min.css @@ -0,0 +1,7 @@ +/** + * Copyright (c) Tiny Technologies, Inc. All rights reserved. + * Licensed under the LGPL or a commercial license. + * For LGPL see License.txt in the project root for license information. + * For commercial licenses see https://www.tiny.cloud/ + */ +body{background-color:#2f3742;color:#dfe0e4;font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,Oxygen,Ubuntu,Cantarell,'Open Sans','Helvetica Neue',sans-serif;line-height:1.4;margin:1rem}a{color:#4099ff}table{border-collapse:collapse}table:not([cellpadding]) td,table:not([cellpadding]) th{padding:.4rem}table[border]:not([border="0"]):not([style*=border-width]) td,table[border]:not([border="0"]):not([style*=border-width]) th{border-width:1px}table[border]:not([border="0"]):not([style*=border-style]) td,table[border]:not([border="0"]):not([style*=border-style]) th{border-style:solid}table[border]:not([border="0"]):not([style*=border-color]) td,table[border]:not([border="0"]):not([style*=border-color]) th{border-color:#6d737b}figure{display:table;margin:1rem auto}figure figcaption{color:#8a8f97;display:block;margin-top:.25rem;text-align:center}hr{border-color:#6d737b;border-style:solid;border-width:1px 0 0 0}code{background-color:#6d737b;border-radius:3px;padding:.1rem .2rem}.mce-content-body:not([dir=rtl]) blockquote{border-left:2px solid #6d737b;margin-left:1.5rem;padding-left:1rem}.mce-content-body[dir=rtl] blockquote{border-right:2px solid #6d737b;margin-right:1.5rem;padding-right:1rem} diff --git a/frontend/public/tinymce-dataease-private/skins/content/default/content.css b/frontend/public/tinymce-dataease-private/skins/content/default/content.css new file mode 100644 index 0000000..2df0c23 --- /dev/null +++ b/frontend/public/tinymce-dataease-private/skins/content/default/content.css @@ -0,0 +1,73 @@ +/** + * Copyright (c) Tiny Technologies, Inc. All rights reserved. + * Licensed under the LGPL or a commercial license. + * For LGPL see License.txt in the project root for license information. + * For commercial licenses see https://www.tiny.cloud/ + */ + +table { + border-collapse: collapse; +} + +/* Apply a default padding if legacy cellpadding attribute is missing */ +table:not([cellpadding]) th, +table:not([cellpadding]) td { + padding: 0.4rem; +} + +/* Set default table styles if a table has a positive border attribute + and no inline css */ +table[border]:not([border="0"]):not([style*="border-width"]) th, +table[border]:not([border="0"]):not([style*="border-width"]) td { + border-width: 1px; +} + +/* Set default table styles if a table has a positive border attribute + and no inline css */ +table[border]:not([border="0"]):not([style*="border-style"]) th, +table[border]:not([border="0"]):not([style*="border-style"]) td { + border-style: solid; +} + +/* Set default table styles if a table has a positive border attribute + and no inline css */ +table[border]:not([border="0"]):not([style*="border-color"]) th, +table[border]:not([border="0"]):not([style*="border-color"]) td { + border-color: #ccc; +} + +figure { + display: table; + margin: 1rem auto; +} + +figure figcaption { + color: #999; + display: block; + margin-top: 0.25rem; + text-align: center; +} + +hr { + border-color: #ccc; + border-style: solid; + border-width: 1px 0 0 0; +} + +code { + background-color: #e8e8e8; + border-radius: 3px; + padding: 0.1rem 0.2rem; +} + +.mce-content-body:not([dir=rtl]) blockquote { + border-left: 2px solid #ccc; + margin-left: 1.5rem; + padding-left: 1rem; +} + +.mce-content-body[dir=rtl] blockquote { + border-right: 2px solid #ccc; + margin-right: 1.5rem; + padding-right: 1rem; +} diff --git a/frontend/public/tinymce-dataease-private/skins/content/default/content.min.css b/frontend/public/tinymce-dataease-private/skins/content/default/content.min.css new file mode 100644 index 0000000..29cd987 --- /dev/null +++ b/frontend/public/tinymce-dataease-private/skins/content/default/content.min.css @@ -0,0 +1,7 @@ +/** + * Copyright (c) Tiny Technologies, Inc. All rights reserved. + * Licensed under the LGPL or a commercial license. + * For LGPL see License.txt in the project root for license information. + * For commercial licenses see https://www.tiny.cloud/ + */ +body{font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,Oxygen,Ubuntu,Cantarell,'Open Sans','Helvetica Neue',sans-serif;line-height:1.4;margin:1rem}table{border-collapse:collapse}table:not([cellpadding]) td,table:not([cellpadding]) th{padding:.4rem}table[border]:not([border="0"]):not([style*=border-width]) td,table[border]:not([border="0"]):not([style*=border-width]) th{border-width:1px}table[border]:not([border="0"]):not([style*=border-style]) td,table[border]:not([border="0"]):not([style*=border-style]) th{border-style:solid}table[border]:not([border="0"]):not([style*=border-color]) td,table[border]:not([border="0"]):not([style*=border-color]) th{border-color:#ccc}figure{display:table;margin:1rem auto}figure figcaption{color:#999;display:block;margin-top:.25rem;text-align:center}hr{border-color:#ccc;border-style:solid;border-width:1px 0 0 0}code{background-color:#e8e8e8;border-radius:3px;padding:.1rem .2rem}.mce-content-body:not([dir=rtl]) blockquote{border-left:2px solid #ccc;margin-left:1.5rem;padding-left:1rem}.mce-content-body[dir=rtl] blockquote{border-right:2px solid #ccc;margin-right:1.5rem;padding-right:1rem} diff --git a/frontend/public/tinymce-dataease-private/skins/content/document/content.css b/frontend/public/tinymce-dataease-private/skins/content/document/content.css new file mode 100644 index 0000000..abd6fc2 --- /dev/null +++ b/frontend/public/tinymce-dataease-private/skins/content/document/content.css @@ -0,0 +1,83 @@ +/** + * Copyright (c) Tiny Technologies, Inc. All rights reserved. + * Licensed under the LGPL or a commercial license. + * For LGPL see License.txt in the project root for license information. + * For commercial licenses see https://www.tiny.cloud/ + */ +@media screen { + html { + background: #f4f4f4; + min-height: 100%; + } +} + +body { + font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif; +} + +@media screen { + body { + background-color: #fff; + box-shadow: 0 0 4px rgba(0, 0, 0, 0.15); + box-sizing: border-box; + margin: 1rem auto 0; + max-width: 820px; + min-height: calc(100vh - 1rem); + padding: 4rem 6rem 6rem 6rem; + } +} + +table { + border-collapse: collapse; +} + +/* Apply a default padding if legacy cellpadding attribute is missing */ +table:not([cellpadding]) th, +table:not([cellpadding]) td { + padding: 0.4rem; +} + +/* Set default table styles if a table has a positive border attribute + and no inline css */ +table[border]:not([border="0"]):not([style*="border-width"]) th, +table[border]:not([border="0"]):not([style*="border-width"]) td { + border-width: 1px; +} + +/* Set default table styles if a table has a positive border attribute + and no inline css */ +table[border]:not([border="0"]):not([style*="border-style"]) th, +table[border]:not([border="0"]):not([style*="border-style"]) td { + border-style: solid; +} + +/* Set default table styles if a table has a positive border attribute + and no inline css */ +table[border]:not([border="0"]):not([style*="border-color"]) th, +table[border]:not([border="0"]):not([style*="border-color"]) td { + border-color: #ccc; +} + +figure figcaption { + color: #999; + margin-top: 0.25rem; + text-align: center; +} + +hr { + border-color: #ccc; + border-style: solid; + border-width: 1px 0 0 0; +} + +.mce-content-body:not([dir=rtl]) blockquote { + border-left: 2px solid #ccc; + margin-left: 1.5rem; + padding-left: 1rem; +} + +.mce-content-body[dir=rtl] blockquote { + border-right: 2px solid #ccc; + margin-right: 1.5rem; + padding-right: 1rem; +} diff --git a/frontend/public/tinymce-dataease-private/skins/content/document/content.min.css b/frontend/public/tinymce-dataease-private/skins/content/document/content.min.css new file mode 100644 index 0000000..a1feef4 --- /dev/null +++ b/frontend/public/tinymce-dataease-private/skins/content/document/content.min.css @@ -0,0 +1,7 @@ +/** + * Copyright (c) Tiny Technologies, Inc. All rights reserved. + * Licensed under the LGPL or a commercial license. + * For LGPL see License.txt in the project root for license information. + * For commercial licenses see https://www.tiny.cloud/ + */ +@media screen{html{background:#f4f4f4;min-height:100%}}body{font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,Oxygen,Ubuntu,Cantarell,'Open Sans','Helvetica Neue',sans-serif}@media screen{body{background-color:#fff;box-shadow:0 0 4px rgba(0,0,0,.15);box-sizing:border-box;margin:1rem auto 0;max-width:820px;min-height:calc(100vh - 1rem);padding:4rem 6rem 6rem 6rem}}table{border-collapse:collapse}table:not([cellpadding]) td,table:not([cellpadding]) th{padding:.4rem}table[border]:not([border="0"]):not([style*=border-width]) td,table[border]:not([border="0"]):not([style*=border-width]) th{border-width:1px}table[border]:not([border="0"]):not([style*=border-style]) td,table[border]:not([border="0"]):not([style*=border-style]) th{border-style:solid}table[border]:not([border="0"]):not([style*=border-color]) td,table[border]:not([border="0"]):not([style*=border-color]) th{border-color:#ccc}figure figcaption{color:#999;margin-top:.25rem;text-align:center}hr{border-color:#ccc;border-style:solid;border-width:1px 0 0 0}.mce-content-body:not([dir=rtl]) blockquote{border-left:2px solid #ccc;margin-left:1.5rem;padding-left:1rem}.mce-content-body[dir=rtl] blockquote{border-right:2px solid #ccc;margin-right:1.5rem;padding-right:1rem} diff --git a/frontend/public/tinymce-dataease-private/skins/content/writer/content.css b/frontend/public/tinymce-dataease-private/skins/content/writer/content.css new file mode 100644 index 0000000..df0b395 --- /dev/null +++ b/frontend/public/tinymce-dataease-private/skins/content/writer/content.css @@ -0,0 +1,79 @@ +/** + * Copyright (c) Tiny Technologies, Inc. All rights reserved. + * Licensed under the LGPL or a commercial license. + * For LGPL see License.txt in the project root for license information. + * For commercial licenses see https://www.tiny.cloud/ + */ +body { + font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif; + line-height: 1.4; + margin: 1rem auto; + max-width: 900px; +} + +table { + border-collapse: collapse; +} + +/* Apply a default padding if legacy cellpadding attribute is missing */ +table:not([cellpadding]) th, +table:not([cellpadding]) td { + padding: 0.4rem; +} + +/* Set default table styles if a table has a positive border attribute + and no inline css */ +table[border]:not([border="0"]):not([style*="border-width"]) th, +table[border]:not([border="0"]):not([style*="border-width"]) td { + border-width: 1px; +} + +/* Set default table styles if a table has a positive border attribute + and no inline css */ +table[border]:not([border="0"]):not([style*="border-style"]) th, +table[border]:not([border="0"]):not([style*="border-style"]) td { + border-style: solid; +} + +/* Set default table styles if a table has a positive border attribute + and no inline css */ +table[border]:not([border="0"]):not([style*="border-color"]) th, +table[border]:not([border="0"]):not([style*="border-color"]) td { + border-color: #ccc; +} + +figure { + display: table; + margin: 1rem auto; +} + +figure figcaption { + color: #999; + display: block; + margin-top: 0.25rem; + text-align: center; +} + +hr { + border-color: #ccc; + border-style: solid; + border-width: 1px 0 0 0; +} + +code { + background-color: #e8e8e8; + border-radius: 3px; + padding: 0.1rem 0.2rem; +} + +.mce-content-body:not([dir=rtl]) blockquote { + border-left: 2px solid #ccc; + margin-left: 1.5rem; + padding-left: 1rem; +} + +.mce-content-body[dir=rtl] blockquote { + border-right: 2px solid #ccc; + margin-right: 1.5rem; + padding-right: 1rem; +} diff --git a/frontend/public/tinymce-dataease-private/skins/content/writer/content.min.css b/frontend/public/tinymce-dataease-private/skins/content/writer/content.min.css new file mode 100644 index 0000000..0d8f5d3 --- /dev/null +++ b/frontend/public/tinymce-dataease-private/skins/content/writer/content.min.css @@ -0,0 +1,7 @@ +/** + * Copyright (c) Tiny Technologies, Inc. All rights reserved. + * Licensed under the LGPL or a commercial license. + * For LGPL see License.txt in the project root for license information. + * For commercial licenses see https://www.tiny.cloud/ + */ +body{font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,Oxygen,Ubuntu,Cantarell,'Open Sans','Helvetica Neue',sans-serif;line-height:1.4;margin:1rem auto;max-width:900px}table{border-collapse:collapse}table:not([cellpadding]) td,table:not([cellpadding]) th{padding:.4rem}table[border]:not([border="0"]):not([style*=border-width]) td,table[border]:not([border="0"]):not([style*=border-width]) th{border-width:1px}table[border]:not([border="0"]):not([style*=border-style]) td,table[border]:not([border="0"]):not([style*=border-style]) th{border-style:solid}table[border]:not([border="0"]):not([style*=border-color]) td,table[border]:not([border="0"]):not([style*=border-color]) th{border-color:#ccc}figure{display:table;margin:1rem auto}figure figcaption{color:#999;display:block;margin-top:.25rem;text-align:center}hr{border-color:#ccc;border-style:solid;border-width:1px 0 0 0}code{background-color:#e8e8e8;border-radius:3px;padding:.1rem .2rem}.mce-content-body:not([dir=rtl]) blockquote{border-left:2px solid #ccc;margin-left:1.5rem;padding-left:1rem}.mce-content-body[dir=rtl] blockquote{border-right:2px solid #ccc;margin-right:1.5rem;padding-right:1rem} diff --git a/frontend/public/tinymce-dataease-private/skins/ui/oxide-dark/content.css b/frontend/public/tinymce-dataease-private/skins/ui/oxide-dark/content.css new file mode 100644 index 0000000..522751b --- /dev/null +++ b/frontend/public/tinymce-dataease-private/skins/ui/oxide-dark/content.css @@ -0,0 +1,849 @@ +/** + * Copyright (c) Tiny Technologies, Inc. All rights reserved. + * Licensed under the LGPL or a commercial license. + * For LGPL see License.txt in the project root for license information. + * For commercial licenses see https://www.tiny.cloud/ + */ +.mce-content-body .mce-item-anchor { + background: transparent url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D'8'%20height%3D'12'%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%3E%3Cpath%20d%3D'M0%200L8%200%208%2012%204.09117821%209%200%2012z'%20fill%3D%22%23cccccc%22%2F%3E%3C%2Fsvg%3E%0A") no-repeat center; + cursor: default; + display: inline-block; + height: 12px !important; + padding: 0 2px; + -webkit-user-modify: read-only; + -moz-user-modify: read-only; + -webkit-user-select: all; + -moz-user-select: all; + -ms-user-select: all; + user-select: all; + width: 8px !important; +} + +.mce-content-body .mce-item-anchor[data-mce-selected] { + outline-offset: 1px; +} + +.tox-comments-visible .tox-comment { + background-color: #fff0b7; +} + +.tox-comments-visible .tox-comment--active { + background-color: #ffe168; +} + +.tox-checklist > li:not(.tox-checklist--hidden) { + list-style: none; + margin: 0.25em 0; +} + +.tox-checklist > li:not(.tox-checklist--hidden)::before { + content: url("data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2216%22%20height%3D%2216%22%20viewBox%3D%220%200%2016%2016%22%3E%3Cg%20id%3D%22checklist-unchecked%22%20fill%3D%22none%22%20fill-rule%3D%22evenodd%22%3E%3Crect%20id%3D%22Rectangle%22%20width%3D%2215%22%20height%3D%2215%22%20x%3D%22.5%22%20y%3D%22.5%22%20fill-rule%3D%22nonzero%22%20stroke%3D%22%236d737b%22%20rx%3D%222%22%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E%0A"); + cursor: pointer; + height: 1em; + margin-left: -1.5em; + margin-top: 0.125em; + position: absolute; + width: 1em; +} + +.tox-checklist li:not(.tox-checklist--hidden).tox-checklist--checked::before { + content: url("data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2216%22%20height%3D%2216%22%20viewBox%3D%220%200%2016%2016%22%3E%3Cg%20id%3D%22checklist-checked%22%20fill%3D%22none%22%20fill-rule%3D%22evenodd%22%3E%3Crect%20id%3D%22Rectangle%22%20width%3D%2216%22%20height%3D%2216%22%20fill%3D%22%234099FF%22%20fill-rule%3D%22nonzero%22%20rx%3D%222%22%2F%3E%3Cpath%20id%3D%22Path%22%20fill%3D%22%23FFF%22%20fill-rule%3D%22nonzero%22%20d%3D%22M11.5703186%2C3.14417309%20C11.8516238%2C2.73724603%2012.4164781%2C2.62829933%2012.83558%2C2.89774797%20C13.260121%2C3.17069355%2013.3759736%2C3.72932262%2013.0909105%2C4.14168582%20L7.7580587%2C11.8560195%20C7.43776896%2C12.3193404%206.76483983%2C12.3852142%206.35607322%2C11.9948725%20L3.02491697%2C8.8138662%20C2.66090143%2C8.46625845%202.65798871%2C7.89594698%203.01850234%2C7.54483354%20C3.373942%2C7.19866177%203.94940006%2C7.19592841%204.30829608%2C7.5386474%20L6.85276923%2C9.9684299%20L11.5703186%2C3.14417309%20Z%22%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E%0A"); +} + +[dir=rtl] .tox-checklist > li:not(.tox-checklist--hidden)::before { + margin-left: 0; + margin-right: -1.5em; +} + +/* stylelint-disable */ +/* http://prismjs.com/ */ +/** + * Dracula Theme originally by Zeno Rocha [@zenorocha] + * https://draculatheme.com/ + * + * Ported for PrismJS by Albert Vallverdu [@byverdu] + */ +code[class*="language-"], +pre[class*="language-"] { + color: #f8f8f2; + background: none; + text-shadow: 0 1px rgba(0, 0, 0, 0.3); + font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace; + text-align: left; + white-space: pre; + word-spacing: normal; + word-break: normal; + word-wrap: normal; + line-height: 1.5; + -moz-tab-size: 4; + tab-size: 4; + -webkit-hyphens: none; + -ms-hyphens: none; + hyphens: none; +} + +/* Code blocks */ +pre[class*="language-"] { + padding: 1em; + margin: 0.5em 0; + overflow: auto; + border-radius: 0.3em; +} + +:not(pre) > code[class*="language-"], +pre[class*="language-"] { + background: #282a36; +} + +/* Inline code */ +:not(pre) > code[class*="language-"] { + padding: 0.1em; + border-radius: 0.3em; + white-space: normal; +} + +.token.comment, +.token.prolog, +.token.doctype, +.token.cdata { + color: #6272a4; +} + +.token.punctuation { + color: #f8f8f2; +} + +.namespace { + opacity: 0.7; +} + +.token.property, +.token.tag, +.token.constant, +.token.symbol, +.token.deleted { + color: #ff79c6; +} + +.token.boolean, +.token.number { + color: #bd93f9; +} + +.token.selector, +.token.attr-name, +.token.string, +.token.char, +.token.builtin, +.token.inserted { + color: #50fa7b; +} + +.token.operator, +.token.entity, +.token.url, +.language-css .token.string, +.style .token.string, +.token.variable { + color: #f8f8f2; +} + +.token.atrule, +.token.attr-value, +.token.function, +.token.class-name { + color: #f1fa8c; +} + +.token.keyword { + color: #8be9fd; +} + +.token.regex, +.token.important { + color: #ffb86c; +} + +.token.important, +.token.bold { + font-weight: bold; +} + +.token.italic { + font-style: italic; +} + +.token.entity { + cursor: help; +} + +/* stylelint-enable */ +.mce-content-body { + overflow-wrap: break-word; + word-wrap: break-word; +} + +.mce-content-body .mce-visual-caret { + background-color: black; + background-color: currentColor; + position: absolute; +} + +.mce-content-body .mce-visual-caret-hidden { + display: none; +} + +.mce-content-body *[data-mce-caret] { + left: -1000px; + margin: 0; + padding: 0; + position: absolute; + right: auto; + top: 0; +} + +.mce-content-body .mce-offscreen-selection { + left: -2000000px; + max-width: 1000000px; + position: absolute; +} + +.mce-content-body *[contentEditable=false] { + cursor: default; +} + +.mce-content-body *[contentEditable=true] { + cursor: text; +} + +.tox-cursor-format-painter { + cursor: url("data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2224%22%20height%3D%2224%22%20viewBox%3D%220%200%2024%2024%22%3E%0A%20%20%3Cg%20fill%3D%22none%22%20fill-rule%3D%22evenodd%22%3E%0A%20%20%20%20%3Cpath%20fill%3D%22%23000%22%20fill-rule%3D%22nonzero%22%20d%3D%22M15%2C6%20C15%2C5.45%2014.55%2C5%2014%2C5%20L6%2C5%20C5.45%2C5%205%2C5.45%205%2C6%20L5%2C10%20C5%2C10.55%205.45%2C11%206%2C11%20L14%2C11%20C14.55%2C11%2015%2C10.55%2015%2C10%20L15%2C9%20L16%2C9%20L16%2C12%20L9%2C12%20L9%2C19%20C9%2C19.55%209.45%2C20%2010%2C20%20L11%2C20%20C11.55%2C20%2012%2C19.55%2012%2C19%20L12%2C14%20L18%2C14%20L18%2C7%20L15%2C7%20L15%2C6%20Z%22%2F%3E%0A%20%20%20%20%3Cpath%20fill%3D%22%23000%22%20fill-rule%3D%22nonzero%22%20d%3D%22M1%2C1%20L8.25%2C1%20C8.66421356%2C1%209%2C1.33578644%209%2C1.75%20L9%2C1.75%20C9%2C2.16421356%208.66421356%2C2.5%208.25%2C2.5%20L2.5%2C2.5%20L2.5%2C8.25%20C2.5%2C8.66421356%202.16421356%2C9%201.75%2C9%20L1.75%2C9%20C1.33578644%2C9%201%2C8.66421356%201%2C8.25%20L1%2C1%20Z%22%2F%3E%0A%20%20%3C%2Fg%3E%0A%3C%2Fsvg%3E%0A"), default; +} + +.mce-content-body figure.align-left { + float: left; +} + +.mce-content-body figure.align-right { + float: right; +} + +.mce-content-body figure.image.align-center { + display: table; + margin-left: auto; + margin-right: auto; +} + +.mce-preview-object { + border: 1px solid gray; + display: inline-block; + line-height: 0; + margin: 0 2px 0 2px; + position: relative; +} + +.mce-preview-object .mce-shim { + background: url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7); + height: 100%; + left: 0; + position: absolute; + top: 0; + width: 100%; +} + +.mce-preview-object[data-mce-selected="2"] .mce-shim { + display: none; +} + +.mce-object { + background: transparent url("data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2224%22%20height%3D%2224%22%3E%3Cpath%20d%3D%22M4%203h16a1%201%200%200%201%201%201v16a1%201%200%200%201-1%201H4a1%201%200%200%201-1-1V4a1%201%200%200%201%201-1zm1%202v14h14V5H5zm4.79%202.565l5.64%204.028a.5.5%200%200%201%200%20.814l-5.64%204.028a.5.5%200%200%201-.79-.407V7.972a.5.5%200%200%201%20.79-.407z%22%20fill%3D%22%23cccccc%22%2F%3E%3C%2Fsvg%3E%0A") no-repeat center; + border: 1px dashed #aaa; +} + +.mce-pagebreak { + border: 1px dashed #aaa; + cursor: default; + display: block; + height: 5px; + margin-top: 15px; + page-break-before: always; + width: 100%; +} + +@media print { + .mce-pagebreak { + border: 0; + } +} + +.tiny-pageembed .mce-shim { + background: url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7); + height: 100%; + left: 0; + position: absolute; + top: 0; + width: 100%; +} + +.tiny-pageembed[data-mce-selected="2"] .mce-shim { + display: none; +} + +.tiny-pageembed { + display: inline-block; + position: relative; +} + +.tiny-pageembed--21by9, +.tiny-pageembed--16by9, +.tiny-pageembed--4by3, +.tiny-pageembed--1by1 { + display: block; + overflow: hidden; + padding: 0; + position: relative; + width: 100%; +} + +.tiny-pageembed--21by9 { + padding-top: 42.857143%; +} + +.tiny-pageembed--16by9 { + padding-top: 56.25%; +} + +.tiny-pageembed--4by3 { + padding-top: 75%; +} + +.tiny-pageembed--1by1 { + padding-top: 100%; +} + +.tiny-pageembed--21by9 iframe, +.tiny-pageembed--16by9 iframe, +.tiny-pageembed--4by3 iframe, +.tiny-pageembed--1by1 iframe { + border: 0; + height: 100%; + left: 0; + position: absolute; + top: 0; + width: 100%; +} + +.mce-content-body[data-mce-placeholder] { + position: relative; +} + +.mce-content-body[data-mce-placeholder]:not(.mce-visualblocks)::before { + color: rgba(34, 47, 62, 0.7); + content: attr(data-mce-placeholder); + position: absolute; +} + +.mce-content-body:not([dir=rtl])[data-mce-placeholder]:not(.mce-visualblocks)::before { + left: 1px; + color:#a1b7cb; +} + +.mce-content-body[dir=rtl][data-mce-placeholder]:not(.mce-visualblocks)::before { + right: 1px; +} + +.mce-content-body div.mce-resizehandle { + background-color: #4099ff; + border-color: #4099ff; + border-style: solid; + border-width: 1px; + box-sizing: border-box; + height: 10px; + position: absolute; + width: 10px; + z-index: 10000; +} + +.mce-content-body div.mce-resizehandle:hover { + background-color: #4099ff; +} + +.mce-content-body div.mce-resizehandle:nth-of-type(1) { + cursor: nwse-resize; +} + +.mce-content-body div.mce-resizehandle:nth-of-type(2) { + cursor: nesw-resize; +} + +.mce-content-body div.mce-resizehandle:nth-of-type(3) { + cursor: nwse-resize; +} + +.mce-content-body div.mce-resizehandle:nth-of-type(4) { + cursor: nesw-resize; +} + +.mce-content-body .mce-resize-backdrop { + z-index: 10000; +} + +.mce-content-body .mce-clonedresizable { + cursor: default; + opacity: 0.5; + outline: 1px dashed black; + position: absolute; + z-index: 10001; +} + +.mce-content-body .mce-clonedresizable.mce-resizetable-columns th, +.mce-content-body .mce-clonedresizable.mce-resizetable-columns td { + border: 0; +} + +.mce-content-body .mce-resize-helper { + background: #555; + background: rgba(0, 0, 0, 0.75); + border: 1px; + border-radius: 3px; + color: white; + display: none; + font-family: sans-serif; + font-size: 12px; + line-height: 14px; + margin: 5px 10px; + padding: 5px; + position: absolute; + white-space: nowrap; + z-index: 10002; +} + +.tox-rtc-user-selection { + position: relative; +} + +.tox-rtc-user-cursor { + bottom: 0; + cursor: default; + position: absolute; + top: 0; + width: 2px; +} + +.tox-rtc-user-cursor::before { + background-color: inherit; + border-radius: 50%; + content: ''; + display: block; + height: 8px; + position: absolute; + right: -3px; + top: -3px; + width: 8px; +} + +.tox-rtc-user-cursor:hover::after { + background-color: inherit; + border-radius: 100px; + box-sizing: border-box; + color: #fff; + content: attr(data-user); + display: block; + font-size: 12px; + font-weight: bold; + left: -5px; + min-height: 8px; + min-width: 8px; + padding: 0 12px; + position: absolute; + top: -11px; + white-space: nowrap; + z-index: 1000; +} + +.tox-rtc-user-selection--1 .tox-rtc-user-cursor { + background-color: #2dc26b; +} + +.tox-rtc-user-selection--2 .tox-rtc-user-cursor { + background-color: #e03e2d; +} + +.tox-rtc-user-selection--3 .tox-rtc-user-cursor { + background-color: #f1c40f; +} + +.tox-rtc-user-selection--4 .tox-rtc-user-cursor { + background-color: #3598db; +} + +.tox-rtc-user-selection--5 .tox-rtc-user-cursor { + background-color: #b96ad9; +} + +.tox-rtc-user-selection--6 .tox-rtc-user-cursor { + background-color: #e67e23; +} + +.tox-rtc-user-selection--7 .tox-rtc-user-cursor { + background-color: #aaa69d; +} + +.tox-rtc-user-selection--8 .tox-rtc-user-cursor { + background-color: #f368e0; +} + +.tox-rtc-remote-image { + background: #eaeaea url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%2236%22%20height%3D%2212%22%20viewBox%3D%220%200%2036%2012%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%20%20%3Ccircle%20cx%3D%226%22%20cy%3D%226%22%20r%3D%223%22%20fill%3D%22rgba(0%2C%200%2C%200%2C%20.2)%22%3E%0A%20%20%20%20%3Canimate%20attributeName%3D%22r%22%20values%3D%223%3B5%3B3%22%20calcMode%3D%22linear%22%20dur%3D%221s%22%20repeatCount%3D%22indefinite%22%20%2F%3E%0A%20%20%3C%2Fcircle%3E%0A%20%20%3Ccircle%20cx%3D%2218%22%20cy%3D%226%22%20r%3D%223%22%20fill%3D%22rgba(0%2C%200%2C%200%2C%20.2)%22%3E%0A%20%20%20%20%3Canimate%20attributeName%3D%22r%22%20values%3D%223%3B5%3B3%22%20calcMode%3D%22linear%22%20begin%3D%22.33s%22%20dur%3D%221s%22%20repeatCount%3D%22indefinite%22%20%2F%3E%0A%20%20%3C%2Fcircle%3E%0A%20%20%3Ccircle%20cx%3D%2230%22%20cy%3D%226%22%20r%3D%223%22%20fill%3D%22rgba(0%2C%200%2C%200%2C%20.2)%22%3E%0A%20%20%20%20%3Canimate%20attributeName%3D%22r%22%20values%3D%223%3B5%3B3%22%20calcMode%3D%22linear%22%20begin%3D%22.66s%22%20dur%3D%221s%22%20repeatCount%3D%22indefinite%22%20%2F%3E%0A%20%20%3C%2Fcircle%3E%0A%3C%2Fsvg%3E%0A") no-repeat center center; + border: 1px solid #ccc; + min-height: 240px; + min-width: 320px; +} + +.mce-match-marker { + background: #aaa; + color: #fff; +} + +.mce-match-marker-selected { + background: #39f; + color: #fff; +} + +.mce-match-marker-selected::-moz-selection { + background: #39f; + color: #fff; +} + +.mce-match-marker-selected::selection { + background: #39f; + color: #fff; +} + +.mce-content-body img[data-mce-selected], +.mce-content-body video[data-mce-selected], +.mce-content-body audio[data-mce-selected], +.mce-content-body object[data-mce-selected], +.mce-content-body embed[data-mce-selected], +.mce-content-body table[data-mce-selected] { + outline: 3px solid #4099ff; +} + +.mce-content-body hr[data-mce-selected] { + outline: 3px solid #4099ff; + outline-offset: 1px; +} + +.mce-content-body *[contentEditable=false] *[contentEditable=true]:focus { + outline: 3px solid #4099ff; +} + +.mce-content-body *[contentEditable=false] *[contentEditable=true]:hover { + outline: 3px solid #4099ff; +} + +.mce-content-body *[contentEditable=false][data-mce-selected] { + cursor: not-allowed; + outline: 3px solid #4099ff; +} + +.mce-content-body.mce-content-readonly *[contentEditable=true]:focus, +.mce-content-body.mce-content-readonly *[contentEditable=true]:hover { + outline: none; +} + +.mce-content-body *[data-mce-selected="inline-boundary"] { + background-color: #4099ff; +} + +.mce-content-body .mce-edit-focus { + outline: 3px solid #4099ff; +} + +.mce-content-body td[data-mce-selected], +.mce-content-body th[data-mce-selected] { + position: relative; +} + +.mce-content-body td[data-mce-selected]::-moz-selection, +.mce-content-body th[data-mce-selected]::-moz-selection { + background: none; +} + +.mce-content-body td[data-mce-selected]::selection, +.mce-content-body th[data-mce-selected]::selection { + background: none; +} + +.mce-content-body td[data-mce-selected] *, +.mce-content-body th[data-mce-selected] * { + outline: none; + -webkit-touch-callout: none; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} + +.mce-content-body td[data-mce-selected]::after, +.mce-content-body th[data-mce-selected]::after { + background-color: rgba(180, 215, 255, 0.7); + border: 1px solid transparent; + bottom: -1px; + content: ''; + left: -1px; + mix-blend-mode: lighten; + position: absolute; + right: -1px; + top: -1px; +} + +@media screen and (-ms-high-contrast: active), (-ms-high-contrast: none) { + .mce-content-body td[data-mce-selected]::after, + .mce-content-body th[data-mce-selected]::after { + border-color: rgba(0, 84, 180, 0.7); + } +} + +.mce-content-body img::-moz-selection { + background: none; +} + +.mce-content-body img::selection { + background: none; +} + +.ephox-snooker-resizer-bar { + background-color: #4099ff; + opacity: 0; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} + +.ephox-snooker-resizer-cols { + cursor: col-resize; +} + +.ephox-snooker-resizer-rows { + cursor: row-resize; +} + +.ephox-snooker-resizer-bar.ephox-snooker-resizer-bar-dragging { + opacity: 1; +} + +.mce-spellchecker-word { + background-image: url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D'4'%20height%3D'4'%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%3E%3Cpath%20stroke%3D'%23ff0000'%20fill%3D'none'%20stroke-linecap%3D'round'%20stroke-opacity%3D'.75'%20d%3D'M0%203L2%201%204%203'%2F%3E%3C%2Fsvg%3E%0A"); + background-position: 0 calc(100% + 1px); + background-repeat: repeat-x; + background-size: auto 6px; + cursor: default; + height: 2rem; +} + +.mce-spellchecker-grammar { + background-image: url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D'4'%20height%3D'4'%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%3E%3Cpath%20stroke%3D'%2300A835'%20fill%3D'none'%20stroke-linecap%3D'round'%20d%3D'M0%203L2%201%204%203'%2F%3E%3C%2Fsvg%3E%0A"); + background-position: 0 calc(100% + 1px); + background-repeat: repeat-x; + background-size: auto 6px; + cursor: default; +} + +.mce-toc { + border: 1px solid gray; +} + +.mce-toc h2 { + margin: 4px; +} + +.mce-toc li { + list-style-type: none; +} + +table[style*="border-width: 0px"], +.mce-item-table:not([border]), +.mce-item-table[border="0"], +table[style*="border-width: 0px"] td, +.mce-item-table:not([border]) td, +.mce-item-table[border="0"] td, +table[style*="border-width: 0px"] th, +.mce-item-table:not([border]) th, +.mce-item-table[border="0"] th, +table[style*="border-width: 0px"] caption, +.mce-item-table:not([border]) caption, +.mce-item-table[border="0"] caption { + border: 1px dashed #bbb; +} + +.mce-visualblocks p, +.mce-visualblocks h1, +.mce-visualblocks h2, +.mce-visualblocks h3, +.mce-visualblocks h4, +.mce-visualblocks h5, +.mce-visualblocks h6, +.mce-visualblocks div:not([data-mce-bogus]), +.mce-visualblocks section, +.mce-visualblocks article, +.mce-visualblocks blockquote, +.mce-visualblocks address, +.mce-visualblocks pre, +.mce-visualblocks figure, +.mce-visualblocks figcaption, +.mce-visualblocks hgroup, +.mce-visualblocks aside, +.mce-visualblocks ul, +.mce-visualblocks ol, +.mce-visualblocks dl { + background-repeat: no-repeat; + border: 1px dashed #bbb; + margin-left: 3px; + padding-top: 10px; +} + +.mce-visualblocks p { + background-image: url(data:image/gif;base64,R0lGODlhCQAJAJEAAAAAAP///7u7u////yH5BAEAAAMALAAAAAAJAAkAAAIQnG+CqCN/mlyvsRUpThG6AgA7); +} + +.mce-visualblocks h1 { + background-image: url(data:image/gif;base64,R0lGODlhDQAKAIABALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybGu1JuxHoAfRNRW3TWXyF2YiRUAOw==); +} + +.mce-visualblocks h2 { + background-image: url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8Hybbx4oOuqgTynJd6bGlWg3DkJzoaUAAAOw==); +} + +.mce-visualblocks h3 { + background-image: url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIZjI8Hybbx4oOuqgTynJf2Ln2NOHpQpmhAAQA7); +} + +.mce-visualblocks h4 { + background-image: url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8HybbxInR0zqeAdhtJlXwV1oCll2HaWgAAOw==); +} + +.mce-visualblocks h5 { + background-image: url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8HybbxIoiuwjane4iq5GlW05GgIkIZUAAAOw==); +} + +.mce-visualblocks h6 { + background-image: url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8HybbxIoiuwjan04jep1iZ1XRlAo5bVgAAOw==); +} + +.mce-visualblocks div:not([data-mce-bogus]) { + background-image: url(data:image/gif;base64,R0lGODlhEgAKAIABALu7u////yH5BAEAAAEALAAAAAASAAoAAAIfjI9poI0cgDywrhuxfbrzDEbQM2Ei5aRjmoySW4pAAQA7); +} + +.mce-visualblocks section { + background-image: url(data:image/gif;base64,R0lGODlhKAAKAIABALu7u////yH5BAEAAAEALAAAAAAoAAoAAAI5jI+pywcNY3sBWHdNrplytD2ellDeSVbp+GmWqaDqDMepc8t17Y4vBsK5hDyJMcI6KkuYU+jpjLoKADs=); +} + +.mce-visualblocks article { + background-image: url(data:image/gif;base64,R0lGODlhKgAKAIABALu7u////yH5BAEAAAEALAAAAAAqAAoAAAI6jI+pywkNY3wG0GBvrsd2tXGYSGnfiF7ikpXemTpOiJScasYoDJJrjsG9gkCJ0ag6KhmaIe3pjDYBBQA7); +} + +.mce-visualblocks blockquote { + background-image: url(data:image/gif;base64,R0lGODlhPgAKAIABALu7u////yH5BAEAAAEALAAAAAA+AAoAAAJPjI+py+0Knpz0xQDyuUhvfoGgIX5iSKZYgq5uNL5q69asZ8s5rrf0yZmpNkJZzFesBTu8TOlDVAabUyatguVhWduud3EyiUk45xhTTgMBBQA7); +} + +.mce-visualblocks address { + background-image: url(data:image/gif;base64,R0lGODlhLQAKAIABALu7u////yH5BAEAAAEALAAAAAAtAAoAAAI/jI+pywwNozSP1gDyyZcjb3UaRpXkWaXmZW4OqKLhBmLs+K263DkJK7OJeifh7FicKD9A1/IpGdKkyFpNmCkAADs=); +} + +.mce-visualblocks pre { + background-image: url(data:image/gif;base64,R0lGODlhFQAKAIABALu7uwAAACH5BAEAAAEALAAAAAAVAAoAAAIjjI+ZoN0cgDwSmnpz1NCueYERhnibZVKLNnbOq8IvKpJtVQAAOw==); +} + +.mce-visualblocks figure { + background-image: url(data:image/gif;base64,R0lGODlhJAAKAIAAALu7u////yH5BAEAAAEALAAAAAAkAAoAAAI0jI+py+2fwAHUSFvD3RlvG4HIp4nX5JFSpnZUJ6LlrM52OE7uSWosBHScgkSZj7dDKnWAAgA7); +} + +.mce-visualblocks figcaption { + border: 1px dashed #bbb; +} + +.mce-visualblocks hgroup { + background-image: url(data:image/gif;base64,R0lGODlhJwAKAIABALu7uwAAACH5BAEAAAEALAAAAAAnAAoAAAI3jI+pywYNI3uB0gpsRtt5fFnfNZaVSYJil4Wo03Hv6Z62uOCgiXH1kZIIJ8NiIxRrAZNMZAtQAAA7); +} + +.mce-visualblocks aside { + background-image: url(data:image/gif;base64,R0lGODlhHgAKAIABAKqqqv///yH5BAEAAAEALAAAAAAeAAoAAAItjI+pG8APjZOTzgtqy7I3f1yehmQcFY4WKZbqByutmW4aHUd6vfcVbgudgpYCADs=); +} + +.mce-visualblocks ul { + background-image: url(data:image/gif;base64,R0lGODlhDQAKAIAAALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybGuYnqUVSjvw26DzzXiqIDlVwAAOw==); +} + +.mce-visualblocks ol { + background-image: url(data:image/gif;base64,R0lGODlhDQAKAIABALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybH6HHt0qourxC6CvzXieHyeWQAAOw==); +} + +.mce-visualblocks dl { + background-image: url(data:image/gif;base64,R0lGODlhDQAKAIABALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybEOnmOvUoWznTqeuEjNSCqeGRUAOw==); +} + +.mce-visualblocks:not([dir=rtl]) p, +.mce-visualblocks:not([dir=rtl]) h1, +.mce-visualblocks:not([dir=rtl]) h2, +.mce-visualblocks:not([dir=rtl]) h3, +.mce-visualblocks:not([dir=rtl]) h4, +.mce-visualblocks:not([dir=rtl]) h5, +.mce-visualblocks:not([dir=rtl]) h6, +.mce-visualblocks:not([dir=rtl]) div:not([data-mce-bogus]), +.mce-visualblocks:not([dir=rtl]) section, +.mce-visualblocks:not([dir=rtl]) article, +.mce-visualblocks:not([dir=rtl]) blockquote, +.mce-visualblocks:not([dir=rtl]) address, +.mce-visualblocks:not([dir=rtl]) pre, +.mce-visualblocks:not([dir=rtl]) figure, +.mce-visualblocks:not([dir=rtl]) figcaption, +.mce-visualblocks:not([dir=rtl]) hgroup, +.mce-visualblocks:not([dir=rtl]) aside, +.mce-visualblocks:not([dir=rtl]) ul, +.mce-visualblocks:not([dir=rtl]) ol, +.mce-visualblocks:not([dir=rtl]) dl { + margin-left: 3px; +} + +.mce-visualblocks[dir=rtl] p, +.mce-visualblocks[dir=rtl] h1, +.mce-visualblocks[dir=rtl] h2, +.mce-visualblocks[dir=rtl] h3, +.mce-visualblocks[dir=rtl] h4, +.mce-visualblocks[dir=rtl] h5, +.mce-visualblocks[dir=rtl] h6, +.mce-visualblocks[dir=rtl] div:not([data-mce-bogus]), +.mce-visualblocks[dir=rtl] section, +.mce-visualblocks[dir=rtl] article, +.mce-visualblocks[dir=rtl] blockquote, +.mce-visualblocks[dir=rtl] address, +.mce-visualblocks[dir=rtl] pre, +.mce-visualblocks[dir=rtl] figure, +.mce-visualblocks[dir=rtl] figcaption, +.mce-visualblocks[dir=rtl] hgroup, +.mce-visualblocks[dir=rtl] aside, +.mce-visualblocks[dir=rtl] ul, +.mce-visualblocks[dir=rtl] ol, +.mce-visualblocks[dir=rtl] dl { + background-position-x: right; + margin-right: 3px; +} + +.mce-nbsp, +.mce-shy { + background: #aaa; +} + +.mce-shy::after { + content: '-'; +} + +body { + font-family: sans-serif; +} + +table { + border-collapse: collapse; +} diff --git a/frontend/public/tinymce-dataease-private/skins/ui/oxide-dark/content.inline.css b/frontend/public/tinymce-dataease-private/skins/ui/oxide-dark/content.inline.css new file mode 100644 index 0000000..fee4323 --- /dev/null +++ b/frontend/public/tinymce-dataease-private/skins/ui/oxide-dark/content.inline.css @@ -0,0 +1,861 @@ +/** + * Copyright (c) Tiny Technologies, Inc. All rights reserved. + * Licensed under the LGPL or a commercial license. + * For LGPL see License.txt in the project root for license information. + * For commercial licenses see https://www.tiny.cloud/ + */ +.mce-content-body .mce-item-anchor { + background: transparent url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D'8'%20height%3D'12'%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%3E%3Cpath%20d%3D'M0%200L8%200%208%2012%204.09117821%209%200%2012z'%2F%3E%3C%2Fsvg%3E%0A") no-repeat center; + cursor: default; + display: inline-block; + height: 12px !important; + padding: 0 2px; + -webkit-user-modify: read-only; + -moz-user-modify: read-only; + -webkit-user-select: all; + -moz-user-select: all; + -ms-user-select: all; + user-select: all; + width: 8px !important; +} + +.mce-content-body .mce-item-anchor[data-mce-selected] { + outline-offset: 1px; +} + +.tox-comments-visible .tox-comment { + background-color: #fff0b7; +} + +.tox-comments-visible .tox-comment--active { + background-color: #ffe168; +} + +.tox-checklist > li:not(.tox-checklist--hidden) { + list-style: none; + margin: 0.25em 0; +} + +.tox-checklist > li:not(.tox-checklist--hidden)::before { + content: url("data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2216%22%20height%3D%2216%22%20viewBox%3D%220%200%2016%2016%22%3E%3Cg%20id%3D%22checklist-unchecked%22%20fill%3D%22none%22%20fill-rule%3D%22evenodd%22%3E%3Crect%20id%3D%22Rectangle%22%20width%3D%2215%22%20height%3D%2215%22%20x%3D%22.5%22%20y%3D%22.5%22%20fill-rule%3D%22nonzero%22%20stroke%3D%22%234C4C4C%22%20rx%3D%222%22%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E%0A"); + cursor: pointer; + height: 1em; + margin-left: -1.5em; + margin-top: 0.125em; + position: absolute; + width: 1em; +} + +.tox-checklist li:not(.tox-checklist--hidden).tox-checklist--checked::before { + content: url("data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2216%22%20height%3D%2216%22%20viewBox%3D%220%200%2016%2016%22%3E%3Cg%20id%3D%22checklist-checked%22%20fill%3D%22none%22%20fill-rule%3D%22evenodd%22%3E%3Crect%20id%3D%22Rectangle%22%20width%3D%2216%22%20height%3D%2216%22%20fill%3D%22%234099FF%22%20fill-rule%3D%22nonzero%22%20rx%3D%222%22%2F%3E%3Cpath%20id%3D%22Path%22%20fill%3D%22%23FFF%22%20fill-rule%3D%22nonzero%22%20d%3D%22M11.5703186%2C3.14417309%20C11.8516238%2C2.73724603%2012.4164781%2C2.62829933%2012.83558%2C2.89774797%20C13.260121%2C3.17069355%2013.3759736%2C3.72932262%2013.0909105%2C4.14168582%20L7.7580587%2C11.8560195%20C7.43776896%2C12.3193404%206.76483983%2C12.3852142%206.35607322%2C11.9948725%20L3.02491697%2C8.8138662%20C2.66090143%2C8.46625845%202.65798871%2C7.89594698%203.01850234%2C7.54483354%20C3.373942%2C7.19866177%203.94940006%2C7.19592841%204.30829608%2C7.5386474%20L6.85276923%2C9.9684299%20L11.5703186%2C3.14417309%20Z%22%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E%0A"); +} + +[dir=rtl] .tox-checklist > li:not(.tox-checklist--hidden)::before { + margin-left: 0; + margin-right: -1.5em; +} + +/* stylelint-disable */ +/* http://prismjs.com/ */ +/** + * prism.js default theme for JavaScript, CSS and HTML + * Based on dabblet (http://dabblet.com) + * @author Lea Verou + */ +code[class*="language-"], +pre[class*="language-"] { + color: black; + background: none; + text-shadow: 0 1px white; + font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace; + font-size: 1em; + text-align: left; + white-space: pre; + word-spacing: normal; + word-break: normal; + word-wrap: normal; + line-height: 1.5; + -moz-tab-size: 4; + tab-size: 4; + -webkit-hyphens: none; + -ms-hyphens: none; + hyphens: none; +} + +pre[class*="language-"]::-moz-selection, +pre[class*="language-"] ::-moz-selection, +code[class*="language-"]::-moz-selection, +code[class*="language-"] ::-moz-selection { + text-shadow: none; + background: #b3d4fc; +} + +pre[class*="language-"]::selection, +pre[class*="language-"] ::selection, +code[class*="language-"]::selection, +code[class*="language-"] ::selection { + text-shadow: none; + background: #b3d4fc; +} + +@media print { + code[class*="language-"], + pre[class*="language-"] { + text-shadow: none; + } +} + +/* Code blocks */ +pre[class*="language-"] { + padding: 1em; + margin: 0.5em 0; + overflow: auto; +} + +:not(pre) > code[class*="language-"], +pre[class*="language-"] { + background: #f5f2f0; +} + +/* Inline code */ +:not(pre) > code[class*="language-"] { + padding: 0.1em; + border-radius: 0.3em; + white-space: normal; +} + +.token.comment, +.token.prolog, +.token.doctype, +.token.cdata { + color: slategray; +} + +.token.punctuation { + color: #999; +} + +.namespace { + opacity: 0.7; +} + +.token.property, +.token.tag, +.token.boolean, +.token.number, +.token.constant, +.token.symbol, +.token.deleted { + color: #905; +} + +.token.selector, +.token.attr-name, +.token.string, +.token.char, +.token.builtin, +.token.inserted { + color: #690; +} + +.token.operator, +.token.entity, +.token.url, +.language-css .token.string, +.style .token.string { + color: #9a6e3a; + background: hsla(0, 0%, 100%, 0.5); +} + +.token.atrule, +.token.attr-value, +.token.keyword { + color: #07a; +} + +.token.function, +.token.class-name { + color: #DD4A68; +} + +.token.regex, +.token.important, +.token.variable { + color: #e90; +} + +.token.important, +.token.bold { + font-weight: bold; +} + +.token.italic { + font-style: italic; +} + +.token.entity { + cursor: help; +} + +/* stylelint-enable */ +.mce-content-body { + overflow-wrap: break-word; + word-wrap: break-word; +} + +.mce-content-body .mce-visual-caret { + background-color: black; + background-color: currentColor; + position: absolute; +} + +.mce-content-body .mce-visual-caret-hidden { + display: none; +} + +.mce-content-body *[data-mce-caret] { + left: -1000px; + margin: 0; + padding: 0; + position: absolute; + right: auto; + top: 0; +} + +.mce-content-body .mce-offscreen-selection { + left: -2000000px; + max-width: 1000000px; + position: absolute; +} + +.mce-content-body *[contentEditable=false] { + cursor: default; +} + +.mce-content-body *[contentEditable=true] { + cursor: text; +} + +.tox-cursor-format-painter { + cursor: url("data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2224%22%20height%3D%2224%22%20viewBox%3D%220%200%2024%2024%22%3E%0A%20%20%3Cg%20fill%3D%22none%22%20fill-rule%3D%22evenodd%22%3E%0A%20%20%20%20%3Cpath%20fill%3D%22%23000%22%20fill-rule%3D%22nonzero%22%20d%3D%22M15%2C6%20C15%2C5.45%2014.55%2C5%2014%2C5%20L6%2C5%20C5.45%2C5%205%2C5.45%205%2C6%20L5%2C10%20C5%2C10.55%205.45%2C11%206%2C11%20L14%2C11%20C14.55%2C11%2015%2C10.55%2015%2C10%20L15%2C9%20L16%2C9%20L16%2C12%20L9%2C12%20L9%2C19%20C9%2C19.55%209.45%2C20%2010%2C20%20L11%2C20%20C11.55%2C20%2012%2C19.55%2012%2C19%20L12%2C14%20L18%2C14%20L18%2C7%20L15%2C7%20L15%2C6%20Z%22%2F%3E%0A%20%20%20%20%3Cpath%20fill%3D%22%23000%22%20fill-rule%3D%22nonzero%22%20d%3D%22M1%2C1%20L8.25%2C1%20C8.66421356%2C1%209%2C1.33578644%209%2C1.75%20L9%2C1.75%20C9%2C2.16421356%208.66421356%2C2.5%208.25%2C2.5%20L2.5%2C2.5%20L2.5%2C8.25%20C2.5%2C8.66421356%202.16421356%2C9%201.75%2C9%20L1.75%2C9%20C1.33578644%2C9%201%2C8.66421356%201%2C8.25%20L1%2C1%20Z%22%2F%3E%0A%20%20%3C%2Fg%3E%0A%3C%2Fsvg%3E%0A"), default; +} + +.mce-content-body figure.align-left { + float: left; +} + +.mce-content-body figure.align-right { + float: right; +} + +.mce-content-body figure.image.align-center { + display: table; + margin-left: auto; + margin-right: auto; +} + +.mce-preview-object { + border: 1px solid gray; + display: inline-block; + line-height: 0; + margin: 0 2px 0 2px; + position: relative; +} + +.mce-preview-object .mce-shim { + background: url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7); + height: 100%; + left: 0; + position: absolute; + top: 0; + width: 100%; +} + +.mce-preview-object[data-mce-selected="2"] .mce-shim { + display: none; +} + +.mce-object { + background: transparent url("data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2224%22%20height%3D%2224%22%3E%3Cpath%20d%3D%22M4%203h16a1%201%200%200%201%201%201v16a1%201%200%200%201-1%201H4a1%201%200%200%201-1-1V4a1%201%200%200%201%201-1zm1%202v14h14V5H5zm4.79%202.565l5.64%204.028a.5.5%200%200%201%200%20.814l-5.64%204.028a.5.5%200%200%201-.79-.407V7.972a.5.5%200%200%201%20.79-.407z%22%2F%3E%3C%2Fsvg%3E%0A") no-repeat center; + border: 1px dashed #aaa; +} + +.mce-pagebreak { + border: 1px dashed #aaa; + cursor: default; + display: block; + height: 5px; + margin-top: 15px; + page-break-before: always; + width: 100%; +} + +@media print { + .mce-pagebreak { + border: 0; + } +} + +.tiny-pageembed .mce-shim { + background: url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7); + height: 100%; + left: 0; + position: absolute; + top: 0; + width: 100%; +} + +.tiny-pageembed[data-mce-selected="2"] .mce-shim { + display: none; +} + +.tiny-pageembed { + display: inline-block; + position: relative; +} + +.tiny-pageembed--21by9, +.tiny-pageembed--16by9, +.tiny-pageembed--4by3, +.tiny-pageembed--1by1 { + display: block; + overflow: hidden; + padding: 0; + position: relative; + width: 100%; +} + +.tiny-pageembed--21by9 { + padding-top: 42.857143%; +} + +.tiny-pageembed--16by9 { + padding-top: 56.25%; +} + +.tiny-pageembed--4by3 { + padding-top: 75%; +} + +.tiny-pageembed--1by1 { + padding-top: 100%; +} + +.tiny-pageembed--21by9 iframe, +.tiny-pageembed--16by9 iframe, +.tiny-pageembed--4by3 iframe, +.tiny-pageembed--1by1 iframe { + border: 0; + height: 100%; + left: 0; + position: absolute; + top: 0; + width: 100%; +} + +.mce-content-body[data-mce-placeholder] { + position: relative; +} + +.mce-content-body[data-mce-placeholder]:not(.mce-visualblocks)::before { + color: rgba(34, 47, 62, 0.7); + content: attr(data-mce-placeholder); + position: absolute; +} + +.mce-content-body:not([dir=rtl])[data-mce-placeholder]:not(.mce-visualblocks)::before { + left: 1px; + color:#a1b7cb; +} + +.mce-content-body[dir=rtl][data-mce-placeholder]:not(.mce-visualblocks)::before { + right: 1px; +} + +.mce-content-body div.mce-resizehandle { + background-color: #4099ff; + border-color: #4099ff; + border-style: solid; + border-width: 1px; + box-sizing: border-box; + height: 10px; + position: absolute; + width: 10px; + z-index: 10000; +} + +.mce-content-body div.mce-resizehandle:hover { + background-color: #4099ff; +} + +.mce-content-body div.mce-resizehandle:nth-of-type(1) { + cursor: nwse-resize; +} + +.mce-content-body div.mce-resizehandle:nth-of-type(2) { + cursor: nesw-resize; +} + +.mce-content-body div.mce-resizehandle:nth-of-type(3) { + cursor: nwse-resize; +} + +.mce-content-body div.mce-resizehandle:nth-of-type(4) { + cursor: nesw-resize; +} + +.mce-content-body .mce-resize-backdrop { + z-index: 10000; +} + +.mce-content-body .mce-clonedresizable { + cursor: default; + opacity: 0.5; + outline: 1px dashed black; + position: absolute; + z-index: 10001; +} + +.mce-content-body .mce-clonedresizable.mce-resizetable-columns th, +.mce-content-body .mce-clonedresizable.mce-resizetable-columns td { + border: 0; +} + +.mce-content-body .mce-resize-helper { + background: #555; + background: rgba(0, 0, 0, 0.75); + border: 1px; + border-radius: 3px; + color: white; + display: none; + font-family: sans-serif; + font-size: 12px; + line-height: 14px; + margin: 5px 10px; + padding: 5px; + position: absolute; + white-space: nowrap; + z-index: 10002; +} + +.tox-rtc-user-selection { + position: relative; +} + +.tox-rtc-user-cursor { + bottom: 0; + cursor: default; + position: absolute; + top: 0; + width: 2px; +} + +.tox-rtc-user-cursor::before { + background-color: inherit; + border-radius: 50%; + content: ''; + display: block; + height: 8px; + position: absolute; + right: -3px; + top: -3px; + width: 8px; +} + +.tox-rtc-user-cursor:hover::after { + background-color: inherit; + border-radius: 100px; + box-sizing: border-box; + color: #fff; + content: attr(data-user); + display: block; + font-size: 12px; + font-weight: bold; + left: -5px; + min-height: 8px; + min-width: 8px; + padding: 0 12px; + position: absolute; + top: -11px; + white-space: nowrap; + z-index: 1000; +} + +.tox-rtc-user-selection--1 .tox-rtc-user-cursor { + background-color: #2dc26b; +} + +.tox-rtc-user-selection--2 .tox-rtc-user-cursor { + background-color: #e03e2d; +} + +.tox-rtc-user-selection--3 .tox-rtc-user-cursor { + background-color: #f1c40f; +} + +.tox-rtc-user-selection--4 .tox-rtc-user-cursor { + background-color: #3598db; +} + +.tox-rtc-user-selection--5 .tox-rtc-user-cursor { + background-color: #b96ad9; +} + +.tox-rtc-user-selection--6 .tox-rtc-user-cursor { + background-color: #e67e23; +} + +.tox-rtc-user-selection--7 .tox-rtc-user-cursor { + background-color: #aaa69d; +} + +.tox-rtc-user-selection--8 .tox-rtc-user-cursor { + background-color: #f368e0; +} + +.tox-rtc-remote-image { + background: #eaeaea url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%2236%22%20height%3D%2212%22%20viewBox%3D%220%200%2036%2012%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%20%20%3Ccircle%20cx%3D%226%22%20cy%3D%226%22%20r%3D%223%22%20fill%3D%22rgba(0%2C%200%2C%200%2C%20.2)%22%3E%0A%20%20%20%20%3Canimate%20attributeName%3D%22r%22%20values%3D%223%3B5%3B3%22%20calcMode%3D%22linear%22%20dur%3D%221s%22%20repeatCount%3D%22indefinite%22%20%2F%3E%0A%20%20%3C%2Fcircle%3E%0A%20%20%3Ccircle%20cx%3D%2218%22%20cy%3D%226%22%20r%3D%223%22%20fill%3D%22rgba(0%2C%200%2C%200%2C%20.2)%22%3E%0A%20%20%20%20%3Canimate%20attributeName%3D%22r%22%20values%3D%223%3B5%3B3%22%20calcMode%3D%22linear%22%20begin%3D%22.33s%22%20dur%3D%221s%22%20repeatCount%3D%22indefinite%22%20%2F%3E%0A%20%20%3C%2Fcircle%3E%0A%20%20%3Ccircle%20cx%3D%2230%22%20cy%3D%226%22%20r%3D%223%22%20fill%3D%22rgba(0%2C%200%2C%200%2C%20.2)%22%3E%0A%20%20%20%20%3Canimate%20attributeName%3D%22r%22%20values%3D%223%3B5%3B3%22%20calcMode%3D%22linear%22%20begin%3D%22.66s%22%20dur%3D%221s%22%20repeatCount%3D%22indefinite%22%20%2F%3E%0A%20%20%3C%2Fcircle%3E%0A%3C%2Fsvg%3E%0A") no-repeat center center; + border: 1px solid #ccc; + min-height: 240px; + min-width: 320px; +} + +.mce-match-marker { + background: #aaa; + color: #fff; +} + +.mce-match-marker-selected { + background: #39f; + color: #fff; +} + +.mce-match-marker-selected::-moz-selection { + background: #39f; + color: #fff; +} + +.mce-match-marker-selected::selection { + background: #39f; + color: #fff; +} + +.mce-content-body img[data-mce-selected], +.mce-content-body video[data-mce-selected], +.mce-content-body audio[data-mce-selected], +.mce-content-body object[data-mce-selected], +.mce-content-body embed[data-mce-selected], +.mce-content-body table[data-mce-selected] { + outline: 3px solid #b4d7ff; +} + +.mce-content-body hr[data-mce-selected] { + outline: 3px solid #b4d7ff; + outline-offset: 1px; +} + +.mce-content-body *[contentEditable=false] *[contentEditable=true]:focus { + outline: 3px solid #b4d7ff; +} + +.mce-content-body *[contentEditable=false] *[contentEditable=true]:hover { + outline: 3px solid #b4d7ff; +} + +.mce-content-body *[contentEditable=false][data-mce-selected] { + cursor: not-allowed; + outline: 3px solid #b4d7ff; +} + +.mce-content-body.mce-content-readonly *[contentEditable=true]:focus, +.mce-content-body.mce-content-readonly *[contentEditable=true]:hover { + outline: none; +} + +.mce-content-body *[data-mce-selected="inline-boundary"] { + background-color: #b4d7ff; +} + +.mce-content-body .mce-edit-focus { + outline: 3px solid #b4d7ff; +} + +.mce-content-body td[data-mce-selected], +.mce-content-body th[data-mce-selected] { + position: relative; +} + +.mce-content-body td[data-mce-selected]::-moz-selection, +.mce-content-body th[data-mce-selected]::-moz-selection { + background: none; +} + +.mce-content-body td[data-mce-selected]::selection, +.mce-content-body th[data-mce-selected]::selection { + background: none; +} + +.mce-content-body td[data-mce-selected] *, +.mce-content-body th[data-mce-selected] * { + outline: none; + -webkit-touch-callout: none; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} + +.mce-content-body td[data-mce-selected]::after, +.mce-content-body th[data-mce-selected]::after { + background-color: rgba(180, 215, 255, 0.7); + border: 1px solid rgba(180, 215, 255, 0.7); + bottom: -1px; + content: ''; + left: -1px; + mix-blend-mode: multiply; + position: absolute; + right: -1px; + top: -1px; +} + +@media screen and (-ms-high-contrast: active), (-ms-high-contrast: none) { + .mce-content-body td[data-mce-selected]::after, + .mce-content-body th[data-mce-selected]::after { + border-color: rgba(0, 84, 180, 0.7); + } +} + +.mce-content-body img::-moz-selection { + background: none; +} + +.mce-content-body img::selection { + background: none; +} + +.ephox-snooker-resizer-bar { + background-color: #b4d7ff; + opacity: 0; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} + +.ephox-snooker-resizer-cols { + cursor: col-resize; +} + +.ephox-snooker-resizer-rows { + cursor: row-resize; +} + +.ephox-snooker-resizer-bar.ephox-snooker-resizer-bar-dragging { + opacity: 1; +} + +.mce-spellchecker-word { + background-image: url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D'4'%20height%3D'4'%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%3E%3Cpath%20stroke%3D'%23ff0000'%20fill%3D'none'%20stroke-linecap%3D'round'%20stroke-opacity%3D'.75'%20d%3D'M0%203L2%201%204%203'%2F%3E%3C%2Fsvg%3E%0A"); + background-position: 0 calc(100% + 1px); + background-repeat: repeat-x; + background-size: auto 6px; + cursor: default; + height: 2rem; +} + +.mce-spellchecker-grammar { + background-image: url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D'4'%20height%3D'4'%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%3E%3Cpath%20stroke%3D'%2300A835'%20fill%3D'none'%20stroke-linecap%3D'round'%20d%3D'M0%203L2%201%204%203'%2F%3E%3C%2Fsvg%3E%0A"); + background-position: 0 calc(100% + 1px); + background-repeat: repeat-x; + background-size: auto 6px; + cursor: default; +} + +.mce-toc { + border: 1px solid gray; +} + +.mce-toc h2 { + margin: 4px; +} + +.mce-toc li { + list-style-type: none; +} + +table[style*="border-width: 0px"], +.mce-item-table:not([border]), +.mce-item-table[border="0"], +table[style*="border-width: 0px"] td, +.mce-item-table:not([border]) td, +.mce-item-table[border="0"] td, +table[style*="border-width: 0px"] th, +.mce-item-table:not([border]) th, +.mce-item-table[border="0"] th, +table[style*="border-width: 0px"] caption, +.mce-item-table:not([border]) caption, +.mce-item-table[border="0"] caption { + border: 1px dashed #bbb; +} + +.mce-visualblocks p, +.mce-visualblocks h1, +.mce-visualblocks h2, +.mce-visualblocks h3, +.mce-visualblocks h4, +.mce-visualblocks h5, +.mce-visualblocks h6, +.mce-visualblocks div:not([data-mce-bogus]), +.mce-visualblocks section, +.mce-visualblocks article, +.mce-visualblocks blockquote, +.mce-visualblocks address, +.mce-visualblocks pre, +.mce-visualblocks figure, +.mce-visualblocks figcaption, +.mce-visualblocks hgroup, +.mce-visualblocks aside, +.mce-visualblocks ul, +.mce-visualblocks ol, +.mce-visualblocks dl { + background-repeat: no-repeat; + border: 1px dashed #bbb; + margin-left: 3px; + padding-top: 10px; +} + +.mce-visualblocks p { + background-image: url(data:image/gif;base64,R0lGODlhCQAJAJEAAAAAAP///7u7u////yH5BAEAAAMALAAAAAAJAAkAAAIQnG+CqCN/mlyvsRUpThG6AgA7); +} + +.mce-visualblocks h1 { + background-image: url(data:image/gif;base64,R0lGODlhDQAKAIABALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybGu1JuxHoAfRNRW3TWXyF2YiRUAOw==); +} + +.mce-visualblocks h2 { + background-image: url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8Hybbx4oOuqgTynJd6bGlWg3DkJzoaUAAAOw==); +} + +.mce-visualblocks h3 { + background-image: url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIZjI8Hybbx4oOuqgTynJf2Ln2NOHpQpmhAAQA7); +} + +.mce-visualblocks h4 { + background-image: url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8HybbxInR0zqeAdhtJlXwV1oCll2HaWgAAOw==); +} + +.mce-visualblocks h5 { + background-image: url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8HybbxIoiuwjane4iq5GlW05GgIkIZUAAAOw==); +} + +.mce-visualblocks h6 { + background-image: url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8HybbxIoiuwjan04jep1iZ1XRlAo5bVgAAOw==); +} + +.mce-visualblocks div:not([data-mce-bogus]) { + background-image: url(data:image/gif;base64,R0lGODlhEgAKAIABALu7u////yH5BAEAAAEALAAAAAASAAoAAAIfjI9poI0cgDywrhuxfbrzDEbQM2Ei5aRjmoySW4pAAQA7); +} + +.mce-visualblocks section { + background-image: url(data:image/gif;base64,R0lGODlhKAAKAIABALu7u////yH5BAEAAAEALAAAAAAoAAoAAAI5jI+pywcNY3sBWHdNrplytD2ellDeSVbp+GmWqaDqDMepc8t17Y4vBsK5hDyJMcI6KkuYU+jpjLoKADs=); +} + +.mce-visualblocks article { + background-image: url(data:image/gif;base64,R0lGODlhKgAKAIABALu7u////yH5BAEAAAEALAAAAAAqAAoAAAI6jI+pywkNY3wG0GBvrsd2tXGYSGnfiF7ikpXemTpOiJScasYoDJJrjsG9gkCJ0ag6KhmaIe3pjDYBBQA7); +} + +.mce-visualblocks blockquote { + background-image: url(data:image/gif;base64,R0lGODlhPgAKAIABALu7u////yH5BAEAAAEALAAAAAA+AAoAAAJPjI+py+0Knpz0xQDyuUhvfoGgIX5iSKZYgq5uNL5q69asZ8s5rrf0yZmpNkJZzFesBTu8TOlDVAabUyatguVhWduud3EyiUk45xhTTgMBBQA7); +} + +.mce-visualblocks address { + background-image: url(data:image/gif;base64,R0lGODlhLQAKAIABALu7u////yH5BAEAAAEALAAAAAAtAAoAAAI/jI+pywwNozSP1gDyyZcjb3UaRpXkWaXmZW4OqKLhBmLs+K263DkJK7OJeifh7FicKD9A1/IpGdKkyFpNmCkAADs=); +} + +.mce-visualblocks pre { + background-image: url(data:image/gif;base64,R0lGODlhFQAKAIABALu7uwAAACH5BAEAAAEALAAAAAAVAAoAAAIjjI+ZoN0cgDwSmnpz1NCueYERhnibZVKLNnbOq8IvKpJtVQAAOw==); +} + +.mce-visualblocks figure { + background-image: url(data:image/gif;base64,R0lGODlhJAAKAIAAALu7u////yH5BAEAAAEALAAAAAAkAAoAAAI0jI+py+2fwAHUSFvD3RlvG4HIp4nX5JFSpnZUJ6LlrM52OE7uSWosBHScgkSZj7dDKnWAAgA7); +} + +.mce-visualblocks figcaption { + border: 1px dashed #bbb; +} + +.mce-visualblocks hgroup { + background-image: url(data:image/gif;base64,R0lGODlhJwAKAIABALu7uwAAACH5BAEAAAEALAAAAAAnAAoAAAI3jI+pywYNI3uB0gpsRtt5fFnfNZaVSYJil4Wo03Hv6Z62uOCgiXH1kZIIJ8NiIxRrAZNMZAtQAAA7); +} + +.mce-visualblocks aside { + background-image: url(data:image/gif;base64,R0lGODlhHgAKAIABAKqqqv///yH5BAEAAAEALAAAAAAeAAoAAAItjI+pG8APjZOTzgtqy7I3f1yehmQcFY4WKZbqByutmW4aHUd6vfcVbgudgpYCADs=); +} + +.mce-visualblocks ul { + background-image: url(data:image/gif;base64,R0lGODlhDQAKAIAAALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybGuYnqUVSjvw26DzzXiqIDlVwAAOw==); +} + +.mce-visualblocks ol { + background-image: url(data:image/gif;base64,R0lGODlhDQAKAIABALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybH6HHt0qourxC6CvzXieHyeWQAAOw==); +} + +.mce-visualblocks dl { + background-image: url(data:image/gif;base64,R0lGODlhDQAKAIABALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybEOnmOvUoWznTqeuEjNSCqeGRUAOw==); +} + +.mce-visualblocks:not([dir=rtl]) p, +.mce-visualblocks:not([dir=rtl]) h1, +.mce-visualblocks:not([dir=rtl]) h2, +.mce-visualblocks:not([dir=rtl]) h3, +.mce-visualblocks:not([dir=rtl]) h4, +.mce-visualblocks:not([dir=rtl]) h5, +.mce-visualblocks:not([dir=rtl]) h6, +.mce-visualblocks:not([dir=rtl]) div:not([data-mce-bogus]), +.mce-visualblocks:not([dir=rtl]) section, +.mce-visualblocks:not([dir=rtl]) article, +.mce-visualblocks:not([dir=rtl]) blockquote, +.mce-visualblocks:not([dir=rtl]) address, +.mce-visualblocks:not([dir=rtl]) pre, +.mce-visualblocks:not([dir=rtl]) figure, +.mce-visualblocks:not([dir=rtl]) figcaption, +.mce-visualblocks:not([dir=rtl]) hgroup, +.mce-visualblocks:not([dir=rtl]) aside, +.mce-visualblocks:not([dir=rtl]) ul, +.mce-visualblocks:not([dir=rtl]) ol, +.mce-visualblocks:not([dir=rtl]) dl { + margin-left: 3px; +} + +.mce-visualblocks[dir=rtl] p, +.mce-visualblocks[dir=rtl] h1, +.mce-visualblocks[dir=rtl] h2, +.mce-visualblocks[dir=rtl] h3, +.mce-visualblocks[dir=rtl] h4, +.mce-visualblocks[dir=rtl] h5, +.mce-visualblocks[dir=rtl] h6, +.mce-visualblocks[dir=rtl] div:not([data-mce-bogus]), +.mce-visualblocks[dir=rtl] section, +.mce-visualblocks[dir=rtl] article, +.mce-visualblocks[dir=rtl] blockquote, +.mce-visualblocks[dir=rtl] address, +.mce-visualblocks[dir=rtl] pre, +.mce-visualblocks[dir=rtl] figure, +.mce-visualblocks[dir=rtl] figcaption, +.mce-visualblocks[dir=rtl] hgroup, +.mce-visualblocks[dir=rtl] aside, +.mce-visualblocks[dir=rtl] ul, +.mce-visualblocks[dir=rtl] ol, +.mce-visualblocks[dir=rtl] dl { + background-position-x: right; + margin-right: 3px; +} + +.mce-nbsp, +.mce-shy { + background: #aaa; +} + +.mce-shy::after { + content: '-'; +} diff --git a/frontend/public/tinymce-dataease-private/skins/ui/oxide-dark/content.inline.min.css b/frontend/public/tinymce-dataease-private/skins/ui/oxide-dark/content.inline.min.css new file mode 100644 index 0000000..5c66aca --- /dev/null +++ b/frontend/public/tinymce-dataease-private/skins/ui/oxide-dark/content.inline.min.css @@ -0,0 +1,7 @@ +/** + * Copyright (c) Tiny Technologies, Inc. All rights reserved. + * Licensed under the LGPL or a commercial license. + * For LGPL see License.txt in the project root for license information. + * For commercial licenses see https://www.tiny.cloud/ + */ +.mce-content-body .mce-item-anchor{background:transparent url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D'8'%20height%3D'12'%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%3E%3Cpath%20d%3D'M0%200L8%200%208%2012%204.09117821%209%200%2012z'%2F%3E%3C%2Fsvg%3E%0A") no-repeat center;cursor:default;display:inline-block;height:12px!important;padding:0 2px;-webkit-user-modify:read-only;-moz-user-modify:read-only;-webkit-user-select:all;-moz-user-select:all;-ms-user-select:all;user-select:all;width:8px!important}.mce-content-body .mce-item-anchor[data-mce-selected]{outline-offset:1px}.tox-comments-visible .tox-comment{background-color:#fff0b7}.tox-comments-visible .tox-comment--active{background-color:#ffe168}.tox-checklist>li:not(.tox-checklist--hidden){list-style:none;margin:.25em 0}.tox-checklist>li:not(.tox-checklist--hidden)::before{content:url("data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2216%22%20height%3D%2216%22%20viewBox%3D%220%200%2016%2016%22%3E%3Cg%20id%3D%22checklist-unchecked%22%20fill%3D%22none%22%20fill-rule%3D%22evenodd%22%3E%3Crect%20id%3D%22Rectangle%22%20width%3D%2215%22%20height%3D%2215%22%20x%3D%22.5%22%20y%3D%22.5%22%20fill-rule%3D%22nonzero%22%20stroke%3D%22%234C4C4C%22%20rx%3D%222%22%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E%0A");cursor:pointer;height:1em;margin-left:-1.5em;margin-top:.125em;position:absolute;width:1em}.tox-checklist li:not(.tox-checklist--hidden).tox-checklist--checked::before{content:url("data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2216%22%20height%3D%2216%22%20viewBox%3D%220%200%2016%2016%22%3E%3Cg%20id%3D%22checklist-checked%22%20fill%3D%22none%22%20fill-rule%3D%22evenodd%22%3E%3Crect%20id%3D%22Rectangle%22%20width%3D%2216%22%20height%3D%2216%22%20fill%3D%22%234099FF%22%20fill-rule%3D%22nonzero%22%20rx%3D%222%22%2F%3E%3Cpath%20id%3D%22Path%22%20fill%3D%22%23FFF%22%20fill-rule%3D%22nonzero%22%20d%3D%22M11.5703186%2C3.14417309%20C11.8516238%2C2.73724603%2012.4164781%2C2.62829933%2012.83558%2C2.89774797%20C13.260121%2C3.17069355%2013.3759736%2C3.72932262%2013.0909105%2C4.14168582%20L7.7580587%2C11.8560195%20C7.43776896%2C12.3193404%206.76483983%2C12.3852142%206.35607322%2C11.9948725%20L3.02491697%2C8.8138662%20C2.66090143%2C8.46625845%202.65798871%2C7.89594698%203.01850234%2C7.54483354%20C3.373942%2C7.19866177%203.94940006%2C7.19592841%204.30829608%2C7.5386474%20L6.85276923%2C9.9684299%20L11.5703186%2C3.14417309%20Z%22%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E%0A")}[dir=rtl] .tox-checklist>li:not(.tox-checklist--hidden)::before{margin-left:0;margin-right:-1.5em}code[class*=language-],pre[class*=language-]{color:#000;background:0 0;text-shadow:0 1px #fff;font-family:Consolas,Monaco,'Andale Mono','Ubuntu Mono',monospace;font-size:1em;text-align:left;white-space:pre;word-spacing:normal;word-break:normal;word-wrap:normal;line-height:1.5;-moz-tab-size:4;tab-size:4;-webkit-hyphens:none;-ms-hyphens:none;hyphens:none}code[class*=language-] ::-moz-selection,code[class*=language-]::-moz-selection,pre[class*=language-] ::-moz-selection,pre[class*=language-]::-moz-selection{text-shadow:none;background:#b3d4fc}code[class*=language-] ::selection,code[class*=language-]::selection,pre[class*=language-] ::selection,pre[class*=language-]::selection{text-shadow:none;background:#b3d4fc}@media print{code[class*=language-],pre[class*=language-]{text-shadow:none}}pre[class*=language-]{padding:1em;margin:.5em 0;overflow:auto}:not(pre)>code[class*=language-],pre[class*=language-]{background:#f5f2f0}:not(pre)>code[class*=language-]{padding:.1em;border-radius:.3em;white-space:normal}.token.cdata,.token.comment,.token.doctype,.token.prolog{color:#708090}.token.punctuation{color:#999}.namespace{opacity:.7}.token.boolean,.token.constant,.token.deleted,.token.number,.token.property,.token.symbol,.token.tag{color:#905}.token.attr-name,.token.builtin,.token.char,.token.inserted,.token.selector,.token.string{color:#690}.language-css .token.string,.style .token.string,.token.entity,.token.operator,.token.url{color:#9a6e3a;background:hsla(0,0%,100%,.5)}.token.atrule,.token.attr-value,.token.keyword{color:#07a}.token.class-name,.token.function{color:#dd4a68}.token.important,.token.regex,.token.variable{color:#e90}.token.bold,.token.important{font-weight:700}.token.italic{font-style:italic}.token.entity{cursor:help}.mce-content-body{overflow-wrap:break-word;word-wrap:break-word}.mce-content-body .mce-visual-caret{background-color:#000;background-color:currentColor;position:absolute}.mce-content-body .mce-visual-caret-hidden{display:none}.mce-content-body [data-mce-caret]{left:-1000px;margin:0;padding:0;position:absolute;right:auto;top:0}.mce-content-body .mce-offscreen-selection{left:-2000000px;max-width:1000000px;position:absolute}.mce-content-body [contentEditable=false]{cursor:default}.mce-content-body [contentEditable=true]{cursor:text}.tox-cursor-format-painter{cursor:url("data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2224%22%20height%3D%2224%22%20viewBox%3D%220%200%2024%2024%22%3E%0A%20%20%3Cg%20fill%3D%22none%22%20fill-rule%3D%22evenodd%22%3E%0A%20%20%20%20%3Cpath%20fill%3D%22%23000%22%20fill-rule%3D%22nonzero%22%20d%3D%22M15%2C6%20C15%2C5.45%2014.55%2C5%2014%2C5%20L6%2C5%20C5.45%2C5%205%2C5.45%205%2C6%20L5%2C10%20C5%2C10.55%205.45%2C11%206%2C11%20L14%2C11%20C14.55%2C11%2015%2C10.55%2015%2C10%20L15%2C9%20L16%2C9%20L16%2C12%20L9%2C12%20L9%2C19%20C9%2C19.55%209.45%2C20%2010%2C20%20L11%2C20%20C11.55%2C20%2012%2C19.55%2012%2C19%20L12%2C14%20L18%2C14%20L18%2C7%20L15%2C7%20L15%2C6%20Z%22%2F%3E%0A%20%20%20%20%3Cpath%20fill%3D%22%23000%22%20fill-rule%3D%22nonzero%22%20d%3D%22M1%2C1%20L8.25%2C1%20C8.66421356%2C1%209%2C1.33578644%209%2C1.75%20L9%2C1.75%20C9%2C2.16421356%208.66421356%2C2.5%208.25%2C2.5%20L2.5%2C2.5%20L2.5%2C8.25%20C2.5%2C8.66421356%202.16421356%2C9%201.75%2C9%20L1.75%2C9%20C1.33578644%2C9%201%2C8.66421356%201%2C8.25%20L1%2C1%20Z%22%2F%3E%0A%20%20%3C%2Fg%3E%0A%3C%2Fsvg%3E%0A"),default}.mce-content-body figure.align-left{float:left}.mce-content-body figure.align-right{float:right}.mce-content-body figure.image.align-center{display:table;margin-left:auto;margin-right:auto}.mce-preview-object{border:1px solid gray;display:inline-block;line-height:0;margin:0 2px 0 2px;position:relative}.mce-preview-object .mce-shim{background:url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7);height:100%;left:0;position:absolute;top:0;width:100%}.mce-preview-object[data-mce-selected="2"] .mce-shim{display:none}.mce-object{background:transparent url("data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2224%22%20height%3D%2224%22%3E%3Cpath%20d%3D%22M4%203h16a1%201%200%200%201%201%201v16a1%201%200%200%201-1%201H4a1%201%200%200%201-1-1V4a1%201%200%200%201%201-1zm1%202v14h14V5H5zm4.79%202.565l5.64%204.028a.5.5%200%200%201%200%20.814l-5.64%204.028a.5.5%200%200%201-.79-.407V7.972a.5.5%200%200%201%20.79-.407z%22%2F%3E%3C%2Fsvg%3E%0A") no-repeat center;border:1px dashed #aaa}.mce-pagebreak{border:1px dashed #aaa;cursor:default;display:block;height:5px;margin-top:15px;page-break-before:always;width:100%}@media print{.mce-pagebreak{border:0}}.tiny-pageembed .mce-shim{background:url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7);height:100%;left:0;position:absolute;top:0;width:100%}.tiny-pageembed[data-mce-selected="2"] .mce-shim{display:none}.tiny-pageembed{display:inline-block;position:relative}.tiny-pageembed--16by9,.tiny-pageembed--1by1,.tiny-pageembed--21by9,.tiny-pageembed--4by3{display:block;overflow:hidden;padding:0;position:relative;width:100%}.tiny-pageembed--21by9{padding-top:42.857143%}.tiny-pageembed--16by9{padding-top:56.25%}.tiny-pageembed--4by3{padding-top:75%}.tiny-pageembed--1by1{padding-top:100%}.tiny-pageembed--16by9 iframe,.tiny-pageembed--1by1 iframe,.tiny-pageembed--21by9 iframe,.tiny-pageembed--4by3 iframe{border:0;height:100%;left:0;position:absolute;top:0;width:100%}.mce-content-body[data-mce-placeholder]{position:relative}.mce-content-body[data-mce-placeholder]:not(.mce-visualblocks)::before{color:rgba(34,47,62,.7);content:attr(data-mce-placeholder);position:absolute}.mce-content-body:not([dir=rtl])[data-mce-placeholder]:not(.mce-visualblocks)::before{left:1px;color:#a1b7cb;}.mce-content-body[dir=rtl][data-mce-placeholder]:not(.mce-visualblocks)::before{right:1px}.mce-content-body div.mce-resizehandle{background-color:#4099ff;border-color:#4099ff;border-style:solid;border-width:1px;box-sizing:border-box;height:10px;position:absolute;width:10px;z-index:10000}.mce-content-body div.mce-resizehandle:hover{background-color:#4099ff}.mce-content-body div.mce-resizehandle:nth-of-type(1){cursor:nwse-resize}.mce-content-body div.mce-resizehandle:nth-of-type(2){cursor:nesw-resize}.mce-content-body div.mce-resizehandle:nth-of-type(3){cursor:nwse-resize}.mce-content-body div.mce-resizehandle:nth-of-type(4){cursor:nesw-resize}.mce-content-body .mce-resize-backdrop{z-index:10000}.mce-content-body .mce-clonedresizable{cursor:default;opacity:.5;outline:1px dashed #000;position:absolute;z-index:10001}.mce-content-body .mce-clonedresizable.mce-resizetable-columns td,.mce-content-body .mce-clonedresizable.mce-resizetable-columns th{border:0}.mce-content-body .mce-resize-helper{background:#555;background:rgba(0,0,0,.75);border:1px;border-radius:3px;color:#fff;display:none;font-family:sans-serif;font-size:12px;line-height:14px;margin:5px 10px;padding:5px;position:absolute;white-space:nowrap;z-index:10002}.tox-rtc-user-selection{position:relative}.tox-rtc-user-cursor{bottom:0;cursor:default;position:absolute;top:0;width:2px}.tox-rtc-user-cursor::before{background-color:inherit;border-radius:50%;content:'';display:block;height:8px;position:absolute;right:-3px;top:-3px;width:8px}.tox-rtc-user-cursor:hover::after{background-color:inherit;border-radius:100px;box-sizing:border-box;color:#fff;content:attr(data-user);display:block;font-size:12px;font-weight:700;left:-5px;min-height:8px;min-width:8px;padding:0 12px;position:absolute;top:-11px;white-space:nowrap;z-index:1000}.tox-rtc-user-selection--1 .tox-rtc-user-cursor{background-color:#2dc26b}.tox-rtc-user-selection--2 .tox-rtc-user-cursor{background-color:#e03e2d}.tox-rtc-user-selection--3 .tox-rtc-user-cursor{background-color:#f1c40f}.tox-rtc-user-selection--4 .tox-rtc-user-cursor{background-color:#3598db}.tox-rtc-user-selection--5 .tox-rtc-user-cursor{background-color:#b96ad9}.tox-rtc-user-selection--6 .tox-rtc-user-cursor{background-color:#e67e23}.tox-rtc-user-selection--7 .tox-rtc-user-cursor{background-color:#aaa69d}.tox-rtc-user-selection--8 .tox-rtc-user-cursor{background-color:#f368e0}.tox-rtc-remote-image{background:#eaeaea url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%2236%22%20height%3D%2212%22%20viewBox%3D%220%200%2036%2012%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%20%20%3Ccircle%20cx%3D%226%22%20cy%3D%226%22%20r%3D%223%22%20fill%3D%22rgba(0%2C%200%2C%200%2C%20.2)%22%3E%0A%20%20%20%20%3Canimate%20attributeName%3D%22r%22%20values%3D%223%3B5%3B3%22%20calcMode%3D%22linear%22%20dur%3D%221s%22%20repeatCount%3D%22indefinite%22%20%2F%3E%0A%20%20%3C%2Fcircle%3E%0A%20%20%3Ccircle%20cx%3D%2218%22%20cy%3D%226%22%20r%3D%223%22%20fill%3D%22rgba(0%2C%200%2C%200%2C%20.2)%22%3E%0A%20%20%20%20%3Canimate%20attributeName%3D%22r%22%20values%3D%223%3B5%3B3%22%20calcMode%3D%22linear%22%20begin%3D%22.33s%22%20dur%3D%221s%22%20repeatCount%3D%22indefinite%22%20%2F%3E%0A%20%20%3C%2Fcircle%3E%0A%20%20%3Ccircle%20cx%3D%2230%22%20cy%3D%226%22%20r%3D%223%22%20fill%3D%22rgba(0%2C%200%2C%200%2C%20.2)%22%3E%0A%20%20%20%20%3Canimate%20attributeName%3D%22r%22%20values%3D%223%3B5%3B3%22%20calcMode%3D%22linear%22%20begin%3D%22.66s%22%20dur%3D%221s%22%20repeatCount%3D%22indefinite%22%20%2F%3E%0A%20%20%3C%2Fcircle%3E%0A%3C%2Fsvg%3E%0A") no-repeat center center;border:1px solid #ccc;min-height:240px;min-width:320px}.mce-match-marker{background:#aaa;color:#fff}.mce-match-marker-selected{background:#39f;color:#fff}.mce-match-marker-selected::-moz-selection{background:#39f;color:#fff}.mce-match-marker-selected::selection{background:#39f;color:#fff}.mce-content-body audio[data-mce-selected],.mce-content-body embed[data-mce-selected],.mce-content-body img[data-mce-selected],.mce-content-body object[data-mce-selected],.mce-content-body table[data-mce-selected],.mce-content-body video[data-mce-selected]{outline:3px solid #b4d7ff}.mce-content-body hr[data-mce-selected]{outline:3px solid #b4d7ff;outline-offset:1px}.mce-content-body [contentEditable=false] [contentEditable=true]:focus{outline:3px solid #b4d7ff}.mce-content-body [contentEditable=false] [contentEditable=true]:hover{outline:3px solid #b4d7ff}.mce-content-body [contentEditable=false][data-mce-selected]{cursor:not-allowed;outline:3px solid #b4d7ff}.mce-content-body.mce-content-readonly [contentEditable=true]:focus,.mce-content-body.mce-content-readonly [contentEditable=true]:hover{outline:0}.mce-content-body [data-mce-selected=inline-boundary]{background-color:#b4d7ff}.mce-content-body .mce-edit-focus{outline:3px solid #b4d7ff}.mce-content-body td[data-mce-selected],.mce-content-body th[data-mce-selected]{position:relative}.mce-content-body td[data-mce-selected]::-moz-selection,.mce-content-body th[data-mce-selected]::-moz-selection{background:0 0}.mce-content-body td[data-mce-selected]::selection,.mce-content-body th[data-mce-selected]::selection{background:0 0}.mce-content-body td[data-mce-selected] *,.mce-content-body th[data-mce-selected] *{outline:0;-webkit-touch-callout:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.mce-content-body td[data-mce-selected]::after,.mce-content-body th[data-mce-selected]::after{background-color:rgba(180,215,255,.7);border:1px solid rgba(180,215,255,.7);bottom:-1px;content:'';left:-1px;mix-blend-mode:multiply;position:absolute;right:-1px;top:-1px}@media screen and (-ms-high-contrast:active),(-ms-high-contrast:none){.mce-content-body td[data-mce-selected]::after,.mce-content-body th[data-mce-selected]::after{border-color:rgba(0,84,180,.7)}}.mce-content-body img::-moz-selection{background:0 0}.mce-content-body img::selection{background:0 0}.ephox-snooker-resizer-bar{background-color:#b4d7ff;opacity:0;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.ephox-snooker-resizer-cols{cursor:col-resize}.ephox-snooker-resizer-rows{cursor:row-resize}.ephox-snooker-resizer-bar.ephox-snooker-resizer-bar-dragging{opacity:1}.mce-spellchecker-word{background-image:url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D'4'%20height%3D'4'%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%3E%3Cpath%20stroke%3D'%23ff0000'%20fill%3D'none'%20stroke-linecap%3D'round'%20stroke-opacity%3D'.75'%20d%3D'M0%203L2%201%204%203'%2F%3E%3C%2Fsvg%3E%0A");background-position:0 calc(100% + 1px);background-repeat:repeat-x;background-size:auto 6px;cursor:default;height:2rem}.mce-spellchecker-grammar{background-image:url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D'4'%20height%3D'4'%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%3E%3Cpath%20stroke%3D'%2300A835'%20fill%3D'none'%20stroke-linecap%3D'round'%20d%3D'M0%203L2%201%204%203'%2F%3E%3C%2Fsvg%3E%0A");background-position:0 calc(100% + 1px);background-repeat:repeat-x;background-size:auto 6px;cursor:default}.mce-toc{border:1px solid gray}.mce-toc h2{margin:4px}.mce-toc li{list-style-type:none}.mce-item-table:not([border]),.mce-item-table:not([border]) caption,.mce-item-table:not([border]) td,.mce-item-table:not([border]) th,.mce-item-table[border="0"],.mce-item-table[border="0"] caption,.mce-item-table[border="0"] td,.mce-item-table[border="0"] th,table[style*="border-width: 0px"],table[style*="border-width: 0px"] caption,table[style*="border-width: 0px"] td,table[style*="border-width: 0px"] th{border:1px dashed #bbb}.mce-visualblocks address,.mce-visualblocks article,.mce-visualblocks aside,.mce-visualblocks blockquote,.mce-visualblocks div:not([data-mce-bogus]),.mce-visualblocks dl,.mce-visualblocks figcaption,.mce-visualblocks figure,.mce-visualblocks h1,.mce-visualblocks h2,.mce-visualblocks h3,.mce-visualblocks h4,.mce-visualblocks h5,.mce-visualblocks h6,.mce-visualblocks hgroup,.mce-visualblocks ol,.mce-visualblocks p,.mce-visualblocks pre,.mce-visualblocks section,.mce-visualblocks ul{background-repeat:no-repeat;border:1px dashed #bbb;margin-left:3px;padding-top:10px}.mce-visualblocks p{background-image:url(data:image/gif;base64,R0lGODlhCQAJAJEAAAAAAP///7u7u////yH5BAEAAAMALAAAAAAJAAkAAAIQnG+CqCN/mlyvsRUpThG6AgA7)}.mce-visualblocks h1{background-image:url(data:image/gif;base64,R0lGODlhDQAKAIABALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybGu1JuxHoAfRNRW3TWXyF2YiRUAOw==)}.mce-visualblocks h2{background-image:url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8Hybbx4oOuqgTynJd6bGlWg3DkJzoaUAAAOw==)}.mce-visualblocks h3{background-image:url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIZjI8Hybbx4oOuqgTynJf2Ln2NOHpQpmhAAQA7)}.mce-visualblocks h4{background-image:url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8HybbxInR0zqeAdhtJlXwV1oCll2HaWgAAOw==)}.mce-visualblocks h5{background-image:url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8HybbxIoiuwjane4iq5GlW05GgIkIZUAAAOw==)}.mce-visualblocks h6{background-image:url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8HybbxIoiuwjan04jep1iZ1XRlAo5bVgAAOw==)}.mce-visualblocks div:not([data-mce-bogus]){background-image:url(data:image/gif;base64,R0lGODlhEgAKAIABALu7u////yH5BAEAAAEALAAAAAASAAoAAAIfjI9poI0cgDywrhuxfbrzDEbQM2Ei5aRjmoySW4pAAQA7)}.mce-visualblocks section{background-image:url(data:image/gif;base64,R0lGODlhKAAKAIABALu7u////yH5BAEAAAEALAAAAAAoAAoAAAI5jI+pywcNY3sBWHdNrplytD2ellDeSVbp+GmWqaDqDMepc8t17Y4vBsK5hDyJMcI6KkuYU+jpjLoKADs=)}.mce-visualblocks article{background-image:url(data:image/gif;base64,R0lGODlhKgAKAIABALu7u////yH5BAEAAAEALAAAAAAqAAoAAAI6jI+pywkNY3wG0GBvrsd2tXGYSGnfiF7ikpXemTpOiJScasYoDJJrjsG9gkCJ0ag6KhmaIe3pjDYBBQA7)}.mce-visualblocks blockquote{background-image:url(data:image/gif;base64,R0lGODlhPgAKAIABALu7u////yH5BAEAAAEALAAAAAA+AAoAAAJPjI+py+0Knpz0xQDyuUhvfoGgIX5iSKZYgq5uNL5q69asZ8s5rrf0yZmpNkJZzFesBTu8TOlDVAabUyatguVhWduud3EyiUk45xhTTgMBBQA7)}.mce-visualblocks address{background-image:url(data:image/gif;base64,R0lGODlhLQAKAIABALu7u////yH5BAEAAAEALAAAAAAtAAoAAAI/jI+pywwNozSP1gDyyZcjb3UaRpXkWaXmZW4OqKLhBmLs+K263DkJK7OJeifh7FicKD9A1/IpGdKkyFpNmCkAADs=)}.mce-visualblocks pre{background-image:url(data:image/gif;base64,R0lGODlhFQAKAIABALu7uwAAACH5BAEAAAEALAAAAAAVAAoAAAIjjI+ZoN0cgDwSmnpz1NCueYERhnibZVKLNnbOq8IvKpJtVQAAOw==)}.mce-visualblocks figure{background-image:url(data:image/gif;base64,R0lGODlhJAAKAIAAALu7u////yH5BAEAAAEALAAAAAAkAAoAAAI0jI+py+2fwAHUSFvD3RlvG4HIp4nX5JFSpnZUJ6LlrM52OE7uSWosBHScgkSZj7dDKnWAAgA7)}.mce-visualblocks figcaption{border:1px dashed #bbb}.mce-visualblocks hgroup{background-image:url(data:image/gif;base64,R0lGODlhJwAKAIABALu7uwAAACH5BAEAAAEALAAAAAAnAAoAAAI3jI+pywYNI3uB0gpsRtt5fFnfNZaVSYJil4Wo03Hv6Z62uOCgiXH1kZIIJ8NiIxRrAZNMZAtQAAA7)}.mce-visualblocks aside{background-image:url(data:image/gif;base64,R0lGODlhHgAKAIABAKqqqv///yH5BAEAAAEALAAAAAAeAAoAAAItjI+pG8APjZOTzgtqy7I3f1yehmQcFY4WKZbqByutmW4aHUd6vfcVbgudgpYCADs=)}.mce-visualblocks ul{background-image:url(data:image/gif;base64,R0lGODlhDQAKAIAAALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybGuYnqUVSjvw26DzzXiqIDlVwAAOw==)}.mce-visualblocks ol{background-image:url(data:image/gif;base64,R0lGODlhDQAKAIABALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybH6HHt0qourxC6CvzXieHyeWQAAOw==)}.mce-visualblocks dl{background-image:url(data:image/gif;base64,R0lGODlhDQAKAIABALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybEOnmOvUoWznTqeuEjNSCqeGRUAOw==)}.mce-visualblocks:not([dir=rtl]) address,.mce-visualblocks:not([dir=rtl]) article,.mce-visualblocks:not([dir=rtl]) aside,.mce-visualblocks:not([dir=rtl]) blockquote,.mce-visualblocks:not([dir=rtl]) div:not([data-mce-bogus]),.mce-visualblocks:not([dir=rtl]) dl,.mce-visualblocks:not([dir=rtl]) figcaption,.mce-visualblocks:not([dir=rtl]) figure,.mce-visualblocks:not([dir=rtl]) h1,.mce-visualblocks:not([dir=rtl]) h2,.mce-visualblocks:not([dir=rtl]) h3,.mce-visualblocks:not([dir=rtl]) h4,.mce-visualblocks:not([dir=rtl]) h5,.mce-visualblocks:not([dir=rtl]) h6,.mce-visualblocks:not([dir=rtl]) hgroup,.mce-visualblocks:not([dir=rtl]) ol,.mce-visualblocks:not([dir=rtl]) p,.mce-visualblocks:not([dir=rtl]) pre,.mce-visualblocks:not([dir=rtl]) section,.mce-visualblocks:not([dir=rtl]) ul{margin-left:3px}.mce-visualblocks[dir=rtl] address,.mce-visualblocks[dir=rtl] article,.mce-visualblocks[dir=rtl] aside,.mce-visualblocks[dir=rtl] blockquote,.mce-visualblocks[dir=rtl] div:not([data-mce-bogus]),.mce-visualblocks[dir=rtl] dl,.mce-visualblocks[dir=rtl] figcaption,.mce-visualblocks[dir=rtl] figure,.mce-visualblocks[dir=rtl] h1,.mce-visualblocks[dir=rtl] h2,.mce-visualblocks[dir=rtl] h3,.mce-visualblocks[dir=rtl] h4,.mce-visualblocks[dir=rtl] h5,.mce-visualblocks[dir=rtl] h6,.mce-visualblocks[dir=rtl] hgroup,.mce-visualblocks[dir=rtl] ol,.mce-visualblocks[dir=rtl] p,.mce-visualblocks[dir=rtl] pre,.mce-visualblocks[dir=rtl] section,.mce-visualblocks[dir=rtl] ul{background-position-x:right;margin-right:3px}.mce-nbsp,.mce-shy{background:#aaa}.mce-shy::after{content:'-'} diff --git a/frontend/public/tinymce-dataease-private/skins/ui/oxide-dark/content.min.css b/frontend/public/tinymce-dataease-private/skins/ui/oxide-dark/content.min.css new file mode 100644 index 0000000..e34ba50 --- /dev/null +++ b/frontend/public/tinymce-dataease-private/skins/ui/oxide-dark/content.min.css @@ -0,0 +1,7 @@ +/** + * Copyright (c) Tiny Technologies, Inc. All rights reserved. + * Licensed under the LGPL or a commercial license. + * For LGPL see License.txt in the project root for license information. + * For commercial licenses see https://www.tiny.cloud/ + */ +.mce-content-body .mce-item-anchor{background:transparent url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D'8'%20height%3D'12'%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%3E%3Cpath%20d%3D'M0%200L8%200%208%2012%204.09117821%209%200%2012z'%20fill%3D%22%23cccccc%22%2F%3E%3C%2Fsvg%3E%0A") no-repeat center;cursor:default;display:inline-block;height:12px!important;padding:0 2px;-webkit-user-modify:read-only;-moz-user-modify:read-only;-webkit-user-select:all;-moz-user-select:all;-ms-user-select:all;user-select:all;width:8px!important}.mce-content-body .mce-item-anchor[data-mce-selected]{outline-offset:1px}.tox-comments-visible .tox-comment{background-color:#fff0b7}.tox-comments-visible .tox-comment--active{background-color:#ffe168}.tox-checklist>li:not(.tox-checklist--hidden){list-style:none;margin:.25em 0}.tox-checklist>li:not(.tox-checklist--hidden)::before{content:url("data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2216%22%20height%3D%2216%22%20viewBox%3D%220%200%2016%2016%22%3E%3Cg%20id%3D%22checklist-unchecked%22%20fill%3D%22none%22%20fill-rule%3D%22evenodd%22%3E%3Crect%20id%3D%22Rectangle%22%20width%3D%2215%22%20height%3D%2215%22%20x%3D%22.5%22%20y%3D%22.5%22%20fill-rule%3D%22nonzero%22%20stroke%3D%22%236d737b%22%20rx%3D%222%22%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E%0A");cursor:pointer;height:1em;margin-left:-1.5em;margin-top:.125em;position:absolute;width:1em}.tox-checklist li:not(.tox-checklist--hidden).tox-checklist--checked::before{content:url("data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2216%22%20height%3D%2216%22%20viewBox%3D%220%200%2016%2016%22%3E%3Cg%20id%3D%22checklist-checked%22%20fill%3D%22none%22%20fill-rule%3D%22evenodd%22%3E%3Crect%20id%3D%22Rectangle%22%20width%3D%2216%22%20height%3D%2216%22%20fill%3D%22%234099FF%22%20fill-rule%3D%22nonzero%22%20rx%3D%222%22%2F%3E%3Cpath%20id%3D%22Path%22%20fill%3D%22%23FFF%22%20fill-rule%3D%22nonzero%22%20d%3D%22M11.5703186%2C3.14417309%20C11.8516238%2C2.73724603%2012.4164781%2C2.62829933%2012.83558%2C2.89774797%20C13.260121%2C3.17069355%2013.3759736%2C3.72932262%2013.0909105%2C4.14168582%20L7.7580587%2C11.8560195%20C7.43776896%2C12.3193404%206.76483983%2C12.3852142%206.35607322%2C11.9948725%20L3.02491697%2C8.8138662%20C2.66090143%2C8.46625845%202.65798871%2C7.89594698%203.01850234%2C7.54483354%20C3.373942%2C7.19866177%203.94940006%2C7.19592841%204.30829608%2C7.5386474%20L6.85276923%2C9.9684299%20L11.5703186%2C3.14417309%20Z%22%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E%0A")}[dir=rtl] .tox-checklist>li:not(.tox-checklist--hidden)::before{margin-left:0;margin-right:-1.5em}code[class*=language-],pre[class*=language-]{color:#f8f8f2;background:0 0;text-shadow:0 1px rgba(0,0,0,.3);font-family:Consolas,Monaco,'Andale Mono','Ubuntu Mono',monospace;text-align:left;white-space:pre;word-spacing:normal;word-break:normal;word-wrap:normal;line-height:1.5;-moz-tab-size:4;tab-size:4;-webkit-hyphens:none;-ms-hyphens:none;hyphens:none}pre[class*=language-]{padding:1em;margin:.5em 0;overflow:auto;border-radius:.3em}:not(pre)>code[class*=language-],pre[class*=language-]{background:#282a36}:not(pre)>code[class*=language-]{padding:.1em;border-radius:.3em;white-space:normal}.token.cdata,.token.comment,.token.doctype,.token.prolog{color:#6272a4}.token.punctuation{color:#f8f8f2}.namespace{opacity:.7}.token.constant,.token.deleted,.token.property,.token.symbol,.token.tag{color:#ff79c6}.token.boolean,.token.number{color:#bd93f9}.token.attr-name,.token.builtin,.token.char,.token.inserted,.token.selector,.token.string{color:#50fa7b}.language-css .token.string,.style .token.string,.token.entity,.token.operator,.token.url,.token.variable{color:#f8f8f2}.token.atrule,.token.attr-value,.token.class-name,.token.function{color:#f1fa8c}.token.keyword{color:#8be9fd}.token.important,.token.regex{color:#ffb86c}.token.bold,.token.important{font-weight:700}.token.italic{font-style:italic}.token.entity{cursor:help}.mce-content-body{overflow-wrap:break-word;word-wrap:break-word}.mce-content-body .mce-visual-caret{background-color:#000;background-color:currentColor;position:absolute}.mce-content-body .mce-visual-caret-hidden{display:none}.mce-content-body [data-mce-caret]{left:-1000px;margin:0;padding:0;position:absolute;right:auto;top:0}.mce-content-body .mce-offscreen-selection{left:-2000000px;max-width:1000000px;position:absolute}.mce-content-body [contentEditable=false]{cursor:default}.mce-content-body [contentEditable=true]{cursor:text}.tox-cursor-format-painter{cursor:url("data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2224%22%20height%3D%2224%22%20viewBox%3D%220%200%2024%2024%22%3E%0A%20%20%3Cg%20fill%3D%22none%22%20fill-rule%3D%22evenodd%22%3E%0A%20%20%20%20%3Cpath%20fill%3D%22%23000%22%20fill-rule%3D%22nonzero%22%20d%3D%22M15%2C6%20C15%2C5.45%2014.55%2C5%2014%2C5%20L6%2C5%20C5.45%2C5%205%2C5.45%205%2C6%20L5%2C10%20C5%2C10.55%205.45%2C11%206%2C11%20L14%2C11%20C14.55%2C11%2015%2C10.55%2015%2C10%20L15%2C9%20L16%2C9%20L16%2C12%20L9%2C12%20L9%2C19%20C9%2C19.55%209.45%2C20%2010%2C20%20L11%2C20%20C11.55%2C20%2012%2C19.55%2012%2C19%20L12%2C14%20L18%2C14%20L18%2C7%20L15%2C7%20L15%2C6%20Z%22%2F%3E%0A%20%20%20%20%3Cpath%20fill%3D%22%23000%22%20fill-rule%3D%22nonzero%22%20d%3D%22M1%2C1%20L8.25%2C1%20C8.66421356%2C1%209%2C1.33578644%209%2C1.75%20L9%2C1.75%20C9%2C2.16421356%208.66421356%2C2.5%208.25%2C2.5%20L2.5%2C2.5%20L2.5%2C8.25%20C2.5%2C8.66421356%202.16421356%2C9%201.75%2C9%20L1.75%2C9%20C1.33578644%2C9%201%2C8.66421356%201%2C8.25%20L1%2C1%20Z%22%2F%3E%0A%20%20%3C%2Fg%3E%0A%3C%2Fsvg%3E%0A"),default}.mce-content-body figure.align-left{float:left}.mce-content-body figure.align-right{float:right}.mce-content-body figure.image.align-center{display:table;margin-left:auto;margin-right:auto}.mce-preview-object{border:1px solid gray;display:inline-block;line-height:0;margin:0 2px 0 2px;position:relative}.mce-preview-object .mce-shim{background:url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7);height:100%;left:0;position:absolute;top:0;width:100%}.mce-preview-object[data-mce-selected="2"] .mce-shim{display:none}.mce-object{background:transparent url("data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2224%22%20height%3D%2224%22%3E%3Cpath%20d%3D%22M4%203h16a1%201%200%200%201%201%201v16a1%201%200%200%201-1%201H4a1%201%200%200%201-1-1V4a1%201%200%200%201%201-1zm1%202v14h14V5H5zm4.79%202.565l5.64%204.028a.5.5%200%200%201%200%20.814l-5.64%204.028a.5.5%200%200%201-.79-.407V7.972a.5.5%200%200%201%20.79-.407z%22%20fill%3D%22%23cccccc%22%2F%3E%3C%2Fsvg%3E%0A") no-repeat center;border:1px dashed #aaa}.mce-pagebreak{border:1px dashed #aaa;cursor:default;display:block;height:5px;margin-top:15px;page-break-before:always;width:100%}@media print{.mce-pagebreak{border:0}}.tiny-pageembed .mce-shim{background:url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7);height:100%;left:0;position:absolute;top:0;width:100%}.tiny-pageembed[data-mce-selected="2"] .mce-shim{display:none}.tiny-pageembed{display:inline-block;position:relative}.tiny-pageembed--16by9,.tiny-pageembed--1by1,.tiny-pageembed--21by9,.tiny-pageembed--4by3{display:block;overflow:hidden;padding:0;position:relative;width:100%}.tiny-pageembed--21by9{padding-top:42.857143%}.tiny-pageembed--16by9{padding-top:56.25%}.tiny-pageembed--4by3{padding-top:75%}.tiny-pageembed--1by1{padding-top:100%}.tiny-pageembed--16by9 iframe,.tiny-pageembed--1by1 iframe,.tiny-pageembed--21by9 iframe,.tiny-pageembed--4by3 iframe{border:0;height:100%;left:0;position:absolute;top:0;width:100%}.mce-content-body[data-mce-placeholder]{position:relative}.mce-content-body[data-mce-placeholder]:not(.mce-visualblocks)::before{color:rgba(34,47,62,.7);content:attr(data-mce-placeholder);position:absolute}.mce-content-body:not([dir=rtl])[data-mce-placeholder]:not(.mce-visualblocks)::before{left:1px;color:#a1b7cb;}.mce-content-body[dir=rtl][data-mce-placeholder]:not(.mce-visualblocks)::before{right:1px}.mce-content-body div.mce-resizehandle{background-color:#4099ff;border-color:#4099ff;border-style:solid;border-width:1px;box-sizing:border-box;height:10px;position:absolute;width:10px;z-index:10000}.mce-content-body div.mce-resizehandle:hover{background-color:#4099ff}.mce-content-body div.mce-resizehandle:nth-of-type(1){cursor:nwse-resize}.mce-content-body div.mce-resizehandle:nth-of-type(2){cursor:nesw-resize}.mce-content-body div.mce-resizehandle:nth-of-type(3){cursor:nwse-resize}.mce-content-body div.mce-resizehandle:nth-of-type(4){cursor:nesw-resize}.mce-content-body .mce-resize-backdrop{z-index:10000}.mce-content-body .mce-clonedresizable{cursor:default;opacity:.5;outline:1px dashed #000;position:absolute;z-index:10001}.mce-content-body .mce-clonedresizable.mce-resizetable-columns td,.mce-content-body .mce-clonedresizable.mce-resizetable-columns th{border:0}.mce-content-body .mce-resize-helper{background:#555;background:rgba(0,0,0,.75);border:1px;border-radius:3px;color:#fff;display:none;font-family:sans-serif;font-size:12px;line-height:14px;margin:5px 10px;padding:5px;position:absolute;white-space:nowrap;z-index:10002}.tox-rtc-user-selection{position:relative}.tox-rtc-user-cursor{bottom:0;cursor:default;position:absolute;top:0;width:2px}.tox-rtc-user-cursor::before{background-color:inherit;border-radius:50%;content:'';display:block;height:8px;position:absolute;right:-3px;top:-3px;width:8px}.tox-rtc-user-cursor:hover::after{background-color:inherit;border-radius:100px;box-sizing:border-box;color:#fff;content:attr(data-user);display:block;font-size:12px;font-weight:700;left:-5px;min-height:8px;min-width:8px;padding:0 12px;position:absolute;top:-11px;white-space:nowrap;z-index:1000}.tox-rtc-user-selection--1 .tox-rtc-user-cursor{background-color:#2dc26b}.tox-rtc-user-selection--2 .tox-rtc-user-cursor{background-color:#e03e2d}.tox-rtc-user-selection--3 .tox-rtc-user-cursor{background-color:#f1c40f}.tox-rtc-user-selection--4 .tox-rtc-user-cursor{background-color:#3598db}.tox-rtc-user-selection--5 .tox-rtc-user-cursor{background-color:#b96ad9}.tox-rtc-user-selection--6 .tox-rtc-user-cursor{background-color:#e67e23}.tox-rtc-user-selection--7 .tox-rtc-user-cursor{background-color:#aaa69d}.tox-rtc-user-selection--8 .tox-rtc-user-cursor{background-color:#f368e0}.tox-rtc-remote-image{background:#eaeaea url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%2236%22%20height%3D%2212%22%20viewBox%3D%220%200%2036%2012%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%20%20%3Ccircle%20cx%3D%226%22%20cy%3D%226%22%20r%3D%223%22%20fill%3D%22rgba(0%2C%200%2C%200%2C%20.2)%22%3E%0A%20%20%20%20%3Canimate%20attributeName%3D%22r%22%20values%3D%223%3B5%3B3%22%20calcMode%3D%22linear%22%20dur%3D%221s%22%20repeatCount%3D%22indefinite%22%20%2F%3E%0A%20%20%3C%2Fcircle%3E%0A%20%20%3Ccircle%20cx%3D%2218%22%20cy%3D%226%22%20r%3D%223%22%20fill%3D%22rgba(0%2C%200%2C%200%2C%20.2)%22%3E%0A%20%20%20%20%3Canimate%20attributeName%3D%22r%22%20values%3D%223%3B5%3B3%22%20calcMode%3D%22linear%22%20begin%3D%22.33s%22%20dur%3D%221s%22%20repeatCount%3D%22indefinite%22%20%2F%3E%0A%20%20%3C%2Fcircle%3E%0A%20%20%3Ccircle%20cx%3D%2230%22%20cy%3D%226%22%20r%3D%223%22%20fill%3D%22rgba(0%2C%200%2C%200%2C%20.2)%22%3E%0A%20%20%20%20%3Canimate%20attributeName%3D%22r%22%20values%3D%223%3B5%3B3%22%20calcMode%3D%22linear%22%20begin%3D%22.66s%22%20dur%3D%221s%22%20repeatCount%3D%22indefinite%22%20%2F%3E%0A%20%20%3C%2Fcircle%3E%0A%3C%2Fsvg%3E%0A") no-repeat center center;border:1px solid #ccc;min-height:240px;min-width:320px}.mce-match-marker{background:#aaa;color:#fff}.mce-match-marker-selected{background:#39f;color:#fff}.mce-match-marker-selected::-moz-selection{background:#39f;color:#fff}.mce-match-marker-selected::selection{background:#39f;color:#fff}.mce-content-body audio[data-mce-selected],.mce-content-body embed[data-mce-selected],.mce-content-body img[data-mce-selected],.mce-content-body object[data-mce-selected],.mce-content-body table[data-mce-selected],.mce-content-body video[data-mce-selected]{outline:3px solid #4099ff}.mce-content-body hr[data-mce-selected]{outline:3px solid #4099ff;outline-offset:1px}.mce-content-body [contentEditable=false] [contentEditable=true]:focus{outline:3px solid #4099ff}.mce-content-body [contentEditable=false] [contentEditable=true]:hover{outline:3px solid #4099ff}.mce-content-body [contentEditable=false][data-mce-selected]{cursor:not-allowed;outline:3px solid #4099ff}.mce-content-body.mce-content-readonly [contentEditable=true]:focus,.mce-content-body.mce-content-readonly [contentEditable=true]:hover{outline:0}.mce-content-body [data-mce-selected=inline-boundary]{background-color:#4099ff}.mce-content-body .mce-edit-focus{outline:3px solid #4099ff}.mce-content-body td[data-mce-selected],.mce-content-body th[data-mce-selected]{position:relative}.mce-content-body td[data-mce-selected]::-moz-selection,.mce-content-body th[data-mce-selected]::-moz-selection{background:0 0}.mce-content-body td[data-mce-selected]::selection,.mce-content-body th[data-mce-selected]::selection{background:0 0}.mce-content-body td[data-mce-selected] *,.mce-content-body th[data-mce-selected] *{outline:0;-webkit-touch-callout:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.mce-content-body td[data-mce-selected]::after,.mce-content-body th[data-mce-selected]::after{background-color:rgba(180,215,255,.7);border:1px solid transparent;bottom:-1px;content:'';left:-1px;mix-blend-mode:lighten;position:absolute;right:-1px;top:-1px}@media screen and (-ms-high-contrast:active),(-ms-high-contrast:none){.mce-content-body td[data-mce-selected]::after,.mce-content-body th[data-mce-selected]::after{border-color:rgba(0,84,180,.7)}}.mce-content-body img::-moz-selection{background:0 0}.mce-content-body img::selection{background:0 0}.ephox-snooker-resizer-bar{background-color:#4099ff;opacity:0;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.ephox-snooker-resizer-cols{cursor:col-resize}.ephox-snooker-resizer-rows{cursor:row-resize}.ephox-snooker-resizer-bar.ephox-snooker-resizer-bar-dragging{opacity:1}.mce-spellchecker-word{background-image:url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D'4'%20height%3D'4'%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%3E%3Cpath%20stroke%3D'%23ff0000'%20fill%3D'none'%20stroke-linecap%3D'round'%20stroke-opacity%3D'.75'%20d%3D'M0%203L2%201%204%203'%2F%3E%3C%2Fsvg%3E%0A");background-position:0 calc(100% + 1px);background-repeat:repeat-x;background-size:auto 6px;cursor:default;height:2rem}.mce-spellchecker-grammar{background-image:url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D'4'%20height%3D'4'%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%3E%3Cpath%20stroke%3D'%2300A835'%20fill%3D'none'%20stroke-linecap%3D'round'%20d%3D'M0%203L2%201%204%203'%2F%3E%3C%2Fsvg%3E%0A");background-position:0 calc(100% + 1px);background-repeat:repeat-x;background-size:auto 6px;cursor:default}.mce-toc{border:1px solid gray}.mce-toc h2{margin:4px}.mce-toc li{list-style-type:none}.mce-item-table:not([border]),.mce-item-table:not([border]) caption,.mce-item-table:not([border]) td,.mce-item-table:not([border]) th,.mce-item-table[border="0"],.mce-item-table[border="0"] caption,.mce-item-table[border="0"] td,.mce-item-table[border="0"] th,table[style*="border-width: 0px"],table[style*="border-width: 0px"] caption,table[style*="border-width: 0px"] td,table[style*="border-width: 0px"] th{border:1px dashed #bbb}.mce-visualblocks address,.mce-visualblocks article,.mce-visualblocks aside,.mce-visualblocks blockquote,.mce-visualblocks div:not([data-mce-bogus]),.mce-visualblocks dl,.mce-visualblocks figcaption,.mce-visualblocks figure,.mce-visualblocks h1,.mce-visualblocks h2,.mce-visualblocks h3,.mce-visualblocks h4,.mce-visualblocks h5,.mce-visualblocks h6,.mce-visualblocks hgroup,.mce-visualblocks ol,.mce-visualblocks p,.mce-visualblocks pre,.mce-visualblocks section,.mce-visualblocks ul{background-repeat:no-repeat;border:1px dashed #bbb;margin-left:3px;padding-top:10px}.mce-visualblocks p{background-image:url(data:image/gif;base64,R0lGODlhCQAJAJEAAAAAAP///7u7u////yH5BAEAAAMALAAAAAAJAAkAAAIQnG+CqCN/mlyvsRUpThG6AgA7)}.mce-visualblocks h1{background-image:url(data:image/gif;base64,R0lGODlhDQAKAIABALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybGu1JuxHoAfRNRW3TWXyF2YiRUAOw==)}.mce-visualblocks h2{background-image:url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8Hybbx4oOuqgTynJd6bGlWg3DkJzoaUAAAOw==)}.mce-visualblocks h3{background-image:url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIZjI8Hybbx4oOuqgTynJf2Ln2NOHpQpmhAAQA7)}.mce-visualblocks h4{background-image:url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8HybbxInR0zqeAdhtJlXwV1oCll2HaWgAAOw==)}.mce-visualblocks h5{background-image:url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8HybbxIoiuwjane4iq5GlW05GgIkIZUAAAOw==)}.mce-visualblocks h6{background-image:url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8HybbxIoiuwjan04jep1iZ1XRlAo5bVgAAOw==)}.mce-visualblocks div:not([data-mce-bogus]){background-image:url(data:image/gif;base64,R0lGODlhEgAKAIABALu7u////yH5BAEAAAEALAAAAAASAAoAAAIfjI9poI0cgDywrhuxfbrzDEbQM2Ei5aRjmoySW4pAAQA7)}.mce-visualblocks section{background-image:url(data:image/gif;base64,R0lGODlhKAAKAIABALu7u////yH5BAEAAAEALAAAAAAoAAoAAAI5jI+pywcNY3sBWHdNrplytD2ellDeSVbp+GmWqaDqDMepc8t17Y4vBsK5hDyJMcI6KkuYU+jpjLoKADs=)}.mce-visualblocks article{background-image:url(data:image/gif;base64,R0lGODlhKgAKAIABALu7u////yH5BAEAAAEALAAAAAAqAAoAAAI6jI+pywkNY3wG0GBvrsd2tXGYSGnfiF7ikpXemTpOiJScasYoDJJrjsG9gkCJ0ag6KhmaIe3pjDYBBQA7)}.mce-visualblocks blockquote{background-image:url(data:image/gif;base64,R0lGODlhPgAKAIABALu7u////yH5BAEAAAEALAAAAAA+AAoAAAJPjI+py+0Knpz0xQDyuUhvfoGgIX5iSKZYgq5uNL5q69asZ8s5rrf0yZmpNkJZzFesBTu8TOlDVAabUyatguVhWduud3EyiUk45xhTTgMBBQA7)}.mce-visualblocks address{background-image:url(data:image/gif;base64,R0lGODlhLQAKAIABALu7u////yH5BAEAAAEALAAAAAAtAAoAAAI/jI+pywwNozSP1gDyyZcjb3UaRpXkWaXmZW4OqKLhBmLs+K263DkJK7OJeifh7FicKD9A1/IpGdKkyFpNmCkAADs=)}.mce-visualblocks pre{background-image:url(data:image/gif;base64,R0lGODlhFQAKAIABALu7uwAAACH5BAEAAAEALAAAAAAVAAoAAAIjjI+ZoN0cgDwSmnpz1NCueYERhnibZVKLNnbOq8IvKpJtVQAAOw==)}.mce-visualblocks figure{background-image:url(data:image/gif;base64,R0lGODlhJAAKAIAAALu7u////yH5BAEAAAEALAAAAAAkAAoAAAI0jI+py+2fwAHUSFvD3RlvG4HIp4nX5JFSpnZUJ6LlrM52OE7uSWosBHScgkSZj7dDKnWAAgA7)}.mce-visualblocks figcaption{border:1px dashed #bbb}.mce-visualblocks hgroup{background-image:url(data:image/gif;base64,R0lGODlhJwAKAIABALu7uwAAACH5BAEAAAEALAAAAAAnAAoAAAI3jI+pywYNI3uB0gpsRtt5fFnfNZaVSYJil4Wo03Hv6Z62uOCgiXH1kZIIJ8NiIxRrAZNMZAtQAAA7)}.mce-visualblocks aside{background-image:url(data:image/gif;base64,R0lGODlhHgAKAIABAKqqqv///yH5BAEAAAEALAAAAAAeAAoAAAItjI+pG8APjZOTzgtqy7I3f1yehmQcFY4WKZbqByutmW4aHUd6vfcVbgudgpYCADs=)}.mce-visualblocks ul{background-image:url(data:image/gif;base64,R0lGODlhDQAKAIAAALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybGuYnqUVSjvw26DzzXiqIDlVwAAOw==)}.mce-visualblocks ol{background-image:url(data:image/gif;base64,R0lGODlhDQAKAIABALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybH6HHt0qourxC6CvzXieHyeWQAAOw==)}.mce-visualblocks dl{background-image:url(data:image/gif;base64,R0lGODlhDQAKAIABALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybEOnmOvUoWznTqeuEjNSCqeGRUAOw==)}.mce-visualblocks:not([dir=rtl]) address,.mce-visualblocks:not([dir=rtl]) article,.mce-visualblocks:not([dir=rtl]) aside,.mce-visualblocks:not([dir=rtl]) blockquote,.mce-visualblocks:not([dir=rtl]) div:not([data-mce-bogus]),.mce-visualblocks:not([dir=rtl]) dl,.mce-visualblocks:not([dir=rtl]) figcaption,.mce-visualblocks:not([dir=rtl]) figure,.mce-visualblocks:not([dir=rtl]) h1,.mce-visualblocks:not([dir=rtl]) h2,.mce-visualblocks:not([dir=rtl]) h3,.mce-visualblocks:not([dir=rtl]) h4,.mce-visualblocks:not([dir=rtl]) h5,.mce-visualblocks:not([dir=rtl]) h6,.mce-visualblocks:not([dir=rtl]) hgroup,.mce-visualblocks:not([dir=rtl]) ol,.mce-visualblocks:not([dir=rtl]) p,.mce-visualblocks:not([dir=rtl]) pre,.mce-visualblocks:not([dir=rtl]) section,.mce-visualblocks:not([dir=rtl]) ul{margin-left:3px}.mce-visualblocks[dir=rtl] address,.mce-visualblocks[dir=rtl] article,.mce-visualblocks[dir=rtl] aside,.mce-visualblocks[dir=rtl] blockquote,.mce-visualblocks[dir=rtl] div:not([data-mce-bogus]),.mce-visualblocks[dir=rtl] dl,.mce-visualblocks[dir=rtl] figcaption,.mce-visualblocks[dir=rtl] figure,.mce-visualblocks[dir=rtl] h1,.mce-visualblocks[dir=rtl] h2,.mce-visualblocks[dir=rtl] h3,.mce-visualblocks[dir=rtl] h4,.mce-visualblocks[dir=rtl] h5,.mce-visualblocks[dir=rtl] h6,.mce-visualblocks[dir=rtl] hgroup,.mce-visualblocks[dir=rtl] ol,.mce-visualblocks[dir=rtl] p,.mce-visualblocks[dir=rtl] pre,.mce-visualblocks[dir=rtl] section,.mce-visualblocks[dir=rtl] ul{background-position-x:right;margin-right:3px}.mce-nbsp,.mce-shy{background:#aaa}.mce-shy::after{content:'-'}body{font-family:sans-serif}table{border-collapse:collapse} diff --git a/frontend/public/tinymce-dataease-private/skins/ui/oxide-dark/content.mobile.css b/frontend/public/tinymce-dataease-private/skins/ui/oxide-dark/content.mobile.css new file mode 100644 index 0000000..68f5f0f --- /dev/null +++ b/frontend/public/tinymce-dataease-private/skins/ui/oxide-dark/content.mobile.css @@ -0,0 +1,34 @@ +/** + * Copyright (c) Tiny Technologies, Inc. All rights reserved. + * Licensed under the LGPL or a commercial license. + * For LGPL see License.txt in the project root for license information. + * For commercial licenses see https://www.tiny.cloud/ + */ +.tinymce-mobile-unfocused-selections .tinymce-mobile-unfocused-selection { + /* Note: this file is used inside the content, so isn't part of theming */ + background-color: green; + display: inline-block; + opacity: 0.5; + position: absolute; +} + +body { + -webkit-text-size-adjust: none; +} + +body img { + /* this is related to the content margin */ + max-width: 96vw; +} + +body table img { + max-width: 95%; +} + +body { + font-family: sans-serif; +} + +table { + border-collapse: collapse; +} diff --git a/frontend/public/tinymce-dataease-private/skins/ui/oxide-dark/content.mobile.min.css b/frontend/public/tinymce-dataease-private/skins/ui/oxide-dark/content.mobile.min.css new file mode 100644 index 0000000..35f7dc0 --- /dev/null +++ b/frontend/public/tinymce-dataease-private/skins/ui/oxide-dark/content.mobile.min.css @@ -0,0 +1,7 @@ +/** + * Copyright (c) Tiny Technologies, Inc. All rights reserved. + * Licensed under the LGPL or a commercial license. + * For LGPL see License.txt in the project root for license information. + * For commercial licenses see https://www.tiny.cloud/ + */ +.tinymce-mobile-unfocused-selections .tinymce-mobile-unfocused-selection{background-color:green;display:inline-block;opacity:.5;position:absolute}body{-webkit-text-size-adjust:none}body img{max-width:96vw}body table img{max-width:95%}body{font-family:sans-serif}table{border-collapse:collapse} diff --git a/frontend/public/tinymce-dataease-private/skins/ui/oxide-dark/fonts/tinymce-mobile.woff b/frontend/public/tinymce-dataease-private/skins/ui/oxide-dark/fonts/tinymce-mobile.woff new file mode 100644 index 0000000000000000000000000000000000000000..1e3be038a607cb7c2544ed8ae3d6621f77bf4c38 GIT binary patch literal 4624 zcmb7IeQaFC5#QN&AGUL{efE7g{=BM1W-|RaVdWQe^e?BC`eGz4^i8S3PQw?Hhd_eQHxTkckXZB zdzU((wCVGko!Qyh+1c6InRotvZ%+>+hNrBQtrFOI4t*}DZ$7=>Sr=uD3c$ZlKuKBQ z8~ervCczs9SOk2!>AAqrz+v$CC}f1JfYPDSqx->|V$6{ekbe8M#Bh3Gkg?)-Fdi3B zeB$}UFqn*$pv&q7*net~hsUOlfG7Ho2zaowY%JPRytMvu{&xRPm(h_~w##F>vqE&a5-ssH##mlfAk}44^ zXRJKd!Ifw&ce{$Y9BAg5c>e>p_Z;t!=P{izddGWie?aHLdKL3Cn9rG=d2vt;esWqH zoD}uAoi3Z~4+LABvADt+so4~t%VlyIJ{O3tm$NC+(!yenQD%NVr*btG$T3+_WX=LH z#1M2ZNEtrO+-x;l2i>M^5o%GQ@s?N+gw*19H@G~vl3Q5Zf*t6jjW0GOTmAmlWYgSS zJeiEo%~LA-FW|YAd_Em$OE#@dw)y*#@p!UtnWa);V1HY3ZBw!>(3gY{iFFa_c6iW9 zIQ@xck^{xu9_o;UyQH#ba@y?L$xW?8J35?$p1z46ZjIctZ8QCKCa29bMC1-t@pT>S zTUT1WMjQz-75d)5zJxv~@Yd)bY)ejQBx_XQiaMJ z>$5`NO3?L*ND{UQeF8%xl)$_>w9tmQpfEebzedazFeh#~d}suN+vzsqLiW~@TLhoe zk1%xEcxP2ZL)FuoXeYzb-J5goljDxPL2@@#RW)d&X#&6QO5U=04_628@ONSvtgpha zDqqmoVep`A4<+PK$V>K+T}}{8Rj+Q|UAzCtl!Fh)uXJg{x$}HMJH7LcBLzj-r{h;< zzote8Id%pcAyE;87D<8glyaFeq#k)OEDB%yA ze%CeZ!?4TEs#pj+%14DBZHn8jxaF2as6}p3+!6p-&@I>5lbP3&N$svcIF-`0R5(o2 zh7la++|;-euckH44a4BAwB++#-cZ z)kFyC=eUS-4D0t}H8LdZY!JD^sW@F85io)%=8HU)ouhEeo-K_dJ3BV+8fo0JXIjlP zZt0H`0=Yv~I|PpRZ)r5_iAYmY9V=wT@BsoN9<3vftB|}TOH;|yNk_e7(2-?y{&cSK zG=E5Nz^Ko4>KxcbY!Q13!=HBS$lM96_+0y3M1yWTAt2u5C;6MWMXbRN?RI{$eHnAx z&t=-PSjZ>Qe2V2-YGs1YWemAq zVHdG{9V$QvsY~Cgq-L*PZqMPGv|px$)K~3<%+fBtG{oIRPL_7ye$-(`C=tS)^xC}% zue73qiF&{nXJ*>-@668G!`IrAeB;ad09shzt{O?7omLE_X@H|#ozGt&64 zb-&_lLkZI8TzigPZvUr=4g2-8M6M8b9EQLgoPswYg)d)j&%gZHJO!2>(?;I*8d>aG z#oS295Kcq{uD4R2@VEG($}WWiF-6YK)kjqks%o_U{CIAVX2;tX7o|unkew5?Gn3(| zOePS^{$(;Xi4ph;`KO#;k+vaLt8n5@doi+OEvH&?*+3(WgqkT9-$b0fTHm;)r=NmR zJnJ9o>UvNR(JMoIdRBf{%kd}jmZ)b)#4>dnDfq0G(?~S%d zv50QeMR$Kzd*S$AEXdp5Fhqe0Pz zZ!oS2e!i-tWEJ2^YoVo}V7S0tV7CujimbVJtVNb#yB&<-f&xpSb@m2=wBZ|qU-_^; z?C{lk+;tlxk&Sh3Pwh(D7~kNh`O=~TMWuRUu^0=9)`CYEVwhvGWUt4Wd3`6*H)Zs>LLYQcC#*~B78EfTt7RQ*l)b{v zqntLNsC`h&zZCY{x*}gfPU4at;nfileU3>zeyLdO7;;lFIft~ zsm6#wb5Jjtv;_VxleU0<%cQON-O*ywHt`@C4fn-Y83}=|hJPOpN>1H%C#7)9etg_yG)$ div { + padding-bottom: 4px; +} + +.tox .accessibility-issue__description > div > div { + align-items: center; + display: flex; + margin-bottom: 4px; +} + +.tox .accessibility-issue__description > *:last-child:not(:only-child) { + border-color: #000000; + border-style: solid; +} + +.tox .accessibility-issue__repair { + margin-top: 16px; +} + +.tox .tox-dialog__body-content .accessibility-issue--info .accessibility-issue__description { + background-color: rgba(32, 122, 183, 0.5); + border-color: #207ab7; + color: #fff; +} + +.tox .tox-dialog__body-content .accessibility-issue--info .accessibility-issue__description > *:last-child { + border-color: #207ab7; +} + +.tox .tox-dialog__body-content .accessibility-issue--info .tox-form__group h2 { + color: #fff; +} + +.tox .tox-dialog__body-content .accessibility-issue--info .tox-icon svg { + fill: #fff; +} + +.tox .tox-dialog__body-content .accessibility-issue--info a .tox-icon { + color: #fff; +} + +.tox .tox-dialog__body-content .accessibility-issue--warn .accessibility-issue__description { + background-color: rgba(255, 165, 0, 0.5); + border-color: rgba(255, 165, 0, 0.8); + color: #fff; +} + +.tox .tox-dialog__body-content .accessibility-issue--warn .accessibility-issue__description > *:last-child { + border-color: rgba(255, 165, 0, 0.8); +} + +.tox .tox-dialog__body-content .accessibility-issue--warn .tox-form__group h2 { + color: #fff; +} + +.tox .tox-dialog__body-content .accessibility-issue--warn .tox-icon svg { + fill: #fff; +} + +.tox .tox-dialog__body-content .accessibility-issue--warn a .tox-icon { + color: #fff; +} + +.tox .tox-dialog__body-content .accessibility-issue--error .accessibility-issue__description { + background-color: rgba(204, 0, 0, 0.5); + border-color: rgba(204, 0, 0, 0.8); + color: #fff; +} + +.tox .tox-dialog__body-content .accessibility-issue--error .accessibility-issue__description > *:last-child { + border-color: rgba(204, 0, 0, 0.8); +} + +.tox .tox-dialog__body-content .accessibility-issue--error .tox-form__group h2 { + color: #fff; +} + +.tox .tox-dialog__body-content .accessibility-issue--error .tox-icon svg { + fill: #fff; +} + +.tox .tox-dialog__body-content .accessibility-issue--error a .tox-icon { + color: #fff; +} + +.tox .tox-dialog__body-content .accessibility-issue--success .accessibility-issue__description { + background-color: rgba(120, 171, 70, 0.5); + border-color: rgba(120, 171, 70, 0.8); + color: #fff; +} + +.tox .tox-dialog__body-content .accessibility-issue--success .accessibility-issue__description > *:last-child { + border-color: rgba(120, 171, 70, 0.8); +} + +.tox .tox-dialog__body-content .accessibility-issue--success .tox-form__group h2 { + color: #fff; +} + +.tox .tox-dialog__body-content .accessibility-issue--success .tox-icon svg { + fill: #fff; +} + +.tox .tox-dialog__body-content .accessibility-issue--success a .tox-icon { + color: #fff; +} + +.tox .tox-dialog__body-content .accessibility-issue__header h1, +.tox .tox-dialog__body-content .tox-form__group .accessibility-issue__description h2 { + margin-top: 0; +} + +.tox:not([dir=rtl]) .tox-dialog__body-content .accessibility-issue__header .tox-button { + margin-left: 4px; +} + +.tox:not([dir=rtl]) .tox-dialog__body-content .accessibility-issue__header > *:nth-last-child(2) { + margin-left: auto; +} + +.tox:not([dir=rtl]) .tox-dialog__body-content .accessibility-issue__description { + padding: 4px 4px 4px 8px; +} + +.tox:not([dir=rtl]) .tox-dialog__body-content .accessibility-issue__description > *:last-child { + border-left-width: 1px; + padding-left: 4px; +} + +.tox[dir=rtl] .tox-dialog__body-content .accessibility-issue__header .tox-button { + margin-right: 4px; +} + +.tox[dir=rtl] .tox-dialog__body-content .accessibility-issue__header > *:nth-last-child(2) { + margin-right: auto; +} + +.tox[dir=rtl] .tox-dialog__body-content .accessibility-issue__description { + padding: 4px 8px 4px 4px; +} + +.tox[dir=rtl] .tox-dialog__body-content .accessibility-issue__description > *:last-child { + border-right-width: 1px; + padding-right: 4px; +} + +.tox .tox-anchorbar { + display: flex; + flex: 0 0 auto; +} + +.tox .tox-bar { + display: flex; + flex: 0 0 auto; +} + +.tox .tox-button { + background-color: #207ab7; + background-image: none; + background-position: 0 0; + background-repeat: repeat; + border-color: #207ab7; + border-radius: 3px; + border-style: solid; + border-width: 1px; + box-shadow: none; + box-sizing: border-box; + color: #fff; + cursor: pointer; + display: inline-block; + font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif; + font-size: 14px; + font-style: normal; + font-weight: bold; + letter-spacing: normal; + line-height: 24px; + margin: 0; + outline: none; + padding: 4px 16px; + text-align: center; + text-decoration: none; + text-transform: none; + white-space: nowrap; +} + +.tox .tox-button[disabled] { + background-color: #207ab7; + background-image: none; + border-color: #207ab7; + box-shadow: none; + color: rgba(255, 255, 255, 0.5); + cursor: not-allowed; +} + +.tox .tox-button:focus:not(:disabled) { + background-color: #1c6ca1; + background-image: none; + border-color: #1c6ca1; + box-shadow: none; + color: #fff; +} + +.tox .tox-button:hover:not(:disabled) { + background-color: #1c6ca1; + background-image: none; + border-color: #1c6ca1; + box-shadow: none; + color: #fff; +} + +.tox .tox-button:active:not(:disabled) { + background-color: #185d8c; + background-image: none; + border-color: #185d8c; + box-shadow: none; + color: #fff; +} + +.tox .tox-button--secondary { + background-color: #3d546f; + background-image: none; + background-position: 0 0; + background-repeat: repeat; + border-color: #3d546f; + border-radius: 3px; + border-style: solid; + border-width: 1px; + box-shadow: none; + color: #fff; + font-size: 14px; + font-style: normal; + font-weight: bold; + letter-spacing: normal; + outline: none; + padding: 4px 16px; + text-decoration: none; + text-transform: none; +} + +.tox .tox-button--secondary[disabled] { + background-color: #3d546f; + background-image: none; + border-color: #3d546f; + box-shadow: none; + color: rgba(255, 255, 255, 0.5); +} + +.tox .tox-button--secondary:focus:not(:disabled) { + background-color: #34485f; + background-image: none; + border-color: #34485f; + box-shadow: none; + color: #fff; +} + +.tox .tox-button--secondary:hover:not(:disabled) { + background-color: #34485f; + background-image: none; + border-color: #34485f; + box-shadow: none; + color: #fff; +} + +.tox .tox-button--secondary:active:not(:disabled) { + background-color: #2b3b4e; + background-image: none; + border-color: #2b3b4e; + box-shadow: none; + color: #fff; +} + +.tox .tox-button--icon, +.tox .tox-button.tox-button--icon, +.tox .tox-button.tox-button--secondary.tox-button--icon { + padding: 4px; +} + +.tox .tox-button--icon .tox-icon svg, +.tox .tox-button.tox-button--icon .tox-icon svg, +.tox .tox-button.tox-button--secondary.tox-button--icon .tox-icon svg { + display: block; + fill: currentColor; +} + +.tox .tox-button-link { + background: 0; + border: none; + box-sizing: border-box; + cursor: pointer; + display: inline-block; + font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif; + font-size: 16px; + font-weight: normal; + line-height: 1.3; + margin: 0; + padding: 0; + white-space: nowrap; +} + +.tox .tox-button-link--sm { + font-size: 14px; +} + +.tox .tox-button--naked { + background-color: transparent; + border-color: transparent; + box-shadow: unset; + color: #fff; +} + +.tox .tox-button--naked[disabled] { + background-color: #3d546f; + border-color: #3d546f; + box-shadow: none; + color: rgba(255, 255, 255, 0.5); +} + +.tox .tox-button--naked:hover:not(:disabled) { + background-color: #34485f; + border-color: #34485f; + box-shadow: none; + color: #fff; +} + +.tox .tox-button--naked:focus:not(:disabled) { + background-color: #34485f; + border-color: #34485f; + box-shadow: none; + color: #fff; +} + +.tox .tox-button--naked:active:not(:disabled) { + background-color: #2b3b4e; + border-color: #2b3b4e; + box-shadow: none; + color: #fff; +} + +.tox .tox-button--naked .tox-icon svg { + fill: currentColor; +} + +.tox .tox-button--naked.tox-button--icon:hover:not(:disabled) { + color: #fff; +} + +.tox .tox-checkbox { + align-items: center; + border-radius: 3px; + cursor: pointer; + display: flex; + height: 36px; + min-width: 36px; +} + +.tox .tox-checkbox__input { + /* Hide from view but visible to screen readers */ + height: 1px; + overflow: hidden; + position: absolute; + top: auto; + width: 1px; +} + +.tox .tox-checkbox__icons { + align-items: center; + border-radius: 3px; + box-shadow: 0 0 0 2px transparent; + box-sizing: content-box; + display: flex; + height: 24px; + justify-content: center; + padding: calc(4px - 1px); + width: 24px; +} + +.tox .tox-checkbox__icons .tox-checkbox-icon__unchecked svg { + display: block; + fill: rgba(255, 255, 255, 0.2); +} + +.tox .tox-checkbox__icons .tox-checkbox-icon__indeterminate svg { + display: none; + fill: #207ab7; +} + +.tox .tox-checkbox__icons .tox-checkbox-icon__checked svg { + display: none; + fill: #207ab7; +} + +.tox .tox-checkbox--disabled { + color: rgba(255, 255, 255, 0.5); + cursor: not-allowed; +} + +.tox .tox-checkbox--disabled .tox-checkbox__icons .tox-checkbox-icon__checked svg { + fill: rgba(255, 255, 255, 0.5); +} + +.tox .tox-checkbox--disabled .tox-checkbox__icons .tox-checkbox-icon__unchecked svg { + fill: rgba(255, 255, 255, 0.5); +} + +.tox .tox-checkbox--disabled .tox-checkbox__icons .tox-checkbox-icon__indeterminate svg { + fill: rgba(255, 255, 255, 0.5); +} + +.tox input.tox-checkbox__input:checked + .tox-checkbox__icons .tox-checkbox-icon__unchecked svg { + display: none; +} + +.tox input.tox-checkbox__input:checked + .tox-checkbox__icons .tox-checkbox-icon__checked svg { + display: block; +} + +.tox input.tox-checkbox__input:indeterminate + .tox-checkbox__icons .tox-checkbox-icon__unchecked svg { + display: none; +} + +.tox input.tox-checkbox__input:indeterminate + .tox-checkbox__icons .tox-checkbox-icon__indeterminate svg { + display: block; +} + +.tox input.tox-checkbox__input:focus + .tox-checkbox__icons { + border-radius: 3px; + box-shadow: inset 0 0 0 1px #207ab7; + padding: calc(4px - 1px); +} + +.tox:not([dir=rtl]) .tox-checkbox__label { + margin-left: 4px; +} + +.tox:not([dir=rtl]) .tox-checkbox__input { + left: -10000px; +} + +.tox:not([dir=rtl]) .tox-bar .tox-checkbox { + margin-left: 4px; +} + +.tox[dir=rtl] .tox-checkbox__label { + margin-right: 4px; +} + +.tox[dir=rtl] .tox-checkbox__input { + right: -10000px; +} + +.tox[dir=rtl] .tox-bar .tox-checkbox { + margin-right: 4px; +} + +.tox { + /* stylelint-disable-next-line no-descending-specificity */ +} + +.tox .tox-collection--toolbar .tox-collection__group { + display: flex; + padding: 0; +} + +.tox .tox-collection--grid .tox-collection__group { + display: flex; + flex-wrap: wrap; + max-height: 208px; + overflow-x: hidden; + overflow-y: auto; + padding: 0; +} + +.tox .tox-collection--list .tox-collection__group { + border-bottom-width: 0; + border-color: #1a1a1a; + border-left-width: 0; + border-right-width: 0; + border-style: solid; + border-top-width: 1px; + padding: 4px 0; +} + +.tox .tox-collection--list .tox-collection__group:first-child { + border-top-width: 0; +} + +.tox .tox-collection__group-heading { + background-color: #333333; + color: #fff; + cursor: default; + font-size: 12px; + font-style: normal; + font-weight: normal; + margin-bottom: 4px; + margin-top: -4px; + padding: 4px 8px; + text-transform: none; + -webkit-touch-callout: none; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} + +.tox .tox-collection__item { + align-items: center; + color: #fff; + cursor: pointer; + display: flex; + -webkit-touch-callout: none; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} + +.tox .tox-collection--list .tox-collection__item { + padding: 4px 8px; +} + +.tox .tox-collection--toolbar .tox-collection__item { + border-radius: 3px; + padding: 4px; +} + +.tox .tox-collection--grid .tox-collection__item { + border-radius: 3px; + padding: 4px; +} + +.tox .tox-collection--list .tox-collection__item--enabled { + background-color: #2b3b4e; + color: #fff; +} + +.tox .tox-collection--list .tox-collection__item--active { + background-color: #4a5562; +} + +.tox .tox-collection--toolbar .tox-collection__item--enabled { + background-color: #757d87; + color: #fff; +} + +.tox .tox-collection--toolbar .tox-collection__item--active { + background-color: #4a5562; +} + +.tox .tox-collection--grid .tox-collection__item--enabled { + background-color: #757d87; + color: #fff; +} + +.tox .tox-collection--grid .tox-collection__item--active:not(.tox-collection__item--state-disabled) { + background-color: #4a5562; + color: #fff; +} + +.tox .tox-collection--list .tox-collection__item--active:not(.tox-collection__item--state-disabled) { + color: #fff; +} + +.tox .tox-collection--toolbar .tox-collection__item--active:not(.tox-collection__item--state-disabled) { + color: #fff; +} + +.tox .tox-collection__item--state-disabled { + background-color: transparent; + color: rgba(255, 255, 255, 0.5); + cursor: not-allowed; +} + +.tox .tox-collection__item-icon, +.tox .tox-collection__item-checkmark { + align-items: center; + display: flex; + height: 24px; + justify-content: center; + width: 24px; +} + +.tox .tox-collection__item-icon svg, +.tox .tox-collection__item-checkmark svg { + fill: currentColor; +} + +.tox .tox-collection--toolbar-lg .tox-collection__item-icon { + height: 48px; + width: 48px; +} + +.tox .tox-collection__item-label { + color: currentColor; + display: inline-block; + flex: 1; + -ms-flex-preferred-size: auto; + font-size: 14px; + font-style: normal; + font-weight: normal; + line-height: 24px; + text-transform: none; + word-break: break-all; +} + +.tox .tox-collection__item-accessory { + color: rgba(255, 255, 255, 0.5); + display: inline-block; + font-size: 14px; + height: 24px; + line-height: 24px; + text-transform: none; +} + +.tox .tox-collection__item-caret { + align-items: center; + display: flex; + min-height: 24px; +} + +.tox .tox-collection__item-caret::after { + content: ''; + font-size: 0; + min-height: inherit; +} + +.tox .tox-collection__item-caret svg { + fill: #fff; +} + +.tox .tox-collection--list .tox-collection__item:not(.tox-collection__item--enabled) .tox-collection__item-checkmark svg { + display: none; +} + +.tox .tox-collection--list .tox-collection__item:not(.tox-collection__item--enabled) .tox-collection__item-accessory + .tox-collection__item-checkmark { + display: none; +} + +.tox .tox-collection--horizontal { + background-color: #2b3b4e; + border: 1px solid #1a1a1a; + border-radius: 3px; + box-shadow: 0 1px 3px rgba(0, 0, 0, 0.15); + display: flex; + flex: 0 0 auto; + flex-shrink: 0; + flex-wrap: nowrap; + margin-bottom: 0; + overflow-x: auto; + padding: 0; +} + +.tox .tox-collection--horizontal .tox-collection__group { + align-items: center; + display: flex; + flex-wrap: nowrap; + margin: 0; + padding: 0 4px; +} + +.tox .tox-collection--horizontal .tox-collection__item { + height: 34px; + margin: 2px 0 3px 0; + padding: 0 4px; +} + +.tox .tox-collection--horizontal .tox-collection__item-label { + white-space: nowrap; +} + +.tox .tox-collection--horizontal .tox-collection__item-caret { + margin-left: 4px; +} + +.tox .tox-collection__item-container { + display: flex; +} + +.tox .tox-collection__item-container--row { + align-items: center; + flex: 1 1 auto; + flex-direction: row; +} + +.tox .tox-collection__item-container--row.tox-collection__item-container--align-left { + margin-right: auto; +} + +.tox .tox-collection__item-container--row.tox-collection__item-container--align-right { + justify-content: flex-end; + margin-left: auto; +} + +.tox .tox-collection__item-container--row.tox-collection__item-container--valign-top { + align-items: flex-start; + margin-bottom: auto; +} + +.tox .tox-collection__item-container--row.tox-collection__item-container--valign-middle { + align-items: center; +} + +.tox .tox-collection__item-container--row.tox-collection__item-container--valign-bottom { + align-items: flex-end; + margin-top: auto; +} + +.tox .tox-collection__item-container--column { + -ms-grid-row-align: center; + align-self: center; + flex: 1 1 auto; + flex-direction: column; +} + +.tox .tox-collection__item-container--column.tox-collection__item-container--align-left { + align-items: flex-start; +} + +.tox .tox-collection__item-container--column.tox-collection__item-container--align-right { + align-items: flex-end; +} + +.tox .tox-collection__item-container--column.tox-collection__item-container--valign-top { + align-self: flex-start; +} + +.tox .tox-collection__item-container--column.tox-collection__item-container--valign-middle { + -ms-grid-row-align: center; + align-self: center; +} + +.tox .tox-collection__item-container--column.tox-collection__item-container--valign-bottom { + align-self: flex-end; +} + +.tox:not([dir=rtl]) .tox-collection--horizontal .tox-collection__group:not(:last-of-type) { + border-right: 1px solid #000000; +} + +.tox:not([dir=rtl]) .tox-collection--list .tox-collection__item > *:not(:first-child) { + margin-left: 8px; +} + +.tox:not([dir=rtl]) .tox-collection--list .tox-collection__item > .tox-collection__item-label:first-child { + margin-left: 4px; +} + +.tox:not([dir=rtl]) .tox-collection__item-accessory { + margin-left: 16px; + text-align: right; +} + +.tox:not([dir=rtl]) .tox-collection .tox-collection__item-caret { + margin-left: 16px; +} + +.tox[dir=rtl] .tox-collection--horizontal .tox-collection__group:not(:last-of-type) { + border-left: 1px solid #000000; +} + +.tox[dir=rtl] .tox-collection--list .tox-collection__item > *:not(:first-child) { + margin-right: 8px; +} + +.tox[dir=rtl] .tox-collection--list .tox-collection__item > .tox-collection__item-label:first-child { + margin-right: 4px; +} + +.tox[dir=rtl] .tox-collection__item-icon-rtl { + /* stylelint-disable-next-line no-descending-specificity */ +} + +.tox[dir=rtl] .tox-collection__item-icon-rtl .tox-collection__item-icon svg { + transform: rotateY(180deg); +} + +.tox[dir=rtl] .tox-collection__item-accessory { + margin-right: 16px; + text-align: left; +} + +.tox[dir=rtl] .tox-collection .tox-collection__item-caret { + margin-right: 16px; + transform: rotateY(180deg); +} + +.tox[dir=rtl] .tox-collection--horizontal .tox-collection__item-caret { + margin-right: 4px; +} + +.tox .tox-color-picker-container { + display: flex; + flex-direction: row; + height: 225px; + margin: 0; +} + +.tox .tox-sv-palette { + box-sizing: border-box; + display: flex; + height: 100%; +} + +.tox .tox-sv-palette-spectrum { + height: 100%; +} + +.tox .tox-sv-palette, +.tox .tox-sv-palette-spectrum { + width: 225px; +} + +.tox .tox-sv-palette-thumb { + background: none; + border: 1px solid black; + border-radius: 50%; + box-sizing: content-box; + height: 12px; + position: absolute; + width: 12px; +} + +.tox .tox-sv-palette-inner-thumb { + border: 1px solid white; + border-radius: 50%; + height: 10px; + position: absolute; + width: 10px; +} + +.tox .tox-hue-slider { + box-sizing: border-box; + height: 100%; + width: 25px; +} + +.tox .tox-hue-slider-spectrum { + background: linear-gradient(to bottom, #f00, #ff0080, #f0f, #8000ff, #00f, #0080ff, #0ff, #00ff80, #0f0, #80ff00, #ff0, #ff8000, #f00); + height: 100%; + width: 100%; +} + +.tox .tox-hue-slider, +.tox .tox-hue-slider-spectrum { + width: 20px; +} + +.tox .tox-hue-slider-thumb { + background: white; + border: 1px solid black; + box-sizing: content-box; + height: 4px; + width: 100%; +} + +.tox .tox-rgb-form { + display: flex; + flex-direction: column; + justify-content: space-between; +} + +.tox .tox-rgb-form div { + align-items: center; + display: flex; + justify-content: space-between; + margin-bottom: 5px; + width: inherit; +} + +.tox .tox-rgb-form input { + width: 6em; +} + +.tox .tox-rgb-form input.tox-invalid { + /* Need !important to override Chrome's focus styling unfortunately */ + border: 1px solid red !important; +} + +.tox .tox-rgb-form .tox-rgba-preview { + border: 1px solid black; + flex-grow: 2; + margin-bottom: 0; +} + +.tox:not([dir=rtl]) .tox-sv-palette { + margin-right: 15px; +} + +.tox:not([dir=rtl]) .tox-hue-slider { + margin-right: 15px; +} + +.tox:not([dir=rtl]) .tox-hue-slider-thumb { + margin-left: -1px; +} + +.tox:not([dir=rtl]) .tox-rgb-form label { + margin-right: 0.5em; +} + +.tox[dir=rtl] .tox-sv-palette { + margin-left: 15px; +} + +.tox[dir=rtl] .tox-hue-slider { + margin-left: 15px; +} + +.tox[dir=rtl] .tox-hue-slider-thumb { + margin-right: -1px; +} + +.tox[dir=rtl] .tox-rgb-form label { + margin-left: 0.5em; +} + +.tox .tox-toolbar .tox-swatches, +.tox .tox-toolbar__primary .tox-swatches, +.tox .tox-toolbar__overflow .tox-swatches { + margin: 2px 0 3px 4px; +} + +.tox .tox-collection--list .tox-collection__group .tox-swatches-menu { + border: 0; + margin: -4px 0; +} + +.tox .tox-swatches__row { + display: flex; +} + +.tox .tox-swatch { + height: 30px; + transition: transform 0.15s, box-shadow 0.15s; + width: 30px; +} + +.tox .tox-swatch:hover, +.tox .tox-swatch:focus { + box-shadow: 0 0 0 1px rgba(127, 127, 127, 0.3) inset; + transform: scale(0.8); +} + +.tox .tox-swatch--remove { + align-items: center; + display: flex; + justify-content: center; +} + +.tox .tox-swatch--remove svg path { + stroke: #e74c3c; +} + +.tox .tox-swatches__picker-btn { + align-items: center; + background-color: transparent; + border: 0; + cursor: pointer; + display: flex; + height: 30px; + justify-content: center; + outline: none; + padding: 0; + width: 30px; +} + +.tox .tox-swatches__picker-btn svg { + height: 24px; + width: 24px; +} + +.tox .tox-swatches__picker-btn:hover { + background: #4a5562; +} + +.tox:not([dir=rtl]) .tox-swatches__picker-btn { + margin-left: auto; +} + +.tox[dir=rtl] .tox-swatches__picker-btn { + margin-right: auto; +} + +.tox .tox-comment-thread { + background: #2b3b4e; + position: relative; +} + +.tox .tox-comment-thread > *:not(:first-child) { + margin-top: 8px; +} + +.tox .tox-comment { + background: #2b3b4e; + border: 1px solid #000000; + border-radius: 3px; + box-shadow: 0 4px 8px 0 rgba(42, 55, 70, 0.1); + padding: 8px 8px 16px 8px; + position: relative; +} + +.tox .tox-comment__header { + align-items: center; + color: #fff; + display: flex; + justify-content: space-between; +} + +.tox .tox-comment__date { + color: rgba(255, 255, 255, 0.5); + font-size: 12px; +} + +.tox .tox-comment__body { + color: #fff; + font-size: 14px; + font-style: normal; + font-weight: normal; + line-height: 1.3; + margin-top: 8px; + position: relative; + text-transform: initial; +} + +.tox .tox-comment__body textarea { + resize: none; + white-space: normal; + width: 100%; +} + +.tox .tox-comment__expander { + padding-top: 8px; +} + +.tox .tox-comment__expander p { + color: rgba(255, 255, 255, 0.5); + font-size: 14px; + font-style: normal; +} + +.tox .tox-comment__body p { + margin: 0; +} + +.tox .tox-comment__buttonspacing { + padding-top: 16px; + text-align: center; +} + +.tox .tox-comment-thread__overlay::after { + background: #2b3b4e; + bottom: 0; + content: ""; + display: flex; + left: 0; + opacity: 0.9; + position: absolute; + right: 0; + top: 0; + z-index: 5; +} + +.tox .tox-comment__reply { + display: flex; + flex-shrink: 0; + flex-wrap: wrap; + justify-content: flex-end; + margin-top: 8px; +} + +.tox .tox-comment__reply > *:first-child { + margin-bottom: 8px; + width: 100%; +} + +.tox .tox-comment__edit { + display: flex; + flex-wrap: wrap; + justify-content: flex-end; + margin-top: 16px; +} + +.tox .tox-comment__gradient::after { + background: linear-gradient(rgba(43, 59, 78, 0), #2b3b4e); + bottom: 0; + content: ""; + display: block; + height: 5em; + margin-top: -40px; + position: absolute; + width: 100%; +} + +.tox .tox-comment__overlay { + background: #2b3b4e; + bottom: 0; + display: flex; + flex-direction: column; + flex-grow: 1; + left: 0; + opacity: 0.9; + position: absolute; + right: 0; + text-align: center; + top: 0; + z-index: 5; +} + +.tox .tox-comment__loading-text { + align-items: center; + color: #fff; + display: flex; + flex-direction: column; + position: relative; +} + +.tox .tox-comment__loading-text > div { + padding-bottom: 16px; +} + +.tox .tox-comment__overlaytext { + bottom: 0; + flex-direction: column; + font-size: 14px; + left: 0; + padding: 1em; + position: absolute; + right: 0; + top: 0; + z-index: 10; +} + +.tox .tox-comment__overlaytext p { + background-color: #2b3b4e; + box-shadow: 0 0 8px 8px #2b3b4e; + color: #fff; + text-align: center; +} + +.tox .tox-comment__overlaytext div:nth-of-type(2) { + font-size: 0.8em; +} + +.tox .tox-comment__busy-spinner { + align-items: center; + background-color: #2b3b4e; + bottom: 0; + display: flex; + justify-content: center; + left: 0; + position: absolute; + right: 0; + top: 0; + z-index: 20; +} + +.tox .tox-comment__scroll { + display: flex; + flex-direction: column; + flex-shrink: 1; + overflow: auto; +} + +.tox .tox-conversations { + margin: 8px; +} + +.tox:not([dir=rtl]) .tox-comment__edit { + margin-left: 8px; +} + +.tox:not([dir=rtl]) .tox-comment__buttonspacing > *:last-child, +.tox:not([dir=rtl]) .tox-comment__edit > *:last-child, +.tox:not([dir=rtl]) .tox-comment__reply > *:last-child { + margin-left: 8px; +} + +.tox[dir=rtl] .tox-comment__edit { + margin-right: 8px; +} + +.tox[dir=rtl] .tox-comment__buttonspacing > *:last-child, +.tox[dir=rtl] .tox-comment__edit > *:last-child, +.tox[dir=rtl] .tox-comment__reply > *:last-child { + margin-right: 8px; +} + +.tox .tox-user { + align-items: center; + display: flex; +} + +.tox .tox-user__avatar svg { + fill: rgba(255, 255, 255, 0.5); +} + +.tox .tox-user__name { + color: rgba(255, 255, 255, 0.5); + font-size: 12px; + font-style: normal; + font-weight: bold; + text-transform: uppercase; +} + +.tox:not([dir=rtl]) .tox-user__avatar svg { + margin-right: 8px; +} + +.tox:not([dir=rtl]) .tox-user__avatar + .tox-user__name { + margin-left: 8px; +} + +.tox[dir=rtl] .tox-user__avatar svg { + margin-left: 8px; +} + +.tox[dir=rtl] .tox-user__avatar + .tox-user__name { + margin-right: 8px; +} + +.tox .tox-dialog-wrap { + align-items: center; + bottom: 0; + display: flex; + justify-content: center; + left: 0; + position: fixed; + right: 0; + top: 0; + z-index: 1100; +} + +.tox .tox-dialog-wrap__backdrop { + background-color: rgba(34, 47, 62, 0.75); + bottom: 0; + left: 0; + position: absolute; + right: 0; + top: 0; + z-index: 1; +} + +.tox .tox-dialog-wrap__backdrop--opaque { + background-color: #222f3e; +} + +.tox .tox-dialog { + background-color: #2b3b4e; + border-color: #000000; + border-radius: 3px; + border-style: solid; + border-width: 1px; + box-shadow: 0 16px 16px -10px rgba(42, 55, 70, 0.15), 0 0 40px 1px rgba(42, 55, 70, 0.15); + display: flex; + flex-direction: column; + max-height: 100%; + max-width: 480px; + overflow: hidden; + position: relative; + width: 95vw; + z-index: 2; +} + +@media only screen and (max-width: 767px) { + body:not(.tox-force-desktop) .tox .tox-dialog { + align-self: flex-start; + margin: 8px auto; + width: calc(100vw - 16px); + } +} + +.tox .tox-dialog-inline { + z-index: 1100; +} + +.tox .tox-dialog__header { + align-items: center; + background-color: #2b3b4e; + border-bottom: none; + color: #fff; + display: flex; + font-size: 16px; + justify-content: space-between; + padding: 8px 16px 0 16px; + position: relative; +} + +.tox .tox-dialog__header .tox-button { + z-index: 1; +} + +.tox .tox-dialog__draghandle { + cursor: grab; + height: 100%; + left: 0; + position: absolute; + top: 0; + width: 100%; +} + +.tox .tox-dialog__draghandle:active { + cursor: grabbing; +} + +.tox .tox-dialog__dismiss { + margin-left: auto; +} + +.tox .tox-dialog__title { + font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif; + font-size: 20px; + font-style: normal; + font-weight: normal; + line-height: 1.3; + margin: 0; + text-transform: none; +} + +.tox .tox-dialog__body { + color: #fff; + display: flex; + flex: 1; + -ms-flex-preferred-size: auto; + font-size: 16px; + font-style: normal; + font-weight: normal; + line-height: 1.3; + min-width: 0; + text-align: left; + text-transform: none; +} + +@media only screen and (max-width: 767px) { + body:not(.tox-force-desktop) .tox .tox-dialog__body { + flex-direction: column; + } +} + +.tox .tox-dialog__body-nav { + align-items: flex-start; + display: flex; + flex-direction: column; + padding: 16px 16px; +} + +@media only screen and (max-width: 767px) { + body:not(.tox-force-desktop) .tox .tox-dialog__body-nav { + flex-direction: row; + -webkit-overflow-scrolling: touch; + overflow-x: auto; + padding-bottom: 0; + } +} + +.tox .tox-dialog__body-nav-item { + border-bottom: 2px solid transparent; + color: rgba(255, 255, 255, 0.5); + display: inline-block; + font-size: 14px; + line-height: 1.3; + margin-bottom: 8px; + text-decoration: none; + white-space: nowrap; +} + +.tox .tox-dialog__body-nav-item:focus { + background-color: rgba(32, 122, 183, 0.1); +} + +.tox .tox-dialog__body-nav-item--active { + border-bottom: 2px solid #207ab7; + color: #207ab7; +} + +.tox .tox-dialog__body-content { + box-sizing: border-box; + display: flex; + flex: 1; + flex-direction: column; + -ms-flex-preferred-size: auto; + max-height: 650px; + overflow: auto; + -webkit-overflow-scrolling: touch; + padding: 16px 16px; +} + +.tox .tox-dialog__body-content > * { + margin-bottom: 0; + margin-top: 16px; +} + +.tox .tox-dialog__body-content > *:first-child { + margin-top: 0; +} + +.tox .tox-dialog__body-content > *:last-child { + margin-bottom: 0; +} + +.tox .tox-dialog__body-content > *:only-child { + margin-bottom: 0; + margin-top: 0; +} + +.tox .tox-dialog__body-content a { + color: #207ab7; + cursor: pointer; + text-decoration: none; +} + +.tox .tox-dialog__body-content a:hover, +.tox .tox-dialog__body-content a:focus { + color: #185d8c; + text-decoration: none; +} + +.tox .tox-dialog__body-content a:active { + color: #185d8c; + text-decoration: none; +} + +.tox .tox-dialog__body-content svg { + fill: #fff; +} + +.tox .tox-dialog__body-content ul { + display: block; + list-style-type: disc; + margin-bottom: 16px; + -webkit-margin-end: 0; + margin-inline-end: 0; + -webkit-margin-start: 0; + margin-inline-start: 0; + -webkit-padding-start: 2.5rem; + padding-inline-start: 2.5rem; +} + +.tox .tox-dialog__body-content .tox-form__group h1 { + color: #fff; + font-size: 20px; + font-style: normal; + font-weight: bold; + letter-spacing: normal; + margin-bottom: 16px; + margin-top: 2rem; + text-transform: none; +} + +.tox .tox-dialog__body-content .tox-form__group h2 { + color: #fff; + font-size: 16px; + font-style: normal; + font-weight: bold; + letter-spacing: normal; + margin-bottom: 16px; + margin-top: 2rem; + text-transform: none; +} + +.tox .tox-dialog__body-content .tox-form__group p { + margin-bottom: 16px; +} + +.tox .tox-dialog__body-content .tox-form__group h1:first-child, +.tox .tox-dialog__body-content .tox-form__group h2:first-child, +.tox .tox-dialog__body-content .tox-form__group p:first-child { + margin-top: 0; +} + +.tox .tox-dialog__body-content .tox-form__group h1:last-child, +.tox .tox-dialog__body-content .tox-form__group h2:last-child, +.tox .tox-dialog__body-content .tox-form__group p:last-child { + margin-bottom: 0; +} + +.tox .tox-dialog__body-content .tox-form__group h1:only-child, +.tox .tox-dialog__body-content .tox-form__group h2:only-child, +.tox .tox-dialog__body-content .tox-form__group p:only-child { + margin-bottom: 0; + margin-top: 0; +} + +.tox .tox-dialog--width-lg { + height: 650px; + max-width: 1200px; +} + +.tox .tox-dialog--width-md { + max-width: 800px; +} + +.tox .tox-dialog--width-md .tox-dialog__body-content { + overflow: auto; +} + +.tox .tox-dialog__body-content--centered { + text-align: center; +} + +.tox .tox-dialog__footer { + align-items: center; + background-color: #2b3b4e; + border-top: 1px solid #000000; + display: flex; + justify-content: space-between; + padding: 8px 16px; +} + +.tox .tox-dialog__footer-start, +.tox .tox-dialog__footer-end { + display: flex; +} + +.tox .tox-dialog__busy-spinner { + align-items: center; + background-color: rgba(34, 47, 62, 0.75); + bottom: 0; + display: flex; + justify-content: center; + left: 0; + position: absolute; + right: 0; + top: 0; + z-index: 3; +} + +.tox .tox-dialog__table { + border-collapse: collapse; + width: 100%; +} + +.tox .tox-dialog__table thead th { + font-weight: bold; + padding-bottom: 8px; +} + +.tox .tox-dialog__table tbody tr { + border-bottom: 1px solid #000000; +} + +.tox .tox-dialog__table tbody tr:last-child { + border-bottom: none; +} + +.tox .tox-dialog__table td { + padding-bottom: 8px; + padding-top: 8px; +} + +.tox .tox-dialog__popups { + position: absolute; + width: 100%; + z-index: 1100; +} + +.tox .tox-dialog__body-iframe { + display: flex; + flex: 1; + flex-direction: column; + -ms-flex-preferred-size: auto; +} + +.tox .tox-dialog__body-iframe .tox-navobj { + display: flex; + flex: 1; + -ms-flex-preferred-size: auto; +} + +.tox .tox-dialog__body-iframe .tox-navobj :nth-child(2) { + flex: 1; + -ms-flex-preferred-size: auto; + height: 100%; +} + +.tox .tox-dialog-dock-fadeout { + opacity: 0; + visibility: hidden; +} + +.tox .tox-dialog-dock-fadein { + opacity: 1; + visibility: visible; +} + +.tox .tox-dialog-dock-transition { + transition: visibility 0s linear 0.3s, opacity 0.3s ease; +} + +.tox .tox-dialog-dock-transition.tox-dialog-dock-fadein { + transition-delay: 0s; +} + +.tox.tox-platform-ie { + /* IE11 CSS styles go here */ +} + +.tox.tox-platform-ie .tox-dialog-wrap { + position: -ms-device-fixed; +} + +@media only screen and (max-width: 767px) { + body:not(.tox-force-desktop) .tox:not([dir=rtl]) .tox-dialog__body-nav { + margin-right: 0; + } +} + +@media only screen and (max-width: 767px) { + body:not(.tox-force-desktop) .tox:not([dir=rtl]) .tox-dialog__body-nav-item:not(:first-child) { + margin-left: 8px; + } +} + +.tox:not([dir=rtl]) .tox-dialog__footer .tox-dialog__footer-start > *, +.tox:not([dir=rtl]) .tox-dialog__footer .tox-dialog__footer-end > * { + margin-left: 8px; +} + +.tox[dir=rtl] .tox-dialog__body { + text-align: right; +} + +@media only screen and (max-width: 767px) { + body:not(.tox-force-desktop) .tox[dir=rtl] .tox-dialog__body-nav { + margin-left: 0; + } +} + +@media only screen and (max-width: 767px) { + body:not(.tox-force-desktop) .tox[dir=rtl] .tox-dialog__body-nav-item:not(:first-child) { + margin-right: 8px; + } +} + +.tox[dir=rtl] .tox-dialog__footer .tox-dialog__footer-start > *, +.tox[dir=rtl] .tox-dialog__footer .tox-dialog__footer-end > * { + margin-right: 8px; +} + +body.tox-dialog__disable-scroll { + overflow: hidden; +} + +.tox .tox-dropzone-container { + display: flex; + flex: 1; + -ms-flex-preferred-size: auto; +} + +.tox .tox-dropzone { + align-items: center; + background: #fff; + border: 2px dashed #000000; + box-sizing: border-box; + display: flex; + flex-direction: column; + flex-grow: 1; + justify-content: center; + min-height: 100px; + padding: 10px; +} + +.tox .tox-dropzone p { + color: rgba(255, 255, 255, 0.5); + margin: 0 0 16px 0; +} + +.tox .tox-edit-area { + display: flex; + flex: 1; + -ms-flex-preferred-size: auto; + overflow: hidden; + position: relative; +} + +.tox .tox-edit-area__iframe { + background-color: #fff; + border: 0; + box-sizing: border-box; + flex: 1; + -ms-flex-preferred-size: auto; + height: 100%; + position: absolute; + width: 100%; +} + +.tox.tox-inline-edit-area { + border: 1px dotted #000000; +} + +.tox .tox-editor-container { + display: flex; + flex: 1 1 auto; + flex-direction: column; + overflow: hidden; +} + +.tox .tox-editor-header { + z-index: 1000; +} + +.tox:not(.tox-tinymce-inline) .tox-editor-header { + box-shadow: none; + transition: box-shadow 0.5s; +} + +.tox.tox-tinymce--toolbar-bottom .tox-editor-header, +.tox.tox-tinymce-inline .tox-editor-header { + margin-bottom: -1px; +} + +.tox.tox-tinymce--toolbar-sticky-on .tox-editor-header { + background-color: transparent; + box-shadow: 0 4px 4px -3px rgba(0, 0, 0, 0.25); +} + +.tox-editor-dock-fadeout { + opacity: 0; + visibility: hidden; +} + +.tox-editor-dock-fadein { + opacity: 1; + visibility: visible; +} + +.tox-editor-dock-transition { + transition: visibility 0s linear 0.25s, opacity 0.25s ease; +} + +.tox-editor-dock-transition.tox-editor-dock-fadein { + transition-delay: 0s; +} + +.tox .tox-control-wrap { + flex: 1; + position: relative; +} + +.tox .tox-control-wrap:not(.tox-control-wrap--status-invalid) .tox-control-wrap__status-icon-invalid, +.tox .tox-control-wrap:not(.tox-control-wrap--status-unknown) .tox-control-wrap__status-icon-unknown, +.tox .tox-control-wrap:not(.tox-control-wrap--status-valid) .tox-control-wrap__status-icon-valid { + display: none; +} + +.tox .tox-control-wrap svg { + display: block; +} + +.tox .tox-control-wrap__status-icon-wrap { + position: absolute; + top: 50%; + transform: translateY(-50%); +} + +.tox .tox-control-wrap__status-icon-invalid svg { + fill: #c00; +} + +.tox .tox-control-wrap__status-icon-unknown svg { + fill: orange; +} + +.tox .tox-control-wrap__status-icon-valid svg { + fill: green; +} + +.tox:not([dir=rtl]) .tox-control-wrap--status-invalid .tox-textfield, +.tox:not([dir=rtl]) .tox-control-wrap--status-unknown .tox-textfield, +.tox:not([dir=rtl]) .tox-control-wrap--status-valid .tox-textfield { + padding-right: 32px; +} + +.tox:not([dir=rtl]) .tox-control-wrap__status-icon-wrap { + right: 4px; +} + +.tox[dir=rtl] .tox-control-wrap--status-invalid .tox-textfield, +.tox[dir=rtl] .tox-control-wrap--status-unknown .tox-textfield, +.tox[dir=rtl] .tox-control-wrap--status-valid .tox-textfield { + padding-left: 32px; +} + +.tox[dir=rtl] .tox-control-wrap__status-icon-wrap { + left: 4px; +} + +.tox .tox-autocompleter { + max-width: 25em; +} + +.tox .tox-autocompleter .tox-menu { + max-width: 25em; +} + +.tox .tox-autocompleter .tox-autocompleter-highlight { + font-weight: bold; +} + +.tox .tox-color-input { + display: flex; + position: relative; + z-index: 1; +} + +.tox .tox-color-input .tox-textfield { + z-index: -1; +} + +.tox .tox-color-input span { + border-color: rgba(42, 55, 70, 0.2); + border-radius: 3px; + border-style: solid; + border-width: 1px; + box-shadow: none; + box-sizing: border-box; + height: 24px; + position: absolute; + top: 6px; + width: 24px; +} + +.tox .tox-color-input span:hover:not([aria-disabled=true]), +.tox .tox-color-input span:focus:not([aria-disabled=true]) { + border-color: #207ab7; + cursor: pointer; +} + +.tox .tox-color-input span::before { + background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.25) 25%, transparent 25%), linear-gradient(-45deg, rgba(255, 255, 255, 0.25) 25%, transparent 25%), linear-gradient(45deg, transparent 75%, rgba(255, 255, 255, 0.25) 75%), linear-gradient(-45deg, transparent 75%, rgba(255, 255, 255, 0.25) 75%); + background-position: 0 0, 0 6px, 6px -6px, -6px 0; + background-size: 12px 12px; + border: 1px solid #2b3b4e; + border-radius: 3px; + box-sizing: border-box; + content: ''; + height: 24px; + left: -1px; + position: absolute; + top: -1px; + width: 24px; + z-index: -1; +} + +.tox .tox-color-input span[aria-disabled=true] { + cursor: not-allowed; +} + +.tox:not([dir=rtl]) .tox-color-input { + /* stylelint-disable-next-line no-descending-specificity */ +} + +.tox:not([dir=rtl]) .tox-color-input .tox-textfield { + padding-left: 36px; +} + +.tox:not([dir=rtl]) .tox-color-input span { + left: 6px; +} + +.tox[dir="rtl"] .tox-color-input { + /* stylelint-disable-next-line no-descending-specificity */ +} + +.tox[dir="rtl"] .tox-color-input .tox-textfield { + padding-right: 36px; +} + +.tox[dir="rtl"] .tox-color-input span { + right: 6px; +} + +.tox .tox-label, +.tox .tox-toolbar-label { + color: rgba(255, 255, 255, 0.5); + display: block; + font-size: 14px; + font-style: normal; + font-weight: normal; + line-height: 1.3; + padding: 0 8px 0 0; + text-transform: none; + white-space: nowrap; +} + +.tox .tox-toolbar-label { + padding: 0 8px; +} + +.tox[dir=rtl] .tox-label { + padding: 0 0 0 8px; +} + +.tox .tox-form { + display: flex; + flex: 1; + flex-direction: column; + -ms-flex-preferred-size: auto; +} + +.tox .tox-form__group { + box-sizing: border-box; + margin-bottom: 4px; +} + +.tox .tox-form-group--maximize { + flex: 1; +} + +.tox .tox-form__group--error { + color: #c00; +} + +.tox .tox-form__group--collection { + display: flex; +} + +.tox .tox-form__grid { + display: flex; + flex-direction: row; + flex-wrap: wrap; + justify-content: space-between; +} + +.tox .tox-form__grid--2col > .tox-form__group { + width: calc(50% - (8px / 2)); +} + +.tox .tox-form__grid--3col > .tox-form__group { + width: calc(100% / 3 - (8px / 2)); +} + +.tox .tox-form__grid--4col > .tox-form__group { + width: calc(25% - (8px / 2)); +} + +.tox .tox-form__controls-h-stack { + align-items: center; + display: flex; +} + +.tox .tox-form__group--inline { + align-items: center; + display: flex; +} + +.tox .tox-form__group--stretched { + display: flex; + flex: 1; + flex-direction: column; + -ms-flex-preferred-size: auto; +} + +.tox .tox-form__group--stretched .tox-textarea { + flex: 1; + -ms-flex-preferred-size: auto; +} + +.tox .tox-form__group--stretched .tox-navobj { + display: flex; + flex: 1; + -ms-flex-preferred-size: auto; +} + +.tox .tox-form__group--stretched .tox-navobj :nth-child(2) { + flex: 1; + -ms-flex-preferred-size: auto; + height: 100%; +} + +.tox:not([dir=rtl]) .tox-form__controls-h-stack > *:not(:first-child) { + margin-left: 4px; +} + +.tox[dir=rtl] .tox-form__controls-h-stack > *:not(:first-child) { + margin-right: 4px; +} + +.tox .tox-lock.tox-locked .tox-lock-icon__unlock, +.tox .tox-lock:not(.tox-locked) .tox-lock-icon__lock { + display: none; +} + +.tox .tox-textfield, +.tox .tox-toolbar-textfield, +.tox .tox-listboxfield .tox-listbox--select, +.tox .tox-textarea { + -webkit-appearance: none; + -moz-appearance: none; + appearance: none; + background-color: #2b3b4e; + border-color: #000000; + border-radius: 3px; + border-style: solid; + border-width: 1px; + box-shadow: none; + box-sizing: border-box; + color: #fff; + font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif; + font-size: 16px; + line-height: 24px; + margin: 0; + min-height: 34px; + outline: none; + padding: 5px 4.75px; + resize: none; + width: 100%; +} + +.tox .tox-textfield[disabled], +.tox .tox-textarea[disabled] { + background-color: #222f3e; + color: rgba(255, 255, 255, 0.85); + cursor: not-allowed; +} + +.tox .tox-textfield:focus, +.tox .tox-listboxfield .tox-listbox--select:focus, +.tox .tox-textarea:focus { + background-color: #2b3b4e; + border-color: #207ab7; + box-shadow: none; + outline: none; +} + +.tox .tox-toolbar-textfield { + border-width: 0; + margin-bottom: 3px; + margin-top: 2px; + max-width: 250px; +} + +.tox .tox-naked-btn { + background-color: transparent; + border: 0; + border-color: transparent; + box-shadow: unset; + color: #207ab7; + cursor: pointer; + display: block; + margin: 0; + padding: 0; +} + +.tox .tox-naked-btn svg { + display: block; + fill: #fff; +} + +.tox:not([dir=rtl]) .tox-toolbar-textfield + * { + margin-left: 4px; +} + +.tox[dir=rtl] .tox-toolbar-textfield + * { + margin-right: 4px; +} + +.tox .tox-listboxfield { + cursor: pointer; + position: relative; +} + +.tox .tox-listboxfield .tox-listbox--select[disabled] { + background-color: #19232e; + color: rgba(255, 255, 255, 0.85); + cursor: not-allowed; +} + +.tox .tox-listbox__select-label { + cursor: default; + flex: 1; + margin: 0 4px; +} + +.tox .tox-listbox__select-chevron { + align-items: center; + display: flex; + justify-content: center; + width: 16px; +} + +.tox .tox-listbox__select-chevron svg { + fill: #fff; +} + +.tox .tox-listboxfield .tox-listbox--select { + align-items: center; + display: flex; +} + +.tox:not([dir=rtl]) .tox-listboxfield svg { + right: 8px; +} + +.tox[dir=rtl] .tox-listboxfield svg { + left: 8px; +} + +.tox .tox-selectfield { + cursor: pointer; + position: relative; +} + +.tox .tox-selectfield select { + -webkit-appearance: none; + -moz-appearance: none; + appearance: none; + background-color: #2b3b4e; + border-color: #000000; + border-radius: 3px; + border-style: solid; + border-width: 1px; + box-shadow: none; + box-sizing: border-box; + color: #fff; + font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif; + font-size: 16px; + line-height: 24px; + margin: 0; + min-height: 34px; + outline: none; + padding: 5px 4.75px; + resize: none; + width: 100%; +} + +.tox .tox-selectfield select[disabled] { + background-color: #19232e; + color: rgba(255, 255, 255, 0.85); + cursor: not-allowed; +} + +.tox .tox-selectfield select::-ms-expand { + display: none; +} + +.tox .tox-selectfield select:focus { + background-color: #2b3b4e; + border-color: #207ab7; + box-shadow: none; + outline: none; +} + +.tox .tox-selectfield svg { + pointer-events: none; + position: absolute; + top: 50%; + transform: translateY(-50%); +} + +.tox:not([dir=rtl]) .tox-selectfield select[size="0"], +.tox:not([dir=rtl]) .tox-selectfield select[size="1"] { + padding-right: 24px; +} + +.tox:not([dir=rtl]) .tox-selectfield svg { + right: 8px; +} + +.tox[dir=rtl] .tox-selectfield select[size="0"], +.tox[dir=rtl] .tox-selectfield select[size="1"] { + padding-left: 24px; +} + +.tox[dir=rtl] .tox-selectfield svg { + left: 8px; +} + +.tox .tox-textarea { + -webkit-appearance: textarea; + -moz-appearance: textarea; + appearance: textarea; + white-space: pre-wrap; +} + +.tox-fullscreen { + border: 0; + height: 100%; + left: 0; + margin: 0; + overflow: hidden; + -ms-scroll-chaining: none; + overscroll-behavior: none; + padding: 0; + position: fixed; + top: 0; + touch-action: pinch-zoom; + width: 100%; +} + +.tox.tox-tinymce.tox-fullscreen .tox-statusbar__resize-handle { + display: none; +} + +.tox.tox-tinymce.tox-fullscreen { + background-color: transparent; + z-index: 1200; +} + +.tox-shadowhost.tox-fullscreen { + z-index: 1200; +} + +.tox-fullscreen .tox.tox-tinymce-aux, +.tox-fullscreen ~ .tox.tox-tinymce-aux { + z-index: 1201; +} + +.tox .tox-help__more-link { + list-style: none; + margin-top: 1em; +} + +.tox .tox-image-tools { + width: 100%; +} + +.tox .tox-image-tools__toolbar { + align-items: center; + display: flex; + justify-content: center; +} + +.tox .tox-image-tools__image { + background-color: #666; + height: 380px; + overflow: auto; + position: relative; + width: 100%; +} + +.tox .tox-image-tools__image, +.tox .tox-image-tools__image + .tox-image-tools__toolbar { + margin-top: 8px; +} + +.tox .tox-image-tools__image-bg { + background: url(data:image/gif;base64,R0lGODdhDAAMAIABAMzMzP///ywAAAAADAAMAAACFoQfqYeabNyDMkBQb81Uat85nxguUAEAOw==); +} + +.tox .tox-image-tools__toolbar > .tox-spacer { + flex: 1; + -ms-flex-preferred-size: auto; +} + +.tox .tox-croprect-block { + background: black; + filter: alpha(opacity=50); + opacity: 0.5; + position: absolute; + zoom: 1; +} + +.tox .tox-croprect-handle { + border: 2px solid white; + height: 20px; + left: 0; + position: absolute; + top: 0; + width: 20px; +} + +.tox .tox-croprect-handle-move { + border: 0; + cursor: move; + position: absolute; +} + +.tox .tox-croprect-handle-nw { + border-width: 2px 0 0 2px; + cursor: nw-resize; + left: 100px; + margin: -2px 0 0 -2px; + top: 100px; +} + +.tox .tox-croprect-handle-ne { + border-width: 2px 2px 0 0; + cursor: ne-resize; + left: 200px; + margin: -2px 0 0 -20px; + top: 100px; +} + +.tox .tox-croprect-handle-sw { + border-width: 0 0 2px 2px; + cursor: sw-resize; + left: 100px; + margin: -20px 2px 0 -2px; + top: 200px; +} + +.tox .tox-croprect-handle-se { + border-width: 0 2px 2px 0; + cursor: se-resize; + left: 200px; + margin: -20px 0 0 -20px; + top: 200px; +} + +.tox:not([dir=rtl]) .tox-image-tools__toolbar > .tox-slider:not(:first-of-type) { + margin-left: 8px; +} + +.tox:not([dir=rtl]) .tox-image-tools__toolbar > .tox-button + .tox-slider { + margin-left: 32px; +} + +.tox:not([dir=rtl]) .tox-image-tools__toolbar > .tox-slider + .tox-button { + margin-left: 32px; +} + +.tox[dir=rtl] .tox-image-tools__toolbar > .tox-slider:not(:first-of-type) { + margin-right: 8px; +} + +.tox[dir=rtl] .tox-image-tools__toolbar > .tox-button + .tox-slider { + margin-right: 32px; +} + +.tox[dir=rtl] .tox-image-tools__toolbar > .tox-slider + .tox-button { + margin-right: 32px; +} + +.tox .tox-insert-table-picker { + display: flex; + flex-wrap: wrap; + width: 170px; +} + +.tox .tox-insert-table-picker > div { + border-color: #000000; + border-style: solid; + border-width: 0 1px 1px 0; + box-sizing: border-box; + height: 17px; + width: 17px; +} + +.tox .tox-collection--list .tox-collection__group .tox-insert-table-picker { + margin: -4px 0; +} + +.tox .tox-insert-table-picker .tox-insert-table-picker__selected { + background-color: rgba(32, 122, 183, 0.5); + border-color: rgba(32, 122, 183, 0.5); +} + +.tox .tox-insert-table-picker__label { + color: #fff; + display: block; + font-size: 14px; + padding: 4px; + text-align: center; + width: 100%; +} + +.tox:not([dir=rtl]) { + /* stylelint-disable-next-line no-descending-specificity */ +} + +.tox:not([dir=rtl]) .tox-insert-table-picker > div:nth-child(10n) { + border-right: 0; +} + +.tox[dir=rtl] { + /* stylelint-disable-next-line no-descending-specificity */ +} + +.tox[dir=rtl] .tox-insert-table-picker > div:nth-child(10n+1) { + border-right: 0; +} + +.tox { + /* stylelint-disable */ + /* stylelint-enable */ +} + +.tox .tox-menu { + background-color: #2b3b4e; + border: 1px solid #000000; + border-radius: 3px; + box-shadow: 0 4px 8px 0 rgba(42, 55, 70, 0.1); + display: inline-block; + overflow: hidden; + vertical-align: top; + z-index: 1150; +} + +.tox .tox-menu.tox-collection.tox-collection--list { + padding: 0; +} + +.tox .tox-menu.tox-collection.tox-collection--toolbar { + padding: 4px; +} + +.tox .tox-menu.tox-collection.tox-collection--grid { + padding: 4px; +} + +.tox .tox-menu__label h1, +.tox .tox-menu__label h2, +.tox .tox-menu__label h3, +.tox .tox-menu__label h4, +.tox .tox-menu__label h5, +.tox .tox-menu__label h6, +.tox .tox-menu__label p, +.tox .tox-menu__label blockquote, +.tox .tox-menu__label code { + margin: 0; +} + +.tox .tox-menubar { + background: url("data:image/svg+xml;charset=utf8,%3Csvg height='39px' viewBox='0 0 40 39px' width='40' xmlns='http://www.w3.org/2000/svg'%3E%3Crect x='0' y='38px' width='100' height='1' fill='%23000000'/%3E%3C/svg%3E") left 0 top 0 #222f3e; + background-color: #222f3e; + display: flex; + flex: 0 0 auto; + flex-shrink: 0; + flex-wrap: wrap; + padding: 0 4px 0 4px; +} + +.tox.tox-tinymce:not(.tox-tinymce-inline) .tox-editor-header:not(:first-child) .tox-menubar { + border-top: 1px solid #000000; +} + +/* Deprecated. Remove in next major release */ +.tox .tox-mbtn { + align-items: center; + background: transparent; + border: 0; + border-radius: 3px; + box-shadow: none; + color: #fff; + display: flex; + flex: 0 0 auto; + font-size: 14px; + font-style: normal; + font-weight: normal; + height: 34px; + justify-content: center; + margin: 2px 0 3px 0; + outline: none; + overflow: hidden; + padding: 0 4px; + text-transform: none; + width: auto; +} + +.tox .tox-mbtn[disabled] { + background-color: transparent; + border: 0; + box-shadow: none; + color: rgba(255, 255, 255, 0.5); + cursor: not-allowed; +} + +.tox .tox-mbtn:focus:not(:disabled) { + background: #4a5562; + border: 0; + box-shadow: none; + color: #fff; +} + +.tox .tox-mbtn--active { + background: #757d87; + border: 0; + box-shadow: none; + color: #fff; +} + +.tox .tox-mbtn:hover:not(:disabled):not(.tox-mbtn--active) { + background: #4a5562; + border: 0; + box-shadow: none; + color: #fff; +} + +.tox .tox-mbtn__select-label { + cursor: default; + font-weight: normal; + margin: 0 4px; +} + +.tox .tox-mbtn[disabled] .tox-mbtn__select-label { + cursor: not-allowed; +} + +.tox .tox-mbtn__select-chevron { + align-items: center; + display: flex; + justify-content: center; + width: 16px; + display: none; +} + +.tox .tox-notification { + border-radius: 3px; + border-style: solid; + border-width: 1px; + box-shadow: none; + box-sizing: border-box; + display: -ms-grid; + display: grid; + font-size: 14px; + font-weight: normal; + -ms-grid-columns: minmax(40px, 1fr) auto minmax(40px, 1fr); + grid-template-columns: minmax(40px, 1fr) auto minmax(40px, 1fr); + margin-top: 4px; + opacity: 0; + padding: 4px; + transition: transform 100ms ease-in, opacity 150ms ease-in; +} + +.tox .tox-notification p { + font-size: 14px; + font-weight: normal; +} + +.tox .tox-notification a { + text-decoration: underline; +} + +.tox .tox-notification--in { + opacity: 1; +} + +.tox .tox-notification--success { + background-color: #e4eeda; + border-color: #d7e6c8; + color: #fff; +} + +.tox .tox-notification--success p { + color: #fff; +} + +.tox .tox-notification--success a { + color: #547831; +} + +.tox .tox-notification--success svg { + fill: #fff; +} + +.tox .tox-notification--error { + background-color: #f8dede; + border-color: #f2bfbf; + color: #fff; +} + +.tox .tox-notification--error p { + color: #fff; +} + +.tox .tox-notification--error a { + color: #c00; +} + +.tox .tox-notification--error svg { + fill: #fff; +} + +.tox .tox-notification--warn, +.tox .tox-notification--warning { + background-color: #fffaea; + border-color: #ffe89d; + color: #fff; +} + +.tox .tox-notification--warn p, +.tox .tox-notification--warning p { + color: #fff; +} + +.tox .tox-notification--warn a, +.tox .tox-notification--warning a { + color: #fff; +} + +.tox .tox-notification--warn svg, +.tox .tox-notification--warning svg { + fill: #fff; +} + +.tox .tox-notification--info { + background-color: #d9edf7; + border-color: #779ecb; + color: #fff; +} + +.tox .tox-notification--info p { + color: #fff; +} + +.tox .tox-notification--info a { + color: #fff; +} + +.tox .tox-notification--info svg { + fill: #fff; +} + +.tox .tox-notification__body { + -ms-grid-row-align: center; + align-self: center; + color: #fff; + font-size: 14px; + -ms-grid-column-span: 1; + grid-column-end: 3; + -ms-grid-column: 2; + grid-column-start: 2; + -ms-grid-row-span: 1; + grid-row-end: 2; + -ms-grid-row: 1; + grid-row-start: 1; + text-align: center; + white-space: normal; + word-break: break-all; + word-break: break-word; +} + +.tox .tox-notification__body > * { + margin: 0; +} + +.tox .tox-notification__body > * + * { + margin-top: 1rem; +} + +.tox .tox-notification__icon { + -ms-grid-row-align: center; + align-self: center; + -ms-grid-column-span: 1; + grid-column-end: 2; + -ms-grid-column: 1; + grid-column-start: 1; + -ms-grid-row-span: 1; + grid-row-end: 2; + -ms-grid-row: 1; + grid-row-start: 1; + -ms-grid-column-align: end; + justify-self: end; +} + +.tox .tox-notification__icon svg { + display: block; +} + +.tox .tox-notification__dismiss { + -ms-grid-row-align: start; + align-self: start; + -ms-grid-column-span: 1; + grid-column-end: 4; + -ms-grid-column: 3; + grid-column-start: 3; + -ms-grid-row-span: 1; + grid-row-end: 2; + -ms-grid-row: 1; + grid-row-start: 1; + -ms-grid-column-align: end; + justify-self: end; +} + +.tox .tox-notification .tox-progress-bar { + -ms-grid-column-span: 3; + grid-column-end: 4; + -ms-grid-column: 1; + grid-column-start: 1; + -ms-grid-row-span: 1; + grid-row-end: 3; + -ms-grid-row: 2; + grid-row-start: 2; + -ms-grid-column-align: center; + justify-self: center; +} + +.tox .tox-pop { + display: inline-block; + position: relative; +} + +.tox .tox-pop--resizing { + transition: width 0.1s ease; +} + +.tox .tox-pop--resizing .tox-toolbar { + flex-wrap: nowrap; +} + +.tox .tox-pop__dialog { + background-color: #222f3e; + border: 1px solid #000000; + border-radius: 3px; + box-shadow: 0 1px 3px rgba(0, 0, 0, 0.15); + min-width: 0; + overflow: hidden; +} + +.tox .tox-pop__dialog > *:not(.tox-toolbar) { + margin: 4px 4px 4px 8px; +} + +.tox .tox-pop__dialog .tox-toolbar { + background-color: transparent; + margin-bottom: -1px; +} + +.tox .tox-pop::before, +.tox .tox-pop::after { + border-style: solid; + content: ''; + display: block; + height: 0; + position: absolute; + width: 0; +} + +.tox .tox-pop.tox-pop--bottom::before, +.tox .tox-pop.tox-pop--bottom::after { + left: 50%; + top: 100%; +} + +.tox .tox-pop.tox-pop--bottom::after { + border-color: #222f3e transparent transparent transparent; + border-width: 8px; + margin-left: -8px; + margin-top: -1px; +} + +.tox .tox-pop.tox-pop--bottom::before { + border-color: #000000 transparent transparent transparent; + border-width: 9px; + margin-left: -9px; +} + +.tox .tox-pop.tox-pop--top::before, +.tox .tox-pop.tox-pop--top::after { + left: 50%; + top: 0; + transform: translateY(-100%); +} + +.tox .tox-pop.tox-pop--top::after { + border-color: transparent transparent #222f3e transparent; + border-width: 8px; + margin-left: -8px; + margin-top: 1px; +} + +.tox .tox-pop.tox-pop--top::before { + border-color: transparent transparent #000000 transparent; + border-width: 9px; + margin-left: -9px; +} + +.tox .tox-pop.tox-pop--left::before, +.tox .tox-pop.tox-pop--left::after { + left: 0; + top: calc(50% - 1px); + transform: translateY(-50%); +} + +.tox .tox-pop.tox-pop--left::after { + border-color: transparent #222f3e transparent transparent; + border-width: 8px; + margin-left: -15px; +} + +.tox .tox-pop.tox-pop--left::before { + border-color: transparent #000000 transparent transparent; + border-width: 10px; + margin-left: -19px; +} + +.tox .tox-pop.tox-pop--right::before, +.tox .tox-pop.tox-pop--right::after { + left: 100%; + top: calc(50% + 1px); + transform: translateY(-50%); +} + +.tox .tox-pop.tox-pop--right::after { + border-color: transparent transparent transparent #222f3e; + border-width: 8px; + margin-left: -1px; +} + +.tox .tox-pop.tox-pop--right::before { + border-color: transparent transparent transparent #000000; + border-width: 10px; + margin-left: -1px; +} + +.tox .tox-pop.tox-pop--align-left::before, +.tox .tox-pop.tox-pop--align-left::after { + left: 20px; +} + +.tox .tox-pop.tox-pop--align-right::before, +.tox .tox-pop.tox-pop--align-right::after { + left: calc(100% - 20px); +} + +.tox .tox-sidebar-wrap { + display: flex; + flex-direction: row; + flex-grow: 1; + -ms-flex-preferred-size: 0; + min-height: 0; +} + +.tox .tox-sidebar { + background-color: #222f3e; + display: flex; + flex-direction: row; + justify-content: flex-end; +} + +.tox .tox-sidebar__slider { + display: flex; + overflow: hidden; +} + +.tox .tox-sidebar__pane-container { + display: flex; +} + +.tox .tox-sidebar__pane { + display: flex; +} + +.tox .tox-sidebar--sliding-closed { + opacity: 0; +} + +.tox .tox-sidebar--sliding-open { + opacity: 1; +} + +.tox .tox-sidebar--sliding-growing, +.tox .tox-sidebar--sliding-shrinking { + transition: width 0.5s ease, opacity 0.5s ease; +} + +.tox .tox-selector { + background-color: #4099ff; + border-color: #4099ff; + border-style: solid; + border-width: 1px; + box-sizing: border-box; + display: inline-block; + height: 10px; + position: absolute; + width: 10px; +} + +.tox.tox-platform-touch .tox-selector { + height: 12px; + width: 12px; +} + +.tox .tox-slider { + align-items: center; + display: flex; + flex: 1; + -ms-flex-preferred-size: auto; + height: 24px; + justify-content: center; + position: relative; +} + +.tox .tox-slider__rail { + background-color: transparent; + border: 1px solid #000000; + border-radius: 3px; + height: 10px; + min-width: 120px; + width: 100%; +} + +.tox .tox-slider__handle { + background-color: #207ab7; + border: 2px solid #185d8c; + border-radius: 3px; + box-shadow: none; + height: 24px; + left: 50%; + position: absolute; + top: 50%; + transform: translateX(-50%) translateY(-50%); + width: 14px; +} + +.tox .tox-source-code { + overflow: auto; +} + +.tox .tox-spinner { + display: flex; +} + +.tox .tox-spinner > div { + animation: tam-bouncing-dots 1.5s ease-in-out 0s infinite both; + background-color: rgba(255, 255, 255, 0.5); + border-radius: 100%; + height: 8px; + width: 8px; +} + +.tox .tox-spinner > div:nth-child(1) { + animation-delay: -0.32s; +} + +.tox .tox-spinner > div:nth-child(2) { + animation-delay: -0.16s; +} + +@keyframes tam-bouncing-dots { + 0%, + 80%, + 100% { + transform: scale(0); + } + 40% { + transform: scale(1); + } +} + +.tox:not([dir=rtl]) .tox-spinner > div:not(:first-child) { + margin-left: 4px; +} + +.tox[dir=rtl] .tox-spinner > div:not(:first-child) { + margin-right: 4px; +} + +.tox .tox-statusbar { + align-items: center; + background-color: #222f3e; + border-top: 1px solid #000000; + color: #fff; + display: flex; + flex: 0 0 auto; + font-size: 12px; + font-weight: normal; + height: 18px; + overflow: hidden; + padding: 0 8px; + position: relative; + text-transform: uppercase; +} + +.tox .tox-statusbar__text-container { + display: flex; + flex: 1 1 auto; + justify-content: flex-end; + overflow: hidden; +} + +.tox .tox-statusbar__path { + display: flex; + flex: 1 1 auto; + margin-right: auto; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.tox .tox-statusbar__path > * { + display: inline; + white-space: nowrap; +} + +.tox .tox-statusbar__wordcount { + flex: 0 0 auto; + margin-left: 1ch; +} + +.tox .tox-statusbar a, +.tox .tox-statusbar__path-item, +.tox .tox-statusbar__wordcount { + color: #fff; + text-decoration: none; +} + +.tox .tox-statusbar a:hover:not(:disabled):not([aria-disabled=true]), +.tox .tox-statusbar__path-item:hover:not(:disabled):not([aria-disabled=true]), +.tox .tox-statusbar__wordcount:hover:not(:disabled):not([aria-disabled=true]), +.tox .tox-statusbar a:focus:not(:disabled):not([aria-disabled=true]), +.tox .tox-statusbar__path-item:focus:not(:disabled):not([aria-disabled=true]), +.tox .tox-statusbar__wordcount:focus:not(:disabled):not([aria-disabled=true]) { + cursor: pointer; + text-decoration: underline; +} + +.tox .tox-statusbar__resize-handle { + align-items: flex-end; + align-self: stretch; + cursor: nwse-resize; + display: flex; + flex: 0 0 auto; + justify-content: flex-end; + margin-left: auto; + margin-right: -8px; + padding-left: 1ch; +} + +.tox .tox-statusbar__resize-handle svg { + display: block; + fill: #fff; +} + +.tox .tox-statusbar__resize-handle:focus svg { + background-color: #4a5562; + border-radius: 1px; + box-shadow: 0 0 0 2px #4a5562; +} + +.tox:not([dir=rtl]) .tox-statusbar__path > * { + margin-right: 4px; +} + +.tox:not([dir=rtl]) .tox-statusbar__branding { + margin-left: 1ch; +} + +.tox[dir=rtl] .tox-statusbar { + flex-direction: row-reverse; +} + +.tox[dir=rtl] .tox-statusbar__path > * { + margin-left: 4px; +} + +.tox .tox-throbber { + z-index: 1299; +} + +.tox .tox-throbber__busy-spinner { + align-items: center; + background-color: rgba(34, 47, 62, 0.6); + bottom: 0; + display: flex; + justify-content: center; + left: 0; + position: absolute; + right: 0; + top: 0; +} + +.tox .tox-tbtn { + align-items: center; + background: transparent; + border: 0; + border-radius: 3px; + box-shadow: none; + color: #fff; + display: flex; + flex: 0 0 auto; + font-size: 14px; + font-style: normal; + font-weight: normal; + height: 34px; + justify-content: center; + margin: 2px 0 3px 0; + outline: none; + overflow: hidden; + padding: 0; + text-transform: none; + width: 34px; +} + +.tox .tox-tbtn svg { + display: block; + fill: #fff; +} + +.tox .tox-tbtn.tox-tbtn-more { + padding-left: 5px; + padding-right: 5px; + width: inherit; +} + +.tox .tox-tbtn:focus { + background: #4a5562; + border: 0; + box-shadow: none; +} + +.tox .tox-tbtn:hover { + background: #4a5562; + border: 0; + box-shadow: none; + color: #fff; +} + +.tox .tox-tbtn:hover svg { + fill: #fff; +} + +.tox .tox-tbtn:active { + background: #757d87; + border: 0; + box-shadow: none; + color: #fff; +} + +.tox .tox-tbtn:active svg { + fill: #fff; +} + +.tox .tox-tbtn--disabled, +.tox .tox-tbtn--disabled:hover, +.tox .tox-tbtn:disabled, +.tox .tox-tbtn:disabled:hover { + background: transparent; + border: 0; + box-shadow: none; + color: rgba(255, 255, 255, 0.5); + cursor: not-allowed; +} + +.tox .tox-tbtn--disabled svg, +.tox .tox-tbtn--disabled:hover svg, +.tox .tox-tbtn:disabled svg, +.tox .tox-tbtn:disabled:hover svg { + /* stylelint-disable-line no-descending-specificity */ + fill: rgba(255, 255, 255, 0.5); +} + +.tox .tox-tbtn--enabled, +.tox .tox-tbtn--enabled:hover { + background: #757d87; + border: 0; + box-shadow: none; + color: #fff; +} + +.tox .tox-tbtn--enabled > *, +.tox .tox-tbtn--enabled:hover > * { + transform: none; +} + +.tox .tox-tbtn--enabled svg, +.tox .tox-tbtn--enabled:hover svg { + /* stylelint-disable-line no-descending-specificity */ + fill: #fff; +} + +.tox .tox-tbtn:focus:not(.tox-tbtn--disabled) { + color: #fff; +} + +.tox .tox-tbtn:focus:not(.tox-tbtn--disabled) svg { + fill: #fff; +} + +.tox .tox-tbtn:active > * { + transform: none; +} + +.tox .tox-tbtn--md { + height: 51px; + width: 51px; +} + +.tox .tox-tbtn--lg { + flex-direction: column; + height: 68px; + width: 68px; +} + +.tox .tox-tbtn--return { + -ms-grid-row-align: stretch; + align-self: stretch; + height: unset; + width: 16px; +} + +.tox .tox-tbtn--labeled { + padding: 0 4px; + width: unset; +} + +.tox .tox-tbtn__vlabel { + display: block; + font-size: 10px; + font-weight: normal; + letter-spacing: -0.025em; + margin-bottom: 4px; + white-space: nowrap; +} + +.tox .tox-tbtn--select { + margin: 2px 0 3px 0; + padding: 0 4px; + width: auto; +} + +.tox .tox-tbtn__select-label { + cursor: default; + font-weight: normal; + margin: 0 4px; +} + +.tox .tox-tbtn__select-chevron { + align-items: center; + display: flex; + justify-content: center; + width: 16px; +} + +.tox .tox-tbtn__select-chevron svg { + fill: rgba(255, 255, 255, 0.5); +} + +.tox .tox-tbtn--bespoke .tox-tbtn__select-label { + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + width: 7em; +} + +.tox .tox-split-button { + border: 0; + border-radius: 3px; + box-sizing: border-box; + display: flex; + margin: 2px 0 3px 0; + overflow: hidden; +} + +.tox .tox-split-button:hover { + box-shadow: 0 0 0 1px #4a5562 inset; +} + +.tox .tox-split-button:focus { + background: #4a5562; + box-shadow: none; + color: #fff; +} + +.tox .tox-split-button > * { + border-radius: 0; +} + +.tox .tox-split-button__chevron { + width: 16px; +} + +.tox .tox-split-button__chevron svg { + fill: rgba(255, 255, 255, 0.5); +} + +.tox .tox-split-button .tox-tbtn { + margin: 0; +} + +.tox.tox-platform-touch .tox-split-button .tox-tbtn:first-child { + width: 30px; +} + +.tox.tox-platform-touch .tox-split-button__chevron { + width: 20px; +} + +.tox .tox-split-button.tox-tbtn--disabled:hover, +.tox .tox-split-button.tox-tbtn--disabled:focus, +.tox .tox-split-button.tox-tbtn--disabled .tox-tbtn:hover, +.tox .tox-split-button.tox-tbtn--disabled .tox-tbtn:focus { + background: transparent; + box-shadow: none; + color: rgba(255, 255, 255, 0.5); +} + +.tox .tox-toolbar-overlord { + background-color: #222f3e; +} + +.tox .tox-toolbar, +.tox .tox-toolbar__primary, +.tox .tox-toolbar__overflow { + background: url("data:image/svg+xml;charset=utf8,%3Csvg height='39px' viewBox='0 0 40 39px' width='40' xmlns='http://www.w3.org/2000/svg'%3E%3Crect x='0' y='38px' width='100' height='1' fill='%23000000'/%3E%3C/svg%3E") left 0 top 0 #222f3e; + background-color: #222f3e; + display: flex; + flex: 0 0 auto; + flex-shrink: 0; + flex-wrap: wrap; + padding: 0 0; +} + +.tox .tox-toolbar__overflow.tox-toolbar__overflow--closed { + height: 0; + opacity: 0; + padding-bottom: 0; + padding-top: 0; + visibility: hidden; +} + +.tox .tox-toolbar__overflow--growing { + transition: height 0.3s ease, opacity 0.2s linear 0.1s; +} + +.tox .tox-toolbar__overflow--shrinking { + transition: opacity 0.3s ease, height 0.2s linear 0.1s, visibility 0s linear 0.3s; +} + +.tox .tox-menubar + .tox-toolbar, +.tox .tox-menubar + .tox-toolbar-overlord .tox-toolbar__primary { + border-top: 1px solid #000000; + margin-top: -1px; +} + +.tox .tox-toolbar--scrolling { + flex-wrap: nowrap; + overflow-x: auto; +} + +.tox .tox-pop .tox-toolbar { + border-width: 0; +} + +.tox .tox-toolbar--no-divider { + background-image: none; +} + +.tox-tinymce:not(.tox-tinymce-inline) .tox-editor-header:not(:first-child) .tox-toolbar:first-child, +.tox-tinymce:not(.tox-tinymce-inline) .tox-editor-header:not(:first-child) .tox-toolbar-overlord:first-child .tox-toolbar__primary { + border-top: 1px solid #000000; +} + +.tox.tox-tinymce-aux .tox-toolbar__overflow { + background-color: #222f3e; + border: 1px solid #000000; + border-radius: 3px; + box-shadow: 0 1px 3px rgba(0, 0, 0, 0.15); +} + +.tox[dir=rtl] .tox-tbtn__icon-rtl svg { + transform: rotateY(180deg); +} + +.tox .tox-toolbar__group { + align-items: center; + display: flex; + flex-wrap: wrap; + margin: 0 0; + padding: 0 4px 0 4px; +} + +.tox .tox-toolbar__group--pull-right { + margin-left: auto; +} + +.tox .tox-toolbar--scrolling .tox-toolbar__group { + flex-shrink: 0; + flex-wrap: nowrap; +} + +.tox:not([dir=rtl]) .tox-toolbar__group:not(:last-of-type) { + border-right: 1px solid #000000; +} + +.tox[dir=rtl] .tox-toolbar__group:not(:last-of-type) { + border-left: 1px solid #000000; +} + +.tox .tox-tooltip { + display: inline-block; + padding: 8px; + position: relative; +} + +.tox .tox-tooltip__body { + background-color: #3d546f; + border-radius: 3px; + box-shadow: 0 2px 4px rgba(42, 55, 70, 0.3); + color: rgba(255, 255, 255, 0.75); + font-size: 14px; + font-style: normal; + font-weight: normal; + padding: 4px 8px; + text-transform: none; +} + +.tox .tox-tooltip__arrow { + position: absolute; +} + +.tox .tox-tooltip--down .tox-tooltip__arrow { + border-left: 8px solid transparent; + border-right: 8px solid transparent; + border-top: 8px solid #3d546f; + bottom: 0; + left: 50%; + position: absolute; + transform: translateX(-50%); +} + +.tox .tox-tooltip--up .tox-tooltip__arrow { + border-bottom: 8px solid #3d546f; + border-left: 8px solid transparent; + border-right: 8px solid transparent; + left: 50%; + position: absolute; + top: 0; + transform: translateX(-50%); +} + +.tox .tox-tooltip--right .tox-tooltip__arrow { + border-bottom: 8px solid transparent; + border-left: 8px solid #3d546f; + border-top: 8px solid transparent; + position: absolute; + right: 0; + top: 50%; + transform: translateY(-50%); +} + +.tox .tox-tooltip--left .tox-tooltip__arrow { + border-bottom: 8px solid transparent; + border-right: 8px solid #3d546f; + border-top: 8px solid transparent; + left: 0; + position: absolute; + top: 50%; + transform: translateY(-50%); +} + +.tox .tox-well { + border: 1px solid #000000; + border-radius: 3px; + padding: 8px; + width: 100%; +} + +.tox .tox-well > *:first-child { + margin-top: 0; +} + +.tox .tox-well > *:last-child { + margin-bottom: 0; +} + +.tox .tox-well > *:only-child { + margin: 0; +} + +.tox .tox-custom-editor { + border: 1px solid #000000; + border-radius: 3px; + display: flex; + flex: 1; + position: relative; +} + +/* stylelint-disable */ +.tox { + /* stylelint-enable */ +} + +.tox .tox-dialog-loading::before { + background-color: rgba(0, 0, 0, 0.5); + content: ""; + height: 100%; + position: absolute; + width: 100%; + z-index: 1000; +} + +.tox .tox-tab { + cursor: pointer; +} + +.tox .tox-dialog__content-js { + display: flex; + flex: 1; + -ms-flex-preferred-size: auto; +} + +.tox .tox-dialog__body-content .tox-collection { + display: flex; + flex: 1; + -ms-flex-preferred-size: auto; +} + +.tox .tox-image-tools-edit-panel { + height: 60px; +} + +.tox .tox-image-tools__sidebar { + height: 60px; +} diff --git a/frontend/public/tinymce-dataease-private/skins/ui/oxide-dark/skin.min.css b/frontend/public/tinymce-dataease-private/skins/ui/oxide-dark/skin.min.css new file mode 100644 index 0000000..5683e99 --- /dev/null +++ b/frontend/public/tinymce-dataease-private/skins/ui/oxide-dark/skin.min.css @@ -0,0 +1,7 @@ +/** + * Copyright (c) Tiny Technologies, Inc. All rights reserved. + * Licensed under the LGPL or a commercial license. + * For LGPL see License.txt in the project root for license information. + * For commercial licenses see https://www.tiny.cloud/ + */ +.tox{box-shadow:none;box-sizing:content-box;color:#2a3746;cursor:auto;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Oxygen-Sans,Ubuntu,Cantarell,"Helvetica Neue",sans-serif;font-size:16px;font-style:normal;font-weight:400;line-height:normal;-webkit-tap-highlight-color:transparent;text-decoration:none;text-shadow:none;text-transform:none;vertical-align:initial;white-space:normal}.tox :not(svg):not(rect){box-sizing:inherit;color:inherit;cursor:inherit;direction:inherit;font-family:inherit;font-size:inherit;font-style:inherit;font-weight:inherit;line-height:inherit;-webkit-tap-highlight-color:inherit;text-align:inherit;text-decoration:inherit;text-shadow:inherit;text-transform:inherit;vertical-align:inherit;white-space:inherit}.tox :not(svg):not(rect){background:0 0;border:0;box-shadow:none;float:none;height:auto;margin:0;max-width:none;outline:0;padding:0;position:static;width:auto}.tox:not([dir=rtl]){direction:ltr;text-align:left}.tox[dir=rtl]{direction:rtl;text-align:right}.tox-tinymce{border:1px solid #000;border-radius:0;box-shadow:none;box-sizing:border-box;display:flex;flex-direction:column;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Oxygen-Sans,Ubuntu,Cantarell,"Helvetica Neue",sans-serif;overflow:hidden;position:relative;visibility:inherit!important}.tox-tinymce-inline{max-width:850px;border:none;box-shadow:none}.tox-tinymce-inline .tox-editor-header{background-color:transparent;border:1px solid #000;border-radius:0;box-shadow:none}.tox-tinymce-aux{font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Oxygen-Sans,Ubuntu,Cantarell,"Helvetica Neue",sans-serif;z-index:1300}.tox-tinymce :focus,.tox-tinymce-aux :focus{outline:0}button::-moz-focus-inner{border:0}.tox .accessibility-issue__header{align-items:center;display:flex;margin-bottom:4px}.tox .accessibility-issue__description{align-items:stretch;border:1px solid #000;border-radius:3px;display:flex;justify-content:space-between}.tox .accessibility-issue__description>div{padding-bottom:4px}.tox .accessibility-issue__description>div>div{align-items:center;display:flex;margin-bottom:4px}.tox .accessibility-issue__description>:last-child:not(:only-child){border-color:#000;border-style:solid}.tox .accessibility-issue__repair{margin-top:16px}.tox .tox-dialog__body-content .accessibility-issue--info .accessibility-issue__description{background-color:rgba(32,122,183,.5);border-color:#207ab7;color:#fff}.tox .tox-dialog__body-content .accessibility-issue--info .accessibility-issue__description>:last-child{border-color:#207ab7}.tox .tox-dialog__body-content .accessibility-issue--info .tox-form__group h2{color:#fff}.tox .tox-dialog__body-content .accessibility-issue--info .tox-icon svg{fill:#fff}.tox .tox-dialog__body-content .accessibility-issue--info a .tox-icon{color:#fff}.tox .tox-dialog__body-content .accessibility-issue--warn .accessibility-issue__description{background-color:rgba(255,165,0,.5);border-color:rgba(255,165,0,.8);color:#fff}.tox .tox-dialog__body-content .accessibility-issue--warn .accessibility-issue__description>:last-child{border-color:rgba(255,165,0,.8)}.tox .tox-dialog__body-content .accessibility-issue--warn .tox-form__group h2{color:#fff}.tox .tox-dialog__body-content .accessibility-issue--warn .tox-icon svg{fill:#fff}.tox .tox-dialog__body-content .accessibility-issue--warn a .tox-icon{color:#fff}.tox .tox-dialog__body-content .accessibility-issue--error .accessibility-issue__description{background-color:rgba(204,0,0,.5);border-color:rgba(204,0,0,.8);color:#fff}.tox .tox-dialog__body-content .accessibility-issue--error .accessibility-issue__description>:last-child{border-color:rgba(204,0,0,.8)}.tox .tox-dialog__body-content .accessibility-issue--error .tox-form__group h2{color:#fff}.tox .tox-dialog__body-content .accessibility-issue--error .tox-icon svg{fill:#fff}.tox .tox-dialog__body-content .accessibility-issue--error a .tox-icon{color:#fff}.tox .tox-dialog__body-content .accessibility-issue--success .accessibility-issue__description{background-color:rgba(120,171,70,.5);border-color:rgba(120,171,70,.8);color:#fff}.tox .tox-dialog__body-content .accessibility-issue--success .accessibility-issue__description>:last-child{border-color:rgba(120,171,70,.8)}.tox .tox-dialog__body-content .accessibility-issue--success .tox-form__group h2{color:#fff}.tox .tox-dialog__body-content .accessibility-issue--success .tox-icon svg{fill:#fff}.tox .tox-dialog__body-content .accessibility-issue--success a .tox-icon{color:#fff}.tox .tox-dialog__body-content .accessibility-issue__header h1,.tox .tox-dialog__body-content .tox-form__group .accessibility-issue__description h2{margin-top:0}.tox:not([dir=rtl]) .tox-dialog__body-content .accessibility-issue__header .tox-button{margin-left:4px}.tox:not([dir=rtl]) .tox-dialog__body-content .accessibility-issue__header>:nth-last-child(2){margin-left:auto}.tox:not([dir=rtl]) .tox-dialog__body-content .accessibility-issue__description{padding:4px 4px 4px 8px}.tox:not([dir=rtl]) .tox-dialog__body-content .accessibility-issue__description>:last-child{border-left-width:1px;padding-left:4px}.tox[dir=rtl] .tox-dialog__body-content .accessibility-issue__header .tox-button{margin-right:4px}.tox[dir=rtl] .tox-dialog__body-content .accessibility-issue__header>:nth-last-child(2){margin-right:auto}.tox[dir=rtl] .tox-dialog__body-content .accessibility-issue__description{padding:4px 8px 4px 4px}.tox[dir=rtl] .tox-dialog__body-content .accessibility-issue__description>:last-child{border-right-width:1px;padding-right:4px}.tox .tox-anchorbar{display:flex;flex:0 0 auto}.tox .tox-bar{display:flex;flex:0 0 auto}.tox .tox-button{background-color:#207ab7;background-image:none;background-position:0 0;background-repeat:repeat;border-color:#207ab7;border-radius:3px;border-style:solid;border-width:1px;box-shadow:none;box-sizing:border-box;color:#fff;cursor:pointer;display:inline-block;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Oxygen-Sans,Ubuntu,Cantarell,"Helvetica Neue",sans-serif;font-size:14px;font-style:normal;font-weight:700;letter-spacing:normal;line-height:24px;margin:0;outline:0;padding:4px 16px;text-align:center;text-decoration:none;text-transform:none;white-space:nowrap}.tox .tox-button[disabled]{background-color:#207ab7;background-image:none;border-color:#207ab7;box-shadow:none;color:rgba(255,255,255,.5);cursor:not-allowed}.tox .tox-button:focus:not(:disabled){background-color:#1c6ca1;background-image:none;border-color:#1c6ca1;box-shadow:none;color:#fff}.tox .tox-button:hover:not(:disabled){background-color:#1c6ca1;background-image:none;border-color:#1c6ca1;box-shadow:none;color:#fff}.tox .tox-button:active:not(:disabled){background-color:#185d8c;background-image:none;border-color:#185d8c;box-shadow:none;color:#fff}.tox .tox-button--secondary{background-color:#3d546f;background-image:none;background-position:0 0;background-repeat:repeat;border-color:#3d546f;border-radius:3px;border-style:solid;border-width:1px;box-shadow:none;color:#fff;font-size:14px;font-style:normal;font-weight:700;letter-spacing:normal;outline:0;padding:4px 16px;text-decoration:none;text-transform:none}.tox .tox-button--secondary[disabled]{background-color:#3d546f;background-image:none;border-color:#3d546f;box-shadow:none;color:rgba(255,255,255,.5)}.tox .tox-button--secondary:focus:not(:disabled){background-color:#34485f;background-image:none;border-color:#34485f;box-shadow:none;color:#fff}.tox .tox-button--secondary:hover:not(:disabled){background-color:#34485f;background-image:none;border-color:#34485f;box-shadow:none;color:#fff}.tox .tox-button--secondary:active:not(:disabled){background-color:#2b3b4e;background-image:none;border-color:#2b3b4e;box-shadow:none;color:#fff}.tox .tox-button--icon,.tox .tox-button.tox-button--icon,.tox .tox-button.tox-button--secondary.tox-button--icon{padding:4px}.tox .tox-button--icon .tox-icon svg,.tox .tox-button.tox-button--icon .tox-icon svg,.tox .tox-button.tox-button--secondary.tox-button--icon .tox-icon svg{display:block;fill:currentColor}.tox .tox-button-link{background:0;border:none;box-sizing:border-box;cursor:pointer;display:inline-block;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Oxygen-Sans,Ubuntu,Cantarell,"Helvetica Neue",sans-serif;font-size:16px;font-weight:400;line-height:1.3;margin:0;padding:0;white-space:nowrap}.tox .tox-button-link--sm{font-size:14px}.tox .tox-button--naked{background-color:transparent;border-color:transparent;box-shadow:unset;color:#fff}.tox .tox-button--naked[disabled]{background-color:#3d546f;border-color:#3d546f;box-shadow:none;color:rgba(255,255,255,.5)}.tox .tox-button--naked:hover:not(:disabled){background-color:#34485f;border-color:#34485f;box-shadow:none;color:#fff}.tox .tox-button--naked:focus:not(:disabled){background-color:#34485f;border-color:#34485f;box-shadow:none;color:#fff}.tox .tox-button--naked:active:not(:disabled){background-color:#2b3b4e;border-color:#2b3b4e;box-shadow:none;color:#fff}.tox .tox-button--naked .tox-icon svg{fill:currentColor}.tox .tox-button--naked.tox-button--icon:hover:not(:disabled){color:#fff}.tox .tox-checkbox{align-items:center;border-radius:3px;cursor:pointer;display:flex;height:36px;min-width:36px}.tox .tox-checkbox__input{height:1px;overflow:hidden;position:absolute;top:auto;width:1px}.tox .tox-checkbox__icons{align-items:center;border-radius:3px;box-shadow:0 0 0 2px transparent;box-sizing:content-box;display:flex;height:24px;justify-content:center;padding:calc(4px - 1px);width:24px}.tox .tox-checkbox__icons .tox-checkbox-icon__unchecked svg{display:block;fill:rgba(255,255,255,.2)}.tox .tox-checkbox__icons .tox-checkbox-icon__indeterminate svg{display:none;fill:#207ab7}.tox .tox-checkbox__icons .tox-checkbox-icon__checked svg{display:none;fill:#207ab7}.tox .tox-checkbox--disabled{color:rgba(255,255,255,.5);cursor:not-allowed}.tox .tox-checkbox--disabled .tox-checkbox__icons .tox-checkbox-icon__checked svg{fill:rgba(255,255,255,.5)}.tox .tox-checkbox--disabled .tox-checkbox__icons .tox-checkbox-icon__unchecked svg{fill:rgba(255,255,255,.5)}.tox .tox-checkbox--disabled .tox-checkbox__icons .tox-checkbox-icon__indeterminate svg{fill:rgba(255,255,255,.5)}.tox input.tox-checkbox__input:checked+.tox-checkbox__icons .tox-checkbox-icon__unchecked svg{display:none}.tox input.tox-checkbox__input:checked+.tox-checkbox__icons .tox-checkbox-icon__checked svg{display:block}.tox input.tox-checkbox__input:indeterminate+.tox-checkbox__icons .tox-checkbox-icon__unchecked svg{display:none}.tox input.tox-checkbox__input:indeterminate+.tox-checkbox__icons .tox-checkbox-icon__indeterminate svg{display:block}.tox input.tox-checkbox__input:focus+.tox-checkbox__icons{border-radius:3px;box-shadow:inset 0 0 0 1px #207ab7;padding:calc(4px - 1px)}.tox:not([dir=rtl]) .tox-checkbox__label{margin-left:4px}.tox:not([dir=rtl]) .tox-checkbox__input{left:-10000px}.tox:not([dir=rtl]) .tox-bar .tox-checkbox{margin-left:4px}.tox[dir=rtl] .tox-checkbox__label{margin-right:4px}.tox[dir=rtl] .tox-checkbox__input{right:-10000px}.tox[dir=rtl] .tox-bar .tox-checkbox{margin-right:4px}.tox .tox-collection--toolbar .tox-collection__group{display:flex;padding:0}.tox .tox-collection--grid .tox-collection__group{display:flex;flex-wrap:wrap;max-height:208px;overflow-x:hidden;overflow-y:auto;padding:0}.tox .tox-collection--list .tox-collection__group{border-bottom-width:0;border-color:#1a1a1a;border-left-width:0;border-right-width:0;border-style:solid;border-top-width:1px;padding:4px 0}.tox .tox-collection--list .tox-collection__group:first-child{border-top-width:0}.tox .tox-collection__group-heading{background-color:#333;color:#fff;cursor:default;font-size:12px;font-style:normal;font-weight:400;margin-bottom:4px;margin-top:-4px;padding:4px 8px;text-transform:none;-webkit-touch-callout:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.tox .tox-collection__item{align-items:center;color:#fff;cursor:pointer;display:flex;-webkit-touch-callout:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.tox .tox-collection--list .tox-collection__item{padding:4px 8px}.tox .tox-collection--toolbar .tox-collection__item{border-radius:3px;padding:4px}.tox .tox-collection--grid .tox-collection__item{border-radius:3px;padding:4px}.tox .tox-collection--list .tox-collection__item--enabled{background-color:#2b3b4e;color:#fff}.tox .tox-collection--list .tox-collection__item--active{background-color:#4a5562}.tox .tox-collection--toolbar .tox-collection__item--enabled{background-color:#757d87;color:#fff}.tox .tox-collection--toolbar .tox-collection__item--active{background-color:#4a5562}.tox .tox-collection--grid .tox-collection__item--enabled{background-color:#757d87;color:#fff}.tox .tox-collection--grid .tox-collection__item--active:not(.tox-collection__item--state-disabled){background-color:#4a5562;color:#fff}.tox .tox-collection--list .tox-collection__item--active:not(.tox-collection__item--state-disabled){color:#fff}.tox .tox-collection--toolbar .tox-collection__item--active:not(.tox-collection__item--state-disabled){color:#fff}.tox .tox-collection__item--state-disabled{background-color:transparent;color:rgba(255,255,255,.5);cursor:not-allowed}.tox .tox-collection__item-checkmark,.tox .tox-collection__item-icon{align-items:center;display:flex;height:24px;justify-content:center;width:24px}.tox .tox-collection__item-checkmark svg,.tox .tox-collection__item-icon svg{fill:currentColor}.tox .tox-collection--toolbar-lg .tox-collection__item-icon{height:48px;width:48px}.tox .tox-collection__item-label{color:currentColor;display:inline-block;flex:1;-ms-flex-preferred-size:auto;font-size:14px;font-style:normal;font-weight:400;line-height:24px;text-transform:none;word-break:break-all}.tox .tox-collection__item-accessory{color:rgba(255,255,255,.5);display:inline-block;font-size:14px;height:24px;line-height:24px;text-transform:none}.tox .tox-collection__item-caret{align-items:center;display:flex;min-height:24px}.tox .tox-collection__item-caret::after{content:'';font-size:0;min-height:inherit}.tox .tox-collection__item-caret svg{fill:#fff}.tox .tox-collection--list .tox-collection__item:not(.tox-collection__item--enabled) .tox-collection__item-checkmark svg{display:none}.tox .tox-collection--list .tox-collection__item:not(.tox-collection__item--enabled) .tox-collection__item-accessory+.tox-collection__item-checkmark{display:none}.tox .tox-collection--horizontal{background-color:#2b3b4e;border:1px solid #1a1a1a;border-radius:3px;box-shadow:0 1px 3px rgba(0,0,0,.15);display:flex;flex:0 0 auto;flex-shrink:0;flex-wrap:nowrap;margin-bottom:0;overflow-x:auto;padding:0}.tox .tox-collection--horizontal .tox-collection__group{align-items:center;display:flex;flex-wrap:nowrap;margin:0;padding:0 4px}.tox .tox-collection--horizontal .tox-collection__item{height:34px;margin:2px 0 3px 0;padding:0 4px}.tox .tox-collection--horizontal .tox-collection__item-label{white-space:nowrap}.tox .tox-collection--horizontal .tox-collection__item-caret{margin-left:4px}.tox .tox-collection__item-container{display:flex}.tox .tox-collection__item-container--row{align-items:center;flex:1 1 auto;flex-direction:row}.tox .tox-collection__item-container--row.tox-collection__item-container--align-left{margin-right:auto}.tox .tox-collection__item-container--row.tox-collection__item-container--align-right{justify-content:flex-end;margin-left:auto}.tox .tox-collection__item-container--row.tox-collection__item-container--valign-top{align-items:flex-start;margin-bottom:auto}.tox .tox-collection__item-container--row.tox-collection__item-container--valign-middle{align-items:center}.tox .tox-collection__item-container--row.tox-collection__item-container--valign-bottom{align-items:flex-end;margin-top:auto}.tox .tox-collection__item-container--column{-ms-grid-row-align:center;align-self:center;flex:1 1 auto;flex-direction:column}.tox .tox-collection__item-container--column.tox-collection__item-container--align-left{align-items:flex-start}.tox .tox-collection__item-container--column.tox-collection__item-container--align-right{align-items:flex-end}.tox .tox-collection__item-container--column.tox-collection__item-container--valign-top{align-self:flex-start}.tox .tox-collection__item-container--column.tox-collection__item-container--valign-middle{-ms-grid-row-align:center;align-self:center}.tox .tox-collection__item-container--column.tox-collection__item-container--valign-bottom{align-self:flex-end}.tox:not([dir=rtl]) .tox-collection--horizontal .tox-collection__group:not(:last-of-type){border-right:1px solid #000}.tox:not([dir=rtl]) .tox-collection--list .tox-collection__item>:not(:first-child){margin-left:8px}.tox:not([dir=rtl]) .tox-collection--list .tox-collection__item>.tox-collection__item-label:first-child{margin-left:4px}.tox:not([dir=rtl]) .tox-collection__item-accessory{margin-left:16px;text-align:right}.tox:not([dir=rtl]) .tox-collection .tox-collection__item-caret{margin-left:16px}.tox[dir=rtl] .tox-collection--horizontal .tox-collection__group:not(:last-of-type){border-left:1px solid #000}.tox[dir=rtl] .tox-collection--list .tox-collection__item>:not(:first-child){margin-right:8px}.tox[dir=rtl] .tox-collection--list .tox-collection__item>.tox-collection__item-label:first-child{margin-right:4px}.tox[dir=rtl] .tox-collection__item-icon-rtl .tox-collection__item-icon svg{transform:rotateY(180deg)}.tox[dir=rtl] .tox-collection__item-accessory{margin-right:16px;text-align:left}.tox[dir=rtl] .tox-collection .tox-collection__item-caret{margin-right:16px;transform:rotateY(180deg)}.tox[dir=rtl] .tox-collection--horizontal .tox-collection__item-caret{margin-right:4px}.tox .tox-color-picker-container{display:flex;flex-direction:row;height:225px;margin:0}.tox .tox-sv-palette{box-sizing:border-box;display:flex;height:100%}.tox .tox-sv-palette-spectrum{height:100%}.tox .tox-sv-palette,.tox .tox-sv-palette-spectrum{width:225px}.tox .tox-sv-palette-thumb{background:0 0;border:1px solid #000;border-radius:50%;box-sizing:content-box;height:12px;position:absolute;width:12px}.tox .tox-sv-palette-inner-thumb{border:1px solid #fff;border-radius:50%;height:10px;position:absolute;width:10px}.tox .tox-hue-slider{box-sizing:border-box;height:100%;width:25px}.tox .tox-hue-slider-spectrum{background:linear-gradient(to bottom,red,#ff0080,#f0f,#8000ff,#00f,#0080ff,#0ff,#00ff80,#0f0,#80ff00,#ff0,#ff8000,red);height:100%;width:100%}.tox .tox-hue-slider,.tox .tox-hue-slider-spectrum{width:20px}.tox .tox-hue-slider-thumb{background:#fff;border:1px solid #000;box-sizing:content-box;height:4px;width:100%}.tox .tox-rgb-form{display:flex;flex-direction:column;justify-content:space-between}.tox .tox-rgb-form div{align-items:center;display:flex;justify-content:space-between;margin-bottom:5px;width:inherit}.tox .tox-rgb-form input{width:6em}.tox .tox-rgb-form input.tox-invalid{border:1px solid red!important}.tox .tox-rgb-form .tox-rgba-preview{border:1px solid #000;flex-grow:2;margin-bottom:0}.tox:not([dir=rtl]) .tox-sv-palette{margin-right:15px}.tox:not([dir=rtl]) .tox-hue-slider{margin-right:15px}.tox:not([dir=rtl]) .tox-hue-slider-thumb{margin-left:-1px}.tox:not([dir=rtl]) .tox-rgb-form label{margin-right:.5em}.tox[dir=rtl] .tox-sv-palette{margin-left:15px}.tox[dir=rtl] .tox-hue-slider{margin-left:15px}.tox[dir=rtl] .tox-hue-slider-thumb{margin-right:-1px}.tox[dir=rtl] .tox-rgb-form label{margin-left:.5em}.tox .tox-toolbar .tox-swatches,.tox .tox-toolbar__overflow .tox-swatches,.tox .tox-toolbar__primary .tox-swatches{margin:2px 0 3px 4px}.tox .tox-collection--list .tox-collection__group .tox-swatches-menu{border:0;margin:-4px 0}.tox .tox-swatches__row{display:flex}.tox .tox-swatch{height:30px;transition:transform .15s,box-shadow .15s;width:30px}.tox .tox-swatch:focus,.tox .tox-swatch:hover{box-shadow:0 0 0 1px rgba(127,127,127,.3) inset;transform:scale(.8)}.tox .tox-swatch--remove{align-items:center;display:flex;justify-content:center}.tox .tox-swatch--remove svg path{stroke:#e74c3c}.tox .tox-swatches__picker-btn{align-items:center;background-color:transparent;border:0;cursor:pointer;display:flex;height:30px;justify-content:center;outline:0;padding:0;width:30px}.tox .tox-swatches__picker-btn svg{height:24px;width:24px}.tox .tox-swatches__picker-btn:hover{background:#4a5562}.tox:not([dir=rtl]) .tox-swatches__picker-btn{margin-left:auto}.tox[dir=rtl] .tox-swatches__picker-btn{margin-right:auto}.tox .tox-comment-thread{background:#2b3b4e;position:relative}.tox .tox-comment-thread>:not(:first-child){margin-top:8px}.tox .tox-comment{background:#2b3b4e;border:1px solid #000;border-radius:3px;box-shadow:0 4px 8px 0 rgba(42,55,70,.1);padding:8px 8px 16px 8px;position:relative}.tox .tox-comment__header{align-items:center;color:#fff;display:flex;justify-content:space-between}.tox .tox-comment__date{color:rgba(255,255,255,.5);font-size:12px}.tox .tox-comment__body{color:#fff;font-size:14px;font-style:normal;font-weight:400;line-height:1.3;margin-top:8px;position:relative;text-transform:initial}.tox .tox-comment__body textarea{resize:none;white-space:normal;width:100%}.tox .tox-comment__expander{padding-top:8px}.tox .tox-comment__expander p{color:rgba(255,255,255,.5);font-size:14px;font-style:normal}.tox .tox-comment__body p{margin:0}.tox .tox-comment__buttonspacing{padding-top:16px;text-align:center}.tox .tox-comment-thread__overlay::after{background:#2b3b4e;bottom:0;content:"";display:flex;left:0;opacity:.9;position:absolute;right:0;top:0;z-index:5}.tox .tox-comment__reply{display:flex;flex-shrink:0;flex-wrap:wrap;justify-content:flex-end;margin-top:8px}.tox .tox-comment__reply>:first-child{margin-bottom:8px;width:100%}.tox .tox-comment__edit{display:flex;flex-wrap:wrap;justify-content:flex-end;margin-top:16px}.tox .tox-comment__gradient::after{background:linear-gradient(rgba(43,59,78,0),#2b3b4e);bottom:0;content:"";display:block;height:5em;margin-top:-40px;position:absolute;width:100%}.tox .tox-comment__overlay{background:#2b3b4e;bottom:0;display:flex;flex-direction:column;flex-grow:1;left:0;opacity:.9;position:absolute;right:0;text-align:center;top:0;z-index:5}.tox .tox-comment__loading-text{align-items:center;color:#fff;display:flex;flex-direction:column;position:relative}.tox .tox-comment__loading-text>div{padding-bottom:16px}.tox .tox-comment__overlaytext{bottom:0;flex-direction:column;font-size:14px;left:0;padding:1em;position:absolute;right:0;top:0;z-index:10}.tox .tox-comment__overlaytext p{background-color:#2b3b4e;box-shadow:0 0 8px 8px #2b3b4e;color:#fff;text-align:center}.tox .tox-comment__overlaytext div:nth-of-type(2){font-size:.8em}.tox .tox-comment__busy-spinner{align-items:center;background-color:#2b3b4e;bottom:0;display:flex;justify-content:center;left:0;position:absolute;right:0;top:0;z-index:20}.tox .tox-comment__scroll{display:flex;flex-direction:column;flex-shrink:1;overflow:auto}.tox .tox-conversations{margin:8px}.tox:not([dir=rtl]) .tox-comment__edit{margin-left:8px}.tox:not([dir=rtl]) .tox-comment__buttonspacing>:last-child,.tox:not([dir=rtl]) .tox-comment__edit>:last-child,.tox:not([dir=rtl]) .tox-comment__reply>:last-child{margin-left:8px}.tox[dir=rtl] .tox-comment__edit{margin-right:8px}.tox[dir=rtl] .tox-comment__buttonspacing>:last-child,.tox[dir=rtl] .tox-comment__edit>:last-child,.tox[dir=rtl] .tox-comment__reply>:last-child{margin-right:8px}.tox .tox-user{align-items:center;display:flex}.tox .tox-user__avatar svg{fill:rgba(255,255,255,.5)}.tox .tox-user__name{color:rgba(255,255,255,.5);font-size:12px;font-style:normal;font-weight:700;text-transform:uppercase}.tox:not([dir=rtl]) .tox-user__avatar svg{margin-right:8px}.tox:not([dir=rtl]) .tox-user__avatar+.tox-user__name{margin-left:8px}.tox[dir=rtl] .tox-user__avatar svg{margin-left:8px}.tox[dir=rtl] .tox-user__avatar+.tox-user__name{margin-right:8px}.tox .tox-dialog-wrap{align-items:center;bottom:0;display:flex;justify-content:center;left:0;position:fixed;right:0;top:0;z-index:1100}.tox .tox-dialog-wrap__backdrop{background-color:rgba(34,47,62,.75);bottom:0;left:0;position:absolute;right:0;top:0;z-index:1}.tox .tox-dialog-wrap__backdrop--opaque{background-color:#222f3e}.tox .tox-dialog{background-color:#2b3b4e;border-color:#000;border-radius:3px;border-style:solid;border-width:1px;box-shadow:0 16px 16px -10px rgba(42,55,70,.15),0 0 40px 1px rgba(42,55,70,.15);display:flex;flex-direction:column;max-height:100%;max-width:480px;overflow:hidden;position:relative;width:95vw;z-index:2}@media only screen and (max-width:767px){body:not(.tox-force-desktop) .tox .tox-dialog{align-self:flex-start;margin:8px auto;width:calc(100vw - 16px)}}.tox .tox-dialog-inline{z-index:1100}.tox .tox-dialog__header{align-items:center;background-color:#2b3b4e;border-bottom:none;color:#fff;display:flex;font-size:16px;justify-content:space-between;padding:8px 16px 0 16px;position:relative}.tox .tox-dialog__header .tox-button{z-index:1}.tox .tox-dialog__draghandle{cursor:grab;height:100%;left:0;position:absolute;top:0;width:100%}.tox .tox-dialog__draghandle:active{cursor:grabbing}.tox .tox-dialog__dismiss{margin-left:auto}.tox .tox-dialog__title{font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Oxygen-Sans,Ubuntu,Cantarell,"Helvetica Neue",sans-serif;font-size:20px;font-style:normal;font-weight:400;line-height:1.3;margin:0;text-transform:none}.tox .tox-dialog__body{color:#fff;display:flex;flex:1;-ms-flex-preferred-size:auto;font-size:16px;font-style:normal;font-weight:400;line-height:1.3;min-width:0;text-align:left;text-transform:none}@media only screen and (max-width:767px){body:not(.tox-force-desktop) .tox .tox-dialog__body{flex-direction:column}}.tox .tox-dialog__body-nav{align-items:flex-start;display:flex;flex-direction:column;padding:16px 16px}@media only screen and (max-width:767px){body:not(.tox-force-desktop) .tox .tox-dialog__body-nav{flex-direction:row;-webkit-overflow-scrolling:touch;overflow-x:auto;padding-bottom:0}}.tox .tox-dialog__body-nav-item{border-bottom:2px solid transparent;color:rgba(255,255,255,.5);display:inline-block;font-size:14px;line-height:1.3;margin-bottom:8px;text-decoration:none;white-space:nowrap}.tox .tox-dialog__body-nav-item:focus{background-color:rgba(32,122,183,.1)}.tox .tox-dialog__body-nav-item--active{border-bottom:2px solid #207ab7;color:#207ab7}.tox .tox-dialog__body-content{box-sizing:border-box;display:flex;flex:1;flex-direction:column;-ms-flex-preferred-size:auto;max-height:650px;overflow:auto;-webkit-overflow-scrolling:touch;padding:16px 16px}.tox .tox-dialog__body-content>*{margin-bottom:0;margin-top:16px}.tox .tox-dialog__body-content>:first-child{margin-top:0}.tox .tox-dialog__body-content>:last-child{margin-bottom:0}.tox .tox-dialog__body-content>:only-child{margin-bottom:0;margin-top:0}.tox .tox-dialog__body-content a{color:#207ab7;cursor:pointer;text-decoration:none}.tox .tox-dialog__body-content a:focus,.tox .tox-dialog__body-content a:hover{color:#185d8c;text-decoration:none}.tox .tox-dialog__body-content a:active{color:#185d8c;text-decoration:none}.tox .tox-dialog__body-content svg{fill:#fff}.tox .tox-dialog__body-content ul{display:block;list-style-type:disc;margin-bottom:16px;-webkit-margin-end:0;margin-inline-end:0;-webkit-margin-start:0;margin-inline-start:0;-webkit-padding-start:2.5rem;padding-inline-start:2.5rem}.tox .tox-dialog__body-content .tox-form__group h1{color:#fff;font-size:20px;font-style:normal;font-weight:700;letter-spacing:normal;margin-bottom:16px;margin-top:2rem;text-transform:none}.tox .tox-dialog__body-content .tox-form__group h2{color:#fff;font-size:16px;font-style:normal;font-weight:700;letter-spacing:normal;margin-bottom:16px;margin-top:2rem;text-transform:none}.tox .tox-dialog__body-content .tox-form__group p{margin-bottom:16px}.tox .tox-dialog__body-content .tox-form__group h1:first-child,.tox .tox-dialog__body-content .tox-form__group h2:first-child,.tox .tox-dialog__body-content .tox-form__group p:first-child{margin-top:0}.tox .tox-dialog__body-content .tox-form__group h1:last-child,.tox .tox-dialog__body-content .tox-form__group h2:last-child,.tox .tox-dialog__body-content .tox-form__group p:last-child{margin-bottom:0}.tox .tox-dialog__body-content .tox-form__group h1:only-child,.tox .tox-dialog__body-content .tox-form__group h2:only-child,.tox .tox-dialog__body-content .tox-form__group p:only-child{margin-bottom:0;margin-top:0}.tox .tox-dialog--width-lg{height:650px;max-width:1200px}.tox .tox-dialog--width-md{max-width:800px}.tox .tox-dialog--width-md .tox-dialog__body-content{overflow:auto}.tox .tox-dialog__body-content--centered{text-align:center}.tox .tox-dialog__footer{align-items:center;background-color:#2b3b4e;border-top:1px solid #000;display:flex;justify-content:space-between;padding:8px 16px}.tox .tox-dialog__footer-end,.tox .tox-dialog__footer-start{display:flex}.tox .tox-dialog__busy-spinner{align-items:center;background-color:rgba(34,47,62,.75);bottom:0;display:flex;justify-content:center;left:0;position:absolute;right:0;top:0;z-index:3}.tox .tox-dialog__table{border-collapse:collapse;width:100%}.tox .tox-dialog__table thead th{font-weight:700;padding-bottom:8px}.tox .tox-dialog__table tbody tr{border-bottom:1px solid #000}.tox .tox-dialog__table tbody tr:last-child{border-bottom:none}.tox .tox-dialog__table td{padding-bottom:8px;padding-top:8px}.tox .tox-dialog__popups{position:absolute;width:100%;z-index:1100}.tox .tox-dialog__body-iframe{display:flex;flex:1;flex-direction:column;-ms-flex-preferred-size:auto}.tox .tox-dialog__body-iframe .tox-navobj{display:flex;flex:1;-ms-flex-preferred-size:auto}.tox .tox-dialog__body-iframe .tox-navobj :nth-child(2){flex:1;-ms-flex-preferred-size:auto;height:100%}.tox .tox-dialog-dock-fadeout{opacity:0;visibility:hidden}.tox .tox-dialog-dock-fadein{opacity:1;visibility:visible}.tox .tox-dialog-dock-transition{transition:visibility 0s linear .3s,opacity .3s ease}.tox .tox-dialog-dock-transition.tox-dialog-dock-fadein{transition-delay:0s}.tox.tox-platform-ie .tox-dialog-wrap{position:-ms-device-fixed}@media only screen and (max-width:767px){body:not(.tox-force-desktop) .tox:not([dir=rtl]) .tox-dialog__body-nav{margin-right:0}}@media only screen and (max-width:767px){body:not(.tox-force-desktop) .tox:not([dir=rtl]) .tox-dialog__body-nav-item:not(:first-child){margin-left:8px}}.tox:not([dir=rtl]) .tox-dialog__footer .tox-dialog__footer-end>*,.tox:not([dir=rtl]) .tox-dialog__footer .tox-dialog__footer-start>*{margin-left:8px}.tox[dir=rtl] .tox-dialog__body{text-align:right}@media only screen and (max-width:767px){body:not(.tox-force-desktop) .tox[dir=rtl] .tox-dialog__body-nav{margin-left:0}}@media only screen and (max-width:767px){body:not(.tox-force-desktop) .tox[dir=rtl] .tox-dialog__body-nav-item:not(:first-child){margin-right:8px}}.tox[dir=rtl] .tox-dialog__footer .tox-dialog__footer-end>*,.tox[dir=rtl] .tox-dialog__footer .tox-dialog__footer-start>*{margin-right:8px}body.tox-dialog__disable-scroll{overflow:hidden}.tox .tox-dropzone-container{display:flex;flex:1;-ms-flex-preferred-size:auto}.tox .tox-dropzone{align-items:center;background:#fff;border:2px dashed #000;box-sizing:border-box;display:flex;flex-direction:column;flex-grow:1;justify-content:center;min-height:100px;padding:10px}.tox .tox-dropzone p{color:rgba(255,255,255,.5);margin:0 0 16px 0}.tox .tox-edit-area{display:flex;flex:1;-ms-flex-preferred-size:auto;overflow:hidden;position:relative}.tox .tox-edit-area__iframe{background-color:#fff;border:0;box-sizing:border-box;flex:1;-ms-flex-preferred-size:auto;height:100%;position:absolute;width:100%}.tox.tox-inline-edit-area{border:1px dotted #000}.tox .tox-editor-container{display:flex;flex:1 1 auto;flex-direction:column;overflow:hidden}.tox .tox-editor-header{z-index:1000}.tox:not(.tox-tinymce-inline) .tox-editor-header{box-shadow:none;transition:box-shadow .5s}.tox.tox-tinymce--toolbar-bottom .tox-editor-header,.tox.tox-tinymce-inline .tox-editor-header{margin-bottom:-1px}.tox.tox-tinymce--toolbar-sticky-on .tox-editor-header{background-color:transparent;box-shadow:0 4px 4px -3px rgba(0,0,0,.25)}.tox-editor-dock-fadeout{opacity:0;visibility:hidden}.tox-editor-dock-fadein{opacity:1;visibility:visible}.tox-editor-dock-transition{transition:visibility 0s linear .25s,opacity .25s ease}.tox-editor-dock-transition.tox-editor-dock-fadein{transition-delay:0s}.tox .tox-control-wrap{flex:1;position:relative}.tox .tox-control-wrap:not(.tox-control-wrap--status-invalid) .tox-control-wrap__status-icon-invalid,.tox .tox-control-wrap:not(.tox-control-wrap--status-unknown) .tox-control-wrap__status-icon-unknown,.tox .tox-control-wrap:not(.tox-control-wrap--status-valid) .tox-control-wrap__status-icon-valid{display:none}.tox .tox-control-wrap svg{display:block}.tox .tox-control-wrap__status-icon-wrap{position:absolute;top:50%;transform:translateY(-50%)}.tox .tox-control-wrap__status-icon-invalid svg{fill:#c00}.tox .tox-control-wrap__status-icon-unknown svg{fill:orange}.tox .tox-control-wrap__status-icon-valid svg{fill:green}.tox:not([dir=rtl]) .tox-control-wrap--status-invalid .tox-textfield,.tox:not([dir=rtl]) .tox-control-wrap--status-unknown .tox-textfield,.tox:not([dir=rtl]) .tox-control-wrap--status-valid .tox-textfield{padding-right:32px}.tox:not([dir=rtl]) .tox-control-wrap__status-icon-wrap{right:4px}.tox[dir=rtl] .tox-control-wrap--status-invalid .tox-textfield,.tox[dir=rtl] .tox-control-wrap--status-unknown .tox-textfield,.tox[dir=rtl] .tox-control-wrap--status-valid .tox-textfield{padding-left:32px}.tox[dir=rtl] .tox-control-wrap__status-icon-wrap{left:4px}.tox .tox-autocompleter{max-width:25em}.tox .tox-autocompleter .tox-menu{max-width:25em}.tox .tox-autocompleter .tox-autocompleter-highlight{font-weight:700}.tox .tox-color-input{display:flex;position:relative;z-index:1}.tox .tox-color-input .tox-textfield{z-index:-1}.tox .tox-color-input span{border-color:rgba(42,55,70,.2);border-radius:3px;border-style:solid;border-width:1px;box-shadow:none;box-sizing:border-box;height:24px;position:absolute;top:6px;width:24px}.tox .tox-color-input span:focus:not([aria-disabled=true]),.tox .tox-color-input span:hover:not([aria-disabled=true]){border-color:#207ab7;cursor:pointer}.tox .tox-color-input span::before{background-image:linear-gradient(45deg,rgba(255,255,255,.25) 25%,transparent 25%),linear-gradient(-45deg,rgba(255,255,255,.25) 25%,transparent 25%),linear-gradient(45deg,transparent 75%,rgba(255,255,255,.25) 75%),linear-gradient(-45deg,transparent 75%,rgba(255,255,255,.25) 75%);background-position:0 0,0 6px,6px -6px,-6px 0;background-size:12px 12px;border:1px solid #2b3b4e;border-radius:3px;box-sizing:border-box;content:'';height:24px;left:-1px;position:absolute;top:-1px;width:24px;z-index:-1}.tox .tox-color-input span[aria-disabled=true]{cursor:not-allowed}.tox:not([dir=rtl]) .tox-color-input .tox-textfield{padding-left:36px}.tox:not([dir=rtl]) .tox-color-input span{left:6px}.tox[dir=rtl] .tox-color-input .tox-textfield{padding-right:36px}.tox[dir=rtl] .tox-color-input span{right:6px}.tox .tox-label,.tox .tox-toolbar-label{color:rgba(255,255,255,.5);display:block;font-size:14px;font-style:normal;font-weight:400;line-height:1.3;padding:0 8px 0 0;text-transform:none;white-space:nowrap}.tox .tox-toolbar-label{padding:0 8px}.tox[dir=rtl] .tox-label{padding:0 0 0 8px}.tox .tox-form{display:flex;flex:1;flex-direction:column;-ms-flex-preferred-size:auto}.tox .tox-form__group{box-sizing:border-box;margin-bottom:4px}.tox .tox-form-group--maximize{flex:1}.tox .tox-form__group--error{color:#c00}.tox .tox-form__group--collection{display:flex}.tox .tox-form__grid{display:flex;flex-direction:row;flex-wrap:wrap;justify-content:space-between}.tox .tox-form__grid--2col>.tox-form__group{width:calc(50% - (8px / 2))}.tox .tox-form__grid--3col>.tox-form__group{width:calc(100% / 3 - (8px / 2))}.tox .tox-form__grid--4col>.tox-form__group{width:calc(25% - (8px / 2))}.tox .tox-form__controls-h-stack{align-items:center;display:flex}.tox .tox-form__group--inline{align-items:center;display:flex}.tox .tox-form__group--stretched{display:flex;flex:1;flex-direction:column;-ms-flex-preferred-size:auto}.tox .tox-form__group--stretched .tox-textarea{flex:1;-ms-flex-preferred-size:auto}.tox .tox-form__group--stretched .tox-navobj{display:flex;flex:1;-ms-flex-preferred-size:auto}.tox .tox-form__group--stretched .tox-navobj :nth-child(2){flex:1;-ms-flex-preferred-size:auto;height:100%}.tox:not([dir=rtl]) .tox-form__controls-h-stack>:not(:first-child){margin-left:4px}.tox[dir=rtl] .tox-form__controls-h-stack>:not(:first-child){margin-right:4px}.tox .tox-lock.tox-locked .tox-lock-icon__unlock,.tox .tox-lock:not(.tox-locked) .tox-lock-icon__lock{display:none}.tox .tox-listboxfield .tox-listbox--select,.tox .tox-textarea,.tox .tox-textfield,.tox .tox-toolbar-textfield{-webkit-appearance:none;-moz-appearance:none;appearance:none;background-color:#2b3b4e;border-color:#000;border-radius:3px;border-style:solid;border-width:1px;box-shadow:none;box-sizing:border-box;color:#fff;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Oxygen-Sans,Ubuntu,Cantarell,"Helvetica Neue",sans-serif;font-size:16px;line-height:24px;margin:0;min-height:34px;outline:0;padding:5px 4.75px;resize:none;width:100%}.tox .tox-textarea[disabled],.tox .tox-textfield[disabled]{background-color:#222f3e;color:rgba(255,255,255,.85);cursor:not-allowed}.tox .tox-listboxfield .tox-listbox--select:focus,.tox .tox-textarea:focus,.tox .tox-textfield:focus{background-color:#2b3b4e;border-color:#207ab7;box-shadow:none;outline:0}.tox .tox-toolbar-textfield{border-width:0;margin-bottom:3px;margin-top:2px;max-width:250px}.tox .tox-naked-btn{background-color:transparent;border:0;border-color:transparent;box-shadow:unset;color:#207ab7;cursor:pointer;display:block;margin:0;padding:0}.tox .tox-naked-btn svg{display:block;fill:#fff}.tox:not([dir=rtl]) .tox-toolbar-textfield+*{margin-left:4px}.tox[dir=rtl] .tox-toolbar-textfield+*{margin-right:4px}.tox .tox-listboxfield{cursor:pointer;position:relative}.tox .tox-listboxfield .tox-listbox--select[disabled]{background-color:#19232e;color:rgba(255,255,255,.85);cursor:not-allowed}.tox .tox-listbox__select-label{cursor:default;flex:1;margin:0 4px}.tox .tox-listbox__select-chevron{align-items:center;display:flex;justify-content:center;width:16px}.tox .tox-listbox__select-chevron svg{fill:#fff}.tox .tox-listboxfield .tox-listbox--select{align-items:center;display:flex}.tox:not([dir=rtl]) .tox-listboxfield svg{right:8px}.tox[dir=rtl] .tox-listboxfield svg{left:8px}.tox .tox-selectfield{cursor:pointer;position:relative}.tox .tox-selectfield select{-webkit-appearance:none;-moz-appearance:none;appearance:none;background-color:#2b3b4e;border-color:#000;border-radius:3px;border-style:solid;border-width:1px;box-shadow:none;box-sizing:border-box;color:#fff;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Oxygen-Sans,Ubuntu,Cantarell,"Helvetica Neue",sans-serif;font-size:16px;line-height:24px;margin:0;min-height:34px;outline:0;padding:5px 4.75px;resize:none;width:100%}.tox .tox-selectfield select[disabled]{background-color:#19232e;color:rgba(255,255,255,.85);cursor:not-allowed}.tox .tox-selectfield select::-ms-expand{display:none}.tox .tox-selectfield select:focus{background-color:#2b3b4e;border-color:#207ab7;box-shadow:none;outline:0}.tox .tox-selectfield svg{pointer-events:none;position:absolute;top:50%;transform:translateY(-50%)}.tox:not([dir=rtl]) .tox-selectfield select[size="0"],.tox:not([dir=rtl]) .tox-selectfield select[size="1"]{padding-right:24px}.tox:not([dir=rtl]) .tox-selectfield svg{right:8px}.tox[dir=rtl] .tox-selectfield select[size="0"],.tox[dir=rtl] .tox-selectfield select[size="1"]{padding-left:24px}.tox[dir=rtl] .tox-selectfield svg{left:8px}.tox .tox-textarea{-webkit-appearance:textarea;-moz-appearance:textarea;appearance:textarea;white-space:pre-wrap}.tox-fullscreen{border:0;height:100%;left:0;margin:0;overflow:hidden;-ms-scroll-chaining:none;overscroll-behavior:none;padding:0;position:fixed;top:0;touch-action:pinch-zoom;width:100%}.tox.tox-tinymce.tox-fullscreen .tox-statusbar__resize-handle{display:none}.tox.tox-tinymce.tox-fullscreen{background-color:transparent;z-index:1200}.tox-shadowhost.tox-fullscreen{z-index:1200}.tox-fullscreen .tox.tox-tinymce-aux,.tox-fullscreen~.tox.tox-tinymce-aux{z-index:1201}.tox .tox-help__more-link{list-style:none;margin-top:1em}.tox .tox-image-tools{width:100%}.tox .tox-image-tools__toolbar{align-items:center;display:flex;justify-content:center}.tox .tox-image-tools__image{background-color:#666;height:380px;overflow:auto;position:relative;width:100%}.tox .tox-image-tools__image,.tox .tox-image-tools__image+.tox-image-tools__toolbar{margin-top:8px}.tox .tox-image-tools__image-bg{background:url(data:image/gif;base64,R0lGODdhDAAMAIABAMzMzP///ywAAAAADAAMAAACFoQfqYeabNyDMkBQb81Uat85nxguUAEAOw==)}.tox .tox-image-tools__toolbar>.tox-spacer{flex:1;-ms-flex-preferred-size:auto}.tox .tox-croprect-block{background:#000;opacity:.5;position:absolute;zoom:1}.tox .tox-croprect-handle{border:2px solid #fff;height:20px;left:0;position:absolute;top:0;width:20px}.tox .tox-croprect-handle-move{border:0;cursor:move;position:absolute}.tox .tox-croprect-handle-nw{border-width:2px 0 0 2px;cursor:nw-resize;left:100px;margin:-2px 0 0 -2px;top:100px}.tox .tox-croprect-handle-ne{border-width:2px 2px 0 0;cursor:ne-resize;left:200px;margin:-2px 0 0 -20px;top:100px}.tox .tox-croprect-handle-sw{border-width:0 0 2px 2px;cursor:sw-resize;left:100px;margin:-20px 2px 0 -2px;top:200px}.tox .tox-croprect-handle-se{border-width:0 2px 2px 0;cursor:se-resize;left:200px;margin:-20px 0 0 -20px;top:200px}.tox:not([dir=rtl]) .tox-image-tools__toolbar>.tox-slider:not(:first-of-type){margin-left:8px}.tox:not([dir=rtl]) .tox-image-tools__toolbar>.tox-button+.tox-slider{margin-left:32px}.tox:not([dir=rtl]) .tox-image-tools__toolbar>.tox-slider+.tox-button{margin-left:32px}.tox[dir=rtl] .tox-image-tools__toolbar>.tox-slider:not(:first-of-type){margin-right:8px}.tox[dir=rtl] .tox-image-tools__toolbar>.tox-button+.tox-slider{margin-right:32px}.tox[dir=rtl] .tox-image-tools__toolbar>.tox-slider+.tox-button{margin-right:32px}.tox .tox-insert-table-picker{display:flex;flex-wrap:wrap;width:170px}.tox .tox-insert-table-picker>div{border-color:#000;border-style:solid;border-width:0 1px 1px 0;box-sizing:border-box;height:17px;width:17px}.tox .tox-collection--list .tox-collection__group .tox-insert-table-picker{margin:-4px 0}.tox .tox-insert-table-picker .tox-insert-table-picker__selected{background-color:rgba(32,122,183,.5);border-color:rgba(32,122,183,.5)}.tox .tox-insert-table-picker__label{color:#fff;display:block;font-size:14px;padding:4px;text-align:center;width:100%}.tox:not([dir=rtl]) .tox-insert-table-picker>div:nth-child(10n){border-right:0}.tox[dir=rtl] .tox-insert-table-picker>div:nth-child(10n+1){border-right:0}.tox .tox-menu{background-color:#2b3b4e;border:1px solid #000;border-radius:3px;box-shadow:0 4px 8px 0 rgba(42,55,70,.1);display:inline-block;overflow:hidden;vertical-align:top;z-index:1150}.tox .tox-menu.tox-collection.tox-collection--list{padding:0}.tox .tox-menu.tox-collection.tox-collection--toolbar{padding:4px}.tox .tox-menu.tox-collection.tox-collection--grid{padding:4px}.tox .tox-menu__label blockquote,.tox .tox-menu__label code,.tox .tox-menu__label h1,.tox .tox-menu__label h2,.tox .tox-menu__label h3,.tox .tox-menu__label h4,.tox .tox-menu__label h5,.tox .tox-menu__label h6,.tox .tox-menu__label p{margin:0}.tox .tox-menubar{background:url("data:image/svg+xml;charset=utf8,%3Csvg height='39px' viewBox='0 0 40 39px' width='40' xmlns='http://www.w3.org/2000/svg'%3E%3Crect x='0' y='38px' width='100' height='1' fill='%23000000'/%3E%3C/svg%3E") left 0 top 0 #222f3e;background-color:#222f3e;display:flex;flex:0 0 auto;flex-shrink:0;flex-wrap:wrap;padding:0 4px 0 4px}.tox.tox-tinymce:not(.tox-tinymce-inline) .tox-editor-header:not(:first-child) .tox-menubar{border-top:1px solid #000}.tox .tox-mbtn{align-items:center;background:0 0;border:0;border-radius:3px;box-shadow:none;color:#fff;display:flex;flex:0 0 auto;font-size:14px;font-style:normal;font-weight:400;height:34px;justify-content:center;margin:2px 0 3px 0;outline:0;overflow:hidden;padding:0 4px;text-transform:none;width:auto}.tox .tox-mbtn[disabled]{background-color:transparent;border:0;box-shadow:none;color:rgba(255,255,255,.5);cursor:not-allowed}.tox .tox-mbtn:focus:not(:disabled){background:#4a5562;border:0;box-shadow:none;color:#fff}.tox .tox-mbtn--active{background:#757d87;border:0;box-shadow:none;color:#fff}.tox .tox-mbtn:hover:not(:disabled):not(.tox-mbtn--active){background:#4a5562;border:0;box-shadow:none;color:#fff}.tox .tox-mbtn__select-label{cursor:default;font-weight:400;margin:0 4px}.tox .tox-mbtn[disabled] .tox-mbtn__select-label{cursor:not-allowed}.tox .tox-mbtn__select-chevron{align-items:center;display:flex;justify-content:center;width:16px;display:none}.tox .tox-notification{border-radius:3px;border-style:solid;border-width:1px;box-shadow:none;box-sizing:border-box;display:-ms-grid;display:grid;font-size:14px;font-weight:400;-ms-grid-columns:minmax(40px,1fr) auto minmax(40px,1fr);grid-template-columns:minmax(40px,1fr) auto minmax(40px,1fr);margin-top:4px;opacity:0;padding:4px;transition:transform .1s ease-in,opacity 150ms ease-in}.tox .tox-notification p{font-size:14px;font-weight:400}.tox .tox-notification a{text-decoration:underline}.tox .tox-notification--in{opacity:1}.tox .tox-notification--success{background-color:#e4eeda;border-color:#d7e6c8;color:#fff}.tox .tox-notification--success p{color:#fff}.tox .tox-notification--success a{color:#547831}.tox .tox-notification--success svg{fill:#fff}.tox .tox-notification--error{background-color:#f8dede;border-color:#f2bfbf;color:#fff}.tox .tox-notification--error p{color:#fff}.tox .tox-notification--error a{color:#c00}.tox .tox-notification--error svg{fill:#fff}.tox .tox-notification--warn,.tox .tox-notification--warning{background-color:#fffaea;border-color:#ffe89d;color:#fff}.tox .tox-notification--warn p,.tox .tox-notification--warning p{color:#fff}.tox .tox-notification--warn a,.tox .tox-notification--warning a{color:#fff}.tox .tox-notification--warn svg,.tox .tox-notification--warning svg{fill:#fff}.tox .tox-notification--info{background-color:#d9edf7;border-color:#779ecb;color:#fff}.tox .tox-notification--info p{color:#fff}.tox .tox-notification--info a{color:#fff}.tox .tox-notification--info svg{fill:#fff}.tox .tox-notification__body{-ms-grid-row-align:center;align-self:center;color:#fff;font-size:14px;-ms-grid-column-span:1;grid-column-end:3;-ms-grid-column:2;grid-column-start:2;-ms-grid-row-span:1;grid-row-end:2;-ms-grid-row:1;grid-row-start:1;text-align:center;white-space:normal;word-break:break-all;word-break:break-word}.tox .tox-notification__body>*{margin:0}.tox .tox-notification__body>*+*{margin-top:1rem}.tox .tox-notification__icon{-ms-grid-row-align:center;align-self:center;-ms-grid-column-span:1;grid-column-end:2;-ms-grid-column:1;grid-column-start:1;-ms-grid-row-span:1;grid-row-end:2;-ms-grid-row:1;grid-row-start:1;-ms-grid-column-align:end;justify-self:end}.tox .tox-notification__icon svg{display:block}.tox .tox-notification__dismiss{-ms-grid-row-align:start;align-self:start;-ms-grid-column-span:1;grid-column-end:4;-ms-grid-column:3;grid-column-start:3;-ms-grid-row-span:1;grid-row-end:2;-ms-grid-row:1;grid-row-start:1;-ms-grid-column-align:end;justify-self:end}.tox .tox-notification .tox-progress-bar{-ms-grid-column-span:3;grid-column-end:4;-ms-grid-column:1;grid-column-start:1;-ms-grid-row-span:1;grid-row-end:3;-ms-grid-row:2;grid-row-start:2;-ms-grid-column-align:center;justify-self:center}.tox .tox-pop{display:inline-block;position:relative}.tox .tox-pop--resizing{transition:width .1s ease}.tox .tox-pop--resizing .tox-toolbar{flex-wrap:nowrap}.tox .tox-pop__dialog{background-color:#222f3e;border:1px solid #000;border-radius:3px;box-shadow:0 1px 3px rgba(0,0,0,.15);min-width:0;overflow:hidden}.tox .tox-pop__dialog>:not(.tox-toolbar){margin:4px 4px 4px 8px}.tox .tox-pop__dialog .tox-toolbar{background-color:transparent;margin-bottom:-1px}.tox .tox-pop::after,.tox .tox-pop::before{border-style:solid;content:'';display:block;height:0;position:absolute;width:0}.tox .tox-pop.tox-pop--bottom::after,.tox .tox-pop.tox-pop--bottom::before{left:50%;top:100%}.tox .tox-pop.tox-pop--bottom::after{border-color:#222f3e transparent transparent transparent;border-width:8px;margin-left:-8px;margin-top:-1px}.tox .tox-pop.tox-pop--bottom::before{border-color:#000 transparent transparent transparent;border-width:9px;margin-left:-9px}.tox .tox-pop.tox-pop--top::after,.tox .tox-pop.tox-pop--top::before{left:50%;top:0;transform:translateY(-100%)}.tox .tox-pop.tox-pop--top::after{border-color:transparent transparent #222f3e transparent;border-width:8px;margin-left:-8px;margin-top:1px}.tox .tox-pop.tox-pop--top::before{border-color:transparent transparent #000 transparent;border-width:9px;margin-left:-9px}.tox .tox-pop.tox-pop--left::after,.tox .tox-pop.tox-pop--left::before{left:0;top:calc(50% - 1px);transform:translateY(-50%)}.tox .tox-pop.tox-pop--left::after{border-color:transparent #222f3e transparent transparent;border-width:8px;margin-left:-15px}.tox .tox-pop.tox-pop--left::before{border-color:transparent #000 transparent transparent;border-width:10px;margin-left:-19px}.tox .tox-pop.tox-pop--right::after,.tox .tox-pop.tox-pop--right::before{left:100%;top:calc(50% + 1px);transform:translateY(-50%)}.tox .tox-pop.tox-pop--right::after{border-color:transparent transparent transparent #222f3e;border-width:8px;margin-left:-1px}.tox .tox-pop.tox-pop--right::before{border-color:transparent transparent transparent #000;border-width:10px;margin-left:-1px}.tox .tox-pop.tox-pop--align-left::after,.tox .tox-pop.tox-pop--align-left::before{left:20px}.tox .tox-pop.tox-pop--align-right::after,.tox .tox-pop.tox-pop--align-right::before{left:calc(100% - 20px)}.tox .tox-sidebar-wrap{display:flex;flex-direction:row;flex-grow:1;-ms-flex-preferred-size:0;min-height:0}.tox .tox-sidebar{background-color:#222f3e;display:flex;flex-direction:row;justify-content:flex-end}.tox .tox-sidebar__slider{display:flex;overflow:hidden}.tox .tox-sidebar__pane-container{display:flex}.tox .tox-sidebar__pane{display:flex}.tox .tox-sidebar--sliding-closed{opacity:0}.tox .tox-sidebar--sliding-open{opacity:1}.tox .tox-sidebar--sliding-growing,.tox .tox-sidebar--sliding-shrinking{transition:width .5s ease,opacity .5s ease}.tox .tox-selector{background-color:#4099ff;border-color:#4099ff;border-style:solid;border-width:1px;box-sizing:border-box;display:inline-block;height:10px;position:absolute;width:10px}.tox.tox-platform-touch .tox-selector{height:12px;width:12px}.tox .tox-slider{align-items:center;display:flex;flex:1;-ms-flex-preferred-size:auto;height:24px;justify-content:center;position:relative}.tox .tox-slider__rail{background-color:transparent;border:1px solid #000;border-radius:3px;height:10px;min-width:120px;width:100%}.tox .tox-slider__handle{background-color:#207ab7;border:2px solid #185d8c;border-radius:3px;box-shadow:none;height:24px;left:50%;position:absolute;top:50%;transform:translateX(-50%) translateY(-50%);width:14px}.tox .tox-source-code{overflow:auto}.tox .tox-spinner{display:flex}.tox .tox-spinner>div{animation:tam-bouncing-dots 1.5s ease-in-out 0s infinite both;background-color:rgba(255,255,255,.5);border-radius:100%;height:8px;width:8px}.tox .tox-spinner>div:nth-child(1){animation-delay:-.32s}.tox .tox-spinner>div:nth-child(2){animation-delay:-.16s}@keyframes tam-bouncing-dots{0%,100%,80%{transform:scale(0)}40%{transform:scale(1)}}.tox:not([dir=rtl]) .tox-spinner>div:not(:first-child){margin-left:4px}.tox[dir=rtl] .tox-spinner>div:not(:first-child){margin-right:4px}.tox .tox-statusbar{align-items:center;background-color:#222f3e;border-top:1px solid #000;color:#fff;display:flex;flex:0 0 auto;font-size:12px;font-weight:400;height:18px;overflow:hidden;padding:0 8px;position:relative;text-transform:uppercase}.tox .tox-statusbar__text-container{display:flex;flex:1 1 auto;justify-content:flex-end;overflow:hidden}.tox .tox-statusbar__path{display:flex;flex:1 1 auto;margin-right:auto;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.tox .tox-statusbar__path>*{display:inline;white-space:nowrap}.tox .tox-statusbar__wordcount{flex:0 0 auto;margin-left:1ch}.tox .tox-statusbar a,.tox .tox-statusbar__path-item,.tox .tox-statusbar__wordcount{color:#fff;text-decoration:none}.tox .tox-statusbar a:focus:not(:disabled):not([aria-disabled=true]),.tox .tox-statusbar a:hover:not(:disabled):not([aria-disabled=true]),.tox .tox-statusbar__path-item:focus:not(:disabled):not([aria-disabled=true]),.tox .tox-statusbar__path-item:hover:not(:disabled):not([aria-disabled=true]),.tox .tox-statusbar__wordcount:focus:not(:disabled):not([aria-disabled=true]),.tox .tox-statusbar__wordcount:hover:not(:disabled):not([aria-disabled=true]){cursor:pointer;text-decoration:underline}.tox .tox-statusbar__resize-handle{align-items:flex-end;align-self:stretch;cursor:nwse-resize;display:flex;flex:0 0 auto;justify-content:flex-end;margin-left:auto;margin-right:-8px;padding-left:1ch}.tox .tox-statusbar__resize-handle svg{display:block;fill:#fff}.tox .tox-statusbar__resize-handle:focus svg{background-color:#4a5562;border-radius:1px;box-shadow:0 0 0 2px #4a5562}.tox:not([dir=rtl]) .tox-statusbar__path>*{margin-right:4px}.tox:not([dir=rtl]) .tox-statusbar__branding{margin-left:1ch}.tox[dir=rtl] .tox-statusbar{flex-direction:row-reverse}.tox[dir=rtl] .tox-statusbar__path>*{margin-left:4px}.tox .tox-throbber{z-index:1299}.tox .tox-throbber__busy-spinner{align-items:center;background-color:rgba(34,47,62,.6);bottom:0;display:flex;justify-content:center;left:0;position:absolute;right:0;top:0}.tox .tox-tbtn{align-items:center;background:0 0;border:0;border-radius:3px;box-shadow:none;color:#fff;display:flex;flex:0 0 auto;font-size:14px;font-style:normal;font-weight:400;height:34px;justify-content:center;margin:2px 0 3px 0;outline:0;overflow:hidden;padding:0;text-transform:none;width:34px}.tox .tox-tbtn svg{display:block;fill:#fff}.tox .tox-tbtn.tox-tbtn-more{padding-left:5px;padding-right:5px;width:inherit}.tox .tox-tbtn:focus{background:#4a5562;border:0;box-shadow:none}.tox .tox-tbtn:hover{background:#4a5562;border:0;box-shadow:none;color:#fff}.tox .tox-tbtn:hover svg{fill:#fff}.tox .tox-tbtn:active{background:#757d87;border:0;box-shadow:none;color:#fff}.tox .tox-tbtn:active svg{fill:#fff}.tox .tox-tbtn--disabled,.tox .tox-tbtn--disabled:hover,.tox .tox-tbtn:disabled,.tox .tox-tbtn:disabled:hover{background:0 0;border:0;box-shadow:none;color:rgba(255,255,255,.5);cursor:not-allowed}.tox .tox-tbtn--disabled svg,.tox .tox-tbtn--disabled:hover svg,.tox .tox-tbtn:disabled svg,.tox .tox-tbtn:disabled:hover svg{fill:rgba(255,255,255,.5)}.tox .tox-tbtn--enabled,.tox .tox-tbtn--enabled:hover{background:#757d87;border:0;box-shadow:none;color:#fff}.tox .tox-tbtn--enabled:hover>*,.tox .tox-tbtn--enabled>*{transform:none}.tox .tox-tbtn--enabled svg,.tox .tox-tbtn--enabled:hover svg{fill:#fff}.tox .tox-tbtn:focus:not(.tox-tbtn--disabled){color:#fff}.tox .tox-tbtn:focus:not(.tox-tbtn--disabled) svg{fill:#fff}.tox .tox-tbtn:active>*{transform:none}.tox .tox-tbtn--md{height:51px;width:51px}.tox .tox-tbtn--lg{flex-direction:column;height:68px;width:68px}.tox .tox-tbtn--return{-ms-grid-row-align:stretch;align-self:stretch;height:unset;width:16px}.tox .tox-tbtn--labeled{padding:0 4px;width:unset}.tox .tox-tbtn__vlabel{display:block;font-size:10px;font-weight:400;letter-spacing:-.025em;margin-bottom:4px;white-space:nowrap}.tox .tox-tbtn--select{margin:2px 0 3px 0;padding:0 4px;width:auto}.tox .tox-tbtn__select-label{cursor:default;font-weight:400;margin:0 4px}.tox .tox-tbtn__select-chevron{align-items:center;display:flex;justify-content:center;width:16px}.tox .tox-tbtn__select-chevron svg{fill:rgba(255,255,255,.5)}.tox .tox-tbtn--bespoke .tox-tbtn__select-label{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;width:7em}.tox .tox-split-button{border:0;border-radius:3px;box-sizing:border-box;display:flex;margin:2px 0 3px 0;overflow:hidden}.tox .tox-split-button:hover{box-shadow:0 0 0 1px #4a5562 inset}.tox .tox-split-button:focus{background:#4a5562;box-shadow:none;color:#fff}.tox .tox-split-button>*{border-radius:0}.tox .tox-split-button__chevron{width:16px}.tox .tox-split-button__chevron svg{fill:rgba(255,255,255,.5)}.tox .tox-split-button .tox-tbtn{margin:0}.tox.tox-platform-touch .tox-split-button .tox-tbtn:first-child{width:30px}.tox.tox-platform-touch .tox-split-button__chevron{width:20px}.tox .tox-split-button.tox-tbtn--disabled .tox-tbtn:focus,.tox .tox-split-button.tox-tbtn--disabled .tox-tbtn:hover,.tox .tox-split-button.tox-tbtn--disabled:focus,.tox .tox-split-button.tox-tbtn--disabled:hover{background:0 0;box-shadow:none;color:rgba(255,255,255,.5)}.tox .tox-toolbar-overlord{background-color:#222f3e}.tox .tox-toolbar,.tox .tox-toolbar__overflow,.tox .tox-toolbar__primary{background:url("data:image/svg+xml;charset=utf8,%3Csvg height='39px' viewBox='0 0 40 39px' width='40' xmlns='http://www.w3.org/2000/svg'%3E%3Crect x='0' y='38px' width='100' height='1' fill='%23000000'/%3E%3C/svg%3E") left 0 top 0 #222f3e;background-color:#222f3e;display:flex;flex:0 0 auto;flex-shrink:0;flex-wrap:wrap;padding:0 0}.tox .tox-toolbar__overflow.tox-toolbar__overflow--closed{height:0;opacity:0;padding-bottom:0;padding-top:0;visibility:hidden}.tox .tox-toolbar__overflow--growing{transition:height .3s ease,opacity .2s linear .1s}.tox .tox-toolbar__overflow--shrinking{transition:opacity .3s ease,height .2s linear .1s,visibility 0s linear .3s}.tox .tox-menubar+.tox-toolbar,.tox .tox-menubar+.tox-toolbar-overlord .tox-toolbar__primary{border-top:1px solid #000;margin-top:-1px}.tox .tox-toolbar--scrolling{flex-wrap:nowrap;overflow-x:auto}.tox .tox-pop .tox-toolbar{border-width:0}.tox .tox-toolbar--no-divider{background-image:none}.tox-tinymce:not(.tox-tinymce-inline) .tox-editor-header:not(:first-child) .tox-toolbar-overlord:first-child .tox-toolbar__primary,.tox-tinymce:not(.tox-tinymce-inline) .tox-editor-header:not(:first-child) .tox-toolbar:first-child{border-top:1px solid #000}.tox.tox-tinymce-aux .tox-toolbar__overflow{background-color:#222f3e;border:1px solid #000;border-radius:3px;box-shadow:0 1px 3px rgba(0,0,0,.15)}.tox[dir=rtl] .tox-tbtn__icon-rtl svg{transform:rotateY(180deg)}.tox .tox-toolbar__group{align-items:center;display:flex;flex-wrap:wrap;margin:0 0;padding:0 4px 0 4px}.tox .tox-toolbar__group--pull-right{margin-left:auto}.tox .tox-toolbar--scrolling .tox-toolbar__group{flex-shrink:0;flex-wrap:nowrap}.tox:not([dir=rtl]) .tox-toolbar__group:not(:last-of-type){border-right:1px solid #000}.tox[dir=rtl] .tox-toolbar__group:not(:last-of-type){border-left:1px solid #000}.tox .tox-tooltip{display:inline-block;padding:8px;position:relative}.tox .tox-tooltip__body{background-color:#3d546f;border-radius:3px;box-shadow:0 2px 4px rgba(42,55,70,.3);color:rgba(255,255,255,.75);font-size:14px;font-style:normal;font-weight:400;padding:4px 8px;text-transform:none}.tox .tox-tooltip__arrow{position:absolute}.tox .tox-tooltip--down .tox-tooltip__arrow{border-left:8px solid transparent;border-right:8px solid transparent;border-top:8px solid #3d546f;bottom:0;left:50%;position:absolute;transform:translateX(-50%)}.tox .tox-tooltip--up .tox-tooltip__arrow{border-bottom:8px solid #3d546f;border-left:8px solid transparent;border-right:8px solid transparent;left:50%;position:absolute;top:0;transform:translateX(-50%)}.tox .tox-tooltip--right .tox-tooltip__arrow{border-bottom:8px solid transparent;border-left:8px solid #3d546f;border-top:8px solid transparent;position:absolute;right:0;top:50%;transform:translateY(-50%)}.tox .tox-tooltip--left .tox-tooltip__arrow{border-bottom:8px solid transparent;border-right:8px solid #3d546f;border-top:8px solid transparent;left:0;position:absolute;top:50%;transform:translateY(-50%)}.tox .tox-well{border:1px solid #000;border-radius:3px;padding:8px;width:100%}.tox .tox-well>:first-child{margin-top:0}.tox .tox-well>:last-child{margin-bottom:0}.tox .tox-well>:only-child{margin:0}.tox .tox-custom-editor{border:1px solid #000;border-radius:3px;display:flex;flex:1;position:relative}.tox .tox-dialog-loading::before{background-color:rgba(0,0,0,.5);content:"";height:100%;position:absolute;width:100%;z-index:1000}.tox .tox-tab{cursor:pointer}.tox .tox-dialog__content-js{display:flex;flex:1;-ms-flex-preferred-size:auto}.tox .tox-dialog__body-content .tox-collection{display:flex;flex:1;-ms-flex-preferred-size:auto}.tox .tox-image-tools-edit-panel{height:60px}.tox .tox-image-tools__sidebar{height:60px} diff --git a/frontend/public/tinymce-dataease-private/skins/ui/oxide-dark/skin.mobile.css b/frontend/public/tinymce-dataease-private/skins/ui/oxide-dark/skin.mobile.css new file mode 100644 index 0000000..efcd1bb --- /dev/null +++ b/frontend/public/tinymce-dataease-private/skins/ui/oxide-dark/skin.mobile.css @@ -0,0 +1,798 @@ +/** + * Copyright (c) Tiny Technologies, Inc. All rights reserved. + * Licensed under the LGPL or a commercial license. + * For LGPL see License.txt in the project root for license information. + * For commercial licenses see https://www.tiny.cloud/ + */ +/* RESET all the things! */ +.tinymce-mobile-outer-container { + all: initial; + display: block; +} + +.tinymce-mobile-outer-container * { + border: 0; + box-sizing: initial; + cursor: inherit; + float: none; + line-height: 1; + margin: 0; + outline: 0; + padding: 0; + -webkit-tap-highlight-color: transparent; + /* TBIO-3691, stop the gray flicker on touch. */ + text-shadow: none; + white-space: nowrap; +} + +.tinymce-mobile-icon-arrow-back::before { + content: "\e5cd"; +} + +.tinymce-mobile-icon-image::before { + content: "\e412"; +} + +.tinymce-mobile-icon-cancel-circle::before { + content: "\e5c9"; +} + +.tinymce-mobile-icon-full-dot::before { + content: "\e061"; +} + +.tinymce-mobile-icon-align-center::before { + content: "\e234"; +} + +.tinymce-mobile-icon-align-left::before { + content: "\e236"; +} + +.tinymce-mobile-icon-align-right::before { + content: "\e237"; +} + +.tinymce-mobile-icon-bold::before { + content: "\e238"; +} + +.tinymce-mobile-icon-italic::before { + content: "\e23f"; +} + +.tinymce-mobile-icon-unordered-list::before { + content: "\e241"; +} + +.tinymce-mobile-icon-ordered-list::before { + content: "\e242"; +} + +.tinymce-mobile-icon-font-size::before { + content: "\e245"; +} + +.tinymce-mobile-icon-underline::before { + content: "\e249"; +} + +.tinymce-mobile-icon-link::before { + content: "\e157"; +} + +.tinymce-mobile-icon-unlink::before { + content: "\eca2"; +} + +.tinymce-mobile-icon-color::before { + content: "\e891"; +} + +.tinymce-mobile-icon-previous::before { + content: "\e314"; +} + +.tinymce-mobile-icon-next::before { + content: "\e315"; +} + +.tinymce-mobile-icon-large-font::before, +.tinymce-mobile-icon-style-formats::before { + content: "\e264"; +} + +.tinymce-mobile-icon-undo::before { + content: "\e166"; +} + +.tinymce-mobile-icon-redo::before { + content: "\e15a"; +} + +.tinymce-mobile-icon-removeformat::before { + content: "\e239"; +} + +.tinymce-mobile-icon-small-font::before { + content: "\e906"; +} + +.tinymce-mobile-icon-readonly-back::before, +.tinymce-mobile-format-matches::after { + content: "\e5ca"; +} + +.tinymce-mobile-icon-small-heading::before { + content: "small"; +} + +.tinymce-mobile-icon-large-heading::before { + content: "large"; +} + +.tinymce-mobile-icon-small-heading::before, +.tinymce-mobile-icon-large-heading::before { + font-family: sans-serif; + font-size: 80%; +} + +.tinymce-mobile-mask-edit-icon::before { + content: "\e254"; +} + +.tinymce-mobile-icon-back::before { + content: "\e5c4"; +} + +.tinymce-mobile-icon-heading::before { + /* TODO: Translate */ + content: "Headings"; + font-family: sans-serif; + font-size: 80%; + font-weight: bold; +} + +.tinymce-mobile-icon-h1::before { + content: "H1"; + font-weight: bold; +} + +.tinymce-mobile-icon-h2::before { + content: "H2"; + font-weight: bold; +} + +.tinymce-mobile-icon-h3::before { + content: "H3"; + font-weight: bold; +} + +.tinymce-mobile-outer-container .tinymce-mobile-disabled-mask { + align-items: center; + display: flex; + justify-content: center; + background: rgba(51, 51, 51, 0.5); + height: 100%; + position: absolute; + top: 0; + width: 100%; +} + +.tinymce-mobile-outer-container .tinymce-mobile-disabled-mask .tinymce-mobile-content-container { + align-items: center; + border-radius: 50%; + display: flex; + flex-direction: column; + font-family: sans-serif; + font-size: 1em; + justify-content: space-between; +} + +.tinymce-mobile-outer-container .tinymce-mobile-disabled-mask .tinymce-mobile-content-container .mixin-menu-item { + align-items: center; + display: flex; + justify-content: center; + border-radius: 50%; + height: 2.1em; + width: 2.1em; +} + +.tinymce-mobile-outer-container .tinymce-mobile-disabled-mask .tinymce-mobile-content-container .tinymce-mobile-content-tap-section { + align-items: center; + display: flex; + justify-content: center; + flex-direction: column; + font-size: 1em; +} + +@media only screen and (min-device-width: 700px) { + .tinymce-mobile-outer-container .tinymce-mobile-disabled-mask .tinymce-mobile-content-container .tinymce-mobile-content-tap-section { + font-size: 1.2em; + } +} + +.tinymce-mobile-outer-container .tinymce-mobile-disabled-mask .tinymce-mobile-content-container .tinymce-mobile-content-tap-section .tinymce-mobile-mask-tap-icon { + align-items: center; + display: flex; + justify-content: center; + border-radius: 50%; + height: 2.1em; + width: 2.1em; + background-color: white; + color: #207ab7; +} + +.tinymce-mobile-outer-container .tinymce-mobile-disabled-mask .tinymce-mobile-content-container .tinymce-mobile-content-tap-section .tinymce-mobile-mask-tap-icon::before { + content: "\e900"; + font-family: 'tinymce-mobile', sans-serif; +} + +.tinymce-mobile-outer-container .tinymce-mobile-disabled-mask .tinymce-mobile-content-container .tinymce-mobile-content-tap-section:not(.tinymce-mobile-mask-tap-icon-selected) .tinymce-mobile-mask-tap-icon { + z-index: 2; +} + +.tinymce-mobile-android-container.tinymce-mobile-android-maximized { + background: #ffffff; + border: none; + bottom: 0; + display: flex; + flex-direction: column; + left: 0; + position: fixed; + right: 0; + top: 0; +} + +.tinymce-mobile-android-container:not(.tinymce-mobile-android-maximized) { + position: relative; +} + +.tinymce-mobile-android-container .tinymce-mobile-editor-socket { + display: flex; + flex-grow: 1; +} + +.tinymce-mobile-android-container .tinymce-mobile-editor-socket iframe { + display: flex !important; + flex-grow: 1; + height: auto !important; +} + +.tinymce-mobile-android-scroll-reload { + overflow: hidden; +} + +:not(.tinymce-mobile-readonly-mode) > .tinymce-mobile-android-selection-context-toolbar { + margin-top: 23px; +} + +.tinymce-mobile-toolstrip { + background: #fff; + display: flex; + flex: 0 0 auto; + z-index: 1; +} + +.tinymce-mobile-toolstrip .tinymce-mobile-toolbar { + align-items: center; + background-color: #fff; + border-bottom: 1px solid #cccccc; + display: flex; + flex: 1; + height: 2.5em; + width: 100%; + /* Make it no larger than the toolstrip, so that it needs to scroll */ +} + +.tinymce-mobile-toolstrip .tinymce-mobile-toolbar:not(.tinymce-mobile-context-toolbar) .tinymce-mobile-toolbar-group { + align-items: center; + display: flex; + height: 100%; + flex-shrink: 1; +} + +.tinymce-mobile-toolstrip .tinymce-mobile-toolbar:not(.tinymce-mobile-context-toolbar) .tinymce-mobile-toolbar-group > div { + align-items: center; + display: flex; + height: 100%; + flex: 1; +} + +.tinymce-mobile-toolstrip .tinymce-mobile-toolbar:not(.tinymce-mobile-context-toolbar) .tinymce-mobile-toolbar-group.tinymce-mobile-exit-container { + background: #f44336; +} + +.tinymce-mobile-toolstrip .tinymce-mobile-toolbar:not(.tinymce-mobile-context-toolbar) .tinymce-mobile-toolbar-group.tinymce-mobile-toolbar-scrollable-group { + flex-grow: 1; +} + +.tinymce-mobile-toolstrip .tinymce-mobile-toolbar:not(.tinymce-mobile-context-toolbar) .tinymce-mobile-toolbar-group .tinymce-mobile-toolbar-group-item { + padding-left: 0.5em; + padding-right: 0.5em; +} + +.tinymce-mobile-toolstrip .tinymce-mobile-toolbar:not(.tinymce-mobile-context-toolbar) .tinymce-mobile-toolbar-group .tinymce-mobile-toolbar-group-item.tinymce-mobile-toolbar-button { + align-items: center; + display: flex; + height: 80%; + margin-left: 2px; + margin-right: 2px; +} + +.tinymce-mobile-toolstrip .tinymce-mobile-toolbar:not(.tinymce-mobile-context-toolbar) .tinymce-mobile-toolbar-group .tinymce-mobile-toolbar-group-item.tinymce-mobile-toolbar-button.tinymce-mobile-toolbar-button-selected { + background: #c8cbcf; + color: #cccccc; +} + +.tinymce-mobile-toolstrip .tinymce-mobile-toolbar:not(.tinymce-mobile-context-toolbar) .tinymce-mobile-toolbar-group:first-of-type, +.tinymce-mobile-toolstrip .tinymce-mobile-toolbar:not(.tinymce-mobile-context-toolbar) .tinymce-mobile-toolbar-group:last-of-type { + background: #207ab7; + color: #eceff1; +} + +.tinymce-mobile-toolstrip .tinymce-mobile-toolbar.tinymce-mobile-context-toolbar { + /* Note, this file is imported inside .tinymce-mobile-context-toolbar, so that prefix is on everything here. */ +} + +.tinymce-mobile-toolstrip .tinymce-mobile-toolbar.tinymce-mobile-context-toolbar .tinymce-mobile-toolbar-group { + align-items: center; + display: flex; + height: 100%; + flex: 1; + padding-bottom: 0.4em; + padding-top: 0.4em; + /* Make any buttons appearing on the left and right display in the centre (e.g. color edges) */ + /* For widgets like the colour picker, use the whole height */ +} + +.tinymce-mobile-toolstrip .tinymce-mobile-toolbar.tinymce-mobile-context-toolbar .tinymce-mobile-toolbar-group .tinymce-mobile-serialised-dialog { + display: flex; + min-height: 1.5em; + overflow: hidden; + padding-left: 0; + padding-right: 0; + position: relative; + width: 100%; +} + +.tinymce-mobile-toolstrip .tinymce-mobile-toolbar.tinymce-mobile-context-toolbar .tinymce-mobile-toolbar-group .tinymce-mobile-serialised-dialog .tinymce-mobile-serialised-dialog-chain { + display: flex; + height: 100%; + transition: left cubic-bezier(0.4, 0, 1, 1) 0.15s; + width: 100%; +} + +.tinymce-mobile-toolstrip .tinymce-mobile-toolbar.tinymce-mobile-context-toolbar .tinymce-mobile-toolbar-group .tinymce-mobile-serialised-dialog .tinymce-mobile-serialised-dialog-chain .tinymce-mobile-serialised-dialog-screen { + display: flex; + flex: 0 0 auto; + justify-content: space-between; + width: 100%; +} + +.tinymce-mobile-toolstrip .tinymce-mobile-toolbar.tinymce-mobile-context-toolbar .tinymce-mobile-toolbar-group .tinymce-mobile-serialised-dialog .tinymce-mobile-serialised-dialog-chain .tinymce-mobile-serialised-dialog-screen input { + font-family: Sans-serif; +} + +.tinymce-mobile-toolstrip .tinymce-mobile-toolbar.tinymce-mobile-context-toolbar .tinymce-mobile-toolbar-group .tinymce-mobile-serialised-dialog .tinymce-mobile-serialised-dialog-chain .tinymce-mobile-serialised-dialog-screen .tinymce-mobile-input-container { + display: flex; + flex-grow: 1; + position: relative; +} + +.tinymce-mobile-toolstrip .tinymce-mobile-toolbar.tinymce-mobile-context-toolbar .tinymce-mobile-toolbar-group .tinymce-mobile-serialised-dialog .tinymce-mobile-serialised-dialog-chain .tinymce-mobile-serialised-dialog-screen .tinymce-mobile-input-container .tinymce-mobile-input-container-x { + -ms-grid-row-align: center; + align-self: center; + background: inherit; + border: none; + border-radius: 50%; + color: #888; + font-size: 0.6em; + font-weight: bold; + height: 100%; + padding-right: 2px; + position: absolute; + right: 0; +} + +.tinymce-mobile-toolstrip .tinymce-mobile-toolbar.tinymce-mobile-context-toolbar .tinymce-mobile-toolbar-group .tinymce-mobile-serialised-dialog .tinymce-mobile-serialised-dialog-chain .tinymce-mobile-serialised-dialog-screen .tinymce-mobile-input-container.tinymce-mobile-input-container-empty .tinymce-mobile-input-container-x { + display: none; +} + +.tinymce-mobile-toolstrip .tinymce-mobile-toolbar.tinymce-mobile-context-toolbar .tinymce-mobile-toolbar-group .tinymce-mobile-serialised-dialog .tinymce-mobile-serialised-dialog-chain .tinymce-mobile-serialised-dialog-screen .tinymce-mobile-icon-previous, +.tinymce-mobile-toolstrip .tinymce-mobile-toolbar.tinymce-mobile-context-toolbar .tinymce-mobile-toolbar-group .tinymce-mobile-serialised-dialog .tinymce-mobile-serialised-dialog-chain .tinymce-mobile-serialised-dialog-screen .tinymce-mobile-icon-next { + align-items: center; + display: flex; +} + +.tinymce-mobile-toolstrip .tinymce-mobile-toolbar.tinymce-mobile-context-toolbar .tinymce-mobile-toolbar-group .tinymce-mobile-serialised-dialog .tinymce-mobile-serialised-dialog-chain .tinymce-mobile-serialised-dialog-screen .tinymce-mobile-icon-previous::before, +.tinymce-mobile-toolstrip .tinymce-mobile-toolbar.tinymce-mobile-context-toolbar .tinymce-mobile-toolbar-group .tinymce-mobile-serialised-dialog .tinymce-mobile-serialised-dialog-chain .tinymce-mobile-serialised-dialog-screen .tinymce-mobile-icon-next::before { + align-items: center; + display: flex; + font-weight: bold; + height: 100%; + padding-left: 0.5em; + padding-right: 0.5em; +} + +.tinymce-mobile-toolstrip .tinymce-mobile-toolbar.tinymce-mobile-context-toolbar .tinymce-mobile-toolbar-group .tinymce-mobile-serialised-dialog .tinymce-mobile-serialised-dialog-chain .tinymce-mobile-serialised-dialog-screen .tinymce-mobile-icon-previous.tinymce-mobile-toolbar-navigation-disabled::before, +.tinymce-mobile-toolstrip .tinymce-mobile-toolbar.tinymce-mobile-context-toolbar .tinymce-mobile-toolbar-group .tinymce-mobile-serialised-dialog .tinymce-mobile-serialised-dialog-chain .tinymce-mobile-serialised-dialog-screen .tinymce-mobile-icon-next.tinymce-mobile-toolbar-navigation-disabled::before { + visibility: hidden; +} + +.tinymce-mobile-toolstrip .tinymce-mobile-toolbar.tinymce-mobile-context-toolbar .tinymce-mobile-toolbar-group .tinymce-mobile-dot-item { + color: #cccccc; + font-size: 10px; + line-height: 10px; + margin: 0 2px; + padding-top: 3px; +} + +.tinymce-mobile-toolstrip .tinymce-mobile-toolbar.tinymce-mobile-context-toolbar .tinymce-mobile-toolbar-group .tinymce-mobile-dot-item.tinymce-mobile-dot-active { + color: #c8cbcf; +} + +.tinymce-mobile-toolstrip .tinymce-mobile-toolbar.tinymce-mobile-context-toolbar .tinymce-mobile-toolbar-group .tinymce-mobile-icon-large-font::before, +.tinymce-mobile-toolstrip .tinymce-mobile-toolbar.tinymce-mobile-context-toolbar .tinymce-mobile-toolbar-group .tinymce-mobile-icon-large-heading::before { + margin-left: 0.5em; + margin-right: 0.9em; +} + +.tinymce-mobile-toolstrip .tinymce-mobile-toolbar.tinymce-mobile-context-toolbar .tinymce-mobile-toolbar-group .tinymce-mobile-icon-small-font::before, +.tinymce-mobile-toolstrip .tinymce-mobile-toolbar.tinymce-mobile-context-toolbar .tinymce-mobile-toolbar-group .tinymce-mobile-icon-small-heading::before { + margin-left: 0.9em; + margin-right: 0.5em; +} + +.tinymce-mobile-toolstrip .tinymce-mobile-toolbar.tinymce-mobile-context-toolbar .tinymce-mobile-toolbar-group .tinymce-mobile-slider { + display: flex; + flex: 1; + margin-left: 0; + margin-right: 0; + padding: 0.28em 0; + position: relative; +} + +.tinymce-mobile-toolstrip .tinymce-mobile-toolbar.tinymce-mobile-context-toolbar .tinymce-mobile-toolbar-group .tinymce-mobile-slider .tinymce-mobile-slider-size-container { + align-items: center; + display: flex; + flex-grow: 1; + height: 100%; +} + +.tinymce-mobile-toolstrip .tinymce-mobile-toolbar.tinymce-mobile-context-toolbar .tinymce-mobile-toolbar-group .tinymce-mobile-slider .tinymce-mobile-slider-size-container .tinymce-mobile-slider-size-line { + background: #cccccc; + display: flex; + flex: 1; + height: 0.2em; + margin-bottom: 0.3em; + margin-top: 0.3em; +} + +.tinymce-mobile-toolstrip .tinymce-mobile-toolbar.tinymce-mobile-context-toolbar .tinymce-mobile-toolbar-group .tinymce-mobile-slider.tinymce-mobile-hue-slider-container { + padding-left: 2em; + padding-right: 2em; +} + +.tinymce-mobile-toolstrip .tinymce-mobile-toolbar.tinymce-mobile-context-toolbar .tinymce-mobile-toolbar-group .tinymce-mobile-slider.tinymce-mobile-hue-slider-container .tinymce-mobile-slider-gradient-container { + align-items: center; + display: flex; + flex-grow: 1; + height: 100%; +} + +.tinymce-mobile-toolstrip .tinymce-mobile-toolbar.tinymce-mobile-context-toolbar .tinymce-mobile-toolbar-group .tinymce-mobile-slider.tinymce-mobile-hue-slider-container .tinymce-mobile-slider-gradient-container .tinymce-mobile-slider-gradient { + background: linear-gradient(to right, hsl(0, 100%, 50%) 0%, hsl(60, 100%, 50%) 17%, hsl(120, 100%, 50%) 33%, hsl(180, 100%, 50%) 50%, hsl(240, 100%, 50%) 67%, hsl(300, 100%, 50%) 83%, hsl(0, 100%, 50%) 100%); + display: flex; + flex: 1; + height: 0.2em; + margin-bottom: 0.3em; + margin-top: 0.3em; +} + +.tinymce-mobile-toolstrip .tinymce-mobile-toolbar.tinymce-mobile-context-toolbar .tinymce-mobile-toolbar-group .tinymce-mobile-slider.tinymce-mobile-hue-slider-container .tinymce-mobile-hue-slider-black { + /* Not part of theming */ + background: black; + height: 0.2em; + margin-bottom: 0.3em; + margin-top: 0.3em; + width: 1.2em; +} + +.tinymce-mobile-toolstrip .tinymce-mobile-toolbar.tinymce-mobile-context-toolbar .tinymce-mobile-toolbar-group .tinymce-mobile-slider.tinymce-mobile-hue-slider-container .tinymce-mobile-hue-slider-white { + /* Not part of theming */ + background: white; + height: 0.2em; + margin-bottom: 0.3em; + margin-top: 0.3em; + width: 1.2em; +} + +.tinymce-mobile-toolstrip .tinymce-mobile-toolbar.tinymce-mobile-context-toolbar .tinymce-mobile-toolbar-group .tinymce-mobile-slider .tinymce-mobile-slider-thumb { + /* vertically centering trick (margin: auto, top: 0, bottom: 0). On iOS and Safari, if you leave + * out these values, then it shows the thumb at the top of the spectrum. This is probably because it is + * absolutely positioned with only a left value, and not a top. Note, on Chrome it seems to be fine without + * this approach. + */ + align-items: center; + background-clip: padding-box; + background-color: #455a64; + border: 0.5em solid rgba(136, 136, 136, 0); + border-radius: 3em; + bottom: 0; + color: #fff; + display: flex; + height: 0.5em; + justify-content: center; + left: -10px; + margin: auto; + position: absolute; + top: 0; + transition: border 120ms cubic-bezier(0.39, 0.58, 0.57, 1); + width: 0.5em; +} + +.tinymce-mobile-toolstrip .tinymce-mobile-toolbar.tinymce-mobile-context-toolbar .tinymce-mobile-toolbar-group .tinymce-mobile-slider .tinymce-mobile-slider-thumb.tinymce-mobile-thumb-active { + border: 0.5em solid rgba(136, 136, 136, 0.39); +} + +.tinymce-mobile-toolstrip .tinymce-mobile-toolbar.tinymce-mobile-context-toolbar .tinymce-mobile-toolbar-group .tinymce-mobile-serializer-wrapper, +.tinymce-mobile-toolstrip .tinymce-mobile-toolbar.tinymce-mobile-context-toolbar .tinymce-mobile-toolbar-group > div { + align-items: center; + display: flex; + height: 100%; + flex: 1; +} + +.tinymce-mobile-toolstrip .tinymce-mobile-toolbar.tinymce-mobile-context-toolbar .tinymce-mobile-toolbar-group .tinymce-mobile-serializer-wrapper { + flex-direction: column; + justify-content: center; +} + +.tinymce-mobile-toolstrip .tinymce-mobile-toolbar.tinymce-mobile-context-toolbar .tinymce-mobile-toolbar-group .tinymce-mobile-toolbar-group-item { + align-items: center; + display: flex; +} + +.tinymce-mobile-toolstrip .tinymce-mobile-toolbar.tinymce-mobile-context-toolbar .tinymce-mobile-toolbar-group .tinymce-mobile-toolbar-group-item:not(.tinymce-mobile-serialised-dialog) { + height: 100%; +} + +.tinymce-mobile-toolstrip .tinymce-mobile-toolbar.tinymce-mobile-context-toolbar .tinymce-mobile-toolbar-group .tinymce-mobile-dot-container { + display: flex; +} + +.tinymce-mobile-toolstrip .tinymce-mobile-toolbar.tinymce-mobile-context-toolbar .tinymce-mobile-toolbar-group input { + background: #ffffff; + border: none; + border-radius: 0; + color: #455a64; + flex-grow: 1; + font-size: 0.85em; + padding-bottom: 0.1em; + padding-left: 5px; + padding-top: 0.1em; +} + +.tinymce-mobile-toolstrip .tinymce-mobile-toolbar.tinymce-mobile-context-toolbar .tinymce-mobile-toolbar-group input::-webkit-input-placeholder { + /* WebKit, Blink, Edge */ + color: #888; +} + +.tinymce-mobile-toolstrip .tinymce-mobile-toolbar.tinymce-mobile-context-toolbar .tinymce-mobile-toolbar-group input::placeholder { + /* WebKit, Blink, Edge */ + color: #888; +} + +/* dropup */ +.tinymce-mobile-dropup { + background: white; + display: flex; + overflow: hidden; + width: 100%; +} + +.tinymce-mobile-dropup.tinymce-mobile-dropup-shrinking { + transition: height 0.3s ease-out; +} + +.tinymce-mobile-dropup.tinymce-mobile-dropup-growing { + transition: height 0.3s ease-in; +} + +.tinymce-mobile-dropup.tinymce-mobile-dropup-closed { + flex-grow: 0; +} + +.tinymce-mobile-dropup.tinymce-mobile-dropup-open:not(.tinymce-mobile-dropup-growing) { + flex-grow: 1; +} + +/* TODO min-height for device size and orientation */ +.tinymce-mobile-ios-container .tinymce-mobile-dropup:not(.tinymce-mobile-dropup-closed) { + min-height: 200px; +} + +@media only screen and (orientation: landscape) { + .tinymce-mobile-dropup:not(.tinymce-mobile-dropup-closed) { + min-height: 200px; + } +} + +@media only screen and (min-device-width: 320px) and (max-device-width: 568px) and (orientation: landscape) { + .tinymce-mobile-ios-container .tinymce-mobile-dropup:not(.tinymce-mobile-dropup-closed) { + min-height: 150px; + } +} + +/* styles menu */ +.tinymce-mobile-styles-menu { + font-family: sans-serif; + outline: 4px solid black; + overflow: hidden; + position: relative; + width: 100%; +} + +.tinymce-mobile-styles-menu [role="menu"] { + display: flex; + flex-direction: column; + height: 100%; + position: absolute; + width: 100%; +} + +.tinymce-mobile-styles-menu [role="menu"].transitioning { + transition: transform 0.5s ease-in-out; +} + +.tinymce-mobile-styles-menu .tinymce-mobile-styles-item { + border-bottom: 1px solid #ddd; + color: #455a64; + cursor: pointer; + display: flex; + padding: 1em 1em; + position: relative; +} + +.tinymce-mobile-styles-menu .tinymce-mobile-styles-collapser .tinymce-mobile-styles-collapse-icon::before { + color: #455a64; + content: "\e314"; + font-family: 'tinymce-mobile', sans-serif; +} + +.tinymce-mobile-styles-menu .tinymce-mobile-styles-item.tinymce-mobile-styles-item-is-menu::after { + color: #455a64; + content: "\e315"; + font-family: 'tinymce-mobile', sans-serif; + padding-left: 1em; + padding-right: 1em; + position: absolute; + right: 0; +} + +.tinymce-mobile-styles-menu .tinymce-mobile-styles-item.tinymce-mobile-format-matches::after { + font-family: 'tinymce-mobile', sans-serif; + padding-left: 1em; + padding-right: 1em; + position: absolute; + right: 0; +} + +.tinymce-mobile-styles-menu .tinymce-mobile-styles-separator, +.tinymce-mobile-styles-menu .tinymce-mobile-styles-collapser { + align-items: center; + background: #fff; + border-top: #455a64; + color: #455a64; + display: flex; + min-height: 2.5em; + padding-left: 1em; + padding-right: 1em; +} + +.tinymce-mobile-styles-menu [data-transitioning-destination="before"][data-transitioning-state], +.tinymce-mobile-styles-menu [data-transitioning-state="before"] { + transform: translate(-100%); +} + +.tinymce-mobile-styles-menu [data-transitioning-destination="current"][data-transitioning-state], +.tinymce-mobile-styles-menu [data-transitioning-state="current"] { + transform: translate(0%); +} + +.tinymce-mobile-styles-menu [data-transitioning-destination="after"][data-transitioning-state], +.tinymce-mobile-styles-menu [data-transitioning-state="after"] { + transform: translate(100%); +} + +@font-face { + font-family: 'tinymce-mobile'; + font-style: normal; + font-weight: normal; + src: url('fonts/tinymce-mobile.woff?8x92w3') format('woff'); +} + +@media (min-device-width: 700px) { + .tinymce-mobile-outer-container, + .tinymce-mobile-outer-container input { + font-size: 25px; + } +} + +@media (max-device-width: 700px) { + .tinymce-mobile-outer-container, + .tinymce-mobile-outer-container input { + font-size: 18px; + } +} + +.tinymce-mobile-icon { + font-family: 'tinymce-mobile', sans-serif; +} + +.mixin-flex-and-centre { + align-items: center; + display: flex; + justify-content: center; +} + +.mixin-flex-bar { + align-items: center; + display: flex; + height: 100%; +} + +.tinymce-mobile-outer-container .tinymce-mobile-editor-socket iframe { + background-color: #fff; + width: 100%; +} + +.tinymce-mobile-editor-socket .tinymce-mobile-mask-edit-icon { + /* Note, on the iPod touch in landscape, this isn't visible when the navbar appears */ + background-color: #207ab7; + border-radius: 50%; + bottom: 1em; + color: white; + font-size: 1em; + height: 2.1em; + position: fixed; + right: 2em; + width: 2.1em; + align-items: center; + display: flex; + justify-content: center; +} + +@media only screen and (min-device-width: 700px) { + .tinymce-mobile-editor-socket .tinymce-mobile-mask-edit-icon { + font-size: 1.2em; + } +} + +.tinymce-mobile-outer-container:not(.tinymce-mobile-fullscreen-maximized) .tinymce-mobile-editor-socket { + height: 300px; + overflow: hidden; +} + +.tinymce-mobile-outer-container:not(.tinymce-mobile-fullscreen-maximized) .tinymce-mobile-editor-socket iframe { + height: 100%; +} + +.tinymce-mobile-outer-container:not(.tinymce-mobile-fullscreen-maximized) .tinymce-mobile-toolstrip { + display: none; +} + +/* + Note, that if you don't include this (::-webkit-file-upload-button), the toolbar width gets + increased and the whole body becomes scrollable. It's important! + */ +input[type="file"]::-webkit-file-upload-button { + display: none; +} + +@media only screen and (min-device-width: 320px) and (max-device-width: 568px) and (orientation: landscape) { + .tinymce-mobile-ios-container .tinymce-mobile-editor-socket .tinymce-mobile-mask-edit-icon { + bottom: 50%; + } +} diff --git a/frontend/public/tinymce-dataease-private/skins/ui/oxide-dark/skin.mobile.min.css b/frontend/public/tinymce-dataease-private/skins/ui/oxide-dark/skin.mobile.min.css new file mode 100644 index 0000000..3a45cac --- /dev/null +++ b/frontend/public/tinymce-dataease-private/skins/ui/oxide-dark/skin.mobile.min.css @@ -0,0 +1,7 @@ +/** + * Copyright (c) Tiny Technologies, Inc. All rights reserved. + * Licensed under the LGPL or a commercial license. + * For LGPL see License.txt in the project root for license information. + * For commercial licenses see https://www.tiny.cloud/ + */ +.tinymce-mobile-outer-container{all:initial;display:block}.tinymce-mobile-outer-container *{border:0;box-sizing:initial;cursor:inherit;float:none;line-height:1;margin:0;outline:0;padding:0;-webkit-tap-highlight-color:transparent;text-shadow:none;white-space:nowrap}.tinymce-mobile-icon-arrow-back::before{content:"\e5cd"}.tinymce-mobile-icon-image::before{content:"\e412"}.tinymce-mobile-icon-cancel-circle::before{content:"\e5c9"}.tinymce-mobile-icon-full-dot::before{content:"\e061"}.tinymce-mobile-icon-align-center::before{content:"\e234"}.tinymce-mobile-icon-align-left::before{content:"\e236"}.tinymce-mobile-icon-align-right::before{content:"\e237"}.tinymce-mobile-icon-bold::before{content:"\e238"}.tinymce-mobile-icon-italic::before{content:"\e23f"}.tinymce-mobile-icon-unordered-list::before{content:"\e241"}.tinymce-mobile-icon-ordered-list::before{content:"\e242"}.tinymce-mobile-icon-font-size::before{content:"\e245"}.tinymce-mobile-icon-underline::before{content:"\e249"}.tinymce-mobile-icon-link::before{content:"\e157"}.tinymce-mobile-icon-unlink::before{content:"\eca2"}.tinymce-mobile-icon-color::before{content:"\e891"}.tinymce-mobile-icon-previous::before{content:"\e314"}.tinymce-mobile-icon-next::before{content:"\e315"}.tinymce-mobile-icon-large-font::before,.tinymce-mobile-icon-style-formats::before{content:"\e264"}.tinymce-mobile-icon-undo::before{content:"\e166"}.tinymce-mobile-icon-redo::before{content:"\e15a"}.tinymce-mobile-icon-removeformat::before{content:"\e239"}.tinymce-mobile-icon-small-font::before{content:"\e906"}.tinymce-mobile-format-matches::after,.tinymce-mobile-icon-readonly-back::before{content:"\e5ca"}.tinymce-mobile-icon-small-heading::before{content:"small"}.tinymce-mobile-icon-large-heading::before{content:"large"}.tinymce-mobile-icon-large-heading::before,.tinymce-mobile-icon-small-heading::before{font-family:sans-serif;font-size:80%}.tinymce-mobile-mask-edit-icon::before{content:"\e254"}.tinymce-mobile-icon-back::before{content:"\e5c4"}.tinymce-mobile-icon-heading::before{content:"Headings";font-family:sans-serif;font-size:80%;font-weight:700}.tinymce-mobile-icon-h1::before{content:"H1";font-weight:700}.tinymce-mobile-icon-h2::before{content:"H2";font-weight:700}.tinymce-mobile-icon-h3::before{content:"H3";font-weight:700}.tinymce-mobile-outer-container .tinymce-mobile-disabled-mask{align-items:center;display:flex;justify-content:center;background:rgba(51,51,51,.5);height:100%;position:absolute;top:0;width:100%}.tinymce-mobile-outer-container .tinymce-mobile-disabled-mask .tinymce-mobile-content-container{align-items:center;border-radius:50%;display:flex;flex-direction:column;font-family:sans-serif;font-size:1em;justify-content:space-between}.tinymce-mobile-outer-container .tinymce-mobile-disabled-mask .tinymce-mobile-content-container .mixin-menu-item{align-items:center;display:flex;justify-content:center;border-radius:50%;height:2.1em;width:2.1em}.tinymce-mobile-outer-container .tinymce-mobile-disabled-mask .tinymce-mobile-content-container .tinymce-mobile-content-tap-section{align-items:center;display:flex;justify-content:center;flex-direction:column;font-size:1em}@media only screen and (min-device-width:700px){.tinymce-mobile-outer-container .tinymce-mobile-disabled-mask .tinymce-mobile-content-container .tinymce-mobile-content-tap-section{font-size:1.2em}}.tinymce-mobile-outer-container .tinymce-mobile-disabled-mask .tinymce-mobile-content-container .tinymce-mobile-content-tap-section .tinymce-mobile-mask-tap-icon{align-items:center;display:flex;justify-content:center;border-radius:50%;height:2.1em;width:2.1em;background-color:#fff;color:#207ab7}.tinymce-mobile-outer-container .tinymce-mobile-disabled-mask .tinymce-mobile-content-container .tinymce-mobile-content-tap-section .tinymce-mobile-mask-tap-icon::before{content:"\e900";font-family:tinymce-mobile,sans-serif}.tinymce-mobile-outer-container .tinymce-mobile-disabled-mask .tinymce-mobile-content-container .tinymce-mobile-content-tap-section:not(.tinymce-mobile-mask-tap-icon-selected) .tinymce-mobile-mask-tap-icon{z-index:2}.tinymce-mobile-android-container.tinymce-mobile-android-maximized{background:#fff;border:none;bottom:0;display:flex;flex-direction:column;left:0;position:fixed;right:0;top:0}.tinymce-mobile-android-container:not(.tinymce-mobile-android-maximized){position:relative}.tinymce-mobile-android-container .tinymce-mobile-editor-socket{display:flex;flex-grow:1}.tinymce-mobile-android-container .tinymce-mobile-editor-socket iframe{display:flex!important;flex-grow:1;height:auto!important}.tinymce-mobile-android-scroll-reload{overflow:hidden}:not(.tinymce-mobile-readonly-mode)>.tinymce-mobile-android-selection-context-toolbar{margin-top:23px}.tinymce-mobile-toolstrip{background:#fff;display:flex;flex:0 0 auto;z-index:1}.tinymce-mobile-toolstrip .tinymce-mobile-toolbar{align-items:center;background-color:#fff;border-bottom:1px solid #ccc;display:flex;flex:1;height:2.5em;width:100%}.tinymce-mobile-toolstrip .tinymce-mobile-toolbar:not(.tinymce-mobile-context-toolbar) .tinymce-mobile-toolbar-group{align-items:center;display:flex;height:100%;flex-shrink:1}.tinymce-mobile-toolstrip .tinymce-mobile-toolbar:not(.tinymce-mobile-context-toolbar) .tinymce-mobile-toolbar-group>div{align-items:center;display:flex;height:100%;flex:1}.tinymce-mobile-toolstrip .tinymce-mobile-toolbar:not(.tinymce-mobile-context-toolbar) .tinymce-mobile-toolbar-group.tinymce-mobile-exit-container{background:#f44336}.tinymce-mobile-toolstrip .tinymce-mobile-toolbar:not(.tinymce-mobile-context-toolbar) .tinymce-mobile-toolbar-group.tinymce-mobile-toolbar-scrollable-group{flex-grow:1}.tinymce-mobile-toolstrip .tinymce-mobile-toolbar:not(.tinymce-mobile-context-toolbar) .tinymce-mobile-toolbar-group .tinymce-mobile-toolbar-group-item{padding-left:.5em;padding-right:.5em}.tinymce-mobile-toolstrip .tinymce-mobile-toolbar:not(.tinymce-mobile-context-toolbar) .tinymce-mobile-toolbar-group .tinymce-mobile-toolbar-group-item.tinymce-mobile-toolbar-button{align-items:center;display:flex;height:80%;margin-left:2px;margin-right:2px}.tinymce-mobile-toolstrip .tinymce-mobile-toolbar:not(.tinymce-mobile-context-toolbar) .tinymce-mobile-toolbar-group .tinymce-mobile-toolbar-group-item.tinymce-mobile-toolbar-button.tinymce-mobile-toolbar-button-selected{background:#c8cbcf;color:#ccc}.tinymce-mobile-toolstrip .tinymce-mobile-toolbar:not(.tinymce-mobile-context-toolbar) .tinymce-mobile-toolbar-group:first-of-type,.tinymce-mobile-toolstrip .tinymce-mobile-toolbar:not(.tinymce-mobile-context-toolbar) .tinymce-mobile-toolbar-group:last-of-type{background:#207ab7;color:#eceff1}.tinymce-mobile-toolstrip .tinymce-mobile-toolbar.tinymce-mobile-context-toolbar .tinymce-mobile-toolbar-group{align-items:center;display:flex;height:100%;flex:1;padding-bottom:.4em;padding-top:.4em}.tinymce-mobile-toolstrip .tinymce-mobile-toolbar.tinymce-mobile-context-toolbar .tinymce-mobile-toolbar-group .tinymce-mobile-serialised-dialog{display:flex;min-height:1.5em;overflow:hidden;padding-left:0;padding-right:0;position:relative;width:100%}.tinymce-mobile-toolstrip .tinymce-mobile-toolbar.tinymce-mobile-context-toolbar .tinymce-mobile-toolbar-group .tinymce-mobile-serialised-dialog .tinymce-mobile-serialised-dialog-chain{display:flex;height:100%;transition:left cubic-bezier(.4,0,1,1) .15s;width:100%}.tinymce-mobile-toolstrip .tinymce-mobile-toolbar.tinymce-mobile-context-toolbar .tinymce-mobile-toolbar-group .tinymce-mobile-serialised-dialog .tinymce-mobile-serialised-dialog-chain .tinymce-mobile-serialised-dialog-screen{display:flex;flex:0 0 auto;justify-content:space-between;width:100%}.tinymce-mobile-toolstrip .tinymce-mobile-toolbar.tinymce-mobile-context-toolbar .tinymce-mobile-toolbar-group .tinymce-mobile-serialised-dialog .tinymce-mobile-serialised-dialog-chain .tinymce-mobile-serialised-dialog-screen input{font-family:Sans-serif}.tinymce-mobile-toolstrip .tinymce-mobile-toolbar.tinymce-mobile-context-toolbar .tinymce-mobile-toolbar-group .tinymce-mobile-serialised-dialog .tinymce-mobile-serialised-dialog-chain .tinymce-mobile-serialised-dialog-screen .tinymce-mobile-input-container{display:flex;flex-grow:1;position:relative}.tinymce-mobile-toolstrip .tinymce-mobile-toolbar.tinymce-mobile-context-toolbar .tinymce-mobile-toolbar-group .tinymce-mobile-serialised-dialog .tinymce-mobile-serialised-dialog-chain .tinymce-mobile-serialised-dialog-screen .tinymce-mobile-input-container .tinymce-mobile-input-container-x{-ms-grid-row-align:center;align-self:center;background:inherit;border:none;border-radius:50%;color:#888;font-size:.6em;font-weight:700;height:100%;padding-right:2px;position:absolute;right:0}.tinymce-mobile-toolstrip .tinymce-mobile-toolbar.tinymce-mobile-context-toolbar .tinymce-mobile-toolbar-group .tinymce-mobile-serialised-dialog .tinymce-mobile-serialised-dialog-chain .tinymce-mobile-serialised-dialog-screen .tinymce-mobile-input-container.tinymce-mobile-input-container-empty .tinymce-mobile-input-container-x{display:none}.tinymce-mobile-toolstrip .tinymce-mobile-toolbar.tinymce-mobile-context-toolbar .tinymce-mobile-toolbar-group .tinymce-mobile-serialised-dialog .tinymce-mobile-serialised-dialog-chain .tinymce-mobile-serialised-dialog-screen .tinymce-mobile-icon-next,.tinymce-mobile-toolstrip .tinymce-mobile-toolbar.tinymce-mobile-context-toolbar .tinymce-mobile-toolbar-group .tinymce-mobile-serialised-dialog .tinymce-mobile-serialised-dialog-chain .tinymce-mobile-serialised-dialog-screen .tinymce-mobile-icon-previous{align-items:center;display:flex}.tinymce-mobile-toolstrip .tinymce-mobile-toolbar.tinymce-mobile-context-toolbar .tinymce-mobile-toolbar-group .tinymce-mobile-serialised-dialog .tinymce-mobile-serialised-dialog-chain .tinymce-mobile-serialised-dialog-screen .tinymce-mobile-icon-next::before,.tinymce-mobile-toolstrip .tinymce-mobile-toolbar.tinymce-mobile-context-toolbar .tinymce-mobile-toolbar-group .tinymce-mobile-serialised-dialog .tinymce-mobile-serialised-dialog-chain .tinymce-mobile-serialised-dialog-screen .tinymce-mobile-icon-previous::before{align-items:center;display:flex;font-weight:700;height:100%;padding-left:.5em;padding-right:.5em}.tinymce-mobile-toolstrip .tinymce-mobile-toolbar.tinymce-mobile-context-toolbar .tinymce-mobile-toolbar-group .tinymce-mobile-serialised-dialog .tinymce-mobile-serialised-dialog-chain .tinymce-mobile-serialised-dialog-screen .tinymce-mobile-icon-next.tinymce-mobile-toolbar-navigation-disabled::before,.tinymce-mobile-toolstrip .tinymce-mobile-toolbar.tinymce-mobile-context-toolbar .tinymce-mobile-toolbar-group .tinymce-mobile-serialised-dialog .tinymce-mobile-serialised-dialog-chain .tinymce-mobile-serialised-dialog-screen .tinymce-mobile-icon-previous.tinymce-mobile-toolbar-navigation-disabled::before{visibility:hidden}.tinymce-mobile-toolstrip .tinymce-mobile-toolbar.tinymce-mobile-context-toolbar .tinymce-mobile-toolbar-group .tinymce-mobile-dot-item{color:#ccc;font-size:10px;line-height:10px;margin:0 2px;padding-top:3px}.tinymce-mobile-toolstrip .tinymce-mobile-toolbar.tinymce-mobile-context-toolbar .tinymce-mobile-toolbar-group .tinymce-mobile-dot-item.tinymce-mobile-dot-active{color:#c8cbcf}.tinymce-mobile-toolstrip .tinymce-mobile-toolbar.tinymce-mobile-context-toolbar .tinymce-mobile-toolbar-group .tinymce-mobile-icon-large-font::before,.tinymce-mobile-toolstrip .tinymce-mobile-toolbar.tinymce-mobile-context-toolbar .tinymce-mobile-toolbar-group .tinymce-mobile-icon-large-heading::before{margin-left:.5em;margin-right:.9em}.tinymce-mobile-toolstrip .tinymce-mobile-toolbar.tinymce-mobile-context-toolbar .tinymce-mobile-toolbar-group .tinymce-mobile-icon-small-font::before,.tinymce-mobile-toolstrip .tinymce-mobile-toolbar.tinymce-mobile-context-toolbar .tinymce-mobile-toolbar-group .tinymce-mobile-icon-small-heading::before{margin-left:.9em;margin-right:.5em}.tinymce-mobile-toolstrip .tinymce-mobile-toolbar.tinymce-mobile-context-toolbar .tinymce-mobile-toolbar-group .tinymce-mobile-slider{display:flex;flex:1;margin-left:0;margin-right:0;padding:.28em 0;position:relative}.tinymce-mobile-toolstrip .tinymce-mobile-toolbar.tinymce-mobile-context-toolbar .tinymce-mobile-toolbar-group .tinymce-mobile-slider .tinymce-mobile-slider-size-container{align-items:center;display:flex;flex-grow:1;height:100%}.tinymce-mobile-toolstrip .tinymce-mobile-toolbar.tinymce-mobile-context-toolbar .tinymce-mobile-toolbar-group .tinymce-mobile-slider .tinymce-mobile-slider-size-container .tinymce-mobile-slider-size-line{background:#ccc;display:flex;flex:1;height:.2em;margin-bottom:.3em;margin-top:.3em}.tinymce-mobile-toolstrip .tinymce-mobile-toolbar.tinymce-mobile-context-toolbar .tinymce-mobile-toolbar-group .tinymce-mobile-slider.tinymce-mobile-hue-slider-container{padding-left:2em;padding-right:2em}.tinymce-mobile-toolstrip .tinymce-mobile-toolbar.tinymce-mobile-context-toolbar .tinymce-mobile-toolbar-group .tinymce-mobile-slider.tinymce-mobile-hue-slider-container .tinymce-mobile-slider-gradient-container{align-items:center;display:flex;flex-grow:1;height:100%}.tinymce-mobile-toolstrip .tinymce-mobile-toolbar.tinymce-mobile-context-toolbar .tinymce-mobile-toolbar-group .tinymce-mobile-slider.tinymce-mobile-hue-slider-container .tinymce-mobile-slider-gradient-container .tinymce-mobile-slider-gradient{background:linear-gradient(to right,red 0,#feff00 17%,#0f0 33%,#00feff 50%,#00f 67%,#ff00fe 83%,red 100%);display:flex;flex:1;height:.2em;margin-bottom:.3em;margin-top:.3em}.tinymce-mobile-toolstrip .tinymce-mobile-toolbar.tinymce-mobile-context-toolbar .tinymce-mobile-toolbar-group .tinymce-mobile-slider.tinymce-mobile-hue-slider-container .tinymce-mobile-hue-slider-black{background:#000;height:.2em;margin-bottom:.3em;margin-top:.3em;width:1.2em}.tinymce-mobile-toolstrip .tinymce-mobile-toolbar.tinymce-mobile-context-toolbar .tinymce-mobile-toolbar-group .tinymce-mobile-slider.tinymce-mobile-hue-slider-container .tinymce-mobile-hue-slider-white{background:#fff;height:.2em;margin-bottom:.3em;margin-top:.3em;width:1.2em}.tinymce-mobile-toolstrip .tinymce-mobile-toolbar.tinymce-mobile-context-toolbar .tinymce-mobile-toolbar-group .tinymce-mobile-slider .tinymce-mobile-slider-thumb{align-items:center;background-clip:padding-box;background-color:#455a64;border:.5em solid rgba(136,136,136,0);border-radius:3em;bottom:0;color:#fff;display:flex;height:.5em;justify-content:center;left:-10px;margin:auto;position:absolute;top:0;transition:border 120ms cubic-bezier(.39,.58,.57,1);width:.5em}.tinymce-mobile-toolstrip .tinymce-mobile-toolbar.tinymce-mobile-context-toolbar .tinymce-mobile-toolbar-group .tinymce-mobile-slider .tinymce-mobile-slider-thumb.tinymce-mobile-thumb-active{border:.5em solid rgba(136,136,136,.39)}.tinymce-mobile-toolstrip .tinymce-mobile-toolbar.tinymce-mobile-context-toolbar .tinymce-mobile-toolbar-group .tinymce-mobile-serializer-wrapper,.tinymce-mobile-toolstrip .tinymce-mobile-toolbar.tinymce-mobile-context-toolbar .tinymce-mobile-toolbar-group>div{align-items:center;display:flex;height:100%;flex:1}.tinymce-mobile-toolstrip .tinymce-mobile-toolbar.tinymce-mobile-context-toolbar .tinymce-mobile-toolbar-group .tinymce-mobile-serializer-wrapper{flex-direction:column;justify-content:center}.tinymce-mobile-toolstrip .tinymce-mobile-toolbar.tinymce-mobile-context-toolbar .tinymce-mobile-toolbar-group .tinymce-mobile-toolbar-group-item{align-items:center;display:flex}.tinymce-mobile-toolstrip .tinymce-mobile-toolbar.tinymce-mobile-context-toolbar .tinymce-mobile-toolbar-group .tinymce-mobile-toolbar-group-item:not(.tinymce-mobile-serialised-dialog){height:100%}.tinymce-mobile-toolstrip .tinymce-mobile-toolbar.tinymce-mobile-context-toolbar .tinymce-mobile-toolbar-group .tinymce-mobile-dot-container{display:flex}.tinymce-mobile-toolstrip .tinymce-mobile-toolbar.tinymce-mobile-context-toolbar .tinymce-mobile-toolbar-group input{background:#fff;border:none;border-radius:0;color:#455a64;flex-grow:1;font-size:.85em;padding-bottom:.1em;padding-left:5px;padding-top:.1em}.tinymce-mobile-toolstrip .tinymce-mobile-toolbar.tinymce-mobile-context-toolbar .tinymce-mobile-toolbar-group input::-webkit-input-placeholder{color:#888}.tinymce-mobile-toolstrip .tinymce-mobile-toolbar.tinymce-mobile-context-toolbar .tinymce-mobile-toolbar-group input::placeholder{color:#888}.tinymce-mobile-dropup{background:#fff;display:flex;overflow:hidden;width:100%}.tinymce-mobile-dropup.tinymce-mobile-dropup-shrinking{transition:height .3s ease-out}.tinymce-mobile-dropup.tinymce-mobile-dropup-growing{transition:height .3s ease-in}.tinymce-mobile-dropup.tinymce-mobile-dropup-closed{flex-grow:0}.tinymce-mobile-dropup.tinymce-mobile-dropup-open:not(.tinymce-mobile-dropup-growing){flex-grow:1}.tinymce-mobile-ios-container .tinymce-mobile-dropup:not(.tinymce-mobile-dropup-closed){min-height:200px}@media only screen and (orientation:landscape){.tinymce-mobile-dropup:not(.tinymce-mobile-dropup-closed){min-height:200px}}@media only screen and (min-device-width :320px) and (max-device-width :568px) and (orientation :landscape){.tinymce-mobile-ios-container .tinymce-mobile-dropup:not(.tinymce-mobile-dropup-closed){min-height:150px}}.tinymce-mobile-styles-menu{font-family:sans-serif;outline:4px solid #000;overflow:hidden;position:relative;width:100%}.tinymce-mobile-styles-menu [role=menu]{display:flex;flex-direction:column;height:100%;position:absolute;width:100%}.tinymce-mobile-styles-menu [role=menu].transitioning{transition:transform .5s ease-in-out}.tinymce-mobile-styles-menu .tinymce-mobile-styles-item{border-bottom:1px solid #ddd;color:#455a64;cursor:pointer;display:flex;padding:1em 1em;position:relative}.tinymce-mobile-styles-menu .tinymce-mobile-styles-collapser .tinymce-mobile-styles-collapse-icon::before{color:#455a64;content:"\e314";font-family:tinymce-mobile,sans-serif}.tinymce-mobile-styles-menu .tinymce-mobile-styles-item.tinymce-mobile-styles-item-is-menu::after{color:#455a64;content:"\e315";font-family:tinymce-mobile,sans-serif;padding-left:1em;padding-right:1em;position:absolute;right:0}.tinymce-mobile-styles-menu .tinymce-mobile-styles-item.tinymce-mobile-format-matches::after{font-family:tinymce-mobile,sans-serif;padding-left:1em;padding-right:1em;position:absolute;right:0}.tinymce-mobile-styles-menu .tinymce-mobile-styles-collapser,.tinymce-mobile-styles-menu .tinymce-mobile-styles-separator{align-items:center;background:#fff;border-top:#455a64;color:#455a64;display:flex;min-height:2.5em;padding-left:1em;padding-right:1em}.tinymce-mobile-styles-menu [data-transitioning-destination=before][data-transitioning-state],.tinymce-mobile-styles-menu [data-transitioning-state=before]{transform:translate(-100%)}.tinymce-mobile-styles-menu [data-transitioning-destination=current][data-transitioning-state],.tinymce-mobile-styles-menu [data-transitioning-state=current]{transform:translate(0)}.tinymce-mobile-styles-menu [data-transitioning-destination=after][data-transitioning-state],.tinymce-mobile-styles-menu [data-transitioning-state=after]{transform:translate(100%)}@font-face{font-family:tinymce-mobile;font-style:normal;font-weight:400;src:url(fonts/tinymce-mobile.woff?8x92w3) format('woff')}@media (min-device-width:700px){.tinymce-mobile-outer-container,.tinymce-mobile-outer-container input{font-size:25px}}@media (max-device-width:700px){.tinymce-mobile-outer-container,.tinymce-mobile-outer-container input{font-size:18px}}.tinymce-mobile-icon{font-family:tinymce-mobile,sans-serif}.mixin-flex-and-centre{align-items:center;display:flex;justify-content:center}.mixin-flex-bar{align-items:center;display:flex;height:100%}.tinymce-mobile-outer-container .tinymce-mobile-editor-socket iframe{background-color:#fff;width:100%}.tinymce-mobile-editor-socket .tinymce-mobile-mask-edit-icon{background-color:#207ab7;border-radius:50%;bottom:1em;color:#fff;font-size:1em;height:2.1em;position:fixed;right:2em;width:2.1em;align-items:center;display:flex;justify-content:center}@media only screen and (min-device-width:700px){.tinymce-mobile-editor-socket .tinymce-mobile-mask-edit-icon{font-size:1.2em}}.tinymce-mobile-outer-container:not(.tinymce-mobile-fullscreen-maximized) .tinymce-mobile-editor-socket{height:300px;overflow:hidden}.tinymce-mobile-outer-container:not(.tinymce-mobile-fullscreen-maximized) .tinymce-mobile-editor-socket iframe{height:100%}.tinymce-mobile-outer-container:not(.tinymce-mobile-fullscreen-maximized) .tinymce-mobile-toolstrip{display:none}input[type=file]::-webkit-file-upload-button{display:none}@media only screen and (min-device-width :320px) and (max-device-width :568px) and (orientation :landscape){.tinymce-mobile-ios-container .tinymce-mobile-editor-socket .tinymce-mobile-mask-edit-icon{bottom:50%}} diff --git a/frontend/public/tinymce-dataease-private/skins/ui/oxide-dark/skin.shadowdom.css b/frontend/public/tinymce-dataease-private/skins/ui/oxide-dark/skin.shadowdom.css new file mode 100644 index 0000000..16f4d30 --- /dev/null +++ b/frontend/public/tinymce-dataease-private/skins/ui/oxide-dark/skin.shadowdom.css @@ -0,0 +1,42 @@ +/** + * Copyright (c) Tiny Technologies, Inc. All rights reserved. + * Licensed under the LGPL or a commercial license. + * For LGPL see License.txt in the project root for license information. + * For commercial licenses see https://www.tiny.cloud/ + */ +body.tox-dialog__disable-scroll { + overflow: hidden; +} + +.tox-fullscreen { + border: 0; + height: 100%; + left: 0; + margin: 0; + overflow: hidden; + -ms-scroll-chaining: none; + overscroll-behavior: none; + padding: 0; + position: fixed; + top: 0; + touch-action: pinch-zoom; + width: 100%; +} + +.tox.tox-tinymce.tox-fullscreen .tox-statusbar__resize-handle { + display: none; +} + +.tox.tox-tinymce.tox-fullscreen { + background-color: transparent; + z-index: 1200; +} + +.tox-shadowhost.tox-fullscreen { + z-index: 1200; +} + +.tox-fullscreen .tox.tox-tinymce-aux, +.tox-fullscreen ~ .tox.tox-tinymce-aux { + z-index: 1201; +} diff --git a/frontend/public/tinymce-dataease-private/skins/ui/oxide-dark/skin.shadowdom.min.css b/frontend/public/tinymce-dataease-private/skins/ui/oxide-dark/skin.shadowdom.min.css new file mode 100644 index 0000000..9ba6e02 --- /dev/null +++ b/frontend/public/tinymce-dataease-private/skins/ui/oxide-dark/skin.shadowdom.min.css @@ -0,0 +1,7 @@ +/** + * Copyright (c) Tiny Technologies, Inc. All rights reserved. + * Licensed under the LGPL or a commercial license. + * For LGPL see License.txt in the project root for license information. + * For commercial licenses see https://www.tiny.cloud/ + */ +body.tox-dialog__disable-scroll{overflow:hidden}.tox-fullscreen{border:0;height:100%;left:0;margin:0;overflow:hidden;-ms-scroll-chaining:none;overscroll-behavior:none;padding:0;position:fixed;top:0;touch-action:pinch-zoom;width:100%}.tox.tox-tinymce.tox-fullscreen .tox-statusbar__resize-handle{display:none}.tox.tox-tinymce.tox-fullscreen{background-color:transparent;z-index:1200}.tox-shadowhost.tox-fullscreen{z-index:1200}.tox-fullscreen .tox.tox-tinymce-aux,.tox-fullscreen~.tox.tox-tinymce-aux{z-index:1201} diff --git a/frontend/public/tinymce-dataease-private/skins/ui/oxide/content.css b/frontend/public/tinymce-dataease-private/skins/ui/oxide/content.css new file mode 100644 index 0000000..0f1e529 --- /dev/null +++ b/frontend/public/tinymce-dataease-private/skins/ui/oxide/content.css @@ -0,0 +1,869 @@ +/** + * Copyright (c) Tiny Technologies, Inc. All rights reserved. + * Licensed under the LGPL or a commercial license. + * For LGPL see License.txt in the project root for license information. + * For commercial licenses see https://www.tiny.cloud/ + */ +.mce-content-body .mce-item-anchor { + background: transparent url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D'8'%20height%3D'12'%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%3E%3Cpath%20d%3D'M0%200L8%200%208%2012%204.09117821%209%200%2012z'%2F%3E%3C%2Fsvg%3E%0A") no-repeat center; + cursor: default; + display: inline-block; + height: 12px !important; + padding: 0 2px; + -webkit-user-modify: read-only; + -moz-user-modify: read-only; + -webkit-user-select: all; + -moz-user-select: all; + -ms-user-select: all; + user-select: all; + width: 8px !important; +} + +.mce-content-body .mce-item-anchor[data-mce-selected] { + outline-offset: 1px; +} + +.tox-comments-visible .tox-comment { + background-color: #fff0b7; +} + +.tox-comments-visible .tox-comment--active { + background-color: #ffe168; +} + +.tox-checklist > li:not(.tox-checklist--hidden) { + list-style: none; + margin: 0.25em 0; +} + +.tox-checklist > li:not(.tox-checklist--hidden)::before { + content: url("data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2216%22%20height%3D%2216%22%20viewBox%3D%220%200%2016%2016%22%3E%3Cg%20id%3D%22checklist-unchecked%22%20fill%3D%22none%22%20fill-rule%3D%22evenodd%22%3E%3Crect%20id%3D%22Rectangle%22%20width%3D%2215%22%20height%3D%2215%22%20x%3D%22.5%22%20y%3D%22.5%22%20fill-rule%3D%22nonzero%22%20stroke%3D%22%234C4C4C%22%20rx%3D%222%22%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E%0A"); + cursor: pointer; + height: 1em; + margin-left: -1.5em; + margin-top: 0.125em; + position: absolute; + width: 1em; +} + +.tox-checklist li:not(.tox-checklist--hidden).tox-checklist--checked::before { + content: url("data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2216%22%20height%3D%2216%22%20viewBox%3D%220%200%2016%2016%22%3E%3Cg%20id%3D%22checklist-checked%22%20fill%3D%22none%22%20fill-rule%3D%22evenodd%22%3E%3Crect%20id%3D%22Rectangle%22%20width%3D%2216%22%20height%3D%2216%22%20fill%3D%22%234099FF%22%20fill-rule%3D%22nonzero%22%20rx%3D%222%22%2F%3E%3Cpath%20id%3D%22Path%22%20fill%3D%22%23FFF%22%20fill-rule%3D%22nonzero%22%20d%3D%22M11.5703186%2C3.14417309%20C11.8516238%2C2.73724603%2012.4164781%2C2.62829933%2012.83558%2C2.89774797%20C13.260121%2C3.17069355%2013.3759736%2C3.72932262%2013.0909105%2C4.14168582%20L7.7580587%2C11.8560195%20C7.43776896%2C12.3193404%206.76483983%2C12.3852142%206.35607322%2C11.9948725%20L3.02491697%2C8.8138662%20C2.66090143%2C8.46625845%202.65798871%2C7.89594698%203.01850234%2C7.54483354%20C3.373942%2C7.19866177%203.94940006%2C7.19592841%204.30829608%2C7.5386474%20L6.85276923%2C9.9684299%20L11.5703186%2C3.14417309%20Z%22%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E%0A"); +} + +[dir=rtl] .tox-checklist > li:not(.tox-checklist--hidden)::before { + margin-left: 0; + margin-right: -1.5em; +} + +/* stylelint-disable */ +/* http://prismjs.com/ */ +/** + * prism.js default theme for JavaScript, CSS and HTML + * Based on dabblet (http://dabblet.com) + * @author Lea Verou + */ +code[class*="language-"], +pre[class*="language-"] { + color: black; + background: none; + text-shadow: 0 1px white; + font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace; + font-size: 1em; + text-align: left; + white-space: pre; + word-spacing: normal; + word-break: normal; + word-wrap: normal; + line-height: 1.5; + -moz-tab-size: 4; + tab-size: 4; + -webkit-hyphens: none; + -ms-hyphens: none; + hyphens: none; +} + +pre[class*="language-"]::-moz-selection, +pre[class*="language-"] ::-moz-selection, +code[class*="language-"]::-moz-selection, +code[class*="language-"] ::-moz-selection { + text-shadow: none; + background: #b3d4fc; +} + +pre[class*="language-"]::selection, +pre[class*="language-"] ::selection, +code[class*="language-"]::selection, +code[class*="language-"] ::selection { + text-shadow: none; + background: #b3d4fc; +} + +@media print { + code[class*="language-"], + pre[class*="language-"] { + text-shadow: none; + } +} + +/* Code blocks */ +pre[class*="language-"] { + padding: 1em; + margin: 0.5em 0; + overflow: auto; +} + +:not(pre) > code[class*="language-"], +pre[class*="language-"] { + background: #f5f2f0; +} + +/* Inline code */ +:not(pre) > code[class*="language-"] { + padding: 0.1em; + border-radius: 0.3em; + white-space: normal; +} + +.token.comment, +.token.prolog, +.token.doctype, +.token.cdata { + color: slategray; +} + +.token.punctuation { + color: #999; +} + +.namespace { + opacity: 0.7; +} + +.token.property, +.token.tag, +.token.boolean, +.token.number, +.token.constant, +.token.symbol, +.token.deleted { + color: #905; +} + +.token.selector, +.token.attr-name, +.token.string, +.token.char, +.token.builtin, +.token.inserted { + color: #690; +} + +.token.operator, +.token.entity, +.token.url, +.language-css .token.string, +.style .token.string { + color: #9a6e3a; + background: hsla(0, 0%, 100%, 0.5); +} + +.token.atrule, +.token.attr-value, +.token.keyword { + color: #07a; +} + +.token.function, +.token.class-name { + color: #DD4A68; +} + +.token.regex, +.token.important, +.token.variable { + color: #e90; +} + +.token.important, +.token.bold { + font-weight: bold; +} + +.token.italic { + font-style: italic; +} + +.token.entity { + cursor: help; +} + +/* stylelint-enable */ +.mce-content-body { + overflow-wrap: break-word; + word-wrap: break-word; +} + +.mce-content-body .mce-visual-caret { + background-color: black; + background-color: currentColor; + position: absolute; +} + +.mce-content-body .mce-visual-caret-hidden { + display: none; +} + +.mce-content-body *[data-mce-caret] { + left: -1000px; + margin: 0; + padding: 0; + position: absolute; + right: auto; + top: 0; +} + +.mce-content-body .mce-offscreen-selection { + left: -2000000px; + max-width: 1000000px; + position: absolute; +} + +.mce-content-body *[contentEditable=false] { + cursor: default; +} + +.mce-content-body *[contentEditable=true] { + cursor: text; +} + +.tox-cursor-format-painter { + cursor: url("data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2224%22%20height%3D%2224%22%20viewBox%3D%220%200%2024%2024%22%3E%0A%20%20%3Cg%20fill%3D%22none%22%20fill-rule%3D%22evenodd%22%3E%0A%20%20%20%20%3Cpath%20fill%3D%22%23000%22%20fill-rule%3D%22nonzero%22%20d%3D%22M15%2C6%20C15%2C5.45%2014.55%2C5%2014%2C5%20L6%2C5%20C5.45%2C5%205%2C5.45%205%2C6%20L5%2C10%20C5%2C10.55%205.45%2C11%206%2C11%20L14%2C11%20C14.55%2C11%2015%2C10.55%2015%2C10%20L15%2C9%20L16%2C9%20L16%2C12%20L9%2C12%20L9%2C19%20C9%2C19.55%209.45%2C20%2010%2C20%20L11%2C20%20C11.55%2C20%2012%2C19.55%2012%2C19%20L12%2C14%20L18%2C14%20L18%2C7%20L15%2C7%20L15%2C6%20Z%22%2F%3E%0A%20%20%20%20%3Cpath%20fill%3D%22%23000%22%20fill-rule%3D%22nonzero%22%20d%3D%22M1%2C1%20L8.25%2C1%20C8.66421356%2C1%209%2C1.33578644%209%2C1.75%20L9%2C1.75%20C9%2C2.16421356%208.66421356%2C2.5%208.25%2C2.5%20L2.5%2C2.5%20L2.5%2C8.25%20C2.5%2C8.66421356%202.16421356%2C9%201.75%2C9%20L1.75%2C9%20C1.33578644%2C9%201%2C8.66421356%201%2C8.25%20L1%2C1%20Z%22%2F%3E%0A%20%20%3C%2Fg%3E%0A%3C%2Fsvg%3E%0A"), default; +} + +.mce-content-body figure.align-left { + float: left; +} + +.mce-content-body figure.align-right { + float: right; +} + +.mce-content-body figure.image.align-center { + display: table; + margin-left: auto; + margin-right: auto; +} + +.mce-preview-object { + border: 1px solid gray; + display: inline-block; + line-height: 0; + margin: 0 2px 0 2px; + position: relative; +} + +.mce-preview-object .mce-shim { + background: url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7); + height: 100%; + left: 0; + position: absolute; + top: 0; + width: 100%; +} + +.mce-preview-object[data-mce-selected="2"] .mce-shim { + display: none; +} + +.mce-object { + background: transparent url("data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2224%22%20height%3D%2224%22%3E%3Cpath%20d%3D%22M4%203h16a1%201%200%200%201%201%201v16a1%201%200%200%201-1%201H4a1%201%200%200%201-1-1V4a1%201%200%200%201%201-1zm1%202v14h14V5H5zm4.79%202.565l5.64%204.028a.5.5%200%200%201%200%20.814l-5.64%204.028a.5.5%200%200%201-.79-.407V7.972a.5.5%200%200%201%20.79-.407z%22%2F%3E%3C%2Fsvg%3E%0A") no-repeat center; + border: 1px dashed #aaa; +} + +.mce-pagebreak { + border: 1px dashed #aaa; + cursor: default; + display: block; + height: 5px; + margin-top: 15px; + page-break-before: always; + width: 100%; +} + +@media print { + .mce-pagebreak { + border: 0; + } +} + +.tiny-pageembed .mce-shim { + background: url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7); + height: 100%; + left: 0; + position: absolute; + top: 0; + width: 100%; +} + +.tiny-pageembed[data-mce-selected="2"] .mce-shim { + display: none; +} + +.tiny-pageembed { + display: inline-block; + position: relative; +} + +.tiny-pageembed--21by9, +.tiny-pageembed--16by9, +.tiny-pageembed--4by3, +.tiny-pageembed--1by1 { + display: block; + overflow: hidden; + padding: 0; + position: relative; + width: 100%; +} + +.tiny-pageembed--21by9 { + padding-top: 42.857143%; +} + +.tiny-pageembed--16by9 { + padding-top: 56.25%; +} + +.tiny-pageembed--4by3 { + padding-top: 75%; +} + +.tiny-pageembed--1by1 { + padding-top: 100%; +} + +.tiny-pageembed--21by9 iframe, +.tiny-pageembed--16by9 iframe, +.tiny-pageembed--4by3 iframe, +.tiny-pageembed--1by1 iframe { + border: 0; + height: 100%; + left: 0; + position: absolute; + top: 0; + width: 100%; +} + +.mce-content-body[data-mce-placeholder] { + position: relative; +} + +.mce-content-body[data-mce-placeholder]:not(.mce-visualblocks)::before { + color: rgba(34, 47, 62, 0.7); + content: attr(data-mce-placeholder); + position: absolute; +} + +.mce-content-body:not([dir=rtl])[data-mce-placeholder]:not(.mce-visualblocks)::before { + left: 1px; + color: #a1b7cb; +} + +.mce-content-body[dir=rtl][data-mce-placeholder]:not(.mce-visualblocks)::before { + right: 1px; +} + +.mce-content-body div.mce-resizehandle { + background-color: #4099ff; + border-color: #4099ff; + border-style: solid; + border-width: 1px; + box-sizing: border-box; + height: 10px; + position: absolute; + width: 10px; + z-index: 10000; +} + +.mce-content-body div.mce-resizehandle:hover { + background-color: #4099ff; +} + +.mce-content-body div.mce-resizehandle:nth-of-type(1) { + cursor: nwse-resize; +} + +.mce-content-body div.mce-resizehandle:nth-of-type(2) { + cursor: nesw-resize; +} + +.mce-content-body div.mce-resizehandle:nth-of-type(3) { + cursor: nwse-resize; +} + +.mce-content-body div.mce-resizehandle:nth-of-type(4) { + cursor: nesw-resize; +} + +.mce-content-body .mce-resize-backdrop { + z-index: 10000; +} + +.mce-content-body .mce-clonedresizable { + cursor: default; + opacity: 0.5; + outline: 1px dashed black; + position: absolute; + z-index: 10001; +} + +.mce-content-body .mce-clonedresizable.mce-resizetable-columns th, +.mce-content-body .mce-clonedresizable.mce-resizetable-columns td { + border: 0; +} + +.mce-content-body .mce-resize-helper { + background: #555; + background: rgba(0, 0, 0, 0.75); + border: 1px; + border-radius: 3px; + color: white; + display: none; + font-family: sans-serif; + font-size: 12px; + line-height: 14px; + margin: 5px 10px; + padding: 5px; + position: absolute; + white-space: nowrap; + z-index: 10002; +} + +.tox-rtc-user-selection { + position: relative; +} + +.tox-rtc-user-cursor { + bottom: 0; + cursor: default; + position: absolute; + top: 0; + width: 2px; +} + +.tox-rtc-user-cursor::before { + background-color: inherit; + border-radius: 50%; + content: ''; + display: block; + height: 8px; + position: absolute; + right: -3px; + top: -3px; + width: 8px; +} + +.tox-rtc-user-cursor:hover::after { + background-color: inherit; + border-radius: 100px; + box-sizing: border-box; + color: #fff; + content: attr(data-user); + display: block; + font-size: 12px; + font-weight: bold; + left: -5px; + min-height: 8px; + min-width: 8px; + padding: 0 12px; + position: absolute; + top: -11px; + white-space: nowrap; + z-index: 1000; +} + +.tox-rtc-user-selection--1 .tox-rtc-user-cursor { + background-color: #2dc26b; +} + +.tox-rtc-user-selection--2 .tox-rtc-user-cursor { + background-color: #e03e2d; +} + +.tox-rtc-user-selection--3 .tox-rtc-user-cursor { + background-color: #f1c40f; +} + +.tox-rtc-user-selection--4 .tox-rtc-user-cursor { + background-color: #3598db; +} + +.tox-rtc-user-selection--5 .tox-rtc-user-cursor { + background-color: #b96ad9; +} + +.tox-rtc-user-selection--6 .tox-rtc-user-cursor { + background-color: #e67e23; +} + +.tox-rtc-user-selection--7 .tox-rtc-user-cursor { + background-color: #aaa69d; +} + +.tox-rtc-user-selection--8 .tox-rtc-user-cursor { + background-color: #f368e0; +} + +.tox-rtc-remote-image { + background: #eaeaea url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%2236%22%20height%3D%2212%22%20viewBox%3D%220%200%2036%2012%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%20%20%3Ccircle%20cx%3D%226%22%20cy%3D%226%22%20r%3D%223%22%20fill%3D%22rgba(0%2C%200%2C%200%2C%20.2)%22%3E%0A%20%20%20%20%3Canimate%20attributeName%3D%22r%22%20values%3D%223%3B5%3B3%22%20calcMode%3D%22linear%22%20dur%3D%221s%22%20repeatCount%3D%22indefinite%22%20%2F%3E%0A%20%20%3C%2Fcircle%3E%0A%20%20%3Ccircle%20cx%3D%2218%22%20cy%3D%226%22%20r%3D%223%22%20fill%3D%22rgba(0%2C%200%2C%200%2C%20.2)%22%3E%0A%20%20%20%20%3Canimate%20attributeName%3D%22r%22%20values%3D%223%3B5%3B3%22%20calcMode%3D%22linear%22%20begin%3D%22.33s%22%20dur%3D%221s%22%20repeatCount%3D%22indefinite%22%20%2F%3E%0A%20%20%3C%2Fcircle%3E%0A%20%20%3Ccircle%20cx%3D%2230%22%20cy%3D%226%22%20r%3D%223%22%20fill%3D%22rgba(0%2C%200%2C%200%2C%20.2)%22%3E%0A%20%20%20%20%3Canimate%20attributeName%3D%22r%22%20values%3D%223%3B5%3B3%22%20calcMode%3D%22linear%22%20begin%3D%22.66s%22%20dur%3D%221s%22%20repeatCount%3D%22indefinite%22%20%2F%3E%0A%20%20%3C%2Fcircle%3E%0A%3C%2Fsvg%3E%0A") no-repeat center center; + border: 1px solid #ccc; + min-height: 240px; + min-width: 320px; +} + +.mce-match-marker { + background: #aaa; + color: #fff; +} + +.mce-match-marker-selected { + background: #39f; + color: #fff; +} + +.mce-match-marker-selected::-moz-selection { + background: #39f; + color: #fff; +} + +.mce-match-marker-selected::selection { + background: #39f; + color: #fff; +} + +.mce-content-body img[data-mce-selected], +.mce-content-body video[data-mce-selected], +.mce-content-body audio[data-mce-selected], +.mce-content-body object[data-mce-selected], +.mce-content-body embed[data-mce-selected], +.mce-content-body table[data-mce-selected] { + outline: 3px solid #b4d7ff; +} + +.mce-content-body hr[data-mce-selected] { + outline: 3px solid #b4d7ff; + outline-offset: 1px; +} + +.mce-content-body *[contentEditable=false] *[contentEditable=true]:focus { + outline: 3px solid #b4d7ff; +} + +.mce-content-body *[contentEditable=false] *[contentEditable=true]:hover { + outline: 3px solid #b4d7ff; +} + +.mce-content-body *[contentEditable=false][data-mce-selected] { + cursor: not-allowed; + outline: 3px solid #b4d7ff; +} + +.mce-content-body.mce-content-readonly *[contentEditable=true]:focus, +.mce-content-body.mce-content-readonly *[contentEditable=true]:hover { + outline: none; +} + +.mce-content-body *[data-mce-selected="inline-boundary"] { + background-color: #b4d7ff; +} + +.mce-content-body .mce-edit-focus { + outline: 3px solid #b4d7ff; +} + +.mce-content-body td[data-mce-selected], +.mce-content-body th[data-mce-selected] { + position: relative; +} + +.mce-content-body td[data-mce-selected]::-moz-selection, +.mce-content-body th[data-mce-selected]::-moz-selection { + background: none; +} + +.mce-content-body td[data-mce-selected]::selection, +.mce-content-body th[data-mce-selected]::selection { + background: none; +} + +.mce-content-body td[data-mce-selected] *, +.mce-content-body th[data-mce-selected] * { + outline: none; + -webkit-touch-callout: none; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} + +.mce-content-body td[data-mce-selected]::after, +.mce-content-body th[data-mce-selected]::after { + background-color: rgba(180, 215, 255, 0.7); + border: 1px solid rgba(180, 215, 255, 0.7); + bottom: -1px; + content: ''; + left: -1px; + mix-blend-mode: multiply; + position: absolute; + right: -1px; + top: -1px; +} + +@media screen and (-ms-high-contrast: active), (-ms-high-contrast: none) { + .mce-content-body td[data-mce-selected]::after, + .mce-content-body th[data-mce-selected]::after { + border-color: rgba(0, 84, 180, 0.7); + } +} + +.mce-content-body img::-moz-selection { + background: none; +} + +.mce-content-body img::selection { + background: none; +} + +.ephox-snooker-resizer-bar { + background-color: #b4d7ff; + opacity: 0; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} + +.ephox-snooker-resizer-cols { + cursor: col-resize; +} + +.ephox-snooker-resizer-rows { + cursor: row-resize; +} + +.ephox-snooker-resizer-bar.ephox-snooker-resizer-bar-dragging { + opacity: 1; +} + +.mce-spellchecker-word { + background-image: url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D'4'%20height%3D'4'%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%3E%3Cpath%20stroke%3D'%23ff0000'%20fill%3D'none'%20stroke-linecap%3D'round'%20stroke-opacity%3D'.75'%20d%3D'M0%203L2%201%204%203'%2F%3E%3C%2Fsvg%3E%0A"); + background-position: 0 calc(100% + 1px); + background-repeat: repeat-x; + background-size: auto 6px; + cursor: default; + height: 2rem; +} + +.mce-spellchecker-grammar { + background-image: url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D'4'%20height%3D'4'%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%3E%3Cpath%20stroke%3D'%2300A835'%20fill%3D'none'%20stroke-linecap%3D'round'%20d%3D'M0%203L2%201%204%203'%2F%3E%3C%2Fsvg%3E%0A"); + background-position: 0 calc(100% + 1px); + background-repeat: repeat-x; + background-size: auto 6px; + cursor: default; +} + +.mce-toc { + border: 1px solid gray; +} + +.mce-toc h2 { + margin: 4px; +} + +.mce-toc li { + list-style-type: none; +} + +table[style*="border-width: 0px"], +.mce-item-table:not([border]), +.mce-item-table[border="0"], +table[style*="border-width: 0px"] td, +.mce-item-table:not([border]) td, +.mce-item-table[border="0"] td, +table[style*="border-width: 0px"] th, +.mce-item-table:not([border]) th, +.mce-item-table[border="0"] th, +table[style*="border-width: 0px"] caption, +.mce-item-table:not([border]) caption, +.mce-item-table[border="0"] caption { + border: 1px dashed #bbb; +} + +.mce-visualblocks p, +.mce-visualblocks h1, +.mce-visualblocks h2, +.mce-visualblocks h3, +.mce-visualblocks h4, +.mce-visualblocks h5, +.mce-visualblocks h6, +.mce-visualblocks div:not([data-mce-bogus]), +.mce-visualblocks section, +.mce-visualblocks article, +.mce-visualblocks blockquote, +.mce-visualblocks address, +.mce-visualblocks pre, +.mce-visualblocks figure, +.mce-visualblocks figcaption, +.mce-visualblocks hgroup, +.mce-visualblocks aside, +.mce-visualblocks ul, +.mce-visualblocks ol, +.mce-visualblocks dl { + background-repeat: no-repeat; + border: 1px dashed #bbb; + margin-left: 3px; + padding-top: 10px; +} + +.mce-visualblocks p { + background-image: url(data:image/gif;base64,R0lGODlhCQAJAJEAAAAAAP///7u7u////yH5BAEAAAMALAAAAAAJAAkAAAIQnG+CqCN/mlyvsRUpThG6AgA7); +} + +.mce-visualblocks h1 { + background-image: url(data:image/gif;base64,R0lGODlhDQAKAIABALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybGu1JuxHoAfRNRW3TWXyF2YiRUAOw==); +} + +.mce-visualblocks h2 { + background-image: url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8Hybbx4oOuqgTynJd6bGlWg3DkJzoaUAAAOw==); +} + +.mce-visualblocks h3 { + background-image: url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIZjI8Hybbx4oOuqgTynJf2Ln2NOHpQpmhAAQA7); +} + +.mce-visualblocks h4 { + background-image: url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8HybbxInR0zqeAdhtJlXwV1oCll2HaWgAAOw==); +} + +.mce-visualblocks h5 { + background-image: url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8HybbxIoiuwjane4iq5GlW05GgIkIZUAAAOw==); +} + +.mce-visualblocks h6 { + background-image: url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8HybbxIoiuwjan04jep1iZ1XRlAo5bVgAAOw==); +} + +.mce-visualblocks div:not([data-mce-bogus]) { + background-image: url(data:image/gif;base64,R0lGODlhEgAKAIABALu7u////yH5BAEAAAEALAAAAAASAAoAAAIfjI9poI0cgDywrhuxfbrzDEbQM2Ei5aRjmoySW4pAAQA7); +} + +.mce-visualblocks section { + background-image: url(data:image/gif;base64,R0lGODlhKAAKAIABALu7u////yH5BAEAAAEALAAAAAAoAAoAAAI5jI+pywcNY3sBWHdNrplytD2ellDeSVbp+GmWqaDqDMepc8t17Y4vBsK5hDyJMcI6KkuYU+jpjLoKADs=); +} + +.mce-visualblocks article { + background-image: url(data:image/gif;base64,R0lGODlhKgAKAIABALu7u////yH5BAEAAAEALAAAAAAqAAoAAAI6jI+pywkNY3wG0GBvrsd2tXGYSGnfiF7ikpXemTpOiJScasYoDJJrjsG9gkCJ0ag6KhmaIe3pjDYBBQA7); +} + +.mce-visualblocks blockquote { + background-image: url(data:image/gif;base64,R0lGODlhPgAKAIABALu7u////yH5BAEAAAEALAAAAAA+AAoAAAJPjI+py+0Knpz0xQDyuUhvfoGgIX5iSKZYgq5uNL5q69asZ8s5rrf0yZmpNkJZzFesBTu8TOlDVAabUyatguVhWduud3EyiUk45xhTTgMBBQA7); +} + +.mce-visualblocks address { + background-image: url(data:image/gif;base64,R0lGODlhLQAKAIABALu7u////yH5BAEAAAEALAAAAAAtAAoAAAI/jI+pywwNozSP1gDyyZcjb3UaRpXkWaXmZW4OqKLhBmLs+K263DkJK7OJeifh7FicKD9A1/IpGdKkyFpNmCkAADs=); +} + +.mce-visualblocks pre { + background-image: url(data:image/gif;base64,R0lGODlhFQAKAIABALu7uwAAACH5BAEAAAEALAAAAAAVAAoAAAIjjI+ZoN0cgDwSmnpz1NCueYERhnibZVKLNnbOq8IvKpJtVQAAOw==); +} + +.mce-visualblocks figure { + background-image: url(data:image/gif;base64,R0lGODlhJAAKAIAAALu7u////yH5BAEAAAEALAAAAAAkAAoAAAI0jI+py+2fwAHUSFvD3RlvG4HIp4nX5JFSpnZUJ6LlrM52OE7uSWosBHScgkSZj7dDKnWAAgA7); +} + +.mce-visualblocks figcaption { + border: 1px dashed #bbb; +} + +.mce-visualblocks hgroup { + background-image: url(data:image/gif;base64,R0lGODlhJwAKAIABALu7uwAAACH5BAEAAAEALAAAAAAnAAoAAAI3jI+pywYNI3uB0gpsRtt5fFnfNZaVSYJil4Wo03Hv6Z62uOCgiXH1kZIIJ8NiIxRrAZNMZAtQAAA7); +} + +.mce-visualblocks aside { + background-image: url(data:image/gif;base64,R0lGODlhHgAKAIABAKqqqv///yH5BAEAAAEALAAAAAAeAAoAAAItjI+pG8APjZOTzgtqy7I3f1yehmQcFY4WKZbqByutmW4aHUd6vfcVbgudgpYCADs=); +} + +.mce-visualblocks ul { + background-image: url(data:image/gif;base64,R0lGODlhDQAKAIAAALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybGuYnqUVSjvw26DzzXiqIDlVwAAOw==); +} + +.mce-visualblocks ol { + background-image: url(data:image/gif;base64,R0lGODlhDQAKAIABALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybH6HHt0qourxC6CvzXieHyeWQAAOw==); +} + +.mce-visualblocks dl { + background-image: url(data:image/gif;base64,R0lGODlhDQAKAIABALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybEOnmOvUoWznTqeuEjNSCqeGRUAOw==); +} + +.mce-visualblocks:not([dir=rtl]) p, +.mce-visualblocks:not([dir=rtl]) h1, +.mce-visualblocks:not([dir=rtl]) h2, +.mce-visualblocks:not([dir=rtl]) h3, +.mce-visualblocks:not([dir=rtl]) h4, +.mce-visualblocks:not([dir=rtl]) h5, +.mce-visualblocks:not([dir=rtl]) h6, +.mce-visualblocks:not([dir=rtl]) div:not([data-mce-bogus]), +.mce-visualblocks:not([dir=rtl]) section, +.mce-visualblocks:not([dir=rtl]) article, +.mce-visualblocks:not([dir=rtl]) blockquote, +.mce-visualblocks:not([dir=rtl]) address, +.mce-visualblocks:not([dir=rtl]) pre, +.mce-visualblocks:not([dir=rtl]) figure, +.mce-visualblocks:not([dir=rtl]) figcaption, +.mce-visualblocks:not([dir=rtl]) hgroup, +.mce-visualblocks:not([dir=rtl]) aside, +.mce-visualblocks:not([dir=rtl]) ul, +.mce-visualblocks:not([dir=rtl]) ol, +.mce-visualblocks:not([dir=rtl]) dl { + margin-left: 3px; +} + +.mce-visualblocks[dir=rtl] p, +.mce-visualblocks[dir=rtl] h1, +.mce-visualblocks[dir=rtl] h2, +.mce-visualblocks[dir=rtl] h3, +.mce-visualblocks[dir=rtl] h4, +.mce-visualblocks[dir=rtl] h5, +.mce-visualblocks[dir=rtl] h6, +.mce-visualblocks[dir=rtl] div:not([data-mce-bogus]), +.mce-visualblocks[dir=rtl] section, +.mce-visualblocks[dir=rtl] article, +.mce-visualblocks[dir=rtl] blockquote, +.mce-visualblocks[dir=rtl] address, +.mce-visualblocks[dir=rtl] pre, +.mce-visualblocks[dir=rtl] figure, +.mce-visualblocks[dir=rtl] figcaption, +.mce-visualblocks[dir=rtl] hgroup, +.mce-visualblocks[dir=rtl] aside, +.mce-visualblocks[dir=rtl] ul, +.mce-visualblocks[dir=rtl] ol, +.mce-visualblocks[dir=rtl] dl { + background-position-x: right; + margin-right: 3px; +} + +.mce-nbsp, +.mce-shy { + background: #aaa; +} + +.mce-shy::after { + content: '-'; +} + +body { + font-family: sans-serif; +} + +table { + border-collapse: collapse; +} diff --git a/frontend/public/tinymce-dataease-private/skins/ui/oxide/content.inline.css b/frontend/public/tinymce-dataease-private/skins/ui/oxide/content.inline.css new file mode 100644 index 0000000..fc15063 --- /dev/null +++ b/frontend/public/tinymce-dataease-private/skins/ui/oxide/content.inline.css @@ -0,0 +1,861 @@ +/** + * Copyright (c) Tiny Technologies, Inc. All rights reserved. + * Licensed under the LGPL or a commercial license. + * For LGPL see License.txt in the project root for license information. + * For commercial licenses see https://www.tiny.cloud/ + */ +.mce-content-body .mce-item-anchor { + background: transparent url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D'8'%20height%3D'12'%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%3E%3Cpath%20d%3D'M0%200L8%200%208%2012%204.09117821%209%200%2012z'%2F%3E%3C%2Fsvg%3E%0A") no-repeat center; + cursor: default; + display: inline-block; + height: 12px !important; + padding: 0 2px; + -webkit-user-modify: read-only; + -moz-user-modify: read-only; + -webkit-user-select: all; + -moz-user-select: all; + -ms-user-select: all; + user-select: all; + width: 8px !important; +} + +.mce-content-body .mce-item-anchor[data-mce-selected] { + outline-offset: 1px; +} + +.tox-comments-visible .tox-comment { + background-color: #fff0b7; +} + +.tox-comments-visible .tox-comment--active { + background-color: #ffe168; +} + +.tox-checklist > li:not(.tox-checklist--hidden) { + list-style: none; + margin: 0.25em 0; +} + +.tox-checklist > li:not(.tox-checklist--hidden)::before { + content: url("data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2216%22%20height%3D%2216%22%20viewBox%3D%220%200%2016%2016%22%3E%3Cg%20id%3D%22checklist-unchecked%22%20fill%3D%22none%22%20fill-rule%3D%22evenodd%22%3E%3Crect%20id%3D%22Rectangle%22%20width%3D%2215%22%20height%3D%2215%22%20x%3D%22.5%22%20y%3D%22.5%22%20fill-rule%3D%22nonzero%22%20stroke%3D%22%234C4C4C%22%20rx%3D%222%22%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E%0A"); + cursor: pointer; + height: 1em; + margin-left: -1.5em; + margin-top: 0.125em; + position: absolute; + width: 1em; +} + +.tox-checklist li:not(.tox-checklist--hidden).tox-checklist--checked::before { + content: url("data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2216%22%20height%3D%2216%22%20viewBox%3D%220%200%2016%2016%22%3E%3Cg%20id%3D%22checklist-checked%22%20fill%3D%22none%22%20fill-rule%3D%22evenodd%22%3E%3Crect%20id%3D%22Rectangle%22%20width%3D%2216%22%20height%3D%2216%22%20fill%3D%22%234099FF%22%20fill-rule%3D%22nonzero%22%20rx%3D%222%22%2F%3E%3Cpath%20id%3D%22Path%22%20fill%3D%22%23FFF%22%20fill-rule%3D%22nonzero%22%20d%3D%22M11.5703186%2C3.14417309%20C11.8516238%2C2.73724603%2012.4164781%2C2.62829933%2012.83558%2C2.89774797%20C13.260121%2C3.17069355%2013.3759736%2C3.72932262%2013.0909105%2C4.14168582%20L7.7580587%2C11.8560195%20C7.43776896%2C12.3193404%206.76483983%2C12.3852142%206.35607322%2C11.9948725%20L3.02491697%2C8.8138662%20C2.66090143%2C8.46625845%202.65798871%2C7.89594698%203.01850234%2C7.54483354%20C3.373942%2C7.19866177%203.94940006%2C7.19592841%204.30829608%2C7.5386474%20L6.85276923%2C9.9684299%20L11.5703186%2C3.14417309%20Z%22%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E%0A"); +} + +[dir=rtl] .tox-checklist > li:not(.tox-checklist--hidden)::before { + margin-left: 0; + margin-right: -1.5em; +} + +/* stylelint-disable */ +/* http://prismjs.com/ */ +/** + * prism.js default theme for JavaScript, CSS and HTML + * Based on dabblet (http://dabblet.com) + * @author Lea Verou + */ +code[class*="language-"], +pre[class*="language-"] { + color: black; + background: none; + text-shadow: 0 1px white; + font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace; + font-size: 1em; + text-align: left; + white-space: pre; + word-spacing: normal; + word-break: normal; + word-wrap: normal; + line-height: 1.5; + -moz-tab-size: 4; + tab-size: 4; + -webkit-hyphens: none; + -ms-hyphens: none; + hyphens: none; +} + +pre[class*="language-"]::-moz-selection, +pre[class*="language-"] ::-moz-selection, +code[class*="language-"]::-moz-selection, +code[class*="language-"] ::-moz-selection { + text-shadow: none; + background: #b3d4fc; +} + +pre[class*="language-"]::selection, +pre[class*="language-"] ::selection, +code[class*="language-"]::selection, +code[class*="language-"] ::selection { + text-shadow: none; + background: #b3d4fc; +} + +@media print { + code[class*="language-"], + pre[class*="language-"] { + text-shadow: none; + } +} + +/* Code blocks */ +pre[class*="language-"] { + padding: 1em; + margin: 0.5em 0; + overflow: auto; +} + +:not(pre) > code[class*="language-"], +pre[class*="language-"] { + background: #f5f2f0; +} + +/* Inline code */ +:not(pre) > code[class*="language-"] { + padding: 0.1em; + border-radius: 0.3em; + white-space: normal; +} + +.token.comment, +.token.prolog, +.token.doctype, +.token.cdata { + color: slategray; +} + +.token.punctuation { + color: #999; +} + +.namespace { + opacity: 0.7; +} + +.token.property, +.token.tag, +.token.boolean, +.token.number, +.token.constant, +.token.symbol, +.token.deleted { + color: #905; +} + +.token.selector, +.token.attr-name, +.token.string, +.token.char, +.token.builtin, +.token.inserted { + color: #690; +} + +.token.operator, +.token.entity, +.token.url, +.language-css .token.string, +.style .token.string { + color: #9a6e3a; + background: hsla(0, 0%, 100%, 0.5); +} + +.token.atrule, +.token.attr-value, +.token.keyword { + color: #07a; +} + +.token.function, +.token.class-name { + color: #DD4A68; +} + +.token.regex, +.token.important, +.token.variable { + color: #e90; +} + +.token.important, +.token.bold { + font-weight: bold; +} + +.token.italic { + font-style: italic; +} + +.token.entity { + cursor: help; +} + +/* stylelint-enable */ +.mce-content-body { + overflow-wrap: break-word; + word-wrap: break-word; +} + +.mce-content-body .mce-visual-caret { + background-color: black; + background-color: currentColor; + position: absolute; +} + +.mce-content-body .mce-visual-caret-hidden { + display: none; +} + +.mce-content-body *[data-mce-caret] { + left: -1000px; + margin: 0; + padding: 0; + position: absolute; + right: auto; + top: 0; +} + +.mce-content-body .mce-offscreen-selection { + left: -2000000px; + max-width: 1000000px; + position: absolute; +} + +.mce-content-body *[contentEditable=false] { + cursor: default; +} + +.mce-content-body *[contentEditable=true] { + cursor: text; +} + +.tox-cursor-format-painter { + cursor: url("data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2224%22%20height%3D%2224%22%20viewBox%3D%220%200%2024%2024%22%3E%0A%20%20%3Cg%20fill%3D%22none%22%20fill-rule%3D%22evenodd%22%3E%0A%20%20%20%20%3Cpath%20fill%3D%22%23000%22%20fill-rule%3D%22nonzero%22%20d%3D%22M15%2C6%20C15%2C5.45%2014.55%2C5%2014%2C5%20L6%2C5%20C5.45%2C5%205%2C5.45%205%2C6%20L5%2C10%20C5%2C10.55%205.45%2C11%206%2C11%20L14%2C11%20C14.55%2C11%2015%2C10.55%2015%2C10%20L15%2C9%20L16%2C9%20L16%2C12%20L9%2C12%20L9%2C19%20C9%2C19.55%209.45%2C20%2010%2C20%20L11%2C20%20C11.55%2C20%2012%2C19.55%2012%2C19%20L12%2C14%20L18%2C14%20L18%2C7%20L15%2C7%20L15%2C6%20Z%22%2F%3E%0A%20%20%20%20%3Cpath%20fill%3D%22%23000%22%20fill-rule%3D%22nonzero%22%20d%3D%22M1%2C1%20L8.25%2C1%20C8.66421356%2C1%209%2C1.33578644%209%2C1.75%20L9%2C1.75%20C9%2C2.16421356%208.66421356%2C2.5%208.25%2C2.5%20L2.5%2C2.5%20L2.5%2C8.25%20C2.5%2C8.66421356%202.16421356%2C9%201.75%2C9%20L1.75%2C9%20C1.33578644%2C9%201%2C8.66421356%201%2C8.25%20L1%2C1%20Z%22%2F%3E%0A%20%20%3C%2Fg%3E%0A%3C%2Fsvg%3E%0A"), default; +} + +.mce-content-body figure.align-left { + float: left; +} + +.mce-content-body figure.align-right { + float: right; +} + +.mce-content-body figure.image.align-center { + display: table; + margin-left: auto; + margin-right: auto; +} + +.mce-preview-object { + border: 1px solid gray; + display: inline-block; + line-height: 0; + margin: 0 2px 0 2px; + position: relative; +} + +.mce-preview-object .mce-shim { + background: url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7); + height: 100%; + left: 0; + position: absolute; + top: 0; + width: 100%; +} + +.mce-preview-object[data-mce-selected="2"] .mce-shim { + display: none; +} + +.mce-object { + background: transparent url("data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2224%22%20height%3D%2224%22%3E%3Cpath%20d%3D%22M4%203h16a1%201%200%200%201%201%201v16a1%201%200%200%201-1%201H4a1%201%200%200%201-1-1V4a1%201%200%200%201%201-1zm1%202v14h14V5H5zm4.79%202.565l5.64%204.028a.5.5%200%200%201%200%20.814l-5.64%204.028a.5.5%200%200%201-.79-.407V7.972a.5.5%200%200%201%20.79-.407z%22%2F%3E%3C%2Fsvg%3E%0A") no-repeat center; + border: 1px dashed #aaa; +} + +.mce-pagebreak { + border: 1px dashed #aaa; + cursor: default; + display: block; + height: 5px; + margin-top: 15px; + page-break-before: always; + width: 100%; +} + +@media print { + .mce-pagebreak { + border: 0; + } +} + +.tiny-pageembed .mce-shim { + background: url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7); + height: 100%; + left: 0; + position: absolute; + top: 0; + width: 100%; +} + +.tiny-pageembed[data-mce-selected="2"] .mce-shim { + display: none; +} + +.tiny-pageembed { + display: inline-block; + position: relative; +} + +.tiny-pageembed--21by9, +.tiny-pageembed--16by9, +.tiny-pageembed--4by3, +.tiny-pageembed--1by1 { + display: block; + overflow: hidden; + padding: 0; + position: relative; + width: 100%; +} + +.tiny-pageembed--21by9 { + padding-top: 42.857143%; +} + +.tiny-pageembed--16by9 { + padding-top: 56.25%; +} + +.tiny-pageembed--4by3 { + padding-top: 75%; +} + +.tiny-pageembed--1by1 { + padding-top: 100%; +} + +.tiny-pageembed--21by9 iframe, +.tiny-pageembed--16by9 iframe, +.tiny-pageembed--4by3 iframe, +.tiny-pageembed--1by1 iframe { + border: 0; + height: 100%; + left: 0; + position: absolute; + top: 0; + width: 100%; +} + +.mce-content-body[data-mce-placeholder] { + position: relative; +} + +.mce-content-body[data-mce-placeholder]:not(.mce-visualblocks)::before { + color: rgba(34, 47, 62, 0.7); + content: attr(data-mce-placeholder); + position: absolute; +} + +.mce-content-body:not([dir=rtl])[data-mce-placeholder]:not(.mce-visualblocks)::before { + left: 1px; + color: #a1b7cb; +} + +.mce-content-body[dir=rtl][data-mce-placeholder]:not(.mce-visualblocks)::before { + right: 1px; +} + +.mce-content-body div.mce-resizehandle { + background-color: #4099ff; + border-color: #4099ff; + border-style: solid; + border-width: 1px; + box-sizing: border-box; + height: 10px; + position: absolute; + width: 10px; + z-index: 10000; +} + +.mce-content-body div.mce-resizehandle:hover { + background-color: #4099ff; +} + +.mce-content-body div.mce-resizehandle:nth-of-type(1) { + cursor: nwse-resize; +} + +.mce-content-body div.mce-resizehandle:nth-of-type(2) { + cursor: nesw-resize; +} + +.mce-content-body div.mce-resizehandle:nth-of-type(3) { + cursor: nwse-resize; +} + +.mce-content-body div.mce-resizehandle:nth-of-type(4) { + cursor: nesw-resize; +} + +.mce-content-body .mce-resize-backdrop { + z-index: 10000; +} + +.mce-content-body .mce-clonedresizable { + cursor: default; + opacity: 0.5; + outline: 1px dashed black; + position: absolute; + z-index: 10001; +} + +.mce-content-body .mce-clonedresizable.mce-resizetable-columns th, +.mce-content-body .mce-clonedresizable.mce-resizetable-columns td { + border: 0; +} + +.mce-content-body .mce-resize-helper { + background: #555; + background: rgba(0, 0, 0, 0.75); + border: 1px; + border-radius: 3px; + color: white; + display: none; + font-family: sans-serif; + font-size: 12px; + line-height: 14px; + margin: 5px 10px; + padding: 5px; + position: absolute; + white-space: nowrap; + z-index: 10002; +} + +.tox-rtc-user-selection { + position: relative; +} + +.tox-rtc-user-cursor { + bottom: 0; + cursor: default; + position: absolute; + top: 0; + width: 2px; +} + +.tox-rtc-user-cursor::before { + background-color: inherit; + border-radius: 50%; + content: ''; + display: block; + height: 8px; + position: absolute; + right: -3px; + top: -3px; + width: 8px; +} + +.tox-rtc-user-cursor:hover::after { + background-color: inherit; + border-radius: 100px; + box-sizing: border-box; + color: #fff; + content: attr(data-user); + display: block; + font-size: 12px; + font-weight: bold; + left: -5px; + min-height: 8px; + min-width: 8px; + padding: 0 12px; + position: absolute; + top: -11px; + white-space: nowrap; + z-index: 1000; +} + +.tox-rtc-user-selection--1 .tox-rtc-user-cursor { + background-color: #2dc26b; +} + +.tox-rtc-user-selection--2 .tox-rtc-user-cursor { + background-color: #e03e2d; +} + +.tox-rtc-user-selection--3 .tox-rtc-user-cursor { + background-color: #f1c40f; +} + +.tox-rtc-user-selection--4 .tox-rtc-user-cursor { + background-color: #3598db; +} + +.tox-rtc-user-selection--5 .tox-rtc-user-cursor { + background-color: #b96ad9; +} + +.tox-rtc-user-selection--6 .tox-rtc-user-cursor { + background-color: #e67e23; +} + +.tox-rtc-user-selection--7 .tox-rtc-user-cursor { + background-color: #aaa69d; +} + +.tox-rtc-user-selection--8 .tox-rtc-user-cursor { + background-color: #f368e0; +} + +.tox-rtc-remote-image { + background: #eaeaea url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%2236%22%20height%3D%2212%22%20viewBox%3D%220%200%2036%2012%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%20%20%3Ccircle%20cx%3D%226%22%20cy%3D%226%22%20r%3D%223%22%20fill%3D%22rgba(0%2C%200%2C%200%2C%20.2)%22%3E%0A%20%20%20%20%3Canimate%20attributeName%3D%22r%22%20values%3D%223%3B5%3B3%22%20calcMode%3D%22linear%22%20dur%3D%221s%22%20repeatCount%3D%22indefinite%22%20%2F%3E%0A%20%20%3C%2Fcircle%3E%0A%20%20%3Ccircle%20cx%3D%2218%22%20cy%3D%226%22%20r%3D%223%22%20fill%3D%22rgba(0%2C%200%2C%200%2C%20.2)%22%3E%0A%20%20%20%20%3Canimate%20attributeName%3D%22r%22%20values%3D%223%3B5%3B3%22%20calcMode%3D%22linear%22%20begin%3D%22.33s%22%20dur%3D%221s%22%20repeatCount%3D%22indefinite%22%20%2F%3E%0A%20%20%3C%2Fcircle%3E%0A%20%20%3Ccircle%20cx%3D%2230%22%20cy%3D%226%22%20r%3D%223%22%20fill%3D%22rgba(0%2C%200%2C%200%2C%20.2)%22%3E%0A%20%20%20%20%3Canimate%20attributeName%3D%22r%22%20values%3D%223%3B5%3B3%22%20calcMode%3D%22linear%22%20begin%3D%22.66s%22%20dur%3D%221s%22%20repeatCount%3D%22indefinite%22%20%2F%3E%0A%20%20%3C%2Fcircle%3E%0A%3C%2Fsvg%3E%0A") no-repeat center center; + border: 1px solid #ccc; + min-height: 240px; + min-width: 320px; +} + +.mce-match-marker { + background: #aaa; + color: #fff; +} + +.mce-match-marker-selected { + background: #39f; + color: #fff; +} + +.mce-match-marker-selected::-moz-selection { + background: #39f; + color: #fff; +} + +.mce-match-marker-selected::selection { + background: #39f; + color: #fff; +} + +.mce-content-body img[data-mce-selected], +.mce-content-body video[data-mce-selected], +.mce-content-body audio[data-mce-selected], +.mce-content-body object[data-mce-selected], +.mce-content-body embed[data-mce-selected], +.mce-content-body table[data-mce-selected] { + outline: 3px solid #b4d7ff; +} + +.mce-content-body hr[data-mce-selected] { + outline: 3px solid #b4d7ff; + outline-offset: 1px; +} + +.mce-content-body *[contentEditable=false] *[contentEditable=true]:focus { + outline: 3px solid #b4d7ff; +} + +.mce-content-body *[contentEditable=false] *[contentEditable=true]:hover { + outline: 3px solid #b4d7ff; +} + +.mce-content-body *[contentEditable=false][data-mce-selected] { + cursor: not-allowed; + outline: 3px solid #b4d7ff; +} + +.mce-content-body.mce-content-readonly *[contentEditable=true]:focus, +.mce-content-body.mce-content-readonly *[contentEditable=true]:hover { + outline: none; +} + +.mce-content-body *[data-mce-selected="inline-boundary"] { + background-color: #b4d7ff; +} + +.mce-content-body .mce-edit-focus { + outline: 3px solid #b4d7ff; +} + +.mce-content-body td[data-mce-selected], +.mce-content-body th[data-mce-selected] { + position: relative; +} + +.mce-content-body td[data-mce-selected]::-moz-selection, +.mce-content-body th[data-mce-selected]::-moz-selection { + background: none; +} + +.mce-content-body td[data-mce-selected]::selection, +.mce-content-body th[data-mce-selected]::selection { + background: none; +} + +.mce-content-body td[data-mce-selected] *, +.mce-content-body th[data-mce-selected] * { + outline: none; + -webkit-touch-callout: none; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} + +.mce-content-body td[data-mce-selected]::after, +.mce-content-body th[data-mce-selected]::after { + background-color: rgba(180, 215, 255, 0.7); + border: 1px solid rgba(180, 215, 255, 0.7); + bottom: -1px; + content: ''; + left: -1px; + mix-blend-mode: multiply; + position: absolute; + right: -1px; + top: -1px; +} + +@media screen and (-ms-high-contrast: active), (-ms-high-contrast: none) { + .mce-content-body td[data-mce-selected]::after, + .mce-content-body th[data-mce-selected]::after { + border-color: rgba(0, 84, 180, 0.7); + } +} + +.mce-content-body img::-moz-selection { + background: none; +} + +.mce-content-body img::selection { + background: none; +} + +.ephox-snooker-resizer-bar { + background-color: #b4d7ff; + opacity: 0; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} + +.ephox-snooker-resizer-cols { + cursor: col-resize; +} + +.ephox-snooker-resizer-rows { + cursor: row-resize; +} + +.ephox-snooker-resizer-bar.ephox-snooker-resizer-bar-dragging { + opacity: 1; +} + +.mce-spellchecker-word { + background-image: url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D'4'%20height%3D'4'%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%3E%3Cpath%20stroke%3D'%23ff0000'%20fill%3D'none'%20stroke-linecap%3D'round'%20stroke-opacity%3D'.75'%20d%3D'M0%203L2%201%204%203'%2F%3E%3C%2Fsvg%3E%0A"); + background-position: 0 calc(100% + 1px); + background-repeat: repeat-x; + background-size: auto 6px; + cursor: default; + height: 2rem; +} + +.mce-spellchecker-grammar { + background-image: url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D'4'%20height%3D'4'%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%3E%3Cpath%20stroke%3D'%2300A835'%20fill%3D'none'%20stroke-linecap%3D'round'%20d%3D'M0%203L2%201%204%203'%2F%3E%3C%2Fsvg%3E%0A"); + background-position: 0 calc(100% + 1px); + background-repeat: repeat-x; + background-size: auto 6px; + cursor: default; +} + +.mce-toc { + border: 1px solid gray; +} + +.mce-toc h2 { + margin: 4px; +} + +.mce-toc li { + list-style-type: none; +} + +table[style*="border-width: 0px"], +.mce-item-table:not([border]), +.mce-item-table[border="0"], +table[style*="border-width: 0px"] td, +.mce-item-table:not([border]) td, +.mce-item-table[border="0"] td, +table[style*="border-width: 0px"] th, +.mce-item-table:not([border]) th, +.mce-item-table[border="0"] th, +table[style*="border-width: 0px"] caption, +.mce-item-table:not([border]) caption, +.mce-item-table[border="0"] caption { + border: 1px dashed #bbb; +} + +.mce-visualblocks p, +.mce-visualblocks h1, +.mce-visualblocks h2, +.mce-visualblocks h3, +.mce-visualblocks h4, +.mce-visualblocks h5, +.mce-visualblocks h6, +.mce-visualblocks div:not([data-mce-bogus]), +.mce-visualblocks section, +.mce-visualblocks article, +.mce-visualblocks blockquote, +.mce-visualblocks address, +.mce-visualblocks pre, +.mce-visualblocks figure, +.mce-visualblocks figcaption, +.mce-visualblocks hgroup, +.mce-visualblocks aside, +.mce-visualblocks ul, +.mce-visualblocks ol, +.mce-visualblocks dl { + background-repeat: no-repeat; + border: 1px dashed #bbb; + margin-left: 3px; + padding-top: 10px; +} + +.mce-visualblocks p { + background-image: url(data:image/gif;base64,R0lGODlhCQAJAJEAAAAAAP///7u7u////yH5BAEAAAMALAAAAAAJAAkAAAIQnG+CqCN/mlyvsRUpThG6AgA7); +} + +.mce-visualblocks h1 { + background-image: url(data:image/gif;base64,R0lGODlhDQAKAIABALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybGu1JuxHoAfRNRW3TWXyF2YiRUAOw==); +} + +.mce-visualblocks h2 { + background-image: url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8Hybbx4oOuqgTynJd6bGlWg3DkJzoaUAAAOw==); +} + +.mce-visualblocks h3 { + background-image: url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIZjI8Hybbx4oOuqgTynJf2Ln2NOHpQpmhAAQA7); +} + +.mce-visualblocks h4 { + background-image: url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8HybbxInR0zqeAdhtJlXwV1oCll2HaWgAAOw==); +} + +.mce-visualblocks h5 { + background-image: url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8HybbxIoiuwjane4iq5GlW05GgIkIZUAAAOw==); +} + +.mce-visualblocks h6 { + background-image: url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8HybbxIoiuwjan04jep1iZ1XRlAo5bVgAAOw==); +} + +.mce-visualblocks div:not([data-mce-bogus]) { + background-image: url(data:image/gif;base64,R0lGODlhEgAKAIABALu7u////yH5BAEAAAEALAAAAAASAAoAAAIfjI9poI0cgDywrhuxfbrzDEbQM2Ei5aRjmoySW4pAAQA7); +} + +.mce-visualblocks section { + background-image: url(data:image/gif;base64,R0lGODlhKAAKAIABALu7u////yH5BAEAAAEALAAAAAAoAAoAAAI5jI+pywcNY3sBWHdNrplytD2ellDeSVbp+GmWqaDqDMepc8t17Y4vBsK5hDyJMcI6KkuYU+jpjLoKADs=); +} + +.mce-visualblocks article { + background-image: url(data:image/gif;base64,R0lGODlhKgAKAIABALu7u////yH5BAEAAAEALAAAAAAqAAoAAAI6jI+pywkNY3wG0GBvrsd2tXGYSGnfiF7ikpXemTpOiJScasYoDJJrjsG9gkCJ0ag6KhmaIe3pjDYBBQA7); +} + +.mce-visualblocks blockquote { + background-image: url(data:image/gif;base64,R0lGODlhPgAKAIABALu7u////yH5BAEAAAEALAAAAAA+AAoAAAJPjI+py+0Knpz0xQDyuUhvfoGgIX5iSKZYgq5uNL5q69asZ8s5rrf0yZmpNkJZzFesBTu8TOlDVAabUyatguVhWduud3EyiUk45xhTTgMBBQA7); +} + +.mce-visualblocks address { + background-image: url(data:image/gif;base64,R0lGODlhLQAKAIABALu7u////yH5BAEAAAEALAAAAAAtAAoAAAI/jI+pywwNozSP1gDyyZcjb3UaRpXkWaXmZW4OqKLhBmLs+K263DkJK7OJeifh7FicKD9A1/IpGdKkyFpNmCkAADs=); +} + +.mce-visualblocks pre { + background-image: url(data:image/gif;base64,R0lGODlhFQAKAIABALu7uwAAACH5BAEAAAEALAAAAAAVAAoAAAIjjI+ZoN0cgDwSmnpz1NCueYERhnibZVKLNnbOq8IvKpJtVQAAOw==); +} + +.mce-visualblocks figure { + background-image: url(data:image/gif;base64,R0lGODlhJAAKAIAAALu7u////yH5BAEAAAEALAAAAAAkAAoAAAI0jI+py+2fwAHUSFvD3RlvG4HIp4nX5JFSpnZUJ6LlrM52OE7uSWosBHScgkSZj7dDKnWAAgA7); +} + +.mce-visualblocks figcaption { + border: 1px dashed #bbb; +} + +.mce-visualblocks hgroup { + background-image: url(data:image/gif;base64,R0lGODlhJwAKAIABALu7uwAAACH5BAEAAAEALAAAAAAnAAoAAAI3jI+pywYNI3uB0gpsRtt5fFnfNZaVSYJil4Wo03Hv6Z62uOCgiXH1kZIIJ8NiIxRrAZNMZAtQAAA7); +} + +.mce-visualblocks aside { + background-image: url(data:image/gif;base64,R0lGODlhHgAKAIABAKqqqv///yH5BAEAAAEALAAAAAAeAAoAAAItjI+pG8APjZOTzgtqy7I3f1yehmQcFY4WKZbqByutmW4aHUd6vfcVbgudgpYCADs=); +} + +.mce-visualblocks ul { + background-image: url(data:image/gif;base64,R0lGODlhDQAKAIAAALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybGuYnqUVSjvw26DzzXiqIDlVwAAOw==); +} + +.mce-visualblocks ol { + background-image: url(data:image/gif;base64,R0lGODlhDQAKAIABALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybH6HHt0qourxC6CvzXieHyeWQAAOw==); +} + +.mce-visualblocks dl { + background-image: url(data:image/gif;base64,R0lGODlhDQAKAIABALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybEOnmOvUoWznTqeuEjNSCqeGRUAOw==); +} + +.mce-visualblocks:not([dir=rtl]) p, +.mce-visualblocks:not([dir=rtl]) h1, +.mce-visualblocks:not([dir=rtl]) h2, +.mce-visualblocks:not([dir=rtl]) h3, +.mce-visualblocks:not([dir=rtl]) h4, +.mce-visualblocks:not([dir=rtl]) h5, +.mce-visualblocks:not([dir=rtl]) h6, +.mce-visualblocks:not([dir=rtl]) div:not([data-mce-bogus]), +.mce-visualblocks:not([dir=rtl]) section, +.mce-visualblocks:not([dir=rtl]) article, +.mce-visualblocks:not([dir=rtl]) blockquote, +.mce-visualblocks:not([dir=rtl]) address, +.mce-visualblocks:not([dir=rtl]) pre, +.mce-visualblocks:not([dir=rtl]) figure, +.mce-visualblocks:not([dir=rtl]) figcaption, +.mce-visualblocks:not([dir=rtl]) hgroup, +.mce-visualblocks:not([dir=rtl]) aside, +.mce-visualblocks:not([dir=rtl]) ul, +.mce-visualblocks:not([dir=rtl]) ol, +.mce-visualblocks:not([dir=rtl]) dl { + margin-left: 3px; +} + +.mce-visualblocks[dir=rtl] p, +.mce-visualblocks[dir=rtl] h1, +.mce-visualblocks[dir=rtl] h2, +.mce-visualblocks[dir=rtl] h3, +.mce-visualblocks[dir=rtl] h4, +.mce-visualblocks[dir=rtl] h5, +.mce-visualblocks[dir=rtl] h6, +.mce-visualblocks[dir=rtl] div:not([data-mce-bogus]), +.mce-visualblocks[dir=rtl] section, +.mce-visualblocks[dir=rtl] article, +.mce-visualblocks[dir=rtl] blockquote, +.mce-visualblocks[dir=rtl] address, +.mce-visualblocks[dir=rtl] pre, +.mce-visualblocks[dir=rtl] figure, +.mce-visualblocks[dir=rtl] figcaption, +.mce-visualblocks[dir=rtl] hgroup, +.mce-visualblocks[dir=rtl] aside, +.mce-visualblocks[dir=rtl] ul, +.mce-visualblocks[dir=rtl] ol, +.mce-visualblocks[dir=rtl] dl { + background-position-x: right; + margin-right: 3px; +} + +.mce-nbsp, +.mce-shy { + background: #aaa; +} + +.mce-shy::after { + content: '-'; +} diff --git a/frontend/public/tinymce-dataease-private/skins/ui/oxide/content.inline.min.css b/frontend/public/tinymce-dataease-private/skins/ui/oxide/content.inline.min.css new file mode 100644 index 0000000..5c66aca --- /dev/null +++ b/frontend/public/tinymce-dataease-private/skins/ui/oxide/content.inline.min.css @@ -0,0 +1,7 @@ +/** + * Copyright (c) Tiny Technologies, Inc. All rights reserved. + * Licensed under the LGPL or a commercial license. + * For LGPL see License.txt in the project root for license information. + * For commercial licenses see https://www.tiny.cloud/ + */ +.mce-content-body .mce-item-anchor{background:transparent url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D'8'%20height%3D'12'%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%3E%3Cpath%20d%3D'M0%200L8%200%208%2012%204.09117821%209%200%2012z'%2F%3E%3C%2Fsvg%3E%0A") no-repeat center;cursor:default;display:inline-block;height:12px!important;padding:0 2px;-webkit-user-modify:read-only;-moz-user-modify:read-only;-webkit-user-select:all;-moz-user-select:all;-ms-user-select:all;user-select:all;width:8px!important}.mce-content-body .mce-item-anchor[data-mce-selected]{outline-offset:1px}.tox-comments-visible .tox-comment{background-color:#fff0b7}.tox-comments-visible .tox-comment--active{background-color:#ffe168}.tox-checklist>li:not(.tox-checklist--hidden){list-style:none;margin:.25em 0}.tox-checklist>li:not(.tox-checklist--hidden)::before{content:url("data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2216%22%20height%3D%2216%22%20viewBox%3D%220%200%2016%2016%22%3E%3Cg%20id%3D%22checklist-unchecked%22%20fill%3D%22none%22%20fill-rule%3D%22evenodd%22%3E%3Crect%20id%3D%22Rectangle%22%20width%3D%2215%22%20height%3D%2215%22%20x%3D%22.5%22%20y%3D%22.5%22%20fill-rule%3D%22nonzero%22%20stroke%3D%22%234C4C4C%22%20rx%3D%222%22%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E%0A");cursor:pointer;height:1em;margin-left:-1.5em;margin-top:.125em;position:absolute;width:1em}.tox-checklist li:not(.tox-checklist--hidden).tox-checklist--checked::before{content:url("data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2216%22%20height%3D%2216%22%20viewBox%3D%220%200%2016%2016%22%3E%3Cg%20id%3D%22checklist-checked%22%20fill%3D%22none%22%20fill-rule%3D%22evenodd%22%3E%3Crect%20id%3D%22Rectangle%22%20width%3D%2216%22%20height%3D%2216%22%20fill%3D%22%234099FF%22%20fill-rule%3D%22nonzero%22%20rx%3D%222%22%2F%3E%3Cpath%20id%3D%22Path%22%20fill%3D%22%23FFF%22%20fill-rule%3D%22nonzero%22%20d%3D%22M11.5703186%2C3.14417309%20C11.8516238%2C2.73724603%2012.4164781%2C2.62829933%2012.83558%2C2.89774797%20C13.260121%2C3.17069355%2013.3759736%2C3.72932262%2013.0909105%2C4.14168582%20L7.7580587%2C11.8560195%20C7.43776896%2C12.3193404%206.76483983%2C12.3852142%206.35607322%2C11.9948725%20L3.02491697%2C8.8138662%20C2.66090143%2C8.46625845%202.65798871%2C7.89594698%203.01850234%2C7.54483354%20C3.373942%2C7.19866177%203.94940006%2C7.19592841%204.30829608%2C7.5386474%20L6.85276923%2C9.9684299%20L11.5703186%2C3.14417309%20Z%22%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E%0A")}[dir=rtl] .tox-checklist>li:not(.tox-checklist--hidden)::before{margin-left:0;margin-right:-1.5em}code[class*=language-],pre[class*=language-]{color:#000;background:0 0;text-shadow:0 1px #fff;font-family:Consolas,Monaco,'Andale Mono','Ubuntu Mono',monospace;font-size:1em;text-align:left;white-space:pre;word-spacing:normal;word-break:normal;word-wrap:normal;line-height:1.5;-moz-tab-size:4;tab-size:4;-webkit-hyphens:none;-ms-hyphens:none;hyphens:none}code[class*=language-] ::-moz-selection,code[class*=language-]::-moz-selection,pre[class*=language-] ::-moz-selection,pre[class*=language-]::-moz-selection{text-shadow:none;background:#b3d4fc}code[class*=language-] ::selection,code[class*=language-]::selection,pre[class*=language-] ::selection,pre[class*=language-]::selection{text-shadow:none;background:#b3d4fc}@media print{code[class*=language-],pre[class*=language-]{text-shadow:none}}pre[class*=language-]{padding:1em;margin:.5em 0;overflow:auto}:not(pre)>code[class*=language-],pre[class*=language-]{background:#f5f2f0}:not(pre)>code[class*=language-]{padding:.1em;border-radius:.3em;white-space:normal}.token.cdata,.token.comment,.token.doctype,.token.prolog{color:#708090}.token.punctuation{color:#999}.namespace{opacity:.7}.token.boolean,.token.constant,.token.deleted,.token.number,.token.property,.token.symbol,.token.tag{color:#905}.token.attr-name,.token.builtin,.token.char,.token.inserted,.token.selector,.token.string{color:#690}.language-css .token.string,.style .token.string,.token.entity,.token.operator,.token.url{color:#9a6e3a;background:hsla(0,0%,100%,.5)}.token.atrule,.token.attr-value,.token.keyword{color:#07a}.token.class-name,.token.function{color:#dd4a68}.token.important,.token.regex,.token.variable{color:#e90}.token.bold,.token.important{font-weight:700}.token.italic{font-style:italic}.token.entity{cursor:help}.mce-content-body{overflow-wrap:break-word;word-wrap:break-word}.mce-content-body .mce-visual-caret{background-color:#000;background-color:currentColor;position:absolute}.mce-content-body .mce-visual-caret-hidden{display:none}.mce-content-body [data-mce-caret]{left:-1000px;margin:0;padding:0;position:absolute;right:auto;top:0}.mce-content-body .mce-offscreen-selection{left:-2000000px;max-width:1000000px;position:absolute}.mce-content-body [contentEditable=false]{cursor:default}.mce-content-body [contentEditable=true]{cursor:text}.tox-cursor-format-painter{cursor:url("data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2224%22%20height%3D%2224%22%20viewBox%3D%220%200%2024%2024%22%3E%0A%20%20%3Cg%20fill%3D%22none%22%20fill-rule%3D%22evenodd%22%3E%0A%20%20%20%20%3Cpath%20fill%3D%22%23000%22%20fill-rule%3D%22nonzero%22%20d%3D%22M15%2C6%20C15%2C5.45%2014.55%2C5%2014%2C5%20L6%2C5%20C5.45%2C5%205%2C5.45%205%2C6%20L5%2C10%20C5%2C10.55%205.45%2C11%206%2C11%20L14%2C11%20C14.55%2C11%2015%2C10.55%2015%2C10%20L15%2C9%20L16%2C9%20L16%2C12%20L9%2C12%20L9%2C19%20C9%2C19.55%209.45%2C20%2010%2C20%20L11%2C20%20C11.55%2C20%2012%2C19.55%2012%2C19%20L12%2C14%20L18%2C14%20L18%2C7%20L15%2C7%20L15%2C6%20Z%22%2F%3E%0A%20%20%20%20%3Cpath%20fill%3D%22%23000%22%20fill-rule%3D%22nonzero%22%20d%3D%22M1%2C1%20L8.25%2C1%20C8.66421356%2C1%209%2C1.33578644%209%2C1.75%20L9%2C1.75%20C9%2C2.16421356%208.66421356%2C2.5%208.25%2C2.5%20L2.5%2C2.5%20L2.5%2C8.25%20C2.5%2C8.66421356%202.16421356%2C9%201.75%2C9%20L1.75%2C9%20C1.33578644%2C9%201%2C8.66421356%201%2C8.25%20L1%2C1%20Z%22%2F%3E%0A%20%20%3C%2Fg%3E%0A%3C%2Fsvg%3E%0A"),default}.mce-content-body figure.align-left{float:left}.mce-content-body figure.align-right{float:right}.mce-content-body figure.image.align-center{display:table;margin-left:auto;margin-right:auto}.mce-preview-object{border:1px solid gray;display:inline-block;line-height:0;margin:0 2px 0 2px;position:relative}.mce-preview-object .mce-shim{background:url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7);height:100%;left:0;position:absolute;top:0;width:100%}.mce-preview-object[data-mce-selected="2"] .mce-shim{display:none}.mce-object{background:transparent url("data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2224%22%20height%3D%2224%22%3E%3Cpath%20d%3D%22M4%203h16a1%201%200%200%201%201%201v16a1%201%200%200%201-1%201H4a1%201%200%200%201-1-1V4a1%201%200%200%201%201-1zm1%202v14h14V5H5zm4.79%202.565l5.64%204.028a.5.5%200%200%201%200%20.814l-5.64%204.028a.5.5%200%200%201-.79-.407V7.972a.5.5%200%200%201%20.79-.407z%22%2F%3E%3C%2Fsvg%3E%0A") no-repeat center;border:1px dashed #aaa}.mce-pagebreak{border:1px dashed #aaa;cursor:default;display:block;height:5px;margin-top:15px;page-break-before:always;width:100%}@media print{.mce-pagebreak{border:0}}.tiny-pageembed .mce-shim{background:url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7);height:100%;left:0;position:absolute;top:0;width:100%}.tiny-pageembed[data-mce-selected="2"] .mce-shim{display:none}.tiny-pageembed{display:inline-block;position:relative}.tiny-pageembed--16by9,.tiny-pageembed--1by1,.tiny-pageembed--21by9,.tiny-pageembed--4by3{display:block;overflow:hidden;padding:0;position:relative;width:100%}.tiny-pageembed--21by9{padding-top:42.857143%}.tiny-pageembed--16by9{padding-top:56.25%}.tiny-pageembed--4by3{padding-top:75%}.tiny-pageembed--1by1{padding-top:100%}.tiny-pageembed--16by9 iframe,.tiny-pageembed--1by1 iframe,.tiny-pageembed--21by9 iframe,.tiny-pageembed--4by3 iframe{border:0;height:100%;left:0;position:absolute;top:0;width:100%}.mce-content-body[data-mce-placeholder]{position:relative}.mce-content-body[data-mce-placeholder]:not(.mce-visualblocks)::before{color:rgba(34,47,62,.7);content:attr(data-mce-placeholder);position:absolute}.mce-content-body:not([dir=rtl])[data-mce-placeholder]:not(.mce-visualblocks)::before{left:1px;color:#a1b7cb;}.mce-content-body[dir=rtl][data-mce-placeholder]:not(.mce-visualblocks)::before{right:1px}.mce-content-body div.mce-resizehandle{background-color:#4099ff;border-color:#4099ff;border-style:solid;border-width:1px;box-sizing:border-box;height:10px;position:absolute;width:10px;z-index:10000}.mce-content-body div.mce-resizehandle:hover{background-color:#4099ff}.mce-content-body div.mce-resizehandle:nth-of-type(1){cursor:nwse-resize}.mce-content-body div.mce-resizehandle:nth-of-type(2){cursor:nesw-resize}.mce-content-body div.mce-resizehandle:nth-of-type(3){cursor:nwse-resize}.mce-content-body div.mce-resizehandle:nth-of-type(4){cursor:nesw-resize}.mce-content-body .mce-resize-backdrop{z-index:10000}.mce-content-body .mce-clonedresizable{cursor:default;opacity:.5;outline:1px dashed #000;position:absolute;z-index:10001}.mce-content-body .mce-clonedresizable.mce-resizetable-columns td,.mce-content-body .mce-clonedresizable.mce-resizetable-columns th{border:0}.mce-content-body .mce-resize-helper{background:#555;background:rgba(0,0,0,.75);border:1px;border-radius:3px;color:#fff;display:none;font-family:sans-serif;font-size:12px;line-height:14px;margin:5px 10px;padding:5px;position:absolute;white-space:nowrap;z-index:10002}.tox-rtc-user-selection{position:relative}.tox-rtc-user-cursor{bottom:0;cursor:default;position:absolute;top:0;width:2px}.tox-rtc-user-cursor::before{background-color:inherit;border-radius:50%;content:'';display:block;height:8px;position:absolute;right:-3px;top:-3px;width:8px}.tox-rtc-user-cursor:hover::after{background-color:inherit;border-radius:100px;box-sizing:border-box;color:#fff;content:attr(data-user);display:block;font-size:12px;font-weight:700;left:-5px;min-height:8px;min-width:8px;padding:0 12px;position:absolute;top:-11px;white-space:nowrap;z-index:1000}.tox-rtc-user-selection--1 .tox-rtc-user-cursor{background-color:#2dc26b}.tox-rtc-user-selection--2 .tox-rtc-user-cursor{background-color:#e03e2d}.tox-rtc-user-selection--3 .tox-rtc-user-cursor{background-color:#f1c40f}.tox-rtc-user-selection--4 .tox-rtc-user-cursor{background-color:#3598db}.tox-rtc-user-selection--5 .tox-rtc-user-cursor{background-color:#b96ad9}.tox-rtc-user-selection--6 .tox-rtc-user-cursor{background-color:#e67e23}.tox-rtc-user-selection--7 .tox-rtc-user-cursor{background-color:#aaa69d}.tox-rtc-user-selection--8 .tox-rtc-user-cursor{background-color:#f368e0}.tox-rtc-remote-image{background:#eaeaea url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%2236%22%20height%3D%2212%22%20viewBox%3D%220%200%2036%2012%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%20%20%3Ccircle%20cx%3D%226%22%20cy%3D%226%22%20r%3D%223%22%20fill%3D%22rgba(0%2C%200%2C%200%2C%20.2)%22%3E%0A%20%20%20%20%3Canimate%20attributeName%3D%22r%22%20values%3D%223%3B5%3B3%22%20calcMode%3D%22linear%22%20dur%3D%221s%22%20repeatCount%3D%22indefinite%22%20%2F%3E%0A%20%20%3C%2Fcircle%3E%0A%20%20%3Ccircle%20cx%3D%2218%22%20cy%3D%226%22%20r%3D%223%22%20fill%3D%22rgba(0%2C%200%2C%200%2C%20.2)%22%3E%0A%20%20%20%20%3Canimate%20attributeName%3D%22r%22%20values%3D%223%3B5%3B3%22%20calcMode%3D%22linear%22%20begin%3D%22.33s%22%20dur%3D%221s%22%20repeatCount%3D%22indefinite%22%20%2F%3E%0A%20%20%3C%2Fcircle%3E%0A%20%20%3Ccircle%20cx%3D%2230%22%20cy%3D%226%22%20r%3D%223%22%20fill%3D%22rgba(0%2C%200%2C%200%2C%20.2)%22%3E%0A%20%20%20%20%3Canimate%20attributeName%3D%22r%22%20values%3D%223%3B5%3B3%22%20calcMode%3D%22linear%22%20begin%3D%22.66s%22%20dur%3D%221s%22%20repeatCount%3D%22indefinite%22%20%2F%3E%0A%20%20%3C%2Fcircle%3E%0A%3C%2Fsvg%3E%0A") no-repeat center center;border:1px solid #ccc;min-height:240px;min-width:320px}.mce-match-marker{background:#aaa;color:#fff}.mce-match-marker-selected{background:#39f;color:#fff}.mce-match-marker-selected::-moz-selection{background:#39f;color:#fff}.mce-match-marker-selected::selection{background:#39f;color:#fff}.mce-content-body audio[data-mce-selected],.mce-content-body embed[data-mce-selected],.mce-content-body img[data-mce-selected],.mce-content-body object[data-mce-selected],.mce-content-body table[data-mce-selected],.mce-content-body video[data-mce-selected]{outline:3px solid #b4d7ff}.mce-content-body hr[data-mce-selected]{outline:3px solid #b4d7ff;outline-offset:1px}.mce-content-body [contentEditable=false] [contentEditable=true]:focus{outline:3px solid #b4d7ff}.mce-content-body [contentEditable=false] [contentEditable=true]:hover{outline:3px solid #b4d7ff}.mce-content-body [contentEditable=false][data-mce-selected]{cursor:not-allowed;outline:3px solid #b4d7ff}.mce-content-body.mce-content-readonly [contentEditable=true]:focus,.mce-content-body.mce-content-readonly [contentEditable=true]:hover{outline:0}.mce-content-body [data-mce-selected=inline-boundary]{background-color:#b4d7ff}.mce-content-body .mce-edit-focus{outline:3px solid #b4d7ff}.mce-content-body td[data-mce-selected],.mce-content-body th[data-mce-selected]{position:relative}.mce-content-body td[data-mce-selected]::-moz-selection,.mce-content-body th[data-mce-selected]::-moz-selection{background:0 0}.mce-content-body td[data-mce-selected]::selection,.mce-content-body th[data-mce-selected]::selection{background:0 0}.mce-content-body td[data-mce-selected] *,.mce-content-body th[data-mce-selected] *{outline:0;-webkit-touch-callout:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.mce-content-body td[data-mce-selected]::after,.mce-content-body th[data-mce-selected]::after{background-color:rgba(180,215,255,.7);border:1px solid rgba(180,215,255,.7);bottom:-1px;content:'';left:-1px;mix-blend-mode:multiply;position:absolute;right:-1px;top:-1px}@media screen and (-ms-high-contrast:active),(-ms-high-contrast:none){.mce-content-body td[data-mce-selected]::after,.mce-content-body th[data-mce-selected]::after{border-color:rgba(0,84,180,.7)}}.mce-content-body img::-moz-selection{background:0 0}.mce-content-body img::selection{background:0 0}.ephox-snooker-resizer-bar{background-color:#b4d7ff;opacity:0;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.ephox-snooker-resizer-cols{cursor:col-resize}.ephox-snooker-resizer-rows{cursor:row-resize}.ephox-snooker-resizer-bar.ephox-snooker-resizer-bar-dragging{opacity:1}.mce-spellchecker-word{background-image:url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D'4'%20height%3D'4'%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%3E%3Cpath%20stroke%3D'%23ff0000'%20fill%3D'none'%20stroke-linecap%3D'round'%20stroke-opacity%3D'.75'%20d%3D'M0%203L2%201%204%203'%2F%3E%3C%2Fsvg%3E%0A");background-position:0 calc(100% + 1px);background-repeat:repeat-x;background-size:auto 6px;cursor:default;height:2rem}.mce-spellchecker-grammar{background-image:url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D'4'%20height%3D'4'%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%3E%3Cpath%20stroke%3D'%2300A835'%20fill%3D'none'%20stroke-linecap%3D'round'%20d%3D'M0%203L2%201%204%203'%2F%3E%3C%2Fsvg%3E%0A");background-position:0 calc(100% + 1px);background-repeat:repeat-x;background-size:auto 6px;cursor:default}.mce-toc{border:1px solid gray}.mce-toc h2{margin:4px}.mce-toc li{list-style-type:none}.mce-item-table:not([border]),.mce-item-table:not([border]) caption,.mce-item-table:not([border]) td,.mce-item-table:not([border]) th,.mce-item-table[border="0"],.mce-item-table[border="0"] caption,.mce-item-table[border="0"] td,.mce-item-table[border="0"] th,table[style*="border-width: 0px"],table[style*="border-width: 0px"] caption,table[style*="border-width: 0px"] td,table[style*="border-width: 0px"] th{border:1px dashed #bbb}.mce-visualblocks address,.mce-visualblocks article,.mce-visualblocks aside,.mce-visualblocks blockquote,.mce-visualblocks div:not([data-mce-bogus]),.mce-visualblocks dl,.mce-visualblocks figcaption,.mce-visualblocks figure,.mce-visualblocks h1,.mce-visualblocks h2,.mce-visualblocks h3,.mce-visualblocks h4,.mce-visualblocks h5,.mce-visualblocks h6,.mce-visualblocks hgroup,.mce-visualblocks ol,.mce-visualblocks p,.mce-visualblocks pre,.mce-visualblocks section,.mce-visualblocks ul{background-repeat:no-repeat;border:1px dashed #bbb;margin-left:3px;padding-top:10px}.mce-visualblocks p{background-image:url(data:image/gif;base64,R0lGODlhCQAJAJEAAAAAAP///7u7u////yH5BAEAAAMALAAAAAAJAAkAAAIQnG+CqCN/mlyvsRUpThG6AgA7)}.mce-visualblocks h1{background-image:url(data:image/gif;base64,R0lGODlhDQAKAIABALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybGu1JuxHoAfRNRW3TWXyF2YiRUAOw==)}.mce-visualblocks h2{background-image:url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8Hybbx4oOuqgTynJd6bGlWg3DkJzoaUAAAOw==)}.mce-visualblocks h3{background-image:url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIZjI8Hybbx4oOuqgTynJf2Ln2NOHpQpmhAAQA7)}.mce-visualblocks h4{background-image:url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8HybbxInR0zqeAdhtJlXwV1oCll2HaWgAAOw==)}.mce-visualblocks h5{background-image:url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8HybbxIoiuwjane4iq5GlW05GgIkIZUAAAOw==)}.mce-visualblocks h6{background-image:url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8HybbxIoiuwjan04jep1iZ1XRlAo5bVgAAOw==)}.mce-visualblocks div:not([data-mce-bogus]){background-image:url(data:image/gif;base64,R0lGODlhEgAKAIABALu7u////yH5BAEAAAEALAAAAAASAAoAAAIfjI9poI0cgDywrhuxfbrzDEbQM2Ei5aRjmoySW4pAAQA7)}.mce-visualblocks section{background-image:url(data:image/gif;base64,R0lGODlhKAAKAIABALu7u////yH5BAEAAAEALAAAAAAoAAoAAAI5jI+pywcNY3sBWHdNrplytD2ellDeSVbp+GmWqaDqDMepc8t17Y4vBsK5hDyJMcI6KkuYU+jpjLoKADs=)}.mce-visualblocks article{background-image:url(data:image/gif;base64,R0lGODlhKgAKAIABALu7u////yH5BAEAAAEALAAAAAAqAAoAAAI6jI+pywkNY3wG0GBvrsd2tXGYSGnfiF7ikpXemTpOiJScasYoDJJrjsG9gkCJ0ag6KhmaIe3pjDYBBQA7)}.mce-visualblocks blockquote{background-image:url(data:image/gif;base64,R0lGODlhPgAKAIABALu7u////yH5BAEAAAEALAAAAAA+AAoAAAJPjI+py+0Knpz0xQDyuUhvfoGgIX5iSKZYgq5uNL5q69asZ8s5rrf0yZmpNkJZzFesBTu8TOlDVAabUyatguVhWduud3EyiUk45xhTTgMBBQA7)}.mce-visualblocks address{background-image:url(data:image/gif;base64,R0lGODlhLQAKAIABALu7u////yH5BAEAAAEALAAAAAAtAAoAAAI/jI+pywwNozSP1gDyyZcjb3UaRpXkWaXmZW4OqKLhBmLs+K263DkJK7OJeifh7FicKD9A1/IpGdKkyFpNmCkAADs=)}.mce-visualblocks pre{background-image:url(data:image/gif;base64,R0lGODlhFQAKAIABALu7uwAAACH5BAEAAAEALAAAAAAVAAoAAAIjjI+ZoN0cgDwSmnpz1NCueYERhnibZVKLNnbOq8IvKpJtVQAAOw==)}.mce-visualblocks figure{background-image:url(data:image/gif;base64,R0lGODlhJAAKAIAAALu7u////yH5BAEAAAEALAAAAAAkAAoAAAI0jI+py+2fwAHUSFvD3RlvG4HIp4nX5JFSpnZUJ6LlrM52OE7uSWosBHScgkSZj7dDKnWAAgA7)}.mce-visualblocks figcaption{border:1px dashed #bbb}.mce-visualblocks hgroup{background-image:url(data:image/gif;base64,R0lGODlhJwAKAIABALu7uwAAACH5BAEAAAEALAAAAAAnAAoAAAI3jI+pywYNI3uB0gpsRtt5fFnfNZaVSYJil4Wo03Hv6Z62uOCgiXH1kZIIJ8NiIxRrAZNMZAtQAAA7)}.mce-visualblocks aside{background-image:url(data:image/gif;base64,R0lGODlhHgAKAIABAKqqqv///yH5BAEAAAEALAAAAAAeAAoAAAItjI+pG8APjZOTzgtqy7I3f1yehmQcFY4WKZbqByutmW4aHUd6vfcVbgudgpYCADs=)}.mce-visualblocks ul{background-image:url(data:image/gif;base64,R0lGODlhDQAKAIAAALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybGuYnqUVSjvw26DzzXiqIDlVwAAOw==)}.mce-visualblocks ol{background-image:url(data:image/gif;base64,R0lGODlhDQAKAIABALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybH6HHt0qourxC6CvzXieHyeWQAAOw==)}.mce-visualblocks dl{background-image:url(data:image/gif;base64,R0lGODlhDQAKAIABALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybEOnmOvUoWznTqeuEjNSCqeGRUAOw==)}.mce-visualblocks:not([dir=rtl]) address,.mce-visualblocks:not([dir=rtl]) article,.mce-visualblocks:not([dir=rtl]) aside,.mce-visualblocks:not([dir=rtl]) blockquote,.mce-visualblocks:not([dir=rtl]) div:not([data-mce-bogus]),.mce-visualblocks:not([dir=rtl]) dl,.mce-visualblocks:not([dir=rtl]) figcaption,.mce-visualblocks:not([dir=rtl]) figure,.mce-visualblocks:not([dir=rtl]) h1,.mce-visualblocks:not([dir=rtl]) h2,.mce-visualblocks:not([dir=rtl]) h3,.mce-visualblocks:not([dir=rtl]) h4,.mce-visualblocks:not([dir=rtl]) h5,.mce-visualblocks:not([dir=rtl]) h6,.mce-visualblocks:not([dir=rtl]) hgroup,.mce-visualblocks:not([dir=rtl]) ol,.mce-visualblocks:not([dir=rtl]) p,.mce-visualblocks:not([dir=rtl]) pre,.mce-visualblocks:not([dir=rtl]) section,.mce-visualblocks:not([dir=rtl]) ul{margin-left:3px}.mce-visualblocks[dir=rtl] address,.mce-visualblocks[dir=rtl] article,.mce-visualblocks[dir=rtl] aside,.mce-visualblocks[dir=rtl] blockquote,.mce-visualblocks[dir=rtl] div:not([data-mce-bogus]),.mce-visualblocks[dir=rtl] dl,.mce-visualblocks[dir=rtl] figcaption,.mce-visualblocks[dir=rtl] figure,.mce-visualblocks[dir=rtl] h1,.mce-visualblocks[dir=rtl] h2,.mce-visualblocks[dir=rtl] h3,.mce-visualblocks[dir=rtl] h4,.mce-visualblocks[dir=rtl] h5,.mce-visualblocks[dir=rtl] h6,.mce-visualblocks[dir=rtl] hgroup,.mce-visualblocks[dir=rtl] ol,.mce-visualblocks[dir=rtl] p,.mce-visualblocks[dir=rtl] pre,.mce-visualblocks[dir=rtl] section,.mce-visualblocks[dir=rtl] ul{background-position-x:right;margin-right:3px}.mce-nbsp,.mce-shy{background:#aaa}.mce-shy::after{content:'-'} diff --git a/frontend/public/tinymce-dataease-private/skins/ui/oxide/content.min.css b/frontend/public/tinymce-dataease-private/skins/ui/oxide/content.min.css new file mode 100644 index 0000000..b3dcb52 --- /dev/null +++ b/frontend/public/tinymce-dataease-private/skins/ui/oxide/content.min.css @@ -0,0 +1,7 @@ +/** + * Copyright (c) Tiny Technologies, Inc. All rights reserved. + * Licensed under the LGPL or a commercial license. + * For LGPL see License.txt in the project root for license information. + * For commercial licenses see https://www.tiny.cloud/ + */ +.mce-content-body .mce-item-anchor{background:transparent url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D'8'%20height%3D'12'%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%3E%3Cpath%20d%3D'M0%200L8%200%208%2012%204.09117821%209%200%2012z'%2F%3E%3C%2Fsvg%3E%0A") no-repeat center;cursor:default;display:inline-block;height:12px!important;padding:0 2px;-webkit-user-modify:read-only;-moz-user-modify:read-only;-webkit-user-select:all;-moz-user-select:all;-ms-user-select:all;user-select:all;width:8px!important}.mce-content-body .mce-item-anchor[data-mce-selected]{outline-offset:1px}.tox-comments-visible .tox-comment{background-color:#fff0b7}.tox-comments-visible .tox-comment--active{background-color:#ffe168}.tox-checklist>li:not(.tox-checklist--hidden){list-style:none;margin:.25em 0}.tox-checklist>li:not(.tox-checklist--hidden)::before{content:url("data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2216%22%20height%3D%2216%22%20viewBox%3D%220%200%2016%2016%22%3E%3Cg%20id%3D%22checklist-unchecked%22%20fill%3D%22none%22%20fill-rule%3D%22evenodd%22%3E%3Crect%20id%3D%22Rectangle%22%20width%3D%2215%22%20height%3D%2215%22%20x%3D%22.5%22%20y%3D%22.5%22%20fill-rule%3D%22nonzero%22%20stroke%3D%22%234C4C4C%22%20rx%3D%222%22%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E%0A");cursor:pointer;height:1em;margin-left:-1.5em;margin-top:.125em;position:absolute;width:1em}.tox-checklist li:not(.tox-checklist--hidden).tox-checklist--checked::before{content:url("data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2216%22%20height%3D%2216%22%20viewBox%3D%220%200%2016%2016%22%3E%3Cg%20id%3D%22checklist-checked%22%20fill%3D%22none%22%20fill-rule%3D%22evenodd%22%3E%3Crect%20id%3D%22Rectangle%22%20width%3D%2216%22%20height%3D%2216%22%20fill%3D%22%234099FF%22%20fill-rule%3D%22nonzero%22%20rx%3D%222%22%2F%3E%3Cpath%20id%3D%22Path%22%20fill%3D%22%23FFF%22%20fill-rule%3D%22nonzero%22%20d%3D%22M11.5703186%2C3.14417309%20C11.8516238%2C2.73724603%2012.4164781%2C2.62829933%2012.83558%2C2.89774797%20C13.260121%2C3.17069355%2013.3759736%2C3.72932262%2013.0909105%2C4.14168582%20L7.7580587%2C11.8560195%20C7.43776896%2C12.3193404%206.76483983%2C12.3852142%206.35607322%2C11.9948725%20L3.02491697%2C8.8138662%20C2.66090143%2C8.46625845%202.65798871%2C7.89594698%203.01850234%2C7.54483354%20C3.373942%2C7.19866177%203.94940006%2C7.19592841%204.30829608%2C7.5386474%20L6.85276923%2C9.9684299%20L11.5703186%2C3.14417309%20Z%22%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E%0A")}[dir=rtl] .tox-checklist>li:not(.tox-checklist--hidden)::before{margin-left:0;margin-right:-1.5em}code[class*=language-],pre[class*=language-]{color:#000;background:0 0;text-shadow:0 1px #fff;font-family:Consolas,Monaco,'Andale Mono','Ubuntu Mono',monospace;font-size:1em;text-align:left;white-space:pre;word-spacing:normal;word-break:normal;word-wrap:normal;line-height:1.5;-moz-tab-size:4;tab-size:4;-webkit-hyphens:none;-ms-hyphens:none;hyphens:none}code[class*=language-] ::-moz-selection,code[class*=language-]::-moz-selection,pre[class*=language-] ::-moz-selection,pre[class*=language-]::-moz-selection{text-shadow:none;background:#b3d4fc}code[class*=language-] ::selection,code[class*=language-]::selection,pre[class*=language-] ::selection,pre[class*=language-]::selection{text-shadow:none;background:#b3d4fc}@media print{code[class*=language-],pre[class*=language-]{text-shadow:none}}pre[class*=language-]{padding:1em;margin:.5em 0;overflow:auto}:not(pre)>code[class*=language-],pre[class*=language-]{background:#f5f2f0}:not(pre)>code[class*=language-]{padding:.1em;border-radius:.3em;white-space:normal}.token.cdata,.token.comment,.token.doctype,.token.prolog{color:#708090}.token.punctuation{color:#999}.namespace{opacity:.7}.token.boolean,.token.constant,.token.deleted,.token.number,.token.property,.token.symbol,.token.tag{color:#905}.token.attr-name,.token.builtin,.token.char,.token.inserted,.token.selector,.token.string{color:#690}.language-css .token.string,.style .token.string,.token.entity,.token.operator,.token.url{color:#9a6e3a;background:hsla(0,0%,100%,.5)}.token.atrule,.token.attr-value,.token.keyword{color:#07a}.token.class-name,.token.function{color:#dd4a68}.token.important,.token.regex,.token.variable{color:#e90}.token.bold,.token.important{font-weight:700}.token.italic{font-style:italic}.token.entity{cursor:help}.mce-content-body{overflow-wrap:break-word;word-wrap:break-word}.mce-content-body .mce-visual-caret{background-color:#000;background-color:currentColor;position:absolute}.mce-content-body .mce-visual-caret-hidden{display:none}.mce-content-body [data-mce-caret]{left:-1000px;margin:0;padding:0;position:absolute;right:auto;top:0}.mce-content-body .mce-offscreen-selection{left:-2000000px;max-width:1000000px;position:absolute}.mce-content-body [contentEditable=false]{cursor:default}.mce-content-body [contentEditable=true]{cursor:text}.tox-cursor-format-painter{cursor:url("data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2224%22%20height%3D%2224%22%20viewBox%3D%220%200%2024%2024%22%3E%0A%20%20%3Cg%20fill%3D%22none%22%20fill-rule%3D%22evenodd%22%3E%0A%20%20%20%20%3Cpath%20fill%3D%22%23000%22%20fill-rule%3D%22nonzero%22%20d%3D%22M15%2C6%20C15%2C5.45%2014.55%2C5%2014%2C5%20L6%2C5%20C5.45%2C5%205%2C5.45%205%2C6%20L5%2C10%20C5%2C10.55%205.45%2C11%206%2C11%20L14%2C11%20C14.55%2C11%2015%2C10.55%2015%2C10%20L15%2C9%20L16%2C9%20L16%2C12%20L9%2C12%20L9%2C19%20C9%2C19.55%209.45%2C20%2010%2C20%20L11%2C20%20C11.55%2C20%2012%2C19.55%2012%2C19%20L12%2C14%20L18%2C14%20L18%2C7%20L15%2C7%20L15%2C6%20Z%22%2F%3E%0A%20%20%20%20%3Cpath%20fill%3D%22%23000%22%20fill-rule%3D%22nonzero%22%20d%3D%22M1%2C1%20L8.25%2C1%20C8.66421356%2C1%209%2C1.33578644%209%2C1.75%20L9%2C1.75%20C9%2C2.16421356%208.66421356%2C2.5%208.25%2C2.5%20L2.5%2C2.5%20L2.5%2C8.25%20C2.5%2C8.66421356%202.16421356%2C9%201.75%2C9%20L1.75%2C9%20C1.33578644%2C9%201%2C8.66421356%201%2C8.25%20L1%2C1%20Z%22%2F%3E%0A%20%20%3C%2Fg%3E%0A%3C%2Fsvg%3E%0A"),default}.mce-content-body figure.align-left{float:left}.mce-content-body figure.align-right{float:right}.mce-content-body figure.image.align-center{display:table;margin-left:auto;margin-right:auto}.mce-preview-object{border:1px solid gray;display:inline-block;line-height:0;margin:0 2px 0 2px;position:relative}.mce-preview-object .mce-shim{background:url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7);height:100%;left:0;position:absolute;top:0;width:100%}.mce-preview-object[data-mce-selected="2"] .mce-shim{display:none}.mce-object{background:transparent url("data:image/svg+xml;charset=UTF-8,%3Csvg%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%20width%3D%2224%22%20height%3D%2224%22%3E%3Cpath%20d%3D%22M4%203h16a1%201%200%200%201%201%201v16a1%201%200%200%201-1%201H4a1%201%200%200%201-1-1V4a1%201%200%200%201%201-1zm1%202v14h14V5H5zm4.79%202.565l5.64%204.028a.5.5%200%200%201%200%20.814l-5.64%204.028a.5.5%200%200%201-.79-.407V7.972a.5.5%200%200%201%20.79-.407z%22%2F%3E%3C%2Fsvg%3E%0A") no-repeat center;border:1px dashed #aaa}.mce-pagebreak{border:1px dashed #aaa;cursor:default;display:block;height:5px;margin-top:15px;page-break-before:always;width:100%}@media print{.mce-pagebreak{border:0}}.tiny-pageembed .mce-shim{background:url(data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7);height:100%;left:0;position:absolute;top:0;width:100%}.tiny-pageembed[data-mce-selected="2"] .mce-shim{display:none}.tiny-pageembed{display:inline-block;position:relative}.tiny-pageembed--16by9,.tiny-pageembed--1by1,.tiny-pageembed--21by9,.tiny-pageembed--4by3{display:block;overflow:hidden;padding:0;position:relative;width:100%}.tiny-pageembed--21by9{padding-top:42.857143%}.tiny-pageembed--16by9{padding-top:56.25%}.tiny-pageembed--4by3{padding-top:75%}.tiny-pageembed--1by1{padding-top:100%}.tiny-pageembed--16by9 iframe,.tiny-pageembed--1by1 iframe,.tiny-pageembed--21by9 iframe,.tiny-pageembed--4by3 iframe{border:0;height:100%;left:0;position:absolute;top:0;width:100%}.mce-content-body[data-mce-placeholder]{position:relative}.mce-content-body[data-mce-placeholder]:not(.mce-visualblocks)::before{color:rgba(34,47,62,.7);content:attr(data-mce-placeholder);position:absolute}.mce-content-body:not([dir=rtl])[data-mce-placeholder]:not(.mce-visualblocks)::before{left:1px;color: #a1b7cb;}.mce-content-body[dir=rtl][data-mce-placeholder]:not(.mce-visualblocks)::before{right:1px}.mce-content-body div.mce-resizehandle{background-color:#4099ff;border-color:#4099ff;border-style:solid;border-width:1px;box-sizing:border-box;height:10px;position:absolute;width:10px;z-index:10000}.mce-content-body div.mce-resizehandle:hover{background-color:#4099ff}.mce-content-body div.mce-resizehandle:nth-of-type(1){cursor:nwse-resize}.mce-content-body div.mce-resizehandle:nth-of-type(2){cursor:nesw-resize}.mce-content-body div.mce-resizehandle:nth-of-type(3){cursor:nwse-resize}.mce-content-body div.mce-resizehandle:nth-of-type(4){cursor:nesw-resize}.mce-content-body .mce-resize-backdrop{z-index:10000}.mce-content-body .mce-clonedresizable{cursor:default;opacity:.5;outline:1px dashed #000;position:absolute;z-index:10001}.mce-content-body .mce-clonedresizable.mce-resizetable-columns td,.mce-content-body .mce-clonedresizable.mce-resizetable-columns th{border:0}.mce-content-body .mce-resize-helper{background:#555;background:rgba(0,0,0,.75);border:1px;border-radius:3px;color:#fff;display:none;font-family:sans-serif;font-size:12px;line-height:14px;margin:5px 10px;padding:5px;position:absolute;white-space:nowrap;z-index:10002}.tox-rtc-user-selection{position:relative}.tox-rtc-user-cursor{bottom:0;cursor:default;position:absolute;top:0;width:2px}.tox-rtc-user-cursor::before{background-color:inherit;border-radius:50%;content:'';display:block;height:8px;position:absolute;right:-3px;top:-3px;width:8px}.tox-rtc-user-cursor:hover::after{background-color:inherit;border-radius:100px;box-sizing:border-box;color:#fff;content:attr(data-user);display:block;font-size:12px;font-weight:700;left:-5px;min-height:8px;min-width:8px;padding:0 12px;position:absolute;top:-11px;white-space:nowrap;z-index:1000}.tox-rtc-user-selection--1 .tox-rtc-user-cursor{background-color:#2dc26b}.tox-rtc-user-selection--2 .tox-rtc-user-cursor{background-color:#e03e2d}.tox-rtc-user-selection--3 .tox-rtc-user-cursor{background-color:#f1c40f}.tox-rtc-user-selection--4 .tox-rtc-user-cursor{background-color:#3598db}.tox-rtc-user-selection--5 .tox-rtc-user-cursor{background-color:#b96ad9}.tox-rtc-user-selection--6 .tox-rtc-user-cursor{background-color:#e67e23}.tox-rtc-user-selection--7 .tox-rtc-user-cursor{background-color:#aaa69d}.tox-rtc-user-selection--8 .tox-rtc-user-cursor{background-color:#f368e0}.tox-rtc-remote-image{background:#eaeaea url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D%2236%22%20height%3D%2212%22%20viewBox%3D%220%200%2036%2012%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%0A%20%20%3Ccircle%20cx%3D%226%22%20cy%3D%226%22%20r%3D%223%22%20fill%3D%22rgba(0%2C%200%2C%200%2C%20.2)%22%3E%0A%20%20%20%20%3Canimate%20attributeName%3D%22r%22%20values%3D%223%3B5%3B3%22%20calcMode%3D%22linear%22%20dur%3D%221s%22%20repeatCount%3D%22indefinite%22%20%2F%3E%0A%20%20%3C%2Fcircle%3E%0A%20%20%3Ccircle%20cx%3D%2218%22%20cy%3D%226%22%20r%3D%223%22%20fill%3D%22rgba(0%2C%200%2C%200%2C%20.2)%22%3E%0A%20%20%20%20%3Canimate%20attributeName%3D%22r%22%20values%3D%223%3B5%3B3%22%20calcMode%3D%22linear%22%20begin%3D%22.33s%22%20dur%3D%221s%22%20repeatCount%3D%22indefinite%22%20%2F%3E%0A%20%20%3C%2Fcircle%3E%0A%20%20%3Ccircle%20cx%3D%2230%22%20cy%3D%226%22%20r%3D%223%22%20fill%3D%22rgba(0%2C%200%2C%200%2C%20.2)%22%3E%0A%20%20%20%20%3Canimate%20attributeName%3D%22r%22%20values%3D%223%3B5%3B3%22%20calcMode%3D%22linear%22%20begin%3D%22.66s%22%20dur%3D%221s%22%20repeatCount%3D%22indefinite%22%20%2F%3E%0A%20%20%3C%2Fcircle%3E%0A%3C%2Fsvg%3E%0A") no-repeat center center;border:1px solid #ccc;min-height:240px;min-width:320px}.mce-match-marker{background:#aaa;color:#fff}.mce-match-marker-selected{background:#39f;color:#fff}.mce-match-marker-selected::-moz-selection{background:#39f;color:#fff}.mce-match-marker-selected::selection{background:#39f;color:#fff}.mce-content-body audio[data-mce-selected],.mce-content-body embed[data-mce-selected],.mce-content-body img[data-mce-selected],.mce-content-body object[data-mce-selected],.mce-content-body table[data-mce-selected],.mce-content-body video[data-mce-selected]{outline:3px solid #b4d7ff}.mce-content-body hr[data-mce-selected]{outline:3px solid #b4d7ff;outline-offset:1px}.mce-content-body [contentEditable=false] [contentEditable=true]:focus{outline:3px solid #b4d7ff}.mce-content-body [contentEditable=false] [contentEditable=true]:hover{outline:3px solid #b4d7ff}.mce-content-body [contentEditable=false][data-mce-selected]{cursor:not-allowed;outline:3px solid #b4d7ff}.mce-content-body.mce-content-readonly [contentEditable=true]:focus,.mce-content-body.mce-content-readonly [contentEditable=true]:hover{outline:0}.mce-content-body [data-mce-selected=inline-boundary]{background-color:#b4d7ff}.mce-content-body .mce-edit-focus{outline:3px solid #b4d7ff}.mce-content-body td[data-mce-selected],.mce-content-body th[data-mce-selected]{position:relative}.mce-content-body td[data-mce-selected]::-moz-selection,.mce-content-body th[data-mce-selected]::-moz-selection{background:0 0}.mce-content-body td[data-mce-selected]::selection,.mce-content-body th[data-mce-selected]::selection{background:0 0}.mce-content-body td[data-mce-selected] *,.mce-content-body th[data-mce-selected] *{outline:0;-webkit-touch-callout:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.mce-content-body td[data-mce-selected]::after,.mce-content-body th[data-mce-selected]::after{background-color:rgba(180,215,255,.7);border:1px solid rgba(180,215,255,.7);bottom:-1px;content:'';left:-1px;mix-blend-mode:multiply;position:absolute;right:-1px;top:-1px}@media screen and (-ms-high-contrast:active),(-ms-high-contrast:none){.mce-content-body td[data-mce-selected]::after,.mce-content-body th[data-mce-selected]::after{border-color:rgba(0,84,180,.7)}}.mce-content-body img::-moz-selection{background:0 0}.mce-content-body img::selection{background:0 0}.ephox-snooker-resizer-bar{background-color:#b4d7ff;opacity:0;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.ephox-snooker-resizer-cols{cursor:col-resize}.ephox-snooker-resizer-rows{cursor:row-resize}.ephox-snooker-resizer-bar.ephox-snooker-resizer-bar-dragging{opacity:1}.mce-spellchecker-word{background-image:url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D'4'%20height%3D'4'%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%3E%3Cpath%20stroke%3D'%23ff0000'%20fill%3D'none'%20stroke-linecap%3D'round'%20stroke-opacity%3D'.75'%20d%3D'M0%203L2%201%204%203'%2F%3E%3C%2Fsvg%3E%0A");background-position:0 calc(100% + 1px);background-repeat:repeat-x;background-size:auto 6px;cursor:default;height:2rem}.mce-spellchecker-grammar{background-image:url("data:image/svg+xml;charset=UTF-8,%3Csvg%20width%3D'4'%20height%3D'4'%20xmlns%3D'http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg'%3E%3Cpath%20stroke%3D'%2300A835'%20fill%3D'none'%20stroke-linecap%3D'round'%20d%3D'M0%203L2%201%204%203'%2F%3E%3C%2Fsvg%3E%0A");background-position:0 calc(100% + 1px);background-repeat:repeat-x;background-size:auto 6px;cursor:default}.mce-toc{border:1px solid gray}.mce-toc h2{margin:4px}.mce-toc li{list-style-type:none}.mce-item-table:not([border]),.mce-item-table:not([border]) caption,.mce-item-table:not([border]) td,.mce-item-table:not([border]) th,.mce-item-table[border="0"],.mce-item-table[border="0"] caption,.mce-item-table[border="0"] td,.mce-item-table[border="0"] th,table[style*="border-width: 0px"],table[style*="border-width: 0px"] caption,table[style*="border-width: 0px"] td,table[style*="border-width: 0px"] th{border:1px dashed #bbb}.mce-visualblocks address,.mce-visualblocks article,.mce-visualblocks aside,.mce-visualblocks blockquote,.mce-visualblocks div:not([data-mce-bogus]),.mce-visualblocks dl,.mce-visualblocks figcaption,.mce-visualblocks figure,.mce-visualblocks h1,.mce-visualblocks h2,.mce-visualblocks h3,.mce-visualblocks h4,.mce-visualblocks h5,.mce-visualblocks h6,.mce-visualblocks hgroup,.mce-visualblocks ol,.mce-visualblocks p,.mce-visualblocks pre,.mce-visualblocks section,.mce-visualblocks ul{background-repeat:no-repeat;border:1px dashed #bbb;margin-left:3px;padding-top:10px}.mce-visualblocks p{background-image:url(data:image/gif;base64,R0lGODlhCQAJAJEAAAAAAP///7u7u////yH5BAEAAAMALAAAAAAJAAkAAAIQnG+CqCN/mlyvsRUpThG6AgA7)}.mce-visualblocks h1{background-image:url(data:image/gif;base64,R0lGODlhDQAKAIABALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybGu1JuxHoAfRNRW3TWXyF2YiRUAOw==)}.mce-visualblocks h2{background-image:url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8Hybbx4oOuqgTynJd6bGlWg3DkJzoaUAAAOw==)}.mce-visualblocks h3{background-image:url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIZjI8Hybbx4oOuqgTynJf2Ln2NOHpQpmhAAQA7)}.mce-visualblocks h4{background-image:url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8HybbxInR0zqeAdhtJlXwV1oCll2HaWgAAOw==)}.mce-visualblocks h5{background-image:url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8HybbxIoiuwjane4iq5GlW05GgIkIZUAAAOw==)}.mce-visualblocks h6{background-image:url(data:image/gif;base64,R0lGODlhDgAKAIABALu7u////yH5BAEAAAEALAAAAAAOAAoAAAIajI8HybbxIoiuwjan04jep1iZ1XRlAo5bVgAAOw==)}.mce-visualblocks div:not([data-mce-bogus]){background-image:url(data:image/gif;base64,R0lGODlhEgAKAIABALu7u////yH5BAEAAAEALAAAAAASAAoAAAIfjI9poI0cgDywrhuxfbrzDEbQM2Ei5aRjmoySW4pAAQA7)}.mce-visualblocks section{background-image:url(data:image/gif;base64,R0lGODlhKAAKAIABALu7u////yH5BAEAAAEALAAAAAAoAAoAAAI5jI+pywcNY3sBWHdNrplytD2ellDeSVbp+GmWqaDqDMepc8t17Y4vBsK5hDyJMcI6KkuYU+jpjLoKADs=)}.mce-visualblocks article{background-image:url(data:image/gif;base64,R0lGODlhKgAKAIABALu7u////yH5BAEAAAEALAAAAAAqAAoAAAI6jI+pywkNY3wG0GBvrsd2tXGYSGnfiF7ikpXemTpOiJScasYoDJJrjsG9gkCJ0ag6KhmaIe3pjDYBBQA7)}.mce-visualblocks blockquote{background-image:url(data:image/gif;base64,R0lGODlhPgAKAIABALu7u////yH5BAEAAAEALAAAAAA+AAoAAAJPjI+py+0Knpz0xQDyuUhvfoGgIX5iSKZYgq5uNL5q69asZ8s5rrf0yZmpNkJZzFesBTu8TOlDVAabUyatguVhWduud3EyiUk45xhTTgMBBQA7)}.mce-visualblocks address{background-image:url(data:image/gif;base64,R0lGODlhLQAKAIABALu7u////yH5BAEAAAEALAAAAAAtAAoAAAI/jI+pywwNozSP1gDyyZcjb3UaRpXkWaXmZW4OqKLhBmLs+K263DkJK7OJeifh7FicKD9A1/IpGdKkyFpNmCkAADs=)}.mce-visualblocks pre{background-image:url(data:image/gif;base64,R0lGODlhFQAKAIABALu7uwAAACH5BAEAAAEALAAAAAAVAAoAAAIjjI+ZoN0cgDwSmnpz1NCueYERhnibZVKLNnbOq8IvKpJtVQAAOw==)}.mce-visualblocks figure{background-image:url(data:image/gif;base64,R0lGODlhJAAKAIAAALu7u////yH5BAEAAAEALAAAAAAkAAoAAAI0jI+py+2fwAHUSFvD3RlvG4HIp4nX5JFSpnZUJ6LlrM52OE7uSWosBHScgkSZj7dDKnWAAgA7)}.mce-visualblocks figcaption{border:1px dashed #bbb}.mce-visualblocks hgroup{background-image:url(data:image/gif;base64,R0lGODlhJwAKAIABALu7uwAAACH5BAEAAAEALAAAAAAnAAoAAAI3jI+pywYNI3uB0gpsRtt5fFnfNZaVSYJil4Wo03Hv6Z62uOCgiXH1kZIIJ8NiIxRrAZNMZAtQAAA7)}.mce-visualblocks aside{background-image:url(data:image/gif;base64,R0lGODlhHgAKAIABAKqqqv///yH5BAEAAAEALAAAAAAeAAoAAAItjI+pG8APjZOTzgtqy7I3f1yehmQcFY4WKZbqByutmW4aHUd6vfcVbgudgpYCADs=)}.mce-visualblocks ul{background-image:url(data:image/gif;base64,R0lGODlhDQAKAIAAALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybGuYnqUVSjvw26DzzXiqIDlVwAAOw==)}.mce-visualblocks ol{background-image:url(data:image/gif;base64,R0lGODlhDQAKAIABALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybH6HHt0qourxC6CvzXieHyeWQAAOw==)}.mce-visualblocks dl{background-image:url(data:image/gif;base64,R0lGODlhDQAKAIABALu7u////yH5BAEAAAEALAAAAAANAAoAAAIXjI8GybEOnmOvUoWznTqeuEjNSCqeGRUAOw==)}.mce-visualblocks:not([dir=rtl]) address,.mce-visualblocks:not([dir=rtl]) article,.mce-visualblocks:not([dir=rtl]) aside,.mce-visualblocks:not([dir=rtl]) blockquote,.mce-visualblocks:not([dir=rtl]) div:not([data-mce-bogus]),.mce-visualblocks:not([dir=rtl]) dl,.mce-visualblocks:not([dir=rtl]) figcaption,.mce-visualblocks:not([dir=rtl]) figure,.mce-visualblocks:not([dir=rtl]) h1,.mce-visualblocks:not([dir=rtl]) h2,.mce-visualblocks:not([dir=rtl]) h3,.mce-visualblocks:not([dir=rtl]) h4,.mce-visualblocks:not([dir=rtl]) h5,.mce-visualblocks:not([dir=rtl]) h6,.mce-visualblocks:not([dir=rtl]) hgroup,.mce-visualblocks:not([dir=rtl]) ol,.mce-visualblocks:not([dir=rtl]) p,.mce-visualblocks:not([dir=rtl]) pre,.mce-visualblocks:not([dir=rtl]) section,.mce-visualblocks:not([dir=rtl]) ul{margin-left:3px}.mce-visualblocks[dir=rtl] address,.mce-visualblocks[dir=rtl] article,.mce-visualblocks[dir=rtl] aside,.mce-visualblocks[dir=rtl] blockquote,.mce-visualblocks[dir=rtl] div:not([data-mce-bogus]),.mce-visualblocks[dir=rtl] dl,.mce-visualblocks[dir=rtl] figcaption,.mce-visualblocks[dir=rtl] figure,.mce-visualblocks[dir=rtl] h1,.mce-visualblocks[dir=rtl] h2,.mce-visualblocks[dir=rtl] h3,.mce-visualblocks[dir=rtl] h4,.mce-visualblocks[dir=rtl] h5,.mce-visualblocks[dir=rtl] h6,.mce-visualblocks[dir=rtl] hgroup,.mce-visualblocks[dir=rtl] ol,.mce-visualblocks[dir=rtl] p,.mce-visualblocks[dir=rtl] pre,.mce-visualblocks[dir=rtl] section,.mce-visualblocks[dir=rtl] ul{background-position-x:right;margin-right:3px}.mce-nbsp,.mce-shy{background:#aaa}.mce-shy::after{content:'-'}body{font-family:sans-serif}table{border-collapse:collapse} diff --git a/frontend/public/tinymce-dataease-private/skins/ui/oxide/content.mobile.css b/frontend/public/tinymce-dataease-private/skins/ui/oxide/content.mobile.css new file mode 100644 index 0000000..68f5f0f --- /dev/null +++ b/frontend/public/tinymce-dataease-private/skins/ui/oxide/content.mobile.css @@ -0,0 +1,34 @@ +/** + * Copyright (c) Tiny Technologies, Inc. All rights reserved. + * Licensed under the LGPL or a commercial license. + * For LGPL see License.txt in the project root for license information. + * For commercial licenses see https://www.tiny.cloud/ + */ +.tinymce-mobile-unfocused-selections .tinymce-mobile-unfocused-selection { + /* Note: this file is used inside the content, so isn't part of theming */ + background-color: green; + display: inline-block; + opacity: 0.5; + position: absolute; +} + +body { + -webkit-text-size-adjust: none; +} + +body img { + /* this is related to the content margin */ + max-width: 96vw; +} + +body table img { + max-width: 95%; +} + +body { + font-family: sans-serif; +} + +table { + border-collapse: collapse; +} diff --git a/frontend/public/tinymce-dataease-private/skins/ui/oxide/content.mobile.min.css b/frontend/public/tinymce-dataease-private/skins/ui/oxide/content.mobile.min.css new file mode 100644 index 0000000..35f7dc0 --- /dev/null +++ b/frontend/public/tinymce-dataease-private/skins/ui/oxide/content.mobile.min.css @@ -0,0 +1,7 @@ +/** + * Copyright (c) Tiny Technologies, Inc. All rights reserved. + * Licensed under the LGPL or a commercial license. + * For LGPL see License.txt in the project root for license information. + * For commercial licenses see https://www.tiny.cloud/ + */ +.tinymce-mobile-unfocused-selections .tinymce-mobile-unfocused-selection{background-color:green;display:inline-block;opacity:.5;position:absolute}body{-webkit-text-size-adjust:none}body img{max-width:96vw}body table img{max-width:95%}body{font-family:sans-serif}table{border-collapse:collapse} diff --git a/frontend/public/tinymce-dataease-private/skins/ui/oxide/fonts/tinymce-mobile.woff b/frontend/public/tinymce-dataease-private/skins/ui/oxide/fonts/tinymce-mobile.woff new file mode 100644 index 0000000000000000000000000000000000000000..1e3be038a607cb7c2544ed8ae3d6621f77bf4c38 GIT binary patch literal 4624 zcmb7IeQaFC5#QN&AGUL{efE7g{=BM1W-|RaVdWQe^e?BC`eGz4^i8S3PQw?Hhd_eQHxTkckXZB zdzU((wCVGko!Qyh+1c6InRotvZ%+>+hNrBQtrFOI4t*}DZ$7=>Sr=uD3c$ZlKuKBQ z8~ervCczs9SOk2!>AAqrz+v$CC}f1JfYPDSqx->|V$6{ekbe8M#Bh3Gkg?)-Fdi3B zeB$}UFqn*$pv&q7*net~hsUOlfG7Ho2zaowY%JPRytMvu{&xRPm(h_~w##F>vqE&a5-ssH##mlfAk}44^ zXRJKd!Ifw&ce{$Y9BAg5c>e>p_Z;t!=P{izddGWie?aHLdKL3Cn9rG=d2vt;esWqH zoD}uAoi3Z~4+LABvADt+so4~t%VlyIJ{O3tm$NC+(!yenQD%NVr*btG$T3+_WX=LH z#1M2ZNEtrO+-x;l2i>M^5o%GQ@s?N+gw*19H@G~vl3Q5Zf*t6jjW0GOTmAmlWYgSS zJeiEo%~LA-FW|YAd_Em$OE#@dw)y*#@p!UtnWa);V1HY3ZBw!>(3gY{iFFa_c6iW9 zIQ@xck^{xu9_o;UyQH#ba@y?L$xW?8J35?$p1z46ZjIctZ8QCKCa29bMC1-t@pT>S zTUT1WMjQz-75d)5zJxv~@Yd)bY)ejQBx_XQiaMJ z>$5`NO3?L*ND{UQeF8%xl)$_>w9tmQpfEebzedazFeh#~d}suN+vzsqLiW~@TLhoe zk1%xEcxP2ZL)FuoXeYzb-J5goljDxPL2@@#RW)d&X#&6QO5U=04_628@ONSvtgpha zDqqmoVep`A4<+PK$V>K+T}}{8Rj+Q|UAzCtl!Fh)uXJg{x$}HMJH7LcBLzj-r{h;< zzote8Id%pcAyE;87D<8glyaFeq#k)OEDB%yA ze%CeZ!?4TEs#pj+%14DBZHn8jxaF2as6}p3+!6p-&@I>5lbP3&N$svcIF-`0R5(o2 zh7la++|;-euckH44a4BAwB++#-cZ z)kFyC=eUS-4D0t}H8LdZY!JD^sW@F85io)%=8HU)ouhEeo-K_dJ3BV+8fo0JXIjlP zZt0H`0=Yv~I|PpRZ)r5_iAYmY9V=wT@BsoN9<3vftB|}TOH;|yNk_e7(2-?y{&cSK zG=E5Nz^Ko4>KxcbY!Q13!=HBS$lM96_+0y3M1yWTAt2u5C;6MWMXbRN?RI{$eHnAx z&t=-PSjZ>Qe2V2-YGs1YWemAq zVHdG{9V$QvsY~Cgq-L*PZqMPGv|px$)K~3<%+fBtG{oIRPL_7ye$-(`C=tS)^xC}% zue73qiF&{nXJ*>-@668G!`IrAeB;ad09shzt{O?7omLE_X@H|#ozGt&64 zb-&_lLkZI8TzigPZvUr=4g2-8M6M8b9EQLgoPswYg)d)j&%gZHJO!2>(?;I*8d>aG z#oS295Kcq{uD4R2@VEG($}WWiF-6YK)kjqks%o_U{CIAVX2;tX7o|unkew5?Gn3(| zOePS^{$(;Xi4ph;`KO#;k+vaLt8n5@doi+OEvH&?*+3(WgqkT9-$b0fTHm;)r=NmR zJnJ9o>UvNR(JMoIdRBf{%kd}jmZ)b)#4>dnDfq0G(?~S%d zv50QeMR$Kzd*S$AEXdp5Fhqe0Pz zZ!oS2e!i-tWEJ2^YoVo}V7S0tV7CujimbVJtVNb#yB&<-f&xpSb@m2=wBZ|qU-_^; z?C{lk+;tlxk&Sh3Pwh(D7~kNh`O=~TMWuRUu^0=9)`CYEVwhvGWUt4Wd3`6*H)Zs>LLYQcC#*~B78EfTt7RQ*l)b{v zqntLNsC`h&zZCY{x*}gfPU4at;nfileU3>zeyLdO7;;lFIft~ zsm6#wb5Jjtv;_VxleU0<%cQON-O*ywHt`@C4fn-Y83}=|hJPOpN>1H%C#7)9etg_yG)$ div { + padding-bottom: 4px; +} + +.tox .accessibility-issue__description > div > div { + align-items: center; + display: flex; + margin-bottom: 4px; +} + +.tox .accessibility-issue__description > *:last-child:not(:only-child) { + border-color: #cccccc; + border-style: solid; +} + +.tox .accessibility-issue__repair { + margin-top: 16px; +} + +.tox .tox-dialog__body-content .accessibility-issue--info .accessibility-issue__description { + background-color: rgba(32, 122, 183, 0.1); + border-color: rgba(32, 122, 183, 0.4); + color: #222f3e; +} + +.tox .tox-dialog__body-content .accessibility-issue--info .accessibility-issue__description > *:last-child { + border-color: rgba(32, 122, 183, 0.4); +} + +.tox .tox-dialog__body-content .accessibility-issue--info .tox-form__group h2 { + color: #207ab7; +} + +.tox .tox-dialog__body-content .accessibility-issue--info .tox-icon svg { + fill: #207ab7; +} + +.tox .tox-dialog__body-content .accessibility-issue--info a .tox-icon { + color: #207ab7; +} + +.tox .tox-dialog__body-content .accessibility-issue--warn .accessibility-issue__description { + background-color: rgba(255, 165, 0, 0.1); + border-color: rgba(255, 165, 0, 0.5); + color: #222f3e; +} + +.tox .tox-dialog__body-content .accessibility-issue--warn .accessibility-issue__description > *:last-child { + border-color: rgba(255, 165, 0, 0.5); +} + +.tox .tox-dialog__body-content .accessibility-issue--warn .tox-form__group h2 { + color: #cc8500; +} + +.tox .tox-dialog__body-content .accessibility-issue--warn .tox-icon svg { + fill: #cc8500; +} + +.tox .tox-dialog__body-content .accessibility-issue--warn a .tox-icon { + color: #cc8500; +} + +.tox .tox-dialog__body-content .accessibility-issue--error .accessibility-issue__description { + background-color: rgba(204, 0, 0, 0.1); + border-color: rgba(204, 0, 0, 0.4); + color: #222f3e; +} + +.tox .tox-dialog__body-content .accessibility-issue--error .accessibility-issue__description > *:last-child { + border-color: rgba(204, 0, 0, 0.4); +} + +.tox .tox-dialog__body-content .accessibility-issue--error .tox-form__group h2 { + color: #c00; +} + +.tox .tox-dialog__body-content .accessibility-issue--error .tox-icon svg { + fill: #c00; +} + +.tox .tox-dialog__body-content .accessibility-issue--error a .tox-icon { + color: #c00; +} + +.tox .tox-dialog__body-content .accessibility-issue--success .accessibility-issue__description { + background-color: rgba(120, 171, 70, 0.1); + border-color: rgba(120, 171, 70, 0.4); + color: #222f3e; +} + +.tox .tox-dialog__body-content .accessibility-issue--success .accessibility-issue__description > *:last-child { + border-color: rgba(120, 171, 70, 0.4); +} + +.tox .tox-dialog__body-content .accessibility-issue--success .tox-form__group h2 { + color: #78AB46; +} + +.tox .tox-dialog__body-content .accessibility-issue--success .tox-icon svg { + fill: #78AB46; +} + +.tox .tox-dialog__body-content .accessibility-issue--success a .tox-icon { + color: #78AB46; +} + +.tox .tox-dialog__body-content .accessibility-issue__header h1, +.tox .tox-dialog__body-content .tox-form__group .accessibility-issue__description h2 { + margin-top: 0; +} + +.tox:not([dir=rtl]) .tox-dialog__body-content .accessibility-issue__header .tox-button { + margin-left: 4px; +} + +.tox:not([dir=rtl]) .tox-dialog__body-content .accessibility-issue__header > *:nth-last-child(2) { + margin-left: auto; +} + +.tox:not([dir=rtl]) .tox-dialog__body-content .accessibility-issue__description { + padding: 4px 4px 4px 8px; +} + +.tox:not([dir=rtl]) .tox-dialog__body-content .accessibility-issue__description > *:last-child { + border-left-width: 1px; + padding-left: 4px; +} + +.tox[dir=rtl] .tox-dialog__body-content .accessibility-issue__header .tox-button { + margin-right: 4px; +} + +.tox[dir=rtl] .tox-dialog__body-content .accessibility-issue__header > *:nth-last-child(2) { + margin-right: auto; +} + +.tox[dir=rtl] .tox-dialog__body-content .accessibility-issue__description { + padding: 4px 8px 4px 4px; +} + +.tox[dir=rtl] .tox-dialog__body-content .accessibility-issue__description > *:last-child { + border-right-width: 1px; + padding-right: 4px; +} + +.tox .tox-anchorbar { + display: flex; + flex: 0 0 auto; +} + +.tox .tox-bar { + display: flex; + flex: 0 0 auto; +} + +.tox .tox-button { + background-color: #207ab7; + background-image: none; + background-position: 0 0; + background-repeat: repeat; + border-color: #207ab7; + border-radius: 3px; + border-style: solid; + border-width: 1px; + box-shadow: none; + box-sizing: border-box; + color: #fff; + cursor: pointer; + display: inline-block; + font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif; + font-size: 14px; + font-style: normal; + font-weight: bold; + letter-spacing: normal; + line-height: 24px; + margin: 0; + outline: none; + padding: 4px 16px; + text-align: center; + text-decoration: none; + text-transform: none; + white-space: nowrap; +} + +.tox .tox-button[disabled] { + background-color: #207ab7; + background-image: none; + border-color: #207ab7; + box-shadow: none; + color: rgba(255, 255, 255, 0.5); + cursor: not-allowed; +} + +.tox .tox-button:focus:not(:disabled) { + background-color: #1c6ca1; + background-image: none; + border-color: #1c6ca1; + box-shadow: none; + color: #fff; +} + +.tox .tox-button:hover:not(:disabled) { + background-color: #1c6ca1; + background-image: none; + border-color: #1c6ca1; + box-shadow: none; + color: #fff; +} + +.tox .tox-button:active:not(:disabled) { + background-color: #185d8c; + background-image: none; + border-color: #185d8c; + box-shadow: none; + color: #fff; +} + +.tox .tox-button--secondary { + background-color: #f0f0f0; + background-image: none; + background-position: 0 0; + background-repeat: repeat; + border-color: #f0f0f0; + border-radius: 3px; + border-style: solid; + border-width: 1px; + box-shadow: none; + color: #222f3e; + font-size: 14px; + font-style: normal; + font-weight: bold; + letter-spacing: normal; + outline: none; + padding: 4px 16px; + text-decoration: none; + text-transform: none; +} + +.tox .tox-button--secondary[disabled] { + background-color: #f0f0f0; + background-image: none; + border-color: #f0f0f0; + box-shadow: none; + color: rgba(34, 47, 62, 0.5); +} + +.tox .tox-button--secondary:focus:not(:disabled) { + background-color: #e3e3e3; + background-image: none; + border-color: #e3e3e3; + box-shadow: none; + color: #222f3e; +} + +.tox .tox-button--secondary:hover:not(:disabled) { + background-color: #e3e3e3; + background-image: none; + border-color: #e3e3e3; + box-shadow: none; + color: #222f3e; +} + +.tox .tox-button--secondary:active:not(:disabled) { + background-color: #d6d6d6; + background-image: none; + border-color: #d6d6d6; + box-shadow: none; + color: #222f3e; +} + +.tox .tox-button--icon, +.tox .tox-button.tox-button--icon, +.tox .tox-button.tox-button--secondary.tox-button--icon { + padding: 4px; +} + +.tox .tox-button--icon .tox-icon svg, +.tox .tox-button.tox-button--icon .tox-icon svg, +.tox .tox-button.tox-button--secondary.tox-button--icon .tox-icon svg { + display: block; + fill: currentColor; +} + +.tox .tox-button-link { + background: 0; + border: none; + box-sizing: border-box; + cursor: pointer; + display: inline-block; + font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif; + font-size: 16px; + font-weight: normal; + line-height: 1.3; + margin: 0; + padding: 0; + white-space: nowrap; +} + +.tox .tox-button-link--sm { + font-size: 14px; +} + +.tox .tox-button--naked { + background-color: transparent; + border-color: transparent; + box-shadow: unset; + color: #222f3e; +} + +.tox .tox-button--naked[disabled] { + background-color: #f0f0f0; + border-color: #f0f0f0; + box-shadow: none; + color: rgba(34, 47, 62, 0.5); +} + +.tox .tox-button--naked:hover:not(:disabled) { + background-color: #e3e3e3; + border-color: #e3e3e3; + box-shadow: none; + color: #222f3e; +} + +.tox .tox-button--naked:focus:not(:disabled) { + background-color: #e3e3e3; + border-color: #e3e3e3; + box-shadow: none; + color: #222f3e; +} + +.tox .tox-button--naked:active:not(:disabled) { + background-color: #d6d6d6; + border-color: #d6d6d6; + box-shadow: none; + color: #222f3e; +} + +.tox .tox-button--naked .tox-icon svg { + fill: currentColor; +} + +.tox .tox-button--naked.tox-button--icon:hover:not(:disabled) { + color: #222f3e; +} + +.tox .tox-checkbox { + align-items: center; + border-radius: 3px; + cursor: pointer; + display: flex; + height: 36px; + min-width: 36px; +} + +.tox .tox-checkbox__input { + /* Hide from view but visible to screen readers */ + height: 1px; + overflow: hidden; + position: absolute; + top: auto; + width: 1px; +} + +.tox .tox-checkbox__icons { + align-items: center; + border-radius: 3px; + box-shadow: 0 0 0 2px transparent; + box-sizing: content-box; + display: flex; + height: 24px; + justify-content: center; + padding: calc(4px - 1px); + width: 24px; +} + +.tox .tox-checkbox__icons .tox-checkbox-icon__unchecked svg { + display: block; + fill: rgba(34, 47, 62, 0.3); +} + +.tox .tox-checkbox__icons .tox-checkbox-icon__indeterminate svg { + display: none; + fill: #207ab7; +} + +.tox .tox-checkbox__icons .tox-checkbox-icon__checked svg { + display: none; + fill: #207ab7; +} + +.tox .tox-checkbox--disabled { + color: rgba(34, 47, 62, 0.5); + cursor: not-allowed; +} + +.tox .tox-checkbox--disabled .tox-checkbox__icons .tox-checkbox-icon__checked svg { + fill: rgba(34, 47, 62, 0.5); +} + +.tox .tox-checkbox--disabled .tox-checkbox__icons .tox-checkbox-icon__unchecked svg { + fill: rgba(34, 47, 62, 0.5); +} + +.tox .tox-checkbox--disabled .tox-checkbox__icons .tox-checkbox-icon__indeterminate svg { + fill: rgba(34, 47, 62, 0.5); +} + +.tox input.tox-checkbox__input:checked + .tox-checkbox__icons .tox-checkbox-icon__unchecked svg { + display: none; +} + +.tox input.tox-checkbox__input:checked + .tox-checkbox__icons .tox-checkbox-icon__checked svg { + display: block; +} + +.tox input.tox-checkbox__input:indeterminate + .tox-checkbox__icons .tox-checkbox-icon__unchecked svg { + display: none; +} + +.tox input.tox-checkbox__input:indeterminate + .tox-checkbox__icons .tox-checkbox-icon__indeterminate svg { + display: block; +} + +.tox input.tox-checkbox__input:focus + .tox-checkbox__icons { + border-radius: 3px; + box-shadow: inset 0 0 0 1px #207ab7; + padding: calc(4px - 1px); +} + +.tox:not([dir=rtl]) .tox-checkbox__label { + margin-left: 4px; +} + +.tox:not([dir=rtl]) .tox-checkbox__input { + left: -10000px; +} + +.tox:not([dir=rtl]) .tox-bar .tox-checkbox { + margin-left: 4px; +} + +.tox[dir=rtl] .tox-checkbox__label { + margin-right: 4px; +} + +.tox[dir=rtl] .tox-checkbox__input { + right: -10000px; +} + +.tox[dir=rtl] .tox-bar .tox-checkbox { + margin-right: 4px; +} + +.tox { + /* stylelint-disable-next-line no-descending-specificity */ +} + +.tox .tox-collection--toolbar .tox-collection__group { + display: flex; + padding: 0; +} + +.tox .tox-collection--grid .tox-collection__group { + display: flex; + flex-wrap: wrap; + max-height: 208px; + overflow-x: hidden; + overflow-y: auto; + padding: 0; +} + +.tox .tox-collection--list .tox-collection__group { + border-bottom-width: 0; + border-color: #cccccc; + border-left-width: 0; + border-right-width: 0; + border-style: solid; + border-top-width: 1px; + padding: 4px 0; +} + +.tox .tox-collection--list .tox-collection__group:first-child { + border-top-width: 0; +} + +.tox .tox-collection__group-heading { + background-color: #e6e6e6; + color: rgba(34, 47, 62, 0.7); + cursor: default; + font-size: 12px; + font-style: normal; + font-weight: normal; + margin-bottom: 4px; + margin-top: -4px; + padding: 4px 8px; + text-transform: none; + -webkit-touch-callout: none; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} + +.tox .tox-collection__item { + align-items: center; + color: #222f3e; + cursor: pointer; + display: flex; + -webkit-touch-callout: none; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} + +.tox .tox-collection--list .tox-collection__item { + padding: 4px 8px; +} + +.tox .tox-collection--toolbar .tox-collection__item { + border-radius: 3px; + padding: 4px; +} + +.tox .tox-collection--grid .tox-collection__item { + border-radius: 3px; + padding: 4px; +} + +.tox .tox-collection--list .tox-collection__item--enabled { + background-color: #fff; + color: #222f3e; +} + +.tox .tox-collection--list .tox-collection__item--active { + background-color: #dee0e2; +} + +.tox .tox-collection--toolbar .tox-collection__item--enabled { + background-color: #c8cbcf; + color: #222f3e; +} + +.tox .tox-collection--toolbar .tox-collection__item--active { + background-color: #dee0e2; +} + +.tox .tox-collection--grid .tox-collection__item--enabled { + background-color: #c8cbcf; + color: #222f3e; +} + +.tox .tox-collection--grid .tox-collection__item--active:not(.tox-collection__item--state-disabled) { + background-color: #dee0e2; + color: #222f3e; +} + +.tox .tox-collection--list .tox-collection__item--active:not(.tox-collection__item--state-disabled) { + color: #222f3e; +} + +.tox .tox-collection--toolbar .tox-collection__item--active:not(.tox-collection__item--state-disabled) { + color: #222f3e; +} + +.tox .tox-collection__item--state-disabled { + background-color: transparent; + color: rgba(34, 47, 62, 0.5); + cursor: not-allowed; +} + +.tox .tox-collection__item-icon, +.tox .tox-collection__item-checkmark { + align-items: center; + display: flex; + height: 24px; + justify-content: center; + width: 24px; +} + +.tox .tox-collection__item-icon svg, +.tox .tox-collection__item-checkmark svg { + fill: currentColor; +} + +.tox .tox-collection--toolbar-lg .tox-collection__item-icon { + height: 48px; + width: 48px; +} + +.tox .tox-collection__item-label { + color: currentColor; + display: inline-block; + flex: 1; + -ms-flex-preferred-size: auto; + font-size: 14px; + font-style: normal; + font-weight: normal; + line-height: 24px; + text-transform: none; + word-break: break-all; +} + +.tox .tox-collection__item-accessory { + color: rgba(34, 47, 62, 0.7); + display: inline-block; + font-size: 14px; + height: 24px; + line-height: 24px; + text-transform: none; +} + +.tox .tox-collection__item-caret { + align-items: center; + display: flex; + min-height: 24px; +} + +.tox .tox-collection__item-caret::after { + content: ''; + font-size: 0; + min-height: inherit; +} + +.tox .tox-collection__item-caret svg { + fill: #222f3e; +} + +.tox .tox-collection--list .tox-collection__item:not(.tox-collection__item--enabled) .tox-collection__item-checkmark svg { + display: none; +} + +.tox .tox-collection--list .tox-collection__item:not(.tox-collection__item--enabled) .tox-collection__item-accessory + .tox-collection__item-checkmark { + display: none; +} + +.tox .tox-collection--horizontal { + background-color: #fff; + border: 1px solid #cccccc; + border-radius: 3px; + box-shadow: 0 1px 3px rgba(0, 0, 0, 0.15); + display: flex; + flex: 0 0 auto; + flex-shrink: 0; + flex-wrap: nowrap; + margin-bottom: 0; + overflow-x: auto; + padding: 0; +} + +.tox .tox-collection--horizontal .tox-collection__group { + align-items: center; + display: flex; + flex-wrap: nowrap; + margin: 0; + padding: 0 4px; +} + +.tox .tox-collection--horizontal .tox-collection__item { + height: 34px; + margin: 2px 0 3px 0; + padding: 0 4px; +} + +.tox .tox-collection--horizontal .tox-collection__item-label { + white-space: nowrap; +} + +.tox .tox-collection--horizontal .tox-collection__item-caret { + margin-left: 4px; +} + +.tox .tox-collection__item-container { + display: flex; +} + +.tox .tox-collection__item-container--row { + align-items: center; + flex: 1 1 auto; + flex-direction: row; +} + +.tox .tox-collection__item-container--row.tox-collection__item-container--align-left { + margin-right: auto; +} + +.tox .tox-collection__item-container--row.tox-collection__item-container--align-right { + justify-content: flex-end; + margin-left: auto; +} + +.tox .tox-collection__item-container--row.tox-collection__item-container--valign-top { + align-items: flex-start; + margin-bottom: auto; +} + +.tox .tox-collection__item-container--row.tox-collection__item-container--valign-middle { + align-items: center; +} + +.tox .tox-collection__item-container--row.tox-collection__item-container--valign-bottom { + align-items: flex-end; + margin-top: auto; +} + +.tox .tox-collection__item-container--column { + -ms-grid-row-align: center; + align-self: center; + flex: 1 1 auto; + flex-direction: column; +} + +.tox .tox-collection__item-container--column.tox-collection__item-container--align-left { + align-items: flex-start; +} + +.tox .tox-collection__item-container--column.tox-collection__item-container--align-right { + align-items: flex-end; +} + +.tox .tox-collection__item-container--column.tox-collection__item-container--valign-top { + align-self: flex-start; +} + +.tox .tox-collection__item-container--column.tox-collection__item-container--valign-middle { + -ms-grid-row-align: center; + align-self: center; +} + +.tox .tox-collection__item-container--column.tox-collection__item-container--valign-bottom { + align-self: flex-end; +} + +.tox:not([dir=rtl]) .tox-collection--horizontal .tox-collection__group:not(:last-of-type) { + border-right: 1px solid #cccccc; +} + +.tox:not([dir=rtl]) .tox-collection--list .tox-collection__item > *:not(:first-child) { + margin-left: 8px; +} + +.tox:not([dir=rtl]) .tox-collection--list .tox-collection__item > .tox-collection__item-label:first-child { + margin-left: 4px; +} + +.tox:not([dir=rtl]) .tox-collection__item-accessory { + margin-left: 16px; + text-align: right; +} + +.tox:not([dir=rtl]) .tox-collection .tox-collection__item-caret { + margin-left: 16px; +} + +.tox[dir=rtl] .tox-collection--horizontal .tox-collection__group:not(:last-of-type) { + border-left: 1px solid #cccccc; +} + +.tox[dir=rtl] .tox-collection--list .tox-collection__item > *:not(:first-child) { + margin-right: 8px; +} + +.tox[dir=rtl] .tox-collection--list .tox-collection__item > .tox-collection__item-label:first-child { + margin-right: 4px; +} + +.tox[dir=rtl] .tox-collection__item-icon-rtl { + /* stylelint-disable-next-line no-descending-specificity */ +} + +.tox[dir=rtl] .tox-collection__item-icon-rtl .tox-collection__item-icon svg { + transform: rotateY(180deg); +} + +.tox[dir=rtl] .tox-collection__item-accessory { + margin-right: 16px; + text-align: left; +} + +.tox[dir=rtl] .tox-collection .tox-collection__item-caret { + margin-right: 16px; + transform: rotateY(180deg); +} + +.tox[dir=rtl] .tox-collection--horizontal .tox-collection__item-caret { + margin-right: 4px; +} + +.tox .tox-color-picker-container { + display: flex; + flex-direction: row; + height: 225px; + margin: 0; +} + +.tox .tox-sv-palette { + box-sizing: border-box; + display: flex; + height: 100%; +} + +.tox .tox-sv-palette-spectrum { + height: 100%; +} + +.tox .tox-sv-palette, +.tox .tox-sv-palette-spectrum { + width: 225px; +} + +.tox .tox-sv-palette-thumb { + background: none; + border: 1px solid black; + border-radius: 50%; + box-sizing: content-box; + height: 12px; + position: absolute; + width: 12px; +} + +.tox .tox-sv-palette-inner-thumb { + border: 1px solid white; + border-radius: 50%; + height: 10px; + position: absolute; + width: 10px; +} + +.tox .tox-hue-slider { + box-sizing: border-box; + height: 100%; + width: 25px; +} + +.tox .tox-hue-slider-spectrum { + background: linear-gradient(to bottom, #f00, #ff0080, #f0f, #8000ff, #00f, #0080ff, #0ff, #00ff80, #0f0, #80ff00, #ff0, #ff8000, #f00); + height: 100%; + width: 100%; +} + +.tox .tox-hue-slider, +.tox .tox-hue-slider-spectrum { + width: 20px; +} + +.tox .tox-hue-slider-thumb { + background: white; + border: 1px solid black; + box-sizing: content-box; + height: 4px; + width: 100%; +} + +.tox .tox-rgb-form { + display: flex; + flex-direction: column; + justify-content: space-between; +} + +.tox .tox-rgb-form div { + align-items: center; + display: flex; + justify-content: space-between; + margin-bottom: 5px; + width: inherit; +} + +.tox .tox-rgb-form input { + width: 6em; +} + +.tox .tox-rgb-form input.tox-invalid { + /* Need !important to override Chrome's focus styling unfortunately */ + border: 1px solid red !important; +} + +.tox .tox-rgb-form .tox-rgba-preview { + border: 1px solid black; + flex-grow: 2; + margin-bottom: 0; +} + +.tox:not([dir=rtl]) .tox-sv-palette { + margin-right: 15px; +} + +.tox:not([dir=rtl]) .tox-hue-slider { + margin-right: 15px; +} + +.tox:not([dir=rtl]) .tox-hue-slider-thumb { + margin-left: -1px; +} + +.tox:not([dir=rtl]) .tox-rgb-form label { + margin-right: 0.5em; +} + +.tox[dir=rtl] .tox-sv-palette { + margin-left: 15px; +} + +.tox[dir=rtl] .tox-hue-slider { + margin-left: 15px; +} + +.tox[dir=rtl] .tox-hue-slider-thumb { + margin-right: -1px; +} + +.tox[dir=rtl] .tox-rgb-form label { + margin-left: 0.5em; +} + +.tox .tox-toolbar .tox-swatches, +.tox .tox-toolbar__primary .tox-swatches, +.tox .tox-toolbar__overflow .tox-swatches { + margin: 2px 0 3px 4px; +} + +.tox .tox-collection--list .tox-collection__group .tox-swatches-menu { + border: 0; + margin: -4px 0; +} + +.tox .tox-swatches__row { + display: flex; +} + +.tox .tox-swatch { + height: 30px; + transition: transform 0.15s, box-shadow 0.15s; + width: 30px; +} + +.tox .tox-swatch:hover, +.tox .tox-swatch:focus { + box-shadow: 0 0 0 1px rgba(127, 127, 127, 0.3) inset; + transform: scale(0.8); +} + +.tox .tox-swatch--remove { + align-items: center; + display: flex; + justify-content: center; +} + +.tox .tox-swatch--remove svg path { + stroke: #e74c3c; +} + +.tox .tox-swatches__picker-btn { + align-items: center; + background-color: transparent; + border: 0; + cursor: pointer; + display: flex; + height: 30px; + justify-content: center; + outline: none; + padding: 0; + width: 30px; +} + +.tox .tox-swatches__picker-btn svg { + height: 24px; + width: 24px; +} + +.tox .tox-swatches__picker-btn:hover { + background: #dee0e2; +} + +.tox:not([dir=rtl]) .tox-swatches__picker-btn { + margin-left: auto; +} + +.tox[dir=rtl] .tox-swatches__picker-btn { + margin-right: auto; +} + +.tox .tox-comment-thread { + background: #fff; + position: relative; +} + +.tox .tox-comment-thread > *:not(:first-child) { + margin-top: 8px; +} + +.tox .tox-comment { + background: #fff; + border: 1px solid #cccccc; + border-radius: 3px; + box-shadow: 0 4px 8px 0 rgba(34, 47, 62, 0.1); + padding: 8px 8px 16px 8px; + position: relative; +} + +.tox .tox-comment__header { + align-items: center; + color: #222f3e; + display: flex; + justify-content: space-between; +} + +.tox .tox-comment__date { + color: rgba(34, 47, 62, 0.7); + font-size: 12px; +} + +.tox .tox-comment__body { + color: #222f3e; + font-size: 14px; + font-style: normal; + font-weight: normal; + line-height: 1.3; + margin-top: 8px; + position: relative; + text-transform: initial; +} + +.tox .tox-comment__body textarea { + resize: none; + white-space: normal; + width: 100%; +} + +.tox .tox-comment__expander { + padding-top: 8px; +} + +.tox .tox-comment__expander p { + color: rgba(34, 47, 62, 0.7); + font-size: 14px; + font-style: normal; +} + +.tox .tox-comment__body p { + margin: 0; +} + +.tox .tox-comment__buttonspacing { + padding-top: 16px; + text-align: center; +} + +.tox .tox-comment-thread__overlay::after { + background: #fff; + bottom: 0; + content: ""; + display: flex; + left: 0; + opacity: 0.9; + position: absolute; + right: 0; + top: 0; + z-index: 5; +} + +.tox .tox-comment__reply { + display: flex; + flex-shrink: 0; + flex-wrap: wrap; + justify-content: flex-end; + margin-top: 8px; +} + +.tox .tox-comment__reply > *:first-child { + margin-bottom: 8px; + width: 100%; +} + +.tox .tox-comment__edit { + display: flex; + flex-wrap: wrap; + justify-content: flex-end; + margin-top: 16px; +} + +.tox .tox-comment__gradient::after { + background: linear-gradient(rgba(255, 255, 255, 0), #fff); + bottom: 0; + content: ""; + display: block; + height: 5em; + margin-top: -40px; + position: absolute; + width: 100%; +} + +.tox .tox-comment__overlay { + background: #fff; + bottom: 0; + display: flex; + flex-direction: column; + flex-grow: 1; + left: 0; + opacity: 0.9; + position: absolute; + right: 0; + text-align: center; + top: 0; + z-index: 5; +} + +.tox .tox-comment__loading-text { + align-items: center; + color: #222f3e; + display: flex; + flex-direction: column; + position: relative; +} + +.tox .tox-comment__loading-text > div { + padding-bottom: 16px; +} + +.tox .tox-comment__overlaytext { + bottom: 0; + flex-direction: column; + font-size: 14px; + left: 0; + padding: 1em; + position: absolute; + right: 0; + top: 0; + z-index: 10; +} + +.tox .tox-comment__overlaytext p { + background-color: #fff; + box-shadow: 0 0 8px 8px #fff; + color: #222f3e; + text-align: center; +} + +.tox .tox-comment__overlaytext div:nth-of-type(2) { + font-size: 0.8em; +} + +.tox .tox-comment__busy-spinner { + align-items: center; + background-color: #fff; + bottom: 0; + display: flex; + justify-content: center; + left: 0; + position: absolute; + right: 0; + top: 0; + z-index: 20; +} + +.tox .tox-comment__scroll { + display: flex; + flex-direction: column; + flex-shrink: 1; + overflow: auto; +} + +.tox .tox-conversations { + margin: 8px; +} + +.tox:not([dir=rtl]) .tox-comment__edit { + margin-left: 8px; +} + +.tox:not([dir=rtl]) .tox-comment__buttonspacing > *:last-child, +.tox:not([dir=rtl]) .tox-comment__edit > *:last-child, +.tox:not([dir=rtl]) .tox-comment__reply > *:last-child { + margin-left: 8px; +} + +.tox[dir=rtl] .tox-comment__edit { + margin-right: 8px; +} + +.tox[dir=rtl] .tox-comment__buttonspacing > *:last-child, +.tox[dir=rtl] .tox-comment__edit > *:last-child, +.tox[dir=rtl] .tox-comment__reply > *:last-child { + margin-right: 8px; +} + +.tox .tox-user { + align-items: center; + display: flex; +} + +.tox .tox-user__avatar svg { + fill: rgba(34, 47, 62, 0.7); +} + +.tox .tox-user__name { + color: rgba(34, 47, 62, 0.7); + font-size: 12px; + font-style: normal; + font-weight: bold; + text-transform: uppercase; +} + +.tox:not([dir=rtl]) .tox-user__avatar svg { + margin-right: 8px; +} + +.tox:not([dir=rtl]) .tox-user__avatar + .tox-user__name { + margin-left: 8px; +} + +.tox[dir=rtl] .tox-user__avatar svg { + margin-left: 8px; +} + +.tox[dir=rtl] .tox-user__avatar + .tox-user__name { + margin-right: 8px; +} + +.tox .tox-dialog-wrap { + align-items: center; + bottom: 0; + display: flex; + justify-content: center; + left: 0; + position: fixed; + right: 0; + top: 0; + z-index: 1100; +} + +.tox .tox-dialog-wrap__backdrop { + background-color: rgba(255, 255, 255, 0.75); + bottom: 0; + left: 0; + position: absolute; + right: 0; + top: 0; + z-index: 1; +} + +.tox .tox-dialog-wrap__backdrop--opaque { + background-color: #fff; +} + +.tox .tox-dialog { + background-color: #fff; + border-color: #cccccc; + border-radius: 3px; + border-style: solid; + border-width: 1px; + box-shadow: 0 16px 16px -10px rgba(34, 47, 62, 0.15), 0 0 40px 1px rgba(34, 47, 62, 0.15); + display: flex; + flex-direction: column; + max-height: 100%; + max-width: 480px; + overflow: hidden; + position: relative; + width: 95vw; + z-index: 2; +} + +@media only screen and (max-width: 767px) { + body:not(.tox-force-desktop) .tox .tox-dialog { + align-self: flex-start; + margin: 8px auto; + width: calc(100vw - 16px); + } +} + +.tox .tox-dialog-inline { + z-index: 1100; +} + +.tox .tox-dialog__header { + align-items: center; + background-color: #fff; + border-bottom: none; + color: #222f3e; + display: flex; + font-size: 16px; + justify-content: space-between; + padding: 8px 16px 0 16px; + position: relative; +} + +.tox .tox-dialog__header .tox-button { + z-index: 1; +} + +.tox .tox-dialog__draghandle { + cursor: grab; + height: 100%; + left: 0; + position: absolute; + top: 0; + width: 100%; +} + +.tox .tox-dialog__draghandle:active { + cursor: grabbing; +} + +.tox .tox-dialog__dismiss { + margin-left: auto; +} + +.tox .tox-dialog__title { + font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif; + font-size: 20px; + font-style: normal; + font-weight: normal; + line-height: 1.3; + margin: 0; + text-transform: none; +} + +.tox .tox-dialog__body { + color: #222f3e; + display: flex; + flex: 1; + -ms-flex-preferred-size: auto; + font-size: 16px; + font-style: normal; + font-weight: normal; + line-height: 1.3; + min-width: 0; + text-align: left; + text-transform: none; +} + +@media only screen and (max-width: 767px) { + body:not(.tox-force-desktop) .tox .tox-dialog__body { + flex-direction: column; + } +} + +.tox .tox-dialog__body-nav { + align-items: flex-start; + display: flex; + flex-direction: column; + padding: 16px 16px; +} + +@media only screen and (max-width: 767px) { + body:not(.tox-force-desktop) .tox .tox-dialog__body-nav { + flex-direction: row; + -webkit-overflow-scrolling: touch; + overflow-x: auto; + padding-bottom: 0; + } +} + +.tox .tox-dialog__body-nav-item { + border-bottom: 2px solid transparent; + color: rgba(34, 47, 62, 0.7); + display: inline-block; + font-size: 14px; + line-height: 1.3; + margin-bottom: 8px; + text-decoration: none; + white-space: nowrap; +} + +.tox .tox-dialog__body-nav-item:focus { + background-color: rgba(32, 122, 183, 0.1); +} + +.tox .tox-dialog__body-nav-item--active { + border-bottom: 2px solid #207ab7; + color: #207ab7; +} + +.tox .tox-dialog__body-content { + box-sizing: border-box; + display: flex; + flex: 1; + flex-direction: column; + -ms-flex-preferred-size: auto; + max-height: 650px; + overflow: auto; + -webkit-overflow-scrolling: touch; + padding: 16px 16px; +} + +.tox .tox-dialog__body-content > * { + margin-bottom: 0; + margin-top: 16px; +} + +.tox .tox-dialog__body-content > *:first-child { + margin-top: 0; +} + +.tox .tox-dialog__body-content > *:last-child { + margin-bottom: 0; +} + +.tox .tox-dialog__body-content > *:only-child { + margin-bottom: 0; + margin-top: 0; +} + +.tox .tox-dialog__body-content a { + color: #207ab7; + cursor: pointer; + text-decoration: none; +} + +.tox .tox-dialog__body-content a:hover, +.tox .tox-dialog__body-content a:focus { + color: #185d8c; + text-decoration: none; +} + +.tox .tox-dialog__body-content a:active { + color: #185d8c; + text-decoration: none; +} + +.tox .tox-dialog__body-content svg { + fill: #222f3e; +} + +.tox .tox-dialog__body-content ul { + display: block; + list-style-type: disc; + margin-bottom: 16px; + -webkit-margin-end: 0; + margin-inline-end: 0; + -webkit-margin-start: 0; + margin-inline-start: 0; + -webkit-padding-start: 2.5rem; + padding-inline-start: 2.5rem; +} + +.tox .tox-dialog__body-content .tox-form__group h1 { + color: #222f3e; + font-size: 20px; + font-style: normal; + font-weight: bold; + letter-spacing: normal; + margin-bottom: 16px; + margin-top: 2rem; + text-transform: none; +} + +.tox .tox-dialog__body-content .tox-form__group h2 { + color: #222f3e; + font-size: 16px; + font-style: normal; + font-weight: bold; + letter-spacing: normal; + margin-bottom: 16px; + margin-top: 2rem; + text-transform: none; +} + +.tox .tox-dialog__body-content .tox-form__group p { + margin-bottom: 16px; +} + +.tox .tox-dialog__body-content .tox-form__group h1:first-child, +.tox .tox-dialog__body-content .tox-form__group h2:first-child, +.tox .tox-dialog__body-content .tox-form__group p:first-child { + margin-top: 0; +} + +.tox .tox-dialog__body-content .tox-form__group h1:last-child, +.tox .tox-dialog__body-content .tox-form__group h2:last-child, +.tox .tox-dialog__body-content .tox-form__group p:last-child { + margin-bottom: 0; +} + +.tox .tox-dialog__body-content .tox-form__group h1:only-child, +.tox .tox-dialog__body-content .tox-form__group h2:only-child, +.tox .tox-dialog__body-content .tox-form__group p:only-child { + margin-bottom: 0; + margin-top: 0; +} + +.tox .tox-dialog--width-lg { + height: 650px; + max-width: 1200px; +} + +.tox .tox-dialog--width-md { + max-width: 800px; +} + +.tox .tox-dialog--width-md .tox-dialog__body-content { + overflow: auto; +} + +.tox .tox-dialog__body-content--centered { + text-align: center; +} + +.tox .tox-dialog__footer { + align-items: center; + background-color: #fff; + border-top: 1px solid #cccccc; + display: flex; + justify-content: space-between; + padding: 8px 16px; +} + +.tox .tox-dialog__footer-start, +.tox .tox-dialog__footer-end { + display: flex; +} + +.tox .tox-dialog__busy-spinner { + align-items: center; + background-color: rgba(255, 255, 255, 0.75); + bottom: 0; + display: flex; + justify-content: center; + left: 0; + position: absolute; + right: 0; + top: 0; + z-index: 3; +} + +.tox .tox-dialog__table { + border-collapse: collapse; + width: 100%; +} + +.tox .tox-dialog__table thead th { + font-weight: bold; + padding-bottom: 8px; +} + +.tox .tox-dialog__table tbody tr { + border-bottom: 1px solid #cccccc; +} + +.tox .tox-dialog__table tbody tr:last-child { + border-bottom: none; +} + +.tox .tox-dialog__table td { + padding-bottom: 8px; + padding-top: 8px; +} + +.tox .tox-dialog__popups { + position: absolute; + width: 100%; + z-index: 1100; +} + +.tox .tox-dialog__body-iframe { + display: flex; + flex: 1; + flex-direction: column; + -ms-flex-preferred-size: auto; +} + +.tox .tox-dialog__body-iframe .tox-navobj { + display: flex; + flex: 1; + -ms-flex-preferred-size: auto; +} + +.tox .tox-dialog__body-iframe .tox-navobj :nth-child(2) { + flex: 1; + -ms-flex-preferred-size: auto; + height: 100%; +} + +.tox .tox-dialog-dock-fadeout { + opacity: 0; + visibility: hidden; +} + +.tox .tox-dialog-dock-fadein { + opacity: 1; + visibility: visible; +} + +.tox .tox-dialog-dock-transition { + transition: visibility 0s linear 0.3s, opacity 0.3s ease; +} + +.tox .tox-dialog-dock-transition.tox-dialog-dock-fadein { + transition-delay: 0s; +} + +.tox.tox-platform-ie { + /* IE11 CSS styles go here */ +} + +.tox.tox-platform-ie .tox-dialog-wrap { + position: -ms-device-fixed; +} + +@media only screen and (max-width: 767px) { + body:not(.tox-force-desktop) .tox:not([dir=rtl]) .tox-dialog__body-nav { + margin-right: 0; + } +} + +@media only screen and (max-width: 767px) { + body:not(.tox-force-desktop) .tox:not([dir=rtl]) .tox-dialog__body-nav-item:not(:first-child) { + margin-left: 8px; + } +} + +.tox:not([dir=rtl]) .tox-dialog__footer .tox-dialog__footer-start > *, +.tox:not([dir=rtl]) .tox-dialog__footer .tox-dialog__footer-end > * { + margin-left: 8px; +} + +.tox[dir=rtl] .tox-dialog__body { + text-align: right; +} + +@media only screen and (max-width: 767px) { + body:not(.tox-force-desktop) .tox[dir=rtl] .tox-dialog__body-nav { + margin-left: 0; + } +} + +@media only screen and (max-width: 767px) { + body:not(.tox-force-desktop) .tox[dir=rtl] .tox-dialog__body-nav-item:not(:first-child) { + margin-right: 8px; + } +} + +.tox[dir=rtl] .tox-dialog__footer .tox-dialog__footer-start > *, +.tox[dir=rtl] .tox-dialog__footer .tox-dialog__footer-end > * { + margin-right: 8px; +} + +body.tox-dialog__disable-scroll { + overflow: hidden; +} + +.tox .tox-dropzone-container { + display: flex; + flex: 1; + -ms-flex-preferred-size: auto; +} + +.tox .tox-dropzone { + align-items: center; + background: #fff; + border: 2px dashed #cccccc; + box-sizing: border-box; + display: flex; + flex-direction: column; + flex-grow: 1; + justify-content: center; + min-height: 100px; + padding: 10px; +} + +.tox .tox-dropzone p { + color: rgba(34, 47, 62, 0.7); + margin: 0 0 16px 0; +} + +.tox .tox-edit-area { + display: flex; + flex: 1; + -ms-flex-preferred-size: auto; + overflow: hidden; + position: relative; +} + +.tox .tox-edit-area__iframe { + background-color: #fff; + border: 0; + box-sizing: border-box; + flex: 1; + -ms-flex-preferred-size: auto; + height: 100%; + position: absolute; + width: 100%; +} + +.tox.tox-inline-edit-area { + border: 1px dotted #cccccc; +} + +.tox .tox-editor-container { + display: flex; + flex: 1 1 auto; + flex-direction: column; + overflow: hidden; +} + +.tox .tox-editor-header { + z-index: 1000; +} + +.tox:not(.tox-tinymce-inline) .tox-editor-header { + box-shadow: none; + transition: box-shadow 0.5s; +} + +.tox.tox-tinymce--toolbar-bottom .tox-editor-header, +.tox.tox-tinymce-inline .tox-editor-header { + margin-bottom: -1px; +} + +.tox.tox-tinymce--toolbar-sticky-on .tox-editor-header { + background-color: transparent; + box-shadow: 0 4px 4px -3px rgba(0, 0, 0, 0.25); +} + +.tox-editor-dock-fadeout { + opacity: 0; + visibility: hidden; +} + +.tox-editor-dock-fadein { + opacity: 1; + visibility: visible; +} + +.tox-editor-dock-transition { + transition: visibility 0s linear 0.25s, opacity 0.25s ease; +} + +.tox-editor-dock-transition.tox-editor-dock-fadein { + transition-delay: 0s; +} + +.tox .tox-control-wrap { + flex: 1; + position: relative; +} + +.tox .tox-control-wrap:not(.tox-control-wrap--status-invalid) .tox-control-wrap__status-icon-invalid, +.tox .tox-control-wrap:not(.tox-control-wrap--status-unknown) .tox-control-wrap__status-icon-unknown, +.tox .tox-control-wrap:not(.tox-control-wrap--status-valid) .tox-control-wrap__status-icon-valid { + display: none; +} + +.tox .tox-control-wrap svg { + display: block; +} + +.tox .tox-control-wrap__status-icon-wrap { + position: absolute; + top: 50%; + transform: translateY(-50%); +} + +.tox .tox-control-wrap__status-icon-invalid svg { + fill: #c00; +} + +.tox .tox-control-wrap__status-icon-unknown svg { + fill: orange; +} + +.tox .tox-control-wrap__status-icon-valid svg { + fill: green; +} + +.tox:not([dir=rtl]) .tox-control-wrap--status-invalid .tox-textfield, +.tox:not([dir=rtl]) .tox-control-wrap--status-unknown .tox-textfield, +.tox:not([dir=rtl]) .tox-control-wrap--status-valid .tox-textfield { + padding-right: 32px; +} + +.tox:not([dir=rtl]) .tox-control-wrap__status-icon-wrap { + right: 4px; +} + +.tox[dir=rtl] .tox-control-wrap--status-invalid .tox-textfield, +.tox[dir=rtl] .tox-control-wrap--status-unknown .tox-textfield, +.tox[dir=rtl] .tox-control-wrap--status-valid .tox-textfield { + padding-left: 32px; +} + +.tox[dir=rtl] .tox-control-wrap__status-icon-wrap { + left: 4px; +} + +.tox .tox-autocompleter { + max-width: 25em; +} + +.tox .tox-autocompleter .tox-menu { + max-width: 25em; +} + +.tox .tox-autocompleter .tox-autocompleter-highlight { + font-weight: bold; +} + +.tox .tox-color-input { + display: flex; + position: relative; + z-index: 1; +} + +.tox .tox-color-input .tox-textfield { + z-index: -1; +} + +.tox .tox-color-input span { + border-color: rgba(34, 47, 62, 0.2); + border-radius: 3px; + border-style: solid; + border-width: 1px; + box-shadow: none; + box-sizing: border-box; + height: 24px; + position: absolute; + top: 6px; + width: 24px; +} + +.tox .tox-color-input span:hover:not([aria-disabled=true]), +.tox .tox-color-input span:focus:not([aria-disabled=true]) { + border-color: #207ab7; + cursor: pointer; +} + +.tox .tox-color-input span::before { + background-image: linear-gradient(45deg, rgba(0, 0, 0, 0.25) 25%, transparent 25%), linear-gradient(-45deg, rgba(0, 0, 0, 0.25) 25%, transparent 25%), linear-gradient(45deg, transparent 75%, rgba(0, 0, 0, 0.25) 75%), linear-gradient(-45deg, transparent 75%, rgba(0, 0, 0, 0.25) 75%); + background-position: 0 0, 0 6px, 6px -6px, -6px 0; + background-size: 12px 12px; + border: 1px solid #fff; + border-radius: 3px; + box-sizing: border-box; + content: ''; + height: 24px; + left: -1px; + position: absolute; + top: -1px; + width: 24px; + z-index: -1; +} + +.tox .tox-color-input span[aria-disabled=true] { + cursor: not-allowed; +} + +.tox:not([dir=rtl]) .tox-color-input { + /* stylelint-disable-next-line no-descending-specificity */ +} + +.tox:not([dir=rtl]) .tox-color-input .tox-textfield { + padding-left: 36px; +} + +.tox:not([dir=rtl]) .tox-color-input span { + left: 6px; +} + +.tox[dir="rtl"] .tox-color-input { + /* stylelint-disable-next-line no-descending-specificity */ +} + +.tox[dir="rtl"] .tox-color-input .tox-textfield { + padding-right: 36px; +} + +.tox[dir="rtl"] .tox-color-input span { + right: 6px; +} + +.tox .tox-label, +.tox .tox-toolbar-label { + color: rgba(34, 47, 62, 0.7); + display: block; + font-size: 14px; + font-style: normal; + font-weight: normal; + line-height: 1.3; + padding: 0 8px 0 0; + text-transform: none; + white-space: nowrap; +} + +.tox .tox-toolbar-label { + padding: 0 8px; +} + +.tox[dir=rtl] .tox-label { + padding: 0 0 0 8px; +} + +.tox .tox-form { + display: flex; + flex: 1; + flex-direction: column; + -ms-flex-preferred-size: auto; +} + +.tox .tox-form__group { + box-sizing: border-box; + margin-bottom: 4px; +} + +.tox .tox-form-group--maximize { + flex: 1; +} + +.tox .tox-form__group--error { + color: #c00; +} + +.tox .tox-form__group--collection { + display: flex; +} + +.tox .tox-form__grid { + display: flex; + flex-direction: row; + flex-wrap: wrap; + justify-content: space-between; +} + +.tox .tox-form__grid--2col > .tox-form__group { + width: calc(50% - (8px / 2)); +} + +.tox .tox-form__grid--3col > .tox-form__group { + width: calc(100% / 3 - (8px / 2)); +} + +.tox .tox-form__grid--4col > .tox-form__group { + width: calc(25% - (8px / 2)); +} + +.tox .tox-form__controls-h-stack { + align-items: center; + display: flex; +} + +.tox .tox-form__group--inline { + align-items: center; + display: flex; +} + +.tox .tox-form__group--stretched { + display: flex; + flex: 1; + flex-direction: column; + -ms-flex-preferred-size: auto; +} + +.tox .tox-form__group--stretched .tox-textarea { + flex: 1; + -ms-flex-preferred-size: auto; +} + +.tox .tox-form__group--stretched .tox-navobj { + display: flex; + flex: 1; + -ms-flex-preferred-size: auto; +} + +.tox .tox-form__group--stretched .tox-navobj :nth-child(2) { + flex: 1; + -ms-flex-preferred-size: auto; + height: 100%; +} + +.tox:not([dir=rtl]) .tox-form__controls-h-stack > *:not(:first-child) { + margin-left: 4px; +} + +.tox[dir=rtl] .tox-form__controls-h-stack > *:not(:first-child) { + margin-right: 4px; +} + +.tox .tox-lock.tox-locked .tox-lock-icon__unlock, +.tox .tox-lock:not(.tox-locked) .tox-lock-icon__lock { + display: none; +} + +.tox .tox-textfield, +.tox .tox-toolbar-textfield, +.tox .tox-listboxfield .tox-listbox--select, +.tox .tox-textarea { + -webkit-appearance: none; + -moz-appearance: none; + appearance: none; + background-color: #fff; + border-color: #cccccc; + border-radius: 3px; + border-style: solid; + border-width: 1px; + box-shadow: none; + box-sizing: border-box; + color: #222f3e; + font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif; + font-size: 16px; + line-height: 24px; + margin: 0; + min-height: 34px; + outline: none; + padding: 5px 4.75px; + resize: none; + width: 100%; +} + +.tox .tox-textfield[disabled], +.tox .tox-textarea[disabled] { + background-color: #f2f2f2; + color: rgba(34, 47, 62, 0.85); + cursor: not-allowed; +} + +.tox .tox-textfield:focus, +.tox .tox-listboxfield .tox-listbox--select:focus, +.tox .tox-textarea:focus { + background-color: #fff; + border-color: #207ab7; + box-shadow: none; + outline: none; +} + +.tox .tox-toolbar-textfield { + border-width: 0; + margin-bottom: 3px; + margin-top: 2px; + max-width: 250px; +} + +.tox .tox-naked-btn { + background-color: transparent; + border: 0; + border-color: transparent; + box-shadow: unset; + color: #207ab7; + cursor: pointer; + display: block; + margin: 0; + padding: 0; +} + +.tox .tox-naked-btn svg { + display: block; + fill: #222f3e; +} + +.tox:not([dir=rtl]) .tox-toolbar-textfield + * { + margin-left: 4px; +} + +.tox[dir=rtl] .tox-toolbar-textfield + * { + margin-right: 4px; +} + +.tox .tox-listboxfield { + cursor: pointer; + position: relative; +} + +.tox .tox-listboxfield .tox-listbox--select[disabled] { + background-color: #f2f2f2; + color: rgba(34, 47, 62, 0.85); + cursor: not-allowed; +} + +.tox .tox-listbox__select-label { + cursor: default; + flex: 1; + margin: 0 4px; +} + +.tox .tox-listbox__select-chevron { + align-items: center; + display: flex; + justify-content: center; + width: 16px; +} + +.tox .tox-listbox__select-chevron svg { + fill: #222f3e; +} + +.tox .tox-listboxfield .tox-listbox--select { + align-items: center; + display: flex; +} + +.tox:not([dir=rtl]) .tox-listboxfield svg { + right: 8px; +} + +.tox[dir=rtl] .tox-listboxfield svg { + left: 8px; +} + +.tox .tox-selectfield { + cursor: pointer; + position: relative; +} + +.tox .tox-selectfield select { + -webkit-appearance: none; + -moz-appearance: none; + appearance: none; + background-color: #fff; + border-color: #cccccc; + border-radius: 3px; + border-style: solid; + border-width: 1px; + box-shadow: none; + box-sizing: border-box; + color: #222f3e; + font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif; + font-size: 16px; + line-height: 24px; + margin: 0; + min-height: 34px; + outline: none; + padding: 5px 4.75px; + resize: none; + width: 100%; +} + +.tox .tox-selectfield select[disabled] { + background-color: #f2f2f2; + color: rgba(34, 47, 62, 0.85); + cursor: not-allowed; +} + +.tox .tox-selectfield select::-ms-expand { + display: none; +} + +.tox .tox-selectfield select:focus { + background-color: #fff; + border-color: #207ab7; + box-shadow: none; + outline: none; +} + +.tox .tox-selectfield svg { + pointer-events: none; + position: absolute; + top: 50%; + transform: translateY(-50%); +} + +.tox:not([dir=rtl]) .tox-selectfield select[size="0"], +.tox:not([dir=rtl]) .tox-selectfield select[size="1"] { + padding-right: 24px; +} + +.tox:not([dir=rtl]) .tox-selectfield svg { + right: 8px; +} + +.tox[dir=rtl] .tox-selectfield select[size="0"], +.tox[dir=rtl] .tox-selectfield select[size="1"] { + padding-left: 24px; +} + +.tox[dir=rtl] .tox-selectfield svg { + left: 8px; +} + +.tox .tox-textarea { + -webkit-appearance: textarea; + -moz-appearance: textarea; + appearance: textarea; + white-space: pre-wrap; +} + +.tox-fullscreen { + border: 0; + height: 100%; + left: 0; + margin: 0; + overflow: hidden; + -ms-scroll-chaining: none; + overscroll-behavior: none; + padding: 0; + position: fixed; + top: 0; + touch-action: pinch-zoom; + width: 100%; +} + +.tox.tox-tinymce.tox-fullscreen .tox-statusbar__resize-handle { + display: none; +} + +.tox.tox-tinymce.tox-fullscreen { + background-color: transparent; + z-index: 1200; +} + +.tox-shadowhost.tox-fullscreen { + z-index: 1200; +} + +.tox-fullscreen .tox.tox-tinymce-aux, +.tox-fullscreen ~ .tox.tox-tinymce-aux { + z-index: 1201; +} + +.tox .tox-help__more-link { + list-style: none; + margin-top: 1em; +} + +.tox .tox-image-tools { + width: 100%; +} + +.tox .tox-image-tools__toolbar { + align-items: center; + display: flex; + justify-content: center; +} + +.tox .tox-image-tools__image { + background-color: #666; + height: 380px; + overflow: auto; + position: relative; + width: 100%; +} + +.tox .tox-image-tools__image, +.tox .tox-image-tools__image + .tox-image-tools__toolbar { + margin-top: 8px; +} + +.tox .tox-image-tools__image-bg { + background: url(data:image/gif;base64,R0lGODdhDAAMAIABAMzMzP///ywAAAAADAAMAAACFoQfqYeabNyDMkBQb81Uat85nxguUAEAOw==); +} + +.tox .tox-image-tools__toolbar > .tox-spacer { + flex: 1; + -ms-flex-preferred-size: auto; +} + +.tox .tox-croprect-block { + background: black; + filter: alpha(opacity=50); + opacity: 0.5; + position: absolute; + zoom: 1; +} + +.tox .tox-croprect-handle { + border: 2px solid white; + height: 20px; + left: 0; + position: absolute; + top: 0; + width: 20px; +} + +.tox .tox-croprect-handle-move { + border: 0; + cursor: move; + position: absolute; +} + +.tox .tox-croprect-handle-nw { + border-width: 2px 0 0 2px; + cursor: nw-resize; + left: 100px; + margin: -2px 0 0 -2px; + top: 100px; +} + +.tox .tox-croprect-handle-ne { + border-width: 2px 2px 0 0; + cursor: ne-resize; + left: 200px; + margin: -2px 0 0 -20px; + top: 100px; +} + +.tox .tox-croprect-handle-sw { + border-width: 0 0 2px 2px; + cursor: sw-resize; + left: 100px; + margin: -20px 2px 0 -2px; + top: 200px; +} + +.tox .tox-croprect-handle-se { + border-width: 0 2px 2px 0; + cursor: se-resize; + left: 200px; + margin: -20px 0 0 -20px; + top: 200px; +} + +.tox:not([dir=rtl]) .tox-image-tools__toolbar > .tox-slider:not(:first-of-type) { + margin-left: 8px; +} + +.tox:not([dir=rtl]) .tox-image-tools__toolbar > .tox-button + .tox-slider { + margin-left: 32px; +} + +.tox:not([dir=rtl]) .tox-image-tools__toolbar > .tox-slider + .tox-button { + margin-left: 32px; +} + +.tox[dir=rtl] .tox-image-tools__toolbar > .tox-slider:not(:first-of-type) { + margin-right: 8px; +} + +.tox[dir=rtl] .tox-image-tools__toolbar > .tox-button + .tox-slider { + margin-right: 32px; +} + +.tox[dir=rtl] .tox-image-tools__toolbar > .tox-slider + .tox-button { + margin-right: 32px; +} + +.tox .tox-insert-table-picker { + display: flex; + flex-wrap: wrap; + width: 170px; +} + +.tox .tox-insert-table-picker > div { + border-color: #cccccc; + border-style: solid; + border-width: 0 1px 1px 0; + box-sizing: border-box; + height: 17px; + width: 17px; +} + +.tox .tox-collection--list .tox-collection__group .tox-insert-table-picker { + margin: -4px 0; +} + +.tox .tox-insert-table-picker .tox-insert-table-picker__selected { + background-color: rgba(32, 122, 183, 0.5); + border-color: rgba(32, 122, 183, 0.5); +} + +.tox .tox-insert-table-picker__label { + color: rgba(34, 47, 62, 0.7); + display: block; + font-size: 14px; + padding: 4px; + text-align: center; + width: 100%; +} + +.tox:not([dir=rtl]) { + /* stylelint-disable-next-line no-descending-specificity */ +} + +.tox:not([dir=rtl]) .tox-insert-table-picker > div:nth-child(10n) { + border-right: 0; +} + +.tox[dir=rtl] { + /* stylelint-disable-next-line no-descending-specificity */ +} + +.tox[dir=rtl] .tox-insert-table-picker > div:nth-child(10n+1) { + border-right: 0; +} + +.tox { + /* stylelint-disable */ + /* stylelint-enable */ +} + +.tox .tox-menu { + background-color: #fff; + border: 1px solid #cccccc; + border-radius: 3px; + box-shadow: 0 4px 8px 0 rgba(34, 47, 62, 0.1); + display: inline-block; + overflow: hidden; + vertical-align: top; + z-index: 1150; +} + +.tox .tox-menu.tox-collection.tox-collection--list { + padding: 0; +} + +.tox .tox-menu.tox-collection.tox-collection--toolbar { + padding: 4px; +} + +.tox .tox-menu.tox-collection.tox-collection--grid { + padding: 4px; +} + +.tox .tox-menu__label h1, +.tox .tox-menu__label h2, +.tox .tox-menu__label h3, +.tox .tox-menu__label h4, +.tox .tox-menu__label h5, +.tox .tox-menu__label h6, +.tox .tox-menu__label p, +.tox .tox-menu__label blockquote, +.tox .tox-menu__label code { + margin: 0; +} + +.tox .tox-menubar { + background: url("data:image/svg+xml;charset=utf8,%3Csvg height='39px' viewBox='0 0 40 39px' width='40' xmlns='http://www.w3.org/2000/svg'%3E%3Crect x='0' y='38px' width='100' height='1' fill='%23cccccc'/%3E%3C/svg%3E") left 0 top 0 #fff; + background-color: #fff; + display: flex; + flex: 0 0 auto; + flex-shrink: 0; + flex-wrap: wrap; + padding: 0 4px 0 4px; +} + +.tox.tox-tinymce:not(.tox-tinymce-inline) .tox-editor-header:not(:first-child) .tox-menubar { + border-top: 1px solid #cccccc; +} + +/* Deprecated. Remove in next major release */ +.tox .tox-mbtn { + align-items: center; + background: transparent; + border: 0; + border-radius: 3px; + box-shadow: none; + color: #222f3e; + display: flex; + flex: 0 0 auto; + font-size: 14px; + font-style: normal; + font-weight: normal; + height: 34px; + justify-content: center; + margin: 2px 0 3px 0; + outline: none; + overflow: hidden; + padding: 0 4px; + text-transform: none; + width: auto; +} + +.tox .tox-mbtn[disabled] { + background-color: transparent; + border: 0; + box-shadow: none; + color: rgba(34, 47, 62, 0.5); + cursor: not-allowed; +} + +.tox .tox-mbtn:focus:not(:disabled) { + background: #dee0e2; + border: 0; + box-shadow: none; + color: #222f3e; +} + +.tox .tox-mbtn--active { + background: #c8cbcf; + border: 0; + box-shadow: none; + color: #222f3e; +} + +.tox .tox-mbtn:hover:not(:disabled):not(.tox-mbtn--active) { + background: #dee0e2; + border: 0; + box-shadow: none; + color: #222f3e; +} + +.tox .tox-mbtn__select-label { + cursor: default; + font-weight: normal; + margin: 0 4px; +} + +.tox .tox-mbtn[disabled] .tox-mbtn__select-label { + cursor: not-allowed; +} + +.tox .tox-mbtn__select-chevron { + align-items: center; + display: flex; + justify-content: center; + width: 16px; + display: none; +} + +.tox .tox-notification { + border-radius: 3px; + border-style: solid; + border-width: 1px; + box-shadow: none; + box-sizing: border-box; + display: -ms-grid; + display: grid; + font-size: 14px; + font-weight: normal; + -ms-grid-columns: minmax(40px, 1fr) auto minmax(40px, 1fr); + grid-template-columns: minmax(40px, 1fr) auto minmax(40px, 1fr); + margin-top: 4px; + opacity: 0; + padding: 4px; + transition: transform 100ms ease-in, opacity 150ms ease-in; +} + +.tox .tox-notification p { + font-size: 14px; + font-weight: normal; +} + +.tox .tox-notification a { + text-decoration: underline; +} + +.tox .tox-notification--in { + opacity: 1; +} + +.tox .tox-notification--success { + background-color: #e4eeda; + border-color: #d7e6c8; + color: #222f3e; +} + +.tox .tox-notification--success p { + color: #222f3e; +} + +.tox .tox-notification--success a { + color: #547831; +} + +.tox .tox-notification--success svg { + fill: #222f3e; +} + +.tox .tox-notification--error { + background-color: #f8dede; + border-color: #f2bfbf; + color: #222f3e; +} + +.tox .tox-notification--error p { + color: #222f3e; +} + +.tox .tox-notification--error a { + color: #c00; +} + +.tox .tox-notification--error svg { + fill: #222f3e; +} + +.tox .tox-notification--warn, +.tox .tox-notification--warning { + background-color: #fffaea; + border-color: #ffe89d; + color: #222f3e; +} + +.tox .tox-notification--warn p, +.tox .tox-notification--warning p { + color: #222f3e; +} + +.tox .tox-notification--warn a, +.tox .tox-notification--warning a { + color: #222f3e; +} + +.tox .tox-notification--warn svg, +.tox .tox-notification--warning svg { + fill: #222f3e; +} + +.tox .tox-notification--info { + background-color: #d9edf7; + border-color: #779ecb; + color: #222f3e; +} + +.tox .tox-notification--info p { + color: #222f3e; +} + +.tox .tox-notification--info a { + color: #222f3e; +} + +.tox .tox-notification--info svg { + fill: #222f3e; +} + +.tox .tox-notification__body { + -ms-grid-row-align: center; + align-self: center; + color: #222f3e; + font-size: 14px; + -ms-grid-column-span: 1; + grid-column-end: 3; + -ms-grid-column: 2; + grid-column-start: 2; + -ms-grid-row-span: 1; + grid-row-end: 2; + -ms-grid-row: 1; + grid-row-start: 1; + text-align: center; + white-space: normal; + word-break: break-all; + word-break: break-word; +} + +.tox .tox-notification__body > * { + margin: 0; +} + +.tox .tox-notification__body > * + * { + margin-top: 1rem; +} + +.tox .tox-notification__icon { + -ms-grid-row-align: center; + align-self: center; + -ms-grid-column-span: 1; + grid-column-end: 2; + -ms-grid-column: 1; + grid-column-start: 1; + -ms-grid-row-span: 1; + grid-row-end: 2; + -ms-grid-row: 1; + grid-row-start: 1; + -ms-grid-column-align: end; + justify-self: end; +} + +.tox .tox-notification__icon svg { + display: block; +} + +.tox .tox-notification__dismiss { + -ms-grid-row-align: start; + align-self: start; + -ms-grid-column-span: 1; + grid-column-end: 4; + -ms-grid-column: 3; + grid-column-start: 3; + -ms-grid-row-span: 1; + grid-row-end: 2; + -ms-grid-row: 1; + grid-row-start: 1; + -ms-grid-column-align: end; + justify-self: end; +} + +.tox .tox-notification .tox-progress-bar { + -ms-grid-column-span: 3; + grid-column-end: 4; + -ms-grid-column: 1; + grid-column-start: 1; + -ms-grid-row-span: 1; + grid-row-end: 3; + -ms-grid-row: 2; + grid-row-start: 2; + -ms-grid-column-align: center; + justify-self: center; +} + +.tox .tox-pop { + display: inline-block; + position: relative; +} + +.tox .tox-pop--resizing { + transition: width 0.1s ease; +} + +.tox .tox-pop--resizing .tox-toolbar { + flex-wrap: nowrap; +} + +.tox .tox-pop__dialog { + background-color: #fff; + border: 1px solid #cccccc; + border-radius: 3px; + box-shadow: 0 1px 3px rgba(0, 0, 0, 0.15); + min-width: 0; + overflow: hidden; +} + +.tox .tox-pop__dialog > *:not(.tox-toolbar) { + margin: 4px 4px 4px 8px; +} + +.tox .tox-pop__dialog .tox-toolbar { + background-color: transparent; + margin-bottom: -1px; +} + +.tox .tox-pop::before, +.tox .tox-pop::after { + border-style: solid; + content: ''; + display: block; + height: 0; + position: absolute; + width: 0; +} + +.tox .tox-pop.tox-pop--bottom::before, +.tox .tox-pop.tox-pop--bottom::after { + left: 50%; + top: 100%; +} + +.tox .tox-pop.tox-pop--bottom::after { + border-color: #fff transparent transparent transparent; + border-width: 8px; + margin-left: -8px; + margin-top: -1px; +} + +.tox .tox-pop.tox-pop--bottom::before { + border-color: #cccccc transparent transparent transparent; + border-width: 9px; + margin-left: -9px; +} + +.tox .tox-pop.tox-pop--top::before, +.tox .tox-pop.tox-pop--top::after { + left: 50%; + top: 0; + transform: translateY(-100%); +} + +.tox .tox-pop.tox-pop--top::after { + border-color: transparent transparent #fff transparent; + border-width: 8px; + margin-left: -8px; + margin-top: 1px; +} + +.tox .tox-pop.tox-pop--top::before { + border-color: transparent transparent #cccccc transparent; + border-width: 9px; + margin-left: -9px; +} + +.tox .tox-pop.tox-pop--left::before, +.tox .tox-pop.tox-pop--left::after { + left: 0; + top: calc(50% - 1px); + transform: translateY(-50%); +} + +.tox .tox-pop.tox-pop--left::after { + border-color: transparent #fff transparent transparent; + border-width: 8px; + margin-left: -15px; +} + +.tox .tox-pop.tox-pop--left::before { + border-color: transparent #cccccc transparent transparent; + border-width: 10px; + margin-left: -19px; +} + +.tox .tox-pop.tox-pop--right::before, +.tox .tox-pop.tox-pop--right::after { + left: 100%; + top: calc(50% + 1px); + transform: translateY(-50%); +} + +.tox .tox-pop.tox-pop--right::after { + border-color: transparent transparent transparent #fff; + border-width: 8px; + margin-left: -1px; +} + +.tox .tox-pop.tox-pop--right::before { + border-color: transparent transparent transparent #cccccc; + border-width: 10px; + margin-left: -1px; +} + +.tox .tox-pop.tox-pop--align-left::before, +.tox .tox-pop.tox-pop--align-left::after { + left: 20px; +} + +.tox .tox-pop.tox-pop--align-right::before, +.tox .tox-pop.tox-pop--align-right::after { + left: calc(100% - 20px); +} + +.tox .tox-sidebar-wrap { + display: flex; + flex-direction: row; + flex-grow: 1; + -ms-flex-preferred-size: 0; + min-height: 0; +} + +.tox .tox-sidebar { + background-color: #fff; + display: flex; + flex-direction: row; + justify-content: flex-end; +} + +.tox .tox-sidebar__slider { + display: flex; + overflow: hidden; +} + +.tox .tox-sidebar__pane-container { + display: flex; +} + +.tox .tox-sidebar__pane { + display: flex; +} + +.tox .tox-sidebar--sliding-closed { + opacity: 0; +} + +.tox .tox-sidebar--sliding-open { + opacity: 1; +} + +.tox .tox-sidebar--sliding-growing, +.tox .tox-sidebar--sliding-shrinking { + transition: width 0.5s ease, opacity 0.5s ease; +} + +.tox .tox-selector { + background-color: #4099ff; + border-color: #4099ff; + border-style: solid; + border-width: 1px; + box-sizing: border-box; + display: inline-block; + height: 10px; + position: absolute; + width: 10px; +} + +.tox.tox-platform-touch .tox-selector { + height: 12px; + width: 12px; +} + +.tox .tox-slider { + align-items: center; + display: flex; + flex: 1; + -ms-flex-preferred-size: auto; + height: 24px; + justify-content: center; + position: relative; +} + +.tox .tox-slider__rail { + background-color: transparent; + border: 1px solid #cccccc; + border-radius: 3px; + height: 10px; + min-width: 120px; + width: 100%; +} + +.tox .tox-slider__handle { + background-color: #207ab7; + border: 2px solid #185d8c; + border-radius: 3px; + box-shadow: none; + height: 24px; + left: 50%; + position: absolute; + top: 50%; + transform: translateX(-50%) translateY(-50%); + width: 14px; +} + +.tox .tox-source-code { + overflow: auto; +} + +.tox .tox-spinner { + display: flex; +} + +.tox .tox-spinner > div { + animation: tam-bouncing-dots 1.5s ease-in-out 0s infinite both; + background-color: rgba(34, 47, 62, 0.7); + border-radius: 100%; + height: 8px; + width: 8px; +} + +.tox .tox-spinner > div:nth-child(1) { + animation-delay: -0.32s; +} + +.tox .tox-spinner > div:nth-child(2) { + animation-delay: -0.16s; +} + +@keyframes tam-bouncing-dots { + 0%, + 80%, + 100% { + transform: scale(0); + } + 40% { + transform: scale(1); + } +} + +.tox:not([dir=rtl]) .tox-spinner > div:not(:first-child) { + margin-left: 4px; +} + +.tox[dir=rtl] .tox-spinner > div:not(:first-child) { + margin-right: 4px; +} + +.tox .tox-statusbar { + align-items: center; + background-color: #fff; + border-top: 1px solid #cccccc; + color: rgba(34, 47, 62, 0.7); + display: flex; + flex: 0 0 auto; + font-size: 12px; + font-weight: normal; + height: 18px; + overflow: hidden; + padding: 0 8px; + position: relative; + text-transform: uppercase; +} + +.tox .tox-statusbar__text-container { + display: flex; + flex: 1 1 auto; + justify-content: flex-end; + overflow: hidden; +} + +.tox .tox-statusbar__path { + display: flex; + flex: 1 1 auto; + margin-right: auto; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.tox .tox-statusbar__path > * { + display: inline; + white-space: nowrap; +} + +.tox .tox-statusbar__wordcount { + flex: 0 0 auto; + margin-left: 1ch; +} + +.tox .tox-statusbar a, +.tox .tox-statusbar__path-item, +.tox .tox-statusbar__wordcount { + color: rgba(34, 47, 62, 0.7); + text-decoration: none; +} + +.tox .tox-statusbar a:hover:not(:disabled):not([aria-disabled=true]), +.tox .tox-statusbar__path-item:hover:not(:disabled):not([aria-disabled=true]), +.tox .tox-statusbar__wordcount:hover:not(:disabled):not([aria-disabled=true]), +.tox .tox-statusbar a:focus:not(:disabled):not([aria-disabled=true]), +.tox .tox-statusbar__path-item:focus:not(:disabled):not([aria-disabled=true]), +.tox .tox-statusbar__wordcount:focus:not(:disabled):not([aria-disabled=true]) { + cursor: pointer; + text-decoration: underline; +} + +.tox .tox-statusbar__resize-handle { + align-items: flex-end; + align-self: stretch; + cursor: nwse-resize; + display: flex; + flex: 0 0 auto; + justify-content: flex-end; + margin-left: auto; + margin-right: -8px; + padding-left: 1ch; +} + +.tox .tox-statusbar__resize-handle svg { + display: block; + fill: rgba(34, 47, 62, 0.7); +} + +.tox .tox-statusbar__resize-handle:focus svg { + background-color: #dee0e2; + border-radius: 1px; + box-shadow: 0 0 0 2px #dee0e2; +} + +.tox:not([dir=rtl]) .tox-statusbar__path > * { + margin-right: 4px; +} + +.tox:not([dir=rtl]) .tox-statusbar__branding { + margin-left: 1ch; +} + +.tox[dir=rtl] .tox-statusbar { + flex-direction: row-reverse; +} + +.tox[dir=rtl] .tox-statusbar__path > * { + margin-left: 4px; +} + +.tox .tox-throbber { + z-index: 1299; +} + +.tox .tox-throbber__busy-spinner { + align-items: center; + background-color: rgba(255, 255, 255, 0.6); + bottom: 0; + display: flex; + justify-content: center; + left: 0; + position: absolute; + right: 0; + top: 0; +} + +.tox .tox-tbtn { + align-items: center; + background: transparent; + border: 0; + border-radius: 3px; + box-shadow: none; + color: #222f3e; + display: flex; + flex: 0 0 auto; + font-size: 14px; + font-style: normal; + font-weight: normal; + height: 34px; + justify-content: center; + margin: 2px 0 3px 0; + outline: none; + overflow: hidden; + padding: 0; + text-transform: none; + width: 34px; +} + +.tox .tox-tbtn svg { + display: block; + fill: #222f3e; +} + +.tox .tox-tbtn.tox-tbtn-more { + padding-left: 5px; + padding-right: 5px; + width: inherit; +} + +.tox .tox-tbtn:focus { + background: #dee0e2; + border: 0; + box-shadow: none; +} + +.tox .tox-tbtn:hover { + background: #dee0e2; + border: 0; + box-shadow: none; + color: #222f3e; +} + +.tox .tox-tbtn:hover svg { + fill: #222f3e; +} + +.tox .tox-tbtn:active { + background: #c8cbcf; + border: 0; + box-shadow: none; + color: #222f3e; +} + +.tox .tox-tbtn:active svg { + fill: #222f3e; +} + +.tox .tox-tbtn--disabled, +.tox .tox-tbtn--disabled:hover, +.tox .tox-tbtn:disabled, +.tox .tox-tbtn:disabled:hover { + background: transparent; + border: 0; + box-shadow: none; + color: rgba(34, 47, 62, 0.5); + cursor: not-allowed; +} + +.tox .tox-tbtn--disabled svg, +.tox .tox-tbtn--disabled:hover svg, +.tox .tox-tbtn:disabled svg, +.tox .tox-tbtn:disabled:hover svg { + /* stylelint-disable-line no-descending-specificity */ + fill: rgba(34, 47, 62, 0.5); +} + +.tox .tox-tbtn--enabled, +.tox .tox-tbtn--enabled:hover { + background: #c8cbcf; + border: 0; + box-shadow: none; + color: #222f3e; +} + +.tox .tox-tbtn--enabled > *, +.tox .tox-tbtn--enabled:hover > * { + transform: none; +} + +.tox .tox-tbtn--enabled svg, +.tox .tox-tbtn--enabled:hover svg { + /* stylelint-disable-line no-descending-specificity */ + fill: #222f3e; +} + +.tox .tox-tbtn:focus:not(.tox-tbtn--disabled) { + color: #222f3e; +} + +.tox .tox-tbtn:focus:not(.tox-tbtn--disabled) svg { + fill: #222f3e; +} + +.tox .tox-tbtn:active > * { + transform: none; +} + +.tox .tox-tbtn--md { + height: 51px; + width: 51px; +} + +.tox .tox-tbtn--lg { + flex-direction: column; + height: 68px; + width: 68px; +} + +.tox .tox-tbtn--return { + -ms-grid-row-align: stretch; + align-self: stretch; + height: unset; + width: 16px; +} + +.tox .tox-tbtn--labeled { + padding: 0 4px; + width: unset; +} + +.tox .tox-tbtn__vlabel { + display: block; + font-size: 10px; + font-weight: normal; + letter-spacing: -0.025em; + margin-bottom: 4px; + white-space: nowrap; +} + +.tox .tox-tbtn--select { + margin: 2px 0 3px 0; + padding: 0 4px; + width: auto; +} + +.tox .tox-tbtn__select-label { + cursor: default; + font-weight: normal; + margin: 0 4px; +} + +.tox .tox-tbtn__select-chevron { + align-items: center; + display: flex; + justify-content: center; + width: 16px; +} + +.tox .tox-tbtn__select-chevron svg { + fill: rgba(34, 47, 62, 0.5); +} + +.tox .tox-tbtn--bespoke .tox-tbtn__select-label { + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + width: 7em; +} + +.tox .tox-split-button { + border: 0; + border-radius: 3px; + box-sizing: border-box; + display: flex; + margin: 2px 0 3px 0; + overflow: hidden; +} + +.tox .tox-split-button:hover { + box-shadow: 0 0 0 1px #dee0e2 inset; +} + +.tox .tox-split-button:focus { + background: #dee0e2; + box-shadow: none; + color: #222f3e; +} + +.tox .tox-split-button > * { + border-radius: 0; +} + +.tox .tox-split-button__chevron { + width: 16px; +} + +.tox .tox-split-button__chevron svg { + fill: rgba(34, 47, 62, 0.5); +} + +.tox .tox-split-button .tox-tbtn { + margin: 0; +} + +.tox.tox-platform-touch .tox-split-button .tox-tbtn:first-child { + width: 30px; +} + +.tox.tox-platform-touch .tox-split-button__chevron { + width: 20px; +} + +.tox .tox-split-button.tox-tbtn--disabled:hover, +.tox .tox-split-button.tox-tbtn--disabled:focus, +.tox .tox-split-button.tox-tbtn--disabled .tox-tbtn:hover, +.tox .tox-split-button.tox-tbtn--disabled .tox-tbtn:focus { + background: transparent; + box-shadow: none; + color: rgba(34, 47, 62, 0.5); +} + +.tox .tox-toolbar-overlord { + background-color: #fff; +} + +.tox .tox-toolbar, +.tox .tox-toolbar__primary, +.tox .tox-toolbar__overflow { + background: url("data:image/svg+xml;charset=utf8,%3Csvg height='39px' viewBox='0 0 40 39px' width='40' xmlns='http://www.w3.org/2000/svg'%3E%3Crect x='0' y='38px' width='100' height='1' fill='%23cccccc'/%3E%3C/svg%3E") left 0 top 0 #fff; + background-color: #fff; + display: flex; + flex: 0 0 auto; + flex-shrink: 0; + flex-wrap: wrap; + padding: 0 0; +} + +.tox .tox-toolbar__overflow.tox-toolbar__overflow--closed { + height: 0; + opacity: 0; + padding-bottom: 0; + padding-top: 0; + visibility: hidden; +} + +.tox .tox-toolbar__overflow--growing { + transition: height 0.3s ease, opacity 0.2s linear 0.1s; +} + +.tox .tox-toolbar__overflow--shrinking { + transition: opacity 0.3s ease, height 0.2s linear 0.1s, visibility 0s linear 0.3s; +} + +.tox .tox-menubar + .tox-toolbar, +.tox .tox-menubar + .tox-toolbar-overlord .tox-toolbar__primary { + border-top: 1px solid #cccccc; + margin-top: -1px; +} + +.tox .tox-toolbar--scrolling { + flex-wrap: nowrap; + overflow-x: auto; +} + +.tox .tox-pop .tox-toolbar { + border-width: 0; +} + +.tox .tox-toolbar--no-divider { + background-image: none; +} + +.tox-tinymce:not(.tox-tinymce-inline) .tox-editor-header:not(:first-child) .tox-toolbar:first-child, +.tox-tinymce:not(.tox-tinymce-inline) .tox-editor-header:not(:first-child) .tox-toolbar-overlord:first-child .tox-toolbar__primary { + border-top: 1px solid #cccccc; +} + +.tox.tox-tinymce-aux .tox-toolbar__overflow { + background-color: #fff; + border: 1px solid #cccccc; + border-radius: 3px; + box-shadow: 0 1px 3px rgba(0, 0, 0, 0.15); +} + +.tox[dir=rtl] .tox-tbtn__icon-rtl svg { + transform: rotateY(180deg); +} + +.tox .tox-toolbar__group { + align-items: center; + display: flex; + flex-wrap: wrap; + margin: 0 0; + padding: 0 4px 0 4px; +} + +.tox .tox-toolbar__group--pull-right { + margin-left: auto; +} + +.tox .tox-toolbar--scrolling .tox-toolbar__group { + flex-shrink: 0; + flex-wrap: nowrap; +} + +.tox:not([dir=rtl]) .tox-toolbar__group:not(:last-of-type) { + border-right: 1px solid #cccccc; +} + +.tox[dir=rtl] .tox-toolbar__group:not(:last-of-type) { + border-left: 1px solid #cccccc; +} + +.tox .tox-tooltip { + display: inline-block; + padding: 8px; + position: relative; +} + +.tox .tox-tooltip__body { + background-color: #222f3e; + border-radius: 3px; + box-shadow: 0 2px 4px rgba(34, 47, 62, 0.3); + color: rgba(255, 255, 255, 0.75); + font-size: 14px; + font-style: normal; + font-weight: normal; + padding: 4px 8px; + text-transform: none; +} + +.tox .tox-tooltip__arrow { + position: absolute; +} + +.tox .tox-tooltip--down .tox-tooltip__arrow { + border-left: 8px solid transparent; + border-right: 8px solid transparent; + border-top: 8px solid #222f3e; + bottom: 0; + left: 50%; + position: absolute; + transform: translateX(-50%); +} + +.tox .tox-tooltip--up .tox-tooltip__arrow { + border-bottom: 8px solid #222f3e; + border-left: 8px solid transparent; + border-right: 8px solid transparent; + left: 50%; + position: absolute; + top: 0; + transform: translateX(-50%); +} + +.tox .tox-tooltip--right .tox-tooltip__arrow { + border-bottom: 8px solid transparent; + border-left: 8px solid #222f3e; + border-top: 8px solid transparent; + position: absolute; + right: 0; + top: 50%; + transform: translateY(-50%); +} + +.tox .tox-tooltip--left .tox-tooltip__arrow { + border-bottom: 8px solid transparent; + border-right: 8px solid #222f3e; + border-top: 8px solid transparent; + left: 0; + position: absolute; + top: 50%; + transform: translateY(-50%); +} + +.tox .tox-well { + border: 1px solid #cccccc; + border-radius: 3px; + padding: 8px; + width: 100%; +} + +.tox .tox-well > *:first-child { + margin-top: 0; +} + +.tox .tox-well > *:last-child { + margin-bottom: 0; +} + +.tox .tox-well > *:only-child { + margin: 0; +} + +.tox .tox-custom-editor { + border: 1px solid #cccccc; + border-radius: 3px; + display: flex; + flex: 1; + position: relative; +} + +/* stylelint-disable */ +.tox { + /* stylelint-enable */ +} + +.tox .tox-dialog-loading::before { + background-color: rgba(0, 0, 0, 0.5); + content: ""; + height: 100%; + position: absolute; + width: 100%; + z-index: 1000; +} + +.tox .tox-tab { + cursor: pointer; +} + +.tox .tox-dialog__content-js { + display: flex; + flex: 1; + -ms-flex-preferred-size: auto; +} + +.tox .tox-dialog__body-content .tox-collection { + display: flex; + flex: 1; + -ms-flex-preferred-size: auto; +} + +.tox .tox-image-tools-edit-panel { + height: 60px; +} + +.tox .tox-image-tools__sidebar { + height: 60px; +} diff --git a/frontend/public/tinymce-dataease-private/skins/ui/oxide/skin.min.css b/frontend/public/tinymce-dataease-private/skins/ui/oxide/skin.min.css new file mode 100644 index 0000000..143255f --- /dev/null +++ b/frontend/public/tinymce-dataease-private/skins/ui/oxide/skin.min.css @@ -0,0 +1,7 @@ +/** + * Copyright (c) Tiny Technologies, Inc. All rights reserved. + * Licensed under the LGPL or a commercial license. + * For LGPL see License.txt in the project root for license information. + * For commercial licenses see https://www.tiny.cloud/ + */ +.tox{box-shadow:none;box-sizing:content-box;color:#222f3e;cursor:auto;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Oxygen-Sans,Ubuntu,Cantarell,"Helvetica Neue",sans-serif;font-size:16px;font-style:normal;font-weight:400;line-height:normal;-webkit-tap-highlight-color:transparent;text-decoration:none;text-shadow:none;text-transform:none;vertical-align:initial;white-space:normal}.tox :not(svg):not(rect){box-sizing:inherit;color:inherit;cursor:inherit;direction:inherit;font-family:inherit;font-size:inherit;font-style:inherit;font-weight:inherit;line-height:inherit;-webkit-tap-highlight-color:inherit;text-align:inherit;text-decoration:inherit;text-shadow:inherit;text-transform:inherit;vertical-align:inherit;white-space:inherit}.tox :not(svg):not(rect){background:0 0;border:0;box-shadow:none;float:none;height:auto;margin:0;max-width:none;outline:0;padding:0;position:static;width:auto}.tox:not([dir=rtl]){direction:ltr;text-align:left}.tox[dir=rtl]{direction:rtl;text-align:right}.tox-tinymce{border:1px solid #ccc;border-radius:0;box-shadow:none;box-sizing:border-box;display:flex;flex-direction:column;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Oxygen-Sans,Ubuntu,Cantarell,"Helvetica Neue",sans-serif;overflow:hidden;position:relative;visibility:inherit!important}.tox-tinymce-inline{max-width:850px;border:none;box-shadow:none}.tox-tinymce-inline .tox-editor-header{background-color:transparent;border:1px solid #ccc;border-radius:0;box-shadow:none}.tox-tinymce-aux{font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Oxygen-Sans,Ubuntu,Cantarell,"Helvetica Neue",sans-serif;z-index:1300}.tox-tinymce :focus,.tox-tinymce-aux :focus{outline:0}button::-moz-focus-inner{border:0}.tox .accessibility-issue__header{align-items:center;display:flex;margin-bottom:4px}.tox .accessibility-issue__description{align-items:stretch;border:1px solid #ccc;border-radius:3px;display:flex;justify-content:space-between}.tox .accessibility-issue__description>div{padding-bottom:4px}.tox .accessibility-issue__description>div>div{align-items:center;display:flex;margin-bottom:4px}.tox .accessibility-issue__description>:last-child:not(:only-child){border-color:#ccc;border-style:solid}.tox .accessibility-issue__repair{margin-top:16px}.tox .tox-dialog__body-content .accessibility-issue--info .accessibility-issue__description{background-color:rgba(32,122,183,.1);border-color:rgba(32,122,183,.4);color:#222f3e}.tox .tox-dialog__body-content .accessibility-issue--info .accessibility-issue__description>:last-child{border-color:rgba(32,122,183,.4)}.tox .tox-dialog__body-content .accessibility-issue--info .tox-form__group h2{color:#207ab7}.tox .tox-dialog__body-content .accessibility-issue--info .tox-icon svg{fill:#207ab7}.tox .tox-dialog__body-content .accessibility-issue--info a .tox-icon{color:#207ab7}.tox .tox-dialog__body-content .accessibility-issue--warn .accessibility-issue__description{background-color:rgba(255,165,0,.1);border-color:rgba(255,165,0,.5);color:#222f3e}.tox .tox-dialog__body-content .accessibility-issue--warn .accessibility-issue__description>:last-child{border-color:rgba(255,165,0,.5)}.tox .tox-dialog__body-content .accessibility-issue--warn .tox-form__group h2{color:#cc8500}.tox .tox-dialog__body-content .accessibility-issue--warn .tox-icon svg{fill:#cc8500}.tox .tox-dialog__body-content .accessibility-issue--warn a .tox-icon{color:#cc8500}.tox .tox-dialog__body-content .accessibility-issue--error .accessibility-issue__description{background-color:rgba(204,0,0,.1);border-color:rgba(204,0,0,.4);color:#222f3e}.tox .tox-dialog__body-content .accessibility-issue--error .accessibility-issue__description>:last-child{border-color:rgba(204,0,0,.4)}.tox .tox-dialog__body-content .accessibility-issue--error .tox-form__group h2{color:#c00}.tox .tox-dialog__body-content .accessibility-issue--error .tox-icon svg{fill:#c00}.tox .tox-dialog__body-content .accessibility-issue--error a .tox-icon{color:#c00}.tox .tox-dialog__body-content .accessibility-issue--success .accessibility-issue__description{background-color:rgba(120,171,70,.1);border-color:rgba(120,171,70,.4);color:#222f3e}.tox .tox-dialog__body-content .accessibility-issue--success .accessibility-issue__description>:last-child{border-color:rgba(120,171,70,.4)}.tox .tox-dialog__body-content .accessibility-issue--success .tox-form__group h2{color:#78ab46}.tox .tox-dialog__body-content .accessibility-issue--success .tox-icon svg{fill:#78ab46}.tox .tox-dialog__body-content .accessibility-issue--success a .tox-icon{color:#78ab46}.tox .tox-dialog__body-content .accessibility-issue__header h1,.tox .tox-dialog__body-content .tox-form__group .accessibility-issue__description h2{margin-top:0}.tox:not([dir=rtl]) .tox-dialog__body-content .accessibility-issue__header .tox-button{margin-left:4px}.tox:not([dir=rtl]) .tox-dialog__body-content .accessibility-issue__header>:nth-last-child(2){margin-left:auto}.tox:not([dir=rtl]) .tox-dialog__body-content .accessibility-issue__description{padding:4px 4px 4px 8px}.tox:not([dir=rtl]) .tox-dialog__body-content .accessibility-issue__description>:last-child{border-left-width:1px;padding-left:4px}.tox[dir=rtl] .tox-dialog__body-content .accessibility-issue__header .tox-button{margin-right:4px}.tox[dir=rtl] .tox-dialog__body-content .accessibility-issue__header>:nth-last-child(2){margin-right:auto}.tox[dir=rtl] .tox-dialog__body-content .accessibility-issue__description{padding:4px 8px 4px 4px}.tox[dir=rtl] .tox-dialog__body-content .accessibility-issue__description>:last-child{border-right-width:1px;padding-right:4px}.tox .tox-anchorbar{display:flex;flex:0 0 auto}.tox .tox-bar{display:flex;flex:0 0 auto}.tox .tox-button{background-color:#207ab7;background-image:none;background-position:0 0;background-repeat:repeat;border-color:#207ab7;border-radius:3px;border-style:solid;border-width:1px;box-shadow:none;box-sizing:border-box;color:#fff;cursor:pointer;display:inline-block;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Oxygen-Sans,Ubuntu,Cantarell,"Helvetica Neue",sans-serif;font-size:14px;font-style:normal;font-weight:700;letter-spacing:normal;line-height:24px;margin:0;outline:0;padding:4px 16px;text-align:center;text-decoration:none;text-transform:none;white-space:nowrap}.tox .tox-button[disabled]{background-color:#207ab7;background-image:none;border-color:#207ab7;box-shadow:none;color:rgba(255,255,255,.5);cursor:not-allowed}.tox .tox-button:focus:not(:disabled){background-color:#1c6ca1;background-image:none;border-color:#1c6ca1;box-shadow:none;color:#fff}.tox .tox-button:hover:not(:disabled){background-color:#1c6ca1;background-image:none;border-color:#1c6ca1;box-shadow:none;color:#fff}.tox .tox-button:active:not(:disabled){background-color:#185d8c;background-image:none;border-color:#185d8c;box-shadow:none;color:#fff}.tox .tox-button--secondary{background-color:#f0f0f0;background-image:none;background-position:0 0;background-repeat:repeat;border-color:#f0f0f0;border-radius:3px;border-style:solid;border-width:1px;box-shadow:none;color:#222f3e;font-size:14px;font-style:normal;font-weight:700;letter-spacing:normal;outline:0;padding:4px 16px;text-decoration:none;text-transform:none}.tox .tox-button--secondary[disabled]{background-color:#f0f0f0;background-image:none;border-color:#f0f0f0;box-shadow:none;color:rgba(34,47,62,.5)}.tox .tox-button--secondary:focus:not(:disabled){background-color:#e3e3e3;background-image:none;border-color:#e3e3e3;box-shadow:none;color:#222f3e}.tox .tox-button--secondary:hover:not(:disabled){background-color:#e3e3e3;background-image:none;border-color:#e3e3e3;box-shadow:none;color:#222f3e}.tox .tox-button--secondary:active:not(:disabled){background-color:#d6d6d6;background-image:none;border-color:#d6d6d6;box-shadow:none;color:#222f3e}.tox .tox-button--icon,.tox .tox-button.tox-button--icon,.tox .tox-button.tox-button--secondary.tox-button--icon{padding:4px}.tox .tox-button--icon .tox-icon svg,.tox .tox-button.tox-button--icon .tox-icon svg,.tox .tox-button.tox-button--secondary.tox-button--icon .tox-icon svg{display:block;fill:currentColor}.tox .tox-button-link{background:0;border:none;box-sizing:border-box;cursor:pointer;display:inline-block;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Oxygen-Sans,Ubuntu,Cantarell,"Helvetica Neue",sans-serif;font-size:16px;font-weight:400;line-height:1.3;margin:0;padding:0;white-space:nowrap}.tox .tox-button-link--sm{font-size:14px}.tox .tox-button--naked{background-color:transparent;border-color:transparent;box-shadow:unset;color:#222f3e}.tox .tox-button--naked[disabled]{background-color:#f0f0f0;border-color:#f0f0f0;box-shadow:none;color:rgba(34,47,62,.5)}.tox .tox-button--naked:hover:not(:disabled){background-color:#e3e3e3;border-color:#e3e3e3;box-shadow:none;color:#222f3e}.tox .tox-button--naked:focus:not(:disabled){background-color:#e3e3e3;border-color:#e3e3e3;box-shadow:none;color:#222f3e}.tox .tox-button--naked:active:not(:disabled){background-color:#d6d6d6;border-color:#d6d6d6;box-shadow:none;color:#222f3e}.tox .tox-button--naked .tox-icon svg{fill:currentColor}.tox .tox-button--naked.tox-button--icon:hover:not(:disabled){color:#222f3e}.tox .tox-checkbox{align-items:center;border-radius:3px;cursor:pointer;display:flex;height:36px;min-width:36px}.tox .tox-checkbox__input{height:1px;overflow:hidden;position:absolute;top:auto;width:1px}.tox .tox-checkbox__icons{align-items:center;border-radius:3px;box-shadow:0 0 0 2px transparent;box-sizing:content-box;display:flex;height:24px;justify-content:center;padding:calc(4px - 1px);width:24px}.tox .tox-checkbox__icons .tox-checkbox-icon__unchecked svg{display:block;fill:rgba(34,47,62,.3)}.tox .tox-checkbox__icons .tox-checkbox-icon__indeterminate svg{display:none;fill:#207ab7}.tox .tox-checkbox__icons .tox-checkbox-icon__checked svg{display:none;fill:#207ab7}.tox .tox-checkbox--disabled{color:rgba(34,47,62,.5);cursor:not-allowed}.tox .tox-checkbox--disabled .tox-checkbox__icons .tox-checkbox-icon__checked svg{fill:rgba(34,47,62,.5)}.tox .tox-checkbox--disabled .tox-checkbox__icons .tox-checkbox-icon__unchecked svg{fill:rgba(34,47,62,.5)}.tox .tox-checkbox--disabled .tox-checkbox__icons .tox-checkbox-icon__indeterminate svg{fill:rgba(34,47,62,.5)}.tox input.tox-checkbox__input:checked+.tox-checkbox__icons .tox-checkbox-icon__unchecked svg{display:none}.tox input.tox-checkbox__input:checked+.tox-checkbox__icons .tox-checkbox-icon__checked svg{display:block}.tox input.tox-checkbox__input:indeterminate+.tox-checkbox__icons .tox-checkbox-icon__unchecked svg{display:none}.tox input.tox-checkbox__input:indeterminate+.tox-checkbox__icons .tox-checkbox-icon__indeterminate svg{display:block}.tox input.tox-checkbox__input:focus+.tox-checkbox__icons{border-radius:3px;box-shadow:inset 0 0 0 1px #207ab7;padding:calc(4px - 1px)}.tox:not([dir=rtl]) .tox-checkbox__label{margin-left:4px}.tox:not([dir=rtl]) .tox-checkbox__input{left:-10000px}.tox:not([dir=rtl]) .tox-bar .tox-checkbox{margin-left:4px}.tox[dir=rtl] .tox-checkbox__label{margin-right:4px}.tox[dir=rtl] .tox-checkbox__input{right:-10000px}.tox[dir=rtl] .tox-bar .tox-checkbox{margin-right:4px}.tox .tox-collection--toolbar .tox-collection__group{display:flex;padding:0}.tox .tox-collection--grid .tox-collection__group{display:flex;flex-wrap:wrap;max-height:208px;overflow-x:hidden;overflow-y:auto;padding:0}.tox .tox-collection--list .tox-collection__group{border-bottom-width:0;border-color:#ccc;border-left-width:0;border-right-width:0;border-style:solid;border-top-width:1px;padding:4px 0}.tox .tox-collection--list .tox-collection__group:first-child{border-top-width:0}.tox .tox-collection__group-heading{background-color:#e6e6e6;color:rgba(34,47,62,.7);cursor:default;font-size:12px;font-style:normal;font-weight:400;margin-bottom:4px;margin-top:-4px;padding:4px 8px;text-transform:none;-webkit-touch-callout:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.tox .tox-collection__item{align-items:center;color:#222f3e;cursor:pointer;display:flex;-webkit-touch-callout:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.tox .tox-collection--list .tox-collection__item{padding:4px 8px}.tox .tox-collection--toolbar .tox-collection__item{border-radius:3px;padding:4px}.tox .tox-collection--grid .tox-collection__item{border-radius:3px;padding:4px}.tox .tox-collection--list .tox-collection__item--enabled{background-color:#fff;color:#222f3e}.tox .tox-collection--list .tox-collection__item--active{background-color:#dee0e2}.tox .tox-collection--toolbar .tox-collection__item--enabled{background-color:#c8cbcf;color:#222f3e}.tox .tox-collection--toolbar .tox-collection__item--active{background-color:#dee0e2}.tox .tox-collection--grid .tox-collection__item--enabled{background-color:#c8cbcf;color:#222f3e}.tox .tox-collection--grid .tox-collection__item--active:not(.tox-collection__item--state-disabled){background-color:#dee0e2;color:#222f3e}.tox .tox-collection--list .tox-collection__item--active:not(.tox-collection__item--state-disabled){color:#222f3e}.tox .tox-collection--toolbar .tox-collection__item--active:not(.tox-collection__item--state-disabled){color:#222f3e}.tox .tox-collection__item--state-disabled{background-color:transparent;color:rgba(34,47,62,.5);cursor:not-allowed}.tox .tox-collection__item-checkmark,.tox .tox-collection__item-icon{align-items:center;display:flex;height:24px;justify-content:center;width:24px}.tox .tox-collection__item-checkmark svg,.tox .tox-collection__item-icon svg{fill:currentColor}.tox .tox-collection--toolbar-lg .tox-collection__item-icon{height:48px;width:48px}.tox .tox-collection__item-label{color:currentColor;display:inline-block;flex:1;-ms-flex-preferred-size:auto;font-size:14px;font-style:normal;font-weight:400;line-height:24px;text-transform:none;word-break:break-all}.tox .tox-collection__item-accessory{color:rgba(34,47,62,.7);display:inline-block;font-size:14px;height:24px;line-height:24px;text-transform:none}.tox .tox-collection__item-caret{align-items:center;display:flex;min-height:24px}.tox .tox-collection__item-caret::after{content:'';font-size:0;min-height:inherit}.tox .tox-collection__item-caret svg{fill:#222f3e}.tox .tox-collection--list .tox-collection__item:not(.tox-collection__item--enabled) .tox-collection__item-checkmark svg{display:none}.tox .tox-collection--list .tox-collection__item:not(.tox-collection__item--enabled) .tox-collection__item-accessory+.tox-collection__item-checkmark{display:none}.tox .tox-collection--horizontal{background-color:#fff;border:1px solid #ccc;border-radius:3px;box-shadow:0 1px 3px rgba(0,0,0,.15);display:flex;flex:0 0 auto;flex-shrink:0;flex-wrap:nowrap;margin-bottom:0;overflow-x:auto;padding:0}.tox .tox-collection--horizontal .tox-collection__group{align-items:center;display:flex;flex-wrap:nowrap;margin:0;padding:0 4px}.tox .tox-collection--horizontal .tox-collection__item{height:34px;margin:2px 0 3px 0;padding:0 4px}.tox .tox-collection--horizontal .tox-collection__item-label{white-space:nowrap}.tox .tox-collection--horizontal .tox-collection__item-caret{margin-left:4px}.tox .tox-collection__item-container{display:flex}.tox .tox-collection__item-container--row{align-items:center;flex:1 1 auto;flex-direction:row}.tox .tox-collection__item-container--row.tox-collection__item-container--align-left{margin-right:auto}.tox .tox-collection__item-container--row.tox-collection__item-container--align-right{justify-content:flex-end;margin-left:auto}.tox .tox-collection__item-container--row.tox-collection__item-container--valign-top{align-items:flex-start;margin-bottom:auto}.tox .tox-collection__item-container--row.tox-collection__item-container--valign-middle{align-items:center}.tox .tox-collection__item-container--row.tox-collection__item-container--valign-bottom{align-items:flex-end;margin-top:auto}.tox .tox-collection__item-container--column{-ms-grid-row-align:center;align-self:center;flex:1 1 auto;flex-direction:column}.tox .tox-collection__item-container--column.tox-collection__item-container--align-left{align-items:flex-start}.tox .tox-collection__item-container--column.tox-collection__item-container--align-right{align-items:flex-end}.tox .tox-collection__item-container--column.tox-collection__item-container--valign-top{align-self:flex-start}.tox .tox-collection__item-container--column.tox-collection__item-container--valign-middle{-ms-grid-row-align:center;align-self:center}.tox .tox-collection__item-container--column.tox-collection__item-container--valign-bottom{align-self:flex-end}.tox:not([dir=rtl]) .tox-collection--horizontal .tox-collection__group:not(:last-of-type){border-right:1px solid #ccc}.tox:not([dir=rtl]) .tox-collection--list .tox-collection__item>:not(:first-child){margin-left:8px}.tox:not([dir=rtl]) .tox-collection--list .tox-collection__item>.tox-collection__item-label:first-child{margin-left:4px}.tox:not([dir=rtl]) .tox-collection__item-accessory{margin-left:16px;text-align:right}.tox:not([dir=rtl]) .tox-collection .tox-collection__item-caret{margin-left:16px}.tox[dir=rtl] .tox-collection--horizontal .tox-collection__group:not(:last-of-type){border-left:1px solid #ccc}.tox[dir=rtl] .tox-collection--list .tox-collection__item>:not(:first-child){margin-right:8px}.tox[dir=rtl] .tox-collection--list .tox-collection__item>.tox-collection__item-label:first-child{margin-right:4px}.tox[dir=rtl] .tox-collection__item-icon-rtl .tox-collection__item-icon svg{transform:rotateY(180deg)}.tox[dir=rtl] .tox-collection__item-accessory{margin-right:16px;text-align:left}.tox[dir=rtl] .tox-collection .tox-collection__item-caret{margin-right:16px;transform:rotateY(180deg)}.tox[dir=rtl] .tox-collection--horizontal .tox-collection__item-caret{margin-right:4px}.tox .tox-color-picker-container{display:flex;flex-direction:row;height:225px;margin:0}.tox .tox-sv-palette{box-sizing:border-box;display:flex;height:100%}.tox .tox-sv-palette-spectrum{height:100%}.tox .tox-sv-palette,.tox .tox-sv-palette-spectrum{width:225px}.tox .tox-sv-palette-thumb{background:0 0;border:1px solid #000;border-radius:50%;box-sizing:content-box;height:12px;position:absolute;width:12px}.tox .tox-sv-palette-inner-thumb{border:1px solid #fff;border-radius:50%;height:10px;position:absolute;width:10px}.tox .tox-hue-slider{box-sizing:border-box;height:100%;width:25px}.tox .tox-hue-slider-spectrum{background:linear-gradient(to bottom,red,#ff0080,#f0f,#8000ff,#00f,#0080ff,#0ff,#00ff80,#0f0,#80ff00,#ff0,#ff8000,red);height:100%;width:100%}.tox .tox-hue-slider,.tox .tox-hue-slider-spectrum{width:20px}.tox .tox-hue-slider-thumb{background:#fff;border:1px solid #000;box-sizing:content-box;height:4px;width:100%}.tox .tox-rgb-form{display:flex;flex-direction:column;justify-content:space-between}.tox .tox-rgb-form div{align-items:center;display:flex;justify-content:space-between;margin-bottom:5px;width:inherit}.tox .tox-rgb-form input{width:6em}.tox .tox-rgb-form input.tox-invalid{border:1px solid red!important}.tox .tox-rgb-form .tox-rgba-preview{border:1px solid #000;flex-grow:2;margin-bottom:0}.tox:not([dir=rtl]) .tox-sv-palette{margin-right:15px}.tox:not([dir=rtl]) .tox-hue-slider{margin-right:15px}.tox:not([dir=rtl]) .tox-hue-slider-thumb{margin-left:-1px}.tox:not([dir=rtl]) .tox-rgb-form label{margin-right:.5em}.tox[dir=rtl] .tox-sv-palette{margin-left:15px}.tox[dir=rtl] .tox-hue-slider{margin-left:15px}.tox[dir=rtl] .tox-hue-slider-thumb{margin-right:-1px}.tox[dir=rtl] .tox-rgb-form label{margin-left:.5em}.tox .tox-toolbar .tox-swatches,.tox .tox-toolbar__overflow .tox-swatches,.tox .tox-toolbar__primary .tox-swatches{margin:2px 0 3px 4px}.tox .tox-collection--list .tox-collection__group .tox-swatches-menu{border:0;margin:-4px 0}.tox .tox-swatches__row{display:flex}.tox .tox-swatch{height:30px;transition:transform .15s,box-shadow .15s;width:30px}.tox .tox-swatch:focus,.tox .tox-swatch:hover{box-shadow:0 0 0 1px rgba(127,127,127,.3) inset;transform:scale(.8)}.tox .tox-swatch--remove{align-items:center;display:flex;justify-content:center}.tox .tox-swatch--remove svg path{stroke:#e74c3c}.tox .tox-swatches__picker-btn{align-items:center;background-color:transparent;border:0;cursor:pointer;display:flex;height:30px;justify-content:center;outline:0;padding:0;width:30px}.tox .tox-swatches__picker-btn svg{height:24px;width:24px}.tox .tox-swatches__picker-btn:hover{background:#dee0e2}.tox:not([dir=rtl]) .tox-swatches__picker-btn{margin-left:auto}.tox[dir=rtl] .tox-swatches__picker-btn{margin-right:auto}.tox .tox-comment-thread{background:#fff;position:relative}.tox .tox-comment-thread>:not(:first-child){margin-top:8px}.tox .tox-comment{background:#fff;border:1px solid #ccc;border-radius:3px;box-shadow:0 4px 8px 0 rgba(34,47,62,.1);padding:8px 8px 16px 8px;position:relative}.tox .tox-comment__header{align-items:center;color:#222f3e;display:flex;justify-content:space-between}.tox .tox-comment__date{color:rgba(34,47,62,.7);font-size:12px}.tox .tox-comment__body{color:#222f3e;font-size:14px;font-style:normal;font-weight:400;line-height:1.3;margin-top:8px;position:relative;text-transform:initial}.tox .tox-comment__body textarea{resize:none;white-space:normal;width:100%}.tox .tox-comment__expander{padding-top:8px}.tox .tox-comment__expander p{color:rgba(34,47,62,.7);font-size:14px;font-style:normal}.tox .tox-comment__body p{margin:0}.tox .tox-comment__buttonspacing{padding-top:16px;text-align:center}.tox .tox-comment-thread__overlay::after{background:#fff;bottom:0;content:"";display:flex;left:0;opacity:.9;position:absolute;right:0;top:0;z-index:5}.tox .tox-comment__reply{display:flex;flex-shrink:0;flex-wrap:wrap;justify-content:flex-end;margin-top:8px}.tox .tox-comment__reply>:first-child{margin-bottom:8px;width:100%}.tox .tox-comment__edit{display:flex;flex-wrap:wrap;justify-content:flex-end;margin-top:16px}.tox .tox-comment__gradient::after{background:linear-gradient(rgba(255,255,255,0),#fff);bottom:0;content:"";display:block;height:5em;margin-top:-40px;position:absolute;width:100%}.tox .tox-comment__overlay{background:#fff;bottom:0;display:flex;flex-direction:column;flex-grow:1;left:0;opacity:.9;position:absolute;right:0;text-align:center;top:0;z-index:5}.tox .tox-comment__loading-text{align-items:center;color:#222f3e;display:flex;flex-direction:column;position:relative}.tox .tox-comment__loading-text>div{padding-bottom:16px}.tox .tox-comment__overlaytext{bottom:0;flex-direction:column;font-size:14px;left:0;padding:1em;position:absolute;right:0;top:0;z-index:10}.tox .tox-comment__overlaytext p{background-color:#fff;box-shadow:0 0 8px 8px #fff;color:#222f3e;text-align:center}.tox .tox-comment__overlaytext div:nth-of-type(2){font-size:.8em}.tox .tox-comment__busy-spinner{align-items:center;background-color:#fff;bottom:0;display:flex;justify-content:center;left:0;position:absolute;right:0;top:0;z-index:20}.tox .tox-comment__scroll{display:flex;flex-direction:column;flex-shrink:1;overflow:auto}.tox .tox-conversations{margin:8px}.tox:not([dir=rtl]) .tox-comment__edit{margin-left:8px}.tox:not([dir=rtl]) .tox-comment__buttonspacing>:last-child,.tox:not([dir=rtl]) .tox-comment__edit>:last-child,.tox:not([dir=rtl]) .tox-comment__reply>:last-child{margin-left:8px}.tox[dir=rtl] .tox-comment__edit{margin-right:8px}.tox[dir=rtl] .tox-comment__buttonspacing>:last-child,.tox[dir=rtl] .tox-comment__edit>:last-child,.tox[dir=rtl] .tox-comment__reply>:last-child{margin-right:8px}.tox .tox-user{align-items:center;display:flex}.tox .tox-user__avatar svg{fill:rgba(34,47,62,.7)}.tox .tox-user__name{color:rgba(34,47,62,.7);font-size:12px;font-style:normal;font-weight:700;text-transform:uppercase}.tox:not([dir=rtl]) .tox-user__avatar svg{margin-right:8px}.tox:not([dir=rtl]) .tox-user__avatar+.tox-user__name{margin-left:8px}.tox[dir=rtl] .tox-user__avatar svg{margin-left:8px}.tox[dir=rtl] .tox-user__avatar+.tox-user__name{margin-right:8px}.tox .tox-dialog-wrap{align-items:center;bottom:0;display:flex;justify-content:center;left:0;position:fixed;right:0;top:0;z-index:1100}.tox .tox-dialog-wrap__backdrop{background-color:rgba(255,255,255,.75);bottom:0;left:0;position:absolute;right:0;top:0;z-index:1}.tox .tox-dialog-wrap__backdrop--opaque{background-color:#fff}.tox .tox-dialog{background-color:#fff;border-color:#ccc;border-radius:3px;border-style:solid;border-width:1px;box-shadow:0 16px 16px -10px rgba(34,47,62,.15),0 0 40px 1px rgba(34,47,62,.15);display:flex;flex-direction:column;max-height:100%;max-width:480px;overflow:hidden;position:relative;width:95vw;z-index:2}@media only screen and (max-width:767px){body:not(.tox-force-desktop) .tox .tox-dialog{align-self:flex-start;margin:8px auto;width:calc(100vw - 16px)}}.tox .tox-dialog-inline{z-index:1100}.tox .tox-dialog__header{align-items:center;background-color:#fff;border-bottom:none;color:#222f3e;display:flex;font-size:16px;justify-content:space-between;padding:8px 16px 0 16px;position:relative}.tox .tox-dialog__header .tox-button{z-index:1}.tox .tox-dialog__draghandle{cursor:grab;height:100%;left:0;position:absolute;top:0;width:100%}.tox .tox-dialog__draghandle:active{cursor:grabbing}.tox .tox-dialog__dismiss{margin-left:auto}.tox .tox-dialog__title{font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Oxygen-Sans,Ubuntu,Cantarell,"Helvetica Neue",sans-serif;font-size:20px;font-style:normal;font-weight:400;line-height:1.3;margin:0;text-transform:none}.tox .tox-dialog__body{color:#222f3e;display:flex;flex:1;-ms-flex-preferred-size:auto;font-size:16px;font-style:normal;font-weight:400;line-height:1.3;min-width:0;text-align:left;text-transform:none}@media only screen and (max-width:767px){body:not(.tox-force-desktop) .tox .tox-dialog__body{flex-direction:column}}.tox .tox-dialog__body-nav{align-items:flex-start;display:flex;flex-direction:column;padding:16px 16px}@media only screen and (max-width:767px){body:not(.tox-force-desktop) .tox .tox-dialog__body-nav{flex-direction:row;-webkit-overflow-scrolling:touch;overflow-x:auto;padding-bottom:0}}.tox .tox-dialog__body-nav-item{border-bottom:2px solid transparent;color:rgba(34,47,62,.7);display:inline-block;font-size:14px;line-height:1.3;margin-bottom:8px;text-decoration:none;white-space:nowrap}.tox .tox-dialog__body-nav-item:focus{background-color:rgba(32,122,183,.1)}.tox .tox-dialog__body-nav-item--active{border-bottom:2px solid #207ab7;color:#207ab7}.tox .tox-dialog__body-content{box-sizing:border-box;display:flex;flex:1;flex-direction:column;-ms-flex-preferred-size:auto;max-height:650px;overflow:auto;-webkit-overflow-scrolling:touch;padding:16px 16px}.tox .tox-dialog__body-content>*{margin-bottom:0;margin-top:16px}.tox .tox-dialog__body-content>:first-child{margin-top:0}.tox .tox-dialog__body-content>:last-child{margin-bottom:0}.tox .tox-dialog__body-content>:only-child{margin-bottom:0;margin-top:0}.tox .tox-dialog__body-content a{color:#207ab7;cursor:pointer;text-decoration:none}.tox .tox-dialog__body-content a:focus,.tox .tox-dialog__body-content a:hover{color:#185d8c;text-decoration:none}.tox .tox-dialog__body-content a:active{color:#185d8c;text-decoration:none}.tox .tox-dialog__body-content svg{fill:#222f3e}.tox .tox-dialog__body-content ul{display:block;list-style-type:disc;margin-bottom:16px;-webkit-margin-end:0;margin-inline-end:0;-webkit-margin-start:0;margin-inline-start:0;-webkit-padding-start:2.5rem;padding-inline-start:2.5rem}.tox .tox-dialog__body-content .tox-form__group h1{color:#222f3e;font-size:20px;font-style:normal;font-weight:700;letter-spacing:normal;margin-bottom:16px;margin-top:2rem;text-transform:none}.tox .tox-dialog__body-content .tox-form__group h2{color:#222f3e;font-size:16px;font-style:normal;font-weight:700;letter-spacing:normal;margin-bottom:16px;margin-top:2rem;text-transform:none}.tox .tox-dialog__body-content .tox-form__group p{margin-bottom:16px}.tox .tox-dialog__body-content .tox-form__group h1:first-child,.tox .tox-dialog__body-content .tox-form__group h2:first-child,.tox .tox-dialog__body-content .tox-form__group p:first-child{margin-top:0}.tox .tox-dialog__body-content .tox-form__group h1:last-child,.tox .tox-dialog__body-content .tox-form__group h2:last-child,.tox .tox-dialog__body-content .tox-form__group p:last-child{margin-bottom:0}.tox .tox-dialog__body-content .tox-form__group h1:only-child,.tox .tox-dialog__body-content .tox-form__group h2:only-child,.tox .tox-dialog__body-content .tox-form__group p:only-child{margin-bottom:0;margin-top:0}.tox .tox-dialog--width-lg{height:650px;max-width:1200px}.tox .tox-dialog--width-md{max-width:800px}.tox .tox-dialog--width-md .tox-dialog__body-content{overflow:auto}.tox .tox-dialog__body-content--centered{text-align:center}.tox .tox-dialog__footer{align-items:center;background-color:#fff;border-top:1px solid #ccc;display:flex;justify-content:space-between;padding:8px 16px}.tox .tox-dialog__footer-end,.tox .tox-dialog__footer-start{display:flex}.tox .tox-dialog__busy-spinner{align-items:center;background-color:rgba(255,255,255,.75);bottom:0;display:flex;justify-content:center;left:0;position:absolute;right:0;top:0;z-index:3}.tox .tox-dialog__table{border-collapse:collapse;width:100%}.tox .tox-dialog__table thead th{font-weight:700;padding-bottom:8px}.tox .tox-dialog__table tbody tr{border-bottom:1px solid #ccc}.tox .tox-dialog__table tbody tr:last-child{border-bottom:none}.tox .tox-dialog__table td{padding-bottom:8px;padding-top:8px}.tox .tox-dialog__popups{position:absolute;width:100%;z-index:1100}.tox .tox-dialog__body-iframe{display:flex;flex:1;flex-direction:column;-ms-flex-preferred-size:auto}.tox .tox-dialog__body-iframe .tox-navobj{display:flex;flex:1;-ms-flex-preferred-size:auto}.tox .tox-dialog__body-iframe .tox-navobj :nth-child(2){flex:1;-ms-flex-preferred-size:auto;height:100%}.tox .tox-dialog-dock-fadeout{opacity:0;visibility:hidden}.tox .tox-dialog-dock-fadein{opacity:1;visibility:visible}.tox .tox-dialog-dock-transition{transition:visibility 0s linear .3s,opacity .3s ease}.tox .tox-dialog-dock-transition.tox-dialog-dock-fadein{transition-delay:0s}.tox.tox-platform-ie .tox-dialog-wrap{position:-ms-device-fixed}@media only screen and (max-width:767px){body:not(.tox-force-desktop) .tox:not([dir=rtl]) .tox-dialog__body-nav{margin-right:0}}@media only screen and (max-width:767px){body:not(.tox-force-desktop) .tox:not([dir=rtl]) .tox-dialog__body-nav-item:not(:first-child){margin-left:8px}}.tox:not([dir=rtl]) .tox-dialog__footer .tox-dialog__footer-end>*,.tox:not([dir=rtl]) .tox-dialog__footer .tox-dialog__footer-start>*{margin-left:8px}.tox[dir=rtl] .tox-dialog__body{text-align:right}@media only screen and (max-width:767px){body:not(.tox-force-desktop) .tox[dir=rtl] .tox-dialog__body-nav{margin-left:0}}@media only screen and (max-width:767px){body:not(.tox-force-desktop) .tox[dir=rtl] .tox-dialog__body-nav-item:not(:first-child){margin-right:8px}}.tox[dir=rtl] .tox-dialog__footer .tox-dialog__footer-end>*,.tox[dir=rtl] .tox-dialog__footer .tox-dialog__footer-start>*{margin-right:8px}body.tox-dialog__disable-scroll{overflow:hidden}.tox .tox-dropzone-container{display:flex;flex:1;-ms-flex-preferred-size:auto}.tox .tox-dropzone{align-items:center;background:#fff;border:2px dashed #ccc;box-sizing:border-box;display:flex;flex-direction:column;flex-grow:1;justify-content:center;min-height:100px;padding:10px}.tox .tox-dropzone p{color:rgba(34,47,62,.7);margin:0 0 16px 0}.tox .tox-edit-area{display:flex;flex:1;-ms-flex-preferred-size:auto;overflow:hidden;position:relative}.tox .tox-edit-area__iframe{background-color:#fff;border:0;box-sizing:border-box;flex:1;-ms-flex-preferred-size:auto;height:100%;position:absolute;width:100%}.tox.tox-inline-edit-area{border:1px dotted #ccc}.tox .tox-editor-container{display:flex;flex:1 1 auto;flex-direction:column;overflow:hidden}.tox .tox-editor-header{z-index:1000}.tox:not(.tox-tinymce-inline) .tox-editor-header{box-shadow:none;transition:box-shadow .5s}.tox.tox-tinymce--toolbar-bottom .tox-editor-header,.tox.tox-tinymce-inline .tox-editor-header{margin-bottom:-1px}.tox.tox-tinymce--toolbar-sticky-on .tox-editor-header{background-color:transparent;box-shadow:0 4px 4px -3px rgba(0,0,0,.25)}.tox-editor-dock-fadeout{opacity:0;visibility:hidden}.tox-editor-dock-fadein{opacity:1;visibility:visible}.tox-editor-dock-transition{transition:visibility 0s linear .25s,opacity .25s ease}.tox-editor-dock-transition.tox-editor-dock-fadein{transition-delay:0s}.tox .tox-control-wrap{flex:1;position:relative}.tox .tox-control-wrap:not(.tox-control-wrap--status-invalid) .tox-control-wrap__status-icon-invalid,.tox .tox-control-wrap:not(.tox-control-wrap--status-unknown) .tox-control-wrap__status-icon-unknown,.tox .tox-control-wrap:not(.tox-control-wrap--status-valid) .tox-control-wrap__status-icon-valid{display:none}.tox .tox-control-wrap svg{display:block}.tox .tox-control-wrap__status-icon-wrap{position:absolute;top:50%;transform:translateY(-50%)}.tox .tox-control-wrap__status-icon-invalid svg{fill:#c00}.tox .tox-control-wrap__status-icon-unknown svg{fill:orange}.tox .tox-control-wrap__status-icon-valid svg{fill:green}.tox:not([dir=rtl]) .tox-control-wrap--status-invalid .tox-textfield,.tox:not([dir=rtl]) .tox-control-wrap--status-unknown .tox-textfield,.tox:not([dir=rtl]) .tox-control-wrap--status-valid .tox-textfield{padding-right:32px}.tox:not([dir=rtl]) .tox-control-wrap__status-icon-wrap{right:4px}.tox[dir=rtl] .tox-control-wrap--status-invalid .tox-textfield,.tox[dir=rtl] .tox-control-wrap--status-unknown .tox-textfield,.tox[dir=rtl] .tox-control-wrap--status-valid .tox-textfield{padding-left:32px}.tox[dir=rtl] .tox-control-wrap__status-icon-wrap{left:4px}.tox .tox-autocompleter{max-width:25em}.tox .tox-autocompleter .tox-menu{max-width:25em}.tox .tox-autocompleter .tox-autocompleter-highlight{font-weight:700}.tox .tox-color-input{display:flex;position:relative;z-index:1}.tox .tox-color-input .tox-textfield{z-index:-1}.tox .tox-color-input span{border-color:rgba(34,47,62,.2);border-radius:3px;border-style:solid;border-width:1px;box-shadow:none;box-sizing:border-box;height:24px;position:absolute;top:6px;width:24px}.tox .tox-color-input span:focus:not([aria-disabled=true]),.tox .tox-color-input span:hover:not([aria-disabled=true]){border-color:#207ab7;cursor:pointer}.tox .tox-color-input span::before{background-image:linear-gradient(45deg,rgba(0,0,0,.25) 25%,transparent 25%),linear-gradient(-45deg,rgba(0,0,0,.25) 25%,transparent 25%),linear-gradient(45deg,transparent 75%,rgba(0,0,0,.25) 75%),linear-gradient(-45deg,transparent 75%,rgba(0,0,0,.25) 75%);background-position:0 0,0 6px,6px -6px,-6px 0;background-size:12px 12px;border:1px solid #fff;border-radius:3px;box-sizing:border-box;content:'';height:24px;left:-1px;position:absolute;top:-1px;width:24px;z-index:-1}.tox .tox-color-input span[aria-disabled=true]{cursor:not-allowed}.tox:not([dir=rtl]) .tox-color-input .tox-textfield{padding-left:36px}.tox:not([dir=rtl]) .tox-color-input span{left:6px}.tox[dir=rtl] .tox-color-input .tox-textfield{padding-right:36px}.tox[dir=rtl] .tox-color-input span{right:6px}.tox .tox-label,.tox .tox-toolbar-label{color:rgba(34,47,62,.7);display:block;font-size:14px;font-style:normal;font-weight:400;line-height:1.3;padding:0 8px 0 0;text-transform:none;white-space:nowrap}.tox .tox-toolbar-label{padding:0 8px}.tox[dir=rtl] .tox-label{padding:0 0 0 8px}.tox .tox-form{display:flex;flex:1;flex-direction:column;-ms-flex-preferred-size:auto}.tox .tox-form__group{box-sizing:border-box;margin-bottom:4px}.tox .tox-form-group--maximize{flex:1}.tox .tox-form__group--error{color:#c00}.tox .tox-form__group--collection{display:flex}.tox .tox-form__grid{display:flex;flex-direction:row;flex-wrap:wrap;justify-content:space-between}.tox .tox-form__grid--2col>.tox-form__group{width:calc(50% - (8px / 2))}.tox .tox-form__grid--3col>.tox-form__group{width:calc(100% / 3 - (8px / 2))}.tox .tox-form__grid--4col>.tox-form__group{width:calc(25% - (8px / 2))}.tox .tox-form__controls-h-stack{align-items:center;display:flex}.tox .tox-form__group--inline{align-items:center;display:flex}.tox .tox-form__group--stretched{display:flex;flex:1;flex-direction:column;-ms-flex-preferred-size:auto}.tox .tox-form__group--stretched .tox-textarea{flex:1;-ms-flex-preferred-size:auto}.tox .tox-form__group--stretched .tox-navobj{display:flex;flex:1;-ms-flex-preferred-size:auto}.tox .tox-form__group--stretched .tox-navobj :nth-child(2){flex:1;-ms-flex-preferred-size:auto;height:100%}.tox:not([dir=rtl]) .tox-form__controls-h-stack>:not(:first-child){margin-left:4px}.tox[dir=rtl] .tox-form__controls-h-stack>:not(:first-child){margin-right:4px}.tox .tox-lock.tox-locked .tox-lock-icon__unlock,.tox .tox-lock:not(.tox-locked) .tox-lock-icon__lock{display:none}.tox .tox-listboxfield .tox-listbox--select,.tox .tox-textarea,.tox .tox-textfield,.tox .tox-toolbar-textfield{-webkit-appearance:none;-moz-appearance:none;appearance:none;background-color:#fff;border-color:#ccc;border-radius:3px;border-style:solid;border-width:1px;box-shadow:none;box-sizing:border-box;color:#222f3e;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Oxygen-Sans,Ubuntu,Cantarell,"Helvetica Neue",sans-serif;font-size:16px;line-height:24px;margin:0;min-height:34px;outline:0;padding:5px 4.75px;resize:none;width:100%}.tox .tox-textarea[disabled],.tox .tox-textfield[disabled]{background-color:#f2f2f2;color:rgba(34,47,62,.85);cursor:not-allowed}.tox .tox-listboxfield .tox-listbox--select:focus,.tox .tox-textarea:focus,.tox .tox-textfield:focus{background-color:#fff;border-color:#207ab7;box-shadow:none;outline:0}.tox .tox-toolbar-textfield{border-width:0;margin-bottom:3px;margin-top:2px;max-width:250px}.tox .tox-naked-btn{background-color:transparent;border:0;border-color:transparent;box-shadow:unset;color:#207ab7;cursor:pointer;display:block;margin:0;padding:0}.tox .tox-naked-btn svg{display:block;fill:#222f3e}.tox:not([dir=rtl]) .tox-toolbar-textfield+*{margin-left:4px}.tox[dir=rtl] .tox-toolbar-textfield+*{margin-right:4px}.tox .tox-listboxfield{cursor:pointer;position:relative}.tox .tox-listboxfield .tox-listbox--select[disabled]{background-color:#f2f2f2;color:rgba(34,47,62,.85);cursor:not-allowed}.tox .tox-listbox__select-label{cursor:default;flex:1;margin:0 4px}.tox .tox-listbox__select-chevron{align-items:center;display:flex;justify-content:center;width:16px}.tox .tox-listbox__select-chevron svg{fill:#222f3e}.tox .tox-listboxfield .tox-listbox--select{align-items:center;display:flex}.tox:not([dir=rtl]) .tox-listboxfield svg{right:8px}.tox[dir=rtl] .tox-listboxfield svg{left:8px}.tox .tox-selectfield{cursor:pointer;position:relative}.tox .tox-selectfield select{-webkit-appearance:none;-moz-appearance:none;appearance:none;background-color:#fff;border-color:#ccc;border-radius:3px;border-style:solid;border-width:1px;box-shadow:none;box-sizing:border-box;color:#222f3e;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Oxygen-Sans,Ubuntu,Cantarell,"Helvetica Neue",sans-serif;font-size:16px;line-height:24px;margin:0;min-height:34px;outline:0;padding:5px 4.75px;resize:none;width:100%}.tox .tox-selectfield select[disabled]{background-color:#f2f2f2;color:rgba(34,47,62,.85);cursor:not-allowed}.tox .tox-selectfield select::-ms-expand{display:none}.tox .tox-selectfield select:focus{background-color:#fff;border-color:#207ab7;box-shadow:none;outline:0}.tox .tox-selectfield svg{pointer-events:none;position:absolute;top:50%;transform:translateY(-50%)}.tox:not([dir=rtl]) .tox-selectfield select[size="0"],.tox:not([dir=rtl]) .tox-selectfield select[size="1"]{padding-right:24px}.tox:not([dir=rtl]) .tox-selectfield svg{right:8px}.tox[dir=rtl] .tox-selectfield select[size="0"],.tox[dir=rtl] .tox-selectfield select[size="1"]{padding-left:24px}.tox[dir=rtl] .tox-selectfield svg{left:8px}.tox .tox-textarea{-webkit-appearance:textarea;-moz-appearance:textarea;appearance:textarea;white-space:pre-wrap}.tox-fullscreen{border:0;height:100%;left:0;margin:0;overflow:hidden;-ms-scroll-chaining:none;overscroll-behavior:none;padding:0;position:fixed;top:0;touch-action:pinch-zoom;width:100%}.tox.tox-tinymce.tox-fullscreen .tox-statusbar__resize-handle{display:none}.tox.tox-tinymce.tox-fullscreen{background-color:transparent;z-index:1200}.tox-shadowhost.tox-fullscreen{z-index:1200}.tox-fullscreen .tox.tox-tinymce-aux,.tox-fullscreen~.tox.tox-tinymce-aux{z-index:1201}.tox .tox-help__more-link{list-style:none;margin-top:1em}.tox .tox-image-tools{width:100%}.tox .tox-image-tools__toolbar{align-items:center;display:flex;justify-content:center}.tox .tox-image-tools__image{background-color:#666;height:380px;overflow:auto;position:relative;width:100%}.tox .tox-image-tools__image,.tox .tox-image-tools__image+.tox-image-tools__toolbar{margin-top:8px}.tox .tox-image-tools__image-bg{background:url(data:image/gif;base64,R0lGODdhDAAMAIABAMzMzP///ywAAAAADAAMAAACFoQfqYeabNyDMkBQb81Uat85nxguUAEAOw==)}.tox .tox-image-tools__toolbar>.tox-spacer{flex:1;-ms-flex-preferred-size:auto}.tox .tox-croprect-block{background:#000;opacity:.5;position:absolute;zoom:1}.tox .tox-croprect-handle{border:2px solid #fff;height:20px;left:0;position:absolute;top:0;width:20px}.tox .tox-croprect-handle-move{border:0;cursor:move;position:absolute}.tox .tox-croprect-handle-nw{border-width:2px 0 0 2px;cursor:nw-resize;left:100px;margin:-2px 0 0 -2px;top:100px}.tox .tox-croprect-handle-ne{border-width:2px 2px 0 0;cursor:ne-resize;left:200px;margin:-2px 0 0 -20px;top:100px}.tox .tox-croprect-handle-sw{border-width:0 0 2px 2px;cursor:sw-resize;left:100px;margin:-20px 2px 0 -2px;top:200px}.tox .tox-croprect-handle-se{border-width:0 2px 2px 0;cursor:se-resize;left:200px;margin:-20px 0 0 -20px;top:200px}.tox:not([dir=rtl]) .tox-image-tools__toolbar>.tox-slider:not(:first-of-type){margin-left:8px}.tox:not([dir=rtl]) .tox-image-tools__toolbar>.tox-button+.tox-slider{margin-left:32px}.tox:not([dir=rtl]) .tox-image-tools__toolbar>.tox-slider+.tox-button{margin-left:32px}.tox[dir=rtl] .tox-image-tools__toolbar>.tox-slider:not(:first-of-type){margin-right:8px}.tox[dir=rtl] .tox-image-tools__toolbar>.tox-button+.tox-slider{margin-right:32px}.tox[dir=rtl] .tox-image-tools__toolbar>.tox-slider+.tox-button{margin-right:32px}.tox .tox-insert-table-picker{display:flex;flex-wrap:wrap;width:170px}.tox .tox-insert-table-picker>div{border-color:#ccc;border-style:solid;border-width:0 1px 1px 0;box-sizing:border-box;height:17px;width:17px}.tox .tox-collection--list .tox-collection__group .tox-insert-table-picker{margin:-4px 0}.tox .tox-insert-table-picker .tox-insert-table-picker__selected{background-color:rgba(32,122,183,.5);border-color:rgba(32,122,183,.5)}.tox .tox-insert-table-picker__label{color:rgba(34,47,62,.7);display:block;font-size:14px;padding:4px;text-align:center;width:100%}.tox:not([dir=rtl]) .tox-insert-table-picker>div:nth-child(10n){border-right:0}.tox[dir=rtl] .tox-insert-table-picker>div:nth-child(10n+1){border-right:0}.tox .tox-menu{background-color:#fff;border:1px solid #ccc;border-radius:3px;box-shadow:0 4px 8px 0 rgba(34,47,62,.1);display:inline-block;overflow:hidden;vertical-align:top;z-index:1150}.tox .tox-menu.tox-collection.tox-collection--list{padding:0}.tox .tox-menu.tox-collection.tox-collection--toolbar{padding:4px}.tox .tox-menu.tox-collection.tox-collection--grid{padding:4px}.tox .tox-menu__label blockquote,.tox .tox-menu__label code,.tox .tox-menu__label h1,.tox .tox-menu__label h2,.tox .tox-menu__label h3,.tox .tox-menu__label h4,.tox .tox-menu__label h5,.tox .tox-menu__label h6,.tox .tox-menu__label p{margin:0}.tox .tox-menubar{background:url("data:image/svg+xml;charset=utf8,%3Csvg height='39px' viewBox='0 0 40 39px' width='40' xmlns='http://www.w3.org/2000/svg'%3E%3Crect x='0' y='38px' width='100' height='1' fill='%23cccccc'/%3E%3C/svg%3E") left 0 top 0 #fff;background-color:#fff;display:flex;flex:0 0 auto;flex-shrink:0;flex-wrap:wrap;padding:0 4px 0 4px}.tox.tox-tinymce:not(.tox-tinymce-inline) .tox-editor-header:not(:first-child) .tox-menubar{border-top:1px solid #ccc}.tox .tox-mbtn{align-items:center;background:0 0;border:0;border-radius:3px;box-shadow:none;color:#222f3e;display:flex;flex:0 0 auto;font-size:14px;font-style:normal;font-weight:400;height:34px;justify-content:center;margin:2px 0 3px 0;outline:0;overflow:hidden;padding:0 4px;text-transform:none;width:auto}.tox .tox-mbtn[disabled]{background-color:transparent;border:0;box-shadow:none;color:rgba(34,47,62,.5);cursor:not-allowed}.tox .tox-mbtn:focus:not(:disabled){background:#dee0e2;border:0;box-shadow:none;color:#222f3e}.tox .tox-mbtn--active{background:#c8cbcf;border:0;box-shadow:none;color:#222f3e}.tox .tox-mbtn:hover:not(:disabled):not(.tox-mbtn--active){background:#dee0e2;border:0;box-shadow:none;color:#222f3e}.tox .tox-mbtn__select-label{cursor:default;font-weight:400;margin:0 4px}.tox .tox-mbtn[disabled] .tox-mbtn__select-label{cursor:not-allowed}.tox .tox-mbtn__select-chevron{align-items:center;display:flex;justify-content:center;width:16px;display:none}.tox .tox-notification{border-radius:3px;border-style:solid;border-width:1px;box-shadow:none;box-sizing:border-box;display:-ms-grid;display:grid;font-size:14px;font-weight:400;-ms-grid-columns:minmax(40px,1fr) auto minmax(40px,1fr);grid-template-columns:minmax(40px,1fr) auto minmax(40px,1fr);margin-top:4px;opacity:0;padding:4px;transition:transform .1s ease-in,opacity 150ms ease-in}.tox .tox-notification p{font-size:14px;font-weight:400}.tox .tox-notification a{text-decoration:underline}.tox .tox-notification--in{opacity:1}.tox .tox-notification--success{background-color:#e4eeda;border-color:#d7e6c8;color:#222f3e}.tox .tox-notification--success p{color:#222f3e}.tox .tox-notification--success a{color:#547831}.tox .tox-notification--success svg{fill:#222f3e}.tox .tox-notification--error{background-color:#f8dede;border-color:#f2bfbf;color:#222f3e}.tox .tox-notification--error p{color:#222f3e}.tox .tox-notification--error a{color:#c00}.tox .tox-notification--error svg{fill:#222f3e}.tox .tox-notification--warn,.tox .tox-notification--warning{background-color:#fffaea;border-color:#ffe89d;color:#222f3e}.tox .tox-notification--warn p,.tox .tox-notification--warning p{color:#222f3e}.tox .tox-notification--warn a,.tox .tox-notification--warning a{color:#222f3e}.tox .tox-notification--warn svg,.tox .tox-notification--warning svg{fill:#222f3e}.tox .tox-notification--info{background-color:#d9edf7;border-color:#779ecb;color:#222f3e}.tox .tox-notification--info p{color:#222f3e}.tox .tox-notification--info a{color:#222f3e}.tox .tox-notification--info svg{fill:#222f3e}.tox .tox-notification__body{-ms-grid-row-align:center;align-self:center;color:#222f3e;font-size:14px;-ms-grid-column-span:1;grid-column-end:3;-ms-grid-column:2;grid-column-start:2;-ms-grid-row-span:1;grid-row-end:2;-ms-grid-row:1;grid-row-start:1;text-align:center;white-space:normal;word-break:break-all;word-break:break-word}.tox .tox-notification__body>*{margin:0}.tox .tox-notification__body>*+*{margin-top:1rem}.tox .tox-notification__icon{-ms-grid-row-align:center;align-self:center;-ms-grid-column-span:1;grid-column-end:2;-ms-grid-column:1;grid-column-start:1;-ms-grid-row-span:1;grid-row-end:2;-ms-grid-row:1;grid-row-start:1;-ms-grid-column-align:end;justify-self:end}.tox .tox-notification__icon svg{display:block}.tox .tox-notification__dismiss{-ms-grid-row-align:start;align-self:start;-ms-grid-column-span:1;grid-column-end:4;-ms-grid-column:3;grid-column-start:3;-ms-grid-row-span:1;grid-row-end:2;-ms-grid-row:1;grid-row-start:1;-ms-grid-column-align:end;justify-self:end}.tox .tox-notification .tox-progress-bar{-ms-grid-column-span:3;grid-column-end:4;-ms-grid-column:1;grid-column-start:1;-ms-grid-row-span:1;grid-row-end:3;-ms-grid-row:2;grid-row-start:2;-ms-grid-column-align:center;justify-self:center}.tox .tox-pop{display:inline-block;position:relative}.tox .tox-pop--resizing{transition:width .1s ease}.tox .tox-pop--resizing .tox-toolbar{flex-wrap:nowrap}.tox .tox-pop__dialog{background-color:#fff;border:1px solid #ccc;border-radius:3px;box-shadow:0 1px 3px rgba(0,0,0,.15);min-width:0;overflow:hidden}.tox .tox-pop__dialog>:not(.tox-toolbar){margin:4px 4px 4px 8px}.tox .tox-pop__dialog .tox-toolbar{background-color:transparent;margin-bottom:-1px}.tox .tox-pop::after,.tox .tox-pop::before{border-style:solid;content:'';display:block;height:0;position:absolute;width:0}.tox .tox-pop.tox-pop--bottom::after,.tox .tox-pop.tox-pop--bottom::before{left:50%;top:100%}.tox .tox-pop.tox-pop--bottom::after{border-color:#fff transparent transparent transparent;border-width:8px;margin-left:-8px;margin-top:-1px}.tox .tox-pop.tox-pop--bottom::before{border-color:#ccc transparent transparent transparent;border-width:9px;margin-left:-9px}.tox .tox-pop.tox-pop--top::after,.tox .tox-pop.tox-pop--top::before{left:50%;top:0;transform:translateY(-100%)}.tox .tox-pop.tox-pop--top::after{border-color:transparent transparent #fff transparent;border-width:8px;margin-left:-8px;margin-top:1px}.tox .tox-pop.tox-pop--top::before{border-color:transparent transparent #ccc transparent;border-width:9px;margin-left:-9px}.tox .tox-pop.tox-pop--left::after,.tox .tox-pop.tox-pop--left::before{left:0;top:calc(50% - 1px);transform:translateY(-50%)}.tox .tox-pop.tox-pop--left::after{border-color:transparent #fff transparent transparent;border-width:8px;margin-left:-15px}.tox .tox-pop.tox-pop--left::before{border-color:transparent #ccc transparent transparent;border-width:10px;margin-left:-19px}.tox .tox-pop.tox-pop--right::after,.tox .tox-pop.tox-pop--right::before{left:100%;top:calc(50% + 1px);transform:translateY(-50%)}.tox .tox-pop.tox-pop--right::after{border-color:transparent transparent transparent #fff;border-width:8px;margin-left:-1px}.tox .tox-pop.tox-pop--right::before{border-color:transparent transparent transparent #ccc;border-width:10px;margin-left:-1px}.tox .tox-pop.tox-pop--align-left::after,.tox .tox-pop.tox-pop--align-left::before{left:20px}.tox .tox-pop.tox-pop--align-right::after,.tox .tox-pop.tox-pop--align-right::before{left:calc(100% - 20px)}.tox .tox-sidebar-wrap{display:flex;flex-direction:row;flex-grow:1;-ms-flex-preferred-size:0;min-height:0}.tox .tox-sidebar{background-color:#fff;display:flex;flex-direction:row;justify-content:flex-end}.tox .tox-sidebar__slider{display:flex;overflow:hidden}.tox .tox-sidebar__pane-container{display:flex}.tox .tox-sidebar__pane{display:flex}.tox .tox-sidebar--sliding-closed{opacity:0}.tox .tox-sidebar--sliding-open{opacity:1}.tox .tox-sidebar--sliding-growing,.tox .tox-sidebar--sliding-shrinking{transition:width .5s ease,opacity .5s ease}.tox .tox-selector{background-color:#4099ff;border-color:#4099ff;border-style:solid;border-width:1px;box-sizing:border-box;display:inline-block;height:10px;position:absolute;width:10px}.tox.tox-platform-touch .tox-selector{height:12px;width:12px}.tox .tox-slider{align-items:center;display:flex;flex:1;-ms-flex-preferred-size:auto;height:24px;justify-content:center;position:relative}.tox .tox-slider__rail{background-color:transparent;border:1px solid #ccc;border-radius:3px;height:10px;min-width:120px;width:100%}.tox .tox-slider__handle{background-color:#207ab7;border:2px solid #185d8c;border-radius:3px;box-shadow:none;height:24px;left:50%;position:absolute;top:50%;transform:translateX(-50%) translateY(-50%);width:14px}.tox .tox-source-code{overflow:auto}.tox .tox-spinner{display:flex}.tox .tox-spinner>div{animation:tam-bouncing-dots 1.5s ease-in-out 0s infinite both;background-color:rgba(34,47,62,.7);border-radius:100%;height:8px;width:8px}.tox .tox-spinner>div:nth-child(1){animation-delay:-.32s}.tox .tox-spinner>div:nth-child(2){animation-delay:-.16s}@keyframes tam-bouncing-dots{0%,100%,80%{transform:scale(0)}40%{transform:scale(1)}}.tox:not([dir=rtl]) .tox-spinner>div:not(:first-child){margin-left:4px}.tox[dir=rtl] .tox-spinner>div:not(:first-child){margin-right:4px}.tox .tox-statusbar{align-items:center;background-color:#fff;border-top:1px solid #ccc;color:rgba(34,47,62,.7);display:flex;flex:0 0 auto;font-size:12px;font-weight:400;height:18px;overflow:hidden;padding:0 8px;position:relative;text-transform:uppercase}.tox .tox-statusbar__text-container{display:flex;flex:1 1 auto;justify-content:flex-end;overflow:hidden}.tox .tox-statusbar__path{display:flex;flex:1 1 auto;margin-right:auto;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.tox .tox-statusbar__path>*{display:inline;white-space:nowrap}.tox .tox-statusbar__wordcount{flex:0 0 auto;margin-left:1ch}.tox .tox-statusbar a,.tox .tox-statusbar__path-item,.tox .tox-statusbar__wordcount{color:rgba(34,47,62,.7);text-decoration:none}.tox .tox-statusbar a:focus:not(:disabled):not([aria-disabled=true]),.tox .tox-statusbar a:hover:not(:disabled):not([aria-disabled=true]),.tox .tox-statusbar__path-item:focus:not(:disabled):not([aria-disabled=true]),.tox .tox-statusbar__path-item:hover:not(:disabled):not([aria-disabled=true]),.tox .tox-statusbar__wordcount:focus:not(:disabled):not([aria-disabled=true]),.tox .tox-statusbar__wordcount:hover:not(:disabled):not([aria-disabled=true]){cursor:pointer;text-decoration:underline}.tox .tox-statusbar__resize-handle{align-items:flex-end;align-self:stretch;cursor:nwse-resize;display:flex;flex:0 0 auto;justify-content:flex-end;margin-left:auto;margin-right:-8px;padding-left:1ch}.tox .tox-statusbar__resize-handle svg{display:block;fill:rgba(34,47,62,.7)}.tox .tox-statusbar__resize-handle:focus svg{background-color:#dee0e2;border-radius:1px;box-shadow:0 0 0 2px #dee0e2}.tox:not([dir=rtl]) .tox-statusbar__path>*{margin-right:4px}.tox:not([dir=rtl]) .tox-statusbar__branding{margin-left:1ch}.tox[dir=rtl] .tox-statusbar{flex-direction:row-reverse}.tox[dir=rtl] .tox-statusbar__path>*{margin-left:4px}.tox .tox-throbber{z-index:1299}.tox .tox-throbber__busy-spinner{align-items:center;background-color:rgba(255,255,255,.6);bottom:0;display:flex;justify-content:center;left:0;position:absolute;right:0;top:0}.tox .tox-tbtn{align-items:center;background:0 0;border:0;border-radius:3px;box-shadow:none;color:#222f3e;display:flex;flex:0 0 auto;font-size:14px;font-style:normal;font-weight:400;height:34px;justify-content:center;margin:2px 0 3px 0;outline:0;overflow:hidden;padding:0;text-transform:none;width:34px}.tox .tox-tbtn svg{display:block;fill:#222f3e}.tox .tox-tbtn.tox-tbtn-more{padding-left:5px;padding-right:5px;width:inherit}.tox .tox-tbtn:focus{background:#dee0e2;border:0;box-shadow:none}.tox .tox-tbtn:hover{background:#dee0e2;border:0;box-shadow:none;color:#222f3e}.tox .tox-tbtn:hover svg{fill:#222f3e}.tox .tox-tbtn:active{background:#c8cbcf;border:0;box-shadow:none;color:#222f3e}.tox .tox-tbtn:active svg{fill:#222f3e}.tox .tox-tbtn--disabled,.tox .tox-tbtn--disabled:hover,.tox .tox-tbtn:disabled,.tox .tox-tbtn:disabled:hover{background:0 0;border:0;box-shadow:none;color:rgba(34,47,62,.5);cursor:not-allowed}.tox .tox-tbtn--disabled svg,.tox .tox-tbtn--disabled:hover svg,.tox .tox-tbtn:disabled svg,.tox .tox-tbtn:disabled:hover svg{fill:rgba(34,47,62,.5)}.tox .tox-tbtn--enabled,.tox .tox-tbtn--enabled:hover{background:#c8cbcf;border:0;box-shadow:none;color:#222f3e}.tox .tox-tbtn--enabled:hover>*,.tox .tox-tbtn--enabled>*{transform:none}.tox .tox-tbtn--enabled svg,.tox .tox-tbtn--enabled:hover svg{fill:#222f3e}.tox .tox-tbtn:focus:not(.tox-tbtn--disabled){color:#222f3e}.tox .tox-tbtn:focus:not(.tox-tbtn--disabled) svg{fill:#222f3e}.tox .tox-tbtn:active>*{transform:none}.tox .tox-tbtn--md{height:51px;width:51px}.tox .tox-tbtn--lg{flex-direction:column;height:68px;width:68px}.tox .tox-tbtn--return{-ms-grid-row-align:stretch;align-self:stretch;height:unset;width:16px}.tox .tox-tbtn--labeled{padding:0 4px;width:unset}.tox .tox-tbtn__vlabel{display:block;font-size:10px;font-weight:400;letter-spacing:-.025em;margin-bottom:4px;white-space:nowrap}.tox .tox-tbtn--select{margin:2px 0 3px 0;padding:0 4px;width:auto}.tox .tox-tbtn__select-label{cursor:default;font-weight:400;margin:0 4px}.tox .tox-tbtn__select-chevron{align-items:center;display:flex;justify-content:center;width:16px}.tox .tox-tbtn__select-chevron svg{fill:rgba(34,47,62,.5)}.tox .tox-tbtn--bespoke .tox-tbtn__select-label{overflow:hidden;text-overflow:ellipsis;white-space:nowrap;width:7em}.tox .tox-split-button{border:0;border-radius:3px;box-sizing:border-box;display:flex;margin:2px 0 3px 0;overflow:hidden}.tox .tox-split-button:hover{box-shadow:0 0 0 1px #dee0e2 inset}.tox .tox-split-button:focus{background:#dee0e2;box-shadow:none;color:#222f3e}.tox .tox-split-button>*{border-radius:0}.tox .tox-split-button__chevron{width:16px}.tox .tox-split-button__chevron svg{fill:rgba(34,47,62,.5)}.tox .tox-split-button .tox-tbtn{margin:0}.tox.tox-platform-touch .tox-split-button .tox-tbtn:first-child{width:30px}.tox.tox-platform-touch .tox-split-button__chevron{width:20px}.tox .tox-split-button.tox-tbtn--disabled .tox-tbtn:focus,.tox .tox-split-button.tox-tbtn--disabled .tox-tbtn:hover,.tox .tox-split-button.tox-tbtn--disabled:focus,.tox .tox-split-button.tox-tbtn--disabled:hover{background:0 0;box-shadow:none;color:rgba(34,47,62,.5)}.tox .tox-toolbar-overlord{background-color:#fff}.tox .tox-toolbar,.tox .tox-toolbar__overflow,.tox .tox-toolbar__primary{background:url("data:image/svg+xml;charset=utf8,%3Csvg height='39px' viewBox='0 0 40 39px' width='40' xmlns='http://www.w3.org/2000/svg'%3E%3Crect x='0' y='38px' width='100' height='1' fill='%23cccccc'/%3E%3C/svg%3E") left 0 top 0 #fff;background-color:#fff;display:flex;flex:0 0 auto;flex-shrink:0;flex-wrap:wrap;padding:0 0}.tox .tox-toolbar__overflow.tox-toolbar__overflow--closed{height:0;opacity:0;padding-bottom:0;padding-top:0;visibility:hidden}.tox .tox-toolbar__overflow--growing{transition:height .3s ease,opacity .2s linear .1s}.tox .tox-toolbar__overflow--shrinking{transition:opacity .3s ease,height .2s linear .1s,visibility 0s linear .3s}.tox .tox-menubar+.tox-toolbar,.tox .tox-menubar+.tox-toolbar-overlord .tox-toolbar__primary{border-top:1px solid #ccc;margin-top:-1px}.tox .tox-toolbar--scrolling{flex-wrap:nowrap;overflow-x:auto}.tox .tox-pop .tox-toolbar{border-width:0}.tox .tox-toolbar--no-divider{background-image:none}.tox-tinymce:not(.tox-tinymce-inline) .tox-editor-header:not(:first-child) .tox-toolbar-overlord:first-child .tox-toolbar__primary,.tox-tinymce:not(.tox-tinymce-inline) .tox-editor-header:not(:first-child) .tox-toolbar:first-child{border-top:1px solid #ccc}.tox.tox-tinymce-aux .tox-toolbar__overflow{background-color:#fff;border:1px solid #ccc;border-radius:3px;box-shadow:0 1px 3px rgba(0,0,0,.15)}.tox[dir=rtl] .tox-tbtn__icon-rtl svg{transform:rotateY(180deg)}.tox .tox-toolbar__group{align-items:center;display:flex;flex-wrap:wrap;margin:0 0;padding:0 4px 0 4px}.tox .tox-toolbar__group--pull-right{margin-left:auto}.tox .tox-toolbar--scrolling .tox-toolbar__group{flex-shrink:0;flex-wrap:nowrap}.tox:not([dir=rtl]) .tox-toolbar__group:not(:last-of-type){border-right:1px solid #ccc}.tox[dir=rtl] .tox-toolbar__group:not(:last-of-type){border-left:1px solid #ccc}.tox .tox-tooltip{display:inline-block;padding:8px;position:relative}.tox .tox-tooltip__body{background-color:#222f3e;border-radius:3px;box-shadow:0 2px 4px rgba(34,47,62,.3);color:rgba(255,255,255,.75);font-size:14px;font-style:normal;font-weight:400;padding:4px 8px;text-transform:none}.tox .tox-tooltip__arrow{position:absolute}.tox .tox-tooltip--down .tox-tooltip__arrow{border-left:8px solid transparent;border-right:8px solid transparent;border-top:8px solid #222f3e;bottom:0;left:50%;position:absolute;transform:translateX(-50%)}.tox .tox-tooltip--up .tox-tooltip__arrow{border-bottom:8px solid #222f3e;border-left:8px solid transparent;border-right:8px solid transparent;left:50%;position:absolute;top:0;transform:translateX(-50%)}.tox .tox-tooltip--right .tox-tooltip__arrow{border-bottom:8px solid transparent;border-left:8px solid #222f3e;border-top:8px solid transparent;position:absolute;right:0;top:50%;transform:translateY(-50%)}.tox .tox-tooltip--left .tox-tooltip__arrow{border-bottom:8px solid transparent;border-right:8px solid #222f3e;border-top:8px solid transparent;left:0;position:absolute;top:50%;transform:translateY(-50%)}.tox .tox-well{border:1px solid #ccc;border-radius:3px;padding:8px;width:100%}.tox .tox-well>:first-child{margin-top:0}.tox .tox-well>:last-child{margin-bottom:0}.tox .tox-well>:only-child{margin:0}.tox .tox-custom-editor{border:1px solid #ccc;border-radius:3px;display:flex;flex:1;position:relative}.tox .tox-dialog-loading::before{background-color:rgba(0,0,0,.5);content:"";height:100%;position:absolute;width:100%;z-index:1000}.tox .tox-tab{cursor:pointer}.tox .tox-dialog__content-js{display:flex;flex:1;-ms-flex-preferred-size:auto}.tox .tox-dialog__body-content .tox-collection{display:flex;flex:1;-ms-flex-preferred-size:auto}.tox .tox-image-tools-edit-panel{height:60px}.tox .tox-image-tools__sidebar{height:60px} diff --git a/frontend/public/tinymce-dataease-private/skins/ui/oxide/skin.mobile.css b/frontend/public/tinymce-dataease-private/skins/ui/oxide/skin.mobile.css new file mode 100644 index 0000000..efcd1bb --- /dev/null +++ b/frontend/public/tinymce-dataease-private/skins/ui/oxide/skin.mobile.css @@ -0,0 +1,798 @@ +/** + * Copyright (c) Tiny Technologies, Inc. All rights reserved. + * Licensed under the LGPL or a commercial license. + * For LGPL see License.txt in the project root for license information. + * For commercial licenses see https://www.tiny.cloud/ + */ +/* RESET all the things! */ +.tinymce-mobile-outer-container { + all: initial; + display: block; +} + +.tinymce-mobile-outer-container * { + border: 0; + box-sizing: initial; + cursor: inherit; + float: none; + line-height: 1; + margin: 0; + outline: 0; + padding: 0; + -webkit-tap-highlight-color: transparent; + /* TBIO-3691, stop the gray flicker on touch. */ + text-shadow: none; + white-space: nowrap; +} + +.tinymce-mobile-icon-arrow-back::before { + content: "\e5cd"; +} + +.tinymce-mobile-icon-image::before { + content: "\e412"; +} + +.tinymce-mobile-icon-cancel-circle::before { + content: "\e5c9"; +} + +.tinymce-mobile-icon-full-dot::before { + content: "\e061"; +} + +.tinymce-mobile-icon-align-center::before { + content: "\e234"; +} + +.tinymce-mobile-icon-align-left::before { + content: "\e236"; +} + +.tinymce-mobile-icon-align-right::before { + content: "\e237"; +} + +.tinymce-mobile-icon-bold::before { + content: "\e238"; +} + +.tinymce-mobile-icon-italic::before { + content: "\e23f"; +} + +.tinymce-mobile-icon-unordered-list::before { + content: "\e241"; +} + +.tinymce-mobile-icon-ordered-list::before { + content: "\e242"; +} + +.tinymce-mobile-icon-font-size::before { + content: "\e245"; +} + +.tinymce-mobile-icon-underline::before { + content: "\e249"; +} + +.tinymce-mobile-icon-link::before { + content: "\e157"; +} + +.tinymce-mobile-icon-unlink::before { + content: "\eca2"; +} + +.tinymce-mobile-icon-color::before { + content: "\e891"; +} + +.tinymce-mobile-icon-previous::before { + content: "\e314"; +} + +.tinymce-mobile-icon-next::before { + content: "\e315"; +} + +.tinymce-mobile-icon-large-font::before, +.tinymce-mobile-icon-style-formats::before { + content: "\e264"; +} + +.tinymce-mobile-icon-undo::before { + content: "\e166"; +} + +.tinymce-mobile-icon-redo::before { + content: "\e15a"; +} + +.tinymce-mobile-icon-removeformat::before { + content: "\e239"; +} + +.tinymce-mobile-icon-small-font::before { + content: "\e906"; +} + +.tinymce-mobile-icon-readonly-back::before, +.tinymce-mobile-format-matches::after { + content: "\e5ca"; +} + +.tinymce-mobile-icon-small-heading::before { + content: "small"; +} + +.tinymce-mobile-icon-large-heading::before { + content: "large"; +} + +.tinymce-mobile-icon-small-heading::before, +.tinymce-mobile-icon-large-heading::before { + font-family: sans-serif; + font-size: 80%; +} + +.tinymce-mobile-mask-edit-icon::before { + content: "\e254"; +} + +.tinymce-mobile-icon-back::before { + content: "\e5c4"; +} + +.tinymce-mobile-icon-heading::before { + /* TODO: Translate */ + content: "Headings"; + font-family: sans-serif; + font-size: 80%; + font-weight: bold; +} + +.tinymce-mobile-icon-h1::before { + content: "H1"; + font-weight: bold; +} + +.tinymce-mobile-icon-h2::before { + content: "H2"; + font-weight: bold; +} + +.tinymce-mobile-icon-h3::before { + content: "H3"; + font-weight: bold; +} + +.tinymce-mobile-outer-container .tinymce-mobile-disabled-mask { + align-items: center; + display: flex; + justify-content: center; + background: rgba(51, 51, 51, 0.5); + height: 100%; + position: absolute; + top: 0; + width: 100%; +} + +.tinymce-mobile-outer-container .tinymce-mobile-disabled-mask .tinymce-mobile-content-container { + align-items: center; + border-radius: 50%; + display: flex; + flex-direction: column; + font-family: sans-serif; + font-size: 1em; + justify-content: space-between; +} + +.tinymce-mobile-outer-container .tinymce-mobile-disabled-mask .tinymce-mobile-content-container .mixin-menu-item { + align-items: center; + display: flex; + justify-content: center; + border-radius: 50%; + height: 2.1em; + width: 2.1em; +} + +.tinymce-mobile-outer-container .tinymce-mobile-disabled-mask .tinymce-mobile-content-container .tinymce-mobile-content-tap-section { + align-items: center; + display: flex; + justify-content: center; + flex-direction: column; + font-size: 1em; +} + +@media only screen and (min-device-width: 700px) { + .tinymce-mobile-outer-container .tinymce-mobile-disabled-mask .tinymce-mobile-content-container .tinymce-mobile-content-tap-section { + font-size: 1.2em; + } +} + +.tinymce-mobile-outer-container .tinymce-mobile-disabled-mask .tinymce-mobile-content-container .tinymce-mobile-content-tap-section .tinymce-mobile-mask-tap-icon { + align-items: center; + display: flex; + justify-content: center; + border-radius: 50%; + height: 2.1em; + width: 2.1em; + background-color: white; + color: #207ab7; +} + +.tinymce-mobile-outer-container .tinymce-mobile-disabled-mask .tinymce-mobile-content-container .tinymce-mobile-content-tap-section .tinymce-mobile-mask-tap-icon::before { + content: "\e900"; + font-family: 'tinymce-mobile', sans-serif; +} + +.tinymce-mobile-outer-container .tinymce-mobile-disabled-mask .tinymce-mobile-content-container .tinymce-mobile-content-tap-section:not(.tinymce-mobile-mask-tap-icon-selected) .tinymce-mobile-mask-tap-icon { + z-index: 2; +} + +.tinymce-mobile-android-container.tinymce-mobile-android-maximized { + background: #ffffff; + border: none; + bottom: 0; + display: flex; + flex-direction: column; + left: 0; + position: fixed; + right: 0; + top: 0; +} + +.tinymce-mobile-android-container:not(.tinymce-mobile-android-maximized) { + position: relative; +} + +.tinymce-mobile-android-container .tinymce-mobile-editor-socket { + display: flex; + flex-grow: 1; +} + +.tinymce-mobile-android-container .tinymce-mobile-editor-socket iframe { + display: flex !important; + flex-grow: 1; + height: auto !important; +} + +.tinymce-mobile-android-scroll-reload { + overflow: hidden; +} + +:not(.tinymce-mobile-readonly-mode) > .tinymce-mobile-android-selection-context-toolbar { + margin-top: 23px; +} + +.tinymce-mobile-toolstrip { + background: #fff; + display: flex; + flex: 0 0 auto; + z-index: 1; +} + +.tinymce-mobile-toolstrip .tinymce-mobile-toolbar { + align-items: center; + background-color: #fff; + border-bottom: 1px solid #cccccc; + display: flex; + flex: 1; + height: 2.5em; + width: 100%; + /* Make it no larger than the toolstrip, so that it needs to scroll */ +} + +.tinymce-mobile-toolstrip .tinymce-mobile-toolbar:not(.tinymce-mobile-context-toolbar) .tinymce-mobile-toolbar-group { + align-items: center; + display: flex; + height: 100%; + flex-shrink: 1; +} + +.tinymce-mobile-toolstrip .tinymce-mobile-toolbar:not(.tinymce-mobile-context-toolbar) .tinymce-mobile-toolbar-group > div { + align-items: center; + display: flex; + height: 100%; + flex: 1; +} + +.tinymce-mobile-toolstrip .tinymce-mobile-toolbar:not(.tinymce-mobile-context-toolbar) .tinymce-mobile-toolbar-group.tinymce-mobile-exit-container { + background: #f44336; +} + +.tinymce-mobile-toolstrip .tinymce-mobile-toolbar:not(.tinymce-mobile-context-toolbar) .tinymce-mobile-toolbar-group.tinymce-mobile-toolbar-scrollable-group { + flex-grow: 1; +} + +.tinymce-mobile-toolstrip .tinymce-mobile-toolbar:not(.tinymce-mobile-context-toolbar) .tinymce-mobile-toolbar-group .tinymce-mobile-toolbar-group-item { + padding-left: 0.5em; + padding-right: 0.5em; +} + +.tinymce-mobile-toolstrip .tinymce-mobile-toolbar:not(.tinymce-mobile-context-toolbar) .tinymce-mobile-toolbar-group .tinymce-mobile-toolbar-group-item.tinymce-mobile-toolbar-button { + align-items: center; + display: flex; + height: 80%; + margin-left: 2px; + margin-right: 2px; +} + +.tinymce-mobile-toolstrip .tinymce-mobile-toolbar:not(.tinymce-mobile-context-toolbar) .tinymce-mobile-toolbar-group .tinymce-mobile-toolbar-group-item.tinymce-mobile-toolbar-button.tinymce-mobile-toolbar-button-selected { + background: #c8cbcf; + color: #cccccc; +} + +.tinymce-mobile-toolstrip .tinymce-mobile-toolbar:not(.tinymce-mobile-context-toolbar) .tinymce-mobile-toolbar-group:first-of-type, +.tinymce-mobile-toolstrip .tinymce-mobile-toolbar:not(.tinymce-mobile-context-toolbar) .tinymce-mobile-toolbar-group:last-of-type { + background: #207ab7; + color: #eceff1; +} + +.tinymce-mobile-toolstrip .tinymce-mobile-toolbar.tinymce-mobile-context-toolbar { + /* Note, this file is imported inside .tinymce-mobile-context-toolbar, so that prefix is on everything here. */ +} + +.tinymce-mobile-toolstrip .tinymce-mobile-toolbar.tinymce-mobile-context-toolbar .tinymce-mobile-toolbar-group { + align-items: center; + display: flex; + height: 100%; + flex: 1; + padding-bottom: 0.4em; + padding-top: 0.4em; + /* Make any buttons appearing on the left and right display in the centre (e.g. color edges) */ + /* For widgets like the colour picker, use the whole height */ +} + +.tinymce-mobile-toolstrip .tinymce-mobile-toolbar.tinymce-mobile-context-toolbar .tinymce-mobile-toolbar-group .tinymce-mobile-serialised-dialog { + display: flex; + min-height: 1.5em; + overflow: hidden; + padding-left: 0; + padding-right: 0; + position: relative; + width: 100%; +} + +.tinymce-mobile-toolstrip .tinymce-mobile-toolbar.tinymce-mobile-context-toolbar .tinymce-mobile-toolbar-group .tinymce-mobile-serialised-dialog .tinymce-mobile-serialised-dialog-chain { + display: flex; + height: 100%; + transition: left cubic-bezier(0.4, 0, 1, 1) 0.15s; + width: 100%; +} + +.tinymce-mobile-toolstrip .tinymce-mobile-toolbar.tinymce-mobile-context-toolbar .tinymce-mobile-toolbar-group .tinymce-mobile-serialised-dialog .tinymce-mobile-serialised-dialog-chain .tinymce-mobile-serialised-dialog-screen { + display: flex; + flex: 0 0 auto; + justify-content: space-between; + width: 100%; +} + +.tinymce-mobile-toolstrip .tinymce-mobile-toolbar.tinymce-mobile-context-toolbar .tinymce-mobile-toolbar-group .tinymce-mobile-serialised-dialog .tinymce-mobile-serialised-dialog-chain .tinymce-mobile-serialised-dialog-screen input { + font-family: Sans-serif; +} + +.tinymce-mobile-toolstrip .tinymce-mobile-toolbar.tinymce-mobile-context-toolbar .tinymce-mobile-toolbar-group .tinymce-mobile-serialised-dialog .tinymce-mobile-serialised-dialog-chain .tinymce-mobile-serialised-dialog-screen .tinymce-mobile-input-container { + display: flex; + flex-grow: 1; + position: relative; +} + +.tinymce-mobile-toolstrip .tinymce-mobile-toolbar.tinymce-mobile-context-toolbar .tinymce-mobile-toolbar-group .tinymce-mobile-serialised-dialog .tinymce-mobile-serialised-dialog-chain .tinymce-mobile-serialised-dialog-screen .tinymce-mobile-input-container .tinymce-mobile-input-container-x { + -ms-grid-row-align: center; + align-self: center; + background: inherit; + border: none; + border-radius: 50%; + color: #888; + font-size: 0.6em; + font-weight: bold; + height: 100%; + padding-right: 2px; + position: absolute; + right: 0; +} + +.tinymce-mobile-toolstrip .tinymce-mobile-toolbar.tinymce-mobile-context-toolbar .tinymce-mobile-toolbar-group .tinymce-mobile-serialised-dialog .tinymce-mobile-serialised-dialog-chain .tinymce-mobile-serialised-dialog-screen .tinymce-mobile-input-container.tinymce-mobile-input-container-empty .tinymce-mobile-input-container-x { + display: none; +} + +.tinymce-mobile-toolstrip .tinymce-mobile-toolbar.tinymce-mobile-context-toolbar .tinymce-mobile-toolbar-group .tinymce-mobile-serialised-dialog .tinymce-mobile-serialised-dialog-chain .tinymce-mobile-serialised-dialog-screen .tinymce-mobile-icon-previous, +.tinymce-mobile-toolstrip .tinymce-mobile-toolbar.tinymce-mobile-context-toolbar .tinymce-mobile-toolbar-group .tinymce-mobile-serialised-dialog .tinymce-mobile-serialised-dialog-chain .tinymce-mobile-serialised-dialog-screen .tinymce-mobile-icon-next { + align-items: center; + display: flex; +} + +.tinymce-mobile-toolstrip .tinymce-mobile-toolbar.tinymce-mobile-context-toolbar .tinymce-mobile-toolbar-group .tinymce-mobile-serialised-dialog .tinymce-mobile-serialised-dialog-chain .tinymce-mobile-serialised-dialog-screen .tinymce-mobile-icon-previous::before, +.tinymce-mobile-toolstrip .tinymce-mobile-toolbar.tinymce-mobile-context-toolbar .tinymce-mobile-toolbar-group .tinymce-mobile-serialised-dialog .tinymce-mobile-serialised-dialog-chain .tinymce-mobile-serialised-dialog-screen .tinymce-mobile-icon-next::before { + align-items: center; + display: flex; + font-weight: bold; + height: 100%; + padding-left: 0.5em; + padding-right: 0.5em; +} + +.tinymce-mobile-toolstrip .tinymce-mobile-toolbar.tinymce-mobile-context-toolbar .tinymce-mobile-toolbar-group .tinymce-mobile-serialised-dialog .tinymce-mobile-serialised-dialog-chain .tinymce-mobile-serialised-dialog-screen .tinymce-mobile-icon-previous.tinymce-mobile-toolbar-navigation-disabled::before, +.tinymce-mobile-toolstrip .tinymce-mobile-toolbar.tinymce-mobile-context-toolbar .tinymce-mobile-toolbar-group .tinymce-mobile-serialised-dialog .tinymce-mobile-serialised-dialog-chain .tinymce-mobile-serialised-dialog-screen .tinymce-mobile-icon-next.tinymce-mobile-toolbar-navigation-disabled::before { + visibility: hidden; +} + +.tinymce-mobile-toolstrip .tinymce-mobile-toolbar.tinymce-mobile-context-toolbar .tinymce-mobile-toolbar-group .tinymce-mobile-dot-item { + color: #cccccc; + font-size: 10px; + line-height: 10px; + margin: 0 2px; + padding-top: 3px; +} + +.tinymce-mobile-toolstrip .tinymce-mobile-toolbar.tinymce-mobile-context-toolbar .tinymce-mobile-toolbar-group .tinymce-mobile-dot-item.tinymce-mobile-dot-active { + color: #c8cbcf; +} + +.tinymce-mobile-toolstrip .tinymce-mobile-toolbar.tinymce-mobile-context-toolbar .tinymce-mobile-toolbar-group .tinymce-mobile-icon-large-font::before, +.tinymce-mobile-toolstrip .tinymce-mobile-toolbar.tinymce-mobile-context-toolbar .tinymce-mobile-toolbar-group .tinymce-mobile-icon-large-heading::before { + margin-left: 0.5em; + margin-right: 0.9em; +} + +.tinymce-mobile-toolstrip .tinymce-mobile-toolbar.tinymce-mobile-context-toolbar .tinymce-mobile-toolbar-group .tinymce-mobile-icon-small-font::before, +.tinymce-mobile-toolstrip .tinymce-mobile-toolbar.tinymce-mobile-context-toolbar .tinymce-mobile-toolbar-group .tinymce-mobile-icon-small-heading::before { + margin-left: 0.9em; + margin-right: 0.5em; +} + +.tinymce-mobile-toolstrip .tinymce-mobile-toolbar.tinymce-mobile-context-toolbar .tinymce-mobile-toolbar-group .tinymce-mobile-slider { + display: flex; + flex: 1; + margin-left: 0; + margin-right: 0; + padding: 0.28em 0; + position: relative; +} + +.tinymce-mobile-toolstrip .tinymce-mobile-toolbar.tinymce-mobile-context-toolbar .tinymce-mobile-toolbar-group .tinymce-mobile-slider .tinymce-mobile-slider-size-container { + align-items: center; + display: flex; + flex-grow: 1; + height: 100%; +} + +.tinymce-mobile-toolstrip .tinymce-mobile-toolbar.tinymce-mobile-context-toolbar .tinymce-mobile-toolbar-group .tinymce-mobile-slider .tinymce-mobile-slider-size-container .tinymce-mobile-slider-size-line { + background: #cccccc; + display: flex; + flex: 1; + height: 0.2em; + margin-bottom: 0.3em; + margin-top: 0.3em; +} + +.tinymce-mobile-toolstrip .tinymce-mobile-toolbar.tinymce-mobile-context-toolbar .tinymce-mobile-toolbar-group .tinymce-mobile-slider.tinymce-mobile-hue-slider-container { + padding-left: 2em; + padding-right: 2em; +} + +.tinymce-mobile-toolstrip .tinymce-mobile-toolbar.tinymce-mobile-context-toolbar .tinymce-mobile-toolbar-group .tinymce-mobile-slider.tinymce-mobile-hue-slider-container .tinymce-mobile-slider-gradient-container { + align-items: center; + display: flex; + flex-grow: 1; + height: 100%; +} + +.tinymce-mobile-toolstrip .tinymce-mobile-toolbar.tinymce-mobile-context-toolbar .tinymce-mobile-toolbar-group .tinymce-mobile-slider.tinymce-mobile-hue-slider-container .tinymce-mobile-slider-gradient-container .tinymce-mobile-slider-gradient { + background: linear-gradient(to right, hsl(0, 100%, 50%) 0%, hsl(60, 100%, 50%) 17%, hsl(120, 100%, 50%) 33%, hsl(180, 100%, 50%) 50%, hsl(240, 100%, 50%) 67%, hsl(300, 100%, 50%) 83%, hsl(0, 100%, 50%) 100%); + display: flex; + flex: 1; + height: 0.2em; + margin-bottom: 0.3em; + margin-top: 0.3em; +} + +.tinymce-mobile-toolstrip .tinymce-mobile-toolbar.tinymce-mobile-context-toolbar .tinymce-mobile-toolbar-group .tinymce-mobile-slider.tinymce-mobile-hue-slider-container .tinymce-mobile-hue-slider-black { + /* Not part of theming */ + background: black; + height: 0.2em; + margin-bottom: 0.3em; + margin-top: 0.3em; + width: 1.2em; +} + +.tinymce-mobile-toolstrip .tinymce-mobile-toolbar.tinymce-mobile-context-toolbar .tinymce-mobile-toolbar-group .tinymce-mobile-slider.tinymce-mobile-hue-slider-container .tinymce-mobile-hue-slider-white { + /* Not part of theming */ + background: white; + height: 0.2em; + margin-bottom: 0.3em; + margin-top: 0.3em; + width: 1.2em; +} + +.tinymce-mobile-toolstrip .tinymce-mobile-toolbar.tinymce-mobile-context-toolbar .tinymce-mobile-toolbar-group .tinymce-mobile-slider .tinymce-mobile-slider-thumb { + /* vertically centering trick (margin: auto, top: 0, bottom: 0). On iOS and Safari, if you leave + * out these values, then it shows the thumb at the top of the spectrum. This is probably because it is + * absolutely positioned with only a left value, and not a top. Note, on Chrome it seems to be fine without + * this approach. + */ + align-items: center; + background-clip: padding-box; + background-color: #455a64; + border: 0.5em solid rgba(136, 136, 136, 0); + border-radius: 3em; + bottom: 0; + color: #fff; + display: flex; + height: 0.5em; + justify-content: center; + left: -10px; + margin: auto; + position: absolute; + top: 0; + transition: border 120ms cubic-bezier(0.39, 0.58, 0.57, 1); + width: 0.5em; +} + +.tinymce-mobile-toolstrip .tinymce-mobile-toolbar.tinymce-mobile-context-toolbar .tinymce-mobile-toolbar-group .tinymce-mobile-slider .tinymce-mobile-slider-thumb.tinymce-mobile-thumb-active { + border: 0.5em solid rgba(136, 136, 136, 0.39); +} + +.tinymce-mobile-toolstrip .tinymce-mobile-toolbar.tinymce-mobile-context-toolbar .tinymce-mobile-toolbar-group .tinymce-mobile-serializer-wrapper, +.tinymce-mobile-toolstrip .tinymce-mobile-toolbar.tinymce-mobile-context-toolbar .tinymce-mobile-toolbar-group > div { + align-items: center; + display: flex; + height: 100%; + flex: 1; +} + +.tinymce-mobile-toolstrip .tinymce-mobile-toolbar.tinymce-mobile-context-toolbar .tinymce-mobile-toolbar-group .tinymce-mobile-serializer-wrapper { + flex-direction: column; + justify-content: center; +} + +.tinymce-mobile-toolstrip .tinymce-mobile-toolbar.tinymce-mobile-context-toolbar .tinymce-mobile-toolbar-group .tinymce-mobile-toolbar-group-item { + align-items: center; + display: flex; +} + +.tinymce-mobile-toolstrip .tinymce-mobile-toolbar.tinymce-mobile-context-toolbar .tinymce-mobile-toolbar-group .tinymce-mobile-toolbar-group-item:not(.tinymce-mobile-serialised-dialog) { + height: 100%; +} + +.tinymce-mobile-toolstrip .tinymce-mobile-toolbar.tinymce-mobile-context-toolbar .tinymce-mobile-toolbar-group .tinymce-mobile-dot-container { + display: flex; +} + +.tinymce-mobile-toolstrip .tinymce-mobile-toolbar.tinymce-mobile-context-toolbar .tinymce-mobile-toolbar-group input { + background: #ffffff; + border: none; + border-radius: 0; + color: #455a64; + flex-grow: 1; + font-size: 0.85em; + padding-bottom: 0.1em; + padding-left: 5px; + padding-top: 0.1em; +} + +.tinymce-mobile-toolstrip .tinymce-mobile-toolbar.tinymce-mobile-context-toolbar .tinymce-mobile-toolbar-group input::-webkit-input-placeholder { + /* WebKit, Blink, Edge */ + color: #888; +} + +.tinymce-mobile-toolstrip .tinymce-mobile-toolbar.tinymce-mobile-context-toolbar .tinymce-mobile-toolbar-group input::placeholder { + /* WebKit, Blink, Edge */ + color: #888; +} + +/* dropup */ +.tinymce-mobile-dropup { + background: white; + display: flex; + overflow: hidden; + width: 100%; +} + +.tinymce-mobile-dropup.tinymce-mobile-dropup-shrinking { + transition: height 0.3s ease-out; +} + +.tinymce-mobile-dropup.tinymce-mobile-dropup-growing { + transition: height 0.3s ease-in; +} + +.tinymce-mobile-dropup.tinymce-mobile-dropup-closed { + flex-grow: 0; +} + +.tinymce-mobile-dropup.tinymce-mobile-dropup-open:not(.tinymce-mobile-dropup-growing) { + flex-grow: 1; +} + +/* TODO min-height for device size and orientation */ +.tinymce-mobile-ios-container .tinymce-mobile-dropup:not(.tinymce-mobile-dropup-closed) { + min-height: 200px; +} + +@media only screen and (orientation: landscape) { + .tinymce-mobile-dropup:not(.tinymce-mobile-dropup-closed) { + min-height: 200px; + } +} + +@media only screen and (min-device-width: 320px) and (max-device-width: 568px) and (orientation: landscape) { + .tinymce-mobile-ios-container .tinymce-mobile-dropup:not(.tinymce-mobile-dropup-closed) { + min-height: 150px; + } +} + +/* styles menu */ +.tinymce-mobile-styles-menu { + font-family: sans-serif; + outline: 4px solid black; + overflow: hidden; + position: relative; + width: 100%; +} + +.tinymce-mobile-styles-menu [role="menu"] { + display: flex; + flex-direction: column; + height: 100%; + position: absolute; + width: 100%; +} + +.tinymce-mobile-styles-menu [role="menu"].transitioning { + transition: transform 0.5s ease-in-out; +} + +.tinymce-mobile-styles-menu .tinymce-mobile-styles-item { + border-bottom: 1px solid #ddd; + color: #455a64; + cursor: pointer; + display: flex; + padding: 1em 1em; + position: relative; +} + +.tinymce-mobile-styles-menu .tinymce-mobile-styles-collapser .tinymce-mobile-styles-collapse-icon::before { + color: #455a64; + content: "\e314"; + font-family: 'tinymce-mobile', sans-serif; +} + +.tinymce-mobile-styles-menu .tinymce-mobile-styles-item.tinymce-mobile-styles-item-is-menu::after { + color: #455a64; + content: "\e315"; + font-family: 'tinymce-mobile', sans-serif; + padding-left: 1em; + padding-right: 1em; + position: absolute; + right: 0; +} + +.tinymce-mobile-styles-menu .tinymce-mobile-styles-item.tinymce-mobile-format-matches::after { + font-family: 'tinymce-mobile', sans-serif; + padding-left: 1em; + padding-right: 1em; + position: absolute; + right: 0; +} + +.tinymce-mobile-styles-menu .tinymce-mobile-styles-separator, +.tinymce-mobile-styles-menu .tinymce-mobile-styles-collapser { + align-items: center; + background: #fff; + border-top: #455a64; + color: #455a64; + display: flex; + min-height: 2.5em; + padding-left: 1em; + padding-right: 1em; +} + +.tinymce-mobile-styles-menu [data-transitioning-destination="before"][data-transitioning-state], +.tinymce-mobile-styles-menu [data-transitioning-state="before"] { + transform: translate(-100%); +} + +.tinymce-mobile-styles-menu [data-transitioning-destination="current"][data-transitioning-state], +.tinymce-mobile-styles-menu [data-transitioning-state="current"] { + transform: translate(0%); +} + +.tinymce-mobile-styles-menu [data-transitioning-destination="after"][data-transitioning-state], +.tinymce-mobile-styles-menu [data-transitioning-state="after"] { + transform: translate(100%); +} + +@font-face { + font-family: 'tinymce-mobile'; + font-style: normal; + font-weight: normal; + src: url('fonts/tinymce-mobile.woff?8x92w3') format('woff'); +} + +@media (min-device-width: 700px) { + .tinymce-mobile-outer-container, + .tinymce-mobile-outer-container input { + font-size: 25px; + } +} + +@media (max-device-width: 700px) { + .tinymce-mobile-outer-container, + .tinymce-mobile-outer-container input { + font-size: 18px; + } +} + +.tinymce-mobile-icon { + font-family: 'tinymce-mobile', sans-serif; +} + +.mixin-flex-and-centre { + align-items: center; + display: flex; + justify-content: center; +} + +.mixin-flex-bar { + align-items: center; + display: flex; + height: 100%; +} + +.tinymce-mobile-outer-container .tinymce-mobile-editor-socket iframe { + background-color: #fff; + width: 100%; +} + +.tinymce-mobile-editor-socket .tinymce-mobile-mask-edit-icon { + /* Note, on the iPod touch in landscape, this isn't visible when the navbar appears */ + background-color: #207ab7; + border-radius: 50%; + bottom: 1em; + color: white; + font-size: 1em; + height: 2.1em; + position: fixed; + right: 2em; + width: 2.1em; + align-items: center; + display: flex; + justify-content: center; +} + +@media only screen and (min-device-width: 700px) { + .tinymce-mobile-editor-socket .tinymce-mobile-mask-edit-icon { + font-size: 1.2em; + } +} + +.tinymce-mobile-outer-container:not(.tinymce-mobile-fullscreen-maximized) .tinymce-mobile-editor-socket { + height: 300px; + overflow: hidden; +} + +.tinymce-mobile-outer-container:not(.tinymce-mobile-fullscreen-maximized) .tinymce-mobile-editor-socket iframe { + height: 100%; +} + +.tinymce-mobile-outer-container:not(.tinymce-mobile-fullscreen-maximized) .tinymce-mobile-toolstrip { + display: none; +} + +/* + Note, that if you don't include this (::-webkit-file-upload-button), the toolbar width gets + increased and the whole body becomes scrollable. It's important! + */ +input[type="file"]::-webkit-file-upload-button { + display: none; +} + +@media only screen and (min-device-width: 320px) and (max-device-width: 568px) and (orientation: landscape) { + .tinymce-mobile-ios-container .tinymce-mobile-editor-socket .tinymce-mobile-mask-edit-icon { + bottom: 50%; + } +} diff --git a/frontend/public/tinymce-dataease-private/skins/ui/oxide/skin.mobile.min.css b/frontend/public/tinymce-dataease-private/skins/ui/oxide/skin.mobile.min.css new file mode 100644 index 0000000..3a45cac --- /dev/null +++ b/frontend/public/tinymce-dataease-private/skins/ui/oxide/skin.mobile.min.css @@ -0,0 +1,7 @@ +/** + * Copyright (c) Tiny Technologies, Inc. All rights reserved. + * Licensed under the LGPL or a commercial license. + * For LGPL see License.txt in the project root for license information. + * For commercial licenses see https://www.tiny.cloud/ + */ +.tinymce-mobile-outer-container{all:initial;display:block}.tinymce-mobile-outer-container *{border:0;box-sizing:initial;cursor:inherit;float:none;line-height:1;margin:0;outline:0;padding:0;-webkit-tap-highlight-color:transparent;text-shadow:none;white-space:nowrap}.tinymce-mobile-icon-arrow-back::before{content:"\e5cd"}.tinymce-mobile-icon-image::before{content:"\e412"}.tinymce-mobile-icon-cancel-circle::before{content:"\e5c9"}.tinymce-mobile-icon-full-dot::before{content:"\e061"}.tinymce-mobile-icon-align-center::before{content:"\e234"}.tinymce-mobile-icon-align-left::before{content:"\e236"}.tinymce-mobile-icon-align-right::before{content:"\e237"}.tinymce-mobile-icon-bold::before{content:"\e238"}.tinymce-mobile-icon-italic::before{content:"\e23f"}.tinymce-mobile-icon-unordered-list::before{content:"\e241"}.tinymce-mobile-icon-ordered-list::before{content:"\e242"}.tinymce-mobile-icon-font-size::before{content:"\e245"}.tinymce-mobile-icon-underline::before{content:"\e249"}.tinymce-mobile-icon-link::before{content:"\e157"}.tinymce-mobile-icon-unlink::before{content:"\eca2"}.tinymce-mobile-icon-color::before{content:"\e891"}.tinymce-mobile-icon-previous::before{content:"\e314"}.tinymce-mobile-icon-next::before{content:"\e315"}.tinymce-mobile-icon-large-font::before,.tinymce-mobile-icon-style-formats::before{content:"\e264"}.tinymce-mobile-icon-undo::before{content:"\e166"}.tinymce-mobile-icon-redo::before{content:"\e15a"}.tinymce-mobile-icon-removeformat::before{content:"\e239"}.tinymce-mobile-icon-small-font::before{content:"\e906"}.tinymce-mobile-format-matches::after,.tinymce-mobile-icon-readonly-back::before{content:"\e5ca"}.tinymce-mobile-icon-small-heading::before{content:"small"}.tinymce-mobile-icon-large-heading::before{content:"large"}.tinymce-mobile-icon-large-heading::before,.tinymce-mobile-icon-small-heading::before{font-family:sans-serif;font-size:80%}.tinymce-mobile-mask-edit-icon::before{content:"\e254"}.tinymce-mobile-icon-back::before{content:"\e5c4"}.tinymce-mobile-icon-heading::before{content:"Headings";font-family:sans-serif;font-size:80%;font-weight:700}.tinymce-mobile-icon-h1::before{content:"H1";font-weight:700}.tinymce-mobile-icon-h2::before{content:"H2";font-weight:700}.tinymce-mobile-icon-h3::before{content:"H3";font-weight:700}.tinymce-mobile-outer-container .tinymce-mobile-disabled-mask{align-items:center;display:flex;justify-content:center;background:rgba(51,51,51,.5);height:100%;position:absolute;top:0;width:100%}.tinymce-mobile-outer-container .tinymce-mobile-disabled-mask .tinymce-mobile-content-container{align-items:center;border-radius:50%;display:flex;flex-direction:column;font-family:sans-serif;font-size:1em;justify-content:space-between}.tinymce-mobile-outer-container .tinymce-mobile-disabled-mask .tinymce-mobile-content-container .mixin-menu-item{align-items:center;display:flex;justify-content:center;border-radius:50%;height:2.1em;width:2.1em}.tinymce-mobile-outer-container .tinymce-mobile-disabled-mask .tinymce-mobile-content-container .tinymce-mobile-content-tap-section{align-items:center;display:flex;justify-content:center;flex-direction:column;font-size:1em}@media only screen and (min-device-width:700px){.tinymce-mobile-outer-container .tinymce-mobile-disabled-mask .tinymce-mobile-content-container .tinymce-mobile-content-tap-section{font-size:1.2em}}.tinymce-mobile-outer-container .tinymce-mobile-disabled-mask .tinymce-mobile-content-container .tinymce-mobile-content-tap-section .tinymce-mobile-mask-tap-icon{align-items:center;display:flex;justify-content:center;border-radius:50%;height:2.1em;width:2.1em;background-color:#fff;color:#207ab7}.tinymce-mobile-outer-container .tinymce-mobile-disabled-mask .tinymce-mobile-content-container .tinymce-mobile-content-tap-section .tinymce-mobile-mask-tap-icon::before{content:"\e900";font-family:tinymce-mobile,sans-serif}.tinymce-mobile-outer-container .tinymce-mobile-disabled-mask .tinymce-mobile-content-container .tinymce-mobile-content-tap-section:not(.tinymce-mobile-mask-tap-icon-selected) .tinymce-mobile-mask-tap-icon{z-index:2}.tinymce-mobile-android-container.tinymce-mobile-android-maximized{background:#fff;border:none;bottom:0;display:flex;flex-direction:column;left:0;position:fixed;right:0;top:0}.tinymce-mobile-android-container:not(.tinymce-mobile-android-maximized){position:relative}.tinymce-mobile-android-container .tinymce-mobile-editor-socket{display:flex;flex-grow:1}.tinymce-mobile-android-container .tinymce-mobile-editor-socket iframe{display:flex!important;flex-grow:1;height:auto!important}.tinymce-mobile-android-scroll-reload{overflow:hidden}:not(.tinymce-mobile-readonly-mode)>.tinymce-mobile-android-selection-context-toolbar{margin-top:23px}.tinymce-mobile-toolstrip{background:#fff;display:flex;flex:0 0 auto;z-index:1}.tinymce-mobile-toolstrip .tinymce-mobile-toolbar{align-items:center;background-color:#fff;border-bottom:1px solid #ccc;display:flex;flex:1;height:2.5em;width:100%}.tinymce-mobile-toolstrip .tinymce-mobile-toolbar:not(.tinymce-mobile-context-toolbar) .tinymce-mobile-toolbar-group{align-items:center;display:flex;height:100%;flex-shrink:1}.tinymce-mobile-toolstrip .tinymce-mobile-toolbar:not(.tinymce-mobile-context-toolbar) .tinymce-mobile-toolbar-group>div{align-items:center;display:flex;height:100%;flex:1}.tinymce-mobile-toolstrip .tinymce-mobile-toolbar:not(.tinymce-mobile-context-toolbar) .tinymce-mobile-toolbar-group.tinymce-mobile-exit-container{background:#f44336}.tinymce-mobile-toolstrip .tinymce-mobile-toolbar:not(.tinymce-mobile-context-toolbar) .tinymce-mobile-toolbar-group.tinymce-mobile-toolbar-scrollable-group{flex-grow:1}.tinymce-mobile-toolstrip .tinymce-mobile-toolbar:not(.tinymce-mobile-context-toolbar) .tinymce-mobile-toolbar-group .tinymce-mobile-toolbar-group-item{padding-left:.5em;padding-right:.5em}.tinymce-mobile-toolstrip .tinymce-mobile-toolbar:not(.tinymce-mobile-context-toolbar) .tinymce-mobile-toolbar-group .tinymce-mobile-toolbar-group-item.tinymce-mobile-toolbar-button{align-items:center;display:flex;height:80%;margin-left:2px;margin-right:2px}.tinymce-mobile-toolstrip .tinymce-mobile-toolbar:not(.tinymce-mobile-context-toolbar) .tinymce-mobile-toolbar-group .tinymce-mobile-toolbar-group-item.tinymce-mobile-toolbar-button.tinymce-mobile-toolbar-button-selected{background:#c8cbcf;color:#ccc}.tinymce-mobile-toolstrip .tinymce-mobile-toolbar:not(.tinymce-mobile-context-toolbar) .tinymce-mobile-toolbar-group:first-of-type,.tinymce-mobile-toolstrip .tinymce-mobile-toolbar:not(.tinymce-mobile-context-toolbar) .tinymce-mobile-toolbar-group:last-of-type{background:#207ab7;color:#eceff1}.tinymce-mobile-toolstrip .tinymce-mobile-toolbar.tinymce-mobile-context-toolbar .tinymce-mobile-toolbar-group{align-items:center;display:flex;height:100%;flex:1;padding-bottom:.4em;padding-top:.4em}.tinymce-mobile-toolstrip .tinymce-mobile-toolbar.tinymce-mobile-context-toolbar .tinymce-mobile-toolbar-group .tinymce-mobile-serialised-dialog{display:flex;min-height:1.5em;overflow:hidden;padding-left:0;padding-right:0;position:relative;width:100%}.tinymce-mobile-toolstrip .tinymce-mobile-toolbar.tinymce-mobile-context-toolbar .tinymce-mobile-toolbar-group .tinymce-mobile-serialised-dialog .tinymce-mobile-serialised-dialog-chain{display:flex;height:100%;transition:left cubic-bezier(.4,0,1,1) .15s;width:100%}.tinymce-mobile-toolstrip .tinymce-mobile-toolbar.tinymce-mobile-context-toolbar .tinymce-mobile-toolbar-group .tinymce-mobile-serialised-dialog .tinymce-mobile-serialised-dialog-chain .tinymce-mobile-serialised-dialog-screen{display:flex;flex:0 0 auto;justify-content:space-between;width:100%}.tinymce-mobile-toolstrip .tinymce-mobile-toolbar.tinymce-mobile-context-toolbar .tinymce-mobile-toolbar-group .tinymce-mobile-serialised-dialog .tinymce-mobile-serialised-dialog-chain .tinymce-mobile-serialised-dialog-screen input{font-family:Sans-serif}.tinymce-mobile-toolstrip .tinymce-mobile-toolbar.tinymce-mobile-context-toolbar .tinymce-mobile-toolbar-group .tinymce-mobile-serialised-dialog .tinymce-mobile-serialised-dialog-chain .tinymce-mobile-serialised-dialog-screen .tinymce-mobile-input-container{display:flex;flex-grow:1;position:relative}.tinymce-mobile-toolstrip .tinymce-mobile-toolbar.tinymce-mobile-context-toolbar .tinymce-mobile-toolbar-group .tinymce-mobile-serialised-dialog .tinymce-mobile-serialised-dialog-chain .tinymce-mobile-serialised-dialog-screen .tinymce-mobile-input-container .tinymce-mobile-input-container-x{-ms-grid-row-align:center;align-self:center;background:inherit;border:none;border-radius:50%;color:#888;font-size:.6em;font-weight:700;height:100%;padding-right:2px;position:absolute;right:0}.tinymce-mobile-toolstrip .tinymce-mobile-toolbar.tinymce-mobile-context-toolbar .tinymce-mobile-toolbar-group .tinymce-mobile-serialised-dialog .tinymce-mobile-serialised-dialog-chain .tinymce-mobile-serialised-dialog-screen .tinymce-mobile-input-container.tinymce-mobile-input-container-empty .tinymce-mobile-input-container-x{display:none}.tinymce-mobile-toolstrip .tinymce-mobile-toolbar.tinymce-mobile-context-toolbar .tinymce-mobile-toolbar-group .tinymce-mobile-serialised-dialog .tinymce-mobile-serialised-dialog-chain .tinymce-mobile-serialised-dialog-screen .tinymce-mobile-icon-next,.tinymce-mobile-toolstrip .tinymce-mobile-toolbar.tinymce-mobile-context-toolbar .tinymce-mobile-toolbar-group .tinymce-mobile-serialised-dialog .tinymce-mobile-serialised-dialog-chain .tinymce-mobile-serialised-dialog-screen .tinymce-mobile-icon-previous{align-items:center;display:flex}.tinymce-mobile-toolstrip .tinymce-mobile-toolbar.tinymce-mobile-context-toolbar .tinymce-mobile-toolbar-group .tinymce-mobile-serialised-dialog .tinymce-mobile-serialised-dialog-chain .tinymce-mobile-serialised-dialog-screen .tinymce-mobile-icon-next::before,.tinymce-mobile-toolstrip .tinymce-mobile-toolbar.tinymce-mobile-context-toolbar .tinymce-mobile-toolbar-group .tinymce-mobile-serialised-dialog .tinymce-mobile-serialised-dialog-chain .tinymce-mobile-serialised-dialog-screen .tinymce-mobile-icon-previous::before{align-items:center;display:flex;font-weight:700;height:100%;padding-left:.5em;padding-right:.5em}.tinymce-mobile-toolstrip .tinymce-mobile-toolbar.tinymce-mobile-context-toolbar .tinymce-mobile-toolbar-group .tinymce-mobile-serialised-dialog .tinymce-mobile-serialised-dialog-chain .tinymce-mobile-serialised-dialog-screen .tinymce-mobile-icon-next.tinymce-mobile-toolbar-navigation-disabled::before,.tinymce-mobile-toolstrip .tinymce-mobile-toolbar.tinymce-mobile-context-toolbar .tinymce-mobile-toolbar-group .tinymce-mobile-serialised-dialog .tinymce-mobile-serialised-dialog-chain .tinymce-mobile-serialised-dialog-screen .tinymce-mobile-icon-previous.tinymce-mobile-toolbar-navigation-disabled::before{visibility:hidden}.tinymce-mobile-toolstrip .tinymce-mobile-toolbar.tinymce-mobile-context-toolbar .tinymce-mobile-toolbar-group .tinymce-mobile-dot-item{color:#ccc;font-size:10px;line-height:10px;margin:0 2px;padding-top:3px}.tinymce-mobile-toolstrip .tinymce-mobile-toolbar.tinymce-mobile-context-toolbar .tinymce-mobile-toolbar-group .tinymce-mobile-dot-item.tinymce-mobile-dot-active{color:#c8cbcf}.tinymce-mobile-toolstrip .tinymce-mobile-toolbar.tinymce-mobile-context-toolbar .tinymce-mobile-toolbar-group .tinymce-mobile-icon-large-font::before,.tinymce-mobile-toolstrip .tinymce-mobile-toolbar.tinymce-mobile-context-toolbar .tinymce-mobile-toolbar-group .tinymce-mobile-icon-large-heading::before{margin-left:.5em;margin-right:.9em}.tinymce-mobile-toolstrip .tinymce-mobile-toolbar.tinymce-mobile-context-toolbar .tinymce-mobile-toolbar-group .tinymce-mobile-icon-small-font::before,.tinymce-mobile-toolstrip .tinymce-mobile-toolbar.tinymce-mobile-context-toolbar .tinymce-mobile-toolbar-group .tinymce-mobile-icon-small-heading::before{margin-left:.9em;margin-right:.5em}.tinymce-mobile-toolstrip .tinymce-mobile-toolbar.tinymce-mobile-context-toolbar .tinymce-mobile-toolbar-group .tinymce-mobile-slider{display:flex;flex:1;margin-left:0;margin-right:0;padding:.28em 0;position:relative}.tinymce-mobile-toolstrip .tinymce-mobile-toolbar.tinymce-mobile-context-toolbar .tinymce-mobile-toolbar-group .tinymce-mobile-slider .tinymce-mobile-slider-size-container{align-items:center;display:flex;flex-grow:1;height:100%}.tinymce-mobile-toolstrip .tinymce-mobile-toolbar.tinymce-mobile-context-toolbar .tinymce-mobile-toolbar-group .tinymce-mobile-slider .tinymce-mobile-slider-size-container .tinymce-mobile-slider-size-line{background:#ccc;display:flex;flex:1;height:.2em;margin-bottom:.3em;margin-top:.3em}.tinymce-mobile-toolstrip .tinymce-mobile-toolbar.tinymce-mobile-context-toolbar .tinymce-mobile-toolbar-group .tinymce-mobile-slider.tinymce-mobile-hue-slider-container{padding-left:2em;padding-right:2em}.tinymce-mobile-toolstrip .tinymce-mobile-toolbar.tinymce-mobile-context-toolbar .tinymce-mobile-toolbar-group .tinymce-mobile-slider.tinymce-mobile-hue-slider-container .tinymce-mobile-slider-gradient-container{align-items:center;display:flex;flex-grow:1;height:100%}.tinymce-mobile-toolstrip .tinymce-mobile-toolbar.tinymce-mobile-context-toolbar .tinymce-mobile-toolbar-group .tinymce-mobile-slider.tinymce-mobile-hue-slider-container .tinymce-mobile-slider-gradient-container .tinymce-mobile-slider-gradient{background:linear-gradient(to right,red 0,#feff00 17%,#0f0 33%,#00feff 50%,#00f 67%,#ff00fe 83%,red 100%);display:flex;flex:1;height:.2em;margin-bottom:.3em;margin-top:.3em}.tinymce-mobile-toolstrip .tinymce-mobile-toolbar.tinymce-mobile-context-toolbar .tinymce-mobile-toolbar-group .tinymce-mobile-slider.tinymce-mobile-hue-slider-container .tinymce-mobile-hue-slider-black{background:#000;height:.2em;margin-bottom:.3em;margin-top:.3em;width:1.2em}.tinymce-mobile-toolstrip .tinymce-mobile-toolbar.tinymce-mobile-context-toolbar .tinymce-mobile-toolbar-group .tinymce-mobile-slider.tinymce-mobile-hue-slider-container .tinymce-mobile-hue-slider-white{background:#fff;height:.2em;margin-bottom:.3em;margin-top:.3em;width:1.2em}.tinymce-mobile-toolstrip .tinymce-mobile-toolbar.tinymce-mobile-context-toolbar .tinymce-mobile-toolbar-group .tinymce-mobile-slider .tinymce-mobile-slider-thumb{align-items:center;background-clip:padding-box;background-color:#455a64;border:.5em solid rgba(136,136,136,0);border-radius:3em;bottom:0;color:#fff;display:flex;height:.5em;justify-content:center;left:-10px;margin:auto;position:absolute;top:0;transition:border 120ms cubic-bezier(.39,.58,.57,1);width:.5em}.tinymce-mobile-toolstrip .tinymce-mobile-toolbar.tinymce-mobile-context-toolbar .tinymce-mobile-toolbar-group .tinymce-mobile-slider .tinymce-mobile-slider-thumb.tinymce-mobile-thumb-active{border:.5em solid rgba(136,136,136,.39)}.tinymce-mobile-toolstrip .tinymce-mobile-toolbar.tinymce-mobile-context-toolbar .tinymce-mobile-toolbar-group .tinymce-mobile-serializer-wrapper,.tinymce-mobile-toolstrip .tinymce-mobile-toolbar.tinymce-mobile-context-toolbar .tinymce-mobile-toolbar-group>div{align-items:center;display:flex;height:100%;flex:1}.tinymce-mobile-toolstrip .tinymce-mobile-toolbar.tinymce-mobile-context-toolbar .tinymce-mobile-toolbar-group .tinymce-mobile-serializer-wrapper{flex-direction:column;justify-content:center}.tinymce-mobile-toolstrip .tinymce-mobile-toolbar.tinymce-mobile-context-toolbar .tinymce-mobile-toolbar-group .tinymce-mobile-toolbar-group-item{align-items:center;display:flex}.tinymce-mobile-toolstrip .tinymce-mobile-toolbar.tinymce-mobile-context-toolbar .tinymce-mobile-toolbar-group .tinymce-mobile-toolbar-group-item:not(.tinymce-mobile-serialised-dialog){height:100%}.tinymce-mobile-toolstrip .tinymce-mobile-toolbar.tinymce-mobile-context-toolbar .tinymce-mobile-toolbar-group .tinymce-mobile-dot-container{display:flex}.tinymce-mobile-toolstrip .tinymce-mobile-toolbar.tinymce-mobile-context-toolbar .tinymce-mobile-toolbar-group input{background:#fff;border:none;border-radius:0;color:#455a64;flex-grow:1;font-size:.85em;padding-bottom:.1em;padding-left:5px;padding-top:.1em}.tinymce-mobile-toolstrip .tinymce-mobile-toolbar.tinymce-mobile-context-toolbar .tinymce-mobile-toolbar-group input::-webkit-input-placeholder{color:#888}.tinymce-mobile-toolstrip .tinymce-mobile-toolbar.tinymce-mobile-context-toolbar .tinymce-mobile-toolbar-group input::placeholder{color:#888}.tinymce-mobile-dropup{background:#fff;display:flex;overflow:hidden;width:100%}.tinymce-mobile-dropup.tinymce-mobile-dropup-shrinking{transition:height .3s ease-out}.tinymce-mobile-dropup.tinymce-mobile-dropup-growing{transition:height .3s ease-in}.tinymce-mobile-dropup.tinymce-mobile-dropup-closed{flex-grow:0}.tinymce-mobile-dropup.tinymce-mobile-dropup-open:not(.tinymce-mobile-dropup-growing){flex-grow:1}.tinymce-mobile-ios-container .tinymce-mobile-dropup:not(.tinymce-mobile-dropup-closed){min-height:200px}@media only screen and (orientation:landscape){.tinymce-mobile-dropup:not(.tinymce-mobile-dropup-closed){min-height:200px}}@media only screen and (min-device-width :320px) and (max-device-width :568px) and (orientation :landscape){.tinymce-mobile-ios-container .tinymce-mobile-dropup:not(.tinymce-mobile-dropup-closed){min-height:150px}}.tinymce-mobile-styles-menu{font-family:sans-serif;outline:4px solid #000;overflow:hidden;position:relative;width:100%}.tinymce-mobile-styles-menu [role=menu]{display:flex;flex-direction:column;height:100%;position:absolute;width:100%}.tinymce-mobile-styles-menu [role=menu].transitioning{transition:transform .5s ease-in-out}.tinymce-mobile-styles-menu .tinymce-mobile-styles-item{border-bottom:1px solid #ddd;color:#455a64;cursor:pointer;display:flex;padding:1em 1em;position:relative}.tinymce-mobile-styles-menu .tinymce-mobile-styles-collapser .tinymce-mobile-styles-collapse-icon::before{color:#455a64;content:"\e314";font-family:tinymce-mobile,sans-serif}.tinymce-mobile-styles-menu .tinymce-mobile-styles-item.tinymce-mobile-styles-item-is-menu::after{color:#455a64;content:"\e315";font-family:tinymce-mobile,sans-serif;padding-left:1em;padding-right:1em;position:absolute;right:0}.tinymce-mobile-styles-menu .tinymce-mobile-styles-item.tinymce-mobile-format-matches::after{font-family:tinymce-mobile,sans-serif;padding-left:1em;padding-right:1em;position:absolute;right:0}.tinymce-mobile-styles-menu .tinymce-mobile-styles-collapser,.tinymce-mobile-styles-menu .tinymce-mobile-styles-separator{align-items:center;background:#fff;border-top:#455a64;color:#455a64;display:flex;min-height:2.5em;padding-left:1em;padding-right:1em}.tinymce-mobile-styles-menu [data-transitioning-destination=before][data-transitioning-state],.tinymce-mobile-styles-menu [data-transitioning-state=before]{transform:translate(-100%)}.tinymce-mobile-styles-menu [data-transitioning-destination=current][data-transitioning-state],.tinymce-mobile-styles-menu [data-transitioning-state=current]{transform:translate(0)}.tinymce-mobile-styles-menu [data-transitioning-destination=after][data-transitioning-state],.tinymce-mobile-styles-menu [data-transitioning-state=after]{transform:translate(100%)}@font-face{font-family:tinymce-mobile;font-style:normal;font-weight:400;src:url(fonts/tinymce-mobile.woff?8x92w3) format('woff')}@media (min-device-width:700px){.tinymce-mobile-outer-container,.tinymce-mobile-outer-container input{font-size:25px}}@media (max-device-width:700px){.tinymce-mobile-outer-container,.tinymce-mobile-outer-container input{font-size:18px}}.tinymce-mobile-icon{font-family:tinymce-mobile,sans-serif}.mixin-flex-and-centre{align-items:center;display:flex;justify-content:center}.mixin-flex-bar{align-items:center;display:flex;height:100%}.tinymce-mobile-outer-container .tinymce-mobile-editor-socket iframe{background-color:#fff;width:100%}.tinymce-mobile-editor-socket .tinymce-mobile-mask-edit-icon{background-color:#207ab7;border-radius:50%;bottom:1em;color:#fff;font-size:1em;height:2.1em;position:fixed;right:2em;width:2.1em;align-items:center;display:flex;justify-content:center}@media only screen and (min-device-width:700px){.tinymce-mobile-editor-socket .tinymce-mobile-mask-edit-icon{font-size:1.2em}}.tinymce-mobile-outer-container:not(.tinymce-mobile-fullscreen-maximized) .tinymce-mobile-editor-socket{height:300px;overflow:hidden}.tinymce-mobile-outer-container:not(.tinymce-mobile-fullscreen-maximized) .tinymce-mobile-editor-socket iframe{height:100%}.tinymce-mobile-outer-container:not(.tinymce-mobile-fullscreen-maximized) .tinymce-mobile-toolstrip{display:none}input[type=file]::-webkit-file-upload-button{display:none}@media only screen and (min-device-width :320px) and (max-device-width :568px) and (orientation :landscape){.tinymce-mobile-ios-container .tinymce-mobile-editor-socket .tinymce-mobile-mask-edit-icon{bottom:50%}} diff --git a/frontend/public/tinymce-dataease-private/skins/ui/oxide/skin.shadowdom.css b/frontend/public/tinymce-dataease-private/skins/ui/oxide/skin.shadowdom.css new file mode 100644 index 0000000..16f4d30 --- /dev/null +++ b/frontend/public/tinymce-dataease-private/skins/ui/oxide/skin.shadowdom.css @@ -0,0 +1,42 @@ +/** + * Copyright (c) Tiny Technologies, Inc. All rights reserved. + * Licensed under the LGPL or a commercial license. + * For LGPL see License.txt in the project root for license information. + * For commercial licenses see https://www.tiny.cloud/ + */ +body.tox-dialog__disable-scroll { + overflow: hidden; +} + +.tox-fullscreen { + border: 0; + height: 100%; + left: 0; + margin: 0; + overflow: hidden; + -ms-scroll-chaining: none; + overscroll-behavior: none; + padding: 0; + position: fixed; + top: 0; + touch-action: pinch-zoom; + width: 100%; +} + +.tox.tox-tinymce.tox-fullscreen .tox-statusbar__resize-handle { + display: none; +} + +.tox.tox-tinymce.tox-fullscreen { + background-color: transparent; + z-index: 1200; +} + +.tox-shadowhost.tox-fullscreen { + z-index: 1200; +} + +.tox-fullscreen .tox.tox-tinymce-aux, +.tox-fullscreen ~ .tox.tox-tinymce-aux { + z-index: 1201; +} diff --git a/frontend/public/tinymce-dataease-private/skins/ui/oxide/skin.shadowdom.min.css b/frontend/public/tinymce-dataease-private/skins/ui/oxide/skin.shadowdom.min.css new file mode 100644 index 0000000..9ba6e02 --- /dev/null +++ b/frontend/public/tinymce-dataease-private/skins/ui/oxide/skin.shadowdom.min.css @@ -0,0 +1,7 @@ +/** + * Copyright (c) Tiny Technologies, Inc. All rights reserved. + * Licensed under the LGPL or a commercial license. + * For LGPL see License.txt in the project root for license information. + * For commercial licenses see https://www.tiny.cloud/ + */ +body.tox-dialog__disable-scroll{overflow:hidden}.tox-fullscreen{border:0;height:100%;left:0;margin:0;overflow:hidden;-ms-scroll-chaining:none;overscroll-behavior:none;padding:0;position:fixed;top:0;touch-action:pinch-zoom;width:100%}.tox.tox-tinymce.tox-fullscreen .tox-statusbar__resize-handle{display:none}.tox.tox-tinymce.tox-fullscreen{background-color:transparent;z-index:1200}.tox-shadowhost.tox-fullscreen{z-index:1200}.tox-fullscreen .tox.tox-tinymce-aux,.tox-fullscreen~.tox.tox-tinymce-aux{z-index:1201} diff --git a/frontend/public/vite.svg b/frontend/public/vite.svg new file mode 100644 index 0000000..e7b8dfb --- /dev/null +++ b/frontend/public/vite.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/src/data-visualization/api/chart.ts b/frontend/src/api/chart.ts similarity index 100% rename from frontend/src/data-visualization/api/chart.ts rename to frontend/src/api/chart.ts diff --git a/frontend/src/api/data-visualization/chart.ts b/frontend/src/api/data-visualization/chart.ts new file mode 100644 index 0000000..b1bad2d --- /dev/null +++ b/frontend/src/api/data-visualization/chart.ts @@ -0,0 +1,124 @@ +import request from '@/data-visualization/config/axios' +export interface Field { + id: number | string + datasourceId: number | string + datasetTableId: number | string + datasetGroupId: number | string + originName: string + name: string + dataeaseName: string + groupType: string + type: string + deType: number + deExtractType: number + extField: number + checked: boolean + fieldShortName: string + desensitized: boolean +} + +export interface ComponentInfo { + id: string + name: string + deType: number + type: string + datasetId: string +} + +export const getFieldByDQ = async (id, chartId, data): Promise => { + return request.post({ url: `/chart/listByDQ/${id}/${chartId}`, data: data }).then(res => { + return res?.data + }) +} + +export const copyChartField = async (id, chartId): Promise => { + return request.post({ url: `/chart/copyField/${id}/${chartId}`, data: {} }).then(res => { + return res?.data + }) +} + +export const deleteChartField = async (id): Promise => { + return request.post({ url: `/chart/deleteField/${id}`, data: {} }).then(res => { + return res?.data + }) +} + +export const deleteChartFieldByChartId = async (chartId): Promise => { + return request.post({ url: `/chart/deleteFieldByChart/${chartId}`, data: {} }).then(res => { + return res?.data + }) +} + +// 通过图表对象获取数据 +export const getData = async (data): Promise => { + delete data.data + return request.post({ url: '/chartData/getData', data }).then(res => { + if (res.code === 0) { + return res?.data + } else { + return res + } + }) +} + +export const innerExportDetails = async (data): Promise => { + return request.post({ + url: '/chartData/innerExportDetails', + method: 'post', + data: data, + loading: true, + responseType: 'blob' + }) +} + +export const innerExportDataSetDetails = async (data): Promise => { + return request.post({ + url: '/chartData/innerExportDataSetDetails', + method: 'post', + data: data, + loading: true, + responseType: 'blob' + }) +} + +// 通过图表id获取数据 +export const getChart = async (id): Promise => { + return request.post({ url: `/chart/getChart/${id}`, data: {} }).then(res => { + return res?.data + }) +} + +// 单个图表保存测试 +export const saveChart = async (data): Promise => { + delete data.data + return request.post({ url: '/chart/save', data }).then(res => { + return res?.data + }) +} + +// 获取单个字段枚举值 +export const getFieldData = async ({ fieldId, fieldType, data }): Promise => { + delete data.data + return request + .post({ url: `/chartData/getFieldData/${fieldId}/${fieldType}`, data }) + .then(res => { + return res + }) +} + +// 获取下钻字段枚举值 +export const getDrillFieldData = async ({ fieldId, data }): Promise => { + delete data.data + return request.post({ url: `/chartData/getDrillFieldData/${fieldId}`, data }).then(res => { + return res + }) +} + +export const getChartDetail = async (id: string): Promise => { + return request.post({ url: `chart/getDetail/${id}`, data: {} }).then(res => { + return res + }) +} + +export const checkSameDataSet = async (viewIdSource, viewIdTarget) => + request.get({ url: '/chart/checkSameDataSet/' + viewIdSource + '/' + viewIdTarget }) diff --git a/frontend/src/api/data-visualization/dataset.ts b/frontend/src/api/data-visualization/dataset.ts new file mode 100644 index 0000000..e5babfb --- /dev/null +++ b/frontend/src/api/data-visualization/dataset.ts @@ -0,0 +1,368 @@ +import request from '@/utils/request' +import { type Field } from '@/api/data-visualization/chart' +import { nameTrim } from '@/data-visualization/utils/utils' +export interface DatasetOrFolder { + name: string + action?: string + id?: number | string + pid?: number | string + appId?: number | string + nodeType: 'folder' | 'dataset' + union?: Array<{}> + allFields?: Array<{}> +} + +export interface EnumValue { + queryId: string + displayId?: string + sortId?: string + sort?: string + resultMode?: number + searchText: string + filter?: Array<{}> +} + +interface Fields { + fields: Array<{}> + data: Array<{}> +} +export interface ParamsDetail { + datasetGroupId: string + type: Array + variableName: string +} + +export interface DatasetDetail { + id: string + name: string + componentId: string + fields: { + dimensionList: Array + quotaList: Array + parameterList?: Array + } + activelist?: string + hasParameter?: boolean + checkList: string[] + list: Array +} + +export interface FieldData { + allFields: Array<{}> + data: Fields + total?: number +} + +export interface Dataset { + id: string + pid: string + name: string + union?: Array<{}> + allFields?: Array<{}> +} + +export interface Table { + datasourceId: string + name: string + tableName: string + type: string + unableCheck?: boolean +} +// 获取权限路 +// edit +export const saveDatasetTree = async (data: DatasetOrFolder): Promise => { + nameTrim(data) + return request.post({ url: '/datasetTree/save', data }).then(res => { + return res?.data + }) +} + +// create +export const createDatasetTree = async (data: DatasetOrFolder): Promise => { + nameTrim(data) + return request.post({ url: '/datasetTree/create', data }).then(res => { + return res?.data + }) +} + +// rename +export const renameDatasetTree = async (data: DatasetOrFolder): Promise => { + nameTrim(data) + return request.post({ url: '/datasetTree/rename', data }).then(res => { + return res?.data + }) +} + +export const enumValueObj = async (data: EnumValue): Promise[]> => { + return request.post({ url: '/datasetData/enumValueObj', data }).then(res => { + return res?.data + }) +} + +export const enumValueDs = async (data: any): Promise[]> => { + return request.post({ url: '/datasetData/enumValueDs', data }).then(res => { + return res?.data + }) +} + +export const moveDatasetTree = async (data: DatasetOrFolder): Promise => { + return request.post({ url: '/datasetTree/move', data }).then(res => { + return res?.data + }) +} + +export const getDatasetTree = async (data: any): Promise => { + data.busiFlag = 'dataset' + return request.post({ url: '/datasetTree/tree', data }).then(res => { + return res?.data + }) +} + +export const barInfoApi = async (id): Promise => { + return request.get({ url: `/datasetTree/barInfo/${id}`, data: {} }).then(res => { + return res?.data + }) +} + +export const delDatasetTree = async (id): Promise => { + return request.post({ url: `/datasetTree/delete/${id}`, data: {} }).then(res => { + return res?.data + }) +} + +export const exportDatasetData = (data = {}) => { + return request.post({ + url: '/datasetTree/exportDataset', + method: 'post', + data: data, + loading: true + }) +} + +export const exportLimit = async (): Promise => { + return request.post({ url: `/exportCenter/exportLimit`, data: {} }).then(res => { + return res?.data + }) +} + +export const perDelete = async (id): Promise => { + return request.post({ url: `/datasetTree/perDelete/${id}`, data: {} }).then(res => { + return res?.data + }) +} + +export const getDatasourceList = async (weight: number,appId:any): Promise => { + const data = { + busiFlag: 'datasource', + appId:appId + } + if (weight) { + data['weight'] = weight + } + return request.post({ url: '/datasource/tree', data }).then(res => { + return res?.data + }) +} + +export const getTables = async (data): Promise => { + return request.post({ url: `/datasource/getTables`, data }).then(res => { + return res?.data + }) +} + +export const getTableField = async (data): Promise => { + return request.post({ url: '/datasetData/tableField', data }).then(res => { + return res?.data + }) +} + +export const getPreviewData = async (data): Promise => { + return request.post({ url: '/datasetData/previewData', data }).then(res => { + return res?.data + }) +} + +export const getDatasetPreview = async (id): Promise => { + return request.post({ url: `/datasetTree/get/${id}`, data: {} }).then(res => { + return res?.data + }) +} + +export const getDatasetTotal = async (id): Promise => { + return request.post({ url: `/datasetData/getDatasetTotal`, data: { id: id } }).then(res => { + return res?.data + }) +} + +export const getDatasetDetails = async (id): Promise => { + return request.post({ url: `/datasetTree/details/${id}`, data: {} }).then(res => { + return res?.data + }) +} + +export const tableUpdate = async (data): Promise => { + return request.post({ url: '/dataset/table/update', data }).then(res => { + return res?.data + }) +} + +export const getPreviewSql = async (data): Promise => { + return request.post({ url: '/datasetData/previewSql', data }).then(res => { + return res?.data + }) +} + +export const getDsDetails = async (data): Promise => { + return request.post({ url: '/datasetTree/dsDetails', data }).then(res => { + return res?.data + }) +} +export const getDsDetailsWithPerm = async (data): Promise => { + return request.post({ url: '/datasetTree/detailWithPerm', data }).then(res => { + return res?.data + }) +} +export const getSqlParams = async (data): Promise => { + return request.post({ url: '/datasetTree/getSqlParams', data }).then(res => { + return res?.data + }) +} +export const rowPermissionList = (page: number, limit: number, datasetId: number) => + request.get({ url: '/dataset/rowPermissions/pager/' + datasetId + '/' + page + '/' + limit }) + +export const columnPermissionList = (page: number, limit: number, datasetId: number) => + request.get({ url: '/dataset/columnPermissions/pager/' + datasetId + '/' + page + '/' + limit }) + +export const rowPermissionTargetObjList = (datasetId: number, type: string) => + request.get({ url: '/dataset/rowPermissions/authObjs/' + datasetId + '/' + type }) + +export const listFieldByDatasetGroup = (datasetId: number) => + request.post({ url: '/datasetField/listByDatasetGroup/' + datasetId }) + +export const multFieldValuesForPermissions = (data = {}) => { + return request.post({ url: '/datasetField/multFieldValuesForPermissions', data }) +} + +export const listFieldsWithPermissions = (datasetId: number) => { + return request.get({ url: '/datasetField/listWithPermissions/' + datasetId }) +} + +export const copilotFields = (datasetId: number) => { + return request.post({ url: '/datasetField/copilotFields/' + datasetId }) +} + +export const saveRowPermission = (data = {}) => { + return request.post({ url: '/dataset/rowPermissions/save', data }) +} + +export const saveColumnPermission = (data = {}) => { + return request.post({ url: '/dataset/columnPermissions/save', data }) +} + +export const deleteRowPermission = (data = {}) => { + return request.post({ url: '/dataset/rowPermissions/delete', data }) +} + +export const deleteColumnPermission = (data = {}) => { + return request.post({ url: '/dataset/columnPermissions/delete', data }) +} + +export const whiteListUsersForPermissions = (data = {}) => { + return request.post({ url: '/dataset/rowPermissions/whiteListUsers', data }) +} + +export const saveField = async (data): Promise => { + return request.post({ url: '/datasetField/save', data }).then(res => { + return res?.data + }) +} + +export const deleteField = async (id): Promise => { + return request.post({ url: `/datasetField/delete/${id}`, data: {} }).then(res => { + return res?.data + }) +} + +export const deleteFieldByChartId = async (id): Promise => { + return request.post({ url: `/datasetField/deleteByChartId/${id}`, data: {} }).then(res => { + return res?.data + }) +} + +export const getEnumValue = async (data): Promise => { + return request.post({ url: '/datasetData/enumValue', data }).then(res => { + return res?.data + }) +} + +export const getFunction = async (): Promise => { + return request.post({ url: '/datasetField/getFunction', data: {} }).then(res => { + return res?.data + }) +} + +export const exportTasks = async (type): Promise => { + return request.post({ url: '/exportCenter/exportTasks/' + type, data: {} }).then(res => { + return res + }) +} + +export const exportRetry = async (id): Promise => { + return request.post({ url: '/exportCenter/retry/' + id, data: {} }).then(res => { + return res?.data + }) +} + +export const downloadFile = async (id): Promise => { + return request.get({ url: 'exportCenter/download/' + id, responseType: 'blob' }).then(res => { + return res?.data + }) +} + +export const exportDelete = async (id): Promise => { + return request.get({ url: '/exportCenter/delete/' + id }).then(res => { + return res?.data + }) +} + +export const exportDeleteAll = async (type, data): Promise => { + return request.post({ url: '/exportCenter/deleteAll/' + type, data }).then(res => { + return res?.data + }) +} + +export const exportDeletePost = async (data): Promise => { + return request.post({ url: '/exportCenter/delete', data }).then(res => { + return res?.data + }) +} + +export const listByDsIds = async (data): Promise => { + return request.post({ url: 'datasetField/listByDsIds', data }).then(res => { + return res?.data + }) +} + +export const getFieldTree = async (data): Promise => { + return request.post({ url: 'datasetData/getFieldTree', data }).then(res => { + return res?.data + }) +} + +export const copilotChat = async (data): Promise => { + return request.post({ url: '/copilot/chat', data }).then(res => { + return res?.data + }) +} + +export const getListCopilot = async (): Promise => { + return request.post({ url: '/copilot/getList' }).then(res => { + return res?.data + }) +} + +export const clearAllCopilot = async (): Promise => { + return request.post({ url: '/copilot/clearAll' }).then(res => { + return res?.data + }) +} diff --git a/frontend/src/api/data-visualization/map.ts b/frontend/src/api/data-visualization/map.ts new file mode 100644 index 0000000..265ddb4 --- /dev/null +++ b/frontend/src/api/data-visualization/map.ts @@ -0,0 +1,53 @@ +import request from '@/data-visualization/config/axios' +import { FeatureCollection } from '@antv/l7plot/dist/esm/plots/choropleth/types' + +export const getWorldTree = (): Promise> => { + return request.get({ url: '/map/worldTree' }) +} + +export const getGeoJson = (areaId: string): Promise> => { + let prefix = '/map' + let areaCode = areaId + if (isCustomGeo(areaId)) { + prefix = '/geo' + areaCode = getBusiGeoCode(areaId) + } + const realCountry = areaCode.substring(0, 3) + const url = `${prefix}/${realCountry}/${areaCode}.json` + return request.get({ url }) +} + +const isCustomGeo = (id: string) => { + return id.startsWith('geo_') +} +const getBusiGeoCode = (id: string) => { + return id.substring(4) +} + +export const listCustomGeoArea = (): Promise> => { + return request.get({ url: '/customGeo/geoArea/list' }) +} + +export const getCustomGeoArea = (id: string): Promise> => { + return request.get({ url: `/customGeo/geoArea/${id}` }) +} + +export const deleteCustomGeoArea = (id: string) => { + return request.delete({ url: `/customGeo/geoArea/${id}` }) +} + +export const saveCustomGeoArea = (area: CustomGeoArea) => { + return request.post({ url: '/customGeo/geoArea/save', data: area }) +} + +export const deleteCustomGeoSubArea = (id: string) => { + return request.delete({ url: `/customGeo/geoSubArea/${id}` }) +} + +export const saveCustomGeoSubArea = (area: CustomGeoSubArea) => { + return request.post({ url: '/customGeo/geoSubArea/save', data: area }) +} + +export const listSubAreaOptions = (): Promise> => { + return request.get({ url: '/customGeo/geoSubArea/options' }) +} diff --git a/frontend/src/api/data-visualization/staticResource.ts b/frontend/src/api/data-visualization/staticResource.ts new file mode 100644 index 0000000..88e71f5 --- /dev/null +++ b/frontend/src/api/data-visualization/staticResource.ts @@ -0,0 +1,33 @@ +import request from '@/data-visualization/config/axios' +import { ElMessage } from 'element-plus-secondary' + +const staticResourcePath = '/static-resource/' +export const uploadFile = (fileId: number | string, param) => + request.post({ + url: '/staticResource/upload/' + fileId, + headersType: 'multipart/form-data', + loading: true, + data: param + }) + +export function beforeUploadCheck(file) { + const isImage = file.type.startsWith('image/') + const isSizeValid = file.size / 1024 / 1024 < 15 // 15MB + + if (!isImage) { + ElMessage.error('请上传图片') + return false + } + if (!isSizeValid) { + ElMessage.error('图片大小不能超过15M') + return false + } + return true +} + +export function findResourceAsBase64(params) { + return request.post({ + url: '/staticResource/findResourceAsBase64', + data: params + }) +} diff --git a/frontend/src/api/data-visualization/user.ts b/frontend/src/api/data-visualization/user.ts new file mode 100644 index 0000000..1e733eb --- /dev/null +++ b/frontend/src/api/data-visualization/user.ts @@ -0,0 +1,3 @@ +import request from '@/data-visualization/config/axios' + +export const ipInfoApi = () => request.get({ url: `/user/ipInfo` }) \ No newline at end of file diff --git a/frontend/src/api/data-visualization/visualization/dataVisualization.ts b/frontend/src/api/data-visualization/visualization/dataVisualization.ts new file mode 100644 index 0000000..efb4753 --- /dev/null +++ b/frontend/src/api/data-visualization/visualization/dataVisualization.ts @@ -0,0 +1,135 @@ +import request from '@/data-visualization/config/axios' +export interface ResourceOrFolder { + name: string + id?: number | string + pid?: number | string + nodeType: 'folder' | 'leaf' + type: string +} + +export interface Panel { + name: string + type: string + updateTime: number + createBy: string + updateBy: string +} + +export const findCopyResource = async (dvId, busiFlag): Promise => { + return request.get({ url: '/dataVisualization/findCopyResource/' + dvId + '/' + busiFlag }) +} + +export const findById = async ( + dvId, + busiFlag, + attachInfo = { source: 'main', taskId: null } +): Promise => { + let busiFlagResult = busiFlag + if (!busiFlagResult) { + await findDvType(dvId).then(res => { + busiFlagResult = res.data + }) + } + const data = { id: dvId, busiFlag: busiFlagResult, ...attachInfo } + return request.post({ url: '/dataVisualization/findById', data }) +} + +export const updateCheckVersion = dvId => + request.get({ url: `/dataVisualization/updateCheckVersion/${dvId}` }) + +export const queryTreeApi = async (data: any): Promise => { + return request.post({ url: '/dataVisualization/tree', data }).then(res => { + return res?.data + }) +} + +export const queryBusiTreeApi = async (data): Promise => { + return request.post({ url: '/dataVisualization/interactiveTree', data }).then(res => { + return res?.data + }) +} + +export const findDvType = async dvId => + request.get({ url: `/dataVisualization/findDvType/${dvId}` }) + +export const save = data => request.post({ url: '/dataVisualization/save', data }) + +export const checkCanvasChange = data => + request.post({ url: '/dataVisualization/checkCanvasChange', data, loading: true }) + +export const saveCanvas = data => + request.post({ url: '/dataVisualization/saveCanvas', data, loading: true }) + +export const appCanvasNameCheck = async data => + request.post({ url: '/dataVisualization/appCanvasNameCheck', data, loading: false }) + +export const updateBase = data => request.post({ url: '/dataVisualization/updateBase', data }) + +export const updateCanvas = data => + request.post({ url: '/dataVisualization/updateCanvas', data, loading: true }) + +export const moveResource = data => request.post({ url: '/dataVisualization/move', data }) + +export const copyResource = data => request.post({ url: '/dataVisualization/copy', data }) + +export const deleteLogic = (dvId, busiFlag) => + request.post({ url: '/dataVisualization/deleteLogic/' + dvId + '/' + busiFlag }) + +export const querySubjectWithGroupApi = data => + request.post({ url: '/visualizationSubject/querySubjectWithGroup', data }) + +export const saveOrUpdateSubject = data => + request.post({ url: '/visualizationSubject/update', data }) + +export const deleteSubject = id => request.post({ url: '/visualizationSubject/delete/' + id }) + +export const dvNameCheck = async data => request.post({ url: '/dataVisualization/nameCheck', data }) + +export const storeApi = (data): Promise => { + return request.post({ url: '/store/execute', data }) +} + +export const storeStatusApi = (id: string): Promise => { + return request.get({ url: `/store/favorited/${id}` }) +} + +export const decompression = async data => + request.post({ url: '/dataVisualization/decompression', data, loading: true }) + +export const viewDetailList = dvId => { + return request.get({ + url: '/dataVisualization/viewDetailList/' + dvId, + method: 'get', + loading: false + }) +} + +export const getComponentInfo = dvId => { + return request.get({ + url: '/panel/view/getComponentInfo/' + dvId, + loading: false + }) +} + +export const export2AppCheck = params => { + return request.post({ + url: '/dataVisualization/export2AppCheck', + data: params, + loading: true + }) +} + +export const queryOuterParamsDsInfo = async dvId => { + return request.get({ + url: '/outerParams/queryDsWithVisualizationId/' + dvId, + method: 'get', + loading: false + }) +} + +export const queryShareBaseApi = () => { + return request.get({ + url: '/sysParameter/shareBase', + loading: false + }) +} diff --git a/frontend/src/api/data-visualization/visualization/linkJump.ts b/frontend/src/api/data-visualization/visualization/linkJump.ts new file mode 100644 index 0000000..615401f --- /dev/null +++ b/frontend/src/api/data-visualization/visualization/linkJump.ts @@ -0,0 +1,57 @@ +import request from '@/data-visualization/config/axios' + +export function getTableFieldWithViewId(viewId) { + return request.get({ + url: '/linkJump/getTableFieldWithViewId/' + viewId + }) +} +export function queryWithViewId(dvId, viewId) { + return request.get({ + url: '/linkJump/queryWithViewId/' + dvId + '/' + viewId + }) +} + +export function updateJumpSet(requestInfo) { + return request.post({ + url: '/linkJump/updateJumpSet', + data: requestInfo, + loading: true + }) +} +export function queryTargetVisualizationJumpInfo(requestInfo) { + return request.post({ + url: '/linkJump/queryTargetVisualizationJumpInfo', + data: requestInfo, + loading: true + }) +} + +export function queryVisualizationJumpInfo(dvId) { + return request.get({ + url: '/linkJump/queryVisualizationJumpInfo/' + dvId, + loading: false + }) +} + +export function viewTableDetailList(dvId) { + return request.get({ + url: '/linkJump/viewTableDetailList/' + dvId, + loading: false + }) +} + +export function updateJumpSetActive(requestInfo) { + return request.post({ + url: '/linkJump/updateJumpSetActive', + data: requestInfo, + loading: true + }) +} + +export function removeJumpSet(requestInfo) { + return request.post({ + url: '/linkJump/removeJumpSet', + data: requestInfo, + loading: true + }) +} diff --git a/frontend/src/api/data-visualization/visualization/linkage.ts b/frontend/src/api/data-visualization/visualization/linkage.ts new file mode 100644 index 0000000..41d50dd --- /dev/null +++ b/frontend/src/api/data-visualization/visualization/linkage.ts @@ -0,0 +1,17 @@ +import request from '@/data-visualization/config/axios' + +export const getViewLinkageGather = data => + request.post({ url: '/linkage/getViewLinkageGather', data }) + +export const getViewLinkageGatherArray = data => + request.post({ url: '/linkage/getViewLinkageGatherArray', data }) + +export const saveLinkage = data => request.post({ url: '/linkage/saveLinkage', data }) + +export const getPanelAllLinkageInfo = dvId => + request.get({ url: '/linkage/getVisualizationAllLinkageInfo/' + dvId }) + +export const updateLinkageActive = data => + request.post({ url: '/linkage/updateLinkageActive', data }) + +export const removeLinkage = data => request.post({ url: '/linkage/removeLinkage', data }) diff --git a/frontend/src/assets/img/error.png b/frontend/src/assets/img/error.png new file mode 100644 index 0000000000000000000000000000000000000000..41c5464d3d44b35075f1192514535768e2c18a3c GIT binary patch literal 3459 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 O5CHO|7renODDf|gUOR~Z literal 0 HcmV?d00001 diff --git a/frontend/src/assets/img/nothing-input.png b/frontend/src/assets/img/nothing-input.png new file mode 100644 index 0000000000000000000000000000000000000000..7b1fa548bf76deb8ac4fbce166a93047d199bb97 GIT binary patch literal 3061 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 FV1mc*^7Q}! literal 0 HcmV?d00001 diff --git a/frontend/src/assets/img/nothing-select.png b/frontend/src/assets/img/nothing-select.png new file mode 100644 index 0000000000000000000000000000000000000000..90e625123840e0147e1de4342d305d29d79c8057 GIT binary patch literal 3354 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 literal 0 HcmV?d00001 diff --git a/frontend/src/assets/img/nothing-table.png b/frontend/src/assets/img/nothing-table.png new file mode 100644 index 0000000000000000000000000000000000000000..700664ed24bce25c0a3834dc841b3d6730166005 GIT binary patch literal 2585 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 literal 0 HcmV?d00001 diff --git a/frontend/src/assets/img/nothing-tree.png b/frontend/src/assets/img/nothing-tree.png new file mode 100644 index 0000000000000000000000000000000000000000..6eb9b2ba9aa944223a1d9ff035358056f3b7ea5c GIT binary patch literal 2330 zcmV+#3FY>QP)}Km#N+35a0R7@D*_Gl}v#9yZ2a*~$

(p^E)m8hr{7; zI2;a#!{Kl^91h0<0T^)eZhR~GF(!cY5v(9|fJ@ zt*AyIAi>b;eqvtf1enjKXCb$g2U@h0$r8ode@=T_h?*EkXcgTH%@sj3T?4Nm3f{g3 zT`^gi%mU~&Oo>zSs!H9SHv?A$K^sfc&bBfB{BOC@nWKvuaYc~MjtKKS1jnDxW_|D2xykYvEtQ98ns@RYySQSqQmJ{!1QviLD2B#3*Kq?^ z1Su4Y#=)r#_aPpG3*s?6nTHgKd7DYj!AiuldC1&+rX`AnjlxZq$M9?((h50+9jKTr zS(c-UqF8q8HJXRCN={)1$AZZ6)~GJ#uFLYKudH6f^N{*+Y_b$(A|*)Tm@Wy|(&=;* zIF6v=LzH{BCImq{clz|Ht-x^vHK(rJ|L5$`(3*+!=YIn)1*sL{Mj{b7bLLk#b?O&5apET!92~4V9=3J% z^>h&-+6*zQ=!VFv$8+f{q|zBj;&`7u>k)S#> zVrEv?6ayXQ(vk|9?4sc(@Nq3VBki!Bm@tW9tC1T}{r0!+KDvh6xy+tJGqrL38cQ)y zgqdX85MW_3SMfZ)ud|~aqFo(T{S7+&r->P8HaciWK6rQJA~c9A>mdj_U@I|Zlk+e& zJ6E;Bi_hW7#sg==;Obro1}YsoI(!U~aZEqrO8LE?INe~tT>HdS5)#wNhRW^p#FRaJ zlCU&o1H`BJ)pXT0LooLs9)KJoIkeXWL`jriJr?xn<=-#M-yAyh#(U9J;R!MW#h6Xm zyOObW6h*gtd-NcdU2*apGm>cK+hY$$63-%0syC?yA4yPj;6%ScN7a6Ie~pZ6Oso(`PRW+ zQj%$7xcgTlANqWHhH5>FsUVSd^OJ#JKM^1#-i@-YLFME!HhX>V(zTJdEXWra*C zs(3ZAST8RWE62ncBl;}bVk*e0VC4j4$3{|aNMQ8-q62lUi>;g>9*uI@q zRj_hgPBJ|Y^BH!X_rAQ7!*aBu=4wZx+n?tYrh*hrvhNO3kCG(%A8X|+qTQVk35S6N zzKgPo#Y#c2{-g%zHyTKixjPgD5dsYVN?%1;OD4;t0&%he14kP$5d?D+zqOMHaHuI`1%tU`Hda%g|_|BVJPJ3`*C*2FwM)la5QXW}PAZFV{)zh=Ma? zc+G%m@e-@a(+yUW7jx9^Sfq%89^18hy8(^V3W0vWee@Iv8WCgL1USUiO`mv@ zQ53a~$Op|4&ICN_5d+6=PW#UbF%HH)aV!Sn`Yzm(DD^bIH9|>1H^I_=XIJD1EisHS zp$VY*`uEYKaYd^X^MtiSeXh3ukOcS0?(JKy0!5m-PaSRk{rG=|F!gRNFghGbZeupX z(6kNoxwOqu*N=R*d*?-_?%Q<{7~ly(N?>j1MQ?BIlZnD$LTQ$8qUnl1oMh6IB}vk; z&-d)O2#oOctu?F?PFAK%l%$hH45t6E#`pI+u?lt3bkU5u$m-z91ABIi17mzINXc}W zK`ZJ)F}~clYaCplCGG~q(sa2g2GTOOXJTQx+!h0A89`{9u4agVP!&Yii+?~9p=G+7 zB?dxOko+n*s~dYrnunF?3K@5Ys69&rNj%pqF%YVPY%~7ls1_p+6=)LWrVC3gxKj%Y znza%|QXRPT#h#ttLla?EiMx3>K1K%Ls)N*&UHzLz*X<>x7)5#fOj*d)t}N%479W26 z;d|r2VFOu` + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/frontend/src/assets/svg/403.svg b/frontend/src/assets/svg/403.svg new file mode 100644 index 0000000..96b2bad --- /dev/null +++ b/frontend/src/assets/svg/403.svg @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/frontend/src/assets/svg/API-ds.svg b/frontend/src/assets/svg/API-ds.svg new file mode 100644 index 0000000..799ecaa --- /dev/null +++ b/frontend/src/assets/svg/API-ds.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/frontend/src/assets/svg/Apache Hive.svg b/frontend/src/assets/svg/Apache Hive.svg new file mode 100644 index 0000000..f0e0d8d --- /dev/null +++ b/frontend/src/assets/svg/Apache Hive.svg @@ -0,0 +1,38 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/frontend/src/assets/svg/Checkbox.svg b/frontend/src/assets/svg/Checkbox.svg new file mode 100644 index 0000000..0645e22 --- /dev/null +++ b/frontend/src/assets/svg/Checkbox.svg @@ -0,0 +1,4 @@ + + + + diff --git a/frontend/src/assets/svg/DM.svg b/frontend/src/assets/svg/DM.svg new file mode 100644 index 0000000..1d74425 --- /dev/null +++ b/frontend/src/assets/svg/DM.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/frontend/src/assets/svg/DataEase.svg b/frontend/src/assets/svg/DataEase.svg new file mode 100644 index 0000000..aa2b44b --- /dev/null +++ b/frontend/src/assets/svg/DataEase.svg @@ -0,0 +1,17 @@ + + + + Layer 1 + + + + + + + + + + + GIS-BI开发平台 + + diff --git a/frontend/src/assets/svg/DataEase1.svg b/frontend/src/assets/svg/DataEase1.svg new file mode 100644 index 0000000..3fe02e0 --- /dev/null +++ b/frontend/src/assets/svg/DataEase1.svg @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + diff --git a/frontend/src/assets/svg/Elasticsearch.svg b/frontend/src/assets/svg/Elasticsearch.svg new file mode 100644 index 0000000..3cec9c9 --- /dev/null +++ b/frontend/src/assets/svg/Elasticsearch.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/frontend/src/assets/svg/Excel-ds.svg b/frontend/src/assets/svg/Excel-ds.svg new file mode 100644 index 0000000..dc9c761 --- /dev/null +++ b/frontend/src/assets/svg/Excel-ds.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/Frame.svg b/frontend/src/assets/svg/Frame.svg new file mode 100644 index 0000000..4f4ae04 --- /dev/null +++ b/frontend/src/assets/svg/Frame.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/frontend/src/assets/svg/KingBase.svg b/frontend/src/assets/svg/KingBase.svg new file mode 100644 index 0000000..e69e04e --- /dev/null +++ b/frontend/src/assets/svg/KingBase.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/frontend/src/assets/svg/Kylin.svg b/frontend/src/assets/svg/Kylin.svg new file mode 100644 index 0000000..33f0b66 --- /dev/null +++ b/frontend/src/assets/svg/Kylin.svg @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/frontend/src/assets/svg/Maxcompute.svg b/frontend/src/assets/svg/Maxcompute.svg new file mode 100644 index 0000000..54a3935 --- /dev/null +++ b/frontend/src/assets/svg/Maxcompute.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/frontend/src/assets/svg/PDF.svg b/frontend/src/assets/svg/PDF.svg new file mode 100644 index 0000000..f04b7a2 --- /dev/null +++ b/frontend/src/assets/svg/PDF.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/src/assets/svg/Presto.svg b/frontend/src/assets/svg/Presto.svg new file mode 100644 index 0000000..6b2fe09 --- /dev/null +++ b/frontend/src/assets/svg/Presto.svg @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/frontend/src/assets/svg/StarRocks-ds.svg b/frontend/src/assets/svg/StarRocks-ds.svg new file mode 100644 index 0000000..5b52c1a --- /dev/null +++ b/frontend/src/assets/svg/StarRocks-ds.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/frontend/src/assets/svg/TiDB-ds.svg b/frontend/src/assets/svg/TiDB-ds.svg new file mode 100644 index 0000000..29dd41f --- /dev/null +++ b/frontend/src/assets/svg/TiDB-ds.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/frontend/src/assets/svg/active-btn_copilot.svg b/frontend/src/assets/svg/active-btn_copilot.svg new file mode 100644 index 0000000..4cc82f4 --- /dev/null +++ b/frontend/src/assets/svg/active-btn_copilot.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/frontend/src/assets/svg/add.svg b/frontend/src/assets/svg/add.svg new file mode 100644 index 0000000..3ffd8d4 --- /dev/null +++ b/frontend/src/assets/svg/add.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/src/assets/svg/add_white.svg b/frontend/src/assets/svg/add_white.svg new file mode 100644 index 0000000..4179e8d --- /dev/null +++ b/frontend/src/assets/svg/add_white.svg @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/frontend/src/assets/svg/adds.svg b/frontend/src/assets/svg/adds.svg new file mode 100644 index 0000000..8c0b9ab --- /dev/null +++ b/frontend/src/assets/svg/adds.svg @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/frontend/src/assets/svg/all-msg.svg b/frontend/src/assets/svg/all-msg.svg new file mode 100644 index 0000000..320a433 --- /dev/null +++ b/frontend/src/assets/svg/all-msg.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/appearance.svg b/frontend/src/assets/svg/appearance.svg new file mode 100644 index 0000000..9e5e052 --- /dev/null +++ b/frontend/src/assets/svg/appearance.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/area-dark.svg b/frontend/src/assets/svg/area-dark.svg new file mode 100644 index 0000000..e11e43a --- /dev/null +++ b/frontend/src/assets/svg/area-dark.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/frontend/src/assets/svg/area-origin.svg b/frontend/src/assets/svg/area-origin.svg new file mode 100644 index 0000000..23d0636 --- /dev/null +++ b/frontend/src/assets/svg/area-origin.svg @@ -0,0 +1,4 @@ + + + + diff --git a/frontend/src/assets/svg/area-stack-dark.svg b/frontend/src/assets/svg/area-stack-dark.svg new file mode 100644 index 0000000..5db66fd --- /dev/null +++ b/frontend/src/assets/svg/area-stack-dark.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/frontend/src/assets/svg/area-stack-origin.svg b/frontend/src/assets/svg/area-stack-origin.svg new file mode 100644 index 0000000..23d0636 --- /dev/null +++ b/frontend/src/assets/svg/area-stack-origin.svg @@ -0,0 +1,4 @@ + + + + diff --git a/frontend/src/assets/svg/area-stack.svg b/frontend/src/assets/svg/area-stack.svg new file mode 100644 index 0000000..ca9c9f9 --- /dev/null +++ b/frontend/src/assets/svg/area-stack.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/frontend/src/assets/svg/area.svg b/frontend/src/assets/svg/area.svg new file mode 100644 index 0000000..10275d9 --- /dev/null +++ b/frontend/src/assets/svg/area.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/frontend/src/assets/svg/association.svg b/frontend/src/assets/svg/association.svg new file mode 100644 index 0000000..5d8243d --- /dev/null +++ b/frontend/src/assets/svg/association.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/frontend/src/assets/svg/auth.svg b/frontend/src/assets/svg/auth.svg new file mode 100644 index 0000000..162b25f --- /dev/null +++ b/frontend/src/assets/svg/auth.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/authentication.svg b/frontend/src/assets/svg/authentication.svg new file mode 100644 index 0000000..f5268c8 --- /dev/null +++ b/frontend/src/assets/svg/authentication.svg @@ -0,0 +1,4 @@ + + + + diff --git a/frontend/src/assets/svg/bar-dark.svg b/frontend/src/assets/svg/bar-dark.svg new file mode 100644 index 0000000..0cd6aac --- /dev/null +++ b/frontend/src/assets/svg/bar-dark.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/frontend/src/assets/svg/bar-group-dark.svg b/frontend/src/assets/svg/bar-group-dark.svg new file mode 100644 index 0000000..1ab3629 --- /dev/null +++ b/frontend/src/assets/svg/bar-group-dark.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/frontend/src/assets/svg/bar-group-origin.svg b/frontend/src/assets/svg/bar-group-origin.svg new file mode 100644 index 0000000..21e1af0 --- /dev/null +++ b/frontend/src/assets/svg/bar-group-origin.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/bar-group-stack-dark.svg b/frontend/src/assets/svg/bar-group-stack-dark.svg new file mode 100644 index 0000000..313c473 --- /dev/null +++ b/frontend/src/assets/svg/bar-group-stack-dark.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/frontend/src/assets/svg/bar-group-stack-origin.svg b/frontend/src/assets/svg/bar-group-stack-origin.svg new file mode 100644 index 0000000..21e1af0 --- /dev/null +++ b/frontend/src/assets/svg/bar-group-stack-origin.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/bar-group-stack.svg b/frontend/src/assets/svg/bar-group-stack.svg new file mode 100644 index 0000000..0e98db5 --- /dev/null +++ b/frontend/src/assets/svg/bar-group-stack.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/frontend/src/assets/svg/bar-group.svg b/frontend/src/assets/svg/bar-group.svg new file mode 100644 index 0000000..11bf7b6 --- /dev/null +++ b/frontend/src/assets/svg/bar-group.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/frontend/src/assets/svg/bar-horizontal-dark.svg b/frontend/src/assets/svg/bar-horizontal-dark.svg new file mode 100644 index 0000000..cab5303 --- /dev/null +++ b/frontend/src/assets/svg/bar-horizontal-dark.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/frontend/src/assets/svg/bar-horizontal-origin.svg b/frontend/src/assets/svg/bar-horizontal-origin.svg new file mode 100644 index 0000000..e8af2b9 --- /dev/null +++ b/frontend/src/assets/svg/bar-horizontal-origin.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/bar-horizontal.svg b/frontend/src/assets/svg/bar-horizontal.svg new file mode 100644 index 0000000..56192e8 --- /dev/null +++ b/frontend/src/assets/svg/bar-horizontal.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/frontend/src/assets/svg/bar-origin.svg b/frontend/src/assets/svg/bar-origin.svg new file mode 100644 index 0000000..21e1af0 --- /dev/null +++ b/frontend/src/assets/svg/bar-origin.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/bar-range-dark.svg b/frontend/src/assets/svg/bar-range-dark.svg new file mode 100644 index 0000000..484d1e1 --- /dev/null +++ b/frontend/src/assets/svg/bar-range-dark.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/frontend/src/assets/svg/bar-range-origin.svg b/frontend/src/assets/svg/bar-range-origin.svg new file mode 100644 index 0000000..26ef1d7 --- /dev/null +++ b/frontend/src/assets/svg/bar-range-origin.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/frontend/src/assets/svg/bar-range.svg b/frontend/src/assets/svg/bar-range.svg new file mode 100644 index 0000000..2f3e88e --- /dev/null +++ b/frontend/src/assets/svg/bar-range.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/frontend/src/assets/svg/bar-stack-dark.svg b/frontend/src/assets/svg/bar-stack-dark.svg new file mode 100644 index 0000000..a19cd7d --- /dev/null +++ b/frontend/src/assets/svg/bar-stack-dark.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/frontend/src/assets/svg/bar-stack-horizontal-dark.svg b/frontend/src/assets/svg/bar-stack-horizontal-dark.svg new file mode 100644 index 0000000..ea9c4da --- /dev/null +++ b/frontend/src/assets/svg/bar-stack-horizontal-dark.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/frontend/src/assets/svg/bar-stack-horizontal-origin.svg b/frontend/src/assets/svg/bar-stack-horizontal-origin.svg new file mode 100644 index 0000000..e8af2b9 --- /dev/null +++ b/frontend/src/assets/svg/bar-stack-horizontal-origin.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/bar-stack-horizontal.svg b/frontend/src/assets/svg/bar-stack-horizontal.svg new file mode 100644 index 0000000..e25d185 --- /dev/null +++ b/frontend/src/assets/svg/bar-stack-horizontal.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/frontend/src/assets/svg/bar-stack-origin.svg b/frontend/src/assets/svg/bar-stack-origin.svg new file mode 100644 index 0000000..21e1af0 --- /dev/null +++ b/frontend/src/assets/svg/bar-stack-origin.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/bar-stack.svg b/frontend/src/assets/svg/bar-stack.svg new file mode 100644 index 0000000..b1700a3 --- /dev/null +++ b/frontend/src/assets/svg/bar-stack.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/frontend/src/assets/svg/bar.svg b/frontend/src/assets/svg/bar.svg new file mode 100644 index 0000000..218592b --- /dev/null +++ b/frontend/src/assets/svg/bar.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/frontend/src/assets/svg/bidirectional-bar-dark.svg b/frontend/src/assets/svg/bidirectional-bar-dark.svg new file mode 100644 index 0000000..f95fe09 --- /dev/null +++ b/frontend/src/assets/svg/bidirectional-bar-dark.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/frontend/src/assets/svg/bidirectional-bar-origin.svg b/frontend/src/assets/svg/bidirectional-bar-origin.svg new file mode 100644 index 0000000..122c82e --- /dev/null +++ b/frontend/src/assets/svg/bidirectional-bar-origin.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/frontend/src/assets/svg/bidirectional-bar.svg b/frontend/src/assets/svg/bidirectional-bar.svg new file mode 100644 index 0000000..31f5b63 --- /dev/null +++ b/frontend/src/assets/svg/bidirectional-bar.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/frontend/src/assets/svg/board_1.svg b/frontend/src/assets/svg/board_1.svg new file mode 100644 index 0000000..aa87694 --- /dev/null +++ b/frontend/src/assets/svg/board_1.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/frontend/src/assets/svg/board_2.svg b/frontend/src/assets/svg/board_2.svg new file mode 100644 index 0000000..53b5b2d --- /dev/null +++ b/frontend/src/assets/svg/board_2.svg @@ -0,0 +1 @@ + diff --git a/frontend/src/assets/svg/board_3.svg b/frontend/src/assets/svg/board_3.svg new file mode 100644 index 0000000..17b9237 --- /dev/null +++ b/frontend/src/assets/svg/board_3.svg @@ -0,0 +1,2 @@ + + diff --git a/frontend/src/assets/svg/board_4.svg b/frontend/src/assets/svg/board_4.svg new file mode 100644 index 0000000..d3bcad9 --- /dev/null +++ b/frontend/src/assets/svg/board_4.svg @@ -0,0 +1,2 @@ + + diff --git a/frontend/src/assets/svg/board_5.svg b/frontend/src/assets/svg/board_5.svg new file mode 100644 index 0000000..1cba354 --- /dev/null +++ b/frontend/src/assets/svg/board_5.svg @@ -0,0 +1,2 @@ + + diff --git a/frontend/src/assets/svg/board_6.svg b/frontend/src/assets/svg/board_6.svg new file mode 100644 index 0000000..9ef2983 --- /dev/null +++ b/frontend/src/assets/svg/board_6.svg @@ -0,0 +1,2 @@ + + diff --git a/frontend/src/assets/svg/board_7.svg b/frontend/src/assets/svg/board_7.svg new file mode 100644 index 0000000..376cbf9 --- /dev/null +++ b/frontend/src/assets/svg/board_7.svg @@ -0,0 +1,2 @@ + + diff --git a/frontend/src/assets/svg/board_8.svg b/frontend/src/assets/svg/board_8.svg new file mode 100644 index 0000000..5b0c850 --- /dev/null +++ b/frontend/src/assets/svg/board_8.svg @@ -0,0 +1,2 @@ + + diff --git a/frontend/src/assets/svg/board_9.svg b/frontend/src/assets/svg/board_9.svg new file mode 100644 index 0000000..ba50537 --- /dev/null +++ b/frontend/src/assets/svg/board_9.svg @@ -0,0 +1,2 @@ + + diff --git a/frontend/src/assets/svg/btn_copilot.svg b/frontend/src/assets/svg/btn_copilot.svg new file mode 100644 index 0000000..56b3df8 --- /dev/null +++ b/frontend/src/assets/svg/btn_copilot.svg @@ -0,0 +1,4 @@ + + + + diff --git a/frontend/src/assets/svg/btn_oidc.svg b/frontend/src/assets/svg/btn_oidc.svg new file mode 100644 index 0000000..8d02149 --- /dev/null +++ b/frontend/src/assets/svg/btn_oidc.svg @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + diff --git a/frontend/src/assets/svg/bubble-map-dark.svg b/frontend/src/assets/svg/bubble-map-dark.svg new file mode 100644 index 0000000..18e8ad1 --- /dev/null +++ b/frontend/src/assets/svg/bubble-map-dark.svg @@ -0,0 +1 @@ + diff --git a/frontend/src/assets/svg/bubble-map-origin.svg b/frontend/src/assets/svg/bubble-map-origin.svg new file mode 100644 index 0000000..e400ccb --- /dev/null +++ b/frontend/src/assets/svg/bubble-map-origin.svg @@ -0,0 +1 @@ + diff --git a/frontend/src/assets/svg/bubble-map.svg b/frontend/src/assets/svg/bubble-map.svg new file mode 100644 index 0000000..beaff8c --- /dev/null +++ b/frontend/src/assets/svg/bubble-map.svg @@ -0,0 +1 @@ + diff --git a/frontend/src/assets/svg/button_right.svg b/frontend/src/assets/svg/button_right.svg new file mode 100644 index 0000000..7972225 --- /dev/null +++ b/frontend/src/assets/svg/button_right.svg @@ -0,0 +1,2 @@ + \ No newline at end of file diff --git a/frontend/src/assets/svg/calculate.svg b/frontend/src/assets/svg/calculate.svg new file mode 100644 index 0000000..600832e --- /dev/null +++ b/frontend/src/assets/svg/calculate.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/src/assets/svg/cancel_release.svg b/frontend/src/assets/svg/cancel_release.svg new file mode 100644 index 0000000..30c5911 --- /dev/null +++ b/frontend/src/assets/svg/cancel_release.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/src/assets/svg/chart-download.svg b/frontend/src/assets/svg/chart-download.svg new file mode 100644 index 0000000..75e7cb8 --- /dev/null +++ b/frontend/src/assets/svg/chart-download.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/chart-mix-dark.svg b/frontend/src/assets/svg/chart-mix-dark.svg new file mode 100644 index 0000000..88e0a54 --- /dev/null +++ b/frontend/src/assets/svg/chart-mix-dark.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/frontend/src/assets/svg/chart-mix-dual-line-dark.svg b/frontend/src/assets/svg/chart-mix-dual-line-dark.svg new file mode 100644 index 0000000..c3819a1 --- /dev/null +++ b/frontend/src/assets/svg/chart-mix-dual-line-dark.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/frontend/src/assets/svg/chart-mix-dual-line-origin.svg b/frontend/src/assets/svg/chart-mix-dual-line-origin.svg new file mode 100644 index 0000000..43f590b --- /dev/null +++ b/frontend/src/assets/svg/chart-mix-dual-line-origin.svg @@ -0,0 +1,4 @@ + + + + diff --git a/frontend/src/assets/svg/chart-mix-dual-line.svg b/frontend/src/assets/svg/chart-mix-dual-line.svg new file mode 100644 index 0000000..f2b52d5 --- /dev/null +++ b/frontend/src/assets/svg/chart-mix-dual-line.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/frontend/src/assets/svg/chart-mix-group-dark.svg b/frontend/src/assets/svg/chart-mix-group-dark.svg new file mode 100644 index 0000000..a921991 --- /dev/null +++ b/frontend/src/assets/svg/chart-mix-group-dark.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/frontend/src/assets/svg/chart-mix-group-origin.svg b/frontend/src/assets/svg/chart-mix-group-origin.svg new file mode 100644 index 0000000..a833627 --- /dev/null +++ b/frontend/src/assets/svg/chart-mix-group-origin.svg @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/frontend/src/assets/svg/chart-mix-group.svg b/frontend/src/assets/svg/chart-mix-group.svg new file mode 100644 index 0000000..bd4a096 --- /dev/null +++ b/frontend/src/assets/svg/chart-mix-group.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/frontend/src/assets/svg/chart-mix-origin.svg b/frontend/src/assets/svg/chart-mix-origin.svg new file mode 100644 index 0000000..f4ed2f0 --- /dev/null +++ b/frontend/src/assets/svg/chart-mix-origin.svg @@ -0,0 +1,4 @@ + + + + diff --git a/frontend/src/assets/svg/chart-mix-stack-dark.svg b/frontend/src/assets/svg/chart-mix-stack-dark.svg new file mode 100644 index 0000000..b4edc0e --- /dev/null +++ b/frontend/src/assets/svg/chart-mix-stack-dark.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/frontend/src/assets/svg/chart-mix-stack-origin.svg b/frontend/src/assets/svg/chart-mix-stack-origin.svg new file mode 100644 index 0000000..1800cfc --- /dev/null +++ b/frontend/src/assets/svg/chart-mix-stack-origin.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/frontend/src/assets/svg/chart-mix-stack.svg b/frontend/src/assets/svg/chart-mix-stack.svg new file mode 100644 index 0000000..4fd947c --- /dev/null +++ b/frontend/src/assets/svg/chart-mix-stack.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/frontend/src/assets/svg/chart-mix.svg b/frontend/src/assets/svg/chart-mix.svg new file mode 100644 index 0000000..60e8e1a --- /dev/null +++ b/frontend/src/assets/svg/chart-mix.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/frontend/src/assets/svg/chart-table.svg b/frontend/src/assets/svg/chart-table.svg new file mode 100644 index 0000000..5d8d412 --- /dev/null +++ b/frontend/src/assets/svg/chart-table.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/circle-packing-dark.svg b/frontend/src/assets/svg/circle-packing-dark.svg new file mode 100644 index 0000000..0e66315 --- /dev/null +++ b/frontend/src/assets/svg/circle-packing-dark.svg @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + diff --git a/frontend/src/assets/svg/circle-packing-origin.svg b/frontend/src/assets/svg/circle-packing-origin.svg new file mode 100644 index 0000000..f71ca31 --- /dev/null +++ b/frontend/src/assets/svg/circle-packing-origin.svg @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/frontend/src/assets/svg/circle-packing.svg b/frontend/src/assets/svg/circle-packing.svg new file mode 100644 index 0000000..73380f1 --- /dev/null +++ b/frontend/src/assets/svg/circle-packing.svg @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/frontend/src/assets/svg/ck-ds.svg b/frontend/src/assets/svg/ck-ds.svg new file mode 100644 index 0000000..0e843c9 --- /dev/null +++ b/frontend/src/assets/svg/ck-ds.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/frontend/src/assets/svg/clock.svg b/frontend/src/assets/svg/clock.svg new file mode 100644 index 0000000..543c400 --- /dev/null +++ b/frontend/src/assets/svg/clock.svg @@ -0,0 +1,4 @@ + + + + diff --git a/frontend/src/assets/svg/combinationpage.svg b/frontend/src/assets/svg/combinationpage.svg new file mode 100644 index 0000000..035f735 --- /dev/null +++ b/frontend/src/assets/svg/combinationpage.svg @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/frontend/src/assets/svg/copilot.svg b/frontend/src/assets/svg/copilot.svg new file mode 100644 index 0000000..9752905 --- /dev/null +++ b/frontend/src/assets/svg/copilot.svg @@ -0,0 +1,92 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/frontend/src/assets/svg/custom_sort.svg b/frontend/src/assets/svg/custom_sort.svg new file mode 100644 index 0000000..5e18dde --- /dev/null +++ b/frontend/src/assets/svg/custom_sort.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/frontend/src/assets/svg/dark_1.svg b/frontend/src/assets/svg/dark_1.svg new file mode 100644 index 0000000..be47b1a --- /dev/null +++ b/frontend/src/assets/svg/dark_1.svg @@ -0,0 +1,2 @@ + diff --git a/frontend/src/assets/svg/dashboard.svg b/frontend/src/assets/svg/dashboard.svg new file mode 100644 index 0000000..4153757 --- /dev/null +++ b/frontend/src/assets/svg/dashboard.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/src/assets/svg/data-reference.svg b/frontend/src/assets/svg/data-reference.svg new file mode 100644 index 0000000..b294b7c --- /dev/null +++ b/frontend/src/assets/svg/data-reference.svg @@ -0,0 +1,4 @@ + + + + diff --git a/frontend/src/assets/svg/database.svg b/frontend/src/assets/svg/database.svg new file mode 100644 index 0000000..30bcf30 --- /dev/null +++ b/frontend/src/assets/svg/database.svg @@ -0,0 +1 @@ + diff --git a/frontend/src/assets/svg/dataset-outline.svg b/frontend/src/assets/svg/dataset-outline.svg new file mode 100644 index 0000000..ed872dd --- /dev/null +++ b/frontend/src/assets/svg/dataset-outline.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/dataset-task.svg b/frontend/src/assets/svg/dataset-task.svg new file mode 100644 index 0000000..65f3ed4 --- /dev/null +++ b/frontend/src/assets/svg/dataset-task.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/src/assets/svg/dataset_params.svg b/frontend/src/assets/svg/dataset_params.svg new file mode 100644 index 0000000..9175e1c --- /dev/null +++ b/frontend/src/assets/svg/dataset_params.svg @@ -0,0 +1,4 @@ + + + + diff --git a/frontend/src/assets/svg/datasource.svg b/frontend/src/assets/svg/datasource.svg new file mode 100644 index 0000000..71af710 --- /dev/null +++ b/frontend/src/assets/svg/datasource.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/src/assets/svg/datasoure_add_dataset.svg b/frontend/src/assets/svg/datasoure_add_dataset.svg new file mode 100644 index 0000000..4ddd6c2 --- /dev/null +++ b/frontend/src/assets/svg/datasoure_add_dataset.svg @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/frontend/src/assets/svg/datasoure_details.svg b/frontend/src/assets/svg/datasoure_details.svg new file mode 100644 index 0000000..e1fd198 --- /dev/null +++ b/frontend/src/assets/svg/datasoure_details.svg @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/frontend/src/assets/svg/db-de.svg b/frontend/src/assets/svg/db-de.svg new file mode 100644 index 0000000..ee44820 --- /dev/null +++ b/frontend/src/assets/svg/db-de.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/db-more-web.svg b/frontend/src/assets/svg/db-more-web.svg new file mode 100644 index 0000000..9bc701c --- /dev/null +++ b/frontend/src/assets/svg/db-more-web.svg @@ -0,0 +1 @@ + diff --git a/frontend/src/assets/svg/db2-ds.svg b/frontend/src/assets/svg/db2-ds.svg new file mode 100644 index 0000000..35810ee --- /dev/null +++ b/frontend/src/assets/svg/db2-ds.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/de-api-new.svg b/frontend/src/assets/svg/de-api-new.svg new file mode 100644 index 0000000..3d73385 --- /dev/null +++ b/frontend/src/assets/svg/de-api-new.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/frontend/src/assets/svg/de-copy.svg b/frontend/src/assets/svg/de-copy.svg new file mode 100644 index 0000000..e885735 --- /dev/null +++ b/frontend/src/assets/svg/de-copy.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/de-db-new.svg b/frontend/src/assets/svg/de-db-new.svg new file mode 100644 index 0000000..07ffb0f --- /dev/null +++ b/frontend/src/assets/svg/de-db-new.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/de-delete.svg b/frontend/src/assets/svg/de-delete.svg new file mode 100644 index 0000000..2c122f8 --- /dev/null +++ b/frontend/src/assets/svg/de-delete.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/de-ds-error.svg b/frontend/src/assets/svg/de-ds-error.svg new file mode 100644 index 0000000..581a013 --- /dev/null +++ b/frontend/src/assets/svg/de-ds-error.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/frontend/src/assets/svg/de-ds-move.svg b/frontend/src/assets/svg/de-ds-move.svg new file mode 100644 index 0000000..5f256f8 --- /dev/null +++ b/frontend/src/assets/svg/de-ds-move.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/de-ds-rename.svg b/frontend/src/assets/svg/de-ds-rename.svg new file mode 100644 index 0000000..b3b369e --- /dev/null +++ b/frontend/src/assets/svg/de-ds-rename.svg @@ -0,0 +1,4 @@ + + + + diff --git a/frontend/src/assets/svg/de-ds-trash.svg b/frontend/src/assets/svg/de-ds-trash.svg new file mode 100644 index 0000000..fd8f126 --- /dev/null +++ b/frontend/src/assets/svg/de-ds-trash.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/de-ds-warning.svg b/frontend/src/assets/svg/de-ds-warning.svg new file mode 100644 index 0000000..2f7ac5a --- /dev/null +++ b/frontend/src/assets/svg/de-ds-warning.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/frontend/src/assets/svg/de-excel-new.svg b/frontend/src/assets/svg/de-excel-new.svg new file mode 100644 index 0000000..5a9d85a --- /dev/null +++ b/frontend/src/assets/svg/de-excel-new.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/de-json.svg b/frontend/src/assets/svg/de-json.svg new file mode 100644 index 0000000..9e62a6c --- /dev/null +++ b/frontend/src/assets/svg/de-json.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/src/assets/svg/de-move.svg b/frontend/src/assets/svg/de-move.svg new file mode 100644 index 0000000..ffa1904 --- /dev/null +++ b/frontend/src/assets/svg/de-move.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/de-search.svg b/frontend/src/assets/svg/de-search.svg new file mode 100644 index 0000000..0986c29 --- /dev/null +++ b/frontend/src/assets/svg/de-search.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/de-sql-new.svg b/frontend/src/assets/svg/de-sql-new.svg new file mode 100644 index 0000000..cf83467 --- /dev/null +++ b/frontend/src/assets/svg/de-sql-new.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/frontend/src/assets/svg/de-union-new.svg b/frontend/src/assets/svg/de-union-new.svg new file mode 100644 index 0000000..2a04a4b --- /dev/null +++ b/frontend/src/assets/svg/de-union-new.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/de_pwd_invisible.svg b/frontend/src/assets/svg/de_pwd_invisible.svg new file mode 100644 index 0000000..6342b71 --- /dev/null +++ b/frontend/src/assets/svg/de_pwd_invisible.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/de_pwd_visible.svg b/frontend/src/assets/svg/de_pwd_visible.svg new file mode 100644 index 0000000..9b21969 --- /dev/null +++ b/frontend/src/assets/svg/de_pwd_visible.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/default_avatar.svg b/frontend/src/assets/svg/default_avatar.svg new file mode 100644 index 0000000..25c4de5 --- /dev/null +++ b/frontend/src/assets/svg/default_avatar.svg @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + + diff --git a/frontend/src/assets/svg/delete.svg b/frontend/src/assets/svg/delete.svg new file mode 100644 index 0000000..a0456c6 --- /dev/null +++ b/frontend/src/assets/svg/delete.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/src/assets/svg/display-setting.svg b/frontend/src/assets/svg/display-setting.svg new file mode 100644 index 0000000..3f59054 --- /dev/null +++ b/frontend/src/assets/svg/display-setting.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/src/assets/svg/doc.svg b/frontend/src/assets/svg/doc.svg new file mode 100644 index 0000000..c34965c --- /dev/null +++ b/frontend/src/assets/svg/doc.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/src/assets/svg/docs.svg b/frontend/src/assets/svg/docs.svg new file mode 100644 index 0000000..f699a59 --- /dev/null +++ b/frontend/src/assets/svg/docs.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/src/assets/svg/doris-ds.svg b/frontend/src/assets/svg/doris-ds.svg new file mode 100644 index 0000000..6d12f37 --- /dev/null +++ b/frontend/src/assets/svg/doris-ds.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/frontend/src/assets/svg/drag.svg b/frontend/src/assets/svg/drag.svg new file mode 100644 index 0000000..cf76a2e --- /dev/null +++ b/frontend/src/assets/svg/drag.svg @@ -0,0 +1 @@ + diff --git a/frontend/src/assets/svg/driver-de.svg b/frontend/src/assets/svg/driver-de.svg new file mode 100644 index 0000000..e83b507 --- /dev/null +++ b/frontend/src/assets/svg/driver-de.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/frontend/src/assets/svg/ds-api.svg b/frontend/src/assets/svg/ds-api.svg new file mode 100644 index 0000000..479f848 --- /dev/null +++ b/frontend/src/assets/svg/ds-api.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/frontend/src/assets/svg/ds-custom.svg b/frontend/src/assets/svg/ds-custom.svg new file mode 100644 index 0000000..fa99b94 --- /dev/null +++ b/frontend/src/assets/svg/ds-custom.svg @@ -0,0 +1 @@ + diff --git a/frontend/src/assets/svg/ds-db.svg b/frontend/src/assets/svg/ds-db.svg new file mode 100644 index 0000000..8b96d0d --- /dev/null +++ b/frontend/src/assets/svg/ds-db.svg @@ -0,0 +1,4 @@ + + + + diff --git a/frontend/src/assets/svg/ds-excel.svg b/frontend/src/assets/svg/ds-excel.svg new file mode 100644 index 0000000..5bf5ed7 --- /dev/null +++ b/frontend/src/assets/svg/ds-excel.svg @@ -0,0 +1,4 @@ + + + + diff --git a/frontend/src/assets/svg/ds-sql.svg b/frontend/src/assets/svg/ds-sql.svg new file mode 100644 index 0000000..10c7673 --- /dev/null +++ b/frontend/src/assets/svg/ds-sql.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/frontend/src/assets/svg/ds-union.svg b/frontend/src/assets/svg/ds-union.svg new file mode 100644 index 0000000..5428e82 --- /dev/null +++ b/frontend/src/assets/svg/ds-union.svg @@ -0,0 +1,4 @@ + + + + diff --git a/frontend/src/assets/svg/dv-ai-window-max.svg b/frontend/src/assets/svg/dv-ai-window-max.svg new file mode 100644 index 0000000..65f2115 --- /dev/null +++ b/frontend/src/assets/svg/dv-ai-window-max.svg @@ -0,0 +1 @@ + diff --git a/frontend/src/assets/svg/dv-ai-window-min.svg b/frontend/src/assets/svg/dv-ai-window-min.svg new file mode 100644 index 0000000..58794a4 --- /dev/null +++ b/frontend/src/assets/svg/dv-ai-window-min.svg @@ -0,0 +1 @@ + diff --git a/frontend/src/assets/svg/dv-ai.svg b/frontend/src/assets/svg/dv-ai.svg new file mode 100644 index 0000000..7927339 --- /dev/null +++ b/frontend/src/assets/svg/dv-ai.svg @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + diff --git a/frontend/src/assets/svg/dv-bar-enlarge.svg b/frontend/src/assets/svg/dv-bar-enlarge.svg new file mode 100644 index 0000000..1926160 --- /dev/null +++ b/frontend/src/assets/svg/dv-bar-enlarge.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/src/assets/svg/dv-bar-unLinkage.svg b/frontend/src/assets/svg/dv-bar-unLinkage.svg new file mode 100644 index 0000000..e66f5a5 --- /dev/null +++ b/frontend/src/assets/svg/dv-bar-unLinkage.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/src/assets/svg/dv-batch.svg b/frontend/src/assets/svg/dv-batch.svg new file mode 100644 index 0000000..c5429c8 --- /dev/null +++ b/frontend/src/assets/svg/dv-batch.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/dv-batch_white.svg b/frontend/src/assets/svg/dv-batch_white.svg new file mode 100644 index 0000000..bac2bf8 --- /dev/null +++ b/frontend/src/assets/svg/dv-batch_white.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/dv-copy-dark.svg b/frontend/src/assets/svg/dv-copy-dark.svg new file mode 100644 index 0000000..9a1c506 --- /dev/null +++ b/frontend/src/assets/svg/dv-copy-dark.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/dv-copy.svg b/frontend/src/assets/svg/dv-copy.svg new file mode 100644 index 0000000..5d26c4f --- /dev/null +++ b/frontend/src/assets/svg/dv-copy.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/dv-dashboard-spine-mobile.svg b/frontend/src/assets/svg/dv-dashboard-spine-mobile.svg new file mode 100644 index 0000000..a7be939 --- /dev/null +++ b/frontend/src/assets/svg/dv-dashboard-spine-mobile.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/frontend/src/assets/svg/dv-dashboard-spine.svg b/frontend/src/assets/svg/dv-dashboard-spine.svg new file mode 100644 index 0000000..1da45d6 --- /dev/null +++ b/frontend/src/assets/svg/dv-dashboard-spine.svg @@ -0,0 +1,4 @@ + + + + diff --git a/frontend/src/assets/svg/dv-dashboard.svg b/frontend/src/assets/svg/dv-dashboard.svg new file mode 100644 index 0000000..999a080 --- /dev/null +++ b/frontend/src/assets/svg/dv-dashboard.svg @@ -0,0 +1,4 @@ + + + + diff --git a/frontend/src/assets/svg/dv-dashboard_white.svg b/frontend/src/assets/svg/dv-dashboard_white.svg new file mode 100644 index 0000000..03b8d2b --- /dev/null +++ b/frontend/src/assets/svg/dv-dashboard_white.svg @@ -0,0 +1,4 @@ + + + + diff --git a/frontend/src/assets/svg/dv-delete.svg b/frontend/src/assets/svg/dv-delete.svg new file mode 100644 index 0000000..79faadf --- /dev/null +++ b/frontend/src/assets/svg/dv-delete.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/dv-details.svg b/frontend/src/assets/svg/dv-details.svg new file mode 100644 index 0000000..7680bf9 --- /dev/null +++ b/frontend/src/assets/svg/dv-details.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/dv-drag-tips.svg b/frontend/src/assets/svg/dv-drag-tips.svg new file mode 100644 index 0000000..21902f0 --- /dev/null +++ b/frontend/src/assets/svg/dv-drag-tips.svg @@ -0,0 +1,123 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/frontend/src/assets/svg/dv-edit.svg b/frontend/src/assets/svg/dv-edit.svg new file mode 100644 index 0000000..f91779b --- /dev/null +++ b/frontend/src/assets/svg/dv-edit.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/dv-empty.svg b/frontend/src/assets/svg/dv-empty.svg new file mode 100644 index 0000000..88843ac --- /dev/null +++ b/frontend/src/assets/svg/dv-empty.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/frontend/src/assets/svg/dv-expand-down.svg b/frontend/src/assets/svg/dv-expand-down.svg new file mode 100644 index 0000000..e0d1dfa --- /dev/null +++ b/frontend/src/assets/svg/dv-expand-down.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/dv-expand-right.svg b/frontend/src/assets/svg/dv-expand-right.svg new file mode 100644 index 0000000..99cffc3 --- /dev/null +++ b/frontend/src/assets/svg/dv-expand-right.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/dv-eye-close.svg b/frontend/src/assets/svg/dv-eye-close.svg new file mode 100644 index 0000000..5cec700 --- /dev/null +++ b/frontend/src/assets/svg/dv-eye-close.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/dv-filter-show.svg b/frontend/src/assets/svg/dv-filter-show.svg new file mode 100644 index 0000000..438f8d1 --- /dev/null +++ b/frontend/src/assets/svg/dv-filter-show.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/dv-filter.svg b/frontend/src/assets/svg/dv-filter.svg new file mode 100644 index 0000000..d064197 --- /dev/null +++ b/frontend/src/assets/svg/dv-filter.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/dv-folder.svg b/frontend/src/assets/svg/dv-folder.svg new file mode 100644 index 0000000..57fdb02 --- /dev/null +++ b/frontend/src/assets/svg/dv-folder.svg @@ -0,0 +1,4 @@ + + + + diff --git a/frontend/src/assets/svg/dv-head-more.svg b/frontend/src/assets/svg/dv-head-more.svg new file mode 100644 index 0000000..69f69a6 --- /dev/null +++ b/frontend/src/assets/svg/dv-head-more.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/dv-hidden.svg b/frontend/src/assets/svg/dv-hidden.svg new file mode 100644 index 0000000..722ce8c --- /dev/null +++ b/frontend/src/assets/svg/dv-hidden.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/src/assets/svg/dv-info.svg b/frontend/src/assets/svg/dv-info.svg new file mode 100644 index 0000000..ba5b133 --- /dev/null +++ b/frontend/src/assets/svg/dv-info.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/frontend/src/assets/svg/dv-link-target.svg b/frontend/src/assets/svg/dv-link-target.svg new file mode 100644 index 0000000..da22305 --- /dev/null +++ b/frontend/src/assets/svg/dv-link-target.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/dv-lock.svg b/frontend/src/assets/svg/dv-lock.svg new file mode 100644 index 0000000..2610f94 --- /dev/null +++ b/frontend/src/assets/svg/dv-lock.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/dv-material.svg b/frontend/src/assets/svg/dv-material.svg new file mode 100644 index 0000000..e1cb013 --- /dev/null +++ b/frontend/src/assets/svg/dv-material.svg @@ -0,0 +1,4 @@ + + + + diff --git a/frontend/src/assets/svg/dv-max.svg b/frontend/src/assets/svg/dv-max.svg new file mode 100644 index 0000000..693745b --- /dev/null +++ b/frontend/src/assets/svg/dv-max.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/frontend/src/assets/svg/dv-media.svg b/frontend/src/assets/svg/dv-media.svg new file mode 100644 index 0000000..2bdfeb2 --- /dev/null +++ b/frontend/src/assets/svg/dv-media.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/frontend/src/assets/svg/dv-min.svg b/frontend/src/assets/svg/dv-min.svg new file mode 100644 index 0000000..6eca09e --- /dev/null +++ b/frontend/src/assets/svg/dv-min.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/dv-more-com.svg b/frontend/src/assets/svg/dv-more-com.svg new file mode 100644 index 0000000..6ef3534 --- /dev/null +++ b/frontend/src/assets/svg/dv-more-com.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/frontend/src/assets/svg/dv-more-time-clock.svg b/frontend/src/assets/svg/dv-more-time-clock.svg new file mode 100644 index 0000000..bf7ddcb --- /dev/null +++ b/frontend/src/assets/svg/dv-more-time-clock.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/src/assets/svg/dv-more.svg b/frontend/src/assets/svg/dv-more.svg new file mode 100644 index 0000000..67b3a62 --- /dev/null +++ b/frontend/src/assets/svg/dv-more.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/dv-move.svg b/frontend/src/assets/svg/dv-move.svg new file mode 100644 index 0000000..7f173c2 --- /dev/null +++ b/frontend/src/assets/svg/dv-move.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/dv-new-folder.svg b/frontend/src/assets/svg/dv-new-folder.svg new file mode 100644 index 0000000..ebe4f9a --- /dev/null +++ b/frontend/src/assets/svg/dv-new-folder.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/frontend/src/assets/svg/dv-new.svg b/frontend/src/assets/svg/dv-new.svg new file mode 100644 index 0000000..76ac290 --- /dev/null +++ b/frontend/src/assets/svg/dv-new.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/dv-no-img.svg b/frontend/src/assets/svg/dv-no-img.svg new file mode 100644 index 0000000..ea98493 --- /dev/null +++ b/frontend/src/assets/svg/dv-no-img.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/src/assets/svg/dv-nothing.svg b/frontend/src/assets/svg/dv-nothing.svg new file mode 100644 index 0000000..45830fe --- /dev/null +++ b/frontend/src/assets/svg/dv-nothing.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/frontend/src/assets/svg/dv-params.svg b/frontend/src/assets/svg/dv-params.svg new file mode 100644 index 0000000..b38d58f --- /dev/null +++ b/frontend/src/assets/svg/dv-params.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/dv-picture-real.svg b/frontend/src/assets/svg/dv-picture-real.svg new file mode 100644 index 0000000..efcf6fe --- /dev/null +++ b/frontend/src/assets/svg/dv-picture-real.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/dv-picture-show.svg b/frontend/src/assets/svg/dv-picture-show.svg new file mode 100644 index 0000000..03f5f28 --- /dev/null +++ b/frontend/src/assets/svg/dv-picture-show.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/dv-picture.svg b/frontend/src/assets/svg/dv-picture.svg new file mode 100644 index 0000000..03f5f28 --- /dev/null +++ b/frontend/src/assets/svg/dv-picture.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/dv-preview-download.svg b/frontend/src/assets/svg/dv-preview-download.svg new file mode 100644 index 0000000..cfaf8c2 --- /dev/null +++ b/frontend/src/assets/svg/dv-preview-download.svg @@ -0,0 +1,4 @@ + + + + diff --git a/frontend/src/assets/svg/dv-preview-inner.svg b/frontend/src/assets/svg/dv-preview-inner.svg new file mode 100644 index 0000000..d50a951 --- /dev/null +++ b/frontend/src/assets/svg/dv-preview-inner.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/dv-preview-outer.svg b/frontend/src/assets/svg/dv-preview-outer.svg new file mode 100644 index 0000000..58e8056 --- /dev/null +++ b/frontend/src/assets/svg/dv-preview-outer.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/dv-preview.svg b/frontend/src/assets/svg/dv-preview.svg new file mode 100644 index 0000000..bdf80b8 --- /dev/null +++ b/frontend/src/assets/svg/dv-preview.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/dv-rename.svg b/frontend/src/assets/svg/dv-rename.svg new file mode 100644 index 0000000..8547ef7 --- /dev/null +++ b/frontend/src/assets/svg/dv-rename.svg @@ -0,0 +1,4 @@ + + + + diff --git a/frontend/src/assets/svg/dv-reposition.svg b/frontend/src/assets/svg/dv-reposition.svg new file mode 100644 index 0000000..dd0c617 --- /dev/null +++ b/frontend/src/assets/svg/dv-reposition.svg @@ -0,0 +1,4 @@ + + + + diff --git a/frontend/src/assets/svg/dv-richText.svg b/frontend/src/assets/svg/dv-richText.svg new file mode 100644 index 0000000..e87faf7 --- /dev/null +++ b/frontend/src/assets/svg/dv-richText.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/dv-ruler.svg b/frontend/src/assets/svg/dv-ruler.svg new file mode 100644 index 0000000..46f262a --- /dev/null +++ b/frontend/src/assets/svg/dv-ruler.svg @@ -0,0 +1 @@ + diff --git a/frontend/src/assets/svg/dv-screen-new.svg b/frontend/src/assets/svg/dv-screen-new.svg new file mode 100644 index 0000000..a249590 --- /dev/null +++ b/frontend/src/assets/svg/dv-screen-new.svg @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/frontend/src/assets/svg/dv-screen-spine.svg b/frontend/src/assets/svg/dv-screen-spine.svg new file mode 100644 index 0000000..5da4106 --- /dev/null +++ b/frontend/src/assets/svg/dv-screen-spine.svg @@ -0,0 +1,4 @@ + + + + diff --git a/frontend/src/assets/svg/dv-scroll-text.svg b/frontend/src/assets/svg/dv-scroll-text.svg new file mode 100644 index 0000000..897afec --- /dev/null +++ b/frontend/src/assets/svg/dv-scroll-text.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/src/assets/svg/dv-share.svg b/frontend/src/assets/svg/dv-share.svg new file mode 100644 index 0000000..6f76a9b --- /dev/null +++ b/frontend/src/assets/svg/dv-share.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/dv-show.svg b/frontend/src/assets/svg/dv-show.svg new file mode 100644 index 0000000..3690059 --- /dev/null +++ b/frontend/src/assets/svg/dv-show.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/dv-sort-asc.svg b/frontend/src/assets/svg/dv-sort-asc.svg new file mode 100644 index 0000000..253a3ce --- /dev/null +++ b/frontend/src/assets/svg/dv-sort-asc.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/frontend/src/assets/svg/dv-sort-desc.svg b/frontend/src/assets/svg/dv-sort-desc.svg new file mode 100644 index 0000000..4b66661 --- /dev/null +++ b/frontend/src/assets/svg/dv-sort-desc.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/frontend/src/assets/svg/dv-style-activeFont.svg b/frontend/src/assets/svg/dv-style-activeFont.svg new file mode 100644 index 0000000..8fe1bc3 --- /dev/null +++ b/frontend/src/assets/svg/dv-style-activeFont.svg @@ -0,0 +1 @@ + diff --git a/frontend/src/assets/svg/dv-style-activeFontSize.svg b/frontend/src/assets/svg/dv-style-activeFontSize.svg new file mode 100644 index 0000000..3259b0c --- /dev/null +++ b/frontend/src/assets/svg/dv-style-activeFontSize.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/src/assets/svg/dv-style-backgroundColor.svg b/frontend/src/assets/svg/dv-style-backgroundColor.svg new file mode 100644 index 0000000..84188fe --- /dev/null +++ b/frontend/src/assets/svg/dv-style-backgroundColor.svg @@ -0,0 +1 @@ + diff --git a/frontend/src/assets/svg/dv-style-blur.svg b/frontend/src/assets/svg/dv-style-blur.svg new file mode 100644 index 0000000..7acdb45 --- /dev/null +++ b/frontend/src/assets/svg/dv-style-blur.svg @@ -0,0 +1,12 @@ + + + 模糊修复 + + + + + + + + + diff --git a/frontend/src/assets/svg/dv-style-borderColor.svg b/frontend/src/assets/svg/dv-style-borderColor.svg new file mode 100644 index 0000000..3cb03b1 --- /dev/null +++ b/frontend/src/assets/svg/dv-style-borderColor.svg @@ -0,0 +1 @@ + diff --git a/frontend/src/assets/svg/dv-style-borderRadius.svg b/frontend/src/assets/svg/dv-style-borderRadius.svg new file mode 100644 index 0000000..165add9 --- /dev/null +++ b/frontend/src/assets/svg/dv-style-borderRadius.svg @@ -0,0 +1 @@ + diff --git a/frontend/src/assets/svg/dv-style-borderSize.svg b/frontend/src/assets/svg/dv-style-borderSize.svg new file mode 100644 index 0000000..517b816 --- /dev/null +++ b/frontend/src/assets/svg/dv-style-borderSize.svg @@ -0,0 +1 @@ + diff --git a/frontend/src/assets/svg/dv-style-borderStyle.svg b/frontend/src/assets/svg/dv-style-borderStyle.svg new file mode 100644 index 0000000..58789ef --- /dev/null +++ b/frontend/src/assets/svg/dv-style-borderStyle.svg @@ -0,0 +1 @@ + diff --git a/frontend/src/assets/svg/dv-style-color.svg b/frontend/src/assets/svg/dv-style-color.svg new file mode 100644 index 0000000..99855ff --- /dev/null +++ b/frontend/src/assets/svg/dv-style-color.svg @@ -0,0 +1 @@ + diff --git a/frontend/src/assets/svg/dv-style-fontFamily.svg b/frontend/src/assets/svg/dv-style-fontFamily.svg new file mode 100644 index 0000000..4f6721e --- /dev/null +++ b/frontend/src/assets/svg/dv-style-fontFamily.svg @@ -0,0 +1 @@ + diff --git a/frontend/src/assets/svg/dv-style-fontSize.svg b/frontend/src/assets/svg/dv-style-fontSize.svg new file mode 100644 index 0000000..15adad7 --- /dev/null +++ b/frontend/src/assets/svg/dv-style-fontSize.svg @@ -0,0 +1 @@ + diff --git a/frontend/src/assets/svg/dv-style-fontWeight.svg b/frontend/src/assets/svg/dv-style-fontWeight.svg new file mode 100644 index 0000000..5bb6f78 --- /dev/null +++ b/frontend/src/assets/svg/dv-style-fontWeight.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/src/assets/svg/dv-style-headBorderActiveColor.svg b/frontend/src/assets/svg/dv-style-headBorderActiveColor.svg new file mode 100644 index 0000000..5b558eb --- /dev/null +++ b/frontend/src/assets/svg/dv-style-headBorderActiveColor.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/src/assets/svg/dv-style-headBorderColor.svg b/frontend/src/assets/svg/dv-style-headBorderColor.svg new file mode 100644 index 0000000..21e8be5 --- /dev/null +++ b/frontend/src/assets/svg/dv-style-headBorderColor.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/src/assets/svg/dv-style-headFontActiveColor.svg b/frontend/src/assets/svg/dv-style-headFontActiveColor.svg new file mode 100644 index 0000000..4c12a4e --- /dev/null +++ b/frontend/src/assets/svg/dv-style-headFontActiveColor.svg @@ -0,0 +1 @@ + diff --git a/frontend/src/assets/svg/dv-style-headFontColor.svg b/frontend/src/assets/svg/dv-style-headFontColor.svg new file mode 100644 index 0000000..0e897c0 --- /dev/null +++ b/frontend/src/assets/svg/dv-style-headFontColor.svg @@ -0,0 +1 @@ + diff --git a/frontend/src/assets/svg/dv-style-headHorizontalPosition.svg b/frontend/src/assets/svg/dv-style-headHorizontalPosition.svg new file mode 100644 index 0000000..82aab47 --- /dev/null +++ b/frontend/src/assets/svg/dv-style-headHorizontalPosition.svg @@ -0,0 +1 @@ + diff --git a/frontend/src/assets/svg/dv-style-letterSpacing.svg b/frontend/src/assets/svg/dv-style-letterSpacing.svg new file mode 100644 index 0000000..cedd710 --- /dev/null +++ b/frontend/src/assets/svg/dv-style-letterSpacing.svg @@ -0,0 +1 @@ + diff --git a/frontend/src/assets/svg/dv-style-lineHeight.svg b/frontend/src/assets/svg/dv-style-lineHeight.svg new file mode 100644 index 0000000..a310698 --- /dev/null +++ b/frontend/src/assets/svg/dv-style-lineHeight.svg @@ -0,0 +1 @@ + diff --git a/frontend/src/assets/svg/dv-style-opacity.svg b/frontend/src/assets/svg/dv-style-opacity.svg new file mode 100644 index 0000000..38a7187 --- /dev/null +++ b/frontend/src/assets/svg/dv-style-opacity.svg @@ -0,0 +1 @@ + diff --git a/frontend/src/assets/svg/dv-style-scroll-speed.svg b/frontend/src/assets/svg/dv-style-scroll-speed.svg new file mode 100644 index 0000000..e0634c5 --- /dev/null +++ b/frontend/src/assets/svg/dv-style-scroll-speed.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/src/assets/svg/dv-style-tab-head.svg b/frontend/src/assets/svg/dv-style-tab-head.svg new file mode 100644 index 0000000..23d91ef --- /dev/null +++ b/frontend/src/assets/svg/dv-style-tab-head.svg @@ -0,0 +1 @@ + diff --git a/frontend/src/assets/svg/dv-style-textAlign.svg b/frontend/src/assets/svg/dv-style-textAlign.svg new file mode 100644 index 0000000..8206d93 --- /dev/null +++ b/frontend/src/assets/svg/dv-style-textAlign.svg @@ -0,0 +1 @@ + diff --git a/frontend/src/assets/svg/dv-tab-show.svg b/frontend/src/assets/svg/dv-tab-show.svg new file mode 100644 index 0000000..c67a1a5 --- /dev/null +++ b/frontend/src/assets/svg/dv-tab-show.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/dv-tab.svg b/frontend/src/assets/svg/dv-tab.svg new file mode 100644 index 0000000..5625982 --- /dev/null +++ b/frontend/src/assets/svg/dv-tab.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/dv-text.svg b/frontend/src/assets/svg/dv-text.svg new file mode 100644 index 0000000..ff6d406 --- /dev/null +++ b/frontend/src/assets/svg/dv-text.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/dv-unlock.svg b/frontend/src/assets/svg/dv-unlock.svg new file mode 100644 index 0000000..a8b53de --- /dev/null +++ b/frontend/src/assets/svg/dv-unlock.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/dv-up-arrow.svg b/frontend/src/assets/svg/dv-up-arrow.svg new file mode 100644 index 0000000..f6f4348 --- /dev/null +++ b/frontend/src/assets/svg/dv-up-arrow.svg @@ -0,0 +1 @@ + diff --git a/frontend/src/assets/svg/dv-use-template.svg b/frontend/src/assets/svg/dv-use-template.svg new file mode 100644 index 0000000..cae2630 --- /dev/null +++ b/frontend/src/assets/svg/dv-use-template.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/dv-video.svg b/frontend/src/assets/svg/dv-video.svg new file mode 100644 index 0000000..1700f7f --- /dev/null +++ b/frontend/src/assets/svg/dv-video.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/dv-view.svg b/frontend/src/assets/svg/dv-view.svg new file mode 100644 index 0000000..1909312 --- /dev/null +++ b/frontend/src/assets/svg/dv-view.svg @@ -0,0 +1,4 @@ + + + + diff --git a/frontend/src/assets/svg/dv_mobile_layout.svg b/frontend/src/assets/svg/dv_mobile_layout.svg new file mode 100644 index 0000000..b242b08 --- /dev/null +++ b/frontend/src/assets/svg/dv_mobile_layout.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/frontend/src/assets/svg/edit-done.svg b/frontend/src/assets/svg/edit-done.svg new file mode 100644 index 0000000..e2049b6 --- /dev/null +++ b/frontend/src/assets/svg/edit-done.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/edit-in.svg b/frontend/src/assets/svg/edit-in.svg new file mode 100644 index 0000000..95428d1 --- /dev/null +++ b/frontend/src/assets/svg/edit-in.svg @@ -0,0 +1 @@ + diff --git a/frontend/src/assets/svg/edit.svg b/frontend/src/assets/svg/edit.svg new file mode 100644 index 0000000..dc80a3e --- /dev/null +++ b/frontend/src/assets/svg/edit.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/src/assets/svg/email-task.svg b/frontend/src/assets/svg/email-task.svg new file mode 100644 index 0000000..be6e900 --- /dev/null +++ b/frontend/src/assets/svg/email-task.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/src/assets/svg/embedded.svg b/frontend/src/assets/svg/embedded.svg new file mode 100644 index 0000000..251744a --- /dev/null +++ b/frontend/src/assets/svg/embedded.svg @@ -0,0 +1,4 @@ + + + + diff --git a/frontend/src/assets/svg/es-ds.svg b/frontend/src/assets/svg/es-ds.svg new file mode 100644 index 0000000..60e5577 --- /dev/null +++ b/frontend/src/assets/svg/es-ds.svg @@ -0,0 +1 @@ + diff --git a/frontend/src/assets/svg/example.svg b/frontend/src/assets/svg/example.svg new file mode 100644 index 0000000..46f42b5 --- /dev/null +++ b/frontend/src/assets/svg/example.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/src/assets/svg/exclamationmark.svg b/frontend/src/assets/svg/exclamationmark.svg new file mode 100644 index 0000000..612b620 --- /dev/null +++ b/frontend/src/assets/svg/exclamationmark.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/src/assets/svg/exclamationmark2.svg b/frontend/src/assets/svg/exclamationmark2.svg new file mode 100644 index 0000000..6e45d42 --- /dev/null +++ b/frontend/src/assets/svg/exclamationmark2.svg @@ -0,0 +1 @@ + diff --git a/frontend/src/assets/svg/exit-fullscreen.svg b/frontend/src/assets/svg/exit-fullscreen.svg new file mode 100644 index 0000000..485c128 --- /dev/null +++ b/frontend/src/assets/svg/exit-fullscreen.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/src/assets/svg/eye-open.svg b/frontend/src/assets/svg/eye-open.svg new file mode 100644 index 0000000..88dcc98 --- /dev/null +++ b/frontend/src/assets/svg/eye-open.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/src/assets/svg/eye.svg b/frontend/src/assets/svg/eye.svg new file mode 100644 index 0000000..4865e0e --- /dev/null +++ b/frontend/src/assets/svg/eye.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/frontend/src/assets/svg/field_location.svg b/frontend/src/assets/svg/field_location.svg new file mode 100644 index 0000000..7def81f --- /dev/null +++ b/frontend/src/assets/svg/field_location.svg @@ -0,0 +1 @@ + diff --git a/frontend/src/assets/svg/field_text.svg b/frontend/src/assets/svg/field_text.svg new file mode 100644 index 0000000..16fa778 --- /dev/null +++ b/frontend/src/assets/svg/field_text.svg @@ -0,0 +1 @@ + diff --git a/frontend/src/assets/svg/field_time.svg b/frontend/src/assets/svg/field_time.svg new file mode 100644 index 0000000..b5c0c4e --- /dev/null +++ b/frontend/src/assets/svg/field_time.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/src/assets/svg/field_url.svg b/frontend/src/assets/svg/field_url.svg new file mode 100644 index 0000000..4d6d540 --- /dev/null +++ b/frontend/src/assets/svg/field_url.svg @@ -0,0 +1 @@ + diff --git a/frontend/src/assets/svg/field_value.svg b/frontend/src/assets/svg/field_value.svg new file mode 100644 index 0000000..b907e4f --- /dev/null +++ b/frontend/src/assets/svg/field_value.svg @@ -0,0 +1 @@ + diff --git a/frontend/src/assets/svg/filter-center.svg b/frontend/src/assets/svg/filter-center.svg new file mode 100644 index 0000000..0cf66b6 --- /dev/null +++ b/frontend/src/assets/svg/filter-center.svg @@ -0,0 +1,4 @@ + + + + diff --git a/frontend/src/assets/svg/filter-h-center.svg b/frontend/src/assets/svg/filter-h-center.svg new file mode 100644 index 0000000..366d8c7 --- /dev/null +++ b/frontend/src/assets/svg/filter-h-center.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/frontend/src/assets/svg/filter-h-left.svg b/frontend/src/assets/svg/filter-h-left.svg new file mode 100644 index 0000000..d7f5a89 --- /dev/null +++ b/frontend/src/assets/svg/filter-h-left.svg @@ -0,0 +1,4 @@ + + + + diff --git a/frontend/src/assets/svg/filter-h-right.svg b/frontend/src/assets/svg/filter-h-right.svg new file mode 100644 index 0000000..21100e0 --- /dev/null +++ b/frontend/src/assets/svg/filter-h-right.svg @@ -0,0 +1,4 @@ + + + + diff --git a/frontend/src/assets/svg/filter-params.svg b/frontend/src/assets/svg/filter-params.svg new file mode 100644 index 0000000..ebe0221 --- /dev/null +++ b/frontend/src/assets/svg/filter-params.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/filter-top.svg b/frontend/src/assets/svg/filter-top.svg new file mode 100644 index 0000000..1d4da9e --- /dev/null +++ b/frontend/src/assets/svg/filter-top.svg @@ -0,0 +1,4 @@ + + + + diff --git a/frontend/src/assets/svg/filter.svg b/frontend/src/assets/svg/filter.svg new file mode 100644 index 0000000..d533bd3 --- /dev/null +++ b/frontend/src/assets/svg/filter.svg @@ -0,0 +1 @@ + diff --git a/frontend/src/assets/svg/flow-map-dark.svg b/frontend/src/assets/svg/flow-map-dark.svg new file mode 100644 index 0000000..ab44292 --- /dev/null +++ b/frontend/src/assets/svg/flow-map-dark.svg @@ -0,0 +1 @@ + diff --git a/frontend/src/assets/svg/flow-map-origin.svg b/frontend/src/assets/svg/flow-map-origin.svg new file mode 100644 index 0000000..5651cb0 --- /dev/null +++ b/frontend/src/assets/svg/flow-map-origin.svg @@ -0,0 +1 @@ + diff --git a/frontend/src/assets/svg/flow-map.svg b/frontend/src/assets/svg/flow-map.svg new file mode 100644 index 0000000..72469aa --- /dev/null +++ b/frontend/src/assets/svg/flow-map.svg @@ -0,0 +1 @@ + diff --git a/frontend/src/assets/svg/folder.svg b/frontend/src/assets/svg/folder.svg new file mode 100644 index 0000000..8216001 --- /dev/null +++ b/frontend/src/assets/svg/folder.svg @@ -0,0 +1 @@ + diff --git a/frontend/src/assets/svg/form.svg b/frontend/src/assets/svg/form.svg new file mode 100644 index 0000000..dcbaa18 --- /dev/null +++ b/frontend/src/assets/svg/form.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/src/assets/svg/fullscreen.svg b/frontend/src/assets/svg/fullscreen.svg new file mode 100644 index 0000000..0e86b6f --- /dev/null +++ b/frontend/src/assets/svg/fullscreen.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/src/assets/svg/funnel-dark.svg b/frontend/src/assets/svg/funnel-dark.svg new file mode 100644 index 0000000..4ded995 --- /dev/null +++ b/frontend/src/assets/svg/funnel-dark.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/frontend/src/assets/svg/funnel-origin.svg b/frontend/src/assets/svg/funnel-origin.svg new file mode 100644 index 0000000..e784314 --- /dev/null +++ b/frontend/src/assets/svg/funnel-origin.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/funnel.svg b/frontend/src/assets/svg/funnel.svg new file mode 100644 index 0000000..ad8ad47 --- /dev/null +++ b/frontend/src/assets/svg/funnel.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/frontend/src/assets/svg/gauge-dark.svg b/frontend/src/assets/svg/gauge-dark.svg new file mode 100644 index 0000000..336e172 --- /dev/null +++ b/frontend/src/assets/svg/gauge-dark.svg @@ -0,0 +1,4 @@ + + + + diff --git a/frontend/src/assets/svg/gauge-origin.svg b/frontend/src/assets/svg/gauge-origin.svg new file mode 100644 index 0000000..8fe48ce --- /dev/null +++ b/frontend/src/assets/svg/gauge-origin.svg @@ -0,0 +1,4 @@ + + + + diff --git a/frontend/src/assets/svg/gauge.svg b/frontend/src/assets/svg/gauge.svg new file mode 100644 index 0000000..336e172 --- /dev/null +++ b/frontend/src/assets/svg/gauge.svg @@ -0,0 +1,4 @@ + + + + diff --git a/frontend/src/assets/svg/graphical-circular.svg b/frontend/src/assets/svg/graphical-circular.svg new file mode 100644 index 0000000..cdffe09 --- /dev/null +++ b/frontend/src/assets/svg/graphical-circular.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/src/assets/svg/graphical-rect.svg b/frontend/src/assets/svg/graphical-rect.svg new file mode 100644 index 0000000..1bbb69c --- /dev/null +++ b/frontend/src/assets/svg/graphical-rect.svg @@ -0,0 +1 @@ + diff --git a/frontend/src/assets/svg/graphical-triangle.svg b/frontend/src/assets/svg/graphical-triangle.svg new file mode 100644 index 0000000..74a6439 --- /dev/null +++ b/frontend/src/assets/svg/graphical-triangle.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/src/assets/svg/group-3400.svg b/frontend/src/assets/svg/group-3400.svg new file mode 100644 index 0000000..d0712e3 --- /dev/null +++ b/frontend/src/assets/svg/group-3400.svg @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/frontend/src/assets/svg/group.svg b/frontend/src/assets/svg/group.svg new file mode 100644 index 0000000..8216001 --- /dev/null +++ b/frontend/src/assets/svg/group.svg @@ -0,0 +1 @@ + diff --git a/frontend/src/assets/svg/heat-map-dark.svg b/frontend/src/assets/svg/heat-map-dark.svg new file mode 100644 index 0000000..a5aff12 --- /dev/null +++ b/frontend/src/assets/svg/heat-map-dark.svg @@ -0,0 +1 @@ + diff --git a/frontend/src/assets/svg/heat-map-origin.svg b/frontend/src/assets/svg/heat-map-origin.svg new file mode 100644 index 0000000..3bf0491 --- /dev/null +++ b/frontend/src/assets/svg/heat-map-origin.svg @@ -0,0 +1 @@ + diff --git a/frontend/src/assets/svg/heat-map.svg b/frontend/src/assets/svg/heat-map.svg new file mode 100644 index 0000000..7e8a1c8 --- /dev/null +++ b/frontend/src/assets/svg/heat-map.svg @@ -0,0 +1 @@ + diff --git a/frontend/src/assets/svg/icon-alarmclock.svg b/frontend/src/assets/svg/icon-alarmclock.svg new file mode 100644 index 0000000..dfb628f --- /dev/null +++ b/frontend/src/assets/svg/icon-alarmclock.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/icon-contacts.svg b/frontend/src/assets/svg/icon-contacts.svg new file mode 100644 index 0000000..f8cf9ae --- /dev/null +++ b/frontend/src/assets/svg/icon-contacts.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/icon-draft.svg b/frontend/src/assets/svg/icon-draft.svg new file mode 100644 index 0000000..7d757c9 --- /dev/null +++ b/frontend/src/assets/svg/icon-draft.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/icon-filter.svg b/frontend/src/assets/svg/icon-filter.svg new file mode 100644 index 0000000..c613a73 --- /dev/null +++ b/frontend/src/assets/svg/icon-filter.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/icon-group.svg b/frontend/src/assets/svg/icon-group.svg new file mode 100644 index 0000000..6255652 --- /dev/null +++ b/frontend/src/assets/svg/icon-group.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/icon-image-upload.svg b/frontend/src/assets/svg/icon-image-upload.svg new file mode 100644 index 0000000..f4033e4 --- /dev/null +++ b/frontend/src/assets/svg/icon-image-upload.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/src/assets/svg/icon-image.svg b/frontend/src/assets/svg/icon-image.svg new file mode 100644 index 0000000..f67e6c6 --- /dev/null +++ b/frontend/src/assets/svg/icon-image.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/src/assets/svg/icon-laser.svg b/frontend/src/assets/svg/icon-laser.svg new file mode 100644 index 0000000..5df3a64 --- /dev/null +++ b/frontend/src/assets/svg/icon-laser.svg @@ -0,0 +1,4 @@ + + + + diff --git a/frontend/src/assets/svg/icon-lock.svg b/frontend/src/assets/svg/icon-lock.svg new file mode 100644 index 0000000..65cf212 --- /dev/null +++ b/frontend/src/assets/svg/icon-lock.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/icon-maybe.svg b/frontend/src/assets/svg/icon-maybe.svg new file mode 100644 index 0000000..c2c801b --- /dev/null +++ b/frontend/src/assets/svg/icon-maybe.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/icon-maybe_outlined.svg b/frontend/src/assets/svg/icon-maybe_outlined.svg new file mode 100644 index 0000000..ac3de0e --- /dev/null +++ b/frontend/src/assets/svg/icon-maybe_outlined.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/icon-more.svg b/frontend/src/assets/svg/icon-more.svg new file mode 100644 index 0000000..76178f1 --- /dev/null +++ b/frontend/src/assets/svg/icon-more.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/icon-quicksetting.svg b/frontend/src/assets/svg/icon-quicksetting.svg new file mode 100644 index 0000000..cf705e8 --- /dev/null +++ b/frontend/src/assets/svg/icon-quicksetting.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/icon-setting.svg b/frontend/src/assets/svg/icon-setting.svg new file mode 100644 index 0000000..857e45a --- /dev/null +++ b/frontend/src/assets/svg/icon-setting.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/icon-stream.svg b/frontend/src/assets/svg/icon-stream.svg new file mode 100644 index 0000000..f0624b7 --- /dev/null +++ b/frontend/src/assets/svg/icon-stream.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/icon-video.svg b/frontend/src/assets/svg/icon-video.svg new file mode 100644 index 0000000..4568a1e --- /dev/null +++ b/frontend/src/assets/svg/icon-video.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/icon/ctrl/close.svg b/frontend/src/assets/svg/icon/ctrl/close.svg new file mode 100644 index 0000000..14f93b6 --- /dev/null +++ b/frontend/src/assets/svg/icon/ctrl/close.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/icon/outline/notification.svg b/frontend/src/assets/svg/icon/outline/notification.svg new file mode 100644 index 0000000..25b9723 --- /dev/null +++ b/frontend/src/assets/svg/icon/outline/notification.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/icon_Batch_outlined.svg b/frontend/src/assets/svg/icon_Batch_outlined.svg new file mode 100644 index 0000000..21f6c5d --- /dev/null +++ b/frontend/src/assets/svg/icon_Batch_outlined.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/icon_Invalid_colorful.svg b/frontend/src/assets/svg/icon_Invalid_colorful.svg new file mode 100644 index 0000000..bcfc7cb --- /dev/null +++ b/frontend/src/assets/svg/icon_Invalid_colorful.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/frontend/src/assets/svg/icon_add-dictionary_outlined.svg b/frontend/src/assets/svg/icon_add-dictionary_outlined.svg new file mode 100644 index 0000000..b2e9708 --- /dev/null +++ b/frontend/src/assets/svg/icon_add-dictionary_outlined.svg @@ -0,0 +1,4 @@ + + + + diff --git a/frontend/src/assets/svg/icon_add-entry_outlined.svg b/frontend/src/assets/svg/icon_add-entry_outlined.svg new file mode 100644 index 0000000..443fda7 --- /dev/null +++ b/frontend/src/assets/svg/icon_add-entry_outlined.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/frontend/src/assets/svg/icon_add-folder_outlined.svg b/frontend/src/assets/svg/icon_add-folder_outlined.svg new file mode 100644 index 0000000..066b59f --- /dev/null +++ b/frontend/src/assets/svg/icon_add-folder_outlined.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/frontend/src/assets/svg/icon_add_outlined-1.svg b/frontend/src/assets/svg/icon_add_outlined-1.svg new file mode 100644 index 0000000..12c99c3 --- /dev/null +++ b/frontend/src/assets/svg/icon_add_outlined-1.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/icon_add_outlined.svg b/frontend/src/assets/svg/icon_add_outlined.svg new file mode 100644 index 0000000..f3364bb --- /dev/null +++ b/frontend/src/assets/svg/icon_add_outlined.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/icon_adjustment_outlined.svg b/frontend/src/assets/svg/icon_adjustment_outlined.svg new file mode 100644 index 0000000..d07b213 --- /dev/null +++ b/frontend/src/assets/svg/icon_adjustment_outlined.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/frontend/src/assets/svg/icon_admin_outlined.svg b/frontend/src/assets/svg/icon_admin_outlined.svg new file mode 100644 index 0000000..40404d0 --- /dev/null +++ b/frontend/src/assets/svg/icon_admin_outlined.svg @@ -0,0 +1,4 @@ + + + + diff --git a/frontend/src/assets/svg/icon_api-outlined.svg b/frontend/src/assets/svg/icon_api-outlined.svg new file mode 100644 index 0000000..d006314 --- /dev/null +++ b/frontend/src/assets/svg/icon_api-outlined.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/frontend/src/assets/svg/icon_api.svg b/frontend/src/assets/svg/icon_api.svg new file mode 100644 index 0000000..4caf125 --- /dev/null +++ b/frontend/src/assets/svg/icon_api.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/frontend/src/assets/svg/icon_app_outlined.svg b/frontend/src/assets/svg/icon_app_outlined.svg new file mode 100644 index 0000000..3548abb --- /dev/null +++ b/frontend/src/assets/svg/icon_app_outlined.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/icon_arrow-right_outlined.svg b/frontend/src/assets/svg/icon_arrow-right_outlined.svg new file mode 100644 index 0000000..e7020ea --- /dev/null +++ b/frontend/src/assets/svg/icon_arrow-right_outlined.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/icon_assigned_outlined.svg b/frontend/src/assets/svg/icon_assigned_outlined.svg new file mode 100644 index 0000000..9f0f15f --- /dev/null +++ b/frontend/src/assets/svg/icon_assigned_outlined.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/frontend/src/assets/svg/icon_attachment_outlined.svg b/frontend/src/assets/svg/icon_attachment_outlined.svg new file mode 100644 index 0000000..1b93ae1 --- /dev/null +++ b/frontend/src/assets/svg/icon_attachment_outlined.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/icon_bold_outlined.svg b/frontend/src/assets/svg/icon_bold_outlined.svg new file mode 100644 index 0000000..19cd7a7 --- /dev/null +++ b/frontend/src/assets/svg/icon_bold_outlined.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/icon_bottom-align_outlined.svg b/frontend/src/assets/svg/icon_bottom-align_outlined.svg new file mode 100644 index 0000000..d9de589 --- /dev/null +++ b/frontend/src/assets/svg/icon_bottom-align_outlined.svg @@ -0,0 +1,4 @@ + + + + diff --git a/frontend/src/assets/svg/icon_calendar-calculated_outlined-1.svg b/frontend/src/assets/svg/icon_calendar-calculated_outlined-1.svg new file mode 100644 index 0000000..f80b8c0 --- /dev/null +++ b/frontend/src/assets/svg/icon_calendar-calculated_outlined-1.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/frontend/src/assets/svg/icon_calendar-calculated_outlined.svg b/frontend/src/assets/svg/icon_calendar-calculated_outlined.svg new file mode 100644 index 0000000..e7c22eb --- /dev/null +++ b/frontend/src/assets/svg/icon_calendar-calculated_outlined.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/frontend/src/assets/svg/icon_calendar_outlined.svg b/frontend/src/assets/svg/icon_calendar_outlined.svg new file mode 100644 index 0000000..c7f73df --- /dev/null +++ b/frontend/src/assets/svg/icon_calendar_outlined.svg @@ -0,0 +1,4 @@ + + + + diff --git a/frontend/src/assets/svg/icon_cancel_store.svg b/frontend/src/assets/svg/icon_cancel_store.svg new file mode 100644 index 0000000..f14c04f --- /dev/null +++ b/frontend/src/assets/svg/icon_cancel_store.svg @@ -0,0 +1 @@ + diff --git a/frontend/src/assets/svg/icon_card_outlined.svg b/frontend/src/assets/svg/icon_card_outlined.svg new file mode 100644 index 0000000..ca7111b --- /dev/null +++ b/frontend/src/assets/svg/icon_card_outlined.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/frontend/src/assets/svg/icon_center-alignment_outlined.svg b/frontend/src/assets/svg/icon_center-alignment_outlined.svg new file mode 100644 index 0000000..d524c3a --- /dev/null +++ b/frontend/src/assets/svg/icon_center-alignment_outlined.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/frontend/src/assets/svg/icon_chart-line-c.svg b/frontend/src/assets/svg/icon_chart-line-c.svg new file mode 100644 index 0000000..6afc7dc --- /dev/null +++ b/frontend/src/assets/svg/icon_chart-line-c.svg @@ -0,0 +1,4 @@ + + + + diff --git a/frontend/src/assets/svg/icon_chart-line.svg b/frontend/src/assets/svg/icon_chart-line.svg new file mode 100644 index 0000000..9a42cdd --- /dev/null +++ b/frontend/src/assets/svg/icon_chart-line.svg @@ -0,0 +1,4 @@ + + + + diff --git a/frontend/src/assets/svg/icon_clear_outlined.svg b/frontend/src/assets/svg/icon_clear_outlined.svg new file mode 100644 index 0000000..ab015c6 --- /dev/null +++ b/frontend/src/assets/svg/icon_clear_outlined.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/icon_close_filled.svg b/frontend/src/assets/svg/icon_close_filled.svg new file mode 100644 index 0000000..ca6a974 --- /dev/null +++ b/frontend/src/assets/svg/icon_close_filled.svg @@ -0,0 +1,4 @@ + + + + diff --git a/frontend/src/assets/svg/icon_close_outlined.svg b/frontend/src/assets/svg/icon_close_outlined.svg new file mode 100644 index 0000000..124221e --- /dev/null +++ b/frontend/src/assets/svg/icon_close_outlined.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/icon_collect_filled.svg b/frontend/src/assets/svg/icon_collect_filled.svg new file mode 100644 index 0000000..f55a99e --- /dev/null +++ b/frontend/src/assets/svg/icon_collect_filled.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/icon_collection_outlined.svg b/frontend/src/assets/svg/icon_collection_outlined.svg new file mode 100644 index 0000000..b5a0a4d --- /dev/null +++ b/frontend/src/assets/svg/icon_collection_outlined.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/icon_copy_filled.svg b/frontend/src/assets/svg/icon_copy_filled.svg new file mode 100644 index 0000000..f3a23c6 --- /dev/null +++ b/frontend/src/assets/svg/icon_copy_filled.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/icon_copy_outlined.svg b/frontend/src/assets/svg/icon_copy_outlined.svg new file mode 100644 index 0000000..ec20e00 --- /dev/null +++ b/frontend/src/assets/svg/icon_copy_outlined.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/icon_customize.svg b/frontend/src/assets/svg/icon_customize.svg new file mode 100644 index 0000000..ff3780d --- /dev/null +++ b/frontend/src/assets/svg/icon_customize.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/frontend/src/assets/svg/icon_dashboard.svg b/frontend/src/assets/svg/icon_dashboard.svg new file mode 100644 index 0000000..b726772 --- /dev/null +++ b/frontend/src/assets/svg/icon_dashboard.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/frontend/src/assets/svg/icon_dashboard_outlined-c.svg b/frontend/src/assets/svg/icon_dashboard_outlined-c.svg new file mode 100644 index 0000000..630be3d --- /dev/null +++ b/frontend/src/assets/svg/icon_dashboard_outlined-c.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/icon_dashboard_outlined.svg b/frontend/src/assets/svg/icon_dashboard_outlined.svg new file mode 100644 index 0000000..3435cd2 --- /dev/null +++ b/frontend/src/assets/svg/icon_dashboard_outlined.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/icon_data-visualization.svg b/frontend/src/assets/svg/icon_data-visualization.svg new file mode 100644 index 0000000..8303575 --- /dev/null +++ b/frontend/src/assets/svg/icon_data-visualization.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/frontend/src/assets/svg/icon_database-alert_filled.svg b/frontend/src/assets/svg/icon_database-alert_filled.svg new file mode 100644 index 0000000..d5429b1 --- /dev/null +++ b/frontend/src/assets/svg/icon_database-alert_filled.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/frontend/src/assets/svg/icon_database-fail_filled.svg b/frontend/src/assets/svg/icon_database-fail_filled.svg new file mode 100644 index 0000000..9e8c6df --- /dev/null +++ b/frontend/src/assets/svg/icon_database-fail_filled.svg @@ -0,0 +1,4 @@ + + + + diff --git a/frontend/src/assets/svg/icon_database.svg b/frontend/src/assets/svg/icon_database.svg new file mode 100644 index 0000000..b07810e --- /dev/null +++ b/frontend/src/assets/svg/icon_database.svg @@ -0,0 +1,4 @@ + + + + diff --git a/frontend/src/assets/svg/icon_database_outlined.svg b/frontend/src/assets/svg/icon_database_outlined.svg new file mode 100644 index 0000000..b19453c --- /dev/null +++ b/frontend/src/assets/svg/icon_database_outlined.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/icon_dataset.svg b/frontend/src/assets/svg/icon_dataset.svg new file mode 100644 index 0000000..da26700 --- /dev/null +++ b/frontend/src/assets/svg/icon_dataset.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/frontend/src/assets/svg/icon_dataset_outlined.svg b/frontend/src/assets/svg/icon_dataset_outlined.svg new file mode 100644 index 0000000..ad16256 --- /dev/null +++ b/frontend/src/assets/svg/icon_dataset_outlined.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/frontend/src/assets/svg/icon_db_filled.svg b/frontend/src/assets/svg/icon_db_filled.svg new file mode 100644 index 0000000..3cf911b --- /dev/null +++ b/frontend/src/assets/svg/icon_db_filled.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/icon_delete-trash_outlined.svg b/frontend/src/assets/svg/icon_delete-trash_outlined.svg new file mode 100644 index 0000000..c71a843 --- /dev/null +++ b/frontend/src/assets/svg/icon_delete-trash_outlined.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/icon_describe_outlined.svg b/frontend/src/assets/svg/icon_describe_outlined.svg new file mode 100644 index 0000000..cfabccf --- /dev/null +++ b/frontend/src/assets/svg/icon_describe_outlined.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/icon_dialpad_outlined.svg b/frontend/src/assets/svg/icon_dialpad_outlined.svg new file mode 100644 index 0000000..8398158 --- /dev/null +++ b/frontend/src/assets/svg/icon_dialpad_outlined.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/frontend/src/assets/svg/icon_disorde-list_outlined.svg b/frontend/src/assets/svg/icon_disorde-list_outlined.svg new file mode 100644 index 0000000..312fa84 --- /dev/null +++ b/frontend/src/assets/svg/icon_disorde-list_outlined.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/icon_divider_outlined.svg b/frontend/src/assets/svg/icon_divider_outlined.svg new file mode 100644 index 0000000..71575af --- /dev/null +++ b/frontend/src/assets/svg/icon_divider_outlined.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/icon_doc-replace_outlined.svg b/frontend/src/assets/svg/icon_doc-replace_outlined.svg new file mode 100644 index 0000000..9b9398a --- /dev/null +++ b/frontend/src/assets/svg/icon_doc-replace_outlined.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/frontend/src/assets/svg/icon_done_outlined.svg b/frontend/src/assets/svg/icon_done_outlined.svg new file mode 100644 index 0000000..4c60343 --- /dev/null +++ b/frontend/src/assets/svg/icon_done_outlined.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/frontend/src/assets/svg/icon_down-right_outlined.svg b/frontend/src/assets/svg/icon_down-right_outlined.svg new file mode 100644 index 0000000..8feb48f --- /dev/null +++ b/frontend/src/assets/svg/icon_down-right_outlined.svg @@ -0,0 +1,4 @@ + + + + diff --git a/frontend/src/assets/svg/icon_down_outlined-1.svg b/frontend/src/assets/svg/icon_down_outlined-1.svg new file mode 100644 index 0000000..7daaede --- /dev/null +++ b/frontend/src/assets/svg/icon_down_outlined-1.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/icon_down_outlined.svg b/frontend/src/assets/svg/icon_down_outlined.svg new file mode 100644 index 0000000..c34cbfb --- /dev/null +++ b/frontend/src/assets/svg/icon_down_outlined.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/icon_download_outlined.svg b/frontend/src/assets/svg/icon_download_outlined.svg new file mode 100644 index 0000000..dca3c20 --- /dev/null +++ b/frontend/src/assets/svg/icon_download_outlined.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/icon_drag_outlined.svg b/frontend/src/assets/svg/icon_drag_outlined.svg new file mode 100644 index 0000000..0244241 --- /dev/null +++ b/frontend/src/assets/svg/icon_drag_outlined.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/icon_drilling_outlined.svg b/frontend/src/assets/svg/icon_drilling_outlined.svg new file mode 100644 index 0000000..6686858 --- /dev/null +++ b/frontend/src/assets/svg/icon_drilling_outlined.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/icon_drive_filled.svg b/frontend/src/assets/svg/icon_drive_filled.svg new file mode 100644 index 0000000..b9fb354 --- /dev/null +++ b/frontend/src/assets/svg/icon_drive_filled.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/frontend/src/assets/svg/icon_edit_outlined.svg b/frontend/src/assets/svg/icon_edit_outlined.svg new file mode 100644 index 0000000..817c15c --- /dev/null +++ b/frontend/src/assets/svg/icon_edit_outlined.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/icon_effects_outlined.svg b/frontend/src/assets/svg/icon_effects_outlined.svg new file mode 100644 index 0000000..6d798aa --- /dev/null +++ b/frontend/src/assets/svg/icon_effects_outlined.svg @@ -0,0 +1,4 @@ + + + + diff --git a/frontend/src/assets/svg/icon_excel.svg b/frontend/src/assets/svg/icon_excel.svg new file mode 100644 index 0000000..d215044 --- /dev/null +++ b/frontend/src/assets/svg/icon_excel.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/frontend/src/assets/svg/icon_excel_outlined.svg b/frontend/src/assets/svg/icon_excel_outlined.svg new file mode 100644 index 0000000..fa0542a --- /dev/null +++ b/frontend/src/assets/svg/icon_excel_outlined.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/icon_expand-down_filled.svg b/frontend/src/assets/svg/icon_expand-down_filled.svg new file mode 100644 index 0000000..9c96d7e --- /dev/null +++ b/frontend/src/assets/svg/icon_expand-down_filled.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/icon_expand-left_filled.svg b/frontend/src/assets/svg/icon_expand-left_filled.svg new file mode 100644 index 0000000..0a102b2 --- /dev/null +++ b/frontend/src/assets/svg/icon_expand-left_filled.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/frontend/src/assets/svg/icon_expand-right_filled.svg b/frontend/src/assets/svg/icon_expand-right_filled.svg new file mode 100644 index 0000000..804bf01 --- /dev/null +++ b/frontend/src/assets/svg/icon_expand-right_filled.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/icon_file-add_outlined.svg b/frontend/src/assets/svg/icon_file-add_outlined.svg new file mode 100644 index 0000000..669ede9 --- /dev/null +++ b/frontend/src/assets/svg/icon_file-add_outlined.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/frontend/src/assets/svg/icon_file-doc_colorful.svg b/frontend/src/assets/svg/icon_file-doc_colorful.svg new file mode 100644 index 0000000..7371ef7 --- /dev/null +++ b/frontend/src/assets/svg/icon_file-doc_colorful.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/frontend/src/assets/svg/icon_file-excel_colorful.svg b/frontend/src/assets/svg/icon_file-excel_colorful.svg new file mode 100644 index 0000000..8355979 --- /dev/null +++ b/frontend/src/assets/svg/icon_file-excel_colorful.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/frontend/src/assets/svg/icon_file-font_colorful.svg b/frontend/src/assets/svg/icon_file-font_colorful.svg new file mode 100644 index 0000000..21e43cf --- /dev/null +++ b/frontend/src/assets/svg/icon_file-font_colorful.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/frontend/src/assets/svg/icon_folder_filled.svg b/frontend/src/assets/svg/icon_folder_filled.svg new file mode 100644 index 0000000..149f804 --- /dev/null +++ b/frontend/src/assets/svg/icon_folder_filled.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/icon_font-color_outlined.svg b/frontend/src/assets/svg/icon_font-color_outlined.svg new file mode 100644 index 0000000..f5f1798 --- /dev/null +++ b/frontend/src/assets/svg/icon_font-color_outlined.svg @@ -0,0 +1,4 @@ + + + + diff --git a/frontend/src/assets/svg/icon_font.svg b/frontend/src/assets/svg/icon_font.svg new file mode 100644 index 0000000..769b6a5 --- /dev/null +++ b/frontend/src/assets/svg/icon_font.svg @@ -0,0 +1,4 @@ + + + + diff --git a/frontend/src/assets/svg/icon_form_outlined.svg b/frontend/src/assets/svg/icon_form_outlined.svg new file mode 100644 index 0000000..b688bb3 --- /dev/null +++ b/frontend/src/assets/svg/icon_form_outlined.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/icon_form_outlined_white.svg b/frontend/src/assets/svg/icon_form_outlined_white.svg new file mode 100644 index 0000000..b6087c9 --- /dev/null +++ b/frontend/src/assets/svg/icon_form_outlined_white.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/icon_free.svg b/frontend/src/assets/svg/icon_free.svg new file mode 100644 index 0000000..96d3018 --- /dev/null +++ b/frontend/src/assets/svg/icon_free.svg @@ -0,0 +1,4 @@ + + + + diff --git a/frontend/src/assets/svg/icon_full-association.svg b/frontend/src/assets/svg/icon_full-association.svg new file mode 100644 index 0000000..f880448 --- /dev/null +++ b/frontend/src/assets/svg/icon_full-association.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/frontend/src/assets/svg/icon_functions_outlined.svg b/frontend/src/assets/svg/icon_functions_outlined.svg new file mode 100644 index 0000000..af8273a --- /dev/null +++ b/frontend/src/assets/svg/icon_functions_outlined.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/icon_graphical.svg b/frontend/src/assets/svg/icon_graphical.svg new file mode 100644 index 0000000..78871f6 --- /dev/null +++ b/frontend/src/assets/svg/icon_graphical.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/src/assets/svg/icon_gridlines_outlined.svg b/frontend/src/assets/svg/icon_gridlines_outlined.svg new file mode 100644 index 0000000..0b5cd51 --- /dev/null +++ b/frontend/src/assets/svg/icon_gridlines_outlined.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/frontend/src/assets/svg/icon_h1_outlined.svg b/frontend/src/assets/svg/icon_h1_outlined.svg new file mode 100644 index 0000000..82868fe --- /dev/null +++ b/frontend/src/assets/svg/icon_h1_outlined.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/icon_h2_outlined.svg b/frontend/src/assets/svg/icon_h2_outlined.svg new file mode 100644 index 0000000..fba5686 --- /dev/null +++ b/frontend/src/assets/svg/icon_h2_outlined.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/icon_h3_outlined.svg b/frontend/src/assets/svg/icon_h3_outlined.svg new file mode 100644 index 0000000..dbb7149 --- /dev/null +++ b/frontend/src/assets/svg/icon_h3_outlined.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/icon_hn_outlined.svg b/frontend/src/assets/svg/icon_hn_outlined.svg new file mode 100644 index 0000000..853b5fd --- /dev/null +++ b/frontend/src/assets/svg/icon_hn_outlined.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/icon_horizontal-align_outlined.svg b/frontend/src/assets/svg/icon_horizontal-align_outlined.svg new file mode 100644 index 0000000..6e96d2d --- /dev/null +++ b/frontend/src/assets/svg/icon_horizontal-align_outlined.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/frontend/src/assets/svg/icon_info_colorful.svg b/frontend/src/assets/svg/icon_info_colorful.svg new file mode 100644 index 0000000..cb82d21 --- /dev/null +++ b/frontend/src/assets/svg/icon_info_colorful.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/frontend/src/assets/svg/icon_info_filled.svg b/frontend/src/assets/svg/icon_info_filled.svg new file mode 100644 index 0000000..34439a4 --- /dev/null +++ b/frontend/src/assets/svg/icon_info_filled.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/frontend/src/assets/svg/icon_info_outlined.svg b/frontend/src/assets/svg/icon_info_outlined.svg new file mode 100644 index 0000000..eebdd2f --- /dev/null +++ b/frontend/src/assets/svg/icon_info_outlined.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/frontend/src/assets/svg/icon_intersect.svg b/frontend/src/assets/svg/icon_intersect.svg new file mode 100644 index 0000000..4513716 --- /dev/null +++ b/frontend/src/assets/svg/icon_intersect.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/frontend/src/assets/svg/icon_into-item_outlined.svg b/frontend/src/assets/svg/icon_into-item_outlined.svg new file mode 100644 index 0000000..296a79a --- /dev/null +++ b/frontend/src/assets/svg/icon_into-item_outlined.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/icon_invisible_outlined.svg b/frontend/src/assets/svg/icon_invisible_outlined.svg new file mode 100644 index 0000000..8f2869c --- /dev/null +++ b/frontend/src/assets/svg/icon_invisible_outlined.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/frontend/src/assets/svg/icon_italic_outlined.svg b/frontend/src/assets/svg/icon_italic_outlined.svg new file mode 100644 index 0000000..db85e3e --- /dev/null +++ b/frontend/src/assets/svg/icon_italic_outlined.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/icon_left-align_outlined.svg b/frontend/src/assets/svg/icon_left-align_outlined.svg new file mode 100644 index 0000000..b03c48c --- /dev/null +++ b/frontend/src/assets/svg/icon_left-align_outlined.svg @@ -0,0 +1,4 @@ + + + + diff --git a/frontend/src/assets/svg/icon_left-alignment_outlined.svg b/frontend/src/assets/svg/icon_left-alignment_outlined.svg new file mode 100644 index 0000000..13ffb12 --- /dev/null +++ b/frontend/src/assets/svg/icon_left-alignment_outlined.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/frontend/src/assets/svg/icon_left-association.svg b/frontend/src/assets/svg/icon_left-association.svg new file mode 100644 index 0000000..2a20b41 --- /dev/null +++ b/frontend/src/assets/svg/icon_left-association.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/frontend/src/assets/svg/icon_left_outlined.svg b/frontend/src/assets/svg/icon_left_outlined.svg new file mode 100644 index 0000000..a102147 --- /dev/null +++ b/frontend/src/assets/svg/icon_left_outlined.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/icon_letter-spacing_outlined.svg b/frontend/src/assets/svg/icon_letter-spacing_outlined.svg new file mode 100644 index 0000000..2648904 --- /dev/null +++ b/frontend/src/assets/svg/icon_letter-spacing_outlined.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/frontend/src/assets/svg/icon_link-calculated_outlined-1.svg b/frontend/src/assets/svg/icon_link-calculated_outlined-1.svg new file mode 100644 index 0000000..14e4764 --- /dev/null +++ b/frontend/src/assets/svg/icon_link-calculated_outlined-1.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/frontend/src/assets/svg/icon_link-calculated_outlined.svg b/frontend/src/assets/svg/icon_link-calculated_outlined.svg new file mode 100644 index 0000000..0d93deb --- /dev/null +++ b/frontend/src/assets/svg/icon_link-calculated_outlined.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/frontend/src/assets/svg/icon_link-record.svg b/frontend/src/assets/svg/icon_link-record.svg new file mode 100644 index 0000000..5ba2d69 --- /dev/null +++ b/frontend/src/assets/svg/icon_link-record.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/frontend/src/assets/svg/icon_link-record_outlined-1.svg b/frontend/src/assets/svg/icon_link-record_outlined-1.svg new file mode 100644 index 0000000..f7feacf --- /dev/null +++ b/frontend/src/assets/svg/icon_link-record_outlined-1.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/icon_link-record_outlined.svg b/frontend/src/assets/svg/icon_link-record_outlined.svg new file mode 100644 index 0000000..77a322b --- /dev/null +++ b/frontend/src/assets/svg/icon_link-record_outlined.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/icon_loading_outlined.svg b/frontend/src/assets/svg/icon_loading_outlined.svg new file mode 100644 index 0000000..1ef953a --- /dev/null +++ b/frontend/src/assets/svg/icon_loading_outlined.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/icon_local-calculated_outlined-1.svg b/frontend/src/assets/svg/icon_local-calculated_outlined-1.svg new file mode 100644 index 0000000..e05567c --- /dev/null +++ b/frontend/src/assets/svg/icon_local-calculated_outlined-1.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/frontend/src/assets/svg/icon_local-calculated_outlined.svg b/frontend/src/assets/svg/icon_local-calculated_outlined.svg new file mode 100644 index 0000000..a11bb57 --- /dev/null +++ b/frontend/src/assets/svg/icon_local-calculated_outlined.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/frontend/src/assets/svg/icon_local.svg b/frontend/src/assets/svg/icon_local.svg new file mode 100644 index 0000000..0c7c0d7 --- /dev/null +++ b/frontend/src/assets/svg/icon_local.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/icon_local_outlined.svg b/frontend/src/assets/svg/icon_local_outlined.svg new file mode 100644 index 0000000..b4a534e --- /dev/null +++ b/frontend/src/assets/svg/icon_local_outlined.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/icon_logs_outlined-1.svg b/frontend/src/assets/svg/icon_logs_outlined-1.svg new file mode 100644 index 0000000..353e1a1 --- /dev/null +++ b/frontend/src/assets/svg/icon_logs_outlined-1.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/icon_logs_outlined.svg b/frontend/src/assets/svg/icon_logs_outlined.svg new file mode 100644 index 0000000..9cf28e2 --- /dev/null +++ b/frontend/src/assets/svg/icon_logs_outlined.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/icon_magnify_outlined.svg b/frontend/src/assets/svg/icon_magnify_outlined.svg new file mode 100644 index 0000000..5893f97 --- /dev/null +++ b/frontend/src/assets/svg/icon_magnify_outlined.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/icon_member-add_outlined.svg b/frontend/src/assets/svg/icon_member-add_outlined.svg new file mode 100644 index 0000000..da2b8ef --- /dev/null +++ b/frontend/src/assets/svg/icon_member-add_outlined.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/frontend/src/assets/svg/icon_member_filled.svg b/frontend/src/assets/svg/icon_member_filled.svg new file mode 100644 index 0000000..ce50081 --- /dev/null +++ b/frontend/src/assets/svg/icon_member_filled.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/frontend/src/assets/svg/icon_mfa_reset.svg b/frontend/src/assets/svg/icon_mfa_reset.svg new file mode 100644 index 0000000..194a3b8 --- /dev/null +++ b/frontend/src/assets/svg/icon_mfa_reset.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/frontend/src/assets/svg/icon_minify_outlined.svg b/frontend/src/assets/svg/icon_minify_outlined.svg new file mode 100644 index 0000000..2037d7f --- /dev/null +++ b/frontend/src/assets/svg/icon_minify_outlined.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/icon_moments-categories_outlined.svg b/frontend/src/assets/svg/icon_moments-categories_outlined.svg new file mode 100644 index 0000000..bdd434c --- /dev/null +++ b/frontend/src/assets/svg/icon_moments-categories_outlined.svg @@ -0,0 +1,4 @@ + + + + diff --git a/frontend/src/assets/svg/icon_more-vertical_outlined.svg b/frontend/src/assets/svg/icon_more-vertical_outlined.svg new file mode 100644 index 0000000..a97197c --- /dev/null +++ b/frontend/src/assets/svg/icon_more-vertical_outlined.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/frontend/src/assets/svg/icon_more-vertical_outlined_white.svg b/frontend/src/assets/svg/icon_more-vertical_outlined_white.svg new file mode 100644 index 0000000..f6cd13c --- /dev/null +++ b/frontend/src/assets/svg/icon_more-vertical_outlined_white.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/frontend/src/assets/svg/icon_more_outlined.svg b/frontend/src/assets/svg/icon_more_outlined.svg new file mode 100644 index 0000000..f6fec92 --- /dev/null +++ b/frontend/src/assets/svg/icon_more_outlined.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/icon_msg_fill.svg b/frontend/src/assets/svg/icon_msg_fill.svg new file mode 100644 index 0000000..7ce39cc --- /dev/null +++ b/frontend/src/assets/svg/icon_msg_fill.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/src/assets/svg/icon_multi-line_outlined.svg b/frontend/src/assets/svg/icon_multi-line_outlined.svg new file mode 100644 index 0000000..24c4b1c --- /dev/null +++ b/frontend/src/assets/svg/icon_multi-line_outlined.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/frontend/src/assets/svg/icon_new-item_outlined.svg b/frontend/src/assets/svg/icon_new-item_outlined.svg new file mode 100644 index 0000000..3c99da7 --- /dev/null +++ b/frontend/src/assets/svg/icon_new-item_outlined.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/frontend/src/assets/svg/icon_notification_filled.svg b/frontend/src/assets/svg/icon_notification_filled.svg new file mode 100644 index 0000000..8e17a11 --- /dev/null +++ b/frontend/src/assets/svg/icon_notification_filled.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/icon_notification_outlined.svg b/frontend/src/assets/svg/icon_notification_outlined.svg new file mode 100644 index 0000000..236a152 --- /dev/null +++ b/frontend/src/assets/svg/icon_notification_outlined.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/icon_number-calculated_outlined-1.svg b/frontend/src/assets/svg/icon_number-calculated_outlined-1.svg new file mode 100644 index 0000000..0d18a77 --- /dev/null +++ b/frontend/src/assets/svg/icon_number-calculated_outlined-1.svg @@ -0,0 +1,4 @@ + + + + diff --git a/frontend/src/assets/svg/icon_number-calculated_outlined.svg b/frontend/src/assets/svg/icon_number-calculated_outlined.svg new file mode 100644 index 0000000..434fa04 --- /dev/null +++ b/frontend/src/assets/svg/icon_number-calculated_outlined.svg @@ -0,0 +1,4 @@ + + + + diff --git a/frontend/src/assets/svg/icon_number_outlined.svg b/frontend/src/assets/svg/icon_number_outlined.svg new file mode 100644 index 0000000..d6d7e66 --- /dev/null +++ b/frontend/src/assets/svg/icon_number_outlined.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/icon_operation-analysis_outlined.svg b/frontend/src/assets/svg/icon_operation-analysis_outlined.svg new file mode 100644 index 0000000..6a792ff --- /dev/null +++ b/frontend/src/assets/svg/icon_operation-analysis_outlined.svg @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/frontend/src/assets/svg/icon_orde-list_outlined.svg b/frontend/src/assets/svg/icon_orde-list_outlined.svg new file mode 100644 index 0000000..66c8ed5 --- /dev/null +++ b/frontend/src/assets/svg/icon_orde-list_outlined.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/icon_organization_outlined.svg b/frontend/src/assets/svg/icon_organization_outlined.svg new file mode 100644 index 0000000..38e011d --- /dev/null +++ b/frontend/src/assets/svg/icon_organization_outlined.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/icon_params_setting.svg b/frontend/src/assets/svg/icon_params_setting.svg new file mode 100644 index 0000000..3dcde7c --- /dev/null +++ b/frontend/src/assets/svg/icon_params_setting.svg @@ -0,0 +1 @@ + diff --git a/frontend/src/assets/svg/icon_pc_fullscreen.svg b/frontend/src/assets/svg/icon_pc_fullscreen.svg new file mode 100644 index 0000000..8c2bdac --- /dev/null +++ b/frontend/src/assets/svg/icon_pc_fullscreen.svg @@ -0,0 +1 @@ + diff --git a/frontend/src/assets/svg/icon_pc_outlined.svg b/frontend/src/assets/svg/icon_pc_outlined.svg new file mode 100644 index 0000000..b5ce9a2 --- /dev/null +++ b/frontend/src/assets/svg/icon_pc_outlined.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/icon_pc_outlined_copy.svg b/frontend/src/assets/svg/icon_pc_outlined_copy.svg new file mode 100644 index 0000000..b5ce9a2 --- /dev/null +++ b/frontend/src/assets/svg/icon_pc_outlined_copy.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/icon_phone_outlined.svg b/frontend/src/assets/svg/icon_phone_outlined.svg new file mode 100644 index 0000000..92ef5b1 --- /dev/null +++ b/frontend/src/assets/svg/icon_phone_outlined.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/frontend/src/assets/svg/icon_pie_outlined-c.svg b/frontend/src/assets/svg/icon_pie_outlined-c.svg new file mode 100644 index 0000000..898dd65 --- /dev/null +++ b/frontend/src/assets/svg/icon_pie_outlined-c.svg @@ -0,0 +1,4 @@ + + + + diff --git a/frontend/src/assets/svg/icon_play-round_filled.svg b/frontend/src/assets/svg/icon_play-round_filled.svg new file mode 100644 index 0000000..54bcfcc --- /dev/null +++ b/frontend/src/assets/svg/icon_play-round_filled.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/icon_play-round_outlined.svg b/frontend/src/assets/svg/icon_play-round_outlined.svg new file mode 100644 index 0000000..c39cecb --- /dev/null +++ b/frontend/src/assets/svg/icon_play-round_outlined.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/icon_play_round_outlined_white.svg b/frontend/src/assets/svg/icon_play_round_outlined_white.svg new file mode 100644 index 0000000..4ee6d01 --- /dev/null +++ b/frontend/src/assets/svg/icon_play_round_outlined_white.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/icon_plugin_outlined.svg b/frontend/src/assets/svg/icon_plugin_outlined.svg new file mode 100644 index 0000000..6be9844 --- /dev/null +++ b/frontend/src/assets/svg/icon_plugin_outlined.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/icon_preferences_outlined.svg b/frontend/src/assets/svg/icon_preferences_outlined.svg new file mode 100644 index 0000000..4ea7279 --- /dev/null +++ b/frontend/src/assets/svg/icon_preferences_outlined.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/icon_pull-left_outlined.svg b/frontend/src/assets/svg/icon_pull-left_outlined.svg new file mode 100644 index 0000000..848ddb3 --- /dev/null +++ b/frontend/src/assets/svg/icon_pull-left_outlined.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/icon_pull-right_outlined.svg b/frontend/src/assets/svg/icon_pull-right_outlined.svg new file mode 100644 index 0000000..86d2767 --- /dev/null +++ b/frontend/src/assets/svg/icon_pull-right_outlined.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/icon_qr_outlined.svg b/frontend/src/assets/svg/icon_qr_outlined.svg new file mode 100644 index 0000000..8fb87a4 --- /dev/null +++ b/frontend/src/assets/svg/icon_qr_outlined.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/frontend/src/assets/svg/icon_radio_outlined.svg b/frontend/src/assets/svg/icon_radio_outlined.svg new file mode 100644 index 0000000..2206cec --- /dev/null +++ b/frontend/src/assets/svg/icon_radio_outlined.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/frontend/src/assets/svg/icon_redo_outlined.svg b/frontend/src/assets/svg/icon_redo_outlined.svg new file mode 100644 index 0000000..7330b74 --- /dev/null +++ b/frontend/src/assets/svg/icon_redo_outlined.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/icon_refresh_outlined.svg b/frontend/src/assets/svg/icon_refresh_outlined.svg new file mode 100644 index 0000000..5765c40 --- /dev/null +++ b/frontend/src/assets/svg/icon_refresh_outlined.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/icon_rename_outlined.svg b/frontend/src/assets/svg/icon_rename_outlined.svg new file mode 100644 index 0000000..962cc5f --- /dev/null +++ b/frontend/src/assets/svg/icon_rename_outlined.svg @@ -0,0 +1,4 @@ + + + + diff --git a/frontend/src/assets/svg/icon_replace_outlined.svg b/frontend/src/assets/svg/icon_replace_outlined.svg new file mode 100644 index 0000000..446d290 --- /dev/null +++ b/frontend/src/assets/svg/icon_replace_outlined.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/frontend/src/assets/svg/icon_reset_outlined.svg b/frontend/src/assets/svg/icon_reset_outlined.svg new file mode 100644 index 0000000..4610736 --- /dev/null +++ b/frontend/src/assets/svg/icon_reset_outlined.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/icon_resetpassword.svg b/frontend/src/assets/svg/icon_resetpassword.svg new file mode 100644 index 0000000..c8d6bf3 --- /dev/null +++ b/frontend/src/assets/svg/icon_resetpassword.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/icon_right-align_outlined.svg b/frontend/src/assets/svg/icon_right-align_outlined.svg new file mode 100644 index 0000000..d4a5fe7 --- /dev/null +++ b/frontend/src/assets/svg/icon_right-align_outlined.svg @@ -0,0 +1,4 @@ + + + + diff --git a/frontend/src/assets/svg/icon_right-alignment_outlined.svg b/frontend/src/assets/svg/icon_right-alignment_outlined.svg new file mode 100644 index 0000000..6f9357f --- /dev/null +++ b/frontend/src/assets/svg/icon_right-alignment_outlined.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/frontend/src/assets/svg/icon_right-association.svg b/frontend/src/assets/svg/icon_right-association.svg new file mode 100644 index 0000000..f4a0659 --- /dev/null +++ b/frontend/src/assets/svg/icon_right-association.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/frontend/src/assets/svg/icon_right_outlined.svg b/frontend/src/assets/svg/icon_right_outlined.svg new file mode 100644 index 0000000..3ac3478 --- /dev/null +++ b/frontend/src/assets/svg/icon_right_outlined.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/icon_scroll_filled.svg b/frontend/src/assets/svg/icon_scroll_filled.svg new file mode 100644 index 0000000..7169587 --- /dev/null +++ b/frontend/src/assets/svg/icon_scroll_filled.svg @@ -0,0 +1,4 @@ + + + + diff --git a/frontend/src/assets/svg/icon_search-outline_outlined.svg b/frontend/src/assets/svg/icon_search-outline_outlined.svg new file mode 100644 index 0000000..dde44c1 --- /dev/null +++ b/frontend/src/assets/svg/icon_search-outline_outlined.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/icon_search.svg b/frontend/src/assets/svg/icon_search.svg new file mode 100644 index 0000000..fa50c16 --- /dev/null +++ b/frontend/src/assets/svg/icon_search.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/src/assets/svg/icon_security.svg b/frontend/src/assets/svg/icon_security.svg new file mode 100644 index 0000000..9e2635b --- /dev/null +++ b/frontend/src/assets/svg/icon_security.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/src/assets/svg/icon_share-label_filled.svg b/frontend/src/assets/svg/icon_share-label_filled.svg new file mode 100644 index 0000000..db0cb09 --- /dev/null +++ b/frontend/src/assets/svg/icon_share-label_filled.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/icon_share-label_outlined.svg b/frontend/src/assets/svg/icon_share-label_outlined.svg new file mode 100644 index 0000000..9538478 --- /dev/null +++ b/frontend/src/assets/svg/icon_share-label_outlined.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/icon_side-expand_outlined.svg b/frontend/src/assets/svg/icon_side-expand_outlined.svg new file mode 100644 index 0000000..8278cbb --- /dev/null +++ b/frontend/src/assets/svg/icon_side-expand_outlined.svg @@ -0,0 +1,4 @@ + + + + diff --git a/frontend/src/assets/svg/icon_side-fold_outlined.svg b/frontend/src/assets/svg/icon_side-fold_outlined.svg new file mode 100644 index 0000000..5a46a35 --- /dev/null +++ b/frontend/src/assets/svg/icon_side-fold_outlined.svg @@ -0,0 +1,4 @@ + + + + diff --git a/frontend/src/assets/svg/icon_single-line_outlined.svg b/frontend/src/assets/svg/icon_single-line_outlined.svg new file mode 100644 index 0000000..5cd8e7b --- /dev/null +++ b/frontend/src/assets/svg/icon_single-line_outlined.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/frontend/src/assets/svg/icon_sort-a-to-z_outlined.svg b/frontend/src/assets/svg/icon_sort-a-to-z_outlined.svg new file mode 100644 index 0000000..332c076 --- /dev/null +++ b/frontend/src/assets/svg/icon_sort-a-to-z_outlined.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/frontend/src/assets/svg/icon_sort-z-to-a_outlined.svg b/frontend/src/assets/svg/icon_sort-z-to-a_outlined.svg new file mode 100644 index 0000000..960d320 --- /dev/null +++ b/frontend/src/assets/svg/icon_sort-z-to-a_outlined.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/frontend/src/assets/svg/icon_sort_outlined.svg b/frontend/src/assets/svg/icon_sort_outlined.svg new file mode 100644 index 0000000..5063832 --- /dev/null +++ b/frontend/src/assets/svg/icon_sort_outlined.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/frontend/src/assets/svg/icon_sort_priority.svg b/frontend/src/assets/svg/icon_sort_priority.svg new file mode 100644 index 0000000..04ac42d --- /dev/null +++ b/frontend/src/assets/svg/icon_sort_priority.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/src/assets/svg/icon_sql.svg b/frontend/src/assets/svg/icon_sql.svg new file mode 100644 index 0000000..38e658c --- /dev/null +++ b/frontend/src/assets/svg/icon_sql.svg @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + diff --git a/frontend/src/assets/svg/icon_sql_outlined.svg b/frontend/src/assets/svg/icon_sql_outlined.svg new file mode 100644 index 0000000..c873600 --- /dev/null +++ b/frontend/src/assets/svg/icon_sql_outlined.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/frontend/src/assets/svg/icon_sql_outlined_1.svg b/frontend/src/assets/svg/icon_sql_outlined_1.svg new file mode 100644 index 0000000..f3cda84 --- /dev/null +++ b/frontend/src/assets/svg/icon_sql_outlined_1.svg @@ -0,0 +1,13 @@ + + + + + + + + + + diff --git a/frontend/src/assets/svg/icon_stretch_outlined.svg b/frontend/src/assets/svg/icon_stretch_outlined.svg new file mode 100644 index 0000000..416c92c --- /dev/null +++ b/frontend/src/assets/svg/icon_stretch_outlined.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/icon_style-set_outlined.svg b/frontend/src/assets/svg/icon_style-set_outlined.svg new file mode 100644 index 0000000..83d7a73 --- /dev/null +++ b/frontend/src/assets/svg/icon_style-set_outlined.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/icon_succeed_colorful.svg b/frontend/src/assets/svg/icon_succeed_colorful.svg new file mode 100644 index 0000000..b8f976a --- /dev/null +++ b/frontend/src/assets/svg/icon_succeed_colorful.svg @@ -0,0 +1,4 @@ + + + + diff --git a/frontend/src/assets/svg/icon_succeed_filled.svg b/frontend/src/assets/svg/icon_succeed_filled.svg new file mode 100644 index 0000000..6945b1b --- /dev/null +++ b/frontend/src/assets/svg/icon_succeed_filled.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/frontend/src/assets/svg/icon_switch_outlined.svg b/frontend/src/assets/svg/icon_switch_outlined.svg new file mode 100644 index 0000000..80ae0f6 --- /dev/null +++ b/frontend/src/assets/svg/icon_switch_outlined.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/frontend/src/assets/svg/icon_sync-play-round_filled.svg b/frontend/src/assets/svg/icon_sync-play-round_filled.svg new file mode 100644 index 0000000..6f81e8f --- /dev/null +++ b/frontend/src/assets/svg/icon_sync-play-round_filled.svg @@ -0,0 +1,4 @@ + + + + diff --git a/frontend/src/assets/svg/icon_sync-play-round_outlined.svg b/frontend/src/assets/svg/icon_sync-play-round_outlined.svg new file mode 100644 index 0000000..0a4d202 --- /dev/null +++ b/frontend/src/assets/svg/icon_sync-play-round_outlined.svg @@ -0,0 +1,4 @@ + + + + diff --git a/frontend/src/assets/svg/icon_sync_close_log_details.svg b/frontend/src/assets/svg/icon_sync_close_log_details.svg new file mode 100644 index 0000000..7c0dc4c --- /dev/null +++ b/frontend/src/assets/svg/icon_sync_close_log_details.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/icon_sync_datasource.svg b/frontend/src/assets/svg/icon_sync_datasource.svg new file mode 100644 index 0000000..1e3fc9d --- /dev/null +++ b/frontend/src/assets/svg/icon_sync_datasource.svg @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + diff --git a/frontend/src/assets/svg/icon_sync_free.svg b/frontend/src/assets/svg/icon_sync_free.svg new file mode 100644 index 0000000..9e36d03 --- /dev/null +++ b/frontend/src/assets/svg/icon_sync_free.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/icon_sync_log_number.svg b/frontend/src/assets/svg/icon_sync_log_number.svg new file mode 100644 index 0000000..49869e0 --- /dev/null +++ b/frontend/src/assets/svg/icon_sync_log_number.svg @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + diff --git a/frontend/src/assets/svg/icon_sync_logs_outlined.svg b/frontend/src/assets/svg/icon_sync_logs_outlined.svg new file mode 100644 index 0000000..6dd112e --- /dev/null +++ b/frontend/src/assets/svg/icon_sync_logs_outlined.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/icon_sync_progress.svg b/frontend/src/assets/svg/icon_sync_progress.svg new file mode 100644 index 0000000..d8ddb73 --- /dev/null +++ b/frontend/src/assets/svg/icon_sync_progress.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/frontend/src/assets/svg/icon_sync_target_to_datasource.svg b/frontend/src/assets/svg/icon_sync_target_to_datasource.svg new file mode 100644 index 0000000..bc4d526 --- /dev/null +++ b/frontend/src/assets/svg/icon_sync_target_to_datasource.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/icon_sync_task_number.svg b/frontend/src/assets/svg/icon_sync_task_number.svg new file mode 100644 index 0000000..bce4a1e --- /dev/null +++ b/frontend/src/assets/svg/icon_sync_task_number.svg @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + diff --git a/frontend/src/assets/svg/icon_take-action_outlined.svg b/frontend/src/assets/svg/icon_take-action_outlined.svg new file mode 100644 index 0000000..e1891fc --- /dev/null +++ b/frontend/src/assets/svg/icon_take-action_outlined.svg @@ -0,0 +1,4 @@ + + + + diff --git a/frontend/src/assets/svg/icon_team-add_outlined.svg b/frontend/src/assets/svg/icon_team-add_outlined.svg new file mode 100644 index 0000000..c85fe1e --- /dev/null +++ b/frontend/src/assets/svg/icon_team-add_outlined.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/frontend/src/assets/svg/icon_template.svg b/frontend/src/assets/svg/icon_template.svg new file mode 100644 index 0000000..639de0a --- /dev/null +++ b/frontend/src/assets/svg/icon_template.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/icon_template_colorful.svg b/frontend/src/assets/svg/icon_template_colorful.svg new file mode 100644 index 0000000..789b3a0 --- /dev/null +++ b/frontend/src/assets/svg/icon_template_colorful.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/frontend/src/assets/svg/icon_template_outlined.svg b/frontend/src/assets/svg/icon_template_outlined.svg new file mode 100644 index 0000000..8320bf8 --- /dev/null +++ b/frontend/src/assets/svg/icon_template_outlined.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/icon_text-box_outlined.svg b/frontend/src/assets/svg/icon_text-box_outlined.svg new file mode 100644 index 0000000..1b23b1c --- /dev/null +++ b/frontend/src/assets/svg/icon_text-box_outlined.svg @@ -0,0 +1,4 @@ + + + + diff --git a/frontend/src/assets/svg/icon_text-calculated_outlined-1.svg b/frontend/src/assets/svg/icon_text-calculated_outlined-1.svg new file mode 100644 index 0000000..7b4227e --- /dev/null +++ b/frontend/src/assets/svg/icon_text-calculated_outlined-1.svg @@ -0,0 +1,4 @@ + + + + diff --git a/frontend/src/assets/svg/icon_text-calculated_outlined.svg b/frontend/src/assets/svg/icon_text-calculated_outlined.svg new file mode 100644 index 0000000..9019c36 --- /dev/null +++ b/frontend/src/assets/svg/icon_text-calculated_outlined.svg @@ -0,0 +1,4 @@ + + + + diff --git a/frontend/src/assets/svg/icon_text_outlined.svg b/frontend/src/assets/svg/icon_text_outlined.svg new file mode 100644 index 0000000..13047e6 --- /dev/null +++ b/frontend/src/assets/svg/icon_text_outlined.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/icon_time_outlined.svg b/frontend/src/assets/svg/icon_time_outlined.svg new file mode 100644 index 0000000..a5d09a9 --- /dev/null +++ b/frontend/src/assets/svg/icon_time_outlined.svg @@ -0,0 +1,4 @@ + + + + diff --git a/frontend/src/assets/svg/icon_title-left-align_outlined.svg b/frontend/src/assets/svg/icon_title-left-align_outlined.svg new file mode 100644 index 0000000..27f7c7f --- /dev/null +++ b/frontend/src/assets/svg/icon_title-left-align_outlined.svg @@ -0,0 +1,4 @@ + + + + diff --git a/frontend/src/assets/svg/icon_title-top-align_outlined.svg b/frontend/src/assets/svg/icon_title-top-align_outlined.svg new file mode 100644 index 0000000..5d3b042 --- /dev/null +++ b/frontend/src/assets/svg/icon_title-top-align_outlined.svg @@ -0,0 +1,4 @@ + + + + diff --git a/frontend/src/assets/svg/icon_todo_outlined.svg b/frontend/src/assets/svg/icon_todo_outlined.svg new file mode 100644 index 0000000..633b9b1 --- /dev/null +++ b/frontend/src/assets/svg/icon_todo_outlined.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/icon_top-align_outlined.svg b/frontend/src/assets/svg/icon_top-align_outlined.svg new file mode 100644 index 0000000..695c4e9 --- /dev/null +++ b/frontend/src/assets/svg/icon_top-align_outlined.svg @@ -0,0 +1,4 @@ + + + + diff --git a/frontend/src/assets/svg/icon_undo_outlined.svg b/frontend/src/assets/svg/icon_undo_outlined.svg new file mode 100644 index 0000000..1154ecd --- /dev/null +++ b/frontend/src/assets/svg/icon_undo_outlined.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/icon_up-left_outlined.svg b/frontend/src/assets/svg/icon_up-left_outlined.svg new file mode 100644 index 0000000..766e655 --- /dev/null +++ b/frontend/src/assets/svg/icon_up-left_outlined.svg @@ -0,0 +1,4 @@ + + + + diff --git a/frontend/src/assets/svg/icon_upload_outlined.svg b/frontend/src/assets/svg/icon_upload_outlined.svg new file mode 100644 index 0000000..c13777d --- /dev/null +++ b/frontend/src/assets/svg/icon_upload_outlined.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/icon_url_outlined.svg b/frontend/src/assets/svg/icon_url_outlined.svg new file mode 100644 index 0000000..4d6d540 --- /dev/null +++ b/frontend/src/assets/svg/icon_url_outlined.svg @@ -0,0 +1 @@ + diff --git a/frontend/src/assets/svg/icon_vertical-align_outlined.svg b/frontend/src/assets/svg/icon_vertical-align_outlined.svg new file mode 100644 index 0000000..8bd7b60 --- /dev/null +++ b/frontend/src/assets/svg/icon_vertical-align_outlined.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/frontend/src/assets/svg/icon_view-list_outlined.svg b/frontend/src/assets/svg/icon_view-list_outlined.svg new file mode 100644 index 0000000..406d5a9 --- /dev/null +++ b/frontend/src/assets/svg/icon_view-list_outlined.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/icon_viewinchat_outlined.svg b/frontend/src/assets/svg/icon_viewinchat_outlined.svg new file mode 100644 index 0000000..3d76192 --- /dev/null +++ b/frontend/src/assets/svg/icon_viewinchat_outlined.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/icon_visible_outlined.svg b/frontend/src/assets/svg/icon_visible_outlined.svg new file mode 100644 index 0000000..47b8391 --- /dev/null +++ b/frontend/src/assets/svg/icon_visible_outlined.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/icon_warning_colorful.svg b/frontend/src/assets/svg/icon_warning_colorful.svg new file mode 100644 index 0000000..dae340c --- /dev/null +++ b/frontend/src/assets/svg/icon_warning_colorful.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/frontend/src/assets/svg/icon_warning_colorful_red.svg b/frontend/src/assets/svg/icon_warning_colorful_red.svg new file mode 100644 index 0000000..a0ffc79 --- /dev/null +++ b/frontend/src/assets/svg/icon_warning_colorful_red.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/frontend/src/assets/svg/icon_warning_filled.svg b/frontend/src/assets/svg/icon_warning_filled.svg new file mode 100644 index 0000000..045912f --- /dev/null +++ b/frontend/src/assets/svg/icon_warning_filled.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/frontend/src/assets/svg/icon_webhook.svg b/frontend/src/assets/svg/icon_webhook.svg new file mode 100644 index 0000000..2a614b6 --- /dev/null +++ b/frontend/src/assets/svg/icon_webhook.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/icon_yes_outlined.svg b/frontend/src/assets/svg/icon_yes_outlined.svg new file mode 100644 index 0000000..6de4ef4 --- /dev/null +++ b/frontend/src/assets/svg/icon_yes_outlined.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/iconfont.svg b/frontend/src/assets/svg/iconfont.svg new file mode 100644 index 0000000..261f9cb --- /dev/null +++ b/frontend/src/assets/svg/iconfont.svg @@ -0,0 +1,71 @@ + + + + + +Created by iconfont + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/frontend/src/assets/svg/impala-ds.svg b/frontend/src/assets/svg/impala-ds.svg new file mode 100644 index 0000000..cb1290f --- /dev/null +++ b/frontend/src/assets/svg/impala-ds.svg @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + + diff --git a/frontend/src/assets/svg/indicator-dark.svg b/frontend/src/assets/svg/indicator-dark.svg new file mode 100644 index 0000000..71ec539 --- /dev/null +++ b/frontend/src/assets/svg/indicator-dark.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/frontend/src/assets/svg/indicator-origin.svg b/frontend/src/assets/svg/indicator-origin.svg new file mode 100644 index 0000000..f37dd9f --- /dev/null +++ b/frontend/src/assets/svg/indicator-origin.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/frontend/src/assets/svg/indicator.svg b/frontend/src/assets/svg/indicator.svg new file mode 100644 index 0000000..71ec539 --- /dev/null +++ b/frontend/src/assets/svg/indicator.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/frontend/src/assets/svg/inner-join.svg b/frontend/src/assets/svg/inner-join.svg new file mode 100644 index 0000000..8b689f4 --- /dev/null +++ b/frontend/src/assets/svg/inner-join.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/frontend/src/assets/svg/international.svg b/frontend/src/assets/svg/international.svg new file mode 100644 index 0000000..e9b56ee --- /dev/null +++ b/frontend/src/assets/svg/international.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/src/assets/svg/join-join.svg b/frontend/src/assets/svg/join-join.svg new file mode 100644 index 0000000..da22305 --- /dev/null +++ b/frontend/src/assets/svg/join-join.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/label.svg b/frontend/src/assets/svg/label.svg new file mode 100644 index 0000000..227ed39 --- /dev/null +++ b/frontend/src/assets/svg/label.svg @@ -0,0 +1,2 @@ + + diff --git a/frontend/src/assets/svg/language.svg b/frontend/src/assets/svg/language.svg new file mode 100644 index 0000000..143b3a6 --- /dev/null +++ b/frontend/src/assets/svg/language.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/src/assets/svg/left-join.svg b/frontend/src/assets/svg/left-join.svg new file mode 100644 index 0000000..b4ecde3 --- /dev/null +++ b/frontend/src/assets/svg/left-join.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/frontend/src/assets/svg/line-dark.svg b/frontend/src/assets/svg/line-dark.svg new file mode 100644 index 0000000..c3819a1 --- /dev/null +++ b/frontend/src/assets/svg/line-dark.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/frontend/src/assets/svg/line-origin.svg b/frontend/src/assets/svg/line-origin.svg new file mode 100644 index 0000000..43f590b --- /dev/null +++ b/frontend/src/assets/svg/line-origin.svg @@ -0,0 +1,4 @@ + + + + diff --git a/frontend/src/assets/svg/line.svg b/frontend/src/assets/svg/line.svg new file mode 100644 index 0000000..f2b52d5 --- /dev/null +++ b/frontend/src/assets/svg/line.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/frontend/src/assets/svg/link-back.svg b/frontend/src/assets/svg/link-back.svg new file mode 100644 index 0000000..88339b6 --- /dev/null +++ b/frontend/src/assets/svg/link-back.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/src/assets/svg/link-down.svg b/frontend/src/assets/svg/link-down.svg new file mode 100644 index 0000000..f0aaca2 --- /dev/null +++ b/frontend/src/assets/svg/link-down.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/src/assets/svg/link.svg b/frontend/src/assets/svg/link.svg new file mode 100644 index 0000000..48197ba --- /dev/null +++ b/frontend/src/assets/svg/link.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/src/assets/svg/liquid-dark.svg b/frontend/src/assets/svg/liquid-dark.svg new file mode 100644 index 0000000..694cb16 --- /dev/null +++ b/frontend/src/assets/svg/liquid-dark.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/frontend/src/assets/svg/liquid-origin.svg b/frontend/src/assets/svg/liquid-origin.svg new file mode 100644 index 0000000..396cb7a --- /dev/null +++ b/frontend/src/assets/svg/liquid-origin.svg @@ -0,0 +1,4 @@ + + + + diff --git a/frontend/src/assets/svg/liquid.svg b/frontend/src/assets/svg/liquid.svg new file mode 100644 index 0000000..2b99d91 --- /dev/null +++ b/frontend/src/assets/svg/liquid.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/frontend/src/assets/svg/lock_closed.svg b/frontend/src/assets/svg/lock_closed.svg new file mode 100644 index 0000000..cea933c --- /dev/null +++ b/frontend/src/assets/svg/lock_closed.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/lock_closed_switch.svg b/frontend/src/assets/svg/lock_closed_switch.svg new file mode 100644 index 0000000..ff11256 --- /dev/null +++ b/frontend/src/assets/svg/lock_closed_switch.svg @@ -0,0 +1 @@ + diff --git a/frontend/src/assets/svg/lock_open.svg b/frontend/src/assets/svg/lock_open.svg new file mode 100644 index 0000000..331563a --- /dev/null +++ b/frontend/src/assets/svg/lock_open.svg @@ -0,0 +1,4 @@ + + + + diff --git a/frontend/src/assets/svg/lock_open_back.svg b/frontend/src/assets/svg/lock_open_back.svg new file mode 100644 index 0000000..a531f6c --- /dev/null +++ b/frontend/src/assets/svg/lock_open_back.svg @@ -0,0 +1 @@ + diff --git a/frontend/src/assets/svg/lock_other_open.svg b/frontend/src/assets/svg/lock_other_open.svg new file mode 100644 index 0000000..0645e22 --- /dev/null +++ b/frontend/src/assets/svg/lock_other_open.svg @@ -0,0 +1,4 @@ + + + + diff --git a/frontend/src/assets/svg/log.svg b/frontend/src/assets/svg/log.svg new file mode 100644 index 0000000..2c1a670 --- /dev/null +++ b/frontend/src/assets/svg/log.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/logo.svg b/frontend/src/assets/svg/logo.svg new file mode 100644 index 0000000..366fe68 --- /dev/null +++ b/frontend/src/assets/svg/logo.svg @@ -0,0 +1,20 @@ + + + + background + + + + Layer 1 + + GIS-BI开发平台 + + \ No newline at end of file diff --git a/frontend/src/assets/svg/logo1.svg b/frontend/src/assets/svg/logo1.svg new file mode 100644 index 0000000..6acaee2 --- /dev/null +++ b/frontend/src/assets/svg/logo1.svg @@ -0,0 +1,21 @@ + + + diff --git a/frontend/src/assets/svg/logo_cas.svg b/frontend/src/assets/svg/logo_cas.svg new file mode 100644 index 0000000..7224246 --- /dev/null +++ b/frontend/src/assets/svg/logo_cas.svg @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + diff --git a/frontend/src/assets/svg/logo_dingtalk.svg b/frontend/src/assets/svg/logo_dingtalk.svg new file mode 100644 index 0000000..c392456 --- /dev/null +++ b/frontend/src/assets/svg/logo_dingtalk.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/frontend/src/assets/svg/logo_lark.svg b/frontend/src/assets/svg/logo_lark.svg new file mode 100644 index 0000000..0eaf8df --- /dev/null +++ b/frontend/src/assets/svg/logo_lark.svg @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + + diff --git a/frontend/src/assets/svg/logo_ldap.svg b/frontend/src/assets/svg/logo_ldap.svg new file mode 100644 index 0000000..57deedf --- /dev/null +++ b/frontend/src/assets/svg/logo_ldap.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/frontend/src/assets/svg/logo_oauth.svg b/frontend/src/assets/svg/logo_oauth.svg new file mode 100644 index 0000000..89ef68c --- /dev/null +++ b/frontend/src/assets/svg/logo_oauth.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/logo_wechat-work.svg b/frontend/src/assets/svg/logo_wechat-work.svg new file mode 100644 index 0000000..99ac1d3 --- /dev/null +++ b/frontend/src/assets/svg/logo_wechat-work.svg @@ -0,0 +1,64 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/frontend/src/assets/svg/map-dark.svg b/frontend/src/assets/svg/map-dark.svg new file mode 100644 index 0000000..cc136f3 --- /dev/null +++ b/frontend/src/assets/svg/map-dark.svg @@ -0,0 +1 @@ + diff --git a/frontend/src/assets/svg/map-origin.svg b/frontend/src/assets/svg/map-origin.svg new file mode 100644 index 0000000..3c37937 --- /dev/null +++ b/frontend/src/assets/svg/map-origin.svg @@ -0,0 +1 @@ + diff --git a/frontend/src/assets/svg/map.svg b/frontend/src/assets/svg/map.svg new file mode 100644 index 0000000..34578f5 --- /dev/null +++ b/frontend/src/assets/svg/map.svg @@ -0,0 +1 @@ + diff --git a/frontend/src/assets/svg/map_mini.svg b/frontend/src/assets/svg/map_mini.svg new file mode 100644 index 0000000..44ccd35 --- /dev/null +++ b/frontend/src/assets/svg/map_mini.svg @@ -0,0 +1 @@ + diff --git a/frontend/src/assets/svg/map_old.svg b/frontend/src/assets/svg/map_old.svg new file mode 100644 index 0000000..721251a --- /dev/null +++ b/frontend/src/assets/svg/map_old.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/src/assets/svg/mariadb-ds.svg b/frontend/src/assets/svg/mariadb-ds.svg new file mode 100644 index 0000000..ce664d6 --- /dev/null +++ b/frontend/src/assets/svg/mariadb-ds.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/frontend/src/assets/svg/market-expand.svg b/frontend/src/assets/svg/market-expand.svg new file mode 100644 index 0000000..278a7ef --- /dev/null +++ b/frontend/src/assets/svg/market-expand.svg @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/frontend/src/assets/svg/market-retract.svg b/frontend/src/assets/svg/market-retract.svg new file mode 100644 index 0000000..64fd486 --- /dev/null +++ b/frontend/src/assets/svg/market-retract.svg @@ -0,0 +1,19 @@ + + + + + + + + + + + + + + + + + + + diff --git a/frontend/src/assets/svg/menu.svg b/frontend/src/assets/svg/menu.svg new file mode 100644 index 0000000..e4360a0 --- /dev/null +++ b/frontend/src/assets/svg/menu.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/src/assets/svg/menuconfig_treeadd_white.svg b/frontend/src/assets/svg/menuconfig_treeadd_white.svg new file mode 100644 index 0000000..bd5e1d9 --- /dev/null +++ b/frontend/src/assets/svg/menuconfig_treeadd_white.svg @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/frontend/src/assets/svg/mobile-checkbox.svg b/frontend/src/assets/svg/mobile-checkbox.svg new file mode 100644 index 0000000..2bee03e --- /dev/null +++ b/frontend/src/assets/svg/mobile-checkbox.svg @@ -0,0 +1,4 @@ + + + + diff --git a/frontend/src/assets/svg/mobile/icon_dashboard_filled.svg b/frontend/src/assets/svg/mobile/icon_dashboard_filled.svg new file mode 100644 index 0000000..01d33d9 --- /dev/null +++ b/frontend/src/assets/svg/mobile/icon_dashboard_filled.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/mobile/icon_dashboard_outlined.svg b/frontend/src/assets/svg/mobile/icon_dashboard_outlined.svg new file mode 100644 index 0000000..0c87145 --- /dev/null +++ b/frontend/src/assets/svg/mobile/icon_dashboard_outlined.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/mobile/icon_home_filled.svg b/frontend/src/assets/svg/mobile/icon_home_filled.svg new file mode 100644 index 0000000..cc62af8 --- /dev/null +++ b/frontend/src/assets/svg/mobile/icon_home_filled.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/mobile/icon_home_outlined.svg b/frontend/src/assets/svg/mobile/icon_home_outlined.svg new file mode 100644 index 0000000..efda93d --- /dev/null +++ b/frontend/src/assets/svg/mobile/icon_home_outlined.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/mobile/icon_member_filled.svg b/frontend/src/assets/svg/mobile/icon_member_filled.svg new file mode 100644 index 0000000..4563c32 --- /dev/null +++ b/frontend/src/assets/svg/mobile/icon_member_filled.svg @@ -0,0 +1,4 @@ + + + + diff --git a/frontend/src/assets/svg/mobile/icon_member_outlined.svg b/frontend/src/assets/svg/mobile/icon_member_outlined.svg new file mode 100644 index 0000000..393e75d --- /dev/null +++ b/frontend/src/assets/svg/mobile/icon_member_outlined.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/mongo-ds.svg b/frontend/src/assets/svg/mongo-ds.svg new file mode 100644 index 0000000..d68949b --- /dev/null +++ b/frontend/src/assets/svg/mongo-ds.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/frontend/src/assets/svg/more_v.svg b/frontend/src/assets/svg/more_v.svg new file mode 100644 index 0000000..68c0c57 --- /dev/null +++ b/frontend/src/assets/svg/more_v.svg @@ -0,0 +1 @@ + diff --git a/frontend/src/assets/svg/move.svg b/frontend/src/assets/svg/move.svg new file mode 100644 index 0000000..3135c7d --- /dev/null +++ b/frontend/src/assets/svg/move.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/src/assets/svg/msg-fill.svg b/frontend/src/assets/svg/msg-fill.svg new file mode 100644 index 0000000..7ce39cc --- /dev/null +++ b/frontend/src/assets/svg/msg-fill.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/src/assets/svg/msg-notice.svg b/frontend/src/assets/svg/msg-notice.svg new file mode 100644 index 0000000..d13c585 --- /dev/null +++ b/frontend/src/assets/svg/msg-notice.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/src/assets/svg/msg-setting.svg b/frontend/src/assets/svg/msg-setting.svg new file mode 100644 index 0000000..4dca3b8 --- /dev/null +++ b/frontend/src/assets/svg/msg-setting.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/src/assets/svg/mysql-ds.svg b/frontend/src/assets/svg/mysql-ds.svg new file mode 100644 index 0000000..3fe231d --- /dev/null +++ b/frontend/src/assets/svg/mysql-ds.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/mysql-frame.svg b/frontend/src/assets/svg/mysql-frame.svg new file mode 100644 index 0000000..af23e7a --- /dev/null +++ b/frontend/src/assets/svg/mysql-frame.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/frontend/src/assets/svg/nested.svg b/frontend/src/assets/svg/nested.svg new file mode 100644 index 0000000..06713a8 --- /dev/null +++ b/frontend/src/assets/svg/nested.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/src/assets/svg/no-join.svg b/frontend/src/assets/svg/no-join.svg new file mode 100644 index 0000000..ff09469 --- /dev/null +++ b/frontend/src/assets/svg/no-join.svg @@ -0,0 +1 @@ + diff --git a/frontend/src/assets/svg/no_result.svg b/frontend/src/assets/svg/no_result.svg new file mode 100644 index 0000000..2621d6b --- /dev/null +++ b/frontend/src/assets/svg/no_result.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/frontend/src/assets/svg/non-existent.svg b/frontend/src/assets/svg/non-existent.svg new file mode 100644 index 0000000..db9a67d --- /dev/null +++ b/frontend/src/assets/svg/non-existent.svg @@ -0,0 +1,2 @@ + \ No newline at end of file diff --git a/frontend/src/assets/svg/none_select.svg b/frontend/src/assets/svg/none_select.svg new file mode 100644 index 0000000..ebafc75 --- /dev/null +++ b/frontend/src/assets/svg/none_select.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/frontend/src/assets/svg/notification.svg b/frontend/src/assets/svg/notification.svg new file mode 100644 index 0000000..4f7b116 --- /dev/null +++ b/frontend/src/assets/svg/notification.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/src/assets/svg/oracle-ds.svg b/frontend/src/assets/svg/oracle-ds.svg new file mode 100644 index 0000000..04efc9e --- /dev/null +++ b/frontend/src/assets/svg/oracle-ds.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/frontend/src/assets/svg/org.svg b/frontend/src/assets/svg/org.svg new file mode 100644 index 0000000..0930bc5 --- /dev/null +++ b/frontend/src/assets/svg/org.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/other_material.svg b/frontend/src/assets/svg/other_material.svg new file mode 100644 index 0000000..8298dfa --- /dev/null +++ b/frontend/src/assets/svg/other_material.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/src/assets/svg/other_material_board.svg b/frontend/src/assets/svg/other_material_board.svg new file mode 100644 index 0000000..9ef3dc3 --- /dev/null +++ b/frontend/src/assets/svg/other_material_board.svg @@ -0,0 +1,4 @@ + + + + diff --git a/frontend/src/assets/svg/other_material_icon.svg b/frontend/src/assets/svg/other_material_icon.svg new file mode 100644 index 0000000..31dba89 --- /dev/null +++ b/frontend/src/assets/svg/other_material_icon.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/other_media.svg b/frontend/src/assets/svg/other_media.svg new file mode 100644 index 0000000..66eb002 --- /dev/null +++ b/frontend/src/assets/svg/other_media.svg @@ -0,0 +1 @@ + diff --git a/frontend/src/assets/svg/other_setting.svg b/frontend/src/assets/svg/other_setting.svg new file mode 100644 index 0000000..be94938 --- /dev/null +++ b/frontend/src/assets/svg/other_setting.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/src/assets/svg/other_text.svg b/frontend/src/assets/svg/other_text.svg new file mode 100644 index 0000000..408d02c --- /dev/null +++ b/frontend/src/assets/svg/other_text.svg @@ -0,0 +1 @@ + diff --git a/frontend/src/assets/svg/outer-params-filter.svg b/frontend/src/assets/svg/outer-params-filter.svg new file mode 100644 index 0000000..81d9a23 --- /dev/null +++ b/frontend/src/assets/svg/outer-params-filter.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/page-line.svg b/frontend/src/assets/svg/page-line.svg new file mode 100644 index 0000000..224b1e0 --- /dev/null +++ b/frontend/src/assets/svg/page-line.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/panel-mobile-publish.svg b/frontend/src/assets/svg/panel-mobile-publish.svg new file mode 100644 index 0000000..99ce7a4 --- /dev/null +++ b/frontend/src/assets/svg/panel-mobile-publish.svg @@ -0,0 +1,18 @@ + + + + + + + + Layer 1 + + + + + + + + + + \ No newline at end of file diff --git a/frontend/src/assets/svg/panel-mobile-unpublished-back.svg b/frontend/src/assets/svg/panel-mobile-unpublished-back.svg new file mode 100644 index 0000000..919694e --- /dev/null +++ b/frontend/src/assets/svg/panel-mobile-unpublished-back.svg @@ -0,0 +1,19 @@ + + + + + + + + Layer 1 + + + + + + + + + + + \ No newline at end of file diff --git a/frontend/src/assets/svg/panel-mobile-unpublished.svg b/frontend/src/assets/svg/panel-mobile-unpublished.svg new file mode 100644 index 0000000..0f89934 --- /dev/null +++ b/frontend/src/assets/svg/panel-mobile-unpublished.svg @@ -0,0 +1,18 @@ + + + + + + + + Layer 1 + + + + + + + + + + diff --git a/frontend/src/assets/svg/panel-publish.svg b/frontend/src/assets/svg/panel-publish.svg new file mode 100644 index 0000000..4153757 --- /dev/null +++ b/frontend/src/assets/svg/panel-publish.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/src/assets/svg/panel-unpublished-back.svg b/frontend/src/assets/svg/panel-unpublished-back.svg new file mode 100644 index 0000000..ac5887e --- /dev/null +++ b/frontend/src/assets/svg/panel-unpublished-back.svg @@ -0,0 +1,10 @@ + + + Layer 1 + + + + + + + \ No newline at end of file diff --git a/frontend/src/assets/svg/panel-unpublished.svg b/frontend/src/assets/svg/panel-unpublished.svg new file mode 100644 index 0000000..a7dae86 --- /dev/null +++ b/frontend/src/assets/svg/panel-unpublished.svg @@ -0,0 +1,9 @@ + + + + Layer 1 + + + + + diff --git a/frontend/src/assets/svg/panel.svg b/frontend/src/assets/svg/panel.svg new file mode 100644 index 0000000..4153757 --- /dev/null +++ b/frontend/src/assets/svg/panel.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/src/assets/svg/people.svg b/frontend/src/assets/svg/people.svg new file mode 100644 index 0000000..26d9c99 --- /dev/null +++ b/frontend/src/assets/svg/people.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/peoples.svg b/frontend/src/assets/svg/peoples.svg new file mode 100644 index 0000000..3a899eb --- /dev/null +++ b/frontend/src/assets/svg/peoples.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/percentage-bar-stack-dark.svg b/frontend/src/assets/svg/percentage-bar-stack-dark.svg new file mode 100644 index 0000000..d8065d8 --- /dev/null +++ b/frontend/src/assets/svg/percentage-bar-stack-dark.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/frontend/src/assets/svg/percentage-bar-stack-horizontal-dark.svg b/frontend/src/assets/svg/percentage-bar-stack-horizontal-dark.svg new file mode 100644 index 0000000..636c610 --- /dev/null +++ b/frontend/src/assets/svg/percentage-bar-stack-horizontal-dark.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/frontend/src/assets/svg/percentage-bar-stack-horizontal-origin.svg b/frontend/src/assets/svg/percentage-bar-stack-horizontal-origin.svg new file mode 100644 index 0000000..e8af2b9 --- /dev/null +++ b/frontend/src/assets/svg/percentage-bar-stack-horizontal-origin.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/percentage-bar-stack-horizontal.svg b/frontend/src/assets/svg/percentage-bar-stack-horizontal.svg new file mode 100644 index 0000000..4c88a91 --- /dev/null +++ b/frontend/src/assets/svg/percentage-bar-stack-horizontal.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/frontend/src/assets/svg/percentage-bar-stack-origin.svg b/frontend/src/assets/svg/percentage-bar-stack-origin.svg new file mode 100644 index 0000000..21e1af0 --- /dev/null +++ b/frontend/src/assets/svg/percentage-bar-stack-origin.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/percentage-bar-stack.svg b/frontend/src/assets/svg/percentage-bar-stack.svg new file mode 100644 index 0000000..0e3d8df --- /dev/null +++ b/frontend/src/assets/svg/percentage-bar-stack.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/frontend/src/assets/svg/perission_role_blue.svg b/frontend/src/assets/svg/perission_role_blue.svg new file mode 100644 index 0000000..3834a19 --- /dev/null +++ b/frontend/src/assets/svg/perission_role_blue.svg @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/frontend/src/assets/svg/permission_del_blue.svg b/frontend/src/assets/svg/permission_del_blue.svg new file mode 100644 index 0000000..4193ad9 --- /dev/null +++ b/frontend/src/assets/svg/permission_del_blue.svg @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/frontend/src/assets/svg/permission_del_white.svg b/frontend/src/assets/svg/permission_del_white.svg new file mode 100644 index 0000000..ff46ddd --- /dev/null +++ b/frontend/src/assets/svg/permission_del_white.svg @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/frontend/src/assets/svg/permission_edit_blue.svg b/frontend/src/assets/svg/permission_edit_blue.svg new file mode 100644 index 0000000..adf3ed0 --- /dev/null +++ b/frontend/src/assets/svg/permission_edit_blue.svg @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/frontend/src/assets/svg/permission_edit_white.svg b/frontend/src/assets/svg/permission_edit_white.svg new file mode 100644 index 0000000..bb73d33 --- /dev/null +++ b/frontend/src/assets/svg/permission_edit_white.svg @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/frontend/src/assets/svg/permission_table_del_blue.svg b/frontend/src/assets/svg/permission_table_del_blue.svg new file mode 100644 index 0000000..2a7da29 --- /dev/null +++ b/frontend/src/assets/svg/permission_table_del_blue.svg @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/frontend/src/assets/svg/permission_table_edit_blue.svg b/frontend/src/assets/svg/permission_table_edit_blue.svg new file mode 100644 index 0000000..4af238f --- /dev/null +++ b/frontend/src/assets/svg/permission_table_edit_blue.svg @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/frontend/src/assets/svg/pg-ds.svg b/frontend/src/assets/svg/pg-ds.svg new file mode 100644 index 0000000..9a5bb6b --- /dev/null +++ b/frontend/src/assets/svg/pg-ds.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + + + diff --git a/frontend/src/assets/svg/picture-group-dark.svg b/frontend/src/assets/svg/picture-group-dark.svg new file mode 100644 index 0000000..d57adf7 --- /dev/null +++ b/frontend/src/assets/svg/picture-group-dark.svg @@ -0,0 +1,4 @@ + + + + diff --git a/frontend/src/assets/svg/picture-group-origin.svg b/frontend/src/assets/svg/picture-group-origin.svg new file mode 100644 index 0000000..6fa4f5b --- /dev/null +++ b/frontend/src/assets/svg/picture-group-origin.svg @@ -0,0 +1,4 @@ + + + + diff --git a/frontend/src/assets/svg/picture-group.svg b/frontend/src/assets/svg/picture-group.svg new file mode 100644 index 0000000..d57adf7 --- /dev/null +++ b/frontend/src/assets/svg/picture-group.svg @@ -0,0 +1,4 @@ + + + + diff --git a/frontend/src/assets/svg/pie-dark.svg b/frontend/src/assets/svg/pie-dark.svg new file mode 100644 index 0000000..58c0090 --- /dev/null +++ b/frontend/src/assets/svg/pie-dark.svg @@ -0,0 +1,4 @@ + + + + diff --git a/frontend/src/assets/svg/pie-donut-dark.svg b/frontend/src/assets/svg/pie-donut-dark.svg new file mode 100644 index 0000000..070d265 --- /dev/null +++ b/frontend/src/assets/svg/pie-donut-dark.svg @@ -0,0 +1,4 @@ + + + + diff --git a/frontend/src/assets/svg/pie-donut-origin.svg b/frontend/src/assets/svg/pie-donut-origin.svg new file mode 100644 index 0000000..b719ba8 --- /dev/null +++ b/frontend/src/assets/svg/pie-donut-origin.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/pie-donut-rose-dark.svg b/frontend/src/assets/svg/pie-donut-rose-dark.svg new file mode 100644 index 0000000..1e51b0e --- /dev/null +++ b/frontend/src/assets/svg/pie-donut-rose-dark.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/src/assets/svg/pie-donut-rose-origin.svg b/frontend/src/assets/svg/pie-donut-rose-origin.svg new file mode 100644 index 0000000..b719ba8 --- /dev/null +++ b/frontend/src/assets/svg/pie-donut-rose-origin.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/pie-donut-rose.svg b/frontend/src/assets/svg/pie-donut-rose.svg new file mode 100644 index 0000000..1e51b0e --- /dev/null +++ b/frontend/src/assets/svg/pie-donut-rose.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/src/assets/svg/pie-donut.svg b/frontend/src/assets/svg/pie-donut.svg new file mode 100644 index 0000000..1139b8e --- /dev/null +++ b/frontend/src/assets/svg/pie-donut.svg @@ -0,0 +1,4 @@ + + + + diff --git a/frontend/src/assets/svg/pie-origin.svg b/frontend/src/assets/svg/pie-origin.svg new file mode 100644 index 0000000..67d3730 --- /dev/null +++ b/frontend/src/assets/svg/pie-origin.svg @@ -0,0 +1,4 @@ + + + + diff --git a/frontend/src/assets/svg/pie-rose-dark.svg b/frontend/src/assets/svg/pie-rose-dark.svg new file mode 100644 index 0000000..f432787 --- /dev/null +++ b/frontend/src/assets/svg/pie-rose-dark.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/frontend/src/assets/svg/pie-rose-origin.svg b/frontend/src/assets/svg/pie-rose-origin.svg new file mode 100644 index 0000000..a83b8cc --- /dev/null +++ b/frontend/src/assets/svg/pie-rose-origin.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/frontend/src/assets/svg/pie-rose.svg b/frontend/src/assets/svg/pie-rose.svg new file mode 100644 index 0000000..8dc1b10 --- /dev/null +++ b/frontend/src/assets/svg/pie-rose.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/frontend/src/assets/svg/pie.svg b/frontend/src/assets/svg/pie.svg new file mode 100644 index 0000000..58c0090 --- /dev/null +++ b/frontend/src/assets/svg/pie.svg @@ -0,0 +1,4 @@ + + + + diff --git a/frontend/src/assets/svg/platform.svg b/frontend/src/assets/svg/platform.svg new file mode 100644 index 0000000..859d0f9 --- /dev/null +++ b/frontend/src/assets/svg/platform.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/plugin-3dmap.svg b/frontend/src/assets/svg/plugin-3dmap.svg new file mode 100644 index 0000000..f8b3e8b --- /dev/null +++ b/frontend/src/assets/svg/plugin-3dmap.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/src/assets/svg/plugin-3dpie.svg b/frontend/src/assets/svg/plugin-3dpie.svg new file mode 100644 index 0000000..84dcb8f --- /dev/null +++ b/frontend/src/assets/svg/plugin-3dpie.svg @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + diff --git a/frontend/src/assets/svg/plugin-dameng.svg b/frontend/src/assets/svg/plugin-dameng.svg new file mode 100644 index 0000000..dade3a8 --- /dev/null +++ b/frontend/src/assets/svg/plugin-dameng.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/frontend/src/assets/svg/plugin-default.svg b/frontend/src/assets/svg/plugin-default.svg new file mode 100644 index 0000000..6bdef21 --- /dev/null +++ b/frontend/src/assets/svg/plugin-default.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/plugin.svg b/frontend/src/assets/svg/plugin.svg new file mode 100644 index 0000000..5151777 --- /dev/null +++ b/frontend/src/assets/svg/plugin.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/plugins-new.svg b/frontend/src/assets/svg/plugins-new.svg new file mode 100644 index 0000000..09668d9 --- /dev/null +++ b/frontend/src/assets/svg/plugins-new.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/plugins.svg b/frontend/src/assets/svg/plugins.svg new file mode 100644 index 0000000..de353db --- /dev/null +++ b/frontend/src/assets/svg/plugins.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/src/assets/svg/progress-bar-dark.svg b/frontend/src/assets/svg/progress-bar-dark.svg new file mode 100644 index 0000000..2f0ea80 --- /dev/null +++ b/frontend/src/assets/svg/progress-bar-dark.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/frontend/src/assets/svg/progress-bar-origin.svg b/frontend/src/assets/svg/progress-bar-origin.svg new file mode 100644 index 0000000..7b61319 --- /dev/null +++ b/frontend/src/assets/svg/progress-bar-origin.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/frontend/src/assets/svg/progress-bar.svg b/frontend/src/assets/svg/progress-bar.svg new file mode 100644 index 0000000..c75e98a --- /dev/null +++ b/frontend/src/assets/svg/progress-bar.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/frontend/src/assets/svg/pwd_invisible.svg b/frontend/src/assets/svg/pwd_invisible.svg new file mode 100644 index 0000000..661ebba --- /dev/null +++ b/frontend/src/assets/svg/pwd_invisible.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/pwd_visible.svg b/frontend/src/assets/svg/pwd_visible.svg new file mode 100644 index 0000000..4e7ba5e --- /dev/null +++ b/frontend/src/assets/svg/pwd_visible.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/quadrant-dark.svg b/frontend/src/assets/svg/quadrant-dark.svg new file mode 100644 index 0000000..b78cb06 --- /dev/null +++ b/frontend/src/assets/svg/quadrant-dark.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/frontend/src/assets/svg/quadrant-origin.svg b/frontend/src/assets/svg/quadrant-origin.svg new file mode 100644 index 0000000..b79493c --- /dev/null +++ b/frontend/src/assets/svg/quadrant-origin.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/frontend/src/assets/svg/quadrant.svg b/frontend/src/assets/svg/quadrant.svg new file mode 100644 index 0000000..9f06298 --- /dev/null +++ b/frontend/src/assets/svg/quadrant.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/frontend/src/assets/svg/radar-dark.svg b/frontend/src/assets/svg/radar-dark.svg new file mode 100644 index 0000000..34169cb --- /dev/null +++ b/frontend/src/assets/svg/radar-dark.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/frontend/src/assets/svg/radar-origin.svg b/frontend/src/assets/svg/radar-origin.svg new file mode 100644 index 0000000..f4813cc --- /dev/null +++ b/frontend/src/assets/svg/radar-origin.svg @@ -0,0 +1,4 @@ + + + + diff --git a/frontend/src/assets/svg/radar.svg b/frontend/src/assets/svg/radar.svg new file mode 100644 index 0000000..a711496 --- /dev/null +++ b/frontend/src/assets/svg/radar.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/frontend/src/assets/svg/read-msg.svg b/frontend/src/assets/svg/read-msg.svg new file mode 100644 index 0000000..55ae260 --- /dev/null +++ b/frontend/src/assets/svg/read-msg.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/src/assets/svg/redshift-ds.svg b/frontend/src/assets/svg/redshift-ds.svg new file mode 100644 index 0000000..38ab4bc --- /dev/null +++ b/frontend/src/assets/svg/redshift-ds.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/frontend/src/assets/svg/reference-field.svg b/frontend/src/assets/svg/reference-field.svg new file mode 100644 index 0000000..b311d14 --- /dev/null +++ b/frontend/src/assets/svg/reference-field.svg @@ -0,0 +1,4 @@ + + + + diff --git a/frontend/src/assets/svg/reference-play.svg b/frontend/src/assets/svg/reference-play.svg new file mode 100644 index 0000000..5a70624 --- /dev/null +++ b/frontend/src/assets/svg/reference-play.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/frontend/src/assets/svg/reference-setting-white.svg b/frontend/src/assets/svg/reference-setting-white.svg new file mode 100644 index 0000000..a5f22f1 --- /dev/null +++ b/frontend/src/assets/svg/reference-setting-white.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/reference-setting.svg b/frontend/src/assets/svg/reference-setting.svg new file mode 100644 index 0000000..74107b6 --- /dev/null +++ b/frontend/src/assets/svg/reference-setting.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/reference-table.svg b/frontend/src/assets/svg/reference-table.svg new file mode 100644 index 0000000..96a9732 --- /dev/null +++ b/frontend/src/assets/svg/reference-table.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/relation_arrow_icon.svg b/frontend/src/assets/svg/relation_arrow_icon.svg new file mode 100644 index 0000000..9dd3a40 --- /dev/null +++ b/frontend/src/assets/svg/relation_arrow_icon.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/release.svg b/frontend/src/assets/svg/release.svg new file mode 100644 index 0000000..2cc2ff9 --- /dev/null +++ b/frontend/src/assets/svg/release.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/src/assets/svg/report.svg b/frontend/src/assets/svg/report.svg new file mode 100644 index 0000000..50204b1 --- /dev/null +++ b/frontend/src/assets/svg/report.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/frontend/src/assets/svg/reset_password_blue.svg b/frontend/src/assets/svg/reset_password_blue.svg new file mode 100644 index 0000000..0028219 --- /dev/null +++ b/frontend/src/assets/svg/reset_password_blue.svg @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/frontend/src/assets/svg/rich-text-dark.svg b/frontend/src/assets/svg/rich-text-dark.svg new file mode 100644 index 0000000..ff6d406 --- /dev/null +++ b/frontend/src/assets/svg/rich-text-dark.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/rich-text-origin.svg b/frontend/src/assets/svg/rich-text-origin.svg new file mode 100644 index 0000000..5c1c6f2 --- /dev/null +++ b/frontend/src/assets/svg/rich-text-origin.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/rich-text.svg b/frontend/src/assets/svg/rich-text.svg new file mode 100644 index 0000000..cea3f7e --- /dev/null +++ b/frontend/src/assets/svg/rich-text.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/richTextView.svg b/frontend/src/assets/svg/richTextView.svg new file mode 100644 index 0000000..91d5c98 --- /dev/null +++ b/frontend/src/assets/svg/richTextView.svg @@ -0,0 +1,2 @@ + \ No newline at end of file diff --git a/frontend/src/assets/svg/right-join.svg b/frontend/src/assets/svg/right-join.svg new file mode 100644 index 0000000..0938320 --- /dev/null +++ b/frontend/src/assets/svg/right-join.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/frontend/src/assets/svg/role.svg b/frontend/src/assets/svg/role.svg new file mode 100644 index 0000000..ae889b1 --- /dev/null +++ b/frontend/src/assets/svg/role.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/round_play.svg b/frontend/src/assets/svg/round_play.svg new file mode 100644 index 0000000..cc27381 --- /dev/null +++ b/frontend/src/assets/svg/round_play.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/sankey-dark.svg b/frontend/src/assets/svg/sankey-dark.svg new file mode 100644 index 0000000..e296f88 --- /dev/null +++ b/frontend/src/assets/svg/sankey-dark.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/frontend/src/assets/svg/sankey-origin.svg b/frontend/src/assets/svg/sankey-origin.svg new file mode 100644 index 0000000..bb2363d --- /dev/null +++ b/frontend/src/assets/svg/sankey-origin.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/frontend/src/assets/svg/sankey.svg b/frontend/src/assets/svg/sankey.svg new file mode 100644 index 0000000..5645f5d --- /dev/null +++ b/frontend/src/assets/svg/sankey.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/frontend/src/assets/svg/scatter-dark.svg b/frontend/src/assets/svg/scatter-dark.svg new file mode 100644 index 0000000..384794b --- /dev/null +++ b/frontend/src/assets/svg/scatter-dark.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/frontend/src/assets/svg/scatter-origin.svg b/frontend/src/assets/svg/scatter-origin.svg new file mode 100644 index 0000000..0a32054 --- /dev/null +++ b/frontend/src/assets/svg/scatter-origin.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/frontend/src/assets/svg/scatter.svg b/frontend/src/assets/svg/scatter.svg new file mode 100644 index 0000000..3ad42c3 --- /dev/null +++ b/frontend/src/assets/svg/scatter.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/frontend/src/assets/svg/scatterpage.svg b/frontend/src/assets/svg/scatterpage.svg new file mode 100644 index 0000000..2f13374 --- /dev/null +++ b/frontend/src/assets/svg/scatterpage.svg @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/frontend/src/assets/svg/scene.svg b/frontend/src/assets/svg/scene.svg new file mode 100644 index 0000000..037555d --- /dev/null +++ b/frontend/src/assets/svg/scene.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/scroll-text.svg b/frontend/src/assets/svg/scroll-text.svg new file mode 100644 index 0000000..5847b4a --- /dev/null +++ b/frontend/src/assets/svg/scroll-text.svg @@ -0,0 +1 @@ + diff --git a/frontend/src/assets/svg/size.svg b/frontend/src/assets/svg/size.svg new file mode 100644 index 0000000..ddb25b8 --- /dev/null +++ b/frontend/src/assets/svg/size.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/src/assets/svg/sort-asc.svg b/frontend/src/assets/svg/sort-asc.svg new file mode 100644 index 0000000..d0bcfa2 --- /dev/null +++ b/frontend/src/assets/svg/sort-asc.svg @@ -0,0 +1 @@ + diff --git a/frontend/src/assets/svg/sort-desc.svg b/frontend/src/assets/svg/sort-desc.svg new file mode 100644 index 0000000..23f1d4a --- /dev/null +++ b/frontend/src/assets/svg/sort-desc.svg @@ -0,0 +1 @@ + diff --git a/frontend/src/assets/svg/sqlServer-ds.svg b/frontend/src/assets/svg/sqlServer-ds.svg new file mode 100644 index 0000000..2f2b31a --- /dev/null +++ b/frontend/src/assets/svg/sqlServer-ds.svg @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/frontend/src/assets/svg/stock-line-dark.svg b/frontend/src/assets/svg/stock-line-dark.svg new file mode 100644 index 0000000..1c8c31f --- /dev/null +++ b/frontend/src/assets/svg/stock-line-dark.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/frontend/src/assets/svg/stock-line-origin.svg b/frontend/src/assets/svg/stock-line-origin.svg new file mode 100644 index 0000000..087dafc --- /dev/null +++ b/frontend/src/assets/svg/stock-line-origin.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/frontend/src/assets/svg/stock-line.svg b/frontend/src/assets/svg/stock-line.svg new file mode 100644 index 0000000..3319059 --- /dev/null +++ b/frontend/src/assets/svg/stock-line.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/frontend/src/assets/svg/style-underline.svg b/frontend/src/assets/svg/style-underline.svg new file mode 100644 index 0000000..c8da46f --- /dev/null +++ b/frontend/src/assets/svg/style-underline.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/src/assets/svg/symbolic-map-dark.svg b/frontend/src/assets/svg/symbolic-map-dark.svg new file mode 100644 index 0000000..87d9516 --- /dev/null +++ b/frontend/src/assets/svg/symbolic-map-dark.svg @@ -0,0 +1 @@ + diff --git a/frontend/src/assets/svg/symbolic-map-origin.svg b/frontend/src/assets/svg/symbolic-map-origin.svg new file mode 100644 index 0000000..0198307 --- /dev/null +++ b/frontend/src/assets/svg/symbolic-map-origin.svg @@ -0,0 +1 @@ + diff --git a/frontend/src/assets/svg/symbolic-map.svg b/frontend/src/assets/svg/symbolic-map.svg new file mode 100644 index 0000000..62d72b1 --- /dev/null +++ b/frontend/src/assets/svg/symbolic-map.svg @@ -0,0 +1 @@ + diff --git a/frontend/src/assets/svg/sync.svg b/frontend/src/assets/svg/sync.svg new file mode 100644 index 0000000..ce1fb9c --- /dev/null +++ b/frontend/src/assets/svg/sync.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/sys-param.svg b/frontend/src/assets/svg/sys-param.svg new file mode 100644 index 0000000..f6c6f02 --- /dev/null +++ b/frontend/src/assets/svg/sys-param.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/src/assets/svg/sys-parameter.svg b/frontend/src/assets/svg/sys-parameter.svg new file mode 100644 index 0000000..40404d0 --- /dev/null +++ b/frontend/src/assets/svg/sys-parameter.svg @@ -0,0 +1,4 @@ + + + + diff --git a/frontend/src/assets/svg/sys-relationship.svg b/frontend/src/assets/svg/sys-relationship.svg new file mode 100644 index 0000000..ec0619f --- /dev/null +++ b/frontend/src/assets/svg/sys-relationship.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/src/assets/svg/sys-setting.svg b/frontend/src/assets/svg/sys-setting.svg new file mode 100644 index 0000000..a85a89c --- /dev/null +++ b/frontend/src/assets/svg/sys-setting.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/sys-tools.svg b/frontend/src/assets/svg/sys-tools.svg new file mode 100644 index 0000000..5c94639 --- /dev/null +++ b/frontend/src/assets/svg/sys-tools.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/system.svg b/frontend/src/assets/svg/system.svg new file mode 100644 index 0000000..9333c60 --- /dev/null +++ b/frontend/src/assets/svg/system.svg @@ -0,0 +1 @@ + diff --git a/frontend/src/assets/svg/t-heatmap-dark.svg b/frontend/src/assets/svg/t-heatmap-dark.svg new file mode 100644 index 0000000..0e550c0 --- /dev/null +++ b/frontend/src/assets/svg/t-heatmap-dark.svg @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + diff --git a/frontend/src/assets/svg/t-heatmap-origin.svg b/frontend/src/assets/svg/t-heatmap-origin.svg new file mode 100644 index 0000000..a19b1d0 --- /dev/null +++ b/frontend/src/assets/svg/t-heatmap-origin.svg @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + diff --git a/frontend/src/assets/svg/t-heatmap.svg b/frontend/src/assets/svg/t-heatmap.svg new file mode 100644 index 0000000..b6c8656 --- /dev/null +++ b/frontend/src/assets/svg/t-heatmap.svg @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + diff --git a/frontend/src/assets/svg/tab-title.svg b/frontend/src/assets/svg/tab-title.svg new file mode 100644 index 0000000..4b1acac --- /dev/null +++ b/frontend/src/assets/svg/tab-title.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/src/assets/svg/table-info-dark.svg b/frontend/src/assets/svg/table-info-dark.svg new file mode 100644 index 0000000..113c08c --- /dev/null +++ b/frontend/src/assets/svg/table-info-dark.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/frontend/src/assets/svg/table-info-origin.svg b/frontend/src/assets/svg/table-info-origin.svg new file mode 100644 index 0000000..76f26d0 --- /dev/null +++ b/frontend/src/assets/svg/table-info-origin.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/table-info.svg b/frontend/src/assets/svg/table-info.svg new file mode 100644 index 0000000..04abc22 --- /dev/null +++ b/frontend/src/assets/svg/table-info.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/frontend/src/assets/svg/table-normal-dark.svg b/frontend/src/assets/svg/table-normal-dark.svg new file mode 100644 index 0000000..43e37e6 --- /dev/null +++ b/frontend/src/assets/svg/table-normal-dark.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/frontend/src/assets/svg/table-normal-origin.svg b/frontend/src/assets/svg/table-normal-origin.svg new file mode 100644 index 0000000..76f26d0 --- /dev/null +++ b/frontend/src/assets/svg/table-normal-origin.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/table-normal.svg b/frontend/src/assets/svg/table-normal.svg new file mode 100644 index 0000000..9fa0254 --- /dev/null +++ b/frontend/src/assets/svg/table-normal.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/frontend/src/assets/svg/table-pivot-dark.svg b/frontend/src/assets/svg/table-pivot-dark.svg new file mode 100644 index 0000000..28f6a20 --- /dev/null +++ b/frontend/src/assets/svg/table-pivot-dark.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/frontend/src/assets/svg/table-pivot-origin.svg b/frontend/src/assets/svg/table-pivot-origin.svg new file mode 100644 index 0000000..76f26d0 --- /dev/null +++ b/frontend/src/assets/svg/table-pivot-origin.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/table-pivot.svg b/frontend/src/assets/svg/table-pivot.svg new file mode 100644 index 0000000..9a4fdca --- /dev/null +++ b/frontend/src/assets/svg/table-pivot.svg @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/frontend/src/assets/svg/table.svg b/frontend/src/assets/svg/table.svg new file mode 100644 index 0000000..0e3dc9d --- /dev/null +++ b/frontend/src/assets/svg/table.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/src/assets/svg/task.svg b/frontend/src/assets/svg/task.svg new file mode 100644 index 0000000..575ba4c --- /dev/null +++ b/frontend/src/assets/svg/task.svg @@ -0,0 +1,4 @@ + + + + diff --git a/frontend/src/assets/svg/text-dark.svg b/frontend/src/assets/svg/text-dark.svg new file mode 100644 index 0000000..71ec539 --- /dev/null +++ b/frontend/src/assets/svg/text-dark.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/frontend/src/assets/svg/text.svg b/frontend/src/assets/svg/text.svg new file mode 100644 index 0000000..568144a --- /dev/null +++ b/frontend/src/assets/svg/text.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/frontend/src/assets/svg/threshold.svg b/frontend/src/assets/svg/threshold.svg new file mode 100644 index 0000000..d3dc3de --- /dev/null +++ b/frontend/src/assets/svg/threshold.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/threshold_full.svg b/frontend/src/assets/svg/threshold_full.svg new file mode 100644 index 0000000..011c456 --- /dev/null +++ b/frontend/src/assets/svg/threshold_full.svg @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/frontend/src/assets/svg/title-bold.svg b/frontend/src/assets/svg/title-bold.svg new file mode 100644 index 0000000..41d9d36 --- /dev/null +++ b/frontend/src/assets/svg/title-bold.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/title-center.svg b/frontend/src/assets/svg/title-center.svg new file mode 100644 index 0000000..0a9a460 --- /dev/null +++ b/frontend/src/assets/svg/title-center.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/frontend/src/assets/svg/title-italic.svg b/frontend/src/assets/svg/title-italic.svg new file mode 100644 index 0000000..af8f5ec --- /dev/null +++ b/frontend/src/assets/svg/title-italic.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/title-left.svg b/frontend/src/assets/svg/title-left.svg new file mode 100644 index 0000000..f297076 --- /dev/null +++ b/frontend/src/assets/svg/title-left.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/frontend/src/assets/svg/title-right.svg b/frontend/src/assets/svg/title-right.svg new file mode 100644 index 0000000..f94767b --- /dev/null +++ b/frontend/src/assets/svg/title-right.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/frontend/src/assets/svg/title-v-bottom.svg b/frontend/src/assets/svg/title-v-bottom.svg new file mode 100644 index 0000000..7406462 --- /dev/null +++ b/frontend/src/assets/svg/title-v-bottom.svg @@ -0,0 +1,4 @@ + + + + diff --git a/frontend/src/assets/svg/title-v-center.svg b/frontend/src/assets/svg/title-v-center.svg new file mode 100644 index 0000000..e12bc04 --- /dev/null +++ b/frontend/src/assets/svg/title-v-center.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/frontend/src/assets/svg/title-v-top.svg b/frontend/src/assets/svg/title-v-top.svg new file mode 100644 index 0000000..3f67f23 --- /dev/null +++ b/frontend/src/assets/svg/title-v-top.svg @@ -0,0 +1,4 @@ + + + + diff --git a/frontend/src/assets/svg/toolbox-data_fill.svg b/frontend/src/assets/svg/toolbox-data_fill.svg new file mode 100644 index 0000000..c4c2f14 --- /dev/null +++ b/frontend/src/assets/svg/toolbox-data_fill.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/frontend/src/assets/svg/toolbox-icon_template.svg b/frontend/src/assets/svg/toolbox-icon_template.svg new file mode 100644 index 0000000..5a67c71 --- /dev/null +++ b/frontend/src/assets/svg/toolbox-icon_template.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/frontend/src/assets/svg/toolbox-log.svg b/frontend/src/assets/svg/toolbox-log.svg new file mode 100644 index 0000000..14d4bb3 --- /dev/null +++ b/frontend/src/assets/svg/toolbox-log.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/frontend/src/assets/svg/top-doc-default.svg b/frontend/src/assets/svg/top-doc-default.svg new file mode 100644 index 0000000..92f4c2c --- /dev/null +++ b/frontend/src/assets/svg/top-doc-default.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/frontend/src/assets/svg/top-enterprise-trial.svg b/frontend/src/assets/svg/top-enterprise-trial.svg new file mode 100644 index 0000000..810340f --- /dev/null +++ b/frontend/src/assets/svg/top-enterprise-trial.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/frontend/src/assets/svg/top-help-doc.svg b/frontend/src/assets/svg/top-help-doc.svg new file mode 100644 index 0000000..1be5f64 --- /dev/null +++ b/frontend/src/assets/svg/top-help-doc.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/frontend/src/assets/svg/top-product-bbs.svg b/frontend/src/assets/svg/top-product-bbs.svg new file mode 100644 index 0000000..542e257 --- /dev/null +++ b/frontend/src/assets/svg/top-product-bbs.svg @@ -0,0 +1,4 @@ + + + + diff --git a/frontend/src/assets/svg/top-tech-video.svg b/frontend/src/assets/svg/top-tech-video.svg new file mode 100644 index 0000000..c184dcb --- /dev/null +++ b/frontend/src/assets/svg/top-tech-video.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/top-technology.svg b/frontend/src/assets/svg/top-technology.svg new file mode 100644 index 0000000..f9ae658 --- /dev/null +++ b/frontend/src/assets/svg/top-technology.svg @@ -0,0 +1,4 @@ + + + + diff --git a/frontend/src/assets/svg/tree.svg b/frontend/src/assets/svg/tree.svg new file mode 100644 index 0000000..dd4b7dd --- /dev/null +++ b/frontend/src/assets/svg/tree.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/src/assets/svg/treemap-dark.svg b/frontend/src/assets/svg/treemap-dark.svg new file mode 100644 index 0000000..73bdeb3 --- /dev/null +++ b/frontend/src/assets/svg/treemap-dark.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/frontend/src/assets/svg/treemap-origin.svg b/frontend/src/assets/svg/treemap-origin.svg new file mode 100644 index 0000000..cbece3a --- /dev/null +++ b/frontend/src/assets/svg/treemap-origin.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/frontend/src/assets/svg/treemap.svg b/frontend/src/assets/svg/treemap.svg new file mode 100644 index 0000000..73bdeb3 --- /dev/null +++ b/frontend/src/assets/svg/treemap.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/frontend/src/assets/svg/unlock.svg b/frontend/src/assets/svg/unlock.svg new file mode 100644 index 0000000..69531f1 --- /dev/null +++ b/frontend/src/assets/svg/unlock.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/src/assets/svg/unpublished.svg b/frontend/src/assets/svg/unpublished.svg new file mode 100644 index 0000000..639db52 --- /dev/null +++ b/frontend/src/assets/svg/unpublished.svg @@ -0,0 +1,2 @@ + \ No newline at end of file diff --git a/frontend/src/assets/svg/unread-msg.svg b/frontend/src/assets/svg/unread-msg.svg new file mode 100644 index 0000000..86c571f --- /dev/null +++ b/frontend/src/assets/svg/unread-msg.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/src/assets/svg/user-img.svg b/frontend/src/assets/svg/user-img.svg new file mode 100644 index 0000000..13a0b27 --- /dev/null +++ b/frontend/src/assets/svg/user-img.svg @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + diff --git a/frontend/src/assets/svg/user-reci.svg b/frontend/src/assets/svg/user-reci.svg new file mode 100644 index 0000000..a6d141f --- /dev/null +++ b/frontend/src/assets/svg/user-reci.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/user.svg b/frontend/src/assets/svg/user.svg new file mode 100644 index 0000000..0ba0716 --- /dev/null +++ b/frontend/src/assets/svg/user.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/src/assets/svg/user_connect_white.svg b/frontend/src/assets/svg/user_connect_white.svg new file mode 100644 index 0000000..bc107b3 --- /dev/null +++ b/frontend/src/assets/svg/user_connect_white.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/src/assets/svg/variable.svg b/frontend/src/assets/svg/variable.svg new file mode 100644 index 0000000..12f4475 --- /dev/null +++ b/frontend/src/assets/svg/variable.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/src/assets/svg/visual-star.svg b/frontend/src/assets/svg/visual-star.svg new file mode 100644 index 0000000..8dd3729 --- /dev/null +++ b/frontend/src/assets/svg/visual-star.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/warn-tree.svg b/frontend/src/assets/svg/warn-tree.svg new file mode 100644 index 0000000..7fdc95f --- /dev/null +++ b/frontend/src/assets/svg/warn-tree.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/src/assets/svg/waterfall-dark.svg b/frontend/src/assets/svg/waterfall-dark.svg new file mode 100644 index 0000000..986f246 --- /dev/null +++ b/frontend/src/assets/svg/waterfall-dark.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/frontend/src/assets/svg/waterfall-origin.svg b/frontend/src/assets/svg/waterfall-origin.svg new file mode 100644 index 0000000..035107b --- /dev/null +++ b/frontend/src/assets/svg/waterfall-origin.svg @@ -0,0 +1,3 @@ + + + diff --git a/frontend/src/assets/svg/waterfall.svg b/frontend/src/assets/svg/waterfall.svg new file mode 100644 index 0000000..567b96e --- /dev/null +++ b/frontend/src/assets/svg/waterfall.svg @@ -0,0 +1,7 @@ + + + + + + + diff --git a/frontend/src/assets/svg/watermark.svg b/frontend/src/assets/svg/watermark.svg new file mode 100644 index 0000000..d8d907f --- /dev/null +++ b/frontend/src/assets/svg/watermark.svg @@ -0,0 +1,4 @@ + + + + diff --git a/frontend/src/assets/svg/web-msg.svg b/frontend/src/assets/svg/web-msg.svg new file mode 100644 index 0000000..1334c9d --- /dev/null +++ b/frontend/src/assets/svg/web-msg.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/frontend/src/assets/svg/wizard_enterprise.svg b/frontend/src/assets/svg/wizard_enterprise.svg new file mode 100644 index 0000000..2bdfdb7 --- /dev/null +++ b/frontend/src/assets/svg/wizard_enterprise.svg @@ -0,0 +1,81 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/frontend/src/assets/svg/wizard_help.svg b/frontend/src/assets/svg/wizard_help.svg new file mode 100644 index 0000000..9094e24 --- /dev/null +++ b/frontend/src/assets/svg/wizard_help.svg @@ -0,0 +1,44 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/frontend/src/assets/svg/wizard_main_bg_inner.svg b/frontend/src/assets/svg/wizard_main_bg_inner.svg new file mode 100644 index 0000000..87c44d4 --- /dev/null +++ b/frontend/src/assets/svg/wizard_main_bg_inner.svg @@ -0,0 +1,266 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/frontend/src/assets/svg/wizard_quick_start.svg b/frontend/src/assets/svg/wizard_quick_start.svg new file mode 100644 index 0000000..6970599 --- /dev/null +++ b/frontend/src/assets/svg/wizard_quick_start.svg @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/frontend/src/assets/svg/word-cloud-dark.svg b/frontend/src/assets/svg/word-cloud-dark.svg new file mode 100644 index 0000000..5727796 --- /dev/null +++ b/frontend/src/assets/svg/word-cloud-dark.svg @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + diff --git a/frontend/src/assets/svg/word-cloud-origin.svg b/frontend/src/assets/svg/word-cloud-origin.svg new file mode 100644 index 0000000..470ddd5 --- /dev/null +++ b/frontend/src/assets/svg/word-cloud-origin.svg @@ -0,0 +1,4 @@ + + + + diff --git a/frontend/src/assets/svg/word-cloud.svg b/frontend/src/assets/svg/word-cloud.svg new file mode 100644 index 0000000..2264bf1 --- /dev/null +++ b/frontend/src/assets/svg/word-cloud.svg @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + + + + + diff --git a/frontend/src/data-collect/index.es.js b/frontend/src/data-collect/index.es.js index cf8760a..3aa350b 100644 --- a/frontend/src/data-collect/index.es.js +++ b/frontend/src/data-collect/index.es.js @@ -52106,10 +52106,10 @@ var o1 = { exports: {} }; }); /*! ***************************************************************************** Copyright (c) Microsoft Corporation. - + Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted. - + THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, @@ -53000,8 +53000,7 @@ var o1 = { exports: {} }; } function b(y, E, x) { var k = x.css, R = x.media, M = x.sourceMap; - if (R ? y.setAttribute("media", R) : y.removeAttribute("media"), M && typeof btoa < "u" && (k += ` -/*# sourceMappingURL=data:application/json;base64,`.concat(btoa(unescape(encodeURIComponent(JSON.stringify(M)))), " */")), y.styleSheet) + if (R ? y.setAttribute("media", R) : y.removeAttribute("media"), M && typeof btoa < "u" && ((null)), y.styleSheet) y.styleSheet.cssText = k; else { for (; y.firstChild; ) @@ -53638,7 +53637,7 @@ var o1 = { exports: {} }; }); }; }, function(i, r) { - i.exports = ` + i.exports = ` \v\f\r \xA0\u1680\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200A\u202F\u205F\u3000\u2028\u2029\uFEFF`; }, function(i, r, n) { var a = n(60), s = n(18), u = n(48); @@ -53971,7 +53970,7 @@ var o1 = { exports: {} }; } } }), Z.length) { - E.customAlert(k("\u56FE\u7247\u9A8C\u8BC1\u672A\u901A\u8FC7") + `: + E.customAlert(k("\u56FE\u7247\u9A8C\u8BC1\u672A\u901A\u8FC7") + `: ` + Z.join(` `), "warning"); return; @@ -57659,8 +57658,8 @@ var o1 = { exports: {} }; var B = R.childNodes(); if ((B == null ? void 0 : B.getNodeName()) === "IMG") { var T = (P = (M = k.selection.getSelectionContainerElem()) === null || M === void 0 ? void 0 : M.children()) === null || P === void 0 ? void 0 : P.elems[0].children[0]; - k.cmd.do("insertHTML", `"); } else { var D, V = R.elems[0], W = V.innerHTML, G = V.parentElement; @@ -58093,10 +58092,10 @@ var o1 = { exports: {} }; }, { title: b.i18next.t("menus.panelMenus.video.\u63D2\u5165\u89C6\u9891"), tpl: `

@@ -128,7 +139,6 @@ const stats = reactive({ dictCount: 0 }) -// 最近活动 const activities = ref([ { id: 1, diff --git a/frontend/src/data-public/FormCreateDesigner.vue b/frontend/src/data-public/FormCreateDesigner.vue index 74a5a47..af4730b 100644 --- a/frontend/src/data-public/FormCreateDesigner.vue +++ b/frontend/src/data-public/FormCreateDesigner.vue @@ -14,7 +14,11 @@ import { onMounted, ref } from 'vue'; import { ElMessage } from 'element-plus-secondary' import formCreate from '@/data-collect/render/element-plus/form-create.es.js' + import { useRoute } from 'vue-router' +// import { moduleById,moduleUpdate } from '@/api/application/module' +// const basePath = import.meta.env.VITE_API_BASEPATH + const route = useRoute() const designerForm = formCreate.factory(); debugger diff --git a/frontend/src/data-visualization/DvPreview.vue b/frontend/src/data-visualization/DvPreview.vue new file mode 100644 index 0000000..c6f6cb1 --- /dev/null +++ b/frontend/src/data-visualization/DvPreview.vue @@ -0,0 +1,110 @@ + + + + + diff --git a/frontend/src/data-visualization/canvas/DeCanvas.vue b/frontend/src/data-visualization/canvas/DeCanvas.vue new file mode 100644 index 0000000..9603124 --- /dev/null +++ b/frontend/src/data-visualization/canvas/DeCanvas.vue @@ -0,0 +1,365 @@ + + + + + diff --git a/frontend/src/data-visualization/chart/components/editor/common/ChartTemplateInfo.vue b/frontend/src/data-visualization/chart/components/editor/common/ChartTemplateInfo.vue new file mode 100644 index 0000000..8774c12 --- /dev/null +++ b/frontend/src/data-visualization/chart/components/editor/common/ChartTemplateInfo.vue @@ -0,0 +1,45 @@ + + + + + diff --git a/frontend/src/data-visualization/chart/components/editor/common/TableTooltip.vue b/frontend/src/data-visualization/chart/components/editor/common/TableTooltip.vue new file mode 100644 index 0000000..727a46f --- /dev/null +++ b/frontend/src/data-visualization/chart/components/editor/common/TableTooltip.vue @@ -0,0 +1,80 @@ + + + diff --git a/frontend/src/data-visualization/chart/components/editor/util/StringUtils.ts b/frontend/src/data-visualization/chart/components/editor/util/StringUtils.ts new file mode 100644 index 0000000..9883ed8 --- /dev/null +++ b/frontend/src/data-visualization/chart/components/editor/util/StringUtils.ts @@ -0,0 +1,56 @@ +// 替换所有 标准模板格式 为 $panelName$ +export function pdfTemplateReplaceAll(content, source, target) { + const pattern = '\\$' + source + '\\$' + content = content.replace(new RegExp(pattern, 'gm'), target) + return content +} + +export function randomRange(min, max) { + let returnStr = '' + const range = max ? Math.round(Math.random() * (max - min)) + min : min + const charStr = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789' + + for (let i = 0; i < range; i++) { + const index = Math.round(Math.random() * (charStr.length - 1)) + returnStr += charStr.substring(index, index + 1) + } + return returnStr +} + +export function equalsAny(target, ...sources) { + for (let i = 0; i < sources.length; i++) { + if (target === sources[i]) { + return true + } + } + return false +} + +export function includesAny(target, ...sources) { + if (!target || !sources) { + return false + } + for (let i = 0; i < sources.length; i++) { + if (target.includes(sources[i])) { + return true + } + } + return false +} + +// 替换字符串中的国际化内容, 格式为$t('xxx') +export function replaceInlineI18n(rawString) { + const res = [] + const reg = /\$t\('([\w.]+)'\)/gm + let tmp + if (!rawString) { + return res + } + while ((tmp = reg.exec(rawString)) !== null) { + res.push(tmp) + } + res.forEach(tmp => { + rawString = rawString.replaceAll(tmp[0], tmp[1]) + }) + return rawString +} diff --git a/frontend/src/data-visualization/chart/components/editor/util/chart.ts b/frontend/src/data-visualization/chart/components/editor/util/chart.ts new file mode 100644 index 0000000..22aa597 --- /dev/null +++ b/frontend/src/data-visualization/chart/components/editor/util/chart.ts @@ -0,0 +1,1759 @@ +import { useI18n } from '@/data-visualization/hooks/web/useI18n' +import { deepCopy } from '@/data-visualization/utils/utils' +import { formatterItem } from '@/data-visualization/chart/components/js/formatter' +const { t } = useI18n() + +export const DEFAULT_COLOR_CASE: DeepPartial = { + basicStyle: { + colorScheme: 'default', + colors: [ + '#1E90FF', + '#90EE90', + '#00CED1', + '#E2BD84', + '#7A90E0', + '#3BA272', + '#2BE7FF', + '#0A8ADA', + '#FFD700' + ], + alpha: 100, + gradient: false, + mapStyle: 'normal', + areaBaseColor: '#FFFFFF', + areaBorderColor: '#303133', + gaugeStyle: 'default', + tableBorderColor: '#E6E7E4', + tableScrollBarColor: 'rgba(0, 0, 0, 0.15)', + zoomButtonColor: '#aaa', + zoomBackground: '#fff' + }, + misc: { + flowMapConfig: { + lineConfig: { + mapLineAnimate: true, + mapLineGradient: false, + mapLineSourceColor: '#1E90FF', + mapLineTargetColor: '#90EE90' + } + }, + nameFontColor: '#000000', + valueFontColor: '#5470c6' + }, + tableHeader: { + tableHeaderBgColor: '#1E90FF', + tableHeaderCornerBgColor: '#1E90FF', + tableHeaderColBgColor: '#1E90FF', + tableHeaderFontColor: '#000000', + tableHeaderCornerFontColor: '#000000', + tableHeaderColFontColor: '#000000' + }, + tableCell: { + tableItemBgColor: '#FFFFFF', + tableFontColor: '#000000', + tableItemSubBgColor: '#EEEEEE' + } +} + +export const DEFAULT_COLOR_CASE_LIGHT: DeepPartial = { + basicStyle: { + colorScheme: 'default', + colors: [ + '#1E90FF', + '#90EE90', + '#00CED1', + '#E2BD84', + '#7A90E0', + '#3BA272', + '#2BE7FF', + '#0A8ADA', + '#FFD700' + ], + alpha: 100, + gradient: false, + mapStyle: 'normal', + areaBaseColor: '#FFFFFF', + areaBorderColor: '#303133', + gaugeStyle: 'default', + tableBorderColor: '#E6E7E4', + tableScrollBarColor: 'rgba(0, 0, 0, 0.15)', + zoomButtonColor: '#aaa', + zoomBackground: '#fff' + }, + misc: { + flowMapConfig: { + lineConfig: { + mapLineAnimate: true, + mapLineGradient: false, + mapLineSourceColor: '#146C94', + mapLineTargetColor: '#576CBC' + } + }, + nameFontColor: '#000000', + valueFontColor: '#5470c6' + }, + tableHeader: { + tableHeaderBgColor: '#1E90FF', + tableHeaderCornerBgColor: '#1E90FF', + tableHeaderColBgColor: '#1E90FF', + tableHeaderFontColor: '#000000', + tableHeaderCornerFontColor: '#000000', + tableHeaderColFontColor: '#000000' + }, + tableCell: { + tableItemBgColor: '#FFFFFF', + tableFontColor: '#000000', + tableItemSubBgColor: '#EEEEEE' + } +} + +export const DEFAULT_COLOR_CASE_DARK: DeepPartial = { + basicStyle: { + colorScheme: 'default', + colors: [ + '#1E90FF', + '#90EE90', + '#00CED1', + '#E2BD84', + '#7A90E0', + '#3BA272', + '#2BE7FF', + '#0A8ADA', + '#FFD700' + ], + alpha: 100, + gradient: false, + mapStyle: 'darkblue', + areaBaseColor: '#5470C6', + areaBorderColor: '#EBEEF5', + gaugeStyle: 'default', + tableBorderColor: '#CCCCCC', + tableScrollBarColor: 'rgba(255, 255, 255, 0.5)', + zoomButtonColor: '#fff', + zoomBackground: '#000' + }, + misc: { + flowMapConfig: { + lineConfig: { + mapLineGradient: false, + mapLineSourceColor: '#146C94', + mapLineTargetColor: '#576CBC' + } + }, + nameFontColor: '#ffffff', + valueFontColor: '#5470c6' + }, + tableHeader: { + tableHeaderBgColor: '#1E90FF', + tableHeaderCornerBgColor: '#1E90FF', + tableHeaderColBgColor: '#1E90FF', + tableHeaderFontColor: '#FFFFFF', + tableHeaderCornerFontColor: '#FFFFFF', + tableHeaderColFontColor: '#FFFFFF' + }, + tableCell: { + tableItemBgColor: '#131E42', + tableFontColor: '#ffffff', + tableItemSubBgColor: '#EEEEEE' + } +} + +export const TAB_COMMON_STYLE_BASE = { + headPosition: 'left' +} +export const TAB_COMMON_STYLE_LIGHT = { + ...TAB_COMMON_STYLE_BASE, + headFontColor: '#000000', + headFontActiveColor: '#000000', + headBorderColor: '#ffffff', + headBorderActiveColor: '#ffffff' +} +export const TAB_COMMON_STYLE_DARK = { + ...TAB_COMMON_STYLE_BASE, + headFontColor: '#ffffff', + headFontActiveColor: '#ffffff', + headBorderColor: '#000000', + headBorderActiveColor: '#000000' +} + +export const SENIOR_STYLE_SETTING_LIGHT = { + linkageIconColor: '#a6a6a6', + drillLayerColor: '#a6a6a6', + pagerColor: '#a6a6a6' +} + +export const SENIOR_STYLE_SETTING_DARK = { + linkageIconColor: '#ffffff', + drillLayerColor: '#ffffff', + pagerColor: '#ffffff' +} + +export const FILTER_COMMON_STYLE_BASE = { + layout: 'horizontal', + titleLayout: 'left' +} + +export const FILTER_COMMON_STYLE_LIGHT = { + ...FILTER_COMMON_STYLE_BASE, + labelColor: '#1f2329', + titleColor: '#1f2329', + color: '#1f2329', + borderColor: '#bbbfc4', + text: '#1f2329', + bgColor: '#FFFFFF' +} + +export const FILTER_COMMON_STYLE_DARK = { + ...FILTER_COMMON_STYLE_BASE, + labelColor: '#ffffff', + titleColor: '#ffffff', + color: '#FFFFFF', + borderColor: '#484747', + text: '#AFAFAF', + bgColor: '#131C42' +} + +export const DEFAULT_TAB_COLOR_CASE_BASE = { + headPosition: 'left' +} + +export const DEFAULT_TAB_COLOR_CASE_DARK = { + ...DEFAULT_TAB_COLOR_CASE_BASE, + headFontColor: '#FFFFFF', + headFontActiveColor: '#FFFFFF', + headBorderColor: '#131E42', + headBorderActiveColor: '#131E42' +} + +export const DEFAULT_TAB_COLOR_CASE_LIGHT = { + ...DEFAULT_TAB_COLOR_CASE_BASE, + headFontColor: '#OOOOOO', + headFontActiveColor: '#OOOOOO', + headBorderColor: '#OOOOOO', + headBorderActiveColor: '#OOOOOO' +} + +export const DEFAULT_MISC: ChartMiscAttr = { + pieInnerRadius: 0, + pieOuterRadius: 80, + radarShape: 'polygon', + radarSize: 80, + gaugeMinType: 'fix', + gaugeMinField: { + id: '', + summary: '' + }, + gaugeMin: 0, + gaugeMaxType: 'dynamic', + gaugeMaxField: { + id: '', + summary: '' + }, + gaugeMax: undefined, + gaugeStartAngle: 225, + gaugeEndAngle: -45, + nameFontSize: 18, + valueFontSize: 18, + nameValueSpace: 10, + valueFontColor: '#5470c6', + valueFontFamily: 'Microsoft YaHei', + valueFontIsBolder: false, + valueFontIsItalic: false, + valueLetterSpace: 0, + valueFontShadow: false, + showName: true, + nameFontColor: '#000000', + nameFontFamily: 'Microsoft YaHei', + nameFontIsBolder: false, + nameFontIsItalic: false, + nameLetterSpace: '0', + nameFontShadow: false, + treemapWidth: 80, + treemapHeight: 80, + liquidMax: undefined, + liquidMaxType: 'dynamic', + liquidMaxField: { + id: '', + summary: '' + }, + liquidSize: 80, + liquidShape: 'circle', + hPosition: 'center', + vPosition: 'center', + mapPitch: 0, + wordSizeRange: [8, 32], + wordSpacing: 6, + mapAutoLegend: true, + mapLegendMax: 0, + mapLegendMin: 0, + mapLegendNumber: 9, + mapLegendRangeType: 'quantize', + mapLegendCustomRange: [], + flowMapConfig: { + lineConfig: { + mapLineAnimate: true, + mapLineType: 'arc', + mapLineWidth: 1, + mapLineAnimateDuration: 3, + mapLineGradient: false, + mapLineSourceColor: '#1E90FF', + mapLineTargetColor: '#90EE90', + alpha: 100 + }, + pointConfig: { + text: { + color: '#146C94', + fontSize: 10 + }, + point: { + color: '#146C94', + size: 4, + animate: false, + speed: 0.01 + } + } + }, + wordCloudAxisValueRange: { + auto: true, + min: 0, + max: 0, + fieldId: undefined + } +} + +export const DEFAULT_MARK = { + fieldId: '', + conditions: [] +} +export const DEFAULT_LABEL: ChartLabelAttr = { + show: false, + childrenShow: true, + position: 'top', + color: '#909399', + fontSize: 12, + formatter: '', + labelLine: { + show: true + }, + labelFormatter: formatterItem, + reserveDecimalCount: 2, + labelShadow: false, + labelBgColor: '', + labelShadowColor: '', + quotaLabelFormatter: formatterItem, + showDimension: true, + showQuota: false, + showProportion: true, + seriesLabelFormatter: [], + conversionTag: { + show: false, + precision: 2, + text: t('chart.conversion_rate') + }, + showTotal: false, + totalFontSize: 12, + totalColor: '#FFF', + totalFormatter: formatterItem, + showStackQuota: false, + fullDisplay: false, + proportionSeriesFormatter: { + show: false, + color: '#000', + fontSize: 12, + formatterCfg: { + decimalCount: 2 + } + } +} +export const DEFAULT_TOOLTIP: ChartTooltipAttr = { + show: true, + trigger: 'item', + confine: true, + fontSize: 12, + color: '#909399', + tooltipFormatter: formatterItem, + backgroundColor: '#ffffff', + seriesTooltipFormatter: [], + carousel: { + enable: false, + stayTime: 3, + intervalTime: 0 + } +} +export const DEFAULT_TABLE_TOTAL: ChartTableTotalAttr = { + row: { + showGrandTotals: true, + showSubTotals: true, + reverseLayout: false, + reverseSubLayout: false, + label: t('chart.total_show'), + subLabel: t('chart.sub_total_show'), + subTotalsDimensions: [], + subTotalsDimensionsNew: true, + calcTotals: { + aggregation: 'SUM', + cfg: [] + }, + calcSubTotals: { + aggregation: 'SUM', + cfg: [] + }, + totalSort: 'none', + totalSortField: '' + }, + col: { + showGrandTotals: true, + showSubTotals: true, + reverseLayout: false, + reverseSubLayout: false, + label: t('chart.total_show'), + subLabel: t('chart.sub_total_show'), + subTotalsDimensions: [], + calcTotals: { + aggregation: 'SUM', + cfg: [] + }, + calcSubTotals: { + aggregation: 'SUM', + cfg: [] + }, + totalSort: 'none', // asc,desc + totalSortField: '' + } +} +export const DEFAULT_TABLE_HEADER: ChartTableHeaderAttr = { + indexLabel: t('relation.index'), + showIndex: false, + tableHeaderAlign: 'left', + tableHeaderCornerAlign: 'left', + tableHeaderColAlign: 'left', + tableHeaderBgColor: '#1E90FF', + tableHeaderCornerBgColor: '#1E90FF', + tableHeaderColBgColor: '#1E90FF', + tableHeaderFontColor: '#000000', + tableHeaderCornerFontColor: '#000000', + tableHeaderColFontColor: '#000000', + tableTitleFontSize: 12, + tableTitleCornerFontSize: 12, + tableTitleColFontSize: 12, + tableTitleHeight: 36, + tableHeaderSort: false, + showColTooltip: false, + showRowTooltip: false, + showTableHeader: true, + showHorizonBorder: true, + showVerticalBorder: true, + isItalic: false, + isCornerItalic: false, + isColItalic: false, + isBolder: true, + isCornerBolder: true, + isColBolder: true, + headerGroup: false, + headerGroupConfig: { + columns: [], + meta: [] + } +} +export const DEFAULT_TABLE_CELL: ChartTableCellAttr = { + tableFontColor: '#000000', + tableItemAlign: 'right', + tableItemBgColor: '#FFFFFF', + tableItemFontSize: 12, + tableItemHeight: 36, + enableTableCrossBG: false, + tableItemSubBgColor: '#EEEEEE', + showTooltip: false, + showHorizonBorder: true, + showVerticalBorder: true, + isItalic: false, + isBolder: false, + tableFreeze: false, + tableColumnFreezeHead: 0, + tableRowFreezeHead: 0, + mergeCells: true +} +export const DEFAULT_TITLE_STYLE: ChartTextStyle = { + show: true, + fontSize: 16, + color: '#ffffff', + hPosition: 'left', + vPosition: 'top', + isItalic: false, + isBolder: true, + remarkShow: false, + remark: '', + remarkBackgroundColor: '#ffffff', + fontFamily: '', + letterSpace: '0', + fontShadow: false +} + +export const DEFAULT_INDICATOR_STYLE: ChartIndicatorStyle = { + show: true, + fontSize: 20, + color: '#5470C6ff', + hPosition: 'center', + vPosition: 'center', + isItalic: false, + isBolder: true, + fontFamily: 'Microsoft YaHei', + letterSpace: 0, + fontShadow: false, + backgroundColor: '', + + suffixEnable: true, + suffix: '', + suffixFontSize: 14, + suffixColor: '#5470C6ff', + suffixIsItalic: false, + suffixIsBolder: true, + suffixFontFamily: 'Microsoft YaHei', + suffixLetterSpace: 0, + suffixFontShadow: false +} +export const DEFAULT_INDICATOR_NAME_STYLE: ChartIndicatorNameStyle = { + show: true, + fontSize: 18, + color: '#ffffffff', + isItalic: false, + isBolder: true, + fontFamily: 'Microsoft YaHei', + letterSpace: 0, + fontShadow: false, + nameValueSpacing: 0 +} + +export const DEFAULT_TITLE_STYLE_BASE: ChartTextStyle = { + show: true, + fontSize: 16, + hPosition: 'left', + vPosition: 'top', + isItalic: false, + isBolder: true, + remarkShow: false, + remark: '', + fontFamily: '', + letterSpace: '0', + fontShadow: false, + color: '', + remarkBackgroundColor: '' +} + +export const DEFAULT_TITLE_STYLE_LIGHT = { + ...DEFAULT_TITLE_STYLE_BASE, + color: '#000000', + remarkBackgroundColor: '#ffffff' +} + +export const DEFAULT_TITLE_STYLE_DARK = { + ...DEFAULT_TITLE_STYLE_BASE, + color: '#FFFFFF', + remarkBackgroundColor: '#5A5C62' +} + +export const DEFAULT_LEGEND_STYLE: ChartLegendStyle = { + show: true, + hPosition: 'center', + vPosition: 'bottom', + orient: 'horizontal', + icon: 'circle', + color: '#333333', + fontSize: 12, + size: 4 +} + +export const DEFAULT_LEGEND_STYLE_BASE: ChartLegendStyle = { + show: true, + hPosition: 'center', + vPosition: 'bottom', + orient: 'horizontal', + icon: 'circle', + color: '#333333', + fontSize: 12, + size: 4 +} + +export const DEFAULT_LEGEND_STYLE_LIGHT: ChartLegendStyle = { + ...DEFAULT_LEGEND_STYLE_BASE, + color: '#333333', + fontSize: 12 +} + +export const DEFAULT_LEGEND_STYLE_DARK: ChartLegendStyle = { + ...DEFAULT_LEGEND_STYLE_BASE, + color: '#ffffff', + fontSize: 12 +} + +export const DEFAULT_MARGIN_STYLE = { + marginModel: 'auto', + marginTop: 40, + marginBottom: 44, + marginLeft: 15, + marginRight: 10 +} + +export const DEFAULT_XAXIS_STYLE: ChartAxisStyle = { + show: true, + position: 'bottom', + nameShow: false, + name: '', + color: '#333333', + fontSize: 12, + axisLabel: { + show: true, + color: '#333333', + fontSize: 12, + rotate: 0, + formatter: '{value}', + lengthLimit: 10 + }, + axisLine: { + show: true, + lineStyle: { + color: '#cccccc', + width: 1, + style: 'solid' + } + }, + splitLine: { + show: false, + lineStyle: { + color: '#cccccc', + width: 1, + style: 'solid' + } + }, + axisValue: { + auto: true, + min: 10, + max: 100, + split: 10, + splitCount: 10 + }, + axisLabelFormatter: { + type: 'auto', + unit: 1, + suffix: '', + decimalCount: 2, + thousandSeparator: true + } +} +export const DEFAULT_YAXIS_STYLE: ChartAxisStyle = { + show: true, + position: 'left', + nameShow: false, + name: '', + color: '#333333', + fontSize: 12, + axisLabel: { + show: true, + color: '#333333', + fontSize: 12, + rotate: 0, + formatter: '{value}', + lengthLimit: 10 + }, + axisLine: { + show: false, + lineStyle: { + color: '#cccccc', + width: 1, + style: 'solid' + } + }, + splitLine: { + show: true, + lineStyle: { + color: '#cccccc', + width: 1, + style: 'solid' + } + }, + axisValue: { + auto: true, + min: 10, + max: 100, + split: 10, + splitCount: 10 + }, + axisLabelFormatter: { + type: 'auto', + unit: 1, + suffix: '', + decimalCount: 2, + thousandSeparator: true + } +} +export const DEFAULT_YAXIS_EXT_STYLE: ChartAxisStyle = { + show: true, + position: 'right', + name: '', + color: '#333333', + fontSize: 12, + axisLabel: { + show: true, + color: '#333333', + fontSize: 12, + rotate: 0, + formatter: '{value}' + }, + axisLine: { + show: false, + lineStyle: { + color: '#cccccc', + width: 1, + style: 'solid' + } + }, + splitLine: { + show: false, + lineStyle: { + color: '#cccccc', + width: 1, + style: 'solid' + } + }, + axisValue: { + auto: true, + min: 10, + max: 100, + split: 10, + splitCount: 10 + }, + axisLabelFormatter: { + type: 'auto', + unit: 1, + suffix: '', + decimalCount: 2, + thousandSeparator: true + } +} +export const DEFAULT_BACKGROUND_COLOR = { + color: '#ffffff', + alpha: 0, + borderRadius: 0 +} +export const DEFAULT_MISC_STYLE: ChartMiscStyle = { + showName: false, + color: '#999', + fontSize: 12, + axisColor: '#999', + splitNumber: 5, + axisLine: { + show: true, + lineStyle: { + color: '#999999', + width: 1, + type: 'solid' + } + }, + axisTick: { + show: false, + length: 5, + lineStyle: { + color: '#999999', + width: 1, + type: 'solid' + } + }, + axisLabel: { + show: false, + rotate: 0, + margin: 8, + color: '#999999', + fontSize: '12', + formatter: '{value}' + }, + splitLine: { + show: true, + lineStyle: { + color: '#999999', + width: 1, + type: 'solid' + } + }, + splitArea: { + show: true + }, + axisValue: { + auto: true, + min: 10, + max: 100, + split: 10, + splitCount: 10 + } +} +export const DEFAULT_FUNCTION_CFG: ChartFunctionCfg = { + sliderShow: false, + sliderRange: [0, 10], + sliderBg: '#FFFFFF', + sliderFillBg: '#BCD6F1', + sliderTextColor: '#999999', + emptyDataStrategy: 'breakLine', + emptyDataCustomValue: '', + emptyDataFieldCtrl: [] +} +export const DEFAULT_ASSIST_LINE_CFG: ChartAssistLineCfg = { + enable: false, + assistLine: [] +} +export const DEFAULT_THRESHOLD: ChartThreshold = { + enable: false, + gaugeThreshold: '', + liquidThreshold: '', + labelThreshold: [], + tableThreshold: [], + textLabelThreshold: [], + lineLabelThreshold: [] +} +export const DEFAULT_SCROLL: ScrollCfg = { + open: false, + row: 1, + interval: 2000, + step: 50 +} + +export const DEFAULT_BUBBLE_ANIMATE: BubbleCfg = { + enable: false, + speed: 1, + rings: 1, + type: 'wave' +} + +export const DEFAULT_QUADRANT_STYLE: QuadrantAttr = { + lineStyle: { + stroke: '#aaa', + lineWidth: 1, + opacity: 0.5 + }, + regionStyle: [ + { + fill: '#fdfcfc', + fillOpacity: 0 + }, + { + fill: '#fafdfa', + fillOpacity: 0 + }, + { + fill: '#fdfcfc', + fillOpacity: 0 + }, + { + fill: '#fafdfa', + fillOpacity: 0 + } + ], + labels: [ + { + content: '', + style: { + fill: '#000000', + fillOpacity: 0.5, + fontSize: 14 + } + }, + { + content: '', + style: { + fill: '#000000', + fillOpacity: 0.5, + fontSize: 14 + } + }, + { + content: '', + style: { + fill: '#000000', + fillOpacity: 0.5, + fontSize: 14 + } + }, + { + content: '', + style: { + fill: '#000000', + fillOpacity: 0.5, + fontSize: 14 + } + } + ] +} + +export const COLOR_PANEL = [ + '#FF4500', + '#FF8C00', + '#FFD700', + '#71AE46', + '#00CED1', + '#1E90FF', + '#C71585', + '#999999', + '#000000', + '#FFFFFF' +] + +export const COLOR_CASES = [ + { + name: t('chart.color_default'), + value: 'default', + colors: [ + '#1E90FF', + '#90EE90', + '#00CED1', + '#E2BD84', + '#7A90E0', + '#3BA272', + '#2BE7FF', + '#0A8ADA', + '#FFD700' + ] + }, + { + name: t('chart.color_retro'), + value: 'retro', + colors: [ + '#0780cf', + '#765005', + '#fa6d1d', + '#0e2c82', + '#b6b51f', + '#da1f18', + '#701866', + '#f47a75', + '#009db2' + ] + }, + { + name: t('chart.color_elegant'), + value: 'elegant', + colors: [ + '#95a2ff', + '#fa8080', + '#ffc076', + '#fae768', + '#87e885', + '#3cb9fc', + '#73abf5', + '#cb9bff', + '#434348' + ] + }, + { + name: t('chart.color_future'), + value: 'future', + colors: [ + '#63b2ee', + '#76da91', + '#f8cb7f', + '#f89588', + '#7cd6cf', + '#9192ab', + '#7898e1', + '#efa666', + '#eddd86' + ] + }, + { + name: t('chart.color_gradual'), + value: 'gradual', + colors: [ + '#71ae46', + '#96b744', + '#c4cc38', + '#ebe12a', + '#eab026', + '#e3852b', + '#d85d2a', + '#ce2626', + '#ac2026' + ] + }, + { + name: t('chart.color_simple'), + value: 'simple', + colors: [ + '#929fff', + '#9de0ff', + '#ffa897', + '#af87fe', + '#7dc3fe', + '#bb60b2', + '#433e7c', + '#f47a75', + '#009db2' + ] + }, + { + name: t('chart.color_business'), + value: 'business', + colors: [ + '#194f97', + '#555555', + '#bd6b08', + '#00686b', + '#c82d31', + '#625ba1', + '#898989', + '#9c9800', + '#007f54' + ] + }, + { + name: t('chart.color_gentle'), + value: 'gentle', + colors: [ + '#5b9bd5', + '#ed7d31', + '#70ad47', + '#ffc000', + '#4472c4', + '#91d024', + '#b235e6', + '#02ae75', + '#5b9bd5' + ] + }, + { + name: t('chart.color_technology'), + value: 'technology', + colors: [ + '#05f8d6', + '#0082fc', + '#fdd845', + '#22ed7c', + '#09b0d3', + '#1d27c9', + '#f9e264', + '#f47a75', + '#009db2' + ] + }, + { + name: t('chart.color_light'), + value: 'light', + colors: [ + '#884898', + '#808080', + '#82ae46', + '#00a3af', + '#ef8b07', + '#007bbb', + '#9d775f', + '#fae800', + '#5f9b3c' + ] + }, + { + name: t('chart.color_classical'), + value: 'classical', + colors: [ + '#007bbb', + '#ffdb4f', + '#dd4b4b', + '#2ca9e1', + '#ef8b07', + '#4a488e', + '#82ae46', + '#dd4b4b', + '#bb9581' + ] + }, + { + name: t('chart.color_fresh'), + value: 'fresh', + colors: [ + '#5f9b3c', + '#75c24b', + '#83d65f', + '#aacf53', + '#c7dc68', + '#d8e698', + '#e0ebaf', + '#bbc8e6', + '#e5e5e5' + ] + }, + { + name: t('chart.color_energy'), + value: 'energy', + colors: [ + '#ef8b07', + '#2a83a2', + '#f07474', + '#c55784', + '#274a78', + '#7058a3', + '#0095d9', + '#75c24b', + '#808080' + ] + }, + { + name: t('chart.color_red'), + value: 'red', + colors: [ + '#ff0000', + '#ef8b07', + '#4c6cb3', + '#f8e944', + '#69821b', + '#9c5ec3', + '#00ccdf', + '#f07474', + '#bb9581' + ] + }, + { + name: t('chart.color_fast'), + value: 'fast', + colors: [ + '#fae800', + '#00c039', + '#0482dc', + '#bb9581', + '#ff7701', + '#9c5ec3', + '#00ccdf', + '#00c039', + '#ff7701' + ] + }, + { + name: t('chart.color_spiritual'), + value: 'spiritual', + colors: [ + '#00a3af', + '#4da798', + '#57baaa', + '#62d0bd', + '#6ee4d0', + '#86e7d6', + '#aeede1', + '#bde1e6', + '#e5e5e5' + ] + } +] + +export const BASE_ECHARTS_SELECT = { + itemStyle: { + shadowBlur: 2 + } +} + +export const CHART_FONT_FAMILY_ORIGIN = [ + { name: t('chart.font_family_ya_hei'), value: 'Microsoft YaHei' }, + { name: t('chart.font_family_song_ti'), value: 'SimSun, "Songti SC", STSong' }, + { name: t('chart.font_family_hei_ti'), value: 'SimHei, Helvetica' }, + { name: t('chart.font_family_kai_ti'), value: 'KaiTi, "Kaiti SC", STKaiti' } +] + +export const CHART_FONT_FAMILY_MAP_TRANS = { + 'Microsoft YaHei': 'Microsoft YaHei', + 'SimSun, "Songti SC", STSong': 'SimSun', + 'SimHei, Helvetica': 'SimHei', + 'KaiTi, "Kaiti SC", STKaiti': 'KaiTi' +} + +export const CHART_FONT_FAMILY = [ + { name: t('chart.font_family_ya_hei'), value: 'Microsoft YaHei' }, + { name: t('chart.font_family_song_ti'), value: 'SimSun' }, + { name: t('chart.font_family_hei_ti'), value: 'SimHei' }, + { name: t('chart.font_family_kai_ti'), value: 'KaiTi' } +] + +export const CHART_FONT_FAMILY_MAP:any = { + 'Microsoft YaHei': 'Microsoft YaHei', + SimSun: 'SimSun, "Songti SC", STSong', + SimHei: 'SimHei, Helvetica', + KaiTi: 'KaiTi, "Kaiti SC", STKaiti' +} + +export const CHART_FONT_LETTER_SPACE = [ + { name: '0px', value: 0 }, + { name: '1px', value: 1 }, + { name: '2px', value: 2 }, + { name: '3px', value: 3 }, + { name: '4px', value: 4 }, + { name: '5px', value: 5 }, + { name: '6px', value: 6 }, + { name: '7px', value: 7 }, + { name: '8px', value: 8 }, + { name: '9px', value: 9 }, + { name: '10px', value: 10 } +] + +export const NOT_SUPPORT_PAGE_DATASET = [ + 'kylin', + 'sqlServer', + 'es', + 'presto', + 'ds_doris', + 'StarRocks', + 'impala' +] + +export const SUPPORT_Y_M = ['y', 'y_M', 'y_M_d'] + +export const DEFAULT_MAP = { + mapPitch: 0, + lineType: 'line', + lineWidth: 1, + lineAnimate: true, + lineAnimateDuration: 4, + lineAnimateInterval: 0.5, + lineAnimateTrailLength: 0.1 +} + +export const CHART_TYPE_CONFIGS = [ + { + category: 'quota', + title: t('chart.chart_type_quota'), + display: 'show', + details: [ + { + render: 'antv', + category: 'quota', + value: 'gauge', + title: t('chart.chart_gauge'), + icon: 'gauge' + }, + { + render: 'antv', + category: 'quota', + value: 'liquid', + title: t('chart.chart_liquid'), + icon: 'liquid' + }, + { + render: 'custom', + category: 'quota', + value: 'indicator', + title: t('chart.chart_indicator'), + icon: 'indicator' + } + ] + }, + { + category: 'table', + title: t('chart.chart_type_table'), + display: 'show', + details: [ + { + render: 'antv', + category: 'table', + value: 'table-info', + title: t('chart.chart_table_info'), + icon: 'table-info' + }, + { + render: 'antv', + category: 'table', + value: 'table-normal', + title: t('chart.chart_table_normal'), + icon: 'table-normal' + }, + { + render: 'antv', + category: 'table', + value: 'table-pivot', + title: t('chart.chart_table_pivot'), + icon: 'table-pivot' + }, + { + render: 'antv', + category: 'table', + value: 't-heatmap', + title: t('chart.chart_table_heatmap'), + icon: 't-heatmap' + } + ] + }, + { + category: 'trend', + title: t('chart.chart_type_trend'), + display: 'show', + details: [ + { + render: 'antv', + category: 'trend', + value: 'line', + title: t('chart.chart_line'), + icon: 'line' + }, + { + render: 'antv', + category: 'trend', + value: 'area', + title: t('chart.chart_area'), + icon: 'area' + }, + { + render: 'antv', + category: 'trend', + value: 'area-stack', + title: t('chart.chart_area_stack'), + icon: 'area-stack' + } + ] + }, + { + category: 'compare', + title: t('chart.chart_type_compare'), + display: 'show', + details: [ + { + render: 'antv', + category: 'compare', + value: 'bar', + title: t('chart.chart_bar'), + icon: 'bar' + }, + { + render: 'antv', + category: 'compare', + value: 'bar-stack', + title: t('chart.chart_bar_stack'), + icon: 'bar-stack' + }, + { + render: 'antv', + category: 'compare', + value: 'percentage-bar-stack', + title: t('chart.chart_percentage_bar_stack'), + icon: 'percentage-bar-stack' + }, + { + render: 'antv', + category: 'compare', + value: 'bar-group', + title: t('chart.chart_bar_group'), + icon: 'bar-group' + }, + { + render: 'antv', + category: 'compare', + value: 'bar-group-stack', + title: t('chart.chart_bar_group_stack'), + icon: 'bar-group-stack' + }, + { + render: 'antv', + category: 'compare', + value: 'waterfall', + title: t('chart.chart_waterfall'), + icon: 'waterfall' + }, + { + render: 'antv', + category: 'compare', + value: 'bar-horizontal', + title: t('chart.chart_bar_horizontal'), + icon: 'bar-horizontal' + }, + { + render: 'antv', + category: 'compare', + value: 'bar-stack-horizontal', + title: t('chart.chart_bar_stack_horizontal'), + icon: 'bar-stack-horizontal' + }, + { + render: 'antv', + category: 'compare', + value: 'percentage-bar-stack-horizontal', + title: t('chart.chart_percentage_bar_stack_horizontal'), + icon: 'percentage-bar-stack-horizontal' + }, + { + render: 'antv', + category: 'compare', + value: 'bar-range', + title: t('chart.chart_bar_range'), + icon: 'bar-range' + }, + { + render: 'antv', + category: 'compare', + value: 'bidirectional-bar', + title: t('chart.chart_bidirectional_bar'), + icon: 'bidirectional-bar' + }, + { + render: 'antv', + category: 'compare', + value: 'progress-bar', + title: t('chart.chart_progress_bar'), + icon: 'progress-bar' + }, + { + render: 'antv', + category: 'trend', + value: 'stock-line', + title: t('chart.chart_stock_line'), + icon: 'stock-line' + } + ] + }, + { + category: 'distribute', + title: t('chart.chart_type_distribute'), + display: 'show', + details: [ + { + render: 'antv', + category: 'distribute', + value: 'pie', + title: t('chart.chart_pie'), + icon: 'pie' + }, + { + render: 'antv', + category: 'distribute', + value: 'pie-donut', + title: t('chart.chart_pie_donut'), + icon: 'pie-donut' + }, + { + render: 'antv', + category: 'distribute', + value: 'pie-rose', + title: t('chart.chart_pie_rose'), + icon: 'pie-rose' + }, + { + render: 'antv', + category: 'distribute', + value: 'pie-donut-rose', + title: t('chart.chart_pie_donut_rose'), + icon: 'pie-donut-rose' + }, + { + render: 'antv', + category: 'chart.chart_type_distribute', + value: 'radar', + title: t('chart.chart_radar'), + icon: 'radar' + }, + { + render: 'antv', + category: 'distribute', + value: 'treemap', + title: t('chart.chart_treemap'), + icon: 'treemap' + }, + { + render: 'antv', + category: 'distribute', + value: 'word-cloud', + title: t('chart.chart_word_cloud'), + icon: 'word-cloud' + } + ] + }, + { + category: 'map', + title: t('chart.chart_type_space'), + display: 'show', + details: [ + { + render: 'antv', + category: 'map', + value: 'map', + title: t('chart.chart_map'), + icon: 'map' + }, + { + render: 'antv', + category: 'map', + value: 'bubble-map', + title: t('chart.chart_bubble_map'), + icon: 'bubble-map' + }, + { + render: 'antv', + category: 'map', + value: 'flow-map', + title: t('chart.chart_flow_map'), + icon: 'flow-map' + }, + { + render: 'antv', + category: 'map', + value: 'heat-map', + title: t('chart.chart_heat_map'), + icon: 'heat-map' + }, + { + render: 'antv', + category: 'map', + value: 'symbolic-map', + title: t('chart.chart_symbolic_map'), + icon: 'symbolic-map' + } + ] + }, + { + category: 'relation', + title: t('chart.chart_type_relation'), + display: 'show', + details: [ + { + render: 'antv', + category: 'distribute', + value: 'scatter', + title: t('chart.chart_scatter'), + icon: 'scatter' + }, + { + render: 'antv', + category: 'distribute', + value: 'quadrant', + title: t('chart.chart_quadrant'), + icon: 'quadrant' + }, + { + render: 'antv', + category: 'distribute', + value: 'funnel', + title: t('chart.chart_funnel'), + icon: 'funnel' + }, + { + render: 'antv', + category: 'relation', + value: 'sankey', + title: t('chart.chart_sankey'), + icon: 'sankey' + }, + { + render: 'antv', + category: 'distribute', + value: 'circle-packing', + title: t('chart.chart_circle_packing'), + icon: 'circle-packing' + } + ] + }, + { + category: 'dual_axes', + title: t('chart.chart_type_dual_axes'), + display: 'show', + details: [ + { + render: 'antv', + category: 'dual_axes', + value: 'chart-mix', + title: t('chart.chart_mix'), + icon: 'chart-mix' + }, + { + render: 'antv', + category: 'dual_axes', + value: 'chart-mix-group', + title: t('chart.chart_mix_group_column'), + icon: 'chart-mix-group' + }, + { + render: 'antv', + category: 'dual_axes', + value: 'chart-mix-stack', + title: t('chart.chart_mix_stack_column'), + icon: 'chart-mix-stack' + }, + { + render: 'antv', + category: 'dual_axes', + value: 'chart-mix-dual-line', + title: t('chart.chart_mix_dual_line'), + icon: 'chart-mix-dual-line' + } + ] + }, + { + category: 'other', + title: t('datasource.other'), + display: 'hidden', + details: [ + { + render: 'custom', + category: 'quota', + value: 'rich-text', + title: t('visualization.rich_text'), + icon: 'rich-text' + }, + { + render: 'custom', + category: 'quota', + value: 'picture-group', + title: t('visualization.picture_group'), + icon: 'picture-group' + } + ] + } +] + +export const DEFAULT_BASIC_STYLE: ChartBasicStyle = { + alpha: 100, + tableBorderColor: '#CCCCCC', + tableScrollBarColor: '#1f23294d', + tableColumnMode: 'adapt', + tableColumnWidth: 100, + tableFieldWidth: [], + tablePageMode: 'page', + tablePageStyle: 'simple', + tablePageSize: 20, + gaugeStyle: 'default', + colorScheme: 'default', + colors: [ + '#5470c6', + '#91cc75', + '#fac858', + '#ee6666', + '#73c0de', + '#3ba272', + '#fc8452', + '#9a60b4', + '#ea7ccc' + ], + mapVendor: 'amap', + gradient: false, + lineWidth: 2, + lineSymbol: 'circle', + lineSymbolSize: 4, + lineSmooth: true, + barDefault: true, + radiusColumnBar: 'rightAngle', + columnBarRightAngleRadius: 20, + columnWidthRatio: 60, + barWidth: 40, + barGap: 0.4, + lineType: 'solid', + scatterSymbol: 'circle', + scatterSymbolSize: 8, + radarShape: 'polygon', + mapStyle: 'normal', + heatMapType: 'heatmap', + heatMapIntensity: 2, + heatMapRadius: 20, + areaBorderColor: '#EBEEF5', + areaBaseColor: '#ffffff', + mapSymbolOpacity: 0.7, + mapSymbolStrokeWidth: 2, + mapSymbol: 'circle', + mapSymbolSize: 6, + radius: 80, + innerRadius: 60, + showZoom: true, + zoomButtonColor: '#aaa', + zoomBackground: '#fff', + tableLayoutMode: 'grid', + calcTopN: false, + topN: 5, + topNLabel: t('datasource.other'), + gaugeAxisLine: true, + gaugePercentLabel: true, + showSummary: false, + summaryLabel: t('chart.total_show'), + seriesColor: [], + layout: 'horizontal', + mapSymbolSizeMin: 4, + mapSymbolSizeMax: 30, + showLabel: true, + mapStyleUrl: '', + autoFit: true, + mapCenter: { + longitude: 117.232, + latitude: 39.354 + }, + zoomLevel: 7, + customIcon: '', + showHoverStyle: true, + autoWrap: false, + maxLines: 3, + radarShowPoint: true, + radarPointSize: 4, + radarAreaColor: true, + circleBorderColor: '#fff', + circleBorderWidth: 0, + circlePadding: 0 +} + +export const BASE_VIEW_CONFIG = { + id: '', // 图表id + title: t('data_set.view'), + sceneId: 0, // 仪表板id + tableId: '', // 数据集id + type: 'bar', + render: 'antv', + resultCount: 1000, + resultMode: 'custom', + refreshViewEnable: false, + refreshTime: 5, + refreshUnit: 'minute', + xAxis: [], + xAxisExt: [], + yAxis: [], + yAxisExt: [], + extStack: [], + drillFields: [], + viewFields: [], + extBubble: [], + extLabel: [], + extTooltip: [], + customFilter: {}, + sortPriority: [], + customAttr: { + basicStyle: DEFAULT_BASIC_STYLE, + misc: DEFAULT_MISC, + label: DEFAULT_LABEL, + tooltip: DEFAULT_TOOLTIP, + tableTotal: DEFAULT_TABLE_TOTAL, + tableHeader: DEFAULT_TABLE_HEADER, + tableCell: DEFAULT_TABLE_CELL, + indicator: DEFAULT_INDICATOR_STYLE, + indicatorName: DEFAULT_INDICATOR_NAME_STYLE, + map: { + id: '', + level: 'world' + } + }, + customStyle: { + text: DEFAULT_TITLE_STYLE, + legend: DEFAULT_LEGEND_STYLE, + xAxis: DEFAULT_XAXIS_STYLE, + yAxis: DEFAULT_YAXIS_STYLE, + yAxisExt: DEFAULT_YAXIS_EXT_STYLE, + misc: DEFAULT_MISC_STYLE + }, + senior: { + functionCfg: DEFAULT_FUNCTION_CFG, + assistLineCfg: DEFAULT_ASSIST_LINE_CFG, + threshold: DEFAULT_THRESHOLD, + scrollCfg: DEFAULT_SCROLL, + areaMapping: {}, + bubbleCfg: DEFAULT_BUBBLE_ANIMATE + }, + flowMapStartName: [], + flowMapEndName: [] +} + +export function getScaleValue(propValue, scale) { + const propValueTemp = Math.round(propValue * scale) + return propValueTemp > 1 ? propValueTemp : 1 +} + +export function getViewConfig(name) { + let viewConfigResult = null + CHART_TYPE_CONFIGS.forEach(category => { + category.details.forEach(viewConfig => { + if (viewConfig.value === name) { + viewConfigResult = deepCopy(viewConfig) + } + }) + }) + return viewConfigResult +} diff --git a/frontend/src/data-visualization/chart/components/editor/util/dataVisualization.ts b/frontend/src/data-visualization/chart/components/editor/util/dataVisualization.ts new file mode 100644 index 0000000..93b6919 --- /dev/null +++ b/frontend/src/data-visualization/chart/components/editor/util/dataVisualization.ts @@ -0,0 +1,142 @@ +export const VIEW_DETAILS_BASH_STYLE = + '{"id":"view-dialog-details-001","title":"图表明细","sceneId":0,"tableId":"1692381412250939392","type":"table-info","render":"antv","resultCount":1000,"resultMode":"all","refreshViewEnable":false,"refreshTime":5,"refreshUnit":"minute","xAxis":[{"id":"1692330126490","datasourceId":"1691734038709071872","datasetTableId":"7098147058204282880","datasetGroupId":"1692381412250939392","chartId":null,"originName":"月","name":"月","dbFieldName":null,"description":null,"dataeaseName":"f_dd62e53a9192cdf4","groupType":"d","type":"ANY","precision":null,"scale":null,"deType":0,"deExtractType":0,"extField":0,"checked":true,"columnIndex":null,"lastSyncTime":null,"dateFormat":null,"dateFormatType":null,"fieldShortName":"f_dd62e53a9192cdf4","summary":null,"sort":"none","dateStyle":"y_M_d","datePattern":"date_sub","chartType":null,"compareCalc":null,"logic":null,"filterType":null,"index":null,"formatterCfg":null,"chartShowName":null,"filter":[],"customSort":null,"busiType":null},{"id":"1692330126489","datasourceId":"1691734038709071872","datasetTableId":"7098147058204282880","datasetGroupId":"1692381412250939392","chartId":null,"originName":"年份","name":"年份","dbFieldName":null,"description":null,"dataeaseName":"f_190480c43bdda8df","groupType":"q","type":"BIGINT","precision":null,"scale":null,"deType":2,"deExtractType":2,"extField":0,"checked":true,"columnIndex":null,"lastSyncTime":null,"dateFormat":null,"dateFormatType":null,"fieldShortName":"f_190480c43bdda8df","summary":"sum","sort":"none","dateStyle":"y_M_d","datePattern":"date_sub","chartType":"bar","compareCalc":{"type":"none","resultData":"percent","field":null,"custom":null},"logic":null,"filterType":null,"index":null,"formatterCfg":{"type":"auto","unit":1,"suffix":"","decimalCount":2,"thousandSeparator":true},"chartShowName":null,"filter":[],"customSort":null,"busiType":null}],"xAxisExt":[],"yAxis":[],"yAxisExt":[],"extStack":[],"drillFields":[],"viewFields":[],"extBubble":[],"extLabel":[],"extTooltip":[],"customFilter":{},"customAttr":{"basicStyle":{"alpha":100,"tableBorderColor":"#E6E7E4","tableScrollBarColor":"#00000024","tableColumnMode":"adapt","tableColumnWidth":100,"tablePageMode":"pull","tablePageSize":20,"gaugeStyle":"default","colorScheme":"default","colors":["#5470c6","#91cc75","#fac858","#ee6666","#73c0de","#3ba272","#fc8452","#9a60b4","#ea7ccc"],"mapVendor":"amap","gradient":false,"lineWidth":2,"lineSymbol":"circle","lineSymbolSize":4,"lineSmooth":true,"barDefault":true,"barWidth":40,"barGap":0.4,"lineType":"solid","scatterSymbol":"circle","scatterSymbolSize":8,"radarShape":"polygon","mapStyle":"normal","areaBorderColor":"#303133","suspension":true,"areaBaseColor":"#FFFFFF","mapSymbolOpacity":0.7,"mapSymbolStrokeWidth":2,"mapSymbol":"circle","mapSymbolSize":20,"radius":100,"innerRadius":60},"misc":{"pieInnerRadius":0,"pieOuterRadius":80,"radarShape":"polygon","radarSize":80,"gaugeMinType":"fix","gaugeMinField":{"id":"","summary":""},"gaugeMin":0,"gaugeMaxType":"fix","gaugeMaxField":{"id":"","summary":""},"gaugeMax":100,"gaugeStartAngle":225,"gaugeEndAngle":-45,"nameFontSize":18,"valueFontSize":18,"nameValueSpace":10,"valueFontColor":"#5470c6","valueFontFamily":"Microsoft YaHei","valueFontIsBolder":false,"valueFontIsItalic":false,"valueLetterSpace":0,"valueFontShadow":false,"showName":true,"nameFontColor":"#000000","nameFontFamily":"Microsoft YaHei","nameFontIsBolder":false,"nameFontIsItalic":false,"nameLetterSpace":"0","nameFontShadow":false,"treemapWidth":80,"treemapHeight":80,"liquidMax":100,"liquidMaxType":"fix","liquidMaxField":{"id":"","summary":""},"liquidSize":80,"liquidShape":"circle","hPosition":"center","vPosition":"center","mapPitch":0,"mapLineType":"arc","mapLineWidth":1,"mapLineAnimateDuration":3,"mapLineGradient":false,"mapLineSourceColor":"#146C94","mapLineTargetColor":"#576CBC"},"label":{"show":false,"position":"top","color":"#000000","fontSize":10,"formatter":"","labelLine":{"show":true},"labelFormatter":{"type":"auto","unit":1,"suffix":"","decimalCount":2,"thousandSeparator":true},"reserveDecimalCount":2,"labelShadow":false,"labelBgColor":"","labelShadowColor":"","quotaLabelFormatter":{"type":"auto","unit":1,"suffix":"","decimalCount":2,"thousandSeparator":true},"showDimension":true,"showQuota":false,"showProportion":true,"seriesLabelFormatter":[]},"tooltip":{"show":true,"trigger":"item","confine":true,"fontSize":10,"color":"#000000","tooltipFormatter":{"type":"auto","unit":1,"suffix":"","decimalCount":2,"thousandSeparator":true},"backgroundColor":"#FFFFFF","seriesTooltipFormatter":[]},"tableTotal":{"row":{"showGrandTotals":true,"showSubTotals":true,"reverseLayout":false,"reverseSubLayout":false,"label":"总计","subLabel":"小计","subTotalsDimensions":[],"calcTotals":{"aggregation":"SUM"},"calcSubTotals":{"aggregation":"SUM"},"totalSort":"none","totalSortField":""},"col":{"showGrandTotals":true,"showSubTotals":true,"reverseLayout":false,"reverseSubLayout":false,"label":"总计","subLabel":"小计","subTotalsDimensions":[],"calcTotals":{"aggregation":"SUM"},"calcSubTotals":{"aggregation":"SUM"},"totalSort":"none","totalSortField":""}},"tableHeader":{"indexLabel":"序号","showIndex":false,"tableHeaderAlign":"left","tableHeaderBgColor":"#F5F6F7","tableHeaderFontColor":"#646A73","tableTitleFontSize":14,"tableTitleHeight":36},"tableCell":{"tableFontColor":"#1F2329","tableItemAlign":"right","tableItemBgColor":"#FFFFFF","tableItemFontSize":14,"tableItemHeight":36},"map":{"id":"","level":"world"}},"customStyle":{"text":{"show":false,"fontSize":"18","hPosition":"left","vPosition":"top","isItalic":false,"isBolder":true,"remarkShow":false,"remark":"","fontFamily":"Microsoft YaHei","letterSpace":"0","fontShadow":false,"color":"#000000","remarkBackgroundColor":"#ffffff"},"legend":{"show":true,"hPosition":"center","vPosition":"bottom","orient":"horizontal","icon":"circle","color":"#000000","fontSize":12},"xAxis":{"show":true,"position":"bottom","name":"","color":"#000000","fontSize":12,"axisLabel":{"show":true,"color":"#000000","fontSize":12,"rotate":0,"formatter":"{value}"},"axisLine":{"show":true,"lineStyle":{"color":"#cccccc","width":1,"style":"solid"}},"splitLine":{"show":false,"lineStyle":{"color":"#CCCCCC","width":1,"style":"solid"}},"axisValue":{"auto":true,"min":10,"max":100,"split":10,"splitCount":10},"axisLabelFormatter":{"type":"auto","unit":1,"suffix":"","decimalCount":2,"thousandSeparator":true}},"yAxis":{"show":true,"position":"left","name":"","color":"#000000","fontSize":12,"axisLabel":{"show":true,"color":"#000000","fontSize":12,"rotate":0,"formatter":"{value}"},"axisLine":{"show":false,"lineStyle":{"color":"#cccccc","width":1,"style":"solid"}},"splitLine":{"show":true,"lineStyle":{"color":"#CCCCCC","width":1,"style":"solid"}},"axisValue":{"auto":true,"min":10,"max":100,"split":10,"splitCount":10},"axisLabelFormatter":{"type":"auto","unit":1,"suffix":"","decimalCount":2,"thousandSeparator":true}},"yAxisExt":{"show":true,"position":"right","name":"","color":"#000000","fontSize":12,"axisLabel":{"show":true,"color":"#000000","fontSize":12,"rotate":0,"formatter":"{value}"},"axisLine":{"show":false,"lineStyle":{"color":"#cccccc","width":1,"style":"solid"}},"splitLine":{"show":true,"lineStyle":{"color":"#CCCCCC","width":1,"style":"solid"}},"axisValue":{"auto":true,"min":null,"max":null,"split":null,"splitCount":null},"axisLabelFormatter":{"type":"auto","unit":1,"suffix":"","decimalCount":2,"thousandSeparator":true}},"misc":{"showName":false,"color":"#000000","fontSize":12,"axisColor":"#999","splitNumber":5,"axisLine":{"show":true,"lineStyle":{"color":"#CCCCCC","width":1,"type":"solid"}},"axisTick":{"show":false,"length":5,"lineStyle":{"color":"#000000","width":1,"type":"solid"}},"axisLabel":{"show":false,"rotate":0,"margin":8,"color":"#000000","fontSize":"12","formatter":"{value}"},"splitLine":{"show":true,"lineStyle":{"color":"#CCCCCC","width":1,"type":"solid"}},"splitArea":{"show":true}}},"senior":{"functionCfg":{"sliderShow":false,"sliderRange":[0,10],"sliderBg":"#FFFFFF","sliderFillBg":"#BCD6F1","sliderTextColor":"#999999","emptyDataStrategy":"breakLine","emptyDataFieldCtrl":[]},"assistLine":[],"threshold":{"gaugeThreshold":"","labelThreshold":[],"tableThreshold":[],"textLabelThreshold":[]},"scrollCfg":{"open":false,"row":1,"interval":2000,"step":50}},"chartExtRequest":{"user":"1","filter":[],"drill":[],"resultCount":1000,"resultMode":"all"}}' + +import { + DEFAULT_COLOR_CASE_DARK, + DEFAULT_COLOR_CASE_LIGHT, + DEFAULT_TITLE_STYLE_DARK, + DEFAULT_TITLE_STYLE_LIGHT, + FILTER_COMMON_STYLE_DARK, + FILTER_COMMON_STYLE_LIGHT, + SENIOR_STYLE_SETTING_DARK, + SENIOR_STYLE_SETTING_LIGHT, + TAB_COMMON_STYLE_DARK, + TAB_COMMON_STYLE_LIGHT +} from '@/data-visualization/chart/components/editor/util/chart' +import { + COMMON_COMPONENT_BACKGROUND_DARK, + COMMON_COMPONENT_BACKGROUND_LIGHT, + COMMON_COMPONENT_BACKGROUND_SCREEN_DARK +} from '@/data-visualization/custom-component/component-list' + +export const PANEL_CHART_INFO_LIGHT = { + chartTitle: DEFAULT_TITLE_STYLE_LIGHT, + chartColor: DEFAULT_COLOR_CASE_LIGHT, + chartCommonStyle: COMMON_COMPONENT_BACKGROUND_LIGHT, + filterStyle: FILTER_COMMON_STYLE_LIGHT, + tabStyle: TAB_COMMON_STYLE_LIGHT, + seniorStyleSetting: SENIOR_STYLE_SETTING_LIGHT +} + +export const PANEL_CHART_INFO_DARK = { + chartTitle: DEFAULT_TITLE_STYLE_DARK, + chartColor: DEFAULT_COLOR_CASE_DARK, + chartCommonStyle: COMMON_COMPONENT_BACKGROUND_DARK, + filterStyle: FILTER_COMMON_STYLE_DARK, + tabStyle: TAB_COMMON_STYLE_DARK, + seniorStyleSetting: SENIOR_STYLE_SETTING_DARK +} + +export const PANEL_CHART_INFO_SCREEN_DARK = { + ...PANEL_CHART_INFO_DARK, + chartCommonStyle: COMMON_COMPONENT_BACKGROUND_SCREEN_DARK +} + +export const MOBILE_SETTING_BASE = { + customSetting: false, + imageUrl: null, + backgroundType: 'image' +} + +export const MOBILE_SETTING_LIGHT = { + ...MOBILE_SETTING_BASE, + color: '#000' +} + +export const MOBILE_SETTING_DARK = { + ...MOBILE_SETTING_BASE, + color: '#fff' +} + +export const DEFAULT_DASHBOARD_STYLE_BASE = { + gap: 'yes', + gapSize: 5, + showGrid: false, + matrixBase: 4, // 当前matrix的基数 (是pcMatrixCount的几倍) + resultMode: 'all', // 图表结果显示模式 all 图表 custom 仪表板自定义 + resultCount: 1000 // 图表结果显示条数 +} + +export const DEFAULT_DASHBOARD_STYLE_LIGHT = { + ...DEFAULT_DASHBOARD_STYLE_BASE, + themeColor: 'light', + mobileSetting: MOBILE_SETTING_LIGHT +} + +export const DEFAULT_DASHBOARD_STYLE_DARK = { + ...DEFAULT_DASHBOARD_STYLE_BASE, + themeColor: 'dark', + mobileSetting: MOBILE_SETTING_DARK +} + +export const DEFAULT_CANVAS_STYLE_DATA_BASE = { + width: 1920, + height: 1080, + refreshBrowserEnable: false, // 开启浏览器刷新(默认关闭) + refreshBrowserUnit: 'minute', // 仪表板刷新时间带外 默认 分钟 + refreshBrowserTime: 5, // 仪表板刷新时间 默认5分钟 + refreshViewEnable: false, // 开启图表刷新(默认关闭) + refreshViewLoading: true, // 仪表板图表loading提示 + refreshUnit: 'minute', // 仪表板刷新时间带外 默认 分钟 + refreshTime: 5, // 仪表板刷新时间 默认5分钟 + popupAvailable: true, // 弹窗区域是否可用 默认为true + popupButtonAvailable: true, // 弹框区域显示按钮是否可用 默认为true + suspensionButtonAvailable: false, // 悬浮按钮是否可用 默认false + screenAdaptor: 'widthFirst', // 屏幕适配方式 widthFirst=宽度优先 heightFirst=高度优先 full=铺满全屏 keepSize=不缩放 + dashboardAdaptor: 'keepHeightAndWidth', //仪表板预览展示适配方式 keepHeightAndWidth=高度宽度独立缩放(默认模式),withWidth=跟随宽度 + scale: 60, + scaleWidth: 60, + scaleHeight: 60, + backgroundColorSelect: true, + backgroundImageEnable: false, + backgroundType: 'backgroundColor', // 废弃 + background: '', + openCommonStyle: true, + opacity: 1, // 废弃 + fontSize: 14, + fontFamily: 'PingFang' //字体设置 默认PingFang +} + +// 基础亮色主题 +export const DEFAULT_CANVAS_STYLE_DATA_LIGHT = { + ...DEFAULT_CANVAS_STYLE_DATA_BASE, + // 页面全局数据 + themeId: '10001', + color: '#000000', + backgroundColor: '#f5f6f7', + dashboard: DEFAULT_DASHBOARD_STYLE_LIGHT, + component: PANEL_CHART_INFO_LIGHT +} + +// 基础暗色主题 +export const DEFAULT_CANVAS_STYLE_DATA_DARK = { + ...DEFAULT_CANVAS_STYLE_DATA_BASE, + // 页面全局数据 + themeId: '10002', + color: '#fff', + backgroundColor: '#020408', + dashboard: DEFAULT_DASHBOARD_STYLE_DARK, + component: PANEL_CHART_INFO_DARK +} + +// 大屏基础暗色主题 +export const DEFAULT_CANVAS_STYLE_DATA_SCREEN_DARK = { + ...DEFAULT_CANVAS_STYLE_DATA_DARK, + component: PANEL_CHART_INFO_SCREEN_DARK +} + +// 基础主题 +export const BASE_THEMES = { + light: DEFAULT_CANVAS_STYLE_DATA_LIGHT, + dark: DEFAULT_CANVAS_STYLE_DATA_DARK +} diff --git a/frontend/src/data-visualization/chart/components/js/extremumUitl.ts b/frontend/src/data-visualization/chart/components/js/extremumUitl.ts new file mode 100644 index 0000000..6413f62 --- /dev/null +++ b/frontend/src/data-visualization/chart/components/js/extremumUitl.ts @@ -0,0 +1,392 @@ +import { valueFormatter } from '@/data-visualization/chart/components/js/formatter' +import { hexToRgba, parseJson } from '@/data-visualization/chart/components/js/util' +import { isEmpty } from 'lodash-es' + +export const clearExtremum = chart => { + // 清除图表标注 + const pointElement = document.getElementById(chartPointParentId(chart)) + if (pointElement) { + pointElement.remove() + pointElement.parentNode?.removeChild(pointElement) + } +} + +/** + * 判断给定的RGBA字符串表示的颜色是亮色还是暗色 + * 通过计算RGB颜色值的加权平均值(灰度值),判断颜色的明暗 + * 如果给定的字符串不包含有效的RGBA值,则原样返回该字符串 + * + * @param rgbaString 一个RGBA颜色字符串,例如 "rgba(255, 255, 255, 1)" + * @param greyValue 灰度值默认128 + * @returns 如果计算出的灰度值大于等于128,则返回true,表示亮色;否则返回false,表示暗色。 + * 如果rgbaString不包含有效的RGBA值,则返回原字符串 + */ +const isColorLight = (rgbaString: string, greyValue = 128) => { + const lastRGBA = getRgbaColorLastRgba(rgbaString) + if (!isEmpty(lastRGBA)) { + // 计算灰度值的公式 + const grayLevel = lastRGBA.r * 0.299 + lastRGBA.g * 0.587 + lastRGBA.b * 0.114 + return grayLevel >= greyValue + } else { + return false + } +} + +/** + * 从给定的rgba颜色字符串中提取最后一个rgba值 + * @param rgbaString 包含一个或多个rgba颜色值的字符串 + * @returns 返回最后一个解析出的rgba对象,如果未找到rgba值,则返回null + */ +const getRgbaColorLastRgba = (rgbaString: string) => { + const rgbaPattern = /rgba\((\d+),\s*(\d+),\s*(\d+),\s*([\d.]+)\)/g + let match: string[] + let lastRGBA = null + while ((match = rgbaPattern.exec(rgbaString)) !== null) { + const r = parseInt(match[1]) + const g = parseInt(match[2]) + const b = parseInt(match[3]) + const a = parseFloat(match[4]) + lastRGBA = { r, g, b, a } + } + return lastRGBA +} + +function createExtremumDiv(id, value, formatterCfg, chart) { + // 空值不处理 + if (!value && value != 0) { + return + } + // 装标注的div + const parentElement = document.getElementById(chartPointParentId(chart)) + if (parentElement) { + // 标注div + const oldElement = document.getElementById(id) + if (oldElement) { + oldElement.remove() + oldElement.parentNode?.removeChild(oldElement) + } + const div = document.createElement('div') + div.id = id + div.className = 'child' + div.setAttribute( + 'style', + `width: auto; + height: auto; + border-radius: 2px; + position: relative; + padding: 4px 5px 4px 5px; + display:none; + transform: translateX(-50%); + opacity: 1; + transition: opacity 0.2s ease-in-out; + white-space:nowrap;` + ) + div.textContent = valueFormatter(value, formatterCfg) + const span = document.createElement('span') + span.setAttribute( + 'style', + `width: 0px; + height: 0px; + border: 4px solid transparent; + border-top-color: red; + position: absolute; + left: calc(50% - 4px); + margin-top:4px;` + ) + div.appendChild(span) + parentElement.appendChild(div) + } +} +/** + * 没有子类别字段的图表 + * @param chart + */ +const noChildrenFieldChart = chart => { + return ['area', 'bar'].includes(chart.type) +} + +/** + * 支持最值图表的折线图,面积图,柱状图,分组柱状图 + * @param chart + */ +const supportExtremumChartType = chart => { + return ['line', 'area', 'bar', 'bar-group'].includes(chart.type) +} + +const chartContainerId = chart => { + return chart.container + '_' +} + +const chartPointParentId = chart => { + return chart.container + '_point_' + chart.id + '_' +} + +function removeDivsWithPrefix(parentDivId, prefix) { + const parentDiv = document.getElementById(parentDivId) + if (!parentDiv) { + console.error('Parent div not found') + return + } + const childDivs = parentDiv.getElementsByTagName('div') + for (let i = childDivs.length - 1; i >= 0; i--) { + const div = childDivs[i] + if (div.id && div.id.startsWith(prefix)) { + div.parentNode.removeChild(div) + } + } +} + +export const extremumEvt = (newChart, chart, _options, container) => { + chart.container = container + if (!supportExtremumChartType(chart)) { + clearExtremum(chart) + return + } + const { label: labelAttr } = parseJson(chart.customAttr) + const { yAxis } = parseJson(chart) + newChart.once('beforerender', ev => { + ev.view.on('beforepaint', () => { + newChart.chart.geometries[0]?.beforeMappingData.forEach(i => { + i.forEach(item => { + delete item._origin.EXTREME + }) + const { minItem, maxItem } = findMinMax(i.filter(item => item._origin.value)) + if (!minItem || !maxItem) { + return + } + let showExtremum = false + if (noChildrenFieldChart(chart) || yAxis.length > 1) { + const seriesLabelFormatter = labelAttr.seriesLabelFormatter.find( + d => + (d.chartShowName ? d.chartShowName : d.name === minItem._origin.category) || + (d.chartShowName ? d.chartShowName : d.name === maxItem._origin.category) + ) + showExtremum = seriesLabelFormatter?.showExtremum + } else { + if (['bar-group'].includes(chart.type)) { + showExtremum = labelAttr.showExtremum + } else { + showExtremum = labelAttr.seriesLabelFormatter[0]?.showExtremum + } + } + if (showExtremum) { + minItem._origin.EXTREME = true + maxItem._origin.EXTREME = true + } + }) + }) + newChart.chart.geometries[0].on('afteranimate', () => { + createExtremumPoint(chart, ev) + }) + }) + newChart.on('legend-item:click', ev => { + const legendHideData = ev.view + .getController('legend') + .components[0].component.cfg.items.filter(l => l.unchecked) + if (legendHideData.length > 0) { + legendHideData.forEach(l => { + const seriesKey = chartContainerId(chart) + chartPointParentId(chart) + l.id + removeDivsWithPrefix(chartPointParentId(chart), seriesKey) + }) + } + }) +} + +const findMinMax = (data): { minItem; maxItem } => { + return data.reduce( + ({ minItem, maxItem }, currentItem) => { + if (minItem === undefined || currentItem._origin.value < minItem._origin.value) { + minItem = currentItem + } + if (maxItem === undefined || currentItem._origin.value > maxItem._origin.value) { + maxItem = currentItem + } + delete minItem?._origin.EXTREME + delete maxItem?._origin.EXTREME + return { minItem, maxItem } + }, + { minItem: undefined, maxItem: undefined } + ) +} +export const createExtremumPoint = (chart, ev) => { + // 获取标注样式 + const { label: labelAttr, basicStyle } = parseJson(chart.customAttr) + const pointSize = basicStyle.lineSymbolSize + const { yAxis } = parseJson(chart) + clearExtremum(chart) + // 创建标注父元素 + const divParentElement = document.getElementById(chartPointParentId(chart)) + if (!divParentElement) { + const divParent = document.createElement('div') + divParent.id = chartPointParentId(chart) + divParent.style.position = 'fixed' + divParent.style.zIndex = '1' + divParent.style.opacity = '0' + divParent.style.transition = 'opacity 0.2s ease-in-out' + // 将父标注加入到图表中 + const containerElement = document.getElementById(chart.container) + containerElement.insertBefore(divParent, containerElement.firstChild) + // 处理最值闪烁的问题 + let opacity = 0 + const animate = () => { + // 增加不透明度 + opacity += 0.19 + if (opacity >= 1) { + cancelAnimationFrame(animationFrameId) + return + } + divParent.style.opacity = opacity + '' + animationFrameId = requestAnimationFrame(animate) + } + let animationFrameId = requestAnimationFrame(animate) + } + let geometriesDataArray = [] + // 获取数据点 + const intervalPoint = ev.view + .getGeometries() + .find((intervalItem: { type: string }) => intervalItem.type === 'interval') + if (intervalPoint) { + geometriesDataArray = intervalPoint.dataArray + } + const pointPoint = ev.view + .getGeometries() + .find((pointItem: { type: string }) => pointItem.type === 'point') + if (pointPoint) { + geometriesDataArray = pointPoint.dataArray + } + performChunk(geometriesDataArray, pointObjList => { + if (pointObjList && pointObjList.length > 0) { + const pointObj = pointObjList[0] + const [minItem, maxItem] = pointObjList.filter(i => i._origin.EXTREME) + let attr + let showExtremum = false + if (noChildrenFieldChart(chart) || yAxis.length > 1) { + const seriesLabelFormatter = labelAttr.seriesLabelFormatter.find(d => + d.chartShowName + ? d.chartShowName === pointObj._origin.category + : d.name === pointObj._origin.category + ) + showExtremum = seriesLabelFormatter?.showExtremum + attr = seriesLabelFormatter + } else { + if (['bar-group'].includes(chart.type)) { + showExtremum = labelAttr.showExtremum + } else { + showExtremum = labelAttr.seriesLabelFormatter[0]?.showExtremum + attr = labelAttr.seriesLabelFormatter[0] + } + } + const fontSize = attr ? attr.fontSize : labelAttr.fontSize + if (!minItem) { + return + } + const maxKey = + chartContainerId(chart) + + chartPointParentId(chart) + + pointObj._origin.category + + '_' + + (maxItem ? maxItem._origin.value : minItem._origin.value) + const minKey = + chartContainerId(chart) + + chartPointParentId(chart) + + pointObj._origin.category + + '_' + + minItem._origin.value + // 最值标注 + if (showExtremum && labelAttr.show) { + if (maxItem) { + createExtremumDiv( + maxKey, + maxItem._origin.value, + attr ? attr.formatterCfg : labelAttr.labelFormatter, + chart + ) + } + createExtremumDiv( + minKey, + minItem._origin.value, + attr ? attr.formatterCfg : labelAttr.labelFormatter, + chart + ) + pointObjList.forEach(point => { + const pointElement = document.getElementById( + chartContainerId(chart) + + chartPointParentId(chart) + + point._origin.category + + '_' + + point._origin.value + ) + if (pointElement && point._origin.EXTREME) { + pointElement.style.position = 'absolute' + const top = + (point.y[1] ? point.y[1] : point.y) - (fontSize + (pointSize ? pointSize : 0) + 12) + pointElement.style.top = top + 'px' + pointElement.style.left = point.x + 'px' + pointElement.style.zIndex = '10' + pointElement.style.fontSize = fontSize + 'px' + pointElement.style.lineHeight = fontSize + 'px' + // 渐变颜色时需要获取最后一个rgba的值作为背景 + const color = point.color.startsWith('#') + ? hexToRgba(point.color, basicStyle.alpha / 100) + : getRgbaColorLastRgba(point.color) + const { r, b, g, a } = color + pointElement.style.backgroundColor = 'rgba(' + r + ',' + g + ',' + b + ',' + a + ')' + pointElement.style.color = isColorLight(point.color) ? '#000' : '#fff' + pointElement.children[0]['style'].borderTopColor = + 'rgba(' + r + ',' + g + ',' + b + ',' + a + ')' + pointElement.style.display = 'table' + // 显示箭头 + const childNode = pointElement.childNodes[1] + // 最值在数据点下方显示 + const translateYValue = Math.ceil(point.y + Math.abs(Math.floor(top)) + 6) + // 最值dom高度超过50%时,最值dom向下 + if (top < 0 && (Math.abs(top) / point.y) * 100 >= 50) { + pointElement.style.transform = `translateX(-50%) translateY(${translateYValue}px)` + childNode.style.marginTop = '-12px' + childNode.style.transform = 'rotate(180deg)' + } else { + childNode.style.display = 'block' + } + } + }) + } else { + removeDivElement(maxKey) + removeDivElement(minKey) + } + } + }) +} + +function removeDivElement(key) { + const element = document.getElementById(key) + if (element) { + element.remove() + element.parentNode?.removeChild(element) + } +} + +/** + * 用于分批处理数据,利用requestIdleCallback在浏览器空闲期间执行任务,避免阻塞主线程 + * @param dataList + * @param taskHandler + */ +function performChunk(dataList, taskHandler) { + if (typeof dataList === 'number') { + dataList = { length: dataList } + } + if (dataList.length === 0) return + let i = 0 + function _run() { + if (i >= dataList.length) return + // 请求浏览器空闲期间执行的回调函数 + requestIdleCallback(idle => { + // 在当前空闲期间内尽可能多地处理任务,直到时间耗尽或所有任务处理完毕 + while (idle.timeRemaining() > 0 && i < dataList.length) { + taskHandler(dataList[i], i) + i++ + } + _run() + }) + } + _run() +} diff --git a/frontend/src/data-visualization/chart/components/js/formatter.ts b/frontend/src/data-visualization/chart/components/js/formatter.ts new file mode 100644 index 0000000..a297fbb --- /dev/null +++ b/frontend/src/data-visualization/chart/components/js/formatter.ts @@ -0,0 +1,107 @@ +import { Datum } from '@antv/g2plot' + +export const formatterItem = { + type: 'auto', // auto,value,percent + unit: 1, // 换算单位 + suffix: '', // 单位后缀 + decimalCount: 2, // 小数位数 + thousandSeparator: true // 千分符 +} + +// 单位list +export const unitType = [ + { name: 'unit_none', value: 1 }, + { name: 'unit_thousand', value: 1000 }, + { name: 'unit_ten_thousand', value: 10000 }, + { name: 'unit_million', value: 1000000 }, + { name: 'unit_hundred_million', value: 100000000 } +] + +// 格式化方式 +export const formatterType = [ + { name: 'value_formatter_auto', value: 'auto' }, + { name: 'value_formatter_value', value: 'value' }, + { name: 'value_formatter_percent', value: 'percent' } +] + +export function valueFormatter(value, formatter) { + if (value === null || value === undefined) { + return null + } + // 1.unit 2.decimal 3.thousand separator and suffix + let result + if (formatter.type === 'auto') { + result = transSeparatorAndSuffix(transUnit(value, formatter), formatter) + } else if (formatter.type === 'value') { + result = transSeparatorAndSuffix( + transDecimal(transUnit(value, formatter), formatter), + formatter + ) + } else if (formatter.type === 'percent') { + value = value * 100 + result = transSeparatorAndSuffix(transDecimal(value, formatter), formatter) + } else { + result = value + } + return result +} + +function transUnit(value, formatter) { + return value / formatter.unit +} + +function transDecimal(value, formatter) { + const resultV = value.toFixed(formatter.decimalCount) + if (Object.is(parseFloat(resultV), -0)) { + return resultV.slice(1) + } + return resultV +} + +function transSeparatorAndSuffix(value, formatter) { + let str = value + '' + if (str.match(/^(\d)(\.\d)?e-(\d)/)) { + str = value.toFixed(18).replace(/\.?0+$/, '') + } + if (formatter.thousandSeparator) { + const thousandsReg = /(\d)(?=(\d{3})+$)/g + const numArr = str.split('.') + numArr[0] = numArr[0].replace(thousandsReg, '$1,') + str = numArr.join('.') + } + if (formatter.type === 'percent') { + str += '%' + //百分比没有后缀,直接返回 + return str + } else { + if (formatter.unit === 1000) { + str += '千' + } else if (formatter.unit === 10000) { + str += '万' + } else if (formatter.unit === 1000000) { + str += '百万' + } else if (formatter.unit === 100000000) { + str += '亿' + } + } + return str + formatter.suffix.replace(/(^\s*)|(\s*$)/g, '') +} + +export function singleDimensionTooltipFormatter(param: Datum, chart: Chart, prop = 'category') { + let res + const yAxis = chart.yAxis + const obj = { name: param[prop], value: param.value } + for (let i = 0; i < yAxis.length; i++) { + const f = yAxis[i] + if (f.name === param[prop]) { + if (f.formatterCfg) { + res = valueFormatter(param.value, f.formatterCfg) + } else { + res = valueFormatter(param.value, formatterItem) + } + break + } + } + obj.value = res ?? '' + return obj +} diff --git a/frontend/src/data-visualization/chart/components/js/panel/charts/bar/bar.ts b/frontend/src/data-visualization/chart/components/js/panel/charts/bar/bar.ts new file mode 100644 index 0000000..3d25530 --- /dev/null +++ b/frontend/src/data-visualization/chart/components/js/panel/charts/bar/bar.ts @@ -0,0 +1,691 @@ +import type { Column, ColumnOptions } from '@antv/g2plot/esm/plots/column' +import { cloneDeep, each, groupBy, isEmpty } from 'lodash-es' +import { + G2PlotChartView, + G2PlotDrawOptions +} from '@/data-visualization/chart/components/js/panel/types/impl/g2plot' +import { + flow, + hexColorToRGBA, + hexToRgba, + parseJson, + setUpGroupSeriesColor, + setUpStackSeriesColor +} from '@/data-visualization/chart/components/js/util' +import type { Datum } from '@antv/g2plot' +import { formatterItem, valueFormatter } from '@/data-visualization/chart/components/js/formatter' +import { + BAR_AXIS_TYPE, + BAR_EDITOR_PROPERTY, + BAR_EDITOR_PROPERTY_INNER +} from '@/data-visualization/chart/components/js/panel/charts/bar/common' +import { + configPlotTooltipEvent, + getLabel, + getPadding, + getTooltipContainer, + setGradientColor, + TOOLTIP_TPL +} from '@/data-visualization/chart/components/js/panel/common/common_antv' +import { useI18n } from '@/data-visualization/hooks/web/useI18n' +import { DEFAULT_BASIC_STYLE, DEFAULT_LABEL } from '@/data-visualization/chart/components/editor/util/chart' +import { clearExtremum, extremumEvt } from '@/data-visualization/chart/components/js/extremumUitl' +import { Group } from '@antv/g-canvas' + +const { t } = useI18n() +const DEFAULT_DATA: any[] = [] +/** + * 柱状图 + */ +export class Bar extends G2PlotChartView { + properties = BAR_EDITOR_PROPERTY + propertyInner = { + ...BAR_EDITOR_PROPERTY_INNER, + 'basic-style-selector': [...BAR_EDITOR_PROPERTY_INNER['basic-style-selector'], 'seriesColor'], + 'label-selector': ['vPosition', 'seriesLabelFormatter', 'showExtremum'], + 'tooltip-selector': ['fontSize', 'color', 'backgroundColor', 'seriesTooltipFormatter', 'show'], + 'y-axis-selector': [...BAR_EDITOR_PROPERTY_INNER['y-axis-selector'], 'axisLabelFormatter'] + } + protected baseOptions: ColumnOptions = { + xField: 'field', + yField: 'value', + seriesField: 'category', + isGroup: true, + data: [] + } + + axis: AxisType[] = [...BAR_AXIS_TYPE] + axisConfig = { + ...this['axisConfig'], + xAxis: { + name: `${t('chart.drag_block_type_axis')} / ${t('chart.dimension')}`, + type: 'd' + }, + yAxis: { + name: `${t('chart.drag_block_value_axis')} / ${t('chart.quota')}`, + type: 'q' + } + } + + async drawChart(drawOptions: G2PlotDrawOptions): Promise { + const { chart, container, action } = drawOptions + if (!chart?.data?.data?.length) { + chart.container = container + clearExtremum(chart) + return + } + const data = cloneDeep(drawOptions.chart.data?.data) + const initOptions: ColumnOptions = { + ...this.baseOptions, + appendPadding: getPadding(chart), + data + } + const options: ColumnOptions = this.setupOptions(chart, initOptions) + let newChart = null + const { Column: ColumnClass } = await import('@antv/g2plot/esm/plots/column') + newChart = new ColumnClass(container, options) + newChart.on('interval:click', action) + extremumEvt(newChart, chart, options, container) + configPlotTooltipEvent(chart, newChart) + return newChart + } + + protected configLabel(chart: Chart, options: ColumnOptions): ColumnOptions { + const tmpOptions = super.configLabel(chart, options) + if (!tmpOptions.label) { + return { + ...tmpOptions, + label: false + } + } + const { label: labelAttr } = parseJson(chart.customAttr) + const formatterMap = labelAttr.seriesLabelFormatter?.reduce((pre, next) => { + pre[next.id] = next + return pre + }, {}) + // 默认是灰色 + tmpOptions.label.style.fill = DEFAULT_LABEL.color + const label = { + fields: [], + ...tmpOptions.label, + formatter: (data: Datum, _point) => { + if (data.EXTREME) { + return '' + } + if (!labelAttr.seriesLabelFormatter?.length) { + return data.value + } + const labelCfg = formatterMap?.[data.quotaList[0].id] as SeriesFormatter + if (!labelCfg) { + return data.value + } + if (!labelCfg.show) { + return + } + const value = valueFormatter(data.value, labelCfg.formatterCfg) + const group = new Group({}) + group.addShape({ + type: 'text', + attrs: { + x: 0, + y: 0, + text: value, + textAlign: 'start', + textBaseline: 'top', + fontSize: labelCfg.fontSize, + fontFamily: chart.fontFamily, + fill: labelCfg.color + } + }) + return group + }, + position: data => { + if (data.value < 0) { + if (tmpOptions.label?.position === 'top') { + return 'bottom' + } + if (tmpOptions.label?.position === 'bottom') { + return 'top' + } + } + return tmpOptions.label?.position + } + } + return { + ...tmpOptions, + label + } + } + + protected configTooltip(chart: Chart, options: ColumnOptions): ColumnOptions { + return super.configMultiSeriesTooltip(chart, options) + } + + protected configBasicStyle(chart: Chart, options: ColumnOptions): ColumnOptions { + const basicStyle = parseJson(chart.customAttr).basicStyle + if (basicStyle.gradient) { + let color = basicStyle.colors + color = color.map(ele => { + const tmp = hexColorToRGBA(ele, basicStyle.alpha) + return setGradientColor(tmp, true, 270) + }) + options = { + ...options, + color + } + } + if (basicStyle.radiusColumnBar === 'roundAngle') { + const columnStyle = { + radius: [ + basicStyle.columnBarRightAngleRadius, + basicStyle.columnBarRightAngleRadius, + basicStyle.columnBarRightAngleRadius, + basicStyle.columnBarRightAngleRadius + ] + } + options = { + ...options, + columnStyle + } + } + let columnWidthRatio + const _v = basicStyle.columnWidthRatio ?? DEFAULT_BASIC_STYLE.columnWidthRatio + if (_v >= 1 && _v <= 100) { + columnWidthRatio = _v / 100.0 + } else if (_v < 1) { + columnWidthRatio = 1 / 100.0 + } else if (_v > 100) { + columnWidthRatio = 1 + } + if (columnWidthRatio) { + options.columnWidthRatio = columnWidthRatio + } + + return options + } + + protected configYAxis(chart: Chart, options: ColumnOptions): ColumnOptions { + const tmpOptions = super.configYAxis(chart, options) + if (!tmpOptions.yAxis) { + return tmpOptions + } + const yAxis = parseJson(chart.customStyle).yAxis + const axisValue = yAxis.axisValue + if (tmpOptions.yAxis.label) { + tmpOptions.yAxis.label.formatter = value => { + return valueFormatter(value, yAxis.axisLabelFormatter) + } + } + if (!axisValue?.auto) { + const axis = { + yAxis: { + ...tmpOptions.yAxis, + min: axisValue.min, + max: axisValue.max, + minLimit: axisValue.min, + maxLimit: axisValue.max, + tickCount: axisValue.splitCount + } + } + return { ...tmpOptions, ...axis } + } + return tmpOptions + } + + protected setupOptions(chart: Chart, options: ColumnOptions): ColumnOptions { + return flow( + this.addConditionsStyleColorToData, + this.configTheme, + this.configEmptyDataStrategy, + this.configColor, + this.configBasicStyle, + this.configLabel, + this.configTooltip, + this.configLegend, + this.configXAxis, + this.configYAxis, + this.configSlider, + this.configAnalyse, + this.configBarConditions + )(chart, options, {}, this) + } + + setupDefaultOptions(chart: ChartObj): ChartObj { + chart.senior.functionCfg.emptyDataStrategy = 'ignoreData' + return chart + } + + constructor(name = 'bar', defaultData = DEFAULT_DATA) { + super(name, defaultData) + } +} + +/** + * 堆叠柱状图 + */ +export class StackBar extends Bar { + properties = BAR_EDITOR_PROPERTY.filter(ele => ele !== 'threshold') + propertyInner = { + ...this['propertyInner'], + 'label-selector': [ + ...BAR_EDITOR_PROPERTY_INNER['label-selector'], + 'vPosition', + 'showTotal', + 'totalColor', + 'totalFontSize', + 'totalFormatter', + 'showStackQuota' + ], + 'tooltip-selector': ['fontSize', 'color', 'backgroundColor', 'tooltipFormatter', 'show'] + } + protected configLabel(chart: Chart, options: ColumnOptions): ColumnOptions { + let label = getLabel(chart) + if (!label) { + return options + } + options = { ...options, label } + const { label: labelAttr } = parseJson(chart.customAttr) + if (labelAttr.showStackQuota || labelAttr.showStackQuota === undefined) { + label.style.fill = labelAttr.color + label = { + ...label, + formatter: function (param: Datum) { + return valueFormatter(param.value, labelAttr.labelFormatter) + } + } + } else { + label = false + } + if (labelAttr.showTotal) { + const formatterCfg = labelAttr.labelFormatter ?? formatterItem + each(groupBy(options.data, 'field'), (values, key) => { + const total = values.reduce((a, b) => a + b.value, 0) + const value = valueFormatter(total, formatterCfg) + if (!options.annotations) { + options = { + ...options, + annotations: [] + } + } + options.annotations.push({ + type: 'text', + position: [key, total], + content: `${value}`, + style: { + textAlign: 'center', + fontSize: labelAttr.fontSize, + fill: labelAttr.color + }, + offsetY: -(parseInt(labelAttr.fontSize as unknown as string) / 2) + }) + }) + } + return { + ...options, + label + } + } + + protected configTooltip(chart: Chart, options: ColumnOptions): ColumnOptions { + const tooltipAttr = parseJson(chart.customAttr).tooltip + if (!tooltipAttr.show) { + return { + ...options, + tooltip: false + } + } + const tooltip = { + formatter: (param: Datum) => { + const name = isEmpty(param.category) ? param.field : param.category + const obj = { name, value: param.value } + const res = valueFormatter(param.value, tooltipAttr.tooltipFormatter) + obj.value = res ?? '' + return obj + }, + container: getTooltipContainer(`tooltip-${chart.id}`), + itemTpl: TOOLTIP_TPL, + enterable: true + } + return { + ...options, + tooltip + } + } + + protected configColor(chart: Chart, options: ColumnOptions): ColumnOptions { + return this.configStackColor(chart, options) + } + + protected configData(chart: Chart, options: ColumnOptions): ColumnOptions { + const { xAxis, extStack, yAxis } = chart + const mainSort = xAxis.some(axis => axis.sort !== 'none') + const subSort = extStack.some(axis => axis.sort !== 'none') + if (mainSort || subSort) { + return options + } + const quotaSort = yAxis?.[0].sort !== 'none' + if (!quotaSort || !extStack.length || !yAxis.length) { + return options + } + const { data } = options + const mainAxisValueMap = data.reduce((p, n) => { + p[n.field] = p[n.field] ? p[n.field] + n.value : n.value || 0 + return p + }, {}) + const sort = yAxis[0].sort + data.sort((p, n) => { + if (sort === 'asc') { + return mainAxisValueMap[p.field] - mainAxisValueMap[n.field] + } else { + return mainAxisValueMap[n.field] - mainAxisValueMap[p.field] + } + }) + return options + } + + public setupSeriesColor(chart: ChartObj, data?: any[]): ChartBasicStyle['seriesColor'] { + return setUpStackSeriesColor(chart, data) + } + + protected setupOptions(chart: Chart, options: ColumnOptions): ColumnOptions { + return flow( + this.configTheme, + this.configEmptyDataStrategy, + this.configData, + this.configColor, + this.configBasicStyle, + this.configLabel, + this.configTooltip, + this.configLegend, + this.configXAxis, + this.configYAxis, + this.configSlider, + this.configAnalyse + )(chart, options, {}, this) + } + + constructor(name = 'bar-stack') { + super(name) + this.baseOptions = { + ...this.baseOptions, + isStack: true, + isGroup: false, + meta: { + category: { + type: 'cat' + } + } + } + this.axis = [...this.axis, 'extStack'] + } +} + +/** + * 分组柱状图 + */ +export class GroupBar extends StackBar { + properties = BAR_EDITOR_PROPERTY + propertyInner = { + ...this['propertyInner'], + 'label-selector': [...BAR_EDITOR_PROPERTY_INNER['label-selector'], 'vPosition', 'showExtremum'] + } + axisConfig = { + ...this['axisConfig'], + yAxis: { + name: `${t('chart.drag_block_value_axis')} / ${t('chart.quota')}`, + type: 'q', + limit: 1 + } + } + + protected configLabel(chart: Chart, options: ColumnOptions): ColumnOptions { + const tmpLabel = getLabel(chart) + if (!tmpLabel) { + return options + } + const baseOptions = { ...options, label: tmpLabel } + const { label: labelAttr } = parseJson(chart.customAttr) + baseOptions.label.style.fill = labelAttr.color + const label = { + ...baseOptions.label, + formatter: function (param: Datum, _point) { + if (param.EXTREME) { + return '' + } + const value = valueFormatter(param.value, labelAttr.labelFormatter) + return labelAttr.childrenShow ? value : null + } + } + return { + ...baseOptions, + label + } + } + + protected configColor(chart: Chart, options: ColumnOptions): ColumnOptions { + return this.configGroupColor(chart, options) + } + + public setupSeriesColor(chart: ChartObj, data?: any[]): ChartBasicStyle['seriesColor'] { + return setUpGroupSeriesColor(chart, data) + } + + protected setupOptions(chart: Chart, options: ColumnOptions): ColumnOptions { + return flow( + this.addConditionsStyleColorToData, + this.configTheme, + this.configEmptyDataStrategy, + this.configColor, + this.configBasicStyle, + this.configLabel, + this.configTooltip, + this.configLegend, + this.configXAxis, + this.configYAxis, + this.configSlider, + this.configAnalyse, + this.configBarConditions + )(chart, options, {}, this) + } + + constructor(name = 'bar-group') { + super(name) + this.baseOptions = { + ...this.baseOptions, + isGroup: true, + isStack: false, + meta: { + category: { + type: 'cat' + } + } + } + this.axis = [...BAR_AXIS_TYPE, 'xAxisExt'] + } +} + +/** + * 分组堆叠柱状图 + */ +export class GroupStackBar extends StackBar { + propertyInner = { + ...this['propertyInner'], + 'label-selector': [...BAR_EDITOR_PROPERTY_INNER['label-selector'], 'vPosition'] + } + protected configTheme(chart: Chart, options: ColumnOptions): ColumnOptions { + const baseOptions = super.configTheme(chart, options) + const baseTheme = baseOptions.theme as object + const theme = { + ...baseTheme, + innerLabels: { + offset: 0 + } + } + return { + ...options, + theme + } + } + + protected configLabel(chart: Chart, options: ColumnOptions): ColumnOptions { + const tmpLabel = getLabel(chart) + if (!tmpLabel) { + return options + } + const baseOptions = { ...options, label: tmpLabel } + const { label: labelAttr } = parseJson(chart.customAttr) + baseOptions.label.style.fill = labelAttr.color + const label = { + ...baseOptions.label, + formatter: function (param: Datum) { + return valueFormatter(param.value, labelAttr.labelFormatter) + } + } + return { + ...baseOptions, + label + } + } + + protected configTooltip(chart: Chart, options: ColumnOptions): ColumnOptions { + const tooltipAttr = parseJson(chart.customAttr).tooltip + if (!tooltipAttr.show) { + return { + ...options, + tooltip: false + } + } + const tooltip = { + fields: [], + formatter: (param: Datum) => { + const obj = { name: `${param.category} - ${param.group}`, value: param.value } + obj.value = valueFormatter(param.value, tooltipAttr.tooltipFormatter) + return obj + }, + container: getTooltipContainer(`tooltip-${chart.id}`), + itemTpl: TOOLTIP_TPL, + enterable: true + } + return { + ...options, + tooltip + } + } + + protected setupOptions(chart: Chart, options: ColumnOptions): ColumnOptions { + return flow( + this.configTheme, + this.configEmptyDataStrategy, + this.configColor, + this.configBasicStyle, + this.configLabel, + this.configTooltip, + this.configLegend, + this.configXAxis, + this.configYAxis, + this.configSlider, + this.configAnalyse + )(chart, options, {}, this) + } + + constructor(name = 'bar-group-stack') { + super(name) + this.baseOptions = { + ...this.baseOptions, + isGroup: true, + groupField: 'group' + } + this.axis = [...this.axis, 'xAxisExt', 'extStack'] + } +} + +/** + * 百分比堆叠柱状图 + */ +export class PercentageStackBar extends GroupStackBar { + propertyInner = { + ...this['propertyInner'], + 'label-selector': ['color', 'fontSize', 'vPosition', 'reserveDecimalCount'], + 'tooltip-selector': ['color', 'fontSize', 'backgroundColor', 'show'] + } + protected configLabel(chart: Chart, options: ColumnOptions): ColumnOptions { + const baseOptions = super.configLabel(chart, options) + if (!baseOptions.label) { + return baseOptions + } + const { customAttr } = chart + const l = parseJson(customAttr).label + const label = { + ...baseOptions.label, + formatter: function (param: Datum) { + if (!param.value) { + return '0%' + } + return (Math.round(param.value * 10000) / 100).toFixed(l.reserveDecimalCount) + '%' + } + } + return { + ...baseOptions, + label + } + } + + protected configTooltip(chart: Chart, options: ColumnOptions): ColumnOptions { + const tooltipAttr = parseJson(chart.customAttr).tooltip + if (!tooltipAttr.show) { + return { + ...options, + tooltip: { + showContent: false + } + } + } + const { customAttr } = chart + const l = parseJson(customAttr).label + const tooltip = { + formatter: (param: Datum) => { + const obj = { name: param.category, value: param.value } + obj.value = (Math.round(param.value * 10000) / 100).toFixed(l.reserveDecimalCount) + '%' + return obj + }, + container: getTooltipContainer(`tooltip-${chart.id}`), + itemTpl: TOOLTIP_TPL, + enterable: true + } + return { + ...options, + tooltip + } + } + protected setupOptions(chart: Chart, options: ColumnOptions): ColumnOptions { + return flow( + this.configTheme, + this.configEmptyDataStrategy, + this.configColor, + this.configBasicStyle, + this.configLabel, + this.configTooltip, + this.configLegend, + this.configXAxis, + this.configYAxis, + this.configSlider, + this.configAnalyse + )(chart, options, {}, this) + } + constructor() { + super('percentage-bar-stack') + this.baseOptions = { + ...this.baseOptions, + isStack: true, + isPercent: true, + isGroup: false, + groupField: undefined, + meta: { + category: { + type: 'cat' + } + } + } + this.axis = [...BAR_AXIS_TYPE, 'extStack'] + } +} diff --git a/frontend/src/data-visualization/chart/components/js/panel/charts/bar/bidirectional-bar.ts b/frontend/src/data-visualization/chart/components/js/panel/charts/bar/bidirectional-bar.ts new file mode 100644 index 0000000..41456d0 --- /dev/null +++ b/frontend/src/data-visualization/chart/components/js/panel/charts/bar/bidirectional-bar.ts @@ -0,0 +1,582 @@ +import { + G2PlotChartView, + G2PlotDrawOptions +} from '@/data-visualization/chart/components/js/panel/types/impl/g2plot' +import { cloneDeep, defaultTo, isEmpty, map } from 'lodash-es' +import { + configAxisLabelLengthLimit, + configPlotTooltipEvent, + getPadding, + getTooltipContainer, + getTooltipItemConditionColor, + getYAxis, + getYAxisExt, + setGradientColor, + TOOLTIP_TPL, + addConditionsStyleColorToData +} from '@/data-visualization/chart/components/js/panel/common/common_antv' +import type { + BidirectionalBar as G2BidirectionalBar, + BidirectionalBarOptions +} from '@antv/g2plot/esm/plots/bidirectional-bar' +import { flow, hexColorToRGBA, parseJson } from '@/data-visualization/chart/components/js/util' +import { useI18n } from '@/data-visualization/hooks/web/useI18n' +import { valueFormatter } from '@/data-visualization/chart/components/js/formatter' +import type { Options } from '@antv/g2plot/esm' +import { Group } from '@antv/g-canvas' + +const { t } = useI18n() +/** + * 对称柱状图 + */ + +export class BidirectionalHorizontalBar extends G2PlotChartView< + BidirectionalBarOptions, + G2BidirectionalBar +> { + axisConfig = { + ...this['axisConfig'], + xAxis: { + name: `${t('chart.drag_block_type_axis')} / ${t('chart.dimension')}`, + type: 'd', + limit: 1 + }, + yAxis: { + name: `${t('chart.drag_block_value_axis')} / ${t('chart.quota')}`, + type: 'q', + limit: 1 + }, + yAxisExt: { + name: `${t('chart.drag_block_value_axis_ext')} / ${t('chart.quota')}`, + type: 'q', + limit: 1 + } + } + axis: AxisType[] = ['xAxis', 'yAxis', 'yAxisExt', 'filter', 'drill', 'extLabel', 'extTooltip'] + properties: EditorProperty[] = [ + 'background-overall-component', + 'border-style', + 'basic-style-selector', + 'x-axis-selector', + 'dual-y-axis-selector', + 'title-selector', + 'legend-selector', + 'label-selector', + 'tooltip-selector', + 'function-cfg', + 'jump-set', + 'linkage', + 'threshold' + ] + propertyInner = { + 'background-overall-component': ['all'], + 'border-style': ['all'], + 'basic-style-selector': ['colors', 'alpha', 'gradient', 'layout', 'radiusColumnBar'], + 'x-axis-selector': ['position', 'axisLabel', 'axisLine', 'splitLine'], + 'dual-y-axis-selector': [ + 'name', + 'position', + 'color', + 'fontSize', + 'axisLabel', + 'axisLine', + 'splitLine', + 'axisValue', + 'axisLabelFormatter' + ], + 'title-selector': [ + 'title', + 'fontSize', + 'color', + 'hPosition', + 'isItalic', + 'isBolder', + 'remarkShow', + 'fontFamily', + 'letterSpace', + 'fontShadow' + ], + 'legend-selector': ['icon', 'orient', 'fontSize', 'color', 'hPosition', 'vPosition'], + 'function-cfg': ['emptyDataStrategy'], + 'label-selector': ['hPosition', 'vPosition', 'seriesLabelFormatter'], + 'tooltip-selector': ['fontSize', 'color', 'backgroundColor', 'seriesTooltipFormatter', 'show'], + threshold: ['lineThreshold'] + } + + selectorSpec: EditorSelectorSpec = { + ...this['selectorSpec'], + 'dual-y-axis-selector': { + title: `${t('chart.xAxis')}` + }, + 'x-axis-selector': { + title: `${t('chart.yAxis')}` + } + } + + async drawChart(drawOptions: G2PlotDrawOptions): Promise { + const { chart, container, action } = drawOptions + if (!chart.data?.data?.length) { + return + } + // data + const data = cloneDeep(chart.data.data) + const data1 = defaultTo(data[0]?.data, []) + const data2 = map(defaultTo(data[1]?.data, []), d => { + return { + ...d, + category: d.field, + value: data1.find(item => item.field === d.field)?.value, + valueExt: d.value + } + }) + // options + const initOptions: BidirectionalBarOptions = { + xField: 'field', + data: data2, + xAxis: { + label: { + style: {} + }, + position: 'bottom' + }, + yField: ['value', 'valueExt'], + appendPadding: getPadding(chart), + meta: { + field: { + type: 'cat' + } + } + } + const customOptions = this.setupOptions(chart, initOptions) + const options = { + ...customOptions + } + const xAxis = chart.xAxis + if (xAxis?.length === 1 && xAxis[0].deType === 1) { + const values = data2.map(item => item.field) + options.meta = { + field: { + type: 'cat', + values: values.reverse() + } + } + } + const { BidirectionalBar: BidirectionalBarClass } = await import( + '@antv/g2plot/esm/plots/bidirectional-bar' + ) + // 开始渲染 + const newChart = new BidirectionalBarClass(container, options) + + newChart.on('interval:click', action) + newChart.on('element:click', ev => { + const sourceData = newChart.options.data.filter( + item => + item.field === ev.data.data.field && + item[ev.data.data['series-field-key']] === ev.data.data[ev.data.data['series-field-key']] + ) + ev.data.data = { + ...ev.data.data, + ...sourceData[0] + } + }) + configPlotTooltipEvent(chart, newChart) + configAxisLabelLengthLimit(chart, newChart) + return newChart + } + + protected configBasicStyle( + chart: Chart, + options: BidirectionalBarOptions + ): BidirectionalBarOptions { + const basicStyle = parseJson(chart.customAttr).basicStyle + if (basicStyle.gradient) { + const color = basicStyle.colors?.map((ele, index) => { + const tmp = hexColorToRGBA(ele, basicStyle.alpha) + let angle = 180 - index * 180 + // 垂直固定角度 + if (basicStyle.layout === 'vertical') { + if (index === 0) { + angle = 280 + } + if (index === 1) { + angle = 90 + } + } + return setGradientColor(tmp, true, angle) + }) + options = { + ...options, + color + } + } + options = { + ...options, + layout: basicStyle.layout + } + if (basicStyle.radiusColumnBar === 'roundAngle') { + const barStyle = { + radius: [ + basicStyle.columnBarRightAngleRadius, + basicStyle.columnBarRightAngleRadius, + basicStyle.columnBarRightAngleRadius, + basicStyle.columnBarRightAngleRadius + ] + } + options = { + ...options, + barStyle + } + } + return options + } + + protected configXAxis(chart: Chart, options: BidirectionalBarOptions): BidirectionalBarOptions { + const tmpOptions = super.configXAxis(chart, options) + if (!tmpOptions.xAxis) { + return tmpOptions + } + if (tmpOptions.xAxis.label) { + delete tmpOptions.xAxis.label.style.textAlign + } + return tmpOptions + } + + protected configTooltip(chart: Chart, options: BidirectionalBarOptions): BidirectionalBarOptions { + const customAttr: DeepPartial = parseJson(chart.customAttr) + const tooltipAttr = customAttr.tooltip + if (!tooltipAttr.show) { + return { + ...options, + tooltip: false + } + } + const yAxis = cloneDeep(chart.yAxis) + const yAxisExt = cloneDeep(chart.yAxisExt) + const formatterMap = tooltipAttr.seriesTooltipFormatter + ?.filter(i => i.show) + .reduce((pre, next) => { + pre[next.seriesId] = next + return pre + }, {}) as Record + const optionsData = cloneDeep(options.data) + const yaxisObj = item => { + const param = item.data + let yaxis = yAxis[0] + let axisType = 'yAxis' + if (param['series-field-key'] === 'valueExt') { + yaxis = yAxisExt[0] + axisType = 'yAxisExt' + } + return { + id: yaxis.id, + name: yaxis.name, + axisType: axisType, + value: param[param['series-field-key']] + } + } + const tooltip: BidirectionalBarOptions['tooltip'] = { + shared: true, + showTitle: true, + customItems(originalItems) { + if (!tooltipAttr.seriesTooltipFormatter?.length) { + return originalItems + } + const result = [] + originalItems + .filter(item => { + const obj = yaxisObj(item) + return formatterMap[obj.id + '-' + obj.axisType] + }) + .forEach(item => { + const obj = yaxisObj(item) + const formatter = formatterMap[obj.id + '-' + obj.axisType] + const value = valueFormatter(parseFloat(item.value as string), formatter.formatterCfg) + const name = isEmpty(formatter.chartShowName) ? formatter.name : formatter.chartShowName + const color = getTooltipItemConditionColor(item) + result.push({ ...item, name, value, color }) + }) + const dynamicTooltipValue = optionsData.find( + d => d.field === originalItems[0]['title'] + )?.dynamicTooltipValue + if (dynamicTooltipValue.length > 0) { + dynamicTooltipValue.forEach(dy => { + const q = tooltipAttr.seriesTooltipFormatter.filter(i => i.id === dy.fieldId) + if (q && q.length > 0) { + const value = valueFormatter(parseFloat(dy.value as string), q[0].formatterCfg) + const name = isEmpty(q[0].chartShowName) ? q[0].name : q[0].chartShowName + result.push({ color: 'grey', name, value }) + } + }) + } + return result + }, + container: getTooltipContainer(`tooltip-${chart.id}`), + itemTpl: TOOLTIP_TPL, + enterable: true + } + return { + ...options, + tooltip + } + } + + protected configLegend(chart: Chart, options: BidirectionalBarOptions): BidirectionalBarOptions { + const o = super.configLegend(chart, options) + if (o.legend) { + o.legend.itemName.formatter = (_text: string, _item: any, index: number) => { + const yaxis = chart.yAxis[0] + const yaxisExt = chart.yAxisExt[0] + if (index === 0) { + return yaxis.chartShowName ? yaxis.chartShowName : yaxis.name + } + return yaxisExt.chartShowName ? yaxisExt.chartShowName : yaxisExt.name + } + } + return o + } + + protected configYAxis(chart: Chart, options: BidirectionalBarOptions): BidirectionalBarOptions { + const yAxis = getYAxis(chart) + let yAxisExt = getYAxisExt(chart) + + const tempOption = { + ...options + } + + if (!yAxis) { + //左右轴都要隐藏 + yAxisExt = false + tempOption['yAxis'] = { + value: false, + valueExt: false + } + } else { + tempOption['yAxis'] = { + value: undefined, + valueExt: undefined + } + } + const layoutHorizontal = options.layout === 'horizontal' + // 处理横轴标题方向不对 + if (yAxis && yAxis['title'] && layoutHorizontal) { + yAxis['title'].autoRotate = false + } + const yAxisTmp = parseJson(chart.customStyle).yAxis + if (yAxis['label']) { + yAxis['label'].formatter = value => { + return valueFormatter(value, yAxisTmp.axisLabelFormatter) + } + } + const axisValue = yAxisTmp.axisValue + if (!axisValue?.auto) { + tempOption.yAxis.value = { + ...yAxis, + min: axisValue.min, + max: axisValue.max, + minLimit: axisValue.min, + maxLimit: axisValue.max, + tickCount: axisValue.splitCount + } + } else { + tempOption.yAxis.value = yAxis + } + + const yAxisExtTmp = parseJson(chart.customStyle).yAxisExt + if (yAxisExt['label']) { + yAxisExt['label'].formatter = value => { + return valueFormatter(value, yAxisExtTmp.axisLabelFormatter) + } + } + const axisExtValue = yAxisExtTmp.axisValue + if (!axisExtValue?.auto) { + tempOption.yAxis.valueExt = { + ...yAxisExt, + min: axisExtValue.min, + max: axisExtValue.max, + minLimit: axisExtValue.min, + maxLimit: axisExtValue.max, + tickCount: axisExtValue.splitCount + } + } else { + tempOption.yAxis.valueExt = yAxisExt + } + + return tempOption + } + + setupDefaultOptions(chart: ChartObj): ChartObj { + chart.customStyle.yAxis = { + ...chart.customStyle.yAxis, + position: 'left' + } + chart.customStyle.yAxisExt = { + ...chart.customStyle.yAxisExt, + position: 'left', + splitLine: chart.customStyle.yAxis.splitLine + } + chart.customAttr.label = { + ...chart.customAttr.label, + position: 'right' + } + chart.customAttr.basicStyle.layout = 'horizontal' + return chart + } + + protected configLabel(chart: Chart, options: BidirectionalBarOptions): BidirectionalBarOptions { + let label + const yAxis = chart.yAxis + const yAxisExt = chart.yAxisExt + const labelAttr = parseJson(chart.customAttr).label + const formatterMap = labelAttr.seriesLabelFormatter?.reduce((pre, next) => { + pre[next.id] = next + return pre + }, {}) + let customAttr: DeepPartial + const layoutHorizontal = options.layout === 'horizontal' + if (chart.customAttr) { + customAttr = parseJson(chart.customAttr) + // label + if (customAttr.label) { + const l = customAttr.label + if (l.show) { + const layout = [] + if (!labelAttr.fullDisplay) { + const tmpOptions = super.configLabel(chart, options) + layout.push(...tmpOptions.label.layout) + } + label = { + position: l.position, + layout, + style: { + fill: l.color, + fontSize: l.fontSize, + fontFamily: chart.fontFamily + }, + formatter: param => { + let yaxis = yAxis[0] + let res = param.value + if (param['series-field-key'] === 'valueExt') { + yaxis = yAxisExt[0] + } + const value = param[param['series-field-key']] + const labelCfg = formatterMap?.[yaxis.id] as SeriesFormatter + if (yaxis.formatterCfg) { + res = valueFormatter(value, yaxis.formatterCfg) + } + if (!labelCfg) { + return res + } + if (!labelCfg.show) { + return + } + if (labelCfg) { + res = valueFormatter(value, labelCfg.formatterCfg) + } else { + res = valueFormatter(value, l.labelFormatter) + } + const group = new Group({}) + const isValue = param['series-field-key'] === 'value' + const textAlign = isValue && layoutHorizontal ? 'end' : 'start' + const isMiddle = label.position === 'middle' + group.addShape({ + type: 'text', + attrs: { + x: + isValue && layoutHorizontal && !isMiddle + ? -6 + : !isValue && layoutHorizontal && !isMiddle + ? 6 + : 0, + y: + isValue && !layoutHorizontal && !isMiddle + ? -8 + : !isValue && !layoutHorizontal && !isMiddle + ? 8 + : 0, + text: res, + textAlign: label.position === 'middle' ? 'start' : textAlign, + textBaseline: 'top', + fontSize: labelCfg.fontSize, + fontFamily: chart.fontFamily, + fill: labelCfg.color + } + }) + return group + } + } + } else { + label = false + } + } + } + if (!layoutHorizontal) { + if (label.position === 'left') { + label.position = 'bottom' + } + if (label.position === 'right') { + label.position = 'top' + } + } + return { ...options, label } + } + + protected configEmptyDataStrategy( + chart: Chart, + options: BidirectionalBarOptions + ): BidirectionalBarOptions { + const { data } = options as unknown as Options + if (!data?.length) { + return options + } + const strategy = parseJson(chart.senior).functionCfg.emptyDataStrategy + if (strategy === 'ignoreData') { + const emptyFields = data + .filter(obj => obj['value'] === null || obj['valueExt'] === null) + .map(obj => obj['field']) + return { + ...options, + data: data.filter(obj => { + if (emptyFields.includes(obj['field'])) { + return false + } + return true + }) + } + } + const updateValues = (strategy: 'breakLine' | 'setZero', data: any[]) => { + data.forEach(obj => { + if (obj['value'] === null) { + obj['value'] = strategy === 'breakLine' ? null : 0 + } + if (obj['valueExt'] === null) { + obj['valueExt'] = strategy === 'breakLine' ? null : 0 + } + }) + } + if (strategy === 'breakLine' || strategy === 'setZero') { + updateValues(strategy, data) + } + return options + } + + protected setupOptions(chart: Chart, options: BidirectionalBarOptions) { + return flow( + this.addConditionsStyleColorToData, + this.configTheme, + this.configBasicStyle, + this.configLabel, + this.configTooltip, + this.configLegend, + this.configXAxis, + this.configYAxis, + this.configAnalyse, + this.configSlider, + this.configEmptyDataStrategy, + this.configBarConditions + )(chart, options) + } + + constructor() { + super('bidirectional-bar', []) + } +} diff --git a/frontend/src/data-visualization/chart/components/js/panel/charts/bar/common.ts b/frontend/src/data-visualization/chart/components/js/panel/charts/bar/common.ts new file mode 100644 index 0000000..6421d18 --- /dev/null +++ b/frontend/src/data-visualization/chart/components/js/panel/charts/bar/common.ts @@ -0,0 +1,84 @@ +export const BAR_EDITOR_PROPERTY: EditorProperty[] = [ + 'background-overall-component', + 'border-style', + 'basic-style-selector', + 'label-selector', + 'tooltip-selector', + 'x-axis-selector', + 'y-axis-selector', + 'title-selector', + 'legend-selector', + 'function-cfg', + 'assist-line', + 'jump-set', + 'linkage', + 'threshold' +] +export const BAR_RANGE_EDITOR_PROPERTY: EditorProperty[] = [ + 'background-overall-component', + 'border-style', + 'basic-style-selector', + 'label-selector', + 'tooltip-selector', + 'x-axis-selector', + 'y-axis-selector', + 'title-selector', + 'legend-selector', + 'function-cfg', + 'jump-set', + 'linkage', + 'threshold' +] + +export const BAR_EDITOR_PROPERTY_INNER: EditorPropertyInner = { + 'background-overall-component': ['all'], + 'border-style': ['all'], + 'basic-style-selector': ['colors', 'alpha', 'gradient', 'radiusColumnBar', 'columnWidthRatio'], + 'label-selector': ['fontSize', 'color', 'labelFormatter'], + 'tooltip-selector': ['fontSize', 'color', 'tooltipFormatter', 'show'], + 'x-axis-selector': [ + 'name', + 'color', + 'fontSize', + 'axisLine', + 'splitLine', + 'axisForm', + 'axisLabel', + 'position' + ], + 'y-axis-selector': [ + 'name', + 'color', + 'fontSize', + 'axisValue', + 'axisLine', + 'splitLine', + 'axisForm', + 'axisLabel', + 'position' + ], + 'title-selector': [ + 'title', + 'fontSize', + 'color', + 'hPosition', + 'isItalic', + 'isBolder', + 'remarkShow', + 'fontFamily', + 'letterSpace', + 'fontShadow' + ], + 'legend-selector': ['icon', 'orient', 'fontSize', 'color', 'hPosition', 'vPosition'], + 'function-cfg': ['slider', 'emptyDataStrategy'], + threshold: ['lineThreshold'] +} + +export const BAR_AXIS_TYPE: AxisType[] = [ + 'xAxis', + 'yAxis', + 'filter', + 'drill', + 'extLabel', + 'extTooltip' +] diff --git a/frontend/src/data-visualization/chart/components/js/panel/charts/bar/horizontal-bar.ts b/frontend/src/data-visualization/chart/components/js/panel/charts/bar/horizontal-bar.ts new file mode 100644 index 0000000..12e8ec9 --- /dev/null +++ b/frontend/src/data-visualization/chart/components/js/panel/charts/bar/horizontal-bar.ts @@ -0,0 +1,501 @@ +import { + G2PlotChartView, + G2PlotDrawOptions +} from '@/data-visualization/chart/components/js/panel/types/impl/g2plot' +import type { Bar, BarOptions } from '@antv/g2plot/esm/plots/bar' +import { + configAxisLabelLengthLimit, + configPlotTooltipEvent, + getPadding, + getTooltipContainer, + setGradientColor, + TOOLTIP_TPL +} from '@/data-visualization/chart/components/js/panel/common/common_antv' +import { cloneDeep } from 'lodash-es' +import { + flow, + hexColorToRGBA, + parseJson, + setUpStackSeriesColor +} from '@/data-visualization/chart/components/js/util' +import { valueFormatter } from '@/data-visualization/chart/components/js/formatter' +import { + BAR_AXIS_TYPE, + BAR_EDITOR_PROPERTY, + BAR_EDITOR_PROPERTY_INNER +} from '@/data-visualization/chart/components/js/panel/charts/bar/common' +import type { Datum } from '@antv/g2plot/esm/types/common' +import { useI18n } from '@/data-visualization/hooks/web/useI18n' +import { DEFAULT_BASIC_STYLE, DEFAULT_LABEL } from '@/data-visualization/chart/components/editor/util/chart' +import { Group } from '@antv/g-canvas' + +const { t } = useI18n() +const DEFAULT_DATA = [] + +/** + * 条形图 + */ +export class HorizontalBar extends G2PlotChartView { + axisConfig = { + ...this['axisConfig'], + xAxis: { + name: `${t('chart.drag_block_type_axis')} / ${t('chart.dimension')}`, + type: 'd' + }, + yAxis: { + name: `${t('chart.drag_block_value_axis')} / ${t('chart.quota')}`, + type: 'q' + } + } + properties = BAR_EDITOR_PROPERTY + propertyInner = { + ...BAR_EDITOR_PROPERTY_INNER, + 'basic-style-selector': [...BAR_EDITOR_PROPERTY_INNER['basic-style-selector'], 'seriesColor'], + 'label-selector': ['hPosition', 'seriesLabelFormatter'], + 'tooltip-selector': ['fontSize', 'color', 'backgroundColor', 'seriesTooltipFormatter', 'show'], + 'x-axis-selector': [ + ...BAR_EDITOR_PROPERTY_INNER['x-axis-selector'], + 'axisLabelFormatter', + 'axisValue' + ], + 'y-axis-selector': [ + 'name', + 'color', + 'fontSize', + 'axisLine', + 'splitLine', + 'axisForm', + 'axisLabel', + 'position', + 'showLengthLimit' + ] + } + axis: AxisType[] = [...BAR_AXIS_TYPE] + protected baseOptions: BarOptions = { + data: [], + xField: 'value', + yField: 'field', + seriesField: 'category', + isGroup: true + } + + async drawChart(drawOptions: G2PlotDrawOptions): Promise { + const { chart, container, action } = drawOptions + if (!chart.data?.data?.length) { + return + } + // data + const data = cloneDeep(chart.data.data) + + // options + const initOptions: BarOptions = { + ...this.baseOptions, + appendPadding: getPadding(chart), + data + } + + const options = this.setupOptions(chart, initOptions) + + const { Bar } = await import('@antv/g2plot/esm/plots/bar') + // 开始渲染 + const newChart = new Bar(container, options) + + newChart.on('interval:click', action) + configPlotTooltipEvent(chart, newChart) + configAxisLabelLengthLimit(chart, newChart) + return newChart + } + + protected configXAxis(chart: Chart, options: BarOptions): BarOptions { + const tmpOptions = super.configXAxis(chart, options) + if (!tmpOptions.xAxis) { + return tmpOptions + } + const xAxis = parseJson(chart.customStyle).xAxis + const axisValue = xAxis.axisValue + if (tmpOptions.xAxis.label) { + tmpOptions.xAxis.label.formatter = value => { + return valueFormatter(value, xAxis.axisLabelFormatter) + } + } + if (tmpOptions.xAxis.position === 'top') { + tmpOptions.xAxis.position = 'left' + } + if (tmpOptions.xAxis.position === 'bottom') { + tmpOptions.xAxis.position = 'right' + } + if (!axisValue?.auto) { + const axis = { + xAxis: { + ...tmpOptions.xAxis, + min: axisValue.min, + max: axisValue.max, + minLimit: axisValue.min, + maxLimit: axisValue.max, + tickCount: axisValue.splitCount + } + } + return { ...tmpOptions, ...axis } + } + return tmpOptions + } + + protected configTooltip(chart: Chart, options: BarOptions): BarOptions { + return super.configMultiSeriesTooltip(chart, options) + } + + protected configBasicStyle(chart: Chart, options: BarOptions): BarOptions { + const basicStyle = parseJson(chart.customAttr).basicStyle + if (basicStyle.gradient) { + let color = basicStyle.colors + color = color.map(ele => { + const tmp = hexColorToRGBA(ele, basicStyle.alpha) + return setGradientColor(tmp, true) + }) + options = { + ...options, + color + } + } + if (basicStyle.radiusColumnBar === 'roundAngle') { + const barStyle = { + radius: [ + basicStyle.columnBarRightAngleRadius, + basicStyle.columnBarRightAngleRadius, + basicStyle.columnBarRightAngleRadius, + basicStyle.columnBarRightAngleRadius + ] + } + options = { + ...options, + barStyle + } + } + + let barWidthRatio + const _v = basicStyle.columnWidthRatio ?? DEFAULT_BASIC_STYLE.columnWidthRatio + if (_v >= 1 && _v <= 100) { + barWidthRatio = _v / 100.0 + } else if (_v < 1) { + barWidthRatio = 1 / 100.0 + } else if (_v > 100) { + barWidthRatio = 1 + } + if (barWidthRatio) { + options.barWidthRatio = barWidthRatio + } + + return options + } + + setupDefaultOptions(chart: ChartObj): ChartObj { + const { customAttr, senior } = chart + const { label } = customAttr + if (!['left', 'middle', 'right'].includes(label.position)) { + label.position = 'middle' + } + senior.functionCfg.emptyDataStrategy = 'ignoreData' + return chart + } + + protected configLabel(chart: Chart, options: BarOptions): BarOptions { + const tmpOptions = super.configLabel(chart, options) + if (!tmpOptions.label) { + return { + ...tmpOptions, + label: false + } + } + const labelAttr = parseJson(chart.customAttr).label + const formatterMap = labelAttr.seriesLabelFormatter?.reduce((pre, next) => { + pre[next.id] = next + return pre + }, {}) + // 默认灰色 + tmpOptions.label.style.fill = DEFAULT_LABEL.color + const label = { + fields: [], + ...tmpOptions.label, + formatter: (data: Datum) => { + if (!labelAttr.seriesLabelFormatter?.length) { + return data.value + } + const labelCfg = formatterMap?.[data.quotaList[0].id] as SeriesFormatter + if (!labelCfg) { + return data.value + } + if (!labelCfg.show) { + return + } + const value = valueFormatter(data.value, labelCfg.formatterCfg) + const group = new Group({}) + group.addShape({ + type: 'text', + attrs: { + x: 0, + y: 0, + text: value, + textAlign: 'start', + textBaseline: 'top', + fontSize: labelCfg.fontSize, + fontFamily: chart.fontFamily, + fill: labelCfg.color + } + }) + return group + } + } + return { + ...tmpOptions, + label + } + } + + protected configYAxis(chart: Chart, options: BarOptions): BarOptions { + const tmpOptions = super.configYAxis(chart, options) + if (!tmpOptions.yAxis) { + return tmpOptions + } + if (tmpOptions.yAxis.position === 'left') { + tmpOptions.yAxis.position = 'bottom' + } + if (tmpOptions.yAxis.position === 'right') { + tmpOptions.yAxis.position = 'top' + } + return tmpOptions + } + + protected setupOptions(chart: Chart, options: BarOptions): BarOptions { + return flow( + this.addConditionsStyleColorToData, + this.configTheme, + this.configEmptyDataStrategy, + this.configColor, + this.configBasicStyle, + this.configLabel, + this.configTooltip, + this.configLegend, + this.configXAxis, + this.configYAxis, + this.configSlider, + this.configAnalyseHorizontal, + this.configBarConditions + )(chart, options, {}, this) + } + + constructor(name = 'bar-horizontal') { + super(name, DEFAULT_DATA) + } +} + +/** + * 堆叠条形图 + */ +export class HorizontalStackBar extends HorizontalBar { + properties = BAR_EDITOR_PROPERTY.filter(ele => ele !== 'threshold') + axisConfig = { + ...this['axisConfig'], + extStack: { + name: `${t('chart.stack_item')} / ${t('chart.dimension')}`, + type: 'd', + limit: 1, + allowEmpty: true + } + } + propertyInner = { + ...this['propertyInner'], + 'label-selector': ['color', 'fontSize', 'hPosition', 'labelFormatter'], + 'tooltip-selector': ['fontSize', 'color', 'backgroundColor', 'tooltipFormatter', 'show'] + } + protected configLabel(chart: Chart, options: BarOptions): BarOptions { + const baseOptions = super.configLabel(chart, options) + if (!baseOptions.label) { + return baseOptions + } + const { label: labelAttr } = parseJson(chart.customAttr) + baseOptions.label.style.fill = labelAttr.color + const label = { + ...baseOptions.label, + formatter: function (param: Datum) { + return valueFormatter(param.value, labelAttr.labelFormatter) + } + } + return { + ...baseOptions, + label + } + } + + protected configTooltip(chart: Chart, options: BarOptions): BarOptions { + const tooltipAttr = parseJson(chart.customAttr).tooltip + if (!tooltipAttr.show) { + return { + ...options, + tooltip: false + } + } + const tooltip = { + formatter: (param: Datum) => { + const obj = { name: param.category, value: param.value } + const res = valueFormatter(param.value, tooltipAttr.tooltipFormatter) + obj.value = res ?? '' + return obj + }, + container: getTooltipContainer(`tooltip-${chart.id}`), + itemTpl: TOOLTIP_TPL, + enterable: true + } + return { + ...options, + tooltip + } + } + protected configColor(chart: Chart, options: BarOptions): BarOptions { + return this.configStackColor(chart, options) + } + public setupSeriesColor(chart: ChartObj, data?: any[]): ChartBasicStyle['seriesColor'] { + return setUpStackSeriesColor(chart, data) + } + + protected configData(chart: Chart, options: BarOptions): BarOptions { + const { xAxis, extStack, yAxis } = chart + const mainSort = xAxis.some(axis => axis.sort !== 'none') + const subSort = extStack.some(axis => axis.sort !== 'none') + if (mainSort || subSort) { + return options + } + const quotaSort = yAxis?.[0]?.sort !== 'none' + if (!quotaSort || !extStack.length || !yAxis.length) { + return options + } + const { data } = options + const mainAxisValueMap = data.reduce((p, n) => { + p[n.field] = p[n.field] ? p[n.field] + n.value : n.value || 0 + return p + }, {}) + const sort = yAxis[0].sort + data.sort((p, n) => { + if (sort === 'asc') { + return mainAxisValueMap[p.field] - mainAxisValueMap[n.field] + } else { + return mainAxisValueMap[n.field] - mainAxisValueMap[p.field] + } + }) + return options + } + + protected setupOptions(chart: Chart, options: BarOptions): BarOptions { + return flow( + this.configTheme, + this.configEmptyDataStrategy, + this.configData, + this.configColor, + this.configBasicStyle, + this.configLabel, + this.configTooltip, + this.configLegend, + this.configXAxis, + this.configYAxis, + this.configSlider, + this.configAnalyseHorizontal + )(chart, options, {}, this) + } + + constructor(name = 'bar-stack-horizontal') { + super(name) + this.baseOptions = { + ...this.baseOptions, + isGroup: false, + isStack: true, + meta: { + category: { + type: 'cat' + } + } + } + this.axis = [...this.axis, 'extStack'] + } +} + +/** + * 百分比堆叠条形图 + */ +export class HorizontalPercentageStackBar extends HorizontalStackBar { + propertyInner = { + ...this['propertyInner'], + 'label-selector': ['color', 'fontSize', 'hPosition', 'reserveDecimalCount'], + 'tooltip-selector': ['color', 'fontSize', 'backgroundColor', 'show'] + } + protected configLabel(chart: Chart, options: BarOptions): BarOptions { + const baseOptions = super.configLabel(chart, options) + if (!baseOptions.label) { + return baseOptions + } + const { customAttr } = chart + const l = parseJson(customAttr).label + const label = { + ...baseOptions.label, + formatter: function (param: Datum) { + if (!param.value) { + return '0%' + } + return (Math.round(param.value * 10000) / 100).toFixed(l.reserveDecimalCount) + '%' + } + } + return { + ...baseOptions, + label + } + } + + protected configTooltip(chart: Chart, options: BarOptions): BarOptions { + const tooltipAttr = parseJson(chart.customAttr).tooltip + if (!tooltipAttr.show) { + return { + ...options, + tooltip: { + showContent: false + } + } + } + const { customAttr } = chart + const l = parseJson(customAttr).label + const tooltip = { + formatter: (param: Datum) => { + const obj = { name: param.category, value: param.value } + obj.value = (Math.round(param.value * 10000) / 100).toFixed(l.reserveDecimalCount) + '%' + return obj + }, + container: getTooltipContainer(`tooltip-${chart.id}`), + itemTpl: TOOLTIP_TPL, + enterable: true + } + return { + ...options, + tooltip + } + } + protected setupOptions(chart: Chart, options: BarOptions): BarOptions { + return flow( + this.configTheme, + this.configEmptyDataStrategy, + this.configColor, + this.configBasicStyle, + this.configLabel, + this.configTooltip, + this.configLegend, + this.configXAxis, + this.configYAxis, + this.configSlider, + this.configAnalyseHorizontal + )(chart, options, {}, this) + } + + constructor() { + super('percentage-bar-stack-horizontal') + this.baseOptions = { + ...this.baseOptions, + isPercent: true + } + } +} diff --git a/frontend/src/data-visualization/chart/components/js/panel/charts/bar/progress-bar.ts b/frontend/src/data-visualization/chart/components/js/panel/charts/bar/progress-bar.ts new file mode 100644 index 0000000..b9399cf --- /dev/null +++ b/frontend/src/data-visualization/chart/components/js/panel/charts/bar/progress-bar.ts @@ -0,0 +1,389 @@ +import { G2PlotChartView, G2PlotDrawOptions } from '../../types/impl/g2plot' +import { flow, hexColorToRGBA, parseJson } from '../../../util' +import { + configAxisLabelLengthLimit, + configPlotTooltipEvent, + getTooltipContainer, + getTooltipItemConditionColor, + setGradientColor, + TOOLTIP_TPL +} from '../../common/common_antv' +import { useI18n } from '@/data-visualization/hooks/web/useI18n' +import type { Bar as G2Progress, BarOptions } from '@antv/g2plot/esm/plots/bar' +import { + BAR_AXIS_TYPE, + BAR_EDITOR_PROPERTY_INNER +} from '@/data-visualization/chart/components/js/panel/charts/bar/common' +import { cloneDeep, defaultTo } from 'lodash-es' +import { valueFormatter } from '@/data-visualization/chart/components/js/formatter' +import { Options } from '@antv/g2plot/esm' +import { DEFAULT_BASIC_STYLE } from '@/data-visualization/chart/components/editor/util/chart' + +const { t } = useI18n() + +export class ProgressBar extends G2PlotChartView { + axisConfig = { + xAxis: { + name: `${t('chart.form_type')} / ${t('chart.dimension')}`, + type: 'd', + limit: 1 + }, + yAxis: { + name: `${t('chart.progress_target')} / ${t('chart.quota')}`, + type: 'q', + limit: 1 + }, + yAxisExt: { + name: `${t('chart.progress_current')} / ${t('chart.quota')}`, + type: 'q', + limit: 1 + } + } + properties: EditorProperty[] = [ + 'background-overall-component', + 'border-style', + 'basic-style-selector', + 'label-selector', + 'tooltip-selector', + 'y-axis-selector', + 'title-selector', + 'function-cfg', + 'jump-set', + 'linkage', + 'threshold' + ] + propertyInner = { + ...BAR_EDITOR_PROPERTY_INNER, + 'legend-selector': null, + 'background-overall-component': ['all'], + 'border-style': ['all'], + 'basic-style-selector': ['colors', 'alpha', 'gradient', 'radiusColumnBar', 'columnWidthRatio'], + 'label-selector': ['hPosition', 'color', 'fontSize', 'showQuota', 'showProportion'], + 'tooltip-selector': ['fontSize', 'color', 'backgroundColor', 'tooltipFormatter', 'show'], + 'y-axis-selector': [ + 'name', + 'color', + 'fontSize', + 'axisForm', + 'axisLabel', + 'position', + 'showLengthLimit' + ], + 'function-cfg': ['emptyDataStrategy'], + threshold: ['lineThreshold'] + } + axis: AxisType[] = [...BAR_AXIS_TYPE, 'yAxisExt'] + protected baseOptions: BarOptions = { + data: [], + xField: 'progress', + yField: 'title', + seriesField: 'type', + isGroup: false, + isPercent: true, + isStack: true, + xAxis: false, + appendPadding: [0, 0, 10, 0] + } + + async drawChart(drawOptions: G2PlotDrawOptions): Promise { + const { chart, container, action } = drawOptions + if (!chart.data?.data?.length) { + return + } + const getCompletionRate = (target: number, current: number) => { + if (target === 0) { + return 100 + } + // 目标为正 当前为负 + if (target > 0 && current < 0) { + return 0 + } + // 目标为负 当前为正 正向 + if ((target < 0 && current > 0) || (target < 0 && current === 0)) { + return (2 - current / target) * 100 + } + // 目标与当前都为正 + if (target > 0 && current > 0) { + return (current / target) * 100 + } + // 目标与当前都为负 负向小于0为0 + if (target < 0 && current < 0) { + const completionRate = (2 - current / target) * 100 + return Number(Math.max(completionRate, 0).toFixed(2)) + } + return 0 + } + // data + const sourceData: Array = cloneDeep(chart.data.data) + const data1 = defaultTo(sourceData[0]?.data, []) + const data2 = defaultTo(sourceData[1]?.data, []) + const currentData = data2.map(item => { + const progress = getCompletionRate(data1.find(i => i.field === item.field)?.value, item.value) + return { + ...item, + type: 'current', + title: item.field, + id: item.quotaList[0].id, + originalValue: item.value, + originalProgress: progress, + progress: progress >= 100 ? 100 : progress + } + }) + const targetData = data1.map(item => { + const progress = 100 - currentData.find(i => i.title === item.field)?.progress + return { + ...item, + type: 'target', + title: item.field, + id: item.quotaList[0].id, + originalValue: item.value, + progress: progress + } + }) + // options + const initOptions: BarOptions = { + ...this.baseOptions, + data: currentData.concat(targetData).flat() + } + const options = this.setupOptions(chart, initOptions) + + const { Bar: G2Progress } = await import('@antv/g2plot/esm/plots/bar') + // 开始渲染 + const newChart = new G2Progress(container, options) + + newChart.on('interval:click', action) + configPlotTooltipEvent(chart, newChart) + configAxisLabelLengthLimit(chart, newChart) + return newChart + } + protected configBasicStyle(chart: Chart, options: BarOptions): BarOptions { + const basicStyle = parseJson(chart.customAttr).basicStyle + let color1 = basicStyle.colors?.map((ele, index) => { + if (index === 1) { + return hexColorToRGBA(ele, basicStyle.alpha > 10 ? 10 : basicStyle.alpha) + } else { + return hexColorToRGBA(ele, basicStyle.alpha) + } + }) + if (basicStyle.gradient) { + color1 = color1.map((ele, _index) => { + return setGradientColor(ele, true, 0) + }) + } + options = { + ...options, + color: datum => { + if (datum.type === 'target') { + return 'rgba(0, 0, 0, 0)' + } + return color1[0] + }, + barBackground: { + style: { + fill: color1[1] + } + } + } + if (basicStyle.radiusColumnBar === 'roundAngle') { + const barStyle = { + radius: [ + basicStyle.columnBarRightAngleRadius, + basicStyle.columnBarRightAngleRadius, + basicStyle.columnBarRightAngleRadius, + basicStyle.columnBarRightAngleRadius + ] + } + options = { + ...options, + barStyle + } + } + + let barWidthRatio + const _v = basicStyle.columnWidthRatio ?? DEFAULT_BASIC_STYLE.columnWidthRatio + if (_v >= 1 && _v <= 100) { + barWidthRatio = _v / 100.0 + } else if (_v < 1) { + barWidthRatio = 1 / 100.0 + } else if (_v > 100) { + barWidthRatio = 1 + } + if (barWidthRatio) { + options.barWidthRatio = barWidthRatio + } + + return options + } + protected configTooltip(chart: Chart, options: BarOptions): BarOptions { + const tooltipAttr = parseJson(chart.customAttr).tooltip + if (!tooltipAttr.show) { + return { + ...options, + tooltip: { + showContent: false + } + } + } + const yAxis = cloneDeep(chart.yAxis)[0] + const yAxisExt = cloneDeep(chart.yAxisExt)[0] + return { + ...options, + tooltip: { + showContent: true, + domStyles: { + 'g2-tooltip-marker': null + }, + customItems(originalItems) { + const result = [] + originalItems.forEach(item => { + if (item.data) { + const value = valueFormatter(item.data.value, tooltipAttr.tooltipFormatter) + if (item.data.id === yAxis.id) { + result.push({ + ...item, + marker: false, + name: yAxis.chartShowName ? yAxis.chartShowName : yAxis.name, + value: value + }) + } + if (item.data.id === yAxisExt.id) { + result.push({ + ...item, + marker: false, + name: yAxisExt.chartShowName ? yAxisExt.chartShowName : yAxisExt.name, + value: value + }) + } + } + }) + return result.length == 0 ? originalItems : result + }, + container: getTooltipContainer(`tooltip-${chart.id}`), + itemTpl: TOOLTIP_TPL, + enterable: true + } + } + } + + protected configLabel(chart: Chart, options: BarOptions): BarOptions { + const baseOptions = super.configLabel(chart, options) + if (!baseOptions.label) return baseOptions + if (!baseOptions.label.layout?.[0]) { + baseOptions.label.layout = [{ type: 'limit-in-canvas' }] + } + const { label: labelAttr } = parseJson(chart.customAttr) + baseOptions.label.style.fill = labelAttr.color + const label = { + ...baseOptions.label, + content: item => { + if (item.type === 'target') return '' + let text = '' + if (labelAttr.showQuota) text += valueFormatter(item.value, labelAttr.quotaLabelFormatter) + if (labelAttr.showProportion) { + let proportion = item.originalProgress.toFixed(labelAttr.reserveDecimalCount) + '%' + if (labelAttr.showQuota) { + proportion = ` (${proportion}) ` + } + text += proportion + } + return text + } + } + if (label.position === 'top') label.position = 'right' + return { ...baseOptions, label } + } + protected configYAxis(chart: Chart, options: BarOptions): BarOptions { + const baseOption = super.configYAxis(chart, options) + if (!baseOption.yAxis) { + return baseOption + } + if (baseOption.yAxis.position === 'left') { + baseOption.yAxis.position = 'bottom' + } + if (baseOption.yAxis.position === 'right') { + baseOption.yAxis.position = 'top' + } + return baseOption + } + setupDefaultOptions(chart: ChartObj): ChartObj { + chart.customStyle.yAxis = { + ...chart.customStyle.yAxis, + position: 'left', + axisLine: { + show: false, + lineStyle: chart.customStyle.yAxis.axisLine.lineStyle + }, + splitLine: { + show: false, + lineStyle: chart.customStyle.yAxis.axisLine.lineStyle + } + } + chart.customStyle.legend.show = false + chart.customAttr.label.show = true + chart.customAttr.label.position = 'right' + chart.customAttr.label.showQuota = false + chart.customAttr.label.showProportion = true + return chart + } + + protected configLegend(chart: Chart, options: BarOptions): BarOptions { + const o = super.configLegend(chart, options) + return { + ...o, + legend: false + } + } + + protected configEmptyDataStrategy(chart: Chart, options: BarOptions): BarOptions { + const { data } = options as unknown as Options + if (!data?.length) { + return options + } + const strategy = parseJson(chart.senior).functionCfg.emptyDataStrategy + if (strategy === 'ignoreData') { + const emptyFields = data.filter(obj => obj['value'] === null).map(obj => obj['field']) + return { + ...options, + data: data.filter(obj => { + if (emptyFields.includes(obj['field'])) { + return false + } + return true + }) + } + } + if (strategy === 'breakLine') { + data.forEach(obj => { + if (obj['value'] === null) { + obj['value'] = null + } + }) + } + if (strategy === 'setZero') { + data.forEach(obj => { + if (obj['value'] === null) { + obj['value'] = 0 + } + }) + } + return options + } + + protected setupOptions(chart: Chart, options: BarOptions): BarOptions { + return flow( + this.addConditionsStyleColorToData, + this.configTheme, + this.configBasicStyle, + this.configLabel, + this.configTooltip, + this.configLegend, + this.configYAxis, + this.configEmptyDataStrategy, + this.configBarConditions + )(chart, options) + } + + constructor() { + super('progress-bar', []) + } +} diff --git a/frontend/src/data-visualization/chart/components/js/panel/charts/bar/range-bar.ts b/frontend/src/data-visualization/chart/components/js/panel/charts/bar/range-bar.ts new file mode 100644 index 0000000..5db5326 --- /dev/null +++ b/frontend/src/data-visualization/chart/components/js/panel/charts/bar/range-bar.ts @@ -0,0 +1,434 @@ +import { + G2PlotChartView, + G2PlotDrawOptions +} from '@/data-visualization/chart/components/js/panel/types/impl/g2plot' +import type { Bar, BarOptions } from '@antv/g2plot/esm/plots/bar' +import { + configAxisLabelLengthLimit, + configPlotTooltipEvent, + getPadding, + getTooltipContainer, + setGradientColor, + TOOLTIP_TPL +} from '@/data-visualization/chart/components/js/panel/common/common_antv' +import { cloneDeep, find } from 'lodash-es' +import { flow, hexColorToRGBA, parseJson } from '@/data-visualization/chart/components/js/util' +import { valueFormatter } from '@/data-visualization/chart/components/js/formatter' +import { + BAR_AXIS_TYPE, + BAR_RANGE_EDITOR_PROPERTY, + BAR_EDITOR_PROPERTY_INNER +} from '@/data-visualization/chart/components/js/panel/charts/bar/common' +import { Datum } from '@antv/g2plot/esm/types/common' +import { useI18n } from '@/data-visualization/hooks/web/useI18n' +import { DEFAULT_BASIC_STYLE } from '@/data-visualization/chart/components/editor/util/chart' + +const { t } = useI18n() +const DEFAULT_DATA = [] + +/** + * 区间条形图 + */ +export class RangeBar extends G2PlotChartView { + axisConfig = { + xAxis: { + name: `${t('chart.drag_block_type_axis')} / ${t('chart.dimension')}`, + type: 'd' + }, + yAxis: { + name: `${t('chart.drag_block_value_start')} / ${t('chart.time_dimension_or_quota')}`, + limit: 1, + type: 'q' + }, + yAxisExt: { + name: `${t('chart.drag_block_value_end')} / ${t('chart.time_dimension_or_quota')}`, + limit: 1, + type: 'q' + } + } + properties = BAR_RANGE_EDITOR_PROPERTY.filter(p => p !== 'threshold') + propertyInner = { + ...BAR_EDITOR_PROPERTY_INNER, + 'label-selector': ['hPosition', 'color', 'fontSize', 'labelFormatter', 'showGap'], + 'tooltip-selector': [ + 'fontSize', + 'color', + 'backgroundColor', + 'tooltipFormatter', + 'showGap', + 'show' + ], + 'x-axis-selector': [...BAR_EDITOR_PROPERTY_INNER['x-axis-selector'], 'axisLabelFormatter'], + 'y-axis-selector': [ + 'name', + 'color', + 'fontSize', + 'axisLine', + 'splitLine', + 'axisForm', + 'axisLabel', + 'position', + 'showLengthLimit' + ] + } + axis: AxisType[] = [...BAR_AXIS_TYPE, 'yAxisExt'] + protected baseOptions: BarOptions = { + data: [], + xField: 'values', + yField: 'field', + colorField: 'category', + isGroup: true + } + + async drawChart(drawOptions: G2PlotDrawOptions): Promise { + const { chart, container, action } = drawOptions + if (!chart.data?.data?.length) { + return + } + // data + const data: Array = cloneDeep(chart.data.data) + + data.forEach(d => { + d.tempId = (Math.random() * 10000000).toString() + }) + + const ifAggregate = !!chart.aggregate + + const isDate = !!chart.data.isDate + + const axis = chart.yAxis ?? chart.yAxisExt ?? [] + let dateFormat: string + const dateSplit = axis[0]?.datePattern === 'date_split' ? '/' : '-' + switch (axis[0]?.dateStyle) { + case 'y': + dateFormat = 'YYYY' + break + case 'y_M': + dateFormat = 'YYYY' + dateSplit + 'MM' + break + case 'y_M_d': + dateFormat = 'YYYY' + dateSplit + 'MM' + dateSplit + 'DD' + break + // case 'H_m_s': + // dateFormat = 'HH:mm:ss' + // break + case 'y_M_d_H': + dateFormat = 'YYYY' + dateSplit + 'MM' + dateSplit + 'DD' + ' HH' + break + case 'y_M_d_H_m': + dateFormat = 'YYYY' + dateSplit + 'MM' + dateSplit + 'DD' + ' HH:mm' + break + case 'y_M_d_H_m_s': + dateFormat = 'YYYY' + dateSplit + 'MM' + dateSplit + 'DD' + ' HH:mm:ss' + break + default: + dateFormat = 'YYYY-MM-dd HH:mm:ss' + } + + const minTime = chart.data.minTime + const maxTime = chart.data.maxTime + + const minNumber = chart.data.min + const maxNumber = chart.data.max + + // options + const initOptions: BarOptions = { + ...this.baseOptions, + appendPadding: getPadding(chart), + data, + seriesField: isDate ? (ifAggregate ? 'category' : undefined) : 'category', + isGroup: isDate ? !ifAggregate : false, + isStack: isDate ? !ifAggregate : false, + meta: isDate + ? { + values: { + type: 'time', + min: minTime, + max: maxTime, + mask: dateFormat + }, + tempId: { + key: true + } + } + : { + values: { + min: minNumber, + max: maxNumber, + mask: dateFormat + }, + tempId: { + key: true + } + } + } + + const options = this.setupOptions(chart, initOptions) + + const { Bar: BarClass } = await import('@antv/g2plot/esm/plots/bar') + // 开始渲染 + const newChart = new BarClass(container, options) + + newChart.on('interval:click', action) + configPlotTooltipEvent(chart, newChart) + configAxisLabelLengthLimit(chart, newChart) + return newChart + } + + protected configXAxis(chart: Chart, options: BarOptions): BarOptions { + const tmpOptions = super.configXAxis(chart, options) + if (!tmpOptions.xAxis) { + return tmpOptions + } + const xAxis = parseJson(chart.customStyle).xAxis + const axisValue = xAxis.axisValue + const isDate = !!chart.data.isDate + if (tmpOptions.xAxis.label) { + tmpOptions.xAxis.label.formatter = value => { + if (isDate) { + return value + } + return valueFormatter(value, xAxis.axisLabelFormatter) + } + } + if (tmpOptions.xAxis.position === 'top') { + tmpOptions.xAxis.position = 'left' + } + if (tmpOptions.xAxis.position === 'bottom') { + tmpOptions.xAxis.position = 'right' + } + if (!axisValue?.auto) { + const axis = { + xAxis: { + ...tmpOptions.xAxis, + min: axisValue.min, + max: axisValue.max, + minLimit: axisValue.min, + maxLimit: axisValue.max, + tickCount: axisValue.splitCount + } + } + return { ...tmpOptions, ...axis } + } + return tmpOptions + } + + protected configTooltip(chart: Chart, options: BarOptions): BarOptions { + const isDate = !!chart.data.isDate + let tooltip + let customAttr: DeepPartial + if (chart.customAttr) { + customAttr = parseJson(chart.customAttr) + // tooltip + if (customAttr.tooltip) { + const t = JSON.parse(JSON.stringify(customAttr.tooltip)) + if (t.show) { + tooltip = { + fields: ['values', 'field', 'gap'], + formatter: function (param: Datum) { + let res + if (isDate) { + res = param.values[0] + ' ~ ' + param.values[1] + if (t.showGap) { + res = res + ' (' + param.gap + ')' + } + } else { + res = + valueFormatter(param.values[0], t.tooltipFormatter) + + ' ~ ' + + valueFormatter(param.values[1], t.tooltipFormatter) + if (t.showGap) { + res = res + ' (' + valueFormatter(param.gap, t.tooltipFormatter) + ')' + } + } + return { value: res, values: param.values, name: param.field } + }, + container: getTooltipContainer(`tooltip-${chart.id}`), + itemTpl: TOOLTIP_TPL, + enterable: true + } + } else { + tooltip = false + } + } + } + return { ...options, tooltip } + } + + protected configBasicStyle(chart: Chart, options: BarOptions): BarOptions { + const isDate = !!chart.data.isDate + const ifAggregate = !!chart.aggregate + const basicStyle = parseJson(chart.customAttr).basicStyle + + if (isDate && !ifAggregate) { + const customColors = [] + const groups = [] + for (let i = 0; i < chart.data.data.length; i++) { + const name = chart.data.data[i].field + if (groups.indexOf(name) < 0) { + groups.push(name) + } + } + for (let i = 0; i < groups.length; i++) { + const s = groups[i] + customColors.push({ + name: s, + color: basicStyle.colors[i % basicStyle.colors.length], + isCustom: false + }) + } + const color = obj => { + const colorObj = find(customColors, o => { + return o.name === obj.field + }) + if (colorObj === undefined) { + return undefined + } + const color = hexColorToRGBA(colorObj.color, basicStyle.alpha) + if (basicStyle.gradient) { + return setGradientColor(color, true) + } else { + return color + } + } + + options = { + ...options, + color + } + } else { + if (basicStyle.gradient) { + let color = basicStyle.colors + color = color.map(ele => { + const tmp = hexColorToRGBA(ele, basicStyle.alpha) + return setGradientColor(tmp, true) + }) + options = { + ...options, + color + } + } + } + if (basicStyle.radiusColumnBar === 'roundAngle') { + const barStyle = { + radius: [ + basicStyle.columnBarRightAngleRadius, + basicStyle.columnBarRightAngleRadius, + basicStyle.columnBarRightAngleRadius, + basicStyle.columnBarRightAngleRadius + ] + } + options = { + ...options, + barStyle + } + } + let barWidthRatio + const _v = basicStyle.columnWidthRatio ?? DEFAULT_BASIC_STYLE.columnWidthRatio + if (_v >= 1 && _v <= 100) { + barWidthRatio = _v / 100.0 + } else if (_v < 1) { + barWidthRatio = 1 / 100.0 + } else if (_v > 100) { + barWidthRatio = 1 + } + if (barWidthRatio) { + options.barWidthRatio = barWidthRatio + } + + return options + } + + setupDefaultOptions(chart: ChartObj): ChartObj { + const { customAttr, senior } = chart + const { label } = customAttr + if (!['left', 'middle', 'right'].includes(label.position)) { + label.position = 'middle' + } + senior.functionCfg.emptyDataStrategy = 'ignoreData' + return chart + } + + protected configLabel(chart: Chart, options: BarOptions): BarOptions { + const isDate = !!chart.data.isDate + const ifAggregate = !!chart.aggregate + + const tmpOptions = super.configLabel(chart, options) + if (!tmpOptions.label) { + return { + ...tmpOptions, + label: false + } + } + const labelAttr = parseJson(chart.customAttr).label + + if (isDate && !ifAggregate) { + if (!tmpOptions.label.layout) { + tmpOptions.label.layout = [] + } + tmpOptions.label.layout.push({ type: 'interval-hide-overlap' }) + tmpOptions.label.layout.push({ type: 'limit-in-plot', cfg: { action: 'hide' } }) + } + + const label = { + fields: [], + ...tmpOptions.label, + formatter: (param: Datum) => { + let res + if (isDate) { + if (labelAttr.showGap) { + res = param.gap + } else { + res = param.values[0] + ' ~ ' + param.values[1] + } + } else { + if (labelAttr.showGap) { + res = valueFormatter(param.gap, labelAttr.labelFormatter) + } else { + res = + valueFormatter(param.values[0], labelAttr.labelFormatter) + + ' ~ ' + + valueFormatter(param.values[1], labelAttr.labelFormatter) + } + } + return res + } + } + return { + ...tmpOptions, + label + } + } + + protected configYAxis(chart: Chart, options: BarOptions): BarOptions { + const tmpOptions = super.configYAxis(chart, options) + if (!tmpOptions.yAxis) { + return tmpOptions + } + if (tmpOptions.yAxis.position === 'left') { + tmpOptions.yAxis.position = 'bottom' + } + if (tmpOptions.yAxis.position === 'right') { + tmpOptions.yAxis.position = 'top' + } + return tmpOptions + } + + protected setupOptions(chart: Chart, options: BarOptions): BarOptions { + return flow( + this.configTheme, + this.configBasicStyle, + this.configLabel, + this.configTooltip, + this.configLegend, + this.configXAxis, + this.configYAxis, + this.configSlider, + this.configEmptyDataStrategy + )(chart, options) + } + + constructor(name = 'bar-range') { + super(name, DEFAULT_DATA) + } +} diff --git a/frontend/src/data-visualization/chart/components/js/panel/charts/bar/waterfall.ts b/frontend/src/data-visualization/chart/components/js/panel/charts/bar/waterfall.ts new file mode 100644 index 0000000..f827924 --- /dev/null +++ b/frontend/src/data-visualization/chart/components/js/panel/charts/bar/waterfall.ts @@ -0,0 +1,337 @@ +import type { WaterfallOptions, Waterfall as G2Waterfall } from '@antv/g2plot/esm/plots/waterfall' +import { G2PlotChartView, G2PlotDrawOptions } from '../../types/impl/g2plot' +import { flow, hexColorToRGBA, parseJson } from '../../../util' +import { valueFormatter } from '../../../formatter' +import { + configAxisLabelLengthLimit, + configPlotTooltipEvent, + getPadding, + getTooltipContainer, + getTooltipItemConditionColor, + getTooltipSeriesTotalMap, + setGradientColor, + TOOLTIP_TPL +} from '../../common/common_antv' +import { isEmpty } from 'lodash-es' +import { useI18n } from '@/data-visualization/hooks/web/useI18n' +import { DEFAULT_BASIC_STYLE } from '@/data-visualization/chart/components/editor/util/chart' +const { t } = useI18n() + +/** + * 瀑布图 + */ +export class Waterfall extends G2PlotChartView { + properties: EditorProperty[] = [ + 'background-overall-component', + 'border-style', + 'basic-style-selector', + 'label-selector', + 'tooltip-selector', + 'title-selector', + 'legend-selector', + 'x-axis-selector', + 'y-axis-selector', + 'threshold' + ] + propertyInner: EditorPropertyInner = { + 'background-overall-component': ['all'], + 'border-style': ['all'], + 'basic-style-selector': ['colors', 'alpha', 'gradient', 'columnWidthRatio'], + 'label-selector': ['fontSize', 'color', 'vPosition', 'labelFormatter'], + 'tooltip-selector': ['fontSize', 'color', 'backgroundColor', 'seriesTooltipFormatter', 'show'], + 'title-selector': [ + 'title', + 'fontSize', + 'color', + 'hPosition', + 'isItalic', + 'isBolder', + 'remarkShow', + 'fontFamily', + 'letterSpace', + 'fontShadow' + ], + 'legend-selector': ['icon', 'orient', 'fontSize', 'color', 'hPosition', 'vPosition'], + 'x-axis-selector': [ + 'position', + 'name', + 'color', + 'fontSize', + 'axisLine', + 'splitLine', + 'axisForm', + 'axisLabel' + ], + 'y-axis-selector': [ + 'position', + 'name', + 'color', + 'fontSize', + 'axisValue', + 'splitLine', + 'axisForm', + 'axisLabel', + 'axisLabelFormatter', + 'showLengthLimit' + ], + threshold: ['lineThreshold'] + } + axis: AxisType[] = ['xAxis', 'yAxis', 'filter', 'drill', 'extLabel', 'extTooltip'] + axisConfig = { + xAxis: { + name: `${t('chart.drag_block_type_axis')} / ${t('chart.dimension')}`, + type: 'd' + }, + yAxis: { + name: `${t('chart.drag_block_value_axis')} / ${t('chart.quota')}`, + type: 'q', + limit: 1 + } + } + async drawChart(drawOptions: G2PlotDrawOptions): Promise { + const { chart, container, action } = drawOptions + if (!chart.data?.data) { + return + } + const data = chart.data.data + const baseOptions = { + data, + xField: 'field', + yField: 'value', + seriesField: 'category', + appendPadding: getPadding(chart) + } + const options = this.setupOptions(chart, baseOptions) + const { Waterfall: G2Waterfall } = await import('@antv/g2plot/esm/plots/waterfall') + const newChart = new G2Waterfall(container, options) + newChart.on('interval:click', action) + configPlotTooltipEvent(chart, newChart) + configAxisLabelLengthLimit(chart, newChart) + return newChart + } + + protected configMeta(chart: Chart, options: WaterfallOptions): WaterfallOptions { + const yAxis = chart.yAxis + const meta: WaterfallOptions['meta'] = { + field: { + type: 'cat' + } + } + if (!yAxis?.length) { + return { + ...options, + meta + } + } + const f = yAxis[0] + const yAxisStyle = parseJson(chart.customStyle).yAxis + meta.value = { + alias: f.name, + formatter: (value: number) => { + return valueFormatter(value, yAxisStyle.axisLabelFormatter) + } + } + return { + ...options, + meta + } + } + + protected configBasicStyle(chart: Chart, options: WaterfallOptions): WaterfallOptions { + const customAttr = parseJson(chart.customAttr) + const { colors, gradient, alpha } = customAttr.basicStyle + const [risingColorRgba, fallingColorRgba, totalColorRgba] = colors + + let columnWidthRatio + const _v = customAttr.basicStyle.columnWidthRatio ?? DEFAULT_BASIC_STYLE.columnWidthRatio + if (_v >= 1 && _v <= 100) { + columnWidthRatio = _v / 100.0 + } else if (_v < 1) { + columnWidthRatio = 1 / 100.0 + } else if (_v > 100) { + columnWidthRatio = 1 + } + if (columnWidthRatio) { + options.columnWidthRatio = columnWidthRatio + } + + return { + ...options, + total: { + label: t('chart.waterfall_total'), + style: { + fill: setGradientColor(hexColorToRGBA(totalColorRgba, alpha), gradient, 270) + } + }, + risingFill: setGradientColor(hexColorToRGBA(risingColorRgba, alpha), gradient, 270), + fallingFill: setGradientColor(hexColorToRGBA(fallingColorRgba, alpha), gradient, 270) + } + } + + protected configYAxis(chart: Chart, options: WaterfallOptions): WaterfallOptions { + const tmpOptions = super.configYAxis(chart, options) + if (!tmpOptions.yAxis) { + return tmpOptions + } + const yAxis = parseJson(chart.customStyle).yAxis + const axisValue = yAxis.axisValue + if (!axisValue?.auto) { + const axis = { + yAxis: { + ...tmpOptions.yAxis, + min: axisValue.min, + max: axisValue.max, + minLimit: axisValue.min, + maxLimit: axisValue.max, + tickCount: axisValue.splitCount + } + } + return { ...tmpOptions, ...axis } + } + return tmpOptions + } + + protected configTooltip(chart: Chart, options: WaterfallOptions): WaterfallOptions { + const customAttr: DeepPartial = parseJson(chart.customAttr) + const tooltipAttr = customAttr.tooltip + const yAxis = chart.yAxis + if (!tooltipAttr.show) { + return { + ...options, + tooltip: false + } + } + const formatterMap = tooltipAttr.seriesTooltipFormatter + ?.filter(i => i.show) + .reduce((pre, next) => { + pre[next.id] = next + return pre + }, {}) as Record + const totalMap = getTooltipSeriesTotalMap(options.data) + const tooltip: WaterfallOptions['tooltip'] = { + showTitle: true, + customItems(originalItems) { + if (!tooltipAttr.seriesTooltipFormatter?.length) { + return originalItems + } + const result = [] + const head = originalItems[0] + // 汇总 + if (!head.data.quotaList) { + Object.keys(formatterMap).forEach(id => { + const formatter = formatterMap[id] + let tmpValue = totalMap[id] + let color = 'grey' + if (id === yAxis[0].id) { + tmpValue = head.data.value + color = head.color + } + const value = valueFormatter(tmpValue, formatter.formatterCfg) + const name = isEmpty(formatter.chartShowName) ? formatter.name : formatter.chartShowName + if (id === yAxis[0].id) { + result.unshift({ color, name, value }) + return + } + result.push({ color, name, value }) + }) + return result + } + originalItems + .filter(item => formatterMap[item.data.quotaList[0].id]) + .forEach(item => { + const formatter = formatterMap[item.data.quotaList[0].id] + const itemValue = (item.value + '').replace(/,/g, '') + formatter.formatterCfg.type = 'value' + const value = valueFormatter(parseFloat(itemValue), formatter.formatterCfg) + const name = isEmpty(formatter.chartShowName) ? formatter.name : formatter.chartShowName + result.push({ ...item, name, value }) + }) + head.data.dynamicTooltipValue?.forEach(item => { + const formatter = formatterMap[item.fieldId] + if (formatter) { + const itemValue = (item.value + '').replace(/,/g, '') + const value = valueFormatter(parseFloat(itemValue), formatter.formatterCfg) + const name = isEmpty(formatter.chartShowName) ? formatter.name : formatter.chartShowName + result.push({ color: 'grey', name, value }) + } + }) + result.forEach(item => { + const color = getTooltipItemConditionColor(item) + item.color = color + }) + return result + }, + container: getTooltipContainer(`tooltip-${chart.id}`), + itemTpl: TOOLTIP_TPL, + enterable: true + } + return { + ...options, + tooltip + } + } + + protected configLegend(chart: Chart, options: WaterfallOptions): WaterfallOptions { + const tmp = super.configLegend(chart, options) + if (!tmp.legend) { + return tmp + } + const customAttr = parseJson(chart.customAttr) + const { colors, gradient, alpha } = customAttr.basicStyle + const [risingColorRgba, fallingColorRgba, totalColorRgba] = colors + return { + ...tmp, + legend: { + ...tmp.legend, + items: [ + { + name: t('chart.increase'), + value: '', + marker: { + style: { + fill: setGradientColor(hexColorToRGBA(risingColorRgba, alpha), gradient, 270) + } + } + }, + { + name: t('chart.decrease'), + value: '', + marker: { + style: { + fill: setGradientColor(hexColorToRGBA(fallingColorRgba, alpha), gradient, 270) + } + } + }, + { + name: t('chart.waterfall_total'), + value: '', + marker: { + style: { + fill: setGradientColor(hexColorToRGBA(totalColorRgba, alpha), gradient, 270) + } + } + } + ] + } + } + } + + protected setupOptions(chart: Chart, options: WaterfallOptions): WaterfallOptions { + return flow( + this.addConditionsStyleColorToData, + this.configTheme, + this.configLegend, + this.configBasicStyle, + this.configLabel, + this.configTooltip, + this.configXAxis, + this.configYAxis, + this.configMeta, + this.configBarConditions + )(chart, options) + } + + constructor() { + super('waterfall', []) + } +} diff --git a/frontend/src/data-visualization/chart/components/js/panel/charts/line/area.ts b/frontend/src/data-visualization/chart/components/js/panel/charts/line/area.ts new file mode 100644 index 0000000..28a3fc6 --- /dev/null +++ b/frontend/src/data-visualization/chart/components/js/panel/charts/line/area.ts @@ -0,0 +1,396 @@ +import { + G2PlotChartView, + G2PlotDrawOptions +} from '@/data-visualization/chart/components/js/panel/types/impl/g2plot' +import type { Area as G2Area, AreaOptions } from '@antv/g2plot/esm/plots/area' +import { + configPlotTooltipEvent, + getPadding, + getTooltipContainer, + setGradientColor, + TOOLTIP_TPL +} from '@/data-visualization/chart/components/js/panel/common/common_antv' +import { cloneDeep } from 'lodash-es' +import { + flow, + getLineConditions, + getLineLabelColorByCondition, + hexColorToRGBA, + parseJson, + setUpStackSeriesColor +} from '@/data-visualization/chart/components/js/util' +import { valueFormatter } from '@/data-visualization/chart/components/js/formatter' +import { + LINE_AXIS_TYPE, + LINE_EDITOR_PROPERTY, + LINE_EDITOR_PROPERTY_INNER +} from '@/data-visualization/chart/components/js/panel/charts/line/common' +import { Label } from '@antv/g2plot/lib/types/label' +import { Datum } from '@antv/g2plot/esm/types/common' +import { useI18n } from '@/data-visualization/hooks/web/useI18n' +import { DEFAULT_LABEL } from '@/data-visualization/chart/components/editor/util/chart' +import { clearExtremum, extremumEvt } from '@/data-visualization/chart/components/js/extremumUitl' +import { Group } from '@antv/g-canvas' + +const { t } = useI18n() +const DEFAULT_DATA = [] +export class Area extends G2PlotChartView { + properties = LINE_EDITOR_PROPERTY + propertyInner = { + ...LINE_EDITOR_PROPERTY_INNER, + 'basic-style-selector': [ + ...LINE_EDITOR_PROPERTY_INNER['basic-style-selector'], + 'gradient', + 'seriesColor' + ], + 'label-selector': ['seriesLabelVPosition', 'seriesLabelFormatter', 'showExtremum'], + 'tooltip-selector': [ + ...LINE_EDITOR_PROPERTY_INNER['tooltip-selector'], + 'seriesTooltipFormatter' + ] + } + axis: AxisType[] = [...LINE_AXIS_TYPE] + axisConfig = { + ...this['axisConfig'], + xAxis: { + name: `${t('chart.drag_block_type_axis')} / ${t('chart.dimension')}`, + type: 'd' + }, + yAxis: { + name: `${t('chart.drag_block_value_axis')} / ${t('chart.quota')}`, + type: 'q' + } + } + baseOptions: AreaOptions = { + data: [], + xField: 'field', + yField: 'value', + seriesField: 'category', + isStack: false, + interactions: [ + { + type: 'legend-active', + cfg: { + start: [{ trigger: 'legend-item:mouseenter', action: ['element-active:reset'] }], + end: [{ trigger: 'legend-item:mouseleave', action: ['element-active:reset'] }] + } + }, + { + type: 'legend-filter', + cfg: { + start: [ + { + trigger: 'legend-item:click', + action: [ + 'list-unchecked:toggle', + 'data-filter:filter', + 'element-active:reset', + 'element-highlight:reset' + ] + } + ] + } + }, + { + type: 'active-region', + cfg: { + start: [{ trigger: 'element:mousemove', action: 'active-region:show' }], + end: [{ trigger: 'element:mouseleave', action: 'active-region:hide' }] + } + } + ] + } + + async drawChart(drawOptions: G2PlotDrawOptions): Promise { + const { chart, container, action } = drawOptions + if (!chart.data?.data?.length) { + chart.container = container + clearExtremum(chart) + return + } + // data + const data = cloneDeep(chart.data.data) + + const initOptions: AreaOptions = { + ...this.baseOptions, + data, + appendPadding: getPadding(chart) + } + // options + const options = this.setupOptions(chart, initOptions) + const { Area: G2Area } = await import('@antv/g2plot/esm/plots/area') + // 开始渲染 + const newChart = new G2Area(container, options) + + newChart.on('point:click', action) + extremumEvt(newChart, chart, options, container) + configPlotTooltipEvent(chart, newChart) + return newChart + } + + protected configLabel(chart: Chart, options: AreaOptions): AreaOptions { + const tmpOptions = super.configLabel(chart, options) + if (!tmpOptions.label) { + return { + ...tmpOptions, + label: false + } + } + const { label: labelAttr, basicStyle } = parseJson(chart.customAttr) + const conditions = getLineConditions(chart) + const formatterMap = labelAttr.seriesLabelFormatter?.reduce((pre, next) => { + pre[next.id] = next + return pre + }, {}) + tmpOptions.label.style.fill = DEFAULT_LABEL.color + const label = { + fields: [], + ...tmpOptions.label, + layout: labelAttr.fullDisplay ? [{ type: 'limit-in-plot' }] : tmpOptions.label.layout, + formatter: (data: Datum, _point) => { + if (data.EXTREME) { + return '' + } + if (!labelAttr.seriesLabelFormatter?.length) { + return data.value + } + const labelCfg = formatterMap?.[data.quotaList[0].id] as SeriesFormatter + if (!labelCfg) { + return data.value + } + if (!labelCfg.show) { + return + } + const position = + labelCfg.position === 'top' + ? -2 - basicStyle.lineSymbolSize + : 10 + basicStyle.lineSymbolSize + const value = valueFormatter(data.value, labelCfg.formatterCfg) + const color = + getLineLabelColorByCondition(conditions, data.value, data.quotaList[0].id) || + labelCfg.color + const group = new Group({}) + group.addShape({ + type: 'text', + attrs: { + x: 0, + y: position, + text: value, + textAlign: 'start', + textBaseline: 'top', + fontSize: labelCfg.fontSize, + fontFamily: chart.fontFamily, + fill: color + } + }) + return group + } + } + return { + ...tmpOptions, + label + } + } + + protected configBasicStyle(chart: Chart, options: AreaOptions): AreaOptions { + // size + const customAttr: DeepPartial = parseJson(chart.customAttr) + const s: DeepPartial = JSON.parse(JSON.stringify(customAttr.basicStyle)) + const smooth = s.lineSmooth + const point = { + size: s.lineSymbolSize, + shape: s.lineSymbol + } + const line = { + style: { + lineWidth: s.lineWidth + } + } + // custom color + const { colors, alpha } = customAttr.basicStyle + const areaColors = [...colors, ...colors] + let areaStyle + if (customAttr.basicStyle.gradient) { + const colorMap = new Map() + const yAxis = parseJson(chart.customStyle).yAxis + const axisValue = yAxis.axisValue + const start = + !axisValue?.auto && axisValue.min && axisValue.max ? axisValue.min / axisValue.max : 0 + areaStyle = item => { + let ele: string + const key = `${item.field}-${item.category}` + if (colorMap.has(key)) { + ele = colorMap.get(key) + } else { + ele = areaColors.shift() + colorMap.set(key, ele) + } + if (ele) { + return { + fill: setGradientColor(hexColorToRGBA(ele, alpha), true, 270, start) + } + } + return { + fill: 'rgba(255,255,255,0)' + } + } + } + return { + ...options, + smooth, + line, + point, + areaStyle + } + } + + protected configYAxis(chart: Chart, options: AreaOptions): AreaOptions { + const tmpOptions = super.configYAxis(chart, options) + if (!tmpOptions.yAxis) { + return tmpOptions + } + const yAxis = parseJson(chart.customStyle).yAxis + if (tmpOptions.yAxis.label) { + tmpOptions.yAxis.label.formatter = value => { + return valueFormatter(value, yAxis.axisLabelFormatter) + } + } + const axisValue = yAxis.axisValue + if (!axisValue?.auto) { + const axis = { + yAxis: { + ...tmpOptions.yAxis, + min: axisValue.min, + max: axisValue.max, + minLimit: axisValue.min, + maxLimit: axisValue.max, + tickCount: axisValue.splitCount + } + } + return { ...tmpOptions, ...axis } + } + return tmpOptions + } + + protected configTooltip(chart: Chart, options: AreaOptions): AreaOptions { + return super.configMultiSeriesTooltip(chart, options) + } + + protected setupOptions(chart: Chart, options: AreaOptions): AreaOptions { + return flow( + this.configTheme, + this.configEmptyDataStrategy, + this.configColor, + this.configLabel, + this.configTooltip, + this.configBasicStyle, + this.configLegend, + this.configXAxis, + this.configYAxis, + this.configSlider, + this.configAnalyse, + this.configConditions + )(chart, options, {}, this) + } + + constructor(name = 'area') { + super(name, DEFAULT_DATA) + } +} + +/** + * 堆叠面积图 + */ +export class StackArea extends Area { + propertyInner = { + ...this['propertyInner'], + 'label-selector': ['vPosition', 'fontSize', 'color', 'labelFormatter'], + 'tooltip-selector': ['fontSize', 'color', 'tooltipFormatter', 'show'] + } + axisConfig = { + ...this['axisConfig'], + extStack: { + name: `${t('chart.stack_item')} / ${t('chart.dimension')}`, + type: 'd', + limit: 1, + allowEmpty: true + } + } + protected configLabel(chart: Chart, options: AreaOptions): AreaOptions { + const { label: labelAttr, basicStyle } = parseJson(chart.customAttr) + if (!labelAttr?.show) { + return { + ...options, + label: false + } + } + const layout = [] + if (!labelAttr.fullDisplay) { + const tmpOptions = super.configLabel(chart, options) + layout.push(...tmpOptions.label.layout) + } else { + layout.push({ type: 'limit-in-plot' }) + } + const position = + labelAttr.position === 'top' ? -2 - basicStyle.lineSymbolSize : 8 + basicStyle.lineSymbolSize + const label: Label = { + position: labelAttr.position as any, + offsetY: position, + layout, + style: { + fill: labelAttr.color, + fontSize: labelAttr.fontSize + }, + formatter: function (param: Datum) { + return valueFormatter(param.value, labelAttr.labelFormatter) + } + } + return { ...options, label } + } + + public setupDefaultOptions(chart: ChartObj): ChartObj { + chart.senior.functionCfg.emptyDataStrategy = 'ignoreData' + return chart + } + + protected configColor(chart: Chart, options: AreaOptions): AreaOptions { + return this.configStackColor(chart, options) + } + public setupSeriesColor(chart: ChartObj, data?: any[]): ChartBasicStyle['seriesColor'] { + return setUpStackSeriesColor(chart, data) + } + protected configTooltip(chart: Chart, options: AreaOptions): AreaOptions { + const customAttr: DeepPartial = parseJson(chart.customAttr) + const tooltipAttr = customAttr.tooltip + if (!tooltipAttr.show) { + return { + ...options, + tooltip: false + } + } + const tooltip = { + formatter: function (param: Datum) { + const obj = { + name: param.category, + value: valueFormatter(param.value, tooltipAttr.tooltipFormatter) + } + return obj + }, + container: getTooltipContainer(`tooltip-${chart.id}`), + itemTpl: TOOLTIP_TPL, + enterable: true + } + return { ...options, tooltip } + } + + constructor() { + super('area-stack') + this.baseOptions = { + ...this.baseOptions, + isStack: true + } + delete this.propertyInner.threshold + this.properties = this.properties.filter(item => item !== 'threshold') + this.axis.push('extStack') + } +} diff --git a/frontend/src/data-visualization/chart/components/js/panel/charts/line/common.ts b/frontend/src/data-visualization/chart/components/js/panel/charts/line/common.ts new file mode 100644 index 0000000..ffc4241 --- /dev/null +++ b/frontend/src/data-visualization/chart/components/js/panel/charts/line/common.ts @@ -0,0 +1,74 @@ +export const LINE_EDITOR_PROPERTY: EditorProperty[] = [ + 'background-overall-component', + 'border-style', + 'basic-style-selector', + 'x-axis-selector', + 'y-axis-selector', + 'title-selector', + 'legend-selector', + 'label-selector', + 'tooltip-selector', + 'assist-line', + 'function-cfg', + 'jump-set', + 'linkage', + 'threshold' +] +export const LINE_EDITOR_PROPERTY_INNER: EditorPropertyInner = { + 'background-overall-component': ['all'], + 'border-style': ['all'], + 'label-selector': ['fontSize', 'color'], + 'tooltip-selector': ['fontSize', 'color', 'backgroundColor', 'show'], + 'basic-style-selector': [ + 'colors', + 'alpha', + 'lineWidth', + 'lineSymbol', + 'lineSymbolSize', + 'lineSmooth' + ], + 'x-axis-selector': [ + 'name', + 'color', + 'fontSize', + 'position', + 'axisLabel', + 'axisLine', + 'splitLine' + ], + 'y-axis-selector': [ + 'name', + 'color', + 'fontSize', + 'position', + 'axisLabel', + 'axisLine', + 'splitLine', + 'axisValue', + 'axisLabelFormatter' + ], + 'title-selector': [ + 'title', + 'fontSize', + 'color', + 'hPosition', + 'isItalic', + 'isBolder', + 'remarkShow', + 'fontFamily', + 'letterSpace', + 'fontShadow' + ], + 'legend-selector': ['icon', 'orient', 'fontSize', 'color', 'hPosition', 'vPosition'], + 'function-cfg': ['slider', 'emptyDataStrategy'], + threshold: ['lineThreshold'] +} + +export const LINE_AXIS_TYPE: AxisType[] = [ + 'xAxis', + 'yAxis', + 'drill', + 'filter', + 'extLabel', + 'extTooltip' +] diff --git a/frontend/src/data-visualization/chart/components/js/panel/charts/line/line.ts b/frontend/src/data-visualization/chart/components/js/panel/charts/line/line.ts new file mode 100644 index 0000000..d128c6c --- /dev/null +++ b/frontend/src/data-visualization/chart/components/js/panel/charts/line/line.ts @@ -0,0 +1,377 @@ +import { + G2PlotChartView, + G2PlotDrawOptions +} from '@/data-visualization/chart/components/js/panel/types/impl/g2plot' +import type { Line as G2Line, LineOptions } from '@antv/g2plot/esm/plots/line' +import { + configPlotTooltipEvent, + getPadding, + getTooltipContainer, + TOOLTIP_TPL +} from '../../common/common_antv' +import { + flow, + getLineConditions, + getLineLabelColorByCondition, + hexColorToRGBA, + parseJson, + setUpGroupSeriesColor +} from '@/data-visualization/chart/components/js/util' +import { cloneDeep, defaults, isEmpty } from 'lodash-es' +import { valueFormatter } from '@/data-visualization/chart/components/js/formatter' +import { + LINE_AXIS_TYPE, + LINE_EDITOR_PROPERTY, + LINE_EDITOR_PROPERTY_INNER +} from '@/data-visualization/chart/components/js/panel/charts/line/common' +import type { Datum } from '@antv/g2plot/esm/types/common' +import { useI18n } from '@/data-visualization/hooks/web/useI18n' +import { DEFAULT_LABEL, DEFAULT_LEGEND_STYLE } from '@/data-visualization/chart/components/editor/util/chart' +import { clearExtremum, extremumEvt } from '@/data-visualization/chart/components/js/extremumUitl' +import { Group } from '@antv/g-canvas' + +const { t } = useI18n() +const DEFAULT_DATA = [] +/** + * 折线图 + */ +export class Line extends G2PlotChartView { + properties = LINE_EDITOR_PROPERTY + propertyInner = { + ...LINE_EDITOR_PROPERTY_INNER, + 'basic-style-selector': [...LINE_EDITOR_PROPERTY_INNER['basic-style-selector'], 'seriesColor'], + 'label-selector': ['seriesLabelVPosition', 'seriesLabelFormatter', 'showExtremum'], + 'tooltip-selector': [ + ...LINE_EDITOR_PROPERTY_INNER['tooltip-selector'], + 'seriesTooltipFormatter' + ] + } + axis: AxisType[] = [...LINE_AXIS_TYPE, 'xAxisExt'] + axisConfig = { + ...this['axisConfig'], + xAxis: { + name: `${t('chart.drag_block_type_axis')} / ${t('chart.dimension')}`, + type: 'd' + }, + xAxisExt: { + name: `${t('chart.chart_group')} / ${t('chart.dimension')}`, + type: 'd', + limit: 1, + allowEmpty: true + }, + yAxis: { + name: `${t('chart.drag_block_value_axis')} / ${t('chart.quota')}`, + type: 'q' + } + } + async drawChart(drawOptions: G2PlotDrawOptions): Promise { + const { chart, action, container } = drawOptions + if (!chart.data?.data?.length) { + chart.container = container + clearExtremum(chart) + return + } + const data = cloneDeep(chart.data.data) + // custom color + const customAttr = parseJson(chart.customAttr) + const color = customAttr.basicStyle.colors + // options + const initOptions: LineOptions = { + data, + xField: 'field', + yField: 'value', + seriesField: 'category', + appendPadding: getPadding(chart), + color, + interactions: [ + { + type: 'legend-active', + cfg: { + start: [{ trigger: 'legend-item:mouseenter', action: ['element-active:reset'] }], + end: [{ trigger: 'legend-item:mouseleave', action: ['element-active:reset'] }] + } + }, + { + type: 'legend-filter', + cfg: { + start: [ + { + trigger: 'legend-item:click', + action: [ + 'list-unchecked:toggle', + 'data-filter:filter', + 'element-active:reset', + 'element-highlight:reset' + ] + } + ] + } + }, + { + type: 'active-region', + cfg: { + start: [{ trigger: 'element:mousemove', action: 'active-region:show' }], + end: [{ trigger: 'element:mouseleave', action: 'active-region:hide' }] + } + } + ] + } + const options = this.setupOptions(chart, initOptions) + const { Line: G2Line } = await import('@antv/g2plot/esm/plots/line') + // 开始渲染 + const newChart = new G2Line(container, options) + + newChart.on('point:click', action) + extremumEvt(newChart, chart, options, container) + configPlotTooltipEvent(chart, newChart) + return newChart + } + + protected configLabel(chart: Chart, options: LineOptions): LineOptions { + const tmpOptions = super.configLabel(chart, options) + if (!tmpOptions.label) { + return { + ...tmpOptions, + label: false + } + } + const { label: labelAttr, basicStyle } = parseJson(chart.customAttr) + const conditions = getLineConditions(chart) + const formatterMap = labelAttr.seriesLabelFormatter?.reduce((pre, next) => { + pre[next.id] = next + return pre + }, {}) + tmpOptions.label.style.fill = DEFAULT_LABEL.color + const label = { + fields: [], + ...tmpOptions.label, + layout: labelAttr.fullDisplay ? [{ type: 'limit-in-plot' }] : tmpOptions.label.layout, + formatter: (data: Datum, _point) => { + if (data.EXTREME) { + return '' + } + if (!labelAttr.seriesLabelFormatter?.length) { + return data.value + } + const labelCfg = formatterMap?.[data.quotaList[0].id] as SeriesFormatter + if (!labelCfg) { + return data.value + } + if (!labelCfg.show) { + return + } + const position = + labelCfg.position === 'top' + ? -2 - basicStyle.lineSymbolSize + : 10 + basicStyle.lineSymbolSize + const value = valueFormatter(data.value, labelCfg.formatterCfg) + const color = + getLineLabelColorByCondition(conditions, data.value, data.quotaList[0].id) || + labelCfg.color + const group = new Group({}) + group.addShape({ + type: 'text', + attrs: { + x: 0, + y: position, + text: value, + textAlign: 'start', + textBaseline: 'top', + fontSize: labelCfg.fontSize, + fontFamily: chart.fontFamily, + fill: color + } + }) + return group + } + } + return { + ...tmpOptions, + label + } + } + + protected configBasicStyle(chart: Chart, options: LineOptions): LineOptions { + // size + const customAttr: DeepPartial = parseJson(chart.customAttr) + const s = JSON.parse(JSON.stringify(customAttr.basicStyle)) + const smooth = s.lineSmooth + const point = { + size: s.lineSymbolSize, + shape: s.lineSymbol + } + const lineStyle = { + lineWidth: s.lineWidth + } + return { + ...options, + smooth, + point, + lineStyle + } + } + + protected configCustomColors(chart: Chart, options: LineOptions): LineOptions { + const basicStyle = parseJson(chart.customAttr).basicStyle + const color = basicStyle.colors.map(item => hexColorToRGBA(item, basicStyle.alpha)) + return { + ...options, + color + } + } + + protected configYAxis(chart: Chart, options: LineOptions): LineOptions { + const tmpOptions = super.configYAxis(chart, options) + if (!tmpOptions.yAxis) { + return tmpOptions + } + const yAxis = parseJson(chart.customStyle).yAxis + if (tmpOptions.yAxis.label) { + tmpOptions.yAxis.label.formatter = value => { + return valueFormatter(value, yAxis.axisLabelFormatter) + } + } + const axisValue = yAxis.axisValue + if (!axisValue?.auto) { + const axis = { + yAxis: { + ...tmpOptions.yAxis, + min: axisValue.min, + max: axisValue.max, + minLimit: axisValue.min, + maxLimit: axisValue.max, + tickCount: axisValue.splitCount + } + } + return { ...tmpOptions, ...axis } + } + return tmpOptions + } + + protected configTooltip(chart: Chart, options: LineOptions): LineOptions { + const customAttr: DeepPartial = parseJson(chart.customAttr) + const tooltipAttr = customAttr.tooltip + if (!tooltipAttr.show) { + return { + ...options, + tooltip: false + } + } + const xAxisExt = chart.xAxisExt + const formatterMap = tooltipAttr.seriesTooltipFormatter + ?.filter(i => i.show) + .reduce((pre, next) => { + pre[next.id] = next + return pre + }, {}) as Record + const tooltip: LineOptions['tooltip'] = { + showTitle: true, + customItems(originalItems) { + if (!tooltipAttr.seriesTooltipFormatter?.length) { + return originalItems + } + const head = originalItems[0] + // 非原始数据 + if (!head.data.quotaList) { + return originalItems + } + const result = [] + originalItems + .filter(item => formatterMap[item.data.quotaList[0].id]) + .forEach(item => { + const formatter = formatterMap[item.data.quotaList[0].id] + const value = valueFormatter(parseFloat(item.value as string), formatter.formatterCfg) + let name = isEmpty(formatter.chartShowName) ? formatter.name : formatter.chartShowName + if (xAxisExt?.length > 0) { + name = item.data.category + } + result.push({ ...item, name, value }) + }) + head.data.dynamicTooltipValue?.forEach(item => { + const formatter = formatterMap[item.fieldId] + if (formatter) { + const value = valueFormatter(parseFloat(item.value), formatter.formatterCfg) + const name = isEmpty(formatter.chartShowName) ? formatter.name : formatter.chartShowName + result.push({ color: 'grey', name, value }) + } + }) + return result + }, + container: getTooltipContainer(`tooltip-${chart.id}`), + itemTpl: TOOLTIP_TPL, + enterable: true + } + return { + ...options, + tooltip + } + } + public setupSeriesColor(chart: ChartObj, data?: any[]): ChartBasicStyle['seriesColor'] { + return setUpGroupSeriesColor(chart, data) + } + protected configLegend(chart: Chart, options: LineOptions): LineOptions { + const optionTmp = super.configLegend(chart, options) + if (!optionTmp.legend) { + return optionTmp + } + const xAxisExt = chart.xAxisExt[0] + if (xAxisExt?.customSort?.length > 0) { + // 图例自定义排序 + const sort = xAxisExt.customSort ?? [] + if (sort?.length) { + // 用值域限定排序,有可能出现新数据但是未出现在图表上,所以这边要遍历一下子维度,加到后面,让新数据显示出来 + const data = optionTmp.data + data?.forEach(d => { + const cat = d['category'] + if (cat && !sort.includes(cat)) { + sort.push(cat) + } + }) + optionTmp.meta = { + ...optionTmp.meta, + category: { + type: 'cat', + values: sort + } + } + } + } + + const customStyle = parseJson(chart.customStyle) + let size + if (customStyle && customStyle.legend) { + size = defaults(JSON.parse(JSON.stringify(customStyle.legend)), DEFAULT_LEGEND_STYLE).size + } else { + size = DEFAULT_LEGEND_STYLE.size + } + + optionTmp.legend.marker.style = style => { + return { + r: size, + fill: style.stroke + } + } + return optionTmp + } + protected setupOptions(chart: Chart, options: LineOptions): LineOptions { + return flow( + this.configTheme, + this.configEmptyDataStrategy, + this.configGroupColor, + this.configLabel, + this.configTooltip, + this.configBasicStyle, + this.configCustomColors, + this.configLegend, + this.configXAxis, + this.configYAxis, + this.configSlider, + this.configAnalyse, + this.configConditions + )(chart, options) + } + + constructor(name = 'line') { + super(name, DEFAULT_DATA) + } +} diff --git a/frontend/src/data-visualization/chart/components/js/panel/charts/line/stock-line.ts b/frontend/src/data-visualization/chart/components/js/panel/charts/line/stock-line.ts new file mode 100644 index 0000000..625ad65 --- /dev/null +++ b/frontend/src/data-visualization/chart/components/js/panel/charts/line/stock-line.ts @@ -0,0 +1,718 @@ +import { + G2PlotChartView, + G2PlotDrawOptions +} from '@/data-visualization/chart/components/js/panel/types/impl/g2plot' +import type { Mix, MixOptions } from '@antv/g2plot/esm/plots/mix' +import { flow, hexColorToRGBA, parseJson } from '@/data-visualization/chart/components/js/util' +import { LINE_EDITOR_PROPERTY_INNER } from '@/data-visualization/chart/components/js/panel/charts/line/common' +import { useI18n } from '@/data-visualization/hooks/web/useI18n' +import { valueFormatter } from '@/data-visualization/chart/components/js/formatter' +import type { Options } from '@antv/g2plot/esm' +import { MixOptions } from '@antv/g2plot' + +const { t } = useI18n() +const DEFAULT_DATA = [] +/** + * K线图 + */ +export class StockLine extends G2PlotChartView { + properties: EditorProperty[] = [ + 'background-overall-component', + 'border-style', + 'basic-style-selector', + 'legend-selector', + 'x-axis-selector', + 'y-axis-selector', + 'title-selector', + 'tooltip-selector', + 'function-cfg', + 'jump-set', + 'linkage' + ] + propertyInner = { + ...LINE_EDITOR_PROPERTY_INNER, + 'function-cfg': ['emptyDataStrategy'], + 'y-axis-selector': [ + 'name', + 'color', + 'fontSize', + 'position', + 'axisLabel', + 'axisLine', + 'splitLine', + 'axisLabelFormatter' + ], + 'legend-selector': ['fontSize', 'color', 'show'] + } + axis: AxisType[] = ['xAxis', 'yAxis', 'filter', 'extLabel', 'extTooltip'] + axisConfig = { + xAxis: { + name: `${t('common.component.date')} / ${t('chart.dimension')}`, + limit: 1, + type: 'd' + }, + yAxis: { + name: `${t('chart.k_line_yaxis_tip')} / ${t('chart.quota')}`, + limit: 4, + type: 'q' + } + } + + /** + * 计算收盘价平均值 + * @param data + * @param dayCount + * @param chart + */ + calculateMovingAverage = (data, dayCount, chart) => { + const xAxis = chart.xAxis + const yAxis = chart.yAxis + // 时间字段 + const xAxisDataeaseName = xAxis[0].dataeaseName + // 收盘价字段 + const yAxisDataeaseName = yAxis[1].dataeaseName + const result = [] + for (let i = 0; i < data.length; i++) { + if (i < dayCount) { + result.push({ + [xAxisDataeaseName]: data[i][xAxisDataeaseName], + value: null + }) + } else { + const sum = data + .slice(i - dayCount + 1, i + 1) + .reduce((sum, item) => sum + item[yAxisDataeaseName], 0) + result.push({ + [xAxisDataeaseName]: data[i][xAxisDataeaseName], + value: parseFloat((sum / dayCount).toFixed(3)) + }) + } + } + return result + } + + /** + * 获取数据集合中对象属性值的最大最小值 + * @param data + */ + calculateMinMax = data => { + return data.reduce( + (acc, current) => { + // 获取 current 对象的所有属性值 + const values = Object.values(current) + // 过滤出数字值 + const numericValues: any[] = values.filter(value => typeof value === 'number') + // 找到 current 对象的数字属性值中的最大值和最小值 + // 如果存在数字值,则计算当前对象的最大值和最小值 + if (numericValues.length > 0) { + const currentMax = Math.max(...numericValues) + const currentMin = Math.min(...numericValues) + // 更新全局最大值和最小值 + acc.maxValue = Math.max(acc.maxValue, currentMax) + acc.minValue = Math.min(acc.minValue, currentMin) + } + return acc + }, + { maxValue: Number.NEGATIVE_INFINITY, minValue: Number.POSITIVE_INFINITY } + ) + } + + /** + * 注册图表事件 + * @param data + * @param plot + * @param averagesLineData + */ + registerEvent = (data, plot, averagesLineData) => { + // 监听图例点击事件,显示隐藏 + let risingVisible = true + plot.on('legend-item:click', evt => { + const { value } = evt.target.get('delegateObject').item + if (value === 'k') { + risingVisible = !risingVisible + plot.chart.geometries.forEach(geom => { + if (geom.type === 'schema') { + geom.changeVisible(risingVisible) + } + }) + } else { + const lines = plot.chart.geometries.filter(item => item.type === 'line') + const points = plot.chart.geometries.filter(item => item.type === 'point') + let lineIndex = 0 + for (const key of averagesLineData.keys()) { + lineIndex++ + if (key === value) { + lines[lineIndex - 1].changeVisible(!lines[lineIndex - 1].visible) + points[lineIndex - 1].changeVisible(!points[lineIndex - 1].visible) + } + } + } + }) + // 监听图表渲染事件 + plot.on('afterrender', e => { + let first = false + if (plot.chart.options.slider.start === 0.5 && plot.chart.options.slider.end === 1) { + first = true + } + if (e.view?.options?.scales) { + const startIndex = Math.floor(0.5 * data.length) + const endIndex = Math.ceil(1 * data.length) + const filteredData = data.slice(startIndex, endIndex) + const { maxValue, minValue } = this.calculateMinMax( + first ? filteredData : e.view.filteredData + ) + const a = e.view.options.scales + Object.keys(a).forEach(item => { + if (a[item].max) { + a[item].max = maxValue + } + if (a[item].min) { + a[item].min = minValue + } + }) + } + }) + // 监听图例组点击事件,设置缩放 + plot.on('legend-item-group:click', e => { + if (e.view?.options?.scales) { + const { maxValue, minValue } = this.calculateMinMax(e.view.filteredData) + const a = e.view.options.scales + Object.keys(a).forEach(item => { + if (a[item].max) { + a[item].max = maxValue + } + if (a[item].min) { + a[item].min = minValue + } + }) + } + }) + // 监听滑块事件,设置缩放 + plot.on('slider:valuechanged', e => { + const start = e.gEvent.currentTarget.cfg.component.cfg.start + const end = e.gEvent.currentTarget.cfg.component.cfg.end + plot.chart.options.slider.start = start + plot.chart.options.slider.end = end + const startIndex = Math.floor(start * data.length) + const endIndex = Math.ceil(end * data.length) + const filteredData = data.slice(startIndex, endIndex) + const { maxValue, minValue } = this.calculateMinMax(filteredData) + const a = e.view.options.scales + Object.keys(a).forEach(item => { + if (a[item].max) { + a[item].max = maxValue + } + if (a[item].min) { + a[item].min = minValue + } + }) + }) + } + + async drawChart(drawOptions: G2PlotDrawOptions): Promise { + const { chart, action, container } = drawOptions + if (!chart.data?.data?.length) { + return + } + const xAxis = chart.xAxis + const yAxis = chart.yAxis + if (yAxis.length != 4) { + return + } + const basicStyle = parseJson(chart.customAttr).basicStyle + const colors = [] + const alpha = basicStyle.alpha + basicStyle.colors.forEach(ele => { + colors.push(hexColorToRGBA(ele, alpha)) + }) + const data = parseJson(chart.data?.tableRow) + + // 时间字段 + const xAxisDataeaseName = xAxis[0].dataeaseName + const averages = [5, 10, 20, 60, 120, 180] + const legendItems: any[] = [ + { + name: '日K', + value: 'k', + marker: { + symbol: (x, y, r) => { + const width = r * 1 + const height = r + return [ + // 矩形框 + ['M', x - width - 1 / 2, y - height / 2], + ['L', x + width + 1 / 2, y - height / 2], + ['L', x + width + 1 / 2, y + height / 2], + ['L', x - width - 1 / 2, y + height / 2], + ['Z'], + // 中线 + ['M', x, y + 10 / 2], + ['L', x, y - 10 / 2] + ] + }, + style: { fill: 'red', stroke: 'red', lineWidth: 2 } + } + } + ] + // 计算均线数据 + const averagesLineData = new Map() + averages.forEach(item => { + averagesLineData.set('ma' + item, this.calculateMovingAverage(data, item, chart)) + }) + + // 将均线数据设置到主数据中 + data.forEach((item: any) => { + const date = item[xAxisDataeaseName] + for (const [key, value] of averagesLineData) { + item[key] = value.find(m => m[xAxisDataeaseName] === date)?.value + } + }) + + const averageLines: any[] = [] + let index = 0 + const start = 0.5 + const end = 1 + const startIndex = Math.floor(start * data.length) + const endIndex = Math.ceil(end * data.length) + const filteredData = data.slice(startIndex, endIndex) + const { maxValue, minValue } = this.calculateMinMax(filteredData) + for (const key of averagesLineData.keys()) { + index++ + averageLines.push({ + type: 'line', + top: true, + options: { + smooth: false, + xField: xAxisDataeaseName, + yField: key, + color: colors[index - 1], + xAxis: null, + yAxis: { + label: false, + min: minValue, + max: maxValue, + grid: null, + line: null + }, + lineStyle: { + lineWidth: 2 + } + } + }) + legendItems.push({ + name: key.toUpperCase(), + value: key, + marker: { symbol: 'hyphen', style: { stroke: colors[index - 1], lineWidth: 2 } } + }) + } + const axis = chart.xAxis ?? [] + let dateFormat: string + const dateSplit = axis[0]?.datePattern === 'date_split' ? '/' : '-' + switch (axis[0]?.dateStyle) { + case 'y': + dateFormat = 'YYYY' + break + case 'y_M': + dateFormat = 'YYYY' + dateSplit + 'MM' + break + case 'y_M_d': + dateFormat = 'YYYY' + dateSplit + 'MM' + dateSplit + 'DD' + break + // case 'H_m_s': + // dateFormat = 'HH:mm:ss' + // break + case 'y_M_d_H': + dateFormat = 'YYYY' + dateSplit + 'MM' + dateSplit + 'DD' + ' HH' + break + case 'y_M_d_H_m': + dateFormat = 'YYYY' + dateSplit + 'MM' + dateSplit + 'DD' + ' HH:mm' + break + case 'y_M_d_H_m_s': + dateFormat = 'YYYY' + dateSplit + 'MM' + dateSplit + 'DD' + ' HH:mm:ss' + break + default: + dateFormat = 'YYYY-MM-dd HH:mm:ss' + } + const option = this.setupOptions(chart, { + data, + slider: { + start: 0.5, + end: 1, + textStyle: { + fontFamily: chart.fontFamily + } + }, + plots: [ + { + type: 'stock', + top: true, + + options: { + meta: { + [xAxisDataeaseName]: { + mask: dateFormat + } + }, + stockStyle: { + stroke: 'black', + lineWidth: 0.5 + }, + yAxis: { + label: {}, + position: 'left', + min: minValue, + max: maxValue + }, + xField: xAxisDataeaseName, + yField: [ + yAxis[0].dataeaseName, + yAxis[1].dataeaseName, + yAxis[2].dataeaseName, + yAxis[3].dataeaseName + ], + legend: { + position: 'top', + custom: true, + items: legendItems + } + } + }, + ...averageLines + ] + }) + const { Mix: MixClass } = await import('@antv/g2plot/esm/plots/mix') + const plot = new MixClass(container, option) + this.registerEvent(data, plot, averagesLineData) + plot.on('schema:click', evt => { + const selectSchema = evt.data.data[xAxisDataeaseName] + const paramData = parseJson(chart.data?.data) + const selectData = paramData.filter(item => item.field === selectSchema) + const quotaList = [] + selectData.forEach(item => { + quotaList.push({ ...item.quotaList[0], value: item.value }) + }) + if (selectData.length) { + const param = { + x: evt.x, + y: evt.y, + data: { + data: { + ...evt.data.data, + value: quotaList[0].value, + name: selectSchema, + dimensionList: selectData[0].dimensionList, + quotaList: quotaList + } + } + } + action(param) + } + }) + return plot + } + + protected configBasicStyle(chart: Chart, options: MixOptions): MixOptions { + // size + const customAttr: DeepPartial = parseJson(chart.customAttr) + const s = JSON.parse(JSON.stringify(customAttr.basicStyle)) + const smooth = s.lineSmooth + const point = { + size: s.lineSymbolSize, + shape: s.lineSymbol + } + const lineStyle = { + lineWidth: s.lineWidth + } + const plots = [] + options.plots.forEach(item => { + if (item.type === 'stock') { + plots.push({ ...item }) + } + if (item.type === 'line') { + plots.push({ ...item, options: { ...item.options, smooth, point, lineStyle } }) + } + }) + return { + ...options, + plots + } + } + + protected configTooltip(chart: Chart, options: MixOptions): MixOptions { + const tooltipAttr = parseJson(chart.customAttr).tooltip + const xAxis = chart.xAxis + const newPlots = [] + const linePlotList = options.plots.filter(item => item.type === 'line') + linePlotList.forEach(item => { + newPlots.push(item) + }) + const stockPlot = options.plots.filter(item => item.type === 'stock')[0] + if (!tooltipAttr.show) { + const stockOption = { + ...stockPlot.options, + tooltip: { + showContent: false + } + } + newPlots.push({ ...stockPlot, options: stockOption }) + return { + ...options, + plots: newPlots + } + } + + const showFiled = chart.data.fields + const customTooltipItems = originalItems => { + const formattedItems = originalItems.map(item => { + const fieldObj = showFiled.find(q => q.dataeaseName === item.name) + const displayName = fieldObj?.chartShowName || fieldObj?.name || item.name + const formattedName = displayName.startsWith('ma') ? displayName.toUpperCase() : displayName + tooltipAttr.tooltipFormatter.decimalCount = 3 + const formattedValue = valueFormatter(item.value, tooltipAttr.tooltipFormatter) + + return { + ...item, + name: formattedName, + value: formattedValue, + color: item.color + } + }) + + const hasKLine = formattedItems.some(item => !item.name.startsWith('MA')) + const kLines = formattedItems.filter(item => !item.name.startsWith('MA')) + return hasKLine + ? [ + { name: '日K', value: '', marker: true, color: kLines[0]?.color }, + ...kLines, + ...formattedItems.filter(item => item.name.startsWith('MA')) + ] + : formattedItems + } + const formatTooltipItem = (item: any) => { + const size = item.name.startsWith('MA') || !item.value ? 10 : 5 + const markerMarginRight = item.name.startsWith('MA') || !item.value ? 5 : 9 + const markerMarginLeft = item.name.startsWith('MA') || !item.value ? 0 : 2 + return ` +
  • +
    + +
    +
    + ${item.name} + ${item.name.startsWith('MA') && item.value === '0' ? '-' : item.value} +
    +
  • + ` + } + const generateCustomTooltipContent = (title: string, items: Array) => { + return ` +
    +
    ${title}
    +
      + ${items.map(formatTooltipItem).join('')} +
    +
    + ` + } + const stockOption = { + ...stockPlot.options, + tooltip: { + showMarkers: true, + showCrosshairs: true, + showNil: true, + crosshairs: { + follow: true, + text: (axisType, value, data) => { + if (axisType === 'y') { + return { content: value ? value.toFixed(0) : value } + } + return { content: data[0].title, position: 'end' } + } + }, + showContent: true, + customItems: customTooltipItems, + customContent: generateCustomTooltipContent + } + } + newPlots.push({ ...stockPlot, options: stockOption }) + return { + ...options, + plots: newPlots + } + } + + protected configXAxis(chart: Chart, options: MixOptions): MixOptions { + const xAxisOptions = super.configXAxis(chart, options) + if (!xAxisOptions) { + return options + } + const newPlots = [] + const linePlotList = options.plots.filter(item => item.type === 'line') + + const stockPlot = options.plots.filter(item => item.type === 'stock')[0] + const newStockPlot = { + ...stockPlot, + options: { + ...stockPlot.options, + xAxis: xAxisOptions['xAxis'] + ? { + ...stockPlot.options['xAxis'], + ...xAxisOptions['xAxis'] + } + : { + label: false, + line: null + } + } + } + newPlots.push(newStockPlot) + linePlotList.forEach(item => { + newPlots.push(item) + }) + return { + ...options, + plots: newPlots + } + } + protected configYAxis(chart: Chart, options: MixOptions): MixOptions { + const yAxisOptions = super.configYAxis(chart, options) + if (!yAxisOptions) { + return options + } + const yAxis = parseJson(chart.customStyle).yAxis + const newPlots = [] + const linePlotList = options.plots.filter(item => item.type === 'line') + + const stockPlot = options.plots.filter(item => item.type === 'stock')[0] + let label = false + if (yAxisOptions['yAxis'].label) { + label = { + ...yAxisOptions['yAxis'].label, + formatter: value => { + return valueFormatter(value, yAxis.axisLabelFormatter) + } + } + } + const newStockPlot = { + ...stockPlot, + options: { + ...stockPlot.options, + yAxis: label + ? { + ...stockPlot.options['yAxis'], + ...yAxisOptions['yAxis'], + label + } + : { + ...yAxisOptions['yAxis'], + label, + grid: null, + line: null + } + } + } + newPlots.push(newStockPlot) + linePlotList.forEach(item => { + newPlots.push(item) + }) + return { + ...options, + plots: newPlots + } + } + + protected customConfigEmptyDataStrategy(chart: Chart, options: MixOptions): MixOptions { + const { data } = options as unknown as Options + if (!data?.length) { + return options + } + const strategy = parseJson(chart.senior).functionCfg.emptyDataStrategy + if (strategy === 'ignoreData') { + for (let i = data.length - 1; i >= 0; i--) { + const item = data[i] + Object.keys(item).forEach(key => { + if (key.startsWith('f_') && item[key] === null) { + data.splice(i, 1) + } + }) + } + } + const updateValues = (strategy: 'breakLine' | 'setZero', data: any[]) => { + data.forEach(obj => { + Object.keys(obj).forEach(key => { + if (key.startsWith('f_') && obj[key] === null) { + obj[key] = strategy === 'breakLine' ? null : 0 + } + }) + }) + } + if (strategy === 'breakLine' || strategy === 'setZero') { + updateValues(strategy, data) + } + return options + } + protected configLegend(chart: Chart, options: MixOptions): MixOptions { + let legend = {} + let customStyle: CustomStyle + const stockPlot = options.plots.filter(item => item.type === 'stock')[0] + if (chart.customStyle) { + customStyle = parseJson(chart.customStyle) + // legend + if (customStyle.legend) { + const l = JSON.parse(JSON.stringify(customStyle.legend)) + if (l.show) { + legend = { + ...stockPlot.options.legend, + itemName: { + style: { + fill: l.color, + fontSize: l.fontSize + } + } + } + } else { + legend = false + } + } + } + const newPlots = [] + const stockOption = { + ...stockPlot.options, + legend: legend + } + const linePlotList = options.plots.filter(item => item.type === 'line') + linePlotList.forEach(item => { + newPlots.push(item) + }) + newPlots.push({ ...stockPlot, options: stockOption }) + return { + ...options, + plots: newPlots + } + } + + protected setupOptions(chart: Chart, options: MixOptions): MixOptions { + return flow( + this.configTheme, + this.configBasicStyle, + this.configXAxis, + this.configYAxis, + this.configTooltip, + this.configLegend, + this.customConfigEmptyDataStrategy + )(chart, options) + } + + constructor(name = 'stock-line') { + super(name, DEFAULT_DATA) + } +} diff --git a/frontend/src/data-visualization/chart/components/js/panel/charts/liquid/liquid.ts b/frontend/src/data-visualization/chart/components/js/panel/charts/liquid/liquid.ts new file mode 100644 index 0000000..9ca812c --- /dev/null +++ b/frontend/src/data-visualization/chart/components/js/panel/charts/liquid/liquid.ts @@ -0,0 +1,221 @@ +import { + G2PlotChartView, + G2PlotDrawOptions +} from '@/data-visualization/chart/components/js/panel/types/impl/g2plot' +import type { Liquid as G2Liquid, LiquidOptions } from '@antv/g2plot/esm/plots/liquid' +import { flow, hexColorToRGBA, parseJson } from '@/data-visualization/chart/components/js/util' +import { DEFAULT_MISC } from '@/data-visualization/chart/components/editor/util/chart' +import { valueFormatter } from '@/data-visualization/chart/components/js/formatter' +import { useI18n } from '@/data-visualization/hooks/web/useI18n' + +const { t } = useI18n() +const DEFAULT_LIQUID_DATA = [] +/** + * 水波图 + */ +export class Liquid extends G2PlotChartView { + properties: EditorProperty[] = [ + 'background-overall-component', + 'border-style', + 'basic-style-selector', + 'label-selector', + 'misc-selector', + 'title-selector', + 'threshold' + ] + propertyInner: EditorPropertyInner = { + 'background-overall-component': ['all'], + 'border-style': ['all'], + 'basic-style-selector': ['colors', 'alpha'], + 'label-selector': ['fontSize', 'color', 'labelFormatter'], + 'misc-selector': ['liquidShape', 'liquidSize', 'liquidMaxType', 'liquidMaxField'], + 'title-selector': [ + 'title', + 'fontSize', + 'color', + 'hPosition', + 'isItalic', + 'isBolder', + 'remarkShow', + 'fontFamily', + 'letterSpace', + 'fontShadow' + ], + threshold: ['liquidThreshold'] + } + axis: AxisType[] = ['yAxis', 'filter'] + axisConfig: AxisConfig = { + yAxis: { + name: `${t('chart.drag_block_progress')} / ${t('chart.quota')}`, + type: 'q', + limit: 1 + } + } + + async drawChart(drawOptions: G2PlotDrawOptions): Promise { + const { chart, container, action } = drawOptions + if (!chart.data?.series || !chart.yAxis.length) { + return + } + const initOptions: LiquidOptions = { + percent: 0 + } + const options = this.setupOptions(chart, initOptions) + const { Liquid: G2Liquid } = await import('@antv/g2plot/esm/plots/liquid') + const newChart = new G2Liquid(container, options) + newChart.on('afterrender', () => { + action({ + from: 'liquid', + data: { + type: 'liquid', + max: chart.data?.series[0]?.data[0] + } + }) + }) + // 处理空数据, 只要有一个指标是空数据,就不显示图表 + const hasNoneData = chart.data?.series.some(s => !s.data?.[0]) + this.configEmptyDataStyle(newChart, hasNoneData ? [] : [1], container) + if (hasNoneData) { + return + } + return newChart + } + + protected configTheme(chart: Chart, options: LiquidOptions): LiquidOptions { + const customAttr = parseJson(chart.customAttr) + const colors: string[] = [] + if (customAttr.basicStyle) { + const basicStyle = customAttr.basicStyle + basicStyle.colors.forEach(ele => { + colors.push(hexColorToRGBA(ele, basicStyle.alpha)) + }) + } + const customStyle = parseJson(chart.customStyle) + let bgColor + if (customStyle.background) { + bgColor = hexColorToRGBA(customStyle.background.color, customStyle.background.alpha) + } + const theme = { + styleSheet: { + brandColor: colors[0], + paletteQualitative10: colors, + paletteQualitative20: colors, + backgroundColor: bgColor + } + } + return { ...options, theme } + } + + protected configMisc(chart: Chart, options: LiquidOptions): LiquidOptions { + const customAttr = parseJson(chart.customAttr) + let value = 0 + if (chart.data.series.length > 0) { + value = chart.data.series[0].data[0] + } + let max, radius, shape + if (customAttr.misc) { + const misc = customAttr.misc + const defaultLiquidMax = chart.data?.series[chart.data?.series.length - 1]?.data[0] + if (misc.liquidMaxType === 'dynamic') { + max = defaultLiquidMax + } else { + max = misc.liquidMax ? misc.liquidMax : defaultLiquidMax + } + radius = (misc.liquidSize ? misc.liquidSize : DEFAULT_MISC.liquidSize) / 100 + shape = misc.liquidShape ?? DEFAULT_MISC.liquidShape + } + const size: LiquidOptions = { + percent: value / max, + radius: radius, + shape: shape + } + return { ...options, ...size } + } + + protected configLabel(chart: Chart, options: LiquidOptions): LiquidOptions { + const customAttr = parseJson(chart.customAttr) + const originVal = options.percent + // 数值过大图表会异常,大于 1 无意义 + if (originVal > 1) { + options = { + ...options, + percent: 1 + } + } + if (!customAttr.label?.show) { + return { + ...options, + statistic: { + content: false + } + } + } + const label = customAttr.label + const labelFormatter = label.labelFormatter + return { + ...options, + statistic: { + content: { + style: { + fontSize: label.fontSize.toString() + 'px', + color: label.color + }, + formatter: () => { + return valueFormatter(originVal, labelFormatter) + } + } + } + } + } + + protected configThreshold(chart: Chart, options: LiquidOptions): LiquidOptions { + const senior = parseJson(chart.senior) + if (senior?.threshold?.enable) { + const { liquidThreshold } = senior?.threshold + if (liquidThreshold) { + const { paletteQualitative10: colors } = (options.theme as any).styleSheet + const liquidStyle = () => { + const thresholdArr = liquidThreshold.split(',') + let index = 0 + thresholdArr.forEach((v, i) => { + if (options.percent > parseFloat(v) / 100) { + index = i + 1 + } + }) + return { + fill: colors[index % colors.length], + stroke: colors[index % colors.length] + } + } + return { ...options, liquidStyle } + } + } + return options + } + + setupDefaultOptions(chart: ChartObj): ChartObj { + chart.customAttr.label = { + ...chart.customAttr.label, + fontSize: 12, + show: true, + labelFormatter: { + type: 'percent', + thousandSeparator: true, + decimalCount: 2 + } + } + return chart + } + + protected setupOptions(chart: Chart, options: LiquidOptions): LiquidOptions { + return flow( + this.configTheme, + this.configMisc, + this.configLabel, + this.configThreshold + )(chart, options) + } + constructor() { + super('liquid', DEFAULT_LIQUID_DATA) + } +} diff --git a/frontend/src/data-visualization/chart/components/js/panel/charts/map/bubble-map.ts b/frontend/src/data-visualization/chart/components/js/panel/charts/map/bubble-map.ts new file mode 100644 index 0000000..d9554e9 --- /dev/null +++ b/frontend/src/data-visualization/chart/components/js/panel/charts/map/bubble-map.ts @@ -0,0 +1,514 @@ +import { useI18n } from '@/data-visualization/hooks/web/useI18n' +import { + L7PlotChartView, + L7PlotDrawOptions +} from '@/data-visualization/chart/components/js/panel/types/impl/l7plot' +import { Choropleth, ChoroplethOptions } from '@antv/l7plot/dist/esm/plots/choropleth' +import { Dot, DotOptions, IPlotLayer } from '@antv/l7plot' +import { + MAP_AXIS_TYPE, + MAP_EDITOR_PROPERTY, + MAP_EDITOR_PROPERTY_INNER, + MapMouseEvent +} from '@/data-visualization/chart/components/js/panel/charts/map/common' +import { flow, getGeoJsonFile, hexColorToRGBA, parseJson } from '@/data-visualization/chart/components/js/util' +import { cloneDeep, isEmpty } from 'lodash-es' +import { FeatureCollection } from '@antv/l7plot/dist/esm/plots/choropleth/types' +import { + handleGeoJson, + mapRendered, + mapRendering +} from '@/data-visualization/chart/components/js/panel/common/common_antv' +import { valueFormatter } from '@/data-visualization/chart/components/js/formatter' +import { deepCopy } from '@/data-visualization/utils/utils' +import { configCarouselTooltip } from '@/data-visualization/chart/components/js/panel/charts/map/tooltip-carousel' +import { getCustomGeoArea } from '@/api/data-visualization/map' +import { TextLayer } from '@antv/l7plot/dist/esm' +import { centroid } from '@turf/centroid' + +const { t } = useI18n() + +/** + * 气泡地图 + */ +export class BubbleMap extends L7PlotChartView { + properties: EditorProperty[] = [...MAP_EDITOR_PROPERTY, 'bubble-animate'] + propertyInner = { + ...MAP_EDITOR_PROPERTY_INNER, + 'tooltip-selector': [...MAP_EDITOR_PROPERTY_INNER['tooltip-selector'], 'carousel'], + 'basic-style-selector': [...MAP_EDITOR_PROPERTY_INNER['basic-style-selector'], 'areaBaseColor'] + } + axis = MAP_AXIS_TYPE + axisConfig: AxisConfig = { + xAxis: { + name: `${t('chart.area')} / ${t('chart.dimension')}`, + type: 'd', + limit: 1 + }, + yAxis: { + name: `${t('chart.bubble_size')} / ${t('chart.quota')}`, + type: 'q', + limit: 1 + } + } + constructor() { + super('bubble-map') + } + + async drawChart(drawOption: L7PlotDrawOptions): Promise { + const { chart, level, areaId, container, action, scope } = drawOption + if (!areaId) { + return + } + chart.container = container + let geoJson = {} as FeatureCollection + let customSubArea: CustomGeoSubArea[] = [] + let data = chart.data?.data + if (areaId.startsWith('custom_')) { + customSubArea = (await getCustomGeoArea(areaId)).data || [] + customSubArea.forEach(a => (a.scopeArr = a.scope?.split(',') || [])) + geoJson = cloneDeep(await getGeoJsonFile('156')) + const areaNameMap = geoJson.features.reduce((p, n) => { + p['156' + n.properties.adcode] = n.properties.name + return p + }, {}) + const { areaMapping } = parseJson(chart.senior) + const areaMap = customSubArea.reduce((p, n) => { + const mappedName = areaMapping?.[areaId]?.[n.name] + if (mappedName) { + n.name = mappedName + } + p[n.name] = n + n.scopeArr = n.scope?.split(',') || [] + return p + }, {}) + const fakeData = [] + data?.forEach(d => { + const area = areaMap[d.name] + if (area) { + area.scopeArr.forEach(adcode => { + fakeData.push({ + ...d, + name: areaNameMap[adcode], + field: areaNameMap[adcode], + scope: area.scopeArr, + areaName: d.name + }) + }) + } + }) + data = fakeData + } else { + if (scope) { + geoJson = cloneDeep(await getGeoJsonFile('156')) + geoJson.features = geoJson.features.filter(f => scope.includes('156' + f.properties.adcode)) + } else { + geoJson = cloneDeep(await getGeoJsonFile(areaId)) + } + } + let options: ChoroplethOptions = { + preserveDrawingBuffer: true, + map: { + type: 'mapbox', + style: 'blank' + }, + geoArea: { + type: 'geojson' + }, + source: { + data: data || [], + joinBy: { + sourceField: 'name', + geoField: 'name', + geoData: geoJson + } + }, + viewLevel: { + level, + adcode: 'all' + }, + autoFit: true, + chinaBorder: false, + color: { + field: 'value' + }, + style: { + opacity: 1, + lineWidth: 0.6, + lineOpacity: 1 + }, + label: { + field: '_DE_LABEL_', + style: { + textAnchor: 'center' + } + }, + tooltip: {}, + legend: false, + // 禁用线上地图数据 + customFetchGeoData: () => null + } + const context: Record = { drawOption, geoJson, customSubArea } + options = this.setupOptions(chart, options, context) + + const tooltip = deepCopy(options.tooltip) + options = { ...options, tooltip: { ...tooltip, showComponent: false } } + const view = new Choropleth(container, options) + const dotLayer = this.getDotLayer(chart, geoJson, drawOption, customSubArea) + if (!areaId.startsWith('custom_')) { + dotLayer.options = { ...dotLayer.options, tooltip } + } + this.configZoomButton(chart, view) + mapRendering(container) + view.once('loaded', () => { + // 修改地图鼠标样式为默认 + view.scene.map._canvasContainer.lastElementChild.style.cursor = 'default' + const { layers } = context + if (layers) { + layers.forEach(l => { + view.addLayer(l) + }) + } + dotLayer.addToScene(view.scene) + dotLayer.once('add', () => { + mapRendered(container) + }) + view.scene.map['keyboard'].disable() + dotLayer.on('dotLayer:click', (ev: MapMouseEvent) => { + const data = ev.feature.properties + let adcode, scope + if (areaId.startsWith('custom_')) { + adcode = '156' + const area = customSubArea.find(a => a.name === data.name) + scope = area?.scopeArr + } else { + adcode = view.currentDistrictData.features.find( + i => i.properties.name === ev.feature.properties.name + )?.properties.adcode + } + action({ + x: ev.x, + y: ev.y, + data: { + data, + extra: { adcode, scope } + } + }) + }) + dotLayer.once('loaded', () => { + chart.container = container + configCarouselTooltip(chart, view, data || [], null, customSubArea, drawOption) + }) + }) + return view + } + + private getDotLayer( + chart: Chart, + geoJson: FeatureCollection, + drawOption: L7PlotDrawOptions, + customSubArea: CustomGeoSubArea[] + ): IPlotLayer { + const { areaId } = drawOption + const { basicStyle, tooltip } = parseJson(chart.customAttr) + const { bubbleCfg } = parseJson(chart.senior) + const { offsetHeight, offsetWidth } = document.getElementById(drawOption.container) + const dotData = [] + const options: DotOptions = { + source: { + data: dotData, + parser: { + type: 'json', + x: 'x', + y: 'y' + } + }, + shape: 'circle', + size: { + field: 'size', + value: [5, Math.min(offsetHeight, offsetWidth) / 20] + }, + visible: true, + zIndex: 0.05, + color: hexColorToRGBA(basicStyle.colors[0], basicStyle.alpha), + name: 'bubbleLayer', + style: { + opacity: 1 + }, + state: { + active: { color: 'rgba(30,90,255,1)' } + }, + tooltip: { + showComponent: tooltip.show + } + } + if (areaId.startsWith('custom_')) { + const geoJsonMap = geoJson.features.reduce((p, n) => { + if (n.properties['adcode']) { + p['156' + n.properties['adcode']] = n + } + return p + }, {}) + const { areaMapping } = parseJson(chart.senior) + const customAreaMap = customSubArea.reduce((p, n) => { + const mappedName = areaMapping?.[areaId]?.[n.name] + if (mappedName) { + n.name = mappedName + } + p[n.name] = n + return p + }, {}) + chart.data?.data?.forEach(d => { + const area = customAreaMap[d.name] + if (area) { + const areaJsonArr = [] + area.scopeArr?.forEach(adcode => { + const json = geoJsonMap[adcode] + json && areaJsonArr.push(json) + }) + if (areaJsonArr.length) { + const areaJson: FeatureCollection = { + type: 'FeatureCollection', + features: areaJsonArr + } + const center = centroid(areaJson) + // 轮播用 + area.centroid = [center.geometry.coordinates[0], center.geometry.coordinates[1]] + dotData.push({ + name: area.name, + size: d.value, + properties: d, + x: center.geometry.coordinates[0], + y: center.geometry.coordinates[1] + }) + } + } + }) + if (options.tooltip && options.tooltip.showComponent) { + options.tooltip.items = ['name', 'adcode', 'value'] + options.tooltip.customTitle = ({ name }) => { + return name + } + const formatterMap = tooltip.seriesTooltipFormatter + ?.filter(i => i.show) + .reduce((pre, next) => { + pre[next.id] = next + return pre + }, {}) as Record + options.tooltip.customItems = originalItem => { + const result = [] + if (isEmpty(formatterMap)) { + return result + } + const head = originalItem.properties + const formatter = formatterMap[head.quotaList?.[0]?.id] + if (!isEmpty(formatter)) { + const originValue = parseFloat(head.value as string) + const value = valueFormatter(originValue, formatter.formatterCfg) + const name = isEmpty(formatter.chartShowName) ? formatter.name : formatter.chartShowName + result.push({ ...head, name, value: `${value ?? ''}` }) + } + head.dynamicTooltipValue?.forEach(item => { + const formatter = formatterMap[item.fieldId] + if (formatter) { + const value = valueFormatter(parseFloat(item.value), formatter.formatterCfg) + const name = isEmpty(formatter.chartShowName) + ? formatter.name + : formatter.chartShowName + result.push({ color: 'grey', name, value: `${value ?? ''}` }) + } + }) + return result + } + options.tooltip.domStyles = { + 'l7plot-tooltip': { + 'background-color': tooltip.backgroundColor, + 'font-size': `${tooltip.fontSize}px`, + 'line-height': 1.6 + }, + 'l7plot-tooltip__name': { + color: tooltip.color + }, + 'l7plot-tooltip__value': { + color: tooltip.color + }, + 'l7plot-tooltip__title': { + color: tooltip.color + } + } + } + } else { + const areaMap = chart.data?.data?.reduce((obj, value) => { + obj[value['field']] = { value: value.value, data: value } + return obj + }, {}) + geoJson.features.forEach(item => { + const name = item.properties['name'] + if (areaMap?.[name]?.value) { + dotData.push({ + x: item.properties['centroid'][0], + y: item.properties['centroid'][1], + size: areaMap[name].value, + properties: areaMap[name].data, + name: name + }) + } + }) + } + if (bubbleCfg && bubbleCfg.enable) { + return new Dot({ + ...options, + size: { + field: 'size', + value: [10, Math.min(offsetHeight, offsetWidth) / 10] + }, + animate: { + enable: true, + speed: bubbleCfg.speed, + rings: bubbleCfg.rings + } + }) + } + return new Dot(options) + } + + private configBasicStyle( + chart: Chart, + options: ChoroplethOptions, + context: Record + ): ChoroplethOptions { + const { areaId }: L7PlotDrawOptions = context.drawOption + const geoJson: FeatureCollection = context.geoJson + const { basicStyle, label } = parseJson(chart.customAttr) + const senior = parseJson(chart.senior) + const curAreaNameMapping = senior.areaMapping?.[areaId] + handleGeoJson(geoJson, curAreaNameMapping) + options.color = basicStyle.areaBaseColor + if (!chart.data?.data?.length || !geoJson?.features?.length) { + options.label && (options.label.field = 'name') + return options + } + const data = chart.data.data + const areaMap = data.reduce((obj, value) => { + obj[value['field']] = value.value + return obj + }, {}) + geoJson.features.forEach(item => { + const name = item.properties['name'] + // trick, maybe move to configLabel, here for perf + if (label.show) { + const content = [] + if (label.showDimension) { + content.push(name) + } + if (label.showQuota) { + areaMap[name] && content.push(valueFormatter(areaMap[name], label.quotaLabelFormatter)) + } + item.properties['_DE_LABEL_'] = content.join('\n\n') + } + }) + return options + } + + protected configCustomArea( + chart: Chart, + options: ChoroplethOptions, + context: Record + ): ChoroplethOptions { + const { drawOption, customSubArea, geoJson } = context + if (!drawOption.areaId.startsWith('custom_')) { + return options + } + const customAttr = parseJson(chart.customAttr) + const { label } = customAttr + const data = chart.data?.data + const areaMap = data?.reduce((obj, value) => { + obj[value['field']] = value + return obj + }, {}) + //处理label + options.label = { + visible: false + } + if (label.show) { + const geoJsonMap = geoJson.features.reduce((p, n) => { + if (n.properties['adcode']) { + p['156' + n.properties['adcode']] = n + } + return p + }, {}) + const { areaMapping } = parseJson(chart.senior) + const labelLocation = [] + customSubArea.forEach(area => { + const areaJsonArr = [] + area.scopeArr?.forEach(adcode => { + const json = geoJsonMap[adcode] + json && areaJsonArr.push(json) + }) + if (areaJsonArr.length) { + const areaJson: FeatureCollection = { + type: 'FeatureCollection', + features: areaJsonArr + } + const content = [] + if (label.showDimension) { + const mappedName = areaMapping?.[drawOption.areaId]?.[area.name] + if (mappedName) { + area.name = mappedName + } + content.push(area.name) + } + if (label.showQuota) { + areaMap[area.name] && + content.push(valueFormatter(areaMap[area.name].value, label.quotaLabelFormatter)) + } + const center = centroid(areaJson) + labelLocation.push({ + name: content.join('\n\n'), + x: center.geometry.coordinates[0], + y: center.geometry.coordinates[1] + }) + } + }) + const areaLabelLayer = new TextLayer({ + name: 'areaLabelLayer', + source: { + data: labelLocation, + parser: { + type: 'json', + x: 'x', + y: 'y' + } + }, + field: 'name', + zIndex: 0.06, + style: { + fill: label.color, + fontSize: label.fontSize, + opacity: 1, + fontWeight: 'bold', + textAnchor: 'center', + textAllowOverlap: label.fullDisplay, + padding: !label.fullDisplay ? [2, 2] : undefined + } + }) + context.layers = [areaLabelLayer] + } + return options + } + + protected setupOptions( + chart: Chart, + options: ChoroplethOptions, + context: Record + ): ChoroplethOptions { + return flow( + this.configEmptyDataStrategy, + this.configLabel, + this.configStyle, + this.configTooltip, + this.configBasicStyle, + this.configCustomArea + )(chart, options, context, this) + } +} diff --git a/frontend/src/data-visualization/chart/components/js/panel/charts/map/common.ts b/frontend/src/data-visualization/chart/components/js/panel/charts/map/common.ts new file mode 100644 index 0000000..7589f4d --- /dev/null +++ b/frontend/src/data-visualization/chart/components/js/panel/charts/map/common.ts @@ -0,0 +1,56 @@ +export const MAP_EDITOR_PROPERTY: EditorProperty[] = [ + 'background-overall-component', + 'border-style', + 'basic-style-selector', + 'title-selector', + 'label-selector', + 'tooltip-selector', + 'function-cfg', + 'map-mapping', + 'jump-set', + 'linkage' +] + +export const MAP_EDITOR_PROPERTY_INNER: EditorPropertyInner = { + 'background-overall-component': ['all'], + 'border-style': ['all'], + 'basic-style-selector': ['colors', 'alpha', 'areaBorderColor', 'zoom'], + 'title-selector': [ + 'title', + 'fontSize', + 'color', + 'hPosition', + 'isItalic', + 'isBolder', + 'remarkShow', + 'fontFamily', + 'letterSpace', + 'fontShadow' + ], + 'label-selector': [ + 'color', + 'fontSize', + 'labelBgColor', + 'labelShadow', + 'labelShadowColor', + 'showDimension', + 'showQuota' + ], + 'tooltip-selector': ['color', 'fontSize', 'backgroundColor', 'seriesTooltipFormatter', 'show'], + 'function-cfg': ['emptyDataStrategy'], + 'map-mapping': [''] +} + +export const MAP_AXIS_TYPE: AxisType[] = [ + 'xAxis', + 'yAxis', + 'area', + 'drill', + 'filter', + 'extLabel', + 'extTooltip' +] + +export declare type MapMouseEvent = MouseEvent & { + feature: GeoJSON.Feature +} diff --git a/frontend/src/data-visualization/chart/components/js/panel/charts/map/flow-map.ts b/frontend/src/data-visualization/chart/components/js/panel/charts/map/flow-map.ts new file mode 100644 index 0000000..2d11189 --- /dev/null +++ b/frontend/src/data-visualization/chart/components/js/panel/charts/map/flow-map.ts @@ -0,0 +1,411 @@ +import { useI18n } from '@/data-visualization/hooks/web/useI18n' +import { + L7ChartView, + L7Config, + L7DrawConfig, + L7Wrapper +} from '@/data-visualization/chart/components/js/panel/types/impl/l7' +import { MAP_EDITOR_PROPERTY_INNER } from '@/data-visualization/chart/components/js/panel/charts/map/common' +import { hexColorToRGBA, parseJson } from '@/data-visualization/chart/components/js/util' +import { deepCopy } from '@/data-visualization/utils/utils' +import { GaodeMap } from '@antv/l7-maps' +import { Scene } from '@antv/l7-scene' +import { LineLayer } from '@antv/l7-layers' +import { PointLayer } from '@antv/l7-layers' +import { mapRendered, mapRendering } from '@/data-visualization/chart/components/js/panel/common/common_antv' +import { DEFAULT_BASIC_STYLE } from '@/data-visualization/chart/components/editor/util/chart' +const { t } = useI18n() + +/** + * 流向地图 + */ +export class FlowMap extends L7ChartView { + properties: EditorProperty[] = [ + 'background-overall-component', + 'border-style', + 'basic-style-selector', + 'title-selector', + 'flow-map-line-selector', + 'flow-map-point-selector', + 'bubble-animate' + ] + propertyInner: EditorPropertyInner = { + ...MAP_EDITOR_PROPERTY_INNER, + 'basic-style-selector': [ + 'mapBaseStyle', + 'mapLineStyle', + 'zoom', + 'showLabel', + 'autoFit', + 'mapCenter', + 'zoomLevel' + ] + } + axis: AxisType[] = ['xAxis', 'xAxisExt', 'filter', 'flowMapStartName', 'flowMapEndName', 'yAxis'] + axisConfig: AxisConfig = { + xAxis: { + name: `${t('chart.start_coordinates')} / ${t('chart.dimension')}`, + type: 'd', + limit: 2 + }, + xAxisExt: { + name: `${t('chart.end_coordinates')} / ${t('chart.dimension')}`, + type: 'd', + limit: 2 + }, + flowMapStartName: { + name: `${t('chart.start_name')} / ${t('chart.dimension')}`, + type: 'd', + limit: 1, + allowEmpty: true + }, + flowMapEndName: { + name: `${t('chart.end_name')} / ${t('chart.dimension')}`, + type: 'd', + limit: 1, + allowEmpty: true + }, + yAxis: { + name: `${t('chart.flow_map_line_width')} / ${t('chart.quota')}`, + type: 'q', + limit: 1, + tooltip: t('chart.flow_map_line_width_tip'), + allowEmpty: true + } + } + constructor() { + super('flow-map', []) + } + + async drawChart(drawOption: L7DrawConfig) { + const { chart, container } = drawOption + const containerDom = document.getElementById(container) + const rect = containerDom?.getBoundingClientRect() + if (rect?.height <= 0) { + return new L7Wrapper(drawOption.chartObj?.getScene(), []) + } + const xAxis = deepCopy(chart.xAxis) + const xAxisExt = deepCopy(chart.xAxisExt) + const { basicStyle, misc } = deepCopy(parseJson(chart.customAttr)) + + let center: [number, number] = [ + DEFAULT_BASIC_STYLE.mapCenter.longitude, + DEFAULT_BASIC_STYLE.mapCenter.latitude + ] + if (basicStyle.autoFit === false) { + center = [basicStyle.mapCenter.longitude, basicStyle.mapCenter.latitude] + } + let mapStyle = basicStyle.mapStyleUrl + if (basicStyle.mapStyle !== 'custom') { + mapStyle = `amap://styles/${basicStyle.mapStyle ? basicStyle.mapStyle : 'normal'}` + } + const mapKey = await this.getMapKey() + // 底层 + const chartObj = drawOption.chartObj as unknown as L7Wrapper + let scene = chartObj?.getScene() + if(scene){ + if (scene.getLayers()?.length) { + await scene.removeAllLayer() + scene.setPitch(misc.mapPitch) + } + } + if (mapStyle.indexOf('Satellite') == -1) { + scene = new Scene({ + id: container, + logoVisible: false, + map: new GaodeMap({ + token: mapKey?.key ?? undefined, + style: mapStyle, + pitch: misc.mapPitch, + center, + zoom: basicStyle.autoFit === false ? basicStyle.zoomLevel : undefined, + showLabel: !(basicStyle.showLabel === false), + WebGLParams: { + preserveDrawingBuffer: true + } + }) + }) + }else{ + scene = new Scene({ + id: container, + logoVisible: false, + map: new GaodeMap({ + token: mapKey?.key ?? undefined, + style: mapStyle, + features: ['bg', 'road'], // 必须开启路网层 + plugin: ['AMap.TileLayer.Satellite'], // 显式声明卫星图层 + WebGLParams: { + preserveDrawingBuffer: true + } + }) + }) + } + // if (!scene) { + // scene = new Scene({ + // id: container, + // logoVisible: false, + // map: new GaodeMap({ + // token: mapKey?.key ?? undefined, + // style: mapStyle, + // pitch: misc.mapPitch, + // center: basicStyle.autoFit === false ? center : undefined, + // zoom: basicStyle.autoFit === false ? basicStyle.zoomLevel : undefined, + // showLabel: !(basicStyle.showLabel === false), + // WebGLParams: { + // preserveDrawingBuffer: true + // } + // }) + // }) + // } else { + // if (scene.getLayers()?.length) { + // await scene.removeAllLayer() + // scene.setPitch(misc.mapPitch) + // scene.setMapStyle(mapStyle) + // scene.map.showLabel = !(basicStyle.showLabel === false) + // } + // if (basicStyle.autoFit === false) { + // scene.setZoomAndCenter(basicStyle.zoomLevel, center) + // } + // } + mapRendering(container) + if (mapStyle.indexOf('Satellite') == -1) { + scene.once('loaded', () => { + mapRendered(container) + }) + } else { + scene.once('loaded', () => { + // 创建卫星图层实例 + const satelliteLayer = new AMap.TileLayer.Satellite() + // 与矢量图层叠加显示 + satelliteLayer.setMap(scene.map) + mapRendered(container) + }) + } + // scene.once('loaded', () => { + // mapRendered(container) + // }) + this.configZoomButton(chart, scene) + if (xAxis?.length < 2 || xAxisExt?.length < 2) { + return new L7Wrapper(scene, undefined) + } + const configList = [] + configList.push(this.lineConfig(chart, xAxis, xAxisExt, basicStyle, misc)) + this.startAndEndNameConfig(chart, xAxis, xAxisExt, misc, configList) + this.pointConfig(chart, xAxis, xAxisExt, misc, configList) + configList[0].once('inited', () => { + mapRendered(container) + }) + return new L7Wrapper(scene, configList) + } + + lineConfig = (chart, xAxis, xAxisExt, basicStyle, misc) => { + const flowLineStyle = { + type: misc.flowMapConfig.lineConfig.mapLineType, + size: + misc.flowMapConfig.lineConfig.mapLineType === 'line' + ? misc.flowMapConfig.lineConfig.mapLineWidth / 2 + : misc.flowMapConfig.lineConfig.mapLineWidth, + animate: misc.flowMapConfig.lineConfig.mapLineAnimate, + animateDuration: misc.flowMapConfig.lineConfig.mapLineAnimateDuration, + gradient: misc.flowMapConfig.lineConfig.mapLineGradient, + sourceColor: misc.flowMapConfig.lineConfig.mapLineSourceColor, + targetColor: misc.flowMapConfig.lineConfig.mapLineTargetColor, + alpha: misc.flowMapConfig.lineConfig.alpha + } + const colorsWithAlpha = basicStyle.colors.map(color => + hexColorToRGBA(color, misc.flowMapConfig.lineConfig.alpha) + ) + flowLineStyle.sourceColor = colorsWithAlpha[0] + flowLineStyle.targetColor = colorsWithAlpha[1] + // 线条粗细 + let lineWidthField = null + const yAxis = deepCopy(chart.yAxis) + if (yAxis.length > 0) { + lineWidthField = yAxis[0].dataeaseName + } + // 线条颜色 + let lineColorField = null + const yAxisExt = deepCopy(chart.yAxisExt) + if (yAxisExt.length > 0) { + lineColorField = yAxisExt[0].dataeaseName + } + const asteriskField = '*' + const data = [] + chart.data?.tableRow.forEach(item => { + const newKey = 'f_record' + const newObj = Object.keys(item).reduce((acc, key) => { + if (key === asteriskField) { + acc[newKey] = item[key] + } else { + acc[key] = item[key] + } + return acc + }, {}) + data.push(newObj) + }) + const config: L7Config = new LineLayer({ + name: 'line', + blend: 'normal', + autoFit: !(basicStyle.autoFit === false) + }) + .source(data, { + parser: { + type: 'json', + x: xAxis[0].dataeaseName, + y: xAxis[1].dataeaseName, + x1: xAxisExt[0].dataeaseName, + y1: xAxisExt[1].dataeaseName + } + }) + .size(flowLineStyle.size) + .shape(flowLineStyle.type) + .animate({ + enable: flowLineStyle.animate, + duration: flowLineStyle.animateDuration, + interval: 1, + trailLength: 1 + }) + + if (lineWidthField) { + config.size(lineWidthField === asteriskField ? 'f_record' : lineWidthField, [1, 10]) + } + if (lineColorField) { + config.style({ + opacity: flowLineStyle.alpha / 100 + }) + config.color(lineColorField) + } else { + if (flowLineStyle.gradient) { + config.style({ + sourceColor: flowLineStyle.sourceColor, + targetColor: flowLineStyle.targetColor, + opacity: flowLineStyle.alpha / 100 + }) + } else { + config + .style({ + opacity: flowLineStyle.alpha / 100 + }) + .color(flowLineStyle.sourceColor) + } + } + + return config + } + + startAndEndNameConfig = (chart, xAxis, xAxisExt, misc, configList) => { + const flowMapStartName = deepCopy(chart.flowMapStartName) + const flowMapEndName = deepCopy(chart.flowMapEndName) + const textColor = misc.flowMapConfig.pointConfig.text.color + const textFontSize = misc.flowMapConfig.pointConfig.text.fontSize + const has = new Map() + if (flowMapStartName?.length > 0) { + const startTextLayer = new PointLayer() + .source(chart.data?.tableRow, { + parser: { + type: 'json', + x: xAxis[0].dataeaseName, + y: xAxis[1].dataeaseName + } + }) + .shape(flowMapStartName[0].dataeaseName, args => { + if (has.has('from-' + args)) { + return '' + } + has.set('from-' + args, args) + return args + }) + .size(textFontSize) + .color(textColor) + .style({ + textAnchor: 'top', // 文本相对锚点的位置 center|left|right|top|bottom|top-left + textOffset: [0, 0], // 文本相对锚点的偏移量 [水平, 垂直] + spacing: 2, // 字符间距 + padding: [1, 1], // 文本包围盒 padding [水平,垂直],影响碰撞检测结果,避免相邻文本靠的太近 + textAllowOverlap: true, + fontFamily: chart.fontFamily ? chart.fontFamily : undefined + }) + configList.push(startTextLayer) + } + if (flowMapEndName?.length > 0) { + const endTextLayer = new PointLayer() + .source(chart.data?.tableRow, { + parser: { + type: 'json', + x: xAxisExt[0].dataeaseName, + y: xAxisExt[1].dataeaseName + } + }) + .shape(flowMapEndName[0].dataeaseName, args => { + if (has.has('from-' + args) || has.has('to-' + args)) { + return '' + } + has.set('to-' + args, args) + return args + }) + .size(textFontSize) + .color(textColor) + .style({ + textAnchor: 'top', // 文本相对锚点的位置 center|left|right|top|bottom|top-left + textOffset: [0, 0], // 文本相对锚点的偏移量 [水平, 垂直] + spacing: 2, // 字符间距 + padding: [1, 1], // 文本包围盒 padding [水平,垂直],影响碰撞检测结果,避免相邻文本靠的太近 + textAllowOverlap: true, + fontFamily: chart.fontFamily ? chart.fontFamily : undefined + }) + configList.push(endTextLayer) + } + } + + pointConfig = (chart, xAxis, xAxisExt, misc, configList) => { + const color = misc.flowMapConfig.pointConfig.point.color + const size = misc.flowMapConfig.pointConfig.point.size + const { bubbleCfg } = parseJson(chart.senior) + const fromDefaultPointLayer = new PointLayer({ zIndex: -1 }) + .source(chart.data?.tableRow, { + parser: { + type: 'json', + x: xAxis[0].dataeaseName, + y: xAxis[1].dataeaseName + } + }) + .shape('circle') + .size(size) + .color(color) + .style({ + blur: 0.6 + }) + const toDefaultPointLayer = new PointLayer({ zIndex: -1 }) + .source(chart.data?.tableRow, { + parser: { + type: 'json', + x: xAxisExt[0].dataeaseName, + y: xAxisExt[1].dataeaseName + } + }) + .shape('circle') + .size(size) + .color(color) + .style({ + blur: 0.6 + }) + if (bubbleCfg && bubbleCfg.enable) { + const animate = { + enable: true, + speed: bubbleCfg.speed, + rings: bubbleCfg.rings + } + fromDefaultPointLayer.size(size * 2) + fromDefaultPointLayer.animate(animate) + toDefaultPointLayer.size(size * 2) + toDefaultPointLayer.animate(animate) + } + configList.push(fromDefaultPointLayer) + configList.push(toDefaultPointLayer) + } + + setupDefaultOptions(chart: ChartObj): ChartObj { + chart.customAttr.misc.flowMapConfig.lineConfig.mapLineAnimate = true + return chart + } +} diff --git a/frontend/src/data-visualization/chart/components/js/panel/charts/map/heat-map.ts b/frontend/src/data-visualization/chart/components/js/panel/charts/map/heat-map.ts new file mode 100644 index 0000000..3701bbd --- /dev/null +++ b/frontend/src/data-visualization/chart/components/js/panel/charts/map/heat-map.ts @@ -0,0 +1,186 @@ +import { useI18n } from '@/data-visualization/hooks/web/useI18n' +import { + L7ChartView, + L7Config, + L7DrawConfig, + L7Wrapper +} from '@/data-visualization/chart/components/js/panel/types/impl/l7' +import { MAP_EDITOR_PROPERTY_INNER } from '@/data-visualization/chart/components/js/panel/charts/map/common' +import { flow, parseJson } from '@/data-visualization/chart/components/js/util' +import { deepCopy } from '@/data-visualization/utils/utils' +import { GaodeMap } from '@antv/l7-maps' +import { Scene } from '@antv/l7-scene' +import { HeatmapLayer } from '@antv/l7-layers' +import { DEFAULT_BASIC_STYLE } from '@/data-visualization/chart/components/editor/util/chart' +import { mapRendered, mapRendering } from '@/data-visualization/chart/components/js/panel/common/common_antv' +const { t } = useI18n() + +/** + * 流向地图 + */ +export class HeatMap extends L7ChartView { + properties: EditorProperty[] = [ + 'background-overall-component', + 'border-style', + 'basic-style-selector', + 'title-selector' + ] + propertyInner: EditorPropertyInner = { + ...MAP_EDITOR_PROPERTY_INNER, + 'basic-style-selector': [ + 'colors', + 'heatMapStyle', + 'zoom', + 'showLabel', + 'autoFit', + 'mapCenter', + 'zoomLevel' + ] + } + axis: AxisType[] = ['xAxis', 'yAxis', 'filter'] + axisConfig: AxisConfig = { + xAxis: { + name: `${t('chart.longitude_and_latitude')} / ${t('chart.dimension')}`, + type: 'd', + limit: 2 + }, + yAxis: { + name: `${t('chart.chart_data')} / ${t('chart.quota')}`, + type: 'q', + limit: 1 + } + } + constructor() { + super('heat-map', []) + } + + async drawChart(drawOption: L7DrawConfig) { + const { chart, container } = drawOption + const containerDom = document.getElementById(container) + const rect = containerDom?.getBoundingClientRect() + if (rect?.height <= 0) { + return new L7Wrapper(drawOption.chartObj?.getScene(), []) + } + const xAxis = deepCopy(chart.xAxis) + const yAxis = deepCopy(chart.yAxis) + let basicStyle: DeepPartial + let miscStyle: DeepPartial + if (chart.customAttr) { + basicStyle = parseJson(chart.customAttr).basicStyle + miscStyle = parseJson(chart.customAttr).misc + } + let center: [number, number] = [ + DEFAULT_BASIC_STYLE.mapCenter.longitude, + DEFAULT_BASIC_STYLE.mapCenter.latitude + ] + if (basicStyle.autoFit === false) { + center = [basicStyle.mapCenter.longitude, basicStyle.mapCenter.latitude] + } + let mapStyle = basicStyle.mapStyleUrl + if (basicStyle.mapStyle !== 'custom') { + mapStyle = `amap://styles/${basicStyle.mapStyle ? basicStyle.mapStyle : 'normal'}` + } + const mapKey = await this.getMapKey() + // 底层 + const chartObj = drawOption.chartObj as unknown as L7Wrapper + let scene = chartObj?.getScene() + if(scene){ + if (scene.getLayers()?.length) { + await scene.removeAllLayer() + scene.setPitch(miscStyle.mapPitch) + } + } + + if (mapStyle.indexOf('Satellite') == -1) { + scene = new Scene({ + id: container, + logoVisible: false, + map: new GaodeMap({ + token: mapKey?.key ?? undefined, + style: mapStyle, + pitch: miscStyle.mapPitch, + center, + zoom: basicStyle.autoFit === false ? basicStyle.zoomLevel : undefined, + showLabel: !(basicStyle.showLabel === false), + WebGLParams: { + preserveDrawingBuffer: true + } + }) + }) + } else { + scene = new Scene({ + id: container, + logoVisible: false, + map: new GaodeMap({ + token: mapKey?.key ?? undefined, + style: mapStyle, + features: ['bg', 'road'], // 必须开启路网层 + plugin: ['AMap.TileLayer.Satellite'], // 显式声明卫星图层 + WebGLParams: { + preserveDrawingBuffer: true + } + }) + }) + } + + // } else { + // // if (scene.getLayers()?.length) { + // await scene.removeAllLayer() + // scene.setPitch(miscStyle.mapPitch) + // scene.setMapStyle(mapStyle) + // scene.map.showLabel = !(basicStyle.showLabel === false) + // if (basicStyle.autoFit === false) { + // scene.setZoomAndCenter(basicStyle.zoomLevel, center) + // } + // // } + // } + mapRendering(container) + if (mapStyle.indexOf('Satellite') == -1) { + scene.once('loaded', () => { + mapRendered(container) + }) + } else { + scene.once('loaded', () => { + // 创建卫星图层实例 + const satelliteLayer = new AMap.TileLayer.Satellite() + // 与矢量图层叠加显示 + satelliteLayer.setMap(scene.map) + mapRendered(container) + }) + } + + this.configZoomButton(chart, scene) + if (xAxis?.length < 2 || yAxis?.length < 1) { + return new L7Wrapper(scene, undefined) + } + const config: L7Config = new HeatmapLayer({ + name: 'line', + blend: 'normal', + autoFit: !(basicStyle.autoFit === false) + }) + .source(chart.data?.data, { + parser: { + type: 'json', + x: 'x', + y: 'y' + } + }) + .size('value', [0, 1.0]) // weight映射通道 + .shape(basicStyle.heatMapType ?? DEFAULT_BASIC_STYLE.heatMapType) + + config.style({ + intensity: basicStyle.heatMapIntensity ?? DEFAULT_BASIC_STYLE.heatMapIntensity, + radius: basicStyle.heatMapRadius ?? DEFAULT_BASIC_STYLE.heatMapRadius, + rampColors: { + colors: basicStyle.colors.reverse(), + positions: [0, 0.11, 0.22, 0.33, 0.44, 0.55, 0.66, 0.77, 0.88, 1.0] + } + }) + + return new L7Wrapper(scene, config) + } + + protected setupOptions(chart: Chart, config: L7Config): L7Config { + return flow(this.configEmptyDataStrategy)(chart, config) + } +} diff --git a/frontend/src/data-visualization/chart/components/js/panel/charts/map/map.ts b/frontend/src/data-visualization/chart/components/js/panel/charts/map/map.ts new file mode 100644 index 0000000..51ceea3 --- /dev/null +++ b/frontend/src/data-visualization/chart/components/js/panel/charts/map/map.ts @@ -0,0 +1,617 @@ +import { + L7PlotChartView, + L7PlotDrawOptions +} from '@/data-visualization/chart/components/js/panel/types/impl/l7plot' +import type { Choropleth, ChoroplethOptions } from '@antv/l7plot/dist/esm/plots/choropleth' +import { + filterChartDataByRange, + flow, + getDynamicColorScale, + getGeoJsonFile, + hexColorToRGBA, + parseJson, + getMaxAndMinValueByData, + filterEmptyMinValue +} from '@/data-visualization/chart/components/js/util' +import { + handleGeoJson, + mapRendered, + mapRendering +} from '@/data-visualization/chart/components/js/panel/common/common_antv' +import type { FeatureCollection } from '@antv/l7plot/dist/esm/plots/choropleth/types' +import { cloneDeep, defaultsDeep, isEmpty } from 'lodash-es' +import { useI18n } from '@/data-visualization/hooks/web/useI18n' +import { valueFormatter } from '../../../formatter' +import { + MAP_AXIS_TYPE, + MAP_EDITOR_PROPERTY, + MAP_EDITOR_PROPERTY_INNER, + MapMouseEvent +} from '@/data-visualization/chart/components/js/panel/charts/map/common' +import type { CategoryLegendListItem } from '@antv/l7plot-component/dist/lib/types/legend' +import createDom from '@antv/dom-util/esm/create-dom' +import { + CONTAINER_TPL, + ITEM_TPL, + LIST_CLASS +} from '@antv/l7plot-component/dist/esm/legend/category/constants' +import substitute from '@antv/util/esm/substitute' +import { configCarouselTooltip } from '@/data-visualization/chart/components/js/panel/charts/map/tooltip-carousel' +import { getCustomGeoArea } from '@/api/data-visualization/map' +import { centroid } from '@turf/centroid' +import { TextLayer } from '@antv/l7plot/dist/esm' + +const { t } = useI18n() + +/** + * 地图 + */ +export class Map extends L7PlotChartView { + properties: EditorProperty[] = [...MAP_EDITOR_PROPERTY, 'legend-selector'] + propertyInner: EditorPropertyInner = { + ...MAP_EDITOR_PROPERTY_INNER, + 'basic-style-selector': [ + 'colors', + 'alpha', + 'areaBorderColor', + 'areaBaseColor', + 'zoom', + 'gradient-color' + ], + 'legend-selector': ['icon', 'fontSize', 'color'], + 'tooltip-selector': [...MAP_EDITOR_PROPERTY_INNER['tooltip-selector'], 'carousel'] + } + axis = MAP_AXIS_TYPE + axisConfig: AxisConfig = { + xAxis: { + name: `${t('chart.area')} / ${t('chart.dimension')}`, + type: 'd', + limit: 1 + }, + yAxis: { + name: `${t('chart.chart_data')} / ${t('chart.quota')}`, + type: 'q', + limit: 1 + } + } + + constructor() { + super('map', []) + } + + async drawChart(drawOption: L7PlotDrawOptions): Promise { + const { chart, level, container, action, scope } = drawOption + const { areaId } = drawOption + if (!areaId) { + return + } + chart.container = container + let sourceData = JSON.parse(JSON.stringify(chart.data?.data || [])) + const { misc } = parseJson(chart.customAttr) + const { legend } = parseJson(chart.customStyle) + let geoJson = {} as FeatureCollection + // 自定义区域,去除非区域数据,优先级最高 + let customSubArea: CustomGeoSubArea[] = [] + if (areaId.startsWith('custom_')) { + customSubArea = (await getCustomGeoArea(areaId)).data || [] + geoJson = cloneDeep(await getGeoJsonFile('156')) + const areaNameMap = geoJson.features.reduce((p, n) => { + p['156' + n.properties.adcode] = n.properties.name + return p + }, {}) + const { areaMapping } = parseJson(chart.senior) + const areaMap = customSubArea.reduce((p, n) => { + const mappedName = areaMapping?.[areaId]?.[n.name] + if (mappedName) { + n.name = mappedName + } + p[n.name] = n + n.scopeArr = n.scope?.split(',') || [] + return p + }, {}) + const fakeData = [] + sourceData.forEach(d => { + const area = areaMap[d.name] + if (area) { + area.scopeArr.forEach(adcode => { + fakeData.push({ + ...d, + name: areaNameMap[adcode], + field: areaNameMap[adcode], + scope: area.scopeArr, + areaName: d.name + }) + }) + } + }) + sourceData = fakeData + } else { + if (scope) { + geoJson = cloneDeep(await getGeoJsonFile('156')) + geoJson.features = geoJson.features.filter(f => scope.includes('156' + f.properties.adcode)) + } else { + geoJson = cloneDeep(await getGeoJsonFile(areaId)) + } + } + let data = [] + // 自定义图例 + if (!misc.mapAutoLegend && legend.show) { + let minValue = misc.mapLegendMin + let maxValue = misc.mapLegendMax + let legendNumber = 9 + if (misc.mapLegendRangeType === 'custom') { + maxValue = 0 + minValue = 0 + legendNumber = misc.mapLegendNumber + } + getMaxAndMinValueByData(sourceData, 'value', maxValue, minValue, (max, min) => { + maxValue = max + minValue = min + action({ + from: 'map', + data: { + max: maxValue, + min: minValue ?? filterEmptyMinValue(sourceData, 'value'), + legendNumber: legendNumber + } + }) + }) + data = filterChartDataByRange(sourceData, maxValue, minValue) + } else { + data = sourceData + } + let options: ChoroplethOptions = { + preserveDrawingBuffer: true, + map: { + type: 'mapbox', + style: 'blank' + }, + geoArea: { + type: 'geojson' + }, + source: { + data: data, + joinBy: { + sourceField: 'name', + geoField: 'name', + geoData: geoJson + } + }, + viewLevel: { + level, + adcode: 'all' + }, + autoFit: true, + chinaBorder: false, + color: { + field: 'value' + }, + style: { + opacity: 1, + lineWidth: 0.6, + lineOpacity: 1 + }, + label: { + field: '_DE_LABEL_', + style: { + textAnchor: 'center' + } + }, + state: { + active: { stroke: 'green', lineWidth: 1 } + }, + tooltip: {}, + // 禁用线上地图数据 + customFetchGeoData: () => null + } + const context: Record = { drawOption, geoJson, customSubArea } + options = this.setupOptions(chart, options, context) + const { Choropleth } = await import('@antv/l7plot/dist/esm/plots/choropleth') + const view = new Choropleth(container, options) + this.configZoomButton(chart, view) + mapRendering(container) + view.once('loaded', () => { + mapRendered(container) + const { layers } = context + if (layers) { + layers.forEach(l => { + view.addLayer(l) + }) + } + view.scene.map['keyboard'].disable() + view.on('fillAreaLayer:click', (ev: MapMouseEvent) => { + const data = ev.feature.properties + if (areaId.startsWith('custom_')) { + data.name = data.areaName + data.adcode = '156' + } + action({ + x: ev.x, + y: ev.y, + data: { + data, + extra: { adcode: data.adcode, scope: data.scope } + } + }) + }) + chart.container = container + configCarouselTooltip(chart, view, data, null, customSubArea, drawOption) + }) + return view + } + + private configBasicStyle( + chart: Chart, + options: ChoroplethOptions, + context: Record + ): ChoroplethOptions { + const { areaId }: L7PlotDrawOptions = context.drawOption + const geoJson: FeatureCollection = context.geoJson + const { basicStyle, label, misc } = parseJson(chart.customAttr) + const senior = parseJson(chart.senior) + const curAreaNameMapping = senior.areaMapping?.[areaId] + handleGeoJson(geoJson, curAreaNameMapping) + options.color = { + field: 'value', + value: [basicStyle.colors[0]], + scale: { + type: 'quantize', + unknown: basicStyle.areaBaseColor + } + } + if (!chart.data?.data?.length || !geoJson?.features?.length) { + options.label && (options.label.field = 'name') + return options + } + const sourceData = options.source.data + const colors = basicStyle.colors.map(item => hexColorToRGBA(item, basicStyle.alpha)) + const { legend } = parseJson(chart.customStyle) + let data = sourceData + let colorScale = [] + let minValue = misc.mapLegendMin + let maxValue = misc.mapLegendMax + let mapLegendNumber = misc.mapLegendNumber + if (legend.show) { + getMaxAndMinValueByData(sourceData, 'value', maxValue, minValue, (max, min) => { + maxValue = max + minValue = min + mapLegendNumber = 9 + }) + // 非自动,过滤数据 + if (!misc.mapAutoLegend) { + data = filterChartDataByRange(sourceData, maxValue, minValue) + } else { + mapLegendNumber = 9 + } + // 定义最大值、最小值、区间数量和对应的颜色 + colorScale = getDynamicColorScale(minValue, maxValue, mapLegendNumber, colors) + } else { + colorScale = colors + } + const areaMap = data.reduce((obj, value) => { + obj[value['field']] = value.value + return obj + }, {}) + geoJson.features.forEach(item => { + const name = item.properties['name'] + // trick, maybe move to configLabel, here for perf + if (label.show) { + const content = [] + if (label.showDimension) { + content.push(name) + } + if (label.showQuota) { + areaMap[name] && content.push(valueFormatter(areaMap[name], label.quotaLabelFormatter)) + } + item.properties['_DE_LABEL_'] = content.join('\n\n') + } + }) + if (colorScale.length) { + options.color['value'] = colorScale.map(item => (item.color ? item.color : item)) + if (colorScale[0].value && !misc.mapAutoLegend) { + options.color['scale']['domain'] = [ + minValue ?? filterEmptyMinValue(sourceData, 'value'), + maxValue + ] + } + } + return options + } + + // 内部函数 创建自定义图例的内容 + private createLegendCustomContent = showItems => { + const containerDom = createDom(CONTAINER_TPL) as HTMLElement + const listDom = containerDom.getElementsByClassName(LIST_CLASS)[0] as HTMLElement + showItems.forEach(item => { + let value = '-' + if (item.value !== '') { + if (Array.isArray(item.value)) { + item.value.forEach((v, i) => { + item.value[i] = Number.isNaN(v) || v === 'NaN' ? 'NaN' : parseFloat(v).toFixed(0) + }) + value = item.value.join('-') + } else { + const tmp = item.value as string + value = Number.isNaN(tmp) || tmp === 'NaN' ? 'NaN' : parseFloat(tmp).toFixed(0) + } + } + const substituteObj = { ...item, value } + + const domStr = substitute(ITEM_TPL, substituteObj) + const itemDom = createDom(domStr) + // 给 legend 形状用的 + itemDom.style.setProperty('--bgColor', item.color) + listDom.appendChild(itemDom) + }) + return listDom + } + + private customConfigLegend( + chart: Chart, + options: ChoroplethOptions, + context: Record + ): ChoroplethOptions { + const { basicStyle, misc } = parseJson(chart.customAttr) + const colors = basicStyle.colors.map(item => hexColorToRGBA(item, basicStyle.alpha)) + if (basicStyle.suspension === false && basicStyle.showZoom === undefined) { + return options + } + const { legend } = parseJson(chart.customStyle) + if (!legend.show) { + return options + } + const LEGEND_SHAPE_STYLE_MAP = { + circle: { + borderRadius: '50%' + }, + square: {}, + triangle: { + border: 'unset', + borderLeft: '5px solid transparent', + borderRight: '5px solid transparent', + borderBottom: '10px solid var(--bgColor)', + background: 'unset' + }, + diamond: { + transform: 'rotate(45deg)' + } + } + const customLegend = { + position: 'bottomleft', + domStyles: { + 'l7plot-legend__category-value': { + fontSize: legend.fontSize + 'px', + color: legend.color, + 'font-family': chart.fontFamily ? chart.fontFamily : undefined + }, + 'l7plot-legend__category-marker': { + ...LEGEND_SHAPE_STYLE_MAP[legend.icon], + width: legend.size + 'px', + height: legend.size + 'px', + ...(legend.icon === 'triangle' + ? { + ...LEGEND_SHAPE_STYLE_MAP[legend.icon]['triangle'], + borderLeft: `${legend.size / 2}px solid transparent`, + borderRight: `${legend.size / 2}px solid transparent`, + borderBottom: `${legend.size}px solid var(--bgColor)` + } + : { border: '0.01px solid #f4f4f4' }), + ...(legend.icon === 'diamond' + ? { + transform: 'rotate(45deg)', + marginBottom: `${legend.size / 4}px` + } + : {}) + } + } + } + // 不是自动图例、自定义图例区间、不是下钻时 + if (!misc.mapAutoLegend && misc.mapLegendRangeType === 'custom' && !chart.drill) { + // 获取图例区间数据 + const items = [] + // 区间数组 + const ranges = misc.mapLegendCustomRange + .slice(0, -1) + .map((item, index) => [item, misc.mapLegendCustomRange[index + 1]]) + ranges.forEach((range, index) => { + const tmpRange = [range[0], range[1]] + const colorIndex = index % colors.length + // 当区间第一个值小于最小值时,颜色取地图底色 + const isLessThanMin = range[0] < ranges[0][0] && range[1] < ranges[0][0] + let rangeColor = colors[colorIndex] + if (isLessThanMin) { + rangeColor = hexColorToRGBA(basicStyle.areaBaseColor, basicStyle.alpha) + } + items.push({ + value: tmpRange, + color: rangeColor + }) + }) + customLegend['customContent'] = (_: string, _items: CategoryLegendListItem[]) => { + if (items?.length) { + return this.createLegendCustomContent(items) + } + return '' + } + options.color['value'] = ({ value }) => { + const item = items.find(item => value >= item.value[0] && value <= item.value[1]) + return item ? item.color : hexColorToRGBA(basicStyle.areaBaseColor, basicStyle.alpha) + } + options.color.scale.domain = [ranges[0][0], ranges[ranges.length - 1][1]] + } else { + customLegend['customContent'] = (_: string, items: CategoryLegendListItem[]) => { + const showItems = items?.length > 30 ? items.slice(0, 30) : items + if (showItems?.length) { + return this.createLegendCustomContent(showItems) + } + return '' + } + } + // 下钻时按照数据值计算图例 + if (chart.drill) { + getMaxAndMinValueByData(options.source.data, 'value', 0, 0, (max, min) => { + options.color.scale.domain = [min, max] + }) + } + defaultsDeep(options, { legend: customLegend }) + return options + } + + protected configCustomArea( + chart: Chart, + options: ChoroplethOptions, + context: Record + ): ChoroplethOptions { + const { drawOption, customSubArea, geoJson } = context + if (!drawOption.areaId.startsWith('custom_')) { + return options + } + const customAttr = parseJson(chart.customAttr) + const { label } = customAttr + const data = chart.data.data + const areaMap = data?.reduce((obj, value) => { + obj[value['field']] = value + return obj + }, {}) + const geoJsonMap = geoJson.features.reduce((p, n) => { + if (n.properties['adcode']) { + p['156' + n.properties['adcode']] = n + } + return p + }, {}) + customSubArea.forEach(area => { + const areaJsonArr = [] + area.scopeArr?.forEach(adcode => { + const json = geoJsonMap[adcode] + json && areaJsonArr.push(json) + }) + if (areaJsonArr.length) { + const areaJson: FeatureCollection = { + type: 'FeatureCollection', + features: areaJsonArr + } + const center = centroid(areaJson) + // 轮播用 + area.centroid = [center.geometry.coordinates[0], center.geometry.coordinates[1]] + } + }) + //处理label + options.label = { + visible: false + } + if (label.show) { + const labelLocation = [] + customSubArea.forEach(area => { + if (area.centroid) { + const content = [] + if (label.showDimension) { + content.push(area.name) + } + if (label.showQuota) { + areaMap[area.name] && + content.push(valueFormatter(areaMap[area.name].value, label.quotaLabelFormatter)) + } + labelLocation.push({ + name: content.join('\n\n'), + x: area.centroid[0], + y: area.centroid[1] + }) + } + }) + const areaLabelLayer = new TextLayer({ + name: 'areaLabelLayer', + source: { + data: labelLocation, + parser: { + type: 'json', + x: 'x', + y: 'y' + } + }, + field: 'name', + style: { + fill: label.color, + fontSize: label.fontSize, + opacity: 1, + fontWeight: 'bold', + textAnchor: 'center', + textAllowOverlap: label.fullDisplay, + padding: !label.fullDisplay ? [2, 2] : undefined + } + }) + context.layers = [areaLabelLayer] + } + // 处理tooltip + const subAreaMap = customSubArea.reduce((p, n) => { + n.scopeArr.forEach(a => { + p[a] = n.name + }) + return p + }, {}) + if (options.tooltip && options.tooltip.showComponent) { + options.tooltip.items = ['name', 'adcode', 'value'] + options.tooltip.customTitle = ({ name, adcode }) => { + adcode = '156' + adcode + return subAreaMap[adcode] ?? name + } + const tooltip = customAttr.tooltip + const formatterMap = tooltip.seriesTooltipFormatter + ?.filter(i => i.show) + .reduce((pre, next) => { + pre[next.id] = next + return pre + }, {}) as Record + options.tooltip.customItems = originalItem => { + const result = [] + if (isEmpty(formatterMap)) { + return result + } + const head = originalItem.properties + const { adcode } = head + const areaName = subAreaMap['156' + adcode] + const valItem = areaMap[areaName] + if (!valItem) { + return result + } + const formatter = formatterMap[valItem.quotaList?.[0]?.id] + if (!isEmpty(formatter)) { + const originValue = parseFloat(valItem.value as string) + const value = valueFormatter(originValue, formatter.formatterCfg) + const name = isEmpty(formatter.chartShowName) ? formatter.name : formatter.chartShowName + result.push({ ...valItem, name, value: `${value ?? ''}` }) + } + valItem.dynamicTooltipValue?.forEach(item => { + const formatter = formatterMap[item.fieldId] + if (formatter) { + const value = valueFormatter(parseFloat(item.value), formatter.formatterCfg) + const name = isEmpty(formatter.chartShowName) ? formatter.name : formatter.chartShowName + result.push({ color: 'grey', name, value: `${value ?? ''}` }) + } + }) + return result + } + } + return options + } + + setupDefaultOptions(chart: ChartObj): ChartObj { + chart.customAttr.basicStyle.areaBaseColor = '#f4f4f4' + return chart + } + + protected setupOptions( + chart: Chart, + options: ChoroplethOptions, + context: Record + ): ChoroplethOptions { + return flow( + this.configEmptyDataStrategy, + this.configLabel, + this.configStyle, + this.configTooltip, + this.configBasicStyle, + this.customConfigLegend, + this.configCustomArea + )(chart, options, context, this) + } +} diff --git a/frontend/src/data-visualization/chart/components/js/panel/charts/map/symbolic-map.ts b/frontend/src/data-visualization/chart/components/js/panel/charts/map/symbolic-map.ts new file mode 100644 index 0000000..8e16a7a --- /dev/null +++ b/frontend/src/data-visualization/chart/components/js/panel/charts/map/symbolic-map.ts @@ -0,0 +1,645 @@ +import { useI18n } from '@/data-visualization/hooks/web/useI18n' +import { + L7ChartView, + L7Config, + L7DrawConfig, + L7Wrapper +} from '@/data-visualization/chart/components/js/panel/types/impl/l7' +import { MAP_EDITOR_PROPERTY_INNER } from '@/data-visualization/chart/components/js/panel/charts/map/common' +import { + getColorFormAlphaColor, + hexColorToRGBA, + parseJson, + svgStrToUrl +} from '@/data-visualization/chart/components/js/util' +import { deepCopy } from '@/data-visualization/utils/utils' +import { GaodeMap } from '@antv/l7-maps' +import { Scene } from '@antv/l7-scene' +import { PointLayer } from '@antv/l7-layers' +import { LayerPopup, Popup } from '@antv/l7' +import { mapRendered, mapRendering } from '@/data-visualization/chart/components/js/panel/common/common_antv' +import { configCarouselTooltip } from '@/data-visualization/chart/components/js/panel/charts/map/tooltip-carousel' +import { DEFAULT_BASIC_STYLE } from '@/data-visualization/chart/components/editor/util/chart' +import { filter } from 'lodash-es' +const { t } = useI18n() + +/** + * 符号地图 + */ +export class SymbolicMap extends L7ChartView { + properties: EditorProperty[] = [ + 'background-overall-component', + 'border-style', + 'basic-style-selector', + 'symbolic-style-selector', + 'title-selector', + 'label-selector', + 'tooltip-selector', + 'threshold' + ] + propertyInner: EditorPropertyInner = { + ...MAP_EDITOR_PROPERTY_INNER, + 'basic-style-selector': [ + 'colors', + 'alpha', + 'mapBaseStyle', + 'zoom', + 'showLabel', + 'autoFit', + 'mapCenter', + 'zoomLevel' + ], + 'symbolic-style-selector': ['symbolicMapStyle'], + 'label-selector': ['color', 'fontSize', 'showFields', 'customContent'], + 'tooltip-selector': [ + 'color', + 'fontSize', + 'showFields', + 'customContent', + 'show', + 'backgroundColor', + 'carousel' + ], + threshold: ['lineThreshold'] + } + axis: AxisType[] = ['xAxis', 'xAxisExt', 'extBubble', 'filter', 'extLabel', 'extTooltip'] + axisConfig: AxisConfig = { + xAxis: { + name: `${t('chart.symbolic_map_coordinates')} / ${t('chart.dimension')}`, + type: 'd', + limit: 2 + }, + xAxisExt: { + name: `${t('chart.color')} / ${t('chart.dimension')}`, + type: 'd', + limit: 1, + allowEmpty: true + }, + extBubble: { + name: `${t('chart.bubble_size')} / ${t('chart.quota')}`, + type: 'q', + limit: 1, + tooltip: t('chart.symbolic_map_bubble_size_tip'), + allowEmpty: true + } + } + constructor() { + super('symbolic-map', []) + } + + async drawChart(drawOption: L7DrawConfig) { + const { chart, container, action } = drawOption + const containerDom = document.getElementById(container) + const rect = containerDom?.getBoundingClientRect() + if (rect?.height <= 0) { + return new L7Wrapper(drawOption.chartObj?.getScene(), []) + } + const xAxis = deepCopy(chart.xAxis) + let basicStyle + let miscStyle + if (chart.customAttr) { + basicStyle = parseJson(chart.customAttr).basicStyle + miscStyle = parseJson(chart.customAttr).misc + } + + let mapStyle = basicStyle.mapStyleUrl + if (basicStyle.mapStyle !== 'custom') { + mapStyle = `amap://styles/${basicStyle.mapStyle ? basicStyle.mapStyle : 'normal'}` + } + const mapKey = await this.getMapKey() + let center: [number, number] = [ + DEFAULT_BASIC_STYLE.mapCenter.longitude, + DEFAULT_BASIC_STYLE.mapCenter.latitude + ] + if (basicStyle.autoFit === false) { + center = [basicStyle.mapCenter.longitude, basicStyle.mapCenter.latitude] + } + // 联动时,聚焦到数据点,多个取第一个 + if ( + chart.chartExtRequest?.linkageFilters?.length && + xAxis?.length === 2 && + chart.data?.tableRow.length + ) { + // 经度 + const lng = chart.data?.tableRow?.[0][chart.xAxis[0].dataeaseName] + // 纬度 + const lat = chart.data?.tableRow?.[0][chart.xAxis[1].dataeaseName] + center = [lng, lat] + } + const chartObj = drawOption.chartObj as unknown as L7Wrapper + let scene = chartObj?.getScene() + if (!scene) { + scene = new Scene({ + id: container, + logoVisible: false, + map: new GaodeMap({ + token: mapKey?.key ?? undefined, + style: mapStyle, + pitch: miscStyle.mapPitch, + center, + zoom: basicStyle.autoFit === false ? basicStyle.zoomLevel : undefined, + showLabel: !(basicStyle.showLabel === false), + WebGLParams: { + preserveDrawingBuffer: true + } + }) + }) + } else { + if (scene.getLayers()?.length) { + await scene.removeAllLayer() + scene.setPitch(miscStyle.mapPitch) + scene.setMapStyle(mapStyle) + scene.map.showLabel = !(basicStyle.showLabel === false) + } + if (basicStyle.autoFit === false) { + scene.setZoomAndCenter(basicStyle.zoomLevel, center) + } + } + mapRendering(container) + scene.once('loaded', () => { + mapRendered(container) + }) + this.configZoomButton(chart, scene) + if (xAxis?.length < 2) { + return new L7Wrapper(scene, undefined) + } + const configList: L7Config[] = [] + const symbolicLayer = await this.buildSymbolicLayer(chart, scene) + configList.push(symbolicLayer) + const tooltipLayer = this.buildTooltip(chart, container, symbolicLayer, scene) + if (tooltipLayer) { + scene.addPopup(tooltipLayer) + } + this.buildLabel(chart, configList) + symbolicLayer.on('inited', () => { + chart.container = container + configCarouselTooltip(chart, symbolicLayer, symbolicLayer.sourceOption.data, scene) + }) + symbolicLayer.on('click', ev => { + const data = ev.feature + const dimensionList = [] + const quotaList = [] + chart.data.fields.forEach((item, index) => { + Object.keys(data).forEach(key => { + if (key.startsWith('f_') && item.dataeaseName === key) { + if (index === 0) { + dimensionList.push({ + id: item.id, + dataeaseName: item.dataeaseName, + value: data[key] + }) + } else { + quotaList.push({ + id: item.id, + dataeaseName: item.dataeaseName, + value: data[key] + }) + } + } + }) + }) + action({ + x: ev.x, + y: ev.y, + data: { + data: { + ...data, + value: quotaList[0].value, + name: dimensionList[0].id, + dimensionList: dimensionList, + quotaList: quotaList + } + } + }) + }) + + return new L7Wrapper(scene, configList) + } + + /** + * 构建符号图层 + * @param chart + */ + buildSymbolicLayer = async (chart, scene: Scene) => { + const { basicStyle } = parseJson(chart.customAttr) as ChartAttr + const xAxis = deepCopy(chart.xAxis) + const xAxisExt = deepCopy(chart.xAxisExt) + const extBubble = deepCopy(chart.extBubble) + const { + mapSymbolOpacity, + mapSymbolSize, + mapSymbol, + mapSymbolStrokeWidth, + colors, + alpha, + mapSymbolSizeMin, + mapSymbolSizeMax + } = deepCopy(basicStyle) + const colorsWithAlpha = colors.map(color => hexColorToRGBA(color, alpha)) + let colorIndex = 0 + // 存储已分配的颜色 + const colorAssignments = new Map() + const sizeKey = extBubble.length > 0 ? extBubble[0].dataeaseName : '' + + //条件颜色 + const { threshold } = parseJson(chart.senior) + let conditions = [] + if (threshold.enable) { + conditions = threshold.lineThreshold ?? [] + } + const extBubbleIds = chart.extBubble.map(i => i.id) + conditions = filter(conditions, c => extBubbleIds.includes(c.fieldId)) + + const baseColor = colorsWithAlpha[0] + const baseColorList = [] + + const data = chart.data?.tableRow + ? chart.data.tableRow.map((item, index) => { + item['_index'] = '_index' + index + // 颜色标识 + const identifier = item[xAxisExt[0]?.dataeaseName] + // 检查该标识是否已有颜色分配,如果没有则分配 + let color = colorAssignments.get(identifier) + if (!color) { + color = colorsWithAlpha[colorIndex++ % colorsWithAlpha.length] + // 记录分配的颜色 + colorAssignments.set(identifier, color) + } + + baseColorList[index] = color + + if (conditions.length > 0) { + for (let i = 0; i < conditions.length; i++) { + const c = conditions[i] + const value = item[c.field.dataeaseName] + for (const t of c.conditions) { + const v = t.value + + //保存一下颜色到map + const _color = getColorFormAlphaColor(t.color) + + if (t.term === 'between') { + const start = parseFloat(t.min) + const end = parseFloat(t.max) + if (start <= value && value <= end) { + color = hexColorToRGBA(_color, alpha) + baseColorList[index] = color + } + } else if ('lt' === t.term) { + if (value < v) { + color = hexColorToRGBA(_color, alpha) + baseColorList[index] = color + } + } else if ('le' === t.term) { + if (value <= v) { + color = hexColorToRGBA(_color, alpha) + baseColorList[index] = color + } + } else if ('gt' === t.term) { + if (value > v) { + color = hexColorToRGBA(_color, alpha) + baseColorList[index] = color + } + } else if ('ge' === t.term) { + if (value >= v) { + color = hexColorToRGBA(_color, alpha) + baseColorList[index] = color + } + } else if ('eq' === t.term) { + if (value === v) { + color = hexColorToRGBA(_color, alpha) + baseColorList[index] = color + } + } else if ('not_eq' === t.term) { + if (value !== v) { + color = hexColorToRGBA(_color, alpha) + baseColorList[index] = color + } + } + } + } + } + + return { + ...item, + color, + size: parseInt(item[sizeKey]) ?? mapSymbolSize, + name: identifier + } + }) + : [] + const pointLayer = new PointLayer({ autoFit: !(basicStyle.autoFit === false) }) + .source(data, { + parser: { + type: 'json', + x: xAxis[0].dataeaseName, + y: xAxis[1].dataeaseName + } + }) + .active(true) + if (xAxisExt[0]?.dataeaseName) { + if (basicStyle.mapSymbol === 'custom' && basicStyle.customIcon) { + // 图片无法改色 + if (basicStyle.customIcon.startsWith('data')) { + scene.removeImage('customIcon') + await scene.addImage('customIcon', basicStyle.customIcon) + pointLayer.shape('customIcon') + } else { + const parser = new DOMParser() + for (let index = 0; index < Math.min(baseColorList.length, colorIndex + 1); index++) { + const color = baseColorList[index] + const fillRegex = /(fill="[^"]*")/g + const svgStr = basicStyle.customIcon.replace(fillRegex, '') + const doc = parser.parseFromString(svgStr, 'image/svg+xml') + const svgEle = doc.documentElement + svgEle.setAttribute('fill', color) + scene.removeImage(`icon-${color}`) + await scene.addImage(`icon-${color}`, svgStrToUrl(svgEle.outerHTML)) + } + pointLayer.shape('color', c => { + return `icon-${c}` + }) + } + } else { + pointLayer.shape(mapSymbol).color('_index', baseColorList) + pointLayer.style({ + stroke: { + field: 'color' + }, + strokeWidth: mapSymbolStrokeWidth, + opacity: mapSymbolOpacity / 10 + }) + } + } else { + if (basicStyle.mapSymbol === 'custom' && basicStyle.customIcon) { + scene.removeImage('customIcon') + if (basicStyle.customIcon.startsWith('data')) { + await scene.addImage('customIcon', basicStyle.customIcon) + pointLayer.shape('customIcon') + } else { + const parser = new DOMParser() + const color = baseColor + const fillRegex = /(fill="[^"]*")/g + const svgStr = basicStyle.customIcon.replace(fillRegex, '') + const doc = parser.parseFromString(svgStr, 'image/svg+xml') + const svgEle = doc.documentElement + svgEle.setAttribute('fill', color) + await scene.addImage(`customIcon`, svgStrToUrl(svgEle.outerHTML)) + pointLayer.shape('customIcon') + } + } else { + pointLayer + .shape(mapSymbol) + .color('_index', baseColorList) + .style({ + stroke: { + field: 'color' + }, + strokeWidth: mapSymbolStrokeWidth, + opacity: mapSymbolOpacity / 10 + }) + } + } + if (sizeKey) { + pointLayer.size('size', [mapSymbolSizeMin, mapSymbolSizeMax]) + } else { + pointLayer.size(mapSymbolSize) + } + return pointLayer + } + + /** + * 合并详情到 map + * @param details + * @returns {Map} + */ + mergeDetailsToMap = details => { + const resultMap = new Map() + details.forEach(item => { + Object.entries(item).forEach(([key, value]) => { + if (resultMap.has(key)) { + const existingValue = resultMap.get(key) + if (existingValue !== value) { + resultMap.set(key, `${existingValue}, ${value}`) + } + } else { + resultMap.set(key, value) + } + }) + }) + return resultMap + } + + /** + * 清除 popup + * @param container + */ + clearPopup = container => { + const containerElement = document.getElementById(container) + containerElement?.querySelectorAll('.l7-popup').forEach((element: Element) => element.remove()) + } + + /** + * 构建 tooltip + * @param chart + * @param pointLayer + */ + buildTooltip = (chart, container, pointLayer, scene) => { + const customAttr = chart.customAttr ? parseJson(chart.customAttr) : null + this.clearPopup(container) + if (customAttr?.tooltip?.show) { + const { tooltip } = deepCopy(customAttr) + let showFields = tooltip.showFields || [] + if (!tooltip.showFields || tooltip.showFields.length === 0) { + showFields = [ + ...chart.xAxisExt.map(i => `${i.dataeaseName}@${i.name}`), + ...chart.xAxis.map(i => `${i.dataeaseName}@${i.name}`) + ] + } + // 修改背景色 + const styleId = 'tooltip-' + container + const styleElement = document.getElementById(styleId) + if (styleElement) { + styleElement.remove() + styleElement.parentNode?.removeChild(styleElement) + } + const style = document.createElement('style') + style.id = styleId + style.innerHTML = ` + #${container} .l7-popup-content { + background-color: ${tooltip.backgroundColor} !important; + padding: 6px 10px 6px; + line-height: 1.6; + border-top-left-radius: 3px; + } + #${container} .l7-popup-tip { + border-top-color: ${tooltip.backgroundColor} !important; + } + ` + document.head.appendChild(style) + const htmlPrefix = `
    ` + const htmlSuffix = '
    ' + const containerElement = document.getElementById(container) + if (containerElement) { + containerElement.addEventListener('mousemove', event => { + const rect = containerElement.getBoundingClientRect() + const mouseX = event.clientX - rect.left + const mouseY = event.clientY - rect.top + const tooltipElement = containerElement.getElementsByClassName('l7-popup') + for (let i = 0; i < tooltipElement?.length; i++) { + const element = tooltipElement[i] as HTMLElement + element.firstElementChild.style.display = 'none' + element.style.transform = 'translate(15px, 12px)' + const isNearRightEdge = + containerElement.clientWidth - mouseX <= element.clientWidth + 10 + const isNearBottomEdge = containerElement.clientHeight - mouseY <= element.clientHeight + let transform = '' + if (isNearRightEdge) { + transform += 'translateX(-120%) translateY(15%) ' + } + if (isNearBottomEdge) { + transform += 'translateX(15%) translateY(-80%) ' + } + if (transform) { + element.style.transform = transform.trim() + } + } + }) + } + pointLayer.on('touchend', e => { + if (e.lngLat) { + const fieldData = { + ...e.feature, + ...Object.fromEntries(this.mergeDetailsToMap(e.feature.details ?? [])) + } + const content = this.buildTooltipContent(tooltip, fieldData, showFields) + const popup = new Popup({ + lngLat: e.lngLat, + title: '', + closeButton: false, + closeOnClick: true, + html: `${htmlPrefix}${content}${htmlSuffix}` + }) + scene.addPopup(popup) + } + }) + return new LayerPopup({ + anchor: 'top-left', + className: 'l7-popup-' + container, + items: [ + { + layer: pointLayer, + customContent: item => { + const fieldData = { + ...item, + ...Object.fromEntries(this.mergeDetailsToMap(item.details)) + } + const content = this.buildTooltipContent(tooltip, fieldData, showFields) + return `${htmlPrefix}${content}${htmlSuffix}` + } + } + ], + trigger: 'hover' + }) + } + return undefined + } + + /** + * 构建 tooltip 内容 + * @param tooltip + * @param fieldData + * @param showFields + * @returns {string} + */ + buildTooltipContent = (tooltip, fieldData, showFields) => { + let content = `` + if (tooltip.customContent) { + content = tooltip.customContent + showFields.forEach(field => { + content = content.replace(`\${${field.split('@')[1]}}`, fieldData[field.split('@')[0]]) + }) + } else { + showFields.forEach(field => { + content += `${field.split('@')[1]}: ${ + fieldData[field.split('@')[0]] + }
    ` + }) + } + return content.replace(/\n/g, '
    ') + } + + /** + * 构建 label + * @param chart + * @param configList + */ + buildLabel = (chart, configList) => { + const xAxis = deepCopy(chart.xAxis) + + const customAttr = chart.customAttr ? parseJson(chart.customAttr) : null + if (customAttr?.label?.show) { + const { label } = customAttr + const data = chart.data?.tableRow || [] + let showFields = label.showFields || [] + if (!label.showFields || label.showFields.length === 0) { + showFields = [ + ...chart.xAxisExt.map(i => `${i.dataeaseName}@${i.name}`), + ...chart.xAxis.map(i => `${i.dataeaseName}@${i.name}`) + ] + } + data.forEach(item => { + const fieldData = { + ...item, + ...Object.fromEntries(this.mergeDetailsToMap(item.details)) + } + let content = label.customContent || '' + + if (content) { + showFields.forEach(field => { + const [fieldKey, fieldName] = field.split('@') + content = content.replace(`\${${fieldName}}`, fieldData[fieldKey]) + }) + } else { + content = showFields.map(field => fieldData[field.split('@')[0]]).join(',') + } + + content = content.replace(/\n/g, '') + item.textLayerContent = content + }) + + configList.push( + new PointLayer() + .source(data, { + parser: { + type: 'json', + x: xAxis[0].dataeaseName, + y: xAxis[1].dataeaseName + } + }) + .shape('textLayerContent', 'text') + .color(label.color) + .size(label.fontSize) + .style({ + textAllowOverlap: label.fullDisplay, + textAnchor: 'center', + textOffset: [0, 0], + fontFamily: chart.fontFamily ? chart.fontFamily : undefined + }) + ) + } + } + + setupDefaultOptions(chart: ChartObj): ChartObj { + chart.customAttr.label = { + ...chart.customAttr.label, + show: false + } + chart.customAttr.basicStyle = { + ...chart.customAttr.basicStyle, + mapSymbolOpacity: 5, + mapStyle: 'normal' + } + return chart + } +} diff --git a/frontend/src/data-visualization/chart/components/js/panel/charts/map/tooltip-carousel.ts b/frontend/src/data-visualization/chart/components/js/panel/charts/map/tooltip-carousel.ts new file mode 100644 index 0000000..31616a8 --- /dev/null +++ b/frontend/src/data-visualization/chart/components/js/panel/charts/map/tooltip-carousel.ts @@ -0,0 +1,657 @@ +import { Popup } from '@antv/l7' +import { Plot } from '@antv/l7plot/dist/lib/core/plot' +import isEmpty from 'lodash-es/isEmpty' +import { valueFormatter } from '@/data-visualization/chart/components/js/formatter' +import { parseJson } from '@/data-visualization/chart/components/js/util' +import { Scene } from '@antv/l7-scene' +import { deepCopy } from '@/data-visualization/utils/utils' + +export const configCarouselTooltip = (chart, view, data, scene, customSubArea?, drawOption?) => { + if (['bubble-map', 'map'].includes(chart.type)) { + data = view.source.data.dataArray + ?.filter(i => i.dimensionList?.length > 0) + .reduce((acc, current) => { + const existingItem = acc.find(obj => { + if (drawOption?.areaId?.startsWith('custom_')) { + return obj.areaName === current.areaName + } else { + return obj.name === current.name || (obj.adcode && obj.adcode === current.adcode) + } + }) + if (!existingItem) { + acc.push(current) + } + return acc + }, []) + } + if (carouselManagerInstances[chart.container]) { + const instances = carouselManagerInstances[chart.container] + instances.update(scene, chart, view, data, customSubArea, drawOption) + } else { + new CarouselManager(scene, chart, view, data, customSubArea, drawOption) + } +} +export const carouselManagerInstances: { [key: string]: CarouselManager } = {} + +/** + * 轮播管理类 + */ +export class CarouselManager { + /** + * 停留时长定时器 + * @private + */ + private popupTimeoutId: number | null = null + /** + * 轮播间隔定时器 + * @private + */ + private popupIntervalId: number | null = null + /** + * 是否暂停轮播 + * @private + */ + private isPaused = false + /** + * 当前显示的数据索引 + * @private + */ + private currentIndex = 0 + /** + * 地图实例,气泡地图用 + * @private + */ + private scene: Scene + private chart: Chart + /** + * 轮播弹窗的位置数据 + * @private + */ + private view: Plot + private data: any[] + /** + * 停留时长 + * @private + */ + private stayTime: number + /** + * 轮播间隔 + * @private + */ + private intervalTime: number + /** + * 轮播弹窗 + * @private + */ + private popup: Popup + + /** + * 自定义区域列表 + * @private + */ + private customSubArea: CustomGeoSubArea[] + + /** + * 渲染参数 + * @private + */ + private drawOption: L7PlotDrawOptions + + // 保存事件监听函数的引用 + private onMouseEnterHandler: () => void + private onMouseLeaveHandler: () => void + private onVisibilityChangeHandler: () => void + + constructor(scene, chart, view, data: any[], customSubArea, drawOption?) { + // 绑定事件处理函数 + this.onMouseEnterHandler = this.pauseCarouselPopups.bind(this) + this.onMouseLeaveHandler = this.resumeCarouselPopups.bind(this) + this.onVisibilityChangeHandler = this.handleVisibilityChange.bind(this) + this.clearExistingTimers = this.clearExistingTimers.bind(this) + this.init(scene, chart, view, data, customSubArea, drawOption) + } + + /** + * 更新轮播弹窗对象内容 + * @param scene + * @param chart + * @param view + * @param data + * @param customSubArea + */ + public update(scene, chart, view, data: any[], customSubArea, drawOption?) { + this.init(scene, chart, view, data, customSubArea, drawOption) + } + + /** + * 初始化轮播弹窗 + * @param scene + * @param chart + * @param view + * @param data + * @private + */ + private init(scene, chart, view, data: any[], customSubArea, drawOption?) { + this.view = view + this.chart = chart + this.scene = scene + this.data = data + this.popup = null + this.currentIndex = 0 + this.customSubArea = customSubArea + this.drawOption = drawOption + this.clearPreviousInstance(this.chart.container) + if ( + this.chart.customAttr?.tooltip?.show && + this.chart.customAttr?.tooltip?.carousel?.enable && + this.data.length > 0 + ) { + this.popup = new Popup({ closeButton: false, maxWidth: 600 }) + const carousel = this.chart.customAttr?.tooltip?.carousel + this.stayTime = carousel.stayTime * 1000 + this.intervalTime = carousel.intervalTime * 1000 + this.startCarouselPopups() + const divElement = document.getElementById(this.chart.container) + divElement.addEventListener('mouseenter', this.pauseCarouselPopups) + divElement.addEventListener('mouseleave', this.resumeCarouselPopups) + // 移动端符号地图不支持mouseenter和mouseleave事件,这里特殊处理一下 + if (this.chart.type === 'symbolic-map') { + // 监听符号触摸事件, 暂停轮播 + scene?.getLayers()?.[0]?.addListener('touchend', () => { + this.pauseCarouselPopups() + }) + // 地图空白区域触摸事件, 启动轮播 + scene?.getMapCanvasContainer()?.addEventListener('touchend', () => { + this.resumeCarouselPopups() + }) + } + // 监听页面可见性变化 + document.addEventListener('visibilitychange', this.handleVisibilityChange) + carouselManagerInstances[this.chart.container] = this + } + } + + private handleVisibilityChange = (): void => { + if (document.hidden) { + this.clearPreviousInstance(this.chart.container) + } else { + this.startCarouselPopups() + } + } + + /** + * 清除之前的实例数据 + * @param containerId + * @private + */ + private clearPreviousInstance(containerId: string): void { + if (carouselManagerInstances[containerId]) { + const instance = carouselManagerInstances[containerId] + this.clearExistingTimers() + instance.popup?.remove() + instance.removeStyle() + } + } + + /** + * 开始轮播 + * @private + */ + private startCarouselPopups(): void { + this.clearExistingTimers() + this.carouselPopups() + } + + /** + * 鼠标移入暂停轮播 + */ + private pauseCarouselPopups = (): void => { + if (this.popup) { + this.popup?.remove() + } + this.removeStyle() + this.isPaused = true + this.clearExistingTimers() + } + + /** + * 鼠标移出开始轮播 + */ + private resumeCarouselPopups = (): void => { + if (this.isPaused) { + this.isPaused = false + this.startCarouselPopups() + } + } + + /** + * 管理轮播弹窗的显示 + * + * 此方法用于处理轮播弹窗的显示逻辑它会根据当前的索引显示对应的弹窗, + * 并在一定时间后自动移除当前弹窗并显示下一个弹窗 + * + * @private + */ + private carouselPopups(): void { + const showPopup = (index: number): void => { + this.removeStyle() + const containerElement = document.getElementById(this.chart.container) + if (containerElement) { + if (this.chart.type === 'symbolic-map') { + // 轮播进行时,隐藏隐藏鼠标悬浮的tooltip + const mouseTooltip = containerElement.getElementsByClassName( + 'l7-popup-' + this.chart.container + ) + for (const tooltip of Array.from(mouseTooltip)) { + const tooltipElement = tooltip as HTMLElement + tooltipElement.classList.add('l7-popup-hide') + } + this.createSymbolicMapPopup(index) + } else { + if (this.chart.type === 'map') { + // 轮播进行时,隐藏隐藏鼠标悬浮的tooltip + const mouseTooltip = containerElement.getElementsByClassName('l7plot-tooltip-container') + for (const tooltip of Array.from(mouseTooltip)) { + const tooltipElement = tooltip as HTMLElement + tooltipElement.style.display = 'none' + } + } + this.createPopup(index) + } + this.clearExistingTimers() + this.popupTimeoutId = window.setTimeout(() => { + this.currentIndex++ + this.popup?.remove() + this.cancelHighlightLayer(index) + if (this.currentIndex >= this.data.length) { + this.currentIndex = 0 + } + this.popupIntervalId = window.setTimeout(() => { + showPopup(this.currentIndex) + }, this.intervalTime) + }, this.stayTime) + } else { + this.clearExistingTimers() + } + } + + showPopup(this.currentIndex) + } + + /** + * 清除定时器 + * @private + */ + private readonly clearExistingTimers = (): void => { + if (this.popupTimeoutId !== null) { + clearTimeout(this.popupTimeoutId) + this.popupTimeoutId = 0 + } + if (this.popupIntervalId !== null) { + clearInterval(this.popupIntervalId) + this.popupIntervalId = 0 + } + } + + /** + * 移除样式 + * 每次创建弹窗前移除之前的样式 + * @private + */ + private removeStyle(): void { + const styleToRemove = document.getElementById('style-' + this.chart.container) + if (styleToRemove) { + styleToRemove.remove() + styleToRemove.parentNode?.removeChild(styleToRemove) + } + } + + /** + * 创建弹窗信息 + * @param index + * @private + */ + private createPopup(index: number): void { + const tooltipStyle = this.view.tooltip.options.domStyles + const tooltipBackgroundColor = tooltipStyle['l7plot-tooltip']['background-color'] + const tooltipFontSize = tooltipStyle['l7plot-tooltip']['font-size'] + const style = document.createElement('style') + style.id = 'style-' + this.chart.container + style.innerHTML = ` + #${this.chart.container} .l7-popup-content { + background-color: ${tooltipBackgroundColor} !important; + font-size: ${tooltipFontSize}; + padding: 10px 10px 6px; + line-height: 1.6; + } + #${this.chart.container} .l7-popup-tip { + border-top-color: ${tooltipBackgroundColor} !important; + } + ` + document.head.appendChild(style) + + const popupData = this.getPopupData(index) + if (popupData.data) { + let tooltipItem = '' + this.getTooltipItems(popupData.data).forEach(fieldData => { + tooltipItem += ` +
  • + ${fieldData.name} + ${fieldData.value} +
  • ` + }) + + const html = ` +
    +
    ${popupData.data.name}
    +
      + ${tooltipItem} +
    +
    + ` + + this.popup.setLngLat({ lng: popupData.centroid[0], lat: popupData.centroid[1] }) + this.popup.setHTML(html) + this.popup.closeButton = false + this.view.addLayer(this.popup) + // 地图层高亮 + this.view.scene + .getLayers() + ?.find(i => i.name === 'highlightLayer') + ?.setData(this.getActiveData(index)) + if (this.chart.type === 'bubble-map') { + // 气泡地图高亮 + const { _id } = this.view.scene + .getLayers() + ?.find(i => i.name === 'bubbleLayer') + ?.layerSource.data.dataArray.find(i => i.name === this.data[index].name) + this.view.scene + .getLayers() + ?.find(i => i.name === 'bubbleLayer' && i.coordCenter) + ?.setActive(_id, { color: 'rgba(30,90,255,1)' }) + } + } + } + + private getActiveData(index): any { + if (this.drawOption?.areaId?.startsWith('custom_')) { + const result = { + type: 'FeatureCollection', + features: [] + } + const area = this.customSubArea.find(a => a.name === this.data[index].areaName) + const areaMap = this.view.currentDistrictData.features.reduce((p, n) => { + p['156' + n.properties.adcode] = n + return p + }, {}) + area?.scopeArr?.forEach(s => { + if (areaMap[s]) { + result.features.push(areaMap[s]) + } + }) + return result + } + return { + type: 'FeatureCollection', + features: [ + this.view.currentDistrictData.features.find( + i => i.properties.name === this.data[index].name + ) + ] + } + } + + /** + * 获取弹窗信息,包括原始数据及位置信息 + * @param index + * @private + */ + private getPopupData(index: number): any { + if (this.drawOption?.areaId?.startsWith('custom_')) { + const data = this.data[index] + const area = this.customSubArea?.find(a => a.name === data.areaName) + data.name = data.areaName + return { + data, + centroid: area.centroid + } + } else { + return { + data: this.data[index], + centroid: this.view.currentDistrictData.features.find( + i => i.properties.name === this.data[index].name + )?.properties.centroid + } + } + } + + /** + * 将对象转换为 CSS 属性 + * @param obj + * @private + */ + private objectToSemicolonSeparated(obj: any): string { + let result = '' + for (const key in obj) { + if (obj.hasOwnProperty(key)) { + result += `${this.convertToSnakeCase(key)}:${obj[key]};` + } + } + return result + } + + private cancelHighlightLayer(index?: number): void { + this.view.scene + ?.getLayers() + ?.find(i => i.name === 'highlightLayer') + ?.setData({ type: 'FeatureCollection', features: [] }) + if (this.chart.type === 'bubble-map') { + const { _id } = this.view.scene + ?.getLayers() + ?.find(i => i.name === 'bubbleLayer') + ?.layerSource.data.dataArray.find(i => i.name === this.data[index].name) + this.view.scene + .getLayers() + ?.find(i => i.name === 'bubbleLayer' && i.coordCenter) + ?.setActive(_id, { + color: this.view.scene + .getLayers() + .find(i => i.name === 'bubbleLayer') + .styleAttributeService.getLayerStyleAttribute('color').scale.field + }) + } + if (this.chart.type === 'symbolic-map') { + const lngField = this.chart.xAxis[0].dataeaseName + const latField = this.chart.xAxis[1].dataeaseName + const { _id } = this.scene + ?.getLayers() + ?.find(i => i.type === 'PointLayer') + ?.layerSource.data.dataArray.find(i => { + const targetLng = this.data[index][lngField] + const targetLat = this.data[index][latField] + return i[lngField] === targetLng && i[latField] === targetLat + }) + this.scene + .getLayers() + ?.find(i => i.type === 'PointLayer' && i.coordCenter) + ?.setActive(_id, { + color: this.scene + .getLayers() + .find(i => i.type === 'PointLayer') + .styleAttributeService.getLayerStyleAttribute('color').scale.field + }) + } + } + + /** + * 将驼峰式命名转换为蛇形命名 + * @param str + * @private + */ + private convertToSnakeCase(str: string): string { + return str.replace(/([A-Z])/g, match => '-' + match.toLowerCase()) + } + + /** + * 获取弹窗字段信息 + * 与tooltip要显示的内容一致 + * @param data + * @private + */ + private getTooltipItems(data) { + const result = [] + const customAttr = parseJson(this.chart.customAttr) + const tooltip = customAttr.tooltip + const formatterMap = tooltip.seriesTooltipFormatter + ?.filter(i => i.show) + .reduce((pre, next) => { + pre[next.id] = next + return pre + }, {}) as Record + if (isEmpty(formatterMap)) { + return result + } + const head = data + const formatter = formatterMap[head.quotaList?.[0]?.id] + if (!isEmpty(formatter)) { + const originValue = parseFloat(head.value as string) + const value = valueFormatter(originValue, formatter.formatterCfg) + const name = isEmpty(formatter.chartShowName) ? formatter.name : formatter.chartShowName + result.push({ ...head, name, value: `${value ?? ''}` }) + } + head.dynamicTooltipValue?.forEach(item => { + const formatter = formatterMap[item.fieldId] + if (formatter) { + const value = valueFormatter(parseFloat(item.value), formatter.formatterCfg) + const name = isEmpty(formatter.chartShowName) ? formatter.name : formatter.chartShowName + result.push({ color: 'grey', name, value: `${value ?? ''}` }) + } + }) + return result + } + + /** + * 符号地图特殊处理,tooltip的配置可自定义显示内容 + * @param index + * @private + */ + private createSymbolicMapPopup(index): void { + const buildTooltip = () => { + const customAttr = this.chart.customAttr ? parseJson(this.chart.customAttr) : null + if (customAttr?.tooltip?.show) { + if (!this.popup) { + return undefined + } + const { tooltip } = deepCopy(customAttr) + let showFields = tooltip.showFields || [] + if (!tooltip.showFields || tooltip.showFields.length === 0) { + showFields = [ + ...this.chart.xAxisExt.map(i => `${i.dataeaseName}@${i.name}`), + ...this.chart.xAxis.map(i => `${i.dataeaseName}@${i.name}`) + ] + } + const style = document.createElement('style') + style.id = 'style-' + this.chart.container + style.innerHTML = ` + #${this.chart.container} .l7-popup-content { + background-color: ${tooltip.backgroundColor} !important; + padding: 6px 10px 6px; + line-height: 1.6; + } + #${this.chart.container} .l7-popup-tip { + border-top-color: ${tooltip.backgroundColor} !important; + } + ` + document.head.appendChild(style) + const lngField = this.chart.xAxis[0].dataeaseName + const latField = this.chart.xAxis[1].dataeaseName + const htmlPrefix = `
    ` + const htmlSuffix = '
    ' + const data = this.view.sourceOption.data[index] + if (data && data.details?.length) { + const fieldData = { + ...data, + ...Object.fromEntries(mergeDetailsToMap(data.details)) + } + const content = buildTooltipContent(tooltip, fieldData, showFields) + const html = `${htmlPrefix}${content}${htmlSuffix}` + this.popup.setLngLat({ + lng: data[lngField], + lat: data[latField] + }) + this.popup.setHTML(html) + this.popup.closeButton = false + this.scene.addPopup(this.popup) + this.popup.addTo(this.scene) + const { _id } = this.scene + .getLayers() + ?.find(i => i.type === 'PointLayer') + ?.layerSource.data.dataArray.find(i => { + const targetLng = this.data[index][lngField] + const targetLat = this.data[index][latField] + return i[lngField] === targetLng && i[latField] === targetLat + }) + this.scene + .getLayers() + ?.find(i => i.type === 'PointLayer' && i.coordCenter) + ?.setActive(_id, { color: 'rgba(30,90,255,1)' }) + } + } + return undefined + } + + /** + * 构建 tooltip 内容 + * @param tooltip + * @param fieldData + * @param showFields + * @returns {string} + */ + const buildTooltipContent = (tooltip, fieldData, showFields) => { + let content = '' + if (tooltip.customContent) { + content = tooltip.customContent + showFields.forEach(field => { + content = content.replace(`\${${field.split('@')[1]}}`, fieldData[field.split('@')[0]]) + }) + } else { + showFields.forEach(field => { + content += `${field.split('@')[1]}: ${ + fieldData[field.split('@')[0]] + }
    ` + }) + } + return content.replace(/\n/g, '
    ') + } + /** + * 合并详情到 map + * @param details + * @returns {Map} + */ + const mergeDetailsToMap = details => { + const resultMap = new Map() + details.forEach(item => { + Object.entries(item).forEach(([key, value]) => { + if (resultMap.has(key)) { + const existingValue = resultMap.get(key) + if (existingValue !== value) { + resultMap.set(key, `${existingValue}, ${value}`) + } + } else { + resultMap.set(key, value) + } + }) + }) + return resultMap + } + buildTooltip() + } +} diff --git a/frontend/src/data-visualization/chart/components/js/panel/charts/others/chart-mix-common.ts b/frontend/src/data-visualization/chart/components/js/panel/charts/others/chart-mix-common.ts new file mode 100644 index 0000000..403f47c --- /dev/null +++ b/frontend/src/data-visualization/chart/components/js/panel/charts/others/chart-mix-common.ts @@ -0,0 +1,119 @@ +import { DEFAULT_BASIC_STYLE } from '@/data-visualization/chart/components/editor/util/chart' + +export const CHART_MIX_EDITOR_PROPERTY: EditorProperty[] = [ + 'background-overall-component', + 'border-style', + 'dual-basic-style-selector', + 'x-axis-selector', + 'dual-y-axis-selector', + 'title-selector', + 'legend-selector', + 'label-selector', + 'tooltip-selector', + 'assist-line', + 'function-cfg', + 'jump-set', + 'linkage' +] +export const CHART_MIX_EDITOR_PROPERTY_INNER: EditorPropertyInner = { + 'background-overall-component': ['all'], + 'border-style': ['all'], + 'label-selector': ['fontSize', 'color'], + 'tooltip-selector': ['fontSize', 'color', 'backgroundColor', 'show'], + 'dual-basic-style-selector': [ + 'colors', + 'alpha', + 'gradient', + 'lineWidth', + 'lineSymbol', + 'lineSymbolSize', + 'lineSmooth', + 'radiusColumnBar', + 'subSeriesColor', + 'seriesColor', + 'columnWidthRatio' + ], + 'x-axis-selector': [ + 'name', + 'color', + 'fontSize', + 'position', + 'axisLabel', + 'axisLine', + 'splitLine' + ], + 'dual-y-axis-selector': [ + 'name', + 'color', + 'fontSize', + 'axisLabel', + 'axisLine', + 'splitLine', + 'axisValue', + 'axisLabelFormatter' + ], + 'title-selector': [ + 'title', + 'fontSize', + 'color', + 'hPosition', + 'isItalic', + 'isBolder', + 'remarkShow', + 'fontFamily', + 'letterSpace', + 'fontShadow' + ], + 'legend-selector': ['icon', 'orient', 'fontSize', 'color', 'hPosition', 'vPosition'], + 'function-cfg': ['emptyDataStrategy'] +} + +export const CHART_MIX_AXIS_TYPE: AxisType[] = [ + 'xAxis', + 'yAxis', + 'drill', + 'filter', + 'extLabel', + 'extTooltip' +] + +export const CHART_MIX_DEFAULT_BASIC_STYLE = { + ...DEFAULT_BASIC_STYLE, + subAlpha: 100, + subColorScheme: 'fast', + subSeriesColor: [], + subColors: [ + '#fae800', + '#00c039', + '#0482dc', + '#bb9581', + '#ff7701', + '#9c5ec3', + '#00ccdf', + '#00c039', + '#ff7701' + ], + leftLineWidth: 2, + leftLineSymbol: 'circle', + leftLineSymbolSize: 4, + leftLineSmooth: true +} + +export interface MixChartBasicStyle extends ChartBasicStyle { + subAlpha: number + subColors: string[] + subSeriesColor: { + /** + * 序列识别id,多指标就是轴id,分组或者堆叠就是类别值 + */ + id: string + /** + * 显示名称 + */ + name: string + /** + * 序列颜色 + */ + color: string + }[] +} diff --git a/frontend/src/data-visualization/chart/components/js/panel/charts/others/chart-mix.ts b/frontend/src/data-visualization/chart/components/js/panel/charts/others/chart-mix.ts new file mode 100644 index 0000000..0d2627a --- /dev/null +++ b/frontend/src/data-visualization/chart/components/js/panel/charts/others/chart-mix.ts @@ -0,0 +1,1006 @@ +import { + G2PlotChartView, + G2PlotDrawOptions +} from '@/data-visualization/chart/components/js/panel/types/impl/g2plot' +import type { DualAxes, DualAxesOptions } from '@antv/g2plot/esm/plots/dual-axes' +import { + configPlotTooltipEvent, + getAnalyse, + getLabel, + getPadding, + getTooltipContainer, + getYAxis, + getYAxisExt, + setGradientColor, + TOOLTIP_TPL +} from '../../common/common_antv' +import { flow, hexColorToRGBA, parseJson } from '@/data-visualization/chart/components/js/util' +import { + cloneDeep, + isEmpty, + defaultTo, + map, + filter, + union, + defaultsDeep, + defaults +} from 'lodash-es' +import { valueFormatter } from '@/data-visualization/chart/components/js/formatter' +import { + CHART_MIX_AXIS_TYPE, + CHART_MIX_DEFAULT_BASIC_STYLE, + CHART_MIX_EDITOR_PROPERTY, + CHART_MIX_EDITOR_PROPERTY_INNER, + MixChartBasicStyle +} from './chart-mix-common' +import type { Datum } from '@antv/g2plot/esm/types/common' +import { useI18n } from '@/data-visualization/hooks/web/useI18n' +import { + DEFAULT_BASIC_STYLE, + DEFAULT_LABEL, + DEFAULT_LEGEND_STYLE +} from '@/data-visualization/chart/components/editor/util/chart' +import type { Options } from '@antv/g2plot/esm' +import { Group } from '@antv/g-canvas' + +const { t } = useI18n() +const DEFAULT_DATA = [] + +/** + * 柱线混合图 + */ +export class ColumnLineMix extends G2PlotChartView { + properties = CHART_MIX_EDITOR_PROPERTY + propertyInner = { + ...CHART_MIX_EDITOR_PROPERTY_INNER, + 'label-selector': ['vPosition', 'seriesLabelFormatter'], + 'tooltip-selector': [ + ...CHART_MIX_EDITOR_PROPERTY_INNER['tooltip-selector'], + 'seriesTooltipFormatter' + ] + } + axis: AxisType[] = [...CHART_MIX_AXIS_TYPE, 'xAxisExtRight', 'yAxisExt'] + axisConfig = { + xAxis: { + name: `${t('chart.drag_block_type_axis')} / ${t('chart.dimension')}`, + type: 'd' + }, + yAxis: { + name: `${t('chart.drag_block_value_axis_left')} / ${t('chart.column_quota')}`, + limit: 1, + type: 'q' + }, + extBubble: { + //用这个字段存放右轴分类 + name: `${t('chart.drag_block_type_axis_right')} / ${t('chart.dimension')}`, + limit: 1, + type: 'd', + allowEmpty: true + }, + yAxisExt: { + name: `${t('chart.drag_block_value_axis_right')} / ${t('chart.line_quota')}`, + limit: 1, + type: 'q', + allowEmpty: true + } + } + + protected getLeftType(): string { + return 'column' + } + protected getRightType(): string { + return 'line' + } + + async drawChart(drawOptions: G2PlotDrawOptions): Promise { + const { chart, action, container } = drawOptions + if (!chart.data?.left?.data?.length && !chart.data?.right?.data?.length) { + return + } + const left = cloneDeep(chart.data?.left?.data) + const right = cloneDeep(chart.data?.right?.data) + + // const data1Type = (left[0]?.type === 'bar' ? 'column' : left[0]?.type) ?? 'column' + // const data2Type = (right[0]?.type === 'bar' ? 'column' : right[0]?.type) ?? 'column' + const data1Type = this.getLeftType() + const data2Type = this.getRightType() + + const isGroup = this.name === 'chart-mix-group' && chart.xAxisExt?.length > 0 + const isStack = this.name === 'chart-mix-stack' && chart.extStack?.length > 0 + const seriesField = 'category' + const seriesField2 = 'category' + + const data1 = defaultTo(left[0]?.data, []) + const data2 = map(defaultTo(right[0]?.data, []), d => { + return { + ...d, + valueExt: d.value + } + }) + + // options + const initOptions: DualAxesOptions = { + data: [data1, data2], + xField: 'field', + yField: ['value', 'valueExt'], //这里不能设置成一样的 + appendPadding: getPadding(chart), + geometryOptions: [ + { + geometry: data1Type, + color: [], + isGroup: isGroup, + isStack: isStack, + seriesField: seriesField + }, + { + geometry: data2Type, + color: [], + seriesField: seriesField2 + } + ], + interactions: [ + { + type: 'legend-active', + cfg: { + start: [{ trigger: 'legend-item:mouseenter', action: ['element-active:reset'] }], + end: [{ trigger: 'legend-item:mouseleave', action: ['element-active:reset'] }] + } + }, + { + type: 'legend-filter', + cfg: { + start: [ + { + trigger: 'legend-item:click', + action: [ + 'list-unchecked:toggle', + 'data-filter:filter', + 'element-active:reset', + 'element-highlight:reset' + ] + } + ] + } + }, + { + type: 'active-region' + } + ] + } + const options = this.setupOptions(chart, initOptions) + const { DualAxes } = await import('@antv/g2plot/esm/plots/dual-axes') + // 开始渲染 + const newChart = new DualAxes(container, options) + + newChart.on('point:click', action) + newChart.on('interval:click', action) + configPlotTooltipEvent(chart, newChart) + return newChart + } + + protected configLabel(chart: Chart, options: DualAxesOptions): DualAxesOptions { + const tempLabel = getLabel(chart) + const tmpOption = { ...options } + if (!tempLabel) { + if (tmpOption.geometryOptions) { + tmpOption.geometryOptions[0].label = false + tmpOption.geometryOptions[1].label = false + } + return tmpOption + } + + const labelAttr = parseJson(chart.customAttr).label + const axisFormatterMap = {} + labelAttr.seriesLabelFormatter?.forEach(attr => { + if (!axisFormatterMap[attr.axisType]) { + axisFormatterMap[attr.axisType] = [] + } + axisFormatterMap[attr.axisType].push(attr) + }) + const axisTypes = ['yAxis', 'yAxisExt'] + axisTypes.forEach(axisType => { + const formatterMap = axisFormatterMap[axisType]?.reduce((pre, next) => { + pre[next.id] = next + return pre + }, {}) + tempLabel.style.fill = DEFAULT_LABEL.color + const label = { + fields: [], + ...tempLabel, + offsetY: -8, + formatter: (data: Datum) => { + if (!labelAttr.seriesLabelFormatter?.length) { + return data.value + } + const labelCfg = formatterMap?.[data.quotaList[0].id] as SeriesFormatter + if (!labelCfg) { + return data.value + } + if (!labelCfg.show) { + return + } + const value = valueFormatter(data.value, labelCfg.formatterCfg) + const group = new Group({}) + group.addShape({ + type: 'text', + attrs: { + x: 0, + y: 0, + text: value, + textAlign: 'start', + textBaseline: 'top', + fontSize: labelCfg.fontSize, + fontFamily: chart.fontFamily, + fill: labelCfg.color + } + }) + return group + } + } + if (tmpOption.geometryOptions) { + if (axisType === 'yAxis') { + tmpOption.geometryOptions[0].label = label + } else if (axisType === 'yAxisExt') { + tmpOption.geometryOptions[1].label = label + } + } + }) + + return tmpOption + } + + protected configBasicStyle(chart: Chart, options: DualAxesOptions): DualAxesOptions { + // size + const customAttr: DeepPartial = parseJson(chart.customAttr) + const s = defaultsDeep( + JSON.parse(JSON.stringify(customAttr.basicStyle)), + CHART_MIX_DEFAULT_BASIC_STYLE + ) + const smooth = s.lineSmooth + const point = { + size: s.lineSymbolSize, + shape: s.lineSymbol, + style: { + stroke: hexColorToRGBA('#FFFFFF', s.subAlpha) + } + } + const lineStyle = { + lineWidth: s.lineWidth + } + const leftSmooth = s.leftLineSmooth + const leftPoint = { + size: s.leftLineSymbolSize, + shape: s.leftLineSymbol, + style: { + stroke: hexColorToRGBA('#FFFFFF', s.alpha) + } + } + const leftLineStyle = { + lineWidth: s.leftLineWidth + } + const tempOption = { + ...options, + smooth, + point, + lineStyle + } + if (tempOption.geometryOptions) { + tempOption.geometryOptions[0].smooth = leftSmooth + tempOption.geometryOptions[0].point = leftPoint + tempOption.geometryOptions[0].lineStyle = leftLineStyle + + tempOption.geometryOptions[1].smooth = smooth + tempOption.geometryOptions[1].point = point + tempOption.geometryOptions[1].lineStyle = lineStyle + + if (s.radiusColumnBar === 'roundAngle') { + const columnStyle = { + radius: [ + s.columnBarRightAngleRadius, + s.columnBarRightAngleRadius, + s.columnBarRightAngleRadius, + s.columnBarRightAngleRadius + ] + } + tempOption.geometryOptions[0].columnStyle = columnStyle + tempOption.geometryOptions[1].columnStyle = columnStyle + } + } + + let columnWidthRatio + const _v = s.columnWidthRatio ?? DEFAULT_BASIC_STYLE.columnWidthRatio + if (_v >= 1 && _v <= 100) { + columnWidthRatio = _v / 100.0 + } else if (_v < 1) { + columnWidthRatio = 1 / 100.0 + } else if (_v > 100) { + columnWidthRatio = 1 + } + if (columnWidthRatio) { + tempOption.geometryOptions[0].columnWidthRatio = columnWidthRatio + } + + if (super.name !== 'chart-mix-dual-line') { + tempOption.geometryOptions[0].appendPadding = getPadding(chart) + } + + return tempOption + } + + setupDefaultOptions(chart: ChartObj): ChartObj { + const { customAttr, senior } = chart + if ( + senior.functionCfg.emptyDataStrategy == undefined || + senior.functionCfg.emptyDataStrategy === 'ignoreData' + ) { + senior.functionCfg.emptyDataStrategy = 'breakLine' + } + return chart + } + + protected configCustomColors(chart: Chart, options: DualAxesOptions): DualAxesOptions { + const tempOption = { + ...options + } + const basicStyle = parseJson(chart.customAttr).basicStyle as MixChartBasicStyle + + const { seriesColor } = basicStyle + if (seriesColor?.length) { + const seriesMap = seriesColor.reduce((p, n) => { + p[n.id] = n + return p + }, {}) + const { yAxis } = chart + yAxis?.forEach((axis, index) => { + const curAxisColor = seriesMap[axis.id] + if (curAxisColor) { + if (index + 1 > basicStyle.colors.length) { + basicStyle.colors.push(curAxisColor.color) + } else { + basicStyle.colors[index] = curAxisColor.color + } + } + }) + } + //左轴 + const color = basicStyle.colors.map(ele => { + const tmp = hexColorToRGBA(ele, basicStyle.alpha) + if (basicStyle.gradient) { + return setGradientColor(tmp, true, 270) + } else { + return tmp + } + }) + tempOption.geometryOptions[0].color = color + + return tempOption + } + + protected configSubCustomColors(chart: Chart, options: DualAxesOptions): DualAxesOptions { + const tempOption = { + ...options + } + const basicStyle = defaultsDeep( + parseJson(chart.customAttr).basicStyle as MixChartBasicStyle, + cloneDeep(CHART_MIX_DEFAULT_BASIC_STYLE) + ) + //右轴 + const { subSeriesColor } = basicStyle + if (subSeriesColor?.length) { + const { yAxisExt, extBubble } = chart + const seriesMap = subSeriesColor.reduce((p, n) => { + p[n.id] = n + return p + }, {}) + const { data } = options as unknown as Options + if (extBubble?.length) { + const seriesSet = new Set() + data[1]?.forEach(d => d.category !== null && seriesSet.add(d.category)) + const tmp = [...seriesSet] + tmp.forEach((c, i) => { + const curAxisColor = seriesMap[c as string] + if (curAxisColor) { + if (i + 1 > basicStyle.subColors.length) { + basicStyle.subColors.push(curAxisColor.color) + } else { + basicStyle.subColors[i] = curAxisColor.color + } + } + }) + } else { + yAxisExt?.forEach((axis, index) => { + const curAxisColor = seriesMap[axis.id] + if (curAxisColor) { + if (index + 1 > basicStyle.subColors.length) { + basicStyle.subColors.push(curAxisColor.color) + } else { + basicStyle.subColors[index] = curAxisColor.color + } + } + }) + } + } + const subColor = basicStyle.subColors.map(c => { + const cc = hexColorToRGBA(c, basicStyle.subAlpha) + return cc + }) + tempOption.geometryOptions[1].color = subColor + + return tempOption + } + + public setupSubSeriesColor(chart: ChartObj, data?: any[]): ChartBasicStyle['seriesColor'] { + const result: ChartBasicStyle['seriesColor'] = [] + const seriesSet = new Set() + const colors = chart.customAttr.basicStyle.subColors ?? CHART_MIX_DEFAULT_BASIC_STYLE.subColors + const { yAxisExt, extBubble } = chart + if (extBubble?.length) { + data?.forEach(d => { + if (d.value === null || d.category === null || seriesSet.has(d.category)) { + return + } + seriesSet.add(d.category) + result.push({ + id: d.category, + name: d.category, + color: colors[(seriesSet.size - 1) % colors.length] + }) + }) + } else { + yAxisExt?.forEach(axis => { + if (seriesSet.has(axis.id)) { + return + } + seriesSet.add(axis.id) + result.push({ + id: axis.id, + name: axis.chartShowName ?? axis.name, + color: colors[(seriesSet.size - 1) % colors.length] + }) + }) + } + return result + } + + protected configYAxis(chart: Chart, options: DualAxesOptions): DualAxesOptions { + const yAxis = getYAxis(chart) + const yAxisExt = getYAxisExt(chart) + + const tempOption = { + ...options + } + + tempOption.yAxis = {} + if (!yAxis) { + //左右轴都要隐藏 + tempOption.yAxis.value = false + } else { + tempOption.yAxis.value = undefined + yAxis.position = 'left' + + const yAxisTmp = parseJson(chart.customStyle).yAxis + if (yAxis.label) { + yAxis.label.style.textAlign = 'end' + yAxis.label.formatter = value => { + return valueFormatter(value, yAxisTmp.axisLabelFormatter) + } + } + const axisValue = yAxisTmp.axisValue + if (!axisValue?.auto) { + tempOption.yAxis.value = { + ...yAxis, + min: axisValue.min, + max: axisValue.max, + minLimit: axisValue.min, + maxLimit: axisValue.max, + tickCount: axisValue.splitCount + } + } else { + tempOption.yAxis.value = yAxis + } + } + + if (!yAxisExt) { + //左右轴都要隐藏 + tempOption.yAxis.valueExt = false + } else { + tempOption.yAxis.valueExt = undefined + yAxisExt.position = 'right' + + const yAxisExtTmp = parseJson(chart.customStyle).yAxisExt + if (yAxisExt.label) { + yAxisExt.label.style.textAlign = 'start' + yAxisExt.label.formatter = value => { + return valueFormatter(value, yAxisExtTmp.axisLabelFormatter) + } + } + const axisExtValue = yAxisExtTmp.axisValue + if (!axisExtValue?.auto) { + tempOption.yAxis.valueExt = { + ...yAxisExt, + min: axisExtValue.min, + max: axisExtValue.max, + minLimit: axisExtValue.min, + maxLimit: axisExtValue.max, + tickCount: axisExtValue.splitCount + } + } else { + tempOption.yAxis.valueExt = yAxisExt + } + } + + return tempOption + } + + protected configTooltip(chart: Chart, options: DualAxesOptions): DualAxesOptions { + const customAttr: DeepPartial = parseJson(chart.customAttr) + const tooltipAttr = customAttr.tooltip + if (!tooltipAttr.show) { + return { + ...options, + tooltip: false + } + } + const formatterMap = tooltipAttr.seriesTooltipFormatter + ?.filter(i => i.show) + .reduce((pre, next) => { + pre[next.id] = next + return pre + }, {}) as Record + const tooltip: DualAxesOptions['tooltip'] = { + shared: true, + showTitle: true, + customItems(originalItems) { + if (!tooltipAttr.seriesTooltipFormatter?.length) { + return originalItems + } + const head = originalItems[0] + // 非原始数据 + if (!head.data.quotaList) { + return originalItems + } + const result = [] + originalItems + .filter(item => formatterMap[item.data.quotaList[0].id]) + .forEach(item => { + const formatter = formatterMap[item.data.quotaList[0].id] + const value = valueFormatter(parseFloat(item.value as string), formatter.formatterCfg) + const name = item.data.category + + result.push({ ...item, name, value }) + }) + head.data.dynamicTooltipValue?.forEach(item => { + const formatter = formatterMap[item.fieldId] + if (formatter) { + const value = valueFormatter(parseFloat(item.value), formatter.formatterCfg) + const name = isEmpty(formatter.chartShowName) ? formatter.name : formatter.chartShowName + result.push({ color: 'grey', name, value }) + } + }) + return result + }, + container: getTooltipContainer(`tooltip-${chart.id}`), + itemTpl: TOOLTIP_TPL, + enterable: true + } + return { + ...options, + tooltip + } + } + + protected configLegend(chart: Chart, options: DualAxesOptions): DualAxesOptions { + const o = super.configLegend(chart, options) + if (o.legend) { + const left = cloneDeep(chart.data?.left?.data) + const right = cloneDeep(chart.data?.right?.data) + + o.legend.itemName.formatter = (text: string, item: any, index: number) => { + let name = undefined + if (item.viewId === 'left-axes-view' && text === 'value') { + name = left[0]?.categories[0] + } else if (item.viewId === 'right-axes-view' && text === 'valueExt') { + name = right[0]?.categories[0] + } + item.id = item.id + '__' + index //防止重复的图例出现问题,但是左右轴如果有相同的怎么办 + if (name === undefined) { + return text + } else { + return name + } + } + + const customStyle = parseJson(chart.customStyle) + let size + if (customStyle && customStyle.legend) { + size = defaults(JSON.parse(JSON.stringify(customStyle.legend)), DEFAULT_LEGEND_STYLE).size + } else { + size = DEFAULT_LEGEND_STYLE.size + } + + o.legend.marker.style = style => { + const fill = style.fill ?? style.stroke + return { + r: size, + fill + } + } + } + return o + } + + protected configAnalyse(chart: Chart, options: DualAxesOptions): DualAxesOptions { + chart.data.dynamicAssistLines = union( + defaultTo(chart.data?.left?.dynamicAssistLines, []), + defaultTo(chart.data?.right?.dynamicAssistLines, []) + ) + const list = getAnalyse(chart) + const annotations = { + value: filter(list, l => l.yAxisType === 'left'), + valueExt: filter(list, l => l.yAxisType === 'right') + } + return { ...options, annotations } + } + + protected setupOptions(chart: Chart, options: DualAxesOptions): DualAxesOptions { + return flow( + this.configTheme, + this.configLabel, + this.configTooltip, + this.configBasicStyle, + this.configCustomColors, + this.configSubCustomColors, + this.configLegend, + this.configXAxis, + this.configYAxis, + this.configAnalyse, + this.configEmptyDataStrategy + )(chart, options) + } + + constructor(name = 'chart-mix') { + super(name, DEFAULT_DATA) + } +} + +export class GroupColumnLineMix extends ColumnLineMix { + axis: AxisType[] = [...this['axis'], 'xAxisExt'] + propertyInner = { + ...CHART_MIX_EDITOR_PROPERTY_INNER, + 'label-selector': ['vPosition', 'seriesLabelFormatter'], + 'tooltip-selector': [ + ...CHART_MIX_EDITOR_PROPERTY_INNER['tooltip-selector'], + 'seriesTooltipFormatter' + ] + } + axisConfig = { + ...this['axisConfig'], + xAxisExt: { + name: `${t('chart.chart_group')} / ${t('chart.dimension')}`, + type: 'd', + limit: 1, + allowEmpty: true + } + } + + protected configCustomColors(chart: Chart, options: DualAxesOptions): DualAxesOptions { + const tempOption = { + ...options + } + const basicStyle = parseJson(chart.customAttr).basicStyle as MixChartBasicStyle + + const { seriesColor } = basicStyle + if (seriesColor?.length) { + const seriesMap = seriesColor.reduce((p, n) => { + p[n.id] = n + return p + }, {}) + const { yAxis, xAxisExt } = chart + const { data } = options as unknown as Options + if (xAxisExt?.length) { + const seriesSet = new Set() + data[0]?.forEach(d => d.category !== null && seriesSet.add(d.category)) + const tmp = [...seriesSet] + tmp.forEach((c, i) => { + const curAxisColor = seriesMap[c as string] + if (curAxisColor) { + if (i + 1 > basicStyle.colors.length) { + basicStyle.colors.push(curAxisColor.color) + } else { + basicStyle.colors[i] = curAxisColor.color + } + } + }) + } else { + yAxis?.forEach((axis, index) => { + const curAxisColor = seriesMap[axis.id] + if (curAxisColor) { + if (index + 1 > basicStyle.colors.length) { + basicStyle.colors.push(curAxisColor.color) + } else { + basicStyle.colors[index] = curAxisColor.color + } + } + }) + } + } + //左轴 + const color = basicStyle.colors.map(ele => { + const tmp = hexColorToRGBA(ele, basicStyle.alpha) + if (basicStyle.gradient) { + return setGradientColor(tmp, true, 270) + } else { + return tmp + } + }) + tempOption.geometryOptions[0].color = color + + return tempOption + } + + public setupSeriesColor(chart: ChartObj, data?: any[]): ChartBasicStyle['seriesColor'] { + const result: ChartBasicStyle['seriesColor'] = [] + const seriesSet = new Set() + const colors = chart.customAttr.basicStyle.colors + const { yAxis, xAxisExt } = chart + if (xAxisExt?.length) { + data?.forEach(d => { + if (d.value === null || d.category === null || seriesSet.has(d.category)) { + return + } + seriesSet.add(d.category) + result.push({ + id: d.category, + name: d.category, + color: colors[(seriesSet.size - 1) % colors.length] + }) + }) + } else { + yAxis?.forEach(axis => { + if (seriesSet.has(axis.id)) { + return + } + seriesSet.add(axis.id) + result.push({ + id: axis.id, + name: axis.chartShowName ?? axis.name, + color: colors[(seriesSet.size - 1) % colors.length] + }) + }) + } + return result + } + + constructor(name = 'chart-mix-group') { + super(name) + } +} +export class StackColumnLineMix extends ColumnLineMix { + axis: AxisType[] = [...this['axis'], 'extStack'] + propertyInner = { + ...CHART_MIX_EDITOR_PROPERTY_INNER, + 'label-selector': ['vPosition', 'seriesLabelFormatter'], + 'tooltip-selector': [ + ...CHART_MIX_EDITOR_PROPERTY_INNER['tooltip-selector'], + 'seriesTooltipFormatter' + ] + } + axisConfig = { + ...this['axisConfig'], + extStack: { + name: `${t('chart.stack_item')} / ${t('chart.dimension')}`, + type: 'd', + limit: 1, + allowEmpty: true + } + } + + protected configCustomColors(chart: Chart, options: DualAxesOptions): DualAxesOptions { + const tempOption = { + ...options + } + const basicStyle = parseJson(chart.customAttr).basicStyle as MixChartBasicStyle + + const { seriesColor } = basicStyle + if (seriesColor?.length) { + const seriesMap = seriesColor.reduce((p, n) => { + p[n.id] = n + return p + }, {}) + const { yAxis, extStack } = chart + const { data } = options as unknown as Options + if (extStack?.length) { + const seriesSet = new Set() + data[0]?.forEach(d => d.category !== null && seriesSet.add(d.category)) + const tmp = [...seriesSet] + tmp.forEach((c, i) => { + const curAxisColor = seriesMap[c as string] + if (curAxisColor) { + if (i + 1 > basicStyle.colors.length) { + basicStyle.colors.push(curAxisColor.color) + } else { + basicStyle.colors[i] = curAxisColor.color + } + } + }) + } else { + yAxis?.forEach((axis, index) => { + const curAxisColor = seriesMap[axis.id] + if (curAxisColor) { + if (index + 1 > basicStyle.colors.length) { + basicStyle.colors.push(curAxisColor.color) + } else { + basicStyle.colors[index] = curAxisColor.color + } + } + }) + } + } + //左轴 + const color = basicStyle.colors.map(ele => { + const tmp = hexColorToRGBA(ele, basicStyle.alpha) + if (basicStyle.gradient) { + return setGradientColor(tmp, true, 270) + } else { + return tmp + } + }) + tempOption.geometryOptions[0].color = color + + return tempOption + } + + public setupSeriesColor(chart: ChartObj, data?: any[]): ChartBasicStyle['seriesColor'] { + const result: ChartBasicStyle['seriesColor'] = [] + const seriesSet = new Set() + const colors = chart.customAttr.basicStyle.colors + const { yAxis, extStack } = chart + if (extStack?.length) { + data?.forEach(d => { + if (d.value === null || d.category === null || seriesSet.has(d.category)) { + return + } + seriesSet.add(d.category) + result.push({ + id: d.category, + name: d.category, + color: colors[(seriesSet.size - 1) % colors.length] + }) + }) + } else { + yAxis?.forEach(axis => { + if (seriesSet.has(axis.id)) { + return + } + seriesSet.add(axis.id) + result.push({ + id: axis.id, + name: axis.chartShowName ?? axis.name, + color: colors[(seriesSet.size - 1) % colors.length] + }) + }) + } + return result + } + + constructor(name = 'chart-mix-stack') { + super(name) + } +} + +export class DualLineMix extends ColumnLineMix { + axis: AxisType[] = [...this['axis'], 'xAxisExt'] + propertyInner = { + ...CHART_MIX_EDITOR_PROPERTY_INNER, + 'label-selector': ['seriesLabelFormatter'], + 'tooltip-selector': [ + ...CHART_MIX_EDITOR_PROPERTY_INNER['tooltip-selector'], + 'seriesTooltipFormatter' + ] + } + axisConfig = { + ...this['axisConfig'], + xAxisExt: { + name: `${t('chart.drag_block_type_axis_left')} / ${t('chart.dimension')}`, + type: 'd', + limit: 1, + allowEmpty: true + } + } + + protected getLeftType(): string { + return 'line' + } + + protected configCustomColors(chart: Chart, options: DualAxesOptions): DualAxesOptions { + const tempOption = { + ...options + } + const basicStyle = parseJson(chart.customAttr).basicStyle as MixChartBasicStyle + + const { seriesColor } = basicStyle + if (seriesColor?.length) { + const seriesMap = seriesColor.reduce((p, n) => { + p[n.id] = n + return p + }, {}) + const { yAxis, xAxisExt } = chart + const { data } = options as unknown as Options + if (xAxisExt?.length) { + const seriesSet = new Set() + data[0]?.forEach(d => d.category !== null && seriesSet.add(d.category)) + const tmp = [...seriesSet] + tmp.forEach((c, i) => { + const curAxisColor = seriesMap[c as string] + if (curAxisColor) { + if (i + 1 > basicStyle.colors.length) { + basicStyle.colors.push(curAxisColor.color) + } else { + basicStyle.colors[i] = curAxisColor.color + } + } + }) + } else { + yAxis?.forEach((axis, index) => { + const curAxisColor = seriesMap[axis.id] + if (curAxisColor) { + if (index + 1 > basicStyle.colors.length) { + basicStyle.colors.push(curAxisColor.color) + } else { + basicStyle.colors[index] = curAxisColor.color + } + } + }) + } + } + //左轴 + const color = basicStyle.colors.map(ele => { + const tmp = hexColorToRGBA(ele, basicStyle.alpha) + if (basicStyle.gradient) { + return setGradientColor(tmp, true, 270) + } else { + return tmp + } + }) + tempOption.geometryOptions[0].color = color + + return tempOption + } + + public setupSeriesColor(chart: ChartObj, data?: any[]): ChartBasicStyle['seriesColor'] { + const result: ChartBasicStyle['seriesColor'] = [] + const seriesSet = new Set() + const colors = chart.customAttr.basicStyle.colors + const { yAxis, xAxisExt } = chart + if (xAxisExt?.length) { + data?.forEach(d => { + if (d.value === null || d.category === null || seriesSet.has(d.category)) { + return + } + seriesSet.add(d.category) + result.push({ + id: d.category, + name: d.category, + color: colors[(seriesSet.size - 1) % colors.length] + }) + }) + } else { + yAxis?.forEach(axis => { + if (seriesSet.has(axis.id)) { + return + } + seriesSet.add(axis.id) + result.push({ + id: axis.id, + name: axis.chartShowName ?? axis.name, + color: colors[(seriesSet.size - 1) % colors.length] + }) + }) + } + return result + } + + constructor(name = 'chart-mix-dual-line') { + super(name) + } +} diff --git a/frontend/src/data-visualization/chart/components/js/panel/charts/others/circle-packing.ts b/frontend/src/data-visualization/chart/components/js/panel/charts/others/circle-packing.ts new file mode 100644 index 0000000..ab6bbad --- /dev/null +++ b/frontend/src/data-visualization/chart/components/js/panel/charts/others/circle-packing.ts @@ -0,0 +1,279 @@ +import { + G2PlotChartView, + G2PlotDrawOptions +} from '@/data-visualization/chart/components/js/panel/types/impl/g2plot' +import type { + CirclePacking as G2CirclePacking, + CirclePackingOptions +} from '@antv/g2plot/esm/plots/circle-packing' +import { flow, parseJson } from '@/data-visualization/chart/components/js/util' +import { getPadding } from '@/data-visualization/chart/components/js/panel/common/common_antv' +import { useI18n } from '@/data-visualization/hooks/web/useI18n' +import type { Datum } from '@antv/g2plot/esm/types/common' +import { valueFormatter } from '@/data-visualization/chart/components/js/formatter' +import { cloneDeep } from 'lodash-es' + +const { t } = useI18n() +const DEFAULT_DATA = [] +/** + * 圆形填充图 + */ +export class CirclePacking extends G2PlotChartView { + properties: EditorProperty[] = [ + 'basic-style-selector', + 'background-overall-component', + 'border-style', + 'label-selector', + 'legend-selector', + 'title-selector', + 'tooltip-selector', + 'jump-set', + 'linkage' + ] + propertyInner: EditorPropertyInner = { + 'background-overall-component': ['all'], + 'border-style': ['all'], + 'basic-style-selector': ['colors', 'alpha', 'circleBorderStyle'], + 'title-selector': [ + 'title', + 'fontSize', + 'color', + 'hPosition', + 'isItalic', + 'isBolder', + 'remarkShow', + 'fontFamily', + 'letterSpace', + 'fontShadow' + ], + 'function-cfg': ['emptyDataStrategy'], + 'label-selector': ['color', 'fontSize'], + 'legend-selector': ['icon', 'orient', 'fontSize', 'color', 'hPosition', 'vPosition'], + 'tooltip-selector': ['color', 'fontSize', 'backgroundColor', 'tooltipFormatter', 'show'] + } + axis: AxisType[] = ['xAxis', 'yAxis', 'filter', 'drill'] + axisConfig: AxisConfig = { + xAxis: { + name: `${t('chart.circle_packing_name')} / ${t('chart.dimension')}`, + type: 'd', + limit: 1 + }, + yAxis: { + name: `${t('chart.circle_packing_value')} / ${t('chart.quota')}`, + type: 'q', + limit: 1 + } + } + async drawChart(drawOptions: G2PlotDrawOptions): Promise { + const { chart, container, action } = drawOptions + if (chart?.data?.data?.length) { + // data + const data = chart.data.data + const { xAxis, yAxis, drillFields } = chart + const ySort = yAxis[0]?.sort ?? 'none' + const sort = { + sort: (a, b) => + ySort === 'asc' ? a.value - b.value : ySort === 'desc' ? b.value - a.value : 0 + } + // 将数据转为圆形填充图数据格式 + const getCirclePackingData = () => { + const result = [{ name: t('commons.all'), children: [] }] + const addNode = (nodes, item) => { + const node = { ...item, name: item.name, children: [] } + nodes.push(node) + } + data.forEach(item => addNode(result[0].children, item)) + return result[0] + } + // options + const initOptions: CirclePackingOptions = { + data: getCirclePackingData(), + appendPadding: getPadding(chart), + hierarchyConfig: { + ...(ySort === 'none' ? {} : sort) + }, + interactions: [ + { + type: 'legend-active', + cfg: { + start: [{ trigger: 'legend-item:mouseenter', action: ['element-active:reset'] }], + end: [{ trigger: 'legend-item:mouseleave', action: ['element-active:reset'] }] + } + }, + { + type: 'legend-filter', + cfg: { + start: [ + { + trigger: 'legend-item:click', + action: [ + 'list-unchecked:toggle', + 'data-filter:filter', + 'element-active:reset', + 'element-highlight:reset' + ] + } + ] + } + } + ] + } + const options = this.setupOptions(chart, initOptions) + const { CirclePacking: G2CirclePacking } = await import( + '@antv/g2plot/esm/plots/circle-packing' + ) + const newChart = new G2CirclePacking(container, options) + newChart.on('point:click', param => { + const pointData = param?.data?.data + if (pointData?.name === t('commons.all')) { + return + } + const actionParams = { + x: param.x, + y: param.y, + data: { + data: { + ...pointData + } + } + } + action(actionParams) + }) + return newChart + } + } + + protected configBasicStyle(chart: Chart, options: CirclePackingOptions): CirclePackingOptions { + // size + const customAttr: DeepPartial = parseJson(chart.customAttr) + const s = JSON.parse(JSON.stringify(customAttr.basicStyle)) + // 圆形边框样式 + const pointStyle = { + stroke: s.circleBorderColor, + lineWidth: s.circleBorderWidth ?? 0 + } + const padding = s.circlePadding + return { + ...options, + hierarchyConfig: { + ...options.hierarchyConfig, + padding: typeof padding === 'number' && !isNaN(padding) ? padding / 100 : 0 + }, + pointStyle + } + } + + protected configLabel(chart: Chart, options: CirclePackingOptions): CirclePackingOptions { + const tmpOptions = super.configLabel(chart, options) + if (!tmpOptions.label) { + return { + ...tmpOptions, + label: false + } + } + const { label: labelAttr } = parseJson(chart.customAttr) + const label = { + ...tmpOptions.label, + textAlign: 'center', + offsetY: 5, + layout: labelAttr.fullDisplay ? [{ type: 'limit-in-plot' }] : tmpOptions.label.layout, + formatter: (d: Datum, _point) => { + return d.children.length === 0 ? d.name : '' + } + } + return { + ...tmpOptions, + label + } + } + + protected configTooltip(chart: Chart, options: CirclePackingOptions): CirclePackingOptions { + const temOptions = super.configTooltip(chart, options) + if (!temOptions.tooltip) { + return temOptions + } + const tooltipAttr = parseJson(chart.customAttr).tooltip + return { + ...temOptions, + tooltip: { + ...temOptions, + fields: ['name', 'value'], + formatter: d => { + let value = d.value + if (tooltipAttr.tooltipFormatter) { + value = valueFormatter(value, tooltipAttr.tooltipFormatter) + } + return { name: d.name, value } + } + } + } + } + configEmptyDataStrategy(chart: Chart, options: CirclePackingOptions): CirclePackingOptions { + const { functionCfg } = parseJson(chart.senior) + const emptyDataStrategy = functionCfg.emptyDataStrategy + const setChildren = children => { + if (emptyDataStrategy === 'ignoreData') { + for (let i = children.length - 1; i >= 0; i--) { + let isNotNullChildren = [] + if (children[i].children?.length) { + isNotNullChildren = children[i].children.filter(item => item.value !== null) + } + if (children[i].children?.length && isNotNullChildren.length) { + setChildren(children[i].children) + } + if (children[i]?.hasOwnProperty('value') && children[i].value === null) { + children.splice(i, 1) + } + if (!children[i]?.hasOwnProperty('value') && isNotNullChildren.length === 0) { + children.splice(i, 1) + } + } + } else { + for (let i = children.length - 1; i >= 0; i--) { + let isNotNullChildren = [] + if (children[i].children?.length) { + isNotNullChildren = children[i].children.filter(item => item.value !== null) + if (!isNotNullChildren.length) { + children[i].children = [] + continue + } + } + setChildren(children[i].children) + } + } + } + const data = cloneDeep(options.data.children) + setChildren(data) + options.data.children = data + return options + } + setupDefaultOptions(chart: ChartObj): ChartObj { + const { customAttr, customStyle, senior } = chart + const { label, basicStyle } = customAttr + const { legend } = customStyle + senior.functionCfg.emptyDataStrategy = 'ignoreData' + customAttr.label = { + ...label, + show: true + } + legend.show = false + basicStyle.circleBorderWidth = 0 + basicStyle.circleBorderColor = '#fff' + basicStyle.circlePadding = 0 + return chart + } + protected setupOptions(chart: Chart, options: CirclePackingOptions): CirclePackingOptions { + return flow( + this.configTheme, + this.configEmptyDataStrategy, + this.configBasicStyle, + this.configLabel, + this.configTooltip, + this.configLegend + )(chart, options) + } + + constructor() { + super('circle-packing', DEFAULT_DATA) + } +} diff --git a/frontend/src/data-visualization/chart/components/js/panel/charts/others/funnel.ts b/frontend/src/data-visualization/chart/components/js/panel/charts/others/funnel.ts new file mode 100644 index 0000000..2120b69 --- /dev/null +++ b/frontend/src/data-visualization/chart/components/js/panel/charts/others/funnel.ts @@ -0,0 +1,215 @@ +import type { FunnelOptions, Funnel as G2Funnel } from '@antv/g2plot/esm/plots/funnel' +import { G2PlotChartView, G2PlotDrawOptions } from '../../types/impl/g2plot' +import { flow, parseJson, setUpSingleDimensionSeriesColor } from '@/data-visualization/chart/components/js/util' +import { configPlotTooltipEvent, getPadding } from '../../common/common_antv' +import { useI18n } from '@/data-visualization/hooks/web/useI18n' +import { Datum } from '@antv/g2plot/esm/types/common' +import { valueFormatter } from '@/data-visualization/chart/components/js/formatter' + +const { t } = useI18n() + +/** + * 漏斗图 + */ +export class Funnel extends G2PlotChartView { + properties: EditorProperty[] = [ + 'background-overall-component', + 'border-style', + 'basic-style-selector', + 'label-selector', + 'tooltip-selector', + 'title-selector', + 'legend-selector', + 'jump-set', + 'linkage' + ] + propertyInner: EditorPropertyInner = { + 'background-overall-component': ['all'], + 'border-style': ['all'], + 'basic-style-selector': ['colors', 'alpha', 'seriesColor'], + 'label-selector': ['fontSize', 'color', 'hPosition', 'showQuota', 'conversionTag'], + 'tooltip-selector': ['color', 'fontSize', 'backgroundColor', 'seriesTooltipFormatter', 'show'], + 'title-selector': [ + 'show', + 'title', + 'fontSize', + 'color', + 'hPosition', + 'isItalic', + 'isBolder', + 'remarkShow', + 'fontFamily', + 'letterSpace', + 'fontShadow' + ], + 'legend-selector': ['icon', 'orient', 'color', 'fontSize', 'hPosition', 'vPosition'] + } + axis: AxisType[] = ['xAxis', 'yAxis', 'filter', 'drill', 'extLabel', 'extTooltip'] + axisConfig: AxisConfig = { + xAxis: { + name: `${t('chart.drag_block_funnel_split')} / ${t('chart.dimension')}`, + type: 'd' + }, + yAxis: { + name: `${t('chart.drag_block_funnel_width')} / ${t('chart.quota')}`, + type: 'q', + limit: 1 + } + } + + async drawChart(drawOptions: G2PlotDrawOptions): Promise { + const { chart, container, action } = drawOptions + if (!chart.data?.data) { + return + } + const data = chart.data.data + const baseOptions: FunnelOptions = { + data, + xField: 'field', + yField: 'value', + appendPadding: getPadding(chart), + interactions: [ + { + type: 'legend-active', + cfg: { + start: [{ trigger: 'legend-item:mouseenter', action: ['element-active:reset'] }], + end: [{ trigger: 'legend-item:mouseleave', action: ['element-active:reset'] }] + } + }, + { + type: 'legend-filter', + cfg: { + start: [ + { + trigger: 'legend-item:click', + action: [ + 'list-unchecked:toggle', + 'data-filter:filter', + 'element-active:reset', + 'element-highlight:reset' + ] + } + ] + } + }, + { + type: 'tooltip', + cfg: { + start: [{ trigger: 'interval:mousemove', action: 'tooltip:show' }], + end: [{ trigger: 'interval:mouseleave', action: 'tooltip:hide' }] + } + } + ], + meta: { + field: { + type: 'cat' + } + } + } + const options = this.setupOptions(chart, baseOptions) + const { Funnel: G2Funnel } = await import('@antv/g2plot/esm/plots/funnel') + const newChart = new G2Funnel(container, options) + newChart.on('interval:click', action) + configPlotTooltipEvent(chart, newChart) + return newChart + } + + protected configLabel(chart: Chart, options: FunnelOptions): FunnelOptions { + let label + let conversionTag + let customAttr: DeepPartial + if (chart.customAttr) { + customAttr = parseJson(chart.customAttr) + const showQuota = customAttr.label.showQuota + const l = customAttr.label + if (customAttr.label?.show) { + // label + if (showQuota) { + const layout = [] + if (!l.fullDisplay) { + layout.push(...[{ type: 'hide-overlap' }, { type: 'limit-in-plot' }]) + } + label = { + position: l.position, + layout, + style: { + fill: l.color, + fontSize: l.fontSize + }, + formatter: function (param: Datum) { + return valueFormatter(param.value, l.quotaLabelFormatter) + } + } + const position = label.position + if (position === 'right') { + label.offsetX = -40 + } + } + // 转化率 + const conversionTagAtt = parseJson(chart.customAttr).label.conversionTag + if (conversionTagAtt && conversionTagAtt.show) { + conversionTag = { + style: { + fill: l.color, + fontSize: l.fontSize + }, + formatter: datum => { + if (!datum['$$conversion$$'][0]) { + return `${conversionTagAtt.text ?? ''} -` + } + const rate = ( + (datum['$$conversion$$'][1] / datum['$$conversion$$'][0]) * + 100 + ).toFixed(conversionTagAtt.precision) + return `${conversionTagAtt.text ?? ''} ${rate}%` + } + } + } + } + return { + ...options, + label, + conversionTag, + maxSize: conversionTag ? 0.8 : 1 + } + } + return options + } + + public setupSeriesColor(chart: ChartObj, data?: any[]): ChartBasicStyle['seriesColor'] { + return setUpSingleDimensionSeriesColor(chart, data) + } + protected setupOptions(chart: Chart, options: FunnelOptions): FunnelOptions { + return flow( + this.configTheme, + this.configSingleDimensionColor, + this.configLabel, + this.configMultiSeriesTooltip, + this.configLegend + )(chart, options) + } + setupDefaultOptions(chart: ChartObj): ChartObj { + const { customAttr, customStyle } = chart + const { label } = customAttr + if (!['left', 'middle', 'right'].includes(label.position)) { + label.position = 'middle' + } + customAttr.label = { + ...label, + show: true, + showQuota: true, + conversionTag: { + show: false, + precision: 2, + text: t('chart.conversion_rate') + } + } + const { legend } = customStyle + legend.show = false + return chart + } + + constructor() { + super('funnel', []) + } +} diff --git a/frontend/src/data-visualization/chart/components/js/panel/charts/others/gauge.ts b/frontend/src/data-visualization/chart/components/js/panel/charts/others/gauge.ts new file mode 100644 index 0000000..1a98729 --- /dev/null +++ b/frontend/src/data-visualization/chart/components/js/panel/charts/others/gauge.ts @@ -0,0 +1,350 @@ +import { + G2PlotChartView, + G2PlotDrawOptions +} from '@/data-visualization/chart/components/js/panel/types/impl/g2plot' +import type { Gauge as G2Gauge, GaugeOptions } from '@antv/g2plot/esm/plots/gauge' +import { flow, parseJson } from '@/data-visualization/chart/components/js/util' +import { + DEFAULT_LABEL, + DEFAULT_MISC, + DEFAULT_THRESHOLD, + getScaleValue +} from '@/data-visualization/chart/components/editor/util/chart' +import { valueFormatter } from '@/data-visualization/chart/components/js/formatter' +import { getPadding, setGradientColor } from '@/data-visualization/chart/components/js/panel/common/common_antv' +import { useI18n } from '@/data-visualization/hooks/web/useI18n' +import { merge } from 'lodash-es' + +const { t } = useI18n() + +const DEFAULT_DATA = [] +export class Gauge extends G2PlotChartView { + properties: EditorProperty[] = [ + 'background-overall-component', + 'border-style', + 'basic-style-selector', + 'label-selector', + 'misc-selector', + 'title-selector', + 'threshold' + ] + propertyInner: EditorPropertyInner = { + 'background-overall-component': ['all'], + 'border-style': ['all'], + 'basic-style-selector': ['colors', 'alpha', 'gradient', 'gaugeAxisLine', 'gaugePercentLabel'], + 'label-selector': ['fontSize', 'color', 'labelFormatter'], + 'title-selector': [ + 'title', + 'fontSize', + 'color', + 'hPosition', + 'isItalic', + 'isBolder', + 'remarkShow', + 'fontFamily', + 'letterSpace', + 'fontShadow' + ], + 'misc-selector': [ + 'gaugeMinType', + 'gaugeMinField', + 'gaugeMin', + 'gaugeMaxType', + 'gaugeMaxField', + 'gaugeMax', + 'gaugeStartAngle', + 'gaugeEndAngle' + ], + threshold: ['gaugeThreshold'] + } + axis: AxisType[] = ['yAxis', 'filter'] + axisConfig: AxisConfig = { + yAxis: { + name: `${t('chart.drag_block_gauge_angel')} / ${t('chart.quota')}`, + type: 'q', + limit: 1 + } + } + + async drawChart(drawOptions: G2PlotDrawOptions): Promise { + const { chart, container, scale, action } = drawOptions + if (!chart.data?.series || !chart.yAxis.length) { + return + } + // options + const initOptions: GaugeOptions = { + percent: 0, + appendPadding: getPadding(chart), + axis: { + tickInterval: 0.2, + label: { + style: { + fontSize: getScaleValue(12, scale) // 刻度值字体大小 + } + }, + tickLine: { + length: getScaleValue(12, scale) * -1, // 刻度线长度 + style: { + lineWidth: getScaleValue(1, scale) // 刻度线宽度 + } + }, + subTickLine: { + count: 4, // 子刻度数 + length: getScaleValue(6, scale) * -1, // 子刻度线长度 + style: { + lineWidth: getScaleValue(1, scale) // 子刻度线宽度 + } + } + } + } + const options = this.setupOptions(chart, initOptions, { scale }) + const { Gauge: G2Gauge } = await import('@antv/g2plot/esm/plots/gauge') + const newChart = new G2Gauge(container, options) + newChart.on('afterrender', () => { + action({ + from: 'gauge', + data: { + type: 'gauge', + max: chart.data?.series[0]?.data[0] + } + }) + }) + const hasNoneData = chart.data?.series.some(s => !s.data?.[0]) + this.configEmptyDataStyle(newChart, hasNoneData ? [] : [1], container) + if (hasNoneData) { + return + } + return newChart + } + + protected configMisc( + chart: Chart, + options: GaugeOptions, + context: Record + ): GaugeOptions { + const customAttr = parseJson(chart.customAttr) + const data = chart.data.series[0].data[0] + let min, max, startAngle, endAngle + if (customAttr.misc) { + const misc = customAttr.misc + if (misc.gaugeMinType === 'dynamic' && misc.gaugeMaxType === 'dynamic') { + min = chart.data?.series[chart.data?.series.length - 2]?.data[0] + max = chart.data?.series[chart.data?.series.length - 1]?.data[0] + } else if (misc.gaugeMinType !== 'dynamic' && misc.gaugeMaxType === 'dynamic') { + min = misc.gaugeMin || misc.gaugeMin === 0 ? misc.gaugeMin : DEFAULT_MISC.gaugeMin + max = chart.data?.series[chart.data?.series.length - 1]?.data[0] + } else if (misc.gaugeMinType === 'dynamic' && misc.gaugeMaxType !== 'dynamic') { + min = chart.data?.series[chart.data?.series.length - 1]?.data[0] + max = misc.gaugeMax ? misc.gaugeMax : DEFAULT_MISC.gaugeMax + } else { + min = misc.gaugeMin || misc.gaugeMin === 0 ? misc.gaugeMin : DEFAULT_MISC.gaugeMin + max = misc.gaugeMax + ? misc.gaugeMax + : chart.data?.series[chart.data?.series.length - 1]?.data[0] + } + startAngle = (misc.gaugeStartAngle * Math.PI) / 180 + endAngle = (misc.gaugeEndAngle * Math.PI) / 180 + context.min = min + context.max = max + } + const percent = (parseFloat(data) - parseFloat(min)) / (parseFloat(max) - parseFloat(min)) + const tmp = { + percent, + startAngle, + endAngle + } + return { ...options, ...tmp } + } + + private configRange( + chart: Chart, + options: GaugeOptions, + context: Record + ): GaugeOptions { + const { scale } = context + const range = [0] + let index = 0 + let flag = false + let hasThreshold = false + const theme = options.theme as any + + if (chart.senior) { + const senior = parseJson(chart.senior) + const threshold = senior.threshold ?? DEFAULT_THRESHOLD + if (threshold.enable && threshold.gaugeThreshold) { + hasThreshold = true + const arr = threshold.gaugeThreshold.split(',') + for (let i = 0; i < arr.length; i++) { + const ele = arr[i] + const p = parseFloat(ele) / 100 + range.push(p) + if (!flag && options.percent <= p) { + flag = true + index = i + } + } + if (!flag) { + index = arr.length + } + } + } + range.push(1) + let rangOptions + if (hasThreshold) { + rangOptions = { + range: { + color: theme.styleSheet.paletteQualitative10, + ticks: range + }, + indicator: { + pointer: { + style: { + stroke: + theme.styleSheet.paletteQualitative10[ + index % theme.styleSheet.paletteQualitative10.length + ] + } + }, + pin: { + style: { + stroke: + theme.styleSheet.paletteQualitative10[ + index % theme.styleSheet.paletteQualitative10.length + ], + r: getScaleValue(10, scale) + } + } + } + } + } else { + rangOptions = { + indicator: { + pin: { + style: { + r: getScaleValue(10, scale) + } + } + } + } + } + const customAttr = parseJson(chart.customAttr) + if (customAttr.basicStyle.gradient) { + const colorList = (theme.styleSheet?.paletteQualitative10 || []).map(ele => { + return setGradientColor(ele, true) + }) + if (!rangOptions.range) { + rangOptions.range = { + color: colorList + } + } else { + rangOptions.range.color = colorList + } + } + return { ...options, ...rangOptions } + } + + protected configLabel( + chart: Chart, + options: GaugeOptions, + context?: Record + ): GaugeOptions { + const customAttr = parseJson(chart.customAttr) + const data = chart.data.series[0].data[0] + let labelTitle: GaugeOptions['statistic']['title'] = false + let labelContent: GaugeOptions['statistic']['content'] = false + const label = customAttr.label + const labelFormatter = label.labelFormatter ?? DEFAULT_LABEL.labelFormatter + if (label.show && label.childrenShow) { + labelTitle = { + style: { + fontSize: `${label.fontSize}px`, + color: label.color + }, + formatter: function () { + let value + if (labelFormatter.type === 'percent') { + value = options.percent + } else { + value = data + } + return valueFormatter(value, labelFormatter) + } + } as GaugeOptions['statistic']['title'] + } + const { min, max } = context + if (label.show && label.proportionSeriesFormatter.show) { + const proportionFormatter = label.proportionSeriesFormatter + labelContent = { + offsetY: proportionFormatter.fontSize + label.fontSize, + style: { + fontSize: `${proportionFormatter.fontSize}px`, + color: proportionFormatter.color + }, + formatter: function () { + const proportionValue = ((parseFloat(data) - min) / (max - min)) * 100 + return ( + t('chart.proportion') + + ': ' + + proportionValue.toFixed(proportionFormatter.formatterCfg.decimalCount) + + '%' + ) + } + } as GaugeOptions['statistic']['content'] + } + const statistic = { + title: labelTitle, + content: labelContent + } + const { gaugeAxisLine, gaugePercentLabel } = customAttr.basicStyle + const tmp = { + axis: { + label: { + formatter: v => { + if (gaugeAxisLine === false) { + return '' + } + if (gaugePercentLabel === false) { + const resultV = v === '0' ? min : v === '1' ? max : min + (max - min) * v + return labelFormatter.type === 'value' + ? valueFormatter(resultV, labelFormatter) + : resultV + } + return v === '0' ? v : v * 100 + '%' + } + } + } + } + options = merge(options, tmp) + return { ...options, statistic } + } + + setupDefaultOptions(chart: ChartObj): ChartObj { + chart.customAttr.label = { + ...chart.customAttr.label, + show: true, + labelFormatter: { + type: 'value', + thousandSeparator: true, + decimalCount: 0, + unit: 1 + } + } + return chart + } + + protected setupOptions( + chart: Chart, + options: GaugeOptions, + context: Record + ): GaugeOptions { + return flow( + this.configTheme, + this.configMisc, + this.configLabel, + this.configRange + )(chart, options, context) + } + constructor() { + super('gauge', DEFAULT_DATA) + } +} diff --git a/frontend/src/data-visualization/chart/components/js/panel/charts/others/indicator.ts b/frontend/src/data-visualization/chart/components/js/panel/charts/others/indicator.ts new file mode 100644 index 0000000..c28611c --- /dev/null +++ b/frontend/src/data-visualization/chart/components/js/panel/charts/others/indicator.ts @@ -0,0 +1,76 @@ +import { AbstractChartView, ChartLibraryType, ChartRenderType } from '../../types' +import { useI18n } from '@/data-visualization/hooks/web/useI18n' +import { COLOR_CASES } from '@/data-visualization/chart/components/editor/util/chart' + +const { t } = useI18n() +/** + * 指标卡图表 + */ +export class IndicatorChartView extends AbstractChartView { + selectorSpec: EditorSelectorSpec + properties: EditorProperty[] = [ + 'background-overall-component', + 'border-style', + 'title-selector', + 'indicator-value-selector', + 'indicator-name-selector', + 'threshold', + 'function-cfg' + ] + propertyInner: EditorPropertyInner = { + 'background-overall-component': ['all'], + 'border-style': ['all'], + 'title-selector': [ + 'title', + 'fontSize', + 'color', + 'hPosition', + 'isItalic', + 'isBolder', + 'remarkShow', + 'fontFamily', + 'letterSpace', + 'fontShadow' + ], + 'indicator-value-selector': [ + 'fontSize', + 'color', + 'hPosition', + 'isItalic', + 'isBolder', + 'fontFamily', + 'letterSpace', + 'fontShadow' + ], + 'indicator-name-selector': [ + 'title', + 'fontSize', + 'color', + 'hPosition', + 'isItalic', + 'isBolder', + 'fontFamily', + 'letterSpace', + 'fontShadow' + ], + 'function-cfg': ['emptyDataStrategy'] + } + axis: AxisType[] = ['yAxis', 'filter'] + axisConfig: AxisConfig = { + yAxis: { + name: `${t('chart.quota')}`, + limit: 1 + } + } + setupDefaultOptions(chart: ChartObj): ChartObj { + const basicColors = COLOR_CASES[0].colors + chart.customAttr.basicStyle.colors = basicColors + chart.customAttr.indicator.color = basicColors[0] + chart.customAttr.indicatorName.color = basicColors[1] + return chart + } + + constructor() { + super(ChartRenderType.CUSTOM, ChartLibraryType.INDICATOR, 'indicator') + } +} diff --git a/frontend/src/data-visualization/chart/components/js/panel/charts/others/picture-group.ts b/frontend/src/data-visualization/chart/components/js/panel/charts/others/picture-group.ts new file mode 100644 index 0000000..bd349c6 --- /dev/null +++ b/frontend/src/data-visualization/chart/components/js/panel/charts/others/picture-group.ts @@ -0,0 +1,29 @@ +import { AbstractChartView, ChartLibraryType, ChartRenderType } from '../../types' +import { useI18n } from '@/data-visualization/hooks/web/useI18n' + +const { t } = useI18n() +/** + * 图片组图表 + */ +export class PictureGroupView extends AbstractChartView { + properties: EditorProperty[] = ['background-overall-component', 'border-style', 'threshold'] + propertyInner: EditorPropertyInner = { + 'background-overall-component': ['all'], + 'border-style': ['all'], + threshold: ['tableThreshold'] + } + axis: AxisType[] = ['xAxis', 'yAxis', 'filter'] + axisConfig: AxisConfig = { + xAxis: { + name: `${t('chart.dimension')}`, + type: 'd' + }, + yAxis: { + name: `${t('chart.quota')}`, + type: 'q' + } + } + constructor() { + super(ChartRenderType.CUSTOM, ChartLibraryType.PICTURE_GROUP, 'picture-group') + } +} diff --git a/frontend/src/data-visualization/chart/components/js/panel/charts/others/quadrant.ts b/frontend/src/data-visualization/chart/components/js/panel/charts/others/quadrant.ts new file mode 100644 index 0000000..d9d4e34 --- /dev/null +++ b/frontend/src/data-visualization/chart/components/js/panel/charts/others/quadrant.ts @@ -0,0 +1,488 @@ +import { + G2PlotChartView, + G2PlotDrawOptions +} from '@/data-visualization/chart/components/js/panel/types/impl/g2plot' +import type { ScatterOptions, Scatter as G2Scatter } from '@antv/g2plot/esm/plots/scatter' +import { flow, parseJson, setUpSingleDimensionSeriesColor } from '../../../util' +import { valueFormatter } from '@/data-visualization/chart/components/js/formatter' +import { useI18n } from '@/data-visualization/hooks/web/useI18n' +import { defaults, isEmpty, map } from 'lodash-es' +import { cloneDeep, defaultTo } from 'lodash-es' +import { + configAxisLabelLengthLimit, + configPlotTooltipEvent, + configYaxisTitleLengthLimit, + getTooltipContainer, + TOOLTIP_TPL +} from '../../common/common_antv' +import { DEFAULT_LEGEND_STYLE } from '@/data-visualization/chart/components/editor/util/chart' + +const { t } = useI18n() +/** + * 象限图 + */ +export class Quadrant extends G2PlotChartView { + properties: EditorProperty[] = [ + 'background-overall-component', + 'border-style', + 'basic-style-selector', + 'x-axis-selector', + 'y-axis-selector', + 'title-selector', + 'label-selector', + 'tooltip-selector', + 'legend-selector', + 'jump-set', + 'linkage', + 'quadrant-selector' + ] + propertyInner: EditorPropertyInner = { + 'basic-style-selector': [ + 'colors', + 'alpha', + 'scatterSymbol', + 'scatterSymbolSize', + 'seriesColor' + ], + 'label-selector': ['fontSize', 'color'], + 'tooltip-selector': ['fontSize', 'color', 'backgroundColor', 'seriesTooltipFormatter', 'show'], + 'x-axis-selector': [ + 'position', + 'name', + 'color', + 'fontSize', + 'axisLine', + 'axisValue', + 'splitLine', + 'axisForm', + 'axisLabel', + 'axisLabelFormatter' + ], + 'y-axis-selector': [ + 'position', + 'name', + 'color', + 'fontSize', + 'axisValue', + 'axisLine', + 'splitLine', + 'axisForm', + 'axisLabel', + 'axisLabelFormatter' + ], + 'title-selector': [ + 'title', + 'fontSize', + 'color', + 'hPosition', + 'isItalic', + 'isBolder', + 'remarkShow', + 'fontFamily', + 'letterSpace', + 'fontShadow' + ], + 'legend-selector': ['icon', 'orient', 'color', 'fontSize', 'hPosition', 'vPosition'], + 'quadrant-selector': ['regionStyle', 'label', 'lineStyle'] + } + axis: AxisType[] = [ + 'xAxis', + 'yAxis', + 'yAxisExt', + 'extBubble', + 'filter', + 'drill', + 'extLabel', + 'extTooltip' + ] + axisConfig: AxisConfig = { + extBubble: { + name: `${t('chart.bubble_size')} / ${t('chart.quota')}`, + type: 'q', + limit: 1, + allowEmpty: true + }, + xAxis: { + name: `${t('chart.form_type')} / ${t('chart.dimension')}`, + type: 'd', + limit: 1 + }, + yAxis: { + name: `${t('chart.x_axis')} / ${t('chart.quota')}`, + type: 'q', + limit: 1 + }, + yAxisExt: { + name: `${t('chart.y_axis')} / ${t('chart.quota')}`, + type: 'q', + limit: 1 + } + } + + public getFieldObject(chart: Chart) { + const colorFieldObj = { id: chart.xAxis[0]?.id, name: chart.xAxis[0]?.['originName'] } + const sizeFieldObj = { id: chart.extBubble[0]?.id, name: chart.extBubble[0]?.['originName'] } + const xFieldObj = { id: chart.yAxis[0]?.id, name: chart.yAxis[0]?.['originName'] } + const yFieldObj = { id: chart.yAxisExt[0]?.id, name: chart.yAxisExt[0]?.['originName'] } + return { colorFieldObj, sizeFieldObj, xFieldObj, yFieldObj } + } + public getUniqueObjects(arr: T[]): T[] { + return [...new Set(arr.map(JSON.stringify))].map(JSON.parse) as T[] + } + + async drawChart(drawOptions: G2PlotDrawOptions): Promise { + const { chart, container, action, quadrantDefaultBaseline } = drawOptions + if (!chart.data?.data) { + return + } + // data + const sourceData: Array = cloneDeep(chart.data.data) + const data1 = defaultTo(sourceData[0]?.data, []) + const data2 = defaultTo(sourceData[1]?.data, []) + const data3 = defaultTo(sourceData[2]?.data, []) + const xData = data1.map(item => { + return { + ...item, + id: item.quotaList[0]?.id, + field: item.field, + value: item.value + } + }) + const yData = data2.map(item => { + return { + ...item, + id: item.quotaList[0]?.id, + field: item.field, + value: item.value + } + }) + const eData = data3.map(item => { + return { + ...item, + id: item.quotaList[0]?.id, + field: item.field, + value: item.value + } + }) + // x轴基准线 默认值 + const xValues = xData.map(item => item.value) + const xBaseline = ((Math.max(...xValues) + Math.min(...xValues)) / 2).toFixed() + // y轴基准线 默认值 + const yValues = yData.map(item => item.value) + const yBaseline = ((Math.max(...yValues) + Math.min(...yValues)) / 2).toFixed() + const defaultBaselineQuadrant = { + ...chart.customAttr['quadrant'] + } + // 新建图表 + if (defaultBaselineQuadrant.xBaseline === undefined) { + // 默认基准线值 + defaultBaselineQuadrant.xBaseline = xBaseline + defaultBaselineQuadrant.yBaseline = yBaseline + } + const getQuotaList = d => { + const eQuotaList = eData.find(item => item.field === d.field)?.quotaList + const yQuotaList = yData.find(item => item.field === d.field)?.quotaList + if (JSON.stringify(eQuotaList) === JSON.stringify(yQuotaList)) { + return yQuotaList + } + return [...(eQuotaList || []), ...(yQuotaList || [])] + } + const data = map(defaultTo(xData, []), d => { + return { + ...d, + yAxis: d.value, + quotaList: getQuotaList(d), + yAxisExt: yData.find(item => item.field === d.field)?.value, + extBubble: eData.find(item => item.field === d.field)?.value + } + }) + const baseOptions: ScatterOptions = { + colorField: 'field', + meta: { + field: { + type: 'cat' + } + }, + quadrant: { + ...defaultBaselineQuadrant + }, + data: data, + xField: 'yAxis', + yField: 'yAxisExt', + appendPadding: 30, + pointStyle: { + fillOpacity: 0.8, + stroke: '#bbb' + } + } + chart.container = container + const options = this.setupOptions(chart, baseOptions) + const { Scatter: G2Scatter } = await import('@antv/g2plot/esm/plots/scatter') + const newChart = new G2Scatter(container, options) + newChart.on('point:click', action) + newChart.on('click', () => quadrantDefaultBaseline(defaultBaselineQuadrant)) + newChart.on('afterrender', () => quadrantDefaultBaseline(defaultBaselineQuadrant)) + const yAxis = parseJson(chart.customStyle).yAxis + if (yAxis?.name) { + configYaxisTitleLengthLimit(chart, newChart) + configAxisLabelLengthLimit(chart, newChart, 'axis-title') + } + configPlotTooltipEvent(chart, newChart) + return newChart + } + + protected configBasicStyle(chart: Chart, options: ScatterOptions): ScatterOptions { + const customAttr = parseJson(chart.customAttr) + const basicStyle = customAttr.basicStyle + if (chart.extBubble?.length) { + return { + ...options, + size: [4, 30], + sizeField: 'extBubble', + shape: basicStyle.scatterSymbol + } + } + return { + ...options, + size: basicStyle.scatterSymbolSize, + shape: basicStyle.scatterSymbol + } + } + + protected configXAxis(chart: Chart, options: ScatterOptions): ScatterOptions { + const tmpOptions = super.configXAxis(chart, options) + if (!tmpOptions.xAxis) { + return tmpOptions + } + const xAxis = parseJson(chart.customStyle).xAxis + if (tmpOptions.xAxis.label) { + tmpOptions.xAxis.label.formatter = value => { + return valueFormatter(value, xAxis.axisLabelFormatter) + } + } + const axisValue = xAxis.axisValue + if (!axisValue?.auto) { + const axis = { + xAxis: { + ...tmpOptions.xAxis, + min: axisValue.min, + max: axisValue.max, + minLimit: axisValue.min, + maxLimit: axisValue.max, + tickCount: axisValue.splitCount + } + } + return { ...tmpOptions, ...axis } + } + return tmpOptions + } + + protected configYAxis(chart: Chart, options: ScatterOptions): ScatterOptions { + const tmpOptions = super.configYAxis(chart, options) + if (!tmpOptions.yAxis) { + return tmpOptions + } + const yAxis = parseJson(chart.customStyle).yAxis + if (tmpOptions.yAxis.label) { + tmpOptions.yAxis.label.formatter = value => { + return valueFormatter(value, yAxis.axisLabelFormatter) + } + } + const axisValue = yAxis.axisValue + if (!axisValue?.auto) { + const axis = { + yAxis: { + ...tmpOptions.yAxis, + min: axisValue.min, + max: axisValue.max, + minLimit: axisValue.min, + maxLimit: axisValue.max, + tickCount: axisValue.splitCount + } + } + return { ...tmpOptions, ...axis } + } + return tmpOptions + } + + protected configLabel(chart: Chart, options: ScatterOptions): ScatterOptions { + let label + let customAttr: DeepPartial + if (chart.customAttr) { + customAttr = parseJson(chart.customAttr) + // label + if (customAttr.label) { + const l = customAttr.label + if (l.show) { + const layout = [] + if (!l.fullDisplay) { + layout.push({ type: 'hide-overlap' }) + layout.push({ type: 'limit-in-shape' }) + } + label = { + offset: 0, + style: { + fill: l.color, + fontSize: l.fontSize + }, + content: datum => { + return datum['name'] + }, + layout + } + } else { + label = false + } + } + } + return { ...options, label } + } + + protected configTooltip(chart: Chart, options: ScatterOptions): ScatterOptions { + const customAttr: DeepPartial = parseJson(chart.customAttr) + const tooltipAttr = customAttr.tooltip + const xAxisTitle = chart.xAxis[0] + const yAxisTitle = chart.yAxis[0] + const yAxisExtTitle = chart.yAxisExt[0] + if (!tooltipAttr.show || (!xAxisTitle && !yAxisTitle && !yAxisExtTitle)) { + return { + ...options, + tooltip: false + } + } + const formatterMap = tooltipAttr.seriesTooltipFormatter + ?.filter(i => i.show) + .reduce((pre, next) => { + pre[next['seriesId']] = next + return pre + }, {}) as Record + const optionsData = cloneDeep(options.data) + const tooltip: ScatterOptions['tooltip'] = { + showTitle: true, + title: (_title, datum) => { + return datum?.['name'] + }, + customItems(originalItems) { + if (!tooltipAttr.seriesTooltipFormatter?.length) { + return originalItems + } + const result = [] + originalItems.forEach(item => { + Object.keys(formatterMap).forEach(key => { + if (key.endsWith(item.name)) { + const formatter = formatterMap[key] + if (formatter) { + const value = + formatter.groupType === 'q' + ? valueFormatter(parseFloat(item.value as string), formatter.formatterCfg) + : item.value + const name = isEmpty(formatter.chartShowName) + ? formatter.name + : formatter.chartShowName + result.push({ color: item.color, name, value }) + } + } + }) + }) + const dynamicTooltipValue = optionsData.find( + d => d.field === originalItems[0]['title'] + )?.dynamicTooltipValue + if (dynamicTooltipValue.length > 0) { + dynamicTooltipValue.forEach(dy => { + const q = tooltipAttr.seriesTooltipFormatter.filter(i => i.id === dy.fieldId) + if (q && q.length > 0) { + const value = valueFormatter(parseFloat(dy.value as string), q[0].formatterCfg) + const name = isEmpty(q[0].chartShowName) ? q[0].name : q[0].chartShowName + result.push({ color: 'grey', name, value }) + } + }) + } + return result + }, + container: getTooltipContainer(`tooltip-${chart.id}`), + itemTpl: TOOLTIP_TPL, + enterable: true + } + return { + ...options, + tooltip + } + } + + setupDefaultOptions(chart: ChartObj): ChartObj { + chart.customStyle.yAxis.splitLine = { + ...chart.customStyle.yAxis.splitLine, + show: false + } + chart.customStyle.yAxisExt.splitLine = { + ...chart.customStyle.yAxisExt.splitLine, + show: false + } + chart.customStyle.yAxis.axisLine = { + ...chart.customStyle.yAxis.axisLine, + show: true + } + chart.customStyle.yAxisExt.axisLine = { + ...chart.customStyle.yAxisExt.axisLine, + show: true + } + return chart + } + + protected configColor(chart: Chart, options: ScatterOptions): ScatterOptions { + const { xAxis, yAxis, yAxisExt } = chart + if (!(xAxis?.length && yAxis?.length && yAxisExt?.length)) { + return options + } + return this.configSingleDimensionColor(chart, options) + } + + public setupSeriesColor(chart: ChartObj, data?: any[]): ChartBasicStyle['seriesColor'] { + const { xAxis, yAxis, yAxisExt } = chart + if (!(xAxis?.length && yAxis?.length && yAxisExt?.length)) { + return [] + } + const tmp = data?.[0]?.data + return setUpSingleDimensionSeriesColor(chart, tmp) + } + + protected configLegend(chart: Chart, options: ScatterOptions): ScatterOptions { + const optionTmp = super.configLegend(chart, options) + if (!optionTmp.legend) { + return optionTmp + } + const customStyle = parseJson(chart.customStyle) + let size + if (customStyle && customStyle.legend) { + size = defaults(JSON.parse(JSON.stringify(customStyle.legend)), DEFAULT_LEGEND_STYLE).size + } else { + size = DEFAULT_LEGEND_STYLE.size + } + optionTmp.legend.marker.style = style => { + return { + r: size, + fill: style.fill + } + } + return optionTmp + } + + protected setupOptions(chart: Chart, options: ScatterOptions) { + return flow( + this.configTheme, + this.configColor, + this.configLabel, + this.configTooltip, + this.configLegend, + this.configXAxis, + this.configYAxis, + this.configAnalyse, + this.configSlider, + this.configBasicStyle + )(chart, options, {}, this) + } + + constructor() { + super('quadrant', []) + } +} diff --git a/frontend/src/data-visualization/chart/components/js/panel/charts/others/radar.ts b/frontend/src/data-visualization/chart/components/js/panel/charts/others/radar.ts new file mode 100644 index 0000000..4da7509 --- /dev/null +++ b/frontend/src/data-visualization/chart/components/js/panel/charts/others/radar.ts @@ -0,0 +1,306 @@ +import type { RadarOptions, Radar as G2Radar } from '@antv/g2plot/esm/plots/radar' +import { G2PlotChartView, G2PlotDrawOptions } from '../../types/impl/g2plot' +import { flow, parseJson } from '../../../util' +import { configPlotTooltipEvent } from '../../common/common_antv' +import { valueFormatter } from '../../../formatter' +import type { Datum } from '@antv/g2plot/esm/types/common' +import { useI18n } from '@/data-visualization/hooks/web/useI18n' +import { DEFAULT_LABEL, DEFAULT_LEGEND_STYLE } from '@/data-visualization/chart/components/editor/util/chart' +import { Group } from '@antv/g-canvas' +import { defaults } from 'lodash-es' + +const { t } = useI18n() + +export class Radar extends G2PlotChartView { + properties: EditorProperty[] = [ + 'background-overall-component', + 'border-style', + 'basic-style-selector', + 'label-selector', + 'tooltip-selector', + 'title-selector', + 'legend-selector', + 'misc-style-selector', + 'jump-set', + 'linkage' + ] + propertyInner: EditorPropertyInner = { + 'basic-style-selector': [ + 'colors', + 'alpha', + 'radarShape', + 'seriesColor', + 'radarShowPoint', + 'radarPointSize', + 'radarAreaColor' + ], + 'label-selector': ['seriesLabelFormatter'], + 'tooltip-selector': ['color', 'fontSize', 'backgroundColor', 'seriesTooltipFormatter', 'show'], + 'misc-style-selector': ['showName', 'color', 'fontSize', 'axisColor', 'axisValue'], + 'title-selector': [ + 'show', + 'title', + 'fontSize', + 'color', + 'hPosition', + 'isItalic', + 'isBolder', + 'remarkShow', + 'fontFamily', + 'letterSpace', + 'fontShadow' + ], + 'legend-selector': ['icon', 'orient', 'color', 'fontSize', 'hPosition', 'vPosition'] + } + selectorSpec: EditorSelectorSpec = { + ...this['selectorSpec'], + 'misc-style-selector': { + title: `${t('chart.tooltip_axis')}` + } + } + axis: AxisType[] = ['xAxis', 'yAxis', 'drill', 'filter', 'extLabel', 'extTooltip'] + axisConfig: AxisConfig = { + xAxis: { + name: `${t('chart.drag_block_radar_label')} / ${t('chart.dimension')}`, + type: 'd' + }, + yAxis: { + name: `${t('chart.drag_block_radar_length')} / ${t('chart.quota')}`, + type: 'q' + } + } + + async drawChart(drawOptions: G2PlotDrawOptions): Promise { + const { chart, container, action } = drawOptions + if (!chart.data?.data) { + return + } + const data = chart.data.data + const baseOptions: RadarOptions = { + data, + xField: 'field', + yField: 'value', + seriesField: 'category', + appendPadding: [10, 10, 10, 10], + interactions: [ + { + type: 'legend-active', + cfg: { + start: [{ trigger: 'legend-item:mouseenter', action: ['element-active:reset'] }], + end: [{ trigger: 'legend-item:mouseleave', action: ['element-active:reset'] }] + } + }, + { + type: 'legend-filter', + cfg: { + start: [ + { + trigger: 'legend-item:click', + action: [ + 'list-unchecked:toggle', + 'data-filter:filter', + 'element-active:reset', + 'element-highlight:reset' + ] + } + ] + } + }, + { + type: 'active-region', + cfg: { + start: [{ trigger: 'point:mousemove', action: 'active-region:show' }], + end: [{ trigger: 'point:mouseleave', action: 'active-region:hide' }] + } + } + ] + } + const options = this.setupOptions(chart, baseOptions) + const { Radar: G2Radar } = await import('@antv/g2plot/esm/plots/radar') + const newChart = new G2Radar(container, options) + newChart.on('point:click', action) + if (options.label) { + newChart.on('label:click', e => { + action({ + x: e.x, + y: e.y, + data: { + data: e.target.attrs.data + } + }) + }) + } + configPlotTooltipEvent(chart, newChart) + return newChart + } + + protected configBasicStyle(chart: Chart, options: RadarOptions): RadarOptions { + const { radarShowPoint, radarPointSize, radarAreaColor } = parseJson( + chart.customAttr + ).basicStyle + const tempOptions: RadarOptions = {} + + if (radarShowPoint) { + tempOptions['point'] = { shape: 'circle', size: radarPointSize, style: { fill: null } } + } + if (radarAreaColor) { + tempOptions['area'] = {} + } + + return { ...options, ...tempOptions } + } + + protected configLabel(chart: Chart, options: RadarOptions): RadarOptions { + const tmpOptions = super.configLabel(chart, options) + if (!tmpOptions.label) { + return { + ...tmpOptions, + label: false + } + } + const labelAttr = parseJson(chart.customAttr).label + const formatterMap = labelAttr.seriesLabelFormatter?.reduce((pre, next) => { + pre[next.id] = next + return pre + }, {}) + tmpOptions.label.style.fill = DEFAULT_LABEL.color + // 自动旋转和标签自定义有冲突 + const label = { + fields: [], + ...tmpOptions.label, + autoRotate: false, + autoHide: true, + formatter: (data: Datum) => { + if (!labelAttr.seriesLabelFormatter?.length) { + return data.value + } + const labelCfg = formatterMap?.[data.quotaList[0].id] as SeriesFormatter + if (!labelCfg) { + return data.value + } + if (!labelCfg.show) { + return + } + const value = valueFormatter(data.value, labelCfg.formatterCfg) + const group = new Group({}) + group.addShape({ + type: 'text', + attrs: { + data, + x: 0, + y: 0, + text: value, + textAlign: 'start', + textBaseline: 'top', + fontSize: labelCfg.fontSize, + fill: labelCfg.color + } + }) + return group + } + } + return { + ...tmpOptions, + label + } + } + + protected configAxis(chart: Chart, options: RadarOptions): RadarOptions { + const customAttr = parseJson(chart.customAttr) + const customStyle = parseJson(chart.customStyle) + const basicStyle = customAttr.basicStyle + const misc = customStyle.misc + let label: any = { + style: { + fill: misc.color, + fontSize: misc.fontSize + } + } + if (!misc.showName) { + label = false + } + const xAxis = { + line: null, + tickLine: null, + label, + grid: { + line: { + style: { + stroke: misc.axisColor + } + } + } + } + const yAxis = { + label: null, + line: null, + tickLine: null, + grid: { + line: { + type: basicStyle.radarShape, + style: { + stroke: misc.axisColor + } + } + } + } + const axisValue = misc.axisValue + if (!axisValue?.auto) { + const axisYAxis = { + ...yAxis, + min: axisValue.min, + max: axisValue.max, + minLimit: axisValue.min, + maxLimit: axisValue.max, + tickCount: axisValue.splitCount + } + return { + ...options, + xAxis, + yAxis: axisYAxis + } + } + return { + ...options, + xAxis, + yAxis + } + } + + protected configLegend(chart: Chart, options: RadarOptions): RadarOptions { + const optionTmp = super.configLegend(chart, options) + if (!optionTmp.legend) { + return optionTmp + } + const customStyle = parseJson(chart.customStyle) + let size + if (customStyle && customStyle.legend) { + size = defaults(JSON.parse(JSON.stringify(customStyle.legend)), DEFAULT_LEGEND_STYLE).size + } else { + size = DEFAULT_LEGEND_STYLE.size + } + optionTmp.legend.marker.style = style => { + return { + r: size, + fill: style.stroke + } + } + return optionTmp + } + + protected setupOptions(chart: Chart, options: RadarOptions): RadarOptions { + return flow( + this.configTheme, + this.configColor, + this.configLabel, + this.configLegend, + this.configMultiSeriesTooltip, + this.configAxis, + this.configBasicStyle + )(chart, options) + } + + constructor() { + super('radar', []) + } +} diff --git a/frontend/src/data-visualization/chart/components/js/panel/charts/others/rich-text.ts b/frontend/src/data-visualization/chart/components/js/panel/charts/others/rich-text.ts new file mode 100644 index 0000000..e0fa370 --- /dev/null +++ b/frontend/src/data-visualization/chart/components/js/panel/charts/others/rich-text.ts @@ -0,0 +1,37 @@ +import { AbstractChartView, ChartLibraryType, ChartRenderType } from '../../types' +import { useI18n } from '@/data-visualization/hooks/web/useI18n' + +const { t } = useI18n() +/** + * 富文本图表 + */ +export class RichTextChartView extends AbstractChartView { + properties: EditorProperty[] = [ + 'background-overall-component', + 'border-style', + 'threshold', + 'function-cfg' + ] + propertyInner: EditorPropertyInner = { + 'background-overall-component': ['all'], + 'border-style': ['all'], + threshold: ['tableThreshold'], + 'function-cfg': ['emptyDataStrategy'] + } + axis: AxisType[] = ['xAxis', 'yAxis', 'filter'] + axisConfig: AxisConfig = { + xAxis: { + name: `${t('chart.dimension')}`, + type: 'd', + allowEmpty: true + }, + yAxis: { + name: `${t('chart.quota')}`, + type: 'q', + allowEmpty: true + } + } + constructor() { + super(ChartRenderType.CUSTOM, ChartLibraryType.RICH_TEXT, 'rich-text') + } +} diff --git a/frontend/src/data-visualization/chart/components/js/panel/charts/others/sankey-common.ts b/frontend/src/data-visualization/chart/components/js/panel/charts/others/sankey-common.ts new file mode 100644 index 0000000..d080ac6 --- /dev/null +++ b/frontend/src/data-visualization/chart/components/js/panel/charts/others/sankey-common.ts @@ -0,0 +1,40 @@ +export const SANKEY_EDITOR_PROPERTY: EditorProperty[] = [ + 'background-overall-component', + 'border-style', + 'basic-style-selector', + 'label-selector', + 'tooltip-selector', + 'title-selector', + 'jump-set', + 'linkage' +] + +export const SANKEY_EDITOR_PROPERTY_INNER: EditorPropertyInner = { + 'background-overall-component': ['all'], + 'border-style': ['all'], + 'basic-style-selector': ['colors', 'alpha', 'gradient'], + 'label-selector': ['fontSize', 'color', 'labelFormatter'], + 'tooltip-selector': ['fontSize', 'color', 'tooltipFormatter'], + 'title-selector': [ + 'title', + 'fontSize', + 'color', + 'hPosition', + 'isItalic', + 'isBolder', + 'remarkShow', + 'fontFamily', + 'letterSpace', + 'fontShadow' + ], + 'function-cfg': ['slider', 'emptyDataStrategy'] +} + +export const SANKEY_AXIS_TYPE: AxisType[] = [ + 'xAxis', + 'xAxisExt', + 'yAxis', + 'filter', + 'extLabel', + 'extTooltip' +] diff --git a/frontend/src/data-visualization/chart/components/js/panel/charts/others/sankey.ts b/frontend/src/data-visualization/chart/components/js/panel/charts/others/sankey.ts new file mode 100644 index 0000000..783efa6 --- /dev/null +++ b/frontend/src/data-visualization/chart/components/js/panel/charts/others/sankey.ts @@ -0,0 +1,285 @@ +import { + G2PlotChartView, + G2PlotDrawOptions +} from '@/data-visualization/chart/components/js/panel/types/impl/g2plot' +import type { Sankey, SankeyOptions } from '@antv/g2plot/esm/plots/sankey' +import { getPadding, setGradientColor } from '@/data-visualization/chart/components/js/panel/common/common_antv' +import { cloneDeep, get } from 'lodash-es' +import { flow, hexColorToRGBA, parseJson } from '@/data-visualization/chart/components/js/util' +import { valueFormatter } from '@/data-visualization/chart/components/js/formatter' + +import { Datum } from '@antv/g2plot/esm/types/common' +import { useI18n } from '@/data-visualization/hooks/web/useI18n' +import { + SANKEY_AXIS_TYPE, + SANKEY_EDITOR_PROPERTY, + SANKEY_EDITOR_PROPERTY_INNER +} from '@/data-visualization/chart/components/js/panel/charts/others/sankey-common' + +const { t } = useI18n() +const DEFAULT_DATA = [] + +/** + * 桑基图 + */ +export class SankeyBar extends G2PlotChartView { + axisConfig = { + xAxis: { + name: `${t('chart.drag_block_type_axis_start')} / ${t('chart.dimension')}`, + limit: 1, + type: 'd' + }, + xAxisExt: { + name: `${t('chart.drag_block_type_axis_end')} / ${t('chart.dimension')}`, + limit: 1, + type: 'd', + allowEmpty: true + }, + yAxis: { + name: `${t('chart.chart_data')} / ${t('chart.quota')}`, + limit: 1, + type: 'q' + } + } + properties = SANKEY_EDITOR_PROPERTY + propertyInner = { + ...SANKEY_EDITOR_PROPERTY_INNER, + 'label-selector': ['color', 'fontSize'], + 'tooltip-selector': ['fontSize', 'color', 'backgroundColor', 'tooltipFormatter', 'show'] + } + axis: AxisType[] = [...SANKEY_AXIS_TYPE] + protected baseOptions: SankeyOptions = { + data: [], + sourceField: 'source', + targetField: 'target', + weightField: 'value', + rawFields: ['dimensionList', 'quotaList'], + interactions: [ + { + type: 'legend-active', + cfg: { + start: [{ trigger: 'legend-item:mouseenter', action: ['element-active:reset'] }], + end: [{ trigger: 'legend-item:mouseleave', action: ['element-active:reset'] }] + } + }, + { + type: 'legend-filter', + cfg: { + start: [ + { + trigger: 'legend-item:click', + action: [ + 'list-unchecked:toggle', + 'data-filter:filter', + 'element-active:reset', + 'element-highlight:reset' + ] + } + ] + } + }, + { + type: 'tooltip', + cfg: { + start: [{ trigger: 'interval:mousemove', action: 'tooltip:show' }], + end: [{ trigger: 'interval:mouseleave', action: 'tooltip:hide' }] + } + }, + { + type: 'active-region', + cfg: { + start: [{ trigger: 'interval:mousemove', action: 'active-region:show' }], + end: [{ trigger: 'interval:mouseleave', action: 'active-region:hide' }] + } + } + ] + } + + async drawChart(drawOptions: G2PlotDrawOptions): Promise { + const { chart, container, action } = drawOptions + if (!chart.data?.data?.length) { + return + } + // data + const data: Array = cloneDeep(chart.data.data) + + data.forEach(d => { + if (d.dimensionList) { + if (d.dimensionList[0]) { + d.source = d.dimensionList[0].value + } + if (d.dimensionList[1]) { + d.target = d.dimensionList[1].value + } + } + }) + + // options + const initOptions: SankeyOptions = { + ...this.baseOptions, + appendPadding: getPadding(chart), + data, + nodeSort: (a, b) => { + // 这里是前端自己排序 + if (chart.yAxis && chart.yAxis[0]) { + if (chart.yAxis[0].sort === 'asc') { + return a.value - b.value + } else if (chart.yAxis[0].sort === 'desc') { + return b.value - a.value + } + } + + if (chart.xAxis && chart.xAxis[0] && a.sourceLinks.length > 0) { + if (chart.xAxis[0].sort === 'custom_sort' && chart.xAxis[0].customSort) { + return ( + chart.xAxis[0].customSort.indexOf(a.name) - chart.xAxis[0].customSort.indexOf(b.name) + ) + } else if (chart.xAxis[0].sort === 'asc') { + return a.name.localeCompare(b.name) + } else if (chart.xAxis[0].sort === 'desc') { + return b.name.localeCompare(a.name) + } + } + if (chart.xAxisExt && chart.xAxisExt[0] && a.targetLinks.length > 0) { + if (chart.xAxisExt[0].sort === 'custom_sort' && chart.xAxisExt[0].customSort) { + return ( + chart.xAxisExt[0].customSort.indexOf(a.name) - + chart.xAxisExt[0].customSort.indexOf(b.name) + ) + } else if (chart.xAxisExt[0].sort === 'asc') { + return a.name.localeCompare(b.name) + } else if (chart.xAxisExt[0].sort === 'desc') { + return b.name.localeCompare(a.name) + } + } + + return b.value - a.value + } + } + + const options = this.setupOptions(chart, initOptions) + const { Sankey } = await import('@antv/g2plot/esm/plots/sankey') + // 开始渲染 + const newChart = new Sankey(container, options) + + newChart.on('edge:click', action) + + return newChart + } + + protected configTooltip(chart: Chart, options: SankeyOptions): SankeyOptions { + let tooltip + let customAttr: DeepPartial + if (chart.customAttr) { + customAttr = parseJson(chart.customAttr) + // tooltip + if (customAttr.tooltip) { + const t = JSON.parse(JSON.stringify(customAttr.tooltip)) + if (t.show) { + tooltip = { + showTitle: false, + showMarkers: false, + shared: false, + // 内置:node 不显示 tooltip,edge 显示 tooltip + showContent: items => { + return !get(items, [0, 'data', 'isNode']) + }, + formatter: (datum: Datum) => { + const { source, target, value } = datum + return { + name: source + ' -> ' + target, + value: valueFormatter(value, t.tooltipFormatter) + } + } + } + } else { + tooltip = false + } + } + } + return { ...options, tooltip } + } + + protected configBasicStyle(chart: Chart, options: SankeyOptions): SankeyOptions { + const basicStyle = parseJson(chart.customAttr).basicStyle + + let color = basicStyle.colors + color = color.map(ele => { + const tmp = hexColorToRGBA(ele, basicStyle.alpha) + if (basicStyle.gradient) { + return setGradientColor(tmp, true) + } else { + return tmp + } + }) + + options = { + ...options, + color + } + return options + } + + setupDefaultOptions(chart: ChartObj): ChartObj { + const { customAttr, senior } = chart + const { label } = customAttr + if (!['left', 'middle', 'right'].includes(label.position)) { + label.position = 'middle' + } + senior.functionCfg.emptyDataStrategy = 'ignoreData' + return chart + } + + protected configLabel(chart: Chart, options: SankeyOptions): SankeyOptions { + const labelAttr = parseJson(chart.customAttr).label + if (labelAttr.show) { + const layout = [] + if (!labelAttr.fullDisplay) { + layout.push(...[{ type: 'hide-overlap' }, { type: 'limit-in-canvas' }]) + } + const label = { + //...tmpOptions.label, + formatter: ({ name }) => name, + callback: (x: number[]) => { + const isLast = x[1] === 1 // 最后一列靠边的节点 + return { + style: { + fill: labelAttr.color, + fontSize: labelAttr.fontSize, + textAlign: isLast ? 'end' : 'start', + fontFamily: chart.fontFamily + }, + offsetX: isLast ? -8 : 8 + } + }, + layout + } + return { + ...options, + label + } + } else { + return { + ...options, + label: false + } + } + } + + protected setupOptions(chart: Chart, options: SankeyOptions): SankeyOptions { + return flow( + this.configTheme, + this.configBasicStyle, + this.configLabel, + this.configTooltip, + this.configLegend, + this.configSlider, + this.configAnalyseHorizontal, + this.configEmptyDataStrategy + )(chart, options) + } + + constructor(name = 'sankey') { + super(name, DEFAULT_DATA) + } +} diff --git a/frontend/src/data-visualization/chart/components/js/panel/charts/others/scatter.ts b/frontend/src/data-visualization/chart/components/js/panel/charts/others/scatter.ts new file mode 100644 index 0000000..a06684e --- /dev/null +++ b/frontend/src/data-visualization/chart/components/js/panel/charts/others/scatter.ts @@ -0,0 +1,298 @@ +import { + G2PlotChartView, + G2PlotDrawOptions +} from '@/data-visualization/chart/components/js/panel/types/impl/g2plot' +import type { ScatterOptions, Scatter as G2Scatter } from '@antv/g2plot/esm/plots/scatter' +import { flow, parseJson } from '../../../util' +import { valueFormatter } from '../../../formatter' +import { + configPlotTooltipEvent, + getPadding, + getTooltipContainer, + TOOLTIP_TPL +} from '../../common/common_antv' +import { useI18n } from '@/data-visualization/hooks/web/useI18n' +import { defaults, isEmpty } from 'lodash-es' +import { DEFAULT_LEGEND_STYLE } from '@/data-visualization/chart/components/editor/util/chart' + +const { t } = useI18n() +/** + * 散点图 + */ +export class Scatter extends G2PlotChartView { + properties: EditorProperty[] = [ + 'background-overall-component', + 'border-style', + 'basic-style-selector', + 'x-axis-selector', + 'y-axis-selector', + 'title-selector', + 'label-selector', + 'tooltip-selector', + 'legend-selector', + 'jump-set', + 'linkage' + ] + propertyInner: EditorPropertyInner = { + 'basic-style-selector': [ + 'colors', + 'alpha', + 'scatterSymbol', + 'scatterSymbolSize', + 'seriesColor' + ], + 'label-selector': ['fontSize', 'color', 'labelFormatter'], + 'tooltip-selector': ['fontSize', 'color', 'backgroundColor', 'seriesTooltipFormatter', 'show'], + 'x-axis-selector': [ + 'position', + 'name', + 'color', + 'fontSize', + 'axisLine', + 'splitLine', + 'axisForm', + 'axisLabel' + ], + 'y-axis-selector': [ + 'position', + 'name', + 'color', + 'fontSize', + 'axisValue', + 'axisLine', + 'splitLine', + 'axisForm', + 'axisLabel', + 'axisLabelFormatter' + ], + 'title-selector': [ + 'title', + 'fontSize', + 'color', + 'hPosition', + 'isItalic', + 'isBolder', + 'remarkShow', + 'fontFamily', + 'letterSpace', + 'fontShadow' + ], + 'legend-selector': ['icon', 'orient', 'color', 'fontSize', 'hPosition', 'vPosition'] + } + axis: AxisType[] = ['xAxis', 'yAxis', 'extBubble', 'filter', 'drill', 'extLabel', 'extTooltip'] + axisConfig: AxisConfig = { + xAxis: { + name: `${t('chart.drag_block_type_axis')} / ${t('chart.dimension')}`, + type: 'd' + }, + yAxis: { + ...this['axisConfig'].yAxis, + limit: undefined, + allowEmpty: false + }, + extBubble: { + name: `${t('chart.bubble_size')} / ${t('chart.quota')}`, + type: 'q', + limit: 1, + allowEmpty: true + } + } + async drawChart(drawOptions: G2PlotDrawOptions): Promise { + const { chart, container, action } = drawOptions + if (!chart.data?.data) { + return + } + const data = chart.data.data + const baseOptions: ScatterOptions = { + data: data, + xField: 'field', + yField: 'value', + colorField: 'category', + meta: { + field: { + type: 'cat' + } + }, + appendPadding: getPadding(chart), + interactions: [ + { + type: 'legend-active', + cfg: { + start: [{ trigger: 'legend-item:mouseenter', action: ['element-active:reset'] }], + end: [{ trigger: 'legend-item:mouseleave', action: ['element-active:reset'] }] + } + }, + { + type: 'legend-filter', + cfg: { + start: [ + { + trigger: 'legend-item:click', + action: [ + 'list-unchecked:toggle', + 'data-filter:filter', + 'element-active:reset', + 'element-highlight:reset' + ] + } + ] + } + } + ] + } + const options = this.setupOptions(chart, baseOptions) + const { Scatter: G2Scatter } = await import('@antv/g2plot/esm/plots/scatter') + const newChart = new G2Scatter(container, options) + newChart.on('point:click', action) + configPlotTooltipEvent(chart, newChart) + return newChart + } + + protected configBasicStyle(chart: Chart, options: ScatterOptions): ScatterOptions { + const customAttr = parseJson(chart.customAttr) + const basicStyle = customAttr.basicStyle + if (chart.extBubble?.length) { + return { + ...options, + size: [5, 30], + sizeField: 'popSize', + shape: basicStyle.scatterSymbol + } + } + return { + ...options, + size: basicStyle.scatterSymbolSize, + shape: basicStyle.scatterSymbol + } + } + + protected configYAxis(chart: Chart, options: ScatterOptions): ScatterOptions { + const tmpOptions = super.configYAxis(chart, options) + if (!tmpOptions.yAxis) { + return tmpOptions + } + const yAxis = parseJson(chart.customStyle).yAxis + if (tmpOptions.yAxis.label) { + tmpOptions.yAxis.label.formatter = value => { + return valueFormatter(value, yAxis.axisLabelFormatter) + } + } + const axisValue = yAxis.axisValue + if (!axisValue?.auto) { + const axis = { + yAxis: { + ...tmpOptions.yAxis, + min: axisValue.min, + max: axisValue.max, + minLimit: axisValue.min, + maxLimit: axisValue.max, + tickCount: axisValue.splitCount + } + } + return { ...tmpOptions, ...axis } + } + return tmpOptions + } + + protected configTooltip(chart: Chart, options: ScatterOptions): ScatterOptions { + const customAttr: DeepPartial = parseJson(chart.customAttr) + const tooltipAttr = customAttr.tooltip + if (!tooltipAttr.show) { + return { + ...options, + tooltip: false + } + } + const formatterMap = tooltipAttr.seriesTooltipFormatter + ?.filter(i => i.show) + .reduce((pre, next) => { + pre[next.seriesId] = next + return pre + }, {}) as Record + const VALID_ITEMS = ['value', 'popSize'] + const tooltip: ScatterOptions['tooltip'] = { + showTitle: true, + customItems(originalItems) { + if (!tooltipAttr.seriesTooltipFormatter?.length) { + return originalItems + } + const head = originalItems[0] + // 非原始数据 + if (!head.data.quotaList) { + return originalItems + } + const result = [] + originalItems + .filter(item => VALID_ITEMS.includes(item.name)) + .forEach(item => { + let formatter = formatterMap[`${item.data.quotaList[0].id}-yAxis`] + if (item.name === 'popSize') { + formatter = formatterMap[`${item.data.quotaList[1].id}-extBubble`] + } + if (!formatter) { + return + } + const value = valueFormatter(parseFloat(item.value as string), formatter.formatterCfg) + const name = isEmpty(formatter.chartShowName) ? formatter.name : formatter.chartShowName + result.push({ ...item, name, value }) + }) + head.data.dynamicTooltipValue?.forEach(item => { + const formatter = formatterMap[item.fieldId] + if (formatter) { + const value = valueFormatter(parseFloat(item.value), formatter.formatterCfg) + const name = isEmpty(formatter.chartShowName) ? formatter.name : formatter.chartShowName + result.push({ color: 'grey', name, value }) + } + }) + return result + }, + container: getTooltipContainer(`tooltip-${chart.id}`), + itemTpl: TOOLTIP_TPL, + enterable: true + } + return { + ...options, + tooltip + } + } + + protected configLegend(chart: Chart, options: ScatterOptions): ScatterOptions { + const optionTmp = super.configLegend(chart, options) + if (!optionTmp.legend) { + return optionTmp + } + const customStyle = parseJson(chart.customStyle) + let size + if (customStyle && customStyle.legend) { + size = defaults(JSON.parse(JSON.stringify(customStyle.legend)), DEFAULT_LEGEND_STYLE).size + } else { + size = DEFAULT_LEGEND_STYLE.size + } + optionTmp.legend.marker.style = style => { + return { + r: size, + fill: style.fill + } + } + return optionTmp + } + + protected setupOptions(chart: Chart, options: ScatterOptions) { + return flow( + this.configTheme, + this.configColor, + this.configLabel, + this.configTooltip, + this.configLegend, + this.configXAxis, + this.configYAxis, + this.configAnalyse, + this.configSlider, + this.configBasicStyle + )(chart, options) + } + + constructor() { + super('scatter', []) + } +} diff --git a/frontend/src/data-visualization/chart/components/js/panel/charts/others/treemap.ts b/frontend/src/data-visualization/chart/components/js/panel/charts/others/treemap.ts new file mode 100644 index 0000000..98f0364 --- /dev/null +++ b/frontend/src/data-visualization/chart/components/js/panel/charts/others/treemap.ts @@ -0,0 +1,246 @@ +import { TreemapOptions, Treemap as G2Treemap } from '@antv/g2plot/esm/plots/treemap' +import { G2PlotChartView, G2PlotDrawOptions } from '../../types/impl/g2plot' +import { flow, parseJson, setUpSingleDimensionSeriesColor } from '../../../util' +import { getPadding, getTooltipSeriesTotalMap } from '../../common/common_antv' +import { valueFormatter } from '../../../formatter' +import { Label } from '@antv/g2plot/lib/types/label' +import { Datum } from '@antv/g2plot/esm/types/common' +import { useI18n } from '@/data-visualization/hooks/web/useI18n' +import isEmpty from 'lodash-es/isEmpty' + +const { t } = useI18n() + +/** + * 矩形树图 + */ +export class Treemap extends G2PlotChartView { + properties: EditorProperty[] = [ + 'background-overall-component', + 'border-style', + 'basic-style-selector', + 'title-selector', + 'legend-selector', + 'label-selector', + 'tooltip-selector', + 'jump-set', + 'linkage' + ] + propertyInner: EditorPropertyInner = { + 'background-overall-component': ['all'], + 'border-style': ['all'], + 'basic-style-selector': ['colors', 'alpha', 'seriesColor'], + 'label-selector': ['fontSize', 'color', 'showDimension', 'showQuota', 'showProportion'], + 'legend-selector': ['icon', 'orient', 'fontSize', 'color', 'hPosition', 'vPosition'], + 'tooltip-selector': ['fontSize', 'color', 'backgroundColor', 'seriesTooltipFormatter', 'show'], + 'title-selector': [ + 'title', + 'fontSize', + 'color', + 'hPosition', + 'isItalic', + 'isBolder', + 'remarkShow', + 'fontFamily', + 'letterSpace', + 'fontShadow' + ] + } + axis: AxisType[] = ['xAxis', 'yAxis', 'filter', 'drill', 'extLabel', 'extTooltip'] + axisConfig: AxisConfig = { + xAxis: { + name: `${t('chart.drag_block_treemap_label')} / ${t('chart.dimension')}`, + type: 'd' + }, + yAxis: { + name: `${t('chart.drag_block_treemap_size')} / ${t('chart.quota')}`, + limit: 1 + } + } + + async drawChart(drawOptions: G2PlotDrawOptions): Promise { + const { chart, container, action } = drawOptions + if (!chart.data?.data?.length) { + return + } + const data = chart.data.data + const baseOptions = { + data: { + name: 'root', + children: data + }, + colorField: 'name', + appendPadding: getPadding(chart), + interactions: [ + { + type: 'legend-active', + cfg: { + start: [{ trigger: 'legend-item:mouseenter', action: ['element-active:reset'] }], + end: [{ trigger: 'legend-item:mouseleave', action: ['element-active:reset'] }] + } + }, + { + type: 'legend-filter', + cfg: { + start: [ + { + trigger: 'legend-item:click', + action: [ + 'list-unchecked:toggle', + 'data-filter:filter', + 'element-active:reset', + 'element-highlight:reset' + ] + } + ] + } + }, + { + type: 'tooltip', + cfg: { + start: [{ trigger: 'element:mousemove', action: 'tooltip:show' }], + end: [{ trigger: 'element:mouseleave', action: 'tooltip:hide' }] + } + } + ] + } + const options = this.setupOptions(chart, baseOptions) + const { Treemap: G2Treemap } = await import('@antv/g2plot/esm/plots/treemap') + const newChart = new G2Treemap(container, options) + newChart.on('polygon:click', action) + return newChart + } + protected configTooltip(chart: Chart, options: TreemapOptions): TreemapOptions { + const { tooltip: tooltipAttr, label } = parseJson(chart.customAttr) + const { yAxis } = chart + if (!tooltipAttr.show) { + return { + ...options, + tooltip: false + } + } + const reserveDecimalCount = label.reserveDecimalCount + const seriesTotalMap = getTooltipSeriesTotalMap(options.data.children) + const formatterMap = tooltipAttr.seriesTooltipFormatter + ?.filter(i => i.show) + .reduce((pre, next) => { + pre[next.id] = next + return pre + }, {}) as Record + const tooltip: TreemapOptions['tooltip'] = { + showTitle: true, + title: () => undefined, + customItems(originalItems) { + let tooltipItems = originalItems + if (tooltipAttr.seriesTooltipFormatter?.length) { + tooltipItems = originalItems.filter(item => formatterMap[item.data.quotaList[0].id]) + } + const result = [] + const head = originalItems[0] + tooltipItems.forEach(item => { + const formatter = formatterMap[item.data.quotaList[0].id] ?? yAxis[0] + const value = valueFormatter(parseFloat(item.value as string), formatter.formatterCfg) + // sync with label + const percent = ( + Math.round((item.data.value / item.data.path[1].value) * 10000) / 100 + ).toFixed(reserveDecimalCount) + const name = isEmpty(formatter.chartShowName) ? formatter.name : formatter.chartShowName + result.push({ ...item, name, value: `${value ?? ''} (${percent}%)` }) + }) + head.data.dynamicTooltipValue?.forEach(item => { + const formatter = formatterMap[item.fieldId] + if (formatter) { + const total = seriesTotalMap[item.fieldId] + // sync with label + const percent = (Math.round((item.value / total) * 10000) / 100).toFixed( + reserveDecimalCount + ) + const value = valueFormatter(parseFloat(item.value), formatter.formatterCfg) + const name = isEmpty(formatter.chartShowName) ? formatter.name : formatter.chartShowName + result.push({ color: 'grey', name, value: `${value ?? ''} (${percent}%)` }) + } + }) + return result + } + } + return { + ...options, + tooltip + } + } + protected configLabel(chart: Chart, options: TreemapOptions): TreemapOptions { + const customAttr: DeepPartial = parseJson(chart.customAttr) + const labelAttr = customAttr.label + if (!labelAttr.show) { + return { + ...options, + label: false + } + } + const label: Label = { + style: { + fill: labelAttr.color, + fontSize: labelAttr.fontSize + }, + formatter: function (param: Datum) { + let res = param.value + const contentItems = [] + if (labelAttr.showDimension) { + contentItems.push(param.field) + } + if (labelAttr.showQuota) { + contentItems.push(valueFormatter(param.value, labelAttr.quotaLabelFormatter)) + } + if (labelAttr.showProportion) { + const percentage = `${(((param.value / param.parent.value) * 10000) / 100).toFixed( + labelAttr.reserveDecimalCount + )}%` + contentItems.push(percentage) + } + res = contentItems.join('\n') + return res + } + } + if (labelAttr.fullDisplay) { + label.layout = [{ type: 'limit-in-plot' }] + } + return { ...options, label } + } + + setupDefaultOptions(chart: ChartObj): ChartObj { + const { customAttr, customStyle } = chart + const { label } = customAttr + customAttr.label = { + ...label, + show: true, + showDimension: true, + showProportion: true, + reserveDecimalCount: 2 + } + const { legend } = customStyle + legend.show = false + return chart + } + public setupSeriesColor(chart: ChartObj, data?: any[]): ChartBasicStyle['seriesColor'] { + data?.sort((a, b) => b.value - a.value) + return setUpSingleDimensionSeriesColor(chart, data) + } + protected configColor(chart: Chart, options: TreemapOptions): TreemapOptions { + const data = options.data.children + data.sort((a, b) => b.value - a.value) + const tmpOptions = this.configSingleDimensionColor(chart, { ...options, data }) + return { ...options, color: tmpOptions.color } + } + protected setupOptions(chart: Chart, options: TreemapOptions): TreemapOptions { + return flow( + this.configTheme, + this.configColor, + this.configLabel, + this.configTooltip, + this.configLegend + )(chart, options, {}, this) + } + + constructor() { + super('treemap', []) + } +} diff --git a/frontend/src/data-visualization/chart/components/js/panel/charts/others/word-cloud.ts b/frontend/src/data-visualization/chart/components/js/panel/charts/others/word-cloud.ts new file mode 100644 index 0000000..0baf181 --- /dev/null +++ b/frontend/src/data-visualization/chart/components/js/panel/charts/others/word-cloud.ts @@ -0,0 +1,184 @@ +import { + G2PlotChartView, + G2PlotDrawOptions +} from '@/data-visualization/chart/components/js/panel/types/impl/g2plot' +import type { WordCloud as G2WordCloud, WordCloudOptions } from '@antv/g2plot/esm/plots/word-cloud' +import { + filterChartDataByRange, + flow, + getMaxAndMinValueByData, + parseJson +} from '@/data-visualization/chart/components/js/util' +import { getPadding } from '@/data-visualization/chart/components/js/panel/common/common_antv' +import { valueFormatter } from '@/data-visualization/chart/components/js/formatter' +import { useI18n } from '@/data-visualization/hooks/web/useI18n' +import { isEmpty } from 'lodash-es' +import { DEFAULT_MISC } from '@/data-visualization/chart/components/editor/util/chart' + +const { t } = useI18n() +const DEFAULT_DATA = [] +/** + * 词云图 + */ +export class WordCloud extends G2PlotChartView { + properties: EditorProperty[] = [ + 'basic-style-selector', + 'background-overall-component', + 'border-style', + 'title-selector', + 'tooltip-selector', + 'misc-selector', + 'jump-set', + 'linkage' + ] + propertyInner: EditorPropertyInner = { + 'background-overall-component': ['all'], + 'border-style': ['all'], + 'basic-style-selector': ['colors', 'alpha'], + 'title-selector': [ + 'title', + 'fontSize', + 'color', + 'hPosition', + 'isItalic', + 'isBolder', + 'remarkShow', + 'fontFamily', + 'letterSpace', + 'fontShadow' + ], + 'misc-selector': ['wordSizeRange', 'wordSpacing', 'wordCloudAxisValueRange'], + 'tooltip-selector': ['color', 'fontSize', 'backgroundColor', 'seriesTooltipFormatter', 'show'] + } + axis: AxisType[] = ['xAxis', 'yAxis', 'filter'] + axisConfig: AxisConfig = { + xAxis: { + name: `${t('chart.drag_block_word_cloud_label')} / ${t('chart.dimension_or_quota')}`, + type: 'd', + limit: 1 + }, + yAxis: { + name: `${t('chart.drag_block_word_cloud_size')} / ${t('chart.quota')}`, + type: 'q', + limit: 1 + } + } + setDataRange = (action, maxValue, minValue) => { + action({ + from: 'word-cloud', + data: { + max: maxValue, + min: minValue + } + }) + } + async drawChart(drawOptions: G2PlotDrawOptions): Promise { + const { chart, container, action } = drawOptions + if (chart?.data) { + // data + let data = chart.data.data + const { misc } = parseJson(chart.customAttr) + let minValue = 0 + let maxValue = 0 + if ( + !misc.wordCloudAxisValueRange?.auto && + misc.wordCloudAxisValueRange?.fieldId === chart.yAxis[0].id + ) { + minValue = misc.wordCloudAxisValueRange.min + maxValue = misc.wordCloudAxisValueRange.max + } + getMaxAndMinValueByData(data ?? [], 'value', maxValue, minValue, (max, min) => { + maxValue = max + minValue = min + }) + data = filterChartDataByRange(data ?? [], maxValue, minValue) + // options + const initOptions: WordCloudOptions = { + data: data, + wordField: 'field', + weightField: 'value', + colorField: 'field', + wordStyle: { + fontFamily: chart.fontFamily ? chart.fontFamily : 'Verdana', + fontSize: (misc.wordSizeRange ?? DEFAULT_MISC.wordSizeRange) as [number, number], + rotation: [0, 0], + padding: misc.wordSpacing ?? DEFAULT_MISC.wordSpacing + }, + random: () => 0.5, + appendPadding: getPadding(chart), + legend: false, + interactions: [] + } + const options = this.setupOptions(chart, initOptions) + const { WordCloud: G2WordCloud } = await import('@antv/g2plot/esm/plots/word-cloud') + const newChart = new G2WordCloud(container, options) + newChart.on('click', () => { + this.setDataRange(action, maxValue, minValue) + }) + newChart.on('afterrender', () => { + this.setDataRange(action, maxValue, minValue) + }) + newChart.on('point:click', param => { + action({ x: param.x, y: param.y, data: { data: param.data.data.datum } }) + }) + return newChart + } + } + + protected configTooltip(chart: Chart, options: WordCloudOptions): WordCloudOptions { + const customAttr: DeepPartial = parseJson(chart.customAttr) + const tooltipAttr = customAttr.tooltip + const yAxis = chart.yAxis + if (!tooltipAttr.show) { + return { + ...options, + tooltip: false + } + } + const formatterMap = tooltipAttr.seriesTooltipFormatter + ?.filter(i => i.show) + .reduce((pre, next) => { + pre[next.id] = next + return pre + }, {}) as Record + const tooltip: WordCloudOptions['tooltip'] = { + showTitle: true, + title: () => undefined, + customItems(originalItems) { + let tooltipItems = originalItems + if (tooltipAttr.seriesTooltipFormatter?.length) { + tooltipItems = originalItems.filter(item => formatterMap[item.data.datum.quotaList[0].id]) + } + const result = [] + const head = originalItems[0] + tooltipItems.forEach(item => { + const formatter = formatterMap[item.data.datum.quotaList[0].id] ?? yAxis[0] + const value = valueFormatter(item.value, formatter.formatterCfg) + const name = isEmpty(formatter.chartShowName) ? formatter.name : formatter.chartShowName + result.push({ ...item, name, value }) + }) + head.data.datum.dynamicTooltipValue?.forEach(item => { + const formatter = formatterMap[item.fieldId] + if (formatter) { + const value = valueFormatter(parseFloat(item.value), formatter.formatterCfg) + const name = isEmpty(formatter.chartShowName) ? formatter.name : formatter.chartShowName + result.push({ color: 'grey', name, value }) + } + }) + return result + } + } + return { + ...options, + tooltip + } + } + + protected setupOptions(chart: Chart, options: WordCloudOptions): WordCloudOptions { + return flow(this.configTheme, this.configTooltip)(chart, options) + } + + constructor() { + super('word-cloud', DEFAULT_DATA) + } +} diff --git a/frontend/src/data-visualization/chart/components/js/panel/charts/pie/common.ts b/frontend/src/data-visualization/chart/components/js/panel/charts/pie/common.ts new file mode 100644 index 0000000..f8b808d --- /dev/null +++ b/frontend/src/data-visualization/chart/components/js/panel/charts/pie/common.ts @@ -0,0 +1,63 @@ +import { useI18n } from '@/data-visualization/hooks/web/useI18n' + +const { t } = useI18n() + +export const PIE_EDITOR_PROPERTY: EditorProperty[] = [ + 'background-overall-component', + 'border-style', + 'basic-style-selector', + 'title-selector', + 'legend-selector', + 'label-selector', + 'tooltip-selector', + 'jump-set', + 'linkage' +] +export const PIE_EDITOR_PROPERTY_INNER: EditorPropertyInner = { + 'background-overall-component': ['all'], + 'border-style': ['all'], + 'label-selector': [ + 'fontSize', + 'color', + 'rPosition', + 'showDimension', + 'showQuota', + 'showProportion' + ], + 'tooltip-selector': ['fontSize', 'color', 'backgroundColor', 'seriesTooltipFormatter', 'show'], + 'basic-style-selector': ['colors', 'alpha', 'radius', 'seriesColor'], + 'title-selector': [ + 'title', + 'fontSize', + 'color', + 'hPosition', + 'isItalic', + 'isBolder', + 'remarkShow', + 'fontFamily', + 'letterSpace', + 'fontShadow' + ], + 'legend-selector': ['icon', 'orient', 'fontSize', 'color', 'hPosition', 'vPosition'] +} + +export const PIE_AXIS_TYPE: AxisType[] = [ + 'xAxis', + 'yAxis', + 'drill', + 'filter', + 'extLabel', + 'extTooltip' +] + +export const PIE_AXIS_CONFIG: AxisConfig = { + xAxis: { + name: `${t('chart.drag_block_pie_label')} / ${t('chart.dimension')}`, + type: 'd' + }, + yAxis: { + name: `${t('chart.drag_block_pie_angle')} / ${t('chart.quota')}`, + type: 'q', + limit: 1 + } +} diff --git a/frontend/src/data-visualization/chart/components/js/panel/charts/pie/pie.ts b/frontend/src/data-visualization/chart/components/js/panel/charts/pie/pie.ts new file mode 100644 index 0000000..0263080 --- /dev/null +++ b/frontend/src/data-visualization/chart/components/js/panel/charts/pie/pie.ts @@ -0,0 +1,356 @@ +import { + G2PlotChartView, + G2PlotDrawOptions +} from '@/data-visualization/chart/components/js/panel/types/impl/g2plot' +import type { Pie as G2Pie, PieOptions } from '@antv/g2plot/esm/plots/pie' +import { + flow, + hexColorToRGBA, + parseJson, + setUpSingleDimensionSeriesColor +} from '@/data-visualization/chart/components/js/util' +import { + configPlotTooltipEvent, + getPadding, + getTooltipContainer, + getTooltipSeriesTotalMap, + TOOLTIP_TPL +} from '@/data-visualization/chart/components/js/panel/common/common_antv' +import { valueFormatter } from '@/data-visualization/chart/components/js/formatter' +import { + PIE_AXIS_CONFIG, + PIE_AXIS_TYPE, + PIE_EDITOR_PROPERTY, + PIE_EDITOR_PROPERTY_INNER +} from '@/data-visualization/chart/components/js/panel/charts/pie/common' +import type { Datum } from '@antv/g2plot/esm/types/common' +import { add } from 'mathjs' +import isEmpty from 'lodash-es/isEmpty' +import { cloneDeep } from 'lodash-es' + +const DEFAULT_DATA = [] +export class Pie extends G2PlotChartView { + axis: AxisType[] = PIE_AXIS_TYPE + properties = PIE_EDITOR_PROPERTY + propertyInner: EditorPropertyInner = { + ...PIE_EDITOR_PROPERTY_INNER, + 'basic-style-selector': ['colors', 'alpha', 'radius', 'topN', 'seriesColor'] + } + axisConfig = PIE_AXIS_CONFIG + + async drawChart(drawOptions: G2PlotDrawOptions): Promise { + const { chart, container, action } = drawOptions + if (!chart.data?.data?.length) { + return + } + // data + const data = chart.data.data + // custom color + const customAttr = parseJson(chart.customAttr) + const color = customAttr.basicStyle.colors.map(i => + hexColorToRGBA(i, customAttr.basicStyle.alpha) + ) + // options + const initOptions: PieOptions = { + data: data, + angleField: 'value', + colorField: 'field', + appendPadding: getPadding(chart), + color, + animation: false, + pieStyle: { + lineWidth: 0 + }, + statistic: { + title: false, + content: { + style: { + whiteSpace: 'pre-wrap', + overflow: 'hidden', + textOverflow: 'ellipsis' + }, + content: '' + } + }, + interactions: [ + { + type: 'legend-active', + cfg: { + start: [{ trigger: 'legend-item:mouseenter', action: ['element-active:reset'] }], + end: [{ trigger: 'legend-item:mouseleave', action: ['element-active:reset'] }] + } + }, + { + type: 'legend-filter', + cfg: { + start: [ + { + trigger: 'legend-item:click', + action: [ + 'list-unchecked:toggle', + 'data-filter:filter', + 'element-active:reset', + 'element-highlight:reset' + ] + } + ] + } + }, + { + type: 'tooltip', + cfg: { + start: [{ trigger: 'interval:mousemove', action: 'tooltip:show' }], + end: [{ trigger: 'interval:mouseleave', action: 'tooltip:hide' }] + } + }, + { + type: 'active-region', + cfg: { + start: [{ trigger: 'interval:mousemove', action: 'active-region:show' }], + end: [{ trigger: 'interval:mouseleave', action: 'active-region:hide' }] + } + } + ], + meta: { + field: { + type: 'cat' + } + } + } + const options = this.setupOptions(chart, initOptions) + const { Pie: G2Pie } = await import('@antv/g2plot/esm/plots/pie') + const newChart = new G2Pie(container, options) + newChart.on('interval:click', action) + configPlotTooltipEvent(chart, newChart) + return newChart + } + + protected configLabel(chart: Chart, options: PieOptions): PieOptions { + const { label: labelAttr } = parseJson(chart.customAttr) + if (!labelAttr?.show) { + return { + ...options, + label: false + } + } + const layout = [] + let textAlign = undefined + if (labelAttr.position === 'inner') { + textAlign = 'center' + if (labelAttr.fullDisplay) { + layout.push({ type: 'limit-in-plot' }) + } else { + layout.push({ type: 'limit-in-canvas' }) + layout.push({ type: 'hide-overlap' }) + } + } else { + if (!labelAttr.fullDisplay) { + layout.push({ type: 'limit-in-plot' }) + } + } + let labelType = labelAttr.position === 'outer' ? 'spider' : labelAttr.position + if (layout.length === 0) { + labelType = 'no' + } + const label = { + type: labelType, + textAlign, + layout, + autoRotate: false, + style: { + fill: labelAttr.color, + fontSize: labelAttr.fontSize + }, + formatter: (param: Datum) => { + let res = param.value + const contentItems = [] + if (labelAttr.showDimension) { + contentItems.push(param.field) + } + if (labelAttr.showQuota) { + contentItems.push(valueFormatter(param.value, labelAttr.quotaLabelFormatter)) + } + if (labelAttr.showProportion) { + const percentage = `${(Math.round(param.percent * 10000) / 100).toFixed( + labelAttr.reserveDecimalCount + )}%` + if (labelAttr.showDimension && labelAttr.showQuota) { + contentItems.push(`(${percentage})`) + } else { + contentItems.push(percentage) + } + } + res = contentItems.join(' ') + return res + } + } + return { ...options, label } + } + + protected configTooltip(chart: Chart, options: PieOptions): PieOptions { + const { tooltip: tooltipAttr, label } = parseJson(chart.customAttr) + const { yAxis } = chart + if (!tooltipAttr.show) { + return { + ...options, + tooltip: false + } + } + const reserveDecimalCount = label.reserveDecimalCount + const seriesTotalMap = getTooltipSeriesTotalMap(options.data) + // trick, cal total, maybe use scale of chart in plot instance + const total = options.data?.reduce((pre, next) => add(pre, next.value ?? 0), 0) + const formatterMap = tooltipAttr.seriesTooltipFormatter + ?.filter(i => i.show) + .reduce((pre, next) => { + pre[next.id] = next + return pre + }, {}) as Record + const tooltip: PieOptions['tooltip'] = { + showTitle: true, + title: () => undefined, + customItems(originalItems) { + let tooltipItems = originalItems + if (tooltipAttr.seriesTooltipFormatter?.length) { + tooltipItems = originalItems.filter(item => formatterMap[item.data.quotaList[0].id]) + } + const result = [] + const head = originalItems[0] + tooltipItems.forEach(item => { + const formatter = formatterMap[item.data.quotaList[0].id] ?? yAxis[0] + const originValue = parseFloat(item.value as string) + const value = valueFormatter(originValue, formatter.formatterCfg) + // sync with label + const percent = (Math.round((originValue / total) * 10000) / 100).toFixed( + reserveDecimalCount + ) + const name = isEmpty(formatter.chartShowName) ? formatter.name : formatter.chartShowName + result.push({ ...item, name, value: `${value ?? ''} (${percent}%)` }) + }) + head.data.dynamicTooltipValue?.forEach(item => { + const formatter = formatterMap[item.fieldId] + if (formatter) { + const total = seriesTotalMap[item.fieldId] + // sync with label + const percent = (Math.round((item.value / total) * 10000) / 100).toFixed( + reserveDecimalCount + ) + const value = valueFormatter(parseFloat(item.value), formatter.formatterCfg) + const name = isEmpty(formatter.chartShowName) ? formatter.name : formatter.chartShowName + result.push({ color: 'grey', name, value: `${value ?? ''} (${percent}%)` }) + } + }) + return result + }, + container: getTooltipContainer(`tooltip-${chart.id}`), + itemTpl: TOOLTIP_TPL, + enterable: true + } + return { + ...options, + tooltip + } + } + + protected configBasicStyle(chart: Chart, options: PieOptions): PieOptions { + const customAttr = parseJson(chart.customAttr) + const { basicStyle } = customAttr + const { data } = options + if (data?.length && basicStyle.calcTopN && data.length > basicStyle.topN) { + data.sort((a, b) => b.value - a.value) + const otherItems = data.splice(basicStyle.topN) + const initOtherItem = { + ...data[0], + dynamicTooltipValue: [], + field: basicStyle.topNLabel, + name: basicStyle.topNLabel, + value: 0 + } + const dynamicTotalMap: Record = {} + otherItems.reduce((p, n) => { + p.value += n.value ?? 0 + n.dynamicTooltipValue?.forEach(val => { + dynamicTotalMap[val.fieldId] = (dynamicTotalMap[val.fieldId] || 0) + val.value + }) + return p + }, initOtherItem) + for (const key in dynamicTotalMap) { + initOtherItem.dynamicTooltipValue.push({ + fieldId: key, + value: dynamicTotalMap[key] + }) + } + data.push(initOtherItem) + } + return { + ...options, + radius: basicStyle.radius / 100 + } + } + setupDefaultOptions(chart: ChartObj): ChartObj { + const { customAttr, customStyle } = chart + const { label } = customAttr + if (!['inner', 'outer'].includes(label.position)) { + label.position = 'outer' + } + customAttr.label = { + ...label, + show: true, + showDimension: true, + showProportion: true, + reserveDecimalCount: 2 + } + const { legend } = customStyle + legend.show = false + return chart + } + + public setupSeriesColor(chart: ChartObj, data?: any[]): ChartBasicStyle['seriesColor'] { + data = cloneDeep(data) + const { calcTopN, topN, topNLabel } = chart.customAttr.basicStyle + if (data?.length && calcTopN && data.length > topN) { + data.sort((a, b) => b.value - a.value) + data.splice(topN) + data.push({ + field: topNLabel, + value: 0 + }) + } + return setUpSingleDimensionSeriesColor(chart, data) + } + + protected setupOptions(chart: Chart, options: PieOptions): PieOptions { + return flow( + this.configTheme, + this.configBasicStyle, + this.configSingleDimensionColor, + this.configLabel, + this.configTooltip, + this.configLegend + )(chart, options, {}, this) + } + + constructor(name = 'pie') { + super(name, DEFAULT_DATA) + } +} + +export class PieDonut extends Pie { + propertyInner: EditorPropertyInner = { + ...PIE_EDITOR_PROPERTY_INNER, + 'basic-style-selector': ['colors', 'alpha', 'radius', 'innerRadius', 'topN', 'seriesColor'] + } + protected configBasicStyle(chart: Chart, options: PieOptions): PieOptions { + const tmp = super.configBasicStyle(chart, options) + const { basicStyle } = parseJson(chart.customAttr) + return { + ...tmp, + radius: basicStyle.radius / 100, + innerRadius: basicStyle.innerRadius / 100 + } + } + + constructor() { + super('pie-donut') + } +} diff --git a/frontend/src/data-visualization/chart/components/js/panel/charts/pie/rose.ts b/frontend/src/data-visualization/chart/components/js/panel/charts/pie/rose.ts new file mode 100644 index 0000000..0432ca7 --- /dev/null +++ b/frontend/src/data-visualization/chart/components/js/panel/charts/pie/rose.ts @@ -0,0 +1,285 @@ +import { + G2PlotChartView, + G2PlotDrawOptions +} from '@/data-visualization/chart/components/js/panel/types/impl/g2plot' +import { RoseOptions, Rose as G2Rose } from '@antv/g2plot/esm/plots/rose' +import { + PIE_AXIS_CONFIG, + PIE_AXIS_TYPE, + PIE_EDITOR_PROPERTY, + PIE_EDITOR_PROPERTY_INNER +} from './common' +import { + configPlotTooltipEvent, + getPadding, + getTooltipContainer, + getTooltipSeriesTotalMap, + TOOLTIP_TPL +} from '@/data-visualization/chart/components/js/panel/common/common_antv' +import { parseJson, flow, setUpSingleDimensionSeriesColor } from '@/data-visualization/chart/components/js/util' +import { Label } from '@antv/g2plot/lib/types/label' +import { valueFormatter } from '@/data-visualization/chart/components/js/formatter' +import { Datum } from '@antv/g2plot/esm/types/common' +import { add } from 'mathjs' +import isEmpty from 'lodash-es/isEmpty' +import { useI18n } from '@/data-visualization/hooks/web/useI18n' +const { t } = useI18n() + +export class Rose extends G2PlotChartView { + axis: AxisType[] = PIE_AXIS_TYPE + properties: EditorProperty[] = PIE_EDITOR_PROPERTY + propertyInner: EditorPropertyInner = PIE_EDITOR_PROPERTY_INNER + axisConfig: AxisConfig = { + ...PIE_AXIS_CONFIG, + yAxis: { + name: `${t('chart.drag_block_pie_radius')} / ${t('chart.quota')}`, + type: 'q', + limit: 1 + } + } + + async drawChart(drawOptions: G2PlotDrawOptions): Promise { + const { chart, container, action } = drawOptions + if (!chart?.data?.data?.length) { + return + } + // data + const data = chart.data.data + // options + const baseOptions: RoseOptions = { + data: data, + xField: 'field', + yField: 'value', + seriesField: 'field', + appendPadding: getPadding(chart), + interactions: [ + { + type: 'legend-active', + cfg: { + start: [{ trigger: 'legend-item:mouseenter', action: ['element-active:reset'] }], + end: [{ trigger: 'legend-item:mouseleave', action: ['element-active:reset'] }] + } + }, + { + type: 'legend-filter', + cfg: { + start: [ + { + trigger: 'legend-item:click', + action: [ + 'list-unchecked:toggle', + 'data-filter:filter', + 'element-active:reset', + 'element-highlight:reset' + ] + } + ] + } + }, + { + type: 'tooltip', + cfg: { + start: [{ trigger: 'interval:mousemove', action: 'tooltip:show' }], + end: [{ trigger: 'interval:mouseleave', action: 'tooltip:hide' }] + } + } + ], + meta: { + field: { + type: 'cat' + } + } + } + const options = this.setupOptions(chart, baseOptions) + + const { Rose: G2Rose } = await import('@antv/g2plot/esm/plots/rose') + // 开始渲染 + const plot = new G2Rose(container, options) + + plot.on('interval:click', action) + configPlotTooltipEvent(chart, plot) + return plot + } + + protected configBasicStyle(chart: Chart, options: RoseOptions): RoseOptions { + const { basicStyle } = parseJson(chart.customAttr) + return { + ...options, + radius: basicStyle.radius / 100 + } + } + + protected configLabel(chart: Chart, options: RoseOptions): RoseOptions { + const { label: labelAttr } = parseJson(chart.customAttr) + if (!labelAttr.show) { + return { + ...options, + label: false + } + } + const total = options.data?.reduce((pre, next) => add(pre, next.value ?? 0), 0) + const layout = [] + if (!labelAttr.fullDisplay) { + const tmpOptions = super.configLabel(chart, options) + layout.push(...tmpOptions.label.layout) + } + const labelOptions: Label = { + autoRotate: true, + layout, + style: { + fill: labelAttr.color, + fontSize: labelAttr.fontSize + }, + formatter: (param: Datum) => { + let res = param.value + const contentItems = [] + if (labelAttr.showDimension) { + contentItems.push(param.field) + } + if (labelAttr.showQuota) { + contentItems.push(valueFormatter(param.value, labelAttr.quotaLabelFormatter)) + } + if (labelAttr.showProportion) { + const percentage = `${(Math.round((param.value / total) * 10000) / 100).toFixed( + labelAttr.reserveDecimalCount + )}%` + if (labelAttr.showDimension && labelAttr.showQuota) { + contentItems.push(`(${percentage})`) + } else { + contentItems.push(percentage) + } + } + res = contentItems.join('\n') + return res + } + } + if (labelAttr.position === 'inner') { + labelOptions.offset = -10 + } + return { + ...options, + label: labelOptions + } + } + + protected configTooltip(chart: Chart, options: RoseOptions): RoseOptions { + const { tooltip: tooltipAttr, label } = parseJson(chart.customAttr) + const { yAxis } = chart + if (!tooltipAttr.show) { + return { + ...options, + tooltip: false + } + } + const reserveDecimalCount = label.reserveDecimalCount + const seriesTotalMap = getTooltipSeriesTotalMap(options.data) + // trick, cal total, maybe use scale of chart in plot instance + const total = options.data?.reduce((pre, next) => add(pre, next.value ?? 0), 0) + const formatterMap = tooltipAttr.seriesTooltipFormatter + ?.filter(i => i.show) + .reduce((pre, next) => { + pre[next.id] = next + return pre + }, {}) as Record + const tooltip: RoseOptions['tooltip'] = { + showTitle: true, + title: () => undefined, + customItems(originalItems) { + let tooltipItems = originalItems + if (tooltipAttr.seriesTooltipFormatter?.length) { + tooltipItems = originalItems.filter(item => formatterMap[item.data.quotaList[0].id]) + } + const result = [] + const head = originalItems[0] + tooltipItems.forEach(item => { + const formatter = formatterMap[item.data.quotaList[0].id] ?? yAxis[0] + const originValue = parseFloat(item.value as string) + const value = valueFormatter(originValue, formatter.formatterCfg) + // sync with label + const percent = (Math.round((originValue / total) * 10000) / 100).toFixed( + reserveDecimalCount + ) + const name = isEmpty(formatter.chartShowName) ? formatter.name : formatter.chartShowName + result.push({ ...item, name, value: `${value ?? ''} (${percent}%)` }) + }) + head.data.dynamicTooltipValue?.forEach(item => { + const formatter = formatterMap[item.fieldId] + if (formatter) { + const total = seriesTotalMap[item.fieldId] + // sync with label + const percent = (Math.round((item.value / total) * 10000) / 100).toFixed( + reserveDecimalCount + ) + const value = valueFormatter(parseFloat(item.value), formatter.formatterCfg) + const name = isEmpty(formatter.chartShowName) ? formatter.name : formatter.chartShowName + result.push({ color: 'grey', name, value: `${value ?? ''} (${percent}%)` }) + } + }) + return result + }, + container: getTooltipContainer(`tooltip-${chart.id}`), + itemTpl: TOOLTIP_TPL, + enterable: true + } + return { + ...options, + tooltip + } + } + + setupDefaultOptions(chart: ChartObj): ChartObj { + const { customAttr, customStyle } = chart + const { label } = customAttr + if (!['inner', 'outer'].includes(label.position)) { + label.position = 'outer' + } + customAttr.label = { + ...label, + show: true, + showDimension: true, + showProportion: true, + reserveDecimalCount: 2 + } + const { legend } = customStyle + legend.show = false + return chart + } + + public setupSeriesColor(chart: ChartObj, data?: any[]): ChartBasicStyle['seriesColor'] { + return setUpSingleDimensionSeriesColor(chart, data) + } + + protected setupOptions(chart: Chart, options: RoseOptions): RoseOptions { + return flow( + this.configBasicStyle, + this.configSingleDimensionColor, + this.configTheme, + this.configLabel, + this.configLegend, + this.configTooltip + )(chart, options) + } + + constructor(name = 'pie-rose') { + super(name, []) + } +} + +export class RoseDonut extends Rose { + propertyInner: EditorPropertyInner = { + ...PIE_EDITOR_PROPERTY_INNER, + 'basic-style-selector': ['colors', 'alpha', 'radius', 'innerRadius', 'seriesColor'] + } + protected configBasicStyle(chart: Chart, options: RoseOptions): RoseOptions { + const customAttr = parseJson(chart.customAttr) + return { + ...options, + radius: customAttr.basicStyle.radius / 100, + innerRadius: customAttr.basicStyle.innerRadius / 100 + } + } + + constructor() { + super('pie-donut-rose') + } +} diff --git a/frontend/src/data-visualization/chart/components/js/panel/charts/table/common.ts b/frontend/src/data-visualization/chart/components/js/panel/charts/table/common.ts new file mode 100644 index 0000000..08b146e --- /dev/null +++ b/frontend/src/data-visualization/chart/components/js/panel/charts/table/common.ts @@ -0,0 +1,58 @@ +export const TABLE_EDITOR_PROPERTY: EditorProperty[] = [ + 'background-overall-component', + 'border-style', + 'basic-style-selector', + 'table-header-selector', + 'table-cell-selector', + 'title-selector', + 'tooltip-selector', + 'function-cfg', + 'threshold', + 'scroll-cfg', + 'jump-set', + 'linkage' +] +export const TABLE_EDITOR_PROPERTY_INNER: EditorPropertyInner = { + 'border-style': ['all'], + 'background-overall-component': ['all'], + 'basic-style-selector': ['tableColumnMode', 'tableBorderColor', 'tableScrollBarColor', 'alpha'], + 'table-header-selector': [ + 'tableHeaderBgColor', + 'tableTitleFontSize', + 'tableHeaderFontColor', + 'tableTitleHeight', + 'tableHeaderAlign', + 'showIndex', + 'indexLabel', + 'showColTooltip', + 'showHorizonBorder', + 'showVerticalBorder' + ], + 'table-cell-selector': [ + 'tableItemBgColor', + 'tableItemFontSize', + 'tableFontColor', + 'tableItemAlign', + 'tableItemHeight', + 'enableTableCrossBG', + 'tableItemSubBgColor', + 'showTooltip', + 'showHorizonBorder', + 'showVerticalBorder' + ], + 'title-selector': [ + 'title', + 'fontSize', + 'color', + 'hPosition', + 'isItalic', + 'isBolder', + 'remarkShow', + 'fontFamily', + 'letterSpace', + 'fontShadow' + ], + 'tooltip-selector': ['fontSize', 'color', 'backgroundColor', 'show'], + 'function-cfg': ['emptyDataStrategy'], + threshold: ['tableThreshold'] +} diff --git a/frontend/src/data-visualization/chart/components/js/panel/charts/table/t-heatmap.ts b/frontend/src/data-visualization/chart/components/js/panel/charts/table/t-heatmap.ts new file mode 100644 index 0000000..8750439 --- /dev/null +++ b/frontend/src/data-visualization/chart/components/js/panel/charts/table/t-heatmap.ts @@ -0,0 +1,362 @@ +import { + G2PlotChartView, + G2PlotDrawOptions +} from '@/data-visualization/chart/components/js/panel/types/impl/g2plot' +import type { Heatmap, HeatmapOptions } from '@antv/g2plot/esm/plots/heatmap' +import { flow, hexColorToRGBA, parseJson } from '@/data-visualization/chart/components/js/util' +import { useI18n } from '@/data-visualization/hooks/web/useI18n' +import { deepCopy } from '@/data-visualization/utils/utils' +import { cloneDeep } from 'lodash-es' +import { + configAxisLabelLengthLimit, + getPadding, + getXAxis, + getYAxis +} from '@/data-visualization/chart/components/js/panel/common/common_antv' +import { valueFormatter } from '@/data-visualization/chart/components/js/formatter' + +const { t } = useI18n() +const DEFAULT_DATA = [] +/** + * 热力图 + */ +export class TableHeatmap extends G2PlotChartView { + properties: EditorProperty[] = [ + 'basic-style-selector', + 'background-overall-component', + 'label-selector', + 'legend-selector', + 'x-axis-selector', + 'y-axis-selector', + 'title-selector', + 'tooltip-selector', + 'jump-set', + 'linkage', + 'border-style' + ] + propertyInner: EditorPropertyInner = { + 'background-overall-component': ['all'], + 'basic-style-selector': ['colors'], + 'label-selector': ['fontSize', 'color'], + 'x-axis-selector': ['name', 'color', 'fontSize', 'position', 'axisLabel', 'axisLine'], + 'y-axis-selector': [ + 'name', + 'color', + 'fontSize', + 'position', + 'axisLabel', + 'axisLine', + 'showLengthLimit' + ], + 'title-selector': [ + 'title', + 'fontSize', + 'color', + 'hPosition', + 'isItalic', + 'isBolder', + 'remarkShow', + 'fontFamily', + 'letterSpace', + 'fontShadow' + ], + 'legend-selector': ['orient', 'color', 'fontSize', 'hPosition', 'vPosition'], + 'tooltip-selector': ['show', 'color', 'fontSize', 'backgroundColor'], + 'border-style': ['all'] + } + axis: AxisType[] = ['xAxis', 'xAxisExt', 'extColor', 'filter'] + axisConfig: AxisConfig = { + xAxis: { + name: `${t('chart.x_axis')} / ${t('chart.dimension')}`, + type: 'd', + limit: 1 + }, + xAxisExt: { + name: `${t('chart.y_axis')} / ${t('chart.dimension')}`, + type: 'd', + limit: 1 + }, + extColor: { + name: `${t('chart.color')} / ${t('chart.dimension_or_quota')}`, + limit: 1 + } + } + protected getDefaultLength = (chart, l) => { + const containerDom = document.getElementById(chart.container) + const containerHeight = containerDom?.clientHeight || 100 + const containerWidth = containerDom?.clientWidth || 100 + let defaultLength = containerHeight - containerHeight * 0.5 + if (l.orient !== 'vertical') { + defaultLength = containerWidth - containerWidth * 0.5 + } + return defaultLength + } + protected sortData = (fieldObj, data) => { + const { deType, sort, customSort } = fieldObj + + if (sort === 'desc') { + if (deType === 0) { + return data.sort().reverse() + } else { + return data.sort((a, b) => b - a) + } + } else if (sort === 'asc') { + if (deType === 0) { + return data.sort() + } else { + return data.sort((a, b) => a - b) + } + } + + // 如果没有指定排序方式,直接返回原始数据或 customSort + return customSort && customSort.length > 0 ? customSort : data + } + async drawChart(drawOptions: G2PlotDrawOptions): Promise { + const { chart, container, action } = drawOptions + const xAxis = deepCopy(chart.xAxis) + const xAxisExt = deepCopy(chart.xAxisExt) + const extColor = deepCopy(chart.extColor) + if (!xAxis?.length || !xAxisExt?.length || !extColor?.length) { + return + } + const xField = xAxis[0].dataeaseName + const xFieldExt = xAxisExt[0].dataeaseName + const extColorField = extColor[0].dataeaseName + // data + const data = cloneDeep(chart.data.tableRow) + data.forEach(i => { + Object.keys(i).forEach(key => { + if (key === '*') { + i['@'] = i[key] + } + }) + }) + + // options + const initOptions: HeatmapOptions = { + data: data, + xField: xField, + yField: xFieldExt, + colorField: extColorField === '*' ? '@' : extColorField, + appendPadding: getPadding(chart), + meta: { + [xField]: { + type: 'cat', + values: this.sortData(xAxis[0], [...new Set(data.map(i => i[[xField]]))]) + }, + [xFieldExt]: { + type: 'cat', + values: this.sortData(xAxisExt[0], [...new Set(data.map(i => i[[xFieldExt]]))]).reverse() + } + }, + legend: { + layout: 'vertical', + position: 'right', + slidable: true, + label: { + align: 'left', + spacing: 10 + } + } + } + chart.container = container + const options = this.setupOptions(chart, initOptions) + const { Heatmap } = await import('@antv/g2plot/esm/plots/heatmap') + const newChart = new Heatmap(container, options) + newChart.on('plot:click', param => { + if (!param.data?.data) { + return + } + const pointData = param.data.data + const dimensionList = [] + chart.data.fields.forEach(item => { + Object.keys(pointData).forEach(key => { + if (key.startsWith('f_') && item.dataeaseName === key) { + dimensionList.push({ + id: item.id, + dataeaseName: item.dataeaseName, + value: pointData[key] + }) + } + }) + }) + action({ + x: param.data.x, + y: param.data.y, + data: { + data: { + ...param.data.data, + value: dimensionList[1].value, + name: dimensionList[1].id, + dimensionList: dimensionList, + quotaList: [dimensionList[1]] + } + } + }) + }) + newChart.on('afterrender', ev => { + const l = JSON.parse(JSON.stringify(parseJson(chart.customStyle).legend)) + if (l.show) { + const rail = ev.view.getController('legend').option[extColor[0].dataeaseName]?.['rail'] + if (rail) { + rail.defaultLength = this.getDefaultLength(chart, l) + } + } + }) + configAxisLabelLengthLimit(chart, newChart) + return newChart + } + + protected configBasicStyle(chart: Chart, options: HeatmapOptions): HeatmapOptions { + const basicStyle = parseJson(chart.customAttr).basicStyle + const color = basicStyle.colors?.map(ele => { + return hexColorToRGBA(ele, basicStyle.alpha) + }) + return { + ...options, + color + } + } + protected configTooltip(chart: Chart, options: HeatmapOptions): HeatmapOptions { + let tooltip + let customAttr: DeepPartial + if (chart.customAttr) { + customAttr = parseJson(chart.customAttr) + // tooltip + if (customAttr.tooltip) { + const extColor = deepCopy(chart.extColor) + const xAxisExt = deepCopy(chart.xAxisExt) + const tooltipFiledList = [xAxisExt, extColor] + const t = JSON.parse(JSON.stringify(customAttr.tooltip)) + if (t.show) { + tooltip = { + showTitle: true, + customItems(originalItems) { + const items = [] + const createItem = (fieldObj, items, originalItems) => { + const name = fieldObj?.chartShowName ? fieldObj?.chartShowName : fieldObj?.name + let value = originalItems[0].data[fieldObj.dataeaseName] + if (!isNaN(Number(value))) { + value = valueFormatter(value, fieldObj?.formatterCfg) + } + items.push({ + ...originalItems[0], + name: name, + value: value + }) + } + tooltipFiledList.forEach(field => { + createItem(field[0], items, originalItems) + }) + return items + } + } + } else { + tooltip = false + } + } + } + return { + ...options, + tooltip + } + } + + protected configXAxis(chart: Chart, options: HeatmapOptions): HeatmapOptions { + const xAxis = getXAxis(chart) + return { + ...options, + xAxis: xAxis ? { ...xAxis, grid: null } : false + } + } + + protected configYAxis(chart: Chart, options: HeatmapOptions): HeatmapOptions { + const yAxis = getYAxis(chart) + return { + ...options, + yAxis: yAxis ? { ...yAxis, grid: null } : false + } + } + + protected configLegend(chart: Chart, options: HeatmapOptions): HeatmapOptions { + const tmpOptions = super.configLegend(chart, options) + if (tmpOptions.legend) { + const l = JSON.parse(JSON.stringify(parseJson(chart.customStyle).legend)) + tmpOptions.legend.slidable = true + tmpOptions.legend.minHeight = 10 + tmpOptions.legend.minWidth = 10 + tmpOptions.legend.maxHeight = 600 + tmpOptions.legend.maxWidth = 600 + const containerDom = document.getElementById(chart.container) + const containerHeight = containerDom?.clientHeight || 100 + const containerWidth = containerDom?.clientWidth || 100 + let defaultLength = containerHeight - containerHeight * 0.5 + if (l.orient === 'vertical') { + tmpOptions.legend.offsetY = -5 + } else { + defaultLength = containerWidth - containerWidth * 0.5 + } + tmpOptions.legend.rail = { defaultLength: defaultLength } + tmpOptions.legend.label = { + spacing: 10, + style: { + fill: l.color, + fontSize: l.fontSize + } + } + } + return tmpOptions + } + + setupDefaultOptions(chart: ChartObj): ChartObj { + chart.customStyle.legend.orient = 'vertical' + chart.customStyle.legend.vPosition = 'center' + chart.customStyle.legend.hPosition = 'right' + chart.customStyle.legend['rail'] = { defaultLength: 100 } + return chart + } + + protected configLabel(chart: Chart, options: HeatmapOptions): HeatmapOptions { + const tmpOptions = super.configLabel(chart, options) + if (tmpOptions.label) { + const extColor = deepCopy(chart.extColor) + const layout = [] + if (!tmpOptions.label.fullDisplay) { + layout.push(...tmpOptions.label.layout) + } + const label = { + ...tmpOptions.label, + position: 'middle', + layout, + formatter: data => { + const value = data[extColor[0]?.dataeaseName] + if (!isNaN(Number(value))) { + return valueFormatter(value, extColor[0]?.formatterCfg) + } + return value + } + } + return { + ...tmpOptions, + label + } + } + return tmpOptions + } + + protected setupOptions(chart: Chart, options: HeatmapOptions): HeatmapOptions { + return flow( + this.configTheme, + this.configXAxis, + this.configYAxis, + this.configBasicStyle, + this.configLegend, + this.configTooltip, + this.configLabel + )(chart, options) + } + + constructor() { + super('t-heatmap', DEFAULT_DATA) + } +} diff --git a/frontend/src/data-visualization/chart/components/js/panel/charts/table/table-info.ts b/frontend/src/data-visualization/chart/components/js/panel/charts/table/table-info.ts new file mode 100644 index 0000000..0485bcd --- /dev/null +++ b/frontend/src/data-visualization/chart/components/js/panel/charts/table/table-info.ts @@ -0,0 +1,510 @@ +import { + type LayoutResult, + S2DataConfig, + S2Event, + S2Options, + S2Theme, + ScrollbarPositionType, + TableColCell, + TableSheet, + ViewMeta +} from '@antv/s2' +import { formatterItem, valueFormatter } from '../../../formatter' +import { hexColorToRGBA, isAlphaColor, parseJson } from '../../../util' +import { S2ChartView, S2DrawOptions } from '../../types/impl/s2' +import { TABLE_EDITOR_PROPERTY, TABLE_EDITOR_PROPERTY_INNER } from './common' +import { useI18n } from '@/data-visualization/hooks/web/useI18n' +import { isEqual, isNumber, merge } from 'lodash-es' +import { + copyContent, + CustomDataCell, + CustomTableColCell, + getRowIndex, + calculateHeaderHeight, + SortTooltip, + configSummaryRow, + summaryRowStyle, + configEmptyDataStyle, + getLeafNodes, + getColumns +} from '@/data-visualization/chart/components/js/panel/common/common_table' + +const { t } = useI18n() +class ImageCell extends CustomDataCell { + protected drawTextShape(): void { + const img = new Image() + const { x, y, width, height, fieldValue } = this.meta + img.src = fieldValue as string + img.setAttribute('crossOrigin', 'anonymous') + img.onload = () => { + !this.cfg.children && (this.cfg.children = []) + const { width: imgWidth, height: imgHeight } = img + const ratio = Math.max(imgWidth / width, imgHeight / height) + // 不铺满,部分留白 + const imgShowWidth = (imgWidth / ratio) * 0.8 + const imgShowHeight = (imgHeight / ratio) * 0.8 + this.textShape = this.addShape('image', { + attrs: { + x: x + (imgShowWidth < width ? (width - imgShowWidth) / 2 : 0), + y: y + (imgShowHeight < height ? (height - imgShowHeight) / 2 : 0), + width: imgShowWidth, + height: imgShowHeight, + img + } + }) + } + } +} +/** + * 明细表 + */ +export class TableInfo extends S2ChartView { + properties = TABLE_EDITOR_PROPERTY + propertyInner = { + ...TABLE_EDITOR_PROPERTY_INNER, + 'table-header-selector': [ + ...TABLE_EDITOR_PROPERTY_INNER['table-header-selector'], + 'tableHeaderSort', + 'showTableHeader', + 'headerGroup' + ], + 'basic-style-selector': [ + 'tableColumnMode', + 'tableBorderColor', + 'tableScrollBarColor', + 'alpha', + 'tablePageMode', + 'showHoverStyle', + 'autoWrap', + 'showSummary', + 'summaryLabel' + ], + 'table-cell-selector': [ + ...TABLE_EDITOR_PROPERTY_INNER['table-cell-selector'], + 'tableFreeze', + 'tableColumnFreezeHead', + 'tableRowFreezeHead', + 'mergeCells' + ] + } + axis: AxisType[] = ['xAxis', 'filter', 'drill'] + axisConfig: AxisConfig = { + xAxis: { + name: `${t('chart.drag_block_table_data_column')} / ${t('chart.dimension_or_quota')}` + } + } + + public drawChart(drawOption: S2DrawOptions): TableSheet { + const { container, chart, pageInfo, action, resizeAction } = drawOption + const containerDom = document.getElementById(container) + + // fields + let fields = chart.data?.fields ?? [] + const columns = [] + const meta = [] + const axisMap = chart.xAxis.reduce((pre, cur) => { + pre[cur.dataeaseName] = cur + return pre + }, {}) + const drillFieldMap = {} + if (chart.drill) { + // 下钻过滤字段 + const filterFields = chart.drillFilters.map(i => i.fieldId) + // 下钻入口的字段下标 + const drillFieldId = chart.drillFields[0].id + const drillFieldIndex = chart.xAxis.findIndex(ele => ele.id === drillFieldId) + // 当前下钻字段 + const curDrillFieldId = chart.drillFields[filterFields.length].id + const curDrillField = fields.find(ele => ele.id === curDrillFieldId) + filterFields.push(curDrillFieldId) + // 移除下钻字段,把当前下钻字段插入到下钻入口位置 + fields = fields.filter(ele => { + return !filterFields.includes(ele.id) + }) + drillFieldMap[curDrillField.dataeaseName] = chart.drillFields[0].dataeaseName + fields.splice(drillFieldIndex, 0, curDrillField) + } + fields.forEach(ele => { + const f = axisMap[ele.dataeaseName] + if (f?.hide === true) { + return + } + columns.push(ele.dataeaseName) + meta.push({ + field: ele.dataeaseName, + name: ele.chartShowName ?? ele.name, + formatter: function (value) { + if (!f) { + return value + } + if (value === null || value === undefined) { + return value + } + if (![2, 3].includes(f.deType) || !isNumber(value)) { + return value + } + let formatCfg = f.formatterCfg + if (!formatCfg) { + formatCfg = formatterItem + } + return valueFormatter(value, formatCfg) + } + }) + }) + const { basicStyle, tableCell, tableHeader, tooltip } = parseJson(chart.customAttr) + // 表头分组 + const { headerGroup, showTableHeader } = tableHeader + if (headerGroup && showTableHeader !== false) { + const { headerGroupConfig } = tableHeader + if (headerGroupConfig?.columns?.length) { + const allKeys = columns.map(c => drillFieldMap[c] || c) + const leafNodes = getLeafNodes(headerGroupConfig.columns as ColumnNode[]) + const leafKeys = leafNodes.map(c => c.key) + if (isEqual(leafKeys, allKeys)) { + if (Object.keys(drillFieldMap).length) { + const originField = Object.values(drillFieldMap)[0] + const drillField = Object.keys(drillFieldMap)[0] + const [drillCol] = getColumns([originField], headerGroupConfig.columns as ColumnNode[]) + drillCol.key = drillField + } + columns.splice(0, columns.length, ...headerGroupConfig.columns) + meta.push(...headerGroupConfig.meta) + } + } + } + // 空值处理 + const newData = this.configEmptyDataStrategy(chart) + // data config + const s2DataConfig: S2DataConfig = { + fields: { + columns: columns + }, + meta: meta, + data: newData + } + + // options + const s2Options: S2Options = { + width: containerDom.getBoundingClientRect().width, + height: containerDom.offsetHeight, + showSeriesNumber: tableHeader.showIndex, + conditions: this.configConditions(chart), + tooltip: { + getContainer: () => containerDom, + renderTooltip: sheet => new SortTooltip(sheet) + }, + interaction: { + hoverHighlight: !(basicStyle.showHoverStyle === false), + scrollbarPosition: newData.length + ? ScrollbarPositionType.CONTENT + : ScrollbarPositionType.CANVAS + } + } + s2Options.style = this.configStyle(chart, s2DataConfig) + // 自适应列宽模式下,URL 字段的宽度固定为 120 + if (basicStyle.tableColumnMode === 'adapt') { + const urlFields = fields.filter( + field => field.deType === 7 && !axisMap[field.dataeaseName]?.hide + ) + s2Options.style.colCfg.widthByFieldValue = urlFields?.reduce((p, n) => { + p[n.chartShowName ?? n.name] = 120 + return p + }, {}) + } + if (tableCell.tableFreeze && !tableCell.mergeCells) { + s2Options.frozenColCount = tableCell.tableColumnFreezeHead ?? 0 + s2Options.frozenRowCount = tableCell.tableRowFreezeHead ?? 0 + } + // 开启序号之后,第一列就是序号列,修改 label 即可 + if (s2Options.showSeriesNumber) { + let indexLabel = tableHeader.indexLabel + if (!indexLabel) { + indexLabel = '' + } + s2Options.layoutCoordinate = (_, __, col) => { + if (col.colIndex === 0 && col.rowIndex === 0) { + col.label = indexLabel + col.value = indexLabel + } + } + } + s2Options.dataCell = viewMeta => { + const field = fields.filter(f => f.dataeaseName === viewMeta.valueField)?.[0] + if (field?.deType === 7 && chart.showPosition !== 'dialog') { + return new ImageCell(viewMeta, viewMeta?.spreadsheet) + } + if (viewMeta.colIndex === 0 && s2Options.showSeriesNumber) { + if (tableCell.mergeCells) { + viewMeta.fieldValue = getRowIndex(s2Options.mergedCellsInfo, viewMeta) + } else { + viewMeta.fieldValue = + pageInfo.pageSize * (pageInfo.currentPage - 1) + viewMeta.rowIndex + 1 + } + } + // 配置文本自动换行参数 + viewMeta.autoWrap = tableCell.mergeCells ? false : basicStyle.autoWrap + viewMeta.maxLines = basicStyle.maxLines + return new CustomDataCell(viewMeta, viewMeta?.spreadsheet) + } + // tooltip + this.configTooltip(chart, s2Options) + // 合并单元格 + this.configMergeCells(chart, s2Options, s2DataConfig) + // 隐藏表头,保留顶部的分割线, 禁用表头横向 resize + if (tableHeader.showTableHeader === false) { + s2Options.style.colCfg.height = 1 + if (tableCell.showHorizonBorder === false) { + s2Options.style.colCfg.height = 0 + } + s2Options.interaction.resize = { + colCellVertical: false + } + s2Options.colCell = (node, sheet, config) => { + node.label = ' ' + return new TableColCell(node, sheet, config) + } + } else { + // header interaction + chart.container = container + this.configHeaderInteraction(chart, s2Options) + s2Options.colCell = (node, sheet, config) => { + // 配置文本自动换行参数 + node.autoWrap = tableCell.mergeCells ? false : basicStyle.autoWrap + node.maxLines = basicStyle.maxLines + return new CustomTableColCell(node, sheet, config) + } + } + // 总计 + configSummaryRow(chart, s2Options, newData, tableHeader, basicStyle, basicStyle.showSummary) + // 开始渲染 + const newChart = new TableSheet(containerDom, s2DataConfig, s2Options) + // 总计紧贴在单元格后面 + summaryRowStyle(newChart, newData, tableCell, tableHeader, basicStyle.showSummary) + // 开启自动换行 + if (basicStyle.autoWrap && !tableCell.mergeCells) { + // 调整表头宽度时,计算表头高度 + newChart.on(S2Event.LAYOUT_RESIZE_COL_WIDTH, info => { + calculateHeaderHeight(info, newChart, tableHeader, basicStyle, null) + }) + newChart.on(S2Event.LAYOUT_AFTER_HEADER_LAYOUT, (ev: LayoutResult) => { + const maxHeight = newChart.store.get('autoCalcHeight') as number + if (maxHeight) { + // 更新列的高度 + ev.colLeafNodes.forEach(n => (n.height = maxHeight)) + ev.colsHierarchy.height = maxHeight + newChart.store.set('autoCalcHeight', undefined) + } else { + if (ev.colLeafNodes?.length) { + const { value, width } = ev.colLeafNodes[0] + calculateHeaderHeight( + { info: { meta: { value }, resizedWidth: width } }, + newChart, + tableHeader, + basicStyle, + ev + ) + } + } + }) + } + // 自适应铺满 + if (basicStyle.tableColumnMode === 'adapt') { + newChart.on(S2Event.LAYOUT_RESIZE_COL_WIDTH, () => { + newChart.store.set('lastLayoutResult', newChart.facet.layoutResult) + }) + newChart.on(S2Event.LAYOUT_AFTER_HEADER_LAYOUT, (ev: LayoutResult) => { + const lastLayoutResult = newChart.store.get('lastLayoutResult') as LayoutResult + if (lastLayoutResult) { + // 拖动表头 resize + const widthByFieldValue = newChart.options.style?.colCfg?.widthByFieldValue + const lastLayoutWidthMap: Record = + lastLayoutResult?.colLeafNodes.reduce((p, n) => { + p[n.value] = widthByFieldValue?.[n.value] ?? n.width + return p + }, {}) || {} + const totalWidth = ev.colLeafNodes.reduce((p, n) => { + n.width = lastLayoutWidthMap[n.value] || n.width + n.x = p + return p + n.width + }, 0) + // 处理分组的单元格,宽度为所有叶子节点之和 + ev.colNodes.forEach(n => { + if (n.colIndex === -1) { + n.width = calcTreeWidth(n) + n.x = getStartPosition(n) + } + }) + ev.colsHierarchy.width = totalWidth + newChart.store.set('lastLayoutResult', undefined) + return + } + // 第一次渲染初始化,把图片字段固定为 120 进行计算 + const urlFields = fields + .filter(field => field.deType === 7 && !axisMap[field.dataeaseName]?.hide) + .map(f => f.dataeaseName) + const totalWidthWithImg = ev.colLeafNodes.reduce((p, n) => { + return p + (urlFields.includes(n.field) ? 120 : n.width) + }, 0) + const containerWidth = containerDom.getBoundingClientRect().width + if (containerWidth <= totalWidthWithImg) { + // 图库计算的布局宽度已经大于等于容器宽度,不需要再扩大,但是需要处理非整数宽度值,不然会出现透明细线 + ev.colLeafNodes.reduce((p, n) => { + n.width = Math.round(n.width) + n.x = p + return p + n.width + }, 0) + return + } + // 图片字段固定 120, 剩余宽度按比例均摊到其他字段进行扩大 + const totalWidthWithoutImg = ev.colLeafNodes.reduce((p, n) => { + return p + (urlFields.includes(n.field) ? 0 : n.width) + }, 0) + const restWidth = containerWidth - urlFields.length * 120 + const scale = restWidth / totalWidthWithoutImg + const totalWidth = ev.colLeafNodes.reduce((p, n) => { + n.width = urlFields.includes(n.field) ? 120 : Math.round(n.width * scale) + n.x = p + return p + n.width + }, 0) + // 处理分组的单元格,宽度为所有叶子节点之和 + ev.colNodes.forEach(n => { + if (n.colIndex === -1) { + n.width = calcTreeWidth(n) + n.x = getStartPosition(n) + } + }) + if (totalWidth > containerWidth) { + ev.colLeafNodes[ev.colLeafNodes.length - 1].width -= totalWidth - containerWidth + } + ev.colsHierarchy.width = containerWidth + }) + } + // 空数据时表格样式 + configEmptyDataStyle(newChart, basicStyle, newData, container) + // click + newChart.on(S2Event.DATA_CELL_CLICK, ev => { + const cell = newChart.getCell(ev.target) + const meta = cell.getMeta() as ViewMeta + const nameIdMap = fields.reduce((pre, next) => { + pre[next['dataeaseName']] = next['id'] + return pre + }, {}) + + const rowData = newChart.dataSet.getRowData(meta) + const dimensionList = [] + for (const key in rowData) { + if (nameIdMap[key]) { + dimensionList.push({ id: nameIdMap[key], value: rowData[key] }) + } + } + const param = { + x: ev.x, + y: ev.y, + data: { + dimensionList, + name: nameIdMap[meta.valueField], + sourceType: 'table-info', + quotaList: [] + } + } + action(param) + }) + // 合并的单元格直接复用数据单元格的事件 + newChart.on(S2Event.MERGED_CELLS_CLICK, e => newChart.emit(S2Event.DATA_CELL_CLICK, e)) + // tooltip + const { show } = tooltip + if (show) { + newChart.on(S2Event.COL_CELL_HOVER, event => this.showTooltip(newChart, event, meta)) + newChart.on(S2Event.DATA_CELL_HOVER, event => this.showTooltip(newChart, event, meta)) + newChart.on(S2Event.MERGED_CELLS_HOVER, event => this.showTooltip(newChart, event, meta)) + } + // header resize + newChart.on(S2Event.LAYOUT_RESIZE_COL_WIDTH, ev => resizeAction(ev)) + // right click + newChart.on(S2Event.GLOBAL_CONTEXT_MENU, event => copyContent(newChart, event, meta)) + // touch + this.configTouchEvent(newChart, drawOption, meta) + // theme + const customTheme = this.configTheme(chart) + newChart.setThemeCfg({ theme: customTheme }) + return newChart + } + + protected configTheme(chart: Chart): S2Theme { + const theme = super.configTheme(chart) + const { basicStyle, tableCell } = parseJson(chart.customAttr) + if (tableCell.mergeCells) { + const tableFontColor = hexColorToRGBA(tableCell.tableFontColor, basicStyle.alpha) + let tableItemBgColor = tableCell.tableItemBgColor + if (!isAlphaColor(tableItemBgColor)) { + tableItemBgColor = hexColorToRGBA(tableItemBgColor, basicStyle.alpha) + } + const { tableBorderColor } = basicStyle + const { tableItemAlign, tableItemFontSize } = tableCell + const fontStyle = tableCell.isItalic ? 'italic' : 'normal' + const fontWeight = tableCell.isBolder === false ? 'normal' : 'bold' + const mergeCellTheme: S2Theme = { + mergedCell: { + cell: { + backgroundColor: tableItemBgColor, + crossBackgroundColor: tableItemBgColor, + horizontalBorderColor: tableBorderColor, + verticalBorderColor: tableBorderColor, + horizontalBorderWidth: tableCell.showHorizonBorder ? 1 : 0, + verticalBorderWidth: tableCell.showVerticalBorder ? 1 : 0 + }, + bolderText: { + fill: tableFontColor, + textAlign: tableItemAlign, + fontSize: tableItemFontSize, + fontStyle, + fontWeight + }, + text: { + fill: tableFontColor, + textAlign: tableItemAlign, + fontSize: tableItemFontSize, + fontStyle, + fontWeight + }, + measureText: { + fill: tableFontColor, + textAlign: tableItemAlign, + fontSize: tableItemFontSize, + fontStyle, + fontWeight + }, + seriesText: { + fill: tableFontColor, + textAlign: tableItemAlign, + fontSize: tableItemFontSize, + fontStyle, + fontWeight + } + } + } + merge(theme, mergeCellTheme) + } + return theme + } + + constructor() { + super('table-info', []) + } +} + +function calcTreeWidth(node) { + if (!node.children?.length) { + return node.width + } + return node.children.reduce((pre, cur) => { + return pre + calcTreeWidth(cur) + }, 0) +} + +function getStartPosition(node) { + if (!node.children?.length) { + return node.x + } + return getStartPosition(node.children[0]) +} diff --git a/frontend/src/data-visualization/chart/components/js/panel/charts/table/table-normal.ts b/frontend/src/data-visualization/chart/components/js/panel/charts/table/table-normal.ts new file mode 100644 index 0000000..327dd5b --- /dev/null +++ b/frontend/src/data-visualization/chart/components/js/panel/charts/table/table-normal.ts @@ -0,0 +1,300 @@ +import { useI18n } from '@/data-visualization/hooks/web/useI18n' +import { formatterItem, valueFormatter } from '@/data-visualization/chart/components/js/formatter' +import { + configEmptyDataStyle, + configSummaryRow, + copyContent, + SortTooltip, + summaryRowStyle +} from '@/data-visualization/chart/components/js/panel/common/common_table' +import { S2ChartView, S2DrawOptions } from '@/data-visualization/chart/components/js/panel/types/impl/s2' +import { parseJson } from '@/data-visualization/chart/components/js/util' +import { + type LayoutResult, + S2DataConfig, + S2Event, + S2Options, + ScrollbarPositionType, + TableColCell, + TableSheet, + ViewMeta +} from '@antv/s2' +import { cloneDeep, isNumber } from 'lodash-es' +import { TABLE_EDITOR_PROPERTY, TABLE_EDITOR_PROPERTY_INNER } from './common' + +const { t } = useI18n() +/** + * 汇总表 + */ +export class TableNormal extends S2ChartView { + properties = TABLE_EDITOR_PROPERTY + propertyInner: EditorPropertyInner = { + ...TABLE_EDITOR_PROPERTY_INNER, + 'table-header-selector': [ + ...TABLE_EDITOR_PROPERTY_INNER['table-header-selector'], + 'tableHeaderSort', + 'showTableHeader' + ], + 'basic-style-selector': [ + ...TABLE_EDITOR_PROPERTY_INNER['basic-style-selector'], + 'showSummary', + 'summaryLabel', + 'showHoverStyle' + ], + 'table-cell-selector': [ + ...TABLE_EDITOR_PROPERTY_INNER['table-cell-selector'], + 'tableFreeze', + 'tableColumnFreezeHead', + 'tableRowFreezeHead' + ] + } + axis: AxisType[] = ['xAxis', 'yAxis', 'drill', 'filter'] + axisConfig: AxisConfig = { + xAxis: { + name: `${t('chart.drag_block_table_data_column')} / ${t('chart.dimension')}`, + type: 'd' + }, + yAxis: { + name: `${t('chart.drag_block_table_data_column')} / ${t('chart.quota')}`, + type: 'q' + } + } + + setupDefaultOptions(chart: ChartObj): ChartObj { + chart.xAxis = [] + return chart + } + + drawChart(drawOption: S2DrawOptions): TableSheet { + const { container, chart, action, resizeAction } = drawOption + const containerDom = document.getElementById(container) + if (!containerDom) return + + // fields + let fields = chart.data.fields + + const columns = [] + const meta = [] + if (chart.drill) { + // 下钻过滤字段 + const filterFields = chart.drillFilters.map(i => i.fieldId) + // 下钻入口的字段下标 + const drillFieldId = chart.drillFields[0].id + const drillFieldIndex = chart.xAxis.findIndex(ele => ele.id === drillFieldId) + // 当前下钻字段 + const curDrillFieldId = chart.drillFields[filterFields.length].id + const curDrillField = fields.filter(ele => ele.id === curDrillFieldId) + filterFields.push(curDrillFieldId) + // 移除下钻字段,把当前下钻字段插入到下钻入口位置 + fields = fields.filter(ele => { + return !filterFields.includes(ele.id) + }) + fields.splice(drillFieldIndex, 0, ...curDrillField) + } + const axisMap = [...chart.xAxis, ...chart.yAxis].reduce((pre, cur) => { + pre[cur.dataeaseName] = cur + return pre + }, {}) + // add drill list + fields.forEach(ele => { + const f = axisMap[ele.dataeaseName] + if (f?.hide === true) { + return + } + columns.push(ele.dataeaseName) + meta.push({ + field: ele.dataeaseName, + name: ele.chartShowName ?? ele.name, + formatter: function (value) { + if (!f) { + return value + } + if (value === null || value === undefined) { + return value + } + if (![2, 3].includes(f.deType) || !isNumber(value)) { + return value + } + let formatCfg = f.formatterCfg + if (!formatCfg) { + formatCfg = formatterItem + } + return valueFormatter(value, formatCfg) + } + }) + }) + + // 空值处理 + const newData = this.configEmptyDataStrategy(chart) + // data config + const s2DataConfig: S2DataConfig = { + fields: { + columns: columns + }, + meta: meta, + data: newData + } + + const { basicStyle, tableCell, tableHeader, tooltip } = parseJson(chart.customAttr) + // options + const s2Options: S2Options = { + width: containerDom.getBoundingClientRect().width, + height: containerDom.offsetHeight, + showSeriesNumber: tableHeader.showIndex, + conditions: this.configConditions(chart), + tooltip: { + getContainer: () => containerDom, + renderTooltip: sheet => new SortTooltip(sheet) + }, + interaction: { + hoverHighlight: !(basicStyle.showHoverStyle === false), + scrollbarPosition: newData.length + ? ScrollbarPositionType.CONTENT + : ScrollbarPositionType.CANVAS + } + } + // 列宽设置 + s2Options.style = this.configStyle(chart, s2DataConfig) + // 行列冻结 + if (tableCell.tableFreeze) { + s2Options.frozenColCount = tableCell.tableColumnFreezeHead ?? 0 + s2Options.frozenRowCount = tableCell.tableRowFreezeHead ?? 0 + } + // 开启序号之后,第一列就是序号列,修改 label 即可 + if (s2Options.showSeriesNumber) { + let indexLabel = tableHeader.indexLabel + if (!indexLabel) { + indexLabel = '' + } + s2Options.layoutCoordinate = (_, __, col) => { + if (col.colIndex === 0 && col.rowIndex === 0) { + col.label = indexLabel + col.value = indexLabel + } + } + } + // tooltip + this.configTooltip(chart, s2Options) + // 隐藏表头,保留顶部的分割线, 禁用表头横向 resize + if (tableHeader.showTableHeader === false) { + s2Options.style.colCfg.height = 1 + if (tableCell.showHorizonBorder === false) { + s2Options.style.colCfg.height = 0 + } + s2Options.interaction.resize = { + colCellVertical: false + } + s2Options.colCell = (node, sheet, config) => { + node.label = ' ' + return new TableColCell(node, sheet, config) + } + } else { + // header interaction + chart.container = container + this.configHeaderInteraction(chart, s2Options) + } + + // 总计 + configSummaryRow(chart, s2Options, newData, tableHeader, basicStyle, basicStyle.showSummary) + // 开始渲染 + const newChart = new TableSheet(containerDom, s2DataConfig, s2Options) + // 总计紧贴在单元格后面 + summaryRowStyle(newChart, newData, tableCell, tableHeader, basicStyle.showSummary) + // 自适应铺满 + if (basicStyle.tableColumnMode === 'adapt') { + newChart.on(S2Event.LAYOUT_RESIZE_COL_WIDTH, () => { + newChart.store.set('lastLayoutResult', newChart.facet.layoutResult) + }) + newChart.on(S2Event.LAYOUT_AFTER_HEADER_LAYOUT, (ev: LayoutResult) => { + const lastLayoutResult = newChart.store.get('lastLayoutResult') as LayoutResult + if (lastLayoutResult) { + // 拖动表头 resize + const widthByFieldValue = newChart.options.style?.colCfg?.widthByFieldValue + const lastLayoutWidthMap: Record = + lastLayoutResult?.colLeafNodes.reduce((p, n) => { + p[n.value] = widthByFieldValue?.[n.value] ?? n.width + return p + }, {}) || {} + const totalWidth = ev.colLeafNodes.reduce((p, n) => { + n.width = lastLayoutWidthMap[n.value] || n.width + n.x = p + return p + n.width + }, 0) + ev.colsHierarchy.width = totalWidth + newChart.store.set('lastLayoutResult', undefined) + return + } + const containerWidth = containerDom.getBoundingClientRect().width + const scale = containerWidth / ev.colsHierarchy.width + if (scale <= 1) { + // 图库计算的布局宽度已经大于等于容器宽度,不需要再扩大,但是需要处理非整数宽度值,不然会出现透明细线 + ev.colLeafNodes.reduce((p, n) => { + n.width = Math.round(n.width) + n.x = p + return p + n.width + }, 0) + return + } + const totalWidth = ev.colLeafNodes.reduce((p, n) => { + n.width = Math.round(n.width * scale) + n.x = p + return p + n.width + }, 0) + if (totalWidth > containerWidth) { + // 从最后一列减掉 + ev.colLeafNodes[ev.colLeafNodes.length - 1].width -= totalWidth - containerWidth + } + ev.colsHierarchy.width = containerWidth + }) + } + configEmptyDataStyle(newChart, basicStyle, newData, container) + // click + newChart.on(S2Event.DATA_CELL_CLICK, ev => { + const cell = newChart.getCell(ev.target) + const meta = cell.getMeta() as ViewMeta + const nameIdMap = fields.reduce((pre, next) => { + pre[next['dataeaseName']] = next['id'] + return pre + }, {}) + + const rowData = newChart.dataSet.getRowData(meta) + const dimensionList = [] + for (const key in rowData) { + if (nameIdMap[key]) { + dimensionList.push({ id: nameIdMap[key], value: rowData[key] }) + } + } + const param = { + x: ev.x, + y: ev.y, + data: { + dimensionList, + name: nameIdMap[meta.valueField], + sourceType: 'table-normal', + quotaList: [] + } + } + action(param) + }) + // tooltip + const { show } = tooltip + if (show) { + newChart.on(S2Event.COL_CELL_HOVER, event => this.showTooltip(newChart, event, meta)) + newChart.on(S2Event.DATA_CELL_HOVER, event => this.showTooltip(newChart, event, meta)) + } + // header resize + newChart.on(S2Event.LAYOUT_RESIZE_COL_WIDTH, ev => resizeAction(ev)) + // right click + newChart.on(S2Event.GLOBAL_CONTEXT_MENU, event => copyContent(newChart, event, meta)) + // touch + this.configTouchEvent(newChart, drawOption, meta) + // theme + const customTheme = this.configTheme(chart) + newChart.setThemeCfg({ theme: customTheme }) + + return newChart + } + constructor() { + super('table-normal', []) + } +} diff --git a/frontend/src/data-visualization/chart/components/js/panel/charts/table/table-pivot.ts b/frontend/src/data-visualization/chart/components/js/panel/charts/table/table-pivot.ts new file mode 100644 index 0000000..f7f695c --- /dev/null +++ b/frontend/src/data-visualization/chart/components/js/panel/charts/table/table-pivot.ts @@ -0,0 +1,1003 @@ +import { + EXTRA_FIELD, + PivotSheet, + S2Event, + S2Options, + TOTAL_VALUE, + S2Theme, + Totals, + PivotDataSet, + Query, + VALUE_FIELD, + QueryDataType, + TotalStatus, + Aggregation, + S2DataConfig, + MergedCell +} from '@antv/s2' +import { formatterItem, valueFormatter } from '../../../formatter' +import { hexColorToRGBA, isAlphaColor, parseJson } from '../../../util' +import { S2ChartView, S2DrawOptions } from '../../types/impl/s2' +import { TABLE_EDITOR_PROPERTY_INNER } from './common' +import { useI18n } from '@/data-visualization/hooks/web/useI18n' +import { isNumber, keys, maxBy, merge, minBy, some, isEmpty, get } from 'lodash-es' +import { copyContent, CustomDataCell } from '../../common/common_table' +import Decimal from 'decimal.js' +import { DEFAULT_TABLE_HEADER } from '@/data-visualization/chart/components/editor/util/chart' + +type DataItem = Record + +const { t } = useI18n() + +class CustomPivotDataset extends PivotDataSet { + getTotalValue(query: Query, totalStatus?: TotalStatus) { + const { options } = this.spreadsheet + const effectiveStatus = some(totalStatus) + const status = effectiveStatus ? totalStatus : this.getTotalStatus(query) + const { aggregation, calcFunc } = + getAggregationAndCalcFuncByQuery(status, options?.totals) || {} + + // 聚合方式从用户配置的 s2Options.totals 取, 在触发前端兜底计算汇总逻辑时, 如果没有汇总的配置, 默认按 [求和] 计算,避免排序失效. + const defaultAggregation = + isEmpty(options?.totals) && !this.spreadsheet.isHierarchyTreeType() ? Aggregation.SUM : '' + const calcAction = calcActionByType[aggregation || defaultAggregation] + + // 前端计算汇总值 + if (calcAction || calcFunc) { + const data = this.getMultiData(query, { + queryType: QueryDataType.DetailOnly + }) + let totalValue: number + if (calcFunc) { + totalValue = calcFunc(query, data, this.spreadsheet, status) + } else if (calcAction) { + totalValue = calcAction(data, VALUE_FIELD) + } + + return { + ...query, + [VALUE_FIELD]: totalValue, + [query[EXTRA_FIELD]]: totalValue + } + } + } +} +/** + * 透视表 + */ +export class TablePivot extends S2ChartView { + properties: EditorProperty[] = [ + 'border-style', + 'background-overall-component', + 'basic-style-selector', + 'table-header-selector', + 'table-cell-selector', + 'table-total-selector', + 'title-selector', + 'tooltip-selector', + 'function-cfg', + 'threshold', + 'linkage', + 'jump-set' + ] + propertyInner = { + ...TABLE_EDITOR_PROPERTY_INNER, + 'table-header-selector': [ + 'tableHeaderBgColor', + 'tableTitleFontSize', + 'tableHeaderFontColor', + 'tableTitleHeight', + 'tableHeaderAlign', + 'showColTooltip', + 'showRowTooltip', + 'showHorizonBorder', + 'showVerticalBorder' + ], + 'table-total-selector': ['row', 'col'], + 'basic-style-selector': [ + 'tableColumnMode', + 'tableBorderColor', + 'tableScrollBarColor', + 'alpha', + 'tableLayoutMode', + 'showHoverStyle' + ] + } + axis: AxisType[] = ['xAxis', 'xAxisExt', 'yAxis', 'filter'] + axisConfig: AxisConfig = { + xAxis: { + name: `${t('chart.table_pivot_row')} / ${t('chart.dimension')}`, + type: 'd' + }, + xAxisExt: { + name: `${t('chart.drag_block_table_data_column')} / ${t('chart.dimension')}`, + type: 'd', + allowEmpty: true + }, + yAxis: { + name: `${t('chart.drag_block_table_data_column')} / ${t('chart.quota')}`, + type: 'q' + } + } + + public drawChart(drawOption: S2DrawOptions): PivotSheet { + const { container, chart, chartObj, action } = drawOption + const containerDom = document.getElementById(container) + + const { xAxisExt: columnFields, xAxis: rowFields, yAxis: valueFields } = chart + const [c, r, v] = [columnFields, rowFields, valueFields].map(arr => + arr.map(i => i.dataeaseName) + ) + + // fields + const { fields, customCalc } = chart.data + if (!fields || fields.length === 0) { + if (chartObj) { + chartObj.destroy() + } + return + } + + const columns = [] + const meta = [] + + const valueFieldMap: Record = [ + ...chart.xAxis, + ...chart.xAxisExt, + ...chart.yAxis + ].reduce((p, n) => { + p[n.dataeaseName] = n + return p + }, {}) + fields.forEach(ele => { + const f = valueFieldMap[ele.dataeaseName] + columns.push(ele.dataeaseName) + meta.push({ + field: ele.dataeaseName, + name: ele.chartShowName ?? ele.name, + formatter: value => { + if (!f) { + return value + } + if (value === null || value === undefined) { + return value + } + if (![2, 3].includes(f.deType) || !isNumber(value)) { + return value + } + if (f.formatterCfg) { + return valueFormatter(value, f.formatterCfg) + } else { + return valueFormatter(value, formatterItem) + } + } + }) + }) + + // total config + const { basicStyle, tooltip, tableTotal } = parseJson(chart.customAttr) + if (!tableTotal.row.subTotalsDimensionsNew || tableTotal.row.subTotalsDimensions == undefined) { + tableTotal.row.subTotalsDimensions = r + } + tableTotal.col.subTotalsDimensions = c + + // 解析合计、小计排序 + const sortParams = [] + if ( + tableTotal.row.totalSort && + tableTotal.row.totalSort !== 'none' && + c.length > 0 && + tableTotal.row.showGrandTotals && + v.indexOf(tableTotal.row.totalSortField) > -1 + ) { + const sort = { + sortFieldId: c[0], + sortMethod: tableTotal.row.totalSort.toUpperCase(), + sortByMeasure: TOTAL_VALUE, + query: { + [EXTRA_FIELD]: tableTotal.row.totalSortField + } + } + sortParams.push(sort) + } + if ( + tableTotal.col.totalSort && + tableTotal.col.totalSort !== 'none' && + r.length > 0 && + tableTotal.col.showGrandTotals && + v.indexOf(tableTotal.col.totalSortField) > -1 + ) { + const sort = { + sortFieldId: r[0], + sortMethod: tableTotal.col.totalSort.toUpperCase(), + sortByMeasure: TOTAL_VALUE, + query: { + [EXTRA_FIELD]: tableTotal.col.totalSortField + } + } + sortParams.push(sort) + } + //列维度为空,行排序按照指标列来排序,取第一个有排序设置的指标 + if (!columnFields?.length) { + const sortField = valueFields?.find(v => !['none', 'custom_sort'].includes(v.sort)) + if (sortField) { + const sort = { + sortFieldId: r[0], + sortMethod: sortField.sort.toUpperCase(), + sortByMeasure: TOTAL_VALUE, + query: { + [EXTRA_FIELD]: sortField.dataeaseName + } + } + sortParams.push(sort) + } + } + // 自定义总计小计 + const totals = [ + tableTotal.row.calcTotals, + tableTotal.row.calcSubTotals, + tableTotal.col.calcTotals, + tableTotal.col.calcSubTotals + ] + const axisMap = { + row: chart.xAxis, + col: chart.xAxisExt, + quota: chart.yAxis + } + //树形模式下,列维度为空,行小计会变成列总计,特殊处理下 + if (basicStyle.tableLayoutMode === 'tree' && !chart.xAxisExt?.length) { + tableTotal.col.calcTotals = tableTotal.row.calcSubTotals + } + totals.forEach(total => { + if (total.cfg?.length) { + delete total.aggregation + const totalCfgMap = total.cfg.reduce((p, n) => { + p[n.dataeaseName] = n + return p + }, {}) + total.calcFunc = (query, data, _, status) => { + return customCalcFunc(query, data, status, chart, totalCfgMap, axisMap, customCalc) + } + } + }) + // 空值处理 + const newData = this.configEmptyDataStrategy(chart) + // data config + const s2DataConfig: S2DataConfig = { + fields: { + rows: r, + columns: c, + values: v + }, + meta: meta, + data: newData, + sortParams: sortParams + } + const s2Options: S2Options = { + width: containerDom.offsetWidth, + height: containerDom.offsetHeight, + totals: tableTotal as Totals, + conditions: this.configConditions(chart), + tooltip: { + getContainer: () => containerDom + }, + hierarchyType: basicStyle.tableLayoutMode ?? 'grid', + dataSet: spreadSheet => new CustomPivotDataset(spreadSheet), + interaction: { + hoverHighlight: !(basicStyle.showHoverStyle === false) + }, + dataCell: meta => { + return new CustomDataCell(meta, meta.spreadsheet) + } + } + // options + s2Options.style = this.configStyle(chart, s2DataConfig) + s2Options.style.hierarchyCollapse = true + // tooltip + this.configTooltip(chart, s2Options) + // 开始渲染 + const s2 = new PivotSheet(containerDom, s2DataConfig, s2Options as unknown as S2Options) + // tooltip + const { show } = tooltip + if (show) { + s2.on(S2Event.COL_CELL_HOVER, event => this.showTooltip(s2, event, meta)) + s2.on(S2Event.ROW_CELL_HOVER, event => this.showTooltip(s2, event, meta)) + s2.on(S2Event.DATA_CELL_HOVER, event => this.showTooltip(s2, event, meta)) + } + // empty data tip + configEmptyDataStyle(s2, newData) + // click + s2.on(S2Event.DATA_CELL_CLICK, ev => this.dataCellClickAction(chart, ev, s2, action)) + s2.on(S2Event.ROW_CELL_CLICK, ev => this.headerCellClickAction(chart, ev, s2, action)) + s2.on(S2Event.COL_CELL_CLICK, ev => this.headerCellClickAction(chart, ev, s2, action)) + // right click + s2.on(S2Event.GLOBAL_CONTEXT_MENU, event => copyContent(s2, event, meta)) + // touch + this.configTouchEvent(s2, drawOption, meta) + // theme + const customTheme = this.configTheme(chart) + s2.setThemeCfg({ theme: customTheme }) + + return s2 + } + private dataCellClickAction(chart: Chart, ev, s2Instance: PivotSheet, callback) { + const cell = s2Instance.getCell(ev.target) + const meta = cell.getMeta() + const nameIdMap = chart.data.fields.reduce((pre, next) => { + pre[next['dataeaseName']] = next['id'] + return pre + }, {}) + const rowData = { ...meta.rowQuery, ...meta.colQuery } + rowData[meta.valueField] = meta.fieldValue + const dimensionList = [] + for (const key in rowData) { + if (nameIdMap[key]) { + dimensionList.push({ id: nameIdMap[key], value: rowData[key] }) + } + } + const param = { + x: ev.x, + y: ev.y, + data: { + dimensionList, + name: nameIdMap[meta.valueField], + sourceType: 'table-pivot', + quotaList: [] + } + } + callback(param) + } + private headerCellClickAction(chart: Chart, ev, s2Instance: PivotSheet, callback) { + const cell = s2Instance.getCell(ev.target) + const meta = cell.getMeta() + const rowData = meta.query + const nameIdMap = chart.data.fields.reduce((pre, next) => { + pre[next['dataeaseName']] = next['id'] + return pre + }, {}) + const dimensionList = [] + for (const key in rowData) { + if (nameIdMap[key]) { + dimensionList.push({ id: nameIdMap[key], value: rowData[key] }) + } + } + const param = { + x: ev.x, + y: ev.y, + data: { + dimensionList, + name: nameIdMap[meta.valueField], + sourceType: 'table-pivot', + quotaList: [] + } + } + callback(param) + } + protected configTheme(chart: Chart): S2Theme { + const theme = super.configTheme(chart) + const { basicStyle, tableHeader } = parseJson(chart.customAttr) + let tableHeaderBgColor = tableHeader.tableHeaderBgColor + if (!isAlphaColor(tableHeaderBgColor)) { + tableHeaderBgColor = hexColorToRGBA(tableHeaderBgColor, basicStyle.alpha) + } + let tableHeaderCornerBgColor = + tableHeader.tableHeaderCornerBgColor ?? DEFAULT_TABLE_HEADER.tableHeaderCornerBgColor + if (!isAlphaColor(tableHeaderCornerBgColor)) { + tableHeaderCornerBgColor = hexColorToRGBA(tableHeaderCornerBgColor, basicStyle.alpha) + } + let tableHeaderColBgColor = + tableHeader.tableHeaderColBgColor ?? DEFAULT_TABLE_HEADER.tableHeaderColBgColor + if (!isAlphaColor(tableHeaderColBgColor)) { + tableHeaderColBgColor = hexColorToRGBA(tableHeaderColBgColor, basicStyle.alpha) + } + let tableBorderColor = basicStyle.tableBorderColor + if (!isAlphaColor(tableBorderColor)) { + tableBorderColor = hexColorToRGBA(tableBorderColor, basicStyle.alpha) + } + const tableHeaderColFontColor = hexColorToRGBA( + tableHeader.tableHeaderColFontColor, + basicStyle.alpha + ) + const tableHeaderCornerFontColor = hexColorToRGBA( + tableHeader.tableHeaderCornerFontColor, + basicStyle.alpha + ) + const colFontStyle = tableHeader.isColItalic ? 'italic' : 'normal' + const cornerFontStyle = tableHeader.isCornerItalic ? 'italic' : 'normal' + const colFontWeight = tableHeader.isColBolder === false ? 'normal' : 'bold' + const cornerFontWeight = tableHeader.isCornerBolder === false ? 'normal' : 'bold' + const pivotTheme = { + rowCell: { + cell: { + backgroundColor: tableHeaderColBgColor, + horizontalBorderColor: tableBorderColor, + verticalBorderColor: tableBorderColor + }, + text: { + fill: tableHeaderColFontColor, + fontSize: tableHeader.tableTitleColFontSize, + textAlign: tableHeader.tableHeaderColAlign, + textBaseline: 'top', + fontStyle: colFontStyle, + fontWeight: colFontWeight + }, + bolderText: { + fill: tableHeaderColFontColor, + fontSize: tableHeader.tableTitleColFontSize, + textAlign: tableHeader.tableHeaderColAlign, + fontStyle: colFontStyle, + fontWeight: colFontWeight + }, + measureText: { + fill: tableHeaderColFontColor, + fontSize: tableHeader.tableTitleColFontSize, + textAlign: tableHeader.tableHeaderColAlign, + fontStyle: colFontStyle, + fontWeight: colFontWeight + }, + seriesText: { + fill: tableHeaderColFontColor, + fontSize: tableHeader.tableTitleColFontSize, + textAlign: tableHeader.tableHeaderColAlign, + fontStyle: colFontStyle, + fontWeight: colFontWeight + } + }, + cornerCell: { + cell: { + backgroundColor: tableHeaderCornerBgColor + }, + text: { + fill: tableHeaderCornerFontColor, + fontSize: tableHeader.tableTitleCornerFontSize, + textAlign: tableHeader.tableHeaderCornerAlign, + fontStyle: cornerFontStyle, + fontWeight: cornerFontWeight + }, + bolderText: { + fill: tableHeaderCornerFontColor, + fontSize: tableHeader.tableTitleCornerFontSize, + textAlign: tableHeader.tableHeaderCornerAlign, + fontStyle: cornerFontStyle, + fontWeight: cornerFontWeight + }, + measureText: { + fill: tableHeaderCornerFontColor, + fontSize: tableHeader.tableTitleCornerFontSize, + textAlign: tableHeader.tableHeaderCornerAlign, + fontStyle: cornerFontStyle, + fontWeight: cornerFontWeight + } + } + } + merge(theme, pivotTheme) + if (tableHeader.showHorizonBorder === false) { + const tmp: S2Theme = { + cornerCell: { + cell: { + horizontalBorderColor: tableHeaderBgColor, + horizontalBorderWidth: 0 + } + }, + rowCell: { + cell: { + horizontalBorderColor: tableHeaderBgColor, + horizontalBorderWidth: 0 + } + } + } + merge(theme, tmp) + } + if (tableHeader.showVerticalBorder === false) { + const tmp: S2Theme = { + cornerCell: { + cell: { + verticalBorderColor: tableHeaderBgColor, + verticalBorderWidth: 0 + } + }, + rowCell: { + cell: { + verticalBorderColor: tableHeaderBgColor, + verticalBorderWidth: 0 + } + } + } + merge(theme, tmp) + } + return theme + } + + setupDefaultOptions(chart: ChartObj): ChartObj { + const { customAttr } = chart + if (customAttr.basicStyle.tableColumnMode === 'field') { + customAttr.basicStyle.tableColumnMode = 'custom' + } + return chart + } + + constructor() { + super('table-pivot', []) + } +} +function customCalcFunc(query, data, status, chart, totalCfgMap, axisMap, customCalc) { + if (!data?.length || !query[EXTRA_FIELD]) { + return 0 + } + const aggregation = totalCfgMap[query[EXTRA_FIELD]]?.aggregation || 'SUM' + switch (aggregation) { + case 'SUM': { + return data.reduce((p, n) => { + return p + parseFloat(n[query[EXTRA_FIELD]] ?? 0) + }, 0) + } + case 'AVG': { + const sum = data.reduce((p, n) => { + return p + parseFloat(n[query[EXTRA_FIELD]] ?? 0) + }, 0) + return sum / data.length + } + case 'MIN': { + const result = minBy(data, n => { + return parseFloat(n[query[EXTRA_FIELD]]) + }) + return result?.[query[EXTRA_FIELD]] + } + case 'MAX': { + const result = maxBy(data, n => { + return parseFloat(n[query[EXTRA_FIELD]]) + }) + return result?.[query[EXTRA_FIELD]] + } + case 'CUSTOM': { + const val = getCustomCalcResult(query, axisMap, chart, status, customCalc || {}) + if (val === '') { + return val + } + return parseFloat(val) + } + default: { + return data.reduce((p, n) => { + return p + parseFloat(n[query[EXTRA_FIELD]] ?? 0) + }, 0) + } + } +} + +function getTreeCustomCalcResult(query, axisMap, status: TotalStatus, customCalc) { + const quotaField = query[EXTRA_FIELD] + const { row, col } = axisMap + // 行列交叉总计 + if (status.isRowTotal && status.isColTotal) { + return customCalc.rowColTotal?.data?.[quotaField] + } + // 列总计 + if (status.isColTotal && !status.isRowSubTotal) { + const { colTotal, rowSubInColTotal } = customCalc + const path = getTreePath(query, row) + let val + if (path.length) { + const subLevel = getSubLevel(query, row) + if (subLevel + 1 === row.length && colTotal) { + path.push(quotaField) + val = get(colTotal.data, path) + } + if (subLevel + 1 < row.length && rowSubInColTotal) { + const data = rowSubInColTotal?.[subLevel]?.data + path.push(quotaField) + val = get(data, path) + } + } + return val + } + // 列小计 + if (status.isColSubTotal && !status.isRowTotal && !status.isRowSubTotal) { + const { colSubTotal } = customCalc + const subLevel = getSubLevel(query, col) + const rowPath = getTreePath(query, row) + const colPath = getTreePath(query, col) + const path = [...rowPath, ...colPath] + const data = colSubTotal?.[subLevel]?.data + let val + if (path.length && data) { + path.push(quotaField) + val = get(data, path) + } + return val + } + // 行总计 + if (status.isRowTotal && !status.isColSubTotal) { + const { rowTotal } = customCalc + const path = getTreePath(query, col) + let val + if (rowTotal) { + if (path.length) { + path.push(quotaField) + val = get(rowTotal.data, path) + } + // 列维度为空,行维度不为空 + if (!col.length && row.length) { + val = get(rowTotal.data, quotaField) + } + } + return val + } + // 行小计 + if (status.isRowSubTotal) { + // 列维度为空,行小计直接当成列总计 + if ( + (!status.isColTotal && !status.isColSubTotal) || + (!col.length && status.isColTotal && status.isRowSubTotal) + ) { + const { rowSubTotal } = customCalc + const rowLevel = getSubLevel(query, row) + const colPath = getTreePath(query, col) + const rowPath = getTreePath(query, row) + const path = [...colPath, ...rowPath] + const data = rowSubTotal?.[rowLevel]?.data + let val + if (path.length && rowSubTotal) { + path.push(quotaField) + val = get(data, path) + } + return val + } + } + // 行总计里面的列小计 + if (status.isRowTotal && status.isColSubTotal) { + const { colSubInRowTotal } = customCalc + const colLevel = getSubLevel(query, col) + const { data } = colSubInRowTotal?.[colLevel] + const colPath = getTreePath(query, col) + let val + if (colPath.length && colSubInRowTotal) { + colPath.push(quotaField) + val = get(data, colPath) + } + return val + } + // 列总计里面的行小计 + if (status.isColTotal && status.isRowSubTotal) { + const { rowSubInColTotal } = customCalc + const rowSubLevel = getSubLevel(query, row) + const data = rowSubInColTotal?.[rowSubLevel]?.data + const path = getTreePath(query, row) + let val + if (path.length && rowSubInColTotal) { + path.push(quotaField) + val = get(data, path) + } + return val + } + // 列小计里面的行小计 + if (status.isColSubTotal && status.isRowSubTotal) { + const { rowSubInColSub } = customCalc + const rowSubLevel = getSubLevel(query, row) + const colSubLevel = getSubLevel(query, col) + const data = rowSubInColSub?.[rowSubLevel]?.[colSubLevel]?.data + const rowPath = getTreePath(query, row) + const colPath = getTreePath(query, col) + const path = [...rowPath, ...colPath] + let val + if (path.length && rowSubInColSub) { + path.push(quotaField) + val = get(data, path) + } + return val + } + return NaN +} + +function getGridCustomCalcResult(query, axisMap, status: TotalStatus, customCalc) { + const quotaField = query[EXTRA_FIELD] + const { row, col } = axisMap + // 行列交叉总计 + if (status.isRowTotal && status.isColTotal) { + return customCalc.rowColTotal?.data?.[quotaField] + } + // 列总计 + if (status.isColTotal && !status.isRowSubTotal) { + const { colTotal } = customCalc + const path = getTreePath(query, row) + let val + if (path.length) { + if (colTotal) { + path.push(quotaField) + val = get(colTotal.data, path) + } + } + return val + } + // 列小计 + if (status.isColSubTotal && !status.isRowTotal && !status.isRowSubTotal) { + const { colSubTotal } = customCalc + const subLevel = getSubLevel(query, col) + const rowPath = getTreePath(query, row) + const colPath = getTreePath(query, col) + const path = [...rowPath, ...colPath] + const data = colSubTotal?.[subLevel]?.data + let val + if (path.length && data) { + path.push(quotaField) + val = get(data, path) + } + return val + } + // 行总计 + if (status.isRowTotal && !status.isColSubTotal) { + const { rowTotal } = customCalc + const path = getTreePath(query, col) + let val + if (rowTotal) { + if (path.length) { + path.push(quotaField) + val = get(rowTotal.data, path) + } + // 列维度为空,行维度不为空 + if (!col.length && row.length) { + val = get(rowTotal.data, quotaField) + } + } + return val + } + // 行小计 + if (status.isRowSubTotal && !status.isColTotal && !status.isColSubTotal) { + const { rowSubTotal } = customCalc + const rowLevel = getSubLevel(query, row) + const colPath = getTreePath(query, col) + const rowPath = getTreePath(query, row) + const path = [...colPath, ...rowPath] + const data = rowSubTotal?.[rowLevel]?.data + let val + if (path.length && rowSubTotal) { + path.push(quotaField) + val = get(data, path) + } + return val + } + // 行总计里面的列小计 + if (status.isRowTotal && status.isColSubTotal) { + const { colSubInRowTotal } = customCalc + const colLevel = getSubLevel(query, col) + const { data } = colSubInRowTotal?.[colLevel] + const colPath = getTreePath(query, col) + let val + if (colPath.length && colSubInRowTotal) { + colPath.push(quotaField) + val = get(data, colPath) + } + return val + } + // 列总计里面的行小计 + if (status.isColTotal && status.isRowSubTotal) { + const { rowSubInColTotal } = customCalc + const rowSubLevel = getSubLevel(query, row) + const data = rowSubInColTotal?.[rowSubLevel]?.data + const path = getTreePath(query, row) + let val + if (path.length && rowSubInColTotal) { + path.push(quotaField) + val = get(data, path) + } + return val + } + // 列小计里面的行小计 + if (status.isColSubTotal && status.isRowSubTotal) { + const { rowSubInColSub } = customCalc + const rowSubLevel = getSubLevel(query, row) + const colSubLevel = getSubLevel(query, col) + const data = rowSubInColSub?.[rowSubLevel]?.[colSubLevel]?.data + const rowPath = getTreePath(query, row) + const colPath = getTreePath(query, col) + const path = [...rowPath, ...colPath] + let val + if (path.length && rowSubInColSub) { + path.push(quotaField) + val = get(data, path) + } + return val + } +} +function getCustomCalcResult(query, axisMap, chart: ChartObj, status: TotalStatus, customCalc) { + const { tableLayoutMode } = chart.customAttr.basicStyle + if (tableLayoutMode === 'tree') { + return getTreeCustomCalcResult(query, axisMap, status, customCalc) + } + return getGridCustomCalcResult(query, axisMap, status, customCalc) +} + +function getSubLevel(query, axis) { + const fields: [] = axis.map(a => a.dataeaseName) + let subLevel = -1 + const queryFields = keys(query) + for (let i = fields.length - 1; i >= 0; i--) { + const field = fields[i] + const index = queryFields.findIndex(f => f === field) + if (index !== -1) { + subLevel++ + } + } + return subLevel +} + +function getTreePath(query, axis) { + const path = [] + const fields = keys(query) + axis.forEach(a => { + const index = fields.findIndex(f => f === a.dataeaseName) + if (index !== -1) { + path.push(query[a.dataeaseName]) + } + }) + return path +} + +function getAggregationAndCalcFuncByQuery(totalsStatus, totalsOptions) { + const { isRowTotal, isRowSubTotal, isColTotal, isColSubTotal } = totalsStatus + const { row, col } = totalsOptions || {} + const { calcTotals: rowCalcTotals = {}, calcSubTotals: rowCalcSubTotals = {} } = row || {} + const { calcTotals: colCalcTotals = {}, calcSubTotals: colCalcSubTotals = {} } = col || {} + + const getCalcTotals = (dimensionTotals: CalcTotals, isTotal: boolean) => { + if ((dimensionTotals.aggregation || dimensionTotals.calcFunc) && isTotal) { + return { + aggregation: dimensionTotals.aggregation, + calcFunc: dimensionTotals.calcFunc + } + } + } + + // 优先级: 列总计/小计 > 行总计/小计 + return ( + getCalcTotals(colCalcTotals, isColTotal) || + getCalcTotals(colCalcSubTotals, isColSubTotal) || + getCalcTotals(rowCalcTotals, isRowTotal) || + getCalcTotals(rowCalcSubTotals, isRowSubTotal) + ) +} + +export const isNotNumber = (value: unknown) => { + if (typeof value === 'number') { + return Number.isNaN(value) + } + if (!value) { + return true + } + if (typeof value === 'string') { + return Number.isNaN(Number(value)) + } + return true +} + +const processFieldValues = (data: DataItem[], field: string, filterIllegalValue = false) => { + if (!data?.length) { + return [] + } + + return data.reduce>((resultArr, item) => { + const fieldValue = get(item, field) + const notNumber = isNotNumber(fieldValue) + + if (filterIllegalValue && notNumber) { + // 过滤非法值 + return resultArr + } + + const val = notNumber ? 0 : fieldValue + resultArr.push(new Decimal(val)) + + return resultArr + }, []) +} + +export const getDataSumByField = (data: DataItem[], field: string): number => { + const fieldValues = processFieldValues(data, field) + if (!fieldValues.length) { + return 0 + } + + return Decimal.sum(...fieldValues).toNumber() +} + +export const getDataExtremumByField = ( + method: 'min' | 'max', + data: DataItem[], + field: string +): number => { + // 防止预处理时默认值 0 影响极值结果,处理时需过滤非法值 + const fieldValues = processFieldValues(data, field, true) + if (!fieldValues?.length) { + return + } + + return Decimal[method](...fieldValues).toNumber() +} + +export const getDataAvgByField = (data: DataItem[], field: string): number => { + const fieldValues = processFieldValues(data, field) + if (!fieldValues?.length) { + return 0 + } + + return Decimal.sum(...fieldValues) + .dividedBy(fieldValues.length) + .toNumber() +} + +const calcActionByType: { + [type in Aggregation]: (data: DataItem[], field: string) => number +} = { + [Aggregation.SUM]: getDataSumByField, + [Aggregation.MIN]: (data, field) => getDataExtremumByField('min', data, field), + [Aggregation.MAX]: (data, field) => getDataExtremumByField('max', data, field), + [Aggregation.AVG]: getDataAvgByField +} + +class EmptyDataCell extends MergedCell { + drawTextShape(): void { + this.meta.fieldValue = ' ' + super.drawTextShape() + const { rowHeader, columnHeader } = this.spreadsheet.facet + const offsetX = columnHeader.getConfig().viewportWidth / 2 + const offsetY = rowHeader.getConfig().viewportHeight / 2 + const style = this.getTextStyle() + const config = { + attrs: { + ...style, + x: offsetX, + y: offsetY, + text: t('data_set.no_data'), + opacity: 1, + textAlign: 'center', + textBaseline: 'middle' + } + } + this.addShape('text', config) + } + + protected drawBackgroundShape(): void { + const cellTheme = this.theme.dataCell.cell + cellTheme.backgroundColor = setColorOpacity(cellTheme.backgroundColor, 1) + super.drawBackgroundShape() + } +} + +export function setColorOpacity(color: string, opacity: number) { + if (color.indexOf('rgba') !== -1) { + const colorArr = color.split(',') + colorArr[3] = `${opacity})` + return colorArr.join(',') + } + if (color.indexOf('rgb') !== -1) { + return `${color.replace('rgb', 'rgba').replace(')', `,${opacity})`)}` + } + if (color.indexOf('#') !== -1) { + if (color.length === 7) { + return `${color}${Math.round(opacity * 255).toString(16)}` + } + if (color.length === 9) { + return color.slice(0, 7) + Math.round(opacity * 255).toString(16) + } + } + return color +} + +function configEmptyDataStyle(instance: PivotSheet, data: any[]) { + if (data?.length) { + return + } + instance.on(S2Event.LAYOUT_AFTER_RENDER, () => { + const { colLeafNodes, rowLeafNodes } = instance.facet?.layoutResult || {} + if (!colLeafNodes?.length || !rowLeafNodes?.length) { + return + } + const mergedCells = [] + colLeafNodes.forEach((_, colIndex) => { + rowLeafNodes.forEach((__, rowIndex) => { + mergedCells.push({ rowIndex, colIndex }) + }) + }) + instance.options.mergedCell = (s, c, m) => new EmptyDataCell(s, c, m) + instance.interaction.mergeCells(mergedCells) + }) +} diff --git a/frontend/src/data-visualization/chart/components/js/panel/common/common_antv.ts b/frontend/src/data-visualization/chart/components/js/panel/common/common_antv.ts new file mode 100644 index 0000000..8bc7d32 --- /dev/null +++ b/frontend/src/data-visualization/chart/components/js/panel/common/common_antv.ts @@ -0,0 +1,1963 @@ +import { hexColorToRGBA, hexToRgba, measureText, parseJson } from '../../util' +import { + DEFAULT_BASIC_STYLE, + DEFAULT_LEGEND_STYLE, + DEFAULT_XAXIS_STYLE, + DEFAULT_YAXIS_EXT_STYLE, + DEFAULT_YAXIS_STYLE +} from '@/data-visualization/chart/components/editor/util/chart' +import { valueFormatter } from '@/data-visualization/chart/components/js/formatter' +import { AreaOptions, LabelOptions } from '@antv/l7plot' +import { TooltipOptions } from '@antv/l7plot/dist/lib/types/tooltip' +import { FeatureCollection } from '@antv/l7plot/dist/esm/plots/choropleth/types' +import { Datum } from '@antv/g2plot/esm/types/common' +import { Tooltip } from '@antv/g2plot/esm' +import { add } from 'mathjs' +import isEmpty from 'lodash-es/isEmpty' +import _ from 'lodash' +import type { LegendOptions } from '@antv/l7plot/dist/esm/types/legend' +import { CategoryLegendListItem } from '@antv/l7plot-component/dist/lib/types/legend' +import createDom from '@antv/dom-util/esm/create-dom' +import { + CONTAINER_TPL, + ITEM_TPL, + LIST_CLASS +} from '@antv/l7plot-component/dist/esm/legend/category/constants' +import substitute from '@antv/util/esm/substitute' +import type { Plot as L7Plot, PlotOptions } from '@antv/l7plot/dist/esm' +import { Zoom } from '@antv/l7' +import { DOM } from '@antv/l7-utils' +import { Scene } from '@antv/l7-scene' +import { type IZoomControlOption } from '@antv/l7-component' +import { PositionType } from '@antv/l7-core' +import { centroid } from '@turf/centroid' +import type { Plot } from '@antv/g2plot' +import type { PickOptions } from '@antv/g2plot/lib/core/plot' +import { defaults } from 'lodash-es' +import { useI18n } from '@/data-visualization/hooks/web/useI18n' +const { t: tI18n } = useI18n() +import { isMobile } from '@/data-visualization/utils/utils' + +export function getPadding(chart: Chart): number[] { + if (chart.drill) { + return [0, 10, 22, 10] + } else { + return [0, 10, 10, 10] + } +} +// color,label,tooltip,axis,legend,background +export function getTheme(chart: Chart) { + const colors = [] + let bgColor, + labelFontsize, + labelColor, + tooltipColor, + tooltipFontsize, + tooltipBackgroundColor, + legendColor, + legendFontsize + let customAttr: DeepPartial + if (chart.customAttr) { + customAttr = parseJson(chart.customAttr) + // color + if (customAttr.basicStyle) { + const b = JSON.parse(JSON.stringify(customAttr.basicStyle)) + b.colors.forEach(ele => { + colors.push(hexColorToRGBA(ele, b.alpha)) + }) + } + // label + if (customAttr.label) { + const l = JSON.parse(JSON.stringify(customAttr.label)) + labelFontsize = l.fontSize + labelColor = l.color + } + // tooltip + if (customAttr.tooltip) { + const t = JSON.parse(JSON.stringify(customAttr.tooltip)) + tooltipColor = t.color + tooltipFontsize = t.fontSize + tooltipBackgroundColor = t.backgroundColor + } + } + + let customStyle: DeepPartial + if (chart.customStyle) { + customStyle = parseJson(chart.customStyle) + // bg + if (customStyle.background) { + bgColor = hexColorToRGBA(customStyle.background.color, customStyle.background.alpha) + } + // legend + if (customStyle.legend) { + const l = customStyle.legend + legendColor = l.color + legendFontsize = l.fontSize + } + } + + const theme = { + styleSheet: { + brandColor: colors[0], + paletteQualitative10: colors, + paletteQualitative20: colors, + backgroundColor: bgColor + }, + labels: { + offset: 4, + style: { + fill: labelColor, + fontSize: labelFontsize + } + }, + innerLabels: { + offset: 4, + style: { + fill: labelColor, + fontSize: labelFontsize + } + }, + pieLabels: { + offset: 4, + style: { + fill: labelColor, + fontSize: labelFontsize + } + }, + components: { + tooltip: { + domStyles: { + 'g2-tooltip': { + color: tooltipColor, + fontSize: tooltipFontsize + 'px', + background: tooltipBackgroundColor, + boxShadow: '0 4px 8px 0 rgba(0, 0, 0, 0.1)', + 'z-index': 2000, + position: 'fixed' + }, + 'g2-tooltip-list-item': { + display: 'flex', + 'align-items': 'center' + }, + 'g2-tooltip-name': { + display: 'inline-block', + 'line-height': tooltipFontsize + 'px', + flex: 1 + }, + 'g2-tooltip-marker': { + 'min-width': '8px', + 'min-height': '8px' + } + } + }, + legend: { + common: { + itemName: { + style: { + fill: legendColor, + fontSize: legendFontsize + } + } + } + } + } + } + if (chart.fontFamily) { + theme.styleSheet.fontFamily = chart.fontFamily + } + return theme +} +// 通用label +export function getLabel(chart: Chart) { + let label + let customAttr: DeepPartial + if (chart.customAttr) { + customAttr = parseJson(chart.customAttr) + // label + if (customAttr.label) { + const l = customAttr.label + if (l.show) { + const layout = [] + if (!l.fullDisplay) { + if (chart.type === 'bar-stack') { + layout.push({ type: 'interval-hide-overlap' }) + } else if ( + chart.type.indexOf('-horizontal') > -1 || + [ + 'bidirectional-bar', + 'progress-bar', + 'pie-donut', + 'radar', + 'waterfall', + 't-heatmap', + 'bar' + ].includes(chart.type) + ) { + layout.push({ type: 'limit-in-canvas' }) + layout.push({ type: 'hide-overlap' }) + } else if (chart.type.includes('chart-mix')) { + layout.push({ type: 'limit-in-canvas' }) + layout.push({ type: 'limit-in-plot' }) + layout.push({ type: 'hide-overlap' }) + } else { + layout.push({ type: 'limit-in-plot' }) + layout.push({ type: 'hide-overlap' }) + } + } + label = { + position: l.position, + layout, + style: { + fill: l.color, + fontSize: l.fontSize, + fontFamily: chart.fontFamily + }, + formatter: function (param: Datum) { + return valueFormatter(param.value, l.labelFormatter) + } + } + } else { + label = false + } + } + } + return label +} +// 通用tooltip +export function getTooltip(chart: Chart) { + let tooltip + let customAttr: DeepPartial + if (chart.customAttr) { + customAttr = parseJson(chart.customAttr) + // tooltip + if (customAttr.tooltip) { + const t = JSON.parse(JSON.stringify(customAttr.tooltip)) + if (t.show) { + tooltip = { + formatter: function (param: Datum) { + const value = valueFormatter(param.value, t.tooltipFormatter) + return { name: param.field, value } + }, + container: getTooltipContainer(`tooltip-${chart.id}`), + itemTpl: TOOLTIP_TPL, + enterable: true + } + } else { + tooltip = false + } + } + } + return tooltip +} + +export function getMultiSeriesTooltip(chart: Chart) { + const customAttr: DeepPartial = parseJson(chart.customAttr) + const tooltipAttr = customAttr.tooltip + if (!tooltipAttr.show) { + return false + } + const formatterMap = tooltipAttr.seriesTooltipFormatter + ?.filter(i => i.show) + .reduce((pre, next) => { + pre[next.id] = next + return pre + }, {}) as Record + const tooltip: Tooltip = { + showTitle: true, + customItems(originalItems) { + if (!tooltipAttr.seriesTooltipFormatter?.length) { + return originalItems + } + const head = originalItems[0] + // 非原始数据 + if (!head.data.quotaList) { + return originalItems + } + const result = [] + originalItems + .filter(item => formatterMap[item.data.quotaList[0].id]) + .forEach(item => { + const formatter = formatterMap[item.data.quotaList[0].id] + const value = valueFormatter(parseFloat(item.value as string), formatter.formatterCfg) + const name = isEmpty(formatter.chartShowName) ? formatter.name : formatter.chartShowName + const color = getTooltipItemConditionColor(item) + result.push({ ...item, name, value, ...(color ? { color } : {}) }) + }) + head.data.dynamicTooltipValue?.forEach(item => { + const formatter = formatterMap[item.fieldId] + if (formatter) { + const value = valueFormatter(parseFloat(item.value), formatter.formatterCfg) + const name = isEmpty(formatter.chartShowName) ? formatter.name : formatter.chartShowName + result.push({ color: 'grey', name, value }) + } + }) + return result + }, + container: getTooltipContainer(`tooltip-${chart.id}`), + itemTpl: TOOLTIP_TPL, + enterable: true + } + return tooltip +} +// 通用legend +export function getLegend(chart: Chart) { + let legend = {} + let customStyle: CustomStyle + if (chart.customStyle) { + customStyle = parseJson(chart.customStyle) + // legend + if (customStyle.legend) { + const l = defaults(JSON.parse(JSON.stringify(customStyle.legend)), DEFAULT_LEGEND_STYLE) + if (l.show) { + let offsetX, offsetY, position + const orient = l.orient + const legendSymbol = l.icon + // fix position + if (l.hPosition === 'center') { + position = l.vPosition === 'center' ? 'top' : l.vPosition + } else if (l.vPosition === 'center') { + position = l.hPosition === 'center' ? 'left' : l.hPosition + } else { + if (orient === 'horizontal') { + position = l.vPosition + '-' + l.hPosition + } else { + position = l.hPosition + '-' + l.vPosition + } + } + // fix offset + if (orient === 'horizontal') { + if (l.hPosition === 'left') { + offsetX = 16 + } else if (l.hPosition === 'right') { + offsetX = -16 + } else { + offsetX = 0 + } + if (l.vPosition === 'top') { + offsetY = 0 + } else if (l.vPosition === 'bottom') { + if (chart.drill) { + offsetY = -12 + } + } else { + offsetY = 0 + } + } else { + if (l.hPosition === 'left') { + offsetX = 10 + } else if (l.hPosition === 'right') { + offsetX = -10 + } else { + offsetX = 0 + } + if (l.vPosition === 'top') { + offsetY = 0 + } else if (l.vPosition === 'bottom') { + if (chart.drill) { + offsetY = -18 + } else { + offsetY = -10 + } + } else { + offsetY = 0 + } + } + + legend = { + layout: orient, + position: position, + offsetX: offsetX, + offsetY: offsetY, + marker: { + symbol: legendSymbol, + style: { + r: l.size + } + }, + itemName: { + style: { + fill: l.color, + fontSize: l.fontSize + } + }, + itemHeight: (l.fontSize > l.size * 2 ? l.fontSize : l.size * 2) + 4, + radio: false, + pageNavigator: { + marker: { + style: { + fill: 'rgba(0,0,0,0.65)', + stroke: 'rgba(192,192,192,0.52)', + size: l.size * 2 + } + }, + text: { + style: { + fill: l.color, + fontSize: l.fontSize + } + } + } + } + } else { + legend = false + } + } + } + return legend +} +// xAxis +export function getXAxis(chart: Chart) { + let axis: Record | boolean = {} + let customStyle: CustomStyle + if (chart.customStyle) { + customStyle = parseJson(chart.customStyle) + // legend + if (customStyle.xAxis) { + const a = JSON.parse(JSON.stringify(customStyle.xAxis)) + if (a.show) { + const title = + a.nameShow && a.name && a.name !== '' + ? { + text: a.name, + style: { + fill: a.color, + fontSize: a.fontSize + }, + spacing: 8 + } + : null + const grid = a.splitLine.show + ? { + line: { + style: { + stroke: a.splitLine.lineStyle.color, + lineWidth: a.splitLine.lineStyle.width, + lineDash: getLineDash(a.splitLine.lineStyle.style) + } + } + } + : null + const axisCfg = a.axisLine ? a.axisLine : DEFAULT_XAXIS_STYLE.axisLine + const line = axisCfg.show + ? { + style: { + stroke: axisCfg.lineStyle.color, + lineWidth: axisCfg.lineStyle.width, + lineDash: getLineDash(axisCfg.lineStyle.style) + } + } + : null + const tickLine = axisCfg.show + ? { + style: { + stroke: axisCfg.lineStyle.color, + lineWidth: axisCfg.lineStyle.width + } + } + : null + let textAlign = 'center' + const rotate = a.axisLabel.rotate + if (a.position === 'top') { + textAlign = rotate > 20 ? 'end' : rotate < -20 ? 'start' : 'center' + } + if (a.position === 'bottom') { + textAlign = rotate > 20 ? 'start' : rotate < -20 ? 'end' : 'center' + } + const label = a.axisLabel.show + ? { + rotate: (rotate * Math.PI) / 180, + style: { + fill: a.axisLabel.color, + fontSize: a.axisLabel.fontSize, + textAlign: textAlign + }, + formatter: value => { + return chart.type === 'bidirectional-bar' && value.length > a.axisLabel.lengthLimit + ? value.substring(0, a.axisLabel.lengthLimit) + '...' + : value + } + } + : null + + axis = { + position: a.position, + title, + grid, + label, + line, + tickLine + } + } else { + axis = false + } + } + } + return axis +} +// yAxis +export function getYAxis(chart: Chart) { + let axis: Record | boolean = {} + const yAxis = parseJson(chart.customStyle).yAxis + if (!yAxis.show) { + return false + } + const title = + yAxis.nameShow && yAxis.name && yAxis.name !== '' + ? { + text: yAxis.name, + style: { + fill: yAxis.color, + fontSize: yAxis.fontSize + }, + spacing: 8 + } + : null + const grid = yAxis.splitLine.show + ? { + line: { + style: { + stroke: yAxis.splitLine.lineStyle.color, + lineWidth: yAxis.splitLine.lineStyle.width, + lineDash: getLineDash(yAxis.splitLine.lineStyle.style) + } + } + } + : null + const axisCfg = yAxis.axisLine ? yAxis.axisLine : DEFAULT_YAXIS_STYLE.axisLine + const line = axisCfg.show + ? { + style: { + stroke: axisCfg.lineStyle.color, + lineWidth: axisCfg.lineStyle.width, + lineDash: getLineDash(axisCfg.lineStyle.style) + } + } + : null + const tickLine = axisCfg.show + ? { + style: { + stroke: axisCfg.lineStyle.color, + lineWidth: axisCfg.lineStyle.width + } + } + : null + const rotate = yAxis.axisLabel.rotate + let textAlign = 'end' + let textBaseline = 'middle' + if (yAxis.position === 'right') { + textAlign = 'start' + if (Math.abs(rotate) > 75) { + textAlign = 'center' + } + if (rotate > 75) { + textBaseline = 'bottom' + } + if (rotate < -75) { + textBaseline = 'top' + } + } + if (yAxis.position === 'left') { + if (Math.abs(rotate) > 75) { + textAlign = 'center' + } + if (rotate > 75) { + textBaseline = 'top' + } + if (rotate < -75) { + textBaseline = 'bottom' + } + } + const label = yAxis.axisLabel.show + ? { + rotate: (rotate * Math.PI) / 180, + style: { + fill: yAxis.axisLabel.color, + fontSize: yAxis.axisLabel.fontSize, + textBaseline, + textAlign + }, + formatter: value => { + return value.length > yAxis.axisLabel.lengthLimit + ? value.substring(0, yAxis.axisLabel.lengthLimit) + '...' + : value + } + } + : null + + axis = { + position: yAxis.position, + title, + grid, + label, + line, + tickLine, + nice: true + } + return axis +} + +export function getYAxisExt(chart: Chart) { + let axis: Record | boolean = {} + const yAxis = parseJson(chart.customStyle).yAxisExt + if (!yAxis.show) { + return false + } + const title = + yAxis.name && yAxis.name !== '' + ? { + text: yAxis.name, + style: { + fill: yAxis.color, + fontSize: yAxis.fontSize + }, + spacing: 8 + } + : null + const grid = yAxis.splitLine.show + ? { + line: { + style: { + stroke: yAxis.splitLine.lineStyle.color, + lineWidth: yAxis.splitLine.lineStyle.width, + lineDash: getLineDash(yAxis.splitLine.lineStyle.style) + } + } + } + : null + const axisCfg = yAxis.axisLine ? yAxis.axisLine : DEFAULT_YAXIS_STYLE.axisLine + const line = axisCfg.show + ? { + style: { + stroke: axisCfg.lineStyle.color, + lineWidth: axisCfg.lineStyle.width + } + } + : null + const tickLine = axisCfg.show + ? { + style: { + stroke: axisCfg.lineStyle.color + } + } + : null + const rotate = yAxis.axisLabel.rotate + let textAlign = 'end' + let textBaseline = 'middle' + if (yAxis.position === 'right') { + textAlign = 'start' + if (Math.abs(rotate) > 75) { + textAlign = 'center' + } + if (rotate > 75) { + textBaseline = 'bottom' + } + if (rotate < -75) { + textBaseline = 'top' + } + } + if (yAxis.position === 'left') { + if (Math.abs(rotate) > 75) { + textAlign = 'center' + } + if (rotate > 75) { + textBaseline = 'top' + } + if (rotate < -75) { + textBaseline = 'bottom' + } + } + const label = yAxis.axisLabel.show + ? { + rotate: (rotate * Math.PI) / 180, + style: { + fill: yAxis.axisLabel.color, + fontSize: yAxis.axisLabel.fontSize, + textBaseline, + textAlign + } + } + : null + + axis = { + position: yAxis.position, + title, + grid, + label, + line, + tickLine, + nice: true + } + return axis +} + +export function getSlider(chart: Chart) { + let cfg + const senior = parseJson(chart.senior) + if (senior.functionCfg) { + if (senior.functionCfg.sliderShow) { + cfg = { + start: senior.functionCfg.sliderRange[0] / 100, + end: senior.functionCfg.sliderRange[1] / 100 + } + + if (senior.functionCfg.sliderBg) { + cfg.backgroundStyle = { + fill: senior.functionCfg.sliderBg, + stroke: senior.functionCfg.sliderBg, + lineWidth: 1, + strokeOpacity: 0.5 + } + } + if (senior.functionCfg.sliderFillBg) { + cfg.foregroundStyle = { + fill: senior.functionCfg.sliderFillBg, + fillOpacity: 0.5 + } + } + if (senior.functionCfg.sliderTextColor) { + cfg.textStyle = { + fill: senior.functionCfg.sliderTextColor, + fontFamily: chart.fontFamily + } + cfg.handlerStyle = { + fill: senior.functionCfg.sliderTextColor, + fillOpacity: 0.5, + highLightFill: senior.functionCfg.sliderTextColor + } + } + } + } + return cfg +} + +export function getAnalyse(chart: Chart) { + const assistLine = [] + const senior = parseJson(chart.senior) + if (!senior.assistLineCfg?.enable) { + return assistLine + } + const assistLineArr = senior.assistLineCfg.assistLine + if (assistLineArr?.length > 0) { + const customStyle = parseJson(chart.customStyle) + let yAxisPosition, axisFormatterCfg, yAxisExtPosition, axisExtFormatterCfg + if (customStyle.yAxis) { + const a = JSON.parse(JSON.stringify(customStyle.yAxis)) + yAxisPosition = a.position + axisFormatterCfg = a.axisLabelFormatter + ? a.axisLabelFormatter + : DEFAULT_YAXIS_STYLE.axisLabelFormatter + } + if (customStyle.yAxisExt) { + const a = JSON.parse(JSON.stringify(customStyle.yAxisExt)) + yAxisExtPosition = a.position + axisExtFormatterCfg = a.axisLabelFormatter + ? a.axisLabelFormatter + : DEFAULT_YAXIS_EXT_STYLE.axisLabelFormatter + } + + const fixedLines = assistLineArr.filter(ele => ele.field === '0') + const dynamicLineFields = assistLineArr + .filter(ele => ele.field === '1') + .map(item => item.fieldId) + const quotaFields = _.filter(chart.yAxis, ele => ele.summary !== '' && ele.id !== '-1') + const quotaExtFields = _.filter(chart.yAxisExt, ele => ele.summary !== '' && ele.id !== '-1') + const dynamicLines = chart.data.dynamicAssistLines?.filter(item => { + return ( + dynamicLineFields?.includes(item.fieldId) && + (!!_.find(quotaFields, d => d.id === item.fieldId) || + (!!_.find(quotaExtFields, d => d.id === item.fieldId) && + chart.type.includes('chart-mix'))) + ) + }) + const lines = fixedLines.concat(dynamicLines || []) + lines.forEach(ele => { + const value = parseFloat(ele.value) + const content = + ele.name + + ' : ' + + valueFormatter(value, ele.yAxisType === 'left' ? axisFormatterCfg : axisExtFormatterCfg) + assistLine.push({ + type: 'line', + yAxisType: ele.yAxisType, + start: ['start', value], + end: ['end', value], + style: { + stroke: ele.color, + lineDash: getLineDash(ele.lineType) + } + }) + assistLine.push({ + type: 'text', + yAxisType: ele.yAxisType, + position: [ + (ele.yAxisType === 'left' ? yAxisPosition : yAxisExtPosition) === 'left' + ? 'start' + : 'end', + value + ], + content: content, + offsetY: -2, + offsetX: + (ele.yAxisType === 'left' ? yAxisPosition : yAxisExtPosition) === 'left' + ? 2 + : -10 * (content.length - 2), + style: { + textBaseline: 'bottom', + fill: ele.color, + fontSize: ele.fontSize ? ele.fontSize : 10 + } + }) + }) + } + return assistLine +} + +export function getAnalyseHorizontal(chart: Chart) { + const assistLine = [] + const senior = parseJson(chart.senior) + if (!senior.assistLineCfg?.enable) { + return assistLine + } + const assistLineArr = senior.assistLineCfg.assistLine + if (assistLineArr?.length > 0) { + const customStyle = parseJson(chart.customStyle) + let xAxisPosition, axisFormatterCfg + if (customStyle.xAxis) { + const a = JSON.parse(JSON.stringify(customStyle.xAxis)) + xAxisPosition = transAxisPosition(a.position) + axisFormatterCfg = a.axisLabelFormatter + ? a.axisLabelFormatter + : DEFAULT_XAXIS_STYLE.axisLabelFormatter + } + + const fixedLines = assistLineArr.filter(ele => ele.field === '0') + const dynamicLineFields = assistLineArr + .filter(ele => ele.field === '1') + .map(item => item.fieldId) + const quotaFields = _.filter(chart.yAxis, ele => ele.summary !== '' && ele.id !== '-1') + const dynamicLines = chart.data.dynamicAssistLines?.filter( + item => + dynamicLineFields?.includes(item.fieldId) && + !!_.find(quotaFields, d => d.id === item.fieldId) + ) + const lines = fixedLines.concat(dynamicLines || []) + + lines.forEach(ele => { + const value = parseFloat(ele.value) + const content = ele.name + ' : ' + valueFormatter(value, axisFormatterCfg) + assistLine.push({ + type: 'line', + start: ['start', value], + end: ['end', value], + style: { + stroke: ele.color, + lineDash: getLineDash(ele.lineType) + } + }) + assistLine.push({ + type: 'text', + position: ['start', value], + content: content, + offsetY: 5, + offsetX: 2, + rotate: Math.PI / 2, + style: { + textBaseline: 'bottom', + fill: ele.color, + fontSize: ele.fontSize ? ele.fontSize : 10 + } + }) + }) + } + return assistLine +} + +export function getLineDash(type) { + switch (type) { + case 'solid': + return [0, 0] + case 'dashed': + return [10, 8] + case 'dotted': + return [2, 2] + default: + return [0, 0] + } +} + +/** + * 将 RGBA 格式的颜色转换成 ANTV 支持的渐变色格式 + * @param rawColor 原始 RGBA 颜色 + * @param show + * @param angle 渐变角度 + * @param start 起始值 + */ +export function setGradientColor(rawColor: string, show = false, angle = 0, start = 0) { + const item = rawColor.split(',') + item.splice(3, 1, '0.3)') + let color: string + if (start == 0) { + color = `l(${angle}) 0:${item.join(',')} 1:${rawColor}` + } else if (start > 0) { + color = `l(${angle}) 0:rgba(255,255,255,0) ${start}:${item.join(',')} 1:${rawColor}` + } else { + color = `l(${angle}) 0:rgba(255,255,255,0) 0.1:${item.join(',')} 1:${rawColor}` + } + return show ? color : rawColor +} + +export function transAxisPosition(position: string): string { + switch (position) { + case 'top': + return 'left' + case 'bottom': + return 'right' + case 'left': + return 'bottom' + case 'right': + return 'top' + default: + return position + } +} + +export function configL7Label(chart: Chart): false | LabelOptions { + const customAttr = parseJson(chart.customAttr) + const label = customAttr.label + const style = { + fill: label.color, + fontSize: label.fontSize, + textAllowOverlap: true, + fontWeight: 'bold' + } + if (!label.fullDisplay) { + style.textAllowOverlap = false + style.padding = [2, 2] + } + if (chart.fontFamily) { + style.fontFamily = chart.fontFamily + } + return { + visible: label.show, + style + } +} + +export function configL7Style(chart: Chart): AreaOptions['style'] { + const customAttr = parseJson(chart.customAttr) + return { + stroke: customAttr.basicStyle.areaBorderColor + } +} + +export function configL7Tooltip(chart: Chart): TooltipOptions { + const customAttr = parseJson(chart.customAttr) + const tooltip = customAttr.tooltip + const formatterMap = tooltip.seriesTooltipFormatter + ?.filter(i => i.show) + .reduce((pre, next) => { + pre[next.id] = next + return pre + }, {}) as Record + const container = document.getElementById(chart.container) + if (container) { + container.addEventListener('mousemove', event => { + const rect = container.getBoundingClientRect() + const mouseX = event.clientX - rect.left + const mouseY = event.clientY - rect.top + const tooltipElement = container.getElementsByClassName('l7plot-tooltip-container') + for (let i = 0; i < tooltipElement?.length; i++) { + const element = tooltipElement[i] as HTMLElement + const isNearRightEdge = container.clientWidth - mouseX <= element.clientWidth + const isNearBottomEdge = container.clientHeight - mouseY <= element.clientHeight + let transform = '' + if (isNearRightEdge) { + transform += 'translateX(-120%) ' + } + if (isNearBottomEdge) { + transform += 'translateY(-100%) ' + } + if (transform) { + element.style.transform = transform.trim() + } + } + }) + } + return { + customTitle(data) { + return data.name + }, + customItems(originalItem) { + const result = [] + if (isEmpty(formatterMap)) { + return result + } + const head = originalItem.properties + const formatter = formatterMap[head.quotaList?.[0]?.id] + if (!isEmpty(formatter)) { + const originValue = parseFloat(head.value as string) + const value = valueFormatter(originValue, formatter.formatterCfg) + const name = isEmpty(formatter.chartShowName) ? formatter.name : formatter.chartShowName + result.push({ ...head, name, value: `${value ?? ''}` }) + } + head.dynamicTooltipValue?.forEach(item => { + const formatter = formatterMap[item.fieldId] + if (formatter) { + const value = valueFormatter(parseFloat(item.value), formatter.formatterCfg) + const name = isEmpty(formatter.chartShowName) ? formatter.name : formatter.chartShowName + result.push({ color: 'grey', name, value: `${value ?? ''}` }) + } + }) + return result + }, + showComponent: tooltip.show, + domStyles: { + 'l7plot-tooltip': { + 'background-color': tooltip.backgroundColor, + 'font-size': `${tooltip.fontSize}px`, + 'line-height': 1.6, + 'font-family': chart.fontFamily ? chart.fontFamily : undefined + }, + 'l7plot-tooltip__name': { + color: tooltip.color + }, + 'l7plot-tooltip__value': { + color: tooltip.color + }, + 'l7plot-tooltip__title': { + color: tooltip.color + } + } + } +} + +export function handleGeoJson(geoJson: FeatureCollection, nameMapping?: Record) { + geoJson.features.forEach(item => { + if (!item.properties['centroid']) { + if (item.properties['center']) { + item.properties['centroid'] = item.properties['center'] + } else { + const tmp = centroid(item.geometry) + item.properties['centroid'] = tmp.geometry.coordinates + } + } + let name = item.properties['name'] + if (nameMapping?.[name]) { + name = nameMapping[name] + item.properties['name'] = name + } + }) +} + +export function getTooltipSeriesTotalMap(data: any[]): Record { + const result = {} + data?.forEach(item => { + item.dynamicTooltipValue?.forEach(ele => { + if (!result[ele.fieldId]) { + result[ele.fieldId] = 0 + } + if (ele.value) { + result[ele.fieldId] = add(result[ele.fieldId], ele.value) + } + }) + }) + return result +} +const LEGEND_SHAPE_STYLE_MAP = { + circle: { + borderRadius: '50%' + }, + square: {}, + triangle: { + borderLeft: '5px solid transparent', + borderRight: '5px solid transparent', + borderBottom: '10px solid var(--bgColor)', + background: 'unset' + }, + diamond: { + transform: 'rotate(45deg)' + } +} +export function configL7Legend(chart: Chart): LegendOptions | false { + const { basicStyle } = parseJson(chart.customAttr) + if (basicStyle.suspension === false && basicStyle.showZoom === undefined) { + return false + } + const { legend } = parseJson(chart.customStyle) + if (!legend.show) { + return false + } + return { + position: 'bottomleft', + customContent: (_: string, items: CategoryLegendListItem[]) => { + const showItems = items?.length > 30 ? items.slice(0, 30) : items + if (showItems?.length) { + const containerDom = createDom(CONTAINER_TPL) as HTMLElement + const listDom = containerDom.getElementsByClassName(LIST_CLASS)[0] as HTMLElement + showItems.forEach(item => { + let value = '-' + if (item.value !== '') { + if (Array.isArray(item.value)) { + item.value.forEach((v, i) => { + item.value[i] = Number.isNaN(v) || v === 'NaN' ? 'NaN' : parseFloat(v).toFixed(0) + }) + value = item.value.join('-') + } else { + const tmp = item.value as string + value = Number.isNaN(tmp) || tmp === 'NaN' ? 'NaN' : parseFloat(tmp).toFixed(0) + } + } + const substituteObj = { ...item, value } + + const domStr = substitute(ITEM_TPL, substituteObj) + const itemDom = createDom(domStr) + // 给 legend 形状用的 + itemDom.style.setProperty('--bgColor', item.color) + listDom.appendChild(itemDom) + }) + return listDom + } + return '' + }, + domStyles: { + 'l7plot-legend__category-value': { + fontSize: legend.fontSize + 'px', + color: legend.color + }, + 'l7plot-legend__category-marker': { + ...LEGEND_SHAPE_STYLE_MAP[legend.icon] + } + } + } +} +const ZOOM_IN_BTN = + '' +const RESET_BTN = + '' +const ZOOM_OUT_BTN = + '' +export class CustomZoom extends Zoom { + resetButtonGroup(container) { + DOM.clearChildren(container) + this['zoomInButton'] = this['createButton']( + this.controlOption.zoomInText, + this.controlOption.zoomInTitle, + 'l7-button-control', + container, + this.zoomIn + ) + this['zoomResetButton'] = this['createButton']( + this.controlOption['resetText'], + 'Reset', + 'l7-button-control', + container, + () => { + if (this.controlOption['bounds']) { + this.mapsService.fitBounds(this.controlOption['bounds'], { animate: true }) + } else { + this.mapsService.setZoomAndCenter( + this.controlOption['initZoom'], + this.controlOption['center'] + ) + } + } + ) + if (this.controlOption.showZoom) { + this['zoomNumDiv'] = this['createButton']( + '0', + '', + 'l7-button-control l7-control-zoom__number', + container + ) + } + this['zoomOutButton'] = this['createButton']( + this.controlOption.zoomOutText, + this.controlOption.zoomOutTitle, + 'l7-button-control', + container, + this.zoomOut + ) + const { buttonBackground } = this.controlOption as any + const elements = [this['zoomResetButton'], this['zoomInButton'], this['zoomOutButton']] + if (buttonBackground) { + setStyle(elements, 'background', buttonBackground) + } + setStyle(elements, 'border-bottom', 'none') + this['updateDisabled']() + } + public getDefault(option: Partial) { + const { buttonColor } = option as any + let zoomInText = ZOOM_IN_BTN + let zoomOutText = ZOOM_OUT_BTN + let resetText = RESET_BTN + if (buttonColor) { + zoomInText = zoomInText.replace('${fill}', buttonColor) + zoomOutText = zoomOutText.replace('${fill}', buttonColor) + resetText = resetText.replace('${fill}', buttonColor) + } + return { + ...option, + position: PositionType.BOTTOMRIGHT, + name: 'zoom', + zoomInText, + zoomInTitle: 'Zoom in', + zoomOutText, + zoomOutTitle: 'Zoom out', + resetText, + showZoom: false + } as IZoomControlOption + } +} +export function configL7Zoom(chart: Chart, scene: Scene) { + const { basicStyle } = parseJson(chart.customAttr) + const zoomOption = scene?.getControlByName('zoom') + if (zoomOption) { + scene.removeControl(zoomOption) + } + if (shouldHideZoom(basicStyle)) { + return + } + if (!scene?.getControlByName('zoom')) { + if (!scene.map) { + scene.once('loaded', () => { + scene.map.on('complete', () => { + const initZoom = basicStyle.autoFit === false ? basicStyle.zoomLevel : scene.getZoom() + const center = + basicStyle.autoFit === false + ? [basicStyle.mapCenter.longitude, basicStyle.mapCenter.latitude] + : [scene.map.getCenter().lng, scene.map.getCenter().lat] + const newZoomOptions = { + initZoom: initZoom, + center: center, + buttonColor: basicStyle.zoomButtonColor, + buttonBackground: basicStyle.zoomBackground + } as any + scene.addControl(new CustomZoom(newZoomOptions)) + }) + }) + } else { + const newZoomOptions = { + buttonColor: basicStyle.zoomButtonColor, + buttonBackground: basicStyle.zoomBackground + } as any + if (basicStyle.autoFit === false) { + newZoomOptions.initZoom = basicStyle.zoomLevel + newZoomOptions.center = [basicStyle.mapCenter.longitude, basicStyle.mapCenter.latitude] + } else { + const coordinates: [][] = [] + if (chart.type === 'flow-map') { + const startAxis = chart.xAxis + const endAxis = chart.xAxisExt + if (startAxis?.length === 2) { + chart.data?.tableRow?.forEach(row => { + coordinates.push([row[startAxis[0].dataeaseName], row[startAxis[1].dataeaseName]]) + }) + } + if (endAxis?.length === 2) { + chart.data?.tableRow?.forEach(row => { + coordinates.push([row[endAxis[0].dataeaseName], row[endAxis[1].dataeaseName]]) + }) + } + } else { + const axis = chart.xAxis + if (axis?.length === 2) { + chart.data?.tableRow?.forEach(row => { + coordinates.push([row[axis[0].dataeaseName], row[axis[1].dataeaseName]]) + }) + } + } + newZoomOptions.bounds = calculateBounds(coordinates) + } + scene.addControl(new CustomZoom(newZoomOptions)) + } + } +} +/** + * 计算经纬度数据的边界点 + * @param coordinates 经纬度数组 [[lng, lat], [lng, lat], ...] + * @returns {[[number, number], [number, number]]} 返回东北角和西南角的坐标 + */ +export function calculateBounds(coordinates: number[][]): { + northEast: [number, number] + southWest: [number, number] +} { + if (!coordinates || coordinates.length === 0) { + return { + northEast: [180, 90], + southWest: [-180, -90] + } + } + + let maxLng = -180 + let minLng = 180 + let maxLat = -90 + let minLat = 90 + + coordinates.forEach(([lng, lat]) => { + maxLng = Math.max(maxLng, lng) + minLng = Math.min(minLng, lng) + maxLat = Math.max(maxLat, lat) + minLat = Math.min(minLat, lat) + }) + + return [ + [maxLng, maxLat], // 东北角坐标 + [minLng, minLat] // 西南角坐标 + ] +} + +export function configL7PlotZoom(chart: Chart, plot: L7Plot) { + const { basicStyle } = parseJson(chart.customAttr) + if (shouldHideZoom(basicStyle)) { + return + } + plot.once('loaded', () => { + const zoomOptions = { + initZoom: plot.scene.getZoom(), + center: plot.scene.getCenter(), + buttonColor: basicStyle.zoomButtonColor, + buttonBackground: basicStyle.zoomBackground + } as any + plot.scene.addControl(new CustomZoom(zoomOptions)) + }) +} + +function setStyle(elements: HTMLElement[], styleProp: string, value) { + elements.forEach(e => { + e.style[styleProp] = value + }) +} + +export function mapRendering(dom: HTMLElement | string) { + if (typeof dom === 'string') { + dom = document.getElementById(dom) + } + dom.classList.add('de-map-rendering') +} + +export function mapRendered(dom: HTMLElement | string) { + if (typeof dom === 'string') { + dom = document.getElementById(dom) + } + dom.classList.add('de-map-rendered') +} + +/** + * 隐藏缩放控件 + * @param basicStyle + */ +function shouldHideZoom(basicStyle: any): boolean { + return ( + (basicStyle.suspension === false && basicStyle.showZoom === undefined) || + basicStyle.showZoom === false + ) +} + +const G2_TOOLTIP_WRAPPER = 'g2-tooltip-wrapper' +export function getTooltipContainer(id) { + let wrapperDom = document.getElementById(G2_TOOLTIP_WRAPPER) + if (!wrapperDom) { + wrapperDom = document.createElement('div') + wrapperDom.id = G2_TOOLTIP_WRAPPER + document.body.appendChild(wrapperDom) + } + const curDom = document.getElementById(id) + if (curDom) { + curDom.remove() + } + const g2Tooltip = document.createElement('div') + g2Tooltip.setAttribute('id', id) + g2Tooltip.classList.add('g2-tooltip') + // 最多半屏,鼠标移入可滚动 + g2Tooltip.style.maxHeight = '50%' + isMobile() ? (g2Tooltip.style.maxWidth = '50%') : (g2Tooltip.style.maxWidth = '25%') + g2Tooltip.style.overflowY = 'auto' + g2Tooltip.style.display = 'none' + g2Tooltip.style.position = 'fixed' + g2Tooltip.style.left = '0px' + g2Tooltip.style.top = '0px' + const g2TooltipTitle = document.createElement('div') + g2TooltipTitle.classList.add('g2-tooltip-title') + g2Tooltip.appendChild(g2TooltipTitle) + + const g2TooltipList = document.createElement('ul') + g2TooltipList.classList.add('g2-tooltip-list') + g2Tooltip.appendChild(g2TooltipList) + const full = document.getElementsByClassName('fullscreen') + if (full.length) { + full.item(0).appendChild(g2Tooltip) + } else { + wrapperDom.appendChild(g2Tooltip) + } + return g2Tooltip +} +export function configPlotTooltipEvent>( + chart: Chart, + plot: P +) { + const { tooltip } = parseJson(chart.customAttr) + if (!tooltip.show) { + return + } + // 鼠标可移入, 移入之后保持显示, 移出之后隐藏 + plot.options.tooltip.container.addEventListener('mouseenter', e => { + e.target.style.visibility = 'visible' + e.target.style.display = 'block' + }) + plot.options.tooltip.container.addEventListener('mouseleave', e => { + e.target.style.visibility = 'hidden' + e.target.style.display = 'none' + }) + // 手动处理 tooltip 的显示和隐藏事件,需配合源码理解 + // https://github.com/antvis/G2/blob/master/src/chart/controller/tooltip.ts#showTooltip + plot.on('tooltip:show', () => { + const tooltipCtl = plot.chart.getController('tooltip') + if (!tooltipCtl) { + return + } + const event = plot.chart.interactions.tooltip?.context?.event + if (tooltipCtl.tooltip) { + // 处理视图放大后再关闭 tooltip 的 dom 被清除 + const container = tooltipCtl.tooltip.cfg.container + container.style.display = 'block' + const dom = document.getElementById(container.id) + if (!dom) { + const full = document.getElementsByClassName('fullscreen') + if (full.length) { + full.item(0).appendChild(container) + } else { + const wrapperDom = document.getElementById(G2_TOOLTIP_WRAPPER) + wrapperDom.appendChild(container) + } + } + } + plot.chart.getOptions().tooltip.follow = false + tooltipCtl.title = Math.random().toString() + plot.chart.getTheme().components.tooltip.x = event.clientX + plot.chart.getTheme().components.tooltip.y = event.clientY + }) + // https://github.com/antvis/G2/blob/master/src/chart/controller/tooltip.ts#hideTooltip + plot.on('plot:leave', () => { + const tooltipCtl = plot.chart.getController('tooltip') + if (!tooltipCtl) { + return + } + plot.chart.getOptions().tooltip.follow = true + const container = tooltipCtl.tooltip?.cfg?.container + if (container) { + container.style.display = 'none' + } + tooltipCtl.hideTooltip() + }) + // 移动端处理,关闭其他图表的提示 + plot.on('plot:touchstart', () => { + const wrapperDom = document.getElementById(G2_TOOLTIP_WRAPPER) + if (wrapperDom) { + const tooltipCtl = plot.chart.getController('tooltip') + if (!tooltipCtl) { + return + } + const container = tooltipCtl.tooltip.cfg.container + for (const ele of wrapperDom.children) { + if (container.id !== ele.id) { + ele.style.display = 'none' + } + } + } + }) +} + +export const TOOLTIP_TPL = + '
  • ' + + '' + + '{name}:' + + '{value}' + + '
  • ' + +export function getConditions(chart: Chart) { + const { threshold } = parseJson(chart.senior) + const annotations = [] + if (!threshold.enable || chart.type === 'area-stack' || chart.type === 'symbolic-map') + return annotations + const conditions = threshold.lineThreshold ?? [] + const yAxisIds = chart.yAxis.map(i => i.id) + for (const field of conditions) { + if (!yAxisIds.includes(field.fieldId)) { + continue + } + for (const t of field.conditions) { + const annotation = { + type: 'regionFilter', + start: ['start', 'median'], + end: ['end', 'min'], + color: t.color + } + // 加中线 + const annotationLine = { + type: 'line', + start: ['start', t.value], + end: ['end', t.value], + style: { + stroke: t.color, + lineDash: [2, 2] + } + } + if (t.term === 'between') { + annotation.start = ['start', parseFloat(t.min)] + annotation.end = ['end', parseFloat(t.max)] + annotationLine.start = ['start', parseFloat(t.min)] + annotationLine.end = ['end', parseFloat(t.min)] + annotations.push(JSON.parse(JSON.stringify(annotationLine))) + annotationLine.start = ['start', parseFloat(t.max)] + annotationLine.end = ['end', parseFloat(t.max)] + annotations.push(annotationLine) + } else if (['lt', 'le'].includes(t.term)) { + annotation.start = ['start', t.value] + annotation.end = ['end', 'min'] + annotations.push(annotationLine) + } else if (['gt', 'ge'].includes(t.term)) { + annotation.start = ['start', t.value] + annotation.end = ['end', 'max'] + annotations.push(annotationLine) + } + annotations.push(annotation) + } + } + return annotations +} +const AXIS_LABEL_TOOLTIP_STYLE = { + transition: + 'left 0.4s cubic-bezier(0.23, 1, 0.32, 1) 0s, top 0.4s cubic-bezier(0.23, 1, 0.32, 1) 0s', + backgroundColor: 'rgb(255, 255, 255)', + boxShadow: 'rgb(174, 174, 174) 0px 0px 10px', + borderRadius: '3px', + padding: '8px 12px', + opacity: '0.95', + position: 'absolute', + visibility: 'visible' +} +const AXIS_LABEL_TOOLTIP_TPL = + '
    ' + '
    {title}
    ' + '
    ' +export function configAxisLabelLengthLimit(chart, plot, triggerObjName) { + // 设置触发事件的名称,如果未传入,则默认为 'axis-label' + const triggerName = triggerObjName || 'axis-label' + + // 判断是否是Y轴标题 + const isYaxisTitle = triggerName === 'axis-title' + + // 解析图表的自定义样式和属性 + const { customStyle, customAttr } = parseJson(chart) + const { lengthLimit, fontSize, color, show } = customStyle.yAxis.axisLabel + const { tooltip } = customAttr + + // 如果不是标题,判断没有设置长度限制、没有显示或Y轴不显示,或图表类型为双向条形图,则不执行后续操作 + if ( + !isYaxisTitle && + (!lengthLimit || !show || !customStyle.yAxis.show || chart.type === 'bidirectional-bar') + ) + return + + // 鼠标进入事件 + plot.on(triggerName + ':mouseenter', e => { + const field = e.target.cfg.delegateObject.component.cfg.field + const position = e.target.cfg.delegateObject.component.cfg.position + const isYaxis = position === 'left' || position === 'right' + + // 如果不是 'field' 或 'title',且不是Y轴,直接返回 + if (field !== 'field' && field !== 'title' && !isYaxis) return + + // 获取轴标签的实际内容 + const realContent = e.target.attrs.text + + // 不是标题时,判断标签长度小于限制或已经省略(以'...'结尾),则不显示 tooltip + if ( + isYaxisTitle ? false : realContent.length < lengthLimit || !(realContent.slice(-3) === '...') + ) + return + + // 获取当前鼠标事件的坐标 + const { x, y } = e + const parentNode = e.event.target.parentNode + + // 获取父节点中是否已有 tooltip + let labelTooltipDom = parentNode.getElementsByClassName('g2-axis-label-tooltip')[0] + + // 获取轴的标题 + const title = + e.target.cfg.delegateObject.item?.name || + e.target.cfg.delegateObject.axis.cfg.title.originalText + + // 如果没有 tooltip,创建新的 tooltip DOM 元素 + if (!labelTooltipDom) { + const domStr = substitute(AXIS_LABEL_TOOLTIP_TPL, { title }) + labelTooltipDom = createDom(domStr) + + // 设置 tooltip 的样式 + AXIS_LABEL_TOOLTIP_STYLE.backgroundColor = tooltip.backgroundColor + AXIS_LABEL_TOOLTIP_STYLE.boxShadow = `${tooltip.backgroundColor} 0px 0px 5px` + AXIS_LABEL_TOOLTIP_STYLE.maxWidth = '200px' + _.assign(labelTooltipDom.style, AXIS_LABEL_TOOLTIP_STYLE) + + // 将 tooltip 添加到父节点 + parentNode.appendChild(labelTooltipDom) + } else { + // 如果已有 tooltip,更新其标题并使其可见 + labelTooltipDom.getElementsByClassName('g2-tooltip-title')[0].innerHTML = title + labelTooltipDom.style.visibility = 'visible' + } + + // 获取父节点的尺寸和 tooltip 的尺寸 + const { height, width } = parentNode.getBoundingClientRect() + const { offsetHeight, offsetWidth } = labelTooltipDom + + // 如果 tooltip 的尺寸超出了父节点的尺寸,则将其位置重置为 (0, 0) + if (offsetHeight > height || offsetWidth > width) { + labelTooltipDom.style.left = labelTooltipDom.style.top = '0px' + return + } + + // 计算 tooltip 的初始位置 + const initPosition = { left: x + 10, top: y + 15 } + + // 调整位置,避免 tooltip 超出边界 + if (initPosition.left + offsetWidth > width) initPosition.left = width - offsetWidth - 10 + if (initPosition.top + offsetHeight > height) initPosition.top -= offsetHeight + 15 + + // 设置 tooltip 的位置和样式 + labelTooltipDom.style.left = `${initPosition.left}px` + labelTooltipDom.style.top = `${initPosition.top}px` + labelTooltipDom.style.color = color + labelTooltipDom.style.fontSize = `${fontSize}px` + }) + + // 鼠标离开事件 + plot.on(triggerName + ':mouseleave', e => { + const field = e.target.cfg.delegateObject.component.cfg.field + const position = e.target.cfg.delegateObject.component.cfg.position + const isYaxis = position === 'left' || position === 'right' + + // 如果不是 'field' 或 'title',且不是Y轴,直接返回 + if (field !== 'field' && field !== 'title' && !isYaxis) return + + // 获取轴标签的实际内容 + const realContent = e.target.attrs.text + + // 如果标签长度小于限制或已经省略(以'...'结尾),则不显示 tooltip + if ( + isYaxisTitle ? false : realContent.length < lengthLimit || !(realContent.slice(-3) === '...') + ) + return + + // 获取父节点中的 tooltip + const parentNode = e.event.target.parentNode + const labelTooltipDom = parentNode.getElementsByClassName('g2-axis-label-tooltip')[0] + + // 如果 tooltip 存在,隐藏它 + if (labelTooltipDom) labelTooltipDom.style.visibility = 'hidden' + }) +} + +/** + * y轴标题截取 + * @param chart + * @param plot + */ +export function configYaxisTitleLengthLimit(chart, plot) { + // 监听图表渲染前事件 + plot.on('beforerender', ev => { + // 获取图表的Y轴自定义样式 + const { yAxis } = parseJson(chart.customStyle) + + // 计算最大可用空间高度,80% 为最大高度比 + const maxHeightRatio = + 0.8 * (ev.view.canvas.cfg.height - (ev.view.canvas.cfg.height < 120 ? 60 : 30)) + + // 计算Y轴标题的每行高度 + const titleHeight = measureText( + chart, + yAxis.name, + { fontSize: yAxis.fontSize, fontFamily: chart.fontFamily }, + 'height' + ) + + // 用于存储截取后的标题 + let wrappedTitle = '' + + // 循环截取标题内容,直到超过最大高度 + for ( + let charIndex = 0; + charIndex < yAxis.name.length && (charIndex + 1) * titleHeight <= maxHeightRatio; + charIndex++ + ) { + wrappedTitle += yAxis.name[charIndex] + } + + // 如果标题被截断,添加省略号 + if (yAxis.name.length > wrappedTitle.length) { + wrappedTitle = + wrappedTitle.length > 2 + ? wrappedTitle.slice(0, wrappedTitle.length - 2) + '...' + : wrappedTitle + '...' + } + + // 更新Y轴标题的原始文本和截断后的文本 + ev.view.options.axes.yAxisExt.title.originalText = yAxis.name + ev.view.options.axes.yAxisExt.title.text = wrappedTitle + }) +} + +/** + * 调整原始数据options.data + * 添加conditionColor字段,用于保存符合条件的颜色 + * conditionColor 为数组,多个指标多个颜色,按照指标的顺序 + * @param chart + * @param options + */ +export const addConditionsStyleColorToData = (chart: Chart, options) => { + const { threshold } = parseJson(chart.senior) + if (!threshold.enable) return options + options.data.forEach(item => { + item['conditionColor'] = [] + // 条形图的值字段是xField,柱形图的值字段是yField + const valueField = chart.type === 'bar-horizontal' ? options.xField : options.yField + // 对称条形图区分左右值,value、 valueExt,quotaList只有一个 + if (chart.type === 'bidirectional-bar') { + valueField.forEach(value => { + const quotaList = value === 'value' ? chart.yAxis : chart.yAxisExt + const conditionColor = getColorByConditions([quotaList[0]?.id], item[value], chart) + if (conditionColor) { + item[item[options.xField] + '-' + value] = conditionColor + } + }) + } else if (item.quotaList?.length) { + const quotaList = item.quotaList.map(q => q.id) ?? [] + quotaList.forEach((q, index) => { + // 定义后,在 handleConditionsStyle 函数中使用 + let currentValue = item[valueField] + if (chart.type === 'progress-bar') { + currentValue = item['originalValue'] + } + const cColor = getColorByConditions([q], currentValue, chart) + if (cColor) { + item.conditionColor.push(cColor) + } else { + item.conditionColor = undefined + } + }) + } + }) + return options +} + +/** + * 辅助函数:获取颜色, 根据条件以及值计算 + * @param quotaList 指标列表 + * @param values 值 + */ +const getColorByConditions = (quotaList: [], values: number | number[], chart) => { + const { threshold } = parseJson(chart.senior) + const { basicStyle } = parseJson(chart.customAttr) + const currentValue = Array.isArray(values) ? values[1] - values[0] : values + if (!currentValue) return undefined + // 同样的指标只取最后一个 + const conditionMap = new Map() + for (const condition of threshold.lineThreshold ?? []) { + conditionMap.set(condition.fieldId, condition) + } + for (const condition of conditionMap.values()) { + if (chart.type === 'progress-bar' && chart.yAxisExt?.[0]?.id !== quotaList[0]) continue + if (!quotaList.includes(condition.fieldId) && chart.type !== 'waterfall') continue + for (const tc of condition.conditions) { + if ( + (tc.term === 'between' && currentValue >= tc.min && currentValue <= tc.max) || + (tc.term === 'lt' && currentValue < tc.value) || + (tc.term === 'le' && currentValue <= tc.value) || + (tc.term === 'gt' && currentValue > tc.value) || + (tc.term === 'ge' && currentValue >= tc.value) + ) { + let tmpColor = hexToRgba(tc.color, basicStyle.alpha) + if (basicStyle.gradient) { + let vhAngle = ['bar-horizontal', 'progress-bar'].includes(chart.type) ? 0 : 270 + if (chart.type === 'bidirectional-bar') { + const yAxis = chart.yAxis.find(item => item.id === condition.fieldId) + vhAngle = getBidirectionalAngle(basicStyle, yAxis ? 0 : 1) + } + tmpColor = setGradientColor(tmpColor, true, vhAngle) + } + return tmpColor + } + } + } +} + +/** + * 处理柱条图的样式 + * 柱条的颜色 + * 提示marker的颜色 + * 注: 原始options中tooltip已经配置了customItems,这里将会忽略 + * @param chart + * @param options + */ +export function handleConditionsStyle(chart: Chart, options: O) { + const { threshold } = parseJson(chart.senior) + if (!threshold.enable) return options + const { basicStyle } = parseJson(chart.customAttr) + // 该字段出处 addConditionsStyleColorToData + const colorField = 'conditionColor' + // 配置条件样式的颜色字段 + const rawFields = options.rawFields || [] + rawFields.push(colorField) + // 辅助函数:配置柱条样式颜色,条形图为barStyle,柱形图为columnStyle + const columnStyle = data => { + return { + ...options.columnStyle, + ...options.barStyle, + ...(data[colorField]?.[0] ? { fill: data[colorField][0] } : {}) + } + } + let newColor = undefined + if (chart.type === 'bidirectional-bar') { + rawFields.push(options.xField) + newColor = getBidirectionalBarColor(chart, basicStyle, options) + } else if (chart.type === 'waterfall') { + newColor = getWaterfallColor(basicStyle, chart) + } + const tmpOption = { + ...options, + rawFields, + columnStyle: columnStyle, + barStyle: columnStyle, + tooltip: { + ...options.tooltip, + ...(options.tooltip['customItems'] + ? {} + : { + customItems: originalItems => { + originalItems.forEach(item => { + if (item.data?.[colorField]) { + item.color = item.data[colorField][0] + } + }) + return originalItems + } + }) + }, + ...(newColor ? { color: newColor } : {}) + } + return tmpOption +} + +/** + * 配置瀑布图的color + * 瀑布color,这个图表固定为基础样式中颜色的前三个颜色,第一个为增加,第二个为减少,第三个为总计 + * @param basicStyle + * @param chart + */ +const getWaterfallColor = (basicStyle, chart) => { + const waterfallBasicColors = getBasicColors(chart, basicStyle, 270) + return data => { + if (data['$$isTotal$$']) return waterfallBasicColors[2] + const values = data['$$yField$$'] + const newColor = getColorByConditions([], values, chart) + return newColor ?? (values[1] > values[0] ? waterfallBasicColors[0] : waterfallBasicColors[1]) + } +} + +/** + * 配置对称条形图的color + * @param basicStyle + * @param options + */ +const getBidirectionalBarColor = (chart, basicStyle, options) => { + const basicColors = getBasicColors(chart, basicStyle, 270) + return ref => { + const obj = options.data.find(item => item[ref[options.xField] + '-' + ref['series-field-key']]) + if (obj) { + return obj[ref[options.xField] + '-' + ref['series-field-key']] + } + return ref['series-field-key'] === 'value' ? basicColors[0] : basicColors[1] + } +} + +/** + * 获取基础颜色 + * @param chart + * @param basicStyle + * @param angle + */ +const getBasicColors = (chart, basicStyle, angle) => { + const baseColors = [] + basicStyle.colors?.forEach((color, index) => { + if (chart.type === 'bidirectional-bar') { + baseColors.push( + setGradientColor( + hexToRgba(color, basicStyle.alpha), + true, + getBidirectionalAngle(basicStyle, index) + ) + ) + } else { + baseColors.push(setGradientColor(hexToRgba(color, basicStyle.alpha), true, angle)) + } + }) + return basicStyle.gradient ? baseColors : basicStyle.colors +} + +/** + * 获取对称条形图颜色的渐变角度 + * @param basicStyle + * @param index + */ +const getBidirectionalAngle = (basicStyle, index) => { + let vhAngle = 180 - index * 180 + if (basicStyle.layout === 'vertical') { + vhAngle = index === 0 ? 280 : 90 + } + return vhAngle +} + +/** + * tooltip验证条件样式中的颜色,有就使用,否则使用原始颜色 + * @param item + */ +export const getTooltipItemConditionColor = item => { + let color = item.color + if (item.data?.['conditionColor']) { + color = item.data['conditionColor'][0] + } + return color +} + +/** + * 配置空数据样式 + * @param newChart + * @param newData + * @param container + */ +export const configEmptyDataStyle = (newChart, newData, container) => { + /** + * 辅助函数:移除空数据dom + */ + const removeEmptyDom = () => { + const emptyElement = document.getElementById(container + '_empty') + if (emptyElement) { + emptyElement.parentElement.removeChild(emptyElement) + } + } + removeEmptyDom() + if (newData.length > 0) return + if (!newData.length) { + const emptyDom = document.createElement('div') + emptyDom.id = container + '_empty' + emptyDom.textContent = tI18n('data_set.no_data') + emptyDom.setAttribute( + 'style', + `position: absolute; + left: 45%; + top: 50%;` + ) + const parent = document.getElementById(container) + parent.insertBefore(emptyDom, parent.firstChild) + newChart.destroy() + } +} diff --git a/frontend/src/data-visualization/chart/components/js/panel/common/common_table.ts b/frontend/src/data-visualization/chart/components/js/panel/common/common_table.ts new file mode 100644 index 0000000..16fb754 --- /dev/null +++ b/frontend/src/data-visualization/chart/components/js/panel/common/common_table.ts @@ -0,0 +1,2021 @@ +/* eslint-disable prettier/prettier */ +import { + copyString, + hexColorToRGBA, + isAlphaColor, + isTransparent, + parseJson, + resetRgbOpacity +} from '../../util' +import { + DEFAULT_BASIC_STYLE, + DEFAULT_TABLE_CELL, + DEFAULT_TABLE_HEADER +} from '@/data-visualization/chart/components/editor/util/chart' +import { + BaseTooltip, + DataCellBrushSelection, + FONT_FAMILY, + getAutoAdjustPosition, + getEmptyPlaceholder, + getPolygonPoints, + getTooltipDefaultOptions, + InteractionName, + InteractionStateName, + MergedCell, + MergedCellInfo, + type Meta, + type Node, + type PivotSheet, + renderPolygon, + renderText, + S2DataConfig, + S2Event, + S2Options, + S2Theme, + SERIES_NUMBER_FIELD, + setTooltipContainerStyle, + SHAPE_STYLE_MAP, + SpreadSheet, + Style, + TableColCell, + TableDataCell, + updateShapeAttr, + ViewMeta +} from '@antv/s2' +import { cloneDeep, filter, find, intersection, keys, merge, repeat } from 'lodash-es' +import { createVNode, render } from 'vue' +import TableTooltip from '@/data-visualization/chart/components/editor/common/TableTooltip.vue' +import Exceljs from 'exceljs' +import { saveAs } from 'file-saver' +import { ElMessage } from 'element-plus-secondary' +import { useI18n } from '@/data-visualization/hooks/web/useI18n' +const { t: i18nt } = useI18n() + +export function getCustomTheme(chart: Chart): S2Theme { + const headerColor = hexColorToRGBA( + DEFAULT_TABLE_HEADER.tableHeaderBgColor, + DEFAULT_BASIC_STYLE.alpha + ) + const headerAlign = DEFAULT_TABLE_HEADER.tableHeaderAlign + const itemColor = hexColorToRGBA(DEFAULT_TABLE_CELL.tableItemBgColor, DEFAULT_BASIC_STYLE.alpha) + const itemAlign = DEFAULT_TABLE_CELL.tableItemAlign + const borderColor = hexColorToRGBA( + DEFAULT_BASIC_STYLE.tableBorderColor, + DEFAULT_BASIC_STYLE.alpha + ) + const scrollBarColor = DEFAULT_BASIC_STYLE.tableScrollBarColor + const scrollBarHoverColor = resetRgbOpacity(scrollBarColor, 3) + const textFontFamily = + chart.fontFamily && chart.fontFamily !== 'inherit' ? chart.fontFamily : FONT_FAMILY + const theme: S2Theme = { + background: { + color: '#00000000' + }, + splitLine: { + horizontalBorderColor: borderColor, + horizontalBorderColorOpacity: 1, + horizontalBorderWidth: 1, + verticalBorderColor: borderColor, + verticalBorderColorOpacity: 1, + verticalBorderWidth: 1, + showShadow: false + }, + cornerCell: { + cell: { + backgroundColor: headerColor, + horizontalBorderColor: borderColor, + verticalBorderColor: borderColor + }, + text: { + fill: DEFAULT_TABLE_HEADER.tableHeaderFontColor, + fontSize: DEFAULT_TABLE_HEADER.tableTitleFontSize, + textAlign: headerAlign, + fontFamily: textFontFamily + }, + bolderText: { + fill: DEFAULT_TABLE_HEADER.tableHeaderFontColor, + fontSize: DEFAULT_TABLE_HEADER.tableTitleFontSize, + textAlign: headerAlign, + fontFamily: textFontFamily + }, + measureText: { + fill: DEFAULT_TABLE_HEADER.tableHeaderFontColor, + fontSize: DEFAULT_TABLE_HEADER.tableTitleFontSize, + textAlign: headerAlign, + fontFamily: textFontFamily + } + }, + rowCell: { + cell: { + backgroundColor: headerColor, + horizontalBorderColor: borderColor, + verticalBorderColor: borderColor + }, + text: { + fill: DEFAULT_TABLE_HEADER.tableHeaderFontColor, + fontSize: DEFAULT_TABLE_HEADER.tableTitleFontSize, + textAlign: headerAlign, + textBaseline: 'middle', + fontFamily: textFontFamily + }, + bolderText: { + fill: DEFAULT_TABLE_HEADER.tableHeaderFontColor, + fontSize: DEFAULT_TABLE_HEADER.tableTitleFontSize, + textAlign: headerAlign, + fontFamily: textFontFamily + }, + measureText: { + fill: DEFAULT_TABLE_HEADER.tableHeaderFontColor, + fontSize: DEFAULT_TABLE_HEADER.tableTitleFontSize, + textAlign: headerAlign, + fontFamily: textFontFamily + }, + seriesText: { + fill: DEFAULT_TABLE_CELL.tableItemBgColor, + fontSize: DEFAULT_TABLE_CELL.tableItemFontSize, + textAlign: itemAlign, + fontFamily: textFontFamily + } + }, + colCell: { + cell: { + backgroundColor: headerColor, + horizontalBorderColor: borderColor, + verticalBorderColor: borderColor + }, + text: { + fill: DEFAULT_TABLE_HEADER.tableHeaderFontColor, + fontSize: DEFAULT_TABLE_HEADER.tableTitleFontSize, + textAlign: headerAlign, + fontFamily: textFontFamily + }, + bolderText: { + fill: DEFAULT_TABLE_HEADER.tableHeaderFontColor, + fontSize: DEFAULT_TABLE_HEADER.tableTitleFontSize, + textAlign: headerAlign, + fontFamily: textFontFamily + }, + measureText: { + fill: DEFAULT_TABLE_HEADER.tableHeaderFontColor, + fontSize: DEFAULT_TABLE_HEADER.tableTitleFontSize, + textAlign: headerAlign, + fontFamily: textFontFamily + } + }, + dataCell: { + cell: { + backgroundColor: itemColor, + horizontalBorderColor: borderColor, + verticalBorderColor: borderColor + }, + text: { + fill: DEFAULT_TABLE_CELL.tableFontColor, + fontSize: DEFAULT_TABLE_CELL.tableItemFontSize, + textAlign: itemAlign, + fontFamily: textFontFamily + }, + bolderText: { + fill: DEFAULT_TABLE_CELL.tableFontColor, + fontSize: DEFAULT_TABLE_CELL.tableItemFontSize, + textAlign: itemAlign, + fontFamily: textFontFamily + }, + measureText: { + fill: DEFAULT_TABLE_CELL.tableFontColor, + fontSize: DEFAULT_TABLE_CELL.tableItemFontSize, + textAlign: headerAlign, + fontFamily: textFontFamily + } + }, + scrollBar: { + thumbColor: scrollBarColor, + thumbHoverColor: scrollBarHoverColor, + size: 8, + hoverSize: 12 + } + } + + let customAttr: DeepPartial + if (chart.customAttr) { + customAttr = parseJson(chart.customAttr) + const { basicStyle, tableHeader, tableCell } = customAttr + // basic + if (basicStyle) { + const tableBorderColor = basicStyle.tableBorderColor + const tableScrollBarColor = basicStyle.tableScrollBarColor + const tmpTheme: S2Theme = { + splitLine: { + horizontalBorderColor: tableBorderColor, + verticalBorderColor: tableBorderColor + }, + cornerCell: { + cell: { + horizontalBorderColor: tableBorderColor, + verticalBorderColor: tableBorderColor + } + }, + colCell: { + cell: { + horizontalBorderColor: tableBorderColor, + verticalBorderColor: tableBorderColor + } + }, + dataCell: { + cell: { + horizontalBorderColor: tableBorderColor, + verticalBorderColor: tableBorderColor, + interactionState: { + hoverFocus: { + borderOpacity: basicStyle.showHoverStyle === false ? 0 : 1 + } + } + } + }, + scrollBar: { + thumbColor: tableScrollBarColor, + thumbHoverColor: resetRgbOpacity(tableScrollBarColor, 1.5) + } + } + merge(theme, tmpTheme) + } + // header + if (tableHeader) { + const tableHeaderFontColor = hexColorToRGBA( + tableHeader.tableHeaderFontColor, + basicStyle.alpha + ) + let tableHeaderBgColor = tableHeader.tableHeaderBgColor + if (!isAlphaColor(tableHeaderBgColor)) { + tableHeaderBgColor = hexColorToRGBA(tableHeaderBgColor, basicStyle.alpha) + } + const fontStyle = tableHeader.isItalic ? 'italic' : 'normal' + const fontWeight = tableHeader.isBolder === false ? 'normal' : 'bold' + const { tableHeaderAlign, tableTitleFontSize } = tableHeader + const tmpTheme: S2Theme = { + cornerCell: { + cell: { + backgroundColor: tableHeaderBgColor + }, + bolderText: { + fill: tableHeaderFontColor, + fontSize: tableTitleFontSize, + textAlign: tableHeaderAlign, + fontStyle, + fontWeight, + fontFamily: textFontFamily + }, + text: { + fill: tableHeaderFontColor, + fontSize: tableTitleFontSize, + textAlign: tableHeaderAlign, + fontStyle, + fontWeight, + fontFamily: textFontFamily + }, + measureText: { + fill: tableHeaderFontColor, + fontSize: tableTitleFontSize, + textAlign: tableHeaderAlign, + fontStyle, + fontWeight, + fontFamily: textFontFamily + } + }, + colCell: { + cell: { + backgroundColor: tableHeaderBgColor + }, + bolderText: { + fill: tableHeaderFontColor, + fontSize: tableTitleFontSize, + textAlign: tableHeaderAlign, + fontStyle, + fontWeight, + fontFamily: textFontFamily + }, + text: { + fill: tableHeaderFontColor, + fontSize: tableTitleFontSize, + textAlign: tableHeaderAlign, + fontStyle, + fontWeight, + fontFamily: textFontFamily + }, + measureText: { + fill: tableHeaderFontColor, + fontSize: tableTitleFontSize, + textAlign: tableHeaderAlign, + fontStyle, + fontWeight, + fontFamily: textFontFamily + } + } + } + merge(theme, tmpTheme) + // 这边设置为 0 的话就会显示表头背景颜色,所以要判断一下表头是否关闭 + if (tableHeader.showHorizonBorder === false && tableHeader.showTableHeader !== false) { + const tmpTheme: S2Theme = { + splitLine: { + horizontalBorderColor: tableHeaderBgColor, + horizontalBorderWidth: 0, + horizontalBorderColorOpacity: 0 + }, + colCell: { + cell: { + horizontalBorderColor: tableHeaderBgColor, + horizontalBorderWidth: 0 + } + } + } + merge(theme, tmpTheme) + } + if (tableHeader.showVerticalBorder === false && tableHeader.showTableHeader !== false) { + const tmpTheme: S2Theme = { + splitLine: { + verticalBorderColor: tableHeaderBgColor, + verticalBorderWidth: 0, + verticalBorderColorOpacity: 0 + }, + colCell: { + cell: { + verticalBorderColor: tableHeaderBgColor, + verticalBorderWidth: 0 + } + }, + cornerCell: { + cell: { + verticalBorderColor: tableHeaderBgColor, + verticalBorderWidth: 0 + } + } + } + merge(theme, tmpTheme) + } + } + // cell + if (tableCell) { + const tableFontColor = hexColorToRGBA(tableCell.tableFontColor, basicStyle.alpha) + let tableItemBgColor = tableCell.tableItemBgColor + if (!isAlphaColor(tableItemBgColor)) { + tableItemBgColor = hexColorToRGBA(tableItemBgColor, basicStyle.alpha) + } + let tableItemSubBgColor = tableCell.tableItemSubBgColor + if (!isAlphaColor(tableItemSubBgColor)) { + tableItemSubBgColor = hexColorToRGBA(tableItemSubBgColor, basicStyle.alpha) + } + const fontStyle = tableCell.isItalic ? 'italic' : 'normal' + const fontWeight = tableCell.isBolder === false ? 'normal' : 'bold' + const { tableItemAlign, tableItemFontSize, enableTableCrossBG } = tableCell + const tmpTheme: S2Theme = { + rowCell: { + cell: { + backgroundColor: tableItemBgColor, + horizontalBorderColor: tableItemBgColor, + verticalBorderColor: tableItemBgColor + }, + bolderText: { + fill: tableFontColor, + textAlign: tableItemAlign, + fontSize: tableItemFontSize, + fontFamily: textFontFamily + }, + text: { + fill: tableFontColor, + textAlign: tableItemAlign, + fontSize: tableItemFontSize, + fontFamily: textFontFamily + }, + measureText: { + fill: tableFontColor, + textAlign: tableItemAlign, + fontSize: tableItemFontSize, + fontFamily: textFontFamily + }, + seriesText: { + fill: tableFontColor, + textAlign: tableItemAlign, + fontSize: tableItemFontSize, + fontFamily: textFontFamily + } + }, + dataCell: { + cell: { + crossBackgroundColor: + enableTableCrossBG && !tableCell.mergeCells ? tableItemSubBgColor : tableItemBgColor, + backgroundColor: tableItemBgColor + }, + bolderText: { + fill: tableFontColor, + textAlign: tableItemAlign, + fontSize: tableItemFontSize, + fontStyle, + fontWeight, + fontFamily: textFontFamily + }, + text: { + fill: tableFontColor, + textAlign: tableItemAlign, + fontSize: tableItemFontSize, + fontStyle, + fontWeight, + fontFamily: textFontFamily + }, + measureText: { + fill: tableFontColor, + textAlign: tableItemAlign, + fontSize: tableItemFontSize, + fontStyle, + fontWeight, + fontFamily: textFontFamily + }, + seriesText: { + fill: tableFontColor, + textAlign: tableItemAlign, + fontSize: tableItemFontSize, + fontStyle, + fontWeight, + fontFamily: textFontFamily + } + } + } + merge(theme, tmpTheme) + if (tableCell.showHorizonBorder === false) { + const tmpTheme: S2Theme = { + dataCell: { + cell: { + horizontalBorderColor: tableItemBgColor, + horizontalBorderWidth: 0 + } + } + } + merge(theme, tmpTheme) + } + if (tableCell.showVerticalBorder === false) { + const tmpTheme: S2Theme = { + splitLine: { + verticalBorderWidth: 0, + verticalBorderColorOpacity: 0 + }, + dataCell: { + cell: { + verticalBorderColor: tableItemBgColor, + verticalBorderWidth: 0 + } + } + } + merge(theme, tmpTheme) + } + } + } + + return theme +} + +export function getStyle(chart: Chart, dataConfig: S2DataConfig): Style { + const style: Style = {} + let customAttr: DeepPartial + if (chart.customAttr) { + customAttr = parseJson(chart.customAttr) + const { basicStyle, tableHeader, tableCell } = customAttr + style.colCfg = { + height: tableHeader.tableTitleHeight + } + style.cellCfg = { + height: tableCell.tableItemHeight + } + switch (basicStyle.tableColumnMode) { + case 'adapt': { + style.layoutWidthType = 'compact' + break + } + case 'field': { + delete style.layoutWidthType + const fieldMap = + basicStyle.tableFieldWidth?.reduce((p, n) => { + p[n.fieldId] = n + return p + }, {}) || {} + // 下钻字段使用入口字段的宽度 + if (chart.drill) { + const { xAxis } = parseJson(chart) + const curDrillField = chart.drillFields[chart.drillFilters.length] + const drillEnterFieldIndex = xAxis.findIndex( + item => item.id === chart.drillFilters[0].fieldId + ) + const drillEnterField = xAxis[drillEnterFieldIndex] + fieldMap[curDrillField.dataeaseName] = { + width: fieldMap[drillEnterField.dataeaseName]?.width + } + } + // 铺满 + const totalWidthPercent = dataConfig.meta?.reduce((p, n) => { + return p + (fieldMap[n.field]?.width ?? 10) + }, 0) + const fullFilled = parseInt(totalWidthPercent.toFixed(0)) === 100 + const widthArr = [] + style.colCfg.width = node => { + const width = node.spreadsheet.container.cfg.el.getBoundingClientRect().width + if (!basicStyle.tableFieldWidth?.length) { + const fieldsSize = chart.data.fields.length + const columnCount = tableHeader.showIndex ? fieldsSize + 1 : fieldsSize + return width / columnCount + } + const baseWidth = width / 100 + const tmpWidth = fieldMap[node.field] + ? fieldMap[node.field].width * baseWidth + : baseWidth * 10 + const resultWidth = parseInt(tmpWidth.toFixed(0)) + if (fullFilled) { + if (widthArr.length === dataConfig.meta.length - 1) { + const curTotalWidth = widthArr.reduce((p, n) => { + return p + n + }, 0) + const restWidth = width - curTotalWidth + widthArr.splice(0) + if (restWidth < resultWidth) { + return restWidth + } + } else { + widthArr.push(resultWidth) + } + } + return resultWidth + } + break + } + case 'custom': { + style.colCfg.width = basicStyle.tableColumnWidth + break + } + // 查看详情用,均分铺满 + default: { + delete style.layoutWidthType + style.colCfg.width = node => { + const width = node.spreadsheet.container.cfg.el.offsetWidth + const fieldsSize = node.spreadsheet.dataCfg.meta.length + if (!fieldsSize) { + return 0 + } + const columnCount = tableHeader.showIndex ? fieldsSize + 1 : fieldsSize + const minWidth = width / columnCount + return Math.max(minWidth, basicStyle.tableColumnWidth) + } + } + } + } + + return style +} + +export function getCurrentField(valueFieldList: Axis[], field: ChartViewField) { + let list = [] + let res = null + try { + list = parseJson(valueFieldList) + } catch (err) { + list = JSON.parse(JSON.stringify(valueFieldList)) + } + if (list) { + for (let i = 0; i < list.length; i++) { + const f = list[i] + if (field.dataeaseName === f.dataeaseName) { + res = f + break + } + } + } + + return res +} + +export function getConditions(chart: Chart) { + const { threshold } = parseJson(chart.senior) + if (!threshold.enable) { + return + } + const res = { + text: [], + background: [] + } + const conditions = threshold.tableThreshold ?? [] + + const dimFields = [...chart.xAxis, ...chart.xAxisExt].map(i => i.dataeaseName) + if (conditions?.length > 0) { + const { tableCell, basicStyle, tableHeader } = parseJson(chart.customAttr) + // 合并单元格时,班马纹失效 + const enableTableCrossBG = + chart.type === 'table-info' + ? tableCell.enableTableCrossBG && !tableCell.mergeCells + : tableCell.enableTableCrossBG + const valueColor = isAlphaColor(tableCell.tableFontColor) + ? tableCell.tableFontColor + : hexColorToRGBA(tableCell.tableFontColor, basicStyle.alpha) + const valueBgColor = enableTableCrossBG + ? null + : isAlphaColor(tableCell.tableItemBgColor) + ? tableCell.tableItemBgColor + : hexColorToRGBA(tableCell.tableItemBgColor, basicStyle.alpha) + const headerValueColor = tableHeader.tableHeaderFontColor + const headerValueBgColor = isAlphaColor(tableHeader.tableHeaderBgColor) + ? tableHeader.tableHeaderBgColor + : hexColorToRGBA(tableHeader.tableHeaderBgColor, basicStyle.alpha) + const filedValueMap = getFieldValueMap(chart) + for (let i = 0; i < conditions.length; i++) { + const field = conditions[i] + let defaultValueColor = valueColor + let defaultBgColor = valueBgColor + // 透视表表头颜色配置 + if (chart.type === 'table-pivot' && dimFields.includes(field.field.dataeaseName)) { + defaultValueColor = headerValueColor + defaultBgColor = headerValueBgColor + } + res.text.push({ + field: field.field.dataeaseName, + mapping(value, rowData) { + // 总计小计 + if (rowData?.isTotals) { + return null + } + // 表头 + if (rowData?.id && rowData?.field === rowData.id) { + return null + } + return { + fill: mappingColor(value, defaultValueColor, field, 'color', filedValueMap, rowData) + } + } + }) + res.background.push({ + field: field.field.dataeaseName, + mapping(value, rowData) { + if (rowData?.isTotals) { + return null + } + if (rowData?.id && rowData?.field === rowData.id) { + return null + } + const fill = mappingColor( + value, + defaultBgColor, + field, + 'backgroundColor', + filedValueMap, + rowData + ) + if (isTransparent(fill)) { + return null + } + return { fill } + } + }) + } + } + return res +} + +export function mappingColor(value, defaultColor, field, type, filedValueMap?, rowData?) { + let color = null + for (let i = 0; i < field.conditions.length; i++) { + let flag = false + const t = field.conditions[i] + let tv, max, min + if (t.type === 'dynamic') { + if (t.term === 'between') { + max = parseFloat(getValue(t.dynamicMaxField, filedValueMap, rowData)) + min = parseFloat(getValue(t.dynamicMinField, filedValueMap, rowData)) + } else { + tv = getValue(t.dynamicField, filedValueMap, rowData) + } + } else { + if (t.term === 'between') { + min = parseFloat(t.min) + max = parseFloat(t.max) + } else { + tv = t.value + } + } + if (field.field.deType === 2 || field.field.deType === 3 || field.field.deType === 4) { + tv = parseFloat(tv) + if (t.term === 'eq') { + if (value === tv) { + color = t[type] + flag = true + } + } else if (t.term === 'not_eq') { + if (value !== tv) { + color = t[type] + flag = true + } + } else if (t.term === 'lt') { + if (value < tv) { + color = t[type] + flag = true + } + } else if (t.term === 'gt') { + if (value > tv) { + color = t[type] + flag = true + } + } else if (t.term === 'le') { + if (value <= tv) { + color = t[type] + flag = true + } + } else if (t.term === 'ge') { + if (value >= tv) { + color = t[type] + flag = true + } + } else if (t.term === 'between') { + if (min <= value && value <= max) { + color = t[type] + flag = true + } + } else if (t.term === 'default') { + color = t[type] + flag = true + } + if (flag) { + break + } else if (i === field.conditions.length - 1) { + color = defaultColor + } + } else if (field.field.deType === 0 || field.field.deType === 5) { + if (t.term === 'eq') { + if (value === tv) { + color = t[type] + flag = true + } + } else if (t.term === 'not_eq') { + if (value !== tv) { + color = t[type] + flag = true + } + } else if (t.term === 'like') { + if (value.includes(tv)) { + color = t[type] + flag = true + } + } else if (t.term === 'not like') { + if (!value.includes(tv)) { + color = t[type] + flag = true + } + } else if (t.term === 'null') { + if (value === null || value === undefined || value === '') { + color = t[type] + flag = true + } + } else if (t.term === 'not_null') { + if (value !== null && value !== undefined && value !== '') { + color = t[type] + flag = true + } + } else if (t.term === 'default') { + color = t[type] + flag = true + } + if (flag) { + break + } else if (i === field.conditions.length - 1) { + color = defaultColor + } + } else { + // time + const fc = field.conditions[i] + tv = new Date(tv.replace(/-/g, '/') + ' GMT+8').getTime() + const v = new Date(value.replace(/-/g, '/') + ' GMT+8').getTime() + if (fc.term === 'eq') { + if (v === tv) { + color = fc[type] + flag = true + } + } else if (fc.term === 'not_eq') { + if (v !== tv) { + color = fc[type] + flag = true + } + } else if (fc.term === 'lt') { + if (v < tv) { + color = fc[type] + flag = true + } + } else if (fc.term === 'gt') { + if (v > tv) { + color = fc[type] + flag = true + } + } else if (fc.term === 'le') { + if (v <= tv) { + color = fc[type] + flag = true + } + } else if (fc.term === 'ge') { + if (v >= tv) { + color = fc[type] + flag = true + } + } else if (fc.term === 'default') { + color = fc[type] + flag = true + } + if (flag) { + break + } else if (i === field.conditions.length - 1) { + color = defaultColor + } + } + } + return color +} + +function getFieldValueMap(view) { + const fieldValueMap = {} + if (view.data && view.data.dynamicAssistLines && view.data.dynamicAssistLines.length > 0) { + view.data.dynamicAssistLines.forEach(ele => { + fieldValueMap[ele.summary + '-' + ele.fieldId] = ele.value + }) + } + return fieldValueMap +} + +function getValue(field, filedValueMap, rowData) { + if (field.summary === 'value') { + return rowData ? rowData[field.field?.dataeaseName] : undefined + } else { + return filedValueMap[field.summary + '-' + field.fieldId] + } +} + +export function handleTableEmptyStrategy(chart: Chart) { + let newData = (chart.data?.tableRow || []) as Record[] + let intersectionArr = [] + const senior = parseJson(chart.senior) + let emptyDataStrategy = senior?.functionCfg?.emptyDataStrategy + if (!emptyDataStrategy) { + emptyDataStrategy = 'breakLine' + } + const emptyDataFieldCtrl = senior?.functionCfg?.emptyDataFieldCtrl + if (emptyDataStrategy !== 'breakLine' && emptyDataFieldCtrl?.length && newData?.length) { + const deNames = keys(newData[0]) + intersectionArr = intersection(deNames, emptyDataFieldCtrl) + } + if (intersectionArr.length) { + newData = cloneDeep(newData) + for (let i = newData.length - 1; i >= 0; i--) { + for (let j = 0, tmp = intersectionArr.length; j < tmp; j++) { + const deName = intersectionArr[j] + if (newData[i][deName] === null) { + if (emptyDataStrategy === 'setZero') { + newData[i][deName] = 0 + } + if (emptyDataStrategy === 'ignoreData') { + newData = filter(newData, (_, index) => index !== i) + break + } + } + } + } + } + return newData +} +export class SortTooltip extends BaseTooltip { + show(showOptions) { + const { iconName } = showOptions + if (iconName) { + this.showSortTooltip(showOptions) + return + } + super.show(showOptions) + } + + showSortTooltip(showOptions) { + const { position, options, meta, event } = showOptions + const { enterable } = getTooltipDefaultOptions(options) + const { autoAdjustBoundary, adjustPosition } = this.spreadsheet.options.tooltip || {} + this.visible = true + this.options = showOptions + const container = this['getContainer']() + // 用 vue 手动 patch + const vNode = createVNode(TableTooltip, { + table: this.spreadsheet, + meta + }) + this.spreadsheet.tooltip.container.innerHTML = '' + const childElement = document.createElement('div') + this.spreadsheet.tooltip.container.appendChild(childElement) + render(vNode, childElement) + + const { x, y } = getAutoAdjustPosition({ + spreadsheet: this.spreadsheet, + position, + tooltipContainer: container, + autoAdjustBoundary + }) + + this.position = adjustPosition?.({ position: { x, y }, event }) ?? { + x, + y + } + + setTooltipContainerStyle(container, { + style: { + left: `${this.position?.x}px`, + top: `${this.position?.y}px`, + pointerEvents: enterable ? 'all' : 'none', + zIndex: 9999, + position: 'absolute', + color: 'black', + background: 'white', + fontSize: '16px' + }, + visible: true + }) + } +} +const SORT_DEFAULT = + '' +const SORT_UP = + '' +const SORT_DOWN = + '' + +function svg2Base64(svg) { + return `data:image/svg+xml;charset=utf-8;base64,${btoa(svg)}` +} + +export function configHeaderInteraction(chart: Chart, option: S2Options) { + const { tableHeaderFontColor, tableHeaderSort } = parseJson(chart.customAttr).tableHeader + if (!tableHeaderSort) { + return + } + const iconColor = tableHeaderFontColor ?? '#666' + const sortDefault = svg2Base64(SORT_DEFAULT.replace('{fill}', iconColor)) + const sortUp = svg2Base64(SORT_UP.replace('{fill}', iconColor)) + const sortDown = svg2Base64(SORT_DOWN.replace('{fill}', iconColor)) + // 防止缓存 + const randomSuffix = Math.random() + const sortIconMap = { + asc: `customSortUp${randomSuffix}`, + desc: `customSortDown${randomSuffix}` + } + option.customSVGIcons = [ + { + name: `customSortDefault${randomSuffix}`, + svg: sortDefault + }, + { + name: `customSortUp${randomSuffix}`, + svg: sortUp + }, + { + name: `customSortDown${randomSuffix}`, + svg: sortDown + } + ] + option.headerActionIcons = [ + { + iconNames: [ + `customSortDefault${randomSuffix}`, + `customSortUp${randomSuffix}`, + `customSortDown${randomSuffix}` + ], + belongsCell: 'colCell', + displayCondition: (meta, iconName) => { + if (meta.field === SERIES_NUMBER_FIELD) { + return false + } + // 分组 + if (meta.colIndex === -1) { + return false + } + const sortMethodMap = meta.spreadsheet.store.get('sortMethodMap') + const sortType = sortMethodMap?.[meta.field] + if (sortType) { + return iconName === sortIconMap[sortType] + } + return iconName === `customSortDefault${randomSuffix}` + }, + onClick: props => { + const { meta, event } = props + meta.spreadsheet.showTooltip({ + position: { + x: event.clientX, + y: event.clientY + }, + event, + ...props + }) + const parent = document.getElementById(chart.container) + if (parent?.childNodes?.length) { + const child = Array.from(parent.childNodes) + .filter(node => node.nodeType === Node.ELEMENT_NODE) + .find(node => node.classList.contains('antv-s2-tooltip-container')) + if (child) { + const left = child.offsetLeft + child.clientWidth + if (left > parent.offsetWidth) { + const newLeft = parent.offsetWidth - child.clientWidth - 10 + child.style.left = `${newLeft}px` + } + } + } + } + } + ] +} + +export function configTooltip(chart: Chart, option: S2Options) { + const { tooltip } = parseJson(chart.customAttr) + const textFontFamily = chart.fontFamily ? chart.fontFamily : FONT_FAMILY + option.tooltip = { + ...option.tooltip, + style: { + background: tooltip.backgroundColor, + fontSize: tooltip.fontSize + 'px', + fontFamily: textFontFamily, + color: tooltip.color, + boxShadow: 'rgba(0, 0, 0, 0.1) 0px 4px 8px 0px', + borderRadius: '3px', + padding: '4px 12px', + opacity: 0.95, + position: 'absolute' + }, + adjustPosition: ({ event }) => { + return getTooltipPosition(event) + } + } +} + +export function copyContent(s2Instance: SpreadSheet, event, fieldMeta) { + event.preventDefault() + const cell = s2Instance.getCell(event.target) + const valueField = cell.getMeta().valueField + const cellMeta = cell.getMeta() + const selectState = s2Instance.interaction.getState() + let content = '' + // 多选 + if (selectState.stateName === InteractionStateName.SELECTED) { + const { cells } = selectState + if (!cells?.length) { + return + } + if (cells.length === 1) { + const curCell = cells[0] + if (cell.getMeta().id === curCell.id) { + copyString(cellMeta.value + '', true) + } + s2Instance.interaction.clearState() + return + } + const brushSelection = s2Instance.interaction.interactions.get( + InteractionName.BRUSH_SELECTION + ) as DataCellBrushSelection + const selectedCells: TableDataCell[] = brushSelection.getScrollBrushRangeCells(cells) + selectedCells.sort((a, b) => { + const aMeta = a.getMeta() + const bMeta = b.getMeta() + if (aMeta.rowIndex !== bMeta.rowIndex) { + return aMeta.rowIndex - bMeta.rowIndex + } + return aMeta.colIndex - bMeta.colIndex + }) + // 点击已选的就复制,未选的就忽略 + let validClick = false + const matrix = selectedCells.reduce((p, n) => { + if ( + n.getMeta().colIndex === cellMeta.colIndex && + n.getMeta().rowIndex === cellMeta.rowIndex + ) { + validClick = true + } + const arr = p[n.getMeta().rowIndex] + if (!arr) { + p[n.getMeta().rowIndex] = [n] + } else { + arr.push(n) + } + return p + }, {}) as Record + if (validClick) { + keys(matrix).forEach(k => { + const arr = matrix[k] as TableDataCell[] + arr.forEach((cell, index) => { + const cellMeta = cell.getMeta() + const value = cellMeta.data?.[cellMeta.valueField] + const metaObj = find(fieldMeta, m => m.field === cellMeta.valueField) + let fieldVal = value?.toString() + if (metaObj) { + fieldVal = metaObj.formatter(value) + } + if (fieldVal === undefined || fieldVal === null) { + fieldVal = '' + } + if (index !== arr.length - 1) { + fieldVal += '\t' + } + content += fieldVal + }) + content = content + '\n' + }) + if (content) { + copyString(content, true) + } + } + s2Instance.interaction.clearState() + return + } + // 单元格 + if (cellMeta?.data) { + const value = cellMeta.data[valueField] + const metaObj = find(fieldMeta, m => m.field === valueField) + content = value?.toString() + if (metaObj) { + content = metaObj.formatter(value) + } + } else { + // 列头&行头 + const fieldMap = fieldMeta?.reduce((p, n) => { + p[n.field] = n.name + return p + }, {}) + content = cellMeta.value + if (fieldMap?.[content]) { + content = fieldMap[content] + } + } + if (content) { + copyString(content, true) + } +} + +function getTooltipPosition(event) { + const s2Instance = event.s2Instance + const { x, y } = event + const result = { x: x + 15, y } + if (!s2Instance) { + return result + } + const { height, width } = s2Instance.getCanvasElement().getBoundingClientRect() + const { offsetHeight, offsetWidth } = s2Instance.tooltip.getContainer() + if (offsetWidth > width) { + result.x = 0 + } + if (offsetHeight > height) { + result.y = 0 + } + if (!(result.x || result.y)) { + return result + } + if (result.x && result.x + offsetWidth > width) { + result.x -= result.x + offsetWidth - width + } + if (result.y) { + if (result.y > offsetHeight) { + if (result.y - offsetHeight >= 15) { + result.y -= offsetHeight + 15 + } else { + result.y = 0 + } + } else { + result.y += 15 + } + } + return result +} + +export async function exportGridPivot(instance: PivotSheet, chart: ChartObj) { + const { layoutResult } = instance.facet + const { meta, fields } = instance.dataCfg + const rowLength = fields?.rows?.length || 0 + const colLength = fields?.columns?.length || 0 + const colNums = layoutResult.colLeafNodes.length + rowLength + 1 + if (colNums > 16384) { + ElMessage.warning(i18nt('chart.pivot_export_invalid_col_exceed')) + return + } + const workbook = new Exceljs.Workbook() + const worksheet = workbook.addWorksheet(i18nt('chart.chart_data')) + const metaMap: Record = meta?.reduce((p, n) => { + if (n.field) { + p[n.field] = n + } + return p + }, {}) + // 角头 + fields.columns?.forEach((column, index) => { + const cell = worksheet.getCell(index + 1, 1) + cell.value = metaMap[column]?.name ?? column + cell.alignment = { vertical: 'middle', horizontal: 'center' } + if (rowLength >= 2) { + worksheet.mergeCells(index + 1, 1, index + 1, rowLength) + } + cell.border = { + right: { style: 'thick', color: { argb: '00000000' } } + } + }) + fields?.rows?.forEach((row, index) => { + const cell = worksheet.getCell(colLength + 1, index + 1) + cell.value = metaMap[row]?.name ?? row + cell.alignment = { vertical: 'middle', horizontal: 'center' } + cell.border = { + bottom: { style: 'thick', color: { argb: '00000000' } } + } + if (index === fields.rows.length - 1) { + cell.border.right = { style: 'thick', color: { argb: '00000000' } } + } + }) + // 行头 + const { rowLeafNodes, rowsHierarchy, rowNodes } = layoutResult + const maxColIndex = rowsHierarchy.maxLevel + 1 + const notLeafNodeHeightMap: Record = {} + rowLeafNodes.forEach(node => { + // 行头的高度由子节点相加决定,也就是行头子节点中包含的叶子节点数量 + let curNode = node.parent + while (curNode) { + const height = notLeafNodeHeightMap[curNode.id] ?? 0 + notLeafNodeHeightMap[curNode.id] = height + 1 + curNode = curNode.parent + } + const { rowIndex } = node + const writeRowIndex = rowIndex + 1 + colLength + 1 + const writeColIndex = node.level + 1 + const cell = worksheet.getCell(writeRowIndex, writeColIndex) + cell.value = node.label + cell.alignment = { vertical: 'middle', horizontal: 'center' } + if (writeColIndex < maxColIndex) { + worksheet.mergeCells(writeRowIndex, writeColIndex, writeRowIndex, maxColIndex) + } + cell.border = { + right: { style: 'thick', color: { argb: '00000000' } } + } + }) + + const getNodeStartRowIndex = (node: Node) => { + if (!node.children?.length) { + return node.rowIndex + 1 + } else { + return getNodeStartRowIndex(node.children[0]) + } + } + rowNodes?.forEach(node => { + if (node.isLeaf) { + return + } + const rowIndex = getNodeStartRowIndex(node) + const height = notLeafNodeHeightMap[node.id] + const writeRowIndex = rowIndex + colLength + 1 + const mergeColCount = node.children[0].level - node.level + const value = node.label + const cell = worksheet.getCell(writeRowIndex, node.level + 1) + cell.value = value + cell.alignment = { vertical: 'middle', horizontal: 'center' } + if (mergeColCount > 1 || height > 1) { + worksheet.mergeCells( + writeRowIndex, + node.level + 1, + writeRowIndex + height - 1, + node.level + mergeColCount + ) + } + }) + + // 列头 + const { colLeafNodes, colNodes, colsHierarchy } = layoutResult + const maxColHeight = colsHierarchy.maxLevel + 1 + const notLeafNodeWidthMap: Record = {} + colLeafNodes.forEach(node => { + // 列头的宽度由子节点相加决定,也就是列头子节点中包含的叶子节点数量 + let curNode = node.parent + while (curNode) { + const width = notLeafNodeWidthMap[curNode.id] ?? 0 + notLeafNodeWidthMap[curNode.id] = width + 1 + curNode = curNode.parent + } + const { colIndex } = node + const writeRowIndex = node.level + 1 + const writeColIndex = colIndex + 1 + rowLength + const cell = worksheet.getCell(writeRowIndex, writeColIndex) + let value = node.label + if (node.field === '$$extra$$' && metaMap[value]?.name) { + value = metaMap[value].name + } + cell.value = value + cell.alignment = { vertical: 'middle', horizontal: 'center' } + if (writeRowIndex < maxColHeight) { + worksheet.mergeCells(writeRowIndex, writeColIndex, maxColHeight, writeColIndex) + } + cell.border = { + bottom: { style: 'thick', color: { argb: '00000000' } } + } + }) + const getNodeStartColIndex = (node: Node) => { + if (!node.children?.length) { + return node.colIndex + 1 + } else { + return getNodeStartColIndex(node.children[0]) + } + } + colNodes.forEach(node => { + if (node.isLeaf) { + return + } + const colIndex = getNodeStartColIndex(node) + const width = notLeafNodeWidthMap[node.id] + const writeRowIndex = node.level + 1 + const mergeRowCount = node.children[0].level - node.level + const value = node.label + const writeColIndex = colIndex + rowLength + const cell = worksheet.getCell(writeRowIndex, writeColIndex) + cell.value = value + cell.alignment = { vertical: 'middle', horizontal: 'center' } + if (mergeRowCount > 1 || width > 1) { + worksheet.mergeCells( + writeRowIndex, + writeColIndex, + writeRowIndex + mergeRowCount - 1, + writeColIndex + width - 1 + ) + } + }) + // 单元格数据 + for (let rowIndex = 0; rowIndex < rowLeafNodes.length; rowIndex++) { + for (let colIndex = 0; colIndex < colLeafNodes.length; colIndex++) { + const dataCellMeta = layoutResult.getCellMeta(rowIndex, colIndex) + const { fieldValue } = dataCellMeta + if (fieldValue === 0 || fieldValue) { + const meta = metaMap[dataCellMeta.valueField] + const cell = worksheet.getCell(rowIndex + maxColHeight + 1, rowLength + colIndex + 1) + const value = meta?.formatter?.(fieldValue) || fieldValue.toString() + cell.alignment = { vertical: 'middle', horizontal: 'center' } + cell.value = value + } + } + } + const buffer = await workbook.xlsx.writeBuffer() + const dataBlob = new Blob([buffer], { + type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=UTF-8' + }) + saveAs(dataBlob, `${chart.title ?? '透视表'}.xlsx`) +} + +export async function exportTreePivot(instance: PivotSheet, chart: ChartObj) { + const layoutResult = instance.facet.layoutResult + if (layoutResult.colLeafNodes.length + 2 > 16384) { + ElMessage.warning(i18nt('chart.pivot_export_invalid_col_exceed')) + return + } + const { meta, fields } = instance.dataCfg + const colLength = fields?.columns?.length || 0 + const workbook = new Exceljs.Workbook() + const worksheet = workbook.addWorksheet(i18nt('chart.chart_data')) + const metaMap: Record = meta?.reduce((p, n) => { + if (n.field) { + p[n.field] = n + } + return p + }, {}) + + // 角头 + fields.columns?.forEach((column, index) => { + const cell = worksheet.getCell(index + 1, 1) + cell.value = metaMap[column]?.name ?? column + cell.alignment = { vertical: 'middle', horizontal: 'center' } + cell.border = { + right: { style: 'thick', color: { argb: '00000000' } } + } + }) + const maxColHeight = layoutResult.colsHierarchy.maxLevel + 1 + const rowName = fields?.rows?.map(row => metaMap[row]?.name ?? row).join('/') + const cell = worksheet.getCell(colLength + 1, 1) + cell.value = rowName + cell.alignment = { vertical: 'middle', horizontal: 'center' } + cell.border = { + right: { style: 'thick', color: { argb: '00000000' } }, + bottom: { style: 'thick', color: { argb: '00000000' } } + } + //行头 + const { rowLeafNodes } = layoutResult + rowLeafNodes.forEach((node, index) => { + const cell = worksheet.getCell(maxColHeight + index + 1, 1) + cell.value = repeat(' ', node.level) + node.label + cell.alignment = { vertical: 'middle', horizontal: 'left' } + cell.border = { + right: { style: 'thick', color: { argb: '00000000' } } + } + }) + // 列头 + const notLeafNodeWidthMap: Record = {} + const { colLeafNodes } = layoutResult + colLeafNodes.forEach(node => { + let curNode = node.parent + while (curNode) { + const width = notLeafNodeWidthMap[curNode.id] ?? 0 + notLeafNodeWidthMap[curNode.id] = width + 1 + curNode = curNode.parent + } + const { colIndex } = node + const writeRowIndex = node.level + 1 + const writeColIndex = colIndex + 1 + 1 + const cell = worksheet.getCell(writeRowIndex, writeColIndex) + let value = node.label + if (node.field === '$$extra$$' && metaMap[value]?.name) { + value = metaMap[value].name + } + cell.value = value + cell.alignment = { vertical: 'middle', horizontal: 'center' } + if (writeRowIndex < maxColHeight) { + worksheet.mergeCells(writeRowIndex, writeColIndex, maxColHeight, writeColIndex) + } + cell.border = { + bottom: { style: 'thick', color: { argb: '00000000' } } + } + }) + const colNodes = layoutResult.colNodes + const getNodeStartIndex = (node: Node) => { + if (!node.children?.length) { + return node.colIndex + 1 + } else { + return getNodeStartIndex(node.children[0]) + } + } + colNodes.forEach(node => { + if (node.isLeaf) { + return + } + const colIndex = getNodeStartIndex(node) + const width = notLeafNodeWidthMap[node.id] + const writeRowIndex = node.level + 1 + const mergeRowCount = node.children[0].level - node.level + const writeColIndex = colIndex + 1 + const cell = worksheet.getCell(writeRowIndex, writeColIndex) + cell.value = node.label + cell.alignment = { vertical: 'middle', horizontal: 'center' } + if (mergeRowCount > 1 || width > 1) { + worksheet.mergeCells( + writeRowIndex, + writeColIndex, + writeRowIndex + mergeRowCount - 1, + writeColIndex + width - 1 + ) + } + }) + // 单元格数据 + for (let rowIndex = 0; rowIndex < rowLeafNodes.length; rowIndex++) { + for (let colIndex = 0; colIndex < colLeafNodes.length; colIndex++) { + const dataCellMeta = layoutResult.getCellMeta(rowIndex, colIndex) + const { fieldValue } = dataCellMeta + if (fieldValue === 0 || fieldValue) { + const meta = metaMap[dataCellMeta.valueField] + const cell = worksheet.getCell(rowIndex + maxColHeight + 1, colIndex + 1 + 1) + const value = meta?.formatter?.(fieldValue) || fieldValue.toString() + cell.alignment = { vertical: 'middle', horizontal: 'center' } + cell.value = value + } + } + } + const buffer = await workbook.xlsx.writeBuffer() + const dataBlob = new Blob([buffer], { + type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=UTF-8' + }) + saveAs(dataBlob, `${chart.title ?? '透视表'}.xlsx`) +} +export async function exportPivotExcel(instance: PivotSheet, chart: ChartObj) { + const { fields } = instance.dataCfg + const rowLength = fields?.rows?.length || 0 + const valueLength = fields?.values?.length || 0 + if (!(rowLength && valueLength)) { + ElMessage.warning(i18nt('chart.pivot_export_invalid_field')) + return + } + if (chart.customAttr.basicStyle.tableLayoutMode !== 'tree') { + exportGridPivot(instance, chart) + } else { + exportTreePivot(instance, chart) + } +} + +export function configMergeCells(chart: Chart, options: S2Options, dataConfig: S2DataConfig) { + const { mergeCells } = parseJson(chart.customAttr).tableCell + const { showIndex } = parseJson(chart.customAttr).tableHeader + if (mergeCells) { + options.frozenColCount = 0 + options.frozenRowCount = 0 + const fields = chart.data.fields || [] + const fieldsMap = + fields.reduce((p, n) => { + p[n.dataeaseName] = n + return p + }, {}) || {} + const quotaIndex = dataConfig.meta.findIndex(m => fieldsMap[m.field]?.groupType === 'q') + const data = chart.data?.tableRow + if (quotaIndex === 0 || !data?.length) { + return + } + const mergedColInfo: number[][][] = [[[0, data.length - 1]]] + const mergedCellsInfo = [] + const axisToMerge = dataConfig.meta.filter((_, i) => i < quotaIndex || quotaIndex === -1) + axisToMerge.forEach((a, i) => { + const preMergedColInfo = mergedColInfo[i] + const curMergedColInfo = [] + mergedColInfo.push(curMergedColInfo) + preMergedColInfo.forEach(range => { + const [start, end] = range + let lastVal = data[start][a.field] + let lastIndex = start + for (let index = start; index <= end; index++) { + const curVal = data[index][a.field] + if (curVal !== lastVal || index === end) { + const curRange = index - lastIndex + if (curRange > 1 || (index === end && curRange === 1 && lastVal === curVal)) { + const tmpMergeCells = [] + const textIndex = curRange % 2 === 1 ? (curRange - 1) / 2 : curRange / 2 - 1 + for (let j = 0; j < curRange; j++) { + tmpMergeCells.push({ + colIndex: showIndex ? i + 1 : i, + rowIndex: lastIndex + j, + showText: j === textIndex + }) + } + if (index === end && lastVal === curVal) { + tmpMergeCells.push({ + colIndex: showIndex ? i + 1 : i, + rowIndex: index, + showText: false + }) + } + mergedCellsInfo.push(tmpMergeCells) + curMergedColInfo.push([ + lastIndex, + index === end && lastVal === curVal ? index : index - 1 + ]) + } + lastVal = curVal + lastIndex = index + } + } + }) + }) + if (showIndex) { + const indexMergedCells = mergedCellsInfo.filter(cells => cells[0].colIndex === 1) + indexMergedCells.forEach(cells => { + const tmpCells = cloneDeep(cells) + tmpCells.forEach(cell => { + cell.colIndex = 0 + }) + mergedCellsInfo.unshift(tmpCells) + }) + } + options.mergedCellsInfo = mergedCellsInfo + options.mergedCell = (sheet, cells, meta) => { + if (showIndex && meta.colIndex === 0) { + meta.fieldValue = getRowIndex(mergedCellsInfo, meta) + } + return new CustomMergedCell(sheet, cells, meta) + } + } +} + +export function getRowIndex(mergedCellsInfo: MergedCellInfo[][], meta: ViewMeta): number { + if (!mergedCellsInfo?.length) { + return meta.rowIndex + 1 + } + let curRangeStartIndex = meta.rowIndex + const lostCells = mergedCellsInfo.reduce((p, n) => { + if (n[0].colIndex !== 0) { + return p + } + const start = n[0].rowIndex + const end = n[n.length - 1].rowIndex + const lost = end - start + if (meta.rowIndex >= start && meta.rowIndex <= end) { + curRangeStartIndex = start + } + if (meta.rowIndex > end) { + return p + lost + } + return p + }, 0) + return curRangeStartIndex - lostCells + 1 +} +class CustomMergedCell extends MergedCell { + protected drawBackgroundShape() { + const allPoints = getPolygonPoints(this.cells) + // 处理条件样式,这里没有用透明度 + // 因为合并的单元格是单独的图层,透明度降低的话会显示底下未合并的单元格,需要单独处理被覆盖的单元格 + const { backgroundColor: fill, backgroundColorOpacity: fillOpacity } = this.getBackgroundColor() + const cellTheme = this.theme.dataCell.cell + this.backgroundShape = renderPolygon(this, { + points: allPoints, + stroke: cellTheme.horizontalBorderColor, + fill, + lineHeight: cellTheme.horizontalBorderWidth + }) + } +} + +export class CustomDataCell extends TableDataCell { + /** + * 重写这个方法是为了处理底部的汇总行取消 hover 状态时设置 border 为 1, + * 这样会导致单元格隐藏横边边框失败,出现一条白线 + */ + hideInteractionShape() { + this.stateShapes.forEach(shape => { + updateShapeAttr(shape, SHAPE_STYLE_MAP.backgroundOpacity, 0) + updateShapeAttr(shape, SHAPE_STYLE_MAP.backgroundColor, 'transparent') + updateShapeAttr(shape, SHAPE_STYLE_MAP.borderOpacity, 0) + updateShapeAttr(shape, SHAPE_STYLE_MAP.borderWidth, 0) + updateShapeAttr(shape, SHAPE_STYLE_MAP.borderColor, 'transparent') + }) + } + + /** + * 重写绘制文本内容的方法 + * @protected + */ + protected drawTextShape() { + if (this.meta.autoWrap) { + drawTextShape(this, false) + } else { + super.drawTextShape() + } + } +} + +export class CustomTableColCell extends TableColCell { + /** + * 重写是为了表头文本内容的换行 + * @protected + */ + protected drawTextShape() { + if (this.meta.autoWrap) { + drawTextShape(this, true) + } else { + super.drawTextShape() + } + } +} + +/** + * 绘制文本 换行 + * @param cell + * @param isHeader + */ +const drawTextShape = (cell, isHeader) => { + // 换行符 + const lineBreak = '\n' + // 省略号 + const ellipsis = '...' + // 用户配置的最大行数 + const maxLines = cell.meta.maxLines ?? 1 + const { + options: { placeholder } + } = cell.spreadsheet + const emptyPlaceholder = getEmptyPlaceholder(this, placeholder) + // 单元格文本 + const { formattedValue } = cell.getFormattedFieldValue() + // 获取文本样式 + const textStyle = cell.getTextStyle() + // 宽度能放几个字符,就放几个,放不下就换行 + let wrapText = getWrapText( + formattedValue ? formattedValue?.toString() : emptyPlaceholder, + textStyle, + cell.meta.width, + cell.spreadsheet + ) + const lines = wrapText.split(lineBreak) + let extraStyleFontSize = textStyle.fontSize + // 不是表头,处理文本高度和换行 + if (!isHeader) { + const textHeight = getWrapTextHeight( + wrapText.replaceAll(lineBreak, ''), + textStyle, + cell.spreadsheet, + maxLines + ) + const lineCountInCell = Math.floor(cell.meta.height / textHeight) + const wrapTextArr = lines.slice(0, lineCountInCell) + + // 根据行数调整换行后的文本内容 + wrapText = lineCountInCell < 1 ? ellipsis : wrapTextArr.join(lineBreak) || ellipsis + const resultWrapArr = wrapText.split(lineBreak) + // 控制最大行数 + if ( + !wrapText.endsWith(ellipsis) && + (lines.length > maxLines || lines.length > lineCountInCell) + ) { + // 第一行的字符个数 + const firstLineStrNumber = resultWrapArr[0].length + const temp = resultWrapArr.slice(0, Math.min(maxLines, lineCountInCell)) + // 修改最后一行的字符,按照第一行字符个数-1,修改最后一行的字符为... + temp[temp.length - 1] = temp[temp.length - 1].slice(0, firstLineStrNumber - 1) + ellipsis + wrapText = temp.join(lineBreak) + } + if (wrapText === ellipsis) { + extraStyleFontSize = 12 + } + } else { + const resultWrapArr = wrapText.split(lineBreak) + // 控制最大行数 + if (lines.length > maxLines) { + const temp = resultWrapArr.slice(0, maxLines) + // 第一行的字符个数 + const firstLineStrNumber = resultWrapArr[0].length + // 修改最后一行的字符 + temp[temp.length - 1] = temp[temp.length - 1].slice(0, firstLineStrNumber - 1) + ellipsis + wrapText = temp.join(lineBreak) + } + } + // 设置最终文本和其宽度 + cell.actualText = wrapText + cell.actualTextWidth = cell.spreadsheet.measureTextWidth(wrapText, textStyle) + + // 获取文本位置并渲染文本 + const position = cell.getTextPosition() + // 绘制文本 + cell.textShape = renderText(cell, [cell.textShape], position.x, position.y, wrapText, textStyle, { + fontSize: extraStyleFontSize + }) + + // 将文本形状添加到形状数组 + cell.textShapes.push(cell.textShape) +} + +/** + * 计算表头高度 + * @param info 单元格信息 + * @param newChart + * @param tableHeader 表头配置 + * @param basicStyle 表格基础样式 + * @param layoutResult + */ +export const calculateHeaderHeight = (info, newChart, tableHeader, basicStyle, layoutResult) => { + if (tableHeader.showTableHeader === false) return + const ev = layoutResult || newChart.facet.layoutResult + const maxLines = basicStyle.maxLines ?? 1 + const textStyle = { ...newChart.theme.cornerCell.text } + const sourceText = info.info.meta.value + let maxHeight = getWrapTextHeight( + getWrapText(sourceText, textStyle, info.info.resizedWidth, ev.spreadsheet), + textStyle, + ev.spreadsheet, + maxLines + ) + + // 获取最大高度的列,排除当前列 + const maxHeightCol = ev.colLeafNodes + .filter(n => n.colIndex !== info.info.meta.colIndex) + .reduce( + (maxHeightNode, currentNode) => { + const wrapTextHeight = getWrapTextHeight( + getWrapText(currentNode.value, textStyle, currentNode.width, currentNode.spreadsheet), + textStyle, + currentNode.spreadsheet, + maxLines + ) + return wrapTextHeight > maxHeightNode.height + ? { height: wrapTextHeight, colIndex: currentNode.colIndex } + : maxHeightNode + }, + { height: 0 } + ) + + // 使用最大高度 + maxHeight = Math.max(maxHeight, maxHeightCol.height) + textStyle.fontSize + 10.5 + + if (layoutResult) { + if (basicStyle.tableColumnMode === 'adapt') maxHeight -= textStyle.fontSize - 2 + ev.colLeafNodes.forEach(n => (n.height = maxHeight)) + ev.colsHierarchy.height = maxHeight + } + + newChart.store.set('autoCalcHeight', maxHeight) +} + +/** + * 获取换行文本 + * 累加字符串单个字符的宽度,超过单元格宽度时,添加换行 + * @param sourceText + * @param textStyle + * @param cellWidth + * @param spreadsheet + */ +const getWrapText = (sourceText, textStyle, cellWidth, spreadsheet) => { + if (!sourceText && sourceText !== 0) return '' + sourceText = sourceText.toString().trim() + const getTextWidth = text => spreadsheet.measureTextWidthRoughly(text, textStyle) + + let resultWrapText = '' + let restText = '' + let restTextWidth = 0 + for (let i = 0; i < sourceText.length; i++) { + const char = sourceText[i] + const charWidth = getTextWidth(char) + restTextWidth += charWidth + restText += char + // 中文时,需要单元格宽度减去16个文字宽度,否则会超出单元格宽度 + const cWidth = char.charCodeAt(0) >= 128 ? 12 : 8 + // 添加换行 + if (restTextWidth >= cellWidth - textStyle.fontSize - cWidth) { + // 最后一个字符不添加换行符 + resultWrapText += restText + (i !== sourceText.length - 1 ? '\n' : '') + restText = '' + restTextWidth = 0 + } + } + + resultWrapText += restText + return resultWrapText +} +/** + * 计算文本行高 + * @param wrapText + * @param textStyle + * @param spreadsheet + * @param maxLines 最大行数 + */ +const getWrapTextHeight = (wrapText, textStyle, spreadsheet, maxLines) => { + // 行内最高 + let maxHeight = 0 + // 获取最高字符的高度 + for (const char of wrapText) { + const h = textStyle.fontSize / (char.charCodeAt(0) >= 128 ? 5 : 2.5) + maxHeight = Math.max(maxHeight, spreadsheet.measureTextHeight(char, textStyle) + h) + } + // 行数 + const lines = wrapText.split('\n').length + return Math.min(lines, maxLines) * maxHeight +} + +/** + * 设置汇总行 + * @param chart + * @param s2Options + * @param newData + * @param tableHeader + * @param basicStyle + * @param showSummary + */ +export const configSummaryRow = ( + chart, + s2Options, + newData, + tableHeader, + basicStyle, + showSummary +) => { + if (!showSummary || !newData.length) return + // 设置汇总行高度和表头一致 + const heightByField = {} + heightByField[newData.length] = tableHeader.tableTitleHeight + s2Options.style.rowCfg = { heightByField } + // 计算汇总加入到数据里,冻结最后一行 + s2Options.frozenTrailingRowCount = 1 + const yAxis = chart.yAxis + const xAxis = chart.xAxis + const summaryObj = newData.reduce( + (p, n) => { + if (chart.type === 'table-info') { + xAxis + .filter(axis => [2, 3, 4].includes(axis.deType)) + .forEach(axis => { + p[axis.dataeaseName] = + (parseFloat(n[axis.dataeaseName]) || 0) + (parseFloat(p[axis.dataeaseName]) || 0) + }) + } else { + yAxis.forEach(axis => { + p[axis.dataeaseName] = + (parseFloat(n[axis.dataeaseName]) || 0) + (parseFloat(p[axis.dataeaseName]) || 0) + }) + } + return p + }, + { SUMMARY: true } + ) + newData.push(summaryObj) + s2Options.dataCell = viewMeta => { + // 配置文本自动换行参数 + viewMeta.autoWrap = basicStyle.autoWrap + viewMeta.maxLines = basicStyle.maxLines + if (viewMeta.rowIndex !== newData.length - 1) { + return new CustomDataCell(viewMeta, viewMeta.spreadsheet) + } + if (viewMeta.colIndex === 0) { + if (tableHeader.showIndex) { + viewMeta.fieldValue = basicStyle.summaryLabel ?? i18nt('chart.total_show') + } else { + if (xAxis.length) { + viewMeta.fieldValue = basicStyle.summaryLabel ?? i18nt('chart.total_show') + } + } + } + return new SummaryCell(viewMeta, viewMeta.spreadsheet) + } +} + +/** + * 汇总行样式,紧贴在单元格后面 + * @param newChart + * @param newData + * @param tableCell + * @param tableHeader + * @param showSummary + */ +export const summaryRowStyle = (newChart, newData, tableCell, tableHeader, showSummary) => { + if (!showSummary || !newData.length) return + newChart.on(S2Event.LAYOUT_BEFORE_RENDER, () => { + const showHeader = tableHeader.showTableHeader === true + // 不显示表头时,减少一个表头的高度 + const headerAndSummaryHeight = showHeader ? 2 : 1 + const totalHeight = + tableHeader.tableTitleHeight * headerAndSummaryHeight + + tableCell.tableItemHeight * (newData.length - 1) + if (totalHeight < newChart.options.height) { + // 6 是阴影高度 + newChart.options.height = + totalHeight < newChart.options.height - 6 ? totalHeight + 6 : totalHeight + } + }) +} + +export class SummaryCell extends CustomDataCell { + getTextStyle() { + const textStyle = cloneDeep(this.theme.colCell.bolderText) + textStyle.textAlign = this.theme.dataCell.text.textAlign + return textStyle + } + getBackgroundColor() { + const { backgroundColor, backgroundColorOpacity } = this.theme.colCell.cell + return { backgroundColor, backgroundColorOpacity } + } +} + +/** + * 配置空数据样式 + * @param newChart + * @param basicStyle + * @param newData + * @param container + */ +export const configEmptyDataStyle = (newChart, basicStyle, newData, container) => { + /** + * 辅助函数:移除空数据dom + */ + const removeEmptyDom = () => { + const emptyElement = document.getElementById(container + '_empty') + if (emptyElement) { + emptyElement.parentElement.removeChild(emptyElement) + } + } + removeEmptyDom() + if (newData.length) return + newChart.on(S2Event.LAYOUT_AFTER_HEADER_LAYOUT, ev => { + removeEmptyDom() + if (!newData.length) { + const emptyDom = document.createElement('div') + const left = Math.min(newChart.options.width, ev.colsHierarchy.width) / 2 - 32 + emptyDom.id = container + '_empty' + emptyDom.textContent = i18nt('data_set.no_data') + emptyDom.setAttribute( + 'style', + `position: absolute; + left: ${left}px; + top: 50%;` + ) + const parent = document.getElementById(container) + parent.insertBefore(emptyDom, parent.firstChild) + } + }) +} + +export const getLeafNodes = (tree: Array): ColumnNode[] => { + const result: ColumnNode[] = [] + const inorderTraversal = node => { + if (!node.children?.length) { + // 叶子节点,添加到结果数组 + result.push(node) + return + } + // 中序遍历 + for (let i = 0; i < node.children?.length; i++) { + inorderTraversal(node.children[i]) + } + } + + // 遍历树中所有节点 + tree.forEach(node => inorderTraversal(node)) + return result +} + +export const getColumns = (fields, cols: Array) => { + const result = [] + for (let i = 0; i < cols.length; i++) { + if (fields.includes(cols[i].key)) { + result.push(cols[i]) + } + if (cols[i].children?.length) { + result.push(...getColumns(fields, cols[i].children as Array)) + } + } + return result +} diff --git a/frontend/src/data-visualization/chart/components/js/panel/index.ts b/frontend/src/data-visualization/chart/components/js/panel/index.ts new file mode 100644 index 0000000..4ecc42a --- /dev/null +++ b/frontend/src/data-visualization/chart/components/js/panel/index.ts @@ -0,0 +1,32 @@ +import { AbstractChartView } from '@/data-visualization/chart/components/js/panel/types' +import { isParent } from '@/data-visualization/chart/components/js/util' + +class ChartViewManager { + private static CHART_VIEW_MAP = new Map>() + + public registerChartView(render: string, name: string, view: AbstractChartView) { + if (ChartViewManager.CHART_VIEW_MAP.has(render)) { + ChartViewManager.CHART_VIEW_MAP.get(render).set(name, view) + } else { + ChartViewManager.CHART_VIEW_MAP.set(render, new Map([[name, view]])) + } + } + + public getChartView(render: string, name: string): AbstractChartView { + return ChartViewManager.CHART_VIEW_MAP.get(render)?.get(name) + } +} + +const chartViewManager = new ChartViewManager() +// 批量自动注册图表,只要是 AbstractChartView 的子类都初始化然后存起来 +const charts = import.meta.glob(['./charts/**/*.ts', '!**/common.ts'], { eager: true }) +for (const chart in charts) { + const chartModule = charts[chart] + Object.getOwnPropertyNames(chartModule).forEach(prop => { + if (isParent(chartModule[prop], AbstractChartView)) { + const chartView = new chartModule[prop]() as AbstractChartView + chartViewManager.registerChartView(chartView.render, chartView.name, chartView) + } + }) +} +export default chartViewManager diff --git a/frontend/src/data-visualization/chart/components/js/panel/types/impl/g2plot.ts b/frontend/src/data-visualization/chart/components/js/panel/types/impl/g2plot.ts new file mode 100644 index 0000000..c8269b5 --- /dev/null +++ b/frontend/src/data-visualization/chart/components/js/panel/types/impl/g2plot.ts @@ -0,0 +1,207 @@ +import type { PickOptions } from '@antv/g2plot/esm/core/plot' +import type { Plot } from '@antv/g2plot/esm/core/plot' +import { + getAnalyse, + getAnalyseHorizontal, + getLabel, + getLegend, + getMultiSeriesTooltip, + getSlider, + getTheme, + getTooltip, + getXAxis, + getYAxis, + getConditions, + handleConditionsStyle, + addConditionsStyleColorToData, + configEmptyDataStyle +} from '@/data-visualization/chart/components/js/panel/common/common_antv' +import { + AntVAbstractChartView, + AntVDrawOptions, + ChartLibraryType, + ChartWrapper +} from '@/data-visualization/chart/components/js/panel/types' + +import { + getColor, + getGroupColor, + getSingleDimensionColor, + getStackColor, + handleEmptyDataStrategy, + setupSeriesColor +} from '../../../util' +import { Options } from '@antv/g2plot' + +export interface G2PlotDrawOptions extends AntVDrawOptions { + /** + * 缩放比例 + */ + scale?: number + /** + * 特殊处理,象限图设置分割线的默认值 + * @param args + */ + quadrantDefaultBaseline?: (...args: any) => void +} + +/** + * 图表对象包装类,一个图表里面可能有多个对象实例 + */ +export class G2PlotWrapper> extends ChartWrapper< + P | Array

    +> { + constructor(chartInstance: P | Array

    ) { + super() + this.chartInstance = chartInstance + } + destroy = () => { + if (!this.chartInstance) { + return + } + if (Array.isArray(this.chartInstance)) { + this.chartInstance?.forEach(p => p.destroy()) + } else { + this.chartInstance?.destroy() + } + } + + render = () => { + if (!this.chartInstance) { + return + } + if (Array.isArray(this.chartInstance)) { + this.chartInstance?.forEach(p => p.render()) + } else { + this.chartInstance?.render() + } + } +} +/** + * G2Plot 的图表抽象类 + */ +export abstract class G2PlotChartView< + O extends PickOptions = PickOptions, + P extends Plot = Plot +> extends AntVAbstractChartView { + /** + * 根据参数构建图表对象然后返回 + * @param drawOptions 图表配置参数 + * @return 生成的图表对象,类型为 Plot 的子类 + */ + public abstract drawChart(drawOptions: G2PlotDrawOptions

    ): G2PlotWrapper | P | Promise

    + + protected configTheme(chart: Chart, options: O): O { + const theme = getTheme(chart) + return { ...options, theme } + } + + protected configLabel(chart: Chart, options: O): O { + const label = getLabel(chart) + return { ...options, label } + } + + protected configMultiSeriesTooltip(chart: Chart, options: O): O { + const tooltip = getMultiSeriesTooltip(chart) + return { ...options, tooltip } + } + + protected configTooltip(chart: Chart, options: O): O { + const tooltip = getTooltip(chart) + return { ...options, tooltip } + } + protected configLegend(chart: Chart, options: O): O { + const legend = getLegend(chart) + return { ...options, legend } + } + + protected configXAxis(chart: Chart, options: O): O { + const xAxis = getXAxis(chart) + return { ...options, xAxis } + } + + protected configYAxis(chart: Chart, options: O): O { + const yAxis = getYAxis(chart) + return { ...options, yAxis } + } + + protected configSlider(chart: Chart, options: O): O { + const slider = getSlider(chart) + return { ...options, slider } + } + + protected configAnalyse(chart: Chart, options: O): O { + const annotations = getAnalyse(chart) + return { + ...options, + annotations: [...annotations, ...((options as unknown as Options).annotations || [])] + } + } + + protected configAnalyseHorizontal(chart: Chart, options: O): O { + const annotations = getAnalyseHorizontal(chart) + return { ...options, annotations } + } + + protected configEmptyDataStrategy(chart: Chart, options: O): O { + return handleEmptyDataStrategy(chart, options) + } + + protected configColor(chart: Chart, options: O): O { + const color = getColor(chart) + return { ...options, color } + } + + protected configGroupColor(chart: Chart, options: O): O { + const color = getGroupColor(chart, options) + return { ...options, color } + } + + protected configStackColor(chart: Chart, options: O): O { + const color = getStackColor(chart, options) + return { ...options, color } + } + + protected configSingleDimensionColor(chart: Chart, options: O): O { + const color = getSingleDimensionColor(chart, options) + return { ...options, color } + } + + public setupSeriesColor(chart: ChartObj, data?: any[]): ChartBasicStyle['seriesColor'] { + return setupSeriesColor(chart, data) + } + + public setupSubSeriesColor(chart: ChartObj, data?: any[]): ChartBasicStyle['seriesColor'] { + return undefined + } + + protected configConditions(chart: Chart, options: O) { + const annotations = getConditions(chart) + return { + ...options, + annotations: [...annotations, ...((options as unknown as Options).annotations || [])] + } + } + + protected configBarConditions(chart: Chart, options: O) { + return handleConditionsStyle(chart, options) + } + + protected addConditionsStyleColorToData(chart: Chart, data: any[]) { + return addConditionsStyleColorToData(chart, data) + } + + protected configEmptyDataStyle(newChart, newData: any[], container: string) { + configEmptyDataStyle(newChart, newData, container) + } + + /** + * 流式配置公共参数,处理常用的配置,后续如果有其他通用配置也可以放进来,需要单独配置的属性在各个图表自行实现。 + * @param chart 数据库图表对象。 + * @param options 各个图表的参数,泛化的 Options,可以自行扩展,比如加个扩展 X 轴或者扩展 Y 轴字段。 + */ + protected abstract setupOptions(chart: Chart, options: O, context?: Record): O + protected constructor(name: string, defaultData: any[]) { + super(ChartLibraryType.G2_PLOT, name, defaultData) + } +} diff --git a/frontend/src/data-visualization/chart/components/js/panel/types/impl/l7.ts b/frontend/src/data-visualization/chart/components/js/panel/types/impl/l7.ts new file mode 100644 index 0000000..24bd6aa --- /dev/null +++ b/frontend/src/data-visualization/chart/components/js/panel/types/impl/l7.ts @@ -0,0 +1,143 @@ +import type { Scene } from '@antv/l7-scene' +import { + AntVAbstractChartView, + AntVDrawOptions, + ChartLibraryType, + ChartWrapper +} from '@/data-visualization/chart/components/js/panel/types' +import { cloneDeep, defaultsDeep } from 'lodash-es' +import { parseJson } from '@/data-visualization/chart/components/js/util' +import type { ILayer } from '@antv/l7plot' +import { + configL7Label, + configL7Tooltip, + configL7Zoom +} from '@/data-visualization/chart/components/js/panel/common/common_antv' +// import { queryMapKeyApi } from '@/api/setting/sysParameter' +import { useMapStoreWithOut } from '@/data-visualization/store/modules/map' +const mapStore = useMapStoreWithOut() + +export type L7DrawConfig

    = AntVDrawOptions

    +export interface L7Config extends ILayer { + handleConfig?: (arg0: Scene) => void + [key: string]: string | any +} +export class L7Wrapper< + O extends L7Config | Array, + S extends Scene +> extends ChartWrapper { + private readonly config: O | Array + private readonly scene: S | null = null + + public getScene() { + return this.scene + } + constructor(scene: S, l7config: O | Array | undefined) { + super() + this.chartInstance = scene + this.config = l7config + this.scene = scene + } + destroy = () => { + if (!this.chartInstance) { + return + } + this.chartInstance?.destroy() + } + render = () => { + if (this.scene && this.config) { + if (this.scene.loaded) { + if (Array.isArray(this.config)) { + this.config?.forEach(p => { + this.handleConfig(p) + }) + } else { + this.handleConfig(this.config) + } + } else { + this.scene.on('loaded', () => { + if (Array.isArray(this.config)) { + this.config?.forEach(p => { + this.handleConfig(p) + }) + } else { + this.handleConfig(this.config) + } + }) + } + } + } + + handleConfig = (config: L7Config) => { + if (config) { + if (config.handleConfig) { + config.handleConfig?.(this.scene) + } else { + this.scene.addLayer(config) + } + } + } +} +export abstract class L7ChartView< + S extends Scene, + O extends L7Config +> extends AntVAbstractChartView { + public abstract drawChart(drawOption: L7DrawConfig): L7Wrapper | any + + protected configEmptyDataStrategy(chart: Chart, options: O): O { + const { functionCfg } = parseJson(chart.senior) + const emptyDataStrategy = functionCfg.emptyDataStrategy + if (!emptyDataStrategy || emptyDataStrategy === 'breakLine') { + return options + } + const data = cloneDeep(options.sourceOption.data) + if (emptyDataStrategy === 'setZero') { + data.forEach(item => { + item.value === null && (item.value = 0) + }) + } + if (emptyDataStrategy === 'ignoreData') { + for (let i = data.length - 1; i >= 0; i--) { + if (data[i].value === null) { + data.splice(i, 1) + } + } + } + options.sourceOption.data = data + return options + } + + protected configZoomButton(chart: Chart, plot: S) { + configL7Zoom(chart, plot) + } + + protected configLabel(chart: Chart, options: O): O { + const label = configL7Label(chart) + defaultsDeep(options.label, label) + return options + } + + protected configTooltip(chart: Chart, options: O): O { + const tooltip = configL7Tooltip(chart) + defaultsDeep(options.tooltip, tooltip) + return options + } + + protected constructor(name: string, defaultData: any[]) { + super(ChartLibraryType.L7, name, defaultData) + } + + protected getMapKey = async () => { + if (!mapStore.mapKey.key) { + // await queryMapKeyApi().then(res => mapStore.setKey(res.data)) + } + if (mapStore.mapKey.securityCode) { + window._AMapSecurityConfig = { + securityJsCode: mapStore.mapKey.securityCode + } + } + return mapStore.mapKey + } + + protected abstract setupOptions(chart: Chart, options: O): O +} diff --git a/frontend/src/data-visualization/chart/components/js/panel/types/impl/l7plot.ts b/frontend/src/data-visualization/chart/components/js/panel/types/impl/l7plot.ts new file mode 100644 index 0000000..21f8b3b --- /dev/null +++ b/frontend/src/data-visualization/chart/components/js/panel/types/impl/l7plot.ts @@ -0,0 +1,95 @@ +import type { ViewLevel } from '@antv/l7plot/dist/esm/plots/choropleth/types' +import type { FeatureCollection } from '@antv/l7plot/dist/esm/plots/choropleth/types' +import type { PlotOptions } from '@antv/l7plot/dist/esm/types/plot' +import type { Plot as L7Plot } from '@antv/l7plot/dist/esm/core/plot' +import { + configL7Label, + configL7Legend, + configL7PlotZoom, + configL7Style, + configL7Tooltip +} from '@/data-visualization/chart/components/js/panel/common/common_antv' +import { + AntVAbstractChartView, + AntVDrawOptions, + ChartLibraryType +} from '@/data-visualization/chart/components/js/panel/types' +import { cloneDeep, defaultsDeep } from 'lodash-es' +import { parseJson } from '@/data-visualization/chart/components/js/util' + +export interface L7PlotDrawOptions

    extends AntVDrawOptions

    { + areaId?: string + level?: ViewLevel['level'] + geoJson?: FeatureCollection + scope?: string[] +} +// S2 or others to be defined next +export abstract class L7PlotChartView< + O extends PlotOptions, + P extends L7Plot +> extends AntVAbstractChartView { + public abstract drawChart(drawOption: L7PlotDrawOptions

    ): P | Promise

    + + protected configLabel(chart: Chart, options: O): O { + const label = configL7Label(chart) + defaultsDeep(options.label, label) + return options + } + + protected configStyle(chart: Chart, options: O): O { + const style = configL7Style(chart) + defaultsDeep(options['style'], style) + return options + } + + protected configTooltip(chart: Chart, options: O): O { + const tooltip = configL7Tooltip(chart) + defaultsDeep(options.tooltip, tooltip) + return options + } + protected configLegend(chart: Chart, options: O): O { + const legend = configL7Legend(chart) + defaultsDeep(options, { legend }) + return options + } + protected configEmptyDataStrategy(chart: Chart, options: O): O { + const { functionCfg } = parseJson(chart.senior) + const emptyDataStrategy = functionCfg.emptyDataStrategy + if (!emptyDataStrategy || emptyDataStrategy === 'breakLine') { + return options + } + const data = cloneDeep(options.source.data) + if (emptyDataStrategy === 'setZero') { + data.forEach(item => { + item.value === null && (item.value = 0) + item.dynamicTooltipValue?.length > 0 && + item.dynamicTooltipValue.forEach(ele => { + ele.value === null && (ele.value = 0) + }) + }) + } + if (emptyDataStrategy === 'ignoreData') { + for (let i = data.length - 1; i >= 0; i--) { + if (data[i].value === null) { + data.splice(i, 1) + } + for (let j = data[i]?.dynamicTooltipValue?.length - 1; j >= 0; j--) { + if (data[i].dynamicTooltipValue[j].value === null) { + data[i].dynamicTooltipValue.splice(j, 1) + } + } + } + } + options.source.data = data + return options + } + + protected configZoomButton(chart: Chart, plot: P) { + configL7PlotZoom(chart, plot) + } + protected constructor(name: string, defaultData?: any[]) { + super(ChartLibraryType.L7_PLOT, name) + this.defaultData = defaultData + } + protected abstract setupOptions(chart: Chart, options: O, context?: Record): O +} diff --git a/frontend/src/data-visualization/chart/components/js/panel/types/impl/s2.ts b/frontend/src/data-visualization/chart/components/js/panel/types/impl/s2.ts new file mode 100644 index 0000000..3bcc669 --- /dev/null +++ b/frontend/src/data-visualization/chart/components/js/panel/types/impl/s2.ts @@ -0,0 +1,169 @@ +import { + AntVAbstractChartView, + AntVDrawOptions, + ChartLibraryType +} from '@/data-visualization/chart/components/js/panel/types' +import { + S2Theme, + SpreadSheet, + Style, + S2Options, + Meta, + SERIES_NUMBER_FIELD, + setTooltipContainerStyle, + S2DataConfig, + S2Event +} from '@antv/s2' +import { + configHeaderInteraction, + configMergeCells, + configTooltip, + getConditions, + getCustomTheme, + getStyle, + handleTableEmptyStrategy +} from '@/data-visualization/chart/components/js/panel/common/common_table' +import '@antv/s2/dist/style.min.css' +import { find } from 'lodash-es' + +declare interface PageInfo { + currentPage: number + pageSize: number + total: number +} + +export interface S2DrawOptions extends AntVDrawOptions { + pageInfo?: PageInfo + resizeAction?: (...args: any) => void + touchAction?: (...args: any) => void +} +export abstract class S2ChartView

    extends AntVAbstractChartView { + public abstract drawChart(drawOption: S2DrawOptions

    ): P + protected constructor(name: string, defaultData: any[]) { + super(ChartLibraryType.S2, name, defaultData) + } + protected configTheme(chart: Chart): S2Theme { + return getCustomTheme(chart) + } + + protected configStyle(chart: Chart, s2DataConfig: S2DataConfig): Style { + return getStyle(chart, s2DataConfig) + } + + protected configEmptyDataStrategy(chart: Chart): Record[] { + return handleTableEmptyStrategy(chart) + } + + protected configTooltip(chart: Chart, option: S2Options) { + configTooltip(chart, option) + } + + protected configHeaderInteraction(chart: Chart, option: S2Options) { + configHeaderInteraction(chart, option) + } + + protected configConditions(chart: Chart) { + return getConditions(chart) + } + + protected configMergeCells(chart: Chart, option: S2Options, dataConfig: S2DataConfig) { + configMergeCells(chart, option, dataConfig) + } + + protected showTooltip(s2Instance: P, event, metaConfig: Meta[]) { + const cell = s2Instance.getCell(event.target) + const meta = cell.getMeta() + let content = '' + let field + switch (cell.cellType) { + case 'dataCell': + case 'mergedCell': + if (meta.valueField === SERIES_NUMBER_FIELD) { + content = meta.fieldValue.toString() + break + } + field = find(metaConfig, item => item.field === meta.valueField) + if (meta.fieldValue === 0) { + content = '0' + } + if (meta.fieldValue) { + content = field?.formatter?.(meta.fieldValue) + } + break + case 'rowCell': + case 'colCell': + content = meta.label + field = find(metaConfig, item => item.field === content) + if (field) { + content = field.name + } + break + } + if (!content) { + return + } + event.s2Instance = s2Instance + const style = s2Instance.options.tooltip.style + setTooltipContainerStyle(s2Instance.tooltip.container, { style }) + s2Instance.showTooltip({ + position: { + x: event.clientX, + y: event.clientY + }, + content, + meta, + event + }) + } + + protected configTouchEvent(s2Instance: P, option: S2DrawOptions

    , meta: Meta[]) { + const { touchAction } = option + // touch action + s2Instance.once(S2Event.LAYOUT_AFTER_RENDER, () => { + const touchActionInit = s2Instance.store.get('touchActionInit') + if (touchActionInit) { + return + } + s2Instance.store.set('touchActionInit', true) + const canvas = s2Instance.getCanvasElement() + let startTime = Date.now() + canvas.addEventListener('touchstart', () => { + startTime = Date.now() + }) + canvas.addEventListener('touchend', e => { + const duration = Date.now() - startTime + // 超过 300ms 触发复制 + if (duration > 300) { + return + } + const callback = () => { + const canvasPosition = canvas.getBoundingClientRect() + const touchPosition = [e.changedTouches[0].pageX, e.changedTouches[0].pageY] + const relativePosition = [ + touchPosition[0] - canvasPosition.x, + touchPosition[1] - canvasPosition.y + ] + const shape = s2Instance.container.getShape(relativePosition[0], relativePosition[1]) + // 图片单元格点击放大图片 + if (shape.cfg?.parent.constructor.name === 'ImageCell') { + return + } + e.preventDefault() + e.stopPropagation() + if (shape) { + const event = { + target: shape, + x: relativePosition[0], + y: relativePosition[1], + clientX: touchPosition[0], + clientY: touchPosition[1], + originEvent: e + } + this.showTooltip(s2Instance, event, meta) + } + } + touchAction(callback) + }) + }) + } +} diff --git a/frontend/src/data-visualization/chart/components/js/panel/types/index.ts b/frontend/src/data-visualization/chart/components/js/panel/types/index.ts new file mode 100644 index 0000000..8c35bcc --- /dev/null +++ b/frontend/src/data-visualization/chart/components/js/panel/types/index.ts @@ -0,0 +1,128 @@ +import { useI18n } from '@/data-visualization/hooks/web/useI18n' + +const { t } = useI18n() + +export enum ChartRenderType { + ANT_V = 'antv', + ECHARTS = 'echarts', + CUSTOM = 'custom' +} + +export enum ChartLibraryType { + G2_PLOT = 'g2plot', + L7_PLOT = 'l7plot', + L7 = 'l7', + ECHARTS = 'echarts', + S2 = 's2', + RICH_TEXT = 'rich-text', + PICTURE_GROUP = 'picture-group', + INDICATOR = 'indicator' +} +export abstract class ChartWrapper { + chartInstance: O + abstract render: () => any + abstract destroy: () => any +} +export abstract class AbstractChartView { + render: ChartRenderType + library: ChartLibraryType + name: string + title: string + abstract properties: EditorProperty[] + abstract propertyInner: EditorPropertyInner + abstract axis: AxisType[] + abstract axisConfig: AxisConfig + abstract selectorSpec: EditorSelectorSpec + /** + * 在新建和切换图表的时候处理默认值 + * @param chart 数据库图表对象 + */ + setupDefaultOptions(chart: ChartObj): ChartObj { + return chart + } + + protected defaultData: any[] + + protected constructor( + render: ChartRenderType, + library: ChartLibraryType, + name: string, + defaultData?: any[] + ) { + this.render = render + this.library = library + this.name = name + this.defaultData = defaultData + } +} + +export interface AntVDrawOptions { + /** + * 生成的图表对象 + */ + chartObj: O + /** + * dom容器id + */ + container: string + /** + * 数据库中的图表配置对象 + */ + chart: Chart + /** + * 事件回调函数 + * @param args 事件参数 + */ + action?: (...args: any[]) => any +} + +export abstract class AntVAbstractChartView extends AbstractChartView { + axisConfig: AxisConfig = { + xAxis: { + name: `${t('chart.drag_block_type_axis')} / ${t('chart.dimension')}`, + type: 'd', + allowEmpty: true + }, + xAxisExt: { + name: `${t('chart.chart_group')} / ${t('chart.dimension')}`, + type: 'd', + limit: 1, + allowEmpty: true + }, + extStack: { + name: `${t('chart.stack_item')} / ${t('chart.dimension')}`, + type: 'd', + limit: 1, + allowEmpty: true + }, + yAxis: { + name: `${t('chart.drag_block_value_axis')} / ${t('chart.quota')}`, + type: 'q', + limit: 1, + allowEmpty: true + } + } + selectorSpec: EditorSelectorSpec = { + 'misc-style-selector': { + title: `${t('chart.size')}` + }, + 'dual-y-axis-selector': { + title: `${t('chart.yAxis')}` + }, + 'x-axis-selector': { + title: `${t('chart.xAxis')}` + } + } + protected constructor(library: ChartLibraryType, name: string, defaultData?: any[]) { + super(ChartRenderType.ANT_V, library, name, defaultData) + } +} + +/** + * Echarts 图表的抽象类 + */ +export abstract class EchartsChartView extends AbstractChartView { + protected constructor(name: string, defaultData: any[]) { + super(ChartRenderType.ECHARTS, ChartLibraryType.ECHARTS, name, defaultData) + } +} diff --git a/frontend/src/data-visualization/chart/components/js/util.ts b/frontend/src/data-visualization/chart/components/js/util.ts new file mode 100644 index 0000000..33984be --- /dev/null +++ b/frontend/src/data-visualization/chart/components/js/util.ts @@ -0,0 +1,1209 @@ +import { isEmpty, isNumber } from 'lodash-es' +import { DEFAULT_TITLE_STYLE } from '../editor/util/chart' +import { equalsAny, includesAny } from '../editor/util/StringUtils' +import { FeatureCollection } from '@antv/l7plot/dist/esm/plots/choropleth/types' +import { useMapStoreWithOut } from '@/data-visualization/store/modules/map' +import { getGeoJson } from '@/api/data-visualization/map' +import { computed, toRaw } from 'vue' +import { Options } from '@antv/g2plot/esm' +import { PickOptions } from '@antv/g2plot/esm/core/plot' +import { innerExportDataSetDetails, innerExportDetails } from '@/api/data-visualization/chart' +import { ElMessage } from 'element-plus-secondary' +import { useI18n } from '@/data-visualization/hooks/web/useI18n' +import { useLinkStoreWithOut } from '@/data-visualization/store/modules/link' +import { useAppStoreWithOut } from '@/data-visualization/store/modules/app' +const appStore = useAppStoreWithOut() +const isDataEaseBi = computed(() => appStore.getIsDataEaseBi) + +const { t } = useI18n() +// 同时支持将hex和rgb,转换成rgba +export function hexColorToRGBA(hex, alpha) { + let rgb = [] // 定义rgb数组 + if (hex.indexOf('#') > -1) { + if (/^\#[0-9A-F]{3}$/i.test(hex)) { + // 判断传入是否为#三位十六进制数 + let sixHex = '#' + hex.replace(/[0-9A-F]/gi, function (kw) { + sixHex += kw + kw // 把三位16进制数转化为六位 + }) + hex = sixHex // 保存回hex + } + if (/^#[0-9A-F]{6}$/i.test(hex)) { + // 判断传入是否为#六位十六进制数 + hex.replace(/[0-9A-F]{2}/gi, function (kw) { + // eslint-disable-next-line no-eval + rgb.push(eval('0x' + kw)) // 十六进制转化为十进制并存如数组 + }) + return `rgba(${rgb.join(',')},${alpha / 100})` // 输出RGB格式颜色 + } else { + return 'rgb(0,0,0)' + } + } else { + rgb = hex.match(/\d+/g) + return `rgba(${rgb.join(',')},${alpha / 100})` + } +} + +export function digToHex(dig) { + let prefix = '' + const num = parseInt((dig * 2.55).toString()) + if (num < 16) { + prefix = '0' + } + return prefix.concat(num.toString(16).toUpperCase()) +} + +export function customSort(custom, data) { + const indexArr = [] + const joinArr = [] + for (let i = 0; i < custom.length; i++) { + const ele = custom[i] + for (let j = 0; j < data.length; j++) { + const d = data[j] + if (ele === d.field) { + joinArr.push(d) + indexArr.push(j) + } + } + } + // 取得 joinArr 就是两者的交集 + const indexArrData = [] + for (let i = 0; i < data.length; i++) { + indexArrData.push(i) + } + const indexResult = [] + for (let i = 0; i < indexArrData.length; i++) { + if (indexArr.indexOf(indexArrData[i]) === -1) { + indexResult.push(indexArrData[i]) + } + } + + const subArr = [] + for (let i = 0; i < indexResult.length; i++) { + subArr.push(data[indexResult[i]]) + } + + return joinArr.concat(subArr) +} + +export function customColor(custom, res) { + const result = [] + for (let i = 0; i < res.length; i++) { + const r = res[i] + let flag = false + for (let j = 0; j < custom.length; j++) { + const c = custom[j] + if (r.name === c.name) { + flag = true + result.push(c) + } + } + if (!flag) { + result.push(r) + } + } + return result +} + +export function getColors(chart, colors, reset) { + // 自定义颜色,先按照没有设定的情况,并排好序,当做最终结果 + let seriesColors = [] + let series + if (chart.type.includes('stack')) { + if (chart.data) { + const data = chart.data.data + const stackData = [] + for (let i = 0; i < data.length; i++) { + const s = data[i] + stackData.push(s.category) + } + const sArr = stackData.filter(function (item, index, stackData) { + return stackData.indexOf(item, 0) === index + }) + + for (let i = 0; i < sArr.length; i++) { + const s = sArr[i] + seriesColors.push({ + name: s, + color: colors[i % colors.length], + isCustom: false + }) + } + } + } else if ( + includesAny(chart.type, 'bar', 'scatter', 'radar', 'area') && + !chart.type.includes('group') + ) { + if (Object.prototype.toString.call(chart.yAxis) === '[object Array]') { + series = JSON.parse(JSON.stringify(chart.yAxis)) + } else { + series = JSON.parse(chart.yAxis) + } + if (series) { + for (let i = 0; i < series.length; i++) { + const s = series[i] + seriesColors.push({ + name: s.name, + color: colors[i % colors.length], + isCustom: false + }) + } + } + } else if (equalsAny(chart.type, 'bar-group', 'line')) { + // 拿到data中的category,并去重,然后构建seriesColor + if (chart.data) { + const data = chart.data.data + const s = [] + if (data) { + data.forEach(cur => { + if (s.indexOf(cur.category) < 0) { + s.push(cur.category) + } + }) + } + for (let i = 0; i < s.length; i++) { + seriesColors.push({ + name: s[i], + color: colors[i % colors.length], + isCustom: false + }) + } + } + } else { + if (chart.data) { + const data = chart.data.data + for (let i = 0; i < data.length; i++) { + const s = data[i] + seriesColors.push({ + name: s.field, + color: colors[i % colors.length], + isCustom: false + }) + } + } + } + // 如果有自定义,则与上述中的结果合并。 + // res,custom,以custom为准,去掉res中不存在的,并将custom中name一样的color赋值给res,不存在的name,即新增值,使用i % colors.length,从配色方案中选 + if (!reset) { + let sc = null + if (Object.prototype.toString.call(chart.customAttr) === '[object Object]') { + sc = JSON.parse(JSON.stringify(chart.customAttr)).color.seriesColors + } else { + sc = JSON.parse(chart.customAttr)['color'].seriesColors + } + if (sc && sc.length > 0) { + seriesColors = customColor(sc, seriesColors) + } + // 根据isCustom字段,修正color + for (let i = 0; i < seriesColors.length; i++) { + if (!seriesColors[i].isCustom) { + seriesColors[i].color = colors[i % colors.length] + } + } + } + return seriesColors +} + +export function antVCustomColor(chart) { + const colors = [] + if (chart.customAttr) { + const customAttr = JSON.parse(JSON.stringify(chart.customAttr)) + // color + if (customAttr.basicStyle) { + const basicStyle = JSON.parse(JSON.stringify(customAttr.basicStyle)) + + const customColors = getColors(chart, basicStyle.colors, false) + for (let i = 0; i < customColors.length; i++) { + colors.push(hexColorToRGBA(customColors[i].color, basicStyle.alpha)) + } + } + } + return colors +} + +export function getRemark(chart) { + const remark = {} as any + if (chart.customStyle) { + const customStyle = JSON.parse(JSON.stringify(chart.customStyle)) + if (customStyle.text) { + const title = JSON.parse(JSON.stringify(customStyle.text)) + remark.show = title.remarkShow ? title.remarkShow : DEFAULT_TITLE_STYLE.remarkShow + remark.content = title.remark ? title.remark : DEFAULT_TITLE_STYLE.remark + remark.bgFill = title.remarkBackgroundColor + ? title.remarkBackgroundColor + : DEFAULT_TITLE_STYLE.remarkBackgroundColor + } + } + return remark +} + +export const quotaViews = ['label', 'richTextView', 'indicator', 'gauge', 'liquid'] +// 地图 +const mapChartTypes = ['bubble-map', 'flow-map', 'heat-map', 'map', 'symbolic-map'] +// 分布图 +const distributionChartTypes = [ + 'pie', + 'pie-donut', + 'pie-rose', + 'pie-donut-rose', + 'radar', + 'treemap', + 'word-cloud' +] +// 关系图 +const relationChartTypes = ['scatter', 'quadrant', 'funnel', 'sankey', 'circle-packing'] +// 不支持指标累加的图表 +export const notSupportAccumulateViews = [ + ...quotaViews, + ...mapChartTypes, + ...distributionChartTypes, + ...relationChartTypes, + 'table-info', + 't-heatmap', + 'percentage-bar-stack', + 'percentage-bar-stack-horizontal', + 'progress-bar', + 'stock-line' +] + +export function handleEmptyDataStrategy(chart: Chart, options: O): O { + const { data } = options as unknown as Options + const isChartMix = chart.type.includes('chart-mix') + if (!data?.length) { + return options + } + const strategy = parseJson(chart.senior).functionCfg.emptyDataStrategy + if (strategy === 'ignoreData') { + if (isChartMix) { + for (let i = 0; i < data.length; i++) { + handleIgnoreData(data[i] as Record[]) + } + } else { + handleIgnoreData(data) + } + return options + } + const { yAxis, xAxisExt, extStack } = chart + const multiDimension = yAxis?.length >= 2 || xAxisExt?.length > 0 || extStack?.length > 0 + switch (strategy) { + case 'breakLine': { + if (multiDimension) { + // 多维度保持空 + if (isChartMix) { + for (let i = 0; i < data.length; i++) { + handleBreakLineMultiDimension(data[i] as Record[]) + } + } else { + handleBreakLineMultiDimension(data) + } + } + return { + ...options, + connectNulls: false + } + } + case 'setZero': { + if (multiDimension) { + // 多维度置0 + if (isChartMix) { + for (let i = 0; i < data.length; i++) { + handleSetZeroMultiDimension(data[i] as Record[]) + } + } else { + handleSetZeroMultiDimension(data) + } + } else { + // 单维度置0 + if (isChartMix) { + for (let i = 0; i < data.length; i++) { + handleSetZeroSingleDimension(data[i] as Record[]) + } + } else { + handleSetZeroSingleDimension(data) + } + } + break + } + } + return options +} + +function handleBreakLineMultiDimension(data) { + const dimensionInfoMap = new Map() + const subDimensionSet = new Set() + const quotaMap = new Map() + for (let i = 0; i < data.length; i++) { + const item = data[i] + const dimensionInfo = dimensionInfoMap.get(item.field) + if (dimensionInfo) { + dimensionInfo.set.add(item.category) + } else { + dimensionInfoMap.set(item.field, { set: new Set([item.category]), index: i }) + } + subDimensionSet.add(item.category) + quotaMap.set(item.category, item.quotaList) + } + // Map 是按照插入顺序排序的,所以插入索引往后推 + let insertCount = 0 + dimensionInfoMap.forEach((dimensionInfo, field) => { + if (dimensionInfo.set.size < subDimensionSet.size) { + let subInsertIndex = 0 + subDimensionSet.forEach(dimension => { + if (!dimensionInfo.set.has(dimension)) { + data.splice(dimensionInfo.index + insertCount + subInsertIndex, 0, { + field, + value: null, + category: dimension, + quotaList: quotaMap.get(dimension as string) + }) + } + subInsertIndex++ + }) + insertCount += subDimensionSet.size - dimensionInfo.set.size + } + }) +} + +function handleSetZeroMultiDimension(data: Record[]) { + const dimensionInfoMap = new Map() + const subDimensionSet = new Set() + const quotaMap = new Map() + for (let i = 0; i < data.length; i++) { + const item = data[i] + if (item.value === null) { + item.value = 0 + } + const dimensionInfo = dimensionInfoMap.get(item.field) + if (dimensionInfo) { + dimensionInfo.set.add(item.category) + } else { + dimensionInfoMap.set(item.field, { set: new Set([item.category]), index: i }) + } + subDimensionSet.add(item.category) + quotaMap.set(item.category, item.quotaList) + } + let insertCount = 0 + dimensionInfoMap.forEach((dimensionInfo, field) => { + if (dimensionInfo.set.size < subDimensionSet.size) { + let subInsertIndex = 0 + subDimensionSet.forEach(dimension => { + if (!dimensionInfo.set.has(dimension)) { + data.splice(dimensionInfo.index + insertCount + subInsertIndex, 0, { + field, + value: 0, + category: dimension, + quotaList: quotaMap.get(dimension as string) + }) + } + subInsertIndex++ + }) + insertCount += subDimensionSet.size - dimensionInfo.set.size + } + }) +} + +function handleSetZeroSingleDimension(data: Record[]) { + data.forEach(item => { + if (item.value === null) { + item.value = 0 + } + }) +} + +function handleIgnoreData(data: Record[]) { + for (let i = data.length - 1; i >= 0; i--) { + const item = data[i] + if (item.value === null) { + data.splice(i, 1) + } + } +} + +export function resetRgbOpacity(sourceColor: string, times: number): string { + if (sourceColor?.startsWith('rgb')) { + const numbers = sourceColor.match(/(\d(\.\d+)?)+/g) + if (numbers?.length === 4) { + const opacity = parseFloat(numbers[3]) + if (isNumber(opacity)) { + let resultOpacity = parseFloat((opacity * times).toFixed(2)) + if (resultOpacity > 1) { + resultOpacity = 1 + } + const colorArr = numbers.slice(0, 3).concat(resultOpacity.toString()) + return `rgba(${colorArr.join(',')})` + } + } + } + return sourceColor +} + +export function parseJson(str: T | JSONString): T { + if (typeof str !== 'string') { + return str as T + } + return JSON.parse(str) as T +} + +type FlowFunction = (param: P, result: R, context?: Record, thisArg?: any) => R + +export function flow(...flows: FlowFunction[]): FlowFunction { + return (param: P, result: R, context?: Record, thisArg?: any) => { + return flows.reduce((result: R, flow: FlowFunction) => { + if (thisArg) { + return flow.call(thisArg, param, result, context) + } else { + return flow(param, result, context) + } + }, result) + } +} + +export const isParent = (type: any, parentType: any) => { + let _type = type + while (_type) { + if (_type === parentType) { + return true + } + _type = _type.__proto__ + } + return false +} + +export const getGeoJsonFile = async (areaId: string): Promise => { + const mapStore = useMapStoreWithOut() + let geoJson = mapStore.mapCache[areaId] + if (!geoJson) { + const res = await getGeoJson(areaId) + geoJson = res.data + mapStore.setMap({ id: areaId, geoJson }) + } + return toRaw(geoJson) +} + +const getExcelDownloadRequest = (data, type?) => { + let fields = JSON.parse(JSON.stringify(data.fields)) + // liquid gauge 只需要导出一个字段 + if (['gauge', 'liquid'].includes(type) && fields.length > 1) { + fields = fields.slice(1) + } + const tableRow = JSON.parse(JSON.stringify(data.tableRow)) + const excelHeader = fields.map(item => item.chartShowName ?? item.name) + const excelTypes = fields.map(item => item.deType) + const excelHeaderKeys = fields.map(item => item.dataeaseName) + let excelData = tableRow.map(item => excelHeaderKeys.map(i => item[i])) + let detailFields = [] + if (data.detailFields?.length) { + detailFields = data.detailFields.map(item => { + return { + name: item.name, + deType: item.deType, + dataeaseName: item.dataeaseName + } + }) + excelData = tableRow.map(item => { + return excelHeaderKeys.map(i => { + if (i === 'detail' && !item[i] && Array.isArray(item['details'])) { + const arr = item['details'] + if (arr?.length) { + return arr.map(ele => detailFields.map(field => ele[field.dataeaseName])) + } + return null + } + return item[i] + }) + }) + } + return { + header: excelHeader, + details: excelData, + excelTypes: excelTypes, + excelHeaderKeys: excelHeaderKeys, + detailFields: detailFields + } +} + +export const exportExcelDownload = (chart, callBack?) => { + const excelName = chart.title + let request: any = { + proxy: null, + dvId: chart.sceneId, + viewId: chart.id, + viewInfo: chart, + viewName: excelName, + busiFlag: chart.busiFlag, + downloadType: chart.downloadType + } + if (chart.type.includes('chart-mix')) { + const req1 = getExcelDownloadRequest(chart.data.left) + const req2 = getExcelDownloadRequest(chart.data.right) + request = { + ...request, + multiInfo: [req1, req2] + } + if (chart.downloadType === 'dataset') { + delete request.multiInfo + } + } else { + const req = getExcelDownloadRequest(chart.data, chart.type) + request = { + ...request, + ...req + } + } + + if (chart.type.includes('symbolic-map')) { + request.detailFields = [] + } + + const linkStore = useLinkStoreWithOut() + + if (isDataEaseBi.value || appStore.getIsIframe) { + request.dataEaseBi = true + } + const method = request.downloadType === 'dataset' ? innerExportDataSetDetails : innerExportDetails + if (request.viewInfo?.customAttr?.basicStyle?.tablePageMode) { + request.viewInfo.customAttr.basicStyle.tablePageMode = 'page' + } + method(request) + .then(res => { + if (linkStore.getLinkToken || isDataEaseBi.value || appStore.getIsIframe) { + const blob = new Blob([res.data], { type: 'application/vnd.ms-excel' }) + const link = document.createElement('a') + link.style.display = 'none' + link.href = URL.createObjectURL(blob) + link.download = excelName + '.xlsx' // 下载的文件名 + document.body.appendChild(link) + link.click() + document.body.removeChild(link) + } else { + callBack && callBack(res) + } + }) + .catch(() => { + console.error('Excel download error') + callBack('error') + }) +} + +export const copyString = (content: string, notify = false) => { + const clipboard = navigator.clipboard || { + writeText: data => { + return new Promise(resolve => { + const textareaDom = document.createElement('textarea') + textareaDom.setAttribute('style', 'z-index: -1;position: fixed;opacity: 0;') + textareaDom.value = data + document.body.appendChild(textareaDom) + textareaDom.select() + document.execCommand('copy') + textareaDom.remove() + resolve() + }) + } + } + clipboard.writeText(content).then(() => { + if (notify) { + ElMessage.success(t('commons.copy_success')) + } + }) +} + +/** + * 计算动态区间和颜色 + * @param minValue + * @param maxValue + * @param intervals + * @param colors + */ +export const getDynamicColorScale = ( + minValue: number, + maxValue: number, + intervals: number, + colors?: string[] +) => { + const step = (maxValue - minValue) / intervals + + const colorScale = [] + for (let i = 0; i < intervals; i++) { + colorScale.push({ + value: [minValue + i * step, minValue + (i + 1) * step], + color: colors?.[i], + label: `${(minValue + i * step).toFixed(0)} - ${(minValue + (i + 1) * step).toFixed(0)}` + }) + } + + return colorScale +} +/** + * 过滤掉不在区间的数据 + * @param data + * @param maxValue + * @param minValue + */ +export const filterChartDataByRange = (data: any[], maxValue: number, minValue: number) => { + return data.filter( + item => + item.value === null || + item.value === undefined || + (item.value >= minValue && item.value <= maxValue) + ) +} + +/** + * 获取数据最大最小值 + * @param data + * @param field 值字段 + * @param maxValue + * @param minValue + * @param callback + */ +export const getMaxAndMinValueByData = ( + data: any[], + field: string, + maxValue: number, + minValue: number, + callback: (max: number, min: number) => void +) => { + // 定义一个辅助函数来计算最大值或最小值 + const calculateExtreme = (isMax: boolean) => { + return data.reduce( + (extreme, current) => { + return isMax + ? current[field] > extreme + ? current[field] + : extreme + : current[field] < extreme + ? current[field] + : extreme + }, + isMax ? Number.MIN_SAFE_INTEGER : Number.MAX_SAFE_INTEGER + ) + } + if (minValue === null || maxValue === null) { + let maxResult = maxValue + let minResult = minValue + if (maxResult === null) { + maxResult = calculateExtreme(true) + } + if (minResult === null) { + minResult = calculateExtreme(false) + } + callback(maxResult, minResult) + } + if (minValue === 0 && maxValue === 0) { + const maxResult = calculateExtreme(true) + const minResult = calculateExtreme(false) + callback(maxResult, minResult) + } +} + +export const stepsColor = (start, end, steps, gamma) => { + let i + let j + let ms + let me + const output = [] + const so = [] + gamma = gamma || 1 + const normalize = function (channel) { + return Math.pow(channel / 255, gamma) + } + start = parseColor(start).map(normalize) + end = parseColor(end).map(normalize) + for (i = 0; i < steps; i++) { + ms = steps - 1 === 0 ? 0 : i / (steps - 1) + me = 1 - ms + for (j = 0; j < 3; j++) { + so[j] = pad(Math.round(Math.pow(start[j] * me + end[j] * ms, 1 / gamma) * 255).toString(16)) + } + output.push('#' + so.join('')) + } + function parseColor(hexStr) { + return hexStr.length === 4 + ? hexStr + .substr(1) + .split('') + .map(function (s) { + return 0x11 * parseInt(s, 16) + }) + : [hexStr.substr(1, 2), hexStr.substr(3, 2), hexStr.substr(5, 2)].map(function (s) { + return parseInt(s, 16) + }) + } + function pad(s) { + return s.length === 1 ? '0' + s : s + } + return output +} + +export const getMapColorCases = colorCases => { + const cloneColorCases = JSON.parse(JSON.stringify(colorCases)) + return cloneColorCases.map(colorItem => { + let curColors = colorItem.colors + if (['fresh', 'red', 'spiritual'].includes(colorItem.value)) { + curColors = colorItem.colors.reverse() + } + const len = curColors.length + const start = curColors[0] + const end = curColors[len - 1] + const itemResult = { + name: colorItem.name, + value: colorItem.value + '_split_gradient', + baseColors: [start, end], + colors: stepsColor(start, end, 9, 1) + } + return itemResult + }) +} + +export function getColor(chart: Chart) { + const basicStyle = parseJson(chart.customAttr).basicStyle + const { seriesColor } = basicStyle + if (seriesColor?.length) { + const { yAxis } = chart + const seriesMap = seriesColor.reduce((p, n) => { + p[n.id] = n + return p + }, {}) + yAxis?.forEach((axis, index) => { + const curAxisColor = seriesMap[axis.id] + if (curAxisColor) { + if (index + 1 > basicStyle.colors.length) { + basicStyle.colors.push(curAxisColor.color) + } else { + basicStyle.colors[index] = curAxisColor.color + } + } + }) + const color = basicStyle.colors.map(c => hexColorToRGBA(c, basicStyle.alpha)) + return color + } +} + +export function setupSeriesColor(chart: ChartObj, data?: any[]): ChartBasicStyle['seriesColor'] { + const result: ChartBasicStyle['seriesColor'] = [] + const seriesSet = new Set() + const colors = chart.customAttr.basicStyle.colors + const yAxis = chart.yAxis + yAxis?.forEach(axis => { + if (seriesSet.has(axis.id)) { + return + } + seriesSet.add(axis.id) + result.push({ + id: axis.id, + name: axis.chartShowName ?? axis.name, + color: colors[(seriesSet.size - 1) % colors.length] + }) + }) + return result +} + +export function getGroupColor(chart: Chart, options: O) { + const { basicStyle } = parseJson(chart.customAttr) + const { seriesColor } = basicStyle + if (!seriesColor?.length) { + return + } + const seriesMap = seriesColor.reduce((p, n) => { + p[n.id] = n + return p + }, {}) + const { yAxis, xAxisExt } = chart + const { data } = options as unknown as Options + if (xAxisExt?.length) { + const seriesSet = new Set() + data?.forEach(d => d.category !== null && seriesSet.add(d.category)) + const tmp = [...seriesSet] + tmp.forEach((c, i) => { + const curAxisColor = seriesMap[c as string] + if (curAxisColor) { + if (i + 1 > basicStyle.colors.length) { + basicStyle.colors.push(curAxisColor.color) + } else { + basicStyle.colors[i] = curAxisColor.color + } + } + }) + } else { + yAxis?.forEach((axis, index) => { + const curAxisColor = seriesMap[axis.id] + if (curAxisColor) { + if (index + 1 > basicStyle.colors.length) { + basicStyle.colors.push(curAxisColor.color) + } else { + basicStyle.colors[index] = curAxisColor.color + } + } + }) + } + const color = basicStyle.colors.map(c => hexColorToRGBA(c, basicStyle.alpha)) + return color +} + +export function setUpGroupSeriesColor( + chart: ChartObj, + data?: any[] +): ChartBasicStyle['seriesColor'] { + const result: ChartBasicStyle['seriesColor'] = [] + const seriesSet = new Set() + const colors = chart.customAttr.basicStyle.colors + const { yAxis, xAxisExt } = chart + if (xAxisExt?.length) { + data?.forEach(d => { + if (d.value === null || d.category === null || seriesSet.has(d.category)) { + return + } + seriesSet.add(d.category) + result.push({ + id: d.category, + name: d.category, + color: colors[(seriesSet.size - 1) % colors.length] + }) + }) + } else { + yAxis?.forEach(axis => { + if (seriesSet.has(axis.id)) { + return + } + seriesSet.add(axis.id) + result.push({ + id: axis.id, + name: axis.chartShowName ?? axis.name, + color: colors[(seriesSet.size - 1) % colors.length] + }) + }) + } + return result +} + +export function getStackColor(chart: Chart, options: O) { + const { basicStyle } = parseJson(chart.customAttr) + const { seriesColor } = basicStyle + if (!seriesColor?.length) { + return + } + const seriesMap = seriesColor.reduce((p, n) => { + p[n.id] = n + return p + }, {}) + const { yAxis, extStack } = chart + const { data } = options as unknown as Options + if (extStack?.length) { + const seriesSet = new Set() + data?.forEach(d => d.category !== null && seriesSet.add(d.category)) + const tmp = [...seriesSet] + tmp.forEach((c, i) => { + const curAxisColor = seriesMap[c as string] + if (curAxisColor) { + if (i + 1 > basicStyle.colors.length) { + basicStyle.colors.push(curAxisColor.color) + } else { + basicStyle.colors[i] = curAxisColor.color + } + } + }) + } else { + yAxis?.forEach((axis, index) => { + const curAxisColor = seriesMap[axis.id] + if (curAxisColor) { + if (index + 1 > basicStyle.colors.length) { + basicStyle.colors.push(curAxisColor.color) + } else { + basicStyle.colors[index] = curAxisColor.color + } + } + }) + } + const color = basicStyle.colors.map(c => hexColorToRGBA(c, basicStyle.alpha)) + return color +} + +export function setUpStackSeriesColor( + chart: ChartObj, + data?: any[] +): ChartBasicStyle['seriesColor'] { + const result: ChartBasicStyle['seriesColor'] = [] + const seriesSet = new Set() + const colors = chart.customAttr.basicStyle.colors + const { yAxis, extStack } = chart + if (extStack?.length) { + data?.forEach(d => { + if (d.value === null || d.category === null || seriesSet.has(d.category)) { + return + } + seriesSet.add(d.category) + result.push({ + id: d.category, + name: d.category, + color: colors[(seriesSet.size - 1) % colors.length] + }) + }) + } else { + yAxis?.forEach(axis => { + if (seriesSet.has(axis.id)) { + return + } + seriesSet.add(axis.id) + result.push({ + id: axis.id, + name: axis.chartShowName ?? axis.name, + color: colors[(seriesSet.size - 1) % colors.length] + }) + }) + } + return result +} + +export function getSingleDimensionColor(chart: Chart, options: O) { + const { basicStyle } = parseJson(chart.customAttr) + const { seriesColor } = basicStyle + if (!seriesColor?.length) { + return + } + const seriesMap = seriesColor.reduce((p, n) => { + p[n.id] = n + return p + }, {}) + const { xAxis, yAxis } = chart + const { data } = options as unknown as Options + if (xAxis?.length && yAxis?.length) { + const seriesSet = new Set() + data?.forEach(d => d.field !== null && seriesSet.add(d.field)) + const tmp = [...seriesSet] + tmp.forEach((c, i) => { + const curAxisColor = seriesMap[c as string] + if (curAxisColor) { + if (i + 1 > basicStyle.colors.length) { + basicStyle.colors.push(curAxisColor.color) + } else { + basicStyle.colors[i] = curAxisColor.color + } + } + }) + } + const color = basicStyle.colors.map(c => hexColorToRGBA(c, basicStyle.alpha)) + return color +} + +export function setUpSingleDimensionSeriesColor( + chart: ChartObj, + data?: any[] +): ChartBasicStyle['seriesColor'] { + const result: ChartBasicStyle['seriesColor'] = [] + const seriesSet = new Set() + const colors = chart.customAttr.basicStyle.colors + const { xAxis, yAxis } = chart + if (!(xAxis?.length && yAxis?.length)) { + return result + } + data?.forEach(item => { + if (seriesSet.has(item.field)) { + return + } + seriesSet.add(item.field) + result.push({ + id: item.field, + name: item.field, + color: colors[(seriesSet.size - 1) % colors.length] + }) + }) + return result +} + +export function isAlphaColor(color: string): boolean { + if (!color?.trim()) { + return false + } + if (color.startsWith('#')) { + return color.length === 9 + } + if (color.startsWith('rgb')) { + return color.split(',').length === 4 + } + return false +} + +export function getColorFormAlphaColor(color: string): string { + if (isAlphaColor(color)) { + if (color.startsWith('#')) { + return color.slice(0, 7) + } + if (color.startsWith('rgb') || color.startsWith('RGB')) { + const list = color.split(',') + return list[0] + ',' + list[1] + ',' + list[2] + ')' + } + } + return color +} + +export function isTransparent(color: string): boolean { + if (!color?.trim()) { + return true + } + if (color.startsWith('#')) { + const tmp = color.substring(1, color.length) + if (tmp.length === 3 || tmp.length === 6) { + return false + } + if (tmp.length === 8) { + return tmp.substring(6, 8) === '00' + } + } + if (color.startsWith('rgb')) { + const tmp = color.split(',') + if (tmp.length !== 4) { + return false + } + const alpha = tmp[3].substring(0, tmp[3].length - 1) + return alpha.trim() === '0' + } + return false +} + +export function convertToAlphaColor(color: string, alpha: number): string { + if (!color?.trim()) { + return 'rgba(255,255,255,1)' + } + if (color.startsWith('#')) { + let colorStr = color.trim().substring(1) + if (colorStr.length === 3) { + const tmp = colorStr.split('') + colorStr = `${tmp[0]}${tmp[0]}${tmp[1]}${tmp[1]}${tmp[2]}${tmp[2]}` + } + if (colorStr.length !== 6) { + return '#FFFFFFFF' + } + const alphaHex = parseInt((alpha * 2.55).toFixed(0)) + .toString(16) + .toUpperCase() + return `#${colorStr}${alphaHex}` + } + if (color.startsWith('rgb')) { + const rgb = color.match(/\d+/g) + return `rgba(${rgb.join(',')},${alpha / 100})` + } + return 'rgba(255,255,255,1)' +} + +export function svgStrToUrl(svgStr: string): string { + let file = '' + try { + if (svgStr) { + const blob = new Blob([svgStr], { type: 'image/svg+xml' }) + file = URL.createObjectURL(blob) + } + } catch (e) {} + return file +} + +/** + * 获取非空数据的最小值 + * @param sourceData + * @param field + * @private + */ +export function filterEmptyMinValue(sourceData, field) { + let notEmptyMinValue = 0 + getMaxAndMinValueByData( + sourceData.filter(item => item[field]), + 'value', + 0, + 0, + (max, min) => { + notEmptyMinValue = min + } + ) + return notEmptyMinValue +} + +/** + * 获取折线条件样式 + * @param chart + */ +export function getLineConditions(chart) { + const { threshold } = parseJson(chart.senior) + const conditions = [] + if (threshold.enable) { + threshold.lineThreshold?.forEach(item => + item.conditions?.forEach(c => + conditions.push({ + fieldId: item.fieldId, + term: c.term, + value: c.value, + color: c.color, + min: c.min, + max: c.max + }) + ) + ) + } + return conditions +} + +/** + * 根据折线阈值条件获取新的标签颜色 + * @param conditions + * @param value + * @param fieldId + */ +export function getLineLabelColorByCondition(conditions, value, fieldId) { + const fieldConditions = conditions.filter(item => item.fieldId === fieldId) + let color = undefined + if (fieldConditions.length) { + fieldConditions.some(item => { + if ( + (item.term === 'lt' && value <= item.value) || + (item.term === 'gt' && value >= item.value) || + (item.term === 'between' && value >= item.min && value <= item.max) + ) { + color = item.color + return true + } + }) + } + return color +} + +/** + * 获取文本在画布中的测量信息 + * @param chart 图表内容 + * @param text 测量文本 + * @param font 文本样式 + * @param type 测量类型,高度宽度 + **/ +export const measureText = (chart, text, font, type) => { + const container = document.getElementById(chart.container) + const canvas = container.querySelector('canvas') + const ctx = canvas.getContext('2d') + const { fontWeight, fontSize, fontFamily } = font + ctx.font = [fontWeight, `${fontSize}px`, fontFamily].join(' ').trim() + const textMetrics = ctx.measureText(text) + if (type === 'height') { + return textMetrics.actualBoundingBoxAscent + textMetrics.actualBoundingBoxDescent + } + if (type === 'width') { + return textMetrics.actualBoundingBoxRight + textMetrics.actualBoundingBoxLeft + } + return 0 +} + +/** + * 获取十六进制颜色值 + * @param hex + * @param alpha + */ +export const hexToRgba = (hex, alpha = 1) => { + if (!hex.startsWith('#')) { + return hex + } + // 去掉 # 号 + hex = hex.replace('#', '') + // 转换为 RGB 分量 + const r = parseInt(hex.slice(0, 2), 16) + const g = parseInt(hex.slice(2, 4), 16) + const b = parseInt(hex.slice(4, 6), 16) + const hexAlpha = hex.slice(6, 8) + const a = hexAlpha ? parseInt(hex.slice(6, 8), 16) / 255 : alpha + // 返回 RGBA 格式 + return `rgba(${r}, ${g}, ${b}, ${a})` +} diff --git a/frontend/src/data-visualization/chart/components/views/components/ChartComponentG2Plot.vue b/frontend/src/data-visualization/chart/components/views/components/ChartComponentG2Plot.vue new file mode 100644 index 0000000..850343f --- /dev/null +++ b/frontend/src/data-visualization/chart/components/views/components/ChartComponentG2Plot.vue @@ -0,0 +1,737 @@ + + + + + diff --git a/frontend/src/data-visualization/chart/components/views/components/ChartComponentS2.vue b/frontend/src/data-visualization/chart/components/views/components/ChartComponentS2.vue new file mode 100644 index 0000000..b7fb246 --- /dev/null +++ b/frontend/src/data-visualization/chart/components/views/components/ChartComponentS2.vue @@ -0,0 +1,831 @@ + + + + + + diff --git a/frontend/src/data-visualization/chart/components/views/components/ChartEmptyInfo.vue b/frontend/src/data-visualization/chart/components/views/components/ChartEmptyInfo.vue new file mode 100644 index 0000000..0468144 --- /dev/null +++ b/frontend/src/data-visualization/chart/components/views/components/ChartEmptyInfo.vue @@ -0,0 +1,49 @@ + + + + + diff --git a/frontend/src/data-visualization/chart/components/views/components/ChartError.vue b/frontend/src/data-visualization/chart/components/views/components/ChartError.vue new file mode 100644 index 0000000..ac3325a --- /dev/null +++ b/frontend/src/data-visualization/chart/components/views/components/ChartError.vue @@ -0,0 +1,67 @@ + + + + + diff --git a/frontend/src/data-visualization/chart/components/views/components/DrillPath.vue b/frontend/src/data-visualization/chart/components/views/components/DrillPath.vue new file mode 100644 index 0000000..b40a787 --- /dev/null +++ b/frontend/src/data-visualization/chart/components/views/components/DrillPath.vue @@ -0,0 +1,131 @@ + + + + + diff --git a/frontend/src/data-visualization/chart/components/views/index.vue b/frontend/src/data-visualization/chart/components/views/index.vue new file mode 100644 index 0000000..add19a2 --- /dev/null +++ b/frontend/src/data-visualization/chart/components/views/index.vue @@ -0,0 +1,1283 @@ + + + + + diff --git a/frontend/src/data-visualization/chart/components/views/util/util.ts b/frontend/src/data-visualization/chart/components/views/util/util.ts new file mode 100644 index 0000000..c389d0a --- /dev/null +++ b/frontend/src/data-visualization/chart/components/views/util/util.ts @@ -0,0 +1,5 @@ +export const reverseColor = colorValue => { + colorValue = '0x' + colorValue.replace(/#/g, '') + const str = '000000' + (0xffffff - colorValue).toString(16) + return '#' + str.substring(str.length - 6, str.length) +} diff --git a/frontend/src/data-visualization/components/collapse-switch-item/index.ts b/frontend/src/data-visualization/components/collapse-switch-item/index.ts new file mode 100644 index 0000000..17ad731 --- /dev/null +++ b/frontend/src/data-visualization/components/collapse-switch-item/index.ts @@ -0,0 +1,2 @@ +import CollapseSwitchItem from './src/CollapseSwitchItem.vue' +export { CollapseSwitchItem } diff --git a/frontend/src/data-visualization/components/collapse-switch-item/src/CollapseSwitchItem.vue b/frontend/src/data-visualization/components/collapse-switch-item/src/CollapseSwitchItem.vue new file mode 100644 index 0000000..046ce69 --- /dev/null +++ b/frontend/src/data-visualization/components/collapse-switch-item/src/CollapseSwitchItem.vue @@ -0,0 +1,88 @@ + + + diff --git a/frontend/src/data-visualization/components/config-global/index.ts b/frontend/src/data-visualization/components/config-global/index.ts new file mode 100644 index 0000000..dda2462 --- /dev/null +++ b/frontend/src/data-visualization/components/config-global/index.ts @@ -0,0 +1,3 @@ +import ConfigGlobal from './src/ConfigGlobal.vue' + +export { ConfigGlobal } diff --git a/frontend/src/data-visualization/components/config-global/src/ConfigGlobal.vue b/frontend/src/data-visualization/components/config-global/src/ConfigGlobal.vue new file mode 100644 index 0000000..a567947 --- /dev/null +++ b/frontend/src/data-visualization/components/config-global/src/ConfigGlobal.vue @@ -0,0 +1,16 @@ + + + diff --git a/frontend/src/data-visualization/components/data-visualization/DeGrid.vue b/frontend/src/data-visualization/components/data-visualization/DeGrid.vue new file mode 100644 index 0000000..306e7b5 --- /dev/null +++ b/frontend/src/data-visualization/components/data-visualization/DeGrid.vue @@ -0,0 +1,92 @@ + + + + + diff --git a/frontend/src/data-visualization/components/data-visualization/DeGridScreen.vue b/frontend/src/data-visualization/components/data-visualization/DeGridScreen.vue new file mode 100644 index 0000000..a36f7f9 --- /dev/null +++ b/frontend/src/data-visualization/components/data-visualization/DeGridScreen.vue @@ -0,0 +1,71 @@ + + + + + diff --git a/frontend/src/data-visualization/components/data-visualization/canvas/Area.vue b/frontend/src/data-visualization/components/data-visualization/canvas/Area.vue new file mode 100644 index 0000000..d425fdb --- /dev/null +++ b/frontend/src/data-visualization/components/data-visualization/canvas/Area.vue @@ -0,0 +1,44 @@ + + + + diff --git a/frontend/src/data-visualization/components/data-visualization/canvas/CanvasCore.vue b/frontend/src/data-visualization/components/data-visualization/canvas/CanvasCore.vue new file mode 100644 index 0000000..1865f98 --- /dev/null +++ b/frontend/src/data-visualization/components/data-visualization/canvas/CanvasCore.vue @@ -0,0 +1,1761 @@ + + + + + diff --git a/frontend/src/data-visualization/components/data-visualization/canvas/ComponentWrapper.vue b/frontend/src/data-visualization/components/data-visualization/canvas/ComponentWrapper.vue new file mode 100644 index 0000000..0f999e7 --- /dev/null +++ b/frontend/src/data-visualization/components/data-visualization/canvas/ComponentWrapper.vue @@ -0,0 +1,478 @@ + + + + + diff --git a/frontend/src/data-visualization/components/data-visualization/canvas/ComposeShow.vue b/frontend/src/data-visualization/components/data-visualization/canvas/ComposeShow.vue new file mode 100644 index 0000000..267a4e1 --- /dev/null +++ b/frontend/src/data-visualization/components/data-visualization/canvas/ComposeShow.vue @@ -0,0 +1,60 @@ + + + + + diff --git a/frontend/src/data-visualization/components/data-visualization/canvas/ContextMenu.vue b/frontend/src/data-visualization/components/data-visualization/canvas/ContextMenu.vue new file mode 100644 index 0000000..0e42cdd --- /dev/null +++ b/frontend/src/data-visualization/components/data-visualization/canvas/ContextMenu.vue @@ -0,0 +1,33 @@ + + + + + diff --git a/frontend/src/data-visualization/components/data-visualization/canvas/ContextMenuAsideDetails.vue b/frontend/src/data-visualization/components/data-visualization/canvas/ContextMenuAsideDetails.vue new file mode 100644 index 0000000..2e8501d --- /dev/null +++ b/frontend/src/data-visualization/components/data-visualization/canvas/ContextMenuAsideDetails.vue @@ -0,0 +1,21 @@ + + + diff --git a/frontend/src/data-visualization/components/data-visualization/canvas/ContextMenuDetails.vue b/frontend/src/data-visualization/components/data-visualization/canvas/ContextMenuDetails.vue new file mode 100644 index 0000000..1ad3dae --- /dev/null +++ b/frontend/src/data-visualization/components/data-visualization/canvas/ContextMenuDetails.vue @@ -0,0 +1,411 @@ + + + + + diff --git a/frontend/src/data-visualization/components/data-visualization/canvas/DePreview.vue b/frontend/src/data-visualization/components/data-visualization/canvas/DePreview.vue new file mode 100644 index 0000000..5f1d24b --- /dev/null +++ b/frontend/src/data-visualization/components/data-visualization/canvas/DePreview.vue @@ -0,0 +1,533 @@ + + + + + diff --git a/frontend/src/data-visualization/components/data-visualization/canvas/DragShadow.vue b/frontend/src/data-visualization/components/data-visualization/canvas/DragShadow.vue new file mode 100644 index 0000000..59ecbb2 --- /dev/null +++ b/frontend/src/data-visualization/components/data-visualization/canvas/DragShadow.vue @@ -0,0 +1,64 @@ + + + + + diff --git a/frontend/src/data-visualization/components/data-visualization/canvas/MarkLine.vue b/frontend/src/data-visualization/components/data-visualization/canvas/MarkLine.vue new file mode 100644 index 0000000..b67239a --- /dev/null +++ b/frontend/src/data-visualization/components/data-visualization/canvas/MarkLine.vue @@ -0,0 +1,261 @@ + + + + diff --git a/frontend/src/data-visualization/components/data-visualization/canvas/PGrid.vue b/frontend/src/data-visualization/components/data-visualization/canvas/PGrid.vue new file mode 100644 index 0000000..86bcce4 --- /dev/null +++ b/frontend/src/data-visualization/components/data-visualization/canvas/PGrid.vue @@ -0,0 +1,48 @@ + + + + + diff --git a/frontend/src/data-visualization/components/data-visualization/canvas/PointShadow.vue b/frontend/src/data-visualization/components/data-visualization/canvas/PointShadow.vue new file mode 100644 index 0000000..65a5e42 --- /dev/null +++ b/frontend/src/data-visualization/components/data-visualization/canvas/PointShadow.vue @@ -0,0 +1,72 @@ + + + + diff --git a/frontend/src/data-visualization/components/data-visualization/canvas/Shape.vue b/frontend/src/data-visualization/components/data-visualization/canvas/Shape.vue new file mode 100644 index 0000000..3f11e84 --- /dev/null +++ b/frontend/src/data-visualization/components/data-visualization/canvas/Shape.vue @@ -0,0 +1,1321 @@ + + + + + diff --git a/frontend/src/data-visualization/components/de-board/Board.vue b/frontend/src/data-visualization/components/de-board/Board.vue new file mode 100644 index 0000000..bf16732 --- /dev/null +++ b/frontend/src/data-visualization/components/de-board/Board.vue @@ -0,0 +1,65 @@ + + + + diff --git a/frontend/src/data-visualization/components/empty-background/index.ts b/frontend/src/data-visualization/components/empty-background/index.ts new file mode 100644 index 0000000..61ce840 --- /dev/null +++ b/frontend/src/data-visualization/components/empty-background/index.ts @@ -0,0 +1,3 @@ +import EmptyBackground from './src/EmptyBackground.vue' + +export { EmptyBackground } diff --git a/frontend/src/data-visualization/components/empty-background/src/EmptyBackground.vue b/frontend/src/data-visualization/components/empty-background/src/EmptyBackground.vue new file mode 100644 index 0000000..2e47e35 --- /dev/null +++ b/frontend/src/data-visualization/components/empty-background/src/EmptyBackground.vue @@ -0,0 +1,66 @@ + + + + + diff --git a/frontend/src/data-visualization/components/icon-custom/index.ts b/frontend/src/data-visualization/components/icon-custom/index.ts new file mode 100644 index 0000000..fb5a732 --- /dev/null +++ b/frontend/src/data-visualization/components/icon-custom/index.ts @@ -0,0 +1,9 @@ +import { h } from 'vue' +import { ElIcon } from 'element-plus-secondary' +import Icon from './src/Icon.vue' +const hIcon = (name: string) => { + return h(ElIcon, null, { + default: () => h(name) + }) +} +export { Icon, hIcon } diff --git a/frontend/src/data-visualization/components/icon-custom/src/Icon.vue b/frontend/src/data-visualization/components/icon-custom/src/Icon.vue new file mode 100644 index 0000000..6319d77 --- /dev/null +++ b/frontend/src/data-visualization/components/icon-custom/src/Icon.vue @@ -0,0 +1,45 @@ + + + + diff --git a/frontend/src/data-visualization/components/icon-group/board-list.ts b/frontend/src/data-visualization/components/icon-group/board-list.ts new file mode 100644 index 0000000..29a6032 --- /dev/null +++ b/frontend/src/data-visualization/components/icon-group/board-list.ts @@ -0,0 +1,22 @@ +import board_1 from '@/assets/svg/board_1.svg' +import board_2 from '@/assets/svg/board_2.svg' +import board_3 from '@/assets/svg/board_3.svg' +import board_4 from '@/assets/svg/board_4.svg' +import board_5 from '@/assets/svg/board_5.svg' +import board_6 from '@/assets/svg/board_6.svg' +import board_7 from '@/assets/svg/board_7.svg' +import board_8 from '@/assets/svg/board_8.svg' +import board_9 from '@/assets/svg/board_9.svg' + +const iconBoardMap = { + board_1: board_1, + board_2: board_2, + board_3: board_3, + board_4: board_4, + board_5: board_5, + board_6: board_6, + board_7: board_7, + board_8: board_8, + board_9: board_9 +} +export { iconBoardMap } diff --git a/frontend/src/data-visualization/components/icon-group/chart-dark-list.ts b/frontend/src/data-visualization/components/icon-group/chart-dark-list.ts new file mode 100644 index 0000000..600db62 --- /dev/null +++ b/frontend/src/data-visualization/components/icon-group/chart-dark-list.ts @@ -0,0 +1,95 @@ +import areaDark from '@/assets/svg/area-dark.svg' +import areaStackDark from '@/assets/svg/area-stack-dark.svg' +import barDark from '@/assets/svg/bar-dark.svg' +import barGroupDark from '@/assets/svg/bar-group-dark.svg' +import barGroupStackDark from '@/assets/svg/bar-group-stack-dark.svg' +import barHorizontalDark from '@/assets/svg/bar-horizontal-dark.svg' +import barRangeDark from '@/assets/svg/bar-range-dark.svg' +import barStackDark from '@/assets/svg/bar-stack-dark.svg' +import barStackHorizontalDark from '@/assets/svg/bar-stack-horizontal-dark.svg' +import bidirectionalBarDark from '@/assets/svg/bidirectional-bar-dark.svg' +import bubbleMapDark from '@/assets/svg/bubble-map-dark.svg' +import chartMixDark from '@/assets/svg/chart-mix-dark.svg' +import chartMixGroupDark from '@/assets/svg/chart-mix-group-dark.svg' +import chartMixStackDark from '@/assets/svg/chart-mix-stack-dark.svg' +import chartMixDualLineDark from '@/assets/svg/chart-mix-dual-line-dark.svg' +import flowMapDark from '@/assets/svg/flow-map-dark.svg' +import funnelDark from '@/assets/svg/funnel-dark.svg' +import gaugeDark from '@/assets/svg/gauge-dark.svg' +import heatMapDark from '@/assets/svg/heat-map-dark.svg' +import indicatorDark from '@/assets/svg/indicator-dark.svg' +import lineDark from '@/assets/svg/line-dark.svg' +import liquidDark from '@/assets/svg/liquid-dark.svg' +import mapDark from '@/assets/svg/map-dark.svg' +import percentageBarStackDark from '@/assets/svg/percentage-bar-stack-dark.svg' +import percentageBarStackHorizontalDark from '@/assets/svg/percentage-bar-stack-horizontal-dark.svg' +import pieDark from '@/assets/svg/pie-dark.svg' +import pieDonutDark from '@/assets/svg/pie-donut-dark.svg' +import pieDonutRoseDark from '@/assets/svg/pie-donut-rose-dark.svg' +import pieRoseDark from '@/assets/svg/pie-rose-dark.svg' +import progressBarDark from '@/assets/svg/progress-bar-dark.svg' +import quadrantDark from '@/assets/svg/quadrant-dark.svg' +import radarDark from '@/assets/svg/radar-dark.svg' +import richTextDark from '@/assets/svg/rich-text-dark.svg' +import sankeyDark from '@/assets/svg/sankey-dark.svg' +import scatterDark from '@/assets/svg/scatter-dark.svg' +import stockLineDark from '@/assets/svg/stock-line-dark.svg' +import symbolicMapDark from '@/assets/svg/symbolic-map-dark.svg' +import tableInfoDark from '@/assets/svg/table-info-dark.svg' +import tableNormalDark from '@/assets/svg/table-normal-dark.svg' +import tablePivotDark from '@/assets/svg/table-pivot-dark.svg' +import treemapDark from '@/assets/svg/treemap-dark.svg' +import waterfallDark from '@/assets/svg/waterfall-dark.svg' +import wordCloudDark from '@/assets/svg/word-cloud-dark.svg' +import tHeatmapDark from '@/assets/svg/t-heatmap-dark.svg' +import circlePackingDark from '@/assets/svg/circle-packing-dark.svg' + +const iconChartDarkMap = { + 'area-dark': areaDark, + 'area-stack-dark': areaStackDark, + 'bar-dark': barDark, + 'bar-group-dark': barGroupDark, + 'bar-group-stack-dark': barGroupStackDark, + 'bar-horizontal-dark': barHorizontalDark, + 'bar-range-dark': barRangeDark, + 'bar-stack-dark': barStackDark, + 'bar-stack-horizontal-dark': barStackHorizontalDark, + 'bidirectional-bar-dark': bidirectionalBarDark, + 'bubble-map-dark': bubbleMapDark, + 'chart-mix-dark': chartMixDark, + 'chart-mix-group-dark': chartMixGroupDark, + 'chart-mix-stack-dark': chartMixStackDark, + 'chart-mix-dual-line-dark': chartMixDualLineDark, + 'flow-map-dark': flowMapDark, + 'funnel-dark': funnelDark, + 'gauge-dark': gaugeDark, + 'heat-map-dark': heatMapDark, + 'indicator-dark': indicatorDark, + 'line-dark': lineDark, + 'liquid-dark': liquidDark, + 'map-dark': mapDark, + 'percentage-bar-stack-dark': percentageBarStackDark, + 'percentage-bar-stack-horizontal-dark': percentageBarStackHorizontalDark, + 'pie-dark': pieDark, + 'pie-donut-dark': pieDonutDark, + 'pie-donut-rose-dark': pieDonutRoseDark, + 'pie-rose-dark': pieRoseDark, + 'progress-bar-dark': progressBarDark, + 'quadrant-dark': quadrantDark, + 'radar-dark': radarDark, + 'rich-text-dark': richTextDark, + 'sankey-dark': sankeyDark, + 'scatter-dark': scatterDark, + 'stock-line-dark': stockLineDark, + 'symbolic-map-dark': symbolicMapDark, + 'table-info-dark': tableInfoDark, + 'table-normal-dark': tableNormalDark, + 'table-pivot-dark': tablePivotDark, + 'treemap-dark': treemapDark, + 'waterfall-dark': waterfallDark, + 'word-cloud-dark': wordCloudDark, + 't-heatmap-dark': tHeatmapDark, + 'circle-packing-dark': circlePackingDark +} + +export { iconChartDarkMap } diff --git a/frontend/src/data-visualization/components/icon-group/chart-list.ts b/frontend/src/data-visualization/components/icon-group/chart-list.ts new file mode 100644 index 0000000..02e6ba9 --- /dev/null +++ b/frontend/src/data-visualization/components/icon-group/chart-list.ts @@ -0,0 +1,101 @@ +import areaStack from '@/assets/svg/area-stack.svg' +import area from '@/assets/svg/area.svg' +import barGroupStack from '@/assets/svg/bar-group-stack.svg' +import barGroup from '@/assets/svg/bar-group.svg' +import barHorizontal from '@/assets/svg/bar-horizontal.svg' +import barRange from '@/assets/svg/bar-range.svg' +import barStackHorizontal from '@/assets/svg/bar-stack-horizontal.svg' +import barStack from '@/assets/svg/bar-stack.svg' +import bar from '@/assets/svg/bar.svg' +import bidirectionalBar from '@/assets/svg/bidirectional-bar.svg' +import bubbleMap from '@/assets/svg/bubble-map.svg' +import chartMixGroup from '@/assets/svg/chart-mix-group.svg' +import chartMixStack from '@/assets/svg/chart-mix-stack.svg' +import chartMixDualLine from '@/assets/svg/chart-mix-dual-line.svg' +import chartMix from '@/assets/svg/chart-mix.svg' +import flowMap from '@/assets/svg/flow-map.svg' +import funnel from '@/assets/svg/funnel.svg' +import gauge from '@/assets/svg/gauge.svg' +import heatMap from '@/assets/svg/heat-map.svg' +import indicator from '@/assets/svg/indicator.svg' +import line from '@/assets/svg/line.svg' +import liquid from '@/assets/svg/liquid.svg' +import map from '@/assets/svg/map.svg' +import percentageBarStackHorizontal from '@/assets/svg/percentage-bar-stack-horizontal.svg' +import percentageBarStack from '@/assets/svg/percentage-bar-stack.svg' +import pieDonutRose from '@/assets/svg/pie-donut-rose.svg' +import pieDonut from '@/assets/svg/pie-donut.svg' +import pieRose from '@/assets/svg/pie-rose.svg' +import pie from '@/assets/svg/pie.svg' +import progressBar from '@/assets/svg/progress-bar.svg' +import quadrant from '@/assets/svg/quadrant.svg' +import radar from '@/assets/svg/radar.svg' +import richText from '@/assets/svg/rich-text.svg' +import sankey from '@/assets/svg/sankey.svg' +import scatter from '@/assets/svg/scatter.svg' +import stockLine from '@/assets/svg/stock-line.svg' +import symbolicMap from '@/assets/svg/symbolic-map.svg' +import tableInfo from '@/assets/svg/table-info.svg' +import tableNormal from '@/assets/svg/table-normal.svg' +import tablePivot from '@/assets/svg/table-pivot.svg' +import treemap from '@/assets/svg/treemap.svg' +import waterfall from '@/assets/svg/waterfall.svg' +import wordCloud from '@/assets/svg/word-cloud.svg' +import tHeatmap from '@/assets/svg/t-heatmap.svg' +import pictureGroup from '@/assets/svg/picture-group.svg' +import filter from '@/assets/svg/filter.svg' +import outerParams from '@/assets/svg/icon_params_setting.svg' +import circlePacking from '@/assets/svg/circle-packing.svg' + +const iconChartMap = { + 'area-stack': areaStack, + area: area, + 'bar-group-stack': barGroupStack, + 'bar-group': barGroup, + 'bar-horizontal': barHorizontal, + 'bar-range': barRange, + 'bar-stack-horizontal': barStackHorizontal, + 'bar-stack': barStack, + bar: bar, + 'bidirectional-bar': bidirectionalBar, + 'bubble-map': bubbleMap, + 'chart-mix-group': chartMixGroup, + 'chart-mix-stack': chartMixStack, + 'chart-mix-dual-line': chartMixDualLine, + 'chart-mix': chartMix, + 'flow-map': flowMap, + funnel: funnel, + gauge: gauge, + 'heat-map': heatMap, + indicator: indicator, + line: line, + liquid: liquid, + map: map, + 'percentage-bar-stack-horizontal': percentageBarStackHorizontal, + 'percentage-bar-stack': percentageBarStack, + 'pie-donut-rose': pieDonutRose, + 'pie-donut': pieDonut, + 'pie-rose': pieRose, + pie: pie, + 'progress-bar': progressBar, + quadrant: quadrant, + radar: radar, + 'rich-text': richText, + sankey: sankey, + scatter: scatter, + 'stock-line': stockLine, + 'symbolic-map': symbolicMap, + 'table-info': tableInfo, + 'table-normal': tableNormal, + 'table-pivot': tablePivot, + treemap: treemap, + waterfall: waterfall, + 'word-cloud': wordCloud, + 't-heatmap': tHeatmap, + 'picture-group': pictureGroup, + filter: filter, + outerParams: outerParams, + 'circle-packing': circlePacking +} + +export { iconChartMap } diff --git a/frontend/src/data-visualization/components/icon-group/datasource-list.ts b/frontend/src/data-visualization/components/icon-group/datasource-list.ts new file mode 100644 index 0000000..2c86934 --- /dev/null +++ b/frontend/src/data-visualization/components/icon-group/datasource-list.ts @@ -0,0 +1,36 @@ +import mysqlDs from '@/assets/svg/mysql-ds.svg' +import oracleDs from '@/assets/svg/oracle-ds.svg' +import sqlServerDs from '@/assets/svg/sqlServer-ds.svg' +import TiDBDs from '@/assets/svg/TiDB-ds.svg' +import impalaDs from '@/assets/svg/impala-ds.svg' +import mariadbDs from '@/assets/svg/mariadb-ds.svg' +import StarRocksDs from '@/assets/svg/StarRocks-ds.svg' +import pgDs from '@/assets/svg/pg-ds.svg' +import mongoDs from '@/assets/svg/mongo-ds.svg' +import ckDs from '@/assets/svg/ck-ds.svg' +import db2Ds from '@/assets/svg/db2-ds.svg' +import redshiftDs from '@/assets/svg/redshift-ds.svg' +import APIDs from '@/assets/svg/API-ds.svg' +import ExcelDs from '@/assets/svg/Excel-ds.svg' +import dorisDs from '@/assets/svg/doris-ds.svg' +import esDs from '@/assets/svg/es-ds.svg' +const iconDatasourceMap = { + mysql: mysqlDs, + oracle: oracleDs, + sqlServer: sqlServerDs, + TiDB: TiDBDs, + impala: impalaDs, + mariadb: mariadbDs, + StarRocks: StarRocksDs, + pg: pgDs, + mongo: mongoDs, + ck: ckDs, + db2: db2Ds, + redshift: redshiftDs, + API: APIDs, + Excel: ExcelDs, + doris: dorisDs, + es: esDs +} + +export { iconDatasourceMap } diff --git a/frontend/src/data-visualization/components/icon-group/field-calculated-list.ts b/frontend/src/data-visualization/components/icon-group/field-calculated-list.ts new file mode 100644 index 0000000..583cd83 --- /dev/null +++ b/frontend/src/data-visualization/components/icon-group/field-calculated-list.ts @@ -0,0 +1,33 @@ +import icon_link_calculated_outlined from '@/assets/svg/icon_link-calculated_outlined.svg' +import icon_link_calculated_outlined_1 from '@/assets/svg/icon_link-calculated_outlined-1.svg' +import icon_text_calculated_outlined from '@/assets/svg/icon_text-calculated_outlined.svg' +import icon_text_calculated_outlined_1 from '@/assets/svg/icon_text-calculated_outlined-1.svg' +import icon_number_calculated_outlined from '@/assets/svg/icon_number-calculated_outlined.svg' +import icon_number_calculated_outlined_1 from '@/assets/svg/icon_number-calculated_outlined-1.svg' +import icon_local_calculated_outlined from '@/assets/svg/icon_local-calculated_outlined.svg' +import icon_local_calculated_outlined_1 from '@/assets/svg/icon_local-calculated_outlined-1.svg' +import icon_calendar_calculated_outlined from '@/assets/svg/icon_calendar-calculated_outlined.svg' +import icon_calendar_calculated_outlined_1 from '@/assets/svg/icon_calendar-calculated_outlined-1.svg' +const iconFieldCalculatedMap = [ + icon_text_calculated_outlined, + icon_calendar_calculated_outlined, + icon_number_calculated_outlined, + icon_number_calculated_outlined, + icon_number_calculated_outlined, + icon_local_calculated_outlined, + 'binary', + icon_link_calculated_outlined +] + +const iconFieldCalculatedQMap = [ + icon_text_calculated_outlined_1, + icon_calendar_calculated_outlined_1, + icon_number_calculated_outlined_1, + icon_number_calculated_outlined_1, + icon_number_calculated_outlined_1, + icon_local_calculated_outlined_1, + 'binary', + icon_link_calculated_outlined_1 +] + +export { iconFieldCalculatedMap, iconFieldCalculatedQMap } diff --git a/frontend/src/data-visualization/components/icon-group/field-list.ts b/frontend/src/data-visualization/components/icon-group/field-list.ts new file mode 100644 index 0000000..784ae35 --- /dev/null +++ b/frontend/src/data-visualization/components/icon-group/field-list.ts @@ -0,0 +1,14 @@ +import field_text from '@/assets/svg/field_text.svg' +import field_time from '@/assets/svg/field_time.svg' +import field_value from '@/assets/svg/field_value.svg' +import field_location from '@/assets/svg/field_location.svg' +import field_url from '@/assets/svg/field_url.svg' +const iconFieldMap = { + text: field_text, + value: field_value, + location: field_location, + time: field_time, + url: field_url +} + +export { iconFieldMap } diff --git a/frontend/src/data-visualization/components/plugin/index.ts b/frontend/src/data-visualization/components/plugin/index.ts new file mode 100644 index 0000000..6e790b2 --- /dev/null +++ b/frontend/src/data-visualization/components/plugin/index.ts @@ -0,0 +1,4 @@ +import XpackComponent from './src/index.vue' +import PluginComponent from './src/PluginComponent.vue' + +export { XpackComponent, PluginComponent } diff --git a/frontend/src/data-visualization/components/plugin/src/PluginComponent.vue b/frontend/src/data-visualization/components/plugin/src/PluginComponent.vue new file mode 100644 index 0000000..1286382 --- /dev/null +++ b/frontend/src/data-visualization/components/plugin/src/PluginComponent.vue @@ -0,0 +1,157 @@ + + + + + diff --git a/frontend/src/data-visualization/components/plugin/src/convert.js b/frontend/src/data-visualization/components/plugin/src/convert.js new file mode 100644 index 0000000..4dbf2b0 --- /dev/null +++ b/frontend/src/data-visualization/components/plugin/src/convert.js @@ -0,0 +1,88 @@ +export const execute = (text, pwd) => { + const te = window.atob(text) + const t = simpleEncode(te, pwd) + const pLen = pwd.length + + const proxyPathBtoa = proxyPath() + const btoaLen = proxyPathBtoa.length + + const prefix = t.substring(0, btoaLen + pLen) + const suffix = t.substring(btoaLen + pLen) + if (validatePrefix(prefix, pwd, proxyPathBtoa)) { + return formatSuffix(suffix, pwd) + } + console.error('please do not do that again!') + return null +} + +export const randomKey = () => { + const m = 8 + const n = 16 + return Math.ceil(Math.random() * (n - m + 1) + m - 1) +} + +const formatSuffix = (suffix, pwd) => { + const reversePwd = strReverse(pwd) + const t = suffix.replace(reversePwd, '') + const pLen = pwd.length + const r = t.substring(0, pLen) + t.substring(pLen + 2) + const encoder = new TextEncoder() + const ar = window.atob(r).split('/') + const bytes = [] + ar.forEach(a => { + const tBytes = encoder.encode(a) + bytes.push(tBytes) + }) + return bytes +} + +export const formatArray = bytesItem => { + if (!(bytesItem instanceof Uint8Array)) { + const bytes = new Uint8Array(bytesItem.length) + for (let index = 0; index < bytesItem.length; index++) { + bytes[index] = bytesItem[index] + } + bytesItem = bytes + } + const decoder = new TextDecoder() + const art = decoder.decode(bytesItem) + bytesItem = 'what is up man ?' + return art +} + +const validatePrefix = (prefix, pwd, proxyPathBtoa) => { + const t = prefix.replace(pwd, '') + return t === proxyPathBtoa +} + +const simpleEncode = (text, key) => { + const encoder = new TextEncoder() + const data = encoder.encode(text) + let tmpc = 0 + const klen = key.length + for (let i = 0; i < data.length; ++i) { + tmpc = data[i] ^ stringToChars(key.charAt(i % klen)) + if (tmpc != 0) { + data[i] = tmpc + } + } + const decoder = new TextDecoder() + return decoder.decode(data) +} + +export function stringToChars(_s) { + _s = _s.replace(/(^\s*)|(\s*$)/g, '') + let _r = '' + for (let i = 0; i < _s.length; i++) { + _r += i == 0 ? _s.charCodeAt(i) : '|' + _s.charCodeAt(i) + } + return _r +} + +const proxyPath = () => { + return 'Zml0MmNsb3VkIGlzIGEgcG90ZW50aWFsIGNvbXBhbnkh' +} + +const strReverse = text => { + return text.split('').reverse().join('') +} diff --git a/frontend/src/data-visualization/components/plugin/src/index.vue b/frontend/src/data-visualization/components/plugin/src/index.vue new file mode 100644 index 0000000..c333a29 --- /dev/null +++ b/frontend/src/data-visualization/components/plugin/src/index.vue @@ -0,0 +1,39 @@ + + + diff --git a/frontend/src/data-visualization/components/plugin/src/nolic.vue b/frontend/src/data-visualization/components/plugin/src/nolic.vue new file mode 100644 index 0000000..a4c3f7b --- /dev/null +++ b/frontend/src/data-visualization/components/plugin/src/nolic.vue @@ -0,0 +1,13 @@ + + + diff --git a/frontend/src/data-visualization/components/visualization/CanvasBaseSetting.vue b/frontend/src/data-visualization/components/visualization/CanvasBaseSetting.vue new file mode 100644 index 0000000..71cd63c --- /dev/null +++ b/frontend/src/data-visualization/components/visualization/CanvasBaseSetting.vue @@ -0,0 +1,145 @@ + + + + + diff --git a/frontend/src/data-visualization/components/visualization/CanvasCacheDialog.vue b/frontend/src/data-visualization/components/visualization/CanvasCacheDialog.vue new file mode 100644 index 0000000..5d9a886 --- /dev/null +++ b/frontend/src/data-visualization/components/visualization/CanvasCacheDialog.vue @@ -0,0 +1,91 @@ + + + + + diff --git a/frontend/src/data-visualization/components/visualization/CanvasOptBar.vue b/frontend/src/data-visualization/components/visualization/CanvasOptBar.vue new file mode 100644 index 0000000..5679bd2 --- /dev/null +++ b/frontend/src/data-visualization/components/visualization/CanvasOptBar.vue @@ -0,0 +1,107 @@ + + + + + diff --git a/frontend/src/data-visualization/components/visualization/ComponentButton.vue b/frontend/src/data-visualization/components/visualization/ComponentButton.vue new file mode 100644 index 0000000..437fa0f --- /dev/null +++ b/frontend/src/data-visualization/components/visualization/ComponentButton.vue @@ -0,0 +1,90 @@ + + + + diff --git a/frontend/src/data-visualization/components/visualization/ComponentButtonLabel.vue b/frontend/src/data-visualization/components/visualization/ComponentButtonLabel.vue new file mode 100644 index 0000000..a768a47 --- /dev/null +++ b/frontend/src/data-visualization/components/visualization/ComponentButtonLabel.vue @@ -0,0 +1,79 @@ + + + + diff --git a/frontend/src/data-visualization/components/visualization/ComponentEditBar.vue b/frontend/src/data-visualization/components/visualization/ComponentEditBar.vue new file mode 100644 index 0000000..7ecdf12 --- /dev/null +++ b/frontend/src/data-visualization/components/visualization/ComponentEditBar.vue @@ -0,0 +1,730 @@ + + + + + diff --git a/frontend/src/data-visualization/components/visualization/ComponentGroup.vue b/frontend/src/data-visualization/components/visualization/ComponentGroup.vue new file mode 100644 index 0000000..7b2d7c8 --- /dev/null +++ b/frontend/src/data-visualization/components/visualization/ComponentGroup.vue @@ -0,0 +1,49 @@ + + + + diff --git a/frontend/src/data-visualization/components/visualization/ComponentSelector.vue b/frontend/src/data-visualization/components/visualization/ComponentSelector.vue new file mode 100644 index 0000000..29b0ffc --- /dev/null +++ b/frontend/src/data-visualization/components/visualization/ComponentSelector.vue @@ -0,0 +1,43 @@ + + + + + diff --git a/frontend/src/data-visualization/components/visualization/DatasetParamsComponent.vue b/frontend/src/data-visualization/components/visualization/DatasetParamsComponent.vue new file mode 100644 index 0000000..92b6ffb --- /dev/null +++ b/frontend/src/data-visualization/components/visualization/DatasetParamsComponent.vue @@ -0,0 +1,144 @@ + + + + + diff --git a/frontend/src/data-visualization/components/visualization/DatasetParamsSettingDialog.vue b/frontend/src/data-visualization/components/visualization/DatasetParamsSettingDialog.vue new file mode 100644 index 0000000..1d32ada --- /dev/null +++ b/frontend/src/data-visualization/components/visualization/DatasetParamsSettingDialog.vue @@ -0,0 +1,110 @@ + + + + + diff --git a/frontend/src/data-visualization/components/visualization/DePreviewPopDialog.vue b/frontend/src/data-visualization/components/visualization/DePreviewPopDialog.vue new file mode 100644 index 0000000..c6389ab --- /dev/null +++ b/frontend/src/data-visualization/components/visualization/DePreviewPopDialog.vue @@ -0,0 +1,93 @@ +