<div class="container">
  <div>
    <div class="panel">
      <h2 class="panel-heading">Pattern Settings</h2>

      <div class="form-group">
        <label for="pattern-type">Pattern Type:</label>
        <select id="pattern-type">
          <option value="custom">Custom SVG</option>
          <option value="url">Image URL</option>
        </select>
      </div>

      <div id="custom-svg-container" class="form-group">
        <label for="custom-svg">Custom SVG Content:</label>
        <textarea id="custom-svg" rows="5" placeholder="<polygon points='5,5 7,10 5,15 10,13 15,15 13,10 15,5 10,7' fill='greenyellow' />"><polygon points='5,5 7,10 5,15 10,13 15,15 13,10 15,5 10,7' fill='greenyellow' /></textarea>
      </div>

      <div id="image-url-container" class="form-group" style="display:none;">
        <label for="image-url">Image URL:</label>
        <input type="text" id="image-url" placeholder="https://example.com/image.svg">
      </div>

      <div class="form-group">
        <label>Pattern Dimensions:</label>
        <div class="grid-controls">
          <div>
            <label for="pattern-width">Width:</label>
            <input type="number" id="pattern-width" value="30" min="10" max="500">
          </div>
          <div>
            <label for="pattern-height">Height:</label>
            <input type="number" id="pattern-height" value="30" min="10" max="500">
          </div>
        </div>
      </div>

      <div class="form-group">
        <label>Pattern Transform:</label>
        <div class="grid-controls">
          <div>
            <label for="pattern-rotation">Rotation (deg):</label>
            <input type="number" id="pattern-rotation" value="-6" min="-360" max="360">
          </div>
          <div>
            <label for="pattern-scale">Scale:</label>
            <input type="number" id="pattern-scale" value="1.5" min="0.1" max="5" step="0.1">
          </div>
        </div>
      </div>

      <button id="generate-btn" class="btn" style="display:none;">Generate Pattern</button>
    </div>
  </div>

  <div>
    <div class="panel">
      <h2 class="panel-heading">Preview</h2>

      <div class="background-selector">
        <span class="label-text">Background:</span>
        <div class="bg-options">
          <label title="White">
            <input type="radio" name="bg-pattern" value="white">
            <div class="bg-preview white"></div>
          </label>
          <label title="White Checkered">
            <input type="radio" name="bg-pattern" value="white-check">
            <div class="bg-preview white-check"></div>
          </label>
          <label title="Dark Checkered">
            <input type="radio" name="bg-pattern" value="dark-check" checked>
            <div class="bg-preview dark-check"></div>
          </label>
          <label title="Black">
            <input type="radio" name="bg-pattern" value="black">
            <div class="bg-preview black"></div>
          </label>
        </div>
      </div>

      <div class="preview-container dark-check">
        <div id="pattern-preview"></div>
      </div>

      <div class="code-container">
        <label for="svg-output">SVG Output:</label>
        <textarea id="svg-output" class="code-output" readonly></textarea>
        <button class="btn btn-copy" data-target="svg-output">Copy SVG</button>
        <span id="svg-output-copy-success" class="success-msg">Copied!</span>
      </div>

      <div class="code-container">
        <label for="css-output">CSS Background:</label>
        <textarea id="css-output" class="code-output" readonly></textarea>
        <button class="btn btn-copy" data-target="css-output">Copy CSS</button>
        <span id="css-output-copy-success" class="success-msg">Copied!</span>
      </div>
    </div>
  </div>
</div>
:root {
  --primary: #3490dc;
  --secondary: #6574cd;
  --success: #38c172;
  --danger: #e3342f;
  --gray-900: #f7fafc;
  --gray-800: #edf2f7;
  --gray-700: #e2e8f0;
  --gray-300: #4a5568;
  --gray-200: #2d3748;
  --gray-100: #1a202c;
}

* {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

body {
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
    "Helvetica Neue", Arial, sans-serif;
  line-height: 1.5;
  color: var(--gray-800);
  background-color: var(--gray-100);
  padding: 20px;
  max-width: 1200px;
  margin: 0 auto;
}

h1 {
  text-align: center;
  margin-bottom: 1rem;
  color: var(--gray-900);
}

.container {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 20px;
}

@media (max-width: 768px) {
  .container {
    grid-template-columns: 1fr;
  }
}

.panel {
  background: black;
  border-radius: 8px;
  padding: 20px;
  margin-bottom: 20px;
}

.panel-heading {
  font-size: 1.25rem;
  font-weight: 600;
  margin-bottom: 1rem;
  padding-bottom: 0.5rem;
  border-bottom: 1px solid var(--gray-200);
}

.form-group {
  margin-bottom: 1rem;
}

label {
  display: block;
  margin-bottom: 0.5rem;
  font-weight: 500;
  color: var(--gray-700);
}

input,
select,
textarea {
  width: 100%;
  padding: 0.5rem;
  border: 1px solid var(--gray-300);
  border-radius: 4px;
  font-size: 1rem;
  background-color: var(--gray-200);
  color: var(--gray-900);
}

.btn {
  display: inline-block;
  font-weight: 500;
  text-align: center;
  white-space: nowrap;
  vertical-align: middle;
  cursor: pointer;
  padding: 0.5rem 1rem;
  font-size: 1rem;
  line-height: 1.5;
  border-radius: 0.25rem;
  transition: all 0.2s ease-in-out;
  color: white;
  background-color: var(--primary);
  border: 1px solid var(--primary);
  margin-right: 0.5rem;
  margin-bottom: 0.5rem;
}

.btn:hover {
  opacity: 0.9;
}

.btn-copy {
  background-color: var(--secondary);
  border-color: var(--secondary);
}

.btn-secondary {
  background-color: var(--gray-700);
  border-color: var(--gray-700);
}

.background-selector {
  margin-bottom: 1rem;
  display: flex;
  align-items: center;
  gap: 12px;
}

.background-selector .label-text {
  color: var(--gray-700);
  font-weight: 500;
}

.bg-options {
  display: flex;
  gap: 12px;
}

.background-selector label {
  margin: 0;
  padding: 0;
  width: 32px;
  height: 32px;
  border-radius: 50%;
  cursor: pointer;
  border: 3px solid transparent;
  position: relative;
}

.background-selector input[type="radio"] {
  display: none;
}

.background-selector input[type="radio"]:checked + .bg-preview {
  border-color: var(--primary);
}

.bg-preview {
  position: absolute;
  inset: -3px;
  border: 3px solid var(--gray-300);
  border-radius: 50%;
  transition: border-color 0.2s;
}

.white {
  background: white;
}

.white-check {
  background-color: white;
  background-image: linear-gradient(
      45deg,
      #e2e8f0 25%,
      transparent 25%,
      transparent 75%,
      #e2e8f0 75%,
      #e2e8f0
    ),
    linear-gradient(
      45deg,
      #e2e8f0 25%,
      transparent 25%,
      transparent 75%,
      #e2e8f0 75%,
      #e2e8f0
    );
  background-size: 10px 10px;
  background-position: 0 0, 5px 5px;
}

.dark-check {
  background-color: var(--gray-300);
  background-image: linear-gradient(
      45deg,
      var(--gray-100) 25%,
      transparent 25%,
      transparent 75%,
      var(--gray-100) 75%,
      var(--gray-100)
    ),
    linear-gradient(
      45deg,
      var(--gray-100) 25%,
      transparent 25%,
      transparent 75%,
      var(--gray-100) 75%,
      var(--gray-100)
    );
  background-size: 10px 10px;
  background-position: 0 0, 5px 5px;
}

.black {
  background: black;
}

.preview-container {
  width: 100%;
  height: 300px;
  border: 1px solid var(--gray-300);
  border-radius: 4px;
  margin-bottom: 1rem;
  overflow: hidden;
}

#pattern-preview {
  width: 100%;
  height: 100%;
}

.code-container {
  position: relative;
  margin-bottom: 1rem;
}

textarea.code-output {
  width: 100%;
  min-height: 100px;
  font-family: monospace;
  padding: 0.5rem;
  border: 1px solid var(--gray-300);
  border-radius: 4px;
  background-color: var(--gray-200);
  color: var(--gray-900);
  resize: vertical;
}

.grid-controls {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 10px;
}

.success-msg {
  color: var(--success);
  font-size: 0.875rem;
  margin-top: 0.25rem;
  display: none;
}
// Initialize the app
document.addEventListener("DOMContentLoaded", function () {
  const patternTypeSelect = document.getElementById("pattern-type");
  const customSvgContainer = document.getElementById("custom-svg-container");
  const imageUrlContainer = document.getElementById("image-url-container");
  const copyButtons = document.querySelectorAll(".btn-copy");
  const bgPatternInputs = document.querySelectorAll('input[name="bg-pattern"]');
  const previewContainer = document.querySelector(".preview-container");

  // Pattern type change handler
  patternTypeSelect.addEventListener("change", function () {
    customSvgContainer.style.display =
      this.value === "custom" ? "block" : "none";
    imageUrlContainer.style.display = this.value === "url" ? "block" : "none";
    generatePattern();
  });

  // Input change handlers
  document
    .querySelectorAll(
      "#custom-svg, #image-url, #pattern-width, #pattern-height, #pattern-rotation, #pattern-scale"
    )
    .forEach((input) => {
      input.addEventListener("input", generatePattern);
    });

  // Copy button click handlers
  copyButtons.forEach((button) => {
    button.addEventListener("click", function () {
      const targetId = this.getAttribute("data-target");
      const targetElement = document.getElementById(targetId);
      const successMsg = document.getElementById(targetId + "-copy-success");

      targetElement.select();
      document.execCommand("copy");

      successMsg.style.display = "inline";
      setTimeout(() => {
        successMsg.style.display = "none";
      }, 2000);
    });
  });

  // Background pattern change handlers
  bgPatternInputs.forEach((input) => {
    input.addEventListener("change", updateBackground);
  });

  function updateBackground() {
    const pattern = document.querySelector('input[name="bg-pattern"]:checked')
      .value;
    const previewContainer = document.querySelector(".preview-container");

    switch (pattern) {
      case "white":
        previewContainer.classList.remove("white-check", "dark-check", "black");
        previewContainer.classList.add("white");
        break;
      case "white-check":
        previewContainer.classList.remove("white", "dark-check", "black");
        previewContainer.classList.add("white-check");
        break;
      case "dark-check":
        previewContainer.classList.remove("white", "white-check", "black");
        previewContainer.classList.add("dark-check");
        break;
      case "black":
        previewContainer.classList.remove("white", "white-check", "dark-check");
        previewContainer.classList.add("black");
        break;
    }
  }

  // Generate initial pattern
  generatePattern();
});

// Generate the pattern based on user inputs
function generatePattern() {
  const patternType = document.getElementById("pattern-type").value;
  const patternWidth = document.getElementById("pattern-width").value;
  const patternHeight = document.getElementById("pattern-height").value;
  const patternRotation = document.getElementById("pattern-rotation").value;
  const patternScale = document.getElementById("pattern-scale").value;

  // Get pattern content based on selected type
  let patternContent = "";

  if (patternType === "custom") {
    patternContent = document.getElementById("custom-svg").value;
  } else if (patternType === "url") {
    const imageUrl = document.getElementById("image-url").value;
    if (imageUrl) {
      patternContent = `<image href="${imageUrl}" x="0" y="0" width="${patternWidth}" height="${patternHeight}" />`;
    }
  }

  // Generate SVG with the pattern
  const transform = [];
  if (patternRotation !== "0") {
    transform.push(`rotate(${patternRotation})`);
  }
  if (patternScale !== "1") {
    transform.push(`scale(${patternScale})`);
  }

  const transformAttribute =
    transform.length > 0 ? `patternTransform="${transform.join(" ")}"` : "";

  const svgContent = `<svg xmlns="http://www.w3.org/2000/svg" width="100%" height="100%">
  <defs>
    <pattern id="pattern" width="${patternWidth}" height="${patternHeight}" patternUnits="userSpaceOnUse" ${transformAttribute}>
      ${patternContent}
    </pattern>
  </defs>
  <rect width="100%" height="100%" fill="url(#pattern)" />
</svg>`;

  // Update outputs
  document.getElementById("svg-output").value = svgContent;

  // URL encode the SVG for CSS
  const encodedSvg = svgContent
    .replace(/"/g, "'")
    .replace(/#/g, "%23")
    .replace(/</g, "%3C")
    .replace(/>/g, "%3E")
    .replace(/\s+/g, " ")
    .replace(/\n/g, "");

  const cssOutput = `background-image: url("data:image/svg+xml,${encodedSvg}");`;
  document.getElementById("css-output").value = cssOutput;

  // Update preview
  document.getElementById(
    "pattern-preview"
  ).style.backgroundImage = `url("data:image/svg+xml,${encodedSvg}")`;
}

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

This Pen doesn't use any external JavaScript resources.