Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
be16784
feat: Add /[lang]/sandbox page with REPL, code execution, file additi…
na-trium-144 Aug 12, 2026
6a396d5
feat(terminal): add supportsMultiFile config and delete button to Edi…
na-trium-144 Aug 13, 2026
05449e8
feat(sandbox): reorder sections and add TOC scroll tracking
na-trium-144 Aug 13, 2026
be051ff
feat(sidebar): move Sandbox to top of language list and render its TOC
na-trium-144 Aug 13, 2026
a47b975
見た目を修正
na-trium-144 Aug 16, 2026
ab4d341
チャット作成時にreplOutputs, files, execResultsを保存し、再生成時に当時のコード情報を引き継ぐように修正
na-trium-144 Aug 16, 2026
813c02c
regenerate-sectionのリクエストから不要なコード状態パラメータを削除し、oldChatの情報のみを使用するように修正
na-trium-144 Aug 16, 2026
3c70709
refactor: api/chat と lib/chatGenerator.ts のプロンプト定義および関連処理を共通化
na-trium-144 Aug 16, 2026
00c8a5c
見た目を修正
na-trium-144 Aug 16, 2026
59430eb
テストを /about/runtime に移動
na-trium-144 Aug 16, 2026
6214260
EmbedContextの管理をURL依存からlang/pageIdパラメータ依存に変更し各docsページへ移動
na-trium-144 Aug 16, 2026
96ce598
useSendChatからEmbedContext依存を削除し引数で受け取るようにリファクタリング
na-trium-144 Aug 16, 2026
55e08d6
不要なlayoutを削除
na-trium-144 Aug 17, 2026
e4a08f7
sampleConfigをruntimeのlanguage定義に統合
na-trium-144 Aug 17, 2026
b2e6c06
tooltipの色を変更
na-trium-144 Aug 17, 2026
f562f14
出力ファイル追加機能
na-trium-144 Aug 17, 2026
dee53bb
fix
na-trium-144 Aug 17, 2026
1978eb2
refactor
na-trium-144 Aug 17, 2026
7f9adfe
最大化ボタン関連のidをエンコード
na-trium-144 Aug 18, 2026
c248174
editorの角を修正、ついでにpadding調整
na-trium-144 Aug 18, 2026
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
27 changes: 19 additions & 8 deletions app/(docs)/@chat/chat/[chatId]/chatArea.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,9 @@ export function ChatAreaContent(props: Props) {
questionScope: "page",
sectionContent: priorSectionContent,
deleteChatOnCreated: chatId,
replOutputs: chatData.replOutputs ?? {},
files: chatData.files ?? {},
execResults: chatData.execResults ?? {},
});
};

Expand All @@ -127,20 +130,28 @@ export function ChatAreaContent(props: Props) {
<div className="flex-none breadcrumbs text-sm">
<ul className="flex-wrap">
<li>
<Link href={`/${langId}/${langEntry?.pages[0].slug}`}>
{langEntry?.name}
<Link
href={
langEntry?.pages[0]
? `/${langId}/${langEntry.pages[0].slug}`
: `/${langId}/sandbox`
}
>
{langEntry?.name ?? langId}
</Link>
</li>
<li>
<Link href={`/${chatData.section.pagePath}`}>
{pageEntry?.index}. {pageEntry?.name}
</Link>
</li>
<li>
<Link href={`/${chatData.section.pagePath}#${chatData.sectionId}`}>
{targetSection?.title}
{pageEntry ? `${pageEntry.index}. ${pageEntry.name}` : "Sandbox"}
</Link>
</li>
{targetSection?.title && targetSection.title !== "sandbox" && (
<li>
<Link href={`/${chatData.section.pagePath}#${chatData.sectionId}`}>
{targetSection.title}
</Link>
</li>
)}
</ul>
</div>
<div className="flex flex-wrap items-center gap-2">
Expand Down
5 changes: 5 additions & 0 deletions app/(docs)/@docs/[lang]/[pageId]/chatForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import {
// import { getLanguageName } from "../pagesList";
import { DynamicMarkdownSection, PagePath } from "@/lib/docs";
import { useSendChat } from "@/(docs)/useSendChat";
import { useEmbedContext } from "@/terminal/embedContext";

interface ChatFormProps {
path: PagePath;
Expand All @@ -30,6 +31,7 @@ export function ChatForm({ path, langName, sectionContent, close }: ChatFormProp
);

const { sendChat, isLoading, errorMessage } = useSendChat();
const { files, replOutputs, execResults } = useEmbedContext();

const exampleData = useMemo(
() =>
Expand Down Expand Up @@ -70,6 +72,9 @@ export function ChatForm({ path, langName, sectionContent, close }: ChatFormProp
userQuestion,
questionScope,
sectionContent,
files,
replOutputs,
execResults,
onSuccess: () => {
setInputValue("");
close();
Expand Down
29 changes: 16 additions & 13 deletions app/(docs)/@docs/[lang]/[pageId]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import {
} from "@/lib/docs";
import { DocsAutoRedirect } from "./autoRedirect";
import { TermDefinitionProvider } from "@/markdown/term";
import { EmbedContextProvider } from "@/terminal/embedContext";

export async function generateMetadata({
params,
Expand Down Expand Up @@ -68,19 +69,21 @@ export default async function Page({

return (
<>
<TermDefinitionProvider
termDefinitions={termDefinitions}
lang={lang}
page={pageId}
>
<PageContent
chatHistories={chatHistories}
splitMdContent={splitMdContent}
langId={lang}
pageSlug={pageId}
path={path}
/>
</TermDefinitionProvider>
<EmbedContextProvider lang={lang} pageId={pageId}>
<TermDefinitionProvider
termDefinitions={termDefinitions}
lang={lang}
page={pageId}
>
<PageContent
chatHistories={chatHistories}
splitMdContent={splitMdContent}
langId={lang}
pageSlug={pageId}
path={path}
/>
</TermDefinitionProvider>
</EmbedContextProvider>
<DocsAutoRedirect path={path} />
</>
);
Expand Down
86 changes: 45 additions & 41 deletions app/(docs)/@docs/[lang]/[pageId]/pageContent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ import Link from "next/link";
import { useChatId } from "@/(docs)/chatAreaState";
import { ChatWithMessages } from "@/lib/chatHistory";
import { usePagesListForLang } from "@/pagesListContext";
import { useEmbedContext } from "@/terminal/embedContext";
import { useRouter } from "next/navigation";
import { revalidateChatAction } from "@/actions/revalidateChat";
import { RegenerateStreamEvent } from "@/api/chat/regenerate-section/route";
Expand Down Expand Up @@ -167,10 +166,12 @@ export function PageContent(props: PageContentProps) {
);
}

function ChatListForSection(props: {
export function ChatListForSection(props: {
dynamicMdContent: DynamicMarkdownSection[];
sectionId: SectionId;
chatHistories: ChatWithMessages[];
fullWidth?: boolean;
className?: string;
}) {
const { dynamicMdContent, sectionId, chatHistories } = props;
const filteredChatHistories = chatHistories.filter(
Expand All @@ -195,10 +196,15 @@ function ChatListForSection(props: {
*/}
<ul
className={clsx(
chatId === null
? "hidden has-chat-1:block"
: "hidden has-chat-2:block",
"mt-2 ml-4 w-full max-w-chat-list",
props.className,
props.fullWidth
? ""
: clsx(
chatId === null
? "hidden has-chat-1:block"
: "hidden has-chat-2:block",
"mt-2 ml-4 w-full max-w-chat-list"
),
"menu menu-sm",
"rounded-lg shadow-sm bg-base-200"
)}
Expand All @@ -223,40 +229,42 @@ function ChatListForSection(props: {
))}
</ul>
{/*xl未満 or xl以上でチャットを表示している → 小さいボタンを表示*/}
<details
className={clsx(
chatId === null
? "block has-chat-1:hidden"
: "block has-chat-2:block",
"dropdown dropdown-end",
"mt-2 ml-2"
)}
>
<summary className="btn btn-outline btn-secondary btn-sm">
<ChatIcon />
{filteredChatHistories.length}
</summary>
<ul
{!props.fullWidth && (
<details
className={clsx(
"menu menu-sm dropdown-content",
"w-max max-w-[75vw]",
"z-30",
"rounded-lg shadow-sm bg-base-200/60 backdrop-blur-xs"
chatId === null
? "block has-chat-1:hidden"
: "block has-chat-2:hidden",
"mt-2 ml-2",
"dropdown dropdown-end"
)}
>
{filteredChatHistories.map(({ title, chatId }) => (
<li key={chatId}>
<Link
className="text-wrap text-justify"
href={`/chat/${chatId}`}
scroll={false}
>
{title}
</Link>
</li>
))}
</ul>
</details>
<summary className="btn btn-outline btn-secondary btn-sm">
<ChatIcon />
{filteredChatHistories.length}
</summary>
<ul
className={clsx(
"menu menu-sm dropdown-content",
"w-max max-w-[75vw]",
"z-30",
"rounded-lg shadow-sm bg-base-200/60 backdrop-blur-xs"
)}
>
{filteredChatHistories.map(({ title, chatId }) => (
<li key={chatId}>
<Link
className="text-wrap text-justify"
href={`/chat/${chatId}`}
scroll={false}
>
{title}
</Link>
</li>
))}
</ul>
</details>
)}
</>
);
}
Expand Down Expand Up @@ -302,7 +310,6 @@ function OutdatedSectionAlert(props: {
total: 0,
});

const { files, replOutputs, execResults } = useEmbedContext();
const router = useRouter();

const handleRegenerateSection = async () => {
Expand All @@ -324,9 +331,6 @@ function OutdatedSectionAlert(props: {
body: JSON.stringify({
path,
sectionId,
replOutputs,
files,
execResults,
}),
});

Expand Down
50 changes: 50 additions & 0 deletions app/(docs)/@docs/[lang]/sandbox/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import { Metadata } from "next";
import { notFound } from "next/navigation";
import { SandboxContent } from "./sandboxContent";
import { getChatFromCache, initContext } from "@/lib/chatHistory";
import { getPagesListForLang, LangId, PageSlug } from "@/lib/docs";
import { EmbedContextProvider } from "@/terminal/embedContext";
import { DocsAutoRedirect } from "../[pageId]/autoRedirect";

export async function generateMetadata({
params,
}: {
params: Promise<{ lang: LangId }>;
}): Promise<Metadata> {
const { lang } = await params;
const langEntry = await getPagesListForLang(lang);
if (!langEntry) notFound();

return {
title: `${langEntry.name} - Sandbox`,
description: `${langEntry.name} のインタラクティブなコード実行サンドボックスです。`,
};
}

export default async function Page({
params,
}: {
params: Promise<{ lang: LangId }>;
}) {
const { lang } = await params;

const langEntry = await getPagesListForLang(lang);
if (!langEntry) notFound();

const path = { lang, page: "sandbox" as PageSlug };
const context = await initContext();
const chatHistories = await getChatFromCache(path, context.userId);

return (
<>
<EmbedContextProvider lang={lang} pageId="sandbox">
<SandboxContent
langId={lang}
path={path}
chatHistories={chatHistories}
/>
</EmbedContextProvider>
<DocsAutoRedirect path={path} />
</>
);
}
Loading
Loading