diff --git a/package.json b/package.json index 715411ca..cb88b015 100644 --- a/package.json +++ b/package.json @@ -69,6 +69,7 @@ "date-fns": "^4.1.0", "embla-carousel-react": "^8.5.2", "emoji-picker-react": "^4.12.2", + "framer-motion": "^12.23.26", "geist": "^1.3.0", "jimp": "0.22.12", "leaflet": "^1.9.4", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index ac63a672..3c6ebeec 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -137,6 +137,9 @@ importers: emoji-picker-react: specifier: ^4.12.2 version: 4.16.1(react@19.2.1) + framer-motion: + specifier: ^12.23.26 + version: 12.23.26(react-dom@19.2.1(react@19.2.1))(react@19.2.1) geist: specifier: ^1.3.0 version: 1.5.1(next@15.5.7(@opentelemetry/api@1.9.0)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)) @@ -2949,6 +2952,20 @@ packages: resolution: {integrity: sha512-w/XBfkibaTl3YDqASwfDUqkna4Z2p9cFSr1aHDt0WoMTECnRfBOv2WArlZILlqgWlmdIlALXGpM2AOhEk5W3IA==} engines: {node: '>=0.8'} + framer-motion@12.23.26: + resolution: {integrity: sha512-cPcIhgR42xBn1Uj+PzOyheMtZ73H927+uWPDVhUMqxy8UHt6Okavb6xIz9J/phFUHUj0OncR6UvMfJTXoc/LKA==} + peerDependencies: + '@emotion/is-prop-valid': '*' + react: ^18.0.0 || ^19.0.0 + react-dom: ^18.0.0 || ^19.0.0 + peerDependenciesMeta: + '@emotion/is-prop-valid': + optional: true + react: + optional: true + react-dom: + optional: true + fs.realpath@1.0.0: resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} @@ -3542,6 +3559,12 @@ packages: monaco-editor@0.55.1: resolution: {integrity: sha512-jz4x+TJNFHwHtwuV9vA9rMujcZRb0CEilTEwG2rRSpe/A7Jdkuj8xPKttCgOh+v/lkHy7HsZ64oj+q3xoAFl9A==} + motion-dom@12.23.23: + resolution: {integrity: sha512-n5yolOs0TQQBRUFImrRfs/+6X4p3Q4n1dUEqt/H58Vx7OW6RF+foWEgmTVDhIWJIMXOuNNL0apKH2S16en9eiA==} + + motion-utils@12.23.6: + resolution: {integrity: sha512-eAWoPgr4eFEOFfg2WjIsMoqJTW6Z8MTUCgn/GZ3VRpClWBdnbjryiA3ZSNLyxCTmCQx4RmYX6jX1iWHbenUPNQ==} + ms@2.1.3: resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} @@ -7798,6 +7821,15 @@ snapshots: frac@1.1.2: {} + framer-motion@12.23.26(react-dom@19.2.1(react@19.2.1))(react@19.2.1): + dependencies: + motion-dom: 12.23.23 + motion-utils: 12.23.6 + tslib: 2.8.1 + optionalDependencies: + react: 19.2.1 + react-dom: 19.2.1(react@19.2.1) + fs.realpath@1.0.0: {} fsevents@2.3.3: @@ -8629,6 +8661,12 @@ snapshots: dompurify: 3.2.7 marked: 14.0.0 + motion-dom@12.23.23: + dependencies: + motion-utils: 12.23.6 + + motion-utils@12.23.6: {} + ms@2.1.3: {} msgpackr-extract@3.0.3: diff --git a/src/app/(authenticated)/dashboard/page.tsx b/src/app/(authenticated)/dashboard/page.tsx index ea809662..c159b6d6 100644 --- a/src/app/(authenticated)/dashboard/page.tsx +++ b/src/app/(authenticated)/dashboard/page.tsx @@ -4,7 +4,8 @@ import { MainCarousel } from "@/components/dashboard/main-carousel" import { BirthdaysCarousel } from "@/components/dashboard/birthdays-carousel" import { api } from "@/trpc/react" import { cn } from "@/lib/utils" -import { LinkIcon, LucideGraduationCap } from "lucide-react" +import { LinkIcon, LucideGraduationCap, Coffee, Sparkles } from "lucide-react" +import { motion } from "framer-motion" import { VideosCarousel } from "@/components/dashboard/videos-carousel" import Link from "next/link" import { NewsDisplay } from "@/components/dashboard/news-displ" @@ -19,6 +20,17 @@ import { CompleteProfileModal } from "@/components/complete-profile-modal" import { WelcomeCard } from "@/components/dashboard/welcome-card" import { useState, useEffect, useMemo } from "react" +// Variantes de animação para o footer +const fadeInUp = { + hidden: { opacity: 0, y: 20 }, + visible: { opacity: 1, y: 0 } +} + +const transitionDefault = { + duration: 0.5, + ease: [0.4, 0, 0.2, 1] as const +} + export default function DashboardPage() { const [showProfileModal, setShowProfileModal] = useState(false) @@ -354,8 +366,8 @@ export default function DashboardPage() { {/* Footer com Redes Sociais */}
-
-
+
+
{/* Redes Sociais */}

@@ -401,23 +413,52 @@ export default function DashboardPage() {

- {/* Créditos */} -
-
-
- Elo © 2025 -
-
- Built with ❤️ by - + +

+ ©️ {new Date().getFullYear()} Elo | Intranet +

+ + {/* Link criativo para a empresa desenvolvedora */} + + Feito com + + + + por + - Allpines Allpines - -
-
+ + + +
diff --git a/src/components/dashboard/news-displ.tsx b/src/components/dashboard/news-displ.tsx index 525fbb89..4ae7ee25 100644 --- a/src/components/dashboard/news-displ.tsx +++ b/src/components/dashboard/news-displ.tsx @@ -63,14 +63,13 @@ function PostItemCompact({ post }: PostItemProps) { {/* Imagem no topo */} {imageUrls.length > 0 && ( -
+
1} showDots={imageUrls.length > 1} - className="h-full w-full" imageFit="cover" />
diff --git a/src/components/ui/image-carousel.tsx b/src/components/ui/image-carousel.tsx index 888b2419..53a39502 100644 --- a/src/components/ui/image-carousel.tsx +++ b/src/components/ui/image-carousel.tsx @@ -51,12 +51,25 @@ export function ImageCarousel({ setCurrent(carouselApi.selectedScrollSnap()) - carouselApi.on("select", () => { + const onSelect = () => { setCurrent(carouselApi.selectedScrollSnap()) - }) + } + + carouselApi.on("select", onSelect) + carouselApi.on("reInit", onSelect) + + return () => { + carouselApi.off("select", onSelect) + carouselApi.off("reInit", onSelect) + } }, [carouselApi]) - // Auto play functionality + useEffect(() => { + if (carouselApi && validImages.length > 0) { + carouselApi.reInit() + } + }, [carouselApi, validImages.length]) + useEffect(() => { if (!autoPlay || validImages.length <= 1 || isHovered) return @@ -67,7 +80,6 @@ export function ImageCarousel({ return () => clearInterval(interval) }, [autoPlay, validImages.length, autoPlayInterval, isHovered, carouselApi]) - const allowedAspects = useMemo(() => ([ { value: 1, className: "aspect-square" }, { value: 4 / 3, className: "aspect-[4/3]" }, @@ -127,31 +139,41 @@ export function ImageCarousel({ }) }, [allowedAspects, aspectRatio]) - // Verificar se deve usar altura total (quando className contém h-full) + // CORREÇÃO: Detectar se h-full ou w-full está no className const shouldUseFullHeight = className?.includes('h-full') ?? false + const shouldUseFullWidth = className?.includes('w-full') ?? false - const renderImage = (image: string, index: number) => ( -
- { + // CORREÇÃO: Se h-full está presente, NÃO usar aspect-ratio + // Deixar o container pai controlar a altura + const aspectClass = shouldUseFullHeight ? "" : resolveAspectClass(index) + + return ( +
handleImageLoad(index, img.target as HTMLImageElement)} - imageFit={imageFit} - /> -
- ) + > + handleImageLoad(index, img.target as HTMLImageElement)} + imageFit={imageFit} + /> +
+ ) + } if (!images || images.length === 0) { console.warn('ImageCarousel: No images provided') @@ -163,7 +185,6 @@ export function ImageCarousel({ return null } - // Se há apenas uma imagem, não mostra o carrossel if (validImages.length === 1) { return (
setIsHovered(true)} onMouseLeave={() => setIsHovered(false)} @@ -194,24 +217,32 @@ export function ImageCarousel({ opts={{ loop: true, align: "center", + slidesToScroll: 1, }} > - + {validImages.map((image, index) => ( - + {renderImage(image, index)} ))} - {/* Setas de navegação - apenas em desktop */} {showArrows && ( <>