diff --git a/src/App.jsx b/src/App.jsx index 78ac2e2..e8fbd97 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -24,23 +24,44 @@ function TetrisPiece({ piece, isDark }) { setShowText(false); }; - const bgColor = piece.label === 'cv' ? piece.color : piece.color; + const bgColor = piece.label === 'cv' + ? piece.color + : (isDark ? piece.colorDark : piece.color); const rowDelay = piece.startY * 4; + const textColor = '#ffffff'; + const isStatic = piece.label === 'cv' || piece.featured; - const style = { + const containerStyle = { gridColumn: `${piece.startX + 1} / span ${piece.w}`, gridRow: `${piece.startY + 1} / span ${piece.h}`, - backgroundColor: color || bgColor, - display: 'flex', - alignItems: 'center', - justifyContent: 'center', - aspectRatio: '1', - transition: 'background 0.15s ease', - cursor: piece.link ? 'pointer' : 'default', - overflow: 'hidden', position: 'relative', - animation: `dropIn 0.5s ease-out forwards, colorBlink 5s ease-in-out ${rowDelay}s infinite`, - animationFillMode: 'forwards, none', + cursor: piece.link ? 'pointer' : 'default', + animation: isStatic + ? `dropIn 0.5s ease-out forwards` + : `dropIn 0.5s ease-out forwards, blink 3s ease-in-out ${rowDelay}s infinite`, + animationFillMode: 'forwards', + }; + + const bgStyle = { + position: 'absolute', + inset: 0, + backgroundColor: color || bgColor, + transition: 'background-color 0.15s ease', + pointerEvents: 'none', + }; + + const textStyle = { + position: 'absolute', + bottom: '8px', + left: '8px', + fontSize: 'clamp(8px, 1.5vw, 12px)', + fontWeight: '500', + textTransform: 'lowercase', + color: textColor, + opacity: alwaysShowText ? 1 : (showText ? 1 : 0), + transition: 'opacity 0.15s ease, color 0.15s ease', + zIndex: 1, + pointerEvents: 'none', }; const className = 'tetris-piece show'; @@ -48,62 +69,35 @@ function TetrisPiece({ piece, isDark }) { // CV block shows looping video if (isCV) { return ( - - - - - - {piece.label} - - + + + {piece.label} + ); } - - // Text only shows on hover, positioned at bottom left - const textStyle = { - fontSize: 'clamp(8px, 1.5vw, 12px)', - fontWeight: '500', - textTransform: 'lowercase', - color: alwaysShowText ? '#fff' : '#000', - opacity: alwaysShowText ? 1 : (showText ? 1 : 0), - transition: 'opacity 0.15s ease', - position: 'absolute', - bottom: '8px', - left: '8px', - }; - + const wrapperStyle = { position: 'relative', width: '100%', @@ -112,29 +106,32 @@ function TetrisPiece({ piece, isDark }) { if (piece.link) { return ( - -
- {piece.label} -
-
+ +
+ {piece.label} +
+
+ ); } return (
+
{piece.label}
@@ -151,18 +148,18 @@ function App() { const shuffleLayout = () => { const items = [ - { w: 4, h: 1, label: 'rm8pfix', link: 'https://rm8pfix.khoavo.myds.me', color: '#E8E8E8', hoverColor: '#00BCD4' }, - { w: 2, h: 2, label: 'netflix', link: 'https://nf.khoavo.myds.me', color: '#E8E8E8', hoverColor: '#FF9800' }, - { w: 2, h: 3, label: 'portfolio', link: 'https://portfolio.khoavo.myds.me', featured: true, color: '#4A7BC7', hoverColor: '#2196F3' }, - { w: 2, h: 3, label: 'cv', link: 'https://cv.khoavo.myds.me', color: '#616161', hoverColor: '#424242' }, - { w: 2, h: 2, label: 'youtube', link: 'https://ut.khoavo.myds.me', color: '#E8E8E8', hoverColor: '#FF5722' }, - { w: 2, h: 2, label: 'tiktok', link: 'https://tt.khoavo.myds.me', color: '#E8E8E8', hoverColor: '#9C27B0' }, - { w: 3, h: 2, label: 'spotify', link: 'https://sp.khoavo.myds.me', color: '#E8E8E8', hoverColor: '#4CAF50' }, - { w: 3, h: 2, label: 'tools', link: 'https://it.khoavo.myds.me', color: '#E8E8E8', hoverColor: '#FFC107' }, - { w: 2, h: 2, label: 'save', link: 'https://save.khoavo.myds.me', color: '#E8E8E8', hoverColor: '#E91E63' }, - { w: 2, h: 2, label: 'free', link: 'https://free.khoavo.myds.me', color: '#E8E8E8', hoverColor: '#00BCD4' }, - { w: 2, h: 2, label: 'jpg', link: 'https://jpg.khoavo.myds.me', color: '#E8E8E8', hoverColor: '#673AB7' }, - { w: 2, h: 2, label: 'pdf', link: 'https://pdf.khoavo.myds.me', color: '#E8E8E8', hoverColor: '#795548' }, + { w: 4, h: 1, label: 'rm8pfix', link: 'https://rm8pfix.khoavo.myds.me', color: '#E8E8E8', colorDark: '#333333', hoverColor: '#00BCD4' }, + { w: 2, h: 2, label: 'netflix', link: 'https://nf.khoavo.myds.me', color: '#E8E8E8', colorDark: '#3a3a3a', hoverColor: '#FF9800' }, + { w: 2, h: 3, label: 'portfolio', link: 'https://portfolio.khoavo.myds.me', featured: true, color: '#4A7BC7', colorDark: '#2d4a7c', hoverColor: '#2196F3' }, + { w: 2, h: 3, label: 'cv', link: 'https://cv.khoavo.myds.me', color: '#616161', colorDark: '#424242', hoverColor: '#424242' }, + { w: 2, h: 2, label: 'youtube', link: 'https://ut.khoavo.myds.me', color: '#E8E8E8', colorDark: '#3a3a3a', hoverColor: '#FF5722' }, + { w: 2, h: 2, label: 'tiktok', link: 'https://tt.khoavo.myds.me', color: '#E8E8E8', colorDark: '#3a3a3a', hoverColor: '#9C27B0' }, + { w: 3, h: 2, label: 'spotify', link: 'https://sp.khoavo.myds.me', color: '#E8E8E8', colorDark: '#3a3a3a', hoverColor: '#4CAF50' }, + { w: 3, h: 2, label: 'tools', link: 'https://it.khoavo.myds.me', color: '#E8E8E8', colorDark: '#3a3a3a', hoverColor: '#FFC107' }, + { w: 2, h: 2, label: 'save', link: 'https://save.khoavo.myds.me', color: '#E8E8E8', colorDark: '#3a3a3a', hoverColor: '#E91E63' }, + { w: 2, h: 2, label: 'free', link: 'https://free.khoavo.myds.me', color: '#E8E8E8', colorDark: '#3a3a3a', hoverColor: '#00BCD4' }, + { w: 2, h: 2, label: 'jpg', link: 'https://jpg.khoavo.myds.me', color: '#E8E8E8', colorDark: '#3a3a3a', hoverColor: '#673AB7' }, + { w: 2, h: 2, label: 'pdf', link: 'https://pdf.khoavo.myds.me', color: '#E8E8E8', colorDark: '#3a3a3a', hoverColor: '#795548' }, ]; const random = (s) => { @@ -235,7 +232,7 @@ const layout = shuffleLayout(); const borderColor = isDark ? '#444' : '#000'; return ( -
+