4
\$\begingroup\$

I'm working on a vue.js / nuxt.js project, applying the Atomic Design methodology, I need to do one to set the grid layout and using CSS Grid Layout.

I already did the component, but I think I did not do it the best way ... the code is great and not very smart, lots of manual work, I would like your opinion and help to make this component better

GridLayout.vue

<template>
  <div class="grid">
    <style>
    {{ css }}
    </style>
    <slot />
  </div>
</template>

<script>
export default {
  props: {
    columns: String,
    rows: String,
    areas: String,
    gap: String,
    columnGap: String,
    rowGap: String,
    // breakpoints
    small: Object,
    medium: Object,
    large: Object
  },
  computed: {
    css () {
      let large = ''
      let finalStyle = ''

      // generic
      let generic = ''
      if (this.columns) generic += `grid-template-columns: ${this.columns};`
      if (this.rows) generic += `grid-template-rows: ${this.rows};`
      if (this.areas) generic += `grid-template-areas: "${this.areas}";`
      if (this.gap) generic += `grid-gap: ${this.gap};`
      if (this.columnGap) generic += `grid-column-gap: ${this.columnGap};`
      if (this.rowGap) generic += `grid-row-gap: ${this.rowGap};`
      finalStyle += ` .grid { ${generic} }`

      // small
      let small = ''
      if (this.small) {
        if (this.small.columns) small += `grid-template-columns: ${this.small.columns};`
        if (this.small.rows) small += `grid-template-rows: ${this.small.rows};`
        if (this.small.areas) small += `grid-template-areas: "${this.small.areas}";`
        if (this.small.gap) small += `grid-gap: ${this.small.gap};`
        if (this.small.columnGap) small += `grid-column-gap: ${this.small.columnGap};`
        if (this.small.rowGap) small += `grid-row-gap: ${this.small.rowGap};`
        finalStyle += `@media (max-width: 600px) { .grid { ${small} } } `
      }

      // medium
      let medium = ''
      if (this.medium) {
        if (this.medium.columns) medium += `grid-template-columns: ${this.medium.columns};`
        if (this.medium.rows) medium += `grid-template-rows: ${this.medium.rows};`
        if (this.medium.areas) medium += `grid-template-areas: "${this.medium.areas}";`
        if (this.medium.gap) medium += `grid-gap: ${this.medium.gap};`
        if (this.medium.columnGap) medium += `grid-column-gap: ${this.medium.columnGap};`
        if (this.medium.rowGap) medium += `grid-row-gap: ${this.medium.rowGap};`
        finalStyle += `@media (min-width: 600px) and (max-width: 992px) { .grid { ${medium} } } `
      }

      return finalStyle
    },
  },
}
</script>

<style lang="scss" scoped>
.grid {
  display: grid;
}
</style>

using component on any page.vue

<template>
  <GridLayout
    columns="1fr 1fr 1fr 1fr"
    rows="auto"
    gap="10px"
    :medium="{
      columns: '1fr 1fr',
      rows:'auto auto'
    }"
    :small="{
      columns: '1fr',
      rows: 'auto auto auto auto',
    }"
  >
    <h1>1</h1>
    <h1>2</h1>
    <h1>3</h1>
    <h1>3</h1>
  </GridLayout>
</template>

<script>
import { GridLayout } from '@/components/bosons'

export default {
  components: {
    GridLayout
  }
}
</script>

problems

1 - the style tag <style> inside ` needs to be scoped, applying only in the component itself

2 - whenever I want new properties for the GridLayout, for example, '' child align '', I will have to add everywhere in computed, that is, generic, small, medium, large

Anyway, I honestly did not like what I did, I would like your opinion and help you guys.

\$\endgroup\$
2
\$\begingroup\$

Never heard of Atomic design till today.Read the blog and a few chapters of the book. Nothing really new, just another analogy (re-branding) for the standard modular design methods.

To your code.

Its not at all DRY but the various settings are consistent and can easily be changed so that you minimize the repeated code and literals.

The following example reduces the repeated code but without knowing more about how these properties change per client/instance I cant add add anything regarding the design methods.

css() {
    const rules = {
        columns: "grid-template-columns: ##SET##;",
        rows: "grid-template-rows: ##SET##;",
        areas: "grid-template-areas: \"##SET##\";",
        gap: "grid-gap: ##SET##;",
        columnGap: "grid-column-gap: ##SET##;",
        rowGap: "grid-row-gap: ##SET##;",
    };
    const sizes = {
        default:" .grid { ##STYLE## }",
        small: "@media (max-width: 600px) { .grid { ##STYLE## } } ",
        medium: "@media (min-width: 600px) and (max-width: 992px) { .grid { ##STYLE## } } ",
    };
    var src, css = "";
    const rule = name => src[name] ? rules[name].replace("##SET##", src[name]) : "";
    for (const size of Object.keys(sizes)) {
        src = size === "default" : this : this[size];
        if (src) {
            css += sizes[size].replace("##STYLE##", Object.keys(rules).map(rule).join(""));
        }
    }
    return css;
}
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.