8. ツールバーコンポーネント
ワークスペースにアクセスした後の画面レイアウトを作成する。
ツールバーの作成まで実施。
ワークスペース画面作成
convexの取得処理
idを指定して取得できるようにする。
convex/workspaces.ts
export const getById = query({
args: {
id: v.id("workspaces"),
},
handler: async (ctx, args) => {
const userId = await getAuthUserId(ctx);
if (!userId) {
throw new Error("Unauthorized");
}
return await ctx.db.get(args.id);
},
});
ワークスペースのレイアウト作成
モックレベルで作成。
ツールバーがクライアント側で動作する仕組みとなるので use client
を記述する。
src/app/workspace/[workspaceId]/layout.tsx
"use client";
import { Toolbar } from "./toolbar";
interface WorkSpaceIdLayoutProps {
children: React.ReactNode;
}
const WorkSpaceIdLayout: React.FC<WorkSpaceIdLayoutProps> = ({ children }) => {
return (
<div className="h-full">
<Toolbar />
{children}
</div>
);
};
export default WorkSpaceIdLayout;
ワークスペースページ作成
データを取得して表示できるようにするのみ。
src/app/workspace/[workspaceId]/page.tsx
"use client";
import { useGetWorkspace } from "@/features/workspaces/api/use-get-workspace";
import { useWorkspaceId } from "@/hooks/use-workspace-id";
const WorkspaceIdPage = () => {
const workspaceId = useWorkspaceId();
const { data } = useGetWorkspace({ id: workspaceId });
return (
<div>
<span>ID: {workspaceId}</span>
<span>DATA: {JSON.stringify(data)}</span>
</div>
);
};
ツールバー作成
ワークスペースを特定し、検索フィールドにワークスペース名を設定。
src/app/workspace/[workspaceId]/toolbar.tsx
import { Button } from "@/components/ui/button";
import { useGetWorkspace } from "@/features/workspaces/api/use-get-workspace";
import { useWorkspaceId } from "@/hooks/use-workspace-id";
import { Info, Search } from "lucide-react";
export const Toolbar = () => {
const workspaceId = useWorkspaceId();
const { data } = useGetWorkspace({ id: workspaceId });
return (
<nav className="bg-[#481349] flex items-center justify-between h-10 p-1.5">
<div className="flex-1" />
<div className="min-w-[280px] max-[642px] grow-[2] shrink">
<Button
size={"sm"}
className="bg-accent/25 hover:bg-accent-25 w-full justify-start h-7 px-2"
>
<Search className="size-4 text-white mr-2" />
<span className="text-white text-xs">Search {data?.name}</span>
</Button>
</div>
<div className="ml-auto flex-1 flex items-center justify-end">
<Button variant={"transparent"} size={"iconSm"}>
<Info className="size-5 text-white" />
</Button>
</div>
</nav>
);
};
shadcn/uiのボタンコンポーネントに定義を追加
Slackに寄せるため transparent
iconSm
という定義を追加する。
src/components/ui/button.tsx
ghost: "hover:bg-accent hover:text-accent-foreground",
link: "text-primary underline-offset-4 hover:underline",
slack: "bg-emerald-500 text-white hover:bg-emerald-500/80",
transparent: "bg-transparent hover:bg-accent/10 text-accent",
},
size: {
default: "h-10 px-4 py-2",
sm: "h-8 rounded-md px-3",
lg: "h-11 rounded-md px-8",
icon: "h-10 w-10",
iconSm: "h-8 w-8",
},
},
defaultVariants: {
ワークスペースを取得するAPIを作成
convexからデータを取得するAPIを作成する。
useQuery
を使うとデータが更新された際に、自動的に反映することができる。
WebSocket? ポーリング? 上手いことやってくれる。
src/features/workspaces/api/use-get-workspace.ts
import { useQuery } from "convex/react";
import { api } from "../../../../convex/_generated/api";
import { Id } from "../../../../convex/_generated/dataModel";
interface UserGetWorkspaceProps {
id: Id<"workspaces">;
}
export const useGetWorkspace = ({ id }: UserGetWorkspaceProps) => {
const data = useQuery(api.workspaces.getById, { id });
const isLoading = data === undefined;
return { data, isLoading };
};
ワークスペースID取得のhookを作成
hookでは存在するワークスペースであるかをチェックし、問題なければIDを返す。
src/hooks/use-workspace-id.ts
import { useParams } from "next/navigation";
import { Id } from "../../convex/_generated/dataModel";
export const useWorkspaceId = () => {
const params = useParams();
return params.workspaceId as Id<"workspaces">;
};