v2.2
MENU ANIMATIONS
UI SURECART
BUTTONS
<!DOCTYPE html>
<html lang="en">
<head>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet">
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Folder Animation Configurator - BricksFusion</title>
<style>
:root {
--background: #000;
--card-bg: #1e1e1e;
--card-bg-hover: #252525;
--text-primary: #f2f2f7;
--text-secondary: #8e8e93;
--accent: #ef6013;
--accent-hover: #c64c0c;
--border: #2c2c2e;
--shadow: 0 4px 20px rgba(0, 0, 0, 0.3);
--track: #2c2c2e;
--thumb: #ef6013;
--card-radius: 16px;
--input-radius: 8px;
--button-radius: 12px;
--transition: all 0.25s ease;
--font: 'Inter', BlinkMacSystemFont, "San Francisco", "Helvetica Neue", Helvetica, Arial, sans-serif;
--action-bar-height: 70px;
--success: #28a745;
--warning: #ffc107;
--danger: #dc3545;
}
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: var(--font);
background-color: var(--background);
color: var(--text-primary);
line-height: 1.5;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
padding-bottom: var(--action-bar-height);
}
.action-bar {
position: fixed;
bottom: 0;
left: 0;
right: 0;
height: var(--action-bar-height);
background: linear-gradient(145deg, #1a1a1a, #0f0f0f);
border-top: 1px solid var(--border);
z-index: 1000;
display: flex;
align-items: center;
padding: 0 1.5rem;
gap: 1rem;
box-shadow: 0 -2px 10px rgba(0, 0, 0, 0.3);
backdrop-filter: blur(10px);
}
.breadcrumb {
display: flex;
align-items: center;
gap: 0.5rem;
flex: 1;
}
.breadcrumb-item {
color: var(--text-secondary);
font-size: var(--text-xs);
font-weight: 500;
text-decoration: none;
transition: var(--transition);
padding: 0.5rem 0.75rem;
border-radius: 6px;
}
.breadcrumb-item:hover {
color: var(--text-primary);
background-color: rgba(255, 255, 255, 0.05);
}
.breadcrumb-item.active {
color: var(--accent);
background-color: rgba(239, 96, 19, 0.1);
}
.breadcrumb-separator {
color: var(--text-secondary);
font-size: var(--text-xs);
opacity: 0.5;
}
.action-buttons {
display: flex;
align-items: center;
gap: 0.75rem;
}
.action-btn {
padding: 0.6rem 1rem;
background-color: var(--card-bg);
color: var(--text-primary);
font-family: var(--font);
font-size: var(--text-xs);
font-weight: 500;
border: 1px solid var(--border);
border-radius: var(--button-radius);
cursor: pointer;
transition: var(--transition);
display: flex;
align-items: center;
gap: 0.5rem;
text-decoration: none;
white-space: nowrap;
}
.action-btn:hover {
background-color: var(--card-bg-hover);
border-color: var(--accent);
transform: translateY(-1px);
}
.action-btn.primary {
background: linear-gradient(90deg, var(--accent), #ff8c51);
border-color: var(--accent);
color: white;
}
.action-btn.primary:hover {
background: linear-gradient(90deg, var(--accent-hover), #e67a3f);
transform: translateY(-2px);
box-shadow: 0 4px 12px rgba(239, 96, 19, 0.3);
}
.data-attribute-display {
background-color: rgba(50, 50, 50, 0.8);
border: 1px solid var(--border);
border-radius: 6px;
padding: 0.5rem 0.75rem;
font-family: 'Menlo', 'Monaco', 'Courier New', monospace;
font-size: var(--text-xs);
color: #ff8c51;
cursor: pointer;
transition: var(--transition);
user-select: all;
}
.data-attribute-display:hover {
background-color: rgba(239, 96, 19, 0.2);
border-color: var(--accent);
}
.container {
max-width: 100%;
margin: 0 auto;
padding: 2rem 1.5rem;
}
.page-header {
text-align: center;
margin-bottom: 2rem;
}
.page-title {
font-size: 2.5rem;
font-weight: 700;
color: var(--text-primary);
margin-bottom: 0.5rem;
background: linear-gradient(90deg, var(--accent), #ff8c51);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
}
.page-subtitle {
font-size: var(--text-s);
color: var(--text-secondary);
font-weight: 500;
}
.instructions-toggle {
margin-bottom: 2rem;
}
.instructions-card {
background-color: var(--card-bg);
border: 1px solid var(--border);
border-radius: var(--card-radius);
box-shadow: var(--shadow);
overflow: hidden;
transition: var(--transition);
}
.instructions-header {
padding: 1rem 1.5rem;
cursor: pointer;
transition: var(--transition);
display: flex;
justify-content: space-between;
align-items: center;
border-bottom: 1px solid transparent;
}
.instructions-header:hover {
background-color: var(--card-bg-hover);
}
.instructions-card.expanded .instructions-header {
border-bottom-color: var(--border);
}
.instructions-title {
font-size: var(--text-s);
font-weight: 600;
}
.toggle-icon {
font-size: 1.2em;
transition: transform 0.3s ease;
}
.toggle-icon.expanded {
transform: rotate(180deg);
}
.instructions-content {
padding: 0 1.5rem;
max-height: 0;
overflow: hidden;
transition: max-height 0.3s ease, padding 0.3s ease;
}
.instructions-content.show {
max-height: 500px;
padding: 1.5rem;
}
.instructions-grid {
display: grid;
grid-template-columns: 1fr;
gap: 1.5rem;
}
.how-to-use ol {
padding-left: 1.5rem;
}
.how-to-use li {
margin-bottom: 0.75rem;
font-size: var(--text-xs);
color: var(--text-secondary);
line-height: 1.6;
}
.how-to-use strong {
color: var(--text-primary);
font-weight: 600;
}
.how-to-use code {
background-color: rgba(50, 50, 50, 0.5);
padding: 0.2rem 0.5rem;
border-radius: 4px;
font-family: 'Menlo', 'Monaco', 'Courier New', monospace;
font-size: var(--text-xs);
color: #ff8c51;
}
.content {
display: grid;
grid-template-columns: 1fr 500px;
gap: 2rem;
align-items: start;
}
.preview-section {
position: sticky;
top: 2rem;
}
.controls-section {
max-width: 500px;
}
.card {
background-color: var(--card-bg);
border-radius: var(--card-radius);
box-shadow: var(--shadow);
overflow: hidden;
margin-bottom: 1.5rem;
border: 1px solid var(--border);
transition: transform 0.3s ease, box-shadow 0.3s ease;
}
.card:hover {
transform: translateY(-2px);
box-shadow: 0 6px 24px rgba(0, 0, 0, 0.4);
}
.preview-container {
height: 400px;
width: 100%;
position: relative;
overflow: visible;
border-radius: var(--card-radius);
background-color: #252525;
border: 1px solid var(--border);
box-shadow: var(--shadow);
display: flex;
align-items: center;
justify-content: center;
padding: 2rem 1.5rem 1.5rem 1.5rem;
box-sizing: border-box;
}
#folder-preview.preview-container {
height: 400px !important;
min-height: 400px !important;
max-height: 400px !important;
overflow: visible !important;
position: relative !important;
box-sizing: border-box !important;
display: flex !important;
align-items: center !important;
justify-content: center !important;
contain: layout style !important;
padding: 2rem 1.5rem 1.5rem 1.5rem !important;
}
.preview-container * {
box-sizing: border-box !important;
}
.preview-container .particle {
pointer-events: none !important;
z-index: 10 !important;
}
.preview-content {
color: white;
text-align: center;
font-weight: bold;
font-size: var(--text-s);
text-shadow: 0 2px 4px rgba(0, 0, 0, 0.5);
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
z-index: 2;
}
.preview-controls {
position: absolute;
top: 1rem;
right: 1rem;
display: flex;
gap: 0.5rem;
z-index: 10;
}
.preview-btn {
padding: 0.5rem;
background-color: rgba(0, 0, 0, 0.7);
color: white;
border: 1px solid rgba(255, 255, 255, 0.2);
border-radius: 6px;
cursor: pointer;
transition: var(--transition);
font-size: var(--text-xs);
backdrop-filter: blur(5px);
}
.preview-btn:hover {
background-color: var(--accent);
border-color: var(--accent);
}
.preview-btn svg {
width: 18px;
height: 18px;
stroke: currentColor;
}
.background-selector-wrapper {
position: relative;
display: inline-block;
}
.background-selector-btn {
position: relative;
}
.background-selector-btn:hover {
background-color: rgba(239, 96, 19, 0.2);
border-color: var(--accent);
box-shadow: 0 0 8px rgba(239, 96, 19, 0.3);
}
.hidden-color-input {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
opacity: 0;
cursor: pointer;
z-index: 1;
}
.card-heading {
padding: 1rem 1.5rem;
font-size: var(--text-s);
font-weight: 600;
border-bottom: 1px solid var(--border);
letter-spacing: 0.3px;
display: flex;
justify-content: space-between;
align-items: center;
}
.card-actions {
display: flex;
gap: 0.5rem;
}
.card-action-btn {
padding: 0.4rem 0.8rem;
background-color: transparent;
color: var(--text-secondary);
border: 1px solid var(--border);
border-radius: 6px;
cursor: pointer;
font-size: var(--text-xs);
transition: var(--transition);
}
.card-action-btn:hover {
color: var(--text-primary);
border-color: var(--accent);
background-color: rgba(239, 96, 19, 0.1);
}
.card-content {
padding: 1.5rem;
}
.control-group {
margin-bottom: 1.5rem;
position: relative;
}
.control-group:last-child {
margin-bottom: 0;
}
.control-label {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 0.75rem;
}
.label-text {
font-size: var(--text-xs);
font-weight: 500;
letter-spacing: 0.2px;
display: flex;
align-items: center;
gap: 0.5rem;
}
.help-tooltip {
cursor: help;
opacity: 0.7;
transition: var(--transition);
}
.help-tooltip:hover {
opacity: 1;
color: var(--accent);
}
.value-display {
display: flex;
align-items: center;
gap: 0.5rem;
}
.value-text {
font-size: var(--text-xs);
color: var(--text-secondary);
background-color: rgba(50, 50, 50, 0.5);
padding: 2px 8px;
border-radius: 4px;
min-width: 45px;
text-align: center;
}
.reset-btn {
padding: 0.2rem 0.4rem;
background-color: transparent;
color: var(--text-secondary);
border: 1px solid var(--border);
border-radius: 4px;
cursor: pointer;
font-size: 10px;
transition: var(--transition);
}
.reset-btn:hover {
color: var(--danger);
border-color: var(--danger);
background-color: rgba(220, 53, 69, 0.1);
}
input[type="range"] {
-webkit-appearance: none;
width: 100%;
height: 6px;
background: var(--track);
border-radius: 3px;
outline: none;
margin: 0.8rem 0;
position: relative;
}
input[type="range"]::-webkit-slider-thumb {
-webkit-appearance: none;
width: 20px;
height: 20px;
background: var(--thumb);
border-radius: 50%;
cursor: pointer;
transition: var(--transition);
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.3);
}
input[type="range"]::-webkit-slider-thumb:hover {
transform: scale(1.2);
box-shadow: 0 0 10px rgba(239, 96, 19, 0.5);
}
.color-list {
display: flex;
flex-direction: column;
gap: 1rem;
margin-bottom: 1.5rem;
}
.color-row {
display: flex;
align-items: center;
gap: 1.25rem;
padding: 1rem 1.25rem;
background-color: rgba(30, 30, 30, 0.7);
border: 1px solid var(--border);
border-radius: var(--input-radius);
transition: var(--transition);
}
.color-row:hover {
border-color: var(--accent);
box-shadow: 0 0 0 1px rgba(239, 96, 19, 0.1);
}
.color-picker-container {
position: relative;
width: 40px;
height: 40px;
border-radius: 8px;
overflow: hidden;
border: 2px solid var(--border);
cursor: pointer;
transition: var(--transition);
flex-shrink: 0;
background: var(--card-bg);
display: flex;
align-items: center;
justify-content: center;
--selected-color: #00d8ff;
}
.color-picker-container:hover {
border-color: var(--accent);
transform: scale(1.05);
box-shadow: 0 0 12px rgba(239, 96, 19, 0.3);
}
.color-picker-container::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: var(--selected-color, #00d8ff);
border-radius: 6px;
transition: var(--transition);
}
input[type="color"] {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
border: none;
cursor: pointer;
background: transparent;
opacity: 0;
z-index: 2;
}
.color-input-group {
display: flex;
flex-direction: column;
gap: 0.5rem;
}
.color-label {
font-size: 10px;
font-weight: 500;
color: var(--text-secondary);
text-transform: uppercase;
letter-spacing: 0.5px;
margin-left: 0.25rem;
}
.color-input {
padding: 0.5rem 0.75rem;
background-color: rgba(0, 0, 0, 0.3);
border: 1px solid var(--border);
border-radius: 6px;
color: var(--text-primary);
font-family: 'Menlo', 'Monaco', 'Courier New', monospace;
font-size: 12px;
transition: var(--transition);
min-width: 0;
}
.color-input:focus {
border-color: var(--accent);
box-shadow: 0 0 0 1px rgba(239, 96, 19, 0.2);
outline: none;
}
.color-input.invalid {
border-color: var(--danger);
box-shadow: 0 0 0 1px rgba(220, 53, 69, 0.2);
}
.hex-input,
.hsl-input {
width: 100%;
}
.color-input-group:nth-child(2) {
flex: 0.3;
}
.color-input-group:nth-child(3) {
flex: 0.7;
}
.image-list {
display: flex;
flex-direction: column;
gap: 1rem;
margin-bottom: 1.5rem;
}
.image-row {
display: flex;
align-items: center;
gap: 1rem;
padding: 1rem;
background-color: rgba(30, 30, 30, 0.7);
border: 1px solid var(--border);
border-radius: var(--input-radius);
transition: var(--transition);
}
.image-row:hover {
border-color: var(--accent);
box-shadow: 0 0 0 1px rgba(239, 96, 19, 0.1);
}
.image-preview-container {
width: 50px;
height: 40px;
border-radius: 6px;
overflow: hidden;
border: 2px solid var(--border);
background: var(--card-bg);
display: flex;
align-items: center;
justify-content: center;
flex-shrink: 0;
position: relative;
}
.image-preview {
width: 100%;
height: 100%;
object-fit: cover;
transition: var(--transition);
}
.image-placeholder {
font-size: 12px;
color: var(--text-secondary);
text-align: center;
}
.image-input-group {
flex: 1;
display: flex;
flex-direction: column;
gap: 0.5rem;
}
.image-label {
font-size: 10px;
font-weight: 500;
color: var(--text-secondary);
text-transform: uppercase;
letter-spacing: 0.5px;
}
.image-input {
padding: 0.5rem 0.75rem;
background-color: rgba(0, 0, 0, 0.3);
border: 1px solid var(--border);
border-radius: 6px;
color: var(--text-primary);
font-family: var(--font);
font-size: 12px;
transition: var(--transition);
}
.image-input:focus {
border-color: var(--accent);
box-shadow: 0 0 0 1px rgba(239, 96, 19, 0.2);
outline: none;
}
.image-input.invalid {
border-color: var(--danger);
box-shadow: 0 0 0 1px rgba(220, 53, 69, 0.2);
}
.image-fit-selector {
width: 100px;
padding: 0.4rem 0.6rem;
background-color: rgba(0, 0, 0, 0.3);
border: 1px solid var(--border);
border-radius: 6px;
color: var(--text-primary);
font-family: var(--font);
font-size: 11px;
transition: var(--transition);
flex-shrink: 0;
}
.image-fit-selector:focus {
border-color: var(--accent);
box-shadow: 0 0 0 1px rgba(239, 96, 19, 0.2);
outline: none;
}
select {
width: 100%;
padding: 0.75rem;
border: 1px solid var(--border);
border-radius: var(--input-radius);
font-family: var(--font);
font-size: var(--text-xs);
color: var(--text-primary);
background-color: var(--card-bg);
margin-bottom: 0.75rem;
outline: none;
transition: var(--transition);
}
select:focus {
border-color: var(--accent);
box-shadow: 0 0 0 2px rgba(239, 96, 19, 0.2);
}
.notification {
position: fixed;
bottom: calc(var(--action-bar-height) + 1rem);
left: 50%;
background-color: var(--success);
color: white;
padding: 0.75rem 1rem;
border-radius: var(--input-radius);
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
z-index: 1001;
transform: translate(-50%, 200px);
opacity: 0;
transition: transform 0.4s cubic-bezier(0.4, 0, 0.2, 1), opacity 0.4s ease;
font-size: var(--text-xs);
font-weight: 500;
max-width: 320px;
word-wrap: break-word;
line-height: 1.4;
text-align: center;
}
.notification.show {
transform: translate(-50%, 0);
opacity: 1;
}
.bricks-folder {
position: relative;
width: 100%;
height: 100%;
display: flex;
justify-content: center;
align-items: center;
overflow: hidden;
max-width: 100%;
max-height: 100%;
padding: 1rem;
box-sizing: border-box;
}
.bricks-folder * {
box-sizing: border-box;
}
.bricks-folder .particle {
pointer-events: none !important;
z-index: 10 !important;
}
.bricks-folder .folder {
transition: all var(--folder-speed, 0.3s) ease-in;
cursor: pointer;
max-width: 150px;
max-height: 120px;
}
.bricks-folder .folder:not(.folder--click):hover {
transform: translateY(-8px);
}
.bricks-folder .folder:not(.folder--click):hover .paper {
transform: translate(-50%, 0%);
}
.bricks-folder .folder:not(.folder--click):hover .folder__front {
transform: skew(15deg) scaleY(0.6);
}
.bricks-folder .folder:not(.folder--click):hover .right {
transform: skew(-15deg) scaleY(0.6);
}
.bricks-folder .folder.open {
transform: translateY(-8px);
}
.bricks-folder .folder.open .paper:nth-child(1) {
transform: translate(-120%, -70%) rotateZ(-15deg);
}
.bricks-folder .folder.open .paper:nth-child(1):hover {
transform: translate(-120%, -70%) rotateZ(-15deg) scale(1.1);
}
.bricks-folder .folder.open .paper:nth-child(2) {
transform: translate(10%, -70%) rotateZ(15deg);
height: 80%;
}
.bricks-folder .folder.open .paper:nth-child(2):hover {
transform: translate(10%, -70%) rotateZ(15deg) scale(1.1);
}
.bricks-folder .folder.open .paper:nth-child(3) {
transform: translate(-50%, -100%) rotateZ(5deg);
height: 80%;
}
.bricks-folder .folder.open .paper:nth-child(3):hover {
transform: translate(-50%, -100%) rotateZ(5deg) scale(1.1);
}
.bricks-folder .folder.open .folder__front {
transform: skew(15deg) scaleY(0.6);
}
.bricks-folder .folder.open .right {
transform: skew(-15deg) scaleY(0.6);
}
.bricks-folder .paper.magnetic {
transform: translate(-50%, 10%) translate(var(--magnet-x, 0), var(--magnet-y, 0));
}
.bricks-folder .folder.open .paper.magnetic:nth-child(1) {
transform: translate(-120%, -70%) rotateZ(-15deg) translate(var(--magnet-x, 0), var(--magnet-y, 0));
}
.bricks-folder .folder.open .paper.magnetic:nth-child(2) {
transform: translate(10%, -70%) rotateZ(15deg) translate(var(--magnet-x, 0), var(--magnet-y, 0));
}
.bricks-folder .folder.open .paper.magnetic:nth-child(3) {
transform: translate(-50%, -100%) rotateZ(5deg) translate(var(--magnet-x, 0), var(--magnet-y, 0));
}
.bricks-folder .folder__back {
position: relative;
width: 100px;
height: 80px;
background: var(--folder-back-color);
border-radius: 0px 10px 10px 10px;
}
.bricks-folder .folder__back::after {
position: absolute;
z-index: 0;
bottom: 98%;
left: 0;
content: "";
width: 30px;
height: 10px;
background: var(--folder-back-color);
border-radius: 5px 5px 0 0;
}
.bricks-folder .paper {
position: absolute;
z-index: 2;
bottom: 10%;
left: 50%;
transform: translate(-50%, 10%);
width: 70%;
height: 80%;
background: var(--paper-1);
border-radius: 10px;
transition: all var(--folder-speed, 0.3s) ease-in-out;
background-size: var(--paper-size, cover);
background-position: center;
background-repeat: no-repeat;
}
.bricks-folder .paper:nth-child(2) {
background: var(--paper-2);
background-size: var(--paper-size, cover);
background-position: center;
background-repeat: no-repeat;
width: 80%;
height: 70%;
}
.bricks-folder .paper:nth-child(3) {
background: var(--paper-3);
background-size: var(--paper-size, cover);
background-position: center;
background-repeat: no-repeat;
width: 90%;
height: 60%;
}
.bricks-folder .folder__front {
position: absolute;
z-index: 3;
width: 100%;
height: 100%;
background: var(--folder-color);
border-radius: 5px 10px 10px 10px;
transform-origin: bottom;
transition: all var(--folder-speed, 0.3s) ease-in-out;
}
.bricks-folder .folder__front.right {
width: 50%;
right: 0;
}
.particle {
position: absolute;
pointer-events: none;
z-index: 1000;
}
.particle.sparkle {
width: 4px;
height: 4px;
background: radial-gradient(circle, #fff 0%, transparent 70%);
border-radius: 50%;
animation: sparkleFloat 2s ease-out forwards;
}
.particle.dot {
width: 3px;
height: 3px;
background: var(--folder-color);
border-radius: 50%;
animation: dotFloat 1.5s ease-out forwards;
}
.particle.star {
width: 6px;
height: 6px;
background: #ffd700;
clip-path: polygon(50% 0%, 61% 35%, 98% 35%, 68% 57%, 79% 91%, 50% 70%, 21% 91%, 32% 57%, 2% 35%, 39% 35%);
animation: starFloat 2.5s ease-out forwards;
}
@keyframes sparkleFloat {
0% {
opacity: 1;
transform: translate(0, 0) scale(0);
}
50% {
opacity: 1;
transform: translate(var(--random-x, 0), var(--random-y, 0)) scale(1);
}
100% {
opacity: 0;
transform: translate(var(--random-x, 0), var(--random-y, 0)) scale(0);
}
}
@keyframes dotFloat {
0% {
opacity: 1;
transform: translate(0, 0) scale(1);
}
100% {
opacity: 0;
transform: translate(var(--random-x, 0), var(--random-y, 0)) scale(0);
}
}
@keyframes starFloat {
0% {
opacity: 1;
transform: translate(0, 0) scale(0) rotate(0deg);
}
50% {
opacity: 1;
transform: translate(var(--random-x, 0), var(--random-y, 0)) scale(1) rotate(180deg);
}
100% {
opacity: 0;
transform: translate(var(--random-x, 0), var(--random-y, 0)) scale(0) rotate(360deg);
}
}
@media (max-width: 1200px) {
.content {
grid-template-columns: 1fr;
gap: 1.5rem;
}
.preview-section {
position: static;
}
.controls-section {
max-width: 100%;
}
}
@media (max-width: 768px) {
.action-bar {
flex-direction: column;
height: auto;
min-height: var(--action-bar-height);
padding: 0.75rem;
}
.breadcrumb {
order: 1;
width: 100%;
}
.action-buttons {
order: 2;
width: 100%;
justify-content: center;
flex-wrap: wrap;
}
body {
padding-bottom: calc(var(--action-bar-height) + 20px);
}
.notification {
bottom: calc(var(--action-bar-height) + 2rem);
max-width: 280px;
transform: translate(-50%, 250px);
}
.notification.show {
transform: translate(-50%, 0);
opacity: 1;
}
.color-row {
flex-direction: column;
align-items: stretch;
gap: 1rem;
padding: 1rem;
}
.color-picker-container {
align-self: center;
margin-bottom: 0.5rem;
}
.color-input-group {
align-items: stretch;
}
.hex-input,
.hsl-input {
width: 100%;
}
.image-row {
flex-direction: column;
align-items: stretch;
gap: 0.75rem;
padding: 1rem;
}
.image-preview-container {
align-self: center;
margin-bottom: 0.5rem;
}
.preview-container {
height: 300px;
padding: 1.5rem 1rem 1rem 1rem;
}
.data-attribute-display {
font-size: 10px;
padding: 0.4rem 0.6rem;
}
.action-btn {
font-size: 11px;
padding: 0.5rem 0.8rem;
}
.page-title {
font-size: 2rem;
}
}
@media (prefers-reduced-motion: reduce) {
.bricks-folder .folder,
.bricks-folder .paper,
.bricks-folder .folder__front {
transition: none;
}
}
@media (prefers-reduced-motion: reduce) {
* {
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.01ms !important;
}
}
button:focus-visible,
input:focus-visible,
.action-btn:focus-visible {
outline: 2px solid var(--accent);
outline-offset: 2px;
}
::-webkit-scrollbar {
width: 8px;
}
::-webkit-scrollbar-track {
background: var(--background);
}
::-webkit-scrollbar-thumb {
background: var(--border);
border-radius: 4px;
}
::-webkit-scrollbar-thumb:hover {
background: var(--accent);
}
.loading {
opacity: 0.6;
pointer-events: none;
position: relative;
}
.loading::after {
content: '';
position: absolute;
top: 50%;
left: 50%;
width: 20px;
height: 20px;
margin: -10px 0 0 -10px;
border: 2px solid var(--border);
border-top-color: var(--accent);
border-radius: 50%;
animation: spin 1s linear infinite;
}
@keyframes spin {
to { transform: rotate(360deg); }
}
</style>
</head>
<body>
<div class="action-bar">
<nav class="breadcrumb">
<a href="https://bricksfusion.com" class="breadcrumb-item">Home</a>
<span class="breadcrumb-separator">›</span>
<a href="https://bricksfusion.com/interaction/" class="breadcrumb-item">Interactions</a>
<span class="breadcrumb-separator">›</span>
<span class="breadcrumb-item active">Folder Animation</span>
</nav>
<div class="action-buttons">
<div class="data-attribute-display" id="quick-attribute" title="Click to copy data attribute">
data-folder
</div>
<button class="action-btn primary" id="download-config" title="Copy JavaScript code (Ctrl+D)" data-protection-animation="true">
<span>📋</span>
Copy JS
</button>
<button class="action-btn" id="copy-full-section" title="Copy complete section JSON for Bricks Builder (Ctrl+S)" data-protection-animation="true">
<span>📦</span>
Copy Full Section
</button>
</div>
</div>
<div class="container">
<div class="page-header">
<h1 class="page-title">Folder Animation</h1>
<p class="page-subtitle">Interactive folder animations with images for Bricks Builder</p>
</div>
<div class="instructions-toggle">
<div class="instructions-card" id="instructions-card">
<div class="instructions-header" id="instructions-toggle">
<div class="instructions-title">
How to Use & Code Information
</div>
<span class="toggle-icon">▼</span>
</div>
<div class="instructions-content" id="instructions-content">
<div class="instructions-grid">
<div class="how-to-use">
<ol>
<li>Customize your folder animation using the controls below</li>
<li>Add image URLs to display content in the papers when the folder opens</li>
<li>Click <strong>Copy JS</strong> to copy the JavaScript code to clipboard</li>
<li>In Bricks Builder, add a <strong>Code</strong> element</li>
<li>Paste or upload the JavaScript code</li>
<li>To add the effect to any container: go to <strong>Section → Style → Attributes</strong>, add <code>data-folder</code> as attribute name (leave value empty)</li>
</ol>
</div>
</div>
</div>
</div>
</div>
<div class="content">
<section class="preview-section">
<div class="preview-container" id="folder-preview" data-folder="true">
<div class="preview-content">Interactive Folder Animation Preview</div>
<div class="preview-controls">
<button class="preview-btn" id="randomize-folder" title="Randomize (R)">🎲</button>
<div class="background-selector-wrapper">
<button class="preview-btn background-selector-btn" id="background-selector">
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<polygon points="12,2 2,7 12,12 22,7"/>
<polyline points="2,17 12,22 22,17"/>
<polyline points="2,12 12,17 22,12"/>
</svg>
</button>
<input type="color" id="preview-background-picker" class="hidden-color-input" value="#252525" title="Change Preview Background (B)">
</div>
</div>
</div>
</section>
<section class="controls-section">
<div class="card">
<div class="card-heading">
Folder Color
<div class="card-actions">
<button class="card-action-btn" id="reset-colors" title="Reset Colors">↺</button>
</div>
</div>
<div class="card-content">
<div class="color-list">
<div class="color-row">
<div class="color-picker-container">
<input type="color" id="folder-color" value="#00d8ff">
</div>
<div class="color-input-group">
<span class="color-label">HEX</span>
<input type="text" class="color-input hex-input" id="folder-color-hex" value="#00d8ff" placeholder="#FFFFFF">
</div>
<div class="color-input-group">
<span class="color-label">HSL</span>
<input type="text" class="color-input hsl-input" id="folder-color-hsl" placeholder="hsl(0, 100%, 50%)">
</div>
</div>
</div>
</div>
</div>
<div class="card">
<div class="card-heading">
Paper Colors
<div class="card-actions">
<button class="card-action-btn" id="reset-papers" title="Reset Paper Colors">↺</button>
</div>
</div>
<div class="card-content">
<div class="color-list">
<div class="color-row">
<div class="color-picker-container">
<input type="color" id="paper1-color" value="#E6E6E6">
</div>
<div class="color-input-group">
<span class="color-label">HEX</span>
<input type="text" class="color-input hex-input" id="paper1-color-hex" value="#E6E6E6" placeholder="#FFFFFF">
</div>
<div class="color-input-group">
<span class="color-label">HSL</span>
<input type="text" class="color-input hsl-input" id="paper1-color-hsl" placeholder="hsl(0, 100%, 50%)">
</div>
</div>
<div class="color-row">
<div class="color-picker-container">
<input type="color" id="paper2-color" value="#F2F2F2">
</div>
<div class="color-input-group">
<span class="color-label">HEX</span>
<input type="text" class="color-input hex-input" id="paper2-color-hex" value="#F2F2F2" placeholder="#FFFFFF">
</div>
<div class="color-input-group">
<span class="color-label">HSL</span>
<input type="text" class="color-input hsl-input" id="paper2-color-hsl" placeholder="hsl(0, 100%, 50%)">
</div>
</div>
<div class="color-row">
<div class="color-picker-container">
<input type="color" id="paper3-color" value="#FFFFFF">
</div>
<div class="color-input-group">
<span class="color-label">HEX</span>
<input type="text" class="color-input hex-input" id="paper3-color-hex" value="#FFFFFF" placeholder="#FFFFFF">
</div>
<div class="color-input-group">
<span class="color-label">HSL</span>
<input type="text" class="color-input hsl-input" id="paper3-color-hsl" placeholder="hsl(0, 100%, 50%)">
</div>
</div>
</div>
</div>
</div>
<div class="card">
<div class="card-heading">
Paper Images
<div class="card-actions">
<button class="card-action-btn" id="reset-images" title="Reset Images">↺</button>
</div>
</div>
<div class="card-content">
<div class="control-group">
<div class="control-label">
<span class="label-text">
Image Fit
<span class="help-tooltip" title="How images should fit within the papers">ℹ</span>
</span>
</div>
<select id="image-fit">
<option value="cover">Cover (crop to fill)</option>
<option value="contain">Contain (fit inside)</option>
<option value="fill">Fill (stretch)</option>
</select>
</div>
<div class="image-list">
<div class="image-row">
<div class="image-preview-container">
<img id="paper1-preview" class="image-preview" style="display: none;" alt="Paper 1">
<div id="paper1-placeholder" class="image-placeholder">IMG</div>
</div>
<div class="image-input-group">
<span class="image-label">Paper 1 URL</span>
<input type="url" class="image-input" id="paper1-image" placeholder="https://example.com/image1.jpg">
</div>
</div>
<div class="image-row">
<div class="image-preview-container">
<img id="paper2-preview" class="image-preview" style="display: none;" alt="Paper 2">
<div id="paper2-placeholder" class="image-placeholder">IMG</div>
</div>
<div class="image-input-group">
<span class="image-label">Paper 2 URL</span>
<input type="url" class="image-input" id="paper2-image" placeholder="https://example.com/image2.jpg">
</div>
</div>
<div class="image-row">
<div class="image-preview-container">
<img id="paper3-preview" class="image-preview" style="display: none;" alt="Paper 3">
<div id="paper3-placeholder" class="image-placeholder">IMG</div>
</div>
<div class="image-input-group">
<span class="image-label">Paper 3 URL</span>
<input type="url" class="image-input" id="paper3-image" placeholder="https://example.com/image3.jpg">
</div>
</div>
</div>
</div>
</div>
<div class="card">
<div class="card-heading">
Animation Settings
<div class="card-actions">
<button class="card-action-btn" id="reset-animation" title="Reset Animation Settings">↺</button>
</div>
</div>
<div class="card-content">
<div class="control-group">
<div class="control-label">
<span class="label-text">
Folder Size
<span class="help-tooltip" title="Scale of the folder element">ℹ</span>
</span>
<div class="value-display">
<span class="value-text"><span id="folder-size-value">1</span>x</span>
<button class="reset-btn" onclick="resetParameter('folder-size', 1)">↺</button>
</div>
</div>
<input type="range" id="folder-size" min="0.5" max="3" step="0.1" value="1">
</div>
<div class="control-group">
<div class="control-label">
<span class="label-text">
Paper Items
<span class="help-tooltip" title="Number of paper documents inside the folder">ℹ</span>
</span>
<div class="value-display">
<span class="value-text"><span id="folder-items-value">3</span></span>
<button class="reset-btn" onclick="resetParameter('folder-items', 3)">↺</button>
</div>
</div>
<input type="range" id="folder-items" min="1" max="3" step="1" value="3">
</div>
<div class="control-group">
<div class="control-label">
<span class="label-text">
Animation Speed
<span class="help-tooltip" title="Speed of hover and click animations">ℹ</span>
</span>
<div class="value-display">
<span class="value-text"><span id="hover-speed-value">0.3</span>s</span>
<button class="reset-btn" onclick="resetParameter('hover-speed', 0.3)">↺</button>
</div>
</div>
<input type="range" id="hover-speed" min="0.1" max="1" step="0.1" value="0.3">
</div>
</div>
</div>
<div class="card">
<div class="card-heading">
Advanced Options
<div class="card-actions">
<button class="card-action-btn" id="reset-advanced" title="Reset Advanced Settings">↺</button>
</div>
</div>
<div class="card-content">
<div class="control-group">
<div class="control-label">
<span class="label-text">
Glow Effect
<span class="help-tooltip" title="Intensity of the glow effect around the folder">ℹ</span>
</span>
<div class="value-display">
<span class="value-text"><span id="glow-intensity-value">0</span>%</span>
<button class="reset-btn" onclick="resetParameter('glow-intensity', 0)">↺</button>
</div>
</div>
<input type="range" id="glow-intensity" min="0" max="100" step="10" value="0">
</div>
<div class="control-group">
<div class="control-label">
<span class="label-text">Particles on Open</span>
</div>
<select id="particle-effect">
<option value="none">No particles</option>
<option value="sparkles">Sparkles</option>
<option value="dots">Floating dots</option>
<option value="stars">Stars</option>
</select>
</div>
<div class="control-group">
<div class="control-label">
<span class="label-text">Entrance Animation</span>
</div>
<select id="entrance-animation">
<option value="none">No animation</option>
<option value="fadeIn">Fade in</option>
<option value="slideUp">Slide up</option>
<option value="bounce">Bounce</option>
<option value="rotate">Rotate</option>
</select>
</div>
<div class="control-group">
<div class="control-label">
<span class="label-text">Magnetic Effect</span>
</div>
<select id="magnetic-effect">
<option value="none">Disabled</option>
<option value="subtle">Subtle</option>
<option value="medium">Medium</option>
<option value="strong">Strong</option>
</select>
</div>
</div>
</div>
</section>
</div>
</div>
<div class="notification" id="notification"></div>
<script>
document.addEventListener('DOMContentLoaded', function() {
let folderConfig = {
folderSize: 1,
folderItems: 3,
hoverSpeed: 0.3,
folderColor: "#00d8ff",
paper1Color: "#E6E6E6",
paper2Color: "#F2F2F2",
paper3Color: "#FFFFFF",
paper1Image: "",
paper2Image: "",
paper3Image: "",
imageFit: "cover",
glowIntensity: 0,
particleEffect: "none",
entranceAnimation: "none",
magneticEffect: "none"
};
const defaultConfig = { ...folderConfig };
const sampleImages = [
"https://images.unsplash.com/photo-1557804506-669a67965ba0?w=400&h=300&fit=crop",
"https://images.unsplash.com/photo-1574169208507-84376144848b?w=400&h=300&fit=crop",
"https://images.unsplash.com/photo-1586281380349-632531db7ed4?w=400&h=300&fit=crop",
"https://images.unsplash.com/photo-1461749280684-dccba630e2f6?w=400&h=300&fit=crop",
"https://images.unsplash.com/photo-1488590528505-98d2b5aba04b?w=400&h=300&fit=crop",
"https://images.unsplash.com/photo-1519389950473-47ba0277781c?w=400&h=300&fit=crop"
];
let activeFolderInstances = [];
function initializeFolderAnimation() {
const sections = document.querySelectorAll('[data-folder]:not([data-folder-initialized="true"])');
sections.forEach((section) => {
const config = {
folderSize: section.getAttribute('data-folder-size') ? parseFloat(section.getAttribute('data-folder-size')) : folderConfig.folderSize,
folderItems: section.getAttribute('data-folder-items') ? parseInt(section.getAttribute('data-folder-items')) : folderConfig.folderItems,
hoverSpeed: section.getAttribute('data-folder-speed') ? parseFloat(section.getAttribute('data-folder-speed')) : folderConfig.hoverSpeed,
folderColor: section.getAttribute('data-folder-color') || folderConfig.folderColor,
paper1Color: section.getAttribute('data-folder-paper1-color') || folderConfig.paper1Color,
paper2Color: section.getAttribute('data-folder-paper2-color') || folderConfig.paper2Color,
paper3Color: section.getAttribute('data-folder-paper3-color') || folderConfig.paper3Color,
paper1Image: folderConfig.paper1Image,
paper2Image: folderConfig.paper2Image,
paper3Image: folderConfig.paper3Image,
imageFit: folderConfig.imageFit,
glowIntensity: section.getAttribute('data-folder-glow') ? parseInt(section.getAttribute('data-folder-glow')) : folderConfig.glowIntensity,
particleEffect: section.getAttribute('data-folder-particles') || folderConfig.particleEffect,
entranceAnimation: section.getAttribute('data-folder-entrance') || folderConfig.entranceAnimation,
magneticEffect: section.getAttribute('data-folder-magnetic') || folderConfig.magneticEffect
};
const instance = setupFolderAnimation(section, config);
section.dataset.folderInitialized = 'true';
if (section.id === 'folder-preview') {
activeFolderInstances = [instance];
folderConfig = { ...config };
} else {
activeFolderInstances.push(instance);
}
});
}
function setupFolderAnimation(element, options) {
const folderBackColor = darkenColor(options.folderColor, 0.08);
element.classList.add('bricks-folder');
if (options.glowIntensity > 0) {
element.classList.add('glow');
element.style.setProperty('--glow-size', `${options.glowIntensity / 5}px`);
} else {
element.classList.remove('glow');
}
element.innerHTML = '';
const folderContainer = document.createElement('div');
folderContainer.className = 'folder';
folderContainer.style.setProperty('--folder-color', options.folderColor);
folderContainer.style.setProperty('--folder-back-color', folderBackColor);
folderContainer.style.setProperty('--paper-1', options.paper1Color);
folderContainer.style.setProperty('--paper-2', options.paper2Color);
folderContainer.style.setProperty('--paper-3', options.paper3Color);
folderContainer.style.setProperty('--folder-speed', options.hoverSpeed + 's');
folderContainer.style.setProperty('--folder-scale', options.folderSize);
folderContainer.style.setProperty('--paper-size', options.imageFit);
folderContainer.style.transform = `scale(${options.folderSize})`;
if (options.entranceAnimation !== 'none') {
folderContainer.classList.add(`entrance-${options.entranceAnimation}`);
}
const folderBack = document.createElement('div');
folderBack.className = 'folder__back';
const papers = [];
for (let i = 0; i < options.folderItems; i++) {
const paper = document.createElement('div');
paper.className = `paper paper-${i + 1}`;
if (options.magneticEffect !== 'none') {
paper.classList.add('magnetic');
}
paper.dataset.index = i;
// Apply image if available
const imageUrl = i === 0 ? options.paper1Image : i === 1 ? options.paper2Image : options.paper3Image;
if (imageUrl) {
paper.style.backgroundImage = `url("${imageUrl}")`;
}
papers.push(paper);
folderBack.appendChild(paper);
}
const folderFront = document.createElement('div');
folderFront.className = 'folder__front';
const folderFrontRight = document.createElement('div');
folderFrontRight.className = 'folder__front right';
folderBack.appendChild(folderFront);
folderBack.appendChild(folderFrontRight);
folderContainer.appendChild(folderBack);
element.appendChild(folderContainer);
let isOpen = false;
if (options.magneticEffect !== 'none') {
const magneticStrength = {
'subtle': 0.05,
'medium': 0.15,
'strong': 0.25
}[options.magneticEffect];
papers.forEach((paper) => {
paper.addEventListener('mousemove', (e) => {
if (!isOpen) return;
const rect = paper.getBoundingClientRect();
const centerX = rect.left + rect.width / 2;
const centerY = rect.top + rect.height / 2;
const offsetX = (e.clientX - centerX) * magneticStrength;
const offsetY = (e.clientY - centerY) * magneticStrength;
paper.style.setProperty('--magnet-x', `${offsetX}px`);
paper.style.setProperty('--magnet-y', `${offsetY}px`);
});
paper.addEventListener('mouseleave', () => {
paper.style.setProperty('--magnet-x', '0px');
paper.style.setProperty('--magnet-y', '0px');
});
});
}
function createParticles(x, y) {
if (options.particleEffect === 'none') return;
const particleCount = 8;
const containerRect = element.getBoundingClientRect();
for (let i = 0; i < particleCount; i++) {
const particle = document.createElement('div');
particle.className = `particle ${options.particleEffect === 'sparkles' ? 'sparkle' : options.particleEffect === 'dots' ? 'dot' : 'star'}`;
const randomX = (Math.random() - 0.5) * 100;
const randomY = (Math.random() - 0.5) * 100;
particle.style.position = 'absolute';
particle.style.left = (x - containerRect.left) + 'px';
particle.style.top = (y - containerRect.top) + 'px';
particle.style.setProperty('--random-x', randomX + 'px');
particle.style.setProperty('--random-y', randomY + 'px');
particle.style.setProperty('--folder-color', options.folderColor);
particle.style.pointerEvents = 'none';
particle.style.zIndex = '1000';
element.appendChild(particle);
setTimeout(() => {
if (particle.parentNode) {
particle.parentNode.removeChild(particle);
}
}, 2500);
}
}
folderContainer.addEventListener('click', (e) => {
isOpen = !isOpen;
if (isOpen) {
folderContainer.classList.add('open');
const rect = folderContainer.getBoundingClientRect();
const x = rect.left + rect.width / 2;
const y = rect.top + rect.height / 2;
createParticles(x, y);
} else {
folderContainer.classList.remove('open');
if (options.magneticEffect !== 'none') {
papers.forEach(paper => {
paper.style.setProperty('--magnet-x', '0px');
paper.style.setProperty('--magnet-y', '0px');
});
}
}
});
const instance = {
element,
folderContainer,
papers,
options,
updateConfig: function(newOptions) {
this.options = { ...this.options, ...newOptions };
const opts = this.options;
const folderBackColor = darkenColor(opts.folderColor, 0.08);
this.folderContainer.style.setProperty('--folder-color', opts.folderColor);
this.folderContainer.style.setProperty('--folder-back-color', folderBackColor);
this.folderContainer.style.setProperty('--paper-1', opts.paper1Color);
this.folderContainer.style.setProperty('--paper-2', opts.paper2Color);
this.folderContainer.style.setProperty('--paper-3', opts.paper3Color);
this.folderContainer.style.setProperty('--folder-speed', opts.hoverSpeed + 's');
this.folderContainer.style.setProperty('--folder-scale', opts.folderSize);
this.folderContainer.style.setProperty('--paper-size', opts.imageFit);
this.folderContainer.style.transform = `scale(${opts.folderSize})`;
// Update images
this.papers.forEach((paper, index) => {
const imageUrl = index === 0 ? opts.paper1Image : index === 1 ? opts.paper2Image : opts.paper3Image;
if (imageUrl) {
paper.style.backgroundImage = `url("${imageUrl}")`;
} else {
paper.style.backgroundImage = 'none';
}
});
if (opts.glowIntensity > 0) {
this.element.classList.add('glow');
this.element.style.setProperty('--glow-size', `${opts.glowIntensity / 5}px`);
} else {
this.element.classList.remove('glow');
}
}
};
return instance;
}
function darkenColor(hex, percent) {
let color = hex.startsWith("#") ? hex.slice(1) : hex;
if (color.length === 3) {
color = color
.split("")
.map((c) => c + c)
.join("");
}
const num = parseInt(color, 16);
let r = (num >> 16) & 0xff;
let g = (num >> 8) & 0xff;
let b = num & 0xff;
r = Math.max(0, Math.min(255, Math.floor(r * (1 - percent))));
g = Math.max(0, Math.min(255, Math.floor(g * (1 - percent))));
b = Math.max(0, Math.min(255, Math.floor(b * (1 - percent))));
return (
"#" +
((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1).toUpperCase()
);
}
function updateFolderPreview() {
activeFolderInstances.forEach(instance => {
instance.updateConfig(folderConfig);
});
}
function generateRandomColor() {
return '#' + Math.floor(Math.random() * 16777215).toString(16).padStart(6, '0');
}
function getRandomImage() {
return sampleImages[Math.floor(Math.random() * sampleImages.length)];
}
function showNotification(message, type = 'success') {
const notification = document.getElementById('notification');
notification.textContent = message;
notification.className = `notification ${type}`;
notification.offsetHeight;
notification.style.visibility = 'visible';
notification.classList.add('show');
setTimeout(() => {
notification.classList.remove('show');
setTimeout(() => {
if (!notification.classList.contains('show')) {
notification.style.visibility = 'hidden';
}
}, 400);
}, 3000);
}
function generateRandomFolder() {
folderConfig.folderSize = Math.random() * 2.5 + 0.5;
folderConfig.folderItems = Math.floor(Math.random() * 3) + 1;
folderConfig.hoverSpeed = Math.random() * 0.9 + 0.1;
folderConfig.folderColor = generateRandomColor();
folderConfig.paper1Color = generateRandomColor();
folderConfig.paper2Color = generateRandomColor();
folderConfig.paper3Color = generateRandomColor();
folderConfig.paper1Image = getRandomImage();
folderConfig.paper2Image = getRandomImage();
folderConfig.paper3Image = getRandomImage();
folderConfig.imageFit = ['cover', 'contain', 'fill'][Math.floor(Math.random() * 3)];
folderConfig.glowIntensity = Math.floor(Math.random() * 10) * 10;
folderConfig.particleEffect = ['none', 'sparkles', 'dots', 'stars'][Math.floor(Math.random() * 4)];
folderConfig.entranceAnimation = ['none', 'fadeIn', 'slideUp', 'bounce', 'rotate'][Math.floor(Math.random() * 5)];
folderConfig.magneticEffect = ['none', 'subtle', 'medium', 'strong'][Math.floor(Math.random() * 4)];
const sizeInput = document.getElementById('folder-size');
const itemsInput = document.getElementById('folder-items');
const speedInput = document.getElementById('hover-speed');
const folderColorInput = document.getElementById('folder-color');
const paper1Input = document.getElementById('paper1-color');
const paper2Input = document.getElementById('paper2-color');
const paper3Input = document.getElementById('paper3-color');
const paper1ImageInput = document.getElementById('paper1-image');
const paper2ImageInput = document.getElementById('paper2-image');
const paper3ImageInput = document.getElementById('paper3-image');
const imageFitSelect = document.getElementById('image-fit');
const glowInput = document.getElementById('glow-intensity');
const particleSelect = document.getElementById('particle-effect');
const entranceSelect = document.getElementById('entrance-animation');
const magneticSelect = document.getElementById('magnetic-effect');
if (sizeInput) sizeInput.value = folderConfig.folderSize;
if (itemsInput) itemsInput.value = folderConfig.folderItems;
if (speedInput) speedInput.value = folderConfig.hoverSpeed;
if (folderColorInput) folderColorInput.value = folderConfig.folderColor;
if (paper1Input) paper1Input.value = folderConfig.paper1Color;
if (paper2Input) paper2Input.value = folderConfig.paper2Color;
if (paper3Input) paper3Input.value = folderConfig.paper3Color;
if (paper1ImageInput) paper1ImageInput.value = folderConfig.paper1Image;
if (paper2ImageInput) paper2ImageInput.value = folderConfig.paper2Image;
if (paper3ImageInput) paper3ImageInput.value = folderConfig.paper3Image;
if (imageFitSelect) imageFitSelect.value = folderConfig.imageFit;
if (glowInput) glowInput.value = folderConfig.glowIntensity;
if (particleSelect) particleSelect.value = folderConfig.particleEffect;
if (entranceSelect) entranceSelect.value = folderConfig.entranceAnimation;
if (magneticSelect) magneticSelect.value = folderConfig.magneticEffect;
const sizeValue = document.getElementById('folder-size-value');
const itemsValue = document.getElementById('folder-items-value');
const speedValue = document.getElementById('hover-speed-value');
const glowValue = document.getElementById('glow-intensity-value');
if (sizeValue) sizeValue.textContent = folderConfig.folderSize.toFixed(1);
if (itemsValue) itemsValue.textContent = folderConfig.folderItems;
if (speedValue) speedValue.textContent = folderConfig.hoverSpeed.toFixed(1);
if (glowValue) glowValue.textContent = folderConfig.glowIntensity;
updateAllColorInputs();
updateAllImagePreviews();
updateFolderPreview();
showNotification('Random folder configuration generated!');
}
function updateAllColorInputs() {
updateColorInputs('folder-color', folderConfig.folderColor);
updateColorInputs('paper1-color', folderConfig.paper1Color);
updateColorInputs('paper2-color', folderConfig.paper2Color);
updateColorInputs('paper3-color', folderConfig.paper3Color);
}
function updateAllImagePreviews() {
updateImagePreview('paper1', folderConfig.paper1Image);
updateImagePreview('paper2', folderConfig.paper2Image);
updateImagePreview('paper3', folderConfig.paper3Image);
}
function updateImagePreview(paperId, imageUrl) {
const preview = document.getElementById(`${paperId}-preview`);
const placeholder = document.getElementById(`${paperId}-placeholder`);
if (imageUrl && imageUrl.trim()) {
preview.src = imageUrl;
preview.style.display = 'block';
placeholder.style.display = 'none';
preview.onerror = function() {
preview.style.display = 'none';
placeholder.style.display = 'flex';
};
} else {
preview.style.display = 'none';
placeholder.style.display = 'flex';
}
}
function updateColorInputs(inputId, color) {
const colorInput = document.getElementById(inputId);
const hexInput = document.getElementById(`${inputId}-hex`);
const hslInput = document.getElementById(`${inputId}-hsl`);
if (colorInput && hexInput && hslInput) {
colorInput.value = color;
hexInput.value = color;
hslInput.value = `hsl(${hexToHsl(color).h}, ${hexToHsl(color).s}%, ${hexToHsl(color).l}%)`;
hexInput.classList.remove('invalid');
hslInput.classList.remove('invalid');
const colorPickerContainer = colorInput.closest('.color-row').querySelector('.color-picker-container');
if (colorPickerContainer) {
colorPickerContainer.style.setProperty('--selected-color', color);
}
}
}
function hexToHsl(hex) {
const r = parseInt(hex.slice(1, 3), 16) / 255;
const g = parseInt(hex.slice(3, 5), 16) / 255;
const b = parseInt(hex.slice(5, 7), 16) / 255;
const max = Math.max(r, g, b);
const min = Math.min(r, g, b);
let h, s, l = (max + min) / 2;
if (max === min) {
h = s = 0;
} else {
const d = max - min;
s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
switch (max) {
case r: h = (g - b) / d + (g < b ? 6 : 0); break;
case g: h = (b - r) / d + 2; break;
case b: h = (r - g) / d + 4; break;
}
h /= 6;
}
return {
h: Math.round(h * 360),
s: Math.round(s * 100),
l: Math.round(l * 100)
};
}
function hslToHex(hsl) {
const match = hsl.match(/hsl\(\s*(\d+)\s*,\s*(\d+)%\s*,\s*(\d+)%\s*\)/);
if (!match) return null;
let h = parseInt(match[1]) / 360;
let s = parseInt(match[2]) / 100;
let l = parseInt(match[3]) / 100;
const hue2rgb = (p, q, t) => {
if (t < 0) t += 1;
if (t > 1) t -= 1;
if (t < 1/6) return p + (q - p) * 6 * t;
if (t < 1/2) return q;
if (t < 2/3) return p + (q - p) * (2/3 - t) * 6;
return p;
};
let r, g, b;
if (s === 0) {
r = g = b = l;
} else {
const q = l < 0.5 ? l * (1 + s) : l + s - l * s;
const p = 2 * l - q;
r = hue2rgb(p, q, h + 1/3);
g = hue2rgb(p, q, h);
b = hue2rgb(p, q, h - 1/3);
}
const toHex = (c) => {
const hex = Math.round(c * 255).toString(16);
return hex.length === 1 ? '0' + hex : hex;
};
return `#${toHex(r)}${toHex(g)}${toHex(b)}`;
}
function isValidHex(hex) {
return /^#[0-9A-F]{6}$/i.test(hex);
}
function isValidHsl(hsl) {
return /^hsl\(\s*(\d{1,3})\s*,\s*(\d{1,3})%\s*,\s*(\d{1,3})%\s*\)$/i.test(hsl);
}
function formatHex(value) {
let hex = value.replace(/[^0-9A-Fa-f#]/g, '');
if (!hex.startsWith('#')) {
hex = '#' + hex;
}
if (hex.length > 7) {
hex = hex.substring(0, 7);
}
return hex.toUpperCase();
}
function formatHsl(value) {
const cleanValue = value.replace(/[^\d,\s]/g, '');
const numbers = cleanValue.match(/\d+/g);
if (!numbers || numbers.length < 3) {
const partialMatch = value.match(/(\d+)/g);
if (partialMatch && partialMatch.length >= 1) {
const h = Math.min(360, Math.max(0, parseInt(partialMatch[0]) || 0));
const s = Math.min(100, Math.max(0, parseInt(partialMatch[1]) || 50));
const l = Math.min(100, Math.max(0, parseInt(partialMatch[2]) || 50));
return `hsl(${h}, ${s}%, ${l}%)`;
}
return value;
}
let h = Math.min(360, Math.max(0, parseInt(numbers[0])));
let s = Math.min(100, Math.max(0, parseInt(numbers[1])));
let l = Math.min(100, Math.max(0, parseInt(numbers[2])));
return `hsl(${h}, ${s}%, ${l}%)`;
}
function generateUniqueId() {
return Math.random().toString(36).substring(2, 8);
}
function generateFullSectionJSON() {
// Generar IDs únicos para todos los elementos
const sectionId = generateUniqueId();
const containerId = generateUniqueId();
const divId = generateUniqueId();
const codeId = generateUniqueId();
const containerAttrId = generateUniqueId();
const divAttrId = generateUniqueId();
// Obtener el JavaScript actual con la configuración del usuario
const jsCode = generateJavaScriptCode();
// Crear el objeto JSON completo de Bricks Builder
const bricksJSON = {
"content": [
{
"id": sectionId,
"name": "section",
"parent": 0,
"children": [containerId, codeId],
"settings": {
"_justifyContent": "center"
}
},
{
"id": containerId,
"name": "container",
"parent": sectionId,
"children": [divId],
"settings": {
"_alignSelf": "center",
"_justifyContent": "center",
"_alignItems": "center",
"_direction": "row",
"_attributes": [
{
"id": containerAttrId,
"name": "data-float-container"
}
]
}
},
{
"id": divId,
"name": "div",
"parent": containerId,
"children": [],
"settings": {
"_attributes": [
{
"id": divAttrId,
"name": "data-folder"
}
],
"_height": "150",
"_width": "200",
"_zIndex": "99"
},
"label": "Folder Div"
},
{
"id": codeId,
"name": "code",
"parent": sectionId,
"children": [],
"settings": {
"javascriptCode": jsCode,
"executeCode": true,
"_display": "none"
},
"label": "Folder JS"
}
],
"source": "bricksCopiedElements",
"sourceUrl": "https://test.bricksfusion.com",
"version": "2.0.1",
"globalClasses": [],
"globalElements": []
};
return JSON.stringify(bricksJSON, null, 2);
}
function generateJavaScriptCode() {
return `(function() {
window.BricksFolderAnimation = window.BricksFolderAnimation || {};
const defaultConfig = {
folderSize: ${folderConfig.folderSize},
folderItems: ${folderConfig.folderItems},
hoverSpeed: ${folderConfig.hoverSpeed},
folderColor: "${folderConfig.folderColor}",
paper1Color: "${folderConfig.paper1Color}",
paper2Color: "${folderConfig.paper2Color}",
paper3Color: "${folderConfig.paper3Color}",
paper1Image: "${folderConfig.paper1Image}",
paper2Image: "${folderConfig.paper2Image}",
paper3Image: "${folderConfig.paper3Image}",
imageFit: "${folderConfig.imageFit}",
glowIntensity: ${folderConfig.glowIntensity},
particleEffect: "${folderConfig.particleEffect}",
entranceAnimation: "${folderConfig.entranceAnimation}",
magneticEffect: "${folderConfig.magneticEffect}"
};
const darkenColor = (hex, percent) => {
let color = hex.startsWith("#") ? hex.slice(1) : hex;
if (color.length === 3) {
color = color
.split("")
.map((c) => c + c)
.join("");
}
const num = parseInt(color, 16);
let r = (num >> 16) & 0xff;
let g = (num >> 8) & 0xff;
let b = num & 0xff;
r = Math.max(0, Math.min(255, Math.floor(r * (1 - percent))));
g = Math.max(0, Math.min(255, Math.floor(g * (1 - percent))));
b = Math.max(0, Math.min(255, Math.floor(b * (1 - percent))));
return (
"#" +
((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1).toUpperCase()
);
};
const createStyles = () => {
const styleElement = document.createElement('style');
styleElement.id = 'bricks-folder-animation-styles';
styleElement.textContent = \`
div[data-folder].bricks-folder {
position: relative !important;
display: flex !important;
justify-content: center !important;
align-items: center !important;
overflow: visible !important;
box-sizing: border-box !important;
padding: 1rem !important;
}
.bricks-folder.glow .folder {
filter: drop-shadow(0 0 var(--glow-size, 10px) var(--folder-color));
}
.bricks-folder .folder {
transition: all var(--folder-speed, \${defaultConfig.hoverSpeed}s) ease-in;
cursor: pointer;
}
.bricks-folder .folder.entrance-fadeIn {
animation: folderFadeIn 1s ease-out;
}
.bricks-folder .folder.entrance-slideUp {
animation: folderSlideUp 0.8s ease-out;
}
.bricks-folder .folder.entrance-bounce {
animation: folderBounce 1.2s ease-out;
}
.bricks-folder .folder.entrance-rotate {
animation: folderRotate 1s ease-out;
}
@keyframes folderFadeIn {
from { opacity: 0; transform: scale(0.8); }
to { opacity: 1; transform: scale(var(--folder-scale, 1)); }
}
@keyframes folderSlideUp {
from { opacity: 0; transform: translateY(50px) scale(var(--folder-scale, 1)); }
to { opacity: 1; transform: translateY(0) scale(var(--folder-scale, 1)); }
}
@keyframes folderBounce {
0% { opacity: 0; transform: scale(0.3) scale(var(--folder-scale, 1)); }
50% { opacity: 1; transform: scale(1.1) scale(var(--folder-scale, 1)); }
70% { transform: scale(0.9) scale(var(--folder-scale, 1)); }
100% { transform: scale(1) scale(var(--folder-scale, 1)); }
}
@keyframes folderRotate {
from { opacity: 0; transform: rotate(-180deg) scale(0.5) scale(var(--folder-scale, 1)); }
to { opacity: 1; transform: rotate(0deg) scale(1) scale(var(--folder-scale, 1)); }
}
.bricks-folder .folder:not(.folder--click):hover {
transform: translateY(-8px);
}
.bricks-folder .folder:not(.folder--click):hover .paper {
transform: translate(-50%, 0%);
}
.bricks-folder .folder:not(.folder--click):hover .folder__front {
transform: skew(15deg) scaleY(0.6);
}
.bricks-folder .folder:not(.folder--click):hover .right {
transform: skew(-15deg) scaleY(0.6);
}
.bricks-folder .folder.open {
transform: translateY(-8px);
}
.bricks-folder .folder.open .paper:nth-child(1) {
transform: translate(-120%, -70%) rotateZ(-15deg);
}
.bricks-folder .folder.open .paper:nth-child(1):hover {
transform: translate(-120%, -70%) rotateZ(-15deg) scale(1.1);
}
.bricks-folder .folder.open .paper:nth-child(2) {
transform: translate(10%, -70%) rotateZ(15deg);
height: 80%;
}
.bricks-folder .folder.open .paper:nth-child(2):hover {
transform: translate(10%, -70%) rotateZ(15deg) scale(1.1);
}
.bricks-folder .folder.open .paper:nth-child(3) {
transform: translate(-50%, -100%) rotateZ(5deg);
height: 80%;
}
.bricks-folder .folder.open .paper:nth-child(3):hover {
transform: translate(-50%, -100%) rotateZ(5deg) scale(1.1);
}
.bricks-folder .folder.open .folder__front {
transform: skew(15deg) scaleY(0.6);
}
.bricks-folder .folder.open .right {
transform: skew(-15deg) scaleY(0.6);
}
.bricks-folder .paper.magnetic {
transform: translate(-50%, 10%) translate(var(--magnet-x, 0), var(--magnet-y, 0));
}
.bricks-folder .folder.open .paper.magnetic:nth-child(1) {
transform: translate(-120%, -70%) rotateZ(-15deg) translate(var(--magnet-x, 0), var(--magnet-y, 0));
}
.bricks-folder .folder.open .paper.magnetic:nth-child(2) {
transform: translate(10%, -70%) rotateZ(15deg) translate(var(--magnet-x, 0), var(--magnet-y, 0));
}
.bricks-folder .folder.open .paper.magnetic:nth-child(3) {
transform: translate(-50%, -100%) rotateZ(5deg) translate(var(--magnet-x, 0), var(--magnet-y, 0));
}
.bricks-folder .folder__back {
position: relative;
width: 100px;
height: 80px;
background: var(--folder-back-color);
border-radius: 0px 10px 10px 10px;
}
.bricks-folder .folder__back::after {
position: absolute;
z-index: 0;
bottom: 98%;
left: 0;
content: "";
width: 30px;
height: 10px;
background: var(--folder-back-color);
border-radius: 5px 5px 0 0;
}
.bricks-folder .paper {
position: absolute;
z-index: 2;
bottom: 10%;
left: 50%;
transform: translate(-50%, 10%);
width: 70%;
height: 80%;
background: var(--paper-1);
border-radius: 10px;
transition: all var(--folder-speed, \${defaultConfig.hoverSpeed}s) ease-in-out;
background-size: var(--paper-size, \${defaultConfig.imageFit});
background-position: center;
background-repeat: no-repeat;
}
.bricks-folder .paper:nth-child(2) {
background: var(--paper-2);
background-size: var(--paper-size, \${defaultConfig.imageFit});
background-position: center;
background-repeat: no-repeat;
width: 80%;
height: 70%;
}
.bricks-folder .paper:nth-child(3) {
background: var(--paper-3);
background-size: var(--paper-size, \${defaultConfig.imageFit});
background-position: center;
background-repeat: no-repeat;
width: 90%;
height: 60%;
}
.bricks-folder .folder__front {
position: absolute;
z-index: 3;
width: 100%;
height: 100%;
background: var(--folder-color);
border-radius: 5px 10px 10px 10px;
transform-origin: bottom;
transition: all var(--folder-speed, \${defaultConfig.hoverSpeed}s) ease-in-out;
}
.bricks-folder .folder__front.right {
width: 50%;
right: 0;
}
.particle {
position: absolute;
pointer-events: none;
z-index: 1000;
}
.particle.sparkle {
width: 4px;
height: 4px;
background: radial-gradient(circle, #fff 0%, transparent 70%);
border-radius: 50%;
animation: sparkleFloat 2s ease-out forwards;
}
.particle.dot {
width: 3px;
height: 3px;
background: var(--folder-color);
border-radius: 50%;
animation: dotFloat 1.5s ease-out forwards;
}
.particle.star {
width: 6px;
height: 6px;
background: #ffd700;
clip-path: polygon(50% 0%, 61% 35%, 98% 35%, 68% 57%, 79% 91%, 50% 70%, 21% 91%, 32% 57%, 2% 35%, 39% 35%);
animation: starFloat 2.5s ease-out forwards;
}
@keyframes sparkleFloat {
0% { opacity: 1; transform: translate(0, 0) scale(0); }
50% { opacity: 1; transform: translate(var(--random-x, 0), var(--random-y, 0)) scale(1); }
100% { opacity: 0; transform: translate(var(--random-x, 0), var(--random-y, 0)) scale(0); }
}
@keyframes dotFloat {
0% { opacity: 1; transform: translate(0, 0) scale(1); }
100% { opacity: 0; transform: translate(var(--random-x, 0), var(--random-y, 0)) scale(0); }
}
@keyframes starFloat {
0% { opacity: 1; transform: translate(0, 0) scale(0) rotate(0deg); }
50% { opacity: 1; transform: translate(var(--random-x, 0), var(--random-y, 0)) scale(1) rotate(180deg); }
100% { opacity: 0; transform: translate(var(--random-x, 0), var(--random-y, 0)) scale(0) rotate(360deg); }
}
@media (prefers-reduced-motion: reduce) {
.bricks-folder .folder,
.bricks-folder .paper,
.bricks-folder .folder__front {
transition: none !important;
}
}
\`;
document.head.appendChild(styleElement);
};
const initFolderAnimation = () => {
if (!document.getElementById('bricks-folder-animation-styles')) {
createStyles();
}
const folderElements = document.querySelectorAll('div[data-folder]');
folderElements.forEach(element => {
if (element.hasAttribute('data-folder-initialized')) {
return;
}
element.setAttribute('data-folder-initialized', 'true');
const color = element.getAttribute('data-folder-color') || defaultConfig.folderColor;
const size = parseFloat(element.getAttribute('data-folder-size') || defaultConfig.folderSize);
const itemsCount = Math.min(3, Math.max(1, parseInt(element.getAttribute('data-folder-items') || defaultConfig.folderItems, 10)));
const speed = parseFloat(element.getAttribute('data-folder-speed') || defaultConfig.hoverSpeed);
const glowIntensity = parseInt(element.getAttribute('data-folder-glow') || defaultConfig.glowIntensity);
const particleEffect = element.getAttribute('data-folder-particles') || defaultConfig.particleEffect;
const entranceAnimation = element.getAttribute('data-folder-entrance') || defaultConfig.entranceAnimation;
const magneticEffect = element.getAttribute('data-folder-magnetic') || defaultConfig.magneticEffect;
const paper1Color = element.getAttribute('data-folder-paper1-color') || defaultConfig.paper1Color;
const paper2Color = element.getAttribute('data-folder-paper2-color') || defaultConfig.paper2Color;
const paper3Color = element.getAttribute('data-folder-paper3-color') || defaultConfig.paper3Color;
const folderBackColor = darkenColor(color, 0.08);
element.classList.add('bricks-folder');
if (glowIntensity > 0) {
element.classList.add('glow');
element.style.setProperty('--glow-size', \`\${glowIntensity / 5}px\`);
} else {
element.classList.remove('glow');
}
element.innerHTML = '';
const folderContainer = document.createElement('div');
folderContainer.className = 'folder';
folderContainer.style.setProperty('--folder-color', color);
folderContainer.style.setProperty('--folder-back-color', folderBackColor);
folderContainer.style.setProperty('--paper-1', paper1Color);
folderContainer.style.setProperty('--paper-2', paper2Color);
folderContainer.style.setProperty('--paper-3', paper3Color);
folderContainer.style.setProperty('--folder-speed', speed + 's');
folderContainer.style.setProperty('--folder-scale', size);
folderContainer.style.setProperty('--paper-size', defaultConfig.imageFit);
folderContainer.style.transform = \`scale(\${size})\`;
if (entranceAnimation !== 'none') {
folderContainer.classList.add(\`entrance-\${entranceAnimation}\`);
}
const folderBack = document.createElement('div');
folderBack.className = 'folder__back';
const papers = [];
for (let i = 0; i < itemsCount; i++) {
const paper = document.createElement('div');
paper.className = \`paper paper-\${i + 1}\`;
if (magneticEffect !== 'none') {
paper.classList.add('magnetic');
}
paper.dataset.index = i;
// Apply images from config
const imageUrl = i === 0 ? defaultConfig.paper1Image : i === 1 ? defaultConfig.paper2Image : defaultConfig.paper3Image;
if (imageUrl) {
paper.style.backgroundImage = \`url("\${imageUrl}")\`;
}
papers.push(paper);
folderBack.appendChild(paper);
}
const folderFront = document.createElement('div');
folderFront.className = 'folder__front';
const folderFrontRight = document.createElement('div');
folderFrontRight.className = 'folder__front right';
folderBack.appendChild(folderFront);
folderBack.appendChild(folderFrontRight);
folderContainer.appendChild(folderBack);
element.appendChild(folderContainer);
let isOpen = false;
if (magneticEffect !== 'none') {
const magneticStrength = {
'subtle': 0.05,
'medium': 0.15,
'strong': 0.25
}[magneticEffect];
papers.forEach((paper, index) => {
paper.addEventListener('mousemove', (e) => {
if (!isOpen) return;
const rect = paper.getBoundingClientRect();
const centerX = rect.left + rect.width / 2;
const centerY = rect.top + rect.height / 2;
const offsetX = (e.clientX - centerX) * magneticStrength;
const offsetY = (e.clientY - centerY) * magneticStrength;
paper.style.setProperty('--magnet-x', \`\${offsetX}px\`);
paper.style.setProperty('--magnet-y', \`\${offsetY}px\`);
});
paper.addEventListener('mouseleave', () => {
paper.style.setProperty('--magnet-x', '0px');
paper.style.setProperty('--magnet-y', '0px');
});
});
}
function createParticles(x, y) {
if (particleEffect === 'none') return;
const particleCount = 8;
const containerRect = element.getBoundingClientRect();
for (let i = 0; i < particleCount; i++) {
const particle = document.createElement('div');
particle.className = \`particle \${particleEffect === 'sparkles' ? 'sparkle' : particleEffect === 'dots' ? 'dot' : 'star'}\`;
const randomX = (Math.random() - 0.5) * 100;
const randomY = (Math.random() - 0.5) * 100;
particle.style.position = 'absolute';
particle.style.left = (x - containerRect.left) + 'px';
particle.style.top = (y - containerRect.top) + 'px';
particle.style.setProperty('--random-x', randomX + 'px');
particle.style.setProperty('--random-y', randomY + 'px');
particle.style.setProperty('--folder-color', color);
particle.style.pointerEvents = 'none';
particle.style.zIndex = '1000';
element.appendChild(particle);
setTimeout(() => {
if (particle.parentNode) {
particle.parentNode.removeChild(particle);
}
}, 2500);
}
}
folderContainer.addEventListener('click', (e) => {
isOpen = !isOpen;
if (isOpen) {
folderContainer.classList.add('open');
const rect = folderContainer.getBoundingClientRect();
const x = rect.left + rect.width / 2;
const y = rect.top + rect.height / 2;
createParticles(x, y);
} else {
folderContainer.classList.remove('open');
if (magneticEffect !== 'none') {
papers.forEach(paper => {
paper.style.setProperty('--magnet-x', '0px');
paper.style.setProperty('--magnet-y', '0px');
});
}
}
});
});
};
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', initFolderAnimation);
} else {
initFolderAnimation();
}
document.addEventListener('bricks/layout/loaded', initFolderAnimation);
window.BricksFolderAnimation.init = initFolderAnimation;
})();`;
}
function copyJsToClipboard() {
const jsCode = generateJavaScriptCode();
navigator.clipboard.writeText(jsCode)
.then(() => {
showNotification('JavaScript code copied to clipboard!');
})
.catch(err => {
try {
const textArea = document.createElement('textarea');
textArea.value = jsCode;
textArea.style.position = 'fixed';
textArea.style.opacity = '0';
document.body.appendChild(textArea);
textArea.select();
document.execCommand('copy');
document.body.removeChild(textArea);
showNotification('JavaScript code copied to clipboard!');
} catch (fallbackErr) {
showNotification('Failed to copy to clipboard. Please try again.', 'error');
}
});
}
function copyFullSectionToClipboard() {
const sectionJSON = generateFullSectionJSON();
navigator.clipboard.writeText(sectionJSON)
.then(() => {
showNotification('Full section JSON copied to clipboard!');
})
.catch(err => {
try {
const textArea = document.createElement('textarea');
textArea.value = sectionJSON;
textArea.style.position = 'fixed';
textArea.style.opacity = '0';
document.body.appendChild(textArea);
textArea.select();
document.execCommand('copy');
document.body.removeChild(textArea);
showNotification('Full section JSON copied to clipboard!');
} catch (fallbackErr) {
showNotification('Failed to copy to clipboard. Please try again.', 'error');
}
});
}
function copyToClipboard(text) {
navigator.clipboard.writeText(text)
.then(() => {
showNotification('Copied to clipboard!');
})
.catch(err => {
showNotification('Failed to copy to clipboard', 'error');
});
}
window.resetParameter = function(parameterId, defaultValue) {
const element = document.getElementById(parameterId);
if (element) {
element.value = defaultValue;
const valueElement = document.getElementById(`${parameterId}-value`);
if (valueElement) {
valueElement.textContent = defaultValue;
}
switch (parameterId) {
case 'folder-size':
folderConfig.folderSize = defaultValue;
break;
case 'folder-items':
folderConfig.folderItems = defaultValue;
break;
case 'hover-speed':
folderConfig.hoverSpeed = defaultValue;
break;
case 'glow-intensity':
folderConfig.glowIntensity = defaultValue;
break;
}
updateFolderPreview();
showNotification(`${parameterId.replace(/-/g, ' ')} reset to default`);
}
};
function initializeUI() {
initializeFolderAnimation();
const instructionsToggle = document.getElementById('instructions-toggle');
const instructionsContent = document.getElementById('instructions-content');
const instructionsCard = document.getElementById('instructions-card');
if (instructionsToggle && instructionsContent && instructionsCard) {
const toggleIcon = instructionsToggle.querySelector('.toggle-icon');
instructionsToggle.addEventListener('click', () => {
const isVisible = instructionsContent.classList.contains('show');
if (isVisible) {
instructionsContent.classList.remove('show');
instructionsCard.classList.remove('expanded');
if (toggleIcon) toggleIcon.classList.remove('expanded');
} else {
instructionsContent.classList.add('show');
instructionsCard.classList.add('expanded');
if (toggleIcon) toggleIcon.classList.add('expanded');
}
});
}
const quickAttributeBtn = document.getElementById('quick-attribute');
if (quickAttributeBtn) {
quickAttributeBtn.addEventListener('click', () => {
copyToClipboard('data-folder');
});
}
const downloadBtn = document.getElementById('download-config');
if (downloadBtn) {
downloadBtn.addEventListener('click', () => {
copyJsToClipboard();
});
}
const copyFullSectionBtn = document.getElementById('copy-full-section');
if (copyFullSectionBtn) {
copyFullSectionBtn.addEventListener('click', () => {
copyFullSectionToClipboard();
});
}
const randomizeBtn = document.getElementById('randomize-folder');
if (randomizeBtn) {
randomizeBtn.addEventListener('click', () => {
generateRandomFolder();
});
}
const backgroundPicker = document.getElementById('preview-background-picker');
const previewContainer = document.getElementById('folder-preview');
if (backgroundPicker && previewContainer) {
backgroundPicker.addEventListener('input', (e) => {
const selectedColor = e.target.value;
previewContainer.style.backgroundColor = selectedColor;
showNotification(`Preview background changed to ${selectedColor}`);
});
previewContainer.style.backgroundColor = '#252525';
}
const resetColorsBtn = document.getElementById('reset-colors');
if (resetColorsBtn) {
resetColorsBtn.addEventListener('click', () => {
folderConfig.folderColor = defaultConfig.folderColor;
const folderColorInput = document.getElementById('folder-color');
if (folderColorInput) {
folderColorInput.value = defaultConfig.folderColor;
}
updateColorInputs('folder-color', defaultConfig.folderColor);
updateFolderPreview();
showNotification('Folder color reset to default');
});
}
const resetPapersBtn = document.getElementById('reset-papers');
if (resetPapersBtn) {
resetPapersBtn.addEventListener('click', () => {
folderConfig.paper1Color = defaultConfig.paper1Color;
folderConfig.paper2Color = defaultConfig.paper2Color;
folderConfig.paper3Color = defaultConfig.paper3Color;
const paper1Input = document.getElementById('paper1-color');
const paper2Input = document.getElementById('paper2-color');
const paper3Input = document.getElementById('paper3-color');
if (paper1Input) paper1Input.value = defaultConfig.paper1Color;
if (paper2Input) paper2Input.value = defaultConfig.paper2Color;
if (paper3Input) paper3Input.value = defaultConfig.paper3Color;
updateColorInputs('paper1-color', defaultConfig.paper1Color);
updateColorInputs('paper2-color', defaultConfig.paper2Color);
updateColorInputs('paper3-color', defaultConfig.paper3Color);
updateFolderPreview();
showNotification('Paper colors reset to default');
});
}
const resetImagesBtn = document.getElementById('reset-images');
if (resetImagesBtn) {
resetImagesBtn.addEventListener('click', () => {
folderConfig.paper1Image = "";
folderConfig.paper2Image = "";
folderConfig.paper3Image = "";
folderConfig.imageFit = "cover";
const paper1ImageInput = document.getElementById('paper1-image');
const paper2ImageInput = document.getElementById('paper2-image');
const paper3ImageInput = document.getElementById('paper3-image');
const imageFitSelect = document.getElementById('image-fit');
if (paper1ImageInput) paper1ImageInput.value = "";
if (paper2ImageInput) paper2ImageInput.value = "";
if (paper3ImageInput) paper3ImageInput.value = "";
if (imageFitSelect) imageFitSelect.value = "cover";
updateAllImagePreviews();
updateFolderPreview();
showNotification('Images reset to default');
});
}
const resetAnimationBtn = document.getElementById('reset-animation');
if (resetAnimationBtn) {
resetAnimationBtn.addEventListener('click', () => {
folderConfig.folderSize = defaultConfig.folderSize;
folderConfig.folderItems = defaultConfig.folderItems;
folderConfig.hoverSpeed = defaultConfig.hoverSpeed;
const sizeInput = document.getElementById('folder-size');
const itemsInput = document.getElementById('folder-items');
const speedInput = document.getElementById('hover-speed');
const sizeValue = document.getElementById('folder-size-value');
const itemsValue = document.getElementById('folder-items-value');
const speedValue = document.getElementById('hover-speed-value');
if (sizeInput) sizeInput.value = defaultConfig.folderSize;
if (itemsInput) itemsInput.value = defaultConfig.folderItems;
if (speedInput) speedInput.value = defaultConfig.hoverSpeed;
if (sizeValue) sizeValue.textContent = defaultConfig.folderSize;
if (itemsValue) itemsValue.textContent = defaultConfig.folderItems;
if (speedValue) speedValue.textContent = defaultConfig.hoverSpeed;
updateFolderPreview();
showNotification('Animation settings reset');
});
}
const resetAdvancedBtn = document.getElementById('reset-advanced');
if (resetAdvancedBtn) {
resetAdvancedBtn.addEventListener('click', () => {
folderConfig.glowIntensity = defaultConfig.glowIntensity;
folderConfig.particleEffect = defaultConfig.particleEffect;
folderConfig.entranceAnimation = defaultConfig.entranceAnimation;
folderConfig.magneticEffect = defaultConfig.magneticEffect;
const glowInput = document.getElementById('glow-intensity');
const particleSelect = document.getElementById('particle-effect');
const entranceSelect = document.getElementById('entrance-animation');
const magneticSelect = document.getElementById('magnetic-effect');
const glowValue = document.getElementById('glow-intensity-value');
if (glowInput) glowInput.value = defaultConfig.glowIntensity;
if (particleSelect) particleSelect.value = defaultConfig.particleEffect;
if (entranceSelect) entranceSelect.value = defaultConfig.entranceAnimation;
if (magneticSelect) magneticSelect.value = defaultConfig.magneticEffect;
if (glowValue) glowValue.textContent = defaultConfig.glowIntensity;
updateFolderPreview();
showNotification('Advanced settings reset');
});
}
function setupColorInputs(colorId) {
const colorInput = document.getElementById(colorId);
const hexInput = document.getElementById(`${colorId}-hex`);
const hslInput = document.getElementById(`${colorId}-hsl`);
if (!colorInput || !hexInput || !hslInput) {
return;
}
hslInput.value = `hsl(${hexToHsl(colorInput.value).h}, ${hexToHsl(colorInput.value).s}%, ${hexToHsl(colorInput.value).l}%)`;
const colorPickerContainer = colorInput.closest('.color-row')?.querySelector('.color-picker-container');
if (colorPickerContainer) {
colorPickerContainer.style.setProperty('--selected-color', colorInput.value);
}
colorInput.addEventListener('input', () => {
const color = colorInput.value;
hexInput.value = color;
hslInput.value = `hsl(${hexToHsl(color).h}, ${hexToHsl(color).s}%, ${hexToHsl(color).l}%)`;
hexInput.classList.remove('invalid');
hslInput.classList.remove('invalid');
const configKey = colorId.replace('-', '').replace('color', '') || 'folder';
if (configKey === 'folder') {
folderConfig.folderColor = color;
} else if (configKey === 'paper1') {
folderConfig.paper1Color = color;
} else if (configKey === 'paper2') {
folderConfig.paper2Color = color;
} else if (configKey === 'paper3') {
folderConfig.paper3Color = color;
}
if (colorPickerContainer) {
colorPickerContainer.style.setProperty('--selected-color', color);
}
updateFolderPreview();
});
hexInput.addEventListener('input', (e) => {
let hex = e.target.value;
hex = formatHex(hex);
e.target.value = hex;
if (isValidHex(hex)) {
colorInput.value = hex;
hslInput.value = `hsl(${hexToHsl(hex).h}, ${hexToHsl(hex).s}%, ${hexToHsl(hex).l}%)`;
const configKey = colorId.replace('-', '').replace('color', '') || 'folder';
if (configKey === 'folder') {
folderConfig.folderColor = hex;
} else if (configKey === 'paper1') {
folderConfig.paper1Color = hex;
} else if (configKey === 'paper2') {
folderConfig.paper2Color = hex;
} else if (configKey === 'paper3') {
folderConfig.paper3Color = hex;
}
e.target.classList.remove('invalid');
hslInput.classList.remove('invalid');
if (colorPickerContainer) {
colorPickerContainer.style.setProperty('--selected-color', hex);
}
updateFolderPreview();
} else {
e.target.classList.add('invalid');
}
});
hexInput.addEventListener('blur', (e) => {
if (!isValidHex(e.target.value)) {
e.target.value = colorInput.value;
e.target.classList.remove('invalid');
}
});
hslInput.addEventListener('input', (e) => {
let hsl = e.target.value;
if (isValidHsl(hsl)) {
const hex = hslToHex(hsl);
if (hex) {
colorInput.value = hex;
hexInput.value = hex;
const configKey = colorId.replace('-', '').replace('color', '') || 'folder';
if (configKey === 'folder') {
folderConfig.folderColor = hex;
} else if (configKey === 'paper1') {
folderConfig.paper1Color = hex;
} else if (configKey === 'paper2') {
folderConfig.paper2Color = hex;
} else if (configKey === 'paper3') {
folderConfig.paper3Color = hex;
}
e.target.classList.remove('invalid');
hexInput.classList.remove('invalid');
if (colorPickerContainer) {
colorPickerContainer.style.setProperty('--selected-color', hex);
}
updateFolderPreview();
return;
}
}
e.target.classList.add('invalid');
});
hslInput.addEventListener('blur', (e) => {
let hsl = e.target.value;
if (!isValidHsl(hsl) && hsl.trim()) {
const formatted = formatHsl(hsl);
if (isValidHsl(formatted)) {
e.target.value = formatted;
const hex = hslToHex(formatted);
if (hex) {
colorInput.value = hex;
hexInput.value = hex;
const configKey = colorId.replace('-', '').replace('color', '') || 'folder';
if (configKey === 'folder') {
folderConfig.folderColor = hex;
} else if (configKey === 'paper1') {
folderConfig.paper1Color = hex;
} else if (configKey === 'paper2') {
folderConfig.paper2Color = hex;
} else if (configKey === 'paper3') {
folderConfig.paper3Color = hex;
}
e.target.classList.remove('invalid');
hexInput.classList.remove('invalid');
updateFolderPreview();
return;
}
}
}
if (!isValidHsl(e.target.value)) {
e.target.value = `hsl(${hexToHsl(colorInput.value).h}, ${hexToHsl(colorInput.value).s}%, ${hexToHsl(colorInput.value).l}%)`;
e.target.classList.remove('invalid');
}
});
}
function setupImageInputs() {
const paper1ImageInput = document.getElementById('paper1-image');
const paper2ImageInput = document.getElementById('paper2-image');
const paper3ImageInput = document.getElementById('paper3-image');
const imageFitSelect = document.getElementById('image-fit');
if (paper1ImageInput) {
paper1ImageInput.addEventListener('input', (e) => {
folderConfig.paper1Image = e.target.value;
updateImagePreview('paper1', e.target.value);
updateFolderPreview();
});
}
if (paper2ImageInput) {
paper2ImageInput.addEventListener('input', (e) => {
folderConfig.paper2Image = e.target.value;
updateImagePreview('paper2', e.target.value);
updateFolderPreview();
});
}
if (paper3ImageInput) {
paper3ImageInput.addEventListener('input', (e) => {
folderConfig.paper3Image = e.target.value;
updateImagePreview('paper3', e.target.value);
updateFolderPreview();
});
}
if (imageFitSelect) {
imageFitSelect.addEventListener('change', (e) => {
folderConfig.imageFit = e.target.value;
updateFolderPreview();
});
}
}
setupColorInputs('folder-color');
setupColorInputs('paper1-color');
setupColorInputs('paper2-color');
setupColorInputs('paper3-color');
setupImageInputs();
const rangeInputs = document.querySelectorAll('input[type="range"]');
rangeInputs.forEach(input => {
const valueElement = document.getElementById(`${input.id}-value`);
if (valueElement) {
valueElement.textContent = input.value;
}
input.addEventListener('input', () => {
if (valueElement) {
valueElement.textContent = input.value;
}
switch (input.id) {
case 'folder-size':
folderConfig.folderSize = parseFloat(input.value);
break;
case 'folder-items':
folderConfig.folderItems = parseInt(input.value);
break;
case 'hover-speed':
folderConfig.hoverSpeed = parseFloat(input.value);
break;
case 'glow-intensity':
folderConfig.glowIntensity = parseInt(input.value);
break;
}
updateFolderPreview();
});
});
const selectInputs = document.querySelectorAll('select');
selectInputs.forEach(select => {
select.addEventListener('change', function() {
switch (this.id) {
case 'particle-effect':
folderConfig.particleEffect = this.value;
break;
case 'entrance-animation':
folderConfig.entranceAnimation = this.value;
break;
case 'magnetic-effect':
folderConfig.magneticEffect = this.value;
break;
case 'image-fit':
folderConfig.imageFit = this.value;
break;
}
updateFolderPreview();
});
});
document.addEventListener('keydown', (e) => {
if (e.target.tagName === 'INPUT' || e.target.tagName === 'TEXTAREA') {
return;
}
if (e.ctrlKey || e.metaKey) {
switch (e.key.toLowerCase()) {
case 'd':
e.preventDefault();
const downloadBtn = document.getElementById('download-config');
if (downloadBtn && downloadBtn.hasAttribute('data-protection-animation')) {
downloadBtn.click();
} else {
copyJsToClipboard();
}
break;
case 's':
e.preventDefault();
const fullSectionBtn = document.getElementById('copy-full-section');
if (fullSectionBtn && fullSectionBtn.hasAttribute('data-protection-animation')) {
fullSectionBtn.click();
} else {
copyFullSectionToClipboard();
}
break;
}
} else {
switch (e.key.toLowerCase()) {
case 'r':
generateRandomFolder();
break;
case 'b':
const backgroundPickerBtn = document.getElementById('preview-background-picker');
if (backgroundPickerBtn) {
backgroundPickerBtn.click();
}
break;
}
}
});
function saveConfiguration() {
try {
localStorage.setItem('bricksfusion-folder-config', JSON.stringify(folderConfig));
} catch (e) {
}
}
function loadConfiguration() {
try {
const saved = localStorage.getItem('bricksfusion-folder-config');
if (saved) {
const savedConfig = JSON.parse(saved);
Object.assign(folderConfig, savedConfig);
const sizeInput = document.getElementById('folder-size');
const itemsInput = document.getElementById('folder-items');
const speedInput = document.getElementById('hover-speed');
const folderColorInput = document.getElementById('folder-color');
const paper1Input = document.getElementById('paper1-color');
const paper2Input = document.getElementById('paper2-color');
const paper3Input = document.getElementById('paper3-color');
const paper1ImageInput = document.getElementById('paper1-image');
const paper2ImageInput = document.getElementById('paper2-image');
const paper3ImageInput = document.getElementById('paper3-image');
const imageFitSelect = document.getElementById('image-fit');
const glowInput = document.getElementById('glow-intensity');
const particleSelect = document.getElementById('particle-effect');
const entranceSelect = document.getElementById('entrance-animation');
const magneticSelect = document.getElementById('magnetic-effect');
if (sizeInput) sizeInput.value = savedConfig.folderSize;
if (itemsInput) itemsInput.value = savedConfig.folderItems;
if (speedInput) speedInput.value = savedConfig.hoverSpeed;
if (folderColorInput) folderColorInput.value = savedConfig.folderColor;
if (paper1Input) paper1Input.value = savedConfig.paper1Color;
if (paper2Input) paper2Input.value = savedConfig.paper2Color;
if (paper3Input) paper3Input.value = savedConfig.paper3Color;
if (paper1ImageInput) paper1ImageInput.value = savedConfig.paper1Image || "";
if (paper2ImageInput) paper2ImageInput.value = savedConfig.paper2Image || "";
if (paper3ImageInput) paper3ImageInput.value = savedConfig.paper3Image || "";
if (imageFitSelect) imageFitSelect.value = savedConfig.imageFit || "cover";
if (glowInput) glowInput.value = savedConfig.glowIntensity;
if (particleSelect) particleSelect.value = savedConfig.particleEffect;
if (entranceSelect) entranceSelect.value = savedConfig.entranceAnimation;
if (magneticSelect) magneticSelect.value = savedConfig.magneticEffect;
const sizeValue = document.getElementById('folder-size-value');
const itemsValue = document.getElementById('folder-items-value');
const speedValue = document.getElementById('hover-speed-value');
const glowValue = document.getElementById('glow-intensity-value');
if (sizeValue) sizeValue.textContent = savedConfig.folderSize;
if (itemsValue) itemsValue.textContent = savedConfig.folderItems;
if (speedValue) speedValue.textContent = savedConfig.hoverSpeed;
if (glowValue) glowValue.textContent = savedConfig.glowIntensity;
updateAllColorInputs();
updateAllImagePreviews();
updateFolderPreview();
}
} catch (e) {
}
}
const originalUpdateFolderPreview = updateFolderPreview;
updateFolderPreview = function() {
originalUpdateFolderPreview();
saveConfiguration();
};
loadConfiguration();
setTimeout(() => {
showNotification('BricksFusion Folder Animation Configurator loaded!');
}, 500);
}
initializeUI();
});
</script>
</body>
</html>
Folder
Creates an interactive 3D folder with papers inside. Click to open and reveal contents with smooth animations. Features customizable colors, particle effects, magnetic interactions, and entrance animations. Perfect for portfolios, file systems, or adding playful document interactions.
Folder
Click the folder to open and close it.
Appearance
Color of the folder. Automatically darkens back panel for depth effect.
Default: #1E40AF (blue)
Scale multiplier for folder size. Smaller for subtle icons, larger for hero elements.
Default: 1.0
Number of papers inside folder. More papers create fuller, busier appearance.
Default: 3
Intensity of drop shadow glow effect. Zero disables, higher creates stronger aura.
Default: 0
Animation
Duration of open/close transitions. Lower is snappier, higher is smoother.
Default: 0.3
Initial appearance animation. Options: none, fadeIn, slideUp, bounce, rotate.
Default: none
Papers
Individual colors for each paper (paper1, paper2, paper3). Creates variety and depth.
Defaults: #E6E6E6, #F2F2F2, #FFFFFF
Background images for each paper (paper1-image, paper2-image, paper3-image). Display thumbnails or previews.
Default: none
How images fit within papers. Cover fills completely, contain shows entire image.
Default: cover
Effects
Particle burst when opening folder. Options: none, sparkles, dots, stars.
Default: none
Papers follow cursor when open. Options: none, subtle, medium, strong.
Default: none
Performance
This element uses pure CSS transforms for 3D folder effects with minimal JavaScript for interactivity. Features click events, particle creation with CSS animations, magnetic cursor tracking, and dynamic style injection. Respects prefers-reduced-motion for accessibility. Very lightweight - suitable for all devices and multiple instances.