Skip to content

Commit

Permalink
šŸ¤šŸ’ø ā† Adding more profile contents & updating styling for Lens frontenā€¦
Browse files Browse the repository at this point in the history
ā€¦d (and defining some new roles for #16 backend)

Check out the Notion documentation here: https://skinetics.notion.site/Lens-posting-a07f0e9c243249c0a3517e4160874137

Currently having a bit of a problem with determining the method we'll use to define proposal parameters, but I've come up with a fallback solution (i.e. using bots & comments) for the MVP. Potentially these "comments" could also be stored off-Lens but still be visible on the frontend (problem here is if you're looking at the proposals from an alternate client), bringing the Discord integration further into the limelight (using DeWork.xyz as the intermediary bot), as well as highlighting a real usecase/benefit to having both Supabase & Moralis as the data stores. Hopefully the metadata standards for publications are just as loose as with the `appId` standard on lens, as we'll just be able to create dummy metadata that is saved to the IPFS publication URI and therefore callable via graphql.

So overall, a lot of questions coming up, but some UI improvements as well as some more read interactivity for the client...
  • Loading branch information
Gizmotronn committed Jan 3, 2023
1 parent 7818816 commit 9023612
Show file tree
Hide file tree
Showing 12 changed files with 396 additions and 48 deletions.
54 changes: 31 additions & 23 deletions Server/frontend/components/FeedPost.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,37 +3,45 @@ import Link from 'next/link';
import React from 'react';
import { ExplorePublicationsQuery } from '../graphql/generated';
import styles from '../styles/FeedPost.module.css';
import { useComments } from '@lens-protocol/react';

type Props = {
publication: ExplorePublicationsQuery["explorePublications"]["items"][0];
}

export default function FeedPost ({publication}: Props) {
return (
<div className={styles.feedPostContainer}>
<div className={styles.feedPostHeader}>
<MediaRenderer
// @ts-ignore
src={publication?.profile?.picture?.original?.url}
alt={publication.profile.name || publication.profile.handle}
className={styles.feedPostProfilePicture}
/>
<Link href={`/profile/${publication.profile.handle}`} className={styles.feedPostProfileName}>
{publication.profile.name || publication.profile.handle}
</Link>
</div>
<div className={styles.feedPostContent}>
<h3 className={styles.feedPostContentTitle}>{publication.metadata.name}</h3>
<p className={styles.feedPostContentDescription}>{publication.metadata.content}</p>
var postId = publication.id;

{ publication.metadata.media?.length > 0 && (
return (
<div className={styles.feedPostContainer}>
<div className={styles.feedPostHeader}>
<MediaRenderer
src={publication.metadata.media[0].original.url}
alt={publication.metadata.name || ""}
className={styles.feedPostContentImage}
// @ts-ignore
src={publication?.profile?.picture?.original?.url || ""}
alt={publication.profile.name || publication.profile.handle}
className={styles.feedPostProfilePicture}
/>
)}
<Link href={`/profile/${publication.profile.handle}`} className={styles.feedPostProfileName}>
{publication.profile.name || publication.profile.handle}
</Link>
</div>
<div className={styles.feedPostContent}>
<h3 className={styles.feedPostContentTitle}>{publication.metadata.name}</h3>
<p className={styles.feedPostContentDescription}>{publication.metadata.content}</p>

{ publication.metadata.media?.length > 0 && (
<MediaRenderer
src={publication.metadata.media[0].original.url}
alt={publication.metadata.name || ""}
className={styles.feedPostContentImage}
/>
)}
</div>
<div className={styles.feedPostFooter}>
<p>{publication.stats.totalAmountOfCollects} Collects</p>
<p>{publication.stats.totalAmountOfComments} Comments</p>
<p>{publication.stats.totalAmountOfMirrors} Mirrors</p>
</div>
</div>
</div>
);
);
};
17 changes: 17 additions & 0 deletions Server/frontend/components/Header.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import Link from "next/link";
import React from "react";
import styles from '../styles/Header.module.css';
import SignInButton from "./SignInButton";

export default function Header () {
return (
<div className={styles.headerContainer}>
<div>
<Link href={'/'}>
<img src="/logo.png" alt='logo' />
</Link>
</div>
<SignInButton />
</div>
)
}
33 changes: 33 additions & 0 deletions Server/frontend/graphql/comment.graphql
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
mutation createCommentTypedData($request: CreatePublicCommentRequest!) {
createCommentTypedData(request: $request) {
id
expiresAt
typedData {
types {
CommentWithSig {
name
type
}
}
domain {
name
chainId
version
verifyingContract
}
value {
nonce
deadline
profileId
profileIdPointed
pubIdPointed
contentURI
collectModule
collectModuleInitData
referenceModule
referenceModuleInitData
referenceModuleData
}
}
}
}
51 changes: 51 additions & 0 deletions Server/frontend/graphql/generated.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3858,6 +3858,13 @@ export type ChallengeQueryVariables = Exact<{

export type ChallengeQuery = { __typename?: 'Query', challenge: { __typename?: 'AuthChallengeResult', text: string } };

export type CreateCommentTypedDataMutationVariables = Exact<{
request: CreatePublicCommentRequest;
}>;


export type CreateCommentTypedDataMutation = { __typename?: 'Mutation', createCommentTypedData: { __typename?: 'CreateCommentBroadcastItemResult', id: any, expiresAt: any, typedData: { __typename?: 'CreateCommentEIP712TypedData', types: { __typename?: 'CreateCommentEIP712TypedDataTypes', CommentWithSig: Array<{ __typename?: 'EIP712TypedDataField', name: string, type: string }> }, domain: { __typename?: 'EIP712TypedDataDomain', name: string, chainId: any, version: string, verifyingContract: any }, value: { __typename?: 'CreateCommentEIP712TypedDataValue', nonce: any, deadline: any, profileId: any, profileIdPointed: any, pubIdPointed: any, contentURI: any, collectModule: any, collectModuleInitData: any, referenceModule: any, referenceModuleInitData: any, referenceModuleData: any } } } };

export type MediaFieldsFragment = { __typename?: 'Media', url: any, width?: number | null, height?: number | null, mimeType?: any | null };

export type ProfileFieldsFragment = { __typename?: 'Profile', id: any, name?: string | null, bio?: string | null, isFollowedByMe: boolean, isFollowing: boolean, followNftAddress?: any | null, metadata?: any | null, isDefault: boolean, handle: any, ownedBy: any, attributes?: Array<{ __typename?: 'Attribute', displayType?: string | null, traitType?: string | null, key: string, value: string }> | null, picture?: { __typename?: 'MediaSet', original: { __typename?: 'Media', url: any, width?: number | null, height?: number | null, mimeType?: any | null }, small?: { __typename?: 'Media', url: any, width?: number | null, height?: number | null, mimeType?: any | null } | null, medium?: { __typename?: 'Media', url: any, width?: number | null, height?: number | null, mimeType?: any | null } | null } | { __typename?: 'NftImage', contractAddress: any, tokenId: string, uri: any, verified: boolean } | null, coverPicture?: { __typename?: 'MediaSet', original: { __typename?: 'Media', url: any, width?: number | null, height?: number | null, mimeType?: any | null }, small?: { __typename?: 'Media', url: any, width?: number | null, height?: number | null, mimeType?: any | null } | null, medium?: { __typename?: 'Media', url: any, width?: number | null, height?: number | null, mimeType?: any | null } | null } | { __typename?: 'NftImage', contractAddress: any, tokenId: string, uri: any, verified: boolean } | null, dispatcher?: { __typename?: 'Dispatcher', address: any, canUseRelay: boolean } | null, stats: { __typename?: 'ProfileStats', totalFollowers: number, totalFollowing: number, totalPosts: number, totalComments: number, totalMirrors: number, totalPublications: number, totalCollects: number }, followModule?: { __typename?: 'FeeFollowModuleSettings', type: FollowModules, recipient: any, amount: { __typename?: 'ModuleFeeAmount', value: string, asset: { __typename?: 'Erc20', name: string, symbol: string, decimals: number, address: any } } } | { __typename?: 'ProfileFollowModuleSettings', type: FollowModules, contractAddress: any } | { __typename?: 'RevertFollowModuleSettings', type: FollowModules, contractAddress: any } | { __typename?: 'UnknownFollowModuleSettings', type: FollowModules, contractAddress: any, followModuleReturnData: any } | null, onChainIdentity: { __typename?: 'OnChainIdentity', proofOfHumanity: boolean, ens?: { __typename?: 'EnsOnChainIdentity', name?: any | null } | null, sybilDotOrg: { __typename?: 'SybilDotOrgIdentity', verified: boolean, source: { __typename?: 'SybilDotOrgIdentitySource', twitter: { __typename?: 'SybilDotOrgTwitterIdentity', handle?: string | null } } }, worldcoin: { __typename?: 'WorldcoinIdentity', isHuman: boolean } } };
Expand Down Expand Up @@ -4613,6 +4620,50 @@ export const useChallengeQuery = <
fetcher<ChallengeQuery, ChallengeQueryVariables>(ChallengeDocument, variables),
options
);
export const CreateCommentTypedDataDocument = `
mutation createCommentTypedData($request: CreatePublicCommentRequest!) {
createCommentTypedData(request: $request) {
id
expiresAt
typedData {
types {
CommentWithSig {
name
type
}
}
domain {
name
chainId
version
verifyingContract
}
value {
nonce
deadline
profileId
profileIdPointed
pubIdPointed
contentURI
collectModule
collectModuleInitData
referenceModule
referenceModuleInitData
referenceModuleData
}
}
}
}
`;
export const useCreateCommentTypedDataMutation = <
TError = unknown,
TContext = unknown
>(options?: UseMutationOptions<CreateCommentTypedDataMutation, TError, CreateCommentTypedDataMutationVariables, TContext>) =>
useMutation<CreateCommentTypedDataMutation, TError, CreateCommentTypedDataMutationVariables, TContext>(
['createCommentTypedData'],
(variables?: CreateCommentTypedDataMutationVariables) => fetcher<CreateCommentTypedDataMutation, CreateCommentTypedDataMutationVariables>(CreateCommentTypedDataDocument, variables)(),
options
);
export const ExplorePublicationsDocument = `
query ExplorePublications($request: ExplorePublicationRequest!) {
explorePublications(request: $request) {
Expand Down
1 change: 1 addition & 0 deletions Server/frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
},
"dependencies": {
"@apollo/client": "^3.7.3",
"@lens-protocol/react": "^0.1.1",
"@supabase/supabase-js": "^2.2.2",
"@tanstack/react-query": "^4.20.4",
"@thirdweb-dev/auth": "^2.0.38",
Expand Down
11 changes: 7 additions & 4 deletions Server/frontend/pages/index.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
import FeedPost from "../components/FeedPost";
import SignInButton from "../components/SignInButton";
import { PublicationSortCriteria, useExplorePublicationsQuery } from "../graphql/generated";
import { PublicationMainFocus, PublicationSortCriteria, useExplorePublicationsQuery } from "../graphql/generated";
import styles from '../styles/Home.module.css';

export default function Home () {
const { isLoading, error, data } = useExplorePublicationsQuery({
request: {
sortCriteria: PublicationSortCriteria.TopCollected,
metadata: {
//mainContentFocus: PublicationSortCriteria.Latest,
}
},
},
{
Expand All @@ -24,10 +27,10 @@ export default function Home () {

return (
<div className={styles.container}>
<div className={styles.postContainer}>
<div className={styles.postsContainer}>
{data?.explorePublications.items.map((publication) => (
<FeedPost publication={publication} key={publication.id} />
))};
<FeedPost publication={publication} key={publication.id} />
))}
</div>
</div>
);
Expand Down
43 changes: 39 additions & 4 deletions Server/frontend/pages/profile/[id].tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import { MediaRenderer } from '@thirdweb-dev/react';
import { useRouter } from 'next/router';
import React from 'react';
import FeedPost from '../../components/FeedPost';
import { useProfileQuery, usePublicationsQuery } from '../../graphql/generated';
import styles from '../../styles/Profile.module.css';

Expand All @@ -8,29 +10,62 @@ type Props = {}
export default function ProfilePage({}: Props) {
const router = useRouter();
const { id } = router.query;
const { isLoading: loadingProfile, data: profileData } = useProfileQuery({
const { isLoading: loadingProfile, data: profileData, error: profileError } = useProfileQuery({
request: {
handle: id,
},
}, {
enabled: !!id,
});

const { isLoading: isLoadingPublications, data: publicationsData } = usePublicationsQuery({
const { isLoading: isLoadingPublications, data: publicationsData, error: publicationsError } = usePublicationsQuery({
request: {
profileId: profileData?.profile?.id
},
}, {
enabled: !!profileData?.profile?.id,
});

if (publicationsError || profileError) {
return <div>Couldn't find this profile</div>;
}

if (loadingProfile) {
return <div>Loading profile...</div>
}

return (
<div className={styles.profileContainer}>
<div className={styles.profileContentContainer}>

{/* @ts-ignore */}
{profileData?.profile?.coverPicture?.original?.url && (
<MediaRenderer
// @ts-ignore
src={profileData?.profile?.coverPicture?.original?.url || ""}
alt={profileData.profile.name || profileData.profile.handle || ""}
className={styles.coverImageContainer}
/>
)}
{/* @ts-ignore */}
{profileData?.profile?.picture?.original?.url && (
<MediaRenderer
// @ts-ignore
src={profileData.profile.picture.original.url}
alt={profileData.profile.name || profileData.profile.handle || ""}
className={styles.profilePictureContainer}
/>
)}
<h1 className={styles.profileName}>{profileData?.profile?.name || 'Unknown user'}</h1>
<p className={styles.profileHandle}>{profileData?.profile?.handle}</p>
<p className={styles.profileDescription}>{profileData?.profile?.bio}</p>
<p className={styles.followerCount}>{profileData?.profile?.stats.totalFollowers} Followers</p>
</div>
<div className={styles.publicationsContainer}>

{
publicationsData?.publications.items.map((publication) => (
<FeedPost publication={publication} key={publication.id} />
))
}
</div>
</div>
)
Expand Down
8 changes: 7 additions & 1 deletion Server/frontend/styles/FeedPost.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,9 @@
}

.feedPostProfilePicture {
border-radius: 50%;
width: 48px;
height: 48px;
border-radius: 50%;
border: 1px solid black;
}

Expand All @@ -45,4 +45,10 @@
.feedPostContentDescription {
font-size: 16px;
font-weight: 400;
}

.feedPostFooter {
display: flex;
flex-direction: row;
gap: 16px;
}
6 changes: 6 additions & 0 deletions Server/frontend/styles/Header.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
.headerContainer {
height: 64px;
display: flex;
flex-direction: center;
justify-content: space-between;
}
42 changes: 42 additions & 0 deletions Server/frontend/styles/Profile.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
.profileContainer {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 1rem;
margin: 1rem;
border-radius: 10px;
box-shadow: 0 0 14px rgba(0, 0, 0, 0.02), 0 5px 5px rgba(0, 0, 0, 0.04);
}

.profileContentContainer {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
max-width: 800px;
}

.coverImageContainer {
width: 100%;
height: 256px;
border-radius: 10px;
object-fit: cover;
}

.profilePictureContainer {
width: 128px;
height: 128px;
border-radius: 50%;
object-fit: cover;
}

.profileHandle {
font-size: 1.5rem;
opacity: 0.7;
}

.followerCount {
margin-top: 32px;
margin-bottom: 32px;
}
Loading

0 comments on commit 9023612

Please sign in to comment.