diff --git a/src/renderer/src/app.css b/src/renderer/src/app.css
index 21dc5bd..9567fca 100644
--- a/src/renderer/src/app.css
+++ b/src/renderer/src/app.css
@@ -1735,3 +1735,13 @@ video.lightbox-media {
min-width: 0;
font-weight: 600;
}
+
+/* A brand mark kept in its own colours. Unlike a guild icon it is a logo
+ rather than a photo, so it is fitted with breathing room instead of cropped
+ to fill the tile. */
+.rail-mark {
+ width: 74%;
+ height: 74%;
+ object-fit: contain;
+ display: block;
+}
diff --git a/src/renderer/src/assets/sneedchat.png b/src/renderer/src/assets/sneedchat.png
new file mode 100644
index 0000000..a3c568d
Binary files /dev/null and b/src/renderer/src/assets/sneedchat.png differ
diff --git a/src/renderer/src/components/AccountsPanel.tsx b/src/renderer/src/components/AccountsPanel.tsx
index a58e02d..a632d19 100644
--- a/src/renderer/src/components/AccountsPanel.tsx
+++ b/src/renderer/src/components/AccountsPanel.tsx
@@ -38,7 +38,7 @@ export function AccountsPanel(): JSX.Element {
className={`service-chip${adding === service ? ' active' : ''}`}
onClick={() => setAdding(adding === service ? null : service)}
>
- {icon.svg ? : }
+ {icon.mark ? : }
{serviceLabel(service)}
)
@@ -72,8 +72,8 @@ function AccountRow({ account }: { account: Account }): JSX.Element {
{account.avatarUrl ? (
})
- ) : icon.svg ? (
-
+ ) : icon.mark ? (
+
) : (
)}
diff --git a/src/renderer/src/components/BufferList.tsx b/src/renderer/src/components/BufferList.tsx
index d956318..0d35863 100644
--- a/src/renderer/src/components/BufferList.tsx
+++ b/src/renderer/src/components/BufferList.tsx
@@ -2,6 +2,7 @@ import { useMemo } from 'react'
import { Icon, IconButton, MaskIcon } from './Icon'
import { ContextMenu, useContextMenu, type MenuEntry } from './ContextMenu'
import { useChat, useIdSetPref, usePref, useStore } from '../state/hooks'
+import { visibleGroups } from '../lib/groups'
import type { BufferEntry } from '../state/store'
import {
bufferDisplayName,
@@ -38,7 +39,8 @@ export function BufferList(): JSX.Element {
// A stale selection (a guild that went away, a first run) resolves to the
// first entry rather than an empty pane.
- const activeGroup = groups.find((g) => g.id === activeGroupId) || groups[0]
+ const shownGroups = useMemo(() => visibleGroups(groups, visible), [groups, visible])
+ const activeGroup = shownGroups.find((g) => g.id === activeGroupId) || shownGroups[0]
const groupAccount = accounts.find((a) => a.id === activeGroup?.accountId)
// Server buffer first, then most recent activity - the ordering nobilis's
@@ -243,8 +245,8 @@ function BufferRow({
// name as text in front of every entry.
const service = serviceIcon(account?.service ?? '')
const leading = showServiceIcon ? (
- service.svg ? (
-
+ service.mark ? (
+
) : (
)
diff --git a/src/renderer/src/components/ServerRail.tsx b/src/renderer/src/components/ServerRail.tsx
index e18a1fd..5668884 100644
--- a/src/renderer/src/components/ServerRail.tsx
+++ b/src/renderer/src/components/ServerRail.tsx
@@ -1,6 +1,7 @@
import { Icon, MaskIcon } from './Icon'
import { useChat, useStore } from '../state/hooks'
import { nickColor, resolveMediaUrl, serviceIcon } from '../lib/util'
+import { visibleGroups } from '../lib/groups'
import type { BufferGroup } from '../../../shared/wire'
import type { BufferEntry } from '../state/store'
@@ -41,8 +42,13 @@ function RailTile({ group, active, unread, highlight, onSelect }: TileProps): JS
content =
})
} else if (group.kind === 'dms') {
content =
+ } else if (group.kind === 'account' && service.mark && service.colour) {
+ // Artwork with colour worth keeping, shown as-is rather than flattened to
+ // a silhouette - it sits beside full-colour guild icons here, and this is
+ // the one place with room for it.
+ content =

} else if (group.kind === 'account') {
- content = service.svg ?
:
+ content = service.mark ?
:
} else {
content = (
@@ -82,8 +88,6 @@ export function ServerRail(): JSX.Element | null {
const activeGroupId = useChat((s) => s.activeGroupId)
const buffers = useChat((s) => s.buffers)
- if (groups.length <= 1) return null
-
// Unread rolls up from the buffers under each entry, so a guild whose
// channels are all collapsed away still shows it has something waiting.
const totals = new Map()
@@ -95,9 +99,13 @@ export function ServerRail(): JSX.Element | null {
totals.set(b.groupId, t)
}
+ const visible = visibleGroups(groups, buffers as BufferEntry[])
+
+ if (visible.length <= 1) return null
+
return (