forked from coracle/flotilla
Optionally protect profiles
This commit is contained in:
@@ -1,25 +1,37 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import type {Profile} from "@welshman/util"
|
import type {Profile} from "@welshman/util"
|
||||||
import {
|
import {
|
||||||
|
getTag,
|
||||||
createEvent,
|
createEvent,
|
||||||
makeProfile,
|
makeProfile,
|
||||||
editProfile,
|
editProfile,
|
||||||
createProfile,
|
createProfile,
|
||||||
isPublishedProfile,
|
isPublishedProfile,
|
||||||
|
uniqTags,
|
||||||
} from "@welshman/util"
|
} from "@welshman/util"
|
||||||
import {Router, pubkey, profilesByPubkey, publishThunk} from "@welshman/app"
|
import {Router, pubkey, profilesByPubkey, publishThunk} from "@welshman/app"
|
||||||
import Button from "@lib/components/Button.svelte"
|
import Button from "@lib/components/Button.svelte"
|
||||||
import ProfileEditForm from "@app/components/ProfileEditForm.svelte"
|
import ProfileEditForm from "@app/components/ProfileEditForm.svelte"
|
||||||
import {clearModals} from "@app/modal"
|
import {clearModals} from "@app/modal"
|
||||||
import {pushToast} from "@app/toast"
|
import {pushToast} from "@app/toast"
|
||||||
|
import {PROTECTED, getMembershipUrls, userMembership} from "@app/state"
|
||||||
|
|
||||||
const initialValues = {...($profilesByPubkey.get($pubkey!) || makeProfile())}
|
const profile = $profilesByPubkey.get($pubkey!) || makeProfile()
|
||||||
|
const shouldBroadcast = !getTag(PROTECTED, profile.event?.tags || [])
|
||||||
|
const initialValues = {profile, shouldBroadcast}
|
||||||
|
|
||||||
const back = () => history.back()
|
const back = () => history.back()
|
||||||
|
|
||||||
const onsubmit = (profile: Profile) => {
|
const onsubmit = ({profile, shouldBroadcast}: {profile: Profile; shouldBroadcast: boolean}) => {
|
||||||
const relays = Router.get().FromUser().getUrls()
|
const relays = shouldBroadcast
|
||||||
|
? Router.get().FromUser().getUrls()
|
||||||
|
: getMembershipUrls($userMembership)
|
||||||
const template = isPublishedProfile(profile) ? editProfile(profile) : createProfile(profile)
|
const template = isPublishedProfile(profile) ? editProfile(profile) : createProfile(profile)
|
||||||
|
|
||||||
|
if (!shouldBroadcast) {
|
||||||
|
template.tags = uniqTags([...template.tags, PROTECTED])
|
||||||
|
}
|
||||||
|
|
||||||
const event = createEvent(template.kind, template)
|
const event = createEvent(template.kind, template)
|
||||||
|
|
||||||
publishThunk({event, relays})
|
publishThunk({event, relays})
|
||||||
|
|||||||
@@ -1,23 +1,28 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import type {Snippet} from "svelte"
|
import type {Snippet} from "svelte"
|
||||||
import type {Profile} from "@welshman/util"
|
import type {Profile} from "@welshman/util"
|
||||||
import {makeProfile} from "@welshman/util"
|
|
||||||
import {preventDefault} from "@lib/html"
|
import {preventDefault} from "@lib/html"
|
||||||
import Icon from "@lib/components/Icon.svelte"
|
import Icon from "@lib/components/Icon.svelte"
|
||||||
import Field from "@lib/components/Field.svelte"
|
import Field from "@lib/components/Field.svelte"
|
||||||
|
import FieldInline from "@lib/components/FieldInline.svelte"
|
||||||
import Button from "@lib/components/Button.svelte"
|
import Button from "@lib/components/Button.svelte"
|
||||||
import InputProfilePicture from "@lib/components/InputProfilePicture.svelte"
|
import InputProfilePicture from "@lib/components/InputProfilePicture.svelte"
|
||||||
import InfoHandle from "@app/components/InfoHandle.svelte"
|
import InfoHandle from "@app/components/InfoHandle.svelte"
|
||||||
import {pushModal} from "@app/modal"
|
import {pushModal} from "@app/modal"
|
||||||
|
|
||||||
|
type Values = {
|
||||||
|
profile: Profile
|
||||||
|
shouldBroadcast: boolean
|
||||||
|
}
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
initialValues?: Profile
|
initialValues: Values
|
||||||
onsubmit: (profile: Profile) => void
|
onsubmit: (values: Values) => void
|
||||||
hideAddress?: boolean
|
hideAddress?: boolean
|
||||||
footer: Snippet
|
footer: Snippet
|
||||||
}
|
}
|
||||||
|
|
||||||
const {initialValues = makeProfile(), hideAddress, onsubmit, footer}: Props = $props()
|
const {initialValues, hideAddress, onsubmit, footer}: Props = $props()
|
||||||
|
|
||||||
const values = $state(initialValues)
|
const values = $state(initialValues)
|
||||||
|
|
||||||
@@ -28,7 +33,7 @@
|
|||||||
|
|
||||||
<form class="col-4" onsubmit={preventDefault(submit)}>
|
<form class="col-4" onsubmit={preventDefault(submit)}>
|
||||||
<div class="flex justify-center py-2">
|
<div class="flex justify-center py-2">
|
||||||
<InputProfilePicture bind:file bind:url={values.picture} />
|
<InputProfilePicture bind:file bind:url={values.profile.picture} />
|
||||||
</div>
|
</div>
|
||||||
<Field>
|
<Field>
|
||||||
{#snippet label()}
|
{#snippet label()}
|
||||||
@@ -37,7 +42,7 @@
|
|||||||
{#snippet input()}
|
{#snippet input()}
|
||||||
<label class="input input-bordered flex w-full items-center gap-2">
|
<label class="input input-bordered flex w-full items-center gap-2">
|
||||||
<Icon icon="user-circle" />
|
<Icon icon="user-circle" />
|
||||||
<input bind:value={values.name} class="grow" type="text" />
|
<input bind:value={values.profile.name} class="grow" type="text" />
|
||||||
</label>
|
</label>
|
||||||
{/snippet}
|
{/snippet}
|
||||||
{#snippet info()}
|
{#snippet info()}
|
||||||
@@ -49,8 +54,10 @@
|
|||||||
<p>About You</p>
|
<p>About You</p>
|
||||||
{/snippet}
|
{/snippet}
|
||||||
{#snippet input()}
|
{#snippet input()}
|
||||||
<textarea class="textarea textarea-bordered leading-4" rows="3" bind:value={values.about}
|
<textarea
|
||||||
></textarea>
|
class="textarea textarea-bordered leading-4"
|
||||||
|
rows="5"
|
||||||
|
bind:value={values.profile.about}></textarea>
|
||||||
{/snippet}
|
{/snippet}
|
||||||
{#snippet info()}
|
{#snippet info()}
|
||||||
Give a brief introduction to why you're here.
|
Give a brief introduction to why you're here.
|
||||||
@@ -64,7 +71,7 @@
|
|||||||
{#snippet input()}
|
{#snippet input()}
|
||||||
<label class="input input-bordered flex w-full items-center gap-2">
|
<label class="input input-bordered flex w-full items-center gap-2">
|
||||||
<Icon icon="map-point" />
|
<Icon icon="map-point" />
|
||||||
<input bind:value={values.nip05} class="grow" type="text" />
|
<input bind:value={values.profile.nip05} class="grow" type="text" />
|
||||||
</label>
|
</label>
|
||||||
{/snippet}
|
{/snippet}
|
||||||
{#snippet info()}
|
{#snippet info()}
|
||||||
@@ -75,5 +82,19 @@
|
|||||||
{/snippet}
|
{/snippet}
|
||||||
</Field>
|
</Field>
|
||||||
{/if}
|
{/if}
|
||||||
|
<FieldInline>
|
||||||
|
{#snippet label()}
|
||||||
|
<p>Broadcast Profile</p>
|
||||||
|
{/snippet}
|
||||||
|
{#snippet input()}
|
||||||
|
<input type="checkbox" class="toggle toggle-primary" bind:checked={values.shouldBroadcast} />
|
||||||
|
{/snippet}
|
||||||
|
{#snippet info()}
|
||||||
|
<p>
|
||||||
|
If enabled, your profile will be published to the broader nostr network, as well as to
|
||||||
|
spaces you are a member of.
|
||||||
|
</p>
|
||||||
|
{/snippet}
|
||||||
|
</FieldInline>
|
||||||
{@render footer()}
|
{@render footer()}
|
||||||
</form>
|
</form>
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import type {Profile} from "@welshman/util"
|
import type {Profile} from "@welshman/util"
|
||||||
import {PROFILE, createProfile, createEvent} from "@welshman/util"
|
import {PROFILE, createProfile, makeProfile, createEvent} from "@welshman/util"
|
||||||
import {loginWithNip01, publishThunk} from "@welshman/app"
|
import {loginWithNip01, publishThunk} from "@welshman/app"
|
||||||
import Button from "@lib/components/Button.svelte"
|
import Button from "@lib/components/Button.svelte"
|
||||||
import ProfileEditForm from "@app/components/ProfileEditForm.svelte"
|
import ProfileEditForm from "@app/components/ProfileEditForm.svelte"
|
||||||
@@ -12,15 +12,21 @@
|
|||||||
|
|
||||||
const {secret}: Props = $props()
|
const {secret}: Props = $props()
|
||||||
|
|
||||||
const onsubmit = (profile: Profile) => {
|
const initialValues = {
|
||||||
|
profile: makeProfile(),
|
||||||
|
shouldBroadcast: true,
|
||||||
|
}
|
||||||
|
|
||||||
|
const onsubmit = ({profile, shouldBroadcast}: {profile: Profile; shouldBroadcast: boolean}) => {
|
||||||
const event = createEvent(PROFILE, createProfile(profile))
|
const event = createEvent(PROFILE, createProfile(profile))
|
||||||
|
const relays = shouldBroadcast ? INDEXER_RELAYS : []
|
||||||
|
|
||||||
loginWithNip01(secret)
|
loginWithNip01(secret)
|
||||||
publishThunk({event, relays: INDEXER_RELAYS})
|
publishThunk({event, relays})
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<ProfileEditForm hideAddress {onsubmit}>
|
<ProfileEditForm hideAddress {initialValues} {onsubmit}>
|
||||||
{#snippet footer()}
|
{#snippet footer()}
|
||||||
<Button type="submit" class="btn btn-primary">Create Account</Button>
|
<Button type="submit" class="btn btn-primary">Create Account</Button>
|
||||||
{/snippet}
|
{/snippet}
|
||||||
|
|||||||
@@ -0,0 +1,6 @@
|
|||||||
|
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<path d="M19.1414 2.07816C20.9097 3.88191 22 6.3527 22 9.07816C22 11.836 20.8836 14.333 19.0782 16.1421M5 16.2196C3.14864 14.4047 2 11.8756 2 9.07816C2 6.31313 3.12222 3.8102 4.93603 2" stroke="#1C274C" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<path d="M16.2849 5.1221C17.3458 6.13689 18 7.52697 18 9.06033C18 10.6119 17.3302 12.0167 16.2469 13.0345M7.8 13.0781C6.68918 12.057 6 10.6342 6 9.06033C6 7.50471 6.67333 6.09655 7.76162 5.07812" stroke="#1C274C" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
<circle cx="12" cy="9.07812" r="2" stroke="#1C274C" stroke-width="1.5"/>
|
||||||
|
<path d="M12.5 11L16 22L10.5 15.5M11.5 11L8 22L13.5 15.5" stroke="#1C274C" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 871 B |
@@ -68,6 +68,7 @@
|
|||||||
import Server from "@assets/icons/Server.svg?dataurl"
|
import Server from "@assets/icons/Server.svg?dataurl"
|
||||||
import Settings from "@assets/icons/Settings.svg?dataurl"
|
import Settings from "@assets/icons/Settings.svg?dataurl"
|
||||||
import SettingsMinimalistic from "@assets/icons/Settings Minimalistic.svg?dataurl"
|
import SettingsMinimalistic from "@assets/icons/Settings Minimalistic.svg?dataurl"
|
||||||
|
import Station from "@assets/icons/Station.svg?dataurl"
|
||||||
import TagHorizontal from "@assets/icons/Tag Horizontal.svg?dataurl"
|
import TagHorizontal from "@assets/icons/Tag Horizontal.svg?dataurl"
|
||||||
import ShareCircle from "@assets/icons/Share Circle.svg?dataurl"
|
import ShareCircle from "@assets/icons/Share Circle.svg?dataurl"
|
||||||
import ShopMinimalistic from "@assets/icons/Shop Minimalistic.svg?dataurl"
|
import ShopMinimalistic from "@assets/icons/Shop Minimalistic.svg?dataurl"
|
||||||
@@ -160,6 +161,7 @@
|
|||||||
server: Server,
|
server: Server,
|
||||||
settings: Settings,
|
settings: Settings,
|
||||||
"settings-minimalistic": SettingsMinimalistic,
|
"settings-minimalistic": SettingsMinimalistic,
|
||||||
|
station: Station,
|
||||||
"tag-horizontal": TagHorizontal,
|
"tag-horizontal": TagHorizontal,
|
||||||
"trash-bin-2": TrashBin2,
|
"trash-bin-2": TrashBin2,
|
||||||
"ufo-3": UFO3,
|
"ufo-3": UFO3,
|
||||||
|
|||||||
Reference in New Issue
Block a user