feat: Fit SD WebUI 1.9

pull/526/head
canisminor1990 2024-05-15 22:25:16 +08:00
parent 77102c0e1e
commit 3e01da0cea
35 changed files with 1041 additions and 404 deletions

View File

@ -10,7 +10,7 @@ module.exports = {
entryLocale: 'en_US', entryLocale: 'en_US',
output: 'locales', output: 'locales',
outputLocales: outputLocales, outputLocales: outputLocales,
modelName: 'gpt-3.5-turbo-1106', modelName: 'gpt-3.5-turbo-0125',
experimental: { experimental: {
jsonMode: true, jsonMode: true,
}, },

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -25,6 +25,7 @@
"title": "Themenfeedback" "title": "Themenfeedback"
}, },
"themeSetting": { "themeSetting": {
"desc": "Einstellungen für Thema und Layout",
"title": "Themen-Einstellungen" "title": "Themen-Einstellungen"
} }
}, },

View File

@ -1,8 +1,8 @@
{ {
"brand": { "brand": {
"custom": "Custom",
"kitchen": "Kitchen", "kitchen": "Kitchen",
"lobe": "LobeHub", "lobe": "LobeHub"
"custom": "Custom"
}, },
"cancel": "Cancel", "cancel": "Cancel",
"confirm": "Confirm", "confirm": "Confirm",
@ -10,34 +10,35 @@
"initializing": "StableDiffusion / LobeTheme is initializing, please wait..." "initializing": "StableDiffusion / LobeTheme is initializing, please wait..."
}, },
"footer": { "footer": {
"resources": "Resources",
"community": "Community", "community": "Community",
"help": "Help", "help": "Help",
"moreProducts": "More Products" "moreProducts": "More Products",
"resources": "Resources"
}, },
"header": { "header": {
"feedback": "Feedback", "feedback": "Feedback",
"switchTheme": "Switch Light/Dark Theme", "setting": "Setting",
"setting": "Setting" "switchTheme": "Switch Light/Dark Theme"
}, },
"modal": { "modal": {
"themeFeedback": { "themeFeedback": {
"title": "Theme Feedback" "title": "Theme Feedback"
}, },
"themeSetting": { "themeSetting": {
"desc": "Preferences and Layout Settings",
"title": "Theme Settings" "title": "Theme Settings"
} }
}, },
"prompt": { "prompt": {
"area": { "area": {
"object": "Object Selection",
"attribute": "Attribute Selection", "attribute": "Attribute Selection",
"object": "Object Selection",
"tag": "Tag Selection" "tag": "Tag Selection"
}, },
"load": "Load Prompt", "load": "Load Prompt",
"set": "Set Prompt",
"negative": "Negative", "negative": "Negative",
"positive": "Positive" "positive": "Positive",
"set": "Set Prompt"
}, },
"setting": { "setting": {
"button": { "button": {
@ -45,152 +46,152 @@
"submit": "Apply and Restart Interface" "submit": "Apply and Restart Interface"
}, },
"confirmPageUnload": { "confirmPageUnload": {
"title": "Confirmation on page leaving", "desc": "Helps prevent loss of unsaved data",
"desc": "Helps prevent loss of unsaved data" "title": "Confirmation on page leaving"
}, },
"customFont": { "customFont": {
"title": "Custom Font", "desc": "When enabled, it will automatically load a webfont to enhance the display of text in Chinese, English, and code",
"desc": "When enabled, it will automatically load a webfont to enhance the display of text in Chinese, English, and code" "title": "Custom Font"
}, },
"customLogo": { "customLogo": {
"title": "Custom Logo", "desc": "Support URL / Base64 / Emoji symbols",
"desc": "Support URL / Base64 / Emoji symbols" "title": "Custom Logo"
}, },
"customTitle": { "customTitle": {
"title": "Custom Title", "desc": "Custom Logo Title",
"desc": "Custom Logo Title" "title": "Custom Title"
}, },
"extraNetworkSidebar": { "extraNetworkSidebar": {
"defaultCardSize": { "defaultCardSize": {
"title": "Model Cover Size", "desc": "Default value of model cover size when starting",
"desc": "Default value of model cover size when starting" "title": "Model Cover Size"
}, },
"defaultExpand": { "defaultExpand": {
"title": "Default Expand", "desc": "Whether to expand the sidebar by default when starting",
"desc": "Whether to expand the sidebar by default when starting" "title": "Default Expand"
}, },
"defaultWidth": { "defaultWidth": {
"title": "Default Width", "desc": "Default width of the sidebar when starting",
"desc": "Default width of the sidebar when starting" "title": "Default Width"
}, },
"displayMode": { "displayMode": {
"title": "Display Mode", "desc": "Fixed as grid mode for constant display, auto-expand when the mouse moves to the side in floating mode",
"desc": "Fixed as grid mode for constant display, auto-expand when the mouse moves to the side in floating mode" "title": "Display Mode"
}, },
"enable": { "enable": {
"title": "Enable", "desc": "Enable the extra network sidebar on the right side",
"desc": "Enable the extra network sidebar on the right side" "title": "Enable"
} }
}, },
"tab": {
"appearance": "Appearance",
"sidebar": "Sidebar",
"layout": "Layout",
"experimental": "Experimental"
},
"group": { "group": {
"experimental": "Experimental Features",
"extraNetworkSidebar": "Extra Network Sidebar", "extraNetworkSidebar": "Extra Network Sidebar",
"layout": "Layout Settings", "layout": "Layout Settings",
"promptTextarea": "Prompt Textbox", "promptTextarea": "Prompt Textbox",
"quickSettingSidebar": "Quick Setting Sidebar", "quickSettingSidebar": "Quick Setting Sidebar",
"theme": "Theme Settings", "theme": "Theme Settings"
"experimental": "Experimental Features"
},
"imageInfo": {
"title": "Image Info Alternative",
"desc": "Display better image information in the generated image"
}, },
"hideFooter": { "hideFooter": {
"title": "Hide Footer", "desc": "Hide the theme footer and only display the default footer of stable diffusion webui",
"desc": "Hide the theme footer and only display the default footer of stable diffusion webui" "title": "Hide Footer"
},
"imageInfo": {
"desc": "Display better image information in the generated image",
"title": "Image Info Alternative"
}, },
"language": { "language": {
"title": "Language", "desc": "Lobe Theme language",
"desc": "Lobe Theme language" "title": "Language"
}, },
"logoType": { "logoType": {
"title": "Logo Type",
"desc": "Logo Type", "desc": "Logo Type",
"preview": "Preview" "preview": "Preview",
"title": "Logo Type"
}, },
"neutralColor": { "neutralColor": {
"title": "Neutral Color", "desc": "Customize different shades of gray with different color tendencies, the second one is the original Kitchen neutral color",
"desc": "Customize different shades of gray with different color tendencies, the second one is the original Kitchen neutral color" "title": "Neutral Color"
}, },
"primaryColor": { "primaryColor": {
"title": "Primary Color", "desc": "Custom primary color, the second one is the original Kitchen theme color",
"desc": "Custom primary color, the second one is the original Kitchen theme color" "title": "Primary Color"
}, },
"promptDisplayMode": { "promptDisplayMode": {
"title": "Prompt Display Mode",
"desc": "Fixed height or auto height with draggable resize support", "desc": "Fixed height or auto height with draggable resize support",
"resizable": "Resizable", "resizable": "Resizable",
"scroll": "Scroll" "scroll": "Scroll",
"title": "Prompt Display Mode"
}, },
"promptEditor": { "promptEditor": {
"title": "Prompt Editor", "desc": "Provide a simple prompt editor at the top of the quick setting sidebar",
"desc": "Provide a simple prompt editor at the top of the quick setting sidebar" "title": "Prompt Editor"
}, },
"promptHighlight": { "promptHighlight": {
"title": "Prompt Syntax Highlighting", "desc": "Automatically colorize prompt display according to the Stable Diffusion syntax rules",
"desc": "Automatically colorize prompt display according to the Stable Diffusion syntax rules" "title": "Prompt Syntax Highlighting"
}, },
"quickSettingSidebar": { "quickSettingSidebar": {
"defaultExpand": { "defaultExpand": {
"title": "Default Expand", "desc": "Whether to expand the sidebar by default when starting",
"desc": "Whether to expand the sidebar by default when starting" "title": "Default Expand"
}, },
"defaultWidth": { "defaultWidth": {
"title": "Default Width", "desc": "Default width of the sidebar when starting",
"desc": "Default width of the sidebar when starting" "title": "Default Width"
}, },
"displayMode": { "displayMode": {
"title": "Display Mode", "desc": "Fixed as grid mode for constant display, auto-expand when the mouse moves to the side in floating mode",
"desc": "Fixed as grid mode for constant display, auto-expand when the mouse moves to the side in floating mode" "title": "Display Mode"
}, },
"enable": { "enable": {
"title": "Enable", "desc": "Enable the quick setting sidebar on the left side",
"desc": "Enable the quick setting sidebar on the left side" "title": "Enable"
} }
}, },
"reduceAnimation": { "reduceAnimation": {
"title": "Reduce Animation", "desc": "Reduce the blur effect and background flow color, which can improve smoothness and save CPU usage",
"desc": "Reduce the blur effect and background flow color, which can improve smoothness and save CPU usage" "title": "Reduce Animation"
}, },
"splitPreviewer": { "splitPreviewer": {
"title": "Split Previewer", "desc": "Put the prompt input box on the left and the generate button on the right, ensuring that the generated image is always displayed at the top when scrolling (experimental)",
"desc": "Put the prompt input box on the left and the generate button on the right, ensuring that the generated image is always displayed at the top when scrolling (experimental)" "title": "Split Previewer"
}, },
"svgIcons": { "svgIcons": {
"title": "SVG Icons", "desc": "Replace all Emoji icons in stable diffusion webui with SVG icons globally",
"desc": "Replace all Emoji icons in stable diffusion webui with SVG icons globally" "title": "SVG Icons"
},
"tab": {
"appearance": "Appearance",
"experimental": "Experimental",
"layout": "Layout",
"sidebar": "Sidebar"
} }
}, },
"share": "Share", "share": "Share",
"shareModal": { "shareModal": {
"download": "Download Screenshot", "download": "Download Screenshot",
"imageType": "Image Format", "imageType": "Image Format",
"screenshot": "Screenshot",
"info": "Image Info", "info": "Image Info",
"screenshot": "Screenshot",
"settings": "Export Settings", "settings": "Export Settings",
"withBackground": "Include Background Image",
"withFooter": "Include Footer",
"warn": "Please Generate Image First",
"showNegative": "Show Negative Promot",
"showConfig": "Show Generate Config",
"showAllImages": "Show All Images", "showAllImages": "Show All Images",
"title": "Image Name", "showConfig": "Show Generate Config",
"showNegative": "Show Negative Promot",
"tabs": { "tabs": {
"info": "Info", "info": "Info",
"settings": "Settings" "settings": "Settings"
} },
"title": "Image Name",
"warn": "Please Generate Image First",
"withBackground": "Include Background Image",
"withFooter": "Include Footer"
}, },
"sidebar": { "sidebar": {
"extraNetwork": "Extra Network", "extraNetwork": "Extra Network",
"quickSetting": "Quick Setting",
"mode": { "mode": {
"fixed": "Fixed", "fixed": "Fixed",
"float": "Float" "float": "Float"
} },
"quickSetting": "Quick Setting"
} }
} }

View File

@ -25,6 +25,7 @@
"title": "Comentarios sobre el tema" "title": "Comentarios sobre el tema"
}, },
"themeSetting": { "themeSetting": {
"desc": "Preferencias y configuración de diseño",
"title": "Configuración del tema" "title": "Configuración del tema"
} }
}, },

View File

@ -25,6 +25,7 @@
"title": "Retour sur le thème" "title": "Retour sur le thème"
}, },
"themeSetting": { "themeSetting": {
"desc": "Paramètres de thème et de mise en page",
"title": "Paramètres du thème" "title": "Paramètres du thème"
} }
}, },

View File

@ -25,6 +25,7 @@
"title": "テーマフィードバック" "title": "テーマフィードバック"
}, },
"themeSetting": { "themeSetting": {
"desc": "テーマとレイアウト設定",
"title": "テーマ設定" "title": "テーマ設定"
} }
}, },

View File

@ -25,6 +25,7 @@
"title": "테마 피드백" "title": "테마 피드백"
}, },
"themeSetting": { "themeSetting": {
"desc": "테마 및 레이아웃 설정",
"title": "테마 설정" "title": "테마 설정"
} }
}, },

View File

@ -25,6 +25,7 @@
"title": "Feedback do Tema" "title": "Feedback do Tema"
}, },
"themeSetting": { "themeSetting": {
"desc": "Preferências e configurações de layout",
"title": "Configurações do Tema" "title": "Configurações do Tema"
} }
}, },

View File

@ -25,6 +25,7 @@
"title": "Обратная связь по теме" "title": "Обратная связь по теме"
}, },
"themeSetting": { "themeSetting": {
"desc": "Настройки темы и макета",
"title": "Настройки темы" "title": "Настройки темы"
} }
}, },

View File

@ -25,6 +25,7 @@
"title": "Tema Geri Bildirimi" "title": "Tema Geri Bildirimi"
}, },
"themeSetting": { "themeSetting": {
"desc": "Tema ve Düzen Ayarları",
"title": "Tema Ayarları" "title": "Tema Ayarları"
} }
}, },

View File

@ -25,7 +25,8 @@
"title": "主题反馈" "title": "主题反馈"
}, },
"themeSetting": { "themeSetting": {
"title": "主题设置" "title": "主题设置",
"desc": "偏好与布局设置"
} }
}, },
"prompt": { "prompt": {

View File

@ -25,6 +25,7 @@
"title": "主題反饋" "title": "主題反饋"
}, },
"themeSetting": { "themeSetting": {
"desc": "偏好與版面設定",
"title": "主題設置" "title": "主題設置"
} }
}, },

View File

@ -2,7 +2,7 @@
"name": "sd-webui-lobe-theme", "name": "sd-webui-lobe-theme",
"version": "3.4.10", "version": "3.4.10",
"private": true, "private": true,
"description": "The modern theme for stable diffusion webui, exquisite interface design, highly customizable UI, and efficiency boosting features.", "description": "LobeThem: The Modern Theme for Stable Diffusion WebUI, Exquisite interface design, Highly customizable UI, and Efficiency boosting features.",
"keywords": [ "keywords": [
"lobehub", "lobehub",
"stable-diffusion-webui", "stable-diffusion-webui",
@ -67,67 +67,68 @@
] ]
}, },
"dependencies": { "dependencies": {
"@bluelovers/auto1111-pnginfo": "^2.0.1", "@bluelovers/auto1111-pnginfo": "^2.0.2",
"@lobehub/ui": "latest", "@lobehub/ui": "^1.138.24",
"@rollup/rollup-win32-x64-msvc": "^4.13.0", "@rollup/rollup-win32-x64-msvc": "^4.17.2",
"ahooks": "^3", "ahooks": "^3.7.11",
"antd": "^5", "antd": "5.17.0",
"antd-style": "latest", "antd-style": "^3.6.2",
"consola": "^3", "consola": "^3.2.3",
"dayjs": "^1", "dayjs": "^1.11.11",
"i18next": "^23", "i18next": "^23.11.4",
"i18next-http-backend": "^2", "i18next-http-backend": "^2.5.1",
"lodash-es": "^4", "lodash-es": "^4.17.21",
"lucide-react": "latest", "lucide-react": "latest",
"lucide-static": "latest", "lucide-static": "latest",
"modern-screenshot": "^4", "modern-screenshot": "^4.4.39",
"polished": "^4", "polished": "^4.3.1",
"react": "^18", "react": "^18.3.1",
"react-dnd": "^16", "react-dnd": "^16.0.1",
"react-dnd-html5-backend": "^16", "react-dnd-html5-backend": "^16.0.1",
"react-dom": "^18", "react-dom": "^18.3.1",
"react-helmet": "^6", "react-helmet": "^6.1.0",
"react-i18next": "^13", "react-i18next": "^13.5.0",
"react-layout-kit": "^1", "react-layout-kit": "^1.9.0",
"react-rnd": "^10", "react-rnd": "^10.4.10",
"react-tag-input": "^6", "react-tag-input": "^6.9.0",
"semver": "^7", "semver": "^7.6.2",
"shikiji": "^0.9", "shikiji": "^0.9.19",
"swr": "^2", "swr": "^2.2.5",
"zustand": "^4.4.1", "url-join": "^5.0.0",
"zustand-utils": "^1.3.1" "zustand": "^4.5.2",
"zustand-utils": "^1.3.2"
}, },
"devDependencies": { "devDependencies": {
"@commitlint/cli": "^18", "@commitlint/cli": "^18.6.1",
"@lobehub/lint": "latest", "@lobehub/lint": "^1.23.4",
"@testing-library/jest-dom": "^6", "@testing-library/jest-dom": "^6.4.5",
"@testing-library/react": "^14", "@testing-library/react": "^14.3.1",
"@types/lodash-es": "^4", "@types/lodash-es": "^4.17.12",
"@types/node": "^20", "@types/node": "^20.12.12",
"@types/react": "^18", "@types/react": "^18.3.2",
"@types/react-dom": "^18", "@types/react-dom": "^18.3.0",
"@types/react-helmet": "^6", "@types/react-helmet": "^6.1.11",
"@types/react-tag-input": "^6", "@types/react-tag-input": "^6.6.6",
"@types/semver": "^7", "@types/semver": "^7.5.8",
"@vitejs/plugin-react-swc": "^3", "@vitejs/plugin-react-swc": "^3.6.0",
"@vitest/coverage-v8": "^1", "@vitest/coverage-v8": "^1.6.0",
"commitlint": "^18", "commitlint": "^18.6.1",
"dotenv": "^16", "dotenv": "^16.4.5",
"eslint": "^8", "eslint": "^8.57.0",
"fast-deep-equal": "^3", "fast-deep-equal": "^3.1.3",
"husky": "^8", "husky": "^8.0.3",
"jsdom": "^23.0.0", "jsdom": "^23.2.0",
"lint-staged": "^15", "lint-staged": "^15.2.2",
"prettier": "^3", "prettier": "^3.2.5",
"query-string": "^8", "query-string": "^8.2.0",
"remark": "^14", "remark": "^14.0.3",
"remark-cli": "^11", "remark-cli": "^11.0.0",
"semantic-release": "^21", "semantic-release": "^21.1.2",
"stylelint": "^15", "stylelint": "^15.11.0",
"terser": "^5", "terser": "^5.31.0",
"typescript": "^5", "typescript": "^5.4.5",
"vite": "^5", "vite": "^5.2.11",
"vitest": "latest" "vitest": "~1.2.2"
}, },
"publishConfig": { "publishConfig": {
"access": "public", "access": "public",

View File

@ -2,6 +2,7 @@ import { LayoutHeader, LayoutMain, LayoutSidebar } from '@lobehub/ui';
import isEqual from 'fast-deep-equal'; import isEqual from 'fast-deep-equal';
import { memo, useEffect } from 'react'; import { memo, useEffect } from 'react';
import StructuredData from '@/components/StructuredData';
import PromptFormator from '@/features/PromptFormator'; import PromptFormator from '@/features/PromptFormator';
import '@/locales/config'; import '@/locales/config';
import ImageInfo from '@/modules/ImageInfo/page'; import ImageInfo from '@/modules/ImageInfo/page';
@ -35,6 +36,7 @@ const Index = memo(() => {
return ( return (
<> <>
<StructuredData />
<GlobalStyle /> <GlobalStyle />
<LayoutHeader headerHeight={HEADER_HEIGHT}> <LayoutHeader headerHeight={HEADER_HEIGHT}>
<Header /> <Header />

View File

@ -67,6 +67,7 @@ export const Layout = memo<PropsWithChildren>(({ children }) => {
content="width=device-width, initial-scale=1, minimum-scale=1, maximum-scale=1, viewport-fit=cover, user-scalable=no" content="width=device-width, initial-scale=1, minimum-scale=1, maximum-scale=1, viewport-fit=cover, user-scalable=no"
name="viewport" name="viewport"
/> />
<title>{TITLE}</title>
<meta content={TITLE} name="apple-mobile-web-app-title" /> <meta content={TITLE} name="apple-mobile-web-app-title" />
<meta content={TITLE} name="application-name" /> <meta content={TITLE} name="application-name" />
<meta content={DESC} name="description" /> <meta content={DESC} name="description" />
@ -76,7 +77,29 @@ export const Layout = memo<PropsWithChildren>(({ children }) => {
<meta content="yes" name="apple-mobile-web-app-capable" /> <meta content="yes" name="apple-mobile-web-app-capable" />
<meta content={TITLE} name="apple-mobile-web-app-title" /> <meta content={TITLE} name="apple-mobile-web-app-title" />
<meta content="black-translucent" name="apple-mobile-web-app-status-bar-style" /> <meta content="black-translucent" name="apple-mobile-web-app-status-bar-style" />
<meta content={TITLE} name="apple-mobile-web-app-title" />
<meta content="yes" name="apple-mobile-web-app-capable" />
<meta content="index,follow" name="robots" />
<link href={manifest(genAssets)} rel="manifest" /> <link href={manifest(genAssets)} rel="manifest" />
<meta content={TITLE} property="og:title" />
<meta content={DESC} property="og:description" />
<meta content="https://github.com/lobehub/sd-webui-lobe-theme" property="og:url" />
<meta content={TITLE} property="og:site_name" />
<meta content="en-US" property="og:locale" />
<meta
content="https://repository-images.githubusercontent.com/606329910/7fd79db5-fd91-450c-9e95-8ccce8ffdc0b"
property="og:image"
/>
<meta content="website" property="og:type" />
<meta content="summary_large_image" name="twitter:card" />
<meta content="@lobehub" name="twitter:site" />
<meta content={TITLE} name="twitter:title" />
<meta content={DESC} name="twitter:description" />
<meta
content="https://repository-images.githubusercontent.com/606329910/7fd79db5-fd91-450c-9e95-8ccce8ffdc0b"
name="twitter:image"
/>
<link href="https://github.com/lobehub/sd-webui-lobe-theme" rel="canonical" />
</Helmet> </Helmet>
<GlobalLayout> <GlobalLayout>
{storeLoading === false && loading === false ? children : <Loading />} {storeLoading === false && loading === false ? children : <Loading />}

View File

@ -0,0 +1,26 @@
import { FC } from 'react';
import pkg from '@/../package.json';
import { ldModule } from '@/components/StructuredData/ld';
const TITLE = 'Stable Diffusion · LobeHub';
const DESC = pkg.description;
const StructuredData: FC = () => {
const ld = ldModule.generate({
description: DESC,
image:
'https://repository-images.githubusercontent.com/606329910/7fd79db5-fd91-450c-9e95-8ccce8ffdc0b',
title: TITLE,
url: '/',
});
return (
<script
dangerouslySetInnerHTML={{ __html: JSON.stringify(ld) }}
id="structured-data"
type="application/ld+json"
/>
);
};
export default StructuredData;

View File

@ -0,0 +1,216 @@
import urlJoin from 'url-join';
import pkg from '@/../package.json';
import { EMAIL_BUSINESS, EMAIL_SUPPORT, OFFICIAL_SITE, SITE_URL, X } from '@/const/url';
const LAST_MODIFIED = new Date().toISOString();
export const AUTHOR_LIST = {
arvinxx: {
avatar: 'https://avatars.githubusercontent.com/u/28616219?v=4',
desc: 'Founder, Design Engineer',
name: 'Arvin Xu',
url: 'https://github.com/arvinxx',
},
canisminor: {
avatar: 'https://avatars.githubusercontent.com/u/17870709?v=4',
desc: 'Founder, Design Engineer',
name: 'CanisMinor',
url: 'https://github.com/arvinxx',
},
lobehub: {
avatar: 'https://avatars.githubusercontent.com/u/131470832?v=4',
desc: 'Official Account',
name: 'LobeHub',
url: 'https://github.com/lobehub',
},
};
class Ld {
generate({
image = '/og/cover.png',
url,
title,
description,
date,
webpage = {
enable: true,
},
}: {
date?: string;
description: string;
image?: string;
title: string;
url: string;
webpage?: {
enable?: boolean;
search?: boolean;
};
}) {
return {
'@context': 'https://schema.org',
'@graph': [
this.genWebSite(),
webpage?.enable &&
this.genWebPage({
...webpage,
date,
description,
image,
title,
url,
}),
image && this.genImageObject({ image, url }),
this.genOrganization(),
].filter(Boolean),
};
}
genOrganization() {
return {
'@id': this.getId(SITE_URL, '#organization'),
'@type': 'Organization',
'alternateName': 'LobeTheme',
'contactPoint': {
'@type': 'ContactPoint',
'contactType': 'customer support',
'email': EMAIL_SUPPORT,
},
'description':
'We are a group of e/acc design-engineers, hoping to provide modern design components and tools for AIGC, and creating a technology-driven forum, fostering knowledge interaction and the exchange of ideas that may culminate in mutual inspiration and collaborative innovation.',
'email': EMAIL_BUSINESS,
'founders': [this.getAuthors(['arvinxx']), this.getAuthors(['canisminor'])],
'image': urlJoin(OFFICIAL_SITE, '/icon-512x512.png'),
'logo': {
'@type': 'ImageObject',
'height': 512,
'url': urlJoin(OFFICIAL_SITE, '/icon-512x512.png'),
'width': 512,
},
'name': 'LobeHub',
'sameAs': [
X,
'https://github.com/lobehub',
'https://medium.com/@lobehub',
'https://www.youtube.com/@lobehub',
],
'url': OFFICIAL_SITE,
};
}
getAuthors(ids: string[] = []) {
const defaultAuthor = {
'@id': this.getId(SITE_URL, '#organization'),
'@type': 'Organization',
};
if (!ids || ids.length === 0) return defaultAuthor;
if (ids.length === 1 && ids[0] === 'lobehub') return defaultAuthor;
const personId = ids.find((id) => id !== 'lobehub');
if (!personId) return defaultAuthor;
const person = (AUTHOR_LIST as any)?.[personId];
if (!person) return defaultAuthor;
return {
'@type': 'Person',
'name': person.name,
'url': person.url,
};
}
genWebPage({
date,
image,
search,
description,
title,
url,
}: {
breadcrumbs?: { title: string; url: string }[];
date?: string;
description: string;
image?: string;
search?: boolean;
title: string;
url: string;
}) {
const fixedUrl = this.fixUrl(url);
const dateCreated = date ? new Date(date).toISOString() : LAST_MODIFIED;
const dateModified = date ? new Date(date).toISOString() : LAST_MODIFIED;
const baseInfo: any = {
'@id': fixedUrl,
'@type': 'WebPage',
'about': {
'@id': this.getId(SITE_URL, '#organization'),
},
'breadcrumbs': {
'@id': this.getId(fixedUrl, '#breadcrumb'),
},
'dateModified': dateModified,
'datePublished': dateCreated,
'description': description,
'image': {
'@id': this.getId(fixedUrl, '#primaryimage'),
},
'inLanguage': 'en-US',
'isPartOf': {
'@id': this.getId(SITE_URL, '#website'),
},
'name': this.fixTitle(title),
'primaryImageOfPage': {
'@id': this.getId(fixedUrl, '#primaryimage'),
},
'thumbnailUrl': image,
};
if (search) {
baseInfo.potentialAction = {
'@type': 'SearchAction',
'query-input': 'required name=search_term_string',
'target': `${fixedUrl}?q={search_term_string}`,
};
}
return baseInfo;
}
genImageObject({ image, url }: { image: string; url: string }) {
const fixedUrl = this.fixUrl(url);
return {
'@id': this.getId(fixedUrl, '#primaryimage'),
'@type': 'ImageObject',
'contentUrl': image,
'inLanguage': 'en-US',
'url': image,
};
}
genWebSite() {
const baseInfo: any = {
'@id': this.getId(SITE_URL, '#website'),
'@type': 'WebSite',
'description': pkg.description,
'inLanguage': 'en-US',
'name': 'LobeTheme',
'publisher': {
'@id': this.getId(SITE_URL, '#organization'),
},
'url': SITE_URL,
};
return baseInfo;
}
private getId(url: string, id: string) {
return [url, id].join('/');
}
private fixTitle(title: string) {
return title.includes('LobeTheme') ? title : `${title} · LobeTheme`;
}
private fixUrl(url: string) {
return urlJoin(SITE_URL, url);
}
}
export const ldModule = new Ld();

View File

@ -2,10 +2,14 @@ import pkg from '@/../package.json';
export const DISCORD_URL = 'https://discord.gg/AYFPHvv2jT'; export const DISCORD_URL = 'https://discord.gg/AYFPHvv2jT';
export const SPONSOR_URL = 'https://opencollective.com/lobehub'; export const SPONSOR_URL = 'https://opencollective.com/lobehub';
export const SPONSOR_IMG = 'https://readme-wizard.lobehub.com/api/sponsor';
export const GISCUS_REPO_ID = 'R_kgDOJCPcNg'; export const GISCUS_REPO_ID = 'R_kgDOJCPcNg';
export const GITHUB_REPO_URL = pkg.homepage; export const GITHUB_REPO_URL = pkg.homepage;
export const REPO_NAME = GITHUB_REPO_URL.replace( export const REPO_NAME = GITHUB_REPO_URL.replace(
'https://github.com/', 'https://github.com/',
'', '',
) as `${string}/${string}`; ) as `${string}/${string}`;
export const OFFICIAL_SITE = 'https://lobehub.com/';
export const SITE_URL = location.origin;
export const EMAIL_SUPPORT = 'support@lobehub.com';
export const EMAIL_BUSINESS = 'hello@lobehub.com';
export const X = 'https://x.com/lobehub';

View File

@ -36,11 +36,14 @@ export const useStyles = createStyles(
overflow: unset; overflow: unset;
display: grid; display: grid;
grid-template-columns: repeat(auto-fill, minmax(${size}px, 1fr)); grid-template-columns: repeat(auto-fill, minmax(${size}px, 1fr));
flex: none !important;
gap: 8px; gap: 8px;
height: unset; height: unset;
min-height: unset; min-height: unset;
border: unset !important;
.name { .name {
background: unset !important; background: unset !important;
} }
@ -55,6 +58,19 @@ export const useStyles = createStyles(
} }
} }
.extra-network-dirs {
display: flex;
flex-wrap: wrap;
gap: 6px;
margin-bottom: 12px;
> button.lg.secondary.gradio-button {
padding: 4px 8px;
font-size: 12px;
line-height: 1;
}
}
.extra-networks { .extra-networks {
.pending { .pending {
opacity: 1 !important; opacity: 1 !important;
@ -78,6 +94,37 @@ export const useStyles = createStyles(
display: none; display: none;
} }
} }
.extra-networks-controls-div {
height: unset !important;
}
.extra-network-control {
position: relative;
flex: none;
flex-wrap: wrap;
gap: 8px;
.extra-network-control--search {
width: 100%;
}
small {
display: none;
}
> div:has(i) {
position: relative;
display: flex;
flex: none;
height: 32px;
background: ${token.colorFillTertiary};
border-radius: ${token.borderRadius}px;
}
}
} }
.extra-network-subdirs { .extra-network-subdirs {

View File

@ -1,7 +1,6 @@
import { Form, Swatches } from '@lobehub/ui'; import { Form, Swatches } from '@lobehub/ui';
import { Input, Segmented, Select, Switch } from 'antd'; import { Input, Segmented, Select, Switch } from 'antd';
import isEqual from 'fast-deep-equal'; import isEqual from 'fast-deep-equal';
import { Palette } from 'lucide-react';
import { memo, useCallback, useMemo, useState } from 'react'; import { memo, useCallback, useMemo, useState } from 'react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
@ -153,7 +152,7 @@ const SettingForm = memo(() => {
valuePropName: 'checked', valuePropName: 'checked',
}, },
], ],
icon: Palette,
title: t('setting.group.theme'), title: t('setting.group.theme'),
}), }),
[ [
@ -173,6 +172,7 @@ const SettingForm = memo(() => {
onFinish={onFinish} onFinish={onFinish}
onValuesChange={(_, v) => setRawSetting(v)} onValuesChange={(_, v) => setRawSetting(v)}
style={{ flex: 1 }} style={{ flex: 1 }}
variant={'pure'}
/> />
); );
}); });

View File

@ -1,7 +1,6 @@
import { Form } from '@lobehub/ui'; import { Form } from '@lobehub/ui';
import { Switch } from 'antd'; import { Switch } from 'antd';
import isEqual from 'fast-deep-equal'; import isEqual from 'fast-deep-equal';
import { Puzzle, TextCursorInput } from 'lucide-react';
import { memo, useCallback, useMemo } from 'react'; import { memo, useCallback, useMemo } from 'react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
@ -31,7 +30,6 @@ const SettingForm = memo(() => {
valuePropName: 'checked', valuePropName: 'checked',
}, },
], ],
icon: Puzzle,
title: t('setting.group.experimental'), title: t('setting.group.experimental'),
}), }),
[], [],
@ -55,7 +53,6 @@ const SettingForm = memo(() => {
valuePropName: 'checked', valuePropName: 'checked',
}, },
], ],
icon: TextCursorInput,
title: t('setting.group.promptTextarea'), title: t('setting.group.promptTextarea'),
}), }),
[], [],
@ -68,6 +65,7 @@ const SettingForm = memo(() => {
items={[experimental, promptTextarea]} items={[experimental, promptTextarea]}
onFinish={onFinish} onFinish={onFinish}
style={{ flex: 1 }} style={{ flex: 1 }}
variant={'pure'}
/> />
); );
}); });

View File

@ -1,7 +1,6 @@
import { Form } from '@lobehub/ui'; import { Form } from '@lobehub/ui';
import { Segmented, Switch } from 'antd'; import { Segmented, Switch } from 'antd';
import isEqual from 'fast-deep-equal'; import isEqual from 'fast-deep-equal';
import { Layout, TextCursorInput } from 'lucide-react';
import { memo, useCallback, useMemo } from 'react'; import { memo, useCallback, useMemo } from 'react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
@ -38,7 +37,7 @@ const SettingForm = memo(() => {
valuePropName: 'checked', valuePropName: 'checked',
}, },
], ],
icon: Layout,
title: t('setting.group.layout'), title: t('setting.group.layout'),
}), }),
[], [],
@ -67,7 +66,7 @@ const SettingForm = memo(() => {
name: 'promptTextareaType', name: 'promptTextareaType',
}, },
], ],
icon: TextCursorInput,
title: t('setting.group.promptTextarea'), title: t('setting.group.promptTextarea'),
}), }),
[], [],
@ -80,6 +79,7 @@ const SettingForm = memo(() => {
items={[layout, promptTextarea]} items={[layout, promptTextarea]}
onFinish={onFinish} onFinish={onFinish}
style={{ flex: 1 }} style={{ flex: 1 }}
variant={'pure'}
/> />
); );
}); });

View File

@ -1,7 +1,6 @@
import { Form } from '@lobehub/ui'; import { Form } from '@lobehub/ui';
import { InputNumber, Segmented, Switch } from 'antd'; import { InputNumber, Segmented, Switch } from 'antd';
import isEqual from 'fast-deep-equal'; import isEqual from 'fast-deep-equal';
import { PanelLeftClose, PanelRightClose } from 'lucide-react';
import { memo, useCallback, useMemo, useState } from 'react'; import { memo, useCallback, useMemo, useState } from 'react';
import { useTranslation } from 'react-i18next'; import { useTranslation } from 'react-i18next';
@ -67,7 +66,7 @@ const SettingForm = memo(() => {
name: 'sidebarWidth', name: 'sidebarWidth',
}, },
], ],
icon: PanelLeftClose,
title: t('setting.group.quickSettingSidebar'), title: t('setting.group.quickSettingSidebar'),
}), }),
[rawSetting.enableSidebar], [rawSetting.enableSidebar],
@ -126,7 +125,7 @@ const SettingForm = memo(() => {
name: 'extraNetworkCardSize', name: 'extraNetworkCardSize',
}, },
], ],
icon: PanelRightClose,
title: t('setting.group.extraNetworkSidebar'), title: t('setting.group.extraNetworkSidebar'),
}), }),
[rawSetting.enableExtraNetworkSidebar], [rawSetting.enableExtraNetworkSidebar],
@ -140,6 +139,7 @@ const SettingForm = memo(() => {
onFinish={onFinish} onFinish={onFinish}
onValuesChange={(_, v) => setRawSetting(v)} onValuesChange={(_, v) => setRawSetting(v)}
style={{ flex: 1 }} style={{ flex: 1 }}
variant={'pure'}
/> />
); );
}); });

View File

@ -0,0 +1,41 @@
import { Logo } from '@lobehub/ui';
import { createStyles } from 'antd-style';
import { memo } from 'react';
import { Flexbox, FlexboxProps } from 'react-layout-kit';
const useStyles = createStyles(({ token, css }) => ({
logoLink: css`
height: 20px;
color: inherit;
&:hover {
color: ${token.colorLink};
}
`,
}));
const BrandWatermark = memo<Omit<FlexboxProps, 'children'>>(({ style, ...rest }) => {
const { styles, theme } = useStyles();
return (
<Flexbox
align={'center'}
flex={'none'}
gap={4}
horizontal
style={{ color: theme.colorTextDescription, fontSize: 12, ...style }}
{...rest}
>
<span>Powered by</span>
<a
className={styles.logoLink}
href={'https://lobehub.com'}
rel="noreferrer"
target={'_blank'}
>
<Logo size={20} type={'text'} />
</a>
</Flexbox>
);
});
export default BrandWatermark;

View File

@ -1,47 +0,0 @@
import { Icon, List } from '@lobehub/ui';
import { createStyles } from 'antd-style';
import { type LucideIcon } from 'lucide-react';
import { CSSProperties, ReactNode, memo } from 'react';
const { Item } = List;
const useStyles = createStyles(({ css, token }) => ({
container: css`
position: relative;
padding: 16px;
border-radius: ${token.borderRadius}px;
div {
overflow: visible;
font-size: 16px;
font-weight: 500;
}
`,
}));
export interface ItemProps {
active?: boolean;
className?: string;
icon: LucideIcon;
label: ReactNode;
onClick?: () => void;
style?: CSSProperties;
}
const SettingItem = memo<ItemProps>(
({ label, icon, active = false, style, className, onClick }) => {
const { cx, styles } = useStyles();
return (
<Item
active={active}
avatar={<Icon icon={icon} size={{ fontSize: 16 }} />}
className={cx(styles.container, className)}
onClick={onClick}
style={style}
title={label as string}
/>
);
},
);
export default SettingItem;

View File

@ -0,0 +1,97 @@
import { Menu as AntdMenu, MenuProps as AntdMenuProps, ConfigProvider } from 'antd';
import { createStyles } from 'antd-style';
import { memo } from 'react';
const useStyles = createStyles(({ css, token, prefixCls }) => ({
compact: css`
display: flex;
flex-direction: column;
gap: 0.125rem;
`,
menu: css`
flex: 1;
background: transparent;
border: none !important;
.${prefixCls}-menu-item-divider {
margin-block: 0.125rem;
border-color: ${token.colorFillTertiary};
&:first-child {
margin-top: 0;
}
&:last-child {
margin-bottom: 0;
}
}
.${prefixCls}-menu-item, .${prefixCls}-menu-submenu-title {
display: flex;
gap: 0.75rem;
align-items: center;
height: unset;
min-height: 2rem;
padding: 0.375rem 0.75rem;
line-height: 2;
.anticon + .${prefixCls}-menu-title-content {
margin-inline-start: 0;
}
}
.${prefixCls}-menu-item-selected {
.${prefixCls}-menu-item-icon svg {
color: ${token.colorText};
}
}
.${prefixCls}-menu-item-icon svg {
color: ${token.colorTextSecondary};
}
.${prefixCls}-menu-title-content {
flex: 1;
}
`,
}));
export interface MenuProps extends AntdMenuProps {
variant?: 'default' | 'compact';
}
const Menu = memo<MenuProps>(({ className, selectable = false, variant, ...rest }) => {
const isCompact = variant === 'compact';
const { cx, styles, theme } = useStyles();
return (
<ConfigProvider
theme={{
components: {
Menu: {
controlHeightLG: 36,
iconMarginInlineEnd: 8,
iconSize: 16,
itemBorderRadius: theme.borderRadius,
itemColor: selectable ? theme.colorTextSecondary : theme.colorText,
itemHoverBg: theme.colorFillTertiary,
itemMarginBlock: isCompact ? 0 : 4,
itemMarginInline: isCompact ? 0 : 4,
itemSelectedBg: theme.colorFillSecondary,
paddingXS: -8,
},
},
}}
>
<AntdMenu
className={cx(styles.menu, isCompact && styles.compact, className)}
mode="vertical"
selectable={selectable}
{...rest}
/>
</ConfigProvider>
);
});
export default Menu;

View File

@ -15,7 +15,7 @@ const MobileSidebar = memo<SidebarProps>(({ tab, setTab }) => {
<Segmented <Segmented
block block
onChange={setTab as any} onChange={setTab as any}
options={items.map(({ value, label }) => ({ label, value }))} options={items.map(({ key, label }) => ({ label, value: key }))}
value={tab} value={tab}
/> />
); );

View File

@ -0,0 +1,56 @@
import { createStyles } from 'antd-style';
import { ReactNode } from 'react';
import { Flexbox, FlexboxProps } from 'react-layout-kit';
import BrandWatermark from './BrandWatermark';
const useStyles = createStyles(({ token, css }) => ({
container: css`
padding: 24px 12px 16px;
background: ${token.colorBgContainer};
border-inline-end: 1px solid ${token.colorBorder};
`,
desc: css`
line-height: 1.4;
color: ${token.colorTextDescription};
`,
header: css`
padding: 0 0.75rem;
`,
logo: css`
fill: ${token.colorText};
`,
title: css`
margin: 0;
font-size: 26px;
font-weight: 600;
line-height: 1.3;
`,
}));
interface SidebarLayoutProps extends FlexboxProps {
desc?: ReactNode;
title?: string;
}
const SidebarLayout = ({ children, className, title, desc, ...rest }: SidebarLayoutProps) => {
const { cx, styles } = useStyles();
return (
<Flexbox
className={cx(styles.container, className)}
flex={'none'}
gap={20}
width={280}
{...rest}
>
<Flexbox className={styles.header} gap={4}>
<h1 className={styles.title}>{title}</h1>
{desc && <p className={styles.desc}>{desc}</p>}
</Flexbox>
{children}
<BrandWatermark paddingInline={12} />
</Flexbox>
);
};
export default SidebarLayout;

View File

@ -1,9 +1,11 @@
import { memo } from 'react'; import { memo } from 'react';
import { useTranslation } from 'react-i18next';
import { Flexbox } from 'react-layout-kit'; import { Flexbox } from 'react-layout-kit';
import { useTabItems } from '@/features/Setting/Sidebar/useTabItems'; import VersionTag from '../../../components/VersionTag';
import Menu from './Menu';
import Item from './Item'; import SidebarLayout from './SidebarLayout';
import { useTabItems } from './useTabItems';
export enum SettingsTabs { export enum SettingsTabs {
Appearance = 'appearance', Appearance = 'appearance',
@ -19,19 +21,24 @@ interface SidebarProps {
const Sidebar = memo<SidebarProps>(({ tab, setTab }) => { const Sidebar = memo<SidebarProps>(({ tab, setTab }) => {
const items = useTabItems(); const items = useTabItems();
const { t } = useTranslation();
return ( return (
<Flexbox gap={4}> <SidebarLayout
{items.map(({ value, icon, label }) => ( desc={
<Item <Flexbox align={'center'} gap={4} horizontal>
active={tab === value} {t('modal.themeSetting.desc')}
icon={icon} <VersionTag />
key={value} </Flexbox>
label={label} }
onClick={() => setTab(value)} title={t('modal.themeSetting.title')}
/> >
))} <Menu
</Flexbox> items={items}
onClick={({ key }) => setTab(key as SettingsTabs)}
selectable
selectedKeys={[tab as any]}
/>
</SidebarLayout>
); );
}); });

View File

@ -1,15 +0,0 @@
import { Brush, FlaskConical, Layout, PanelRight } from 'lucide-react';
import { useTranslation } from 'react-i18next';
import { SettingsTabs } from '@/features/Setting/Sidebar/index';
export const useTabItems = () => {
const { t } = useTranslation();
return [
{ icon: Brush, label: t('setting.tab.appearance'), value: SettingsTabs.Appearance },
{ icon: Layout, label: t('setting.tab.layout'), value: SettingsTabs.Layout },
{ icon: PanelRight, label: t('setting.tab.sidebar'), value: SettingsTabs.Sidebar },
{ icon: FlaskConical, label: t('setting.tab.experimental'), value: SettingsTabs.Experimental },
];
};

View File

@ -0,0 +1,28 @@
import { Icon } from '@lobehub/ui';
import { Brush, FlaskConical, Layout, PanelRight } from 'lucide-react';
import { useTranslation } from 'react-i18next';
import { SettingsTabs } from '@/features/Setting/Sidebar/index';
export const useTabItems = () => {
const { t } = useTranslation();
return [
{
icon: <Icon icon={Brush} />,
key: SettingsTabs.Appearance,
label: t('setting.tab.appearance'),
},
{ icon: <Icon icon={Layout} />, key: SettingsTabs.Layout, label: t('setting.tab.layout') },
{
icon: <Icon icon={PanelRight} />,
key: SettingsTabs.Sidebar,
label: t('setting.tab.sidebar'),
},
{
icon: <Icon icon={FlaskConical} />,
key: SettingsTabs.Experimental,
label: t('setting.tab.experimental'),
},
];
};

View File

@ -1,13 +1,8 @@
import { ActionIcon, Modal, type ModalProps } from '@lobehub/ui'; import { Modal, type ModalProps } from '@lobehub/ui';
import { useResponsive } from 'antd-style'; import { useResponsive, useTheme } from 'antd-style';
import { Book } from 'lucide-react';
import { memo, useState } from 'react'; import { memo, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { Flexbox } from 'react-layout-kit'; import { Flexbox } from 'react-layout-kit';
import VersionTag from '@/components/VersionTag';
import { GITHUB_REPO_URL } from '@/const/url';
import FormAppearance from './Form/Appearance'; import FormAppearance from './Form/Appearance';
import FormExperimental from './Form/Experimental'; import FormExperimental from './Form/Experimental';
import Footer from './Form/Footer'; import Footer from './Form/Footer';
@ -23,7 +18,7 @@ export interface SettingProps {
const Setting = memo<SettingProps>(({ open, onCancel }) => { const Setting = memo<SettingProps>(({ open, onCancel }) => {
const [tab, setTab] = useState<SettingsTabs>(SettingsTabs.Appearance); const [tab, setTab] = useState<SettingsTabs>(SettingsTabs.Appearance);
const { mobile } = useResponsive(); const { mobile } = useResponsive();
const { t } = useTranslation(); const theme = useTheme();
const content = ( const content = (
<> <>
@ -36,37 +31,65 @@ const Setting = memo<SettingProps>(({ open, onCancel }) => {
return ( return (
<Modal <Modal
footer={<Footer />} allowFullscreen={true}
footer={mobile ? <Footer /> : null}
onCancel={onCancel} onCancel={onCancel}
open={open} open={open}
styles={{ styles={{
body: mobile ? { padding: 0 } : {}, body: {
display: 'flex',
minHeight: 'min(75vh, 750px)',
overflow: 'hidden',
padding: 0,
paddingBlock: 0,
},
content: {
background: mobile ? theme.colorBgContainer : undefined,
border: 'none',
boxShadow: `0 0 0 1px ${theme.colorBorderSecondary}`,
},
}} }}
title={ title={false}
<Flexbox align={'center'} gap={4}> width={1024}
<Flexbox align={'center'} gap={4} horizontal>
<a href={GITHUB_REPO_URL} rel="noreferrer" target="_blank">
<ActionIcon icon={Book} title="Setting Documents" />
</a>
{t('modal.themeSetting.title')}
<VersionTag />
</Flexbox>
</Flexbox>
}
width={960}
> >
{mobile ? ( {mobile ? (
<Flexbox> <Flexbox
height={'100%'}
style={{ overflow: 'hidden', position: 'relative' }}
width={'100%'}
>
<div style={{ padding: 16 }}> <div style={{ padding: 16 }}>
<MobileSidebar setTab={setTab} tab={tab} /> <MobileSidebar setTab={setTab} tab={tab} />
</div> </div>
{content} <Flexbox
height={'100%'}
style={{ overflowX: 'hidden', overflowY: 'auto', position: 'relative' }}
width={'100%'}
>
{content}
</Flexbox>
</Flexbox> </Flexbox>
) : ( ) : (
<Flexbox gap={16} horizontal> <Flexbox horizontal width={'100%'}>
<Sidebar setTab={setTab} tab={tab} /> <Sidebar setTab={setTab} tab={tab} />
{content} <Flexbox
align={'center'}
gap={64}
style={{
background: theme.isDarkMode ? theme.colorFillQuaternary : theme.colorBgElevated,
minHeight: '100%',
overflowX: 'hidden',
overflowY: 'auto',
paddingBlock: 40,
paddingInline: 56,
}}
width={'100%'}
>
{content}
<Flexbox width={'100%'}>
<Footer />
</Flexbox>
</Flexbox>
</Flexbox> </Flexbox>
)} )}
</Modal> </Modal>

View File

@ -1,6 +1,7 @@
import { Converter } from '@/scripts/formatPrompt';
import { parseFromRawInfo } from '@bluelovers/auto1111-pnginfo'; import { parseFromRawInfo } from '@bluelovers/auto1111-pnginfo';
import { Converter } from '@/scripts/formatPrompt';
const formatPrompt = (prompt: string) => { const formatPrompt = (prompt: string) => {
let newPrompt = prompt.replaceAll('&lt;', '<').replaceAll('&gt;', '>'); let newPrompt = prompt.replaceAll('&lt;', '<').replaceAll('&gt;', '>');
return Converter.convert(newPrompt); return Converter.convert(newPrompt);
@ -13,13 +14,13 @@ export const formatInfo = (info: string) => {
let { let {
prompt: position, prompt: position,
negative_prompt: negative, negative_prompt: negative,
...config, ...config
} = parseFromRawInfo(info, { } = parseFromRawInfo(info, {
isIncludePrompts: true, isIncludePrompts: true,
}) });
position = position.trim().replaceAll('<br>', '\n').replace(/[\s\r\n]+$/g, ''); position = position.trim().replaceAll('<br>', '\n').replaceAll(/\s+$/g, '');
negative = negative.trim().replaceAll('<br>', '\n').replace(/[\s\r\n]+$/g, ''); negative = negative.trim().replaceAll('<br>', '\n').replaceAll(/\s+$/g, '');
position = position ? formatPrompt(position) : ''; position = position ? formatPrompt(position) : '';
negative = negative ? formatPrompt(negative) : ''; negative = negative ? formatPrompt(negative) : '';