diff --git a/colors.json b/colors.json index 708cd9e..fabd44e 100644 --- a/colors.json +++ b/colors.json @@ -1,114 +1,88 @@ [ { - "family": "Reds & Oranges", + "family": "Whites & Neutrals", "colors": [ - { "name": "Red", "hex": "#ef2a2f" }, - { "name": "Maroon", "hex": "#80011f" }, - { "name": "Aloha", "hex": "#e05251" }, - { "name": "Maroon", "hex": "#800000" }, - { "name": "Orange", "hex": "#ff7600" }, - { "name": "Burnt Orange", "hex": "#9d4223" }, - { "name": "Terra Cotta", "hex": "#934c34" } + { "name": "Retro White", "hex": "#e8e3d9" }, + { "name": "White", "hex": "#ffffff" }, + { "name": "Cameo", "hex": "#e9ccc8" }, + { "name": "Sand", "hex": "#e1d8c6" }, + { "name": "Stone", "hex": "#8f8d7c" }, + { "name": "Fog", "hex": "#6b9098" }, + { "name": "Smoke", "hex": "#75777b" }, + { "name": "Grey", "hex": "#ced3d4" }, + { "name": "Black", "hex": "#0b0d0f" } ] }, { - "family": "Yellows & Golds", + "family": "Pinks & Reds", "colors": [ - { "name": "Yellow", "hex": "#f2e44b" }, - { "name": "Gold", "hex": "#C39953" }, + { "name": "Light Pink", "hex": "#fcccda" }, + { "name": "Blush", "hex": "#ecccad" }, + { "name": "Rose Pink", "hex": "#d984a3" }, + { "name": "Fuchsia", "hex": "#eb4799" }, + { "name": "Rosewood", "hex": "#ad7271" }, + { "name": "Canyon Rose", "hex": "#ca93b3" }, + { "name": "Coral", "hex": "#bd4b3b" }, + { "name": "Rose Gold", "hex": "#c67a6d", "metallic": true, "chromeType": "rosegold" }, + { "name": "Aloha", "hex": "#e45c56" }, + { "name": "Red", "hex": "#ef2a2f" }, + { "name": "Maroon", "hex": "#80011f" } + ] + }, + { + "family": "Oranges & Yellows", + "colors": [ + { "name": "Burnt Orange", "hex": "#9d4223" }, + { "name": "Orange", "hex": "#ef6b24" }, { "name": "Goldenrod", "hex": "#f7b615" }, - { "name": "Mustard", "hex": "#e1a02e" }, - { "name": "Sunflower", "hex": "#FFC512" } + { "name": "Yellow", "hex": "#f5e812" }, + { "name": "Pastel Yellow", "hex": "#fcfd96" } ] }, { "family": "Greens", "colors": [ - { "name": "Lime", "hex": "#8fc73e" }, - { "name": "Grass Green", "hex": "#218b21" }, - { "name": "Forest Green", "hex": "#228B22" }, - { "name": "Willow", "hex": "#4b715a" }, - { "name": "Empowermint", "hex": "#759786" }, - { "name": "Eucalyptus", "hex": "#a3bba1" }, - { "name": "Mint Green", "hex": "#acdba7" }, - { "name": "Tropical Teal", "hex": "#0d868f" }, - { "name": "Seafoam", "hex": "#00c7b2" } + { "name": "Lime Green", "hex": "#8fc73e" }, + { "name": "Grass Green", "hex": "#28b35e" }, + { "name": "Seafoam", "hex": "#00c7b2" }, + { "name": "Pastel Green", "hex": "#acdba7" }, + { "name": "Forest Green", "hex": "#218b21" } ] }, { "family": "Blues", "colors": [ - { "name": "Light Blue", "hex": "#a5c4dd" }, - { "name": "Medium Blue", "hex": "#1b70bc" }, - { "name": "Royal Blue", "hex": "#005ba4" }, - { "name": "Navy", "hex": "#262266" }, + { "name": "Sky Blue", "hex": "#c6e9e8" }, + { "name": "Medium Blue", "hex": "#1b89e8" }, + { "name": "Royal Blue", "hex": "#005eb7" }, { "name": "Blue Slate", "hex": "#327295" }, - { "name": "Caribbean Blue", "hex": "#0bbbb6"} + { "name": "Caribbean Blue", "hex": "#0bbbb6" }, + { "name": "Tropical Teal", "hex": "#0d868f" }, + { "name": "Dark Blue", "hex": "#26408e" }, + { "name": "Navy", "hex": "#262266" } ] }, { - "family": "Purples & Lavenders", + "family": "Purples", "colors": [ + { "name": "Violet", "hex": "#812a8c" }, { "name": "Lavender", "hex": "#866c92" }, { "name": "Lilac", "hex": "#c69edb" }, - { "name": "Violet", "hex": "#812a8c" }, - { "name": "Plum", "hex": "#DDA0DD" } + { "name": "Orchid", "hex": "#a42487" }, + { "name": "Pastel Dusk", "hex": "#d7c4c8" } ] }, { - "family": "Pinks & Roses", + "family": "Browns", "colors": [ - { "name": "Light Pink", "hex": "#FFC0CB" }, - { "name": "Rose", "hex": "#e47d97" }, - { "name": "Rosewood", "hex": "#ad7171" }, - { "name": "Fuchsia", "hex": "#eb4799" }, - { "name": "Peach", "hex": "#FFE5B4" }, - { "name": "Melon", "hex": "#fac4bc" }, - { "name": "Rose Gold", "hex": "#c67a6d", "metallic": true, "chromeType": "rosegold" }, - { "name": "Cayon Rose", "hex": "#ca93b3"}, - { "name": "Coral", "hex": "#bd4b3b"} + { "name": "Coffee", "hex": "#957461" } ] }, { - "family": "Browns & Neutrals", + "family": "Metallics", "colors": [ - { "name": "Chocolate", "hex": "#D2691E" }, - { "name": "Terra Cotta", "hex": "#A0522D" }, - { "name": "Tan", "hex": "#D2B48C" }, - { "name": "Beige", "hex": "#F5F5DC" }, - { "name": "Coffee", "hex": "#6F4E37" }, - { "name": "Classic Gold", "hex": "#dea85e"}, - { "name": "Fog", "hex": "#6b9098" }, - { "name": "Smoke", "hex": "#75777b" }, - { "name": "Grey", "hex": "#ced3d4" }, - { "name": "Silver", "hex": "#A6A6A6" } - ] - }, - { - "family": "Pastels", - "colors": [ - { "name": "Pastel Pink", "hex": "#fcccda" }, - { "name": "Baby Blue", "hex": "#89ccff" }, - { "name": "Green Tea", "hex": "#b2ddc3" }, - { "name": "Lilac", "hex": "#c69edb" }, - { "name": "Pastel Yellow", "hex": "#fcfd96" }, - { "name": "Retro White", "hex": "#e8e3d9"}, - { "name": "White", "hex": "#ffffff"}, - { "name": "Sand", "hex": "#e1d8c6"}, - { "name": "Stone", "hex": "#8f8d7c"}, - { "name": "Latte", "hex": "#a97d55"}, - { "name": "Pastel Dusk", "hex": "#d7c4c8"}, - { "name": "Black", "hex": "#0b0d0f"} - ] - }, - { - "family": "Neon (blacklight reactive)", - "colors": [ - { "name": "Neon Green", "hex": "#a4ce46" }, - { "name": "Neon Blue", "hex": "#4ca3da" }, - { "name": "Neon Orange", "hex": "#f68d5c" }, - { "name": "Neon Yellow", "hex": "#e6e751" }, - { "name": "Neon Magenta", "hex": "#eb6faa" } + { "name": "Classic Gold", "hex": "#dea85e", "metallic": true }, + { "name": "Rose Gold", "hex": "#c67a6d", "metallic": true, "chromeType": "rosegold" } ] }, { diff --git a/index.html b/index.html index f249cd2..d65557f 100644 --- a/index.html +++ b/index.html @@ -13,19 +13,28 @@

🎈 Color Balloon Picker

Select and float your favorite shades

-
+

Your Palette

-
- + +
-
+ + +
+ \ No newline at end of file diff --git a/script.js b/script.js index f1dfc74..dea00f5 100644 --- a/script.js +++ b/script.js @@ -1,27 +1,41 @@ let selectedPalette = []; let animationsEnabled = true; +// --- LOCAL STORAGE LOADING --- +// Load palette from Local Storage on startup +const savedPaletteJSON = localStorage.getItem('userPalette'); +if (savedPaletteJSON) { + try { + selectedPalette = JSON.parse(savedPaletteJSON); + } catch (e) { + console.error("Error parsing saved palette from Local Storage", e); + selectedPalette = []; // Reset if data is corrupt + } +} + +// Main function to fetch color data and build the page fetch('colors.json') .then(response => response.json()) .then(data => { const colorFamiliesContainer = document.getElementById('color-families'); - + + // Create the color swatch for each color in the JSON data data.forEach(family => { const familyDiv = document.createElement('div'); familyDiv.classList.add('color-family'); familyDiv.innerHTML = `

${family.family}

`; - + const swatchContainer = document.createElement('div'); swatchContainer.classList.add('swatch-container'); - + family.colors.forEach(color => { const swatchWrapper = document.createElement('div'); swatchWrapper.classList.add('swatch-wrapper'); - + const swatch = document.createElement('div'); swatch.classList.add('color-swatch'); swatch.dataset.color = color.hex; - + const backgroundDiv = document.createElement('div'); backgroundDiv.classList.add('color-background'); @@ -50,7 +64,8 @@ fetch('colors.json') const colorName = document.createElement('span'); colorName.classList.add('color-name'); colorName.textContent = color.name; - + + // Event listener to add/remove a color from the palette swatch.addEventListener('click', () => { const isSelected = selectedPalette.some(c => c.hex === color.hex); if (isSelected) { @@ -58,55 +73,67 @@ fetch('colors.json') } else { selectedPalette.push(color); } - + + // Add a 'pop' animation on click backgroundDiv.classList.add('pop'); backgroundDiv.addEventListener('animationend', () => { backgroundDiv.classList.remove('pop'); }, { once: true }); - + renderSelectedPalette(); updateSwatchHighlights(); }); - + swatchWrapper.appendChild(swatch); swatchWrapper.appendChild(colorName); swatchContainer.appendChild(swatchWrapper); }); - + familyDiv.appendChild(swatchContainer); colorFamiliesContainer.appendChild(familyDiv); }); + // Initial renders after setting up the page renderSelectedPalette(); updateSwatchHighlights(); + + // Check if a palette was shared in the URL (will override Local Storage) + loadPaletteFromURL(data); }) .catch(error => console.error('Error loading colors:', error)); +/** + * Saves the current 'selectedPalette' array to the browser's Local Storage. + */ +function savePaletteToLocalStorage() { + localStorage.setItem('userPalette', JSON.stringify(selectedPalette)); +} + +/** + * Renders the selected colors as floating balloons in the top palette. + */ function renderSelectedPalette() { const paletteColorsContainer = document.getElementById('palette-colors'); paletteColorsContainer.innerHTML = ''; - + selectedPalette.forEach(color => { const swatchWrapper = document.createElement('div'); swatchWrapper.classList.add('swatch-wrapper'); - - // --- Balloon and String Container --- + const floatGroup = document.createElement('div'); floatGroup.classList.add('balloon-float-group'); + if (animationsEnabled) { - floatGroup.classList.add('balloon-float'); - floatGroup.style.animationDuration = `${(Math.random() * 3 + 3).toFixed(2)}s`; - floatGroup.style.animationDelay = `${(Math.random() * 2).toFixed(2)}s`; - } else { - floatGroup.classList.remove('balloon-float'); - floatGroup.style.animation = 'none'; - } + floatGroup.style.animationDuration = `${(Math.random() * 3 + 3).toFixed(2)}s`; + floatGroup.style.animationDelay = `${(Math.random() * 2).toFixed(2)}s`; + } else { + floatGroup.style.animation = 'none'; + } - // --- Balloon --- const swatch = document.createElement('div'); swatch.classList.add('color-swatch'); swatch.dataset.color = color.hex; - + const backgroundDiv = document.createElement('div'); backgroundDiv.classList.add('color-background', 'chosen'); @@ -123,7 +150,7 @@ function renderSelectedPalette() { if (color.metallic && color.chromeType) { backgroundDiv.classList.add('metallic', `chrome-${color.chromeType}`); } - + swatch.appendChild(backgroundDiv); const shineImg = document.createElement('img'); @@ -132,53 +159,53 @@ function renderSelectedPalette() { shineImg.alt = ""; swatch.appendChild(shineImg); - // --- SVG String --- const svgNS = "http://www.w3.org/2000/svg"; const stringSVG = document.createElementNS(svgNS, "svg"); stringSVG.setAttribute("class", "balloon-string-svg"); stringSVG.setAttribute("width", "20"); stringSVG.setAttribute("height", "60"); stringSVG.setAttribute("viewBox", "0 0 20 60"); - const path = document.createElementNS(svgNS, "path"); path.setAttribute("d", "M10 0 C8 10, 12 20, 10 30 C8 40, 12 50, 10 60"); path.setAttribute("stroke", "#444"); path.setAttribute("stroke-width", "2"); path.setAttribute("fill", "none"); - stringSVG.appendChild(path); - // --- Assemble Group --- floatGroup.appendChild(swatch); floatGroup.appendChild(stringSVG); swatchWrapper.appendChild(floatGroup); - // --- Name --- const colorName = document.createElement('span'); colorName.classList.add('color-name', 'highlighted-name'); colorName.textContent = color.name; swatchWrapper.appendChild(colorName); - // --- Click to remove --- + // Click to remove a color from the selected palette swatch.addEventListener('click', () => { selectedPalette = selectedPalette.filter(c => c.hex !== color.hex); renderSelectedPalette(); updateSwatchHighlights(); }); - + paletteColorsContainer.appendChild(swatchWrapper); }); + + // Save the state to Local Storage whenever the palette is re-rendered + savePaletteToLocalStorage(); } +/** + * Updates the visual highlight on the main color swatches to show which are selected. + */ function updateSwatchHighlights() { const allSwatches = document.querySelectorAll('#color-families .color-swatch'); - allSwatches.forEach(swatch => { const color = swatch.dataset.color; const background = swatch.querySelector('.color-background'); const nameEl = swatch.parentElement.querySelector('.color-name'); const isSelected = selectedPalette.some(c => c.hex === color); - + if (isSelected) { background.classList.add('chosen'); nameEl.classList.add('highlighted-name'); @@ -189,12 +216,59 @@ function updateSwatchHighlights() { }); } +/** + * Determines if a hex color is light or dark to decide on border visibility. + * @param {string} hex - The hex color code (e.g., "#FFFFFF"). + * @returns {boolean} - True if the color is light, false otherwise. + */ function isLightColor(hex) { const rgb = hex.replace('#', '').match(/.{1,2}/g).map(x => parseInt(x, 16)); const brightness = (rgb[0] * 299 + rgb[1] * 587 + rgb[2] * 114) / 1000; return brightness > 220; } +/** + * Shuffles an array in place. + * @param {Array} array - The array to shuffle. + * @returns {Array} - The shuffled array. + */ +function shuffleArray(array) { + for (let i = array.length - 1; i > 0; i--) { + const j = Math.floor(Math.random() * (i + 1)); + [array[i], array[j]] = [array[j], array[i]]; + } + return array; +} + +/** + * Checks the URL for a 'colors' parameter and loads the corresponding palette. + * @param {Array} allColorData - The entire array of color families from colors.json. + */ +function loadPaletteFromURL(allColorData) { + const params = new URLSearchParams(window.location.search); + const colorsFromURL = params.get('colors'); + + if (colorsFromURL) { + const flatColorList = allColorData.flatMap(family => family.colors); + const hexCodesFromURL = colorsFromURL.split(','); + + // Find the full color object for each hex code in the URL + const paletteFromURL = hexCodesFromURL.map(hex => { + // The URL stores hex codes without the '#', so we add it back for the comparison + return flatColorList.find(color => color.hex === `#${hex}`); + }).filter(Boolean); // Filter out any invalid colors + + // If we found valid colors from the URL, it overrides Local Storage + if (paletteFromURL.length > 0) { + selectedPalette = paletteFromURL; + renderSelectedPalette(); + updateSwatchHighlights(); + } + } +} + +// --- Event Listeners for Palette Controls --- + document.getElementById('clear-palette').addEventListener('click', () => { selectedPalette = []; renderSelectedPalette(); @@ -212,10 +286,53 @@ document.getElementById('shuffle-palette').addEventListener('click', () => { updateSwatchHighlights(); }); -function shuffleArray(array) { - for (let i = array.length - 1; i > 0; i--) { - const j = Math.floor(Math.random() * (i + 1)); - [array[i], array[j]] = [array[j], array[i]]; +// --- Modal Functionality --- + +const shareButton = document.getElementById('share-palette'); +const modalBackdrop = document.querySelector('.modal-backdrop'); +const closeModalButton = document.getElementById('close-modal'); +const modalColorList = document.getElementById('modal-color-list'); + +shareButton.addEventListener('click', () => { + if (selectedPalette.length === 0) { + alert("Your palette is empty! Add some colors to create a shareable link."); + return; } - return array; -} + + const baseURL = window.location.href.split('?')[0]; + const colorParams = selectedPalette.map(color => color.hex.substring(1)).join(','); + const shareableLink = `${baseURL}?colors=${colorParams}`; + + modalColorList.innerHTML = ` +

Copy this link to share your palette:

+ + + `; + + document.getElementById('copy-link-button').addEventListener('click', () => { + const linkInput = document.getElementById('share-link-input'); + + navigator.clipboard.writeText(linkInput.value).then(() => { + const copyButton = document.getElementById('copy-link-button'); + copyButton.textContent = 'Copied! ✅'; + setTimeout(() => { + copyButton.textContent = 'Copy Link'; + }, 2000); + }).catch(err => { + console.error('Failed to copy link: ', err); + alert('Failed to copy link.'); + }); + }); + + modalBackdrop.style.display = 'flex'; +}); + +closeModalButton.addEventListener('click', () => { + modalBackdrop.style.display = 'none'; +}); + +modalBackdrop.addEventListener('click', (event) => { + if (event.target === modalBackdrop) { + modalBackdrop.style.display = 'none'; + } +}); \ No newline at end of file diff --git a/style.css b/style.css index bfb3edb..5aee5b9 100644 --- a/style.css +++ b/style.css @@ -233,20 +233,11 @@ footer { } .color-shine { position: absolute; - top: 50%; -<<<<<<< HEAD - left: 55%; + top: 45%; + left: 45%; width: 70px; opacity: 0.6; z-index: 100; /* make this high enough */ -======= - left: 50%; - width: 20px; - height: auto; - max-width: 20px; - opacity: 0.5; - z-index: 10; ->>>>>>> a20d50f (new balloon mask) pointer-events: none; transform: translate(-50%, -50%); height: auto; @@ -265,650 +256,6 @@ footer { z-index: 1; } -<<<<<<< HEAD -======= -#palette-colors .color-swatch { - body { - margin: 0; - padding: 10px; - box-sizing: border-box; - /* font-family: sans-serif; */ - font-family: "Autour One", serif; - background-color: #e8e8e8; - background-image: url("https://www.transparenttextures.com/patterns/asfalt-dark.png"); - /* This is mostly intended for prototyping; please download the pattern and re-host for production environments. Thank you! */ - } - #main-header { - text-align: center; - padding: 20px 10px; - background: #ffffffdd; - box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05); - border-radius: 12px; - margin-bottom: 20px; - } - - #main-header h1 { - font-size: 2rem; - margin-bottom: 5px; - } - - #main-header p { - font-size: 1rem; - color: #666; - } - - #selected-palette { - position: sticky; - top: 10px; - background: #fff; - z-index: 100; - padding: 10px; - border: 2px solid #ccc; - border-radius: 10px; - transition: box-shadow 0.3s ease; - max-width: 80%; - margin: auto; - display: flex; - flex-direction: column; - align-items: center; - justify-content: center; - text-align: center; - - gap: 15px; - background-color: #e8e8e8; - background-image: url("https://www.transparenttextures.com/patterns/asfalt-light.png"); - /* This is mostly intended for prototyping; please download the pattern and re-host for production environments. Thank you! */ - } - - /* Strong shadow when stuck */ - #selected-palette.stuck { - box-shadow: 16px 16px 15px rgba(0, 0, 0, 0.25); - border: 1px solid rgb(0, 0, 0); - border-radius: 7px; - } - - - - #palette-colors { - display: flex; - flex-wrap: wrap; - justify-content: center; - overflow: visible; - padding: 10px; - /* transition: padding 0.3s ease; */ - transition: max-height 0.3s ease, padding 0.3s ease; - } - - - #clear-palette { - margin-top: 20px; - padding: 8px 12px; - font-size: 0.9rem; - background: #8ae7db; - border: 1px solid #ccc; - border-radius: 15px; - cursor: pointer; - margin: auto; - - } - - #color-families { - display: flex; - flex-direction: column; - gap: 15px; - - } - - @keyframes fadeInUp { - from { - opacity: 0; - transform: translateY(10px); - } - to { - opacity: 1; - transform: translateY(0); - } - } - footer { - text-align: center; - font-size: 0.9rem; - color: #777; - padding: 20px; - } - - @media (max-width: 480px) { - .color-name { - font-size: 0.7rem; - } - - .swatch-wrapper { - padding: 6px; - } - - #main-header h1 { - font-size: 1.5rem; - } - } - .color-family { - display: flex; - flex-direction: column; - align-items: center; - gap: 10px; - padding-bottom: 20px; - border-bottom: 1px solid #ccc; - animation: fadeInUp 0.5s ease; - - } - .swatch-container { - display: flex; - flex-wrap: wrap; - justify-content: center; - gap: 10px 20px; /* add horizontal AND vertical gaps */ - } - - .color-family h3 { - text-align: center; - margin: 10px 0 5px; - font-size: 1rem; - font-weight: bold; - } - - - .swatch-wrapper { - display: inline-flex; - flex-direction: column; - align-items: center; - justify-content: space-around; - /* width: 60px; */ - margin: 0 5px; - padding: 10px; - max-width: min-content; - /* overflow-wrap: break-word; */ - - - } - - /* .color-swatch { - width: 55px; - height: 65px; - border-radius: 50%; - position: relative; - cursor: pointer; - transition: transform 0.2s ease; - } */ - .color-swatch::before { - content: ''; - position: absolute; - top: 10%; - left: 20%; - width: 60%; - height: 40%; - border-radius: 50% / 30%; - background: linear-gradient( - 135deg, - rgba(255, 255, 255, 0.8), - rgba(255, 255, 255, 0) 70% - ); - pointer-events: none; - filter: blur(4px); - } - - .metallic-element[data-color="#FFD700"] { - background: linear-gradient(to bottom, #B88606, #79550E); - box-shadow: - inset 0 0 0 0 rgba(255, 255, 255, 0.3), - inset 0 0 0 1px rgba(0, 0, 0, 0.3), - inset 0 0 10px rgba(0, 0, 0, 0.2); - } - - /* .color-swatch::after { - content: ''; - position: absolute; - top: 2%; - left: 2%; - width: 96%; - height: 96%; - border-radius: 50%; - border: 1px solid rgba(255, 255, 255, 0.3); - pointer-events: none; - box-shadow: 0 0 8px 2px rgba(255, 255, 255, 0.2); - } - */ - .color-swatch { - width: 100px; - height: 136px; - position: relative; - background: #ccc; /* fallback */ - transition: transform 0.3s ease; - - background: radial-gradient(circle at 30% 30%, #fff5, transparent 60%), #ddd; - - -webkit-mask-image: url('images/balloon-mask.svg'); - -webkit-mask-size: contain; - -webkit-mask-repeat: no-repeat; - -webkit-mask-position: center; - - mask-image: url('images/balloon-mask.svg'); - mask-size: contain; - mask-repeat: no-repeat; - mask-position: center; - - box-shadow: - inset 2px 2px 6px rgba(255, 255, 255, 0.6), - 0 4px 8px rgba(0, 0, 0, 0.2); - } - - - - .color-swatch::after { - content: ''; - position: absolute; - bottom: -6px; - left: 50%; - transform: translateX(-50%); - width: 10px; - height: 6px; - background: inherit; - border-radius: 50% 50% 30% 30%; - box-shadow: inset 0 0 2px rgba(0,0,0,0.2); - } - - - - .color-swatch:hover, - .color-swatch:active { - transform: scale(1.2); - box-shadow: 0 0 5px rgba(0,0,0,0.2); - } - - .color-swatch.chosen { - outline: 3px solid #333; - outline-offset: 1px; - width: 100px; - height: 136px; - z-index: 10; - } - - .color-background { - width: 100%; - height: 100%; - border-radius: 50%; - border: 2px solid rgba(0, 0, 0, 0.1); /* Light gray border */ - box-shadow: 1 1 1; - } - .color-shine { - position: absolute; - top: 30%; - left: 50%; - width: 20px; - height: auto; - max-width: 20px; - opacity: 0.5; - z-index: 10; - pointer-events: none; - transform: translate(-50%, -50%); - - } - - .color-name { - font-size: 0.85rem; - text-align: center; - margin-top: 5px; - word-break: keep-all; /* Prevent breaking long words */ - /* white-space: nowrap; Keep names on a single line */ - /* overflow: hidden; /*Hide overflow text if necessary */ - text-overflow: ellipsis; /* Add ... when text is too long */ - max-width: 100%; - background-color: #e8e8e8; - z-index: 1; - } - - #palette-colors .color-swatch { - width: 100px; - height: 136px; - } - - /* .checkmark-overlay { - position: absolute; - top: 4px; - right: 4px; - font-size: 16px; - font-weight: bold; - color: white; - background: rgba(0, 0, 0, 0.6); - border-radius: 50%; - width: 20px; - height: 20px; - display: flex; - align-items: center; - justify-content: center; - z-index: 20; - pointer-events: none; - } */ - - @media (max-width: 600px) { - - .swatch-wrapper { - width: 50px; - } - - .color-name { - font-size: 0.65rem; - max-width: 40px; - word-wrap: break-word; - } - - #selected-palette h2 { - font-size: 1.1rem; - } - } - - .color-name { - transition: all 0.3s ease; - } - - .color-name.highlighted-name { - text-decoration:underline; - font-weight: bold; - color: #111; - } - - @keyframes pop { - 0% { transform: scale(1); } - 50% { transform: scale(1.2); } - 100% { transform: scale(1); } - } - - .color-background.pop { - animation: pop 0.25s ease; - } - - .color-background.chosen { - transform: scale(2.2); - box-shadow: 0 0 10px rgba(0, 0, 0, 0.25); - } - .chosen{ - z-index: 4; - } - - /* Shared metallic style */ - .metallic { - position: relative; - border: 1px solid rgba(255, 255, 255, 0.3); - /* box-shadow: inset 1px 1px 4px rgba(255, 255, 255, 0.6), - 0 2px 4px rgba(0, 0, 0, 0.3); */ - overflow: hidden; - } - - /* Highlight overlay */ - .metallic1::after { - content: ''; - position: absolute; - top: 15%; - left: 15%; - width: 70%; - height: 70%; - background: radial-gradient(circle at top left, rgba(255,255,255,0.3), transparent 70%); - transform: rotate(-20deg); - pointer-events: none; - border-radius: 50%; - } - - /* Specific chrome variants */ - .chrome-gold { - background: linear-gradient(145deg, #fefcea, #b69978, #a18b67, #806748); - } - - .chrome-silver { - background: linear-gradient(145deg, #e0e0e0, #a9a9a9, #808080, #e0e0e0); - } - - .chrome-rosegold { - background: linear-gradient(145deg, #fbe3dc, #e6b7a9, #d19387, #fbe3dc); - } - - .chrome-champagne { - background: linear-gradient(145deg, #fff2cc, #f2e6b6, #d9c08e, #fff2cc); - } - - .chrome-blue { - background: linear-gradient(145deg, #d0f0ff, #4d7995, #2d576f, #d0f0ff); - } - - .chrome-purple { - background: linear-gradient(145deg, #e0ccff, #b08be1, #915bc4, #e0ccff); - } - - .chrome-green { - background: linear-gradient(145deg, #e2ffe2, #457066, #5c877d, #e2ffe2); - } - - - @keyframes balloonFloat { - 0%, 100% { transform: translateY(0) rotate(-4deg); } - 50% { transform: translateY(-25px) rotate(4deg); } - } - - .balloon-float { - animation-name: balloonFloat; - animation-timing-function: 4s ease-in-out; - animation-iteration-count: infinite; - transform-origin: bottom center; - position: relative; - } - - .color-background { - background-size: cover; - background-position: center; - background-repeat: no-repeat; - } - /* --- SVG Balloon String --- */ - .balloon-string-svg { - position: absolute; -translateY(-25px) rotate(4deg); } - } - - .balloon-float { - animation-name: balloonFloat; - animation-timing-function: 4s ease-in-out; - animation-iteration-count: infinite; - transform-origin: bottom center; - position: relative; - } - - .color-background { - background-size: cover; - background-position: center; - background-repeat: no-repeat; - } - /* --- SVG Balloon String --- */ - .balloon-string-svg { - position: absolute; - top: 50px; /* match .color-swatch height */ - left: 50%; - transform: translateX(-50%); - width: 20px; - height: 40px; - z-index: 0; - pointer-events: none; - overflow: visible; - transform-origin: top center; - animation: svgWiggle 2s ease-in-out infinite; - } - - - .balloon-float-group { - position: relative; - display: flex; - flex-direction: column; - align-items: center; - animation-name: balloonFloat; -translateY(-25px) rotate(4deg); } - } - - .balloon-float { - animation-name: balloonFloat; - animation-timing-function: 4s ease-in-out; - animation-iteration-count: infinite; - transform-origin: bottom center; - position: relative; - } - - .color-background { - background-size: cover; - background-position: center; - background-repeat: no-repeat; - } - /* --- SVG Balloon String --- */ - .balloon-string-svg { - position: absolute; - top: 30px; /* match .color-swatch height */ - left: 50%; - transform: translateX(-50%); - width: 20px; - height: 40px; - z-index: 0; - pointer-events: none; - overflow: visible; - transform-origin: top center; - animation: svgWiggle 2s ease-in-out infinite; - } - - - .balloon-float-group { - position: relative; - display: flex; - flex-direction: column; - align-items: center; - animation-name: balloonFloat; - animation-duration: 4s;0px; /* match .color-swatch height */ - left: 50%; - transform: translateX(-50%); - width: 20px; - height: 40px; - z-index: 0; - pointer-events: none; - overflow: visible; - transform-origin: top center; - animation: svgWiggle 2s ease-in-out infinite; - } - - - .balloon-float-group { - position: relative; - display: flex; - flex-direction: column; - align-items: center; - animation-name: balloonFloat; - animation-duration: 4s; - animation-timing-function: ease-in-out; - animation-iteration-count: infinite; - transform-origin: bottom center; - } - - .wiggle-path { - stroke: #727171; - stroke-width: 2; - fill: none; - stroke-linecap: round; - stroke-dasharray: 1, 2; - } - - @keyframes svgWiggle { - 0%, 100% { - transform: translateX(-50%) rotate(0deg); - } - 25% { - transform: translateX(-50%) rotate(2deg); - } - 50% { - transform: translateX(-50%) rotate(-2.5deg); - } - 75% { - transform: translateX(-50%) rotate(1.5deg); - } - } - - #palette-controls { - position: absolute; - top: 10px; - right: 10px; - display: flex; - align-items: center; - gap: 10px; - z-index: 200; - } - - /* Toggle Switch Styling */ - .switch { - position: relative; - display: inline-block; - width: 60px; - height: 20px; - } - .switch input { - opacity: 0; - width: 0; - height: 0; - } - .slider { - position: absolute; - cursor: pointer; - top: 0; left: 0; - right: 0; bottom: 0; - background-color: #ccc; - transition: 0.4s; - border-radius: 20px; - } - .slider:before { - position: absolute; - content: ""; - height: 14px; - width: 14px; - left: 3px; - bottom: 3px; - background-color: white; - transition: 0.4s; - border-radius: 50%; - } - input:checked + .slider { - background-color: #4caf50; - } - input:checked + .slider:before { - transform: translateX(20px); - } - - /* Shuffle Button */ - #shuffle-palette { - font-size: 16px; - padding: 4px 8px; - border: none; - background: #f0f0f0; - border-radius: 6px; - cursor: pointer; - } - */ -} - - -/* .checkmark-overlay { - position: absolute; - top: 4px; - right: 4px; - font-size: 16px; - font-weight: bold; - color: white; - background: rgba(0, 0, 0, 0.6); - border-radius: 50%; - width: 20px; - height: 20px; - display: flex; - align-items: center; - justify-content: center; - z-index: 20; - pointer-events: none; -} */ ->>>>>>> a20d50f (new balloon mask) @media (max-width: 600px) { @@ -1040,8 +387,8 @@ translateY(-25px) rotate(4deg); } /* --- SVG Balloon String --- */ .balloon-string-svg { position: absolute; - top: 98px; /* match .color-swatch height */ - left: 50%; + top: 82px; /* match .color-swatch height */ + left: 45%; transform: translateX(-50%); width: 20px; height: 40px; @@ -1097,7 +444,6 @@ translateY(-25px) rotate(4deg); } gap: 10px; z-index: 200; } - /* Toggle Switch Styling */ .switch { position: relative; @@ -1146,3 +492,53 @@ input:checked + .slider:before { border-radius: 6px; cursor: pointer; } +.modal-backdrop { + position: fixed; + top: 0; left: 0; + width: 100vw; height: 100vh; + background: rgba(0, 0, 0, 0.4); + display: none; /* Start hidden */ + justify-content: center; + align-items: center; + z-index: 9999; +} + +.modal { + background: white; + padding: 20px; + border-radius: 12px; + max-width: 90%; + width: 400px; + box-shadow: 0 5px 20px rgba(0, 0, 0, 0.3); + text-align: center; +} + +/* Styling for the share link input field inside the modal */ +#share-link-input { + display: block; + width: 90%; + padding: 8px; + margin: 15px auto 0; + border: 1px solid #ccc; + border-radius: 4px; + font-size: 0.9rem; + text-align: center; +} + +/* Styling for the copy button inside the modal */ +#copy-link-button { + margin-top: 15px; + padding: 10px 20px; + font-size: 1rem; + font-weight: bold; + background-color: #4CAF50; /* Green */ + color: white; + border: none; + border-radius: 5px; + cursor: pointer; + transition: background-color 0.3s ease; +} + +#copy-link-button:hover { + background-color: #45a049; +} \ No newline at end of file