diff --git a/src/App.tsx b/src/App.tsx index 45fbf04..bf24892 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -10,6 +10,7 @@ import { import Sidebar from "./components/view/Sidebar"; import { ThemeProvider } from "next-themes"; import Page from "./components/page/PageView"; +import { SettingsDialog } from "./components/settings/SettingsDialog"; export default function App() { const appRef = useRef(null); @@ -54,6 +55,8 @@ export default function App() { + + )} diff --git a/src/app/app.ts b/src/app/app.ts index 1150284..c02b33d 100644 --- a/src/app/app.ts +++ b/src/app/app.ts @@ -28,12 +28,14 @@ export default class Enclave

{ public accounts?: AccountsFile; public server?: EnclaveServer; public serverList: ServerList; + public isSettingsOpen: boolean; public forceRender: () => void; public page?: P; public constructor() { this.serverList = {}; this.forceRender = () => {}; + this.isSettingsOpen = false; } public async init() { diff --git a/src/components/settings/AppearanceSettings.tsx b/src/components/settings/AppearanceSettings.tsx new file mode 100644 index 0000000..19e5c8f --- /dev/null +++ b/src/components/settings/AppearanceSettings.tsx @@ -0,0 +1,14 @@ +import { Palette } from "lucide-react"; + +export function AppearanceSettings() { + return ( +

+

+ Appearance +

+

+ Theme and display settings go here. +

+
+ ); +} diff --git a/src/components/settings/AudioVideoSettings.tsx b/src/components/settings/AudioVideoSettings.tsx new file mode 100644 index 0000000..11b75c2 --- /dev/null +++ b/src/components/settings/AudioVideoSettings.tsx @@ -0,0 +1,14 @@ +import { Volume2 } from "lucide-react"; + +export function AudioVideoSettings() { + return ( +
+

+ Audio & Video +

+

+ Microphone/camera device selection goes here. +

+
+ ); +} diff --git a/src/components/settings/ProfileSettings.tsx b/src/components/settings/ProfileSettings.tsx new file mode 100644 index 0000000..d6957c1 --- /dev/null +++ b/src/components/settings/ProfileSettings.tsx @@ -0,0 +1,14 @@ +import { User } from "lucide-react"; + +export function ProfileSettings() { + return ( +
+

+ Profile +

+

+ Display name and avatar settings go here. +

+
+ ); +} diff --git a/src/components/settings/SettingsDialog.tsx b/src/components/settings/SettingsDialog.tsx new file mode 100644 index 0000000..ade9c34 --- /dev/null +++ b/src/components/settings/SettingsDialog.tsx @@ -0,0 +1,74 @@ +import { useState } from "react"; +import { Dialog, DialogContent } from "@/components/ui/dialog"; +import { cn } from "@/lib/utils"; +import { User, Palette, Mic, Volume2 } from "lucide-react"; +import { ProfileSettings } from "./ProfileSettings"; +import { AppearanceSettings } from "./AppearanceSettings"; +import { AudioVideoSettings } from "./AudioVideoSettings"; +import Enclave from "@/app/app"; + +type SettingsCategory = "profile" | "appearance" | "audio-video"; + +const CATEGORIES: { + id: SettingsCategory; + label: string; + icon: React.ElementType; +}[] = [ + { id: "profile", label: "Profile", icon: User }, + { id: "appearance", label: "Appearance", icon: Palette }, + { id: "audio-video", label: "Audio & Video", icon: Volume2 }, +]; + +export function SettingsDialog({ + appRef, +}: { + appRef: React.RefObject; +}) { + const [category, setCategory] = useState("profile"); + + return ( + { + if (!appRef.current) return; + + appRef.current.isSettingsOpen = open; + appRef.current.forceRender(); + }} + > + +
+ + Settings + + +
+ +
+ {category === "profile" && } + {category === "appearance" && } + {category === "audio-video" && } +
+
+
+ ); +} diff --git a/src/components/ui/dialog.tsx b/src/components/ui/dialog.tsx index 3fc1dda..3770278 100644 --- a/src/components/ui/dialog.tsx +++ b/src/components/ui/dialog.tsx @@ -1,24 +1,24 @@ -import * as React from "react" -import { Dialog as DialogPrimitive } from "@base-ui/react/dialog" +import * as React from "react"; +import { Dialog as DialogPrimitive } from "@base-ui/react/dialog"; -import { cn } from "@/lib/utils" -import { Button } from "@/components/ui/button" -import { XIcon } from "lucide-react" +import { cn } from "@/lib/utils"; +import { Button } from "@/components/ui/button"; +import { XIcon } from "lucide-react"; function Dialog({ ...props }: DialogPrimitive.Root.Props) { - return + return ; } function DialogTrigger({ ...props }: DialogPrimitive.Trigger.Props) { - return + return ; } function DialogPortal({ ...props }: DialogPrimitive.Portal.Props) { - return + return ; } function DialogClose({ ...props }: DialogPrimitive.Close.Props) { - return + return ; } function DialogOverlay({ @@ -29,12 +29,12 @@ function DialogOverlay({ - ) + ); } function DialogContent({ @@ -43,7 +43,7 @@ function DialogContent({ showCloseButton = true, ...props }: DialogPrimitive.Popup.Props & { - showCloseButton?: boolean + showCloseButton?: boolean; }) { return ( @@ -52,7 +52,7 @@ function DialogContent({ data-slot="dialog-content" className={cn( "fixed top-1/2 left-1/2 z-50 grid w-full max-w-[calc(100%-2rem)] -translate-x-1/2 -translate-y-1/2 gap-4 rounded-xl bg-popover p-4 text-sm text-popover-foreground ring-1 ring-foreground/10 duration-100 outline-none sm:max-w-sm data-open:animate-in data-open:fade-in-0 data-open:zoom-in-95 data-closed:animate-out data-closed:fade-out-0 data-closed:zoom-out-95", - className + className, )} {...props} > @@ -68,14 +68,13 @@ function DialogContent({ /> } > - + Close )} - ) + ); } function DialogHeader({ className, ...props }: React.ComponentProps<"div">) { @@ -85,7 +84,7 @@ function DialogHeader({ className, ...props }: React.ComponentProps<"div">) { className={cn("flex flex-col gap-2", className)} {...props} /> - ) + ); } function DialogFooter({ @@ -94,14 +93,14 @@ function DialogFooter({ children, ...props }: React.ComponentProps<"div"> & { - showCloseButton?: boolean + showCloseButton?: boolean; }) { return (
@@ -112,7 +111,7 @@ function DialogFooter({ )}
- ) + ); } function DialogTitle({ className, ...props }: DialogPrimitive.Title.Props) { @@ -121,11 +120,11 @@ function DialogTitle({ className, ...props }: DialogPrimitive.Title.Props) { data-slot="dialog-title" className={cn( "font-heading text-base leading-none font-medium", - className + className, )} {...props} /> - ) + ); } function DialogDescription({ @@ -137,11 +136,11 @@ function DialogDescription({ data-slot="dialog-description" className={cn( "text-sm text-muted-foreground *:[a]:underline *:[a]:underline-offset-3 *:[a]:hover:text-foreground", - className + className, )} {...props} /> - ) + ); } export { @@ -155,4 +154,4 @@ export { DialogPortal, DialogTitle, DialogTrigger, -} +}; diff --git a/src/components/view/AccountCard.tsx b/src/components/view/AccountCard.tsx index 67b8a9a..d5d63e4 100644 --- a/src/components/view/AccountCard.tsx +++ b/src/components/view/AccountCard.tsx @@ -41,7 +41,16 @@ export default function AccountCard({
-