feat(desktop): port v0.11.4-v0.15.2 from Tauri to Electron + Discord-parity audio (v0.16.0)

Chronological port of every Tauri release commit (v0.11.4 -> v0.15.2)
into the Electron rebuild, plus Discord-style audio handling that goes
beyond the Tauri original.

Highlights:
  - All 17 Tauri release commits ported (audio fixes, custom notification
    sound, Discord-style chat UX, profile banner, changelog page,
    Discord-parity call UX, screen-share echo + re-watch UX, audio-loop
    fix).
  - Native napi-rs audio-loopback addon with WASAPI process-loopback:
      * EXCLUDE_TARGET_PROCESS_TREE for full-screen shares -> peers
        never hear themselves echoed back through the capture.
      * INCLUDE_TARGET_PROCESS_TREE for window shares -> only the
        picked window's audio is captured, not the whole OS mixer
        (Discord parity).
      * HWND -> PID resolution via Win32 GetWindowThreadProcessId.
  - Discord-style screen-source picker (thumbnail grid, screens vs
    apps tabs, live-refreshing thumbnails).
  - Hash routing fix for packaged builds (file:// can't resolve
    BrowserRouter paths).
  - Tauri sources removed (apps/desktop/src-tauri).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
byGalax
2026-05-06 23:35:01 +02:00
parent 72d02e385f
commit 825160ee46
504 changed files with 14217 additions and 14366 deletions
+22 -30
View File
@@ -4,15 +4,13 @@ import { NavLink } from 'react-router-dom';
import { useAuth } from '../context/AuthContext';
import { useConversationsContext } from '../context/ConversationsContext';
import { useFriendshipsContext } from '../context/FriendshipsContext';
import { useTheme } from '../context/ThemeContext';
import {
ChatBubbleIcon,
GearIcon,
LogoMark,
MoonIcon,
ShieldIcon,
SignOutIcon,
SunIcon,
SparklesIcon,
UsersIcon,
} from './icons';
@@ -41,29 +39,27 @@ export function Sidebar() {
const { signOut, profile } = useAuth();
const { incomingCount } = useFriendshipsContext();
const { totalUnread } = useConversationsContext();
const { theme, toggle } = useTheme();
const navItems: NavItem[] = profile?.isAdmin ? [...PRIMARY_NAV, ADMIN_NAV] : PRIMARY_NAV;
return (
<aside
aria-label="Primary navigation"
className="flex h-screen w-[72px] shrink-0 flex-col items-center border-r border-line bg-surface-2/80 py-4 backdrop-blur-xl"
className="discord-rail flex h-screen w-[72px] shrink-0 flex-col items-center border-r border-line bg-surface-2 py-3"
>
<div className="flex h-10 w-10 items-center justify-center" title="Netralax">
<LogoMark className="h-8 w-8" />
<div
className="flex h-12 w-12 items-center justify-center rounded-2xl bg-accent text-accent-fg shadow-[0_10px_26px_rgba(88,101,242,0.32)]"
title="Netralax"
>
<LogoMark className="h-10 w-10" />
</div>
<div className="my-3 h-px w-8 bg-line" aria-hidden="true" />
<div className="my-3 h-0.5 w-8 rounded-full bg-line" aria-hidden="true" />
<nav className="flex flex-col items-center gap-2">
<nav className="flex flex-col items-center gap-2.5">
{navItems.map((item) => {
const badgeCount =
item.badge === 'friends'
? incomingCount
: item.badge === 'chats'
? totalUnread
: 0;
item.badge === 'friends' ? incomingCount : item.badge === 'chats' ? totalUnread : 0;
return (
<RailNavLink
key={item.to}
@@ -78,17 +74,13 @@ export function Sidebar() {
<div className="flex-1" />
<div className="flex flex-col items-center gap-2">
<div className="flex flex-col items-center gap-2.5">
<RailNavLink
to="/settings"
label={t('app:nav.settings')}
icon={GearIcon}
/>
<RailIconButton
label={theme === 'dark' ? t('app:theme.light', { defaultValue: 'Light mode' }) : t('app:theme.dark', { defaultValue: 'Dark mode' })}
onClick={toggle}
icon={theme === 'dark' ? SunIcon : MoonIcon}
to="/changelog"
label={t('app:nav.changelog', { defaultValue: 'Was ist neu' })}
icon={SparklesIcon}
/>
<RailNavLink to="/settings" label={t('app:nav.settings')} icon={GearIcon} />
<RailIconButton
label={t('app:sidebar.sign_out')}
onClick={() => void signOut()}
@@ -119,8 +111,8 @@ function RailNavLink({ to, label, icon: Icon, badge = 0 }: RailNavLinkProps) {
'group relative flex h-11 w-11 cursor-pointer items-center justify-center rounded-xl transition',
'focus:outline-none focus-visible:ring-2 focus-visible:ring-accent/50',
isActive
? 'bg-accent/15 text-accent'
: 'text-fg-muted hover:bg-surface-3/60 hover:text-fg',
? 'bg-accent text-accent-fg shadow-[0_8px_22px_rgba(88,101,242,0.34)]'
: 'text-fg-muted hover:rounded-2xl hover:bg-surface-3/80 hover:text-fg dark:hover:bg-[#313338]',
].join(' ')
}
>
@@ -129,7 +121,7 @@ function RailNavLink({ to, label, icon: Icon, badge = 0 }: RailNavLinkProps) {
{isActive && (
<span
aria-hidden="true"
className="absolute -left-4 h-6 w-1 rounded-r-full bg-accent"
className="absolute -left-[15px] h-7 w-1 rounded-r-full bg-fg"
/>
)}
<Icon style={{ width: '20px', height: '20px' }} />
@@ -150,8 +142,8 @@ interface RailIconButtonProps {
function RailIconButton({ label, onClick, icon: Icon, tone = 'default' }: RailIconButtonProps) {
const toneClass =
tone === 'danger'
? 'text-fg-muted hover:bg-rose-500/10 hover:text-rose-400 focus-visible:ring-rose-400/40'
: 'text-fg-muted hover:bg-surface-3/60 hover:text-fg focus-visible:ring-accent/50';
? 'text-fg-muted hover:rounded-2xl hover:bg-rose-500/10 hover:text-rose-400 focus-visible:ring-rose-400/40'
: 'text-fg-muted hover:rounded-2xl hover:bg-surface-3/80 hover:text-fg focus-visible:ring-accent/50 dark:hover:bg-[#313338]';
return (
<button
type="button"
@@ -159,7 +151,7 @@ function RailIconButton({ label, onClick, icon: Icon, tone = 'default' }: RailIc
title={label}
onClick={onClick}
className={
'flex h-11 w-11 cursor-pointer items-center justify-center rounded-xl transition focus:outline-none focus-visible:ring-2 ' +
'flex h-11 w-11 cursor-pointer items-center justify-center rounded-xl transition-all duration-150 focus:outline-none focus-visible:ring-2 ' +
toneClass
}
>
@@ -173,7 +165,7 @@ function RailBadge({ count }: { count: number }) {
return (
<span
aria-hidden="true"
className="absolute -right-1 -top-1 inline-flex min-w-[18px] items-center justify-center rounded-full bg-rose-500 px-1 text-[10px] font-bold leading-tight text-white ring-2 ring-surface-2"
className="absolute -right-1 -top-1 inline-flex min-w-[18px] items-center justify-center rounded-full bg-rose-500 px-1 text-[10px] font-bold leading-tight text-white ring-2 ring-surface-2 dark:ring-[#1e1f22]"
>
{display}
</span>