Changeset 0.37.19 (#232)

Co-authored-by: gobha <jasafpro@gmail.com>
Co-committed-by: gobha <jasafpro@gmail.com>
This commit is contained in:
2026-03-25 00:26:44 +00:00
committed by xcaliber
parent 54ceeb4299
commit be67feaa8e
21 changed files with 173 additions and 88 deletions

View File

@@ -172,7 +172,7 @@ function ChatDashboard({ onNewChat, onCreateChannel, items, onNavigate }) {
const _onDmSelect = useCallback((user) => {
setShowDmPicker(false);
const name = user.display_name || user.username;
onCreateChannel('dm', 'DM: ' + name, { participant: user.username || user.id });
onCreateChannel('dm', 'DM: ' + name, { participant: user.id });
}, [onCreateChannel]);
return html`
@@ -186,14 +186,16 @@ function ChatDashboard({ onNewChat, onCreateChannel, items, onNavigate }) {
<span class="sw-chat-dashboard__card-icon">\u{1F4AC}</span>
<span class="sw-chat-dashboard__card-label">New AI Chat</span>
</button>
${sw.can('channel.create') && html`
<button class="sw-chat-dashboard__card" onClick=${() => _create('channel')}>
<span class="sw-chat-dashboard__card-icon">#</span>
<span class="sw-chat-dashboard__card-label">New Channel</span>
</button>
</button>`}
${sw.can('channel.create') && html`
<button class="sw-chat-dashboard__card" onClick=${() => _create('group')}>
<span class="sw-chat-dashboard__card-icon">\u{1F465}</span>
<span class="sw-chat-dashboard__card-label">New Group</span>
</button>
</button>`}
<button class="sw-chat-dashboard__card" onClick=${() => _create('dm')}>
<span class="sw-chat-dashboard__card-icon">\u{1F4E8}</span>
<span class="sw-chat-dashboard__card-label">Direct Message</span>

View File

@@ -82,7 +82,7 @@ export function SidebarItems({
const _openMenu = useCallback((e, type, item) => {
e.preventDefault();
e.stopPropagation();
const scale = _getScale();
const scale = sw.shell.getScale();
// The dots button may be display:none (zero rect) — fall back to parent
let rect = e.currentTarget.getBoundingClientRect();
if (!rect.width && !rect.height) {
@@ -97,7 +97,7 @@ export function SidebarItems({
const _bodyContextMenu = useCallback((e) => {
if (e.target.closest('.sw-chat-surface__item') || e.target.closest('.sw-chat-surface__folder-header')) return;
e.preventDefault();
const scale = _getScale();
const scale = sw.shell.getScale();
setContextMenu({ type: 'body', item: null, x: e.clientX / scale, y: e.clientY / scale });
}, []);
@@ -356,16 +356,6 @@ function ChannelItem({ channel, activeId, onSelect, onOpenMenu, onDragStart, ind
</button>`;
}
// Read the CSS scale transform on .surface-inner (set by appearance zoom).
// Context menus use position:fixed which breaks under transforms,
// so we divide getBoundingClientRect values by scale to compensate.
function _getScale() {
const el = document.getElementById('surfaceInner');
if (!el) return 1;
const t = getComputedStyle(el).transform;
if (!t || t === 'none') return 1;
const m = t.match(/matrix\(([^,]+)/);
return m ? parseFloat(m[1]) || 1 : 1;
}
// Scale detection moved to sw.shell.getScale() in v0.37.19 (CR P3-3).
// Folder count = direct children only (subfolders + channels in this folder).

View File

@@ -6,6 +6,7 @@
import { SidebarItems } from './sidebar-chats.js';
import { UserMenu } from '../../shell/user-menu.js';
import { UserPicker } from '../../primitives/user-picker.js';
const html = window.html;
const { useState, useCallback, useRef, useEffect } = window.hooks;
@@ -50,6 +51,7 @@ const FOLDER_PLUS_SVG = html`
*/
export function Sidebar({ sidebar, activeId, onSelect, onNewChat, onCreateChannel, onDeleteChat, onCollapse }) {
const [newMenuOpen, setNewMenuOpen] = useState(false);
const [showDmPicker, setShowDmPicker] = useState(false);
const newMenuRef = useRef(null);
const _onSearch = useCallback((e) => {
@@ -82,14 +84,19 @@ export function Sidebar({ sidebar, activeId, onSelect, onNewChat, onCreateChanne
if (type === 'direct') {
onNewChat();
} else if (type === 'dm') {
const who = await window.sw.prompt('Username to DM:', '');
if (who && who.trim()) onCreateChannel('dm', 'DM: ' + who.trim(), { participant: who.trim() });
setShowDmPicker(true);
} else {
const name = await window.sw.prompt((type === 'channel' ? 'Channel' : 'Group') + ' name:', '');
if (name && name.trim()) onCreateChannel(type, name.trim());
}
}, [onNewChat, onCreateChannel]);
const _onDmSelect = useCallback((user) => {
setShowDmPicker(false);
const name = user.display_name || user.username;
onCreateChannel('dm', 'DM: ' + name, { participant: user.id });
}, [onCreateChannel]);
return html`
<div class="sw-chat-surface__sidebar" role="navigation" aria-label="Chat sidebar">
${/* Header: new chat + collapse */''}
@@ -107,12 +114,12 @@ export function Sidebar({ sidebar, activeId, onSelect, onNewChat, onCreateChanne
<button onClick=${() => _newChannel('direct')}>
<span class="sw-chat-surface__new-menu-icon">\u{1F4AC}</span> AI Chat
</button>
<button onClick=${() => _newChannel('channel')}>
${sw.can('channel.create') && html`<button onClick=${() => _newChannel('channel')}>
<span class="sw-chat-surface__new-menu-icon">#</span> Channel
</button>
<button onClick=${() => _newChannel('group')}>
</button>`}
${sw.can('channel.create') && html`<button onClick=${() => _newChannel('group')}>
<span class="sw-chat-surface__new-menu-icon">\u{1F465}</span> Group
</button>
</button>`}
<button onClick=${() => _newChannel('dm')}>
<span class="sw-chat-surface__new-menu-icon">\u{1F4E8}</span> Direct Message
</button>
@@ -132,6 +139,17 @@ export function Sidebar({ sidebar, activeId, onSelect, onNewChat, onCreateChanne
</button>
</div>
${showDmPicker && html`
<div style="padding: 6px 8px;">
<${UserPicker}
onSelect=${_onDmSelect}
placeholder="Search for a user\u2026"
autoFocus=${true} />
<button class="btn-small"
style="margin-top: 4px; width: 100%;"
onClick=${() => setShowDmPicker(false)}>Cancel</button>
</div>`}
${/* Search */''}
<div class="sw-chat-surface__search-wrap">
<span class="sw-chat-surface__search-icon">${SEARCH_SVG}</span>