Commit 2daef95a authored by Дмитрий Малюгин's avatar Дмитрий Малюгин 🕓
Browse files

feat: component 'Rating'

parent 743bc88e
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -110,6 +110,7 @@ import TriangleIcon from '@stories/icons/Mono/TriangleIcon.vue';
import Playground from '@/Playground.vue';
import ArrowShortDownIcon from '@stories/icons/Mono/ArrowShortDownIcon.vue';
import StarIcon from '@stories/icons/Mono/StarIcon.vue';
import StarFilledIcon from '@stories/icons/Mono/StarFilledIcon.vue';

const gentleIcons = {
  Age18Icon,
@@ -214,6 +215,7 @@ const gentleIcons = {
  SearchIcon,
  SettingsIcon,
  StarIcon,
  StarFilledIcon,
  SortDownIcon,
  SortHorizontalIcon,
  SortUpIcon,
+10 −1
Original line number Diff line number Diff line
@@ -18,6 +18,8 @@ import Tag from '@stories/components/Tag/Tag.vue';
import Select from '@stories/components/Select/Select.vue';
import AtIcon from '@stories/icons/Mono/AtIcon.vue';
import Knob from '@stories/components/Knob/Knob.vue';
import Rating from '@stories/components/Rating/Rating.vue';
import HomeIcon from '@stories/icons/Mono/HomeIcon.vue';

const visibleDrawer = ref(false);
const sliderOptions: ISliderOptions[] = [
@@ -197,7 +199,14 @@ const knob = ref(0);

<template>
  <h2 class="title gradient-text">Playground</h2>
  {{ knob }}
  <Rating theme="red">
    <template #offIcon>
      <CrossIcon color="red" />
    </template>
    <template #onIcon>
      <HomeIcon color="blue" />
    </template>
  </Rating>
  <Knob v-model="knob" />
  <Select :options="selectOptions" theme="sky">
    <template #icon-left-First>
+2 −0
Original line number Diff line number Diff line
@@ -110,6 +110,7 @@ import SortVerticalIcon from '@stories/icons/Mono/SortVerticalIcon.vue';
import ArrowShortDownIcon from '@stories/icons/Mono/ArrowShortDownIcon.vue';
import SearchIcon from '@stories/icons/Mono/SearchIcon.vue';
import StarIcon from '@stories/icons/Mono/StarIcon.vue';
import StarFilledIcon from '@stories/icons/Mono/StarFilledIcon.vue';

export const iconsSet: Record<string, Component> = {
  Age18: Age18Icon,
@@ -214,6 +215,7 @@ export const iconsSet: Record<string, Component> = {
  Search: SearchIcon,
  Settings: SettingsIcon,
  Star: StarIcon,
  StarFilled: StarFilledIcon,
  SortDown: SortDownIcon,
  SortHorizontal: SortHorizontalIcon,
  SortUp: SortUpIcon,
+18 −29
Original line number Diff line number Diff line
@@ -14,17 +14,10 @@ const meta: Meta = {
    },
  },
  argTypes: {
    label: { control: 'text' },
    padding: { control: 'text' },
    count: { control: 'number' },
    gap: { control: 'text' },
    size: { control: 'select', options: ['small', 'normal', 'large', 'huge'] },
    textStyle: { control: 'select', options: ['bold', 'italic'] },
    iconPos: { control: 'select', options: ['left', 'top', 'right', 'bottom'] },
    width: { control: 'text' },
    darknessTheme: { control: 'select', options: ['100', '200', '300', '400', '500', '600', '700', '800', '900'] },
    darknessTextColor: {
      control: 'select',
      options: ['100', '200', '300', '400', '500', '600', '700', '800', '900'],
    },
    theme: {
      control: 'select',
      options: [
@@ -45,26 +38,6 @@ const meta: Meta = {
        'black',
      ],
    },
    textColor: {
      control: 'select',
      options: [
        'white',
        'blue',
        'sky',
        'cyan',
        'teal',
        'green',
        'yellow',
        'orange',
        'pink',
        'fuchsia',
        'purple',
        'indigo',
        'rose',
        'red',
        'black',
      ],
    },
  },
  args: {},
} satisfies Meta<typeof Rating>;
@@ -76,3 +49,19 @@ type Story = StoryObj<typeof meta>;
export const Simple: Story = {
  args: {},
};

export const Small: Story = {
  args: {
    size: 'small',
  },
};

export const Full: Story = {
  args: {
    theme: 'sky',
    darknessTheme: '400',
    count: 7,
    gap: '2px',
    size: 'huge',
  },
};
+65 −22
Original line number Diff line number Diff line
<script setup lang="ts">
import type { IRatingProps } from '@interfaces/componentsProps';
import { ref } from 'vue';
import { computed, type Ref, ref } from 'vue';
import { iconsSet } from '@/common/constants/icons';
import StarFilledIcon from '@stories/icons/Mono/StarFilledIcon.vue';
import { convertThemeToColor } from '@helpers/common';

const props = withDefaults(defineProps<IRatingProps>(), {
  count: 5,
  gap: '5px',
  size: 'normal',
  theme: 'black',
  darknessTheme: '500',
});

const value = defineModel();
const value = defineModel({
  default: 0,
}) as Ref<number>;
const onHoverIndex = ref();

// const textColor = computed(() => {});
const themeColor = computed(() => convertThemeToColor(props.theme, props.darknessTheme));
const themeColorOnHover = computed(() => convertThemeToColor(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 onActiveClick = (index: number) => {
  if (value.value > index) {
    value.value = index;
    return;
  }
  value.value = 0;
};
</script>

<template>
  {{ value }}
  <ul class="list">
    <li v-for="index of Array(count).keys()" :key="index" class="item">
  <ul class="list" :style="`gap: ${gap}`">
    <li v-for="index of Array(count).keys()" :key="index" class="item iconSize">
      <div v-show="value < index + 1 && !$slots.offIcon" class="iconSize iconContainer">
        <component
        class="icon"
        :is="iconsSet[icon ?? 'Star']"
        color="black"
          class="icon absoluteIcon"
          :is="iconsSet['Star']"
          :color="themeColor"
          @pointerenter="onHoverIndex = index"
          @pointerleave="onHoverIndex = null"
          :size="iconSize"
        />
        <Transition>
          <component
          class="hoverIcon"
            class="absoluteIcon"
            v-show="onHoverIndex === index"
          :is="iconsSet[icon ?? 'Star']"
          color="gray"
            :is="iconsSet['Star']"
            :color="themeColorOnHover"
            @pointerenter="onHoverIndex = index"
            @pointerleave="onHoverIndex = null"
            @click="value = index + 1"
      /></Transition>
            :size="iconSize"
          />
        </Transition>
      </div>
      <div v-show="value < index + 1" @click="value = index + 1">
        <slot name="offIcon" :size="iconSize"></slot>
      </div>
      <StarFilledIcon
        v-show="value >= index + 1 && !$slots.onIcon"
        :color="themeColor"
        :size="iconSize"
        class="absoluteIcon"
        @click="onActiveClick(index + 1)"
      />
      <div class="iconSize" v-show="value >= index + 1" @click="onActiveClick(index + 1)">
        <slot name="onIcon" :size="iconSize"></slot>
      </div>
    </li>
  </ul>
</template>
@@ -45,7 +85,6 @@ const onHoverIndex = ref();
.item {
  position: relative;
  cursor: pointer;
  transition: all 1s ease-in-out;
}
.icon {
  opacity: 1;
@@ -54,11 +93,15 @@ const onHoverIndex = ref();
    opacity: 0;
  }
}
.hoverIcon {
.absoluteIcon {
  position: absolute;
  top: 0;
  left: 0;
}
.iconSize {
  width: v-bind(iconSize);
  height: v-bind(iconSize);
}
.v-enter-active,
.v-leave-active {
  transition: opacity 0.15s ease;
Loading