diff --git a/d.ts b/d.ts index 63fda725..457c08e1 100644 --- a/d.ts +++ b/d.ts @@ -2,3 +2,8 @@ declare module "*.jpg" { const value: any export default value } + +declare module "*.svg" { + const value: any + export default value +} diff --git a/src/Element/Avatar.css b/src/Element/Avatar.css index a474f224..b3bca95e 100644 --- a/src/Element/Avatar.css +++ b/src/Element/Avatar.css @@ -2,8 +2,8 @@ border-radius: 50%; height: 210px; width: 210px; - background-image: var(--img-url), var(--gray-gradient); - border: 2px solid transparent; + background-image: var(--img-url); + border: 1px solid transparent; background-origin: border-box; background-clip: content-box, border-box; background-size: cover; diff --git a/src/Element/Copy.css b/src/Element/Copy.css index 35af72ab..2c99df14 100644 --- a/src/Element/Copy.css +++ b/src/Element/Copy.css @@ -1,15 +1,9 @@ .copy { - user-select: none; - cursor: pointer; - -webkit-tap-highlight-color: transparent; + cursor: pointer; } .copy .body { - font-family: monospace; - font-size: 14px; - background: var(--note-bg); + font-size: var(--font-size-small); color: var(--font-color); - padding: 2px 4px; - border-radius: 10px; - margin: 0 4px 0 0; + margin-right: 8px; } diff --git a/src/Element/Copy.tsx b/src/Element/Copy.tsx index 0168447c..a2e557b4 100644 --- a/src/Element/Copy.tsx +++ b/src/Element/Copy.tsx @@ -10,7 +10,7 @@ export interface CopyProps { export default function Copy({ text, maxSize = 32 }: CopyProps) { const { copy, copied, error } = useCopy(); const sliceLength = maxSize / 2 - const trimmed = text.length > maxSize ? `${text.slice(0, sliceLength)}:${text.slice(-sliceLength)}` : text + const trimmed = text.length > maxSize ? `${text.slice(0, sliceLength)}...${text.slice(-sliceLength)}` : text return (
copy(text)}> @@ -20,7 +20,7 @@ export default function Copy({ text, maxSize = 32 }: CopyProps) {
) diff --git a/src/Element/FollowButton.tsx b/src/Element/FollowButton.tsx index 747813bb..7609d5ad 100644 --- a/src/Element/FollowButton.tsx +++ b/src/Element/FollowButton.tsx @@ -7,14 +7,12 @@ import { RootState } from "State/Store"; export interface FollowButtonProps { pubkey: HexKey, - className?: string, + className?: string } export default function FollowButton(props: FollowButtonProps) { const pubkey = props.pubkey; const publiser = useEventPublisher(); const isFollowing = useSelector(s => s.login.follows?.includes(pubkey) ?? false); - const baseClassName = isFollowing ? `btn btn-warn follow-button` : `btn btn-success follow-button` - const className = props.className ? `${baseClassName} ${props.className}` : `${baseClassName}`; async function follow(pubkey: HexKey) { let ev = await publiser.addFollow(pubkey); @@ -27,8 +25,8 @@ export default function FollowButton(props: FollowButtonProps) { } return ( -
isFollowing ? unfollow(pubkey) : follow(pubkey)}> - -
+ ) -} \ No newline at end of file +} diff --git a/src/Element/FollowListBase.tsx b/src/Element/FollowListBase.tsx index 7b8dc85d..c8692f36 100644 --- a/src/Element/FollowListBase.tsx +++ b/src/Element/FollowListBase.tsx @@ -15,12 +15,12 @@ export default function FollowListBase({ pubkeys, title }: FollowListBaseProps) } return ( - <> +
{title}
-
followAll()}>Follow All
+
{pubkeys?.map(a => )} - +
) -} \ No newline at end of file +} diff --git a/src/Element/FollowsYou.css b/src/Element/FollowsYou.css index 23fb9b9e..744aa217 100644 --- a/src/Element/FollowsYou.css +++ b/src/Element/FollowsYou.css @@ -1,5 +1,5 @@ .follows-you { - color: var(--font-color); + color: var(--gray-light); font-size: var(--font-size-tiny); margin-left: .2em; font-weight: normal diff --git a/src/Element/LNURLTip.css b/src/Element/LNURLTip.css index 74e4cd25..20fb44ab 100644 --- a/src/Element/LNURLTip.css +++ b/src/Element/LNURLTip.css @@ -1,10 +1,5 @@ .lnurl-tip { - background-color: var(--note-bg); - padding: 10px; - border-radius: 10px; - width: 500px; text-align: center; - min-height: 10vh; } .lnurl-tip .btn { @@ -62,10 +57,3 @@ align-items: center; justify-content: center; } - -@media(max-width: 720px) { - .lnurl-tip { - width: 100vw; - margin: 0 10px; - } -} diff --git a/src/Element/Modal.css b/src/Element/Modal.css index 3d5ebee2..37dd7ec4 100644 --- a/src/Element/Modal.css +++ b/src/Element/Modal.css @@ -8,5 +8,20 @@ display: flex; justify-content: center; align-items: center; - z-index: 9999999; + z-index: 42; +} + +.modal-body { + background-color: var(--note-bg); + padding: 10px; + border-radius: 10px; + width: 500px; + min-height: 10vh; +} + +@media(max-width: 720px) { + .modal-body { + width: 100vw; + margin: 0 10px; + } } diff --git a/src/Element/Modal.tsx b/src/Element/Modal.tsx index d91ad504..0fefb877 100644 --- a/src/Element/Modal.tsx +++ b/src/Element/Modal.tsx @@ -17,7 +17,9 @@ export default function Modal(props: ModalProps) { return (
{ e.stopPropagation(); onClose(); }}> +
{props.children} +
) -} \ No newline at end of file +} diff --git a/src/Element/Nip05.css b/src/Element/Nip05.css index 2cc3ef46..866e62a8 100644 --- a/src/Element/Nip05.css +++ b/src/Element/Nip05.css @@ -1,7 +1,6 @@ .nip05 { justify-content: flex-start; align-items: center; - font-size: 14px; margin: .2em; } @@ -10,50 +9,8 @@ } .nip05 .nick { - color: var(--gray-light); + color: var(--font-secondary-color); font-weight: bold; - margin-right: .2em; -} - -.nip05 .domain { - color: var(--gray-superlight); - font-weight: bold; -} - -.nip05 .text-gradient { - -webkit-background-clip: text; - -webkit-text-fill-color: transparent; - background-clip: text; - text-fill-color: transparent; - background-color: var(--gray-superlight); -} - -.nip05 .domain[data-domain="snort.social"] { - background-image: var(--snort-gradient); -} - -.nip05 .domain[data-domain="nostrplebs.com"] { - background-image: var(--nostrplebs-gradient); -} - -.nip05 .domain[data-domain="nostrpurple.com"] { - background-image: var(--nostrplebs-gradient); -} - -.nip05 .domain[data-domain="nostr.fan"] { - background-image: var(--nostrplebs-gradient); -} - -.nip05 .domain[data-domain="nostrich.zone"] { - background-image: var(--nostrplebs-gradient); -} - -.nip05 .domain[data-domain="nostriches.net"] { - background-image: var(--nostrplebs-gradient); -} - -.nip05 .domain[data-domain="strike.army"] { - background-image: var(--strike-army-gradient); } .nip05 .badge { diff --git a/src/Element/Nip05.tsx b/src/Element/Nip05.tsx index d68332e2..99e860a6 100644 --- a/src/Element/Nip05.tsx +++ b/src/Element/Nip05.tsx @@ -1,7 +1,7 @@ import { useQuery } from "react-query"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; -import { faSpinner, faTriangleExclamation } from "@fortawesome/free-solid-svg-icons"; +import { faCircleCheck, faSpinner, faTriangleExclamation } from "@fortawesome/free-solid-svg-icons"; import './Nip05.css' import { HexKey } from "Nostr"; @@ -57,16 +57,20 @@ const Nip05 = (props: Nip05Params) => { const { isVerified, couldNotVerify } = useIsVerified(props.pubkey, props.nip05) return ( -
- {!isDefaultUser && ( -
- {name} -
- )} -
- {domain} +
ev.stopPropagation()}> +
+ {isDefaultUser ? ( + `${domain}` + ) : `@${name}`}
+ {isVerified && ( + + )} {!isVerified && !couldNotVerify && ( .header .reply a { + color: var(--highlight); +} + +.note>.header .reply a:hover { + text-decoration-color: var(--highlight); +} + .note>.header>.info { font-size: var(--font-size); white-space: nowrap; @@ -18,7 +26,7 @@ } .note>.body { - margin-top: 12px; + margin-top: 4px; padding-left: 56px; text-overflow: ellipsis; white-space: pre-wrap; diff --git a/src/Element/Note.tsx b/src/Element/Note.tsx index d68d1383..68a54288 100644 --- a/src/Element/Note.tsx +++ b/src/Element/Note.tsx @@ -1,6 +1,6 @@ import "./Note.css"; -import { useCallback, useMemo } from "react"; -import { useNavigate } from "react-router-dom"; +import { useCallback, useMemo, ReactNode } from "react"; +import { useNavigate, Link } from "react-router-dom"; import { default as NEvent } from "Nostr/Event"; import ProfileImage from "Element/ProfileImage"; @@ -64,21 +64,57 @@ export default function Note(props: NoteProps) { const maxMentions = 2; let replyId = ev.Thread?.ReplyTo?.Event ?? ev.Thread?.Root?.Event; - let mentions: string[] = []; + let mentions: {pk: string, name: string, link: ReactNode}[] = []; for (let pk of ev.Thread?.PubKeys) { - let u = users?.get(pk); + const u = users?.get(pk); + const npub = hexToBech32("npub", pk) + const shortNpub = npub.substring(0, 12); if (u) { - mentions.push(u.name ?? hexToBech32("npub", pk).substring(0, 12)); + mentions.push({ + pk, + name: u.name ?? shortNpub, + link: ( + + {u.name ? `@${u.name}` : shortNpub} + + ) + }); } else { - mentions.push(hexToBech32("npub", pk).substring(0, 12)); + mentions.push({ + pk, + name: shortNpub, + link: ( + + {shortNpub} + + ) + }); } } - mentions.sort((a, b) => a.startsWith("npub") ? 1 : -1); + mentions.sort((a, b) => a.name.startsWith("npub") ? 1 : -1); let othersLength = mentions.length - maxMentions - let pubMentions = mentions.length > maxMentions ? `${mentions?.slice(0, maxMentions).join(", ")} & ${othersLength} other${othersLength > 1 ? 's' : ''}` : mentions?.join(", "); + const renderMention = (m: any, idx: number) => { + return ( + <> + {idx > 0 && ", "} + {m.link} + + ) + } + const pubMentions = mentions.length > maxMentions ? ( + mentions?.slice(0, maxMentions).map(renderMention) + ) : mentions?.map(renderMention); + const others = mentions.length > maxMentions ? ` & ${othersLength} other${othersLength > 1 ? 's' : ''}` : '' return (
- {(pubMentions?.length ?? 0) > 0 ? pubMentions : replyId ? hexToBech32("note", replyId)?.substring(0, 12) : ""} + {(mentions?.length ?? 0) > 0 ? ( + <> + {pubMentions} + {others} + + ) : replyId ? ( + hexToBech32("note", replyId)?.substring(0, 12) // todo: link + ) : ""}
) } diff --git a/src/Element/NoteCreator.css b/src/Element/NoteCreator.css index 9dce9434..2a4ad48a 100644 --- a/src/Element/NoteCreator.css +++ b/src/Element/NoteCreator.css @@ -13,23 +13,28 @@ .note-creator textarea { outline: none; resize: none; - min-height: 40px; background-color: var(--note-bg); border-radius: 10px 10px 0 0; max-width: stretch; min-width: stretch; } -.note-creator .actions { +.note-creator-actions { width: 100%; + display: flex; + flex-direction: row; + align-items: center; justify-content: flex-end; margin-bottom: 5px; } .note-creator .attachment { cursor: pointer; - padding: 5px 10px; - border-radius: 10px; + margin-left: auto; +} + +.note-creator-actions button:not(:last-child) { + margin-right: 4px; } .note-creator .attachment .error { @@ -45,3 +50,26 @@ color: var(--font-color); font-size: var(--font-size); } + +.note-create-button { + width: 48px; + height: 48px; + background-color: var(--highlight); + border: none; + border-radius: 100%; + position: fixed; + bottom: 50px; + right: 16px; +} + +@media (min-width: 520px) { + .note-create-button { + right: 10vw; + } +} + +@media (min-width: 1020px) { + .note-create-button { + right: 25vw; + } +} diff --git a/src/Element/NoteCreator.tsx b/src/Element/NoteCreator.tsx index 426bfce1..3dfda16e 100644 --- a/src/Element/NoteCreator.tsx +++ b/src/Element/NoteCreator.tsx @@ -4,21 +4,26 @@ import { faPaperclip } from "@fortawesome/free-solid-svg-icons"; import "./NoteCreator.css"; +import Plus from "Icons/Plus"; import useEventPublisher from "Feed/EventPublisher"; import { openFile } from "Util"; import VoidUpload from "Feed/VoidUpload"; import { FileExtensionRegex } from "Const"; import Textarea from "Element/Textarea"; -import Event, { default as NEvent } from "Nostr/Event"; +import Modal from "Element/Modal"; +import { default as NEvent } from "Nostr/Event"; export interface NoteCreatorProps { + show: boolean + setShow: (s: boolean) => void replyTo?: NEvent, onSend?: Function, - show: boolean, + onClose?(): void autoFocus: boolean } export function NoteCreator(props: NoteCreatorProps) { + const { show, setShow } = props const publisher = useEventPublisher(); const [note, setNote] = useState(); const [error, setError] = useState(); @@ -68,14 +73,23 @@ export function NoteCreator(props: NoteCreatorProps) { } } + function cancel(ev: any) { + setShow(false) + setNote("") + } + function onSubmit(ev: React.MouseEvent) { ev.stopPropagation(); sendNote().catch(console.warn); } - if (!props.show) return null; return ( <> + + {show && ( +
-
sendDm()}>Send
+
) -} \ No newline at end of file +} diff --git a/src/Pages/DonatePage.tsx b/src/Pages/DonatePage.tsx index b5be933c..8421bcfd 100644 --- a/src/Pages/DonatePage.tsx +++ b/src/Pages/DonatePage.tsx @@ -44,7 +44,7 @@ const DonatePage = () => { } return ( -
+

Help fund the development of Snort

Snort is an open source project built by passionate people in their free time diff --git a/src/Pages/Layout.css b/src/Pages/Layout.css index 76462f49..d8664c1a 100644 --- a/src/Pages/Layout.css +++ b/src/Pages/Layout.css @@ -1,20 +1,37 @@ .logo { cursor: pointer; + font-weight: bold; + font-size: 29px; } -.unread-count { - width: 20px; - height: 20px; - border: 1px solid; - border-radius: 100%; - position: relative; - padding: 3px; - line-height: 1.5em; - top: -10px; - left: -10px; - font-size: var(--font-size-small); - background-color: var(--error); - color: var(--note-bg); - font-weight: bold; - text-align: center; +header { + display: flex; + flex-direction: row; + align-items: center; + justify-content: space-between; + height: 72px; + padding: 0 12px; +} + +header .pfp .avatar-wrapper { + margin-right: 0; +} + +.header-actions { + display: flex; + flex-direction: row; +} + +.header-actions .btn-rnd { + position: relative; +} + +.header-actions .btn-rnd .has-unread { + background: var(--highlight); + border-radius: 100%; + width: 9px; + height: 9px; + position: absolute; + top: 0; + right: 0; } diff --git a/src/Pages/Layout.tsx b/src/Pages/Layout.tsx index dffdc48a..4243189e 100644 --- a/src/Pages/Layout.tsx +++ b/src/Pages/Layout.tsx @@ -2,8 +2,8 @@ import "./Layout.css"; import { useEffect } from "react" import { useDispatch, useSelector } from "react-redux"; import { Outlet, useNavigate } from "react-router-dom"; -import { faBell, faMessage } from "@fortawesome/free-solid-svg-icons"; -import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; +import Envelope from "Icons/Envelope" +import Bell from "Icons/Bell" import { RootState } from "State/Store"; import { init, setPreferences, UserPreferences } from "State/Login"; @@ -84,21 +84,17 @@ export default function Layout() { const unreadNotifications = notifications?.filter(a => (a.created_at * 1000) > readNotifications).length; const unreadDms = key ? totalUnread(dms, key) : 0; return ( - <> +

navigate("/messages")}> - + + {unreadDms > 0 && ()}
- {unreadDms > 0 && ( - {unreadDms > 100 ? ">99" : unreadDms} - )}
goToNotifications(e)}> - + + {unreadNotifications > 0 && ()}
- {unreadNotifications > 0 && ( - {unreadNotifications > 100 ? ">99" : unreadNotifications} - )} - +
) } @@ -108,14 +104,14 @@ export default function Layout() { return (
-
-
navigate("/")}>snort
+
+
navigate("/")}>Snort
{key ? accountHeader() : -
navigate("/login")}>Login
+ }
-
+
diff --git a/src/Pages/Login.tsx b/src/Pages/Login.tsx index cf117b86..0768af51 100644 --- a/src/Pages/Login.tsx +++ b/src/Pages/Login.tsx @@ -85,24 +85,24 @@ export default function LoginPage() { <>

Other Login Methods

-
doNip07Login()}>Login with Extension (NIP-07)
+
) } return ( - <> +

Login

setKey(e.target.value)} />
{error.length > 0 ? {error} : null}
-
doLogin()}>Login
-
makeRandomKey()}>Generate Key
+ +
{altLogins()} - +
); -} \ No newline at end of file +} diff --git a/src/Pages/MessagesPage.tsx b/src/Pages/MessagesPage.tsx index 5142f016..f0936fb4 100644 --- a/src/Pages/MessagesPage.tsx +++ b/src/Pages/MessagesPage.tsx @@ -51,17 +51,17 @@ export default function MessagesPage() { } return ( - <> +

Messages

-
markAllRead()}>Mark All Read
+
{chats.sort((a, b) => { return a.pubkey === myPubKey ? -1 : b.pubkey === myPubKey ? 1 : b.newestMessage - a.newestMessage }).map(person)} - +
) } @@ -122,4 +122,4 @@ export function extractChats(dms: RawEvent[], myPubKey: HexKey) { newestMessage: newestMessage(dms, myPubKey, a) } as DmChat; }) -} \ No newline at end of file +} diff --git a/src/Pages/NewUserPage.tsx b/src/Pages/NewUserPage.tsx index f268856f..fdd8c61e 100644 --- a/src/Pages/NewUserPage.tsx +++ b/src/Pages/NewUserPage.tsx @@ -67,9 +67,9 @@ export default function NewUserPage() { } return ( - <> +
{importTwitterFollows()} {followSomebody()} - +
); } \ No newline at end of file diff --git a/src/Pages/ProfilePage.css b/src/Pages/ProfilePage.css index 5479f191..a97143c3 100644 --- a/src/Pages/ProfilePage.css +++ b/src/Pages/ProfilePage.css @@ -1,26 +1,29 @@ .profile { + display: flex; flex-direction: column; + align-items: flex-start; } .profile .banner { - width: 100%; - height: 210px; - margin-bottom: -80px; - object-fit: cover; - mask-image: linear-gradient(to bottom, var(--bg-color) 60%, rgba(0,0,0,0)); - -webkit-mask-image: linear-gradient(to bottom, var(--bg-color) 60%, rgba(0,0,0,0)); - z-index: 0; + width: 100%; + height: 160px; + object-fit: cover; + margin-bottom: -60px; + mask-image: linear-gradient(to bottom, var(--bg-color) 60%, rgba(0,0,0,0)); + -webkit-mask-image: linear-gradient(to bottom, var(--bg-color) 60%, rgba(0,0,0,0)); + z-index: 0; } -@media (min-width: 720px) { - .profile .banner { - width: 100%; - max-width: 720px; - height: 300px; - margin-bottom: -120px; - } +.profile .profile-wrapper { + margin: 0 16px; + width: calc(100% - 32px); + display: flex; + flex-direction: column; + align-items: flex-start; + position: relative; } + .profile p { white-space: pre-wrap; } @@ -29,35 +32,37 @@ margin: 0; } -@media (min-width: 720px) { - .profile .banner { - width: 100%; - max-width: 720px; - height: 300px; - margin-bottom: -120px; - } +.profile .nip05 { + display: flex; + margin: 4px 0 12px 0; +} + +.profile .nip05 .nick { + font-weight: normal; + color: var(--gray-light); } .profile .avatar-wrapper { - align-self: flex-start; - z-index: 1; - margin-left: 4px; + z-index: 1; +} + +.profile .avatar-wrapper .avatar { + width: 120px; + height: 120px; } .profile .name { - display: flex; - flex-direction: column; - align-items: flex-start; -} - -.profile .name h2 { - margin: 0; + display: flex; + flex-direction: column; } .profile .details { - max-width: 680px; width: 100%; margin-top: 12px; + background-color: var(--note-bg); + padding: 12px 16px; + margin: 0 auto; + border-radius: 16px; } .profile .details p { @@ -76,129 +81,63 @@ .profile .btn-icon { color: var(--font-color); padding: 6px; - margin-left: 4px; } .profile .details-wrapper { display: flex; flex-direction: column; - align-items: flex-start; justify-content: space-between; - position: relative; - width: 100%; - margin-left: 4px; -} - -.profile .copy .body { font-size: 12px } - -@media (min-width: 360px) { - .profile .copy .body { font-size: 14px } - .profile .details-wrapper, .profile .avatar-wrapper { margin-left: 21px; } - .profile .details { width: calc(100% - 21px); } -} - -@media (min-width: 720px) { - .profile .details-wrapper, .profile .avatar-wrapper { margin-left: 30px; } - .profile .details { width: calc(100% - 30px); } -} - -.profile .follow-button { - position: absolute; - top: -30px; - right: 20px; -} - -.profile .message-button { - position: absolute; - top: -30px; - right: 74px; -} - -.profile .no-banner .follow-button { - right: 0px; -} -.profile .no-banner .message-button { - right: 54px; -} - -.tabs { - display: flex; - justify-content: flex-start; - width: 100%; - margin: 10px 0; + width: calc(100% - 32px); } .tabs > div { margin-right: 0; } -.tab { - margin: 0; - padding: 8px 0; - border-bottom: 3px solid var(--gray-secondary); -} -.tab.active { - border-bottom: 3px solid var(--highlight); -} - -.profile .no-banner { - display: flex; - flex-direction: column; - align-items: center; - justify-content: center; - width: 100%; -} - -.profile .no-banner .avatar { - height: 256px; - width: 256px; - margin-bottom: 30px; -} - -.profile .no-banner .avatar-wrapper, .profile .no-banner .details-wrapper { - margin: 0 auto; -} - -@media (min-width: 720px) { - .profile .no-banner { - width: 100%; - flex-direction: row; - justify-content: space-around; - margin-top: 21px; - } - .profile .no-banner .avatar-wrapper { - margin: auto 10px; - } - .profile .no-banner .details-wrapper { - margin-left: 10px; - margin-top: 21px; - max-width: 420px; - } -} - .profile .links { - margin: 8px 12px; + margin-top: 4px; + margin-left: 2px; +} + +.profile h3 { + color: var(--font-secondary-color); + font-size: 10px; + letter-spacing: .11em; + font-weight: 600; + line-height: 12px; + text-transform: uppercase; + margin-left: 16px; } .profile .website { - color: var(--highlight); - margin: 6px 0; + margin: 4px 0; + display: flex; + flex-direction: row; + align-items: center; +} + +.profile .website a { + color: var(--font-color); } .profile .website a { text-decoration: none; } -.profile .website::before { - content: '🔗 '; +.profile .website a:hover { + text-decoration: underline; } .profile .lnurl { - color: var(--highlight); - margin: 6px 0; cursor: pointer; } +.profile .ln-address { + display: flex; + flex-direction: row; + align-items: center; +} + .profile .lnurl:hover { text-decoration: underline; } @@ -208,6 +147,42 @@ text-overflow: ellipsis; } -.profile .zap { - margin-right: .3em; +.profile .link-icon { + color: var(--highlight); + margin-right: 8px; } + +.profile .link-icon svg { + width: 12px; + height: 12px; +} + +.profile .profile-actions { + position: absolute; + top: 80px; + right: 0; +} + +@media (min-width: 520px) { + .profile .profile-actions { + top: 120px; + } +} + +.profile .profile-actions button:not(:last-child) { + margin-right: 8px; +} + +@media (min-width: 520px) { + .profile .banner { + width: 100%; + max-width: 720px; + height: 300px; + margin-bottom: -100px; + } + .profile .avatar-wrapper .avatar { + width: 210px; + height: 210px; + } +} + diff --git a/src/Pages/ProfilePage.tsx b/src/Pages/ProfilePage.tsx index 8ad0e744..d92101fa 100644 --- a/src/Pages/ProfilePage.tsx +++ b/src/Pages/ProfilePage.tsx @@ -2,10 +2,10 @@ import "./ProfilePage.css"; import { useEffect, useMemo, useState } from "react"; import { useSelector } from "react-redux"; -import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; -import { faGear, faEnvelope } from "@fortawesome/free-solid-svg-icons"; import { useNavigate, useParams } from "react-router-dom"; +import Link from "Icons/Link"; +import Zap from "Icons/Zap"; import useProfile from "Feed/ProfileFeed"; import FollowButton from "Element/FollowButton"; import { extractLnAddress, parseId, hexToBech32 } from "Util"; @@ -39,7 +39,9 @@ export default function ProfilePage() { const isMe = loginPubKey === id; const [showLnQr, setShowLnQr] = useState(false); const [tab, setTab] = useState(ProfileTab.Notes); + const aboutText = user?.about || '' const about = Text({ content: user?.about || '', tags: [], users: new Map() }) + const lnurl = extractLnAddress(user?.lud16 || user?.lud06 || ""); useEffect(() => { setTab(ProfileTab.Notes); @@ -52,36 +54,48 @@ export default function ProfilePage() { {user?.display_name || user?.name || 'Nostrich'} - {user?.nip05 && } + + {links()}
) } + function links() { + return ( +
+ {user?.website && ( +
+ + + + {user.website} +
+ )} + + {lnurl && ( +
setShowLnQr(true)}> + + + + + {lnurl} + +
+ )} + setShowLnQr(false)} /> +
+ ) + } + function bio() { - const lnurl = extractLnAddress(user?.lud16 || user?.lud06 || ""); - return ( -
-
{about}
- -
- {user?.website && ( - - )} - - {lnurl && ( -
setShowLnQr(true)}> - ⚡️ - - {lnurl} - -
- )} -
- setShowLnQr(false)} /> -
+ return aboutText.length > 0 && ( + <> +

Bio

+
+ {about} +
+ ) } @@ -119,17 +133,20 @@ export default function ProfilePage() { return (
{username()} - {isMe ? ( -
navigate("/settings")}> - -
- ) : <> -
navigate(`/messages/${hexToBech32("npub", id)}`)}> - -
- - - } +
+ {isMe ? ( + + ) : ( + <> + + + + )} +
{bio()}
) @@ -138,18 +155,11 @@ export default function ProfilePage() { return ( <>
- {user?.banner && banner} - {user?.banner ? ( - <> - {avatar()} - {userDetails()} - - ) : ( -
- {avatar()} - {userDetails()} -
- )} + {user?.banner && banner} +
+ {avatar()} + {userDetails()} +
{[ProfileTab.Notes, ProfileTab.Followers, ProfileTab.Follows].map(v => { diff --git a/src/Pages/Root.tsx b/src/Pages/Root.tsx index 75383348..739e8e24 100644 --- a/src/Pages/Root.tsx +++ b/src/Pages/Root.tsx @@ -16,6 +16,7 @@ const RootTab = { }; export default function RootPage() { + const [show, setShow] = useState(false) const [loggedOut, pubKey, follows] = useSelector(s => [s.login.loggedOut, s.login.publicKey, s.login.follows]); const [tab, setTab] = useState(RootTab.Posts); @@ -32,20 +33,20 @@ export default function RootPage() { return ( <> {pubKey ? <> - -
-
setTab(RootTab.Posts)}> +
+
setTab(RootTab.Posts)}> Posts
-
setTab(RootTab.PostsAndReplies)}> - Posts & Replies +
setTab(RootTab.PostsAndReplies)}> + Conversations
-
setTab(RootTab.Global)}> +
setTab(RootTab.Global)}> Global
: null} {followHints()} + ); -} \ No newline at end of file +} diff --git a/src/Pages/SettingsPage.tsx b/src/Pages/SettingsPage.tsx index aa60cd87..6af73c9d 100644 --- a/src/Pages/SettingsPage.tsx +++ b/src/Pages/SettingsPage.tsx @@ -9,10 +9,10 @@ export default function SettingsPage() { const navigate = useNavigate(); return ( - <> +

navigate("/settings")} className="pointer">Settings

- +
); } diff --git a/src/Pages/Verification.tsx b/src/Pages/Verification.tsx index 683c9025..3732bca1 100644 --- a/src/Pages/Verification.tsx +++ b/src/Pages/Verification.tsx @@ -24,7 +24,7 @@ export default function VerificationPage() { ]; return ( -
+

Get Verified

NIP-05 is a DNS based verification spec which helps to validate you as a real user. diff --git a/src/Pages/settings/Profile.tsx b/src/Pages/settings/Profile.tsx index 482340da..bd96889f 100644 --- a/src/Pages/settings/Profile.tsx +++ b/src/Pages/settings/Profile.tsx @@ -128,11 +128,11 @@ export default function ProfileSettings() {

NIP-05:
setNip05(e.target.value)} /> -
navigate("/verification")}> +
+
@@ -143,10 +143,10 @@ export default function ProfileSettings() {
-
{ dispatch(logout()); navigate("/"); }}>Logout
+
-
saveProfile()}>Save
+
diff --git a/src/Pages/settings/Relays.tsx b/src/Pages/settings/Relays.tsx index b5e2d241..f8c83383 100644 --- a/src/Pages/settings/Relays.tsx +++ b/src/Pages/settings/Relays.tsx @@ -27,7 +27,7 @@ const RelaySettingsPage = () => {
setNewRelay(e.target.value)} />
-
addNewRelay()}>Add
+ ) } @@ -49,16 +49,16 @@ const RelaySettingsPage = () => { return ( <>

Relays

-
+
{Object.keys(relays || {}).map(a => )}
-
saveRelays()}>Save
+
{addRelay()} ) } -export default RelaySettingsPage; \ No newline at end of file +export default RelaySettingsPage; diff --git a/src/index.css b/src/index.css index 8556f0db..e0153880 100644 --- a/src/index.css +++ b/src/index.css @@ -1,4 +1,4 @@ -@import url('https://fonts.googleapis.com/css2?family=Montserrat:wght@400;700&display=swap'); +@import url('https://fonts.googleapis.com/css2?family=Be+Bietnam+Pro:wght@400;600;700&display=swap'); :root { --bg-color: #000; @@ -9,10 +9,8 @@ --font-size-small: 14px; --font-size-tiny: 12px; --modal-bg-color: rgba(0, 0, 0, 0.8); - --note-bg: #111; - --highlight-light: #ffd342; - --highlight: #ffc400; - --highlight-dark: #dba800; + --note-bg: #0C0C0C; + --highlight: #8B5CF6; --error: #FF6053; --success: #2AD544; @@ -22,8 +20,10 @@ --gray: #333; --gray-secondary: #222; --gray-tertiary: #444; + --gray-dark: #2B2B2B; + --gray-superdark: #171717; --gray-gradient: linear-gradient(to bottom right, var(--gray-superlight), var(--gray), var(--gray-light)); - --snort-gradient: linear-gradient(to bottom right, var(--highlight-light), var(--highlight), var(--highlight-dark)); + --snort-gradient: linear-gradient(180deg, #FFC7B7 0%, #4F1B73 100%); --nostrplebs-gradient: linear-gradient(to bottom right, #ff3cac, #2b86c5); --strike-army-gradient: linear-gradient(to bottom right, #CCFF00, #a1c900); } @@ -46,11 +46,13 @@ html.light { --gray-tertiary: #EEE; --gray-superlight: #333; --gray-light: #555; + --gray-dark: #2B2B2B; + --gray-superdark: #171717; } body { margin: 0; - font-family: 'Montserrat', sans-serif; + font-family: 'Be Vietnam Pro', sans-serif; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; background-color: var(--bg-color); @@ -63,25 +65,17 @@ code { } .page { - width: 720px; + width: 100vw; margin-left: auto; margin-right: auto; } -.page>.header { - display: flex; - align-items: center; - margin: 10px 0; -} - -.page>.header>div:nth-child(1) { - font-size: x-large; - flex-grow: 1; -} - -.page>.header>div:nth-child(2) { - display: flex; - align-items: center; +@media (min-width: 720px) { + .page { + width: 720px; + margin-left: auto; + margin-right: auto; + } } .card { @@ -115,10 +109,42 @@ html.light .card { margin-top: 12px; } +button { + cursor: pointer; + padding: 6px 12px; + font-weight: bold; + color: white; + font-size: var(--font-size); + background-color: var(--highlight); + border: none; + border-radius: 16px; + outline: none; +} +button:hover { + background-color: var(--font-color); + color: var(--bg-color); +} + +button.secondary { + color: var(--font-color); + background-color: var(--gray-dark); +} +.light button.secondary { + background-color: var(--gray); +} +button.secondary:hover { + color: var(--font-color); + background-color: var(--gray-superdark); +} +.light button.secondary:hover { + background-color: var(--gray-secondary); +} + .btn { padding: 10px; border-radius: 5px; cursor: pointer; + color: var(--font-color); user-select: none; background-color: var(--bg-color); color: var(--font-color); @@ -155,6 +181,17 @@ html.light .card { .btn-rnd { border-radius: 100%; + border-color: var(--gray-superdark); + width: 32px; + height: 32px; + display: flex; + align-items: center; + justify-content: center; + margin-right: 16px; +} + +.light .btn-rnd { + border-color: var(--gray); } textarea { @@ -365,18 +402,23 @@ body.scroll-lock { background-color: var(--success); } -.root-tabs { +.tabs { padding: 0; align-items: center; justify-content: flex-start; + margin-bottom: 16px; } -.root-tab { - border-bottom: 3px solid var(--gray-secondary); +.tab { + border-bottom: 1px solid var(--gray-secondary); + font-weight: bold; + color: var(--font-secondary-color); + padding: 8px 0; } -.root-tab.active { - border-bottom: 3px solid var(--highlight); +.tab.active { + border-bottom: 1px solid var(--highlight); + color: var(--font-color); } .tweet { @@ -398,10 +440,6 @@ body.scroll-lock { } @media(max-width: 720px) { - .page { - width: calc(100vw - 8px); - } - div.form-group { flex-direction: column; align-items: flex-start; @@ -410,4 +448,15 @@ body.scroll-lock { .highlight { color: var(--highlight); -} \ No newline at end of file +} + +.main-content { + padding: 0 12px; +} + +@media (min-width: 720px) { + .main-content { + padding: 0; + } +} +