Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
69 changes: 46 additions & 23 deletions client/src/components/SongCard.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,15 @@
import { Link } from "wouter";
import { Music, Calendar, Trash2, Globe, Lock } from "lucide-react";
import { Music, Calendar, Trash2, Globe, Lock, Loader2 } from "lucide-react";
import { type Song } from "@shared/schema";
import { format } from "date-fns";
import { useDeleteSong } from "@/hooks/use-songs";
import { Button } from "@/components/ui/button";
import { memo } from "react";
import {
Tooltip,
TooltipContent,
TooltipTrigger,
} from "@/components/ui/tooltip";
import {
AlertDialog,
AlertDialogAction,
Expand Down Expand Up @@ -45,30 +50,48 @@ export const SongCard = memo(function SongCard({ song }: SongCardProps) {
</div>

<div className="flex items-center gap-1 relative z-20 pointer-events-auto">
{song.isPublic ? (
<span className="p-2 text-primary" title="Public">
<Globe className="w-4 h-4" />
</span>
) : (
<span className="p-2 text-muted-foreground" title="Private">
<Lock className="w-4 h-4" />
</span>
)}
<Tooltip>
<TooltipTrigger asChild>
{song.isPublic ? (
<span className="p-2 text-primary cursor-default" tabIndex={0} role="img" aria-label="Public song">
<Globe className="w-4 h-4" />
</span>
) : (
<span className="p-2 text-muted-foreground cursor-default" tabIndex={0} role="img" aria-label="Private song">
<Lock className="w-4 h-4" />
</span>
)}
Comment on lines +55 to +63
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

This block of code for displaying the public/private icon can be simplified to be more DRY (Don't Repeat Yourself). You can use a single <span> element and conditionally set the className, aria-label, and the icon component based on song.isPublic. This will make the code cleaner and easier to maintain.

Suggested change
{song.isPublic ? (
<span className="p-2 text-primary cursor-default" tabIndex={0} role="img" aria-label="Public song">
<Globe className="w-4 h-4" />
</span>
) : (
<span className="p-2 text-muted-foreground cursor-default" tabIndex={0} role="img" aria-label="Private song">
<Lock className="w-4 h-4" />
</span>
)}
<span
className={`p-2 cursor-default ${song.isPublic ? "text-primary" : "text-muted-foreground"}`}
tabIndex={0}
role="img"
aria-label={song.isPublic ? "Public song" : "Private song"}
>
{song.isPublic ? <Globe className="w-4 h-4" /> : <Lock className="w-4 h-4" />}
</span>

</TooltipTrigger>
<TooltipContent>
<p>{song.isPublic ? "Public - visible to everyone" : "Private - only visible to you"}</p>
</TooltipContent>
Comment on lines +65 to +67

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Portal SongCard tooltip content to avoid clipping

The new TooltipContent instances in SongCard are rendered inside a card container that has overflow-hidden (client/src/components/SongCard.tsx), and our tooltip primitive currently renders content inline (no TooltipPrimitive.Portal in client/src/components/ui/tooltip.tsx). In this layout (top-right icons near the card edge), the tooltip for Public/Private and Delete song is clipped by the card bounds, so the added guidance is partially or fully unreadable for users.

Useful? React with 👍 / 👎.

</Tooltip>

<AlertDialog>
<AlertDialogTrigger asChild>
<Button
size="icon"
variant="ghost"
onClick={(e) => e.stopPropagation()}
disabled={isPending}
className="opacity-0 group-hover:opacity-100 focus:opacity-100 transition-opacity"
data-testid={`button-delete-${song.id}`}
aria-label="Delete song"
>
<Trash2 className="w-4 h-4 text-destructive" />
</Button>
</AlertDialogTrigger>
<Tooltip>
<TooltipTrigger asChild>
<AlertDialogTrigger asChild>
<Button
size="icon"
variant="ghost"
onClick={(e) => e.stopPropagation()}
disabled={isPending}
className="opacity-0 group-hover:opacity-100 focus:opacity-100 transition-opacity"
data-testid={`button-delete-${song.id}`}
aria-label="Delete song"
>
{isPending ? (
<Loader2 className="w-4 h-4 animate-spin" />
) : (
<Trash2 className="w-4 h-4 text-destructive" />
)}
</Button>
</AlertDialogTrigger>
</TooltipTrigger>
<TooltipContent>
<p>Delete song</p>
</TooltipContent>
</Tooltip>
<AlertDialogContent>
<AlertDialogHeader>
<AlertDialogTitle>Delete Song</AlertDialogTitle>
Expand Down
1 change: 1 addition & 0 deletions server.log
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Frontend server running at http://localhost:3000
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

Log files should not be committed to the version control system. This file appears to be a server log. Please remove it from the repository and add server.log or a more general pattern like *.log to your .gitignore file to prevent this from happening in the future.

Binary file added verification_debug.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.