Profile view #33
This commit is contained in:
Generated
+38
@@ -16,6 +16,7 @@
|
|||||||
"@radix-ui/react-dialog": "^1.1.15",
|
"@radix-ui/react-dialog": "^1.1.15",
|
||||||
"@radix-ui/react-dropdown-menu": "^2.1.16",
|
"@radix-ui/react-dropdown-menu": "^2.1.16",
|
||||||
"@radix-ui/react-label": "^2.1.7",
|
"@radix-ui/react-label": "^2.1.7",
|
||||||
|
"@radix-ui/react-popover": "^1.1.15",
|
||||||
"@radix-ui/react-scroll-area": "^1.2.10",
|
"@radix-ui/react-scroll-area": "^1.2.10",
|
||||||
"@radix-ui/react-select": "^2.2.6",
|
"@radix-ui/react-select": "^2.2.6",
|
||||||
"@radix-ui/react-separator": "^1.1.7",
|
"@radix-ui/react-separator": "^1.1.7",
|
||||||
@@ -1422,6 +1423,43 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@radix-ui/react-popover": {
|
||||||
|
"version": "1.1.15",
|
||||||
|
"resolved": "https://registry.npmjs.org/@radix-ui/react-popover/-/react-popover-1.1.15.tgz",
|
||||||
|
"integrity": "sha512-kr0X2+6Yy/vJzLYJUPCZEc8SfQcf+1COFoAqauJm74umQhta9M7lNJHP7QQS3vkvcGLQUbWpMzwrXYwrYztHKA==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@radix-ui/primitive": "1.1.3",
|
||||||
|
"@radix-ui/react-compose-refs": "1.1.2",
|
||||||
|
"@radix-ui/react-context": "1.1.2",
|
||||||
|
"@radix-ui/react-dismissable-layer": "1.1.11",
|
||||||
|
"@radix-ui/react-focus-guards": "1.1.3",
|
||||||
|
"@radix-ui/react-focus-scope": "1.1.7",
|
||||||
|
"@radix-ui/react-id": "1.1.1",
|
||||||
|
"@radix-ui/react-popper": "1.2.8",
|
||||||
|
"@radix-ui/react-portal": "1.1.9",
|
||||||
|
"@radix-ui/react-presence": "1.1.5",
|
||||||
|
"@radix-ui/react-primitive": "2.1.3",
|
||||||
|
"@radix-ui/react-slot": "1.2.3",
|
||||||
|
"@radix-ui/react-use-controllable-state": "1.2.2",
|
||||||
|
"aria-hidden": "^1.2.4",
|
||||||
|
"react-remove-scroll": "^2.6.3"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@types/react": "*",
|
||||||
|
"@types/react-dom": "*",
|
||||||
|
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
|
||||||
|
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"@types/react": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"@types/react-dom": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@radix-ui/react-popper": {
|
"node_modules/@radix-ui/react-popper": {
|
||||||
"version": "1.2.8",
|
"version": "1.2.8",
|
||||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-popper/-/react-popper-1.2.8.tgz",
|
"resolved": "https://registry.npmjs.org/@radix-ui/react-popper/-/react-popper-1.2.8.tgz",
|
||||||
|
|||||||
@@ -19,6 +19,7 @@
|
|||||||
"@radix-ui/react-dialog": "^1.1.15",
|
"@radix-ui/react-dialog": "^1.1.15",
|
||||||
"@radix-ui/react-dropdown-menu": "^2.1.16",
|
"@radix-ui/react-dropdown-menu": "^2.1.16",
|
||||||
"@radix-ui/react-label": "^2.1.7",
|
"@radix-ui/react-label": "^2.1.7",
|
||||||
|
"@radix-ui/react-popover": "^1.1.15",
|
||||||
"@radix-ui/react-scroll-area": "^1.2.10",
|
"@radix-ui/react-scroll-area": "^1.2.10",
|
||||||
"@radix-ui/react-select": "^2.2.6",
|
"@radix-ui/react-select": "^2.2.6",
|
||||||
"@radix-ui/react-separator": "^1.1.7",
|
"@radix-ui/react-separator": "^1.1.7",
|
||||||
|
|||||||
+5
-11
@@ -1,6 +1,6 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import ProfilePicture from "@/components/ProfilePicture";
|
import ProfilePreview, { ProfileImage } from "@/components/ProfilePicture";
|
||||||
import SettingsDialog from "@/components/settings/SettingsDialog";
|
import SettingsDialog from "@/components/settings/SettingsDialog";
|
||||||
import AppLayout from "@/components/app/AppLayout";
|
import AppLayout from "@/components/app/AppLayout";
|
||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
@@ -93,10 +93,7 @@ export default function ChatHub() {
|
|||||||
className="flex justify-between items-center hover:bg-accent hover:text-accent-foreground rounded p-2 transition"
|
className="flex justify-between items-center hover:bg-accent hover:text-accent-foreground rounded p-2 transition"
|
||||||
>
|
>
|
||||||
<span className="flex gap-2">
|
<span className="flex gap-2">
|
||||||
<ProfilePicture
|
<ProfilePreview profile={dm} />
|
||||||
name={dm.display_name}
|
|
||||||
url={dm.avatar_url}
|
|
||||||
/>
|
|
||||||
<span className="truncate my-auto">
|
<span className="truncate my-auto">
|
||||||
{dm.display_name || dm.id}
|
{dm.display_name || dm.id}
|
||||||
</span>
|
</span>
|
||||||
@@ -129,7 +126,7 @@ export default function ChatHub() {
|
|||||||
className="flex justify-between items-center hover:bg-accent hover:text-accent-foreground rounded p-2 transition"
|
className="flex justify-between items-center hover:bg-accent hover:text-accent-foreground rounded p-2 transition"
|
||||||
>
|
>
|
||||||
<span className="flex gap-2">
|
<span className="flex gap-2">
|
||||||
<ProfilePicture
|
<ProfileImage
|
||||||
name={srv.name}
|
name={srv.name}
|
||||||
url={srv.icon_url || ""}
|
url={srv.icon_url || ""}
|
||||||
/>
|
/>
|
||||||
@@ -167,10 +164,7 @@ export default function ChatHub() {
|
|||||||
className="flex items-center justify-between hover:bg-accent rounded p-2 transition"
|
className="flex items-center justify-between hover:bg-accent rounded p-2 transition"
|
||||||
>
|
>
|
||||||
<div className="flex items-center gap-3">
|
<div className="flex items-center gap-3">
|
||||||
<ProfilePicture
|
<ProfilePreview profile={user || undefined} />
|
||||||
name={user?.display_name || ""}
|
|
||||||
url={user?.avatar_url || ""}
|
|
||||||
/>
|
|
||||||
<div>
|
<div>
|
||||||
<p className="font-medium">
|
<p className="font-medium">
|
||||||
{user?.display_name || ""}
|
{user?.display_name || ""}
|
||||||
@@ -233,7 +227,7 @@ export default function ChatHub() {
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<CardContent className="p-4 flex flex-col items-center text-center gap-2">
|
<CardContent className="p-4 flex flex-col items-center text-center gap-2">
|
||||||
<ProfilePicture name={srv.name} url={srv.icon_url} />
|
<ProfileImage name={srv.name} url={srv.icon_url} />
|
||||||
<h3 className="font-medium truncate">{srv.name}</h3>
|
<h3 className="font-medium truncate">{srv.name}</h3>
|
||||||
</CardContent>
|
</CardContent>
|
||||||
</Card>
|
</Card>
|
||||||
|
|||||||
@@ -1,19 +1,80 @@
|
|||||||
import { cn } from "@/lib/utils";
|
import { cn } from "@/lib/utils";
|
||||||
import { Avatar, AvatarFallback, AvatarImage } from "./ui/avatar";
|
import { Avatar, AvatarFallback, AvatarImage } from "./ui/avatar";
|
||||||
|
import { Popover, PopoverTrigger, PopoverContent } from "./ui/popover";
|
||||||
|
import { Button } from "./ui/button";
|
||||||
|
import { UserProfile } from "@/hooks/get-user";
|
||||||
|
|
||||||
export default function ProfilePicture({
|
export function ProfileImage({
|
||||||
name,
|
name,
|
||||||
url,
|
url,
|
||||||
className,
|
className,
|
||||||
}: {
|
}: {
|
||||||
name: string;
|
name: string;
|
||||||
url: string | undefined;
|
url: string;
|
||||||
className?: string;
|
className?: string;
|
||||||
}) {
|
}) {
|
||||||
return (
|
return (
|
||||||
<Avatar className={cn("h-8 w-8", className)}>
|
<Avatar className={cn("h-8 w-8 cursor-pointer", className)}>
|
||||||
<AvatarImage src={url} alt={name} />
|
<AvatarImage src={url} alt={name} />
|
||||||
<AvatarFallback>{name[0]}</AvatarFallback>
|
<AvatarFallback>{name[0]}</AvatarFallback>
|
||||||
</Avatar>
|
</Avatar>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export default function ProfilePreview({
|
||||||
|
className,
|
||||||
|
profile,
|
||||||
|
}: {
|
||||||
|
profile?: UserProfile;
|
||||||
|
className?: string;
|
||||||
|
}) {
|
||||||
|
if (!profile)
|
||||||
|
return (
|
||||||
|
<Avatar className={cn("h-8 w-8 cursor-pointer", className)}>
|
||||||
|
<AvatarFallback>Loading</AvatarFallback>
|
||||||
|
</Avatar>
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Popover>
|
||||||
|
<PopoverTrigger asChild>
|
||||||
|
<Avatar className={cn("h-8 w-8 cursor-pointer", className)}>
|
||||||
|
<AvatarImage src={profile.avatar_url} alt={profile.display_name} />
|
||||||
|
<AvatarFallback>{profile.display_name[0]}</AvatarFallback>
|
||||||
|
</Avatar>
|
||||||
|
</PopoverTrigger>
|
||||||
|
|
||||||
|
<PopoverContent
|
||||||
|
side="right"
|
||||||
|
align="center"
|
||||||
|
sideOffset={8}
|
||||||
|
className="w-64 p-4"
|
||||||
|
>
|
||||||
|
<div className="flex items-center gap-4">
|
||||||
|
<Avatar className={cn("h-8 w-8 cursor-pointer", className)}>
|
||||||
|
<AvatarImage src={profile.avatar_url} alt={profile.display_name} />
|
||||||
|
<AvatarFallback>{profile.display_name[0]}</AvatarFallback>
|
||||||
|
</Avatar>
|
||||||
|
|
||||||
|
<div className="flex flex-col">
|
||||||
|
<span className="font-medium leading-none">
|
||||||
|
{profile.display_name}
|
||||||
|
</span>
|
||||||
|
<span className="text-sm text-muted-foreground">
|
||||||
|
@{profile.username}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="mt-4 flex gap-2">
|
||||||
|
<Button size="sm" className="flex-1">
|
||||||
|
Message
|
||||||
|
</Button>
|
||||||
|
{/* <Button size="sm" variant="outline" className="flex-1">
|
||||||
|
Message
|
||||||
|
</Button> */}
|
||||||
|
</div>
|
||||||
|
</PopoverContent>
|
||||||
|
</Popover>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|||||||
@@ -91,9 +91,8 @@ export default function AppLayout({
|
|||||||
|
|
||||||
<footer className="mt-auto pb-3 px-3">
|
<footer className="mt-auto pb-3 px-3">
|
||||||
<DMItem
|
<DMItem
|
||||||
name={app.profile?.display_name || "Loading.."}
|
profile={app.profile}
|
||||||
id={app.profile?.id || "me"}
|
id={app.profile?.id || "me"}
|
||||||
avatar={app.profile?.avatar_url || ""}
|
|
||||||
status="online"
|
status="online"
|
||||||
app={app}
|
app={app}
|
||||||
settings
|
settings
|
||||||
|
|||||||
@@ -1,24 +1,23 @@
|
|||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import Link from "next/link";
|
import Link from "next/link";
|
||||||
import ProfilePicture from "../ProfilePicture";
|
import ProfilePreview from "../ProfilePicture";
|
||||||
import SettingsDialog from "../settings/SettingsDialog";
|
import SettingsDialog from "../settings/SettingsDialog";
|
||||||
import App from "@/types/app";
|
import App from "@/types/app";
|
||||||
import { ProfileSettings } from "@/types/settings";
|
import { ProfileSettings } from "@/types/settings";
|
||||||
|
import { UserProfile } from "@/hooks/get-user";
|
||||||
|
|
||||||
export default function DMItem({
|
export default function DMItem({
|
||||||
name,
|
|
||||||
id,
|
|
||||||
avatar,
|
|
||||||
status,
|
status,
|
||||||
settings,
|
settings,
|
||||||
app,
|
app,
|
||||||
|
profile,
|
||||||
|
id,
|
||||||
}: {
|
}: {
|
||||||
name: string;
|
profile?: UserProfile | null;
|
||||||
id: string;
|
|
||||||
avatar: string;
|
|
||||||
status: string;
|
|
||||||
settings?: boolean;
|
settings?: boolean;
|
||||||
|
id: string;
|
||||||
|
status: string;
|
||||||
app: App;
|
app: App;
|
||||||
}) {
|
}) {
|
||||||
return (
|
return (
|
||||||
@@ -26,11 +25,15 @@ export default function DMItem({
|
|||||||
href={settings ? "" : `/chat/${id}`}
|
href={settings ? "" : `/chat/${id}`}
|
||||||
className="p-2 flex items-center gap-2 cursor-pointer hover:bg-accent rounded-md"
|
className="p-2 flex items-center gap-2 cursor-pointer hover:bg-accent rounded-md"
|
||||||
>
|
>
|
||||||
<ProfilePicture name={name} url={avatar} />
|
{profile && (
|
||||||
|
<>
|
||||||
|
<ProfilePreview profile={profile} />
|
||||||
<div className="flex flex-col">
|
<div className="flex flex-col">
|
||||||
<span className="text-sm font-medium">{name}</span>
|
<span className="text-sm font-medium">{profile.display_name}</span>
|
||||||
<span className="text-xs text-muted-foreground">{status}</span>
|
<span className="text-xs text-muted-foreground">{status}</span>
|
||||||
</div>
|
</div>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
{settings && (
|
{settings && (
|
||||||
<SettingsDialog
|
<SettingsDialog
|
||||||
className="ml-auto w-7 h-7 p-0 flex items-center justify-center"
|
className="ml-auto w-7 h-7 p-0 flex items-center justify-center"
|
||||||
|
|||||||
@@ -65,9 +65,8 @@ export default function SidebarDMs({ app }: { app: App }) {
|
|||||||
{dms.map((user) => (
|
{dms.map((user) => (
|
||||||
<DMItem
|
<DMItem
|
||||||
key={user.id}
|
key={user.id}
|
||||||
name={user.display_name}
|
profile={user}
|
||||||
id={user.id}
|
id={user.id}
|
||||||
avatar={user.avatar_url}
|
|
||||||
status="online"
|
status="online"
|
||||||
app={app}
|
app={app}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ import { Label } from "../ui/label";
|
|||||||
import { toast } from "sonner";
|
import { toast } from "sonner";
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
import App from "@/types/app";
|
import App from "@/types/app";
|
||||||
import ProfilePicture from "../ProfilePicture";
|
import ProfilePreview, { ProfileImage } from "../ProfilePicture";
|
||||||
import SettingsDialog from "../settings/SettingsDialog";
|
import SettingsDialog from "../settings/SettingsDialog";
|
||||||
import { useRouter } from "next/navigation";
|
import { useRouter } from "next/navigation";
|
||||||
import { getServerById } from "@/actions/get-server";
|
import { getServerById } from "@/actions/get-server";
|
||||||
@@ -52,7 +52,7 @@ export default function SidebarServers({ app }: { app: App }) {
|
|||||||
(srv, i) =>
|
(srv, i) =>
|
||||||
srv && (
|
srv && (
|
||||||
<Link href={`/server/${srv.id}`} key={i}>
|
<Link href={`/server/${srv.id}`} key={i}>
|
||||||
<ProfilePicture name={srv.name} url={srv.icon_url} />
|
<ProfileImage name={srv.name} url={srv.icon_url} />
|
||||||
</Link>
|
</Link>
|
||||||
)
|
)
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ import { format, isToday, isYesterday } from "date-fns";
|
|||||||
import ReactMarkdown from "react-markdown";
|
import ReactMarkdown from "react-markdown";
|
||||||
import remarkGfm from "remark-gfm";
|
import remarkGfm from "remark-gfm";
|
||||||
import { UserProfile } from "@/hooks/get-user";
|
import { UserProfile } from "@/hooks/get-user";
|
||||||
import ProfilePicture from "../ProfilePicture";
|
import ProfilePreview, { ProfileImage } from "../ProfilePicture";
|
||||||
import App, { SetState } from "@/types/app";
|
import App, { SetState } from "@/types/app";
|
||||||
import { Textarea } from "../ui/textarea";
|
import { Textarea } from "../ui/textarea";
|
||||||
import {
|
import {
|
||||||
@@ -60,10 +60,7 @@ function MessageContainer({
|
|||||||
<div className="flex flex-col gap-3 rounded-lg p-4 hover:bg-accent">
|
<div className="flex flex-col gap-3 rounded-lg p-4 hover:bg-accent">
|
||||||
<div className="flex gap-2">
|
<div className="flex gap-2">
|
||||||
{/* <div className="w-8 h-8 rounded-full bg-gray-400" /> */}
|
{/* <div className="w-8 h-8 rounded-full bg-gray-400" /> */}
|
||||||
<ProfilePicture
|
<ProfilePreview profile={profile || undefined} />
|
||||||
url={profile?.avatar_url}
|
|
||||||
name={profile?.display_name || message.from}
|
|
||||||
/>
|
|
||||||
<div className="flex flex-col flex-1">
|
<div className="flex flex-col flex-1">
|
||||||
<span className="font-bold flex gap-1 items-center select-none">
|
<span className="font-bold flex gap-1 items-center select-none">
|
||||||
{profile?.display_name || message.from}
|
{profile?.display_name || message.from}
|
||||||
@@ -379,7 +376,7 @@ export default function MessageBox({
|
|||||||
<ChevronLeftIcon className="w-5 h-5 my-auto md:hidden" />
|
<ChevronLeftIcon className="w-5 h-5 my-auto md:hidden" />
|
||||||
<span className="flex items-center gap-1.5">
|
<span className="flex items-center gap-1.5">
|
||||||
{channelIcon && (
|
{channelIcon && (
|
||||||
<ProfilePicture
|
<ProfileImage
|
||||||
name={channelName}
|
name={channelName}
|
||||||
url={channelIcon}
|
url={channelIcon}
|
||||||
className="size-7"
|
className="size-7"
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ export default function Settings({
|
|||||||
schema={CLIENT_SCHEMA}
|
schema={CLIENT_SCHEMA}
|
||||||
onSave={() => {
|
onSave={() => {
|
||||||
setClientSettings(settings);
|
setClientSettings(settings);
|
||||||
router.refresh();
|
setTimeout(() => router.refresh(), 300);
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</CardContent>
|
</CardContent>
|
||||||
|
|||||||
@@ -0,0 +1,48 @@
|
|||||||
|
"use client"
|
||||||
|
|
||||||
|
import * as React from "react"
|
||||||
|
import * as PopoverPrimitive from "@radix-ui/react-popover"
|
||||||
|
|
||||||
|
import { cn } from "@/lib/utils"
|
||||||
|
|
||||||
|
function Popover({
|
||||||
|
...props
|
||||||
|
}: React.ComponentProps<typeof PopoverPrimitive.Root>) {
|
||||||
|
return <PopoverPrimitive.Root data-slot="popover" {...props} />
|
||||||
|
}
|
||||||
|
|
||||||
|
function PopoverTrigger({
|
||||||
|
...props
|
||||||
|
}: React.ComponentProps<typeof PopoverPrimitive.Trigger>) {
|
||||||
|
return <PopoverPrimitive.Trigger data-slot="popover-trigger" {...props} />
|
||||||
|
}
|
||||||
|
|
||||||
|
function PopoverContent({
|
||||||
|
className,
|
||||||
|
align = "center",
|
||||||
|
sideOffset = 4,
|
||||||
|
...props
|
||||||
|
}: React.ComponentProps<typeof PopoverPrimitive.Content>) {
|
||||||
|
return (
|
||||||
|
<PopoverPrimitive.Portal>
|
||||||
|
<PopoverPrimitive.Content
|
||||||
|
data-slot="popover-content"
|
||||||
|
align={align}
|
||||||
|
sideOffset={sideOffset}
|
||||||
|
className={cn(
|
||||||
|
"bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 w-72 origin-(--radix-popover-content-transform-origin) rounded-md border p-4 shadow-md outline-hidden",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
</PopoverPrimitive.Portal>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
function PopoverAnchor({
|
||||||
|
...props
|
||||||
|
}: React.ComponentProps<typeof PopoverPrimitive.Anchor>) {
|
||||||
|
return <PopoverPrimitive.Anchor data-slot="popover-anchor" {...props} />
|
||||||
|
}
|
||||||
|
|
||||||
|
export { Popover, PopoverTrigger, PopoverContent, PopoverAnchor }
|
||||||
Reference in New Issue
Block a user