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

フロントUIの改善 #41

Merged
merged 27 commits into from
Nov 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
ada00c7
feat: PC版ログインボタン実装
YutaK1026 Nov 12, 2024
69702d7
feat: 検索体験の向上
YutaK1026 Nov 12, 2024
28d99d6
feat: Loopボタンの追加 && Sliderの不審な挙動の修正
YutaK1026 Nov 12, 2024
2ebc916
fix: strict modeによるエラーの修正
YutaK1026 Nov 12, 2024
285d0d6
feat: sp版で現在のステップが確認できるように修正
YutaK1026 Nov 12, 2024
d0a804c
feat: ページネーションで最初と最後が常に見えるように修正
YutaK1026 Nov 12, 2024
9fdbbd6
feat: ハンバーガーメニューを追加
YutaK1026 Nov 12, 2024
632932b
fix: logoの位置のずれを修正
YutaK1026 Nov 12, 2024
902a2fe
fix: fail build
YutaK1026 Nov 12, 2024
6665afc
fix: failed build
YutaK1026 Nov 12, 2024
c00c4cd
feat: control panelにborderを付与
YutaK1026 Nov 12, 2024
0268f35
feat: itemにshadowをつけて、押せるような印象を与える
YutaK1026 Nov 12, 2024
9280e6c
feat: ゆってぃーとの話で修正した点
YutaK1026 Nov 13, 2024
1d4a249
feat: loginボタンをgoogleに変更
YutaK1026 Nov 13, 2024
4e60ddb
feat: paginationの修正
YutaK1026 Nov 13, 2024
55c32e5
feat: ループ待機中のアニメーションを追加
YutaK1026 Nov 13, 2024
3f64570
feat: 不要なコード削除
YutaK1026 Nov 13, 2024
8a41fd5
feat: loop buttonのactiveがわかりやすいように修正
YutaK1026 Nov 13, 2024
d6fc907
feat: ローディングボタンのデザイン修正
YutaK1026 Nov 14, 2024
e7a2464
feat: ループ待機中にボタンを押したときの振る舞いを変更
YutaK1026 Nov 14, 2024
9f13440
fix: failed build
YutaK1026 Nov 14, 2024
89f3df9
feat: children modeのhooksを用意
YutaK1026 Nov 15, 2024
4839b76
feat: ひらがな化APIの機構実装
YutaK1026 Nov 16, 2024
7648ef2
Merge branch 'main' into feat/refactor-front-design
YutaK1026 Nov 16, 2024
f82d62a
feat: Childrenモードのボタン実装
YutaK1026 Nov 16, 2024
c375f5b
feat: spにchildmodeのボタンを実装
YutaK1026 Nov 16, 2024
aaa6241
fix: build failed
YutaK1026 Nov 16, 2024
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
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