Polish business FA layout and wire special-group keys plus SSL sync.
RTL carousels/FABs, special key+title fields, slider gallery fixes, and dashboard SSL sync agent for super-admin. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
co-authored by
Cursor
parent
66004a0fba
commit
672091d1f5
@@ -1,7 +1,9 @@
|
||||
import { Link } from 'react-router-dom'
|
||||
import { ChevronUp, Pencil, MessageSquare, Trash2 } from 'lucide-react'
|
||||
import { useLocale } from '@meshkee/dashboard-ui'
|
||||
import type { Portfolio } from '../types/portfolio'
|
||||
import { formatPortfolioCardDate } from '../services/portfolioService'
|
||||
import { useT } from '../i18n/useT'
|
||||
import { textLocaleAttrs } from '../utils/textLocale'
|
||||
import { Tooltip } from './Tooltip'
|
||||
import cardStyles from './PortfolioCard.module.css'
|
||||
@@ -28,13 +30,21 @@ export function PortfolioCard({
|
||||
onComments,
|
||||
onRemove,
|
||||
}: PortfolioCardProps) {
|
||||
const publishDate = formatPortfolioCardDate(portfolio.publishedAt ?? portfolio.createdAt)
|
||||
const t = useT()
|
||||
const { locale } = useLocale()
|
||||
const isFa = locale === 'fa'
|
||||
const publishDate = formatPortfolioCardDate(
|
||||
portfolio.publishedAt ?? portfolio.createdAt,
|
||||
isFa ? 'fa' : 'en',
|
||||
)
|
||||
const titleFa = (portfolio.titleFa || portfolio.title || '').trim()
|
||||
const titleEn = (portfolio.titleEn || '').trim()
|
||||
const showBothTitles = Boolean(titleFa && titleEn)
|
||||
const showAbstract = !showBothTitles
|
||||
const abstractLocale = textLocaleAttrs(portfolio.abstract)
|
||||
const hasAbstract = Boolean(portfolio.abstract?.trim())
|
||||
// In FA UI, keep cards RTL even when EN titles/abstracts are shown.
|
||||
const abstractDir = isFa ? 'rtl' : abstractLocale.dir
|
||||
|
||||
return (
|
||||
<article className={cardStyles.card}>
|
||||
@@ -52,14 +62,14 @@ export function PortfolioCard({
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className={cardStyles.body}>
|
||||
<div className={cardStyles.body} dir={isFa ? 'rtl' : 'ltr'}>
|
||||
{titleFa ? (
|
||||
<h3 className={`${cardStyles.titleFa} faText`} lang="fa" dir="rtl">
|
||||
{titleFa}
|
||||
</h3>
|
||||
) : null}
|
||||
{titleEn ? (
|
||||
<p className={cardStyles.titleEn} lang="en" dir="ltr">
|
||||
<p className={cardStyles.titleEn} lang="en" dir={isFa ? 'rtl' : 'ltr'}>
|
||||
{titleEn}
|
||||
</p>
|
||||
) : null}
|
||||
@@ -70,13 +80,17 @@ export function PortfolioCard({
|
||||
.filter(Boolean)
|
||||
.join(' ')}
|
||||
lang={abstractLocale.lang}
|
||||
dir={abstractLocale.dir}
|
||||
dir={abstractDir}
|
||||
>
|
||||
{portfolio.abstract}
|
||||
</p>
|
||||
) : (
|
||||
<p className={cardStyles.abstract} lang="en" dir="ltr">
|
||||
No summary yet.
|
||||
<p
|
||||
className={cardStyles.abstract}
|
||||
lang={isFa ? 'fa' : 'en'}
|
||||
dir={isFa ? 'rtl' : 'ltr'}
|
||||
>
|
||||
{t('portfolio.card.noSummary')}
|
||||
</p>
|
||||
)
|
||||
) : null}
|
||||
@@ -93,27 +107,31 @@ export function PortfolioCard({
|
||||
</Link>
|
||||
|
||||
<div className={controlStyles.controls}>
|
||||
<Tooltip label="Move up">
|
||||
<Tooltip label={t('portfolio.card.moveUp')}>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => onMoveUp(portfolio.id)}
|
||||
disabled={!canMoveUp || isMovingUp}
|
||||
aria-label="Move up"
|
||||
aria-label={t('portfolio.card.moveUp')}
|
||||
>
|
||||
<ChevronUp size={16} />
|
||||
</button>
|
||||
</Tooltip>
|
||||
<Tooltip label="Edit portfolio">
|
||||
<button type="button" onClick={() => onEdit(portfolio.id)} aria-label="Edit">
|
||||
<Tooltip label={t('portfolio.card.edit')}>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => onEdit(portfolio.id)}
|
||||
aria-label={t('portfolio.card.edit')}
|
||||
>
|
||||
<Pencil size={16} />
|
||||
</button>
|
||||
</Tooltip>
|
||||
<Tooltip label="View comments">
|
||||
<Tooltip label={t('portfolio.card.comments')}>
|
||||
<button
|
||||
type="button"
|
||||
className={controlStyles.iconBtn}
|
||||
onClick={() => onComments(portfolio.id)}
|
||||
aria-label={`Comments (${commentCount})`}
|
||||
aria-label={`${t('portfolio.card.comments')} (${commentCount})`}
|
||||
>
|
||||
<MessageSquare size={16} />
|
||||
{commentCount > 0 && (
|
||||
@@ -121,12 +139,12 @@ export function PortfolioCard({
|
||||
)}
|
||||
</button>
|
||||
</Tooltip>
|
||||
<Tooltip label="Remove portfolio">
|
||||
<Tooltip label={t('portfolio.card.remove')}>
|
||||
<button
|
||||
type="button"
|
||||
className={controlStyles.danger}
|
||||
onClick={() => onRemove(portfolio.id)}
|
||||
aria-label="Remove"
|
||||
aria-label={t('portfolio.card.remove')}
|
||||
>
|
||||
<Trash2 size={16} />
|
||||
</button>
|
||||
|
||||
Reference in New Issue
Block a user