mirror of
https://github.com/doocs/md.git
synced 2026-09-01 15:46:27 +08:00
fix: xss (#831)
This commit is contained in:
@@ -0,0 +1,12 @@
|
||||
#!/bin/sh
|
||||
|
||||
if [ "$SKIP_SIMPLE_GIT_HOOKS" = "1" ]; then
|
||||
echo "[INFO] SKIP_SIMPLE_GIT_HOOKS is set to 1, skipping hook."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if [ -f "$SIMPLE_GIT_HOOKS_RC" ]; then
|
||||
. "$SIMPLE_GIT_HOOKS_RC"
|
||||
fi
|
||||
|
||||
npx lint-staged
|
||||
Generated
+4301
-2490
File diff suppressed because it is too large
Load Diff
@@ -58,7 +58,6 @@
|
||||
"juice": "^11.0.0",
|
||||
"lucide-vue-next": "^0.473.0",
|
||||
"marked": "^15.0.6",
|
||||
"marked-highlight": "^2.2.1",
|
||||
"mermaid": "^11.6.0",
|
||||
"node-fetch": "^3.3.2",
|
||||
"pinia": "^3.0.1",
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
<script setup lang="ts">
|
||||
import { Pause, Settings, X } from 'lucide-vue-next'
|
||||
import { nextTick, ref, toRaw, watch } from 'vue'
|
||||
import { Button } from '@/components/ui/button'
|
||||
import {
|
||||
Select,
|
||||
@@ -9,8 +11,6 @@ import {
|
||||
SelectValue,
|
||||
} from '@/components/ui/select'
|
||||
import useAIConfigStore from '@/stores/AIConfig'
|
||||
import { Pause, Settings, X } from 'lucide-vue-next'
|
||||
import { nextTick, ref, toRaw, watch } from 'vue'
|
||||
|
||||
/* -------------------- props / emits -------------------- */
|
||||
const props = defineProps<{
|
||||
@@ -337,7 +337,7 @@ defineExpose({ visible, runAIAction, replaceText, show, close, stopAI })
|
||||
原文
|
||||
</div>
|
||||
<div
|
||||
class="border-border custom-scroll bg-muted/20 text-muted-foreground max-h-32 overflow-y-auto whitespace-pre-line border rounded px-3 py-2 text-sm"
|
||||
class="border-border custom-scroll text-muted-foreground bg-muted/20 max-h-32 overflow-y-auto whitespace-pre-line border rounded px-3 py-2 text-sm"
|
||||
>
|
||||
{{ currentText }}
|
||||
</div>
|
||||
|
||||
@@ -1,19 +1,4 @@
|
||||
<script setup lang="ts">
|
||||
/* ---------- 依赖 ---------- */
|
||||
import type { QuickCommandRuntime } from '@/stores/useQuickCommands'
|
||||
import { Button } from '@/components/ui/button'
|
||||
import {
|
||||
Dialog,
|
||||
DialogContent,
|
||||
DialogHeader,
|
||||
DialogTitle,
|
||||
} from '@/components/ui/dialog'
|
||||
import { Textarea } from '@/components/ui/textarea'
|
||||
import useAIConfigStore from '@/stores/AIConfig'
|
||||
import { useQuickCommands } from '@/stores/useQuickCommands'
|
||||
import { copyPlain } from '@/utils/clipboard'
|
||||
import hljs from 'highlight.js'
|
||||
|
||||
import {
|
||||
Check,
|
||||
Copy,
|
||||
@@ -25,34 +10,25 @@ import {
|
||||
Settings,
|
||||
Trash2,
|
||||
} from 'lucide-vue-next'
|
||||
|
||||
/* ---------- Markdown & highlight.js ---------- */
|
||||
import { Marked } from 'marked'
|
||||
import { markedHighlight } from 'marked-highlight'
|
||||
import { nextTick, onMounted, ref, watch } from 'vue'
|
||||
import { Button } from '@/components/ui/button'
|
||||
import {
|
||||
Dialog,
|
||||
DialogContent,
|
||||
DialogHeader,
|
||||
DialogTitle,
|
||||
} from '@/components/ui/dialog'
|
||||
import { Textarea } from '@/components/ui/textarea'
|
||||
import useAIConfigStore from '@/stores/AIConfig'
|
||||
/* ---------- 依赖 ---------- */
|
||||
import type { QuickCommandRuntime } from '@/stores/useQuickCommands'
|
||||
|
||||
import { useQuickCommands } from '@/stores/useQuickCommands'
|
||||
|
||||
import { copyPlain } from '@/utils/clipboard'
|
||||
/* ---------- 组件属性 ---------- */
|
||||
const props = defineProps<{ open: boolean }>()
|
||||
const emit = defineEmits([`update:open`])
|
||||
// 浅色主题
|
||||
|
||||
const aiMarked = new Marked(
|
||||
markedHighlight({
|
||||
highlight(code: string, lang: string) {
|
||||
return lang && hljs.getLanguage(lang)
|
||||
? hljs.highlight(code, { language: lang }).value
|
||||
: hljs.highlightAuto(code).value
|
||||
},
|
||||
}),
|
||||
)
|
||||
|
||||
aiMarked.setOptions({
|
||||
gfm: true,
|
||||
breaks: true,
|
||||
})
|
||||
|
||||
function renderMarkdown(text: string) {
|
||||
return aiMarked.parse(text)
|
||||
}
|
||||
|
||||
const store = useStore()
|
||||
const { editor } = storeToRefs(store)
|
||||
@@ -500,19 +476,14 @@ async function sendMessage() {
|
||||
</div>
|
||||
|
||||
<!-- Markdown 内容 -->
|
||||
<div v-if="msg.content" class="space-y-2 overflow-x-auto">
|
||||
<div
|
||||
class="chat-markdown prose prose-sm dark:prose-invert max-w-none"
|
||||
v-html="renderMarkdown(msg.content)"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- 占位/加载动画 -->
|
||||
<div
|
||||
v-else
|
||||
class="text-muted-foreground animate-pulse whitespace-pre-wrap"
|
||||
class="whitespace-pre-wrap"
|
||||
:class="msg.content ? '' : 'animate-pulse text-muted-foreground'"
|
||||
>
|
||||
{{ msg.role === 'assistant' && !msg.done ? '思考中…' : '' }}
|
||||
{{
|
||||
msg.content
|
||||
|| (msg.role === 'assistant' && !msg.done ? '思考中…' : '')
|
||||
}}
|
||||
</div>
|
||||
|
||||
<!-- 工具按钮 -->
|
||||
@@ -562,7 +533,7 @@ async function sendMessage() {
|
||||
<!-- ============ 输入框 ============ -->
|
||||
<div v-if="!configVisible" class="relative mt-2">
|
||||
<div
|
||||
class="bg-background border-border item-start flex flex-col items-baseline gap-2 border rounded-xl px-3 py-2 pr-12 shadow-inner"
|
||||
class="item-start bg-background border-border flex flex-col items-baseline gap-2 border rounded-xl px-3 py-2 pr-12 shadow-inner"
|
||||
>
|
||||
<Textarea
|
||||
v-model="input"
|
||||
|
||||
Reference in New Issue
Block a user