|  | 
|  | 1 | +<template> | 
|  | 2 | +  <Header /> | 
|  | 3 | +  <HeroSection /> | 
|  | 4 | +  <Roadmap /> | 
|  | 5 | +  <Teleport to="body"> | 
|  | 6 | +  <div v-if="content" :class="['fixed top-0 h-screen', sidebarClass]"> | 
|  | 7 | +    <div | 
|  | 8 | +        class="prose dark:prose-invert max-w-full flex overflow-y-auto overflow-x-hidden h-full w-full flex-col items-center p-4 focus:outline-0 sm:p-6 bg-orange-50 dark:bg-gray-800" | 
|  | 9 | +    > | 
|  | 10 | +      <div class="w-full flex flex-row justify-between px-4 pb-2"> | 
|  | 11 | +        <Dropdown | 
|  | 12 | +          ref="statusDropDown" | 
|  | 13 | +          :customTriggerClass="['px-4 py-2 border-black border', status.toLowerCase()]" | 
|  | 14 | +          :border="false" | 
|  | 15 | +        > | 
|  | 16 | +          <!-- trigger element --> | 
|  | 17 | +          <template #trigger> | 
|  | 18 | +            <button type="button" v-text="status"/> | 
|  | 19 | +          </template> | 
|  | 20 | + | 
|  | 21 | +          <!-- contents display in dropdown --> | 
|  | 22 | +          <ul class="flex flex-col bg-orange-100 dark:bg-gray-600"> | 
|  | 23 | +            <li | 
|  | 24 | +              v-for="(s, i) in allStatus" | 
|  | 25 | +              :key="'status-' + i" | 
|  | 26 | +              @click="changeStatus(s)" | 
|  | 27 | +              :class="['px-4 py-2 hover:cursor-pointer border-b border-black hover:bg-orange-50 dark:hover:bg-gray-500', s.toLowerCase()]" | 
|  | 28 | +              v-text="s" | 
|  | 29 | +            > | 
|  | 30 | +            </li> | 
|  | 31 | +          </ul> | 
|  | 32 | +        </Dropdown> | 
|  | 33 | +        <span class="hover:cursor-pointer" @click="closeSidebar">X</span> | 
|  | 34 | +      </div> | 
|  | 35 | +      <ContentRenderer :key="content._id" :value="content"> | 
|  | 36 | +        <ContentRendererMarkdown class="flex flex-col w-full m:max-w-[800px] sm:max-w-[600px]" tag="article" :value="content" /> | 
|  | 37 | +        <div class="flex flex-col items-start w-full m:max-w-[800px] sm:max-w-[600px]"> | 
|  | 38 | +          <h4 id="related-content" class="mb-3"> | 
|  | 39 | +            <a href="#related-content">Contenido Extra Relacionado</a> | 
|  | 40 | +          </h4> | 
|  | 41 | +          <a | 
|  | 42 | +            class="gap-x-2 mb-1" | 
|  | 43 | +            v-for="(link, i) in content.data.externalLinks.sort((a, b) => a.english - b.english)" | 
|  | 44 | +            :key="i" | 
|  | 45 | +            :href="link.link" | 
|  | 46 | +            > | 
|  | 47 | +              <Card moreTransparency > | 
|  | 48 | +                <strong v-if="link.english">[Contenido en Ingles]</strong> | 
|  | 49 | +                {{link.name}} | 
|  | 50 | +              </Card> | 
|  | 51 | +          </a> | 
|  | 52 | +        </div> | 
|  | 53 | +      </ContentRenderer> | 
|  | 54 | +    </div> | 
|  | 55 | +  </div> | 
|  | 56 | +  </Teleport> | 
|  | 57 | +</template> | 
|  | 58 | + | 
|  | 59 | +<script setup lang="ts"> | 
|  | 60 | +import { useRoute } from 'vue-router' | 
|  | 61 | +import { ref, onMounted } from 'vue' | 
|  | 62 | +import Roadmap from '@/components/Roadmap.vue' | 
|  | 63 | +import HeroSection from '@/layouts/hero.vue' | 
|  | 64 | +import Dropdown from 'v-dropdown' | 
|  | 65 | +
 | 
|  | 66 | +const { $locally } = useNuxtApp() | 
|  | 67 | +
 | 
|  | 68 | +const allStatus = [ 'Pendiente', 'Leyendo', 'Completado', 'Omitir' ] | 
|  | 69 | +const route = useRoute() | 
|  | 70 | +const nodeId = route.params.slug | 
|  | 71 | +const showSidebar = ref(true) | 
|  | 72 | +const content = ref(null) | 
|  | 73 | +const statusDropDown = ref(null) | 
|  | 74 | +const status = ref($locally.get(nodeId) ?? 'Pendiente') | 
|  | 75 | +
 | 
|  | 76 | +
 | 
|  | 77 | +onMounted(async () => { | 
|  | 78 | +  if (!nodeId) return | 
|  | 79 | +  const contentResult = await queryContent(nodeId.join("/")).findOne() | 
|  | 80 | +  content.value = contentResult | 
|  | 81 | +  showSidebar.value = contentResult && (route.query.fromClick || false) | 
|  | 82 | +}) | 
|  | 83 | +
 | 
|  | 84 | +const closeSidebar = () => { | 
|  | 85 | +  content.value = null; | 
|  | 86 | +  document.body.classList.remove('overflow-hidden') | 
|  | 87 | +} | 
|  | 88 | +const sidebarClass = computed(() => showSidebar.value ? 'right-0 w-screen lg:w-2/4' : 'w-screen') | 
|  | 89 | +
 | 
|  | 90 | +function changeStatus(val) { | 
|  | 91 | +  if (val == status.value) return | 
|  | 92 | +  if (!statusDropDown.value) return | 
|  | 93 | +  status.value = val | 
|  | 94 | +  $locally.set(nodeId, val) | 
|  | 95 | +  statusDropDown.value.close() | 
|  | 96 | +} | 
|  | 97 | +</script> | 
|  | 98 | + | 
|  | 99 | +<style> | 
|  | 100 | +.pendiente::before, | 
|  | 101 | +.leyendo::before, | 
|  | 102 | +.completado::before, | 
|  | 103 | +.omitir::before { | 
|  | 104 | +  content: '•'; | 
|  | 105 | +  margin-right: 5px; | 
|  | 106 | +} | 
|  | 107 | +
 | 
|  | 108 | +.pendiente::before { color: var(--tw-text-gray-950); } | 
|  | 109 | +.leyendo::before { color: var(--tw-text-orange-500); } | 
|  | 110 | +.completado::before { color: var(--tw-text-green-600); } | 
|  | 111 | +.omitir::before { color: var(--tw-text-slate-500); } | 
|  | 112 | +
 | 
|  | 113 | +.v-dropdown-container.v-dropdown-no-border { border-radius: 0px !important } | 
|  | 114 | +</style> | 
0 commit comments