diff --git a/packages/app/public/icons.svg b/packages/app/public/icons.svg
index f40715f4..27b9b9d1 100644
--- a/packages/app/public/icons.svg
+++ b/packages/app/public/icons.svg
@@ -145,5 +145,12 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/packages/app/src/Element/Avatar.css b/packages/app/src/Element/Avatar.css
index 18305b12..178f52d4 100644
--- a/packages/app/src/Element/Avatar.css
+++ b/packages/app/src/Element/Avatar.css
@@ -8,6 +8,7 @@
background-clip: content-box, border-box;
background-size: cover;
box-sizing: border-box;
+ background-color: var(--gray);
}
.avatar[data-domain="snort.social"] {
diff --git a/packages/app/src/Element/AvatarEditor.tsx b/packages/app/src/Element/AvatarEditor.tsx
new file mode 100644
index 00000000..690fc189
--- /dev/null
+++ b/packages/app/src/Element/AvatarEditor.tsx
@@ -0,0 +1,49 @@
+import Icon from "Icons/Icon";
+import { useState } from "react";
+import useFileUpload from "Upload";
+import { openFile, unwrap } from "Util";
+
+interface AvatarEditorProps {
+ picture?: string;
+ onPictureChange?: (newPicture: string) => void;
+}
+
+export default function AvatarEditor({ picture, onPictureChange }: AvatarEditorProps) {
+ const uploader = useFileUpload();
+ const [error, setError] = useState("");
+
+ async function uploadFile() {
+ setError("");
+ try {
+ const f = await openFile();
+ if (f) {
+ const rsp = await uploader.upload(f, f.name);
+ console.log(rsp);
+ if (typeof rsp?.error === "string") {
+ setError(`Upload failed: ${rsp.error}`);
+ } else {
+ onPictureChange?.(unwrap(rsp.url));
+ }
+ }
+ } catch (e) {
+ if (e instanceof Error) {
+ setError(`Upload failed: ${e.message}`);
+ } else {
+ setError(`Upload failed`);
+ }
+ }
+ }
+
+ return (
+ <>
+
+
+
uploadFile().catch(console.error)}>
+
+
+
+
+ {error && {error}}
+ >
+ );
+}
diff --git a/packages/app/src/Element/FollowListBase.tsx b/packages/app/src/Element/FollowListBase.tsx
index c072bfcf..8465f83d 100644
--- a/packages/app/src/Element/FollowListBase.tsx
+++ b/packages/app/src/Element/FollowListBase.tsx
@@ -1,12 +1,12 @@
import { ReactNode } from "react";
import { FormattedMessage } from "react-intl";
+import { HexKey } from "@snort/nostr";
import useEventPublisher from "Feed/EventPublisher";
-import { HexKey } from "@snort/nostr";
import ProfilePreview from "Element/ProfilePreview";
+import useLogin from "Hooks/useLogin";
import messages from "./messages";
-import useLogin from "Hooks/useLogin";
export interface FollowListBaseProps {
pubkeys: HexKey[];
@@ -26,7 +26,7 @@ export default function FollowListBase({ pubkeys, title, showFollowAll, showAbou
}
return (
-
+ <>
{(showFollowAll ?? true) && (
{title}
@@ -38,6 +38,6 @@ export default function FollowListBase({ pubkeys, title, showFollowAll, showAbou
{pubkeys?.map(a => (
))}
-
+ >
);
}
diff --git a/packages/app/src/Element/Hashtag.css b/packages/app/src/Element/Hashtag.css
index 52232cc2..ad81ad4d 100644
--- a/packages/app/src/Element/Hashtag.css
+++ b/packages/app/src/Element/Hashtag.css
@@ -1,3 +1,7 @@
.hashtag {
color: var(--highlight);
}
+
+.hashtag > a {
+ text-decoration: none;
+}
diff --git a/packages/app/src/Element/LinkPreview.css b/packages/app/src/Element/LinkPreview.css
index ab4d37a7..d7ab0e69 100644
--- a/packages/app/src/Element/LinkPreview.css
+++ b/packages/app/src/Element/LinkPreview.css
@@ -8,6 +8,10 @@
cursor: pointer;
}
+.link-preview-container > a {
+ text-decoration: none;
+}
+
.link-preview-title {
padding: 0 10px 10px 10px;
}
diff --git a/packages/app/src/Pages/ProfilePage.tsx b/packages/app/src/Pages/ProfilePage.tsx
index 968ad110..41f4a56c 100644
--- a/packages/app/src/Pages/ProfilePage.tsx
+++ b/packages/app/src/Pages/ProfilePage.tsx
@@ -264,14 +264,7 @@ export default function ProfilePage() {
}
case FOLLOWS: {
if (isMe) {
- return (
- <>
-
-
;
- >
- );
+ return
;
} else {
return
;
}
@@ -379,7 +372,7 @@ export default function ProfilePage() {
{isMe && blocked.length > 0 && renderTab(ProfileTab.Blocked)}
- {tabContent()}
+ {tabContent()}
>
);
}
diff --git a/packages/app/src/Pages/new/DiscoverFollows.tsx b/packages/app/src/Pages/new/DiscoverFollows.tsx
index 468e7e29..53d0ca1f 100644
--- a/packages/app/src/Pages/new/DiscoverFollows.tsx
+++ b/packages/app/src/Pages/new/DiscoverFollows.tsx
@@ -44,7 +44,7 @@ export default function DiscoverFollows() {
- {sortedReccomends.length > 0 && }
+ {sortedReccomends.length > 0 && }
);
diff --git a/packages/app/src/Pages/new/NewUserFlow.tsx b/packages/app/src/Pages/new/NewUserFlow.tsx
index d319f82a..b63fb724 100644
--- a/packages/app/src/Pages/new/NewUserFlow.tsx
+++ b/packages/app/src/Pages/new/NewUserFlow.tsx
@@ -9,6 +9,7 @@ import { hexToMnemonic } from "nip6";
import useLogin from "Hooks/useLogin";
import messages from "./messages";
+import { PROFILE } from ".";
const WhatIsSnort = () => {
return (
@@ -107,7 +108,7 @@ export default function NewUserFlow() {
-
diff --git a/packages/app/src/Pages/new/NewUsername.tsx b/packages/app/src/Pages/new/ProfileSetup.tsx
similarity index 53%
rename from packages/app/src/Pages/new/NewUsername.tsx
rename to packages/app/src/Pages/new/ProfileSetup.tsx
index e6a19446..20d6864d 100644
--- a/packages/app/src/Pages/new/NewUsername.tsx
+++ b/packages/app/src/Pages/new/ProfileSetup.tsx
@@ -1,26 +1,47 @@
-import { useState } from "react";
+import { useEffect, useState } from "react";
import { useIntl, FormattedMessage } from "react-intl";
import { useNavigate } from "react-router-dom";
import Logo from "Element/Logo";
import useEventPublisher from "Feed/EventPublisher";
+import useLogin from "Hooks/useLogin";
+import { useUserProfile } from "Hooks/useUserProfile";
+import { mapEventToProfile, UserCache } from "Cache";
+import AvatarEditor from "Element/AvatarEditor";
import messages from "./messages";
+import { DISCOVER } from ".";
-export default function NewUserName() {
+export default function ProfileSetup() {
+ const login = useLogin();
+ const myProfile = useUserProfile(login.publicKey);
const [username, setUsername] = useState("");
+ const [picture, setPicture] = useState("");
const { formatMessage } = useIntl();
const publisher = useEventPublisher();
const navigate = useNavigate();
- const nextPage = "/new/discover";
+ useEffect(() => {
+ if (myProfile) {
+ setUsername(myProfile.name ?? "");
+ setPicture(myProfile.picture ?? "");
+ }
+ }, [myProfile]);
const onNext = async () => {
- if (username.length > 0 && publisher) {
- const ev = await publisher.metadata({ name: username });
+ if ((username.length > 0 || picture.length > 0) && publisher) {
+ const ev = await publisher.metadata({
+ ...myProfile,
+ name: username,
+ picture,
+ });
publisher.broadcast(ev);
+ const profile = mapEventToProfile(ev);
+ if (profile) {
+ UserCache.set(profile);
+ }
}
- navigate(nextPage);
+ navigate(DISCOVER);
};
return (
@@ -30,13 +51,14 @@ export default function NewUserName() {
-
+
-
-
-
-
+
+
+ setPicture(p)} />
+
+
-
navigate(nextPage)}>
+ navigate(DISCOVER)}>
diff --git a/packages/app/src/Pages/new/index.tsx b/packages/app/src/Pages/new/index.tsx
index fd31e1b0..2bd6ea03 100644
--- a/packages/app/src/Pages/new/index.tsx
+++ b/packages/app/src/Pages/new/index.tsx
@@ -2,15 +2,15 @@ import "./index.css";
import { RouteObject } from "react-router-dom";
import GetVerified from "Pages/new/GetVerified";
-import NewUserName from "Pages/new/NewUsername";
+import ProfileSetup from "Pages/new/ProfileSetup";
import NewUserFlow from "Pages/new/NewUserFlow";
import ImportFollows from "Pages/new/ImportFollows";
import DiscoverFollows from "Pages/new/DiscoverFollows";
-const USERNAME = "/new/username";
-const IMPORT = "/new/import";
-const DISCOVER = "/new/discover";
-const VERIFY = "/new/verify";
+export const PROFILE = "/new/profile";
+export const IMPORT = "/new/import";
+export const DISCOVER = "/new/discover";
+export const VERIFY = "/new/verify";
export const NewUserRoutes: RouteObject[] = [
{
@@ -18,8 +18,8 @@ export const NewUserRoutes: RouteObject[] = [
element: ,
},
{
- path: USERNAME,
- element: ,
+ path: PROFILE,
+ element: ,
},
{
path: IMPORT,
diff --git a/packages/app/src/Pages/new/messages.ts b/packages/app/src/Pages/new/messages.ts
index 9c333b14..788130a5 100644
--- a/packages/app/src/Pages/new/messages.ts
+++ b/packages/app/src/Pages/new/messages.ts
@@ -37,10 +37,6 @@ export default defineMessages({
ExtensionsNostr: { defaultMessage: `You can also use these extensions to login to most Nostr sites.` },
ImproveSecurity: { defaultMessage: "Improve login security with browser extensions" },
PickUsername: { defaultMessage: "Pick a username" },
- UsernameHelp: {
- defaultMessage:
- "On Nostr, many people have the same username. User names and identity are separate things. You can get a unique identifier in the next step.",
- },
Username: { defaultMessage: "Username" },
UsernamePlaceholder: { defaultMessage: "e.g. Jack" },
PopularAccounts: { defaultMessage: "Follow some popular accounts" },
diff --git a/packages/app/src/Pages/settings/Profile.css b/packages/app/src/Pages/settings/Profile.css
index dd8be0ec..5e86ff7f 100644
--- a/packages/app/src/Pages/settings/Profile.css
+++ b/packages/app/src/Pages/settings/Profile.css
@@ -22,29 +22,31 @@
.settings .image-setting {
display: flex;
+ justify-content: space-between;
}
.settings .image-setting > div:first-child {
align-self: center;
}
-.settings .avatar,
-.settings .banner {
- margin-left: auto;
-}
-
-.settings .avatar .edit,
-.settings .banner .edit {
+.avatar .edit,
+.banner .edit {
display: flex;
align-items: center;
justify-content: center;
width: 100%;
height: 100%;
- opacity: 0;
background-color: var(--bg-color);
+ cursor: pointer;
+ opacity: 0;
+ border-radius: 100%;
}
-.settings .avatar .edit:hover {
+.avatar .edit.new {
+ opacity: 0.5;
+}
+
+.avatar .edit:hover {
opacity: 0.5;
}
diff --git a/packages/app/src/Pages/settings/Profile.tsx b/packages/app/src/Pages/settings/Profile.tsx
index de98ed8e..9beee16d 100644
--- a/packages/app/src/Pages/settings/Profile.tsx
+++ b/packages/app/src/Pages/settings/Profile.tsx
@@ -15,6 +15,7 @@ import { mapEventToProfile, UserCache } from "Cache";
import useLogin from "Hooks/useLogin";
import messages from "./messages";
+import AvatarEditor from "Element/AvatarEditor";
export interface ProfileSettingsProps {
avatar?: boolean;
@@ -36,7 +37,6 @@ export default function ProfileSettings(props: ProfileSettingsProps) {
const [website, setWebsite] = useState();
const [nip05, setNip05] = useState();
const [lud16, setLud16] = useState();
- const [reactions, setReactions] = useState();
const avatarPicture = (picture?.length ?? 0) === 0 ? Nostrich : picture;
@@ -98,13 +98,6 @@ export default function ProfileSettings(props: ProfileSettingsProps) {
}
}
- async function setNewAvatar() {
- const rsp = await uploadFile();
- if (rsp) {
- setPicture(rsp);
- }
- }
-
async function setNewBanner() {
const rsp = await uploadFile();
if (rsp) {
@@ -189,11 +182,7 @@ export default function ProfileSettings(props: ProfileSettingsProps) {
:
-
+ setPicture(p)} />
)}
{(props.banner ?? true) && (
diff --git a/packages/app/src/index.css b/packages/app/src/index.css
index 4e0a3c95..f9e3a792 100644
--- a/packages/app/src/index.css
+++ b/packages/app/src/index.css
@@ -374,7 +374,6 @@ input:disabled {
a {
color: inherit;
line-height: 1.3em;
- text-decoration: none;
}
a.ext {