mirror of
https://github.com/block/buzz.git
synced 2026-11-07 18:01:06 +00:00
Polish desktop Pulse and Home views (#764)
Signed-off-by: Wes <wesbillman@users.noreply.github.com>
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
import type {
|
||||
ContactListResponse,
|
||||
NoteReactionSummary,
|
||||
PublishNoteResult,
|
||||
UserNote,
|
||||
UserNotesResponse,
|
||||
@@ -12,6 +13,14 @@ type RawUserNote = {
|
||||
pubkey: string;
|
||||
created_at: number;
|
||||
content: string;
|
||||
tags: string[][];
|
||||
};
|
||||
|
||||
type RawNoteReactionSummary = {
|
||||
note_id: string;
|
||||
emoji: string;
|
||||
count: number;
|
||||
pubkeys: string[];
|
||||
};
|
||||
|
||||
type RawUserNotesCursor = {
|
||||
@@ -38,9 +47,32 @@ function fromRawUserNote(note: RawUserNote): UserNote {
|
||||
pubkey: note.pubkey,
|
||||
createdAt: note.created_at,
|
||||
content: note.content,
|
||||
tags: note.tags,
|
||||
};
|
||||
}
|
||||
|
||||
export async function getNoteReactions(
|
||||
noteIds: string[],
|
||||
): Promise<NoteReactionSummary[]> {
|
||||
const response = await invokeTauri<RawNoteReactionSummary[]>(
|
||||
"get_note_reactions",
|
||||
{ noteIds },
|
||||
);
|
||||
return response.map((summary) => ({
|
||||
noteId: summary.note_id,
|
||||
emoji: summary.emoji,
|
||||
count: summary.count,
|
||||
pubkeys: summary.pubkeys,
|
||||
}));
|
||||
}
|
||||
|
||||
export async function getNote(noteId: string): Promise<UserNote | null> {
|
||||
const response = await invokeTauri<RawUserNote | null>("get_note", {
|
||||
noteId,
|
||||
});
|
||||
return response ? fromRawUserNote(response) : null;
|
||||
}
|
||||
|
||||
export async function getUserNotes(
|
||||
pubkey: string,
|
||||
options?: {
|
||||
@@ -137,6 +169,48 @@ export async function setContactList(
|
||||
};
|
||||
}
|
||||
|
||||
export async function getLikedNotes(
|
||||
authorPubkey: string,
|
||||
limit?: number,
|
||||
): Promise<UserNotesResponse> {
|
||||
const response = await invokeTauri<RawUserNotesResponse>("get_liked_notes", {
|
||||
authorPubkey,
|
||||
limit: limit ?? null,
|
||||
});
|
||||
|
||||
return {
|
||||
notes: response.notes.map(fromRawUserNote),
|
||||
nextCursor: response.next_cursor
|
||||
? {
|
||||
before: response.next_cursor.before,
|
||||
beforeId: response.next_cursor.before_id,
|
||||
}
|
||||
: null,
|
||||
};
|
||||
}
|
||||
|
||||
export async function getGlobalNotes(options?: {
|
||||
limit?: number;
|
||||
before?: number;
|
||||
beforeId?: string;
|
||||
}): Promise<UserNotesResponse> {
|
||||
const response = await invokeTauri<RawUserNotesResponse>("get_global_notes", {
|
||||
limit: options?.limit ?? null,
|
||||
before: options?.before ?? null,
|
||||
beforeId: options?.beforeId ?? null,
|
||||
});
|
||||
|
||||
return {
|
||||
notes: response.notes.map(fromRawUserNote),
|
||||
nextCursor: response.next_cursor
|
||||
? {
|
||||
before: response.next_cursor.before,
|
||||
beforeId: response.next_cursor.before_id,
|
||||
}
|
||||
: null,
|
||||
};
|
||||
}
|
||||
|
||||
export async function getNotesTimeline(
|
||||
pubkeys: string[],
|
||||
limitPerUser?: number,
|
||||
|
||||
@@ -3,6 +3,14 @@ export type UserNote = {
|
||||
pubkey: string;
|
||||
createdAt: number;
|
||||
content: string;
|
||||
tags: string[][];
|
||||
};
|
||||
|
||||
export type NoteReactionSummary = {
|
||||
noteId: string;
|
||||
emoji: string;
|
||||
count: number;
|
||||
pubkeys: string[];
|
||||
};
|
||||
|
||||
export type UserNotesCursor = {
|
||||
|
||||
97
desktop/src/shared/hooks/useThreadPanelWidth.ts
Normal file
97
desktop/src/shared/hooks/useThreadPanelWidth.ts
Normal file
@@ -0,0 +1,97 @@
|
||||
import * as React from "react";
|
||||
|
||||
const THREAD_PANEL_DEFAULT_WIDTH_PX = 380;
|
||||
const THREAD_PANEL_MIN_WIDTH_PX = 320;
|
||||
const THREAD_PANEL_MAX_WIDTH_PX = 720;
|
||||
const THREAD_PANEL_WIDTH_SESSION_KEY = "sprout.desktop.thread-panel-width";
|
||||
|
||||
function clampThreadPanelWidth(width: number): number {
|
||||
return Math.max(
|
||||
THREAD_PANEL_MIN_WIDTH_PX,
|
||||
Math.min(THREAD_PANEL_MAX_WIDTH_PX, width),
|
||||
);
|
||||
}
|
||||
|
||||
function getInitialThreadPanelWidth(): number {
|
||||
if (typeof window === "undefined") {
|
||||
return THREAD_PANEL_DEFAULT_WIDTH_PX;
|
||||
}
|
||||
|
||||
try {
|
||||
const raw = window.sessionStorage.getItem(THREAD_PANEL_WIDTH_SESSION_KEY);
|
||||
if (!raw) {
|
||||
return THREAD_PANEL_DEFAULT_WIDTH_PX;
|
||||
}
|
||||
|
||||
const parsed = Number.parseInt(raw, 10);
|
||||
if (!Number.isFinite(parsed)) {
|
||||
return THREAD_PANEL_DEFAULT_WIDTH_PX;
|
||||
}
|
||||
|
||||
return clampThreadPanelWidth(parsed);
|
||||
} catch {
|
||||
return THREAD_PANEL_DEFAULT_WIDTH_PX;
|
||||
}
|
||||
}
|
||||
|
||||
export function useThreadPanelWidth() {
|
||||
const [widthPx, setWidthPx] = React.useState<number>(() =>
|
||||
getInitialThreadPanelWidth(),
|
||||
);
|
||||
|
||||
React.useEffect(() => {
|
||||
if (typeof window === "undefined") {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
window.sessionStorage.setItem(
|
||||
THREAD_PANEL_WIDTH_SESSION_KEY,
|
||||
String(widthPx),
|
||||
);
|
||||
} catch {
|
||||
// Ignore storage failures and keep in-memory width for this session.
|
||||
}
|
||||
}, [widthPx]);
|
||||
|
||||
const onResizeStart = React.useCallback(
|
||||
(event: React.PointerEvent<HTMLButtonElement>) => {
|
||||
event.preventDefault();
|
||||
|
||||
const startX = event.clientX;
|
||||
const startWidth = widthPx;
|
||||
const previousCursor = document.body.style.cursor;
|
||||
const previousUserSelect = document.body.style.userSelect;
|
||||
|
||||
document.body.style.cursor = "col-resize";
|
||||
document.body.style.userSelect = "none";
|
||||
|
||||
const handlePointerMove = (moveEvent: PointerEvent) => {
|
||||
const deltaX = startX - moveEvent.clientX;
|
||||
const nextWidth = clampThreadPanelWidth(startWidth + deltaX);
|
||||
setWidthPx(nextWidth);
|
||||
};
|
||||
|
||||
const handlePointerUp = () => {
|
||||
document.body.style.cursor = previousCursor;
|
||||
document.body.style.userSelect = previousUserSelect;
|
||||
window.removeEventListener("pointermove", handlePointerMove);
|
||||
};
|
||||
|
||||
window.addEventListener("pointermove", handlePointerMove);
|
||||
window.addEventListener("pointerup", handlePointerUp, { once: true });
|
||||
},
|
||||
[widthPx],
|
||||
);
|
||||
|
||||
const onResetWidth = React.useCallback(() => {
|
||||
setWidthPx(THREAD_PANEL_DEFAULT_WIDTH_PX);
|
||||
}, []);
|
||||
|
||||
return {
|
||||
canReset: widthPx !== THREAD_PANEL_DEFAULT_WIDTH_PX,
|
||||
onResetWidth,
|
||||
onResizeStart,
|
||||
widthPx,
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user