diff --git a/frontend/src/components/GenerativeBanner.tsx b/frontend/src/components/GenerativeBanner.tsx index 144158b..fe7be70 100644 --- a/frontend/src/components/GenerativeBanner.tsx +++ b/frontend/src/components/GenerativeBanner.tsx @@ -30,11 +30,9 @@ const GenerativeBanner: React.FC = ({ username, palette, let animationFrameId: number; const seed = getSeed(username); - // Dynamic count and speed - const nodeCount = Math.min(20 + Math.floor(ratingsCount / 2), 50); - const speedMultiplier = 0.25 + (Math.min(followersCount, 50) / 80); + const nodeCount = Math.min(25 + Math.floor(ratingsCount / 2), 60); + const speedMultiplier = 0.3 + (Math.min(followersCount, 50) / 80); - // Prefer vibrant colors const colors = palette.length >= 2 ? palette : [theme.palette.primary.main, theme.palette.secondary.main, theme.palette.info.main]; interface Node { @@ -62,7 +60,7 @@ const GenerativeBanner: React.FC = ({ username, palette, vx: (pseudoRandom(i + 200) - 0.5) * speedMultiplier, vy: (pseudoRandom(i + 300) - 0.5) * speedMultiplier, color: colors[i % colors.length], - size: 2 + pseudoRandom(i + 400) * 5 + size: 2 + pseudoRandom(i + 400) * 4 }); } return newNodes; @@ -72,15 +70,12 @@ const GenerativeBanner: React.FC = ({ username, palette, const parent = canvas.parentElement; if (parent) { const rect = parent.getBoundingClientRect(); - // Scale for high DPI const dpr = window.devicePixelRatio || 1; canvas.width = rect.width * dpr; canvas.height = rect.height * dpr; ctx.scale(dpr, dpr); - // Adjust CSS display size canvas.style.width = `${rect.width}px`; canvas.style.height = `${rect.height}px`; - nodes = initNodes(rect.width, rect.height); } }; @@ -91,6 +86,7 @@ const GenerativeBanner: React.FC = ({ username, palette, resize(); let mouse = { x: -1000, y: -1000, down: false }; + const handleMouseMove = (e: MouseEvent) => { const rect = canvas.getBoundingClientRect(); mouse.x = e.clientX - rect.left; @@ -105,17 +101,17 @@ const GenerativeBanner: React.FC = ({ username, palette, } }; - const handleMouseDown = () => mouse.down = true; - const handleMouseUp = () => mouse.down = false; + const handleMouseDown = () => { mouse.down = true; }; + const handleMouseUp = () => { mouse.down = false; }; - // Attach to window for better tracking - window.addEventListener('mousemove', handleMouseMove); - window.addEventListener('touchmove', handleTouchMove); - window.addEventListener('mousedown', handleMouseDown); - window.addEventListener('mouseup', handleMouseUp); + // Event listeners on canvas for local coordinates + canvas.addEventListener('mousemove', handleMouseMove); + canvas.addEventListener('touchmove', handleTouchMove); + canvas.addEventListener('mousedown', handleMouseDown); + canvas.addEventListener('mouseup', handleMouseUp); + canvas.addEventListener('mouseleave', () => { mouse.x = -1000; mouse.y = -1000; mouse.down = false; }); const draw = () => { - // Get CSS dimensions for drawing const width = canvas.width / (window.devicePixelRatio || 1); const height = canvas.height / (window.devicePixelRatio || 1); @@ -136,11 +132,11 @@ const GenerativeBanner: React.FC = ({ username, palette, const dx = mouse.x - node.x; const dy = mouse.y - node.y; const dist = Math.sqrt(dx * dx + dy * dy); - const maxDist = mouse.down ? 400 : 200; + const maxDist = mouse.down ? 300 : 150; if (dist < maxDist) { const force = (maxDist - dist) / maxDist; - const strength = mouse.down ? 0.2 : 0.08; + const strength = mouse.down ? 0.3 : 0.1; if (mouse.down) { node.x += dx * force * strength; node.y += dy * force * strength; @@ -151,30 +147,30 @@ const GenerativeBanner: React.FC = ({ username, palette, } }); - // Draw mesh connections - ctx.lineWidth = 1.5; + // Draw mesh + ctx.lineWidth = 1; for (let i = 0; i < nodes.length; i++) { for (let j = i + 1; j < nodes.length; j++) { const ddist = Math.sqrt(Math.pow(nodes[i].x - nodes[j].x, 2) + Math.pow(nodes[i].y - nodes[j].y, 2)); - if (ddist < 160) { + if (ddist < 120) { ctx.beginPath(); ctx.moveTo(nodes[i].x, nodes[i].y); ctx.lineTo(nodes[j].x, nodes[j].y); - ctx.strokeStyle = alpha(nodes[i].color, (1 - ddist / 160) * 0.3); + ctx.strokeStyle = alpha(nodes[i].color, (1 - ddist / 120) * 0.4); ctx.stroke(); for (let k = j + 1; k < nodes.length; k++) { const ddist2 = Math.sqrt(Math.pow(nodes[j].x - nodes[k].x, 2) + Math.pow(nodes[j].y - nodes[k].y, 2)); const ddist3 = Math.sqrt(Math.pow(nodes[i].x - nodes[k].x, 2) + Math.pow(nodes[i].y - nodes[k].y, 2)); - if (ddist2 < 160 && ddist3 < 160) { + if (ddist2 < 120 && ddist3 < 120) { ctx.beginPath(); ctx.moveTo(nodes[i].x, nodes[i].y); ctx.lineTo(nodes[j].x, nodes[j].y); ctx.lineTo(nodes[k].x, nodes[k].y); ctx.closePath(); - ctx.fillStyle = alpha(nodes[i].color, 0.06); + ctx.fillStyle = alpha(nodes[i].color, 0.1); ctx.fill(); } } @@ -182,24 +178,16 @@ const GenerativeBanner: React.FC = ({ username, palette, } } - // Draw nodes with high-visibility glow + // Draw nodes nodes.forEach(node => { - // Core ctx.beginPath(); ctx.arc(node.x, node.y, node.size, 0, Math.PI * 2); - ctx.fillStyle = alpha(node.color, 0.8); + ctx.fillStyle = alpha(node.color, 0.9); ctx.fill(); - // Inner Glow ctx.beginPath(); - ctx.arc(node.x, node.y, node.size * 2, 0, Math.PI * 2); - ctx.fillStyle = alpha(node.color, 0.2); - ctx.fill(); - - // Outer Atmosphere - ctx.beginPath(); - ctx.arc(node.x, node.y, node.size * 4, 0, Math.PI * 2); - ctx.fillStyle = alpha(node.color, 0.05); + ctx.arc(node.x, node.y, node.size * 2.5, 0, Math.PI * 2); + ctx.fillStyle = alpha(node.color, 0.15); ctx.fill(); }); @@ -210,10 +198,10 @@ const GenerativeBanner: React.FC = ({ username, palette, return () => { resizeObserver.disconnect(); - window.removeEventListener('mousemove', handleMouseMove); - window.removeEventListener('touchmove', handleTouchMove); - window.removeEventListener('mousedown', handleMouseDown); - window.removeEventListener('mouseup', handleMouseUp); + canvas.removeEventListener('mousemove', handleMouseMove); + canvas.removeEventListener('touchmove', handleTouchMove); + canvas.removeEventListener('mousedown', handleMouseDown); + canvas.removeEventListener('mouseup', handleMouseUp); cancelAnimationFrame(animationFrameId); }; }, [username, palette, ratingsCount, followersCount, theme]); @@ -225,9 +213,11 @@ const GenerativeBanner: React.FC = ({ username, palette, position: 'absolute', top: 0, left: 0, - pointerEvents: 'none', - zIndex: 10, - mixBlendMode: 'plus-lighter' // Makes it pop against dark backgrounds + width: '100%', + height: '100%', + pointerEvents: 'auto', // Enable direct interaction + zIndex: 5, + cursor: 'pointer' }} /> ); diff --git a/frontend/src/i18n.ts b/frontend/src/i18n.ts index 0b0d73b..4856b6f 100644 --- a/frontend/src/i18n.ts +++ b/frontend/src/i18n.ts @@ -40,12 +40,12 @@ const resources = { "newScore": "New Score:", "searchMissing": "Search flavors you haven't rated...", "searchRated": "Search your reviews...", - "circleAvg": "Average rating from people you follow", + "circleAvg": "Average rating from your friends", "sortBy": "Sort by", "date": "Date", "rating": "Rating", "communityRating": "Community Rating", - "circleRating": "Circle Rating" + "circleRating": "Friends Rating" }, "settings": { "subtitle": "Manage your account and preferences", @@ -234,12 +234,12 @@ const resources = { "newScore": "Neue Bewertung:", "searchMissing": "Suche nach Sorten, die du noch nicht bewertet hast...", "searchRated": "Suche in deinen Rezensionen...", - "circleAvg": "Durchschnittsbewertung der Personen, denen du folgst", + "circleAvg": "Durchschnittsbewertung deiner Freunde", "sortBy": "Sortieren nach", "date": "Datum", "rating": "Bewertung", "communityRating": "Community-Bewertung", - "circleRating": "Circle-Bewertung" + "circleRating": "Freunde-Bewertung" }, "settings": { "subtitle": "Verwalte dein Konto und deine Einstellungen", diff --git a/frontend/src/pages/Dashboard.tsx b/frontend/src/pages/Dashboard.tsx index 525e6f8..876db1e 100644 --- a/frontend/src/pages/Dashboard.tsx +++ b/frontend/src/pages/Dashboard.tsx @@ -21,8 +21,11 @@ import { TextField, InputAdornment, Tooltip, - useMediaQuery + useMediaQuery, + Select, + MenuItem } from '@mui/material';import ArrowBackIcon from '@mui/icons-material/ArrowBack'; +import SortIcon from '@mui/icons-material/Sort'; import ShareIcon from '@mui/icons-material/Share'; import CommentIcon from '@mui/icons-material/Comment'; import VerifiedIcon from '@mui/icons-material/Verified'; @@ -262,10 +265,10 @@ const Dashboard: React.FC = () => { { - - - - + @@ -561,24 +564,24 @@ const Dashboard: React.FC = () => { - - - - + @@ -620,14 +623,24 @@ const Dashboard: React.FC = () => { }} /> - + {flavor.followed_average_rating && ( - + - {flavor.followed_average_rating.toFixed(1)} + {flavor.followed_average_rating.toFixed(1)} diff --git a/frontend/src/pages/PublicProfile.tsx b/frontend/src/pages/PublicProfile.tsx index e065ea2..b2182d6 100644 --- a/frontend/src/pages/PublicProfile.tsx +++ b/frontend/src/pages/PublicProfile.tsx @@ -234,12 +234,12 @@ const PublicProfile: React.FC = ({ adminMode }) => { ]; const abstractBanner = ` - radial-gradient(at 0% 0%, ${alpha(bannerColors[0], 0.8)} 0px, transparent 55%), - radial-gradient(at 100% 0%, ${alpha(bannerColors[1], 0.7)} 0px, transparent 55%), - radial-gradient(at 100% 100%, ${alpha(bannerColors[2], 0.6)} 0px, transparent 55%), - radial-gradient(at 0% 100%, ${alpha(bannerColors[3], 0.5)} 0px, transparent 55%), - radial-gradient(at 50% 50%, ${alpha(bannerColors[0], 0.4)} 0px, transparent 60%), - linear-gradient(135deg, ${alpha(bannerColors[0], 0.2)} 0%, ${alpha(bannerColors[1], 0.2)} 100%) + radial-gradient(at 0% 0%, ${alpha(bannerColors[0], 0.6)} 0px, transparent 55%), + radial-gradient(at 100% 0%, ${alpha(bannerColors[1], 0.5)} 0px, transparent 55%), + radial-gradient(at 100% 100%, ${alpha(bannerColors[2], 0.4)} 0px, transparent 55%), + radial-gradient(at 0% 100%, ${alpha(bannerColors[3], 0.3)} 0px, transparent 55%), + radial-gradient(at 50% 50%, ${alpha(bannerColors[0], 0.3)} 0px, transparent 60%), + linear-gradient(135deg, ${alpha(bannerColors[0], 0.1)} 0%, ${alpha(bannerColors[1], 0.1)} 100%) `; const handleGoBack = () => {