Improve business profile branding uploads and super-admin link menus.
Show separate light/dark logo and favicon croppers in a compact grid, support favicon saves, and keep super-admin overflow dashboard links in English. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
co-authored by
Cursor
parent
5e799eddf9
commit
468bb87fcf
@@ -172,3 +172,45 @@
|
|||||||
.changeBtn:hover {
|
.changeBtn:hover {
|
||||||
background: rgba(var(--primary-rgb) / 0.08);
|
background: rgba(var(--primary-rgb) / 0.08);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.compact .preview,
|
||||||
|
.compact .uploadZone,
|
||||||
|
.compact .cropArea {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.compact .cropPanel {
|
||||||
|
width: 100%;
|
||||||
|
max-width: none;
|
||||||
|
margin-inline: 0;
|
||||||
|
align-self: stretch;
|
||||||
|
}
|
||||||
|
|
||||||
|
.compact .changeBtn {
|
||||||
|
align-self: stretch;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.compact .uploadZone {
|
||||||
|
gap: 4px;
|
||||||
|
font-size: 11px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.compact .hint {
|
||||||
|
font-size: 10px;
|
||||||
|
text-align: center;
|
||||||
|
line-height: 1.3;
|
||||||
|
}
|
||||||
|
|
||||||
|
.compact .changeBtn {
|
||||||
|
display: flex;
|
||||||
|
padding: 6px 10px;
|
||||||
|
font-size: 11px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.compact .removeBtn {
|
||||||
|
top: 4px;
|
||||||
|
right: 4px;
|
||||||
|
width: 22px;
|
||||||
|
height: 22px;
|
||||||
|
}
|
||||||
|
|||||||
@@ -15,6 +15,8 @@ interface ImageCropperProps {
|
|||||||
uploadLabel?: string
|
uploadLabel?: string
|
||||||
hint?: string
|
hint?: string
|
||||||
changeLabel?: string
|
changeLabel?: string
|
||||||
|
/** Smaller upload/preview frame for narrow grid columns. */
|
||||||
|
compact?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
export function ImageCropper({
|
export function ImageCropper({
|
||||||
@@ -26,6 +28,7 @@ export function ImageCropper({
|
|||||||
uploadLabel,
|
uploadLabel,
|
||||||
hint,
|
hint,
|
||||||
changeLabel,
|
changeLabel,
|
||||||
|
compact = false,
|
||||||
}: ImageCropperProps) {
|
}: ImageCropperProps) {
|
||||||
const t = useT()
|
const t = useT()
|
||||||
const resolvedUploadLabel = uploadLabel ?? t('products.form.thumbnailUpload')
|
const resolvedUploadLabel = uploadLabel ?? t('products.form.thumbnailUpload')
|
||||||
@@ -81,7 +84,14 @@ export function ImageCropper({
|
|||||||
|
|
||||||
const isPortrait = aspect < 1
|
const isPortrait = aspect < 1
|
||||||
const maxHeight = isPortrait ? 'min(360px, 42vh)' : 'min(280px, 36vh)'
|
const maxHeight = isPortrait ? 'min(360px, 42vh)' : 'min(280px, 36vh)'
|
||||||
const frameStyle: React.CSSProperties = {
|
const frameStyle: React.CSSProperties = compact
|
||||||
|
? {
|
||||||
|
aspectRatio: String(aspect),
|
||||||
|
width: '100%',
|
||||||
|
height: 'auto',
|
||||||
|
minHeight: 0,
|
||||||
|
}
|
||||||
|
: {
|
||||||
aspectRatio: String(aspect),
|
aspectRatio: String(aspect),
|
||||||
width: `min(100%, calc(${maxHeight} * ${aspect}))`,
|
width: `min(100%, calc(${maxHeight} * ${aspect}))`,
|
||||||
height: 'auto',
|
height: 'auto',
|
||||||
@@ -92,7 +102,7 @@ export function ImageCropper({
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={styles.wrapper}>
|
<div className={`${styles.wrapper} ${compact ? styles.compact : ''}`}>
|
||||||
{value && !imageSrc && (
|
{value && !imageSrc && (
|
||||||
<div className={styles.preview} style={frameStyle}>
|
<div className={styles.preview} style={frameStyle}>
|
||||||
<img src={value} alt={resolvedUploadLabel} className={styles.previewImg} />
|
<img src={value} alt={resolvedUploadLabel} className={styles.previewImg} />
|
||||||
@@ -109,7 +119,7 @@ export function ImageCropper({
|
|||||||
|
|
||||||
{!value && !imageSrc && (
|
{!value && !imageSrc && (
|
||||||
<label className={styles.uploadZone} style={frameStyle}>
|
<label className={styles.uploadZone} style={frameStyle}>
|
||||||
<ImagePlus size={28} />
|
<ImagePlus size={compact ? 20 : 28} />
|
||||||
<span>{resolvedUploadLabel}</span>
|
<span>{resolvedUploadLabel}</span>
|
||||||
<span className={styles.hint}>{resolvedHint}</span>
|
<span className={styles.hint}>{resolvedHint}</span>
|
||||||
<input type="file" accept={accept} onChange={handleFile} hidden />
|
<input type="file" accept={accept} onChange={handleFile} hidden />
|
||||||
|
|||||||
@@ -147,9 +147,12 @@ const en = {
|
|||||||
'bizProfile.logo.upload': 'Upload logo',
|
'bizProfile.logo.upload': 'Upload logo',
|
||||||
'bizProfile.logo.hint': 'Transparent PNG recommended',
|
'bizProfile.logo.hint': 'Transparent PNG recommended',
|
||||||
'bizProfile.logo.change': 'Change logo',
|
'bizProfile.logo.change': 'Change logo',
|
||||||
'bizProfile.logo.light': 'Light mode',
|
'bizProfile.logo.lightTheme': 'Logo for light theme',
|
||||||
'bizProfile.logo.dark': 'Dark mode',
|
'bizProfile.logo.darkTheme': 'Logo for dark theme',
|
||||||
'bizProfile.logo.modeSwitch': 'Logo for light or dark mode',
|
'bizProfile.favicon': 'Favicon',
|
||||||
|
'bizProfile.favicon.upload': 'Upload favicon',
|
||||||
|
'bizProfile.favicon.hint': 'Square PNG recommended',
|
||||||
|
'bizProfile.favicon.change': 'Change favicon',
|
||||||
'bizProfile.categories': 'Activity categories',
|
'bizProfile.categories': 'Activity categories',
|
||||||
'bizProfile.categories.placeholder': 'Select activity categories',
|
'bizProfile.categories.placeholder': 'Select activity categories',
|
||||||
'bizProfile.nameFa': 'Name (FA)',
|
'bizProfile.nameFa': 'Name (FA)',
|
||||||
@@ -2384,9 +2387,12 @@ const fa: Record<MessageKey, string> = {
|
|||||||
'bizProfile.logo.upload': 'آپلود لوگو',
|
'bizProfile.logo.upload': 'آپلود لوگو',
|
||||||
'bizProfile.logo.hint': 'PNG شفاف توصیه میشود',
|
'bizProfile.logo.hint': 'PNG شفاف توصیه میشود',
|
||||||
'bizProfile.logo.change': 'تغییر لوگو',
|
'bizProfile.logo.change': 'تغییر لوگو',
|
||||||
'bizProfile.logo.light': 'حالت روشن',
|
'bizProfile.logo.lightTheme': 'لوگو در تم روشن',
|
||||||
'bizProfile.logo.dark': 'حالت تیره',
|
'bizProfile.logo.darkTheme': 'لوگو در تم تیره',
|
||||||
'bizProfile.logo.modeSwitch': 'لوگوی حالت روشن یا تیره',
|
'bizProfile.favicon': 'فاوآیکن',
|
||||||
|
'bizProfile.favicon.upload': 'آپلود فاوآیکن',
|
||||||
|
'bizProfile.favicon.hint': 'PNG مربعی توصیه میشود',
|
||||||
|
'bizProfile.favicon.change': 'تغییر فاوآیکن',
|
||||||
'bizProfile.categories': 'دستهبندیهای فعالیت',
|
'bizProfile.categories': 'دستهبندیهای فعالیت',
|
||||||
'bizProfile.categories.placeholder': 'انتخاب دستهبندیهای فعالیت',
|
'bizProfile.categories.placeholder': 'انتخاب دستهبندیهای فعالیت',
|
||||||
'bizProfile.nameFa': 'نام (فارسی)',
|
'bizProfile.nameFa': 'نام (فارسی)',
|
||||||
|
|||||||
@@ -40,28 +40,21 @@
|
|||||||
margin-bottom: 0;
|
margin-bottom: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.logoCol {
|
.logoLightCol,
|
||||||
|
.logoDarkCol,
|
||||||
|
.faviconCol {
|
||||||
grid-column: span 12;
|
grid-column: span 12;
|
||||||
}
|
min-width: 0;
|
||||||
|
|
||||||
.logoModeRow {
|
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
flex-direction: column;
|
||||||
justify-content: center;
|
|
||||||
gap: 10px;
|
|
||||||
margin-bottom: 10px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.logoModeLabel {
|
.mediaFieldLabel {
|
||||||
|
display: block;
|
||||||
|
margin-bottom: 8px;
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
font-weight: 500;
|
|
||||||
color: var(--text-muted);
|
|
||||||
transition: color 0.15s;
|
|
||||||
}
|
|
||||||
|
|
||||||
.logoModeLabelActive {
|
|
||||||
color: var(--text-primary);
|
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
|
color: var(--text-secondary);
|
||||||
}
|
}
|
||||||
|
|
||||||
.basicAside {
|
.basicAside {
|
||||||
@@ -70,6 +63,7 @@
|
|||||||
grid-template-columns: repeat(12, 1fr);
|
grid-template-columns: repeat(12, 1fr);
|
||||||
gap: 12px 16px;
|
gap: 12px 16px;
|
||||||
align-content: start;
|
align-content: start;
|
||||||
|
min-width: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.fullRow {
|
.fullRow {
|
||||||
@@ -233,12 +227,20 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
@media (min-width: 1280px) {
|
@media (min-width: 1280px) {
|
||||||
.logoCol {
|
.logoLightCol {
|
||||||
grid-column: span 2;
|
grid-column: span 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.logoDarkCol {
|
||||||
|
grid-column: span 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.faviconCol {
|
||||||
|
grid-column: span 1;
|
||||||
|
}
|
||||||
|
|
||||||
.basicAside {
|
.basicAside {
|
||||||
grid-column: span 10;
|
grid-column: span 7;
|
||||||
}
|
}
|
||||||
|
|
||||||
.halfRow {
|
.halfRow {
|
||||||
|
|||||||
@@ -14,7 +14,6 @@ import { PageTitle } from '../components/PageTitle'
|
|||||||
import { ImageCropper } from '../components/ImageCropper'
|
import { ImageCropper } from '../components/ImageCropper'
|
||||||
import { MultiSelectDropdown } from '../components/MultiSelectDropdown'
|
import { MultiSelectDropdown } from '../components/MultiSelectDropdown'
|
||||||
import { RichTextEditor } from '../components/RichTextEditor'
|
import { RichTextEditor } from '../components/RichTextEditor'
|
||||||
import { Switch } from '../components/Switch'
|
|
||||||
import { useToast } from '../context/ToastContext'
|
import { useToast } from '../context/ToastContext'
|
||||||
import { useT } from '../i18n/useT'
|
import { useT } from '../i18n/useT'
|
||||||
import { ApiError } from '../lib/api'
|
import { ApiError } from '../lib/api'
|
||||||
@@ -83,7 +82,8 @@ export function BusinessProfilePage() {
|
|||||||
const [logoMediaId, setLogoMediaId] = useState<string | null>(null)
|
const [logoMediaId, setLogoMediaId] = useState<string | null>(null)
|
||||||
const [logoDark, setLogoDark] = useState<string | null>(null)
|
const [logoDark, setLogoDark] = useState<string | null>(null)
|
||||||
const [logoDarkMediaId, setLogoDarkMediaId] = useState<string | null>(null)
|
const [logoDarkMediaId, setLogoDarkMediaId] = useState<string | null>(null)
|
||||||
const [logoModeDark, setLogoModeDark] = useState(false)
|
const [favicon, setFavicon] = useState<string | null>(null)
|
||||||
|
const [faviconMediaId, setFaviconMediaId] = useState<string | null>(null)
|
||||||
const [addresses, setAddresses] = useState<AddressDraft[]>([createEmptyAddressItem()])
|
const [addresses, setAddresses] = useState<AddressDraft[]>([createEmptyAddressItem()])
|
||||||
const [phoneNumbers, setPhoneNumbers] = useState<BusinessPhoneNumber[]>([
|
const [phoneNumbers, setPhoneNumbers] = useState<BusinessPhoneNumber[]>([
|
||||||
createEmptyPhone(),
|
createEmptyPhone(),
|
||||||
@@ -159,6 +159,10 @@ export function BusinessProfilePage() {
|
|||||||
setLogoMediaId(profileData.profile.logoMediaId)
|
setLogoMediaId(profileData.profile.logoMediaId)
|
||||||
setLogoDark(profileData.profile.logoDarkUrl)
|
setLogoDark(profileData.profile.logoDarkUrl)
|
||||||
setLogoDarkMediaId(profileData.profile.logoDarkMediaId)
|
setLogoDarkMediaId(profileData.profile.logoDarkMediaId)
|
||||||
|
setFavicon(
|
||||||
|
profileData.profile.faviconMediaId ? profileData.profile.faviconUrl : null,
|
||||||
|
)
|
||||||
|
setFaviconMediaId(profileData.profile.faviconMediaId)
|
||||||
|
|
||||||
const nextAddresses =
|
const nextAddresses =
|
||||||
profileData.addresses.length > 0
|
profileData.addresses.length > 0
|
||||||
@@ -284,6 +288,11 @@ export function BusinessProfilePage() {
|
|||||||
'business-logo-dark.png',
|
'business-logo-dark.png',
|
||||||
logoDarkMediaId,
|
logoDarkMediaId,
|
||||||
)
|
)
|
||||||
|
const nextFaviconMediaId = await resolveDataUrlToMediaId(
|
||||||
|
favicon,
|
||||||
|
'business-favicon.png',
|
||||||
|
faviconMediaId,
|
||||||
|
)
|
||||||
|
|
||||||
const payloadAddresses = addresses
|
const payloadAddresses = addresses
|
||||||
.filter(
|
.filter(
|
||||||
@@ -321,6 +330,7 @@ export function BusinessProfilePage() {
|
|||||||
socialMedia,
|
socialMedia,
|
||||||
logoMediaId: nextLogoMediaId,
|
logoMediaId: nextLogoMediaId,
|
||||||
logoDarkMediaId: nextLogoDarkMediaId,
|
logoDarkMediaId: nextLogoDarkMediaId,
|
||||||
|
faviconMediaId: nextFaviconMediaId,
|
||||||
categoryIds,
|
categoryIds,
|
||||||
addresses: payloadAddresses,
|
addresses: payloadAddresses,
|
||||||
})
|
})
|
||||||
@@ -368,29 +378,12 @@ export function BusinessProfilePage() {
|
|||||||
<section className={styles.section}>
|
<section className={styles.section}>
|
||||||
<h3 className={styles.sectionTitle}>{t('bizProfile.section.basic')}</h3>
|
<h3 className={styles.sectionTitle}>{t('bizProfile.section.basic')}</h3>
|
||||||
<div className={formStyles.formGrid}>
|
<div className={formStyles.formGrid}>
|
||||||
<div className={`${formStyles.field} ${styles.logoCol}`}>
|
<div className={`${formStyles.field} ${styles.logoLightCol}`}>
|
||||||
<label>{t('bizProfile.logo')}</label>
|
<label className={styles.mediaFieldLabel}>{t('bizProfile.logo.lightTheme')}</label>
|
||||||
<div className={styles.logoModeRow}>
|
|
||||||
<span
|
|
||||||
className={`${styles.logoModeLabel} ${!logoModeDark ? styles.logoModeLabelActive : ''}`}
|
|
||||||
>
|
|
||||||
{t('bizProfile.logo.light')}
|
|
||||||
</span>
|
|
||||||
<Switch
|
|
||||||
checked={logoModeDark}
|
|
||||||
onChange={setLogoModeDark}
|
|
||||||
aria-label={t('bizProfile.logo.modeSwitch')}
|
|
||||||
/>
|
|
||||||
<span
|
|
||||||
className={`${styles.logoModeLabel} ${logoModeDark ? styles.logoModeLabelActive : ''}`}
|
|
||||||
>
|
|
||||||
{t('bizProfile.logo.dark')}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
<ImageCropper
|
<ImageCropper
|
||||||
key={logoModeDark ? 'logo-dark' : 'logo-light'}
|
compact
|
||||||
value={logoModeDark ? logoDark : logo}
|
value={logo}
|
||||||
onChange={logoModeDark ? setLogoDark : setLogo}
|
onChange={setLogo}
|
||||||
outputFormat="png"
|
outputFormat="png"
|
||||||
accept="image/png"
|
accept="image/png"
|
||||||
uploadLabel={t('bizProfile.logo.upload')}
|
uploadLabel={t('bizProfile.logo.upload')}
|
||||||
@@ -399,6 +392,34 @@ export function BusinessProfilePage() {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div className={`${formStyles.field} ${styles.logoDarkCol}`}>
|
||||||
|
<label className={styles.mediaFieldLabel}>{t('bizProfile.logo.darkTheme')}</label>
|
||||||
|
<ImageCropper
|
||||||
|
compact
|
||||||
|
value={logoDark}
|
||||||
|
onChange={setLogoDark}
|
||||||
|
outputFormat="png"
|
||||||
|
accept="image/png"
|
||||||
|
uploadLabel={t('bizProfile.logo.upload')}
|
||||||
|
hint={t('bizProfile.logo.hint')}
|
||||||
|
changeLabel={t('bizProfile.logo.change')}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className={`${formStyles.field} ${styles.faviconCol}`}>
|
||||||
|
<label className={styles.mediaFieldLabel}>{t('bizProfile.favicon')}</label>
|
||||||
|
<ImageCropper
|
||||||
|
compact
|
||||||
|
value={favicon}
|
||||||
|
onChange={setFavicon}
|
||||||
|
outputFormat="png"
|
||||||
|
accept="image/png"
|
||||||
|
uploadLabel={t('bizProfile.favicon.upload')}
|
||||||
|
hint={t('bizProfile.favicon.hint')}
|
||||||
|
changeLabel={t('bizProfile.favicon.change')}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div className={styles.basicAside}>
|
<div className={styles.basicAside}>
|
||||||
<div className={`${formStyles.field} ${styles.fullRow}`}>
|
<div className={`${formStyles.field} ${styles.fullRow}`}>
|
||||||
<label htmlFor="activity-categories">{t('bizProfile.categories')}</label>
|
<label htmlFor="activity-categories">{t('bizProfile.categories')}</label>
|
||||||
|
|||||||
@@ -59,6 +59,7 @@ export interface UpdateBusinessProfilePayload {
|
|||||||
socialMedia?: Partial<BusinessSocialMedia>
|
socialMedia?: Partial<BusinessSocialMedia>
|
||||||
logoMediaId?: string | null
|
logoMediaId?: string | null
|
||||||
logoDarkMediaId?: string | null
|
logoDarkMediaId?: string | null
|
||||||
|
faviconMediaId?: string | null
|
||||||
categoryIds?: string[]
|
categoryIds?: string[]
|
||||||
addresses?: Array<{
|
addresses?: Array<{
|
||||||
id?: string
|
id?: string
|
||||||
@@ -101,6 +102,12 @@ export async function updateBusinessProfile(payload: UpdateBusinessProfilePayloa
|
|||||||
: payload.logoDarkMediaId
|
: payload.logoDarkMediaId
|
||||||
? Number(payload.logoDarkMediaId)
|
? Number(payload.logoDarkMediaId)
|
||||||
: null,
|
: null,
|
||||||
|
faviconMediaId:
|
||||||
|
payload.faviconMediaId === undefined
|
||||||
|
? undefined
|
||||||
|
: payload.faviconMediaId
|
||||||
|
? Number(payload.faviconMediaId)
|
||||||
|
: null,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -61,21 +61,21 @@ export function BusinessActionsOverflowMenu({
|
|||||||
? ([
|
? ([
|
||||||
{
|
{
|
||||||
key: 'website',
|
key: 'website',
|
||||||
label: 'باز کردن وبسایت',
|
label: 'Open website',
|
||||||
detail: apex,
|
detail: apex,
|
||||||
icon: Globe,
|
icon: Globe,
|
||||||
onClick: () => openHost(apex),
|
onClick: () => openHost(apex),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: 'business',
|
key: 'business',
|
||||||
label: 'داشبورد کسبوکار',
|
label: 'Business dashboard',
|
||||||
detail: `business.${apex}`,
|
detail: `business.${apex}`,
|
||||||
icon: Building2,
|
icon: Building2,
|
||||||
onClick: () => openHost(`business.${apex}`),
|
onClick: () => openHost(`business.${apex}`),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: 'customer',
|
key: 'customer',
|
||||||
label: 'داشبورد مشتری',
|
label: 'Customer dashboard',
|
||||||
detail: `customer.${apex}`,
|
detail: `customer.${apex}`,
|
||||||
icon: UserRound,
|
icon: UserRound,
|
||||||
onClick: () => openHost(`customer.${apex}`),
|
onClick: () => openHost(`customer.${apex}`),
|
||||||
@@ -151,8 +151,8 @@ export function BusinessActionsOverflowMenu({
|
|||||||
e.stopPropagation()
|
e.stopPropagation()
|
||||||
toggleOpen()
|
toggleOpen()
|
||||||
}}
|
}}
|
||||||
title="عملیات بیشتر"
|
title="More actions"
|
||||||
aria-label={`عملیات بیشتر برای ${businessName}`}
|
aria-label={`More actions for ${businessName}`}
|
||||||
aria-haspopup="menu"
|
aria-haspopup="menu"
|
||||||
aria-expanded={open}
|
aria-expanded={open}
|
||||||
>
|
>
|
||||||
@@ -166,9 +166,7 @@ export function BusinessActionsOverflowMenu({
|
|||||||
ref={popoverRef}
|
ref={popoverRef}
|
||||||
className={styles.menu}
|
className={styles.menu}
|
||||||
role="menu"
|
role="menu"
|
||||||
aria-label={`عملیات بیشتر برای ${businessName}`}
|
aria-label={`More actions for ${businessName}`}
|
||||||
lang="fa"
|
|
||||||
dir="rtl"
|
|
||||||
style={{
|
style={{
|
||||||
top: popoverPos.top,
|
top: popoverPos.top,
|
||||||
left: popoverPos.left,
|
left: popoverPos.left,
|
||||||
@@ -206,7 +204,7 @@ export function BusinessActionsOverflowMenu({
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Users size={16} />
|
<Users size={16} />
|
||||||
<span>همه کاربران</span>
|
<span>All users</span>
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
@@ -220,7 +218,7 @@ export function BusinessActionsOverflowMenu({
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Eraser size={16} />
|
<Eraser size={16} />
|
||||||
<span>پاکسازی داده</span>
|
<span>Wipe data</span>
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
@@ -232,7 +230,7 @@ export function BusinessActionsOverflowMenu({
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Trash2 size={16} />
|
<Trash2 size={16} />
|
||||||
<span>حذف</span>
|
<span>Remove</span>
|
||||||
</button>
|
</button>
|
||||||
</div>,
|
</div>,
|
||||||
document.body,
|
document.body,
|
||||||
|
|||||||
@@ -109,21 +109,21 @@ export function DomainLinksOverflowMenu({ host, onRemove }: DomainLinksOverflowM
|
|||||||
const items = [
|
const items = [
|
||||||
{
|
{
|
||||||
key: 'website',
|
key: 'website',
|
||||||
label: 'باز کردن وبسایت',
|
label: 'Open website',
|
||||||
detail: websiteHost,
|
detail: websiteHost,
|
||||||
icon: Globe,
|
icon: Globe,
|
||||||
onClick: () => openHost(websiteHost),
|
onClick: () => openHost(websiteHost),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: 'business',
|
key: 'business',
|
||||||
label: 'داشبورد کسبوکار',
|
label: 'Business dashboard',
|
||||||
detail: businessHost,
|
detail: businessHost,
|
||||||
icon: Building2,
|
icon: Building2,
|
||||||
onClick: () => openHost(businessHost),
|
onClick: () => openHost(businessHost),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: 'customer',
|
key: 'customer',
|
||||||
label: 'داشبورد مشتری',
|
label: 'Customer dashboard',
|
||||||
detail: customerHost,
|
detail: customerHost,
|
||||||
icon: UserRound,
|
icon: UserRound,
|
||||||
onClick: () => openHost(customerHost),
|
onClick: () => openHost(customerHost),
|
||||||
@@ -141,8 +141,8 @@ export function DomainLinksOverflowMenu({ host, onRemove }: DomainLinksOverflowM
|
|||||||
e.stopPropagation()
|
e.stopPropagation()
|
||||||
toggleOpen()
|
toggleOpen()
|
||||||
}}
|
}}
|
||||||
title="عملیات بیشتر"
|
title="More actions"
|
||||||
aria-label={`عملیات بیشتر برای ${apex}`}
|
aria-label={`More actions for ${apex}`}
|
||||||
aria-haspopup="menu"
|
aria-haspopup="menu"
|
||||||
aria-expanded={open}
|
aria-expanded={open}
|
||||||
>
|
>
|
||||||
@@ -156,9 +156,7 @@ export function DomainLinksOverflowMenu({ host, onRemove }: DomainLinksOverflowM
|
|||||||
ref={popoverRef}
|
ref={popoverRef}
|
||||||
className={styles.menu}
|
className={styles.menu}
|
||||||
role="menu"
|
role="menu"
|
||||||
aria-label={`عملیات بیشتر برای ${apex}`}
|
aria-label={`More actions for ${apex}`}
|
||||||
lang="fa"
|
|
||||||
dir="rtl"
|
|
||||||
style={{
|
style={{
|
||||||
top: popoverPos.top,
|
top: popoverPos.top,
|
||||||
left: popoverPos.left,
|
left: popoverPos.left,
|
||||||
@@ -196,7 +194,7 @@ export function DomainLinksOverflowMenu({ host, onRemove }: DomainLinksOverflowM
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Trash2 size={16} />
|
<Trash2 size={16} />
|
||||||
<span>حذف</span>
|
<span>Remove</span>
|
||||||
</button>
|
</button>
|
||||||
</div>,
|
</div>,
|
||||||
document.body,
|
document.body,
|
||||||
|
|||||||
Reference in New Issue
Block a user