mirror of
https://github.com/block/buzz.git
synced 2026-10-29 05:21:31 +00:00
feat(desktop): preview panel merge edge
Signed-off-by: cynfria <yescynthia@gmail.com>
This commit is contained in:
@@ -1025,8 +1025,32 @@ function MessagesView() {
|
||||
y: number;
|
||||
connectedAtStart: boolean;
|
||||
hasBroken: boolean;
|
||||
previewCell: HTMLElement | null;
|
||||
previewEdge: MessagePanelEdge | null;
|
||||
} | null>(null);
|
||||
|
||||
const clearMergePreview = (drag: NonNullable<typeof dragRef.current>) => {
|
||||
if (drag.previewCell && drag.previewEdge) {
|
||||
drag.previewCell.classList.remove(`merge-preview-${drag.previewEdge}`);
|
||||
}
|
||||
drag.previewCell = null;
|
||||
drag.previewEdge = null;
|
||||
};
|
||||
|
||||
const updateMergePreview = (
|
||||
drag: NonNullable<typeof dragRef.current>,
|
||||
snap: ReturnType<typeof findSnapTarget>,
|
||||
) => {
|
||||
if (snap && drag.previewCell?.dataset.panelId === snap.target && drag.previewEdge === snap.edge) return;
|
||||
clearMergePreview(drag);
|
||||
if (!snap) return;
|
||||
const targetCell = boardRef.current?.querySelector<HTMLElement>(`[data-panel-id="${snap.target}"]`);
|
||||
if (!targetCell) return;
|
||||
targetCell.classList.add(`merge-preview-${snap.edge}`);
|
||||
drag.previewCell = targetCell;
|
||||
drag.previewEdge = snap.edge;
|
||||
};
|
||||
|
||||
const isPanelConnected = (id: MessagePanelId) =>
|
||||
connections.some((connection) => connection.a === id || connection.b === id);
|
||||
|
||||
@@ -1149,6 +1173,8 @@ function MessagesView() {
|
||||
y: current.y,
|
||||
connectedAtStart,
|
||||
hasBroken: false,
|
||||
previewCell: null,
|
||||
previewEdge: null,
|
||||
};
|
||||
cell.classList.add("is-pulling", "is-active-drag");
|
||||
};
|
||||
@@ -1173,6 +1199,10 @@ function MessagesView() {
|
||||
drag.cell.style.setProperty("--panel-y", `${drag.y}px`);
|
||||
drag.cell.style.setProperty("--panel-tilt", `${Math.max(-1.2, Math.min(1.2, (event.clientX - drag.startX) * 0.012))}deg`);
|
||||
drag.cell.classList.toggle("is-breaking", drag.hasBroken);
|
||||
updateMergePreview(
|
||||
drag,
|
||||
drag.connectedAtStart && !drag.hasBroken ? null : findSnapTarget(drag.id, drag.x, drag.y),
|
||||
);
|
||||
};
|
||||
|
||||
const endPanelDrag = (event: ReactPointerEvent<HTMLElement>) => {
|
||||
@@ -1186,6 +1216,7 @@ function MessagesView() {
|
||||
? connections
|
||||
: connections.filter((connection) => connection.a !== drag.id && connection.b !== drag.id);
|
||||
const snap = stayedConnected ? null : findSnapTarget(drag.id, drag.x, drag.y);
|
||||
clearMergePreview(drag);
|
||||
const next = stayedConnected
|
||||
? { x: drag.originX, y: drag.originY }
|
||||
: snap
|
||||
@@ -1223,6 +1254,7 @@ function MessagesView() {
|
||||
<div ref={boardRef} className="messages-board">
|
||||
<div data-panel-id="sidebar" className={`message-panel-cell sidebar-cell${isPanelConnected("sidebar") ? "" : " is-detached"}`} style={panelStyle("sidebar")}>
|
||||
<aside className="message-panel channel-panel">
|
||||
<span className="merge-edge-indicator" aria-hidden="true" />
|
||||
<div className="panel-drag-handle channel-search-wrap" {...dragHandlers("sidebar")}>
|
||||
<Search aria-hidden="true" size={18} strokeWidth={1.7} />
|
||||
<input aria-label="Search channels" placeholder="Search" />
|
||||
@@ -1240,6 +1272,7 @@ function MessagesView() {
|
||||
|
||||
<div data-panel-id="chat" className={`message-panel-cell chat-cell${isPanelConnected("chat") ? "" : " is-detached"}`} style={panelStyle("chat")}>
|
||||
<article className="message-panel chat-panel">
|
||||
<span className="merge-edge-indicator" aria-hidden="true" />
|
||||
<header className="panel-drag-handle chat-header" {...dragHandlers("chat")}>
|
||||
<div><LockKeyhole aria-hidden="true" size={18} strokeWidth={1.7} /><strong>buzz-interface-squad</strong></div>
|
||||
<div className="chat-header-actions"><button type="button" aria-label="Channel privacy"><LockKeyhole aria-hidden="true" size={18} strokeWidth={1.7} /></button><button type="button" aria-label="Members"><Users aria-hidden="true" size={18} strokeWidth={1.7} /><span>13</span></button><button type="button" aria-label="Huddle"><Headphones aria-hidden="true" size={18} strokeWidth={1.7} /></button><button type="button" aria-label="More"><MoreVertical aria-hidden="true" size={18} strokeWidth={1.7} /></button></div>
|
||||
@@ -1255,6 +1288,7 @@ function MessagesView() {
|
||||
|
||||
<div data-panel-id="thread" className={`message-panel-cell thread-cell${isPanelConnected("thread") ? "" : " is-detached"}`} style={panelStyle("thread")}>
|
||||
<aside className="message-panel thread-panel">
|
||||
<span className="merge-edge-indicator" aria-hidden="true" />
|
||||
<header className="panel-drag-handle thread-header" {...dragHandlers("thread")}><div><PanelRightOpen aria-hidden="true" size={18} strokeWidth={1.7} /><strong>Thread</strong></div><button type="button" aria-label="Close thread"><X aria-hidden="true" size={18} strokeWidth={1.7} /></button></header>
|
||||
<div className="thread-content">
|
||||
<div className="thread-message"><img src="/berd-agent-avatars/pushback-gloopies-5.png" alt="" /><div><p><strong>Caroline McKenzie</strong><span>Yesterday at 7:05PM</span></p><div>Brought copy link out of the context menu and into the main message rail. Also tried simplifying by removing quick reactions but can put them back later if people really miss them.</div></div></div>
|
||||
|
||||
@@ -198,6 +198,32 @@ body { background: #e6f2f5; color: var(--ink); font-family: Inter, ui-sans-serif
|
||||
.message-panel-cell.is-pulling { --panel-scale: .997; }
|
||||
.message-panel-cell.is-pulling.is-breaking { --panel-scale: 1; }
|
||||
.message-panel-cell.is-pulling .message-panel { transition: border-radius 180ms ease-out, box-shadow 180ms ease-out; }
|
||||
.merge-edge-indicator {
|
||||
position: absolute;
|
||||
z-index: 20;
|
||||
pointer-events: none;
|
||||
background: rgba(0, 112, 255, .4);
|
||||
opacity: 0;
|
||||
transition: opacity 80ms ease-out;
|
||||
}
|
||||
.merge-preview-left .merge-edge-indicator,
|
||||
.merge-preview-right .merge-edge-indicator {
|
||||
top: 18px;
|
||||
bottom: 18px;
|
||||
width: 2px;
|
||||
opacity: 1;
|
||||
}
|
||||
.merge-preview-left .merge-edge-indicator { left: 0; }
|
||||
.merge-preview-right .merge-edge-indicator { right: 0; }
|
||||
.merge-preview-top .merge-edge-indicator,
|
||||
.merge-preview-bottom .merge-edge-indicator {
|
||||
right: 18px;
|
||||
left: 18px;
|
||||
height: 2px;
|
||||
opacity: 1;
|
||||
}
|
||||
.merge-preview-top .merge-edge-indicator { top: 0; }
|
||||
.merge-preview-bottom .merge-edge-indicator { bottom: 0; }
|
||||
.panel-drag-handle { cursor: grab; touch-action: none; user-select: none; }
|
||||
.message-panel-cell.is-pulling .panel-drag-handle { cursor: grabbing; }
|
||||
.channel-panel { padding: 10px; }
|
||||
@@ -437,6 +463,7 @@ body { background: #e6f2f5; color: var(--ink); font-family: Inter, ui-sans-serif
|
||||
.wrapped-labels { will-change: auto; }
|
||||
.orbit-system, .task-detail-panel { transition-duration: 1ms; animation-duration: 1ms; }
|
||||
.message-panel { transition: none; }
|
||||
.merge-edge-indicator { transition: none; }
|
||||
.response-composer { transition: none; }
|
||||
.response-composer textarea { animation: none; }
|
||||
.project-name-pill { transition: none; }
|
||||
|
||||
Reference in New Issue
Block a user