diff --git a/.github/workflows/create-spectacle.yml b/.github/workflows/create-spectacle.yml index 982502bea..a9afd2ffd 100644 --- a/.github/workflows/create-spectacle.yml +++ b/.github/workflows/create-spectacle.yml @@ -5,14 +5,14 @@ on: branches: - main paths: - - ".github/workflows/create-spectacle.yml" - - "packages/create-spectacle/**" + - '.github/workflows/create-spectacle.yml' + - 'packages/create-spectacle/**' pull_request: branches: - main paths: - - ".github/workflows/create-spectacle.yml" - - "packages/create-spectacle/**" + - '.github/workflows/create-spectacle.yml' + - 'packages/create-spectacle/**' jobs: build: @@ -22,7 +22,7 @@ jobs: strategy: matrix: node-version: [18.x] - create-type: ['jsx', 'tsx', 'onepage'] + create-type: ['tsx', 'onepage'] steps: - uses: actions/checkout@v2 - uses: actions/setup-node@v2 diff --git a/docs/faq.md b/docs/faq.md index e8968081c..07fb39081 100644 --- a/docs/faq.md +++ b/docs/faq.md @@ -12,8 +12,8 @@ Yes - you can export your slides in PDF format. Appending your presentation URL If you want a black & white version of your slides printed to PDF, append your URL with `?exportMode=true&printMode=true` to get a printer-friendly, flattened, black & white print out of your slideshow. -For more info about the query parameters Spectacle supports, please check out our section about it in the [advanced concepts documentation](./advanced-concepts.md#query-parameters). +For more info about the query parameters Spectacle supports, please check out our section about it in the [presenting controls documentation](./presenting-controls#query-parameters). ## Can I write my presentation in TypeScript? -Yes - Spectacle types are shipped with the package, so you can safely use Spectacle in any `.ts` or `.js` presentation without a separate type definition import. +Yes—Spectacle types are shipped with the package, so you can safely use Spectacle in any `.ts` or `.js` presentation without a separate type definition import. TypeScript is now the default language for Spectacle and the `create-spectacle` CLI, so you can use it without any additional configuration. diff --git a/docs/index.md b/docs/index.md deleted file mode 100644 index d8cf24ce8..000000000 --- a/docs/index.md +++ /dev/null @@ -1,149 +0,0 @@ ---- -sidebar_label: Basic Concepts -order: 1 -sidebar_position: 1 -slug: / ---- - -# Basic Concepts - -## Installation - -Installing Spectacle is as quick as you'd expect. Install it using your package manager of choice. - -```bash -$ yarn add spectacle -# or -$ npm install --save spectacle -``` - -## Getting Started with Development - -The `src` directory contains all the source for the Spectacle library. All components designed to be part of the Spectacle API must be exported in `src/index.tsx`. - -#### JavaScript-based Decks - -To start the development server at port `3000` against a JavaScript-based deck (found in `examples/js`) use `yarn start:js` or `npm run start:js`. - -#### Markdown-based Decks - -To start the development server at port `3100` against a Markdown-based deck (found in `examples/md`) use `yarn start:md` or `npm run start:md`. - -## Writing your Presentation - -After installing Spectacle, all of your presentation and style logic will live in a main file, while your content exists either inline (with JSX) or in a separate markdown file (using MDX). - -### MDX/Markdown - -This approach involves statically generating your slides from a `.mdx` or .`md` file, which is accomplished with [`spectacle-cli`](https://www.github.com/FormidableLabs/spectacle-cli). With this package, you can either generate a new presentation (with the `spectacle-boilerplate` tool) or you can serve up an existing MDX/Markdown file as a presentation (with `spectacle -s`). It can be installed globally, locally, or used via `npx`. - -```bash -# globally install `spectacle` and `spectacle-boilerplate` tools -$ npm install --global spectacle-cli -$ yarn global add spectacle-cli - -# serving a presentation using npx -$ npx spectacle-cli - -# generating a new presentation using npx -$ npx -p spectacle-cli spectacle-boilerplate -``` - -To serve a local Markdown or MDX file up as a presentation with the CLI tool: - -```bash -# navigate to the directory containing your slides -$ cd my-cool-presentation - -# run the CLI (given there is a slides.md or slides.mdx in the CWD) -$ spectacle -s -``` - -To generate a new MDX or MD presentation using the boilerplate tool: - -```bash -$ spectacle-boilerplate -m mdx -$ spectacle-boilerplate -m md -``` - -To see a more complete examples of a presentation generated with MDX or Markdown, please check out our three samples available for use with the CLI as well as manual builds: - -- [`.md` Example](https://github.com/FormidableLabs/spectacle/tree/main/examples/md) (`spectacle`) -- [`.mdx` Example](https://github.com/FormidableLabs/spectacle-mdx-loader/tree/main/examples/mdx) (`spectacle-mdx-loader`) -- [`.mdx` + Babel Example](https://github.com/FormidableLabs/spectacle-cli/tree/main/examples/cli-mdx-babel) (`spectacle-cli`) - -For a more thorough understanding of the features and flags provided by the CLI, please see its [complete documentation](./extensions.md#spectacle-cli). - -**Note:** If you want to manually create the build infrastructure for MDX support in a Spectacle deck, you can add the [`spectacle-mdx-loader`](https://github.com/FormidableLabs/spectacle-mdx-loader) plugin to your webpack configuration. - -### JSX - -This approach is where you use the library's tags to compose your presentation. While you can mix in your own JSX syntax here, building your presentation with the supplied tags will allow for out-of-box themeing and layouts to work properly. - -The bare minimum you'll want to use to build your presentation are the `Deck` element and a `Slide` element. Each `Slide` represents a slide within your presentation `Deck` (the entire slideshow). - -To see a complete example of a presentation written in JSX, please check out our [sample JSX presentation](https://github.com/FormidableLabs/spectacle/blob/main/examples/js/index.js). - -You can also bootstrap a fresh JSX project with `spectacle-boilerplate`: - -```bash -$ spectacle-boilerplate -``` - -### One HTML Page - -To create a Spectacle presentation that lives in a single HTML page, you will only need to add a few scripts to your setup: - -```html - - - - - -``` - -... and then wrap your HTML in a declarative `module` script, like so: - -```html - -``` - -To see a complete example of a presentation written as a single HTML page, please check out our [sample one page presentation](https://github.com/FormidableLabs/spectacle/blob/main/examples/one-page/index.html). - -## Presenting - -Spectacle comes with a built-in presenter mode. It shows you a slide lookahead, your current slide, current time (or time elapsed), and any notes you've appended to your slide: - -![Screenshot of presenter mode in use](https://i.ibb.co/qsgYCkn/presentation-mode.png) - -To present: - -1. Run `yarn start`, which will open up a presentation at [localhost:3000/](http://localhost:3000/) by default. -2. Open a second browser window on a different screen. -3. Append [`?presenterMode=true`](http://localhost:3000/?presenterMode=true) immediately after the `/` -4. Give an amazingly in-sync and stylish presentation. - -**Note:** Any windows/tabs in the same browser running Spectacle will sync to one another, even if you aren't in presentation mode. - -![Gif of two screens presenting the same Spectacle presentation](https://i.ibb.co/jVBSRT9/presentation-mode.gif) diff --git a/docs/index.mdx b/docs/index.mdx new file mode 100644 index 000000000..62ef3ad95 --- /dev/null +++ b/docs/index.mdx @@ -0,0 +1,89 @@ +--- +title: Introduction +order: 1 +sidebar_position: 1 +--- + +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; +import defaultDeckImg from '../website/static/img/default-deck.png' +import presenterModeImg from '../website/static/img/presenter-mode.png' +import animatedPresentationImg from '../website/static/img/presentation-mode.gif' + +Spectacle is a React-based library for creating sleek presentations using React or Markdown that gives you the ability to live demo your code and use React libraries in your slides. + + + +## How to get started with Spectacle + + + + + The fastest and easiest way to get started with Spectacle is to use the Create Spectacle CLI. This will create a new Spectacle project with a default deck and all the necessary dependencies. + + There are four different kinds of templates you can use to create your Spectacle project: + + 1. ⚡️ **One Page** - A single HTML file using [htm](https://github.com/developit/htm) that self contains everything you need. Since it does not require a server to run your presentation, this is the recommended option for quickly spinning up a deck. + 2. 📄 **Markdown** - An app that uses Markdown for your presentation’s content with support for [Markdown Slide Layouts](md-slide-layouts). This is a React app that uses webpack and imports the Markdown content using Spectacle’s [`MarkdownSlideSet`](api-reference#markdown-components) component. + 3. 🏗️ **React using Vite** - An app that lets you build your presentation in React and uses Vite for building and running. This is the recommended option if you plan on using a number of additional npm libraries in your presentation. + 4. 🏗️ **React using webpack** - An app that lets you build your presentation in React and uses webpack for building and running. + + **To get started use `npx` or `pnpm dlx` to run the `create-spectacle` cli:** + + ```bash + + $ npx create-spectacle + + ``` + + This will create a new Spectacle presentation in a directory of your deck’s name or one page file in the current directory. + + + + + + 1. Install Spectacle by running `npm add spectacle`. + + 2. In your main entry file, return the following Spectacle starter: + + ```tsx + import { Deck, Slide, Heading, DefaultTemplate } from 'spectacle'; + + function App() { + return ( + }> + + Welcome to Spectacle + + + ); + } + + export default App; + ``` + + :::info + + If you are using NextJS with App Router, Spectacle needs to be rendered inside a client component. You can read more about this [here](https://nextjs.org/docs/app/building-your-application/rendering/client-components). + + ::: + + + + + +## Presenter Mode + +Spectacle also has a presenter mode that allows you to view your slides and notes on one screen while your audience views your slides on another. To use presenter mode, open a second browser window and visit your deck’s local server and enable it by using the key command. You can find more information about presentation controls [here](presenting-controls). + + + + + +## Documentation, Contributing, and Source + +For more information about Spectacle and its components, check out [the docs](https://formidable.com/open-source/spectacle). + +Interested in helping out or seeing what's happening under the hood? Spectacle is maintained [on Github](https://github.com/FormidableLabs/spectacle) and you can [start contributing here](https://github.com/FormidableLabs/spectacle/blob/main/CONTRIBUTING.md). + +For any questions, feel free to [open a new question on Github](https://github.com/FormidableLabs/spectacle/issues/new?template=question.md). diff --git a/docs/advanced-concepts.md b/docs/presenting-controls.mdx similarity index 50% rename from docs/advanced-concepts.md rename to docs/presenting-controls.mdx index a57ee3bd1..75dc93ac2 100644 --- a/docs/advanced-concepts.md +++ b/docs/presenting-controls.mdx @@ -1,28 +1,31 @@ --- -title: Advanced Concepts +title: Presenting Controls order: 2 sidebar_position: 2 --- -# Advanced Concepts +import commandBarImage from "../website/static/img/command-bar.png" -## Build & Deployment +# Presenting Controls -There are a variety of ways to host your Spectacle presentation. +Spectacle comes with a few keyboard shortcuts to help you navigate your presentation. These shortcuts are available in both the browser and the Presenter Mode. You can also use the command bar to see all available shortcuts. -1. If you are integrating this lib yourself, take your build and follow the linked instructions from any of (but not limited to) the following providers: [Netlify](https://docs.netlify.com/get-started/#deploy-a-project-to-netlify), [Vercel](https://vercel.com/docs/concepts/deployments/overview), or [Surge](https://surge.sh/help/deploying-continuously-using-git-hooks). +## Command Bar + +Pressing /Ctrl + k will open the command bar. This will show you all available keyboard shortcuts and common navigation options. + +Command Bar interface -2. If using `spectacle-cli` (either `spectacle --action build` or `spectacle-boilerplate` with `yarn clean && yarn build`) your output is `dist/` and upload that directory to any of the above static hosting providers. ## Keyboard Controls | Key Combination | Function | | --------------- | ---------------------- | -| Right Arrow | Next Slide | -| Left Arrow | Previous Slide | -| Alt/Option + O | Toggle Overview Mode | -| Alt/Option + P | Toggle Presenter Mode | -| Alt/Option + F | Toggle Fullscreen Mode | +| | Next Slide | +| | Previous Slide | +| /Alt + + O | Toggle Overview Mode | +| /Alt + + P | Toggle Presenter Mode | +| /Alt + + F | Toggle Fullscreen Mode | ## Query Parameters @@ -34,4 +37,4 @@ To combine parameters, use multiple `&` to separate the parameters, e.g.: `&expo | --------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------- | | `exportMode` | For exporting your presentation as a PDF. Add it to your project URL and "Save to PDF" directly from the browser | | `printMode` | Turns your slideshow into a printer-friendly, black & white version. Meant for use concurrently with `?exportMode` e.g. `?exportMode=true&printMode=true` | -| `presenterMode` | Displays a Presenter Mode for ease of presentation. For more info on this mode, please see [Presenting](./index.md#presenting) in our Basic Concepts doc | +| `presenterMode` | Displays a Presenter Mode with slide notes, a timer, and the upcoming slide. | diff --git a/docs/jsx-slide-layouts.md b/docs/react-slide-layouts.md similarity index 99% rename from docs/jsx-slide-layouts.md rename to docs/react-slide-layouts.md index 271a9b7fa..9c386bf12 100644 --- a/docs/jsx-slide-layouts.md +++ b/docs/react-slide-layouts.md @@ -1,5 +1,5 @@ --- -title: JSX Slide Layouts +title: React Slide Layouts order: 6 sidebar_position: 6 --- diff --git a/docs/tutorial.md b/docs/tutorial.md deleted file mode 100644 index 0eaad78a5..000000000 --- a/docs/tutorial.md +++ /dev/null @@ -1,162 +0,0 @@ ---- -title: Getting Started -order: 3 -sidebar_position: 3 ---- - -# Getting Started with Spectacle: A Tutorial - -In this guide, we'll show you a couple of different ways to get started with Spectacle and walk you through the creation and customization of a presentation deck. - -## Option One: Using Vite to bootstrap a React-based Spectacle app - -1. Spin up a new React project using [`vite`](https://vitejs.dev/guide/#scaffolding-your-first-vite-project): - - ```bash - npm create vite@latest my-spectacle-deck -- --template react-ts - ``` - -2. Install Spectacle by running `npm add spectacle`. - -3. In `App.tsx`, replace the boilerplate content with this Spectacle starter: - - ```tsx - import { Deck, Slide, Heading, DefaultTemplate } from 'spectacle'; - - function App() { - return ( - }> - - Welcome to Spectacle - - - ); - } - - export default App; - ``` - -## Option Two: Using Next.js App Router to bootstrap a React-based Spectacle app - -1. Spin up a new React project using [`create-next-app`](https://nextjs.org/docs/pages/api-reference/create-next-app): - - ```bash - npx create-next-app@latest - ``` - -2. Install Spectacle by running `npm add spectacle`. - -3. Create a `deck.tsx` file inside the `app` directory and add the following Spectacle starter: - - ```tsx - 'use client'; - - import { Deck, Slide, Heading, DefaultTemplate } from 'spectacle'; - - export const SpectacleDeck = () => { - return ( - }> - - Welcome to Spectacle - - - ); - }; - ``` - -4. In `app/page.tsx`, import the `` component: - - ```tsx - import { SpectacleDeck } from './deck'; - - export default function Home() { - return ; - } - ``` - -## Option Three: Using Markdown and the Spectacle CLI - -1. Create a new markdown file. You can use `.md` or `.mdx` (MDX lets you mix JSX components inside markdown). - - You can use this as a starter: - - ```md - # Welcome to Spectacle - - - This is a list item - - This is another list item - - --- - - # Second Slide - - Text can be **bold** or _italic_! - - Notes: These are presenter notes, only visible in presenter mode to the speaker. - ``` - - **Note:** The triple dash (`---`) is used as a slide delimiter. The `Notes:` keyword is used to embed presenter notes only visible to the speaker in presenter mode. - -2. To view your slides, supply your markdown to the Spectacle CLI to start a local web server. - - ```bash - $ npm install --global spectacle-cli - $ spectacle -s my-slides.mdx - ``` - -3. And you're good to go! The web server you started supports live refreshing and will update your deck as you make changes to the markdown file. - -## Option Four: Using One Page - -One Page is a single self-contained `HTML` file that lets you build a deck using no build steps, using [htm](https://github.com/developit/htm) over JSX to reduce the dependencies and load time. - -As a self-contained entity, it already has references to the dependencies you need to author and launch a deck in a web browser. Since there is no tooling required, One Page is also optimal on tablets. The One Page `HTML` file can be downloaded from the `examples` directory [in this repository](https://github.com/FormidableLabs/spectacle/blob/main/examples/one-page/index.html). - -## Next Steps - -### Styling your Spectacle Deck - -The easiest way to apply consistent styles to your Spectacle deck is using [themes](./themes.md). - -1. Create a theme JS file containing a single object export. Supplied properties will be merged with the default base theme (found in Spectacle at `src/theme/default-theme.js`). - - Here's a sample object: - - ```js - export default { - colors: { - primary: 'red', - secondary: 'green' - }, - fonts: { - header: '"Helvetica Neue", Helvetica, Arial, sans-serif' - }, - fontSizes: { - h1: '72px', - h2: '64px' - } - }; - ``` - -2. Consume the theme using the approach of your choice: - - a. To use a custom theme with a JSX- (Option One) or HTM- (Option Three) Deck, supply the object to the `theme` prop in the `Deck` tag. ``. - - b. To use a custom theme with the Markdown CLI (Option Two), supply the file using the `-t` argument. - - ```bash - $ npm install --global spectacle-cli - $ spectacle -s my-slides.mdx -t custom-theme.js - ``` - -### Sharing your Spectacle Deck - -For more information on [presenting](./index.md#presenting), [exporting](./advanced-concepts.md#exporting), [building](./advanced-concepts.md#build--deployment), or [deploying](./advanced-concepts.md#build--deployment) your Spectacle deck, please check out [the documentation on advanced concepts](./advanced-concepts.md). - -## Documentation, Contributing, and Source - -For more information about Spectacle and its components, check out [the docs](https://formidable.com/open-source/spectacle). - -Interested in helping out or seeing what's happening under the hood? Spectacle is maintained [on Github](https://github.com/FormidableLabs/spectacle) and you can [start contributing here](https://github.com/FormidableLabs/spectacle/blob/main/CONTRIBUTING.md). - -For any questions, feel free to [open a new question on Github](https://github.com/FormidableLabs/spectacle/issues/new?template=question.md). diff --git a/packages/create-spectacle/src/cli.test.ts b/packages/create-spectacle/src/cli.test.ts index f168b2632..2ffb5e688 100644 --- a/packages/create-spectacle/src/cli.test.ts +++ b/packages/create-spectacle/src/cli.test.ts @@ -70,20 +70,20 @@ describe('create-spectacle', () => { expect(await peakFile('webpack.config.js')).toContain('6969'); }); - it('generates jsx (webpack) deck with expected files', async () => { - await runCliWithArgs({ type: 'jsx' }); + it('generates a markdown deck with expected files', async () => { + await runCliWithArgs({ type: 'md', lang: 'foobar', port: 6969 }); - const files = await listFiles(); - expect(files).toEqual([ + expect(await listFiles()).toEqual([ '.babelrc', '.gitignore', 'README.md', 'index.html', - 'index.jsx', + 'index.tsx', 'package.json', + 'slides.md', + 'tsconfig.json', 'webpack.config.js' ]); - expect(files).not.toContain('tsconfig.json'); // package.json fields const pak = JSON.parse(await peakFile('package.json')); @@ -97,14 +97,32 @@ describe('create-spectacle', () => { expect(Object.keys(pak.dependencies)).toEqual( expect.arrayContaining(['spectacle', 'react', 'react-dom']) ); - expect(Object.keys(pak.devDependencies)).not.toContain([ - 'typescript', - '@types/react' - ]); + expect(Object.keys(pak.devDependencies)).toEqual( + expect.arrayContaining([ + '@babel/core', + '@babel/preset-env' /* ignoring a lot... */, + 'typescript', + '@types/react' + ]) + ); + + // README instructions for changing dist directory + expect(await peakFile('README.md')).toContain( + `\`output.path\` in \`webpack.config.js\`` + ); // Custom lang/port - expect(await peakFile('index.html')).toContain(`lang="en"`); - expect(await peakFile('webpack.config.js')).toContain('3000'); + expect(await peakFile('index.html')).toContain(`lang="foobar"`); + expect(await peakFile('slides.md')).toContain( + ` +--- { "layout" : "center" } +# my-deck + +--- +- Made with Spectacle + `.trim() + ); + expect(await peakFile('webpack.config.js')).toContain('6969'); }); it('generates tsx (vite) deck with expected files', async () => { @@ -158,55 +176,6 @@ describe('create-spectacle', () => { expect(pak.scripts.start).toContain('--port 6969'); }); - it('generates jsx (vite) deck with expected files', async () => { - await runCliWithArgs({ type: 'jsx-vite' }); - - expect(await listFiles()).toEqual([ - '.gitignore', - 'README.md', - 'index.html', - 'index.jsx', - 'package.json', - 'vite.config.js' - ]); - - // package.json fields - const pak = JSON.parse(await peakFile('package.json')); - expect(Object.keys(pak)).toEqual([ - 'name', - 'private', - 'scripts', - 'dependencies', - 'devDependencies' - ]); - expect(Object.keys(pak.dependencies)).toEqual( - expect.arrayContaining(['spectacle', 'react', 'react-dom']) - ); - expect(Object.keys(pak.devDependencies)).toEqual( - expect.arrayContaining([ - '@types/react', - '@types/react-dom', - '@vitejs/plugin-react' - ]) - ); - - // Vite config should have react plugin - expect(await peakFile('vite.config.js')).toContain('plugins: [react()]'); - // Vite index.html should have entry point - expect(await peakFile('index.html')).toContain( - `` - ); - - // README instructions for changing dist directory - expect(await peakFile('README.md')).toContain( - `\`build.outDir\` in \`vite.config.js` - ); - - // Custom lang/port - expect(await peakFile('index.html')).toContain(`lang="en"`); - expect(pak.scripts.start).toContain('--port 3000'); - }); - it('generates a onepage file', async () => { await runCliWithArgs({ type: 'onepage' }); @@ -224,7 +193,7 @@ describe('create-spectacle', () => { /** * Run the cli with certain args */ -type Type = 'tsx' | 'jsx' | 'tsx-vite' | 'jsx-vite' | 'onepage'; +type Type = 'tsx' | 'md' | 'tsx-vite' | 'onepage'; const runCliWithArgs = ({ type, lang = 'en', diff --git a/packages/create-spectacle/src/cli.ts b/packages/create-spectacle/src/cli.ts index 9dd41e9c8..b28faa30e 100644 --- a/packages/create-spectacle/src/cli.ts +++ b/packages/create-spectacle/src/cli.ts @@ -29,11 +29,10 @@ enum ArgName { } const DeckTypeOptions = [ - { title: 'tsx (webpack)', value: 'tsx' }, - { title: 'jsx (webpack)', value: 'jsx' }, - { title: 'tsx (vite)', value: 'tsx-vite' }, - { title: 'jsx (vite)', value: 'jsx-vite' }, - { title: 'One Page', value: 'onepage' } + { title: 'One Page', value: 'onepage' }, + { title: 'Markdown', value: 'md' }, + { title: 'React using Vite', value: 'tsx-vite' }, + { title: 'React using webpack', value: 'tsx' } ]; let progressInterval: NodeJS.Timer; @@ -176,17 +175,20 @@ const main = async () => { name, lang, port, - enableTypeScriptSupport: /^tsx/.test(type), isVite: /vite$/.test(type), spectacleVersion: devDependencies.spectacle }; switch (type) { - case 'jsx': + case 'md': + await writeWebpackProjectFiles({ + ...fileOptions, + useMarkdownSlides: true + }); + break; case 'tsx': await writeWebpackProjectFiles(fileOptions); break; - case 'jsx-vite': case 'tsx-vite': await writeViteProjectFiles(fileOptions); break; diff --git a/packages/create-spectacle/src/templates/babel.ts b/packages/create-spectacle/src/templates/babel.ts index 3ef7a2921..5955c33ec 100644 --- a/packages/create-spectacle/src/templates/babel.ts +++ b/packages/create-spectacle/src/templates/babel.ts @@ -1,11 +1,7 @@ -type BabelTemplateOptions = { - enableTypeScriptSupport: boolean; -}; - -export const babelTemplate = (options: BabelTemplateOptions) => +export const babelTemplate = () => `{ "presets": [ - ${options.enableTypeScriptSupport ? '"@babel/preset-typescript",' : ''} + "@babel/preset-typescript", ["@babel/preset-env", { "modules": false }], ["@babel/preset-react", { "runtime": "automatic" }] ], diff --git a/packages/create-spectacle/src/templates/file-writers.ts b/packages/create-spectacle/src/templates/file-writers.ts index 9d900a0d7..6a15773fd 100644 --- a/packages/create-spectacle/src/templates/file-writers.ts +++ b/packages/create-spectacle/src/templates/file-writers.ts @@ -10,20 +10,20 @@ import { gitignoreTemplate } from './gitignore'; import { readmeTemplate } from './readme'; import { viteConfigTemplate } from './viteConfig'; import { createOnePage } from '../generators/one-page'; +import { markdownTemplate } from './markdown'; export type FileOptions = { snakeCaseName: string; name: string; lang: string; port: number; - enableTypeScriptSupport: boolean; + useMarkdownSlides?: boolean; spectacleVersion: string; isVite: boolean; }; const prepForProjectWrite = async (fileOptions: FileOptions) => { - const { name, lang, snakeCaseName, enableTypeScriptSupport, isVite } = - fileOptions; + const { name, lang, snakeCaseName, isVite } = fileOptions; const outPath = path.resolve(process.cwd(), snakeCaseName); const pathFor = (file: string) => path.join(outPath, file); @@ -38,25 +38,21 @@ const prepForProjectWrite = async (fileOptions: FileOptions) => { htmlTemplate({ name, lang, - entryFile: isVite - ? `/index.${enableTypeScriptSupport ? 'tsx' : 'jsx'}` - : undefined + entryFile: isVite ? '/index.tsx' : undefined }) ); await writeFile( - pathFor(`index.${enableTypeScriptSupport ? 'tsx' : 'jsx'}`), + pathFor('index.tsx'), indexTemplate({ - usesTypeScript: enableTypeScriptSupport, - name + name, + usesMarkdown: fileOptions.useMarkdownSlides }) ); await writeFile(pathFor('.gitignore'), gitignoreTemplate()); - await writeFile( - pathFor('README.md'), - readmeTemplate({ name, enableTypeScriptSupport, isVite }) - ); - enableTypeScriptSupport && - (await writeFile(pathFor('tsconfig.json'), tsconfigTemplate())); + await writeFile(pathFor('README.md'), readmeTemplate({ name, isVite })); + await writeFile(pathFor('tsconfig.json'), tsconfigTemplate()); + fileOptions.useMarkdownSlides && + (await writeFile(pathFor('slides.md'), markdownTemplate({ name }))); return { outPath, pathFor }; }; @@ -65,22 +61,14 @@ const prepForProjectWrite = async (fileOptions: FileOptions) => { * Generate a webpack-based project */ export const writeWebpackProjectFiles = async (options: FileOptions) => { - const { port, enableTypeScriptSupport, snakeCaseName, spectacleVersion } = - options; + const { port, snakeCaseName, spectacleVersion } = options; const { pathFor } = await prepForProjectWrite(options); - await writeFile( - pathFor('webpack.config.js'), - webpackTemplate({ port, usesTypeScript: enableTypeScriptSupport }) - ); - await writeFile( - pathFor('.babelrc'), - babelTemplate({ enableTypeScriptSupport }) - ); + await writeFile(pathFor('webpack.config.js'), webpackTemplate({ port })); + await writeFile(pathFor('.babelrc'), babelTemplate()); await writeFile( pathFor('package.json'), packageTemplate({ - usesTypeScript: enableTypeScriptSupport, name: snakeCaseName, spectacleVersion }) @@ -91,24 +79,19 @@ export const writeWebpackProjectFiles = async (options: FileOptions) => { * Generate a vite-based project */ export const writeViteProjectFiles = async (options: FileOptions) => { - const { enableTypeScriptSupport, snakeCaseName, spectacleVersion, port } = - options; + const { snakeCaseName, spectacleVersion, port } = options; const { pathFor } = await prepForProjectWrite(options); await writeFile( pathFor('package.json'), vitePackageTemplate({ - usesTypeScript: enableTypeScriptSupport, name: snakeCaseName, spectacleVersion, port }) ); - await writeFile( - pathFor(`vite.config.${enableTypeScriptSupport ? 'ts' : 'js'}`), - viteConfigTemplate() - ); + await writeFile(pathFor(`vite.config.ts`), viteConfigTemplate()); }; /** diff --git a/packages/create-spectacle/src/templates/index.ts b/packages/create-spectacle/src/templates/index.ts index edd6284e5..3fa7aed13 100644 --- a/packages/create-spectacle/src/templates/index.ts +++ b/packages/create-spectacle/src/templates/index.ts @@ -1,31 +1,27 @@ type IndexTemplateOptions = { name: string; - usesTypeScript: boolean; + usesMarkdown: boolean; }; +const tsxImports = ` +import { Deck, DefaultTemplate, Slide, FlexBox, Heading, SpectacleLogo } from 'spectacle'; +`; + +const mdImports = ` +import { Deck, DefaultTemplate, MarkdownSlideSet } from 'spectacle'; +import mdContent from './slides.md'; +`; + export const indexTemplate = (options: IndexTemplateOptions) => `import React from 'react'; import { createRoot } from 'react-dom/client'; -import { Slide, Deck, FlexBox, Heading, SpectacleLogo, Box, FullScreen, AnimatedProgress } from 'spectacle'; - -const template = () => ( - - - - - - - - -); +${(options.usesMarkdown ? mdImports : tsxImports).trim()} const Presentation = () => ( - + }> + ${(options.usesMarkdown + ? `{mdContent}` + : ` ${options.name} @@ -37,10 +33,10 @@ const Presentation = () => ( + ` + ).trim()} ); -createRoot(document.getElementById('app')${ - options.usesTypeScript ? '!' : '' - }).render(); +createRoot(document.getElementById('app')!).render(); `; diff --git a/packages/create-spectacle/src/templates/markdown.ts b/packages/create-spectacle/src/templates/markdown.ts new file mode 100644 index 000000000..4e8cf4207 --- /dev/null +++ b/packages/create-spectacle/src/templates/markdown.ts @@ -0,0 +1,12 @@ +type TemplateOptions = { + name: string; +}; + +export const markdownTemplate = (options: TemplateOptions) => + ` +--- { "layout" : "center" } +# ${options.name} + +--- +- Made with Spectacle +`.trim(); diff --git a/packages/create-spectacle/src/templates/package.ts b/packages/create-spectacle/src/templates/package.ts index 9fbb651a4..2ed251435 100644 --- a/packages/create-spectacle/src/templates/package.ts +++ b/packages/create-spectacle/src/templates/package.ts @@ -1,7 +1,6 @@ type PackageTemplateOptions = { name: string; spectacleVersion: string; - usesTypeScript: boolean; port?: number; }; @@ -16,8 +15,8 @@ export const packageTemplate = (options: PackageTemplateOptions) => build: 'webpack --config ./webpack.config.js --mode production' }, dependencies: { - react: '^18.1.0', - 'react-dom': '^18.1.0', + react: '^18.2.0', + 'react-dom': '^18.2.0', spectacle: options.spectacleVersion === 'workspace:*' ? '*' @@ -38,14 +37,10 @@ export const packageTemplate = (options: PackageTemplateOptions) => webpack: '^5.68.0', 'webpack-cli': '^4.5.0', 'webpack-dev-server': '^4.7.4', - ...(options.usesTypeScript - ? { - typescript: '^4.5.2', - '@babel/preset-typescript': '^7.16.0', - '@types/react': '^18.0.12', - '@types/react-dom': '^18.0.5' - } - : {}) + typescript: '^5.3.3', + '@babel/preset-typescript': '^7.16.0', + '@types/react': '^18.0.12', + '@types/react-dom': '^18.0.5' } }, null, @@ -73,11 +68,7 @@ export const vitePackageTemplate = (options: PackageTemplateOptions) => '@types/react': '^18.0.17', '@types/react-dom': '^18.0.6', '@vitejs/plugin-react': '^2.0.1', - ...(options.usesTypeScript - ? { - typescript: '^4.6.4' - } - : {}), + typescript: '^5.3.3', vite: '^3.0.7' } }, diff --git a/packages/create-spectacle/src/templates/readme.ts b/packages/create-spectacle/src/templates/readme.ts index 05a51c554..00ca76d0b 100644 --- a/packages/create-spectacle/src/templates/readme.ts +++ b/packages/create-spectacle/src/templates/readme.ts @@ -1,14 +1,9 @@ type ReadmeTemplateOptions = { name: string; - enableTypeScriptSupport: boolean; isVite?: boolean; }; -export const readmeTemplate = ({ - name, - enableTypeScriptSupport, - isVite -}: ReadmeTemplateOptions) => +export const readmeTemplate = ({ name, isVite }: ReadmeTemplateOptions) => ` # ${name} @@ -18,19 +13,15 @@ Made with ❤️ and [Spectacle](https://github.com/FormidableLabs/spectacle/). - Run \`yarn install\` (or \`npm install\` or \`pnpm install\`) to install dependencies. - Run \`yarn start\` (or \`npm start\` or \`pnpm start\`) to start the presentation. -- Edit \`index.${ - enableTypeScriptSupport ? 'tsx' : 'jsx' - }\` to add your presentation content. - +- Edit \`index.tsx to add your presentation content. + ## Building you presentation To build your presentation for a production deploy, run \`yarn build\` (or \`npm build\` or \`pnpm build\`). The build artifacts will be placed in the \`dist\` directory. If you'd like to change this location, edit ${ isVite - ? `\`build.outDir\` in \`vite.config.${ - enableTypeScriptSupport ? 'ts' : 'js' - }\`` + ? `\`build.outDir\` in \`vite.config.ts\`` : `\`output.path\` in \`webpack.config.js\`` }. `.trim(); diff --git a/packages/create-spectacle/src/templates/webpack.ts b/packages/create-spectacle/src/templates/webpack.ts index 70c99c7a6..d8393d938 100644 --- a/packages/create-spectacle/src/templates/webpack.ts +++ b/packages/create-spectacle/src/templates/webpack.ts @@ -1,6 +1,5 @@ type WebpackTemplateOptions = { port: number; - usesTypeScript: boolean; }; export const webpackTemplate = (options: WebpackTemplateOptions) => @@ -10,7 +9,7 @@ const HtmlWebpackPlugin = require('html-webpack-plugin'); module.exports = { mode: 'development', context: __dirname, - entry: './index.${options.usesTypeScript ? 'tsx' : 'jsx'}', + entry: './index.tsx', output: { path: path.join(__dirname, '/dist'), filename: 'app.bundle.js' @@ -22,7 +21,8 @@ module.exports = { rules: [ { test: /\\.[tj]sx?$/, use: ['babel-loader'] }, { test: /\\.(png|svg|jpg|gif)$/, use: ['file-loader'] }, - { test: /\\.css$/, use: ['style-loader', 'css-loader'] } + { test: /\\.css$/, use: ['style-loader', 'css-loader'] }, + { test: /\\.md$/, use: [require.resolve('raw-loader')] } ] }, plugins: [ diff --git a/website/static/img/command-bar.png b/website/static/img/command-bar.png new file mode 100644 index 000000000..645580c07 Binary files /dev/null and b/website/static/img/command-bar.png differ diff --git a/website/static/img/default-deck.png b/website/static/img/default-deck.png new file mode 100644 index 000000000..a0aa1cae3 Binary files /dev/null and b/website/static/img/default-deck.png differ diff --git a/website/static/img/presentation-mode.gif b/website/static/img/presentation-mode.gif new file mode 100644 index 000000000..99a4fd1a0 Binary files /dev/null and b/website/static/img/presentation-mode.gif differ diff --git a/website/static/img/presenter-mode.png b/website/static/img/presenter-mode.png new file mode 100644 index 000000000..1a13af7ee Binary files /dev/null and b/website/static/img/presenter-mode.png differ