diff --git a/src/css/tailwind.css b/src/css/tailwind.css index 149ea400..ffe29d5f 100644 --- a/src/css/tailwind.css +++ b/src/css/tailwind.css @@ -259,7 +259,6 @@ textarea.input { @apply mb-2; @apply font-bold; @apply text-gray-700; - @apply capitalize; } .post-status-circle { diff --git a/src/pages/api/import/mirror.xyz.ts b/src/pages/api/import/mirror.xyz.ts new file mode 100644 index 00000000..d3aabf74 --- /dev/null +++ b/src/pages/api/import/mirror.xyz.ts @@ -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) +} diff --git a/src/pages/dashboard/[subdomain]/import/index.tsx b/src/pages/dashboard/[subdomain]/import/index.tsx index 2648a5af..ee5de6f3 100644 --- a/src/pages/dashboard/[subdomain]/import/index.tsx +++ b/src/pages/dashboard/[subdomain]/import/index.tsx @@ -41,7 +41,7 @@ export default function ImportPage() { return ( -
+
{options.map((option) => (
-
+
{ + 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 ( + + +
+
+
Preview your entries on Mirror.xyz
+ {notes?.length ? ( + notes?.map((note: NoteMetadata) => ( + + )) + ) : ( +
No files chosen
+ )} +
+
+ +
+
+ +
+ ) +} + +ImportMarkdownPage.getLayout = (page: ReactElement) => { + return ( + {page} + ) +} diff --git a/src/queries/page.ts b/src/queries/page.ts index fc862f17..a7f98eb7 100644 --- a/src/queries/page.ts +++ b/src/queries/page.ts @@ -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[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[] + }[] + }) +}