Profile / Thread styles

This commit is contained in:
2023-07-24 15:30:21 +01:00
parent d292e658fc
commit 076d5d8cd5
67 changed files with 684 additions and 602 deletions

View File

@ -16,7 +16,7 @@ export default function Copy({ text, maxSize = 32, className }: CopyProps) {
<div className={`flex flex-row copy ${className}`} onClick={() => copy(text)}>
<span className="body">{trimmed}</span>
<span className="icon" style={{ color: copied ? "var(--success)" : "var(--highlight)" }}>
{copied ? <Icon name="check" size={14} /> : <Icon name="copy" size={14} />}
{copied ? <Icon name="check" size={14} /> : <Icon name="copy-solid" size={14} />}
</span>
</div>
);

View File

@ -13,7 +13,7 @@ export function LiveEvent({ ev }: { ev: NostrEvent }) {
<h3>{title}</h3>
</div>
<div>
<Link to={`/live/${encodeTLV(NostrPrefix.Address, d, undefined, ev.kind, ev.pubkey)}`}>
<Link to={`https://zap.stream/${encodeTLV(NostrPrefix.Address, d, undefined, ev.kind, ev.pubkey)}`}>
<button className="primary" type="button">
<FormattedMessage defaultMessage="Watch Live!" />
</button>

View File

@ -29,7 +29,7 @@ const Nip05 = ({ nip05, pubkey, verifyNip = true }: Nip05Params) => {
<span className="domain" data-domain={domain?.toLowerCase()}>
{domain}
</span>
<Icon name="badge" className="badge" size={16} />
<Icon name="check-verified" className="badge" size={16} />
</>
)}
</div>

View File

@ -2,7 +2,7 @@
min-height: 110px;
display: flex;
flex-direction: column;
gap: 12px;
gap: 8px;
}
.note:hover {
@ -185,7 +185,6 @@
.note.active {
border-left: 1px solid var(--highlight);
border-bottom-left-radius: 0;
margin-left: -1px;
}

View File

@ -191,7 +191,7 @@ export default function NoteFooter(props: NoteFooterProps) {
function repostIcon() {
return (
<div className={`reaction-pill ${hasReposted() ? "reacted" : ""}`} onClick={() => repost()}>
<Icon name="repost" size={17} />
<Icon name="repeat" size={18} />
{reposts.length > 0 && <div className="reaction-pill-number">{formatShort(reposts.length)}</div>}
</div>
);
@ -201,12 +201,11 @@ export default function NoteFooter(props: NoteFooterProps) {
if (!prefs.enableReactions) {
return null;
}
const reacted = hasReacted("+");
return (
<>
<div
className={`reaction-pill ${hasReacted("+") ? "reacted" : ""} `}
onClick={() => react(prefs.reactionEmoji)}>
<Icon name="heart" />
<div className={`reaction-pill ${reacted ? "reacted" : ""} `} onClick={() => react(prefs.reactionEmoji)}>
<Icon name={reacted ? "heart-solid" : "heart"} size={18} />
<div className="reaction-pill-number">{formatShort(positive.length)}</div>
</div>
</>

View File

@ -1,23 +1,14 @@
.reaction {
}
.reaction > .note {
margin: 10px 0;
}
.reaction > .header {
display: flex;
flex-direction: row;
justify-content: space-between;
flex-direction: column;
gap: 8px;
}
.reaction > .header .reply {
font-size: var(--font-size-small);
.reaction > div:nth-child(1) {
font-size: 16px;
font-weight: 600;
}
.reaction > .header > .info {
font-size: var(--font-size);
white-space: nowrap;
color: var(--font-secondary-color);
margin-right: 24px;
.reaction > div:nth-child(1) svg {
opacity: 0.5;
}

View File

@ -1,13 +1,16 @@
import "./NoteReaction.css";
import { Link } from "react-router-dom";
import { useMemo } from "react";
import { EventKind, NostrEvent, TaggedNostrEvent, NostrPrefix, EventExt } from "@snort/system";
import { EventKind, NostrEvent, TaggedNostrEvent, NostrPrefix } from "@snort/system";
import Note from "Element/Note";
import ProfileImage from "Element/ProfileImage";
import { getDisplayName } from "Element/ProfileImage";
import { eventLink, hexToBech32 } from "SnortUtils";
import NoteTime from "Element/NoteTime";
import useModeration from "Hooks/useModeration";
import { FormattedMessage } from "react-intl";
import Icon from "Icons/Icon";
import { useUserProfile } from "@snort/system-react";
import { System } from "index";
export interface NoteReactionProps {
data: TaggedNostrEvent;
@ -16,6 +19,7 @@ export interface NoteReactionProps {
export default function NoteReaction(props: NoteReactionProps) {
const { data: ev } = props;
const { isMuted } = useModeration();
const profile = useUserProfile(System, ev.pubkey);
const refEvent = useMemo(() => {
if (ev) {
@ -60,12 +64,15 @@ export default function NoteReaction(props: NoteReactionProps) {
};
return shouldNotBeRendered ? null : (
<div className="reaction">
<div className="header flex">
<ProfileImage pubkey={EventExt.getRootPubKey(ev)} />
<div className="info">
<NoteTime from={ev.created_at * 1000} />
</div>
<div className="card reaction">
<div className="flex g4">
<Icon name="repeat" size={18} />
<FormattedMessage
defaultMessage="{name} reposted"
values={{
name: getDisplayName(profile, ev.pubkey),
}}
/>
</div>
{root ? <Note data={root} options={opt} related={[]} /> : null}
{!root && refEvent ? (

View File

@ -50,8 +50,7 @@ export default function ProfileImage({
<Link
className={`pfp${className ? ` ${className}` : ""}`}
to={link === undefined ? profileLink(pubkey) : link}
onClick={handleClick}
replace={true}>
onClick={handleClick}>
<div className="avatar-wrapper">
<Avatar user={user} />
</div>

View File

@ -5,8 +5,9 @@
overflow-x: scroll;
-ms-overflow-style: none; /* for Internet Explorer, Edge */
scrollbar-width: none; /* Firefox */
margin-bottom: 18px;
white-space: nowrap;
gap: 8px;
padding: 16px 12px;
}
.tabs::-webkit-scrollbar {
@ -14,23 +15,21 @@
}
.tab {
background: var(--gray-ultradark);
color: var(--font-tertiary-color);
border: 1px solid var(--border-color);
border-radius: 16px;
border-radius: 100px;
font-weight: 600;
font-size: 14px;
padding: 6px 12px;
text-align: center;
font-feature-settings: "tnum";
}
.tab:not(:last-of-type) {
margin-right: 8px;
font-size: 16px;
padding: 10px 16px;
display: flex;
align-items: center;
justify-items: center;
gap: 6px;
}
.tab.active {
border-color: var(--font-color);
color: var(--font-color);
color: black;
background: white;
}
.tabs > div {

View File

@ -1,8 +1,9 @@
import { ReactNode } from "react";
import "./Tabs.css";
import useHorizontalScroll from "Hooks/useHorizontalScroll";
export interface Tab {
text: string;
text: ReactNode;
value: number;
disabled?: boolean;
}

View File

@ -1,7 +1,3 @@
.thread-container {
margin: 12px 0 150px 0;
}
.thread-container .hidden-note {
margin: 0;
border-radius: 0;
@ -11,11 +7,6 @@
box-shadow: none;
}
.thread-root.note > .body {
margin-top: 8px;
padding-left: 8px;
}
.thread-root.note > .body .text {
font-size: 19px;
}
@ -31,12 +22,13 @@
}
.thread-note.note {
border-radius: 0;
margin-bottom: 0;
border: 0;
}
.light .thread-note.note.card {
box-shadow: none;
.thread-note.note .zaps-summary,
.thread-note.note .footer,
.thread-note.note .body {
margin-left: 61px;
}
.thread-container .hidden-note {
@ -58,83 +50,47 @@
position: relative;
}
.line-container {
background: var(--note-bg);
}
.subthread-container.subthread-multi .line-container:before {
content: "";
position: absolute;
left: 36px;
left: calc(48px / 2 + 16px);
top: 48px;
border-left: 1px solid var(--gray-superdark);
height: 100%;
z-index: -1;
}
@media (min-width: 720px) {
.subthread-container.subthread-multi .line-container:before {
left: 48px;
}
}
.subthread-container.subthread-mid:not(.subthread-last) .line-container:after {
content: "";
position: absolute;
left: 36px;
top: 48px;
border-left: 1px solid var(--gray-superdark);
height: 100%;
}
@media (min-width: 720px) {
.subthread-container.subthread-mid:not(.subthread-last) .line-container:after {
left: 48px;
}
}
.subthread-container.subthread-mid:not(.subthread-last) .line-container:after {
.subthread-container.subthread-mid:not(.subthread-last) .line-container:before {
content: "";
position: absolute;
border-left: 1px solid var(--gray-superdark);
left: 36px;
left: calc(48px / 2 + 16px);
top: 0;
height: 48px;
}
@media (min-width: 720px) {
.subthread-container.subthread-mid:not(.subthread-last) .line-container:after {
left: 48px;
}
z-index: -1;
}
.subthread-container.subthread-last .line-container:before {
content: "";
position: absolute;
border-left: 1px solid var(--gray-superdark);
left: 36px;
left: calc(48px / 2 + 16px);
top: 0;
height: 48px;
}
@media (min-width: 720px) {
.subthread-container.subthread-last .line-container:before {
left: 48px;
}
z-index: -1;
}
.divider-container {
background: var(--note-bg);
margin-right: 16px;
}
.divider {
height: 1px;
background: var(--gray-superdark);
margin-left: 28px;
margin-right: 22px;
}
.divider.divider-small {
margin-left: 80px;
margin-left: calc(16px + 61px);
}
.thread-container .collapsed,
@ -143,11 +99,6 @@
min-height: 48px;
}
.thread-note.is-last-note {
border-bottom-left-radius: 16px;
border-bottom-right-radius: 16px;
}
.thread-container .collapsed {
background-color: var(--note-bg);
}
@ -155,13 +106,3 @@
.thread-container .hidden-note {
padding-left: 48px;
}
.thread-root.thread-root-single.note {
border-bottom-left-radius: 16px;
border-bottom-right-radius: 16px;
}
.thread-root.ghost-root {
border-top-left-radius: 16px;
border-top-right-radius: 16px;
}

View File

@ -374,9 +374,11 @@ export default function Thread() {
description: "Navigate back button on threads view",
});
return (
<div className="main-content mt10">
<BackButton onClick={goBack} text={parent ? parentText : backText} />
<div className="thread-container">
<>
<div className="main-content">
<BackButton onClick={goBack} text={parent ? parentText : backText} />
</div>
<div className="main-content">
{root && renderRoot(root)}
{root && renderChain(root.id)}
@ -392,7 +394,7 @@ export default function Thread() {
);
})}
</div>
</div>
</>
);
}

View File

@ -40,7 +40,7 @@ export default function Layout() {
};
const shouldHideNoteCreator = useMemo(() => {
const hideOn = ["/settings", "/messages", "/new", "/login", "/donate", "/p/", "/e", "/subscribe", "/live"];
const hideOn = ["/settings", "/messages", "/new", "/login", "/donate", "/p/", "/e", "/subscribe"];
return isReplyNoteCreatorShowing || hideOn.some(a => location.pathname.startsWith(a));
}, [location, isReplyNoteCreatorShowing]);
@ -50,8 +50,8 @@ export default function Layout() {
}, [location]);
useEffect(() => {
const widePage = ["/login", "/messages", "/live"];
const noScroll = ["/messages", "/live"];
const widePage = ["/login", "/messages"];
const noScroll = ["/messages"];
if (widePage.some(a => location.pathname.startsWith(a))) {
setPageClass(noScroll.some(a => location.pathname.startsWith(a)) ? "scroll-lock" : "");
} else {

View File

@ -2,28 +2,21 @@
display: flex;
flex-direction: column;
align-items: flex-start;
border: 1px solid var(--gray-superdark);
}
.profile .banner {
width: 100%;
height: 160px;
object-fit: cover;
margin-bottom: -60px;
margin-bottom: -37px;
z-index: 0;
}
@media (min-width: 720px) {
.profile .banner {
border-radius: 12px;
}
}
.profile .profile-actions {
position: absolute;
top: 72px;
right: 0;
display: flex;
flex-direction: row;
align-items: center;
align-self: flex-end;
}
.profile .icon-actions {
@ -52,13 +45,13 @@
}
.profile .profile-wrapper {
margin: 0 16px;
width: calc(100% - 32px);
margin: 0 16px 12px 16px;
display: flex;
flex-direction: column;
align-items: flex-start;
position: relative;
overflow: hidden;
gap: 16px;
}
.profile p {
@ -66,21 +59,26 @@
}
.details-wrapper > .name > h2 {
margin: 12px 0 0 0;
margin: 0 0 4px 0;
font-weight: 600;
font-size: 19px;
line-height: 23px;
font-size: 21px;
}
.details-wrapper > .name > .nip05 {
font-size: 15px;
}
.profile-wrapper > .avatar-wrapper {
z-index: 1;
display: flex;
justify-content: space-between;
}
.profile-wrapper > .avatar-wrapper .avatar {
width: 120px;
height: 120px;
width: 100px;
height: 100px;
background-image: var(--img-url);
border: 3px solid var(--bg-color);
border: 3px solid #fff;
}
.profile .name {
@ -88,28 +86,30 @@
flex-direction: column;
}
.profile .details {
width: 100%;
.profile .about {
color: var(--font-secondary-color);
margin-bottom: 12px;
font-weight: 400;
font-size: 14px;
line-height: 22px;
font-size: 16px;
line-height: 26px;
}
.profile .details p {
.profile .about p {
word-break: break-word;
}
.profile .details a {
.profile .about a {
color: var(--highlight);
text-decoration: none;
}
.profile .details a:hover {
.profile .about a:hover {
text-decoration: underline;
}
.profile .about .text {
font-size: inherit;
line-height: inherit;
}
.profile .btn-icon {
color: var(--font-color);
padding: 6px;
@ -118,54 +118,36 @@
.profile .details-wrapper {
display: flex;
flex-direction: column;
justify-content: space-between;
width: calc(100% - 32px);
gap: 16px;
}
.profile .details .text {
font-size: 14px;
}
.profile .links {
font-size: 14px;
margin-top: 4px;
margin-left: 2px;
margin-bottom: 12px;
}
.profile .website {
margin: 4px 0;
.profile .link-section {
display: flex;
flex-direction: column;
gap: 4px;
font-size: 15px;
line-height: 24px;
}
.profile .link {
display: flex;
flex-direction: row;
align-items: center;
}
@media (max-width: 720px) {
.profile .lnurl {
display: none;
}
}
.profile .website a {
color: var(--font-color);
gap: 8px;
}
.profile .website a {
text-decoration: none;
}
.profile .website a:hover {
text-decoration: underline;
}
.profile .lnurl {
cursor: pointer;
.profile .link svg {
color: var(--highlight);
}
.profile .ln-address {
display: flex;
flex-direction: row;
align-items: center;
.profile .lnurl {
cursor: pointer;
}
.profile .lnurl:hover {
@ -177,21 +159,9 @@
text-overflow: ellipsis;
}
.profile .links svg {
color: var(--highlight);
margin-right: 8px;
width: 12px;
height: 12px;
}
.profile .npub {
display: flex;
flex-direction: row;
align-items: center;
}
.profile .copy {
margin-top: 12px;
.profile .copy .body {
font-size: inherit;
line-height: inherit;
}
.qr-modal .pfp {

View File

@ -1,6 +1,6 @@
import "./ProfilePage.css";
import { useEffect, useState } from "react";
import { useIntl, FormattedMessage } from "react-intl";
import { FormattedMessage } from "react-intl";
import { useNavigate, useParams } from "react-router-dom";
import {
encodeTLV,
@ -109,7 +109,6 @@ function BookMarksTab({ id }: { id: HexKey }) {
}
export default function ProfilePage() {
const { formatMessage } = useIntl();
const params = useParams();
const navigate = useNavigate();
const [id, setId] = useState<string>();
@ -144,16 +143,88 @@ export default function ProfilePage() {
const follows = useFollowsFeed(id);
// tabs
const ProfileTab = {
Notes: { text: formatMessage({ defaultMessage: "Notes" }), value: NOTES },
Reactions: { text: formatMessage(messages.Reactions), value: REACTIONS },
Followers: { text: formatMessage(messages.Followers), value: FOLLOWERS },
Follows: { text: formatMessage(messages.Follows), value: FOLLOWS },
Zaps: { text: formatMessage(messages.Zaps), value: ZAPS },
Muted: { text: formatMessage(messages.Muted), value: MUTED },
Blocked: { text: formatMessage(messages.BlockedCount, { n: blocked.length }), value: BLOCKED },
Relays: { text: formatMessage(messages.Relays), value: RELAYS },
Bookmarks: { text: formatMessage(messages.Bookmarks), value: BOOKMARKS },
};
Notes: {
text: (
<>
<Icon name="pencil" size={16} />
<FormattedMessage defaultMessage="Notes" />
</>
),
value: NOTES,
},
Reactions: {
text: (
<>
<Icon name="reaction" size={16} />
<FormattedMessage defaultMessage="Reactions" />
</>
),
value: REACTIONS,
},
Followers: {
text: (
<>
<Icon name="user-v2" size={16} />
<FormattedMessage defaultMessage="Followers" />
</>
),
value: FOLLOWERS,
},
Follows: {
text: (
<>
<Icon name="stars" size={16} />
<FormattedMessage defaultMessage="Follows" />
</>
),
value: FOLLOWS,
},
Zaps: {
text: (
<>
<Icon name="zap-solid" size={16} />
<FormattedMessage defaultMessage="Zaps" />
</>
),
value: ZAPS,
},
Muted: {
text: (
<>
<Icon name="mute" size={16} />
<FormattedMessage defaultMessage="Muted" />
</>
),
value: MUTED,
},
Blocked: {
text: (
<>
<Icon name="block" size={16} />
<FormattedMessage defaultMessage="Blocked" />
</>
),
value: BLOCKED,
},
Relays: {
text: (
<>
<Icon name="wifi" size={16} />
<FormattedMessage defaultMessage="Relays" />
</>
),
value: RELAYS,
},
Bookmarks: {
text: (
<>
<Icon name="bookmark-solid" size={16} />
<FormattedMessage defaultMessage="Bookmarks" />
</>
),
value: BOOKMARKS,
},
} as { [key: string]: Tab };
const [tab, setTab] = useState<Tab>(ProfileTab.Notes);
const optionalTabs = [ProfileTab.Zaps, ProfileTab.Relays, ProfileTab.Bookmarks, ProfileTab.Muted].filter(a =>
unwrap(a)
@ -179,34 +250,48 @@ export default function ProfilePage() {
function username() {
return (
<div className="name">
<h2>
{user?.display_name || user?.name || "Nostrich"}
<FollowsYou followsMe={follows.includes(loginPubKey ?? "")} />
</h2>
{user?.nip05 && <Nip05 nip05={user.nip05} pubkey={user.pubkey} />}
<>
<div className="name">
<h2>
{user?.display_name || user?.name || "Nostrich"}
<FollowsYou followsMe={follows.includes(loginPubKey ?? "")} />
</h2>
{user?.nip05 && <Nip05 nip05={user.nip05} pubkey={user.pubkey} />}
</div>
<BadgeList badges={badges} />
<Copy text={npub} />
{links()}
</div>
<div className="link-section">
<Copy text={npub} />
{links()}
</div>
</>
);
}
function tryFormatWebsite(url: string) {
try {
const u = new URL(url);
return `${u.hostname}${u.pathname !== "/" ? u.pathname : ""}`;
} catch {
// ignore
}
return url;
}
function links() {
return (
<div className="links">
<>
{user?.website && (
<div className="website f-ellipsis">
<Icon name="link" />
<div className="link website f-ellipsis">
<Icon name="link-02" size={16} />
<a href={website_url} target="_blank" rel="noreferrer">
{user.website}
{tryFormatWebsite(user.website)}
</a>
</div>
)}
{lnurl && (
<div className="lnurl f-ellipsis" onClick={() => setShowLnQr(true)}>
<Icon name="zap" />
<div className="link lnurl f-ellipsis" onClick={() => setShowLnQr(true)}>
<Icon name="zapCircle" size={16} />
{lnurl.name}
</div>
)}
@ -218,14 +303,14 @@ export default function ProfilePage() {
author={id}
target={user?.display_name || user?.name}
/>
</div>
</>
);
}
function bio() {
return (
aboutText.length > 0 && (
<div dir="auto" className="details">
<div dir="auto" className="about">
{about}
</div>
)
@ -296,8 +381,12 @@ export default function ProfilePage() {
function avatar() {
return (
<div className="avatar-wrapper">
<div className="avatar-wrapper w-max">
<Avatar user={user} />
<div className="profile-actions">
{renderIcons()}
{!isMe && id && <FollowButton pubkey={id} />}
</div>
</div>
);
}
@ -356,12 +445,8 @@ export default function ProfilePage() {
function userDetails() {
if (!id) return;
return (
<div className="details-wrapper">
<div className="details-wrapper w-max">
{username()}
<div className="profile-actions">
{renderIcons()}
{!isMe && <FollowButton pubkey={id} />}
</div>
{bio()}
</div>
);
@ -374,9 +459,9 @@ export default function ProfilePage() {
const w = window.document.querySelector(".page")?.clientWidth;
return (
<>
<div className="profile flex">
<div className="profile">
{user?.banner && <ProxyImg alt="banner" className="banner" src={user.banner} size={w} />}
<div className="profile-wrapper flex">
<div className="profile-wrapper w-max">
{avatar()}
{userDetails()}
</div>

View File

@ -31,15 +31,6 @@ export default function RootPage() {
const { publicKey: pubKey, tags, preferences } = useLogin();
const [rootType, setRootType] = useState<RootPage>("following");
useEffect(() => {
if (location.pathname === "/") {
const t = pubKey ? preferences.defaultRootTab ?? "/notes" : "/global";
navigate(t, {
replace: true,
});
}
}, [location]);
const menuItems = [
{
tab: "following",
@ -107,6 +98,18 @@ export default function RootPage() {
element: ReactNode;
}>;
useEffect(() => {
if (location.pathname === "/") {
const t = pubKey ? preferences.defaultRootTab ?? "/notes" : "/global";
navigate(t);
} else {
const currentTab = menuItems.find(a => a.path === location.pathname)?.tab;
if (currentTab) {
setRootType(currentTab);
}
}
}, [location]);
function currentMenuItem() {
if (location.pathname.startsWith("/t/")) {
return (
@ -139,8 +142,7 @@ export default function RootPage() {
{menuItems.map(a => (
<MenuItem
onClick={() => {
setRootType(a.tab);
navigate(a.path, { replace: true });
navigate(a.path);
}}>
{a.element}
</MenuItem>
@ -148,8 +150,7 @@ export default function RootPage() {
{tags.item.map(v => (
<MenuItem
onClick={() => {
setRootType("tags");
navigate(`/t/${v}`, { replace: true });
navigate(`/t/${v}`);
}}>
<Icon name="hash" />
{v}

View File

@ -9,7 +9,7 @@
--font-size-tiny: 11px;
--modal-bg-color: rgba(0, 0, 0, 0.8);
--note-bg: #0c0c0c;
--highlight: #8b5cf6;
--highlight: #ac88ff;
--error: #ff6053;
--success: #2ad544;
--warning: #ff8800;
@ -23,6 +23,7 @@
--gray-tertiary: #444;
--gray-dark: #2b2b2b;
--gray-superdark: #1a1a1a;
--gray-ultradark: #111;
--gray-gradient: linear-gradient(to bottom right, var(--gray-superlight), var(--gray), var(--gray-light));
--snort-gradient: linear-gradient(90deg, #a178ff 0%, #ff6baf 100%);
--dm-gradient: linear-gradient(90deg, #5722d2 0%, #db1771 100%);
@ -123,10 +124,17 @@ body #root > div:not(.page) header {
}
.card {
padding: 16px;
padding: 12px 16px;
border-bottom: 1px solid var(--gray-superdark);
}
/* Card inside card */
.card .card {
border: 1px solid var(--gray-superdark);
border-radius: 16px;
min-height: 0;
}
.card .header {
display: flex;
flex-direction: row;
@ -407,6 +415,11 @@ input:disabled {
a {
color: inherit;
line-height: 1.3em;
text-decoration: none;
}
a:hover {
text-decoration: underline;
}
a.ext {

View File

@ -17,6 +17,9 @@
"+vVZ/G": {
"defaultMessage": "Connect"
},
"+xliwN": {
"defaultMessage": "{name} reposted"
},
"/4tOwT": {
"defaultMessage": "Skip"
},
@ -36,6 +39,9 @@
"/n5KSF": {
"defaultMessage": "{n} ms"
},
"00LcfG": {
"defaultMessage": "Load more"
},
"08zn6O": {
"defaultMessage": "Export Keys"
},
@ -438,6 +444,9 @@
"IEwZvs": {
"defaultMessage": "Are you sure you want to unpin this note?"
},
"IKKHqV": {
"defaultMessage": "Follows"
},
"INSqIz": {
"defaultMessage": "Twitter username..."
},

View File

@ -5,12 +5,14 @@
"+vA//S": "Logins",
"+vIQlC": "Please make sure to save the following password in order to manage your handle in the future",
"+vVZ/G": "Connect",
"+xliwN": "{name} reposted",
"/4tOwT": "Skip",
"/JE/X+": "Account Support",
"/PCavi": "Public",
"/RD0e2": "Nostr uses digital signature technology to provide tamper proof notes which can safely be replicated to many relays to provide redundant storage of your content.",
"/d6vEc": "Make your profile easier to find and share",
"/n5KSF": "{n} ms",
"00LcfG": "Load more",
"08zn6O": "Export Keys",
"0Azlrb": "Manage",
"0BUTMv": "Search...",
@ -87,7 +89,6 @@
"B6+XJy": "zapped",
"B6H7eJ": "nsec, npub, nip-05, hex",
"BGCM48": "Write access to Snort relay, with 1 year of event retention",
"BGxpTN": "Stream Chat",
"BOUMjw": "No nostr users found for {twitterUsername}",
"BOr9z/": "Snort is an open source project built by passionate people in their free time",
"BWpuKl": "Update",
@ -144,6 +145,7 @@
"HbefNb": "Open Wallet",
"IDjHJ6": "Thanks for using Snort, please consider donating if you can.",
"IEwZvs": "Are you sure you want to unpin this note?",
"IKKHqV": "Follows",
"INSqIz": "Twitter username...",
"IUZC+0": "This means that nobody can modify notes which you have created and everybody can easily verify that the notes they are reading are created by you.",
"Ig9/a1": "Sent {n} sats to {name}",
@ -268,7 +270,6 @@
"c+oiJe": "Install Extension",
"c35bj2": "If you have an enquiry about your NIP-05 order please DM {link}",
"c3g2hL": "Broadcast Again",
"cE4Hfw": "Discover",
"cFbU1B": "Using Alby? Go to {link} to get your NWC config!",
"cPIKU2": "Following",
"cQfLWb": "URL..",
@ -285,7 +286,6 @@
"eHAneD": "Reaction emoji",
"eJj8HD": "Get Verified",
"eSzf2G": "A single zap of {nIn} sats will allocate {nOut} sats to the zap pool.",
"fBI91o": "Zap",
"fOksnD": "Can't vote because LNURL service does not support zaps",
"fWZYP5": "Pinned",
"filwqD": "Read",
@ -366,7 +366,6 @@
"pzTOmv": "Followers",
"qD9EUF": "Email <> DM bridge for your Snort nostr address",
"qDwvZ4": "Unknown error",
"qInqHy": "Message...",
"qMx1sA": "Default Zap amount",
"qUJTsT": "Blocked",
"qdGuQo": "Your Private Key Is (do not share this with anyone)",
@ -426,4 +425,4 @@
"zjJZBd": "You're ready!",
"zonsdq": "Failed to load LNURL service",
"zvCDao": "Automatically show latest notes"
}
}