mirror of
https://github.com/lobehub/lobe-chat.git
synced 2026-06-13 19:20:04 +00:00
💄 style: support html preview (#8969)
* support preview html * add html * refactor some code
This commit is contained in:
+1
-1
@@ -25,7 +25,7 @@ module.exports = defineConfig({
|
||||
],
|
||||
temperature: 0,
|
||||
saveImmediately: true,
|
||||
modelName: 'gpt-5-mini',
|
||||
modelName: 'gpt-4.1-mini',
|
||||
experimental: {
|
||||
jsonMode: true,
|
||||
},
|
||||
|
||||
@@ -73,6 +73,18 @@
|
||||
"GoBack": {
|
||||
"back": "عودة"
|
||||
},
|
||||
"HtmlPreview": {
|
||||
"actions": {
|
||||
"download": "تنزيل",
|
||||
"preview": "معاينة"
|
||||
},
|
||||
"iframeTitle": "معاينة HTML",
|
||||
"mode": {
|
||||
"code": "رمز",
|
||||
"preview": "معاينة"
|
||||
},
|
||||
"title": "معاينة HTML"
|
||||
},
|
||||
"ImageUpload": {
|
||||
"actions": {
|
||||
"changeImage": "انقر لتغيير الصورة",
|
||||
|
||||
@@ -73,6 +73,18 @@
|
||||
"GoBack": {
|
||||
"back": "Назад"
|
||||
},
|
||||
"HtmlPreview": {
|
||||
"actions": {
|
||||
"download": "Изтегляне",
|
||||
"preview": "Преглед"
|
||||
},
|
||||
"iframeTitle": "HTML Преглед",
|
||||
"mode": {
|
||||
"code": "Код",
|
||||
"preview": "Преглед"
|
||||
},
|
||||
"title": "HTML Преглед"
|
||||
},
|
||||
"ImageUpload": {
|
||||
"actions": {
|
||||
"changeImage": "Кликнете, за да смените изображението",
|
||||
|
||||
@@ -73,6 +73,18 @@
|
||||
"GoBack": {
|
||||
"back": "Zurück"
|
||||
},
|
||||
"HtmlPreview": {
|
||||
"actions": {
|
||||
"download": "Herunterladen",
|
||||
"preview": "Vorschau"
|
||||
},
|
||||
"iframeTitle": "HTML-Vorschau",
|
||||
"mode": {
|
||||
"code": "Code",
|
||||
"preview": "Vorschau"
|
||||
},
|
||||
"title": "HTML-Vorschau"
|
||||
},
|
||||
"ImageUpload": {
|
||||
"actions": {
|
||||
"changeImage": "Klicken, um das Bild zu ändern",
|
||||
|
||||
@@ -73,6 +73,18 @@
|
||||
"GoBack": {
|
||||
"back": "Back"
|
||||
},
|
||||
"HtmlPreview": {
|
||||
"actions": {
|
||||
"download": "Download",
|
||||
"preview": "Preview"
|
||||
},
|
||||
"iframeTitle": "HTML Preview",
|
||||
"mode": {
|
||||
"code": "Code",
|
||||
"preview": "Preview"
|
||||
},
|
||||
"title": "HTML Preview"
|
||||
},
|
||||
"ImageUpload": {
|
||||
"actions": {
|
||||
"changeImage": "Click to change image",
|
||||
|
||||
@@ -73,6 +73,18 @@
|
||||
"GoBack": {
|
||||
"back": "Regresar"
|
||||
},
|
||||
"HtmlPreview": {
|
||||
"actions": {
|
||||
"download": "Descargar",
|
||||
"preview": "Vista previa"
|
||||
},
|
||||
"iframeTitle": "Vista previa HTML",
|
||||
"mode": {
|
||||
"code": "Código",
|
||||
"preview": "Vista previa"
|
||||
},
|
||||
"title": "Vista previa HTML"
|
||||
},
|
||||
"ImageUpload": {
|
||||
"actions": {
|
||||
"changeImage": "Haz clic para cambiar la imagen",
|
||||
|
||||
@@ -73,6 +73,18 @@
|
||||
"GoBack": {
|
||||
"back": "بازگشت"
|
||||
},
|
||||
"HtmlPreview": {
|
||||
"actions": {
|
||||
"download": "دانلود",
|
||||
"preview": "پیشنمایش"
|
||||
},
|
||||
"iframeTitle": "پیشنمایش HTML",
|
||||
"mode": {
|
||||
"code": "کد",
|
||||
"preview": "پیشنمایش"
|
||||
},
|
||||
"title": "پیشنمایش HTML"
|
||||
},
|
||||
"ImageUpload": {
|
||||
"actions": {
|
||||
"changeImage": "برای تغییر تصویر کلیک کنید",
|
||||
|
||||
@@ -73,6 +73,18 @@
|
||||
"GoBack": {
|
||||
"back": "Retour"
|
||||
},
|
||||
"HtmlPreview": {
|
||||
"actions": {
|
||||
"download": "Télécharger",
|
||||
"preview": "Aperçu"
|
||||
},
|
||||
"iframeTitle": "Aperçu HTML",
|
||||
"mode": {
|
||||
"code": "Code",
|
||||
"preview": "Aperçu"
|
||||
},
|
||||
"title": "Aperçu HTML"
|
||||
},
|
||||
"ImageUpload": {
|
||||
"actions": {
|
||||
"changeImage": "Cliquez pour changer l'image",
|
||||
|
||||
@@ -73,6 +73,18 @@
|
||||
"GoBack": {
|
||||
"back": "Indietro"
|
||||
},
|
||||
"HtmlPreview": {
|
||||
"actions": {
|
||||
"download": "Scarica",
|
||||
"preview": "Anteprima"
|
||||
},
|
||||
"iframeTitle": "Anteprima HTML",
|
||||
"mode": {
|
||||
"code": "Codice",
|
||||
"preview": "Anteprima"
|
||||
},
|
||||
"title": "Anteprima HTML"
|
||||
},
|
||||
"ImageUpload": {
|
||||
"actions": {
|
||||
"changeImage": "Clicca per cambiare immagine",
|
||||
|
||||
@@ -73,6 +73,18 @@
|
||||
"GoBack": {
|
||||
"back": "戻る"
|
||||
},
|
||||
"HtmlPreview": {
|
||||
"actions": {
|
||||
"download": "ダウンロード",
|
||||
"preview": "プレビュー"
|
||||
},
|
||||
"iframeTitle": "HTML プレビュー",
|
||||
"mode": {
|
||||
"code": "コード",
|
||||
"preview": "プレビュー"
|
||||
},
|
||||
"title": "HTML プレビュー"
|
||||
},
|
||||
"ImageUpload": {
|
||||
"actions": {
|
||||
"changeImage": "画像を変更するにはクリックしてください",
|
||||
|
||||
@@ -73,6 +73,18 @@
|
||||
"GoBack": {
|
||||
"back": "뒤로 가기"
|
||||
},
|
||||
"HtmlPreview": {
|
||||
"actions": {
|
||||
"download": "다운로드",
|
||||
"preview": "미리보기"
|
||||
},
|
||||
"iframeTitle": "HTML 미리보기",
|
||||
"mode": {
|
||||
"code": "코드",
|
||||
"preview": "미리보기"
|
||||
},
|
||||
"title": "HTML 미리보기"
|
||||
},
|
||||
"ImageUpload": {
|
||||
"actions": {
|
||||
"changeImage": "이미지 변경 클릭",
|
||||
|
||||
@@ -73,6 +73,18 @@
|
||||
"GoBack": {
|
||||
"back": "Terug"
|
||||
},
|
||||
"HtmlPreview": {
|
||||
"actions": {
|
||||
"download": "Downloaden",
|
||||
"preview": "Voorbeeld"
|
||||
},
|
||||
"iframeTitle": "HTML Voorbeeld",
|
||||
"mode": {
|
||||
"code": "Code",
|
||||
"preview": "Voorbeeld"
|
||||
},
|
||||
"title": "HTML Voorbeeld"
|
||||
},
|
||||
"ImageUpload": {
|
||||
"actions": {
|
||||
"changeImage": "Klik om afbeelding te wijzigen",
|
||||
|
||||
@@ -73,6 +73,18 @@
|
||||
"GoBack": {
|
||||
"back": "Wróć"
|
||||
},
|
||||
"HtmlPreview": {
|
||||
"actions": {
|
||||
"download": "Pobierz",
|
||||
"preview": "Podgląd"
|
||||
},
|
||||
"iframeTitle": "Podgląd HTML",
|
||||
"mode": {
|
||||
"code": "Kod",
|
||||
"preview": "Podgląd"
|
||||
},
|
||||
"title": "Podgląd HTML"
|
||||
},
|
||||
"ImageUpload": {
|
||||
"actions": {
|
||||
"changeImage": "Kliknij, aby zmienić obraz",
|
||||
|
||||
@@ -73,6 +73,18 @@
|
||||
"GoBack": {
|
||||
"back": "Voltar"
|
||||
},
|
||||
"HtmlPreview": {
|
||||
"actions": {
|
||||
"download": "Baixar",
|
||||
"preview": "Visualizar"
|
||||
},
|
||||
"iframeTitle": "Visualização HTML",
|
||||
"mode": {
|
||||
"code": "Código",
|
||||
"preview": "Visualizar"
|
||||
},
|
||||
"title": "Visualização HTML"
|
||||
},
|
||||
"ImageUpload": {
|
||||
"actions": {
|
||||
"changeImage": "Clique para alterar a imagem",
|
||||
|
||||
@@ -73,6 +73,18 @@
|
||||
"GoBack": {
|
||||
"back": "Назад"
|
||||
},
|
||||
"HtmlPreview": {
|
||||
"actions": {
|
||||
"download": "Скачать",
|
||||
"preview": "Предпросмотр"
|
||||
},
|
||||
"iframeTitle": "Предпросмотр HTML",
|
||||
"mode": {
|
||||
"code": "Код",
|
||||
"preview": "Предпросмотр"
|
||||
},
|
||||
"title": "Предпросмотр HTML"
|
||||
},
|
||||
"ImageUpload": {
|
||||
"actions": {
|
||||
"changeImage": "Нажмите, чтобы изменить изображение",
|
||||
|
||||
@@ -73,6 +73,18 @@
|
||||
"GoBack": {
|
||||
"back": "Geri dön"
|
||||
},
|
||||
"HtmlPreview": {
|
||||
"actions": {
|
||||
"download": "İndir",
|
||||
"preview": "Önizleme"
|
||||
},
|
||||
"iframeTitle": "HTML Önizlemesi",
|
||||
"mode": {
|
||||
"code": "Kod",
|
||||
"preview": "Önizleme"
|
||||
},
|
||||
"title": "HTML Önizlemesi"
|
||||
},
|
||||
"ImageUpload": {
|
||||
"actions": {
|
||||
"changeImage": "Resmi değiştirmek için tıklayın",
|
||||
|
||||
@@ -73,6 +73,18 @@
|
||||
"GoBack": {
|
||||
"back": "Quay lại"
|
||||
},
|
||||
"HtmlPreview": {
|
||||
"actions": {
|
||||
"download": "Tải xuống",
|
||||
"preview": "Xem trước"
|
||||
},
|
||||
"iframeTitle": "Xem trước HTML",
|
||||
"mode": {
|
||||
"code": "Mã",
|
||||
"preview": "Xem trước"
|
||||
},
|
||||
"title": "Xem trước HTML"
|
||||
},
|
||||
"ImageUpload": {
|
||||
"actions": {
|
||||
"changeImage": "Nhấn để thay đổi hình ảnh",
|
||||
|
||||
@@ -73,6 +73,18 @@
|
||||
"GoBack": {
|
||||
"back": "返回"
|
||||
},
|
||||
"HtmlPreview": {
|
||||
"actions": {
|
||||
"download": "下载",
|
||||
"preview": "预览"
|
||||
},
|
||||
"iframeTitle": "HTML 预览",
|
||||
"mode": {
|
||||
"code": "代码",
|
||||
"preview": "预览"
|
||||
},
|
||||
"title": "HTML 预览"
|
||||
},
|
||||
"ImageUpload": {
|
||||
"actions": {
|
||||
"changeImage": "点击更换图片",
|
||||
|
||||
@@ -73,6 +73,18 @@
|
||||
"GoBack": {
|
||||
"back": "返回"
|
||||
},
|
||||
"HtmlPreview": {
|
||||
"actions": {
|
||||
"download": "下載",
|
||||
"preview": "預覽"
|
||||
},
|
||||
"iframeTitle": "HTML 預覽",
|
||||
"mode": {
|
||||
"code": "程式碼",
|
||||
"preview": "預覽"
|
||||
},
|
||||
"title": "HTML 預覽"
|
||||
},
|
||||
"ImageUpload": {
|
||||
"actions": {
|
||||
"changeImage": "點擊更換圖片",
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
export * from './branding';
|
||||
export * from './image';
|
||||
export * from './layoutTokens';
|
||||
export * from './message';
|
||||
export * from './settings';
|
||||
export * from './version';
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
export * from './downloadFile';
|
||||
export * from './exportFile';
|
||||
@@ -0,0 +1,32 @@
|
||||
import { ActionIcon } from '@lobehub/ui';
|
||||
import { Eye } from 'lucide-react';
|
||||
import { memo, useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import HtmlPreviewDrawer from './PreviewDrawer';
|
||||
|
||||
interface HtmlPreviewActionProps {
|
||||
content: string;
|
||||
size?: number;
|
||||
}
|
||||
|
||||
const HtmlPreviewAction = memo<HtmlPreviewActionProps>(({ content, size }) => {
|
||||
const { t } = useTranslation('components');
|
||||
const [open, setOpen] = useState(false);
|
||||
|
||||
return (
|
||||
<>
|
||||
<ActionIcon
|
||||
icon={Eye}
|
||||
onClick={() => setOpen(true)}
|
||||
size={size}
|
||||
title={t('HtmlPreview.actions.preview')}
|
||||
/>
|
||||
<HtmlPreviewDrawer content={content} onClose={() => setOpen(false)} open={open} />
|
||||
</>
|
||||
);
|
||||
});
|
||||
|
||||
HtmlPreviewAction.displayName = 'HtmlPreviewAction';
|
||||
|
||||
export default HtmlPreviewAction;
|
||||
@@ -0,0 +1,133 @@
|
||||
import { exportFile } from '@lobechat/utils/client';
|
||||
import { Block, Button, Highlighter, Segmented } from '@lobehub/ui';
|
||||
import { Drawer } from 'antd';
|
||||
import { createStyles } from 'antd-style';
|
||||
import { Code2, Download, Eye } from 'lucide-react';
|
||||
import { memo, useCallback, useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { Flexbox } from 'react-layout-kit';
|
||||
|
||||
import { isDesktop } from '@/const/version';
|
||||
import { TITLE_BAR_HEIGHT } from '@/features/ElectronTitlebar';
|
||||
|
||||
const useStyles = createStyles(({ css }) => ({
|
||||
container: css`
|
||||
height: 100%;
|
||||
`,
|
||||
iframe: css`
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border: none;
|
||||
`,
|
||||
}));
|
||||
|
||||
interface HtmlPreviewDrawerProps {
|
||||
content: string;
|
||||
onClose: () => void;
|
||||
open: boolean;
|
||||
}
|
||||
|
||||
const HtmlPreviewDrawer = memo<HtmlPreviewDrawerProps>(({ content, open, onClose }) => {
|
||||
const { styles } = useStyles();
|
||||
const { t } = useTranslation('components');
|
||||
const [mode, setMode] = useState<'preview' | 'code'>('preview');
|
||||
|
||||
const htmlContent = content;
|
||||
|
||||
const extractTitle = useCallback(() => {
|
||||
const m = htmlContent.match(/<title>([\S\s]*?)<\/title>/i);
|
||||
return m ? m[1].trim() : undefined;
|
||||
}, [htmlContent]);
|
||||
|
||||
const sanitizeFileName = useCallback((name: string) => {
|
||||
return name
|
||||
.replaceAll(/["*/:<>?\\|]/g, '-')
|
||||
.replaceAll(/\s+/g, ' ')
|
||||
.trim()
|
||||
.slice(0, 100);
|
||||
}, []);
|
||||
|
||||
const onDownload = useCallback(() => {
|
||||
const title = extractTitle();
|
||||
const base = title ? sanitizeFileName(title) : `chat-html-preview-${Date.now()}`;
|
||||
exportFile(content, `${base}.html`);
|
||||
}, [content, extractTitle, sanitizeFileName]);
|
||||
|
||||
const Title = (
|
||||
<Flexbox align={'center'} horizontal justify={'space-between'} style={{ width: '100%' }}>
|
||||
{t('HtmlPreview.title')}
|
||||
<Segmented
|
||||
onChange={(v) => setMode(v as 'preview' | 'code')}
|
||||
options={[
|
||||
{
|
||||
label: (
|
||||
<Flexbox align={'center'} gap={6} horizontal>
|
||||
<Eye size={16} />
|
||||
{t('HtmlPreview.mode.preview')}
|
||||
</Flexbox>
|
||||
),
|
||||
value: 'preview',
|
||||
},
|
||||
{
|
||||
label: (
|
||||
<Flexbox align={'center'} gap={6} horizontal>
|
||||
<Code2 size={16} />
|
||||
{t('HtmlPreview.mode.code')}
|
||||
</Flexbox>
|
||||
),
|
||||
value: 'code',
|
||||
},
|
||||
]}
|
||||
value={mode}
|
||||
/>
|
||||
<Button
|
||||
color={'default'}
|
||||
icon={<Download size={16} />}
|
||||
onClick={onDownload}
|
||||
variant={'filled'}
|
||||
>
|
||||
{t('HtmlPreview.actions.download')}
|
||||
</Button>
|
||||
</Flexbox>
|
||||
);
|
||||
|
||||
return (
|
||||
<Drawer
|
||||
destroyOnHidden
|
||||
height={isDesktop ? `calc(100vh - ${TITLE_BAR_HEIGHT}px)` : '100vh'}
|
||||
onClose={onClose}
|
||||
open={open}
|
||||
placement="bottom"
|
||||
styles={{
|
||||
body: { height: '100%', padding: 0 },
|
||||
header: { paddingBlock: 8, paddingInline: 12 },
|
||||
}}
|
||||
title={Title}
|
||||
>
|
||||
{mode === 'preview' ? (
|
||||
<Block className={styles.container}>
|
||||
<iframe
|
||||
className={styles.iframe}
|
||||
sandbox="allow-scripts allow-same-origin"
|
||||
srcDoc={content}
|
||||
title={t('HtmlPreview.iframeTitle')}
|
||||
/>
|
||||
</Block>
|
||||
) : (
|
||||
<Block className={styles.container}>
|
||||
<Highlighter
|
||||
language={'html'}
|
||||
showLanguage={false}
|
||||
style={{ height: '100%', overflow: 'auto' }}
|
||||
>
|
||||
{htmlContent}
|
||||
</Highlighter>
|
||||
</Block>
|
||||
)}
|
||||
</Drawer>
|
||||
);
|
||||
});
|
||||
|
||||
HtmlPreviewDrawer.displayName = 'HtmlPreviewDrawer';
|
||||
|
||||
export default HtmlPreviewDrawer;
|
||||
@@ -0,0 +1,2 @@
|
||||
export { default as HtmlPreviewAction } from './HtmlPreviewAction';
|
||||
export { default as HtmlPreviewDrawer } from './PreviewDrawer';
|
||||
@@ -1,3 +1,4 @@
|
||||
import { exportFile } from '@lobechat/utils/client';
|
||||
import { Button, copyToClipboard } from '@lobehub/ui';
|
||||
import { App } from 'antd';
|
||||
import isEqual from 'fast-deep-equal';
|
||||
@@ -10,7 +11,6 @@ import { useIsMobile } from '@/hooks/useIsMobile';
|
||||
import { useChatStore } from '@/store/chat';
|
||||
import { topicSelectors } from '@/store/chat/selectors';
|
||||
import { ChatMessage } from '@/types/message';
|
||||
import { exportFile } from '@/utils/client/exportFile';
|
||||
|
||||
import { useStyles } from '../style';
|
||||
import Preview from './Preview';
|
||||
|
||||
@@ -6,6 +6,7 @@ import { MouseEventHandler, ReactNode, memo, use, useCallback, useMemo } from 'r
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { Flexbox } from 'react-layout-kit';
|
||||
|
||||
import { HtmlPreviewAction } from '@/components/HtmlPreview';
|
||||
import { isDesktop } from '@/const/version';
|
||||
import ChatItem from '@/features/ChatItem';
|
||||
import { VirtuosoContext } from '@/features/Conversation/components/VirtualizedList/VirtuosoContext';
|
||||
@@ -33,6 +34,14 @@ import { normalizeThinkTags, processWithArtifact } from './utils';
|
||||
const rehypePlugins = markdownElements.map((element) => element.rehypePlugin).filter(Boolean);
|
||||
const remarkPlugins = markdownElements.map((element) => element.remarkPlugin).filter(Boolean);
|
||||
|
||||
const isHtmlCode = (content: string, language: string) => {
|
||||
return (
|
||||
language === 'html' ||
|
||||
(language === '' && content.includes('<html>')) ||
|
||||
(language === '' && content.includes('<!DOCTYPE html>'))
|
||||
);
|
||||
};
|
||||
|
||||
const useStyles = createStyles(({ css, prefixCls }) => ({
|
||||
loading: css`
|
||||
opacity: 0.6;
|
||||
@@ -175,6 +184,20 @@ const Item = memo<ChatListItemProps>(
|
||||
() => ({
|
||||
animated,
|
||||
citations: item?.role === 'user' ? undefined : item?.search?.citations,
|
||||
componentProps: {
|
||||
highlight: {
|
||||
actionsRender: ({ content, actionIconSize, language, originalNode }: any) => {
|
||||
const showHtmlPreview = isHtmlCode(content, language);
|
||||
|
||||
return (
|
||||
<>
|
||||
{showHtmlPreview && <HtmlPreviewAction content={content} size={actionIconSize} />}
|
||||
{originalNode}
|
||||
</>
|
||||
);
|
||||
},
|
||||
},
|
||||
},
|
||||
components,
|
||||
customRender: markdownCustomRender,
|
||||
enableCustomFootnotes: item?.role === 'assistant',
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import { FORM_STYLE } from '@lobechat/const';
|
||||
import { exportFile } from '@lobechat/utils/client';
|
||||
import { Button, Form, type FormItemProps, copyToClipboard } from '@lobehub/ui';
|
||||
import { App, Switch } from 'antd';
|
||||
import isEqual from 'fast-deep-equal';
|
||||
@@ -6,13 +8,11 @@ import { memo, useState } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { Flexbox } from 'react-layout-kit';
|
||||
|
||||
import { FORM_STYLE } from '@/const/layoutTokens';
|
||||
import { useIsMobile } from '@/hooks/useIsMobile';
|
||||
import { useAgentStore } from '@/store/agent';
|
||||
import { agentSelectors } from '@/store/agent/selectors';
|
||||
import { useChatStore } from '@/store/chat';
|
||||
import { chatSelectors, topicSelectors } from '@/store/chat/selectors';
|
||||
import { exportFile } from '@/utils/client/exportFile';
|
||||
|
||||
import { useStyles } from '../style';
|
||||
import Preview from './Preview';
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { exportFile } from '@lobechat/utils/client';
|
||||
import { Button, Form, type FormItemProps, copyToClipboard } from '@lobehub/ui';
|
||||
import { App, Switch } from 'antd';
|
||||
import isEqual from 'fast-deep-equal';
|
||||
@@ -12,7 +13,6 @@ import { useAgentStore } from '@/store/agent';
|
||||
import { agentSelectors } from '@/store/agent/selectors';
|
||||
import { useChatStore } from '@/store/chat';
|
||||
import { chatSelectors, topicSelectors } from '@/store/chat/selectors';
|
||||
import { exportFile } from '@/utils/client/exportFile';
|
||||
|
||||
import { useStyles } from '../style';
|
||||
import Preview from './Preview';
|
||||
|
||||
@@ -75,6 +75,18 @@ export default {
|
||||
GoBack: {
|
||||
back: '返回',
|
||||
},
|
||||
HtmlPreview: {
|
||||
actions: {
|
||||
download: '下载',
|
||||
preview: '预览',
|
||||
},
|
||||
iframeTitle: 'HTML 预览',
|
||||
mode: {
|
||||
code: '代码',
|
||||
preview: '预览',
|
||||
},
|
||||
title: 'HTML 预览',
|
||||
},
|
||||
ImageUpload: {
|
||||
actions: {
|
||||
changeImage: '点击更换图片',
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
import { BRANDING_NAME, isDeprecatedEdition, isServerMode } from '@lobechat/const';
|
||||
import { downloadFile, exportJSONFile } from '@lobechat/utils/client';
|
||||
import dayjs from 'dayjs';
|
||||
|
||||
import { BRANDING_NAME } from '@/const/branding';
|
||||
import { isDeprecatedEdition, isServerMode } from '@/const/version';
|
||||
import { CURRENT_CONFIG_VERSION } from '@/migrations';
|
||||
import { ImportPgDataStructure } from '@/types/export';
|
||||
import { downloadFile } from '@/utils/client/downloadFile';
|
||||
import { exportJSONFile } from '@/utils/client/exportFile';
|
||||
|
||||
import { exportService } from './export';
|
||||
import { configService as deprecatedExportService } from './export/_deprecated';
|
||||
|
||||
Reference in New Issue
Block a user