Einen coolen Front-End-Generator bauen

Avatar of John Polacek
John Polacek am

DigitalOcean bietet Cloud-Produkte für jede Phase Ihrer Reise. Starten Sie mit 200 $ kostenlosem Guthaben!

Egal, ob Sie gerade erst mit Front-End anfangen oder schon lange dabei sind, der Bau eines Tools, das coole Front-End-Magie generieren kann, kann Ihnen helfen, etwas Neues zu lernen, Ihre Fähigkeiten zu entwickeln und vielleicht sogar ein wenig Bekanntheit zu erlangen.

Sie sind vielleicht schon auf einige dieser beliebten Online-Generatoren gestoßen

Ich hatte Spaß daran, im Laufe der Jahre ein paar davon selbst zu bauen. Grundsätzlich kann jedes Mal, wenn Sie auf etwas Cooles im Front-End stoßen, eine Gelegenheit bestehen, einen interaktiven Generator für diese Sache zu erstellen.

In diesem Fall werden wir einen Generator für animierte Gradient-Hintergründe erstellen.

Das Projekt in Next aufsetzen

Eine schöne Sache an diesen Projekten ist, dass sie ganz Ihnen gehören. Wählen Sie jeden beliebigen Stack und legen Sie los. Ich bin ein großer Fan von Next.js, daher werde ich für dieses Projekt als grundlegendes Create Next App-Projekt beginnen.

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

Dies generiert alle Dateien, die wir zum Start benötigen. Wir können pages/index.js als Shell für unser Projekt bearbeiten.

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="/favicon.ico" />
      </Head>
      <main>
        <h1>
          Animated CSS Gradient Background Generator
        </h1>
      </main>
    </>
  )
}

Animierte Verläufe?

Zum Zeitpunkt der Erstellung dieses Artikels, wenn Sie nach animierten CSS-Gradient-Hintergründen suchen, ist das erste Ergebnis dieser Pen von Manuel Pinto.

Werfen wir einen Blick auf das 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%;
  }
}

Dies ist ein großartiges Beispiel, das wir als Grundlage für die generierte Animation verwenden können.

Eine React-Komponente zur Beschreibung eines animierten Verlaufs

Wir können ein paar mögliche konfigurierbare Optionen für den Generator herausgreifen

  • Ein Array von Verlauffarben
  • Der Winkel des Verlaufs
  • Die Geschwindigkeit der Animation

Um es in den *Kontext* zu stellen, möchten wir diese Einstellungen mit einer Higher-Order-Komponente, context/SettingsContext.js, zusammen mit einigen Standardwerten als Daten in unserer kleinen App *bereitstellen*.

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 }

Für die Komponenten unseres Generators möchten wir erstellen

  • eine Steuerkomponente zur Anpassung dieser Einstellungen,
  • eine visuelle Anzeigekomponente für den generierten animierten Verlauf und
  • eine Komponente für die CSS-Codeausgabe.

Beginnen wir mit einer Controls-Komponente, die die verschiedenen Eingaben zur Anpassung der Einstellungen enthält.

import Colors from "./Colors"

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

export default Controls

Wir können unsere SettingsProvider und Controls-Komponenten zu pages/index.js hinzufügen

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>
    </>
  )
}

Unser SettingsProvider beginnt mit den drei Farben aus unserem CodePen-Beispiel als Standardwerten. Wir können überprüfen, ob wir die Farneinstellungen über unseren SettingsContext in einer neuen Colors-Komponente erhalten.

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

Wir werden die Colors-Komponente verwenden, um einzelne Farbfelder mit einer kleinen Schaltfläche zum Löschen über unseren SettingsContext anzuzeigen.

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

Sie werden vielleicht bemerken, dass wir zu diesem Zeitpunkt Inline-Stile für CSS verwendet haben. Wen kümmert's! Wir haben hier Spaß, also können wir tun, was immer uns gefällt.

Farben verwalten

Als Nächstes erstellen wir eine AddColor-Komponente mit einer Schaltfläche, die einen Farbwähler öffnet, der zum Hinzufügen weiterer Farben zum Verlauf verwendet wird.

Für den Farbwähler installieren wir react-color und verwenden die Option ChromePicker.

npm install react-color

Auch hier werden wir SettingsContext verwenden, um die Auswahl der Verlauffarben zu aktualisieren.

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

Winkel und Geschwindigkeit verwalten

Nachdem unsere Farbsteuerungen fertig sind, fügen wir nun Komponenten mit Bereichseingaben hinzu, um den Winkel und die Animationsgeschwindigkeit einzustellen.

Hier ist der Code für AngleRange, wobei SpeedRange sehr ähnlich ist.

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

Nun zum spaßigen Teil: **Das Rendern des animierten Hintergrunds**. Wenden wir dies auf den gesamten Hintergrund der Seite mit einer AnimatedBackground-Wrapperkomponente an.

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

Wir nennen die CSS-Animation für den Verlauf gradient-animation. Wir müssen diese zu styles/globals.css hinzufügen, um die Animation auszulösen

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

Nützlich für Benutzer machen

Als Nächstes fügen wir eine Codeausgabe hinzu, damit die Leute den generierten CSS-Code kopieren und einfügen und in ihren eigenen Projekten verwenden können.

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

Spaß machen

Es macht manchmal Spaß (und ist nützlich), eine Schaltfläche hinzuzufügen, die zufällige Werte auf einem Generator wie diesem einstellt. Das gibt den Leuten eine Möglichkeit, schnell zu experimentieren und zu sehen, welche Ergebnisse sie mit dem Tool erzielen können. Es ist auch eine Gelegenheit, coole Dinge nachzuschlagen, wie z. B. wie man zufällige Hex-Farben generiert.

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

Zusammenfassung

Es gibt ein paar abschließende Dinge, die Sie tun möchten, um Ihr Projekt für die Erstveröffentlichung abzuschließen

  • Aktualisieren Sie package.json mit Ihren Projektinformationen.
  • Fügen Sie einige Links zu Ihrer persönlichen Website, dem Repository des Projekts hinzu und geben Sie die gebührende Anerkennung.
  • Aktualisieren Sie die Datei README.md, die von Create Next App mit Standardinhalten generiert wurde.

Das ist es! Wir sind bereit, unseren neuen coolen Front-End-Generator zu veröffentlichen und die Belohnungen für Ruhm und Vermögen zu ernten, die uns erwarten!

Sie können den Code für dieses Projekt auf GitHub sehen und die Demo ist auf Netlify gehostet.