Skip to content
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
65 changes: 36 additions & 29 deletions app/(docs)/@chat/chat/[chatId]/chatArea.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,42 +20,49 @@ export function ChatAreaContainer(props: {
<aside
className={clsx(
// モバイルでは全画面表示する
"fixed inset-0 pt-20 bg-base-100",
"fixed inset-0 bg-base-100",
// PCではスクロールで動かない右サイドバー
"has-chat-1:sticky has-chat-1:top-16 has-sidebar:top-0 has-chat-1:pt-4",
// 左にサイドバーがない=navvarがある とき、navbar分のスペースをあける(top-16, h-[100vh-4rem])
"has-chat-1:sticky has-chat-1:top-16 has-sidebar:top-0",
"has-chat-1:basis-2/5 has-chat-1:max-w-chat-area has-chat-1:h-[calc(100vh-4rem)] has-sidebar:h-screen",
"has-chat-1:shadow-md has-chat-1:bg-base-200",
// navbar(z-40)よりは下、ChatListForSectionのdropdown(デフォルトでz-999だがz-30に変えている)よりも上
"z-35",
"p-4",
"flex flex-col",
"overflow-y-auto"
"z-35"
)}
>
<ChatAreaStateUpdater chatId={props.chatId} />
<div className="flex flex-row items-center">
<span className="flex-1 text-base font-bold opacity-40">
AIへの質問
</span>
<Link className="btn btn-ghost" href="/chat" scroll={false}>
<svg
className="w-8 h-8 -scale-x-100"
viewBox="0 0 24 24"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M18 17L13 12L18 7M11 17L6 12L11 7"
stroke="currentColor"
strokeWidth="1.5"
strokeLinecap="round"
strokeLinejoin="round"
/>
</svg>
<span className="text-lg">閉じる</span>
</Link>
<div className="absolute inset-x-0 bottom-0 h-16 bg-linear-to-t from-base-200 to-base-200/0 z-1" />
<div
className={clsx(
"p-4 pb-16",
"pt-20 has-chat-1:pt-4",
"h-full flex flex-col overflow-y-auto"
)}
>
<ChatAreaStateUpdater chatId={props.chatId} />
<div className="flex flex-row items-center">
<span className="flex-1 text-base font-bold opacity-40">
AIへの質問
</span>
<Link className="btn btn-ghost" href="/chat" scroll={false}>
<svg
className="w-8 h-8 -scale-x-100"
viewBox="0 0 24 24"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M18 17L13 12L18 7M11 17L6 12L11 7"
stroke="currentColor"
strokeWidth="1.5"
strokeLinecap="round"
strokeLinejoin="round"
/>
</svg>
<span className="text-lg">閉じる</span>
</Link>
</div>
{props.children}
</div>
{props.children}
</aside>
);
}
Expand Down
2 changes: 1 addition & 1 deletion app/(docs)/@docs/[lang]/[pageId]/pageContent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ export function PageContent(props: PageContentProps) {
const [isFormVisible, setIsFormVisible] = useState(false);

return (
<div className="flex-1 p-4 flex flex-col">
<div className="flex-1 p-4 pb-16 flex flex-col">
<div
className="max-w-full mx-auto grid"
style={{
Expand Down
232 changes: 232 additions & 0 deletions app/featureCard.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,232 @@
"use client";

import clsx from "clsx";
import { ReactNode } from "react";
import { StyledMarkdown } from "./markdown/markdown";
import { Heading } from "./markdown/heading";
import {
ChatAreaStateProvider,
ChatAreaStateUpdater,
} from "./(docs)/chatAreaState";

export function FeatureCard(props: {
reversed?: boolean;
icon: ReactNode;
title: ReactNode;
children: ReactNode;
iconColor: string;
image: ReactNode;
}) {
return (
<div
className={clsx(
"flex flex-col items-center gap-4 md:gap-8",
props.reversed ? "md:flex-row-reverse" : "md:flex-row"
)}
>
<div className="flex-1 space-y-4 lg:space-y-8">
<div className="flex flex-row gap-2 items-center">
<span className={clsx("p-3 rounded-xl text-2xl", props.iconColor)}>
{props.icon}
</span>
<h3 className="text-2xl/8 md:text-3xl/10 font-bold">{props.title}</h3>
</div>
<p className="opacity-70 leading-relaxed text-lg">{props.children}</p>
</div>
<div className="w-80 max-w-full md:min-w-3/7 md:max-w-1/2">
<figure
className={clsx(
"aspect-video bg-base-200 rounded-xl border border-base-300 shadow-sm",
"relative overflow-hidden select-none"
)}
>
{props.image}
</figure>
</div>
</div>
);
}

export function RuntimeImage() {
// public/docs/python/1-basics/2-2-str.md より
return (
<div className="absolute left-2 w-200 -inset-y-100 h-max my-auto scale-70 md:scale-85 origin-left">
<StyledMarkdown
content={`### 文字列(str)

文字列はシングルクォート (\`'\`) またはダブルクォート (\`"\`) で囲んで作成します。

文字列の連結は \`+\` 演算子、繰り返しは \`*\` 演算子を使います。
`}
/>
<pre
className={clsx(
"bg-base-300 border-2 border-accent rounded-box shadow-md m-2 h-max",
"p-4 font-mono"
)}
>
&gt;&gt;&gt; name <HOperator>=</HOperator>{" "}
<HString>&quot;Guido&quot;</HString>
{"\n"}
&gt;&gt;&gt; greeting <HOperator>=</HOperator>{" "}
<HString>&apos;Hello&apos;</HString>
{"\n"}
&gt;&gt;&gt; full_greeting <HOperator>=</HOperator> greeting{" "}
<HOperator>+</HOperator> <HString>&quot;, &quot;</HString>{" "}
<HOperator>+</HOperator> name <HOperator>+</HOperator>{" "}
<HString>&quot;!&quot;</HString>
{"\n"}
&gt;&gt;&gt; <Cursor />
</pre>
</div>
);
}

export function PracticeImage() {
// public/docs/python/1-basics/2-2-str.md より
return (
<div className="absolute left-2 w-200 top-0 scale-70 md:scale-85 origin-top-left">
<StyledMarkdown
content={`### 練習問題1

\`item_name\` という変数に商品名(文字列)、\`price\` という変数に価格(整数)、\`stock\` という変数に在庫数(整数)をそれぞれ代入してください。その後、f-stringを使って「商品: [商品名], 価格: [価格]円, 在庫: [在庫数]個」という形式の文字列にし、 \`print()\` で出力するコードを書いてみましょう。
`}
/>
<div
className={clsx(
"bg-base-300 border-2 border-accent rounded-box shadow-md m-2",
"h-60 overflow-hidden"
)}
>
<div className="flex flex-row items-center bg-base-200">
<span className="mt-2 mb-1 ml-3 mr-2 text-sm text-left">
<span>ファイルを編集:</span>
<span className="font-mono ml-2">practice2-1.py</span>
</span>
<div className="flex-1" />
</div>
<pre className="px-4 py-2">
item_name = <HString>&quot;高性能マウス&quot;</HString>
{"\n"}
price = <HNumber>4500</HNumber>
</pre>
</div>
</div>
);
}

export function ChatImage() {
// public/docs/python/1-basics/2-1-str.md より
return (
<>
<div className="absolute right-2/5 w-[85%] md:w-[70%] top-0 scale-70 md:scale-85 origin-top-right pointer-events-none">
{/*ここでChatAreaStateProviderのインスタンス作りダミーの値をセットすることで、
StyledMarkdownが呼び出すMultiHighlightに現在このチャットを開いていると認識させる
*/}
<ChatAreaStateProvider>
<ChatAreaStateUpdater chatId="sample" />
<StyledMarkdown
content={`### 数値(int, float)

Pythonは整数 (\`int\`) と浮動小数点数 (\`float\`) を区別します。
浮動小数点数 (\`float\`) は、他の言語の double 型に相当する倍精度浮動小数点数です。
`}
replacedRange={[{ start: 64, end: 120, id: "sample" }]}
/>
</ChatAreaStateProvider>
<pre
className={clsx(
"bg-base-300 border-2 border-accent rounded-box shadow-md m-2 h-max",
"p-4 font-mono"
)}
>
&gt;&gt;&gt; <HDim># 整数 (int)</HDim>
{"\n"}
&gt;&gt;&gt; a <HOperator>=</HOperator> <HNumber>10</HNumber>
{"\n"}
&gt;&gt;&gt; <HFunc>type</HFunc>
<HDim>(</HDim>a<HDim>)</HDim>
{"\n"}
<HOperator>
&lt;class <HString>&apos;int&apos;</HString>&gt;
</HOperator>
{"\n"}
&gt;&gt;&gt; <HDim># 浮動小数点数 (float)</HDim>
{"\n"}
&gt;&gt;&gt; b <HOperator>=</HOperator> <HNumber>3.14</HNumber>
{"\n"}
&gt;&gt;&gt; <HFunc>type</HFunc>
<HDim>(</HDim>b<HDim>)</HDim>
{"\n"}
<HOperator>
&lt;class <HString>&apos;float&apos;</HString>&gt;
</HOperator>
</pre>
</div>
<aside
className={clsx(
"absolute left-3/5 md:w-80 top-0 scale-70 md:scale-85 origin-top-left",
"bg-base-300 shadow-md p-3 flex flex-col"
)}
>
<span className="flex-1 text-base font-bold opacity-40">
AIへの質問
</span>
<Heading level={2} className="mt-1! mb-1! text-nowrap">
Pythonのdouble型について
</Heading>
<div className="divider my-0" />
<div className="chat chat-end place-items-start ml-3">
<div
className="chat-bubble p-0! bg-secondary/30"
style={{ maxWidth: "100%", wordBreak: "break-word" }}
>
<StyledMarkdown content="double型はありますか?" />
</div>
</div>
<StyledMarkdown
content={`Pythonには「double型」は存在しません。他の言語(C++、Java、C#など)でおなじみのdouble型に相当するのは、Pythonの**float型**です。

Pythonのfloat型は**倍精度浮動小数点数(double-precision floating point)** を表し、他の言語のdouble型と同じ桁数の精度(通常15〜17桁)を提供します。そのため、Pythonでは単一のfloat型だけで十分です。`}
/>
</aside>
</>
);
}

function HString(props: { children: ReactNode }) {
return <span className="text-green-700">{props.children}</span>;
}
function HOperator(props: { children: ReactNode }) {
return <span className="text-fuchsia-500">{props.children}</span>;
}
function HNumber(props: { children: ReactNode }) {
return <span className="text-yellow-700">{props.children}</span>;
}
function HFunc(props: { children: ReactNode }) {
return <span className="text-cyan-600">{props.children}</span>;
}
function HDim(props: { children: ReactNode }) {
return <span className="opacity-50">{props.children}</span>;
}
function Cursor() {
return (
<span
ref={(el) => {
// カーソルの点滅アニメーション
el?.animate([{ opacity: "1" }, { opacity: "0" }, { opacity: "1" }], {
duration: 1000,
iterations: Infinity,
easing: "steps(2, end)",
});
}}
style={{
display: "inline-block",
boxShadow: `2px 0 0 var(--color-primary) inset`,
verticalAlign: "top",
}}
>
{" "}
</span>
);
}
48 changes: 48 additions & 0 deletions app/footer.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
export function Footer() {
return (
<footer className="footer sm:footer-horizontal bg-neutral text-neutral-content p-10 z-30">
<aside>
<h6 className="flex gap-2 items-center">
<img src="/icon.svg" alt="my.code(); Logo" className="w-12 h-12" />
<span className="text-3xl font-semibold font-mono drop-shadow-sm">
my.code();
</span>
</h6>
<p className="text-lg">環境構築不要、その場で実践。</p>
<a
className="link link-hover"
href="https://github.com/ut-code/my-code"
target="_blank"
>
{/*<!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->*/}
<svg
fill="currentColor"
className="inline-block w-4 h-4 mr-1"
viewBox="0 0 24 24"
>
<path d="M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12" />
</svg>
ut-code / my-code
</a>
<p>Copyright © 2026 ut.code();</p>
</aside>
<nav>
<h6 className="footer-title normal-case">ut.code(); について</h6>
<a
className="link link-hover"
href="https://utcode.net/"
target="_blank"
>
公式ウェブサイト
</a>
<a
className="link link-hover"
href="https://twitter.com/utokyo_code"
target="_blank"
>
公式 𝕏 アカウント
</a>
</nav>
</footer>
);
}
2 changes: 2 additions & 0 deletions app/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import { AutoAnonymousLogin } from "./accountMenu";
import { SidebarMdProvider } from "./sidebar";
import { RuntimeProvider } from "@my-code/runtime/context";
import { getPagesList } from "@/lib/docs";
import { Footer } from "./footer";

export const metadata: Metadata = {
title: {
Expand Down Expand Up @@ -53,6 +54,7 @@ export default async function RootLayout({
</div>
</div>
</SidebarMdProvider>
<Footer />
</body>
</html>
);
Expand Down
Loading
Loading