Re-creation of marp.app (#36)
* Re-creation of marp.app * Set correct host in Netlify's deploy preview * Prevent purging Tailwind classes used in utils * Update glob path for purging CSS * Don't build a docs page working in progress
@ -1,82 +0,0 @@
|
|||||||
version: 2.1
|
|
||||||
|
|
||||||
executors:
|
|
||||||
node:
|
|
||||||
parameters:
|
|
||||||
version:
|
|
||||||
type: string
|
|
||||||
default: lts
|
|
||||||
docker:
|
|
||||||
- image: circleci/node:<< parameters.version >>
|
|
||||||
working_directory: ~/marp
|
|
||||||
|
|
||||||
commands:
|
|
||||||
install:
|
|
||||||
parameters:
|
|
||||||
postinstall:
|
|
||||||
type: steps
|
|
||||||
default: []
|
|
||||||
yarn:
|
|
||||||
type: string
|
|
||||||
default: 1.22.4
|
|
||||||
steps:
|
|
||||||
- run:
|
|
||||||
name: Upgrade yarn for current user
|
|
||||||
command: cd ~ && yarn policies set-version << parameters.yarn >>
|
|
||||||
|
|
||||||
- restore_cache:
|
|
||||||
keys:
|
|
||||||
- v2.2-dependencies-{{ .Environment.CIRCLE_JOB }}-{{ checksum "yarn.lock" }}-{{ .Branch }}
|
|
||||||
- v2.2-dependencies-{{ .Environment.CIRCLE_JOB }}-{{ checksum "yarn.lock" }}-
|
|
||||||
- v2.2-dependencies-{{ .Environment.CIRCLE_JOB }}-
|
|
||||||
|
|
||||||
- run: yarn install
|
|
||||||
- steps: << parameters.postinstall >>
|
|
||||||
|
|
||||||
- save_cache:
|
|
||||||
key: v2.2-dependencies-{{ .Environment.CIRCLE_JOB }}-{{ checksum "yarn.lock" }}-{{ .Branch }}
|
|
||||||
paths:
|
|
||||||
- ~/.cache/yarn
|
|
||||||
|
|
||||||
audit:
|
|
||||||
steps:
|
|
||||||
- checkout
|
|
||||||
- install:
|
|
||||||
postinstall:
|
|
||||||
- run: yarn audit
|
|
||||||
|
|
||||||
test:
|
|
||||||
steps:
|
|
||||||
- run: node --version
|
|
||||||
|
|
||||||
- checkout
|
|
||||||
- install
|
|
||||||
|
|
||||||
- run:
|
|
||||||
name: Prettier formatting
|
|
||||||
command: yarn check:format
|
|
||||||
|
|
||||||
- run:
|
|
||||||
name: ESLint
|
|
||||||
command: yarn lint
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
audit:
|
|
||||||
executor: node
|
|
||||||
steps:
|
|
||||||
- audit
|
|
||||||
|
|
||||||
test-node:
|
|
||||||
executor:
|
|
||||||
name: node
|
|
||||||
version: '12.16.3' # Specify LTS version for development
|
|
||||||
steps:
|
|
||||||
- test
|
|
||||||
|
|
||||||
workflows:
|
|
||||||
test:
|
|
||||||
jobs:
|
|
||||||
- audit
|
|
||||||
- test-node:
|
|
||||||
requires:
|
|
||||||
- audit
|
|
@ -1,4 +1,5 @@
|
|||||||
.cache/
|
.next
|
||||||
dist
|
coverage
|
||||||
|
lib
|
||||||
node_modules
|
node_modules
|
||||||
tmp
|
out
|
||||||
|
40
.eslintrc.js
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
const path = require('path')
|
||||||
|
const { workspaces } = require('./package.json')
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
root: true,
|
||||||
|
env: {
|
||||||
|
browser: true,
|
||||||
|
node: true,
|
||||||
|
},
|
||||||
|
extends: ['eslint:recommended', 'plugin:import/recommended', 'prettier'],
|
||||||
|
rules: {
|
||||||
|
'import/order': ['error', { alphabetize: { order: 'asc' } }],
|
||||||
|
},
|
||||||
|
overrides: [
|
||||||
|
{
|
||||||
|
files: ['**/*.ts', '**/*.tsx'],
|
||||||
|
parser: '@typescript-eslint/parser',
|
||||||
|
plugins: ['@typescript-eslint'],
|
||||||
|
extends: [
|
||||||
|
'plugin:@typescript-eslint/recommended',
|
||||||
|
'plugin:import/typescript',
|
||||||
|
'prettier/@typescript-eslint',
|
||||||
|
],
|
||||||
|
rules: {
|
||||||
|
'@typescript-eslint/no-explicit-any': 'off',
|
||||||
|
'@typescript-eslint/explicit-function-return-type': 'off',
|
||||||
|
'@typescript-eslint/explicit-module-boundary-types': 'off',
|
||||||
|
},
|
||||||
|
settings: {
|
||||||
|
'import/resolver': {
|
||||||
|
typescript: {
|
||||||
|
project: ['', ...workspaces].map((dir) =>
|
||||||
|
path.join(dir, 'tsconfig.json')
|
||||||
|
),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
@ -1,29 +0,0 @@
|
|||||||
env:
|
|
||||||
browser: true
|
|
||||||
es6: true
|
|
||||||
node: true
|
|
||||||
|
|
||||||
extends:
|
|
||||||
- eslint:recommended
|
|
||||||
- plugin:import/recommended
|
|
||||||
- plugin:import/react
|
|
||||||
- plugin:react/recommended
|
|
||||||
- prettier
|
|
||||||
- prettier/react
|
|
||||||
|
|
||||||
root: true
|
|
||||||
|
|
||||||
settings:
|
|
||||||
import/resolver:
|
|
||||||
node:
|
|
||||||
extensions:
|
|
||||||
- .js
|
|
||||||
- .jsx
|
|
||||||
react:
|
|
||||||
version: detect
|
|
||||||
|
|
||||||
rules:
|
|
||||||
import/order:
|
|
||||||
- error
|
|
||||||
- alphabetize:
|
|
||||||
order: asc
|
|
21
.github/dependabot.yml
vendored
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
version: 2
|
||||||
|
|
||||||
|
updates:
|
||||||
|
- package-ecosystem: npm
|
||||||
|
directory: '/'
|
||||||
|
reviewers:
|
||||||
|
- 'marp-team/maintainers'
|
||||||
|
schedule:
|
||||||
|
interval: daily
|
||||||
|
allow:
|
||||||
|
- dependency-name: '@marp-team/*'
|
||||||
|
versioning-strategy: increase
|
||||||
|
|
||||||
|
- package-ecosystem: github-actions
|
||||||
|
directory: '/'
|
||||||
|
reviewers:
|
||||||
|
- 'marp-team/maintainers'
|
||||||
|
schedule:
|
||||||
|
interval: weekly
|
||||||
|
# versioning-strategy: increase-if-necessary
|
||||||
|
open-pull-requests-limit: 0 # Dependabot does not allow relaxed versioning :(
|
54
.github/workflows/test.yml
vendored
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
name: Test
|
||||||
|
|
||||||
|
on:
|
||||||
|
- pull_request
|
||||||
|
- push
|
||||||
|
|
||||||
|
env:
|
||||||
|
CACHE_PREFIX: v1
|
||||||
|
YARN_VERSION: '^1.22.4'
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
validate:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
if: ${{ github.ref == 'refs/heads/master' || !startsWith(github.event.head_commit.message, '[ci skip]') }}
|
||||||
|
steps:
|
||||||
|
- run: echo "${{ github.event.head_commit.message }}"
|
||||||
|
|
||||||
|
test:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
needs: validate
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
|
||||||
|
- name: Detect Node version from .nvmrc
|
||||||
|
id: node_version
|
||||||
|
run: echo "::set-output name=nvmrc::$(cat .nvmrc)"
|
||||||
|
|
||||||
|
- uses: actions/setup-node@v2-beta
|
||||||
|
with:
|
||||||
|
node-version: ${{ steps.node_version.outputs.nvmrc }}
|
||||||
|
|
||||||
|
- name: Install yarn
|
||||||
|
id: yarn
|
||||||
|
run: |
|
||||||
|
cd $HOME && yarn policies set-version $YARN_VERSION
|
||||||
|
echo "::set-output name=cache_dir::$(yarn cache dir)"
|
||||||
|
|
||||||
|
- uses: actions/cache@v2
|
||||||
|
with:
|
||||||
|
path: ${{ steps.yarn.outputs.cache_dir }}
|
||||||
|
key: yarn_cache-${{ env.CACHE_PREFIX }}-${{ hashFiles('**/yarn.lock') }}
|
||||||
|
restore-keys: yarn_cache-${{ env.CACHE_PREFIX }}-
|
||||||
|
|
||||||
|
- run: yarn install
|
||||||
|
- run: yarn audit
|
||||||
|
|
||||||
|
- name: Prettier formatting
|
||||||
|
run: yarn check:format
|
||||||
|
|
||||||
|
- name: ESLint
|
||||||
|
run: yarn lint:js
|
||||||
|
|
||||||
|
- name: TypeScript type checking
|
||||||
|
run: yarn check:ts
|
66
.gitignore
vendored
@ -1,6 +1,7 @@
|
|||||||
tmp
|
out
|
||||||
|
|
||||||
# Created by https://www.gitignore.io/api/node,windows,macos,linux,sublimetext,emacs,vim,visualstudiocode
|
# Created by https://www.toptal.com/developers/gitignore/api/node,windows,macos,linux,sublimetext,emacs,vim,visualstudiocode
|
||||||
|
# Edit at https://www.toptal.com/developers/gitignore?templates=node,windows,macos,linux,sublimetext,emacs,vim,visualstudiocode
|
||||||
|
|
||||||
### Emacs ###
|
### Emacs ###
|
||||||
# -*- mode: gitignore; -*-
|
# -*- mode: gitignore; -*-
|
||||||
@ -49,6 +50,10 @@ flycheck_*.el
|
|||||||
# directory configuration
|
# directory configuration
|
||||||
.dir-locals.el
|
.dir-locals.el
|
||||||
|
|
||||||
|
# network security
|
||||||
|
/network-security.data
|
||||||
|
|
||||||
|
|
||||||
### Linux ###
|
### Linux ###
|
||||||
|
|
||||||
# temporary files which can be created if a process still has a handle open of a deleted file
|
# temporary files which can be created if a process still has a handle open of a deleted file
|
||||||
@ -98,6 +103,10 @@ logs
|
|||||||
npm-debug.log*
|
npm-debug.log*
|
||||||
yarn-debug.log*
|
yarn-debug.log*
|
||||||
yarn-error.log*
|
yarn-error.log*
|
||||||
|
lerna-debug.log*
|
||||||
|
|
||||||
|
# Diagnostic reports (https://nodejs.org/api/report.html)
|
||||||
|
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
|
||||||
|
|
||||||
# Runtime data
|
# Runtime data
|
||||||
pids
|
pids
|
||||||
@ -110,11 +119,12 @@ lib-cov
|
|||||||
|
|
||||||
# Coverage directory used by tools like istanbul
|
# Coverage directory used by tools like istanbul
|
||||||
coverage
|
coverage
|
||||||
|
*.lcov
|
||||||
|
|
||||||
# nyc test coverage
|
# nyc test coverage
|
||||||
.nyc_output
|
.nyc_output
|
||||||
|
|
||||||
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
|
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
|
||||||
.grunt
|
.grunt
|
||||||
|
|
||||||
# Bower dependency directory (https://bower.io/)
|
# Bower dependency directory (https://bower.io/)
|
||||||
@ -133,12 +143,21 @@ jspm_packages/
|
|||||||
# TypeScript v1 declaration files
|
# TypeScript v1 declaration files
|
||||||
typings/
|
typings/
|
||||||
|
|
||||||
|
# TypeScript cache
|
||||||
|
*.tsbuildinfo
|
||||||
|
|
||||||
# Optional npm cache directory
|
# Optional npm cache directory
|
||||||
.npm
|
.npm
|
||||||
|
|
||||||
# Optional eslint cache
|
# Optional eslint cache
|
||||||
.eslintcache
|
.eslintcache
|
||||||
|
|
||||||
|
# Microbundle cache
|
||||||
|
.rpt2_cache/
|
||||||
|
.rts2_cache_cjs/
|
||||||
|
.rts2_cache_es/
|
||||||
|
.rts2_cache_umd/
|
||||||
|
|
||||||
# Optional REPL history
|
# Optional REPL history
|
||||||
.node_repl_history
|
.node_repl_history
|
||||||
|
|
||||||
@ -150,21 +169,41 @@ typings/
|
|||||||
|
|
||||||
# dotenv environment variables file
|
# dotenv environment variables file
|
||||||
.env
|
.env
|
||||||
|
.env.test
|
||||||
|
|
||||||
# parcel-bundler cache (https://parceljs.org/)
|
# parcel-bundler cache (https://parceljs.org/)
|
||||||
.cache
|
.cache
|
||||||
|
|
||||||
# next.js build output
|
# Next.js build output
|
||||||
.next
|
.next
|
||||||
|
|
||||||
# nuxt.js build output
|
# Nuxt.js build / generate output
|
||||||
.nuxt
|
.nuxt
|
||||||
|
dist
|
||||||
|
|
||||||
|
# Gatsby files
|
||||||
|
.cache/
|
||||||
|
# Comment in the public line in if your project uses Gatsby and not Next.js
|
||||||
|
# https://nextjs.org/blog/next-9-1#public-directory-support
|
||||||
|
# public
|
||||||
|
|
||||||
# vuepress build output
|
# vuepress build output
|
||||||
.vuepress/dist
|
.vuepress/dist
|
||||||
|
|
||||||
# Serverless directories
|
# Serverless directories
|
||||||
.serverless
|
.serverless/
|
||||||
|
|
||||||
|
# FuseBox cache
|
||||||
|
.fusebox/
|
||||||
|
|
||||||
|
# DynamoDB Local files
|
||||||
|
.dynamodb/
|
||||||
|
|
||||||
|
# TernJS port file
|
||||||
|
.tern-port
|
||||||
|
|
||||||
|
# Stores VSCode versions used for testing VSCode extensions
|
||||||
|
.vscode-test
|
||||||
|
|
||||||
### SublimeText ###
|
### SublimeText ###
|
||||||
# Cache files for Sublime Text
|
# Cache files for Sublime Text
|
||||||
@ -201,6 +240,7 @@ GitHub.sublime-settings
|
|||||||
### Vim ###
|
### Vim ###
|
||||||
# Swap
|
# Swap
|
||||||
[._]*.s[a-v][a-z]
|
[._]*.s[a-v][a-z]
|
||||||
|
!*.svg # comment out if you don't need vector files
|
||||||
[._]*.sw[a-p]
|
[._]*.sw[a-p]
|
||||||
[._]s[a-rt-v][a-z]
|
[._]s[a-rt-v][a-z]
|
||||||
[._]ss[a-gi-z]
|
[._]ss[a-gi-z]
|
||||||
@ -208,6 +248,7 @@ GitHub.sublime-settings
|
|||||||
|
|
||||||
# Session
|
# Session
|
||||||
Session.vim
|
Session.vim
|
||||||
|
Sessionx.vim
|
||||||
|
|
||||||
# Temporary
|
# Temporary
|
||||||
.netrwhist
|
.netrwhist
|
||||||
@ -218,14 +259,16 @@ tags
|
|||||||
|
|
||||||
### VisualStudioCode ###
|
### VisualStudioCode ###
|
||||||
.vscode/*
|
.vscode/*
|
||||||
!.vscode/settings.json
|
*.code-workspace
|
||||||
!.vscode/tasks.json
|
|
||||||
!.vscode/launch.json
|
### VisualStudioCode Patch ###
|
||||||
!.vscode/extensions.json
|
# Ignore all local history of files
|
||||||
|
.history
|
||||||
|
|
||||||
### Windows ###
|
### Windows ###
|
||||||
# Windows thumbnail cache files
|
# Windows thumbnail cache files
|
||||||
Thumbs.db
|
Thumbs.db
|
||||||
|
Thumbs.db:encryptable
|
||||||
ehthumbs.db
|
ehthumbs.db
|
||||||
ehthumbs_vista.db
|
ehthumbs_vista.db
|
||||||
|
|
||||||
@ -248,5 +291,4 @@ $RECYCLE.BIN/
|
|||||||
# Windows shortcuts
|
# Windows shortcuts
|
||||||
*.lnk
|
*.lnk
|
||||||
|
|
||||||
|
# End of https://www.toptal.com/developers/gitignore/api/node,windows,macos,linux,sublimetext,emacs,vim,visualstudiocode
|
||||||
# End of https://www.gitignore.io/api/node,windows,macos,linux,sublimetext,emacs,vim,visualstudiocode
|
|
||||||
|
@ -1,6 +1,3 @@
|
|||||||
.git/
|
.next
|
||||||
.cache/
|
|
||||||
.vscode/
|
|
||||||
dist
|
|
||||||
node_modules
|
node_modules
|
||||||
tmp
|
out
|
||||||
|
2
LICENSE
@ -1,6 +1,6 @@
|
|||||||
MIT License
|
MIT License
|
||||||
|
|
||||||
Copyright (c) 2018- Marp team (marp-team@marp.app)
|
Copyright (c) 2018-2020 Marp team (marp-team@marp.app)
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
of this software and associated documentation files (the "Software"), to deal
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
67
README.md
@ -1,6 +1,6 @@
|
|||||||
<div align="center">
|
<div align="center">
|
||||||
<p>
|
<p>
|
||||||
<img src="marp.png" alt="Marp" width="500" />
|
<a href="https://marp.app/"><img src="marp.png" alt="Marp" width="500" /></a>
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
<strong>Marp</strong>: Markdown Presentation Ecosystem
|
<strong>Marp</strong>: Markdown Presentation Ecosystem
|
||||||
@ -9,72 +9,85 @@
|
|||||||
|
|
||||||
**Marp** is the ecosystem to write your presentation with plain Markdown.
|
**Marp** is the ecosystem to write your presentation with plain Markdown.
|
||||||
|
|
||||||
|
<div align="center">
|
||||||
|
|
||||||
|
### [Go to the official website ▶︎](https://marp.app)
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
## Marp family
|
## Marp family
|
||||||
|
|
||||||
Our project is spread over many repos in order to focus on a limited scope per repository. Active projects are shown as emphasized in following list.
|
Our project is spread over many repos in order to focus on a limited scope per repository.
|
||||||
|
|
||||||
This repo (**[@marp-team/marp][marp]**) is an entrance to the Marp family, and places [our website](https://marp.app/).
|
This repo (**[marp-team/marp][marp]**) is an entrance to the Marp family, and places [our website](https://marp.app/) in `/website`.
|
||||||
|
|
||||||
### Framework / Core
|
### Framework / Core
|
||||||
|
|
||||||
| Name | Description | Release |
|
| Name | Description | Release |
|
||||||
| -------------------------: | :--------------------------------------------------------------------------------- | :-------------------------------------------------------- |
|
| -------------------------: | :------------------------------------------------------------------------------------------ | :-------------------------------------------------------- |
|
||||||
| **[Marpit]** | The skinny framework for creating slide deck from Markdown. ([marpit.marp.app]) | [![@marp-team/marpit][badge-marpit]][marpit-npm] |
|
| **[Marpit]** | The skinny framework for creating slide deck from Markdown. ([marpit.marp.app]) | [![@marp-team/marpit][badge-marpit]][marpit-npm] |
|
||||||
| **[Marp Core][marp-core]** | The core of Marp converter with practical features and [themes][marp-core-themes]. | [![@marp-team/marp-core][badge-marp-core]][marp-core-npm] |
|
| **[Marp Core][marp-core]** | The core of Marp converter with practical features and [built-in themes][marp-core-themes]. | [![@marp-team/marp-core][badge-marp-core]][marp-core-npm] |
|
||||||
|
|
||||||
### Apps
|
### Apps
|
||||||
|
|
||||||
| Name | Description | Release |
|
| Name | Description | Release |
|
||||||
| -----------------------: | :----------------------------------------------------------------------------------------------- | :----------------------------------------------------- |
|
| -----------------------: | :----------------------------------------------------------------------------------------------- | :----------------------------------------------------- |
|
||||||
| **[Marp CLI][marp-cli]** | [Marp Core][marp-core] / [Marpit]'s CLI interface to convert into HTML, PDF, PPTX, and image(s). | [![@marp-team/marp-cli][badge-marp-cli]][marp-cli-npm] |
|
| **[Marp CLI][marp-cli]** | [Marp Core][marp-core] / [Marpit]'s CLI interface to convert into HTML, PDF, PPTX, and image(s). | [![@marp-team/marp-cli][badge-marp-cli]][marp-cli-npm] |
|
||||||
| [Marp Web][marp-web] | The main interface of Marp based on [PWA] and [Preact] framework. | [![tech demo][badge-marp-web]][marp-web-site] |
|
|
||||||
| Marp Desktop | The desktop client for [Marp Web][marp-web-site] for replacing [yhatt/marp]. | ![PLANNED][badge-planned] |
|
|
||||||
|
|
||||||
### Integrations
|
### Integrations
|
||||||
|
|
||||||
| Name | Description | Release |
|
| Name | Description | Release |
|
||||||
| -----------------------------: | :-------------------------------------------------------------------------------- | :----------------------------------------------------------- |
|
| ----------------------------------: | :-------------------------------------------------------------------------------- | :---------------------------------------------------------- |
|
||||||
| **[Marp VSCode][marp-vscode]** | A [VS Code][vscode] extension to preview the slide deck written in Marp Markdown. | [![VS Marketplace][badge-marp-vscode]][marp-vscode-release] |
|
| **[Marp for VS Code][marp-vscode]** | A [VS Code][vscode] extension to preview the slide deck written in Marp Markdown. | [![VS Marketplace][badge-marp-vscode]][marp-vscode-release] |
|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary><b>See outdated/inactive projects...</b></summary><br />
|
||||||
|
|
||||||
|
| Name | Description | Release |
|
||||||
|
| -----------------------: | :--------------------------------------------------------------- | :----------------------------------------------------------- |
|
||||||
|
| [Marp Web][marp-web] | The Web interface of Marp based on [PWA] and [Preact] framework. | [![tech demo][badge-marp-web]][marp-web-site] |
|
||||||
| [Marp React][marp-react] | Marp renderer component for [React]. | [![@marp-team/marp-react][badge-marp-react]][marp-react-npm] |
|
| [Marp React][marp-react] | Marp renderer component for [React]. | [![@marp-team/marp-react][badge-marp-react]][marp-react-npm] |
|
||||||
| [Marp Vue][marp-vue] | Marp renderer component for [Vue]. | [![@marp-team/marp-vue][badge-marp-vue]][marp-vue-npm] |
|
| [Marp Vue][marp-vue] | Marp renderer component for [Vue]. | [![@marp-team/marp-vue][badge-marp-vue]][marp-vue-npm] |
|
||||||
|
|
||||||
|
And there is a gravesite of classic Marp app in https://github.com/yhatt/marp. :ghost:
|
||||||
|
|
||||||
|
[marp-web]: https://github.com/marp-team/marp-web
|
||||||
|
[marp-react]: https://github.com/marp-team/marp-react
|
||||||
|
[marp-vue]: https://github.com/marp-team/marp-vue
|
||||||
|
[pwa]: https://en.wikipedia.org/wiki/Progressive_Web_Apps
|
||||||
|
[preact]: https://preactjs.com/
|
||||||
|
[react]: https://reactjs.org/
|
||||||
|
[vue]: https://vuejs.org/
|
||||||
|
[marp-web-site]: https://web.marp.app/
|
||||||
|
[marp-react-npm]: https://www.npmjs.com/package/@marp-team/marp-react
|
||||||
|
[marp-vue-npm]: https://www.npmjs.com/package/@marp-team/marp-vue
|
||||||
|
[badge-marp-web]: https://img.shields.io/badge/%E2%80%8B-tech%20demo-%230288d1.svg?style=flat-square&logo=data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA4AAAAOCAYAAAAfSC3RAAAAUUlEQVQokWNgGD6AqePif3Sx9B2PMcQwNKFrTN/x+D9ejTBNyBphmnBqRNYE04isCatGdE1MHRf/o2vC0IhNE1PaXPwacWnCqxGfJoI2Dn4AAN0ZrMM1VUFvAAAAAElFTkSuQmCC
|
||||||
|
[badge-marp-react]: https://img.shields.io/npm/v/@marp-team/marp-react.svg?style=flat-square&logo=npm
|
||||||
|
[badge-marp-vue]: https://img.shields.io/npm/v/@marp-team/marp-vue.svg?style=flat-square&logo=npm
|
||||||
|
|
||||||
|
</details>
|
||||||
|
|
||||||
[yhatt/marp]: https://github.com/yhatt/marp
|
[yhatt/marp]: https://github.com/yhatt/marp
|
||||||
[marp]: https://github.com/marp-team/marp
|
[marp]: https://github.com/marp-team/marp
|
||||||
[marpit]: https://github.com/marp-team/marpit
|
[marpit]: https://github.com/marp-team/marpit
|
||||||
[marp-core]: https://github.com/marp-team/marp-core
|
[marp-core]: https://github.com/marp-team/marp-core
|
||||||
[marp-core-themes]: https://github.com/marp-team/marp-core/tree/master/themes
|
[marp-core-themes]: https://github.com/marp-team/marp-core/tree/master/themes
|
||||||
[marp-cli]: https://github.com/marp-team/marp-cli
|
[marp-cli]: https://github.com/marp-team/marp-cli
|
||||||
[marp-web]: https://github.com/marp-team/marp-web
|
|
||||||
[marp-vscode]: https://github.com/marp-team/marp-vscode
|
[marp-vscode]: https://github.com/marp-team/marp-vscode
|
||||||
[marp-react]: https://github.com/marp-team/marp-react
|
|
||||||
[marp-vue]: https://github.com/marp-team/marp-vue
|
|
||||||
[pwa]: https://en.wikipedia.org/wiki/Progressive_Web_Apps
|
|
||||||
[preact]: https://preactjs.com/
|
|
||||||
[electron]: https://electronjs.org/
|
|
||||||
[vscode]: https://code.visualstudio.com/
|
[vscode]: https://code.visualstudio.com/
|
||||||
[react]: https://reactjs.org/
|
|
||||||
[vue]: https://vuejs.org/
|
|
||||||
[marpit.marp.app]: https://marpit.marp.app/
|
[marpit.marp.app]: https://marpit.marp.app/
|
||||||
[marpit-npm]: https://www.npmjs.com/package/@marp-team/marpit
|
[marpit-npm]: https://www.npmjs.com/package/@marp-team/marpit
|
||||||
[marp-core-npm]: https://www.npmjs.com/package/@marp-team/marp-core
|
[marp-core-npm]: https://www.npmjs.com/package/@marp-team/marp-core
|
||||||
[marp-cli-npm]: https://www.npmjs.com/package/@marp-team/marp-cli
|
[marp-cli-npm]: https://www.npmjs.com/package/@marp-team/marp-cli
|
||||||
[marp-web-site]: https://web.marp.app/
|
|
||||||
[marp-vscode-release]: https://marketplace.visualstudio.com/items?itemName=marp-team.marp-vscode
|
[marp-vscode-release]: https://marketplace.visualstudio.com/items?itemName=marp-team.marp-vscode
|
||||||
[marp-react-npm]: https://www.npmjs.com/package/@marp-team/marp-react
|
|
||||||
[marp-vue-npm]: https://www.npmjs.com/package/@marp-team/marp-vue
|
|
||||||
[badge-marpit]: https://img.shields.io/npm/v/@marp-team/marpit.svg?style=flat-square&logo=npm
|
[badge-marpit]: https://img.shields.io/npm/v/@marp-team/marpit.svg?style=flat-square&logo=npm
|
||||||
[badge-marp-core]: https://img.shields.io/npm/v/@marp-team/marp-core.svg?style=flat-square&logo=npm
|
[badge-marp-core]: https://img.shields.io/npm/v/@marp-team/marp-core.svg?style=flat-square&logo=npm
|
||||||
[badge-marp-cli]: https://img.shields.io/npm/v/@marp-team/marp-cli.svg?style=flat-square&logo=npm
|
[badge-marp-cli]: https://img.shields.io/npm/v/@marp-team/marp-cli.svg?style=flat-square&logo=npm
|
||||||
[badge-marp-web]: https://img.shields.io/badge/%E2%80%8B-tech%20demo-%230288d1.svg?style=flat-square&logo=data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAA4AAAAOCAYAAAAfSC3RAAAAUUlEQVQokWNgGD6AqePif3Sx9B2PMcQwNKFrTN/x+D9ejTBNyBphmnBqRNYE04isCatGdE1MHRf/o2vC0IhNE1PaXPwacWnCqxGfJoI2Dn4AAN0ZrMM1VUFvAAAAAElFTkSuQmCC
|
|
||||||
[badge-marp-vscode]: https://img.shields.io/visual-studio-marketplace/v/marp-team.marp-vscode.svg?style=flat-square&logo=visual-studio-code&label=Marketplace
|
[badge-marp-vscode]: https://img.shields.io/visual-studio-marketplace/v/marp-team.marp-vscode.svg?style=flat-square&logo=visual-studio-code&label=Marketplace
|
||||||
[badge-marp-react]: https://img.shields.io/npm/v/@marp-team/marp-react.svg?style=flat-square&logo=npm
|
|
||||||
[badge-marp-vue]: https://img.shields.io/npm/v/@marp-team/marp-vue.svg?style=flat-square&logo=npm
|
|
||||||
[badge-planned]: https://img.shields.io/badge/-PLANNED-lightgrey.svg?style=flat-square
|
|
||||||
[badge-wip]: https://img.shields.io/badge/-Work%20in%20progress-lightgrey.svg?style=flat-square
|
|
||||||
|
|
||||||
## Examples
|
## Examples
|
||||||
|
|
||||||
### Starter
|
### Starter by Marp author
|
||||||
|
|
||||||
- **[Marp CLI example](https://yhatt-marp-cli-example.netlify.com/)** by [@yhatt](https://github.com/yhatt) - A good starter to write and host Marp slide with [GitPitch](https://gitpitch.com/) style powered by [Netlify](https://www.netlify.com/). (https://github.com/yhatt/marp-cli-example)
|
- **[Marp CLI example](https://yhatt-marp-cli-example.netlify.com/)** by [@yhatt](https://github.com/yhatt) - A good starter to write and host Marp slide with [GitPitch](https://gitpitch.com/) style powered by [Netlify](https://www.netlify.com/). (https://github.com/yhatt/marp-cli-example)
|
||||||
|
|
||||||
@ -88,8 +101,6 @@ This repo (**[@marp-team/marp][marp]**) is an entrance to the Marp family, and p
|
|||||||
|
|
||||||
Let us know if you have created an awesome slide deck with Marp ecosystem! [Edit README.md and send pull request.](https://github.com/marp-team/marp/edit/master/README.md)
|
Let us know if you have created an awesome slide deck with Marp ecosystem! [Edit README.md and send pull request.](https://github.com/marp-team/marp/edit/master/README.md)
|
||||||
|
|
||||||
<!-- NOTE: The slide deck created by outdated yhatt/marp desktop app cannot add to examples. -->
|
|
||||||
|
|
||||||
## Contributing
|
## Contributing
|
||||||
|
|
||||||
Marp and sub-projects are following the [contributing guideline of marp-team][contributing]. Please read this before starting work in our projects.
|
Marp and sub-projects are following the [contributing guideline of marp-team][contributing]. Please read this before starting work in our projects.
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"version": "0.0.0",
|
"version": "0.0.0",
|
||||||
"packages": ["packages/*"],
|
"packages": ["packages/*", "website"],
|
||||||
"npmClient": "yarn",
|
"npmClient": "yarn",
|
||||||
"useWorkspaces": true
|
"useWorkspaces": true
|
||||||
}
|
}
|
||||||
|
BIN
marp.png
Before Width: | Height: | Size: 7.7 KiB After Width: | Height: | Size: 3.4 KiB |
@ -1,3 +1,3 @@
|
|||||||
[build]
|
[build]
|
||||||
publish = "packages/website/dist"
|
publish = "website/out"
|
||||||
command = "yarn workspace @marp-team/marp-website build"
|
command = "yarn workspace @marp-team/marp-website export"
|
||||||
|
28
package.json
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@marp-team/marp",
|
"name": "@marp-team/marp",
|
||||||
"description": "The entrance repository of Marp family",
|
"description": "The entrance repository of Markdown presentation ecosystem",
|
||||||
"private": true,
|
"private": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"author": {
|
"author": {
|
||||||
@ -18,7 +18,8 @@
|
|||||||
"url": "https://github.com/marp-team/marp"
|
"url": "https://github.com/marp-team/marp"
|
||||||
},
|
},
|
||||||
"workspaces": [
|
"workspaces": [
|
||||||
"packages/*"
|
"packages/*",
|
||||||
|
"website"
|
||||||
],
|
],
|
||||||
"prettier": {
|
"prettier": {
|
||||||
"semi": false,
|
"semi": false,
|
||||||
@ -26,16 +27,23 @@
|
|||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"check:format": "yarn -s format -c",
|
"check:format": "yarn -s format -c",
|
||||||
"format": "prettier \"**/*.{css,html,js,json,jsx,md,scss,yaml,yml}\"",
|
"check:ts": "lerna run --parallel check:ts",
|
||||||
"lint": "eslint \"**/*.{js,jsx}\"",
|
"format:write": "yarn -s format --write",
|
||||||
"website": "yarn -s workspace @marp-team/marp-website serve"
|
"format": "prettier \"**/*.{css,js,jsx,json,md,mdx,scss,ts,tsx,yaml,yml}\"",
|
||||||
|
"lint:js": "eslint --ext .js,.jsx,.ts,.tsx --report-unused-disable-directives --cache .",
|
||||||
|
"website": "yarn workspace @marp-team/marp-website dev"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"eslint": "^7.0.0",
|
"@tsconfig/recommended": "^1.0.1",
|
||||||
|
"@types/node": "^12.12.54",
|
||||||
|
"@typescript-eslint/eslint-plugin": "^3.9.1",
|
||||||
|
"@typescript-eslint/parser": "^3.9.1",
|
||||||
|
"eslint": "^7.7.0",
|
||||||
"eslint-config-prettier": "^6.11.0",
|
"eslint-config-prettier": "^6.11.0",
|
||||||
"eslint-plugin-import": "^2.20.2",
|
"eslint-import-resolver-typescript": "^2.2.1",
|
||||||
"eslint-plugin-react": "^7.20.0",
|
"eslint-plugin-import": "^2.22.0",
|
||||||
"lerna": "^3.21.0",
|
"lerna": "^3.22.1",
|
||||||
"prettier": "^2.0.5"
|
"prettier": "^2.0.5",
|
||||||
|
"typescript": "^4.0.2"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +0,0 @@
|
|||||||
rules:
|
|
||||||
react/prop-types: 0
|
|
||||||
react/react-in-jsx-scope: 0 # Charge does not require to import React
|
|
||||||
import/extensions: # Charge cannot resolve dependency correctly if omitted extension
|
|
||||||
- error
|
|
||||||
- always
|
|
@ -1,27 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "@marp-team/marp-website",
|
|
||||||
"version": "0.0.0",
|
|
||||||
"private": true,
|
|
||||||
"license": "MIT",
|
|
||||||
"author": {
|
|
||||||
"name": "Marp team",
|
|
||||||
"url": "https://github.com/marp-team"
|
|
||||||
},
|
|
||||||
"repository": {
|
|
||||||
"type": "git",
|
|
||||||
"url": "https://github.com/marp-team/marp"
|
|
||||||
},
|
|
||||||
"scripts": {
|
|
||||||
"build": "cross-env NODE_ENV=production charge build src dist",
|
|
||||||
"serve": "cross-env NODE_ENV=development charge serve src"
|
|
||||||
},
|
|
||||||
"devDependencies": {
|
|
||||||
"@emotion/core": "^10.0.28",
|
|
||||||
"@marp-team/marp-core": "^1.1.0",
|
|
||||||
"@static/charge": "^1.7.0",
|
|
||||||
"cross-env": "^7.0.2",
|
|
||||||
"github-slugger": "^1.3.0",
|
|
||||||
"highlight.js": "^10.0.3",
|
|
||||||
"react-innertext": "^1.1.5"
|
|
||||||
}
|
|
||||||
}
|
|
Before Width: | Height: | Size: 631 B |
Before Width: | Height: | Size: 58 KiB |
Before Width: | Height: | Size: 142 KiB |
@ -1,97 +0,0 @@
|
|||||||
/** @jsx jsx */
|
|
||||||
import { jsx, css } from '@emotion/core'
|
|
||||||
import { Meta, blogStyle } from './blog.jsx'
|
|
||||||
import { Heading } from './components/heading.js.jsx'
|
|
||||||
import { Layout, contentStyle, generateTitle } from './layout.jsx'
|
|
||||||
|
|
||||||
export default function Blog({ environment, pages }) {
|
|
||||||
const articles = pages
|
|
||||||
.filter((p) => p.path.startsWith('/blog/') && p.meta.title && p.meta.date)
|
|
||||||
.sort((a, b) => new Date(b.meta.date) - new Date(a.meta.date))
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Layout
|
|
||||||
environment={environment}
|
|
||||||
route="/blog"
|
|
||||||
title={generateTitle('Blog')}
|
|
||||||
>
|
|
||||||
<section css={contentStyle}>
|
|
||||||
<Heading
|
|
||||||
css={css`
|
|
||||||
text-transform: uppercase;
|
|
||||||
margin-top: 0;
|
|
||||||
`}
|
|
||||||
>
|
|
||||||
Blog
|
|
||||||
</Heading>
|
|
||||||
{articles.map((article) => (
|
|
||||||
<section
|
|
||||||
key={article.path}
|
|
||||||
css={css`
|
|
||||||
margin: 1em 0;
|
|
||||||
padding: 25px;
|
|
||||||
position: relative;
|
|
||||||
`}
|
|
||||||
>
|
|
||||||
<a
|
|
||||||
href={article.path}
|
|
||||||
css={css`
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
right: 0;
|
|
||||||
bottom: 0;
|
|
||||||
overflow: hidden;
|
|
||||||
text-indent: 200%;
|
|
||||||
white-space: nowrap;
|
|
||||||
pointer-events: auto;
|
|
||||||
z-index: 1;
|
|
||||||
transition: background-color 0.2s linear, box-shadow 0.2s linear;
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
transition: background-color 0.2s linear,
|
|
||||||
box-shadow 0.2s linear;
|
|
||||||
background: white;
|
|
||||||
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.1);
|
|
||||||
|
|
||||||
&:active {
|
|
||||||
transition: box-shadow 0.07s linear;
|
|
||||||
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.3);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`}
|
|
||||||
>
|
|
||||||
{article.meta.title}
|
|
||||||
</a>
|
|
||||||
<div
|
|
||||||
css={css`
|
|
||||||
position: relative;
|
|
||||||
pointer-events: none;
|
|
||||||
z-index: 2;
|
|
||||||
h2 {
|
|
||||||
font-size: 1.75em;
|
|
||||||
font-size: calc(1.25em + 0.4vw);
|
|
||||||
margin: 0 0 0.5em 0;
|
|
||||||
}
|
|
||||||
`}
|
|
||||||
>
|
|
||||||
<a href={article.path} tabIndex={-1}>
|
|
||||||
<h2>{article.meta.title}</h2>
|
|
||||||
</a>
|
|
||||||
<Meta
|
|
||||||
author={article.meta.author}
|
|
||||||
date={article.meta.date}
|
|
||||||
github={article.meta.github}
|
|
||||||
/>
|
|
||||||
{article.meta.description && (
|
|
||||||
<div css={blogStyle()} style={{ margin: '1em 0 0 0' }}>
|
|
||||||
<p style={{ margin: 0 }}>{article.meta.description}</p>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
))}
|
|
||||||
</section>
|
|
||||||
</Layout>
|
|
||||||
)
|
|
||||||
}
|
|
@ -1,276 +0,0 @@
|
|||||||
/** @jsx jsx */
|
|
||||||
import { jsx, css } from '@emotion/core'
|
|
||||||
import { MDXProvider } from '@mdx-js/react'
|
|
||||||
import GitHubSlugger from 'github-slugger'
|
|
||||||
import { Heading } from './components/blog/heading.js.jsx'
|
|
||||||
import { Layout, contentStyle, generateTitle, resolvePath } from './layout.jsx'
|
|
||||||
|
|
||||||
const articleStyle = css`
|
|
||||||
margin: 10px auto;
|
|
||||||
|
|
||||||
h1 {
|
|
||||||
margin: 0 0 0.5em 0;
|
|
||||||
}
|
|
||||||
`
|
|
||||||
const coverStyle = css`
|
|
||||||
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.1);
|
|
||||||
display: block;
|
|
||||||
height: auto;
|
|
||||||
margin: 1em auto;
|
|
||||||
max-height: 320px;
|
|
||||||
max-width: 640px;
|
|
||||||
object-fit: cover;
|
|
||||||
width: 100%;
|
|
||||||
`
|
|
||||||
|
|
||||||
export const blogStyle = ({ fontSize = 17 } = {}) => css`
|
|
||||||
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen,
|
|
||||||
Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif,
|
|
||||||
Apple Color Emoji, Segoe UI Emoji;
|
|
||||||
font-size: ${fontSize}px;
|
|
||||||
letter-spacing: 0.03em;
|
|
||||||
line-height: 1.5;
|
|
||||||
margin: 2em 0;
|
|
||||||
white-space: break-word;
|
|
||||||
|
|
||||||
p {
|
|
||||||
margin: ${fontSize}px 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
h1,
|
|
||||||
h2,
|
|
||||||
h3,
|
|
||||||
h4,
|
|
||||||
h5,
|
|
||||||
h6 {
|
|
||||||
margin: ${fontSize * 2}px 0 ${fontSize}px 0;
|
|
||||||
font-weight: bold;
|
|
||||||
}
|
|
||||||
|
|
||||||
h1 {
|
|
||||||
background: transparent
|
|
||||||
linear-gradient(to bottom, transparent 85%, #67b8e3 85%);
|
|
||||||
font-size: 1.6em;
|
|
||||||
max-width: 100%;
|
|
||||||
width: max-content;
|
|
||||||
}
|
|
||||||
|
|
||||||
h2 {
|
|
||||||
font-size: 1.3em;
|
|
||||||
}
|
|
||||||
|
|
||||||
h3 {
|
|
||||||
font-size: 1.1em;
|
|
||||||
}
|
|
||||||
|
|
||||||
h4 {
|
|
||||||
font-size: 1em;
|
|
||||||
}
|
|
||||||
|
|
||||||
h5 {
|
|
||||||
font-size: 0.9em;
|
|
||||||
}
|
|
||||||
|
|
||||||
h6 {
|
|
||||||
color: #666;
|
|
||||||
font-size: 0.8em;
|
|
||||||
}
|
|
||||||
|
|
||||||
img {
|
|
||||||
border-style: none;
|
|
||||||
max-width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
figure {
|
|
||||||
img {
|
|
||||||
display: block;
|
|
||||||
margin: 1em auto;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
hr {
|
|
||||||
background: linear-gradient(-45deg, #eee 33%, #ccc 33%, #ccc 67%, #eee 67%)
|
|
||||||
repeat center center;
|
|
||||||
background-size: 6px 3px;
|
|
||||||
border: none;
|
|
||||||
height: 3px;
|
|
||||||
margin: ${fontSize * 2}px 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
ul,
|
|
||||||
ol,
|
|
||||||
pre,
|
|
||||||
blockquote {
|
|
||||||
margin: ${fontSize * 1.5}px 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
ul,
|
|
||||||
ol {
|
|
||||||
padding: 0 0 0 1.75em;
|
|
||||||
|
|
||||||
li {
|
|
||||||
margin: ${fontSize * 0.25}px 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
ul,
|
|
||||||
ol {
|
|
||||||
margin: ${fontSize * 0.25}px 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
code,
|
|
||||||
pre {
|
|
||||||
font-family: 'Source Code Pro', 'Courier New', Courier, monospace;
|
|
||||||
background-color: #f6f6f6;
|
|
||||||
border-radius: 2px;
|
|
||||||
letter-spacing: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
code {
|
|
||||||
font-size: 0.85em;
|
|
||||||
margin: 0;
|
|
||||||
padding: 0.15em 0.35em;
|
|
||||||
}
|
|
||||||
|
|
||||||
pre {
|
|
||||||
background-image: url('/assets/noise.png');
|
|
||||||
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.15);
|
|
||||||
box-sizing: border-box;
|
|
||||||
font-weight: 500;
|
|
||||||
line-height: 1.1em;
|
|
||||||
overflow-x: auto;
|
|
||||||
white-space: pre;
|
|
||||||
word-wrap: normal;
|
|
||||||
|
|
||||||
> code {
|
|
||||||
background-color: transparent;
|
|
||||||
border-radius: 0;
|
|
||||||
box-shadow: none;
|
|
||||||
display: inline-block;
|
|
||||||
margin: 1em;
|
|
||||||
padding: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
blockquote {
|
|
||||||
border-left: 3px solid #007aad;
|
|
||||||
color: #666;
|
|
||||||
padding: 0 0 0 1em;
|
|
||||||
|
|
||||||
blockquote {
|
|
||||||
border-color: #009bda;
|
|
||||||
|
|
||||||
blockquote {
|
|
||||||
border-color: #78c5e9;
|
|
||||||
|
|
||||||
blockquote {
|
|
||||||
border-color: #ccc;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`
|
|
||||||
|
|
||||||
export const Meta = ({ author, date, github }) => (
|
|
||||||
<div
|
|
||||||
css={css`
|
|
||||||
font-size: calc(11.5px + 0.25vw);
|
|
||||||
font-weight: 500;
|
|
||||||
color: #666;
|
|
||||||
|
|
||||||
&,
|
|
||||||
& > a {
|
|
||||||
align-items: center;
|
|
||||||
display: flex;
|
|
||||||
flex-wrap: wrap;
|
|
||||||
}
|
|
||||||
|
|
||||||
img {
|
|
||||||
width: 2em;
|
|
||||||
height: 2em;
|
|
||||||
border-radius: 2em;
|
|
||||||
}
|
|
||||||
`}
|
|
||||||
>
|
|
||||||
<time dateTime={date}>Posted {date}</time>
|
|
||||||
{author && (
|
|
||||||
<>
|
|
||||||
by
|
|
||||||
{(() => {
|
|
||||||
if (!github) return author
|
|
||||||
|
|
||||||
return (
|
|
||||||
<a
|
|
||||||
href={`https://github.com/${github}`}
|
|
||||||
rel="noopener"
|
|
||||||
// eslint-disable-next-line react/jsx-no-target-blank
|
|
||||||
target="_blank"
|
|
||||||
>
|
|
||||||
<img
|
|
||||||
alt={author}
|
|
||||||
src={`https://github.com/${github}.png`}
|
|
||||||
width="40"
|
|
||||||
height="40"
|
|
||||||
/>
|
|
||||||
{author}
|
|
||||||
</a>
|
|
||||||
)
|
|
||||||
})()}
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
|
|
||||||
export const BlogLayout = ({ children, meta }) => {
|
|
||||||
const {
|
|
||||||
title,
|
|
||||||
description,
|
|
||||||
image,
|
|
||||||
imageCaption,
|
|
||||||
slug,
|
|
||||||
date,
|
|
||||||
author,
|
|
||||||
github,
|
|
||||||
} = meta
|
|
||||||
const route = slug && `/blog/${slug}`
|
|
||||||
|
|
||||||
// Slugified headings
|
|
||||||
const slugger = new GitHubSlugger()
|
|
||||||
const h1 = (props) => <Heading {...props} level={1} slugger={slugger} />
|
|
||||||
const h2 = (props) => <Heading {...props} level={2} slugger={slugger} />
|
|
||||||
const h3 = (props) => <Heading {...props} level={3} slugger={slugger} />
|
|
||||||
const h4 = (props) => <Heading {...props} level={4} slugger={slugger} />
|
|
||||||
const h5 = (props) => <Heading {...props} level={5} slugger={slugger} />
|
|
||||||
const h6 = (props) => <Heading {...props} level={6} slugger={slugger} />
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Layout
|
|
||||||
description={description}
|
|
||||||
image={image}
|
|
||||||
route={route}
|
|
||||||
title={generateTitle('Blog', title)}
|
|
||||||
>
|
|
||||||
<article css={[contentStyle, articleStyle]}>
|
|
||||||
<a href={route || '#'}>
|
|
||||||
<h1 style={{ marginTop: 0 }}>{title}</h1>
|
|
||||||
</a>
|
|
||||||
<Meta author={author} date={date} github={github} />
|
|
||||||
{image && (
|
|
||||||
<figure>
|
|
||||||
<img
|
|
||||||
css={coverStyle}
|
|
||||||
src={resolvePath(image)}
|
|
||||||
alt={imageCaption || title}
|
|
||||||
/>
|
|
||||||
{imageCaption && <figcaption>{imageCaption}</figcaption>}
|
|
||||||
</figure>
|
|
||||||
)}
|
|
||||||
<div css={blogStyle()}>
|
|
||||||
<MDXProvider components={{ h1, h2, h3, h4, h5, h6 }}>
|
|
||||||
{children}
|
|
||||||
</MDXProvider>
|
|
||||||
</div>
|
|
||||||
</article>
|
|
||||||
</Layout>
|
|
||||||
)
|
|
||||||
}
|
|
Before Width: | Height: | Size: 19 KiB |
@ -1,63 +0,0 @@
|
|||||||
/** @jsx jsx */
|
|
||||||
import { css, jsx } from '@emotion/core'
|
|
||||||
import GitHubSlugger from 'github-slugger'
|
|
||||||
import innerText from 'react-innertext'
|
|
||||||
|
|
||||||
export const Heading = ({
|
|
||||||
anchorOffset = -80,
|
|
||||||
children,
|
|
||||||
level = 1,
|
|
||||||
slugger = new GitHubSlugger(),
|
|
||||||
...props
|
|
||||||
}) => {
|
|
||||||
const anchor = slugger.slug(innerText(children))
|
|
||||||
const Tag = `h${level}`
|
|
||||||
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<a
|
|
||||||
name={anchor}
|
|
||||||
css={css`
|
|
||||||
visibility: hidden;
|
|
||||||
display: block;
|
|
||||||
position: relative;
|
|
||||||
top: ${anchorOffset}px;
|
|
||||||
`}
|
|
||||||
/>
|
|
||||||
<Tag {...props}>
|
|
||||||
<span
|
|
||||||
css={css`
|
|
||||||
display: inline-block;
|
|
||||||
position: relative;
|
|
||||||
|
|
||||||
> .anchor-link {
|
|
||||||
align-items: center;
|
|
||||||
bottom: 0;
|
|
||||||
display: none;
|
|
||||||
justify-content: center;
|
|
||||||
left: -32px;
|
|
||||||
overflow: hidden;
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
width: 32px;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:hover > .anchor-link {
|
|
||||||
display: flex;
|
|
||||||
}
|
|
||||||
`}
|
|
||||||
>
|
|
||||||
<a href={`#${anchor}`} className="anchor-link" aria-hidden="true">
|
|
||||||
<img
|
|
||||||
src="https://icongr.am/octicons/link.svg?color=444455"
|
|
||||||
width="16"
|
|
||||||
height="16"
|
|
||||||
loading="lazy"
|
|
||||||
/>
|
|
||||||
</a>
|
|
||||||
{children}
|
|
||||||
</span>
|
|
||||||
</Tag>
|
|
||||||
</>
|
|
||||||
)
|
|
||||||
}
|
|
@ -1,111 +0,0 @@
|
|||||||
/** @jsx jsx */
|
|
||||||
import { css, jsx } from '@emotion/core'
|
|
||||||
|
|
||||||
const btnShadow = '0 3px 6px rgba(0, 0, 0, 0.25)'
|
|
||||||
const btnShadowFocus = '0 0 0 0.15em #67b8e3'
|
|
||||||
|
|
||||||
const button = css`
|
|
||||||
appearance: none;
|
|
||||||
border-radius: 1.5em;
|
|
||||||
border: 0;
|
|
||||||
box-shadow: ${btnShadow};
|
|
||||||
box-sizing: content-box;
|
|
||||||
cursor: pointer;
|
|
||||||
display: inline-block;
|
|
||||||
font: inherit;
|
|
||||||
letter-spacing: inherit;
|
|
||||||
line-height: inherit;
|
|
||||||
font-weight: bold;
|
|
||||||
outline: 0;
|
|
||||||
overflow: hidden;
|
|
||||||
margin: 0;
|
|
||||||
padding: 0.6em 0.95em;
|
|
||||||
text-decoration: none;
|
|
||||||
user-select: none;
|
|
||||||
white-space: nowrap;
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
transition: color 0.15s linear, background-color 0.15s linear;
|
|
||||||
|
|
||||||
&:active {
|
|
||||||
transition: none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&:focus {
|
|
||||||
box-shadow: ${btnShadowFocus}, ${btnShadow};
|
|
||||||
}
|
|
||||||
`
|
|
||||||
|
|
||||||
const outline = css`
|
|
||||||
padding: 0.475em 0.825em;
|
|
||||||
`
|
|
||||||
|
|
||||||
const colors = {
|
|
||||||
default: {
|
|
||||||
common: css`
|
|
||||||
background-color: #fff;
|
|
||||||
color: #444;
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
color: #444;
|
|
||||||
background-color: #f8f8f8;
|
|
||||||
|
|
||||||
&:active {
|
|
||||||
color: #444;
|
|
||||||
background-color: #e0e0e0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`,
|
|
||||||
outline: css`
|
|
||||||
border: 0.125em solid #444;
|
|
||||||
`,
|
|
||||||
},
|
|
||||||
primary: {
|
|
||||||
regular: css`
|
|
||||||
color: #fff;
|
|
||||||
background: #0288d1
|
|
||||||
linear-gradient(30deg, transparent, rgba(255, 255, 255, 0.3));
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
color: #fff;
|
|
||||||
background-color: #0277b7;
|
|
||||||
|
|
||||||
&:active {
|
|
||||||
color: #fff;
|
|
||||||
background-color: #02669d;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`,
|
|
||||||
outline: css`
|
|
||||||
color: #0288d1;
|
|
||||||
border: 0.125em solid #0288d1;
|
|
||||||
background-color: #fff;
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
color: #fff;
|
|
||||||
background-color: #0288d1;
|
|
||||||
|
|
||||||
&:active {
|
|
||||||
color: #fff;
|
|
||||||
background-color: #0277b7;
|
|
||||||
border-color: #0277b7;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
export const Button = (props) => {
|
|
||||||
const color = colors[props.color] || colors.default
|
|
||||||
const style = [
|
|
||||||
button,
|
|
||||||
color.common,
|
|
||||||
props.outline && outline,
|
|
||||||
color[props.outline ? 'outline' : 'regular'],
|
|
||||||
props.css,
|
|
||||||
]
|
|
||||||
|
|
||||||
if (props.href) return <a tabIndex={0} role="button" {...props} css={style} />
|
|
||||||
return <button {...props} css={style} />
|
|
||||||
}
|
|
@ -1,60 +0,0 @@
|
|||||||
/** @jsx jsx */
|
|
||||||
import { css, jsx } from '@emotion/core'
|
|
||||||
import highlightjs from 'highlight.js'
|
|
||||||
|
|
||||||
export const Code = ({ children, language, style }) => {
|
|
||||||
const colored = highlightjs.getLanguage(language)
|
|
||||||
? highlightjs.highlight(language, children, true)
|
|
||||||
: highlightjs.highlightAuto(children)
|
|
||||||
|
|
||||||
const lines = colored.value.split('\n')
|
|
||||||
const codeStyle = css`
|
|
||||||
--line-number-width: 3.5em;
|
|
||||||
|
|
||||||
cursor: text;
|
|
||||||
font-family: 'Source Code Pro', 'Courier New', Courier, monospace;
|
|
||||||
font-weight: 500;
|
|
||||||
letter-spacing: 0;
|
|
||||||
word-wrap: break-word;
|
|
||||||
|
|
||||||
> ol {
|
|
||||||
box-sizing: border-box;
|
|
||||||
list-style: none;
|
|
||||||
margin: 0;
|
|
||||||
padding: 0 0 0 var(--line-number-width);
|
|
||||||
}
|
|
||||||
|
|
||||||
.code-line {
|
|
||||||
counter-increment: code;
|
|
||||||
|
|
||||||
&::before {
|
|
||||||
pointer-events: none;
|
|
||||||
display: inline-block;
|
|
||||||
text-align: right;
|
|
||||||
content: counter(code);
|
|
||||||
margin-left: calc(var(--line-number-width) * -1);
|
|
||||||
width: var(--line-number-width);
|
|
||||||
box-sizing: border-box;
|
|
||||||
padding-right: calc(var(--line-number-width) * 0.3);
|
|
||||||
color: rgba(0, 0, 0, 0.5);
|
|
||||||
font-size: 80%;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div css={[codeStyle, style]}>
|
|
||||||
<ol>
|
|
||||||
{lines.map((line, i) => (
|
|
||||||
<li className="code-line" key={i}>
|
|
||||||
{line === '' ? (
|
|
||||||
<br />
|
|
||||||
) : (
|
|
||||||
<span dangerouslySetInnerHTML={{ __html: line }} />
|
|
||||||
)}
|
|
||||||
</li>
|
|
||||||
))}
|
|
||||||
</ol>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
@ -1,37 +0,0 @@
|
|||||||
/** @jsx jsx */
|
|
||||||
import { css, jsx } from '@emotion/core'
|
|
||||||
|
|
||||||
export const Heading = ({ children, level = 1, ...props }) => {
|
|
||||||
const Tag = `h${level}`
|
|
||||||
|
|
||||||
return (
|
|
||||||
<span
|
|
||||||
css={css`
|
|
||||||
display: block;
|
|
||||||
filter: drop-shadow(0 5px 10px rgba(0, 0, 0, 0.15));
|
|
||||||
`}
|
|
||||||
>
|
|
||||||
<Tag
|
|
||||||
css={css`
|
|
||||||
background-color: #009bda;
|
|
||||||
background-image: url('/assets/noise.png'),
|
|
||||||
linear-gradient(-30deg, #02669d, #009bda);
|
|
||||||
box-sizing: border-box;
|
|
||||||
clip-path: polygon(1.5em 0, 100% 0, calc(100% - 1.5em) 100%, 0 100%);
|
|
||||||
color: #fff;
|
|
||||||
line-height: 1.2;
|
|
||||||
margin-left: auto;
|
|
||||||
margin-right: auto;
|
|
||||||
max-width: calc(100% - 60px);
|
|
||||||
padding: 0.25em 2em;
|
|
||||||
text-align: center;
|
|
||||||
width: max-content;
|
|
||||||
word-wrap: break-word;
|
|
||||||
`}
|
|
||||||
{...props}
|
|
||||||
>
|
|
||||||
{children}
|
|
||||||
</Tag>
|
|
||||||
</span>
|
|
||||||
)
|
|
||||||
}
|
|
@ -1,47 +0,0 @@
|
|||||||
/** @jsx jsx */
|
|
||||||
import { css, jsx } from '@emotion/core'
|
|
||||||
import { Marp as MarpCore } from '@marp-team/marp-core'
|
|
||||||
import { resolvePath } from '../layout.jsx'
|
|
||||||
|
|
||||||
const reset = css`
|
|
||||||
all: initial;
|
|
||||||
display: inline;
|
|
||||||
display: contents;
|
|
||||||
|
|
||||||
svg {
|
|
||||||
pointer-events: none;
|
|
||||||
user-select: none;
|
|
||||||
vertical-align: bottom;
|
|
||||||
}
|
|
||||||
`
|
|
||||||
|
|
||||||
const container = css`
|
|
||||||
display: inline-block;
|
|
||||||
`
|
|
||||||
|
|
||||||
export const Marp = (props) => {
|
|
||||||
const marp = new MarpCore({
|
|
||||||
container: null,
|
|
||||||
script: false,
|
|
||||||
printable: false,
|
|
||||||
})
|
|
||||||
|
|
||||||
marp.markdown.normalizeLink = (url) => resolvePath(url)
|
|
||||||
|
|
||||||
const rendered = marp.render(props.markdown, { htmlAsArray: true })
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div css={reset}>
|
|
||||||
<div
|
|
||||||
css={[
|
|
||||||
container,
|
|
||||||
css([rendered.css.replace(/\/\*[\s\S]*?\*\//g, '')]),
|
|
||||||
props.style,
|
|
||||||
]}
|
|
||||||
dangerouslySetInnerHTML={{
|
|
||||||
__html: rendered.html[props.page ? props.page - 1 : 0],
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
Before Width: | Height: | Size: 680 B |
@ -1 +0,0 @@
|
|||||||
@import 'highlight.js/styles/atom-one-light.css';
|
|
@ -1,27 +0,0 @@
|
|||||||
/** @jsx jsx */
|
|
||||||
import { css, jsx } from '@emotion/core'
|
|
||||||
import { Description } from './index/description.js.jsx'
|
|
||||||
import { Features } from './index/features.js.jsx'
|
|
||||||
import { GetStarted } from './index/get-started.js.jsx'
|
|
||||||
import { Hero } from './index/hero.js.jsx'
|
|
||||||
import { Layout } from './layout.jsx'
|
|
||||||
|
|
||||||
export default function Index() {
|
|
||||||
return (
|
|
||||||
<Layout
|
|
||||||
route="/"
|
|
||||||
description="Marp, Markdown Presentation Ecosystem, provides the great experience to create beautiful slide deck. You only have to focus writing your story in Markdown document."
|
|
||||||
type="website"
|
|
||||||
globalStyles={css`
|
|
||||||
html {
|
|
||||||
scroll-behavior: smooth;
|
|
||||||
}
|
|
||||||
`}
|
|
||||||
>
|
|
||||||
<Hero />
|
|
||||||
<Description />
|
|
||||||
<Features />
|
|
||||||
<GetStarted />
|
|
||||||
</Layout>
|
|
||||||
)
|
|
||||||
}
|
|
@ -1,6 +0,0 @@
|
|||||||
document
|
|
||||||
.getElementById('show-markdown-example')
|
|
||||||
.addEventListener('click', () => {
|
|
||||||
const example = document.getElementById('markdown-example')
|
|
||||||
example.open = !example.open
|
|
||||||
})
|
|
@ -1,140 +0,0 @@
|
|||||||
/** @jsx jsx */
|
|
||||||
import { css, jsx } from '@emotion/core'
|
|
||||||
import { version } from '@marp-team/marp-core/package.json'
|
|
||||||
import { Button } from '../components/button.js.jsx'
|
|
||||||
import { Code } from '../components/code.js.jsx'
|
|
||||||
import { Marp } from '../components/marp.js.jsx'
|
|
||||||
import { contentStyle, resolvePath } from '../layout.jsx'
|
|
||||||
|
|
||||||
const example = (resolver = (v) => v) =>
|
|
||||||
`
|
|
||||||
---
|
|
||||||
theme: gaia
|
|
||||||
_class: lead
|
|
||||||
paginate: true
|
|
||||||
backgroundColor: #fff
|
|
||||||
backgroundImage: url('${resolver('/assets/hero-background.jpg')}')
|
|
||||||
---
|
|
||||||
|
|
||||||
![bg left:40% 80%](https://raw.githubusercontent.com/marp-team/marp/master/marp.png)
|
|
||||||
|
|
||||||
# **Marp**
|
|
||||||
|
|
||||||
Markdown Presentation Ecosystem
|
|
||||||
|
|
||||||
https://marp.app/
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
# How to write slides
|
|
||||||
|
|
||||||
Split pages by horizontal ruler (\`---\`). It's very simple! :satisfied:
|
|
||||||
|
|
||||||
\`\`\`markdown
|
|
||||||
# Slide 1
|
|
||||||
|
|
||||||
foobar
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
# Slide 2
|
|
||||||
|
|
||||||
foobar
|
|
||||||
\`\`\`
|
|
||||||
`.trim()
|
|
||||||
|
|
||||||
const MarpExample = ({ page }) => (
|
|
||||||
<Marp
|
|
||||||
markdown={example()}
|
|
||||||
page={page}
|
|
||||||
style={css`
|
|
||||||
border: thin solid #ddd;
|
|
||||||
box-shadow: 0 5px 10px rgba(0, 0, 0, 0.15);
|
|
||||||
box-sizing: border-box;
|
|
||||||
margin: 20px;
|
|
||||||
max-width: 360px;
|
|
||||||
width: 80%;
|
|
||||||
`}
|
|
||||||
/>
|
|
||||||
)
|
|
||||||
|
|
||||||
export const Description = () => (
|
|
||||||
<section
|
|
||||||
css={[
|
|
||||||
contentStyle,
|
|
||||||
css`
|
|
||||||
font-weight: 500;
|
|
||||||
text-align: center;
|
|
||||||
|
|
||||||
> section {
|
|
||||||
text-align: left;
|
|
||||||
|
|
||||||
p {
|
|
||||||
margin-left: auto;
|
|
||||||
margin-right: auto;
|
|
||||||
max-width: 640px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
> figure {
|
|
||||||
margin-top: 1em;
|
|
||||||
}
|
|
||||||
`,
|
|
||||||
]}
|
|
||||||
>
|
|
||||||
<h1>
|
|
||||||
<mark>The great experience</mark> for creating slide deck
|
|
||||||
</h1>
|
|
||||||
<section>
|
|
||||||
<p>
|
|
||||||
Marp, Markdown Presentation Ecosystem, provides the great experience to
|
|
||||||
create beautiful slide deck. You only have to focus writing your story
|
|
||||||
in Markdown document.
|
|
||||||
</p>
|
|
||||||
</section>
|
|
||||||
<figure>
|
|
||||||
<MarpExample page={1} />
|
|
||||||
<MarpExample page={2} />
|
|
||||||
<figcaption>
|
|
||||||
We're rendering slides generated in{' '}
|
|
||||||
<a href="https://github.com/marp-team/marp-core">Marp Core</a>
|
|
||||||
</figcaption>
|
|
||||||
</figure>
|
|
||||||
<p>
|
|
||||||
<Button
|
|
||||||
onClick="this"
|
|
||||||
id="show-markdown-example"
|
|
||||||
style={{ fontSize: '0.85em' }}
|
|
||||||
>
|
|
||||||
Show Markdown example...
|
|
||||||
</Button>
|
|
||||||
</p>
|
|
||||||
<section>
|
|
||||||
<details id="markdown-example">
|
|
||||||
<summary style={{ display: 'none' }} />
|
|
||||||
<Code
|
|
||||||
language="markdown"
|
|
||||||
style={css`
|
|
||||||
border: thin solid #eee;
|
|
||||||
background: #f6f6f6 url('/assets/noise.png');
|
|
||||||
border-radius: 15px;
|
|
||||||
box-sizing: border-box;
|
|
||||||
font-size: 0.8em;
|
|
||||||
margin: 0 auto;
|
|
||||||
max-width: 800px;
|
|
||||||
padding: 20px 10px;
|
|
||||||
width: 85%;
|
|
||||||
`}
|
|
||||||
>
|
|
||||||
{example(resolvePath)}
|
|
||||||
</Code>
|
|
||||||
</details>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<script src="/index/description.js" />
|
|
||||||
<script
|
|
||||||
async
|
|
||||||
src={`https://cdn.jsdelivr.net/npm/@marp-team/marp-core@${version}/lib/browser.js`}
|
|
||||||
/>
|
|
||||||
</section>
|
|
||||||
)
|
|
@ -1,373 +0,0 @@
|
|||||||
/** @jsx jsx */
|
|
||||||
import { css, jsx } from '@emotion/core'
|
|
||||||
import { contentStyle } from '../layout.jsx'
|
|
||||||
|
|
||||||
const FeatureSections = (props) => (
|
|
||||||
<section {...props}>
|
|
||||||
<section>
|
|
||||||
<figure>
|
|
||||||
<img
|
|
||||||
src="https://icongr.am/octicons/markdown.svg?size=50&color=444455"
|
|
||||||
alt="Based on CommonMark"
|
|
||||||
/>
|
|
||||||
</figure>
|
|
||||||
<h2>
|
|
||||||
Based on <mark>CommonMark</mark>
|
|
||||||
</h2>
|
|
||||||
<p>
|
|
||||||
If you know how to write document with Markdown, you already know how to
|
|
||||||
write Marp slide deck too. Our format is based on{' '}
|
|
||||||
<a
|
|
||||||
href="https://commonmark.org/"
|
|
||||||
target="_blank"
|
|
||||||
rel="noopener noreferrer"
|
|
||||||
>
|
|
||||||
CommonMark
|
|
||||||
</a>
|
|
||||||
, the consistent spec of Markdown. The only important difference is{' '}
|
|
||||||
<a
|
|
||||||
href="https://marpit.marp.app/markdown"
|
|
||||||
rel="noopener noreferrer"
|
|
||||||
target="_blank"
|
|
||||||
>
|
|
||||||
a ruler <code>---</code> for splitting pages.
|
|
||||||
</a>
|
|
||||||
</p>
|
|
||||||
</section>
|
|
||||||
<section>
|
|
||||||
<figure>
|
|
||||||
<img
|
|
||||||
src="https://icongr.am/octicons/code-square.svg?size=50&color=444455"
|
|
||||||
alt="Directives and extended syntax"
|
|
||||||
/>
|
|
||||||
</figure>
|
|
||||||
<h2>
|
|
||||||
<mark>Directives</mark> and <mark>extended syntax</mark>
|
|
||||||
</h2>
|
|
||||||
<p>
|
|
||||||
Nevertheless, you may think the simple text content is lacking to
|
|
||||||
emphasize your voice. We are supporting to create beautiful slide
|
|
||||||
through{' '}
|
|
||||||
<a
|
|
||||||
href="https://marpit.marp.app/directives"
|
|
||||||
rel="noopener noreferrer"
|
|
||||||
target="_blank"
|
|
||||||
>
|
|
||||||
directives
|
|
||||||
</a>{' '}
|
|
||||||
and extended syntax (
|
|
||||||
<a
|
|
||||||
href="https://marpit.marp.app/image-syntax"
|
|
||||||
rel="noopener noreferrer"
|
|
||||||
target="_blank"
|
|
||||||
>
|
|
||||||
Image syntax
|
|
||||||
</a>
|
|
||||||
,{' '}
|
|
||||||
<a
|
|
||||||
href="https://github.com/marp-team/marp-core#math-typesetting"
|
|
||||||
rel="noopener"
|
|
||||||
// eslint-disable-next-line react/jsx-no-target-blank
|
|
||||||
target="_blank"
|
|
||||||
>
|
|
||||||
math typesetting
|
|
||||||
</a>
|
|
||||||
,{' '}
|
|
||||||
<a
|
|
||||||
href="https://github.com/marp-team/marp-core#auto-scaling-features"
|
|
||||||
rel="noopener"
|
|
||||||
// eslint-disable-next-line react/jsx-no-target-blank
|
|
||||||
target="_blank"
|
|
||||||
>
|
|
||||||
auto-scaling
|
|
||||||
</a>
|
|
||||||
, etc...).
|
|
||||||
</p>
|
|
||||||
</section>
|
|
||||||
<section>
|
|
||||||
<figure>
|
|
||||||
<img
|
|
||||||
src="https://icongr.am/octicons/paintbrush.svg?size=50&color=444455"
|
|
||||||
alt="Built-in themes and CSS theming"
|
|
||||||
/>
|
|
||||||
</figure>
|
|
||||||
<h2>
|
|
||||||
<mark>Built-in themes</mark> and <mark>CSS theming</mark>
|
|
||||||
</h2>
|
|
||||||
<p>
|
|
||||||
<a
|
|
||||||
href="https://github.com/marp-team/marp-core/"
|
|
||||||
rel="noopener"
|
|
||||||
// eslint-disable-next-line react/jsx-no-target-blank
|
|
||||||
target="_blank"
|
|
||||||
>
|
|
||||||
Our core engine
|
|
||||||
</a>{' '}
|
|
||||||
has{' '}
|
|
||||||
<a
|
|
||||||
href="https://github.com/marp-team/marp-core/tree/master/themes"
|
|
||||||
rel="noopener"
|
|
||||||
// eslint-disable-next-line react/jsx-no-target-blank
|
|
||||||
target="_blank"
|
|
||||||
>
|
|
||||||
3 built-in themes called <code>default</code>, <code>gaia</code>, and{' '}
|
|
||||||
<code>uncover</code>
|
|
||||||
</a>
|
|
||||||
, to tell your story beautifully. If you are feeling unsatisfied to
|
|
||||||
design, Marp can{' '}
|
|
||||||
<a
|
|
||||||
href="https://marpit.marp.app/theme-css?id=tweak-style-through-markdown"
|
|
||||||
rel="noopener noreferrer"
|
|
||||||
target="_blank"
|
|
||||||
>
|
|
||||||
tweak style through Markdown
|
|
||||||
</a>
|
|
||||||
, or{' '}
|
|
||||||
<a
|
|
||||||
href="https://marpit.marp.app/theme-css"
|
|
||||||
rel="noopener noreferrer"
|
|
||||||
target="_blank"
|
|
||||||
>
|
|
||||||
create your own theme with plain CSS
|
|
||||||
</a>
|
|
||||||
.
|
|
||||||
</p>
|
|
||||||
</section>
|
|
||||||
<section>
|
|
||||||
<figure>
|
|
||||||
<img
|
|
||||||
src="https://icongr.am/octicons/file.svg?size=50&color=444455"
|
|
||||||
alt="Export to HTML, PDF, and PowerPoint"
|
|
||||||
/>
|
|
||||||
</figure>
|
|
||||||
<h2>
|
|
||||||
Export to <mark>HTML, PDF, and PowerPoint</mark>
|
|
||||||
</h2>
|
|
||||||
<p>
|
|
||||||
Have you finished writing? Let's share the deck with a favorite
|
|
||||||
way! We can convert Markdown into HTML, what is more, PDF and PowerPoint
|
|
||||||
document directly! (Powered by{' '}
|
|
||||||
<a
|
|
||||||
href="https://www.google.com/chrome/"
|
|
||||||
rel="noopener noreferrer"
|
|
||||||
target="_blank"
|
|
||||||
>
|
|
||||||
Google Chrome
|
|
||||||
</a>{' '}
|
|
||||||
/{' '}
|
|
||||||
<a
|
|
||||||
href="https://www.chromium.org/Home"
|
|
||||||
rel="noopener noreferrer"
|
|
||||||
target="_blank"
|
|
||||||
>
|
|
||||||
Chromium
|
|
||||||
</a>
|
|
||||||
)
|
|
||||||
</p>
|
|
||||||
</section>
|
|
||||||
<section>
|
|
||||||
<figure>
|
|
||||||
<img
|
|
||||||
src="https://icongr.am/octicons/package.svg?size=50&color=444455"
|
|
||||||
alt="Marp family: The official toolset"
|
|
||||||
/>
|
|
||||||
</figure>
|
|
||||||
<h2>
|
|
||||||
<mark>Marp family</mark>: The official toolset
|
|
||||||
</h2>
|
|
||||||
<p>
|
|
||||||
Marp family has the rich toolset to assist your work.{' '}
|
|
||||||
<a
|
|
||||||
href="https://marketplace.visualstudio.com/items?itemName=marp-team.marp-vscode"
|
|
||||||
rel="noopener noreferrer"
|
|
||||||
target="_blank"
|
|
||||||
>
|
|
||||||
<b>Marp for VS Code</b>
|
|
||||||
</a>{' '}
|
|
||||||
extension can preview editting Markdown and custom theme immediately.{' '}
|
|
||||||
<a
|
|
||||||
href="https://github.com/marp-team/marp-cli/"
|
|
||||||
rel="noopener"
|
|
||||||
// eslint-disable-next-line react/jsx-no-target-blank
|
|
||||||
target="_blank"
|
|
||||||
>
|
|
||||||
<b>Marp CLI</b>
|
|
||||||
</a>{' '}
|
|
||||||
allows to convert Markdown through CLI interface.{' '}
|
|
||||||
<a
|
|
||||||
href="https://web.marp.app/"
|
|
||||||
rel="noopener"
|
|
||||||
// eslint-disable-next-line react/jsx-no-target-blank
|
|
||||||
target="_blank"
|
|
||||||
>
|
|
||||||
Marp Web <i>(Tech demo)</i>
|
|
||||||
</a>{' '}
|
|
||||||
can render your deck in online.{' '}
|
|
||||||
<a
|
|
||||||
href="https://github.com/marp-team/marp/"
|
|
||||||
rel="noopener"
|
|
||||||
// eslint-disable-next-line react/jsx-no-target-blank
|
|
||||||
target="_blank"
|
|
||||||
>
|
|
||||||
...and more!
|
|
||||||
</a>
|
|
||||||
</p>
|
|
||||||
</section>
|
|
||||||
<section>
|
|
||||||
<figure>
|
|
||||||
<img
|
|
||||||
src="https://icongr.am/octicons/plug.svg?size=50&color=444455"
|
|
||||||
alt="Pluggable architecture"
|
|
||||||
/>
|
|
||||||
</figure>
|
|
||||||
<h2>
|
|
||||||
<mark>Pluggable</mark> architecture
|
|
||||||
</h2>
|
|
||||||
<p>
|
|
||||||
As a matter of fact,{' '}
|
|
||||||
<em>Marp is essentially just a converter for Markdown.</em> Marp
|
|
||||||
ecosystem is built on{' '}
|
|
||||||
<a
|
|
||||||
href="https://marpit.marp.app"
|
|
||||||
rel="noopener noreferrer"
|
|
||||||
target="_blank"
|
|
||||||
>
|
|
||||||
<b>Marpit framework</b>
|
|
||||||
</a>
|
|
||||||
, the skinny framework for creating HTML + CSS slide deck. It has a
|
|
||||||
pluggable architecture and developer can{' '}
|
|
||||||
<a
|
|
||||||
href="https://marpit.marp.app/usage?id=extend-marpit-by-plugins"
|
|
||||||
rel="noopener noreferrer"
|
|
||||||
target="_blank"
|
|
||||||
>
|
|
||||||
extend features via plugin
|
|
||||||
</a>
|
|
||||||
.
|
|
||||||
</p>
|
|
||||||
</section>
|
|
||||||
<section>
|
|
||||||
<figure>
|
|
||||||
<img
|
|
||||||
src="https://icongr.am/octicons/heart-fill.svg?size=50&color=444455"
|
|
||||||
alt="Fully open source"
|
|
||||||
/>
|
|
||||||
</figure>
|
|
||||||
<h2>
|
|
||||||
Fully <mark>open-source</mark>
|
|
||||||
</h2>
|
|
||||||
<p>
|
|
||||||
We are loving open source! All tools and related libraries by{' '}
|
|
||||||
<a
|
|
||||||
href="https://github.com/marp-team"
|
|
||||||
rel="noopener"
|
|
||||||
// eslint-disable-next-line react/jsx-no-target-blank
|
|
||||||
target="_blank"
|
|
||||||
>
|
|
||||||
Marp team
|
|
||||||
</a>{' '}
|
|
||||||
are MIT license.
|
|
||||||
</p>
|
|
||||||
</section>
|
|
||||||
</section>
|
|
||||||
)
|
|
||||||
|
|
||||||
export const Features = () => {
|
|
||||||
const { length } = FeatureSections().props.children
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div
|
|
||||||
css={css`
|
|
||||||
position: relative;
|
|
||||||
|
|
||||||
&:before {
|
|
||||||
position: absolute;
|
|
||||||
display: block;
|
|
||||||
content: '';
|
|
||||||
top: 0;
|
|
||||||
right: 0;
|
|
||||||
bottom: 0;
|
|
||||||
left: 0;
|
|
||||||
background: linear-gradient(
|
|
||||||
-8deg,
|
|
||||||
rgba(120, 197, 233, 0),
|
|
||||||
rgba(120, 197, 233, 0) 50%,
|
|
||||||
rgba(120, 197, 233, 0.5)
|
|
||||||
);
|
|
||||||
z-index: 0;
|
|
||||||
clip-path: polygon(0 15vw, 100% 0, 100% 100%, 0 100%);
|
|
||||||
}
|
|
||||||
`}
|
|
||||||
>
|
|
||||||
<FeatureSections
|
|
||||||
css={[
|
|
||||||
contentStyle,
|
|
||||||
css`
|
|
||||||
position: relative;
|
|
||||||
z-index: 1;
|
|
||||||
display: grid;
|
|
||||||
grid-template-rows: repeat(${length + 1}, auto);
|
|
||||||
grid-template-columns: 1fr;
|
|
||||||
max-width: 1200px;
|
|
||||||
|
|
||||||
section {
|
|
||||||
background: #fff;
|
|
||||||
box-shadow: 0 5px 10px rgba(0, 0, 0, 0.15);
|
|
||||||
box-sizing: border-box;
|
|
||||||
font-size: 85%;
|
|
||||||
margin: 10px;
|
|
||||||
padding: 25px;
|
|
||||||
white-space: break-word;
|
|
||||||
grid-column: 1;
|
|
||||||
|
|
||||||
figure {
|
|
||||||
margin: 0;
|
|
||||||
height: 50px;
|
|
||||||
text-align: center;
|
|
||||||
|
|
||||||
img {
|
|
||||||
width: 50px;
|
|
||||||
height: 50px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
h2 {
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
p {
|
|
||||||
font-size: 14px;
|
|
||||||
font-size: calc(14px + 0.02vw);
|
|
||||||
margin-bottom: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (min-width: 768px) {
|
|
||||||
grid-template-columns: 1fr 1fr;
|
|
||||||
|
|
||||||
section {
|
|
||||||
margin: 20px;
|
|
||||||
|
|
||||||
&:nth-of-type(odd) {
|
|
||||||
grid-column: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:nth-of-type(even) {
|
|
||||||
grid-column: 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
${[...Array(length)].map(
|
|
||||||
(_, i) => css`
|
|
||||||
&:nth-of-type(${i + 1}) {
|
|
||||||
grid-row: ${i + 1} / span 2;
|
|
||||||
}
|
|
||||||
`
|
|
||||||
)}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`,
|
|
||||||
]}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
|
@ -1,366 +0,0 @@
|
|||||||
/** @jsx jsx */
|
|
||||||
import { css, jsx } from '@emotion/core'
|
|
||||||
import { Button } from '../components/button.js.jsx'
|
|
||||||
import { Heading } from '../components/heading.js.jsx'
|
|
||||||
|
|
||||||
export const GetStarted = () => (
|
|
||||||
<section
|
|
||||||
id="get-started"
|
|
||||||
css={css`
|
|
||||||
position: relative;
|
|
||||||
|
|
||||||
/* Fix position for anchor link */
|
|
||||||
padding-top: 110px;
|
|
||||||
margin: -110px 0 -1px 0;
|
|
||||||
|
|
||||||
&::before {
|
|
||||||
background: #0288d1 url('/assets/noise.png');
|
|
||||||
bottom: 0;
|
|
||||||
clip-path: polygon(0 0, 100% 8vw, 100% 100%, 0 100%);
|
|
||||||
content: '';
|
|
||||||
display: block;
|
|
||||||
left: 0;
|
|
||||||
overflow: visible;
|
|
||||||
position: absolute;
|
|
||||||
right: 0;
|
|
||||||
top: calc(-12vw + 110px);
|
|
||||||
z-index: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
&::after {
|
|
||||||
clear: both;
|
|
||||||
content: '';
|
|
||||||
display: block;
|
|
||||||
height: 1px;
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
> p,
|
|
||||||
> section {
|
|
||||||
margin: 40px;
|
|
||||||
max-width: 1000px;
|
|
||||||
position: relative;
|
|
||||||
z-index: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
> p {
|
|
||||||
color: #fff;
|
|
||||||
margin: 30px auto;
|
|
||||||
padding: 0 40px;
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
> section {
|
|
||||||
background: #fff url('/assets/noise.png');
|
|
||||||
border-radius: 1em;
|
|
||||||
box-shadow: 0 5px 10px rgba(0, 0, 0, 0.15);
|
|
||||||
box-sizing: border-box;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
align-items: center;
|
|
||||||
font-size: calc(16px + 0.1vw);
|
|
||||||
padding: 40px 30px;
|
|
||||||
white-space: break-word;
|
|
||||||
width: auto;
|
|
||||||
|
|
||||||
@media (min-width: 1060px) {
|
|
||||||
margin: 40px auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
figure {
|
|
||||||
margin: 0 0 20px 0;
|
|
||||||
max-width: 75%;
|
|
||||||
min-width: 180px;
|
|
||||||
box-sizing: border-box;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (min-width: 768px) {
|
|
||||||
flex-direction: row;
|
|
||||||
|
|
||||||
figure {
|
|
||||||
max-width: 33%;
|
|
||||||
order: 2;
|
|
||||||
margin: 0 0 0 20px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
header {
|
|
||||||
margin: 0 0 1em 0;
|
|
||||||
|
|
||||||
h3 {
|
|
||||||
font-size: 1.5em;
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
p {
|
|
||||||
color: #888;
|
|
||||||
font-size: 75%;
|
|
||||||
margin: 0.5em 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
p {
|
|
||||||
&:last-child {
|
|
||||||
margin-bottom: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[role='button'] {
|
|
||||||
margin-top: 8px;
|
|
||||||
font-size: 83%;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`}
|
|
||||||
>
|
|
||||||
<Heading
|
|
||||||
level={2}
|
|
||||||
css={css`
|
|
||||||
background: #02669d;
|
|
||||||
color: #fff;
|
|
||||||
margin-top: 10px;
|
|
||||||
margin-bottom: 10px;
|
|
||||||
`}
|
|
||||||
>
|
|
||||||
Tools and integrations
|
|
||||||
</Heading>
|
|
||||||
<section>
|
|
||||||
<figure>
|
|
||||||
<a
|
|
||||||
href="https://marketplace.visualstudio.com/items?itemName=marp-team.marp-vscode"
|
|
||||||
target="_blank"
|
|
||||||
rel="noopener noreferrer"
|
|
||||||
>
|
|
||||||
<img
|
|
||||||
src="/assets/marp-for-vs-code.png"
|
|
||||||
alt="Marp for VS Code"
|
|
||||||
loading="lazy"
|
|
||||||
/>
|
|
||||||
</a>
|
|
||||||
</figure>
|
|
||||||
<div>
|
|
||||||
<header>
|
|
||||||
<h3>
|
|
||||||
<mark>Marp for VS Code</mark>{' '}
|
|
||||||
<img
|
|
||||||
src="https://img.shields.io/visual-studio-marketplace/v/marp-team.marp-vscode.svg?style=flat-square&label=&colorB=67b8e3"
|
|
||||||
alt="Marp for VS Code"
|
|
||||||
/>
|
|
||||||
</h3>
|
|
||||||
<p>Create slide deck written in Marp Markdown on VS Code</p>
|
|
||||||
</header>
|
|
||||||
<p>
|
|
||||||
Enhance VS Code's Markdown preview pane to support writing your
|
|
||||||
beautiful presentation. You can see the slide deck output as soon as
|
|
||||||
editting Markdown.
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
<Button
|
|
||||||
href="https://marketplace.visualstudio.com/items?itemName=marp-team.marp-vscode"
|
|
||||||
target="_blank"
|
|
||||||
rel="noopener noreferrer"
|
|
||||||
color="primary"
|
|
||||||
>
|
|
||||||
VS Marketplace
|
|
||||||
</Button>{' '}
|
|
||||||
<Button
|
|
||||||
href="https://github.com/marp-team/marp-vscode"
|
|
||||||
rel="noopener"
|
|
||||||
target="_blank"
|
|
||||||
outline="true"
|
|
||||||
>
|
|
||||||
GitHub
|
|
||||||
</Button>
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
<section>
|
|
||||||
<figure>
|
|
||||||
<a
|
|
||||||
href="https://github.com/marp-team/marp-cli"
|
|
||||||
// eslint-disable-next-line react/jsx-no-target-blank
|
|
||||||
target="_blank"
|
|
||||||
rel="noopener"
|
|
||||||
>
|
|
||||||
<img src="/assets/marp-cli.png" alt="Marp CLI" loading="lazy" />
|
|
||||||
</a>
|
|
||||||
</figure>
|
|
||||||
<div>
|
|
||||||
<header>
|
|
||||||
<h3>
|
|
||||||
<mark>Marp CLI</mark>{' '}
|
|
||||||
<img
|
|
||||||
src="https://img.shields.io/npm/v/@marp-team/marp-cli.svg?style=flat-square&label=&colorB=67b8e3"
|
|
||||||
alt="Marp CLI"
|
|
||||||
/>
|
|
||||||
</h3>
|
|
||||||
<p>A CLI interface for Marp and Marpit based converters</p>
|
|
||||||
</header>
|
|
||||||
<p>
|
|
||||||
CLI is the swiss army knife for Marp ecosystem. Convert your Markdown
|
|
||||||
into various formats, watch changes, launch server for on-demand
|
|
||||||
conversion, and customize engine.
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
<Button
|
|
||||||
href="https://www.npmjs.com/package/@marp-team/marp-cli"
|
|
||||||
rel="noopener noreferrer"
|
|
||||||
target="_blank"
|
|
||||||
color="primary"
|
|
||||||
outline="true"
|
|
||||||
>
|
|
||||||
npm
|
|
||||||
</Button>{' '}
|
|
||||||
<Button
|
|
||||||
href="https://github.com/marp-team/marp-cli"
|
|
||||||
rel="noopener"
|
|
||||||
target="_blank"
|
|
||||||
outline="true"
|
|
||||||
>
|
|
||||||
GitHub
|
|
||||||
</Button>
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
<Heading
|
|
||||||
level={3}
|
|
||||||
css={css`
|
|
||||||
background: #02669d;
|
|
||||||
color: #fff;
|
|
||||||
`}
|
|
||||||
>
|
|
||||||
For developers
|
|
||||||
</Heading>
|
|
||||||
<section>
|
|
||||||
<figure
|
|
||||||
css={css`
|
|
||||||
min-width: 100px !important;
|
|
||||||
max-width: 100px !important;
|
|
||||||
`}
|
|
||||||
>
|
|
||||||
<a
|
|
||||||
href="https://github.com/marp-team/marp-core"
|
|
||||||
// eslint-disable-next-line react/jsx-no-target-blank
|
|
||||||
target="_blank"
|
|
||||||
rel="noopener"
|
|
||||||
>
|
|
||||||
<img src="/assets/marp-logo.svg" alt="Marp Core" loading="lazy" />
|
|
||||||
</a>
|
|
||||||
</figure>
|
|
||||||
<div>
|
|
||||||
<header>
|
|
||||||
<h3>
|
|
||||||
<mark>Marp Core</mark>{' '}
|
|
||||||
<img
|
|
||||||
src="https://img.shields.io/npm/v/@marp-team/marp-core.svg?style=flat-square&label=&colorB=67b8e3"
|
|
||||||
alt="Marp Core"
|
|
||||||
/>
|
|
||||||
</h3>
|
|
||||||
<p>The core of Marp converter</p>
|
|
||||||
</header>
|
|
||||||
<p>
|
|
||||||
All official Marp tools provided by us are using this core as the
|
|
||||||
engine. It is based on Marpit framework, and includes some extended
|
|
||||||
features to help creating beautiful slide deck.
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
<Button
|
|
||||||
href="https://www.npmjs.com/package/@marp-team/marp-core"
|
|
||||||
target="_blank"
|
|
||||||
rel="noopener noreferrer"
|
|
||||||
color="primary"
|
|
||||||
outline="true"
|
|
||||||
>
|
|
||||||
npm
|
|
||||||
</Button>{' '}
|
|
||||||
<Button
|
|
||||||
href="https://github.com/marp-team/marp-core"
|
|
||||||
rel="noopener"
|
|
||||||
target="_blank"
|
|
||||||
outline="true"
|
|
||||||
>
|
|
||||||
GitHub
|
|
||||||
</Button>
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
<section>
|
|
||||||
<figure
|
|
||||||
css={css`
|
|
||||||
min-width: 100px !important;
|
|
||||||
max-width: 100px !important;
|
|
||||||
`}
|
|
||||||
>
|
|
||||||
<a
|
|
||||||
href="https://marpit.marp.app/"
|
|
||||||
// eslint-disable-next-line react/jsx-no-target-blank
|
|
||||||
target="_blank"
|
|
||||||
rel="noopener"
|
|
||||||
>
|
|
||||||
<img src="/assets/marpit.svg" alt="Marpit" loading="lazy" />
|
|
||||||
</a>
|
|
||||||
</figure>
|
|
||||||
<div>
|
|
||||||
<header>
|
|
||||||
<h3>
|
|
||||||
<mark>Marpit</mark> framework{' '}
|
|
||||||
<img
|
|
||||||
src="https://img.shields.io/npm/v/@marp-team/marpit.svg?style=flat-square&label=&colorB=67b8e3"
|
|
||||||
alt="Marpit framework"
|
|
||||||
/>
|
|
||||||
</h3>
|
|
||||||
<p>The skinny framework for creating slide deck from Markdown</p>
|
|
||||||
</header>
|
|
||||||
<p>
|
|
||||||
Marpit, independented from Marp, is the skinny framework to transform
|
|
||||||
Markdown + CSS theme to the deck composed of HTML + CSS. It has
|
|
||||||
designed to output only minimum assets.
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
<Button
|
|
||||||
href="https://marpit.marp.app/"
|
|
||||||
target="_blank"
|
|
||||||
rel="noopener noreferrer"
|
|
||||||
color="primary"
|
|
||||||
>
|
|
||||||
Documentation
|
|
||||||
</Button>{' '}
|
|
||||||
<Button
|
|
||||||
href="https://www.npmjs.com/package/@marp-team/marpit"
|
|
||||||
target="_blank"
|
|
||||||
rel="noopener noreferrer"
|
|
||||||
color="primary"
|
|
||||||
outline="true"
|
|
||||||
>
|
|
||||||
npm
|
|
||||||
</Button>{' '}
|
|
||||||
<Button
|
|
||||||
href="https://github.com/marp-team/marpit"
|
|
||||||
rel="noopener"
|
|
||||||
target="_blank"
|
|
||||||
outline="true"
|
|
||||||
>
|
|
||||||
GitHub
|
|
||||||
</Button>
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
<p>
|
|
||||||
...and find out all tools, integrations, examples at our GitHub entrance
|
|
||||||
repository!
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
<Button
|
|
||||||
color="primary"
|
|
||||||
outline="true"
|
|
||||||
href="https://github.com/marp-team/marp/"
|
|
||||||
rel="noopener"
|
|
||||||
target="_blank"
|
|
||||||
css={css`
|
|
||||||
font-size: calc(12px + 0.25vw);
|
|
||||||
`}
|
|
||||||
>
|
|
||||||
Go to the entrance repository...
|
|
||||||
</Button>
|
|
||||||
</p>
|
|
||||||
</section>
|
|
||||||
)
|
|
@ -1,66 +0,0 @@
|
|||||||
/** @jsx jsx */
|
|
||||||
import { css, jsx } from '@emotion/core'
|
|
||||||
import { Button } from '../components/button.js.jsx'
|
|
||||||
import { defaultTitle } from '../layout.jsx'
|
|
||||||
|
|
||||||
export const Hero = () => (
|
|
||||||
<section
|
|
||||||
css={css`
|
|
||||||
background: #fcfcfc url('./assets/hero-background.jpg') no-repeat right
|
|
||||||
center;
|
|
||||||
background-size: cover;
|
|
||||||
overflow: hidden;
|
|
||||||
padding: 70px 20px;
|
|
||||||
text-align: center;
|
|
||||||
`}
|
|
||||||
>
|
|
||||||
<h1
|
|
||||||
css={css`
|
|
||||||
margin: 50px 0;
|
|
||||||
font-size: calc(12px + 0.75vw);
|
|
||||||
font-weight: bold;
|
|
||||||
letter-spacing: 1px;
|
|
||||||
|
|
||||||
> img {
|
|
||||||
display: block;
|
|
||||||
max-width: 560px;
|
|
||||||
width: 80%;
|
|
||||||
height: auto;
|
|
||||||
margin: 0 auto 20px auto;
|
|
||||||
}
|
|
||||||
`}
|
|
||||||
>
|
|
||||||
<img
|
|
||||||
src="https://raw.githubusercontent.com/marp-team/marp/master/marp.png"
|
|
||||||
alt={defaultTitle}
|
|
||||||
/>
|
|
||||||
Markdown Presentation Ecosystem
|
|
||||||
</h1>
|
|
||||||
<p>
|
|
||||||
{/* TODO: Change this link to "Docs" page that would be hosted on marp.app in future */}
|
|
||||||
<Button
|
|
||||||
color="primary"
|
|
||||||
href="#get-started"
|
|
||||||
css={css`
|
|
||||||
font-size: calc(18px + 0.5vw);
|
|
||||||
padding: 0.75em 1.5em;
|
|
||||||
`}
|
|
||||||
>
|
|
||||||
Get started!
|
|
||||||
</Button>
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
<Button
|
|
||||||
color="primary"
|
|
||||||
outline="true"
|
|
||||||
href="https://github.com/marp-team/marp/"
|
|
||||||
rel="noopener"
|
|
||||||
css={css`
|
|
||||||
font-size: calc(12px + 0.25vw);
|
|
||||||
`}
|
|
||||||
>
|
|
||||||
Find out Marp tools at GitHub...
|
|
||||||
</Button>
|
|
||||||
</p>
|
|
||||||
</section>
|
|
||||||
)
|
|
@ -1,425 +0,0 @@
|
|||||||
/** @jsx jsx */
|
|
||||||
import { URL } from 'url'
|
|
||||||
import { Global, css, jsx } from '@emotion/core'
|
|
||||||
|
|
||||||
export const defaultTitle = 'Marp: Markdown Presentation Ecosystem'
|
|
||||||
export const defaultImage = '/assets/og-image.png'
|
|
||||||
|
|
||||||
export const generateTitle = (...breadcrumbs) =>
|
|
||||||
['Marp', ...breadcrumbs].reverse().join(' | ')
|
|
||||||
|
|
||||||
export const resolvePath = (path) =>
|
|
||||||
new URL(
|
|
||||||
path,
|
|
||||||
(() => {
|
|
||||||
// For Netlify deploy preview
|
|
||||||
if (process.env.CONTEXT === 'deploy-preview')
|
|
||||||
return process.env.DEPLOY_URL
|
|
||||||
|
|
||||||
if (process.env.NODE_ENV === 'production') return 'https://marp.app/'
|
|
||||||
|
|
||||||
return 'http://localhost:2468/'
|
|
||||||
})()
|
|
||||||
).toString()
|
|
||||||
|
|
||||||
export const contentStyle = css`
|
|
||||||
max-width: 1000px;
|
|
||||||
overflow: hidden;
|
|
||||||
padding: 30px;
|
|
||||||
margin: 0 auto;
|
|
||||||
`
|
|
||||||
|
|
||||||
const globalStyle = css`
|
|
||||||
html,
|
|
||||||
body {
|
|
||||||
padding: 0;
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
html {
|
|
||||||
height: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
body {
|
|
||||||
color: #445;
|
|
||||||
font-family: Quicksand, Avenir, Century Gothic, -apple-system,
|
|
||||||
BlinkMacSystemFont, sans-serif, Apple Color Emoji, Segoe UI Emoji;
|
|
||||||
font-size: 18px;
|
|
||||||
font-size: calc(15px + 0.2vw);
|
|
||||||
letter-spacing: 0.04em;
|
|
||||||
line-height: 1.4;
|
|
||||||
min-height: 100%;
|
|
||||||
position: relative;
|
|
||||||
|
|
||||||
/* "background-attachment: fixed" may break background rendering in mobile device. */
|
|
||||||
&::before {
|
|
||||||
display: block;
|
|
||||||
position: fixed;
|
|
||||||
z-index: -1;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
content: '';
|
|
||||||
background-color: #f8f8f8;
|
|
||||||
background-image: url('/assets/noise.png'),
|
|
||||||
linear-gradient(to bottom, #fafafa, #fff 50%);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
img {
|
|
||||||
border: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
a {
|
|
||||||
color: #0288d1;
|
|
||||||
text-decoration: none;
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
color: #02669d;
|
|
||||||
transition: color 0.15s linear;
|
|
||||||
|
|
||||||
&:active {
|
|
||||||
color: #1b4d68;
|
|
||||||
transition: none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
h1 {
|
|
||||||
font-size: 1.75em;
|
|
||||||
font-size: calc(1.25em + 0.4vw);
|
|
||||||
}
|
|
||||||
|
|
||||||
h2 {
|
|
||||||
font-size: 1.6em;
|
|
||||||
font-size: calc(1.2em + 0.2vw);
|
|
||||||
}
|
|
||||||
|
|
||||||
h3 {
|
|
||||||
font-size: 1.35em;
|
|
||||||
font-size: calc(1.13em + 0.1vw);
|
|
||||||
}
|
|
||||||
|
|
||||||
mark {
|
|
||||||
color: inherit;
|
|
||||||
background-color: transparent;
|
|
||||||
background-image: linear-gradient(to bottom, transparent 85%, #67b8e3 85%);
|
|
||||||
}
|
|
||||||
|
|
||||||
figure {
|
|
||||||
margin: 2em 0;
|
|
||||||
|
|
||||||
img {
|
|
||||||
max-width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
figcaption {
|
|
||||||
color: #999;
|
|
||||||
text-align: center;
|
|
||||||
font-size: 75%;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
code {
|
|
||||||
font-family: 'Source Code Pro', 'Courier New', Courier, monospace;
|
|
||||||
background-color: #f8f8f8;
|
|
||||||
letter-spacing: 0;
|
|
||||||
padding: 0 0.2em;
|
|
||||||
}
|
|
||||||
`
|
|
||||||
|
|
||||||
const headerHeight = 80
|
|
||||||
|
|
||||||
const Header = ({ route }) => (
|
|
||||||
<header
|
|
||||||
css={css`
|
|
||||||
--header-gap: calc(5px + 1vw);
|
|
||||||
|
|
||||||
background: #fff;
|
|
||||||
border: 0;
|
|
||||||
border-bottom-width: thin;
|
|
||||||
border-color: rgba(51, 51, 51, 0.07);
|
|
||||||
border-style: solid;
|
|
||||||
box-shadow: 0 0 40px rgba(128, 128, 128, 0.05);
|
|
||||||
box-sizing: border-box;
|
|
||||||
display: flex;
|
|
||||||
font-size: ${headerHeight * 0.22}px;
|
|
||||||
height: ${headerHeight}px;
|
|
||||||
left: 0;
|
|
||||||
overflow: hidden;
|
|
||||||
padding: 0 var(--header-gap);
|
|
||||||
position: sticky;
|
|
||||||
justify-content: center;
|
|
||||||
top: 0;
|
|
||||||
width: 100%;
|
|
||||||
z-index: 99;
|
|
||||||
|
|
||||||
> a {
|
|
||||||
align-items: center;
|
|
||||||
align-self: center;
|
|
||||||
display: flex;
|
|
||||||
margin: 0 var(--header-gap);
|
|
||||||
width: ${headerHeight * 0.75}px;
|
|
||||||
|
|
||||||
> img {
|
|
||||||
width: ${headerHeight * 0.75}px;
|
|
||||||
height: ${headerHeight * 0.75}px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
> nav {
|
|
||||||
> ul {
|
|
||||||
align-items: center;
|
|
||||||
display: flex;
|
|
||||||
font-weight: 500;
|
|
||||||
height: 100%;
|
|
||||||
letter-spacing: 0.1vw;
|
|
||||||
list-style: none;
|
|
||||||
margin: 0;
|
|
||||||
padding: 0;
|
|
||||||
text-transform: uppercase;
|
|
||||||
|
|
||||||
a {
|
|
||||||
position: relative;
|
|
||||||
align-items: center;
|
|
||||||
color: currentColor;
|
|
||||||
display: flex;
|
|
||||||
margin: 0 var(--header-gap);
|
|
||||||
text-decoration: none;
|
|
||||||
|
|
||||||
&::before {
|
|
||||||
/* Expand hit area */
|
|
||||||
content: '';
|
|
||||||
display: block;
|
|
||||||
position: absolute;
|
|
||||||
left: calc(var(--header-gap) * -1);
|
|
||||||
right: calc(var(--header-gap) * -1);
|
|
||||||
top: ${headerHeight * -0.5}px;
|
|
||||||
bottom: ${headerHeight * -0.5}px;
|
|
||||||
}
|
|
||||||
|
|
||||||
&::after {
|
|
||||||
content: '';
|
|
||||||
display: block;
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
right: 0;
|
|
||||||
bottom: ${headerHeight * -0.075}px;
|
|
||||||
transition: box-shadow 0.2s linear;
|
|
||||||
}
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
&::after {
|
|
||||||
box-shadow: inset 0 ${headerHeight * -0.05}px
|
|
||||||
rgba(0, 0, 0, 0.25);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&.active {
|
|
||||||
&::after {
|
|
||||||
transition: none;
|
|
||||||
box-shadow: inset 0 ${headerHeight * -0.05}px #009bda;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&:focus {
|
|
||||||
outline: 0;
|
|
||||||
|
|
||||||
&::after {
|
|
||||||
transition: none;
|
|
||||||
box-shadow: inset 0 ${headerHeight * -0.05}px #78c5e9;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&:hover:active {
|
|
||||||
&::after {
|
|
||||||
transition: none;
|
|
||||||
box-shadow: inset 0 ${headerHeight * -0.05}px #007aad;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`}
|
|
||||||
>
|
|
||||||
<a href="/">
|
|
||||||
<img src="/assets/marp-logo.svg" alt={defaultTitle} />
|
|
||||||
</a>
|
|
||||||
<nav>
|
|
||||||
<ul>
|
|
||||||
<li>
|
|
||||||
<a
|
|
||||||
href="/blog"
|
|
||||||
className={
|
|
||||||
route && route.startsWith('/blog') ? 'active' : undefined
|
|
||||||
}
|
|
||||||
>
|
|
||||||
Blog
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
<li>
|
|
||||||
<a
|
|
||||||
href="https://github.com/marp-team/marp"
|
|
||||||
// eslint-disable-next-line react/jsx-no-target-blank
|
|
||||||
target="_blank"
|
|
||||||
rel="noopener"
|
|
||||||
>
|
|
||||||
GitHub
|
|
||||||
</a>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</nav>
|
|
||||||
</header>
|
|
||||||
)
|
|
||||||
|
|
||||||
const footerHeight = 90
|
|
||||||
|
|
||||||
const Footer = ({ children }) => (
|
|
||||||
<footer
|
|
||||||
css={css`
|
|
||||||
background: #334 url('/assets/noise.png');
|
|
||||||
box-sizing: border-box;
|
|
||||||
color: #bbc;
|
|
||||||
min-height: ${footerHeight}px;
|
|
||||||
padding: 10px 30px 30px 10px;
|
|
||||||
overflow: hidden;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: row;
|
|
||||||
flex-wrap: wrap;
|
|
||||||
align-items: center;
|
|
||||||
|
|
||||||
p {
|
|
||||||
margin: 20px 0 0 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
iframe {
|
|
||||||
vertical-align: bottom;
|
|
||||||
}
|
|
||||||
`}
|
|
||||||
>
|
|
||||||
{children}
|
|
||||||
</footer>
|
|
||||||
)
|
|
||||||
|
|
||||||
export const Layout = ({
|
|
||||||
children,
|
|
||||||
description,
|
|
||||||
globalStyles,
|
|
||||||
image = defaultImage,
|
|
||||||
route,
|
|
||||||
title = defaultTitle,
|
|
||||||
type = 'article',
|
|
||||||
}) => (
|
|
||||||
<html lang="en">
|
|
||||||
<head>
|
|
||||||
<title>{title}</title>
|
|
||||||
<meta charSet="UTF-8" />
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
||||||
<meta httpEquiv="X-UA-Compatible" content="ie=edge" />
|
|
||||||
{description && (
|
|
||||||
<>
|
|
||||||
<meta name="description" content={description} />
|
|
||||||
<meta property="og:description" content={description} />
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
{route && (
|
|
||||||
<>
|
|
||||||
<link rel="canonical" content={resolvePath(route)} />
|
|
||||||
<meta property="og:url" content={resolvePath(route)} />
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
<meta property="og:title" content={title} />
|
|
||||||
<meta property="og:type" content={type} />
|
|
||||||
<meta property="og:image" content={resolvePath(image)} />
|
|
||||||
<meta
|
|
||||||
property="twitter:card"
|
|
||||||
content={type === 'website' ? 'summary_large_image' : 'summary'}
|
|
||||||
/>
|
|
||||||
<link rel="icon" href="/favicon.png" type="image/png" />
|
|
||||||
<link
|
|
||||||
rel="apple-touch-icon"
|
|
||||||
sizes="180x180"
|
|
||||||
href="/apple-touch-icon-180x180.png"
|
|
||||||
/>
|
|
||||||
<link
|
|
||||||
rel="stylesheet"
|
|
||||||
href="https://fonts.googleapis.com/css?family=Quicksand:400,500,700|Source+Code+Pro:400,500&display=swap"
|
|
||||||
/>
|
|
||||||
<link href="/highlightjs.css" rel="stylesheet" />
|
|
||||||
<Global styles={[globalStyle, globalStyles]} />
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<Header route={route} />
|
|
||||||
<main
|
|
||||||
css={css`
|
|
||||||
min-height: calc(100vh - ${headerHeight + footerHeight}px);
|
|
||||||
`}
|
|
||||||
>
|
|
||||||
{children}
|
|
||||||
</main>
|
|
||||||
<Footer>
|
|
||||||
<p>Copyright © 2019- Marp Team.</p>
|
|
||||||
<p>
|
|
||||||
<iframe
|
|
||||||
src="https://ghbtns.com/github-btn.html?user=marp-team&repo=marp&type=star&count=true"
|
|
||||||
title="Stars"
|
|
||||||
loading="lazy"
|
|
||||||
frameBorder="0"
|
|
||||||
scrolling="0"
|
|
||||||
width="160"
|
|
||||||
height="20"
|
|
||||||
/>
|
|
||||||
</p>
|
|
||||||
</Footer>
|
|
||||||
<a
|
|
||||||
href="#"
|
|
||||||
title="Back to top"
|
|
||||||
css={css`
|
|
||||||
position: fixed;
|
|
||||||
right: 0;
|
|
||||||
bottom: 0;
|
|
||||||
width: calc(30px + 5vw);
|
|
||||||
height: calc(30px + 5vw);
|
|
||||||
max-width: ${footerHeight}px;
|
|
||||||
max-height: ${footerHeight}px;
|
|
||||||
color: #fff !important;
|
|
||||||
z-index: 100;
|
|
||||||
display: block;
|
|
||||||
filter: drop-shadow(0 0 5px rgba(0, 0, 0, 0.25));
|
|
||||||
line-height: ${footerHeight * 3}px;
|
|
||||||
pointer-events: none;
|
|
||||||
overflow: hidden;
|
|
||||||
|
|
||||||
background: linear-gradient(135deg, transparent 50%, #67b8e3 50%);
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
background: linear-gradient(135deg, transparent 50%, #0288d1 50%);
|
|
||||||
|
|
||||||
&:active {
|
|
||||||
background: linear-gradient(135deg, transparent 50%, #02669d 50%);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&::after {
|
|
||||||
display: block;
|
|
||||||
position: absolute;
|
|
||||||
top: 0;
|
|
||||||
right: 0;
|
|
||||||
bottom: 0;
|
|
||||||
left: 0;
|
|
||||||
content: '';
|
|
||||||
pointer-events: auto;
|
|
||||||
clip-path: polygon(0 100%, 100% 0, 100% 100%);
|
|
||||||
background: url('https://icongr.am/octicons/arrow-up.svg?color=ffffff')
|
|
||||||
no-repeat 80% 80%;
|
|
||||||
background-size: 35% 35%;
|
|
||||||
}
|
|
||||||
`}
|
|
||||||
>
|
|
||||||
Back to top
|
|
||||||
</a>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
)
|
|
9
tsconfig.json
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
{
|
||||||
|
"extends": "@tsconfig/recommended/tsconfig.json",
|
||||||
|
"compilerOptions": {
|
||||||
|
"lib": ["es2015", "dom"],
|
||||||
|
"noImplicitAny": false,
|
||||||
|
"resolveJsonModule": true,
|
||||||
|
"strict": true
|
||||||
|
}
|
||||||
|
}
|
1
website/.env.development
Normal file
@ -0,0 +1 @@
|
|||||||
|
NEXT_PUBLIC_HOST=http://localhost:3000/
|
1
website/.env.production
Normal file
@ -0,0 +1 @@
|
|||||||
|
NEXT_PUBLIC_HOST=https://marp.app/
|
29
website/.eslintrc.js
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
module.exports = {
|
||||||
|
extends: [
|
||||||
|
'plugin:import/react',
|
||||||
|
'plugin:react/recommended',
|
||||||
|
'plugin:react-hooks/recommended',
|
||||||
|
'plugin:jsx-a11y/recommended',
|
||||||
|
'prettier/react',
|
||||||
|
],
|
||||||
|
rules: {
|
||||||
|
'react/react-in-jsx-scope': 'off',
|
||||||
|
'jsx-a11y/anchor-is-valid': [
|
||||||
|
'error',
|
||||||
|
{
|
||||||
|
components: ['Link'],
|
||||||
|
specialLink: ['hrefLeft', 'hrefRight'],
|
||||||
|
aspects: ['invalidHref', 'preferButton'],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
overrides: [
|
||||||
|
{
|
||||||
|
files: ['**/*.ts', '**/*.tsx'],
|
||||||
|
rules: {
|
||||||
|
'react/prop-types': 'off',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
settings: { react: { version: 'detect' } },
|
||||||
|
}
|
19
website/babel.config.js
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
const path = require('path')
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
presets: [
|
||||||
|
[
|
||||||
|
'next/babel',
|
||||||
|
{
|
||||||
|
'styled-jsx': {
|
||||||
|
plugins: [
|
||||||
|
[
|
||||||
|
'styled-jsx-plugin-postcss',
|
||||||
|
{ path: path.resolve(__dirname, './postcss.config.js') },
|
||||||
|
],
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
],
|
||||||
|
}
|
44
website/blog/re-creation-of-marp-website.md
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
---
|
||||||
|
title: Re-creation of Marp website for the unified docs
|
||||||
|
date: 2020-08-22
|
||||||
|
author: Yuki Hattori
|
||||||
|
github: yhatt
|
||||||
|
---
|
||||||
|
|
||||||
|
[marpit framework]: https://marpit.marp.app/
|
||||||
|
[marp core]: https://github.com/marp-team/marp-core
|
||||||
|
[marp cli]: https://github.com/marp-team/marp-cli
|
||||||
|
[marp for vs code]: https://marketplace.visualstudio.com/items?itemName=marp-team.marp-vscode
|
||||||
|
|
||||||
|
I could not have imagined that now we are living in a unique pandemic era when I wrote [the last article](/blog/the-story-of-marp-next). Even under those severe circumstances, I'm still making progress of Marp.
|
||||||
|
|
||||||
|
Marp gives some tools for making a convincing slide deck with fewer efforts, and they get loved by a lot of users. In early this year, [Marp Core] has reached the stable v1 release, and our tools around the core are keeping steps with it. Needless to mention here, we will keep going to enhance our tools.
|
||||||
|
|
||||||
|
Today we are announcing that **Marp team is working to the re-creation of [marp.app](/) website for hosting the unified documentation**. If you are reading this article, you should have already seen the re-created website! Currently the unified docs is not yet ready but we are going to announce here as soon as getting ready.
|
||||||
|
|
||||||
|
<!-- more -->
|
||||||
|
|
||||||
|
# For the unified documentation
|
||||||
|
|
||||||
|
As Marp ecosystem spreads out, Marp team has become to regard the lack of unified documentation as an important issue. Our docs are scattered to many repos per tool, and it would make confusion when learning overall of Marp. In addition, we often have been asked basics of Marp in the issue tracker and sometimes even prevent our works for evolving Marp.
|
||||||
|
|
||||||
|
For making users take advantage of Marp easier, I'm going to work improving the documentation together with evolving Marp tools.
|
||||||
|
|
||||||
|
## Re-created [marp.app](/)
|
||||||
|
|
||||||
|
The re-created web page is the first step for building the unified docs. I had tried various tools to build the website and found a place to rest in [Next.js](https://nextjs.org/) and [Tailwind CSS](https://tailwindcss.com/). I believe we will be able to build more useful documentation pages by these.
|
||||||
|
|
||||||
|
It is managed in our entrance repository [marp-team/marp](https://github.com/marp-team/marp) as same as before. If shipped new documentation, we would accept some improvements in the documentation from the community.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Mid-term plans for Marp tools
|
||||||
|
|
||||||
|
Might as well, finally let me share some mid-term plans for each tools I'll work shortly.
|
||||||
|
|
||||||
|
- [Marpit framework]: Enhance directives
|
||||||
|
- [Marp Core]: Add new built-in theme and simplify auto-scaling feature
|
||||||
|
- [Marp CLI]: Handout template
|
||||||
|
- [Marp for VS Code]: Better auto-completion for Marp directives
|
||||||
|
|
||||||
|
We also had announced [long-term plans earlier](/blog/the-story-of-marp-next): [Marp Web](https://web.marp.app/), Marp integration modules with [React](https://github.com/marp-team/marp-react) and [Vue](https://github.com/marp-team/marp-react), and [Marpit v2](https://github.com/marp-team/marpit/issues/194). However, _they are not yet in active and may need to reconsider plans because we have not enough positive feedbacks from community._
|
@ -1,21 +1,11 @@
|
|||||||
import { BlogLayout } from '../blog.jsx'
|
---
|
||||||
|
title: The story of Marp Next
|
||||||
export const meta = {
|
date: 2019-06-06
|
||||||
slug: 'the-story-of-marp-next',
|
description: Today, I'm so excited to introduce the story of Marp Next! The full-rewritten Marp is not only just a writer. To be usable in various situations, we build a brand-new Marp ecosystem consisted of multiple modules.
|
||||||
title: 'The story of Marp Next',
|
author: Yuki Hattori
|
||||||
image: '/blog/og-images/the-story-of-marp-next.png',
|
github: yhatt
|
||||||
description:
|
image: /og-images/the-story-of-marp-next.png
|
||||||
"Today, I'm so excited to introduce the story of Marp Next! The full-rewritten Marp is not only just a writer. To be usable in various situations, we build a brand-new Marp ecosystem consisted of multiple modules.",
|
---
|
||||||
date: '2019-06-06',
|
|
||||||
author: 'Yuki Hattori',
|
|
||||||
github: 'yhatt',
|
|
||||||
}
|
|
||||||
|
|
||||||
export const layout = ({ children, environment }) => (
|
|
||||||
<BlogLayout environment={environment} meta={meta}>
|
|
||||||
{children}
|
|
||||||
</BlogLayout>
|
|
||||||
)
|
|
||||||
|
|
||||||
The first version of [Marp](https://yhatt.github.io/marp/) was released at almost 3 years ago. At first, it was started from a simple tool for personal usage called "mdSlide". And now, Marp has been used by a lot of users who would recognize the real value of the presentation writer. Marp is amassed around [8,000 stars](https://github.com/yhatt/marp/stargazers) until now.
|
The first version of [Marp](https://yhatt.github.io/marp/) was released at almost 3 years ago. At first, it was started from a simple tool for personal usage called "mdSlide". And now, Marp has been used by a lot of users who would recognize the real value of the presentation writer. Marp is amassed around [8,000 stars](https://github.com/yhatt/marp/stargazers) until now.
|
||||||
|
|
||||||
@ -23,6 +13,8 @@ However, our headache brought from lacked maintainability to develop. We had rec
|
|||||||
|
|
||||||
Today, I'm so excited to introduce the story of Marp Next! The full-rewritten Marp is not only just a writer. To be usable in various situations, we build **a brand-new Marp ecosystem** consisted of multiple modules. They are developed with JavaScript and TypeScript, and much more maintainable than the previous Marp.
|
Today, I'm so excited to introduce the story of Marp Next! The full-rewritten Marp is not only just a writer. To be usable in various situations, we build **a brand-new Marp ecosystem** consisted of multiple modules. They are developed with JavaScript and TypeScript, and much more maintainable than the previous Marp.
|
||||||
|
|
||||||
|
<!-- more -->
|
||||||
|
|
||||||
# Marp ecosystem
|
# Marp ecosystem
|
||||||
|
|
||||||
Marp Next has two core components: **[Marpit]** framework and **[Marp Core]**. Tools by Marp ecosystem are usually based on these.
|
Marp Next has two core components: **[Marpit]** framework and **[Marp Core]**. Tools by Marp ecosystem are usually based on these.
|
||||||
@ -94,11 +86,7 @@ Many of the features are based on the old desktop app, and have improved to be s
|
|||||||
|
|
||||||
**[Marp CLI]** is a CLI interface of Marpit and Marp Core converter. It's a Swiss-Army knife for Marp slide deck!
|
**[Marp CLI]** is a CLI interface of Marpit and Marp Core converter. It's a Swiss-Army knife for Marp slide deck!
|
||||||
|
|
||||||
<figure>
|
[![Marp CLI](https://raw.githubusercontent.com/marp-team/marp-cli/master/docs/images/marp-cli.gif ' ')][marp cli]
|
||||||
|
|
||||||
[![](https://raw.githubusercontent.com/marp-team/marp-cli/master/docs/images/marp-cli.gif)][marp cli]
|
|
||||||
|
|
||||||
</figure>
|
|
||||||
|
|
||||||
You can use it right now by running `npx @marp-team/marp-cli` if [Node.js](https://nodejs.org/) is installed.
|
You can use it right now by running `npx @marp-team/marp-cli` if [Node.js](https://nodejs.org/) is installed.
|
||||||
|
|
||||||
@ -131,22 +119,13 @@ It made [some strong oppositions by users that is using Marp in offline](https:/
|
|||||||
|
|
||||||
And 2 years later, the time has come to use PWA! After the first access to **[https://web.marp.app/][marp web]**, Marp Web would be ready to use in both of online and offline. Online resources to use the web interface would be cached in your browser, and use them when network is offline.
|
And 2 years later, the time has come to use PWA! After the first access to **[https://web.marp.app/][marp web]**, Marp Web would be ready to use in both of online and offline. Online resources to use the web interface would be cached in your browser, and use them when network is offline.
|
||||||
|
|
||||||
<figure>
|
[![Marp Web + Progressive Web Apps](https://raw.githubusercontent.com/marp-team/marp-web/master/desktop-pwa.png ' ')][marp web]
|
||||||
|
|
||||||
[<img src="https://raw.githubusercontent.com/marp-team/marp-web/master/desktop-pwa.png" width="640" />][marp web]
|
|
||||||
|
|
||||||
</figure>
|
|
||||||
|
|
||||||
### Use via any devices
|
### Use via any devices
|
||||||
|
|
||||||
By migrating to the web-based app, Marp will be able using in mobile device: Android and iOS. That's sure it's well suited to the tablet device like iPad.
|
By migrating to the web-based app, Marp will be able using in mobile device: Android and iOS. That's sure it's well suited to the tablet device like iPad.
|
||||||
|
|
||||||
<figure>
|
![Marp Web on iPad](https://user-images.githubusercontent.com/3993388/50569518-5305c800-0daa-11e9-8fa4-08053c9b51cd.png ' ')
|
||||||
<img
|
|
||||||
src="https://user-images.githubusercontent.com/3993388/50569518-5305c800-0daa-11e9-8fa4-08053c9b51cd.png"
|
|
||||||
width="640"
|
|
||||||
/>
|
|
||||||
</figure>
|
|
||||||
|
|
||||||
Marp Web would work also in Chrome OS well. Marp especially has many users in the field of education, and supporting Chrome OS that has large share in its field is meaningful.
|
Marp Web would work also in Chrome OS well. Marp especially has many users in the field of education, and supporting Chrome OS that has large share in its field is meaningful.
|
||||||
|
|
||||||
@ -164,11 +143,7 @@ The modulized Marp Core brought Marp integrations for some tools.
|
|||||||
|
|
||||||
Honestly, I don't think to want to make a new editor because there are many great Markdown editors in the world. I had been thinking it would be awesome if Marp could integrate with a something else powerful Markdown editor. And now, Marp can use in [Visual Studio Code](https://code.visualstudio.com/)!
|
Honestly, I don't think to want to make a new editor because there are many great Markdown editors in the world. I had been thinking it would be awesome if Marp could integrate with a something else powerful Markdown editor. And now, Marp can use in [Visual Studio Code](https://code.visualstudio.com/)!
|
||||||
|
|
||||||
<figure>
|
![Marp for VS Code](/assets/marp-for-vs-code.png ' ')
|
||||||
|
|
||||||
[<img src="https://marp.app/assets/marp-for-vs-code.png" width="640" />][marp vscode]
|
|
||||||
|
|
||||||
</figure>
|
|
||||||
|
|
||||||
It was realized because VS Code is using the same Markdown engine (markdown-it) as Marpit framework. Of course you can export slides as PDF and HTML easily, powered by [Marp CLI].
|
It was realized because VS Code is using the same Markdown engine (markdown-it) as Marpit framework. Of course you can export slides as PDF and HTML easily, powered by [Marp CLI].
|
||||||
|
|
||||||
@ -234,4 +209,4 @@ Marp Next just focuses to build the ecosystem for Markdown slide deck with pure
|
|||||||
|
|
||||||
We still have stood at the beginning of the brand-new ecosystem. Are you interested to Marp team and our ecosystem? We welcome to start your contribution! See [our contributing guideline](https://github.com/marp-team/marp/blob/master/.github/CONTRIBUTING.md) and get started!
|
We still have stood at the beginning of the brand-new ecosystem. Are you interested to Marp team and our ecosystem? We welcome to start your contribution! See [our contributing guideline](https://github.com/marp-team/marp/blob/master/.github/CONTRIBUTING.md) and get started!
|
||||||
|
|
||||||
> PS. I've started [Patreon](https://www.patreon.com/yhatt) and stood in a line of [GitHub Sponsors](https://github.com/sponsors). These are also good contribution if you want to help my working for open source.
|
> PS. [GitHub Sponsors](https://github.com/sponsors/yhatt) is also good contribution if you want to help my working for open source.
|
104
website/components/Button.tsx
Normal file
@ -0,0 +1,104 @@
|
|||||||
|
import classNames from 'classnames'
|
||||||
|
|
||||||
|
export type ButtonProps = {
|
||||||
|
color?: 'primary'
|
||||||
|
outline?: boolean
|
||||||
|
[key: string]: unknown
|
||||||
|
}
|
||||||
|
|
||||||
|
export const Button = ({
|
||||||
|
children,
|
||||||
|
className,
|
||||||
|
color,
|
||||||
|
href,
|
||||||
|
outline,
|
||||||
|
...rest
|
||||||
|
}: ButtonProps) => {
|
||||||
|
const Tag = href ? 'a' : 'button'
|
||||||
|
const attrs = {
|
||||||
|
...rest,
|
||||||
|
...(Tag === 'a' ? { href, role: 'button', tabIndex: 0 } : {}),
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Tag
|
||||||
|
{...attrs}
|
||||||
|
className={classNames(
|
||||||
|
Tag === 'a' && 'custom-anchor',
|
||||||
|
'button',
|
||||||
|
color,
|
||||||
|
{ outline },
|
||||||
|
className as any
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
<style jsx>{`
|
||||||
|
.button {
|
||||||
|
@apply appearance-none no-underline inline-block relative select-none font-bold rounded-full shadow-md bg-white text-center;
|
||||||
|
|
||||||
|
padding: 0.625em 1.25em;
|
||||||
|
transition: color, background-color, opacity;
|
||||||
|
}
|
||||||
|
|
||||||
|
@screen md {
|
||||||
|
.button {
|
||||||
|
@apply tracking-wider;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.button:hover {
|
||||||
|
@apply bg-background duration-150;
|
||||||
|
}
|
||||||
|
.button:hover:active {
|
||||||
|
@apply outline-none shadow-outline bg-gray-300;
|
||||||
|
|
||||||
|
transition-duration: 0s;
|
||||||
|
}
|
||||||
|
.button:focus {
|
||||||
|
@apply outline-none shadow-outline;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Primary color */
|
||||||
|
.button.primary {
|
||||||
|
@apply bg-marp-brand text-white;
|
||||||
|
|
||||||
|
background-image: linear-gradient(
|
||||||
|
30deg,
|
||||||
|
transparent,
|
||||||
|
rgba(255, 255, 255, 0.3)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
.button.primary:hover {
|
||||||
|
@apply bg-marp-darken;
|
||||||
|
}
|
||||||
|
.button.primary:hover:active {
|
||||||
|
@apply bg-marp-dark;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Outline */
|
||||||
|
.button.outline {
|
||||||
|
@apply text-foreground;
|
||||||
|
}
|
||||||
|
.button.outline::after {
|
||||||
|
@apply absolute block inset-0 pointer-events-none border-current border-2;
|
||||||
|
|
||||||
|
border-radius: inherit;
|
||||||
|
content: '';
|
||||||
|
transition: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
.button.outline.primary {
|
||||||
|
@apply text-marp-brand bg-white;
|
||||||
|
|
||||||
|
background-image: none;
|
||||||
|
}
|
||||||
|
.button.outline.primary:hover {
|
||||||
|
@apply bg-marp-darken text-white;
|
||||||
|
}
|
||||||
|
.button.outline.primary:hover::after {
|
||||||
|
@apply opacity-0;
|
||||||
|
}
|
||||||
|
`}</style>
|
||||||
|
</Tag>
|
||||||
|
)
|
||||||
|
}
|
176
website/components/CodeBlock.tsx
Normal file
@ -0,0 +1,176 @@
|
|||||||
|
/* eslint-disable react/jsx-key */
|
||||||
|
import classNames from 'classnames'
|
||||||
|
import Highlight, {
|
||||||
|
defaultProps,
|
||||||
|
Language,
|
||||||
|
PrismTheme,
|
||||||
|
} from 'prism-react-renderer'
|
||||||
|
import nightOwlLight from 'prism-react-renderer/themes/nightOwlLight'
|
||||||
|
import { useRef, useState, MouseEvent } from 'react'
|
||||||
|
import { Button } from 'components/Button'
|
||||||
|
|
||||||
|
const theme: PrismTheme = {
|
||||||
|
plain: {
|
||||||
|
...nightOwlLight.plain,
|
||||||
|
backgroundColor: '#f5f5f5',
|
||||||
|
},
|
||||||
|
styles: [
|
||||||
|
...nightOwlLight.styles,
|
||||||
|
{ types: ['italic'], style: { fontStyle: 'italic' } },
|
||||||
|
{ types: ['important', 'bold'], style: { fontWeight: 'bold' } },
|
||||||
|
],
|
||||||
|
}
|
||||||
|
|
||||||
|
export type CodeBlockProps = {
|
||||||
|
children: string
|
||||||
|
copyButton?: boolean
|
||||||
|
language: Language
|
||||||
|
lineNumber?: boolean
|
||||||
|
[key: string]: unknown
|
||||||
|
}
|
||||||
|
|
||||||
|
export const CodeBlock = ({
|
||||||
|
children,
|
||||||
|
className,
|
||||||
|
copyButton,
|
||||||
|
language,
|
||||||
|
lineNumber = false,
|
||||||
|
...rest
|
||||||
|
}: CodeBlockProps) => {
|
||||||
|
const [copied, setCopied] = useState(false)
|
||||||
|
const copiedTimer = useRef<number | undefined>(undefined)
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Highlight
|
||||||
|
{...defaultProps}
|
||||||
|
code={children}
|
||||||
|
language={language}
|
||||||
|
theme={theme}
|
||||||
|
>
|
||||||
|
{({ className: cn, style, tokens, getLineProps, getTokenProps }) => (
|
||||||
|
<div className={classNames('code-block-container', className as any)}>
|
||||||
|
<pre
|
||||||
|
className={classNames(lineNumber && 'line-number', cn)}
|
||||||
|
style={style}
|
||||||
|
{...rest}
|
||||||
|
>
|
||||||
|
<code className="code-block">
|
||||||
|
<ol className="code-block">
|
||||||
|
{tokens.map((line, i) => {
|
||||||
|
const lineProps = getLineProps({ line, key: i })
|
||||||
|
|
||||||
|
return (
|
||||||
|
<li
|
||||||
|
{...lineProps}
|
||||||
|
className={classNames(
|
||||||
|
lineProps.className,
|
||||||
|
'code-block'
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
{line.map((token, key) =>
|
||||||
|
token.empty ? (
|
||||||
|
<br key={key} />
|
||||||
|
) : (
|
||||||
|
<span {...getTokenProps({ token, key })} />
|
||||||
|
)
|
||||||
|
)}
|
||||||
|
</li>
|
||||||
|
)
|
||||||
|
})}
|
||||||
|
</ol>
|
||||||
|
</code>
|
||||||
|
</pre>
|
||||||
|
{copyButton && (
|
||||||
|
<div className="copy-btn-container">
|
||||||
|
<Button
|
||||||
|
className={copied ? 'copied' : undefined}
|
||||||
|
onClick={(e: MouseEvent<HTMLButtonElement>) => {
|
||||||
|
const tmpTextarea = document.createElement('textarea')
|
||||||
|
tmpTextarea.value = children
|
||||||
|
|
||||||
|
tmpTextarea.style.position = 'absolute'
|
||||||
|
tmpTextarea.style.left = '0'
|
||||||
|
tmpTextarea.style.top = '0'
|
||||||
|
tmpTextarea.style.opacity = '0'
|
||||||
|
tmpTextarea.style.pointerEvents = 'none'
|
||||||
|
|
||||||
|
document.body.appendChild(tmpTextarea)
|
||||||
|
tmpTextarea.select()
|
||||||
|
|
||||||
|
document.execCommand('copy')
|
||||||
|
document.body.removeChild(tmpTextarea)
|
||||||
|
e.currentTarget.focus()
|
||||||
|
|
||||||
|
// Update React state
|
||||||
|
setCopied(true)
|
||||||
|
|
||||||
|
if (copiedTimer.current !== undefined) {
|
||||||
|
window.clearTimeout(copiedTimer.current)
|
||||||
|
}
|
||||||
|
|
||||||
|
copiedTimer.current = window.setTimeout(() => {
|
||||||
|
copiedTimer.current = undefined
|
||||||
|
setCopied(false)
|
||||||
|
}, 1000)
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{copied ? 'Copied!' : 'Copy'}
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</Highlight>
|
||||||
|
<style jsx>{`
|
||||||
|
.code-block-container {
|
||||||
|
@apply relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.prism-code {
|
||||||
|
@apply text-sm border rounded-lg leading-5 whitespace-pre overflow-x-auto overflow-y-hidden break-words shadow-inner;
|
||||||
|
|
||||||
|
font-family: inherit;
|
||||||
|
background-image: url('/assets/noise.png');
|
||||||
|
}
|
||||||
|
|
||||||
|
.prism-code code {
|
||||||
|
@apply inline-block p-4 min-w-full font-mono;
|
||||||
|
}
|
||||||
|
|
||||||
|
.prism-code.line-number {
|
||||||
|
@apply whitespace-pre-wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.prism-code.line-number ol {
|
||||||
|
counter-reset: line 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.prism-code.line-number li {
|
||||||
|
@apply relative pl-12;
|
||||||
|
|
||||||
|
counter-increment: line;
|
||||||
|
}
|
||||||
|
|
||||||
|
.prism-code.line-number li::before {
|
||||||
|
@apply absolute inset-0 w-12 pr-3 text-right text-gray-500 text-xs leading-5;
|
||||||
|
|
||||||
|
content: counter(line);
|
||||||
|
}
|
||||||
|
|
||||||
|
.copy-btn-container {
|
||||||
|
@apply absolute top-0 right-0 m-3;
|
||||||
|
}
|
||||||
|
|
||||||
|
.copy-btn-container :global(button) {
|
||||||
|
@apply text-xs opacity-0 transition-opacity duration-300 w-24 py-1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.code-block-container:hover .copy-btn-container :global(button),
|
||||||
|
.copy-btn-container :global(button):focus {
|
||||||
|
@apply opacity-100;
|
||||||
|
}
|
||||||
|
`}</style>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
29
website/components/Footer.tsx
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
import { ScrollToTop } from 'components/ScrollToTop'
|
||||||
|
|
||||||
|
export const Footer = () => (
|
||||||
|
<footer>
|
||||||
|
<div className="container mx-auto table">
|
||||||
|
<p className="mx-6 my-5 mr-20 leading-loose">
|
||||||
|
Copyright © 2019-{process.env.BUILD_YEAR} Marp team. 
|
||||||
|
<iframe
|
||||||
|
className="inline-block align-text-top"
|
||||||
|
src="https://ghbtns.com/github-btn.html?user=marp-team&repo=marp&type=star&count=true"
|
||||||
|
frameBorder={0}
|
||||||
|
scrolling="0"
|
||||||
|
width={150}
|
||||||
|
height={20}
|
||||||
|
title="GitHub"
|
||||||
|
></iframe>
|
||||||
|
</p>
|
||||||
|
<ScrollToTop />
|
||||||
|
</div>
|
||||||
|
<style jsx>{`
|
||||||
|
footer {
|
||||||
|
@apply bg-gray-800 text-gray-500;
|
||||||
|
|
||||||
|
min-height: 4.5rem;
|
||||||
|
background-image: url('/assets/noise.png');
|
||||||
|
}
|
||||||
|
`}</style>
|
||||||
|
</footer>
|
||||||
|
)
|
147
website/components/Header.tsx
Normal file
@ -0,0 +1,147 @@
|
|||||||
|
import classNames from 'classnames'
|
||||||
|
import Head from 'next/head'
|
||||||
|
import Link from 'next/link'
|
||||||
|
|
||||||
|
const handleMouseUp = (e: React.MouseEvent<HTMLElement>) =>
|
||||||
|
e.currentTarget.blur()
|
||||||
|
|
||||||
|
export type ItemSlug = 'docs' | 'blog'
|
||||||
|
|
||||||
|
export const Header = ({ activeItem }: { activeItem?: ItemSlug }) => (
|
||||||
|
<>
|
||||||
|
<Head>
|
||||||
|
<link rel="preload" href="/assets/marp-logo.svg" as="image" />
|
||||||
|
</Head>
|
||||||
|
<header className="z-50 flex justify-center bg-white shadow-sm fixed top-0 left-0 w-full h-16 md:h-20">
|
||||||
|
<Link href="/">
|
||||||
|
<a
|
||||||
|
className="custom-anchor header-item"
|
||||||
|
role="link"
|
||||||
|
tabIndex={0}
|
||||||
|
onMouseUp={handleMouseUp}
|
||||||
|
>
|
||||||
|
<img
|
||||||
|
src="/assets/marp-logo.svg"
|
||||||
|
alt="Marp"
|
||||||
|
className="block h-16 w-16 p-2 md:p-3 md:h-20 md:w-20"
|
||||||
|
/>
|
||||||
|
</a>
|
||||||
|
</Link>
|
||||||
|
<nav className="ml-2">
|
||||||
|
<ul className="flex items-stretch h-16 md:h-20">
|
||||||
|
{/* TODO: Add document page and remove noIndex from docs layout */}
|
||||||
|
{/*
|
||||||
|
<li className="relative flex items-center justify-center">
|
||||||
|
<Link href="/docs">
|
||||||
|
<a
|
||||||
|
className={classNames('custom-anchor header-item nav-item', {
|
||||||
|
active: activeItem === 'docs',
|
||||||
|
})}
|
||||||
|
role="link"
|
||||||
|
tabIndex={0}
|
||||||
|
onMouseUp={handleMouseUp}
|
||||||
|
>
|
||||||
|
<span>Docs</span>
|
||||||
|
</a>
|
||||||
|
</Link>
|
||||||
|
</li>
|
||||||
|
*/}
|
||||||
|
<li className="relative flex items-center justify-center">
|
||||||
|
<Link href="/blog">
|
||||||
|
<a
|
||||||
|
className={classNames('custom-anchor header-item nav-item', {
|
||||||
|
active: activeItem === 'blog',
|
||||||
|
})}
|
||||||
|
role="link"
|
||||||
|
tabIndex={0}
|
||||||
|
onMouseUp={handleMouseUp}
|
||||||
|
>
|
||||||
|
<span>Blog</span>
|
||||||
|
</a>
|
||||||
|
</Link>
|
||||||
|
</li>
|
||||||
|
<li className="relative flex items-center justify-center">
|
||||||
|
<a
|
||||||
|
href="https://github.com/marp-team/marp"
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
className="custom-anchor header-item nav-item"
|
||||||
|
onMouseUp={handleMouseUp}
|
||||||
|
>
|
||||||
|
<span>GitHub</span>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</nav>
|
||||||
|
<style jsx>{`
|
||||||
|
.header-item {
|
||||||
|
@apply no-underline text-current outline-none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header-item > img {
|
||||||
|
@apply transition-transform duration-200;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header-item:hover:active > img {
|
||||||
|
@apply transform scale-125 shadow-none;
|
||||||
|
|
||||||
|
-webkit-tap-highlight-color: transparent;
|
||||||
|
transition-duration: 0ms;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media not all and (hover: none) {
|
||||||
|
.header-item:hover:active > img {
|
||||||
|
@apply scale-110;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-item {
|
||||||
|
@apply font-rounded font-medium mx-2 uppercase text-lg leading-none outline-none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-item::before {
|
||||||
|
@apply absolute inset-0;
|
||||||
|
|
||||||
|
content: '';
|
||||||
|
}
|
||||||
|
|
||||||
|
.header-item:focus-visible,
|
||||||
|
.nav-item:focus-visible::before {
|
||||||
|
@apply bg-gray-200;
|
||||||
|
}
|
||||||
|
|
||||||
|
@screen md {
|
||||||
|
.nav-item {
|
||||||
|
@apply mx-3 tracking-wider;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-item > span {
|
||||||
|
@apply relative z-10;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-item > span::after {
|
||||||
|
@apply absolute block inset-x-0 h-1 mt-1 transition-all duration-300;
|
||||||
|
|
||||||
|
content: '';
|
||||||
|
top: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-item:hover > span::after,
|
||||||
|
.nav-item:focus-within > span::after {
|
||||||
|
box-shadow: inset 0 -0.25rem theme('colors.gray.400');
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-item.active > span::after {
|
||||||
|
transition-duration: 0ms;
|
||||||
|
box-shadow: inset 0 -0.25rem theme('colors.marp.brand');
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-item:hover:active > span::after {
|
||||||
|
transition-duration: 0ms;
|
||||||
|
box-shadow: inset 0 -0.25rem theme('colors.marp.dark');
|
||||||
|
}
|
||||||
|
`}</style>
|
||||||
|
</header>
|
||||||
|
</>
|
||||||
|
)
|
91
website/components/Layout.tsx
Normal file
@ -0,0 +1,91 @@
|
|||||||
|
import Head from 'next/head'
|
||||||
|
import { useRouter } from 'next/router'
|
||||||
|
import { Footer } from 'components/Footer'
|
||||||
|
import { Header, ItemSlug } from 'components/Header'
|
||||||
|
import { generateTitle } from 'utils/title'
|
||||||
|
import { absoluteUrl } from 'utils/url'
|
||||||
|
|
||||||
|
export type LayoutProps = {
|
||||||
|
activeItem?: ItemSlug
|
||||||
|
canonical?: string
|
||||||
|
description?: string
|
||||||
|
image?: string
|
||||||
|
noIndex?: boolean
|
||||||
|
title?: string | string[]
|
||||||
|
type?: string
|
||||||
|
}
|
||||||
|
|
||||||
|
const defaultDescription =
|
||||||
|
'Marp, Markdown Presentation Ecosystem, provides the great experience to create beautiful slide deck. You only have to focus writing your story in Markdown document.'
|
||||||
|
|
||||||
|
export const Layout: React.FC<LayoutProps> = ({
|
||||||
|
activeItem,
|
||||||
|
canonical: _canonical,
|
||||||
|
children,
|
||||||
|
description = defaultDescription,
|
||||||
|
image: _image,
|
||||||
|
noIndex,
|
||||||
|
title: _title,
|
||||||
|
type = 'article',
|
||||||
|
}) => {
|
||||||
|
const router = useRouter()
|
||||||
|
|
||||||
|
const canonical = absoluteUrl(_canonical || router.asPath).href
|
||||||
|
const image = _image || '/assets/og-image.png'
|
||||||
|
const title = typeof _title === 'string' ? _title : generateTitle(_title)
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Head>
|
||||||
|
<title key="title">{title}</title>
|
||||||
|
{description && (
|
||||||
|
<>
|
||||||
|
<meta name="description" key="description" content={description} />
|
||||||
|
<meta
|
||||||
|
property="og:description"
|
||||||
|
key="og:description"
|
||||||
|
content={description}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
{canonical && (
|
||||||
|
<>
|
||||||
|
<link rel="canonical" key="canonical" href={canonical} />
|
||||||
|
<meta property="og:url" key="og:url" content={canonical} />
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
<meta property="og:title" key="og:title" content={title} />
|
||||||
|
<meta property="og:type" key="og:type" content={type} />
|
||||||
|
<meta
|
||||||
|
property="og:image"
|
||||||
|
key="og:image"
|
||||||
|
content={absoluteUrl(image).href}
|
||||||
|
/>
|
||||||
|
<meta
|
||||||
|
property="twitter:card"
|
||||||
|
key="twitter:card"
|
||||||
|
content={
|
||||||
|
type === 'website' || _image ? 'summary_large_image' : 'summary'
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
{noIndex && <meta name="robots" content="noindex,nofollow" />}
|
||||||
|
</Head>
|
||||||
|
<Header activeItem={activeItem} />
|
||||||
|
<main className="relative mt-16 md:mt-20">
|
||||||
|
{children}
|
||||||
|
<style jsx>{`
|
||||||
|
main {
|
||||||
|
min-height: calc(100vh - 8.5rem);
|
||||||
|
}
|
||||||
|
|
||||||
|
@screen md {
|
||||||
|
main {
|
||||||
|
min-height: calc(100vh - 9.5rem);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`}</style>
|
||||||
|
</main>
|
||||||
|
<Footer />
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
51
website/components/Marp.tsx
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
import { Marp as MarpCore } from '@marp-team/marp-core'
|
||||||
|
import { browser } from '@marp-team/marp-core/browser'
|
||||||
|
import classNames from 'classnames'
|
||||||
|
import { useEffect, useRef } from 'react'
|
||||||
|
|
||||||
|
export type RenderedMarp = ReturnType<typeof generateRenderedMarp>
|
||||||
|
|
||||||
|
export type MarpProps = {
|
||||||
|
className?: string
|
||||||
|
rendered: RenderedMarp
|
||||||
|
page?: number
|
||||||
|
}
|
||||||
|
|
||||||
|
export const generateRenderedMarp = (markdown: string) => {
|
||||||
|
const marp = new MarpCore({
|
||||||
|
container: false,
|
||||||
|
script: false,
|
||||||
|
printable: false,
|
||||||
|
})
|
||||||
|
|
||||||
|
return { markdown, ...marp.render(markdown, { htmlAsArray: true }) }
|
||||||
|
}
|
||||||
|
|
||||||
|
export const Marp = ({
|
||||||
|
className,
|
||||||
|
rendered: { css, html },
|
||||||
|
page = 1,
|
||||||
|
}: MarpProps) => {
|
||||||
|
const element = useRef<HTMLDivElement>(null)
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!element.current) return
|
||||||
|
if (!element.current.shadowRoot)
|
||||||
|
element.current.attachShadow({ mode: 'open' })
|
||||||
|
|
||||||
|
// Render Marp slide to shadow root (tailwind default styles will break Marp slide CSS)
|
||||||
|
const root = element.current.shadowRoot as ShadowRoot
|
||||||
|
|
||||||
|
root.innerHTML =
|
||||||
|
html[page - 1] +
|
||||||
|
`<style>${css}</style><style>:host{all:initial;}:host>[data-marpit-svg]{vertical-align:top;}</style>`
|
||||||
|
|
||||||
|
return browser(root)
|
||||||
|
}, [css, html, page])
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className={classNames('border shadow-lg', className)}>
|
||||||
|
<span ref={element} />
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
43
website/components/ScrollToTop.tsx
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
import { useCallback } from 'react'
|
||||||
|
|
||||||
|
export const ScrollToTop = () => {
|
||||||
|
const handleClick = useCallback<React.MouseEventHandler<HTMLElement>>((e) => {
|
||||||
|
window.scrollTo({ top: 0 })
|
||||||
|
e.currentTarget.blur()
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="scroll-to-top">
|
||||||
|
<button onClick={handleClick} title="Scroll to top">
|
||||||
|
<span className="sr-only">Scroll to top</span>
|
||||||
|
</button>
|
||||||
|
<style jsx>{`
|
||||||
|
.scroll-to-top {
|
||||||
|
@apply fixed right-0 bottom-0 z-50 pointer-events-none;
|
||||||
|
|
||||||
|
filter: drop-shadow(0 0px 7px rgba(0, 0, 0, 0.3))
|
||||||
|
drop-shadow(0 0px 4px rgba(0, 0, 0, 0.15));
|
||||||
|
}
|
||||||
|
button {
|
||||||
|
@apply appearance-none text-white w-20 h-20 bg-marp-light align-top pointer-events-auto;
|
||||||
|
|
||||||
|
background-image: url('https://icongr.am/octicons/arrow-up.svg?color=ffffff');
|
||||||
|
background-position: 80% 80%;
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
background-size: 35% 35%;
|
||||||
|
clip-path: polygon(100% 0, 100% 100%, 0 100%);
|
||||||
|
}
|
||||||
|
button:hover {
|
||||||
|
@apply bg-marp-brand;
|
||||||
|
}
|
||||||
|
button:focus {
|
||||||
|
@apply outline-none;
|
||||||
|
}
|
||||||
|
button:focus,
|
||||||
|
button:hover:active {
|
||||||
|
@apply bg-marp-dark;
|
||||||
|
}
|
||||||
|
`}</style>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
17
website/components/Title.tsx
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
export const Title: React.FC = ({ children }) => (
|
||||||
|
<section className="border-b bg-marp-brand text-white py-3">
|
||||||
|
<h1 className="text-3xl font-bold text-center font-rounded uppercase">
|
||||||
|
{children}
|
||||||
|
<style jsx>{`
|
||||||
|
& :global(a),
|
||||||
|
& :global(a:hover),
|
||||||
|
& :global(a:hover:active) {
|
||||||
|
@apply no-underline text-current;
|
||||||
|
}
|
||||||
|
& :global(a:focus-visible) {
|
||||||
|
@apply underline outline-none;
|
||||||
|
}
|
||||||
|
`}</style>
|
||||||
|
</h1>
|
||||||
|
</section>
|
||||||
|
)
|
133
website/components/Typography.tsx
Normal file
@ -0,0 +1,133 @@
|
|||||||
|
export const Typography: React.FC = ({ children }) => (
|
||||||
|
<div className="typography">
|
||||||
|
{children}
|
||||||
|
<style jsx>{`
|
||||||
|
.typography {
|
||||||
|
@apply break-words leading-relaxed text-base;
|
||||||
|
}
|
||||||
|
.typography :global(p) {
|
||||||
|
@apply my-4;
|
||||||
|
}
|
||||||
|
.typography :global(h1) {
|
||||||
|
@apply relative font-bold text-3xl mt-8 mb-5;
|
||||||
|
}
|
||||||
|
.typography :global(h2) {
|
||||||
|
@apply relative font-bold text-2xl mt-8 mb-5;
|
||||||
|
}
|
||||||
|
.typography :global(h3) {
|
||||||
|
@apply relative font-bold text-xl mt-8 mb-4;
|
||||||
|
}
|
||||||
|
.typography :global(h4) {
|
||||||
|
@apply relative font-bold text-lg mt-6 mb-4;
|
||||||
|
}
|
||||||
|
.typography :global(h5) {
|
||||||
|
@apply relative font-bold text-base mt-6 mb-4;
|
||||||
|
}
|
||||||
|
.typography :global(h6) {
|
||||||
|
@apply relative font-bold text-sm text-gray-600 mt-6 mb-4;
|
||||||
|
}
|
||||||
|
.typography :global(.anchor-link) {
|
||||||
|
@apply absolute inset-0 w-5 -ml-5 overflow-hidden whitespace-no-wrap my-auto bg-no-repeat bg-left hidden;
|
||||||
|
|
||||||
|
background-size: 1rem 1rem;
|
||||||
|
background-image: url('https://icongr.am/octicons/link.svg?color=718096');
|
||||||
|
}
|
||||||
|
.typography :global(h1:hover > .anchor-link),
|
||||||
|
.typography :global(h2:hover > .anchor-link),
|
||||||
|
.typography :global(h3:hover > .anchor-link),
|
||||||
|
.typography :global(h4:hover > .anchor-link),
|
||||||
|
.typography :global(h5:hover > .anchor-link),
|
||||||
|
.typography :global(h6:hover > .anchor-link) {
|
||||||
|
@apply block;
|
||||||
|
}
|
||||||
|
.typography :global(hr) {
|
||||||
|
@apply my-8;
|
||||||
|
}
|
||||||
|
.typography :global(blockquote) {
|
||||||
|
@apply text-gray-600 border-l-4 border-marp-light pl-5 my-6;
|
||||||
|
}
|
||||||
|
.typography :global(blockquote blockquote) {
|
||||||
|
border-left-width: 3px;
|
||||||
|
}
|
||||||
|
.typography :global(blockquote blockquote blockquote) {
|
||||||
|
@apply border-l-2;
|
||||||
|
}
|
||||||
|
.typography :global(ul) {
|
||||||
|
@apply list-disc ml-8 mr-3 my-6;
|
||||||
|
}
|
||||||
|
.typography :global(ul ul) {
|
||||||
|
list-style-type: circle;
|
||||||
|
}
|
||||||
|
.typography :global(ul ul ul) {
|
||||||
|
list-style-type: square;
|
||||||
|
}
|
||||||
|
.typography :global(ol:not(.code-block)) {
|
||||||
|
@apply list-decimal ml-8 mr-3 my-6;
|
||||||
|
}
|
||||||
|
.typography :global(ul ul),
|
||||||
|
.typography :global(ul ol:not(._)),
|
||||||
|
.typography :global(ol:not(._) ul),
|
||||||
|
.typography :global(ol:not(._) ol:not(._)) {
|
||||||
|
@apply my-0 mr-0;
|
||||||
|
}
|
||||||
|
.typography :global(li:not(.code-block)) {
|
||||||
|
@apply my-1;
|
||||||
|
}
|
||||||
|
.typography :global(code:not(.code-block)) {
|
||||||
|
@apply bg-gray-200 border rounded border-gray-400;
|
||||||
|
|
||||||
|
font-size: 0.9em;
|
||||||
|
padding: 0.15em 0.35em;
|
||||||
|
}
|
||||||
|
.typography :global(pre) {
|
||||||
|
@apply my-6;
|
||||||
|
}
|
||||||
|
.typography :global(img) {
|
||||||
|
@apply inline;
|
||||||
|
}
|
||||||
|
.typography :global(figure) {
|
||||||
|
@apply my-6;
|
||||||
|
}
|
||||||
|
.typography :global(figure img) {
|
||||||
|
@apply block mx-auto max-w-screen-md w-full;
|
||||||
|
}
|
||||||
|
.typography :global(figcaption) {
|
||||||
|
@apply text-gray-600 text-sm text-center mx-auto w-11/12 my-4;
|
||||||
|
}
|
||||||
|
.typography :global(table) {
|
||||||
|
@apply max-w-full mx-auto my-8;
|
||||||
|
}
|
||||||
|
.typography :global(td),
|
||||||
|
.typography :global(th) {
|
||||||
|
@apply p-2 border-b border-gray-500 text-sm;
|
||||||
|
}
|
||||||
|
.typography :global(thead tr:last-child td),
|
||||||
|
.typography :global(thead tr:last-child th) {
|
||||||
|
@apply border-b-2;
|
||||||
|
}
|
||||||
|
|
||||||
|
@screen sm {
|
||||||
|
.typography :global(td),
|
||||||
|
.typography :global(th) {
|
||||||
|
@apply py-2 px-4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@screen md {
|
||||||
|
.typography :global(td),
|
||||||
|
.typography :global(th) {
|
||||||
|
@apply text-base;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.typography > :global(*:first-child),
|
||||||
|
.typography > :global(*:first-child *:first-child) {
|
||||||
|
@apply mt-0;
|
||||||
|
}
|
||||||
|
.typography > :global(*:last-child),
|
||||||
|
.typography > :global(*:last-child *:last-child) {
|
||||||
|
@apply mb-0;
|
||||||
|
}
|
||||||
|
`}</style>
|
||||||
|
</div>
|
||||||
|
)
|
85
website/components/blog/BlogHeader.tsx
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
import Link from 'next/link'
|
||||||
|
import { formatDate, formatDateShort } from 'utils/date'
|
||||||
|
|
||||||
|
export type BlogHeaderProps = {
|
||||||
|
author?: string
|
||||||
|
date?: Date
|
||||||
|
github?: string
|
||||||
|
slug: string
|
||||||
|
title: string
|
||||||
|
}
|
||||||
|
|
||||||
|
export const BlogHeader = ({
|
||||||
|
author,
|
||||||
|
date,
|
||||||
|
github,
|
||||||
|
slug,
|
||||||
|
title,
|
||||||
|
}: BlogHeaderProps) => (
|
||||||
|
<div className="text-center text-gray-600">
|
||||||
|
<Link href={`/blog/${slug}`}>
|
||||||
|
<a>
|
||||||
|
<h1 className="text-gradient text-3xl font-bold md:text-4xl">
|
||||||
|
{title}
|
||||||
|
</h1>
|
||||||
|
</a>
|
||||||
|
</Link>
|
||||||
|
{date && (
|
||||||
|
<p className="mt-4">
|
||||||
|
<time dateTime={formatDateShort(date)}>{formatDate(date)}</time>
|
||||||
|
</p>
|
||||||
|
)}
|
||||||
|
<p className="author">
|
||||||
|
{(author || github) && (
|
||||||
|
<>
|
||||||
|
{github && (
|
||||||
|
<img
|
||||||
|
src={`https://github.com/${github}.png`}
|
||||||
|
alt={author || github}
|
||||||
|
className="h-16 w-16 rounded-full shadow-md bg-white mr-4"
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
<span className="leading-relaxed">
|
||||||
|
by{' '}
|
||||||
|
{author && (
|
||||||
|
<>
|
||||||
|
{author}
|
||||||
|
{github && <br />}
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
{github && (
|
||||||
|
<a
|
||||||
|
href={`https://github.com/${github}`}
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
>
|
||||||
|
@{github}
|
||||||
|
</a>
|
||||||
|
)}
|
||||||
|
</span>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
<style jsx>{`
|
||||||
|
.author {
|
||||||
|
@apply mt-5 flex text-left items-center -mx-6;
|
||||||
|
}
|
||||||
|
|
||||||
|
.author::before,
|
||||||
|
.author::after {
|
||||||
|
@apply block flex-1 h-px mx-6 bg-gray-400;
|
||||||
|
|
||||||
|
content: '';
|
||||||
|
}
|
||||||
|
|
||||||
|
.author:empty {
|
||||||
|
@apply h-px mx-0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.author:empty::before,
|
||||||
|
.author:empty::after {
|
||||||
|
@apply mx-0;
|
||||||
|
}
|
||||||
|
`}</style>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
)
|
204
website/components/docs/Layout.tsx
Normal file
@ -0,0 +1,204 @@
|
|||||||
|
import classNames from 'classnames'
|
||||||
|
import { useState } from 'react'
|
||||||
|
import { useMedia } from 'use-media'
|
||||||
|
import { Navigation } from './Navigation'
|
||||||
|
import { useDrawer } from './useDrawer'
|
||||||
|
import { Layout } from 'components/Layout'
|
||||||
|
|
||||||
|
export type LayoutProps = {
|
||||||
|
breadcrumbs?: React.ReactNode[]
|
||||||
|
}
|
||||||
|
|
||||||
|
const PageLayout: React.FC<LayoutProps> = ({ breadcrumbs = [], children }) => {
|
||||||
|
const [drawer, setDrawer] = useState<HTMLElement | null>(null)
|
||||||
|
const drawerEnabled = !useMedia({ minWidth: '768px' })
|
||||||
|
const { active, handleClose, handleOpen, open } = useDrawer({
|
||||||
|
drawer,
|
||||||
|
enabled: drawerEnabled,
|
||||||
|
})
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Layout
|
||||||
|
activeItem="docs"
|
||||||
|
title={['Docs']}
|
||||||
|
noIndex // TODO: Remove noIndex
|
||||||
|
>
|
||||||
|
<div className="docs-container">
|
||||||
|
{drawerEnabled && (
|
||||||
|
<div
|
||||||
|
className={classNames('docs-backdrop', { active, open })}
|
||||||
|
onClick={handleClose}
|
||||||
|
aria-hidden
|
||||||
|
></div>
|
||||||
|
)}
|
||||||
|
<nav
|
||||||
|
className={classNames('docs-nav', {
|
||||||
|
active,
|
||||||
|
open,
|
||||||
|
enabled: drawerEnabled,
|
||||||
|
})}
|
||||||
|
ref={setDrawer}
|
||||||
|
tabIndex={drawerEnabled && !open ? -1 : undefined}
|
||||||
|
aria-hidden={drawerEnabled && !open}
|
||||||
|
>
|
||||||
|
{drawerEnabled && (
|
||||||
|
<button
|
||||||
|
className="docs-nav-button docs-nav-button-close"
|
||||||
|
onClick={handleClose}
|
||||||
|
>
|
||||||
|
<img
|
||||||
|
src="https://icongr.am/octicons/x.svg?color=4a5568"
|
||||||
|
alt="Close navigation"
|
||||||
|
className="w-8 h-8"
|
||||||
|
/>
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
|
<Navigation />
|
||||||
|
</nav>
|
||||||
|
<article className="docs-article">
|
||||||
|
<nav className="docs-breadcrumb">
|
||||||
|
{drawerEnabled && (
|
||||||
|
<button className="docs-nav-button" onClick={handleOpen}>
|
||||||
|
<img
|
||||||
|
src="https://icongr.am/octicons/three-bars.svg?color=4a5568"
|
||||||
|
alt="Open navigation"
|
||||||
|
className="p-1 w-8 h-8"
|
||||||
|
/>
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
|
{!!breadcrumbs.length && (
|
||||||
|
<ol>
|
||||||
|
{breadcrumbs.map((el, i) => (
|
||||||
|
<li key={i}>{el}</li>
|
||||||
|
))}
|
||||||
|
</ol>
|
||||||
|
)}
|
||||||
|
</nav>
|
||||||
|
<section className="container mx-auto md:px-4">{children}</section>
|
||||||
|
</article>
|
||||||
|
<style jsx>{`
|
||||||
|
.docs-container {
|
||||||
|
@apply relative flex text-sm;
|
||||||
|
|
||||||
|
min-height: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
.docs-backdrop {
|
||||||
|
@apply fixed inset-0 opacity-0 transition-opacity pointer-events-none cursor-pointer;
|
||||||
|
|
||||||
|
-webkit-tap-highlight-color: transparent;
|
||||||
|
backdrop-filter: blur(2px);
|
||||||
|
background: rgba(255, 255, 255, 0.5);
|
||||||
|
z-index: 60;
|
||||||
|
}
|
||||||
|
.docs-backdrop.active {
|
||||||
|
@apply duration-300;
|
||||||
|
}
|
||||||
|
.docs-backdrop.open {
|
||||||
|
@apply pointer-events-auto opacity-100;
|
||||||
|
}
|
||||||
|
|
||||||
|
.docs-nav {
|
||||||
|
@apply px-8 my-8 w-64 border-r;
|
||||||
|
}
|
||||||
|
.docs-nav.enabled {
|
||||||
|
@apply fixed inset-0 bg-background my-0 py-8 overflow-auto transform -translate-x-full;
|
||||||
|
|
||||||
|
transition-property: box-shadow, transform;
|
||||||
|
z-index: 60;
|
||||||
|
}
|
||||||
|
.docs-nav.enabled.active {
|
||||||
|
@apply duration-300;
|
||||||
|
}
|
||||||
|
.docs-nav.enabled.open {
|
||||||
|
@apply transform-none shadow-2xl;
|
||||||
|
}
|
||||||
|
|
||||||
|
.docs-article {
|
||||||
|
@apply flex-1 relative p-8 mt-12;
|
||||||
|
}
|
||||||
|
|
||||||
|
.docs-breadcrumb {
|
||||||
|
@apply fixed inset-x-0 h-12 flex items-center px-4 bg-white text-gray-600 shadow-sm z-50;
|
||||||
|
|
||||||
|
top: 4rem;
|
||||||
|
}
|
||||||
|
.docs-breadcrumb::after {
|
||||||
|
@apply absolute inset-0 w-4 h-full pointer-events-none;
|
||||||
|
|
||||||
|
left: 3rem;
|
||||||
|
background: linear-gradient(
|
||||||
|
to right,
|
||||||
|
theme('colors.white') 50%,
|
||||||
|
rgba(255, 255, 255, 0)
|
||||||
|
);
|
||||||
|
content: '';
|
||||||
|
}
|
||||||
|
|
||||||
|
.docs-breadcrumb ol {
|
||||||
|
@apply relative flex items-center justify-end overflow-x-hidden h-full;
|
||||||
|
}
|
||||||
|
.docs-breadcrumb li {
|
||||||
|
@apply block whitespace-no-wrap;
|
||||||
|
}
|
||||||
|
.docs-breadcrumb li::before {
|
||||||
|
@apply pl-6 bg-no-repeat;
|
||||||
|
|
||||||
|
background-image: url('https://icongr.am/octicons/triangle-right.svg?color=718096');
|
||||||
|
background-position: 0.25rem center;
|
||||||
|
background-size: 1rem 1rem;
|
||||||
|
content: '';
|
||||||
|
}
|
||||||
|
.docs-breadcrumb li:first-child::before {
|
||||||
|
@apply pl-4;
|
||||||
|
|
||||||
|
background-image: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.docs-nav-button {
|
||||||
|
@apply flex-shrink-0 appearance-none rounded h-8 w-8 outline-none;
|
||||||
|
}
|
||||||
|
.docs-nav-button:focus-visible {
|
||||||
|
@apply bg-gray-200;
|
||||||
|
}
|
||||||
|
.docs-nav-button > img {
|
||||||
|
@apply transition-transform duration-200;
|
||||||
|
}
|
||||||
|
.docs-nav-button > img:hover:active {
|
||||||
|
@apply transform scale-125;
|
||||||
|
|
||||||
|
transition-duration: 0ms;
|
||||||
|
}
|
||||||
|
|
||||||
|
.docs-nav-button-close {
|
||||||
|
@apply mb-6 -ml-1;
|
||||||
|
}
|
||||||
|
|
||||||
|
@screen md {
|
||||||
|
.docs-article {
|
||||||
|
@apply mt-0;
|
||||||
|
}
|
||||||
|
.docs-breadcrumb {
|
||||||
|
@apply static bg-transparent shadow-none px-0 h-auto mb-6;
|
||||||
|
}
|
||||||
|
.docs-breadcrumb::after,
|
||||||
|
.docs-breadcrumb li:first-child::before {
|
||||||
|
@apply hidden;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@screen xl {
|
||||||
|
.docs-container {
|
||||||
|
@apply text-base;
|
||||||
|
}
|
||||||
|
.docs-nav {
|
||||||
|
@apply w-3/12;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`}</style>
|
||||||
|
</div>
|
||||||
|
</Layout>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export { PageLayout as Layout }
|
27
website/components/docs/Navigation.tsx
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
export const Navigation = () => (
|
||||||
|
<div className="xl:w-5/6 xl:mx-auto">
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
<h3 className="font-rounded font-bold text-gray-600 uppercase text-lg xl:text-xl">
|
||||||
|
Concept
|
||||||
|
</h3>
|
||||||
|
<ul>
|
||||||
|
<li className="mt-3">What's Marp?</li>
|
||||||
|
</ul>
|
||||||
|
<ul>
|
||||||
|
<li className="mt-3">Ecosystem</li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
<ul className="mt-8">
|
||||||
|
<li>
|
||||||
|
<h3 className="font-rounded font-bold text-gray-600 uppercase text-lg xl:text-xl">
|
||||||
|
Markdown
|
||||||
|
</h3>
|
||||||
|
<ul>
|
||||||
|
<li className="mt-3">How to write slides</li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
)
|
55
website/components/docs/useDrawer.ts
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
import { disableBodyScroll, enableBodyScroll } from 'body-scroll-lock'
|
||||||
|
import { useRouter } from 'next/router'
|
||||||
|
import { useCallback, useEffect, useRef, useState } from 'react'
|
||||||
|
|
||||||
|
export type UseDrawerOptions = {
|
||||||
|
drawer?: HTMLElement | null
|
||||||
|
duration?: number
|
||||||
|
enabled?: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
export const useDrawer = ({
|
||||||
|
drawer,
|
||||||
|
duration = 300,
|
||||||
|
enabled = true,
|
||||||
|
}: UseDrawerOptions = {}) => {
|
||||||
|
const router = useRouter()
|
||||||
|
const [open, setOpen] = useState(false)
|
||||||
|
const [active, setActive] = useState(false)
|
||||||
|
const activeTimer = useRef<number>()
|
||||||
|
|
||||||
|
const handleOpen = useCallback(() => {
|
||||||
|
setOpen(true)
|
||||||
|
setActive(true)
|
||||||
|
}, [])
|
||||||
|
const handleClose = useCallback(() => {
|
||||||
|
setOpen(false)
|
||||||
|
setActive(true)
|
||||||
|
}, [])
|
||||||
|
const toggle = useCallback(() => {
|
||||||
|
open ? handleClose() : handleOpen()
|
||||||
|
}, [open, handleOpen, handleClose])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
router.events.on('routeChangeComplete', handleClose)
|
||||||
|
return () => router.events.off('routeChangeComplete', handleClose)
|
||||||
|
}, [handleClose, router.events])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (drawer && enabled && open) {
|
||||||
|
disableBodyScroll(drawer)
|
||||||
|
return () => enableBodyScroll(drawer)
|
||||||
|
}
|
||||||
|
}, [drawer, enabled, open])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (active && enabled) {
|
||||||
|
if (activeTimer.current !== undefined)
|
||||||
|
window.clearTimeout(activeTimer.current)
|
||||||
|
|
||||||
|
activeTimer.current = window.setTimeout(() => setActive(false), duration)
|
||||||
|
}
|
||||||
|
}, [active, duration, enabled])
|
||||||
|
|
||||||
|
return { active, handleClose, handleOpen, toggle, open: enabled && open }
|
||||||
|
}
|
74
website/components/top/Description.tsx
Normal file
@ -0,0 +1,74 @@
|
|||||||
|
import classNames from 'classnames'
|
||||||
|
import { useState } from 'react'
|
||||||
|
import { Button } from 'components/Button'
|
||||||
|
import { CodeBlock } from 'components/CodeBlock'
|
||||||
|
import { Marp, RenderedMarp } from 'components/Marp'
|
||||||
|
|
||||||
|
export type DescriptionProps = {
|
||||||
|
example: RenderedMarp
|
||||||
|
}
|
||||||
|
|
||||||
|
export const Description = ({ example }: DescriptionProps) => {
|
||||||
|
const [showExample, setShowExample] = useState(false)
|
||||||
|
|
||||||
|
return (
|
||||||
|
<section className="container mx-auto py-16">
|
||||||
|
<h2 className="w-5/6 mx-auto text-gradient text-center text-3xl font-bold md:text-4xl">
|
||||||
|
The great experience to create slide deck with Markdown
|
||||||
|
</h2>
|
||||||
|
<p className="w-5/6 mx-auto mt-8 md:text-lg lg:w-2/3">
|
||||||
|
Marp, Markdown Presentation Ecosystem, provides the great experience to
|
||||||
|
create beautiful slide deck. You only have to focus writing your story
|
||||||
|
in Markdown document.
|
||||||
|
</p>
|
||||||
|
<figure className="text-center m-8 mb-0">
|
||||||
|
<Marp
|
||||||
|
rendered={example}
|
||||||
|
page={1}
|
||||||
|
className="max-w-sm w-full inline-block"
|
||||||
|
/>
|
||||||
|
<Marp
|
||||||
|
rendered={example}
|
||||||
|
page={2}
|
||||||
|
className="max-w-sm w-full inline-block mt-5 lg:ml-5 lg:mt-0"
|
||||||
|
/>
|
||||||
|
<figcaption className="mt-5 text-sm text-gray-500">
|
||||||
|
We're rendering slides generated in{' '}
|
||||||
|
<a href="https://github.com/marp-team/marp-core">Marp Core</a>
|
||||||
|
</figcaption>
|
||||||
|
</figure>
|
||||||
|
<p className="text-center mt-8 mx-auto w-5/6">
|
||||||
|
<Button
|
||||||
|
className="text-sm"
|
||||||
|
onClick={() => setShowExample((v) => !v)}
|
||||||
|
aria-expanded={showExample}
|
||||||
|
>
|
||||||
|
{showExample ? 'Hide' : 'Show'} Markdown example...
|
||||||
|
<img
|
||||||
|
className={classNames(
|
||||||
|
'inline w-4 h-4 ml-1 transform transition-transform duration-300 md:w-6 md:h-6 md:-my-1',
|
||||||
|
showExample && '-rotate-180'
|
||||||
|
)}
|
||||||
|
style={showExample ? {} : { verticalAlign: 'sub' }}
|
||||||
|
src="https://icongr.am/octicons/chevron-down.svg?color=4a5568"
|
||||||
|
alt=""
|
||||||
|
/>
|
||||||
|
</Button>
|
||||||
|
</p>
|
||||||
|
<div
|
||||||
|
aria-hidden={!showExample}
|
||||||
|
className="overflow-hidden transition-all duration-300"
|
||||||
|
style={{ maxHeight: showExample ? '1000px' : '0' }}
|
||||||
|
>
|
||||||
|
<CodeBlock
|
||||||
|
language="markdown"
|
||||||
|
lineNumber
|
||||||
|
className="mx-auto mt-5 w-5/6 xl:w-2/3"
|
||||||
|
copyButton={showExample}
|
||||||
|
>
|
||||||
|
{example.markdown}
|
||||||
|
</CodeBlock>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
)
|
||||||
|
}
|
300
website/components/top/Features.tsx
Normal file
@ -0,0 +1,300 @@
|
|||||||
|
type CardProps = {
|
||||||
|
name: string
|
||||||
|
icon: string
|
||||||
|
index: number
|
||||||
|
}
|
||||||
|
|
||||||
|
const Card: React.FC<CardProps> = ({ children, name, icon, index }) => (
|
||||||
|
<section className="card">
|
||||||
|
<div>
|
||||||
|
<img
|
||||||
|
className="mx-auto w-12 h-12 m-2 lg:w-16 lg:h-16"
|
||||||
|
src={icon}
|
||||||
|
alt={name}
|
||||||
|
/>
|
||||||
|
<h3 className="text-gradient text-2xl text-center font-semibold my-4">
|
||||||
|
{name}
|
||||||
|
</h3>
|
||||||
|
<p className="text-sm lg:text-base">{children}</p>
|
||||||
|
</div>
|
||||||
|
<style jsx>{`
|
||||||
|
.card {
|
||||||
|
@apply flex justify-center items-center bg-white shadow-lg rounded-lg mx-4 my-8 p-6 mb-0 relative z-10;
|
||||||
|
|
||||||
|
grid-column: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
@screen md {
|
||||||
|
.card {
|
||||||
|
grid-row: ${index + 1} / span 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card:first-child {
|
||||||
|
@apply mt-0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card:nth-of-type(even) {
|
||||||
|
grid-column: 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`}</style>
|
||||||
|
</section>
|
||||||
|
)
|
||||||
|
|
||||||
|
const cards = [
|
||||||
|
({ index }) => (
|
||||||
|
<Card
|
||||||
|
index={index}
|
||||||
|
name="Based on CommonMark"
|
||||||
|
icon="https://icongr.am/octicons/markdown.svg?color=4a5568"
|
||||||
|
>
|
||||||
|
If you know how to write document with Markdown, you already know how to
|
||||||
|
write Marp slide deck too. Our format is based on{' '}
|
||||||
|
<a
|
||||||
|
href="https://commonmark.org/"
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
>
|
||||||
|
CommonMark
|
||||||
|
</a>
|
||||||
|
, the consistent spec of Markdown. The only important difference is{' '}
|
||||||
|
<a
|
||||||
|
href="https://marpit.marp.app/markdown"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
target="_blank"
|
||||||
|
>
|
||||||
|
a ruler <code>---</code> for splitting pages.
|
||||||
|
</a>
|
||||||
|
</Card>
|
||||||
|
),
|
||||||
|
({ index }) => (
|
||||||
|
<Card
|
||||||
|
index={index}
|
||||||
|
name="Directives and extended syntax"
|
||||||
|
icon="https://icongr.am/octicons/code-square.svg?color=4a5568"
|
||||||
|
>
|
||||||
|
Nevertheless, you may think the simple text content is lacking to
|
||||||
|
emphasize your voice. We are supporting to create beautiful slide through{' '}
|
||||||
|
<a
|
||||||
|
href="https://marpit.marp.app/directives"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
target="_blank"
|
||||||
|
>
|
||||||
|
directives
|
||||||
|
</a>{' '}
|
||||||
|
and extended syntax (
|
||||||
|
<a
|
||||||
|
href="https://marpit.marp.app/image-syntax"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
target="_blank"
|
||||||
|
>
|
||||||
|
Image syntax
|
||||||
|
</a>
|
||||||
|
,{' '}
|
||||||
|
<a
|
||||||
|
href="https://github.com/marp-team/marp-core#math-typesetting"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
target="_blank"
|
||||||
|
>
|
||||||
|
math typesetting
|
||||||
|
</a>
|
||||||
|
,{' '}
|
||||||
|
<a
|
||||||
|
href="https://github.com/marp-team/marp-core#auto-scaling-features"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
target="_blank"
|
||||||
|
>
|
||||||
|
auto-scaling
|
||||||
|
</a>
|
||||||
|
, etc...).
|
||||||
|
</Card>
|
||||||
|
),
|
||||||
|
({ index }) => (
|
||||||
|
<Card
|
||||||
|
index={index}
|
||||||
|
name="Built-in themes and CSS theming"
|
||||||
|
icon="https://icongr.am/octicons/paintbrush.svg?color=4a5568"
|
||||||
|
>
|
||||||
|
<a
|
||||||
|
href="https://github.com/marp-team/marp-core/"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
target="_blank"
|
||||||
|
>
|
||||||
|
Our core engine
|
||||||
|
</a>{' '}
|
||||||
|
has{' '}
|
||||||
|
<a
|
||||||
|
href="https://github.com/marp-team/marp-core/tree/master/themes"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
target="_blank"
|
||||||
|
>
|
||||||
|
3 built-in themes called <code>default</code>, <code>gaia</code>, and{' '}
|
||||||
|
<code>uncover</code>
|
||||||
|
</a>
|
||||||
|
, to tell your story beautifully. If you are feeling unsatisfied to
|
||||||
|
design, Marp can{' '}
|
||||||
|
<a
|
||||||
|
href="https://marpit.marp.app/theme-css?id=tweak-style-through-markdown"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
target="_blank"
|
||||||
|
>
|
||||||
|
tweak style through Markdown
|
||||||
|
</a>
|
||||||
|
, or{' '}
|
||||||
|
<a
|
||||||
|
href="https://marpit.marp.app/theme-css"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
target="_blank"
|
||||||
|
>
|
||||||
|
create your own theme with plain CSS
|
||||||
|
</a>
|
||||||
|
.
|
||||||
|
</Card>
|
||||||
|
),
|
||||||
|
({ index }) => (
|
||||||
|
<Card
|
||||||
|
index={index}
|
||||||
|
name="Export to HTML, PDF, and PowerPoint"
|
||||||
|
icon="https://icongr.am/octicons/file.svg?color=4a5568"
|
||||||
|
>
|
||||||
|
Have you finished writing? Let's share the deck with a favorite way!
|
||||||
|
We can convert Markdown into presentation-ready HTML, what is more, PDF
|
||||||
|
and PowerPoint document directly! (Powered by{' '}
|
||||||
|
<a
|
||||||
|
href="https://www.google.com/chrome/"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
target="_blank"
|
||||||
|
>
|
||||||
|
Google Chrome
|
||||||
|
</a>{' '}
|
||||||
|
/{' '}
|
||||||
|
<a
|
||||||
|
href="https://www.chromium.org/Home"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
target="_blank"
|
||||||
|
>
|
||||||
|
Chromium
|
||||||
|
</a>
|
||||||
|
)
|
||||||
|
</Card>
|
||||||
|
),
|
||||||
|
({ index }) => (
|
||||||
|
<Card
|
||||||
|
index={index}
|
||||||
|
name="Marp family: The official toolset"
|
||||||
|
icon="https://icongr.am/octicons/package.svg?color=4a5568"
|
||||||
|
>
|
||||||
|
Marp family has the rich toolset to assist your work.{' '}
|
||||||
|
<a
|
||||||
|
href="https://marketplace.visualstudio.com/items?itemName=marp-team.marp-vscode"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
target="_blank"
|
||||||
|
>
|
||||||
|
<b>Marp for VS Code</b>
|
||||||
|
</a>{' '}
|
||||||
|
extension can preview editting Markdown and custom theme immediately.{' '}
|
||||||
|
<a
|
||||||
|
href="https://github.com/marp-team/marp-cli/"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
target="_blank"
|
||||||
|
>
|
||||||
|
<b>Marp CLI</b>
|
||||||
|
</a>{' '}
|
||||||
|
allows to convert Markdown through CLI interface.{' '}
|
||||||
|
<a
|
||||||
|
href="https://github.com/marp-team/marp/"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
target="_blank"
|
||||||
|
>
|
||||||
|
...and more!
|
||||||
|
</a>
|
||||||
|
</Card>
|
||||||
|
),
|
||||||
|
({ index }) => (
|
||||||
|
<Card
|
||||||
|
index={index}
|
||||||
|
name="Pluggable architecture"
|
||||||
|
icon="https://icongr.am/octicons/plug.svg?color=4a5568"
|
||||||
|
>
|
||||||
|
As a matter of fact,{' '}
|
||||||
|
<em>Marp is essentially just a converter for Markdown.</em> Marp ecosystem
|
||||||
|
is built on{' '}
|
||||||
|
<a
|
||||||
|
href="https://marpit.marp.app"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
target="_blank"
|
||||||
|
>
|
||||||
|
<b>Marpit framework</b>
|
||||||
|
</a>
|
||||||
|
, the skinny framework for creating HTML + CSS slide deck. It has a
|
||||||
|
pluggable architecture and developer can{' '}
|
||||||
|
<a
|
||||||
|
href="https://marpit.marp.app/usage?id=extend-marpit-by-plugins"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
target="_blank"
|
||||||
|
>
|
||||||
|
extend features via plugin
|
||||||
|
</a>
|
||||||
|
.
|
||||||
|
</Card>
|
||||||
|
),
|
||||||
|
({ index }) => (
|
||||||
|
<Card
|
||||||
|
index={index}
|
||||||
|
name="Fully open-source"
|
||||||
|
icon="https://icongr.am/octicons/heart-fill.svg?color=4a5568"
|
||||||
|
>
|
||||||
|
We are loving open source! All tools and related libraries by{' '}
|
||||||
|
<a
|
||||||
|
href="https://github.com/marp-team"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
target="_blank"
|
||||||
|
>
|
||||||
|
Marp team
|
||||||
|
</a>{' '}
|
||||||
|
are licensed by MIT License.
|
||||||
|
</Card>
|
||||||
|
),
|
||||||
|
]
|
||||||
|
|
||||||
|
export const Features = () => (
|
||||||
|
<div className="features">
|
||||||
|
<div className="container features-grid">
|
||||||
|
{cards.map((Card, i) => (
|
||||||
|
<Card index={i} key={i} />
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
<style jsx>{`
|
||||||
|
.features {
|
||||||
|
@apply relative py-5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.features::before {
|
||||||
|
@apply absolute block inset-0;
|
||||||
|
|
||||||
|
background-image: url('/assets/noise.png'),
|
||||||
|
linear-gradient(
|
||||||
|
-8deg,
|
||||||
|
rgba(120, 197, 233, 0),
|
||||||
|
rgba(120, 197, 233, 0) 50%,
|
||||||
|
rgba(120, 197, 233, 0.5)
|
||||||
|
);
|
||||||
|
clip-path: polygon(0 15vw, 100% 0, 100% 100%, 0 100%);
|
||||||
|
content: '';
|
||||||
|
}
|
||||||
|
|
||||||
|
.features-grid {
|
||||||
|
@apply grid mx-auto px-4;
|
||||||
|
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
grid-template-rows: repeat(${cards.length + 1}, auto);
|
||||||
|
}
|
||||||
|
|
||||||
|
@screen md {
|
||||||
|
.features-grid {
|
||||||
|
grid-template-columns: 1fr 1fr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`}</style>
|
||||||
|
</div>
|
||||||
|
)
|
327
website/components/top/GetStarted.tsx
Normal file
@ -0,0 +1,327 @@
|
|||||||
|
import classNames from 'classnames'
|
||||||
|
import { Button } from 'components/Button'
|
||||||
|
|
||||||
|
type CardProps = {
|
||||||
|
badge?: string
|
||||||
|
className?: string
|
||||||
|
description: string
|
||||||
|
href: string
|
||||||
|
name: string
|
||||||
|
screenShot?: string
|
||||||
|
summary: string
|
||||||
|
}
|
||||||
|
|
||||||
|
const Card: React.FC<CardProps> = ({
|
||||||
|
badge,
|
||||||
|
children,
|
||||||
|
className,
|
||||||
|
description,
|
||||||
|
href,
|
||||||
|
name,
|
||||||
|
screenShot: screenshot,
|
||||||
|
summary,
|
||||||
|
}) => (
|
||||||
|
<section className={classNames('card', className, { screenshot })}>
|
||||||
|
<a
|
||||||
|
href={href}
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
className="custom-anchor card-link"
|
||||||
|
>
|
||||||
|
<h4 className="inline-block font-bold text-gradient pr-3 pb-1 text-xl sm:text-2xl md:text-3xl">
|
||||||
|
{name}
|
||||||
|
</h4>
|
||||||
|
{badge && (
|
||||||
|
<img
|
||||||
|
src={badge}
|
||||||
|
alt=""
|
||||||
|
className="inline rounded-sm align-text-top sm:align-baseline"
|
||||||
|
loading="lazy"
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
<p className="text-gray-600 text-sm pt-1 leading-tight">{summary}</p>
|
||||||
|
</a>
|
||||||
|
{screenshot && (
|
||||||
|
<figure>
|
||||||
|
<img src={screenshot} alt={name} loading="lazy" />
|
||||||
|
</figure>
|
||||||
|
)}
|
||||||
|
<p className="mx-5 lg:my-3">{description}</p>
|
||||||
|
<p className="text-sm mx-5 my-4">{children}</p>
|
||||||
|
<style jsx>{`
|
||||||
|
.card {
|
||||||
|
@apply bg-white text-foreground relative grid my-8 p-2 rounded-lg shadow-xl overflow-hidden;
|
||||||
|
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
}
|
||||||
|
.card::before {
|
||||||
|
@apply absolute right-0 w-40 h-40 opacity-25 transform bg-center bg-no-repeat bg-contain;
|
||||||
|
|
||||||
|
content: '';
|
||||||
|
top: -2rem;
|
||||||
|
transform: rotate(-15deg);
|
||||||
|
}
|
||||||
|
.card.vscode::before {
|
||||||
|
background-image: url('https://icongr.am/simple/visualstudiocode.svg?color=67b8e3');
|
||||||
|
}
|
||||||
|
.card.cli::before {
|
||||||
|
background-image: url('https://icongr.am/octicons/terminal.svg?color=67b8e3');
|
||||||
|
}
|
||||||
|
.card.core::before {
|
||||||
|
background-image: url('/assets/marp-logo.svg');
|
||||||
|
}
|
||||||
|
.card.marpit::before {
|
||||||
|
background-image: url('/assets/marpit.svg');
|
||||||
|
}
|
||||||
|
.card > * {
|
||||||
|
@apply relative col-start-1 col-end-1;
|
||||||
|
}
|
||||||
|
.card > figure {
|
||||||
|
@apply flex justify-center items-center mx-auto p-4;
|
||||||
|
}
|
||||||
|
.card > figure > img {
|
||||||
|
@apply max-w-full;
|
||||||
|
|
||||||
|
width: 28rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card-link {
|
||||||
|
@apply relative block p-5 transition-all duration-150 rounded z-10;
|
||||||
|
}
|
||||||
|
.card-link:hover,
|
||||||
|
.card-link:focus {
|
||||||
|
@apply shadow;
|
||||||
|
|
||||||
|
background-color: rgba(255, 255, 255, 0.5);
|
||||||
|
}
|
||||||
|
.card-link:hover:active,
|
||||||
|
.card-link:focus {
|
||||||
|
@apply shadow-outline outline-none;
|
||||||
|
|
||||||
|
transition-duration: 0ms;
|
||||||
|
}
|
||||||
|
|
||||||
|
@screen lg {
|
||||||
|
.card.screenshot {
|
||||||
|
grid-template-columns: 3fr 2fr;
|
||||||
|
}
|
||||||
|
.card > figure {
|
||||||
|
@apply col-start-2 col-end-2 w-full h-full object-contain px-6 py-0;
|
||||||
|
|
||||||
|
grid-row: 1 / span 9999;
|
||||||
|
}
|
||||||
|
.card::before {
|
||||||
|
@apply w-64 h-64;
|
||||||
|
|
||||||
|
top: -4rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@screen xl {
|
||||||
|
.card {
|
||||||
|
@apply w-5/6 mx-auto;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`}</style>
|
||||||
|
</section>
|
||||||
|
)
|
||||||
|
|
||||||
|
export const GetStarted = () => (
|
||||||
|
<>
|
||||||
|
<a id="get-started" className="named-anchor">
|
||||||
|
Get started
|
||||||
|
</a>
|
||||||
|
<div className="get-started clearfix">
|
||||||
|
<section className="container mx-auto py-10 px-8 lg:px-16">
|
||||||
|
<h3 className="font-bold text-center text-2xl sm:text-3xl">
|
||||||
|
<mark>Tools and integrations</mark>
|
||||||
|
</h3>
|
||||||
|
<Card
|
||||||
|
description="Enhance VS Code's Markdown preview pane to support writing your beautiful presentation. You can see the slide deck output as soon as editting Markdown."
|
||||||
|
name="Marp for VS Code"
|
||||||
|
summary="Create slide deck written in Marp Markdown, in VS Code"
|
||||||
|
badge="https://img.shields.io/visual-studio-marketplace/v/marp-team.marp-vscode.svg?style=flat-square&label=&colorB=0288d1"
|
||||||
|
href="https://marketplace.visualstudio.com/items?itemName=marp-team.marp-vscode"
|
||||||
|
screenShot="/assets/marp-for-vs-code.png"
|
||||||
|
className="vscode"
|
||||||
|
>
|
||||||
|
<Button
|
||||||
|
color="primary"
|
||||||
|
className="mr-2 mb-2"
|
||||||
|
href="https://marketplace.visualstudio.com/items?itemName=marp-team.marp-vscode"
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
>
|
||||||
|
VS Marketplace
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
outline
|
||||||
|
className="mr-2 mb-2"
|
||||||
|
href="https://github.com/marp-team/marp-vscode"
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
>
|
||||||
|
GitHub
|
||||||
|
</Button>
|
||||||
|
</Card>
|
||||||
|
<Card
|
||||||
|
description="CLI is the swiss army knife for Marp ecosystem. Convert your Markdown into various formats, watch changes, launch server for on-demand conversion, and customize engine."
|
||||||
|
name="Marp CLI"
|
||||||
|
summary="A CLI interface for Marp and Marpit based converters"
|
||||||
|
badge="https://img.shields.io/npm/v/@marp-team/marp-cli.svg?style=flat-square&label=&colorB=0288d1"
|
||||||
|
href="https://github.com/marp-team/marp-cli"
|
||||||
|
screenShot="/assets/marp-cli.png"
|
||||||
|
className="cli"
|
||||||
|
>
|
||||||
|
<Button
|
||||||
|
color="primary"
|
||||||
|
className="mr-2 mb-2"
|
||||||
|
href="https://github.com/marp-team/marp-cli/releases"
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
>
|
||||||
|
Releases
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
outline
|
||||||
|
color="primary"
|
||||||
|
className="mr-2 mb-2"
|
||||||
|
href="https://www.npmjs.com/package/@marp-team/marp-cli"
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
>
|
||||||
|
npm
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
outline
|
||||||
|
className="mr-2 mb-2"
|
||||||
|
href="https://github.com/marp-team/marp-cli"
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
>
|
||||||
|
GitHub
|
||||||
|
</Button>
|
||||||
|
</Card>
|
||||||
|
<h3 className="font-bold text-center text-2xl sm:text-3xl">
|
||||||
|
<mark>For developers</mark>
|
||||||
|
</h3>
|
||||||
|
<Card
|
||||||
|
description="All official Marp tools provided by us are using this core as the engine. It is based on Marpit framework, and includes some extended features to help creating beautiful slide deck."
|
||||||
|
name="Marp Core"
|
||||||
|
summary="The core of Marp converter"
|
||||||
|
badge="https://img.shields.io/npm/v/@marp-team/marp-core.svg?style=flat-square&label=&colorB=0288d1"
|
||||||
|
href="https://github.com/marp-team/marp-core"
|
||||||
|
className="core"
|
||||||
|
>
|
||||||
|
<Button
|
||||||
|
outline
|
||||||
|
color="primary"
|
||||||
|
className="mr-2 mb-2"
|
||||||
|
href="https://www.npmjs.com/package/@marp-team/marp-core"
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
>
|
||||||
|
npm
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
outline
|
||||||
|
className="mr-2 mb-2"
|
||||||
|
href="https://github.com/marp-team/marp-core"
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
>
|
||||||
|
GitHub
|
||||||
|
</Button>
|
||||||
|
</Card>
|
||||||
|
<Card
|
||||||
|
description="Marpit, independented from Marp, is the skinny framework to transform Markdown + CSS theme to the deck composed of HTML + CSS. It has designed to output only minimum assets."
|
||||||
|
name="Marpit framework"
|
||||||
|
summary="The skinny framework for creating slide deck from Markdown"
|
||||||
|
badge="https://img.shields.io/npm/v/@marp-team/marpit.svg?style=flat-square&label=&colorB=0288d1"
|
||||||
|
href="https://marpit.marp.app/"
|
||||||
|
className="marpit"
|
||||||
|
>
|
||||||
|
<Button
|
||||||
|
color="primary"
|
||||||
|
className="mr-2 mb-2"
|
||||||
|
href="https://marpit.marp.app/"
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
>
|
||||||
|
Documentation
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
outline
|
||||||
|
color="primary"
|
||||||
|
className="mr-2 mb-2"
|
||||||
|
href="https://www.npmjs.com/package/@marp-team/marpit"
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
>
|
||||||
|
npm
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
outline
|
||||||
|
className="mr-2 mb-2"
|
||||||
|
href="https://github.com/marp-team/marpit"
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
>
|
||||||
|
GitHub
|
||||||
|
</Button>
|
||||||
|
</Card>
|
||||||
|
<p className="text-center mt-4">
|
||||||
|
...and find out all tools, integrations, examples at our GitHub
|
||||||
|
entrance repository!
|
||||||
|
</p>
|
||||||
|
<p className="text-center text-sm text-foreground mt-4">
|
||||||
|
<Button
|
||||||
|
href="https://github.com/marp-team/marp/"
|
||||||
|
rel="noopener"
|
||||||
|
target="_blank"
|
||||||
|
>
|
||||||
|
Go to the entrance repository of Marp...
|
||||||
|
</Button>
|
||||||
|
</p>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
<style jsx>{`
|
||||||
|
.get-started {
|
||||||
|
@apply relative bg-marp-brand text-white;
|
||||||
|
|
||||||
|
background-image: url('/assets/noise.png'),
|
||||||
|
linear-gradient(
|
||||||
|
-2deg,
|
||||||
|
theme('colors.marp.darken'),
|
||||||
|
theme('colors.marp.brand') 500px
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
.get-started::before,
|
||||||
|
.get-started::after {
|
||||||
|
@apply block absolute inset-x-0;
|
||||||
|
|
||||||
|
background-image: url('/assets/noise.png'),
|
||||||
|
linear-gradient(to bottom, rgba(255, 255, 255, 0.4), transparent 95%);
|
||||||
|
bottom: calc(100% - 5px);
|
||||||
|
content: '';
|
||||||
|
transform: translateZ(0);
|
||||||
|
z-index: -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.get-started::before {
|
||||||
|
@apply bg-marp-light;
|
||||||
|
|
||||||
|
clip-path: polygon(0 0, 100% 90%, 100% 100%, 0 100%);
|
||||||
|
height: calc(120px + 5vw);
|
||||||
|
}
|
||||||
|
|
||||||
|
.get-started::after {
|
||||||
|
@apply bg-marp-brand;
|
||||||
|
|
||||||
|
clip-path: polygon(0 0, 100% 95%, 100% 100%, 0 100%);
|
||||||
|
height: calc(60px + 5vw);
|
||||||
|
}
|
||||||
|
`}</style>
|
||||||
|
</>
|
||||||
|
)
|
53
website/components/top/Hero.tsx
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
import Head from 'next/head'
|
||||||
|
import { Button } from 'components/Button'
|
||||||
|
|
||||||
|
const marp = '/assets/marp.svg' as const
|
||||||
|
const heroBg = '/assets/hero-background.jpg' as const
|
||||||
|
|
||||||
|
export const Hero = () => (
|
||||||
|
<>
|
||||||
|
<Head>
|
||||||
|
<link rel="preload" href={heroBg} as="image" />
|
||||||
|
<link rel="preload" href={marp} as="image" />
|
||||||
|
</Head>
|
||||||
|
<section className="py-16 px-4 border-b md:py-24 md:tracking-wider">
|
||||||
|
<h1 className="text-center font-rounded font-bold sm:text-xl md:text-2xl">
|
||||||
|
<img
|
||||||
|
src={marp}
|
||||||
|
alt="Marp: Markdown Presentation Ecosystem"
|
||||||
|
className="mx-auto w-4/5 h-auto max-w-xl mb-5 p-3"
|
||||||
|
width={1045}
|
||||||
|
height={320}
|
||||||
|
/>
|
||||||
|
Markdown Presentation Ecosystem
|
||||||
|
</h1>
|
||||||
|
<p className="text-center mt-10">
|
||||||
|
<Button
|
||||||
|
href="#get-started"
|
||||||
|
color="primary"
|
||||||
|
className="text-xl md:text-2xl"
|
||||||
|
>
|
||||||
|
Get started!
|
||||||
|
</Button>
|
||||||
|
</p>
|
||||||
|
<p className="text-center mt-5">
|
||||||
|
<Button
|
||||||
|
href="https://github.com/marp-team/marp"
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
className="text-sm md:text-base"
|
||||||
|
color="primary"
|
||||||
|
outline
|
||||||
|
>
|
||||||
|
Find out Marp tools at GitHub...
|
||||||
|
</Button>
|
||||||
|
</p>
|
||||||
|
<style jsx>{`
|
||||||
|
section {
|
||||||
|
background: #fcfcfc url('${heroBg}') no-repeat right center;
|
||||||
|
background-size: cover;
|
||||||
|
}
|
||||||
|
`}</style>
|
||||||
|
</section>
|
||||||
|
</>
|
||||||
|
)
|
82
website/css/index.css
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
@tailwind base;
|
||||||
|
@tailwind components;
|
||||||
|
@tailwind utilities;
|
||||||
|
|
||||||
|
html:not(.translating) {
|
||||||
|
scroll-behavior: smooth;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
@apply relative text-foreground bg-background min-h-full;
|
||||||
|
}
|
||||||
|
|
||||||
|
body::before {
|
||||||
|
@apply fixed block inset-0 bg-background;
|
||||||
|
|
||||||
|
background-image: url('/assets/noise.png'),
|
||||||
|
linear-gradient(
|
||||||
|
to bottom,
|
||||||
|
theme('colors.gray.100'),
|
||||||
|
theme('colors.background') 50%
|
||||||
|
);
|
||||||
|
content: '';
|
||||||
|
z-index: -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
a:not(.custom-anchor) {
|
||||||
|
@apply text-marp-brand;
|
||||||
|
}
|
||||||
|
|
||||||
|
a:not(.custom-anchor):hover {
|
||||||
|
@apply underline text-marp-dark transition-colors duration-300;
|
||||||
|
}
|
||||||
|
|
||||||
|
a:not(.custom-anchor):hover:active {
|
||||||
|
@apply text-marp-darkest;
|
||||||
|
|
||||||
|
transition-duration: 0ms;
|
||||||
|
}
|
||||||
|
|
||||||
|
a.named-anchor {
|
||||||
|
@apply invisible block h-0 relative;
|
||||||
|
|
||||||
|
top: -4rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
@screen md {
|
||||||
|
a.named-anchor {
|
||||||
|
top: -5rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
mark {
|
||||||
|
background: none;
|
||||||
|
color: inherit;
|
||||||
|
box-shadow: inset 0 -0.2em theme('colors.marp.light');
|
||||||
|
}
|
||||||
|
|
||||||
|
/* NProgress */
|
||||||
|
#nprogress .bar {
|
||||||
|
@apply bg-marp-brand;
|
||||||
|
}
|
||||||
|
#nprogress .peg {
|
||||||
|
@apply shadow-none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Helper classes */
|
||||||
|
.text-gradient {
|
||||||
|
@apply text-marp-brand leading-tight;
|
||||||
|
}
|
||||||
|
|
||||||
|
@supports (background-clip: text) {
|
||||||
|
.text-gradient {
|
||||||
|
@apply text-transparent bg-marp-brand bg-clip-text;
|
||||||
|
|
||||||
|
background-image: linear-gradient(
|
||||||
|
-1deg,
|
||||||
|
theme('colors.marp.light'),
|
||||||
|
theme('colors.marp.brand'),
|
||||||
|
theme('colors.marp.dark')
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
2
website/next-env.d.ts
vendored
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
/// <reference types="next" />
|
||||||
|
/// <reference types="next/types/global" />
|
16
website/next.config.js
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
const withBundleAnalyzer = require('@next/bundle-analyzer')({
|
||||||
|
enabled: !!process.env.ANALYZE,
|
||||||
|
})
|
||||||
|
|
||||||
|
const env = { BUILD_YEAR: new Date().getFullYear().toString() }
|
||||||
|
|
||||||
|
// for Netlify's deploy preview
|
||||||
|
if (process.env.DEPLOY_URL) env.NEXT_PUBLIC_HOST = process.env.DEPLOY_URL
|
||||||
|
|
||||||
|
module.exports = withBundleAnalyzer({
|
||||||
|
env,
|
||||||
|
webpack: (config) => {
|
||||||
|
config.module.rules.push({ test: /\.md$/, use: 'raw-loader' })
|
||||||
|
return config
|
||||||
|
},
|
||||||
|
})
|
50
website/package.json
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
{
|
||||||
|
"name": "@marp-team/marp-website",
|
||||||
|
"version": "0.0.0",
|
||||||
|
"private": true,
|
||||||
|
"scripts": {
|
||||||
|
"check:ts": "tsc --noEmit",
|
||||||
|
"export": "next build && next export",
|
||||||
|
"dev": "next dev",
|
||||||
|
"build": "next build",
|
||||||
|
"start": "next start"
|
||||||
|
},
|
||||||
|
"browser": {
|
||||||
|
"@marp-team/marp-core": false,
|
||||||
|
"gray-matter": false,
|
||||||
|
"remark-parse": false
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@marp-team/marp-core": "^1.3.0",
|
||||||
|
"@next/bundle-analyzer": "^9.5.2",
|
||||||
|
"body-scroll-lock": "^3.0.3",
|
||||||
|
"classnames": "^2.2.6",
|
||||||
|
"focus-visible": "^5.1.0",
|
||||||
|
"github-slugger": "^1.3.0",
|
||||||
|
"gray-matter": "^4.0.2",
|
||||||
|
"next": "^9.5.2",
|
||||||
|
"nprogress": "^0.2.0",
|
||||||
|
"postcss-flexbugs-fixes": "^4.2.1",
|
||||||
|
"postcss-preset-env": "^6.7.0",
|
||||||
|
"prism-react-renderer": "^1.1.1",
|
||||||
|
"raw-loader": "^4.0.1",
|
||||||
|
"react": "^16.13.1",
|
||||||
|
"react-dom": "^16.13.1",
|
||||||
|
"react-innertext": "^1.1.5",
|
||||||
|
"remark-parse": "^8.0.3",
|
||||||
|
"remark-react": "^7.0.1",
|
||||||
|
"styled-jsx-plugin-postcss": "^2.0.1",
|
||||||
|
"tailwindcss": "^1.7.3",
|
||||||
|
"unified": "^9.2.0",
|
||||||
|
"use-media": "^1.4.0",
|
||||||
|
"wicg-inert": "^3.0.3"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@types/classnames": "^2.2.10",
|
||||||
|
"@types/react": "^16.9.46",
|
||||||
|
"@types/webpack-env": "^1.15.2",
|
||||||
|
"eslint-plugin-jsx-a11y": "^6.3.1",
|
||||||
|
"eslint-plugin-react": "^7.20.6",
|
||||||
|
"eslint-plugin-react-hooks": "^4.1.0"
|
||||||
|
}
|
||||||
|
}
|
43
website/pages/404.tsx
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
import { Button } from 'components/Button'
|
||||||
|
import { Layout } from 'components/Layout'
|
||||||
|
|
||||||
|
const error404 = () => (
|
||||||
|
<Layout title={['404 Not Found']} noIndex>
|
||||||
|
<section className="text-center">
|
||||||
|
<div className="w-screen m-8 max-w-2xl sm:m-16">
|
||||||
|
<h1 className="font-rounded text-4xl text-gray-700 font-bold tracking-tighter">
|
||||||
|
404 Not Found
|
||||||
|
</h1>
|
||||||
|
<hr className="my-6" />
|
||||||
|
<p className="text-lg">Oops! The requested page could not be found.</p>
|
||||||
|
<p className="mt-10">
|
||||||
|
<Button
|
||||||
|
className="w-full max-w-xs text-xs"
|
||||||
|
onClick={() => window.history.back()}
|
||||||
|
outline
|
||||||
|
style={{ color: '#4a5568' }}
|
||||||
|
>
|
||||||
|
<span className="flex justify-center items-center text-lg">
|
||||||
|
<img
|
||||||
|
className="w-8 h-8 mr-2"
|
||||||
|
src="https://icongr.am/octicons/arrow-left.svg?color=4a5568"
|
||||||
|
alt="←"
|
||||||
|
/>
|
||||||
|
Back to previous
|
||||||
|
</span>
|
||||||
|
</Button>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<style jsx>{`
|
||||||
|
section {
|
||||||
|
@apply flex w-full items-center justify-center;
|
||||||
|
|
||||||
|
background-image: url("data:image/svg+xml,%3csvg width='40' height='40' xmlns='http://www.w3.org/2000/svg'%3e%3cpath d='M0 40L40 0H20L0 20m40 20V20L20 40' fill='%23f0f0f0' fill-opacity='.2' fill-rule='evenodd'/%3e%3c/svg%3e");
|
||||||
|
min-height: inherit;
|
||||||
|
}
|
||||||
|
`}</style>
|
||||||
|
</section>
|
||||||
|
</Layout>
|
||||||
|
)
|
||||||
|
|
||||||
|
export default error404
|
29
website/pages/_app.tsx
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
import { Router } from 'next/router'
|
||||||
|
import NProgress from 'nprogress'
|
||||||
|
import 'focus-visible'
|
||||||
|
import 'wicg-inert'
|
||||||
|
import 'nprogress/nprogress.css'
|
||||||
|
import 'css/index.css'
|
||||||
|
|
||||||
|
const translating = () => {
|
||||||
|
NProgress.start()
|
||||||
|
document.documentElement.classList.add('translating')
|
||||||
|
}
|
||||||
|
|
||||||
|
const translated = () => {
|
||||||
|
NProgress.done()
|
||||||
|
setTimeout(
|
||||||
|
() => document.documentElement.classList.remove('translating'),
|
||||||
|
250
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
Router.events.on('routeChangeStart', translating)
|
||||||
|
Router.events.on('routeChangeComplete', translated)
|
||||||
|
Router.events.on('routeChangeError', translated)
|
||||||
|
|
||||||
|
NProgress.configure({ showSpinner: false, trickleSpeed: 350 })
|
||||||
|
|
||||||
|
const App = ({ Component, pageProps }) => <Component {...pageProps} />
|
||||||
|
|
||||||
|
export default App
|
26
website/pages/_document.tsx
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
import Document, { Html, Head, Main, NextScript } from 'next/document'
|
||||||
|
|
||||||
|
class MyDocument extends Document {
|
||||||
|
render = () => (
|
||||||
|
<Html lang="en">
|
||||||
|
<Head>
|
||||||
|
<link rel="icon" href="/favicon.png" type="image/png" />
|
||||||
|
<link
|
||||||
|
rel="apple-touch-icon"
|
||||||
|
sizes="180x180"
|
||||||
|
href="/apple-touch-icon-180x180.png"
|
||||||
|
/>
|
||||||
|
<link
|
||||||
|
href="https://fonts.googleapis.com/css2?family=Inter:wght@400;600;700&family=Quicksand:wght@500;700&display=swap"
|
||||||
|
rel="stylesheet"
|
||||||
|
/>
|
||||||
|
</Head>
|
||||||
|
<body>
|
||||||
|
<Main />
|
||||||
|
<NextScript />
|
||||||
|
</body>
|
||||||
|
</Html>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default MyDocument
|
140
website/pages/blog.tsx
Normal file
@ -0,0 +1,140 @@
|
|||||||
|
import { basename } from 'path'
|
||||||
|
import { InferGetStaticPropsType } from 'next'
|
||||||
|
import Link from 'next/link'
|
||||||
|
import { Layout } from 'components/Layout'
|
||||||
|
import { Title } from 'components/Title'
|
||||||
|
import { Typography } from 'components/Typography'
|
||||||
|
import { formatDate, formatDateShort } from 'utils/date'
|
||||||
|
import { parse, parseMatter, renderToReact } from 'utils/markdown'
|
||||||
|
|
||||||
|
export const getStaticProps = async () => {
|
||||||
|
const ctx = require.context('blog', false, /\.md$/)
|
||||||
|
const mdMetas = await Promise.all(
|
||||||
|
ctx.keys().map((id) => {
|
||||||
|
const { default: md } = ctx(id)
|
||||||
|
const { data, excerpt } = parseMatter(md)
|
||||||
|
|
||||||
|
return (async () => ({
|
||||||
|
data,
|
||||||
|
excerpt: excerpt ? await parse(excerpt) : undefined,
|
||||||
|
slug: basename(id, '.md'),
|
||||||
|
}))()
|
||||||
|
})
|
||||||
|
)
|
||||||
|
|
||||||
|
const articles = mdMetas.filter(({ data }) => data.date)
|
||||||
|
articles.sort((a, b) => b.data.date.getTime() - a.data.date.getTime())
|
||||||
|
|
||||||
|
return {
|
||||||
|
props: {
|
||||||
|
articles: JSON.parse(JSON.stringify(articles)) as typeof articles,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const Blog = ({ articles }: InferGetStaticPropsType<typeof getStaticProps>) => (
|
||||||
|
<Layout activeItem="blog" title={['Blog']}>
|
||||||
|
<Title>
|
||||||
|
<Link href="/blog">
|
||||||
|
<a>Blog</a>
|
||||||
|
</Link>
|
||||||
|
</Title>
|
||||||
|
<div className="container mx-auto max-w-screen-lg px-3 py-1">
|
||||||
|
{articles.map((article) => {
|
||||||
|
let summary: JSX.Element | string | undefined
|
||||||
|
|
||||||
|
if (article.excerpt) {
|
||||||
|
summary = (
|
||||||
|
<Typography>{renderToReact(article.excerpt.mdast)}</Typography>
|
||||||
|
)
|
||||||
|
} else if (article.data.description) {
|
||||||
|
summary = article.data.description
|
||||||
|
}
|
||||||
|
|
||||||
|
const date = new Date(article.data.date)
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div key={article.slug} className="article-container">
|
||||||
|
<Link href={`/blog/${article.slug}`}>
|
||||||
|
<a className="article-container-link">
|
||||||
|
<h1 className="sr-only">{article.data.title}</h1>
|
||||||
|
</a>
|
||||||
|
</Link>
|
||||||
|
<div className="relative pointer-events-none">
|
||||||
|
<h1 className="text-3xl text-gradient font-bold" aria-hidden>
|
||||||
|
{article.data.title}
|
||||||
|
</h1>
|
||||||
|
<p className="mt-2 text-gray-600 pb-4 border-b-2 mb-4 text-sm">
|
||||||
|
<time dateTime={formatDateShort(date)}>{formatDate(date)}</time>
|
||||||
|
{article.data.author && ` by ${article.data.author}`}
|
||||||
|
</p>
|
||||||
|
{summary && (
|
||||||
|
<>
|
||||||
|
{/* @ts-ignore for inert attribute */}
|
||||||
|
<div className="flex flex-col lg:flex-row" inert="">
|
||||||
|
{article.data.image && (
|
||||||
|
<figure className="mx-auto mb-6 lg:order-1 lg:mb-0 lg:ml-6 lg:w-full lg:max-w-sm">
|
||||||
|
<img
|
||||||
|
src={article.data.image}
|
||||||
|
alt={article.data.title}
|
||||||
|
className="bg-white border border-gray-100 shadow-md w-full max-w-sm"
|
||||||
|
/>
|
||||||
|
</figure>
|
||||||
|
)}
|
||||||
|
<article className="flex-grow">{summary}</article>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
<p className="read-more">
|
||||||
|
<img
|
||||||
|
className="inline w-8 h-8"
|
||||||
|
src="https://icongr.am/octicons/arrow-right.svg?color=4a5568"
|
||||||
|
alt="→"
|
||||||
|
/>
|
||||||
|
Read more...
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
})}
|
||||||
|
<style jsx>{`
|
||||||
|
.article-container {
|
||||||
|
@apply relative p-6 my-6;
|
||||||
|
}
|
||||||
|
.article-container-link {
|
||||||
|
@apply absolute inset-0 rounded-lg transition-all duration-300;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media not all and (hover: none) {
|
||||||
|
.article-container-link:hover {
|
||||||
|
@apply shadow-lg bg-white;
|
||||||
|
}
|
||||||
|
.article-container-link:hover:active {
|
||||||
|
@apply shadow-outline bg-white outline-none;
|
||||||
|
transition-duration: 0s;
|
||||||
|
}
|
||||||
|
.article-container-link:hover + * .read-more {
|
||||||
|
@apply text-marp-brand;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.article-container-link:focus {
|
||||||
|
@apply shadow-outline bg-white outline-none;
|
||||||
|
transition-duration: 0s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.read-more {
|
||||||
|
@apply mt-6 text-right uppercase font-bold flex justify-end items-center transition-colors duration-300;
|
||||||
|
}
|
||||||
|
|
||||||
|
@screen md {
|
||||||
|
.article-container {
|
||||||
|
@apply relative p-8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`}</style>
|
||||||
|
</div>
|
||||||
|
</Layout>
|
||||||
|
)
|
||||||
|
|
||||||
|
export default Blog
|
69
website/pages/blog/[slug].tsx
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
import { basename } from 'path'
|
||||||
|
import {
|
||||||
|
GetStaticPaths,
|
||||||
|
GetStaticPropsContext,
|
||||||
|
InferGetStaticPropsType,
|
||||||
|
} from 'next'
|
||||||
|
import Link from 'next/link'
|
||||||
|
import { Layout } from 'components/Layout'
|
||||||
|
import { Title } from 'components/Title'
|
||||||
|
import { Typography } from 'components/Typography'
|
||||||
|
import { BlogHeader } from 'components/blog/BlogHeader'
|
||||||
|
import { parse, renderToReact } from 'utils/markdown'
|
||||||
|
|
||||||
|
export const getStaticPaths: GetStaticPaths = async () => ({
|
||||||
|
paths: require
|
||||||
|
.context('blog', false, /\.md$/)
|
||||||
|
.keys()
|
||||||
|
.map((id) => `/blog/${basename(id, '.md')}`),
|
||||||
|
fallback: false,
|
||||||
|
})
|
||||||
|
|
||||||
|
export const getStaticProps = async ({ params }: GetStaticPropsContext) => {
|
||||||
|
const slug = params?.slug as string
|
||||||
|
const { default: md } = await import(`blog/${slug}.md`)
|
||||||
|
|
||||||
|
return { props: { markdown: await parse(md), slug } }
|
||||||
|
}
|
||||||
|
|
||||||
|
const Blog = ({
|
||||||
|
markdown,
|
||||||
|
slug,
|
||||||
|
}: InferGetStaticPropsType<typeof getStaticProps>) => (
|
||||||
|
<Layout
|
||||||
|
activeItem="blog"
|
||||||
|
description={markdown.data.description || ''}
|
||||||
|
image={markdown.data.image}
|
||||||
|
noIndex={!markdown.data.date}
|
||||||
|
title={[markdown.data.title || slug, 'Blog']}
|
||||||
|
>
|
||||||
|
<Title>
|
||||||
|
<Link href="/blog">
|
||||||
|
<a>Blog</a>
|
||||||
|
</Link>
|
||||||
|
</Title>
|
||||||
|
<div className="container mx-auto px-6 py-12">
|
||||||
|
<BlogHeader
|
||||||
|
title={markdown.data.title}
|
||||||
|
date={markdown.data.date ? new Date(markdown.data.date) : undefined}
|
||||||
|
author={markdown.data.author}
|
||||||
|
github={markdown.data.github}
|
||||||
|
slug={slug}
|
||||||
|
/>
|
||||||
|
<article className="mt-8 mx-auto max-w-screen-lg">
|
||||||
|
{markdown.data.image && (
|
||||||
|
<figure className="my-12">
|
||||||
|
<img
|
||||||
|
src={markdown.data.image}
|
||||||
|
alt={markdown.data.title}
|
||||||
|
className="block bg-white mx-auto max-w-screen-md shadow-xl w-full"
|
||||||
|
/>
|
||||||
|
</figure>
|
||||||
|
)}
|
||||||
|
<Typography>{renderToReact(markdown.mdast)}</Typography>
|
||||||
|
</article>
|
||||||
|
</div>
|
||||||
|
</Layout>
|
||||||
|
)
|
||||||
|
|
||||||
|
export default Blog
|
33
website/pages/docs._tsx
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
import { Layout } from 'components/docs/Layout'
|
||||||
|
|
||||||
|
const Docs = () => (
|
||||||
|
<Layout breadcrumbs={['Concept', "What's Marp?"]}>
|
||||||
|
<p>
|
||||||
|
Lorem ipsum, dolor sit amet consectetur adipisicing elit. Assumenda, earum
|
||||||
|
porro, ex magnam aut sequi corrupti, minus molestiae neque et maiores
|
||||||
|
veniam. Odio quos eveniet qui. Non quisquam itaque sunt?
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Lorem ipsum, dolor sit amet consectetur adipisicing elit. Assumenda, earum
|
||||||
|
porro, ex magnam aut sequi corrupti, minus molestiae neque et maiores
|
||||||
|
veniam. Odio quos eveniet qui. Non quisquam itaque sunt?
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Lorem ipsum, dolor sit amet consectetur adipisicing elit. Assumenda, earum
|
||||||
|
porro, ex magnam aut sequi corrupti, minus molestiae neque et maiores
|
||||||
|
veniam. Odio quos eveniet qui. Non quisquam itaque sunt?
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Lorem ipsum, dolor sit amet consectetur adipisicing elit. Assumenda, earum
|
||||||
|
porro, ex magnam aut sequi corrupti, minus molestiae neque et maiores
|
||||||
|
veniam. Odio quos eveniet qui. Non quisquam itaque sunt?
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Lorem ipsum, dolor sit amet consectetur adipisicing elit. Assumenda, earum
|
||||||
|
porro, ex magnam aut sequi corrupti, minus molestiae neque et maiores
|
||||||
|
veniam. Odio quos eveniet qui. Non quisquam itaque sunt?
|
||||||
|
</p>
|
||||||
|
</Layout>
|
||||||
|
)
|
||||||
|
|
||||||
|
export default Docs
|
59
website/pages/index.tsx
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
import { InferGetStaticPropsType } from 'next'
|
||||||
|
import { Layout } from 'components/Layout'
|
||||||
|
import { generateRenderedMarp } from 'components/Marp'
|
||||||
|
import { Description } from 'components/top/Description'
|
||||||
|
import { Features } from 'components/top/Features'
|
||||||
|
import { GetStarted } from 'components/top/GetStarted'
|
||||||
|
import { Hero } from 'components/top/Hero'
|
||||||
|
import { absoluteUrl } from 'utils/url'
|
||||||
|
|
||||||
|
const exampleMarkdown = `
|
||||||
|
---
|
||||||
|
theme: gaia
|
||||||
|
_class: lead
|
||||||
|
paginate: true
|
||||||
|
backgroundColor: #fff
|
||||||
|
backgroundImage: url('${absoluteUrl('/assets/hero-background.jpg')}')
|
||||||
|
---
|
||||||
|
|
||||||
|
![bg left:40% 80%](${absoluteUrl('/assets/marp.svg')})
|
||||||
|
|
||||||
|
# **Marp**
|
||||||
|
|
||||||
|
Markdown Presentation Ecosystem
|
||||||
|
|
||||||
|
https://marp.app/
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# How to write slides
|
||||||
|
|
||||||
|
Split pages by horizontal ruler (\`---\`). It's very simple! :satisfied:
|
||||||
|
|
||||||
|
\`\`\`markdown
|
||||||
|
# Slide 1
|
||||||
|
|
||||||
|
foobar
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
# Slide 2
|
||||||
|
|
||||||
|
foobar
|
||||||
|
\`\`\`
|
||||||
|
`.trim()
|
||||||
|
|
||||||
|
export const getStaticProps = async () => ({
|
||||||
|
props: { example: generateRenderedMarp(exampleMarkdown) },
|
||||||
|
})
|
||||||
|
|
||||||
|
const Index = (props: InferGetStaticPropsType<typeof getStaticProps>) => (
|
||||||
|
<Layout type="website">
|
||||||
|
<Hero />
|
||||||
|
<Description example={props.example} />
|
||||||
|
<Features />
|
||||||
|
<GetStarted />
|
||||||
|
</Layout>
|
||||||
|
)
|
||||||
|
|
||||||
|
export default Index
|
14
website/postcss.config.js
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
module.exports = {
|
||||||
|
plugins: {
|
||||||
|
'postcss-flexbugs-fixes': {},
|
||||||
|
tailwindcss: {},
|
||||||
|
'postcss-preset-env': {
|
||||||
|
autoprefixer: { flexbox: 'no-2009' },
|
||||||
|
stage: 3,
|
||||||
|
features: {
|
||||||
|
'custom-properties': false,
|
||||||
|
'focus-visible-pseudo-class': true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
BIN
website/public/apple-touch-icon-180x180.png
Normal file
After Width: | Height: | Size: 371 B |
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB |
BIN
website/public/assets/marp-cli.png
Normal file
After Width: | Height: | Size: 52 KiB |
BIN
website/public/assets/marp-for-vs-code.png
Normal file
After Width: | Height: | Size: 136 KiB |
Before Width: | Height: | Size: 210 B After Width: | Height: | Size: 210 B |
1
website/public/assets/marp.svg
Normal file
@ -0,0 +1 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 522.5 160"><defs><style>.d{fill:none;stroke:#000;stroke-linecap:square;stroke-miterlimit:10;stroke-width:5px}</style></defs><path fill="#67b8e3" d="M250 0l-90 90v70h90V0z"/><path fill="#0288d1" d="M160 0L0 160h90l70-70V0z"/><path fill="#02669d" d="M90 160h70V90l-70 70z"/><path class="d" d="M300 110V50l30 30 30-30v60"/><circle class="d" cx="400" cy="90" r="20"/><path class="d" d="M440 90a20.1 20.1 0 0120-20M420 70v40"/><circle class="d" cx="500" cy="90" r="20"/><path class="d" d="M480 70v60M440 70v40"/></svg>
|
After Width: | Height: | Size: 566 B |
Before Width: | Height: | Size: 198 B After Width: | Height: | Size: 198 B |
Before Width: | Height: | Size: 4.6 KiB After Width: | Height: | Size: 4.6 KiB |
Before Width: | Height: | Size: 24 KiB After Width: | Height: | Size: 24 KiB |
BIN
website/public/favicon.png
Normal file
After Width: | Height: | Size: 435 B |
BIN
website/public/og-images/the-story-of-marp-next.png
Normal file
After Width: | Height: | Size: 7.6 KiB |
37
website/tailwind.config.js
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
const {
|
||||||
|
colors: { black, current, gray, transparent, white },
|
||||||
|
fontFamily,
|
||||||
|
} = require('tailwindcss/defaultTheme')
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
future: { removeDeprecatedGapUtilities: true },
|
||||||
|
plugins: [],
|
||||||
|
purge: ['@(components|pages|utils)/**/*.[jt]s?(x)'],
|
||||||
|
theme: {
|
||||||
|
colors: {
|
||||||
|
black,
|
||||||
|
current,
|
||||||
|
gray,
|
||||||
|
transparent,
|
||||||
|
white,
|
||||||
|
background: '#f8f8f8',
|
||||||
|
foreground: gray[800],
|
||||||
|
marp: {
|
||||||
|
// Brand colors
|
||||||
|
brand: '#0288d1',
|
||||||
|
light: '#67b8e3',
|
||||||
|
dark: '#02669d',
|
||||||
|
|
||||||
|
// Color variations
|
||||||
|
darken: '#0277b7',
|
||||||
|
darkest: '#1b4d68',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
fontFamily: {
|
||||||
|
...fontFamily,
|
||||||
|
sans: ['Inter', ...fontFamily.sans],
|
||||||
|
rounded: ['Quicksand', 'Avenir', 'Century Gothic', ...fontFamily.sans],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
variants: { transitionDuration: ['responsive', 'hover'] },
|
||||||
|
}
|
16
website/tsconfig.json
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
{
|
||||||
|
"extends": "../tsconfig.json",
|
||||||
|
"compilerOptions": {
|
||||||
|
"allowJs": true,
|
||||||
|
"baseUrl": ".",
|
||||||
|
"isolatedModules": true,
|
||||||
|
"jsx": "preserve",
|
||||||
|
"lib": ["dom", "dom.iterable", "esnext"],
|
||||||
|
"module": "esnext",
|
||||||
|
"moduleResolution": "node",
|
||||||
|
"noEmit": true,
|
||||||
|
"target": "es5"
|
||||||
|
},
|
||||||
|
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"],
|
||||||
|
"exclude": ["node_modules"]
|
||||||
|
}
|
34
website/utils/date.ts
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
const monthNames = [
|
||||||
|
'January',
|
||||||
|
'February',
|
||||||
|
'March',
|
||||||
|
'April',
|
||||||
|
'May',
|
||||||
|
'June',
|
||||||
|
'July',
|
||||||
|
'August',
|
||||||
|
'September',
|
||||||
|
'October',
|
||||||
|
'November',
|
||||||
|
'December',
|
||||||
|
] as const
|
||||||
|
|
||||||
|
const nth = (day) => {
|
||||||
|
if (day > 3 && day < 21) return `${day}th`
|
||||||
|
|
||||||
|
const firstPlace = day % 10
|
||||||
|
if (firstPlace === 1) return `${day}st`
|
||||||
|
if (firstPlace === 2) return `${day}nd`
|
||||||
|
if (firstPlace === 3) return `${day}rd`
|
||||||
|
|
||||||
|
return `${day}th`
|
||||||
|
}
|
||||||
|
|
||||||
|
export const formatDate = (date: Date) =>
|
||||||
|
`${monthNames[date.getMonth()]} ${nth(date.getDate())}, ${date.getFullYear()}`
|
||||||
|
|
||||||
|
export const formatDateShort = (date: Date) =>
|
||||||
|
`${date.getFullYear()}-${`${date.getMonth() + 1}`.padStart(
|
||||||
|
2,
|
||||||
|
'0'
|
||||||
|
)}-${`${date.getDate()}`.padStart(2, '0')}`
|
138
website/utils/markdown.tsx
Normal file
@ -0,0 +1,138 @@
|
|||||||
|
/* eslint-disable jsx-a11y/alt-text, jsx-a11y/anchor-has-content */
|
||||||
|
import GitHubSlugger from 'github-slugger'
|
||||||
|
import matter from 'gray-matter'
|
||||||
|
import gitHubSanitize from 'hast-util-sanitize/lib/github.json'
|
||||||
|
import Link from 'next/link'
|
||||||
|
import innerText from 'react-innertext'
|
||||||
|
import remarkParse from 'remark-parse'
|
||||||
|
import remarkReact from 'remark-react'
|
||||||
|
import unified from 'unified'
|
||||||
|
import { CodeBlock } from 'components/CodeBlock'
|
||||||
|
|
||||||
|
const parser = unified().use(remarkParse, { commonmark: true })
|
||||||
|
const toJSON = (value: any) => JSON.parse(JSON.stringify(value))
|
||||||
|
|
||||||
|
export const parseMatter = (markdown: string) =>
|
||||||
|
matter(markdown, {
|
||||||
|
excerpt_separator: '<!-- more -->',
|
||||||
|
})
|
||||||
|
|
||||||
|
export const parse = async (markdown: string) => {
|
||||||
|
const md = parseMatter(markdown)
|
||||||
|
|
||||||
|
return {
|
||||||
|
markdown,
|
||||||
|
mdast: toJSON(await parser.run(parser.parse(md.content))),
|
||||||
|
data: toJSON(md.data),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const Anchor = ({ href, ...rest }) => {
|
||||||
|
if (href && (href.startsWith('http://') || href.startsWith('https://'))) {
|
||||||
|
return <a href={href} {...rest} target="_blank" rel="noreferrer noopener" />
|
||||||
|
}
|
||||||
|
return (
|
||||||
|
<Link href={href}>
|
||||||
|
<a {...rest} />
|
||||||
|
</Link>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const MarkWrapper: React.FC = ({ children }) => (
|
||||||
|
<span>
|
||||||
|
{children}
|
||||||
|
<style jsx>{`
|
||||||
|
& {
|
||||||
|
box-shadow: inset 0 -0.2em theme('colors.marp.light');
|
||||||
|
}
|
||||||
|
`}</style>
|
||||||
|
</span>
|
||||||
|
)
|
||||||
|
|
||||||
|
const PreCodeBlock: React.FC = (props) => {
|
||||||
|
if (props['data-code'] === undefined) return <pre {...props} />
|
||||||
|
|
||||||
|
return (
|
||||||
|
<CodeBlock
|
||||||
|
className="sm:mx-auto sm:w-11/12 lg:w-5/6"
|
||||||
|
language={props['data-language']}
|
||||||
|
copyButton
|
||||||
|
>
|
||||||
|
{props['data-code']}
|
||||||
|
</CodeBlock>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
const Img: React.FC = (props) =>
|
||||||
|
props['title'] ? (
|
||||||
|
<figure>
|
||||||
|
<img {...props} />
|
||||||
|
{props['title'].trim() && <figcaption>{props['title']}</figcaption>}
|
||||||
|
</figure>
|
||||||
|
) : (
|
||||||
|
<img {...props} />
|
||||||
|
)
|
||||||
|
|
||||||
|
export const renderToReact = (
|
||||||
|
mdast: any,
|
||||||
|
{ anchorLink = true }: { anchorLink?: boolean } = {}
|
||||||
|
) => {
|
||||||
|
const slugger = new GitHubSlugger()
|
||||||
|
const heading = (level: number, Wrapper?: React.FC) => {
|
||||||
|
const Heading: React.FC = ({ children }) => {
|
||||||
|
const anchor = slugger.slug(innerText(children))
|
||||||
|
const Tag = `h${level}` as any
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Tag>
|
||||||
|
<a id={anchor} className="named-anchor" aria-hidden />
|
||||||
|
{anchorLink && (
|
||||||
|
<a
|
||||||
|
aria-hidden
|
||||||
|
className="anchor-link"
|
||||||
|
href={`#${anchor}`}
|
||||||
|
tabIndex={-1}
|
||||||
|
></a>
|
||||||
|
)}
|
||||||
|
{Wrapper ? <Wrapper>{children}</Wrapper> : children}
|
||||||
|
</Tag>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
return Heading
|
||||||
|
}
|
||||||
|
|
||||||
|
const renderer = unified().use(remarkReact, {
|
||||||
|
remarkReactComponents: {
|
||||||
|
a: Anchor,
|
||||||
|
h1: heading(1, MarkWrapper),
|
||||||
|
h2: heading(2),
|
||||||
|
h3: heading(3),
|
||||||
|
h4: heading(4),
|
||||||
|
h5: heading(5),
|
||||||
|
h6: heading(6),
|
||||||
|
pre: PreCodeBlock,
|
||||||
|
img: Img,
|
||||||
|
},
|
||||||
|
sanitize: {
|
||||||
|
...gitHubSanitize,
|
||||||
|
attributes: {
|
||||||
|
...gitHubSanitize.attributes,
|
||||||
|
'*': [...gitHubSanitize.attributes['*'], 'data*'],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
toHast: {
|
||||||
|
commonmark: true,
|
||||||
|
handlers: {
|
||||||
|
code: (h, { position, lang, value }) =>
|
||||||
|
h(
|
||||||
|
position,
|
||||||
|
'pre',
|
||||||
|
{ 'data-code': value, 'data-language': lang?.trim() },
|
||||||
|
[]
|
||||||
|
),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
return renderer.stringify(renderer.runSync(mdast))
|
||||||
|
}
|
7
website/utils/title.ts
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
export const generateTitle = (breadcrumbs: string[] = []) =>
|
||||||
|
[
|
||||||
|
...breadcrumbs,
|
||||||
|
`Marp${
|
||||||
|
breadcrumbs.length === 0 ? ': Markdown Presentation Ecosystem' : ''
|
||||||
|
}`,
|
||||||
|
].join(' | ')
|
2
website/utils/url.ts
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
export const absoluteUrl = (path: string) =>
|
||||||
|
new URL(path, process.env.NEXT_PUBLIC_HOST)
|