_vertical-nav.scss 6.38 KB
@use "@core/scss/base/placeholders" as *;
@use "@core/scss/template/placeholders" as *;
@use "@layouts/styles/mixins" as layoutsMixins;
@use "@configured-variables" as variables;
@use "@core/scss/base/mixins" as mixins;
@use "vuetify/lib/styles/tools/states" as vuetifyStates;

.layout-nav-type-vertical {
  // 👉 Layout Vertical nav
  .layout-vertical-nav {
    $sl-layout-nav-type-vertical: &;

    @extend %nav;

    @at-root {
      // ℹ️ Add styles for collapsed vertical nav
      .layout-vertical-nav-collapsed#{$sl-layout-nav-type-vertical}.hovered {
        @include mixins.elevation(6);
      }
    }

    background-color: variables.$vertical-nav-background-color;

    // 👉 Nav header
    .nav-header {
      overflow: hidden;
      padding: variables.$vertical-nav-header-padding;
      margin-inline: variables.$vertical-nav-header-inline-spacing;
      min-block-size: variables.$vertical-nav-header-height;

      // TEMPLATE: Check if we need to move this to master
      .app-logo {
        flex-shrink: 0;
        transition: transform 0.25s ease-in-out;

        @at-root {
          // Move logo a bit to align center with the icons in vertical nav mini variant
          .layout-vertical-nav-collapsed#{$sl-layout-nav-type-vertical}:not(.hovered) .nav-header .app-logo {
            transform: translateX(variables.$vertical-nav-header-logo-translate-x-when-vertical-nav-mini);

            @include layoutsMixins.rtl {
              transform: translateX(-(variables.$vertical-nav-header-logo-translate-x-when-vertical-nav-mini));
            }
          }
        }
      }

      .app-title {
        margin-inline-start: variables.$vertical-nav-header-logo-title-spacing;
      }

      .header-action {
        @extend %nav-header-action;
      }
    }

    // 👉 Nav items shadow
    .vertical-nav-items-shadow {
      position: absolute;
      z-index: 1;
      background:
        linear-gradient(
          rgb(#{variables.$vertical-nav-background-color-rgb}) 5%,
          rgba(#{variables.$vertical-nav-background-color-rgb}, 75%) 45%,
          rgba(#{variables.$vertical-nav-background-color-rgb}, 20%) 80%,
          transparent
        );
      block-size: 55px;
      inline-size: 100%;
      inset-block-start: calc(#{variables.$vertical-nav-header-height} - 2px);
      opacity: 0;
      pointer-events: none;
      transition: opacity 0.15s ease-in-out;
      will-change: opacity;

      @include layoutsMixins.rtl {
        transform: translateX(8px);
      }
    }

    &.scrolled {
      .vertical-nav-items-shadow {
        opacity: 1;
      }
    }

    // ℹ️ Setting z-index 1 will make perfect scrollbar thumb appear on top of vertical nav items shadow;
    .ps__rail-y {
      z-index: 1;
    }

    // 👉 Nav section title
    .nav-section-title {
      @extend %vertical-nav-item;
      @extend %vertical-nav-section-title;

      margin-block-end: variables.$vertical-nav-section-title-mb;

      &:not(:first-child) {
        margin-block-start: variables.$vertical-nav-section-title-mt;
      }

      .placeholder-icon {
        margin-inline: auto;
      }
    }

    // Nav item badge
    .nav-item-badge {
      @extend %vertical-nav-item-badge;
    }

    // 👉 Nav group & Link
    .nav-link,
    .nav-group {
      overflow: hidden;

      > :first-child {
        @extend %vertical-nav-item;
        @extend %vertical-nav-item-interactive;
      }

      .nav-item-icon {
        @extend %vertical-nav-items-icon;
      }

      &.disabled {
        opacity: var(--v-disabled-opacity);
        pointer-events: none;
      }

      a {
        outline: none;
      }
    }

    // 👉 Vertical nav link
    .nav-link {
      @extend %nav-link;

      > .router-link-exact-active {
        @extend %nav-link-active;
      }

      > a {
        // Adds before psudo element to style hover state
        @include mixins.before-pseudo;

        // Adds vuetify states

        &:not(.router-link-active, .router-link-exact-active) {
          @include vuetifyStates.states($active: false);
        }
      }
    }

    // 👉 Vertical nav group
    .nav-group {
      // Reduce the size of icon if link/group is inside group
      .nav-group,
      .nav-link {
        .nav-item-icon {
          @extend %vertical-nav-items-nested-icon;
        }
      }

      // Hide icons after 2nd level
      & .nav-group {
        .nav-link,
        .nav-group {
          .nav-item-icon {
            @extend %vertical-nav-items-icon-after-2nd-level;
          }
        }
      }

      .nav-group-arrow {
        flex-shrink: 0;
        transform-origin: center;
        transition: transform variables.$vertical-nav-nav-group-arrow-transition-duration variables.$vertical-nav-nav-group-arrow-transition-timing-function;
        will-change: transform;
      }

      // Rotate arrow icon if group is opened
      &.open {
        > .nav-group-label .nav-group-arrow {
          transform: rotateZ(90deg);
        }
      }

      // Nav group label
      > :first-child {
        // Adds before psudo element to style hover state
        @include mixins.before-pseudo;
      }

      &:not(.active,.open) > :first-child {
        // Adds vuetify states
        @include vuetifyStates.states($active: false);
      }

      // Active & open states for nav group label
      &.active,
      &.open {
        > :first-child {
          @extend %vertical-nav-group-open-active;
        }
      }
    }
  }
}

// SECTION: Transitions
.vertical-nav-section-title-enter-active,
.vertical-nav-section-title-leave-active {
  transition: opacity 0.1s ease-in-out, transform 0.1s ease-in-out;
}

.vertical-nav-section-title-enter-from,
.vertical-nav-section-title-leave-to {
  opacity: 0;
  transform: translateX(15px);

  @include layoutsMixins.rtl {
    transform: translateX(-15px);
  }
}

.transition-slide-x-enter-active,
.transition-slide-x-leave-active {
  transition: opacity 0.1s ease-in-out, transform 0.12s ease-in-out;
}

.transition-slide-x-enter-from,
.transition-slide-x-leave-to {
  opacity: 0;
  transform: translateX(-15px);

  @include layoutsMixins.rtl {
    transform: translateX(15px);
  }
}

.vertical-nav-app-title-enter-active,
.vertical-nav-app-title-leave-active {
  transition: opacity 0.1s ease-in-out, transform 0.12s ease-in-out;
}

.vertical-nav-app-title-enter-from,
.vertical-nav-app-title-leave-to {
  opacity: 0;
  transform: translateX(-15px);

  @include layoutsMixins.rtl {
    transform: translateX(15px);
  }
}

// !SECTION