feat: bookmarks, message scheduling, image compression, room insights
CI / Build & Quality Checks (push) Failing after 5m48s
CI / Build & Quality Checks (push) Failing after 5m48s
P3-1: Message Bookmarks — right-click any message to bookmark; saved to io.lotus.bookmarks account data (max 500, syncs across devices); star icon in sidebar opens BookmarksPanel with filter, Jump-to-message, and remove buttons; reactive to AccountData events P3-2: Message Scheduling (MSC4140) — clock button next to send opens ScheduleMessageModal with datetime-local picker; validates ≥1 min future; calls PUT org.matrix.msc4140 delayed event API; collapsible ScheduledMessagesTray above composer lists pending messages with cancel; local Jotai atom tracks scheduled messages per room P3-3: File Upload Compression — opt-in checkbox per JPEG/PNG file ≥200KB in upload preview; canvas API compresses at 0.82 quality; shows before/ after size estimate; compressed blob used in upload when checked P3-7: Room Insights — new Insights tab in room settings; top 5 active members (bar chart), top 5 reactions (chips), media breakdown (4 tiles), 24-hour activity heatmap (CSS bar chart); all from local cache only with disclaimer banner; never the first tab shown Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1,11 +1,18 @@
|
||||
import React, { ReactNode } from 'react';
|
||||
import { Box } from 'folds';
|
||||
import { Box, Line } from 'folds';
|
||||
import { useAtom } from 'jotai';
|
||||
import { bookmarksPanelAtom } from '../../state/bookmarksPanel';
|
||||
import { BookmarksPanel } from '../../features/bookmarks/BookmarksPanel';
|
||||
import { ScreenSize, useScreenSizeContext } from '../../hooks/useScreenSize';
|
||||
|
||||
type ClientLayoutProps = {
|
||||
nav: ReactNode;
|
||||
children: ReactNode;
|
||||
};
|
||||
export function ClientLayout({ nav, children }: ClientLayoutProps) {
|
||||
const [bookmarksOpen, setBookmarksOpen] = useAtom(bookmarksPanelAtom);
|
||||
const screenSize = useScreenSizeContext();
|
||||
|
||||
return (
|
||||
<>
|
||||
<a
|
||||
@@ -37,6 +44,12 @@ export function ClientLayout({ nav, children }: ClientLayoutProps) {
|
||||
<Box grow="Yes" as="main" id="main-content">
|
||||
{children}
|
||||
</Box>
|
||||
{bookmarksOpen && screenSize === ScreenSize.Desktop && (
|
||||
<>
|
||||
<Line variant="Background" direction="Vertical" size="300" />
|
||||
<BookmarksPanel onClose={() => setBookmarksOpen(false)} />
|
||||
</>
|
||||
)}
|
||||
</Box>
|
||||
</>
|
||||
);
|
||||
|
||||
@@ -16,6 +16,7 @@ import {
|
||||
SettingsTab,
|
||||
UnverifiedTab,
|
||||
SearchTab,
|
||||
BookmarksTab,
|
||||
} from './sidebar';
|
||||
import { CreateTab } from './sidebar/CreateTab';
|
||||
|
||||
@@ -44,6 +45,7 @@ export function SidebarNav() {
|
||||
<SidebarStackSeparator />
|
||||
<SidebarStack>
|
||||
<SearchTab />
|
||||
<BookmarksTab />
|
||||
<UnverifiedTab />
|
||||
<InboxTab />
|
||||
<SettingsTab />
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
import React from 'react';
|
||||
import { Icon, Icons } from 'folds';
|
||||
import { useAtom } from 'jotai';
|
||||
import { SidebarAvatar, SidebarItem, SidebarItemTooltip } from '../../../components/sidebar';
|
||||
import { bookmarksPanelAtom } from '../../../state/bookmarksPanel';
|
||||
|
||||
export function BookmarksTab() {
|
||||
const [opened, setOpen] = useAtom(bookmarksPanelAtom);
|
||||
|
||||
const toggle = () => setOpen((v) => !v);
|
||||
|
||||
return (
|
||||
<SidebarItem active={opened}>
|
||||
<SidebarItemTooltip tooltip="Saved Messages">
|
||||
{(triggerRef) => (
|
||||
<SidebarAvatar as="button" ref={triggerRef} outlined onClick={toggle}>
|
||||
<Icon src={Icons.Star} filled={opened} />
|
||||
</SidebarAvatar>
|
||||
)}
|
||||
</SidebarItemTooltip>
|
||||
</SidebarItem>
|
||||
);
|
||||
}
|
||||
@@ -6,3 +6,4 @@ export * from './ExploreTab';
|
||||
export * from './SettingsTab';
|
||||
export * from './UnverifiedTab';
|
||||
export * from './SearchTab';
|
||||
export * from './BookmarksTab';
|
||||
|
||||
Reference in New Issue
Block a user