├── .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 |
20 | {direction === "next" ? : }
21 |
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 | setTheme(theme === 'dark' ? 'light' : 'dark')}
14 | >
15 | {theme === 'dark' ? (
16 |
17 | ) : (
18 |
19 | )}
20 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
15 | {label &&
16 |
19 | }
20 |
26 | {props.name && }
27 |
28 | );
29 | });
--------------------------------------------------------------------------------
/src/components/UI/Toggle.tsx:
--------------------------------------------------------------------------------
1 | import { Switch } from '@headlessui/react';
2 | import clsx from 'clsx';
3 | import type { Dispatch, FC } from 'react';
4 |
5 | interface Props {
6 | on: boolean;
7 | setOn: Dispatch;
8 | }
9 |
10 | export const Toggle: FC = ({ on, setOn }) => {
11 | return (
12 | {
15 | setOn(!on);
16 | }}
17 | className={clsx(
18 | on ? 'primary-button' : 'bg-gray-200 dark:bg-gray-700',
19 | 'inline-flex h-[22px] w-[42.5px] border-2 border-transparent rounded-full cursor-pointer transition-colors ease-in-out duration-200 focus:outline-none'
20 | )}
21 | >
22 |
29 |
30 | );
31 | };
--------------------------------------------------------------------------------
/src/components/UI/Tooltip.tsx:
--------------------------------------------------------------------------------
1 |
2 |
3 | import Tippy from '@tippyjs/react';
4 | import clsx from 'clsx';
5 | import type { FC, ReactNode } from 'react';
6 |
7 | interface Props {
8 | children: ReactNode;
9 | content: ReactNode;
10 | placement?: 'top' | 'right' | 'bottom' | 'left';
11 | className?: string;
12 | withDelay?: boolean;
13 | }
14 |
15 | export const Tooltip: FC = ({ children, content, placement = 'right', className = '', withDelay = false }) => {
16 | return (
17 | {content}}
23 | >
24 | {children}
25 |
26 | );
27 | };
--------------------------------------------------------------------------------
/src/components/UI/WarningMessage.tsx:
--------------------------------------------------------------------------------
1 | import type { FC, ReactNode } from 'react';
2 |
3 | interface Props {
4 | title?: string;
5 | message?: ReactNode;
6 | className?: string;
7 | }
8 |
9 | export const WarningMessage: FC = ({ title, message, className = '' }) => {
10 | if (!message) {
11 | return null;
12 | }
13 |
14 | return (
15 |
16 | {title &&
{title} }
17 |
{message}
18 |
19 | );
20 | };
--------------------------------------------------------------------------------
/src/lib/apollo/cache.ts:
--------------------------------------------------------------------------------
1 | import { InMemoryCache } from '@apollo/client'
2 | import result from '@utils/lens'
3 |
4 | import cursorBasedPagination from './cursorBasedPagination'
5 |
6 | const cache = new InMemoryCache({
7 | possibleTypes: result.possibleTypes,
8 | typePolicies: {
9 | Query: {
10 | fields: {
11 | feed: cursorBasedPagination(['request', ['profileId', 'metadata']]),
12 | explorePublications: cursorBasedPagination([
13 | 'request',
14 | ['sortCriteria', 'noRandomize', 'profileId', 'sources', 'metadata']
15 | ]),
16 | publications: cursorBasedPagination([
17 | 'request',
18 | ['profileId', 'commentsOf', 'publicationTypes', 'sources']
19 | ]),
20 | nfts: cursorBasedPagination(['request', ['ownerAddress']]),
21 | notifications: cursorBasedPagination([
22 | 'request',
23 | ['profileId', 'notificationTypes']
24 | ]),
25 | followers: cursorBasedPagination(['request', ['profileId']]),
26 | following: cursorBasedPagination(['request', ['address']]),
27 | search: cursorBasedPagination(['request', ['query', 'type']]),
28 | profiles: cursorBasedPagination([
29 | 'request',
30 | ['profileIds', 'ownedBy', 'handles', 'whoMirroredPublicationId']
31 | ]),
32 | whoCollectedPublication: cursorBasedPagination([
33 | 'request',
34 | ['publicationId']
35 | ]),
36 | whoReactedPublication: cursorBasedPagination([
37 | 'request',
38 | ['publicationId']
39 | ]),
40 | mutualFollowersProfiles: cursorBasedPagination([
41 | 'request',
42 | ['viewingProfileId', 'yourProfileId', 'limit']
43 | ])
44 | }
45 | }
46 | }
47 | })
48 |
49 | export default cache
--------------------------------------------------------------------------------
/src/lib/apollo/cursorBasedPagination.ts:
--------------------------------------------------------------------------------
1 | import type { FieldPolicy, StoreValue } from '@apollo/client/core'
2 | import type { PaginatedResultInfo } from '@utils/lens'
3 |
4 | type CursorBasedPagination = {
5 | items: T[]
6 | pageInfo: PaginatedResultInfo
7 | }
8 |
9 | type SafeReadonly = T extends object ? Readonly : T
10 |
11 | function cursorBasedPagination(
12 | keyArgs: FieldPolicy['keyArgs']
13 | ): FieldPolicy {
14 | return {
15 | keyArgs,
16 |
17 | read(existing: SafeReadonly | undefined, { canRead }) {
18 | if (!existing) {
19 | return existing
20 | }
21 | const { items, pageInfo } = existing
22 | const removedItems = items?.filter((item) => !canRead(item))
23 | return {
24 | ...existing,
25 | items,
26 | pageInfo: {
27 | ...pageInfo,
28 | totalCount: pageInfo?.totalCount
29 | ? pageInfo.totalCount - removedItems?.length
30 | : null
31 | }
32 | } as SafeReadonly
33 | },
34 |
35 | merge(existing: Readonly | undefined, incoming: SafeReadonly) {
36 | if (!existing) {
37 | return incoming
38 | }
39 | const existingItems = existing.items ?? []
40 | const incomingItems = incoming.items ?? []
41 | return {
42 | ...incoming,
43 | items: existingItems?.concat(incomingItems),
44 | pageInfo: incoming.pageInfo
45 | } as SafeReadonly
46 | }
47 | }
48 | }
49 |
50 | export default cursorBasedPagination
--------------------------------------------------------------------------------
/src/lib/apollo/index.ts:
--------------------------------------------------------------------------------
1 | import { ApolloClient, from, HttpLink } from '@apollo/client'
2 | import { RetryLink } from '@apollo/client/link/retry'
3 | import { API_URL } from '@utils/constants'
4 |
5 | import authLink from './authLink'
6 | import cache from './cache'
7 |
8 | const retryLink = new RetryLink({
9 | delay: {
10 | initial: 100
11 | },
12 | attempts: {
13 | max: 2,
14 | retryIf: (error) => !!error
15 | }
16 | })
17 |
18 | const httpLink = new HttpLink({
19 | uri: API_URL,
20 | fetchOptions: 'no-cors',
21 | fetch
22 | })
23 |
24 | const apolloClient = new ApolloClient({
25 | link: from([authLink, retryLink, httpLink]),
26 | cache
27 | })
28 |
29 | export default apolloClient
--------------------------------------------------------------------------------
/src/lib/store/access-settings.ts:
--------------------------------------------------------------------------------
1 | import { create } from 'zustand'
2 |
3 | interface AccessSettingsState {
4 | restricted: boolean;
5 | setRestricted: (restricted: boolean) => void;
6 | collectToView: boolean;
7 | setCollectToView: (collectToView: boolean) => void;
8 | followToView: boolean;
9 | setFollowToView: (followToView: boolean) => void;
10 | hasConditions: () => boolean;
11 | reset: () => void;
12 | }
13 |
14 | export const useAccessSettingsStore = create((set, get) => ({
15 | restricted: false,
16 | setRestricted: (restricted) => set({ restricted }),
17 | collectToView: false,
18 | setCollectToView: (collectToView) => set({ collectToView }),
19 | followToView: false,
20 | setFollowToView: (followToView) => set({ followToView }),
21 | hasConditions: () => {
22 | const { followToView, collectToView } = get();
23 |
24 | return followToView || collectToView;
25 | },
26 | reset: () =>
27 | set({
28 | restricted: false,
29 | collectToView: false,
30 | followToView: false
31 | })
32 | }));
--------------------------------------------------------------------------------
/src/pages/404.tsx:
--------------------------------------------------------------------------------
1 | import { Button } from '@components/UI/Button'
2 | import Head from 'next/head'
3 | import Link from 'next/link'
4 | import React from 'react'
5 | import { APP } from '@utils/constants'
6 |
7 | export default function Custom404() {
8 | return (
9 | <>
10 |
11 | 404
12 |
13 |
14 |
21 |
22 |
404
23 |
This page could not be found.
24 |
25 |
Go Home
26 |
27 |
28 |
29 | >
30 | )
31 | }
--------------------------------------------------------------------------------
/src/pages/500.tsx:
--------------------------------------------------------------------------------
1 | import { Button } from '@components/UI/Button'
2 | import Head from 'next/head'
3 | import Link from 'next/link'
4 | import React from 'react'
5 | import { APP } from '@utils/constants'
6 |
7 | export default function Custom500() {
8 | return (
9 | <>
10 |
11 | 500 - Server Error
12 |
13 |
14 |
21 |
22 |
23 | Looks like something went wrong!
24 |
25 |
26 | We track these errors automatically, but if the problem persists
27 | feel free to contact us. In the meantime, try refreshing.
28 |
29 |
30 |
Go Home
31 |
32 |
33 |
34 | >
35 | )
36 | }
--------------------------------------------------------------------------------
/src/pages/[username]/[board]/index.tsx:
--------------------------------------------------------------------------------
1 | import Board from '@components/Board'
2 | import { getBoardBySlug } from '@lib/db/api';
3 |
4 | export default Board
5 |
6 | export const getServerSideProps = async (ctx : any) => {
7 | const { board, username } = ctx.params;
8 | const loading = true;
9 |
10 | const response = await getBoardBySlug(username, board);
11 | if (response && response.data.length > 0) {
12 | const board = response.data[0];
13 | return {
14 | props: {
15 | board,
16 | loading: false,
17 | },
18 | }
19 | } else {
20 | return {
21 | props: {
22 | board: null,
23 | loading,
24 | },
25 | }
26 | }
27 | }
--------------------------------------------------------------------------------
/src/pages/[username]/index.tsx:
--------------------------------------------------------------------------------
1 | import Profile from '@components/Profile'
2 | import formatHandle from '@utils/functions/formatHandle'
3 | import getApolloClient from '@utils/functions/getApolloClient'
4 | import { Profile as PinstaProfile, ProfileDocument } from '@utils/lens/generated'
5 | import { GetServerSideProps } from 'next'
6 |
7 | export default Profile
8 |
9 | const apolloClient = getApolloClient()
10 |
11 | interface Props {
12 | profile: PinstaProfile
13 | }
14 |
15 | export const getServerSideProps: GetServerSideProps = async (
16 | context
17 | ) => {
18 | const username = context.query.username as string
19 | const handle = formatHandle(username as string, true);
20 | context.res.setHeader('Cache-Control', 'public, s-maxage=86400')
21 | const { data, error } = await apolloClient.query({
22 | query: ProfileDocument,
23 | variables: {
24 | request: { handle }
25 | }
26 | })
27 | if (!data.profile || error) {
28 | return { notFound: true }
29 | }
30 | return {
31 | props: { profile: data.profile }
32 | }
33 | }
--------------------------------------------------------------------------------
/src/pages/_app.tsx:
--------------------------------------------------------------------------------
1 | import usePersistStore from '@lib/store/persist'
2 | import '../styles/globals.css'
3 | import FullPageLoader from '@components/UI/FullPageLoader'
4 | import { AUTH_ROUTES } from '@utils/data/auth-routes'
5 | import type { AppProps } from 'next/app'
6 | import { useRouter } from 'next/router'
7 | import React, { lazy, Suspense, useEffect, useState } from 'react'
8 | import { Hydrate, QueryClient, QueryClientProvider } from '@tanstack/react-query'
9 | import NextNProgress from 'nextjs-progressbar';
10 | import { Analytics } from '@vercel/analytics/react';
11 | import { DefaultSeo } from 'next-seo'
12 | import { DEFAULT_SEO } from '@utils/constants'
13 |
14 | const Providers = lazy(() => import('../components/Common/Providers'))
15 | const Layout = lazy(() => import('../components/Common/Layout'))
16 |
17 |
18 | export default function App({ Component, pageProps }: AppProps) {
19 |
20 | const [queryClient] = React.useState(() => new QueryClient())
21 |
22 | const currentProfileId = usePersistStore((state) => state.currentProfileId)
23 |
24 | const { pathname, replace, asPath } = useRouter()
25 |
26 | useEffect(() => {
27 | if (!currentProfileId && AUTH_ROUTES.includes(pathname)) {
28 | replace(`/auth?next=${asPath}`)
29 | }
30 | }, [currentProfileId, pathname, asPath, replace])
31 |
32 | return (
33 | }>
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 | )
48 | }
49 |
--------------------------------------------------------------------------------
/src/pages/api/hello.ts:
--------------------------------------------------------------------------------
1 | // Next.js API route support: https://nextjs.org/docs/api-routes/introduction
2 | import type { NextApiRequest, NextApiResponse } from 'next'
3 |
4 | type Data = {
5 | name: string
6 | }
7 |
8 | export default function handler(
9 | req: NextApiRequest,
10 | res: NextApiResponse
11 | ) {
12 | res.status(200).json({ name: 'John Doe' })
13 | }
14 |
--------------------------------------------------------------------------------
/src/pages/auth.tsx:
--------------------------------------------------------------------------------
1 | import Login from '@components/Common/Auth/Login'
2 | import MetaTags from '@components/Common/MetaTags'
3 | import usePersistStore from '@lib/store/persist'
4 | import { useRouter } from 'next/router'
5 | import React, { useEffect } from 'react'
6 | import { APP } from '@utils/constants'
7 |
8 | const AuthRequiredPage = () => {
9 | const currentProfileId = usePersistStore((state) => state.currentProfileId)
10 | const { replace, query } = useRouter()
11 |
12 | useEffect(() => {
13 | if (currentProfileId && query?.next) {
14 | replace(query?.next as string)
15 | }
16 | }, [currentProfileId, query, replace])
17 |
18 | return (
19 | <>
20 |
21 |
22 |
29 |
30 |
Sign In Required
31 |
32 | Connect Wallet & Sign with Lens to continue,
33 |
34 |
35 |
36 |
37 |
38 |
39 | >
40 | )
41 | }
42 |
43 | export default AuthRequiredPage
--------------------------------------------------------------------------------
/src/pages/create/index.tsx:
--------------------------------------------------------------------------------
1 | import Create from '@components/Create'
2 |
3 | export default Create
--------------------------------------------------------------------------------
/src/pages/explore.tsx:
--------------------------------------------------------------------------------
1 | import Explore from '@components/Explore'
2 |
3 | export default Explore
--------------------------------------------------------------------------------
/src/pages/hashtag/[tag].tsx:
--------------------------------------------------------------------------------
1 | import Hashtag from '@components/Hashtag'
2 |
3 | export default Hashtag
--------------------------------------------------------------------------------
/src/pages/index.tsx:
--------------------------------------------------------------------------------
1 | import Home from '@components/Home'
2 |
3 | export default Home
--------------------------------------------------------------------------------
/src/pages/latest.tsx:
--------------------------------------------------------------------------------
1 | import Latest from '@components/Latest'
2 |
3 | export default Latest
--------------------------------------------------------------------------------
/src/pages/messages/[...conversationKey].tsx:
--------------------------------------------------------------------------------
1 | import Message from '@components/Messages/Message';
2 |
3 | export default Message;
--------------------------------------------------------------------------------
/src/pages/messages/index.tsx:
--------------------------------------------------------------------------------
1 | import Messages from '@components/Messages';
2 |
3 | export default Messages;
--------------------------------------------------------------------------------
/src/pages/notifications.tsx:
--------------------------------------------------------------------------------
1 | import Notifications from '@components/Notifications'
2 |
3 | export default Notifications
--------------------------------------------------------------------------------
/src/pages/pin/[id].tsx:
--------------------------------------------------------------------------------
1 | import Pin from '@components/Pin'
2 | import { PinstaPublication } from '@utils/custom-types'
3 | import getApolloClient from '@utils/functions/getApolloClient'
4 | import { PublicationDetailsDocument } from '@utils/lens/generated'
5 | import { GetServerSideProps } from 'next'
6 |
7 | export default Pin
8 |
9 | const apolloClient = getApolloClient()
10 |
11 | interface Props {
12 | pin: PinstaPublication
13 | }
14 |
15 | export const getServerSideProps: GetServerSideProps = async (
16 | context
17 | ) => {
18 | const publicationId = context.query.id as string
19 | // const splitted = publicationId.split('-')
20 | // if (splitted.length !== 2) {
21 | // return { notFound: true }
22 | // }
23 | // context.res.setHeader('Cache-Control', 'public, s-maxage=86400')
24 | const { data, error } = await apolloClient.query({
25 | query: PublicationDetailsDocument,
26 | variables: {
27 | request: { publicationId }
28 | }
29 | })
30 | if (!data.publication || error) {
31 | return { notFound: true }
32 | }
33 | return {
34 | props: { pin: data.publication, error: false, loading: false }
35 | }
36 | }
--------------------------------------------------------------------------------
/src/pages/settings/danger.tsx:
--------------------------------------------------------------------------------
1 | import Settings from '@components/Settings'
2 |
3 | export default Settings
--------------------------------------------------------------------------------
/src/pages/settings/index.tsx:
--------------------------------------------------------------------------------
1 | import Settings from '@components/Settings'
2 |
3 | export default Settings
--------------------------------------------------------------------------------
/src/pages/settings/interests.tsx:
--------------------------------------------------------------------------------
1 | import Settings from '@components/Settings'
2 |
3 | export default Settings
--------------------------------------------------------------------------------
/src/pages/settings/permissions.tsx:
--------------------------------------------------------------------------------
1 | import Settings from '@components/Settings'
2 |
3 | export default Settings
--------------------------------------------------------------------------------
/src/pages/stats/index.tsx:
--------------------------------------------------------------------------------
1 | import Stats from '@components/Stats'
2 |
3 | export default Stats
--------------------------------------------------------------------------------
/src/utils/abis/.eslintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | root: true,
3 | extends: ['weblint']
4 | };
5 |
--------------------------------------------------------------------------------
/src/utils/abis/index.ts:
--------------------------------------------------------------------------------
1 | export * from './FollowNFT';
2 | export * from './LensHubProxy';
3 | export * from './LensPeriphery';
4 | export * from './UpdateOwnableFeeCollectModule';
5 |
--------------------------------------------------------------------------------
/src/utils/abis/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "abis",
3 | "version": "0.0.0",
4 | "main": "index.ts",
5 | "scripts": {
6 | "typecheck": "tsc --noEmit",
7 | "lint": "eslint . --ext .ts"
8 | },
9 | "dependencies": {
10 | "typescript": "4.9.4"
11 | },
12 | "devDependencies": {
13 | "eslint-config-weblint": "*",
14 | "tsconfig": "*"
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/src/utils/abis/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "https://json.schemastore.org/tsconfig",
3 | "display": "Default",
4 | "compilerOptions": {
5 | "composite": false,
6 | "declaration": true,
7 | "declarationMap": true,
8 | "esModuleInterop": true,
9 | "forceConsistentCasingInFileNames": true,
10 | "inlineSources": false,
11 | "isolatedModules": true,
12 | "moduleResolution": "node",
13 | "noUnusedLocals": false,
14 | "noUnusedParameters": false,
15 | "preserveWatchOutput": true,
16 | "skipLibCheck": true,
17 | "strict": true,
18 | "target": "es5",
19 | "lib": ["dom", "dom.iterable", "esnext"],
20 | "allowJs": true,
21 | "forceConsistentCasingInFileNames": true,
22 | "noEmit": true,
23 | "module": "esnext",
24 | "resolveJsonModule": true,
25 | "jsx": "preserve",
26 | "incremental": true,
27 | "baseUrl": ".",
28 | "noEmit": true
29 | },
30 | "exclude": ["node_modules", ".next", ".turbo"]
31 | }
--------------------------------------------------------------------------------
/src/utils/contracts.ts:
--------------------------------------------------------------------------------
1 | export const MAINNET_LENSHUB_PROXY = '0xDb46d1Dc155634FbC732f92E853b10B288AD5a1d';
2 | export const MAINNET_LENS_PERIPHERY = '0xeff187b4190E551FC25a7fA4dFC6cf7fDeF7194f';
3 | export const MAINNET_DEFAULT_TOKEN = '0x0d500b1d8e8ef31e21c99d1db9a6444d3adf1270';
4 | export const MAINNET_UPDATE_OWNABLE_FEE_COLLECT_MODULE_ADDRESS = '0x432960b3209686Cc69e2EEC1dBBaB52A1c0Bf938';
5 | export const TESTNET_LENSHUB_PROXY = '0x60Ae865ee4C725cd04353b5AAb364553f56ceF82';
6 | export const TESTNET_LENS_PERIPHERY = '0xD5037d72877808cdE7F669563e9389930AF404E8';
7 | export const TESTNET_DEFAULT_TOKEN = '0x9c3C9283D3e44854697Cd22D3Faa240Cfb032889';
8 | export const TESTNET_UPDATE_OWNABLE_FEE_COLLECT_MODULE_ADDRESS = '0xA78E4a4D0367f0f4674130F0Bb2653957ab5917e';
9 | export const SANDBOX_LENSHUB_PROXY = '0x7582177F9E536aB0b6c721e11f383C326F2Ad1D5';
10 | export const SANDBOX_LENS_PERIPHERY = '0x5dDD1d6c04E805D830574A31Bf7979D416c6d7c5';
--------------------------------------------------------------------------------
/src/utils/data/aave-members.ts:
--------------------------------------------------------------------------------
1 | export const aaveMembers = [
2 | '0x05', // stani.lens
3 | '0x16', // davidev.lens,
4 | '0x06', // wagmi.lens
5 | '0x08', // donosonaumczuk.lens
6 | '0x01', // lensprotocol
7 | '0x04', // letsraave.lens
8 | '0x03', // aavegrants.lens
9 | '0x02', // aaveaave.lens
10 | '0x8e', // christina.lens
11 | '0x0b', // zer0dot.lens
12 | '0x10', // damarnez.lens
13 | '0x09', // nicolo.lens
14 | '0xa1', // pealco.lens
15 | '0x24', // bradorbradley.lens
16 | '0x7b38', // lensapi.lens
17 | '0x07', // wassim.lens
18 | '0x0580', // josepbove.lens
19 | '0xfcc1', // cultivatordao.lens
20 | '0x2d', // sasicodes.lens
21 | '0x45', // keeks.lens
22 | '0x31', // mariariivari.lens
23 | '0x03f9', // ilyab.lens
24 | '0x1966', // hazbobo.lens
25 | '0x27', // 0xjim.lens
26 | '0x25b7', // stefan.lens
27 | '0x0a', // jouni.lens
28 | '0x12', // zannis.lens
29 | '0x2ee4', // essah.lens
30 | '0x3a', // cesare.lens
31 | '0x20e7', // reecej.lens
32 | '0xada1', // katya.lens
33 | '0x40', // tamrat.lens
34 | '0xf9f4', // grocery.lens
35 | '0x28a2', // nader.lens
36 | '0x84ed', // bensparks.lens
37 | '0x35', // superproduct.lens
38 | '0x6b46', // 0xgraham.lens
39 | '0x0636', // jenny.lens
40 | '0x8a58', // fabri.lens
41 | '0x8d68', // avadi.lens
42 | '0xadb2', // jameslondon.lens
43 | '0x1044', // south.lens
44 | '0xd543' // mirran.lens
45 | ];
--------------------------------------------------------------------------------
/src/utils/data/auth-routes.ts:
--------------------------------------------------------------------------------
1 | // auth routes
2 | export const AUTH_ROUTES = [
3 | '/create',
4 | '/settings',
5 | '/following',
6 | '/settings/permissions',
7 | '/settings/interests',
8 | '/settings/danger',
9 | '/notifications'
10 | ]
--------------------------------------------------------------------------------
/src/utils/data/paid-members.ts:
--------------------------------------------------------------------------------
1 | export const paidMembers = [
2 | { '0x0f85' : 'Red' }, // punkess.lens
3 | { '0x012b94' : 'Red' }, // blackjoker.lens
4 | { '0x960f' : 'Red' }, // zerts.lens
5 |
6 | ]
--------------------------------------------------------------------------------
/src/utils/data/pinsta-members.ts:
--------------------------------------------------------------------------------
1 | export const pinstaMembers = [
2 | '0x016efc', // JsonPreet.lens
3 | '0x018ec4', // Pinsta.lens
4 | '0x010040', // Anku.lens
5 | '0x01a2ee', // Wav3s.lens
6 | '0x019b72', // Buttrfly.lens
7 | '0x01b1d6', // Focalize.lens
8 | '0xd8', // PaulBurke.lens
9 | '0x0f85', // punkess.lens
10 | '0x012b94', // blackjoker.lens
11 | '0x960f', // zerts.lens
12 | '0xacaf', // zelda.lens
13 | ]
--------------------------------------------------------------------------------
/src/utils/data/tags.ts:
--------------------------------------------------------------------------------
1 | export const TAGS = [
2 | {
3 | 'name': 'Lens',
4 | },
5 | {
6 | 'name': 'Meme',
7 | },
8 | {
9 | 'name': 'Music',
10 | },
11 | {
12 | 'name': 'LMCC',
13 | },
14 | {
15 | 'name': 'NFT',
16 | },
17 | {
18 | 'name': 'Crypto',
19 | },
20 | {
21 | 'name': 'Funny',
22 | },
23 | {
24 | 'name': 'Art',
25 | },
26 | {
27 | 'name': 'People',
28 | },
29 | {
30 | 'name': 'Random',
31 | }
32 | ]
--------------------------------------------------------------------------------
/src/utils/data/verified.ts:
--------------------------------------------------------------------------------
1 | import { IS_MAINNET } from '../constants'
2 | import { aaveMembers } from './aave-members'
3 | import { paidMembers } from './paid-members'
4 | import { pinstaMembers } from './pinsta-members'
5 |
6 | export const VERIFIED_CHANNELS = IS_MAINNET
7 | ? [
8 | ...aaveMembers,
9 | ...paidMembers,
10 | ...pinstaMembers,
11 | ]
12 | : [
13 | '0x5f8e',
14 | '0x57a4',
15 | '0x62fa', // Prashant.lens
16 | ]
--------------------------------------------------------------------------------
/src/utils/functions/buildConversationId.ts:
--------------------------------------------------------------------------------
1 | import { XMTP_PREFIX } from '@utils/constants';
2 |
3 | const buildConversationId = (profileA: string, profileB: string) => {
4 | const numberA = parseInt(profileA.substring(2), 16);
5 | const numberB = parseInt(profileB.substring(2), 16);
6 | return numberA < numberB
7 | ? `${XMTP_PREFIX}/${profileA}-${profileB}`
8 | : `${XMTP_PREFIX}/${profileB}-${profileA}`;
9 | };
10 |
11 | export default buildConversationId;
--------------------------------------------------------------------------------
/src/utils/functions/chunkArray.ts:
--------------------------------------------------------------------------------
1 | const chunkArray = (arr: T[], chunkSize: number): T[][] => {
2 | const out: T[][] = [];
3 | for (let i = 0; i < arr.length; i += chunkSize) {
4 | const chunk = arr.slice(i, i + chunkSize);
5 | out.push(chunk);
6 | }
7 |
8 | return out;
9 | };
10 |
11 | export default chunkArray;
12 |
--------------------------------------------------------------------------------
/src/utils/functions/clearLocalStorage.ts:
--------------------------------------------------------------------------------
1 | const clearLocalStorage = () => {
2 | localStorage.removeItem('accessToken')
3 | localStorage.removeItem('refreshToken')
4 | localStorage.removeItem('pinsta.store')
5 | }
6 | export default clearLocalStorage
--------------------------------------------------------------------------------
/src/utils/functions/conversationKey.ts:
--------------------------------------------------------------------------------
1 | import { XMTP_PREFIX } from '@utils/constants';
2 |
3 | const CONVERSATION_KEY_RE = /^(.*)\/lens\.dev\/dm\/(.*)-(.*)$/;
4 |
5 | /**
6 | * Builds a conversation key for a given peer address and conversation id
7 | *
8 | * @param peerAddress The peer address of the user
9 | * @param conversationId The conversation id
10 | * @returns The conversation key
11 | */
12 | export const buildConversationKey = (
13 | peerAddress: string,
14 | conversationId: string
15 | ): string =>
16 | conversationId
17 | ? `${peerAddress.toLowerCase()}/${conversationId}`
18 | : peerAddress.toLowerCase();
19 |
20 | /**
21 | * Parses a conversation key into its peer address, members, and conversation id
22 | *
23 | * @param conversationKey The conversation key
24 | * @returns An object containing the peer address, members, and conversation id, or null if the conversation key is invalid
25 | */
26 | export const parseConversationKey = (
27 | conversationKey: string
28 | ): {
29 | peerAddress: string;
30 | members: string[];
31 | conversationId?: string;
32 | } | null => {
33 | const matches = conversationKey.match(CONVERSATION_KEY_RE);
34 |
35 | if (!matches || matches.length !== 4) {
36 | return {
37 | peerAddress: conversationKey,
38 | members: [],
39 | };
40 | }
41 |
42 | const [, peerAddress, memberA, memberB] = Array.from(matches);
43 |
44 | return {
45 | peerAddress,
46 | members: [memberA, memberB],
47 | conversationId: `${XMTP_PREFIX}/${memberA}-${memberB}`,
48 | };
49 | };
--------------------------------------------------------------------------------
/src/utils/functions/conversationMatchesProfile.ts:
--------------------------------------------------------------------------------
1 | import { XMTP_PREFIX } from '@utils/constants';
2 |
3 | const conversationMatchesProfile = (profileId: string) => new RegExp(`${XMTP_PREFIX}/.*${profileId}`);
4 |
5 | export default conversationMatchesProfile;
--------------------------------------------------------------------------------
/src/utils/functions/formatAddress.ts:
--------------------------------------------------------------------------------
1 | import { ADDRESS_REGEX } from '@utils/constants';
2 |
3 | /**
4 | *
5 | * @param address - Complete ethereum address
6 | * @returns formatted ethereum address
7 | */
8 | const formatAddress = (address: string | null): string => {
9 | if (!address) {
10 | return '';
11 | }
12 |
13 | const regex = ADDRESS_REGEX;
14 | if (address.match(regex)) {
15 | return `${address.slice(0, 4)}…${address.slice(address.length - 4, address.length)}`;
16 | }
17 |
18 | return address;
19 | };
20 |
21 | export default formatAddress;
--------------------------------------------------------------------------------
/src/utils/functions/formatBytes.ts:
--------------------------------------------------------------------------------
1 | const formatBytes = (bytes: number) => {
2 | if (bytes) {
3 | const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB']
4 | const i = Math.min(
5 | parseInt(Math.floor(Math.log(bytes) / Math.log(1024)).toString(), 10),
6 | sizes.length - 1
7 | )
8 | return `${(bytes / 1024 ** i).toFixed(i ? 1 : 0)} ${sizes[i]}`
9 | }
10 | return 'n/a'
11 | }
12 |
13 | export default formatBytes
--------------------------------------------------------------------------------
/src/utils/functions/formatHandle.ts:
--------------------------------------------------------------------------------
1 | import { HANDLE_SUFFIX, LENSPROTOCOL_HANDLE } from "@utils/constants";
2 |
3 | /**
4 | * Format the given handle by conditionally removing or appending the .lens or .test suffix.
5 | *
6 | * @param handle Complete handle
7 | * @param keepSuffix Keep the .lens or .test suffix if true, remove if false
8 | * @returns Formatted handle without .lens or .test suffix, unless keepSuffix is true
9 | */
10 | const formatHandle = (handle: string | null, keepSuffix = false): string => {
11 | if (!handle) {
12 | return "";
13 | }
14 |
15 | if (handle.toLowerCase() === LENSPROTOCOL_HANDLE) {
16 | return handle;
17 | }
18 |
19 | if (keepSuffix) {
20 | return handle.match(HANDLE_SUFFIX)
21 | ? handle.split(HANDLE_SUFFIX)[0] + HANDLE_SUFFIX
22 | : handle + HANDLE_SUFFIX;
23 | }
24 |
25 | return handle.replace(HANDLE_SUFFIX, "");
26 | };
27 |
28 | export default formatHandle;
29 |
--------------------------------------------------------------------------------
/src/utils/functions/formatNumber.ts:
--------------------------------------------------------------------------------
1 | export const formatNumber = (num: number) => {
2 | if (num > 999 && num < 1000000) {
3 | return `${(num / 1000).toPrecision(3)}k`
4 | } else if (num > 1000000) {
5 | return `${(num / 1000000).toPrecision(3)}m`
6 | } else if (num < 1000) {
7 | return num
8 | }
9 | }
--------------------------------------------------------------------------------
/src/utils/functions/formatTime.ts:
--------------------------------------------------------------------------------
1 | import dayjs from 'dayjs';
2 |
3 | const formatTime = (date: Date | undefined): string => {
4 | return date ? dayjs(date).format('h:mm A · MMM D, YYYY') : '';
5 | };
6 |
7 | export default formatTime;
--------------------------------------------------------------------------------
/src/utils/functions/getApolloClient.ts:
--------------------------------------------------------------------------------
1 | import { ApolloClient, InMemoryCache } from '@apollo/client'
2 | import { API_URL } from '@utils/constants'
3 |
4 | const getApolloClient = () => {
5 | return new ApolloClient({
6 | uri: API_URL,
7 | cache: new InMemoryCache()
8 | })
9 | }
10 |
11 | export default getApolloClient
--------------------------------------------------------------------------------
/src/utils/functions/getAppName.ts:
--------------------------------------------------------------------------------
1 | const getAppName = (str: string): string => {
2 | const initCase = str.charAt(0).toUpperCase() + str.slice(1);
3 | return initCase.replace(/-/g, ' ');
4 | };
5 |
6 | export default getAppName;
--------------------------------------------------------------------------------
/src/utils/functions/getAssetAddress.ts:
--------------------------------------------------------------------------------
1 | import { MAINNET_DEFAULT_TOKEN } from '@utils/contracts';
2 |
3 | /**
4 | *
5 | * @param symbol - The symbol of the token
6 | * @returns the address of the token
7 | */
8 | const getAssetAddress = (symbol: string) => {
9 | switch (symbol) {
10 | case 'WMATIC':
11 | return MAINNET_DEFAULT_TOKEN;
12 | case 'WETH':
13 | return '0x7ceb23fd6bc0add59e62ac25578270cff1b9f619';
14 | case 'USDC':
15 | return '0x2791bca1f2de4661ed88a30c99a7a9449aa84174';
16 | case 'DAI':
17 | return '0x8f3Cf7ad23Cd3CaDbD9735AFf958023239c6A063';
18 | case 'NCT':
19 | return '0xD838290e877E0188a4A44700463419ED96c16107';
20 | default:
21 | return MAINNET_DEFAULT_TOKEN;
22 | }
23 | };
24 |
25 | export default getAssetAddress;
--------------------------------------------------------------------------------
/src/utils/functions/getAttribute.ts:
--------------------------------------------------------------------------------
1 | import type { Maybe } from '@utils/lens';
2 |
3 | interface Attribute {
4 | key: string;
5 | value: string;
6 | }
7 |
8 | type Query = 'hasPrideLogo' | 'app' | 'twitter' | 'location' | 'website' | 'statusEmoji' | 'statusMessage';
9 |
10 | /**
11 | *
12 | * @param attributes - Array of attributes
13 | * @param query - Query to search for
14 | * @returns attribute if found, otherwise undefined
15 | */
16 | const getAttribute = (attributes?: Maybe, query?: Query): string => {
17 | return attributes?.find((o) => o.key === query)?.value || '';
18 | };
19 |
20 | export default getAttribute;
--------------------------------------------------------------------------------
/src/utils/functions/getAttributeFromTrait.ts:
--------------------------------------------------------------------------------
1 | import type { Attribute } from '@utils/lens';
2 |
3 | /**
4 | *
5 | * @param attributes - The attributes to search through
6 | * @param traitType - The trait type to search for
7 | * @returns the attribute from a trait
8 | */
9 | const getAttributeFromTrait = (attributes: Attribute[] | null | undefined, traitType: string) => {
10 | return attributes?.find((el) => el.traitType === traitType)?.value;
11 | };
12 |
13 | export default getAttributeFromTrait;
--------------------------------------------------------------------------------
/src/utils/functions/getCoingeckoPrice.ts:
--------------------------------------------------------------------------------
1 | import axios from 'axios';
2 |
3 | /**
4 | *
5 | * @param address - The address of the token
6 | * @returns the price of the token
7 | */
8 | const getCoingeckoPrice = async (address: string) => {
9 | try {
10 | const response = await axios('https://api.coingecko.com/api/v3/simple/token_price/polygon-pos', {
11 | params: {
12 | contract_addresses: address,
13 | vs_currencies: 'usd'
14 | }
15 | });
16 |
17 | return response.data[address].usd;
18 | } catch {
19 | return 0;
20 | }
21 | };
22 |
23 | export default getCoingeckoPrice;
--------------------------------------------------------------------------------
/src/utils/functions/getCoverPicture.ts:
--------------------------------------------------------------------------------
1 | import type { Profile } from '@utils/lens'
2 |
3 | const getCoverPicture = (profile: Profile): string => {
4 | return profile.coverPicture && profile.coverPicture.__typename === 'MediaSet'
5 | ? profile?.coverPicture?.original?.url
6 | : `/patterns/9.png`
7 | }
8 |
9 | export default getCoverPicture
--------------------------------------------------------------------------------
/src/utils/functions/getExport.ts:
--------------------------------------------------------------------------------
1 | import { APP } from "@utils/constants";
2 | import axios from "axios";
3 |
4 | export async function exportPNG({ url, name }: { url: string, name?: string }, setSaving: any) {
5 | const fileName = name || APP.URLName + "_" + new Date().toLocaleDateString();
6 | var element = document.createElement("a");
7 | await axios.get(url, { responseType: "blob" }).then((res) => {
8 | var file = new Blob([res.data], { type: "image/*" });
9 | element.href = URL.createObjectURL(file);
10 | element.download = `${fileName}.png`;
11 | element.click();
12 | setSaving(false);
13 | });
14 |
15 | // var file = new Blob(
16 | // [url],
17 | // { type: "image/*" }
18 | // );
19 | // element.href = URL.createObjectURL(file);
20 | // element.download = "image.jpg";
21 | // element.click();
22 | }
--------------------------------------------------------------------------------
/src/utils/functions/getFileFromDataURL.ts:
--------------------------------------------------------------------------------
1 | export const getFileFromDataURL = (dataUrl: string, fileName: string) => {
2 | // convert base64 to raw binary data held in a string
3 | const byteString = atob(dataUrl.split(',')[1])
4 | // separate out the mime component
5 | const mimeString = dataUrl.split(',')[0].split(':')[1].split(';')[0]
6 | // write the bytes of the string to an ArrayBuffer
7 | const ab = new ArrayBuffer(byteString.length)
8 | // create a view into the buffer
9 | const ia = new Uint8Array(ab)
10 | // set the bytes of the buffer to the correct values
11 | for (let i = 0; i < byteString.length; i++) {
12 | ia[i] = byteString.charCodeAt(i)
13 | }
14 | // write the ArrayBuffer to a blob, and you're done
15 | const blob = new Blob([ab], { type: mimeString })
16 | const file = new File([blob], fileName)
17 | return file
18 | }
--------------------------------------------------------------------------------
/src/utils/functions/getFollowModule.ts:
--------------------------------------------------------------------------------
1 | /**
2 | *
3 | * @param name - Name to format
4 | * @returns formatted name
5 | */
6 | export const getFollowModule = (name?: string): { description: string } => {
7 | switch (name) {
8 | case 'ProfileFollowModuleSettings':
9 | return { description: 'Only Lens profiles can follow' };
10 | case 'FeeFollowModuleSettings':
11 | return { description: 'Charge to follow' };
12 | case 'RevertFollowModuleSettings':
13 | return { description: 'No one can follow' };
14 | default:
15 | return { description: 'Anyone can follow' };
16 | }
17 | };
--------------------------------------------------------------------------------
/src/utils/functions/getFromAttributes.ts:
--------------------------------------------------------------------------------
1 | import type { Attribute } from '@utils/lens'
2 |
3 | // key available only profile metadata
4 | export const getValueFromKeyInAttributes = (
5 | attributes: Attribute[] | null | undefined,
6 | key: string
7 | ) => {
8 | return attributes?.find((el) => el.key === key)?.value
9 | }
10 |
11 | export const getValueFromTraitType = (
12 | attributes: Attribute[] | null | undefined,
13 | traitType: string
14 | ) => {
15 | return attributes?.find((el) => el.traitType === traitType)?.value
16 | }
17 |
18 | export const checkValueInAttributes = (
19 | attributes: Attribute[],
20 | value: string
21 | ) => {
22 | return attributes?.find((el) => el.value === value)?.value
23 | }
--------------------------------------------------------------------------------
/src/utils/functions/getHashTags.ts:
--------------------------------------------------------------------------------
1 | export const getHashTags = (inputText: string) => {
2 | const regex = /(?:^|\s)#([\dA-Za-z]+)/gm;
3 | const matches: string[] = [];
4 | let match;
5 |
6 | while ((match = regex.exec(inputText))) {
7 | matches.push(match[1]);
8 | }
9 |
10 | return matches.filter((item, pos) => matches.indexOf(item) == pos).slice(0, 5);
11 | };
--------------------------------------------------------------------------------
/src/utils/functions/getIsAuthTokensAvailable.ts:
--------------------------------------------------------------------------------
1 | export const getIsAuthTokensAvailable = () => {
2 | const accessToken = localStorage.getItem('accessToken')
3 | const refreshToken = localStorage.getItem('refreshToken')
4 | const isAvailable =
5 | accessToken !== 'undefined' && refreshToken !== 'undefined'
6 | return isAvailable
7 | }
--------------------------------------------------------------------------------
/src/utils/functions/getLensHandle.ts:
--------------------------------------------------------------------------------
1 | import { IS_MAINNET } from '../constants'
2 |
3 | const getLensHandle = (handle: string) => {
4 | const name = handle.replace('.lens', '').replace('.test', '')
5 | return `${name}.${IS_MAINNET ? 'lens' : 'test'}`
6 | }
7 |
8 | export default getLensHandle
--------------------------------------------------------------------------------
/src/utils/functions/getLivePeer.ts:
--------------------------------------------------------------------------------
1 | import type { ThemeConfig } from '@livepeer/react'
2 | import { createReactClient, studioProvider } from '@livepeer/react'
3 | import { LIVEPEER_STUDIO_API_KEY } from '@utils/constants'
4 |
5 | export const getLivepeerClient = () => {
6 | return createReactClient({
7 | provider: studioProvider({
8 | apiKey: LIVEPEER_STUDIO_API_KEY
9 | })
10 | })
11 | }
12 |
13 | export const videoPlayerTheme: ThemeConfig = {
14 | colors: {
15 | accent: '#fff',
16 | progressLeft: '#ec4899',
17 | loading: '#ec4899'
18 | },
19 | fonts: {
20 | display: 'Matter'
21 | },
22 | fontSizes: {
23 | timeFontSize: '12px'
24 | },
25 | space: {
26 | timeMarginX: '22px',
27 | controlsBottomMarginX: '10px',
28 | controlsBottomMarginY: '10px'
29 | },
30 | sizes: {
31 | iconButtonSize: '35px',
32 | loading: '30px',
33 | thumb: '7px',
34 | thumbActive: '7px',
35 | trackActive: '3px',
36 | trackInactive: '3px'
37 | },
38 | radii: {
39 | containerBorderRadius: '0px'
40 | }
41 | }
--------------------------------------------------------------------------------
/src/utils/functions/getProfilePicture.ts:
--------------------------------------------------------------------------------
1 | import type { Profile } from '@utils/lens'
2 |
3 | import { getRandomProfilePicture } from './getRandomProfilePicture'
4 | import imageCdn from './imageCdn'
5 | import sanitizeIpfsUrl from './sanitizeIpfsUrl'
6 |
7 | const getProfilePicture = (profile: Profile, type: string): string => {
8 | if (!profile) return getRandomProfilePicture('abcd');
9 | const url =
10 | profile?.picture && profile?.picture.__typename === "MediaSet"
11 | ? imageCdn(sanitizeIpfsUrl(profile?.picture?.original?.url), type)
12 | : profile?.picture?.__typename === "NftImage"
13 | ? imageCdn(sanitizeIpfsUrl(profile?.picture?.uri), type)
14 | : getRandomProfilePicture(profile?.handle);
15 | return url
16 | }
17 |
18 | export default getProfilePicture
--------------------------------------------------------------------------------
/src/utils/functions/getRandomProfilePicture.ts:
--------------------------------------------------------------------------------
1 | export const getRandomProfilePicture = (seed: string) => {
2 | return `https://avatar.tobi.sh/${seed}.png`
3 | }
--------------------------------------------------------------------------------
/src/utils/functions/getSignature.ts:
--------------------------------------------------------------------------------
1 | import omit from './omit';
2 |
3 | /**
4 | *
5 | * @param typedData - Typed data to split
6 | * @returns typed data parts
7 | */
8 | const getSignature = (typedData: any) => {
9 | return {
10 | domain: omit(typedData.domain, '__typename'),
11 | types: omit(typedData.types, '__typename'),
12 | value: omit(typedData.value, '__typename')
13 | };
14 | };
15 |
16 | export default getSignature;
--------------------------------------------------------------------------------
/src/utils/functions/getStampFyiURL.ts:
--------------------------------------------------------------------------------
1 | /**
2 | *
3 | * @param address - The address to get the cdn.stamp.fyi url for
4 | * @returns cdn.stamp.fyi url
5 | */
6 | const getStampFyiURL = (address: string) => {
7 | return `https://cdn.stamp.fyi/avatar/eth:${address.toLowerCase()}?s=250`;
8 | };
9 |
10 | export default getStampFyiURL;
--------------------------------------------------------------------------------
/src/utils/functions/getTags.ts:
--------------------------------------------------------------------------------
1 | const getTags = (inputText: string) => {
2 | const regex = /(?:^|\s)#([\dA-Za-z]+)/gm;
3 | const matches: string[] = [];
4 | let match;
5 |
6 | while ((match = regex.exec(inputText))) {
7 | matches.push(match[1]);
8 | }
9 |
10 | return matches.filter((item, pos) => matches.indexOf(item) == pos).slice(0, 5);
11 | };
12 |
13 | export default getTags;
--------------------------------------------------------------------------------
/src/utils/functions/getThumbnailUrl.ts:
--------------------------------------------------------------------------------
1 | import { APP } from '../constants'
2 | import type { PinstaPublication } from '../custom-types'
3 | import sanitizeIpfsUrl from './sanitizeIpfsUrl'
4 |
5 | const getThumbnailUrl = (pin: PinstaPublication): string => {
6 | const url =
7 | pin.metadata?.cover?.original.url || pin.metadata?.media[0]?.original.url ||
8 | pin.metadata?.image ||
9 | `${APP.URL}/fallbackThumbnail.png`
10 | return sanitizeIpfsUrl(url)
11 | }
12 |
13 | export default getThumbnailUrl
--------------------------------------------------------------------------------
/src/utils/functions/getToastOptions.ts:
--------------------------------------------------------------------------------
1 | export const getToastOptions = (theme: string | undefined) => ({
2 | style: {
3 | padding: '16px',
4 | background: theme === 'dark' ? '#ec1e25' : '',
5 | borderRadius: '100px',
6 | boxShadow: 'rgba(0, 0, 0, 0.35) 0px 6px 45px',
7 | backdropFilter: 'blur(3px)',
8 | color: theme === 'dark' ? '#fff' : '',
9 | textShadow: 'rgba(17, 17, 17, 0.21) 0px 1px 12px',
10 | },
11 | success: {
12 | className: '!px-3 !bg-green-500 !text-white overflow-hidden',
13 | iconTheme: {
14 | primary: '#fff',
15 | secondary: '#10B981'
16 | }
17 | },
18 | error: {
19 | className: '!px-3 !bg-red-500 !text-white overflow-hidden',
20 | iconTheme: {
21 | primary: '#fff',
22 | secondary: '#ec1e25'
23 | }
24 | },
25 | loading: {
26 | className: '!px-3 !bg-yellow-500 !text-white overflow-hidden',
27 | iconTheme: {
28 | primary: '#fff',
29 | secondary: 'rgba(230, 125, 0, 1)',
30 | },
31 | },
32 | reverseOrder: false,
33 | duration: 4000
34 | })
--------------------------------------------------------------------------------
/src/utils/functions/getTokenImage.ts:
--------------------------------------------------------------------------------
1 |
2 |
3 | /**
4 | *
5 | * @param symbol - Token symbol
6 | * @returns token image url
7 | */
8 | const getTokenImage = (symbol: string): string => `/tokens/${symbol?.toLowerCase()}.svg`;
9 |
10 | export default getTokenImage;
--------------------------------------------------------------------------------
/src/utils/functions/getUniqueMessages.ts:
--------------------------------------------------------------------------------
1 | import type { DecodedMessage } from '@xmtp/xmtp-js';
2 |
3 | const getUniqueMessages = (msgObj: DecodedMessage[]): DecodedMessage[] => {
4 | const uniqueMessages = [...Array.from(new Map(msgObj.map((item) => [item['id'], item])).values())];
5 | uniqueMessages.sort((a, b) => {
6 | return (b.sent?.getTime() ?? 0) - (a.sent?.getTime() ?? 0);
7 | });
8 |
9 | return uniqueMessages ?? [];
10 | };
11 |
12 | export default getUniqueMessages;
--------------------------------------------------------------------------------
/src/utils/functions/getUniswapURL.ts:
--------------------------------------------------------------------------------
1 | import { IS_MAINNET } from '@utils/constants';
2 |
3 | /**
4 | *
5 | * @param amount - Amount to swap
6 | * @param outputCurrency - Output currency symbol
7 | * @returns uniswap link
8 | */
9 | const getUniswapURL = (amount: number, outputCurrency: string): string => {
10 | return `https://app.uniswap.org/#/swap?exactField=output&exactAmount=${amount}&outputCurrency=${outputCurrency}&chain=${
11 | IS_MAINNET ? 'polygon' : 'polygon_mumbai'
12 | }`;
13 | };
14 |
15 | export default getUniswapURL;
--------------------------------------------------------------------------------
/src/utils/functions/getUserLocale.ts:
--------------------------------------------------------------------------------
1 | const getUserLocale = () => {
2 | return navigator?.languages?.length
3 | ? navigator.languages[0]
4 | : navigator.language
5 | }
6 |
7 | export default getUserLocale
--------------------------------------------------------------------------------
/src/utils/functions/getVideoCoverUrl.ts:
--------------------------------------------------------------------------------
1 | import { APP } from '../constants'
2 | import type { PinstaPublication } from '../custom-types'
3 | import sanitizeIpfsUrl from './sanitizeIpfsUrl'
4 |
5 | const getVideoCoverUrl = (pin: PinstaPublication): string => {
6 | const url =
7 | pin.metadata.cover?.original?.url ||
8 | `${APP.URL}/fallbackThumbnail.png`
9 | return sanitizeIpfsUrl(url)
10 | }
11 |
12 | export default getVideoCoverUrl
--------------------------------------------------------------------------------
/src/utils/functions/imageCdn.ts:
--------------------------------------------------------------------------------
1 | import { IMAGE_CDN_URL, IPFS_GATEWAY } from '../constants'
2 |
3 | const imageCdn = ( url: string, name?: string ): string => {
4 | if (!url) {
5 | return '';
6 | }
7 |
8 | if (url.includes(IMAGE_CDN_URL)) {
9 | const splitedUrl = url.split('/');
10 | const path = splitedUrl[splitedUrl.length - 1];
11 |
12 | return name ? `${IMAGE_CDN_URL}/${name}/${path}` : url;
13 | }
14 |
15 |
16 |
17 | return url;
18 | }
19 |
20 | export default imageCdn
--------------------------------------------------------------------------------
/src/utils/functions/omit.ts:
--------------------------------------------------------------------------------
1 | /**
2 | *
3 | * @param object - Object to remove properties from
4 | * @param name - Name of property to remove
5 | * @returns object with property removed
6 | */
7 | const omit = (object: Record, name: string) => {
8 | delete object[name];
9 | return object;
10 | };
11 |
12 | export default omit;
--------------------------------------------------------------------------------
/src/utils/functions/onError.ts:
--------------------------------------------------------------------------------
1 | import { ERROR_MESSAGE } from '../constants';
2 | import toast from 'react-hot-toast';
3 |
4 | const onError = (error: any) => {
5 | toast.error(error?.data?.message ?? error?.message ?? ERROR_MESSAGE);
6 | };
7 |
8 | export default onError;
--------------------------------------------------------------------------------
/src/utils/functions/parseJwt.ts:
--------------------------------------------------------------------------------
1 | type ReturnType = {
2 | exp: number
3 | }
4 |
5 | export const parseJwt = (token: string): ReturnType => {
6 | try {
7 | return JSON.parse(atob(token.split('.')[1]))
8 | } catch (e) {
9 | console.error('Error Parse JWT', e)
10 | return { exp: 0 }
11 | }
12 | }
--------------------------------------------------------------------------------
/src/utils/functions/publicationKeyFields.ts:
--------------------------------------------------------------------------------
1 | /**
2 | *
3 | * @param publication The publication to get the key fields from.
4 | * @returns key fields of the publication.
5 | */
6 | export const publicationKeyFields = (publication: any) => {
7 | return `${publication.__typename}:${JSON.stringify({
8 | id: publication.id,
9 | collectedBy: publication.collectedBy?.address,
10 | createdAt: publication.createdAt
11 | })}`;
12 | };
--------------------------------------------------------------------------------
/src/utils/functions/resolveEns.ts:
--------------------------------------------------------------------------------
1 |
2 | import { ENS_RESOLVER_WORKER_URL } from '@utils/constants';
3 | import axios from 'axios';
4 |
5 | export const resolveEns = async (addresses: string[]) => {
6 | const payload = JSON.stringify({
7 | addresses: addresses.map((address) => {
8 | return address.split("/")[0];
9 | }),
10 | });
11 | const response = await axios.post(ENS_RESOLVER_WORKER_URL, payload, {
12 | headers: {
13 | "Content-Type": "application/json",
14 | },
15 | });
16 | return response.data.ensNames;
17 | };
--------------------------------------------------------------------------------
/src/utils/functions/sanitizeDisplayName.ts:
--------------------------------------------------------------------------------
1 | import { Regex } from "@utils/constants";
2 |
3 | /**
4 | * Remove restricted symbols from profile name
5 | *
6 | * @param name Profile name
7 | * @returns Profile name with restricted symbols removed
8 | */
9 | const sanitizeDisplayName = (
10 | name: string | null | undefined
11 | ): string | null => {
12 | if (!name) {
13 | return null;
14 | }
15 |
16 | return name.replace(Regex.profileNameFilter, " ").trim();
17 | };
18 |
19 | export default sanitizeDisplayName;
20 |
--------------------------------------------------------------------------------
/src/utils/functions/sanitizeIpfsUrl.ts:
--------------------------------------------------------------------------------
1 | import { IPFS_GATEWAY } from '../constants'
2 |
3 | const sanitizeIpfsUrl = (url: string) => {
4 | const gateway = IPFS_GATEWAY
5 | if (!url) return url
6 |
7 | return url
8 | .replace(/^Qm[1-9A-Za-z]{44}/gm, `${gateway}${url}`)
9 | .replace('https://ipfs.io/ipfs/', gateway)
10 | .replace('https://ipfs.infura.io/ipfs/', gateway)
11 | .replace('ipfs://', gateway)
12 | }
13 |
14 | export default sanitizeIpfsUrl
--------------------------------------------------------------------------------
/src/utils/functions/sanitizeProfileInterests.ts:
--------------------------------------------------------------------------------
1 | import type { ProfileInterest } from '../custom-types'
2 |
3 | const sanitizeProfileInterests = (profileInterests: string[]) => {
4 | if (!profileInterests) return []
5 | const interests: Array = []
6 | const categories = profileInterests.filter(
7 | (interest) => !interest.includes('__')
8 | )
9 | categories.forEach((category) => {
10 | let subCategories = profileInterests
11 | .filter(
12 | (interest) => interest.includes(category) && interest.includes('__')
13 | )
14 | .map((item) => {
15 | return {
16 | label: item.toLowerCase().split('__')[1].replaceAll('_', ' & '),
17 | id: item
18 | }
19 | })
20 | interests.push({
21 | category: {
22 | label: category.replaceAll('_', ' & ').toLowerCase(),
23 | id: category
24 | },
25 | subCategories
26 | })
27 | })
28 | return interests
29 | }
30 |
31 | export default sanitizeProfileInterests
--------------------------------------------------------------------------------
/src/utils/functions/splitSignature.ts:
--------------------------------------------------------------------------------
1 | import { utils } from 'ethers';
2 |
3 | /**
4 | *
5 | * @param signature - Signature to split
6 | * @returns signature parts
7 | */
8 | const splitSignature = (signature: string) => {
9 | return utils.splitSignature(signature);
10 | };
11 |
12 | export default splitSignature;
--------------------------------------------------------------------------------
/src/utils/functions/trimify.ts:
--------------------------------------------------------------------------------
1 | /**
2 | *
3 | * @param value - Value to trim
4 | * @returns trimmed value
5 | */
6 | const trimify = (value: string): string => value?.replace(/\n\n\s*\n/g, '\n\n').trim();
7 |
8 | export default trimify;
--------------------------------------------------------------------------------
/src/utils/functions/truncate.ts:
--------------------------------------------------------------------------------
1 | const truncate = (str: string, max: number, suffix = '...') =>
2 | str.length < max
3 | ? str
4 | : `${str.substring(
5 | 0,
6 | str.substring(0, max - suffix.length).lastIndexOf(' ')
7 | )}${suffix}`
8 |
9 | export default truncate
--------------------------------------------------------------------------------
/src/utils/functions/uploadToAr.ts:
--------------------------------------------------------------------------------
1 | import axios from 'axios'
2 | import type { PublicationMetadataV2Input } from '@utils/lens'
3 | import toast from 'react-hot-toast'
4 |
5 | import type { ProfileMetadata } from '../custom-types'
6 | import { PINSTA_API_URL } from '@utils/constants'
7 |
8 | const uploadToAr = async (
9 | data: PublicationMetadataV2Input | ProfileMetadata
10 | ): Promise<{ url: string | null }> => {
11 | try {
12 | const response = await axios.post(
13 | `${PINSTA_API_URL}/metadata/upload`,
14 | data
15 | )
16 | const { url } = response.data
17 | return { url }
18 | } catch (error) {
19 | console.log('[Error AR Data Upload]', error)
20 | toast.error('Failed to upload metadata!')
21 | return { url: null }
22 | }
23 | }
24 |
25 | export default uploadToAr
--------------------------------------------------------------------------------
/src/utils/functions/wav3sMirror.ts:
--------------------------------------------------------------------------------
1 | import axios from 'axios'
2 | import toast from 'react-hot-toast'
3 |
4 | import { PINSTA_API_URL } from '@utils/constants'
5 |
6 | type Wav3sMirrorData = {
7 | appId: string,
8 | pubIdPointed: string,
9 | profileId: string,
10 | }
11 |
12 | const wav3sMirror = async (data: Wav3sMirrorData) => {
13 | try {
14 | const response = await axios.post(
15 | `${PINSTA_API_URL}/wav3s/mirror`,
16 | data
17 | )
18 | const res = response.data
19 | return res
20 | } catch (error) {
21 | console.log('[Error update Mirror on Wav3s]', error)
22 | toast.error('Failed to update Mirror on Wav3s!')
23 | }
24 | }
25 |
26 | export default wav3sMirror
--------------------------------------------------------------------------------
/src/utils/hooks/useDebounce.ts:
--------------------------------------------------------------------------------
1 | import { useEffect, useState } from 'react'
2 |
3 | function useDebounce(value: T, delay?: number): T {
4 | const [debouncedValue, setDebouncedValue] = useState(value)
5 |
6 | useEffect(() => {
7 | const timer = setTimeout(() => setDebouncedValue(value), delay || 500)
8 |
9 | return () => {
10 | clearTimeout(timer)
11 | }
12 | }, [value, delay])
13 |
14 | return debouncedValue
15 | }
16 |
17 | export default useDebounce
--------------------------------------------------------------------------------
/src/utils/hooks/useDragAndDrop.ts:
--------------------------------------------------------------------------------
1 | import { useState } from 'react'
2 |
3 | const useDragAndDrop = () => {
4 | const [dragOver, setDragOver] = useState(false)
5 | const [fileDropError, setFileDropError] = useState('')
6 |
7 | const onDragOver = (e: React.SyntheticEvent) => {
8 | e.preventDefault()
9 | setDragOver(true)
10 | }
11 |
12 | const onDragLeave = () => setDragOver(false)
13 |
14 | return {
15 | dragOver,
16 | setDragOver,
17 | onDragOver,
18 | onDragLeave,
19 | fileDropError,
20 | setFileDropError
21 | }
22 | }
23 |
24 | export default useDragAndDrop
--------------------------------------------------------------------------------
/src/utils/hooks/useHorizantalScroll.ts:
--------------------------------------------------------------------------------
1 | import { useEffect, useRef } from 'react'
2 |
3 | const useHorizontalScroll = () => {
4 | const elRef = useRef(null)
5 | useEffect(() => {
6 | const el = elRef.current
7 | if (!el) return
8 | const handleWheelEvent = (e: any) => {
9 | if (e.deltaY === 0) return
10 | e.preventDefault()
11 | el.scrollTo({
12 | left: el.scrollLeft + e.deltaY,
13 | behavior: 'smooth'
14 | })
15 | }
16 | el.addEventListener('wheel', handleWheelEvent)
17 | return () => el.removeEventListener('wheel', handleWheelEvent)
18 | }, [])
19 | return elRef
20 | }
21 |
22 | export default useHorizontalScroll
--------------------------------------------------------------------------------
/src/utils/hooks/useIsMounted.ts:
--------------------------------------------------------------------------------
1 | import { useEffect, useState } from 'react'
2 |
3 | function useIsMounted() {
4 | const [mounted, setMounted] = useState(false)
5 |
6 | useEffect(() => {
7 | setMounted(true)
8 | }, [])
9 |
10 | return { mounted }
11 | }
12 |
13 | export default useIsMounted
--------------------------------------------------------------------------------
/src/utils/hooks/useIsMounted.tsx:
--------------------------------------------------------------------------------
1 | import { useEffect, useState } from 'react'
2 |
3 | function useIsMounted() {
4 | const [mounted, setMounted] = useState(false)
5 |
6 | useEffect(() => {
7 | setMounted(true)
8 | }, [])
9 |
10 | return { mounted }
11 | }
12 |
13 | export default useIsMounted
--------------------------------------------------------------------------------
/src/utils/hooks/useOutsideClick.ts:
--------------------------------------------------------------------------------
1 | import type { RefObject } from 'react'
2 | import { useEffect } from 'react'
3 |
4 | type AnyEvent = MouseEvent | TouchEvent
5 |
6 | const useOutsideClick = (
7 | ref: RefObject,
8 | handler: (event: AnyEvent) => void
9 | ): void => {
10 | useEffect(() => {
11 | const listener = (event: AnyEvent) => {
12 | const el = ref?.current
13 |
14 | // Do nothing if clicking ref's element or descendent elements
15 | if (!el || el.contains(event.target as Node)) {
16 | return
17 | }
18 |
19 | handler(event)
20 | }
21 |
22 | document.addEventListener(`mousedown`, listener)
23 | document.addEventListener(`touchstart`, listener)
24 |
25 | return () => {
26 | document.removeEventListener(`mousedown`, listener)
27 | document.removeEventListener(`touchstart`, listener)
28 | }
29 |
30 | // Reload only if ref or handler changes
31 | }, [ref, handler])
32 | }
33 |
34 | export default useOutsideClick
--------------------------------------------------------------------------------
/src/utils/hooks/usePendingTxn.ts:
--------------------------------------------------------------------------------
1 | import { useHasTxHashBeenIndexedQuery } from '@utils/lens'
2 | import { useCallback, useEffect } from 'react'
3 | import toast from 'react-hot-toast'
4 |
5 | type Props = {
6 | txHash?: string
7 | txId?: string
8 | }
9 |
10 | const usePendingTxn = ({ txHash, txId }: Props) => {
11 | const { data, loading, stopPolling } = useHasTxHashBeenIndexedQuery({
12 | variables: {
13 | request: { txHash, txId }
14 | },
15 | skip: !txHash && !txHash?.length && !txId && !txId?.length,
16 | pollInterval: 1000
17 | })
18 |
19 | const checkIsIndexed = useCallback(() => {
20 | if (data?.hasTxHashBeenIndexed?.__typename) {
21 | if (
22 | data?.hasTxHashBeenIndexed?.__typename === 'TransactionIndexedResult' &&
23 | data?.hasTxHashBeenIndexed?.indexed
24 | ) {
25 | stopPolling()
26 | }
27 |
28 | if (data?.hasTxHashBeenIndexed?.__typename === 'TransactionError') {
29 | stopPolling()
30 | return toast.error(
31 | `Relay Error - ${data?.hasTxHashBeenIndexed?.reason}`
32 | )
33 | }
34 | }
35 | }, [stopPolling, data?.hasTxHashBeenIndexed])
36 |
37 | useEffect(() => {
38 | checkIsIndexed()
39 | }, [data, checkIsIndexed])
40 |
41 | return {
42 | data,
43 | indexed:
44 | data?.hasTxHashBeenIndexed?.__typename === 'TransactionIndexedResult' &&
45 | data.hasTxHashBeenIndexed.indexed,
46 | loading
47 | }
48 | }
49 |
50 | export default usePendingTxn
--------------------------------------------------------------------------------
/src/utils/hooks/useStreamMessages.tsx:
--------------------------------------------------------------------------------
1 | import { useMessageStore } from "@lib/store/message";
2 | import type { Conversation, DecodedMessage, Stream } from "@xmtp/xmtp-js";
3 | import { useEffect, useState } from "react";
4 |
5 | const useStreamMessages = (
6 | conversationKey: string,
7 | conversation?: Conversation,
8 | onMessageCallback?: () => void
9 | ) => {
10 | const addMessages = useMessageStore((state) => state.addMessages);
11 | const [stream, setStream] = useState>();
12 |
13 | useEffect(() => {
14 | if (!conversation) {
15 | return;
16 | }
17 | const closeStream = async () => {
18 | if (!stream) {
19 | return;
20 | }
21 | await stream.return();
22 | };
23 | const streamMessages = async () => {
24 | closeStream();
25 | const newStream = await conversation.streamMessages();
26 | setStream(newStream);
27 | for await (const msg of newStream) {
28 | const numAdded = addMessages(conversationKey, [msg]);
29 | if (numAdded > 0 && onMessageCallback) {
30 | onMessageCallback();
31 | }
32 | }
33 | };
34 | streamMessages();
35 | return () => {
36 | closeStream();
37 | };
38 | // eslint-disable-next-line react-hooks/exhaustive-deps
39 | }, [conversation]);
40 | };
41 |
42 | export default useStreamMessages;
43 |
--------------------------------------------------------------------------------
/src/utils/hooks/useWindowSize.tsx:
--------------------------------------------------------------------------------
1 | import { useEffect, useState } from 'react';
2 |
3 | interface Size {
4 | width: number | undefined;
5 | height: number | undefined;
6 | }
7 |
8 | // Borrowed from https://usehooks.com/useWindowSize/
9 | const useWindowSize = (): Size => {
10 | const [windowSize, setWindowSize] = useState({
11 | width: undefined,
12 | height: undefined
13 | });
14 |
15 | useEffect(() => {
16 | // Handler to call on window resize
17 | const handleResize = () => {
18 | // Set window width/height to state
19 | setWindowSize({
20 | width: window.innerWidth,
21 | height: window.innerHeight
22 | });
23 | };
24 |
25 | window.addEventListener('resize', handleResize);
26 | // Call handler right away so state gets updated with initial window size
27 | handleResize();
28 | // Remove event listener on cleanup
29 | return () => window.removeEventListener('resize', handleResize);
30 | }, []);
31 |
32 | return windowSize;
33 | };
34 |
35 | export default useWindowSize;
--------------------------------------------------------------------------------
/src/utils/lens/.eslintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | root: true,
3 | extends: ['weblint'],
4 | ignorePatterns: ['generated.ts']
5 | }
6 |
--------------------------------------------------------------------------------
/src/utils/lens/codegen.yml:
--------------------------------------------------------------------------------
1 | schema: https://api-mumbai.lens.dev
2 | documents:
3 | ['./documents/queries/*.graphql', './documents/mutations/*.graphql', './documents/fragments/*.graphql']
4 |
5 | hooks:
6 | afterAllFileWrite:
7 | - prettier --write
8 |
9 | generates:
10 | generated.ts:
11 | plugins:
12 | - typescript
13 | - typescript-operations
14 | - fragment-matcher
15 | - typescript-react-apollo
--------------------------------------------------------------------------------
/src/utils/lens/documents/fragments/CollectFields.graphql:
--------------------------------------------------------------------------------
1 | fragment CollectFields on CollectModule {
2 | ... on FreeCollectModuleSettings {
3 | type
4 | contractAddress
5 | followerOnly
6 | }
7 | ... on FeeCollectModuleSettings {
8 | type
9 | recipient
10 | referralFee
11 | contractAddress
12 | followerOnly
13 | amount {
14 | asset {
15 | symbol
16 | decimals
17 | address
18 | }
19 | value
20 | }
21 | }
22 | ... on LimitedFeeCollectModuleSettings {
23 | type
24 | collectLimit
25 | recipient
26 | referralFee
27 | contractAddress
28 | followerOnly
29 | amount {
30 | asset {
31 | symbol
32 | decimals
33 | address
34 | }
35 | value
36 | }
37 | }
38 | ... on LimitedTimedFeeCollectModuleSettings {
39 | type
40 | collectLimit
41 | recipient
42 | endTimestamp
43 | referralFee
44 | contractAddress
45 | followerOnly
46 | amount {
47 | asset {
48 | symbol
49 | decimals
50 | address
51 | }
52 | value
53 | }
54 | }
55 | ... on TimedFeeCollectModuleSettings {
56 | type
57 | recipient
58 | endTimestamp
59 | referralFee
60 | contractAddress
61 | followerOnly
62 | amount {
63 | asset {
64 | symbol
65 | decimals
66 | address
67 | }
68 | value
69 | }
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/src/utils/lens/documents/fragments/CollectModuleFields.graphql:
--------------------------------------------------------------------------------
1 | fragment CollectModuleFields on CollectModule {
2 | ... on FreeCollectModuleSettings {
3 | type
4 | contractAddress
5 | followerOnly
6 | }
7 | ... on FeeCollectModuleSettings {
8 | type
9 | referralFee
10 | contractAddress
11 | followerOnly
12 | amount {
13 | asset {
14 | symbol
15 | decimals
16 | address
17 | }
18 | value
19 | }
20 | }
21 | ... on LimitedFeeCollectModuleSettings {
22 | type
23 | collectLimit
24 | referralFee
25 | contractAddress
26 | followerOnly
27 | amount {
28 | asset {
29 | symbol
30 | decimals
31 | address
32 | }
33 | value
34 | }
35 | }
36 | ... on LimitedTimedFeeCollectModuleSettings {
37 | type
38 | collectLimit
39 | endTimestamp
40 | referralFee
41 | contractAddress
42 | followerOnly
43 | amount {
44 | asset {
45 | symbol
46 | decimals
47 | address
48 | }
49 | value
50 | }
51 | }
52 | ... on TimedFeeCollectModuleSettings {
53 | type
54 | endTimestamp
55 | referralFee
56 | contractAddress
57 | followerOnly
58 | amount {
59 | asset {
60 | symbol
61 | decimals
62 | address
63 | }
64 | value
65 | }
66 | }
67 | }
--------------------------------------------------------------------------------
/src/utils/lens/documents/fragments/CommentFields.graphql:
--------------------------------------------------------------------------------
1 | fragment CommentFields on Comment {
2 | id
3 | reaction(request: $reactionRequest)
4 | profile {
5 | ...ProfileFields
6 | }
7 | collectedBy {
8 | address
9 | defaultProfile {
10 | handle
11 | }
12 | }
13 | collectModule {
14 | ...CollectModuleFields
15 | }
16 | referenceModule {
17 | __typename
18 | }
19 | canComment(profileId: $profileId) {
20 | result
21 | }
22 | canMirror(profileId: $profileId) {
23 | result
24 | }
25 | collectNftAddress
26 | onChainContentURI
27 | hidden
28 | hasCollectedByMe
29 | stats {
30 | totalAmountOfComments
31 | totalAmountOfCollects
32 | totalAmountOfMirrors
33 | totalUpvotes
34 | }
35 | metadata {
36 | name
37 | description
38 | content
39 | contentWarning
40 | mainContentFocus
41 | tags
42 | media {
43 | original {
44 | url
45 | mimeType
46 | }
47 | }
48 | cover {
49 | original {
50 | url
51 | }
52 | }
53 | attributes {
54 | value
55 | traitType
56 | }
57 | }
58 | commentOn {
59 | ... on Post {
60 | id
61 | createdAt
62 | profile {
63 | ...ProfileFields
64 | }
65 | metadata {
66 | name
67 | cover {
68 | original {
69 | url
70 | }
71 | }
72 | attributes {
73 | value
74 | traitType
75 | }
76 | }
77 | }
78 | }
79 | createdAt
80 | appId
81 | }
82 |
--------------------------------------------------------------------------------
/src/utils/lens/documents/fragments/MetadataFields.graphql:
--------------------------------------------------------------------------------
1 | fragment MetadataFields on MetadataOutput {
2 | name
3 | content
4 | image
5 | attributes {
6 | displayType
7 | traitType
8 | value
9 | }
10 | cover {
11 | original {
12 | url
13 | }
14 | }
15 | media {
16 | original {
17 | url
18 | mimeType
19 | }
20 | }
21 | encryptionParams {
22 | accessCondition {
23 | or {
24 | criteria {
25 | ...SimpleConditionFields
26 | and {
27 | criteria {
28 | ...SimpleConditionFields
29 | }
30 | }
31 | or {
32 | criteria {
33 | ...SimpleConditionFields
34 | }
35 | }
36 | }
37 | }
38 | }
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/src/utils/lens/documents/fragments/MirrorFields.graphql:
--------------------------------------------------------------------------------
1 | fragment MirrorFields on Mirror {
2 | id
3 | profile {
4 | ...ProfileFields
5 | }
6 | reaction(request: $reactionRequest)
7 | isGated
8 | canComment(profileId: $profileId) {
9 | result
10 | }
11 | canMirror(profileId: $profileId) {
12 | result
13 | }
14 | canDecrypt(profileId: $profileId) {
15 | result
16 | reasons
17 | }
18 | collectModule {
19 | ...CollectModuleFields
20 | }
21 | stats {
22 | ...StatsFields
23 | }
24 | metadata {
25 | ...MetadataFields
26 | }
27 | hidden
28 | mirrorOf {
29 | ... on Post {
30 | ...PostFields
31 | }
32 | ... on Comment {
33 | id
34 | profile {
35 | ...ProfileFields
36 | }
37 | reaction(request: $reactionRequest)
38 | mirrors(by: $profileId)
39 | onChainContentURI
40 | isGated
41 | canComment(profileId: $profileId) {
42 | result
43 | }
44 | canMirror(profileId: $profileId) {
45 | result
46 | }
47 | canDecrypt(profileId: $profileId) {
48 | result
49 | reasons
50 | }
51 | stats {
52 | ...StatsFields
53 | }
54 | createdAt
55 | }
56 | }
57 | createdAt
58 | appId
59 | }
60 |
--------------------------------------------------------------------------------
/src/utils/lens/documents/fragments/PostFields.graphql:
--------------------------------------------------------------------------------
1 | fragment PostFields on Post {
2 | id
3 | profile {
4 | ...ProfileFields
5 | }
6 | reaction(request: $reactionRequest)
7 | mirrors(by: $profileId)
8 | hasCollectedByMe
9 | onChainContentURI
10 | canComment(profileId: $profileId) {
11 | result
12 | }
13 | canMirror(profileId: $profileId) {
14 | result
15 | }
16 | canDecrypt(profileId: $profileId) {
17 | result
18 | reasons
19 | }
20 | collectedBy {
21 | address
22 | defaultProfile {
23 | ...ProfileFields
24 | }
25 | }
26 | collectModule {
27 | ...CollectModuleFields
28 | }
29 | stats {
30 | ...StatsFields
31 | }
32 | metadata {
33 | ...MetadataFields
34 | }
35 | hidden
36 | createdAt
37 | appId
38 | }
39 |
--------------------------------------------------------------------------------
/src/utils/lens/documents/fragments/ProfileFields.graphql:
--------------------------------------------------------------------------------
1 | fragment ProfileFields on Profile {
2 | id
3 | name
4 | handle
5 | bio
6 | ownedBy
7 | isDefault
8 | interests
9 | isFollowedByMe
10 | dispatcher {
11 | canUseRelay
12 | }
13 | attributes {
14 | key
15 | value
16 | }
17 | stats {
18 | totalFollowers
19 | totalPosts
20 | }
21 | picture {
22 | ... on MediaSet {
23 | original {
24 | url
25 | }
26 | }
27 | ... on NftImage {
28 | uri
29 | }
30 | }
31 | followModule {
32 | __typename
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/src/utils/lens/documents/fragments/RelayerResult.graphql:
--------------------------------------------------------------------------------
1 | fragment RelayerResult on RelayResult {
2 | ... on RelayerResult {
3 | txId
4 | txHash
5 | }
6 | ... on RelayError {
7 | reason
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/src/utils/lens/documents/fragments/SimpleConditionFields.graphql:
--------------------------------------------------------------------------------
1 | fragment SimpleConditionFields on AccessConditionOutput {
2 | nft {
3 | contractAddress
4 | chainID
5 | contractType
6 | tokenIds
7 | }
8 | eoa {
9 | address
10 | }
11 | token {
12 | contractAddress
13 | amount
14 | chainID
15 | condition
16 | decimals
17 | }
18 | follow {
19 | profileId
20 | }
21 | collect {
22 | publicationId
23 | thisPublication
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/src/utils/lens/documents/fragments/StatsFields.graphql:
--------------------------------------------------------------------------------
1 | fragment StatsFields on PublicationStats {
2 | totalUpvotes
3 | totalAmountOfMirrors
4 | totalAmountOfCollects
5 | totalAmountOfComments
6 | }
7 |
--------------------------------------------------------------------------------
/src/utils/lens/documents/mutations/AddProfileInterest.graphql:
--------------------------------------------------------------------------------
1 | mutation AddProfileInterest($request: AddProfileInterestsRequest!) {
2 | addProfileInterests(request: $request)
3 | }
4 |
--------------------------------------------------------------------------------
/src/utils/lens/documents/mutations/AddReaction.graphql:
--------------------------------------------------------------------------------
1 | mutation AddReaction($request: ReactionRequest!) {
2 | addReaction(request: $request)
3 | }
4 |
--------------------------------------------------------------------------------
/src/utils/lens/documents/mutations/Authenticate.graphql:
--------------------------------------------------------------------------------
1 | mutation Authenticate($request: SignedAuthChallenge!) {
2 | authenticate(request: $request) {
3 | accessToken
4 | refreshToken
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/src/utils/lens/documents/mutations/Broadcast.graphql:
--------------------------------------------------------------------------------
1 | mutation Broadcast($request: BroadcastRequest!) {
2 | broadcast(request: $request) {
3 | ... on RelayerResult {
4 | txId
5 | txHash
6 | }
7 | ... on RelayError {
8 | reason
9 | }
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/src/utils/lens/documents/mutations/CreateBurnProfileTypedData.graphql:
--------------------------------------------------------------------------------
1 | mutation CreateBurnProfileTypedData($request: BurnProfileRequest!) {
2 | createBurnProfileTypedData(request: $request) {
3 | id
4 | expiresAt
5 | typedData {
6 | domain {
7 | name
8 | chainId
9 | version
10 | verifyingContract
11 | }
12 | types {
13 | BurnWithSig {
14 | name
15 | type
16 | }
17 | }
18 | value {
19 | nonce
20 | deadline
21 | tokenId
22 | }
23 | }
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/src/utils/lens/documents/mutations/CreateCollectTypedData.graphql:
--------------------------------------------------------------------------------
1 | mutation CreateCollectTypedData(
2 | $options: TypedDataOptions
3 | $request: CreateCollectRequest!
4 | ) {
5 | createCollectTypedData(options: $options, request: $request) {
6 | id
7 | expiresAt
8 | typedData {
9 | types {
10 | CollectWithSig {
11 | name
12 | type
13 | }
14 | }
15 | domain {
16 | name
17 | chainId
18 | version
19 | verifyingContract
20 | }
21 | value {
22 | nonce
23 | deadline
24 | profileId
25 | pubId
26 | data
27 | }
28 | }
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/src/utils/lens/documents/mutations/CreateCommentTypedData.graphql:
--------------------------------------------------------------------------------
1 | mutation CreateCommentTypedData(
2 | $options: TypedDataOptions
3 | $request: CreatePublicCommentRequest!
4 | ) {
5 | createCommentTypedData(options: $options, request: $request) {
6 | id
7 | expiresAt
8 | typedData {
9 | types {
10 | CommentWithSig {
11 | name
12 | type
13 | }
14 | }
15 | domain {
16 | name
17 | chainId
18 | version
19 | verifyingContract
20 | }
21 | value {
22 | nonce
23 | deadline
24 | profileId
25 | profileIdPointed
26 | pubIdPointed
27 | contentURI
28 | collectModule
29 | collectModuleInitData
30 | referenceModule
31 | referenceModuleData
32 | referenceModuleInitData
33 | }
34 | }
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/src/utils/lens/documents/mutations/CreateCommentViaDispatcher.graphql:
--------------------------------------------------------------------------------
1 | mutation CreateCommentViaDispatcher($request: CreatePublicCommentRequest!) {
2 | createCommentViaDispatcher(request: $request) {
3 | ...RelayerResult
4 | }
5 | }
6 |
--------------------------------------------------------------------------------
/src/utils/lens/documents/mutations/CreateFollowTypedData.graphql:
--------------------------------------------------------------------------------
1 | mutation CreateFollowTypedData(
2 | $options: TypedDataOptions
3 | $request: FollowRequest!
4 | ) {
5 | createFollowTypedData(options: $options, request: $request) {
6 | id
7 | expiresAt
8 | typedData {
9 | domain {
10 | name
11 | chainId
12 | version
13 | verifyingContract
14 | }
15 | types {
16 | FollowWithSig {
17 | name
18 | type
19 | }
20 | }
21 | value {
22 | nonce
23 | deadline
24 | profileIds
25 | datas
26 | }
27 | }
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/utils/lens/documents/mutations/CreateMirrorTypedData.graphql:
--------------------------------------------------------------------------------
1 | mutation CreateMirrorTypedData(
2 | $options: TypedDataOptions
3 | $request: CreateMirrorRequest!
4 | ) {
5 | createMirrorTypedData(options: $options, request: $request) {
6 | id
7 | expiresAt
8 | typedData {
9 | types {
10 | MirrorWithSig {
11 | name
12 | type
13 | }
14 | }
15 | domain {
16 | name
17 | chainId
18 | version
19 | verifyingContract
20 | }
21 | value {
22 | nonce
23 | deadline
24 | profileId
25 | profileIdPointed
26 | pubIdPointed
27 | referenceModule
28 | referenceModuleData
29 | referenceModuleInitData
30 | }
31 | }
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/src/utils/lens/documents/mutations/CreateMirrorViaDispatcher.graphql:
--------------------------------------------------------------------------------
1 | mutation CreateMirrorViaDispatcher($request: CreateMirrorRequest!) {
2 | createMirrorViaDispatcher(request: $request) {
3 | ...RelayerResult
4 | }
5 | }
6 |
--------------------------------------------------------------------------------
/src/utils/lens/documents/mutations/CreatePostTypedData.graphql:
--------------------------------------------------------------------------------
1 | mutation CreatePostTypedData($request: CreatePublicPostRequest!) {
2 | createPostTypedData(request: $request) {
3 | id
4 | expiresAt
5 | typedData {
6 | types {
7 | PostWithSig {
8 | name
9 | type
10 | }
11 | }
12 | domain {
13 | name
14 | chainId
15 | version
16 | verifyingContract
17 | }
18 | value {
19 | nonce
20 | deadline
21 | profileId
22 | contentURI
23 | collectModule
24 | collectModuleInitData
25 | referenceModule
26 | referenceModuleInitData
27 | }
28 | }
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/src/utils/lens/documents/mutations/CreatePostViaDispatcher.graphql:
--------------------------------------------------------------------------------
1 | mutation CreatePostViaDispatcher($request: CreatePublicPostRequest!) {
2 | createPostViaDispatcher(request: $request) {
3 | ...RelayerResult
4 | }
5 | }
6 |
--------------------------------------------------------------------------------
/src/utils/lens/documents/mutations/CreateProfile.graphql:
--------------------------------------------------------------------------------
1 | mutation CreateProfile($request: CreateProfileRequest!) {
2 | createProfile(request: $request) {
3 | ... on RelayerResult {
4 | txHash
5 | }
6 | ... on RelayError {
7 | reason
8 | }
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/src/utils/lens/documents/mutations/CreateSetDispatcherTypedData.graphql:
--------------------------------------------------------------------------------
1 | mutation CreateSetDispatcherTypedData(
2 | $options: TypedDataOptions
3 | $request: SetDispatcherRequest!
4 | ) {
5 | createSetDispatcherTypedData(options: $options, request: $request) {
6 | id
7 | typedData {
8 | types {
9 | SetDispatcherWithSig {
10 | name
11 | type
12 | }
13 | }
14 | domain {
15 | name
16 | chainId
17 | version
18 | verifyingContract
19 | }
20 | value {
21 | nonce
22 | deadline
23 | profileId
24 | dispatcher
25 | }
26 | }
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/src/utils/lens/documents/mutations/CreateSetFollowModuleTypedData.graphql:
--------------------------------------------------------------------------------
1 | mutation CreateSetFollowModuleTypedData(
2 | $options: TypedDataOptions
3 | $request: CreateSetFollowModuleRequest!
4 | ) {
5 | createSetFollowModuleTypedData(options: $options, request: $request) {
6 | id
7 | expiresAt
8 | typedData {
9 | types {
10 | SetFollowModuleWithSig {
11 | name
12 | type
13 | }
14 | }
15 | domain {
16 | name
17 | chainId
18 | version
19 | verifyingContract
20 | }
21 | value {
22 | nonce
23 | deadline
24 | profileId
25 | followModule
26 | followModuleInitData
27 | }
28 | }
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/src/utils/lens/documents/mutations/CreateSetProfileImageURITypedData.graphql:
--------------------------------------------------------------------------------
1 | mutation CreateSetProfileImageURITypedData(
2 | $options: TypedDataOptions
3 | $request: UpdateProfileImageRequest!
4 | ) {
5 | createSetProfileImageURITypedData(options: $options, request: $request) {
6 | id
7 | expiresAt
8 | typedData {
9 | domain {
10 | name
11 | chainId
12 | version
13 | verifyingContract
14 | }
15 | types {
16 | SetProfileImageURIWithSig {
17 | name
18 | type
19 | }
20 | }
21 | value {
22 | nonce
23 | deadline
24 | imageURI
25 | profileId
26 | }
27 | }
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/utils/lens/documents/mutations/CreateSetProfileImageURIViaDispatcher.graphql:
--------------------------------------------------------------------------------
1 | mutation CreateSetProfileImageURIViaDispatcher(
2 | $request: UpdateProfileImageRequest!
3 | ) {
4 | createSetProfileImageURIViaDispatcher(request: $request) {
5 | ...RelayerResult
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/src/utils/lens/documents/mutations/CreateSetProfileMetadataTypedData.graphql:
--------------------------------------------------------------------------------
1 | mutation CreateSetProfileMetadataTypedData(
2 | $request: CreatePublicSetProfileMetadataURIRequest!
3 | ) {
4 | createSetProfileMetadataTypedData(request: $request) {
5 | id
6 | expiresAt
7 | typedData {
8 | types {
9 | SetProfileMetadataURIWithSig {
10 | name
11 | type
12 | }
13 | }
14 | domain {
15 | name
16 | chainId
17 | version
18 | verifyingContract
19 | }
20 | value {
21 | nonce
22 | deadline
23 | profileId
24 | metadata
25 | }
26 | }
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/src/utils/lens/documents/mutations/CreateSetProfileMetadataViaDispatcher.graphql:
--------------------------------------------------------------------------------
1 | mutation CreateSetProfileMetadataViaDispatcher(
2 | $request: CreatePublicSetProfileMetadataURIRequest!
3 | ) {
4 | createSetProfileMetadataViaDispatcher(request: $request) {
5 | ...RelayerResult
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/src/utils/lens/documents/mutations/HidePublication.graphql:
--------------------------------------------------------------------------------
1 | mutation HidePublication($request: HidePublicationRequest!) {
2 | hidePublication(request: $request)
3 | }
4 |
--------------------------------------------------------------------------------
/src/utils/lens/documents/mutations/ProxyAction.graphql:
--------------------------------------------------------------------------------
1 | mutation proxyAction($request: ProxyActionRequest!) {
2 | proxyAction(request: $request)
3 | }
4 |
--------------------------------------------------------------------------------
/src/utils/lens/documents/mutations/RemoveProfileInterest.graphql:
--------------------------------------------------------------------------------
1 | mutation RemoveProfileInterest($request: RemoveProfileInterestsRequest!) {
2 | removeProfileInterests(request: $request)
3 | }
4 |
--------------------------------------------------------------------------------
/src/utils/lens/documents/mutations/RemoveReaction.graphql:
--------------------------------------------------------------------------------
1 | mutation RemoveReaction($request: ReactionRequest!) {
2 | removeReaction(request: $request)
3 | }
4 |
--------------------------------------------------------------------------------
/src/utils/lens/documents/mutations/ReportPublication.graphql:
--------------------------------------------------------------------------------
1 | mutation ReportPublication($request: ReportPublicationRequest!) {
2 | reportPublication(request: $request)
3 | }
4 |
--------------------------------------------------------------------------------
/src/utils/lens/documents/queries/AllProfiles.graphql:
--------------------------------------------------------------------------------
1 | query AllProfiles($request: ProfileQueryRequest!) {
2 | profiles(request: $request) {
3 | items {
4 | ...ProfileFields
5 | }
6 | pageInfo {
7 | totalCount
8 | next
9 | }
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/src/utils/lens/documents/queries/AllPublicationsTags.graphql:
--------------------------------------------------------------------------------
1 | query AllPublicationsTags($request: AllPublicationsTagsRequest!) {
2 | allPublicationsTags(request: $request) {
3 | items {
4 | tag
5 | total
6 | }
7 | pageInfo {
8 | totalCount
9 | next
10 | }
11 | }
12 | }
--------------------------------------------------------------------------------
/src/utils/lens/documents/queries/ApprovedModuleAllowanceAmount.graphql:
--------------------------------------------------------------------------------
1 | query ApprovedModuleAllowanceAmount(
2 | $request: ApprovedModuleAllowanceAmountRequest!
3 | ) {
4 | approvedModuleAllowanceAmount(request: $request) {
5 | currency
6 | module
7 | allowance
8 | contractAddress
9 | }
10 | enabledModuleCurrencies {
11 | name
12 | symbol
13 | decimals
14 | address
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/src/utils/lens/documents/queries/Challenge.graphql:
--------------------------------------------------------------------------------
1 | query Challenge($request: ChallengeRequest!) {
2 | challenge(request: $request) {
3 | text
4 | }
5 | }
6 |
--------------------------------------------------------------------------------
/src/utils/lens/documents/queries/CollectModule.graphql:
--------------------------------------------------------------------------------
1 | query CollectModule($request: PublicationQueryRequest!) {
2 | publication(request: $request) {
3 | ... on Post {
4 | collectNftAddress
5 | collectModule {
6 | ...CollectModuleFields
7 | }
8 | }
9 | ... on Comment {
10 | collectNftAddress
11 | collectModule {
12 | ...CollectModuleFields
13 | }
14 | }
15 | ... on Mirror {
16 | collectNftAddress
17 | collectModule {
18 | ...CollectModuleFields
19 | }
20 | }
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/src/utils/lens/documents/queries/Collectors.graphql:
--------------------------------------------------------------------------------
1 | query Collectors($request: WhoCollectedPublicationRequest!) {
2 | whoCollectedPublication(request: $request) {
3 | items {
4 | address
5 | defaultProfile {
6 | ...ProfileFields
7 | }
8 | }
9 | pageInfo {
10 | next
11 | totalCount
12 | }
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/src/utils/lens/documents/queries/CommentFeed.graphql:
--------------------------------------------------------------------------------
1 | query CommentFeed(
2 | $request: PublicationsQueryRequest!
3 | $reactionRequest: ReactionFieldResolverRequest
4 | $profileId: ProfileId
5 | ) {
6 | publications(request: $request) {
7 | items {
8 | ... on Comment {
9 | ...CommentFields
10 | }
11 | }
12 | pageInfo {
13 | totalCount
14 | next
15 | }
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/src/utils/lens/documents/queries/CreateUnFollowTypedData.graphql:
--------------------------------------------------------------------------------
1 | mutation CreateUnfollowTypedData($request: UnfollowRequest!) {
2 | createUnfollowTypedData(request: $request) {
3 | id
4 | expiresAt
5 | typedData {
6 | domain {
7 | name
8 | chainId
9 | version
10 | verifyingContract
11 | }
12 | types {
13 | BurnWithSig {
14 | name
15 | type
16 | }
17 | }
18 | value {
19 | nonce
20 | deadline
21 | tokenId
22 | }
23 | }
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/src/utils/lens/documents/queries/EnabledCurrencyModules.graphql:
--------------------------------------------------------------------------------
1 | query EnabledCurrencyModules {
2 | enabledModuleCurrencies {
3 | name
4 | symbol
5 | decimals
6 | address
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/src/utils/lens/documents/queries/EnabledCurrencyModulesWithProfile.graphql:
--------------------------------------------------------------------------------
1 | query EnabledCurrencyModulesWithProfile($request: SingleProfileQueryRequest!) {
2 | enabledModuleCurrencies {
3 | name
4 | symbol
5 | decimals
6 | address
7 | }
8 | profile(request: $request) {
9 | followModule {
10 | __typename
11 | }
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/src/utils/lens/documents/queries/EnabledModuleCurrrencies.graphql:
--------------------------------------------------------------------------------
1 | query EnabledModuleCurrrencies($request: ProfileQueryRequest!) {
2 | enabledModuleCurrencies {
3 | name
4 | symbol
5 | decimals
6 | address
7 | }
8 | profiles(request: $request) {
9 | items {
10 | followModule {
11 | __typename
12 | }
13 | }
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/src/utils/lens/documents/queries/EnabledModules.graphql:
--------------------------------------------------------------------------------
1 | query EnabledModules {
2 | enabledModules {
3 | collectModules {
4 | moduleName
5 | contractAddress
6 | }
7 | }
8 | enabledModuleCurrencies {
9 | name
10 | symbol
11 | decimals
12 | address
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/src/utils/lens/documents/queries/Explore.graphql:
--------------------------------------------------------------------------------
1 | query Explore(
2 | $request: ExplorePublicationRequest!
3 | $reactionRequest: ReactionFieldResolverRequest
4 | $profileId: ProfileId
5 | ) {
6 | explorePublications(request: $request) {
7 | items {
8 | ... on Post {
9 | ...PostFields
10 | }
11 | ... on Comment {
12 | ...CommentFields
13 | }
14 | ... on Mirror {
15 | ...MirrorFields
16 | }
17 | }
18 | pageInfo {
19 | totalCount
20 | next
21 | }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/utils/lens/documents/queries/Feed.graphql:
--------------------------------------------------------------------------------
1 | query Feed(
2 | $request: FeedRequest!
3 | $reactionRequest: ReactionFieldResolverRequest
4 | $profileId: ProfileId
5 | ) {
6 | feed(request: $request) {
7 | items {
8 | root {
9 | ... on Post {
10 | ...PostFields
11 | }
12 | ... on Comment {
13 | ...CommentFields
14 | }
15 | }
16 | electedMirror {
17 | mirrorId
18 | profile {
19 | ...ProfileFields
20 | }
21 | timestamp
22 | }
23 | mirrors {
24 | profile {
25 | ...ProfileFields
26 | }
27 | timestamp
28 | }
29 | collects {
30 | profile {
31 | ...ProfileFields
32 | }
33 | timestamp
34 | }
35 | reactions {
36 | profile {
37 | ...ProfileFields
38 | }
39 | reaction
40 | timestamp
41 | }
42 | comments {
43 | ...CommentFields
44 | }
45 | }
46 | pageInfo {
47 | next
48 | totalCount
49 | }
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/src/utils/lens/documents/queries/Followers.graphql:
--------------------------------------------------------------------------------
1 | query Followers($request: FollowersRequest!) {
2 | followers(request: $request) {
3 | items {
4 | wallet {
5 | address
6 | defaultProfile {
7 | ...ProfileFields
8 | isFollowedByMe
9 | }
10 | }
11 | totalAmountOfTimesFollowed
12 | }
13 | pageInfo {
14 | next
15 | totalCount
16 | }
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/src/utils/lens/documents/queries/Following.graphql:
--------------------------------------------------------------------------------
1 | query Following($request: FollowingRequest!) {
2 | following(request: $request) {
3 | items {
4 | profile {
5 | ...ProfileFields
6 | isFollowedByMe
7 | }
8 | totalAmountOfTimesFollowing
9 | }
10 | pageInfo {
11 | next
12 | totalCount
13 | }
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/src/utils/lens/documents/queries/GenerateModuleCurrencyApprovalData.graphql:
--------------------------------------------------------------------------------
1 | query GenerateModuleCurrencyApprovalData(
2 | $request: GenerateModuleCurrencyApprovalDataRequest!
3 | ) {
4 | generateModuleCurrencyApprovalData(request: $request) {
5 | to
6 | from
7 | data
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/src/utils/lens/documents/queries/GlobalProtocolStats.graphql:
--------------------------------------------------------------------------------
1 | query GlobalProtocolStats($request: GlobalProtocolStatsRequest) {
2 | globalProtocolStats(request: $request) {
3 | totalProfiles
4 | totalBurntProfiles
5 | totalPosts
6 | totalMirrors
7 | totalComments
8 | totalCollects
9 | totalFollows
10 | totalRevenue {
11 | asset {
12 | name
13 | symbol
14 | decimals
15 | address
16 | }
17 | value
18 | }
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/src/utils/lens/documents/queries/HasPublicationIndexed.graphql:
--------------------------------------------------------------------------------
1 | query HasPublicationIndexed($request: PublicationQueryRequest!) {
2 | publication(request: $request) {
3 | ... on Post {
4 | id
5 | }
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/src/utils/lens/documents/queries/HasTxHashBeenIndexed.graphql:
--------------------------------------------------------------------------------
1 | query HasTxHashBeenIndexed($request: HasTxHashBeenIndexedRequest!) {
2 | hasTxHashBeenIndexed(request: $request) {
3 | ... on TransactionIndexedResult {
4 | metadataStatus {
5 | status
6 | }
7 | txHash
8 | indexed
9 | }
10 | ... on TransactionError {
11 | reason
12 | }
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/src/utils/lens/documents/queries/MutualFollowers.graphql:
--------------------------------------------------------------------------------
1 | query MutualFollowers($request: MutualFollowersProfilesQueryRequest!) {
2 | mutualFollowersProfiles(request: $request) {
3 | items {
4 | ...ProfileFields
5 | }
6 | pageInfo {
7 | next
8 | totalCount
9 | }
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/src/utils/lens/documents/queries/NFTChallenge.graphql:
--------------------------------------------------------------------------------
1 | query NFTChallenge($request: NftOwnershipChallengeRequest!) {
2 | nftOwnershipChallenge(request: $request) {
3 | id
4 | text
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/src/utils/lens/documents/queries/NFTFeed.graphql:
--------------------------------------------------------------------------------
1 | query NFTFeed($request: NFTsRequest!) {
2 | nfts(request: $request) {
3 | items {
4 | name
5 | collectionName
6 | contractAddress
7 | tokenId
8 | chainId
9 | originalContent {
10 | uri
11 | animatedUrl
12 | }
13 | }
14 | pageInfo {
15 | next
16 | totalCount
17 | }
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/src/utils/lens/documents/queries/NotificationCount.graphql:
--------------------------------------------------------------------------------
1 | query NotificationCount($request: NotificationRequest!) {
2 | notifications(request: $request) {
3 | pageInfo {
4 | totalCount
5 | }
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/src/utils/lens/documents/queries/Profile.graphql:
--------------------------------------------------------------------------------
1 | query Profile($request: SingleProfileQueryRequest!, $who: ProfileId) {
2 | profile(request: $request) {
3 | id
4 | handle
5 | ownedBy
6 | name
7 | dispatcher {
8 | canUseRelay
9 | }
10 | interests
11 | isFollowedByMe
12 | isFollowing(who: $who)
13 | onChainIdentity {
14 | proofOfHumanity
15 | worldcoin {
16 | isHuman
17 | }
18 | sybilDotOrg {
19 | verified
20 | source {
21 | twitter {
22 | handle
23 | }
24 | }
25 | }
26 | ens {
27 | name
28 | }
29 | }
30 | attributes {
31 | key
32 | value
33 | }
34 | bio
35 | stats {
36 | totalFollowers
37 | totalFollowing
38 | totalPosts
39 | totalComments
40 | totalMirrors
41 | totalPublications
42 | totalCollects
43 | }
44 | picture {
45 | ... on MediaSet {
46 | original {
47 | url
48 | }
49 | }
50 | ... on NftImage {
51 | uri
52 | }
53 | }
54 | coverPicture {
55 | ... on MediaSet {
56 | original {
57 | url
58 | }
59 | }
60 | }
61 | followModule {
62 | __typename
63 | }
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/src/utils/lens/documents/queries/ProfileAddress.graphql:
--------------------------------------------------------------------------------
1 | query ProfileAddress($request: SingleProfileQueryRequest!) {
2 | profile(request: $request) {
3 | id
4 | ownedBy
5 | }
6 | }
7 |
--------------------------------------------------------------------------------
/src/utils/lens/documents/queries/ProfileComments.graphql:
--------------------------------------------------------------------------------
1 | query ProfileComments(
2 | $request: PublicationsQueryRequest!
3 | $reactionRequest: ReactionFieldResolverRequest
4 | $profileId: ProfileId
5 | ) {
6 | publications(request: $request) {
7 | items {
8 | ... on Comment {
9 | ...CommentFields
10 | }
11 | }
12 | pageInfo {
13 | totalCount
14 | next
15 | }
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/src/utils/lens/documents/queries/ProfileFollowModule.graphql:
--------------------------------------------------------------------------------
1 | query ProfileFollowModule($request: ProfileQueryRequest!) {
2 | profiles(request: $request) {
3 | items {
4 | followModule {
5 | ... on FeeFollowModuleSettings {
6 | amount {
7 | asset {
8 | name
9 | symbol
10 | address
11 | decimals
12 | }
13 | value
14 | }
15 | recipient
16 | }
17 | }
18 | }
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/src/utils/lens/documents/queries/ProfileInterests.graphql:
--------------------------------------------------------------------------------
1 | query ProfileInterests {
2 | profileInterests
3 | }
4 |
--------------------------------------------------------------------------------
/src/utils/lens/documents/queries/ProfileMirrors.graphql:
--------------------------------------------------------------------------------
1 | query ProfileMirrors(
2 | $request: PublicationsQueryRequest!
3 | $reactionRequest: ReactionFieldResolverRequest
4 | $profileId: ProfileId
5 | ) {
6 | publications(request: $request) {
7 | items {
8 | ... on Mirror {
9 | ...MirrorFields
10 | }
11 | }
12 | pageInfo {
13 | totalCount
14 | next
15 | }
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/src/utils/lens/documents/queries/ProfileNFTs.graphql:
--------------------------------------------------------------------------------
1 | query ProfileNFTs($request: NFTsRequest!) {
2 | nfts(request: $request) {
3 | items {
4 | contractAddress
5 | tokenId
6 | name
7 | originalContent {
8 | animatedUrl
9 | uri
10 | metaType
11 | }
12 | collectionName
13 | }
14 | pageInfo {
15 | next
16 | totalCount
17 | }
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/src/utils/lens/documents/queries/ProfilePosts.graphql:
--------------------------------------------------------------------------------
1 | query ProfilePosts(
2 | $request: PublicationsQueryRequest!
3 | $reactionRequest: ReactionFieldResolverRequest
4 | $profileId: ProfileId
5 | ) {
6 | publications(request: $request) {
7 | items {
8 | ... on Post {
9 | ...PostFields
10 | }
11 | ... on Comment {
12 | ...CommentFields
13 | }
14 | ... on Mirror {
15 | ...MirrorFields
16 | }
17 | }
18 | pageInfo {
19 | totalCount
20 | next
21 | }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/utils/lens/documents/queries/ProxyActionStatus.graphql:
--------------------------------------------------------------------------------
1 | query ProxyActionStatus($proxyActionId: ProxyActionId!) {
2 | proxyActionStatus(proxyActionId: $proxyActionId) {
3 | ... on ProxyActionStatusResult {
4 | txId
5 | status
6 | }
7 | ... on ProxyActionError {
8 | reason
9 | }
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/src/utils/lens/documents/queries/Publication.graphql:
--------------------------------------------------------------------------------
1 | query Publication(
2 | $request: PublicationQueryRequest!
3 | $reactionRequest: ReactionFieldResolverRequest
4 | $profileId: ProfileId
5 | ) {
6 | publication(request: $request) {
7 | ... on Post {
8 | ...PostFields
9 | collectNftAddress
10 | profile {
11 | isFollowedByMe
12 | }
13 | referenceModule {
14 | __typename
15 | }
16 | }
17 | ... on Comment {
18 | ...CommentFields
19 | collectNftAddress
20 | profile {
21 | isFollowedByMe
22 | }
23 | referenceModule {
24 | __typename
25 | }
26 | }
27 | ... on Mirror {
28 | ...MirrorFields
29 | collectNftAddress
30 | profile {
31 | isFollowedByMe
32 | }
33 | referenceModule {
34 | __typename
35 | }
36 | }
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/src/utils/lens/documents/queries/PublicationCollectModule.graphql:
--------------------------------------------------------------------------------
1 | query PublicationCollectModule($request: PublicationQueryRequest!) {
2 | publication(request: $request) {
3 | ... on Post {
4 | collectNftAddress
5 | collectModule {
6 | ...CollectModuleFields
7 | }
8 | }
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/src/utils/lens/documents/queries/PublicationDetails.graphql:
--------------------------------------------------------------------------------
1 | query PublicationDetails(
2 | $request: PublicationQueryRequest!
3 | $reactionRequest: ReactionFieldResolverRequest
4 | $profileId: ProfileId
5 | ) {
6 | publication(request: $request) {
7 | ... on Post {
8 | ...PostFields
9 | }
10 | ... on Comment {
11 | ...CommentFields
12 | }
13 | ... on Mirror {
14 | ...MirrorFields
15 | }
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/src/utils/lens/documents/queries/PublicationRevenue.graphql:
--------------------------------------------------------------------------------
1 | query PublicationRevenue($request: PublicationRevenueQueryRequest!) {
2 | publicationRevenue(request: $request) {
3 | revenue {
4 | total {
5 | value
6 | }
7 | }
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/src/utils/lens/documents/queries/Publications.graphql:
--------------------------------------------------------------------------------
1 | query PublicationsByIds(
2 | $request: PublicationsQueryRequest!
3 | $reactionRequest: ReactionFieldResolverRequest
4 | $profileId: ProfileId
5 | ) {
6 | publications(request: $request) {
7 | items {
8 | ... on Post {
9 | ...PostFields
10 | }
11 | ... on Comment {
12 | ...CommentFields
13 | }
14 | ... on Mirror {
15 | ...MirrorFields
16 | }
17 | }
18 | pageInfo {
19 | next
20 | totalCount
21 | }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/utils/lens/documents/queries/RelevantPeople.graphql:
--------------------------------------------------------------------------------
1 | query RelevantPeople($request: ProfileQueryRequest!) {
2 | profiles(request: $request) {
3 | items {
4 | ...ProfileFields
5 | isFollowedByMe
6 | }
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/src/utils/lens/documents/queries/SearchProfiles.graphql:
--------------------------------------------------------------------------------
1 | query SearchProfiles($request: SearchQueryRequest!) {
2 | search(request: $request) {
3 | ... on ProfileSearchResult {
4 | items {
5 | ...ProfileFields
6 | }
7 | }
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/src/utils/lens/documents/queries/SearchPublications.graphql:
--------------------------------------------------------------------------------
1 | query SearchPublications(
2 | $request: SearchQueryRequest!
3 | $reactionRequest: ReactionFieldResolverRequest
4 | $profileId: ProfileId
5 | ) {
6 | search(request: $request) {
7 | ... on PublicationSearchResult {
8 | items {
9 | ... on Post {
10 | ...PostFields
11 | }
12 | ... on Comment {
13 | ...CommentFields
14 | }
15 | }
16 | pageInfo {
17 | next
18 | totalCount
19 | }
20 | }
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/src/utils/lens/documents/queries/Subscribers.graphql:
--------------------------------------------------------------------------------
1 | query Subscribers($request: FollowersRequest!) {
2 | followers(request: $request) {
3 | items {
4 | wallet {
5 | address
6 | defaultProfile {
7 | ...ProfileFields
8 | }
9 | }
10 | }
11 | pageInfo {
12 | next
13 | totalCount
14 | }
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/src/utils/lens/documents/queries/SuperFollow.graphql:
--------------------------------------------------------------------------------
1 | query SuperFollow($request: SingleProfileQueryRequest!) {
2 | profile(request: $request) {
3 | id
4 | followModule {
5 | ... on FeeFollowModuleSettings {
6 | amount {
7 | asset {
8 | name
9 | symbol
10 | decimals
11 | address
12 | }
13 | value
14 | }
15 | recipient
16 | }
17 | }
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/src/utils/lens/documents/queries/TxIdToTxHash.graphql:
--------------------------------------------------------------------------------
1 | query TxIdToTxHash($txId: TxId!) {
2 | txIdToTxHash(txId: $txId)
3 | }
4 |
--------------------------------------------------------------------------------
/src/utils/lens/documents/queries/UserProfiles.graphql:
--------------------------------------------------------------------------------
1 | query UserProfiles($request: ProfileQueryRequest!) {
2 | profiles(request: $request) {
3 | items {
4 | ...ProfileFields
5 | }
6 | }
7 | userSigNonces {
8 | lensHubOnChainSigNonce
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/src/utils/lens/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "lens",
3 | "version": "0.0.0",
4 | "main": "./generated.ts",
5 | "scripts": {
6 | "codegen": "graphql-codegen",
7 | "typecheck": "tsc --noEmit"
8 | },
9 | "dependencies": {
10 | "@apollo/client": "^3.7.1",
11 | "graphql": "^16.6.0"
12 | },
13 | "devDependencies": {
14 | "@graphql-codegen/cli": "2.16.1",
15 | "@graphql-codegen/fragment-matcher": "^3.3.1",
16 | "@graphql-codegen/typescript": "^2.8.2",
17 | "@graphql-codegen/typescript-operations": "^2.5.7",
18 | "@graphql-codegen/typescript-react-apollo": "^3.3.6",
19 | "prettier": "^2.8.1",
20 | "tsconfig": "*",
21 | "typescript": "^4.9.4",
22 | "@graphql-codegen/client-preset": "1.2.3"
23 | }
24 | }
--------------------------------------------------------------------------------
/src/utils/lens/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "https://json.schemastore.org/tsconfig",
3 | "display": "Default",
4 | "compilerOptions": {
5 | "composite": false,
6 | "declaration": true,
7 | "declarationMap": true,
8 | "esModuleInterop": true,
9 | "forceConsistentCasingInFileNames": true,
10 | "inlineSources": false,
11 | "isolatedModules": true,
12 | "moduleResolution": "node",
13 | "noUnusedLocals": false,
14 | "noUnusedParameters": false,
15 | "preserveWatchOutput": true,
16 | "skipLibCheck": true,
17 | "strict": true,
18 | "target": "es5",
19 | "lib": ["dom", "dom.iterable", "esnext"],
20 | "allowJs": true,
21 | "forceConsistentCasingInFileNames": true,
22 | "noEmit": true,
23 | "module": "esnext",
24 | "resolveJsonModule": true,
25 | "jsx": "preserve",
26 | "incremental": true,
27 | "baseUrl": ".",
28 | "noEmit": true
29 | },
30 | "exclude": ["node_modules", ".next", ".turbo"]
31 | }
--------------------------------------------------------------------------------
/src/utils/paths.ts:
--------------------------------------------------------------------------------
1 | export const HOME = '/'
2 | export const EXPLORE = '/explore'
3 | export const LATEST = '/latest'
4 | export const NOTIFICATIONS = '/notifications'
5 | export const MESSAGES = '/messages'
6 | export const SETTINGS = '/settings'
7 | export const PRIVACY = '/privacy'
8 | export const SEARCH = '/search'
9 | export const CREATE = '/create'
10 | export const CREATE_PIN = '/create/pin'
11 |
12 | export const DISCORD = '/discord'
13 |
14 | export const SETTINGS_INTERESTS = '/settings/interests'
15 | export const SETTINGS_PERMISSIONS = '/settings/permissions'
16 | export const SETTINGS_DANGER_ZONE = '/settings/danger'
--------------------------------------------------------------------------------
/tailwind.config.js:
--------------------------------------------------------------------------------
1 | /** @type {import('tailwindcss').Config} */
2 | const colors = require('tailwindcss/colors');
3 | module.exports = {
4 | mode: 'jit',
5 | content: ['./src/**/*.{js,ts,jsx,tsx}'],
6 | darkMode: 'class',
7 | theme: {
8 | extend: {
9 | colors: {
10 | gray: colors.zinc,
11 | green: colors.emerald,
12 | purple: colors.violet,
13 | yellow: colors.yellow,
14 | brand: colors.pink,
15 | },
16 | animation: {
17 | 'spin-slow': 'spin 3s linear infinite',
18 | }
19 | }
20 | },
21 | plugins: [],
22 | }
23 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "es2015",
4 | "lib": ["dom", "dom.iterable", "esnext"],
5 | "allowJs": true,
6 | "skipLibCheck": true,
7 | "strict": true,
8 | "forceConsistentCasingInFileNames": true,
9 | "noEmit": true,
10 | "esModuleInterop": true,
11 | "module": "esnext",
12 | "moduleResolution": "node",
13 | "resolveJsonModule": true,
14 | "isolatedModules": true,
15 | "jsx": "preserve",
16 | "incremental": true,
17 | "baseUrl": ".",
18 | "paths": {
19 | "@components*": ["src/components*"],
20 | "@hooks*": ["src/utils/hooks*"],
21 | "@pages*": ["src/pages*"],
22 | "@lib*": ["src/lib*"],
23 | "@ui*": ["src/components/ui*"],
24 | "@abis*": ["src/abis*"],
25 | "@gql*": ["src/gql*"],
26 | "@utils*": ["src/utils*"],
27 | "@data*": ["src/data*"]
28 | }
29 | },
30 | "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"],
31 | "exclude": ["node_modules"]
32 | }
33 |
--------------------------------------------------------------------------------