import { Callout } from 'nextra/components'
import CodeRender from '@/components/CodeRender'

# Build button component

We found a `button` component on the Internet, its html is as follows

```html
<a
  href="https://ui.icebreaker.top/"
  target="_blank"
  class="group relative overflow-hidden bg-blue-600 focus:ring-4 focus:ring-blue-300 inline-flex items-center px-7 py-2.5 rounded-lg text-white justify-center"
>
  <span class="z-40">Hover Me</span>
  <div
    class="absolute inset-0 h-[200%] w-[200%] rotate-45 translate-x-[-75%] transition-all group-hover:scale-100 bg-white/30 group-hover:translate-x-[50%] z-20 duration-1000"
  ></div>
</a>
```

The display effect is as follows:

<CodeRender
  code={`<a
  href="https://ui.icebreaker.top/"
  target="_blank"
  class="group relative overflow-hidden bg-blue-600 focus:ring-4 focus:ring-blue-300 inline-flex items-center px-7 py-2.5 rounded-lg text-white justify-center"
>
  <span class="z-40">Hover Me</span>
  <div class="absolute inset-0 h-[200%] w-[200%] rotate-45 translate-x-[-75%] transition-all group-hover:scale-100 bg-white/30 group-hover:translate-x-[50%] z-20 duration-1000"></div>
</a>`}
/>

## Style refinement

Then we start to refine `html` and extract its styles:

```html
<a href="https://icebreaker.top/" target="_blank" class="cbtn">
  <span>Hover Me</span>
</a>
```

Convert the original long-passed `class` into `@apply`, and wrap it in the selector `.cbtn`, then convert the last animated `div` element into a pseudo element, and modify the style.

<Callout type="info">@apply should not be used with the 'group' utility</Callout>

```scss
.cbtn {
  @apply relative overflow-hidden bg-blue-600 focus:ring-4 focus:ring-blue-300 inline-flex items-center px-7 py-2.5 rounded-lg text-white justify-center;

  &::after {
    content: '';
    @apply absolute inset-0 h-[200%] w-[200%] rotate-45 translate-x-[-75%] transition-all bg-white/30 z-20 duration-1000;
  }

  &:hover::after {
    @apply translate-x-[50%];
  }
}
```

## Write configuration file

```js
/**
 * @type {import('@icestack/ui').Config}
 */
const config = {
  outdir: './my-ui',
  components: {
    cbutton: {
      selector: '.cbtn',
      // selector is .cbtn
      schema: ({ selector, params, types }) => {
        return {
          selector,
          defaults: {
            // return a string template
            base: `
            ${selector} {
  @apply relative overflow-hidden bg-blue-600 focus:ring-4 focus:ring-blue-300 inline-flex items-center px-7 py-2.5 rounded-lg text-white justify-center;

  &::after {
    content: '';
    @apply absolute inset-0 h-[200%] w-[200%] rotate-45 translate-x-[-75%] transition-all bg-white/30 z-20 duration-1000;
  }

  &:hover::after {
    @apply translate-x-[50%];
  }
}
            `
          }
        }
      }
    }
  }
}
module.exports = config
```

Then after executing `icestack build`, `.cbtn` will be successfully loaded by `tailwindcss plugin`. You can write like this:

<CodeRender
  code={`
<a href="https://icebreaker.top/" target="_blank" class="cbtn">
  Hover Me
</a>
`}
/>

```html
<a href="https://icebreaker.top/" target="_blank" class="cbtn"> Hover Me </a>
```

## Add more color varieties

The component written above has the default color: `bg-blue-600 focus:ring-blue-300`

We have a need to support incoming red, yellow, and other colors. How should we handle it?

```js
/**
 * @type {import('@icestack/ui').Config}
 */
const config = {
  outdir: './my-ui',
  components: {
    cbutton: {
      selector: '.cbtn',
      schema: ({ selector, params, types }) => {
        // add colors
        const colors = ['red', 'yellow', 'green']
        return {
          selector,
          // utils > styled > base
          defaults: {
            base: `...previous code`,
            // add styled
            styled: `
            ${colors
              .map((color) => {
                return `${selector}-${color}{
                @apply bg-${color}-600 focus:ring-${color}-300;
              }`
              })
              .join('\n')}
            
            `
          }
        }
      }
    }
  }
}
module.exports = config
```

After rebuilding, the effect is as follows:

<CodeRender className="gap-2" code={`
<button href="https://icebreaker.top/" target="_blank" class="cbtn">
  <span>Hover Me default</span>
</button>

<button href="https://icebreaker.top/" target="_blank" class="cbtn cbtn-red">
  <span>Hover Me red</span>
</button>

<button href="https://icebreaker.top/" target="_blank" class="cbtn cbtn-yellow">
  <span>Hover Me yellow</span>
</button>

<button href="https://icebreaker.top/" target="_blank" class="cbtn cbtn-green">
  <span>Hover Me green</span>
</button>
`} / >

```html
<button href="https://icebreaker.top/" target="_blank" class="cbtn">
  <span>Hover Me default</span>
</button>

<button href="https://icebreaker.top/" target="_blank" class="cbtn cbtn-red">
  <span>Hover Me red</span>
</button>

<button href="https://icebreaker.top/" target="_blank" class="cbtn cbtn-yellow">
  <span>Hover Me yellow</span>
</button>

<button href="https://icebreaker.top/" target="_blank" class="cbtn cbtn-green">
  <span>Hover Me green</span>
</button>
```

## Add more sizes

```js
/**
 * @type {import('@icestack/ui').Config}
 */
const config = {
  outdir: './my-ui',
  components: {
    cbutton: {
      selector: '.cbtn',
      schema: ({ selector, params, types }) => {
        // add colors
        const colors = ['red', 'yellow', 'green']
        return {
          selector,
          // utils > styled > base
          defaults: {
            base: `...previous code`,
            // add styled
            styled: `...previous code`,
            // add sizes
            utils: `
            ${selector}-xs{
              @apply px-3 py-1.5 rounded;
            }
            ${selector}-sm{
              @apply px-5 py-2 rounded-md;
            }
            ${selector}-md{
              @apply px-7 py-2.5 rounded-lg;
            }
            ${selector}-lg{
              @apply px-8 py-3 rounded-lg;
            }
            `
          }
        }
      }
    }
  }
}
module.exports = config
```

The effect is as follows:

<CodeRender className="gap-2" code={`
<button href="https://icebreaker.top/" target="_blank" class="cbtn cbtn-xs">
  <span>Hover Me xs</span>
</button>

<button href="https://icebreaker.top/" target="_blank" class="cbtn cbtn-sm">
  <span>Hover Me sm</span>
</button>

<button href="https://icebreaker.top/" target="_blank" class="cbtn cbtn-md">
  <span>Hover Me md</span>
</button>

<button href="https://icebreaker.top/" target="_blank" class="cbtn cbtn-lg">
  <span>Hover Me lg</span>
</button>
`} />

```html
<button href="https://icebreaker.top/" target="_blank" class="cbtn cbtn-xs">
  <span>Hover Me xs</span>
</button>

<button href="https://icebreaker.top/" target="_blank" class="cbtn cbtn-sm">
  <span>Hover Me sm</span>
</button>

<button href="https://icebreaker.top/" target="_blank" class="cbtn cbtn-md">
  <span>Hover Me md</span>
</button>

<button href="https://icebreaker.top/" target="_blank" class="cbtn cbtn-lg">
  <span>Hover Me lg</span>
</button>
```

## More

You must have noticed that the `schema` method has multiple parameters:

- `selector` is the selector
- `types` is the automatically generated color name in the `base` option
- `params` is the incoming parameter, which can render different performances of the component according to different parameters.

We can render different `Css` style codes based on different parameters.
