adata-ui 2.1.40 → 2.1.41-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/-error.vue +2 -2
- package/.playground/app.vue +13 -13
- package/.playground/nuxt.config.ts +1 -1
- package/CLAUDE.md +63 -0
- package/assets/styles/main.css +12 -0
- package/assets/styles/theme.css +583 -0
- package/assets/styles/ui.css +247 -0
- package/components/elements/a-select-row/ASelectRowV2.vue +13 -17
- package/components/elements/a-select-row/index.vue +13 -12
- package/components/elements/accordion/AAccordion.vue +2 -2
- package/components/elements/accordion/AAccordionGroup/AAccordionGroup.vue +1 -1
- package/components/elements/accordion/AAccordionGroup/ui.config.ts +4 -4
- package/components/elements/accordion/ui.config.ts +4 -4
- package/components/elements/alert/AAlert.vue +5 -5
- package/components/elements/bg-block/ABgBlock.vue +1 -1
- package/components/elements/button/AButton.vue +48 -45
- package/components/elements/button/AButtonV2.vue +74 -30
- package/components/elements/button-login/index.vue +2 -1
- package/components/elements/carousel/config.ui.ts +2 -2
- package/components/elements/chip-wrapper/AChipWrapper.vue +4 -3
- package/components/elements/chips/AChips.vue +4 -3
- package/components/elements/companies/AOurClients.vue +1 -1
- package/components/elements/count-up/ACountUp.vue +54 -0
- package/components/elements/curve-block/ACurveBlock.vue +15 -48
- package/components/elements/curve-block-v2/ACurveBlockV2.vue +60 -25
- package/components/elements/digit-badge/ADigitBadge.vue +17 -16
- package/components/elements/empty-box/empty-box-V2.vue +92 -0
- package/components/elements/error-template/index.vue +99 -31
- package/components/elements/feature-description/AFeatureDescription.vue +8 -8
- package/components/elements/illustrations/noAccess.vue +1 -1
- package/components/elements/infinite-carousel/AInfiniteCarousel.vue +44 -16
- package/components/elements/leave-note/ALeaveNote.vue +2 -2
- package/components/elements/pagination/APagination.vue +8 -8
- package/components/elements/section-heading/ASectionHeading.vue +35 -0
- package/components/elements/segmented/ASegmentedV2.vue +24 -21
- package/components/elements/select/ASelect.vue +28 -27
- package/components/elements/select/ASelectMobile.vue +5 -5
- package/components/elements/select/ASelectV2.vue +20 -28
- package/components/elements/select/ui/select-button.vue +8 -8
- package/components/elements/select/ui/select-list.vue +2 -2
- package/components/elements/show-more/AShowMore.vue +2 -2
- package/components/elements/show-more/AShowMoreV2.vue +3 -3
- package/components/elements/skeleton/ASkeleton.vue +1 -1
- package/components/elements/slider/ASlider.vue +3 -2
- package/components/elements/slider/ASliderV2.vue +182 -0
- package/components/elements/star-rating/AStarRating.vue +2 -2
- package/components/elements/status-badge/AStatusBadge.vue +40 -36
- package/components/elements/step-slider/AStepSliderColCard.vue +77 -39
- package/components/elements/step-slider/AStepSliderColNumber.vue +74 -53
- package/components/elements/table/table.config.ts +8 -8
- package/components/elements/tree-select/components/ATreeSelectNode.vue +4 -4
- package/components/elements/tree-select-mobile/components/ATreeSelectNodesMobile.vue +3 -3
- package/components/elements/tree-select-modal/ATreeSelectModal.vue +4 -4
- package/components/features/color-mode/AColorMode.client.vue +2 -24
- package/components/features/dropdown/ADropdownV2.vue +1 -1
- package/components/features/lang-switcher/lang-switcher.vue +6 -6
- package/components/features/payment/banner/BasicPlusLimitBanner.vue +3 -23
- package/components/features/payment/banner/PaymentBanner.vue +3 -23
- package/components/features/payment/banner/UpSellBanner.vue +1 -21
- package/components/features/payment/process/PaymentKaspiQrSidePanel.vue +8 -7
- package/components/features/payment/process/PaymentKaspiRedirectSidePanel.vue +5 -5
- package/components/features/payment/process/PaymentMethodSidePanel.vue +12 -12
- package/components/features/payment/process/PaymentTopUpSidePanel.vue +6 -6
- package/components/features/pk-mobile-services/APkMobileServices.vue +14 -43
- package/components/features//321/201hange-version/AChangeVersion.vue +1 -1
- package/components/forms/checkbox/ACheckbox.vue +8 -8
- package/components/forms/checkbox/ACheckboxV2.vue +8 -8
- package/components/forms/feedback-form/FeedbackForm.vue +8 -8
- package/components/forms/feedback-form/FeedbackFormV2.vue +9 -8
- package/components/forms/input/AInputV2.vue +39 -25
- package/components/forms/input/button/AInputButton.vue +1 -1
- package/components/forms/input/date/AInputDate.vue +13 -9
- package/components/forms/input/password/AInputPassword.vue +1 -1
- package/components/forms/input/standard/AInputStandard.vue +23 -14
- package/components/forms/input/textarea/ATextarea.vue +15 -11
- package/components/forms/input/textarea/ATextareaV2.vue +18 -13
- package/components/forms/radio-button/ARadioButton.vue +4 -4
- package/components/forms/request-demo/ARequestDemo.vue +5 -5
- package/components/forms/toggle/AToggle.vue +8 -7
- package/components/forms/toggle/AToggleV2.vue +7 -6
- package/components/modals/AConfirmationEmail.vue +3 -3
- package/components/modals/AboutTariffModal.vue +10 -9
- package/components/modals/AnotherDeviceModal.vue +11 -10
- package/components/modals/ApplicationAcceptedModal.vue +3 -2
- package/components/modals/ConnectingTariffModal.vue +1 -1
- package/components/modals/ContactsMobileModel.vue +5 -5
- package/components/modals/ContentNavigationModal.vue +8 -7
- package/components/modals/Insufficient-funds-modal.vue +4 -4
- package/components/modals/LimitReachedModal.vue +18 -7
- package/components/modals/NoAccessModal.vue +7 -3
- package/components/modals/PaymentMethodModal.vue +4 -4
- package/components/modals/RedirectsBanksModal.vue +4 -4
- package/components/modals/ReplenishModal.vue +2 -2
- package/components/modals/ReportBugConfirmModal.vue +2 -2
- package/components/modals/ReportBugModal.vue +2 -2
- package/components/modals/Resend.vue +4 -4
- package/components/modals/SubmitApplicationModal.vue +1 -5
- package/components/modals/id/AuthModal.vue +27 -47
- package/components/modals/id/IdAutoLogoutModal.vue +23 -24
- package/components/modals/id/IdBanner.vue +4 -24
- package/components/modals/id/IdConfirmAccountOtpModal.vue +5 -4
- package/components/modals/id/IdConfirmSuccessfulModal.vue +3 -3
- package/components/modals/id/IdLoginModal.vue +8 -8
- package/components/modals/id/IdModals.vue +1 -3
- package/components/modals/id/IdNewPasswordModal.vue +3 -3
- package/components/modals/id/IdOtpInput.vue +3 -3
- package/components/modals/id/IdPasswordSuccessfulModal.vue +3 -3
- package/components/modals/id/IdRecoveryModal.vue +3 -3
- package/components/modals/id/IdRegistrationModal.vue +4 -4
- package/components/modals/id/IdResetPasswordOtpModal.vue +5 -4
- package/components/modals/id/IdTwoFactorModal.vue +3 -2
- package/components/navigation/bottom-navigation/ABottomNavigation.vue +7 -7
- package/components/navigation/breadcrumbs/ABreadcrumbs.vue +4 -4
- package/components/navigation/footer/AFooter.vue +2 -2
- package/components/navigation/footer/ui/a-footer-accordion.vue +1 -1
- package/components/navigation/header/AHeader.vue +11 -11
- package/components/navigation/header/AlmatyContacts.vue +7 -7
- package/components/navigation/header/AstanaContacts.vue +4 -4
- package/components/navigation/header/CardGallery.vue +8 -7
- package/components/navigation/header/ContactMenu.vue +1 -1
- package/components/navigation/header/HeaderLink.vue +5 -5
- package/components/navigation/header/HeaderUsage.vue +14 -14
- package/components/navigation/header/ListItem.vue +4 -3
- package/components/navigation/header/NavCard.vue +6 -5
- package/components/navigation/header/NavList.vue +9 -8
- package/components/navigation/header/NotificationsMenu.vue +10 -10
- package/components/navigation/header/ProductMenu.vue +10 -9
- package/components/navigation/header/ProfileMenu.vue +13 -12
- package/components/navigation/header/SystemNotification.vue +4 -4
- package/components/navigation/line-tabs/ALineTabs.vue +10 -9
- package/components/navigation/pill-tabs/APillTabs.vue +18 -16
- package/components/navigation/pill-tabs/APillTabsV2.vue +40 -25
- package/components/navigation/side-navigation/ASideNavigation.vue +3 -3
- package/components/overlays/drawer/ADrawerV2.vue +12 -11
- package/components/overlays/modal/AModal.vue +4 -4
- package/components/overlays/modal/AModalV2.vue +17 -13
- package/components/overlays/side-panel/ASidePanel.vue +7 -7
- package/components/overlays/sideover/ASlideover.vue +4 -4
- package/components/overlays/tooltip/ATooltip.vue +3 -2
- package/components/overlays/tooltip/ATooltipV2.vue +2 -2
- package/composables/highlight.ts +2 -1
- package/eslint.config.mjs +14 -1
- package/icons/arrow/arrow-left.vue +14 -0
- package/icons/arrow-currency-gray.vue +1 -1
- package/icons/arrow-currency-green.vue +1 -1
- package/icons/arrow-currency-red.vue +1 -1
- package/icons/avatar.vue +1 -1
- package/icons/bar-chart-3.vue +3 -0
- package/icons/book-open.vue +3 -0
- package/icons/bookmark/bookmark-filled.vue +1 -0
- package/icons/braces.vue +3 -0
- package/icons/check/check-outline.vue +3 -0
- package/icons/chevron/chevron-down-outline.vue +3 -0
- package/icons/clipboard-list.vue +3 -0
- package/icons/clock-outline.vue +3 -0
- package/icons/company-egov-small.vue +1 -1
- package/icons/database.vue +3 -0
- package/icons/download-outline.vue +3 -0
- package/icons/download.vue +1 -1
- package/icons/egov.vue +1 -1
- package/icons/elicense.vue +1 -1
- package/icons/file-json.vue +3 -0
- package/icons/file-search.vue +3 -0
- package/icons/file-text.vue +3 -0
- package/icons/flask-conical.vue +3 -0
- package/icons/folder-open.vue +3 -0
- package/icons/gift-outline.vue +3 -0
- package/icons/globe-2.vue +3 -0
- package/icons/graph-loading.vue +2 -2
- package/icons/hand/hand-thumb-up-filled.vue +1 -1
- package/icons/home.vue +14 -0
- package/icons/invoice.vue +1 -0
- package/icons/key-round.vue +3 -0
- package/icons/letter/letter-a.vue +4 -2
- package/icons/letter/letter-b.vue +2 -2
- package/icons/letter/letter-c.vue +2 -2
- package/icons/letter/letter-d.vue +2 -2
- package/icons/letter/letter-e.vue +2 -2
- package/icons/logo.vue +1 -1
- package/icons/main-filter.vue +1 -1
- package/icons/menu.vue +4 -4
- package/icons/message/message.vue +1 -1
- package/icons/messages-square.vue +3 -0
- package/icons/more.vue +1 -1
- package/icons/payment/payment-card.vue +2 -2
- package/icons/radio/radio-check.vue +1 -1
- package/icons/robot-outline.vue +3 -0
- package/icons/scales/scale-outline.vue +3 -0
- package/icons/search-outline.vue +3 -0
- package/icons/send.vue +3 -0
- package/icons/star/star-filled.vue +1 -0
- package/icons/star/star-half-filled.vue +1 -0
- package/icons/sun.vue +1 -0
- package/icons/terminal.vue +3 -0
- package/icons/toasts/warning-triangle-toast.vue +1 -0
- package/icons/triangle-alert.vue +3 -0
- package/icons/users-outline.vue +3 -0
- package/icons/webhook.vue +3 -0
- package/icons/x-outline.vue +3 -0
- package/icons/yandex.vue +2 -1
- package/illustrations/address-location.vue +2 -2
- package/illustrations/award-badge.vue +105 -0
- package/illustrations/ball-with-chain.vue +7 -7
- package/illustrations/bill.vue +5 -5
- package/illustrations/buildings.vue +4 -4
- package/illustrations/calendar.vue +11 -11
- package/illustrations/chains.vue +12 -12
- package/illustrations/coin-percent.vue +3 -3
- package/illustrations/coins-stack.vue +4 -4
- package/illustrations/delete-dark.vue +1 -0
- package/illustrations/delete.vue +1 -0
- package/illustrations/doc-with-stamp.vue +5 -5
- package/illustrations/document.vue +3 -3
- package/illustrations/door.vue +79 -68
- package/illustrations/empty-badge-check.vue +20 -0
- package/illustrations/empty-ban.vue +18 -0
- package/illustrations/empty-box.vue +5 -5
- package/illustrations/empty-filter.vue +20 -0
- package/illustrations/empty-inbox.vue +19 -0
- package/illustrations/empty-scale.vue +22 -0
- package/illustrations/empty-search-x.vue +21 -0
- package/illustrations/empty-shopping-cart.vue +21 -0
- package/illustrations/empty-users-round.vue +20 -0
- package/illustrations/empty-wallet.vue +121 -155
- package/illustrations/graph-in-coin.vue +2 -2
- package/illustrations/hammer.vue +5 -5
- package/illustrations/hand-cash.vue +1 -1
- package/illustrations/info.vue +49 -36
- package/illustrations/mail-active.vue +86 -0
- package/illustrations/mail.vue +4 -4
- package/illustrations/no-access.vue +92 -0
- package/illustrations/ok.vue +86 -58
- package/illustrations/people-group.vue +1 -1
- package/illustrations/person-with-phone.vue +5 -5
- package/illustrations/person.vue +3 -3
- package/illustrations/phone-check.vue +104 -84
- package/illustrations/phone-payment-method.vue +1 -1
- package/illustrations/shield-user.vue +94 -0
- package/illustrations/stop-hand.vue +78 -71
- package/illustrations/stop-sign.vue +1 -1
- package/illustrations/suit.vue +93 -107
- package/illustrations/suitcase.vue +6 -6
- package/illustrations/terminal.vue +94 -228
- package/illustrations/trash-can.vue +60 -102
- package/illustrations/turn-on-tariff.vue +2 -2
- package/illustrations/two-persons.vue +2 -2
- package/lang/en.ts +25 -29
- package/lang/kk.ts +24 -28
- package/lang/ru.ts +24 -29
- package/nuxt.config.ts +11 -4
- package/package.json +7 -12
- package/assets/styles/index.scss +0 -166
- package/assets/styles/modules/_base.scss +0 -5
- package/assets/styles/modules/_typography.scss +0 -152
- package/components/elements/error-template/types.ts +0 -23
- package/illustrations/terminal-dark.vue +0 -48
- package/tailwind.config.ts +0 -194
- package/tests/AButton.test.ts +0 -81
|
@@ -126,6 +126,7 @@ defineExpose({ next, prev, goTo, index, count })
|
|
|
126
126
|
class="absolute bottom-0 left-1/2 z-10 flex -translate-x-1/2 gap-2"
|
|
127
127
|
role="tablist"
|
|
128
128
|
>
|
|
129
|
+
<!-- пастельный бренд-трек: семантического токена нет, dark-компенсация вручную -->
|
|
129
130
|
<button
|
|
130
131
|
v-for="(_, i) in count"
|
|
131
132
|
:key="i"
|
|
@@ -133,14 +134,14 @@ defineExpose({ next, prev, goTo, index, count })
|
|
|
133
134
|
role="tab"
|
|
134
135
|
:aria-selected="index === i"
|
|
135
136
|
:aria-label="`Слайд ${i + 1}`"
|
|
136
|
-
class="relative h-[6px] cursor-pointer overflow-hidden rounded-full bg-
|
|
137
|
+
class="relative h-[6px] cursor-pointer overflow-hidden rounded-full bg-brand-200 dark:bg-brand-500/30 transition-all duration-300"
|
|
137
138
|
:class="index === i ? 'w-[30px]' : 'w-[20px]'"
|
|
138
139
|
@click="goTo(i)"
|
|
139
140
|
>
|
|
140
141
|
<span
|
|
141
142
|
v-if="index === i && shouldRun"
|
|
142
143
|
:key="tick"
|
|
143
|
-
class="a-slider-progress absolute inset-0 rounded-full bg-
|
|
144
|
+
class="a-slider-progress absolute inset-0 rounded-full bg-brand"
|
|
144
145
|
:style="timingStyle"
|
|
145
146
|
/>
|
|
146
147
|
</button>
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
<script setup lang="ts" generic="T">
|
|
2
|
+
import { useElementHover } from '@vueuse/core'
|
|
3
|
+
import { computed, ref, watch } from 'vue'
|
|
4
|
+
|
|
5
|
+
interface Props {
|
|
6
|
+
/** Slides. The slider only uses their count and the current one. */
|
|
7
|
+
slides: readonly T[]
|
|
8
|
+
/** Time each slide stays active, in ms. Also the progress-bar duration. */
|
|
9
|
+
interval?: number
|
|
10
|
+
/** Advance automatically. */
|
|
11
|
+
autoplay?: boolean
|
|
12
|
+
/** Freeze autoplay while the cursor is over the slider. */
|
|
13
|
+
pauseOnHover?: boolean
|
|
14
|
+
/** Render the built-in progress indicators. */
|
|
15
|
+
indicators?: boolean
|
|
16
|
+
/**
|
|
17
|
+
* CSS transition name for the built-in slide swap, e.g. `"fade"`.
|
|
18
|
+
* The slider only passes the name through to `<transition>` — the CSS
|
|
19
|
+
* itself stays with the slide. Without it slides swap instantly.
|
|
20
|
+
* Ignored when the default slot is used: taking over the rendering means
|
|
21
|
+
* taking over the transition too.
|
|
22
|
+
*/
|
|
23
|
+
transition?: string
|
|
24
|
+
/** Transition mode, as on Vue's `<transition>`. */
|
|
25
|
+
transitionMode?: 'out-in' | 'in-out' | 'default'
|
|
26
|
+
/** Explicit transition duration in ms, as on Vue's `<transition>`. */
|
|
27
|
+
transitionDuration?: number | { enter: number, leave: number }
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const props = withDefaults(defineProps<Props>(), {
|
|
31
|
+
interval: 5000,
|
|
32
|
+
autoplay: true,
|
|
33
|
+
pauseOnHover: true,
|
|
34
|
+
indicators: true,
|
|
35
|
+
transition: undefined,
|
|
36
|
+
transitionMode: 'out-in',
|
|
37
|
+
transitionDuration: undefined,
|
|
38
|
+
})
|
|
39
|
+
|
|
40
|
+
/** Active slide index — usable as `v-model:index`. */
|
|
41
|
+
const index = defineModel<number>('index', { default: 0 })
|
|
42
|
+
|
|
43
|
+
const root = ref<HTMLElement>()
|
|
44
|
+
const count = computed(() => props.slides.length)
|
|
45
|
+
|
|
46
|
+
/* ---- navigation (always wraps around) ---- */
|
|
47
|
+
function goTo(to: number) {
|
|
48
|
+
if (count.value === 0)
|
|
49
|
+
return
|
|
50
|
+
index.value = ((to % count.value) + count.value) % count.value
|
|
51
|
+
}
|
|
52
|
+
function next() {
|
|
53
|
+
goTo(index.value + 1)
|
|
54
|
+
}
|
|
55
|
+
function prev() {
|
|
56
|
+
goTo(index.value - 1)
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/* ---- autoplay ----
|
|
60
|
+
* Timing is driven by an invisible "clock" element's CSS animation.
|
|
61
|
+
* `animation-play-state: paused` freezes both the clock and the visible
|
|
62
|
+
* progress bar in one place, so the pause stays perfectly in sync and
|
|
63
|
+
* resumes from where it stopped — no JS timers to keep aligned. */
|
|
64
|
+
|
|
65
|
+
// Bumping this key remounts the clock/progress element, restarting the timing.
|
|
66
|
+
// Watched rather than bumped inside `goTo`, so writing to `v-model:index`
|
|
67
|
+
// from the outside restarts the timing too.
|
|
68
|
+
const tick = ref(0)
|
|
69
|
+
watch(index, () => {
|
|
70
|
+
tick.value++
|
|
71
|
+
})
|
|
72
|
+
|
|
73
|
+
// The slide list may have shrunk under the current index.
|
|
74
|
+
watch(count, (n) => {
|
|
75
|
+
if (index.value >= n)
|
|
76
|
+
goTo(0)
|
|
77
|
+
})
|
|
78
|
+
|
|
79
|
+
const hovered = useElementHover(root)
|
|
80
|
+
|
|
81
|
+
const running = computed(() => props.autoplay && count.value > 1)
|
|
82
|
+
const timingStyle = computed(() => ({
|
|
83
|
+
animationDuration: `${props.interval}ms`,
|
|
84
|
+
animationPlayState: props.pauseOnHover && hovered.value ? 'paused' : 'running',
|
|
85
|
+
}))
|
|
86
|
+
|
|
87
|
+
defineExpose({ next, prev, goTo })
|
|
88
|
+
</script>
|
|
89
|
+
|
|
90
|
+
<template>
|
|
91
|
+
<div
|
|
92
|
+
ref="root"
|
|
93
|
+
class="relative overflow-hidden"
|
|
94
|
+
role="group"
|
|
95
|
+
aria-roledescription="carousel"
|
|
96
|
+
>
|
|
97
|
+
<!-- Invisible clock: fires `next` when a slide's time elapses. -->
|
|
98
|
+
<div
|
|
99
|
+
v-if="running"
|
|
100
|
+
:key="tick"
|
|
101
|
+
class="a-slider-clock"
|
|
102
|
+
:style="timingStyle"
|
|
103
|
+
@animationend="next"
|
|
104
|
+
/>
|
|
105
|
+
|
|
106
|
+
<!-- Rendered once, for the active slide. Markup and animations are the
|
|
107
|
+
consumer's job — the slider only says which slide is active.
|
|
108
|
+
Without a slot the slider still works on its own: it renders the
|
|
109
|
+
active slide as-is, optionally wrapped in a named transition. -->
|
|
110
|
+
<slot
|
|
111
|
+
v-if="$slots.default"
|
|
112
|
+
:slide="slides[index]"
|
|
113
|
+
:index="index"
|
|
114
|
+
:count="count"
|
|
115
|
+
:go-to="goTo"
|
|
116
|
+
/>
|
|
117
|
+
|
|
118
|
+
<!-- БЕЗ `appear` — это принципиально. Под SSR `<transition appear>`
|
|
119
|
+
сериализует содержимое в литеральный `<template>`: браузер такой узел
|
|
120
|
+
не рендерит, слайдер стоит пустым до гидратации, а сама гидратация
|
|
121
|
+
падает с mismatch (проверено на Nuxt 3.18 / Vue 3.5).
|
|
122
|
+
Вход первого слайда всё равно задаётся обычной CSS-анимацией на
|
|
123
|
+
монтировании — `appear` при SSR-гидратации Vue и так не проигрывает. -->
|
|
124
|
+
<transition
|
|
125
|
+
v-else-if="transition && slides[index]"
|
|
126
|
+
:name="transition"
|
|
127
|
+
:mode="transitionMode"
|
|
128
|
+
:duration="transitionDuration"
|
|
129
|
+
>
|
|
130
|
+
<component :is="slides[index]" :key="index" />
|
|
131
|
+
</transition>
|
|
132
|
+
|
|
133
|
+
<component
|
|
134
|
+
:is="slides[index]"
|
|
135
|
+
v-else-if="slides[index]"
|
|
136
|
+
:key="index"
|
|
137
|
+
/>
|
|
138
|
+
|
|
139
|
+
<div
|
|
140
|
+
v-if="indicators && count > 1"
|
|
141
|
+
class="absolute bottom-0 left-1/2 z-10 flex -translate-x-1/2 gap-2"
|
|
142
|
+
>
|
|
143
|
+
<!-- пастельный бренд-трек: семантического токена нет, dark-компенсация вручную -->
|
|
144
|
+
<button
|
|
145
|
+
v-for="(_, i) in count"
|
|
146
|
+
:key="i"
|
|
147
|
+
type="button"
|
|
148
|
+
:aria-label="`Слайд ${i + 1}`"
|
|
149
|
+
:aria-current="index === i"
|
|
150
|
+
class="relative h-[6px] cursor-pointer overflow-hidden rounded-full bg-brand-200 transition-all duration-300 dark:bg-brand-500/30"
|
|
151
|
+
:class="index === i ? 'w-[30px]' : 'w-[20px]'"
|
|
152
|
+
@click="goTo(i)"
|
|
153
|
+
>
|
|
154
|
+
<span
|
|
155
|
+
v-if="index === i && running"
|
|
156
|
+
:key="tick"
|
|
157
|
+
class="a-slider-progress absolute inset-0 rounded-full bg-brand"
|
|
158
|
+
:style="timingStyle"
|
|
159
|
+
/>
|
|
160
|
+
</button>
|
|
161
|
+
</div>
|
|
162
|
+
</div>
|
|
163
|
+
</template>
|
|
164
|
+
|
|
165
|
+
<style scoped>
|
|
166
|
+
.a-slider-clock {
|
|
167
|
+
position: absolute;
|
|
168
|
+
height: 1px;
|
|
169
|
+
opacity: 0;
|
|
170
|
+
pointer-events: none;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
.a-slider-clock,
|
|
174
|
+
.a-slider-progress {
|
|
175
|
+
animation: a-slider-run linear forwards;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
@keyframes a-slider-run {
|
|
179
|
+
from { width: 0; }
|
|
180
|
+
to { width: 100%; }
|
|
181
|
+
}
|
|
182
|
+
</style>
|
|
@@ -114,7 +114,7 @@ createStars(shouldRound.value)
|
|
|
114
114
|
<div class="w-full flex items-center gap-2">
|
|
115
115
|
<span
|
|
116
116
|
v-if="ratingPlacement === 'left' && !hideValue"
|
|
117
|
-
class="text-
|
|
117
|
+
class="text-quaternary mt-px"
|
|
118
118
|
:style="{fontSize: `${fontSize}px`}"
|
|
119
119
|
>
|
|
120
120
|
{{ modelValue }}
|
|
@@ -136,7 +136,7 @@ createStars(shouldRound.value)
|
|
|
136
136
|
</div>
|
|
137
137
|
<span
|
|
138
138
|
v-if="ratingPlacement === 'right' && !hideValue"
|
|
139
|
-
class="text-
|
|
139
|
+
class="text-body-md text-quaternary mt-px"
|
|
140
140
|
>
|
|
141
141
|
{{ modelValue }}
|
|
142
142
|
</span>
|
|
@@ -34,37 +34,41 @@ const props = withDefaults(defineProps<Props>(), {
|
|
|
34
34
|
|
|
35
35
|
const typeSwitchValues: ViewType = {
|
|
36
36
|
default: {
|
|
37
|
-
primary: 'bg-
|
|
38
|
-
success: 'bg-
|
|
39
|
-
danger: 'bg-
|
|
40
|
-
warning: 'bg-
|
|
41
|
-
|
|
37
|
+
primary: 'bg-brand text-white border-transparent',
|
|
38
|
+
success: 'bg-success text-white border-transparent',
|
|
39
|
+
danger: 'bg-danger text-white border-transparent',
|
|
40
|
+
warning: 'bg-warning text-white border-transparent',
|
|
41
|
+
/* solid-серый бейдж: токена нет, константный примитив */
|
|
42
|
+
gray: 'bg-gray-600 text-white border-transparent',
|
|
42
43
|
},
|
|
43
44
|
inverted: {
|
|
44
|
-
primary: 'bg-
|
|
45
|
-
success: 'bg-
|
|
46
|
-
danger: 'bg-
|
|
47
|
-
warning: 'bg-
|
|
48
|
-
gray: 'bg-
|
|
45
|
+
primary: 'bg-brand-subtle text-brand border-transparent',
|
|
46
|
+
success: 'bg-success-subtle text-success border-transparent',
|
|
47
|
+
danger: 'bg-danger-subtle text-danger border-transparent',
|
|
48
|
+
warning: 'bg-warning-subtle text-warning border-transparent',
|
|
49
|
+
gray: 'bg-muted text-quaternary border-transparent',
|
|
49
50
|
},
|
|
51
|
+
/* бордеры: для brand/green/yellow пастельных токенов нет — примитивы осознанно */
|
|
50
52
|
transparent: {
|
|
51
|
-
primary: 'bg-
|
|
52
|
-
success: 'bg-
|
|
53
|
-
danger: 'bg-
|
|
54
|
-
warning: 'bg-
|
|
55
|
-
gray: 'bg-
|
|
53
|
+
primary: 'bg-main border-brand-200 text-brand dark:bg-transparent',
|
|
54
|
+
success: 'bg-main border-green-300 text-success dark:bg-transparent',
|
|
55
|
+
danger: 'bg-main border-red text-danger dark:bg-transparent',
|
|
56
|
+
warning: 'bg-main border-yellow-300 text-warning dark:bg-transparent',
|
|
57
|
+
gray: 'bg-main border-strong text-quaternary dark:bg-transparent',
|
|
56
58
|
},
|
|
59
|
+
/* тинты и пастельные бордеры subtle-вью: токенов нет — примитивы + dark:-пары осознанно */
|
|
57
60
|
subtle: {
|
|
58
|
-
primary: 'bg-
|
|
59
|
-
success: 'bg-
|
|
60
|
-
danger: 'bg-
|
|
61
|
-
warning: 'bg-
|
|
62
|
-
gray: 'bg-
|
|
61
|
+
primary: 'bg-brand-500/5 border-brand-200 text-brand dark:bg-brand-500/10 dark:border-brand-500/40',
|
|
62
|
+
success: 'bg-green-600/5 border-green-300 text-success dark:bg-green-500/10 dark:border-green-600/40',
|
|
63
|
+
danger: 'bg-red-600/5 border-red text-danger dark:bg-red-500/10 dark:border-red-600/40',
|
|
64
|
+
warning: 'bg-amber-600/5 border-yellow-300 text-warning dark:bg-yellow-500/10 dark:border-amber-600/40',
|
|
65
|
+
gray: 'bg-gray-600/5 border-strong text-quaternary dark:bg-gray-500/10 dark:border-gray-600/40',
|
|
63
66
|
},
|
|
64
67
|
}
|
|
65
68
|
|
|
66
69
|
const pointSwitchValues: ViewType = {
|
|
67
70
|
default: {
|
|
71
|
+
/* белая точка на цветной плашке — осознанно константный white */
|
|
68
72
|
primary: 'bg-white',
|
|
69
73
|
success: 'bg-white',
|
|
70
74
|
danger: 'bg-white',
|
|
@@ -72,25 +76,25 @@ const pointSwitchValues: ViewType = {
|
|
|
72
76
|
gray: 'bg-white',
|
|
73
77
|
},
|
|
74
78
|
inverted: {
|
|
75
|
-
primary: 'bg-
|
|
76
|
-
success: 'bg-
|
|
77
|
-
danger: 'bg-
|
|
78
|
-
warning: 'bg-
|
|
79
|
-
gray: 'bg-
|
|
79
|
+
primary: 'bg-brand',
|
|
80
|
+
success: 'bg-success',
|
|
81
|
+
danger: 'bg-danger',
|
|
82
|
+
warning: 'bg-warning',
|
|
83
|
+
gray: 'bg-icon-default',
|
|
80
84
|
},
|
|
81
85
|
transparent: {
|
|
82
|
-
primary: 'bg-
|
|
83
|
-
success: 'bg-
|
|
84
|
-
danger: 'bg-
|
|
85
|
-
warning: 'bg-
|
|
86
|
-
gray: 'bg-
|
|
86
|
+
primary: 'bg-brand',
|
|
87
|
+
success: 'bg-success',
|
|
88
|
+
danger: 'bg-danger',
|
|
89
|
+
warning: 'bg-warning',
|
|
90
|
+
gray: 'bg-icon-default',
|
|
87
91
|
},
|
|
88
92
|
subtle: {
|
|
89
|
-
primary: 'bg-
|
|
90
|
-
success: 'bg-
|
|
91
|
-
danger: 'bg-
|
|
92
|
-
warning: 'bg-
|
|
93
|
-
gray: 'bg-
|
|
93
|
+
primary: 'bg-brand',
|
|
94
|
+
success: 'bg-success',
|
|
95
|
+
danger: 'bg-danger',
|
|
96
|
+
warning: 'bg-warning',
|
|
97
|
+
gray: 'bg-icon-default',
|
|
94
98
|
},
|
|
95
99
|
}
|
|
96
100
|
|
|
@@ -100,7 +104,7 @@ const classes = computed(() =>
|
|
|
100
104
|
typeSwitchValues[props.view][props.type],
|
|
101
105
|
props.size === 'xs' ? 'px-2 py-[2px] text-body-sm font-bold' : '',
|
|
102
106
|
props.size === 'sm' ? 'px-[10px] py-1 text-body-sm font-semibold h-6' : '',
|
|
103
|
-
props.size === 'md' ? 'px-3 py-[
|
|
107
|
+
props.size === 'md' ? 'px-3 py-[6px] text-body-sm font-semibold h-7' : '',
|
|
104
108
|
props.size === 'lg' ? 'px-4 py-[6px] font-semibold' : '',
|
|
105
109
|
])
|
|
106
110
|
|
|
@@ -87,14 +87,18 @@ function goTo(index: number) {
|
|
|
87
87
|
startTicker()
|
|
88
88
|
}
|
|
89
89
|
|
|
90
|
+
const isPaused = ref(false)
|
|
91
|
+
|
|
90
92
|
function onMouseEnter() {
|
|
91
|
-
if (props.pauseOnHover)
|
|
92
|
-
|
|
93
|
+
if (!props.pauseOnHover) return
|
|
94
|
+
isPaused.value = true
|
|
95
|
+
stopTicker()
|
|
93
96
|
}
|
|
94
97
|
|
|
95
98
|
function onMouseLeave() {
|
|
96
|
-
if (props.pauseOnHover)
|
|
97
|
-
|
|
99
|
+
if (!props.pauseOnHover) return
|
|
100
|
+
isPaused.value = false
|
|
101
|
+
startTicker()
|
|
98
102
|
}
|
|
99
103
|
|
|
100
104
|
onMounted(startTicker)
|
|
@@ -106,43 +110,55 @@ watch(() => [props.interval, props.autoplay, props.steps.length], () => {
|
|
|
106
110
|
</script>
|
|
107
111
|
|
|
108
112
|
<template>
|
|
113
|
+
<!-- eslint-disable tailwindcss/no-unnecessary-arbitrary-value --
|
|
114
|
+
Размеры и типографика скопированы из макета литералами (см. предупреждения
|
|
115
|
+
правила). Токены здесь не использовать: подсказка leading-1.4 в v4 значит
|
|
116
|
+
0.35rem, а не line-height 1.4. -->
|
|
109
117
|
<div
|
|
110
|
-
class="grid grid-cols-1 gap-
|
|
118
|
+
class="grid grid-cols-1 gap-8"
|
|
111
119
|
:class="colsClass"
|
|
120
|
+
@mouseenter="onMouseEnter"
|
|
121
|
+
@mouseleave="onMouseLeave"
|
|
112
122
|
>
|
|
113
|
-
<ol class="flex flex-col gap-
|
|
123
|
+
<ol class="flex flex-col gap-2">
|
|
114
124
|
<li
|
|
115
125
|
v-for="(step, i) in steps"
|
|
116
126
|
:key="i"
|
|
117
|
-
class="ss-card group relative cursor-pointer overflow-hidden rounded-
|
|
127
|
+
class="ss-card group relative cursor-pointer overflow-hidden rounded-14 border bg-main transition-[background-color,box-shadow,border-color,opacity] duration-300"
|
|
118
128
|
:class="i === active
|
|
119
|
-
? 'ss-card-active border-
|
|
120
|
-
: 'border-
|
|
129
|
+
? 'ss-card-active border-strong'
|
|
130
|
+
: 'border-default opacity-60 hover:bg-brand-subtle hover:opacity-100'"
|
|
121
131
|
@click="goTo(i)"
|
|
122
132
|
>
|
|
123
133
|
<div class="p-4">
|
|
124
134
|
<div
|
|
125
|
-
class="flex gap-
|
|
135
|
+
class="flex gap-[13px]"
|
|
126
136
|
:class="expandable ? 'items-center' : 'items-start'"
|
|
127
137
|
>
|
|
128
138
|
<span
|
|
129
|
-
class="flex size-
|
|
130
|
-
:class="step.iconBg || 'bg-
|
|
139
|
+
class="flex size-10 shrink-0 items-center justify-center rounded-[12px]"
|
|
140
|
+
:class="step.iconBg || 'bg-brand-subtle'"
|
|
131
141
|
>
|
|
132
142
|
<component
|
|
133
143
|
:is="step.icon"
|
|
134
144
|
v-if="step.icon"
|
|
135
145
|
class="size-5"
|
|
136
|
-
:class="step.iconColor || 'text-
|
|
146
|
+
:class="step.iconColor || 'text-brand'"
|
|
137
147
|
/>
|
|
138
148
|
</span>
|
|
139
149
|
<div class="min-w-0 flex-1">
|
|
140
|
-
<p
|
|
150
|
+
<p
|
|
151
|
+
class="block text-[14px] font-bold transition-colors"
|
|
152
|
+
:class="i === active ? 'text-primary' : 'text-quaternary'"
|
|
153
|
+
>
|
|
141
154
|
{{ step.title }}
|
|
142
155
|
</p>
|
|
143
156
|
|
|
144
157
|
<div v-if="!expandable">
|
|
145
|
-
<p
|
|
158
|
+
<p
|
|
159
|
+
class="mt-0.5 block text-[12px] leading-[1.4] transition-colors"
|
|
160
|
+
:class="i === active ? 'text-quaternary' : 'text-secondary'"
|
|
161
|
+
>
|
|
146
162
|
{{ step.description }}
|
|
147
163
|
</p>
|
|
148
164
|
<div
|
|
@@ -172,7 +188,7 @@ watch(() => [props.interval, props.autoplay, props.steps.length], () => {
|
|
|
172
188
|
: 'grid-rows-[0fr] opacity-0'"
|
|
173
189
|
>
|
|
174
190
|
<div class="overflow-hidden">
|
|
175
|
-
<p class="text-body-sm text-
|
|
191
|
+
<p class="text-body-sm text-quaternary">
|
|
176
192
|
{{ step.description }}
|
|
177
193
|
</p>
|
|
178
194
|
<div
|
|
@@ -194,39 +210,61 @@ watch(() => [props.interval, props.autoplay, props.steps.length], () => {
|
|
|
194
210
|
</div>
|
|
195
211
|
</div>
|
|
196
212
|
|
|
213
|
+
<!-- Прогресс — CSS-анимация scaleX, как в макете (не JS-ширина);
|
|
214
|
+
длительность приходит переменной: scoped-стили переименовывают
|
|
215
|
+
@keyframes, поэтому inline-строку animation здесь использовать нельзя.
|
|
216
|
+
Константный бренд-градиент — одинаков в темах. -->
|
|
197
217
|
<span
|
|
198
218
|
v-if="i === active && autoplay && steps.length > 1"
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
/>
|
|
205
|
-
</span>
|
|
219
|
+
:key="active"
|
|
220
|
+
class="cap-prog absolute inset-x-0 bottom-0 h-[3px] bg-linear-to-r from-brand to-[#4da8ff]"
|
|
221
|
+
:class="{ 'is-paused': isPaused }"
|
|
222
|
+
:style="{ '--cap-dur': `${interval}ms` }"
|
|
223
|
+
/>
|
|
206
224
|
</li>
|
|
207
225
|
</ol>
|
|
208
226
|
|
|
209
|
-
<div
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
:count="steps.length"
|
|
220
|
-
:fill-width="fillWidth"
|
|
221
|
-
:go-to="goTo"
|
|
222
|
-
/>
|
|
223
|
-
</div>
|
|
227
|
+
<div class="flex justify-center">
|
|
228
|
+
<slot
|
|
229
|
+
name="panel"
|
|
230
|
+
:active="active"
|
|
231
|
+
:step="steps[active]"
|
|
232
|
+
:progress="progress"
|
|
233
|
+
:count="steps.length"
|
|
234
|
+
:fill-width="fillWidth"
|
|
235
|
+
:go-to="goTo"
|
|
236
|
+
/>
|
|
224
237
|
</div>
|
|
225
238
|
</div>
|
|
226
239
|
</template>
|
|
227
240
|
|
|
228
241
|
<style scoped>
|
|
229
242
|
.ss-card-active {
|
|
230
|
-
box-shadow: 0
|
|
243
|
+
box-shadow: 0 14px 34px -18px color-mix(in srgb, var(--color-brand-500) 32%, transparent);
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
@keyframes cap-prog {
|
|
247
|
+
from {
|
|
248
|
+
transform: scaleX(0);
|
|
249
|
+
}
|
|
250
|
+
to {
|
|
251
|
+
transform: scaleX(1);
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
.cap-prog {
|
|
256
|
+
transform-origin: left;
|
|
257
|
+
animation: cap-prog var(--cap-dur, 4600ms) linear;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
.cap-prog.is-paused {
|
|
261
|
+
animation-play-state: paused;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
@media (prefers-reduced-motion: reduce) {
|
|
265
|
+
.cap-prog {
|
|
266
|
+
animation: none;
|
|
267
|
+
transform: none;
|
|
268
|
+
}
|
|
231
269
|
}
|
|
232
270
|
</style>
|