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 @@ -87,4 +87,5 @@ export interface StorageKV {
selected_engine: string | null
widget_tab: string
yadkar_tab: string
notifications: any
}
81 changes: 81 additions & 0 deletions src/common/motion.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import React from 'react'
import { motion, type HTMLMotionProps, type SVGMotionProps } from 'framer-motion'
import { useGeneralSetting } from '@/context/general-setting.context'

function cleanMotionProps<T extends object>(props: T): T {
const {
initial,
animate,
exit,
variants,
transition,
whileHover,
whileTap,
whileDrag,
whileFocus,
whileInView,
layout,
layoutId,
drag,
dragConstraints,
dragElastic,
dragMomentum,
onAnimationStart,
onAnimationComplete,
...rest
} = props as any

return {
...rest,
initial: false,
transition: { duration: 0 },
} as T
}

function createMotionComponent<T extends keyof typeof motion, P extends object>(
Component: React.ComponentType<P>
) {
return React.forwardRef<any, P>((props, ref) => {
const { isOptimalMode } = useGeneralSetting()

return (
<Component
ref={ref}
{...((isOptimalMode ? cleanMotionProps(props) : props) as P)}
/>
)
})
}

export const Motion = {
div: createMotionComponent<'div', HTMLMotionProps<'div'>>(motion.div),

span: createMotionComponent<'span', HTMLMotionProps<'span'>>(motion.span),

button: createMotionComponent<'button', HTMLMotionProps<'button'>>(motion.button),

img: createMotionComponent<'img', HTMLMotionProps<'img'>>(motion.img),

ul: createMotionComponent<'ul', HTMLMotionProps<'ul'>>(motion.ul),

li: createMotionComponent<'li', HTMLMotionProps<'li'>>(motion.li),

svg: createMotionComponent<'svg', SVGMotionProps<SVGSVGElement>>(motion.svg),

path: createMotionComponent<'path', SVGMotionProps<SVGPathElement>>(motion.path),
}

import { AnimatePresence } from 'framer-motion'

export function Presence({
children,
...props
}: React.ComponentProps<typeof AnimatePresence>) {
const { isOptimalMode } = useGeneralSetting()

if (isOptimalMode) {
return <>{children}</>
}

return <AnimatePresence {...props}>{children}</AnimatePresence>
}
2 changes: 1 addition & 1 deletion src/components/auth/require-auth.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { motion } from 'framer-motion'
import { Motion as motion } from "@/common/motion";
import type { ReactNode } from 'react'
import { callEvent } from '@/common/utils/call-event'
import { useAuth } from '@/context/auth.context'
Expand Down
2 changes: 1 addition & 1 deletion src/components/auth/require-verification.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { motion } from 'framer-motion'
import { Motion as motion } from "@/common/motion";
import type { ReactNode } from 'react'
import { callEvent } from '@/common/utils/call-event'
import { useAuth } from '@/context/auth.context'
Expand Down
8 changes: 4 additions & 4 deletions src/components/bottom-sheet/bottom-sheet.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { useState, type ReactNode } from 'react'
import { motion, AnimatePresence, type PanInfo } from 'framer-motion'
import { Presence, Motion as motion } from '@/common/motion'
import { Portal } from '../portal/Portal'
import { Icon } from '@/src/icons'

Expand Down Expand Up @@ -40,7 +40,7 @@ export function BottomSheet({
screen: '98vh',
}

const handleDragEnd = (_: any, info: PanInfo) => {
const handleDragEnd = (_: any, info: any) => {
setIsDragging(false)

if (info.offset.y > dragThreshold) {
Expand All @@ -50,7 +50,7 @@ export function BottomSheet({

return (
<Portal>
<AnimatePresence>
<Presence>
{isOpen && (
<>
<motion.div
Expand Down Expand Up @@ -133,7 +133,7 @@ export function BottomSheet({
</motion.div>
</>
)}
</AnimatePresence>
</Presence>
</Portal>
)
}
45 changes: 22 additions & 23 deletions src/components/clickableTooltip.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { AnimatePresence, domAnimation, LazyMotion, m } from 'framer-motion'
import { Motion as motion, Presence } from '@/common/motion'

import { type ReactNode, useEffect, useRef, useState, type RefObject } from 'react'
import ReactDOM from 'react-dom'

Expand Down Expand Up @@ -208,28 +209,26 @@ const ClickableTooltip = ({
return (
<>
{ReactDOM.createPortal(
<LazyMotion features={domAnimation}>
<AnimatePresence mode="wait">
{isOpen && (
<m.div
ref={tooltipRef}
className={`fixed rounded-xl py-1 px-2 text-xs max-w-xs bg-base-300 shadow bg-glass ${contentClassName}`}
style={{
left: tooltipCoords.x,
top: tooltipCoords.y,
zIndex: 9999,
}}
initial="hidden"
animate="visible"
exit="hidden"
variants={variants[calculatedPosition]}
transition={{ duration: 0.15, ease: 'easeOut' }}
>
{content}
</m.div>
)}
</AnimatePresence>
</LazyMotion>,
<Presence mode="wait">
{isOpen && (
<motion.div
ref={tooltipRef}
className={`fixed rounded-xl py-1 px-2 text-xs max-w-xs bg-base-300 shadow bg-glass ${contentClassName}`}
style={{
left: tooltipCoords.x,
top: tooltipCoords.y,
zIndex: 9999,
}}
initial="hidden"
animate="visible"
exit="hidden"
variants={variants[calculatedPosition]}
transition={{ duration: 0.15, ease: 'easeOut' }}
>
{content}
</motion.div>
)}
</Presence>,
document.body
)}
</>
Expand Down
2 changes: 1 addition & 1 deletion src/components/tab-navigation.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React, { useId } from 'react'
import { motion } from 'framer-motion'
import { Motion as motion } from "@/common/motion";

interface TabItem<T> {
id: T
Expand Down
44 changes: 21 additions & 23 deletions src/components/toolTip.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { AnimatePresence, domAnimation, LazyMotion, m } from 'framer-motion'
import { Motion as motion, Presence } from '@/common/motion'
import { type ReactNode, useEffect, useRef, useState } from 'react'
import ReactDOM from 'react-dom'

Expand Down Expand Up @@ -218,28 +218,26 @@ const Tooltip = ({

{(alwaysShow || isVisible) &&
ReactDOM.createPortal(
<LazyMotion features={domAnimation}>
<AnimatePresence>
<m.div
ref={tooltipRef}
className={`tooltip fixed rounded-lg py-1.5 px-3 text-xs max-w-xs bg-content shadow-lg z-[9999] ${contentClassName}`}
style={{
left: tooltipCoords.x,
top: tooltipCoords.y,
}}
initial="hidden"
animate="visible"
exit="hidden"
variants={variants[calculatedPosition]}
transition={{ duration: 0.15, ease: 'easeOut' }}
onMouseEnter={showTooltip}
onMouseLeave={hideTooltip}
>
{content}
<div className={getArrowClasses(calculatedPosition)} />
</m.div>
</AnimatePresence>
</LazyMotion>,
<Presence>
<motion.div
ref={tooltipRef}
className={`tooltip fixed rounded-lg py-1.5 px-3 text-xs max-w-xs bg-content shadow-lg z-[9999] ${contentClassName}`}
style={{
left: tooltipCoords.x,
top: tooltipCoords.y,
}}
initial="hidden"
animate="visible"
exit="hidden"
variants={variants[calculatedPosition]}
transition={{ duration: 0.15, ease: 'easeOut' }}
onMouseEnter={showTooltip}
onMouseLeave={hideTooltip}
>
{content}
<div className={getArrowClasses(calculatedPosition)} />
</motion.div>
</Presence>,
document.body
)}
</>
Expand Down
3 changes: 3 additions & 0 deletions src/context/general-setting.context.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { useAuth } from './auth.context'

export interface GeneralData {
blurMode: boolean
isOptimalMode: boolean
analyticsEnabled: boolean
selected_timezone: FetchedTimezone
browserBookmarksEnabled: boolean
Expand All @@ -35,6 +36,7 @@ const DEFAULT_SETTINGS: GeneralData = {
},
browserBookmarksEnabled: false,
browserTabsEnabled: false,
isOptimalMode: false,
}

export const GeneralSettingContext = createContext<GeneralSettingContextType | null>(null)
Expand Down Expand Up @@ -223,6 +225,7 @@ export function GeneralSettingProvider({ children }: { children: React.ReactNode
setBrowserBookmarksEnabled,
browserTabsEnabled: settings.browserTabsEnabled,
setBrowserTabsEnabled,
isOptimalMode: settings.isOptimalMode,
}

return (
Expand Down
6 changes: 3 additions & 3 deletions src/layouts/setting/tabs/account/account.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { AnimatePresence, motion } from 'framer-motion'
import { Motion as motion, Presence } from '@/common/motion'
import { useAuth } from '@/context/auth.context'
import AuthForm from './auth-form/auth-form'
import { UserProfile } from './tabs/user-profile/user-profile'
Expand All @@ -8,7 +8,7 @@ export const AccountTab = () => {

return (
<div className="w-full h-full max-w-xl mx-auto">
<AnimatePresence mode="wait">
<Presence mode="wait">
{isAuthenticated ? (
<motion.div
key="profile"
Expand All @@ -32,7 +32,7 @@ export const AccountTab = () => {
<AuthForm />
</motion.div>
)}
</AnimatePresence>
</Presence>
</div>
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ export function TimezoneSettings() {
}

return (
<SectionPanel title="منطقه‌ی زمانی" delay={0.1}>
<SectionPanel title="منطقه‌ی زمانی" delay={0.1} size="sm">
<div className="space-y-3">
<p className={'text-sm text-muted'}>
منطقه‌ی زمانی مورد نظر خود را انتخاب کنید.
Expand Down
26 changes: 26 additions & 0 deletions src/layouts/setting/tabs/general/general.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,37 @@
import { ToggleSwitch } from '@/components/toggle-switch.component'
import { SelectCity } from './components/select-city'
import { TimezoneSettings } from './components/timezone-settings'
import { useGeneralSetting } from '@/context/general-setting.context'
import { SectionPanel } from '@/components/section-panel'

export function GeneralSettingTab() {
const { isOptimalMode, updateSetting } = useGeneralSetting()
return (
<div className="w-full max-w-xl mx-auto">
<SelectCity key={'selectCity'} />
<TimezoneSettings key="timezone" />
<SectionPanel
title={
<div className="flex items-center">
<p>حالت بهینه</p>
<span className="mr-2 text-white badge badge-error badge-xs outline-2 outline-error/20">
جدید
</span>
</div>
}
size="sm"
>
<div className="flex">
<p className="flex-1 text-sm font-light leading-relaxed text-muted">
برای کاهش مصرف منابع، انیمیشن‌ها، حیوان خانگی، ثانیه‌شمار ساعت و
برخی افکت‌های بصری غیرفعال می‌شوند.
</p>
<ToggleSwitch
enabled={isOptimalMode}
onToggle={() => updateSetting('isOptimalMode', !isOptimalMode)}
/>
</div>
</SectionPanel>
</div>
)
}
4 changes: 3 additions & 1 deletion src/layouts/widgetify-card/pets/pet.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import { usePetContext } from './pet.context'
import { PetFactory } from './pet-factory'
import { useGeneralSetting } from '@/context/general-setting.context'

export function Pet() {
const { isOptimalMode } = useGeneralSetting()
const { isEnabled } = usePetContext()

if (!isEnabled) return null
if (!isEnabled || isOptimalMode) return null

return <PetFactory />
}
Loading
Loading