diff --git a/packages/console/src/components/ListPage/index.tsx b/packages/console/src/components/ListPage/index.tsx index 20ae8674f..a363714e7 100644 --- a/packages/console/src/components/ListPage/index.tsx +++ b/packages/console/src/components/ListPage/index.tsx @@ -26,7 +26,7 @@ type Props< subHeader?: ReactNode; table: TableProps; /** @deprecated Need refactor. */ - widgets: ReactNode; + widgets?: ReactNode; className?: string; }; diff --git a/packages/console/src/containers/ConsoleContent/index.tsx b/packages/console/src/containers/ConsoleContent/index.tsx index f6c1ef9f9..9bf603381 100644 --- a/packages/console/src/containers/ConsoleContent/index.tsx +++ b/packages/console/src/containers/ConsoleContent/index.tsx @@ -70,7 +70,7 @@ function ConsoleContent() { } /> } /> - } /> + } /> } /> diff --git a/packages/console/src/ds-components/Checkbox/CheckboxGroup/index.module.scss b/packages/console/src/ds-components/Checkbox/CheckboxGroup/index.module.scss index b3985b56e..8f0bb1adc 100644 --- a/packages/console/src/ds-components/Checkbox/CheckboxGroup/index.module.scss +++ b/packages/console/src/ds-components/Checkbox/CheckboxGroup/index.module.scss @@ -1,7 +1,7 @@ @use '@/scss/underscore' as _; .group { - > div:not(:last-child) { - margin-bottom: _.unit(3); - } + display: flex; + flex-direction: column; + gap: _.unit(3); } diff --git a/packages/console/src/pages/ApplicationDetails/index.tsx b/packages/console/src/pages/ApplicationDetails/index.tsx index 619cabac8..fc986e789 100644 --- a/packages/console/src/pages/ApplicationDetails/index.tsx +++ b/packages/console/src/pages/ApplicationDetails/index.tsx @@ -50,9 +50,9 @@ const mapToUriOriginFormatArrays = (value?: string[]) => value?.filter(Boolean).map((uri) => decodeURIComponent(uri.replace(/\/*$/, ''))); function ApplicationDetails() { - const { id } = useParams(); + const { id, guideId } = useParams(); const { navigate, match } = useTenantPathname(); - const isGuideView = id && match(`/applications/${id}/guide`); + const isGuideView = id && guideId && match(`/applications/${id}/guide/${guideId}`); const { t } = useTranslation(undefined, { keyPrefix: 'admin_console' }); const { data, error, mutate } = useSWR( @@ -243,6 +243,7 @@ function ApplicationDetails() { {isGuideView && ( { navigate(`/applications/${id}`); diff --git a/packages/console/src/pages/Applications/components/ApplicationsPlaceholder/index.module.scss b/packages/console/src/pages/Applications/components/ApplicationsPlaceholder/index.module.scss deleted file mode 100644 index f97b6274e..000000000 --- a/packages/console/src/pages/Applications/components/ApplicationsPlaceholder/index.module.scss +++ /dev/null @@ -1,42 +0,0 @@ -@use '@/scss/underscore' as _; - -.placeholder { - display: flex; - flex-direction: column; - align-items: center; - padding-bottom: _.unit(5); - - .title { - font: var(--font-title-1); - } - - .description { - font: var(--font-body-2); - color: var(--color-text-secondary); - margin-top: _.unit(1); - text-align: center; - max-width: 600px; - } - - .options { - margin-top: _.unit(6); - display: flex; - justify-content: space-between; - align-items: stretch; - max-width: 736px; - gap: _.unit(4); - - .option { - flex: 1; - display: flex; - flex-direction: column; - border: 1px solid var(--color-divider); - border-radius: 12px; - padding: _.unit(3); - - .createButton { - margin-top: _.unit(2.5); - } - } - } -} diff --git a/packages/console/src/pages/Applications/components/ApplicationsPlaceholder/index.tsx b/packages/console/src/pages/Applications/components/ApplicationsPlaceholder/index.tsx deleted file mode 100644 index c46f5802f..000000000 --- a/packages/console/src/pages/Applications/components/ApplicationsPlaceholder/index.tsx +++ /dev/null @@ -1,53 +0,0 @@ -import { ApplicationType } from '@logto/schemas'; -import { useContext } from 'react'; -import { useTranslation } from 'react-i18next'; - -import { TenantsContext } from '@/contexts/TenantsProvider'; -import Button from '@/ds-components/Button'; -import useSubscriptionPlan from '@/hooks/use-subscription-plan'; -import { applicationTypeI18nKey } from '@/types/applications'; - -import TypeDescription from '../TypeDescription'; - -import * as styles from './index.module.scss'; - -type Props = { - onSelect: (type: ApplicationType) => void; -}; - -function ApplicationsPlaceholder({ onSelect }: Props) { - const { t } = useTranslation(undefined, { keyPrefix: 'admin_console' }); - const { currentTenantId } = useContext(TenantsContext); - const { data: currentPlan } = useSubscriptionPlan(currentTenantId); - const isMachineToMachineDisabled = !currentPlan?.quota.machineToMachineLimit; - - return ( -
-
{t('applications.placeholder_title')}
-
{t('applications.placeholder_description')}
-
- {Object.values(ApplicationType).map((type) => ( -
- -
- ))} -
-
- ); -} - -export default ApplicationsPlaceholder; diff --git a/packages/console/src/pages/Applications/components/CreateForm/index.tsx b/packages/console/src/pages/Applications/components/CreateForm/index.tsx index c3bd97a98..3eab8b4dc 100644 --- a/packages/console/src/pages/Applications/components/CreateForm/index.tsx +++ b/packages/console/src/pages/Applications/components/CreateForm/index.tsx @@ -1,7 +1,7 @@ import type { Application } from '@logto/schemas'; import { ApplicationType } from '@logto/schemas'; import { conditional } from '@silverhand/essentials'; -import { useContext, useEffect } from 'react'; +import { useContext } from 'react'; import { useController, useForm } from 'react-hook-form'; import { useTranslation } from 'react-i18next'; import Modal from 'react-modal'; @@ -30,12 +30,11 @@ type FormData = { }; type Props = { - isOpen: boolean; defaultCreateType?: ApplicationType; onClose?: (createdApp?: Application) => void; }; -function CreateForm({ isOpen, defaultCreateType, onClose }: Props) { +function CreateForm({ defaultCreateType, onClose }: Props) { const { currentTenantId } = useContext(TenantsContext); const { data: currentPlan } = useSubscriptionPlan(currentTenantId); const isMachineToMachineDisabled = !currentPlan?.quota.machineToMachineLimit; @@ -44,7 +43,6 @@ function CreateForm({ isOpen, defaultCreateType, onClose }: Props) { handleSubmit, control, register, - resetField, formState: { errors, isSubmitting }, } = useForm(); @@ -56,19 +54,9 @@ function CreateForm({ isOpen, defaultCreateType, onClose }: Props) { rules: { required: true }, }); - useEffect(() => { - if (defaultCreateType) { - resetField('type', { defaultValue: defaultCreateType }); - } - }, [defaultCreateType, resetField]); - const { t } = useTranslation(undefined, { keyPrefix: 'admin_console' }); const api = useApi(); - if (!isOpen) { - return null; - } - const onSubmit = handleSubmit( trySubmitSafe(async (data) => { if (isSubmitting) { @@ -89,7 +77,7 @@ function CreateForm({ isOpen, defaultCreateType, onClose }: Props) { return ( { @@ -104,37 +92,40 @@ function CreateForm({ isOpen, defaultCreateType, onClose }: Props) { onClose={onClose} >
- - - {Object.values(ApplicationType).map((type) => ( - - - - ))} - - {errors.type?.type === 'required' && ( -
{t('applications.no_application_type_selected')}
- )} -
+ {defaultCreateType && } + {!defaultCreateType && ( + + + {Object.values(ApplicationType).map((type) => ( + + + + ))} + + {errors.type?.type === 'required' && ( +
{t('applications.no_application_type_selected')}
+ )} +
+ )} void; }; -function GuideModal({ app, onClose }: Props) { +function GuideModal({ guideId, app, onClose }: Props) { if (!app) { return null; } @@ -33,7 +34,7 @@ function GuideModal({ app, onClose }: Props) { {isProduction ? ( ) : ( - + )} ); diff --git a/packages/console/src/pages/Applications/components/Guide/index.tsx b/packages/console/src/pages/Applications/components/Guide/index.tsx index 8509a32b7..04981977f 100644 --- a/packages/console/src/pages/Applications/components/Guide/index.tsx +++ b/packages/console/src/pages/Applications/components/Guide/index.tsx @@ -27,6 +27,7 @@ type Props = { onClose: () => void; }; +/** @deprecated */ const Guides: Record JSX.Element>> = { ios: lazy(async () => import('@/assets/docs/tutorial/integrate-sdk/ios.mdx')), android: lazy(async () => import('@/assets/docs/tutorial/integrate-sdk/android.mdx')), @@ -77,12 +78,7 @@ function Guide({ app, isCompact, onClose }: Props) { return (
- +
{cloneElement(, { className: styles.banner, diff --git a/packages/console/src/pages/Applications/components/GuideCard/index.module.scss b/packages/console/src/pages/Applications/components/GuideCard/index.module.scss new file mode 100644 index 000000000..bc8355ff3 --- /dev/null +++ b/packages/console/src/pages/Applications/components/GuideCard/index.module.scss @@ -0,0 +1,54 @@ +@use '@/scss/underscore' as _; + +.card { + display: flex; + flex-direction: column; + gap: _.unit(2); + background-color: var(--color-layer-1); + border: 1px solid transparent; + border-radius: 12px; + padding: _.unit(3); + min-width: 220px; + max-width: 460px; + justify-content: space-between; + + &.hasBorder { + border-color: var(--color-divider); + } + + .header { + display: flex; + align-items: flex-start; + gap: _.unit(2); + } + + .logo { + width: 48px; + height: 48px; + flex-shrink: 0; + } + + .infoWrapper { + display: flex; + flex-direction: column; + gap: _.unit(1); + } + + .name { + font: var(--font-label-2); + color: var(--color-text); + } + + .description { + font: var(--font-body-3); + color: var(--color-text-secondary); + } +} + +.logoSkeleton { + width: 48px; + height: 48px; + flex-shrink: 0; + border-radius: 12px; + @include _.shimmering-animation; +} diff --git a/packages/console/src/pages/Applications/components/GuideCard/index.tsx b/packages/console/src/pages/Applications/components/GuideCard/index.tsx new file mode 100644 index 000000000..e9dda6529 --- /dev/null +++ b/packages/console/src/pages/Applications/components/GuideCard/index.tsx @@ -0,0 +1,53 @@ +import classNames from 'classnames'; +import { Suspense } from 'react'; + +import { type Guide, type GuideMetadata } from '@/assets/docs/guides/types'; +import Button from '@/ds-components/Button'; + +import * as styles from './index.module.scss'; + +export type SelectedGuide = { + target: GuideMetadata['target']; + id: Guide['id']; +}; + +type Props = { + data: Guide; + onClick: (data: SelectedGuide) => void; + hasBorder?: boolean; +}; + +function LogoSkeleton() { + return
; +} + +function GuideCard({ data, onClick, hasBorder }: Props) { + const { + id, + Logo, + metadata: { target, name, description }, + } = data; + + return ( +
+
+ }> + + +
+
{name}
+
{description}
+
+
+
+ ); +} + +export default GuideCard; diff --git a/packages/console/src/pages/Applications/components/GuideHeaderV2/RequestGuide.tsx b/packages/console/src/pages/Applications/components/GuideHeader/RequestGuide.tsx similarity index 100% rename from packages/console/src/pages/Applications/components/GuideHeaderV2/RequestGuide.tsx rename to packages/console/src/pages/Applications/components/GuideHeader/RequestGuide.tsx diff --git a/packages/console/src/pages/Applications/components/GuideHeader/index.module.scss b/packages/console/src/pages/Applications/components/GuideHeader/index.module.scss index 449b08294..527eda8f6 100644 --- a/packages/console/src/pages/Applications/components/GuideHeader/index.module.scss +++ b/packages/console/src/pages/Applications/components/GuideHeader/index.module.scss @@ -3,9 +3,10 @@ .header { display: flex; align-items: center; - background-color: var(--color-layer-1); + background-color: var(--color-base); height: 64px; padding: 0 _.unit(6); + flex-shrink: 0; .separator { @include _.vertical-bar; @@ -31,7 +32,7 @@ } } - .getSampleButton { - margin: 0 _.unit(15) 0 _.unit(6); + .requestSdkButton { + margin-right: _.unit(2); } } diff --git a/packages/console/src/pages/Applications/components/GuideHeader/index.tsx b/packages/console/src/pages/Applications/components/GuideHeader/index.tsx index 543d61347..3ba4fbdd7 100644 --- a/packages/console/src/pages/Applications/components/GuideHeader/index.tsx +++ b/packages/console/src/pages/Applications/components/GuideHeader/index.tsx @@ -1,73 +1,31 @@ +import { useCallback, useState } from 'react'; import { useTranslation } from 'react-i18next'; +import Box from '@/assets/icons/box.svg'; import Close from '@/assets/icons/close.svg'; -import GetSample from '@/assets/icons/get-sample.svg'; +import { githubIssuesLink } from '@/consts'; +import { isCloud } from '@/consts/env'; import Button from '@/ds-components/Button'; import CardTitle from '@/ds-components/CardTitle'; -import DangerousRaw from '@/ds-components/DangerousRaw'; import IconButton from '@/ds-components/IconButton'; import Spacer from '@/ds-components/Spacer'; import Tooltip from '@/ds-components/Tip/Tooltip'; -import { SupportedSdk } from '@/types/applications'; +import RequestGuide from './RequestGuide'; import * as styles from './index.module.scss'; type Props = { - appName: string; - selectedSdk: SupportedSdk; isCompact?: boolean; onClose: () => void; }; -const getSampleProjectUrl = (sdk: SupportedSdk) => { - const githubUrlPrefix = 'https://github.com/logto-io'; - - switch (sdk) { - case SupportedSdk.iOS: { - return `${githubUrlPrefix}/swift/tree/master/Demos/SwiftUI%20Demo`; - } - - case SupportedSdk.Android: { - return `${githubUrlPrefix}/kotlin/tree/master/android-sample-kotlin`; - } - - case SupportedSdk.React: { - return `${githubUrlPrefix}/js/tree/master/packages/react-sample`; - } - - case SupportedSdk.Vue: { - return `${githubUrlPrefix}/js/tree/master/packages/vue-sample`; - } - - case SupportedSdk.Vanilla: { - return `${githubUrlPrefix}/js/tree/master/packages/browser-sample`; - } - - case SupportedSdk.Next: { - return `${githubUrlPrefix}/js/tree/master/packages/next-sample`; - } - - case SupportedSdk.Express: { - return `${githubUrlPrefix}/js/tree/master/packages/express-sample`; - } - - case SupportedSdk.Go: { - return `${githubUrlPrefix}/go/tree/master/gin-sample`; - } - - default: { - return ''; - } - } -}; - -function GuideHeader({ appName, selectedSdk, isCompact = false, onClose }: Props) { +function GuideHeader({ isCompact = false, onClose }: Props) { const { t } = useTranslation(undefined, { keyPrefix: 'admin_console' }); - const onClickGetSample = () => { - const sampleUrl = getSampleProjectUrl(selectedSdk); - window.open(sampleUrl, '_blank'); - }; + const [isRequestGuideOpen, setIsRequestGuideOpen] = useState(false); + const onRequestGuideClose = useCallback(() => { + setIsRequestGuideOpen(false); + }, []); return (
@@ -75,19 +33,15 @@ function GuideHeader({ appName, selectedSdk, isCompact = false, onClose }: Props <> {appName}} - subtitle="applications.guide.header_description" + title="applications.guide.modal_header_title" + subtitle="applications.guide.header_subtitle" /> - - - - + /> @@ -101,19 +55,26 @@ function GuideHeader({ appName, selectedSdk, isCompact = false, onClose }: Props
{appName}} - subtitle="applications.guide.header_description" + title="applications.guide.modal_header_title" + subtitle="applications.guide.header_subtitle" /> -
); } diff --git a/packages/console/src/pages/Applications/components/GuideHeaderV2/index.module.scss b/packages/console/src/pages/Applications/components/GuideHeaderV2/index.module.scss deleted file mode 100644 index 03dfc812f..000000000 --- a/packages/console/src/pages/Applications/components/GuideHeaderV2/index.module.scss +++ /dev/null @@ -1,37 +0,0 @@ -@use '@/scss/underscore' as _; - -.header { - display: flex; - align-items: center; - background-color: var(--color-layer-1); - height: 64px; - padding: 0 _.unit(6); - - .separator { - @include _.vertical-bar; - height: 20px; - margin: 0 _.unit(5) 0 _.unit(4); - } - - .closeIcon { - color: var(--color-text-secondary); - } - - .githubToolTipAnchor { - margin-right: _.unit(4); - } - - .githubIcon { - div { - display: flex; - } - - svg { - color: var(--color-text); - } - } - - .requestSdkButton { - margin-right: _.unit(15); - } -} diff --git a/packages/console/src/pages/Applications/components/GuideHeaderV2/index.tsx b/packages/console/src/pages/Applications/components/GuideHeaderV2/index.tsx deleted file mode 100644 index b560310f0..000000000 --- a/packages/console/src/pages/Applications/components/GuideHeaderV2/index.tsx +++ /dev/null @@ -1,70 +0,0 @@ -import { useCallback, useState } from 'react'; - -import Box from '@/assets/icons/box.svg'; -import Close from '@/assets/icons/close.svg'; -import { isCloud } from '@/consts/env'; -import Button from '@/ds-components/Button'; -import CardTitle from '@/ds-components/CardTitle'; -import DangerousRaw from '@/ds-components/DangerousRaw'; -import IconButton from '@/ds-components/IconButton'; -import Spacer from '@/ds-components/Spacer'; - -import RequestGuide from './RequestGuide'; -import * as styles from './index.module.scss'; - -type Props = { - appName: string; - isCompact?: boolean; - onClose: () => void; -}; - -function GuideHeaderV2({ appName, isCompact = false, onClose }: Props) { - const [isRequestGuideOpen, setIsRequestGuideOpen] = useState(false); - const onRequestGuideClose = useCallback(() => { - setIsRequestGuideOpen(false); - }, []); - - return ( -
- {isCompact && ( - <> - {appName}} - subtitle="applications.guide.header_description" - /> - - - - - - )} - {!isCompact && ( - <> - - - -
- {appName}} - subtitle="applications.guide.header_description" - /> - -
- ); -} - -export default GuideHeaderV2; diff --git a/packages/console/src/pages/Applications/components/GuideLibrary/hook.ts b/packages/console/src/pages/Applications/components/GuideLibrary/hook.ts index 2c2265b06..3e9599ca3 100644 --- a/packages/console/src/pages/Applications/components/GuideLibrary/hook.ts +++ b/packages/console/src/pages/Applications/components/GuideLibrary/hook.ts @@ -83,5 +83,4 @@ const useAppGuideMetadata = (): [ return [getFilteredMetadata, getStructuredMetadata]; }; -// eslint-disable-next-line import/no-unused-modules export default useAppGuideMetadata; diff --git a/packages/console/src/pages/Applications/components/GuideLibrary/index.module.scss b/packages/console/src/pages/Applications/components/GuideLibrary/index.module.scss new file mode 100644 index 000000000..5c0f5916b --- /dev/null +++ b/packages/console/src/pages/Applications/components/GuideLibrary/index.module.scss @@ -0,0 +1,78 @@ +@use '@/scss/underscore' as _; + +.container { + display: flex; + gap: _.unit(7); +} + +.filters { + display: flex; + flex-direction: column; + gap: _.unit(4); + padding: _.unit(8) 0 _.unit(8) _.unit(11); + flex-shrink: 0; + overflow-y: auto; + + label { + font: var(--font-label-2); + color: var(--color-text); + } + + .searchInput { + svg { + color: var(--color-text-secondary); + } + } + + .checkboxGroup { + gap: _.unit(4); + } +} + +.groups { + flex: 1; + display: flex; + flex-direction: column; + padding-bottom: _.unit(8); + overflow-y: auto; + + > div { + flex: unset; + } +} + +.guideGroup { + flex: 1; + display: flex; + flex-direction: column; + margin: _.unit(8) _.unit(8) 0 0; + container-type: inline-size; + + label { + @include _.section-head-1; + margin-bottom: _.unit(4); + } + + .grid { + display: grid; + gap: _.unit(4) _.unit(3); + } + + @container (max-width: 680px) { + .grid { + grid-template-columns: repeat(2, 1fr); + } + } + + @container (min-width: 681px) and (max-width: 1080px) { + .grid { + grid-template-columns: repeat(3, 1fr); + } + } + + @container (min-width: 1081px) { + .grid { + grid-template-columns: repeat(4, 1fr); + } + } +} diff --git a/packages/console/src/pages/Applications/components/GuideLibrary/index.tsx b/packages/console/src/pages/Applications/components/GuideLibrary/index.tsx new file mode 100644 index 000000000..378fbfe9c --- /dev/null +++ b/packages/console/src/pages/Applications/components/GuideLibrary/index.tsx @@ -0,0 +1,146 @@ +import { type Application } from '@logto/schemas'; +import classNames from 'classnames'; +import { useCallback, useMemo, useState } from 'react'; +import { useTranslation } from 'react-i18next'; + +import { type Guide } from '@/assets/docs/guides/types'; +import SearchIcon from '@/assets/icons/search.svg'; +import { CheckboxGroup } from '@/ds-components/Checkbox'; +import OverlayScrollbar from '@/ds-components/OverlayScrollbar'; +import TextInput from '@/ds-components/TextInput'; +import useTenantPathname from '@/hooks/use-tenant-pathname'; +import { allAppGuideCategories, type AppGuideCategory } from '@/types/applications'; + +import CreateForm from '../CreateForm'; +import GuideCard, { type SelectedGuide } from '../GuideCard'; + +import useAppGuideMetadata from './hook'; +import * as styles from './index.module.scss'; + +type Props = { + className?: string; + hasFilter?: boolean; + hasCardBorder?: boolean; +}; + +type GuideGroupProps = { + categoryName?: string; + guides?: readonly Guide[]; + hasCardBorder?: boolean; + onClickGuide: (data: SelectedGuide) => void; +}; + +function GuideGroup({ categoryName, guides, hasCardBorder, onClickGuide }: GuideGroupProps) { + if (!guides?.length) { + return null; + } + + return ( +
+ {categoryName && } +
+ {guides.map((guide) => ( + + ))} +
+
+ ); +} + +function GuideLibrary({ className, hasFilter, hasCardBorder }: Props) { + const { t } = useTranslation(undefined, { keyPrefix: 'admin_console.applications.guide' }); + const { navigate } = useTenantPathname(); + const [keyword, setKeyword] = useState(''); + const [filterCategories, setFilterCategories] = useState([]); + const [selectedGuide, setSelectedGuide] = useState(); + const [getFilteredMetadata, getStructuredMetadata] = useAppGuideMetadata(); + const [showCreateForm, setShowCreateForm] = useState(false); + + const structuredMetadata = useMemo( + () => getStructuredMetadata({ categories: filterCategories }), + [getStructuredMetadata, filterCategories] + ); + + const filteredMetadata = useMemo( + () => getFilteredMetadata({ keyword, categories: filterCategories }), + [getFilteredMetadata, keyword, filterCategories] + ); + + const onClickGuide = useCallback((data: SelectedGuide) => { + setShowCreateForm(true); + setSelectedGuide(data); + }, []); + + const onCloseCreateForm = useCallback( + (newApp?: Application) => { + if (newApp && selectedGuide) { + navigate(`/applications/${newApp.id}/guide/${selectedGuide.id}`, { replace: true }); + return; + } + setShowCreateForm(false); + setSelectedGuide(undefined); + }, + [navigate, selectedGuide] + ); + + return ( +
+ {hasFilter && ( +
+ + } + placeholder={t('filter.placeholder')} + value={keyword} + onChange={(event) => { + setKeyword(event.currentTarget.value); + }} + /> + ({ + title: `applications.guide.categories.${category}`, + value: category, + }))} + value={filterCategories} + onChange={(value) => { + const sortedValue = allAppGuideCategories.filter((category) => + value.includes(category) + ); + setFilterCategories(sortedValue); + }} + /> +
+ )} + {keyword && ( + + )} + {!keyword && ( + + {(filterCategories.length > 0 ? filterCategories : allAppGuideCategories).map( + (category) => + structuredMetadata[category].length > 0 && ( + + ) + )} + + )} + {selectedGuide?.target !== 'API' && showCreateForm && ( + + )} +
+ ); +} + +export default GuideLibrary; diff --git a/packages/console/src/pages/Applications/components/GuideLibraryModal/index.module.scss b/packages/console/src/pages/Applications/components/GuideLibraryModal/index.module.scss new file mode 100644 index 000000000..a2c33d373 --- /dev/null +++ b/packages/console/src/pages/Applications/components/GuideLibraryModal/index.module.scss @@ -0,0 +1,38 @@ +@use '@/scss/underscore' as _; + +.container { + display: flex; + flex-direction: column; + background-color: var(--color-base); + height: 100vh; + + .content { + flex: 1; + display: flex; + width: 100%; + overflow: hidden; + } + + .actionBar { + display: flex; + align-items: center; + inset: auto 0 0 0; + padding: _.unit(4) _.unit(8); + background-color: var(--color-layer-1); + box-shadow: var(--shadow-2-reversed); + z-index: 1; + + .text { + font: var(--font-body-2); + color: var(--color-text); + margin-left: _.unit(62.5); + margin-right: _.unit(4); + @include _.multi-line-ellipsis(2); + } + + .button { + margin-right: 0; + margin-left: auto; + } + } +} diff --git a/packages/console/src/pages/Applications/components/GuideLibraryModal/index.tsx b/packages/console/src/pages/Applications/components/GuideLibraryModal/index.tsx new file mode 100644 index 000000000..aa3690f81 --- /dev/null +++ b/packages/console/src/pages/Applications/components/GuideLibraryModal/index.tsx @@ -0,0 +1,61 @@ +import { useState } from 'react'; +import { useTranslation } from 'react-i18next'; +import Modal from 'react-modal'; + +import Button from '@/ds-components/Button'; +import useTenantPathname from '@/hooks/use-tenant-pathname'; +import * as modalStyles from '@/scss/modal.module.scss'; + +import CreateForm from '../CreateForm'; +import GuideHeader from '../GuideHeader'; +import GuideLibrary from '../GuideLibrary'; + +import * as styles from './index.module.scss'; + +type Props = { + isOpen: boolean; + onClose: () => void; +}; + +function GuideLibraryModal({ isOpen, onClose }: Props) { + const { t } = useTranslation(undefined, { keyPrefix: 'admin_console.applications.guide' }); + const { navigate } = useTenantPathname(); + const [showCreateForm, setShowCreateForm] = useState(false); + return ( + +
+ + + +
+ {showCreateForm && ( + { + if (newApp) { + navigate(`/applications/${newApp.id}`); + } + setShowCreateForm(false); + }} + /> + )} +
+ ); +} + +export default GuideLibraryModal; diff --git a/packages/console/src/pages/Applications/components/GuideV2/index.module.scss b/packages/console/src/pages/Applications/components/GuideV2/index.module.scss index 8890c5886..394c3c879 100644 --- a/packages/console/src/pages/Applications/components/GuideV2/index.module.scss +++ b/packages/console/src/pages/Applications/components/GuideV2/index.module.scss @@ -34,7 +34,9 @@ position: absolute; inset: auto 0 0 0; padding: _.unit(4); - background-color: var(--color-bg-float); + background-color: var(--color-layer-1); + box-shadow: var(--shadow-2-reversed); + z-index: 1; .layout { margin: 0 auto; diff --git a/packages/console/src/pages/Applications/components/GuideV2/index.tsx b/packages/console/src/pages/Applications/components/GuideV2/index.tsx index 4f1ec857a..8a7c4d7cf 100644 --- a/packages/console/src/pages/Applications/components/GuideV2/index.tsx +++ b/packages/console/src/pages/Applications/components/GuideV2/index.tsx @@ -19,7 +19,7 @@ import TextLink from '@/ds-components/TextLink'; import useCustomDomain from '@/hooks/use-custom-domain'; import DetailsSummary from '@/mdx-components/DetailsSummary'; -import GuideHeaderV2 from '../GuideHeaderV2'; +import GuideHeader from '../GuideHeader'; import StepsSkeleton from '../StepsSkeleton'; import * as styles from './index.module.scss'; @@ -39,16 +39,17 @@ type GuideContextType = { export const GuideContext = createContext({} as GuideContextType); type Props = { + guideId: string; app?: Application; isCompact?: boolean; onClose: () => void; }; -function GuideV2({ app, isCompact, onClose }: Props) { +function GuideV2({ guideId, app, isCompact, onClose }: Props) { const { tenantEndpoint } = useContext(AppDataContext); const { data: customDomain } = useCustomDomain(); const isCustomDomainActive = customDomain?.status === DomainStatus.Active; - const guide = guides.find(({ id }) => id === 'web-gpt-plugin'); + const guide = guides.find(({ id }) => id === guideId); if (!app || !guide) { throw new Error('Invalid app or guide'); @@ -73,7 +74,7 @@ function GuideV2({ app, isCompact, onClose }: Props) { return (
- +
diff --git a/packages/console/src/pages/Applications/index.module.scss b/packages/console/src/pages/Applications/index.module.scss index 8c7fb150e..a2bf671de 100644 --- a/packages/console/src/pages/Applications/index.module.scss +++ b/packages/console/src/pages/Applications/index.module.scss @@ -7,3 +7,20 @@ .applicationName { width: 360px; } + +.guideLibraryContainer { + flex: 1; + overflow-y: auto; + background: var(--color-layer-1); + border-radius: 12px; + padding: _.unit(6) 0; + margin: _.unit(4) 0; + + .title { + text-align: center; + } + + .library { + padding: 0 _.unit(6); + } +} diff --git a/packages/console/src/pages/Applications/index.tsx b/packages/console/src/pages/Applications/index.tsx index d18f6f093..252794af2 100644 --- a/packages/console/src/pages/Applications/index.tsx +++ b/packages/console/src/pages/Applications/index.tsx @@ -1,24 +1,29 @@ import { withAppInsights } from '@logto/app-insights/react'; import type { Application } from '@logto/schemas'; import { ApplicationType } from '@logto/schemas'; -import { useState } from 'react'; import { useTranslation } from 'react-i18next'; import { useLocation } from 'react-router-dom'; import useSWR from 'swr'; +import Plus from '@/assets/icons/plus.svg'; import ApplicationIcon from '@/components/ApplicationIcon'; import ItemPreview from '@/components/ItemPreview'; -import ListPage from '@/components/ListPage'; +import PageMeta from '@/components/PageMeta'; import { defaultPageSize } from '@/consts'; +import Button from '@/ds-components/Button'; +import CardTitle from '@/ds-components/CardTitle'; import CopyToClipboard from '@/ds-components/CopyToClipboard'; +import OverlayScrollbar from '@/ds-components/OverlayScrollbar'; +import Table from '@/ds-components/Table'; import type { RequestError } from '@/hooks/use-api'; import useSearchParametersWatcher from '@/hooks/use-search-parameters-watcher'; import useTenantPathname from '@/hooks/use-tenant-pathname'; +import * as pageLayout from '@/scss/page-layout.module.scss'; import { applicationTypeI18nKey } from '@/types/applications'; import { buildUrl } from '@/utils/url'; -import ApplicationsPlaceholder from './components/ApplicationsPlaceholder'; -import CreateForm from './components/CreateForm'; +import GuideLibrary from './components/GuideLibrary'; +import GuideLibraryModal from './components/GuideLibraryModal'; import * as styles from './index.module.scss'; const pageSize = defaultPageSize; @@ -39,7 +44,6 @@ function Applications() { const { match, navigate } = useTenantPathname(); const isCreating = match(createApplicationPathname); const { t } = useTranslation(undefined, { keyPrefix: 'admin_console' }); - const [defaultCreateType, setDefaultCreateType] = useState(); const [{ page }, updateSearchParameters] = useSearchParametersWatcher({ page: 1, }); @@ -55,89 +59,87 @@ function Applications() { const [applications, totalCount] = data ?? []; return ( - { - navigate({ - pathname: createApplicationPathname, - search, - }); - }, - }} - table={{ - rowGroups: [{ key: 'applications', data: applications }], - rowIndexKey: 'id', - isLoading, - errorMessage: error?.body?.message ?? error?.message, - columns: [ - { - title: t('applications.application_name'), - dataIndex: 'name', - colSpan: 6, - render: ({ id, name, type }) => ( - } - to={buildDetailsPathname(id)} - /> - ), - }, - { - title: t('applications.app_id'), - dataIndex: 'id', - colSpan: 10, - render: ({ id }) => , - }, - ], - placeholder: ( - { - setDefaultCreateType(createType); +
+ +
+ + {!!totalCount && ( +
+ {!isLoading && !applications?.length && ( + + + + + )} + {(isLoading || !!applications?.length) && ( + ( + } + to={buildDetailsPathname(id)} + /> + ), + }, + { + title: t('applications.app_id'), + dataIndex: 'id', + colSpan: 10, + render: ({ id }) => , + }, + ]} + rowClickHandler={({ id }) => { + navigate(buildDetailsPathname(id)); }} + pagination={{ + page, + totalCount, + pageSize, + onChange: (page) => { + updateSearchParameters({ page }); + }, + }} + onRetry={async () => mutate(undefined, true)} /> - } - /> + )} + { + navigate({ + pathname: applicationsPathname, + search, + }); + }} + /> + ); } diff --git a/packages/console/src/types/applications.ts b/packages/console/src/types/applications.ts index 49ae313e2..12dc18464 100644 --- a/packages/console/src/types/applications.ts +++ b/packages/console/src/types/applications.ts @@ -34,7 +34,6 @@ export const applicationTypeAndSdkTypeMappings = Object.freeze({ * All application guide categories, including all 4 existing application types, * plus the "featured" category. */ -/* eslint-disable import/no-unused-modules */ export const allAppGuideCategories = Object.freeze([ 'featured', 'Traditional', @@ -50,4 +49,3 @@ export type AppGuideCategory = (typeof allAppGuideCategories)[number]; * E.g. `{'featured': [...], 'Traditional': [...], 'SPA': [...], 'Native': [...]}` */ export type StructuredAppGuideMetadata = Record; -/* eslint-enable import/no-unused-modules */ diff --git a/packages/phrases/src/locales/de/translation/admin-console/applications.ts b/packages/phrases/src/locales/de/translation/admin-console/applications.ts index 7b9bf971a..edb95c4ef 100644 --- a/packages/phrases/src/locales/de/translation/admin-console/applications.ts +++ b/packages/phrases/src/locales/de/translation/admin-console/applications.ts @@ -37,14 +37,30 @@ const applications = { }, }, guide: { + header_title: 'Select a framework or tutorial', // UNTRANSLATED + modal_header_title: 'Start with SDK and guides', // UNTRANSLATED + header_subtitle: 'Jumpstart your app development process with our pre-built SDK and tutorials.', // UNTRANSLATED + start_building: 'Start Building', // UNTRANSLATED + categories: { + featured: 'Popular and for you', // UNTRANSLATED + Traditional: 'Traditional web app', // UNTRANSLATED + SPA: 'Single page app', // UNTRANSLATED + Native: 'Native', // UNTRANSLATED + MachineToMachine: 'Machine-to-machine', // UNTRANSLATED + }, + filter: { + title: 'Filter framework', // UNTRANSLATED + placeholder: 'Search for framework', // UNTRANSLATED + }, get_sample_file: 'Zum Beispielprojekt', - header_description: - 'Folge der Schritt-für-Schritt-Anleitung, um die Anwendung zu integrieren, oder klick auf die rechte Schaltfläche, um unser Beispielprojekt zu erhalten', title: 'Die Anwendung wurde erfolgreich erstellt', subtitle: 'Folge nun den folgenden Schritten, um deine App-Einstellungen abzuschließen. Bitte wähle den SDK-Typ aus, um fortzufahren.', description_by_sdk: 'Diese Schnellstart-Anleitung zeigt, wie man Logto in die {{sdk}} App integriert', + do_not_need_tutorial: + 'If you don’t need a tutorial, you can continue without a framework guide', // UNTRANSLATED + create_without_framework: 'Create app without framework', // UNTRANSLATED finish_and_done: 'Fertig und erledigt', cannot_find_guide: "Can't find your guide?", // UNTRANSLATED describe_guide_looking_for: 'Describe the guide you are looking for', // UNTRANSLATED diff --git a/packages/phrases/src/locales/en/translation/admin-console/applications.ts b/packages/phrases/src/locales/en/translation/admin-console/applications.ts index 5d98c9c7e..4440221f0 100644 --- a/packages/phrases/src/locales/en/translation/admin-console/applications.ts +++ b/packages/phrases/src/locales/en/translation/admin-console/applications.ts @@ -36,14 +36,30 @@ const applications = { }, }, guide: { + header_title: 'Select a framework or tutorial', + modal_header_title: 'Start with SDK and guides', + header_subtitle: 'Jumpstart your app development process with our pre-built SDK and tutorials.', + start_building: 'Start Building', + categories: { + featured: 'Popular and for you', + Traditional: 'Traditional web app', + SPA: 'Single page app', + Native: 'Native', + MachineToMachine: 'Machine-to-machine', + }, + filter: { + title: 'Filter framework', + placeholder: 'Search for framework', + }, get_sample_file: 'Get Sample', - header_description: - 'Follow a step by step guide to integrate your application or click the right button to get our sample project', title: 'The application has been successfully created', subtitle: 'Now follow the steps below to finish your app settings. Please select the SDK type to continue.', description_by_sdk: 'This quick start guide demonstrates how to integrate Logto into {{sdk}} app', + do_not_need_tutorial: + 'If you don’t need a tutorial, you can continue without a framework guide', + create_without_framework: 'Create app without framework', finish_and_done: 'Finish and done', cannot_find_guide: "Can't find your guide?", describe_guide_looking_for: 'Describe the guide you are looking for', diff --git a/packages/phrases/src/locales/es/translation/admin-console/applications.ts b/packages/phrases/src/locales/es/translation/admin-console/applications.ts index 70fa75868..44bb865b8 100644 --- a/packages/phrases/src/locales/es/translation/admin-console/applications.ts +++ b/packages/phrases/src/locales/es/translation/admin-console/applications.ts @@ -37,14 +37,30 @@ const applications = { }, }, guide: { + header_title: 'Select a framework or tutorial', // UNTRANSLATED + modal_header_title: 'Start with SDK and guides', // UNTRANSLATED + header_subtitle: 'Jumpstart your app development process with our pre-built SDK and tutorials.', // UNTRANSLATED + start_building: 'Start Building', // UNTRANSLATED + categories: { + featured: 'Popular and for you', // UNTRANSLATED + Traditional: 'Traditional web app', // UNTRANSLATED + SPA: 'Single page app', // UNTRANSLATED + Native: 'Native', // UNTRANSLATED + MachineToMachine: 'Machine-to-machine', // UNTRANSLATED + }, + filter: { + title: 'Filter framework', // UNTRANSLATED + placeholder: 'Search for framework', // UNTRANSLATED + }, get_sample_file: 'Obtener muestra', - header_description: - 'Sigue una guía paso a paso para integrar tu aplicación o haz clic en el botón adecuado para obtener nuestro proyecto de muestra', title: 'La aplicación se ha creado correctamente', subtitle: 'Sigue los pasos siguientes para completar la configuración de tu aplicación. Por favor, selecciona el tipo de SDK para continuar.', description_by_sdk: 'Esta guía de inicio rápido muestra cómo integrar Logto en la aplicación {{sdk}}', + do_not_need_tutorial: + 'If you don’t need a tutorial, you can continue without a framework guide', // UNTRANSLATED + create_without_framework: 'Create app without framework', // UNTRANSLATED finish_and_done: 'Finalizar y hecho', cannot_find_guide: "Can't find your guide?", // UNTRANSLATED describe_guide_looking_for: 'Describe the guide you are looking for', // UNTRANSLATED diff --git a/packages/phrases/src/locales/fr/translation/admin-console/applications.ts b/packages/phrases/src/locales/fr/translation/admin-console/applications.ts index 150f8198f..61c0ff309 100644 --- a/packages/phrases/src/locales/fr/translation/admin-console/applications.ts +++ b/packages/phrases/src/locales/fr/translation/admin-console/applications.ts @@ -38,14 +38,30 @@ const applications = { }, }, guide: { + header_title: 'Select a framework or tutorial', // UNTRANSLATED + modal_header_title: 'Start with SDK and guides', // UNTRANSLATED + header_subtitle: 'Jumpstart your app development process with our pre-built SDK and tutorials.', // UNTRANSLATED + start_building: 'Start Building', // UNTRANSLATED + categories: { + featured: 'Popular and for you', // UNTRANSLATED + Traditional: 'Traditional web app', // UNTRANSLATED + SPA: 'Single page app', // UNTRANSLATED + Native: 'Native', // UNTRANSLATED + MachineToMachine: 'Machine-to-machine', // UNTRANSLATED + }, + filter: { + title: 'Filter framework', // UNTRANSLATED + placeholder: 'Search for framework', // UNTRANSLATED + }, get_sample_file: 'Obtenir un exemple', - header_description: - 'Suivez un guide étape par étape pour intégrer votre application ou cliquez sur le bouton de droite pour obtenir notre exemple de projet.', title: "L'application a été créée avec succès", subtitle: 'Suivez maintenant les étapes ci-dessous pour terminer la configuration de votre application. Veuillez sélectionner le type de SDK pour continuer.', description_by_sdk: "Ce guide de démarrage rapide montre comment intégrer Logto dans l'application {{sdk}}.", + do_not_need_tutorial: + 'If you don’t need a tutorial, you can continue without a framework guide', // UNTRANSLATED + create_without_framework: 'Create app without framework', // UNTRANSLATED finish_and_done: 'Terminer et terminé', cannot_find_guide: "Can't find your guide?", // UNTRANSLATED describe_guide_looking_for: 'Describe the guide you are looking for', // UNTRANSLATED diff --git a/packages/phrases/src/locales/it/translation/admin-console/applications.ts b/packages/phrases/src/locales/it/translation/admin-console/applications.ts index 8e18a6a2b..a057de191 100644 --- a/packages/phrases/src/locales/it/translation/admin-console/applications.ts +++ b/packages/phrases/src/locales/it/translation/admin-console/applications.ts @@ -37,13 +37,29 @@ const applications = { }, }, guide: { + header_title: 'Select a framework or tutorial', // UNTRANSLATED + modal_header_title: 'Start with SDK and guides', // UNTRANSLATED + header_subtitle: 'Jumpstart your app development process with our pre-built SDK and tutorials.', // UNTRANSLATED + start_building: 'Start Building', // UNTRANSLATED + categories: { + featured: 'Popular and for you', // UNTRANSLATED + Traditional: 'Traditional web app', // UNTRANSLATED + SPA: 'Single page app', // UNTRANSLATED + Native: 'Native', // UNTRANSLATED + MachineToMachine: 'Machine-to-machine', // UNTRANSLATED + }, + filter: { + title: 'Filter framework', // UNTRANSLATED + placeholder: 'Search for framework', // UNTRANSLATED + }, get_sample_file: 'Scarica Esempio', - header_description: - 'Segui la guida passo passo per integrare la tua applicazione o clicca il pulsante corretto per scaricare il nostro progetto di esempio', title: "L'applicazione è stata creata con successo", subtitle: 'Ora segui i passi di seguito per completare le impostazioni della tua app. Seleziona il tipo di SDK per continuare.', description_by_sdk: "Questa guida rapida illustra come integrare Logto in un'app {{sdk}}", + do_not_need_tutorial: + 'If you don’t need a tutorial, you can continue without a framework guide', // UNTRANSLATED + create_without_framework: 'Create app without framework', // UNTRANSLATED finish_and_done: 'Completato e fatto', cannot_find_guide: "Can't find your guide?", // UNTRANSLATED describe_guide_looking_for: 'Describe the guide you are looking for', // UNTRANSLATED diff --git a/packages/phrases/src/locales/ja/translation/admin-console/applications.ts b/packages/phrases/src/locales/ja/translation/admin-console/applications.ts index 34f0c9548..1c7abe2ed 100644 --- a/packages/phrases/src/locales/ja/translation/admin-console/applications.ts +++ b/packages/phrases/src/locales/ja/translation/admin-console/applications.ts @@ -36,14 +36,30 @@ const applications = { }, }, guide: { + header_title: 'Select a framework or tutorial', // UNTRANSLATED + modal_header_title: 'Start with SDK and guides', // UNTRANSLATED + header_subtitle: 'Jumpstart your app development process with our pre-built SDK and tutorials.', // UNTRANSLATED + start_building: 'Start Building', // UNTRANSLATED + categories: { + featured: 'Popular and for you', // UNTRANSLATED + Traditional: 'Traditional web app', // UNTRANSLATED + SPA: 'Single page app', // UNTRANSLATED + Native: 'Native', // UNTRANSLATED + MachineToMachine: 'Machine-to-machine', // UNTRANSLATED + }, + filter: { + title: 'Filter framework', // UNTRANSLATED + placeholder: 'Search for framework', // UNTRANSLATED + }, get_sample_file: 'サンプルを取得する', - header_description: - 'アプリケーションを統合するためのステップバイステップガイドに従うか、サンプルプロジェクトを取得するための適切なボタンをクリックしてください。', title: 'アプリケーションが正常に作成されました', subtitle: '以下の手順に従ってアプリの設定を完了してください。SDKタイプを選択して続行してください。', description_by_sdk: 'このクイックスタートガイドでは、{{sdk}}アプリにLogtoを統合する方法を説明します。', + do_not_need_tutorial: + 'If you don’t need a tutorial, you can continue without a framework guide', // UNTRANSLATED + create_without_framework: 'Create app without framework', // UNTRANSLATED finish_and_done: '完了', cannot_find_guide: "Can't find your guide?", // UNTRANSLATED describe_guide_looking_for: 'Describe the guide you are looking for', // UNTRANSLATED diff --git a/packages/phrases/src/locales/ko/translation/admin-console/applications.ts b/packages/phrases/src/locales/ko/translation/admin-console/applications.ts index e68ddde51..796993d98 100644 --- a/packages/phrases/src/locales/ko/translation/admin-console/applications.ts +++ b/packages/phrases/src/locales/ko/translation/admin-console/applications.ts @@ -36,12 +36,28 @@ const applications = { }, }, guide: { + header_title: 'Select a framework or tutorial', // UNTRANSLATED + modal_header_title: 'Start with SDK and guides', // UNTRANSLATED + header_subtitle: 'Jumpstart your app development process with our pre-built SDK and tutorials.', // UNTRANSLATED + start_building: 'Start Building', // UNTRANSLATED + categories: { + featured: 'Popular and for you', // UNTRANSLATED + Traditional: 'Traditional web app', // UNTRANSLATED + SPA: 'Single page app', // UNTRANSLATED + Native: 'Native', // UNTRANSLATED + MachineToMachine: 'Machine-to-machine', // UNTRANSLATED + }, + filter: { + title: 'Filter framework', // UNTRANSLATED + placeholder: 'Search for framework', // UNTRANSLATED + }, get_sample_file: '예제 찾기', - header_description: - '단계별 가이드에 따라 어플리케이션을 연동하거나, 오른쪽 버튼을 클릭하여 샘플 프로젝트를 받아 보세요.', title: '어플리케이션이 생성되었어요.', subtitle: '앱 설정을 마치기 위해 아래 단계를 따라주세요. SDK 종류를 선택해 주세요.', description_by_sdk: '아래 과정을 따라서 Logto를 {{sdk}} 앱과 빠르게 연동해 보세요.', + do_not_need_tutorial: + 'If you don’t need a tutorial, you can continue without a framework guide', // UNTRANSLATED + create_without_framework: 'Create app without framework', // UNTRANSLATED finish_and_done: '끝내기', cannot_find_guide: "Can't find your guide?", // UNTRANSLATED describe_guide_looking_for: 'Describe the guide you are looking for', // UNTRANSLATED diff --git a/packages/phrases/src/locales/pl-pl/translation/admin-console/applications.ts b/packages/phrases/src/locales/pl-pl/translation/admin-console/applications.ts index 799384e41..4f538b719 100644 --- a/packages/phrases/src/locales/pl-pl/translation/admin-console/applications.ts +++ b/packages/phrases/src/locales/pl-pl/translation/admin-console/applications.ts @@ -37,14 +37,30 @@ const applications = { }, }, guide: { + header_title: 'Select a framework or tutorial', // UNTRANSLATED + modal_header_title: 'Start with SDK and guides', // UNTRANSLATED + header_subtitle: 'Jumpstart your app development process with our pre-built SDK and tutorials.', // UNTRANSLATED + start_building: 'Start Building', // UNTRANSLATED + categories: { + featured: 'Popular and for you', // UNTRANSLATED + Traditional: 'Traditional web app', // UNTRANSLATED + SPA: 'Single page app', // UNTRANSLATED + Native: 'Native', // UNTRANSLATED + MachineToMachine: 'Machine-to-machine', // UNTRANSLATED + }, + filter: { + title: 'Filter framework', // UNTRANSLATED + placeholder: 'Search for framework', // UNTRANSLATED + }, get_sample_file: 'Pobierz przykład', - header_description: - 'Postępuj zgodnie z przewodnikiem krok po kroku, aby zintegrować swoją aplikację lub kliknij prawy przycisk, aby pobrać nasz przykładowy projekt', title: 'Aplikacja została pomyślnie utworzona', subtitle: 'Teraz postępuj zgodnie z poniższymi krokami, aby zakończyć konfigurację aplikacji. Wybierz typ SDK, aby kontynuować.', description_by_sdk: 'Ten przewodnik po szybkim rozpoczęciu demonstruje, jak zintegrować Logto z aplikacją {{sdk}}', + do_not_need_tutorial: + 'If you don’t need a tutorial, you can continue without a framework guide', // UNTRANSLATED + create_without_framework: 'Create app without framework', // UNTRANSLATED finish_and_done: 'Zakończ i zrobione', cannot_find_guide: "Can't find your guide?", // UNTRANSLATED describe_guide_looking_for: 'Describe the guide you are looking for', // UNTRANSLATED diff --git a/packages/phrases/src/locales/pt-br/translation/admin-console/applications.ts b/packages/phrases/src/locales/pt-br/translation/admin-console/applications.ts index ebf019cd1..feb3742df 100644 --- a/packages/phrases/src/locales/pt-br/translation/admin-console/applications.ts +++ b/packages/phrases/src/locales/pt-br/translation/admin-console/applications.ts @@ -37,14 +37,30 @@ const applications = { }, }, guide: { + header_title: 'Select a framework or tutorial', // UNTRANSLATED + modal_header_title: 'Start with SDK and guides', // UNTRANSLATED + header_subtitle: 'Jumpstart your app development process with our pre-built SDK and tutorials.', // UNTRANSLATED + start_building: 'Start Building', // UNTRANSLATED + categories: { + featured: 'Popular and for you', // UNTRANSLATED + Traditional: 'Traditional web app', // UNTRANSLATED + SPA: 'Single page app', // UNTRANSLATED + Native: 'Native', // UNTRANSLATED + MachineToMachine: 'Machine-to-machine', // UNTRANSLATED + }, + filter: { + title: 'Filter framework', // UNTRANSLATED + placeholder: 'Search for framework', // UNTRANSLATED + }, get_sample_file: 'Obter amostra', - header_description: - 'Siga um guia passo a passo para integrar seu aplicativo ou clique no botão direito para obter nosso projeto de amostra', title: 'O aplicativo foi criado com sucesso', subtitle: 'Agora siga as etapas abaixo para concluir as configurações do aplicativo. Selecione o tipo de SDK para continuar.', description_by_sdk: 'Este guia de início rápido demonstra como integrar o Logto ao aplicativo {{sdk}}', + do_not_need_tutorial: + 'If you don’t need a tutorial, you can continue without a framework guide', // UNTRANSLATED + create_without_framework: 'Create app without framework', // UNTRANSLATED finish_and_done: 'Concluído', cannot_find_guide: "Can't find your guide?", // UNTRANSLATED describe_guide_looking_for: 'Describe the guide you are looking for', // UNTRANSLATED diff --git a/packages/phrases/src/locales/pt-pt/translation/admin-console/applications.ts b/packages/phrases/src/locales/pt-pt/translation/admin-console/applications.ts index 3dc9bc8a2..53d2b571e 100644 --- a/packages/phrases/src/locales/pt-pt/translation/admin-console/applications.ts +++ b/packages/phrases/src/locales/pt-pt/translation/admin-console/applications.ts @@ -36,13 +36,29 @@ const applications = { }, }, guide: { + header_title: 'Select a framework or tutorial', // UNTRANSLATED + modal_header_title: 'Start with SDK and guides', // UNTRANSLATED + header_subtitle: 'Jumpstart your app development process with our pre-built SDK and tutorials.', // UNTRANSLATED + start_building: 'Start Building', // UNTRANSLATED + categories: { + featured: 'Popular and for you', // UNTRANSLATED + Traditional: 'Traditional web app', // UNTRANSLATED + SPA: 'Single page app', // UNTRANSLATED + Native: 'Native', // UNTRANSLATED + MachineToMachine: 'Machine-to-machine', // UNTRANSLATED + }, + filter: { + title: 'Filter framework', // UNTRANSLATED + placeholder: 'Search for framework', // UNTRANSLATED + }, get_sample_file: 'Obter amostra', - header_description: - 'Siga um guia passo a passo para integrar a sua aplicação ou clique com o botão direito para obter nosso projeto de amostra', title: 'A aplicação foi criada com sucesso', subtitle: 'Agora siga as etapas abaixo para concluir as configurações da aplicação. Selecione o tipo de SDK para continuar.', description_by_sdk: 'Este guia de início rápido demonstra como integrar o Logto em {{sdk}}', + do_not_need_tutorial: + 'If you don’t need a tutorial, you can continue without a framework guide', // UNTRANSLATED + create_without_framework: 'Create app without framework', // UNTRANSLATED finish_and_done: 'Finalizar e concluir', cannot_find_guide: "Can't find your guide?", // UNTRANSLATED describe_guide_looking_for: 'Describe the guide you are looking for', // UNTRANSLATED diff --git a/packages/phrases/src/locales/ru/translation/admin-console/applications.ts b/packages/phrases/src/locales/ru/translation/admin-console/applications.ts index 93f2bff95..ac7243613 100644 --- a/packages/phrases/src/locales/ru/translation/admin-console/applications.ts +++ b/packages/phrases/src/locales/ru/translation/admin-console/applications.ts @@ -36,14 +36,30 @@ const applications = { }, }, guide: { + header_title: 'Select a framework or tutorial', // UNTRANSLATED + modal_header_title: 'Start with SDK and guides', // UNTRANSLATED + header_subtitle: 'Jumpstart your app development process with our pre-built SDK and tutorials.', // UNTRANSLATED + start_building: 'Start Building', // UNTRANSLATED + categories: { + featured: 'Popular and for you', // UNTRANSLATED + Traditional: 'Traditional web app', // UNTRANSLATED + SPA: 'Single page app', // UNTRANSLATED + Native: 'Native', // UNTRANSLATED + MachineToMachine: 'Machine-to-machine', // UNTRANSLATED + }, + filter: { + title: 'Filter framework', // UNTRANSLATED + placeholder: 'Search for framework', // UNTRANSLATED + }, get_sample_file: 'Получить образец', - header_description: - 'Следуйте пошаговому руководству, чтобы интегрировать ваше приложение, или нажимите правильную кнопку, чтобы получить наш образец проекта', title: 'Приложение успешно создано', subtitle: 'Теперь следуйте инструкциям ниже, чтобы завершить настройку приложения. Выберите тип SDK, чтобы продолжить.', description_by_sdk: 'Это быстрое руководство демонстрирует, как интегрировать Logto в {{sdk}} приложение', + do_not_need_tutorial: + 'If you don’t need a tutorial, you can continue without a framework guide', // UNTRANSLATED + create_without_framework: 'Create app without framework', // UNTRANSLATED finish_and_done: 'Завершить и готово', cannot_find_guide: "Can't find your guide?", // UNTRANSLATED describe_guide_looking_for: 'Describe the guide you are looking for', // UNTRANSLATED diff --git a/packages/phrases/src/locales/tr-tr/translation/admin-console/applications.ts b/packages/phrases/src/locales/tr-tr/translation/admin-console/applications.ts index a480adc53..51475ded1 100644 --- a/packages/phrases/src/locales/tr-tr/translation/admin-console/applications.ts +++ b/packages/phrases/src/locales/tr-tr/translation/admin-console/applications.ts @@ -37,14 +37,30 @@ const applications = { }, }, guide: { + header_title: 'Select a framework or tutorial', // UNTRANSLATED + modal_header_title: 'Start with SDK and guides', // UNTRANSLATED + header_subtitle: 'Jumpstart your app development process with our pre-built SDK and tutorials.', // UNTRANSLATED + start_building: 'Start Building', // UNTRANSLATED + categories: { + featured: 'Popular and for you', // UNTRANSLATED + Traditional: 'Traditional web app', // UNTRANSLATED + SPA: 'Single page app', // UNTRANSLATED + Native: 'Native', // UNTRANSLATED + MachineToMachine: 'Machine-to-machine', // UNTRANSLATED + }, + filter: { + title: 'Filter framework', // UNTRANSLATED + placeholder: 'Search for framework', // UNTRANSLATED + }, get_sample_file: 'Örnek Gör', - header_description: - 'Uygulamanızı entegre etmek için adım adım kılavuzu izleyin veya örnek projemizi almak için sağ düğmeye tıklayınız', title: 'Uygulama başarıyla oluşturuldu', subtitle: 'Şimdi uygulama ayarlarınızı tamamlamak için aşağıdaki adımları izleyiniz. Lütfen devam etmek için SDK türünü seçiniz.', description_by_sdk: 'Bu hızlı başlangıç kılavuzu, Logtoyu {{sdk}} uygulamasına nasıl entegre edeceğinizi gösterir', + do_not_need_tutorial: + 'If you don’t need a tutorial, you can continue without a framework guide', // UNTRANSLATED + create_without_framework: 'Create app without framework', // UNTRANSLATED finish_and_done: 'Bitir ve tamamlandı', cannot_find_guide: "Can't find your guide?", // UNTRANSLATED describe_guide_looking_for: 'Describe the guide you are looking for', // UNTRANSLATED diff --git a/packages/phrases/src/locales/zh-cn/translation/admin-console/applications.ts b/packages/phrases/src/locales/zh-cn/translation/admin-console/applications.ts index 161fb42bd..84ae4dfd7 100644 --- a/packages/phrases/src/locales/zh-cn/translation/admin-console/applications.ts +++ b/packages/phrases/src/locales/zh-cn/translation/admin-console/applications.ts @@ -34,12 +34,28 @@ const applications = { }, }, guide: { + header_title: 'Select a framework or tutorial', // UNTRANSLATED + modal_header_title: 'Start with SDK and guides', // UNTRANSLATED + header_subtitle: 'Jumpstart your app development process with our pre-built SDK and tutorials.', // UNTRANSLATED + start_building: 'Start Building', // UNTRANSLATED + categories: { + featured: 'Popular and for you', // UNTRANSLATED + Traditional: 'Traditional web app', // UNTRANSLATED + SPA: 'Single page app', // UNTRANSLATED + Native: 'Native', // UNTRANSLATED + MachineToMachine: 'Machine-to-machine', // UNTRANSLATED + }, + filter: { + title: 'Filter framework', // UNTRANSLATED + placeholder: 'Search for framework', // UNTRANSLATED + }, get_sample_file: '获取示例', - header_description: - '参考如下教程,将 Logto 集成到你的应用中。你也可以点击右侧按钮,获取我们为你准备好的示例工程。', title: '应用创建成功', subtitle: '参考以下步骤完成你的应用设置。首先,选择你要使用的 SDK 类型:', description_by_sdk: '本教程向你演示如何在 {{sdk}} 应用中集成 Logto 登录功能', + do_not_need_tutorial: + 'If you don’t need a tutorial, you can continue without a framework guide', // UNTRANSLATED + create_without_framework: 'Create app without framework', // UNTRANSLATED finish_and_done: '完成并结束', cannot_find_guide: "Can't find your guide?", // UNTRANSLATED describe_guide_looking_for: 'Describe the guide you are looking for', // UNTRANSLATED diff --git a/packages/phrases/src/locales/zh-hk/translation/admin-console/applications.ts b/packages/phrases/src/locales/zh-hk/translation/admin-console/applications.ts index 8fb047a3d..aee8f86a6 100644 --- a/packages/phrases/src/locales/zh-hk/translation/admin-console/applications.ts +++ b/packages/phrases/src/locales/zh-hk/translation/admin-console/applications.ts @@ -34,12 +34,28 @@ const applications = { }, }, guide: { + header_title: 'Select a framework or tutorial', // UNTRANSLATED + modal_header_title: 'Start with SDK and guides', // UNTRANSLATED + header_subtitle: 'Jumpstart your app development process with our pre-built SDK and tutorials.', // UNTRANSLATED + start_building: 'Start Building', // UNTRANSLATED + categories: { + featured: 'Popular and for you', // UNTRANSLATED + Traditional: 'Traditional web app', // UNTRANSLATED + SPA: 'Single page app', // UNTRANSLATED + Native: 'Native', // UNTRANSLATED + MachineToMachine: 'Machine-to-machine', // UNTRANSLATED + }, + filter: { + title: 'Filter framework', // UNTRANSLATED + placeholder: 'Search for framework', // UNTRANSLATED + }, get_sample_file: '獲取示例', - header_description: - '參考如下教程,將 Logto 集成到你的應用中。你也可以點擊右側按鈕,獲取我們為你準備好的示例工程。', title: '應用創建成功', subtitle: '參考以下步驟完成你的應用設置。首先,選擇你要使用的 SDK 類型:', description_by_sdk: '本教程向你演示如何在 {{sdk}} 應用中集成 Logto 登錄功能', + do_not_need_tutorial: + 'If you don’t need a tutorial, you can continue without a framework guide', // UNTRANSLATED + create_without_framework: 'Create app without framework', // UNTRANSLATED finish_and_done: '完成並結束', cannot_find_guide: "Can't find your guide?", // UNTRANSLATED describe_guide_looking_for: 'Describe the guide you are looking for', // UNTRANSLATED diff --git a/packages/phrases/src/locales/zh-tw/translation/admin-console/applications.ts b/packages/phrases/src/locales/zh-tw/translation/admin-console/applications.ts index 92d304484..9d64c84b3 100644 --- a/packages/phrases/src/locales/zh-tw/translation/admin-console/applications.ts +++ b/packages/phrases/src/locales/zh-tw/translation/admin-console/applications.ts @@ -34,12 +34,28 @@ const applications = { }, }, guide: { + header_title: 'Select a framework or tutorial', // UNTRANSLATED + modal_header_title: 'Start with SDK and guides', // UNTRANSLATED + header_subtitle: 'Jumpstart your app development process with our pre-built SDK and tutorials.', // UNTRANSLATED + start_building: 'Start Building', // UNTRANSLATED + categories: { + featured: 'Popular and for you', // UNTRANSLATED + Traditional: 'Traditional web app', // UNTRANSLATED + SPA: 'Single page app', // UNTRANSLATED + Native: 'Native', // UNTRANSLATED + MachineToMachine: 'Machine-to-machine', // UNTRANSLATED + }, + filter: { + title: 'Filter framework', // UNTRANSLATED + placeholder: 'Search for framework', // UNTRANSLATED + }, get_sample_file: '獲取示例', - header_description: - '參考如下教程,將 Logto 集成到你的應用中。你也可以點擊右側按鈕,獲取我們為你準備好的示例工程。', title: '應用創建成功', subtitle: '參考以下步驟完成你的應用設置。首先,選擇你要使用的 SDK 類型:', description_by_sdk: '本教程向你演示如何在 {{sdk}} 應用中集成 Logto 登入功能', + do_not_need_tutorial: + 'If you don’t need a tutorial, you can continue without a framework guide', // UNTRANSLATED + create_without_framework: 'Create app without framework', // UNTRANSLATED finish_and_done: '完成並結束', cannot_find_guide: "Can't find your guide?", // UNTRANSLATED describe_guide_looking_for: 'Describe the guide you are looking for', // UNTRANSLATED