**RSPS Guide Builder app with Laravel backend + React frontend**. This will be closer to a **Notion-lite** experience, with drag-and-drop guides, tags, TOC, copy buttons, and HTML export. --- # π RSPS Guide Builder (Laravel API + React Frontend) --- ## πΉ Overall Architecture * **Backend: Laravel** * REST or GraphQL API (`/api/guides`, `/api/tags`). * Handles authentication (Laravel Sanctum recommended). * Stores guides in DB as JSON. * Provides **export endpoint** β generates `.html` file with inline CSS/JS. * **Frontend: React (Vite or CRA)** * SPA with React Router. * Uses `react-editor-js` or `tiptap-react` for Notion-style editing. * Components: Editor, Viewer, TOC, GuideList. * Styled with Tailwind (dark + blue theme). --- ## πΉ Database Design (Laravel) **`guides`** ```sql id BIGINT AUTO_INCREMENT PRIMARY KEY title VARCHAR(255) slug VARCHAR(255) UNIQUE description TEXT NULL content JSON -- Editor.js or TipTap JSON created_at TIMESTAMP updated_at TIMESTAMP ``` **`tags`** ```sql id BIGINT AUTO_INCREMENT PRIMARY KEY name VARCHAR(100) UNIQUE slug VARCHAR(100) UNIQUE ``` **`guide_tag`** ```sql guide_id BIGINT tag_id BIGINT PRIMARY KEY (guide_id, tag_id) ``` --- ## πΉ Backend API (Laravel) * `GET /api/guides` β List all guides (with tags). * `POST /api/guides` β Create new guide. * `GET /api/guides/{id}` β Fetch guide by ID. * `PUT /api/guides/{id}` β Update guide (title + content JSON). * `DELETE /api/guides/{id}` β Delete guide. * `GET /api/guides/{id}/export` β Returns self-contained `.html`. --- ## πΉ React Project Structure ``` src/ components/ Editor/GuideEditor.jsx Viewer/GuideViewer.jsx TOC/TOC.jsx GuideList.jsx CodeBlock.jsx TagFilter.jsx pages/ GuideEditorPage.jsx GuideViewerPage.jsx GuideListPage.jsx api/ guides.js tags.js App.jsx index.jsx ``` --- ## πΉ React Components ### 1. **GuideEditor.jsx** (Notion-style editor) Using `react-editor-js`: ```jsx import React, { useRef } from 'react'; import { createReactEditorJS } from 'react-editor-js'; import Header from '@editorjs/header'; import Code from '@editorjs/code'; import Paragraph from '@editorjs/paragraph'; import Image from '@editorjs/image'; const ReactEditorJS = createReactEditorJS(); const GuideEditor = ({ initialData, onSave }) => { const editorCore = useRef(null); const handleSave = async () => { const savedData = await editorCore.current.save(); onSave(savedData); }; return (
{guide.description}
{blocks.map((block, i) => { if (block.type === 'header') { return{block.data.text}
; } if (block.type === 'code') { return (
{block.data.code}