diff --git a/apps/tauri/package.json b/apps/tauri/package.json index 4253c23..c2c3cff 100644 --- a/apps/tauri/package.json +++ b/apps/tauri/package.json @@ -4,24 +4,25 @@ "version": "0.0.0", "type": "module", "exports": { - "./context": "./src/context.tsx" + "./context": "./src/context.tsx", + "./controls": "./src/windowControls.tsx" }, "scripts": { "dev:mobile:raw": "tauri android dev", "build:mobile:raw": "tauri android build", "dev:mobile": "if command -v nix >/dev/null 2>&1; then nix develop --command bun dev:mobile:raw; else bun dev:mobile:raw; fi", "build:mobile": "if command -v nix >/dev/null 2>&1; then nix develop --command bun build:mobile:raw; else bun build:mobile:raw; fi", - "dev:desktop:raw": "tauri dev", "build:desktop:raw": "tauri build", "dev:desktop": "if command -v nix >/dev/null 2>&1; then nix develop --command bun dev:desktop:raw; else bun dev:desktop:raw; fi", "build:desktop": "if command -v nix >/dev/null 2>&1; then nix develop --command bun build:desktop:raw; else bun build:desktop:raw; fi", - "gen-icons": "tauri icon ./logo.png" }, "dependencies": { "@tauri-apps/api": "^2", "@tauri-apps/plugin-opener": "^2", + "@tensamin/ui": "workspace:*", + "lucide-react": "^1.7.0", "react": "^19.2.0", "react-dom": "^19.2.0" }, diff --git a/apps/tauri/readme.md b/apps/tauri/readme.md index ff047a2..38cb730 100644 --- a/apps/tauri/readme.md +++ b/apps/tauri/readme.md @@ -1,4 +1,5 @@ # Outputs + - ./src-tauri/gen/android/app/build/outputs/apk/universal/release/app-universal-release.apk -- ./src-tauri/target/release/bundle/deb/Tensamin_{version}_{arch}.deb +- ./src-tauri/target/release/bundle/deb/Tensamin*{version}*{arch}.deb - ./src-tauri/target/release/bundle/rpm/Tensamin-{version}-1.{arch}.rpm diff --git a/apps/tauri/src-tauri/capabilities/default.json b/apps/tauri/src-tauri/capabilities/default.json index f778364..63f70d5 100644 --- a/apps/tauri/src-tauri/capabilities/default.json +++ b/apps/tauri/src-tauri/capabilities/default.json @@ -2,6 +2,16 @@ "$schema": "../gen/schemas/desktop-schema.json", "identifier": "default", "description": "Capability for the main window", - "windows": ["main"], - "permissions": ["core:default", "opener:default"] -} + "windows": [ + "main" + ], + "permissions": [ + "core:default", + "opener:default", + "core:window:default", + "core:window:allow-start-dragging", + "core:window:allow-close", + "core:window:allow-toggle-maximize", + "core:window:allow-minimize" + ] +} \ No newline at end of file diff --git a/apps/tauri/src/windowControls.tsx b/apps/tauri/src/windowControls.tsx new file mode 100644 index 0000000..a114dcb --- /dev/null +++ b/apps/tauri/src/windowControls.tsx @@ -0,0 +1,53 @@ +import { Maximize, Minus, X } from "lucide-react"; +import { Button, buttonVariants } from "@tensamin/ui/cmp/button"; + +import { isTauri } from "@tauri-apps/api/core"; +import { getCurrentWindow } from "@tauri-apps/api/window"; +import { cn, useIsMobile } from "@tensamin/ui/utils"; +import { Card } from "@tensamin/ui/cmp/card"; + +export default function Controls({ + className, + notPresentClassName, +}: { + className?: string; + notPresentClassName?: string; +}) { + const isMobile = useIsMobile(); + if (!isTauri() || isMobile) return
; + + const currentWindow = getCurrentWindow(); + + return ( + + <> + + + + + + ); +} diff --git a/apps/web/src/components/navbar.tsx b/apps/web/src/components/navbar.tsx index 82366e4..7b95efa 100644 --- a/apps/web/src/components/navbar.tsx +++ b/apps/web/src/components/navbar.tsx @@ -14,6 +14,7 @@ import { displayCallId } from "@tensamin/call/utils"; import { useState } from "react"; import { SidebarTrigger, useSidebar } from "@tensamin/ui/cmp/sidebar"; import { useTTP } from "@tensamin/ttp/context"; +import Controls from "@tensamin/tauri/controls"; export default function Navbar({ forMobile }: { forMobile: boolean }) { const navigate = useNavigate(); @@ -30,7 +31,8 @@ export default function Navbar({ forMobile }: { forMobile: boolean }) { return (
{forMobile ? ( } /> )} -
+ {/* Empty space */} {pathname === "/chat" && id && ( <> {currentCalls.length === 0 ? ( @@ -77,7 +79,7 @@ export default function Navbar({ forMobile }: { forMobile: boolean }) { onClick={() => { joinCall(id, currentCalls[0]); }} - className="w-9 h-9 aspect-square rounded-lg mr-2" + className="w-9 h-9 aspect-square rounded-lg" > @@ -85,7 +87,7 @@ export default function Navbar({ forMobile }: { forMobile: boolean }) { <> @@ -109,6 +111,7 @@ export default function Navbar({ forMobile }: { forMobile: boolean }) { )} )} +
); } diff --git a/apps/web/src/components/sidebar.tsx b/apps/web/src/components/sidebar.tsx index f4276f2..50a54bc 100644 --- a/apps/web/src/components/sidebar.tsx +++ b/apps/web/src/components/sidebar.tsx @@ -23,7 +23,9 @@ export default function Sidebar() { return (
diff --git a/apps/web/src/features/legal/screen.tsx b/apps/web/src/features/legal/screen.tsx index 9dd388b..171fab4 100644 --- a/apps/web/src/features/legal/screen.tsx +++ b/apps/web/src/features/legal/screen.tsx @@ -10,6 +10,7 @@ import { legalDocsSchema } from "@tensamin/shared/features/legal/schema"; import { log } from "@tensamin/shared/log"; import Link from "@tensamin/ui/link"; import { Label } from "@tensamin/ui/cmp/label"; +import CreateScreen from "@tensamin/ui/screens/util"; // Prevents the user from using Tensamin without accepting the privacy policy and terms of service. export default function Screen(props: { children: React.ReactNode }) { @@ -160,7 +161,7 @@ export default function Screen(props: { children: React.ReactNode }) { } return ( -
+

Privacy Policy & ToS @@ -198,7 +199,7 @@ export default function Screen(props: { children: React.ReactNode }) { onClick={handleContinueLegal} />

-
+ ); } diff --git a/apps/web/src/index.tsx b/apps/web/src/index.tsx index 8b3641f..be49329 100644 --- a/apps/web/src/index.tsx +++ b/apps/web/src/index.tsx @@ -17,7 +17,6 @@ import Home from "@/routes/app/home"; import ChatScreen from "@tensamin/chat/screen"; import CallScreen from "@tensamin/call/screen"; import Login from "@/routes/screens/login"; -import Signup from "@/routes/screens/signup"; import ChatContext from "@tensamin/chat/context"; import CallContext from "@tensamin/call/context"; @@ -117,16 +116,9 @@ const loginRoute = createRoute({ component: Login, }); -const signupRoute = createRoute({ - getParentRoute: () => rootRoute, - path: "signup", - component: Signup, -}); - const routeTree = rootRoute.addChildren([ appRoute.addChildren([homeRoute, chatRoute, callRoute]), loginRoute, - signupRoute, ]); const router = createRouter({ diff --git a/apps/web/src/routes/screens/login.tsx b/apps/web/src/routes/screens/login.tsx index 84b5d44..d6c3b2d 100644 --- a/apps/web/src/routes/screens/login.tsx +++ b/apps/web/src/routes/screens/login.tsx @@ -1,4 +1,5 @@ import Form from "@/components/screens/login/form"; +import CreateScreen from "@tensamin/ui/screens/util"; /** * Executes Page. @@ -7,7 +8,7 @@ import Form from "@/components/screens/login/form"; */ export default function Page() { return ( - + ); } diff --git a/apps/web/src/routes/screens/signup.tsx b/apps/web/src/routes/screens/signup.tsx deleted file mode 100644 index e3697ad..0000000 --- a/apps/web/src/routes/screens/signup.tsx +++ /dev/null @@ -1,8 +0,0 @@ -/** - * Executes Page. - * @param none This function has no parameters. - * @returns unknown. - */ -export default function Page() { - return
Signup Page
; -} diff --git a/bun.lock b/bun.lock index 5688e14..c79a9a8 100644 --- a/bun.lock +++ b/bun.lock @@ -24,6 +24,8 @@ "dependencies": { "@tauri-apps/api": "^2", "@tauri-apps/plugin-opener": "^2", + "@tensamin/ui": "workspace:*", + "lucide-react": "^1.7.0", "react": "^19.2.0", "react-dom": "^19.2.0", }, @@ -194,6 +196,7 @@ "version": "0.0.0", "dependencies": { "@base-ui/react": "^1.3.0", + "@tensamin/tauri": "workspace:*", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", "lucide-react": "^0.564.0", @@ -1402,6 +1405,8 @@ "@tensamin/notifications/@tensamin/ttp": ["TTP@github:Tensamin/TTP#e246d1a", {}, "Tensamin-TTP-e246d1a"], + "@tensamin/tauri/lucide-react": ["lucide-react@1.7.0", "", { "peerDependencies": { "react": "^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, "sha512-yI7BeItCLZJTXikmK4KNUGCKoGzSvbKlfCvw44bU4fXAL6v3gYS4uHD1jzsLkfwODYwI6Drw5Tu9Z5ulDe0TSg=="], + "@tensamin/ui/sonner": ["sonner@2.0.7", "", { "peerDependencies": { "react": "^18.0.0 || ^19.0.0 || ^19.0.0-rc", "react-dom": "^18.0.0 || ^19.0.0 || ^19.0.0-rc" } }, "sha512-W6ZN4p58k8aDKA4XPcx2hpIQXBRAgyiWVkYhT7CvK6D3iAu7xjvVyhQHg2/iaKJZ1XVJ4r7XuwGL+WGEK37i9w=="], "@typescript-eslint/eslint-plugin/ignore": ["ignore@7.0.5", "", {}, "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg=="], diff --git a/packages/shared/src/log.tsx b/packages/shared/src/log.tsx index 3af4597..3109c95 100644 --- a/packages/shared/src/log.tsx +++ b/packages/shared/src/log.tsx @@ -45,7 +45,9 @@ export function log( return; } - console.groupCollapsed(`${colorCodes[color]}${logger}${resetCode} ${args[0]}`); + console.groupCollapsed( + `${colorCodes[color]}${logger}${resetCode} ${args[0]}`, + ); try { for (const arg of args.slice(1)) { console.log(arg); diff --git a/packages/ttp/src/context.tsx b/packages/ttp/src/context.tsx index 907e66f..0f54f1e 100644 --- a/packages/ttp/src/context.tsx +++ b/packages/ttp/src/context.tsx @@ -189,8 +189,8 @@ export default function Provider(props: { * Sends typed protocol messages through the active transport client. * @param type Protocol message type. * @param data Optional request payload. - * @param options Optional request id. - * @returns A promise for the typed message payload. + * @param options Optional request id. + * @returns A promise for the typed message payload. */ const send = useCallback>( (( diff --git a/packages/ttp/src/core.test.ts b/packages/ttp/src/core.test.ts index 007b7b4..6b5e63b 100644 --- a/packages/ttp/src/core.test.ts +++ b/packages/ttp/src/core.test.ts @@ -61,9 +61,9 @@ function createMockWebTransport() { let readyResolve!: () => void; let closedResolve!: () => void; - let incomingController: - | ReadableStreamDefaultController> - | null = null; + let incomingController: ReadableStreamDefaultController< + ReadableStream + > | null = null; const outgoingMessages: TypedMessage[] = []; const ready = new Promise((resolve) => { @@ -426,7 +426,11 @@ describe("Core Protocol", () => { const firstSend = client.send("ping", {}); const secondSend = client.send("ping", {}); - for (let attempt = 0; attempt < 10 && outgoingMessages.length === 0; attempt += 1) { + for ( + let attempt = 0; + attempt < 10 && outgoingMessages.length === 0; + attempt += 1 + ) { await Promise.resolve(); } @@ -439,7 +443,11 @@ describe("Core Protocol", () => { }); await firstSend; - for (let attempt = 0; attempt < 10 && outgoingMessages.length === 1; attempt += 1) { + for ( + let attempt = 0; + attempt < 10 && outgoingMessages.length === 1; + attempt += 1 + ) { await Promise.resolve(); } diff --git a/packages/ttp/src/core.ts b/packages/ttp/src/core.ts index 3cfabba..588e409 100644 --- a/packages/ttp/src/core.ts +++ b/packages/ttp/src/core.ts @@ -523,8 +523,8 @@ export function createTransportClient( * Sends a typed protocol request over the current connection. * @param type Protocol message type. * @param input Optional request payload. - * @param options Optional request id. - * @returns Promise for the typed response message. + * @param options Optional request id. + * @returns Promise for the typed response message. */ const send: BoundSendFn = (( type: string, @@ -612,14 +612,15 @@ export function createTransportClient( timeoutId, }); - void writeMessageOnPersistentStream(enqueuedConnection, messageBytes).catch( - (error) => { - handleConnectionFailure(enqueuedConnection, error); - clearTimeout(timeoutId); - pending.delete(requestId); - reject(error); - }, - ); + void writeMessageOnPersistentStream( + enqueuedConnection, + messageBytes, + ).catch((error) => { + handleConnectionFailure(enqueuedConnection, error); + clearTimeout(timeoutId); + pending.delete(requestId); + reject(error); + }); }); }); } catch (error) { diff --git a/packages/ui/package.json b/packages/ui/package.json index d28a010..d523bc0 100644 --- a/packages/ui/package.json +++ b/packages/ui/package.json @@ -17,6 +17,7 @@ "build": "tsc -p tsconfig.json --noEmit" }, "dependencies": { + "@tensamin/tauri": "workspace:*", "@base-ui/react": "^1.3.0", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", diff --git a/packages/ui/src/cmp/button.tsx b/packages/ui/src/cmp/button.tsx index 96b2139..68d2e3b 100644 --- a/packages/ui/src/cmp/button.tsx +++ b/packages/ui/src/cmp/button.tsx @@ -12,7 +12,7 @@ const buttonVariants = cva( variant: { default: "bg-primary text-primary-foreground [a]:hover:bg-primary/80", outline: - "border-border bg-background hover:bg-muted hover:text-foreground aria-expanded:bg-muted aria-expanded:text-foreground dark:border-input dark:bg-input/30 dark:hover:bg-input/50", + "border-border bg-background hover:bg-muted hover:text-foreground aria-expanded:bg-muted aria-expanded:text-foreground dark:bg-input/30 dark:hover:bg-input/50", secondary: "bg-secondary text-secondary-foreground hover:bg-secondary/80 aria-expanded:bg-secondary aria-expanded:text-secondary-foreground", ghost: diff --git a/packages/ui/src/screens/error.tsx b/packages/ui/src/screens/error.tsx index 99e671a..8d5cfa4 100644 --- a/packages/ui/src/screens/error.tsx +++ b/packages/ui/src/screens/error.tsx @@ -1,4 +1,5 @@ import Link from "../link"; +import CreateScreen from "./util"; /** * Executes Screen. @@ -7,12 +8,12 @@ import Link from "../link"; */ export default function Screen(props: { error: string; description: string }) { return ( -
+

{props.error}

{props.description}

-
+ ); } diff --git a/packages/ui/src/screens/loading.tsx b/packages/ui/src/screens/loading.tsx index 7ebebab..b1c2720 100644 --- a/packages/ui/src/screens/loading.tsx +++ b/packages/ui/src/screens/loading.tsx @@ -1,4 +1,5 @@ import * as React from "react"; +import CreateScreen from "./util"; const DELAY = 250; @@ -58,14 +59,8 @@ export default function Screen(props: ScreenProps) { }; }, [props.progress]); - const wrapperClass = props.fullscreen - ? "fixed inset-0 z-50 bg-background" - : "bg-background w-full h-screen"; - return ( -
+

{props.title ?? "Loading"}

@@ -84,6 +79,6 @@ export default function Screen(props: ScreenProps) { }} />
-
+ ); } diff --git a/packages/ui/src/screens/util.tsx b/packages/ui/src/screens/util.tsx new file mode 100644 index 0000000..adc4c45 --- /dev/null +++ b/packages/ui/src/screens/util.tsx @@ -0,0 +1,19 @@ +import Controls from "@tensamin/tauri/controls"; + +export default function CreateScreen({ + children, +}: { + children: React.ReactNode; +}) { + return ( +
+ <> + + {children} + +
+ ); +}