Skip to content
Snippets Groups Projects
Drawer.vue 4.51 KiB
Newer Older
import { computed, type Ref, watch } from 'vue';
import { iconsSet } from '@/common/constants/icons';
import type { IDrawerProps } from '@interfaces/componentsProps';
import { convertThemeToColor, convertThemeToSecondaryColor, convertThemeToTextColor } from '@helpers/common';
import type { CustomWindow } from '@interfaces/common';
const props = withDefaults(defineProps<IDrawerProps>(), {
  position: 'left',
  width: 400,
  modal: true,
  dismissible: true,
  theme: 'white',
  closeIcon: 'Cross',
  headerDivider: false,
  footerDivider: false,
});
const body = document.querySelector('body')!;
const emit = defineEmits(['onClose']);
const visible = defineModel<boolean>('visible', {
  set(value) {
    if (!value) {
      (window as CustomWindow).blockPopupActions = false;
      body.style.paddingRight = '0';
      emit('onClose');
    }
    return value;
  },
watch(visible, () => {
  if (visible.value) {
    (window as CustomWindow).blockPopupActions = true;
    body.style.paddingRight = '14px';
  }
});
const themeColor = computed(() => convertThemeToColor(props.theme, props.darknessTheme));
const secondaryColor = computed(() => convertThemeToSecondaryColor(props.theme, props.darknessTheme));
const color = computed(() =>
  props.textColor
    ? convertThemeToColor(props.textColor, props.darknessTextColor)
    : convertThemeToTextColor(props.theme, props.darknessTheme),
const drawerWidth = computed(() => {
  if (+props.width < 200) return '200px';
  return `${props.width}px`;
});
</script>
<template>
  <article>
    <section
      :class="[
        'drawerBackground',
        {
          drawerBackgroundOpened: visible,
        },
      ]"
      @pointerdown="() => (dismissible ? (visible = false) : '')"
          drawerLeft: position === 'left',
          drawerRight: position === 'right',
          drawerTop: position === 'top',
          drawerBottom: position === 'bottom',
          drawerVertical: position === 'top' || position === 'bottom',
        },
      ]"
    >
      <header class="drawerHeader">
        <slot name="header" />
        <button class="buttonClose" @click.prevent="visible = false">
      <div v-if="headerDivider" class="divider divider-header"></div>
      <div class="main">
        <slot />
      </div>
      <div v-if="$slots.footer">
        <div v-if="footerDivider" class="divider"></div>
        <footer class="drawerFooter">
          <slot name="footer" />
        </footer>
      </div>
    </section>
  </article>
</template>

<style scoped>
.drawerBackground {
  position: fixed;
  top: 0;
  left: 0;
  width: 100vw;
  height: 100vh;
  background-color: rgba(0, 0, 0, 0.5);
  transition: all ease-out 0.2s;
  z-index: -50;
  opacity: 0;
}
.drawerBackgroundOpened {
  z-index: 200;
  opacity: 1;
}
.drawer {
  width: v-bind(drawerWidth);
  position: fixed;
  z-index: 201;
  height: 100vh;
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  padding: 20px;
  transition: transform ease-out 0.2s;
}
.drawerVertical {
  width: 100vw !important;
  height: v-bind(drawerWidth) !important;
  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: 32px;
  width: calc(100% - 30px);
  margin-bottom: 10px;
  overflow: auto;
}
.main {
  flex: 1 1 auto;
  overflow: auto;
  padding: 10px 10px 0 10px;
}
.divider {
  height: 2px;
.divider-header {
  position: absolute;
  left: 20px;
  top: 65px;
  width: calc(100% - 40px);
}
.buttonClose {
  position: absolute;
  display: flex;
  align-items: center;
}
::-webkit-scrollbar-thumb {
  border-radius: 5px;