assetmapper
This commit is contained in:
parent
89c54af921
commit
caeb663251
23 changed files with 982 additions and 175 deletions
25
assets/app.js
Normal file
25
assets/app.js
Normal file
|
@ -0,0 +1,25 @@
|
|||
/*
|
||||
* Welcome to your app's main JavaScript file!
|
||||
*
|
||||
* This file will be included onto the page via the importmap() Twig function,
|
||||
* which should already be in your base.html.twig.
|
||||
*/
|
||||
import 'bootstrap/dist/css/bootstrap.min.css';
|
||||
import './styles/app.css';
|
||||
import './styles/modes.css';
|
||||
import './styles/emoji-footprint.css';
|
||||
|
||||
// Import modules
|
||||
import './theme.js';
|
||||
import './emoji-footprint.js';
|
||||
import { initNumberInputs } from './numberInputs.js';
|
||||
import { initRadioState } from './radioState.js';
|
||||
|
||||
// Initialize everything when DOM is ready
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
// Initialize radio button state management
|
||||
initRadioState();
|
||||
|
||||
// Initialize number inputs on page load
|
||||
initNumberInputs();
|
||||
});
|
19
assets/emoji-footprint.js
Normal file
19
assets/emoji-footprint.js
Normal file
|
@ -0,0 +1,19 @@
|
|||
// Sparkle effect on mouse move
|
||||
document.addEventListener('mousemove', function (e) {
|
||||
const emojis = ['✨', '💖', '🌟', '💅', '🦄', '🎉', '🌈'];
|
||||
const sparkle = document.createElement('div');
|
||||
sparkle.className = 'emoji-footprint';
|
||||
sparkle.textContent = emojis[Math.floor(Math.random() * emojis.length)];
|
||||
sparkle.style.left = e.pageX + 'px';
|
||||
sparkle.style.top = e.pageY + 'px';
|
||||
document.body.appendChild(sparkle);
|
||||
|
||||
setTimeout(() => {
|
||||
sparkle.remove();
|
||||
}, 1000);
|
||||
});
|
||||
|
||||
export function initEmojiFootprint() {
|
||||
// The sparkle effect is already initialized when this module is imported
|
||||
// This function can be used if we need to control when the effect starts
|
||||
}
|
0
assets/modes.js
Normal file
0
assets/modes.js
Normal file
55
assets/numberInputs.js
Normal file
55
assets/numberInputs.js
Normal file
|
@ -0,0 +1,55 @@
|
|||
// Function to initialize number input buttons
|
||||
function initNumberInputs(container = document) {
|
||||
container.querySelectorAll('.number-input-wrapper').forEach(function(wrapper) {
|
||||
const input = wrapper.querySelector('input[type="number"]');
|
||||
const decreaseBtn = wrapper.querySelector('[data-action="decrease"]');
|
||||
const increaseBtn = wrapper.querySelector('[data-action="increase"]');
|
||||
|
||||
if (!input || !decreaseBtn || !increaseBtn) return;
|
||||
|
||||
// Skip if already initialized
|
||||
if (decreaseBtn.hasAttribute('data-initialized')) return;
|
||||
|
||||
const step = parseFloat(input.getAttribute('step')) || 1;
|
||||
const min = 0;
|
||||
const max = input.getAttribute('max') ? parseFloat(input.getAttribute('max')) : null;
|
||||
|
||||
decreaseBtn.addEventListener('click', function() {
|
||||
const currentValue = parseFloat(input.value) || 0;
|
||||
const newValue = currentValue - step;
|
||||
|
||||
if (min === null || newValue >= min) {
|
||||
input.value = newValue;
|
||||
input.dispatchEvent(new Event('change', { bubbles: true }));
|
||||
}
|
||||
});
|
||||
|
||||
increaseBtn.addEventListener('click', function() {
|
||||
const currentValue = parseFloat(input.value) || 0;
|
||||
const newValue = currentValue + step;
|
||||
|
||||
if (max === null || newValue <= max) {
|
||||
input.value = newValue;
|
||||
input.dispatchEvent(new Event('change', { bubbles: true }));
|
||||
}
|
||||
});
|
||||
|
||||
// Validate input on change
|
||||
input.addEventListener('input', function() {
|
||||
const value = parseFloat(this.value);
|
||||
|
||||
if (min !== null && value < min) {
|
||||
this.value = min;
|
||||
}
|
||||
if (max !== null && value > max) {
|
||||
this.value = max;
|
||||
}
|
||||
});
|
||||
|
||||
// Mark as initialized
|
||||
decreaseBtn.setAttribute('data-initialized', 'true');
|
||||
increaseBtn.setAttribute('data-initialized', 'true');
|
||||
});
|
||||
}
|
||||
|
||||
export { initNumberInputs };
|
35
assets/radioState.js
Normal file
35
assets/radioState.js
Normal file
|
@ -0,0 +1,35 @@
|
|||
// Radio button state management with localStorage
|
||||
function initRadioState() {
|
||||
// Store and retrieve radio button state
|
||||
const radioButtons = document.querySelectorAll('input[name="mode"]');
|
||||
|
||||
// Load saved state on page load
|
||||
const savedMode = localStorage.getItem('selectedMode');
|
||||
if (savedMode) {
|
||||
const radioToCheck = document.getElementById(savedMode);
|
||||
if (radioToCheck) {
|
||||
radioToCheck.checked = true;
|
||||
// Set the data attribute to match the saved mode
|
||||
document.documentElement.setAttribute('data-website-mode', savedMode);
|
||||
}
|
||||
} else {
|
||||
// If no saved state, set to the currently checked radio button
|
||||
const checkedRadio = document.querySelector('input[name="mode"]:checked');
|
||||
if (checkedRadio) {
|
||||
document.documentElement.setAttribute('data-website-mode', checkedRadio.id);
|
||||
}
|
||||
}
|
||||
|
||||
// Save state when radio button changes
|
||||
radioButtons.forEach(radio => {
|
||||
radio.addEventListener('change', function() {
|
||||
if (this.checked) {
|
||||
localStorage.setItem('selectedMode', this.id);
|
||||
// Update the data attribute when mode changes
|
||||
document.documentElement.setAttribute('data-website-mode', this.id);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
export { initRadioState };
|
120
assets/styles/app.css
Normal file
120
assets/styles/app.css
Normal file
|
@ -0,0 +1,120 @@
|
|||
/*
|
||||
* =================================================================================================
|
||||
* 💖 BUBBLEGUM PUNK THEME (LIGHT) 💖
|
||||
*
|
||||
* This isn't just a theme. It's a statement.
|
||||
* Unapologetically loud, pink, and quirky.
|
||||
* =================================================================================================
|
||||
*/
|
||||
:root,
|
||||
[data-bs-theme=light] {
|
||||
/* --- CORE VIBE --- */
|
||||
--bs-pink: #FF007A; /* 💖 Hyper Pink (Our Queen) */
|
||||
--bs-green: #CFFF50; /* 🧪 Toxic Slime */
|
||||
--bs-purple: #A328D6; /* 👾 Graffiti Purple */
|
||||
--bs-yellow: #F9F871; /* ⚡ Neon Lemon */
|
||||
--bs-cyan: #00F5D4; /* 💎 Glitchy Teal */
|
||||
--bs-blue: #00A9E0; /* 💦 Splash Zone */
|
||||
|
||||
/* Let's redefine ALL the core colors to match the new energy */
|
||||
--bs-primary: var(--bs-pink);
|
||||
--bs-secondary: var(--bs-green);
|
||||
--bs-success: var(--bs-cyan);
|
||||
--bs-info: var(--bs-blue);
|
||||
--bs-warning: var(--bs-yellow);
|
||||
--bs-danger: #FF3D3D; /* 🚨 Code Red Rave */
|
||||
|
||||
/* --- BACKGROUNDS & TEXT --- */
|
||||
/* No more boring white! */
|
||||
--bs-body-bg: #FFF5FD; /* A soft, dreamy pink canvas */
|
||||
--bs-body-color: #4A003D; /* Dark Plum (instead of black) for text */
|
||||
--bs-heading-color: var(--bs-purple); /* Make headings POP */
|
||||
--bs-secondary-color: rgba(74, 0, 61, 0.75); /* Plum, but softer */
|
||||
--bs-tertiary-color: rgba(74, 0, 61, 0.5);
|
||||
|
||||
/* Make cards and containers pure white to contrast the pink background */
|
||||
--bs-tertiary-bg: #FFFFFF;
|
||||
--bs-secondary-bg: #FEF9FE;
|
||||
|
||||
/* --- LINKS & CODE --- */
|
||||
--bs-link-color: var(--bs-pink);
|
||||
--bs-link-hover-color: var(--bs-purple);
|
||||
--bs-code-color: var(--bs-purple);
|
||||
|
||||
/* --- BORDERS & SHADOWS: LET'S GET QUIRKY --- */
|
||||
--bs-border-width: 2px; /* Chunky borders! */
|
||||
--bs-border-color: #FFD6F5; /* Pink-tinted border color */
|
||||
--bs-border-color-translucent: rgba(74, 0, 61, 0.2);
|
||||
--bs-border-radius: 1rem; /* Super bubbly and round */
|
||||
--bs-border-radius-sm: 0.5rem;
|
||||
--bs-border-radius-lg: 1.5rem;
|
||||
--bs-border-radius-pill: 50rem;
|
||||
|
||||
/* Say goodbye to black shadows, hello to colored glows! */
|
||||
--bs-box-shadow: 0 4px 12px rgba(255, 0, 122, 0.2);
|
||||
--bs-box-shadow-sm: 0 2px 4px rgba(255, 0, 122, 0.15);
|
||||
--bs-box-shadow-lg: 0 8px 30px rgba(255, 0, 122, 0.25);
|
||||
--bs-box-shadow-inset: inset 0 1px 4px rgba(74, 0, 61, 0.2);
|
||||
|
||||
/* --- THE GRADIENT: THE SOUL OF THE THEME --- */
|
||||
--bs-gradient: linear-gradient(75deg, var(--bs-primary), var(--bs-secondary));
|
||||
|
||||
/* --- Don't forget the RGB values for Bootstrap components! --- */
|
||||
--bs-primary-rgb: 255, 0, 122;
|
||||
--bs-secondary-rgb: 207, 255, 80;
|
||||
--bs-body-color-rgb: 74, 0, 61;
|
||||
--bs-body-bg-rgb: 255, 245, 253;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* =================================================================================================
|
||||
* 🌙🦇 CYBER GOTH THEME (DARK) 🦇🌙
|
||||
*
|
||||
* The lights are out, the neon is ON.
|
||||
* A dark, moody theme with vibrant, glowing accents.
|
||||
* =================================================================================================
|
||||
*/
|
||||
[data-bs-theme=dark] {
|
||||
color-scheme: dark;
|
||||
|
||||
/* --- BACKGROUNDS & TEXT --- */
|
||||
--bs-body-bg: #1D001A; /* Deep, dark space purple */
|
||||
--bs-body-color: #FFE9FA; /* Light pink text for high contrast */
|
||||
--bs-heading-color: var(--bs-cyan); /* Glowing cyan headings */
|
||||
|
||||
--bs-tertiary-bg: #2E0028; /* A slightly lighter container background */
|
||||
--bs-secondary-bg: #3A0033;
|
||||
--bs-secondary-color: rgba(255, 233, 250, 0.75);
|
||||
--bs-tertiary-color: rgba(255, 233, 250, 0.5);
|
||||
|
||||
/* --- LINKS & CODE --- */
|
||||
/* Using the Toxic Slime for links gives it that cyber look */
|
||||
--bs-link-color: var(--bs-green);
|
||||
--bs-link-hover-color: var(--bs-cyan);
|
||||
--bs-code-color: var(--bs-pink);
|
||||
|
||||
/* --- BORDERS & SHADOWS: NEON GLOWS --- */
|
||||
--bs-border-color: #5C004F;
|
||||
--bs-border-color-translucent: rgba(255, 255, 255, 0.15);
|
||||
|
||||
/* Redefine shadows to be neon glows */
|
||||
--bs-box-shadow: 0 0 15px rgba(var(--bs-primary-rgb), 0.4);
|
||||
--bs-box-shadow-lg: 0 0 30px rgba(var(--bs-primary-rgb), 0.5);
|
||||
|
||||
/* --- EMPHASIS & SUBTLE BACKGROUNDS --- */
|
||||
/* These are for alerts, badges, etc. They'll be dark with glowing text. */
|
||||
--bs-primary-text-emphasis: #FF8AD1;
|
||||
--bs-secondary-text-emphasis: #E2FF8A;
|
||||
--bs-success-text-emphasis: #8AFFEB;
|
||||
--bs-info-text-emphasis: #7ADCF5;
|
||||
--bs-warning-text-emphasis: #FAF8A8;
|
||||
--bs-danger-text-emphasis: #FF8A8A;
|
||||
|
||||
--bs-primary-bg-subtle: #3D002B;
|
||||
--bs-secondary-bg-subtle: #415215;
|
||||
--bs-success-bg-subtle: #00332B;
|
||||
--bs-info-bg-subtle: #00313D;
|
||||
--bs-warning-bg-subtle: #3E3D1C;
|
||||
--bs-danger-bg-subtle: #520E0E;
|
||||
}
|
30
assets/styles/emoji-footprint.css
Normal file
30
assets/styles/emoji-footprint.css
Normal file
|
@ -0,0 +1,30 @@
|
|||
|
||||
/* Emoji Footprint Animation */
|
||||
.emoji-footprint {
|
||||
position: absolute;
|
||||
font-size: 1.6rem;
|
||||
pointer-events: none;
|
||||
animation: emojiFade 1s ease-out forwards;
|
||||
transform: translate(-50%, -50%) scale(1);
|
||||
opacity: 1;
|
||||
z-index: 9999;
|
||||
text-shadow:
|
||||
0 0 4px #ff00bf,
|
||||
0 0 8px #ff80df,
|
||||
0 0 12px #ffccff;
|
||||
}
|
||||
|
||||
@keyframes emojiFade {
|
||||
0% {
|
||||
transform: translate(-50%, -50%) scale(1);
|
||||
opacity: 1;
|
||||
}
|
||||
50% {
|
||||
transform: translate(-50%, -50%) scale(1.5);
|
||||
opacity: 0.7;
|
||||
}
|
||||
100% {
|
||||
transform: translate(-50%, -50%) scale(2);
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
0
assets/styles/modes.css
Normal file
0
assets/styles/modes.css
Normal file
18
assets/theme.js
Normal file
18
assets/theme.js
Normal file
|
@ -0,0 +1,18 @@
|
|||
// Theme detection and switching
|
||||
const getPreferredTheme = () => {
|
||||
return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light'
|
||||
}
|
||||
|
||||
const setTheme = theme => {
|
||||
document.documentElement.setAttribute('data-bs-theme', theme)
|
||||
}
|
||||
|
||||
// Set initial theme
|
||||
setTheme(getPreferredTheme())
|
||||
|
||||
// Listen for changes in user's preferred color scheme
|
||||
window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', () => {
|
||||
setTheme(getPreferredTheme())
|
||||
})
|
||||
|
||||
export { getPreferredTheme, setTheme };
|
Loading…
Add table
Add a link
Reference in a new issue