Add forced refresh button to DM list and update UI styles

- Add a refresh button to `ConversationList` header.
- Make DM sidebar background transparent.
- Update DM settings gear icon to match `VideoCard` style.
- Wire up refresh action in `ProfileModalController` to force-fetch messages.
This commit is contained in:
google-labs-jules[bot] committed 2026-01-23 14:04:55 +00:00
1 parent 2029ba6272
commit 145796c5e0
6 files changed
+1954 -1443

No files matched your search

+4 -1
View File
@@ -134,6 +134,7 @@ export class AppShell {
onMarkAllRead,
onToggleReadReceipts,
onToggleTypingIndicators,
onRefreshConversations,
onBack,
} = {}) {
if (!doc) {
@@ -162,6 +163,7 @@ export class AppShell {
);
const sidebar = createElement(doc, "aside", "dm-app-shell__sidebar");
sidebar.style.background = "transparent";
const sidebarHeader = createElement(doc, "div", "dm-app-shell__sidebar-header flex items-center justify-between p-4 relative");
const sidebarTitle = createElement(
doc,
@@ -172,7 +174,7 @@ export class AppShell {
sidebarHeader.appendChild(sidebarTitle);
const settingsBtn = createElement(doc, "button", "btn-ghost btn-icon");
settingsBtn.innerHTML = `<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="3"></circle><path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1 0 2.83 2 2 0 0 1-2.83 0l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-2 2 2 2 0 0 1-2-2v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 0 1-2.83 0 2 2 0 0 1 0-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1-2-2 2 2 0 0 1 2-2h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 0-2.83 2 2 0 0 1 2.83 0l.06.06a1.65 1.65 0 0 0 1.82.33H9a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 2-2 2 2 0 0 1 2 2v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 0 2 2 0 0 1 0 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82V9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 2 2 2 2 0 0 1-2 2h-.09a1.65 1.65 0 0 0-1.51 1z"></path></svg>`;
settingsBtn.innerHTML = `<svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="0" stroke-linecap="round" stroke-linejoin="round"><path d="M24,13.616L24,10.384C22.349,9.797 21.306,9.632 20.781,8.365L20.781,8.364C20.254,7.093 20.881,6.23 21.628,4.657L19.343,2.372C17.782,3.114 16.91,3.747 15.636,3.219L15.635,3.219C14.366,2.693 14.2,1.643 13.616,0L10.384,0C9.802,1.635 9.635,2.692 8.365,3.219L8.364,3.219C7.093,3.747 6.232,3.121 4.657,2.372L2.372,4.657C3.117,6.225 3.747,7.091 3.219,8.364C2.692,9.635 1.635,9.802 0,10.384L0,13.616C1.632,14.196 2.692,14.365 3.219,15.635C3.749,16.917 3.105,17.801 2.372,19.342L4.657,21.628C6.219,20.885 7.091,20.253 8.364,20.781L8.365,20.781C9.635,21.307 9.801,22.36 10.384,24L13.616,24C14.198,22.364 14.366,21.31 15.643,20.778L15.644,20.778C16.906,20.254 17.764,20.879 19.342,21.629L21.627,19.343C20.883,17.78 20.252,16.91 20.779,15.637C21.306,14.366 22.367,14.197 24,13.616ZM12,16C9.791,16 8,14.209 8,12C8,9.791 9.791,8 12,8C14.209,8 16,9.791 16,12C16,14.209 14.209,16 12,16Z" fill="currentColor" fill-rule="evenodd" clip-rule="evenodd"></path></svg>`;
settingsBtn.ariaLabel = "Direct message settings";
settingsBtn.addEventListener("click", (e) => {
e.stopPropagation();
@@ -210,6 +212,7 @@ export class AppShell {
state: conversationState,
onSelect: onSelectConversation,
onMarkAllRead,
onRefresh: onRefreshConversations,
}),
);
+11
View File
@@ -22,6 +22,7 @@ export function ConversationList({
state = "idle",
onSelect,
onMarkAllRead,
onRefresh,
} = {}) {
if (!doc) {
throw new Error("ConversationList requires a document reference.");
@@ -32,6 +33,16 @@ export function ConversationList({
// We removed the redundant "Messages" title here.
// If we need spacing/alignment for the button, justify-end in CSS handles it.
if (typeof onRefresh === "function") {
const refreshBtn = createElement(doc, "button", "btn-ghost btn-icon");
refreshBtn.type = "button";
refreshBtn.dataset.size = "sm";
refreshBtn.ariaLabel = "Refresh conversations";
refreshBtn.innerHTML = `<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 12a9 9 0 0 0-9-9 9.75 9.75 0 0 0-6.74 2.74L3 8"></path><path d="M3 3v5h5"></path><path d="M3 12a9 9 0 0 0 9 9 9.75 9.75 0 0 0 6.74-2.74L21 16"></path><path d="M16 21h5v-5"></path></svg>`;
refreshBtn.addEventListener("click", onRefresh);
header.appendChild(refreshBtn);
}
if (typeof onMarkAllRead === "function") {
const markAllButton = createElement(
doc,
+3
View File
@@ -4442,6 +4442,9 @@ export class ProfileModalController {
onSelectConversation: (conversation) => {
void this.handleDmConversationSelect(conversation);
},
onRefreshConversations: () => {
this.populateProfileMessages({ force: true });
},
onBack: () => {
this.dmMobileView = "list";
void this.renderDmAppShell(this.directMessagesCache, {
+1936 -1391
View File
File diff suppressed because it is too large. Load diff
Binary file not shown.

After

Width:  |  Height:  |  Size: 136 KiB

-51
View File
@@ -1,51 +0,0 @@
from playwright.sync_api import sync_playwright
def verify_profile_messages():
with sync_playwright() as p:
browser = p.chromium.launch(headless=True)
page = browser.new_page()
page.goto("http://localhost:8000")
# 1. Close disclaimer modal if present
# The logs say #disclaimerModal intercepts events.
try:
page.wait_for_selector("#closeDisclaimerModal", timeout=5000)
page.click("#closeDisclaimerModal")
except:
print("Disclaimer modal not found or not visible")
# Also could be #disclaimerAgreeBtn
try:
page.wait_for_selector("#disclaimerAgreeBtn", timeout=2000)
page.click("#disclaimerAgreeBtn")
except:
pass
# 2. Open Profile Modal via JS
page.evaluate("""
const modal = document.getElementById('profileModal');
if (modal) {
modal.classList.remove('hidden');
modal.setAttribute('aria-hidden', 'false');
document.body.classList.add('modal-open');
// Ensure profile modal is on top if multiple modals
modal.style.zIndex = '9999';
}
""")
# 3. Click Messages tab
# Wait for animation/visibility
page.wait_for_timeout(500)
page.click("#profileNavMessages")
# 4. Wait for AppShell
page.wait_for_selector("#dmAppShellMount")
page.wait_for_timeout(2000)
# 5. Take screenshot
page.screenshot(path="verification_profile_messages.png")
browser.close()
if __name__ == "__main__":
verify_profile_messages()