feat: implement profile edit
All checks were successful
Release to Staging / build_and_release (push) Successful in 44s
All checks were successful
Release to Staging / build_and_release (push) Successful in 44s
This commit is contained in:
parent
e490b35a5f
commit
1a889213fa
@ -182,7 +182,7 @@ export const Profile = ({ profile }: ProfileProps) => {
|
|||||||
<path d='M384 96L384 0h-112c-26.51 0-48 21.49-48 48v288c0 26.51 21.49 48 48 48H464c26.51 0 48-21.49 48-48V128h-95.1C398.4 128 384 113.6 384 96zM416 0v96h96L416 0zM192 352V128h-144c-26.51 0-48 21.49-48 48v288c0 26.51 21.49 48 48 48h192c26.51 0 48-21.49 48-48L288 416h-32C220.7 416 192 387.3 192 352z'></path>
|
<path d='M384 96L384 0h-112c-26.51 0-48 21.49-48 48v288c0 26.51 21.49 48 48 48H464c26.51 0 48-21.49 48-48V128h-95.1C398.4 128 384 113.6 384 96zM416 0v96h96L416 0zM192 352V128h-144c-26.51 0-48 21.49-48 48v288c0 26.51 21.49 48 48 48h192c26.51 0 48-21.49 48-48L288 416h-32C220.7 416 192 387.3 192 352z'></path>
|
||||||
</svg>
|
</svg>
|
||||||
</div>
|
</div>
|
||||||
<QRButtonWithPopUp pubkey={hexPubkey} />
|
<ProfileQRButtonWithPopUp pubkey={hexPubkey} />
|
||||||
<ZapButtonWithPopUp pubkey={hexPubkey} />
|
<ZapButtonWithPopUp pubkey={hexPubkey} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -231,7 +231,9 @@ type QRButtonWithPopUpProps = {
|
|||||||
pubkey: string
|
pubkey: string
|
||||||
}
|
}
|
||||||
|
|
||||||
const QRButtonWithPopUp = ({ pubkey }: QRButtonWithPopUpProps) => {
|
export const ProfileQRButtonWithPopUp = ({
|
||||||
|
pubkey
|
||||||
|
}: QRButtonWithPopUpProps) => {
|
||||||
const [isOpen, setIsOpen] = useState(false)
|
const [isOpen, setIsOpen] = useState(false)
|
||||||
|
|
||||||
const nprofile = nip19.nprofileEncode({
|
const nprofile = nip19.nprofileEncode({
|
||||||
|
51
src/components/SVGs.tsx
Normal file
51
src/components/SVGs.tsx
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
export const ProfileSVG = (props: React.SVGProps<SVGSVGElement>) => (
|
||||||
|
<svg
|
||||||
|
xmlns='http://www.w3.org/2000/svg'
|
||||||
|
viewBox='-32 0 512 512'
|
||||||
|
width='1em'
|
||||||
|
height='1em'
|
||||||
|
fill='currentColor'
|
||||||
|
{...props}
|
||||||
|
>
|
||||||
|
<path d='M224 256c70.7 0 128-57.31 128-128s-57.3-128-128-128C153.3 0 96 57.31 96 128S153.3 256 224 256zM274.7 304H173.3C77.61 304 0 381.6 0 477.3c0 19.14 15.52 34.67 34.66 34.67h378.7C432.5 512 448 496.5 448 477.3C448 381.6 370.4 304 274.7 304z'></path>
|
||||||
|
</svg>
|
||||||
|
)
|
||||||
|
|
||||||
|
export const RelaySVG = (props: React.SVGProps<SVGSVGElement>) => (
|
||||||
|
<svg
|
||||||
|
xmlns='http://www.w3.org/2000/svg'
|
||||||
|
viewBox='0 0 512 512'
|
||||||
|
width='1em'
|
||||||
|
height='1em'
|
||||||
|
fill='currentColor'
|
||||||
|
{...props}
|
||||||
|
>
|
||||||
|
<path d='M480 288H32c-17.62 0-32 14.38-32 32v128c0 17.62 14.38 32 32 32h448c17.62 0 32-14.38 32-32v-128C512 302.4 497.6 288 480 288zM352 408c-13.25 0-24-10.75-24-24s10.75-24 24-24s24 10.75 24 24S365.3 408 352 408zM416 408c-13.25 0-24-10.75-24-24s10.75-24 24-24s24 10.75 24 24S429.3 408 416 408zM480 32H32C14.38 32 0 46.38 0 64v128c0 17.62 14.38 32 32 32h448c17.62 0 32-14.38 32-32V64C512 46.38 497.6 32 480 32zM352 152c-13.25 0-24-10.75-24-24S338.8 104 352 104S376 114.8 376 128S365.3 152 352 152zM416 152c-13.25 0-24-10.75-24-24S402.8 104 416 104S440 114.8 440 128S429.3 152 416 152z'></path>
|
||||||
|
</svg>
|
||||||
|
)
|
||||||
|
|
||||||
|
export const PreferenceSVG = (props: React.SVGProps<SVGSVGElement>) => (
|
||||||
|
<svg
|
||||||
|
xmlns='http://www.w3.org/2000/svg'
|
||||||
|
viewBox='0 0 512 512'
|
||||||
|
width='1em'
|
||||||
|
height='1em'
|
||||||
|
fill='currentColor'
|
||||||
|
{...props}
|
||||||
|
>
|
||||||
|
<path d='M0 416C0 398.3 14.33 384 32 384H86.66C99 355.7 127.2 336 160 336C192.8 336 220.1 355.7 233.3 384H480C497.7 384 512 398.3 512 416C512 433.7 497.7 448 480 448H233.3C220.1 476.3 192.8 496 160 496C127.2 496 99 476.3 86.66 448H32C14.33 448 0 433.7 0 416V416zM192 416C192 398.3 177.7 384 160 384C142.3 384 128 398.3 128 416C128 433.7 142.3 448 160 448C177.7 448 192 433.7 192 416zM352 176C384.8 176 412.1 195.7 425.3 224H480C497.7 224 512 238.3 512 256C512 273.7 497.7 288 480 288H425.3C412.1 316.3 384.8 336 352 336C319.2 336 291 316.3 278.7 288H32C14.33 288 0 273.7 0 256C0 238.3 14.33 224 32 224H278.7C291 195.7 319.2 176 352 176zM384 256C384 238.3 369.7 224 352 224C334.3 224 320 238.3 320 256C320 273.7 334.3 288 352 288C369.7 288 384 273.7 384 256zM480 64C497.7 64 512 78.33 512 96C512 113.7 497.7 128 480 128H265.3C252.1 156.3 224.8 176 192 176C159.2 176 131 156.3 118.7 128H32C14.33 128 0 113.7 0 96C0 78.33 14.33 64 32 64H118.7C131 35.75 159.2 16 192 16C224.8 16 252.1 35.75 265.3 64H480zM160 96C160 113.7 174.3 128 192 128C209.7 128 224 113.7 224 96C224 78.33 209.7 64 192 64C174.3 64 160 78.33 160 96z'></path>
|
||||||
|
</svg>
|
||||||
|
)
|
||||||
|
|
||||||
|
export const AdminSVG = (props: React.SVGProps<SVGSVGElement>) => (
|
||||||
|
<svg
|
||||||
|
xmlns='http://www.w3.org/2000/svg'
|
||||||
|
viewBox='0 -32 576 576'
|
||||||
|
width='1em'
|
||||||
|
height='1em'
|
||||||
|
fill='currentColor'
|
||||||
|
{...props}
|
||||||
|
>
|
||||||
|
<path d='M560 448H512V113.5c0-27.25-21.5-49.5-48-49.5L352 64.01V128h96V512h112c8.875 0 16-7.125 16-15.1v-31.1C576 455.1 568.9 448 560 448zM280.3 1.007l-192 49.75C73.1 54.51 64 67.76 64 82.88V448H16c-8.875 0-16 7.125-16 15.1v31.1C0 504.9 7.125 512 16 512H320V33.13C320 11.63 300.5-4.243 280.3 1.007zM232 288c-13.25 0-24-14.37-24-31.1c0-17.62 10.75-31.1 24-31.1S256 238.4 256 256C256 273.6 245.3 288 232 288z'></path>
|
||||||
|
</svg>
|
||||||
|
)
|
@ -109,10 +109,24 @@ export class RelayController {
|
|||||||
)
|
)
|
||||||
|
|
||||||
// Wait for all relay connection attempts to settle (either fulfilled or rejected)
|
// Wait for all relay connection attempts to settle (either fulfilled or rejected)
|
||||||
await Promise.allSettled([appRelayPromise, ...relayPromises])
|
const results = await Promise.allSettled([
|
||||||
|
appRelayPromise,
|
||||||
|
...relayPromises
|
||||||
|
])
|
||||||
|
|
||||||
|
// Extract non-null values from fulfilled promises in a single pass
|
||||||
|
const relays = results.reduce<Relay[]>((acc, result) => {
|
||||||
|
if (result.status === 'fulfilled') {
|
||||||
|
const value = result.value
|
||||||
|
if (value) {
|
||||||
|
acc.push(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return acc
|
||||||
|
}, [])
|
||||||
|
|
||||||
// If no relays are connected, log an error and return an empty array
|
// If no relays are connected, log an error and return an empty array
|
||||||
if (this.connectedRelays.length === 0) {
|
if (relays.length === 0) {
|
||||||
log(this.debug, LogType.Error, 'No relay is connected!')
|
log(this.debug, LogType.Error, 'No relay is connected!')
|
||||||
return []
|
return []
|
||||||
}
|
}
|
||||||
@ -120,7 +134,7 @@ export class RelayController {
|
|||||||
const publishedOnRelays: string[] = [] // Track relays where the event was successfully published
|
const publishedOnRelays: string[] = [] // Track relays where the event was successfully published
|
||||||
|
|
||||||
// Create promises to publish the event to each connected relay
|
// Create promises to publish the event to each connected relay
|
||||||
const publishPromises = this.connectedRelays.map((relay) => {
|
const publishPromises = relays.map((relay) => {
|
||||||
log(
|
log(
|
||||||
this.debug,
|
this.debug,
|
||||||
LogType.Info,
|
LogType.Info,
|
||||||
@ -311,7 +325,7 @@ export class RelayController {
|
|||||||
const publishedOnRelays: string[] = [] // Track relays where the event was successfully published
|
const publishedOnRelays: string[] = [] // Track relays where the event was successfully published
|
||||||
|
|
||||||
// Create promises to publish the event to each connected relay
|
// Create promises to publish the event to each connected relay
|
||||||
const publishPromises = this.connectedRelays.map((relay) => {
|
const publishPromises = relays.map((relay) => {
|
||||||
log(
|
log(
|
||||||
this.debug,
|
this.debug,
|
||||||
LogType.Info,
|
LogType.Info,
|
||||||
|
@ -1,971 +0,0 @@
|
|||||||
import { logout } from 'nostr-login'
|
|
||||||
import { Link, useLocation } from 'react-router-dom'
|
|
||||||
import { toast } from 'react-toastify'
|
|
||||||
import { InputField } from '../components/Inputs'
|
|
||||||
import { ProfileSection } from '../components/ProfileSection'
|
|
||||||
import { useAppSelector } from '../hooks'
|
|
||||||
import { appRoutes } from '../routes'
|
|
||||||
import { AuthMethod } from '../store/reducers/user'
|
|
||||||
import '../styles/feed.css'
|
|
||||||
import '../styles/innerPage.css'
|
|
||||||
import '../styles/popup.css'
|
|
||||||
import '../styles/profile.css'
|
|
||||||
import '../styles/settings.css'
|
|
||||||
import '../styles/styles.css'
|
|
||||||
import '../styles/write.css'
|
|
||||||
import { copyTextToClipboard } from '../utils'
|
|
||||||
import { MetadataController } from '../controllers'
|
|
||||||
import { useEffect, useState } from 'react'
|
|
||||||
|
|
||||||
export const SettingsPage = () => {
|
|
||||||
const location = useLocation()
|
|
||||||
const userState = useAppSelector((state) => state.user)
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className='InnerBodyMain'>
|
|
||||||
<div className='ContainerMain'>
|
|
||||||
<div className='IBMSecMainGroup IBMSecMainGroupAlt'>
|
|
||||||
<div className='IBMSMSplitMain IBMSMSplitMainThree'>
|
|
||||||
<SettingTabs />
|
|
||||||
{location.pathname === appRoutes.settingsProfile && (
|
|
||||||
<ProfileSettings />
|
|
||||||
)}
|
|
||||||
{location.pathname === appRoutes.settingsRelays && (
|
|
||||||
<RelaySettings />
|
|
||||||
)}
|
|
||||||
{location.pathname === appRoutes.settingsPreferences && (
|
|
||||||
<PreferencesSetting />
|
|
||||||
)}
|
|
||||||
{location.pathname === appRoutes.settingsAdmin && <AdminSetting />}
|
|
||||||
{userState.auth && userState.user?.pubkey && (
|
|
||||||
<ProfileSection pubkey={userState.user.pubkey as string} />
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
const SettingTabs = () => {
|
|
||||||
const location = useLocation()
|
|
||||||
const [isAdmin, setIsAdmin] = useState(false)
|
|
||||||
const userState = useAppSelector((state) => state.user)
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
MetadataController.getInstance().then((controller) => {
|
|
||||||
if (userState.auth && userState.user?.npub) {
|
|
||||||
setIsAdmin(
|
|
||||||
controller.adminNpubs.includes(userState.user.npub as string)
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
setIsAdmin(false)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}, [userState])
|
|
||||||
|
|
||||||
const handleSignOut = () => {
|
|
||||||
logout()
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className='IBMSMSplitMainSmallSide'>
|
|
||||||
<div className='IBMSMSplitMainSmallSideSec'>
|
|
||||||
<div className='IBMSMSplitMainSmallSideSec'>
|
|
||||||
<h3 className='IBMSMSMSSS_Text'>Settings (WIP)</h3>
|
|
||||||
</div>
|
|
||||||
<div className='IBMSMSMSSS_Buttons'>
|
|
||||||
<Link
|
|
||||||
className={`btn btnMain btnMainAltText btnMainClear ${
|
|
||||||
location.pathname === appRoutes.settingsProfile
|
|
||||||
? 'btnMainClearActive'
|
|
||||||
: ''
|
|
||||||
}`}
|
|
||||||
role='button'
|
|
||||||
to={appRoutes.settingsProfile}
|
|
||||||
>
|
|
||||||
<svg
|
|
||||||
xmlns='http://www.w3.org/2000/svg'
|
|
||||||
viewBox='-32 0 512 512'
|
|
||||||
width='1em'
|
|
||||||
height='1em'
|
|
||||||
fill='currentColor'
|
|
||||||
>
|
|
||||||
<path d='M224 256c70.7 0 128-57.31 128-128s-57.3-128-128-128C153.3 0 96 57.31 96 128S153.3 256 224 256zM274.7 304H173.3C77.61 304 0 381.6 0 477.3c0 19.14 15.52 34.67 34.66 34.67h378.7C432.5 512 448 496.5 448 477.3C448 381.6 370.4 304 274.7 304z'></path>
|
|
||||||
</svg>
|
|
||||||
Profile
|
|
||||||
</Link>
|
|
||||||
<Link
|
|
||||||
className={`btn btnMain btnMainAltText btnMainClear ${
|
|
||||||
location.pathname === appRoutes.settingsRelays
|
|
||||||
? 'btnMainClearActive'
|
|
||||||
: ''
|
|
||||||
}`}
|
|
||||||
role='button'
|
|
||||||
to={appRoutes.settingsRelays}
|
|
||||||
>
|
|
||||||
<svg
|
|
||||||
xmlns='http://www.w3.org/2000/svg'
|
|
||||||
viewBox='0 0 512 512'
|
|
||||||
width='1em'
|
|
||||||
height='1em'
|
|
||||||
fill='currentColor'
|
|
||||||
>
|
|
||||||
<path d='M480 288H32c-17.62 0-32 14.38-32 32v128c0 17.62 14.38 32 32 32h448c17.62 0 32-14.38 32-32v-128C512 302.4 497.6 288 480 288zM352 408c-13.25 0-24-10.75-24-24s10.75-24 24-24s24 10.75 24 24S365.3 408 352 408zM416 408c-13.25 0-24-10.75-24-24s10.75-24 24-24s24 10.75 24 24S429.3 408 416 408zM480 32H32C14.38 32 0 46.38 0 64v128c0 17.62 14.38 32 32 32h448c17.62 0 32-14.38 32-32V64C512 46.38 497.6 32 480 32zM352 152c-13.25 0-24-10.75-24-24S338.8 104 352 104S376 114.8 376 128S365.3 152 352 152zM416 152c-13.25 0-24-10.75-24-24S402.8 104 416 104S440 114.8 440 128S429.3 152 416 152z'></path>
|
|
||||||
</svg>
|
|
||||||
Relays
|
|
||||||
</Link>
|
|
||||||
<Link
|
|
||||||
className={`btn btnMain btnMainAltText btnMainClear ${
|
|
||||||
location.pathname === appRoutes.settingsPreferences
|
|
||||||
? 'btnMainClearActive'
|
|
||||||
: ''
|
|
||||||
}`}
|
|
||||||
role='button'
|
|
||||||
to={appRoutes.settingsPreferences}
|
|
||||||
>
|
|
||||||
<svg
|
|
||||||
xmlns='http://www.w3.org/2000/svg'
|
|
||||||
viewBox='0 0 512 512'
|
|
||||||
width='1em'
|
|
||||||
height='1em'
|
|
||||||
fill='currentColor'
|
|
||||||
>
|
|
||||||
<path d='M0 416C0 398.3 14.33 384 32 384H86.66C99 355.7 127.2 336 160 336C192.8 336 220.1 355.7 233.3 384H480C497.7 384 512 398.3 512 416C512 433.7 497.7 448 480 448H233.3C220.1 476.3 192.8 496 160 496C127.2 496 99 476.3 86.66 448H32C14.33 448 0 433.7 0 416V416zM192 416C192 398.3 177.7 384 160 384C142.3 384 128 398.3 128 416C128 433.7 142.3 448 160 448C177.7 448 192 433.7 192 416zM352 176C384.8 176 412.1 195.7 425.3 224H480C497.7 224 512 238.3 512 256C512 273.7 497.7 288 480 288H425.3C412.1 316.3 384.8 336 352 336C319.2 336 291 316.3 278.7 288H32C14.33 288 0 273.7 0 256C0 238.3 14.33 224 32 224H278.7C291 195.7 319.2 176 352 176zM384 256C384 238.3 369.7 224 352 224C334.3 224 320 238.3 320 256C320 273.7 334.3 288 352 288C369.7 288 384 273.7 384 256zM480 64C497.7 64 512 78.33 512 96C512 113.7 497.7 128 480 128H265.3C252.1 156.3 224.8 176 192 176C159.2 176 131 156.3 118.7 128H32C14.33 128 0 113.7 0 96C0 78.33 14.33 64 32 64H118.7C131 35.75 159.2 16 192 16C224.8 16 252.1 35.75 265.3 64H480zM160 96C160 113.7 174.3 128 192 128C209.7 128 224 113.7 224 96C224 78.33 209.7 64 192 64C174.3 64 160 78.33 160 96z'></path>
|
|
||||||
</svg>
|
|
||||||
Preference
|
|
||||||
</Link>
|
|
||||||
{isAdmin && (
|
|
||||||
<Link
|
|
||||||
className={`btn btnMain btnMainAltText btnMainClear ${
|
|
||||||
location.pathname === appRoutes.settingsAdmin
|
|
||||||
? 'btnMainClearActive'
|
|
||||||
: ''
|
|
||||||
}`}
|
|
||||||
role='button'
|
|
||||||
to={appRoutes.settingsAdmin}
|
|
||||||
>
|
|
||||||
<svg
|
|
||||||
xmlns='http://www.w3.org/2000/svg'
|
|
||||||
viewBox='0 -32 576 576'
|
|
||||||
width='1em'
|
|
||||||
height='1em'
|
|
||||||
fill='currentColor'
|
|
||||||
>
|
|
||||||
<path d='M560 448H512V113.5c0-27.25-21.5-49.5-48-49.5L352 64.01V128h96V512h112c8.875 0 16-7.125 16-15.1v-31.1C576 455.1 568.9 448 560 448zM280.3 1.007l-192 49.75C73.1 54.51 64 67.76 64 82.88V448H16c-8.875 0-16 7.125-16 15.1v31.1C0 504.9 7.125 512 16 512H320V33.13C320 11.63 300.5-4.243 280.3 1.007zM232 288c-13.25 0-24-14.37-24-31.1c0-17.62 10.75-31.1 24-31.1S256 238.4 256 256C256 273.6 245.3 288 232 288z'></path>
|
|
||||||
</svg>
|
|
||||||
Admin
|
|
||||||
</Link>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{userState.auth &&
|
|
||||||
userState.auth.method === AuthMethod.Local &&
|
|
||||||
userState.auth.localNsec && (
|
|
||||||
<div className='inputLabelWrapperMain'>
|
|
||||||
<label className='form-label labelMain'>Your Private Key</label>
|
|
||||||
<p className='labelDescriptionMain'>
|
|
||||||
NOTICE: Make sure you save your private key (nsec) somewhere
|
|
||||||
safe.
|
|
||||||
</p>
|
|
||||||
<div className='inputWrapperMain'>
|
|
||||||
<input
|
|
||||||
type='password'
|
|
||||||
className='inputMain inputMainWithBtn'
|
|
||||||
value={userState.auth.localNsec}
|
|
||||||
/>
|
|
||||||
<button
|
|
||||||
className='btn btnMain btnMainInsideField'
|
|
||||||
type='button'
|
|
||||||
onClick={() => {
|
|
||||||
copyTextToClipboard(
|
|
||||||
userState.auth?.localNsec as string
|
|
||||||
).then((isCopied) => {
|
|
||||||
if (isCopied) toast.success('Nsec copied to clipboard!')
|
|
||||||
})
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<svg
|
|
||||||
xmlns='http://www.w3.org/2000/svg'
|
|
||||||
viewBox='0 0 512 512'
|
|
||||||
width='1em'
|
|
||||||
height='1em'
|
|
||||||
fill='currentColor'
|
|
||||||
>
|
|
||||||
<path d='M384 96L384 0h-112c-26.51 0-48 21.49-48 48v288c0 26.51 21.49 48 48 48H464c26.51 0 48-21.49 48-48V128h-95.1C398.4 128 384 113.6 384 96zM416 0v96h96L416 0zM192 352V128h-144c-26.51 0-48 21.49-48 48v288c0 26.51 21.49 48 48 48h192c26.51 0 48-21.49 48-48L288 416h-32C220.7 416 192 387.3 192 352z'></path>
|
|
||||||
</svg>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
<p className='labelDescriptionMain'>
|
|
||||||
WARNING: Do not sign-out without saving your nsec somewhere
|
|
||||||
safe. Otherwise, you'll lose access to your "account".
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{userState.auth && (
|
|
||||||
<button className='btn btnMain' type='button' onClick={handleSignOut}>
|
|
||||||
Sign out
|
|
||||||
</button>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
const ProfileSettings = () => {
|
|
||||||
return (
|
|
||||||
<div className='IBMSMSplitMainFullSideFWMid'>
|
|
||||||
<div className='IBMSMSplitMainFullSideSec'>
|
|
||||||
<div className='IBMSMSMBSS_Profile'>
|
|
||||||
<div className='IBMSMSMBSS_ProfilePreview'>
|
|
||||||
<div className='IBMSMSMSSS_Author_Top_Left'>
|
|
||||||
<div
|
|
||||||
className='IBMSMSMSSS_Author_Top_Banner'
|
|
||||||
style={{
|
|
||||||
background: `url('assets/img/DEGMods%20Placeholder%20Img.png') center / cover no-repeat`
|
|
||||||
}}
|
|
||||||
></div>
|
|
||||||
<a
|
|
||||||
className='IBMSMSMSSS_Author_Top_Left_InsideLinkWrapper'
|
|
||||||
href='profile.html'
|
|
||||||
>
|
|
||||||
<div className='IBMSMSMSSS_Author_Top_Left_Inside'>
|
|
||||||
<div className='IBMSMSMSSS_Author_Top_Left_InsidePic'>
|
|
||||||
<div className='IBMSMSMSSS_Author_Top_PPWrapper'>
|
|
||||||
<div
|
|
||||||
className='IBMSMSMSSS_Author_Top_PP'
|
|
||||||
style={{
|
|
||||||
background: `url('/assets/img/DEG%20Mods%20Default%20PP.png') center / cover no-repeat`
|
|
||||||
}}
|
|
||||||
></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className='IBMSMSMSSS_Author_Top_Left_InsideDetails'>
|
|
||||||
<div className='IBMSMSMSSS_Author_TopWrapper'>
|
|
||||||
<p className='IBMSMSMSSS_Author_Top_Name'>User name</p>
|
|
||||||
<p className='IBMSMSMSSS_Author_Top_Handle'>
|
|
||||||
nip5handle@domain.com
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</a>
|
|
||||||
<div className='IBMSMSMSSS_Author_Top_AddressWrapper'>
|
|
||||||
<div className='IBMSMSMSSS_Author_Top_AddressWrapped'>
|
|
||||||
<p
|
|
||||||
id='SiteOwnerAddress-1'
|
|
||||||
className='IBMSMSMSSS_Author_Top_Address'
|
|
||||||
>
|
|
||||||
npub1address
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
<div className='IBMSMSMSSS_Author_Top_IconWrapper'>
|
|
||||||
<div
|
|
||||||
id='copySiteOwnerAddress-1'
|
|
||||||
className='IBMSMSMSSS_Author_Top_IconWrapped'
|
|
||||||
>
|
|
||||||
<svg
|
|
||||||
xmlns='http://www.w3.org/2000/svg'
|
|
||||||
viewBox='0 0 512 512'
|
|
||||||
width='1em'
|
|
||||||
height='1em'
|
|
||||||
fill='currentColor'
|
|
||||||
className='IBMSMSMSSS_Author_Top_Icon'
|
|
||||||
>
|
|
||||||
<path d='M384 96L384 0h-112c-26.51 0-48 21.49-48 48v288c0 26.51 21.49 48 48 48H464c26.51 0 48-21.49 48-48V128h-95.1C398.4 128 384 113.6 384 96zM416 0v96h96L416 0zM192 352V128h-144c-26.51 0-48 21.49-48 48v288c0 26.51 21.49 48 48 48h192c26.51 0 48-21.49 48-48L288 416h-32C220.7 416 192 387.3 192 352z'></path>
|
|
||||||
</svg>
|
|
||||||
</div>
|
|
||||||
<div className='IBMSMSMSSS_Author_Top_IconWrapped IBMSMSMSSS_Author_Top_IconWrappedQR'>
|
|
||||||
<svg
|
|
||||||
xmlns='http://www.w3.org/2000/svg'
|
|
||||||
viewBox='-32 0 512 512'
|
|
||||||
width='1em'
|
|
||||||
height='1em'
|
|
||||||
fill='currentColor'
|
|
||||||
className='IBMSMSMSSS_Author_Top_Icon'
|
|
||||||
>
|
|
||||||
<path d='M144 32C170.5 32 192 53.49 192 80V176C192 202.5 170.5 224 144 224H48C21.49 224 0 202.5 0 176V80C0 53.49 21.49 32 48 32H144zM128 96H64V160H128V96zM144 288C170.5 288 192 309.5 192 336V432C192 458.5 170.5 480 144 480H48C21.49 480 0 458.5 0 432V336C0 309.5 21.49 288 48 288H144zM128 352H64V416H128V352zM256 80C256 53.49 277.5 32 304 32H400C426.5 32 448 53.49 448 80V176C448 202.5 426.5 224 400 224H304C277.5 224 256 202.5 256 176V80zM320 160H384V96H320V160zM352 448H384V480H352V448zM448 480H416V448H448V480zM416 288H448V416H352V384H320V480H256V288H352V320H416V288z'></path>
|
|
||||||
</svg>
|
|
||||||
</div>
|
|
||||||
<div className='IBMSMSMSSS_Author_Top_IconWrapped'>
|
|
||||||
<svg
|
|
||||||
xmlns='http://www.w3.org/2000/svg'
|
|
||||||
viewBox='-32 0 512 512'
|
|
||||||
width='1em'
|
|
||||||
height='1em'
|
|
||||||
fill='currentColor'
|
|
||||||
className='IBMSMSMSSS_Author_Top_Icon'
|
|
||||||
>
|
|
||||||
<path d='M240.5 224H352C365.3 224 377.3 232.3 381.1 244.7C386.6 257.2 383.1 271.3 373.1 280.1L117.1 504.1C105.8 513.9 89.27 514.7 77.19 505.9C65.1 497.1 60.7 481.1 66.59 467.4L143.5 288H31.1C18.67 288 6.733 279.7 2.044 267.3C-2.645 254.8 .8944 240.7 10.93 231.9L266.9 7.918C278.2-1.92 294.7-2.669 306.8 6.114C318.9 14.9 323.3 30.87 317.4 44.61L240.5 224z'></path>
|
|
||||||
</svg>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className='IBMSMSMSSS_Author_Top_Details'>
|
|
||||||
<p className='IBMSMSMSSS_Author_Top_Bio'>
|
|
||||||
user bio, this is a long string of temporary text that would
|
|
||||||
be replaced with the user bio from their metada address
|
|
||||||
</p>
|
|
||||||
<div
|
|
||||||
id='OwnerFollowLogin-1'
|
|
||||||
className='IBMSMSMSSS_Author_Top_NostrLinks'
|
|
||||||
style={{ display: 'flex' }}
|
|
||||||
></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className='IBMSMSMBSS_ProfileEdit'>
|
|
||||||
<InputField
|
|
||||||
label='Name'
|
|
||||||
placeholder=''
|
|
||||||
name='name'
|
|
||||||
value=''
|
|
||||||
onChange={() => {}}
|
|
||||||
/>
|
|
||||||
<InputField
|
|
||||||
label='Bio'
|
|
||||||
placeholder=''
|
|
||||||
name='bio'
|
|
||||||
type='textarea'
|
|
||||||
value=''
|
|
||||||
onChange={() => {}}
|
|
||||||
/>
|
|
||||||
<InputField
|
|
||||||
label='Profile picture URL'
|
|
||||||
placeholder=''
|
|
||||||
name='profilePicture'
|
|
||||||
inputMode='url'
|
|
||||||
value=''
|
|
||||||
onChange={() => {}}
|
|
||||||
/>
|
|
||||||
<InputField
|
|
||||||
label='Banner picture URL'
|
|
||||||
placeholder=''
|
|
||||||
name='bannerPicture'
|
|
||||||
inputMode='url'
|
|
||||||
value=''
|
|
||||||
onChange={() => {}}
|
|
||||||
/>
|
|
||||||
<InputField
|
|
||||||
label='Nip-05 address'
|
|
||||||
placeholder=''
|
|
||||||
name='nip05'
|
|
||||||
value=''
|
|
||||||
onChange={() => {}}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
className='IBMSMSMBSS_ProfileActions'
|
|
||||||
style={{ padding: 'unset', border: 'unset', justifyContent: 'end' }}
|
|
||||||
>
|
|
||||||
<button className='btn btnMain' type='button'>
|
|
||||||
Publish Changes
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
const RelaySettings = () => {
|
|
||||||
return (
|
|
||||||
<div className='IBMSMSplitMainFullSideFWMid'>
|
|
||||||
<div className='IBMSMSplitMainFullSideSec'>
|
|
||||||
<div className='relayList'>
|
|
||||||
<div className='inputLabelWrapperMain'>
|
|
||||||
<label className='form-label labelMain'>Your relays</label>
|
|
||||||
</div>
|
|
||||||
{usersRelays.map((relay, index) => (
|
|
||||||
<RelayListItem key={index} item={relay} isOwnRelay />
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className='IBMSMSplitMainFullSideSec'>
|
|
||||||
<InputField
|
|
||||||
label='Add Relays'
|
|
||||||
placeholder='wss://some-relay.com'
|
|
||||||
type='text'
|
|
||||||
name='relay'
|
|
||||||
value=''
|
|
||||||
onChange={() => {}}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<button className='btn btnMain' type='button'>
|
|
||||||
Add
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className='IBMSMSplitMainFullSideSec'>
|
|
||||||
<div className='inputLabelWrapperMain'>
|
|
||||||
<label className='form-label labelMain'>DEG Mods Relays</label>
|
|
||||||
<p className='labelDescriptionMain'>
|
|
||||||
We recommend adding one of our relays if you're planning to
|
|
||||||
frequently use DEG Mods, for a better experience.
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
<div className='relayList'>
|
|
||||||
{degmodsRelays.map((relay, index) => (
|
|
||||||
<RelayListItem key={index} item={relay} />
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className='IBMSMSplitMainFullSideSec'>
|
|
||||||
<div className='inputLabelWrapperMain'>
|
|
||||||
<label className='form-label labelMain'>Recommended Relays</label>
|
|
||||||
<p className='labelDescriptionMain'>
|
|
||||||
Relays we recommend using as they support the same functionalities
|
|
||||||
that our relays provide.
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
<div className='relayList'>
|
|
||||||
{recommendRelays.map((relay, index) => (
|
|
||||||
<RelayListItem key={index} item={relay} />
|
|
||||||
))}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
const RelayListItem = ({
|
|
||||||
item,
|
|
||||||
isOwnRelay
|
|
||||||
}: {
|
|
||||||
item: RelayItem
|
|
||||||
isOwnRelay?: boolean
|
|
||||||
}) => {
|
|
||||||
return (
|
|
||||||
<div className='relayListItem'>
|
|
||||||
<div className='relayListItemSec relayListItemSecPic'>
|
|
||||||
<div
|
|
||||||
className='relayListItemSecPicImg'
|
|
||||||
style={{
|
|
||||||
background: item.backgroundColor
|
|
||||||
}}
|
|
||||||
></div>
|
|
||||||
</div>
|
|
||||||
<div className='relayListItemSec relayListItemSecDetails'>
|
|
||||||
<p className='relayListItemSecDetailsText'>{item.url}</p>
|
|
||||||
<div className='relayListItemSecDetailsExtra'>
|
|
||||||
<svg
|
|
||||||
xmlns='http://www.w3.org/2000/svg'
|
|
||||||
viewBox='-64 0 512 512'
|
|
||||||
width='1em'
|
|
||||||
height='1em'
|
|
||||||
fill='currentColor'
|
|
||||||
data-bs-toggle='tooltip'
|
|
||||||
data-bss-tooltip
|
|
||||||
aria-label={item.readTitle}
|
|
||||||
>
|
|
||||||
<path d='M0 64C0 28.65 28.65 0 64 0H224V128C224 145.7 238.3 160 256 160H384V448C384 483.3 355.3 512 320 512H64C28.65 512 0 483.3 0 448V64zM256 128V0L384 128H256z'></path>
|
|
||||||
</svg>
|
|
||||||
<svg
|
|
||||||
xmlns='http://www.w3.org/2000/svg'
|
|
||||||
viewBox='0 -32 576 576'
|
|
||||||
width='1em'
|
|
||||||
height='1em'
|
|
||||||
fill='currentColor'
|
|
||||||
data-bs-toggle='tooltip'
|
|
||||||
data-bss-tooltip
|
|
||||||
aria-label={item.writeTitle}
|
|
||||||
>
|
|
||||||
<path d='M0 64C0 28.65 28.65 0 64 0H224V128C224 145.7 238.3 160 256 160H384V299.6L289.3 394.3C281.1 402.5 275.3 412.8 272.5 424.1L257.4 484.2C255.1 493.6 255.7 503.2 258.8 512H64C28.65 512 0 483.3 0 448V64zM256 128V0L384 128H256zM564.1 250.1C579.8 265.7 579.8 291 564.1 306.7L534.7 336.1L463.8 265.1L493.2 235.7C508.8 220.1 534.1 220.1 549.8 235.7L564.1 250.1zM311.9 416.1L441.1 287.8L512.1 358.7L382.9 487.9C378.8 492 373.6 494.9 368 496.3L307.9 511.4C302.4 512.7 296.7 511.1 292.7 507.2C288.7 503.2 287.1 497.4 288.5 491.1L303.5 431.8C304.9 426.2 307.8 421.1 311.9 416.1V416.1z'></path>
|
|
||||||
</svg>
|
|
||||||
{item.subscribedTitle && (
|
|
||||||
<svg
|
|
||||||
xmlns='http://www.w3.org/2000/svg'
|
|
||||||
viewBox='0 0 512 512'
|
|
||||||
width='1em'
|
|
||||||
height='1em'
|
|
||||||
fill='currentColor'
|
|
||||||
data-bs-toggle='tooltip'
|
|
||||||
data-bss-tooltip
|
|
||||||
aria-label={item.subscribedTitle}
|
|
||||||
>
|
|
||||||
<path d='M504 256c0 136.967-111.033 248-248 248S8 392.967 8 256 119.033 8 256 8s248 111.033 248 248zm-141.651-35.33c4.937-32.999-20.191-50.739-54.55-62.573l11.146-44.702-27.213-6.781-10.851 43.524c-7.154-1.783-14.502-3.464-21.803-5.13l10.929-43.81-27.198-6.781-11.153 44.686c-5.922-1.349-11.735-2.682-17.377-4.084l.031-.14-37.53-9.37-7.239 29.062s20.191 4.627 19.765 4.913c11.022 2.751 13.014 10.044 12.68 15.825l-12.696 50.925c.76.194 1.744.473 2.829.907-.907-.225-1.876-.473-2.876-.713l-17.796 71.338c-1.349 3.348-4.767 8.37-12.471 6.464.271.395-19.78-4.937-19.78-4.937l-13.51 31.147 35.414 8.827c6.588 1.651 13.045 3.379 19.4 5.006l-11.262 45.213 27.182 6.781 11.153-44.733a1038.209 1038.209 0 0 0 21.687 5.627l-11.115 44.523 27.213 6.781 11.262-45.128c46.404 8.781 81.299 5.239 95.986-36.727 11.836-33.79-.589-53.281-25.004-65.991 17.78-4.098 31.174-15.792 34.747-39.949zm-62.177 87.179c-8.41 33.79-65.308 15.523-83.755 10.943l14.944-59.899c18.446 4.603 77.6 13.717 68.811 48.956zm8.417-87.667c-7.673 30.736-55.031 15.12-70.393 11.292l13.548-54.327c15.363 3.828 64.836 10.973 56.845 43.035z'></path>
|
|
||||||
</svg>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className='relayListItemSec relayListItemSecActions'>
|
|
||||||
{isOwnRelay && (
|
|
||||||
<div
|
|
||||||
className='dropstart dropdownMain'
|
|
||||||
style={{ position: 'absolute' }}
|
|
||||||
>
|
|
||||||
<button
|
|
||||||
className='btn btnMain'
|
|
||||||
aria-expanded='false'
|
|
||||||
data-bs-toggle='dropdown'
|
|
||||||
type='button'
|
|
||||||
>
|
|
||||||
<svg
|
|
||||||
xmlns='http://www.w3.org/2000/svg'
|
|
||||||
viewBox='-192 0 512 512'
|
|
||||||
width='1em'
|
|
||||||
height='1em'
|
|
||||||
fill='currentColor'
|
|
||||||
>
|
|
||||||
<path d='M64 360C94.93 360 120 385.1 120 416C120 446.9 94.93 472 64 472C33.07 472 8 446.9 8 416C8 385.1 33.07 360 64 360zM64 200C94.93 200 120 225.1 120 256C120 286.9 94.93 312 64 312C33.07 312 8 286.9 8 256C8 225.1 33.07 200 64 200zM64 152C33.07 152 8 126.9 8 96C8 65.07 33.07 40 64 40C94.93 40 120 65.07 120 96C120 126.9 94.93 152 64 152z'></path>
|
|
||||||
</svg>
|
|
||||||
</button>
|
|
||||||
<div
|
|
||||||
className='dropdown-menu dropdownMainMenu'
|
|
||||||
style={{ position: 'absolute' }}
|
|
||||||
>
|
|
||||||
<a className='dropdown-item dropdownMainMenuItem' href='#'>
|
|
||||||
Remove
|
|
||||||
</a>
|
|
||||||
<a className='dropdown-item dropdownMainMenuItem' href='#'>
|
|
||||||
Details
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
{!isOwnRelay && (
|
|
||||||
<button className='btn btnMain' type='button'>
|
|
||||||
<svg
|
|
||||||
xmlns='http://www.w3.org/2000/svg'
|
|
||||||
viewBox='-32 0 512 512'
|
|
||||||
width='1em'
|
|
||||||
height='1em'
|
|
||||||
fill='currentColor'
|
|
||||||
>
|
|
||||||
<path d='M432 256c0 17.69-14.33 32.01-32 32.01H256v144c0 17.69-14.33 31.99-32 31.99s-32-14.3-32-31.99v-144H48c-17.67 0-32-14.32-32-32.01s14.33-31.99 32-31.99H192v-144c0-17.69 14.33-32.01 32-32.01s32 14.32 32 32.01v144h144C417.7 224 432 238.3 432 256z'></path>
|
|
||||||
</svg>
|
|
||||||
</button>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
// todo: use components from Input.tsx
|
|
||||||
const PreferencesSetting = () => {
|
|
||||||
return (
|
|
||||||
<div className='IBMSMSplitMainFullSideFWMid'>
|
|
||||||
<div className='IBMSMSplitMainFullSideSec'>
|
|
||||||
<div className='IBMSMSMBS_Write'>
|
|
||||||
<div className='inputLabelWrapperMain'>
|
|
||||||
<div className='labelWrapperMain'>
|
|
||||||
<p className='labelMain'>Notifications</p>
|
|
||||||
</div>
|
|
||||||
<div className='inputLabelWrapperMain inputLabelWrapperMainAlt inputLabelWrapperMainAltStylized'>
|
|
||||||
<label className='form-label labelMain'>
|
|
||||||
When someone follows you
|
|
||||||
</label>
|
|
||||||
<input
|
|
||||||
type='checkbox'
|
|
||||||
className='CheckboxMain'
|
|
||||||
name='notificationsSettings'
|
|
||||||
checked
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div className='inputLabelWrapperMain inputLabelWrapperMainAlt inputLabelWrapperMainAltStylized'>
|
|
||||||
<label className='form-label labelMain'>
|
|
||||||
When someone mentions you
|
|
||||||
</label>
|
|
||||||
<input
|
|
||||||
type='checkbox'
|
|
||||||
className='CheckboxMain'
|
|
||||||
name='notificationsSettings'
|
|
||||||
checked
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div className='inputLabelWrapperMain inputLabelWrapperMainAlt inputLabelWrapperMainAltStylized'>
|
|
||||||
<label className='form-label labelMain'>
|
|
||||||
When someone sends a reaction to your post
|
|
||||||
</label>
|
|
||||||
<input
|
|
||||||
type='checkbox'
|
|
||||||
className='CheckboxMain'
|
|
||||||
name='notificationsSettings'
|
|
||||||
checked
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div className='inputLabelWrapperMain inputLabelWrapperMainAlt inputLabelWrapperMainAltStylized'>
|
|
||||||
<label className='form-label labelMain'>
|
|
||||||
When someone Tips/Zaps you
|
|
||||||
</label>
|
|
||||||
<input
|
|
||||||
type='checkbox'
|
|
||||||
className='CheckboxMain'
|
|
||||||
name='notificationsSettings'
|
|
||||||
checked
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<div className='inputLabelWrapperMain inputLabelWrapperMainAlt inputLabelWrapperMainAltStylized'>
|
|
||||||
<label className='form-label labelMain'>
|
|
||||||
When someone re-posts your post
|
|
||||||
</label>
|
|
||||||
<input
|
|
||||||
type='checkbox'
|
|
||||||
className='CheckboxMain'
|
|
||||||
name='notificationsSettings'
|
|
||||||
checked
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className='inputLabelWrapperMain'>
|
|
||||||
<div className='labelWrapperMain'>
|
|
||||||
<p className='labelMain'>Not Safe For Work (NSFW)</p>
|
|
||||||
</div>
|
|
||||||
<div className='inputLabelWrapperMain inputLabelWrapperMainAlt inputLabelWrapperMainAltStylized'>
|
|
||||||
<label className='form-label labelMain'>
|
|
||||||
Show all NSFW posts
|
|
||||||
</label>
|
|
||||||
<input
|
|
||||||
type='checkbox'
|
|
||||||
className='CheckboxMain'
|
|
||||||
name='NSFWPreference'
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className='inputLabelWrapperMain'>
|
|
||||||
<div className='labelWrapperMain'>
|
|
||||||
<p className='labelMain'>Web of Trust (WoT) level</p>
|
|
||||||
</div>
|
|
||||||
<p className='labelDescriptionMain'>
|
|
||||||
This affects what posts you see, reactions, DMs, and
|
|
||||||
notifications. Learn more: Link
|
|
||||||
</p>
|
|
||||||
<div className='inputLabelWrapperMainSliderWrapper'>
|
|
||||||
<input
|
|
||||||
className='form-range inputRangeMain inputRangeMainZap'
|
|
||||||
type='range'
|
|
||||||
max='100'
|
|
||||||
min='0'
|
|
||||||
value='10'
|
|
||||||
step='1'
|
|
||||||
required
|
|
||||||
name='WoTLevel'
|
|
||||||
/>
|
|
||||||
<p className='ZapSplitUserBoxRangeText'>10</p>
|
|
||||||
</div>
|
|
||||||
<div className='inputLabelWrapperMain inputLabelWrapperMainAlt inputLabelWrapperMainAltStylized'>
|
|
||||||
<label className='form-label labelMain'>
|
|
||||||
Consider those who zap/tip, regardless of WoT level
|
|
||||||
</label>
|
|
||||||
<input
|
|
||||||
type='checkbox'
|
|
||||||
className='CheckboxMain'
|
|
||||||
name='WoTZap'
|
|
||||||
checked
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className='IBMSMSMBS_WriteAction'>
|
|
||||||
<button className='btn btnMain' type='button'>
|
|
||||||
Save
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
// todo: use components from Input.tsx
|
|
||||||
const AdminSetting = () => {
|
|
||||||
return (
|
|
||||||
<div className='IBMSMSplitMainFullSideFWMid'>
|
|
||||||
<div className='IBMSMSplitMainFullSideSec'>
|
|
||||||
<div className='IBMSMSMBS_Write'>
|
|
||||||
<div className='inputLabelWrapperMain'>
|
|
||||||
<div className='labelWrapperMain'>
|
|
||||||
<p className='labelMain'>Slider Featured Mods</p>
|
|
||||||
<button className='btn btnMain btnMainAdd' type='button'>
|
|
||||||
<svg
|
|
||||||
xmlns='http://www.w3.org/2000/svg'
|
|
||||||
viewBox='-32 0 512 512'
|
|
||||||
width='1em'
|
|
||||||
height='1em'
|
|
||||||
fill='currentColor'
|
|
||||||
>
|
|
||||||
<path d='M432 256c0 17.69-14.33 32.01-32 32.01H256v144c0 17.69-14.33 31.99-32 31.99s-32-14.3-32-31.99v-144H48c-17.67 0-32-14.32-32-32.01s14.33-31.99 32-31.99H192v-144c0-17.69 14.33-32.01 32-32.01s32 14.32 32 32.01v144h144C417.7 224 432 238.3 432 256z'></path>
|
|
||||||
</svg>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
<div className='inputWrapperMain'>
|
|
||||||
<input
|
|
||||||
type='text'
|
|
||||||
className='inputMain'
|
|
||||||
inputMode='url'
|
|
||||||
placeholder='Note ID'
|
|
||||||
/>
|
|
||||||
<button className='btn btnMain btnMainRemove' type='button'>
|
|
||||||
<svg
|
|
||||||
xmlns='http://www.w3.org/2000/svg'
|
|
||||||
viewBox='-32 0 512 512'
|
|
||||||
width='1em'
|
|
||||||
height='1em'
|
|
||||||
fill='currentColor'
|
|
||||||
>
|
|
||||||
<path d='M135.2 17.69C140.6 6.848 151.7 0 163.8 0H284.2C296.3 0 307.4 6.848 312.8 17.69L320 32H416C433.7 32 448 46.33 448 64C448 81.67 433.7 96 416 96H32C14.33 96 0 81.67 0 64C0 46.33 14.33 32 32 32H128L135.2 17.69zM394.8 466.1C393.2 492.3 372.3 512 346.9 512H101.1C75.75 512 54.77 492.3 53.19 466.1L31.1 128H416L394.8 466.1z'></path>
|
|
||||||
</svg>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
<div className='inputWrapperMain'>
|
|
||||||
<input
|
|
||||||
type='text'
|
|
||||||
className='inputMain'
|
|
||||||
inputMode='url'
|
|
||||||
placeholder='Note ID'
|
|
||||||
/>
|
|
||||||
<button className='btn btnMain btnMainRemove' type='button'>
|
|
||||||
<svg
|
|
||||||
xmlns='http://www.w3.org/2000/svg'
|
|
||||||
viewBox='-32 0 512 512'
|
|
||||||
width='1em'
|
|
||||||
height='1em'
|
|
||||||
fill='currentColor'
|
|
||||||
>
|
|
||||||
<path d='M135.2 17.69C140.6 6.848 151.7 0 163.8 0H284.2C296.3 0 307.4 6.848 312.8 17.69L320 32H416C433.7 32 448 46.33 448 64C448 81.67 433.7 96 416 96H32C14.33 96 0 81.67 0 64C0 46.33 14.33 32 32 32H128L135.2 17.69zM394.8 466.1C393.2 492.3 372.3 512 346.9 512H101.1C75.75 512 54.77 492.3 53.19 466.1L31.1 128H416L394.8 466.1z'></path>
|
|
||||||
</svg>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className='inputLabelWrapperMain'>
|
|
||||||
<div className='labelWrapperMain'>
|
|
||||||
<p className='labelMain'>Featured Games</p>
|
|
||||||
<button className='btn btnMain btnMainAdd' type='button'>
|
|
||||||
<svg
|
|
||||||
xmlns='http://www.w3.org/2000/svg'
|
|
||||||
viewBox='-32 0 512 512'
|
|
||||||
width='1em'
|
|
||||||
height='1em'
|
|
||||||
fill='currentColor'
|
|
||||||
>
|
|
||||||
<path d='M432 256c0 17.69-14.33 32.01-32 32.01H256v144c0 17.69-14.33 31.99-32 31.99s-32-14.3-32-31.99v-144H48c-17.67 0-32-14.32-32-32.01s14.33-31.99 32-31.99H192v-144c0-17.69 14.33-32.01 32-32.01s32 14.32 32 32.01v144h144C417.7 224 432 238.3 432 256z'></path>
|
|
||||||
</svg>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
<div className='inputWrapperMain'>
|
|
||||||
<input
|
|
||||||
type='text'
|
|
||||||
className='inputMain'
|
|
||||||
inputMode='url'
|
|
||||||
placeholder='Game name'
|
|
||||||
value='Witcher 3: Wild Hunt'
|
|
||||||
/>
|
|
||||||
<button className='btn btnMain btnMainRemove' type='button'>
|
|
||||||
<svg
|
|
||||||
xmlns='http://www.w3.org/2000/svg'
|
|
||||||
viewBox='-32 0 512 512'
|
|
||||||
width='1em'
|
|
||||||
height='1em'
|
|
||||||
fill='currentColor'
|
|
||||||
>
|
|
||||||
<path d='M135.2 17.69C140.6 6.848 151.7 0 163.8 0H284.2C296.3 0 307.4 6.848 312.8 17.69L320 32H416C433.7 32 448 46.33 448 64C448 81.67 433.7 96 416 96H32C14.33 96 0 81.67 0 64C0 46.33 14.33 32 32 32H128L135.2 17.69zM394.8 466.1C393.2 492.3 372.3 512 346.9 512H101.1C75.75 512 54.77 492.3 53.19 466.1L31.1 128H416L394.8 466.1z'></path>
|
|
||||||
</svg>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
<div className='inputWrapperMain'>
|
|
||||||
<input
|
|
||||||
type='text'
|
|
||||||
className='inputMain'
|
|
||||||
inputMode='url'
|
|
||||||
placeholder='Game name'
|
|
||||||
/>
|
|
||||||
<button className='btn btnMain btnMainRemove' type='button'>
|
|
||||||
<svg
|
|
||||||
xmlns='http://www.w3.org/2000/svg'
|
|
||||||
viewBox='-32 0 512 512'
|
|
||||||
width='1em'
|
|
||||||
height='1em'
|
|
||||||
fill='currentColor'
|
|
||||||
>
|
|
||||||
<path d='M135.2 17.69C140.6 6.848 151.7 0 163.8 0H284.2C296.3 0 307.4 6.848 312.8 17.69L320 32H416C433.7 32 448 46.33 448 64C448 81.67 433.7 96 416 96H32C14.33 96 0 81.67 0 64C0 46.33 14.33 32 32 32H128L135.2 17.69zM394.8 466.1C393.2 492.3 372.3 512 346.9 512H101.1C75.75 512 54.77 492.3 53.19 466.1L31.1 128H416L394.8 466.1z'></path>
|
|
||||||
</svg>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className='inputLabelWrapperMain'>
|
|
||||||
<div className='labelWrapperMain'>
|
|
||||||
<p className='labelMain'>Featured Mods</p>
|
|
||||||
<button className='btn btnMain btnMainAdd' type='button'>
|
|
||||||
<svg
|
|
||||||
xmlns='http://www.w3.org/2000/svg'
|
|
||||||
viewBox='-32 0 512 512'
|
|
||||||
width='1em'
|
|
||||||
height='1em'
|
|
||||||
fill='currentColor'
|
|
||||||
>
|
|
||||||
<path d='M432 256c0 17.69-14.33 32.01-32 32.01H256v144c0 17.69-14.33 31.99-32 31.99s-32-14.3-32-31.99v-144H48c-17.67 0-32-14.32-32-32.01s14.33-31.99 32-31.99H192v-144c0-17.69 14.33-32.01 32-32.01s32 14.32 32 32.01v144h144C417.7 224 432 238.3 432 256z'></path>
|
|
||||||
</svg>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
<div className='inputWrapperMain'>
|
|
||||||
<input
|
|
||||||
type='text'
|
|
||||||
className='inputMain'
|
|
||||||
inputMode='url'
|
|
||||||
placeholder='Note ID'
|
|
||||||
/>
|
|
||||||
<button className='btn btnMain btnMainRemove' type='button'>
|
|
||||||
<svg
|
|
||||||
xmlns='http://www.w3.org/2000/svg'
|
|
||||||
viewBox='-32 0 512 512'
|
|
||||||
width='1em'
|
|
||||||
height='1em'
|
|
||||||
fill='currentColor'
|
|
||||||
>
|
|
||||||
<path d='M135.2 17.69C140.6 6.848 151.7 0 163.8 0H284.2C296.3 0 307.4 6.848 312.8 17.69L320 32H416C433.7 32 448 46.33 448 64C448 81.67 433.7 96 416 96H32C14.33 96 0 81.67 0 64C0 46.33 14.33 32 32 32H128L135.2 17.69zM394.8 466.1C393.2 492.3 372.3 512 346.9 512H101.1C75.75 512 54.77 492.3 53.19 466.1L31.1 128H416L394.8 466.1z'></path>
|
|
||||||
</svg>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
<div className='inputWrapperMain'>
|
|
||||||
<input
|
|
||||||
type='text'
|
|
||||||
className='inputMain'
|
|
||||||
inputMode='url'
|
|
||||||
placeholder='Note ID'
|
|
||||||
/>
|
|
||||||
<button className='btn btnMain btnMainRemove' type='button'>
|
|
||||||
<svg
|
|
||||||
xmlns='http://www.w3.org/2000/svg'
|
|
||||||
viewBox='-32 0 512 512'
|
|
||||||
width='1em'
|
|
||||||
height='1em'
|
|
||||||
fill='currentColor'
|
|
||||||
>
|
|
||||||
<path d='M135.2 17.69C140.6 6.848 151.7 0 163.8 0H284.2C296.3 0 307.4 6.848 312.8 17.69L320 32H416C433.7 32 448 46.33 448 64C448 81.67 433.7 96 416 96H32C14.33 96 0 81.67 0 64C0 46.33 14.33 32 32 32H128L135.2 17.69zM394.8 466.1C393.2 492.3 372.3 512 346.9 512H101.1C75.75 512 54.77 492.3 53.19 466.1L31.1 128H416L394.8 466.1z'></path>
|
|
||||||
</svg>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className='inputLabelWrapperMain'>
|
|
||||||
<div className='labelWrapperMain'>
|
|
||||||
<p className='labelMain'>Blog writers</p>
|
|
||||||
<button className='btn btnMain btnMainAdd' type='button'>
|
|
||||||
<svg
|
|
||||||
xmlns='http://www.w3.org/2000/svg'
|
|
||||||
viewBox='-32 0 512 512'
|
|
||||||
width='1em'
|
|
||||||
height='1em'
|
|
||||||
fill='currentColor'
|
|
||||||
>
|
|
||||||
<path d='M432 256c0 17.69-14.33 32.01-32 32.01H256v144c0 17.69-14.33 31.99-32 31.99s-32-14.3-32-31.99v-144H48c-17.67 0-32-14.32-32-32.01s14.33-31.99 32-31.99H192v-144c0-17.69 14.33-32.01 32-32.01s32 14.32 32 32.01v144h144C417.7 224 432 238.3 432 256z'></path>
|
|
||||||
</svg>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
<div className='inputWrapperMain'>
|
|
||||||
<input
|
|
||||||
type='text'
|
|
||||||
className='inputMain'
|
|
||||||
inputMode='url'
|
|
||||||
placeholder='nPubs'
|
|
||||||
value='npub18n4ysp43ux5c98fs6h9c57qpr4p8r3j8f6e32v0vj8egzy878aqqyzzk9r'
|
|
||||||
/>
|
|
||||||
<button className='btn btnMain btnMainRemove' type='button'>
|
|
||||||
<svg
|
|
||||||
xmlns='http://www.w3.org/2000/svg'
|
|
||||||
viewBox='-32 0 512 512'
|
|
||||||
width='1em'
|
|
||||||
height='1em'
|
|
||||||
fill='currentColor'
|
|
||||||
>
|
|
||||||
<path d='M135.2 17.69C140.6 6.848 151.7 0 163.8 0H284.2C296.3 0 307.4 6.848 312.8 17.69L320 32H416C433.7 32 448 46.33 448 64C448 81.67 433.7 96 416 96H32C14.33 96 0 81.67 0 64C0 46.33 14.33 32 32 32H128L135.2 17.69zM394.8 466.1C393.2 492.3 372.3 512 346.9 512H101.1C75.75 512 54.77 492.3 53.19 466.1L31.1 128H416L394.8 466.1z'></path>
|
|
||||||
</svg>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
<div className='inputWrapperMain'>
|
|
||||||
<input
|
|
||||||
type='text'
|
|
||||||
className='inputMain'
|
|
||||||
inputMode='url'
|
|
||||||
placeholder='nPubs'
|
|
||||||
/>
|
|
||||||
<button className='btn btnMain btnMainRemove' type='button'>
|
|
||||||
<svg
|
|
||||||
xmlns='http://www.w3.org/2000/svg'
|
|
||||||
viewBox='-32 0 512 512'
|
|
||||||
width='1em'
|
|
||||||
height='1em'
|
|
||||||
fill='currentColor'
|
|
||||||
>
|
|
||||||
<path d='M135.2 17.69C140.6 6.848 151.7 0 163.8 0H284.2C296.3 0 307.4 6.848 312.8 17.69L320 32H416C433.7 32 448 46.33 448 64C448 81.67 433.7 96 416 96H32C14.33 96 0 81.67 0 64C0 46.33 14.33 32 32 32H128L135.2 17.69zM394.8 466.1C393.2 492.3 372.3 512 346.9 512H101.1C75.75 512 54.77 492.3 53.19 466.1L31.1 128H416L394.8 466.1z'></path>
|
|
||||||
</svg>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className='IBMSMSMBS_WriteAction'>
|
|
||||||
<button className='btn btnMain' type='button'>
|
|
||||||
Save
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
interface RelayItem {
|
|
||||||
url: string
|
|
||||||
backgroundColor: string
|
|
||||||
readTitle: string
|
|
||||||
writeTitle: string
|
|
||||||
subscribedTitle: string
|
|
||||||
}
|
|
||||||
|
|
||||||
const usersRelays: RelayItem[] = [
|
|
||||||
{
|
|
||||||
url: 'wss://relay.wibblywobbly.com',
|
|
||||||
backgroundColor: '#cd4d45',
|
|
||||||
readTitle: 'Read',
|
|
||||||
writeTitle: 'Write',
|
|
||||||
subscribedTitle: ''
|
|
||||||
},
|
|
||||||
{
|
|
||||||
url: 'wss://relay.wibblywobbly.com',
|
|
||||||
backgroundColor: '#60ae60',
|
|
||||||
readTitle: 'Read',
|
|
||||||
writeTitle: 'Write',
|
|
||||||
subscribedTitle: 'Paid (Subscribed)'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
url: 'wss://relay.degmods.com',
|
|
||||||
backgroundColor: '#60ae60',
|
|
||||||
readTitle: 'Read',
|
|
||||||
writeTitle: 'Write',
|
|
||||||
subscribedTitle: ''
|
|
||||||
}
|
|
||||||
]
|
|
||||||
|
|
||||||
const degmodsRelays: RelayItem[] = [
|
|
||||||
{
|
|
||||||
url: 'wss://relay1.degmods.com',
|
|
||||||
backgroundColor: '#60ae60',
|
|
||||||
readTitle: 'Read',
|
|
||||||
writeTitle: 'Write',
|
|
||||||
subscribedTitle: ''
|
|
||||||
},
|
|
||||||
{
|
|
||||||
url: 'wss://relay2.degmods.com',
|
|
||||||
backgroundColor: '#60ae60',
|
|
||||||
readTitle: 'Read',
|
|
||||||
writeTitle: 'Write',
|
|
||||||
subscribedTitle: ''
|
|
||||||
}
|
|
||||||
]
|
|
||||||
|
|
||||||
const recommendRelays: RelayItem[] = [
|
|
||||||
{
|
|
||||||
url: 'wss://relay1.degmods.com',
|
|
||||||
backgroundColor: '#60ae60',
|
|
||||||
readTitle: 'Read',
|
|
||||||
writeTitle: 'Write',
|
|
||||||
subscribedTitle: ''
|
|
||||||
},
|
|
||||||
{
|
|
||||||
url: 'wss://relay2.degmods.com',
|
|
||||||
backgroundColor: '#60ae60',
|
|
||||||
readTitle: 'Read',
|
|
||||||
writeTitle: 'Write',
|
|
||||||
subscribedTitle: ''
|
|
||||||
}
|
|
||||||
]
|
|
234
src/pages/settings/admin.tsx
Normal file
234
src/pages/settings/admin.tsx
Normal file
@ -0,0 +1,234 @@
|
|||||||
|
// todo: use components from Input.tsx
|
||||||
|
export const AdminSetting = () => {
|
||||||
|
return (
|
||||||
|
<div className='IBMSMSplitMainFullSideFWMid'>
|
||||||
|
<div className='IBMSMSplitMainFullSideSec'>
|
||||||
|
<div className='IBMSMSMBS_Write'>
|
||||||
|
<div className='inputLabelWrapperMain'>
|
||||||
|
<div className='labelWrapperMain'>
|
||||||
|
<p className='labelMain'>Slider Featured Mods</p>
|
||||||
|
<button className='btn btnMain btnMainAdd' type='button'>
|
||||||
|
<svg
|
||||||
|
xmlns='http://www.w3.org/2000/svg'
|
||||||
|
viewBox='-32 0 512 512'
|
||||||
|
width='1em'
|
||||||
|
height='1em'
|
||||||
|
fill='currentColor'
|
||||||
|
>
|
||||||
|
<path d='M432 256c0 17.69-14.33 32.01-32 32.01H256v144c0 17.69-14.33 31.99-32 31.99s-32-14.3-32-31.99v-144H48c-17.67 0-32-14.32-32-32.01s14.33-31.99 32-31.99H192v-144c0-17.69 14.33-32.01 32-32.01s32 14.32 32 32.01v144h144C417.7 224 432 238.3 432 256z'></path>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div className='inputWrapperMain'>
|
||||||
|
<input
|
||||||
|
type='text'
|
||||||
|
className='inputMain'
|
||||||
|
inputMode='url'
|
||||||
|
placeholder='Note ID'
|
||||||
|
/>
|
||||||
|
<button className='btn btnMain btnMainRemove' type='button'>
|
||||||
|
<svg
|
||||||
|
xmlns='http://www.w3.org/2000/svg'
|
||||||
|
viewBox='-32 0 512 512'
|
||||||
|
width='1em'
|
||||||
|
height='1em'
|
||||||
|
fill='currentColor'
|
||||||
|
>
|
||||||
|
<path d='M135.2 17.69C140.6 6.848 151.7 0 163.8 0H284.2C296.3 0 307.4 6.848 312.8 17.69L320 32H416C433.7 32 448 46.33 448 64C448 81.67 433.7 96 416 96H32C14.33 96 0 81.67 0 64C0 46.33 14.33 32 32 32H128L135.2 17.69zM394.8 466.1C393.2 492.3 372.3 512 346.9 512H101.1C75.75 512 54.77 492.3 53.19 466.1L31.1 128H416L394.8 466.1z'></path>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div className='inputWrapperMain'>
|
||||||
|
<input
|
||||||
|
type='text'
|
||||||
|
className='inputMain'
|
||||||
|
inputMode='url'
|
||||||
|
placeholder='Note ID'
|
||||||
|
/>
|
||||||
|
<button className='btn btnMain btnMainRemove' type='button'>
|
||||||
|
<svg
|
||||||
|
xmlns='http://www.w3.org/2000/svg'
|
||||||
|
viewBox='-32 0 512 512'
|
||||||
|
width='1em'
|
||||||
|
height='1em'
|
||||||
|
fill='currentColor'
|
||||||
|
>
|
||||||
|
<path d='M135.2 17.69C140.6 6.848 151.7 0 163.8 0H284.2C296.3 0 307.4 6.848 312.8 17.69L320 32H416C433.7 32 448 46.33 448 64C448 81.67 433.7 96 416 96H32C14.33 96 0 81.67 0 64C0 46.33 14.33 32 32 32H128L135.2 17.69zM394.8 466.1C393.2 492.3 372.3 512 346.9 512H101.1C75.75 512 54.77 492.3 53.19 466.1L31.1 128H416L394.8 466.1z'></path>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className='inputLabelWrapperMain'>
|
||||||
|
<div className='labelWrapperMain'>
|
||||||
|
<p className='labelMain'>Featured Games</p>
|
||||||
|
<button className='btn btnMain btnMainAdd' type='button'>
|
||||||
|
<svg
|
||||||
|
xmlns='http://www.w3.org/2000/svg'
|
||||||
|
viewBox='-32 0 512 512'
|
||||||
|
width='1em'
|
||||||
|
height='1em'
|
||||||
|
fill='currentColor'
|
||||||
|
>
|
||||||
|
<path d='M432 256c0 17.69-14.33 32.01-32 32.01H256v144c0 17.69-14.33 31.99-32 31.99s-32-14.3-32-31.99v-144H48c-17.67 0-32-14.32-32-32.01s14.33-31.99 32-31.99H192v-144c0-17.69 14.33-32.01 32-32.01s32 14.32 32 32.01v144h144C417.7 224 432 238.3 432 256z'></path>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div className='inputWrapperMain'>
|
||||||
|
<input
|
||||||
|
type='text'
|
||||||
|
className='inputMain'
|
||||||
|
inputMode='url'
|
||||||
|
placeholder='Game name'
|
||||||
|
value='Witcher 3: Wild Hunt'
|
||||||
|
/>
|
||||||
|
<button className='btn btnMain btnMainRemove' type='button'>
|
||||||
|
<svg
|
||||||
|
xmlns='http://www.w3.org/2000/svg'
|
||||||
|
viewBox='-32 0 512 512'
|
||||||
|
width='1em'
|
||||||
|
height='1em'
|
||||||
|
fill='currentColor'
|
||||||
|
>
|
||||||
|
<path d='M135.2 17.69C140.6 6.848 151.7 0 163.8 0H284.2C296.3 0 307.4 6.848 312.8 17.69L320 32H416C433.7 32 448 46.33 448 64C448 81.67 433.7 96 416 96H32C14.33 96 0 81.67 0 64C0 46.33 14.33 32 32 32H128L135.2 17.69zM394.8 466.1C393.2 492.3 372.3 512 346.9 512H101.1C75.75 512 54.77 492.3 53.19 466.1L31.1 128H416L394.8 466.1z'></path>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div className='inputWrapperMain'>
|
||||||
|
<input
|
||||||
|
type='text'
|
||||||
|
className='inputMain'
|
||||||
|
inputMode='url'
|
||||||
|
placeholder='Game name'
|
||||||
|
/>
|
||||||
|
<button className='btn btnMain btnMainRemove' type='button'>
|
||||||
|
<svg
|
||||||
|
xmlns='http://www.w3.org/2000/svg'
|
||||||
|
viewBox='-32 0 512 512'
|
||||||
|
width='1em'
|
||||||
|
height='1em'
|
||||||
|
fill='currentColor'
|
||||||
|
>
|
||||||
|
<path d='M135.2 17.69C140.6 6.848 151.7 0 163.8 0H284.2C296.3 0 307.4 6.848 312.8 17.69L320 32H416C433.7 32 448 46.33 448 64C448 81.67 433.7 96 416 96H32C14.33 96 0 81.67 0 64C0 46.33 14.33 32 32 32H128L135.2 17.69zM394.8 466.1C393.2 492.3 372.3 512 346.9 512H101.1C75.75 512 54.77 492.3 53.19 466.1L31.1 128H416L394.8 466.1z'></path>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className='inputLabelWrapperMain'>
|
||||||
|
<div className='labelWrapperMain'>
|
||||||
|
<p className='labelMain'>Featured Mods</p>
|
||||||
|
<button className='btn btnMain btnMainAdd' type='button'>
|
||||||
|
<svg
|
||||||
|
xmlns='http://www.w3.org/2000/svg'
|
||||||
|
viewBox='-32 0 512 512'
|
||||||
|
width='1em'
|
||||||
|
height='1em'
|
||||||
|
fill='currentColor'
|
||||||
|
>
|
||||||
|
<path d='M432 256c0 17.69-14.33 32.01-32 32.01H256v144c0 17.69-14.33 31.99-32 31.99s-32-14.3-32-31.99v-144H48c-17.67 0-32-14.32-32-32.01s14.33-31.99 32-31.99H192v-144c0-17.69 14.33-32.01 32-32.01s32 14.32 32 32.01v144h144C417.7 224 432 238.3 432 256z'></path>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div className='inputWrapperMain'>
|
||||||
|
<input
|
||||||
|
type='text'
|
||||||
|
className='inputMain'
|
||||||
|
inputMode='url'
|
||||||
|
placeholder='Note ID'
|
||||||
|
/>
|
||||||
|
<button className='btn btnMain btnMainRemove' type='button'>
|
||||||
|
<svg
|
||||||
|
xmlns='http://www.w3.org/2000/svg'
|
||||||
|
viewBox='-32 0 512 512'
|
||||||
|
width='1em'
|
||||||
|
height='1em'
|
||||||
|
fill='currentColor'
|
||||||
|
>
|
||||||
|
<path d='M135.2 17.69C140.6 6.848 151.7 0 163.8 0H284.2C296.3 0 307.4 6.848 312.8 17.69L320 32H416C433.7 32 448 46.33 448 64C448 81.67 433.7 96 416 96H32C14.33 96 0 81.67 0 64C0 46.33 14.33 32 32 32H128L135.2 17.69zM394.8 466.1C393.2 492.3 372.3 512 346.9 512H101.1C75.75 512 54.77 492.3 53.19 466.1L31.1 128H416L394.8 466.1z'></path>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div className='inputWrapperMain'>
|
||||||
|
<input
|
||||||
|
type='text'
|
||||||
|
className='inputMain'
|
||||||
|
inputMode='url'
|
||||||
|
placeholder='Note ID'
|
||||||
|
/>
|
||||||
|
<button className='btn btnMain btnMainRemove' type='button'>
|
||||||
|
<svg
|
||||||
|
xmlns='http://www.w3.org/2000/svg'
|
||||||
|
viewBox='-32 0 512 512'
|
||||||
|
width='1em'
|
||||||
|
height='1em'
|
||||||
|
fill='currentColor'
|
||||||
|
>
|
||||||
|
<path d='M135.2 17.69C140.6 6.848 151.7 0 163.8 0H284.2C296.3 0 307.4 6.848 312.8 17.69L320 32H416C433.7 32 448 46.33 448 64C448 81.67 433.7 96 416 96H32C14.33 96 0 81.67 0 64C0 46.33 14.33 32 32 32H128L135.2 17.69zM394.8 466.1C393.2 492.3 372.3 512 346.9 512H101.1C75.75 512 54.77 492.3 53.19 466.1L31.1 128H416L394.8 466.1z'></path>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className='inputLabelWrapperMain'>
|
||||||
|
<div className='labelWrapperMain'>
|
||||||
|
<p className='labelMain'>Blog writers</p>
|
||||||
|
<button className='btn btnMain btnMainAdd' type='button'>
|
||||||
|
<svg
|
||||||
|
xmlns='http://www.w3.org/2000/svg'
|
||||||
|
viewBox='-32 0 512 512'
|
||||||
|
width='1em'
|
||||||
|
height='1em'
|
||||||
|
fill='currentColor'
|
||||||
|
>
|
||||||
|
<path d='M432 256c0 17.69-14.33 32.01-32 32.01H256v144c0 17.69-14.33 31.99-32 31.99s-32-14.3-32-31.99v-144H48c-17.67 0-32-14.32-32-32.01s14.33-31.99 32-31.99H192v-144c0-17.69 14.33-32.01 32-32.01s32 14.32 32 32.01v144h144C417.7 224 432 238.3 432 256z'></path>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div className='inputWrapperMain'>
|
||||||
|
<input
|
||||||
|
type='text'
|
||||||
|
className='inputMain'
|
||||||
|
inputMode='url'
|
||||||
|
placeholder='nPubs'
|
||||||
|
value='npub18n4ysp43ux5c98fs6h9c57qpr4p8r3j8f6e32v0vj8egzy878aqqyzzk9r'
|
||||||
|
/>
|
||||||
|
<button className='btn btnMain btnMainRemove' type='button'>
|
||||||
|
<svg
|
||||||
|
xmlns='http://www.w3.org/2000/svg'
|
||||||
|
viewBox='-32 0 512 512'
|
||||||
|
width='1em'
|
||||||
|
height='1em'
|
||||||
|
fill='currentColor'
|
||||||
|
>
|
||||||
|
<path d='M135.2 17.69C140.6 6.848 151.7 0 163.8 0H284.2C296.3 0 307.4 6.848 312.8 17.69L320 32H416C433.7 32 448 46.33 448 64C448 81.67 433.7 96 416 96H32C14.33 96 0 81.67 0 64C0 46.33 14.33 32 32 32H128L135.2 17.69zM394.8 466.1C393.2 492.3 372.3 512 346.9 512H101.1C75.75 512 54.77 492.3 53.19 466.1L31.1 128H416L394.8 466.1z'></path>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div className='inputWrapperMain'>
|
||||||
|
<input
|
||||||
|
type='text'
|
||||||
|
className='inputMain'
|
||||||
|
inputMode='url'
|
||||||
|
placeholder='nPubs'
|
||||||
|
/>
|
||||||
|
<button className='btn btnMain btnMainRemove' type='button'>
|
||||||
|
<svg
|
||||||
|
xmlns='http://www.w3.org/2000/svg'
|
||||||
|
viewBox='-32 0 512 512'
|
||||||
|
width='1em'
|
||||||
|
height='1em'
|
||||||
|
fill='currentColor'
|
||||||
|
>
|
||||||
|
<path d='M135.2 17.69C140.6 6.848 151.7 0 163.8 0H284.2C296.3 0 307.4 6.848 312.8 17.69L320 32H416C433.7 32 448 46.33 448 64C448 81.67 433.7 96 416 96H32C14.33 96 0 81.67 0 64C0 46.33 14.33 32 32 32H128L135.2 17.69zM394.8 466.1C393.2 492.3 372.3 512 346.9 512H101.1C75.75 512 54.77 492.3 53.19 466.1L31.1 128H416L394.8 466.1z'></path>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className='IBMSMSMBS_WriteAction'>
|
||||||
|
<button className='btn btnMain' type='button'>
|
||||||
|
Save
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
164
src/pages/settings/index.tsx
Normal file
164
src/pages/settings/index.tsx
Normal file
@ -0,0 +1,164 @@
|
|||||||
|
import { AdminSVG, PreferenceSVG, ProfileSVG, RelaySVG } from 'components/SVGs'
|
||||||
|
import { MetadataController } from 'controllers'
|
||||||
|
import { useAppSelector } from 'hooks'
|
||||||
|
import { logout } from 'nostr-login'
|
||||||
|
import { useEffect, useState } from 'react'
|
||||||
|
import { Link, useLocation } from 'react-router-dom'
|
||||||
|
import { toast } from 'react-toastify'
|
||||||
|
import { appRoutes } from 'routes'
|
||||||
|
import { AuthMethod } from 'store/reducers/user'
|
||||||
|
import { copyTextToClipboard } from 'utils'
|
||||||
|
import { ProfileSettings } from './profile'
|
||||||
|
import { RelaySettings } from './relay'
|
||||||
|
import { PreferencesSetting } from './preference'
|
||||||
|
import { AdminSetting } from './admin'
|
||||||
|
import { ProfileSection } from 'components/ProfileSection'
|
||||||
|
|
||||||
|
export const SettingsPage = () => {
|
||||||
|
const location = useLocation()
|
||||||
|
const userState = useAppSelector((state) => state.user)
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className='InnerBodyMain'>
|
||||||
|
<div className='ContainerMain'>
|
||||||
|
<div className='IBMSecMainGroup IBMSecMainGroupAlt'>
|
||||||
|
<div className='IBMSMSplitMain IBMSMSplitMainThree'>
|
||||||
|
<SettingTabs />
|
||||||
|
{location.pathname === appRoutes.settingsProfile && (
|
||||||
|
<ProfileSettings />
|
||||||
|
)}
|
||||||
|
{location.pathname === appRoutes.settingsRelays && (
|
||||||
|
<RelaySettings />
|
||||||
|
)}
|
||||||
|
{location.pathname === appRoutes.settingsPreferences && (
|
||||||
|
<PreferencesSetting />
|
||||||
|
)}
|
||||||
|
{location.pathname === appRoutes.settingsAdmin && <AdminSetting />}
|
||||||
|
{userState.auth && userState.user?.pubkey && (
|
||||||
|
<ProfileSection pubkey={userState.user.pubkey as string} />
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const SettingTabs = () => {
|
||||||
|
const location = useLocation()
|
||||||
|
const [isAdmin, setIsAdmin] = useState(false)
|
||||||
|
const userState = useAppSelector((state) => state.user)
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
MetadataController.getInstance().then((controller) => {
|
||||||
|
if (userState.auth && userState.user?.npub) {
|
||||||
|
setIsAdmin(
|
||||||
|
controller.adminNpubs.includes(userState.user.npub as string)
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
setIsAdmin(false)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}, [userState])
|
||||||
|
|
||||||
|
const handleSignOut = () => {
|
||||||
|
logout()
|
||||||
|
}
|
||||||
|
|
||||||
|
const navLinks = [
|
||||||
|
{ path: appRoutes.settingsProfile, label: 'Profile', icon: <ProfileSVG /> },
|
||||||
|
{ path: appRoutes.settingsRelays, label: 'Relays', icon: <RelaySVG /> },
|
||||||
|
{
|
||||||
|
path: appRoutes.settingsPreferences,
|
||||||
|
label: 'Preferences',
|
||||||
|
icon: <PreferenceSVG />
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
if (isAdmin) {
|
||||||
|
navLinks.push({
|
||||||
|
path: appRoutes.settingsAdmin,
|
||||||
|
label: 'Admin',
|
||||||
|
icon: <AdminSVG />
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const renderNavLink = (path: string, label: string, icon: JSX.Element) => (
|
||||||
|
<Link
|
||||||
|
key={path}
|
||||||
|
className={`btn btnMain btnMainAltText btnMainClear ${
|
||||||
|
location.pathname === path ? 'btnMainClearActive' : ''
|
||||||
|
}`}
|
||||||
|
role='button'
|
||||||
|
to={path}
|
||||||
|
>
|
||||||
|
{icon}
|
||||||
|
{label}
|
||||||
|
</Link>
|
||||||
|
)
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className='IBMSMSplitMainSmallSide'>
|
||||||
|
<div className='IBMSMSplitMainSmallSideSec'>
|
||||||
|
<div className='IBMSMSplitMainSmallSideSec'>
|
||||||
|
<h3 className='IBMSMSMSSS_Text'>Settings (WIP)</h3>
|
||||||
|
</div>
|
||||||
|
<div className='IBMSMSMSSS_Buttons'>
|
||||||
|
{navLinks.map(({ path, label, icon }) =>
|
||||||
|
renderNavLink(path, label, icon)
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{userState.auth &&
|
||||||
|
userState.auth.method === AuthMethod.Local &&
|
||||||
|
userState.auth.localNsec && (
|
||||||
|
<div className='inputLabelWrapperMain'>
|
||||||
|
<label className='form-label labelMain'>Your Private Key</label>
|
||||||
|
<p className='labelDescriptionMain'>
|
||||||
|
NOTICE: Make sure you save your private key (nsec) somewhere
|
||||||
|
safe.
|
||||||
|
</p>
|
||||||
|
<div className='inputWrapperMain'>
|
||||||
|
<input
|
||||||
|
type='password'
|
||||||
|
className='inputMain inputMainWithBtn'
|
||||||
|
value={userState.auth.localNsec}
|
||||||
|
/>
|
||||||
|
<button
|
||||||
|
className='btn btnMain btnMainInsideField'
|
||||||
|
type='button'
|
||||||
|
onClick={() => {
|
||||||
|
copyTextToClipboard(
|
||||||
|
userState.auth?.localNsec as string
|
||||||
|
).then((isCopied) => {
|
||||||
|
if (isCopied) toast.success('Nsec copied to clipboard!')
|
||||||
|
})
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
xmlns='http://www.w3.org/2000/svg'
|
||||||
|
viewBox='0 0 512 512'
|
||||||
|
width='1em'
|
||||||
|
height='1em'
|
||||||
|
fill='currentColor'
|
||||||
|
>
|
||||||
|
<use href='#copy-icon'></use>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<p className='labelDescriptionMain'>
|
||||||
|
WARNING: Do not sign-out without saving your nsec somewhere
|
||||||
|
safe. Otherwise, you'll lose access to your "account".
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{userState.auth && (
|
||||||
|
<button className='btn btnMain' type='button' onClick={handleSignOut}>
|
||||||
|
Sign out
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
124
src/pages/settings/preference.tsx
Normal file
124
src/pages/settings/preference.tsx
Normal file
@ -0,0 +1,124 @@
|
|||||||
|
// todo: use components from Input.tsx
|
||||||
|
export const PreferencesSetting = () => {
|
||||||
|
return (
|
||||||
|
<div className='IBMSMSplitMainFullSideFWMid'>
|
||||||
|
<div className='IBMSMSplitMainFullSideSec'>
|
||||||
|
<div className='IBMSMSMBS_Write'>
|
||||||
|
<div className='inputLabelWrapperMain'>
|
||||||
|
<div className='labelWrapperMain'>
|
||||||
|
<p className='labelMain'>Notifications</p>
|
||||||
|
</div>
|
||||||
|
<div className='inputLabelWrapperMain inputLabelWrapperMainAlt inputLabelWrapperMainAltStylized'>
|
||||||
|
<label className='form-label labelMain'>
|
||||||
|
When someone follows you
|
||||||
|
</label>
|
||||||
|
<input
|
||||||
|
type='checkbox'
|
||||||
|
className='CheckboxMain'
|
||||||
|
name='notificationsSettings'
|
||||||
|
checked
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className='inputLabelWrapperMain inputLabelWrapperMainAlt inputLabelWrapperMainAltStylized'>
|
||||||
|
<label className='form-label labelMain'>
|
||||||
|
When someone mentions you
|
||||||
|
</label>
|
||||||
|
<input
|
||||||
|
type='checkbox'
|
||||||
|
className='CheckboxMain'
|
||||||
|
name='notificationsSettings'
|
||||||
|
checked
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className='inputLabelWrapperMain inputLabelWrapperMainAlt inputLabelWrapperMainAltStylized'>
|
||||||
|
<label className='form-label labelMain'>
|
||||||
|
When someone sends a reaction to your post
|
||||||
|
</label>
|
||||||
|
<input
|
||||||
|
type='checkbox'
|
||||||
|
className='CheckboxMain'
|
||||||
|
name='notificationsSettings'
|
||||||
|
checked
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className='inputLabelWrapperMain inputLabelWrapperMainAlt inputLabelWrapperMainAltStylized'>
|
||||||
|
<label className='form-label labelMain'>
|
||||||
|
When someone Tips/Zaps you
|
||||||
|
</label>
|
||||||
|
<input
|
||||||
|
type='checkbox'
|
||||||
|
className='CheckboxMain'
|
||||||
|
name='notificationsSettings'
|
||||||
|
checked
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div className='inputLabelWrapperMain inputLabelWrapperMainAlt inputLabelWrapperMainAltStylized'>
|
||||||
|
<label className='form-label labelMain'>
|
||||||
|
When someone re-posts your post
|
||||||
|
</label>
|
||||||
|
<input
|
||||||
|
type='checkbox'
|
||||||
|
className='CheckboxMain'
|
||||||
|
name='notificationsSettings'
|
||||||
|
checked
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className='inputLabelWrapperMain'>
|
||||||
|
<div className='labelWrapperMain'>
|
||||||
|
<p className='labelMain'>Not Safe For Work (NSFW)</p>
|
||||||
|
</div>
|
||||||
|
<div className='inputLabelWrapperMain inputLabelWrapperMainAlt inputLabelWrapperMainAltStylized'>
|
||||||
|
<label className='form-label labelMain'>
|
||||||
|
Show all NSFW posts
|
||||||
|
</label>
|
||||||
|
<input
|
||||||
|
type='checkbox'
|
||||||
|
className='CheckboxMain'
|
||||||
|
name='NSFWPreference'
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className='inputLabelWrapperMain'>
|
||||||
|
<div className='labelWrapperMain'>
|
||||||
|
<p className='labelMain'>Web of Trust (WoT) level</p>
|
||||||
|
</div>
|
||||||
|
<p className='labelDescriptionMain'>
|
||||||
|
This affects what posts you see, reactions, DMs, and
|
||||||
|
notifications. Learn more: Link
|
||||||
|
</p>
|
||||||
|
<div className='inputLabelWrapperMainSliderWrapper'>
|
||||||
|
<input
|
||||||
|
className='form-range inputRangeMain inputRangeMainZap'
|
||||||
|
type='range'
|
||||||
|
max='100'
|
||||||
|
min='0'
|
||||||
|
value='10'
|
||||||
|
step='1'
|
||||||
|
required
|
||||||
|
name='WoTLevel'
|
||||||
|
/>
|
||||||
|
<p className='ZapSplitUserBoxRangeText'>10</p>
|
||||||
|
</div>
|
||||||
|
<div className='inputLabelWrapperMain inputLabelWrapperMainAlt inputLabelWrapperMainAltStylized'>
|
||||||
|
<label className='form-label labelMain'>
|
||||||
|
Consider those who zap/tip, regardless of WoT level
|
||||||
|
</label>
|
||||||
|
<input
|
||||||
|
type='checkbox'
|
||||||
|
className='CheckboxMain'
|
||||||
|
name='WoTZap'
|
||||||
|
checked
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className='IBMSMSMBS_WriteAction'>
|
||||||
|
<button className='btn btnMain' type='button'>
|
||||||
|
Save
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
344
src/pages/settings/profile.tsx
Normal file
344
src/pages/settings/profile.tsx
Normal file
@ -0,0 +1,344 @@
|
|||||||
|
import { InputField } from 'components/Inputs'
|
||||||
|
import { ProfileQRButtonWithPopUp } from 'components/ProfileSection'
|
||||||
|
import { useAppDispatch, useAppSelector } from 'hooks'
|
||||||
|
import { kinds, nip19, UnsignedEvent, Event } from 'nostr-tools'
|
||||||
|
import { useEffect, useState } from 'react'
|
||||||
|
import { Link } from 'react-router-dom'
|
||||||
|
import { toast } from 'react-toastify'
|
||||||
|
import { appRoutes, getProfilePageRoute } from 'routes'
|
||||||
|
import { copyTextToClipboard, log, LogType, now, npubToHex } from 'utils'
|
||||||
|
import 'styles/profile.css'
|
||||||
|
import {
|
||||||
|
NDKEvent,
|
||||||
|
NDKUserProfile,
|
||||||
|
profileFromEvent,
|
||||||
|
serializeProfile
|
||||||
|
} from '@nostr-dev-kit/ndk'
|
||||||
|
import { RelayController } from 'controllers'
|
||||||
|
import { LoadingSpinner } from 'components/LoadingSpinner'
|
||||||
|
import { setUser } from 'store/reducers/user'
|
||||||
|
|
||||||
|
type FormState = {
|
||||||
|
name: string
|
||||||
|
displayName: string
|
||||||
|
bio: string
|
||||||
|
picture: string
|
||||||
|
banner: string
|
||||||
|
nip05: string
|
||||||
|
lud16: string
|
||||||
|
}
|
||||||
|
|
||||||
|
const defaultFormState: FormState = {
|
||||||
|
name: '',
|
||||||
|
displayName: '',
|
||||||
|
bio: '',
|
||||||
|
picture: '',
|
||||||
|
banner: '',
|
||||||
|
nip05: '',
|
||||||
|
lud16: ''
|
||||||
|
}
|
||||||
|
|
||||||
|
export const ProfileSettings = () => {
|
||||||
|
const dispatch = useAppDispatch()
|
||||||
|
const userState = useAppSelector((state) => state.user)
|
||||||
|
|
||||||
|
const [isPublishing, setIsPublishing] = useState(false)
|
||||||
|
const [formState, setFormState] = useState<FormState>(defaultFormState)
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (userState.auth && userState.user) {
|
||||||
|
const {
|
||||||
|
name,
|
||||||
|
displayName,
|
||||||
|
about,
|
||||||
|
bio,
|
||||||
|
image,
|
||||||
|
picture,
|
||||||
|
banner,
|
||||||
|
nip05,
|
||||||
|
lud16
|
||||||
|
} = userState.user
|
||||||
|
|
||||||
|
setFormState({
|
||||||
|
name: name || '',
|
||||||
|
displayName: displayName || '',
|
||||||
|
bio: bio || about || '',
|
||||||
|
picture: typeof picture === 'string' ? picture : image || '',
|
||||||
|
banner: banner || '',
|
||||||
|
nip05: nip05 || '',
|
||||||
|
lud16: lud16 || ''
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
setFormState(defaultFormState)
|
||||||
|
}
|
||||||
|
}, [userState])
|
||||||
|
|
||||||
|
const handleInputChange = (field: string, value: string) => {
|
||||||
|
setFormState((prev) => ({
|
||||||
|
...prev,
|
||||||
|
[field]: value
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
const banner =
|
||||||
|
formState.banner || '/assets/img/DEGMods%20Placeholder%20Img.png'
|
||||||
|
|
||||||
|
const picture =
|
||||||
|
formState.picture || '/assets/img/DEG%20Mods%20Default%20PP.png'
|
||||||
|
|
||||||
|
const name = formState.displayName || formState.name || 'User name'
|
||||||
|
|
||||||
|
const nip05 = formState.nip05 || 'nip5handle@domain.com'
|
||||||
|
|
||||||
|
const npub = (userState.user?.npub as string) || 'npub1address'
|
||||||
|
|
||||||
|
const bio =
|
||||||
|
formState.bio ||
|
||||||
|
'user bio, this is a long string of temporary text that would be replaced with the user bio from their metadata address'
|
||||||
|
|
||||||
|
// In case user is not logged in clicking on profile link will navigate to homepage
|
||||||
|
let profileRoute = appRoutes.home
|
||||||
|
if (userState.auth && userState.user) {
|
||||||
|
const hexPubkey = npubToHex(userState.user.npub as string)
|
||||||
|
|
||||||
|
if (hexPubkey) {
|
||||||
|
profileRoute = getProfilePageRoute(
|
||||||
|
nip19.nprofileEncode({
|
||||||
|
pubkey: hexPubkey
|
||||||
|
})
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleCopy = async () => {
|
||||||
|
copyTextToClipboard(npub).then((isCopied) => {
|
||||||
|
if (isCopied) {
|
||||||
|
toast.success('Npub copied to clipboard!')
|
||||||
|
} else {
|
||||||
|
toast.error(
|
||||||
|
'Failed to copy, look into console for more details on error!'
|
||||||
|
)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const handlePublish = async () => {
|
||||||
|
if (!userState.auth && !userState.user?.pubkey) return
|
||||||
|
|
||||||
|
setIsPublishing(true)
|
||||||
|
|
||||||
|
const prevProfile = userState.user as NDKUserProfile
|
||||||
|
const updatedProfile = {
|
||||||
|
...prevProfile,
|
||||||
|
name: formState.name,
|
||||||
|
displayName: formState.displayName,
|
||||||
|
bio: formState.bio,
|
||||||
|
picture: formState.picture,
|
||||||
|
banner: formState.banner,
|
||||||
|
nip05: formState.nip05,
|
||||||
|
lud16: formState.lud16
|
||||||
|
}
|
||||||
|
|
||||||
|
const serializedProfile = serializeProfile(updatedProfile)
|
||||||
|
|
||||||
|
const unsignedEvent: UnsignedEvent = {
|
||||||
|
kind: kinds.Metadata,
|
||||||
|
tags: [],
|
||||||
|
content: serializedProfile,
|
||||||
|
created_at: now(),
|
||||||
|
pubkey: userState.user?.pubkey as string
|
||||||
|
}
|
||||||
|
|
||||||
|
const signedEvent = await window.nostr
|
||||||
|
?.signEvent(unsignedEvent)
|
||||||
|
.then((event) => event as Event)
|
||||||
|
.catch((err) => {
|
||||||
|
toast.error('Failed to sign the event!')
|
||||||
|
log(true, LogType.Error, 'Failed to sign the event!', err)
|
||||||
|
return null
|
||||||
|
})
|
||||||
|
|
||||||
|
if (!signedEvent) {
|
||||||
|
setIsPublishing(false)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const publishedOnRelays = await RelayController.getInstance().publish(
|
||||||
|
signedEvent as Event
|
||||||
|
)
|
||||||
|
|
||||||
|
// Handle cases where publishing failed or succeeded
|
||||||
|
if (publishedOnRelays.length === 0) {
|
||||||
|
toast.error('Failed to publish event on any relay')
|
||||||
|
} else {
|
||||||
|
toast.success(
|
||||||
|
`Event published successfully to the following relays\n\n${publishedOnRelays.join(
|
||||||
|
'\n'
|
||||||
|
)}`
|
||||||
|
)
|
||||||
|
|
||||||
|
const ndkEvent = new NDKEvent(undefined, signedEvent)
|
||||||
|
const userProfile = profileFromEvent(ndkEvent)
|
||||||
|
dispatch(setUser(userProfile))
|
||||||
|
}
|
||||||
|
|
||||||
|
setIsPublishing(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{isPublishing && <LoadingSpinner desc='Publishing event' />}
|
||||||
|
<div className='IBMSMSplitMainFullSideFWMid'>
|
||||||
|
<div className='IBMSMSplitMainFullSideSec'>
|
||||||
|
<div className='IBMSMSMBSS_Profile'>
|
||||||
|
<div className='IBMSMSMBSS_ProfilePreview'>
|
||||||
|
<div className='IBMSMSMSSS_Author_Top_Left'>
|
||||||
|
<div
|
||||||
|
className='IBMSMSMSSS_Author_Top_Banner'
|
||||||
|
style={{
|
||||||
|
background: `url(${banner}) center / cover no-repeat`
|
||||||
|
}}
|
||||||
|
></div>
|
||||||
|
<Link
|
||||||
|
className='IBMSMSMSSS_Author_Top_Left_InsideLinkWrapper'
|
||||||
|
to={profileRoute}
|
||||||
|
>
|
||||||
|
<div className='IBMSMSMSSS_Author_Top_Left_Inside'>
|
||||||
|
<div className='IBMSMSMSSS_Author_Top_Left_InsidePic'>
|
||||||
|
<div className='IBMSMSMSSS_Author_Top_PPWrapper'>
|
||||||
|
<div
|
||||||
|
className='IBMSMSMSSS_Author_Top_PP'
|
||||||
|
style={{
|
||||||
|
background: `url(${picture}) center / cover no-repeat`
|
||||||
|
}}
|
||||||
|
></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className='IBMSMSMSSS_Author_Top_Left_InsideDetails'>
|
||||||
|
<div className='IBMSMSMSSS_Author_TopWrapper'>
|
||||||
|
<p className='IBMSMSMSSS_Author_Top_Name'>{name}</p>
|
||||||
|
<p className='IBMSMSMSSS_Author_Top_Handle'>{nip05}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</Link>
|
||||||
|
<div className='IBMSMSMSSS_Author_Top_AddressWrapper'>
|
||||||
|
<div className='IBMSMSMSSS_Author_Top_AddressWrapped'>
|
||||||
|
<p
|
||||||
|
id='SiteOwnerAddress-1'
|
||||||
|
className='IBMSMSMSSS_Author_Top_Address'
|
||||||
|
>
|
||||||
|
{npub}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div className='IBMSMSMSSS_Author_Top_IconWrapper'>
|
||||||
|
<div
|
||||||
|
id='copySiteOwnerAddress'
|
||||||
|
className='IBMSMSMSSS_Author_Top_IconWrapped'
|
||||||
|
onClick={handleCopy}
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
xmlns='http://www.w3.org/2000/svg'
|
||||||
|
viewBox='0 0 512 512'
|
||||||
|
width='1em'
|
||||||
|
height='1em'
|
||||||
|
fill='currentColor'
|
||||||
|
className='IBMSMSMSSS_Author_Top_Icon'
|
||||||
|
>
|
||||||
|
<path d='M384 96L384 0h-112c-26.51 0-48 21.49-48 48v288c0 26.51 21.49 48 48 48H464c26.51 0 48-21.49 48-48V128h-95.1C398.4 128 384 113.6 384 96zM416 0v96h96L416 0zM192 352V128h-144c-26.51 0-48 21.49-48 48v288c0 26.51 21.49 48 48 48h192c26.51 0 48-21.49 48-48L288 416h-32C220.7 416 192 387.3 192 352z'></path>
|
||||||
|
</svg>
|
||||||
|
</div>
|
||||||
|
{typeof userState.user?.pubkey === 'string' && (
|
||||||
|
<ProfileQRButtonWithPopUp
|
||||||
|
pubkey={userState.user.pubkey}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className='IBMSMSMSSS_Author_Top_Details'>
|
||||||
|
<p className='IBMSMSMSSS_Author_Top_Bio'>{bio}</p>
|
||||||
|
<div
|
||||||
|
id='OwnerFollowLogin-1'
|
||||||
|
className='IBMSMSMSSS_Author_Top_NostrLinks'
|
||||||
|
style={{ display: 'flex' }}
|
||||||
|
></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className='IBMSMSMBSS_ProfileEdit'>
|
||||||
|
<InputField
|
||||||
|
label='Name'
|
||||||
|
placeholder=''
|
||||||
|
name='name'
|
||||||
|
value={formState.name}
|
||||||
|
onChange={handleInputChange}
|
||||||
|
/>
|
||||||
|
<InputField
|
||||||
|
label='Display name'
|
||||||
|
placeholder=''
|
||||||
|
name='displayName'
|
||||||
|
value={formState.displayName}
|
||||||
|
onChange={handleInputChange}
|
||||||
|
/>
|
||||||
|
<InputField
|
||||||
|
label='Bio'
|
||||||
|
placeholder=''
|
||||||
|
name='bio'
|
||||||
|
type='textarea'
|
||||||
|
value={formState.bio}
|
||||||
|
onChange={handleInputChange}
|
||||||
|
/>
|
||||||
|
<InputField
|
||||||
|
label='Profile picture URL'
|
||||||
|
placeholder=''
|
||||||
|
name='picture'
|
||||||
|
inputMode='url'
|
||||||
|
value={formState.picture}
|
||||||
|
onChange={handleInputChange}
|
||||||
|
/>
|
||||||
|
<InputField
|
||||||
|
label='Banner picture URL'
|
||||||
|
placeholder=''
|
||||||
|
name='banner'
|
||||||
|
inputMode='url'
|
||||||
|
value={formState.banner}
|
||||||
|
onChange={handleInputChange}
|
||||||
|
/>
|
||||||
|
<InputField
|
||||||
|
label='Nip-05 address'
|
||||||
|
placeholder=''
|
||||||
|
name='nip05'
|
||||||
|
value={formState.nip05}
|
||||||
|
onChange={handleInputChange}
|
||||||
|
/>
|
||||||
|
<InputField
|
||||||
|
label='Lightning Address (lud16)'
|
||||||
|
placeholder=''
|
||||||
|
name='lud16'
|
||||||
|
value={formState.lud16}
|
||||||
|
onChange={handleInputChange}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
className='IBMSMSMBSS_ProfileActions'
|
||||||
|
style={{
|
||||||
|
padding: 'unset',
|
||||||
|
border: 'unset',
|
||||||
|
justifyContent: 'end'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<button
|
||||||
|
className='btn btnMain'
|
||||||
|
type='button'
|
||||||
|
disabled={isPublishing}
|
||||||
|
onClick={handlePublish}
|
||||||
|
>
|
||||||
|
Publish Changes
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
242
src/pages/settings/relay.tsx
Normal file
242
src/pages/settings/relay.tsx
Normal file
@ -0,0 +1,242 @@
|
|||||||
|
import { InputField } from 'components/Inputs'
|
||||||
|
|
||||||
|
export const RelaySettings = () => {
|
||||||
|
return (
|
||||||
|
<div className='IBMSMSplitMainFullSideFWMid'>
|
||||||
|
<div className='IBMSMSplitMainFullSideSec'>
|
||||||
|
<div className='relayList'>
|
||||||
|
<div className='inputLabelWrapperMain'>
|
||||||
|
<label className='form-label labelMain'>Your relays</label>
|
||||||
|
</div>
|
||||||
|
{usersRelays.map((relay, index) => (
|
||||||
|
<RelayListItem key={index} item={relay} isOwnRelay />
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className='IBMSMSplitMainFullSideSec'>
|
||||||
|
<InputField
|
||||||
|
label='Add Relays'
|
||||||
|
placeholder='wss://some-relay.com'
|
||||||
|
type='text'
|
||||||
|
name='relay'
|
||||||
|
value=''
|
||||||
|
onChange={() => {}}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<button className='btn btnMain' type='button'>
|
||||||
|
Add
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className='IBMSMSplitMainFullSideSec'>
|
||||||
|
<div className='inputLabelWrapperMain'>
|
||||||
|
<label className='form-label labelMain'>DEG Mods Relays</label>
|
||||||
|
<p className='labelDescriptionMain'>
|
||||||
|
We recommend adding one of our relays if you're planning to
|
||||||
|
frequently use DEG Mods, for a better experience.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div className='relayList'>
|
||||||
|
{degmodsRelays.map((relay, index) => (
|
||||||
|
<RelayListItem key={index} item={relay} />
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className='IBMSMSplitMainFullSideSec'>
|
||||||
|
<div className='inputLabelWrapperMain'>
|
||||||
|
<label className='form-label labelMain'>Recommended Relays</label>
|
||||||
|
<p className='labelDescriptionMain'>
|
||||||
|
Relays we recommend using as they support the same functionalities
|
||||||
|
that our relays provide.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div className='relayList'>
|
||||||
|
{recommendRelays.map((relay, index) => (
|
||||||
|
<RelayListItem key={index} item={relay} />
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const RelayListItem = ({
|
||||||
|
item,
|
||||||
|
isOwnRelay
|
||||||
|
}: {
|
||||||
|
item: RelayItem
|
||||||
|
isOwnRelay?: boolean
|
||||||
|
}) => {
|
||||||
|
return (
|
||||||
|
<div className='relayListItem'>
|
||||||
|
<div className='relayListItemSec relayListItemSecPic'>
|
||||||
|
<div
|
||||||
|
className='relayListItemSecPicImg'
|
||||||
|
style={{
|
||||||
|
background: item.backgroundColor
|
||||||
|
}}
|
||||||
|
></div>
|
||||||
|
</div>
|
||||||
|
<div className='relayListItemSec relayListItemSecDetails'>
|
||||||
|
<p className='relayListItemSecDetailsText'>{item.url}</p>
|
||||||
|
<div className='relayListItemSecDetailsExtra'>
|
||||||
|
<svg
|
||||||
|
xmlns='http://www.w3.org/2000/svg'
|
||||||
|
viewBox='-64 0 512 512'
|
||||||
|
width='1em'
|
||||||
|
height='1em'
|
||||||
|
fill='currentColor'
|
||||||
|
data-bs-toggle='tooltip'
|
||||||
|
data-bss-tooltip
|
||||||
|
aria-label={item.readTitle}
|
||||||
|
>
|
||||||
|
<path d='M0 64C0 28.65 28.65 0 64 0H224V128C224 145.7 238.3 160 256 160H384V448C384 483.3 355.3 512 320 512H64C28.65 512 0 483.3 0 448V64zM256 128V0L384 128H256z'></path>
|
||||||
|
</svg>
|
||||||
|
<svg
|
||||||
|
xmlns='http://www.w3.org/2000/svg'
|
||||||
|
viewBox='0 -32 576 576'
|
||||||
|
width='1em'
|
||||||
|
height='1em'
|
||||||
|
fill='currentColor'
|
||||||
|
data-bs-toggle='tooltip'
|
||||||
|
data-bss-tooltip
|
||||||
|
aria-label={item.writeTitle}
|
||||||
|
>
|
||||||
|
<path d='M0 64C0 28.65 28.65 0 64 0H224V128C224 145.7 238.3 160 256 160H384V299.6L289.3 394.3C281.1 402.5 275.3 412.8 272.5 424.1L257.4 484.2C255.1 493.6 255.7 503.2 258.8 512H64C28.65 512 0 483.3 0 448V64zM256 128V0L384 128H256zM564.1 250.1C579.8 265.7 579.8 291 564.1 306.7L534.7 336.1L463.8 265.1L493.2 235.7C508.8 220.1 534.1 220.1 549.8 235.7L564.1 250.1zM311.9 416.1L441.1 287.8L512.1 358.7L382.9 487.9C378.8 492 373.6 494.9 368 496.3L307.9 511.4C302.4 512.7 296.7 511.1 292.7 507.2C288.7 503.2 287.1 497.4 288.5 491.1L303.5 431.8C304.9 426.2 307.8 421.1 311.9 416.1V416.1z'></path>
|
||||||
|
</svg>
|
||||||
|
{item.subscribedTitle && (
|
||||||
|
<svg
|
||||||
|
xmlns='http://www.w3.org/2000/svg'
|
||||||
|
viewBox='0 0 512 512'
|
||||||
|
width='1em'
|
||||||
|
height='1em'
|
||||||
|
fill='currentColor'
|
||||||
|
data-bs-toggle='tooltip'
|
||||||
|
data-bss-tooltip
|
||||||
|
aria-label={item.subscribedTitle}
|
||||||
|
>
|
||||||
|
<path d='M504 256c0 136.967-111.033 248-248 248S8 392.967 8 256 119.033 8 256 8s248 111.033 248 248zm-141.651-35.33c4.937-32.999-20.191-50.739-54.55-62.573l11.146-44.702-27.213-6.781-10.851 43.524c-7.154-1.783-14.502-3.464-21.803-5.13l10.929-43.81-27.198-6.781-11.153 44.686c-5.922-1.349-11.735-2.682-17.377-4.084l.031-.14-37.53-9.37-7.239 29.062s20.191 4.627 19.765 4.913c11.022 2.751 13.014 10.044 12.68 15.825l-12.696 50.925c.76.194 1.744.473 2.829.907-.907-.225-1.876-.473-2.876-.713l-17.796 71.338c-1.349 3.348-4.767 8.37-12.471 6.464.271.395-19.78-4.937-19.78-4.937l-13.51 31.147 35.414 8.827c6.588 1.651 13.045 3.379 19.4 5.006l-11.262 45.213 27.182 6.781 11.153-44.733a1038.209 1038.209 0 0 0 21.687 5.627l-11.115 44.523 27.213 6.781 11.262-45.128c46.404 8.781 81.299 5.239 95.986-36.727 11.836-33.79-.589-53.281-25.004-65.991 17.78-4.098 31.174-15.792 34.747-39.949zm-62.177 87.179c-8.41 33.79-65.308 15.523-83.755 10.943l14.944-59.899c18.446 4.603 77.6 13.717 68.811 48.956zm8.417-87.667c-7.673 30.736-55.031 15.12-70.393 11.292l13.548-54.327c15.363 3.828 64.836 10.973 56.845 43.035z'></path>
|
||||||
|
</svg>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className='relayListItemSec relayListItemSecActions'>
|
||||||
|
{isOwnRelay && (
|
||||||
|
<div
|
||||||
|
className='dropstart dropdownMain'
|
||||||
|
style={{ position: 'absolute' }}
|
||||||
|
>
|
||||||
|
<button
|
||||||
|
className='btn btnMain'
|
||||||
|
aria-expanded='false'
|
||||||
|
data-bs-toggle='dropdown'
|
||||||
|
type='button'
|
||||||
|
>
|
||||||
|
<svg
|
||||||
|
xmlns='http://www.w3.org/2000/svg'
|
||||||
|
viewBox='-192 0 512 512'
|
||||||
|
width='1em'
|
||||||
|
height='1em'
|
||||||
|
fill='currentColor'
|
||||||
|
>
|
||||||
|
<path d='M64 360C94.93 360 120 385.1 120 416C120 446.9 94.93 472 64 472C33.07 472 8 446.9 8 416C8 385.1 33.07 360 64 360zM64 200C94.93 200 120 225.1 120 256C120 286.9 94.93 312 64 312C33.07 312 8 286.9 8 256C8 225.1 33.07 200 64 200zM64 152C33.07 152 8 126.9 8 96C8 65.07 33.07 40 64 40C94.93 40 120 65.07 120 96C120 126.9 94.93 152 64 152z'></path>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
<div
|
||||||
|
className='dropdown-menu dropdownMainMenu'
|
||||||
|
style={{ position: 'absolute' }}
|
||||||
|
>
|
||||||
|
<a className='dropdown-item dropdownMainMenuItem' href='#'>
|
||||||
|
Remove
|
||||||
|
</a>
|
||||||
|
<a className='dropdown-item dropdownMainMenuItem' href='#'>
|
||||||
|
Details
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
{!isOwnRelay && (
|
||||||
|
<button className='btn btnMain' type='button'>
|
||||||
|
<svg
|
||||||
|
xmlns='http://www.w3.org/2000/svg'
|
||||||
|
viewBox='-32 0 512 512'
|
||||||
|
width='1em'
|
||||||
|
height='1em'
|
||||||
|
fill='currentColor'
|
||||||
|
>
|
||||||
|
<path d='M432 256c0 17.69-14.33 32.01-32 32.01H256v144c0 17.69-14.33 31.99-32 31.99s-32-14.3-32-31.99v-144H48c-17.67 0-32-14.32-32-32.01s14.33-31.99 32-31.99H192v-144c0-17.69 14.33-32.01 32-32.01s32 14.32 32 32.01v144h144C417.7 224 432 238.3 432 256z'></path>
|
||||||
|
</svg>
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
interface RelayItem {
|
||||||
|
url: string
|
||||||
|
backgroundColor: string
|
||||||
|
readTitle: string
|
||||||
|
writeTitle: string
|
||||||
|
subscribedTitle: string
|
||||||
|
}
|
||||||
|
|
||||||
|
const usersRelays: RelayItem[] = [
|
||||||
|
{
|
||||||
|
url: 'wss://relay.wibblywobbly.com',
|
||||||
|
backgroundColor: '#cd4d45',
|
||||||
|
readTitle: 'Read',
|
||||||
|
writeTitle: 'Write',
|
||||||
|
subscribedTitle: ''
|
||||||
|
},
|
||||||
|
{
|
||||||
|
url: 'wss://relay.wibblywobbly.com',
|
||||||
|
backgroundColor: '#60ae60',
|
||||||
|
readTitle: 'Read',
|
||||||
|
writeTitle: 'Write',
|
||||||
|
subscribedTitle: 'Paid (Subscribed)'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
url: 'wss://relay.degmods.com',
|
||||||
|
backgroundColor: '#60ae60',
|
||||||
|
readTitle: 'Read',
|
||||||
|
writeTitle: 'Write',
|
||||||
|
subscribedTitle: ''
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
const degmodsRelays: RelayItem[] = [
|
||||||
|
{
|
||||||
|
url: 'wss://relay1.degmods.com',
|
||||||
|
backgroundColor: '#60ae60',
|
||||||
|
readTitle: 'Read',
|
||||||
|
writeTitle: 'Write',
|
||||||
|
subscribedTitle: ''
|
||||||
|
},
|
||||||
|
{
|
||||||
|
url: 'wss://relay2.degmods.com',
|
||||||
|
backgroundColor: '#60ae60',
|
||||||
|
readTitle: 'Read',
|
||||||
|
writeTitle: 'Write',
|
||||||
|
subscribedTitle: ''
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
const recommendRelays: RelayItem[] = [
|
||||||
|
{
|
||||||
|
url: 'wss://relay1.degmods.com',
|
||||||
|
backgroundColor: '#60ae60',
|
||||||
|
readTitle: 'Read',
|
||||||
|
writeTitle: 'Write',
|
||||||
|
subscribedTitle: ''
|
||||||
|
},
|
||||||
|
{
|
||||||
|
url: 'wss://relay2.degmods.com',
|
||||||
|
backgroundColor: '#60ae60',
|
||||||
|
readTitle: 'Read',
|
||||||
|
writeTitle: 'Write',
|
||||||
|
subscribedTitle: ''
|
||||||
|
}
|
||||||
|
]
|
Loading…
Reference in New Issue
Block a user