feat: support primary color customization
This commit is contained in:
@@ -2,6 +2,7 @@ import Icon from '@/assets/Icon'
|
||||
import Logo from '@/assets/Logo'
|
||||
import { cn } from '@/lib/utils'
|
||||
import { useScreenSize } from '@/providers/ScreenSizeProvider'
|
||||
import { useTheme } from '@/providers/ThemeProvider'
|
||||
import { useUserPreferences } from '@/providers/UserPreferencesProvider'
|
||||
import { ChevronsLeft, ChevronsRight } from 'lucide-react'
|
||||
import AccountButton from './AccountButton'
|
||||
@@ -15,6 +16,7 @@ import SettingsButton from './SettingsButton'
|
||||
|
||||
export default function PrimaryPageSidebar() {
|
||||
const { isSmallScreen } = useScreenSize()
|
||||
const { themeSetting } = useTheme()
|
||||
const { sidebarCollapse, updateSidebarCollapse } = useUserPreferences()
|
||||
|
||||
if (isSmallScreen) return null
|
||||
@@ -46,7 +48,10 @@ export default function PrimaryPageSidebar() {
|
||||
</div>
|
||||
<AccountButton collapse={sidebarCollapse} />
|
||||
<button
|
||||
className="absolute flex flex-col justify-center items-center top-5 right-0 w-5 h-6 p-0 rounded-l-md hover:shadow-md text-muted-foreground hover:text-foreground hover:bg-background transition-colors [&_svg]:size-4"
|
||||
className={cn(
|
||||
'absolute flex flex-col justify-center items-center right-0 w-5 h-6 p-0 rounded-l-md hover:shadow-md text-muted-foreground hover:text-foreground hover:bg-background transition-colors [&_svg]:size-4',
|
||||
themeSetting === 'pure-black' ? 'top-3' : 'top-5'
|
||||
)}
|
||||
onClick={(e) => {
|
||||
e.stopPropagation()
|
||||
updateSidebarCollapse(!sidebarCollapse)
|
||||
|
||||
239
src/constants.ts
239
src/constants.ts
@@ -49,6 +49,7 @@ export const StorageKey = {
|
||||
MEDIA_AUTO_LOAD_POLICY: 'mediaAutoLoadPolicy',
|
||||
SHOWN_CREATE_WALLET_GUIDE_TOAST_PUBKEYS: 'shownCreateWalletGuideToastPubkeys',
|
||||
SIDEBAR_COLLAPSE: 'sidebarCollapse',
|
||||
PRIMARY_COLOR: 'primaryColor',
|
||||
MEDIA_UPLOAD_SERVICE: 'mediaUploadService', // deprecated
|
||||
HIDE_UNTRUSTED_EVENTS: 'hideUntrustedEvents', // deprecated
|
||||
ACCOUNT_RELAY_LIST_EVENT_MAP: 'accountRelayListEventMap', // deprecated
|
||||
@@ -156,3 +157,241 @@ export const MEDIA_AUTO_LOAD_POLICY = {
|
||||
} as const
|
||||
|
||||
export const MAX_PINNED_NOTES = 10
|
||||
|
||||
export const PRIMARY_COLORS = {
|
||||
DEFAULT: {
|
||||
name: 'Default',
|
||||
light: {
|
||||
primary: '259 43% 56%',
|
||||
'primary-hover': '259 43% 65%',
|
||||
'primary-foreground': '0 0% 98%'
|
||||
},
|
||||
dark: {
|
||||
primary: '259 43% 56%',
|
||||
'primary-hover': '259 43% 65%',
|
||||
'primary-foreground': '240 5.9% 10%'
|
||||
}
|
||||
},
|
||||
RED: {
|
||||
name: 'Red',
|
||||
light: {
|
||||
primary: '0 65% 55%',
|
||||
'primary-hover': '0 65% 65%',
|
||||
'primary-foreground': '0 0% 98%'
|
||||
},
|
||||
dark: {
|
||||
primary: '0 65% 55%',
|
||||
'primary-hover': '0 65% 65%',
|
||||
'primary-foreground': '240 5.9% 10%'
|
||||
}
|
||||
},
|
||||
ORANGE: {
|
||||
name: 'Orange',
|
||||
light: {
|
||||
primary: '30 100% 50%',
|
||||
'primary-hover': '30 100% 60%',
|
||||
'primary-foreground': '0 0% 98%'
|
||||
},
|
||||
dark: {
|
||||
primary: '30 100% 50%',
|
||||
'primary-hover': '30 100% 60%',
|
||||
'primary-foreground': '240 5.9% 10%'
|
||||
}
|
||||
},
|
||||
AMBER: {
|
||||
name: 'Amber',
|
||||
light: {
|
||||
primary: '42 100% 50%',
|
||||
'primary-hover': '42 100% 60%',
|
||||
'primary-foreground': '0 0% 98%'
|
||||
},
|
||||
dark: {
|
||||
primary: '42 100% 50%',
|
||||
'primary-hover': '42 100% 60%',
|
||||
'primary-foreground': '240 5.9% 10%'
|
||||
}
|
||||
},
|
||||
YELLOW: {
|
||||
name: 'Yellow',
|
||||
light: {
|
||||
primary: '54 100% 50%',
|
||||
'primary-hover': '54 100% 60%',
|
||||
'primary-foreground': '0 0% 10%'
|
||||
},
|
||||
dark: {
|
||||
primary: '54 100% 50%',
|
||||
'primary-hover': '54 100% 60%',
|
||||
'primary-foreground': '240 5.9% 10%'
|
||||
}
|
||||
},
|
||||
LIME: {
|
||||
name: 'Lime',
|
||||
light: {
|
||||
primary: '90 60% 50%',
|
||||
'primary-hover': '90 60% 60%',
|
||||
'primary-foreground': '0 0% 98%'
|
||||
},
|
||||
dark: {
|
||||
primary: '90 60% 50%',
|
||||
'primary-hover': '90 60% 60%',
|
||||
'primary-foreground': '240 5.9% 10%'
|
||||
}
|
||||
},
|
||||
GREEN: {
|
||||
name: 'Green',
|
||||
light: {
|
||||
primary: '140 60% 40%',
|
||||
'primary-hover': '140 60% 50%',
|
||||
'primary-foreground': '0 0% 98%'
|
||||
},
|
||||
dark: {
|
||||
primary: '140 60% 40%',
|
||||
'primary-hover': '140 60% 50%',
|
||||
'primary-foreground': '240 5.9% 10%'
|
||||
}
|
||||
},
|
||||
EMERALD: {
|
||||
name: 'Emerald',
|
||||
light: {
|
||||
primary: '160 70% 40%',
|
||||
'primary-hover': '160 70% 50%',
|
||||
'primary-foreground': '0 0% 98%'
|
||||
},
|
||||
dark: {
|
||||
primary: '160 70% 40%',
|
||||
'primary-hover': '160 70% 50%',
|
||||
'primary-foreground': '240 5.9% 10%'
|
||||
}
|
||||
},
|
||||
TEAL: {
|
||||
name: 'Teal',
|
||||
light: {
|
||||
primary: '180 70% 40%',
|
||||
'primary-hover': '180 70% 50%',
|
||||
'primary-foreground': '0 0% 98%'
|
||||
},
|
||||
dark: {
|
||||
primary: '180 70% 40%',
|
||||
'primary-hover': '180 70% 50%',
|
||||
'primary-foreground': '240 5.9% 10%'
|
||||
}
|
||||
},
|
||||
CYAN: {
|
||||
name: 'Cyan',
|
||||
light: {
|
||||
primary: '200 70% 40%',
|
||||
'primary-hover': '200 70% 50%',
|
||||
'primary-foreground': '0 0% 98%'
|
||||
},
|
||||
dark: {
|
||||
primary: '200 70% 40%',
|
||||
'primary-hover': '200 70% 50%',
|
||||
'primary-foreground': '240 5.9% 10%'
|
||||
}
|
||||
},
|
||||
SKY: {
|
||||
name: 'Sky',
|
||||
light: {
|
||||
primary: '210 70% 50%',
|
||||
'primary-hover': '210 70% 60%',
|
||||
'primary-foreground': '0 0% 98%'
|
||||
},
|
||||
dark: {
|
||||
primary: '210 70% 50%',
|
||||
'primary-hover': '210 70% 60%',
|
||||
'primary-foreground': '240 5.9% 10%'
|
||||
}
|
||||
},
|
||||
BLUE: {
|
||||
name: 'Blue',
|
||||
light: {
|
||||
primary: '220 80% 50%',
|
||||
'primary-hover': '220 80% 60%',
|
||||
'primary-foreground': '0 0% 98%'
|
||||
},
|
||||
dark: {
|
||||
primary: '220 80% 50%',
|
||||
'primary-hover': '220 80% 60%',
|
||||
'primary-foreground': '240 5.9% 10%'
|
||||
}
|
||||
},
|
||||
INDIGO: {
|
||||
name: 'Indigo',
|
||||
light: {
|
||||
primary: '230 80% 50%',
|
||||
'primary-hover': '230 80% 60%',
|
||||
'primary-foreground': '0 0% 98%'
|
||||
},
|
||||
dark: {
|
||||
primary: '230 80% 50%',
|
||||
'primary-hover': '230 80% 60%',
|
||||
'primary-foreground': '240 5.9% 10%'
|
||||
}
|
||||
},
|
||||
VIOLET: {
|
||||
name: 'Violet',
|
||||
light: {
|
||||
primary: '250 80% 50%',
|
||||
'primary-hover': '250 80% 60%',
|
||||
'primary-foreground': '0 0% 98%'
|
||||
},
|
||||
dark: {
|
||||
primary: '250 80% 50%',
|
||||
'primary-hover': '250 80% 60%',
|
||||
'primary-foreground': '240 5.9% 10%'
|
||||
}
|
||||
},
|
||||
PURPLE: {
|
||||
name: 'Purple',
|
||||
light: {
|
||||
primary: '280 80% 50%',
|
||||
'primary-hover': '280 80% 60%',
|
||||
'primary-foreground': '0 0% 98%'
|
||||
},
|
||||
dark: {
|
||||
primary: '280 80% 50%',
|
||||
'primary-hover': '280 80% 60%',
|
||||
'primary-foreground': '240 5.9% 10%'
|
||||
}
|
||||
},
|
||||
FUCHSIA: {
|
||||
name: 'Fuchsia',
|
||||
light: {
|
||||
primary: '310 80% 50%',
|
||||
'primary-hover': '310 80% 60%',
|
||||
'primary-foreground': '0 0% 98%'
|
||||
},
|
||||
dark: {
|
||||
primary: '310 80% 50%',
|
||||
'primary-hover': '310 80% 60%',
|
||||
'primary-foreground': '240 5.9% 10%'
|
||||
}
|
||||
},
|
||||
PINK: {
|
||||
name: 'Pink',
|
||||
light: {
|
||||
primary: '330 80% 60%',
|
||||
'primary-hover': '330 80% 70%',
|
||||
'primary-foreground': '0 0% 10%'
|
||||
},
|
||||
dark: {
|
||||
primary: '330 80% 60%',
|
||||
'primary-hover': '330 80% 70%',
|
||||
'primary-foreground': '240 5.9% 10%'
|
||||
}
|
||||
},
|
||||
ROSE: {
|
||||
name: 'Rose',
|
||||
light: {
|
||||
primary: '350 80% 60%',
|
||||
'primary-hover': '350 80% 70%',
|
||||
'primary-foreground': '0 0% 10%'
|
||||
},
|
||||
dark: {
|
||||
primary: '350 80% 60%',
|
||||
'primary-hover': '350 80% 70%',
|
||||
'primary-foreground': '240 5.9% 10%'
|
||||
}
|
||||
}
|
||||
} as const
|
||||
export type TPrimaryColor = keyof typeof PRIMARY_COLORS
|
||||
|
||||
@@ -457,6 +457,25 @@ export default {
|
||||
'Unpin from profile': 'إلغاء التثبيت من الملف الشخصي',
|
||||
'Pin to profile': 'تثبيت في الملف الشخصي',
|
||||
Appearance: 'المظهر',
|
||||
'Pure Black': 'أسود نقي'
|
||||
'Pure Black': 'أسود نقي',
|
||||
Default: 'افتراضي',
|
||||
Red: 'أحمر',
|
||||
Orange: 'برتقالي',
|
||||
Amber: 'عنبر',
|
||||
Yellow: 'أصفر',
|
||||
Lime: 'ليموني',
|
||||
Green: 'أخضر',
|
||||
Emerald: 'زمردي',
|
||||
Teal: 'أزرق مخضر',
|
||||
Cyan: 'سماوي',
|
||||
Sky: 'سماء',
|
||||
Blue: 'أزرق',
|
||||
Indigo: 'نيلي',
|
||||
Violet: 'بنفسجي',
|
||||
Purple: 'أرجواني',
|
||||
Fuchsia: 'فوشيا',
|
||||
Pink: 'وردي',
|
||||
Rose: 'وردة',
|
||||
'Primary color': 'اللون الأساسي'
|
||||
}
|
||||
}
|
||||
|
||||
@@ -471,6 +471,25 @@ export default {
|
||||
'Unpin from profile': 'Vom Profil lösen',
|
||||
'Pin to profile': 'An Profil anheften',
|
||||
Appearance: 'Aussehen',
|
||||
'Pure Black': 'Reines Schwarz'
|
||||
'Pure Black': 'Reines Schwarz',
|
||||
Default: 'Standard',
|
||||
Red: 'Rot',
|
||||
Orange: 'Orange',
|
||||
Amber: 'Bernstein',
|
||||
Yellow: 'Gelb',
|
||||
Lime: 'Limette',
|
||||
Green: 'Grün',
|
||||
Emerald: 'Smaragd',
|
||||
Teal: 'Blaugrün',
|
||||
Cyan: 'Cyan',
|
||||
Sky: 'Himmelblau',
|
||||
Blue: 'Blau',
|
||||
Indigo: 'Indigo',
|
||||
Violet: 'Violett',
|
||||
Purple: 'Lila',
|
||||
Fuchsia: 'Fuchsia',
|
||||
Pink: 'Rosa',
|
||||
Rose: 'Rose',
|
||||
'Primary color': 'Primärfarbe'
|
||||
}
|
||||
}
|
||||
|
||||
@@ -456,6 +456,25 @@ export default {
|
||||
'Unpin from profile': 'Unpin from profile',
|
||||
'Pin to profile': 'Pin to profile',
|
||||
Appearance: 'Appearance',
|
||||
'Pure Black': 'Pure Black'
|
||||
'Pure Black': 'Pure Black',
|
||||
Default: 'Default',
|
||||
Red: 'Red',
|
||||
Orange: 'Orange',
|
||||
Amber: 'Amber',
|
||||
Yellow: 'Yellow',
|
||||
Lime: 'Lime',
|
||||
Green: 'Green',
|
||||
Emerald: 'Emerald',
|
||||
Teal: 'Teal',
|
||||
Cyan: 'Cyan',
|
||||
Sky: 'Sky',
|
||||
Blue: 'Blue',
|
||||
Indigo: 'Indigo',
|
||||
Violet: 'Violet',
|
||||
Purple: 'Purple',
|
||||
Fuchsia: 'Fuchsia',
|
||||
Pink: 'Pink',
|
||||
Rose: 'Rose',
|
||||
'Primary color': 'Primary color'
|
||||
}
|
||||
}
|
||||
|
||||
@@ -465,6 +465,25 @@ export default {
|
||||
'Unpin from profile': 'Desfijar del perfil',
|
||||
'Pin to profile': 'Fijar al perfil',
|
||||
Appearance: 'Apariencia',
|
||||
'Pure Black': 'Negro Puro'
|
||||
'Pure Black': 'Negro Puro',
|
||||
Default: 'Predeterminado',
|
||||
Red: 'Rojo',
|
||||
Orange: 'Naranja',
|
||||
Amber: 'Ámbar',
|
||||
Yellow: 'Amarillo',
|
||||
Lime: 'Lima',
|
||||
Green: 'Verde',
|
||||
Emerald: 'Esmeralda',
|
||||
Teal: 'Verde azulado',
|
||||
Cyan: 'Cian',
|
||||
Sky: 'Cielo',
|
||||
Blue: 'Azul',
|
||||
Indigo: 'Índigo',
|
||||
Violet: 'Violeta',
|
||||
Purple: 'Púrpura',
|
||||
Fuchsia: 'Fucsia',
|
||||
Pink: 'Rosa',
|
||||
Rose: 'Rosa',
|
||||
'Primary color': 'Color primario'
|
||||
}
|
||||
}
|
||||
|
||||
@@ -460,6 +460,25 @@ export default {
|
||||
'Unpin from profile': 'لغو پین از پروفایل',
|
||||
'Pin to profile': 'پین به پروفایل',
|
||||
Appearance: 'ظاهر',
|
||||
'Pure Black': 'سیاه خالص'
|
||||
'Pure Black': 'سیاه خالص',
|
||||
Default: 'پیشفرض',
|
||||
Red: 'قرمز',
|
||||
Orange: 'نارنجی',
|
||||
Amber: 'کهربایی',
|
||||
Yellow: 'زرد',
|
||||
Lime: 'لیمویی',
|
||||
Green: 'سبز',
|
||||
Emerald: 'زمردی',
|
||||
Teal: 'سبز آبی',
|
||||
Cyan: 'فیروزهای',
|
||||
Sky: 'آسمانی',
|
||||
Blue: 'آبی',
|
||||
Indigo: 'نیلی',
|
||||
Violet: 'بنفش',
|
||||
Purple: 'ارغوانی',
|
||||
Fuchsia: 'فوشیا',
|
||||
Pink: 'صورتی',
|
||||
Rose: 'گلی',
|
||||
'Primary color': 'رنگ اصلی'
|
||||
}
|
||||
}
|
||||
|
||||
@@ -470,6 +470,25 @@ export default {
|
||||
'Unpin from profile': 'Retirer l’épingle du profil',
|
||||
'Pin to profile': 'Épingler au profil',
|
||||
Appearance: 'Apparence',
|
||||
'Pure Black': 'Noir pur'
|
||||
'Pure Black': 'Noir pur',
|
||||
Default: 'Par défaut',
|
||||
Red: 'Rouge',
|
||||
Orange: 'Orange',
|
||||
Amber: 'Ambre',
|
||||
Yellow: 'Jaune',
|
||||
Lime: 'Citron vert',
|
||||
Green: 'Vert',
|
||||
Emerald: 'Émeraude',
|
||||
Teal: 'Sarcelle',
|
||||
Cyan: 'Cyan',
|
||||
Sky: 'Bleu ciel',
|
||||
Blue: 'Bleu',
|
||||
Indigo: 'Indigo',
|
||||
Violet: 'Violet',
|
||||
Purple: 'Pourpre',
|
||||
Fuchsia: 'Fuchsia',
|
||||
Pink: 'Rose',
|
||||
Rose: 'Rose',
|
||||
'Primary color': 'Couleur principale'
|
||||
}
|
||||
}
|
||||
|
||||
@@ -462,6 +462,25 @@ export default {
|
||||
'Unpin from profile': 'प्रोफ़ाइल से पिन हटाएं',
|
||||
'Pin to profile': 'प्रोफ़ाइल पर पिन करें',
|
||||
Appearance: 'दिखावट',
|
||||
'Pure Black': 'शुद्ध काला'
|
||||
'Pure Black': 'शुद्ध काला',
|
||||
Default: 'डिफ़ॉल्ट',
|
||||
Red: 'लाल',
|
||||
Orange: 'नारंगी',
|
||||
Amber: 'एम्बर',
|
||||
Yellow: 'पीला',
|
||||
Lime: 'नींबू',
|
||||
Green: 'हरा',
|
||||
Emerald: 'पन्ना',
|
||||
Teal: 'टील',
|
||||
Cyan: 'सियान',
|
||||
Sky: 'आसमानी',
|
||||
Blue: 'नीला',
|
||||
Indigo: 'नील',
|
||||
Violet: 'बैंगनी',
|
||||
Purple: 'जामुनी',
|
||||
Fuchsia: 'फुशिया',
|
||||
Pink: 'गुलाबी',
|
||||
Rose: 'गुलाब',
|
||||
'Primary color': 'प्राथमिक रंग'
|
||||
}
|
||||
}
|
||||
|
||||
@@ -465,6 +465,25 @@ export default {
|
||||
'Unpin from profile': 'Rimuovi fissaggio dal profilo',
|
||||
'Pin to profile': 'Fissa al profilo',
|
||||
Appearance: 'Aspetto',
|
||||
'Pure Black': 'Nero Puro'
|
||||
'Pure Black': 'Nero Puro',
|
||||
Default: 'Predefinito',
|
||||
Red: 'Rosso',
|
||||
Orange: 'Arancione',
|
||||
Amber: 'Ambra',
|
||||
Yellow: 'Giallo',
|
||||
Lime: 'Lime',
|
||||
Green: 'Verde',
|
||||
Emerald: 'Smeraldo',
|
||||
Teal: 'Turchese',
|
||||
Cyan: 'Ciano',
|
||||
Sky: 'Cielo',
|
||||
Blue: 'Blu',
|
||||
Indigo: 'Indaco',
|
||||
Violet: 'Viola',
|
||||
Purple: 'Porpora',
|
||||
Fuchsia: 'Fucsia',
|
||||
Pink: 'Rosa',
|
||||
Rose: 'Rosa',
|
||||
'Primary color': 'Colore primario'
|
||||
}
|
||||
}
|
||||
|
||||
@@ -461,6 +461,25 @@ export default {
|
||||
'Unpin from profile': 'プロフィールから固定解除',
|
||||
'Pin to profile': 'プロフィールに固定',
|
||||
Appearance: '外観',
|
||||
'Pure Black': '純黒'
|
||||
'Pure Black': '純黒',
|
||||
Default: 'デフォルト',
|
||||
Red: '赤',
|
||||
Orange: 'オレンジ',
|
||||
Amber: 'アンバー',
|
||||
Yellow: '黄色',
|
||||
Lime: 'ライム',
|
||||
Green: '緑',
|
||||
Emerald: 'エメラルド',
|
||||
Teal: 'ティール',
|
||||
Cyan: 'シアン',
|
||||
Sky: 'スカイ',
|
||||
Blue: '青',
|
||||
Indigo: 'インディゴ',
|
||||
Violet: 'バイオレット',
|
||||
Purple: '紫',
|
||||
Fuchsia: 'フクシア',
|
||||
Pink: 'ピンク',
|
||||
Rose: 'ローズ',
|
||||
'Primary color': '主要な色'
|
||||
}
|
||||
}
|
||||
|
||||
@@ -461,6 +461,25 @@ export default {
|
||||
'Unpin from profile': '프로필에서 고정 해제',
|
||||
'Pin to profile': '프로필에 고정',
|
||||
Appearance: '외관',
|
||||
'Pure Black': '순수한 검은색'
|
||||
'Pure Black': '순수한 검은색',
|
||||
Default: '기본',
|
||||
Red: '빨강',
|
||||
Orange: '주황',
|
||||
Amber: '호박색',
|
||||
Yellow: '노랑',
|
||||
Lime: '라임',
|
||||
Green: '초록',
|
||||
Emerald: '에메랄드',
|
||||
Teal: '청록',
|
||||
Cyan: '시안',
|
||||
Sky: '하늘색',
|
||||
Blue: '파랑',
|
||||
Indigo: '남색',
|
||||
Violet: '보라',
|
||||
Purple: '자주',
|
||||
Fuchsia: '자홍',
|
||||
Pink: '분홍',
|
||||
Rose: '장미',
|
||||
'Primary color': '기본 색상'
|
||||
}
|
||||
}
|
||||
|
||||
@@ -465,6 +465,25 @@ export default {
|
||||
'Unpin from profile': 'Odpiń z profilu',
|
||||
'Pin to profile': 'Przypnij do profilu',
|
||||
Appearance: 'Wygląd',
|
||||
'Pure Black': 'Czysta Czerń'
|
||||
'Pure Black': 'Czysta Czerń',
|
||||
Default: 'Domyślny',
|
||||
Red: 'Czerwony',
|
||||
Orange: 'Pomarańczowy',
|
||||
Amber: 'Bursztynowy',
|
||||
Yellow: 'Żółty',
|
||||
Lime: 'Limonkowy',
|
||||
Green: 'Zielony',
|
||||
Emerald: 'Szmaragdowy',
|
||||
Teal: 'Morski',
|
||||
Cyan: 'Cyjan',
|
||||
Sky: 'Niebieski',
|
||||
Blue: 'Niebieski',
|
||||
Indigo: 'Indygo',
|
||||
Violet: 'Fioletowy',
|
||||
Purple: 'Purpurowy',
|
||||
Fuchsia: 'Fuksja',
|
||||
Pink: 'Różowy',
|
||||
Rose: 'Różany',
|
||||
'Primary color': 'Kolor podstawowy'
|
||||
}
|
||||
}
|
||||
|
||||
@@ -462,6 +462,25 @@ export default {
|
||||
'Unpin from profile': 'Desafixar do perfil',
|
||||
'Pin to profile': 'Fixar no perfil',
|
||||
Appearance: 'Aparência',
|
||||
'Pure Black': 'Preto Puro'
|
||||
'Pure Black': 'Preto Puro',
|
||||
Default: 'Padrão',
|
||||
Red: 'Vermelho',
|
||||
Orange: 'Laranja',
|
||||
Amber: 'Âmbar',
|
||||
Yellow: 'Amarelo',
|
||||
Lime: 'Lima',
|
||||
Green: 'Verde',
|
||||
Emerald: 'Esmeralda',
|
||||
Teal: 'Turquesa',
|
||||
Cyan: 'Ciano',
|
||||
Sky: 'Céu',
|
||||
Blue: 'Azul',
|
||||
Indigo: 'Índigo',
|
||||
Violet: 'Violeta',
|
||||
Purple: 'Roxo',
|
||||
Fuchsia: 'Fúcsia',
|
||||
Pink: 'Rosa',
|
||||
Rose: 'Rosa',
|
||||
'Primary color': 'Cor primária'
|
||||
}
|
||||
}
|
||||
|
||||
@@ -465,6 +465,25 @@ export default {
|
||||
'Unpin from profile': 'Desafixar do perfil',
|
||||
'Pin to profile': 'Fixar no perfil',
|
||||
Appearance: 'Aparência',
|
||||
'Pure Black': 'Preto Puro'
|
||||
'Pure Black': 'Preto Puro',
|
||||
Default: 'Padrão',
|
||||
Red: 'Vermelho',
|
||||
Orange: 'Laranja',
|
||||
Amber: 'Âmbar',
|
||||
Yellow: 'Amarelo',
|
||||
Lime: 'Lima',
|
||||
Green: 'Verde',
|
||||
Emerald: 'Esmeralda',
|
||||
Teal: 'Turquesa',
|
||||
Cyan: 'Ciano',
|
||||
Sky: 'Céu',
|
||||
Blue: 'Azul',
|
||||
Indigo: 'Índigo',
|
||||
Violet: 'Violeta',
|
||||
Purple: 'Roxo',
|
||||
Fuchsia: 'Fúcsia',
|
||||
Pink: 'Rosa',
|
||||
Rose: 'Rosa',
|
||||
'Primary color': 'Cor primária'
|
||||
}
|
||||
}
|
||||
|
||||
@@ -467,6 +467,25 @@ export default {
|
||||
'Unpin from profile': 'Открепить из профиля',
|
||||
'Pin to profile': 'Закрепить в профиле',
|
||||
Appearance: 'Внешний вид',
|
||||
'Pure Black': 'Чистый Черный'
|
||||
'Pure Black': 'Чистый Черный',
|
||||
Default: 'По умолчанию',
|
||||
Red: 'Красный',
|
||||
Orange: 'Оранжевый',
|
||||
Amber: 'Янтарный',
|
||||
Yellow: 'Желтый',
|
||||
Lime: 'Лаймовый',
|
||||
Green: 'Зеленый',
|
||||
Emerald: 'Изумрудный',
|
||||
Teal: 'Бирюзовый',
|
||||
Cyan: 'Голубой',
|
||||
Sky: 'Небесный',
|
||||
Blue: 'Синий',
|
||||
Indigo: 'Индиго',
|
||||
Violet: 'Фиолетовый',
|
||||
Purple: 'Пурпурный',
|
||||
Fuchsia: 'Фуксия',
|
||||
Pink: 'Розовый',
|
||||
Rose: 'Роза',
|
||||
'Primary color': 'Основной цвет'
|
||||
}
|
||||
}
|
||||
|
||||
@@ -455,6 +455,25 @@ export default {
|
||||
'Unpin from profile': 'ยกเลิกปักหมุดจากโปรไฟล์',
|
||||
'Pin to profile': 'ปักหมุดไปที่โปรไฟล์',
|
||||
Appearance: 'รูปลักษณ์',
|
||||
'Pure Black': 'สีดำล้วน'
|
||||
'Pure Black': 'สีดำล้วน',
|
||||
Default: 'ค่าเริ่มต้น',
|
||||
Red: 'แดง',
|
||||
Orange: 'ส้ม',
|
||||
Amber: 'อำพัน',
|
||||
Yellow: 'เหลือง',
|
||||
Lime: 'มะนาว',
|
||||
Green: 'เขียว',
|
||||
Emerald: 'มรกต',
|
||||
Teal: 'ฟ้าเขียว',
|
||||
Cyan: 'ฟ้าน้ำทะเล',
|
||||
Sky: 'ฟ้า',
|
||||
Blue: 'น้ำเงิน',
|
||||
Indigo: 'คราม',
|
||||
Violet: 'ม่วงอ่อน',
|
||||
Purple: 'ม่วง',
|
||||
Fuchsia: 'บานเย็น',
|
||||
Pink: 'ชมพู',
|
||||
Rose: 'กุหลาบ',
|
||||
'Primary color': 'สีหลัก'
|
||||
}
|
||||
}
|
||||
|
||||
@@ -453,6 +453,25 @@ export default {
|
||||
'Unpin from profile': '从个人资料取消置顶',
|
||||
'Pin to profile': '置顶到个人资料',
|
||||
Appearance: '外观',
|
||||
'Pure Black': '纯黑'
|
||||
'Pure Black': '纯黑',
|
||||
Default: '默认',
|
||||
Red: '红色',
|
||||
Orange: '橙色',
|
||||
Amber: '琥珀色',
|
||||
Yellow: '黄色',
|
||||
Lime: '青柠色',
|
||||
Green: '绿色',
|
||||
Emerald: '翡翠色',
|
||||
Teal: '蓝绿色',
|
||||
Cyan: '青色',
|
||||
Sky: '天空色',
|
||||
Blue: '蓝色',
|
||||
Indigo: '靛蓝色',
|
||||
Violet: '紫罗兰色',
|
||||
Purple: '紫色',
|
||||
Fuchsia: '紫红色',
|
||||
Pink: '粉色',
|
||||
Rose: '玫瑰色',
|
||||
'Primary color': '主色调'
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { Label } from '@/components/ui/label'
|
||||
import { PRIMARY_COLORS, TPrimaryColor } from '@/constants'
|
||||
import SecondaryPageLayout from '@/layouts/SecondaryPageLayout'
|
||||
import { cn } from '@/lib/utils'
|
||||
import { useTheme } from '@/providers/ThemeProvider'
|
||||
@@ -15,11 +16,11 @@ const THEMES = [
|
||||
|
||||
const AppearanceSettingsPage = forwardRef(({ index }: { index?: number }, ref) => {
|
||||
const { t } = useTranslation()
|
||||
const { themeSetting, setThemeSetting } = useTheme()
|
||||
const { themeSetting, setThemeSetting, primaryColor, setPrimaryColor } = useTheme()
|
||||
|
||||
return (
|
||||
<SecondaryPageLayout ref={ref} index={index} title={t('Appearance')}>
|
||||
<div className="space-y-4 mt-3">
|
||||
<div className="space-y-4 my-3">
|
||||
<div className="flex flex-col gap-2 px-4">
|
||||
<Label className="text-base">{t('Theme')}</Label>
|
||||
<div className="grid grid-cols-2 md:grid-cols-4 gap-4 w-full">
|
||||
@@ -31,7 +32,9 @@ const AppearanceSettingsPage = forwardRef(({ index }: { index?: number }, ref) =
|
||||
}}
|
||||
className={cn(
|
||||
'flex flex-col items-center gap-2 py-4 rounded-lg border-2 transition-all',
|
||||
themeSetting === key ? 'border-primary' : 'border-border hover:border-primary/60'
|
||||
themeSetting === key
|
||||
? 'border-primary'
|
||||
: 'border-border hover:border-muted-foreground/40'
|
||||
)}
|
||||
>
|
||||
<div className="flex items-center justify-center w-8 h-8">{icon}</div>
|
||||
@@ -40,6 +43,31 @@ const AppearanceSettingsPage = forwardRef(({ index }: { index?: number }, ref) =
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex flex-col gap-2 px-4">
|
||||
<Label className="text-base">{t('Primary color')}</Label>
|
||||
<div className="grid grid-cols-4 gap-4 w-full">
|
||||
{Object.entries(PRIMARY_COLORS).map(([key, config]) => (
|
||||
<button
|
||||
key={key}
|
||||
onClick={() => setPrimaryColor(key as TPrimaryColor)}
|
||||
className={cn(
|
||||
'flex flex-col items-center gap-2 py-4 rounded-lg border-2 transition-all',
|
||||
primaryColor === key
|
||||
? 'border-primary'
|
||||
: 'border-border hover:border-muted-foreground/40'
|
||||
)}
|
||||
>
|
||||
<div
|
||||
className="size-8 rounded-full shadow-md"
|
||||
style={{
|
||||
backgroundColor: `hsl(${config.light.primary})`
|
||||
}}
|
||||
/>
|
||||
<span className="text-xs font-medium">{t(config.name)}</span>
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</SecondaryPageLayout>
|
||||
)
|
||||
|
||||
@@ -1,36 +1,36 @@
|
||||
import { PRIMARY_COLORS, StorageKey, TPrimaryColor } from '@/constants'
|
||||
import storage from '@/services/local-storage.service'
|
||||
import { TTheme, TThemeSetting } from '@/types'
|
||||
import { createContext, useContext, useEffect, useState } from 'react'
|
||||
|
||||
type ThemeProviderState = {
|
||||
themeSetting: TThemeSetting
|
||||
setThemeSetting: (themeSetting: TThemeSetting) => Promise<void>
|
||||
}
|
||||
|
||||
function getSystemTheme() {
|
||||
return window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light'
|
||||
setThemeSetting: (themeSetting: TThemeSetting) => void
|
||||
primaryColor: TPrimaryColor
|
||||
setPrimaryColor: (color: TPrimaryColor) => void
|
||||
}
|
||||
|
||||
const ThemeProviderContext = createContext<ThemeProviderState | undefined>(undefined)
|
||||
|
||||
const updateCSSVariables = (color: TPrimaryColor, currentTheme: TTheme) => {
|
||||
const root = window.document.documentElement
|
||||
const colorConfig = PRIMARY_COLORS[color] ?? PRIMARY_COLORS.DEFAULT
|
||||
|
||||
const config = currentTheme === 'light' ? colorConfig.light : colorConfig.dark
|
||||
|
||||
root.style.setProperty('--primary', config.primary)
|
||||
root.style.setProperty('--primary-hover', config['primary-hover'])
|
||||
root.style.setProperty('--primary-foreground', config['primary-foreground'])
|
||||
}
|
||||
|
||||
export function ThemeProvider({ children }: { children: React.ReactNode }) {
|
||||
const [themeSetting, setThemeSetting] = useState<TThemeSetting>(
|
||||
(localStorage.getItem('themeSetting') as TThemeSetting | null) ?? 'system'
|
||||
(localStorage.getItem(StorageKey.THEME_SETTING) as TThemeSetting) ?? 'system'
|
||||
)
|
||||
const [theme, setTheme] = useState<TTheme>('light')
|
||||
|
||||
useEffect(() => {
|
||||
const init = async () => {
|
||||
const themeSetting = storage.getThemeSetting()
|
||||
if (themeSetting === 'system') {
|
||||
setTheme(getSystemTheme())
|
||||
return
|
||||
}
|
||||
setTheme(themeSetting)
|
||||
}
|
||||
|
||||
init()
|
||||
}, [])
|
||||
const [primaryColor, setPrimaryColor] = useState<TPrimaryColor>(
|
||||
(localStorage.getItem(StorageKey.PRIMARY_COLOR) as TPrimaryColor) ?? 'DEFAULT'
|
||||
)
|
||||
|
||||
useEffect(() => {
|
||||
if (themeSetting !== 'system') {
|
||||
@@ -65,16 +65,27 @@ export function ThemeProvider({ children }: { children: React.ReactNode }) {
|
||||
updateTheme()
|
||||
}, [theme])
|
||||
|
||||
const updateThemeSetting = async (themeSetting: TThemeSetting) => {
|
||||
useEffect(() => {
|
||||
updateCSSVariables(primaryColor, theme)
|
||||
}, [theme, primaryColor])
|
||||
|
||||
const updateThemeSetting = (themeSetting: TThemeSetting) => {
|
||||
storage.setThemeSetting(themeSetting)
|
||||
setThemeSetting(themeSetting)
|
||||
}
|
||||
|
||||
const updatePrimaryColor = (color: TPrimaryColor) => {
|
||||
storage.setPrimaryColor(color)
|
||||
setPrimaryColor(color)
|
||||
}
|
||||
|
||||
return (
|
||||
<ThemeProviderContext.Provider
|
||||
value={{
|
||||
themeSetting: themeSetting,
|
||||
setThemeSetting: updateThemeSetting
|
||||
themeSetting,
|
||||
setThemeSetting: updateThemeSetting,
|
||||
primaryColor,
|
||||
setPrimaryColor: updatePrimaryColor
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
|
||||
@@ -4,7 +4,8 @@ import {
|
||||
MEDIA_AUTO_LOAD_POLICY,
|
||||
NOTIFICATION_LIST_STYLE,
|
||||
SUPPORTED_KINDS,
|
||||
StorageKey
|
||||
StorageKey,
|
||||
TPrimaryColor
|
||||
} from '@/constants'
|
||||
import { isSameAccount } from '@/lib/account'
|
||||
import { randomString } from '@/lib/random'
|
||||
@@ -49,6 +50,7 @@ class LocalStorageService {
|
||||
private mediaAutoLoadPolicy: TMediaAutoLoadPolicy = MEDIA_AUTO_LOAD_POLICY.ALWAYS
|
||||
private shownCreateWalletGuideToastPubkeys: Set<string> = new Set()
|
||||
private sidebarCollapse: boolean = false
|
||||
private primaryColor: TPrimaryColor = 'DEFAULT'
|
||||
|
||||
constructor() {
|
||||
if (!LocalStorageService.instance) {
|
||||
@@ -196,6 +198,9 @@ class LocalStorageService {
|
||||
|
||||
this.sidebarCollapse = window.localStorage.getItem(StorageKey.SIDEBAR_COLLAPSE) === 'true'
|
||||
|
||||
this.primaryColor =
|
||||
(window.localStorage.getItem(StorageKey.PRIMARY_COLOR) as TPrimaryColor) ?? 'DEFAULT'
|
||||
|
||||
// Clean up deprecated data
|
||||
window.localStorage.removeItem(StorageKey.ACCOUNT_PROFILE_EVENT_MAP)
|
||||
window.localStorage.removeItem(StorageKey.ACCOUNT_FOLLOW_LIST_EVENT_MAP)
|
||||
@@ -488,6 +493,15 @@ class LocalStorageService {
|
||||
this.sidebarCollapse = collapse
|
||||
window.localStorage.setItem(StorageKey.SIDEBAR_COLLAPSE, collapse.toString())
|
||||
}
|
||||
|
||||
getPrimaryColor() {
|
||||
return this.primaryColor
|
||||
}
|
||||
|
||||
setPrimaryColor(color: TPrimaryColor) {
|
||||
this.primaryColor = color
|
||||
window.localStorage.setItem(StorageKey.PRIMARY_COLOR, color)
|
||||
}
|
||||
}
|
||||
|
||||
const instance = new LocalStorageService()
|
||||
|
||||
Reference in New Issue
Block a user