Skip to content

Commit 5605e7f

Browse files
authored
Merge pull request #53 from ut-code/copilot/improve-homepage-design
トップページのデザインを改善 (Improve top page design)
2 parents 0acc349 + fe8c119 commit 5605e7f

21 files changed

+420
-301
lines changed

app/[docs_id]/chatForm.tsx

Lines changed: 48 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,13 @@ interface ChatFormProps {
2121
execResults: Record<string, ReplOutput[]>;
2222
}
2323

24-
export function ChatForm({ documentContent, sectionId, replOutputs, fileContents, execResults }: ChatFormProps) {
24+
export function ChatForm({
25+
documentContent,
26+
sectionId,
27+
replOutputs,
28+
fileContents,
29+
execResults,
30+
}: ChatFormProps) {
2531
const [messages, updateChatHistory] = useChatHistory(sectionId);
2632
const [inputValue, setInputValue] = useState("");
2733
const [isLoading, setIsLoading] = useState(false);
@@ -54,9 +60,10 @@ export function ChatForm({ documentContent, sectionId, replOutputs, fileContents
5460
updateChatHistory([userMessage]);
5561

5662
let userQuestion = inputValue;
57-
if(!userQuestion && exampleData){
63+
if (!userQuestion && exampleData) {
5864
// 質問が空欄なら、質問例を使用
59-
userQuestion = exampleData[Math.floor(exampleChoice * exampleData.length)];
65+
userQuestion =
66+
exampleData[Math.floor(exampleChoice * exampleData.length)];
6067
setInputValue(userQuestion);
6168
}
6269

@@ -69,7 +76,11 @@ export function ChatForm({ documentContent, sectionId, replOutputs, fileContents
6976
});
7077

7178
if (result.error) {
72-
const errorMessage: Message = { sender: "ai", text: `エラー: ${result.error}`, isError: true };
79+
const errorMessage: Message = {
80+
sender: "ai",
81+
text: `エラー: ${result.error}`,
82+
isError: true,
83+
};
7384
updateChatHistory([userMessage, errorMessage]);
7485
} else {
7586
const aiMessage: Message = { sender: "ai", text: result.response };
@@ -83,12 +94,20 @@ export function ChatForm({ documentContent, sectionId, replOutputs, fileContents
8394
const handleClearHistory = () => {
8495
updateChatHistory([]);
8596
};
86-
97+
8798
return (
8899
<>
89100
{isFormVisible && (
90-
<form className="border border-2 border-secondary shadow-md rounded-lg bg-base-100" style={{width:"100%", textAlign:"center", boxShadow:"-moz-initial"}} onSubmit={handleSubmit}>
91-
<div className="input-area">
101+
<form
102+
className="border border-2 border-secondary shadow-md rounded-lg bg-base-100"
103+
style={{
104+
width: "100%",
105+
textAlign: "center",
106+
boxShadow: "-moz-initial",
107+
}}
108+
onSubmit={handleSubmit}
109+
>
110+
<div className="input-area">
92111
<textarea
93112
className="textarea textarea-ghost textarea-md rounded-lg"
94113
placeholder={
@@ -108,7 +127,15 @@ export function ChatForm({ documentContent, sectionId, replOutputs, fileContents
108127
disabled={isLoading}
109128
></textarea>
110129
</div>
111-
<div className="controls" style={{margin:"10px", display:"flex", alignItems:"center", justifyContent:"space-between"}}>
130+
<div
131+
className="controls"
132+
style={{
133+
margin: "10px",
134+
display: "flex",
135+
alignItems: "center",
136+
justifyContent: "space-between",
137+
}}
138+
>
112139
<div className="left-icons">
113140
<button
114141
className="btn btn-soft btn-secondary rounded-full"
@@ -156,15 +183,21 @@ export function ChatForm({ documentContent, sectionId, replOutputs, fileContents
156183
</button>
157184
</div>
158185
{messages.map((msg, index) => (
159-
<div key={index} className={`chat ${msg.sender === 'user' ? 'chat-end' : 'chat-start'}`}>
160-
<div
186+
<div
187+
key={index}
188+
className={`chat ${msg.sender === "user" ? "chat-end" : "chat-start"}`}
189+
>
190+
<div
161191
className={clsx(
162192
"chat-bubble",
163-
{ "bg-primary text-primary-content": msg.sender === 'user' },
164-
{ "bg-secondary-content dark:bg-neutral text-black dark:text-white": msg.sender === 'ai' && !msg.isError },
193+
{ "bg-primary text-primary-content": msg.sender === "user" },
194+
{
195+
"bg-secondary-content dark:bg-neutral text-black dark:text-white":
196+
msg.sender === "ai" && !msg.isError,
197+
},
165198
{ "chat-bubble-error": msg.isError }
166-
)}
167-
style={{maxWidth: "100%", wordBreak: "break-word"}}
199+
)}
200+
style={{ maxWidth: "100%", wordBreak: "break-word" }}
168201
>
169202
<StyledMarkdown content={msg.text} />
170203
</div>
@@ -178,7 +211,6 @@ export function ChatForm({ documentContent, sectionId, replOutputs, fileContents
178211
AIが考え中です…
179212
</div>
180213
)}
181-
182214
</>
183215
);
184-
}
216+
}

app/[docs_id]/chatServer.ts

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
11
"use server";
22

3-
export async function hello() {
4-
5-
}
3+
export async function hello() {}

app/[docs_id]/markdown.tsx

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,10 @@ import { Heading } from "./section";
66
import { type AceLang, EditorComponent } from "../terminal/editor";
77
import { ExecFile, ExecLang } from "../terminal/exec";
88
import { useChangeTheme } from "./themeToggle";
9-
import { tomorrow, atomOneDark } from "react-syntax-highlighter/dist/esm/styles/hljs";
9+
import {
10+
tomorrow,
11+
atomOneDark,
12+
} from "react-syntax-highlighter/dist/esm/styles/hljs";
1013

1114
export function StyledMarkdown({ content }: { content: string }) {
1215
return (
@@ -16,7 +19,6 @@ export function StyledMarkdown({ content }: { content: string }) {
1619
);
1720
}
1821

19-
2022
// TailwindCSSがh1などのタグのスタイルを消してしまうので、手動でスタイルを指定する必要がある
2123
const components: Components = {
2224
h1: ({ children }) => <Heading level={1}>{children}</Heading>,
@@ -44,11 +46,25 @@ const components: Components = {
4446
),
4547
hr: ({ node, ...props }) => <hr className="border-primary my-4" {...props} />,
4648
pre: ({ node, ...props }) => props.children,
47-
code: ({ node, className, ref, style, ...props }) => <CodeComponent {...{ node, className, ref, style, ...props }} />,
49+
code: ({ node, className, ref, style, ...props }) => (
50+
<CodeComponent {...{ node, className, ref, style, ...props }} />
51+
),
4852
};
49-
function CodeComponent({ node, className, ref, style, ...props }: { node: unknown; className?: string; ref?: unknown; style?: unknown; [key: string]: unknown }) {
53+
function CodeComponent({
54+
node,
55+
className,
56+
ref,
57+
style,
58+
...props
59+
}: {
60+
node: unknown;
61+
className?: string;
62+
ref?: unknown;
63+
style?: unknown;
64+
[key: string]: unknown;
65+
}) {
5066
const theme = useChangeTheme();
51-
const codetheme= theme === "tomorrow" ? tomorrow : atomOneDark;
67+
const codetheme = theme === "tomorrow" ? tomorrow : atomOneDark;
5268
const match = /^language-(\w+)(-repl|-exec|-readonly)?\:?(.+)?$/.exec(
5369
className || ""
5470
);

app/[docs_id]/section.tsx

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -73,13 +73,13 @@ export function Section({ section, sectionId }: SectionProps) {
7373
<div>
7474
<Heading level={section.level}>{section.title}</Heading>
7575
<StyledMarkdown content={section.content} />
76-
<ChatForm
77-
documentContent={section.content}
78-
sectionId={sectionId}
79-
replOutputs={replOutputs}
80-
fileContents={fileContents}
81-
execResults={execResults}
82-
/>
76+
<ChatForm
77+
documentContent={section.content}
78+
sectionId={sectionId}
79+
replOutputs={replOutputs}
80+
fileContents={fileContents}
81+
execResults={execResults}
82+
/>
8383
</div>
8484
</SectionCodeContext.Provider>
8585
);

app/[docs_id]/splitMarkdown.ts

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,7 @@ export interface MarkdownSection {
1111
* Markdownコンテンツを見出しごとに分割し、
1212
* 見出しのレベルとタイトル、内容を含むオブジェクトの配列を返す。
1313
*/
14-
export function splitMarkdown(
15-
content: string
16-
): MarkdownSection[] {
14+
export function splitMarkdown(content: string): MarkdownSection[] {
1715
const tree = unified().use(remarkParse).use(remarkGfm).parse(content);
1816
// console.log(tree.children.map(({ type, position }) => ({ type, position: JSON.stringify(position) })));
1917
const headingNodes = tree.children.filter((node) => node.type === "heading");

app/[docs_id]/themeToggle.tsx

Lines changed: 57 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -1,75 +1,73 @@
11
"use client";
2-
import { useState, useEffect} from "react";
2+
import { useState, useEffect } from "react";
33

4-
export function useChangeTheme(){
5-
const [theme, setTheme] = useState("tomorrow");
6-
useEffect(() => {
4+
export function useChangeTheme() {
5+
const [theme, setTheme] = useState("tomorrow");
6+
useEffect(() => {
7+
const updateTheme = () => {
8+
const theme = document.documentElement.getAttribute("data-theme");
9+
setTheme(theme === "dark" ? "twilight" : "tomorrow");
10+
};
711

8-
const updateTheme = () => {
9-
const theme = document.documentElement.getAttribute("data-theme");
10-
setTheme(theme === "dark" ? "twilight" : "tomorrow");
11-
};
12-
13-
const observer = new MutationObserver(updateTheme);
14-
observer.observe(document.documentElement, {
15-
attributes: true,
16-
attributeFilter: ["data-theme"],
17-
});
18-
19-
20-
return () => observer.disconnect();
21-
}, []);
22-
return theme;
12+
const observer = new MutationObserver(updateTheme);
13+
observer.observe(document.documentElement, {
14+
attributes: true,
15+
attributeFilter: ["data-theme"],
16+
});
2317

24-
};
18+
return () => observer.disconnect();
19+
}, []);
20+
return theme;
21+
}
2522
export function ThemeToggle() {
2623
const theme = useChangeTheme();
2724
const isChecked = theme === "twilight";
2825
useEffect(() => {
2926
const checkIsDarkSchemePreferred = () =>
30-
window?.matchMedia?.('(prefers-color-scheme:dark)')?.matches ?? false;
27+
window?.matchMedia?.("(prefers-color-scheme:dark)")?.matches ?? false;
3128
const initialTheme = checkIsDarkSchemePreferred() ? "dark" : "light";
3229
document.documentElement.setAttribute("data-theme", initialTheme);
3330
}, []);
34-
31+
3532
return (
3633
<label className="flex cursor-pointer gap-2" style={{ marginLeft: "1em" }}>
37-
<svg
38-
xmlns="http://www.w3.org/2000/svg"
39-
width="20"
40-
height="20"
41-
viewBox="0 0 24 24"
42-
fill="none"
43-
stroke="currentColor"
44-
strokeWidth="2"
45-
strokeLinecap="round"
46-
strokeLinejoin="round">
47-
<circle cx="12" cy="12" r="5" />
48-
<path
49-
d="M12 1v2M12 21v2M4.2 4.2l1.4 1.4M18.4 18.4l1.4 1.4M1 12h2M21 12h2M4.2 19.8l1.4-1.4M18.4 5.6l1.4-1.4" />
50-
</svg>
51-
<input
52-
type="checkbox"
53-
checked={isChecked}
54-
className="toggle theme-controller"
55-
onChange={(e) => {
56-
const isdark = e.target.checked;
57-
const theme = isdark ? "dark" : "light";
58-
document.documentElement.setAttribute("data-theme", theme);
59-
}}
60-
/>
61-
<svg
62-
xmlns="http://www.w3.org/2000/svg"
63-
width="20"
64-
height="20"
65-
viewBox="0 0 24 24"
66-
fill="none"
67-
stroke="currentColor"
68-
strokeWidth="2"
69-
strokeLinecap="round"
70-
strokeLinejoin="round">
71-
<path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z"></path>
72-
</svg>
73-
</label>
34+
<svg
35+
xmlns="http://www.w3.org/2000/svg"
36+
width="20"
37+
height="20"
38+
viewBox="0 0 24 24"
39+
fill="none"
40+
stroke="currentColor"
41+
strokeWidth="2"
42+
strokeLinecap="round"
43+
strokeLinejoin="round"
44+
>
45+
<circle cx="12" cy="12" r="5" />
46+
<path d="M12 1v2M12 21v2M4.2 4.2l1.4 1.4M18.4 18.4l1.4 1.4M1 12h2M21 12h2M4.2 19.8l1.4-1.4M18.4 5.6l1.4-1.4" />
47+
</svg>
48+
<input
49+
type="checkbox"
50+
checked={isChecked}
51+
className="toggle theme-controller"
52+
onChange={(e) => {
53+
const isdark = e.target.checked;
54+
const theme = isdark ? "dark" : "light";
55+
document.documentElement.setAttribute("data-theme", theme);
56+
}}
57+
/>
58+
<svg
59+
xmlns="http://www.w3.org/2000/svg"
60+
width="20"
61+
height="20"
62+
viewBox="0 0 24 24"
63+
fill="none"
64+
stroke="currentColor"
65+
strokeWidth="2"
66+
strokeLinecap="round"
67+
strokeLinejoin="round"
68+
>
69+
<path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z"></path>
70+
</svg>
71+
</label>
7472
);
7573
}

0 commit comments

Comments
 (0)