NewsletterCreator / src / pages / IndexPage.vue
IndexPage.vue
Raw
<template>
  <q-page class="flex">
    <div class="column window-height full-width">
      <div class="col-2 justify-between flex">
        <img src="~assets/le-logo.svg" alt="Logo" id="logo" class="q-mt-xl q-ml-xl h-50">
        <p>Version {{ appVersion.toString().split('').join('.') }}</p>
      </div>
      <div class="col-5 row reverse">
        <div class="col-3 bg-secondary row justify-end content-center full-height">
          <div id="decorationUpperContainer" class="bg-accent flex flex-center">
            <q-icon class="q-ml-md" name="mail" color="primary" size="25vh" />
          </div>
          <div id="decorationLowerContainer" class="bg-dark">
            <q-icon class="q-ml-md" name="subject" color="primary" size="25vh" />
          </div>
        </div>
        <div class="col-8 bg-secondary items-center flex" id="titlearea">
          <div class="q-ml-lg">
            <h1>Newsletter Creator</h1>
            <div class="rotating-text-wrapper">
              <h2 class="font-md">{{ $t('inspiring') }}</h2>
              <h2 class="font-md">{{ $t('informative') }}</h2>
              <h2 class="font-md">{{ $t('innovative') }}</h2>
            </div>
          </div>
        </div>
      </div>
      <div class="col-5 row justify-between items-end">
        <div class="q-mb-xl w-50">
          <p class="font-s q-px-xl q-py-sm bg-accent" id="copyright">{{ $t('credit') }}</p>
        </div>
        <div class="q-mb-xl w-50 row justify-evenly">
          <q-btn color="primary" class="button q-mt-md" @click="loadBlankNewsletter">
            <div class="column items-center">
              <q-icon name="add" size="10vw" />
              <p class="font-md">{{ $t('create') }}</p>
              <p class="font-s">{{ $t('createSubSlogan') }}</p>
            </div>
          </q-btn>
          <q-btn color="primary" class="button q-mt-md" @click="triggerFileUpload">
            <div class="column items-center">
              <q-icon name="sym_o_folder_open" size="10vw" />
              <p class="font-md">{{ $t('open') }}</p>
              <p class="font-s">{{ $t('openSubSlogan') }}</p>
            </div>
          </q-btn>
          <input type="file" id="fileInput" accept=".newsletter" style="display: none" @change="handleFileChange">
        </div>
      </div>
    </div>
  </q-page>
  <q-dialog v-model="showErrorDialog">
    <q-card>
      <q-card-section class="row items-center q-pb-none">
        <div class="text-h6">Error</div>
        <q-space />
        <q-btn icon="close" flat round dense @click="showErrorDialog = false" />
      </q-card-section>

      <q-card-section>
        {{ errorMessage }}
      </q-card-section>
    </q-card>
  </q-dialog>
</template>

<script>
import { useNewsletterStore } from 'src/stores/newsletter.js'
import { useSettingsStore } from 'src/stores/settings.js'

export default {
  data () {
    return {
      showErrorDialog: false,
      errorMessage: '',
      appVersion: useSettingsStore().appVersion
    }
  },
  methods: {
    triggerFileUpload () {
      document.getElementById('fileInput').click()
      // TODO: alternatively use file system api and show modal with last opened files for more seamless experience
    },
    handleFileChange (event) {
      const file = event.target.files[0]
      if (file) {
        const reader = new FileReader()
        reader.onload = (e) => {
          const content = e.target.result
          try {
            this.openNewsletter(content)
          } catch (error) {
            console.error(error)
            event.target.value = ''
          }
        }
        reader.readAsText(file)
      }
    },
    loadBlankNewsletter () {
      const blankNewsletter =
      {
        title: '',
        creationTime: new Date().toDateString(),
        CreatorVersion: this.appVersion,
        sections: [
          {
            name: 'preface',
            elements: []
          },
          {
            name: 'offer',
            elements: []
          },
          {
            name: 'onTheGo',
            elements: []
          },
          {
            name: 'informed',
            elements: []
          },
          {
            name: 'connected',
            elements: []
          },
          {
            name: 'outro',
            elements: []
          }
        ]
      }
      this.openNewsletter(JSON.stringify(blankNewsletter))
      this.$router.push('/editor')
    },
    openNewsletter (content) {
      const { loadNewsletter } = useNewsletterStore()
      try {
        loadNewsletter(JSON.parse(content))
      } catch (error) {
        // show an error message
        this.errorMessage = error
        this.showErrorDialog = true
        throw error
      }
      this.$router.push('/editor')
    }
  },
  async mounted () {
    if (window.api && useNewsletterStore().newsletter.CreatorVersion === undefined) {
      const openedFile = await window.api.getFile()
      if (openedFile) {
        this.openNewsletter(openedFile)
      }
    } else {
      console.error('myAPI is not defined')
    }
  }

}
</script>

<style scoped lang="scss">
#logo {
  object-fit: contain;
}

#titlearea {
  border-top-left-radius: 36px;
  border-bottom-left-radius: 36px;
}

#decorationUpperContainer {
  height: 30%;
  width: 70%;
  border-top-left-radius: 36px;
  overflow: hidden;
}

#decorationLowerContainer {
  z-index: 1;
  height: 60%;
  width: 100%;
  border-top-left-radius: 36px;
  border-bottom-left-radius: 36px;
}

#copyright {
  display: inline;
  border-top-right-radius: 12px;
  border-bottom-right-radius: 12px;
}

.button {
  border-radius: 24px;
  width: 30%;
}

/* Animation based on https://codingyaar.com/rotating-text-animation-css/ */
.rotating-text-wrapper{
  margin-top: -2rem;
}
.rotating-text-wrapper h2 {
  animation-duration: 10s;
  animation-iteration-count: infinite;
  opacity: 0;
}
.rotating-text-wrapper h2:nth-child(1) {
  animation-name: rotating-text-1;
}
@keyframes rotating-text-1 {
  0% {
    transform: translateY(200%);
  }
  23% {
    transform: translateY(100%);
    opacity: 1;
  }
  33% {
    opacity: 0;
  }
}
.rotating-text-wrapper h2:nth-child(2) {
  animation-name: rotating-text-2;
}
@keyframes rotating-text-2 {
  33% {
    transform: translateY(100%);
    opacity: 0;
  }
  56% {
    transform: translateY(0);
    opacity: 1;
  }
  66% {
    opacity: 0;
  }
}
.rotating-text-wrapper h2:nth-child(3) {
  animation-name: rotating-text-3;
}
@keyframes rotating-text-3 {
  66% {
    transform: translateY(0);
    opacity: 0;
  }
  89% {
    transform: translateY(-100%);
    opacity: 1;
  }
  99% {
    transform: translateY(-100%);
    opacity: 0;
  }
}
@media screen and (max-width: 576px) {
  .rotating-text-wrapper {
    font-size: 0.7rem;
  }
}

</style>