Add CSS animations for rotating stars in MainPageLayout: Implemented new animations for star graphics to enhance visual appeal. Updated SharedCarousel to support dynamic language changes and improved category fetching logic. Enhanced localization files with new text for indoor season prompts in multiple languages.

This commit is contained in:
sebseb7
2025-07-18 15:26:11 +02:00
parent 93887ce397
commit 04e97c2522
25 changed files with 233 additions and 37 deletions

View File

@@ -23,6 +23,39 @@ const MainPageLayout = () => {
const isAktionen = currentPath === "/aktionen";
const isFiliale = currentPath === "/filiale";
// Add CSS animations for rotating stars
React.useEffect(() => {
const style = document.createElement('style');
style.textContent = `
@keyframes rotateClockwise {
from { transform: rotate(0deg); }
to { transform: rotate(360deg); }
}
@keyframes rotateCounterClockwise {
from { transform: rotate(0deg); }
to { transform: rotate(-360deg); }
}
.star-rotate-slow-cw {
animation: rotateClockwise 60s linear infinite;
}
.star-rotate-slow-ccw {
animation: rotateCounterClockwise 45s linear infinite;
}
.star-rotate-medium-cw {
animation: rotateClockwise 30s linear infinite;
}
`;
document.head.appendChild(style);
return () => {
document.head.removeChild(style);
};
}, []);
// Get navigation config based on current page
const getNavigationConfig = () => {
if (isHome) {
@@ -359,6 +392,7 @@ const MainPageLayout = () => {
viewBox="0 0 60 60"
width="168"
height="168"
className="star-rotate-slow-cw"
style={{
position: 'absolute',
top: '-9px',
@@ -378,6 +412,7 @@ const MainPageLayout = () => {
viewBox="0 0 60 60"
width="159"
height="159"
className="star-rotate-slow-ccw"
style={{
position: 'absolute',
top: '-4.5px',
@@ -397,6 +432,7 @@ const MainPageLayout = () => {
viewBox="0 0 60 60"
width="150"
height="150"
className="star-rotate-medium-cw"
>
<polygon
points="30,0 38,20 60,22 43,37 48,60 30,48 12,60 17,37 0,22 22,20"
@@ -451,6 +487,96 @@ const MainPageLayout = () => {
</div>
)}
{/* Multi-pointed star for stecklinge box - bottom right */}
{index === 1 && pageType === "home" && (
<div
style={{
position: 'absolute',
bottom: '-65px',
right: '-65px',
width: '180px',
height: '180px',
zIndex: 999,
pointerEvents: 'auto',
cursor: 'pointer'
}}
>
{/* Background star - slightly larger and rotated */}
<svg
viewBox="0 0 60 60"
width="168"
height="168"
className="star-rotate-slow-ccw"
style={{
position: 'absolute',
top: '-9px',
left: '-9px',
transform: 'rotate(20deg)'
}}
>
<polygon
points="30,0 38,20 60,22 43,37 48,60 30,48 12,60 17,37 0,22 22,20"
fill="#5F9EA0"
stroke="none"
/>
</svg>
{/* Middle star - medium size with different rotation */}
<svg
viewBox="0 0 60 60"
width="159"
height="159"
className="star-rotate-medium-cw"
style={{
position: 'absolute',
top: '-4.5px',
left: '-4.5px',
transform: 'rotate(-25deg)'
}}
>
<polygon
points="30,0 38,20 60,22 43,37 48,60 30,48 12,60 17,37 0,22 22,20"
fill="#7FCDCD"
stroke="none"
/>
</svg>
{/* Foreground star - main star with text */}
<svg
viewBox="0 0 60 60"
width="150"
height="150"
className="star-rotate-slow-cw"
>
<polygon
points="30,0 38,20 60,22 43,37 48,60 30,48 12,60 17,37 0,22 22,20"
fill="#AFEEEE"
stroke="none"
/>
</svg>
{/* Text positioned in the center of the star */}
<div
style={{
position: 'absolute',
top: '42%',
left: '45%',
transform: 'translate(-50%, -50%) rotate(10deg)',
color: 'white',
fontWeight: '900',
fontSize: '20px',
textShadow: '0px 3px 6px rgba(0,0,0,0.5)',
zIndex: 1000,
textAlign: 'center',
lineHeight: '1.1',
width: '135px'
}}
>
{t('sections.indoorSeason')}
</div>
</div>
)}
<div className={`animated-border-card ${index === 0 ? 'seeds-card' : 'cutlings-card'}`}>
<Paper
component={Link}

View File

@@ -38,28 +38,52 @@ const getProductCache = () => {
};
// Initialize categories
const initializeCategories = () => {
const initializeCategories = (language = 'en') => {
const productCache = getProductCache();
if (productCache && productCache[`categoryTree_209_${language}`]) {
const cached = productCache[`categoryTree_209_${language}`];
if (cached.categoryTree) {
return processCategoryTree(cached.categoryTree);
}
}
// Fallback to old cache format if language-specific cache doesn't exist
if (productCache && productCache["categoryTree_209"]) {
const cached = productCache["categoryTree_209"];
if (cached.categoryTree) {
return processCategoryTree(cached.categoryTree);
}
}
return [];
};
const SharedCarousel = () => {
const { carouselRef, filteredCategories, setFilteredCategories, moveCarousel } = useCarousel();
const context = useContext(SocketContext);
const { t } = useTranslation();
const { t, i18n } = useTranslation();
const [rootCategories, setRootCategories] = useState([]);
const [currentLanguage, setCurrentLanguage] = useState(i18n.language);
useEffect(() => {
const initialCategories = initializeCategories();
const initialCategories = initializeCategories(currentLanguage);
setRootCategories(initialCategories);
}, []);
}, [currentLanguage]);
// Listen for language changes
useEffect(() => {
const handleLanguageChange = (lng) => {
setCurrentLanguage(lng);
// Clear categories to force refetch
setRootCategories([]);
};
i18n.on('languageChanged', handleLanguageChange);
return () => {
i18n.off('languageChanged', handleLanguageChange);
};
}, [i18n]);
useEffect(() => {
// Only fetch from socket if we don't already have categories
@@ -68,12 +92,30 @@ const SharedCarousel = () => {
context && context.socket && context.socket.connected &&
typeof window !== "undefined"
) {
context.socket.emit("categoryList", { categoryId: 209, language: 'en', requestTranslation: true }, (response) => {
if (response && response.categoryTree) {
// Store in cache
context.socket.emit("categoryList", { categoryId: 209, language: currentLanguage, requestTranslation: true }, (response) => {
if (response && response.success) {
// Use translated data if available, otherwise fall back to original
const categoryTreeToUse = response.translation || response.categoryTree;
if (categoryTreeToUse) {
// Store in cache with language-specific key
try {
if (!window.productCache) window.productCache = {};
window.productCache[`categoryTree_209_${currentLanguage}`] = {
categoryTree: categoryTreeToUse,
timestamp: Date.now(),
};
} catch (err) {
console.error(err);
}
setRootCategories(categoryTreeToUse.children || []);
}
} else if (response && response.categoryTree) {
// Fallback for old response format
// Store in cache with language-specific key
try {
if (!window.productCache) window.productCache = {};
window.productCache["categoryTree_209"] = {
window.productCache[`categoryTree_209_${currentLanguage}`] = {
categoryTree: response.categoryTree,
timestamp: Date.now(),
};
@@ -84,7 +126,7 @@ const SharedCarousel = () => {
}
});
}
}, [context, context?.socket?.connected, rootCategories.length]);
}, [context, context?.socket?.connected, rootCategories.length, currentLanguage]);
useEffect(() => {
const filtered = rootCategories.filter(