refactor: improve whitelabel config
Some checks failed
continuous-integration/drone/push Build is failing

This commit is contained in:
Kieran 2024-01-22 16:41:40 +00:00
parent 4aa00405ee
commit e7f9b5e2ea
Signed by: Kieran
GPG Key ID: DE71CEB3925BE941
20 changed files with 90 additions and 86 deletions

View File

@ -4,8 +4,7 @@
"appTitle": "Snort - Nostr",
"hostname": "snort.social",
"nip05Domain": "snort.social",
"favicon": "public/favicon.ico",
"appleTouchIconUrl": "/nostrich_512.png",
"icon": "/nostrich_512.png",
"navLogo": null,
"publicDir": "public/snort",
"httpCache": "",

View File

@ -4,8 +4,7 @@
"appTitle": "iris",
"hostname": "iris.to",
"nip05Domain": "iris.to",
"favicon": "public/iris/favicon.ico",
"appleTouchIconUrl": "/img/apple-touch-icon.png",
"icon": "/img/icon128.png",
"navLogo": "/img/icon128.png",
"publicDir": "public/iris",
"httpCache": "",

View File

@ -4,10 +4,9 @@
"appTitle": "Nostr",
"hostname": "nostr.com",
"nip05Domain": "nostr.com",
"favicon": "public/favicon.ico",
"appleTouchIconUrl": "/nostrich_512.png",
"icon": "/nostr.jpg",
"navLogo": null,
"publicDir": "public/snort",
"publicDir": "public/nostr",
"httpCache": "",
"animalNamePlaceholders": false,
"features": {
@ -40,6 +39,7 @@
"defaultRelays": {
"wss://relay.snort.social/": { "read": true, "write": true },
"wss://nostr.wine/": { "read": true, "write": false },
"wss://eden.nostr.land/": { "read": true, "write": false }
"wss://eden.nostr.land/": { "read": true, "write": false },
"wss://nos.lol/": { "read": true, "write": true }
}
}

View File

@ -47,8 +47,7 @@ declare const CONFIG: {
appTitle: string;
hostname: string;
nip05Domain: string;
favicon: string;
appleTouchIconUrl: string;
icon: string;
navLogo: string | null;
httpCache: string;
animalNamePlaceholders: boolean;

View File

@ -11,10 +11,12 @@
name="keywords"
content="nostr snort fast decentralized social media censorship resistant open source software" />
<link rel="preconnect" href="https://imgproxy.snort.social" />
<link rel="apple-touch-icon" href="" />
<link rel="apple-touch-icon" href="/img/apple-touch-icon.png" />
<link rel="manifest" href="/manifest.json" />
<link rel="icon" href="/favicon.png" />
<title></title>
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/index.tsx"></script>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 165 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 405 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

View File

@ -0,0 +1,29 @@
import { unwrap } from "@snort/shared";
import { decodeTLV, EventKind, RequestBuilder, TLVEntryType } from "@snort/system";
import { useRequestBuilder } from "@snort/system-react";
import { useMemo } from "react";
import { createEmptyChatObject } from "@/chat";
export function useEmptyChatSystem(id?: string) {
const sub = useMemo(() => {
if (!id) return;
if (id.startsWith("chat281")) {
const cx = unwrap(decodeTLV(id).find(a => a.type === TLVEntryType.Special)).value as string;
const rb = new RequestBuilder(`nip28:${id}`);
rb.withFilter().ids([cx]).kinds([EventKind.PublicChatChannel, EventKind.PublicChatMetadata]);
rb.withFilter()
.tag("e", [cx])
.kinds([EventKind.PublicChatChannel, EventKind.PublicChatMessage, EventKind.PublicChatMetadata]);
return rb;
}
}, [id]);
const data = useRequestBuilder(sub);
return useMemo(() => {
if (!id) return;
return createEmptyChatObject(id, data);
}, [id, data.length]);
}

View File

@ -12,6 +12,7 @@ import Modal from "@/Components/Modal/Modal";
import QrCode from "@/Components/QrCode";
import ProfilePreview from "@/Components/User/ProfilePreview";
import SnortApi, { RevenueSplit, RevenueToday } from "@/External/SnortApi";
import useLogin from "@/Hooks/useLogin";
import { bech32ToHex, unwrap } from "@/Utils";
import { ApiHost, DeveloperAccounts, SnortPubKey } from "@/Utils/Const";
import { ZapPoolController, ZapPoolRecipientType } from "@/Utils/ZapPoolController";
@ -67,6 +68,7 @@ const DonatePage = () => {
const [onChain, setOnChain] = useState("");
const api = new SnortApi(ApiHost);
const navigate = useNavigate();
const login = useLogin();
async function getOnChainAddress() {
const { address } = await api.onChainDonation();
@ -153,9 +155,10 @@ const DonatePage = () => {
return (
<AsyncButton
onClick={() => {
navigate(`/messages/${Nip28ChatSystem.chatId(a.value)}`);
const id = Nip28ChatSystem.chatId(a.value);
navigate(`/messages/${id}`);
}}>
<img src={CONFIG.appleTouchIconUrl} width={24} height={24} className="rounded-full" />
<img src={CONFIG.icon} width={24} height={24} className="rounded-full" />
<FormattedMessage defaultMessage="Nostr Public Chat" id="whSrs+" />
</AsyncButton>
);

View File

@ -1,19 +1,18 @@
import { useEffect, useMemo, useRef } from "react";
import { useMemo } from "react";
import { FormattedMessage } from "react-intl";
import { Chat, createEmptyChatObject, useChatSystem } from "@/chat";
import { Chat, useChat } from "@/chat";
import ProfileImage from "@/Components/User/ProfileImage";
import useLogin from "@/Hooks/useLogin";
import DM from "@/Pages/Messages/DM";
import WriteMessage from "@/Pages/Messages/WriteMessage";
import { ChatParticipantProfile } from "./ChatParticipant";
export default function DmWindow({ id }: { id: string }) {
const dms = useChatSystem();
const chat = dms.find(a => a.id === id) ?? createEmptyChatObject(id);
const chat = useChat(id);
function sender() {
if (!chat) return;
if (chat.participants.length === 1) {
return <ChatParticipantProfile participant={chat.participants[0]} />;
} else {
@ -29,63 +28,28 @@ export default function DmWindow({ id }: { id: string }) {
}
return (
<div className="flex flex-1 flex-col h-[calc(100vh-62px)] md:h-screen">
<div className="flex flex-1 flex-col h-full w-full md:h-screen">
<div className="p-3">{sender()}</div>
<div className="overflow-y-auto hide-scrollbar p-2.5 flex-grow">
<div className="flex flex-col">{chat && <DmChatSelected chat={chat} />}</div>
</div>
<div className="flex items-center gap-2.5 p-2.5">
<WriteMessage chat={chat} />
</div>
<div className="overflow-y-auto hide-scrollbar p-2.5 flex-grow">{chat && <DmChatSelected chat={chat} />}</div>
<div className="flex items-center gap-2.5 p-2.5">{chat && <WriteMessage chat={chat} />}</div>
</div>
);
}
function DmChatSelected({ chat }: { chat: Chat }) {
const { publicKey: myPubKey } = useLogin(s => ({ publicKey: s.publicKey }));
const messagesContainerRef = useRef<HTMLDivElement>(null);
const messagesEndRef = useRef<HTMLDivElement>(null);
const sortedDms = useMemo(() => {
const myDms = chat?.messages;
if (myPubKey && myDms) {
// filter dms in this chat, or dms to self
return [...myDms].sort((a, b) => a.created_at - b.created_at);
if (myDms) {
return [...myDms].sort((a, b) => (a.created_at > b.created_at ? -1 : 1));
}
return [];
}, [chat, myPubKey]);
const scrollToBottom = () => {
messagesEndRef.current?.scrollIntoView({ behavior: "instant" });
};
useEffect(() => {
const observer = new ResizeObserver(() => {
scrollToBottom();
});
// Start observing the element that you want to keep in view
if (messagesContainerRef.current) {
observer.observe(messagesContainerRef.current);
}
// Make sure to scroll to bottom on initial load
scrollToBottom();
// Clean up the observer on component unmount
return () => {
if (messagesContainerRef.current) {
observer.unobserve(messagesContainerRef.current);
}
};
}, [sortedDms]);
}, [chat]);
return (
<div className="flex flex-col" ref={messagesContainerRef}>
<div className="flex flex-col-reverse">
{sortedDms.map(a => (
<DM data={a} key={a.id} chat={chat} />
))}
<div ref={messagesEndRef} />
</div>
);
}

View File

@ -1,5 +1,5 @@
import classNames from "classnames";
import React, { useEffect, useMemo, useState } from "react";
import React, { useMemo } from "react";
import { FormattedMessage, useIntl } from "react-intl";
import { useNavigate, useParams } from "react-router-dom";
@ -13,7 +13,6 @@ import { ChatParticipantProfile } from "@/Pages/Messages/ChatParticipant";
import DmWindow from "@/Pages/Messages/DmWindow";
import NewChatWindow from "@/Pages/Messages/NewChatWindow";
import UnreadCount from "@/Pages/Messages/UnreadCount";
import { parseId } from "@/Utils";
const TwoCol = 768;
@ -22,13 +21,8 @@ export default function MessagesPage() {
const { formatMessage } = useIntl();
const navigate = useNavigate();
const { id } = useParams();
const [chat, setChat] = useState<string>();
const pageWidth = usePageWidth();
useEffect(() => {
const parsedId = parseId(id ?? "");
setChat(id ? parsedId : undefined);
}, [id]);
const chats = useChatSystem();
const unreadCount = useMemo(() => chats.reduce((p, c) => p + c.unread, 0), [chats]);
@ -67,7 +61,7 @@ export default function MessagesPage() {
const participants = cx.participants.map(a => a.id);
if (participants.length === 1 && participants[0] === login.publicKey) return noteToSelf(cx);
const isActive = cx.id === chat;
const isActive = cx.id === id;
return (
<div
className={classNames("flex items-center p cursor-pointer justify-between", { active: isActive })}
@ -89,7 +83,7 @@ export default function MessagesPage() {
return (
<div className="flex flex-1 md:h-screen md:overflow-hidden">
{(pageWidth >= TwoCol || !chat) && (
{pageWidth >= TwoCol && !id && (
<div className="overflow-y-auto md:h-screen p-1 w-full md:w-1/3 flex-shrink-0">
<div className="flex items-center justify-between p-2">
<button disabled={unreadCount <= 0} type="button" className="text-sm font-semibold">
@ -109,7 +103,7 @@ export default function MessagesPage() {
.map(conversation)}
</div>
)}
{chat ? <DmWindow id={chat} /> : pageWidth >= TwoCol && <div className="flex-1 rt-border"></div>}
{id ? <DmWindow id={id} /> : pageWidth >= TwoCol && <div className="flex-1 rt-border"></div>}
</div>
);
}

View File

@ -71,7 +71,7 @@ export function SignIn() {
const nip7Login = hasNip7 && !useKey;
return (
<div className="flex flex-col g24">
<img src={CONFIG.appleTouchIconUrl} width={48} height={48} className="br mr-auto ml-auto" />
<img src={CONFIG.icon} width={48} height={48} className="br mr-auto ml-auto" />
<div className="flex flex-col g16 items-center">
<h1>
<FormattedMessage defaultMessage="Sign In" id="Ub+AGc" />
@ -152,7 +152,7 @@ export function SignUp() {
return (
<div className="flex flex-col g24">
<img src={CONFIG.appleTouchIconUrl} width={48} height={48} className="br mr-auto ml-auto" />
<img src={CONFIG.icon} width={48} height={48} className="br mr-auto ml-auto" />
<div className="flex flex-col g16 items-center">
<h1>
<FormattedMessage defaultMessage="Sign Up" id="39AHJm" />

View File

@ -15,6 +15,7 @@ import {
import { useSyncExternalStore } from "react";
import { Chats, GiftsCache } from "@/Cache";
import { useEmptyChatSystem } from "@/Hooks/useEmptyChatSystem";
import useLogin from "@/Hooks/useLogin";
import useModeration from "@/Hooks/useModeration";
import { findTag } from "@/Utils";
@ -155,15 +156,15 @@ export function createChatLink(type: ChatType, ...params: Array<string>) {
throw new Error("Unknown chat type");
}
export function createEmptyChatObject(id: string) {
export function createEmptyChatObject(id: string, messages?: Array<TaggedNostrEvent>) {
if (id.startsWith("chat41")) {
return Nip4ChatSystem.createChatObj(id, []);
return Nip4ChatSystem.createChatObj(id, messages ?? []);
}
if (id.startsWith("chat241")) {
return Nip24ChatSystem.createChatObj(id, []);
}
if (id.startsWith("chat281")) {
return Nip28ChatSystem.createChatObj(id, []);
return Nip28ChatSystem.createChatObj(id, messages ?? []);
}
throw new Error("Cant create new empty chat, unknown id");
}
@ -209,3 +210,24 @@ export function useChatSystem() {
return authors.length === 0 || !authors.every(a => isBlocked(a));
});
}
export function useChat(id: string) {
const getStore = () => {
if (id.startsWith("chat41")) {
return Nip4Chats;
}
if (id.startsWith("chat281")) {
return Nip28Chats;
}
throw new Error("Unsupported chat system");
};
const store = getStore();
const ret = useSyncExternalStore(
c => store.hook(c),
() => {
return store.snapshot().find(a => a.id === id);
},
);
const emptyChat = useEmptyChatSystem(ret === undefined ? id : undefined);
return ret ?? emptyChat;
}

View File

@ -2,7 +2,7 @@ import "./index.css";
import "@szhsin/react-menu/dist/index.css";
import "@/assets/fonts/inter.css";
import { encodeTLVEntries, socialGraphInstance } from "@snort/system";
import { socialGraphInstance } from "@snort/system";
import { SnortContext } from "@snort/system-react";
import { StrictMode } from "react";
import * as ReactDOM from "react-dom/client";
@ -34,6 +34,9 @@ import { RootTabRoutes } from "@/Pages/Root/RootTabRoutes";
import SearchPage from "@/Pages/SearchPage";
import SettingsRoutes from "@/Pages/settings/Routes";
import { SubscribeRoutes } from "@/Pages/subscribe";
import WalletPage from "@/Pages/wallet";
import { WalletReceivePage } from "@/Pages/wallet/receive";
import { WalletSendPage } from "@/Pages/wallet/send";
import ZapPoolPage from "@/Pages/ZapPool";
import { System } from "@/system";
import { storeRefCode, unwrap } from "@/Utils";
@ -42,10 +45,6 @@ import { hasWasm, wasmInit, WasmPath } from "@/Utils/wasm";
import { Wallets } from "@/Wallet";
import { setupWebLNWalletConfig } from "@/Wallet/WebLN";
import WalletPage from "./Pages/wallet";
import { WalletReceivePage } from "./Pages/wallet/receive";
import { WalletSendPage } from "./Pages/wallet/send";
async function initSite() {
storeRefCode();
if (hasWasm) {
@ -222,10 +221,5 @@ root.render(
</StrictMode>,
);
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
//@ts-ignore
window.encodeTLV = encodeTLVEntries;
// Use react-helmet instead?
document.title = CONFIG.appTitle;
document.querySelector('link[rel="apple-touch-icon"]')?.setAttribute("href", CONFIG.appleTouchIconUrl);

View File

@ -272,7 +272,6 @@ function makeNotification(n: PushNotification) {
const ret = {
body: body(),
icon: evx.author.avatar ?? defaultAvatar(evx.author.pubkey),
badge: `${location.protocol}//${location.hostname}${CONFIG.appleTouchIconUrl}`,
timestamp: evx.created_at * 1000,
tag: evx.id,
data: JSON.stringify(n),