mirror of
https://github.com/jkingsman/Remote-Terminal-for-MeshCore.git
synced 2026-03-28 17:43:05 +01:00
Mark all as read
This commit is contained in:
2
frontend/dist/index.html
vendored
2
frontend/dist/index.html
vendored
@@ -4,7 +4,7 @@
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>RemoteTerm for MeshCore</title>
|
||||
<script type="module" crossorigin src="/assets/index-Bjui8xah.js"></script>
|
||||
<script type="module" crossorigin src="/assets/index-D9RuHvp1.js"></script>
|
||||
<link rel="stylesheet" crossorigin href="/assets/index-RWG6EjFU.css">
|
||||
</head>
|
||||
<body>
|
||||
|
||||
@@ -515,6 +515,28 @@ export function App() {
|
||||
setSidebarOpen(false);
|
||||
}, []);
|
||||
|
||||
// Mark all conversations as read
|
||||
const handleMarkAllRead = useCallback(() => {
|
||||
const now = Math.floor(Date.now() / 1000);
|
||||
|
||||
// Update localStorage for all channels
|
||||
for (const channel of channels) {
|
||||
const key = getStateKey('channel', channel.key);
|
||||
setLastReadTime(key, now);
|
||||
}
|
||||
|
||||
// Update localStorage for all contacts
|
||||
for (const contact of contacts) {
|
||||
if (contact.public_key) {
|
||||
const key = getStateKey('contact', contact.public_key);
|
||||
setLastReadTime(key, now);
|
||||
}
|
||||
}
|
||||
|
||||
// Clear all unread counts
|
||||
setUnreadCounts({});
|
||||
}, [channels, contacts]);
|
||||
|
||||
// Delete channel handler
|
||||
const handleDeleteChannel = useCallback(async (key: string) => {
|
||||
if (!confirm('Delete this channel? Message history will be preserved.')) return;
|
||||
@@ -640,6 +662,7 @@ export function App() {
|
||||
showCracker={showCracker}
|
||||
crackerRunning={crackerRunning}
|
||||
onToggleCracker={() => setShowCracker((prev) => !prev)}
|
||||
onMarkAllRead={handleMarkAllRead}
|
||||
/>
|
||||
);
|
||||
|
||||
|
||||
@@ -21,15 +21,16 @@ interface SidebarProps {
|
||||
showCracker: boolean;
|
||||
crackerRunning: boolean;
|
||||
onToggleCracker: () => void;
|
||||
onMarkAllRead: () => void;
|
||||
}
|
||||
|
||||
// Load sort preference from localStorage
|
||||
// Load sort preference from localStorage (default to 'recent')
|
||||
function loadSortOrder(): SortOrder {
|
||||
try {
|
||||
const stored = localStorage.getItem('remoteterm-sortOrder');
|
||||
return stored === 'recent' ? 'recent' : 'alpha';
|
||||
return stored === 'alpha' ? 'alpha' : 'recent';
|
||||
} catch {
|
||||
return 'alpha';
|
||||
return 'recent';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -53,6 +54,7 @@ export function Sidebar({
|
||||
showCracker,
|
||||
crackerRunning,
|
||||
onToggleCracker,
|
||||
onMarkAllRead,
|
||||
}: SidebarProps) {
|
||||
const [sortOrder, setSortOrder] = useState<SortOrder>(loadSortOrder);
|
||||
const [searchQuery, setSearchQuery] = useState('');
|
||||
@@ -247,6 +249,17 @@ export function Sidebar({
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Mark All Read */}
|
||||
{!query && Object.keys(unreadCounts).length > 0 && (
|
||||
<div
|
||||
className="px-3 py-2.5 cursor-pointer flex items-center gap-2 border-l-2 border-transparent hover:bg-accent"
|
||||
onClick={onMarkAllRead}
|
||||
>
|
||||
<span className="text-muted-foreground text-xs">✓</span>
|
||||
<span className="flex-1 truncate text-muted-foreground">Mark all as read</span>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Channels */}
|
||||
{filteredChannels.length > 0 && (
|
||||
<>
|
||||
|
||||
Reference in New Issue
Block a user