feat: import from mirror.xyz

This commit is contained in:
DIYgod 2023-03-09 13:47:04 +00:00
parent 737c2b8411
commit 07a2336450
No known key found for this signature in database
6 changed files with 187 additions and 3 deletions

View File

@ -259,7 +259,6 @@ textarea.input {
@apply mb-2;
@apply font-bold;
@apply text-gray-700;
@apply capitalize;
}
.post-status-circle {

View File

@ -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)
}

View File

@ -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"

View File

@ -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`}

View File

@ -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>
)
}

View File

@ -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[]
}[]
})
}