Alpine-tabs

HTML
<div
  class="content"
  x-data
  @colorchange="$el.style.backgroundColor = $event.detail.hex"
>
  <div
    class="card"
    x-data="{ currentTab: 'Colors' }"
    @tab-change="currentTab = $event.detail"
  >
    <div class="tabs" x-data="tabs()">
      <template x-for="tab in items" :key="tab">
        <button
          class="tab"
          x-bind:class="{ 'selected': tab === current }"
          x-text="tab"
          x-on:click="
            changeTab(tab)
            $dispatch('tab-change', tab)
          "
        ></button>
      </template>
    </div>
    <div x-show="currentTab === 'Colors'" class="card-content">
      <div x-data="colors()">
        <h2 class="title" x-bind:style="'color:' + getCurrentColor().hex">
          Pick a color
        </h2>
        <div class="colors">
          <template x-for="color in list" :key="color.name">
            <!-- Template Literals are allowed to use with x-bindings -->
            <div
              class="color"
              x-bind:style="`background-color: ${color.hex}`"
              @click="
                changeColor(color.name)
                $dispatch('colorchange', color)
              "
            ></div>
          </template>
        </div>
      </div>
    </div>
    <div x-show="currentTab === 'Quotes'" class="card-content">
      <div x-data="quotes()" x-init="fetchQuote()">
        <div class="quote">
          <p class="text" x-text='`"${quote.quote}"`'></p>
          <p class="author" x-text="'~ ' + quote.author"></p>
        </div>
        <h2 class="error" x-show="Boolean(error)" x-text="error"></h2>
        <div class="button-container">
          <button class="button" @click="fetchQuote()" x-show="!loading">
            Refresh
          </button>
          <div x-show="loading" class="lds-dual-ring"></div>
        </div>
      </div>
    </div>
    <div x-show="currentTab === 'About'" class="card-content">
      <div x-data="{ open: false }" class="button-container">
        <button x-show="!open" class="button" @click="open = true">
          Show content
        </button>
        <p x-show.transition="open" class="credits">
          A lot of thanks to
          <a
            class="mention"
            href="https://twitter.com/calebporzio"
            target="_blank"
          >
            @calebporzio
          </a>
          for this incredible and useful library.
          <br />
          <br />
          <a class="mention" href="https://speckyboy.com/" target="_blank">
            Speckyboy
          </a>
          for this fancy and awesome design idea.
          <br />
          <br />
          And finally thanks to
          <a
            class="mention"
            href="https://github.com/shevabam"
            target="_blank"
            >Shevabam</a
          >
          for an amazing Breaking Bad Quotes API.
        </p>
      </div>
    </div>
  </div>
  <footer class="footer">
    <p>
      Coded by
      <a
        href="https://github.com/jhonny9550"
        target="_blank"
        class="mention mention-alt"
        >jhonny9550</a
      >
    </p>
  </footer>
</div>

<!--
    https://medium.com/@jhonny9550/alpine-js-ser%C3%A1-tu-mejor-aliado-d5d9a8756edb
-->
CSS
body {
  margin: 0;
}

html,
body,
.content {
  height: 100%;
}

*,
*::after,
*::before {
  box-sizing: border-box;
}

* {
  font-family: Verdana, Geneva, Tahoma, sans-serif !important;
}

.content {
  align-items: center;
  background-color: #47a1df;
  display: flex;
  padding: 48px;
}

.card {
  border-radius: 8px;
  flex: 1;
  margin: 0 auto;
  max-width: 800px;
  overflow: hidden;
}

.tabs {
  display: flex;
}

.tab {
  background-color: transparent;
  border: none;
  color: #fff;
  cursor: pointer;
  flex-grow: 1;
  font-size: 18px;
  padding: 12px;
}

.tab:focus {
  outline: none;
}

.tab.selected {
  background-color: #fff;
  border-radius: 8px 8px 0 0;
  color: #424242;
}

.card-content {
  background-color: #fff;
  min-height: 300px;
  padding: 48px 24px;
}

.title {
  font-weight: 400;
  text-align: center;
}

.colors {
  display: flex;
  justify-content: center;
  padding: 12px 0;
}

.color {
  border-radius: 50%;
  box-shadow: 0 6px 3px rgba(0, 0, 0, 0.13);
  cursor: pointer;
  height: 50px;
  margin: 0 12px;
  width: 50px;
}

.color:hover {
  transform: scale(1.2);
}

.error {
  color: rgb(255, 66, 66);
  text-align: center;
}

.quote {
  color: #424242;
  font-size: 16px;
  margin: 0 auto;
  max-width: 50%;
  padding: 24px;
}

.quote > .text {
  font-style: italic;
}

.quote > .author {
  font-weight: 600;
  text-align: right;
}

.button {
  background-color: transparent;
  border: 1px solid #3A87BB;
  border-radius: 5px;
  color: #3A87BB;
  cursor: pointer;
  font-size: 16px;
  padding: 10px 24px;
}

.button-container {
  text-align: center;
}

.credits {
  padding: 12px;
}

.mention {
  color: #3A87BB;
  font-size: 20px;
  text-decoration: none;
}

.mention-alt {
  color: #424242;
}

.footer {
  bottom: 0;
  color: #FFF;
  font-size: 24px;
  left: 0;
  position: fixed;
  text-align: center;
  width: 100%;
}

/* Loader */
.lds-dual-ring {
  display: inline-block;
  width: 44px;
  height: 44px;
}
.lds-dual-ring:after {
  content: " ";
  display: block;
  width: 40px;
  height: 40px;
  margin: 3px;
  border-radius: 50%;
  border: 6px solid #424242;
  border-color: #424242 transparent #424242 transparent;
  animation: lds-dual-ring 1.2s linear infinite;
}
@keyframes lds-dual-ring {
  0% {
    transform: rotate(0deg);
  }
  100% {
    transform: rotate(360deg);
  }
}

@media only screen and (max-width: 600px) {
  .content {
    padding: 12px;
  }
  .card-content {
    min-height: 300px;
    padding: 24px 0;
  }
  .color {
    height: 36px;
    width: 36px;
  }
  .quote {
    max-width: unset;
  }
}
JS
function tabs() {
  return {
    current: 'Colors',
    items: ['Colors', 'Quotes', 'About'],
    changeTab(tab) {
      this.current = tab;
    }
  };
}

function colors() {
  return {
    list: [
      { hex: '#2DCC72', name: 'green' },
      { hex: '#D64A4B', name: 'red' },
      { hex: '#8E46AC', name: 'purple' },
      { hex: '#3A87BB', name: 'blue' },
      { hex: '#BFC4C8', name: 'gray' }
    ],
    selected: 'blue',
    changeColor(name) {
      this.selected = name;
    },
    getCurrentColor() {
      return this.list.find(c => c.name === this.selected);
    }
  };
}

function quotes() {
  return {
    quote: {},
    error: null,
    loading: false,
    async fetchQuote() {
      const apiUrl = 'https://breaking-bad-quotes.herokuapp.com/v1/quotes';
      this.loading = true;
      try {
        const result = await fetch(apiUrl);
        const [quote] = await result.json();
        this.quote = quote;
      } catch (error) {
        this.error = 'Oops. Something went wrong.';
      }
      this.loading = false;
    }
  };
}

Autor: William

Publicado: 03/12/2020

Compartir Elemento Web

Donar a Compositu
Otras formas de ayudar
  • Compártelo en tus redes sociales.
  • Recomienda los elementos.
  • Regístrate Aquí
  • Deja tu comentario agradeciendo el aporte.

Descarga el código completo del Elemento Web y archivos necesarios (imágenes, librerias, plugins, frameword, etc)

Deja tu comentario