Skip to content

Commit

Permalink
fix load and save page
Browse files Browse the repository at this point in the history
  • Loading branch information
LiveDuo committed Nov 4, 2023
1 parent fcbd2ba commit bcf7366
Show file tree
Hide file tree
Showing 4 changed files with 92 additions and 51 deletions.
40 changes: 40 additions & 0 deletions dev/nextjs-project/data/default.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
<section
class="relative bg-[url(https://images.unsplash.com/photo-1604014237800-1c9102c219da?ixlib=rb-1.2.1&amp;ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&amp;auto=format&amp;fit=crop&amp;w=1770&amp;q=80)] bg-cover bg-center bg-no-repeat"
>
<div
class="absolute inset-0 bg-white/75 sm:bg-transparent sm:bg-gradient-to-r sm:from-white/95 sm:to-white/25"
></div>

<div
class="relative mx-auto max-w-screen-xl px-4 py-32 sm:px-6 lg:flex lg:h-screen lg:items-center lg:px-8"
>
<div class="max-w-xl text-center sm:text-left">
<h1 class="text-3xl font-extrabold sm:text-5xl">
Let us find your

<strong class="block font-extrabold text-rose-700"> Forever Home. </strong>
</h1>

<p class="mt-4 max-w-lg sm:text-xl sm:leading-relaxed">
Lorem ipsum dolor sit amet consectetur, adipisicing elit. Nesciunt illo tenetur fuga ducimus
numquam ea!
</p>

<div class="mt-8 flex flex-wrap gap-4 text-center">
<a
href="#"
class="block w-full rounded bg-red-600 px-12 py-3 text-sm font-medium text-white shadow hover:bg-rose-700 focus:outline-none focus:ring active:bg-rose-500 sm:w-auto cursor-pointer"
>
Get Started
</a>

<a
href="#"
class="block w-full rounded bg-white px-12 py-3 text-sm font-medium text-red-600 shadow hover:text-rose-700 focus:outline-none focus:ring active:text-rose-500 sm:w-auto cursor-pointer"
>
Learn More
</a>
</div>
</div>
</div>
</section>
60 changes: 35 additions & 25 deletions lib/client/vanilla/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,15 @@ const themes = [

const placeholderImageUrl = 'https://placehold.co/400x200'

function debounce(callback, timeout = 1000) {
let timeoutFn
return (...args) => {
const context = this
clearTimeout(timeoutFn)
timeoutFn = setTimeout(() => callback.apply(context, args), timeout)
}
}

const getBaseUrl = (standaloneServer) => {
return standaloneServer ? `http://localhost:${standaloneServerPort}` : ''
}
Expand All @@ -37,50 +46,51 @@ function ContentProvider() {
const [hoveredComponent, setHoveredComponent] = useState()
const [components, setComponents] = useState([])

const loadData = async () => {
const loadComponents = async () => {
const baseUrl = getBaseUrl(false)
const url = `${baseUrl}/api/builder/handle?type=theme&name=${themes[0].folder}`
const _components = await fetch(url).then((r) => r.json())

setComponents(_components)
}

const loadPage = async () => {
const baseUrl = getBaseUrl(false)
const url2 = `${baseUrl}/api/builder/handle?type=data&path=${location.pathname}`
const data = await fetch(url2).then((r) => r.text())
canvasRef.current.innerHTML = data
}

const savePage = async () => {
console.log('dom changed')

const baseUrl = getBaseUrl(false)
const url = `${baseUrl}/api/builder/handle?type=data&path=${location.pathname}`

// TODO load page from served
await fetch(url, { method: 'post', body: canvasRef.current.innerHTML })
}

const onDomChange = () => {
canvasRef.current
const config = { attributes: true, childList: true, subtree: true }
const observer = new MutationObserver(() => {
console.log('dom changed')
// TODO save page to server
})
const observer = new MutationObserver(
debounce(() => {
savePage()
}),
)
observer.observe(canvasRef.current, config)
return observer
}

useEffect(() => {
loadData()

loadPage()
loadComponents()

const observer = onDomChange()

return () => observer.disconnect()
}, [])

const loadComponents = () => {
const html = localStorage.getItem('page')
if (html) {
canvasRef.current.innerHTML = html
} else {
alert('Save not found')
}
}

const saveComponents = () => {
localStorage.setItem('page', canvasRef.current.innerHTML)
}

const clearComponents = async () => {
canvasRef.current.innerHTML = ''
}
Expand Down Expand Up @@ -231,11 +241,11 @@ function ContentProvider() {
</div>
<div className="w-full" style={{ height: '100vh', display: 'flex', flexDirection: 'column' }}>
<div className="flex items-center m-2">
<ArrowDownOnSquareIcon
{/* <ArrowDownOnSquareIcon
className="h-6 w-6 mx-2 ml-4 cursor-pointer"
onClick={loadComponents}
/>
<ArrowUpOnSquareIcon className="h-6 w-6 mx-2 cursor-pointer" onClick={saveComponents} />
onClick={() => {}}
/> */}
{/* <ArrowUpOnSquareIcon className="h-6 w-6 mx-2 cursor-pointer" onClick={() => {}} /> */}
<TrashIcon className="h-6 w-6 mx-2 cursor-pointer" onClick={clearComponents} />
<button
className="bg-green-500 hover:bg-green-700 text-white px-4 py-2 ml-auto mr-6 rounded-md"
Expand Down
32 changes: 11 additions & 21 deletions lib/server/api/handle.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,9 @@ import { NextApiResponse, NextApiRequest } from 'next'
import path from 'path'
import fs from 'fs'

import { formParse, getJson, exists, readdirRecursive } from '../utils'
import { formParse, getPage, exists, readdirRecursive } from '../utils'
import { dataType } from '../../types'

const DEFAULT_TEMPLATE = {
ROOT: {
type: { resolvedName: 'Container' },
isCanvas: true,
props: { width: '100%', height: '800px' },
displayName: 'Container',
custom: { displayName: 'App' },
},
}

const development = process.env.NODE_ENV !== 'production'

const rootPath = process.cwd()
Expand Down Expand Up @@ -44,19 +34,19 @@ const uploadFiles = async (req: NextApiRequest): Promise<string[]> => {
}
export { uploadFiles }

const getFileNameFromRoute = (route: string) => (route === '/' ? 'default.json' : `${route}.json`) // browser paths are always "/"
const getFileNameFromRoute = (route: string) => (route === '/' ? 'default.html' : `${route}.html`) // browser paths are always "/"
const getRouteFromFilename = (filename: string) =>
filename === path.sep + 'default.json' ? path.sep : `${filename.slice(0, -5)}` // file paths are OS-specific
filename === path.sep + 'default.html' ? path.sep : `${filename.slice(0, -5)}` // file paths are OS-specific

const loadData = async (route: string): Promise<dataType> => {
const loadData = async (route: string): Promise<string> => {
const fileName = getFileNameFromRoute(route)
const dataPath = path.join(rootPath, dataFolder, fileName)
const dataExists = await exists(dataPath)
if (!dataExists) {
return { content: JSON.stringify(DEFAULT_TEMPLATE) }
return '<div>hello</div>'
} else {
const content = await fs.readFileSync(dataPath, 'utf8')
return { content }
const content = fs.readFileSync(dataPath, 'utf8')
return content
}
}
export { loadData }
Expand Down Expand Up @@ -92,7 +82,7 @@ const updateData = async (route: string, data: string): Promise<void> => {
await fs.promises.mkdir(updatePath)
}

await fs.promises.writeFile(path.join(updatePath, fileName), JSON.stringify(data))
await fs.promises.writeFile(path.join(updatePath, fileName), data)
}
export { updateData }

Expand All @@ -105,13 +95,13 @@ const handleData = async (req: NextApiRequest, res: NextApiResponse): Promise<vo
// handle request
if (req.method === 'GET') {
const data = await loadData(req.query.path as string)
return res.status(200).json(data)
return res.status(200).send(data)
} else if (req.method === 'POST') {
const contentType = req.headers['content-type']!
const isMultiPart = contentType.startsWith('multipart/form-data')
if (!isMultiPart) {
const body = await getJson(req)
await updateData(req.query.path as string, body.data)
const body = await getPage(req)
await updateData(req.query.path as string, body)
return res.status(200).json({})
} else {
const urls = await uploadFiles(req)
Expand Down
11 changes: 6 additions & 5 deletions lib/server/utils/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,20 +14,21 @@ const formParse = (form: FormidableForm, req: NextApiRequest): Promise<formidabl
})
export { formParse }

const getJson = (req: NextApiRequest): Promise<Record<string, string>> =>
new Promise<Record<string, string>>((resolve) => {
const getPage = (req: NextApiRequest): Promise<string> =>
new Promise<string>((resolve) => {
if (!req.body) {
let buffer = ''
req.on('data', (chunk) => {
buffer += chunk
})
req.on('end', () => {
const str = Buffer.from(buffer).toString()
if (str && str.indexOf('{') > -1) resolve(JSON.parse(str))
resolve(buffer)
})
} else {
resolve(req.body)
}
})
export { getJson }
export { getPage }

const exists = (s: fs.PathLike): Promise<boolean> =>
fs.promises
Expand Down

0 comments on commit bcf7366

Please sign in to comment.