prlg-ui 1.2.7 → 1.3.0

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 (51) hide show
  1. package/package.json +2 -1
  2. package/dist/SortDownFillIcon-7Z207bxw.js +0 -270
  3. package/dist/SortDownFillIcon-CSQH3vsY.cjs +0 -1
  4. package/dist/fonts/Roboto/Roboto-Black.woff +0 -0
  5. package/dist/fonts/Roboto/Roboto-Black.woff2 +0 -0
  6. package/dist/fonts/Roboto/Roboto-Bold.woff +0 -0
  7. package/dist/fonts/Roboto/Roboto-Bold.woff2 +0 -0
  8. package/dist/fonts/Roboto/Roboto-ExtraBold.woff +0 -0
  9. package/dist/fonts/Roboto/Roboto-ExtraBold.woff2 +0 -0
  10. package/dist/fonts/Roboto/Roboto-ExtraLight.woff +0 -0
  11. package/dist/fonts/Roboto/Roboto-ExtraLight.woff2 +0 -0
  12. package/dist/fonts/Roboto/Roboto-Light.woff +0 -0
  13. package/dist/fonts/Roboto/Roboto-Light.woff2 +0 -0
  14. package/dist/fonts/Roboto/Roboto-Medium.woff +0 -0
  15. package/dist/fonts/Roboto/Roboto-Medium.woff2 +0 -0
  16. package/dist/fonts/Roboto/Roboto-Regular.woff +0 -0
  17. package/dist/fonts/Roboto/Roboto-Regular.woff2 +0 -0
  18. package/dist/fonts/Roboto/Roboto-SemiBold.woff +0 -0
  19. package/dist/fonts/Roboto/Roboto-SemiBold.woff2 +0 -0
  20. package/dist/fonts/Roboto/Roboto-Thin.woff +0 -0
  21. package/dist/fonts/Roboto/Roboto-Thin.woff2 +0 -0
  22. package/dist/icons/index.cjs.js +0 -1
  23. package/dist/icons/index.es.js +0 -1095
  24. package/dist/icons.d.ts +0 -150
  25. package/dist/index.d.ts +0 -1033
  26. package/dist/prlg-ui.cjs.js +0 -1
  27. package/dist/prlg-ui.css +0 -1
  28. package/dist/prlg-ui.es.js +0 -2803
  29. package/dist/scss/colors.scss +0 -134
  30. package/dist/scss/fonts.scss +0 -3
  31. package/dist/scss/main.scss +0 -36
  32. package/dist/scss/mixins.scss +0 -177
  33. package/dist/scss/reset.scss +0 -51
  34. package/dist/scss/root-vars.scss +0 -4
  35. package/dist/useBodyScroll.util-BgQeA8Dg.js +0 -82
  36. package/dist/useBodyScroll.util-D-eNxODy.cjs +0 -1
  37. package/dist/utils/Portal/Portal.vue +0 -27
  38. package/dist/utils/Portal/index.ts +0 -3
  39. package/dist/utils/Portal.vue +0 -27
  40. package/dist/utils/date.util.ts +0 -29
  41. package/dist/utils/dayjs.util.ts +0 -26
  42. package/dist/utils/eventBus.util.ts +0 -41
  43. package/dist/utils/index.cjs.js +0 -1
  44. package/dist/utils/index.es.js +0 -498
  45. package/dist/utils/index.ts +0 -3
  46. package/dist/utils/isClient.util.ts +0 -3
  47. package/dist/utils/onClickOutside.util.ts +0 -57
  48. package/dist/utils/price.util.ts +0 -21
  49. package/dist/utils/useBodyScroll.util.ts +0 -33
  50. package/dist/utils.d.ts +0 -93
  51. package/dist/vite.svg +0 -1
@@ -1,134 +0,0 @@
1
- //GLOBAL
2
- :root {
3
- --theme-color-m: #E3E9ED;
4
- --animate-duration: 0.3s;
5
- }
6
-
7
- //NEUTRAL
8
- :root {
9
- --theme-neutral-0: #ffffff;
10
- --theme-neutral-100: #FDFDFD; //use bg main fill
11
- --theme-neutral-200: #FAFAFA;
12
- --theme-neutral-250: #EBEBEB;
13
- --theme-neutral-250_40: #EBEBEB66; //use dissabled fill
14
- --theme-neutral-300: #CECECE; //use border icon,text
15
- --theme-neutral-300_40: #CECECE66; //use hover table fill
16
- --theme-neutral-400: #BFBFBF;
17
- --theme-neutral-400_40: #BFBFBF66;
18
- --theme-neutral-500: #A1A1A1; //use btn icon
19
- --theme-neutral-600: #525252;
20
- --theme-neutral-700: #3D3D3D;
21
- --theme-neutral-800: #292929;
22
- --theme-neutral-850: #1F1F1F;
23
- --theme-neutral-950: #0A0A0A;
24
-
25
- --theme-neutral-surface-bg: var(--theme-neutral-100);
26
- --theme-neutral-surface-default: var(--theme-neutral-0);
27
- --theme-neutral-surface-subtitle: var(--theme-neutral-200);
28
- --theme-neutral-surface-icon: #F1F4F5;
29
- --theme-neutral-surface-disabled: var(--theme-neutral-250_40);
30
-
31
- --theme-text-icon-body: #3B3B3B;
32
- --theme-neutral-text-title: var(--theme-neutral-950);
33
- --theme-neutral-text-subtitle: var(--theme-neutral-800);
34
- --theme-neutral-text-body: var(--theme-neutral-700);
35
- --theme-neutral-text-caption: var(--theme-neutral-500);
36
- --theme-neutral-text-disabled: var(--theme-neutral-400_40);
37
- --theme-neutral-text-negative: var(--theme-neutral-0);
38
-
39
- --theme-neutral-icon-primary: #90A4AE;
40
- --theme-neutral-icon-secondary: var(--theme-neutral-400);
41
- --theme-neutral-icon-caption: var(--theme-neutral-500);
42
- --theme-neutral-icon-disabled: #B5B5B5;
43
- --theme-neutral-icon-negative: var(--theme-neutral-0);
44
-
45
- --theme-neutral-border-default: var(--theme-neutral-300);
46
- --theme-neutral-border-darker: var(--theme-neutral-400);
47
- --theme-neutral-border-divider: #E3E9ED;
48
- --theme-neutral-border-disabled: var(--theme-neutral-400_40);
49
-
50
- //BOX-SHADOW
51
- --theme-main-interface-shadow: 0 2px 8.8px 2px #0000000D, 0 0 13.4px 0 #0000000A;
52
- --theme-hover-interface-shadow: 0 2px 8.8px 2px #0000000D, 0 1px 1px 0 #0000000A;
53
-
54
- }
55
-
56
- //PRIMARY
57
- :root {
58
- --theme-primary-50: #EAFEF0;
59
- --theme-primary-50_40: #EAFEF066;
60
- --theme-primary-100: #BFF7CD;
61
- --theme-primary-200: #AAEEBC;
62
- --theme-primary-200_15: #94E6AA; //use focussed stroke
63
- --theme-primary-200_25: #94E6AA40; //use focussed stroke
64
- --theme-primary-200_50: #94E6AA80; //use focussed stroke
65
- --theme-primary-250: #CAF3D5; //use hover fill
66
- --theme-primary-300: #7FDD98; //use hover fill
67
- --theme-primary-400: #2ABC51; //use focussed fill
68
- --theme-primary-500_5: #00AB2E0D; //use default fill
69
- --theme-primary-500: #00AB2E; //use default fill
70
- --theme-primary-600: #008925; //use pressed fill
71
- --theme-primary-700: #00671C;
72
- --theme-primary-800: #004412;
73
- --theme-primary-900: #002209;
74
-
75
- --theme-primary-surface-default: var(--theme-primary-500);
76
- --theme-primary-surface-subtitle: var(--theme-primary-50);
77
- --theme-primary-surface-darker: var(--theme-primary-600);
78
- --theme-primary-surface-lighter: var(--theme-primary-200_25);
79
- --theme-primary-surface-hover: var(--theme-primary-50_40);
80
-
81
- --theme-primary-border-default: var(--theme-primary-700);
82
- --theme-primary-border-subtitle: var(--theme-primary-600);
83
- --theme-primary-border-darker: var(--theme-primary-800);
84
- --theme-primary-border-lighter: var(--theme-primary-200);
85
-
86
- --theme-primary-icon-default: var(--theme-primary-500);
87
- }
88
-
89
- //INFO
90
- :root {
91
- --theme-info-100: #E3EEFA;
92
- --theme-info-100_50: #E3EEFA80; //use fill
93
- --theme-info-200: #C2D9F5; //use stroke
94
- --theme-info-300: #6EA6E7; //hover
95
- --theme-info-400: #2674CE; //use link (подчеркивание при наведении)
96
- --theme-info-500: #235FA4; //use icon
97
- --theme-info-600: #02538F;
98
- --theme-info-700: #134A73;
99
- --theme-info-800: #152D4F;
100
- --theme-info-900: #161E33;
101
- }
102
-
103
- //WARN
104
- :root {
105
- --theme-warn-100: #FDF4EA; //use fill
106
- --theme-warn-200: #FADFC1; //use stroke
107
- --theme-warn-300: #F4C083; //hover
108
- --theme-warn-400: #F1AB5A;
109
- --theme-warn-500: #ED9631; //use icon
110
- --theme-warn-600: #D47D16;
111
- --theme-warn-700: #AC6410;
112
- --theme-warn-800: #814A09;
113
- --theme-warn-900: #492C0A;
114
- }
115
-
116
- //ERROR
117
- :root {
118
- --theme-error-100: #FCEAEA;
119
- --theme-error-100_50: #FCEAEA80; //use fill
120
- --theme-error-200_50: #FCEAEA; //use stroke
121
- --theme-error-200: #FFD4D4; //use stroke
122
- --theme-error-300: #F4A6A6; //hover
123
- --theme-error-400: #DF575C;
124
- --theme-error-500: #DE292F; //use icon
125
- --theme-error-600: #BD2429;
126
- --theme-error-700: #921D21;
127
- --theme-error-800: #6E1820;
128
- --theme-error-900: #4E1012;
129
- }
130
-
131
- //SHADOW
132
- :root {
133
- --theme-shadow-button: 0px 2px 8.8px 2px #0000000D, 0px 1px 1px 0px #0000000A;
134
- }
@@ -1,3 +0,0 @@
1
- @use "./mixins.scss" as mixins;
2
-
3
- @include mixins.font-face("Roboto", (100, 200, 300, 400, 500, 600, 700, 800, 900));
@@ -1,36 +0,0 @@
1
- @use './reset.scss';
2
- @use './colors.scss';
3
- @use './root-vars.scss';
4
- @use './mixins.scss';
5
- @use './fonts.scss';
6
-
7
- .container {
8
- width: 100%;
9
- margin: 0 auto;
10
- padding: 0 10px;
11
- max-width: 768px; // Базовая ширина для мобильных
12
-
13
- @media screen and (min-width: 1010px) {
14
- max-width: 991px;
15
- }
16
-
17
- @media screen and (min-width: 1220px) {
18
- max-width: 1200px;
19
- }
20
-
21
- @media screen and (min-width: 1420px) {
22
- max-width: 1400px;
23
- }
24
-
25
- @media screen and (min-width: 1620px) {
26
- max-width: 1600px;
27
- }
28
- }
29
-
30
- .page-title {
31
- font-weight: 600;
32
- font-size: 24px;
33
- line-height: 120%;
34
- color: var(--theme-neutral-text-title);
35
- text-transform: uppercase;
36
- }
@@ -1,177 +0,0 @@
1
- /**
2
- * Миксин для подключения шрифтов
3
- * @param {string} $font-family - Название семейства шрифтов
4
- * @param {list} $weights - Список весов шрифта (100-900)
5
- *
6
- * Пример использования:
7
- * $weights: (100, 200, 300, 400, 500, 600, 700, 800, 900);
8
- * $styles: (normal, italic);
9
- * @include font-face('Roboto', $weights);
10
- *
11
- * Структура файлов шрифтов должна быть следующей:
12
- * fonts/
13
- * Roboto/
14
- * Roboto-Thin.woff2
15
- * Roboto-Thin.woff
16
- * ...
17
- */
18
-
19
- @mixin font-face($font-family, $weights) {
20
- @each $weight in $weights {
21
- $weight-name: if(
22
- $weight == 100,
23
- "Thin",
24
- if(
25
- $weight == 200,
26
- "ExtraLight",
27
- if(
28
- $weight == 300,
29
- "Light",
30
- if(
31
- $weight == 400,
32
- "Regular",
33
- if(
34
- $weight == 500,
35
- "Medium",
36
- if(
37
- $weight == 600,
38
- "SemiBold",
39
- if(
40
- $weight == 700,
41
- "Bold",
42
- if(
43
- $weight == 800,
44
- "ExtraBold",
45
- if($weight == 900, "Black", $weight)
46
- )
47
- )
48
- )
49
- )
50
- )
51
- )
52
- )
53
- );
54
- @font-face {
55
- font-family: "#{$font-family}";
56
- font-weight: #{$weight};
57
- src: url("./fonts/#{$font-family}/#{$font-family}-#{$weight-name}.woff2") format("woff2"),
58
- url("./fonts/#{$font-family}/#{$font-family}-#{$weight-name}.woff") format("woff");
59
- }
60
- }
61
- }
62
-
63
-
64
- /**
65
- * Миксин для создания медиа-запросов с минимальной шириной
66
- *
67
- * @param {number} $width - Минимальная ширина в пикселях
68
- *
69
- * Пример использования:
70
- * @include media-min-width(768px) {
71
- * .container {
72
- * padding: 20px;
73
- * }
74
- * }
75
- *
76
- * Применит стили для экранов шириной от 768px и больше
77
- */
78
-
79
-
80
- @mixin media-min-width($width) {
81
- @media screen and (min-width: $width) {
82
- @content;
83
- }
84
- }
85
-
86
- /// Миксин для обрезки многострочного текста с троеточием
87
- ///
88
- /// @param {Number} $lines - Количество отображаемых строк (по умолчанию: 2)
89
- ///
90
- /// Используется для ограничения текста по количеству строк с добавлением "..."
91
- /// Работает на основе -webkit-line-clamp и поддерживается в современных браузерах.
92
- ///
93
- /// 🔁 Пример использования:
94
- /// .text {
95
- /// @include ellipsis-multiline(3);
96
- /// }
97
- @mixin ellipsis-multiline($lines: 2) {
98
- display: -webkit-box;
99
- -webkit-line-clamp: $lines;
100
- -webkit-box-orient: vertical;
101
- overflow: hidden;
102
- text-overflow: ellipsis;
103
- }
104
-
105
- // 📱 Адаптив
106
- @mixin respond($breakpoint) {
107
- @if $breakpoint == sm {
108
- @media (min-width: 640px) {
109
- @content;
110
- }
111
- } @else if $breakpoint == md {
112
- @media (min-width: 768px) {
113
- @content;
114
- }
115
- } @else if $breakpoint == lg {
116
- @media (min-width: 1024px) {
117
- @content;
118
- }
119
- } @else if $breakpoint == xl {
120
- @media (min-width: 1280px) {
121
- @content;
122
- }
123
- } @else if $breakpoint == xxl {
124
- @media (min-width: 1420px) {
125
- @content;
126
- }
127
- } @else if $breakpoint == xxxl {
128
- @media (min-width: 1620px) {
129
- @content;
130
- }
131
- }
132
- }
133
-
134
- // ✨ Кастомный скроллбар
135
- @mixin custom-scrollbar($direction) {
136
- box-sizing: content-box;
137
-
138
- scrollbar-width: thin;
139
- scrollbar-color: var(--theme-neutral-border-default) transparent;
140
-
141
- // WebKit scrollbar
142
- &::-webkit-scrollbar {
143
- @if $direction == "right" {
144
- width: 8px;
145
- height: 0;
146
- } @else if $direction == "bottom" {
147
- width: 0;
148
- height: 8px;
149
- } @else if $direction == "both" {
150
- width: 8px;
151
- height: 8px;
152
- }
153
- }
154
-
155
- &::-webkit-scrollbar-thumb {
156
- background-color: var(--theme-neutral-border-default);
157
- border-radius: 4px;
158
- }
159
-
160
- &::-webkit-scrollbar-track {
161
- background: transparent;
162
- }
163
-
164
- &::-webkit-scrollbar-corner {
165
- background: transparent;
166
- }
167
-
168
- // Add paddings depending on direction
169
- // @if $direction == "right" {
170
- // padding-right: 10px;
171
- // } @else if $direction == "bottom" {
172
- // padding-bottom: 10px;
173
- // } @else if $direction == "both" {
174
- // padding-right: 10px;
175
- // padding-bottom: 10px;
176
- // }
177
- }
@@ -1,51 +0,0 @@
1
- * {
2
- margin: 0;
3
- padding: 0;
4
- box-sizing: border-box;
5
- }
6
-
7
- html, body {
8
- height: 100%;
9
- width: 100%;
10
- }
11
-
12
- body {
13
- font-family: "Roboto", sans-serif;
14
- -webkit-font-smoothing: antialiased;
15
- -moz-osx-font-smoothing: grayscale;
16
- font-size: 16px;
17
- line-height: 1.5;
18
- color: #333;
19
- }
20
-
21
- a {
22
- text-decoration: none;
23
- color: inherit;
24
- }
25
-
26
- button {
27
- border: none;
28
- background: none;
29
- cursor: pointer;
30
- font: inherit;
31
- }
32
-
33
- ul, ol {
34
- list-style: none;
35
- }
36
-
37
- img {
38
- max-width: 100%;
39
- height: auto;
40
- display: block;
41
- }
42
-
43
- input, textarea, select {
44
- font: inherit;
45
- border: none;
46
- outline: none;
47
- }
48
-
49
- h1, h2, h3, h4, h5, h6 {
50
- font-weight: normal;
51
- }
@@ -1,4 +0,0 @@
1
- //MODAL
2
- :root {
3
- --modal-z-index: 1000;
4
- }
@@ -1,82 +0,0 @@
1
- import { defineComponent as f, ref as p, computed as m, onMounted as w, renderSlot as c, createBlock as g, createCommentVNode as y, openBlock as h, Teleport as v } from "vue";
2
- const u = /* @__PURE__ */ new WeakMap();
3
- function S(e, t, r = {}) {
4
- if (!e) return () => {
5
- };
6
- const o = u.get(e);
7
- o && (o(), u.delete(e));
8
- const n = (d) => {
9
- const s = d.target instanceof Node ? d.target : null;
10
- if (!s) return;
11
- const a = (typeof r.ignore == "function" ? r.ignore() : r.ignore ?? []).map((l) => typeof l == "string" ? document.querySelector(l) : l instanceof HTMLElement ? l : null).filter((l) => l != null);
12
- e.contains(s) || a.some((l) => l.contains(s)) || t(d);
13
- };
14
- document.addEventListener("mousedown", n, { capture: !0 }), document.addEventListener("touchstart", n, { capture: !0 });
15
- const i = () => {
16
- document.removeEventListener("mousedown", n, { capture: !0 }), document.removeEventListener("touchstart", n, { capture: !0 }), u.delete(e);
17
- };
18
- return u.set(e, i), i;
19
- }
20
- function k() {
21
- return !!(typeof window < "u" && window.document && window.document.createElement);
22
- }
23
- const L = /* @__PURE__ */ f({
24
- __name: "Portal",
25
- props: {
26
- appendTo: { default: "body" },
27
- disabled: { type: Boolean }
28
- },
29
- setup(e) {
30
- const t = p(), r = m(() => e.disabled || e.appendTo === "self");
31
- return w(() => {
32
- t.value = k();
33
- }), (o, n) => r.value ? c(o.$slots, "default", { key: 0 }) : t.value ? (h(), g(v, {
34
- key: 1,
35
- to: o.appendTo
36
- }, [
37
- c(o.$slots, "default")
38
- ], 8, ["to"])) : y("", !0);
39
- }
40
- });
41
- function B() {
42
- const e = /* @__PURE__ */ new Map();
43
- return {
44
- on(t, r) {
45
- const o = e.get(t) || [];
46
- o.push(r), e.set(t, o);
47
- },
48
- off(t, r) {
49
- const o = e.get(t);
50
- o && e.set(
51
- t,
52
- o.filter((n) => n !== r)
53
- );
54
- },
55
- emit(t, r) {
56
- const o = e.get(t);
57
- o && o.forEach((n) => n(r));
58
- },
59
- clear() {
60
- e.clear();
61
- }
62
- };
63
- }
64
- function C() {
65
- let e = null, t = null;
66
- return { lockScroll: () => {
67
- if (typeof window > "u") return;
68
- const n = document.body, i = window.innerWidth - n.clientWidth;
69
- e === null && (e = n.style.overflow, t = n.style.paddingRight), n.style.overflow = "hidden", n.style.paddingRight = `${i}px`;
70
- }, unlockScroll: () => {
71
- if (!(typeof window > "u") && e !== null && t !== null) {
72
- const n = document.body;
73
- n.style.overflow = e, n.style.paddingRight = t, e = null, t = null;
74
- }
75
- } };
76
- }
77
- export {
78
- B as E,
79
- L as _,
80
- S as o,
81
- C as u
82
- };
@@ -1 +0,0 @@
1
- "use strict";const l=require("vue"),d=new WeakMap;function f(e,t,r={}){if(!e)return()=>{};const o=d.get(e);o&&(o(),d.delete(e));const n=c=>{const s=c.target instanceof Node?c.target:null;if(!s)return;const a=(typeof r.ignore=="function"?r.ignore():r.ignore??[]).map(i=>typeof i=="string"?document.querySelector(i):i instanceof HTMLElement?i:null).filter(i=>i!=null);e.contains(s)||a.some(i=>i.contains(s))||t(c)};document.addEventListener("mousedown",n,{capture:!0}),document.addEventListener("touchstart",n,{capture:!0});const u=()=>{document.removeEventListener("mousedown",n,{capture:!0}),document.removeEventListener("touchstart",n,{capture:!0}),d.delete(e)};return d.set(e,u),u}function m(){return!!(typeof window<"u"&&window.document&&window.document.createElement)}const p=l.defineComponent({__name:"Portal",props:{appendTo:{default:"body"},disabled:{type:Boolean}},setup(e){const t=l.ref(),r=l.computed(()=>e.disabled||e.appendTo==="self");return l.onMounted(()=>{t.value=m()}),(o,n)=>r.value?l.renderSlot(o.$slots,"default",{key:0}):t.value?(l.openBlock(),l.createBlock(l.Teleport,{key:1,to:o.appendTo},[l.renderSlot(o.$slots,"default")],8,["to"])):l.createCommentVNode("",!0)}});function w(){const e=new Map;return{on(t,r){const o=e.get(t)||[];o.push(r),e.set(t,o)},off(t,r){const o=e.get(t);o&&e.set(t,o.filter(n=>n!==r))},emit(t,r){const o=e.get(t);o&&o.forEach(n=>n(r))},clear(){e.clear()}}}function g(){let e=null,t=null;return{lockScroll:()=>{if(typeof window>"u")return;const n=document.body,u=window.innerWidth-n.clientWidth;e===null&&(e=n.style.overflow,t=n.style.paddingRight),n.style.overflow="hidden",n.style.paddingRight=`${u}px`},unlockScroll:()=>{if(!(typeof window>"u")&&e!==null&&t!==null){const n=document.body;n.style.overflow=e,n.style.paddingRight=t,e=null,t=null}}}}exports.EventBus=w;exports._sfc_main=p;exports.onClickOutside=f;exports.useBodyScroll=g;
@@ -1,27 +0,0 @@
1
- <template>
2
- <template v-if="inline">
3
- <slot></slot>
4
- </template>
5
- <template v-else-if="mounted">
6
- <Teleport :to="appendTo">
7
- <slot></slot>
8
- </Teleport>
9
- </template>
10
- </template>
11
-
12
- <script setup lang="ts">
13
- import { computed, onMounted, ref } from 'vue';
14
- import isClient from '../../utils/isClient.util';
15
-
16
- const { appendTo = 'body', disabled } = defineProps<{
17
- appendTo?: 'self' | string,
18
- disabled?: boolean
19
- }>()
20
-
21
- const mounted = ref<boolean>()
22
- const inline = computed(() => disabled || appendTo === 'self')
23
-
24
- onMounted(() => {
25
- mounted.value = isClient()
26
- })
27
- </script>
@@ -1,3 +0,0 @@
1
- import Portal from "./Portal.vue";
2
-
3
- export { Portal };
@@ -1,27 +0,0 @@
1
- <template>
2
- <template v-if="inline">
3
- <slot></slot>
4
- </template>
5
- <template v-else-if="mounted">
6
- <Teleport :to="appendTo">
7
- <slot></slot>
8
- </Teleport>
9
- </template>
10
- </template>
11
-
12
- <script setup lang="ts">
13
- import { computed, onMounted, ref } from 'vue';
14
- import isClient from '../../utils/isClient.util';
15
-
16
- const { appendTo = 'body', disabled } = defineProps<{
17
- appendTo?: 'self' | string,
18
- disabled?: boolean
19
- }>()
20
-
21
- const mounted = ref<boolean>()
22
- const inline = computed(() => disabled || appendTo === 'self')
23
-
24
- onMounted(() => {
25
- mounted.value = isClient()
26
- })
27
- </script>
@@ -1,29 +0,0 @@
1
- import {dayjs} from './dayjs.util.ts'
2
-
3
- /**
4
- * Форматирует дату в человекочитаемый вид: 20 июня 2025
5
- */
6
- export function formatDateReadable(date: string | Date): string {
7
- return dayjs(date).format('D MMMM YYYY')
8
- }
9
-
10
- /**
11
- * Форматирует дату для отображения времени: 20 июня, 14:30
12
- */
13
- export function formatDateWithTime(date: string | Date): string {
14
- return dayjs(date).format('D MMMM, HH:mm')
15
- }
16
-
17
- /**
18
- * Возвращает разницу между датами в днях
19
- */
20
- export function getDaysBetween(start: string | Date, end: string | Date): number {
21
- return dayjs(end).diff(dayjs(start), 'day')
22
- }
23
-
24
- /**
25
- * Проверяет, истекла ли дата
26
- */
27
- export function isExpired(date: string | Date): boolean {
28
- return dayjs().isAfter(dayjs(date))
29
- }
@@ -1,26 +0,0 @@
1
- import dayjs from 'dayjs'
2
-
3
- // 📦 Плагины
4
- import localizedFormat from 'dayjs/plugin/localizedFormat'
5
- import relativeTime from 'dayjs/plugin/relativeTime'
6
- import isToday from 'dayjs/plugin/isToday'
7
- import isBetween from 'dayjs/plugin/isBetween'
8
- import isSameOrBefore from 'dayjs/plugin/isSameOrBefore'
9
- import isSameOrAfter from 'dayjs/plugin/isSameOrAfter'
10
-
11
- // 🌍 Локаль
12
- import 'dayjs/locale/ru'
13
-
14
- // 🧩 Установка плагинов
15
- dayjs.extend(localizedFormat)
16
- dayjs.extend(relativeTime)
17
- dayjs.extend(isToday)
18
- dayjs.extend(isBetween)
19
- dayjs.extend(isSameOrBefore)
20
- dayjs.extend(isSameOrAfter)
21
-
22
- // 🗣️ Установка локали
23
- dayjs.locale('ru')
24
-
25
- // 📤 Экспорт по умолчанию
26
- export {dayjs}
@@ -1,41 +0,0 @@
1
- export type Handler<T> = (event: T) => void;
2
-
3
- export interface TypedEventBus<Events extends Record<string, any>> {
4
- on<K extends keyof Events>(type: K, handler: Handler<Events[K]>): void;
5
- off<K extends keyof Events>(type: K, handler: Handler<Events[K]>): void;
6
- emit<K extends keyof Events>(type: K, evt?: Events[K]): void;
7
- clear(): void;
8
- }
9
-
10
- export function EventBus<Events extends Record<string, any>>(): TypedEventBus<Events> {
11
- const allHandlers = new Map<keyof Events, Handler<any>[]>();
12
-
13
- return {
14
- on<K extends keyof Events>(type: K, handler: Handler<Events[K]>) {
15
- const handlers = allHandlers.get(type) || [];
16
- handlers.push(handler);
17
- allHandlers.set(type, handlers);
18
- },
19
-
20
- off<K extends keyof Events>(type: K, handler: Handler<Events[K]>) {
21
- const handlers = allHandlers.get(type);
22
- if (handlers) {
23
- allHandlers.set(
24
- type,
25
- handlers.filter(h => h !== handler)
26
- );
27
- }
28
- },
29
-
30
- emit<K extends keyof Events>(type: K, evt?: Events[K]) {
31
- const handlers = allHandlers.get(type);
32
- if (handlers) {
33
- handlers.forEach(handler => handler(evt));
34
- }
35
- },
36
-
37
- clear() {
38
- allHandlers.clear();
39
- }
40
- };
41
- }