fix: RTL support for timelines and header dropdown
All checks were successful
Deploy / deploy (push) Successful in 11s
All checks were successful
Deploy / deploy (push) Successful in 11s
- InteractiveTimeline: dir="ltr" on scroll area, i18n for all strings - ArtefactVersionTimeline: text-start, ms-11 logical properties - Header dropdown: end-0 instead of right-0, text-start on menu items - Added 11 new timeline i18n keys (en + ar) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -19,7 +19,7 @@ export default function ArtefactVersionTimeline({ versions, activeVersionId, onS
|
|||||||
<button
|
<button
|
||||||
key={version.Id}
|
key={version.Id}
|
||||||
onClick={() => onSelectVersion(version)}
|
onClick={() => onSelectVersion(version)}
|
||||||
className={`w-full text-left p-3 rounded-lg border transition-colors ${
|
className={`w-full text-start p-3 rounded-lg border transition-colors ${
|
||||||
isActive
|
isActive
|
||||||
? 'border-brand-primary bg-brand-primary/5'
|
? 'border-brand-primary bg-brand-primary/5'
|
||||||
: 'border-border hover:border-brand-primary/30 bg-surface hover:shadow-sm'
|
: 'border-border hover:border-brand-primary/30 bg-surface hover:shadow-sm'
|
||||||
@@ -80,7 +80,7 @@ export default function ArtefactVersionTimeline({ versions, activeVersionId, onS
|
|||||||
|
|
||||||
{/* Thumbnail for image artefacts */}
|
{/* Thumbnail for image artefacts */}
|
||||||
{artefactType === 'design' && version.thumbnail && (
|
{artefactType === 'design' && version.thumbnail && (
|
||||||
<div className="mt-2 ml-11">
|
<div className="mt-2 ms-11">
|
||||||
<img
|
<img
|
||||||
src={version.thumbnail}
|
src={version.thumbnail}
|
||||||
alt={`Version ${version.version_number}`}
|
alt={`Version ${version.version_number}`}
|
||||||
|
|||||||
@@ -122,7 +122,7 @@ export default function Header() {
|
|||||||
}`}>
|
}`}>
|
||||||
{getInitials(user?.name)}
|
{getInitials(user?.name)}
|
||||||
</div>
|
</div>
|
||||||
<div className="text-left hidden sm:block">
|
<div className="text-start hidden sm:block">
|
||||||
<p className="text-sm font-medium text-text-primary">
|
<p className="text-sm font-medium text-text-primary">
|
||||||
{user?.name || 'User'}
|
{user?.name || 'User'}
|
||||||
</p>
|
</p>
|
||||||
@@ -134,7 +134,7 @@ export default function Header() {
|
|||||||
</button>
|
</button>
|
||||||
|
|
||||||
{showDropdown && (
|
{showDropdown && (
|
||||||
<div className="absolute right-0 top-full mt-2 w-64 bg-white rounded-xl shadow-lg border border-border overflow-hidden animate-scale-in">
|
<div className="absolute end-0 top-full mt-2 w-64 bg-white rounded-xl shadow-lg border border-border overflow-hidden animate-scale-in">
|
||||||
{/* User info */}
|
{/* User info */}
|
||||||
<div className="px-4 py-3 border-b border-border-light bg-surface-secondary">
|
<div className="px-4 py-3 border-b border-border-light bg-surface-secondary">
|
||||||
<p className="text-sm font-semibold text-text-primary">{user?.name}</p>
|
<p className="text-sm font-semibold text-text-primary">{user?.name}</p>
|
||||||
@@ -153,7 +153,7 @@ export default function Header() {
|
|||||||
setShowDropdown(false)
|
setShowDropdown(false)
|
||||||
window.location.href = '/users'
|
window.location.href = '/users'
|
||||||
}}
|
}}
|
||||||
className="w-full flex items-center gap-3 px-4 py-2.5 hover:bg-surface-secondary transition-colors text-left"
|
className="w-full flex items-center gap-3 px-4 py-2.5 hover:bg-surface-secondary transition-colors text-start"
|
||||||
>
|
>
|
||||||
<Shield className="w-4 h-4 text-text-tertiary" />
|
<Shield className="w-4 h-4 text-text-tertiary" />
|
||||||
<span className="text-sm text-text-primary">User Management</span>
|
<span className="text-sm text-text-primary">User Management</span>
|
||||||
@@ -162,7 +162,7 @@ export default function Header() {
|
|||||||
|
|
||||||
<button
|
<button
|
||||||
onClick={openPasswordModal}
|
onClick={openPasswordModal}
|
||||||
className="w-full flex items-center gap-3 px-4 py-2.5 hover:bg-surface-secondary transition-colors text-left"
|
className="w-full flex items-center gap-3 px-4 py-2.5 hover:bg-surface-secondary transition-colors text-start"
|
||||||
>
|
>
|
||||||
<Lock className="w-4 h-4 text-text-tertiary" />
|
<Lock className="w-4 h-4 text-text-tertiary" />
|
||||||
<span className="text-sm text-text-primary">Change Password</span>
|
<span className="text-sm text-text-primary">Change Password</span>
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { useState, useRef, useEffect, useCallback, useMemo } from 'react'
|
import { useState, useRef, useEffect, useCallback, useMemo } from 'react'
|
||||||
import { format, differenceInDays, startOfDay, addDays, isBefore, isAfter } from 'date-fns'
|
import { format, differenceInDays, startOfDay, addDays, isBefore, isAfter } from 'date-fns'
|
||||||
import { Calendar, Rows3, Rows4 } from 'lucide-react'
|
import { Calendar, Rows3, Rows4 } from 'lucide-react'
|
||||||
|
import { useLanguage } from '../i18n/LanguageContext'
|
||||||
|
|
||||||
const STATUS_COLORS = {
|
const STATUS_COLORS = {
|
||||||
todo: 'bg-gray-500',
|
todo: 'bg-gray-500',
|
||||||
@@ -33,9 +34,9 @@ const PRIORITY_BORDER = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const ZOOM_LEVELS = [
|
const ZOOM_LEVELS = [
|
||||||
{ key: 'month', label: 'Month', pxPerDay: 8 },
|
{ key: 'month', i18n: 'timeline.month', pxPerDay: 8 },
|
||||||
{ key: 'week', label: 'Week', pxPerDay: 20 },
|
{ key: 'week', i18n: 'timeline.week', pxPerDay: 20 },
|
||||||
{ key: 'day', label: 'Day', pxPerDay: 48 },
|
{ key: 'day', i18n: 'timeline.day', pxPerDay: 48 },
|
||||||
]
|
]
|
||||||
|
|
||||||
const COLOR_PALETTE = [
|
const COLOR_PALETTE = [
|
||||||
@@ -50,6 +51,7 @@ function getInitials(name) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export default function InteractiveTimeline({ items = [], mapItem, onDateChange, onColorChange, onItemClick, readOnly = false }) {
|
export default function InteractiveTimeline({ items = [], mapItem, onDateChange, onColorChange, onItemClick, readOnly = false }) {
|
||||||
|
const { t } = useLanguage()
|
||||||
const containerRef = useRef(null)
|
const containerRef = useRef(null)
|
||||||
const didDragRef = useRef(false)
|
const didDragRef = useRef(false)
|
||||||
const optimisticRef = useRef({}) // { [itemId]: { startDate, endDate } } — keeps bar in place until fresh data arrives
|
const optimisticRef = useRef({}) // { [itemId]: { startDate, endDate } } — keeps bar in place until fresh data arrives
|
||||||
@@ -237,8 +239,8 @@ export default function InteractiveTimeline({ items = [], mapItem, onDateChange,
|
|||||||
return (
|
return (
|
||||||
<div className="bg-white rounded-xl border border-border py-16 text-center">
|
<div className="bg-white rounded-xl border border-border py-16 text-center">
|
||||||
<Calendar className="w-12 h-12 text-text-tertiary mx-auto mb-3" />
|
<Calendar className="w-12 h-12 text-text-tertiary mx-auto mb-3" />
|
||||||
<p className="text-text-secondary font-medium">No items to display</p>
|
<p className="text-text-secondary font-medium">{t('timeline.noItems')}</p>
|
||||||
<p className="text-sm text-text-tertiary mt-1">Add items with dates to see the timeline</p>
|
<p className="text-sm text-text-tertiary mt-1">{t('timeline.addItems')}</p>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -258,7 +260,7 @@ export default function InteractiveTimeline({ items = [], mapItem, onDateChange,
|
|||||||
: 'text-text-tertiary hover:text-text-primary hover:bg-surface-tertiary'
|
: 'text-text-tertiary hover:text-text-primary hover:bg-surface-tertiary'
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
{z.label}
|
{t(z.i18n)}
|
||||||
</button>
|
</button>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
@@ -266,28 +268,28 @@ export default function InteractiveTimeline({ items = [], mapItem, onDateChange,
|
|||||||
<button
|
<button
|
||||||
onClick={() => setBarMode(m => m === 'compact' ? 'expanded' : 'compact')}
|
onClick={() => setBarMode(m => m === 'compact' ? 'expanded' : 'compact')}
|
||||||
className="flex items-center gap-1.5 px-3 py-1 text-xs font-medium text-text-secondary hover:text-text-primary hover:bg-surface-tertiary rounded-md transition-colors"
|
className="flex items-center gap-1.5 px-3 py-1 text-xs font-medium text-text-secondary hover:text-text-primary hover:bg-surface-tertiary rounded-md transition-colors"
|
||||||
title={isExpanded ? 'Compact bars' : 'Expanded bars'}
|
title={isExpanded ? t('timeline.compactBars') : t('timeline.expandedBars')}
|
||||||
>
|
>
|
||||||
{isExpanded ? <Rows4 className="w-3.5 h-3.5" /> : <Rows3 className="w-3.5 h-3.5" />}
|
{isExpanded ? <Rows4 className="w-3.5 h-3.5" /> : <Rows3 className="w-3.5 h-3.5" />}
|
||||||
{isExpanded ? 'Compact' : 'Expand'}
|
{isExpanded ? t('timeline.compact') : t('timeline.expand')}
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
onClick={scrollToToday}
|
onClick={scrollToToday}
|
||||||
className="flex items-center gap-1.5 px-3 py-1 text-xs font-medium text-brand-primary hover:bg-brand-primary/10 rounded-md transition-colors"
|
className="flex items-center gap-1.5 px-3 py-1 text-xs font-medium text-brand-primary hover:bg-brand-primary/10 rounded-md transition-colors"
|
||||||
>
|
>
|
||||||
<Calendar className="w-3.5 h-3.5" />
|
<Calendar className="w-3.5 h-3.5" />
|
||||||
Today
|
{t('timeline.today')}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Timeline */}
|
{/* Timeline */}
|
||||||
<div ref={containerRef} className="overflow-x-auto relative" style={{ cursor: dragState ? 'grabbing' : undefined }}>
|
<div ref={containerRef} dir="ltr" className="overflow-x-auto relative" style={{ cursor: dragState ? 'grabbing' : undefined }}>
|
||||||
<div style={{ minWidth: `${labelWidth + totalDays * pxPerDay}px` }}>
|
<div style={{ minWidth: `${labelWidth + totalDays * pxPerDay}px` }}>
|
||||||
{/* Day header */}
|
{/* Day header */}
|
||||||
<div className="flex sticky top-0 z-20 bg-white border-b border-border" style={{ height: headerHeight }}>
|
<div className="flex sticky top-0 z-20 bg-white border-b border-border" style={{ height: headerHeight }}>
|
||||||
<div className="shrink-0 border-r border-border bg-surface-secondary flex items-center px-4 sticky left-0 z-30" style={{ width: labelWidth }}>
|
<div className="shrink-0 border-e border-border bg-surface-secondary flex items-center px-4 sticky left-0 z-30" style={{ width: labelWidth }}>
|
||||||
<span className="text-xs font-semibold text-text-tertiary uppercase tracking-wider">Item</span>
|
<span className="text-xs font-semibold text-text-tertiary uppercase tracking-wider">{t('timeline.item')}</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex relative">
|
<div className="flex relative">
|
||||||
{days.map((day, i) => {
|
{days.map((day, i) => {
|
||||||
@@ -336,7 +338,7 @@ export default function InteractiveTimeline({ items = [], mapItem, onDateChange,
|
|||||||
>
|
>
|
||||||
{/* Label column */}
|
{/* Label column */}
|
||||||
<div
|
<div
|
||||||
className={`shrink-0 border-r border-border flex ${isExpanded ? 'flex-col justify-center gap-1' : 'items-center gap-2'} px-3 overflow-hidden sticky left-0 z-10 bg-white group-hover/row:bg-surface-secondary/50`}
|
className={`shrink-0 border-e border-border flex ${isExpanded ? 'flex-col justify-center gap-1' : 'items-center gap-2'} px-3 overflow-hidden sticky left-0 z-10 bg-white group-hover/row:bg-surface-secondary/50`}
|
||||||
style={{ width: labelWidth }}
|
style={{ width: labelWidth }}
|
||||||
>
|
>
|
||||||
{isExpanded ? (
|
{isExpanded ? (
|
||||||
@@ -351,7 +353,7 @@ export default function InteractiveTimeline({ items = [], mapItem, onDateChange,
|
|||||||
}}
|
}}
|
||||||
className={`w-5 h-5 rounded-full border-2 border-white shadow-sm shrink-0 hover:scale-110 transition-transform ${!item.color ? (STATUS_COLORS[item.status] || 'bg-gray-400') : ''}`}
|
className={`w-5 h-5 rounded-full border-2 border-white shadow-sm shrink-0 hover:scale-110 transition-transform ${!item.color ? (STATUS_COLORS[item.status] || 'bg-gray-400') : ''}`}
|
||||||
style={item.color ? { backgroundColor: item.color } : undefined}
|
style={item.color ? { backgroundColor: item.color } : undefined}
|
||||||
title="Change color"
|
title={t('timeline.changeColor')}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{item.thumbnailUrl ? (
|
{item.thumbnailUrl ? (
|
||||||
@@ -387,7 +389,7 @@ export default function InteractiveTimeline({ items = [], mapItem, onDateChange,
|
|||||||
}}
|
}}
|
||||||
className={`w-4 h-4 rounded-full border-2 border-white shadow-sm shrink-0 hover:scale-110 transition-transform ${!item.color ? (STATUS_COLORS[item.status] || 'bg-gray-400') : ''}`}
|
className={`w-4 h-4 rounded-full border-2 border-white shadow-sm shrink-0 hover:scale-110 transition-transform ${!item.color ? (STATUS_COLORS[item.status] || 'bg-gray-400') : ''}`}
|
||||||
style={item.color ? { backgroundColor: item.color } : undefined}
|
style={item.color ? { backgroundColor: item.color } : undefined}
|
||||||
title="Change color"
|
title={t('timeline.changeColor')}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{item.thumbnailUrl ? (
|
{item.thumbnailUrl ? (
|
||||||
@@ -414,7 +416,7 @@ export default function InteractiveTimeline({ items = [], mapItem, onDateChange,
|
|||||||
>
|
>
|
||||||
{idx === 0 && (
|
{idx === 0 && (
|
||||||
<div className="absolute -top-0 left-1 text-[8px] font-bold text-red-500 bg-red-50 px-1 rounded whitespace-nowrap">
|
<div className="absolute -top-0 left-1 text-[8px] font-bold text-red-500 bg-red-50 px-1 rounded whitespace-nowrap">
|
||||||
Today
|
{t('timeline.today')}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
@@ -477,7 +479,7 @@ export default function InteractiveTimeline({ items = [], mapItem, onDateChange,
|
|||||||
</span>
|
</span>
|
||||||
)}
|
)}
|
||||||
{width > 120 && item.status && (
|
{width > 120 && item.status && (
|
||||||
<span className="text-[9px] text-white/70 bg-white/15 px-1.5 py-0.5 rounded ml-auto shrink-0">
|
<span className="text-[9px] text-white/70 bg-white/15 px-1.5 py-0.5 rounded ms-auto shrink-0">
|
||||||
{item.status.replace(/_/g, ' ')}
|
{item.status.replace(/_/g, ' ')}
|
||||||
</span>
|
</span>
|
||||||
)}
|
)}
|
||||||
@@ -493,7 +495,7 @@ export default function InteractiveTimeline({ items = [], mapItem, onDateChange,
|
|||||||
<span key={i} className="text-[8px] px-1 py-0.5 rounded bg-white/15 text-white/70 font-medium">{tag}</span>
|
<span key={i} className="text-[8px] px-1 py-0.5 rounded bg-white/15 text-white/70 font-medium">{tag}</span>
|
||||||
))}
|
))}
|
||||||
{width > 140 && item.startDate && item.endDate && (
|
{width > 140 && item.startDate && item.endDate && (
|
||||||
<span className="text-[8px] text-white/50 ml-auto">
|
<span className="text-[8px] text-white/50 ms-auto">
|
||||||
{format(item.startDate, 'MMM d')} – {format(item.endDate, 'MMM d')}
|
{format(item.startDate, 'MMM d')} – {format(item.endDate, 'MMM d')}
|
||||||
</span>
|
</span>
|
||||||
)}
|
)}
|
||||||
@@ -557,7 +559,7 @@ export default function InteractiveTimeline({ items = [], mapItem, onDateChange,
|
|||||||
}}
|
}}
|
||||||
className="w-full text-[10px] text-text-tertiary hover:text-text-primary text-center py-1 hover:bg-surface-tertiary rounded transition-colors"
|
className="w-full text-[10px] text-text-tertiary hover:text-text-primary text-center py-1 hover:bg-surface-tertiary rounded transition-colors"
|
||||||
>
|
>
|
||||||
Reset to default
|
{t('timeline.resetColor')}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
@@ -576,21 +578,21 @@ export default function InteractiveTimeline({ items = [], mapItem, onDateChange,
|
|||||||
<div className="font-semibold mb-1">{tooltip.item.label}</div>
|
<div className="font-semibold mb-1">{tooltip.item.label}</div>
|
||||||
<div className="text-gray-300 space-y-0.5">
|
<div className="text-gray-300 space-y-0.5">
|
||||||
{tooltip.item.startDate && (
|
{tooltip.item.startDate && (
|
||||||
<div>Start: {format(tooltip.item.startDate, 'MMM d, yyyy')}</div>
|
<div>{t('timeline.startDate')}: {format(tooltip.item.startDate, 'MMM d, yyyy')}</div>
|
||||||
)}
|
)}
|
||||||
{tooltip.item.endDate && (
|
{tooltip.item.endDate && (
|
||||||
<div>End: {format(tooltip.item.endDate, 'MMM d, yyyy')}</div>
|
<div>{t('timeline.endDate')}: {format(tooltip.item.endDate, 'MMM d, yyyy')}</div>
|
||||||
)}
|
)}
|
||||||
{tooltip.item.assigneeName && (
|
{tooltip.item.assigneeName && (
|
||||||
<div>Assignee: {tooltip.item.assigneeName}</div>
|
<div>{t('timeline.assignee')}: {tooltip.item.assigneeName}</div>
|
||||||
)}
|
)}
|
||||||
{tooltip.item.status && (
|
{tooltip.item.status && (
|
||||||
<div>Status: {tooltip.item.status.replace(/_/g, ' ')}</div>
|
<div>{t('timeline.status')}: {tooltip.item.status.replace(/_/g, ' ')}</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
{!readOnly && onDateChange && (
|
{!readOnly && onDateChange && (
|
||||||
<div className="text-gray-400 mt-1 text-[10px] italic">
|
<div className="text-gray-400 mt-1 text-[10px] italic">
|
||||||
Drag to move · Drag edges to resize
|
{t('timeline.dragToMove')} · {t('timeline.dragToResize')}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -351,13 +351,24 @@
|
|||||||
"timeline.day": "يوم",
|
"timeline.day": "يوم",
|
||||||
"timeline.week": "أسبوع",
|
"timeline.week": "أسبوع",
|
||||||
"timeline.today": "اليوم",
|
"timeline.today": "اليوم",
|
||||||
"timeline.startDate": "تاريخ البدء",
|
"timeline.startDate": "البداية",
|
||||||
|
"timeline.endDate": "النهاية",
|
||||||
|
"timeline.assignee": "المُكلّف",
|
||||||
|
"timeline.status": "الحالة",
|
||||||
"timeline.dragToMove": "اسحب للنقل",
|
"timeline.dragToMove": "اسحب للنقل",
|
||||||
"timeline.dragToResize": "اسحب الحواف لتغيير الحجم",
|
"timeline.dragToResize": "اسحب الحواف لتغيير الحجم",
|
||||||
"timeline.noItems": "لا توجد عناصر للعرض",
|
"timeline.noItems": "لا توجد عناصر للعرض",
|
||||||
"timeline.addItems": "أضف عناصر بتواريخ لعرض الجدول الزمني",
|
"timeline.addItems": "أضف عناصر بتواريخ لعرض الجدول الزمني",
|
||||||
"timeline.tracks": "المسارات",
|
"timeline.tracks": "المسارات",
|
||||||
"timeline.timeline": "الجدول الزمني",
|
"timeline.timeline": "الجدول الزمني",
|
||||||
|
"timeline.item": "العنصر",
|
||||||
|
"timeline.month": "شهر",
|
||||||
|
"timeline.compact": "مضغوط",
|
||||||
|
"timeline.expand": "موسّع",
|
||||||
|
"timeline.resetColor": "إعادة إلى الافتراضي",
|
||||||
|
"timeline.changeColor": "تغيير اللون",
|
||||||
|
"timeline.compactBars": "أشرطة مضغوطة",
|
||||||
|
"timeline.expandedBars": "أشرطة موسّعة",
|
||||||
"posts.details": "التفاصيل",
|
"posts.details": "التفاصيل",
|
||||||
"posts.platformsLinks": "المنصات والروابط",
|
"posts.platformsLinks": "المنصات والروابط",
|
||||||
"posts.discussion": "النقاش",
|
"posts.discussion": "النقاش",
|
||||||
|
|||||||
@@ -351,13 +351,24 @@
|
|||||||
"timeline.day": "Day",
|
"timeline.day": "Day",
|
||||||
"timeline.week": "Week",
|
"timeline.week": "Week",
|
||||||
"timeline.today": "Today",
|
"timeline.today": "Today",
|
||||||
"timeline.startDate": "Start Date",
|
"timeline.startDate": "Start",
|
||||||
|
"timeline.endDate": "End",
|
||||||
|
"timeline.assignee": "Assignee",
|
||||||
|
"timeline.status": "Status",
|
||||||
"timeline.dragToMove": "Drag to move",
|
"timeline.dragToMove": "Drag to move",
|
||||||
"timeline.dragToResize": "Drag edges to resize",
|
"timeline.dragToResize": "Drag edges to resize",
|
||||||
"timeline.noItems": "No items to display",
|
"timeline.noItems": "No items to display",
|
||||||
"timeline.addItems": "Add items with dates to see the timeline",
|
"timeline.addItems": "Add items with dates to see the timeline",
|
||||||
"timeline.tracks": "Tracks",
|
"timeline.tracks": "Tracks",
|
||||||
"timeline.timeline": "Timeline",
|
"timeline.timeline": "Timeline",
|
||||||
|
"timeline.item": "Item",
|
||||||
|
"timeline.month": "Month",
|
||||||
|
"timeline.compact": "Compact",
|
||||||
|
"timeline.expand": "Expand",
|
||||||
|
"timeline.resetColor": "Reset to default",
|
||||||
|
"timeline.changeColor": "Change color",
|
||||||
|
"timeline.compactBars": "Compact bars",
|
||||||
|
"timeline.expandedBars": "Expanded bars",
|
||||||
"posts.details": "Details",
|
"posts.details": "Details",
|
||||||
"posts.platformsLinks": "Platforms & Links",
|
"posts.platformsLinks": "Platforms & Links",
|
||||||
"posts.discussion": "Discussion",
|
"posts.discussion": "Discussion",
|
||||||
|
|||||||
Reference in New Issue
Block a user