├── .env.example ├── .eslintrc.json ├── .gitignore ├── README.md ├── next.config.js ├── package.json ├── postcss.config.js ├── public ├── android-chrome-192x192.png ├── android-chrome-512x512.png ├── apple-touch-icon.png ├── badges │ ├── ens.png │ ├── poh.png │ ├── sybil.png │ └── worldcoin.png ├── brands │ ├── ens.svg │ ├── lens.png │ ├── lens.svg │ ├── lenster.svg │ ├── twitter-dark.svg │ ├── twitter-light.svg │ └── uniswap.png ├── dollar.png ├── fallbackThumbnail.png ├── favicon-16x16.png ├── favicon.ico ├── favicon.png ├── fonts │ ├── Metropolis-Black.woff │ ├── Metropolis-BlackItalic.woff │ ├── Metropolis-Bold.woff │ ├── Metropolis-BoldItalic.woff │ ├── Metropolis-ExtraBold.woff │ ├── Metropolis-ExtraBoldItalic.woff │ ├── Metropolis-ExtraLight.woff │ ├── Metropolis-ExtraLightItalic.woff │ ├── Metropolis-Light.woff │ ├── Metropolis-LightItalic.woff │ ├── Metropolis-Medium.woff │ ├── Metropolis-MediumItalic.woff │ ├── Metropolis-Regular.woff │ ├── Metropolis-RegularItalic.woff │ ├── Metropolis-SemiBold.woff │ ├── Metropolis-SemiBoldItalic.woff │ ├── Metropolis-Thin.woff │ ├── Metropolis-ThinItalic.woff │ ├── example.html │ └── fonts.css ├── hashflags │ ├── bitcoin.png │ ├── blm.png │ ├── bts.png │ ├── btsarmy.png │ ├── ethereum.png │ ├── hashtag.png │ ├── lens.png │ ├── lenster.png │ ├── lenstube.png │ ├── pride.png │ └── voted.png ├── logo.png ├── manifest.json ├── meta.png ├── patterns │ ├── 1.png │ ├── 10.png │ ├── 11.png │ ├── 2.png │ ├── 3.png │ ├── 4.png │ ├── 5.png │ ├── 6.png │ ├── 7.png │ ├── 8.png │ └── 9.png ├── site.webmanifest ├── source │ ├── buttrfly.jpeg │ ├── lensport.jpeg │ ├── lenster.jpeg │ ├── lenstube-bytes.jpeg │ ├── lenstube.jpeg │ ├── memester.jpeg │ ├── orb.jpeg │ └── phaver.jpeg ├── sw.js ├── sw.js.map ├── thanks │ ├── 4everland-dark.png │ ├── 4everland-light.png │ ├── imagekit-dark.svg │ ├── imagekit-light.svg │ ├── vercel-dark.svg │ └── vercel-light.svg ├── tokens │ ├── bct.svg │ ├── dai.svg │ ├── nct.svg │ ├── usdc.svg │ ├── weth.svg │ └── wmatic.svg ├── wallets │ ├── browser-wallet.svg │ └── walletconnect.svg ├── workbox-327c579b.js └── workbox-327c579b.js.map ├── src ├── components │ ├── Board │ │ ├── Info.tsx │ │ ├── Pins.tsx │ │ └── index.tsx │ ├── Common │ │ ├── Auth │ │ │ ├── ConnectWalletButton.tsx │ │ │ └── Login.tsx │ │ ├── BetaNotification.tsx │ │ ├── Cards │ │ │ ├── Pin │ │ │ │ ├── Image.tsx │ │ │ │ ├── Video.tsx │ │ │ │ └── index.tsx │ │ │ ├── QueuedPinCard.tsx │ │ │ └── Tag.tsx │ │ ├── CategoriesList.tsx │ │ ├── CollectWarning.tsx │ │ ├── ErrorBoundary.tsx │ │ ├── Filters.tsx │ │ ├── Follow.tsx │ │ ├── Header.tsx │ │ ├── InterweaveContent.tsx │ │ ├── Layout.tsx │ │ ├── Menu │ │ │ ├── CreateMenu.tsx │ │ │ ├── Help.tsx │ │ │ ├── Menu.tsx │ │ │ ├── MobileMenu.tsx │ │ │ ├── UserMenu.tsx │ │ │ └── index.ts │ │ ├── MetaTags.tsx │ │ ├── Modals │ │ │ ├── CreateBoard.tsx │ │ │ ├── CreateProfile.tsx │ │ │ └── EditBoard.tsx │ │ ├── Providers.tsx │ │ ├── ReferralAlert.tsx │ │ ├── Search │ │ │ ├── Boards.tsx │ │ │ ├── GlobalSearchBar.tsx │ │ │ └── Profiles.tsx │ │ ├── Sidebar.tsx │ │ ├── Slider │ │ │ ├── Slider.tsx │ │ │ ├── buttons.tsx │ │ │ └── index.tsx │ │ ├── Slug.tsx │ │ ├── SuperFollow │ │ │ ├── FollowModule.tsx │ │ │ └── index.tsx │ │ ├── ThemeSwitch.tsx │ │ ├── Timeline.tsx │ │ ├── TrendingTags.tsx │ │ ├── Unfollow.tsx │ │ ├── Uniswap.tsx │ │ ├── UserPreview.tsx │ │ ├── UserProfile.tsx │ │ ├── Video.tsx │ │ └── matchers │ │ │ ├── HashtagMatcher.tsx │ │ │ ├── MentionMatcher.tsx │ │ │ ├── UrlMatcher │ │ │ ├── constants.ts │ │ │ └── index.tsx │ │ │ └── markdown │ │ │ ├── MDBoldMatcher.tsx │ │ │ ├── MDCodeMatcher.tsx │ │ │ ├── MDItalicMatcher.tsx │ │ │ ├── MDLinkMatcher.tsx │ │ │ ├── MDQuoteMatcher.tsx │ │ │ └── MDStrikeMatcher.tsx │ ├── Create │ │ ├── Actions │ │ │ ├── Boards.tsx │ │ │ └── Collect │ │ │ │ ├── CollectForm.tsx │ │ │ │ └── index.tsx │ │ ├── Category.tsx │ │ ├── Details.tsx │ │ ├── Video.tsx │ │ └── index.tsx │ ├── Explore │ │ └── index.tsx │ ├── Hashtag │ │ └── index.tsx │ ├── Home │ │ ├── Explore.tsx │ │ ├── Feed.tsx │ │ └── index.tsx │ ├── Latest │ │ └── index.tsx │ ├── Messages │ │ ├── Attachment.tsx │ │ ├── Composer.tsx │ │ ├── Giphy │ │ │ ├── GifSelector.tsx │ │ │ └── index.tsx │ │ ├── Message.tsx │ │ ├── MessageHeader.tsx │ │ ├── MessageIcon.tsx │ │ ├── MessageMedia.tsx │ │ ├── MessagesList.tsx │ │ ├── Preview.tsx │ │ ├── PreviewList.tsx │ │ └── index.tsx │ ├── Notifications │ │ ├── Menu │ │ │ ├── Profile.tsx │ │ │ ├── Type │ │ │ │ ├── CollectNotification │ │ │ │ │ ├── Amount.tsx │ │ │ │ │ ├── Content.tsx │ │ │ │ │ └── index.tsx │ │ │ │ ├── CommentNotification.tsx │ │ │ │ ├── FollowerNotification.tsx │ │ │ │ ├── LikeNotification.tsx │ │ │ │ ├── MentionNotification.tsx │ │ │ │ └── MirrorNotification.tsx │ │ │ └── index.tsx │ │ ├── Profile.tsx │ │ ├── Type │ │ │ ├── CollectNotification │ │ │ │ ├── Amount.tsx │ │ │ │ ├── Content.tsx │ │ │ │ └── index.tsx │ │ │ ├── CommentNotification.tsx │ │ │ ├── FollowerNotification.tsx │ │ │ ├── LikeNotification.tsx │ │ │ ├── MentionNotification.tsx │ │ │ └── MirrorNotification.tsx │ │ ├── WalletProfile.tsx │ │ └── index.tsx │ ├── Pin │ │ ├── Attachments │ │ │ ├── PinImage.tsx │ │ │ ├── PinVideo.tsx │ │ │ └── index.tsx │ │ ├── Comments │ │ │ ├── Comment.tsx │ │ │ ├── NewComment.tsx │ │ │ ├── QueuedComment.tsx │ │ │ └── index.tsx │ │ ├── Meta │ │ │ ├── Collect.tsx │ │ │ ├── CollectModule.tsx │ │ │ ├── Like.tsx │ │ │ ├── Mirror.tsx │ │ │ ├── Wav3s.tsx │ │ │ └── index.tsx │ │ ├── Related │ │ │ └── index.tsx │ │ ├── Saved.tsx │ │ ├── Share.tsx │ │ ├── User.tsx │ │ └── index.tsx │ ├── Profile │ │ ├── Cover.tsx │ │ ├── Details.tsx │ │ ├── Followerings.tsx │ │ ├── Following.tsx │ │ ├── Info.tsx │ │ ├── MetaDetails.tsx │ │ ├── Pins │ │ │ ├── All.tsx │ │ │ ├── Common │ │ │ │ ├── Board.tsx │ │ │ │ ├── Pins.tsx │ │ │ │ ├── Thumbnail.tsx │ │ │ │ └── Thumbnails.tsx │ │ │ ├── Created.tsx │ │ │ ├── Mirrored.tsx │ │ │ ├── Saved.tsx │ │ │ └── index.tsx │ │ └── index.tsx │ ├── Settings │ │ ├── Allowance │ │ │ └── Button.tsx │ │ ├── BasicInfo.tsx │ │ ├── DangerZone.tsx │ │ ├── Permissions │ │ │ ├── Dispatcher │ │ │ │ ├── Toggle.tsx │ │ │ │ └── index.tsx │ │ │ ├── Modules │ │ │ │ └── index.tsx │ │ │ └── index.tsx │ │ ├── ProfileInterests │ │ │ ├── Topics.tsx │ │ │ └── index.tsx │ │ ├── ProfilePicture.tsx │ │ ├── SideNav.tsx │ │ └── index.tsx │ ├── Shimmers │ │ ├── CommentItemShimmer.tsx │ │ ├── CommentsShimmer.tsx │ │ ├── NotificationShimmer.tsx │ │ ├── PinCardShimmer.tsx │ │ ├── PinShimmer.tsx │ │ ├── ProfileShimmer.tsx │ │ └── TimelineShimmer.tsx │ ├── Stats │ │ ├── StatCard.tsx │ │ └── index.tsx │ └── UI │ │ ├── Alert.tsx │ │ ├── Button.tsx │ │ ├── Card.tsx │ │ ├── DropMenu.tsx │ │ ├── EmptyState.tsx │ │ ├── ErrorMessage.tsx │ │ ├── Form.tsx │ │ ├── FullPageLoader.tsx │ │ ├── GetModuleIcon.tsx │ │ ├── InfiniteLoader.tsx │ │ ├── Input.tsx │ │ ├── InputMentions.tsx │ │ ├── IsVerified.tsx │ │ ├── Loader.tsx │ │ ├── Modal.tsx │ │ ├── NoDataFound.tsx │ │ ├── TextArea.tsx │ │ ├── Toggle.tsx │ │ ├── Tooltip.tsx │ │ └── WarningMessage.tsx ├── lib │ ├── apollo │ │ ├── authLink.ts │ │ ├── cache.ts │ │ ├── cursorBasedPagination.ts │ │ └── index.ts │ ├── db │ │ ├── actions.tsx │ │ └── api.ts │ └── store │ │ ├── access-settings.ts │ │ ├── collect-module.ts │ │ ├── index.ts │ │ ├── message.ts │ │ ├── persist.ts │ │ └── publication.ts ├── pages │ ├── 404.tsx │ ├── 500.tsx │ ├── [username] │ │ ├── [board] │ │ │ └── index.tsx │ │ └── index.tsx │ ├── _app.tsx │ ├── _document.tsx │ ├── api │ │ └── hello.ts │ ├── auth.tsx │ ├── create │ │ └── index.tsx │ ├── explore.tsx │ ├── hashtag │ │ └── [tag].tsx │ ├── index.tsx │ ├── latest.tsx │ ├── messages │ │ ├── [...conversationKey].tsx │ │ └── index.tsx │ ├── notifications.tsx │ ├── pin │ │ └── [id].tsx │ ├── settings │ │ ├── danger.tsx │ │ ├── index.tsx │ │ ├── interests.tsx │ │ └── permissions.tsx │ └── stats │ │ └── index.tsx ├── styles │ └── globals.css └── utils │ ├── abis │ ├── .eslintrc.js │ ├── FollowNFT.ts │ ├── LensHubProxy.ts │ ├── LensPeriphery.ts │ ├── UpdateOwnableFeeCollectModule.ts │ ├── index.ts │ ├── package.json │ └── tsconfig.json │ ├── analytics.ts │ ├── constants.ts │ ├── contracts.ts │ ├── custom-types.ts │ ├── data │ ├── aave-members.ts │ ├── auth-routes.ts │ ├── categories.ts │ ├── paid-members.ts │ ├── pinsta-members.ts │ ├── tags.ts │ └── verified.ts │ ├── functions │ ├── buildConversationId.ts │ ├── chunkArray.ts │ ├── clearLocalStorage.ts │ ├── conversationKey.ts │ ├── conversationMatchesProfile.ts │ ├── formatAddress.ts │ ├── formatBytes.ts │ ├── formatHandle.ts │ ├── formatNumber.ts │ ├── formatTime.ts │ ├── generateVideoThumbnails.ts │ ├── getApolloClient.ts │ ├── getAppName.ts │ ├── getAssetAddress.ts │ ├── getAttribute.ts │ ├── getAttributeFromTrait.ts │ ├── getCoingeckoPrice.ts │ ├── getCollectModule.ts │ ├── getCoverPicture.ts │ ├── getExport.ts │ ├── getFileFromDataURL.ts │ ├── getFollowModule.ts │ ├── getFromAttributes.ts │ ├── getHashTags.ts │ ├── getIsAuthTokensAvailable.ts │ ├── getLensHandle.ts │ ├── getLivePeer.ts │ ├── getModule.ts │ ├── getProfilePicture.ts │ ├── getRandomProfilePicture.ts │ ├── getSignature.ts │ ├── getStampFyiURL.ts │ ├── getTags.ts │ ├── getTextImage.ts │ ├── getTextNftUrl.ts │ ├── getThumbnailUrl.ts │ ├── getToastOptions.ts │ ├── getTokenImage.ts │ ├── getUniqueMessages.ts │ ├── getUniswapURL.ts │ ├── getUserLocale.ts │ ├── getVideoCoverUrl.ts │ ├── imageCdn.ts │ ├── omit.ts │ ├── onError.ts │ ├── parseJwt.ts │ ├── publicationKeyFields.ts │ ├── resolveEns.ts │ ├── sanitizeDisplayName.ts │ ├── sanitizeIpfsUrl.ts │ ├── sanitizeProfileInterests.ts │ ├── splitSignature.ts │ ├── trimify.ts │ ├── truncate.ts │ ├── uploadToAr.ts │ ├── uploadToIPFS.ts │ └── wav3sMirror.ts │ ├── hooks │ ├── useDebounce.ts │ ├── useDragAndDrop.ts │ ├── useGetConversation.tsx │ ├── useGetMessages.tsx │ ├── useHorizantalScroll.ts │ ├── useIsMounted.ts │ ├── useIsMounted.tsx │ ├── useMessagePreviews.tsx │ ├── useOutsideClick.ts │ ├── usePendingTxn.ts │ ├── useSendMessage.tsx │ ├── useStreamAllMessages.ts │ ├── useStreamMessages.tsx │ ├── useUploadAttachments.tsx │ ├── useWindowSize.tsx │ └── useXmtpClient.tsx │ ├── lens │ ├── .eslintrc.js │ ├── codegen.yml │ ├── documents │ │ ├── fragments │ │ │ ├── CollectFields.graphql │ │ │ ├── CollectModuleFields.graphql │ │ │ ├── CommentFields.graphql │ │ │ ├── MetadataFields.graphql │ │ │ ├── MirrorFields.graphql │ │ │ ├── PostFields.graphql │ │ │ ├── ProfileFields.graphql │ │ │ ├── RelayerResult.graphql │ │ │ ├── SimpleConditionFields.graphql │ │ │ └── StatsFields.graphql │ │ ├── mutations │ │ │ ├── AddProfileInterest.graphql │ │ │ ├── AddReaction.graphql │ │ │ ├── Authenticate.graphql │ │ │ ├── Broadcast.graphql │ │ │ ├── CreateBurnProfileTypedData.graphql │ │ │ ├── CreateCollectTypedData.graphql │ │ │ ├── CreateCommentTypedData.graphql │ │ │ ├── CreateCommentViaDispatcher.graphql │ │ │ ├── CreateFollowTypedData.graphql │ │ │ ├── CreateMirrorTypedData.graphql │ │ │ ├── CreateMirrorViaDispatcher.graphql │ │ │ ├── CreatePostTypedData.graphql │ │ │ ├── CreatePostViaDispatcher.graphql │ │ │ ├── CreateProfile.graphql │ │ │ ├── CreateSetDispatcherTypedData.graphql │ │ │ ├── CreateSetFollowModuleTypedData.graphql │ │ │ ├── CreateSetProfileImageURITypedData.graphql │ │ │ ├── CreateSetProfileImageURIViaDispatcher.graphql │ │ │ ├── CreateSetProfileMetadataTypedData.graphql │ │ │ ├── CreateSetProfileMetadataViaDispatcher.graphql │ │ │ ├── HidePublication.graphql │ │ │ ├── ProxyAction.graphql │ │ │ ├── RemoveProfileInterest.graphql │ │ │ ├── RemoveReaction.graphql │ │ │ └── ReportPublication.graphql │ │ └── queries │ │ │ ├── AllProfiles.graphql │ │ │ ├── AllPublicationsTags.graphql │ │ │ ├── ApprovedModuleAllowanceAmount.graphql │ │ │ ├── Challenge.graphql │ │ │ ├── CollectModule.graphql │ │ │ ├── Collectors.graphql │ │ │ ├── CommentFeed.graphql │ │ │ ├── CreateUnFollowTypedData.graphql │ │ │ ├── EnabledCurrencyModules.graphql │ │ │ ├── EnabledCurrencyModulesWithProfile.graphql │ │ │ ├── EnabledModuleCurrrencies.graphql │ │ │ ├── EnabledModules.graphql │ │ │ ├── Explore.graphql │ │ │ ├── Feed.graphql │ │ │ ├── Followers.graphql │ │ │ ├── Following.graphql │ │ │ ├── GenerateModuleCurrencyApprovalData.graphql │ │ │ ├── GlobalProtocolStats.graphql │ │ │ ├── HasPublicationIndexed.graphql │ │ │ ├── HasTxHashBeenIndexed.graphql │ │ │ ├── MutualFollowers.graphql │ │ │ ├── NFTChallenge.graphql │ │ │ ├── NFTFeed.graphql │ │ │ ├── NotificationCount.graphql │ │ │ ├── Notifications.graphql │ │ │ ├── Profile.graphql │ │ │ ├── ProfileAddress.graphql │ │ │ ├── ProfileComments.graphql │ │ │ ├── ProfileFollowModule.graphql │ │ │ ├── ProfileInterests.graphql │ │ │ ├── ProfileMirrors.graphql │ │ │ ├── ProfileNFTs.graphql │ │ │ ├── ProfilePosts.graphql │ │ │ ├── ProxyActionStatus.graphql │ │ │ ├── Publication.graphql │ │ │ ├── PublicationCollectModule.graphql │ │ │ ├── PublicationDetails.graphql │ │ │ ├── PublicationRevenue.graphql │ │ │ ├── Publications.graphql │ │ │ ├── RelevantPeople.graphql │ │ │ ├── SearchProfiles.graphql │ │ │ ├── SearchPublications.graphql │ │ │ ├── Subscribers.graphql │ │ │ ├── SuperFollow.graphql │ │ │ ├── TxIdToTxHash.graphql │ │ │ └── UserProfiles.graphql │ ├── generated.ts │ ├── package.json │ └── tsconfig.json │ └── paths.ts ├── tailwind.config.js ├── tsconfig.json └── yarn.lock /.env.example: -------------------------------------------------------------------------------- 1 | NEXT_PUBLIC_PINSTA_API_URL='http://localhost:5000' 2 | NEXT_PUBLIC_MIX_PANEL_ID 3 | NEXT_PUBLIC_ENVIRONMENT='testnet' -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "next/core-web-vitals" 3 | } 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # next.js 12 | /.next/ 13 | /out/ 14 | 15 | # production 16 | /build 17 | 18 | # misc 19 | .DS_Store 20 | *.pem 21 | 22 | # debug 23 | npm-debug.log* 24 | yarn-debug.log* 25 | yarn-error.log* 26 | .pnpm-debug.log* 27 | 28 | # local env files 29 | .env*.local 30 | 31 | # vercel 32 | .vercel 33 | 34 | # typescript 35 | *.tsbuildinfo 36 | next-env.d.ts 37 | 38 | # Auto Generated PWA files 39 | **/public/sw.js 40 | **/public/workbox-*.js 41 | **/public/worker-*.js 42 | **/public/sw.js.map 43 | **/public/workbox-*.js.map 44 | **/public/worker-*.js.map -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Pinsta is a decentralized image and video sharing platform that allows users to save and organize their discovery information using images, videos, and animated GIFs. This information is saved in the form of "pin boards," which are collections of pins that are grouped together based on a common theme or topic. Pinsta is designed to be a more private and secure alternative to traditional social media platforms, as it is decentralized and does not rely on a central authority to host and manage user data. Because Pinsta is decentralized, users have more control over their content and data, and can choose to share it with only the people they trust. This makes it a great option for users who want to save and share their discovery information without worrying about it being accessed by third parties. 2 | 3 | Built with Lens Protocol 🌿 4 | 5 | ## Inspired from LensTube & Lenster 6 | 7 | [Lenstube](https://github.com/lenstube-xyz/lenstube) 8 | [Lenster](https://github.com/lensterxyz/lenster) 9 | 10 | -------------------------------------------------------------------------------- /next.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('next').NextConfig} */ 2 | 3 | const nextConfig = { 4 | experimental: { 5 | scrollRestoration: true, 6 | newNextLinkBehavior: true 7 | }, 8 | images: { 9 | minimumCacheTTL: 3600, 10 | deviceSizes: [96, 128, 256, 384, 512, 640, 750, 828, 1080, 1200, 1920, 2048, 3840], 11 | imageSizes: [16, 32, 48, 64], 12 | remotePatterns: [ 13 | { 14 | protocol: "https", 15 | hostname: "**", 16 | }, 17 | ], 18 | }, 19 | reactStrictMode: process.env.NODE_ENV === 'production', 20 | swcMinify: true, 21 | async redirects() { 22 | return [ 23 | { 24 | source: '/discord', 25 | destination: 'https://discord.gg/7eCKW2Y3az', 26 | permanent: true 27 | }, 28 | { 29 | source: '/twitter', 30 | destination: 'https://twitter.com/PinstaApp', 31 | permanent: true 32 | }, 33 | { 34 | source: '/lenster', 35 | destination: 'https://lenster.xyz/u/pinsta', 36 | permanent: true 37 | }, 38 | { 39 | source: '/feedback', 40 | destination: 'https://pinsta.canny.io/', 41 | permanent: true 42 | }, 43 | { 44 | source: '/github', 45 | destination: 'https://github.com/jsonpreet/Pinsta', 46 | permanent: true 47 | } 48 | ]; 49 | } 50 | } 51 | 52 | module.exports = nextConfig 53 | -------------------------------------------------------------------------------- /postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | tailwindcss: {}, 4 | autoprefixer: {}, 5 | }, 6 | } 7 | -------------------------------------------------------------------------------- /public/android-chrome-192x192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jsonpreet/Pinsta/28919ce5abaf9981ed897c83184546751a8f012d/public/android-chrome-192x192.png -------------------------------------------------------------------------------- /public/android-chrome-512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jsonpreet/Pinsta/28919ce5abaf9981ed897c83184546751a8f012d/public/android-chrome-512x512.png -------------------------------------------------------------------------------- /public/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jsonpreet/Pinsta/28919ce5abaf9981ed897c83184546751a8f012d/public/apple-touch-icon.png -------------------------------------------------------------------------------- /public/badges/ens.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jsonpreet/Pinsta/28919ce5abaf9981ed897c83184546751a8f012d/public/badges/ens.png -------------------------------------------------------------------------------- /public/badges/poh.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jsonpreet/Pinsta/28919ce5abaf9981ed897c83184546751a8f012d/public/badges/poh.png -------------------------------------------------------------------------------- /public/badges/sybil.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jsonpreet/Pinsta/28919ce5abaf9981ed897c83184546751a8f012d/public/badges/sybil.png -------------------------------------------------------------------------------- /public/badges/worldcoin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jsonpreet/Pinsta/28919ce5abaf9981ed897c83184546751a8f012d/public/badges/worldcoin.png -------------------------------------------------------------------------------- /public/brands/lens.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jsonpreet/Pinsta/28919ce5abaf9981ed897c83184546751a8f012d/public/brands/lens.png -------------------------------------------------------------------------------- /public/brands/lenster.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /public/brands/twitter-dark.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /public/brands/twitter-light.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /public/brands/uniswap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jsonpreet/Pinsta/28919ce5abaf9981ed897c83184546751a8f012d/public/brands/uniswap.png -------------------------------------------------------------------------------- /public/dollar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jsonpreet/Pinsta/28919ce5abaf9981ed897c83184546751a8f012d/public/dollar.png -------------------------------------------------------------------------------- /public/fallbackThumbnail.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jsonpreet/Pinsta/28919ce5abaf9981ed897c83184546751a8f012d/public/fallbackThumbnail.png -------------------------------------------------------------------------------- /public/favicon-16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jsonpreet/Pinsta/28919ce5abaf9981ed897c83184546751a8f012d/public/favicon-16x16.png -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jsonpreet/Pinsta/28919ce5abaf9981ed897c83184546751a8f012d/public/favicon.ico -------------------------------------------------------------------------------- /public/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jsonpreet/Pinsta/28919ce5abaf9981ed897c83184546751a8f012d/public/favicon.png -------------------------------------------------------------------------------- /public/fonts/Metropolis-Black.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jsonpreet/Pinsta/28919ce5abaf9981ed897c83184546751a8f012d/public/fonts/Metropolis-Black.woff -------------------------------------------------------------------------------- /public/fonts/Metropolis-BlackItalic.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jsonpreet/Pinsta/28919ce5abaf9981ed897c83184546751a8f012d/public/fonts/Metropolis-BlackItalic.woff -------------------------------------------------------------------------------- /public/fonts/Metropolis-Bold.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jsonpreet/Pinsta/28919ce5abaf9981ed897c83184546751a8f012d/public/fonts/Metropolis-Bold.woff -------------------------------------------------------------------------------- /public/fonts/Metropolis-BoldItalic.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jsonpreet/Pinsta/28919ce5abaf9981ed897c83184546751a8f012d/public/fonts/Metropolis-BoldItalic.woff -------------------------------------------------------------------------------- /public/fonts/Metropolis-ExtraBold.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jsonpreet/Pinsta/28919ce5abaf9981ed897c83184546751a8f012d/public/fonts/Metropolis-ExtraBold.woff -------------------------------------------------------------------------------- /public/fonts/Metropolis-ExtraBoldItalic.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jsonpreet/Pinsta/28919ce5abaf9981ed897c83184546751a8f012d/public/fonts/Metropolis-ExtraBoldItalic.woff -------------------------------------------------------------------------------- /public/fonts/Metropolis-ExtraLight.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jsonpreet/Pinsta/28919ce5abaf9981ed897c83184546751a8f012d/public/fonts/Metropolis-ExtraLight.woff -------------------------------------------------------------------------------- /public/fonts/Metropolis-ExtraLightItalic.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jsonpreet/Pinsta/28919ce5abaf9981ed897c83184546751a8f012d/public/fonts/Metropolis-ExtraLightItalic.woff -------------------------------------------------------------------------------- /public/fonts/Metropolis-Light.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jsonpreet/Pinsta/28919ce5abaf9981ed897c83184546751a8f012d/public/fonts/Metropolis-Light.woff -------------------------------------------------------------------------------- /public/fonts/Metropolis-LightItalic.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jsonpreet/Pinsta/28919ce5abaf9981ed897c83184546751a8f012d/public/fonts/Metropolis-LightItalic.woff -------------------------------------------------------------------------------- /public/fonts/Metropolis-Medium.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jsonpreet/Pinsta/28919ce5abaf9981ed897c83184546751a8f012d/public/fonts/Metropolis-Medium.woff -------------------------------------------------------------------------------- /public/fonts/Metropolis-MediumItalic.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jsonpreet/Pinsta/28919ce5abaf9981ed897c83184546751a8f012d/public/fonts/Metropolis-MediumItalic.woff -------------------------------------------------------------------------------- /public/fonts/Metropolis-Regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jsonpreet/Pinsta/28919ce5abaf9981ed897c83184546751a8f012d/public/fonts/Metropolis-Regular.woff -------------------------------------------------------------------------------- /public/fonts/Metropolis-RegularItalic.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jsonpreet/Pinsta/28919ce5abaf9981ed897c83184546751a8f012d/public/fonts/Metropolis-RegularItalic.woff -------------------------------------------------------------------------------- /public/fonts/Metropolis-SemiBold.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jsonpreet/Pinsta/28919ce5abaf9981ed897c83184546751a8f012d/public/fonts/Metropolis-SemiBold.woff -------------------------------------------------------------------------------- /public/fonts/Metropolis-SemiBoldItalic.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jsonpreet/Pinsta/28919ce5abaf9981ed897c83184546751a8f012d/public/fonts/Metropolis-SemiBoldItalic.woff -------------------------------------------------------------------------------- /public/fonts/Metropolis-Thin.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jsonpreet/Pinsta/28919ce5abaf9981ed897c83184546751a8f012d/public/fonts/Metropolis-Thin.woff -------------------------------------------------------------------------------- /public/fonts/Metropolis-ThinItalic.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jsonpreet/Pinsta/28919ce5abaf9981ed897c83184546751a8f012d/public/fonts/Metropolis-ThinItalic.woff -------------------------------------------------------------------------------- /public/hashflags/bitcoin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jsonpreet/Pinsta/28919ce5abaf9981ed897c83184546751a8f012d/public/hashflags/bitcoin.png -------------------------------------------------------------------------------- /public/hashflags/blm.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jsonpreet/Pinsta/28919ce5abaf9981ed897c83184546751a8f012d/public/hashflags/blm.png -------------------------------------------------------------------------------- /public/hashflags/bts.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jsonpreet/Pinsta/28919ce5abaf9981ed897c83184546751a8f012d/public/hashflags/bts.png -------------------------------------------------------------------------------- /public/hashflags/btsarmy.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jsonpreet/Pinsta/28919ce5abaf9981ed897c83184546751a8f012d/public/hashflags/btsarmy.png -------------------------------------------------------------------------------- /public/hashflags/ethereum.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jsonpreet/Pinsta/28919ce5abaf9981ed897c83184546751a8f012d/public/hashflags/ethereum.png -------------------------------------------------------------------------------- /public/hashflags/hashtag.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jsonpreet/Pinsta/28919ce5abaf9981ed897c83184546751a8f012d/public/hashflags/hashtag.png -------------------------------------------------------------------------------- /public/hashflags/lens.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jsonpreet/Pinsta/28919ce5abaf9981ed897c83184546751a8f012d/public/hashflags/lens.png -------------------------------------------------------------------------------- /public/hashflags/lenster.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jsonpreet/Pinsta/28919ce5abaf9981ed897c83184546751a8f012d/public/hashflags/lenster.png -------------------------------------------------------------------------------- /public/hashflags/lenstube.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jsonpreet/Pinsta/28919ce5abaf9981ed897c83184546751a8f012d/public/hashflags/lenstube.png -------------------------------------------------------------------------------- /public/hashflags/pride.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jsonpreet/Pinsta/28919ce5abaf9981ed897c83184546751a8f012d/public/hashflags/pride.png -------------------------------------------------------------------------------- /public/hashflags/voted.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jsonpreet/Pinsta/28919ce5abaf9981ed897c83184546751a8f012d/public/hashflags/voted.png -------------------------------------------------------------------------------- /public/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jsonpreet/Pinsta/28919ce5abaf9981ed897c83184546751a8f012d/public/logo.png -------------------------------------------------------------------------------- /public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Pinsta App", 3 | "short_name": "Pinsta", 4 | "icons": [ 5 | { 6 | "src": "android-chrome-192x192.png", 7 | "sizes": "192x192", 8 | "type": "image/png", 9 | "purpose": "any maskable" 10 | }, 11 | { 12 | "src": "android-chrome-384x384.png", 13 | "sizes": "384x384", 14 | "type": "image/png" 15 | }, 16 | { 17 | "src": "icon-512x512.png", 18 | "sizes": "512x512", 19 | "type": "image/png" 20 | } 21 | ], 22 | "theme_color": "#FFFFFF", 23 | "background_color": "#FFFFFF", 24 | "start_url": "/", 25 | "display": "standalone", 26 | "orientation": "portrait" 27 | } -------------------------------------------------------------------------------- /public/meta.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jsonpreet/Pinsta/28919ce5abaf9981ed897c83184546751a8f012d/public/meta.png -------------------------------------------------------------------------------- /public/patterns/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jsonpreet/Pinsta/28919ce5abaf9981ed897c83184546751a8f012d/public/patterns/1.png -------------------------------------------------------------------------------- /public/patterns/10.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jsonpreet/Pinsta/28919ce5abaf9981ed897c83184546751a8f012d/public/patterns/10.png -------------------------------------------------------------------------------- /public/patterns/11.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jsonpreet/Pinsta/28919ce5abaf9981ed897c83184546751a8f012d/public/patterns/11.png -------------------------------------------------------------------------------- /public/patterns/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jsonpreet/Pinsta/28919ce5abaf9981ed897c83184546751a8f012d/public/patterns/2.png -------------------------------------------------------------------------------- /public/patterns/3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jsonpreet/Pinsta/28919ce5abaf9981ed897c83184546751a8f012d/public/patterns/3.png -------------------------------------------------------------------------------- /public/patterns/4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jsonpreet/Pinsta/28919ce5abaf9981ed897c83184546751a8f012d/public/patterns/4.png -------------------------------------------------------------------------------- /public/patterns/5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jsonpreet/Pinsta/28919ce5abaf9981ed897c83184546751a8f012d/public/patterns/5.png -------------------------------------------------------------------------------- /public/patterns/6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jsonpreet/Pinsta/28919ce5abaf9981ed897c83184546751a8f012d/public/patterns/6.png -------------------------------------------------------------------------------- /public/patterns/7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jsonpreet/Pinsta/28919ce5abaf9981ed897c83184546751a8f012d/public/patterns/7.png -------------------------------------------------------------------------------- /public/patterns/8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jsonpreet/Pinsta/28919ce5abaf9981ed897c83184546751a8f012d/public/patterns/8.png -------------------------------------------------------------------------------- /public/patterns/9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jsonpreet/Pinsta/28919ce5abaf9981ed897c83184546751a8f012d/public/patterns/9.png -------------------------------------------------------------------------------- /public/site.webmanifest: -------------------------------------------------------------------------------- 1 | {"name":"","short_name":"","icons":[{"src":"/android-chrome-192x192.png","sizes":"192x192","type":"image/png"},{"src":"/android-chrome-512x512.png","sizes":"512x512","type":"image/png"}],"theme_color":"#ffffff","background_color":"#ffffff","display":"standalone"} -------------------------------------------------------------------------------- /public/source/buttrfly.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jsonpreet/Pinsta/28919ce5abaf9981ed897c83184546751a8f012d/public/source/buttrfly.jpeg -------------------------------------------------------------------------------- /public/source/lensport.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jsonpreet/Pinsta/28919ce5abaf9981ed897c83184546751a8f012d/public/source/lensport.jpeg -------------------------------------------------------------------------------- /public/source/lenster.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jsonpreet/Pinsta/28919ce5abaf9981ed897c83184546751a8f012d/public/source/lenster.jpeg -------------------------------------------------------------------------------- /public/source/lenstube-bytes.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jsonpreet/Pinsta/28919ce5abaf9981ed897c83184546751a8f012d/public/source/lenstube-bytes.jpeg -------------------------------------------------------------------------------- /public/source/lenstube.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jsonpreet/Pinsta/28919ce5abaf9981ed897c83184546751a8f012d/public/source/lenstube.jpeg -------------------------------------------------------------------------------- /public/source/memester.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jsonpreet/Pinsta/28919ce5abaf9981ed897c83184546751a8f012d/public/source/memester.jpeg -------------------------------------------------------------------------------- /public/source/orb.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jsonpreet/Pinsta/28919ce5abaf9981ed897c83184546751a8f012d/public/source/orb.jpeg -------------------------------------------------------------------------------- /public/source/phaver.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jsonpreet/Pinsta/28919ce5abaf9981ed897c83184546751a8f012d/public/source/phaver.jpeg -------------------------------------------------------------------------------- /public/thanks/4everland-dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jsonpreet/Pinsta/28919ce5abaf9981ed897c83184546751a8f012d/public/thanks/4everland-dark.png -------------------------------------------------------------------------------- /public/thanks/4everland-light.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jsonpreet/Pinsta/28919ce5abaf9981ed897c83184546751a8f012d/public/thanks/4everland-light.png -------------------------------------------------------------------------------- /public/thanks/vercel-dark.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /public/thanks/vercel-light.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /public/tokens/dai.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /public/tokens/usdc.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/components/Common/BetaNotification.tsx: -------------------------------------------------------------------------------- 1 | import { FC } from 'react' 2 | 3 | const BetaNotification: FC = () => { 4 | return ( 5 |
6 |
7 |

NOTE: This is a alpha version of the site. Please report any bugs or issues you find.

8 |
9 |
10 | ) 11 | } 12 | 13 | export default BetaNotification -------------------------------------------------------------------------------- /src/components/Common/CollectWarning.tsx: -------------------------------------------------------------------------------- 1 | import { Card } from '@components/UI/Card'; 2 | import clsx from 'clsx'; 3 | import type { FC } from 'react'; 4 | import { BsStar } from 'react-icons/bs'; 5 | import { HiOutlineUsers } from 'react-icons/hi'; 6 | import Slug from './Slug'; 7 | 8 | interface Props { 9 | handle: string; 10 | isSuperFollow?: boolean | null; 11 | } 12 | 13 | const CollectWarning: FC = ({ handle, isSuperFollow = false }) => { 14 | return ( 15 | 21 | {isSuperFollow ? ( 22 | <> 23 | 24 | Only 25 | 26 | super followers 27 | can collect 28 | 29 | ) : ( 30 | <> 31 | 32 | Only 33 | 34 | followers can collect 35 | 36 | )} 37 | 38 | ); 39 | }; 40 | 41 | export default CollectWarning; -------------------------------------------------------------------------------- /src/components/Common/ErrorBoundary.tsx: -------------------------------------------------------------------------------- 1 | import Custom500 from '@pages/500'; 2 | import type { ReactNode } from 'react'; 3 | import { Component } from 'react'; 4 | 5 | interface ErrorBoundaryProps { 6 | children?: ReactNode; 7 | } 8 | 9 | interface ErrorBoundaryState { 10 | hasError: boolean; 11 | } 12 | 13 | class ErrorBoundary extends Component { 14 | public state: ErrorBoundaryState = { 15 | hasError: false 16 | }; 17 | 18 | public static getDerivedStateFromError(): ErrorBoundaryState { 19 | return { hasError: true }; 20 | } 21 | 22 | public componentDidCatch(error: Error) { 23 | console.error('Uncaught error:', error); 24 | } 25 | 26 | public render() { 27 | if (this.state.hasError) { 28 | return ; 29 | } 30 | 31 | return this.props.children; 32 | } 33 | } 34 | 35 | export default ErrorBoundary; -------------------------------------------------------------------------------- /src/components/Common/InterweaveContent.tsx: -------------------------------------------------------------------------------- 1 | import { Interweave } from 'interweave' 2 | import { EmailMatcher } from 'interweave-autolink' 3 | import type { FC, MouseEvent } from 'react'; 4 | 5 | import { HashtagMatcher } from './matchers/HashtagMatcher' 6 | import { MentionMatcher } from './matchers/MentionMatcher' 7 | import { UrlMatcher } from './matchers/UrlMatcher' 8 | import { MDLinkMatcher } from './matchers/markdown/MDLinkMatcher'; 9 | import { MDBoldMatcher } from './matchers/markdown/MDBoldMatcher'; 10 | import { MDItalicMatcher } from './matchers/markdown/MDItalicMatcher'; 11 | import { MDStrikeMatcher } from './matchers/markdown/MDStrikeMatcher'; 12 | import { MDQuoteMatcher } from './matchers/markdown/MDQuoteMatcher'; 13 | import { MDCodeMatcher } from './matchers/markdown/MDCodeMatcher'; 14 | import trimify from '@utils/functions/trimify' 15 | 16 | const InterweaveContent = ({ content }: { content: string }) => { 17 | const matchers = [ 18 | new MDCodeMatcher('mdCode'), 19 | new MentionMatcher('mention'), 20 | new MDLinkMatcher('mdLink'), 21 | new UrlMatcher('url'), 22 | new HashtagMatcher('hashtag'), 23 | new MDBoldMatcher('mdBold'), 24 | new MDItalicMatcher('mdItalic'), 25 | new MDStrikeMatcher('mdStrike'), 26 | new MDQuoteMatcher('mdQuote') 27 | ] 28 | return ( 29 | 30 | ) => event.stopPropagation()} 36 | matchers={matchers} 37 | /> 38 | 39 | ) 40 | } 41 | 42 | export default InterweaveContent -------------------------------------------------------------------------------- /src/components/Common/Menu/index.ts: -------------------------------------------------------------------------------- 1 | export { default as Menu } from './Menu' -------------------------------------------------------------------------------- /src/components/Common/MetaTags.tsx: -------------------------------------------------------------------------------- 1 | import Head from 'next/head' 2 | import { useRouter } from 'next/router' 3 | import type { FC } from 'react' 4 | import React from 'react' 5 | import { APP } from '@utils/constants' 6 | import { NextSeo } from 'next-seo' 7 | 8 | type Props = { 9 | title?: string 10 | description?: string | null 11 | image?: string 12 | } 13 | 14 | const MetaTags: FC = (props) => { 15 | const { description, title, image } = props 16 | const router = useRouter() 17 | 18 | const meta = { 19 | title: title ?? APP.Name, 20 | description: description ?? APP.Description, 21 | image: image ?? `${APP.URL}${APP.Meta.image}`, 22 | type: 'website' 23 | } 24 | 25 | return ( 26 | 42 | ) 43 | } 44 | 45 | export default MetaTags -------------------------------------------------------------------------------- /src/components/Common/ReferralAlert.tsx: -------------------------------------------------------------------------------- 1 | import type { ElectedMirror, Publication } from '@utils/lens'; 2 | import type { FC } from 'react'; 3 | import { BsHeart } from 'react-icons/bs'; 4 | import Slug from './Slug'; 5 | import formatHandle from '@utils/functions/formatHandle'; 6 | 7 | interface Props { 8 | mirror: Publication; 9 | referralFee?: number; 10 | electedMirror?: ElectedMirror; 11 | } 12 | 13 | const ReferralAlert: FC = ({ mirror, electedMirror, referralFee = 0 }) => { 14 | if ((mirror.__typename !== 'Mirror' && !electedMirror) || referralFee === 0) { 15 | return null; 16 | } 17 | const publication = electedMirror ?? mirror; 18 | 19 | return ( 20 |
21 | 22 | 23 | 24 | {' '} 25 | will get {referralFee}% referral fee 26 | 27 |
28 | ); 29 | }; 30 | 31 | export default ReferralAlert; -------------------------------------------------------------------------------- /src/components/Common/Search/Profiles.tsx: -------------------------------------------------------------------------------- 1 | /* eslint-disable @next/next/no-img-element */ 2 | import type { Profile } from '@utils/lens' 3 | import type { FC } from 'react' 4 | import React from 'react' 5 | import UserProfile from '../UserProfile' 6 | 7 | interface Props { 8 | results: Profile[] 9 | onProfileSelected? : (profile: Profile) => void 10 | loading: boolean 11 | linkToProfile?: boolean 12 | clearSearch: () => void 13 | } 14 | 15 | const Profiles: FC = ({ results, loading, clearSearch, onProfileSelected, linkToProfile }) => { 16 | return ( 17 | <> 18 | {results?.map((profile: Profile) => ( 19 |
{ 21 | clearSearch() 22 | if (onProfileSelected) { 23 | onProfileSelected(profile); 24 | } 25 | }} 26 | key={profile.id} 27 | className="px-5 py-2 cursor-pointer hover:bg-gray-100 dark:hover:bg-gray-900" 28 | role="button" 29 | > 30 | 35 |
36 | ))} 37 | {!results?.length && !loading && ( 38 |
39 | No results found. 40 |
41 | )} 42 | 43 | ) 44 | } 45 | 46 | export default Profiles -------------------------------------------------------------------------------- /src/components/Common/Slider/buttons.tsx: -------------------------------------------------------------------------------- 1 | import React, { FC } from "react"; 2 | import { BiChevronLeft, BiChevronRight } from "react-icons/bi"; 3 | import clsx from "clsx"; 4 | 5 | interface Props { 6 | direction: string; 7 | moveSlide: () => void; 8 | } 9 | 10 | const SliderBtn:FC = ({ direction, moveSlide }) => { 11 | return ( 12 | 22 | ); 23 | } 24 | 25 | export default SliderBtn; -------------------------------------------------------------------------------- /src/components/Common/Slug.tsx: -------------------------------------------------------------------------------- 1 | import clsx from 'clsx'; 2 | import type { FC } from 'react'; 3 | 4 | interface Props { 5 | slug: string; 6 | prefix?: string; 7 | className?: string; 8 | isMention?: boolean; 9 | } 10 | 11 | const Slug: FC = ({ slug, prefix, isMention = false, className = '' }) => { 12 | return ( 13 | 16 | {prefix} 17 | {slug} 18 | 19 | ); 20 | }; 21 | 22 | export default Slug; -------------------------------------------------------------------------------- /src/components/Common/ThemeSwitch.tsx: -------------------------------------------------------------------------------- 1 | import { useTheme } from 'next-themes' 2 | import React, {FC} from 'react' 3 | import { BsMoon, BsSun } from 'react-icons/bs' 4 | 5 | const ThemeSwitch: FC = () => { 6 | const { theme, setTheme } = useTheme() 7 | 8 | return ( 9 | <> 10 | 21 | 22 | ) 23 | } 24 | 25 | export default ThemeSwitch -------------------------------------------------------------------------------- /src/components/Common/Uniswap.tsx: -------------------------------------------------------------------------------- 1 | import type { PinstaCollectModule, PinstaFollowModule } from '@utils/custom-types'; 2 | import getUniswapURL from '@utils/functions/getUniswapURL'; 3 | import type { FC } from 'react'; 4 | 5 | interface Props { 6 | module: PinstaCollectModule | PinstaFollowModule; 7 | } 8 | 9 | const Uniswap: FC = ({ module }) => { 10 | return ( 11 |
12 |
13 | You don't have enough {module?.amount?.asset?.symbol} 14 |
15 | 21 | Uniswap 28 |
Swap in Uniswap
29 |
30 |
31 | ); 32 | }; 33 | 34 | export default Uniswap; -------------------------------------------------------------------------------- /src/components/Common/Video.tsx: -------------------------------------------------------------------------------- 1 | import type { FC } from 'react'; 2 | import type { AspectRatio } from '@livepeer/react' 3 | import { Player } from '@livepeer/react' 4 | import React from 'react'; 5 | import { IPFS_GATEWAY } from '@utils/constants'; 6 | 7 | export interface PlayerProps { 8 | playerRef?: (ref: HTMLMediaElement) => void 9 | src: string 10 | posterUrl?: string 11 | ratio?: AspectRatio 12 | showControls?: boolean 13 | options?: { 14 | autoPlay?: boolean 15 | muted?: boolean 16 | loop?: boolean 17 | loadingSpinner: boolean 18 | } 19 | } 20 | 21 | const Video: FC = ({ 22 | ratio = '16to9', 23 | src, 24 | posterUrl, 25 | playerRef, 26 | options, 27 | showControls = true 28 | }) => { 29 | return ( 30 | 49 | {/* eslint-disable-next-line react/jsx-no-useless-fragment */} 50 | {!showControls ? <> : null} 51 | 52 | ) 53 | } 54 | 55 | export default React.memo(Video) -------------------------------------------------------------------------------- /src/components/Common/matchers/HashtagMatcher.tsx: -------------------------------------------------------------------------------- 1 | import { Matcher } from 'interweave' 2 | import Link from 'next/link' 3 | import React from 'react' 4 | 5 | const Hashtag = ({ ...props }: any) => { 6 | return ( 7 | 8 | 9 | 10 | {props.display} 11 | 12 | 13 | 14 | ) 15 | } 16 | 17 | export class HashtagMatcher extends Matcher { 18 | replaceWith(match: string, props: any) { 19 | return React.createElement(Hashtag, props, match) 20 | } 21 | 22 | asTag(): string { 23 | return 'a' 24 | } 25 | 26 | match(value: string) { 27 | return this.doMatch(value, /\B#(\w+)/, (matches) => { 28 | return { 29 | display: matches[0] 30 | } 31 | }) 32 | } 33 | } -------------------------------------------------------------------------------- /src/components/Common/matchers/MentionMatcher.tsx: -------------------------------------------------------------------------------- 1 | import Slug from '@components/Common/Slug'; 2 | import UserPreview from '@components/Common/UserPreview'; 3 | import formatHandle from '@utils/functions/formatHandle'; 4 | import { Matcher } from 'interweave'; 5 | import type { Profile } from '@utils/lens'; 6 | import Link from 'next/link'; 7 | import { createElement } from 'react'; 8 | 9 | export const Mention = ({ ...props }: any) => { 10 | const profile = { 11 | __typename: 'Profile', 12 | handle: props?.display.slice(1), 13 | name: null, 14 | id: null 15 | }; 16 | 17 | return ( 18 | { 21 | event.stopPropagation(); 22 | }} 23 | > 24 | 25 | {/* {profile?.handle ? ( 26 | 31 | 32 | 33 | ) : ( 34 | 35 | )} */} 36 | 37 | ); 38 | }; 39 | 40 | export class MentionMatcher extends Matcher { 41 | replaceWith(match: string, props: any) { 42 | return createElement(Mention, props, match); 43 | } 44 | 45 | asTag(): string { 46 | return 'a'; 47 | } 48 | 49 | match(value: string) { 50 | return this.doMatch(value, /@[\w.-]+/, (matches) => { 51 | return { display: matches[0] }; 52 | }); 53 | } 54 | } -------------------------------------------------------------------------------- /src/components/Common/matchers/markdown/MDBoldMatcher.tsx: -------------------------------------------------------------------------------- 1 | import type { ChildrenNode } from 'interweave'; 2 | import { Matcher } from 'interweave'; 3 | 4 | export class MDBoldMatcher extends Matcher { 5 | replaceWith(children: ChildrenNode) { 6 | return {children}; 7 | } 8 | 9 | asTag(): string { 10 | return 'b'; 11 | } 12 | 13 | match(value: string) { 14 | return this.doMatch(value, /\*\*([^**]*?)\*\*/u, (matches) => ({ 15 | match: matches[1] 16 | })); 17 | } 18 | } -------------------------------------------------------------------------------- /src/components/Common/matchers/markdown/MDCodeMatcher.tsx: -------------------------------------------------------------------------------- 1 | import type { ChildrenNode } from 'interweave'; 2 | import { Matcher } from 'interweave'; 3 | 4 | export class MDCodeMatcher extends Matcher { 5 | replaceWith(children: ChildrenNode) { 6 | return ( 7 | {children} 8 | ); 9 | } 10 | 11 | asTag(): string { 12 | return 'code'; 13 | } 14 | 15 | match(value: string) { 16 | return this.doMatch( 17 | value, 18 | /`(.*?)`/u, 19 | (matches) => ({ 20 | match: matches[1] 21 | }), 22 | true 23 | ); 24 | } 25 | } -------------------------------------------------------------------------------- /src/components/Common/matchers/markdown/MDItalicMatcher.tsx: -------------------------------------------------------------------------------- 1 | import type { ChildrenNode } from 'interweave'; 2 | import { Matcher } from 'interweave'; 3 | 4 | export class MDItalicMatcher extends Matcher { 5 | replaceWith(children: ChildrenNode) { 6 | return {children}; 7 | } 8 | 9 | asTag(): string { 10 | return 'i'; 11 | } 12 | 13 | match(value: string) { 14 | return this.doMatch(value, /\*([^**]*?)\*/u, (matches) => ({ 15 | match: matches[1] 16 | })); 17 | } 18 | } -------------------------------------------------------------------------------- /src/components/Common/matchers/markdown/MDLinkMatcher.tsx: -------------------------------------------------------------------------------- 1 | import type { ChildrenNode } from 'interweave'; 2 | import { Matcher } from 'interweave'; 3 | import { v4 as uuid } from 'uuid'; 4 | 5 | const createHyperlink = (href: string | undefined, title: string | undefined) => { 6 | const keyId = '_' + href + '-' + uuid().slice(-7); 7 | return ( 8 | 9 | {title} 10 | 11 | ); 12 | }; 13 | 14 | export class MDLinkMatcher extends Matcher { 15 | replaceWith(children: ChildrenNode, props: any) { 16 | return createHyperlink(props.href, props.title); 17 | } 18 | 19 | asTag(): string { 20 | return 'a'; 21 | } 22 | 23 | match(value: string) { 24 | return this.doMatch(value, /\[(.*?)\]\((.*?)\)/u, (matches) => ({ 25 | href: matches[2], 26 | title: matches[1] 27 | })); 28 | } 29 | } -------------------------------------------------------------------------------- /src/components/Common/matchers/markdown/MDQuoteMatcher.tsx: -------------------------------------------------------------------------------- 1 | import type { ChildrenNode } from 'interweave'; 2 | import { Matcher } from 'interweave'; 3 | 4 | export class MDQuoteMatcher extends Matcher { 5 | replaceWith(children: ChildrenNode) { 6 | return ( 7 | 8 | {children} 9 | 10 | ); 11 | } 12 | 13 | asTag(): string { 14 | return 'span'; 15 | } 16 | 17 | match(value: string) { 18 | return this.doMatch(value, /^> (.*$)/, (matches) => ({ 19 | match: matches[1] 20 | })); 21 | } 22 | } -------------------------------------------------------------------------------- /src/components/Common/matchers/markdown/MDStrikeMatcher.tsx: -------------------------------------------------------------------------------- 1 | import type { ChildrenNode } from 'interweave'; 2 | import { Matcher } from 'interweave'; 3 | 4 | export class MDStrikeMatcher extends Matcher { 5 | replaceWith(children: ChildrenNode) { 6 | return {children}; 7 | } 8 | 9 | asTag(): string { 10 | return 's'; 11 | } 12 | 13 | match(value: string) { 14 | return this.doMatch(value, /~~(.*?)~~/u, (matches) => ({ 15 | match: matches[1] 16 | })); 17 | } 18 | } -------------------------------------------------------------------------------- /src/components/Home/index.tsx: -------------------------------------------------------------------------------- 1 | import MetaTags from '@components/Common/MetaTags' 2 | import type { NextPage } from 'next' 3 | import useAppStore from '@lib/store' 4 | import { Analytics, TRACK } from '@utils/analytics' 5 | import { useEffect } from 'react' 6 | import usePersistStore from '@lib/store/persist' 7 | import Explore from './Explore' 8 | import Feed from './Feed' 9 | 10 | const Home: NextPage = () => { 11 | const currentProfile = useAppStore((state) => state.currentProfile) 12 | const currentProfileId = usePersistStore((state) => state.currentProfileId) 13 | 14 | useEffect(() => { 15 | Analytics.track(TRACK.PAGE_VIEW.HOME) 16 | }, []) 17 | 18 | return ( 19 | <> 20 | 21 | {!currentProfile && !currentProfileId ? ( 22 | 23 | ) 24 | : 25 | } 26 | 27 | ) 28 | } 29 | 30 | export default Home -------------------------------------------------------------------------------- /src/components/Messages/Attachment.tsx: -------------------------------------------------------------------------------- 1 | import imageCdn from '@utils/functions/imageCdn'; 2 | import sanitizeIpfsUrl from '@utils/functions/sanitizeIpfsUrl'; 3 | import Link from 'next/link'; 4 | import type { FC } from 'react'; 5 | import type { Attachment as TAttachment } from 'xmtp-content-type-remote-attachment'; 6 | 7 | interface AttachmentProps { 8 | attachment: TAttachment; 9 | } 10 | 11 | const isImage = (mimeType: string): boolean => 12 | ['image/png', 'image/jpeg', 'image/gif'].includes(mimeType); 13 | 14 | const Attachment: FC = ({ attachment }) => { 15 | /** 16 | * The attachment.data gets turned into an object when it's serialized 17 | * via JSON.stringify in the store persistence. This check restores it 18 | * to the correct type. 19 | */ 20 | if (!(attachment.data instanceof Uint8Array)) { 21 | attachment.data = Uint8Array.from(Object.values(attachment.data)); 22 | } 23 | 24 | const objectURL = URL.createObjectURL( 25 | new Blob([Buffer.from(attachment.data)], { 26 | type: attachment.mimeType 27 | }) 28 | ); 29 | 30 | if (isImage(attachment.mimeType)) { 31 | return ( 32 | // eslint-disable-next-line @next/next/no-img-element 33 | {attachment.filename} 38 | ); 39 | } 40 | 41 | return ( 42 | 43 | {attachment.filename} 44 | 45 | ); 46 | }; 47 | 48 | export default Attachment; -------------------------------------------------------------------------------- /src/components/Messages/index.tsx: -------------------------------------------------------------------------------- 1 | import MetaTags from '@components/Common/MetaTags'; 2 | import { Card } from '@components/UI/Card'; 3 | import { APP } from '@utils/constants'; 4 | import type { NextPage } from 'next'; 5 | import Custom404 from 'src/pages/404'; 6 | 7 | import PreviewList from './PreviewList'; 8 | import useAppStore from '@lib/store'; 9 | 10 | const NoConversationSelected = () => { 11 | return ( 12 |
13 |
14 | 👋 15 |

16 | Select a conversation 17 |

18 |

19 | Choose an existing conversation or create a new one to start messaging 20 |

21 |
22 |
23 | ); 24 | }; 25 | 26 | const Messages: NextPage = () => { 27 | 28 | const currentProfile = useAppStore((state) => state.currentProfile); 29 | 30 | if (!currentProfile) { 31 | return ; 32 | } 33 | 34 | return ( 35 | <> 36 | 37 |
38 | 39 |
40 | 41 | 42 | 43 |
44 |
45 | 46 | ); 47 | }; 48 | 49 | export default Messages; -------------------------------------------------------------------------------- /src/components/Notifications/Menu/Profile.tsx: -------------------------------------------------------------------------------- 1 | /* eslint-disable @next/next/no-img-element */ 2 | import formatHandle from '@utils/functions/formatHandle'; 3 | import IsVerified from '@components/UI/IsVerified'; 4 | import getProfilePicture from '@utils/functions/getProfilePicture'; 5 | import type { Profile } from '@utils/lens'; 6 | import Link from 'next/link'; 7 | import type { FC } from 'react'; 8 | import { AVATAR } from '@utils/constants'; 9 | 10 | interface Props { 11 | profile: Profile; 12 | } 13 | 14 | export const NotificationProfileAvatar: FC = ({ profile }) => { 15 | return ( 16 | 17 | {formatHandle(profile?.handle)} 24 | 25 | ); 26 | }; 27 | 28 | export const NotificationProfileName: FC = ({ profile }) => { 29 | return ( 30 | 34 |
{profile?.name ?? formatHandle(profile?.handle)}
35 | 36 | 37 | ); 38 | }; -------------------------------------------------------------------------------- /src/components/Notifications/Menu/Type/CollectNotification/Amount.tsx: -------------------------------------------------------------------------------- 1 | 2 | import { formatNumber } from '@utils/functions/formatNumber'; 3 | import getTokenImage from '@utils/functions/getTokenImage'; 4 | import type { NewCollectNotification } from '@utils/lens'; 5 | import type { FC } from 'react'; 6 | import { HiOutlineCurrencyDollar } from 'react-icons/hi2'; 7 | 8 | interface Props { 9 | notification: NewCollectNotification; 10 | } 11 | 12 | const CollectedAmount: FC = ({ notification }) => { 13 | const collectModule: any = notification?.collectedPublication?.collectModule; 14 | 15 | return ( 16 |
17 | 18 | {!collectModule || collectModule.__typename === 'FreeCollectModuleSettings' ? ( 19 |
Collected for free
20 | ) : ( 21 | <> 22 |
23 | Collected for {formatNumber(collectModule?.amount?.value)} {collectModule?.amount?.asset?.symbol} 24 |
25 | {collectModule?.amount?.asset?.symbol} 32 | 33 | )} 34 |
35 | ); 36 | }; 37 | 38 | export default CollectedAmount; -------------------------------------------------------------------------------- /src/components/Notifications/Menu/Type/CollectNotification/Content.tsx: -------------------------------------------------------------------------------- 1 | import InterweaveContent from '@components/Common/InterweaveContent'; 2 | import type { NewCollectNotification } from '@utils/lens'; 3 | import Link from 'next/link'; 4 | import type { FC } from 'react'; 5 | 6 | interface Props { 7 | notification: NewCollectNotification; 8 | } 9 | 10 | const CollectedContent: FC = ({ notification }) => { 11 | return ( 12 | 16 | 17 | 18 | ); 19 | }; 20 | 21 | export default CollectedContent; -------------------------------------------------------------------------------- /src/components/Notifications/Menu/Type/CommentNotification.tsx: -------------------------------------------------------------------------------- 1 | import dayjs from 'dayjs'; 2 | import relativeTime from 'dayjs/plugin/relativeTime'; 3 | import type { NewCommentNotification } from '@utils/lens'; 4 | import Link from 'next/link'; 5 | import type { FC } from 'react'; 6 | 7 | import { NotificationProfileAvatar, NotificationProfileName } from '../Profile'; 8 | import { HiOutlineChatAlt2 } from 'react-icons/hi'; 9 | 10 | dayjs.extend(relativeTime); 11 | 12 | interface Props { 13 | notification: NewCommentNotification; 14 | } 15 | 16 | const CommentNotification: FC = ({ notification }) => { 17 | return ( 18 |
19 |
20 |
21 | {/* */} 22 | 23 | 24 |
25 | commented on your 26 | 27 | {notification?.comment?.commentOn?.__typename?.toLowerCase()} 28 | 29 |
30 |
31 |
32 | {/*
33 | {dayjs(new Date(notification?.createdAt)).fromNow()} 34 |
*/} 35 |
36 | ); 37 | }; 38 | 39 | export default CommentNotification; -------------------------------------------------------------------------------- /src/components/Notifications/Profile.tsx: -------------------------------------------------------------------------------- 1 | /* eslint-disable @next/next/no-img-element */ 2 | import formatHandle from '@utils/functions/formatHandle'; 3 | import IsVerified from '@components/UI/IsVerified'; 4 | import getProfilePicture from '@utils/functions/getProfilePicture'; 5 | import type { Profile } from '@utils/lens'; 6 | import Link from 'next/link'; 7 | import type { FC } from 'react'; 8 | import { AVATAR } from '@utils/constants'; 9 | 10 | interface Props { 11 | profile: Profile; 12 | } 13 | 14 | export const NotificationProfileAvatar: FC = ({ profile }) => { 15 | return ( 16 | 17 | {formatHandle(profile?.handle)} 24 | 25 | ); 26 | }; 27 | 28 | export const NotificationProfileName: FC = ({ profile }) => { 29 | return ( 30 | 34 |
{profile?.name ?? formatHandle(profile?.handle)}
35 | 36 | 37 | ); 38 | }; -------------------------------------------------------------------------------- /src/components/Notifications/Type/CollectNotification/Amount.tsx: -------------------------------------------------------------------------------- 1 | /* eslint-disable @next/next/no-img-element */ 2 | 3 | import { formatNumber } from '@utils/functions/formatNumber'; 4 | import getTokenImage from '@utils/functions/getTokenImage'; 5 | import type { NewCollectNotification } from '@utils/lens'; 6 | import type { FC } from 'react'; 7 | import { HiOutlineCurrencyDollar } from 'react-icons/hi2'; 8 | 9 | interface Props { 10 | notification: NewCollectNotification; 11 | } 12 | 13 | const CollectedAmount: FC = ({ notification }) => { 14 | const collectModule: any = notification?.collectedPublication?.collectModule; 15 | 16 | return ( 17 |
18 | 19 | {!collectModule || collectModule.__typename === 'FreeCollectModuleSettings' ? ( 20 |
Collected for free
21 | ) : ( 22 | <> 23 |
24 | Collected for {formatNumber(collectModule?.amount?.value)} {collectModule?.amount?.asset?.symbol} 25 |
26 | {collectModule?.amount?.asset?.symbol} 33 | 34 | )} 35 |
36 | ); 37 | }; 38 | 39 | export default CollectedAmount; -------------------------------------------------------------------------------- /src/components/Notifications/Type/CollectNotification/Content.tsx: -------------------------------------------------------------------------------- 1 | import InterweaveContent from '@components/Common/InterweaveContent'; 2 | import type { NewCollectNotification } from '@utils/lens'; 3 | import Link from 'next/link'; 4 | import type { FC } from 'react'; 5 | 6 | interface Props { 7 | notification: NewCollectNotification; 8 | } 9 | 10 | const CollectedContent: FC = ({ notification }) => { 11 | return ( 12 | 16 | 17 | 18 | ); 19 | }; 20 | 21 | export default CollectedContent; -------------------------------------------------------------------------------- /src/components/Notifications/WalletProfile.tsx: -------------------------------------------------------------------------------- 1 | /* eslint-disable @next/next/no-img-element */ 2 | import formatAddress from '@utils/functions/formatAddress'; 3 | import getStampFyiURL from '@utils/functions/getStampFyiURL'; 4 | import { AVATAR, POLYGONSCAN_URL } from '@utils/constants'; 5 | import type { Wallet } from '@utils/lens'; 6 | import type { FC } from 'react'; 7 | import imageCdn from '@utils/functions/imageCdn'; 8 | 9 | interface Props { 10 | wallet: Wallet; 11 | } 12 | 13 | export const NotificationWalletProfileAvatar: FC = ({ wallet }) => { 14 | return ( 15 | 16 | {wallet?.address} 23 | 24 | ); 25 | }; 26 | 27 | export const NotificationWalletProfileName: FC = ({ wallet }) => { 28 | return ( 29 | 35 |
{formatAddress(wallet?.address)}
36 |
37 | ); 38 | }; -------------------------------------------------------------------------------- /src/components/Pin/Attachments/PinVideo.tsx: -------------------------------------------------------------------------------- 1 | import Video from '@components/Common/Video' 2 | import { ALLOWED_APP_IDS, THUMBNAIL_LG } from '@utils/constants' 3 | import { PinstaPublication } from '@utils/custom-types' 4 | import getVideoCoverUrl from '@utils/functions/getVideoCoverUrl' 5 | import imageCdn from '@utils/functions/imageCdn' 6 | import sanitizeIpfsUrl from '@utils/functions/sanitizeIpfsUrl' 7 | import React, { FC } from 'react' 8 | 9 | interface Props { 10 | pin: PinstaPublication 11 | } 12 | 13 | const PinVideo:FC = ({pin}) => { 14 | const url = sanitizeIpfsUrl(pin?.metadata?.media[0].original?.url); 15 | return ( 16 | <> 17 |
18 |
19 |
27 |
28 | 29 | ) 30 | } 31 | 32 | export default PinVideo -------------------------------------------------------------------------------- /src/components/Pin/Attachments/index.tsx: -------------------------------------------------------------------------------- 1 | /* eslint-disable @next/next/no-img-element */ 2 | import { Analytics } from '@utils/analytics' 3 | import { PinstaPublication } from '@utils/custom-types' 4 | import { FC, useEffect } from 'react' 5 | import useAppStore from '@lib/store' 6 | import { ALLOWED_IMAGE_TYPES, ALLOWED_VIDEO_TYPES } from '@utils/constants' 7 | import PinImage from './PinImage' 8 | import PinVideo from './PinVideo' 9 | 10 | interface Props { 11 | pin: PinstaPublication 12 | } 13 | 14 | const Attachments: FC = ({ pin }) => { 15 | const currentProfile = useAppStore((state) => state.currentProfile) 16 | 17 | const isVideo = ALLOWED_VIDEO_TYPES.includes(pin?.metadata?.media[0]?.original.mimeType) 18 | const isImage = ALLOWED_IMAGE_TYPES.includes(pin?.metadata?.media[0]?.original.mimeType) 19 | 20 | useEffect(() => { 21 | Analytics.track(`viewed_pin_${pin.id}`) 22 | // eslint-disable-next-line react-hooks/exhaustive-deps 23 | }, []) 24 | 25 | return ( 26 | <> 27 |
30 | {isImage ? ( 31 | 32 | ) : null} 33 | {isVideo ? ( 34 | 35 | ) : null} 36 |
37 | 38 | ) 39 | } 40 | 41 | export default Attachments -------------------------------------------------------------------------------- /src/components/Profile/Cover.tsx: -------------------------------------------------------------------------------- 1 | import { COVER } from '@utils/constants'; 2 | import type { FC } from 'react'; 3 | import sanitizeIpfsUrl from '@utils/functions/sanitizeIpfsUrl'; 4 | import imageCdn from '@utils/functions/imageCdn'; 5 | import { Profile } from '@utils/lens/generated'; 6 | import {LeftMetaDetails, RightMetaDetails} from './MetaDetails'; 7 | 8 | interface Props { 9 | cover: string; 10 | profile: Profile; 11 | } 12 | 13 | const Cover: FC = ({ cover, profile }) => { 14 | return ( 15 | <> 16 |
17 |
29 |
30 | 31 |
32 |
33 | 34 |
35 |
36 | 37 | ); 38 | }; 39 | 40 | export default Cover; -------------------------------------------------------------------------------- /src/components/Profile/Followerings.tsx: -------------------------------------------------------------------------------- 1 | import { formatNumber } from '@utils/functions/formatNumber'; 2 | import type { Profile } from '@utils/lens'; 3 | import type { FC } from 'react'; 4 | 5 | interface Props { 6 | profile: Profile; 7 | } 8 | 9 | const Followerings: FC = ({ profile }) => { 10 | return ( 11 |
12 |
13 |
{formatNumber(profile?.stats?.totalFollowing)}
14 |
Following
15 |
16 |
17 |
{formatNumber(profile?.stats?.totalFollowers)}
18 |
Followers
19 |
20 |
21 | ); 22 | }; 23 | 24 | export default Followerings; -------------------------------------------------------------------------------- /src/components/Profile/Info.tsx: -------------------------------------------------------------------------------- 1 | import { Profile } from "@utils/lens/generated" 2 | import Cover from "./Cover" 3 | import Details from "./Details" 4 | 5 | const Info = ({ profile }: { profile: Profile }) => { 6 | return ( 7 | <> 8 |
9 |
10 | 18 |
19 |
20 |
21 |
22 |
23 | 24 | ) 25 | } 26 | 27 | export default Info -------------------------------------------------------------------------------- /src/components/Profile/Pins/All.tsx: -------------------------------------------------------------------------------- 1 | 2 | import { Profile } from '@utils/lens/generated' 3 | import { FC } from 'react' 4 | import BoardPins from './Common/Pins' 5 | 6 | interface Props { 7 | profile: Profile 8 | pins: any 9 | refetchSavedPins: () => void 10 | } 11 | 12 | const AllPins: FC = ({profile, pins, refetchSavedPins}) => { 13 | const postIds = pins?.length > 0 ? pins?.map((pin: { post_id: string }) => pin.post_id) : [] 14 | 15 | return ( 16 | <> 17 | {pins && postIds?.length > 0 ? 18 | <> 19 |
20 |

21 | Unorganized Pins 22 |

23 | 24 |
25 | 26 | : null 27 | } 28 | 29 | ) 30 | } 31 | 32 | export default AllPins -------------------------------------------------------------------------------- /src/components/Profile/Pins/Common/Thumbnail.tsx: -------------------------------------------------------------------------------- 1 | /* eslint-disable @next/next/no-img-element */ 2 | import { PinstaPublication } from '@utils/custom-types' 3 | import getThumbnailUrl from '@utils/functions/getThumbnailUrl' 4 | import imageCdn from '@utils/functions/imageCdn' 5 | import { usePublicationsByIdsQuery } from '@utils/lens/generated' 6 | import React, { FC } from 'react' 7 | import usePersistStore from '@lib/store/persist' 8 | import clsx from 'clsx' 9 | import { THUMBNAIL_SM } from '@utils/constants' 10 | 11 | interface Props { 12 | board: any 13 | setShowEditBoard: (show: boolean) => void 14 | } 15 | 16 | const BoardThumbnail: FC = ({ board, setShowEditBoard }) => { 17 | 18 | return ( 19 | <> 20 |
21 |
22 |
26 |
27 |
28 | 29 | ) 30 | } 31 | 32 | export default BoardThumbnail -------------------------------------------------------------------------------- /src/components/Settings/Permissions/Dispatcher/index.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | import Toggle from './Toggle' 4 | import { APP } from '@utils/constants' 5 | 6 | const DispatcherPermissions = () => { 7 | return ( 8 |
9 |
10 |

Dispatcher

11 |

12 | Dispacher helps interact with {APP.Name} without signing any 13 | of your transactions. 14 |

15 |
16 |
17 | 18 |
19 |
20 | ) 21 | } 22 | 23 | export default DispatcherPermissions -------------------------------------------------------------------------------- /src/components/Settings/Permissions/index.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | import DispatcherPermissions from './Dispatcher' 4 | import ModulePermissions from './Modules' 5 | 6 | const Permissions = () => { 7 | return ( 8 |
9 | 10 | 11 |
12 | ) 13 | } 14 | 15 | export default Permissions -------------------------------------------------------------------------------- /src/components/Settings/ProfileInterests/index.tsx: -------------------------------------------------------------------------------- 1 | import { FC } from 'react' 2 | import Topics from './Topics' 3 | 4 | const ProfileInterests:FC = () => { 5 | return ( 6 | <> 7 |
8 |
9 |

Interests

10 |

11 | There is so much good content on Pinsta, it may be hard to find 12 | what’s most relevant to you from time to time. That’s where profile 13 | interests can help curate content the way you like. 14 |

15 |
16 | 17 |
18 | 19 | ) 20 | } 21 | 22 | export default ProfileInterests -------------------------------------------------------------------------------- /src/components/Shimmers/CommentItemShimmer.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | const CommentItemShimmer = () => { 4 | return ( 5 |
6 |
7 |
8 |
9 | 10 |
11 |
12 | 13 |
14 |
15 |
16 | ) 17 | } 18 | 19 | export default CommentItemShimmer -------------------------------------------------------------------------------- /src/components/Shimmers/CommentsShimmer.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | import CommentItemShimmer from './CommentItemShimmer' 4 | 5 | const CommentsShimmer = () => { 6 | return ( 7 |
8 | 9 | 10 | 11 |
12 | ) 13 | } 14 | 15 | export default CommentsShimmer -------------------------------------------------------------------------------- /src/components/Shimmers/NotificationShimmer.tsx: -------------------------------------------------------------------------------- 1 | import type { FC } from 'react'; 2 | 3 | const NotificationShimmer: FC = () => { 4 | return ( 5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 | ); 21 | }; 22 | 23 | export default NotificationShimmer; -------------------------------------------------------------------------------- /src/components/Shimmers/PinCardShimmer.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | 3 | export const CardShimmer = () => { 4 | return ( 5 |
6 |
7 |
8 |
9 |
10 | ) 11 | } 12 | 13 | const PinCardShimmer = ({height} : { height: number}) => { 14 | return ( 15 |
16 | ) 17 | } 18 | 19 | export default PinCardShimmer -------------------------------------------------------------------------------- /src/components/Shimmers/TimelineShimmer.tsx: -------------------------------------------------------------------------------- 1 | import React, { useMemo } from 'react' 2 | 3 | import PinCardShimmer from './PinCardShimmer' 4 | import Masonry from '@mui/lab/Masonry'; 5 | 6 | const TimelineShimmer = () => { 7 | const cards = useMemo(() => Array(32).fill(1), []) 8 | const heights = [200, 400, 300, 200, 300, 400, 100, 200, 400, 200, 100, 300, 400, 100, 400, 100, 200, 150, 300, 200, 300, 400, 100, 200, 400, 220, 100, 300, 400, 100, 400, 300] 9 | return ( 10 |
11 | 12 | {cards.map((i, idx) => ( 13 | 14 | ))} 15 | 16 |
17 | ) 18 | } 19 | 20 | export default TimelineShimmer 21 | 22 | // const TimelineShimmer = () => { 23 | // const cards = useMemo(() => Array(16).fill(1), []) 24 | // return ( 25 | //
26 | // {cards.map((i, idx) => ( 27 | // 28 | // ))} 29 | //
30 | // ) 31 | // } 32 | -------------------------------------------------------------------------------- /src/components/Stats/StatCard.tsx: -------------------------------------------------------------------------------- 1 | import type { FC } from 'react' 2 | import React from 'react' 3 | 4 | type Props = { 5 | icon: React.ReactNode 6 | count: number 7 | text: string 8 | } 9 | 10 | const StatCard: FC = ({ icon, count, text }) => { 11 | return ( 12 |
13 | 14 | {icon} 15 | 16 |
17 |
{count}
18 |
19 | {text} 20 |
21 |
22 |
23 | ) 24 | } 25 | 26 | export default StatCard -------------------------------------------------------------------------------- /src/components/UI/Alert.tsx: -------------------------------------------------------------------------------- 1 | import clsx from 'clsx' 2 | import type { FC, ReactNode } from 'react' 3 | import React from 'react' 4 | 5 | type Props = { 6 | children: ReactNode 7 | variant?: 'warning' | 'danger' | 'success' 8 | } 9 | 10 | const Alert: FC = ({ children, variant = 'warning' }) => { 11 | return ( 12 |
19 | {children} 20 |
21 | ) 22 | } 23 | 24 | export default Alert -------------------------------------------------------------------------------- /src/components/UI/Card.tsx: -------------------------------------------------------------------------------- 1 | import clsx from 'clsx'; 2 | import type { ElementType, FC, MouseEvent, ReactNode } from 'react'; 3 | 4 | interface CardProps { 5 | children: ReactNode; 6 | as?: ElementType; 7 | className?: string; 8 | forceRounded?: boolean; 9 | onClick?: (event: MouseEvent) => void; 10 | } 11 | 12 | export const Card: FC = ({ 13 | children, 14 | as: Tag = 'div', 15 | className = '', 16 | forceRounded = false, 17 | onClick 18 | }) => { 19 | return ( 20 | 28 | {children} 29 | 30 | ); 31 | }; -------------------------------------------------------------------------------- /src/components/UI/DropMenu.tsx: -------------------------------------------------------------------------------- 1 | import { Menu, Transition } from '@headlessui/react' 2 | import clsx from 'clsx' 3 | import Link from 'next/link' 4 | import type { FC, ReactElement, ReactNode } from 'react' 5 | import React from 'react' 6 | 7 | interface Props { 8 | trigger: ReactNode 9 | children: ReactElement 10 | panelClassName?: string 11 | positionClassName?: string 12 | triggerClassName?: string 13 | className?: string 14 | position?: 'right' | 'left' | 'bottom' 15 | } 16 | 17 | export const NextLink = ({ href, children, ...rest }: Record) => ( 18 | 19 | {children} 20 | 21 | ) 22 | 23 | const DropMenu: FC = ({ 24 | trigger, 25 | children, 26 | positionClassName, 27 | position = 'right' 28 | }) => ( 29 | 30 | 31 | {trigger} 32 | 33 | 50 | {children} 51 | 52 | 53 | ) 54 | 55 | export default DropMenu -------------------------------------------------------------------------------- /src/components/UI/EmptyState.tsx: -------------------------------------------------------------------------------- 1 | import type { FC, ReactNode } from 'react'; 2 | 3 | import { Card } from './Card'; 4 | 5 | interface Props { 6 | message: ReactNode; 7 | icon: ReactNode; 8 | hideCard?: boolean; 9 | } 10 | 11 | export const EmptyState: FC = ({ message, icon, hideCard = false }) => { 12 | return ( 13 | 14 |
15 |
{icon}
16 |
{message}
17 |
18 |
19 | ); 20 | }; -------------------------------------------------------------------------------- /src/components/UI/ErrorMessage.tsx: -------------------------------------------------------------------------------- 1 | 2 | import type { FC } from 'react'; 3 | 4 | interface Props { 5 | title?: string; 6 | error?: Error; 7 | className?: string; 8 | } 9 | 10 | export const ErrorMessage: FC = ({ title, error, className = '' }) => { 11 | if (!error) { 12 | return null; 13 | } 14 | 15 | return ( 16 |
19 | {title &&

{title}

} 20 |
{error?.message}
21 |
22 | ); 23 | }; -------------------------------------------------------------------------------- /src/components/UI/FullPageLoader.tsx: -------------------------------------------------------------------------------- 1 | /* eslint-disable @next/next/no-img-element */ 2 | import React from 'react' 3 | 4 | const FullPageLoader = () => { 5 | return ( 6 | <> 7 |
8 |
9 | Pinsta 15 |
16 |
17 | 18 | ) 19 | } 20 | 21 | export default FullPageLoader -------------------------------------------------------------------------------- /src/components/UI/InfiniteLoader.tsx: -------------------------------------------------------------------------------- 1 | import type { FC } from 'react'; 2 | 3 | import { Loader } from './Loader'; 4 | 5 | const InfiniteLoader: FC = () => { 6 | return ( 7 | 8 | 9 | 10 | ); 11 | }; 12 | 13 | export default InfiniteLoader; -------------------------------------------------------------------------------- /src/components/UI/IsVerified.tsx: -------------------------------------------------------------------------------- 1 | import clsx from 'clsx' 2 | import type { FC } from 'react' 3 | import { VERIFIED_CHANNELS } from '@utils/data/verified' 4 | import { BsFillPatchCheckFill } from "react-icons/bs"; 5 | 6 | type Props = { 7 | id: string 8 | size?: 'xs' | 'sm' | 'lg' 9 | color?: string 10 | } 11 | 12 | const IsVerified: FC = ({ id, size = 'sm', color = 'text-red-500 dark:text-red-400' }) => { 13 | if (!VERIFIED_CHANNELS.includes(id)) return null 14 | return ( 15 |
16 | 27 |
28 | ) 29 | } 30 | 31 | export default IsVerified -------------------------------------------------------------------------------- /src/components/UI/NoDataFound.tsx: -------------------------------------------------------------------------------- 1 | /* eslint-disable @next/next/no-img-element */ 2 | import clsx from 'clsx' 3 | import React from 'react' 4 | import { APP } from '@utils/constants' 5 | 6 | export const NoDataFound = ({ 7 | text = 'No data found', 8 | withImage = false, 9 | isCenter = false 10 | }) => { 11 | return ( 12 |
17 | {withImage && ( 18 | no results 24 | )} 25 |
30 | {text} 31 |
32 |
33 | ) 34 | } -------------------------------------------------------------------------------- /src/components/UI/TextArea.tsx: -------------------------------------------------------------------------------- 1 | import type { ComponentProps } from 'react'; 2 | import { forwardRef, useId } from 'react'; 3 | 4 | import { FieldError } from './Form'; 5 | 6 | interface Props extends ComponentProps<'textarea'> { 7 | label?: string; 8 | } 9 | 10 | export const TextArea = forwardRef(function TextArea({ label, ...props }, ref) { 11 | const id = useId(); 12 | 13 | return ( 14 |