Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/translateedit #27

Merged
merged 2 commits into from
Jul 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
96 changes: 58 additions & 38 deletions web/app/components/Header.tsx
Original file line number Diff line number Diff line change
@@ -1,46 +1,66 @@
import type { User } from "@prisma/client";
import { Link } from "@remix-run/react";
import { TranslationLanguageSelect } from "./TranslationLanguageSelect";
import { Form, useSubmit } from "@remix-run/react";

type UserWithoutPassword = Omit<User, "password">;

interface HeaderProps {
user: UserWithoutPassword | null;
user: UserWithoutPassword | null;
language: string;
}

export function Header({ user }: HeaderProps) {
return (
<header className="bg-white shadow-sm">
<div className="max-w-7xl mx-auto py-4 px-4 sm:px-6 lg:px-8 flex justify-between items-center">
<h1 className="text-3xl font-bold text-gray-900">EveEve</h1>
<nav>
{user ? (
<div className="flex items-center space-x-4">
<span className="text-gray-700">ようこそ、{user.name}さん!</span>
<Link
to="/auth/logout"
className="text-blue-600 hover:text-blue-800 font-medium"
>
ログアウト
</Link>
</div>
) : (
<div className="space-x-4">
<Link
to="/auth/login"
className="text-blue-600 hover:text-blue-800 font-medium"
>
ログイン
</Link>
<Link
to="/auth/signup"
className="text-blue-600 hover:text-blue-800 font-medium"
>
サインアップ
</Link>
</div>
)}
</nav>
</div>
</header>
);
}
export function Header({ user, language }: HeaderProps) {
const submit = useSubmit();

const handleLanguageChange = (newLanguage: string) => {
const formData = new FormData();
formData.append("language", newLanguage);
submit(formData, { method: "post" });
};
return (
<header className="bg-white shadow-sm">
<div className="max-w-7xl mx-auto py-4 px-4 sm:px-6 lg:px-8 flex justify-between items-center">
<Link to="/">
<h1 className="text-3xl font-bold text-gray-900">EveEve</h1>
</Link>
<div className="flex items-center space-x-4">
<Form method="post">
<TranslationLanguageSelect
value={language}
onChange={handleLanguageChange}
/>
</Form>
<nav>
{user ? (
<div className="flex items-center space-x-4">
<span className="text-gray-700">ようこそ、{user.name}さん!</span>
<Link
to="/auth/logout"
className="text-blue-600 hover:text-blue-800 font-medium"
>
ログアウト
</Link>
</div>
) : (
<div className="space-x-4">
<Link
to="/auth/login"
className="text-blue-600 hover:text-blue-800 font-medium"
>
ログイン
</Link>
<Link
to="/auth/signup"
className="text-blue-600 hover:text-blue-800 font-medium"
>
サインアップ
</Link>
</div>
)}
</nav>
</div>
</div>
</header>
);
}
24 changes: 24 additions & 0 deletions web/app/components/ui/textarea.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import * as React from "react";

import { cn } from "~/utils";

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Image description CodeRabbit

cn関数のインポート元が不明確です。~/utilsから正しくインポートされているか確認してください。

- import { cn } from "~/utils";
+ import { cn } from "../path/to/utils"; // 正しいパスに変更してください


export interface TextareaProps
extends React.TextareaHTMLAttributes<HTMLTextAreaElement> {}

const Textarea = React.forwardRef<HTMLTextAreaElement, TextareaProps>(
({ className, ...props }, ref) => {
return (
<textarea
className={cn(
"flex min-h-[60px] w-full rounded-md border border-input bg-transparent px-3 py-2 text-sm shadow-sm placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50",
className,
)}
ref={ref}
{...props}
/>
);
},
);
Textarea.displayName = "Textarea";

export { Textarea };
59 changes: 48 additions & 11 deletions web/app/root.tsx
Original file line number Diff line number Diff line change
@@ -1,47 +1,84 @@
import type { User } from "@prisma/client";
import { json } from "@remix-run/node";
import type { LoaderFunctionArgs, ActionFunctionArgs } from "@remix-run/node";
import type { LinksFunction } from "@remix-run/node";
import {
Links,
Meta,
Outlet,
Scripts,
ScrollRestoration,
} from "@remix-run/react";
import tailwind from "~/tailwind.css?url";
import type { User } from "@prisma/client";
import { json } from "@remix-run/node";
import type { LoaderFunctionArgs } from "@remix-run/node";
import { useLoaderData } from "@remix-run/react";
import tailwind from "~/tailwind.css?url";
import { Header } from "./components/Header";
import { authenticator } from "./utils/auth.server";
import type { LinksFunction } from "@remix-run/node";
import { getSession, commitSession } from "~/utils/session.server";
import { redirect } from "@remix-run/node";
import { Form } from "@remix-run/react";

type UserWithoutPassword = Omit<User, "password">;

export const links: LinksFunction = () => [
{ rel: "stylesheet", href: tailwind },
{ rel: "stylesheet", href: tailwind },
];
export interface RootLoaderData {
user: UserWithoutPassword | null;
language: string;
}

export async function loader({ request }: LoaderFunctionArgs) {
const user = await authenticator.isAuthenticated(request);
const safeUser = user ? { ...user, password: undefined } : null;
return json<RootLoaderData>({ user: safeUser });

const session = await getSession(request.headers.get("Cookie"));
const language = session.get("language") || "ja";

return json(
{ user: safeUser, language },
{
headers: {
"Set-Cookie": await commitSession(session),
},
}
);
}


export async function action({ request }: ActionFunctionArgs) {
const session = await getSession(request.headers.get("Cookie"));
const formData = await request.formData();
const language = formData.get("language");

if (typeof language === "string") {
session.set("language", language);
}


return json(
{ success: true },
{
headers: {
"Set-Cookie": await commitSession(session),
},
}
);
}

export function Layout({ children }: { children: React.ReactNode }) {
const data = useLoaderData<typeof loader>();
const user = data?.user as UserWithoutPassword | null;
const data = useLoaderData<typeof loader>();
const user = data?.user as UserWithoutPassword | null;

return (
<html lang="en">
<html lang={data.language}>
<head>
<meta charSet="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<Meta />
<Links />
</head>
<body>
<Header user={user as UserWithoutPassword | null} />
<Header user={user as UserWithoutPassword | null} language={data.language}/>
{children}
<ScrollRestoration />
<Scripts />
Expand Down
10 changes: 1 addition & 9 deletions web/app/routes/_index/components/URLTranslationForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,10 @@ import {
useNavigation,
useSubmit,
} from "@remix-run/react";
import { useState } from "react";
import { z } from "zod";
import { Alert, AlertDescription } from "~/components/ui/alert";
import { Button } from "~/components/ui/button";
import { Input } from "~/components/ui/input";
import { TranslationLanguageSelect } from "./TranslationLanguageSelect";

const urlTranslationSchema = z.object({
url: z.string().url("有効なURLを入力してください"),
Expand All @@ -21,7 +19,6 @@ const urlTranslationSchema = z.object({

export function URLTranslationForm() {
const navigation = useNavigation();
const [targetLanguage, setTargetLanguage] = useState("ja");
const submit = useSubmit();

const actionData = useActionData<{
Expand Down Expand Up @@ -54,11 +51,6 @@ export function URLTranslationForm() {
required
className="flex-grow"
/>
<input type="hidden" name="targetLanguage" value={targetLanguage} />
<TranslationLanguageSelect
value={targetLanguage}
onChange={setTargetLanguage}
/>
<Button type="submit" disabled={navigation.state === "submitting"}>
{navigation.state === "submitting" ? "翻訳中..." : "翻訳開始"}
</Button>
Expand Down Expand Up @@ -91,4 +83,4 @@ export function URLTranslationForm() {
);
}

export { urlTranslationSchema };
export { urlTranslationSchema };
29 changes: 23 additions & 6 deletions web/app/routes/_index/components/translatedList.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,28 @@
import type { Page } from "@prisma/client";
import { useLoaderData } from "@remix-run/react";
import type { PageVersion } from "@prisma/client";
import { useLoaderData, useMatches } from "@remix-run/react";
import type { RootLoaderData } from "~/root"; // root.tsxからインポート

interface LoaderData {
pageList: Page[];
pageVersionList: PageVersion[];
}

export function TranslatedList() {
const { pageList } = useLoaderData<LoaderData>();
return <div>TranslatedList</div>;
}
const { pageVersionList } = useLoaderData<LoaderData>();
const matches = useMatches();
const rootData = matches[0].data as RootLoaderData;
const language = rootData.language;

return (
<div>
<h2>Translated List (Language: {language})</h2>
<ul>
{pageVersionList.map((pageVersion) => (
<li key={pageVersion.id}>
{/* ページのタイトルや他の情報を表示 */}
{pageVersion.title} - {pageVersion.url}
</li>
))}
</ul>
</div>
);
}
Loading
Loading