Files
cinny/src/app/components/presence/PresenceRingAvatar.tsx
T
Lotus CIandClaude Opus 5.5 00f962a463
CI / Build & Quality Checks (pull_request) Successful in 1m52s
CI / Trigger Desktop Build (pull_request) Skipped
CI / Docker image build & smoke test (pull_request) Skipped
CI / Secret scan (gitleaks) (pull_request) Successful in 8s
CI / Playwright smoke (e2e) (pull_request) Successful in 10m59s
fix(presence): Do Not Disturb is real "busy" presence and keeps your status (#283)
DND was sent as presence unavailable with the literal status text
"dnd": it replaced your status, and other clients showed "dnd". Where
the server supports MSC3026 (busy_presence), DND now sends presence
org.matrix.msc3026.busy and leaves the status alone (Synapse keeps
busy across /sync set_presence=online). Busy renders as red "Do Not
Disturb" with the real status line; the legacy unavailable + "dnd"
encoding is still recognised and still used on servers without it.
Status saves / clears no longer downgrade busy. The SDK rejects
non-spec presences, so busy goes through a direct authed PUT.

Fixes #283

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017PCb59uY3UKqDqt7B6hzd5
2026-10-19 01:04:27 -04:00

36 lines
1.3 KiB
TypeScript

import React, { CSSProperties } from 'react';
import { color } from 'folds';
import { Presence, useUserPresence } from '../../hooks/useUserPresence';
function presenceRingColor(presence: Presence | undefined, status?: string): string | null {
if (!presence || presence === Presence.Offline) return null;
if (presence === Presence.Busy) return color.Critical.Main; // [Gitea #283] DND
if (presence === Presence.Unavailable) {
return status === 'dnd' ? color.Critical.Main : color.Warning.Main;
}
return color.Success.Main;
}
type PresenceRingAvatarProps = {
userId: string;
children: React.ReactElement<{ style?: CSSProperties }>;
};
export function PresenceRingAvatar({ userId, children }: PresenceRingAvatarProps) {
const presence = useUserPresence(userId);
const ringColor = presenceRingColor(presence?.presence, presence?.status);
if (!ringColor) return <>{children}</>;
// Apply outline directly to the child so it follows the child's actual border-radius.
// outline follows border-radius in Chrome 94+, Firefox 88+, Safari 16.4+.
// This avoids the mismatch of a circular wrapper around a rounded-square avatar.
return React.cloneElement(children, {
style: {
...children.props.style,
outline: `2px solid ${ringColor}`,
outlineOffset: '2px',
},
});
}