<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}")`;
}
This Pen doesn't use any external CSS resources.
This Pen doesn't use any external JavaScript resources.