Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
10 changes: 9 additions & 1 deletion desktop/src-tauri/capabilities/default.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,13 @@
"identifier": "default",
"description": "Capability for the main window",
"windows": ["main"],
"permissions": ["core:default", "opener:default", "websocket:default"]
"permissions": [
"core:default",
"core:window:allow-start-dragging",
"core:window:allow-show",
"core:window:allow-close",
"opener:default",
"websocket:default",
"window-state:default"
]
}
2 changes: 1 addition & 1 deletion desktop/src-tauri/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -609,7 +609,7 @@ pub fn run() {
.plugin(
tauri_plugin_window_state::Builder::default()
.with_state_flags(
StateFlags::SIZE | StateFlags::POSITION | StateFlags::MAXIMIZED,
StateFlags::all() & !StateFlags::VISIBLE,
)
.build(),
)
Expand Down
6 changes: 5 additions & 1 deletion desktop/src-tauri/tauri.conf.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,11 @@
{
"title": "",
"width": 800,
"height": 600
"height": 600,
"visible": false,
"titleBarStyle": "Overlay",
"hiddenTitle": true,
"trafficLightPosition": { "x": 12, "y": 22 }
}
],
"security": {
Expand Down
7 changes: 7 additions & 0 deletions desktop/src/app/App.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
import { getCurrentWindow } from "@tauri-apps/api/window";
import { useEffect } from "react";

import { AppShell } from "@/app/AppShell";

export function App() {
useEffect(() => {
getCurrentWindow().show();
}, []);

return <AppShell />;
}
21 changes: 19 additions & 2 deletions desktop/src/app/AppShell.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { getCurrentWindow } from "@tauri-apps/api/window";
import * as React from "react";
import { Settings2 } from "lucide-react";

Expand Down Expand Up @@ -26,7 +27,11 @@ import { getEventById } from "@/shared/api/tauri";
import { useIdentityQuery } from "@/shared/api/hooks";
import type { RelayEvent, SearchHit } from "@/shared/api/types";
import { Button } from "@/shared/ui/button";
import { SidebarInset, SidebarProvider } from "@/shared/ui/sidebar";
import {
SidebarInset,
SidebarProvider,
SidebarTrigger,
} from "@/shared/ui/sidebar";

type AppView = "home" | "channel";

Expand Down Expand Up @@ -168,6 +173,7 @@ export function AppShell() {

return (
<SidebarProvider className="h-dvh overflow-hidden overscroll-none">
<SidebarTrigger className="fixed left-[80px] top-[9px] z-50 h-6 w-6" />
<AppSidebar
channels={channels}
errorMessage={
Expand Down Expand Up @@ -210,9 +216,20 @@ export function AppShell() {
/>

<SidebarInset
className="min-h-0 min-w-0 overflow-hidden"
className="relative min-h-0 min-w-0 overflow-hidden pt-7"
key={contentPaneKey}
>
{/* Drag strip covering the traffic-light inset area */}
<div
className="absolute inset-x-0 top-0 flex h-7 items-center px-2"
onPointerDown={(e) => {
if (e.button !== 0) return;
const target = e.target as HTMLElement;
if (target.closest('button, a, input, [role="button"]')) return;
e.preventDefault();
getCurrentWindow().startDragging();
}}
/>
{selectedView === "home" ? (
<ChatHeader
description="Personalized feed for mentions, reminders, channel activity, and agent work."
Expand Down
13 changes: 10 additions & 3 deletions desktop/src/features/chat/ui/ChatHeader.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { getCurrentWindow } from "@tauri-apps/api/window";
import { CircleDot, FileText, Hash, Home } from "lucide-react";
import type * as React from "react";

import type { ChannelType } from "@/shared/api/types";
import { SidebarTrigger } from "@/shared/ui/sidebar";

type ChatHeaderProps = {
actions?: React.ReactNode;
Expand Down Expand Up @@ -34,6 +34,14 @@ function ChannelIcon({
return <Hash className="h-5 w-5 text-primary" />;
}

function handlePointerDown(e: React.PointerEvent) {
if (e.button !== 0) return;
const target = e.target as HTMLElement;
if (target.closest('button, a, input, [role="button"]')) return;
e.preventDefault();
getCurrentWindow().startDragging();
}

export function ChatHeader({
actions,
title,
Expand All @@ -45,9 +53,8 @@ export function ChatHeader({
<header
className="flex min-w-0 items-center gap-3 border-b border-border/80 bg-background px-4 py-3 sm:px-6"
data-testid="chat-header"
onPointerDown={handlePointerDown}
>
<SidebarTrigger />

<div className="min-w-0 flex-1">
<div className="flex min-w-0 items-center gap-2">
<ChannelIcon channelType={channelType} mode={mode} />
Expand Down
28 changes: 14 additions & 14 deletions desktop/src/features/home/ui/HomeView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -144,11 +144,11 @@ function FeedSection({
onOpenChannel,
}: FeedSectionProps) {
return (
<section className="rounded-[1.75rem] border border-border/80 bg-card/80 p-5 shadow-sm">
<section className="rounded-xl border border-border/80 bg-card/80 p-5 shadow-sm">
<div className="flex items-start justify-between gap-4">
<div className="min-w-0">
<div className="flex items-center gap-3">
<div className="flex h-10 w-10 items-center justify-center rounded-2xl bg-primary/10 text-primary">
<div className="flex h-10 w-10 items-center justify-center rounded-lg bg-primary/10 text-primary">
<Icon className="h-4 w-4" />
</div>
<div>
Expand All @@ -166,7 +166,7 @@ function FeedSection({

<div className="mt-5 space-y-3">
{items.length === 0 ? (
<div className="rounded-3xl border border-dashed border-border/80 bg-background/60 px-5 py-7 text-center">
<div className="rounded-lg border border-dashed border-border/80 bg-background/60 px-5 py-7 text-center">
<p className="text-sm font-semibold tracking-tight">{emptyTitle}</p>
<p className="mt-2 text-sm text-muted-foreground">
{emptyDescription}
Expand All @@ -181,11 +181,11 @@ function FeedSection({

return (
<article
className="rounded-3xl border border-border/70 bg-background/70 p-4 shadow-sm"
className="rounded-lg border border-border/70 bg-background/70 p-4 shadow-sm"
key={item.id}
>
<div className="flex gap-3">
<div className="flex h-10 w-10 shrink-0 items-center justify-center rounded-2xl bg-secondary/70 text-secondary-foreground">
<div className="flex h-10 w-10 shrink-0 items-center justify-center rounded-lg bg-secondary/70 text-secondary-foreground">
<Icon className="h-4 w-4" />
</div>

Expand Down Expand Up @@ -271,7 +271,7 @@ function SummaryCard({
return (
<div
className={cn(
"rounded-3xl border p-4 shadow-sm",
"rounded-lg border p-4 shadow-sm",
tone === "urgent"
? "border-primary/20 bg-primary/10"
: "border-border/80 bg-background/70",
Expand All @@ -280,7 +280,7 @@ function SummaryCard({
<div className="flex items-center gap-3">
<div
className={cn(
"flex h-10 w-10 items-center justify-center rounded-2xl",
"flex h-10 w-10 items-center justify-center rounded-lg",
tone === "urgent"
? "bg-primary text-primary-foreground"
: "bg-secondary text-secondary-foreground",
Expand All @@ -303,28 +303,28 @@ function HomeLoadingState() {
return (
<div className="flex-1 overflow-y-auto overflow-x-hidden overscroll-contain px-4 py-4 sm:px-6">
<div className="mx-auto flex w-full max-w-6xl flex-col gap-6">
<div className="rounded-[1.75rem] border border-border/80 bg-card/80 p-5 shadow-sm">
<div className="rounded-xl border border-border/80 bg-card/80 p-5 shadow-sm">
<Skeleton className="h-6 w-44" />
<Skeleton className="mt-3 h-4 w-full max-w-xl" />

<div className="mt-5 grid gap-3 sm:grid-cols-2 xl:grid-cols-4">
{["first", "second", "third", "fourth"].map((item) => (
<Skeleton className="h-24 rounded-3xl" key={item} />
<Skeleton className="h-24 rounded-lg" key={item} />
))}
</div>
</div>

<div className="grid gap-4 xl:grid-cols-2">
{["mentions", "actions", "activity", "agents"].map((section) => (
<div
className="rounded-[1.75rem] border border-border/80 bg-card/80 p-5 shadow-sm"
className="rounded-xl border border-border/80 bg-card/80 p-5 shadow-sm"
key={section}
>
<Skeleton className="h-6 w-32" />
<Skeleton className="mt-3 h-4 w-full max-w-xs" />
<div className="mt-5 space-y-3">
{["a", "b", "c"].map((row) => (
<Skeleton className="h-28 rounded-3xl" key={row} />
<Skeleton className="h-28 rounded-lg" key={row} />
))}
</div>
</div>
Expand Down Expand Up @@ -364,7 +364,7 @@ export function HomeView({
return (
<div className="flex-1 overflow-y-auto overflow-x-hidden overscroll-contain px-4 py-4 sm:px-6">
<div className="mx-auto flex w-full max-w-3xl flex-col gap-4">
<div className="rounded-[1.75rem] border border-destructive/30 bg-destructive/5 px-6 py-8 shadow-sm">
<div className="rounded-xl border border-destructive/30 bg-destructive/5 px-6 py-8 shadow-sm">
<p className="text-base font-semibold tracking-tight">
Home feed unavailable
</p>
Expand All @@ -386,11 +386,11 @@ export function HomeView({
return (
<div className="flex-1 overflow-y-auto overflow-x-hidden overscroll-contain px-4 py-4 sm:px-6">
<div className="mx-auto flex w-full max-w-6xl flex-col gap-6">
<section className="rounded-[1.75rem] border border-border/80 bg-card/80 p-5 shadow-sm">
<section className="rounded-xl border border-border/80 bg-card/80 p-5 shadow-sm">
<div className="flex flex-col gap-4 lg:flex-row lg:items-end lg:justify-between">
<div className="min-w-0">
<div className="flex items-center gap-3">
<div className="flex h-12 w-12 items-center justify-center rounded-[1.25rem] bg-primary text-primary-foreground shadow-sm">
<div className="flex h-12 w-12 items-center justify-center rounded-lg bg-primary text-primary-foreground shadow-sm">
<Sparkles className="h-5 w-5" />
</div>
<div>
Expand Down
18 changes: 14 additions & 4 deletions desktop/src/features/sidebar/ui/AppSidebar.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { getCurrentWindow } from "@tauri-apps/api/window";
import {
CircleDot,
FileText,
Expand Down Expand Up @@ -294,13 +295,24 @@ export function AppSidebar({
}
}

function handleDragPointerDown(e: React.PointerEvent) {
if (e.button !== 0) return;
const target = e.target as HTMLElement;
if (target.closest('button, a, input, [role="button"]')) return;
e.preventDefault();
getCurrentWindow().startDragging();
}

return (
<Sidebar
collapsible="offcanvas"
data-testid="app-sidebar"
variant="sidebar"
>
<SidebarHeader className="gap-3">
<SidebarHeader
className="gap-3 pt-7"
onPointerDown={handleDragPointerDown}
>
<div className="flex items-center gap-3 rounded-xl bg-sidebar-accent/80 px-3 py-3">
<div className="flex h-6 w-6 items-center justify-center rounded-xl text-lg">
<span aria-hidden="true">🌱</span>
Expand All @@ -324,9 +336,7 @@ export function AppSidebar({
<Search className="h-4 w-4" />
Search messages
</span>
<span className="rounded-md border border-sidebar-border/80 px-1.5 py-0.5 text-[10px] font-semibold uppercase tracking-[0.14em] text-sidebar-foreground/60">
Cmd K
</span>
<span className="text-xs text-sidebar-foreground/50">&#x2318;K</span>
</Button>
</SidebarHeader>

Expand Down
6 changes: 3 additions & 3 deletions desktop/src/shared/ui/sidebar.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import * as React from "react";
import { Slot } from "@radix-ui/react-slot";
import { cva, type VariantProps } from "class-variance-authority";
import { PanelLeft } from "lucide-react";
import { PanelLeftClose, PanelLeftOpen } from "lucide-react";

import { cn } from "@/shared/lib/cn";
import { useIsMobile } from "@/shared/hooks/use-mobile";
Expand Down Expand Up @@ -271,7 +271,7 @@ const SidebarTrigger = React.forwardRef<
React.ElementRef<typeof Button>,
React.ComponentProps<typeof Button>
>(({ className, onClick, ...props }, ref) => {
const { toggleSidebar } = useSidebar();
const { toggleSidebar, open } = useSidebar();

return (
<Button
Expand All @@ -286,7 +286,7 @@ const SidebarTrigger = React.forwardRef<
}}
{...props}
>
<PanelLeft />
{open ? <PanelLeftClose /> : <PanelLeftOpen />}
<span className="sr-only">Toggle Sidebar</span>
</Button>
);
Expand Down
Loading