From 68de986bddc4430914e71f72655c0552708ab52e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=D0=94=D0=BC=D0=B8=D1=82=D1=80=D0=B8=D0=B9=20=D0=9C=D0=B0?=
 =?UTF-8?q?=D0=BB=D1=8E=D0=B3=D0=B8=D0=BD?= <d.malygin@iqdev.digital>
Date: Mon, 10 Feb 2025 11:03:06 +0500
Subject: [PATCH] feat: 'Toast' in process (add styles and icons)

---
 src/App.vue                                   |  10 +-
 src/common/constants/icons.ts                 |  10 +-
 src/common/helpers/common.ts                  |   9 +-
 src/common/interfaces/componentsProps.ts      |   3 +
 src/components/Carousel/Carousel.vue          |  25 ++--
 src/components/Checkbox/Checkbox.vue          |  16 +--
 src/components/ColorPicker/ColorPicker.vue    |  10 +-
 src/components/Paginator/Paginator.vue        |  19 +--
 src/components/ProgressBar/ProgressBar.vue    |  19 +--
 src/components/Rating/Rating.vue              |  10 +-
 src/components/Tag/Tag.vue                    |  18 +--
 src/components/Toast/Toast.stories.ts         |  54 +++++++-
 src/components/Toast/Toast.vue                | 124 ++++++++++++++----
 src/icons/Mono/CheckMarkIcon.vue              |   2 +-
 ...ircleIcon.vue => CrossRoundFilledIcon.vue} |   0
 src/icons/Mono/CrossRoundIcon.vue             |  23 ++++
 src/icons/Mono/InfoIcon.vue                   |  25 ++++
 src/icons/Mono/WarningIcon.vue                |  27 ++++
 18 files changed, 281 insertions(+), 123 deletions(-)
 rename src/icons/Mono/{CrossCircleIcon.vue => CrossRoundFilledIcon.vue} (100%)
 create mode 100644 src/icons/Mono/CrossRoundIcon.vue
 create mode 100644 src/icons/Mono/InfoIcon.vue
 create mode 100644 src/icons/Mono/WarningIcon.vue

diff --git a/src/App.vue b/src/App.vue
index 81a1ef6..4f8b11a 100644
--- a/src/App.vue
+++ b/src/App.vue
@@ -41,7 +41,7 @@ import CompassIcon from '@icons/Mono/CompassIcon.vue';
 import ConstructionWorkerIcon from '@icons/Mono/ConstructionWorkerIcon.vue';
 import ContactsIcon from '@icons/Mono/ContactsIcon.vue';
 import CropIcon from '@icons/Mono/CropIcon.vue';
-import CrossCircleIcon from '@icons/Mono/CrossCircleIcon.vue';
+import CrossRoundFilledIcon from '@icons/Mono/CrossRoundFilledIcon.vue';
 import CrossIcon from '@icons/Mono/CrossIcon.vue';
 import CubeIcon from '@icons/Mono/CubeIcon.vue';
 import CupIcon from '@icons/Mono/CupIcon.vue';
@@ -119,6 +119,9 @@ import CornerLeftBottomIcon from '@icons/Mono/CornerLeftBottomIcon.vue';
 import CornerLeftTopIcon from '@icons/Mono/CornerLeftTopIcon.vue';
 import CornerRightBottomIcon from '@icons/Mono/CornerRightBottomIcon.vue';
 import CornerRightTopIcon from '@icons/Mono/CornerRightTopIcon.vue';
+import InfoIcon from '@icons/Mono/InfoIcon.vue';
+import WarningIcon from '@icons/Mono/WarningIcon.vue';
+import CrossRoundIcon from '@icons/Mono/CrossRoundIcon.vue';
 
 const gentleIcons = {
   Age18Icon,
@@ -174,7 +177,8 @@ const gentleIcons = {
   CornerRightTopIcon,
   CropIcon,
   CrossIcon,
-  CrossCircleIcon,
+  CrossRoundIcon,
+  CrossRoundFilledIcon,
   CubeIcon,
   CupIcon,
   CursorIcon,
@@ -217,6 +221,7 @@ const gentleIcons = {
   HomeIcon,
   ImageIcon,
   ImageEditIcon,
+  InfoIcon,
   LineIcon,
   LineDashedIcon,
   LineDottedIcon,
@@ -240,6 +245,7 @@ const gentleIcons = {
   TrashIcon,
   TriangleIcon,
   UserIcon,
+  WarningIcon,
 };
 </script>
 
diff --git a/src/common/constants/icons.ts b/src/common/constants/icons.ts
index 45babbb..f44b674 100644
--- a/src/common/constants/icons.ts
+++ b/src/common/constants/icons.ts
@@ -33,7 +33,7 @@ import CardsIcon from '@icons/Mono/CardsIcon.vue';
 import ChartLineIcon from '@icons/Mono/ChartLineIcon.vue';
 import ChartPieIcon from '@icons/Mono/ChartPieIcon.vue';
 import ChatIcon from '@icons/Mono/ChatIcon.vue';
-import CrossCircleIcon from '@icons/Mono/CrossCircleIcon.vue';
+import CrossRoundFilledIcon from '@icons/Mono/CrossRoundFilledIcon.vue';
 import CropIcon from '@icons/Mono/CropIcon.vue';
 import ChatWritingIcon from '@icons/Mono/ChatWritingIcon.vue';
 import CheckMarkIcon from '@icons/Mono/CheckMarkIcon.vue';
@@ -115,6 +115,9 @@ import CornerLeftBottomIcon from '@icons/Mono/CornerLeftBottomIcon.vue';
 import CornerLeftTopIcon from '@icons/Mono/CornerLeftTopIcon.vue';
 import CornerRightBottomIcon from '@icons/Mono/CornerRightBottomIcon.vue';
 import CornerRightTopIcon from '@icons/Mono/CornerRightTopIcon.vue';
+import InfoIcon from '@icons/Mono/InfoIcon.vue';
+import WarningIcon from '@icons/Mono/WarningIcon.vue';
+import CrossRoundIcon from '@icons/Mono/CrossRoundIcon.vue';
 
 export const iconsSet: Record<string, Component> = {
   Age18: Age18Icon,
@@ -166,7 +169,8 @@ export const iconsSet: Record<string, Component> = {
   CornerRightTop: CornerRightTopIcon,
   Crop: CropIcon,
   Cross: CrossIcon,
-  CrossCircle: CrossCircleIcon,
+  CrossRound: CrossRoundIcon,
+  CrossRoundFilled: CrossRoundFilledIcon,
   Cube: CubeIcon,
   Cup: CupIcon,
   Cursor: CursorIcon,
@@ -209,6 +213,7 @@ export const iconsSet: Record<string, Component> = {
   Home: HomeIcon,
   Image: ImageIcon,
   ImageEdit: ImageEditIcon,
+  Info: InfoIcon,
   Line: LineIcon,
   LineDashed: LineDashedIcon,
   LineDotted: LineDottedIcon,
@@ -232,4 +237,5 @@ export const iconsSet: Record<string, Component> = {
   Trash: TrashIcon,
   Triangle: TriangleIcon,
   User: UserIcon,
+  Warning: WarningIcon,
 };
diff --git a/src/common/helpers/common.ts b/src/common/helpers/common.ts
index d224eb3..e7743e9 100644
--- a/src/common/helpers/common.ts
+++ b/src/common/helpers/common.ts
@@ -1,4 +1,4 @@
-import { EThemeColor, type TDarkness, type TThemeColor } from '@interfaces/common';
+import { EThemeColor, type TDarkness, type TSize, type TThemeColor } from '@interfaces/common';
 import {
   convert100ThemeToColor,
   convert200ThemeToColor,
@@ -58,3 +58,10 @@ export const convertThemeToSecondaryColor = (theme: TThemeColor, darkness: TDark
     ? convertWhiteOrBlackToColor(theme, darkness as TDarkness)
     : convertThemeToColor(theme, String(100 + ((+darkness + 600) % 900)));
 };
+
+export const getValueFromSize = (size: TSize, options: string[] | number[]) => {
+  if (size === 'normal') return options[1];
+  if (size === 'large') return options[2];
+  if (size === 'huge') return options[3];
+  return options[0];
+};
diff --git a/src/common/interfaces/componentsProps.ts b/src/common/interfaces/componentsProps.ts
index cfb5109..d36204b 100644
--- a/src/common/interfaces/componentsProps.ts
+++ b/src/common/interfaces/componentsProps.ts
@@ -296,6 +296,9 @@ export interface IToastProps {
   text?: string;
   header?: string;
   icon?: TIcon;
+  width?: string;
+  position?: TExpandedPosition;
+  static?: boolean;
 }
 
 export interface ITagProps {
diff --git a/src/components/Carousel/Carousel.vue b/src/components/Carousel/Carousel.vue
index e246121..9975714 100644
--- a/src/components/Carousel/Carousel.vue
+++ b/src/components/Carousel/Carousel.vue
@@ -2,7 +2,7 @@
 import type { ICarouselProps } from '@interfaces/componentsProps';
 import CarouselButtonContainer from '@components/Carousel/CarouselButtonContainer.vue';
 import { computed, ref } from 'vue';
-import { convertThemeToColor, convertThemeToTextColor } from '@helpers/common';
+import { convertThemeToColor, convertThemeToTextColor, getValueFromSize } from '@helpers/common';
 import ArrowLeftShortIcon from '@icons/Mono/ArrowLeftShortIcon.vue';
 import ArrowRightShortIcon from '@icons/Mono/ArrowRightShortIcon.vue';
 import { defaultProps, getNewValue } from './helpers';
@@ -25,22 +25,17 @@ const isStartDisabled = computed(() => (props.circular ? false : current.value =
 const isEndDisabled = computed(() =>
   props.circular ? false : current.value === Math.ceil(itemsLength.value / props.perView) || !itemsLength.value,
 );
-const sizeCoefficient = computed(() => {
-  const size = props.size;
-  if (size === 'normal') return 1;
-  if (size === 'large') return 2;
-  if (size === 'huge') return 3;
-  return 0.75;
-});
+const sizeCoefficient = computed(() => getValueFromSize(props.size, [0.75, 1, 2, 3]));
 const iconSize = computed(() => 10 * sizeCoefficient.value);
 const itemWidth = computed(() => `calc(${props.innerWidth} / ${props.perView}`);
-const buttonSize = computed(() => {
-  const size = props.size;
-  if (size === 'normal') return 12 * sizeCoefficient.value + 'px';
-  if (size === 'large') return 12 * sizeCoefficient.value + 'px';
-  if (size === 'huge') return 15 * sizeCoefficient.value + 'px';
-  return 9 * sizeCoefficient.value + 'px';
-});
+const buttonSize = computed(() =>
+  getValueFromSize(props.size, [
+    9 * sizeCoefficient.value + 'px',
+    12 * sizeCoefficient.value + 'px',
+    12 * sizeCoefficient.value + 'px',
+    15 * sizeCoefficient.value + 'px',
+  ]),
+);
 const translate = computed(() => `translateX(calc(-${props.innerWidth} / ${props.perView} * ${current.value - 1}))`);
 </script>
 
diff --git a/src/components/Checkbox/Checkbox.vue b/src/components/Checkbox/Checkbox.vue
index eae61a0..f2b5e97 100644
--- a/src/components/Checkbox/Checkbox.vue
+++ b/src/components/Checkbox/Checkbox.vue
@@ -1,7 +1,7 @@
 <script setup lang="ts">
 import type { ICheckboxProps } from '@interfaces/componentsProps';
 import { computed, watch } from 'vue';
-import { convertThemeToColor, convertThemeToTextColor } from '@helpers/common';
+import { convertThemeToColor, convertThemeToTextColor, getValueFromSize } from '@helpers/common';
 import CheckMarkIcon from '@icons/Mono/CheckMarkIcon.vue';
 
 const props = withDefaults(defineProps<ICheckboxProps>(), {
@@ -37,20 +37,10 @@ const color = computed(() => convertThemeToColor(props.textColor, props.darkness
 const borderColor = computed(() =>
   props.invalid ? 'red' : props.disabled ? '#62708c' : convertThemeToColor(props.borderColor, props.darknessBorder),
 );
-const elSize = computed(() => {
-  const size = props.size;
-  if (size === 'normal') return 20;
-  if (size === 'large') return 30;
-  if (size === 'huge') return 40;
-  return 13;
-});
+const elSize = computed(() => getValueFromSize(props.size, [13, 20, 30, 40]));
 const gap = computed(() => {
   if (!props.label) return '0px';
-  const size = props.size;
-  if (size === 'normal') return '7px';
-  if (size === 'large') return '10px';
-  if (size === 'huge') return '15px';
-  return '5px';
+  return getValueFromSize(props.size, ['5px', '7px', '10px', '15px']);
 });
 const borderWidth = computed(() => (props.size === 'large' || props.size === 'huge' ? 2 : 1));
 const borderRadius = computed(() => `${elSize.value / 7 - borderWidth.value}px`);
diff --git a/src/components/ColorPicker/ColorPicker.vue b/src/components/ColorPicker/ColorPicker.vue
index ee6b412..8cdaf2f 100644
--- a/src/components/ColorPicker/ColorPicker.vue
+++ b/src/components/ColorPicker/ColorPicker.vue
@@ -2,7 +2,7 @@
 import type { IColorPickerProps } from '@interfaces/componentsProps';
 import { computed, type Ref } from 'vue';
 import Button from './Button.vue';
-import { convertThemeToColor, convertThemeToTextColor } from '@helpers/common';
+import { convertThemeToColor, convertThemeToTextColor, getValueFromSize } from '@helpers/common';
 
 const props = withDefaults(defineProps<IColorPickerProps>(), {
   size: 'normal',
@@ -10,13 +10,7 @@ const props = withDefaults(defineProps<IColorPickerProps>(), {
 });
 
 const value = defineModel() as Ref<string>;
-const size = computed(() => {
-  const size = props.size;
-  if (size === 'normal') return '25px';
-  if (size === 'large') return '40px';
-  if (size === 'huge') return '60px';
-  return '15px';
-}) as Ref<string>;
+const size = computed(() => getValueFromSize(props.size, ['15px', '25px', '40px', '60px']));
 const borderWidth = computed(() => (props.size === 'small' ? '2px' : '3px')) as Ref<string>;
 const borderRadius = computed(() => `calc(${size.value} * 0.3)`);
 
diff --git a/src/components/Paginator/Paginator.vue b/src/components/Paginator/Paginator.vue
index 7e6aa4b..14dfc4b 100644
--- a/src/components/Paginator/Paginator.vue
+++ b/src/components/Paginator/Paginator.vue
@@ -8,7 +8,7 @@ import PaginatorItem from '@components/Paginator/PaginatorItem.vue';
 import { computed, type Ref, watch } from 'vue';
 import Select from '@components/Select/Select.vue';
 import type { ISelectOption } from '@interfaces/componentsProp';
-import { convertThemeToColor, convertThemeToTextColor } from '@helpers/common';
+import { convertThemeToColor, convertThemeToTextColor, getValueFromSize } from '@helpers/common';
 
 const props = withDefaults(defineProps<IPaginatorProps>(), {
   total: 10,
@@ -45,21 +45,8 @@ const items = computed(() => {
   if (itemsPerView === 5) return [cur - 2, cur - 1, cur, cur + 1, cur + 2];
   return initArray.value;
 });
-const iconSize = computed(() => {
-  const size = props.size;
-  if (size === 'normal') return '10';
-  if (size === 'large') return '15';
-  if (size === 'huge') return '18';
-  return '7';
-});
-const fontSize = computed(() => {
-  if (props.fontSize) return props.fontSize;
-  const size = props.size;
-  if (size === 'normal') return '16px';
-  if (size === 'large') return '26px';
-  if (size === 'huge') return '32px';
-  return '12px';
-});
+const iconSize = computed(() => getValueFromSize(props.size, ['7', '10', '15', '18']));
+const fontSize = computed(() => getValueFromSize(props.size, ['12px', '16px', '26px', '32px']));
 const itemSize = computed(() => `${+iconSize.value * 2.5}px`);
 const color = computed(() => convertThemeToColor(props.theme, props.darknessTheme));
 const textColor = computed(() => convertThemeToTextColor(props.theme, props.darknessTheme));
diff --git a/src/components/ProgressBar/ProgressBar.vue b/src/components/ProgressBar/ProgressBar.vue
index 4bc23be..ee2cde7 100644
--- a/src/components/ProgressBar/ProgressBar.vue
+++ b/src/components/ProgressBar/ProgressBar.vue
@@ -1,7 +1,7 @@
 <script setup lang="ts">
 import type { IProgressBarProps } from '@interfaces/componentsProps';
 import { computed, ref, type Ref, watch } from 'vue';
-import { convertThemeToColor, convertThemeToTextColor } from '@helpers/common';
+import { convertThemeToColor, convertThemeToTextColor, getValueFromSize } from '@helpers/common';
 
 const props = withDefaults(defineProps<IProgressBarProps>(), {
   value: 0,
@@ -36,21 +36,8 @@ const inactiveColor = computed(() => {
   return convertThemeToColor(current.color, current.darknessColor);
 });
 const textColor = computed(() => convertThemeToTextColor(props.theme, props.darknessTheme));
-const fontSize = computed(() => {
-  if (props.fontSize) return props.fontSize;
-  const size = props.size;
-  if (size === 'normal') return '16px';
-  if (size === 'large') return '20px';
-  if (size === 'huge') return '24px';
-  return '12px';
-});
-const defaultHeight = computed(() => {
-  const size = props.size;
-  if (size === 'normal') return '30px';
-  if (size === 'large') return '45px';
-  if (size === 'huge') return '60px';
-  return '15px';
-});
+const fontSize = computed(() => getValueFromSize(props.size, ['12px', '16px', '20px', '24px']));
+const defaultHeight = computed(() => getValueFromSize(props.size, ['15px', '30px', '45px', '60px']));
 
 const isClickHold = ref<boolean>(false);
 
diff --git a/src/components/Rating/Rating.vue b/src/components/Rating/Rating.vue
index 57017ce..aef15bc 100644
--- a/src/components/Rating/Rating.vue
+++ b/src/components/Rating/Rating.vue
@@ -3,7 +3,7 @@ import type { IRatingProps } from '@interfaces/componentsProps';
 import { computed, type Ref, ref, watch } from 'vue';
 import { iconsSet } from '@/common/constants/icons';
 import StarFilledIcon from '@icons/Mono/StarFilledIcon.vue';
-import { convertThemeToColor } from '@helpers/common';
+import { convertThemeToColor, getValueFromSize } from '@helpers/common';
 
 const props = withDefaults(defineProps<IRatingProps>(), {
   count: 5,
@@ -30,13 +30,7 @@ const onHoverIndex = ref();
 const themeColor = computed(() => convertThemeToColor(props.theme, props.darknessTheme));
 const offColor = computed(() => (props.offTheme ? convertThemeToColor(props.offTheme, props.darknessTheme) : null));
 const themeColorOnHover = computed(() => convertThemeToColor(props.offTheme ?? props.theme, '200'));
-const iconSize = computed(() => {
-  const size = props.size;
-  if (size === 'normal') return '20px';
-  if (size === 'large') return '30px';
-  if (size === 'huge') return '40px';
-  return '10px';
-});
+const iconSize = computed(() => getValueFromSize(props.size, ['10px', '20px', '30px', '40px']) as string);
 const onActiveClick = (index: number) => {
   if (value.value > index) {
     value.value = index;
diff --git a/src/components/Tag/Tag.vue b/src/components/Tag/Tag.vue
index 1de0ac7..2b7d31b 100644
--- a/src/components/Tag/Tag.vue
+++ b/src/components/Tag/Tag.vue
@@ -1,7 +1,7 @@
 <script setup lang="ts">
 import type { ITagProps } from '@interfaces/componentsProps';
 import { computed } from 'vue';
-import { convertThemeToColor } from '@helpers/common';
+import { convertThemeToColor, getValueFromSize } from '@helpers/common';
 import { iconsSet } from '@/common/constants/icons';
 
 const props = withDefaults(defineProps<ITagProps>(), {
@@ -22,20 +22,8 @@ const backgroundColor = computed(() =>
 const borderColor = computed(() =>
   props.border ? convertThemeToColor(props.border, props.darknessBorder) : 'transparent',
 );
-const fontSize = computed(() => {
-  const size = props.size;
-  if (size === 'normal') return '16px';
-  if (size === 'large') return '20px';
-  if (size === 'huge') return '24px';
-  return '12px';
-});
-const padding = computed(() => {
-  const size = props.size;
-  if (size === 'normal') return '5px 11px';
-  if (size === 'large') return '6px 13px';
-  if (size === 'huge') return '7px 16px';
-  return '3px 7px';
-});
+const fontSize = computed(() => getValueFromSize(props.size, ['12px', '16px', '20px', '24px']));
+const padding = computed(() => getValueFromSize(props.size, ['3px 7px', '5px 11px', '6px 13px', '7px 16px']));
 </script>
 
 <template>
diff --git a/src/components/Toast/Toast.stories.ts b/src/components/Toast/Toast.stories.ts
index b63ccaf..df07b91 100644
--- a/src/components/Toast/Toast.stories.ts
+++ b/src/components/Toast/Toast.stories.ts
@@ -1,6 +1,7 @@
 import type { Meta, StoryObj } from '@storybook/vue3';
 
 import Toast from './Toast.vue';
+import { iconsSet } from '@/common/constants/icons';
 
 const meta: Meta = {
   title: 'Components/Toast',
@@ -14,7 +15,12 @@ const meta: Meta = {
     },
   },
   argTypes: {
+    type: { control: 'select', options: ['success', 'info', 'warn', 'error'] },
     size: { control: 'select', options: ['small', 'normal', 'large', 'huge'] },
+    width: { control: 'text' },
+    header: { control: 'text' },
+    text: { control: 'text' },
+    icon: { control: 'select', options: Object.keys(iconsSet) },
     theme: {
       control: 'select',
       options: [
@@ -49,11 +55,53 @@ export const Simple: Story = {
   },
 };
 
+export const Info: Story = {
+  args: {
+    active: true,
+    type: 'info',
+  },
+};
+
+export const Warn: Story = {
+  args: {
+    active: true,
+    type: 'warn',
+  },
+};
+
+export const Error: Story = {
+  args: {
+    active: true,
+    type: 'error',
+  },
+};
+
 export const Small: Story = {
   args: {
+    active: true,
     size: 'small',
-    theme: 'red',
-    value: 'Dangerous',
-    iconRight: 'Age18Icon',
+  },
+};
+
+export const Large: Story = {
+  args: {
+    active: true,
+    size: 'large',
+    width: '400px',
+    text: 'This is a text of large toast!',
+    icon: 'Award',
+    theme: 'sky',
+  },
+};
+
+export const Huge: Story = {
+  args: {
+    active: true,
+    size: 'huge',
+    width: '500px',
+    text: 'Oh, so huge... mmm.....',
+    icon: 'Badge',
+    theme: 'purple',
+    header: 'Custom header',
   },
 };
diff --git a/src/components/Toast/Toast.vue b/src/components/Toast/Toast.vue
index 176c1ae..389cd82 100644
--- a/src/components/Toast/Toast.vue
+++ b/src/components/Toast/Toast.vue
@@ -1,16 +1,27 @@
 <script setup lang="ts">
 import type { IToastProps } from '@interfaces/componentsProps';
-import { computed } from 'vue';
-import { convertThemeToColor } from '@helpers/common';
+import { computed, ref } from 'vue';
+import { convertThemeToColor, getValueFromSize } from '@helpers/common';
 import type { TToastType } from '@interfaces/componentsProp';
+import { iconsSet } from '@/common/constants/icons';
+import CrossIcon from '@icons/Mono/CrossIcon.vue';
+import type { TThemeColor } from '@interfaces/common';
 
 const props = withDefaults(defineProps<IToastProps>(), {
   type: 'success',
   text: 'This is a toast about success.',
   size: 'normal',
-  theme: 'green',
+  width: '300px',
+  position: 'topRight',
 });
 
+const typeToTheme: Record<TToastType, string> = {
+  success: 'green',
+  info: 'blue',
+  warn: 'yellow',
+  error: 'red',
+};
+
 const typeToHeader: Record<TToastType, string> = {
   success: 'Success Message',
   info: 'Info Message',
@@ -18,51 +29,118 @@ const typeToHeader: Record<TToastType, string> = {
   error: 'Error Message',
 };
 
+const typeToIcon: Record<TToastType, string> = {
+  success: 'CheckMark',
+  info: 'Info',
+  warn: 'Warning',
+  error: 'CrossRound',
+};
+
+const active = ref<boolean>(false);
+
+const themeColor = computed<TThemeColor>(() => props.theme ?? typeToTheme[props.type]);
 const header = computed<string>(() => props.header ?? typeToHeader[props.type]);
+const icon = computed(() => props.icon ?? typeToIcon[props.type]);
 
-const color = computed(() => convertThemeToColor(props.theme, '400'));
-const whiteOrBlack = computed(() => (props.theme === 'white' ? 'black' : 'white'));
+const color = computed(() => convertThemeToColor(themeColor.value, '400'));
+const whiteOrBlack = computed(() => (themeColor.value === 'white' ? 'black' : 'white'));
 const backgroundColor = computed(() =>
-  convertThemeToColor(props.theme === 'white' ? 'black' : props.theme === 'black' ? 'white' : props.theme, '700'),
+  convertThemeToColor(
+    themeColor.value === 'white' ? 'black' : themeColor.value === 'black' ? 'white' : themeColor.value,
+    '800',
+  ),
+);
+const borderColor = computed(() => convertThemeToColor(themeColor.value, '500'));
+const fontSize = computed(() => getValueFromSize(props.size, ['12px', '16px', '20px', '24px']));
+const padding = computed(() => getValueFromSize(props.size, ['7px 10px', '10px 15px', '14px 20px', '20px 30px']));
+const gap = computed(() =>
+  props.size === 'normal' ? '10px' : props.size === 'large' || props.size === 'huge' ? '15px' : '5px',
 );
-const borderColor = computed(() => convertThemeToColor(props.theme, '500'));
-const fontSize = computed(() => {
-  const size = props.size;
-  if (size === 'normal') return '16px';
-  if (size === 'large') return '20px';
-  if (size === 'huge') return '24px';
-  return '12px';
+const iconSize = computed(() => fontSize.value.slice(0, -2));
+const textMargin = computed(() => {
+  return +iconSize.value + +gap.value.slice(0, -2) + 'px';
 });
-const padding = computed(() => {
-  const size = props.size;
-  if (size === 'normal') return '5px 11px';
-  if (size === 'large') return '6px 13px';
-  if (size === 'huge') return '7px 16px';
-  return '3px 7px';
+const positionParts = computed(() => {
+  const result = [];
+  const position = props.position.toLowerCase();
+  if (position.includes('top')) result.push('top');
+  if (position.includes('bottom')) result.push('bottom');
+  if (position.includes('left')) result.push('left');
+  if (position.includes('right')) result.push('right');
+  return result;
 });
+const activeStyles = computed(() => {
+  let result = '';
+  if (positionParts.value[0] === 'top') result += 'top: 0;';
+  if (positionParts.value[0] === 'bottom') result += 'bottom: 0;';
+  if (positionParts.value[1] === 'left') result += 'left: 0;';
+  if (positionParts.value[1] === 'right') result += 'right: 0;';
+  return result;
+});
+
+const closeToast = () => {};
 </script>
 
 <template>
-  <section class="toast-container">
-    <h3 class="toast-header" :style="`font-size: calc(${fontSize} + 4px)`">{{ header }}</h3>
+  <section
+    class="toast-container"
+    :style="`position: ${static ? 'relative' : 'absolute'};
+    ${positionParts[0]}: ${positionParts[0] === 'top' ? '-100%' : '100%'};
+    ${positionParts[1]}: ${positionParts[1] === 'left' ? '-100%' : '100%'};
+    ${active ? activeStyles : null}`"
+  >
+    <h3 class="toast-header" :style="`font-size: calc(${fontSize} + 4px)`">
+      <component :is="iconsSet[icon]" :color="color" :size="iconSize" />
+      <span class="toast-header-text">{{ header }}</span>
+    </h3>
     <p class="toast-text">{{ text }}</p>
+    <CrossIcon
+      @click="closeToast"
+      class="toast-close_button"
+      :style="`top: ${padding.split(' ')[0]}; right: ${padding.split(' ')[1]}`"
+      :color="color"
+      :size="iconSize"
+    />
   </section>
 </template>
 
 <style scoped>
 .toast-container {
-  position: absolute;
   padding: v-bind(padding);
   border: 1px solid v-bind(borderColor);
   border-radius: 5px;
-  background-color: v-bind(backgroundColor);
+  width: v-bind(width);
+  ::before {
+    content: '';
+    position: absolute;
+    z-index: -1;
+    top: 0;
+    left: 0;
+    background-color: v-bind(backgroundColor);
+    width: 100%;
+    height: 100%;
+    opacity: 0.55;
+    border-radius: 4px;
+  }
 }
 .toast-header {
+  display: flex;
+  gap: v-bind(gap);
   color: v-bind(color);
   margin-bottom: 5px;
 }
+.toast-header-text {
+  font-weight: 500;
+}
 .toast-text {
+  margin-left: v-bind(textMargin);
   color: v-bind(whiteOrBlack);
   font-size: v-bind(fontSize);
 }
+.toast-close_button {
+  background-color: transparent;
+  position: absolute;
+  cursor: pointer;
+  display: block;
+}
 </style>
diff --git a/src/icons/Mono/CheckMarkIcon.vue b/src/icons/Mono/CheckMarkIcon.vue
index 05ab9bd..b13d20f 100644
--- a/src/icons/Mono/CheckMarkIcon.vue
+++ b/src/icons/Mono/CheckMarkIcon.vue
@@ -15,7 +15,7 @@ defineProps<Props>();
     xmlns="http://www.w3.org/2000/svg"
   >
     <path
-      d="M19 7.34189C18.6095 6.95136 17.9763 6.95136 17.5858 7.34189L10.3407 14.587C9.95016 14.9775 9.31699 14.9775 8.92647 14.587L6.38507 12.0456C5.99454 11.6551 5.36138 11.6551 4.97085 12.0456C4.58033 12.4361 4.58033 13.0693 4.97085 13.4598L7.51774 16C8.68969 17.1689 10.5869 17.1677 11.7574 15.9974L19 8.7561C19.3905 8.36558 19.3905 7.73241 19 7.34189Z"
+      d="M22.7048 4.95406C22.3143 4.56353 21.6811 4.56353 21.2906 4.95406L8.72696 17.5177C8.33643 17.9082 7.70327 17.9082 7.31274 17.5177L2.714 12.919C2.32348 12.5284 1.69031 12.5284 1.29979 12.919C0.909266 13.3095 0.909265 13.9427 1.29979 14.3332L5.90392 18.9289C7.07575 20.0986 8.97367 20.0978 10.1445 18.9271L22.7048 6.36827C23.0953 5.97775 23.0953 5.34458 22.7048 4.95406Z"
       :fill="color ?? '#000000'"
     />
   </svg>
diff --git a/src/icons/Mono/CrossCircleIcon.vue b/src/icons/Mono/CrossRoundFilledIcon.vue
similarity index 100%
rename from src/icons/Mono/CrossCircleIcon.vue
rename to src/icons/Mono/CrossRoundFilledIcon.vue
diff --git a/src/icons/Mono/CrossRoundIcon.vue b/src/icons/Mono/CrossRoundIcon.vue
new file mode 100644
index 0000000..8c14a47
--- /dev/null
+++ b/src/icons/Mono/CrossRoundIcon.vue
@@ -0,0 +1,23 @@
+<script setup lang="ts">
+interface Props {
+  color?: string;
+  size?: string | number;
+}
+defineProps<Props>();
+</script>
+
+<template>
+  <svg
+    :fill="color ?? '#000000'"
+    :width="`${size ?? 40}px`"
+    :height="`${size ?? 40}px`"
+    viewBox="0 0 32 32"
+    xmlns="http://www.w3.org/2000/svg"
+  >
+    <path
+      d="M0 16q0 3.264 1.28 6.208t3.392 5.12 5.12 3.424 6.208 1.248 6.208-1.248 5.12-3.424 3.392-5.12 1.28-6.208-1.28-6.208-3.392-5.12-5.088-3.392-6.24-1.28q-3.264 0-6.208 1.28t-5.12 3.392-3.392 5.12-1.28 6.208zM4 16q0-3.264 1.6-6.016t4.384-4.352 6.016-1.632 6.016 1.632 4.384 4.352 1.6 6.016-1.6 6.048-4.384 4.352-6.016 1.6-6.016-1.6-4.384-4.352-1.6-6.048zM9.76 20.256q0 0.832 0.576 1.408t1.44 0.608 1.408-0.608l2.816-2.816 2.816 2.816q0.576 0.608 1.408 0.608t1.44-0.608 0.576-1.408-0.576-1.408l-2.848-2.848 2.848-2.816q0.576-0.576 0.576-1.408t-0.576-1.408-1.44-0.608-1.408 0.608l-2.816 2.816-2.816-2.816q-0.576-0.608-1.408-0.608t-1.44 0.608-0.576 1.408 0.576 1.408l2.848 2.816-2.848 2.848q-0.576 0.576-0.576 1.408z"
+    ></path>
+  </svg>
+</template>
+
+<style scoped></style>
diff --git a/src/icons/Mono/InfoIcon.vue b/src/icons/Mono/InfoIcon.vue
new file mode 100644
index 0000000..32ee02d
--- /dev/null
+++ b/src/icons/Mono/InfoIcon.vue
@@ -0,0 +1,25 @@
+<script setup lang="ts">
+interface Props {
+  color?: string;
+  size?: string | number;
+}
+defineProps<Props>();
+</script>
+
+<template>
+  <svg
+    :width="`${size ?? 40}px`"
+    :height="`${size ?? 40}px`"
+    viewBox="0 0 20 20"
+    xmlns="http://www.w3.org/2000/svg"
+    fill="none"
+  >
+    <path
+      :fill="color ?? '#000000'"
+      fill-rule="evenodd"
+      d="M10 3a7 7 0 100 14 7 7 0 000-14zm-9 7a9 9 0 1118 0 9 9 0 01-18 0zm8-4a1 1 0 011-1h.01a1 1 0 110 2H10a1 1 0 01-1-1zm.01 8a1 1 0 102 0V9a1 1 0 10-2 0v5z"
+    />
+  </svg>
+</template>
+
+<style scoped></style>
diff --git a/src/icons/Mono/WarningIcon.vue b/src/icons/Mono/WarningIcon.vue
new file mode 100644
index 0000000..f6c17b0
--- /dev/null
+++ b/src/icons/Mono/WarningIcon.vue
@@ -0,0 +1,27 @@
+<script setup lang="ts">
+interface Props {
+  color?: string;
+  size?: string | number;
+}
+defineProps<Props>();
+</script>
+
+<template>
+  <svg
+    :width="`${size ?? 40}px`"
+    :height="`${size ?? 40}px`"
+    viewBox="0 0 24 24"
+    fill="none"
+    xmlns="http://www.w3.org/2000/svg"
+  >
+    <path
+      d="M12 15H12.01M12 12V9M4.98207 19H19.0179C20.5615 19 21.5233 17.3256 20.7455 15.9923L13.7276 3.96153C12.9558 2.63852 11.0442 2.63852 10.2724 3.96153L3.25452 15.9923C2.47675 17.3256 3.43849 19 4.98207 19Z"
+      :stroke="color ?? '#000000'"
+      stroke-width="2"
+      stroke-linecap="round"
+      stroke-linejoin="round"
+    />
+  </svg>
+</template>
+
+<style scoped></style>
-- 
GitLab