kodadot/nft-gallery

View on GitHub
pages/blog/index.vue

Summary

Maintainability
Test Coverage
<template>
  <div class="content">
    <div class="content-headline text-center">
      <h1 class="title is-1 relative z-[1]">
        KodaDot Blog
      </h1>
      <div class="relative z-[1] text-2xl mb-20 font-medium">
        Let’s Explore The NFT Universe
      </div>
      <img
        class="content-headline-cover"
        src="/blog-cover.png"
        alt="KodaDot Blog"
      >
    </div>

    <div
      v-for="post in posts?.featured.slice(0, 1)"
      :key="post.title"
      class="relative z-[1] mb-20 content-list"
    >
      <div
        class="content-list-cover"
        :style="{ backgroundImage: `url(${post.image})` }"
      />

      <div class="content-list-card">
        <div>
          <div class="card-tag">
            • {{ post.tags }}
          </div>
          <p class="title is-4">
            <nuxt-link :to="post._path">
              {{ post.title }}
            </nuxt-link>
          </p>
          <div class="truncate mb-4">
            {{ post.subtitle }}
          </div>
        </div>

        <div>
          <NeoButton
            :tag="NuxtLink"
            :to="post._path"
            no-shadow
            rounded
            icon="arrow-right-long"
          >
            View Article
          </NeoButton>
        </div>
      </div>
    </div>

    <!-- article section with 2 grid cols -->
    <h2 class="title is-2">
      Tokens
    </h2>
    <div class="content-list-grid content-list-grid-2">
      <nuxt-link
        v-for="post in posts?.tokensPosts.slice(0, 2)"
        :key="post.title"
        class="content-board block"
        :to="post._path"
      >
        <div
          class="content-board-cover"
          :style="{ backgroundImage: `url(${post.image})` }"
        />
        <div class="content-board-text">
          <p class="font-bold">
            {{ post.title }}
          </p>
          <div class="content-board-subtitle">
            {{ post.subtitle }}
          </div>
        </div>
      </nuxt-link>
    </div>

    <!-- article section -->
    <h2 class="title is-2">
      Latest Posts
    </h2>
    <div class="content-list-grid">
      <nuxt-link
        v-for="post in posts?.posts"
        :key="post.title"
        class="content-board block"
        :to="post._path"
      >
        <div
          class="content-board-cover"
          :style="{ backgroundImage: `url(${post.image})` }"
        />
        <div class="content-board-text">
          <p class="font-bold">
            {{ post.title }}
          </p>
          <div class="content-board-subtitle">
            {{ post.subtitle }}
          </div>
        </div>
      </nuxt-link>
    </div>
  </div>
</template>

<script lang="ts" setup>
import { NeoButton } from '@kodadot1/brick'
import { resolveComponent } from 'vue'

const NuxtLink = resolveComponent('NuxtLink')
const { data: posts } = useAsyncData('posts', async () => {
  const contents = await queryContent('/').find()
  const tags = {
    tokens: 'Tokens',
  }
  const latestPosts = contents.sort(
    (content_a, content_b) =>
      +new Date(content_b.date) - +new Date(content_a.date),
  )

  const reduce = latestPosts.reduce(
    (acc, post, index) => {
      if (index === 0) {
        acc.featured.push(post)
        return acc
      }
      if (post.tags === tags.tokens) {
        acc.tokensPosts.push(post)
      }
      acc.posts.push(post)
      return acc
    },
    {
      featured: [],
      posts: [],
      tokensPosts: [],
    },
  )

  return reduce
})
</script>

<style lang="scss">
@import '@/assets/styles/abstracts/variables';

.content {
  margin: 0 auto;
  max-width: 60rem;

  &-headline {
    &-cover {
      position: absolute;
      top: -100%;
      left: 50%;
      transform: translateX(-50%);
      height: 25rem;
    }

    h1 {
      letter-spacing: -0.02em;
      @include ktheme() {
        color: theme('text-color-inverse');
        text-shadow:
          1px 1px 0 theme('text-color'),
          1px -1px 0 theme('text-color'),
          -1px 1px 0 theme('text-color'),
          -1px -1px 0 theme('text-color'),
          1px 0px 0 theme('text-color'),
          0px 1px 0 theme('text-color'),
          -1px 0px 0 theme('text-color'),
          0px -1px 0 theme('text-color'),
          4px 4px theme('text-color');
      }
    }

    @include touch {
      h1 {
        font-size: 2rem;
      }

      .subtitle {
        font-size: 1rem;
        margin-bottom: 2.5rem;
      }
    }
  }

  &-board {
    border-radius: 1rem;
    overflow: hidden;

    &-cover {
      @apply border-b border-card-border-color;
    }

    @include ktheme() {
      border: 1px solid theme('card-border-color');
      background-color: theme('background-color');

      &:hover {
        border-color: theme('border-color');

        p,
        div {
          color: theme('text-color');
        }

        .content-board-cover {
          opacity: theme('card-hover-opacity');
        }
      }
    }

    &-cover {
      background-size: cover;
      background-position: center;
      height: 8rem;
    }

    &-text {
      padding: 1rem;
    }

    &-subtitle {
      max-width: 300px;
      display: -webkit-box;
      -webkit-line-clamp: 3;
      -webkit-box-orient: vertical;
      overflow: hidden;
    }
  }

  &-list {
    @apply overflow-hidden flex h-[22rem] rounded-[2.5rem];

    @include touch {
      height: auto;
    }

    &-grid {
      display: grid;
      grid-template-columns: repeat(3, minmax(0, 1fr));
      grid-gap: 1.5rem;
      margin-bottom: 1.5rem;

      &-2 {
        grid-template-columns: repeat(2, minmax(0, 1fr));

        .content-board-cover {
          height: 14rem;
        }
      }

      @include until(769px) {
        grid-template-columns: repeat(2, minmax(0, 1fr));
      }

      @include until(426px) {
        grid-template-columns: repeat(1, minmax(0, 1fr));
      }
    }

    &-cover {
      background-size: cover;
      background-position: center;
      width: 40rem;
      max-height: 22rem;
    }

    &-card {
      display: flex;
      flex-direction: column;
      justify-content: space-between;
      padding: 1.5rem;
      width: 20rem;

      .card-tag {
        @include ktheme() {
          color: theme('k-grey-fix');
        }
      }

      .truncate {
        display: -webkit-box;
        -webkit-line-clamp: 3;
        -webkit-box-orient: vertical;
        overflow: hidden;
      }

      .title {
        display: -webkit-box;
        -webkit-box-orient: vertical;
        -webkit-line-clamp: 4;
        overflow: hidden;
      }
    }

    @include ktheme() {
      background-color: theme('k-white');
      border: 1px solid theme('border-color');
      box-shadow: 4px 4px 0px 0px theme('border-color');

      &-cover {
        border-right: 1px solid theme('border-color');
      }
    }

    @include touch {
      flex-direction: column;

      &-cover {
        border-right: none !important;
        height: 20rem;
        width: 100%;
      }

      &-card {
        &-title {
          font-size: 1.5rem;
        }
      }

      .o-btn {
        margin-top: 1rem;
      }
    }
  }
}
</style>