Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/common/constant/store.key.ts
Original file line number Diff line number Diff line change
Expand Up @@ -89,4 +89,5 @@ export interface StorageKV {
}
pendingOrders: any
petState: boolean
showNewBadgeForReOrderWidgets: boolean
}
32 changes: 30 additions & 2 deletions src/context/appearance.context.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@ interface AppearanceContextContextType extends AppearanceData {
) => void
setContentAlignment: (value: 'center' | 'top') => void
setFontFamily: (value: FontFamily) => void
canReOrderWidget: boolean
toggleCanReOrderWidget: () => void
showNewBadge: boolean
}

const DEFAULT_SETTINGS: AppearanceData = {
Expand All @@ -41,20 +44,33 @@ export const AppearanceContext = createContext<AppearanceContextContextType | nu
export function AppearanceProvider({ children }: { children: React.ReactNode }) {
const [settings, setSettings] = useState<AppearanceData>(DEFAULT_SETTINGS)
const [isInitialized, setIsInitialized] = useState(false)
const [canReOrderWidget, setCanReOrderWidget] = useState(false)
const [showNewBadge, setNewBadge] = useState<boolean>(false)
const { mutateAsync: changeFontAsync } = useChangeFont()
const { isAuthenticated } = useAuth()

useEffect(() => {
async function loadSettings() {
try {
const storedSettings = await getFromStorage('appearance')

const [storedSettings, showNewBadgeForReOrderWidgets] = await Promise.all(
[
getFromStorage('appearance'),
getFromStorage('showNewBadgeForReOrderWidgets'),
]
)
if (storedSettings) {
setSettings({
...DEFAULT_SETTINGS,
...storedSettings,
})
}

if (typeof showNewBadgeForReOrderWidgets === 'boolean') {
setNewBadge(showNewBadgeForReOrderWidgets)
} else {
setNewBadge(true)
await setToStorage('showNewBadgeForReOrderWidgets', true)
}
} finally {
setIsInitialized(true)
}
Expand Down Expand Up @@ -105,6 +121,15 @@ export function AppearanceProvider({ children }: { children: React.ReactNode })
}
}

const toggleCanReOrderWidget = async () => {
setCanReOrderWidget(!canReOrderWidget)
if (showNewBadge) {
setNewBadge(false)
await setToStorage('showNewBadgeForReOrderWidgets', false)
}
Analytics.event('toggle_can_reorder_widget')
}

useEffect(() => {
if (isInitialized && settings.fontFamily) {
document.body.style.fontFamily = `"${settings.fontFamily}", sans-serif`
Expand All @@ -121,6 +146,9 @@ export function AppearanceProvider({ children }: { children: React.ReactNode })
updateSetting,
setContentAlignment,
setFontFamily,
canReOrderWidget,
showNewBadge,
toggleCanReOrderWidget,
}

return (
Expand Down
26 changes: 26 additions & 0 deletions src/layouts/navbar/components/settingsDropdown.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,15 @@ import { HiCog, HiViewGridAdd } from 'react-icons/hi'
import { callEvent } from '@/common/utils/call-event'
import { Dropdown } from '@/components/dropdown'
import Tooltip from '@/components/toolTip'
import { useAppearanceSetting } from '@/context/appearance.context'
import { AiOutlineDrag } from 'react-icons/ai'

interface SettingsProps {
setShowSettings: (value: boolean) => void
}
export const SettingsDropdown = ({ setShowSettings }: SettingsProps) => {
const { canReOrderWidget, toggleCanReOrderWidget, showNewBadge } =
useAppearanceSetting()
const handleWidgetSettingsClick = useCallback(() => {
callEvent('openWidgetsSettings', { tab: null })
callEvent('closeAllDropdowns')
Expand All @@ -25,6 +29,9 @@ export const SettingsDropdown = ({ setShowSettings }: SettingsProps) => {
id="settings-button"
>
<HiCog size={20} className="text-muted group-hover:!text-primary" />
{showNewBadge && (
<span className="absolute w-2 h-2 rounded-full right-4 bottom-1 bg-error animate-pulse"></span>
)}
</div>
</Tooltip>
)
Expand Down Expand Up @@ -56,6 +63,25 @@ export const SettingsDropdown = ({ setShowSettings }: SettingsProps) => {
<span>مدیریت ویجت‌ها</span>
</div>
</button>

<div
className="relative px-3 py-2 border-t cursor-pointer border-base-300 group hover:bg-primary/10 hover:text-primary"
onClick={() => toggleCanReOrderWidget()}
>
<div className="flex items-center gap-3">
<AiOutlineDrag
size={16}
className="text-muted group-hover:!text-primary"
/>
{canReOrderWidget ? (
<span>غیرفعال‌سازی حالت جابجایی</span>
) : (
<span>حالت جابجایی ویجت ها</span>
)}
</div>

<span className="absolute w-2 h-2 rounded-full left-4 top-2 bg-error animate-pulse"></span>
</div>
</div>
</Dropdown>
)
Expand Down
31 changes: 30 additions & 1 deletion src/layouts/navbar/navbar.layout.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { type JSX, useCallback, useEffect, useState } from 'react'
import { HiHome } from 'react-icons/hi'
import { HiHome, HiX } from 'react-icons/hi'
import { AiOutlineDrag } from 'react-icons/ai'
import { getFromStorage, setToStorage } from '@/common/storage'
import { listenEvent } from '@/common/utils/call-event'
import { useAuth } from '@/context/auth.context'
Expand All @@ -11,6 +12,7 @@ import { FriendsList } from './friends-list/friends'
import { MarketButton } from './market/market-button'
import { ProfileNav } from './profile/profile'
import { SyncButton } from './sync/sync'
import { useAppearanceSetting } from '@/context/appearance.context'

export interface PageLink {
name: string
Expand All @@ -32,6 +34,7 @@ const WIDGETIFY_URLS = {
} as const

export function NavbarLayout(): JSX.Element {
const { canReOrderWidget, toggleCanReOrderWidget } = useAppearanceSetting()
const [showSettings, setShowSettings] = useState(false)
const [tab, setTab] = useState<string | null>(null)
const [logoData, setLogoData] = useState<LogoData>(DEFAULT_LOGO_DATA)
Expand Down Expand Up @@ -134,6 +137,32 @@ export function NavbarLayout(): JSX.Element {
/>
</div>
</div>

{canReOrderWidget && (
<div
className="fixed transform -translate-x-1/2 top-1 left-1/2"
style={{
zIndex: 100,
}}
>
<div className="p-2 border shadow-xl rounded-xl bg-warning/90 backdrop-blur-sm border-warning-content/20">
<div className="flex items-center gap-3 text-warning-content">
<AiOutlineDrag size={20} className="animate-bounce" />
<span className="text-sm font-medium">
حالت جابجایی ویجت‌ها فعال است. بالای هر ویجت رو نگه
داشته و جابجا کنید
</span>

<button
onClick={() => toggleCanReOrderWidget()}
className="transition-colors cursor-pointer text-warning-content/70 hover:text-warning-content"
>
<HiX size={16} />
</button>
</div>
</div>
</div>
)}
</nav>

<SettingModal
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,7 @@ export const CalendarDayDetails: React.FC<CalendarDayDetailsProps> = ({
key={option.value}
onClick={() => handleMoodChange(option.value)}
disabled={isAdding}
className={`p-1.5 rounded-md transition-all cursor-pointer ${
className={`p-1.5 rounded-xl transition-all cursor-pointer ${
mood === option.value
? `bg-${option.colorClass} text-${option.colorClass}-content scale-105`
: `bg-base-300 hover:bg-base-300/70 opacity-80 hover:opacity-100`
Expand Down
23 changes: 17 additions & 6 deletions src/pages/home/content-section.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ function SortableWidget({ widget }: { widget: WidgetItem }) {
}

export function ContentSection() {
const { contentAlignment } = useAppearanceSetting()
const { contentAlignment, canReOrderWidget } = useAppearanceSetting()
const { getSortedWidgets, reorderWidgets } = useWidgetVisibility()
const sortedWidgets = getSortedWidgets().filter((widget) => !widget.disabled)

Expand All @@ -91,6 +91,7 @@ export function ContentSection() {
)

const handleDragEnd = (event: DragEndEvent) => {
if (!canReOrderWidget) return
const { active, over } = event

if (!over || active.id === over.id) {
Expand Down Expand Up @@ -145,9 +146,11 @@ export function ContentSection() {
{sortedWidgets.length > 0 && (
<div className="w-full" id="widgets">
<DndContext
sensors={sensors}
collisionDetection={closestCenter}
onDragEnd={handleDragEnd}
sensors={canReOrderWidget ? sensors : []}
collisionDetection={
canReOrderWidget ? closestCenter : undefined
}
onDragEnd={canReOrderWidget ? handleDragEnd : undefined}
>
<SortableContext
items={sortedWidgets.map((widget) => widget.id)}
Expand All @@ -161,15 +164,23 @@ export function ContentSection() {
key={widget.id}
className="flex-shrink-0 w-full lg:w-3/12"
>
<SortableWidget widget={widget} />
{canReOrderWidget ? (
<SortableWidget
widget={widget}
/>
) : (
widget.node
)}
</div>
)
}
return (
return canReOrderWidget ? (
<SortableWidget
key={widget.id}
widget={widget}
/>
) : (
widget.node
)
})}
</div>
Expand Down