Spaces:
Running
Running
Commit ·
6bad670
1
Parent(s): a99ebea
Add logout menu under the user pill
Browse files- index.html +46 -1
index.html
CHANGED
|
@@ -111,6 +111,7 @@ body {
|
|
| 111 |
}
|
| 112 |
|
| 113 |
.user-pill {
|
|
|
|
| 114 |
display: flex;
|
| 115 |
align-items: center;
|
| 116 |
gap: 8px;
|
|
@@ -120,7 +121,10 @@ body {
|
|
| 120 |
border-radius: 20px;
|
| 121 |
font-size: 13px;
|
| 122 |
color: var(--text-secondary);
|
|
|
|
|
|
|
| 123 |
}
|
|
|
|
| 124 |
|
| 125 |
.user-pill img {
|
| 126 |
width: 24px;
|
|
@@ -128,6 +132,22 @@ body {
|
|
| 128 |
border-radius: 50%;
|
| 129 |
}
|
| 130 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 131 |
.sidebar {
|
| 132 |
background: var(--surface);
|
| 133 |
border-right: 1px solid var(--border);
|
|
@@ -780,9 +800,15 @@ pre {
|
|
| 780 |
<button class="theme-btn" onclick="cycleTheme()" title="Toggle theme" id="theme-btn-app">
|
| 781 |
<svg id="theme-icon-app" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="5"/><path d="M12 1v2M12 21v2M4.22 4.22l1.42 1.42M18.36 18.36l1.42 1.42M1 12h2M21 12h2M4.22 19.78l1.42-1.42M18.36 5.64l1.42-1.42"/></svg>
|
| 782 |
</button>
|
| 783 |
-
<div class="user-pill" id="user-pill">
|
| 784 |
<img id="user-avatar" src="" alt="">
|
| 785 |
<span id="user-name"></span>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 786 |
</div>
|
| 787 |
</div>
|
| 788 |
</div>
|
|
@@ -2257,6 +2283,25 @@ window.login = async function() {
|
|
| 2257 |
window.location.href = await oauthLoginUrl({ scopes: "openid profile read-billing" });
|
| 2258 |
};
|
| 2259 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2260 |
function showApp() {
|
| 2261 |
document.getElementById("landing").style.display = "none";
|
| 2262 |
document.getElementById("app").style.display = "grid";
|
|
|
|
| 111 |
}
|
| 112 |
|
| 113 |
.user-pill {
|
| 114 |
+
position: relative;
|
| 115 |
display: flex;
|
| 116 |
align-items: center;
|
| 117 |
gap: 8px;
|
|
|
|
| 121 |
border-radius: 20px;
|
| 122 |
font-size: 13px;
|
| 123 |
color: var(--text-secondary);
|
| 124 |
+
cursor: pointer;
|
| 125 |
+
transition: all 0.1s;
|
| 126 |
}
|
| 127 |
+
.user-pill:hover { border-color: var(--border-hover); color: var(--text); }
|
| 128 |
|
| 129 |
.user-pill img {
|
| 130 |
width: 24px;
|
|
|
|
| 132 |
border-radius: 50%;
|
| 133 |
}
|
| 134 |
|
| 135 |
+
.user-menu {
|
| 136 |
+
position: absolute; top: calc(100% + 6px); right: 0;
|
| 137 |
+
min-width: 160px; background: var(--surface); border: 1px solid var(--border); border-radius: 10px;
|
| 138 |
+
box-shadow: 0 8px 24px var(--shadow-color); padding: 4px; z-index: 50;
|
| 139 |
+
display: none;
|
| 140 |
+
}
|
| 141 |
+
.user-menu.visible { display: block; }
|
| 142 |
+
.user-menu-item {
|
| 143 |
+
display: flex; align-items: center; gap: 8px; width: 100%;
|
| 144 |
+
padding: 8px 10px; border: none; background: transparent;
|
| 145 |
+
font-family: 'Inter', sans-serif; font-size: 13px; color: var(--text);
|
| 146 |
+
text-align: left; border-radius: 6px; cursor: pointer;
|
| 147 |
+
}
|
| 148 |
+
.user-menu-item:hover { background: var(--surface2); }
|
| 149 |
+
.user-menu-item svg { width: 14px; height: 14px; flex-shrink: 0; }
|
| 150 |
+
|
| 151 |
.sidebar {
|
| 152 |
background: var(--surface);
|
| 153 |
border-right: 1px solid var(--border);
|
|
|
|
| 800 |
<button class="theme-btn" onclick="cycleTheme()" title="Toggle theme" id="theme-btn-app">
|
| 801 |
<svg id="theme-icon-app" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="5"/><path d="M12 1v2M12 21v2M4.22 4.22l1.42 1.42M18.36 18.36l1.42 1.42M1 12h2M21 12h2M4.22 19.78l1.42-1.42M18.36 5.64l1.42-1.42"/></svg>
|
| 802 |
</button>
|
| 803 |
+
<div class="user-pill" id="user-pill" onclick="toggleUserMenu(event)">
|
| 804 |
<img id="user-avatar" src="" alt="">
|
| 805 |
<span id="user-name"></span>
|
| 806 |
+
<div class="user-menu" id="user-menu">
|
| 807 |
+
<button class="user-menu-item" type="button" onclick="event.stopPropagation();logout()">
|
| 808 |
+
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4"/><polyline points="16 17 21 12 16 7"/><line x1="21" y1="12" x2="9" y2="12"/></svg>
|
| 809 |
+
Log out
|
| 810 |
+
</button>
|
| 811 |
+
</div>
|
| 812 |
</div>
|
| 813 |
</div>
|
| 814 |
</div>
|
|
|
|
| 2283 |
window.location.href = await oauthLoginUrl({ scopes: "openid profile read-billing" });
|
| 2284 |
};
|
| 2285 |
|
| 2286 |
+
window.toggleUserMenu = function(e) {
|
| 2287 |
+
e.stopPropagation();
|
| 2288 |
+
document.getElementById("user-menu").classList.toggle("visible");
|
| 2289 |
+
};
|
| 2290 |
+
|
| 2291 |
+
window.logout = function() {
|
| 2292 |
+
sessionStorage.removeItem("zl_token");
|
| 2293 |
+
sessionStorage.removeItem("zl_user");
|
| 2294 |
+
sessionStorage.removeItem("zl_expires");
|
| 2295 |
+
// Clean OAuth params from URL if present, then reload
|
| 2296 |
+
const url = new URL(window.location.href);
|
| 2297 |
+
["code", "state", "oauth_redirect", "id_token", "access_token"].forEach(k => url.searchParams.delete(k));
|
| 2298 |
+
window.location.replace(url.toString().replace(/\?$/, ""));
|
| 2299 |
+
};
|
| 2300 |
+
|
| 2301 |
+
document.addEventListener("click", () => {
|
| 2302 |
+
document.getElementById("user-menu")?.classList.remove("visible");
|
| 2303 |
+
});
|
| 2304 |
+
|
| 2305 |
function showApp() {
|
| 2306 |
document.getElementById("landing").style.display = "none";
|
| 2307 |
document.getElementById("app").style.display = "grid";
|