Co-authored-by: crazywoola <427733928@qq.com>tags/1.7.2
| @@ -3,7 +3,7 @@ | |||
| import { useEffect, useMemo, useState } from 'react' | |||
| import { useContext } from 'use-context-selector' | |||
| import { useTranslation } from 'react-i18next' | |||
| import { RiListUnordered } from '@remixicon/react' | |||
| import { RiCloseLine, RiListUnordered } from '@remixicon/react' | |||
| import TemplateEn from './template/template.en.mdx' | |||
| import TemplateZh from './template/template.zh.mdx' | |||
| import TemplateJa from './template/template.ja.mdx' | |||
| @@ -22,6 +22,7 @@ const Doc = ({ apiBaseUrl }: DocProps) => { | |||
| const { t } = useTranslation() | |||
| const [toc, setToc] = useState<Array<{ href: string; text: string }>>([]) | |||
| const [isTocExpanded, setIsTocExpanded] = useState(false) | |||
| const [activeSection, setActiveSection] = useState<string>('') | |||
| const { theme } = useTheme() | |||
| // Set initial TOC expanded state based on screen width | |||
| @@ -47,12 +48,47 @@ const Doc = ({ apiBaseUrl }: DocProps) => { | |||
| return null | |||
| }).filter((item): item is { href: string; text: string } => item !== null) | |||
| setToc(tocItems) | |||
| // Set initial active section | |||
| if (tocItems.length > 0) | |||
| setActiveSection(tocItems[0].href.replace('#', '')) | |||
| } | |||
| } | |||
| setTimeout(extractTOC, 0) | |||
| }, [locale]) | |||
| // Track scroll position for active section highlighting | |||
| useEffect(() => { | |||
| const handleScroll = () => { | |||
| const scrollContainer = document.querySelector('.scroll-container') | |||
| if (!scrollContainer || toc.length === 0) | |||
| return | |||
| // Find active section based on scroll position | |||
| let currentSection = '' | |||
| toc.forEach((item) => { | |||
| const targetId = item.href.replace('#', '') | |||
| const element = document.getElementById(targetId) | |||
| if (element) { | |||
| const rect = element.getBoundingClientRect() | |||
| // Consider section active if its top is above the middle of viewport | |||
| if (rect.top <= window.innerHeight / 2) | |||
| currentSection = targetId | |||
| } | |||
| }) | |||
| if (currentSection && currentSection !== activeSection) | |||
| setActiveSection(currentSection) | |||
| } | |||
| const scrollContainer = document.querySelector('.scroll-container') | |||
| if (scrollContainer) { | |||
| scrollContainer.addEventListener('scroll', handleScroll) | |||
| handleScroll() // Initial check | |||
| return () => scrollContainer.removeEventListener('scroll', handleScroll) | |||
| } | |||
| }, [toc, activeSection]) | |||
| // Handle TOC item click | |||
| const handleTocClick = (e: React.MouseEvent<HTMLAnchorElement>, item: { href: string; text: string }) => { | |||
| e.preventDefault() | |||
| @@ -84,40 +120,76 @@ const Doc = ({ apiBaseUrl }: DocProps) => { | |||
| return ( | |||
| <div className="flex"> | |||
| <div className={`fixed right-20 top-32 z-10 transition-all ${isTocExpanded ? 'w-64' : 'w-10'}`}> | |||
| <div className={`fixed right-20 top-32 z-10 transition-all duration-150 ease-out ${isTocExpanded ? 'w-[280px]' : 'w-11'}`}> | |||
| {isTocExpanded | |||
| ? ( | |||
| <nav className="toc max-h-[calc(100vh-150px)] w-full overflow-y-auto rounded-lg border border-components-panel-border bg-components-panel-bg p-4 shadow-md"> | |||
| <div className="mb-4 flex items-center justify-between"> | |||
| <h3 className="text-lg font-semibold text-text-primary">{t('appApi.develop.toc')}</h3> | |||
| <nav className="toc flex max-h-[calc(100vh-150px)] w-full flex-col overflow-hidden rounded-xl border-[0.5px] border-components-panel-border bg-background-default-hover shadow-xl"> | |||
| <div className="relative z-10 flex items-center justify-between border-b border-components-panel-border-subtle bg-background-default-hover px-4 py-2.5"> | |||
| <span className="text-xs font-medium uppercase tracking-wide text-text-tertiary"> | |||
| {t('appApi.develop.toc')} | |||
| </span> | |||
| <button | |||
| onClick={() => setIsTocExpanded(false)} | |||
| className="text-text-tertiary hover:text-text-secondary" | |||
| className="group flex h-6 w-6 items-center justify-center rounded-md transition-colors hover:bg-state-base-hover" | |||
| aria-label="Close" | |||
| > | |||
| ✕ | |||
| <RiCloseLine className="h-3 w-3 text-text-quaternary transition-colors group-hover:text-text-secondary" /> | |||
| </button> | |||
| </div> | |||
| <ul className="space-y-2"> | |||
| {toc.map((item, index) => ( | |||
| <li key={index}> | |||
| <a | |||
| href={item.href} | |||
| className="text-text-secondary transition-colors duration-200 hover:text-text-primary hover:underline" | |||
| onClick={e => handleTocClick(e, item)} | |||
| > | |||
| {item.text} | |||
| </a> | |||
| </li> | |||
| ))} | |||
| </ul> | |||
| <div className="from-components-panel-border-subtle/20 pointer-events-none absolute left-0 right-0 top-[41px] z-10 h-2 bg-gradient-to-b to-transparent"></div> | |||
| <div className="pointer-events-none absolute left-0 right-0 top-[43px] z-10 h-3 bg-gradient-to-b from-background-default-hover to-transparent"></div> | |||
| <div className="relative flex-1 overflow-y-auto px-3 py-3 pt-1"> | |||
| {toc.length === 0 ? ( | |||
| <div className="px-2 py-8 text-center text-xs text-text-quaternary"> | |||
| {t('appApi.develop.noContent')} | |||
| </div> | |||
| ) : ( | |||
| <ul className="space-y-0.5"> | |||
| {toc.map((item, index) => { | |||
| const isActive = activeSection === item.href.replace('#', '') | |||
| return ( | |||
| <li key={index}> | |||
| <a | |||
| href={item.href} | |||
| onClick={e => handleTocClick(e, item)} | |||
| className={cn( | |||
| 'group relative flex items-center rounded-md px-3 py-2 text-[13px] transition-all duration-200', | |||
| isActive | |||
| ? 'bg-state-base-hover font-medium text-text-primary' | |||
| : 'text-text-tertiary hover:bg-state-base-hover hover:text-text-secondary', | |||
| )} | |||
| > | |||
| <span | |||
| className={cn( | |||
| 'mr-2 h-1.5 w-1.5 rounded-full transition-all duration-200', | |||
| isActive | |||
| ? 'scale-100 bg-text-accent' | |||
| : 'scale-75 bg-components-panel-border', | |||
| )} | |||
| /> | |||
| <span className="flex-1 truncate"> | |||
| {item.text} | |||
| </span> | |||
| </a> | |||
| </li> | |||
| ) | |||
| })} | |||
| </ul> | |||
| )} | |||
| </div> | |||
| <div className="pointer-events-none absolute bottom-0 left-0 right-0 z-10 h-4 rounded-b-xl bg-gradient-to-t from-background-default-hover to-transparent"></div> | |||
| </nav> | |||
| ) | |||
| : ( | |||
| <button | |||
| onClick={() => setIsTocExpanded(true)} | |||
| className="flex h-10 w-10 items-center justify-center rounded-full border border-components-panel-border bg-components-button-secondary-bg shadow-md transition-colors duration-200 hover:bg-components-button-secondary-bg-hover" | |||
| className="group flex h-11 w-11 items-center justify-center rounded-full border-[0.5px] border-components-panel-border bg-components-panel-bg shadow-lg transition-all duration-150 hover:bg-background-default-hover hover:shadow-xl" | |||
| aria-label="Open table of contents" | |||
| > | |||
| <RiListUnordered className="h-6 w-6 text-components-button-secondary-text" /> | |||
| <RiListUnordered className="h-5 w-5 text-text-tertiary transition-colors group-hover:text-text-secondary" /> | |||
| </button> | |||
| )} | |||
| </div> | |||
| @@ -1,8 +1,8 @@ | |||
| 'use client' | |||
| import { useEffect, useState } from 'react' | |||
| import { useEffect, useMemo, useState } from 'react' | |||
| import { useContext } from 'use-context-selector' | |||
| import { useTranslation } from 'react-i18next' | |||
| import { RiListUnordered } from '@remixicon/react' | |||
| import { RiCloseLine, RiListUnordered } from '@remixicon/react' | |||
| import TemplateEn from './template/template.en.mdx' | |||
| import TemplateZh from './template/template.zh.mdx' | |||
| import TemplateJa from './template/template.ja.mdx' | |||
| @@ -30,6 +30,7 @@ const Doc = ({ appDetail }: IDocProps) => { | |||
| const { t } = useTranslation() | |||
| const [toc, setToc] = useState<Array<{ href: string; text: string }>>([]) | |||
| const [isTocExpanded, setIsTocExpanded] = useState(false) | |||
| const [activeSection, setActiveSection] = useState<string>('') | |||
| const { theme } = useTheme() | |||
| const variables = appDetail?.model_config?.configs?.prompt_variables || [] | |||
| @@ -59,13 +60,43 @@ const Doc = ({ appDetail }: IDocProps) => { | |||
| return null | |||
| }).filter((item): item is { href: string; text: string } => item !== null) | |||
| setToc(tocItems) | |||
| if (tocItems.length > 0) | |||
| setActiveSection(tocItems[0].href.replace('#', '')) | |||
| } | |||
| } | |||
| // Run after component has rendered | |||
| setTimeout(extractTOC, 0) | |||
| }, [appDetail, locale]) | |||
| useEffect(() => { | |||
| const handleScroll = () => { | |||
| const scrollContainer = document.querySelector('.overflow-auto') | |||
| if (!scrollContainer || toc.length === 0) | |||
| return | |||
| let currentSection = '' | |||
| toc.forEach((item) => { | |||
| const targetId = item.href.replace('#', '') | |||
| const element = document.getElementById(targetId) | |||
| if (element) { | |||
| const rect = element.getBoundingClientRect() | |||
| if (rect.top <= window.innerHeight / 2) | |||
| currentSection = targetId | |||
| } | |||
| }) | |||
| if (currentSection && currentSection !== activeSection) | |||
| setActiveSection(currentSection) | |||
| } | |||
| const scrollContainer = document.querySelector('.overflow-auto') | |||
| if (scrollContainer) { | |||
| scrollContainer.addEventListener('scroll', handleScroll) | |||
| handleScroll() | |||
| return () => scrollContainer.removeEventListener('scroll', handleScroll) | |||
| } | |||
| }, [toc, activeSection]) | |||
| const handleTocClick = (e: React.MouseEvent<HTMLAnchorElement>, item: { href: string; text: string }) => { | |||
| e.preventDefault() | |||
| const targetId = item.href.replace('#', '') | |||
| @@ -82,94 +113,128 @@ const Doc = ({ appDetail }: IDocProps) => { | |||
| } | |||
| } | |||
| } | |||
| const Template = useMemo(() => { | |||
| if (appDetail?.mode === 'chat' || appDetail?.mode === 'agent-chat') { | |||
| switch (locale) { | |||
| case LanguagesSupported[1]: | |||
| return <TemplateChatZh appDetail={appDetail} variables={variables} inputs={inputs} /> | |||
| case LanguagesSupported[7]: | |||
| return <TemplateChatJa appDetail={appDetail} variables={variables} inputs={inputs} /> | |||
| default: | |||
| return <TemplateChatEn appDetail={appDetail} variables={variables} inputs={inputs} /> | |||
| } | |||
| } | |||
| if (appDetail?.mode === 'advanced-chat') { | |||
| switch (locale) { | |||
| case LanguagesSupported[1]: | |||
| return <TemplateAdvancedChatZh appDetail={appDetail} variables={variables} inputs={inputs} /> | |||
| case LanguagesSupported[7]: | |||
| return <TemplateAdvancedChatJa appDetail={appDetail} variables={variables} inputs={inputs} /> | |||
| default: | |||
| return <TemplateAdvancedChatEn appDetail={appDetail} variables={variables} inputs={inputs} /> | |||
| } | |||
| } | |||
| if (appDetail?.mode === 'workflow') { | |||
| switch (locale) { | |||
| case LanguagesSupported[1]: | |||
| return <TemplateWorkflowZh appDetail={appDetail} variables={variables} inputs={inputs} /> | |||
| case LanguagesSupported[7]: | |||
| return <TemplateWorkflowJa appDetail={appDetail} variables={variables} inputs={inputs} /> | |||
| default: | |||
| return <TemplateWorkflowEn appDetail={appDetail} variables={variables} inputs={inputs} /> | |||
| } | |||
| } | |||
| if (appDetail?.mode === 'completion') { | |||
| switch (locale) { | |||
| case LanguagesSupported[1]: | |||
| return <TemplateZh appDetail={appDetail} variables={variables} inputs={inputs} /> | |||
| case LanguagesSupported[7]: | |||
| return <TemplateJa appDetail={appDetail} variables={variables} inputs={inputs} /> | |||
| default: | |||
| return <TemplateEn appDetail={appDetail} variables={variables} inputs={inputs} /> | |||
| } | |||
| } | |||
| return null | |||
| }, [appDetail, locale, variables, inputs]) | |||
| return ( | |||
| <div className="flex"> | |||
| <div className={`fixed right-8 top-32 z-10 transition-all ${isTocExpanded ? 'w-64' : 'w-10'}`}> | |||
| <div className={`fixed right-20 top-32 z-10 transition-all duration-150 ease-out ${isTocExpanded ? 'w-[280px]' : 'w-11'}`}> | |||
| {isTocExpanded | |||
| ? ( | |||
| <nav className="toc max-h-[calc(100vh-150px)] w-full overflow-y-auto rounded-lg border border-components-panel-border bg-components-panel-bg p-4 shadow-md"> | |||
| <div className="mb-4 flex items-center justify-between"> | |||
| <h3 className="text-lg font-semibold text-text-primary">{t('appApi.develop.toc')}</h3> | |||
| <nav className="toc flex max-h-[calc(100vh-150px)] w-full flex-col overflow-hidden rounded-xl border-[0.5px] border-components-panel-border bg-background-default-hover shadow-xl"> | |||
| <div className="relative z-10 flex items-center justify-between border-b border-components-panel-border-subtle bg-background-default-hover px-4 py-2.5"> | |||
| <span className="text-xs font-medium uppercase tracking-wide text-text-tertiary"> | |||
| {t('appApi.develop.toc')} | |||
| </span> | |||
| <button | |||
| onClick={() => setIsTocExpanded(false)} | |||
| className="text-text-tertiary hover:text-text-secondary" | |||
| className="group flex h-6 w-6 items-center justify-center rounded-md transition-colors hover:bg-state-base-hover" | |||
| aria-label="Close" | |||
| > | |||
| ✕ | |||
| <RiCloseLine className="h-3 w-3 text-text-quaternary transition-colors group-hover:text-text-secondary" /> | |||
| </button> | |||
| </div> | |||
| <ul className="space-y-2"> | |||
| {toc.map((item, index) => ( | |||
| <li key={index}> | |||
| <a | |||
| href={item.href} | |||
| className="text-text-secondary transition-colors duration-200 hover:text-text-primary hover:underline" | |||
| onClick={e => handleTocClick(e, item)} | |||
| > | |||
| {item.text} | |||
| </a> | |||
| </li> | |||
| ))} | |||
| </ul> | |||
| <div className="from-components-panel-border-subtle/20 pointer-events-none absolute left-0 right-0 top-[41px] z-10 h-2 bg-gradient-to-b to-transparent"></div> | |||
| <div className="pointer-events-none absolute left-0 right-0 top-[43px] z-10 h-3 bg-gradient-to-b from-background-default-hover to-transparent"></div> | |||
| <div className="relative flex-1 overflow-y-auto px-3 py-3 pt-1"> | |||
| {toc.length === 0 ? ( | |||
| <div className="px-2 py-8 text-center text-xs text-text-quaternary"> | |||
| {t('appApi.develop.noContent')} | |||
| </div> | |||
| ) : ( | |||
| <ul className="space-y-0.5"> | |||
| {toc.map((item, index) => { | |||
| const isActive = activeSection === item.href.replace('#', '') | |||
| return ( | |||
| <li key={index}> | |||
| <a | |||
| href={item.href} | |||
| onClick={e => handleTocClick(e, item)} | |||
| className={cn( | |||
| 'group relative flex items-center rounded-md px-3 py-2 text-[13px] transition-all duration-200', | |||
| isActive | |||
| ? 'bg-state-base-hover font-medium text-text-primary' | |||
| : 'text-text-tertiary hover:bg-state-base-hover hover:text-text-secondary', | |||
| )} | |||
| > | |||
| <span | |||
| className={cn( | |||
| 'mr-2 h-1.5 w-1.5 rounded-full transition-all duration-200', | |||
| isActive | |||
| ? 'scale-100 bg-text-accent' | |||
| : 'scale-75 bg-components-panel-border', | |||
| )} | |||
| /> | |||
| <span className="flex-1 truncate"> | |||
| {item.text} | |||
| </span> | |||
| </a> | |||
| </li> | |||
| ) | |||
| })} | |||
| </ul> | |||
| )} | |||
| </div> | |||
| <div className="pointer-events-none absolute bottom-0 left-0 right-0 z-10 h-4 rounded-b-xl bg-gradient-to-t from-background-default-hover to-transparent"></div> | |||
| </nav> | |||
| ) | |||
| : ( | |||
| <button | |||
| onClick={() => setIsTocExpanded(true)} | |||
| className="flex h-10 w-10 items-center justify-center rounded-full border border-components-panel-border bg-components-button-secondary-bg shadow-md transition-colors duration-200 hover:bg-components-button-secondary-bg-hover" | |||
| className="group flex h-11 w-11 items-center justify-center rounded-full border-[0.5px] border-components-panel-border bg-components-panel-bg shadow-lg transition-all duration-150 hover:bg-background-default-hover hover:shadow-xl" | |||
| aria-label="Open table of contents" | |||
| > | |||
| <RiListUnordered className="h-6 w-6 text-components-button-secondary-text" /> | |||
| <RiListUnordered className="h-5 w-5 text-text-tertiary transition-colors group-hover:text-text-secondary" /> | |||
| </button> | |||
| )} | |||
| </div> | |||
| <article className={cn('prose-xl prose', theme === Theme.dark && 'prose-invert')} > | |||
| {(appDetail?.mode === 'chat' || appDetail?.mode === 'agent-chat') && ( | |||
| (() => { | |||
| switch (locale) { | |||
| case LanguagesSupported[1]: | |||
| return <TemplateChatZh appDetail={appDetail} variables={variables} inputs={inputs} /> | |||
| case LanguagesSupported[7]: | |||
| return <TemplateChatJa appDetail={appDetail} variables={variables} inputs={inputs} /> | |||
| default: | |||
| return <TemplateChatEn appDetail={appDetail} variables={variables} inputs={inputs} /> | |||
| } | |||
| })() | |||
| )} | |||
| {appDetail?.mode === 'advanced-chat' && ( | |||
| (() => { | |||
| switch (locale) { | |||
| case LanguagesSupported[1]: | |||
| return <TemplateAdvancedChatZh appDetail={appDetail} variables={variables} inputs={inputs} /> | |||
| case LanguagesSupported[7]: | |||
| return <TemplateAdvancedChatJa appDetail={appDetail} variables={variables} inputs={inputs} /> | |||
| default: | |||
| return <TemplateAdvancedChatEn appDetail={appDetail} variables={variables} inputs={inputs} /> | |||
| } | |||
| })() | |||
| )} | |||
| {appDetail?.mode === 'workflow' && ( | |||
| (() => { | |||
| switch (locale) { | |||
| case LanguagesSupported[1]: | |||
| return <TemplateWorkflowZh appDetail={appDetail} variables={variables} inputs={inputs} /> | |||
| case LanguagesSupported[7]: | |||
| return <TemplateWorkflowJa appDetail={appDetail} variables={variables} inputs={inputs} /> | |||
| default: | |||
| return <TemplateWorkflowEn appDetail={appDetail} variables={variables} inputs={inputs} /> | |||
| } | |||
| })() | |||
| )} | |||
| {appDetail?.mode === 'completion' && ( | |||
| (() => { | |||
| switch (locale) { | |||
| case LanguagesSupported[1]: | |||
| return <TemplateZh appDetail={appDetail} variables={variables} inputs={inputs} /> | |||
| case LanguagesSupported[7]: | |||
| return <TemplateJa appDetail={appDetail} variables={variables} inputs={inputs} /> | |||
| default: | |||
| return <TemplateEn appDetail={appDetail} variables={variables} inputs={inputs} /> | |||
| } | |||
| })() | |||
| )} | |||
| <article className={cn('prose-xl prose', theme === Theme.dark && 'prose-invert')}> | |||
| {Template} | |||
| </article> | |||
| </div> | |||
| ) | |||
| @@ -448,7 +448,7 @@ import { Row, Col, Properties, Property, Heading, SubProperty, Paragraph } from | |||
| url='/text-to-audio' | |||
| method='POST' | |||
| title='テキストから音声' | |||
| name='#audio' | |||
| name='#text-to-audio' | |||
| /> | |||
| <Row> | |||
| <Col> | |||
| @@ -423,7 +423,7 @@ import { Row, Col, Properties, Property, Heading, SubProperty } from '../md.tsx' | |||
| url='/text-to-audio' | |||
| method='POST' | |||
| title='文字转语音' | |||
| name='#audio' | |||
| name='#text-to-audio' | |||
| /> | |||
| <Row> | |||
| <Col> | |||
| @@ -1136,7 +1136,7 @@ Chat applications support session persistence, allowing previous chat history to | |||
| url='/audio-to-text' | |||
| method='POST' | |||
| title='Speech to Text' | |||
| name='#audio' | |||
| name='#audio-to-text' | |||
| /> | |||
| <Row> | |||
| <Col> | |||
| @@ -1187,7 +1187,7 @@ Chat applications support session persistence, allowing previous chat history to | |||
| url='/text-to-audio' | |||
| method='POST' | |||
| title='Text to Audio' | |||
| name='#audio' | |||
| name='#text-to-audio' | |||
| /> | |||
| <Row> | |||
| <Col> | |||
| @@ -1136,7 +1136,7 @@ import { Row, Col, Properties, Property, Heading, SubProperty, Paragraph } from | |||
| url='/audio-to-text' | |||
| method='POST' | |||
| title='音声からテキストへ' | |||
| name='#audio' | |||
| name='#audio-to-text' | |||
| /> | |||
| <Row> | |||
| <Col> | |||
| @@ -1187,7 +1187,7 @@ import { Row, Col, Properties, Property, Heading, SubProperty, Paragraph } from | |||
| url='/text-to-audio' | |||
| method='POST' | |||
| title='テキストから音声へ' | |||
| name='#audio' | |||
| name='#text-to-audio' | |||
| /> | |||
| <Row> | |||
| <Col> | |||
| @@ -1174,7 +1174,7 @@ import { Row, Col, Properties, Property, Heading, SubProperty } from '../md.tsx' | |||
| url='/audio-to-text' | |||
| method='POST' | |||
| title='语音转文字' | |||
| name='#audio' | |||
| name='#audio-to-text' | |||
| /> | |||
| <Row> | |||
| <Col> | |||
| @@ -1222,7 +1222,7 @@ import { Row, Col, Properties, Property, Heading, SubProperty } from '../md.tsx' | |||
| url='/text-to-audio' | |||
| method='POST' | |||
| title='文字转语音' | |||
| name='#audio' | |||
| name='#text-to-audio' | |||
| /> | |||
| <Row> | |||
| <Col> | |||
| @@ -1170,7 +1170,7 @@ Chat applications support session persistence, allowing previous chat history to | |||
| url='/audio-to-text' | |||
| method='POST' | |||
| title='Speech to Text' | |||
| name='#audio' | |||
| name='#audio-to-text' | |||
| /> | |||
| <Row> | |||
| <Col> | |||
| @@ -1221,7 +1221,7 @@ Chat applications support session persistence, allowing previous chat history to | |||
| url='/text-to-audio' | |||
| method='POST' | |||
| title='Text to Audio' | |||
| name='#audio' | |||
| name='#text-to-audio' | |||
| /> | |||
| <Row> | |||
| <Col> | |||
| @@ -1169,7 +1169,7 @@ import { Row, Col, Properties, Property, Heading, SubProperty, Paragraph } from | |||
| url='/audio-to-text' | |||
| method='POST' | |||
| title='音声からテキストへ' | |||
| name='#audio' | |||
| name='#audio-to-text' | |||
| /> | |||
| <Row> | |||
| <Col> | |||
| @@ -1220,7 +1220,7 @@ import { Row, Col, Properties, Property, Heading, SubProperty, Paragraph } from | |||
| url='/text-to-audio' | |||
| method='POST' | |||
| title='テキストから音声へ' | |||
| name='#audio' | |||
| name='#text-to-audio' | |||
| /> | |||
| <Row> | |||
| <Col> | |||
| @@ -1185,7 +1185,7 @@ import { Row, Col, Properties, Property, Heading, SubProperty } from '../md.tsx' | |||
| url='/audio-to-text' | |||
| method='POST' | |||
| title='语音转文字' | |||
| name='#audio' | |||
| name='#audio-to-text' | |||
| /> | |||
| <Row> | |||
| <Col> | |||
| @@ -1233,7 +1233,7 @@ import { Row, Col, Properties, Property, Heading, SubProperty } from '../md.tsx' | |||
| url='/text-to-audio' | |||
| method='POST' | |||
| title='文字转语音' | |||
| name='#audio' | |||
| name='#text-to-audio' | |||
| /> | |||
| <Row> | |||
| <Col> | |||
| @@ -287,6 +287,18 @@ const translation = { | |||
| zoomTo50: 'Auf 50% vergrößern', | |||
| zoomTo100: 'Auf 100% vergrößern', | |||
| zoomToFit: 'An Bildschirm anpassen', | |||
| selectionAlignment: 'Ausrichtung der Auswahl', | |||
| alignLeft: 'Links', | |||
| alignTop: 'Nach oben', | |||
| distributeVertical: 'Vertikaler Raum', | |||
| alignBottom: 'Unteres', | |||
| distributeHorizontal: 'Horizontaler Raum', | |||
| vertical: 'Senkrecht', | |||
| alignMiddle: 'Mitte', | |||
| alignCenter: 'Mitte', | |||
| alignRight: 'Rechts', | |||
| alignNodes: 'Knoten ausrichten', | |||
| horizontal: 'Horizontal', | |||
| }, | |||
| panel: { | |||
| userInputField: 'Benutzereingabefeld', | |||
| @@ -287,6 +287,18 @@ const translation = { | |||
| zoomTo50: 'Zoom al 50%', | |||
| zoomTo100: 'Zoom al 100%', | |||
| zoomToFit: 'Ajustar al tamaño', | |||
| alignTop: 'Arriba', | |||
| alignBottom: 'Fondo', | |||
| alignNodes: 'Alinear nodos', | |||
| alignCenter: 'Centro', | |||
| selectionAlignment: 'Alineación de selección', | |||
| horizontal: 'Horizontal', | |||
| distributeHorizontal: 'Espaciar horizontalmente', | |||
| vertical: 'Vertical', | |||
| distributeVertical: 'Espaciar verticalmente', | |||
| alignMiddle: 'medio', | |||
| alignLeft: 'izquierdo', | |||
| alignRight: 'derecho', | |||
| }, | |||
| panel: { | |||
| userInputField: 'Campo de entrada del usuario', | |||
| @@ -287,6 +287,18 @@ const translation = { | |||
| zoomTo50: 'بزرگنمایی به 50%', | |||
| zoomTo100: 'بزرگنمایی به 100%', | |||
| zoomToFit: 'تناسب با اندازه', | |||
| horizontal: 'افقی', | |||
| alignBottom: 'پایین', | |||
| alignRight: 'راست', | |||
| vertical: 'عمودی', | |||
| alignCenter: 'مرکز', | |||
| alignLeft: 'چپ', | |||
| distributeVertical: 'فضا عمودی', | |||
| distributeHorizontal: 'فضا به صورت افقی', | |||
| alignTop: 'بالا', | |||
| alignNodes: 'تراز کردن گره ها', | |||
| selectionAlignment: 'تراز انتخاب', | |||
| alignMiddle: 'میانه', | |||
| }, | |||
| panel: { | |||
| userInputField: 'فیلد ورودی کاربر', | |||
| @@ -287,6 +287,18 @@ const translation = { | |||
| zoomTo50: 'Zoomer à 50%', | |||
| zoomTo100: 'Zoomer à 100%', | |||
| zoomToFit: 'Zoomer pour ajuster', | |||
| alignBottom: 'Fond', | |||
| alignLeft: 'Gauche', | |||
| alignCenter: 'Centre', | |||
| alignTop: 'Retour au début', | |||
| alignNodes: 'Aligner les nœuds', | |||
| distributeHorizontal: 'Espace horizontal', | |||
| alignMiddle: 'Milieu', | |||
| horizontal: 'Horizontal', | |||
| selectionAlignment: 'Alignement de la sélection', | |||
| alignRight: 'Droite', | |||
| vertical: 'Vertical', | |||
| distributeVertical: 'Espace vertical', | |||
| }, | |||
| panel: { | |||
| userInputField: 'Champ de saisie de l\'utilisateur', | |||
| @@ -298,6 +298,18 @@ const translation = { | |||
| zoomTo50: '50% पर ज़ूम करें', | |||
| zoomTo100: '100% पर ज़ूम करें', | |||
| zoomToFit: 'फिट करने के लिए ज़ूम करें', | |||
| alignRight: 'सही', | |||
| alignLeft: 'बाईं ओर', | |||
| alignTop: 'शीर्ष', | |||
| horizontal: 'क्षैतिज', | |||
| alignNodes: 'नोड्स को संरेखित करें', | |||
| selectionAlignment: 'चयन संरेखण', | |||
| alignCenter: 'केंद्र', | |||
| vertical: 'ऊर्ध्वाधर', | |||
| distributeHorizontal: 'क्षैतिज स्पेस', | |||
| alignBottom: 'तल', | |||
| distributeVertical: 'अंतरिक्ष को वर्टिकल रूप से', | |||
| alignMiddle: 'मध्य', | |||
| }, | |||
| panel: { | |||
| userInputField: 'उपयोगकर्ता इनपुट फ़ील्ड', | |||
| @@ -301,6 +301,18 @@ const translation = { | |||
| zoomTo50: 'Zoom al 50%', | |||
| zoomTo100: 'Zoom al 100%', | |||
| zoomToFit: 'Zoom per Adattare', | |||
| alignRight: 'A destra', | |||
| selectionAlignment: 'Allineamento della selezione', | |||
| alignBottom: 'Fondoschiena', | |||
| alignTop: 'In alto', | |||
| vertical: 'Verticale', | |||
| alignCenter: 'Centro', | |||
| alignLeft: 'A sinistra', | |||
| alignMiddle: 'Mezzo', | |||
| horizontal: 'Orizzontale', | |||
| alignNodes: 'Allinea nodi', | |||
| distributeHorizontal: 'Spazia orizzontalmente', | |||
| distributeVertical: 'Spazia verticalmente', | |||
| }, | |||
| panel: { | |||
| userInputField: 'Campo di Input Utente', | |||
| @@ -287,6 +287,18 @@ const translation = { | |||
| zoomTo50: '50% サイズ', | |||
| zoomTo100: '等倍表示', | |||
| zoomToFit: '画面に合わせる', | |||
| horizontal: '横', | |||
| alignBottom: '底', | |||
| alignNodes: 'ノードを整列させる', | |||
| vertical: '垂直', | |||
| alignLeft: '左', | |||
| alignTop: 'トップ', | |||
| alignRight: '右', | |||
| alignMiddle: '中間', | |||
| distributeVertical: '垂直にスペースを', | |||
| alignCenter: 'センター', | |||
| selectionAlignment: '選択の整列', | |||
| distributeHorizontal: '空間を水平方向に', | |||
| }, | |||
| variableReference: { | |||
| noAvailableVars: '利用可能な変数がありません', | |||
| @@ -308,6 +308,18 @@ const translation = { | |||
| zoomTo50: '50% 로 확대', | |||
| zoomTo100: '100% 로 확대', | |||
| zoomToFit: '화면에 맞게 확대', | |||
| alignCenter: '중', | |||
| alignRight: '오른쪽', | |||
| alignLeft: '왼쪽', | |||
| vertical: '세로', | |||
| alignTop: '맨 위로', | |||
| alignMiddle: '중간', | |||
| alignNodes: '노드 정렬', | |||
| distributeVertical: '수직 공간', | |||
| horizontal: '가로', | |||
| selectionAlignment: '선택 정렬', | |||
| alignBottom: '밑바닥', | |||
| distributeHorizontal: '수평 공간', | |||
| }, | |||
| panel: { | |||
| userInputField: '사용자 입력 필드', | |||
| @@ -287,6 +287,18 @@ const translation = { | |||
| zoomTo50: 'Powiększ do 50%', | |||
| zoomTo100: 'Powiększ do 100%', | |||
| zoomToFit: 'Dopasuj do ekranu', | |||
| alignMiddle: 'Środek', | |||
| alignTop: 'Do góry', | |||
| distributeHorizontal: 'Odstęp w poziomie', | |||
| alignCenter: 'Centrum', | |||
| alignRight: 'Prawy', | |||
| alignNodes: 'Wyrównywanie węzłów', | |||
| selectionAlignment: 'Wyrównanie zaznaczenia', | |||
| horizontal: 'Poziomy', | |||
| distributeVertical: 'Przestrzeń w pionie', | |||
| alignBottom: 'Dno', | |||
| alignLeft: 'Lewy', | |||
| vertical: 'Pionowy', | |||
| }, | |||
| panel: { | |||
| userInputField: 'Pole wprowadzania użytkownika', | |||
| @@ -287,6 +287,18 @@ const translation = { | |||
| zoomTo50: 'Aproximar para 50%', | |||
| zoomTo100: 'Aproximar para 100%', | |||
| zoomToFit: 'Aproximar para ajustar', | |||
| vertical: 'Vertical', | |||
| alignNodes: 'Alinhar nós', | |||
| selectionAlignment: 'Alinhamento de seleção', | |||
| alignLeft: 'Esquerda', | |||
| alignBottom: 'Fundo', | |||
| distributeHorizontal: 'Espaço horizontalmente', | |||
| alignMiddle: 'Meio', | |||
| alignRight: 'Certo', | |||
| horizontal: 'Horizontal', | |||
| distributeVertical: 'Espaço Verticalmente', | |||
| alignCenter: 'Centro', | |||
| alignTop: 'Início', | |||
| }, | |||
| panel: { | |||
| userInputField: 'Campo de entrada do usuário', | |||
| @@ -287,6 +287,18 @@ const translation = { | |||
| zoomTo50: 'Mărește la 50%', | |||
| zoomTo100: 'Mărește la 100%', | |||
| zoomToFit: 'Mărește pentru a se potrivi', | |||
| horizontal: 'Orizontal', | |||
| selectionAlignment: 'Alinierea selecției', | |||
| vertical: 'Vertical', | |||
| alignRight: 'Dreapta', | |||
| alignLeft: 'Stânga', | |||
| alignMiddle: 'Mijloc', | |||
| distributeVertical: 'Spațiu vertical', | |||
| alignCenter: 'Centru', | |||
| distributeHorizontal: 'Spațiu orizontal', | |||
| alignBottom: 'Fund', | |||
| alignTop: 'Culme', | |||
| alignNodes: 'Alinierea nodurilor', | |||
| }, | |||
| panel: { | |||
| userInputField: 'Câmp de introducere utilizator', | |||
| @@ -287,6 +287,18 @@ const translation = { | |||
| zoomTo50: 'Масштаб 50%', | |||
| zoomTo100: 'Масштаб 100%', | |||
| zoomToFit: 'По размеру', | |||
| alignTop: 'Вверх', | |||
| alignBottom: 'Дно', | |||
| alignRight: 'Правильно', | |||
| distributeHorizontal: 'Пространство по горизонтали', | |||
| alignMiddle: 'Середина', | |||
| vertical: 'Вертикальный', | |||
| alignCenter: 'Центр', | |||
| alignLeft: 'Налево', | |||
| selectionAlignment: 'Выравнивание выделения', | |||
| horizontal: 'Горизонтальный', | |||
| alignNodes: 'Выравнивание узлов', | |||
| distributeVertical: 'Пространство по вертикали', | |||
| }, | |||
| panel: { | |||
| userInputField: 'Поле ввода пользователя', | |||
| @@ -287,6 +287,18 @@ const translation = { | |||
| zoomIn: 'Zoom in', | |||
| zoomTo50: 'Povečaj na 50%', | |||
| zoomTo100: 'Povečaj na 100%', | |||
| alignMiddle: 'Srednji', | |||
| alignBottom: 'Dno', | |||
| alignCenter: 'Center', | |||
| distributeVertical: 'Razmik navpično', | |||
| alignRight: 'Desno', | |||
| alignTop: 'Vrh', | |||
| vertical: 'Navpičen', | |||
| distributeHorizontal: 'Razmik vodoravno', | |||
| selectionAlignment: 'Poravnava izbora', | |||
| alignNodes: 'Poravnava vozlišč', | |||
| horizontal: 'Vodoraven', | |||
| alignLeft: 'Levo', | |||
| }, | |||
| variableReference: { | |||
| conversationVars: 'pogovorne spremenljivke', | |||
| @@ -287,6 +287,18 @@ const translation = { | |||
| zoomTo50: 'ซูมไปที่ 50%', | |||
| zoomTo100: 'ซูมไปที่ 100%', | |||
| zoomToFit: 'ซูมให้พอดี', | |||
| alignBottom: 'ก้น', | |||
| alignCenter: 'ศูนย์กลาง', | |||
| alignMiddle: 'กลาง', | |||
| horizontal: 'แนวราบ', | |||
| vertical: 'ซึ่งตั้งตรง', | |||
| alignTop: 'ด้านบน', | |||
| distributeVertical: 'พื้นที่ในแนวตั้ง', | |||
| alignLeft: 'ซ้าย', | |||
| selectionAlignment: 'การจัดตําแหน่งการเลือก', | |||
| distributeHorizontal: 'ช่องว่างในแนวนอน', | |||
| alignRight: 'ขวา', | |||
| alignNodes: 'จัดตําแหน่งโหนด', | |||
| }, | |||
| panel: { | |||
| userInputField: 'ฟิลด์ป้อนข้อมูลของผู้ใช้', | |||
| @@ -287,6 +287,18 @@ const translation = { | |||
| zoomTo50: '%50 Yakınlaştır', | |||
| zoomTo100: '%100 Yakınlaştır', | |||
| zoomToFit: 'Sığdıracak Şekilde Yakınlaştır', | |||
| alignCenter: 'Orta', | |||
| alignMiddle: 'Orta', | |||
| alignLeft: 'Sol', | |||
| alignNodes: 'Düğümleri Hizala', | |||
| vertical: 'Dikey', | |||
| alignRight: 'Sağ', | |||
| alignTop: 'Sayfanın Üstü', | |||
| alignBottom: 'Dip', | |||
| selectionAlignment: 'Seçim Hizalama', | |||
| distributeHorizontal: 'Yatay Boşluk', | |||
| horizontal: 'Yatay', | |||
| distributeVertical: 'Dikey Boşluk', | |||
| }, | |||
| panel: { | |||
| userInputField: 'Kullanıcı Giriş Alanı', | |||
| @@ -287,6 +287,18 @@ const translation = { | |||
| zoomTo50: 'Збільшити до 50%', | |||
| zoomTo100: 'Збільшити до 100%', | |||
| zoomToFit: 'Збільшити для підгонки', | |||
| alignCenter: 'Центр', | |||
| alignRight: 'Праворуч', | |||
| vertical: 'Вертикальні', | |||
| alignBottom: 'Низ', | |||
| alignLeft: 'Ліворуч', | |||
| alignTop: 'Верх', | |||
| horizontal: 'Горизонтальні', | |||
| alignMiddle: 'Середній', | |||
| distributeVertical: 'Простір по вертикалі', | |||
| distributeHorizontal: 'Простір по горизонталі', | |||
| selectionAlignment: 'Вирівнювання вибору', | |||
| alignNodes: 'Вирівнювання вузлів', | |||
| }, | |||
| panel: { | |||
| userInputField: 'Поле введення користувача', | |||
| @@ -287,6 +287,18 @@ const translation = { | |||
| zoomTo50: 'Phóng to 50%', | |||
| zoomTo100: 'Phóng to 100%', | |||
| zoomToFit: 'Phóng to vừa màn hình', | |||
| alignBottom: 'Đáy', | |||
| alignMiddle: 'Trung', | |||
| alignRight: 'Bên phải', | |||
| alignNodes: 'Căn chỉnh các nút', | |||
| alignLeft: 'Bên trái', | |||
| horizontal: 'Ngang', | |||
| alignCenter: 'Trung tâm', | |||
| alignTop: 'Đỉnh', | |||
| distributeVertical: 'Không gian theo chiều dọc', | |||
| selectionAlignment: 'Căn chỉnh lựa chọn', | |||
| distributeHorizontal: 'Không gian theo chiều ngang', | |||
| vertical: 'Thẳng đứng', | |||
| }, | |||
| panel: { | |||
| userInputField: 'Trường đầu vào của người dùng', | |||
| @@ -287,6 +287,18 @@ const translation = { | |||
| zoomTo50: '縮放到 50%', | |||
| zoomTo100: '放大到 100%', | |||
| zoomToFit: '自適應視圖', | |||
| alignNodes: '對齊節點(Align Nodes)', | |||
| distributeVertical: '垂直空間', | |||
| alignLeft: '左', | |||
| distributeHorizontal: '水平空間', | |||
| vertical: '垂直', | |||
| alignTop: '返回頁首', | |||
| alignCenter: '中心', | |||
| horizontal: '水準', | |||
| selectionAlignment: '選擇對齊', | |||
| alignRight: '右', | |||
| alignBottom: '底', | |||
| alignMiddle: '中間', | |||
| }, | |||
| panel: { | |||
| userInputField: '用戶輸入字段', | |||