Open7
ユーザーボタンを作ってみる
zennみたいにユーザーボタンからユーザー設定ページの動線にしたいのだ。
v0でプロンプト書いた
use shadcn botton user image botton dropdown-menu
一旦こんなもんで
import { Button } from "~/components/ui/button"
import { DropdownMenuTrigger, DropdownMenuItem, DropdownMenuSeparator, DropdownMenuContent, DropdownMenu } from "~/components/ui/dropdown-menu"
import {Link} from "@remix-run/react"
import { Avatar, AvatarFallback, AvatarImage } from "./ui/avatar"
export default function Component() {
return (
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button className="flex items-center gap-2" variant="ghost">
<Avatar>
<AvatarImage src="https://github.com/shadcn.png" />
<AvatarFallback>CN</AvatarFallback>
</Avatar>
<span className="font-medium">John Doe</span>
<ChevronDownIcon className="h-4 w-4" />
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent align="end" className="w-48">
<DropdownMenuItem>
<Link className="flex items-center gap-2" href="#">
<UserIcon className="h-4 w-4" />
<span>Profile</span>
</Link>
</DropdownMenuItem>
<DropdownMenuItem>
<Link className="flex items-center gap-2" href="#">
<SettingsIcon className="h-4 w-4" />
<span>Settings</span>
</Link>
</DropdownMenuItem>
<DropdownMenuSeparator />
<DropdownMenuItem className="text-red-600">
<Link className="flex items-center gap-2" href="#">
<LogOutIcon className="h-4 w-4" />
<span>Logout</span>
</Link>
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
)
}
function ChevronDownIcon(props) {
return (
<svg
{...props}
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
>
<path d="m6 9 6 6 6-6" />
</svg>
)
}
function LogOutIcon(props) {
return (
<svg
{...props}
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
>
<path d="M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4" />
<polyline points="16 17 21 12 16 7" />
<line x1="21" x2="9" y1="12" y2="12" />
</svg>
)
}
function SettingsIcon(props) {
return (
<svg
{...props}
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
>
<path d="M12.22 2h-.44a2 2 0 0 0-2 2v.18a2 2 0 0 1-1 1.73l-.43.25a2 2 0 0 1-2 0l-.15-.08a2 2 0 0 0-2.73.73l-.22.38a2 2 0 0 0 .73 2.73l.15.1a2 2 0 0 1 1 1.72v.51a2 2 0 0 1-1 1.74l-.15.09a2 2 0 0 0-.73 2.73l.22.38a2 2 0 0 0 2.73.73l.15-.08a2 2 0 0 1 2 0l.43.25a2 2 0 0 1 1 1.73V20a2 2 0 0 0 2 2h.44a2 2 0 0 0 2-2v-.18a2 2 0 0 1 1-1.73l.43-.25a2 2 0 0 1 2 0l.15.08a2 2 0 0 0 2.73-.73l.22-.39a2 2 0 0 0-.73-2.73l-.15-.08a2 2 0 0 1-1-1.74v-.5a2 2 0 0 1 1-1.74l.15-.09a2 2 0 0 0 .73-2.73l-.22-.38a2 2 0 0 0-2.73-.73l-.15.08a2 2 0 0 1-2 0l-.43-.25a2 2 0 0 1-1-1.73V4a2 2 0 0 0-2-2z" />
<circle cx="12" cy="12" r="3" />
</svg>
)
}
function UserIcon(props) {
return (
<svg
{...props}
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
>
<path d="M19 21v-2a4 4 0 0 0-4-4H9a4 4 0 0 0-4 4v2" />
<circle cx="12" cy="7" r="4" />
</svg>
)
}
import { Link } from "@remix-run/react";
import { SignInButton, useAuth,useUser, SignOutButton } from "@clerk/remix";
import { Button } from "./ui/button";
import { ModeToggle } from "./dark-mode-toggle";
import { DropdownMenuTrigger, DropdownMenuItem, DropdownMenuSeparator, DropdownMenuContent, DropdownMenu } from "~/components/ui/dropdown-menu"
import { Avatar, AvatarFallback, AvatarImage } from "./ui/avatar"
export default function HeaderComponent() {
const { userId } = useAuth();
// ログイン状態に基づいたレンダリングコンテンツを取得する関数
function getUserRelatedContent() {
if (userId) {
return <UserButton />;
} else {
return (
<SignInButton>
<Button variant="ghost">ログイン</Button>
</SignInButton>
);
}
}
return (
<header className="flex items-center justify-between px-4 py-3">
<Link to="#" className="flex items-center">
<p>Acme Inc</p>
</Link>
<div className="flex items-center gap-4">
<ModeToggle />
{getUserRelatedContent()}
</div>
</header>
);
}
function UserButton() {
const {user} = useUser();
return (
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button className="flex items-center gap-2" variant="ghost">
<Avatar>
<AvatarImage src={user?.imageUrl} />
<AvatarFallback>A</AvatarFallback>
</Avatar>
<ChevronDownIcon className="h-4 w-4" />
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent align="end" className="w-48">
<DropdownMenuItem>
<Link className="flex items-center gap-2" to="#">
<UserIcon className="h-4 w-4" />
<span>Profile</span>
</Link>
</DropdownMenuItem>
<DropdownMenuItem>
<Link className="flex items-center gap-2" to="#">
<SettingsIcon className="h-4 w-4" />
<span>Settings</span>
</Link>
</DropdownMenuItem>
<DropdownMenuSeparator />
<SignOutButton>
<DropdownMenuItem className="flex items-center gap-2 text-red-600">
<LogOutIcon className="h-4 w-4"/>
<button>Sign out</button>
</DropdownMenuItem>
</SignOutButton>
</DropdownMenuContent>
</DropdownMenu>
)
}
function ChevronDownIcon(props) {
return (
<svg
{...props}
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
>
<path d="m6 9 6 6 6-6" />
</svg>
)
}
function LogOutIcon(props) {
return (
<svg
{...props}
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
>
<path d="M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4" />
<polyline points="16 17 21 12 16 7" />
<line x1="21" x2="9" y1="12" y2="12" />
</svg>
)
}
function SettingsIcon(props) {
return (
<svg
{...props}
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
>
<path d="M12.22 2h-.44a2 2 0 0 0-2 2v.18a2 2 0 0 1-1 1.73l-.43.25a2 2 0 0 1-2 0l-.15-.08a2 2 0 0 0-2.73.73l-.22.38a2 2 0 0 0 .73 2.73l.15.1a2 2 0 0 1 1 1.72v.51a2 2 0 0 1-1 1.74l-.15.09a2 2 0 0 0-.73 2.73l.22.38a2 2 0 0 0 2.73.73l.15-.08a2 2 0 0 1 2 0l.43.25a2 2 0 0 1 1 1.73V20a2 2 0 0 0 2 2h.44a2 2 0 0 0 2-2v-.18a2 2 0 0 1 1-1.73l.43-.25a2 2 0 0 1 2 0l.15.08a2 2 0 0 0 2.73-.73l.22-.39a2 2 0 0 0-.73-2.73l-.15-.08a2 2 0 0 1-1-1.74v-.5a2 2 0 0 1 1-1.74l.15-.09a2 2 0 0 0 .73-2.73l-.22-.38a2 2 0 0 0-2.73-.73l-.15.08a2 2 0 0 1-2 0l-.43-.25a2 2 0 0 1-1-1.73V4a2 2 0 0 0-2-2z" />
<circle cx="12" cy="12" r="3" />
</svg>
)
}
function UserIcon(props) {
return (
<svg
{...props}
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
>
<path d="M19 21v-2a4 4 0 0 0-4-4H9a4 4 0 0 0-4 4v2" />
<circle cx="12" cy="7" r="4" />
</svg>
)
}
やっぱりこんなもんで
日本語にしてみる