-
Notifications
You must be signed in to change notification settings - Fork 27
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* initial generating of images for open graph / x posts. need ttf font for this generator not woof woof * wip generated images * gvoernance proposal image * drop the the its cleaner * generating * moved validators component * unused * do we need this? * rename font * fetch names and logos for validators and delegates * test open graph * work on getting stuff to show on twitter * cant use with use Client * does this work? * move components to new file so we can have server rendered head content * move proposal components out of app folder * refactor staking validator page so that the "use client" is not use top level * dynamc og title for staking * pages render on server * uniform mondo logo width/size show x names in the twitter metadata. use short address for twitter titles delegatees page metadata show fallback image on more pages * deadcode add delegate reg image * use large summary cards --------- Co-authored-by: Leszek Stachowski <leszek.stachowski@clabs.co>
- Loading branch information
Showing
30 changed files
with
1,171 additions
and
678 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,6 @@ | ||
/// <reference types="next" /> | ||
/// <reference types="next/image-types/global" /> | ||
/// <reference types="next/navigation-types/compat/navigation" /> | ||
|
||
// NOTE: This file should not be edited | ||
// see https://nextjs.org/docs/app/building-your-application/configuring/typescript for more information. |
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
the Alpina ttf here is for use in generating ImageResponse for opengraph images. | ||
|
||
more alpina woff files are found in src/styles which are used in the app itself |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
import { FallBack, OpenGraphImage } from 'src/app/twitter-image'; | ||
|
||
export { contentType, size } from 'src/app/twitter-image'; | ||
export const runtime = 'edge'; | ||
|
||
export const alt = 'Celo Mondo | Account'; | ||
export default function Image() { | ||
return OpenGraphImage({ children: <FallBack /> }); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
import { FallBack, OpenGraphImage } from 'src/app/twitter-image'; | ||
|
||
export { contentType, size } from 'src/app/twitter-image'; | ||
export const runtime = 'edge'; | ||
|
||
export const alt = 'Celo Mondo | Bridges'; | ||
export default function Image() { | ||
return OpenGraphImage({ children: <FallBack /> }); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,137 +1,31 @@ | ||
'use client'; | ||
|
||
import { useMemo } from 'react'; | ||
import { FullWidthSpinner, SpinnerWithLabel } from 'src/components/animation/Spinner'; | ||
import { BackLink } from 'src/components/buttons/BackLink'; | ||
import { Section } from 'src/components/layout/Section'; | ||
import { SocialLogoLink } from 'src/components/logos/SocialLogo'; | ||
import { CollapsibleResponsiveMenu } from 'src/components/menus/CollapsibleResponsiveMenu'; | ||
import { ShortAddress } from 'src/components/text/ShortAddress'; | ||
import { SocialLinkType } from 'src/config/types'; | ||
import { DelegateButton } from 'src/features/delegation/components/DelegateButton'; | ||
import { DelegateeLogo } from 'src/features/delegation/components/DelegateeLogo'; | ||
import { DelegatorsTable } from 'src/features/delegation/components/DelegatorsTable'; | ||
import { useDelegateeHistory } from 'src/features/delegation/hooks/useDelegateeHistory'; | ||
import { useDelegatees } from 'src/features/delegation/hooks/useDelegatees'; | ||
import { Delegatee } from 'src/features/delegation/types'; | ||
import { ProposalCard } from 'src/features/governance/components/ProposalCard'; | ||
import { useGovernanceProposals } from 'src/features/governance/hooks/useGovernanceProposals'; | ||
import { VoteTypeToIcon } from 'src/features/governance/types'; | ||
import { getLargestVoteType } from 'src/features/governance/utils'; | ||
import { usePageInvariant } from 'src/utils/navigation'; | ||
|
||
// DO NOT USE "use client" here as it breaks metadata for openGraph | ||
import DelegatePage from 'src/features/delegation/components/delegatePage'; | ||
import { getDelegateeMetadata } from 'src/features/delegation/delegateeMetadata'; | ||
import { getXName } from 'src/features/delegation/utils'; | ||
import { shortenAddress } from 'src/utils/addresses'; | ||
export const dynamicParams = true; | ||
|
||
export default function Page({ params: { address } }: { params: { address: Address } }) { | ||
const { addressToDelegatee } = useDelegatees(); | ||
const delegatee = addressToDelegatee?.[address]; | ||
|
||
usePageInvariant(!addressToDelegatee || delegatee, '/delegate', 'Delegate not found'); | ||
|
||
if (!addressToDelegatee || !delegatee) { | ||
return <FullWidthSpinner>Loading delegate data</FullWidthSpinner>; | ||
} | ||
|
||
return ( | ||
<Section containerClassName="mt-4 lg:flex lg:gap-6 lg:items-start"> | ||
<DelegateeDescription delegatee={delegatee} /> | ||
<CollapsibleResponsiveMenu> | ||
<DelegateeDetails delegatee={delegatee} /> | ||
</CollapsibleResponsiveMenu> | ||
</Section> | ||
); | ||
} | ||
|
||
function DelegateeDescription({ delegatee }: { delegatee: Delegatee }) { | ||
const dateString = new Date(delegatee.date).toLocaleDateString(); | ||
|
||
return ( | ||
<div className="space-y-4"> | ||
<BackLink href="/delegate">Browse delegates</BackLink> | ||
<div className="flex items-center gap-1"> | ||
<DelegateeLogo address={delegatee.address} size={90} /> | ||
<div className="ml-4 flex flex-col"> | ||
<h1 className="font-serif text-2xl md:text-3xl">{delegatee.name}</h1> | ||
<div className="flex items-center space-x-2"> | ||
<ShortAddress | ||
address={delegatee.address} | ||
className="font-mono text-sm text-taupe-600" | ||
/> | ||
<span className="text-sm text-taupe-600">•</span> | ||
<span className="text-sm text-taupe-600">{`Since ${dateString}`}</span> | ||
</div> | ||
<div className="mt-1.5 flex items-center space-x-3"> | ||
{Object.entries(delegatee.links).map(([type, href], i) => ( | ||
<SocialLogoLink key={i} type={type as SocialLinkType} href={href} /> | ||
))} | ||
{delegatee.interests.map((interest, i) => ( | ||
<span | ||
key={i} | ||
className="hidden rounded-full border border-taupe-300 px-2 text-sm sm:block" | ||
> | ||
{interest} | ||
</span> | ||
))} | ||
</div> | ||
</div> | ||
</div> | ||
<h2 className="font-serif text-xl">Introduction</h2> | ||
<p style={{ maxWidth: 'min(96vw, 700px)' }} className="overflow-auto leading-relaxed"> | ||
{delegatee.description} | ||
</p> | ||
<GovernanceParticipation delegatee={delegatee} /> | ||
</div> | ||
); | ||
} | ||
|
||
function GovernanceParticipation({ delegatee }: { delegatee: Delegatee }) { | ||
const { proposalToVotes, isLoading: isLoadingHistory } = useDelegateeHistory(delegatee.address); | ||
const { proposals, isLoading: isLoadingProposals } = useGovernanceProposals(); | ||
|
||
const isLoading = isLoadingHistory || isLoadingProposals; | ||
const sortedIds = useMemo( | ||
() => | ||
Object.keys(proposalToVotes || {}) | ||
.map((p) => parseInt(p)) | ||
.sort((a, b) => b - a), | ||
[proposalToVotes], | ||
); | ||
const hasVotes = proposalToVotes && sortedIds.length > 0; | ||
|
||
return ( | ||
<div className="flex flex-col space-y-2.5 divide-y border-taupe-300 py-1"> | ||
<h2 className="font-serif text-xl">Governance Participation</h2> | ||
{isLoading ? ( | ||
<SpinnerWithLabel className="py-10">Loading governance history</SpinnerWithLabel> | ||
) : proposals && hasVotes ? ( | ||
sortedIds.map((id, i) => { | ||
const votes = proposalToVotes[id]; | ||
const proposal = proposals.find((p) => p.id === id); | ||
if (!proposal) return null; | ||
const { type } = getLargestVoteType(votes); | ||
return ( | ||
<div key={i} className="pt-2.5"> | ||
<ProposalCard propData={proposal} isCompact={true} /> | ||
<div className="mt-1.5 text-sm">{`Voted ${type} ${VoteTypeToIcon[type]}`}</div> | ||
</div> | ||
); | ||
}) | ||
) : ( | ||
<p className="text-gray-600">This delegate has not voted for governance proposals yet</p> | ||
)} | ||
</div> | ||
); | ||
export type DelegateParams = { params: { address: Address } }; | ||
|
||
export async function generateMetadata({ params: { address } }: DelegateParams) { | ||
const metadata = getDelegateeMetadata(); | ||
|
||
const data = metadata[address]; | ||
|
||
return { | ||
openGraph: { | ||
title: `${data.name} - ${shortenAddress(address)}`, | ||
description: `Delegate to ${data.name} | ${address}`, | ||
}, | ||
twitter: { | ||
title: shortenAddress(address), | ||
creator: getXName(data), | ||
site: '@celo', | ||
card: 'summary_large_image', | ||
}, | ||
}; | ||
} | ||
|
||
function DelegateeDetails({ delegatee }: { delegatee: Delegatee }) { | ||
return ( | ||
<div className="space-y-4 lg:w-[330px] lg:min-w-[20rem]"> | ||
<div className="border-taupe-300 p-3 lg:border"> | ||
<DelegateButton delegatee={delegatee} /> | ||
</div> | ||
<div className="hidden border-taupe-300 p-3 lg:block lg:border"> | ||
<DelegatorsTable delegatee={delegatee} /> | ||
</div> | ||
</div> | ||
); | ||
export default function Page({ params: { address } }: DelegateParams) { | ||
return <DelegatePage address={address} />; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
import { OpenGraphImage } from 'src/app/twitter-image'; | ||
import { Background } from 'src/components/open-graph/Background'; | ||
import { MondoWithSubText } from 'src/components/open-graph/MondoLogo'; | ||
import { Portrait } from 'src/components/open-graph/Portrait'; | ||
import { getDelegateeMetadata } from 'src/features/delegation/delegateeMetadata'; | ||
|
||
export { contentType, size } from 'src/app/twitter-image'; | ||
|
||
export const alt = 'Delegate'; | ||
|
||
export default function Image({ params: { address } }: { params: { address: Address } }) { | ||
const metadata = getDelegateeMetadata(); | ||
|
||
const { name, logoUri } = metadata[address]; | ||
|
||
return OpenGraphImage({ children: <Delgatee name={name} address={address} logoUri={logoUri} /> }); | ||
} | ||
|
||
function Delgatee({ name, logoUri, address }: { name: string; address: Address; logoUri: string }) { | ||
return ( | ||
<Background direction="h"> | ||
<MondoWithSubText baseSize={40} subText="Delegate" /> | ||
<Portrait name={name} relativeImage={logoUri} address={address} /> | ||
</Background> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
import { OpenGraphImage } from 'src/app/twitter-image'; | ||
import { BasePage } from 'src/components/open-graph/BasePage'; | ||
export { contentType, size } from 'src/app/twitter-image'; | ||
export const runtime = 'edge'; | ||
|
||
export const alt = 'Delegate Registration'; | ||
export default function Image() { | ||
return OpenGraphImage({ children: <BasePage title="Become a Delegate" /> }); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
import { OpenGraphImage } from 'src/app/twitter-image'; | ||
import { BasePage } from 'src/components/open-graph/BasePage'; | ||
export { contentType, size } from 'src/app/twitter-image'; | ||
export const runtime = 'edge'; | ||
|
||
export const alt = 'Delegate'; | ||
export default function Image() { | ||
return OpenGraphImage({ children: <BasePage title="Delegate" /> }); | ||
} |
Oops, something went wrong.