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
34 changes: 34 additions & 0 deletions client/src/components/Leaderboard.css
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ h2 {
width: 100%;
flex-grow: 1;
overflow-y: auto;
overflow-x: visible;
Copy link

Copilot AI Nov 2, 2025

Choose a reason for hiding this comment

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

Setting overflow-x to visible while overflow-y is auto (line 61) can cause unexpected behavior in some browsers, as they may force both overflow properties to the same value. Consider using a wrapper element for the tooltip or alternative positioning strategies to avoid potential cross-browser issues.

Copilot uses AI. Check for mistakes.
border-radius: 8px;
background-color: rgba(30, 30, 30, 0.4); /* Slightly darker but still transparent */
border: 1px solid rgba(255, 255, 255, 0.05);
Expand Down Expand Up @@ -176,6 +177,39 @@ h2 {
border-radius: 4px;
}

/* Title tooltip styles */
.title-with-tooltip {
position: relative;
cursor: help;
}

.title-tooltip {
visibility: hidden;
opacity: 0;
position: fixed;
background-color: rgba(20, 20, 20, 0.98);
color: #fff;
padding: 0.6rem 0.9rem;
border-radius: 6px;
font-size: 0.85rem;
max-width: 280px;
text-align: left;
z-index: 10000;
box-shadow: 0 6px 20px rgba(0, 0, 0, 0.6);
border: 1px solid rgba(245, 128, 37, 0.4);
pointer-events: none;
transition: opacity 0.2s ease, visibility 0.2s ease;
line-height: 1.4;
white-space: normal;
word-wrap: break-word;
transform: translateY(8px);
Copy link

Copilot AI Nov 2, 2025

Choose a reason for hiding this comment

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

The tooltip in Leaderboard.css uses transform: translateY(8px) (line 205) while ProfileModal.css tooltips don't use this transform property, despite both positioning tooltips 8px below the element. This inconsistency means tooltips appear slightly different between components. Consider standardizing the approach.

Suggested change
transform: translateY(8px);

Copilot uses AI. Check for mistakes.
}

.title-with-tooltip:hover .title-tooltip {
visibility: visible;
opacity: 1;
}

.leaderboard-stats {
display: flex;
gap: 1.5rem;
Expand Down
15 changes: 14 additions & 1 deletion client/src/components/Leaderboard.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -425,8 +425,21 @@ function Leaderboard({ defaultDuration = 15, defaultPeriod = 'alltime', layoutMo
const titleToShow = titles?.find(t => t.is_equipped);
return titleToShow ? (
<div className="leaderboard-titles">
<span className="leaderboard-title-badge">
<span
className="leaderboard-title-badge title-with-tooltip"
onMouseEnter={(e) => {
const tooltip = e.currentTarget.querySelector('.title-tooltip');
if (tooltip) {
const rect = e.currentTarget.getBoundingClientRect();
tooltip.style.top = `${rect.bottom + 8}px`;
tooltip.style.left = `${rect.left}px`;
}
}}
>
{titleToShow.name}
{titleToShow.description && (
<span className="title-tooltip">{titleToShow.description}</span>
)}
</span>
</div>
) : null;
Expand Down
32 changes: 32 additions & 0 deletions client/src/components/ProfileModal.css
Original file line number Diff line number Diff line change
Expand Up @@ -950,6 +950,38 @@
color: var(--text-color-highlight);
}

/* Title tooltip styles for profile modal */
.displayed-title-name.title-with-tooltip {
position: relative;
cursor: help;
}

.displayed-title-name.title-with-tooltip .title-tooltip {
visibility: hidden;
opacity: 0;
position: fixed;
background-color: rgba(20, 20, 20, 0.98);
color: #fff;
padding: 0.6rem 0.9rem;
border-radius: 6px;
font-size: 0.85rem;
max-width: 280px;
text-align: left;
z-index: 10001;
box-shadow: 0 6px 20px rgba(0, 0, 0, 0.6);
border: 1px solid rgba(245, 128, 37, 0.4);
pointer-events: none;
transition: opacity 0.2s ease, visibility 0.2s ease;
line-height: 1.4;
white-space: normal;
word-wrap: break-word;
}

.displayed-title-name.title-with-tooltip:hover .title-tooltip {
visibility: visible;
opacity: 1;
}

.no-title-display {
font-style: italic;
color: #888888;
Expand Down
48 changes: 44 additions & 4 deletions client/src/components/ProfileModal.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -757,12 +757,52 @@ function ProfileModal({ isOpen, onClose, netid }) {
<div className="title-display static-title">
{loadingTitles ? (
<span>Loading title...</span>
) : displayUser && displayUser.selected_title_id && userTitles.find(t => String(t.id) === String(displayUser.selected_title_id))?.name ? (
) : displayUser && displayUser.selected_title_id && userTitles.find(t => String(t.id) === String(displayUser.selected_title_id)) ? (
// Display the equipped title if available
<span className="displayed-title-name">{userTitles.find(t => String(t.id) === String(displayUser.selected_title_id)).name}</span>
) : userTitles.find(t => t.is_equipped)?.name ? (
(() => {
const equippedTitle = userTitles.find(t => String(t.id) === String(displayUser.selected_title_id));
return (
<span
className="displayed-title-name title-with-tooltip"
onMouseEnter={(e) => {
const tooltip = e.currentTarget.querySelector('.title-tooltip');
if (tooltip) {
const rect = e.currentTarget.getBoundingClientRect();
tooltip.style.top = `${rect.bottom + 8}px`;
tooltip.style.left = `${rect.left}px`;
}
}}
Comment on lines +767 to +774
Copy link

Copilot AI Nov 2, 2025

Choose a reason for hiding this comment

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

The tooltip positioning logic runs on every mouse enter event. When the tooltip is hidden (visibility: hidden in CSS), getBoundingClientRect() still triggers a layout recalculation. Consider debouncing or using CSS-only positioning if possible to avoid unnecessary layout calculations on hover.

Copilot uses AI. Check for mistakes.
>
{equippedTitle.name}
{equippedTitle.description && (
<span className="title-tooltip">{equippedTitle.description}</span>
)}
</span>
);
})()
Comment on lines +762 to +782
Copy link

Copilot AI Nov 2, 2025

Choose a reason for hiding this comment

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

This tooltip positioning logic is duplicated three times across ProfileModal.jsx and Leaderboard.jsx. Consider extracting it into a reusable component or custom hook (e.g., TitleWithTooltip) to reduce code duplication and improve maintainability.

Copilot uses AI. Check for mistakes.
) : userTitles.find(t => t.is_equipped) ? (
// Alternatively check for is_equipped flag from the API response
<span className="displayed-title-name">{userTitles.find(t => t.is_equipped).name}</span>
(() => {
const equippedTitle = userTitles.find(t => t.is_equipped);
return (
<span
className="displayed-title-name title-with-tooltip"
onMouseEnter={(e) => {
const tooltip = e.currentTarget.querySelector('.title-tooltip');
if (tooltip) {
const rect = e.currentTarget.getBoundingClientRect();
tooltip.style.top = `${rect.bottom + 8}px`;
tooltip.style.left = `${rect.left}px`;
}
}}
>
{equippedTitle.name}
{equippedTitle.description && (
<span className="title-tooltip">{equippedTitle.description}</span>
)}
</span>
);
})()
) : (
// Display message if no title is equipped
<span className="no-title-display">User has no title selected</span>
Expand Down