diff --git a/assets/brand/app-icon-1024.png b/assets/brand/app-icon-1024.png
index cde5ab5d..6b12975e 100644
Binary files a/assets/brand/app-icon-1024.png and b/assets/brand/app-icon-1024.png differ
diff --git a/assets/brand/app-icon-x1.png b/assets/brand/app-icon-x1.png
index 5d9acb7f..e3414ff4 100644
Binary files a/assets/brand/app-icon-x1.png and b/assets/brand/app-icon-x1.png differ
diff --git a/assets/brand/app-icon-x2.png b/assets/brand/app-icon-x2.png
index 5551eca1..d6502379 100644
Binary files a/assets/brand/app-icon-x2.png and b/assets/brand/app-icon-x2.png differ
diff --git a/assets/brand/app-icon-x3.png b/assets/brand/app-icon-x3.png
index d445814a..75358436 100644
Binary files a/assets/brand/app-icon-x3.png and b/assets/brand/app-icon-x3.png differ
diff --git a/assets/brand/app-icon.svg b/assets/brand/app-icon.svg
index 821b870c..48ac3b8a 100644
--- a/assets/brand/app-icon.svg
+++ b/assets/brand/app-icon.svg
@@ -1,33 +1,40 @@
-
diff --git a/assets/brand/mark-mono-dark.svg b/assets/brand/mark-mono-dark.svg
index 9afd7c2f..b82df255 100644
--- a/assets/brand/mark-mono-dark.svg
+++ b/assets/brand/mark-mono-dark.svg
@@ -1,14 +1,20 @@
-
+
+
-
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
\ No newline at end of file
+
+
+
diff --git a/assets/brand/mark.svg b/assets/brand/mark.svg
index bee798f9..6746bb40 100644
--- a/assets/brand/mark.svg
+++ b/assets/brand/mark.svg
@@ -1,28 +1,33 @@
-
+
+
-
-
-
-
+
+
+
-
-
-
+
+
+
+
+
+
+
+
-
-
-
-
-
+
+
+
+
+
+
-
\ No newline at end of file
+
diff --git a/docs/roadmap-resenha.md b/docs/roadmap-resenha.md
index 0bab4d1f..df6b9ff9 100644
--- a/docs/roadmap-resenha.md
+++ b/docs/roadmap-resenha.md
@@ -29,6 +29,8 @@ código e os commits seguem em inglês, como o resto do repositório.
| Busca: filtros embutidos e tradução | `50a8f12c` | Os filtros já existiam; faltava `de:fulano` e descoberta |
| Emojis e figurinhas do servidor | `7d003021` | `:nome:` no markdown sem plugin; figurinha como mensagem inteira |
| Fundação de i18n (en + pt-BR) | `688a1335` | `src/i18n/`; pt-BR é parcial e cai para inglês. Aba Idioma nas configurações |
+| Rebrand: **Resenhacord** + logo nova | (ver git log) | `productName` mudou, `appId` **não** — assim o NSIS troca a instalação antiga no lugar. `userData` migra `Backspace` → `Resenhacord` no primeiro boot (senão todo mundo cairia da sessão). Logo: duas bolhas de conversa, roxo → rosa; fonte em `assets/brand/*.svg`, PNGs e ícones gerados por `pnpm gen-icons` |
+| Aviso "X fixou uma mensagem" | (ver git log) | Tabela `messages` ganhou `type` (migração 0018); a rota de pin posta uma mensagem de sistema. Dois links: pular pra mensagem e abrir o painel de fixadas |
| Menção `@everyone` | (ver git log) | Reusa o token `<@id>`; permissão `MENTION_EVERYONE` nova, concedida ao `@everyone` por padrão e retroativa via backfill no boot. Servidor neutraliza o token de quem não tem a permissão, no envio **e** na edição |
| Renomear canal (nome e tópico) | (ver git log) | Rota `PATCH /api/channels/:id` já existia; faltava interface. Normalização em `shared/constants` para servidor e web usarem a mesma regra |
| Volume da tela em 50% por padrão | (ver git log) | `DEFAULT_STREAM_VOLUME`; o publicador reforça o áudio do sistema, então o padrão anterior chegava alto demais |
@@ -63,6 +65,11 @@ Ordem sugerida: as pequenas primeiro, as grandes uma de cada vez.
| # | Feature | Tamanho | Observação técnica |
|---|---|---|---|
+## Próximo foco (pedido em 2026-09-02): personalização do usuário e do perfil
+
+A definir com o dono. Já existe: avatar, banner (imagem ou GIF), cor do avatar
+e do banner, sobre mim, status personalizado, atividade (Spotify/jogos).
+
## Pendente — ideias aprovadas
| Feature | Tamanho | Observação técnica |
diff --git a/packages/desktop/build/icon.icns b/packages/desktop/build/icon.icns
index 3a7ea90d..47502ac9 100644
Binary files a/packages/desktop/build/icon.icns and b/packages/desktop/build/icon.icns differ
diff --git a/packages/desktop/build/icon.ico b/packages/desktop/build/icon.ico
index 26c5d417..afbcc481 100644
Binary files a/packages/desktop/build/icon.ico and b/packages/desktop/build/icon.ico differ
diff --git a/packages/desktop/build/icon.png b/packages/desktop/build/icon.png
index 5ad038bd..c366ed03 100644
Binary files a/packages/desktop/build/icon.png and b/packages/desktop/build/icon.png differ
diff --git a/packages/desktop/build/icons/1024x1024.png b/packages/desktop/build/icons/1024x1024.png
index a670e29d..9580695e 100644
Binary files a/packages/desktop/build/icons/1024x1024.png and b/packages/desktop/build/icons/1024x1024.png differ
diff --git a/packages/desktop/build/icons/128x128.png b/packages/desktop/build/icons/128x128.png
index 73fe02fa..dc00d0c5 100644
Binary files a/packages/desktop/build/icons/128x128.png and b/packages/desktop/build/icons/128x128.png differ
diff --git a/packages/desktop/build/icons/16x16.png b/packages/desktop/build/icons/16x16.png
index 8a4c0db3..06a76900 100644
Binary files a/packages/desktop/build/icons/16x16.png and b/packages/desktop/build/icons/16x16.png differ
diff --git a/packages/desktop/build/icons/256x256.png b/packages/desktop/build/icons/256x256.png
index 71989079..63508950 100644
Binary files a/packages/desktop/build/icons/256x256.png and b/packages/desktop/build/icons/256x256.png differ
diff --git a/packages/desktop/build/icons/32x32.png b/packages/desktop/build/icons/32x32.png
index 70250d7c..167cb4f0 100644
Binary files a/packages/desktop/build/icons/32x32.png and b/packages/desktop/build/icons/32x32.png differ
diff --git a/packages/desktop/build/icons/48x48.png b/packages/desktop/build/icons/48x48.png
index fc6737b3..b015098d 100644
Binary files a/packages/desktop/build/icons/48x48.png and b/packages/desktop/build/icons/48x48.png differ
diff --git a/packages/desktop/build/icons/512x512.png b/packages/desktop/build/icons/512x512.png
index 5ad038bd..c366ed03 100644
Binary files a/packages/desktop/build/icons/512x512.png and b/packages/desktop/build/icons/512x512.png differ
diff --git a/packages/desktop/build/icons/64x64.png b/packages/desktop/build/icons/64x64.png
index 6ab93cfa..b86a2b13 100644
Binary files a/packages/desktop/build/icons/64x64.png and b/packages/desktop/build/icons/64x64.png differ
diff --git a/packages/desktop/electron-builder.yml b/packages/desktop/electron-builder.yml
index 0c5cc7dd..ea28f6bc 100644
--- a/packages/desktop/electron-builder.yml
+++ b/packages/desktop/electron-builder.yml
@@ -1,5 +1,5 @@
appId: com.backspace.desktop
-productName: Backspace
+productName: Resenhacord
artifactName: "${productName}-${version}-${arch}.${ext}"
directories:
output: dist-electron
@@ -36,7 +36,7 @@ publish:
- provider: generic
url: https://git.resenha.website/devsyncwrld/backspace/releases/download/latest/
protocols:
- - name: Backspace
+ - name: Resenhacord
schemes:
- backspace
mac:
diff --git a/packages/desktop/package.json b/packages/desktop/package.json
index 44173852..fab22a82 100644
--- a/packages/desktop/package.json
+++ b/packages/desktop/package.json
@@ -3,7 +3,7 @@
"version": "1.5.0",
"private": true,
"license": "AGPL-3.0-only",
- "description": "Backspace",
+ "description": "Resenhacord",
"author": {
"name": "Jannis Braun",
"email": "backspace@backspace.chat"
diff --git a/packages/desktop/resources/instance-picker.html b/packages/desktop/resources/instance-picker.html
index b427dae0..06a633c3 100644
--- a/packages/desktop/resources/instance-picker.html
+++ b/packages/desktop/resources/instance-picker.html
@@ -3,7 +3,7 @@
- Backspace — Connect
+ Resenhacord — Conectar
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
+
+
+
+
+
+
-
\ No newline at end of file
+
diff --git a/packages/web/public/icons/logo.png b/packages/web/public/icons/logo.png
index 71989079..63508950 100644
Binary files a/packages/web/public/icons/logo.png and b/packages/web/public/icons/logo.png differ
diff --git a/packages/web/src/components/JoinPage.tsx b/packages/web/src/components/JoinPage.tsx
index 5faa0cdf..a1a633bb 100644
--- a/packages/web/src/components/JoinPage.tsx
+++ b/packages/web/src/components/JoinPage.tsx
@@ -232,7 +232,7 @@ export function JoinPage() {
onClick={() => navigate('/channels/@me')}
className="px-6 py-2.5 bg-accent-primary hover:bg-accent-primary/80 text-white font-medium rounded transition-colors"
>
- Back to Backspace
+ {t('join.page.back')}
) : (
prevState.realtimeMessageEvents.length) {
const newEvents = state.realtimeMessageEvents.slice(prevState.realtimeMessageEvents.length);
for (const { message } of newEvents) {
- if (message.userId !== currentUser?.id) {
+ // System notices (pins, membership) are not from anyone — no toast.
+ if (message.type !== 'system' && message.userId !== currentUser?.id) {
if (focused && message.channelId === currentChannel) break;
const displayName = message.user?.displayName || message.user?.username || 'Someone';
diff --git a/packages/web/src/components/chat/SystemMessage.test.tsx b/packages/web/src/components/chat/SystemMessage.test.tsx
index 63ebdfe7..f7ea98e4 100644
--- a/packages/web/src/components/chat/SystemMessage.test.tsx
+++ b/packages/web/src/components/chat/SystemMessage.test.tsx
@@ -96,3 +96,26 @@ describe('SystemMessage — icon_changed', () => {
expect(screen.getByText(/Heidi updated the group icon/)).toBeDefined();
});
});
+
+describe('SystemMessage — message_pinned (space channel, no roster)', () => {
+ it('names the actor from message.user and offers both links', async () => {
+ const { useUIStore } = await import('../../stores/uiStore');
+ const msg = buildMessage({ event: 'message_pinned', messageId: 'M9' });
+ renderSM(msg, null);
+
+ expect(screen.getByText(/Heidi pinned/)).toBeDefined();
+
+ const before = useUIStore.getState().pinsPanelRequest;
+ screen.getByText('a message').click();
+ expect(useUIStore.getState().jumpToMessageRequest).toBe('M9');
+
+ screen.getByText('See all pinned messages.').click();
+ expect(useUIStore.getState().pinsPanelRequest).toBe(before + 1);
+ });
+
+ it('falls back to the plain renderer when messageId is missing', () => {
+ // A malformed payload must not throw — it degrades to the generic branch.
+ const msg = buildMessage({ event: 'message_pinned' });
+ expect(() => renderSM(msg, null)).not.toThrow();
+ });
+});
diff --git a/packages/web/src/components/chat/SystemMessage.tsx b/packages/web/src/components/chat/SystemMessage.tsx
index 4d088949..36ed8997 100644
--- a/packages/web/src/components/chat/SystemMessage.tsx
+++ b/packages/web/src/components/chat/SystemMessage.tsx
@@ -1,6 +1,7 @@
import type { DmChannel, MessageWithUser, SpaceInviteSystemPayload, User } from '@backspace/shared';
import { SpaceInviteCard } from './SpaceInviteCard';
import { useT } from '../../i18n';
+import { useUIStore } from '../../stores/uiStore';
interface SystemMessageProps {
message: MessageWithUser;
@@ -52,6 +53,33 @@ export function SystemMessage({ message, dm }: SystemMessageProps) {
);
}
+ // The pin notice has two links in one sentence — the pinned message, and the
+ // pins panel — so it is assembled from parts around the placeholders rather
+ // than as flat text. Word order stays with the translation.
+ if (data.event === 'message_pinned' && typeof data.messageId === 'string') {
+ const pinnedId = data.messageId;
+ const parts = t('system.pinned', { actor: actorName, message: '\u0000', seeAll: '\u0001' });
+ const [beforeMsg, rest = ''] = parts.split('\u0000');
+ const [between, after = ''] = rest.split('\u0001');
+ const linkClass = 'text-txt-secondary hover:text-txt-primary hover:underline cursor-pointer';
+ return (
+
+
+ 📌
+ {beforeMsg}
+ useUIStore.getState().requestJumpToMessage(pinnedId)}>
+ {t('system.pinned.message')}
+
+ {between}
+ useUIStore.getState().requestPinsPanel()}>
+ {t('system.pinned.seeAll')}
+
+ {after}
+
+
+ );
+ }
+
// Inline-text events.
let text = '';
let icon = '';
diff --git a/packages/web/src/components/layout/AppLayout.tsx b/packages/web/src/components/layout/AppLayout.tsx
index 01314d7b..c689925a 100644
--- a/packages/web/src/components/layout/AppLayout.tsx
+++ b/packages/web/src/components/layout/AppLayout.tsx
@@ -353,7 +353,7 @@ export function AppLayout() {
if (!user || showBootSkeleton) {
return (
-
+
{/* Space strip */}
{Array.from({ length: 5 }, (_, i) => (
diff --git a/packages/web/src/components/layout/MainContent.tsx b/packages/web/src/components/layout/MainContent.tsx
index 4d36de68..ea84fe42 100644
--- a/packages/web/src/components/layout/MainContent.tsx
+++ b/packages/web/src/components/layout/MainContent.tsx
@@ -56,6 +56,20 @@ export function MainContent() {
const [searchOpen, setSearchOpen] = useState(false);
const [pinsOpen, setPinsOpen] = useState(false);
const [jumpToMessageId, setJumpToMessageId] = useState
(null);
+ const pinsPanelRequest = useUIStore((st) => st.pinsPanelRequest);
+ const jumpToMessageRequest = useUIStore((st) => st.jumpToMessageRequest);
+ const clearJumpToMessageRequest = useUIStore((st) => st.clearJumpToMessageRequest);
+ // Requests arrive from the pin system notice (see SystemMessage). The
+ // counter starts at 0 and only ever increments, so the initial render is a
+ // no-op and every later change is a real click.
+ useEffect(() => {
+ if (pinsPanelRequest > 0) setPinsOpen(true);
+ }, [pinsPanelRequest]);
+ useEffect(() => {
+ if (!jumpToMessageRequest) return;
+ setJumpToMessageId(jumpToMessageRequest);
+ clearJumpToMessageRequest();
+ }, [jumpToMessageRequest, clearJumpToMessageRequest]);
// Resolve the DM header's "first other" member through the canonical view
// cache. The hook must be called unconditionally at the component top, so we
diff --git a/packages/web/src/components/layout/SpaceSidebar.tsx b/packages/web/src/components/layout/SpaceSidebar.tsx
index 659a3c26..1d78ff10 100644
--- a/packages/web/src/components/layout/SpaceSidebar.tsx
+++ b/packages/web/src/components/layout/SpaceSidebar.tsx
@@ -111,7 +111,7 @@ function SidebarItem({ id, name, icon, avatarColor, active, onClick, onContextMe
const buttonContent = (