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(

View File

@@ -350,7 +350,6 @@ i18n
.init({
resources,
fallbackLng: 'de', // German as fallback since it's your primary language
lng: 'de', // Default language
debug: process.env.NODE_ENV === 'development',
// Language detection options

View File

@@ -6,5 +6,6 @@ export default {
"address1": "Trachenberger Straße 14",
"address2": "01129 Dresden",
"showUsPhoto": "ورينا أجمل صورة عندك",
"selectSeedRate": "اختار البذرة واضغط للتقييم"
"selectSeedRate": "اختار البذرة واضغط تقييم",
"indoorSeason": "موسم الزراعة الداخلية بدأ"
};

View File

@@ -6,5 +6,6 @@ export default {
"address1": "Trachenberger Straße 14",
"address2": "01129 Dresden",
"showUsPhoto": "Покажи ни най-красивата си снимка",
"selectSeedRate": "Избери семе, кликни за оценка"
"selectSeedRate": "Избери семе, кликни за оценка",
"indoorSeason": "Вътрешният сезон започва"
};

View File

@@ -6,5 +6,6 @@ export default {
"address1": "Trachenberger Straße 14",
"address2": "01129 Dresden",
"showUsPhoto": "Ukaž nám svou nejkrásnější fotku",
"selectSeedRate": "Vyber semeno, klikni pro hodnocení"
"selectSeedRate": "Vyber semeno, klikni na hodnocení",
"indoorSeason": "Začíná indoor sezóna"
};

View File

@@ -6,5 +6,6 @@ export default {
"address1": "Trachenberger Straße 14",
"address2": "01129 Dresden",
"showUsPhoto": "Zeig uns dein schönstes Foto",
"selectSeedRate": "Wähle Seed aus, klicke Bewerten"
"selectSeedRate": "Wähle Seed aus, klicke Bewerten",
"indoorSeason": "Die Indoorsaison beginnt"
};

View File

@@ -5,6 +5,7 @@ export default {
"thcTest": "Τεστ THC",
"address1": "Trachenberger Straße 14",
"address2": "01129 Dresden",
"showUsPhoto": "Δείξε μας τη πιο όμορφη φωτογραφία σου",
"selectSeedRate": "Επίλεξε σπόρο, κάνε κλικ για αξιολόγηση"
"showUsPhoto": "Δείξε μας την πιο όμορφη φωτογραφία σου",
"selectSeedRate": "Επίλεξε σπόρο, κάνε κλικ για αξιολόγηση",
"indoorSeason": "Η εσωτερική σεζόν ξεκινά"
};

View File

@@ -6,5 +6,6 @@ export default {
"address1": "Trachenberger Straße 14", // Trachenberger Straße 14
"address2": "01129 Dresden", // 01129 Dresden
"showUsPhoto": "Show us your most beautiful photo", // Zeig uns dein schönstes Foto
"selectSeedRate": "Select seed, click to rate" // Wähle Seed aus, klicke Bewerten
"selectSeedRate": "Select seed, click rate", // Wähle Seed aus, klicke Bewerten
"indoorSeason": "The indoor season begins" // Die Indoorsaison beginnt
};

View File

@@ -6,5 +6,6 @@ export default {
"address1": "Trachenberger Straße 14",
"address2": "01129 Dresden",
"showUsPhoto": "Muéstranos tu foto más hermosa",
"selectSeedRate": "Selecciona semilla, haz clic para calificar"
"selectSeedRate": "Selecciona semilla, haz clic para valorar",
"indoorSeason": "Comienza la temporada de interior"
};

View File

@@ -6,5 +6,6 @@ export default {
"address1": "Trachenberger Straße 14",
"address2": "01129 Dresden",
"showUsPhoto": "Montre-nous ta plus belle photo",
"selectSeedRate": "Sélectionne une graine, clique pour évaluer"
"selectSeedRate": "Sélectionne une graine, clique pour noter",
"indoorSeason": "La saison en intérieur commence"
};

View File

@@ -6,5 +6,6 @@ export default {
"address1": "Trachenberger Straße 14",
"address2": "01129 Dresden",
"showUsPhoto": "Pokaži nam svoju najljepšu fotografiju",
"selectSeedRate": "Odaberi sjeme, klikni za ocjenu"
"selectSeedRate": "Odaberi sjeme, klikni ocjenu",
"indoorSeason": "Počinje sezona uzgoja u zatvorenom"
};

View File

@@ -6,5 +6,6 @@ export default {
"address1": "Trachenberger Straße 14",
"address2": "01129 Dresden",
"showUsPhoto": "Mutasd meg nekünk a legszebb fotódat",
"selectSeedRate": "Válassz magot, kattints az értékeléshez"
"selectSeedRate": "Válassz magot, kattints az értékelésre",
"indoorSeason": "Kezdődik a beltéri szezon"
};

View File

@@ -6,5 +6,6 @@ export default {
"address1": "Trachenberger Straße 14",
"address2": "01129 Dresden",
"showUsPhoto": "Mostraci la tua foto più bella",
"selectSeedRate": "Seleziona il seme, clicca per valutare"
"selectSeedRate": "Seleziona il seme, clicca per valutare",
"indoorSeason": "Inizia la stagione indoor"
};

View File

@@ -6,5 +6,6 @@ export default {
"address1": "Trachenberger Straße 14",
"address2": "01129 Dresden",
"showUsPhoto": "Pokaż nam swoje najpiękniejsze zdjęcie",
"selectSeedRate": "Wybierz nasiono, kliknij, aby ocenić"
"selectSeedRate": "Wybierz nasiono, kliknij ocenę",
"indoorSeason": "Sezon indoor się zaczyna"
};

View File

@@ -6,5 +6,6 @@ export default {
"address1": "Trachenberger Straße 14",
"address2": "01129 Dresden",
"showUsPhoto": "Arată-ne cea mai frumoasă fotografie a ta",
"selectSeedRate": "Selectează sămânța, fă clic pentru a evalua"
"selectSeedRate": "Selectează sămânța, apasă pentru evaluare",
"indoorSeason": "Sezonul indoor începe"
};

View File

@@ -6,5 +6,6 @@ export default {
"address1": "Trachenberger Straße 14",
"address2": "01129 Dresden",
"showUsPhoto": "Покажи нам свою самую красивую фотографию",
"selectSeedRate": "Выберите семя, нажмите для оценки"
"selectSeedRate": "Выберите семя, нажмите оценить",
"indoorSeason": "Начинается сезон для выращивания в помещении"
};

View File

@@ -6,5 +6,6 @@ export default {
"address1": "Trachenberger Straße 14",
"address2": "01129 Dresden",
"showUsPhoto": "Ukážte nám svoju najkrajšiu fotku",
"selectSeedRate": "Vyberte semienko, kliknite na hodnotenie"
"selectSeedRate": "Vyberte semienko, kliknite na hodnotenie",
"indoorSeason": "Začína sezóna pestovania v interiéri"
};

View File

@@ -1,10 +1,11 @@
export default {
"seeds": "Semena",
"stecklinge": "Rezalci",
"oilPress": "Izposodi si stiskalnico olja",
"oilPress": "Izposodi si stiskalnico za olje",
"thcTest": "THC test",
"address1": "Trachenberger Straße 14",
"address2": "01129 Dresden",
"showUsPhoto": "Pokaži nam svojo najlepšo fotografijo",
"selectSeedRate": "Izberi seme, klikni za oceno"
"selectSeedRate": "Izberi seme, klikni oceno",
"indoorSeason": "Začne se sezona gojenja v zaprtih prostorih"
};

View File

@@ -6,5 +6,6 @@ export default {
"address1": "Trachenberger Straße 14",
"address2": "01129 Dresden",
"showUsPhoto": "Pokaži nam svoju najlepšu fotografiju",
"selectSeedRate": "Izaberi seme, klikni da oceniš"
"selectSeedRate": "Izaberi seme, klikni oceni",
"indoorSeason": "Počinje sezona za uzgoj u zatvorenom"
};

View File

@@ -6,5 +6,6 @@ export default {
"address1": "Trachenberger Straße 14",
"address2": "01129 Dresden",
"showUsPhoto": "Visa oss ditt vackraste foto",
"selectSeedRate": "Välj frö, klicka för att betygsätta"
"selectSeedRate": "Välj frö, klicka betyg",
"indoorSeason": "Inomhussäsongen börjar"
};

View File

@@ -1,10 +1,11 @@
export default {
"seeds": "Tohumlar",
"stecklinge": "Çelikler",
"oilPress": "Yağ presi ödünç al",
"oilPress": "Yağ presini ödünç al",
"thcTest": "THC testi",
"address1": "Trachenberger Straße 14",
"address2": "01129 Dresden",
"showUsPhoto": "Bize en güzel fotoğrafını göster",
"selectSeedRate": "Tohumu seç, değerlendirmek için tıkla"
"showUsPhoto": "En güzel fotoğrafını göster",
"selectSeedRate": "Tohumu seç, oy ver",
"indoorSeason": "Kapalı sezon başlıyor"
};

View File

@@ -6,5 +6,6 @@ export default {
"address1": "Trachenberger Straße 14",
"address2": "01129 Dresden",
"showUsPhoto": "Покажи нам своє найкрасивіше фото",
"selectSeedRate": "Виберіть насіння, натисніть, щоб оцінити"
"selectSeedRate": "Виберіть насіння, натисніть оцінити",
"indoorSeason": "Починається сезон для вирощування в приміщенні"
};

View File

@@ -6,5 +6,6 @@ export default {
"address1": "Trachenberger Straße 14",
"address2": "01129 Dresden",
"showUsPhoto": "展示你最美的照片",
"selectSeedRate": "选择种子,点击评分"
"selectSeedRate": "选择种子,点击评分",
"indoorSeason": "室内季节开始了"
};

View File

@@ -28,14 +28,15 @@ export class LanguageProvider extends Component {
}
componentDidMount() {
// Listen for language changes from i18n
if (this.props.i18n) {
this.props.i18n.on('languageChanged', this.handleLanguageChanged);
// Set initial language state and HTML attribute
this.setState({ currentLanguage: this.props.i18n.language });
document.documentElement.lang = this.props.i18n.language;
}
}
componentWillUnmount() {
// Clean up listener
if (this.props.i18n) {
this.props.i18n.off('languageChanged', this.handleLanguageChanged);
}
@@ -47,6 +48,13 @@ export class LanguageProvider extends Component {
// Update HTML lang attribute for SEO
document.documentElement.lang = lng;
// Ensure language is saved to localStorage
try {
localStorage.setItem('i18nextLng', lng);
} catch (error) {
console.warn('Could not save language to localStorage:', error);
}
// Update config if available
if (window.shopConfig) {
// Language code mapping for all supported languages