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

v1.0.7 #37

Merged
merged 5 commits into from
Feb 1, 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
2 changes: 1 addition & 1 deletion .github/workflows/build_test.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
name: "Nextjs build test"
on: [push, pull_request]
on: [push]
jobs:
build_test:
runs-on: ubuntu-latest
Expand Down
108 changes: 13 additions & 95 deletions app/(app)/app/_components/edit/main.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,110 +3,28 @@
import { customSession } from "@/@types/customSession";
import { fileType } from "@/@types/fileType";
import { useSession } from "next-auth/react";
import React, { useEffect, useState } from "react";
import React from "react";
import EditMenu from "./EditMenu";
import {
getFileContent,
getFileInfo,
updateFileInfo,
uploadFile,
} from "@/googledrive";
import { useHotkeys } from "react-hotkeys-hook";
import { useDocumentTitle } from "@uidotdev/usehooks";
import EditHeader from "./editHeader";
import { useFile } from "../../../../../googledrive/useFile";

export default function FileMenu({ fileID }: { fileID: string }) {
const [title, setTitle] = useState(""); //拡張子付き
const [fileContent, setFileContent] = useState<fileType | undefined>();
const [loading, setLoading] = useState(true);
const [saving, setSaving] = useState(false); // 保存中はtrue
const [titleSaving, setTitleSaving] = useState(false); // タイトル保存中はtrue
const [fileContentSaving, setFileContentSaving] = useState(false); // ファイルコンテンツ保存中はtrue
const [serverFileContent, setServerFileContent] = useState<
fileType | undefined
>(undefined);
const [serverTitle, setServerTitle] = useState(undefined); //拡張子付き
const [shouldSaveTitle, setShouldSaveTitle] = useState(false); // タイトルを保存する必要があるときはtrue
const [shouldSaveFileContent, setShouldSaveFileContent] = useState(false); // ファイルコンテンツを保存する必要があるときはtrue
const { data: session }: { data: customSession | null } =
useSession() as unknown as { data: customSession };
const token = session?.accessToken;
useEffect(() => {
(async () => {
if (!token) return;
try {
const title = (await getFileInfo(token, fileID)).name;
if (!title) throw new Error("file is not found");
const fileContent =
JSON.parse(await getFileContent(token, fileID)) ||
({ mode: null, content: [] } as fileType);
console.log("fileFound");
setTitle(title);
setServerTitle(title);
setFileContent(fileContent);
setServerFileContent(fileContent);
} catch (e: any) {
// 空ファイルでは "SyntaxError: Unexpected end of JSON input" を吐くが問題なし
if (e.message == "Unexpected end of JSON input") {
setFileContent({ mode: null, content: [] } as fileType);
return;
}
console.error(e);
} finally {
setLoading(false);
}
})();
}, [token, fileID]);
/**
* タイトルを更新します
* @returns
*/
async function saveFileInfo() {
if (!token) return;
if (title === "") return;
if (titleSaving) {
setShouldSaveTitle(true);
return;
}
setSaving(true);
setTitleSaving(true);
await updateFileInfo(token, fileID, {
name: title,
});
if (shouldSaveTitle) saveFileContent();
setSaving(false);
setTitleSaving(false);
setShouldSaveTitle(false);
}
/**
* ファイル本体を更新します
* @returns
*/
async function saveFileContent() {
if (!token) return;
if (fileContent?.content?.length === 0) return;
if (fileContentSaving) {
setShouldSaveFileContent(true);
return;
}
setSaving(true);
setFileContentSaving(true);
await uploadFile(token, fileID, JSON.stringify(fileContent));
if (shouldSaveFileContent) saveFileContent();
setSaving(false);
setFileContentSaving(false);
setShouldSaveFileContent(false);
}
useEffect(() => {
if (serverFileContent === fileContent) return;
saveFileContent();
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [fileID, fileContent, token]);
useEffect(() => {
if (serverTitle === title) return;
saveFileInfo();
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [fileID, title, token]);
const {
title,
setTitle,
fileContent,
setFileContent,
loading,
saving,
saveFileContent,
saveFileInfo,
} = useFile(token, fileID);

useHotkeys(
"ctrl+s",
() => {
Expand Down
4 changes: 2 additions & 2 deletions app/(app)/app/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,13 @@ import { Metadata } from "next";

export default function AppLayout({ children }: { children: ReactNode }) {
return (
<div className="h-screen">
<>
<Header />
<div className="flex mt-20">
<LeftBar />
<div className="flex-1 md:w-auto">{children}</div>
</div>
</div>
</>
);
}
export const metadata: Metadata = {
Expand Down
56 changes: 28 additions & 28 deletions app/(app)/flashCard/HeaderRight.tsx
Original file line number Diff line number Diff line change
@@ -1,43 +1,43 @@
"use client";
import { ReactNode, useState } from "react";
import { CiSettings } from "react-icons/ci";
import { useState } from "react";
import { CgMaximizeAlt } from "react-icons/cg";
import { MdOutlineZoomInMap } from "react-icons/md";
import { MdLogout, MdOutlineZoomInMap } from "react-icons/md";

export default function HeaderRight() {
export default function HeaderRight({
mode,
setMode,
}: {
mode: "home" | "cards" | "result";
setMode: (mode: "home" | "cards" | "result") => void;
}) {
const [isMaximized, setIsMaximized] = useState(false);
document.addEventListener("fullscreenchange", () => {
setIsMaximized((prev) => !prev);
});

return (
<nav className="gap-4 flex">
{(
[
{
title: isMaximized ? "戻す" : "最大化",
icon: isMaximized ? <MdOutlineZoomInMap /> : <CgMaximizeAlt />,
onClick: () => {
isMaximized
? document.exitFullscreen()
: document.documentElement.requestFullscreen();
setIsMaximized((prev) => !prev);
},
},
] as {
title: string;
icon: ReactNode;
onClick?: (e: any) => void;
}[]
).map(({ title, icon, onClick }, i) => (
{mode == "cards" && (
<button
key={i}
onClick={onClick}
className="gap-2 p-2 bg-primary-300 hover:bg-primary-400 rounded-full w-12 h-12 grid place-items-center"
title={title}
className="gap-2 p-2 bg-primary-300 hover:bg-primary-400 rounded-full w-12 h-12 grid place-items-center"
onClick={() => setMode("result")}
title="終了"
>
{icon}
<MdLogout />
</button>
))}
)}
<button
className="gap-2 p-2 bg-primary-300 hover:bg-primary-400 rounded-full w-12 h-12 grid place-items-center"
onClick={() => {
isMaximized
? document.exitFullscreen()
: document.documentElement.requestFullscreen();
setIsMaximized((prev) => !prev);
}}
title={isMaximized ? "戻す" : "最大化"}
>
{isMaximized ? <MdOutlineZoomInMap /> : <CgMaximizeAlt />}
</button>
</nav>
);
}
13 changes: 5 additions & 8 deletions app/(app)/flashCard/_card/card.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -91,10 +91,7 @@ export default function FlashCard({
);

return (
<div
className="flex-1 flex flex-col p-4 w-full max-w-7xl mx-auto gap-4"
{...handles}
>
<div className="h-full p-4 w-full max-w-7xl mx-auto " {...handles}>
{currentQuestion && (
<CardMain
currentQuestion={currentQuestion as fileType["content"][0]}
Expand All @@ -110,16 +107,16 @@ export default function FlashCard({
isAnswerWithKeyboard={flashCardSettings.isAnswerWithKeyboard}
/>
)}
<nav className="flex-none flex items-stretch gap-4">
<nav className="flex w-full max-w-7xl bottom-2 fixed p-4 right-0 left-0 mx-auto">
<button
onClick={back}
className="p-2 rounded-full bg-gray-100 hover:bg-gray-200 aspect-square"
className="p-2 rounded-l-full bg-gray-100 hover:bg-gray-200 w-12 h-12 flex-none grid items-center justify-center"
title="戻る"
>
<IoChevronBackSharp />
</button>
<div
className="flex-1 border p-2 rounded flex items-center justify-center"
className="flex-1 border h-12 flex items-center justify-center"
style={{
background: `linear-gradient(to right, #dbb946 ${
((questionIndex + 1) / questionList.length) * 100
Expand All @@ -132,7 +129,7 @@ export default function FlashCard({
</div>
<button
onClick={next}
className="p-2 rounded-full bg-gray-100 hover:bg-gray-200 aspect-square"
className="p-2 rounded-r-full bg-gray-100 hover:bg-gray-200 w-12 h-12 grid items-center justify-center flex-none"
title="次へ"
>
<IoChevronBackSharp className="transform rotate-180" />
Expand Down
2 changes: 1 addition & 1 deletion app/(app)/flashCard/_card/main.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ export function CardMain({
isAnswerWithKeyboard: boolean;
}) {
return (
<div className="flex-1 w-full flex flex-col gap-4 justify-center ">
<div className="w-full flex flex-col gap-4 justify-center fixed inset-0 m-auto p-4 max-w-7xl">
<div className="mx-auto bg-gray-100 rounded w-full grid gap-4 p-4">
<div className="flex items-center gap-4">
<p className="md:text-heading-S p-4 bg-gray-200 rounded flex-1">
Expand Down
Loading