Skip to content

Commit 373e50b

Browse files
authored
Merge pull request #379 from widgetify-app/feature/notification-system-and-mood-tracker
Feature/notification system and mood tracker
2 parents 3c39426 + 79a1a7a commit 373e50b

53 files changed

Lines changed: 1530 additions & 1018 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

src/App.tsx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { AppearanceProvider } from './context/appearance.context'
33
import { AuthProvider } from './context/auth.context'
44
import { ThemeProvider } from './context/theme.context'
55
import { HomePage } from './pages/home'
6+
import { PageProvider } from './context/page.context'
67

78
const queryClient = new QueryClient({
89
defaultOptions: {
@@ -18,7 +19,9 @@ function App() {
1819
<AuthProvider>
1920
<ThemeProvider>
2021
<AppearanceProvider>
21-
<HomePage />
22+
<PageProvider>
23+
<HomePage />
24+
</PageProvider>
2225
</AppearanceProvider>
2326
</ThemeProvider>
2427
</AuthProvider>

src/common/constant/config.key.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
export enum ConfigKey {
2-
VERSION_NAME = 'نسخه یلدا 🍉',
2+
VERSION_NAME = 'امید',
33
WIG_COIN_ICON = 'https://cdn.widgetify.ir/extension/wig-icon.png',
44
}

src/common/constant/moods.ts

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
export const moodOptions = [
2+
{
3+
value: 'sad',
4+
emoji: '😔',
5+
label: 'ناراحتم',
6+
colorClass: 'error',
7+
borderClass: 'border-error/50',
8+
},
9+
{
10+
value: 'tired',
11+
emoji: '😴',
12+
label: 'خستم',
13+
colorClass: 'warning',
14+
borderClass: 'border-yellow-400/50',
15+
},
16+
{
17+
value: 'happy',
18+
emoji: '🙂',
19+
label: 'اوکی‌ام',
20+
colorClass: 'secondary',
21+
borderClass: 'border-secondary/50',
22+
},
23+
{
24+
value: 'excited',
25+
emoji: '😄',
26+
label: 'سرحالم',
27+
colorClass: 'success',
28+
borderClass: 'border-green-400/50',
29+
},
30+
]

src/common/constant/priority_options.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ export const PRIORITY_OPTIONS = [
1313
},
1414
{
1515
value: 'high',
16-
ariaLabel: 'اولویت زیاد',
16+
ariaLabel: 'اولویت مهم',
1717
bgColor: 'bg-red-500',
1818
hoverBgColor: 'hover:bg-red-500',
1919
},

src/common/constant/store.key.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,4 +89,5 @@ export interface StorageKV {
8989
petState: boolean
9090
showNewBadgeForReOrderWidgets: boolean
9191
navbarVisible: boolean
92+
[key: `removed_notification_${string}`]: string
9293
}

src/common/storage.ts

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,3 +57,31 @@ export async function clearStorage() {
5757
export async function removeFromStorage<K extends keyof StorageKV>(key: K) {
5858
await storage.removeItem(`local:${key}`)
5959
}
60+
61+
export async function setWithExpiry<K extends keyof StorageKV>(
62+
key: K,
63+
value: StorageKV[K],
64+
minutes: number
65+
) {
66+
const expiry = Date.now() + minutes * 60000
67+
const data = { value, expiry }
68+
69+
await setToStorage(key, data as any)
70+
}
71+
72+
export async function getWithExpiry<K extends keyof StorageKV>(
73+
key: K
74+
): Promise<StorageKV[K] | null> {
75+
const data = (await getFromStorage(key)) as any
76+
77+
if (!data || typeof data !== 'object' || !('expiry' in data)) {
78+
return data
79+
}
80+
81+
if (Date.now() > data.expiry) {
82+
await removeFromStorage(key)
83+
return null
84+
}
85+
86+
return data.value as StorageKV[K]
87+
}

src/common/utils/call-event.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import type { WidgetTabKeys } from '@/layouts/widgets-settings/constant/tab-keys
1111
import type { StoredWallpaper } from '../wallpaper.interface'
1212
import type { Todo } from '@/services/hooks/todo/todo.interface'
1313
import type { FontFamily } from '@/context/appearance.context'
14+
import React from 'react'
1415

1516
export interface EventName {
1617
startSync: SyncTarget
@@ -31,8 +32,6 @@ export interface EventName {
3132
name: string
3233
template: string
3334
}
34-
openExplorerPage: null
35-
closeExplorerPage: null
3635

3736
// setting keys
3837
wigiPadDateSettingsChanged: WigiPadDateSetting
@@ -49,6 +48,9 @@ export interface EventName {
4948
font_change: FontFamily
5049
close_all_modals: null
5150
openWizardModal: null
51+
add_to_notifications: { id: string; node: React.ReactNode }
52+
remove_from_notifications: { id: string; ttl?: number }
53+
go_to_page: 'explorer' | 'home'
5254
}
5355

5456
export function callEvent<K extends keyof EventName>(eventName: K, data?: EventName[K]) {

src/components/UpdateReleaseNotesModal.tsx

Lines changed: 33 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -27,45 +27,14 @@ const VERSION_NAME = ConfigKey.VERSION_NAME
2727

2828
const releaseNotes: ReleaseNote[] = [
2929
{
30-
title: 'ویرایش وظایف',
31-
type: 'feature',
32-
description:
33-
'بالاخره اضافه شد! دیگه لازم نیست برای یه تغییر کوچیک، کل تسک رو پاک کنی و از اول بنویسی.',
34-
},
35-
{
36-
title: 'برنامه‌ریزی دقیق‌تر',
37-
type: 'feature',
38-
description:
39-
'حالا می‌تونی برای کارهات تاریخ و میزان اهمیت (اولویت) تعیین کنی تا هیچ چیزی یادت نره.',
40-
},
41-
{
42-
title: 'انتخاب راحت‌تر شهر',
4330
type: 'improvement',
44-
description:
45-
'بخش آب‌وهوا رو جوری ردیف کردیم که خیلی سریع‌تر و راحت‌تر بتونی شهرت رو پیدا کنی.',
31+
title: 'بهبود ظاهری',
32+
description: 'ظاهر بعضی از قسمت هارو بهتر کردیم',
4633
},
4734
{
48-
title: 'خوشگل‌سازی منو',
49-
type: 'improvement',
50-
description:
51-
'منوی دسترسی پایین رو کمی دست‌کاری کردیم تا هم خوشگل‌تر بشه و هم کار کردن باهاش حال بده.',
52-
},
53-
{
54-
title: 'آب‌وهوای خلوت‌تر',
55-
type: 'improvement',
56-
description:
57-
'ویجت آب‌وهوا رو ساده کردیم تا فقط چیزایی که لازمه رو در یک نگاه ببینی.',
58-
},
59-
{
60-
title: 'بهبود فیلترهای صوتی',
61-
type: 'improvement',
62-
description:
63-
'بخش فیلترها و صداهای لیست وظایف رو بهینه کردیم تا حس بهتری موقع کار داشته باشی.',
64-
},
65-
{
66-
title: 'خداحافظی با فضای خالی',
6735
type: 'bugfix',
68-
description: 'اون فضای خالی و اضافه پایین پنجره‌ها که رو مخ بود رو کلاً حذف کردیم.',
36+
title: 'رفع چندین مشکل جزئی',
37+
description: 'با سپاس از شما، مشکلات گزارش شده رو برطرف کردیم',
6938
},
7039
]
7140

@@ -124,18 +93,30 @@ export const UpdateReleaseNotesModal = ({
12493
showCloseButton={false}
12594
>
12695
<div className="flex flex-col max-h-[80vh]">
127-
<div className="flex flex-col gap-1 p-4 border-b border-base-300/20 bg-base-200/20">
128-
<div className="flex items-center justify-between">
129-
<div className="flex flex-col italic">
130-
<h2 className="text-3xl font-black text-content">
131-
{VERSION_NAME}
132-
</h2>
133-
<p className="mt-1 text-xs font-medium text-muted opacity-60">
134-
تغییرات جدید برای طولانی‌ترین شب سال
135-
</p>
136-
</div>
137-
<div className="p-2 border rounded-2xl bg-base-200/50 text-primary border-base-300/20">
138-
<RiCompassDiscoverLine size={24} />
96+
<div className="relative overflow-hidden border-b border-base-300/20 rounded-2xl h-28">
97+
<div
98+
className="absolute inset-0 scale-105 bg-center bg-no-repeat bg-cover animate-pan"
99+
style={{
100+
backgroundImage:
101+
'url(http://cdn.widgetify.ir/extension/hope.png)',
102+
filter: 'brightness(0.35) contrast(1.1)',
103+
maskImage:
104+
'linear-gradient(to bottom, black 0%, transparent 100%)',
105+
WebkitMaskImage:
106+
'linear-gradient(to bottom, black 0%, transparent 100%)',
107+
}}
108+
/>
109+
110+
<div className="relative flex flex-col gap-1 p-5">
111+
<div className="flex items-center justify-between">
112+
<div className="flex flex-col">
113+
<h2 className="text-3xl font-black text-content">
114+
{VERSION_NAME}
115+
</h2>
116+
<p className="mt-1 text-xs font-medium text-muted">
117+
آدمیزاد به امید زندسـت! 🤞💙{' '}
118+
</p>
119+
</div>
139120
</div>
140121
</div>
141122
</div>
@@ -145,7 +126,7 @@ export const UpdateReleaseNotesModal = ({
145126
{releaseNotes.map((note, index) => (
146127
<div
147128
key={index}
148-
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"
129+
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"
149130
style={{ animationDelay: `${index * 50}ms` }}
150131
>
151132
<div className="flex items-center justify-between">
@@ -164,11 +145,9 @@ export const UpdateReleaseNotesModal = ({
164145
))}
165146
</div>
166147

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

@@ -177,15 +156,15 @@ export const UpdateReleaseNotesModal = ({
177156
href="https://feedback.widgetify.ir"
178157
target="_blank"
179158
rel="noreferrer"
180-
className="text-[10px] italic font-black text-muted hover:text-content transition-all underline decoration-dotted underline-offset-4"
159+
className="text-[10px] font-black text-muted hover:text-content transition-all underline decoration-dotted underline-offset-4"
181160
>
182161
پیشنهاد یا گزارش مشکل
183162
</a>
184163
<Button
185164
size="sm"
186165
onClick={onClose}
187166
disabled={counter > 0}
188-
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"
167+
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"
189168
isPrimary={true}
190169
>
191170
{counter > 0 ? `یه چند لحظه صبر کن (${counter})` : 'فهمیدم'}

src/components/tab-navigation.tsx

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
import type React from 'react'
2+
3+
interface TabItem<T> {
4+
id: T
5+
label: string
6+
icon?: React.ReactNode
7+
}
8+
9+
interface TabNavigationProps<T> {
10+
tabs: TabItem<T>[]
11+
activeTab: T | null
12+
onTabClick: (tab: T) => void
13+
size?: 'small' | 'medium' | 'large'
14+
className?: string
15+
}
16+
17+
export const TabNavigation = <T,>({
18+
tabs,
19+
activeTab,
20+
onTabClick,
21+
size = 'medium',
22+
className = '',
23+
}: TabNavigationProps<T>) => {
24+
const sizeClasses = {
25+
small: 'py-1 px-2 text-[10px]',
26+
medium: 'py-2 px-1 text-xs',
27+
large: 'py-3 px-2 text-sm',
28+
}
29+
30+
return (
31+
<div
32+
className={`flex items-center p-1 bg-base-300/40 rounded-2xl border border-base-content/5 ${className}`}
33+
>
34+
{tabs.map((tab) => {
35+
const isActive = activeTab === tab.id
36+
37+
return (
38+
<button
39+
key={tab.id as unknown as string}
40+
type="button"
41+
onClick={() => onTabClick(tab.id)}
42+
className={`
43+
flex-1 flex items-center justify-center gap-1
44+
cursor-pointer rounded-xl
45+
transition-all duration-200
46+
active:scale-95 z-10
47+
${sizeClasses[size]}
48+
${
49+
isActive
50+
? 'bg-primary text-white shadow-md'
51+
: 'text-base-content/50 hover:text-base-content hover:bg-base-content/5 active:bg-base-content/10'
52+
}
53+
`}
54+
>
55+
{tab.icon && (
56+
<span
57+
className={`transition-transform duration-200 ${isActive ? 'scale-110' : ''}`}
58+
>
59+
{tab.icon}
60+
</span>
61+
)}
62+
63+
<span
64+
className={`block font-semibold truncate transition-opacity ${isActive ? 'opacity-100' : 'opacity-80'}`}
65+
>
66+
{tab.label}
67+
</span>
68+
</button>
69+
)
70+
})}
71+
</div>
72+
)
73+
}

src/context/page.context.tsx

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
import { listenEvent } from '@/common/utils/call-event'
2+
import type React from 'react'
3+
import { createContext, useContext, useState } from 'react'
4+
5+
type Page = 'home' | 'explorer'
6+
interface PageContextType {
7+
page: Page
8+
setPage: (page: Page) => void
9+
}
10+
11+
export const PageContext = createContext<PageContextType | null>(null)
12+
export function PageProvider({ children }: { children: React.ReactNode }) {
13+
const [page, setPage] = useState<Page>('home')
14+
15+
useEffect(() => {
16+
const event = listenEvent('go_to_page', (p) => {
17+
console.log('listenEvent', p)
18+
setPage(p)
19+
})
20+
console.log('listenEvent go_to_page')
21+
return () => {
22+
event()
23+
}
24+
}, [])
25+
26+
return (
27+
<PageContext.Provider value={{ page, setPage }}>{children}</PageContext.Provider>
28+
)
29+
}
30+
31+
export function usePage() {
32+
const context = useContext(PageContext)
33+
34+
if (!context) {
35+
throw new Error('usePage must be used within a PageProvider')
36+
}
37+
38+
return context
39+
}

0 commit comments

Comments
 (0)