Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
quantum-kittens
GitHub Repository: quantum-kittens/platypus
Path: blob/main/frontend/vue/components/UtilityPanel/UtilityPanel.vue
3375 views
<template>
  <section class="utility-panel" :class="{ 'utility-panel_open': isVisible, 'utility-panel_closed': !isVisible }">
    <UtilityPanelHeader
      ref="panelHeader"
      class="utility-panel__header"
      :label="getLabel()"
      @updatePanelStatus="togglePanel"
      @selectedPanelTitle="getSelectedPanelTitle"
    />
    <UtilityPanelContent
      ref="panelContent"
      class="utility-panel__content"
      :selection="selectedPanelTitle"
      :notations-data="filteredNotations"
      :vocabulary-data="filteredVocabulary"
      @emptyStateRedirect="redirectToPanel"
    />
  </section>
</template>

<script lang="ts">
import { Vue, Options, prop } from 'vue-class-component'
import UtilityPanelHeader from './UtilityPanelHeader.vue'
import UtilityPanelContent from './UtilityPanelContent.vue'

export interface Notation {
  html: string
  say?: string
  meaning: string
  type?: string
  sections: any[]
}

interface NotationsJson {
  [key: string] : Notation
}

export interface Term {
  title: string
  text: string[]
  sections: any[]
}

interface TermsJson {
  [key: string] : Term
}

class Props {
  notations = prop<Notation>({})
  glossaryTerms = prop<Term>({})
}

@Options({
  components: { UtilityPanelHeader, UtilityPanelContent },
  computed: {
    filteredNotations (): Notation[] {
      const data = document.getElementById('notations')
      const sectionNode = document.querySelector('x-course')
      const finalNotations: Notation[] = []

      if (data && sectionNode) {
        const sectionTitle = sectionNode.getAttribute('data-section')
        const notationsParsed = JSON.parse(data.innerHTML) as NotationsJson
        const notationsKeys = Object.keys(notationsParsed).filter(key => !key.startsWith('_'))
        const notationsArr = notationsKeys.map(key => notationsParsed[key])

        notationsArr.forEach((item: Notation) => {
          if (item.sections.includes(sectionTitle)) {
            finalNotations.push(item)
          }
        })
      }

      this.notationsData = finalNotations

      return finalNotations
    },
    filteredVocabulary ():Term[] {
      const data = document.getElementById('glossary')
      const sectionNode = document.querySelector('x-course')
      const finalVocabulary: Term[] = []

      if (data && sectionNode) {
        const vocabularyParsed = JSON.parse(data.innerHTML) as TermsJson
        const vocabularyArr = Object.values(vocabularyParsed)
        const sectionTitle = sectionNode.getAttribute('data-section')

        vocabularyArr.forEach((item) => {
          if (item.sections.includes(sectionTitle)) {
            finalVocabulary.push(item)
          }
        })
      }

      this.vocabData = finalVocabulary

      return finalVocabulary
    }
  },
  methods: {
    getSelectedPanelTitle (val: any) {
      const refPanelContent: any = this.$refs.panelContent
      this.selectedPanelTitle = val
      refPanelContent.chooseTitle(val)
    }
  }
})

export default class UtilityPanel extends Vue.with(Props) {
  isVisible = true;
  selectedPanelTitle:string = ''
  isMobile = false;

  notationsData = []
  vocabData = []

  mounted () {
    this.detectSmallScreen()
  }

  detectSmallScreen () {
    const rootComponent = this
    window.addEventListener('load', function () {
      const HTMLFrame = document.getElementsByTagName('html')[0]
      const mobileDetected = HTMLFrame.classList.contains('is-mobile')

      if (window.innerWidth <= 1056 || mobileDetected) {
        rootComponent.isVisible = false
        rootComponent.isMobile = true
      }
      // handling tablet use case
      if (window.innerWidth >= 672 && window.innerWidth <= 1056) {
        rootComponent.isVisible = true
        rootComponent.isMobile = true
      }
    })
  }

  togglePanel (val: boolean) {
    this.isVisible = val
  }

  getLabel () {
    if (this.isVisible) {
      return 'Hide'
    } else {
      return 'Show details'
    }
  }

  redirectToPanel (e:string) {
    const refPanelContent: any = this.$refs.panelContent
    const refPanelHeader: any = this.$refs.panelHeader
    this.selectedPanelTitle = e
    refPanelContent.chooseTitle(e)
    refPanelHeader.getUpdatedPanelSelection(e)
  }
}
</script>

<style lang="scss">
@use 'sass:math';
@import 'carbon-components/scss/globals/scss/typography';
@import '../../../scss/variables/settings.scss';
@import '../../../scss/variables/colors.scss';
@import '../../../scss/variables/mq.scss';

.utility-panel {
  background-color: $background-color-white;
  width: 100%;
  height: auto;
  user-select: text;

  @include mq($until: small) {
    top: 6rem;
  }

  &__header {
    flex: 0 0 auto;
  }

  &__content {
    flex: 1 0 0;
    overflow: auto;
    padding-bottom: $spacing-13;
  }

  &_open {
    width: 100%;
    border-left: 1px solid $border-color;
    max-width: $right-sidebar-width-xl;
    min-height: 100vh;
    flex-direction: column;
    display: flex;

    @include mq($from: x-large) {
      max-width: $right-sidebar-width-xl;
    }

    @include mq($from: large, $until: x-large) {
      max-width: $right-sidebar-width-lg;
    }

    @include mq($from: medium, $until: large) {
      max-width: math.div($right-sidebar-width-xl, 1.5);
    }

    @include mq($from: max-size) {
      max-width: $right-sidebar-width-max;
    }

    @include mq($until: medium) {
      max-width: initial;

      .app-cta__content {
        display: none;
      }

      .app-cta {
        width: 3.25rem;
      }

      .utility-panel-header {
        border-bottom: 1px solid $border-color;
      }
    }

    p:hover {
      cursor: text;
    }
  }

  &_closed {
    width: 10rem;
    background-color: transparent;

    .utility-panel-dropdown,
    .utility-panel-content {
      display: none;
    }

    .utility-panel-header {
      justify-content: flex-end;
    }

    .app-cta__icon_arrow-right-16 {
      transform: rotate(-180deg);
    }

    @include mq($until: medium) {
      width: 100%;

      .utility-panel-header {
        border-bottom: 1px solid $border-color;
      }
    }
  }

}
</style>