Skip to content
Snippets Groups Projects
Commit a93da3d4 authored by Дмитрий Малюгин's avatar Дмитрий Малюгин :clock4:
Browse files

feat: really finish with Drawer and add Divider

parent cef215c4
No related branches found
No related tags found
1 merge request!1Project setup and add 9 initial components
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<link rel="icon" href="./storybook.ico">
<title>Storybook</title>
</head>
<body>
</body>
</html>
\ No newline at end of file
......@@ -27,3 +27,9 @@ yarn dev
```sh
yarn build
```
## Важные моменты при разработке
После создания иконки:
1. Добавить иконку в iconsSet (src/common/constants/icons);
2. Добавить иконку в соответствующий массив в App.vue.
\ No newline at end of file
public/storybook.ico

213 KiB

import type { Component } from 'vue';
import Age18Icon from '@stories/icons/Mono/Age18Icon.vue';
import AirplaneIcon from '@stories/icons/Mono/AirplaneIcon.vue';
import AlarmIcon from '@stories/icons/Mono/AlarmIcon.vue';
import AlignCenterIcon from '@stories/icons/Mono/AlignCenterIcon.vue';
import AlignLeftIcon from '@stories/icons/Mono/AlignLeftIcon.vue';
import AlignRightIcon from '@stories/icons/Mono/AlignRightIcon.vue';
import AnchorIcon from '@stories/icons/Mono/AnchorIcon.vue';
import AnchorLinkIcon from '@stories/icons/Mono/AnchorLinkIcon.vue';
import ArchiveIcon from '@stories/icons/Mono/ArchiveIcon.vue';
import ArrowForwardIcon from '@stories/icons/Mono/ArrowForwardIcon.vue';
import ArrowLeftIcon from '@stories/icons/Mono/ArrowLeftIcon.vue';
import ArrowRightIcon from '@stories/icons/Mono/ArrowRightIcon.vue';
import ArrowsVerticalIcon from '@stories/icons/Mono/ArrowsVerticalIcon.vue';
import AtIcon from '@stories/icons/Mono/AtIcon.vue';
import AwardIcon from '@stories/icons/Mono/AwardIcon.vue';
import BackspaceIcon from '@stories/icons/Mono/BackspaceIcon.vue';
import BadgeIcon from '@stories/icons/Mono/BadgeIcon.vue';
import BallFootballIcon from '@stories/icons/Mono/BallFootballIcon.vue';
import BallIcon from '@stories/icons/Mono/BallIcon.vue';
import BanknoteIcon from '@stories/icons/Mono/BanknoteIcon.vue';
import BellIcon from '@stories/icons/Mono/BellIcon.vue';
import BellOffIcon from '@stories/icons/Mono/BellOffIcon.vue';
import BoxIcon from '@stories/icons/Mono/BoxIcon.vue';
import BrightnessIcon from '@stories/icons/Mono/BrightnessIcon.vue';
import BulbIcon from '@stories/icons/Mono/BulbIcon.vue';
import CalculatorIcon from '@stories/icons/Mono/CalculatorIcon.vue';
import CalendarAddIcon from '@stories/icons/Mono/CalendarAddIcon.vue';
import CalendarIcon from '@stories/icons/Mono/CalendarIcon.vue';
import CalendarRemoveIcon from '@stories/icons/Mono/CalendarRemoveIcon.vue';
import CardsIcon from '@stories/icons/Mono/CardsIcon.vue';
import ChartLineIcon from '@stories/icons/Mono/ChartLineIcon.vue';
import ChartPieIcon from '@stories/icons/Mono/ChartPieIcon.vue';
import ChatIcon from '@stories/icons/Mono/ChatIcon.vue';
import CrossCircleIcon from '@stories/icons/Mono/CrossCircleIcon.vue';
import CropIcon from '@stories/icons/Mono/CropIcon.vue';
import ChatWritingIcon from '@stories/icons/Mono/ChatWritingIcon.vue'
import CheckmarkIcon from '@stories/icons/Mono/CheckmarkIcon.vue'
import ChemistryFlaskIcon from '@stories/icons/Mono/ChemistryFlaskIcon.vue'
import CodeIcon from '@stories/icons/Mono/CodeIcon.vue'
import CoinsIcon from '@stories/icons/Mono/CoinsIcon.vue'
import ColorPaletteIcon from '@stories/icons/Mono/ColorPaletteIcon.vue'
import CompassIcon from '@stories/icons/Mono/CompassIcon.vue'
import ConstructionWorkerIcon from '@stories/icons/Mono/ConstructionWorkerIcon.vue'
import ContactsIcon from '@stories/icons/Mono/ContactsIcon.vue'
import CrossIcon from '@stories/icons/Mono/CrossIcon.vue'
import CubeIcon from '@stories/icons/Mono/CubeIcon.vue'
import CupIcon from '@stories/icons/Mono/CupIcon.vue'
import CursorIcon from '@stories/icons/Mono/CursorIcon.vue'
import DiamondIcon from '@stories/icons/Mono/DiamondIcon.vue'
import DiaryIcon from '@stories/icons/Mono/DiaryIcon.vue'
import DiceIcon from '@stories/icons/Mono/DiceIcon.vue'
import DigIcon from '@stories/icons/Mono/DigIcon.vue'
import DislikeIcon from '@stories/icons/Mono/DislikeIcon.vue'
import DisplayIcon from '@stories/icons/Mono/DisplayIcon.vue'
import DocumentIcon from '@stories/icons/Mono/DocumentIcon.vue'
import DocumentAddIcon from '@stories/icons/Mono/DocumentAddIcon.vue'
import DocumentDeleteIcon from '@stories/icons/Mono/DocumentDeleteIcon.vue'
import DocumentEditIcon from '@stories/icons/Mono/DocumentEditIcon.vue'
import DollarIcon from '@stories/icons/Mono/DollarIcon.vue'
import DotsHorizontalIcon from '@stories/icons/Mono/DotsHorizontalIcon.vue'
import DotsVerticalIcon from '@stories/icons/Mono/DotsVerticalIcon.vue'
import DownloadIcon from '@stories/icons/Mono/DownloadIcon.vue'
import DropIcon from '@stories/icons/Mono/DropIcon.vue'
import DumbbelIcon from '@stories/icons/Mono/DumbbelIcon.vue'
import EarthIcon from '@stories/icons/Mono/EarthIcon.vue'
import EditIcon from '@stories/icons/Mono/EditIcon.vue'
import EncyclopediaIcon from '@stories/icons/Mono/EncyclopediaIcon.vue'
import ExitIcon from '@stories/icons/Mono/ExitIcon.vue'
import EyeIcon from '@stories/icons/Mono/EyeIcon.vue'
import FeedbackIcon from '@stories/icons/Mono/FeedbackIcon.vue'
import FilterIcon from '@stories/icons/Mono/FilterIcon.vue'
import FingerprintIcon from '@stories/icons/Mono/FingerprintIcon.vue'
import FireIcon from '@stories/icons/Mono/FireIcon.vue'
import FlagIcon from '@stories/icons/Mono/FlagIcon.vue'
import FlashIcon from '@stories/icons/Mono/FlashIcon.vue'
import FlashlightIcon from '@stories/icons/Mono/FlashlightIcon.vue'
import FolderLockIcon from '@stories/icons/Mono/FolderLockIcon.vue'
import FrameIcon from '@stories/icons/Mono/FrameIcon.vue'
import FullScreenIcon from '@stories/icons/Mono/FullScreenIcon.vue'
import GameControllerIcon from '@stories/icons/Mono/GameControllerIcon.vue'
import GiftIcon from '@stories/icons/Mono/GiftIcon.vue'
import GlassesIcon from '@stories/icons/Mono/GlassesIcon.vue'
import HamburgerIcon from '@stories/icons/Mono/HamburgerIcon.vue'
import HandIcon from '@stories/icons/Mono/HandIcon.vue'
import HomeIcon from '@stories/icons/Mono/HomeIcon.vue'
import ImageIcon from '@stories/icons/Mono/ImageIcon.vue'
import ImageEditIcon from '@stories/icons/Mono/ImageEditIcon.vue'
import LineIcon from '@stories/icons/Mono/LineIcon.vue'
import LineDashedIcon from '@stories/icons/Mono/LineDashedIcon.vue'
import LineDottedIcon from '@stories/icons/Mono/LineDottedIcon.vue'
import LineDiagonalIcon from '@stories/icons/Mono/LineDiagonalIcon.vue'
import MoveIcon from '@stories/icons/Mono/MoveIcon.vue'
import ParagraphIcon from '@stories/icons/Mono/ParagraphIcon.vue'
import PhoneHandsetIcon from '@stories/icons/Mono/PhoneHandsetIcon.vue'
import PlusCircleIcon from '@stories/icons/Mono/PlusCircleIcon.vue'
import PlusIcon from '@stories/icons/Mono/PlusIcon.vue'
import PointerIcon from '@stories/icons/Mono/PointerIcon.vue'
import SaveIcon from '@stories/icons/Mono/SaveIcon.vue'
import SettingsIcon from '@stories/icons/Mono/SettingsIcon.vue'
import TableIcon from '@stories/icons/Mono/TableIcon.vue'
import TrashIcon from '@stories/icons/Mono/TrashIcon.vue'
import UserIcon from '@stories/icons/Mono/UserIcon.vue'
export const iconsSet: Record<string, Component> = {
Age18Icon: Age18Icon,
AirplaneIcon: AirplaneIcon,
AlarmIcon: AlarmIcon,
AlignCenterIcon: AlignCenterIcon,
AlignLeftIcon: AlignLeftIcon,
AlignRightIcon: AlignRightIcon,
AnchorIcon: AnchorIcon,
AnchorLinkIcon: AnchorLinkIcon,
ArchiveIcon: ArchiveIcon,
ArrowForwardIcon: ArrowForwardIcon,
ArrowLeftIcon: ArrowLeftIcon,
ArrowRightIcon: ArrowRightIcon,
ArrowsVerticalIcon: ArrowsVerticalIcon,
AtIcon: AtIcon,
AwardIcon: AwardIcon,
BackspaceIcon: BackspaceIcon,
BadgeIcon: BadgeIcon,
BallFootballIcon: BallFootballIcon,
BallIcon: BallIcon,
BanknoteIcon: BanknoteIcon,
BellIcon: BellIcon,
BellOffIcon: BellOffIcon,
BoxIcon: BoxIcon,
BrightnessIcon: BrightnessIcon,
BulbIcon: BulbIcon,
CalculatorIcon: CalculatorIcon,
CalendarAddIcon: CalendarAddIcon,
CalendarIcon: CalendarIcon,
CalendarRemoveIcon: CalendarRemoveIcon,
CardsIcon: CardsIcon,
ChartLineIcon: ChartLineIcon,
ChartPieIcon: ChartPieIcon,
ChatIcon: ChatIcon,
ChatWritingIcon: ChatWritingIcon,
CheckmarkIcon: CheckmarkIcon,
ChemistryFlaskIcon: ChemistryFlaskIcon,
CodeIcon: CodeIcon,
CoinsIcon: CoinsIcon,
ColorPaletteIcon: ColorPaletteIcon,
CompassIcon: CompassIcon,
ConstructionWorkerIcon: ConstructionWorkerIcon,
ContactsIcon: ContactsIcon,
CropIcon: CropIcon,
CrossIcon: CrossIcon,
CrossCircleIcon: CrossCircleIcon,
CubeIcon: CubeIcon,
CupIcon: CupIcon,
CursorIcon: CursorIcon,
DiamondIcon: DiamondIcon,
DiaryIcon: DiaryIcon,
DiceIcon: DiceIcon,
DigIcon: DigIcon,
DislikeIcon: DislikeIcon,
DisplayIcon: DisplayIcon,
DocumentIcon: DocumentIcon,
DocumentAddIcon: DocumentAddIcon,
DocumentDeleteIcon: DocumentDeleteIcon,
DocumentEditIcon: DocumentEditIcon,
DollarIcon: DollarIcon,
DotsHorizontalIcon: DotsHorizontalIcon,
DotsVerticalIcon: DotsVerticalIcon,
DownloadIcon: DownloadIcon,
DropIcon: DropIcon,
DumbbelIcon: DumbbelIcon,
EarthIcon: EarthIcon,
EditIcon: EditIcon,
EncyclopediaIcon: EncyclopediaIcon,
ExitIcon: ExitIcon,
EyeIcon: EyeIcon,
FeedbackIcon: FeedbackIcon,
FilterIcon: FilterIcon,
FingerprintIcon: FingerprintIcon,
FireIcon: FireIcon,
FlagIcon: FlagIcon,
FlashIcon: FlashIcon,
FlashlightIcon: FlashlightIcon,
FolderLockIcon: FolderLockIcon,
FrameIcon: FrameIcon,
FullScreenIcon: FullScreenIcon,
GameControllerIcon: GameControllerIcon,
GiftIcon: GiftIcon,
GlassesIcon: GlassesIcon,
HamburgerIcon: HamburgerIcon,
HandIcon: HandIcon,
HomeIcon: HomeIcon,
ImageIcon: ImageIcon,
ImageEditIcon: ImageEditIcon,
LineIcon: LineIcon,
LineDashedIcon: LineDashedIcon,
LineDottedIcon: LineDottedIcon,
LineDiagonalIcon: LineDiagonalIcon,
MoveIcon: MoveIcon,
ParagraphIcon: ParagraphIcon,
PhoneHandsetIcon: PhoneHandsetIcon,
PlusCircleIcon: PlusCircleIcon,
PlusIcon: PlusIcon,
PointerIcon: PointerIcon,
SaveIcon: SaveIcon,
SettingsIcon: SettingsIcon,
TableIcon: TableIcon,
TrashIcon: TrashIcon,
UserIcon: UserIcon,
};
import CrossCircleIcon from '@stories/icons/Mono/CrossCircleIcon.vue';
import CropIcon from '@stories/icons/Mono/CropIcon.vue';
import type { Component } from 'vue';
export const iconsSet: Record<string, Component> = {
CrossCircleIcon: CrossCircleIcon,
CropIcon: CropIcon,
};
import type { iconsSet } from '@/common/constants/icons';
export type TThemeColor =
| 'white'
| 'slate'
......@@ -14,3 +16,5 @@ export type TThemeColor =
| 'rose'
| 'red'
| 'black';
export type TIcons = keyof typeof iconsSet;
import type { Meta, StoryObj } from '@storybook/vue3';
import Divider from './Divider.vue';
const meta: Meta = {
title: 'Components/Divider',
component: Divider,
tags: ['autodocs'],
argTypes: {
height: { control: 'number' },
type: { control: 'select', options: ['solid', 'dashed', 'dotted'] },
color: {
control: 'select',
options: [
'white',
'slate',
'blue',
'sky',
'teal',
'green',
'yellow',
'orange',
'pink',
'fuchsia',
'purple',
'indigo',
'rose',
'red',
'black',
],
},
},
args: {
// primary: false,
// Use `fn` to spy on the onClick arg, which will appear in the actions panel once invoked: https://storybook.js.org/docs/essentials/actions#action-args
// onClick: fn(),
},
} satisfies Meta<typeof Divider>;
export default meta;
type Story = StoryObj<typeof meta>;
/*
*👇 Render functions are a framework specific feature to allow you control on how the component renders.
* See https://storybook.js.org/docs/api/csf
* to learn how to use render functions.
*/
export const Primary: Story = {
args: {},
};
export const RedDashed: Story = {
args: {
height: 2,
color: 'red',
type: 'dashed',
},
};
<script setup lang="ts">
import { computed } from 'vue';
import type { TThemeColor } from '@interfaces/common';
import { convert500ThemeToColor } from '@helpers/colors';
interface Props {
height?: number;
type?: 'solid' | 'dashed' | 'dotted';
color?: TThemeColor;
}
defineProps<Props>();
const props = withDefaults(defineProps<Props>(), {
height: 1,
type: 'solid',
color: 'black',
});
const colorConverted = computed(() => convert500ThemeToColor(props.color));
</script>
<template>
<div :style="`border-bottom: ${height ?? 1}px ${type ?? 'solid'} #6b7280`" class="w-full"></div>
<div :style="`border-bottom: ${height}px ${type} ${colorConverted}`" class="w-full"></div>
</template>
<style scoped></style>
import type { Meta, StoryObj } from '@storybook/vue3';
import Drawer from './Drawer.vue';
import { iconsSet } from '@/common/constants/icons';
const meta: Meta = {
title: 'Components/Drawer',
component: Drawer,
tags: ['autodocs'],
argTypes: {
visible: { control: 'boolean' },
position: { control: 'select', options: ['left', 'right', 'top', 'bottom'] },
width: { control: 'number' },
header: { control: 'text' },
default: { control: 'text' },
footer: { control: 'text' },
isModal: { control: 'boolean' },
isDismissible: { control: 'boolean' },
closeIcon: { control: 'select', options: Object.keys(iconsSet) },
isHeaderDivider: { control: 'boolean' },
isFooterDivider: { control: 'boolean' },
theme: {
control: 'select',
options: [
......@@ -27,11 +39,6 @@ const meta: Meta = {
'black',
],
},
visible: { control: 'boolean' },
width: { control: 'number' },
header: { control: 'text' },
default: { control: 'text' },
footer: { control: 'text' },
},
args: {
// primary: false,
......@@ -51,5 +58,24 @@ type Story = StoryObj<typeof meta>;
export const Primary: Story = {
args: {
visible: true,
default: 'Какой-то текст.',
},
};
export const BlackFull: Story = {
args: {
visible: true,
width: 200,
theme: 'black',
closeIcon: 'CrossIcon',
header: 'Drawer',
footer: 'The end.',
isHeaderDivider: true,
isFooterDivider: true,
default:
' Lorem ipsum dolor sit amet, consectetur adipisicing elit. Architecto dicta dolorum eaque explicabo illo. Beatae et eveniet itaque libero sint. Atque blanditiis consequuntur dolorum explicabo, facilis iste nulla numquam provident.',
isModal: true,
},
};
<script setup lang="ts">
import { convert500ThemeToColor, convert300ThemeToColor } from '@helpers/colors';
import type { TThemeColor } from '@interfaces/common';
import { computed } from 'vue';
import { iconsSet } from '@helpers/icons';
import { iconsSet } from '@/common/constants/icons';
import { convert500ThemeToColor, convert300ThemeToColor } from '@helpers/colors';
import type { TIcons, TThemeColor } from '@interfaces/common';
const props = withDefaults(
defineProps<{
position: 'left' | 'right' | 'top' | 'bottom';
width?: string | number;
theme?: TThemeColor;
closeIcon?: string;
isModal?: boolean;
isDismissible?: boolean;
closeIcon?: TIcons;
isHeaderDivider?: boolean;
isFooterDivider?: boolean;
}>(),
{
visible: false,
position: 'left',
width: 400,
isModal: true,
isDismissible: true,
theme: 'white',
closeIcon: 'CrossCircleIcon',
closeIcon: 'CrossIcon',
isHeaderDivider: false,
isFooterDivider: false,
},
);
const emit = defineEmits(['onClose']);
......@@ -27,28 +37,33 @@ const textColor = computed(() => {
return 'white';
});
const drawerWidth = computed(() => {
if (+props.width < 100) return '100px';
if (+props.width < 200) return '200px';
return `${props.width}px`;
});
</script>
<template>
<article>
<section
v-if="isModal"
:class="[
'drawerBackground',
{
drawerBackgroundOpened: visible,
},
]"
@click.prevent="visible = false"
@click.prevent="isDismissible ? (visible = false) : false"
></section>
<section
:style="`color: ${textColor}; background-color: ${themeColor}`"
:class="[
'drawer',
{
drawerLeft: position === 'left',
drawerRight: position === 'right',
drawerTop: position === 'top',
drawerBottom: position === 'bottom',
drawerOpened: visible,
drawerVertical: position === 'top' || position === 'bottom',
},
]"
>
......@@ -66,11 +81,12 @@ const drawerWidth = computed(() => {
<component :is="iconsSet[closeIcon]" :color="textColor" />
</button>
</header>
<div v-if="isHeaderDivider" class="divider divider-header"></div>
<div class="main">
<slot />
</div>
<div v-if="$slots.footer">
<div class="divider"></div>
<div v-if="isFooterDivider" class="divider"></div>
<footer class="drawerFooter">
<slot name="footer" />
</footer>
......@@ -98,47 +114,76 @@ const drawerWidth = computed(() => {
.drawer {
width: v-bind(drawerWidth);
position: fixed;
top: 0;
left: 0;
z-index: 31;
height: 100vh;
display: flex;
flex-direction: column;
justify-content: space-between;
padding: 20px;
transform: translateX(-100%);
transition: transform ease-out 0.2s;
border-right: 2px solid gray;
border-right: 2px solid #b1b1b1;
}
.drawerVertical {
width: 100vw !important;
height: v-bind(drawerWidth) !important;
}
.drawerOpened {
transform: translateX(0);
transform: translateX(0) !important;
}
.drawerLeft {
transform: translateX(-100%);
top: 0;
left: 0;
}
.drawerRight {
transform: translateX(100%);
top: 0;
right: 0;
}
.drawerTop {
transform: translateY(-100%);
top: 0;
left: 0;
}
.drawerBottom {
transform: translateY(100%);
bottom: 0;
left: 0;
}
.drawerHeader {
font-weight: bold;
font-size: 2rem;
padding-right: 50px;
font-size: 32px;
width: calc(100% - 30px);
margin-bottom: 10px;
min-height: 1rem;
height: 37px;
overflow: auto;
}
.main {
flex: 1 1 auto;
overflow: auto;
padding: 10px;
margin: 10px;
}
.drawerFooter {
overflow: auto;
padding: 10px 10px 0 10px;
overflow: auto;
}
.divider {
height: 2px;
background-color: v-bind(scrollColor);
}
.divider-header {
position: absolute;
left: 20px;
top: 65px;
width: calc(100% - 40px);
}
.buttonClose {
position: absolute;
top: 20px;
top: 25px;
right: 20px;
width: 30px;
display: flex;
align-items: center;
}
::-webkit-scrollbar {
width: 8px;
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment