list pages from pocketbase
This commit is contained in:
parent
699fbf06c5
commit
23d6930bd6
|
|
@ -1,5 +1,6 @@
|
||||||
import { memo, useEffect, useRef } from "react";
|
import { memo, useEffect, useRef } from "react";
|
||||||
import EditorJS, { OutputData } from "@editorjs/editorjs";
|
import EditorJS from "@editorjs/editorjs";
|
||||||
|
import type { OutputData } from "@editorjs/editorjs";
|
||||||
import { EDITOR_JS_TOOLS } from "@/utils/tools";
|
import { EDITOR_JS_TOOLS } from "@/utils/tools";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
|
|
@ -17,7 +18,7 @@ const EditorBlock = ({ data, onChange, holder }: Props) => {
|
||||||
holder: holder,
|
holder: holder,
|
||||||
tools: EDITOR_JS_TOOLS,
|
tools: EDITOR_JS_TOOLS,
|
||||||
data,
|
data,
|
||||||
async onChange(api, event) {
|
async onChange(api) {
|
||||||
const data = await api.saver.save();
|
const data = await api.saver.save();
|
||||||
onChange(data);
|
onChange(data);
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -1,27 +0,0 @@
|
||||||
import type { PagesRecord } from '@/@types/pocketbase-types';
|
|
||||||
import Layout from '@/layouts/Home'
|
|
||||||
import { getPageBySlug } from '@/utils/pb'
|
|
||||||
|
|
||||||
export default function Page({data}: {slug: string, data: PagesRecord}) {
|
|
||||||
return (
|
|
||||||
<Layout title={data.title}>
|
|
||||||
<h1>{data.title}</h1>
|
|
||||||
<pre>{JSON.stringify(data.content, null, 2)}</pre>
|
|
||||||
</Layout>
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function getServerSideProps({params}: {params: {slug: string}}) {
|
|
||||||
const {data, error} = await getPageBySlug(params.slug);
|
|
||||||
if (error || !data) {
|
|
||||||
return {
|
|
||||||
notFound: true,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
props: {
|
|
||||||
data: data,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -0,0 +1,101 @@
|
||||||
|
import type { PagesRecord } from '@/@types/pocketbase-types';
|
||||||
|
import Layout from '@/layouts/Home'
|
||||||
|
import { getPageBySlug } from '@/utils/pb'
|
||||||
|
|
||||||
|
function parseBoldText(text: string) {
|
||||||
|
const parts = text.split(/(<b>.*?<\/b>)/g);
|
||||||
|
const result = [];
|
||||||
|
for (let i = 0; i < parts.length; i++) {
|
||||||
|
if (parts[i]?.startsWith('<b>')) {
|
||||||
|
result.push(<b key={i}>{parts[i]?.slice(3, -4)}</b>)
|
||||||
|
} else {
|
||||||
|
result.push(parts[i])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
function Paragraph({text}: {text: string}) {
|
||||||
|
return <p className='text-xl'>{parseBoldText(text)}</p>
|
||||||
|
}
|
||||||
|
|
||||||
|
function Heading({text, level}: {text: string, level: number}) {
|
||||||
|
switch (level) {
|
||||||
|
case 1:
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<h1 className='font-poppins text-5xl'>{text}</h1>
|
||||||
|
<div className="line h-1 w-full bg-black"></div>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
case 2:
|
||||||
|
return <h2 className='text-2xl'>{text}</h2>
|
||||||
|
case 3:
|
||||||
|
return <h3>{text}</h3>
|
||||||
|
default:
|
||||||
|
return <h4>{text}</h4>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type ParagraphBlock = {
|
||||||
|
type: 'paragraph',
|
||||||
|
data: {
|
||||||
|
text: string,
|
||||||
|
},
|
||||||
|
id: string,
|
||||||
|
}
|
||||||
|
|
||||||
|
type HeaderBlock = {
|
||||||
|
type: 'header',
|
||||||
|
data: {
|
||||||
|
text: string,
|
||||||
|
level: number,
|
||||||
|
},
|
||||||
|
id: string,
|
||||||
|
}
|
||||||
|
|
||||||
|
type Block = ParagraphBlock | HeaderBlock;
|
||||||
|
|
||||||
|
type Content = {
|
||||||
|
blocks: Block[],
|
||||||
|
version: string,
|
||||||
|
time: number,
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function Page({data}: {slug: string, data: PagesRecord<Content>}) {
|
||||||
|
return (
|
||||||
|
<Layout title={data.title}>
|
||||||
|
<div className="container mx-auto p-8">
|
||||||
|
<p>Here is the content rendered:</p>
|
||||||
|
<div className="flex flex-col gap-6">
|
||||||
|
{data.content && data.content.blocks.map((block, index): (JSX.Element | null) => {
|
||||||
|
switch (block.type) {
|
||||||
|
case 'paragraph':
|
||||||
|
return <Paragraph key={index} text={block.data.text} />
|
||||||
|
case 'header':
|
||||||
|
return <Heading key={index} text={block.data.text} level={block.data.level} />
|
||||||
|
default:
|
||||||
|
return <p key={index}>Unknown block type: <pre>{JSON.stringify(block, null, 2)}</pre></p>
|
||||||
|
}
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<pre>{JSON.stringify(data.content, null, 2)}</pre>
|
||||||
|
</Layout>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function getServerSideProps({params}: {params: {slug: string}}) {
|
||||||
|
const {data, error} = await getPageBySlug(params.slug);
|
||||||
|
if (error || !data) {
|
||||||
|
return {
|
||||||
|
notFound: true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
props: {
|
||||||
|
data: data,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -2,6 +2,7 @@ import dynamic from 'next/dynamic'
|
||||||
import Layout from '@/layouts/Home'
|
import Layout from '@/layouts/Home'
|
||||||
import { useState } from 'react'
|
import { useState } from 'react'
|
||||||
import { OutputData } from "@editorjs/editorjs";
|
import { OutputData } from "@editorjs/editorjs";
|
||||||
|
import { api } from '@/utils/api';
|
||||||
|
|
||||||
const ReactEditorJS = dynamic(() => import('@/components/ReactEditor'), {
|
const ReactEditorJS = dynamic(() => import('@/components/ReactEditor'), {
|
||||||
ssr: false
|
ssr: false
|
||||||
|
|
@ -9,8 +10,26 @@ const ReactEditorJS = dynamic(() => import('@/components/ReactEditor'), {
|
||||||
|
|
||||||
export default function Editor() {
|
export default function Editor() {
|
||||||
const [data, setData] = useState<OutputData>()
|
const [data, setData] = useState<OutputData>()
|
||||||
|
const {mutate, isLoading, data: data2, isError} = api.pages.updatePage.useMutation();
|
||||||
|
|
||||||
|
if (data2) console.log(data2)
|
||||||
|
|
||||||
|
const handleSubmit = () => {
|
||||||
|
if (!data) return
|
||||||
|
mutate({
|
||||||
|
slug: 'test',
|
||||||
|
title: 'Test',
|
||||||
|
content: data
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Layout title='React EditorJS'>
|
<Layout title='EditorJS'>
|
||||||
|
<button onClick={handleSubmit}>Save</button>
|
||||||
|
{isLoading && <p>Loading...</p>}
|
||||||
|
{data2 && !isError && <p>Saved!</p>}
|
||||||
|
{isError && <p>Error!</p>}
|
||||||
|
|
||||||
<h1>React EditorJS</h1>
|
<h1>React EditorJS</h1>
|
||||||
<div className="container mx-auto p-8">
|
<div className="container mx-auto p-8">
|
||||||
<h2>EditorJS with React</h2>
|
<h2>EditorJS with React</h2>
|
||||||
|
|
@ -1,13 +1,13 @@
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
import { createTRPCRouter, publicProcedure } from "../trpc";
|
import { createTRPCRouter, publicProcedure } from "../trpc";
|
||||||
import { getPage, getPages } from "@/utils/pb";
|
import { getPageById, getPages, updatePage, getIdFromSlug } from "@/utils/pb";
|
||||||
|
|
||||||
export const pagesRouter = createTRPCRouter({
|
export const pagesRouter = createTRPCRouter({
|
||||||
getPage: publicProcedure
|
getPage: publicProcedure
|
||||||
.input(z.object({ id: z.string() }))
|
.input(z.object({ id: z.string() }))
|
||||||
.query(({ input }) => {
|
.query(({ input }) => {
|
||||||
return {
|
return {
|
||||||
data: getPage(input.id),
|
data: getPageById(input.id),
|
||||||
};
|
};
|
||||||
}),
|
}),
|
||||||
getPages: publicProcedure
|
getPages: publicProcedure
|
||||||
|
|
@ -16,4 +16,28 @@ export const pagesRouter = createTRPCRouter({
|
||||||
data: getPages(),
|
data: getPages(),
|
||||||
};
|
};
|
||||||
}),
|
}),
|
||||||
|
updatePage: publicProcedure
|
||||||
|
.input(z.object({ slug: z.string(), title: z.string().optional(), content: z.any().optional() }))
|
||||||
|
.mutation(async ({ input }) => {
|
||||||
|
const id = await getIdFromSlug(input.slug);
|
||||||
|
if (!id || id.error || !id.data) {
|
||||||
|
return {
|
||||||
|
error: {
|
||||||
|
code: "NOT_FOUND",
|
||||||
|
message: "Page not found",
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
let data = {};
|
||||||
|
if (input.title) {
|
||||||
|
data = { ...data, title: input.title };
|
||||||
|
}
|
||||||
|
if (input.content) {
|
||||||
|
data = { ...data, content: input.content };
|
||||||
|
}
|
||||||
|
const res = await updatePage(id.data, data);
|
||||||
|
return {
|
||||||
|
data: res,
|
||||||
|
};
|
||||||
|
}),
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -56,4 +56,16 @@ async function updatePage(id: string, data: PagesRecord) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export { pb, getPages, getPageById, getPageBySlug, createPage, updatePage };
|
async function getIdFromSlug(slug: string) {
|
||||||
|
try {
|
||||||
|
const res = await pb
|
||||||
|
.collection("pages")
|
||||||
|
.getFirstListItem('slug="' + slug + '"');
|
||||||
|
return { data: res.id };
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error);
|
||||||
|
return { error };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export { pb, getPages, getPageById, getPageBySlug, createPage, updatePage, getIdFromSlug };
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue