feat: showcase
This commit is contained in:
parent
d71a2c53a4
commit
7e0aafff19
2
LICENSE
2
LICENSE
|
|
@ -1,4 +1,4 @@
|
|||
Copyright (c) 2022-present Proselog.
|
||||
Copyright (c) 2022-present xLog.
|
||||
|
||||
Portions of this software are licensed as follows:
|
||||
|
||||
|
|
|
|||
|
|
@ -41,6 +41,7 @@
|
|||
"@trpc/next": "^9.27.2",
|
||||
"@trpc/react": "^9.27.2",
|
||||
"@trpc/server": "^9.27.2",
|
||||
"@urql/core": "^3.0.3",
|
||||
"@web-std/form-data": "^3.0.2",
|
||||
"async-busboy": "^1.1.0",
|
||||
"axios": "^0.27.2",
|
||||
|
|
|
|||
|
|
@ -51,6 +51,7 @@ specifiers:
|
|||
'@types/uuid': ^8.3.4
|
||||
'@unocss/cli': ^0.45.25
|
||||
'@unocss/preset-icons': ^0.45.25
|
||||
'@urql/core': ^3.0.3
|
||||
'@web-std/form-data': ^3.0.2
|
||||
async-busboy: ^1.1.0
|
||||
autoprefixer: ^10.4.12
|
||||
|
|
@ -153,6 +154,7 @@ dependencies:
|
|||
'@trpc/next': 9.27.2_dyodlyrl4jlccmeg4rab7q5slm
|
||||
'@trpc/react': 9.27.2_r3nohbkvzkycnbsdj5gzhfx2rm
|
||||
'@trpc/server': 9.27.2
|
||||
'@urql/core': 3.0.3
|
||||
'@web-std/form-data': 3.0.2
|
||||
async-busboy: 1.1.0
|
||||
axios: 0.27.2
|
||||
|
|
@ -1318,6 +1320,12 @@ packages:
|
|||
react-dom: 18.2.0_react@18.2.0
|
||||
dev: false
|
||||
|
||||
/@graphql-typed-document-node/core/3.1.1:
|
||||
resolution: {integrity: sha512-NQ17ii0rK1b34VZonlmT2QMJFI70m0TRwbknO/ihlbatXyaktDhN/98vBiUU6kNBPljqGqyIrl2T4nY2RpFANg==}
|
||||
peerDependencies:
|
||||
graphql: ^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0
|
||||
dev: false
|
||||
|
||||
/@graphql-typed-document-node/core/3.1.1_graphql@16.5.0:
|
||||
resolution: {integrity: sha512-NQ17ii0rK1b34VZonlmT2QMJFI70m0TRwbknO/ihlbatXyaktDhN/98vBiUU6kNBPljqGqyIrl2T4nY2RpFANg==}
|
||||
peerDependencies:
|
||||
|
|
@ -2774,6 +2782,15 @@ packages:
|
|||
wonka: 4.0.15
|
||||
dev: false
|
||||
|
||||
/@urql/core/3.0.3:
|
||||
resolution: {integrity: sha512-raQP51ERNtg5BvlN8x8mHVRvk4K0ugWQ69n53BdkjKpXVV5kuWp7trnwriGv1fQKa8HuiGNSCfyslUucc0OVQg==}
|
||||
peerDependencies:
|
||||
graphql: ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0
|
||||
dependencies:
|
||||
'@graphql-typed-document-node/core': 3.1.1
|
||||
wonka: 6.1.0
|
||||
dev: false
|
||||
|
||||
/@vanilla-extract/css/1.7.0:
|
||||
resolution: {integrity: sha512-2Abpr5aJskwKS+waMWxWnTBqq/rj4J93KtGteW0VSORMUsijrupwjOXECd7Llh+nSFfx/Y6usuexF5/ffyDF8A==}
|
||||
dependencies:
|
||||
|
|
@ -11096,6 +11113,10 @@ packages:
|
|||
resolution: {integrity: sha512-U0IUQHKXXn6PFo9nqsHphVCE5m3IntqZNB9Jjn7EB1lrR7YTDY3YWgFvEvwniTzXSvOH/XMzAZaIfJF/LvHYXg==}
|
||||
dev: false
|
||||
|
||||
/wonka/6.1.0:
|
||||
resolution: {integrity: sha512-VgiMCz7BXOiDbgpVhf5iNhK7hurteY5Jv0fDJewUkY0s4fbxQD2iKqfGxNXNTwp2v3bgT8QVu2l5H7YdkZ5WIA==}
|
||||
dev: false
|
||||
|
||||
/word-wrap/1.2.3:
|
||||
resolution: {integrity: sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,48 @@
|
|||
[
|
||||
"xlog",
|
||||
"diygod",
|
||||
"rss3",
|
||||
"crossbell-blog",
|
||||
"hey",
|
||||
"song",
|
||||
"atlas-thinking",
|
||||
"joshua",
|
||||
"jeff",
|
||||
"walter",
|
||||
"crossbell-io-updates",
|
||||
"xtao",
|
||||
"polebug",
|
||||
"pengchao",
|
||||
"boyuand",
|
||||
"lilo",
|
||||
"coolcat",
|
||||
"dao",
|
||||
"0x55f110395c844963b075674e2956eb414018a7a7",
|
||||
"139",
|
||||
"just1lovewrl",
|
||||
"kanikig",
|
||||
"coosir",
|
||||
"atryte",
|
||||
"qihangsun",
|
||||
"brucexx",
|
||||
"0x1",
|
||||
"duogeyu",
|
||||
"stone",
|
||||
"lastmelody",
|
||||
"12138",
|
||||
"isheep",
|
||||
"atryte",
|
||||
"henryqw",
|
||||
"whost",
|
||||
"twifag",
|
||||
"hominsu",
|
||||
"exodus-exodus",
|
||||
"zoo",
|
||||
"colojayce",
|
||||
"stars",
|
||||
"somehacker",
|
||||
"nss",
|
||||
"somehacker",
|
||||
"novonine",
|
||||
"nafidurmus"
|
||||
]
|
||||
|
|
@ -4,6 +4,8 @@ import unidata from "~/queries/unidata.server"
|
|||
import { renderPageContent } from "~/markdown"
|
||||
import { toGateway } from "~/lib/ipfs-parser"
|
||||
import type Unidata from "unidata.js"
|
||||
import { createClient } from "@urql/core"
|
||||
import axios from "axios"
|
||||
|
||||
export const checkSubdomain = async ({
|
||||
subdomain,
|
||||
|
|
@ -94,6 +96,72 @@ export const getSite = async (input: string, customUnidata?: Unidata) => {
|
|||
return site
|
||||
}
|
||||
|
||||
export const getSites = async (input: string[]) => {
|
||||
const client = createClient({
|
||||
url: "https://indexer.crossbell.io/v1/graphql",
|
||||
})
|
||||
const result = await client
|
||||
.query(
|
||||
`
|
||||
query getCharacters($identities: [String!], $limit: Int) {
|
||||
characters( where: { handle: { in: $identities } }, orderBy: [{ updatedAt: desc }], take: $limit ) {
|
||||
handle
|
||||
updatedAt
|
||||
notes {
|
||||
updatedAt
|
||||
}
|
||||
metadata {
|
||||
uri
|
||||
content
|
||||
}
|
||||
}
|
||||
}`,
|
||||
{
|
||||
identities: input,
|
||||
},
|
||||
)
|
||||
.toPromise()
|
||||
|
||||
await Promise.all(
|
||||
result.data?.characters?.map(async (site: any) => {
|
||||
if (!site?.metadata?.content && site?.metadata?.uri) {
|
||||
site.metadata.content = (
|
||||
await axios.get(
|
||||
toGateway(site?.metadata?.uri, {
|
||||
needRequestAtServerSide: true,
|
||||
}),
|
||||
{
|
||||
...(typeof window === "undefined" && {
|
||||
headers: {
|
||||
"User-Agent":
|
||||
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.0.0 Safari/537.36",
|
||||
},
|
||||
}),
|
||||
},
|
||||
)
|
||||
).data
|
||||
}
|
||||
site.metadata.content.name = site.metadata.content.name || site.handle
|
||||
|
||||
site.custom_domain =
|
||||
site.metadata?.content?.attributes?.find(
|
||||
(a: any) => a.trait_type === "xlog_custom_domain",
|
||||
)?.value || ""
|
||||
|
||||
site.updatedAt = [...site.notes, site]
|
||||
.map((i) => i.updatedAt)
|
||||
.sort()
|
||||
.pop()
|
||||
}),
|
||||
)
|
||||
|
||||
result.data?.characters?.sort((a: any, b: any) => {
|
||||
return b.updatedAt > a.updatedAt ? 1 : -1
|
||||
})
|
||||
|
||||
return result.data?.characters
|
||||
}
|
||||
|
||||
export const getSubscription = async (
|
||||
data: {
|
||||
userId: string
|
||||
|
|
|
|||
|
|
@ -16,10 +16,18 @@ import { GITHUB_LINK, APP_NAME, CSB_SCAN } from "~/lib/env"
|
|||
import { getSiteLink } from "~/lib/helpers"
|
||||
import { Link, Element } from "react-scroll"
|
||||
import { Image } from "~/components/ui/Image"
|
||||
import { dehydrate, QueryClient } from "@tanstack/react-query"
|
||||
import { prefetchGetSites } from "~/queries/site.server"
|
||||
import { useGetSites } from "~/queries/site"
|
||||
import showcase from "../../showcase.json"
|
||||
|
||||
export const getServerSideProps: GetServerSideProps = async (ctx) => {
|
||||
const queryClient = new QueryClient()
|
||||
await prefetchGetSites(showcase, queryClient)
|
||||
|
||||
return {
|
||||
props: {
|
||||
dehydratedState: dehydrate(queryClient),
|
||||
region: FLY_REGION,
|
||||
},
|
||||
}
|
||||
|
|
@ -30,6 +38,7 @@ export default function Home({ region }: { region: string | null }) {
|
|||
const { address } = useAccount()
|
||||
const { openConnectModal } = useConnectModal()
|
||||
const router = useRouter()
|
||||
const showcaseSites = useGetSites(showcase)
|
||||
|
||||
useEffect(() => {
|
||||
console.log("-> region", region)
|
||||
|
|
@ -99,60 +108,8 @@ export default function Home({ region }: { region: string | null }) {
|
|||
},
|
||||
]
|
||||
|
||||
const comparing = [
|
||||
"Only Controlled by Yourself",
|
||||
"Open Source",
|
||||
"Self-hosting",
|
||||
"Like Posts",
|
||||
"Comment Posts",
|
||||
"Custom Domain",
|
||||
"Custom CSS",
|
||||
"Navigation",
|
||||
"Pages",
|
||||
"Scheduled Publishing",
|
||||
]
|
||||
|
||||
const stars = [
|
||||
{
|
||||
username: "rss3",
|
||||
avartar: "bafkreigjinhazhgvqaj423fhuuev7ormzf5vsm4iu4vrx2zgk2l5nugm4m",
|
||||
},
|
||||
{
|
||||
username: "crossbell-blog",
|
||||
avartar: "bafkreic5k3zvarbsondfrowy7kpbj6xo7cj25hobksgileqbbupjvvmkoq",
|
||||
},
|
||||
{
|
||||
username: "diygod",
|
||||
avartar: "bafybeibefx2tyow77m2wcnsh5anaaxfy7ypxbcuapb52c4h255onqp72ye",
|
||||
},
|
||||
{
|
||||
username: "hey",
|
||||
avartar: "bafkreigfhmqizqi7jwg5sw522kwcqilq7m6g4mbicpyit4avezaztvovey",
|
||||
},
|
||||
{
|
||||
username: "song",
|
||||
avartar: "QmQArk2yEF9t2Ud7vbhMyAQu8DJnTzc3EduSm7rcF2LQv4",
|
||||
},
|
||||
{
|
||||
username: "atlas-thinking",
|
||||
avartar: "QmNks3cJWDXzG5WSBzTVv1regkhXhzChK6LhJYu1HiBLS2",
|
||||
},
|
||||
{
|
||||
username: "joshua",
|
||||
avartar: "QmTUYz29S5bMqozK2uyQ1Y91DZzka4PLjReAD7J2nkbLMN",
|
||||
},
|
||||
{
|
||||
username: "jeff",
|
||||
avartar: "QmdvVh2w375eVMfDmi9yb2hks1X3MDDEAbbJB7FH2FVKxd",
|
||||
},
|
||||
{
|
||||
username: "walter",
|
||||
avartar: "QmRXkowLwfqjMKZS41KrnjM6JjAG5eerGWyFbo6ZzB1uUD",
|
||||
},
|
||||
]
|
||||
|
||||
return (
|
||||
<MainLayout tabs={["Features", `Why ${APP_NAME}`]}>
|
||||
<MainLayout tabs={["Features", "Showcase"]}>
|
||||
<section>
|
||||
<div className="max-w-screen-lg px-5 mx-auto">
|
||||
<div className="h-screen w-full flex justify-center flex-col relative">
|
||||
|
|
@ -223,45 +180,57 @@ export default function Home({ region }: { region: string | null }) {
|
|||
))}
|
||||
</ul>
|
||||
</Element>
|
||||
<Element name={`Why ${APP_NAME}`}>
|
||||
<div className="pt-28 text-4xl font-bold">Why {APP_NAME}</div>
|
||||
<div className="text-xl mt-10 leading-normal">
|
||||
We believe freedom of expression is a universal right. In your
|
||||
long-form writing, you should be able to express your thoughts
|
||||
freely; without fear of your post being removed or censored.
|
||||
xLog ensures that whatever you write, it will be immutable and
|
||||
permanently stored.
|
||||
</div>
|
||||
<Element name="Showcase">
|
||||
<div className="pt-28 text-4xl font-bold">Showcase</div>
|
||||
<div className="my-10 text-zinc-500">
|
||||
Trusted by these awesome teams and geeks
|
||||
<ul className="mt-4 space-x-4">
|
||||
{stars.map((item) => (
|
||||
Discover these awesome teams and geeks (sorted by update time)
|
||||
<ul className="mt-4 grid grid-cols-2 md:grid-cols-3 gap-4">
|
||||
{showcaseSites.data?.map((site: any) => (
|
||||
<li
|
||||
className="inline-flex align-middle"
|
||||
key={item.username}
|
||||
className="inline-flex align-middle py-2"
|
||||
key={site.handle}
|
||||
>
|
||||
<UniLink
|
||||
href={getSiteLink({
|
||||
subdomain: item.username,
|
||||
})}
|
||||
className="w-14 h-14"
|
||||
href={
|
||||
site.custom_domain
|
||||
? `https://${site.custom_domain}`
|
||||
: getSiteLink({
|
||||
subdomain: site.handle,
|
||||
})
|
||||
}
|
||||
className="inline-flex align-middle w-full"
|
||||
>
|
||||
<Image
|
||||
className="rounded-full"
|
||||
src={`/_ipfs/${item.avartar}`}
|
||||
alt={item.username}
|
||||
width="56"
|
||||
height="56"
|
||||
></Image>
|
||||
<span className="w-14 h-14">
|
||||
<Image
|
||||
className="rounded-full"
|
||||
src={
|
||||
site.metadata.content?.avatars?.[0] ||
|
||||
"ipfs://bafkreiabgixxp63pg64moxnsydz7hewmpdkxxi3kdsa4oqv4pb6qvwnmxa"
|
||||
}
|
||||
alt={site.handle}
|
||||
width="56"
|
||||
height="56"
|
||||
></Image>
|
||||
</span>
|
||||
<span className="ml-4 min-w-0 flex-1">
|
||||
<span className="truncate w-full inline-block">
|
||||
{site.metadata.content?.name}
|
||||
</span>
|
||||
{site.metadata.content?.bio && (
|
||||
<span className="text-gray-500 text-xs truncate w-full inline-block">
|
||||
{site.metadata.content?.bio}
|
||||
</span>
|
||||
)}
|
||||
</span>
|
||||
</UniLink>
|
||||
</li>
|
||||
))}
|
||||
<li className="inline-flex h-5 align-middle items-center">
|
||||
<li className="inline-flex h-full align-middle items-center">
|
||||
<UniLink
|
||||
className="inline-block"
|
||||
href="https://github.com/Crossbell-Box/xLog/issues/new"
|
||||
className="inline-block text-accent text-center pl-2"
|
||||
href="https://github.com/Crossbell-Box/xLog/edit/dev/showcase.json"
|
||||
>
|
||||
<EllipsisHorizontalIcon className="w-14 h-4" />
|
||||
Submit yours
|
||||
</UniLink>
|
||||
</li>
|
||||
</ul>
|
||||
|
|
|
|||
|
|
@ -28,3 +28,13 @@ export const prefetchGetSiteSubscriptions = async (
|
|||
return cacheGet(key, () => siteModel.getSiteSubscriptions(input))
|
||||
})
|
||||
}
|
||||
|
||||
export const prefetchGetSites = async (
|
||||
input: string[],
|
||||
queryClient: QueryClient,
|
||||
) => {
|
||||
const key = ["getSites", input]
|
||||
return await queryClient.fetchQuery(key, async () => {
|
||||
return cacheGet(key, () => siteModel.getSites(input))
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,6 +22,15 @@ export const useGetSite = (input: string) => {
|
|||
})
|
||||
}
|
||||
|
||||
export const useGetSites = (input: string[]) => {
|
||||
return useQuery(["getSites", input], async () => {
|
||||
if (!input) {
|
||||
return null
|
||||
}
|
||||
return siteModel.getSites(input)
|
||||
})
|
||||
}
|
||||
|
||||
export const useGetSubscription = (data: {
|
||||
userId: string
|
||||
siteId: string
|
||||
|
|
|
|||
Loading…
Reference in New Issue