adata-ui 2.1.40-beta.10 → 2.1.40-beta.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (139) hide show
  1. package/.claude/settings.local.json +19 -0
  2. package/assets/styles/index.scss +67 -5
  3. package/components/elements/a-select-row/ASelectRowV2.vue +8 -8
  4. package/components/elements/a-select-row/index.vue +3 -5
  5. package/components/elements/accordion/AAccordion.vue +5 -3
  6. package/components/elements/accordion/AAccordionGroup/AAccordionGroup.vue +3 -3
  7. package/components/elements/alert/AAlert.vue +34 -47
  8. package/components/elements/bg-block/ABgBlock.vue +1 -1
  9. package/components/elements/button/AButton.vue +3 -3
  10. package/components/elements/button/AButtonV2.vue +7 -5
  11. package/components/elements/button-login/index.vue +1 -1
  12. package/components/elements/chip-wrapper/AChipWrapper.vue +1 -1
  13. package/components/elements/chips/AChips.vue +2 -2
  14. package/components/elements/digit-badge/ADigitBadge.vue +21 -19
  15. package/components/elements/feature-description/AFeatureDescription.vue +1 -1
  16. package/components/elements/leave-note/ALeaveNote.vue +1 -1
  17. package/components/elements/pagination/APagination.vue +7 -7
  18. package/components/elements/segmented/ASegmentedV2.vue +103 -10
  19. package/components/elements/select/ASelect.vue +4 -4
  20. package/components/elements/select/ASelectMobile.vue +2 -2
  21. package/components/elements/select/ASelectV2.vue +10 -11
  22. package/components/elements/select/ui/select-button.vue +1 -1
  23. package/components/elements/status-badge/AStatusBadge.vue +22 -19
  24. package/components/elements/status-badge-v2/StatusBadgeV2.vue +1 -3
  25. package/components/elements/table/ATable.vue +1 -1
  26. package/components/elements/table/table.config.ts +2 -2
  27. package/components/elements/tree-select/ATreeSelect.vue +97 -113
  28. package/components/elements/tree-select/TreeService.ts +142 -207
  29. package/components/elements/tree-select/components/ATreeSelectNode.vue +104 -0
  30. package/components/elements/tree-select/types.ts +40 -11
  31. package/components/elements/tree-select/utils.ts +30 -0
  32. package/components/elements/tree-select-modal/ATreeSelectModal.vue +217 -0
  33. package/components/features/color-mode/AColorMode.client.vue +1 -1
  34. package/components/features/dropdown/ADropdownV2.vue +1 -2
  35. package/components/features/lang-switcher/lang-switcher.vue +9 -4
  36. package/components/features/payment/banner/BasicPlusLimitBanner.vue +3 -3
  37. package/components/features/payment/banner/PaymentBanner.vue +3 -3
  38. package/components/features/payment/banner/UpSellBanner.vue +3 -3
  39. package/components/features/payment/process/PaymentKaspiQrSidePanel.vue +43 -27
  40. package/components/features/payment/process/PaymentKaspiRedirectSidePanel.vue +34 -23
  41. package/components/features/payment/process/PaymentMethodSidePanel.vue +61 -49
  42. package/components/features/payment/process/PaymentProcess.vue +6 -6
  43. package/components/features/payment/process/PaymentTopUpSidePanel.vue +44 -63
  44. package/components/features/pk-mobile-services/APkMobileServices.vue +1 -1
  45. package/components/features//321/201hange-version/AChangeVersion.vue +2 -2
  46. package/components/forms/checkbox/ACheckbox.vue +1 -1
  47. package/components/forms/checkbox/ACheckboxV2.vue +5 -5
  48. package/components/forms/input/AInputV2.vue +4 -4
  49. package/components/forms/input/date/AInputDate.vue +2 -2
  50. package/components/forms/input/password/AInputPassword.vue +8 -2
  51. package/components/forms/input/standard/AInputStandard.vue +3 -3
  52. package/components/forms/input/textarea/ATextarea.vue +2 -2
  53. package/components/forms/toggle/AToggle.vue +2 -3
  54. package/components/forms/toggle/AToggleV2.vue +3 -3
  55. package/components/modals/AnotherDeviceModal.vue +1 -1
  56. package/components/modals/ContactsMobileModel.vue +1 -1
  57. package/components/modals/ContentNavigationModal.vue +77 -333
  58. package/components/modals/Insufficient-funds-modal.vue +1 -1
  59. package/components/modals/PaymentMethodModal.vue +1 -1
  60. package/components/modals/id/IdBanner.vue +3 -3
  61. package/components/modals/id/IdRecoveryModal.vue +1 -1
  62. package/components/navigation/bottom-navigation/ABottomNavigation.vue +1 -1
  63. package/components/navigation/breadcrumbs/ABreadcrumbs.vue +106 -45
  64. package/components/navigation/breadcrumbs/types.ts +3 -0
  65. package/components/navigation/footer/AFooter.vue +39 -40
  66. package/components/navigation/footer/ui/a-footer-accordion.vue +9 -9
  67. package/components/navigation/header/AHeader.vue +13 -19
  68. package/components/navigation/header/AlmatyContacts.vue +78 -78
  69. package/components/navigation/header/CardGallery.vue +4 -4
  70. package/components/navigation/header/HeaderUsage.vue +4 -6
  71. package/components/navigation/header/ListItem.vue +2 -2
  72. package/components/navigation/header/NavCard.vue +1 -1
  73. package/components/navigation/header/NavList.vue +2 -2
  74. package/components/navigation/header/NotificationsMenu.vue +2 -3
  75. package/components/navigation/header/ProductMenu.vue +7 -7
  76. package/components/navigation/header/ProfileMenu.vue +26 -35
  77. package/components/navigation/header/SystemNotification.vue +1 -3
  78. package/components/navigation/pill-tabs/APillTabs.vue +2 -2
  79. package/components/navigation/pill-tabs/APillTabsV2.vue +22 -6
  80. package/components/overlays/drawer/ADrawerV2.vue +335 -0
  81. package/components/overlays/modal/AModal.vue +4 -4
  82. package/components/overlays/modal/AModalV2.vue +7 -4
  83. package/components/overlays/side-panel/ASidePanel.vue +6 -6
  84. package/components/overlays/sideover/ASlideover.vue +6 -6
  85. package/components/overlays/tooltip/ATooltip.vue +1 -1
  86. package/components/overlays/tooltip/ATooltipV2.vue +2 -12
  87. package/components/transitions/ATransitionHeight.vue +1 -1
  88. package/composables/useHeaderNavigationLinks.ts +100 -94
  89. package/icons/archive.vue +16 -0
  90. package/icons/arrow/arrows-in.vue +11 -0
  91. package/icons/arrow/arrows-out.vue +11 -0
  92. package/icons/arrow/arrows-resize-in.vue +38 -0
  93. package/icons/arrow/arrows-resize-out.vue +17 -0
  94. package/icons/bot.vue +52 -0
  95. package/icons/clock-time.vue +24 -0
  96. package/icons/compare-outlined.vue +8 -0
  97. package/icons/dots-horizontal.vue +31 -0
  98. package/icons/download-line.vue +13 -0
  99. package/icons/egov.vue +41 -0
  100. package/icons/elicense.vue +38 -0
  101. package/icons/favourite-bookmark-outline.vue +17 -0
  102. package/icons/file-pen.vue +31 -0
  103. package/icons/file-stack.vue +31 -0
  104. package/icons/file-types/excel.vue +131 -0
  105. package/icons/file-types/html.vue +13 -0
  106. package/icons/file-types/jpeg.vue +16 -0
  107. package/icons/file-types/pdf.vue +11 -0
  108. package/icons/file-types/png.vue +11 -0
  109. package/icons/file-types/rar.vue +11 -0
  110. package/icons/file-types/word.vue +50 -0
  111. package/icons/file-types/zip.vue +11 -0
  112. package/icons/git-compare.vue +38 -0
  113. package/icons/graduation-cap.vue +31 -0
  114. package/icons/graph-loading.vue +34 -0
  115. package/icons/help-question-circle.vue +26 -0
  116. package/icons/in-row-type.vue +46 -0
  117. package/icons/in-table-type.vue +29 -0
  118. package/icons/message-dotted.vue +30 -0
  119. package/icons/notification-error.vue +17 -0
  120. package/icons/person.vue +22 -0
  121. package/icons/settings.vue +26 -0
  122. package/icons/shield-alert.vue +31 -0
  123. package/icons/socials/facebook-color.vue +16 -0
  124. package/icons/socials/globe-color.vue +16 -0
  125. package/icons/socials/instagram-color.vue +46 -0
  126. package/icons/socials/linkedin-color.vue +14 -0
  127. package/icons/socials/telegram-color.vue +16 -0
  128. package/icons/socials/tiktok-color.vue +14 -0
  129. package/icons/socials/vk-color.vue +16 -0
  130. package/icons/socials/youtube-color.vue +16 -0
  131. package/icons/view-eye-open.vue +13 -0
  132. package/lang/en.ts +1 -0
  133. package/lang/kk.ts +1 -0
  134. package/lang/ru.ts +1 -0
  135. package/package.json +1 -1
  136. package/plugins/toast.client.ts +38 -55
  137. package/tailwind.config.ts +147 -116
  138. package/utils/twMerge.ts +34 -0
  139. package/components/elements/tree-select/components/tree-select-nodes.vue +0 -91
@@ -0,0 +1,104 @@
1
+ <script lang="ts" setup>
2
+ import type { TreeViewNode } from '#adata-ui/components/elements/tree-select/types'
3
+
4
+ interface Props {
5
+ node: TreeViewNode
6
+ toggleExpand: (node: TreeViewNode) => void | Promise<void>
7
+ toggleCheckbox: (id: string | number, checked: boolean) => void
8
+ type: 'checkbox' | 'select'
9
+ disabled: boolean
10
+ }
11
+
12
+ const props = defineProps<Props>()
13
+
14
+ // explicit slot type breaks the recursive self-reference inference (TS7022)
15
+ defineSlots<{ label?: (props: { node: TreeViewNode }) => unknown }>()
16
+
17
+ const isDisabled = computed(() => props.disabled && props.node.state === 'unchecked')
18
+
19
+ function onSelectToggle() {
20
+ if (isDisabled.value) return
21
+ props.toggleCheckbox(props.node.id, props.node.state !== 'checked')
22
+ }
23
+ </script>
24
+
25
+ <template>
26
+ <li
27
+ :style="{ paddingLeft: `${node.level * 20}px` }"
28
+ :class="[{ 'bg-[#2C3E500D] dark:bg-[#E3E5E80D]': node.state === 'checked' && type === 'select' }]"
29
+ >
30
+ <div
31
+ v-if="!node.hidden"
32
+ class="flex items-center gap-1 p-2"
33
+ :class="{ 'bg-deepblue-50 dark:bg-gray-200/5': isDisabled }"
34
+ >
35
+ <div class="flex min-w-4 items-center">
36
+ <a-icon-loader-circle
37
+ v-if="node.loading"
38
+ class="size-4 animate-spin text-gray-400 dark:text-gray-500"
39
+ />
40
+ <a-icon-chevron-down
41
+ v-else-if="node.expandable"
42
+ width="16"
43
+ height="16"
44
+ class="cursor-pointer transition-all"
45
+ :class="{ '-rotate-90': !node.expanded }"
46
+ @click="toggleExpand(node)"
47
+ />
48
+ </div>
49
+
50
+ <a-checkbox-v2
51
+ v-if="type === 'checkbox'"
52
+ size="lg"
53
+ side="left"
54
+ class="flex w-full items-center justify-between text-left"
55
+ :model-value="node.state === 'checked'"
56
+ :intermediate="node.state === 'indeterminate'"
57
+ :disabled="isDisabled"
58
+ :name="`${node.id}`"
59
+ @update:model-value="(checked) => toggleCheckbox(node.id, checked as boolean)"
60
+ >
61
+ <slot name="label" :node="node">
62
+ <span class="text-body-md-strong" v-html="node.text" />
63
+ </slot>
64
+ </a-checkbox-v2>
65
+
66
+ <div
67
+ v-else
68
+ role="button"
69
+ tabindex="0"
70
+ class="flex w-full cursor-pointer items-center justify-between gap-4"
71
+ :class="{ 'pointer-events-none opacity-60': isDisabled }"
72
+ @click="onSelectToggle"
73
+ @keydown.enter.prevent="onSelectToggle"
74
+ @keydown.space.prevent="onSelectToggle"
75
+ >
76
+ <slot name="label" :node="node">
77
+ <span :class="{ 'font-semibold': node.level === 0 }" v-html="node.text" />
78
+ </slot>
79
+ <a-icon-check
80
+ v-if="node.state === 'checked'"
81
+ class="min-w-4 text-blue-700 dark:text-blue-400"
82
+ />
83
+ </div>
84
+ </div>
85
+
86
+ <a-transition-height>
87
+ <ul v-if="node.expandable && node.expanded">
88
+ <a-tree-select-node
89
+ v-for="child in node.children"
90
+ :key="child.id"
91
+ :node="child"
92
+ :toggle-expand="toggleExpand"
93
+ :toggle-checkbox="toggleCheckbox"
94
+ :type="type"
95
+ :disabled="disabled"
96
+ >
97
+ <template v-if="$slots.label" #label="slotProps">
98
+ <slot name="label" v-bind="slotProps" />
99
+ </template>
100
+ </a-tree-select-node>
101
+ </ul>
102
+ </a-transition-height>
103
+ </li>
104
+ </template>
@@ -1,3 +1,43 @@
1
+ export type TreeNodeState = 'checked' | 'unchecked' | 'indeterminate'
2
+ export type TreeNodeStateEditable = 'checked' | 'unchecked'
3
+
4
+ export type TreeData = {
5
+ id?: number | string
6
+ name?: string
7
+ children?: TreeData[]
8
+ [key: string]: unknown
9
+ }
10
+
11
+ export interface TreeViewNode {
12
+ id: string | number
13
+ name: string
14
+ text: string
15
+ baseText: string
16
+ level: number
17
+ state: TreeNodeState
18
+ expandable: boolean
19
+ expanded: boolean
20
+ hidden: boolean
21
+ loaded: boolean
22
+ loading: boolean
23
+ parent: TreeViewNode | null
24
+ children: TreeViewNode[]
25
+ raw: TreeData
26
+ }
27
+
28
+ export interface TreeKeyConfig {
29
+ idKey?: string
30
+ nameKey?: string
31
+ childrenKey?: string
32
+ hasChildrenKey?: string
33
+ }
34
+
35
+ export interface TreeServiceOptions extends TreeKeyConfig {
36
+ withoutId?: boolean
37
+ lazy?: boolean
38
+ loadChildren?: (node: TreeViewNode) => Promise<TreeData[]> | TreeData[]
39
+ }
40
+
1
41
  export interface TreeNode {
2
42
  id: string | number
3
43
  name: string
@@ -19,16 +59,5 @@ export interface TreeNestedNode {
19
59
  expandableClosed: boolean
20
60
  text: string
21
61
  hidden: boolean
22
- // parent: TreeNestedNode | null;
23
62
  child: TreeNestedNode[]
24
63
  }
25
-
26
- export type TreeData = {
27
- // [key: string]: null | string[] | TreeData;
28
- id: number | string
29
- name: string
30
- children?: TreeData[]
31
- }
32
-
33
- export type TreeNodeState = 'checked' | 'unchecked' | 'indeterminate'
34
- export type TreeNodeStateEditable = 'checked' | 'unchecked'
@@ -0,0 +1,30 @@
1
+ import type { TreeData, TreeKeyConfig } from '#adata-ui/components/elements/tree-select/types'
2
+
3
+ export interface SelectedItem {
4
+ id: string | number
5
+ name: string
6
+ }
7
+
8
+ export function getSelectedItems(
9
+ options: TreeData[],
10
+ ids: (string | number)[],
11
+ keys: TreeKeyConfig = {},
12
+ ): SelectedItem[] {
13
+ const { idKey = 'id', nameKey = 'name', childrenKey = 'children' } = keys
14
+ const wanted = new Set(ids ?? [])
15
+ const result: SelectedItem[] = []
16
+
17
+ const walk = (items: TreeData[]): void => {
18
+ items.forEach((item) => {
19
+ const id = item[idKey] as string | number
20
+ if (wanted.has(id)) {
21
+ result.push({ id, name: String(item[nameKey] ?? '') })
22
+ }
23
+ const children = item[childrenKey] as TreeData[] | undefined
24
+ if (children?.length) walk(children)
25
+ })
26
+ }
27
+
28
+ walk(options ?? [])
29
+ return result
30
+ }
@@ -0,0 +1,217 @@
1
+ <script lang="ts" setup>
2
+ import type { TreeData, TreeViewNode } from '#adata-ui/components/elements/tree-select/types'
3
+ import { getSelectedItems } from '#adata-ui/components/elements/tree-select/utils'
4
+ import AIconSearch from '#adata-ui/icons/search.vue'
5
+
6
+ type ModalSize = 'sm' | 'md' | 'lg' | 'xl' | 'container' | 'fullscreen'
7
+
8
+ interface Props {
9
+ options: TreeData[]
10
+ label?: string
11
+ title?: string
12
+ searchLabel?: string
13
+ type?: 'checkbox' | 'select'
14
+ onlyOne?: boolean
15
+ withoutId?: boolean
16
+ loading?: boolean
17
+ disabled?: boolean
18
+ asyncSearch?: (keyword: string) => TreeData[] | Promise<TreeData[]>
19
+ filteringLabel?: string
20
+ applyLabel?: string
21
+ resetLabel?: string
22
+ btnClass?: string
23
+ size?: ModalSize
24
+ width?: string
25
+ bodyHeight?: string
26
+ idKey?: string
27
+ nameKey?: string
28
+ childrenKey?: string
29
+ hasChildrenKey?: string
30
+ lazy?: boolean
31
+ loadChildren?: (node: TreeViewNode) => TreeData[] | Promise<TreeData[]>
32
+ }
33
+
34
+ const props = withDefaults(defineProps<Props>(), {
35
+ label: '',
36
+ title: '',
37
+ searchLabel: '',
38
+ type: 'checkbox',
39
+ onlyOne: false,
40
+ withoutId: false,
41
+ loading: false,
42
+ disabled: false,
43
+ filteringLabel: '',
44
+ applyLabel: 'Применить',
45
+ resetLabel: 'Сбросить',
46
+ btnClass: '',
47
+ size: 'lg',
48
+ bodyHeight: '50vh',
49
+ idKey: 'id',
50
+ nameKey: 'name',
51
+ childrenKey: 'children',
52
+ lazy: false,
53
+ })
54
+
55
+ const emit = defineEmits<{
56
+ (e: 'submit'): void
57
+ (e: 'cancel'): void
58
+ }>()
59
+
60
+ const selected = defineModel<(string | number)[]>({ default: () => [] })
61
+ const search = defineModel<string>('search', { default: '' })
62
+ const isOpen = defineModel<boolean>('open', { default: false })
63
+
64
+ const treeRef = ref<{ reset: () => void } | null>(null)
65
+ const isSearch = ref(false)
66
+
67
+ const count = computed(() => selected.value?.length ?? 0)
68
+
69
+ const dataForDisplay = computed(() =>
70
+ getSelectedItems(props.options, selected.value ?? [], {
71
+ idKey: props.idKey,
72
+ nameKey: props.nameKey,
73
+ childrenKey: props.childrenKey,
74
+ }),
75
+ )
76
+
77
+ const treeAreaStyle = computed(() =>
78
+ props.bodyHeight && props.bodyHeight !== 'auto' ? { height: props.bodyHeight } : undefined,
79
+ )
80
+
81
+ function openModal() {
82
+ if (props.disabled) return
83
+ isOpen.value = true
84
+ }
85
+
86
+ function onApply() {
87
+ isOpen.value = false
88
+ search.value = ''
89
+ nextTick(() => emit('submit'))
90
+ }
91
+
92
+ function onReset() {
93
+ treeRef.value?.reset()
94
+ selected.value = []
95
+ search.value = ''
96
+ emit('cancel')
97
+ }
98
+
99
+ watch(
100
+ () => props.loading,
101
+ (loading) => {
102
+ if (!loading) isSearch.value = !!search.value.length
103
+ },
104
+ )
105
+
106
+ defineExpose({ open: openModal, close: () => (isOpen.value = false) })
107
+ </script>
108
+
109
+ <template>
110
+ <div class="tree-select-modal w-full">
111
+ <slot
112
+ name="trigger"
113
+ :open="openModal"
114
+ :selected="dataForDisplay"
115
+ :count="count"
116
+ >
117
+ <a-select-row-v2
118
+ v-model:is-open="isOpen"
119
+ :label="label"
120
+ :selected-items="dataForDisplay"
121
+ :disabled="disabled"
122
+ :btn-class="btnClass"
123
+ :clearable="false"
124
+ :deletable="false"
125
+ />
126
+ </slot>
127
+
128
+ <a-modal-v2
129
+ v-model="isOpen"
130
+ :title="title"
131
+ :size="size"
132
+ :width="width"
133
+ >
134
+ <template #header>
135
+ <slot name="header" :title="title">
136
+ <h2 class="text-h5 text-gray-900 dark:text-gray-100">
137
+ {{ title }}
138
+ </h2>
139
+ </slot>
140
+ </template>
141
+
142
+ <div class="flex flex-col">
143
+ <div class="sticky top-0 z-[1] flex flex-col gap-4 bg-white px-5 pb-4 pt-4 dark:bg-gray-900">
144
+ <a-input-v2
145
+ v-model="search"
146
+ type="search"
147
+ :label="searchLabel"
148
+ :start-icon="AIconSearch"
149
+ clearable
150
+ />
151
+
152
+ <p v-if="filteringLabel" class="text-body-sm text-gray-500 dark:text-gray-400">
153
+ {{ filteringLabel }}
154
+ </p>
155
+ </div>
156
+
157
+ <div
158
+ class="tree-select-modal__body px-5 pb-4"
159
+ :class="{ 'overflow-auto': treeAreaStyle }"
160
+ :style="treeAreaStyle"
161
+ >
162
+ <a-tree-select
163
+ v-if="!loading"
164
+ ref="treeRef"
165
+ v-model="selected"
166
+ :options="options"
167
+ :type="type"
168
+ :only-one="onlyOne"
169
+ :is-search="isSearch"
170
+ :search-text="search"
171
+ :async-search="asyncSearch"
172
+ :without-id="withoutId"
173
+ :id-key="idKey"
174
+ :name-key="nameKey"
175
+ :children-key="childrenKey"
176
+ :has-children-key="hasChildrenKey"
177
+ :lazy="lazy"
178
+ :load-children="loadChildren"
179
+ >
180
+ <template v-if="$slots.label" #label="slotProps">
181
+ <slot name="label" v-bind="slotProps" />
182
+ </template>
183
+ </a-tree-select>
184
+
185
+ <div v-else class="flex items-center justify-center py-10 text-gray-400 dark:text-gray-500">
186
+ <a-icon-loader-circle class="size-6 animate-spin" />
187
+ </div>
188
+ </div>
189
+ </div>
190
+
191
+ <template #footer="{ close }">
192
+ <slot
193
+ name="footer"
194
+ :reset="onReset"
195
+ :apply="onApply"
196
+ :close="close"
197
+ :count="count"
198
+ >
199
+ <div class="flex justify-end gap-2">
200
+ <a-button-v2
201
+ view="outline"
202
+ color="gray"
203
+ @click="onReset"
204
+ >
205
+ {{ resetLabel }}
206
+ </a-button-v2>
207
+ <a-button-v2 @click="onApply">
208
+ {{ applyLabel }}<template v-if="count">
209
+ ({{ count }})
210
+ </template>
211
+ </a-button-v2>
212
+ </div>
213
+ </slot>
214
+ </template>
215
+ </a-modal-v2>
216
+ </div>
217
+ </template>
@@ -37,7 +37,7 @@ useEventListener(window, 'storage', (event: StorageEvent) => {
37
37
  <client-only>
38
38
  <button
39
39
  type="button"
40
- class="relative inline-flex size-8 items-center justify-center overflow-hidden rounded-xl text-deepblue-900/80 transition-colors duration-150 hover:bg-deepblue-900/5 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-blue-500/50 focus-visible:ring-offset-1 dark:text-gray-200 dark:hover:bg-white/10 dark:focus-visible:ring-offset-gray-900"
40
+ class="relative inline-flex size-8 items-center justify-center overflow-hidden rounded-lg text-deepblue-900/80 transition-colors duration-150 hover:bg-deepblue-900/5 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-blue-500/50 focus-visible:ring-offset-1 dark:text-gray-200 dark:hover:bg-white/10 dark:focus-visible:ring-offset-gray-900"
41
41
  :aria-label="isDark ? 'Switch to light mode' : 'Switch to dark mode'"
42
42
  data-test-id="header-switch-theme-toggle"
43
43
  @click="toggle"
@@ -24,7 +24,6 @@ const { x, y, strategy, update, placement: resolvedPlacement } = useFloating(ref
24
24
  middleware: computed(() => [offsetMiddleware(props.offset), flip(), shift({ padding: 8 })]),
25
25
  })
26
26
 
27
- // Anchor the grow/shrink animation to the trigger so the panel feels attached.
28
27
  const transformOrigin = computed(() => {
29
28
  const [side, align] = resolvedPlacement.value.split('-')
30
29
  const vertical = side === 'top' ? 'bottom' : 'top'
@@ -85,7 +84,7 @@ onKeyStroke('Escape', () => {
85
84
  <div
86
85
  v-if="isOpen"
87
86
  ref="floating"
88
- class="z-[60] overflow-hidden rounded-xl shadow-lg shadow-gray-900/10 dark:shadow-black/30"
87
+ class="z-[60] overflow-hidden rounded-lg shadow-lg shadow-gray-900/10 dark:shadow-black/30"
89
88
  :style="{
90
89
  position: strategy,
91
90
  left: x != null ? `${x}px` : '',
@@ -66,7 +66,7 @@ function onSelect(loc: LocaleItem) {
66
66
  <button
67
67
  ref="reference"
68
68
  type="button"
69
- class="inline-flex size-8 items-center justify-center rounded-xl text-xs font-semibold text-gray-900 transition-colors duration-150 hover:bg-deepblue-900/5 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-blue-500/50 focus-visible:ring-offset-1 dark:text-gray-100 dark:hover:bg-white/10 dark:focus-visible:ring-offset-gray-900"
69
+ class="inline-flex size-8 items-center justify-center rounded-lg text-body-sm font-semibold text-gray-900 transition-colors duration-150 hover:bg-deepblue-900/5 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-blue-500/50 focus-visible:ring-offset-1 dark:text-gray-100 dark:hover:bg-white/10 dark:focus-visible:ring-offset-gray-900"
70
70
  :class="[
71
71
  isOpen
72
72
  ? 'bg-blue-50 text-blue-700 ring-2 ring-blue-500/20 dark:bg-blue-900/40 dark:text-blue-300'
@@ -91,7 +91,7 @@ function onSelect(loc: LocaleItem) {
91
91
  <div
92
92
  v-if="isOpen"
93
93
  ref="floating"
94
- class="z-[10000] w-fit rounded-xl border border-gray-200 bg-white shadow-lg shadow-gray-900/10 dark:border-gray-700 dark:bg-gray-900 dark:shadow-black/30"
94
+ class="z-[10000] w-fit rounded-lg border border-gray-200 bg-white shadow-lg shadow-gray-900/10 dark:border-gray-700 dark:bg-gray-900 dark:shadow-black/30"
95
95
  :style="{
96
96
  position: strategy,
97
97
  left: x != null ? `${x}px` : '',
@@ -99,11 +99,16 @@ function onSelect(loc: LocaleItem) {
99
99
  }"
100
100
  >
101
101
  <ul class="flex flex-col gap-1 p-1.5" role="listbox">
102
- <li v-for="loc in locales" :key="localeCode(loc)" role="option" :aria-selected="localeCode(loc) === locale">
102
+ <li
103
+ v-for="loc in locales"
104
+ :key="localeCode(loc)"
105
+ role="option"
106
+ :aria-selected="localeCode(loc) === locale"
107
+ >
103
108
  <nuxt-link
104
109
  :data-test-id="`header-switch-${localeCode(loc)}-language-button${testIdSuffix}`"
105
110
  :to="switchLocalePath(localeCode(loc))"
106
- class="flex w-full items-center justify-between gap-3 rounded-lg px-3 py-2 text-sm transition-colors duration-100"
111
+ class="flex w-full items-center justify-between gap-3 rounded-md px-3 py-2 text-body-md transition-colors duration-100"
107
112
  :class="[
108
113
  localeCode(loc) === locale
109
114
  ? 'bg-blue-50 font-medium text-blue-700 dark:bg-blue-900/30 dark:text-blue-400'
@@ -51,15 +51,15 @@ function onUpdate() {
51
51
  </script>
52
52
 
53
53
  <template>
54
- <div class="gradient flex justify-between rounded-lg p-4 ring-1 ring-inset ring-blue-700/80 dark:bg-gray-800">
54
+ <div class="gradient flex justify-between rounded-md p-4 ring-1 ring-inset ring-blue-700/80 dark:bg-gray-800">
55
55
  <div>
56
- <p class="mb-2 font-semibold">
56
+ <p class="mb-2 text-h5">
57
57
  {{ t('modals.id.banners.basicPlusLimit.title') }}
58
58
  </p>
59
59
  <i18n-t
60
60
  keypath="modals.id.banners.basicPlusLimit.subtitle"
61
61
  tag="p"
62
- class="text-sm text-gray-600 dark:text-gray-200"
62
+ class="text-body-md text-gray-600 dark:text-gray-200"
63
63
  >
64
64
  <template #topUp>
65
65
  <button
@@ -56,15 +56,15 @@ function onBuy() {
56
56
  </script>
57
57
 
58
58
  <template>
59
- <div class="gradient flex justify-between rounded-lg p-4 ring-1 ring-inset ring-blue-700/80 dark:bg-gray-800">
59
+ <div class="gradient flex justify-between rounded-md p-4 ring-1 ring-inset ring-blue-700/80 dark:bg-gray-800">
60
60
  <div>
61
- <p class="mb-2 font-semibold">
61
+ <p class="mb-2 text-h5">
62
62
  {{ t('payment.banner.title') }}
63
63
  </p>
64
64
  <i18n-t
65
65
  keypath="payment.banner.subtitle"
66
66
  tag="p"
67
- class="text-sm text-gray-600 dark:text-gray-200"
67
+ class="text-body-md text-gray-600 dark:text-gray-200"
68
68
  >
69
69
  <template #tariffs>
70
70
  <nuxt-link
@@ -72,16 +72,16 @@ function onBuy() {
72
72
  </script>
73
73
 
74
74
  <template>
75
- <div class="relative gradient flex justify-between rounded-lg p-4 ring-1 ring-inset ring-blue-700/80 dark:bg-gray-800">
75
+ <div class="relative gradient flex justify-between rounded-md p-4 ring-1 ring-inset ring-blue-700/80 dark:bg-gray-800">
76
76
  <div class="flex flex-col gap-3">
77
- <p class="font-semibold">
77
+ <p class="text-h5">
78
78
  {{ t(`payment.upsell.${code}.title`) }}
79
79
  </p>
80
80
 
81
81
  <i18n-t
82
82
  :keypath="`payment.upsell.${code}.description`"
83
83
  tag="p"
84
- class="text-sm whitespace-pre-line"
84
+ class="text-body-md whitespace-pre-line"
85
85
  >
86
86
  <template #highlight>
87
87
  <span class="font-semibold">{{ t(`payment.upsell.${code}.highlight`) }}</span>
@@ -1,6 +1,6 @@
1
1
  <script setup lang="ts">
2
- import { toCanvas } from 'qrcode'
3
2
  import { removeTrailingSlash } from '#adata-ui/components/utils/removeTrailingSlash'
3
+ import { toCanvas } from 'qrcode'
4
4
 
5
5
  const props = defineProps<{
6
6
  requestUrl: string
@@ -9,7 +9,7 @@ const props = defineProps<{
9
9
 
10
10
  const emit = defineEmits<{
11
11
  (e: 'back', type: 'kaspi'): void
12
- (e: 'updateUserRate'): void
12
+ (e: 'updateUserRate'): void
13
13
  }>()
14
14
 
15
15
  const isOpen = defineModel({ default: false })
@@ -74,11 +74,10 @@ watch(isOpen, async (value) => {
74
74
  margin: 0,
75
75
  color: {
76
76
  dark: colorMode.value === 'dark' ? '#FFFFFF' : '#000000', // квадраты
77
- light: colorMode.value === 'dark' ? '#000000' : '#FFFFFF' // фон
78
- }
77
+ light: colorMode.value === 'dark' ? '#000000' : '#FFFFFF', // фон
78
+ },
79
79
  },
80
80
  (error) => {
81
-
82
81
  if (error) {
83
82
  console.error(error)
84
83
  return
@@ -99,7 +98,8 @@ watch(isOpen, async (value) => {
99
98
 
100
99
  ctx.drawImage(logo, x, y, size, size)
101
100
  }
102
- })
101
+ },
102
+ )
103
103
 
104
104
  intervalId = setInterval(() => {
105
105
  if (paymentSuccess.value && intervalId) {
@@ -110,7 +110,6 @@ watch(isOpen, async (value) => {
110
110
  checkPayment()
111
111
  }, 1000)
112
112
  })
113
-
114
113
  </script>
115
114
 
116
115
  <template>
@@ -120,42 +119,59 @@ watch(isOpen, async (value) => {
120
119
  >
121
120
  <template #header>
122
121
  <div class="flex items-center gap-2">
123
- <button @click="onBack">
122
+ <button
123
+ type="button"
124
+ class="rounded-md p-1 transition-colors hover:bg-gray-100 dark:hover:bg-white/[0.06]"
125
+ @click="onBack"
126
+ >
124
127
  <a-icon-chevron-left class="size-6" />
125
128
  </button>
126
- <p class="text-xl font-semibold">
129
+ <p class="text-xl font-semibold text-deepblue-900 dark:text-gray-100">
127
130
  {{ t('payment.kaspi.title') }}
128
131
  </p>
129
132
  </div>
130
133
  </template>
131
134
 
132
135
  <div class="flex flex-col gap-6">
133
- <div class="flex flex-col items-center text-center text-black dark:text-white">
134
- <p class="mb-4 font-semibold text-sm">
135
- {{ t('payment.kaspi.description') }}
136
- </p>
137
-
138
- <div class="flex gap-3 items-center">
139
- <a-icon-kaspi-qr class="size-16" />
140
- <span class="font-bold text-[44px]">
141
- {{ t('payment.kaspi.qr') }}
136
+ <p class="text-center text-sm font-medium text-gray-600 dark:text-gray-300">
137
+ {{ t('payment.kaspi.description') }}
138
+ </p>
139
+
140
+ <div class="flex flex-col items-center gap-5 rounded-xl border border-gray-200 bg-white p-6 dark:border-gray-700 dark:bg-gray-900">
141
+ <div class="flex items-center gap-3">
142
+ <a-icon-kaspi-qr class="size-14" />
143
+ <span class="text-[40px] font-bold leading-none text-deepblue-900 dark:text-white">
144
+ {{ t('payment.kaspi.qr') }}
142
145
  </span>
143
146
  </div>
144
147
 
145
- <p class="mt-5 font-bold text-2xl">{{ t('payment.kaspi.scan') }}</p>
148
+ <p class="text-center text-xl font-bold text-deepblue-900 dark:text-white">
149
+ {{ t('payment.kaspi.scan') }}
150
+ </p>
146
151
 
147
- <canvas class="mt-5" id="kaspiQr"></canvas>
152
+ <canvas
153
+ id="kaspiQr"
154
+ class="rounded-md"
155
+ />
148
156
 
149
- <p class="mt-10 text-lg">{{ t('payment.kaspi.adata') }}</p>
157
+ <p class="text-center text-base text-gray-600 dark:text-gray-300">
158
+ {{ t('payment.kaspi.adata') }}
159
+ </p>
150
160
  </div>
161
+ </div>
151
162
 
152
- <a-button @click="onBack" view="outline">
163
+ <template #footer>
164
+ <a-button-v2
165
+ view="outline"
166
+ color="gray"
167
+ size="lg"
168
+ block
169
+ @click="onBack"
170
+ >
153
171
  {{ t('payment.kaspi.changeMethod') }}
154
- </a-button>
155
- </div>
172
+ </a-button-v2>
173
+ </template>
156
174
  </a-side-panel>
157
175
  </template>
158
176
 
159
- <style scoped>
160
-
161
- </style>
177
+ <style scoped></style>