Construyendo un Generador de Cosas Genial de Front End | Programar Plus

Ya sea que esté comenzando en el front-end o lo haya estado haciendo durante mucho tiempo, crear una herramienta que pueda generar algo de magia en el front-end puede ayudarlo a aprender algo nuevo, desarrollar sus habilidades y tal vez incluso conseguirlo. un poco de notoriedad.

Es posible que se haya encontrado con algunos de estos populares generadores en línea:

  • The Hero Generator y CSS Grid Generator de Sarah Drasner
  • Generador de CSS Glassmorphism de Themesburg
  • Text Shadows by Components AI (y tienen un montón más)

Me divertí construyendo algunos de estos yo mismo a lo largo de los años. Básicamente, cada vez que te encuentres con algo interesante en el front-end, es posible que tengas la oportunidad de hacer un generador interactivo para eso.

En este caso, vamos a hacer un generador de degradado de fondo animado.

Andamiaje del proyecto en Siguiente

Lo bueno de estos proyectos es que son todos tuyos. Elija la pila que desee y póngase en marcha. Soy un gran admirador de Next.js, así que para este proyecto, comenzaré como un proyecto básico de Create Next App.

npx create-next-app animated-gradient-background-generator

Esto genera todos los archivos que necesitamos para comenzar. Podemos editar pages/index.js para ser el caparazón de nuestro proyecto.

import Head from "next/head"
import Image from "next/image"
export default function Home() {
  return (
    <>
      <Head>
        <title>Animated CSS Gradient Background Generator</title>
        <meta name="description" content="A tool for creating animated background gradients in pure CSS." />
        <link rel="icon" href="https://css-tricks.com/favicon.ico" />
      </Head>
      <main>
        <h1>
          Animated CSS Gradient Background Generator
        </h1>
      </main>
    </>
  )
}

¿Gradientes animados?

En el momento en que estoy escribiendo este artículo, si haces una búsqueda de fondo de degradado CSS animado, el primer resultado es este lápiz de Manuel Pinto.

Echemos un vistazo al CSS:

body {
  background: linear-gradient(-45deg, #ee7752, #e73c7e, #23a6d5, #23d5ab);
  background-size: 400% 400%;
  animation: gradient 15s ease infinite;
}

@keyframes gradient {
  0% {
    background-position: 0% 50%;
  }
  50% {
    background-position: 100% 50%;
  }
  100% {
    background-position: 0% 50%;
  }
}

Este es un gran ejemplo que podemos usar como base para la animación generada.

Un componente de React para describir un degradado animado

Podemos desglosar algunas posibles opciones configurables para el generador:

  • Una variedad de colores degradados
  • El ángulo del gradiente
  • La velocidad de la animación.

Para poner en contexto, queremos proporcionar esta configuración como datos en toda nuestra pequeña aplicación utilizando un componente de orden superior, context/SettingsContext.jsjunto con algunos valores predeterminados.

import React, { useState, createContext } from "react"

const SettingsContext = createContext({ colorSelection: [] })

const SettingsProvider = ({ children }) => {
  const [colorSelection, setColorSelection] = useState([
    "deepskyblue",
    "darkviolet",
    "blue",
  ])
  const [angle, setAngle] = useState(300)
  const [speed, setSpeed] = useState(5)
  
  return (
    <SettingsContext.Provider
      value={{
        colorSelection,
        setColorSelection,
        angle,
        setAngle,
        speed,
        setSpeed,
      }}
    >
      {children}
    </SettingsContext.Provider>
  )
}

export { SettingsContext, SettingsProvider }

Para los componentes de nuestro generador, queremos crear:

  • componentes de control para ajustar estos ajustes,
  • un componente de visualización visual para el degradado animado generado, y
  • un componente para la salida del código CSS.

Empecemos con un Controls componente que contiene las diversas entradas que usamos para ajustar la configuración.

import Colors from "./Colors"

const Controls = (props) => (
  <>
    <Colors />
  </>
)

export default Controls

Podemos agregar nuestro SettingsProvider y Controls componentes a pages/index.js:

import Head from "next/head"
import Image from "next/image"
import { SettingsProvider } from "../context/SettingsContext"
import Controls from "../components/Controls"
import Output from "../components/Output"

export default function Home() {
  return (
    <>
      <Head>
        ...
      </Head>

      <SettingsProvider>
        <main style={{ textAlign: "center", padding: "64px" }}>
          <h1>Animated CSS Gradient Background Generator</h1>
          <Controls />
          <Output />
        </main>
      </SettingsProvider>
    </>
  )
}

Nuestra SettingsProvider comienza con los tres colores de nuestro ejemplo de CodePen como valores predeterminados. Podemos verificar que estamos obteniendo la configuración de color a través de nuestro SettingsContext en un nuevo Colors componente.

import React, { useContext } from "react"
import { SettingsContext } from "../context/SettingsContext"

const Colors = () => {
  const { colorSelection } = useContext(SettingsContext)
  return (
    <>
      {colorSelection.map((color) => (
        <div>{color}</div>
      ))}
    </>
  )
}

export default Colors

Usemos el Colors componente para mostrar muestras de color individuales con un pequeño botón para eliminar a través de nuestro SettingsContext.

import React, { useContext } from "react"
import { SettingsContext } from "../context/SettingsContext"

const Colors = () => {
  const { colorSelection, setColorSelection } = useContext(SettingsContext)

  const onDelete = (deleteColor) => {
    setColorSelection(colorSelection.filter((color) => color !== deleteColor))
  }

  return (
    <div>
      {colorSelection.map((color) => (
        <div
          key={color}
          style={{
            background: color,
            display: "inline-block",
            padding: "32px",
            margin: "16px",
            position: "relative",
            borderRadius: "4px",
          }}
        >
          <button
            onClick={() => onDelete(color)}
            style={{
              background: "crimson",
              color: "white",
              display: "inline-block",
              borderRadius: "50%",
              position: "absolute",
              top: "-8px",
              right: "-8px",
              border: "none",
              fontSize: "18px",
              lineHeight: 1,
              width: "24px",
              height: "24px",
              cursor: "pointer",
              boxShadow: "0 0 1px #000",
            }}
          >
            ×
          </button>
        </div>
      ))}
    </div>
  )
}

export default Colors

Puede notar que hemos estado usando estilos en línea para CSS en este momento. ¡A quien le importa! Nos estamos divirtiendo aquí, así que podemos hacer lo que sea que haga flotar nuestros barcos.

Manejo de colores

A continuación, creamos un AddColor componente con un botón que abre un selector de color utilizado para agregar más colores al degradado.

Para el selector de color, instalaremos react-color y usa el ChromePicker opción.

npm install react-color

Una vez más, utilizaremos SettingsContext para actualizar la selección de color degradado.

import React, { useState, useContext } from "react"
import { ChromePicker } from "react-color"
import { SettingsContext } from "../context/SettingsContext"

const AddColor = () => {
  const [color, setColor] = useState("white")
  const { colorSelection, setColorSelection } = useContext(SettingsContext)

  return (
    <>
      <div style={{ display: "inline-block", paddingBottom: "32px" }}>
        <ChromePicker
          header="Pick Colors"
          color={color}
          onChange={(newColor) => {
            setColor(newColor.hex)
          }}
        />
      </div>
      <div>
        <button
          onClick={() => {
            setColorSelection([...colorSelection, color])
          }}
          style={{
            background: "royalblue",
            color: "white",
            padding: "12px 16px",
            borderRadius: "8px",
            border: "none",
            fontSize: "16px",
            cursor: "pointer",
            lineHeight: 1,
          }}
        >
          + Add Color
        </button>
      </div>
    </>
  )
}

export default AddColor

Ángulo y velocidad de manejo

Ahora que nuestros controles de color están terminados, agreguemos algunos componentes con entradas de rango para configurar el ángulo y la velocidad de animación.

Aquí está el código para AngleRangecon SpeedRange siendo muy similar.

import React, { useContext } from "react"
import { SettingsContext } from "../context/SettingsContext"

const AngleRange = () => {
  const { angle, setAngle } = useContext(SettingsContext)

  return (
    <div style={{ padding: "32px 0", fontSize: "18px" }}>
      <label
        style={{
          display: "inline-block",
          fontWeight: "bold",
          width: "100px",
          textAlign: "right",
        }}
        htmlFor="angle"
      >
        Angle
      </label>
      <input
        type="range"
        id="angle"
        name="angle"
        min="-180"
        max="180"
        value={angle}
        onChange={(e) => {
          setAngle(e.target.value)
        }}
        style={{
          margin: "0 16px",
          width: "180px",
          position: "relative",
          top: "2px",
        }}
      />
      <span
        style={{
          fontSize: "14px",
          padding: "0 8px",
          position: "relative",
          top: "-2px",
          width: "120px",
          display: "inline-block",
        }}
      >
        {angle} degrees
      </span>
    </div>
  )
}

export default AngleRange

Ahora viene la parte divertida: renderizando el fondo animado. Apliquemos esto a todo el fondo de la página con un AnimatedBackground componente de envoltura.

import React, { useContext } from "react"
import { SettingsContext } from "../context/SettingsContext"
const AnimatedBackground = ({ children }) => {
  const { colorSelection, speed, angle } = useContext(SettingsContext)
const background =
  "linear-gradient(" + angle + "deg, " + colorSelection.toString() + ")"
const backgroundSize =
  colorSelection.length * 60 + "%" + " " + colorSelection.length * 60 + "%"
const animation =
  "gradient-animation " +
  colorSelection.length * Math.abs(speed - 11) +
  "s ease infinite"
return (
  <div style={{ background, "background-size": backgroundSize, animation, color: "white" }}>
    {children}
  </div>
  )
}
export default AnimatedBackground

Llamamos a la animación CSS para el degradado. gradient-animation. Necesitamos agregar eso a styles/globals.css para activar la animación:

@keyframes gradient-animation {
  0% {
    background-position: 0% 50%;
  }
  50% {
    background-position: 100% 50%;
  }
  100% {
    background-position: 0% 50%;
  }
}

Haciéndolo útil para los usuarios

A continuación, agreguemos algunos resultados de código para que las personas puedan copiar y pegar el CSS generado y usarlo en sus propios proyectos.

import React, { useContext, useState } from "react"
import { SettingsContext } from "../context/SettingsContext"
const Output = () => {
  const [copied, setCopied] = useState(false)
const { colorSelection, speed, angle } = useContext(SettingsContext)
const background =
  "linear-gradient(" + angle + "deg," + colorSelection.toString() + ")"
const backgroundSize =
  colorSelection.length * 60 + "%" + " " + colorSelection.length * 60 + "%"
const animation =
  "gradient-animation " +
  colorSelection.length * Math.abs(speed - 11) +
  "s ease infinite"
const code = `.gradient-background {
  background: ${background};
  background-size: ${backgroundSize};
  animation: ${animation};
}
@keyframes gradient-animation {
  0% {
    background-position: 0% 50%;
  }
  50% {
    background-position: 100% 50%;
  }
  100% {
    background-position: 0% 50%;
  }
}`
return (
    <div
      style={{ position: "relative", maxWidth: "640px", margin: "64px auto" }}
    >
      <pre
        style={{
          background: "#fff",
          color: "#222",
          padding: "32px",
          width: "100%",
          borderRadius: "4px",
          textAlign: "left",
          whiteSpace: "pre",
          boxShadow: "0 2px 8px rgba(0,0,0,.33)",
          overflowX: "scroll",
        }}
      >
        <code>{code}</code>
        <button
          style={{
            position: "absolute",
            top: "8px",
            right: "8px",
            background: "royalblue",
            color: "white",
            padding: "8px 12px",
            borderRadius: "8px",
            border: "none",
            fontSize: "16px",
            cursor: "pointer",
            lineHeight: 1,
          }}
          onClick={() => {
            setCopied(true)
            navigator.clipboard.writeText(code)
          }}
        >
          {copied ? "copied" : "copy"}
        </button>
      </pre>
    </div>
  )
}
export default Output

Haciéndolo divertido

A veces es divertido (y útil) agregar un botón que establece valores aleatorios en un generador como este. Eso les da a las personas una forma de experimentar rápidamente y ver qué tipo de resultados pueden obtener de la herramienta. También es una oportunidad para buscar cosas interesantes como cómo generar colores hexadecimales aleatorios.

import React, { useContext } from "react"
import { SettingsContext } from "../context/SettingsContext"

const Random = () => {
  const { setColorSelection, setAngle, setSpeed } = useContext(SettingsContext)

  const goRandom = () => {
    const numColors = 3 + Math.round(Math.random() * 3)
    const colors = [...Array(numColors)].map(() => {
      return "#" + Math.floor(Math.random() * 16777215).toString(16)
    })
    setColorSelection(colors)
    setAngle(Math.floor(Math.random() * 361))
    setSpeed(Math.floor(Math.random() * 10) + 1)
  }

  return (
    <div style={{ padding: "48px 0 16px" }}>
      <button
        onClick={goRandom}
        style={{
          fontSize: "24px",
          fontWeight: 200,
          background: "rgba(255,255,255,.9)",
          color: "blue",
          padding: "24px 48px",
          borderRadius: "8px",
          cursor: "pointer",
          boxShadow: "0 0 4px #000",
          border: "none",
        }}
      >
        RANDOM
      </button>
    </div>
  )
}

export default Random

Terminando

Habrá algunas cosas finales que querrá hacer para concluir su proyecto para el lanzamiento inicial:

  • Actualizar package.json con la información de su proyecto.
  • Agregue algunos enlaces a su sitio personal, el repositorio del proyecto y dé el crédito donde corresponda.
  • Actualizar el README.md archivo que fue generado con contenido predeterminado por Create Next App.

¡Eso es! ¡Estamos listos para lanzar nuestro nuevo generador de cosas de front-end y cosechar las recompensas de la fama y la fortuna que nos esperan!

Puede ver el código de este proyecto en GitHub y la demostración está alojada en Netlify.

(Visited 11 times, 1 visits today)