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

feat: component "Checkbox"

parent f9bc1598
Loading
Loading
Loading
Loading
+7 −0
Original line number Diff line number Diff line
@@ -13,6 +13,7 @@ import Popup from '@stories/components/Popup/Popup.vue';
import Table from '@stories/components/Table/Table.vue';
import { ref } from 'vue';
import type { ISBOption, ISliderOptions, ITableColumn } from '@interfaces/componentsProp';
import Checkbox from '@stories/components/Checkbox/Checkbox.vue';

const visibleDrawer = ref(false);
const sliderOptions: ISliderOptions[] = [
@@ -178,10 +179,16 @@ const tableData = [
    },
  ],
];
const activeCheckbox = ref();
</script>

<template>
  <h2 class="title gradient-text">Playground</h2>
  {{ activeCheckbox }}
  <Checkbox v-model:active="activeCheckbox" size="small" />
  <Checkbox v-model:active="activeCheckbox" />
  <Checkbox v-model:active="activeCheckbox" size="large" />
  <Checkbox v-model:active="activeCheckbox" size="huge" />
  <Table
    show-all-lines
    :columns="tableColumns"
+17 −0
Original line number Diff line number Diff line
@@ -157,6 +157,23 @@ export interface ITSProps {
  disabled?: boolean;
}

export interface ICheckboxProps {
  label?: string;
  labelPos?: TPosition;
  name?: string;
  size?: TSize;
  disabled?: boolean;
  invalid?: boolean;
  theme?: TThemeColor;
  activeTheme?: TThemeColor;
  textColor?: TThemeColor;
  borderColor?: TThemeColor;
  darknessTheme?: TDarkness;
  darknessActiveTheme?: TDarkness;
  darknessTextColor?: TDarkness;
  darknessBorderColor?: TDarkness;
}

export interface IDividerProps {
  height?: number;
  type?: TBorder;
+171 −0
Original line number Diff line number Diff line
import type { Meta, StoryObj } from '@storybook/vue3';

import Checkbox from './Checkbox.vue';

const meta: Meta = {
  title: 'Components/Checkbox',
  component: Checkbox,
  tags: ['autodocs'],
  parameters: {
    docs: {
      description: {
        component: 'A component that is used as a Checkbox. Can be used with icon.',
      },
    },
  },
  argTypes: {
    active: { control: 'boolean' },
    invalid: { control: 'boolean' },
    disabled: { control: 'boolean' },
    label: { control: 'text' },
    name: { control: 'text' },
    size: { control: 'select', options: ['small', 'normal', 'large', 'huge'] },
    labelPos: { control: 'select', options: ['left', 'top', 'right', 'bottom'] },
    darknessTheme: { control: 'select', options: ['100', '200', '300', '400', '500', '600', '700', '800', '900'] },
    darknessActiveTheme: {
      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'],
    },
    darknessBorderColor: {
      control: 'select',
      options: ['100', '200', '300', '400', '500', '600', '700', '800', '900'],
    },
    theme: {
      control: 'select',
      options: [
        'white',
        'blue',
        'sky',
        'cyan',
        'teal',
        'green',
        'yellow',
        'orange',
        'pink',
        'fuchsia',
        'purple',
        'indigo',
        'rose',
        'red',
        'black',
      ],
    },
    activeTheme: {
      control: 'select',
      options: [
        'white',
        'blue',
        'sky',
        'cyan',
        'teal',
        'green',
        'yellow',
        'orange',
        'pink',
        'fuchsia',
        'purple',
        'indigo',
        'rose',
        'red',
        'black',
      ],
    },
    textColor: {
      control: 'select',
      options: [
        'white',
        'blue',
        'sky',
        'cyan',
        'teal',
        'green',
        'yellow',
        'orange',
        'pink',
        'fuchsia',
        'purple',
        'indigo',
        'rose',
        'red',
        'black',
      ],
    },
    borderColor: {
      control: 'select',
      options: [
        'white',
        'blue',
        'sky',
        'cyan',
        'teal',
        'green',
        'yellow',
        'orange',
        'pink',
        'fuchsia',
        'purple',
        'indigo',
        'rose',
        'red',
        'black',
      ],
    },
  },
  args: {},
} satisfies Meta<typeof Checkbox>;

export default meta;

type Story = StoryObj<typeof meta>;

export const Simple: Story = {
  args: {
    active: true,
  },
};

export const Small: Story = {
  args: {
    active: false,
    size: 'small',
    theme: 'yellow',
    activeTheme: 'blue',
    darknessTheme: '300',
    darknessActiveTheme: '700',
    label: 'Are you gay?',
  },
};

export const Large: Story = {
  args: {
    active: true,
    size: 'large',
    theme: 'green',
    activeTheme: 'sky',
    darknessTheme: '700',
    darknessActiveTheme: '300',
    label: 'Checkbox',
    labelPos: 'top',
    invalid: true,
  },
};

export const Huge: Story = {
  args: {
    active: false,
    size: 'huge',
    theme: 'indigo',
    activeTheme: 'purple',
    darknessTheme: '500',
    darknessActiveTheme: '500',
    label: 'Checkbox',
    textColor: 'blue',
    invalid: false,
    disabled: true,
    labelPos: 'left',
  },
};
+143 −0
Original line number Diff line number Diff line
<script setup lang="ts">
import type { ICheckboxProps } from '@interfaces/componentsProps';
import { computed } from 'vue';
import { convertThemeToColor, convertThemeToTextColor } from '@helpers/common';
import CheckMarkIcon from '@stories/icons/Mono/CheckMarkIcon.vue';

const props = withDefaults(defineProps<ICheckboxProps>(), {
  label: '',
  name: '',
  labelPos: 'right',
  size: 'normal',
  theme: 'white',
  activeTheme: 'black',
  textColor: 'black',
  borderColor: 'black',
  darknessTheme: '500',
  darknessActiveTheme: '500',
  darknessTextColor: '500',
  darknessBorderColor: '500',
});
const active = defineModel('active');
// watch(, () => {});
const themeColor = computed(() => convertThemeToColor(props.theme, props.darknessTheme));
const activeThemeColor = computed(() => convertThemeToColor(props.activeTheme, props.darknessActiveTheme));
const iconColor = computed(() =>
  props.disabled ? '#62708c' : convertThemeToTextColor(props.activeTheme, props.darknessActiveTheme),
);
const color = computed(() => convertThemeToColor(props.textColor, props.darknessTextColor));
const borderColor = computed(() =>
  props.invalid
    ? 'red'
    : props.disabled
      ? '#62708c'
      : convertThemeToColor(props.borderColor, props.darknessBorderColor),
);
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 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';
});
const borderWidth = computed(() => (props.size === 'large' || props.size === 'huge' ? 2 : 1));
const borderRadius = computed(() => `${elSize.value / 7 - borderWidth.value}px`);
</script>

<template>
  <section
    :class="[
      'container',
      {
        flexColumn: ['top', 'bottom'].includes(labelPos),
      },
    ]"
    @click.prevent="!disabled ? (active = !active) : ''"
  >
    <div class="main" :style="`width: ${elSize}px; height: ${elSize}px; border: ${borderWidth}px solid ${borderColor}`">
      <input
        :style="`width: ${elSize}px; height: ${elSize}px; position: absolute; z-index: 100; cursor: ${disabled ? 'initial' : 'pointer'}`"
        v-model="active"
        type="checkbox"
        :name="name"
        :value="label"
        :disabled="disabled"
      />
      <div
        :class="[
          {
            inactive: !active,
            active: active,
            disabled: disabled,
          },
        ]"
      >
        <CheckMarkIcon
          :style="`transition: all 0.3s ease-in-out; opacity: ${active ? 1 : 0}; position: absolute;`"
          :color="iconColor"
          :size="elSize"
        />
      </div>
    </div>
    <p
      :class="[
        {
          first: ['top', 'left'].includes(labelPos),
        },
      ]"
      :style="`color: ${color}; line-height: 0.9; font-size: ${elSize}px; pointer-events: none`"
    >
      {{ label }}
    </p>
  </section>
</template>

<style scoped>
.container {
  position: relative;
  display: flex;
  gap: v-bind(gap);
  box-sizing: content-box;
  width: max-content;
}
.main {
  position: relative;
  border-radius: 15%;
}
.inactive {
  height: 100%;
  border-radius: v-bind(borderRadius);

  background-color: v-bind(themeColor);
  transition: all 0.2s ease-in-out;
}
.active {
  width: 100%;
  height: 100%;
  border-radius: v-bind(borderRadius);
  background-color: v-bind(activeThemeColor);
  transition: all 0.2s ease-in-out;
}
.disabled {
  background-color: #e1e7f1 !important;
}
.first {
  order: -1;
}
.flexColumn {
  flex-direction: column;
  align-items: center;
}
input[type='checkbox'] {
  all: unset;
  width: 100%;
}
</style>
+0 −1
Original line number Diff line number Diff line
@@ -222,7 +222,6 @@ export const Full: Story = {
        },
      ],
    ],

    fontSize: '24px',
    showAllLines: true,
    border: 'fuchsia',
Loading