Header.vue 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182
  1. <template>
  2. <div>
  3. <header
  4. class="flex space-x-2 flex-1 py-2 px-2 items-center justify-between"
  5. >
  6. <div class="space-x-2 inline-flex items-center">
  7. <ButtonSecondary
  8. class="tracking-wide !font-bold !text-secondaryDark hover:bg-primaryDark focus-visible:bg-primaryDark"
  9. label="HOPPSCOTCH"
  10. to="/"
  11. />
  12. <AppGitHubStarButton class="mt-1.5 transition hidden sm:flex" />
  13. </div>
  14. <div class="space-x-2 inline-flex items-center">
  15. <ButtonSecondary
  16. id="installPWA"
  17. v-tippy="{ theme: 'tooltip' }"
  18. :title="t('header.install_pwa')"
  19. svg="download"
  20. class="rounded hover:bg-primaryDark focus-visible:bg-primaryDark"
  21. @click.native="showInstallPrompt()"
  22. />
  23. <ButtonSecondary
  24. v-tippy="{ theme: 'tooltip' }"
  25. :title="`${t('app.search')} <kbd>/</kbd>`"
  26. svg="search"
  27. class="rounded hover:bg-primaryDark focus-visible:bg-primaryDark"
  28. @click.native="showSearch = true"
  29. />
  30. <ButtonSecondary
  31. v-tippy="{ theme: 'tooltip' }"
  32. :title="`${t('support.title')} <kbd>?</kbd>`"
  33. svg="life-buoy"
  34. class="rounded hover:bg-primaryDark focus-visible:bg-primaryDark"
  35. @click.native="showSupport = true"
  36. />
  37. <ButtonSecondary
  38. v-if="currentUser === null"
  39. svg="upload-cloud"
  40. :label="t('header.save_workspace')"
  41. filled
  42. class="hidden md:flex"
  43. @click.native="showLogin = true"
  44. />
  45. <ButtonPrimary
  46. v-if="currentUser === null"
  47. :label="t('header.login')"
  48. @click.native="showLogin = true"
  49. />
  50. <div v-else class="space-x-2 inline-flex items-center">
  51. <ButtonPrimary
  52. v-tippy="{ theme: 'tooltip' }"
  53. :title="t('team.invite_tooltip')"
  54. :label="t('team.invite')"
  55. svg="user-plus"
  56. class="!bg-green-500 !bg-opacity-15 !text-green-500 !hover:bg-opacity-10 !hover:bg-green-400 !hover:text-green-600"
  57. @click.native="showTeamsModal = true"
  58. />
  59. <span class="px-2">
  60. <tippy ref="user" interactive trigger="click" theme="popover" arrow>
  61. <template #trigger>
  62. <ProfilePicture
  63. v-if="currentUser.photoURL"
  64. v-tippy="{
  65. theme: 'tooltip',
  66. }"
  67. :url="currentUser.photoURL"
  68. :alt="currentUser.displayName"
  69. :title="currentUser.displayName"
  70. indicator
  71. :indicator-styles="isOnLine ? 'bg-green-500' : 'bg-red-500'"
  72. />
  73. <ButtonSecondary
  74. v-else
  75. v-tippy="{ theme: 'tooltip' }"
  76. :title="t('header.account')"
  77. class="rounded hover:bg-primaryDark focus-visible:bg-primaryDark"
  78. svg="user"
  79. />
  80. </template>
  81. <SmartItem
  82. to="/profile"
  83. svg="user"
  84. :label="t('navigation.profile')"
  85. @click.native="$refs.user.tippy().hide()"
  86. />
  87. <SmartItem
  88. to="/settings"
  89. svg="settings"
  90. :label="t('navigation.settings')"
  91. @click.native="$refs.user.tippy().hide()"
  92. />
  93. <FirebaseLogout @confirm-logout="$refs.user.tippy().hide()" />
  94. </tippy>
  95. </span>
  96. </div>
  97. </div>
  98. </header>
  99. <AppAnnouncement v-if="!isOnLine" />
  100. <FirebaseLogin :show="showLogin" @hide-modal="showLogin = false" />
  101. <AppSupport :show="showSupport" @hide-modal="showSupport = false" />
  102. <AppPowerSearch :show="showSearch" @hide-modal="showSearch = false" />
  103. <TeamsModal :show="showTeamsModal" @hide-modal="showTeamsModal = false" />
  104. </div>
  105. </template>
  106. <script setup lang="ts">
  107. import { onMounted, ref } from "@nuxtjs/composition-api"
  108. import intializePwa from "~/helpers/pwa"
  109. import { probableUser$ } from "~/helpers/fb/auth"
  110. import { getLocalConfig, setLocalConfig } from "~/newstore/localpersistence"
  111. import {
  112. useReadonlyStream,
  113. useI18n,
  114. useToast,
  115. } from "~/helpers/utils/composables"
  116. import { defineActionHandler } from "~/helpers/actions"
  117. const t = useI18n()
  118. const toast = useToast()
  119. /**
  120. * Once the PWA code is initialized, this holds a method
  121. * that can be called to show the user the installation
  122. * prompt.
  123. */
  124. const showInstallPrompt = ref(() => Promise.resolve()) // Async no-op till it is initialized
  125. const showSupport = ref(false)
  126. const showSearch = ref(false)
  127. const showLogin = ref(false)
  128. const showTeamsModal = ref(false)
  129. const isOnLine = ref(navigator.onLine)
  130. const currentUser = useReadonlyStream(probableUser$, null)
  131. defineActionHandler("modals.support.toggle", () => {
  132. showSupport.value = !showSupport.value
  133. })
  134. defineActionHandler("modals.search.toggle", () => {
  135. showSearch.value = !showSearch.value
  136. })
  137. onMounted(() => {
  138. window.addEventListener("online", () => {
  139. isOnLine.value = true
  140. })
  141. window.addEventListener("offline", () => {
  142. isOnLine.value = false
  143. })
  144. // Initializes the PWA code - checks if the app is installed,
  145. // etc.
  146. showInstallPrompt.value = intializePwa()
  147. const cookiesAllowed = getLocalConfig("cookiesAllowed") === "yes"
  148. if (!cookiesAllowed) {
  149. toast.show(`${t("app.we_use_cookies")}`, {
  150. duration: 0,
  151. action: [
  152. {
  153. text: `${t("action.learn_more")}`,
  154. onClick: (_, toastObject) => {
  155. setLocalConfig("cookiesAllowed", "yes")
  156. toastObject.goAway(0)
  157. window.open("https://docs.hoppscotch.io/privacy", "_blank")?.focus()
  158. },
  159. },
  160. {
  161. text: `${t("action.dismiss")}`,
  162. onClick: (_, toastObject) => {
  163. setLocalConfig("cookiesAllowed", "yes")
  164. toastObject.goAway(0)
  165. },
  166. },
  167. ],
  168. })
  169. }
  170. })
  171. </script>