63 lines
1.8 KiB
JavaScript
63 lines
1.8 KiB
JavaScript
import express from 'express'
|
|
import { mkdir, readFile, writeFile } from 'node:fs/promises'
|
|
import path from 'node:path'
|
|
import { fileURLToPath } from 'node:url'
|
|
|
|
const __filename = fileURLToPath(import.meta.url)
|
|
const __dirname = path.dirname(__filename)
|
|
const DATA_DIR = path.join(__dirname, 'data')
|
|
const DATA_FILE = path.join(DATA_DIR, 'admin-content.json')
|
|
const DIST_DIR = path.join(__dirname, 'dist')
|
|
const INDEX_FILE = path.join(DIST_DIR, 'index.html')
|
|
|
|
const app = express()
|
|
app.use(express.json({ limit: '10mb' }))
|
|
|
|
app.get('/api/admin-content', async (_req, res) => {
|
|
try {
|
|
const raw = await readFile(DATA_FILE, 'utf8')
|
|
const parsed = JSON.parse(raw)
|
|
res.json(parsed)
|
|
} catch {
|
|
res.status(404).json({ message: 'No saved admin content file yet.' })
|
|
}
|
|
})
|
|
|
|
app.put('/api/admin-content', async (req, res) => {
|
|
try {
|
|
const { siteContent } = req.body ?? {}
|
|
|
|
if (!siteContent || typeof siteContent !== 'object' || Array.isArray(siteContent)) {
|
|
res.status(400).json({ message: 'Invalid payload: siteContent must be an object.' })
|
|
return
|
|
}
|
|
|
|
await mkdir(DATA_DIR, { recursive: true })
|
|
await writeFile(
|
|
DATA_FILE,
|
|
JSON.stringify({ siteContent, updatedAt: new Date().toISOString() }, null, 2),
|
|
'utf8',
|
|
)
|
|
|
|
res.json({ ok: true })
|
|
} catch {
|
|
res.status(500).json({ message: 'Failed to persist admin content.' })
|
|
}
|
|
})
|
|
|
|
app.use(express.static(DIST_DIR))
|
|
|
|
app.use(async (_req, res) => {
|
|
try {
|
|
const html = await readFile(INDEX_FILE, 'utf8')
|
|
res.type('html').send(html)
|
|
} catch {
|
|
res.status(503).send('Frontend build not found. Run "npm run build" first.')
|
|
}
|
|
})
|
|
|
|
const PORT = Number(process.env.PORT ?? 4173)
|
|
app.listen(PORT, () => {
|
|
console.log(`Portfolio app listening on http://localhost:${PORT}`)
|
|
})
|