Skip to content

Commit

Permalink
feat: add a 'publicodes dev' command
Browse files Browse the repository at this point in the history
  • Loading branch information
johangirod committed Jan 27, 2025
1 parent 2ad8c4f commit 63903b2
Show file tree
Hide file tree
Showing 18 changed files with 1,356 additions and 51 deletions.
20 changes: 16 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@
},
"files": [
"dist",
"bin"
"bin",
"quick-doc"
],
"exports": {
".": {
Expand Down Expand Up @@ -62,18 +63,28 @@
"dependencies": {
"@clack/prompts": "^0.7.0",
"@oclif/core": "^4.0.23",
"@publicodes/react-ui": "^1.5.4",
"@tailwindcss/typography": "^0.5.16",
"@tailwindcss/vite": "^4.0.0",
"@types/node": "^18.11.18",
"chalk": "^5.3.0",
"chokidar": "^4.0.3",
"glob": "^10.4.1",
"path": "^0.12.7",
"publicodes": "^1.6.1",
"yaml": "^2.4.5"
"react": "^19.0.0",
"react-dom": "^19.0.0",
"react-router-dom": "^7.1.3",
"tailwindcss": "^4.0.0",
"vite": "^6.0.11",
"yaml": "^2.7.0"
},
"devDependencies": {
"@oclif/test": "^4.0.9",
"@types/jest": "^29.5.13",
"@types/react": "^19.0.8",
"docdash": "^2.0.1",
"prettier": "^3.0.0",
"prettier": "^3.4.2",
"ts-node": "^10.9.2",
"tsup": "^8.0.2",
"typedoc": "^0.24.8",
Expand Down Expand Up @@ -106,5 +117,6 @@
},
"publishConfig": {
"access": "public"
}
},
"packageManager": "[email protected]+sha1.4ba7fc5c6e704fce2066ecbfb0b0d8976fe62447"
}
Empty file added quick-doc/README.md
Empty file.
15 changes: 15 additions & 0 deletions quick-doc/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>⚡️ QuickDoc - Publicodes</title>
<!-- <link rel="stylesheet" href="./src/index.css" /> -->
</head>
<body>
<div id="root"></div>

<script type="module" src="/src/index.tsx"></script>
<link href="/src/app.css" rel="stylesheet" />
</body>
</html>
50 changes: 50 additions & 0 deletions quick-doc/src/app.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
@import 'tailwindcss';

@layer base {
h1 {
@apply text-4xl font-bold mt-8 mb-6 text-[#10162F];
}

h2 {
@apply text-3xl font-semibold mt-6 mb-5 text-[#10162F];
}

h3 {
@apply text-2xl font-semibold mt-5 mb-4 text-[#10162F];
}

p {
@apply text-base leading-relaxed mb-4 text-[#4B5563];
}

ul {
@apply list-disc list-inside mb-4 space-y-2;
}

ol {
@apply list-decimal list-inside mb-4 space-y-2;
}

li {
@apply text-[#4B5563] leading-relaxed;
}

a {
@apply text-[#2975d1] hover:text-[#1a365d] transition-colors underline-offset-2 hover:underline;
}

blockquote {
@apply pl-4 border-l-4 border-[#E5E7EB] italic my-4;
}

code {
@apply bg-[#F3F4F6] px-2 py-1 rounded text-sm text-[#10162F];
}

pre {
@apply bg-[#F3F4F6] p-4 rounded-lg mb-4 overflow-x-auto;
}
button {
@apply bg-slate-100 px-2 py-1 rounded-md hover:bg-slate-50 transition-colors cursor-pointer disabled:opacity-50 text-sm disabled:cursor-not-allowed border border-slate-600 text-slate-800 ml-2;
}
}
74 changes: 74 additions & 0 deletions quick-doc/src/components/App.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
import {
BrowserRouter,
Route,
Routes,
Link,
useParams,
Navigate,
} from 'react-router-dom'
import { RulePage } from '@publicodes/react-ui'
import { engine, onEngineUpdate } from '../engine'
import { RulesIndex } from './RulesIndex'
import { useEffect, useState } from 'react'
import Header from './Header'
import { onSituationUpdate, situations } from '../situations'
import { sitemap } from '../sitemap'

function RulePageWrapper() {
let { '*': splat } = useParams()
return (
<RulePage
engine={engine}
documentationPath=""
rulePath={splat}
searchBar={true}
showDevSection={true}
language="fr"
renderers={{ Link: Link }}
/>
)
}

export default function App() {
const [, forceUpdate] = useState({})
useEffect(() => {
// Subscribe to engine updates
return onEngineUpdate(() => forceUpdate({}))
}, [])
const [activeSituation, setActiveSituation] = useState('')

useEffect(() => {
return onSituationUpdate(() => {
// forceUpdate({})
console.log('situation updated', activeSituation)
engine.setSituation(situations[activeSituation] ?? {})
setActiveSituation(activeSituation in situations ? activeSituation : '')
forceUpdate({})
})
}, [activeSituation])

function handleSituationChange(situation: string) {
setActiveSituation(situation)
engine.setSituation(situations[situation] ?? {})
}

return (
<>
<BrowserRouter>
<Header
setSituation={handleSituationChange}
activeSituation={activeSituation}
/>
<div className="container mx-auto">
<Routes>
<Route
path="/"
element={<Navigate to={Object.keys(sitemap)[0]} replace />}
/>
<Route path="/*" element={<RulePageWrapper />} />
</Routes>
</div>
</BrowserRouter>
</>
)
}
46 changes: 46 additions & 0 deletions quick-doc/src/components/Header.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import { Link } from 'react-router-dom'
import { situations } from '../situations'

export default function Header({
setSituation,
activeSituation,
}: {
setSituation: (situation: string) => void
activeSituation: string
}) {
return (
<header className=" container mx-auto">
<div className="flex items-center justify-between">
<h1>
<Link to="/" className="text-xl font-bold">
⚡ Quick-doc
</Link>
</h1>

<nav className="w-full md:w-auto">
<div className="flex flex-col gap-2">
<label
htmlFor="situation-select"
className="text-sm font-medium text-gray-700"
>
Selectionner une situation
</label>
<select
id="situation-select"
value={activeSituation}
onChange={(e) => setSituation(e.target.value)}
className="block w-full md:w-64 px-3 py-2 bg-white border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-blue-500"
>
<option value=""></option>
{Object.keys(situations).map((situationName) => (
<option key={situationName} value={situationName}>
{situationName}
</option>
))}
</select>
</div>
</nav>
</div>
</header>
)
}
Empty file.
17 changes: 17 additions & 0 deletions quick-doc/src/components/RulesIndex.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { Link } from 'react-router-dom'
import { sitemap } from '../sitemap'

export function RulesIndex() {
return (
<div>
<h1>Index des règles</h1>
<ul>
{Object.entries(sitemap).map(([path, name]) => (
<li key={path}>
<Link to={path}>{name}</Link>
</li>
))}
</ul>
</div>
)
}
23 changes: 23 additions & 0 deletions quick-doc/src/engine.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import Engine from 'publicodes'

// Create a custom event for engine updates
const ENGINE_UPDATED = 'engine-updated'
const engineUpdate = new EventTarget()

export let engine = new Engine(__INJECTED_RULES__)

// Helper to subscribe to engine updates
export function onEngineUpdate(callback: () => void) {
engineUpdate.addEventListener(ENGINE_UPDATED, callback)
return () => engineUpdate.removeEventListener(ENGINE_UPDATED, callback)
}

if (import.meta.hot) {
import.meta.hot.on('rules-updated', (newRules) => {
const previousEngine = engine
engine = new Engine(newRules)
engine.setSituation(previousEngine.getSituation())
// Dispatch event to notify subscribers
engineUpdate.dispatchEvent(new Event(ENGINE_UPDATED))
})
}
9 changes: 9 additions & 0 deletions quick-doc/src/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import React from 'react'
import ReactDOM from 'react-dom/client'
import App from './components/App.js'

ReactDOM.createRoot(document.getElementById('root')!).render(
<React.StrictMode>
<App />
</React.StrictMode>,
)
6 changes: 6 additions & 0 deletions quick-doc/src/sitemap.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { getDocumentationSiteMap } from '@publicodes/react-ui'
import { engine } from './engine'
export const sitemap = getDocumentationSiteMap({
documentationPath: '',
engine,
})
15 changes: 15 additions & 0 deletions quick-doc/src/situations.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
export let situations = __INJECTED_SITUATIONS__
const situationUpdate = new EventTarget()
const SITUATION_UPDATED = 'situations-updated'

export function onSituationUpdate(callback: () => void) {
situationUpdate.addEventListener(SITUATION_UPDATED, callback)
return () => situationUpdate.removeEventListener(SITUATION_UPDATED, callback)
}

if (import.meta.hot) {
import.meta.hot.on('situations-updated', (newSituations) => {
situations = newSituations
situationUpdate.dispatchEvent(new Event(SITUATION_UPDATED))
})
}
24 changes: 24 additions & 0 deletions quick-doc/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
{
"compilerOptions": {
"target": "ES2020",
"useDefineForClassFields": true,
"lib": ["ES2020", "DOM", "DOM.Iterable"],
"module": "ESNext",
"skipLibCheck": true,

/* Bundler mode */
"moduleResolution": "bundler",
"allowImportingTsExtensions": true,
"resolveJsonModule": true,
"isolatedModules": true,
"noEmit": true,
"jsx": "react-jsx",

/* Linting */
"strict": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noFallthroughCasesInSwitch": true
},
"include": ["src"]
}
Loading

0 comments on commit 63903b2

Please sign in to comment.