chore: cleanup
continuous-integration/drone/push Build is running Details

This commit is contained in:
Kieran 2023-11-16 15:54:02 +00:00
parent 981ab5790a
commit 5a63a21fec
Signed by: Kieran
GPG Key ID: DE71CEB3925BE941
6 changed files with 127 additions and 78 deletions

View File

@ -314,18 +314,18 @@ export function NoteCreator() {
onChange={e => {
note.update(
v =>
(v.selectedCustomRelays =
// set false if all relays selected
e.target.checked &&
(v.selectedCustomRelays =
// set false if all relays selected
e.target.checked &&
note.selectedCustomRelays &&
note.selectedCustomRelays.length == a.length - 1
? undefined
: // otherwise return selectedCustomRelays with target relay added / removed
a.filter(el =>
el === r
? e.target.checked
: !note.selectedCustomRelays || note.selectedCustomRelays.includes(el),
)),
? undefined
: // otherwise return selectedCustomRelays with target relay added / removed
a.filter(el =>
el === r
? e.target.checked
: !note.selectedCustomRelays || note.selectedCustomRelays.includes(el),
)),
);
}}
/>
@ -394,9 +394,9 @@ export function NoteCreator() {
onChange={e =>
note.update(
v =>
(v.zapSplits = arr.map((vv, ii) =>
ii === i ? { ...vv, weight: Number(e.target.value) } : vv,
)),
(v.zapSplits = arr.map((vv, ii) =>
ii === i ? { ...vv, weight: Number(e.target.value) } : vv,
)),
)
}
/>
@ -572,35 +572,43 @@ export function NoteCreator() {
</>
)}
{note.preview && getPreviewNote()}
{!note.preview && (<>
<div onPaste={handlePaste} className={classNames("note-creator", { poll: Boolean(note.pollOptions) })}>
<Textarea
onDragOver={handleDragOver}
onDragLeave={handleDragLeave}
onDrop={handleDrop}
autoFocus
className={classNames("textarea", { "textarea--focused": note.active })}
onChange={c => onChange(c)}
value={note.note}
onFocus={() => note.update(v => (v.active = true))}
onKeyDown={e => {
if (e.key === "Enter" && e.metaKey) {
sendNote().catch(console.warn);
}
}}
/>
{renderPollOptions()}
</div>
<div className="flex flex-col g4">
<TagsInput value={note.hashTags} onChange={e => note.update(s => s.hashTags = e)} placeHolder={formatMessage({
defaultMessage: "Add up to 4 hashtags"
})} separators={["Enter", ","]} />
{note.hashTags.length > 4 && <small className="warning">
<FormattedMessage defaultMessage="Try to use less than 4 hashtags to stay on topic 🙏" />
</small>}
<TrendingHashTagsLine onClick={t => note.update(s => s.hashTags = appendDedupe(s.hashTags, [t]))} />
</div>
</>
{!note.preview && (
<>
<div onPaste={handlePaste} className={classNames("note-creator", { poll: Boolean(note.pollOptions) })}>
<Textarea
onDragOver={handleDragOver}
onDragLeave={handleDragLeave}
onDrop={handleDrop}
autoFocus
className={classNames("textarea", { "textarea--focused": note.active })}
onChange={c => onChange(c)}
value={note.note}
onFocus={() => note.update(v => (v.active = true))}
onKeyDown={e => {
if (e.key === "Enter" && e.metaKey) {
sendNote().catch(console.warn);
}
}}
/>
{renderPollOptions()}
</div>
<div className="flex flex-col g4">
<TagsInput
value={note.hashTags}
onChange={e => note.update(s => (s.hashTags = e))}
placeHolder={formatMessage({
defaultMessage: "Add up to 4 hashtags",
})}
separators={["Enter", ","]}
/>
{note.hashTags.length > 4 && (
<small className="warning">
<FormattedMessage defaultMessage="Try to use less than 5 hashtags to stay on topic 🙏" />
</small>
)}
<TrendingHashTagsLine onClick={t => note.update(s => (s.hashTags = appendDedupe(s.hashTags, [t])))} />
</div>
</>
)}
{uploader.progress.length > 0 && <FileUploadProgress progress={uploader.progress} />}
{noteCreatorFooter()}
@ -627,7 +635,7 @@ export function NoteCreator() {
}
function TrendingHashTagsLine(props: { onClick: (tag: string) => void }) {
const [hashtags, setHashtags] = useState<Array<{ hashtag: string, posts: number }>>();
const [hashtags, setHashtags] = useState<Array<{ hashtag: string; posts: number }>>();
const { lang } = useLocale();
async function loadTrendingHashtags() {
@ -641,14 +649,18 @@ function TrendingHashTagsLine(props: { onClick: (tag: string) => void }) {
}, []);
if (!hashtags || hashtags.length === 0) return;
return <div className="flex flex-col g4">
<small>
<FormattedMessage defaultMessage="Popular Hashtags" />
</small>
<div className="flex g4 flex-wrap">
{hashtags.slice(0, 5).map(a => <span className="px-2 py-1 bg-dark rounded-full pointer nowrap" onClick={() => props.onClick(a.hashtag)}>
#{a.hashtag}
</span>)}
return (
<div className="flex flex-col g4">
<small>
<FormattedMessage defaultMessage="Popular Hashtags" />
</small>
<div className="flex g4 flex-wrap">
{hashtags.slice(0, 5).map(a => (
<span className="px-2 py-1 bg-dark rounded-full pointer nowrap" onClick={() => props.onClick(a.hashtag)}>
#{a.hashtag}
</span>
))}
</div>
</div>
</div>
}
);
}

View File

@ -7,29 +7,33 @@ import { HashTagHeader } from "Pages/HashTagsPage";
import { useLocale } from "IntlProvider";
export default function TrendingHashtags({ title }: { title?: ReactNode }) {
const [hashtags, setHashtags] = useState<Array<{ hashtag: string, posts: number }>>();
const [error, setError] = useState<Error>();
const { lang } = useLocale();
const [hashtags, setHashtags] = useState<Array<{ hashtag: string; posts: number }>>();
const [error, setError] = useState<Error>();
const { lang } = useLocale();
async function loadTrendingHashtags() {
const api = new NostrBandApi();
const rsp = await api.trendingHashtags(lang);
setHashtags(rsp.hashtags);
}
async function loadTrendingHashtags() {
const api = new NostrBandApi();
const rsp = await api.trendingHashtags(lang);
setHashtags(rsp.hashtags);
}
useEffect(() => {
loadTrendingHashtags().catch(e => {
if (e instanceof Error) {
setError(e);
}
});
}, []);
useEffect(() => {
loadTrendingHashtags().catch(e => {
if (e instanceof Error) {
setError(e);
}
});
}, []);
if (error) return <ErrorOrOffline error={error} onRetry={loadTrendingHashtags} className="p" />;
if (!hashtags) return <PageSpinner />;
if (error) return <ErrorOrOffline error={error} onRetry={loadTrendingHashtags} className="p" />;
if (!hashtags) return <PageSpinner />;
return <>
{title}
{hashtags.map(a => <HashTagHeader tag={a.hashtag} className="bb p" />)}
return (
<>
{title}
{hashtags.map(a => (
<HashTagHeader tag={a.hashtag} events={a.posts} className="bb p" />
))}
</>
);
}

View File

@ -20,9 +20,9 @@ export interface TrendingNoteResponse {
export interface TrendingHashtagsResponse {
hashtags: Array<{
hashtag: string,
posts: number
}>
hashtag: string;
posts: number;
}>;
}
export interface SuggestedFollow {

View File

@ -12,6 +12,7 @@ import { setTags } from "Login";
import AsyncButton from "Element/AsyncButton";
import ProfileImage from "Element/User/ProfileImage";
import classNames from "classnames";
import { formatShort } from "Number";
const HashTagsPage = () => {
const params = useParams();
@ -34,7 +35,7 @@ const HashTagsPage = () => {
export default HashTagsPage;
export function HashTagHeader({ tag, className }: { tag: string, className?: string }) {
export function HashTagHeader({ tag, events, className }: { tag: string; events?: number; className?: string }) {
const login = useLogin();
const isFollowing = useMemo(() => {
return login.tags.item.includes(tag);
@ -63,7 +64,19 @@ export function HashTagHeader({ tag, className }: { tag: string, className?: str
return (
<div className={classNames("flex flex-col", className)}>
<div className="flex items-center justify-between">
<b className="text-lg">#{tag}</b>
<div className="flex g8 items-center">
<b className="text-xl">#{tag}</b>
{events && (
<small>
<FormattedMessage
defaultMessage="{n} notes"
values={{
n: formatShort(events),
}}
/>
</small>
)}
</div>
{isFollowing ? (
<AsyncButton className="secondary" onClick={() => followTags(login.tags.item.filter(t => t !== tag))}>
<FormattedMessage defaultMessage="Unfollow" />

View File

@ -298,6 +298,9 @@
"defaultMessage": "Parent",
"description": "Link to parent note in thread"
},
"AIgmDy": {
"defaultMessage": "Add up to 4 hashtags"
},
"AN0Z7Q": {
"defaultMessage": "Muted Words"
},
@ -879,6 +882,9 @@
"XICsE8": {
"defaultMessage": "File hosts"
},
"XXm7jJ": {
"defaultMessage": "Trending Hashtags"
},
"XgWvGA": {
"defaultMessage": "Reactions"
},
@ -993,9 +999,15 @@
"d7d0/x": {
"defaultMessage": "LN Address"
},
"d8gpCh": {
"defaultMessage": "Try to use less than 5 hashtags to stay on topic 🙏"
},
"dOQCL8": {
"defaultMessage": "Display name"
},
"ddd3JX": {
"defaultMessage": "Popular Hashtags"
},
"deEeEI": {
"defaultMessage": "Register"
},
@ -1382,6 +1394,9 @@
"ugyJnE": {
"defaultMessage": "Sending notes and other stuff"
},
"un1nGw": {
"defaultMessage": "{n} notes"
},
"usAvMr": {
"defaultMessage": "Edit Profile"
},

View File

@ -98,6 +98,7 @@
"9wO4wJ": "Lightning Invoice",
"ABAQyo": "Chats",
"ADmfQT": "Parent",
"AIgmDy": "Add up to 4 hashtags",
"AN0Z7Q": "Muted Words",
"ASRK0S": "This author has been muted",
"Ai8VHU": "Unlimited note retention on Snort relay",
@ -289,6 +290,7 @@
"X7xU8J": "nsec, npub, nip-05, hex, mnemonic",
"XECMfW": "Send usage metrics",
"XICsE8": "File hosts",
"XXm7jJ": "Trending Hashtags",
"XgWvGA": "Reactions",
"Xopqkl": "Your default zap amount is {number} sats, example values are calculated from this.",
"XrSk2j": "Redeem",
@ -326,7 +328,9 @@
"d+6YsV": "Lists to mute:",
"d6CyG5": "History",
"d7d0/x": "LN Address",
"d8gpCh": "Try to use less than 5 hashtags to stay on topic 🙏",
"dOQCL8": "Display name",
"ddd3JX": "Popular Hashtags",
"deEeEI": "Register",
"dmsiLv": "A default Zap Pool split of {n} has been configured for {site} developers, you can disable it at any time in {link}",
"e61Jf3": "Coming soon",
@ -455,6 +459,7 @@
"uSV4Ti": "Reposts need to be manually confirmed",
"uc0din": "Send sats splits to",
"ugyJnE": "Sending notes and other stuff",
"un1nGw": "{n} notes",
"usAvMr": "Edit Profile",
"v8lolG": "Start chat",
"vB3oQ/": "Must be a contact list or pubkey list",