Add lnbc to DMs

This commit is contained in:
Bojan Mojsilovic 2024-04-05 15:16:45 +02:00
parent 8d2124a56b
commit f4b3cf831e
4 changed files with 267 additions and 24 deletions

View File

@ -150,6 +150,170 @@
}
}
}
&.noBack {
background-color: unset;
}
}
.lnbcAlter {
width: 100%;
min-height: 158px;
background-color: none;
border-radius: var(--border-radius-small);
display: flex;
flex-direction: column;
gap: 6px;
padding: 12px 0;
position: relative;
.paymentOverlay {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: var(--background-site);
opacity: 0.6;
display: flex;
justify-content: center;
align-items: center;
}
.header {
display: flex;
align-items: center;
justify-content: space-between;
width: 100%;
height: 20px;
.title {
display: flex;
justify-content: flex-start;
align-items: center;
color: white;
font-size: 15px;
font-weight: 700;
line-height: 16px;
}
.headerActions {
display: flex;
justify-content: flex-end;
align-items: center;
gap: 2px;
button {
.qrIcon {
width: 18px;
height: 18px;
display: inline-block;
margin: 0px;
background-color: white;
-webkit-mask: url(../../assets/icons/qr_code.svg) no-repeat 0px / 18px;
mask: url(../../assets/icons/qr_code.svg) no-repeat 0px / 18px;
}
.copyIcon {
width: 18px;
height: 18px;
display: inline-block;
margin: 0px;
background-color: white;
-webkit-mask: url(../../assets/icons/copy_border.svg) no-repeat 0px / 18px;
mask: url(../../assets/icons/copy_border.svg) no-repeat 0px / 18px;
}
&:hover {
.qrIcon, .copyIcon {
background-color: white;
}
}
}
.copyDone {
width: 30px;
height: 30px;
display: flex;
justify-content: center;
align-items: center;
.checkIcon {
width: 18px;
height: 18px;
display: inline-block;
margin: 0px;
background-color: var(--success-bright);
-webkit-mask: url(../../assets/icons/check.svg) no-repeat 0px / 18px;
mask: url(../../assets/icons/check.svg) no-repeat 0px / 18px;
}
}
}
}
.body {
display: flex;
flex-direction: column;
flex-grow: 1;
gap: 8px;
.description {
color: white;
font-size: 15px;
font-weight: 400;
line-height: 18px;
}
.amount {
color: white;
font-size: 24px;
font-weight: 600;
line-height: 24px;
}
}
.footer {
height: 36px;
width: 100%;
display: flex;
justify-content: space-between;
align-items: flex-end;
.expiryDate {
color: white;
font-size: 15px;
font-weight: 400;
line-height: 18px;
letter-spacing: 0.15px;
}
.expiredDate {
color: white;
font-size: 15px;
font-weight: 400;
line-height: 18px;
letter-spacing: 0.15px;
}
.payAction {
height: 36px;
min-width: 120px;
button {
width: 100%;
height: 100%;
color: var(--accent);
background-color: white;
}
}
}
&.noBack {
background-color: unset;
}
}
.lnIcon {

View File

@ -22,7 +22,7 @@ import { useIntl } from '@cookbook/solid-intl';
import { lnInvoice } from '../../translations';
const Lnbc: Component< { id?: string, lnbc: string } > = (props) => {
const Lnbc: Component< { id?: string, lnbc: string, alternative?: boolean, noBack?: boolean } > = (props) => {
const app = useAppContext();
const toast = useToastContext();
@ -151,8 +151,17 @@ const Lnbc: Component< { id?: string, lnbc: string } > = (props) => {
}
};
const klass = () => {
let k = props.alternative ? styles.lnbcAlter : styles.lnbc;
if (props.noBack) {
k += ` ${styles.noBack}`
}
return k;
}
return (
<div id={props.id} class={styles.lnbc}>
<div id={props.id} class={klass()}>
<Show when={paymentInProgress()}>
<div class={styles.paymentOverlay}>
<Loader />

View File

@ -26,7 +26,7 @@
align-items: flex-start;
max-width: calc(100% - 48px);
.message {
.message, .messageLn {
@include messageContent();
@if $align-end {
@ -46,12 +46,18 @@
background-color: var(--subtile-devider);
}
}
.messageLn {
display: flex;
width: calc(500px + 12px - 40px) !important;
}
.threadTime {
color: var(--text-tertiary-2);
font-weight: 400;
font-size: 12px;
line-height: 16px;
}
}
.messagesContent {
@ -258,7 +264,7 @@
.myThread {
@include thread(true);
.threadMessages {
.message {
.message, .messageLn {
color: var(--text-primary-button);
background-color: var(--accent);
border-radius: 12px 0px 0px 12px;
@ -279,7 +285,7 @@
.theirThread {
@include thread(false);
.threadMessages {
.message {
.message, .messageLn {
background-color: var(--background-input);
border-radius: 0px 12px 12px 0px;
&:last-child {

View File

@ -1,11 +1,11 @@
import { useIntl } from '@cookbook/solid-intl';
import { nip19 } from 'nostr-tools';
import { Component, createEffect, createSignal, For, onCleanup, onMount, Show } from 'solid-js';
import { Component, createEffect, createSignal, For, JSXElement, Match, onCleanup, onMount, Show, Switch } from 'solid-js';
import Avatar from '../components/Avatar/Avatar';
import { useAccountContext } from '../contexts/AccountContext';
import { useMessagesContext } from '../contexts/MessagesContext';
import { nip05Verification, truncateNpub, userName } from '../stores/profile';
import { PrimalNote, PrimalUser } from '../types/primal';
import { DirectMessage, DirectMessageThread, PrimalNote, PrimalUser } from '../types/primal';
import { date } from '../lib/dates';
import styles from './Messages.module.scss';
@ -20,7 +20,7 @@ import SearchOption from '../components/Search/SearchOption';
import { debounce, isVisibleInContainer, uuidv4 } from '../utils';
import { useSearchContext } from '../contexts/SearchContext';
import { createStore } from 'solid-js/store';
import { editMentionRegex, emojiSearchLimit } from '../constants';
import { editMentionRegex, emojiSearchLimit, linebreakRegex } from '../constants';
import Search from '../components/Search/Search';
import { useProfileContext } from '../contexts/ProfileContext';
import Paginator from '../components/Paginator/Paginator';
@ -35,6 +35,7 @@ import {
import PageCaption from '../components/PageCaption/PageCaption';
import { useMediaContext } from '../contexts/MediaContext';
import PageTitle from '../components/PageTitle/PageTitle';
import Lnbc from '../components/Lnbc/Lnbc';
type AutoSizedTextArea = HTMLTextAreaElement & { _baseScrollHeight: number };
@ -294,6 +295,7 @@ const Messages: Component = () => {
if (!messages) {
return message;
}
return parseNoteLinks(
parseNpubLinks(
highlightHashtags(
@ -831,6 +833,13 @@ const Messages: Component = () => {
newMessageInput.dispatchEvent(e);
};
const msgHasInvoice = (msg: DirectMessage) => {
const r =/(\s+|\r\n|\r|\n|^)lnbc[a-zA-Z0-9]+/;
const test = r.test(msg.content);
return test
};
createEffect(() => {
if (account?.hasPublicKey()) {
profile?.actions.setProfileKey(account.publicKey)
@ -884,6 +893,75 @@ const Messages: Component = () => {
newMessageInput && setMessage(newMessageInput.value)
}
const renderMessage = (msg: DirectMessage, thread: DirectMessageThread) => {
if (!msgHasInvoice(msg)) {
return (
<div
class={styles.message}
data-event-id={msg.id}
title={date(msg.created_at || 0).date.toLocaleString()}
innerHTML={parseMessage(msg.content)}
></div>
);
};
let sections: string[] = [];
let content = msg.content.replace(linebreakRegex, ' __LB__ ').replace(/\s+/g, ' __SP__ ');
let tokens: string[] = content.split(/[\s]+/);
let sectionIndex = 0;
tokens.forEach((t) => {
if (t.startsWith('lnbc')) {
if (sections[sectionIndex]) sectionIndex++;
sections[sectionIndex] = t;
sectionIndex++;
}
else {
let c = t;
const prev = sections[sectionIndex] || '';
if (t === '__SP__') {
c = prev.length === 0 ? '' : ' ';
}
if (t === '__LB__') {
c = prev.length === 0 ? '' : '\r';
}
sections[sectionIndex] = prev + c;
}
});
return (
<For each={sections.reverse()}>
{section => (
<Switch fallback={
<div
class={styles.message}
data-event-id={msg.id}
title={date(msg.created_at || 0).date.toLocaleString()}
innerHTML={parseMessage(section)}
></div>
}>
<Match when={section.startsWith('lnbc')}>
<div
class={styles.messageLn}
data-event-id={msg.id}
title={date(msg.created_at || 0).date.toLocaleString()}
>
<Lnbc lnbc={section} noBack={true} alternative={!isSelectedSender(thread.author)} />
</div>
</Match>
</Switch>
)}
</For>
);
};
return (
<div>
<PageTitle title={intl.formatMessage(tMessages.title)} />
@ -1064,14 +1142,7 @@ const Messages: Component = () => {
</A>
<div class={styles.threadMessages}>
<For each={thread.messages}>
{(msg) => (
<div
class={styles.message}
data-event-id={msg.id}
title={date(msg.created_at || 0).date.toLocaleString()}
innerHTML={parseMessage(msg.content)}
></div>
)}
{msg => renderMessage(msg, thread)}
</For>
</div>
<Show when={thread.messages[0]}>
@ -1091,14 +1162,7 @@ const Messages: Component = () => {
</A>
<div class={styles.threadMessages}>
<For each={thread.messages}>
{(msg) => (
<div
class={styles.message}
data-event-id={msg.id}
title={date(msg.created_at || 0).date.toLocaleString()}
innerHTML={parseMessage(msg.content)}
></div>
)}
{msg => renderMessage(msg, thread)}
</For>
</div>
<Show when={thread.messages[0]}>