Skip to content

Commit

Permalink
Merge pull request #41 from jphacks/feat/refactor-front-design
Browse files Browse the repository at this point in the history
フロントUIの改善
  • Loading branch information
YutaK1026 authored Nov 16, 2024
2 parents ef8a4ea + aaa6241 commit 96b31ea
Show file tree
Hide file tree
Showing 31 changed files with 1,021 additions and 178 deletions.
Binary file added public/assets/google.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
38 changes: 38 additions & 0 deletions src/app/_children-provider.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
"use client";
import { createContext, useContext, useState } from "react";

type ChildrenProviderProps = {
isChildren: boolean;
setIsChildren: React.Dispatch<React.SetStateAction<boolean>>;
};

const ChildrenProviderContext = createContext<ChildrenProviderProps>(
{} as ChildrenProviderProps
);

export const ChildrenProvider: React.FC<{
children: React.ReactNode;
}> = ({ children }: { children: React.ReactNode }) => {
const [isChildren, setIsChildren] = useState(false);

return (
<ChildrenProviderContext.Provider
value={{
isChildren: isChildren,
setIsChildren: setIsChildren,
}}
>
{children}
</ChildrenProviderContext.Provider>
);
};

export function useChildren() {
const context = useContext(ChildrenProviderContext);
if (!context) {
throw new Error(
"useChildren must be used within a ChildrenContextProvider"
);
}
return context;
}
63 changes: 63 additions & 0 deletions src/app/api/hiragana/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import { NextRequest, NextResponse } from "next/server";
import axios from "axios";

export interface ChildrenModeRequestBody {
request_id?: string; // オプショナルフィールド
sentence: string; // 必須フィールド
output_type: "hiragana" | "katakana"; // 必須フィールドでリテラル型を使用
}

export async function POST(request: NextRequest) {
try {
const body: ChildrenModeRequestBody = await request.json();
const { request_id, sentence, output_type } = body;

// 必須パラメータのチェック
if (!sentence || !output_type) {
return NextResponse.json(
{ error: "sentence と output_type は必須です。" },
{ status: 400 }
);
}

const app_id = process.env.GOO_APP_ID;
if (!app_id) {
return NextResponse.json(
{ error: "サーバー設定エラー: GOO_APP_IDが設定されていません。" },
{ status: 500 }
);
}

// リクエストIDの生成(省略時の形式)
const generated_request_id: string =
request_id ||
`labs.goo.ne.jp\t${new Date().toISOString()}\t${Math.floor(
Math.random() * 100000
)}`;

const payload = {
app_id,
request_id: generated_request_id,
sentence,
output_type,
};

const response = await axios.post(
"https://labs.goo.ne.jp/api/hiragana",
payload,
{
headers: {
"Content-Type": "application/json",
},
}
);

return NextResponse.json(response.data, { status: 200 });
} catch (error) {
console.error(error);
return NextResponse.json(
{ error: "API呼び出し中にエラーが発生しました。" },
{ status: 500 }
);
}
}
5 changes: 4 additions & 1 deletion src/app/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import "@/styles/globals.scss";
import "@radix-ui/themes/styles.css";
import { Theme } from "@radix-ui/themes";
import NextAuthProvider from "./_auth";
import { ChildrenProvider } from "./_children-provider";

export const metadata: Metadata = {
title: "OriCube",
Expand All @@ -18,7 +19,9 @@ export default function RootLayout({
<html lang="ja">
<body>
<NextAuthProvider>
<Theme>{children}</Theme>
<ChildrenProvider>
<Theme>{children}</Theme>
</ChildrenProvider>
</NextAuthProvider>
</body>
</html>
Expand Down
25 changes: 25 additions & 0 deletions src/components/Header/ChildButton/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
"use client";

import { useChildren } from "@/app/_children-provider";
import { Button } from "@radix-ui/themes";

const ChildrenModeButton = () => {
const { isChildren, setIsChildren } = useChildren();

const toggleChildrenMode = () => {
setIsChildren(!isChildren);
};

return (
<Button
color="gray"
variant="surface"
highContrast
onClick={() => toggleChildrenMode()}
>
{isChildren ? <div>漢字にする</div> : <div>ひらがなにする</div>}
</Button>
);
};

export default ChildrenModeButton;
19 changes: 16 additions & 3 deletions src/components/Header/GoogleAuth/Login/index.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,28 @@
import React from "react";
import { useSession, signIn } from "next-auth/react";
import { Button } from "@radix-ui/themes";
import Image from "next/image";

export const Login = () => {
const { status } = useSession();

if (status !== "authenticated") {
return (
<div>
<button onClick={() => signIn("google", {}, { prompt: "login" })}>
ログイン
</button>
<Button
color="gray"
variant="surface"
highContrast
onClick={() => signIn("google", {}, { prompt: "login" })}
>
<Image
src="/assets/google.png"
alt="google icon"
width={20}
height={20}
/>
Googleでログイン
</Button>
</div>
);
}
Expand Down
17 changes: 16 additions & 1 deletion src/components/Header/GoogleAuth/Logout/index.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,28 @@
import React from "react";
import { useSession, signOut } from "next-auth/react";
import { Button } from "@radix-ui/themes";
import Image from "next/image";

export const Logout = () => {
const { status } = useSession();

if (status === "authenticated") {
return (
<div>
<button onClick={() => signOut()}>ログアウト</button>
<Button
color="gray"
variant="surface"
highContrast
onClick={() => signOut()}
>
<Image
src="/assets/google.png"
alt="google icon"
width={20}
height={20}
/>
ログアウト
</Button>
</div>
);
}
Expand Down
86 changes: 86 additions & 0 deletions src/components/Header/HamburgerMenu/index.module.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
/* index.module.scss */

.mobile_menu_container {
position: relative;

.hamburger_button {
padding: 0.5rem;
}

.menu_icon {
/* 必要に応じて追加のスタイル */
padding-top: 1rem;
padding-left: 0.5rem;
}

.menu {
position: fixed;
top: 0;
left: 0;
height: 100vh;
width: 16rem; // 64px * 4 = 256px = 16rem
background-color: #ffffff;
box-shadow: 2px 0 8px rgba(0, 0, 0, 0.1);
transform: translateX(-100%);
transition: transform 0.3s ease-in-out;
z-index: 1100;

&.open {
transform: translateX(0);
}

&.closed {
transform: translateX(-100%);
}

.menu_nav {
padding-top: 1rem; // pt-16 equivalent
}

.menu_list {
list-style: none;
padding: 0;
margin: 0;
display: flex;
flex-direction: column;
gap: 0.5rem; // space-y-2 equivalent
}

.menu_item {
/* Optional: Additional styles for list items */
}

.menu_link {
display: block;
padding: 0.5rem 1rem; // px-4 py-2 equivalent
font-size: 0.875rem; // text-sm equivalent
color: #4b5563; // text-gray-700 equivalent
text-decoration: none;
border-radius: 0.375rem; // Optional: similar to hover:bg-gray-100

&:hover {
background-color: #f3f4f6; // hover:bg-gray-100 equivalent
color: #374151; // Optional: Slightly darker on hover
}
}

.menu_auth {
padding: 1rem; // px-4 py-4 equivalent
/* Optional: Additional styles */
}
.menu_child_mode {
margin-bottom: 1rem;
}
}

.menu_overlay {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100vh;
background-color: rgba(0, 0, 0, 0.5); // bg-black bg-opacity-50 equivalent
z-index: 30;
cursor: pointer;
}
}
94 changes: 94 additions & 0 deletions src/components/Header/HamburgerMenu/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
// MobileMenu.jsx
"use client";

import { useState, useEffect, useRef } from "react";
import Link from "next/link";
import { RxHamburgerMenu } from "react-icons/rx";
import { HiMiniXMark } from "react-icons/hi2";
import { IconButton } from "@/components/ui/IconButton";
import { GoogleAuthButton } from "../GoogleAuth";
import ChildrenModeButton from "../ChildButton";
import styles from "./index.module.scss"; // Sassファイルをインポート
import { ButtonSizeProp } from "@/types/button";
import { useSession } from "next-auth/react";

export default function MobileMenu() {
const [isOpen, setIsOpen] = useState(false);
const menuRef = useRef<HTMLDivElement>(null);
const { status } = useSession();
const toggleMenu = () => setIsOpen(!isOpen);

useEffect(() => {
const handleClickOutside = (event: MouseEvent) => {
if (menuRef.current && !menuRef.current.contains(event.target as Node)) {
setIsOpen(false);
}
};

document.addEventListener("mousedown", handleClickOutside);
return () => {
document.removeEventListener("mousedown", handleClickOutside);
};
}, []);

return (
<div className={styles.mobile_menu_container}>
<div className={styles.hamburger_button}>
<IconButton
handleClick={toggleMenu}
Icon={RxHamburgerMenu}
disable={false}
/>
</div>
<div
ref={menuRef}
className={`${styles.menu} ${isOpen ? styles.open : styles.closed}`}
>
<div className={styles.menu_icon}>
<IconButton
handleClick={toggleMenu}
Icon={HiMiniXMark}
disable={false}
size={ButtonSizeProp.medium}
/>
</div>
<nav className={styles.menu_nav}>
<ul className={styles.menu_list}>
<li className={styles.menu_item}>
<Link href="/" className={styles.menu_link} onClick={toggleMenu}>
ホーム
</Link>
</li>
{status === "authenticated" ? (
<li className={styles.menu_item}>
<Link
href="/add"
className={styles.menu_link}
onClick={toggleMenu}
>
折り紙を追加
</Link>
</li>
) : (
<></>
)}
</ul>

<div className={styles.menu_auth}>
<div className={styles.menu_child_mode}>
<ChildrenModeButton />
</div>
<GoogleAuthButton />
</div>
</nav>
</div>
{isOpen && (
<div
className={styles.menu_overlay}
aria-hidden="true"
onClick={toggleMenu}
/>
)}
</div>
);
}
3 changes: 3 additions & 0 deletions src/components/Header/SearchBox/InputField/index.module.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
.text_field {
height: 44px;
}
Loading

0 comments on commit 96b31ea

Please sign in to comment.