mirror of
https://github.com/langgenius/dify.git
synced 2026-05-02 16:38:04 +08:00
fix(web): quadrant matrix i18n
This commit is contained in:
@ -3,6 +3,7 @@ import type { FC } from 'react'
|
||||
import type { QuadrantData } from './types'
|
||||
import { RiExpandDiagonalLine } from '@remixicon/react'
|
||||
import { useCallback, useMemo, useState } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import ActionButton from '@/app/components/base/action-button'
|
||||
import FullScreenModal from '@/app/components/base/fullscreen-modal'
|
||||
import QuadrantCard from './quadrant-card'
|
||||
@ -13,6 +14,7 @@ type QuadrantMatrixProps = {
|
||||
}
|
||||
|
||||
const QuadrantMatrix: FC<QuadrantMatrixProps> = ({ content }) => {
|
||||
const { t } = useTranslation()
|
||||
const [isExpanded, setIsExpanded] = useState(false)
|
||||
|
||||
const parsedData = useMemo<QuadrantData | null>(() => {
|
||||
@ -42,9 +44,9 @@ const QuadrantMatrix: FC<QuadrantMatrixProps> = ({ content }) => {
|
||||
return (
|
||||
<div className="flex items-center justify-center rounded-xl bg-components-panel-bg-blur p-8">
|
||||
<div className="text-center text-text-secondary">
|
||||
<div className="system-md-semibold mb-2">Invalid Quadrant Data</div>
|
||||
<div className="system-md-semibold mb-2">{t('quadrantMatrix.invalidData', { ns: 'app' })}</div>
|
||||
<div className="text-sm text-text-tertiary">
|
||||
Expected JSON format with q1, q2, q3, q4 arrays
|
||||
{t('quadrantMatrix.invalidDataDesc', { ns: 'app' })}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -93,30 +95,17 @@ const QuadrantMatrix: FC<QuadrantMatrixProps> = ({ content }) => {
|
||||
<div className="mb-4 flex items-center justify-between">
|
||||
<div>
|
||||
<div className="system-md-semibold text-text-primary">
|
||||
Eisenhower Matrix
|
||||
{t('quadrantMatrix.title', { ns: 'app' })}
|
||||
</div>
|
||||
<div className="text-xs text-text-tertiary">
|
||||
{totalTasks}
|
||||
{' '}
|
||||
task
|
||||
{totalTasks !== 1 ? 's' : ''}
|
||||
{' '}
|
||||
prioritized
|
||||
{t('quadrantMatrix.taskCount', { ns: 'app', count: totalTasks })}
|
||||
</div>
|
||||
</div>
|
||||
{/* Legend + Expand Button */}
|
||||
<div className="flex items-center gap-3">
|
||||
<div className="flex items-center gap-3 text-[11px] text-text-quaternary">
|
||||
<span>
|
||||
<span className="font-medium text-blue-600">I</span>
|
||||
{' '}
|
||||
= Importance
|
||||
</span>
|
||||
<span>
|
||||
<span className="font-medium text-orange-500">U</span>
|
||||
{' '}
|
||||
= Urgency
|
||||
</span>
|
||||
<span>{t('quadrantMatrix.legend.importance', { ns: 'app' })}</span>
|
||||
<span>{t('quadrantMatrix.legend.urgency', { ns: 'app' })}</span>
|
||||
</div>
|
||||
<ActionButton onClick={handleExpand}>
|
||||
<RiExpandDiagonalLine className="h-4 w-4" />
|
||||
@ -139,28 +128,15 @@ const QuadrantMatrix: FC<QuadrantMatrixProps> = ({ content }) => {
|
||||
<div className="mb-6 flex items-center justify-between">
|
||||
<div>
|
||||
<div className="text-xl font-semibold text-text-primary">
|
||||
Eisenhower Matrix
|
||||
{t('quadrantMatrix.title', { ns: 'app' })}
|
||||
</div>
|
||||
<div className="text-sm text-text-tertiary">
|
||||
{totalTasks}
|
||||
{' '}
|
||||
task
|
||||
{totalTasks !== 1 ? 's' : ''}
|
||||
{' '}
|
||||
prioritized
|
||||
{t('quadrantMatrix.taskCount', { ns: 'app', count: totalTasks })}
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex items-center gap-3 text-sm text-text-quaternary">
|
||||
<span>
|
||||
<span className="font-medium text-blue-600">I</span>
|
||||
{' '}
|
||||
= Importance
|
||||
</span>
|
||||
<span>
|
||||
<span className="font-medium text-orange-500">U</span>
|
||||
{' '}
|
||||
= Urgency
|
||||
</span>
|
||||
<span>{t('quadrantMatrix.legend.importance', { ns: 'app' })}</span>
|
||||
<span>{t('quadrantMatrix.legend.urgency', { ns: 'app' })}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
'use client'
|
||||
import type { FC } from 'react'
|
||||
import type { QuadrantConfig, Task } from './types'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { cn } from '@/utils/classnames'
|
||||
import TaskItem from './task-item'
|
||||
|
||||
@ -17,7 +18,8 @@ const QuadrantCard: FC<QuadrantCardProps> = ({
|
||||
expanded = false,
|
||||
maxDisplay = 3,
|
||||
}) => {
|
||||
const { number, title, subtitle, bgClass, borderClass, titleClass } = config
|
||||
const { t } = useTranslation()
|
||||
const { number, titleKey, subtitleKey, bgClass, borderClass, titleClass } = config
|
||||
const displayLimit = expanded ? Infinity : maxDisplay
|
||||
const displayTasks = tasks.slice(0, displayLimit)
|
||||
const remainingCount = Math.max(0, tasks.length - displayLimit)
|
||||
@ -43,14 +45,14 @@ const QuadrantCard: FC<QuadrantCardProps> = ({
|
||||
>
|
||||
{number}
|
||||
</span>
|
||||
<span className={cn('system-sm-semibold', titleClass)}>{title}</span>
|
||||
<span className={cn('system-sm-semibold', titleClass)}>{t(titleKey, { ns: 'app' })}</span>
|
||||
{tasks.length > 0 && (
|
||||
<span className="bg-components-badge-bg-gray rounded-full px-1.5 py-0.5 text-[10px] font-medium text-text-tertiary">
|
||||
{tasks.length}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
<div className="text-[11px] text-text-tertiary">{subtitle}</div>
|
||||
<div className="text-[11px] text-text-tertiary">{t(subtitleKey, { ns: 'app' })}</div>
|
||||
</div>
|
||||
|
||||
{/* Task List */}
|
||||
@ -61,17 +63,28 @@ const QuadrantCard: FC<QuadrantCardProps> = ({
|
||||
>
|
||||
{displayTasks.length > 0
|
||||
? (
|
||||
displayTasks.map((task, index) => (
|
||||
<TaskItem
|
||||
key={`${task.name}-${index}`}
|
||||
task={task}
|
||||
expanded={expanded}
|
||||
/>
|
||||
))
|
||||
displayTasks.map((task) => {
|
||||
const taskKey = [
|
||||
task.name,
|
||||
task.deadline ?? 'no-deadline',
|
||||
task.importance_score,
|
||||
task.urgency_score,
|
||||
task.description ?? '',
|
||||
task.action_advice ?? '',
|
||||
].join('|')
|
||||
|
||||
return (
|
||||
<TaskItem
|
||||
key={taskKey}
|
||||
task={task}
|
||||
expanded={expanded}
|
||||
/>
|
||||
)
|
||||
})
|
||||
)
|
||||
: (
|
||||
<div className="flex flex-1 items-center justify-center text-xs text-text-quaternary">
|
||||
No tasks
|
||||
{t('quadrantMatrix.noTasks', { ns: 'app' })}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
@ -79,10 +92,7 @@ const QuadrantCard: FC<QuadrantCardProps> = ({
|
||||
{/* More indicator (only in non-expanded mode) */}
|
||||
{!expanded && remainingCount > 0 && (
|
||||
<div className="mt-2 shrink-0 text-center text-[11px] text-text-tertiary">
|
||||
+
|
||||
{remainingCount}
|
||||
{' '}
|
||||
more
|
||||
{t('quadrantMatrix.more', { ns: 'app', count: remainingCount })}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
@ -2,6 +2,7 @@
|
||||
import type { FC } from 'react'
|
||||
import type { Task } from './types'
|
||||
import { RiCalendarLine } from '@remixicon/react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { cn } from '@/utils/classnames'
|
||||
|
||||
type TaskItemProps = {
|
||||
@ -11,6 +12,7 @@ type TaskItemProps = {
|
||||
}
|
||||
|
||||
const TaskItem: FC<TaskItemProps> = ({ task, expanded = false, showScores = true }) => {
|
||||
const { t } = useTranslation()
|
||||
const { name, description, deadline, importance_score, urgency_score, action_advice } = task
|
||||
|
||||
return (
|
||||
@ -57,7 +59,8 @@ const TaskItem: FC<TaskItemProps> = ({ task, expanded = false, showScores = true
|
||||
<span className="bg-components-badge-bg-gray inline-flex items-center gap-1 rounded px-1.5 py-0.5 text-[10px] text-text-tertiary">
|
||||
<RiCalendarLine className="h-3 w-3" />
|
||||
<span>
|
||||
DDL:
|
||||
{t('quadrantMatrix.deadline', { ns: 'app' })}
|
||||
{' '}
|
||||
{deadline}
|
||||
</span>
|
||||
</span>
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
/**
|
||||
* Type definitions for Eisenhower Matrix (Task Quadrant) visualization
|
||||
*/
|
||||
import type { I18nKeysWithPrefix } from '@/types/i18n'
|
||||
|
||||
export type Task = {
|
||||
name: string
|
||||
@ -18,11 +19,15 @@ export type QuadrantData = {
|
||||
q4: Task[] // Not Urgent & Not Important - Don't Do
|
||||
}
|
||||
|
||||
type QuadrantKeyBase = I18nKeysWithPrefix<'app', 'quadrantMatrix.q'>
|
||||
type QuadrantTitleKey = Extract<QuadrantKeyBase, `${string}.title`>
|
||||
type QuadrantSubtitleKey = Extract<QuadrantKeyBase, `${string}.subtitle`>
|
||||
|
||||
export type QuadrantConfig = {
|
||||
key: 'q1' | 'q2' | 'q3' | 'q4'
|
||||
number: number
|
||||
title: string
|
||||
subtitle: string
|
||||
titleKey: QuadrantTitleKey // i18n key for title
|
||||
subtitleKey: QuadrantSubtitleKey // i18n key for subtitle
|
||||
bgClass: string
|
||||
borderClass: string
|
||||
titleClass: string
|
||||
@ -35,8 +40,8 @@ export const QUADRANT_CONFIGS: Record<string, QuadrantConfig> = {
|
||||
q1: {
|
||||
key: 'q1',
|
||||
number: 1,
|
||||
title: 'Do First',
|
||||
subtitle: 'Urgent & Important',
|
||||
titleKey: 'quadrantMatrix.q1.title',
|
||||
subtitleKey: 'quadrantMatrix.q1.subtitle',
|
||||
bgClass: 'bg-state-destructive-hover',
|
||||
borderClass: 'border-state-destructive-border',
|
||||
titleClass: 'text-text-destructive',
|
||||
@ -44,8 +49,8 @@ export const QUADRANT_CONFIGS: Record<string, QuadrantConfig> = {
|
||||
q2: {
|
||||
key: 'q2',
|
||||
number: 2,
|
||||
title: 'Schedule',
|
||||
subtitle: 'Important & Not Urgent',
|
||||
titleKey: 'quadrantMatrix.q2.title',
|
||||
subtitleKey: 'quadrantMatrix.q2.subtitle',
|
||||
bgClass: 'bg-state-accent-hover',
|
||||
borderClass: 'border-state-accent-border',
|
||||
titleClass: 'text-text-accent',
|
||||
@ -53,8 +58,8 @@ export const QUADRANT_CONFIGS: Record<string, QuadrantConfig> = {
|
||||
q3: {
|
||||
key: 'q3',
|
||||
number: 3,
|
||||
title: 'Delegate',
|
||||
subtitle: 'Urgent & Not Important',
|
||||
titleKey: 'quadrantMatrix.q3.title',
|
||||
subtitleKey: 'quadrantMatrix.q3.subtitle',
|
||||
bgClass: 'bg-state-warning-hover',
|
||||
borderClass: 'border-state-warning-border',
|
||||
titleClass: 'text-text-warning',
|
||||
@ -62,8 +67,8 @@ export const QUADRANT_CONFIGS: Record<string, QuadrantConfig> = {
|
||||
q4: {
|
||||
key: 'q4',
|
||||
number: 4,
|
||||
title: 'Don\'t Do',
|
||||
subtitle: 'Not Urgent & Not Important',
|
||||
titleKey: 'quadrantMatrix.q4.title',
|
||||
subtitleKey: 'quadrantMatrix.q4.subtitle',
|
||||
bgClass: 'bg-components-panel-on-panel-item-bg',
|
||||
borderClass: 'border-divider-regular',
|
||||
titleClass: 'text-text-tertiary',
|
||||
|
||||
@ -196,6 +196,24 @@
|
||||
"publishApp.notSet": "Not set",
|
||||
"publishApp.notSetDesc": "Currently nobody can access the web app. Please set permissions.",
|
||||
"publishApp.title": "Who can access web app",
|
||||
"quadrantMatrix.deadline": "DDL:",
|
||||
"quadrantMatrix.invalidData": "Invalid Quadrant Data",
|
||||
"quadrantMatrix.invalidDataDesc": "Expected JSON format with q1, q2, q3, q4 arrays",
|
||||
"quadrantMatrix.legend.importance": "I = Importance",
|
||||
"quadrantMatrix.legend.urgency": "U = Urgency",
|
||||
"quadrantMatrix.more": "+{{count}} more",
|
||||
"quadrantMatrix.noTasks": "No tasks",
|
||||
"quadrantMatrix.q1.subtitle": "Urgent & Important",
|
||||
"quadrantMatrix.q1.title": "Do First",
|
||||
"quadrantMatrix.q2.subtitle": "Important & Not Urgent",
|
||||
"quadrantMatrix.q2.title": "Schedule",
|
||||
"quadrantMatrix.q3.subtitle": "Urgent & Not Important",
|
||||
"quadrantMatrix.q3.title": "Delegate",
|
||||
"quadrantMatrix.q4.subtitle": "Not Urgent & Not Important",
|
||||
"quadrantMatrix.q4.title": "Don't Do",
|
||||
"quadrantMatrix.taskCount_one": "{{count}} task prioritized",
|
||||
"quadrantMatrix.taskCount_other": "{{count}} tasks prioritized",
|
||||
"quadrantMatrix.title": "Eisenhower Matrix",
|
||||
"removeOriginal": "Delete the original app",
|
||||
"roadmap": "See our roadmap",
|
||||
"showMyCreatedAppsOnly": "Created by me",
|
||||
|
||||
@ -196,6 +196,24 @@
|
||||
"publishApp.notSet": "未设置",
|
||||
"publishApp.notSetDesc": "当前任何人都无法访问 Web 应用。请设置访问权限。",
|
||||
"publishApp.title": "谁可以访问 web 应用",
|
||||
"quadrantMatrix.deadline": "截止:",
|
||||
"quadrantMatrix.invalidData": "无效的象限数据",
|
||||
"quadrantMatrix.invalidDataDesc": "需要包含 q1, q2, q3, q4 数组的 JSON 格式",
|
||||
"quadrantMatrix.legend.importance": "I = 重要性",
|
||||
"quadrantMatrix.legend.urgency": "U = 紧急性",
|
||||
"quadrantMatrix.more": "+{{count}} 更多",
|
||||
"quadrantMatrix.noTasks": "暂无任务",
|
||||
"quadrantMatrix.q1.subtitle": "紧急且重要",
|
||||
"quadrantMatrix.q1.title": "立即执行",
|
||||
"quadrantMatrix.q2.subtitle": "重要但不紧急",
|
||||
"quadrantMatrix.q2.title": "计划安排",
|
||||
"quadrantMatrix.q3.subtitle": "紧急但不重要",
|
||||
"quadrantMatrix.q3.title": "委派他人",
|
||||
"quadrantMatrix.q4.subtitle": "不紧急也不重要",
|
||||
"quadrantMatrix.q4.title": "不要做",
|
||||
"quadrantMatrix.taskCount_one": "{{count}} 个任务已排序",
|
||||
"quadrantMatrix.taskCount_other": "{{count}} 个任务已排序",
|
||||
"quadrantMatrix.title": "艾森豪威尔矩阵",
|
||||
"removeOriginal": "删除原应用",
|
||||
"roadmap": "产品路线图",
|
||||
"showMyCreatedAppsOnly": "我创建的",
|
||||
|
||||
Reference in New Issue
Block a user