mirror of
https://github.com/utopia-os/utopia-ui.git
synced 2026-03-01 12:44:17 +00:00
ui improvements
This commit is contained in:
parent
ad5e55bd27
commit
4de4cab9bb
@ -1,24 +1,14 @@
|
||||
import Bars3Icon from '@heroicons/react/16/solid/Bars3Icon'
|
||||
import EllipsisVerticalIcon from '@heroicons/react/16/solid/EllipsisVerticalIcon'
|
||||
import QuestionMarkIcon from '@heroicons/react/24/outline/QuestionMarkCircleIcon'
|
||||
import { useEffect, useRef, useState } from 'react'
|
||||
import { Link, useLocation } from 'react-router-dom'
|
||||
import { toast } from 'react-toastify'
|
||||
|
||||
import { useAuth } from '#components/Auth/useAuth'
|
||||
import { useItems } from '#components/Map/hooks/useItems'
|
||||
import { ThemeControl } from '#components/Templates/ThemeControl'
|
||||
|
||||
import { useAppState, useSetAppState } from './hooks/useAppState'
|
||||
|
||||
import type { Item } from '#types/Item'
|
||||
import { UserControl } from './UserControl'
|
||||
|
||||
export default function NavBar({ appName }: { appName: string }) {
|
||||
const { isAuthenticated, user, logout } = useAuth()
|
||||
|
||||
const [userProfile, setUserProfile] = useState<Item>({} as Item)
|
||||
const items = useItems()
|
||||
|
||||
const appState = useAppState()
|
||||
const setAppState = useSetAppState()
|
||||
|
||||
@ -26,14 +16,6 @@ export default function NavBar({ appName }: { appName: string }) {
|
||||
setAppState({ sideBarOpen: !appState.sideBarOpen })
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
const profile =
|
||||
user && items.find((i) => i.user_created?.id === user.id && i.layer?.userProfileLayer)
|
||||
profile
|
||||
? setUserProfile(profile)
|
||||
: setUserProfile({ id: crypto.randomUUID(), name: user?.first_name ?? '', text: '' })
|
||||
}, [user, items])
|
||||
|
||||
const nameRef = useRef<HTMLHeadingElement>(null)
|
||||
const [nameWidth, setNameWidth] = useState<number>(0)
|
||||
const location = useLocation()
|
||||
@ -49,24 +31,6 @@ export default function NavBar({ appName }: { appName: string }) {
|
||||
embedded !== 'true' && setShowNav(true)
|
||||
}, [location])
|
||||
|
||||
const onLogout = async () => {
|
||||
await toast.promise(logout(), {
|
||||
success: {
|
||||
render() {
|
||||
return 'Bye bye'
|
||||
},
|
||||
// other options
|
||||
icon: '👋',
|
||||
},
|
||||
error: {
|
||||
render({ data }) {
|
||||
return JSON.stringify(data)
|
||||
},
|
||||
},
|
||||
pending: 'logging out ..',
|
||||
})
|
||||
}
|
||||
|
||||
if (showNav) {
|
||||
return (
|
||||
<>
|
||||
@ -102,77 +66,7 @@ export default function NavBar({ appName }: { appName: string }) {
|
||||
</div>
|
||||
|
||||
{appState.showThemeControl && <ThemeControl />}
|
||||
|
||||
{isAuthenticated ? (
|
||||
<div className='tw:flex tw:mr-2'>
|
||||
<Link
|
||||
to={`${userProfile.id && '/item/' + userProfile.id}`}
|
||||
className='tw:flex tw:items-center'
|
||||
>
|
||||
{userProfile.image && (
|
||||
<div className='tw:avatar'>
|
||||
<div className='tw:w-10 tw:rounded-full'>
|
||||
<img src={appState.assetsApi.url + userProfile.image} />
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
<div className='tw:ml-2 tw:mr-2'>{userProfile.name || user?.first_name}</div>
|
||||
</Link>
|
||||
<div className='tw:dropdown tw:dropdown-end'>
|
||||
<label tabIndex={0} className='tw:btn tw:btn-ghost tw:btn-square'>
|
||||
<EllipsisVerticalIcon className='tw:h-5 tw:w-5' />
|
||||
</label>
|
||||
<ul
|
||||
tabIndex={0}
|
||||
className='tw:menu tw:menu-compact tw:dropdown-content tw:mt-4 tw:p-2 tw:shadow tw:bg-base-100 tw:rounded-box tw:w-52 tw:z-10000!'
|
||||
>
|
||||
<li>
|
||||
<Link to={`${userProfile.id && '/edit-item/' + userProfile.id}`}>Profile</Link>
|
||||
</li>
|
||||
<li>
|
||||
<Link to={'/user-settings'}>Settings</Link>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
onClick={() => {
|
||||
void onLogout()
|
||||
}}
|
||||
>
|
||||
Logout
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
<div className='tw:mr-2 tw:flex tw:items-center'>
|
||||
<div className='tw:hidden tw:md:flex'>
|
||||
<Link to={'/login'}>
|
||||
<div className='tw:self-center tw:btn tw:btn-ghost tw:mr-2'>Login</div>
|
||||
</Link>
|
||||
|
||||
<Link to={'/signup'}>
|
||||
<div className='tw:btn tw:btn-ghost tw:mr-2'>Sign Up</div>
|
||||
</Link>
|
||||
</div>
|
||||
<div className='tw:dropdown tw:dropdown-end'>
|
||||
<label tabIndex={1} className='tw:btn tw:btn-ghost tw:md:hidden'>
|
||||
<EllipsisVerticalIcon className='tw:h-5 tw:w-5' />
|
||||
</label>
|
||||
<ul
|
||||
tabIndex={1}
|
||||
className='tw:menu tw:dropdown-content tw:mt-4 tw:p-2 tw:shadow tw:bg-base-100 tw:rounded-box tw:w-52 tw:z-10000!'
|
||||
>
|
||||
<li>
|
||||
<Link to={'/login'}>Login</Link>
|
||||
</li>
|
||||
<li>
|
||||
<Link to={'/signup'}>Sign Up</Link>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
<UserControl />
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
|
||||
119
src/Components/AppShell/UserControl.tsx
Normal file
119
src/Components/AppShell/UserControl.tsx
Normal file
@ -0,0 +1,119 @@
|
||||
import EllipsisVerticalIcon from '@heroicons/react/16/solid/EllipsisVerticalIcon'
|
||||
import { useState, useEffect } from 'react'
|
||||
import { Link } from 'react-router-dom'
|
||||
import { toast } from 'react-toastify'
|
||||
|
||||
import { useAuth } from '#components/Auth/useAuth'
|
||||
import { useItems } from '#components/Map/hooks/useItems'
|
||||
|
||||
import { useAppState } from './hooks/useAppState'
|
||||
|
||||
import type { Item } from '#types/Item'
|
||||
|
||||
export const UserControl = () => {
|
||||
const { isAuthenticated, user, logout } = useAuth()
|
||||
const appState = useAppState()
|
||||
|
||||
const [userProfile, setUserProfile] = useState<Item>({} as Item)
|
||||
const items = useItems()
|
||||
|
||||
useEffect(() => {
|
||||
const profile =
|
||||
user && items.find((i) => i.user_created?.id === user.id && i.layer?.userProfileLayer)
|
||||
profile
|
||||
? setUserProfile(profile)
|
||||
: setUserProfile({ id: crypto.randomUUID(), name: user?.first_name ?? '', text: '' })
|
||||
}, [user, items])
|
||||
|
||||
const onLogout = async () => {
|
||||
await toast.promise(logout(), {
|
||||
success: {
|
||||
render() {
|
||||
return 'Bye bye'
|
||||
},
|
||||
// other options
|
||||
icon: '👋',
|
||||
},
|
||||
error: {
|
||||
render({ data }) {
|
||||
return JSON.stringify(data)
|
||||
},
|
||||
},
|
||||
pending: 'logging out ..',
|
||||
})
|
||||
}
|
||||
return (
|
||||
<>
|
||||
{isAuthenticated ? (
|
||||
<div className='tw:flex tw:mr-2'>
|
||||
<Link
|
||||
to={`${userProfile.id && '/item/' + userProfile.id}`}
|
||||
className='tw:flex tw:items-center'
|
||||
>
|
||||
{userProfile.image && (
|
||||
<div className='tw:avatar'>
|
||||
<div className='tw:w-10 tw:rounded-full'>
|
||||
<img src={appState.assetsApi.url + userProfile.image} />
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
<div className='tw:ml-2 tw:mr-2'>{userProfile.name || user?.first_name}</div>
|
||||
</Link>
|
||||
<div className='tw:dropdown tw:dropdown-end'>
|
||||
<label tabIndex={0} className='tw:btn tw:btn-ghost tw:btn-square'>
|
||||
<EllipsisVerticalIcon className='tw:h-5 tw:w-5' />
|
||||
</label>
|
||||
<ul
|
||||
tabIndex={0}
|
||||
className='tw:menu tw:menu-compact tw:dropdown-content tw:mt-4 tw:p-2 tw:shadow tw:bg-base-100 tw:rounded-box tw:w-52 tw:z-10000!'
|
||||
>
|
||||
<li>
|
||||
<Link to={`${userProfile.id && '/edit-item/' + userProfile.id}`}>Profile</Link>
|
||||
</li>
|
||||
<li>
|
||||
<Link to={'/user-settings'}>Settings</Link>
|
||||
</li>
|
||||
<li>
|
||||
<a
|
||||
onClick={() => {
|
||||
void onLogout()
|
||||
}}
|
||||
>
|
||||
Logout
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
<div className='tw:mr-2 tw:flex tw:items-center'>
|
||||
<div className='tw:hidden tw:md:flex'>
|
||||
<Link to={'/login'}>
|
||||
<div className='tw:self-center tw:btn tw:btn-ghost tw:mr-2'>Login</div>
|
||||
</Link>
|
||||
|
||||
<Link to={'/signup'}>
|
||||
<div className='tw:btn tw:btn-ghost tw:mr-2'>Sign Up</div>
|
||||
</Link>
|
||||
</div>
|
||||
<div className='tw:dropdown tw:dropdown-end'>
|
||||
<label tabIndex={1} className='tw:btn tw:btn-ghost tw:md:hidden'>
|
||||
<EllipsisVerticalIcon className='tw:h-5 tw:w-5' />
|
||||
</label>
|
||||
<ul
|
||||
tabIndex={1}
|
||||
className='tw:menu tw:dropdown-content tw:mt-4 tw:p-2 tw:shadow tw:bg-base-100 tw:rounded-box tw:w-52 tw:z-10000!'
|
||||
>
|
||||
<li>
|
||||
<Link to={'/login'}>Login</Link>
|
||||
</li>
|
||||
<li>
|
||||
<Link to={'/signup'}>Sign Up</Link>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
)
|
||||
}
|
||||
@ -123,7 +123,7 @@ export const TabsView = ({
|
||||
role='tabpanel'
|
||||
className='tw:tab-content tw:bg-base-100 tw:rounded-box tw:h-[calc(100dvh-280px)] tw:overflow-y-auto fade tw:pt-2 tw:pb-4 tw:mb-4 tw:overflow-x-hidden'
|
||||
>
|
||||
<table className='sm:tw:table-sm md:tw:table-md'>
|
||||
<table className='sm:tw:table-sm md:tw:table-md tw:w-full'>
|
||||
<tbody>
|
||||
{attestations
|
||||
.filter((a) => a.to.some((t) => t.directus_users_id === item.user_created?.id))
|
||||
@ -135,7 +135,9 @@ export const TabsView = ({
|
||||
<tr key={i}>
|
||||
<td>
|
||||
<div
|
||||
className={`tw:cursor-pointer tw:text-3xl tw:mask tw:mask-${a.shape} tw:p-3 tw:mr-2 tw:shadow-xl tw:bg-[${a.color}]`}
|
||||
className={`tw:cursor-pointer tw:text-3xl tw:mask ${a.shape === 'squircle' ? 'tw:mask-squircle' : a.shape === 'circle' ? 'tw:mask-circle' : 'tw:mask-hexagon-2'} tw:p-2 tw:my-2 tw:mr-2 tw:shadow-xl`}
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
||||
style={{ backgroundColor: a.color }}
|
||||
>
|
||||
{a.emoji}
|
||||
</div>
|
||||
|
||||
@ -22,8 +22,8 @@ export const ThemeControl = () => {
|
||||
useEffect(() => {
|
||||
if (theme !== 'default') {
|
||||
localStorage.setItem('theme', JSON.stringify(theme))
|
||||
document.documentElement.setAttribute('data-theme', theme)
|
||||
}
|
||||
} else localStorage.removeItem('theme')
|
||||
document.documentElement.setAttribute('data-theme', theme)
|
||||
}, [theme])
|
||||
|
||||
return (
|
||||
@ -42,12 +42,12 @@ export const ThemeControl = () => {
|
||||
</div>
|
||||
<ul
|
||||
tabIndex={0}
|
||||
className='tw:dropdown-content tw:bg-base-300 tw:rounded-box tw:z-1 tw:w-52 tw:p-2 tw:shadow-2xl'
|
||||
className='tw:dropdown-content tw:bg-base-200 tw:rounded-box tw:z-1 tw:w-36 tw:p-2 tw:shadow-2xl'
|
||||
>
|
||||
{themes.map((t) => (
|
||||
<li key={t}>
|
||||
<input
|
||||
className={`tw:btn ${theme === t ? 'tw:bg-primary' : ''} tw:btn-sm tw:btn-block tw:btn-ghost tw:justify-start`}
|
||||
className={`tw:btn ${theme === t ? 'tw:bg-base-300' : ''} tw:btn-sm tw:btn-block tw:btn-ghost tw:justify-start`}
|
||||
type='radio'
|
||||
name='theme'
|
||||
value={t}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user