philippebeck/vue-elt

View on GitHub
components/elements/TableElt.vue

Summary

Maintainability
Test Coverage
<template>
  <table>
    <caption v-if="hasSlot('title')">
      <slot name="title">{{ title }}</slot>
    </caption>

    <thead>
      <tr>
        <th v-for="(value, key) in items[0]" :key="key">{{ key }}</th>

        <th v-if="hasSlot('head')">
          <slot name="head"></slot>
        </th>
      </tr>
    </thead>
    <tbody>
      <tr v-for="(item, index) in items" :key="index">

        <td v-for="(value, key) in item" :key="key">
          <slot :name="`cell-${key}`"
            :index="index"
            :item="item"
            :key="key"
            :value="value">
            {{ value }}
          </slot>
        </td>

        <td v-if="hasSlot('body')">
          <slot name="body" :index="index" :item="item"></slot>
        </td>
      </tr>
    </tbody>

    <tfoot v-if="hasSlot('foot')">
      <slot name="foot"></slot>
    </tfoot>
  </table>
</template>

<script>
export default {
  name: "TableElt",
  props: {
    title: { type: String },
    items: { type: Array, required: true }
  },

  methods: {
    /**
     * ? HAS SLOT
     * * Determines if the specified slot name is available in the component's slots.
     * @param {string} name - The name of the slot to check for.
     * @return {boolean} Returns true if the component has the specified slot, false otherwise.
     */
    hasSlot(name) {
      return Object.prototype.hasOwnProperty.call(this.$slots, name);
    }
  }
}
</script>

<style>
table {
  --ve-table-display: table;
  --ve-table-overflow: hidden;
  --ve-table-table-layout: fixed;
  --ve-table-margin: 50px auto;
  --ve-table-border-collapse: separate;
  --ve-table-border-spacing: 1px;
  --ve-table-border-radius: 10px;
  --ve-table-width: 100%;
  --ve-table-max-width: 100%;
  --ve-table-font-size: 1.5rem;
}

caption {
  --ve-table-caption-caption-side: top;
  --ve-table-caption-margin-bottom: 20px;
  --ve-table-caption-font-size: 1.5rem;
  --ve-table-caption-font-weight: bold;
  --ve-table-caption-color: var(--ani-slate);
  --ve-table-caption-text-shadow: 1px 1px 2px;
}

thead {
  --ve-table-thead-border-radius: 10px;
}

tr {
  --ve-table-tr-display: flex;
  --ve-table-tr-flex-flow: column;
  --ve-table-tr-padding: 20px;
  --ve-table-tbody-tr-even-background-color: var(--ani-silver);
  --ve-table-tbody-tr-even-color: var(--ani-black);
  --ve-table-tbody-tr-odd-background-color: var(--ani-white);
  --ve-table-tbody-tr-odd-color: var(--ani-slate);
  --ve-table-tbody-tr-hover-background-color: var(--ani-gray);
  --ve-table-tbody-tr-hover-color: var(--ani-black);
}

th {
  --ve-table-th-display: none;
  --ve-table-th-padding: 5px;
  --ve-table-th-font-size: 1.5rem;
  --ve-table-th-font-style: italic;
  --ve-table-th-text-align: center;
  --ve-table-th-text-transform: uppercase;
  --ve-table-th-vertical-align: middle;
  --ve-table-th-background-color: var(--ani-sky-dark);
  --ve-table-th-color: var(--ani-white);
}

td {
  --ve-table-td-display: table;
  --ve-table-td-padding: 5px;
  --ve-table-td-text-align: center;
  --ve-table-td-vertical-align: middle;
  --ve-table-td-word-break: normal;
  --ve-table-td-cursor: cell;
}

@media (min-width: 1200px) {
  tr {
    --ve-table-tr-display: table-row;
  }

  th {
    --ve-table-th-display: table-cell;
  }

  td {
    --ve-table-td-display: table-cell;
  }
}
</style>

<style scoped>
table {
  display: var(--ve-table-display);
  overflow: var(--ve-table-overflow);
  table-layout: var(--ve-table-table-layout);
  margin: var(--ve-table-margin);
  border-collapse: var(--ve-table-border-collapse);
  border-spacing: var(--ve-table-border-spacing);
  border-radius: var(--ve-table-border-radius);
  width: var(--ve-table-width);
  max-width: var(--ve-table-max-width);
  font-size: var(--ve-table-font-size);
}

caption {
  caption-side: var(--ve-table-caption-caption-side);
  margin-bottom: var(--ve-table-caption-margin-bottom);
  font-size: var(--ve-table-caption-font-size);
  font-weight: var(--ve-table-caption-font-weight);
  color: var(--ve-table-caption-color);
  text-shadow: var(--ve-table-caption-text-shadow);
}

thead {
  border-radius: var(--ve-table-thead-border-radius);
}

tr {
  display: var(--ve-table-tr-display);
  flex-flow: var(--ve-table-tr-flex-flow);
  padding: var(--ve-table-tr-padding);
}

tbody tr:nth-child(even) {
  background-color: var(--ve-table-tbody-tr-even-background-color);
  color: var(--ve-table-tbody-tr-even-color);
}

tbody tr:nth-child(odd) {
  background-color: var(--ve-table-tbody-tr-odd-background-color);
  color: var(--ve-table-tbody-tr-odd-color);
}

tbody tr:hover,
tbody tr:focus {
  background-color: var(--ve-table-tbody-tr-hover-background-color);
  color: var(--ve-table-tbody-tr-hover-color);
}

th {
  display: var(--ve-table-th-display);
  padding: var(--ve-table-th-padding);
  font-size: var(--ve-table-th-font-size);
  font-style: var(--ve-table-th-font-style);
  text-align: var(--ve-table-th-text-align);
  text-transform: var(--ve-table-th-text-transform);
  vertical-align: var(--ve-table-th-vertical-align);
  background-color: var(--ve-table-th-background-color);
  color: var(--ve-table-th-color);
}

td {
  display: var(--ve-table-td-display);
  padding: var(--ve-table-td-padding);
  text-align: var(--ve-table-td-text-align);
  vertical-align: var(--ve-table-td-vertical-align);
  word-break: var(--ve-table-td-word-break);;
  cursor: var(--ve-table-td-cursor);
}
</style>