Browse Source

implemented imwald styling

imwald
Silberengel 5 months ago
parent
commit
520d3d1b55
  1. 3
      index.html
  2. 61
      src/components/AboutInfoDialog/index.tsx
  3. 1
      src/constants.ts
  4. 12
      src/index.css
  5. 1
      src/lib/link.ts
  6. 4
      src/pages/secondary/SettingsPage/index.tsx
  7. 13
      src/pages/secondary/WalletPage/index.tsx
  8. 47
      src/providers/NotificationProvider.tsx
  9. 4
      src/routes.tsx

3
index.html

@ -16,8 +16,7 @@
<meta name="apple-mobile-web-app-title" content="Jumble" /> <meta name="apple-mobile-web-app-title" content="Jumble" />
<link rel="apple-touch-icon" href="/apple-touch-icon.png" /> <link rel="apple-touch-icon" href="/apple-touch-icon.png" />
<link rel="icon" href="/favicon.ico" sizes="48x48" /> <link rel="icon" href="data:image/svg+xml,&lt;svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 100 100%22&gt;&lt;text y=%22.9em%22 font-size=%2290%22&gt;🌲&lt;/text&gt;&lt;/svg&gt;" type="image/svg+xml" />
<link rel="icon" href="/favicon.svg" sizes="any" type="image/svg+xml" />
<meta name="theme-color" content="#171717" media="(prefers-color-scheme: dark)" /> <meta name="theme-color" content="#171717" media="(prefers-color-scheme: dark)" />
<meta name="theme-color" content="#FFFFFF" media="(prefers-color-scheme: light)" /> <meta name="theme-color" content="#FFFFFF" media="(prefers-color-scheme: light)" />

61
src/components/AboutInfoDialog/index.tsx

@ -1,22 +1,60 @@
import { Dialog, DialogContent, DialogTrigger } from '@/components/ui/dialog' import { Dialog, DialogContent, DialogTrigger } from '@/components/ui/dialog'
import { Drawer, DrawerContent, DrawerTrigger } from '@/components/ui/drawer' import { Drawer, DrawerContent, DrawerTrigger } from '@/components/ui/drawer'
import { CODY_PUBKEY } from '@/constants' import { CODY_PUBKEY, SILBERENGEL_PUBKEY } from '@/constants'
import { useScreenSize } from '@/providers/ScreenSizeProvider' import { useScreenSize } from '@/providers/ScreenSizeProvider'
import { useState } from 'react' import { useState, useEffect } from 'react'
import Username from '../Username' import Username from '../Username'
import client from '@/services/client.service'
export default function AboutInfoDialog({ children }: { children: React.ReactNode }) { export default function AboutInfoDialog({ children }: { children: React.ReactNode }) {
const { isSmallScreen } = useScreenSize() const { isSmallScreen } = useScreenSize()
const [open, setOpen] = useState(false) const [open, setOpen] = useState(false)
const [codyLightning, setCodyLightning] = useState<string | null>(null)
const [silberengelLightning, setSilberengelLightning] = useState<string | null>(null)
useEffect(() => {
const fetchProfiles = async () => {
const [codyProfile, silberengelProfile] = await Promise.all([
client.fetchProfile(CODY_PUBKEY),
client.fetchProfile(SILBERENGEL_PUBKEY)
])
if (codyProfile?.lightningAddress) {
setCodyLightning(codyProfile.lightningAddress)
}
if (silberengelProfile?.lightningAddress) {
setSilberengelLightning(silberengelProfile.lightningAddress)
}
}
fetchProfiles()
}, [])
const content = ( const content = (
<> <>
<div className="text-xl font-semibold">Jumble</div> <div className="text-xl font-semibold">Jumble 🌲</div>
<div className="text-muted-foreground"> <div className="text-muted-foreground">
A user-friendly Nostr client focused on relay feed browsing and relay discovery A user-friendly Nostr client focused on relay feed browsing and relay discovery
</div> </div>
<div> <div className="space-y-2">
Made by <Username userId={CODY_PUBKEY} className="inline-block text-primary" showAt /> <div>
<div className="font-medium">Main developer:</div>
<div className="ml-2">
<Username userId={CODY_PUBKEY} className="inline-block text-primary" showAt />
{codyLightning && (
<div className="text-sm text-muted-foreground"> {codyLightning}</div>
)}
</div>
</div>
<div>
<div className="font-medium">Imwald branch:</div>
<div className="ml-2">
<Username userId={SILBERENGEL_PUBKEY} className="inline-block text-primary" showAt />
{silberengelLightning && (
<div className="text-sm text-muted-foreground"> {silberengelLightning}</div>
)}
</div>
</div>
</div> </div>
<div> <div>
Source code:{' '} Source code:{' '}
@ -26,9 +64,18 @@ export default function AboutInfoDialog({ children }: { children: React.ReactNod
rel="noreferrer" rel="noreferrer"
className="text-primary hover:underline" className="text-primary hover:underline"
> >
GitHub Main repo
</a>
{' · '}
<a
href="https://github.com/Silberengel/jumble"
target="_blank"
rel="noreferrer"
className="text-primary hover:underline"
>
Imwald fork
</a> </a>
<div className="text-sm text-muted-foreground"> <div className="text-sm text-muted-foreground mt-1">
If you like Jumble, please consider giving it a star If you like Jumble, please consider giving it a star
</div> </div>
</div> </div>

1
src/constants.ts

@ -166,6 +166,7 @@ export const YOUTUBE_URL_REGEX =
export const JUMBLE_PUBKEY = 'f4eb8e62add1340b9cadcd9861e669b2e907cea534e0f7f3ac974c11c758a51a' export const JUMBLE_PUBKEY = 'f4eb8e62add1340b9cadcd9861e669b2e907cea534e0f7f3ac974c11c758a51a'
export const CODY_PUBKEY = '8125b911ed0e94dbe3008a0be48cfe5cd0c0b05923cfff917ae7e87da8400883' export const CODY_PUBKEY = '8125b911ed0e94dbe3008a0be48cfe5cd0c0b05923cfff917ae7e87da8400883'
export const SILBERENGEL_PUBKEY = 'fd208ee8c8f283780a9552896e4823cc9dc6bfd442063889577106940fd927c1'
export const NIP_96_SERVICE = [ export const NIP_96_SERVICE = [
'https://mockingyou.com', 'https://mockingyou.com',

12
src/index.css

@ -85,8 +85,8 @@
--card-foreground: 240 10% 3.9%; --card-foreground: 240 10% 3.9%;
--popover: 0 0% 100%; --popover: 0 0% 100%;
--popover-foreground: 240 10% 3.9%; --popover-foreground: 240 10% 3.9%;
--primary: 259 43% 56%; --primary: 140 70% 28%;
--primary-hover: 259 43% 65%; --primary-hover: 140 70% 35%;
--primary-foreground: 0 0% 98%; --primary-foreground: 0 0% 98%;
--secondary: 240 4.8% 94%; --secondary: 240 4.8% 94%;
--secondary-foreground: 240 5.9% 10%; --secondary-foreground: 240 5.9% 10%;
@ -98,7 +98,7 @@
--destructive-foreground: 0 0% 98%; --destructive-foreground: 0 0% 98%;
--border: 240 5.9% 90%; --border: 240 5.9% 90%;
--input: 240 5.9% 90%; --input: 240 5.9% 90%;
--ring: 259 43% 56%; --ring: 140 70% 28%;
--chart-1: 12 76% 61%; --chart-1: 12 76% 61%;
--chart-2: 173 58% 39%; --chart-2: 173 58% 39%;
--chart-3: 197 37% 24%; --chart-3: 197 37% 24%;
@ -114,8 +114,8 @@
--card-foreground: 0 0% 98%; --card-foreground: 0 0% 98%;
--popover: 0 0% 9%; --popover: 0 0% 9%;
--popover-foreground: 0 0% 98%; --popover-foreground: 0 0% 98%;
--primary: 259 43% 56%; --primary: 140 70% 40%;
--primary-hover: 259 43% 65%; --primary-hover: 140 70% 50%;
--primary-foreground: 240 5.9% 10%; --primary-foreground: 240 5.9% 10%;
--secondary: 240 3.7% 15.9%; --secondary: 240 3.7% 15.9%;
--secondary-foreground: 0 0% 98%; --secondary-foreground: 0 0% 98%;
@ -127,7 +127,7 @@
--destructive-foreground: 0 0% 98%; --destructive-foreground: 0 0% 98%;
--border: 240 3.7% 15.9%; --border: 240 3.7% 15.9%;
--input: 240 3.7% 15.9%; --input: 240 3.7% 15.9%;
--ring: 259 43% 56%; --ring: 140 70% 40%;
--chart-1: 220 70% 50%; --chart-1: 220 70% 50%;
--chart-2: 160 60% 45%; --chart-2: 160 60% 45%;
--chart-3: 30 80% 55%; --chart-3: 30 80% 55%;

1
src/lib/link.ts

@ -74,7 +74,6 @@ export const toProfileEditor = () => '/profile-editor'
export const toRelay = (url: string) => `/relays/${encodeURIComponent(url)}` export const toRelay = (url: string) => `/relays/${encodeURIComponent(url)}`
export const toRelayReviews = (url: string) => `/relays/${encodeURIComponent(url)}/reviews` export const toRelayReviews = (url: string) => `/relays/${encodeURIComponent(url)}/reviews`
export const toMuteList = () => '/mutes' export const toMuteList = () => '/mutes'
export const toRizful = () => '/rizful'
export const toChachiChat = (relay: string, d: string) => { export const toChachiChat = (relay: string, d: string) => {
return `https://chachi.chat/${relay.replace(/^wss?:\/\//, '').replace(/\/$/, '')}/${d}` return `https://chachi.chat/${relay.replace(/^wss?:\/\//, '').replace(/\/$/, '')}/${d}`

4
src/pages/secondary/SettingsPage/index.tsx

@ -1,5 +1,4 @@
import AboutInfoDialog from '@/components/AboutInfoDialog' import AboutInfoDialog from '@/components/AboutInfoDialog'
import Donation from '@/components/Donation'
import SecondaryPageLayout from '@/layouts/SecondaryPageLayout' import SecondaryPageLayout from '@/layouts/SecondaryPageLayout'
import { import {
toGeneralSettings, toGeneralSettings,
@ -122,9 +121,6 @@ const SettingsPage = forwardRef(({ index }: { index?: number }, ref) => {
</div> </div>
</SettingItem> </SettingItem>
</AboutInfoDialog> </AboutInfoDialog>
<div className="px-4 mt-4">
<Donation />
</div>
</SecondaryPageLayout> </SecondaryPageLayout>
) )
}) })

13
src/pages/secondary/WalletPage/index.tsx

@ -1,4 +1,3 @@
import { useSecondaryPage } from '@/PageManager'
import { import {
AlertDialog, AlertDialog,
AlertDialogAction, AlertDialogAction,
@ -12,7 +11,6 @@ import {
} from '@/components/ui/alert-dialog' } from '@/components/ui/alert-dialog'
import { Button } from '@/components/ui/button' import { Button } from '@/components/ui/button'
import SecondaryPageLayout from '@/layouts/SecondaryPageLayout' import SecondaryPageLayout from '@/layouts/SecondaryPageLayout'
import { toRizful } from '@/lib/link'
import { useZap } from '@/providers/ZapProvider' import { useZap } from '@/providers/ZapProvider'
import { disconnect, launchModal } from '@getalby/bitcoin-connect-react' import { disconnect, launchModal } from '@getalby/bitcoin-connect-react'
import { forwardRef } from 'react' import { forwardRef } from 'react'
@ -25,7 +23,6 @@ import ZapReplyThresholdInput from './ZapReplyThresholdInput'
const WalletPage = forwardRef(({ index }: { index?: number }, ref) => { const WalletPage = forwardRef(({ index }: { index?: number }, ref) => {
const { t } = useTranslation() const { t } = useTranslation()
const { push } = useSecondaryPage()
const { isWalletConnected, walletInfo } = useZap() const { isWalletConnected, walletInfo } = useZap()
return ( return (
@ -65,18 +62,14 @@ const WalletPage = forwardRef(({ index }: { index?: number }, ref) => {
<LightningAddressInput /> <LightningAddressInput />
</> </>
) : ( ) : (
<div className="flex items-center gap-2"> <div>
<Button className="bg-foreground hover:bg-foreground/90" onClick={() => push(toRizful())}>
{t('Start with a Rizful Vault')}
</Button>
<Button <Button
variant="link" className="bg-foreground hover:bg-foreground/90"
className="text-muted-foreground hover:text-foreground px-0"
onClick={() => { onClick={() => {
launchModal() launchModal()
}} }}
> >
{t('or other wallets')} {t('Connect Wallet')}
</Button> </Button>
</div> </div>
)} )}

47
src/providers/NotificationProvider.tsx

@ -255,30 +255,37 @@ export function NotificationProvider({ children }: { children: React.ReactNode }
const favicons = document.querySelectorAll<HTMLLinkElement>("link[rel*='icon']") const favicons = document.querySelectorAll<HTMLLinkElement>("link[rel*='icon']")
if (!favicons.length) return if (!favicons.length) return
const treeFavicon = "data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 100 100%22><text y=%22.9em%22 font-size=%2290%22>🌲</text></svg>"
if (newNotificationCount === 0) { if (newNotificationCount === 0) {
favicons.forEach((favicon) => { favicons.forEach((favicon) => {
favicon.href = '/favicon.ico' favicon.href = treeFavicon
}) })
} else { } else {
const img = document.createElement('img') // Create a canvas with the tree emoji and a notification badge
img.src = '/favicon.ico' const canvas = document.createElement('canvas')
img.onload = () => { const size = 64
const size = Math.max(img.width, img.height, 32) canvas.width = size
const canvas = document.createElement('canvas') canvas.height = size
canvas.width = size const ctx = canvas.getContext('2d')
canvas.height = size if (!ctx) return
const ctx = canvas.getContext('2d')
if (!ctx) return // Draw tree emoji as text
ctx.drawImage(img, 0, 0, size, size) ctx.font = `${size * 0.9}px Arial`
const r = size * 0.16 ctx.textBaseline = 'middle'
ctx.beginPath() ctx.textAlign = 'center'
ctx.arc(size - r - 6, r + 6, r, 0, 2 * Math.PI) ctx.fillText('🌲', size / 2, size / 2)
ctx.fillStyle = '#FF0000'
ctx.fill() // Draw red notification badge
favicons.forEach((favicon) => { const r = size * 0.16
favicon.href = canvas.toDataURL('image/png') ctx.beginPath()
}) ctx.arc(size - r - 6, r + 6, r, 0, 2 * Math.PI)
} ctx.fillStyle = '#FF0000'
ctx.fill()
favicons.forEach((favicon) => {
favicon.href = canvas.toDataURL('image/png')
})
} }
}, [filteredNewNotifications]) }, [filteredNewNotifications])

4
src/routes.tsx

@ -13,7 +13,6 @@ import ProfilePage from './pages/secondary/ProfilePage'
import RelayPage from './pages/secondary/RelayPage' import RelayPage from './pages/secondary/RelayPage'
import RelayReviewsPage from './pages/secondary/RelayReviewsPage' import RelayReviewsPage from './pages/secondary/RelayReviewsPage'
import RelaySettingsPage from './pages/secondary/RelaySettingsPage' import RelaySettingsPage from './pages/secondary/RelaySettingsPage'
import RizfulPage from './pages/secondary/RizfulPage'
import SearchPage from './pages/secondary/SearchPage' import SearchPage from './pages/secondary/SearchPage'
import SettingsPage from './pages/secondary/SettingsPage' import SettingsPage from './pages/secondary/SettingsPage'
import TranslationPage from './pages/secondary/TranslationPage' import TranslationPage from './pages/secondary/TranslationPage'
@ -36,8 +35,7 @@ const ROUTES = [
{ path: '/settings/general', element: <GeneralSettingsPage /> }, { path: '/settings/general', element: <GeneralSettingsPage /> },
{ path: '/settings/translation', element: <TranslationPage /> }, { path: '/settings/translation', element: <TranslationPage /> },
{ path: '/profile-editor', element: <ProfileEditorPage /> }, { path: '/profile-editor', element: <ProfileEditorPage /> },
{ path: '/mutes', element: <MuteListPage /> }, { path: '/mutes', element: <MuteListPage /> }
{ path: '/rizful', element: <RizfulPage /> }
] ]
export const routes = ROUTES.map(({ path, element }) => ({ export const routes = ROUTES.map(({ path, element }) => ({

Loading…
Cancel
Save