@@ -12,9 +12,12 @@ import {
1212 MarkdownSection ,
1313 PageEntry ,
1414 PagePath ,
15+ SectionId ,
1516} from "@/lib/docs" ;
1617import { ReplacedRange } from "@/markdown/multiHighlight" ;
1718import { Heading } from "@/markdown/heading" ;
19+ import Link from "next/link" ;
20+ import { useChatId } from "@/(docs)/chatAreaState" ;
1821
1922/**
2023 * MarkdownSectionに追加で、動的な情報を持たせる
@@ -159,71 +162,41 @@ export function PageContent(props: PageContentProps) {
159162 const [ isFormVisible , setIsFormVisible ] = useState ( false ) ;
160163
161164 return (
162- < div
163- className = "p-4 mx-auto max-w-full grid"
164- style = { {
165- gridTemplateColumns : `1fr auto` ,
166- } }
167- >
168- < Heading level = { 1 } >
169- 第{ pageEntry . index } 章: { pageEntry . title }
170- </ Heading >
171- < div />
172- { dynamicMdContent . map ( ( section , index ) => (
173- < Fragment key = { section . id } >
174- < div
175- className = "min-w-1/2 max-w-200 text-justify"
176- id = { section . id } // 目次からaタグで飛ぶために必要
177- ref = { ( el ) => {
178- sectionRefs . current [ index ] = el ;
179- } }
180- >
181- { /* ドキュメントのコンテンツ */ }
182- < StyledMarkdown
183- content = { section . replacedContent }
184- replacedRange = { section . replacedRange }
185- />
186- </ div >
187- < div >
188- { /* 右側に表示するチャット履歴欄 */ }
189- { chatHistories
190- . filter (
191- ( c ) =>
192- c . sectionId === section . id ||
193- // 対象のセクションが存在しないものは、introセクション(index=0)にフォールバックする
194- ( index === 0 &&
195- dynamicMdContent . every ( ( sec ) => c . sectionId !== sec . id ) )
196- )
197- . map ( ( { chatId, messages } ) => (
198- < div
199- key = { chatId }
200- className = "max-w-xs mb-2 p-2 text-sm border border-base-content/10 rounded-sm shadow-sm bg-base-200"
201- >
202- < div className = "max-h-60 overflow-y-auto" >
203- { messages . map ( ( msg , index ) => (
204- < div
205- key = { index }
206- className = { `chat ${ msg . role === "user" ? "chat-end" : "chat-start" } ` }
207- >
208- < div
209- className = { clsx (
210- msg . role === "user" &&
211- "chat-bubble p-0.5! bg-secondary/30" ,
212- msg . role === "ai" && "chat-bubble p-0.5!" ,
213- msg . role === "error" && "text-error"
214- ) }
215- style = { { maxWidth : "100%" , wordBreak : "break-word" } }
216- >
217- < StyledMarkdown content = { msg . content } />
218- </ div >
219- </ div >
220- ) ) }
221- </ div >
222- </ div >
223- ) ) }
224- </ div >
225- </ Fragment >
226- ) ) }
165+ < div className = "flex-1 p-4 flex flex-col" >
166+ < div
167+ className = "max-w-full mx-auto grid"
168+ style = { {
169+ gridTemplateColumns : `1fr auto` ,
170+ } }
171+ >
172+ < Heading className = "max-w-200" level = { 1 } >
173+ 第{ pageEntry . index } 章: { pageEntry . title }
174+ </ Heading >
175+ < div />
176+ { dynamicMdContent . map ( ( section , index ) => (
177+ < Fragment key = { section . id } >
178+ < div
179+ className = "min-w-1/2 max-w-200 text-justify"
180+ id = { section . id } // 目次からaタグで飛ぶために必要
181+ ref = { ( el ) => {
182+ sectionRefs . current [ index ] = el ;
183+ } }
184+ >
185+ { /* ドキュメントのコンテンツ */ }
186+ < StyledMarkdown
187+ content = { section . replacedContent }
188+ replacedRange = { section . replacedRange }
189+ />
190+ </ div >
191+ < div >
192+ < ChatListForSection
193+ sectionId = { section . id }
194+ dynamicMdContent = { dynamicMdContent }
195+ />
196+ </ div >
197+ </ Fragment >
198+ ) ) }
199+ </ div >
227200 < PageTransition
228201 lang = { path . lang }
229202 prevPage = { props . prevPage }
@@ -250,3 +223,96 @@ export function PageContent(props: PageContentProps) {
250223 </ div >
251224 ) ;
252225}
226+
227+ function ChatListForSection ( props : {
228+ dynamicMdContent : DynamicMarkdownSection [ ] ;
229+ sectionId : SectionId ;
230+ } ) {
231+ const { chatHistories } = useChatHistoryContext ( ) ;
232+ const { dynamicMdContent, sectionId } = props ;
233+ const filteredChatHistories = chatHistories . filter (
234+ ( c ) =>
235+ c . sectionId === sectionId ||
236+ // 対象のセクションが存在しないものは、introセクション(index=0)にフォールバックする
237+ ( dynamicMdContent [ 0 ] . id === sectionId &&
238+ dynamicMdContent . every ( ( sec ) => c . sectionId !== sec . id ) )
239+ ) ;
240+
241+ const chatId = useChatId ( ) ;
242+
243+ if ( filteredChatHistories . length === 0 ) {
244+ // チャットがないなら何も表示しない
245+ return null ;
246+ }
247+
248+ return (
249+ < >
250+ { /*PC表示かつチャットを表示していない → チャットリストを表示*/ }
251+ < ul
252+ className = { clsx (
253+ chatId === null ? "hidden lg:block" : "hidden" ,
254+ "mt-2 ml-4 max-w-60" ,
255+ "menu menu-sm" ,
256+ "border border-base-content/10 rounded-sm shadow-sm bg-base-200"
257+ ) }
258+ >
259+ < li className = "menu-title" > チャット</ li >
260+ { filteredChatHistories . map ( ( { chatId } ) => (
261+ < li key = { chatId } className = "" >
262+ < Link className = "link link-info" href = { `/chat/${ chatId } ` } >
263+ { chatId }
264+ </ Link >
265+ </ li >
266+ ) ) }
267+ </ ul >
268+ { /*PCでない or PC表示でチャットを表示している → 小さい吹き出しを表示*/ }
269+ < details
270+ className = { clsx (
271+ chatId === null ? "block lg:hidden" : "block" ,
272+ "dropdown dropdown-end" ,
273+ "mt-2 ml-2"
274+ ) }
275+ >
276+ < summary className = "btn btn-outline btn-secondary btn-sm" >
277+ { /*<!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->*/ }
278+ < svg
279+ className = "w-4 h-4"
280+ viewBox = "3.5 2.5 18 18"
281+ fill = "none"
282+ xmlns = "http://www.w3.org/2000/svg"
283+ >
284+ < path
285+ fillRule = "evenodd"
286+ clipRule = "evenodd"
287+ d = "M5.5 12C5.49988 14.613 6.95512 17.0085 9.2741 18.2127C11.5931 19.4169 14.3897 19.2292 16.527 17.726L19.5 18V12C19.5 8.13401 16.366 5 12.5 5C8.63401 5 5.5 8.13401 5.5 12Z"
288+ stroke = "currentColor"
289+ strokeWidth = "1.5"
290+ strokeLinecap = "round"
291+ strokeLinejoin = "round"
292+ />
293+ < path
294+ d = "M9.5 13.25C9.08579 13.25 8.75 13.5858 8.75 14C8.75 14.4142 9.08579 14.75 9.5 14.75V13.25ZM13.5 14.75C13.9142 14.75 14.25 14.4142 14.25 14C14.25 13.5858 13.9142 13.25 13.5 13.25V14.75ZM9.5 10.25C9.08579 10.25 8.75 10.5858 8.75 11C8.75 11.4142 9.08579 11.75 9.5 11.75V10.25ZM15.5 11.75C15.9142 11.75 16.25 11.4142 16.25 11C16.25 10.5858 15.9142 10.25 15.5 10.25V11.75ZM9.5 14.75H13.5V13.25H9.5V14.75ZM9.5 11.75H15.5V10.25H9.5V11.75Z"
295+ fill = "currentColor"
296+ />
297+ </ svg >
298+ { filteredChatHistories . length }
299+ </ summary >
300+ < ul
301+ className = { clsx (
302+ "menu menu-sm dropdown-content" ,
303+ "w-max max-w-[75vw]" ,
304+ "border border-base-content/10 rounded-sm shadow-sm bg-base-200"
305+ ) }
306+ >
307+ { filteredChatHistories . map ( ( { chatId } ) => (
308+ < li key = { chatId } className = "" >
309+ < Link className = "link link-info" href = { `/chat/${ chatId } ` } >
310+ { chatId }
311+ </ Link >
312+ </ li >
313+ ) ) }
314+ </ ul >
315+ </ details >
316+ </ >
317+ ) ;
318+ }
0 commit comments