Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/instantiator/reveal-on-next
Exploration of using Reveal.js (slide presentation framework) in a NextJS / React app
https://github.com/instantiator/reveal-on-next
Last synced: about 16 hours ago
JSON representation
Exploration of using Reveal.js (slide presentation framework) in a NextJS / React app
- Host: GitHub
- URL: https://github.com/instantiator/reveal-on-next
- Owner: instantiator
- License: mit
- Created: 2023-09-03T17:01:05.000Z (over 1 year ago)
- Default Branch: main
- Last Pushed: 2023-09-10T15:16:52.000Z (over 1 year ago)
- Last Synced: 2023-09-10T16:24:23.872Z (over 1 year ago)
- Language: TypeScript
- Size: 3.53 MB
- Stars: 0
- Watchers: 1
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# test-reveal-on-next
This is a simple application that allows the incorporation of a [Reveal.js](https://revealjs.com/) presentation into a [NextJS](https://nextjs.org/) / [React](https://react.dev/) application.
- NextJS / React web app
- Incoroporates Reveal slides as content
- HTML content is loaded from a remote (or local) URL
- React element inside the HTML content can be created as needed
- Slide show can be multiplexed between controller and clients
- Supports build and export that can be hosted statically (eg. with [GitHub Pages](https://pages.github.com/))Multiplexing allows the controller to update all the clients as it moves through the presentation. Effectively, they follow along...
![](docs/images/multiplexing-slides-1-and-2.gif)
## Test this app
If you've just cloned the repository, you probably need to install the node packages:
```bash
npm install
```Now you can launch the development server:
```bash
npm run dev
```It'll serve the application at: [localhost:3000](http://localhost:3000)
## Developer notes
The following notes outline an approach to developing a Next/React application that incorporates a Reveal presentation.
### Install node and npx
```bash
brew install node
npm install -g npx
```### Create the app
```bash
npx create-next-app@latest
```### Install `reveal.js`
There are a few react-reveal packages that wrap Reveal for React/Next applications, but they're a little out of date now (the latest was last updated 3 years ago), and aren't really suited to Next or server-side rendering without some extra work.
Install `reveal.js` directly:
```bash
npm install reveal.js
```### Create a presentation component
**See `components/Presentation.tsx`**
`reveal.js` will only run in a browser environment, as it needs access to client specific javascript objects, such as `navigator`. It also needs to be able to see the `div` elements with `reveal` and `slides` CSS classes, as soon as it is created. This code forces Next to only invoke it in a browser...
This is an invocation for Next - telling it that the component needs client-side rendering:
```tsx
"use client";
````Reveal` is only created inside a `useEffect` - which is called when the page and divs are ready.
The `embedded` option is set to true - and this helps to incorporate other layout and elements alongside the presentation. As the presentation no longer automatically fills the page, the `reveal` `div` will need to have its size specified in CSS...
_NB. The configuration also includes multiplex information and dependencies. See below for more information._
`Reveal` is only initialised once the content inside the presentation is ready. See below for details of how the content is retrieved and rendered.
### Modify `globals.css`
**See: `app/globals.css`**
The global CSS has been simplified and adjusted to help fit the presentation to the page. If you are using another framework, such as [MUI](https://mui.com/), you may need to solve this another way.
Here, you can see that `margin` and `padding` on `html` and `body` have been zeroed. This removes any whitespace around the edges of the page.
`body` has also been set to `display: flex` (in column direction), which will allow us to resize the presentation to fit below any layout above it.
### Import the presentation component
**See: `app/slides/page.tsx`**
`dynamic` is used to import the `Presentation` element dynamically, with `ssr: false` to prevent server-side rendering.
## Remote content
The `Presentation` element has a `src` parameter, and this is passed to an internal `PresentationContent` element which uses the [SWR](https://swr.vercel.app/) library to fetch the content. This content is then enriched (React elements are created where needed inside it), and then rendered inside the `Presentation`.
```bash
npm install swr
```### Dynamically creating React elements
Some of the content is regular HTML, but some of the elements are React components. There are a number of packages that might help us convert the HTML and manage React components:
| Library | Last updated |
| ------------------------------------------------------------------------ | ------------ |
| [html-react-parser](https://www.npmjs.com/package/html-react-parser) | recently |
| [html-to-react](https://www.npmjs.com/package/html-to-react) | recently |
| ~~[react-html-parser](https://www.npmjs.com/package/react-html-parser)~~ | 6 years ago |Install `html-react-parser`
```bash
npm install html-react-parser
```**NB.** `html-react-parser` is simple to use, but not XSS-safe, and should be used with caution. `PresentationContent` manages replacement of individual React elements by type:
```tsx
const options = {
replace: (domNode: any) => {
if (domNode instanceof Element && domNode.attribs) {
switch (domNode.tagName) {
case "question":
console.log("Enriching question tag...");
let question = domNode.attribs["question"];
let explanation = domNode.attribs["explanation"];
let instruction = domNode.attribs["instruction"];
if (question && explanation && instruction) {
return (
);
}
break;
}
}
},
};
```Here, `Question` also incorporates a `Rating` element, from: [react-rating](https://www.npmjs.com/package/react-rating)
```bash
npm install react-rating
```## Multiplexing
Multiplexing allows a controller presentation to send its state to client presentations on other devices (ie. to allow them to follow along).
There are 3 components:
- Any number of client presentations
- A controller\* presentation, with the same slides
- A socket.io based server that passes messages between the various presentations_\*Sometimes referred to as a master presentation._
### The server
This demo uses the server at: https://reveal-multiplex.glitch.me/
```tsx
const SOCKET_IO_SERVER = "https://reveal-multiplex.glitch.me/";
```- To test locally, you could also run your own server.
- A production system should host its own server.
- See: [reveal/multiplex](https://github.com/reveal/multiplex)### Client and controller
Install the multiplex plugin:
```bash
npm install reveal-multiplex
```The Presentation component in `presentation.tsx` accepts several parameters:
- `secret` (a secret to permit control, or `null` if acting as the client)
- `id` (the id of the presentation)
- `role` (not currently used)- To collect a fresh secret and id from the server, visit: https://reveal-multiplex.glitch.me/token
The multiplex plugin is configured during initialization of Reveal:
```tsx
multiplex: {
secret: secret,
id: id,
url: SOCKET_IO_SERVER
},
dependencies: [
{ src: 'https://reveal-multiplex.glitch.me/socket.io/socket.io.js', async: true },
{ src: 'https://reveal-multiplex.glitch.me/master.js', async: true },
{ src: 'https://reveal-multiplex.glitch.me/client.js', async: true },
]
```Because these dependencies rely on being able to find `Reveal` as a global variable, we also add this, just before initialization:
```tsx
window.Reveal = reveal;
```## Static builds
### Fix compiler issues
Not all imports agree on the version of React to use, and this can lead to difficulties with imported elements (such as the `Rating` element used in `Question.tsx`). In `tsconfig.json` add the following to `$.compilerOptions.paths` to enforce use of the same version:
```json
"react": ["./node_modules/@types/react"]
```In `Presentation.tsx`, `window.Reveal` is explicitly set to ensure that it is available to the multiplexing scripts imported as dependencies of `Reveal`. TypeScript is strict during a production build, and rejects this as it thinks `Reveal` is already the name of the module.
To instruct the compiler to overlook TypeScript errors, precede the line with `// @ts-ignore`, as here:
```tsx
// @ts-ignore
window.Reveal = reveal;
```### Build and export the project
Modify `next.config.js` to set `output` to `export`:
```js
const nextConfig = { output: "export" };
```Build the project:
```bash
npx next build
```Static output is put into the `out` directory by default.
## Hosting on GitHub pages
[GitHub Pages](https://pages.github.com/) can serve the static content either from the root directory of a repository, or from the `docs/` directory. You can place the output from `out` into another repository, and serve it from there by enabling GitHub Pages.
**However,** directories that are prefixed with `_` (underscore) are ignored by default. To work around this, add an empty file called `.nojekyll` at the root of the repository (see: [this blog post](https://github.blog/2009-12-29-bypassing-jekyll-on-github-pages/) about it).