feat: update layout
This commit is contained in:
@@ -18,7 +18,7 @@
|
|||||||
<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="/favicon.ico" sizes="48x48" />
|
||||||
<link rel="icon" href="/favicon.svg" sizes="any" type="image/svg+xml" />
|
<link rel="icon" href="/favicon.svg" sizes="any" type="image/svg+xml" />
|
||||||
<meta name="theme-color" content="#09090b" 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)" />
|
||||||
|
|
||||||
<meta property="og:url" content="https://jumble.social" />
|
<meta property="og:url" content="https://jumble.social" />
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
import Sidebar from '@/components/Sidebar'
|
import Sidebar from '@/components/Sidebar'
|
||||||
import { Separator } from '@/components/ui/separator'
|
|
||||||
import { cn } from '@/lib/utils'
|
import { cn } from '@/lib/utils'
|
||||||
import NoteListPage from '@/pages/primary/NoteListPage'
|
import NoteListPage from '@/pages/primary/NoteListPage'
|
||||||
import HomePage from '@/pages/secondary/HomePage'
|
import HomePage from '@/pages/secondary/HomePage'
|
||||||
@@ -15,6 +14,7 @@ import {
|
|||||||
useRef,
|
useRef,
|
||||||
useState
|
useState
|
||||||
} from 'react'
|
} from 'react'
|
||||||
|
import BottomNavigationBar from './components/BottomNavigationBar'
|
||||||
import TooManyRelaysAlertDialog from './components/TooManyRelaysAlertDialog'
|
import TooManyRelaysAlertDialog from './components/TooManyRelaysAlertDialog'
|
||||||
import ExplorePage from './pages/primary/ExplorePage'
|
import ExplorePage from './pages/primary/ExplorePage'
|
||||||
import MePage from './pages/primary/MePage'
|
import MePage from './pages/primary/MePage'
|
||||||
@@ -90,12 +90,10 @@ export function PageManager({ maxStackSize = 5 }: { maxStackSize?: number }) {
|
|||||||
}
|
}
|
||||||
])
|
])
|
||||||
const [secondaryStack, setSecondaryStack] = useState<TStackItem[]>([])
|
const [secondaryStack, setSecondaryStack] = useState<TStackItem[]>([])
|
||||||
const [isShared, setIsShared] = useState(false)
|
|
||||||
const { isSmallScreen } = useScreenSize()
|
const { isSmallScreen } = useScreenSize()
|
||||||
const ignorePopStateRef = useRef(false)
|
const ignorePopStateRef = useRef(false)
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const hasHistoryState = !!history.state
|
|
||||||
if (['/npub1', '/nprofile1'].some((prefix) => window.location.pathname.startsWith(prefix))) {
|
if (['/npub1', '/nprofile1'].some((prefix) => window.location.pathname.startsWith(prefix))) {
|
||||||
window.history.replaceState(
|
window.history.replaceState(
|
||||||
null,
|
null,
|
||||||
@@ -115,12 +113,6 @@ export function PageManager({ maxStackSize = 5 }: { maxStackSize?: number }) {
|
|||||||
}
|
}
|
||||||
window.history.pushState(null, '', window.location.href)
|
window.history.pushState(null, '', window.location.href)
|
||||||
if (window.location.pathname !== '/') {
|
if (window.location.pathname !== '/') {
|
||||||
if (
|
|
||||||
['/users', '/notes', '/relays'].some((path) => window.location.pathname.startsWith(path)) &&
|
|
||||||
!hasHistoryState
|
|
||||||
) {
|
|
||||||
setIsShared(true)
|
|
||||||
}
|
|
||||||
const url = window.location.pathname + window.location.search + window.location.hash
|
const url = window.location.pathname + window.location.search + window.location.hash
|
||||||
setSecondaryStack((prevStack) => {
|
setSecondaryStack((prevStack) => {
|
||||||
if (isCurrentPage(prevStack, url)) return prevStack
|
if (isCurrentPage(prevStack, url)) return prevStack
|
||||||
@@ -248,7 +240,6 @@ export function PageManager({ maxStackSize = 5 }: { maxStackSize?: number }) {
|
|||||||
if (secondaryStack.length === 1) {
|
if (secondaryStack.length === 1) {
|
||||||
// back to home page
|
// back to home page
|
||||||
window.history.replaceState(null, '', '/')
|
window.history.replaceState(null, '', '/')
|
||||||
setIsShared(false)
|
|
||||||
setSecondaryStack([])
|
setSecondaryStack([])
|
||||||
} else {
|
} else {
|
||||||
window.history.go(-1)
|
window.history.go(-1)
|
||||||
@@ -301,6 +292,7 @@ export function PageManager({ maxStackSize = 5 }: { maxStackSize?: number }) {
|
|||||||
{element}
|
{element}
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
|
<BottomNavigationBar />
|
||||||
<TooManyRelaysAlertDialog />
|
<TooManyRelaysAlertDialog />
|
||||||
</NotificationProvider>
|
</NotificationProvider>
|
||||||
</SecondaryPageContext.Provider>
|
</SecondaryPageContext.Provider>
|
||||||
@@ -308,39 +300,6 @@ export function PageManager({ maxStackSize = 5 }: { maxStackSize?: number }) {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isShared && secondaryStack.length > 0) {
|
|
||||||
return (
|
|
||||||
<PrimaryPageContext.Provider
|
|
||||||
value={{
|
|
||||||
navigate: navigatePrimaryPage,
|
|
||||||
current: currentPrimaryPage,
|
|
||||||
display: false
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<SecondaryPageContext.Provider
|
|
||||||
value={{
|
|
||||||
push: pushSecondaryPage,
|
|
||||||
pop: popSecondaryPage,
|
|
||||||
currentIndex: secondaryStack[secondaryStack.length - 1].index
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<NotificationProvider>
|
|
||||||
<div className="h-screen overflow-hidden max-w-4xl mx-auto border-x">
|
|
||||||
{secondaryStack.map((item, index) => (
|
|
||||||
<div
|
|
||||||
key={item.index}
|
|
||||||
style={{ display: index === secondaryStack.length - 1 ? 'block' : 'none' }}
|
|
||||||
>
|
|
||||||
{item.component}
|
|
||||||
</div>
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
</NotificationProvider>
|
|
||||||
</SecondaryPageContext.Provider>
|
|
||||||
</PrimaryPageContext.Provider>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<PrimaryPageContext.Provider
|
<PrimaryPageContext.Provider
|
||||||
value={{
|
value={{
|
||||||
@@ -357,11 +316,10 @@ export function PageManager({ maxStackSize = 5 }: { maxStackSize?: number }) {
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<NotificationProvider>
|
<NotificationProvider>
|
||||||
<div className="flex h-screen overflow-hidden">
|
<div className="flex h-screen overflow-hidden bg-surface-background">
|
||||||
<Sidebar />
|
<Sidebar />
|
||||||
<Separator orientation="vertical" />
|
<div className="grid grid-cols-2 gap-2 w-full pr-2">
|
||||||
<div className="grid grid-cols-2 w-full">
|
<div className="flex rounded-lg my-2 max-h-screen shadow-md bg-background overflow-hidden">
|
||||||
<div className="flex border-r">
|
|
||||||
{primaryPages.map(({ name, element }) => (
|
{primaryPages.map(({ name, element }) => (
|
||||||
<div
|
<div
|
||||||
key={name}
|
key={name}
|
||||||
@@ -374,16 +332,21 @@ export function PageManager({ maxStackSize = 5 }: { maxStackSize?: number }) {
|
|||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div className="flex rounded-lg my-2 max-h-screen shadow-md bg-background overflow-hidden">
|
||||||
{secondaryStack.map((item, index) => (
|
{secondaryStack.map((item, index) => (
|
||||||
<div
|
<div
|
||||||
key={item.index}
|
key={item.index}
|
||||||
|
className="w-full"
|
||||||
style={{ display: index === secondaryStack.length - 1 ? 'block' : 'none' }}
|
style={{ display: index === secondaryStack.length - 1 ? 'block' : 'none' }}
|
||||||
>
|
>
|
||||||
{item.component}
|
{item.component}
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
<div key="home" style={{ display: secondaryStack.length === 0 ? 'block' : 'none' }}>
|
<div
|
||||||
|
key="home"
|
||||||
|
className="w-full"
|
||||||
|
style={{ display: secondaryStack.length === 0 ? 'block' : 'none' }}
|
||||||
|
>
|
||||||
<HomePage />
|
<HomePage />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ export default function BottomNavigationBar() {
|
|||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={cn(
|
className={cn(
|
||||||
'fixed bottom-0 w-full z-40 bg-background/80 backdrop-blur-xl flex items-center justify-around [&_svg]:size-4 [&_svg]:shrink-0'
|
'fixed bottom-0 w-full z-40 bg-background border-t flex items-center justify-around [&_svg]:size-4 [&_svg]:shrink-0'
|
||||||
)}
|
)}
|
||||||
style={{
|
style={{
|
||||||
height: 'calc(3rem + env(safe-area-inset-bottom))',
|
height: 'calc(3rem + env(safe-area-inset-bottom))',
|
||||||
|
|||||||
@@ -88,7 +88,7 @@ export default function KindFilter({
|
|||||||
key={label}
|
key={label}
|
||||||
className={cn(
|
className={cn(
|
||||||
'cursor-pointer grid gap-1.5 rounded-lg border px-4 py-3',
|
'cursor-pointer grid gap-1.5 rounded-lg border px-4 py-3',
|
||||||
checked ? 'border-primary bg-primary/20' : 'clickable'
|
checked ? 'border-primary/60 bg-primary/5' : 'clickable'
|
||||||
)}
|
)}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
console.log(checked)
|
console.log(checked)
|
||||||
@@ -166,7 +166,7 @@ export default function KindFilter({
|
|||||||
return (
|
return (
|
||||||
<Popover open={open} onOpenChange={setOpen}>
|
<Popover open={open} onOpenChange={setOpen}>
|
||||||
<PopoverTrigger asChild>{trigger}</PopoverTrigger>
|
<PopoverTrigger asChild>{trigger}</PopoverTrigger>
|
||||||
<PopoverContent className="w-96" collisionPadding={16}>
|
<PopoverContent className="w-96" collisionPadding={16} sideOffset={0}>
|
||||||
{content}
|
{content}
|
||||||
</PopoverContent>
|
</PopoverContent>
|
||||||
</Popover>
|
</Popover>
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import { Button } from '@/components/ui/button'
|
|||||||
import { SimpleUserAvatar } from '@/components/UserAvatar'
|
import { SimpleUserAvatar } from '@/components/UserAvatar'
|
||||||
import { cn } from '@/lib/utils'
|
import { cn } from '@/lib/utils'
|
||||||
import { useScreenSize } from '@/providers/ScreenSizeProvider'
|
import { useScreenSize } from '@/providers/ScreenSizeProvider'
|
||||||
|
import { ArrowUp } from 'lucide-react'
|
||||||
import { Event } from 'nostr-tools'
|
import { Event } from 'nostr-tools'
|
||||||
import { useMemo } from 'react'
|
import { useMemo } from 'react'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
@@ -32,34 +33,25 @@ export default function NewNotesButton({
|
|||||||
<div
|
<div
|
||||||
className={cn(
|
className={cn(
|
||||||
'w-full flex justify-center z-40 pointer-events-none',
|
'w-full flex justify-center z-40 pointer-events-none',
|
||||||
isSmallScreen ? 'fixed' : 'absolute bottom-4'
|
isSmallScreen ? 'fixed' : 'absolute bottom-6'
|
||||||
)}
|
)}
|
||||||
style={isSmallScreen ? { bottom: 'calc(4rem + env(safe-area-inset-bottom))' } : undefined}
|
style={isSmallScreen ? { bottom: 'calc(4rem + env(safe-area-inset-bottom))' } : undefined}
|
||||||
>
|
>
|
||||||
<Button
|
<Button
|
||||||
onClick={onClick}
|
onClick={onClick}
|
||||||
className="group rounded-full h-fit pl-2 pr-3 hover:bg-primary-hover pointer-events-auto"
|
className="group rounded-full h-fit py-2 pl-2 pr-3 hover:bg-primary-hover pointer-events-auto"
|
||||||
>
|
>
|
||||||
{pubkeys.length > 0 && (
|
{pubkeys.length > 0 && (
|
||||||
<div className="flex items-center">
|
<div className="*:data-[slot=avatar]:ring-background flex -space-x-2 *:data-[slot=avatar]:ring-2 *:data-[slot=avatar]:grayscale">
|
||||||
{pubkeys.map((pubkey, index) => (
|
{pubkeys.map((pubkey) => (
|
||||||
<div
|
<SimpleUserAvatar userId={pubkey} size="small" />
|
||||||
key={pubkey}
|
|
||||||
className="relative -mr-2.5 last:mr-0"
|
|
||||||
style={{ zIndex: 3 - index }}
|
|
||||||
>
|
|
||||||
<SimpleUserAvatar
|
|
||||||
userId={pubkey}
|
|
||||||
size="small"
|
|
||||||
className="border-primary border-2 group-hover:border-primary-hover"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
<div className="text-md font-medium">
|
<div className="text-md font-medium">
|
||||||
{t('Show n new notes', { n: newEvents.length > 99 ? '99+' : newEvents.length })}
|
{t('Show n new notes', { n: newEvents.length > 99 ? '99+' : newEvents.length })}
|
||||||
</div>
|
</div>
|
||||||
|
<ArrowUp />
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -209,7 +209,7 @@ const NoteList = forwardRef(
|
|||||||
setEvents((oldEvents) => [...newEvents, ...oldEvents])
|
setEvents((oldEvents) => [...newEvents, ...oldEvents])
|
||||||
setNewEvents([])
|
setNewEvents([])
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
scrollToTop()
|
scrollToTop('smooth')
|
||||||
}, 0)
|
}, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -218,7 +218,7 @@ const NoteList = forwardRef(
|
|||||||
{filteredNewEvents.length > 0 && (
|
{filteredNewEvents.length > 0 && (
|
||||||
<NewNotesButton newEvents={filteredNewEvents} onClick={showNewEvents} />
|
<NewNotesButton newEvents={filteredNewEvents} onClick={showNewEvents} />
|
||||||
)}
|
)}
|
||||||
<div ref={topRef} className="scroll-mt-24" />
|
<div ref={topRef} className="scroll-mt-[calc(6rem+1px)]" />
|
||||||
<PullToRefresh
|
<PullToRefresh
|
||||||
onRefresh={async () => {
|
onRefresh={async () => {
|
||||||
setRefreshCount((count) => count + 1)
|
setRefreshCount((count) => count + 1)
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ export default function ProfileList({ pubkeys }: { pubkeys: string[] }) {
|
|||||||
}, [visiblePubkeys, pubkeys])
|
}, [visiblePubkeys, pubkeys])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="px-4">
|
<div className="px-4 pt-2">
|
||||||
{visiblePubkeys.map((pubkey, index) => (
|
{visiblePubkeys.map((pubkey, index) => (
|
||||||
<UserItem key={`${index}-${pubkey}`} pubkey={pubkey} />
|
<UserItem key={`${index}-${pubkey}`} pubkey={pubkey} />
|
||||||
))}
|
))}
|
||||||
|
|||||||
@@ -12,8 +12,8 @@ const SidebarItem = forwardRef<
|
|||||||
return (
|
return (
|
||||||
<Button
|
<Button
|
||||||
className={cn(
|
className={cn(
|
||||||
'flex shadow-none items-center bg-transparent w-12 h-12 xl:w-full xl:h-auto p-3 m-0 xl:py-2 xl:px-4 rounded-lg xl:justify-start gap-4 text-lg font-semibold [&_svg]:size-full xl:[&_svg]:size-4',
|
'flex shadow-none items-center transition-colors duration-500 bg-transparent w-12 h-12 xl:w-full xl:h-auto p-3 m-0 xl:py-2 xl:px-3 rounded-lg xl:justify-start gap-4 text-lg font-semibold [&_svg]:size-full xl:[&_svg]:size-4',
|
||||||
active && 'text-primary hover:text-primary',
|
active && 'text-primary hover:text-primary bg-primary/10 hover:bg-primary/10',
|
||||||
className
|
className
|
||||||
)}
|
)}
|
||||||
variant="ghost"
|
variant="ghost"
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ export default function PrimaryPageSidebar() {
|
|||||||
if (isSmallScreen) return null
|
if (isSmallScreen) return null
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="w-16 xl:w-52 flex flex-col pb-2 pt-4 px-2 justify-between h-full shrink-0">
|
<div className="w-16 xl:w-52 flex flex-col pb-2 pt-4 px-2 xl:px-4 justify-between h-full shrink-0">
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
<div className="px-3 xl:px-4 mb-6 w-full">
|
<div className="px-3 xl:px-4 mb-6 w-full">
|
||||||
<Icon className="xl:hidden" />
|
<Icon className="xl:hidden" />
|
||||||
|
|||||||
@@ -87,7 +87,7 @@ export default function Tabs({
|
|||||||
<div
|
<div
|
||||||
ref={containerRef}
|
ref={containerRef}
|
||||||
className={cn(
|
className={cn(
|
||||||
'sticky flex justify-between top-12 bg-background z-30 px-1 w-full transition-transform',
|
'sticky flex justify-between top-12 bg-background z-30 px-1 w-full transition-transform border-b',
|
||||||
deepBrowsing && lastScrollTop > threshold ? '-translate-y-[calc(100%+12rem)]' : ''
|
deepBrowsing && lastScrollTop > threshold ? '-translate-y-[calc(100%+12rem)]' : ''
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -2,15 +2,18 @@ import { cn } from '@/lib/utils'
|
|||||||
|
|
||||||
export function Titlebar({
|
export function Titlebar({
|
||||||
children,
|
children,
|
||||||
className
|
className,
|
||||||
|
hideBottomBorder = false
|
||||||
}: {
|
}: {
|
||||||
children?: React.ReactNode
|
children?: React.ReactNode
|
||||||
className?: string
|
className?: string
|
||||||
|
hideBottomBorder?: boolean
|
||||||
}) {
|
}) {
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={cn(
|
className={cn(
|
||||||
'sticky top-0 w-full h-12 z-40 bg-background [&_svg]:size-5 [&_svg]:shrink-0 select-none',
|
'sticky top-0 w-full h-12 z-40 bg-background [&_svg]:size-5 [&_svg]:shrink-0 select-none',
|
||||||
|
!hideBottomBorder && 'border-b',
|
||||||
className
|
className
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -50,6 +50,14 @@
|
|||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.scrollbar-hide {
|
||||||
|
-ms-overflow-style: none; /* Internet Explorer 10+ */
|
||||||
|
scrollbar-width: none; /* Firefox */
|
||||||
|
}
|
||||||
|
.scrollbar-hide::-webkit-scrollbar {
|
||||||
|
display: none; /* Safari and Chrome */
|
||||||
|
}
|
||||||
|
|
||||||
@media (hover: hover) and (pointer: fine) {
|
@media (hover: hover) and (pointer: fine) {
|
||||||
.clickable:hover {
|
.clickable:hover {
|
||||||
background-color: hsl(var(--muted) / 0.5);
|
background-color: hsl(var(--muted) / 0.5);
|
||||||
@@ -70,6 +78,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
:root {
|
:root {
|
||||||
|
--surface-background: 0 0% 98%;
|
||||||
--background: 0 0% 100%;
|
--background: 0 0% 100%;
|
||||||
--foreground: 240 10% 3.9%;
|
--foreground: 240 10% 3.9%;
|
||||||
--card: 0 0% 100%;
|
--card: 0 0% 100%;
|
||||||
@@ -79,11 +88,11 @@
|
|||||||
--primary: 259 43% 56%;
|
--primary: 259 43% 56%;
|
||||||
--primary-hover: 259 43% 65%;
|
--primary-hover: 259 43% 65%;
|
||||||
--primary-foreground: 0 0% 98%;
|
--primary-foreground: 0 0% 98%;
|
||||||
--secondary: 240 4.8% 95.9%;
|
--secondary: 240 4.8% 94%;
|
||||||
--secondary-foreground: 240 5.9% 10%;
|
--secondary-foreground: 240 5.9% 10%;
|
||||||
--muted: 240 4.8% 95.9%;
|
--muted: 240 4.8% 94%;
|
||||||
--muted-foreground: 240 3.8% 46.1%;
|
--muted-foreground: 240 3.8% 46.1%;
|
||||||
--accent: 240 4.8% 95.9%;
|
--accent: 240 4.8% 94%;
|
||||||
--accent-foreground: 240 5.9% 10%;
|
--accent-foreground: 240 5.9% 10%;
|
||||||
--destructive: 0 84.2% 60.2%;
|
--destructive: 0 84.2% 60.2%;
|
||||||
--destructive-foreground: 0 0% 98%;
|
--destructive-foreground: 0 0% 98%;
|
||||||
@@ -98,11 +107,12 @@
|
|||||||
--radius: 0.5rem;
|
--radius: 0.5rem;
|
||||||
}
|
}
|
||||||
.dark {
|
.dark {
|
||||||
--background: 240 10% 3.9%;
|
--surface-background: 240 10% 3.9%;
|
||||||
|
--background: 0 0% 9%;
|
||||||
--foreground: 0 0% 98%;
|
--foreground: 0 0% 98%;
|
||||||
--card: 240 10% 3.9%;
|
--card: 0 0% 9%;
|
||||||
--card-foreground: 0 0% 98%;
|
--card-foreground: 0 0% 98%;
|
||||||
--popover: 240 10% 3.9%;
|
--popover: 0 0% 9%;
|
||||||
--popover-foreground: 0 0% 98%;
|
--popover-foreground: 0 0% 98%;
|
||||||
--primary: 259 43% 56%;
|
--primary: 259 43% 56%;
|
||||||
--primary-hover: 259 43% 65%;
|
--primary-hover: 259 43% 65%;
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
import BottomNavigationBar from '@/components/BottomNavigationBar'
|
|
||||||
import ScrollToTopButton from '@/components/ScrollToTopButton'
|
import ScrollToTopButton from '@/components/ScrollToTopButton'
|
||||||
import { Titlebar } from '@/components/Titlebar'
|
import { Titlebar } from '@/components/Titlebar'
|
||||||
import { ScrollArea } from '@/components/ui/scroll-area'
|
import { ScrollArea } from '@/components/ui/scroll-area'
|
||||||
@@ -13,12 +12,14 @@ const PrimaryPageLayout = forwardRef(
|
|||||||
children,
|
children,
|
||||||
titlebar,
|
titlebar,
|
||||||
pageName,
|
pageName,
|
||||||
displayScrollToTopButton = false
|
displayScrollToTopButton = false,
|
||||||
|
hideTitlebarBottomBorder = false
|
||||||
}: {
|
}: {
|
||||||
children?: React.ReactNode
|
children?: React.ReactNode
|
||||||
titlebar: React.ReactNode
|
titlebar: React.ReactNode
|
||||||
pageName: TPrimaryPageName
|
pageName: TPrimaryPageName
|
||||||
displayScrollToTopButton?: boolean
|
displayScrollToTopButton?: boolean
|
||||||
|
hideTitlebarBottomBorder?: boolean
|
||||||
},
|
},
|
||||||
ref
|
ref
|
||||||
) => {
|
) => {
|
||||||
@@ -69,9 +70,10 @@ const PrimaryPageLayout = forwardRef(
|
|||||||
paddingBottom: 'calc(env(safe-area-inset-bottom) + 3rem)'
|
paddingBottom: 'calc(env(safe-area-inset-bottom) + 3rem)'
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<PrimaryPageTitlebar>{titlebar}</PrimaryPageTitlebar>
|
<PrimaryPageTitlebar hideBottomBorder={hideTitlebarBottomBorder}>
|
||||||
|
{titlebar}
|
||||||
|
</PrimaryPageTitlebar>
|
||||||
{children}
|
{children}
|
||||||
<BottomNavigationBar />
|
|
||||||
</div>
|
</div>
|
||||||
{displayScrollToTopButton && <ScrollToTopButton />}
|
{displayScrollToTopButton && <ScrollToTopButton />}
|
||||||
</DeepBrowsingProvider>
|
</DeepBrowsingProvider>
|
||||||
@@ -81,7 +83,7 @@ const PrimaryPageLayout = forwardRef(
|
|||||||
return (
|
return (
|
||||||
<DeepBrowsingProvider active={current === pageName && display} scrollAreaRef={scrollAreaRef}>
|
<DeepBrowsingProvider active={current === pageName && display} scrollAreaRef={scrollAreaRef}>
|
||||||
<ScrollArea
|
<ScrollArea
|
||||||
className="h-screen overflow-auto"
|
className="h-full overflow-auto"
|
||||||
scrollBarClassName="z-50 pt-12"
|
scrollBarClassName="z-50 pt-12"
|
||||||
ref={scrollAreaRef}
|
ref={scrollAreaRef}
|
||||||
>
|
>
|
||||||
@@ -101,6 +103,16 @@ export type TPrimaryPageLayoutRef = {
|
|||||||
scrollToTop: () => void
|
scrollToTop: () => void
|
||||||
}
|
}
|
||||||
|
|
||||||
function PrimaryPageTitlebar({ children }: { children?: React.ReactNode }) {
|
function PrimaryPageTitlebar({
|
||||||
return <Titlebar className="p-1">{children}</Titlebar>
|
children,
|
||||||
|
hideBottomBorder = false
|
||||||
|
}: {
|
||||||
|
children?: React.ReactNode
|
||||||
|
hideBottomBorder?: boolean
|
||||||
|
}) {
|
||||||
|
return (
|
||||||
|
<Titlebar className="p-1" hideBottomBorder={hideBottomBorder}>
|
||||||
|
{children}
|
||||||
|
</Titlebar>
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
import BackButton from '@/components/BackButton'
|
import BackButton from '@/components/BackButton'
|
||||||
import BottomNavigationBar from '@/components/BottomNavigationBar'
|
|
||||||
import ScrollToTopButton from '@/components/ScrollToTopButton'
|
import ScrollToTopButton from '@/components/ScrollToTopButton'
|
||||||
import { Titlebar } from '@/components/Titlebar'
|
import { Titlebar } from '@/components/Titlebar'
|
||||||
import { ScrollArea } from '@/components/ui/scroll-area'
|
import { ScrollArea } from '@/components/ui/scroll-area'
|
||||||
@@ -16,6 +15,7 @@ const SecondaryPageLayout = forwardRef(
|
|||||||
title,
|
title,
|
||||||
controls,
|
controls,
|
||||||
hideBackButton = false,
|
hideBackButton = false,
|
||||||
|
hideTitlebarBottomBorder = false,
|
||||||
displayScrollToTopButton = false
|
displayScrollToTopButton = false
|
||||||
}: {
|
}: {
|
||||||
children?: React.ReactNode
|
children?: React.ReactNode
|
||||||
@@ -23,6 +23,7 @@ const SecondaryPageLayout = forwardRef(
|
|||||||
title?: React.ReactNode
|
title?: React.ReactNode
|
||||||
controls?: React.ReactNode
|
controls?: React.ReactNode
|
||||||
hideBackButton?: boolean
|
hideBackButton?: boolean
|
||||||
|
hideTitlebarBottomBorder?: boolean
|
||||||
displayScrollToTopButton?: boolean
|
displayScrollToTopButton?: boolean
|
||||||
},
|
},
|
||||||
ref
|
ref
|
||||||
@@ -65,9 +66,9 @@ const SecondaryPageLayout = forwardRef(
|
|||||||
title={title}
|
title={title}
|
||||||
controls={controls}
|
controls={controls}
|
||||||
hideBackButton={hideBackButton}
|
hideBackButton={hideBackButton}
|
||||||
|
hideBottomBorder={hideTitlebarBottomBorder}
|
||||||
/>
|
/>
|
||||||
{children}
|
{children}
|
||||||
<BottomNavigationBar />
|
|
||||||
</div>
|
</div>
|
||||||
{displayScrollToTopButton && <ScrollToTopButton />}
|
{displayScrollToTopButton && <ScrollToTopButton />}
|
||||||
</DeepBrowsingProvider>
|
</DeepBrowsingProvider>
|
||||||
@@ -77,7 +78,7 @@ const SecondaryPageLayout = forwardRef(
|
|||||||
return (
|
return (
|
||||||
<DeepBrowsingProvider active={currentIndex === index} scrollAreaRef={scrollAreaRef}>
|
<DeepBrowsingProvider active={currentIndex === index} scrollAreaRef={scrollAreaRef}>
|
||||||
<ScrollArea
|
<ScrollArea
|
||||||
className="h-screen overflow-auto"
|
className="h-full overflow-auto"
|
||||||
scrollBarClassName="z-50 pt-12"
|
scrollBarClassName="z-50 pt-12"
|
||||||
ref={scrollAreaRef}
|
ref={scrollAreaRef}
|
||||||
>
|
>
|
||||||
@@ -85,6 +86,7 @@ const SecondaryPageLayout = forwardRef(
|
|||||||
title={title}
|
title={title}
|
||||||
controls={controls}
|
controls={controls}
|
||||||
hideBackButton={hideBackButton}
|
hideBackButton={hideBackButton}
|
||||||
|
hideBottomBorder={hideTitlebarBottomBorder}
|
||||||
/>
|
/>
|
||||||
{children}
|
{children}
|
||||||
<div className="h-4" />
|
<div className="h-4" />
|
||||||
@@ -100,14 +102,19 @@ export default SecondaryPageLayout
|
|||||||
export function SecondaryPageTitlebar({
|
export function SecondaryPageTitlebar({
|
||||||
title,
|
title,
|
||||||
controls,
|
controls,
|
||||||
hideBackButton = false
|
hideBackButton = false,
|
||||||
|
hideBottomBorder = false
|
||||||
}: {
|
}: {
|
||||||
title?: React.ReactNode
|
title?: React.ReactNode
|
||||||
controls?: React.ReactNode
|
controls?: React.ReactNode
|
||||||
hideBackButton?: boolean
|
hideBackButton?: boolean
|
||||||
|
hideBottomBorder?: boolean
|
||||||
}): JSX.Element {
|
}): JSX.Element {
|
||||||
return (
|
return (
|
||||||
<Titlebar className="flex gap-1 p-1 items-center justify-between font-semibold">
|
<Titlebar
|
||||||
|
className="flex gap-1 p-1 items-center justify-between font-semibold"
|
||||||
|
hideBottomBorder={hideBottomBorder}
|
||||||
|
>
|
||||||
{hideBackButton ? (
|
{hideBackButton ? (
|
||||||
<div className="flex gap-2 items-center pl-3 w-fit truncate text-lg font-semibold">
|
<div className="flex gap-2 items-center pl-3 w-fit truncate text-lg font-semibold">
|
||||||
{title}
|
{title}
|
||||||
|
|||||||
@@ -33,7 +33,12 @@ const MePage = forwardRef((_, ref) => {
|
|||||||
|
|
||||||
if (!pubkey) {
|
if (!pubkey) {
|
||||||
return (
|
return (
|
||||||
<PrimaryPageLayout ref={ref} pageName="home" titlebar={<MePageTitlebar />}>
|
<PrimaryPageLayout
|
||||||
|
ref={ref}
|
||||||
|
pageName="home"
|
||||||
|
titlebar={<MePageTitlebar />}
|
||||||
|
hideTitlebarBottomBorder
|
||||||
|
>
|
||||||
<div className="flex flex-col p-4 gap-4 overflow-auto">
|
<div className="flex flex-col p-4 gap-4 overflow-auto">
|
||||||
<AccountManager />
|
<AccountManager />
|
||||||
</div>
|
</div>
|
||||||
@@ -42,7 +47,12 @@ const MePage = forwardRef((_, ref) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<PrimaryPageLayout ref={ref} pageName="home" titlebar={<MePageTitlebar />}>
|
<PrimaryPageLayout
|
||||||
|
ref={ref}
|
||||||
|
pageName="home"
|
||||||
|
titlebar={<MePageTitlebar />}
|
||||||
|
hideTitlebarBottomBorder
|
||||||
|
>
|
||||||
<div className="flex gap-4 items-center p-4">
|
<div className="flex gap-4 items-center p-4">
|
||||||
<SimpleUserAvatar userId={pubkey} size="big" />
|
<SimpleUserAvatar userId={pubkey} size="big" />
|
||||||
<div className="space-y-1 flex-1 w-0">
|
<div className="space-y-1 flex-1 w-0">
|
||||||
|
|||||||
@@ -34,7 +34,11 @@ export default function FeedButton({ className }: { className?: string }) {
|
|||||||
<PopoverTrigger asChild>
|
<PopoverTrigger asChild>
|
||||||
<FeedSwitcherTrigger className={className} />
|
<FeedSwitcherTrigger className={className} />
|
||||||
</PopoverTrigger>
|
</PopoverTrigger>
|
||||||
<PopoverContent side="bottom" className="w-96 p-4 max-h-[80vh] overflow-auto">
|
<PopoverContent
|
||||||
|
sideOffset={0}
|
||||||
|
side="bottom"
|
||||||
|
className="w-96 p-4 max-h-[80vh] overflow-auto scrollbar-hide"
|
||||||
|
>
|
||||||
<FeedSwitcher close={() => setOpen(false)} />
|
<FeedSwitcher close={() => setOpen(false)} />
|
||||||
</PopoverContent>
|
</PopoverContent>
|
||||||
</Popover>
|
</Popover>
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ const NoteListPage = forwardRef((_, ref) => {
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (layoutRef.current) {
|
if (layoutRef.current) {
|
||||||
layoutRef.current.scrollToTop()
|
layoutRef.current.scrollToTop('instant')
|
||||||
}
|
}
|
||||||
}, [JSON.stringify(relayUrls), feedInfo])
|
}, [JSON.stringify(relayUrls), feedInfo])
|
||||||
|
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ const GeneralSettingsPage = forwardRef(({ index }: { index?: number }, ref) => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<SecondaryPageLayout ref={ref} index={index} title={t('General')}>
|
<SecondaryPageLayout ref={ref} index={index} title={t('General')}>
|
||||||
<div className="space-y-4 mt-2">
|
<div className="space-y-4 mt-3">
|
||||||
<SettingItem>
|
<SettingItem>
|
||||||
<Label htmlFor="languages" className="text-base font-normal">
|
<Label htmlFor="languages" className="text-base font-normal">
|
||||||
{t('Languages')}
|
{t('Languages')}
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ const HomePage = forwardRef(({ index }: { index?: number }, ref) => {
|
|||||||
|
|
||||||
if (!recommendedRelayInfos.length) {
|
if (!recommendedRelayInfos.length) {
|
||||||
return (
|
return (
|
||||||
<SecondaryPageLayout ref={ref} index={index} hideBackButton>
|
<SecondaryPageLayout ref={ref} index={index} hideBackButton hideTitlebarBottomBorder>
|
||||||
<div className="text-muted-foreground w-full h-screen flex items-center justify-center">
|
<div className="text-muted-foreground w-full h-screen flex items-center justify-center">
|
||||||
{t('Welcome! 🥳')}
|
{t('Welcome! 🥳')}
|
||||||
</div>
|
</div>
|
||||||
@@ -49,8 +49,9 @@ const HomePage = forwardRef(({ index }: { index?: number }, ref) => {
|
|||||||
</>
|
</>
|
||||||
}
|
}
|
||||||
hideBackButton
|
hideBackButton
|
||||||
|
hideTitlebarBottomBorder
|
||||||
>
|
>
|
||||||
<div className="px-4">
|
<div className="px-4 pt-2">
|
||||||
<div className="grid grid-cols-2 gap-3">
|
<div className="grid grid-cols-2 gap-3">
|
||||||
{recommendedRelayInfos.map((relayInfo) => (
|
{recommendedRelayInfos.map((relayInfo) => (
|
||||||
<RelaySimpleInfo
|
<RelaySimpleInfo
|
||||||
|
|||||||
@@ -1,14 +0,0 @@
|
|||||||
import SecondaryPageLayout from '@/layouts/SecondaryPageLayout'
|
|
||||||
import { forwardRef } from 'react'
|
|
||||||
|
|
||||||
const LoadingPage = forwardRef(({ title, index }: { title?: string; index?: number }, ref) => {
|
|
||||||
return (
|
|
||||||
<SecondaryPageLayout ref={ref} index={index} title={title}>
|
|
||||||
<div className="text-muted-foreground text-center">
|
|
||||||
<div>Loading...</div>
|
|
||||||
</div>
|
|
||||||
</SecondaryPageLayout>
|
|
||||||
)
|
|
||||||
})
|
|
||||||
LoadingPage.displayName = 'LoadingPage'
|
|
||||||
export default LoadingPage
|
|
||||||
@@ -35,7 +35,7 @@ const NotePage = forwardRef(({ id, index }: { id?: string; index?: number }, ref
|
|||||||
if (!event && isFetching) {
|
if (!event && isFetching) {
|
||||||
return (
|
return (
|
||||||
<SecondaryPageLayout ref={ref} index={index} title={t('Note')}>
|
<SecondaryPageLayout ref={ref} index={index} title={t('Note')}>
|
||||||
<div className="px-4">
|
<div className="px-4 pt-3">
|
||||||
<div className="flex items-center space-x-2">
|
<div className="flex items-center space-x-2">
|
||||||
<Skeleton className="w-10 h-10 rounded-full" />
|
<Skeleton className="w-10 h-10 rounded-full" />
|
||||||
<div className={`flex-1 w-0`}>
|
<div className={`flex-1 w-0`}>
|
||||||
@@ -69,7 +69,7 @@ const NotePage = forwardRef(({ id, index }: { id?: string; index?: number }, ref
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<SecondaryPageLayout ref={ref} index={index} title={t('Note')} displayScrollToTopButton>
|
<SecondaryPageLayout ref={ref} index={index} title={t('Note')} displayScrollToTopButton>
|
||||||
<div className="px-4">
|
<div className="px-4 pt-3">
|
||||||
{rootITag && <ExternalRoot value={rootITag[1]} />}
|
{rootITag && <ExternalRoot value={rootITag[1]} />}
|
||||||
{rootEventId !== parentEventId && (
|
{rootEventId !== parentEventId && (
|
||||||
<ParentNote
|
<ParentNote
|
||||||
@@ -132,12 +132,12 @@ function ParentNote({
|
|||||||
if (isFetching) {
|
if (isFetching) {
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<Card className="flex space-x-1 px-1.5 py-1 items-center clickable text-sm text-muted-foreground">
|
<div className="flex space-x-1 px-[0.4375rem] py-1 items-center rounded-full border clickable text-sm text-muted-foreground">
|
||||||
<Skeleton className="shrink w-4 h-4 rounded-full" />
|
<Skeleton className="shrink w-4 h-4 rounded-full" />
|
||||||
<div className="py-1 flex-1">
|
<div className="py-1 flex-1">
|
||||||
<Skeleton className="h-3" />
|
<Skeleton className="h-3" />
|
||||||
</div>
|
</div>
|
||||||
</Card>
|
</div>
|
||||||
<div className="ml-5 w-px h-3 bg-border" />
|
<div className="ml-5 w-px h-3 bg-border" />
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
@@ -146,9 +146,9 @@ function ParentNote({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<Card
|
<div
|
||||||
className={cn(
|
className={cn(
|
||||||
'flex space-x-1 px-1.5 py-1 items-center clickable text-sm text-muted-foreground',
|
'flex space-x-1 px-[0.4375rem] py-1 items-center rounded-full border clickable text-sm text-muted-foreground',
|
||||||
event && 'hover:text-foreground'
|
event && 'hover:text-foreground'
|
||||||
)}
|
)}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
@@ -158,7 +158,7 @@ function ParentNote({
|
|||||||
>
|
>
|
||||||
{event && <UserAvatar userId={event.pubkey} size="tiny" className="shrink-0" />}
|
{event && <UserAvatar userId={event.pubkey} size="tiny" className="shrink-0" />}
|
||||||
<ContentPreview className="truncate" event={event} />
|
<ContentPreview className="truncate" event={event} />
|
||||||
</Card>
|
</div>
|
||||||
{isConsecutive ? (
|
{isConsecutive ? (
|
||||||
<div className="ml-5 w-px h-3 bg-border" />
|
<div className="ml-5 w-px h-3 bg-border" />
|
||||||
) : (
|
) : (
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ const RelaySettingsPage = forwardRef(({ id, index }: { id?: string; index?: numb
|
|||||||
index={index}
|
index={index}
|
||||||
title={t("username's used relays", { username: profile.username })}
|
title={t("username's used relays", { username: profile.username })}
|
||||||
>
|
>
|
||||||
<div className="px-4">
|
<div className="px-4 pt-3">
|
||||||
<OthersRelayList userId={id} />
|
<OthersRelayList userId={id} />
|
||||||
</div>
|
</div>
|
||||||
</SecondaryPageLayout>
|
</SecondaryPageLayout>
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ const PostSettingsPage = forwardRef(({ index }: { index?: number }, ref) => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<SecondaryPageLayout ref={ref} index={index} title={t('Post settings')}>
|
<SecondaryPageLayout ref={ref} index={index} title={t('Post settings')}>
|
||||||
<div className="px-4 pt-2 space-y-4">
|
<div className="px-4 pt-3 space-y-4">
|
||||||
<MediaUploadServiceSetting />
|
<MediaUploadServiceSetting />
|
||||||
</div>
|
</div>
|
||||||
</SecondaryPageLayout>
|
</SecondaryPageLayout>
|
||||||
|
|||||||
@@ -124,8 +124,7 @@ const ProfileEditorPage = forwardRef(({ index }: { index?: number }, ref) => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<SecondaryPageLayout ref={ref} index={index} title={profile.username} controls={controls}>
|
<SecondaryPageLayout ref={ref} index={index} title={profile.username} controls={controls}>
|
||||||
<div className="px-4">
|
<div className="relative bg-cover bg-center mb-2">
|
||||||
<div className="relative bg-cover bg-center rounded-lg mb-2">
|
|
||||||
<Uploader
|
<Uploader
|
||||||
onUploadSuccess={onBannerUploadSuccess}
|
onUploadSuccess={onBannerUploadSuccess}
|
||||||
onUploadStart={() => setUploadingBanner(true)}
|
onUploadStart={() => setUploadingBanner(true)}
|
||||||
@@ -135,14 +134,10 @@ const ProfileEditorPage = forwardRef(({ index }: { index?: number }, ref) => {
|
|||||||
<ProfileBanner
|
<ProfileBanner
|
||||||
banner={banner}
|
banner={banner}
|
||||||
pubkey={account.pubkey}
|
pubkey={account.pubkey}
|
||||||
className="w-full aspect-[3/1] object-cover rounded-lg"
|
className="w-full aspect-[3/1] object-cover"
|
||||||
/>
|
/>
|
||||||
<div className="absolute top-0 bg-muted/30 w-full h-full rounded-lg flex flex-col justify-center items-center">
|
<div className="absolute top-0 bg-muted/30 w-full h-full flex flex-col justify-center items-center">
|
||||||
{uploadingBanner ? (
|
{uploadingBanner ? <Loader size={36} className="animate-spin" /> : <Upload size={36} />}
|
||||||
<Loader size={36} className="animate-spin" />
|
|
||||||
) : (
|
|
||||||
<Upload size={36} />
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
</Uploader>
|
</Uploader>
|
||||||
<Uploader
|
<Uploader
|
||||||
@@ -162,7 +157,7 @@ const ProfileEditorPage = forwardRef(({ index }: { index?: number }, ref) => {
|
|||||||
</div>
|
</div>
|
||||||
</Uploader>
|
</Uploader>
|
||||||
</div>
|
</div>
|
||||||
<div className="pt-14 flex flex-col gap-4">
|
<div className="pt-14 px-4 flex flex-col gap-4">
|
||||||
<Item>
|
<Item>
|
||||||
<Label htmlFor="profile-username-input">{t('Display Name')}</Label>
|
<Label htmlFor="profile-username-input">{t('Display Name')}</Label>
|
||||||
<Input
|
<Input
|
||||||
@@ -230,7 +225,6 @@ const ProfileEditorPage = forwardRef(({ index }: { index?: number }, ref) => {
|
|||||||
)}
|
)}
|
||||||
</Item>
|
</Item>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
</SecondaryPageLayout>
|
</SecondaryPageLayout>
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -87,9 +87,9 @@ const ProfilePage = forwardRef(({ id, index }: { id?: string; index?: number },
|
|||||||
if (!profile && isFetching) {
|
if (!profile && isFetching) {
|
||||||
return (
|
return (
|
||||||
<SecondaryPageLayout index={index} ref={ref}>
|
<SecondaryPageLayout index={index} ref={ref}>
|
||||||
<div className="sm:px-4">
|
<div>
|
||||||
<div className="relative bg-cover bg-center mb-2">
|
<div className="relative bg-cover bg-center mb-2">
|
||||||
<Skeleton className="w-full aspect-[3/1] sm:rounded-lg" />
|
<Skeleton className="w-full aspect-[3/1] rounded-none" />
|
||||||
<Skeleton className="w-24 h-24 absolute bottom-0 left-3 translate-y-1/2 border-4 border-background rounded-full" />
|
<Skeleton className="w-24 h-24 absolute bottom-0 left-3 translate-y-1/2 border-4 border-background rounded-full" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -106,13 +106,8 @@ const ProfilePage = forwardRef(({ id, index }: { id?: string; index?: number },
|
|||||||
return (
|
return (
|
||||||
<SecondaryPageLayout index={index} title={username} displayScrollToTopButton ref={ref}>
|
<SecondaryPageLayout index={index} title={username} displayScrollToTopButton ref={ref}>
|
||||||
<div ref={topContainerRef}>
|
<div ref={topContainerRef}>
|
||||||
<div className="sm:px-4">
|
|
||||||
<div className="relative bg-cover bg-center mb-2">
|
<div className="relative bg-cover bg-center mb-2">
|
||||||
<ProfileBanner
|
<ProfileBanner banner={banner} pubkey={pubkey} className="w-full aspect-[3/1]" />
|
||||||
banner={banner}
|
|
||||||
pubkey={pubkey}
|
|
||||||
className="w-full aspect-[3/1] sm:rounded-lg"
|
|
||||||
/>
|
|
||||||
<Avatar className="w-24 h-24 absolute left-3 bottom-0 translate-y-1/2 border-4 border-background">
|
<Avatar className="w-24 h-24 absolute left-3 bottom-0 translate-y-1/2 border-4 border-background">
|
||||||
<AvatarImage src={avatar} className="object-cover object-center" />
|
<AvatarImage src={avatar} className="object-cover object-center" />
|
||||||
<AvatarFallback>
|
<AvatarFallback>
|
||||||
@@ -120,9 +115,8 @@ const ProfilePage = forwardRef(({ id, index }: { id?: string; index?: number },
|
|||||||
</AvatarFallback>
|
</AvatarFallback>
|
||||||
</Avatar>
|
</Avatar>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
<div className="px-4">
|
<div className="px-4">
|
||||||
<div className="flex justify-end h-8 gap-2 items-center max-sm:translate-x-2">
|
<div className="flex justify-end h-8 gap-2 items-center">
|
||||||
<ProfileOptions pubkey={pubkey} />
|
<ProfileOptions pubkey={pubkey} />
|
||||||
{isSelf ? (
|
{isSelf ? (
|
||||||
<Button
|
<Button
|
||||||
|
|||||||
@@ -42,6 +42,7 @@ const RelayPage = forwardRef(({ url, index }: { url?: string; index?: number },
|
|||||||
controls={<RelayPageControls url={normalizedUrl} />}
|
controls={<RelayPageControls url={normalizedUrl} />}
|
||||||
displayScrollToTopButton
|
displayScrollToTopButton
|
||||||
>
|
>
|
||||||
|
<div className="h-3 w-full" />
|
||||||
<RelayInfo url={normalizedUrl} />
|
<RelayInfo url={normalizedUrl} />
|
||||||
{relayInfo?.supported_nips?.includes(50) && (
|
{relayInfo?.supported_nips?.includes(50) && (
|
||||||
<div className="px-4 py-2">
|
<div className="px-4 py-2">
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ const RelaySettingsPage = forwardRef(({ index }: { index?: number }, ref) => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<SecondaryPageLayout ref={ref} index={index} title={t('Relay settings')}>
|
<SecondaryPageLayout ref={ref} index={index} title={t('Relay settings')}>
|
||||||
<Tabs value={tabValue} onValueChange={setTabValue} className="px-4 pb-4 space-y-4">
|
<Tabs value={tabValue} onValueChange={setTabValue} className="px-4 py-3 space-y-4">
|
||||||
<TabsList>
|
<TabsList>
|
||||||
<TabsTrigger value="favorite-relays">{t('Favorite Relays')}</TabsTrigger>
|
<TabsTrigger value="favorite-relays">{t('Favorite Relays')}</TabsTrigger>
|
||||||
<TabsTrigger value="mailbox">{t('Read & Write Relays')}</TabsTrigger>
|
<TabsTrigger value="mailbox">{t('Read & Write Relays')}</TabsTrigger>
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ const TranslationPage = forwardRef(({ index }: { index?: number }, ref) => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<SecondaryPageLayout ref={ref} index={index} title={t('Translation')}>
|
<SecondaryPageLayout ref={ref} index={index} title={t('Translation')}>
|
||||||
<div className="px-4 pt-2 space-y-4">
|
<div className="px-4 pt-3 space-y-4">
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
<Label htmlFor="languages" className="text-base font-medium">
|
<Label htmlFor="languages" className="text-base font-medium">
|
||||||
{t('Languages')}
|
{t('Languages')}
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ const WalletPage = forwardRef(({ index }: { index?: number }, ref) => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<SecondaryPageLayout ref={ref} index={index} title={t('Wallet')}>
|
<SecondaryPageLayout ref={ref} index={index} title={t('Wallet')}>
|
||||||
<div className="px-4 pt-2 space-y-4">
|
<div className="px-4 pt-3 space-y-4">
|
||||||
<BcButton />
|
<BcButton />
|
||||||
<LightningAddressInput />
|
<LightningAddressInput />
|
||||||
<DefaultZapAmountInput />
|
<DefaultZapAmountInput />
|
||||||
|
|||||||
@@ -10,6 +10,9 @@ export default {
|
|||||||
sm: 'calc(var(--radius) - 4px)'
|
sm: 'calc(var(--radius) - 4px)'
|
||||||
},
|
},
|
||||||
colors: {
|
colors: {
|
||||||
|
surface: {
|
||||||
|
background: 'hsl(var(--surface-background))'
|
||||||
|
},
|
||||||
background: 'hsl(var(--background))',
|
background: 'hsl(var(--background))',
|
||||||
foreground: 'hsl(var(--foreground))',
|
foreground: 'hsl(var(--foreground))',
|
||||||
card: {
|
card: {
|
||||||
|
|||||||
Reference in New Issue
Block a user