diff --git a/src/models/campaign.py b/src/models/campaign.py
index 4d4dcb4..2c68a9e 100644
--- a/src/models/campaign.py
+++ b/src/models/campaign.py
@@ -28,6 +28,7 @@ class DropsCampaign:
def __init__(self, twitch: Twitch, data: JsonType, claimed_benefits: dict[str, datetime]):
self._twitch: Twitch = twitch
self.id: str = data["id"]
+ self.campaign_url: str = f"https://www.twitch.tv/drops/campaigns?dropID={self.id}"
self.name: str = data["name"]
self.game: Game = Game(data["game"])
self.linked: bool = data["self"]["isAccountConnected"]
diff --git a/src/web/managers/inventory.py b/src/web/managers/inventory.py
index 6856942..1dd86a2 100644
--- a/src/web/managers/inventory.py
+++ b/src/web/managers/inventory.py
@@ -75,7 +75,8 @@ class InventoryManager:
"name": campaign.name,
"game_name": campaign.game.name,
"image_url": image_url,
- "link_url": f"https://www.twitch.tv/drops/campaigns?dropID={campaign.id}",
+ "campaign_url": campaign.campaign_url,
+ "link_url": campaign.link_url,
"starts_at": campaign.starts_at.isoformat(),
"ends_at": campaign.ends_at.isoformat(),
"linked": campaign.linked,
diff --git a/web/static/app.js b/web/static/app.js
index ed9d9cb..4fe7e48 100644
--- a/web/static/app.js
+++ b/web/static/app.js
@@ -800,16 +800,26 @@ function renderInventory() {
`;
}).join('');
- // Make campaign name clickable if link_url is available
- const campaignNameHtml = campaign.link_url
- ? `${campaign.name} 🔗`
- : `
${campaign.name}
`;
+ const campaignNameHtml = `${campaign.name} 🔗`
+
+ // Add LINKED or NOT LINKED badge
+ const linkStatusBadgeHtml = campaign.linked
+ ? `LINKED`
+ : `NOT LINKED`;
+
+ const linkAccountButtonHtml = !campaign.linked && campaign.link_url
+ ? ``
+ : '';
const claimedCountText = t.gui?.inventory?.claimed_drops || 'claimed';
card.innerHTML = `
${statusText}
diff --git a/web/static/styles.css b/web/static/styles.css
index 843f54f..f575dfc 100644
--- a/web/static/styles.css
+++ b/web/static/styles.css
@@ -609,6 +609,7 @@ header h1 {
border-radius: 8px;
overflow: hidden;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
+ position: relative;
}
.campaign-header {
@@ -647,6 +648,63 @@ header h1 {
opacity: 0.7;
}
+.campaign-badge {
+ position: absolute;
+ right: 15px;
+ padding: 4px 10px;
+ border-radius: 4px;
+ font-size: 11px;
+ font-weight: 600;
+ cursor: pointer;
+ transition: all 0.2s;
+ z-index: 10;
+}
+
+.campaign-badge.linked {
+ background: rgba(0, 200, 83, 0.15);
+ color: var(--success-color);
+ border: 1px solid rgba(0, 200, 83, 0.3);
+ cursor: default;
+}
+
+.campaign-badge.not-linked {
+ background: var(--warning-color);
+ color: white;
+ box-shadow: 0 2px 4px rgba(255, 167, 38, 0.3);
+}
+
+.campaign-badge.not-linked:hover {
+ background: #ff9800;
+ transform: translateY(-1px);
+ box-shadow: 0 3px 6px rgba(255, 167, 38, 0.4);
+}
+
+.link-account-btn {
+ margin-top: 8px;
+ padding: 8px 16px;
+ background: var(--warning-color);
+ color: white;
+ border: none;
+ border-radius: 6px;
+ font-size: 13px;
+ font-weight: 600;
+ cursor: pointer;
+ transition: all 0.2s;
+ box-shadow: 0 2px 4px rgba(255, 167, 38, 0.3);
+ width: 100%;
+}
+
+.link-account-btn:hover {
+ background: #ff9800;
+ transform: translateY(-1px);
+ box-shadow: 0 3px 6px rgba(255, 167, 38, 0.4);
+}
+
+.link-account-btn:active {
+ transform: translateY(0);
+ box-shadow: 0 1px 2px rgba(255, 167, 38, 0.3);
+}
+
.campaign-status {
padding: 10px 15px;
font-size: 12px;