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
5 changes: 4 additions & 1 deletion src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { AppearanceProvider } from './context/appearance.context'
import { AuthProvider } from './context/auth.context'
import { ThemeProvider } from './context/theme.context'
import { HomePage } from './pages/home'
import { PageProvider } from './context/page.context'

const queryClient = new QueryClient({
defaultOptions: {
Expand All @@ -18,7 +19,9 @@ function App() {
<AuthProvider>
<ThemeProvider>
<AppearanceProvider>
<HomePage />
<PageProvider>
<HomePage />
</PageProvider>
</AppearanceProvider>
</ThemeProvider>
</AuthProvider>
Expand Down
2 changes: 1 addition & 1 deletion src/common/constant/config.key.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
export enum ConfigKey {
VERSION_NAME = 'نسخه یلدا 🍉',
VERSION_NAME = 'امید',
WIG_COIN_ICON = 'https://cdn.widgetify.ir/extension/wig-icon.png',
}
30 changes: 30 additions & 0 deletions src/common/constant/moods.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
export const moodOptions = [
{
value: 'sad',
emoji: '😔',
label: 'ناراحتم',
colorClass: 'error',
borderClass: 'border-error/50',
},
{
value: 'tired',
emoji: '😴',
label: 'خستم',
colorClass: 'warning',
borderClass: 'border-yellow-400/50',
},
{
value: 'happy',
emoji: '🙂',
label: 'اوکی‌ام',
colorClass: 'secondary',
borderClass: 'border-secondary/50',
},
{
value: 'excited',
emoji: '😄',
label: 'سرحالم',
colorClass: 'success',
borderClass: 'border-green-400/50',
},
]
2 changes: 1 addition & 1 deletion src/common/constant/priority_options.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ export const PRIORITY_OPTIONS = [
},
{
value: 'high',
ariaLabel: 'اولویت زیاد',
ariaLabel: 'اولویت مهم',
bgColor: 'bg-red-500',
hoverBgColor: 'hover:bg-red-500',
},
Expand Down
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 {
petState: boolean
showNewBadgeForReOrderWidgets: boolean
navbarVisible: boolean
[key: `removed_notification_${string}`]: string
}
28 changes: 28 additions & 0 deletions src/common/storage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,3 +57,31 @@ export async function clearStorage() {
export async function removeFromStorage<K extends keyof StorageKV>(key: K) {
await storage.removeItem(`local:${key}`)
}

export async function setWithExpiry<K extends keyof StorageKV>(
key: K,
value: StorageKV[K],
minutes: number
) {
const expiry = Date.now() + minutes * 60000
const data = { value, expiry }

await setToStorage(key, data as any)
}

export async function getWithExpiry<K extends keyof StorageKV>(
key: K
): Promise<StorageKV[K] | null> {
const data = (await getFromStorage(key)) as any

if (!data || typeof data !== 'object' || !('expiry' in data)) {
return data
}

if (Date.now() > data.expiry) {
await removeFromStorage(key)
return null
}

return data.value as StorageKV[K]
}
6 changes: 4 additions & 2 deletions src/common/utils/call-event.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import type { WidgetTabKeys } from '@/layouts/widgets-settings/constant/tab-keys
import type { StoredWallpaper } from '../wallpaper.interface'
import type { Todo } from '@/services/hooks/todo/todo.interface'
import type { FontFamily } from '@/context/appearance.context'
import React from 'react'

export interface EventName {
startSync: SyncTarget
Expand All @@ -31,8 +32,6 @@ export interface EventName {
name: string
template: string
}
openExplorerPage: null
closeExplorerPage: null

// setting keys
wigiPadDateSettingsChanged: WigiPadDateSetting
Expand All @@ -49,6 +48,9 @@ export interface EventName {
font_change: FontFamily
close_all_modals: null
openWizardModal: null
add_to_notifications: { id: string; node: React.ReactNode }
remove_from_notifications: { id: string; ttl?: number }
go_to_page: 'explorer' | 'home'
}

export function callEvent<K extends keyof EventName>(eventName: K, data?: EventName[K]) {
Expand Down
87 changes: 33 additions & 54 deletions src/components/UpdateReleaseNotesModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,45 +27,14 @@ const VERSION_NAME = ConfigKey.VERSION_NAME

const releaseNotes: ReleaseNote[] = [
{
title: 'ویرایش وظایف',
type: 'feature',
description:
'بالاخره اضافه شد! دیگه لازم نیست برای یه تغییر کوچیک، کل تسک رو پاک کنی و از اول بنویسی.',
},
{
title: 'برنامه‌ریزی دقیق‌تر',
type: 'feature',
description:
'حالا می‌تونی برای کارهات تاریخ و میزان اهمیت (اولویت) تعیین کنی تا هیچ چیزی یادت نره.',
},
{
title: 'انتخاب راحت‌تر شهر',
type: 'improvement',
description:
'بخش آب‌وهوا رو جوری ردیف کردیم که خیلی سریع‌تر و راحت‌تر بتونی شهرت رو پیدا کنی.',
title: 'بهبود ظاهری',
description: 'ظاهر بعضی از قسمت هارو بهتر کردیم',
},
{
title: 'خوشگل‌سازی منو',
type: 'improvement',
description:
'منوی دسترسی پایین رو کمی دست‌کاری کردیم تا هم خوشگل‌تر بشه و هم کار کردن باهاش حال بده.',
},
{
title: 'آب‌وهوای خلوت‌تر',
type: 'improvement',
description:
'ویجت آب‌وهوا رو ساده کردیم تا فقط چیزایی که لازمه رو در یک نگاه ببینی.',
},
{
title: 'بهبود فیلترهای صوتی',
type: 'improvement',
description:
'بخش فیلترها و صداهای لیست وظایف رو بهینه کردیم تا حس بهتری موقع کار داشته باشی.',
},
{
title: 'خداحافظی با فضای خالی',
type: 'bugfix',
description: 'اون فضای خالی و اضافه پایین پنجره‌ها که رو مخ بود رو کلاً حذف کردیم.',
title: 'رفع چندین مشکل جزئی',
description: 'با سپاس از شما، مشکلات گزارش شده رو برطرف کردیم',
},
]

Expand Down Expand Up @@ -124,18 +93,30 @@ export const UpdateReleaseNotesModal = ({
showCloseButton={false}
>
<div className="flex flex-col max-h-[80vh]">
<div className="flex flex-col gap-1 p-4 border-b border-base-300/20 bg-base-200/20">
<div className="flex items-center justify-between">
<div className="flex flex-col italic">
<h2 className="text-3xl font-black text-content">
{VERSION_NAME}
</h2>
<p className="mt-1 text-xs font-medium text-muted opacity-60">
تغییرات جدید برای طولانی‌ترین شب سال
</p>
</div>
<div className="p-2 border rounded-2xl bg-base-200/50 text-primary border-base-300/20">
<RiCompassDiscoverLine size={24} />
<div className="relative overflow-hidden border-b border-base-300/20 rounded-2xl h-28">
<div
className="absolute inset-0 scale-105 bg-center bg-no-repeat bg-cover animate-pan"
style={{
backgroundImage:
'url(http://cdn.widgetify.ir/extension/hope.png)',
filter: 'brightness(0.35) contrast(1.1)',
maskImage:
'linear-gradient(to bottom, black 0%, transparent 100%)',
WebkitMaskImage:
'linear-gradient(to bottom, black 0%, transparent 100%)',
}}
/>

<div className="relative flex flex-col gap-1 p-5">
<div className="flex items-center justify-between">
<div className="flex flex-col">
<h2 className="text-3xl font-black text-content">
{VERSION_NAME}
</h2>
<p className="mt-1 text-xs font-medium text-muted">
آدمیزاد به امید زندسـت! 🤞💙{' '}
</p>
</div>
</div>
</div>
</div>
Expand All @@ -145,7 +126,7 @@ export const UpdateReleaseNotesModal = ({
{releaseNotes.map((note, index) => (
<div
key={index}
className="flex flex-col gap-2 p-4 italic border bg-base-200/10 border-base-300/20 rounded-[2rem] animate-in fade-in slide-in-from-bottom-3"
className="flex flex-col gap-2 p-4 border bg-base-200/10 border-base-300/20 rounded-2xl animate-in fade-in slide-in-from-bottom-3"
style={{ animationDelay: `${index * 50}ms` }}
>
<div className="flex items-center justify-between">
Expand All @@ -164,11 +145,9 @@ export const UpdateReleaseNotesModal = ({
))}
</div>

<div className="flex items-center justify-center p-6 italic border border-dashed border-base-300/20 rounded-[2rem] opacity-30">
<div className="flex items-center justify-center p-6 text-muted">
<RiThumbUpLine className="ml-2" size={16} />
<span className="text-[9px] font-black tracking-widest uppercase">
دمت گرم که همراه مایی
</span>
<span className="text-xs">دمت گرم که همراه مایی</span>
</div>
</div>

Expand All @@ -177,15 +156,15 @@ export const UpdateReleaseNotesModal = ({
href="https://feedback.widgetify.ir"
target="_blank"
rel="noreferrer"
className="text-[10px] italic font-black text-muted hover:text-content transition-all underline decoration-dotted underline-offset-4"
className="text-[10px] font-black text-muted hover:text-content transition-all underline decoration-dotted underline-offset-4"
>
پیشنهاد یا گزارش مشکل
</a>
<Button
size="sm"
onClick={onClose}
disabled={counter > 0}
className="min-w-[130px] h-11 !rounded-2xl font-black italic text-[11px] shadow-lg shadow-primary/10 disabled:shadow-none active:scale-90 transition-all disabled:text-base-content/30"
className="min-w-[130px] h-11 !rounded-2xl font-black text-xs shadow-lg shadow-primary/10 disabled:shadow-none active:scale-90 transition-all disabled:text-base-content/30"
isPrimary={true}
>
{counter > 0 ? `یه چند لحظه صبر کن (${counter})` : 'فهمیدم'}
Expand Down
73 changes: 73 additions & 0 deletions src/components/tab-navigation.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import type React from 'react'

interface TabItem<T> {
id: T
label: string
icon?: React.ReactNode
}

interface TabNavigationProps<T> {
tabs: TabItem<T>[]
activeTab: T | null
onTabClick: (tab: T) => void
size?: 'small' | 'medium' | 'large'
className?: string
}

export const TabNavigation = <T,>({
tabs,
activeTab,
onTabClick,
size = 'medium',
className = '',
}: TabNavigationProps<T>) => {
const sizeClasses = {
small: 'py-1 px-2 text-[10px]',
medium: 'py-2 px-1 text-xs',
large: 'py-3 px-2 text-sm',
}

return (
<div
className={`flex items-center p-1 bg-base-300/40 rounded-2xl border border-base-content/5 ${className}`}
>
{tabs.map((tab) => {
const isActive = activeTab === tab.id

return (
<button
key={tab.id as unknown as string}
type="button"
onClick={() => onTabClick(tab.id)}
className={`
flex-1 flex items-center justify-center gap-1
cursor-pointer rounded-xl
transition-all duration-200
active:scale-95 z-10
${sizeClasses[size]}
${
isActive
? 'bg-primary text-white shadow-md'
: 'text-base-content/50 hover:text-base-content hover:bg-base-content/5 active:bg-base-content/10'
}
`}
>
{tab.icon && (
<span
className={`transition-transform duration-200 ${isActive ? 'scale-110' : ''}`}
>
{tab.icon}
</span>
)}

<span
className={`block font-semibold truncate transition-opacity ${isActive ? 'opacity-100' : 'opacity-80'}`}
>
{tab.label}
</span>
</button>
)
})}
</div>
)
}
39 changes: 39 additions & 0 deletions src/context/page.context.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { listenEvent } from '@/common/utils/call-event'
import type React from 'react'
import { createContext, useContext, useState } from 'react'

type Page = 'home' | 'explorer'
interface PageContextType {
page: Page
setPage: (page: Page) => void
}

export const PageContext = createContext<PageContextType | null>(null)
export function PageProvider({ children }: { children: React.ReactNode }) {
const [page, setPage] = useState<Page>('home')

useEffect(() => {
const event = listenEvent('go_to_page', (p) => {
console.log('listenEvent', p)
setPage(p)
})
console.log('listenEvent go_to_page')
return () => {
event()
}
}, [])

return (
<PageContext.Provider value={{ page, setPage }}>{children}</PageContext.Provider>
)
}

export function usePage() {
const context = useContext(PageContext)

if (!context) {
throw new Error('usePage must be used within a PageProvider')
}

return context
}
Loading