Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions desktop/src-tauri/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,13 @@ pub fn run() {
// on macOS/Windows.
linux_media::enable_media_capture(&webview);

#[cfg(target_os = "macos")]
if let Err(error) = webview
.set_background_color(Some(tauri::window::Color(0, 0, 0, 0)))
{
eprintln!("buzz-desktop: failed to make the macOS webview transparent: {error}");
}

// macOS applies the restored geometry asynchronously. Wait
// for several identical outer bounds and for React to
// commit the startup surface before revealing it.
Expand Down
4 changes: 4 additions & 0 deletions desktop/src/app/useTauriWindowDrag.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@ export function useTauriWindowDrag() {
return;
}

// A native window drag replaces the browser's normal pointer gesture.
// Cancel that gesture before handing control to Tauri so moving from the
// titlebar across page copy cannot start a text selection.
event.preventDefault();
void getCurrentWindow().startDragging();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,10 @@ function RelayMemberRow({
<Shield className="h-4 w-4 text-blue-500" />
) : null}
</div>
<div className="flex items-center gap-1.5 text-xs text-muted-foreground">
<div
className="flex items-center gap-1.5 text-xs text-muted-foreground/70"
data-settings-subcopy
>
<span className="shrink-0 capitalize">{member.role}</span>
<span aria-hidden="true" className="shrink-0">
·
Expand Down Expand Up @@ -311,19 +314,18 @@ export function CommunityMembersSettingsCard({
description="Manage members and community access."
/>

<div className="overflow-hidden rounded-2xl border border-border/70 bg-background/70 shadow-xs">
<div className="overflow-hidden rounded-xl border border-border/70 bg-background/70 divide-y divide-border/55">
<div className="flex min-h-14 items-center px-4 py-3">
<h2 className="text-lg font-semibold tracking-tight">
Members
{members.length > 0 ? (
<span className="ml-1.5 text-sm font-normal text-muted-foreground">
{members.length}
</span>
) : null}
</h2>
</div>
<div className="space-y-3 p-4 sm:p-5">
<div className="flex items-center justify-between gap-3">
<h2 className="text-sm font-medium">
Members
{members.length > 0 ? (
<span className="ml-1.5 text-xs font-normal text-muted-foreground">
{members.length}
</span>
) : null}
</h2>
</div>

<div className="relative">
<Search className="pointer-events-none absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-muted-foreground" />
<input
Expand Down
47 changes: 26 additions & 21 deletions desktop/src/features/custom-emoji/ui/CustomEmojiSettingsCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -143,11 +143,14 @@ export function CustomEmojiSettingsCard() {
if (canSubmit) void handleAdd();
}}
>
<SettingsOptionGroup>
<SettingsOptionGroup title="Add emoji">
<div className="flex flex-wrap items-center justify-between gap-3 px-4 py-3 text-sm">
<div className="min-w-0 flex-[1_1_22rem]">
<h4 className="text-sm font-medium">Upload an image</h4>
<p className="text-sm font-normal text-muted-foreground">
<p
className="text-sm font-normal text-muted-foreground/70"
data-settings-subcopy
>
Square images work best. GIF, PNG, JPEG, and WebP files are
supported.
</p>
Expand Down Expand Up @@ -191,7 +194,10 @@ export function CustomEmojiSettingsCard() {
<div className="flex flex-wrap items-start justify-between gap-3 px-4 py-3 text-sm">
<div className="min-w-0 flex-[1_1_22rem]">
<h4 className="text-sm font-medium">Give it a name</h4>
<p className="text-sm font-normal text-muted-foreground">
<p
className="text-sm font-normal text-muted-foreground/70"
data-settings-subcopy
>
This is what you’ll type to add this emoji to messages and
reactions.
</p>
Expand Down Expand Up @@ -221,12 +227,18 @@ export function CustomEmojiSettingsCard() {
Use only letters, numbers, hyphen, or underscore.
</p>
) : pendingUpload === null ? (
<p className="text-sm font-normal text-muted-foreground">
<p
className="text-sm font-normal text-muted-foreground/70"
data-settings-subcopy
>
Choose an image first; Buzz will suggest a name from the
filename.
</p>
) : ownDuplicate ? (
<p className="text-sm font-normal text-muted-foreground">
<p
className="text-sm font-normal text-muted-foreground/70"
data-settings-subcopy
>
You already have :{normalized}: — saving will replace its
image.
</p>
Expand Down Expand Up @@ -256,24 +268,21 @@ export function CustomEmojiSettingsCard() {
</SettingsOptionGroup>
</form>

<div className="space-y-3" data-testid="custom-emoji-mine">
<h2 className="text-lg font-semibold tracking-tight">
My emoji{own.length > 0 ? ` (${own.length})` : ""}
</h2>
<div data-testid="custom-emoji-mine">
{ownLoading ? (
<SettingsOptionGroup>
<SettingsOptionGroup title="My emoji">
<div className="px-4 py-3 text-sm font-normal text-muted-foreground">
Loading…
</div>
</SettingsOptionGroup>
) : own.length === 0 ? (
<SettingsOptionGroup>
<SettingsOptionGroup title="My emoji">
<div className="px-4 py-3 text-sm font-normal text-muted-foreground">
You haven&apos;t added any emoji yet. Add one above.
</div>
</SettingsOptionGroup>
) : (
<SettingsOptionGroup>
<SettingsOptionGroup title={`My emoji (${own.length})`}>
{own.map((e) => (
<div
key={e.shortcode}
Expand Down Expand Up @@ -304,15 +313,11 @@ export function CustomEmojiSettingsCard() {
</div>

{!communityLoading && othersEmoji.length > 0 ? (
<div className="space-y-3" data-testid="custom-emoji-community">
<h2 className="text-lg font-semibold tracking-tight">
Community emoji ({othersEmoji.length})
</h2>
<p className="text-sm font-normal text-muted-foreground">
Added by other members. You can use these, but only their owner
can remove them.
</p>
<SettingsOptionGroup>
<div data-testid="custom-emoji-community">
<SettingsOptionGroup
description="Added by other members. You can use these, but only their owner can remove them."
title={`Community emoji (${othersEmoji.length})`}
>
{othersEmoji.map((e) => (
<div
key={e.shortcode}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,11 +77,8 @@ function ObserverArchiveSection({
}: ObserverSectionProps) {
const toggleDisabled = toggling;
return (
<div className="space-y-3" data-testid="local-archive-observer-section">
<h2 className="text-lg font-semibold tracking-tight">
Agent observer feed
</h2>
<SettingsOptionGroup>
<div data-testid="local-archive-observer-section">
<SettingsOptionGroup title="Agent observer feed">
<SettingsOptionRow>
<div className="min-w-0 flex-1">
<label
Expand All @@ -90,7 +87,10 @@ function ObserverArchiveSection({
>
Archive my agents' observer frames
</label>
<p className="text-sm font-normal text-muted-foreground">
<p
className="text-sm font-normal text-muted-foreground/70"
data-settings-subcopy
>
{`Saves kind ${KIND_AGENT_OBSERVER_FRAME} observer frames addressed to your pubkey. These are ephemeral — not stored by the relay — so local archiving is the only way to retain them.`}
</p>
</div>
Expand Down Expand Up @@ -121,11 +121,8 @@ function AgentMetricArchiveSection({
onToggle,
}: AgentMetricSectionProps) {
return (
<div className="space-y-3" data-testid="local-archive-agent-metric-section">
<h2 className="text-lg font-semibold tracking-tight">
Agent turn metrics
</h2>
<SettingsOptionGroup>
<div data-testid="local-archive-agent-metric-section">
<SettingsOptionGroup title="Agent turn metrics">
<SettingsOptionRow>
<div className="min-w-0 flex-1">
<label
Expand All @@ -134,7 +131,10 @@ function AgentMetricArchiveSection({
>
Archive my agents' turn metrics
</label>
<p className="text-sm font-normal text-muted-foreground">
<p
className="text-sm font-normal text-muted-foreground/70"
data-settings-subcopy
>
Saves kind {KIND_AGENT_TURN_METRIC} turn-metric events addressed
to your pubkey. Stored as plaintext in your local archive so
token-usage calculators can read them directly.
Expand Down Expand Up @@ -240,7 +240,10 @@ function CustomKindsInput({ value, onChange }: CustomKindsInputProps) {
type="text"
value={value}
/>
<p className="mt-1 text-xs text-muted-foreground">
<p
className="mt-1 text-xs text-muted-foreground/70"
data-settings-subcopy
>
Space- or comma-separated non-negative integers. Kinds already in the
checklist above are ignored.
</p>
Expand All @@ -266,11 +269,17 @@ function CustomKindsInput({ value, onChange }: CustomKindsInputProps) {

type AddFormProps = {
channels: Array<{ id: string; name: string }>;
title?: React.ReactNode;
onSaved: () => void;
onCancel: () => void;
};

function AddSubscriptionForm({ channels, onSaved, onCancel }: AddFormProps) {
function AddSubscriptionForm({
channels,
title,
onSaved,
onCancel,
}: AddFormProps) {
const [selectedChannelId, setSelectedChannelId] = React.useState("");
const [checkedKinds, setCheckedKinds] = React.useState<Set<number>>(
new Set(),
Expand Down Expand Up @@ -316,7 +325,7 @@ function AddSubscriptionForm({ channels, onSaved, onCancel }: AddFormProps) {
};

return (
<SettingsOptionGroup>
<SettingsOptionGroup title={title}>
<div className="space-y-5 px-4 py-4">
{/* Channel picker */}
<div>
Expand Down Expand Up @@ -535,25 +544,23 @@ export function LocalArchiveSettingsCard() {
/>

{/* Channel subscriptions */}
<div className="space-y-3" data-testid="local-archive-subscriptions">
<h2 className="text-lg font-semibold tracking-tight">
Channel subscriptions
{channelSubs.length > 0 ? ` (${channelSubs.length})` : ""}
</h2>
<div data-testid="local-archive-subscriptions">
{isLoading ? (
<SettingsOptionGroup>
<SettingsOptionGroup title="Channel subscriptions">
<div className="px-4 py-3 text-sm font-normal text-muted-foreground">
Loading…
</div>
</SettingsOptionGroup>
) : channelSubs.length === 0 ? (
<SettingsOptionGroup>
<SettingsOptionGroup title="Channel subscriptions">
<div className="px-4 py-3 text-sm font-normal text-muted-foreground">
No channel subscriptions yet. Add one below.
</div>
</SettingsOptionGroup>
) : (
<SettingsOptionGroup>
<SettingsOptionGroup
title={`Channel subscriptions (${channelSubs.length})`}
>
{channelSubs.map((sub) => {
const key = `${sub.scopeType}:${sub.scopeValue}`;
return (
Expand All @@ -567,7 +574,10 @@ export function LocalArchiveSettingsCard() {
<p className="truncate text-sm font-medium">
{scopeLabel(sub, channelNameById)}
</p>
<p className="text-xs text-muted-foreground">
<p
className="text-xs text-muted-foreground/70"
data-settings-subcopy
>
{sub.scopeType} · kinds: {kindSummary(sub.kinds)}
</p>
</div>
Expand All @@ -590,10 +600,7 @@ export function LocalArchiveSettingsCard() {
</div>

{/* Add channel subscription */}
<div className="space-y-3" data-testid="local-archive-add">
<h2 className="text-lg font-semibold tracking-tight">
Add channel subscription
</h2>
<div data-testid="local-archive-add">
{isAddingOpen ? (
<AddSubscriptionForm
channels={joinedChannels}
Expand All @@ -602,13 +609,17 @@ export function LocalArchiveSettingsCard() {
setIsAddingOpen(false);
void reload();
}}
title="Add channel subscription"
/>
) : (
<SettingsOptionGroup>
<SettingsOptionGroup title="Add channel subscription">
<SettingsOptionRow>
<div className="min-w-0 flex-1">
<p className="text-sm font-medium">Subscribe to a channel</p>
<p className="text-xs text-muted-foreground">
<p
className="text-xs text-muted-foreground/70"
data-settings-subcopy
>
Choose a channel and select which event types to archive.
</p>
</div>
Expand Down
Loading
Loading