mirror of
				https://github.com/open-webui/open-webui
				synced 2025-06-26 18:26:48 +00:00 
			
		
		
		
	Merge pull request #11699 from shaun-gallagher-octane/markdown-alert-renderer
feat: Markdown alert renderer
This commit is contained in:
		
						commit
						f1a84f45c8
					
				
							
								
								
									
										116
									
								
								src/lib/components/chat/Messages/Markdown/AlertRenderer.svelte
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										116
									
								
								src/lib/components/chat/Messages/Markdown/AlertRenderer.svelte
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,116 @@ | ||||
| <script lang="ts" context="module"> | ||||
| 	import { marked, type Token } from 'marked'; | ||||
| 
 | ||||
|     type AlertType = "NOTE" | "TIP" | "IMPORTANT" | "WARNING" | "CAUTION"; | ||||
| 
 | ||||
|     interface AlertTheme { | ||||
|         border: string; | ||||
|         text: string; | ||||
|         icon: ComponentType; | ||||
|     } | ||||
| 
 | ||||
|     export interface AlertData { | ||||
|         type: AlertType; | ||||
|         text: string; | ||||
|         tokens: Token[]; | ||||
|     } | ||||
| 
 | ||||
|     const alertStyles: Record<AlertType, AlertTheme> = { | ||||
|         "NOTE": { | ||||
|             border: "border-sky-500", | ||||
|             text: "text-sky-500", | ||||
|             icon: Info | ||||
|         }, | ||||
|         "TIP": { | ||||
|             border: "border-emerald-500", | ||||
|             text: "text-emerald-500", | ||||
|             icon: LightBlub | ||||
|         }, | ||||
|         "IMPORTANT": { | ||||
|             border: "border-purple-500", | ||||
|             text: "text-purple-500", | ||||
|             icon: Star | ||||
|         }, | ||||
|         "WARNING": { | ||||
|             border: "border-yellow-500", | ||||
|             text: "text-yellow-500", | ||||
|             icon: ArrowRightCircle | ||||
|         }, | ||||
|         "CAUTION": { | ||||
|             border: "border-rose-500", | ||||
|             text: "text-rose-500", | ||||
|             icon: Bolt | ||||
|         } | ||||
|     }; | ||||
| 
 | ||||
|     export function alertComponent(token: Token): AlertData | false { | ||||
|         const regExpStr = `^(?:\\[!(NOTE|TIP|IMPORTANT|WARNING|CAUTION)\\])\\s*?\n*`; | ||||
|         const regExp = new RegExp(regExpStr); | ||||
|         const matches = token.text?.match(regExp); | ||||
| 
 | ||||
|         if (matches && matches.length) { | ||||
|             const alertType = matches[1] as AlertType; | ||||
|             const newText = token.text.replace(regExp, ''); | ||||
|             const newTokens = marked.lexer(newText); | ||||
|             return { | ||||
|                 type: alertType, | ||||
|                 text: newText, | ||||
|                 tokens: newTokens | ||||
|             }; | ||||
|         } | ||||
|         return false; | ||||
|     } | ||||
| </script> | ||||
| 
 | ||||
| <script lang="ts"> | ||||
|     import Info from '$lib/components/icons/Info.svelte'; | ||||
|     import Star from '$lib/components/icons/Star.svelte'; | ||||
|     import LightBlub from '$lib/components/icons/LightBlub.svelte'; | ||||
|     import Bolt from '$lib/components/icons/Bolt.svelte'; | ||||
|     import ArrowRightCircle from '$lib/components/icons/ArrowRightCircle.svelte'; | ||||
|     import MarkdownTokens from './MarkdownTokens.svelte'; | ||||
|     import type { ComponentType } from 'svelte'; | ||||
| 
 | ||||
|     export let token: Token; | ||||
|     export let alert: AlertData; | ||||
|     export let id = ''; | ||||
|     export let tokenIdx = 0; | ||||
|     export let onTaskClick: ((event: MouseEvent) => void) | undefined = undefined; | ||||
|     export let onSourceClick: ((event: MouseEvent) => void) | undefined = undefined; | ||||
| </script> | ||||
| 
 | ||||
| <!-- | ||||
| 
 | ||||
| Renders the following Markdown as alerts: | ||||
| 
 | ||||
| > [!NOTE] | ||||
| > Example note | ||||
| 
 | ||||
| > [!TIP] | ||||
| > Example tip | ||||
| 
 | ||||
| > [!IMPORTANT] | ||||
| > Example important | ||||
| 
 | ||||
| > [!CAUTION] | ||||
| > Example caution | ||||
| 
 | ||||
| > [!WARNING] | ||||
| > Example warning | ||||
| 
 | ||||
| --> | ||||
| <div class={`border-l-2 pl-2 ${alertStyles[alert.type].border}`}> | ||||
|     <p class={alertStyles[alert.type].text}> | ||||
|         <svelte:component | ||||
|             this={alertStyles[alert.type].icon} | ||||
|             className="inline-block size-4" | ||||
|         /> | ||||
|         <b>{alert.type}</b> | ||||
|     </p> | ||||
|     <MarkdownTokens | ||||
|         id={`${id}-${tokenIdx}`} | ||||
|         tokens={alert.tokens} | ||||
|         {onTaskClick} | ||||
|         {onSourceClick} | ||||
|     /> | ||||
| </div> | ||||
| @ -14,9 +14,11 @@ | ||||
| 	import CodeBlock from '$lib/components/chat/Messages/CodeBlock.svelte'; | ||||
| 	import MarkdownInlineTokens from '$lib/components/chat/Messages/Markdown/MarkdownInlineTokens.svelte'; | ||||
| 	import KatexRenderer from './KatexRenderer.svelte'; | ||||
| 	import AlertRenderer, { alertComponent } from './AlertRenderer.svelte'; | ||||
| 	import Collapsible from '$lib/components/common/Collapsible.svelte'; | ||||
| 	import Tooltip from '$lib/components/common/Tooltip.svelte'; | ||||
| 	import ArrowDownTray from '$lib/components/icons/ArrowDownTray.svelte'; | ||||
| 
 | ||||
| 	import Source from './Source.svelte'; | ||||
| 	import { settings } from '$lib/stores'; | ||||
| 
 | ||||
| @ -172,9 +174,14 @@ | ||||
| 			</div> | ||||
| 		</div> | ||||
| 	{:else if token.type === 'blockquote'} | ||||
| 		<blockquote dir="auto"> | ||||
| 			<svelte:self id={`${id}-${tokenIdx}`} tokens={token.tokens} {onTaskClick} {onSourceClick} /> | ||||
| 		</blockquote> | ||||
| 		{@const alert = alertComponent(token)} | ||||
| 		{#if alert} | ||||
| 			<AlertRenderer token={token} alert={alert} /> | ||||
| 		{:else} | ||||
| 			<blockquote dir="auto"> | ||||
| 				<svelte:self id={`${id}-${tokenIdx}`} tokens={token.tokens} {onTaskClick} {onSourceClick} /> | ||||
| 			</blockquote> | ||||
| 		{/if} | ||||
| 	{:else if token.type === 'list'} | ||||
| 		{#if token.ordered} | ||||
| 			<ol start={token.start || 1}> | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user