diff --git a/.changeset/honest-actors-allow.md b/.changeset/honest-actors-allow.md new file mode 100644 index 000000000..d4ac80b7f --- /dev/null +++ b/.changeset/honest-actors-allow.md @@ -0,0 +1,5 @@ +--- +"nostrudel": minor +--- + +Show image and video embeds in DMs (big refactor to support hashtags) diff --git a/.changeset/silent-gifts-brush.md b/.changeset/silent-gifts-brush.md new file mode 100644 index 000000000..28c44c9e0 --- /dev/null +++ b/.changeset/silent-gifts-brush.md @@ -0,0 +1,5 @@ +--- +"nostrudel": minor +--- + +Desktop: Remove following list on right side diff --git a/.changeset/silly-rats-count.md b/.changeset/silly-rats-count.md new file mode 100644 index 000000000..2b5ce181f --- /dev/null +++ b/.changeset/silly-rats-count.md @@ -0,0 +1,5 @@ +--- +"nostrudel": minor +--- + +Add simple event deletion modal diff --git a/.changeset/tame-forks-raise.md b/.changeset/tame-forks-raise.md new file mode 100644 index 000000000..75cb46d95 --- /dev/null +++ b/.changeset/tame-forks-raise.md @@ -0,0 +1,5 @@ +--- +"nostrudel": minor +--- + +Mobile: Move user icon to bottom bar diff --git a/LICENSE b/LICENSE new file mode 100644 index 000000000..34e8cf2c2 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2023 Talha Buğra Bulut + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/src/app.tsx b/src/app.tsx index c4f165045..ee3d750f5 100644 --- a/src/app.tsx +++ b/src/app.tsx @@ -15,6 +15,7 @@ import ProfileView from "./views/profile"; import FollowingTab from "./views/home/following-tab"; import DiscoverTab from "./views/home/discover-tab"; import GlobalTab from "./views/home/global-tab"; +import HashTagView from "./views/hashtag"; import UserView from "./views/user"; import UserNotesTab from "./views/user/notes"; import UserFollowersTab from "./views/user/followers"; @@ -121,6 +122,7 @@ const router = createBrowserRouter([ { path: "dm/:key", element: }, { path: "profile", element: }, { path: "l/:link", element: }, + { path: "t/:hashtag", element: }, { path: "", element: , diff --git a/src/components/debug-modals/note-debug-modal.tsx b/src/components/debug-modals/note-debug-modal.tsx index afa33c86e..fe76510ca 100644 --- a/src/components/debug-modals/note-debug-modal.tsx +++ b/src/components/debug-modals/note-debug-modal.tsx @@ -11,9 +11,8 @@ export default function NoteDebugModal({ event, ...props }: { event: NostrEvent - Event Debug - + diff --git a/src/components/debug-modals/user-debug-modal.tsx b/src/components/debug-modals/user-debug-modal.tsx index 799193edf..a1c204851 100644 --- a/src/components/debug-modals/user-debug-modal.tsx +++ b/src/components/debug-modals/user-debug-modal.tsx @@ -15,7 +15,7 @@ export default function UserDebugModal({ pubkey, ...props }: { pubkey: string } - + {npub && } diff --git a/src/components/embed-types/app-music.tsx b/src/components/embed-types/app-music.tsx new file mode 100644 index 000000000..4ef9e5716 --- /dev/null +++ b/src/components/embed-types/app-music.tsx @@ -0,0 +1,20 @@ +import { EmbedableContent, embedJSX } from "../../helpers/embeds"; + +// note1tvqk2mu829yr6asf7w5dgpp8t0mlp2ax5t26ctfdx8m0ptkssamqsleeux +// note1ygx9tec3af92704d92jwrj3zs7cws2jl29yvrlxzqlcdlykhwssqpupa7t +export function embedAppleMusic(content: EmbedableContent) { + return embedJSX(content, { + regexp: /https?:\/\/music\.apple\.com(?:\/[\+~%\/\.\w\-_]*)?(\??(?:[\?#\-\+=&;%@\.\w_]*)#?(?:[\-\.\!\/\\\w]*))?/, + render: (match) => ( + + ), + name: "Apple Music", + }); +} diff --git a/src/components/embed-types/common.tsx b/src/components/embed-types/common.tsx new file mode 100644 index 000000000..7482c592f --- /dev/null +++ b/src/components/embed-types/common.tsx @@ -0,0 +1,49 @@ +import { Box, Image, ImageProps, Link, useDisclosure } from "@chakra-ui/react"; +import { EmbedableContent, embedJSX } from "../../helpers/embeds"; +import appSettings from "../../services/app-settings"; + +const BlurredImage = (props: ImageProps) => { + const { isOpen, onToggle } = useDisclosure(); + return ( + + + + ); +}; + +// note1n06jceulg3gukw836ghd94p0ppwaz6u3mksnnz960d8vlcp2fnqsgx3fu9 +export function embedImages(content: EmbedableContent, trusted = false) { + return embedJSX(content, { + regexp: + /https?:\/\/([\dA-z\.-]+\.[A-z\.]{2,6})((?:\/[\+~%\/\.\w\-_]*)?\.(?:svg|gif|png|jpg|jpeg|webp|avif))(\??(?:[\?#\-\+=&;%@\.\w_]*)#?(?:[\-\.\!\/\\\w]*))?/i, + render: (match) => { + const ImageComponent = trusted || !appSettings.value.blurImages ? Image : BlurredImage; + return ; + }, + name: "Image", + }); +} + +export function embedVideos(content: EmbedableContent) { + return embedJSX(content, { + name: "Video", + regexp: + /https?:\/\/([\dA-z\.-]+\.[A-z\.]{2,6})((?:\/[\+~%\/\.\w\-_]*)?\.(?:mp4|mkv|webm|mov))(\??(?:[\?#\-\+=&;%@\.\w_]*)#?(?:[\-\.\!\/\\\w]*))?/i, + render: (match) => - + ); } function DirectMessagesView() { + const isMobile = useIsMobile(); const [from, setFrom] = useState(moment().subtract(2, "days")); const conversations = useSubject(directMessagesService.conversations); @@ -93,6 +97,20 @@ function DirectMessagesView() { return ( + + + + Give NostrChat a try + + + Its a much better chat app than what I can build inside of noStrudel.{" "} + + nostrchat.io + + + + + {sortedConversations.map((pubkey) => ( ))} diff --git a/src/views/hashtag/index.tsx b/src/views/hashtag/index.tsx new file mode 100644 index 000000000..4eff5bfcc --- /dev/null +++ b/src/views/hashtag/index.tsx @@ -0,0 +1,10 @@ +import { Flex } from "@chakra-ui/react"; +import { useParams } from "react-router-dom"; +import { useAppTitle } from "../../hooks/use-app-title"; + +export default function HashTagView() { + const { hashtag } = useParams() as { hashtag: string }; + useAppTitle("#" + hashtag); + + return ; +} diff --git a/src/views/user/components/user-profile-menu.tsx b/src/views/user/components/user-profile-menu.tsx index 5b99a75cd..4cbefbacd 100644 --- a/src/views/user/components/user-profile-menu.tsx +++ b/src/views/user/components/user-profile-menu.tsx @@ -21,6 +21,7 @@ import { getUserDisplayName } from "../../../helpers/user-metadata"; import { useUserRelays } from "../../../hooks/use-user-relays"; import { RelayMode } from "../../../classes/relay"; import { CopyIconButton } from "../../../components/copy-icon-button"; +import UserDebugModal from "../../../components/debug-modals/user-debug-modal"; export const UserProfileMenu = ({ pubkey, ...props }: { pubkey: string } & Omit) => { const npub = normalizeToBech32(pubkey, Bech32Prefix.Pubkey); @@ -67,46 +68,7 @@ export const UserProfileMenu = ({ pubkey, ...props }: { pubkey: string } & Omit< {infoModal.isOpen && ( - - - - - - - - Hex pubkey - - - - {pubkey} - - - - - {npub && ( - <> - - Encoded pubkey (NIP-19) - - - - {npub} - - - - - )} - - - Metadata (kind 0) - - - {JSON.stringify(metadata, null, 2)} - - - - - + )} );