chore: create app card

This commit is contained in:
Joel
2026-05-13 14:33:21 +08:00
committed by Jingyi-Dify
parent 7be8a5b883
commit 3e75d5e443
2 changed files with 23 additions and 18 deletions

View File

@ -63,7 +63,7 @@ describe('CreateAppCard', () => {
describe('Rendering', () => {
it('should render without crashing', () => {
render(<CreateAppCard ref={defaultRef} />)
expect(screen.getByText('app.createApp')).toBeInTheDocument()
expect(screen.getByText('app.newApp.startFromBlank')).toBeInTheDocument()
})
it('should render three create buttons', () => {
@ -96,7 +96,7 @@ describe('CreateAppCard', () => {
it('should render with selectedAppType prop', () => {
render(<CreateAppCard ref={defaultRef} selectedAppType="chat" />)
expect(screen.getByText('app.createApp')).toBeInTheDocument()
expect(screen.getByText('app.newApp.startFromBlank')).toBeInTheDocument()
})
})
@ -222,7 +222,7 @@ describe('CreateAppCard', () => {
const { container } = render(<CreateAppCard ref={defaultRef} />)
const card = container.firstChild as HTMLElement
expect(card).toHaveClass('h-[160px]', 'rounded-xl')
expect(card).toHaveClass('h-41.5', 'rounded-xl', 'bg-background-default-dimmed')
})
it('should have proper button styling', () => {

View File

@ -6,7 +6,6 @@ import { useEffect, useMemo, useState } from 'react'
import { useTranslation } from 'react-i18next'
import { useContextSelector } from 'use-context-selector'
import { CreateFromDSLModalTab } from '@/app/components/app/create-from-dsl-modal'
import { FileArrow01, FilePlus01, FilePlus02 } from '@/app/components/base/icons/src/vender/line/files'
import AppListContext from '@/context/app-list-context'
import { useProviderContext } from '@/context/provider-context'
import dynamic from '@/next/dynamic'
@ -25,6 +24,9 @@ const CreateFromDSLModal = dynamic(() => import('@/app/components/app/create-fro
ssr: false,
})
const actionButtonClassName = 'group flex w-full cursor-pointer items-center gap-2 rounded-lg px-4 py-2 text-left system-sm-medium text-text-tertiary outline-hidden transition-colors hover:bg-background-default-dodge hover:text-text-secondary hover:shadow-xs hover:shadow-shadow-shadow-3 focus-visible:bg-background-default-dodge focus-visible:text-text-secondary focus-visible:shadow-xs focus-visible:shadow-shadow-shadow-3'
const actionIconClassName = 'size-4 shrink-0 text-text-tertiary group-hover:text-text-secondary group-focus-visible:text-text-secondary'
type CreateAppCardProps = {
className?: string
isLoading?: boolean
@ -68,28 +70,31 @@ const CreateAppCard = ({
<div
ref={ref}
className={cn(
'relative col-span-1 inline-flex h-41.5 flex-col justify-between rounded-xl border-[0.5px] border-components-card-border bg-components-card-bg transition-opacity',
'relative col-span-1 inline-flex h-41.5 flex-col overflow-hidden rounded-xl bg-background-default-dimmed transition-opacity',
isLoading && 'pointer-events-none opacity-50',
className,
)}
>
<div className="grow rounded-t-xl p-2">
<div className="px-6 pt-2 pb-1 text-xs leading-[18px] font-medium text-text-tertiary">{t('createApp', { ns: 'app' })}</div>
<button type="button" className="mb-1 flex w-full cursor-pointer items-center rounded-lg px-6 py-[7px] text-[13px] leading-[18px] font-medium text-text-tertiary hover:bg-state-base-hover hover:text-text-secondary" onClick={() => setShowNewAppModal(true)}>
<FilePlus01 className="mr-2 h-4 w-4 shrink-0" />
{t('newApp.startFromBlank', { ns: 'app' })}
</button>
<button type="button" className="flex w-full cursor-pointer items-center rounded-lg px-6 py-[7px] text-[13px] leading-[18px] font-medium text-text-tertiary hover:bg-state-base-hover hover:text-text-secondary" onClick={() => setShowNewAppTemplateDialog(true)}>
<FilePlus02 className="mr-2 h-4 w-4 shrink-0" />
{t('newApp.startFromTemplate', { ns: 'app' })}
</button>
<div className="flex min-h-0 grow flex-col justify-center p-2">
<div className="flex w-full flex-col gap-0.5">
<button type="button" className={actionButtonClassName} onClick={() => setShowNewAppModal(true)}>
<span aria-hidden="true" className={cn('i-ri-sticky-note-add-line', actionIconClassName)} />
<span className="min-w-0 grow truncate">{t('newApp.startFromBlank', { ns: 'app' })}</span>
</button>
<button type="button" className={actionButtonClassName} onClick={() => setShowNewAppTemplateDialog(true)}>
<span aria-hidden="true" className={cn('i-ri-function-add-line', actionIconClassName)} />
<span className="min-w-0 grow truncate">{t('newApp.startFromTemplate', { ns: 'app' })}</span>
</button>
</div>
</div>
<div className="flex shrink-0 items-center border-t-[0.5px] border-divider-subtle p-2">
<button
type="button"
onClick={() => setShowCreateFromDSLModal(true)}
className="flex w-full cursor-pointer items-center rounded-lg px-6 py-[7px] text-[13px] leading-[18px] font-medium text-text-tertiary hover:bg-state-base-hover hover:text-text-secondary"
className={actionButtonClassName}
>
<FileArrow01 className="mr-2 h-4 w-4 shrink-0" />
{t('importDSL', { ns: 'app' })}
<span aria-hidden="true" className={cn('i-ri-file-upload-line', actionIconClassName)} />
<span className="min-w-0 grow truncate">{t('importDSL', { ns: 'app' })}</span>
</button>
</div>