From 31e50af593c9500fb9daacfbcc395b96aea1350a Mon Sep 17 00:00:00 2001 From: yohlo Date: Mon, 29 Sep 2025 10:20:54 -0500 Subject: [PATCH] team logo compression, play around with style --- package.json | 1 + src/features/core/components/header.tsx | 5 ++- src/features/core/components/navbar.tsx | 10 ++++-- .../teams/components/team-form/index.tsx | 31 ++++++++++++++++--- src/lib/spotify/auth.ts | 2 +- 5 files changed, 41 insertions(+), 8 deletions(-) diff --git a/package.json b/package.json index c8d71d4..0334e71 100644 --- a/package.json +++ b/package.json @@ -32,6 +32,7 @@ "@tiptap/starter-kit": "^3.4.3", "@types/bun": "^1.2.22", "@types/ioredis": "^4.28.10", + "browser-image-compression": "^2.0.2", "dotenv": "^17.2.2", "embla-carousel-react": "^8.6.0", "framer-motion": "^12.23.12", diff --git a/src/features/core/components/header.tsx b/src/features/core/components/header.tsx index da789a5..c1ec8e9 100644 --- a/src/features/core/components/header.tsx +++ b/src/features/core/components/header.tsx @@ -6,7 +6,10 @@ interface HeaderProps extends HeaderConfig {} const Header = ({ collapsed, title, withBackButton }: HeaderProps) => { return ( - + { withBackButton && } {title} diff --git a/src/features/core/components/navbar.tsx b/src/features/core/components/navbar.tsx index 6c25739..80d6114 100644 --- a/src/features/core/components/navbar.tsx +++ b/src/features/core/components/navbar.tsx @@ -1,4 +1,4 @@ -import { AppShell, ScrollArea, Stack, Group, Paper } from "@mantine/core"; +import { AppShell, ScrollArea, Stack, Group, Paper, useMantineColorScheme } from "@mantine/core"; import { Link } from "@tanstack/react-router"; import { NavLink } from "./nav-link"; import { useIsMobile } from "@/hooks/use-is-mobile"; @@ -9,11 +9,17 @@ import { memo } from "react"; const Navbar = () => { const { user, roles } = useAuth() const isMobile = useIsMobile(); + const { colorScheme } = useMantineColorScheme(); const links = useLinks(user?.id, roles); + const isDark = colorScheme === 'dark'; + const borderColor = isDark ? 'var(--mantine-color-dimmed)' : 'black'; + const boxShadowColor = isDark ? 'var(--mantine-color-dimmed)' : 'black'; + // boxShadow: `5px 5px ${boxShadowColor}`, borderColor + if (isMobile) return ( - + {links.map((link) => ( diff --git a/src/features/teams/components/team-form/index.tsx b/src/features/teams/components/team-form/index.tsx index 17d7c44..d03a73c 100644 --- a/src/features/teams/components/team-form/index.tsx +++ b/src/features/teams/components/team-form/index.tsx @@ -1,7 +1,7 @@ -import { Badge, FileInput, Group, Stack, Text, TextInput } from "@mantine/core"; +import { FileInput, Stack, TextInput } from "@mantine/core"; import { useForm, UseFormInput } from "@mantine/form"; import { LinkIcon } from "@phosphor-icons/react"; -import SlidePanel, { SlidePanelField } from "@/components/sheet/slide-panel"; +import SlidePanel from "@/components/sheet/slide-panel"; import { isNotEmpty } from "@mantine/form"; import useCreateTeam from "../../hooks/use-create-team"; import useUpdateTeam from "../../hooks/use-update-team"; @@ -13,8 +13,8 @@ import { useCallback } from "react"; import { TeamInput } from "../../types"; import { teamKeys } from "../../queries"; import SongPicker from "./song-picker"; -import TeamColorPicker from "./color-picker"; import PlayersPicker from "./players-picker"; +import imageCompression from "browser-image-compression"; interface TeamFormProps { close: () => void; @@ -113,9 +113,32 @@ const TeamForm = ({ if (logo && team) { try { + let processedLogo = logo; + + if (logo.size > 500 * 1024) { + const compressionOptions = { + maxSizeMB: 0.5, + maxWidthOrHeight: 800, + useWebWorker: true, + fileType: logo.type, + }; + + try { + processedLogo = await imageCompression(logo, compressionOptions); + logger.info("image compressed", { + originalSize: logo.size, + compressedSize: processedLogo.size, + reduction: ((logo.size - processedLogo.size) / logo.size * 100).toFixed(1) + "%" + }); + } catch (compressionError) { + logger.warn("compression failed, falling back", compressionError); + processedLogo = logo; + } + } + const formData = new FormData(); formData.append("teamId", team.id); - formData.append("logo", logo); + formData.append("logo", processedLogo); const response = await fetch("/api/teams/upload-logo", { method: "POST", diff --git a/src/lib/spotify/auth.ts b/src/lib/spotify/auth.ts index 332e06a..b0aeaaf 100644 --- a/src/lib/spotify/auth.ts +++ b/src/lib/spotify/auth.ts @@ -1,4 +1,4 @@ -import type { PKCEState, SpotifyTokenResponse } from './types'; +import type { SpotifyTokenResponse } from './types'; const SPOTIFY_AUTH_BASE = 'https://accounts.spotify.com'; const SPOTIFY_SCOPES = [