diff --git a/client/src/components/Leaderboard.css b/client/src/components/Leaderboard.css
index 0dda857a..f05e2a9b 100644
--- a/client/src/components/Leaderboard.css
+++ b/client/src/components/Leaderboard.css
@@ -59,6 +59,7 @@ h2 {
width: 100%;
flex-grow: 1;
overflow-y: auto;
+ overflow-x: visible;
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);
@@ -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);
+}
+
+.title-with-tooltip:hover .title-tooltip {
+ visibility: visible;
+ opacity: 1;
+}
+
.leaderboard-stats {
display: flex;
gap: 1.5rem;
diff --git a/client/src/components/Leaderboard.jsx b/client/src/components/Leaderboard.jsx
index 46c6b001..94566458 100644
--- a/client/src/components/Leaderboard.jsx
+++ b/client/src/components/Leaderboard.jsx
@@ -425,8 +425,21 @@ function Leaderboard({ defaultDuration = 15, defaultPeriod = 'alltime', layoutMo
const titleToShow = titles?.find(t => t.is_equipped);
return titleToShow ? (
-
+ {
+ 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 && (
+ {titleToShow.description}
+ )}
) : null;
diff --git a/client/src/components/ProfileModal.css b/client/src/components/ProfileModal.css
index a794ee43..1fe205c4 100644
--- a/client/src/components/ProfileModal.css
+++ b/client/src/components/ProfileModal.css
@@ -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;
diff --git a/client/src/components/ProfileModal.jsx b/client/src/components/ProfileModal.jsx
index 6106cd6b..d856e03b 100644
--- a/client/src/components/ProfileModal.jsx
+++ b/client/src/components/ProfileModal.jsx
@@ -757,12 +757,52 @@ function ProfileModal({ isOpen, onClose, netid }) {
{loadingTitles ? (
Loading title...
- ) : 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
- {userTitles.find(t => String(t.id) === String(displayUser.selected_title_id)).name}
- ) : userTitles.find(t => t.is_equipped)?.name ? (
+ (() => {
+ const equippedTitle = userTitles.find(t => String(t.id) === String(displayUser.selected_title_id));
+ return (
+ {
+ 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 && (
+ {equippedTitle.description}
+ )}
+
+ );
+ })()
+ ) : userTitles.find(t => t.is_equipped) ? (
// Alternatively check for is_equipped flag from the API response
- {userTitles.find(t => t.is_equipped).name}
+ (() => {
+ const equippedTitle = userTitles.find(t => t.is_equipped);
+ return (
+ {
+ 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 && (
+ {equippedTitle.description}
+ )}
+
+ );
+ })()
) : (
// Display message if no title is equipped
User has no title selected