feat: nostr activity and tag support

This commit is contained in:
benalleng
2023-09-14 20:08:38 -04:00
committed by Paul Miller
parent 54e2db2ce5
commit fa1dab3eb4
7 changed files with 69 additions and 14 deletions

View File

@@ -56,6 +56,7 @@ export function ContactViewer(props: {
showToast(result.error);
return;
} else {
result.value.privateTag = props.contact.name;
if (
result.value?.address ||
result.value?.invoice ||

View File

@@ -6,9 +6,11 @@ import {
Show,
Switch
} from "solid-js";
import { Dynamic } from "solid-js/web";
import rightArrow from "~/assets/icons/right-arrow.svg";
import { AmountSats, VStack } from "~/components";
import { AmountSats, TinyText, VStack } from "~/components";
import { useI18n } from "~/i18n/context";
import { useMegaStore } from "~/state/megaStore";
import { fetchZaps, getHexpubFromNpub } from "~/utils";
import { timeAgo } from "~/utils/prettyPrintTime";
@@ -31,6 +33,7 @@ function formatProfileLink(hexpub: string): string {
}
export function NostrActivity() {
const i18n = useI18n();
const [state, _actions] = useMegaStore();
const [data, { refetch }] = createResource(state.npub, fetchZaps);
@@ -93,10 +96,10 @@ export function NostrActivity() {
</a>
</Match>
<Match when={zap.kind === "private"}>
Private
{i18n.t("activity.private")}
</Match>
<Match when={zap.kind === "anonymous"}>
Anonymous
{i18n.t("activity.anonymous")}
</Match>
</Switch>
</span>
@@ -151,10 +154,36 @@ export function NostrActivity() {
</div>
<Show when={zap.content}>
<hr class="my-2 border-m-grey-750" />
<p
class="truncate text-center text-sm font-light text-neutral-200"
textContent={zap.content}
/>
<TinyText>
<Dynamic
component={
zap.content?.includes("From:") ||
zap.content?.includes("://")
? "a"
: "p"
}
href={
zap.content?.split("nostr:")[1]
? formatProfileLink(
getHexpubFromNpub(
zap.content?.split(
"nostr:"
)[1]
) ?? ""
)
: zap.content
}
class="block truncate text-center text-sm font-light text-neutral-200"
target="_blank"
rel="noopener noreferrer"
>
{zap.content?.includes("From:")
? `${i18n.t(
"activity.from"
)} ${zap.content?.split("nostr:")[1]}`
: zap.content}
</Dynamic>
</TinyText>
</Show>
</div>
)}

View File

@@ -16,6 +16,7 @@ export function TagEditor(props: {
selectedValues: Partial<MutinyTagItem>[];
setSelectedValues: (value: Partial<MutinyTagItem>[]) => void;
placeholder: string;
autoFillTag?: string | undefined;
}) {
const [_state, actions] = useMegaStore();
const [availableTags, setAvailableTags] = createSignal<MutinyTagItem[]>([]);
@@ -28,12 +29,24 @@ export function TagEditor(props: {
.filter((tag) => tag.kind === "Contact")
.sort(sortByLastUsed)
);
if (props.autoFillTag && availableTags()) {
const tagToAutoSelect = availableTags().find(
(tag) => tag.name === props.autoFillTag
);
if (tagToAutoSelect) {
props.setSelectedValues([
...props.selectedValues,
tagToAutoSelect
]);
}
}
}
});
const selectProps = createMemo(() => {
return createOptions(availableTags() || [], {
key: "name",
disable: (value) => props.selectedValues.includes(value),
filterable: true, // Default
createable: createLabelValue
});
@@ -42,8 +55,6 @@ export function TagEditor(props: {
const onChange = (selected: MutinyTagItem[]) => {
props.setSelectedValues(selected);
console.log(selected);
const lastValue = selected[selected.length - 1];
if (
lastValue &&
@@ -54,7 +65,6 @@ export function TagEditor(props: {
}
};
// FIXME: eslint is mad about reactivity
const onTagTap = (tag: MutinyTagItem) => {
props.setSelectedValues([...props.selectedValues!, tag]);
};
@@ -70,10 +80,16 @@ export function TagEditor(props: {
/>
<div class="flex flex-wrap gap-2">
<Show when={availableTags() && availableTags()!.length > 0}>
<For each={availableTags()!.slice(0, 3)}>
<For
each={availableTags()!.slice(0, 3).sort(sortByLastUsed)}
>
{(tag) => (
<TinyButton
hidden={props.selectedValues.includes(tag)}
tag={tag}
// eslint-disable-next-line solid/reactivity
<TinyButton tag={tag} onClick={() => onTagTap(tag)}>
onClick={() => onTagTap(tag)}
>
{tag.name}
</TinyButton>
)}

View File

@@ -258,6 +258,7 @@ export const TinyText: ParentComponent = (props) => {
export const TinyButton: ParentComponent<{
onClick: () => void;
tag?: MutinyTagItem;
hidden?: boolean;
}> = (props) => {
// TODO: don't need to run this if it's not a contact
const [gradient] = createResource(async () => {
@@ -272,6 +273,7 @@ export const TinyButton: ParentComponent<{
return (
<button
class="rounded-lg bg-white/10 px-2 py-1"
classList={{ hidden: props.hidden }}
onClick={() => props.onClick()}
style={{ background: bg() }}
>

View File

@@ -151,7 +151,10 @@ export default {
unknown: "Unknown",
import_contacts:
"Import your contacts from nostr to see who they're zapping.",
coming_soon: "Coming soon"
coming_soon: "Coming soon",
private: "Private",
anonymous: "Anonymous",
from: "From:"
},
redshift: {
title: "Redshift",

View File

@@ -11,6 +11,7 @@ export type ParsedParams = {
amount_sats?: bigint;
network?: string;
memo?: string;
privateTag?: string;
node_pubkey?: string;
lnurl?: string;
};

View File

@@ -685,6 +685,9 @@ export default function Send() {
{i18n.t("common.private_tags")}
</SmallHeader>
<TagEditor
autoFillTag={
destination()?.privateTag
}
selectedValues={selectedContacts()}
setSelectedValues={
setSelectedContacts