feat: import from mirror.xyz
This commit is contained in:
parent
737c2b8411
commit
07a2336450
|
|
@ -259,7 +259,6 @@ textarea.input {
|
|||
@apply mb-2;
|
||||
@apply font-bold;
|
||||
@apply text-gray-700;
|
||||
@apply capitalize;
|
||||
}
|
||||
|
||||
.post-status-circle {
|
||||
|
|
|
|||
|
|
@ -0,0 +1,24 @@
|
|||
import { NextApiRequest, NextApiResponse } from "next"
|
||||
|
||||
export default async function handler(
|
||||
req: NextApiRequest,
|
||||
res: NextApiResponse,
|
||||
) {
|
||||
const { address } = req.query
|
||||
|
||||
const result = await (
|
||||
await fetch("https://mirror.xyz/api/graphql", {
|
||||
headers: {
|
||||
"content-type": "application/json",
|
||||
Referer: `https://mirror.xyz/${address}/`,
|
||||
origin: "https://mirror.xyz",
|
||||
"user-agent":
|
||||
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/110.0.0.0 Safari/537.36",
|
||||
},
|
||||
body: `{"operationName":"ProjectPage","variables":{"projectAddress":"${address}","limit":9},"query":"query ProjectPage($projectAddress: String\u0021, $limit: Int, $cursor: Int) {\\n projectFeed(projectAddress: $projectAddress, limit: $limit, cursor: $cursor) {\\n _id\\n domain\\n ens\\n theme {\\n accent\\n colorMode\\n __typename\\n }\\n displayName\\n ens\\n address\\n ...projectPage\\n ...publicationLayoutProject\\n __typename\\n }\\n}\\n\\nfragment projectPage on ProjectType {\\n _id\\n address\\n avatarURL\\n description\\n displayName\\n domain\\n ens\\n theme {\\n accent\\n colorMode\\n __typename\\n }\\n headerImage {\\n id\\n url\\n __typename\\n }\\n posts {\\n ... on crowdfund {\\n _id\\n id\\n __typename\\n }\\n ... on entry {\\n _id\\n id\\n body\\n digest\\n title\\n publishedAtTimestamp\\n writingNFT {\\n _id\\n optimisticNumSold\\n proxyAddress\\n purchases {\\n numSold\\n __typename\\n }\\n __typename\\n }\\n featuredImage {\\n mimetype\\n url\\n __typename\\n }\\n publisher {\\n ...publisherDetails\\n __typename\\n }\\n settings {\\n ...entrySettingsDetails\\n __typename\\n }\\n __typename\\n }\\n ... on SubscriberEditionType {\\n _id\\n __typename\\n }\\n __typename\\n }\\n __typename\\n}\\n\\nfragment publisherDetails on PublisherType {\\n project {\\n ...projectDetails\\n __typename\\n }\\n member {\\n ...projectDetails\\n __typename\\n }\\n __typename\\n}\\n\\nfragment projectDetails on ProjectType {\\n _id\\n address\\n avatarURL\\n description\\n displayName\\n domain\\n ens\\n gaTrackingID\\n mailingListURL\\n headerImage {\\n ...mediaAsset\\n __typename\\n }\\n theme {\\n ...themeDetails\\n __typename\\n }\\n __typename\\n}\\n\\nfragment mediaAsset on MediaAssetType {\\n id\\n cid\\n mimetype\\n sizes {\\n ...mediaAssetSizes\\n __typename\\n }\\n url\\n __typename\\n}\\n\\nfragment mediaAssetSizes on MediaAssetSizesType {\\n og {\\n ...mediaAssetSize\\n __typename\\n }\\n lg {\\n ...mediaAssetSize\\n __typename\\n }\\n md {\\n ...mediaAssetSize\\n __typename\\n }\\n sm {\\n ...mediaAssetSize\\n __typename\\n }\\n __typename\\n}\\n\\nfragment mediaAssetSize on MediaAssetSizeType {\\n src\\n height\\n width\\n __typename\\n}\\n\\nfragment themeDetails on UserProfileThemeType {\\n accent\\n colorMode\\n __typename\\n}\\n\\nfragment entrySettingsDetails on EntrySettingsType {\\n description\\n metaImage {\\n ...mediaAsset\\n __typename\\n }\\n title\\n __typename\\n}\\n\\nfragment publicationLayoutProject on ProjectType {\\n _id\\n avatarURL\\n displayName\\n domain\\n address\\n ens\\n gaTrackingID\\n mailingListURL\\n description\\n __typename\\n}\\n"}`,
|
||||
method: "POST",
|
||||
})
|
||||
).json()
|
||||
|
||||
res.status(200).json(result)
|
||||
}
|
||||
|
|
@ -41,7 +41,7 @@ export default function ImportPage() {
|
|||
|
||||
return (
|
||||
<DashboardMain title="Import">
|
||||
<div className="min-w-[270px] flex flex-col space-y-4">
|
||||
<div className="min-w-[270px] max-w-screen-lg flex flex-col space-y-4">
|
||||
{options.map((option) => (
|
||||
<UniLink
|
||||
className="prose p-6 bg-slate-100 rounded-lg relative"
|
||||
|
|
|
|||
|
|
@ -92,7 +92,7 @@ export default function ImportMarkdownPage() {
|
|||
return (
|
||||
<DashboardMain title="Import from Markdown files">
|
||||
<form onSubmit={handleSubmit}>
|
||||
<div className="min-w-[270px] flex flex-col space-y-4">
|
||||
<div className="min-w-[270px] max-w-screen-lg flex flex-col space-y-4">
|
||||
<Input
|
||||
className="py-1"
|
||||
label={`Select Markdown Files`}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,122 @@
|
|||
import { useRouter } from "next/router"
|
||||
import { DashboardLayout } from "~/components/dashboard/DashboardLayout"
|
||||
import { DashboardMain } from "~/components/dashboard/DashboardMain"
|
||||
import { ReactElement, useEffect, useState } from "react"
|
||||
import { useGetSite } from "~/queries/site"
|
||||
import { useTranslation } from "next-i18next"
|
||||
import { getServerSideProps as getLayoutServerSideProps } from "~/components/dashboard/DashboardLayout.server"
|
||||
import { GetServerSideProps } from "next"
|
||||
import { serverSidePropsHandler } from "~/lib/server-side-props"
|
||||
import { useForm } from "react-hook-form"
|
||||
import { Input } from "~/components/ui/Input"
|
||||
import { Button } from "~/components/ui/Button"
|
||||
import { readFiles } from "~/lib/read-files"
|
||||
import { getSiteLink } from "~/lib/helpers"
|
||||
import type { NoteMetadata } from "crossbell.js"
|
||||
import { ImportPreview } from "~/components/dashboard/ImportPreview"
|
||||
import { usePostNotes } from "~/queries/page"
|
||||
import { toast } from "react-hot-toast"
|
||||
import { useGetMirrorXyz } from "~/queries/page"
|
||||
|
||||
export const getServerSideProps: GetServerSideProps = serverSidePropsHandler(
|
||||
async (ctx) => {
|
||||
const { props: layoutProps } = await getLayoutServerSideProps(ctx)
|
||||
|
||||
return {
|
||||
props: {
|
||||
...layoutProps,
|
||||
},
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
export default function ImportMarkdownPage() {
|
||||
const router = useRouter()
|
||||
const subdomain = router.query.subdomain as string
|
||||
const site = useGetSite(subdomain)
|
||||
const { t } = useTranslation("dashboard")
|
||||
const form = useForm({
|
||||
defaultValues: {
|
||||
type: "post",
|
||||
},
|
||||
})
|
||||
const postNotes = usePostNotes()
|
||||
const mirrorXyz = useGetMirrorXyz({
|
||||
address: site.data?.metadata?.owner,
|
||||
})
|
||||
|
||||
const notes = mirrorXyz?.data?.map((note) => ({
|
||||
title: note.title,
|
||||
content: note.content,
|
||||
tags: ["post", ...note.tags],
|
||||
sources: ["xlog"],
|
||||
attributes: [
|
||||
{
|
||||
trait_type: "xlog_slug",
|
||||
value: note.slug,
|
||||
},
|
||||
],
|
||||
date_published: note.date_published,
|
||||
external_urls: [
|
||||
`${getSiteLink({
|
||||
subdomain,
|
||||
domain: site.data?.custom_domain,
|
||||
})}/${encodeURIComponent(note.slug)}`,
|
||||
...note.external_urls,
|
||||
],
|
||||
}))
|
||||
|
||||
const handleSubmit = form.handleSubmit(async (values) => {
|
||||
if (notes?.length && site.data?.username && site.data.metadata?.proof) {
|
||||
postNotes.mutate({
|
||||
siteId: site.data.username,
|
||||
characterId: site.data.metadata.proof,
|
||||
notes: notes,
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
useEffect(() => {
|
||||
if (postNotes.isSuccess) {
|
||||
form.reset()
|
||||
toast.success("Notes imported successfully")
|
||||
}
|
||||
}, [postNotes.isSuccess, form])
|
||||
|
||||
return (
|
||||
<DashboardMain title="Import from Mirror.xyz">
|
||||
<form onSubmit={handleSubmit}>
|
||||
<div className="min-w-[270px] max-w-screen-lg flex flex-col space-y-4">
|
||||
<div>
|
||||
<div className="form-label">Preview your entries on Mirror.xyz</div>
|
||||
{notes?.length ? (
|
||||
notes?.map((note: NoteMetadata) => (
|
||||
<ImportPreview key={note.title} note={note} />
|
||||
))
|
||||
) : (
|
||||
<div className="text-gray-500">No files chosen</div>
|
||||
)}
|
||||
</div>
|
||||
<div>
|
||||
<Button
|
||||
isAutoWidth={true}
|
||||
type="submit"
|
||||
isLoading={
|
||||
site.isLoading || mirrorXyz.isLoading || postNotes.isLoading
|
||||
}
|
||||
disabled={!notes?.length}
|
||||
>
|
||||
{t("Import")}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</DashboardMain>
|
||||
)
|
||||
}
|
||||
|
||||
ImportMarkdownPage.getLayout = (page: ReactElement) => {
|
||||
return (
|
||||
<DashboardLayout title="Import from Mirror.xyz">{page}</DashboardLayout>
|
||||
)
|
||||
}
|
||||
|
|
@ -19,6 +19,7 @@ import { useContract } from "@crossbell/contract"
|
|||
import * as pageModel from "~/models/page.model"
|
||||
|
||||
import { useUnidata } from "./unidata"
|
||||
import { getDefaultSlug } from "~/lib/helpers"
|
||||
|
||||
export const useGetPagesBySiteLite = (
|
||||
input: Parameters<typeof pageModel.getPagesBySite>[0],
|
||||
|
|
@ -252,3 +253,41 @@ export function useGetSummary(input: { cid?: string; lang?: string }) {
|
|||
})
|
||||
})
|
||||
}
|
||||
|
||||
export function useGetMirrorXyz(input: { address: string }) {
|
||||
return useQuery(["getMirror", input.address], async () => {
|
||||
if (!input.address) {
|
||||
return null
|
||||
}
|
||||
const response = await (
|
||||
await fetch(
|
||||
"/api/import/mirror.xyz?" +
|
||||
new URLSearchParams({
|
||||
...input,
|
||||
} as any),
|
||||
)
|
||||
).json()
|
||||
|
||||
return response?.data?.projectFeed?.posts?.map((post: any) => {
|
||||
return {
|
||||
title: post.title,
|
||||
date_published: new Date(
|
||||
post.publishedAtTimestamp * 1000,
|
||||
).toISOString(),
|
||||
slug: getDefaultSlug(post.title, post.digest),
|
||||
tags: ["Mirror.xyz"],
|
||||
content: post.body,
|
||||
external_urls: [`https://mirror.xyz/${input.address}/${post.digest}`],
|
||||
}
|
||||
}) as {
|
||||
title: string
|
||||
type: string
|
||||
size: number
|
||||
date_published: string
|
||||
slug: string
|
||||
tags: string[]
|
||||
content: string
|
||||
external_urls: string[]
|
||||
}[]
|
||||
})
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue