Showing preview only (475K chars total). Download the full file or copy to clipboard to get everything.
Repository: ksky521/nodeppt
Branch: master
Commit: 44f4babb6586
Files: 159
Total size: 434.6 KB
Directory structure:
gitextract_k4sj6t2_/
├── .editorconfig
├── .github/
│ └── ISSUE_TEMPLATE.md
├── .gitignore
├── .prettierrc
├── MIT-LICENSE.txt
├── README.md
├── gh-page.sh
├── lerna.json
├── package.json
├── packages/
│ ├── nodeppt/
│ │ ├── .npmignore
│ │ ├── README.md
│ │ ├── __tests__/
│ │ │ └── demo.md
│ │ ├── bin/
│ │ │ └── nodeppt
│ │ ├── commands/
│ │ │ └── new.js
│ │ ├── lib/
│ │ │ ├── ask.js
│ │ │ └── generate.js
│ │ └── package.json
│ ├── nodeppt-js/
│ │ ├── .npmignore
│ │ ├── assets/
│ │ │ └── less/
│ │ │ ├── _base.less
│ │ │ ├── _color.less
│ │ │ ├── _typography.less
│ │ │ ├── _vars.less
│ │ │ ├── full.less
│ │ │ ├── index.less
│ │ │ ├── modules/
│ │ │ │ ├── _animation.less
│ │ │ │ ├── _avatars.less
│ │ │ │ ├── _badges.less
│ │ │ │ ├── _browser.less
│ │ │ │ ├── _build.less
│ │ │ │ ├── _button.less
│ │ │ │ ├── _cards.less
│ │ │ │ ├── _flexblock-activity.less
│ │ │ │ ├── _flexblock-clients.less
│ │ │ │ ├── _flexblock-features.less
│ │ │ │ ├── _flexblock-gallery.less
│ │ │ │ ├── _flexblock-metrics.less
│ │ │ │ ├── _flexblock-plans.less
│ │ │ │ ├── _flexblock-reasons.less
│ │ │ │ ├── _flexblock-specs.less
│ │ │ │ ├── _flexblock-steps.less
│ │ │ │ ├── _flexblock.less
│ │ │ │ ├── _form.less
│ │ │ │ ├── _grid.less
│ │ │ │ ├── _header-footer.less
│ │ │ │ ├── _logo.less
│ │ │ │ ├── _longform.less
│ │ │ │ ├── _media.less
│ │ │ │ ├── _navigation.less
│ │ │ │ ├── _print.less
│ │ │ │ ├── _promos.less
│ │ │ │ ├── _quotes.less
│ │ │ │ ├── _slides-bg.less
│ │ │ │ ├── _slides-navigation.less
│ │ │ │ ├── _slides.less
│ │ │ │ ├── _speaker-note.less
│ │ │ │ ├── _tables.less
│ │ │ │ ├── _toc.less
│ │ │ │ ├── _with-note.less
│ │ │ │ ├── _work.less
│ │ │ │ └── _zoom.less
│ │ │ └── utils/
│ │ │ ├── _animations.less
│ │ │ ├── _bugs.less
│ │ │ ├── _clear.less
│ │ │ └── _reset.less
│ │ ├── index.js
│ │ ├── package.json
│ │ └── plugins/
│ │ ├── echarts.js
│ │ ├── keyboard.js
│ │ ├── mermaid.js
│ │ ├── speaker-mode.js
│ │ └── speaker-note.js
│ ├── nodeppt-parser/
│ │ ├── .npmignore
│ │ ├── __tests__/
│ │ │ ├── classes.md
│ │ │ ├── demo.md
│ │ │ └── public/
│ │ │ └── demo.js
│ │ ├── defaults.js
│ │ ├── index.js
│ │ ├── lib/
│ │ │ ├── get-markdown-parser.js
│ │ │ ├── get-parser.js
│ │ │ ├── markdown/
│ │ │ │ ├── attrs/
│ │ │ │ │ ├── index.js
│ │ │ │ │ ├── patterns.js
│ │ │ │ │ └── utils.js
│ │ │ │ ├── cite.js
│ │ │ │ ├── container.js
│ │ │ │ ├── containers/
│ │ │ │ │ ├── blink.js
│ │ │ │ │ ├── card.js
│ │ │ │ │ ├── column.js
│ │ │ │ │ ├── cta.js
│ │ │ │ │ ├── div.js
│ │ │ │ │ ├── features.js
│ │ │ │ │ ├── flexblock.js
│ │ │ │ │ ├── flexbox.js
│ │ │ │ │ ├── gallery.js
│ │ │ │ │ ├── shadow.js
│ │ │ │ │ ├── specs.js
│ │ │ │ │ └── steps.js
│ │ │ │ ├── echarts.js
│ │ │ │ ├── fa.js
│ │ │ │ ├── img.js
│ │ │ │ ├── jsx.js
│ │ │ │ ├── link.js
│ │ │ │ ├── mermaid.js
│ │ │ │ ├── plus-list.js
│ │ │ │ ├── prism.js
│ │ │ │ ├── regexp/
│ │ │ │ │ ├── index.js
│ │ │ │ │ └── utils.js
│ │ │ │ └── span.js
│ │ │ ├── tags/
│ │ │ │ ├── attrs.js
│ │ │ │ ├── header-footer.js
│ │ │ │ ├── note.js
│ │ │ │ ├── slide.js
│ │ │ │ └── utils.js
│ │ │ ├── utils.js
│ │ │ └── yaml-parser.js
│ │ ├── package.json
│ │ └── template/
│ │ └── index.ejs
│ ├── nodeppt-serve/
│ │ ├── .npmignore
│ │ ├── PluginAPI.js
│ │ ├── Service.js
│ │ ├── commands/
│ │ │ ├── build.js
│ │ │ └── serve.js
│ │ ├── config/
│ │ │ ├── app.js
│ │ │ ├── base.js
│ │ │ ├── css.js
│ │ │ ├── dev.js
│ │ │ └── prod.js
│ │ ├── index.js
│ │ ├── lib/
│ │ │ ├── globalConfigPlugin.js
│ │ │ └── utils.js
│ │ ├── options.js
│ │ ├── package.json
│ │ └── template/
│ │ ├── main.js
│ │ └── reload.js
│ └── nodeppt-shared-utils/
│ ├── .npmignore
│ ├── index.js
│ ├── lib/
│ │ ├── download-repo.js
│ │ ├── eval.js
│ │ ├── find-existing.js
│ │ ├── get-debug.js
│ │ ├── get-latest-version.js
│ │ ├── git-user.js
│ │ ├── logger.js
│ │ ├── new-version-log.js
│ │ ├── path.js
│ │ ├── plugin.js
│ │ ├── prepare-urls.js
│ │ ├── spinner.js
│ │ └── webpack-error.js
│ └── package.json
└── site/
├── animation.md
├── background.md
├── classes.md
├── component.md
├── echarts.md
├── index.md
├── layout.md
├── media.md
├── mermaid.md
└── public/
└── background.js
================================================
FILE CONTENTS
================================================
================================================
FILE: .editorconfig
================================================
root = true
[*]
charset = utf-8
indent_style = space
indent_size = 4
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true
[{.travis.yml,ci.yml}]
indent_style = space
indent_size = 2
[*.md]
trim_trailing_whitespace = false
================================================
FILE: .github/ISSUE_TEMPLATE.md
================================================
<!--
提issue,请注意:
1. 请按照下面模板填写,否则issue会直接被关闭!
2. 请使用Chrome浏览器查看样式问题,不再做其他浏览器兼容性支持;
3. Node版本需要大于8.9,不再解决低版本问题;
4. 请使用build命令直接导出静态文件部署,不鼓励使用seve命令做服务部署;
5. 只有title的issue会被忽略
--->
| Executable | Version |
| ---: | :--- |
| `node --version` | VERSION |
| `npm --version` | VERSION |
| `nodeppt -v` | VERSION |
| OS | Version |
| --- | --- |
| NAME | VERSION |
<!-- For example:
| macOS Sierra | 10.12.3 |
| Windows 10 | 1607 |
| Ubuntu | 16.10 |
-->
================================================
FILE: .gitignore
================================================
yarn.lock
/node_modules
/.sass-cache
/src/index.html
/test
/3th
/.idea
/.vscode
.DS_Store
/npm-debug.log
dist
publish
output
yarn-lock.json
package-lock.json
.DS_Store
### Node ###
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
# Runtime data
pids
*.pid
*.seed
*.pid.lock
# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov
# Coverage directory used by tools like istanbul
coverage
# nyc test coverage
.nyc_output
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
.grunt
# Bower dependency directory (https://bower.io/)
bower_components
# node-waf configuration
.lock-wscript
# Compiled binary addons (http://nodejs.org/api/addons.html)
build/Release
# Dependency directories
node_modules/
jspm_packages/
# Typescript v1 declaration files
typings/
# Optional npm cache directory
.npm
# Optional eslint cache
.eslintcache
# Optional REPL history
.node_repl_history
# Output of 'npm pack'
*.tgz
# Yarn Integrity file
.yarn-integrity
# dotenv environment variables file
.env
### WebStorm ###
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm
# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
# User-specific stuff:
.idea/**/workspace.xml
.idea/**/tasks.xml
.idea/dictionaries
# Sensitive or high-churn files:
.idea/**/dataSources/
.idea/**/dataSources.ids
.idea/**/dataSources.xml
.idea/**/dataSources.local.xml
.idea/**/sqlDataSources.xml
.idea/**/dynamic.xml
.idea/**/uiDesigner.xml
# Gradle:
.idea/**/gradle.xml
.idea/**/libraries
# CMake
cmake-build-debug/
# Mongo Explorer plugin:
.idea/**/mongoSettings.xml
## File-based project format:
*.iws
## Plugin-specific files:
# IntelliJ
/out/
# mpeltonen/sbt-idea plugin
.idea_modules/
# JIRA plugin
atlassian-ide-plugin.xml
# Cursive Clojure plugin
.idea/replstate.xml
# Crashlytics plugin (for Android Studio and IntelliJ)
com_crashlytics_export_strings.xml
crashlytics.properties
crashlytics-build.properties
fabric.properties
### WebStorm Patch ###
# Comment Reason: https://github.com/joeblau/gitignore.io/issues/186#issuecomment-215987721
# *.iml
# modules.xml
# .idea/misc.xml
# *.ipr
# Sonarlint plugin
.idea/sonarlint
# End of https://www.gitignore.io/api/node,webstorm
================================================
FILE: .prettierrc
================================================
{
"singleQuote": true,
"printWidth": 120,
"tabWidth": 4,
"bracketSpacing": false,
"overrides": [
{
"files": ".prettierrc",
"options": {"parser": "json"}
}
]
}
================================================
FILE: MIT-LICENSE.txt
================================================
Copyright 2013 Theowang http://js8.in
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
================================================
FILE: README.md
================================================
<h1 align="center">nodeppt 2.0</h1>
> 累死累活干不过做 PPT 的!<br/> > **查看效果:https://nodeppt.js.org**
[](https://www.npmjs.com/package/nodeppt)
**nodeppt 2.0** 基于[webslides](https://github.com/webslides/WebSlides)、webpack、markdown-it、posthtml 重构,[新效果](https://nodeppt.js.org)
<h2 align="center">Install</h2>
```bash
npm install -g nodeppt
```
## TODO
* bug fix
* 增加多页编辑公共资源,说人话就是 splitChunks
<h2 align="center">Usage</h2>
简化了,就三个命令:
- new:使用线上模板创建一个新的 md 文件
- serve:启动一个 md 文件的 webpack dev server
- build:编译产出一个 md 文件
```bash
# create a new slide with an official template
$ nodeppt new slide.md
# create a new slide straight from a github template
$ nodeppt new slide.md -t username/repo
# start local sever show slide
$ nodeppt serve slide.md
# to build a slide
$ nodeppt build slide.md
```
### 帮助
```bash
# help
nodeppt -h
# 获取帮助
nodeppt serve -h
```
<h2 align="center">演讲者模式</h2>
nodeppt 有演讲者模式,在页面 url 后面增加`?mode=speaker` 既可以打开演讲者模式,双屏同步
<h2 align="center">Keyboard Shortcuts</h2>
- Page: ↑/↓/←/→ Space Home End
- Fullscreen: F
- Overview: -/+
- Speaker Note: N
- Grid Background: Enter
<h2 align="center">公共资源:public 文件夹</h2>
如果项目文件夹下,存在`public`文件夹,可以直接通过 url 访问,参考`webpack dev server`的 `contentBase` 选项。
在`build`的时候,public 文件夹中的文件会完全 copy 到`dist`文件夹中
<h2 align="center">编写</h2>
最佳体验是 chrome 浏览器,本来就是给做演示用的,所以就别考虑非 Chrome 浏览器兼容问题了!
这里说下怎么编写。
### 基本语法
整个 markdown 文件分为两部分,第一部分是写在最前面的**配置**,然后是使用`<slide>`隔开的每页幻灯片内容。
### 配置
nodeppt 的配置是直接写在 md 文件顶部的,采用 yaml 语法,例如下面配置:
```yaml
title: nodeppt markdown 演示
speaker: 三水清
url: https://github.com/ksky521/nodeppt
js:
- https://www.echartsjs.com/asset/theme/shine.js
prismTheme: solarizedlight
plugins:
- echarts
- mermaid
- katex
```
- title: 演讲主题
- speaker:演讲者
- url:地址
- js:js 文件数组,放到 body 之前
- css:css 文件数组,放到头部
- prismTheme:prism 配色,取值范围 `['dark', 'coy', 'funky', 'okaidia', 'tomorrow', 'solarizedlight', 'twilight']`
- plugins:目前支持 [echarts](https://echarts.baidu.com/),[mermaid](https://mermaidjs.github.io/)和 [katex](https://katex.org) 三个插件
#### 插件
目前 nodeppt 支持 [图表 echarts](https://echarts.baidu.com/),[流程图 mermaid](https://mermaidjs.github.io/),[数学符号 KaTeX](https://katex.org) 三个插件。
#### echarts
echarts 主题配色可以直接在`yaml`配置的 js 中引入。echarts 采用`fence`语法,如下:
```echarts
{
xAxis: {
type: 'category',
data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
},
yAxis: {
type: 'value'
},
series: [{
data: [820, 932, 901, 934, 1290, 1330, 1320],
type: 'line'
}]
}
```
详见[site/echarts.md](./site/echarts.md)
#### mermaid
mermaid 主题配色可以直接在`yaml`配置的 js 中引入。mermaid 采用`fence`语法,如下:
```mermaid
sequenceDiagram
Alice ->> Bob: Hello Bob, how are you?
Bob-->>John: How about you John?
Bob--x Alice: I am good thanks!
Bob-x John: I am good thanks!
Note right of John: Bob thinks a long<br/>long time, so long<br/>that the text does<br/>not fit on a row.
Bob-->Alice: Checking with John...
Alice->John: Yes... John, how are you?
```
详见[site/mermaid.md](./site/mermaid.md)
#### ketex
参考:[markdown-it-katex](https://www.npmjs.com/package/markdown-it-katex)语法
### `<slide>` 语法
nodeppt 会根据`<slide>`对整个 markdown 文件进行拆分,拆成单页的幻灯片内容。`<slide>` 标签支持下面标签:
- class/style 等:正常的 class 类,可以通过这个控制居中(aligncenter),内容位置,背景色等
- image:背景图片,基本语法 `image="img_url"`
- video:背景视频,基本语法 `video="video_src1,video_src2"`
- :class:wrap 的 class,下面详解
每个 slide 会解析成下面的 html 结构:
```html
<section class="slide" attrs...><div class="wrap" wrap="true">// 具体 markdown 渲染的内容</div></section>
```
其中`<slide>` 的`class`等会被解析到 `<section>`标签上面,而`:class`则被解析到`div.wrap`上面,例如:
```html
<slide :class="size-50" class="bg-primary"></slide>
```
output 为:
```html
<section class="slide bg-primary"><div class="wrap size-50" wrap="true">// 具体 markdown 渲染的内容</div></section>
```
#### 背景:图片
`<slide>`的`image` 会被解析成背景大图,常见的支持方式有:
```md
<slide image="https://source.unsplash.com/UJbHNoVPZW0/">
# 这是一个普通的背景图
<slide image="https://source.unsplash.com/UJbHNoVPZW0/ .dark">
# 这张背景图会在图片上面蒙一层偏黑色的透明层
<slide image="https://source.unsplash.com/UJbHNoVPZW0/ .light">
# 这张背景图会在图片上面蒙一层偏白色的透明层
<slide class="bg-black aligncenter" image="https://source.unsplash.com/n9WPPWiPPJw/ .anim">
# 这张背景图会缓慢动
```
详见[site/background.md](./site/background.md)和[在线演示](https://js8.in/nodeppt/background.html)
### 样式
样式太多,具体详见[site/classes.md](./site/classes.md)和[在线演示](https://js8.in/nodeppt/classes.html)
### 布局
nodeppt 这次使用`webslides`的布局,支持丰富的布局,实在太多了,直接看文档[site/layout.md](./site/layout.md)和[在线演示](https://js8.in/nodeppt/layout.html)
### attribute
参考[markdown-it-attrs](https://www.npmjs.com/package/markdown-it-attrs),支持了`attribute`,修改增加多 class 支持等功能。
其中:`..class`会往上一级节点添加 class,支持`{.class1.class2}`这种多 class 的语法。用法举例:
```markdown
# header {.style-me.class2}
paragraph {data-toggle=modal}
```
Output:
```html
<h1 class="style-me class2">header</h1>
<p data-toggle="modal">paragraph</p>
```
```markdown
Use the css-module green on this paragraph. {.text-intro}
```
Output:
```html
<p class="text-intro">Use the css-module green on this paragraph.</p>
```
```markdown
- list item **bold** {.red}
```
Output:
```html
<ul>
<li class="red">list item <strong>bold</strong></li>
</ul>
```
```markdown
- list item **bold**
{.red}
```
Output:
```html
<ul class="red">
<li>list item <strong>bold</strong></li>
</ul>
```
### image 增强
对于 image ,支持外面包裹一层的写法,具体语法 `!`,例如:
```markdown
!
```
Output:
```html
<img src="https://webslides.tv/static/images/iphone.png" class="size-50 alignleft" />
```
```markdown
!
```
Output:
```html
<figure><img src="https://webslides.tv/static/images/setup.png" class="aligncenter" /></figure>
```
### button
nodeppt 的 button 是类似`link`语法的,支持蓝色、圆角、空心和 icon 版本的 button:
```markdown
[普通按钮](){.button} [圆角普通按钮](){.button.radius}
[空心](){.button.ghost} [:fa-github: 前面带 icon](){.button}
```
### Icon:FontAwesome
nodeppt 的 icon 支持 [FontAwesome](https://fontawesome.com/)
语法:
- `:fa-xxx:` → `<i class="fa fa-xxx"></i>`
- `:~fa-xxx:~` → `<span><i class="fa fa-xxx"></i></span>`
- `::fa-xxx::` → 块级`<i class="fa fa-xxx"></i>`,即不会被`p`包裹
### span
代码修改自[markdown-it-span](https://github.com/pnewell/markdown-it-span/),支持 `attr`语法,基本用法:
```md
:span:
:span: {.text-span}
```
### 动效
nodeppt 一如既往的支持动效,2.0 版本支持动效主要是页面内的动效。
支持动效包括:
- fadeIn
- zoomIn
- rollIn
- moveIn
- fadeInUp
- slow
在需要支持的动效父节点添加`.build`或者在具体的某个元素上添加`.tobuild+动效 class`即可。
按照惯例,nodeppt 还支持`animate.css`的动效哦~
详细查看文件:[site/animation.md](./site/animation.md)和[在线演示](https://js8.in/nodeppt/animation.html)
### 使用强大的`:::`完成复杂布局
`:::`语法是扩展了 [markdown-it-container](https://www.npmjs.com/package/markdown-it-container) 语法,默认是任意 tag,例如
```markdown
:::div {.content-left}
## title
:::
```
Output:
```html
<div class="content-left"><h2>title</h2></div>
```
还支持,`tag` 嵌套,除此之外,支持的组件包括:
- card:卡片,一边是图片,一边是内容
- column:column 多栏布局
- shadowbox:带阴影的盒子
- steps:步骤组件
- cta:
- gallery:图片
- flexblock:flex block 布局,支持多个子类型
- note: 演讲注释
基本语法是:
```markdown
:::TYPE {.attrs}
## 第一部分
使用 hr 标签隔开
---
## 第二部分
这里的内容也是哦
:::
```
详细可以看 [component](./site/component.md) 部分的 markdown 文件和[在线演示](https://js8.in/nodeppt/component.html)
<h2 align="center">打印?导出 pdf?</h2>
chrome 浏览器,直接在第一页 `command+P/ctrl+P` 即可
<h2 align="center">高级玩法</h2>
如果上面
### `nodeppt.config.js`
在 nodeppt 执行路径下创建`nodeppt.config.js`文件,可以配置跟`webpack`相关的选项,另外可以支持自研 nodeppt 插件。
默认内置的`config.js`内容如下:
```js
/**
* @file 默认配置
*/
module.exports = () => ({
// project deployment base
baseUrl: '/',
// where to output built files
outputDir: 'dist',
// where to put static assets (js/css/img/font/...)
assetsDir: '',
// filename for index.html (relative to outputDir)
indexPath: 'index.html',
// 插件,包括 markdown 和 posthtml
plugins: [],
// chainWebpack: [],
// whether filename will contain hash part
filenameHashing: true,
// boolean, use full build?
runtimeCompiler: false,
// deps to transpile
transpileDependencies: [
/* string or regex */
],
// sourceMap for production build?
productionSourceMap: true,
// use thread-loader for babel & TS in production build
// enabled by default if the machine has more than 1 cores
parallel: () => {
try {
return require('os').cpus().length > 1;
} catch (e) {
return false;
}
},
// multi-page config
pages: undefined,
// <script type="module" crossorigin="use-credentials">
// #1656, #1867, #2025
crossorigin: undefined,
// subresource integrity
integrity: false,
css: {
extract: true
// modules: false,
// localIdentName: '[name]_[local]_[hash:base64:5]',
// sourceMap: false,
// loaderOptions: {}
},
devServer: {
/*
host: '0.0.0.0',
port: 8080,
https: false,
proxy: null, // string | Object
before: app => {}
*/
}
});
```
### parser plugin
解析插件分两类: `markdown-it` 和 `posthtml`,
- markdown-it:是解析 markdown 文件的,如果是增强 markdown 语法,可以用这类插件
- posthtml:是处理 html 标签的,如果是修改输出的 html 内容,可以用这类插件
定义一个 plugin :
```js
module.exports = {
// 这里的 id 必须以 markdown/posthtml开头
// 分别对应 markdown-it和 posthtml 插件语法
id: 'markdown-xxx',
// 这里的 apply 是插件实际的内容,详细查看 markdown-it和 posthtml 插件开发
apply: () => {}
};
```
- [markdown-it docs](https://github.com/markdown-it/markdown-it/tree/master/docs)
- [posthtml docs](https://github.com/posthtml/posthtml/tree/master/docs)
### webslides plugin
WebSlides 插件需要写到一个 js 文件中,然后作为数组放到`window.WSPlugins_`中,然后通过在 md 页面的配置(yaml)添加 js 的方法引入。
```md
js: - webslide_plugins.js
```
```js
// webslide_plugins.js内容
window.WSPlugins_ = [
{
id: 'webslide_plugin_name',
// 下面是对应的插件类
apply: class Plugin {}
}
];
```
参考[WebSlides 文档](https://github.com/webslides/WebSlides/wiki/Plugin-development)
### Template:自制模板
参考[nodeppt-template-default](https://github.com/ksky521/nodeppt-template-default)。
然后使用`nodeppt new username/repo xxx.md`使用
<h2 align="center">Thanks</h2>
- [WebSlides](https://github.com/webslides/WebSlides)
- [markdown-it](https://github.com/markdown-it/markdown-it)
- [posthtml](https://github.com/posthtml/posthtml)
- [webpack](https://github.com/webpack/webpack)
- [vue-cli](https://github.com/vuejs/vue-cli)
================================================
FILE: gh-page.sh
================================================
#! /bin/sh
set -e
rm -rf publish
cd site
node ../packages/nodeppt/bin/nodeppt build index.md
node ../packages/nodeppt/bin/nodeppt build animation.md
node ../packages/nodeppt/bin/nodeppt build component.md
node ../packages/nodeppt/bin/nodeppt build layout.md
node ../packages/nodeppt/bin/nodeppt build media.md
node ../packages/nodeppt/bin/nodeppt build background.md
node ../packages/nodeppt/bin/nodeppt build classes.md
cd dist
echo 'nodeppt.js.org' > CNAME
git init
git add -A
date_str=`date "+DATE: %m/%d/%Y%nTIME: %H:%M:%S"`
git commit -m "build with nodeppt on $date_str"
#exit
echo 'push remote github'
git push -u git@github.com:ksky521/nodeppt.git master:gh-pages --force
================================================
FILE: lerna.json
================================================
{
"packages": [
"packages/*"
],
"npmClient": "yarn",
"command": {
"bootstrap": {
"npmClientArgs": [
"--no-lockfile"
]
}
},
"version": "2.2.2"
}
================================================
FILE: package.json
================================================
{
"name": "nodeppt",
"private": true,
"workspaces": [
"packages/*"
],
"devDependencies": {
"lerna": "^3.20.2"
}
}
================================================
FILE: packages/nodeppt/.npmignore
================================================
__tests__
__mocks__
package-lock.json
yarn.lock
================================================
FILE: packages/nodeppt/README.md
================================================
# nodeppt 2.0
> 累死累活干不过做 PPT 的!<br/> > **查看效果:https://nodeppt.js.org**
[](https://www.npmjs.com/package/nodeppt)
**nodeppt 2.0** 基于[webslides](https://github.com/webslides/WebSlides)、webpack、markdown-it、posthtml 重构,[新效果](https://nodeppt.js.org)
## Install
```bash
npm install -g nodeppt
```
## Usage
简化了,就三个命令:
- new:使用线上模板创建一个新的 md 文件
- serve:启动一个 md 文件的 webpack dev server
- build:编译产出一个 md 文件
```bash
# create a new slide with an official template
$ nodeppt new slide.md
# create a new slide straight from a github template
$ nodeppt new slide.md -t username/repo
# start local sever show slide
$ nodeppt serve slide.md
# to build a slide
$ nodeppt build slide.md
```
### 帮助
```bash
# help
nodeppt -h
# 获取帮助
nodeppt serve -h
```
## 演讲者模式
nodeppt 有演讲者模式,在页面 url 后面增加`?mode=speaker` 既可以打开演讲者模式,双屏同步
## Keyboard Shortcuts
- Page: ↑/↓/←/→ Space Home End
- Fullscreen: F
- Overview: -/+
- Speaker Note: N
- Grid Background: Enter
## 公共资源:public 文件夹
如果项目文件夹下,存在`public`文件夹,可以直接通过 url 访问,参考`webpack dev server`的 `contentBase` 选项。
在`build`的时候,public 文件夹中的文件会完全 copy 到`dist`文件夹中
## 编写
最佳体验是 chrome 浏览器,本来就是给做演示用的,所以就别考虑非 Chrome 浏览器兼容问题了!
这里说下怎么编写。
### 基本语法
整个 markdown 文件分为两部分,第一部分是写在最前面的**配置**,然后是使用`<slide>`隔开的每页幻灯片内容。
### 配置
nodeppt 的配置是直接写在 md 文件顶部的,采用 yaml 语法,例如下面配置:
```yaml
title: nodeppt markdown 演示
speaker: 三水清
url: https://github.com/ksky521/nodeppt
js:
- https://www.echartsjs.com/asset/theme/shine.js
prismTheme: solarizedlight
plugins:
- echarts
- katex
```
- title: 演讲主题
- speaker:演讲者
- url:地址
- js:js 文件数组,放到 body 之前
- css:css 文件数组,放到头部
- prismTheme:prism 配色,取值范围 `['dark', 'coy', 'funky', 'okaidia', 'tomorrow', 'solarizedlight', 'twilight']`
- plugins:目前支持 [echarts](https://echarts.baidu.com/) 和 [katex](https://katex.org) 两个插件
- pluginsOptions:插件的配置
- webslidesOptions:[webslides](https://github.com/webslides/WebSlides/wiki/Core-API#options)配置
**webslidesOptions 对应的是 webslides 的配置,例如开启`autoslide`**:
```yaml
webslidesOptions:
autoslide: 5000
```
#### 插件
目前 nodeppt 支持 [图表 echarts](https://echarts.baidu.com/) ,[流程图 mermaid](https://mermaidjs.github.io/),[数学符号 KaTeX](https://katex.org) 3 个插件。
#### echarts
echarts 主题配色可以直接在`yaml`配置的 js 中引入。echarts 采用`fence`语法,如下:
```echarts
{
xAxis: {
type: 'category',
data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
},
yAxis: {
type: 'value'
},
series: [{
data: [820, 932, 901, 934, 1290, 1330, 1320],
type: 'line'
}]
}
```
详见[site/echarts.md](./site/echarts.md)
#### mermaid
mermaid 主题配色可以直接在`yaml`配置的 js 中引入。mermaid 采用`fence`语法,如下:
```mermaid
sequenceDiagram
Alice ->> Bob: Hello Bob, how are you?
Bob-->>John: How about you John?
Bob--x Alice: I am good thanks!
Bob-x John: I am good thanks!
Note right of John: Bob thinks a long<br/>long time, so long<br/>that the text does<br/>not fit on a row.
Bob-->Alice: Checking with John...
Alice->John: Yes... John, how are you?
```
详见[site/mermaid.md](./site/mermaid.md)
#### ketex
参考:[markdown-it-katex](https://www.npmjs.com/package/markdown-it-katex)语法
### `<slide>` 语法
nodeppt 会根据`<slide>`对整个 markdown 文件进行拆分,拆成单页的幻灯片内容。`<slide>` 标签支持下面标签:
- class/style 等:正常的 class 类,可以通过这个控制居中(aligncenter),内容位置,背景色等
- image:背景图片,基本语法 `image="img_url"`
- video:背景视频,基本语法 `video="video_src1,video_src2"`
- :class:wrap 的 class,下面详解
每个 slide 会解析成下面的 html 结构:
```html
<section class="slide" attrs...><div class="wrap" wrap="true">// 具体 markdown 渲染的内容</div></section>
```
其中`<slide>` 的`class`等会被解析到 `<section>`标签上面,而`:class`则被解析到`div.wrap`上面,例如:
```html
<slide :class="size-50" class="bg-primary"></slide>
```
output 为:
```html
<section class="slide bg-primary"><div class="wrap size-50" wrap="true">// 具体 markdown 渲染的内容</div></section>
```
#### 背景:图片
`<slide>`的`image` 会被解析成背景大图,常见的支持方式有:
```md
<slide image="https://source.unsplash.com/UJbHNoVPZW0/">
# 这是一个普通的背景图
<slide image="https://source.unsplash.com/UJbHNoVPZW0/ .dark">
# 这张背景图会在图片上面蒙一层偏黑色的透明层
<slide image="https://source.unsplash.com/UJbHNoVPZW0/ .light">
# 这张背景图会在图片上面蒙一层偏白色的透明层
<slide class="bg-black aligncenter" image="https://source.unsplash.com/n9WPPWiPPJw/ .anim">
# 这张背景图会缓慢动
```
详见[site/background.md](./site/background.md)和[在线演示](https://js8.in/nodeppt/background.html)
### 样式
样式太多,具体详见[site/classes.md](./site/classes.md)和[在线演示](https://js8.in/nodeppt/classes.html)
### 布局
nodeppt 这次使用`webslides`的布局,支持丰富的布局,实在太多了,直接看文档[site/layout.md](./site/layout.md)和[在线演示](https://js8.in/nodeppt/layout.html)
### attribute
参考[markdown-it-attrs](https://www.npmjs.com/package/markdown-it-attrs),支持了`attribute`,修改增加多 class 支持等功能。
其中:`..class`会往上一级节点添加 class,支持`{.class1.class2}`这种多 class 的语法。用法举例:
```markdown
# header {.style-me.class2}
paragraph {data-toggle=modal}
```
Output:
```html
<h1 class="style-me class2">header</h1>
<p data-toggle="modal">paragraph</p>
```
```markdown
Use the css-module green on this paragraph. {.text-intro}
```
Output:
```html
<p class="text-intro">Use the css-module green on this paragraph.</p>
```
```markdown
- list item **bold** {.red}
```
Output:
```html
<ul>
<li class="red">list item <strong>bold</strong></li>
</ul>
```
```markdown
- list item **bold**
{.red}
```
Output:
```html
<ul class="red">
<li>list item <strong>bold</strong></li>
</ul>
```
### image 增强
对于 image ,支持外面包裹一层的写法,具体语法 `!`,例如:
```markdown
!
```
Output:
```html
<img src="https://webslides.tv/static/images/iphone.png" class="size-50 alignleft" />
```
```markdown
!
```
Output:
```html
<figure><img src="https://webslides.tv/static/images/setup.png" class="aligncenter" /></figure>
```
### button
nodeppt 的 button 是类似`link`语法的,支持蓝色、圆角、空心和 icon 版本的 button:
```markdown
[普通按钮](){.button} [圆角普通按钮](){.button.radius}
[空心](){.button.ghost} [:fa-github: 前面带 icon](){.button}
```
### Icon:FontAwesome
nodeppt 的 icon 支持 [FontAwesome](https://fontawesome.com/)
语法:
- `:fa-xxx:` → `<i class="fa fa-xxx"></i>`
- `:~fa-xxx:~` → `<span><i class="fa fa-xxx"></i></span>`
- `::fa-xxx::` → 块级`<i class="fa fa-xxx"></i>`,即不会被`p`包裹
### span
代码修改自[markdown-it-span](https://github.com/pnewell/markdown-it-span/),支持 `attr`语法,基本用法:
```md
:span:
:span: {.text-span}
```
### 动效
nodeppt 一如既往的支持动效,2.0 版本支持动效主要是页面内的动效。
支持动效包括:
- fadeIn
- zoomIn
- rollIn
- moveIn
- fadeInUp
- slow
在需要支持的动效父节点添加`.build`或者在具体的某个元素上添加`.tobuild+动效 class`即可。
按照惯例,nodeppt 还支持`animate.css`的动效哦~
详细查看文件:[site/animation.md](./site/animation.md)和[在线演示](https://js8.in/nodeppt/animation.html)
### 使用强大的`:::`完成复杂布局
`:::`语法是扩展了 [markdown-it-container](https://www.npmjs.com/package/markdown-it-container) 语法,默认是任意 tag,例如
```markdown
:::div {.content-left}
## title
:::
```
Output:
```html
<div class="content-left"><h2>title</h2></div>
```
还支持,`tag` 嵌套,除此之外,支持的组件包括:
- card:卡片,一边是图片,一边是内容
- column:column 多栏布局
- shadowbox:带阴影的盒子
- steps:步骤组件
- cta:
- gallery:图片
- flexblock:flex block 布局,支持多个子类型
**基本语法**是:
```markdown
:::TYPE {.attrs}
## 第一部分
使用 hr 标签隔开
---
## 第二部分
这里的内容也是哦
:::
```
详细可以看 [component](./site/component.md) 部分的 markdown 文件和[在线演示](https://js8.in/nodeppt/component.html)
## 打印?导出 pdf?
在 chrome 浏览器,在 URL 添加`URL?print-pdf`,然后直接 `command+P/ctrl+P` 选择打印即可!
## 高级玩法
如果上面
### `nodeppt.config.js`
在 nodeppt 执行路径下创建`nodeppt.config.js`文件,可以配置跟`webpack`相关的选项,另外可以支持自研 nodeppt 插件。
默认内置的`config.js`内容如下:
```js
/**
* @file 默认配置
*/
module.exports = () => ({
// project deployment base
baseUrl: '/',
// where to output built files
outputDir: 'dist',
// where to put static assets (js/css/img/font/...)
assetsDir: '',
// filename for index.html (relative to outputDir)
indexPath: 'index.html',
// 插件,包括 markdown 和 posthtml
plugins: [],
// chainWebpack: [],
// whether filename will contain hash part
filenameHashing: true,
// boolean, use full build?
runtimeCompiler: false,
// deps to transpile
transpileDependencies: [
/* string or regex */
],
// sourceMap for production build?
productionSourceMap: true,
// use thread-loader for babel & TS in production build
// enabled by default if the machine has more than 1 cores
parallel: () => {
try {
return require('os').cpus().length > 1;
} catch (e) {
return false;
}
},
// multi-page config
pages: undefined,
// <script type="module" crossorigin="use-credentials">
// #1656, #1867, #2025
crossorigin: undefined,
// subresource integrity
integrity: false,
css: {
extract: true,
// modules: false,
// localIdentName: '[name]_[local]_[hash:base64:5]',
// sourceMap: false,
// loaderOptions: {}
},
devServer: {
/*
host: '0.0.0.0',
port: 8080,
https: false,
proxy: null, // string | Object
before: app => {}
*/
},
});
```
### parser plugin
解析插件分两类: `markdown-it` 和 `posthtml`,
- markdown-it:是解析 markdown 文件的,如果是增强 markdown 语法,可以用这类插件
- posthtml:是处理 html 标签的,如果是修改输出的 html 内容,可以用这类插件
定义一个 plugin :
```js
module.exports = {
// 这里的 id 必须以 markdown/posthtml开头
// 分别对应 markdown-it和 posthtml 插件语法
id: 'markdown-xxx',
// 这里的 apply 是插件实际的内容,详细查看 markdown-it和 posthtml 插件开发
apply: () => {},
};
```
- [markdown-it docs](https://github.com/markdown-it/markdown-it/tree/master/docs)
- [posthtml docs](https://github.com/posthtml/posthtml/tree/master/docs)
### webslides plugin
WebSlides 插件需要写到一个 js 文件中,然后作为数组放到`window.WSPlugins_`中,然后通过在 md 页面的配置(yaml)添加 js 的方法引入。
```md
js: - webslide_plugins.js
```
```js
// webslide_plugins.js内容
window.WSPlugins_ = [
{
id: 'webslide_plugin_name',
// 下面是对应的插件类
apply: class Plugin {},
},
];
```
参考[WebSlides 文档](https://github.com/webslides/WebSlides/wiki/Plugin-development)
### Template:自制模板
参考[nodeppt-template-default](https://github.com/ksky521/nodeppt-template-default)。
然后使用`nodeppt new username/repo xxx.md`使用
## Thanks
- [WebSlides](https://github.com/webslides/WebSlides)
- [markdown-it](https://github.com/markdown-it/markdown-it)
- [posthtml](https://github.com/posthtml/posthtml)
- [webpack](https://github.com/webpack/webpack)
- [vue-cli](https://github.com/vuejs/vue-cli)
================================================
FILE: packages/nodeppt/__tests__/demo.md
================================================
title: xxx
[slide]
# haha
## hahah121212
================================================
FILE: packages/nodeppt/bin/nodeppt
================================================
#!/usr/bin/env node
const program = require('commander');
const chalk = require('chalk');
const semver = require('semver');
const packageJson = require('../package.json');
const requiredVersion = packageJson.engines.node;
function checkNodeVersion(wanted, id) {
if (!semver.satisfies(process.version, wanted)) {
console.log(chalk.red(' You must upgrade node to >=' + wanted + ' to use nodeppt'));
process.exit(1);
}
}
checkNodeVersion(requiredVersion, packageJson.name);
if (process.argv[2] && process.argv[2] === '-v') {
process.argv[2] = '-V';
}
program.version(packageJson.version);
program
.command('serve [entry]')
.description('start local sever show slide')
.option('-p, --port [port]', 'set server port ', 8080)
.option('--https', 'use https ', 8080)
.option('-d, --dest <dir>', 'output directory')
.option('-H, --host [host]', 'set host address', '0.0.0.0')
.action((entry, cmd) => {
require('nodeppt-serve').serve(entry, cleanArgs(cmd));
})
.on('--help', () => {
console.log(' Examples:');
console.log();
console.log(' nodeppt serve slide.md');
console.log(' nodeppt serve slide.md -p 8080');
console.log();
});
program
.command('build [entry]')
.option('-m, --map', 'Release sourcemap')
.option('-d, --dest <dir>', 'output directory')
.description('build html file')
.action((entry, cmd) => {
require('nodeppt-serve').build(entry, cleanArgs(cmd));
})
.on('--help', () => {
console.log(' Examples:');
console.log();
console.log(' nodeppt build slide.md');
console.log();
});
program
.command('new [dest]')
.description('Create a new markdown slide')
.option('-t, --template [template]', 'template repo or path')
.option('-f, --force', 'force', 'Force to delete file exist, default:true')
.action((dest, cmd) => {
return require('../commands/new')(dest, cleanArgs(cmd));
})
.on('--help', () => {
console.log(' Examples:');
console.log();
console.log(chalk.gray(' # create a new slide with an official template'));
console.log(' $ nodeppt new slide.md');
console.log();
console.log(chalk.gray(' # create a new slide straight from a github template'));
console.log(' $ nodeppt new slide.md -t username/repo');
});
program.on('--help', () => {
console.log(' Examples:');
console.log();
console.log(chalk.gray(' # create a new slide with an official template'));
console.log(' $ nodeppt new slide.md');
console.log();
console.log(chalk.gray(' # create a new slide straight from a github template'));
console.log(' $ nodeppt new slide.md -t username/repo');
console.log();
console.log(chalk.gray(' # start local sever show slide'));
console.log(' $ nodeppt serve slide.md');
console.log();
console.log(chalk.gray(' # to build a slide'));
console.log(' $ nodeppt build slide.md');
console.log();
});
program.parse(process.argv);
if (!program.args[0] && process.argv[2] !== 'new') {
process.stdout.write(program.helpInformation());
program.emit('--help');
} else if (!['serve', 'build', 'new'].includes(process.argv[2])) {
program.emit('--help');
}
function cleanArgs(cmd) {
const args = {version: packageJson.version};
cmd.options.forEach((o) => {
const key = o.long.replace(/^--/, '');
// if an option is not present and Command has a method with the same name
// it should not be copied
if (typeof cmd[key] !== 'function' && typeof cmd[key] !== 'undefined') {
args[key] = cmd[key];
}
});
return args;
}
================================================
FILE: packages/nodeppt/commands/new.js
================================================
/**
* @file init 初始化项目
*/
const path = require('path');
const fs = require('fs-extra');
const home = require('user-home');
const inquirer = require('inquirer');
const exists = fs.existsSync;
const rm = fs.removeSync;
const generate = require('../lib/generate');
const {
chalk,
isLocalPath,
getTemplatePath,
error,
updateSpinner,
logWithSpinner,
stopSpinner,
log,
downloadRepo,
clearConsole
} = require('nodeppt-shared-utils');
const ALIAS_MAP = process.env.alias || {
buildin: path.parse(require.resolve('nodeppt-template-default')).dir,
default: 'ksky521/nodeppt-template-default'
};
const alias = name => {
if (ALIAS_MAP[name]) {
return ALIAS_MAP[name];
}
return name;
};
module.exports = async (dest, opts) => {
let template = opts.template;
// 使用内置的
template = alias(template || 'buildin');
if (!dest) {
const {filename} = await inquirer.prompt([
{
name: 'filename',
type: 'string',
required: true,
label: 'Please input markdown file name',
default: 'nodeppt.md'
}
]);
if (!filename) {
return;
} else {
dest = filename;
}
}
if (path.parse(dest).ext === '') {
dest += '.md';
}
if (exists(dest)) {
if (opts.force) {
// 强力删除
await fs.remove(dest);
} else {
clearConsole();
// 提示让删除
const {action} = await inquirer.prompt([
{
name: 'action',
type: 'list',
message: `${dest} file exists. Continue?:`,
choices: [
{name: 'overwrite', value: 'overwrite'},
{name: 'cancel', value: false}
]
}
]);
if (!action) {
return;
} else if (action === 'overwrite') {
log(`delete ${chalk.cyan(dest)}...`);
await fs.remove(dest);
}
}
}
if (isLocalPath(template)) {
// 使用离线地址
// 直接复制,不下载github代码
const templatePath = getTemplatePath(template);
if (exists(templatePath)) {
generate(templatePath, dest, opts);
} else {
error('Template not found');
}
} else {
// 临时存放地址,存放在~/.nodeppt-templates 下面
let tmp = path.join(home, '.nodeppt-templates', template.replace(/[/:#]/g, '-'));
clearConsole();
logWithSpinner('🗃', 'Download...');
if (exists(tmp)) {
rm(tmp);
}
downloadRepo(template, tmp, opts, err => {
if (!err) {
updateSpinner('🗃', 'Template download success!');
} else {
updateSpinner('❌', 'Template download error!');
}
stopSpinner();
console.log();
if (!err) {
generate(tmp, dest, opts);
} else {
error('Failed to download repo ' + template + ': ' + err.message.trim());
if (!process.env.DEBUG) {
log(`Use「${chalk.bgYellow.black('DEBUG=*')}」 to get more info`);
}
}
});
}
};
================================================
FILE: packages/nodeppt/lib/ask.js
================================================
/**
* @file 修改字 vue-cli,prompt 收集答案
*/
const inquirer = require('inquirer');
const {evaluate} = require('nodeppt-shared-utils');
const promptMapping = {
string: 'input',
boolean: 'confirm'
};
module.exports = (prompts, data) => {
const answers = {};
let keys = Object.keys(prompts);
return new Promise(async (resolve, reject) => {
let key;
while ((key = keys.shift())) {
await prompt(answers, key, prompts[key], data);
}
resolve(answers);
});
};
// 将 default 使用 templateData 渲染一下,比如作者之类的
function render(content, data) {
if (content && /{{([^{}]+)}}/g.test(content)) {
Object.keys(data).forEach(key => {
if (data[key] && typeof data[key] === 'string') {
content = content.split(new RegExp(`{{\\s*${key}\\s*}}`, 'g')).join(data[key]);
}
});
return content;
}
return content;
}
async function prompt(data, key, prompt, tplData) {
// 当 when 起作用的时候跳过
if (prompt.when && !evaluate(prompt.when, data)) {
return;
}
let promptDefault = prompt.default;
if (typeof promptDefault === 'function') {
promptDefault = function() {
return prompt.default.bind(this)(data);
};
}
const answers = await inquirer.prompt([
{
type: promptMapping[prompt.type] || prompt.type,
name: key,
message: prompt.message || prompt.label || key,
default: render(promptDefault, tplData),
choices: prompt.choices || [],
validate: prompt.validate || (() => true)
}
]);
if (Array.isArray(answers[key])) {
data[key] = {};
answers[key].forEach(multiChoiceAnswer => {
data[key][multiChoiceAnswer] = true;
});
} else if (typeof answers[key] === 'string') {
data[key] = answers[key].replace(/"/g, '\\"');
} else {
data[key] = answers[key];
}
}
================================================
FILE: packages/nodeppt/lib/generate.js
================================================
/**
* @file 根据模板生成项目目录结构
*/
const path = require('path');
const fs = require('fs');
const exists = fs.existsSync;
const semver = require('semver');
const Handlebars = require('handlebars');
const username = require('username');
const render = require('consolidate').handlebars.render;
const {
error,
log,
chalk,
success,
line,
getGitUser,
newVersionLog,
getLatestVersion,
logWithSpinner,
updateSpinner,
stopSpinner,
getDebugLogger
} = require('nodeppt-shared-utils');
const {name, version: localVersion} = require('../package.json');
const debug = getDebugLogger('generate', name);
const ask = require('./ask');
let newVersion = 0;
getLatestVersion().then(latest => {
if (semver.lt(localVersion, latest)) {
newVersion = latest;
}
});
// 增加 handleba helper
Handlebars.registerHelper('if_eq', (a, b, opts) => {
return a === b ? opts.fn(this) : opts.inverse(this);
});
Handlebars.registerHelper('unless_eq', (a, b, opts) => {
return a === b ? opts.inverse(this) : opts.fn(this);
});
module.exports = async (src, dest, cmdOpts) => {
// 0. 设置meta信息
const opts = getMetadata(src);
try {
opts.username = await username();
} catch (e) {
const {name: gitUser} = getGitUser();
opts.username = gitUser;
}
debug(opts);
// 1. 添加 handlebar helper
// eslint-disable-next-line
opts.helpers &&
Object.keys(opts.helpers).map(key => {
Handlebars.registerHelper(key, opts.helpers[key]);
});
// 2. 请回答
const answers = await ask(opts.prompts || {}, opts);
const data = Object.assign(
{
filename: dest,
inPlace: dest === process.cwd(),
noEscape: true
},
answers
);
debug(data);
console.log();
logWithSpinner('🐝', '开始初始化模板...');
const tpl = getTemplateContent(src);
const content = await template(tpl, data);
fs.writeFileSync(path.resolve(dest), content);
updateSpinner('🐝', `${dest} create success!`);
stopSpinner();
line(' 🎉 Success! ');
if (typeof opts.complete === 'function') {
// 跟 vue template 参数保持一致
opts.complete(data, {
chalk,
logger: {
log,
fatal: error,
success: success
}
});
if (newVersion) {
// 存在新版本
newVersionLog(localVersion, newVersion);
}
} else {
logMessage(opts.completeMessage, data);
}
};
function logMessage(message, data) {
if (isHandlebarTPL(message)) {
render(message, data)
.then(res => {
log(res);
})
.catch(err => {
error('\n Error when rendering template complete message:' + err.message.trim());
debug(message, data, err);
});
} else if (message) {
log(message);
}
if (newVersion) {
newVersionLog(localVersion, newVersion);
}
}
function getMetadata(dir) {
const json = path.join(dir, 'meta.json');
const js = path.join(dir, 'meta.js');
let opts = {};
if (exists(json)) {
const content = fs.readFileSync(json, 'utf-8');
opts = JSON.parse(content);
} else if (exists(js)) {
const req = require(path.resolve(js));
if (req !== Object(req)) {
throw new Error('meta.js syntax error');
}
opts = req;
}
return opts;
}
function getTemplateContent(dir) {
const md = path.join(dir, 'template.md');
const markdown = path.join(dir, 'template.markdown');
if (exists(md)) {
const content = fs.readFileSync(md, 'utf-8');
return content;
} else if (exists(markdown)) {
const content = fs.readFileSync(markdown, 'utf-8');
return content;
} else {
throw new Error('template.md not exist');
}
}
function isHandlebarTPL(content) {
return /{{([^{}]+)}}/g.test(content);
}
function template(content, data) {
if (!isHandlebarTPL(content)) {
return Promise.resolve(content);
}
return render(content, data);
}
================================================
FILE: packages/nodeppt/package.json
================================================
{
"name": "nodeppt",
"jsname": "nodeppt",
"description": "A simple, in-browser, markdown-driven presentation framework",
"version": "2.2.1",
"site": "https://github.com/ksky521/nodeppt",
"main": "index.js",
"author": {
"name": "Theo Wang",
"email": "ksky521@gmail.com"
},
"bin": {
"nodeppt": "bin/nodeppt"
},
"repository": {
"type": "git",
"url": "git://github.com/ksky521/nodeppt"
},
"engines": {
"node": ">=8.9"
},
"dependencies": {
"commander": "^4.1.0",
"consolidate": "^0.15.1",
"fs-extra": "^8.1.0",
"handlebars": "^4.0.12",
"inquirer": "^7.0.3",
"nodeppt-js": "^2.2.1",
"nodeppt-parser": "^2.2.1",
"nodeppt-serve": "^2.2.1",
"nodeppt-shared-utils": "^2.2.1",
"nodeppt-template-default": "^1.0.2",
"semver": "^7.1.1",
"user-home": "^2.0.0",
"username": "^5.1.0"
},
"keywords": [
"presentation",
"powerpoint",
"slideshow",
"keynote",
"ppt",
"slide",
"revealjs",
"impressjs",
"markdown-it",
"posthtml",
"webpack",
"nodeppt",
"markdown"
],
"readmeFilename": "README.md",
"license": "MIT",
"gitHead": "9fba34ba1a8cc3ab149c2447c313e25b1e25093e"
}
================================================
FILE: packages/nodeppt-js/.npmignore
================================================
__tests__
__mocks__
package-lock.json
yarn.lock
================================================
FILE: packages/nodeppt-js/assets/less/_base.less
================================================
// sass-lint:disable no-vendor-prefixes
/*=========================================
1. Base --> Baseline: 8px = .8rem
=========================================== */
/* -- Disable elastic scrolling/bounce:
webslides.js will add .ws-ready automatically. Don't worry :) -- */
.ws-ready {
&,
body {
height: 100%;
overflow: hidden;
width: 100%;
}
&.ws-ready-zoom {
overflow: visible;
body {
overflow: auto;
}
}
}
#webslides {
-ms-overflow-style: none;
-webkit-overflow-scrolling: touch; // sass-lint:disable-line no-misspelled-properties
height: 100vh;
overflow-x: hidden;
overflow-y: scroll;
&::-webkit-scrollbar {
display: none;
}
}
li li {
margin-left: 1.6rem;
}
a,
a:active,
a:focus,
a:visited,
input:focus,
textarea:focus,
button {
text-decoration: none;
transition: all 0.3s ease-out;
}
p a:active {
position: relative;
top: 2px;
}
nav a[rel='external'] em,
.hidden {
clip: rect(1px, 1px, 1px, 1px);
height: 1px;
overflow: hidden;
position: absolute;
width: 1px;
}
.shadow {
position: relative;
&:before,
&:after {
bottom: 1.6rem;
content: '';
max-width: 300px;
position: absolute;
top: 80%;
width: 50%;
z-index: -1;
}
&:after {
right: 2.4rem;
transform: rotate(3deg);
}
&:before {
left: 2.4rem;
transform: rotate(-3deg);
}
}
/*=== 1.1 WRAP/CONTAINER === */
.wrap,
header nav,
footer nav {
margin-left: auto;
margin-right: auto;
max-width: 100%;
position: relative;
width: 100%;
z-index: 2;
@media (min-width: 1024px) {
width: 90%;
}
}
.frame,
.shadow {
padding: 2.4rem;
}
.radius {
border-radius: 0.4rem;
}
.alignright {
float: right;
}
.alignleft {
float: left;
}
.aligncenter {
margin-left: auto;
margin-right: auto;
text-align: center;
}
img.aligncenter,
figure.aligncenter {
display: block;
margin-bottom: 0.8rem;
margin-top: 0.8rem;
}
img.alignleft,
figure.alignleft,
img.alignright,
figure.alignright,
img.aligncenter,
figure.aligncenter {
margin-bottom: 3.2rem;
margin-top: 3.2rem;
}
img.alignright,
svg.alignright,
figure.alignright {
margin: 0.8rem 0 0.8rem 2.4rem;
}
img.alignleft,
svg.alignleft,
figure.alignleft {
margin: 0.8rem 2.4rem 0.8rem 0;
}
@sizes: 80, 70, 60, 50, 40, 30, 20;
/*=== div.size-60, img.size-50, h1.size-40, p.size-30... === */
@media (min-width: 1024px) {
each(@sizes, {
.size-@{value} {
width: @value * 1%;
}
});
}
pre,
code {
font-family: 'Cousine', monospace;
}
pre {
font-size: 1.6rem;
line-height: 2.4rem;
overflow: auto;
padding: 2.4rem;
text-align: left;
white-space: pre-wrap;
width: 100%;
word-wrap: break-word;
& + p {
margin-top: 3.2rem;
}
code {
padding: 0;
}
}
code {
padding: 0.4rem;
}
================================================
FILE: packages/nodeppt-js/assets/less/_color.less
================================================
// sass-lint:disable no-color-literals
// sass-lint:disable no-vendor-prefixes
/*=========================================
19. Colors
=========================================== */
/* -- Disable elastic scrolling/bounce:
webslides.js will add .ws-ready automatically. Don't worry :) -- */
body {
background-color: @body-bg;
color: @body-color;
}
:focus {
box-shadow: @focus-box-shadow;
}
svg {
fill: currentColor;
}
[class*='bg-'] a,
[class*='bg-gradient-'] a {
color: @spindle;
}
.bg-brown a {
color: @link-color-secondary;
}
a,
.bg-white a,
.bg-light a,
.bg-gradient-white a {
color: @link-color;
}
a:hover {
color: @link-hover;
}
.flexblock li > a,
[class*='bg-'] li > a,
[class*='bg-gradient-'] li > a,
article header a {
color: inherit;
}
hr {
background: @hr-bg;
}
hr:after {
background-color: fade(@white, (0.8 * 100));
color: @body-color;
}
abbr,
acronym {
border-bottom: 1px dotted @body-bg;
}
mark,
ins {
background-color: fade(@pattens-blue, (0.8 * 100));
color: inherit;
}
::-moz-selection {
background-color: fade(@pattens-blue, (0.8 * 100));
}
::-webkit-selection {
background-color: fade(@pattens-blue, (0.8 * 100));
}
::selection {
background-color: fade(@pattens-blue, (0.8 * 100));
}
pre {
background: @white;
border: 1px solid fade(@stratos, (0.1 * 100));
box-shadow: 0 8px 16px fade(@stratos, (0.04 * 100)), 0 4px 16px fade(@black, (0.08 * 100));
&:hover {
box-shadow: 0 8px 16px rgba(0, 40, 160, 0.08), 0 8px 24px fade(@black, (0.08 * 100));
}
}
pre.no-style {
background: transparent;
border: none;
box-shadow: none;
&:hover {
box-shadow: none;
}
}
code,
[class*='bg-'] pre {
background-color: fade(@white, (0.09 * 100));
}
.bg-white code {
background: fade(@stratos, (0.03 * 100));
}
/*================================================
Slides - Backgrounds <section class="bg-primary">
================================================== */
/*3 Corp Colors*/
@bg-color-names: primary, secondary, light, black, black-blue, blue, brown, gray, green, purple, red, white, facebook;
@bg-colors: @royal-blue, @havelock-blue, @catskill-white, @cod-gray, @big-stone, @rhino, @gray-brown, @mischka,
@pine-green, @purple-heart, @cardinal, @white, @facebook;
.bg-colors-mixin(@names; @colors; @index) when (iscolor(extract(@colors, @index))) and (@index > 0) {
.bg-colors-mixin(@names; @colors; (@index - 1));
@name: extract(@names, @index);
@color: extract(@colors, @index);
.bg-@{name} {
background-color: @color;
}
}
// prettier-ignore
.bg-colors-mixin(@bg-color-names; @bg-colors;length(@bg-colors));
[class*='bg-'] .bg-white {
color: @body-color;
text-shadow: none;
}
/* BG Apple Keynote*/
.bg-apple {
background: linear-gradient(to bottom, @black 0%, #1a2028 50%, #293845 100%);
}
/*Font Color*/
.bg-trans-dark,
.bg-trans-gradient,
.bg-primary,
.bg-secondary,
.bg-blue,
.bg-green,
.bg-purple,
.bg-red,
.bg-facebook,
.bg-apple,
[class*='bg-black'],
[class*='bg-gradient-'] {
color: @white;
text-shadow: 0 1px 0 #013;
}
.bg-light p {
color: #456;
}
.bg-brown p {
color: #666;
}
/*Transparent/Opacity*/
.bg-trans-dark {
background: fade(@black, (0.8 * 100));
}
.bg-trans-light {
background: fade(@black, (0.2 * 100));
}
/*Covers/Longforms...*/
.bg-trans-gradient {
background: linear-gradient(to top, fade(@black, (0.8 * 100)) 0%, fade(@black, (0 * 100)) 100%);
}
/*Horizontal Gradient*/
.bg-gradient-h {
background: linear-gradient(134deg, #32b 0, #62b 100%);
}
/*Vertical Gradient*/
.bg-gradient-v {
background: linear-gradient(to top, #62b 0%, #32b 100%);
}
/*Radial Gradient*/
.bg-gradient-r {
background: radial-gradient(ellipse at center, #62b 0%, #32b 100%);
}
/*White Gradient (vertical)*/
.bg-gradient-white {
background: linear-gradient(180deg, #f2f4f6 0, @white 100%);
color: @body-color;
text-shadow: none;
}
/*Gray Gradient (horizontal)*/
.bg-gradient-gray {
background: linear-gradient(90deg, #f7f9fb 0, #dee2e6 100%);
color: @body-color;
text-shadow: none;
}
/*Border/Frame*/
.frame {
border: 0.8rem solid @white;
}
[class*='background'].frame {
border-width: 0.2rem;
}
/*Layer/Box Shadow*/
.shadow,
.pre {
position: relative;
}
.shadow:before,
.shadow:after {
box-shadow: 0 16px 24px fade(@stratos, (0.3 * 100));
}
/*============================
TYPOGRAPHY
============================== */
/* -- Horizontal separator -- */
.text-separator:before {
background-color: rgba(170, 0, 0, 0.8);
}
/* -- Pull Quote (Right/Left) -- */
[class*='text-pull-'] {
border-top: 4px solid fade(@black, (0.5 * 100));
}
img[class*='text-pull-'],
figure[class*='text-pull-'] {
border-top: 0;
}
/* -- Context -- */
[class*='bg-'] .text-context:before {
background-color: @white;
}
.text-context:before,
.bg-white .text-context:before {
background-color: fade(@stratos, (0.2 * 100));
}
/* -- Text shadow -- */
.text-shadow {
text-shadow: 0 0 40px fade(@black, (0.5 * 100));
}
/* -- time, ampersands, prepositions (for, of...), symbols...
[class*='card-'] time,
h1 span {
color: #abd;
}
/* -- <pre> comment -- */
.code-comment {
color: rgba(70, 170, 130, 0.9);
text-shadow: none;
}
/*=========================================
Header/Nav
=========================================== */
header[role='banner'] {
background-color: @white;
}
.logo a {
color: inherit;
}
nav[role='navigation'] li {
&.active a {
background-color: #555;
color: @white;
}
a {
background-color: rgba(50, 50, 50, 0.9);
color: @white;
&:hover {
background-color: rgba(50, 50, 50, 0.7);
}
}
}
@socials: twitter, facebook, linkedin, dribbble, github, email;
@socials-colors: #1da1f3, @facebook, #1683bb, #ea4c89, #60b044, #dd4b39;
.socials-colors-mixin(@names; @colors; @index) when (iscolor(extract(@colors, @index))) and (@index > 0) {
.socials-colors-mixin(@names; @colors; (@index - 1));
@name: extract(@names, @index);
@color: extract(@colors, @index);
nav li.@{name} a:hover {
background-color: @color;
}
}
// prettier-ignore
.socials-colors-mixin(@socials; @socials-colors;length(@socials-colors));
/*===================================================
.flexblock li hover/active
===================================================== */
.flexblock li.active a,
.metrics li:hover,
.specs li:hover,
.reasons li:hover {
background-color: fade(@stratos, (0.03 * 100));
}
/*=========================================
Features & Clients List
=========================================== */
.features li,
.clients li {
background-color: fade(@white, (0.9 * 100));
}
[class*='bg-'] .features li,
[class*='bg-'] .clients li {
background-color: fade(@white, (0.1 * 100));
}
.features li:hover,
.clients li:hover {
box-shadow: 0 8px 16px fade(@stratos, (0.02 * 100)), 0 4px 16px fade(@black, (0.08 * 100));
}
/*============================
.flexblock with border
============================== */
.border {
border-bottom: 1px solid fade(@stratos, (0.1 * 100));
border-right: 1px solid fade(@stratos, (0.1 * 100));
}
.border li {
border-left: 1px solid fade(@stratos, (0.1 * 100));
border-top: 1px solid fade(@stratos, (0.1 * 100));
}
.flexblock.border li li {
border: 0;
}
/*===========================================
flexblock.steps
============================================= */
.steps li:nth-child(1) {
background-color: #e8eef7;
}
.steps li:nth-child(2) {
background-color: #dde5f3;
}
.steps li:nth-child(3) {
background-color: #cdd8ec;
}
.steps li:nth-child(4) {
background-color: #bbcdec;
}
.process {
border-bottom: 15px solid transparent;
border-top: 15px solid transparent;
}
.steps li:hover,
.steps.blink li:hover > a {
background-color: #b8cef7;
}
@media (min-width: 1024px) {
.process.step-2 {
border-left-color: #e8eef7;
}
.process.step-3 {
border-left-color: #dde5f3;
}
.process.step-4 {
border-left-color: #cdd8ec;
}
.steps li:hover + li [class*='step-'] {
border-left-color: #b8cef7;
}
}
/*=========================================================
Items: You can use for settings, drag&drop, close/delete...
=========================================================== */
.specs li:after {
background: linear-gradient(
to right,
fade(@stratos, (0 * 100)) 0%,
fade(@stratos, (0.2 * 100)) 50%,
fade(@stratos, (0 * 100)) 100%
);
}
.specs li:last-child:after {
background: none;
}
/*=========================================================
Why/Steps/Motivation/Reasons - Decimal/Numbers
=========================================================== */
.reasons li:after {
background: linear-gradient(
to right,
fade(@stratos, (0 * 100)) 0%,
fade(@stratos, (0.2 * 100)) 50%,
fade(@stratos, (0 * 100)) 100%
);
}
.reasons li:last-child:after {
background: none;
}
/*=========================================
Overlays
=========================================== */
.overlay {
background-color: fade(@black, (0.2 * 100));
}
li:hover .overlay {
background-color: fade(@black, (0.1 * 100));
}
.overlay,
.overlay a {
color: @white;
text-shadow: 0 1px 0 #111;
}
/*=========================================
Gallery li+.overlay+image
=========================================== */
.gallery li {
background-color: fade(@stratos, (0.06 * 100));
box-shadow: 0 1px 1px fade(@black, (0.2 * 100)), 0 4px 8px fade(@black, (0.03 * 100));
}
.gallery li figcaption {
background-color: @white;
}
.flexblock.gallery li:hover {
box-shadow: 0 1px 1px fade(@black, (0.2 * 100)), 0 4px 8px fade(@black, (0.08 * 100));
}
.gallery li footer {
border-top: 1px solid fade(@stratos, (0.1 * 100));
}
.gallery li a {
color: @body-color;
text-shadow: none;
}
.flesblock.gallery li a footer {
color: #aaa;
}
/*Arrow */
.gallery li figcaption:before {
border: 0.8rem solid @black;
border-color: transparent transparent @white @white;
}
/*=========================================
Plans / Pricing
=========================================== */
.plans > li div,
.flexblock.plans li:hover div {
background-color: @white;
}
.plans > li:hover,
.plans > li:nth-child(2) {
box-shadow: 0 1px 1px fade(@black, (0.1 * 100)), 0 8px 16px fade(@black, (0.1 * 100));
}
.plans:hover li:nth-child(2):not(:hover) {
box-shadow: none;
}
.plans li h2 {
background-color: fade(@stratos, (0.5 * 100));
color: @white;
}
.plans ul li {
border-bottom: 1px solid fade(@stratos, (0.1 * 100));
&:last-child {
border-bottom: 0;
}
}
.plans > li > a {
color: @body-color;
text-shadow: none;
}
/*============================
Activity/CV/Timeline/News
============================== */
.activity li {
border-top: 0.1rem solid fade(@stratos, (0.1 * 100));
}
.activity li:hover {
background-color: fade(@stratos, (0.02 * 100));
}
/*=========================================
Resume/Work/CV/Portfolio
=========================================== */
.work-label,
.work li a {
border-bottom: 1px solid fade(@stratos, (0.1 * 100));
}
.work li:nth-child(odd) > a {
background-color: fade(@stratos, (0.03 * 100));
}
.work li a:hover {
background-color: fade(@stratos, (0.04 * 100));
}
/*===========================================
Clients / Services / Logos...
============================================= */
.clients.border figcaption {
border-top: 1px solid fade(@stratos, (0.1 * 100));
}
/*====================
LOGOS
====================== */
/* --- Images (black logo/image) --- */
img.blacklogo {
background: none;
filter: grayscale(100%) brightness(10%) contrast(100%);
}
/* --- Images (gray logo/image) --- */
img.graylogo {
filter: grayscale(100%) brightness(10%) contrast(10%);
}
/* --- Images (white Logo/Image) --- */
img.whitelogo {
filter: brightness(0) invert(1);
}
/* --- Logo/Images Hover --- */
li:hover img.blacklogo,
li:hover img.graylogo,
img.blacklogo:hover,
img.graylogo:hover {
background: none;
filter: grayscale(0%);
transition: all 0.6s ease;
}
/*=========================================================
Cards
=========================================================== */
[class*='card-'] > a {
color: inherit;
}
/* --- card ul specs --- */
.description > li {
border-bottom: 1px solid fade(@stratos, (0.1 * 100));
}
.description > li:last-child {
border-bottom: 0;
}
/*== Figure Background === */
[class*='card-'][class*='bg-'] figure {
background-color: fade(@stratos, (0.06 * 100));
}
/*== Ficaption Cards === */
[class*='card'] figcaption,
[class*='card'] figcaption a {
background: linear-gradient(to bottom, fade(@black, (0 * 100)) 0%, fade(@black, (0.2 * 100)) 100%);
color: @white;
}
/*===CTA (Call to Action - Numbers, Price, Promo...) ===== */
@media (min-width: 768px) {
.cta .benefit {
border-image: linear-gradient(90deg, transparent, fade(@black, (0.4 * 100)) 50%, transparent) 1 100%;
border-left-width: 1px;
border-style: solid;
}
}
/*=========================================
Tables
=========================================== */
table.table-dark {
td,
th,
thead {
border: 1px solid fade(@black, (0.5 * 100));
}
thead {
background-color: fade(@black, (0.3 * 100));
}
tr:nth-child(even) > td {
background: fade(@black, (0.1 * 100));
}
tr > td {
border-top: 1px solid fade(@black, (0.5 * 100));
}
td:hover,
tr:nth-child(even) > td:hover {
background-color: fade(@white, (0.5 * 100));
}
}
table td,
th,
thead {
border: 1px solid fade(@stratos, (0.1 * 100));
}
tr:nth-child(even) > td {
background-color: fade(@stratos, (0.03 * 100));
}
tr > td {
border-bottom: 1px solid fade(@stratos, (0.1 * 100));
}
td:hover,
tr:nth-child(even) > td:hover {
background-color: fade(@stratos, (0.04 * 100));
}
/*============================
Browser (Screenshots)
============================== */
.browser {
border: 1px solid fade(@stratos, (0.1 * 100));
}
.browser:hover {
box-shadow: 0 1px 1px fade(@black, (0.1 * 100)), 0 8px 16px fade(@black, (0.1 * 100));
}
/*=== Topbar === */
.browser:before {
background-color: fade(@stratos, (0.1 * 100));
border-bottom: 1px solid fade(@stratos, (0.2 * 100));
color: fade(@white, (0.9 * 100));
}
.browser:hover:before {
background-color: fade(@stratos, (0.12 * 100));
color: @white;
}
/*=========================================
Forms
=========================================== */
input,
textarea {
background-color: #fafbfc;
}
input:focus,
textarea:focus {
background-color: @white;
box-shadow: 0 0 5px rgba(81, 203, 238, 1);
}
input:focus::-moz-placeholder {
color: #ddd;
}
input:focus::-webkit-input-placeholder {
color: #ddd;
}
a.button,
[class*='badge-'],
button[type='submit'],
input {
box-shadow: 0 10px 16px -8px fade(@stratos, (0.3 * 100));
}
button,
input,
select,
textarea,
button[type='submit'],
input[type='submit'],
.button,
.button:hover,
button[type='submit']:hover,
input[type='submit']:hover {
border: 1px solid @royal-blue;
}
button[type='submit'],
input[type='submit'],
.button,
.button:hover,
button[type='submit']:hover,
input[type='submit']:hover {
background-color: @royal-blue;
color: @white;
text-shadow: 0 1px 0 #123;
}
.button:active,
button[type='submit']:active,
input[type='submit']:active {
background-color: #17d;
}
.ghost,
.ghost:hover {
background: none;
color: inherit;
text-shadow: none;
}
.bg-primary select,
.bg-primary textarea,
.bg-primary .button,
.bg-primary button,
.bg-primary button:hover,
.bg-primary input,
[class*='bg-gradient-'] .button,
[class*='bg-'] a.button.ghost {
border-color: @white;
}
[class*='bg-'] a.button {
color: @white;
}
.bg-white a.button.ghost,
.bg-gradient-white a.button.ghost {
border: 1px solid @royal-blue;
color: @body-color;
}
:disabled,
button:disabled:hover {
background-color: #eee;
border-color: #eee;
color: #ccc;
}
fieldset {
background-color: fade(@stratos, (0.2 * 100));
border: 1px solid @royal-blue;
}
legend {
background-color: fade(@black, (0.6 * 100));
color: @white;
}
/* Inputs/Buttons - hover */
input:hover,
select:hover {
box-shadow: 0 0 8px fade(@black, (0.3 * 100));
}
/* App Store Badges */
[class*='badge-'] {
background-color: @black;
border: 1px solid #345;
}
form .flexblock li:hover {
background-color: fade(@black, (0.05 * 100));
}
/*============================
Table of Contents
============================== */
.toc,
.toc ol > li:before,
.chapter {
background-color: #f7f9fb;
}
.toc li .toc-page:before {
border-bottom: 1px dotted fade(@black, (0.9 * 100));
}
/*============================
Slides (Counter/Arrows)
============================== */
#counter,
#navigation a {
color: #abc;
}
#webslides:hover #navigation a:hover {
background-color: @index-overlay;
color: @white;
}
/*============================
Footer
============================== */
footer[role='contentinfo'] {
background-color: @white;
}
/*============================
Slides Index
============================== */
#webslides-zoomed {
background: @index-overlay;
}
#webslides-zoomed .column > .wrap-zoom {
background-color: @catskill-white;
box-shadow: 0 1px 1px rgba(0, 0, 0, 0.2), 0 4px 8px rgba(0, 0, 0, 0.04);
color: @mine-shaft;
&:hover {
box-shadow: 0 1px 1px rgba(0, 0, 0, 0.2), 0 4px 8px rgba(0, 0, 0, 0.08);
}
&.current {
border: 0.6rem solid rgba(0, 20, 280, 0.2);
}
}
.text-slide-number {
color: #abc;
}
================================================
FILE: packages/nodeppt-js/assets/less/_typography.less
================================================
/*============================
2. TYPOGRAPHY & LISTS
============================== */
html,
body {
line-height: 1;
text-rendering: optimizeLegibility;
}
html,
body,
input,
select,
textarea {
font-family: -apple-system, 'Noto Sans', SFMono-Regular, Consolas, Liberation Mono, Menlo, Courier, monospace,
'Helvetica Neue', Helvetica, 'Nimbus Sans L', Arial, 'Liberation Sans', 'PingFang SC', 'Hiragino Sans GB',
'Noto Sans CJK SC', 'Source Han Sans SC', 'Source Han Sans CN', 'Microsoft YaHei', 'Wenquanyi Micro Hei',
'WenQuanYi Zen Hei', 'ST Heiti', SimHei, 'WenQuanYi Zen Hei Sharp', sans-serif;
font-size: 62.5%;
}
body,
textarea {
font-size: 1.8rem;
}
p,
li,
dt,
dd,
time,
table,
big,
textarea,
label {
line-height: 3.2rem;
margin-bottom: 3.2rem;
}
li,
p:last-child {
margin-bottom: 0;
}
ul > li,
ol > li {
margin-left: 3.2rem;
}
li li {
font-size: 100%;
}
/*== List .description (Product/Specs) === */
ul.description {
padding: 0;
& + p {
margin-top: 3.2rem;
}
li {
padding-bottom: 0.8rem;
padding-top: 0.8rem;
position: relative;
transition: 0.3s;
}
li:hover {
padding-left: 0.4rem;
}
}
ul.description li,
.column ul li {
list-style: none;
margin-left: 0;
}
.column ol > li {
margin-left: 1.6rem;
}
h1 svg,
h2 svg,
h3 svg,
h4 svg {
margin-top: -0.8rem;
}
.text-intro svg,
.text-quote p svg,
.wall p svg,
.try svg {
margin-top: -0.4rem;
}
h1 {
font-size: 4rem;
line-height: 5.6rem;
@media (min-width: 768px) {
font-size: 5.6rem;
line-height: 7.2rem;
}
}
h1 span {
font-style: italic;
}
h2 {
font-size: 3.2rem;
line-height: 4.8rem;
@media (min-width: 768px) {
font-size: 4.8rem;
line-height: 6.4rem;
}
}
h3 {
font-size: 2.4rem;
line-height: 4rem;
@media (min-width: 768px) {
font-size: 4rem;
line-height: 5.6rem;
}
}
h4 {
font-size: 2.2rem;
line-height: 4rem;
@media (min-width: 768px) {
font-size: 3.2rem;
line-height: 4.8rem;
}
}
h5 {
font-size: 2rem;
font-weight: 600;
line-height: 3.2rem;
}
h6 {
font-size: 1.8rem;
font-weight: 600;
line-height: 3.2rem;
}
h2.alignleft + p.alignright {
margin-bottom: 0;
margin-top: 1.2rem;
}
h3.alignleft + p.alignright {
margin-bottom: 0;
margin-top: 0.4rem;
}
each(range(6), {
h@{value} + h1,
h@{value} + h2,
h@{value} + h3,
h@{value} + h4,
h@{value} + h5,
h@{value} + h6 {
margin-top: 0.8rem;
}
});
h1 + img,
h2 + img,
h3 + img {
margin-bottom: 4.8rem;
margin-top: 4.8rem;
}
[class*='content-'] > [class*='content-'] h2,
[class*='content-'] > [class*='content-'] h3,
[class*='content-'] > [class*='content-'] h4 {
font-size: 2.4rem;
line-height: 4rem;
}
/*== 2.1. Headings with background ==*/
each(range(6), {
h@{value}[class*='bg-'] {
padding: 2.4rem;
}
});
ul[class*='bg-'],
ol[class*='bg-'],
li[class*='bg-'],
p[class*='bg-'] {
padding: 2.4rem;
}
h1 [class*='bg-'],
h2 [class*='bg-'],
h3 [class*='bg-'] {
padding: 0.4rem 0.8rem;
}
/*== 2.2. Typography Classes = .text- == */
.text-intro,
[class*='content-'] p {
font-size: 2.4rem;
line-height: 4rem;
}
/* -- Serif -- */
.text-serif,
h1 span {
font-family: 'Maitree', times, serif;
}
/* -- h1,h2... Promo/Landings -- */
.text-landing {
letter-spacing: 0.4rem;
text-transform: uppercase;
@media (min-width: 768px) {
letter-spacing: 1.6rem;
}
}
/* -- Subtitle (Before h1, h2) p.subtitle + h1/h2 */
.text-subtitle {
letter-spacing: 0.2rem;
margin-bottom: 0;
text-transform: uppercase;
p& {
font-size: 1.6rem;
svg {
vertical-align: text-top;
}
}
+ p {
margin-top: 3.2rem;
}
}
.text-uppercase {
text-transform: uppercase;
}
.text-lowercase {
text-transform: lowercase;
}
/* -- Emoji (you'll love this) -- */
.text-emoji {
font-size: 6.8rem;
line-height: 8.8rem;
@media (min-width: 768px) {
font-size: 12.8rem;
line-height: 16rem;
}
}
/* -- Numbers (results, sales... 23,478,289 iphones) -- */
.text-data {
font-size: 6.4rem;
line-height: 8rem;
margin-bottom: 0.8rem;
@media (min-width: 768px) {
font-size: 15.2rem;
line-height: 16.8rem;
}
}
.text-label {
display: inline-block;
font-weight: 600;
text-transform: uppercase;
width: 12.8rem;
}
/* -- Magazine Two Columns -- */
@media (min-width: 768px) {
.text-cols {
column-count: 2;
column-gap: 4.8rem;
text-align: left;
}
.text-landing + .text-cols {
margin-top: 3.2rem;
}
}
.text-cols p:first-child:first-letter {
float: left;
font-size: 11rem;
font-weight: 600;
line-height: 1;
margin: -0.4rem 1.6rem 0 0;
padding: 0;
text-transform: uppercase;
}
/* -- Heading with border -- */
.text-context {
position: relative;
&:before {
content: '';
display: block;
height: 0.2rem;
margin-bottom: 0.6rem;
width: 12rem;
.column & {
width: 100%;
}
}
&.text-uppercase {
letter-spacing: 0.1rem;
}
}
/* -- Separator/Symbols (stars ***...) -- */
.text-symbols {
font-weight: 600;
letter-spacing: 0.8rem;
text-align: center;
}
.text-separator {
margin-top: 2.4rem;
&:before {
content: '';
height: 0.4rem;
left: 0;
margin-top: -1.6rem;
position: absolute;
width: 16%;
}
@media (min-width: 568px) {
margin-left: 20%;
margin-top: 0;
width: 80%;
&:before {
margin-top: 1.2rem;
}
}
}
/* -- Pull Quote (Right/Left) -- */
[class*='text-pull'] {
font-size: 2.4rem;
font-weight: 400;
line-height: 4rem;
margin-bottom: 3.2rem;
margin-left: 2.4rem;
margin-right: 2.4rem;
position: relative;
}
[class*='text-pull-'] {
margin-top: 0.8rem;
padding-top: 1.4rem;
@media (min-width: 1024px) {
margin-left: -4.8rem;
margin-right: -4.8rem;
}
}
@media (min-width: 568px) {
[class*='text-pull-'] {
max-width: 40%;
}
.text-pull-right {
float: right;
margin-left: 2.4rem;
margin-right: -2.4rem;
}
.text-pull-left {
float: left;
margin-left: -2.4rem;
margin-right: 2.4rem;
}
}
img[class*='text-pull-'],
figure[class*='text-pull-'] {
margin-top: 0.8rem;
padding-top: 0;
}
/* -- Interviews (Questions & Answers) --- */
/* -- <dl class="text-interview">
<dt>name</dt>
<dd><p>question or answer</p>
</dd>
--- */
.text-interview dt {
font-weight: 600;
margin-bottom: 0;
text-transform: uppercase;
}
@media (min-width: 1024px) {
.text-interview dt {
margin-left: -34%;
position: absolute;
text-align: right;
white-space: nowrap;
width: 30%;
}
}
/* -- Info Messages (error, warning, success... -- */
.text-info {
font-size: 1.6rem;
line-height: 2.4rem;
}
/*=========================================
2.1. San Francisco Font (Apple's new font)
=========================================== */
.text-apple,
.bg-apple {
font-family: 'San Francisco', helvetica, arial, sans-serif;
}
/* Ultra Light */
@font-face {
font-family: 'San Francisco';
font-weight: 100;
src: url('https://applesocial.s3.amazonaws.com/assets/styles/fonts/sanfrancisco/sanfranciscodisplay-ultralight-webfont.woff2');
}
/* Thin */
@font-face {
font-family: 'San Francisco';
font-weight: 200;
src: url('https://applesocial.s3.amazonaws.com/assets/styles/fonts/sanfrancisco/sanfranciscodisplay-thin-webfont.woff2');
}
/* Regular */
@font-face {
font-family: 'San Francisco';
font-weight: 400;
src: url('https://applesocial.s3.amazonaws.com/assets/styles/fonts/sanfrancisco/sanfranciscodisplay-regular-webfont.woff2');
}
/* Bold */
@font-face {
font-family: 'San Francisco';
font-weight: bold;
src: url('https://applesocial.s3.amazonaws.com/assets/styles/fonts/sanfrancisco/sanfranciscodisplay-bold-webfont.woff2');
}
================================================
FILE: packages/nodeppt-js/assets/less/_vars.less
================================================
// sass-lint:disable no-color-literals
// =========
// Colors. Names from http://chir.ag/projects/name-that-color/
// =========
@black: #000;
@white: #fff;
@mine-shaft: #333;
@royal-blue: #44d;
@havelock-blue: #67d;
@catskill-white: #f7f9fb;
@cod-gray: #111;
@big-stone: #123;
@rhino: #346;
@athens-gray: #f8f8f9;
@mischka: #d5d9e2;
@pine-green: #077;
@purple-heart: #62b;
@cardinal: #c23;
@mirage: #1a2028;
@pickled-bluewood: #293845;
@facebook: #3b5998;
@spindle: #bce;
@dodger-blue: #3af;
@pattens-blue: #def;
@stratos: #001450;
@gray-brown: #f9f8f2;
@body-color: @mine-shaft;
@body-bg: @catskill-white;
@focus-box-shadow: 0 0 2px rgba(150, 187, 238, 1);
@link-color: @royal-blue;
@link-color-secondary: @cardinal;
@link-hover: @dodger-blue;
@hr-bg: radial-gradient(ellipse at center, rgba(0, 20, 80, 0.2) 0, rgba(255, 255, 255, 0) 75%);
@current-zoomed-slide-shadow: 0 0 7px rgba(0, 187, 255, 0.5);
@index-overlay: rgba(0, 10, 40, 0.8);
================================================
FILE: packages/nodeppt-js/assets/less/full.less
================================================
/*-----------------------------------------------------------------------------------
0. CSS Reset & Normalize
1. Base
1.1 Wrap/Container
1.2 Animations
1.3 Responsive Media (videos, iframe, screenshots...)
1.4 Basic Grid (2,3,4 columns)
2. Typography & Lists
2.1 Headings with background
2.2 Classes: .text-
2.3 San Francisco Font (Apple)
3. Header & Footer
3.1 Logo
4. Navigation
4.1 Navbars
5. SLIDES (vertically and horizontally centered)
5.1 Mini container & Alignment
5.2 Counter / Navigation Slides
5.3 Background Images/Video
6. Magic blocks = .flexblock (Flexible blocks with auto-fill and equal height).
6.1 .flexblock.features
6.2 .flexblock.clients
6.3 .flexblock.steps
6.4 .flexblock.metrics
6.5 .flexblock.specs
6.6 .flexblock.reasons
6.7 .flexblock.gallery
6.8 .flexblock.plans
6.9. flexblock.activity
7. Promos/Offers (pricing, tagline, CTA...)
8. Work / Resume / CV
9. Table of contents
10. Cards
11. Quotes
12. Avatars
13. Tables
14. Forms
15. Longform Elements
16. Safari Bug (flex-wrap)
17. Slidex index (aka zoom)
18. Print
19. Colors
----------------------------------------------------------------------------------- */
@import (optional) '_vars.less';
@import (optional) 'utils/_reset.less';
@import (optional) 'utils/_clear.less';
@import (optional) '_base.less';
@import (optional) 'utils/_animations.less';
@import (optional) 'modules/_media.less';
@import (optional) 'modules/_browser.less';
@import (optional) 'modules/_grid.less';
@import (optional) '_typography.less';
@import (optional) 'modules/_header-footer.less';
// @import (optional) "modules/logo.less";
// @import (optional) 'modules/_logo.less';
@import (optional) 'modules/_navigation.less';
@import (optional) 'modules/_slides.less';
@import (optional) 'modules/_slides-bg.less';
@import (optional) 'modules/_slides-navigation.less';
@import (optional) 'modules/_flexblock.less';
@import (optional) 'modules/_flexblock-features.less';
@import (optional) 'modules/_flexblock-clients.less';
@import (optional) 'modules/_flexblock-steps.less';
@import (optional) 'modules/_flexblock-metrics.less';
@import (optional) 'modules/_flexblock-specs.less';
@import (optional) 'modules/_flexblock-reasons.less';
@import (optional) 'modules/_flexblock-gallery.less';
@import (optional) 'modules/_flexblock-plans.less';
@import (optional) 'modules/_flexblock-activity.less';
@import (optional) 'modules/_promos.less';
@import (optional) 'modules/_work.less';
@import (optional) 'modules/_toc.less';
@import (optional) 'modules/_cards.less';
@import (optional) 'modules/_quotes.less';
@import (optional) 'modules/_avatars.less';
@import (optional) 'modules/_tables.less';
@import (optional) 'modules/_form.less';
@import (optional) 'modules/_button.less';
@import (optional) "modules/_badges.less";
@import (optional) 'modules/_longform.less';
@import (optional) 'utils/_bugs.less';
@import (optional) 'modules/_zoom.less';
@import (optional) 'modules/_print.less';
// speaker mode
@import (optional) 'modules/_with-note.less';
@import (optional) '_color.less';
// speaker-note
@import (optional) 'modules/_speaker-note.less';
@import (optional) 'modules/_animation.less';
// build item
@import (optional) 'modules/_build.less';
================================================
FILE: packages/nodeppt-js/assets/less/index.less
================================================
#webslides {
opacity: 0;
}
.ws-ready #webslides {
opacity: 1;
}
i.fa {
display: inline-block;
vertical-align: middle;
width: 1em;
height: 1em;
}
[class*='fa-'].large {
font-size: 8rem;
}
.embed .echarts,
.embed .lang-mermaid {
min-height: 20vw;
> div {
margin: 0 auto;
}
}
.embed .lang-mermaid {
visibility: hidden;
text-align: center;
}
.animated.delay-300 {
animation-delay: 0.3s;
}
.animated.delay-400 {
animation-delay: 0.4s;
}
.animated.delay-500 {
animation-delay: 0.5s;
}
.animated.delay-600 {
animation-delay: 0.6s;
}
.animated.delay-700 {
animation-delay: 0.7s;
}
.animated.delay-800 {
animation-delay: 0.8s;
}
.animated.delay-900 {
animation-delay: 0.9s;
}
.animated.delay-1100 {
animation-delay: 1.1s;
}
.animated.delay-1200 {
animation-delay: 1.2s;
}
.animated.delay-1300 {
animation-delay: 1.3s;
}
.animated.delay-1400 {
animation-delay: 1.4s;
}
.animated.delay-1500 {
animation-delay: 1.5s;
}
.animated.delay-1600 {
animation-delay: 1.6s;
}
.animated.delay-1700 {
animation-delay: 1.7s;
}
.animated.delay-1800 {
animation-delay: 1.8s;
}
.animated.delay-2400 {
animation-delay: 2.4s;
}
.animated.delay-2500 {
animation-delay: 2.5s;
}
.animated.delay-2800 {
animation-delay: 2.8s;
}
.animated.delay-3200 {
animation-delay: 3.2s;
}
.animated.delay-3600 {
animation-delay: 3.6s;
}
.animated.delay-4s {
animation-delay: 4s;
}
section ul {
display: inline-block;
text-align: left;
list-style: disc;
&.no-list-style {
list-style: none;
}
& > li {
margin-bottom: 0.5em;
ul {
margin-top: 0.5em;
display: block;
}
ul > li {
list-style-type: circle;
}
}
}
.flexblock li {
a.bg-trans-light,
a.bg-red,
a.bg-green,
a.bg-blue,
a.bg-purple,
a.bg-trans-dark,
a.bg-primary,
a.bg-secondary,
a.bg-black,
a.bg-black-blue {
color: white;
}
}
.badge-ios {
background-image: url('../images/bt-appstore.png');
}
.badge-android {
background-image: url('../images/bt-playstore.png');
}
================================================
FILE: packages/nodeppt-js/assets/less/modules/_animation.less
================================================
// 翻页效果
.slide.pagedown[data-transition='slide'].past {
animation: slideOutScaleLeft 1s forwards cubic-bezier(1, 0, 0, 1);
}
.slide.pagedown[data-transition='slide'].current {
opacity: 1;
animation: slideInFromRight 1s forwards cubic-bezier(1, 0, 0, 1);
}
.slide.pageup[data-transition='slide'].current {
opacity: 1;
animation: slideInFromLeft 1s forwards cubic-bezier(1, 0, 0, 1);
}
.slide.pageup[data-transition='slide'].next {
opacity: 1;
animation: slideOutScaleRight 1s forwards cubic-bezier(1, 0, 0, 1);
}
================================================
FILE: packages/nodeppt-js/assets/less/modules/_avatars.less
================================================
/*=========================================
12. Avatars - uifaces.com
=========================================== */
cite img,
img[class*='avatar-'] {
display: inline-block;
margin-right: 6px;
vertical-align: middle;
}
img[class*='avatar-'] {
border-radius: 50%;
}
@avatar-sizes: 40, 48, 56, 64, 72, 80;
each(@avatar-sizes, {
img.avatar-@{value} {
@width: @{value}px;
height: @width;
width: @width;
}
});
================================================
FILE: packages/nodeppt-js/assets/less/modules/_badges.less
================================================
/*=== App Store Badges === */
/* Change width and height: 216x64px, 162x48px, 135x40... */
[class*='badge-'] {
background-repeat: no-repeat;
background-size: cover;
border-radius: 0.6rem;
display: inline-block;
height: 40px;
line-height: 4rem;
text-indent: -4000px;
width: 135px;
&:hover {
opacity: 0.7;
}
@media (min-width: 1024px) {
height: 48px;
line-height: 4.8rem;
width: 162px;
}
@media (min-width: 500px) {
& + & {
margin-left: 1.8rem;
}
}
@media (max-width: 499px) {
& + & {
margin-top: 0.8rem;
}
}
}
================================================
FILE: packages/nodeppt-js/assets/less/modules/_browser.less
================================================
/*=== HTML Browser (Screenshots) ================ */
/* <figure class="browser"> img </figure> */
.browser {
border-radius: 0.3rem;
margin: 0 auto 3.2rem;
max-width: 1024px;
overflow: hidden;
li & {
margin-bottom: 0;
}
h1 + &,
h2 + &,
p + & {
margin-top: 4.8rem;
}
figcaption {
padding: 2.4rem;
}
&:before {
content: '● ● ●';
font-size: 0.8rem;
left: 0;
line-height: 0;
padding: 1.6rem;
position: absolute;
text-align: left;
top: 0;
width: 100%;
@media (min-width: 768px) {
font-size: 1.6rem;
}
}
}
================================================
FILE: packages/nodeppt-js/assets/less/modules/_build.less
================================================
/* Builds */
.build.fadeIn {
> * {
transition: opacity 0.5s ease-in-out 0.2s;
}
.tobuild {
opacity: 0;
}
}
.zoomIn > * {
animation: none;
}
.zoomIn {
> * {
opacity: 1;
}
.tobuild {
opacity: 0;
}
.animated {
opacity: 1;
animation-duration: 0.75s;
animation-fill-mode: both;
}
}
.zoomIn {
.animated {
animation-name: zoomIn;
}
}
.moveIn {
> * {
transition: all 0.5s ease-in-out 0.2s;
}
.tobuild {
opacity: 0;
transform: translate3d(60px, 0, 0);
}
}
.rollIn {
> * {
transition: all 0.4s ease;
}
.animated {
opacity: 1;
visibility: visible;
transform: rotateX(0);
}
.tobuild {
opacity: 0;
visibility: hidden;
transform: rotateX(90deg);
}
}
section .build,
section .tobuild {
animation: none;
}
section .tobuild {
opacity: 0;
}
================================================
FILE: packages/nodeppt-js/assets/less/modules/_button.less
================================================
/* Buttons/Badges */
[class*='button'] {
@media (min-width: 500px) {
& + & {
margin-left: 1.8rem;
}
}
@media (max-width: 499px) {
& + & {
margin-top: 0.8rem;
}
}
}
================================================
FILE: packages/nodeppt-js/assets/less/modules/_cards.less
================================================
/*===========================================
10. Cards
============================================= */
[class*='card-'] {
&,
& > a {
clear: both;
display: flex;
flex-direction: row;
position: relative;
}
.fullscreen &,
.fullscreen & > a {
min-height: 100vh;
}
figure img,
figure iframe {
display: block;
margin: 0 auto;
}
figure figcaption {
bottom: 0;
font-size: 1.4rem;
left: 0;
line-height: 2.4rem;
padding: 0.8rem 2.4rem;
position: absolute;
z-index: 2;
svg {
font-size: 1rem;
}
}
}
@media (min-width: 768px) {
[class*='card'][class*='bg-'] figure,
.fullscreen [class*='card'] figure {
max-height: 100%;
min-width: 380px;
text-align: center;
vertical-align: middle;
}
[class*='card-'][class*='bg-'] figure img,
[class*='card-'][class*='bg-'] figure iframe,
.fullscreen [class*='card-'] figure img,
.fullscreen [class*='card-'] figure iframe {
height: 100%;
left: 0;
object-fit: cover;
position: absolute;
top: 0;
width: 100%;
z-index: 1;
}
}
.flex-content,
[class*='card'] blockquote {
padding: 2.4rem;
position: relative;
}
[class*='card-'] .flex-content,
[class*='card-'] blockquote {
display: flex;
flex-direction: column;
justify-content: center;
}
.flex-content p {
position: relative;
}
@media (min-width: 768px) {
.card-50 figure,
.card-50 blockquote,
.card-50 .flex-content {
width: 50%;
}
.card-30 figure,
.card-70 .flex-content,
.card-70 blockquote {
width: 30%;
}
.card-40 figure,
.card-60 .flex-content,
.card-60 blockquote {
width: 40%;
}
.card-60 figure,
.card-40 .flex-content,
.card-40 blockquote {
width: 60%;
}
.card-70 figure,
.card-30 .flex-content,
.card-30 blockquote {
width: 70%;
}
[class*='card']:nth-child(odd) figure {
order: 0;
}
[class*='card']:nth-child(even) figure {
order: 1;
}
.flex-content,
[class*='card'] blockquote {
padding: 4.8rem;
}
.fullscreen [class*='card'] .flex-content,
.fullscreen [class*='card'] blockquote {
padding: 6.4rem;
}
}
@media (max-width: 767px) {
[class*='card-'],
[class*='card-'] > a {
flex-flow: column;
}
.card figure,
.card header {
width: 100%;
}
}
================================================
FILE: packages/nodeppt-js/assets/less/modules/_flexblock-activity.less
================================================
/*===========================================
6.9 Block Activity <ul class="activity">
CV / News
============================================= */
.flexblock.activity {
flex-direction: column;
li {
flex: 1;
position: relative;
width: auto;
}
p {
margin-bottom: 0;
vertical-align: top;
}
img {
display: block;
}
.year,
.title {
display: inline;
font-weight: 600;
}
.summary {
width: 100%;
}
.title {
margin-left: 1rem;
}
@media (min-width: 768px) {
p {
float: left;
}
.year {
width: 15%;
}
.title {
margin-left: 4%;
margin-right: 4%;
width: 27%;
}
.summary {
width: 50%;
}
}
}
================================================
FILE: packages/nodeppt-js/assets/less/modules/_flexblock-clients.less
================================================
/*=====================================================================
6.2 Clients Logos <ul class="flexblock clients">
======================================================================= */
.flexblock.clients.blink li > a,
.flexblock.clients li {
padding: 0;
}
.flexblock.clients li figcaption {
padding: 0 2.4rem 2.4rem;
}
.flexblock.clients.border li figcaption {
padding-top: 2.4rem;
}
.clients.blink li > a,
.clients li {
justify-content: inherit;
}
.clients li img,
.clients li svg {
display: block;
padding: 2.4rem;
}
.clients.border li img,
.clients.border li svg {
display: block;
margin-left: auto;
margin-right: auto;
}
.clients li:hover {
z-index: 1;
}
================================================
FILE: packages/nodeppt-js/assets/less/modules/_flexblock-features.less
================================================
/*====================================================================
6.1 Features <ul class="flexblock features">
====================================================================== */
.flexblock.features {
> li {
border-radius: 0.4rem;
margin-bottom: 4.8rem;
width: 100%;
}
li h2 {
text-transform: uppercase;
}
li span {
font-weight: 300;
}
li p {
margin: 0;
}
li p em {
display: block;
}
li span,
li svg,
li i.fa {
display: block;
font-size: 6.4rem;
line-height: 1;
margin: 0;
}
li img {
width: 6.4rem;
}
li span sup {
font-size: 3rem;
}
@media (min-width: 1200px) {
li span,
li svg,
li i.fa,
li img {
float: left;
margin-right: 0.8rem;
}
li i.fa {
margin-right: 1.8rem;
}
}
}
@media (min-width: 768px) {
.flexblock.features {
margin-left: -2%;
margin-right: -2%;
}
.flexblock.features > li {
margin-left: 2%;
margin-right: 2%;
width: 29%;
}
.size-50 .flexblock.features > li {
width: 46%;
}
.column .flexblock.features > li {
width: 100%;
}
footer .flexblock.features > li {
margin-bottom: 0;
}
}
================================================
FILE: packages/nodeppt-js/assets/less/modules/_flexblock-gallery.less
================================================
/*=================================================
6.7 Gallery - <ul class="flexblock gallery">
Block Thumbnails li+.overlay+image
img size recommended:800x600px
=================================================== */
.flexblock.gallery {
li {
margin-bottom: 4.8rem;
&:nth-child(n + 4) {
flex: inherit;
}
figcaption {
padding: 1.6rem;
position: relative;
&:before {
content: '';
height: 0;
left: 20%;
margin-left: -0.5em;
position: absolute;
top: 0.4rem;
transform: rotate(135deg);
transform-origin: 0 0;
transition: 0.1s;
width: 0;
}
}
&:hover figcaption:before {
top: 0.3rem;
}
}
.aligncenter & li figcaption:before {
left: 55%;
margin-left: 0;
}
li,
&.blink li > a {
padding: 0;
}
h2 {
text-transform: uppercase;
}
h2 + p,
h3 + p {
margin-top: 0.8rem;
}
p {
font-size: 1.6rem;
line-height: 2.4rem;
margin-bottom: 0;
}
li footer {
margin-top: 0.8rem;
padding: 1.2rem 0 0;
position: relative;
}
li img {
display: block;
margin-left: auto;
margin-right: auto;
}
@media (min-width: 600px) {
margin-left: -2%;
margin-right: -2%;
li {
margin-left: 2%;
margin-right: 2%;
width: 46%;
}
}
}
@media (min-width: 1024px) {
.flexblock.gallery li {
width: 21%;
}
.grid.sm .flexblock.gallery li,
.grid.ms .flexblock.gallery li {
width: 29%;
}
.grid.sms .flexblock.gallery li {
width: 46%;
}
}
.overlay {
bottom: 0;
cursor: pointer;
display: flex;
flex-direction: column;
height: 100%;
justify-content: center;
left: 0;
opacity: 1;
position: absolute;
right: 0;
top: 0;
transition: all 0.3s linear;
width: 100%;
z-index: 2;
}
li .overlay {
align-items: center;
}
li .overlay h2 {
letter-spacing: 0.2rem;
margin: 0;
padding: 0 2.4rem;
text-align: center;
text-transform: uppercase;
width: 100%;
}
.overlay p,
.overlay time {
margin-bottom: 0;
}
li:hover .overlay {
cursor: pointer;
}
================================================
FILE: packages/nodeppt-js/assets/less/modules/_flexblock-metrics.less
================================================
/*=================================================
6.4 Block Numbers - <ul class="flexblock metrics">
=================================================== */
.metrics li {
text-align: center;
width: 100%;
@media (min-width: 568px) {
width: 50%;
}
@media (min-width: 1024px) {
width: 25%;
}
}
.metrics li strong {
display: block;
}
.metrics li span,
.metrics li i,
.metrics li svg {
display: block;
font-size: 6.4rem;
line-height: 7.2rem;
margin: 0 auto;
}
.card-50 .metrics li {
width: 50%;
}
================================================
FILE: packages/nodeppt-js/assets/less/modules/_flexblock-plans.less
================================================
/*===============================================
6.8 Plans / Pricing <ul class="flexblock plans">
================================================= */
.flexblock.plans {
> li {
border-radius: 3px;
margin-bottom: 4.8rem;
text-align: center;
z-index: 1;
}
li,
&.blink li > a {
padding: 0;
}
&.blink li > a div,
li div {
padding-bottom: 3.2rem;
}
li p,
li h2 {
padding: 0.8rem 3.2rem;
}
li h2 {
float: left;
font-weight: 400;
letter-spacing: 0.1rem;
text-transform: uppercase;
width: 100%;
}
.price {
clear: both;
display: block;
font-size: 4.8rem;
font-weight: 400;
line-height: 6.2rem;
padding: 2.4rem;
sup {
font-size: 1.8rem;
margin-right: 0.4rem;
}
li ul {
margin-bottom: 2.4rem;
}
}
li ul li {
display: block;
padding: 0.8rem 3.2rem;
text-align: left;
width: 100%;
}
@media (min-width: 1024px) {
margin-left: -2%;
margin-right: -2%;
> li {
margin-left: 2%;
margin-right: 2%;
width: 29%;
}
> li:hover,
> li:nth-child(2) {
position: relative;
transform: scale(1.08);
z-index: 2;
}
&:hover li:nth-child(2):not(:hover) {
position: relative;
transform: scale(1);
z-index: 1;
}
}
}
================================================
FILE: packages/nodeppt-js/assets/less/modules/_flexblock-reasons.less
================================================
/*=================================================
6.6 Reasons/Why/Numbers (counter-increment)
<ul class="flexblock reasons">
=================================================== */
.flexblock.reasons {
li {
counter-increment: list;
text-align: left;
width: 100%;
&:hover {
transform: translateY(-0.2rem);
}
&:after {
bottom: -2.4rem;
content: '';
display: block;
height: 1px;
position: relative;
}
&:before {
content: counter(list) '.';
font-size: 6.4rem;
line-height: 1;
}
@media (min-width: 768px) {
padding-left: 8.8rem;
/* You need two digits? (1-10)*/
/*padding-left: 12rem; */
&:before {
left: 2.4rem;
position: absolute;
}
}
}
}
================================================
FILE: packages/nodeppt-js/assets/less/modules/_flexblock-specs.less
================================================
/*=====================================================
6.5 Specs/Items: <ul class="flexblock specs">
======================================================= */
.specs li {
text-align: left;
width: 100%;
&:after {
bottom: -2.4rem;
content: '';
display: block;
height: 1px;
position: relative;
}
&:hover {
transform: translateX(0.2rem);
}
span,
i,
svg {
display: block;
font-size: 6.4rem;
line-height: 1;
margin: 0;
}
img {
width: 6.4rem;
}
span {
font-weight: 300;
sup {
font-size: 3rem;
}
}
@media (min-width: 1024px) {
span,
svg,
i,
img {
float: left;
margin-right: 2.4rem;
}
}
}
================================================
FILE: packages/nodeppt-js/assets/less/modules/_flexblock-steps.less
================================================
/*==================================================
6.3 flexblock.steps <ul class="flexblock steps">
About, Philosophy...
=================================================== */
.steps li {
width: 100%;
img,
span {
display: block;
margin: 0 auto 0.8rem;
}
span {
font-size: 6.4rem;
}
@media (min-width: 768px) {
width: 50%;
}
}
@media (min-width: 1024px) {
.steps li {
width: 25%;
}
.process {
border-left-style: solid;
border-left-width: 15px;
height: 0;
left: 0;
position: absolute;
top: 60px;
width: 0;
}
}
================================================
FILE: packages/nodeppt-js/assets/less/modules/_flexblock.less
================================================
/*===============================================================
6. Magic blocks with flexbox (Auto-fill & Equal Height)
Blocks Links li>a = .flexblock.blink (.blink required)
================================================================= */
.flexblock {
clear: both;
display: flex;
flex-wrap: wrap;
margin-left: auto;
margin-right: auto;
padding: 0;
&:after {
clear: both;
}
&:before {
content: '';
display: table;
}
li,
&.blink li > a {
display: flex;
flex-direction: column;
margin: 0;
padding: 2.4rem;
position: relative;
}
li {
flex: auto;
text-align: left;
transition: 0.3s;
width: 100%;
&:hover {
transform: translateY(-0.2rem);
}
@media (min-width: 600px) {
width: 50%;
}
@media (min-width: 1024px) {
width: 25%;
}
}
&.aligncenter li {
text-align: center;
}
&.vertical-align li {
justify-content: center;
}
&.blink li {
padding: 0;
}
li h2 svg,
li h2 i,
li h3 i,
li h3 svg {
margin-top: 0;
}
}
h1 + .flexblock,
h2 + .flexblock,
h3 + .flexblock,
div + ul,
div + ol {
margin-top: 3.2rem;
}
.flexblock li h2,
.flexblock li h3,
footer .column h2,
footer .column h3 {
font-size: 1.8rem;
font-weight: 600;
line-height: 3.2rem;
margin-bottom: 0;
}
.flexblock li li,
.flexblock.blink li li {
padding: 0;
width: 100%;
}
[class*='content-'] .flexblock li p {
font-size: 1.8rem;
line-height: 3.2rem;
}
.content-right .flexblock.features li,
.content-left .flexblock.features li {
width: 46%;
}
================================================
FILE: packages/nodeppt-js/assets/less/modules/_form.less
================================================
/*=========================================
14. Forms
=========================================== */
form {
text-align: left;
& + p,
input + p,
textarea + p {
margin-top: 0.8rem;
}
}
input[type='text'],
input[type='email'],
input[type='tel'],
input[type='url'],
input[type='search'],
input[type='password'] {
appearance: none;
border-radius: 0;
}
input,
button,
select {
display: inline-block;
font-size: 1.6rem;
font-weight: 400;
height: 4.8rem;
margin: 0;
padding: 0.7rem;
position: relative;
width: 100%;
}
input[type='radio'],
input[type='checkbox'] {
height: auto;
padding: 4px;
width: auto;
}
button[type='submit'],
textarea {
width: 100%;
}
textarea {
padding: 0.7rem;
}
button {
cursor: pointer;
text-align: center;
width: auto;
}
.button {
cursor: pointer;
display: inline-block;
font-size: 1.8rem;
font-weight: 400;
line-height: 4.8rem;
min-width: 16rem;
padding: 0 1.6rem;
text-align: center;
svg {
font-size: 2.4rem;
}
}
.button.radius,
input.radius {
border-radius: 2.4rem;
}
button,
input[type='submit'] {
font-weight: 400;
letter-spacing: 0.1rem;
text-transform: uppercase;
}
.plans .button {
margin-left: auto;
margin-right: auto;
width: 50%;
}
.try {
display: block;
font-size: 1.6rem;
margin-top: 1.6rem;
}
fieldset {
padding: 2.4rem;
}
legend {
border: 0;
font-weight: 400;
letter-spacing: 0.1rem;
padding: 1.6rem 2.4rem;
text-align: center;
text-transform: uppercase;
width: 100%;
}
input:focus,
textarea:focus,
select:focus {
border-width: 1px;
}
a.button:hover,
button[type='submit']:hover,
input[type='submit']:hover {
transform: scale(1.01);
}
:disabled,
button:disabled:hover {
cursor: not-allowed;
}
.user {
input {
margin-bottom: 0;
&[type='email'],
&[type='search'],
&[type='text'] {
width: 100%;
@media (min-width: 500px) {
float: left;
width: 70%;
}
}
}
button,
input[type='submit'] {
left: 0;
width: 100%;
@media (min-width: 500px) {
cursor: pointer;
width: 30%;
}
}
}
================================================
FILE: packages/nodeppt-js/assets/less/modules/_grid.less
================================================
/*=== 1.4. Basic Grid (Flexible blocks)
Auto-fill & Equal height === */
.grid {
clear: both;
display: flex;
flex-wrap: wrap;
margin-left: auto;
margin-right: auto;
&:after {
clear: both;
}
&:before {
content: '';
display: table;
}
& > .column {
display: flex;
flex: auto;
flex-direction: column;
padding: 2.4rem;
position: relative;
transition: 0.3s;
width: 100%;
}
&.vertical-align .column {
justify-content: center;
}
@media (min-width: 768px) {
& > .column {
width: 25%;
}
&.sm .column:nth-child(1) {
width: 30%;
}
&.sm .column:nth-child(2) {
width: 70%;
}
&.ms .column:nth-child(1) {
width: 70%;
}
&.ms .column:nth-child(2) {
width: 30%;
}
&.sms .column:nth-child(2) {
width: 50%;
}
}
}
================================================
FILE: packages/nodeppt-js/assets/less/modules/_header-footer.less
================================================
/*=========================================
3. Header & Footer
=========================================== */
/* -- If you want an unique, global header/footer,read this:
https://github.com/webslides/webslides/issues/57 -- */
header,
footer,
#navigation {
padding: 2.4rem;
transition: all 0.4s ease-in-out;
width: 100%;
}
header p,
footer p {
line-height: 4.8rem;
margin-bottom: 0;
}
header[role='banner'] img,
footer img {
height: 4rem;
vertical-align: middle;
}
footer {
position: relative;
}
header,
footer {
z-index: 3;
}
header,
.ws-ready footer {
left: 0;
position: absolute;
top: 0;
}
.ws-ready footer {
bottom: 0;
top: auto;
}
// Remove "opacity=0" if you want an unique, visible header on each slide
header[role='banner'] {
opacity: 0;
&:hover {
opacity: 1;
}
}
@media (max-width: 767px) {
footer .alignleft,
footer .alignright {
display: block;
float: none;
}
}
================================================
FILE: packages/nodeppt-js/assets/less/modules/_logo.less
================================================
/*=== 3.1. Logo === */
.logo {
text-transform: lowercase;
a {
background: url('../../images/logos/logo.svg') no-repeat 0 0;
background-size: 4.8rem;
float: left;
height: 4.8rem;
text-indent: -4000px;
/*If you remove text-indent and add: */
/*padding-left: 6rem;*/
vertical-align: middle;
width: 4.8rem;
}
}
================================================
FILE: packages/nodeppt-js/assets/less/modules/_longform.less
================================================
/*=========================================
15. Longform
=========================================== */
/* -- Posts = .wrap.longform -- */
.longform {
width: 72rem;
/* Why 72rem=720px?
90-95 characters per line = better reading speed */
& .alignleft,
& .alignright {
max-width: 40%;
}
img.aligncenter,
figure.aligncenter {
margin-bottom: 3.2rem;
margin-top: 3.2rem;
}
ul,
ol {
margin-bottom: 3.2rem;
}
ul ol,
ol ul,
ul ul,
ol ol {
margin-bottom: 0;
}
figcaption p,
[class*='text-pull-'] p {
font-size: 1.6rem;
line-height: 2.4rem;
}
/* Mobile: video full width */
.text-pull.embed {
margin-left: -2.4rem;
margin-right: -2.4rem;
padding-bottom: 60.6%;
}
@media (min-width: 1280px) {
[class*='text-pull-'] {
max-width: 32%;
}
.text-pull-right {
margin-right: -256px;
}
.text-pull-left {
margin-left: -256px;
}
}
@media (min-width: 1024px) {
.text-quote {
margin-left: -4.8rem;
margin-right: -4.8rem;
}
}
}
================================================
FILE: packages/nodeppt-js/assets/less/modules/_media.less
================================================
/*=== 1.3 Responsive Media (videos, iframe...) === */
.embed {
height: 0;
overflow: hidden;
/*aspect ratio:16:9*/
padding-bottom: 56.6%;
/*aspect ratio: 4:3*/
/*padding-bottom: 75%;*/
position: relative;
iframe,
object,
embed,
.echarts,
video {
height: 100%;
left: 0;
margin: 0;
position: absolute;
top: 0;
width: 100%;
}
/* -- Responsive background video
https://fvsch.com/code/video-background/ -- */
.fullscreen > & {
bottom: 0;
height: auto;
left: 0;
padding-bottom: 0;
position: fixed;
right: 0;
top: 0;
/* 1. No object-fit support: */
& > iframe,
& > object,
& > .echarts,
& > .lang-mermaid,
& > embed,
& > video {
@media (min-aspect-ratio: 16 / 9) {
height: 300%;
top: -100%;
}
@media (max-aspect-ratio: 16 / 9) {
left: -100%;
width: 300%;
}
/* 2. If supporting object-fit, overriding (1): */
@supports (object-fit: cover) {
height: 100%;
left: 0;
object-fit: cover;
top: 0;
width: 100%;
}
}
}
}
================================================
FILE: packages/nodeppt-js/assets/less/modules/_navigation.less
================================================
/*=========================================
4. Navigation
=========================================== */
/*=== 4.1. Navbars === */
nav ul {
display: flex;
flex-wrap: wrap;
/*====align left====*/
justify-content: flex-start;
/* ==== align center ====*/
/*justify-content: center; */
/*====align right====*/
/* justify-content: flex-end; */
/*====separated columns li a====*/
/* justify-content: space-between; */
/*====separated columns centered li a====*/
/*justify-content: space-around;*/
li {
float: left;
list-style: none;
position: relative;
}
}
nav ul li:first-child,
nav[role='navigation'] ul li {
margin-left: 0;
}
nav[role='navigation'] li a {
display: flex;
justify-content: center;
line-height: 4.8rem;
max-width: 100%;
padding: 0 1.6rem;
position: relative;
text-decoration: none;
svg {
margin: 1.5rem 0.4rem 1.5rem 0;
}
}
header nav ul {
justify-content: flex-end;
margin: 0;
}
nav.aligncenter ul,
.aligncenter nav ul {
/* ==== align center ====*/
justify-content: center;
}
nav.navbar ul li {
/*====full float li a ====*/
flex: 1 1 auto;
}
@media (max-width: 568px) {
nav.navbar ul {
flex-flow: column wrap;
padding: 0;
}
nav.navbar li a {
justify-content: flex-start;
}
}
================================================
FILE: packages/nodeppt-js/assets/less/modules/_print.less
================================================
/*=========================================
17. PRINT
=========================================== */
// sass-lint:disable no-important
@media print {
@page {
margin: 0.5cm;
size: A4 landscape;
}
// Black prints faster
* {
// background: transparent !important;
// color: @black !important;
// filter: none !important;
// text-shadow: none !important;
}
html,
body,
#webslides {
height: auto !important;
overflow: auto !important;
width: auto !important;
}
#webslides {
overflow-x: auto !important;
overflow-y: auto !important;
}
section,
.slide {
display: flex !important;
height: auto !important;
}
section * {
animation: none;
}
table,
figure {
page-break-inside: avoid;
}
#counter,
#navigation {
display: none;
}
.build .tobuild {
opacity: 1 !important;
visibility: visible !important;
}
}
================================================
FILE: packages/nodeppt-js/assets/less/modules/_promos.less
================================================
/*=============================================
7. Promos/Offers (pricing, tagline, CTA...)
=============================================== */
.cta {
display: flex;
flex-wrap: wrap;
justify-content: center;
.number,
.benefit {
display: flex;
flex-direction: column;
justify-content: center;
max-width: 100%;
padding: 0.8rem;
}
.number {
text-align: center;
}
.benefit {
max-width: 100%;
text-align: center;
}
.number span {
display: block;
font-size: 8rem;
line-height: 8rem;
}
.number span sup {
font-size: 4rem;
}
p {
margin-bottom: 0;
}
}
@media (min-width: 768px) {
.cta .number,
.cta .benefit {
max-width: 50%;
padding: 4.8rem;
}
.cta .benefit {
text-align: left;
}
.cta .number span {
font-size: 16rem;
line-height: 16rem;
sup {
font-size: 6rem;
vertical-align: middle;
}
}
}
/* --- Header CTA --- */
.cta-cover {
display: table;
width: 100%;
h1 strong {
font-weight: 400;
}
@media (min-width: 1024px) {
h1 {
float: left;
max-width: 80%;
}
h1 strong {
display: block;
}
.button {
margin-top: 1.2rem;
}
.try {
text-align: center;
}
}
@media (max-width: 1023px) {
.alignright {
float: none;
}
}
}
================================================
FILE: packages/nodeppt-js/assets/less/modules/_quotes.less
================================================
/*=========================================
11. Quotes
=========================================== */
blockquote {
display: inline-block;
position: relative;
p {
font-size: 2.4rem;
line-height: 4rem;
&:last-child {
margin-bottom: 3.2rem;
}
}
}
/* -- Interviews dl.text-interview -- */
dd blockquote p:last-child {
margin-bottom: 0;
}
cite {
display: block;
text-align: center;
&:before {
content: '\2014 \2009';
margin-right: 6px;
}
}
cite span {
display: block;
}
/* -- A big Blockquote -- */
/* .wall will be deprecated soon. Use .text-quote ;) */
.text-quote,
.wall {
/* Versatility: blockquote, p, h2... */
position: relative;
&:before {
content: '\201C';
font-family: arial, sans-serif;
font-size: 12rem;
height: 5.6rem;
left: -0.8rem;
line-height: 1;
position: absolute;
text-align: center;
top: -4rem;
width: 5.6rem;
}
@media (min-width: 768px) {
padding-left: 6.4rem;
p {
font-size: 3.2rem;
line-height: 4.8rem;
}
&:before {
left: 0.8rem;
top: -1.6rem;
}
}
}
================================================
FILE: packages/nodeppt-js/assets/less/modules/_slides-bg.less
================================================
/*=== 5.3 Slides - Background Images/Videos === */
.background,
[class*='background-'] {
background-repeat: no-repeat;
bottom: 0;
left: 0;
position: absolute;
right: 0;
top: 0;
}
/*=== BG Positions === */
.background {
background-position: center;
background-size: cover;
&-top {
background-position: top;
background-size: cover;
}
&-bottom {
background-position: bottom;
background-size: cover;
}
&-center {
background-position: center;
}
&-center-top {
background-position: center top;
}
&-right-top {
background-position: right top;
}
&-left-top {
background-position: left top;
}
&-center-bottom,
&-left-bottom,
&-right-bottom,
&-left,
&-right {
background-position: center bottom;
}
@media (min-width: 1024px) {
&-left-bottom {
background-position: left bottom;
}
&-right-bottom {
background-position: right bottom;
}
&-right {
background-position: right;
}
&-left {
background-position: left;
}
}
/*fullscreen video
<video class="background-video">
*/
&-video {
height: 100%;
object-fit: fill;
width: 100%;
}
}
/*=== bg image/video overlay === */
/*-- [class*="bg-"] .background.dark, [class*="bg-"] .embed.dark... -- */
[class*='bg-'] .light,
[class*='bg-'] .light {
opacity: 0.8;
}
[class*='bg-'] .dark,
[class*='bg-'] .dark {
opacity: 0.2;
}
[class*='bg-'] .background-video.dark {
opacity: 0.5;
}
@media (max-width: 1023px) {
[class*='background-'] {
animation: fadeIn ease-in 0.2;
opacity: 0.2;
}
.background-video {
opacity: 0.8;
}
}
/*=== Animated Background Image === */
.background.anim {
animation: anim 80s linear infinite;
background-position: center top;
background-repeat: repeat;
background-size: 100%;
height: 200%;
}
/*=== Background with a frame === */
/*<span class="background" style="background-image:url('image.jpg')"></span>
<span class="background frame"></span>*/
[class*='background'].frame {
margin: 2.4rem;
}
================================================
FILE: packages/nodeppt-js/assets/less/modules/_slides-navigation.less
================================================
/* === 5.2 Counter / Navigation Slides === */
#navigation {
animation: fadeIn 8s;
bottom: 0;
left: 0;
margin-left: auto;
margin-right: auto;
opacity: 0;
position: fixed;
right: 0;
width: 24.4rem;
/* hover/visibility */
z-index: 4;
&:hover {
opacity: 1;
}
p {
margin-bottom: 0;
}
}
#counter {
display: block;
line-height: 4.8rem;
margin-left: auto;
margin-right: auto;
position: relative;
text-align: center;
width: 10rem;
a:hover {
padding: 0.8rem;
}
}
a#next,
a#previous {
border-radius: 0.4rem;
cursor: pointer;
font-size: 2.4rem;
height: 4rem;
padding: 0.8rem;
position: absolute;
text-align: center;
width: 4rem;
}
a#next {
right: 3.2rem;
}
a#previous {
left: 3.2rem;
}
@media (max-width: 1024px) {
#navigation {
animation: fadeIn 6s;
background: url('../../images/swipe.svg') no-repeat center top;
background-size: 4.8rem;
}
#navigation a,
#counter {
display: none;
}
}
================================================
FILE: packages/nodeppt-js/assets/less/modules/_slides.less
================================================
/*============================================
5. SLIDES (Full Screen)
Vertically and horizontally centered
============================================== */
/* Fade transition to all slides.
* = All HTML elements will have those styles.*/
section * {
animation: fadeIn 0.6s ease-in-out;
}
section .background,
section .light,
section .dark {
animation-duration: 0s;
}
/*=== Section = Slide === */
section,
.slide {
display: flex;
flex-direction: column;
justify-content: center;
min-height: 100vh;
/*Fullscreen*/
/* Prototyping? min-height: 720px (Baseline: 8px = .8rem)*/
padding: 2.4rem;
/*Fixed/Visible header? padding-top: 12rem; */
page-break-after: always;
position: relative;
word-wrap: break-word;
@media (min-width: 1024px) {
padding-bottom: 12rem;
padding-top: 12rem;
}
}
/*slide with no padding (full card, .embed youtube video...) */
.fullscreen {
padding: 0;
/* Fixed/Visible header?
padding:8.2rem 0 0 0;
*/
.wrap {
@media (min-width: 1024px) {
width: 100%;
}
}
}
/* slide alignment - top */
.slide-top {
justify-content: flex-start;
}
/* slide alignment - bottom */
.slide-bottom {
justify-content: flex-end;
}
/*== 5.1. Mini container width:50%
Aligned items [class*="content-"]=== */
[class*='content-'] {
position: relative;
text-align: left;
}
.wrap[class*='bg-'],
.wrap.frame,
[class*='content-'][class*='bg-'],
[class*='content-'].frame,
[class*='align'][class*='bg-'] {
padding: 4.8rem;
}
form[class*='bg-'] {
padding: 2.4rem;
}
[class*='content-'] > [class*='content-'] p {
font-size: 1.8rem;
line-height: 3.2rem;
}
.content-center {
margin: 0 auto;
text-align: center;
}
@media (min-width: 768px) {
[class*='content-'] {
width: 50%;
&:after,
&:before {
content: '';
display: table;
}
&:after {
clear: both;
}
}
.content-left {
float: left;
}
.content-right {
float: right;
}
[class*='content-'] + [class*='content-'] {
margin-bottom: 4.8rem;
padding-left: 2.4rem;
}
[class*='content-'] + [class*='size-'] {
clear: both;
margin-top: 6.4rem;
}
}
================================================
FILE: packages/nodeppt-js/assets/less/modules/_speaker-note.less
================================================
section .speaker-note {
animation: none;
display: none;
position: absolute;
width: 100%;
height: 100%;
top: 0;
left: 0;
padding: 1em;
background: rgba(0, 0, 0, 0.3);
opacity: 1;
z-index: 99999;
flex-flow: row;
justify-content: center;
box-sizing: border-box;
transition: all 0.4s ease-in-out;
> .wrap {
padding: 2em;
text-align: left; // .display-flex;
background: #fff;
}
&.show {
display: flex;
animation-duration: 0.8s;
animation-fill-mode: both;
animation-name: slideInUp;
}
}
================================================
FILE: packages/nodeppt-js/assets/less/modules/_tables.less
================================================
/*=========================================
13. Tables
=========================================== */
table {
margin-bottom: 3.2rem;
margin-top: 3.2rem;
}
td,
th,
thead {
border-spacing: 0;
padding: 0.7rem 2.4rem;
}
table.text-hight {
td,
th,
thead {
border-spacing: 0;
padding: 1.7rem 2.4rem;
}
}
thead th,
th {
cursor: default;
font-weight: 600;
text-align: left;
text-transform: uppercase;
white-space: nowrap;
}
thead,
td.goals {
font-weight: 600;
text-shadow: none;
}
tr > td {
font-weight: 400;
}
================================================
FILE: packages/nodeppt-js/assets/less/modules/_toc.less
================================================
/*===========================================
9. Table of contents
============================================= */
.toc,
.toc ol > li:before,
.chapter {
position: relative;
z-index: 2;
}
.toc {
ol {
counter-reset: item;
position: relative;
& > li:before {
content: counters(item, '.') '. ';
display: table-cell;
padding-right: 0.8rem;
width: 2.4rem;
}
li li:before {
content: counters(item, '.') ' ';
}
}
li {
counter-increment: item;
display: table;
font-weight: 400;
margin-bottom: 0.8rem;
margin-left: 0;
transition: 0.3s;
width: 100%;
li {
font-weight: 300;
margin-bottom: 0;
margin-left: 0;
}
.toc-page:before {
content: '';
display: block;
left: 0;
margin-top: 1.8rem;
position: absolute;
right: 4rem;
}
& > a {
display: inline-block;
width: 100%;
}
a:hover span {
font-weight: 600;
}
a:hover .toc-page:before {
border-bottom-width: 2px;
}
}
}
.chapter {
display: inline-block;
font-size: 1.8rem;
line-height: 3.2rem;
padding-right: 0.8rem;
}
.toc-page {
float: right;
}
================================================
FILE: packages/nodeppt-js/assets/less/modules/_with-note.less
================================================
.with-note {
background: rgba(0, 0, 0, 0.3);
.slide.current,
.slide {
&:not([class*='bg-']) {
background: #f7f9fb;
}
width: 100vw !important;
overflow: visible;
transition: none !important;
transform-origin: 0 0 !important;
transform: scale(0.6) translate3d(0.5vw, 0.5vw, 0);
.speaker-note {
display: flex;
width: 100vw;
height: 38vh;
padding: 0;
background: transparent;
transform: translate3d(35vw, 115vh, 0) scale(1.5);
transition: none;
> .wrap {
padding: 1em;
overflow-y: auto;
}
&.hide,
&.show {
animation: none;
}
}
}
.slide.current + .slide {
position: absolute;
top: 0;
left: 0;
transform: translate3d(64vw, 13vh, 0) scale(0.35);
opacity: 1 !important;
display: flex !important;
.speaker-note {
display: none !important;
}
}
}
================================================
FILE: packages/nodeppt-js/assets/less/modules/_work.less
================================================
/*=========================================
8. Work/Resumé/CV <ul class="work">
=========================================== */
.work {
clear: both;
display: flex;
flex-direction: column;
text-align: left;
h1 + &,
h2 + &,
h3 + &,
p + & {
margin-top: 4.8rem;
}
li {
flex: 1;
list-style: none;
margin: 0;
position: relative;
}
p {
margin-bottom: 0;
transition: 0.3s;
}
li a {
display: block;
float: left;
height: 100%;
padding: 2.4rem 0;
width: 100%;
}
li p {
padding-left: 1.2rem;
}
li.work-label p {
padding-left: 0;
}
li a:hover p:first-child {
padding-left: 1.6rem;
}
li p:last-child {
position: absolute;
right: 1.2rem;
top: 2.4rem;
}
li.work-label p:last-child {
right: 0;
top: 0;
}
&-label {
float: left;
font-weight: 600;
padding: 0 0 2.4rem;
width: 100%;
}
&-title {
display: block;
padding-right: 1.2rem;
width: 75%;
}
}
@media (min-width: 768px) {
.work-label p,
.work li p {
float: left;
margin-right: 2%;
width: 25%;
}
.work li.work-label p:last-child,
.work li p:last-child {
float: right;
margin-right: 0;
padding-right: 1.2rem;
position: relative;
right: auto;
text-align: right;
top: auto;
}
.work li p.work-date {
width: 120px;
}
}
@media (max-width: 768px) {
.work-client,
.work-label .work-services {
clip: rect(1px, 1px, 1px, 1px);
height: 1px;
overflow: hidden;
position: absolute;
width: 1px;
}
}
================================================
FILE: packages/nodeppt-js/assets/less/modules/_zoom.less
================================================
/*==============================================
18. Slides Index: Thumbnails navigation gallery
================================================ */
#webslides-zoomed {
align-content: flex-start;
align-items: flex-start;
flex-direction: row;
justify-content: flex-start;
min-height: 100vh;
position: relative;
z-index: 2;
&.disabled {
left: -100000px;
position: absolute;
}
.slide {
height: 400%;
width: 400%;
@media screen and (orientation: portrait), screen and (max-width: 768px) and (orientation: landscape) {
height: 200%;
width: 200%;
}
@media (max-aspect-ratio: 2 / 3) {
height: 200%;
width: 200%;
}
}
> .wrap {
@media (min-width: 1024px) {
padding-bottom: 12rem;
padding-top: 12rem;
}
}
> .wrap > .grid > .column {
align-self: auto;
flex: 0 1 auto;
order: 0;
position: relative;
width: 25%;
@media screen and (max-width: 567px) {
width: 100%;
}
@media screen and (min-width: 568px) and (max-width: 1024px) {
width: 50%;
}
@media screen and (max-width: 567px) and (orientation: portrait) {
width: 100%;
}
> .wrap-zoom {
border-radius: 0.3rem;
display: inline-block;
height: 25vh;
overflow: hidden;
position: relative;
transition: 0.3s;
@media screen and (max-width: 567px) {
height: 50vh;
}
@media screen and (min-width: 568px) and (max-width: 1023px) {
height: 33vh;
}
@media screen and (orientation: portrait) {
height: 50vw;
}
&:hover {
transform: scale(1.02);
z-index: 2;
}
&.current {
transform: scale(1.08);
}
}
> .wrap-zoom > .zoom-layer {
background: transparent;
cursor: pointer;
height: 100%;
position: absolute;
width: 100%;
}
}
.column > .wrap-zoom > .slide {
clip: rect(0 auto auto 0);
display: flex !important; // sass-lint:disable-line no-important
left: 0;
position: absolute;
top: 0;
transform: scale(0.25) translate(-150%, -150vh);
@media screen and (orientation: portrait), screen and (max-width: 768px) and (orientation: landscape) {
transform: scale(0.5) translate(-50%, -50%);
}
@media (max-aspect-ratio: 2 / 3) {
transform: scale(0.5) translate(-50%, -50%);
}
}
& .column {
opacity: 0;
transform: scale(1.2);
transition: opacity 0.4s, transform 0.4s;
transition-delay: 0.2s;
}
&.in {
.column {
opacity: 1;
transform: scale(1);
}
}
}
.text-slide-number {
display: inline-block;
margin: 0.8rem auto;
text-align: center;
}
#webslides {
transition: filter 0.3s;
&.disabled,
&.zooming {
position: fixed;
width: 100%;
z-index: 0;
}
&.disabled {
/*
filter: blur(10px);
transform: scale(1.1);
*/
/* Blur makes scroll no accesible */
width: calc(~'100% - 10px');
}
}
================================================
FILE: packages/nodeppt-js/assets/less/utils/_animations.less
================================================
/* === 1.2 Animations ================
Just 5 basic animations:
.fadeIn, .fadeInUp, .zoomIn, .slideInLeft, and .slideInRight
https://github.com/daneden/animate.css */
/*-- fadeIn -- */
@keyframes fadeIn {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
.fadeIn {
animation: fadeIn 1s;
}
/*-- fadeInUp -- */
@keyframes fadeInUp {
from {
opacity: 0;
transform: translate3d(0, 100%, 0);
}
to {
opacity: 1;
transform: none;
}
}
.fadeInUp {
animation: fadeInUp 1s;
}
/*-- zoomIn -- */
@keyframes zoomIn {
from {
transform: scale3d(0.3, 0.3, 0.3);
}
50% {
opacity: 1;
}
}
.zoomIn {
animation: zoomIn 1s;
}
/*-- slideInLeft -- */
@keyframes slideInLeft {
from {
transform: translate3d(-100%, 0, 0);
visibility: visible;
}
to {
transform: translate3d(0, 0, 0);
}
}
.slideInLeft {
animation: slideInLeft 1s;
animation-fill-mode: both;
}
/*-- slideInRight -- */
@keyframes slideInRight {
from {
transform: translate3d(100%, 0, 0);
visibility: visible;
}
to {
transform: translate3d(0, 0, 0);
}
}
.slideInRight {
animation: slideInRight 1s;
animation-fill-mode: both;
}
/* Animated Background (Matrix) */
@keyframes anim {
0% {
transform: translateY(0);
}
100% {
transform: translateY(-1200px);
}
}
/* Duration */
.slow {
animation-duration: 4s;
& + & {
animation-duration: 5s;
}
}
// slideOutScaleLeft
@keyframes slideOutScaleLeft {
from {
opacity: 1;
}
to {
transform: translateX(-100%) scale(0.9);
opacity: 0;
}
}
@keyframes slideInFromRight {
from {
transform: translateX(100%);
}
to {
transform: translateX(0);
}
}
@keyframes slideInFromLeft {
from {
transform: translateX(-100%);
}
to {
transform: translateX(0);
}
}
@keyframes slideOutScaleRight {
from {
opacity: 1;
}
to {
transform: translateX(100%) scale(0.9);
opacity: 0;
}
}
================================================
FILE: packages/nodeppt-js/assets/less/utils/_bugs.less
================================================
/*=========================================
16. SAFARI BUGS (flex-wrap)
Solution: stackoverflow.com/questions/34250282/flexbox-safari-bug-flex-wrap
=========================================== */
.flexblock:before,
.flexblock:after,
.grid:before,
.grid:after,
.cta:before,
.cta:after {
width: 0;
}
================================================
FILE: packages/nodeppt-js/assets/less/utils/_clear.less
================================================
/*=== Clearing === */
header,
main,
section,
aside,
footer,
.clear,
.wrap {
&:before,
&:after {
content: '';
display: table;
}
&:after {
clear: both;
}
}
================================================
FILE: packages/nodeppt-js/assets/less/utils/_reset.less
================================================
// sass-lint:disable no-vendor-prefixes
/*
=========================================
0. CSS Reset & Normalize
=========================================
*/
html,
body,
div,
span,
applet,
object,
iframe,
h1,
h2,
h3,
h4,
h5,
h6,
p,
blockquote,
pre,
a,
abbr,
acronym,
address,
big,
cite,
code,
del,
dfn,
em,
img,
ins,
kbd,
q,
s,
samp,
small,
strike,
strong,
sub,
sup,
tt,
var,
b,
u,
i,
center,
dl,
dt,
dd,
ol,
ul,
li,
fieldset,
form,
label,
legend,
table,
caption,
tbody,
tfoot,
thead,
tr,
th,
td,
article,
aside,
canvas,
details,
embed,
figure,
figcaption,
footer,
header,
menu,
nav,
output,
ruby,
section,
summary,
time,
mark,
audio,
video {
border: 0;
font: inherit;
font-size: 100%;
margin: 0;
padding: 0;
vertical-align: baseline;
}
article,
aside,
details,
figcaption,
figure,
footer,
header,
main,
menu,
nav,
section,
summary {
display: block;
}
body {
line-height: 1;
}
blockquote,
q {
quotes: '' '';
}
blockquote:before,
blockquote:after,
q:before,
q:after {
content: '';
}
table {
border-collapse: collapse;
border-spacing: 0;
margin-bottom: 24px;
width: 100%;
}
html {
box-sizing: border-box;
}
*,
*::before,
*::after {
box-sizing: inherit;
}
audio,
canvas,
progress,
video {
display: inline-block;
vertical-align: baseline;
}
embed,
iframe,
object {
max-width: 100%;
}
audio:not([controls]) {
display: none;
height: 0;
}
[hidden],
template {
display: none;
}
ul {
list-style: square;
text-indent: inherit;
}
ol {
list-style: decimal;
}
b,
strong {
font-weight: 600;
}
a {
background-color: transparent;
}
a:active,
a:hover {
outline: 0;
}
sup,
sub {
font-size: 0.75em;
height: 0;
line-height: 2.2em;
position: relative;
vertical-align: baseline;
}
sup {
bottom: 1ex;
}
sub {
top: 0.5ex;
}
small {
font-size: 0.75em;
line-height: 1.72;
}
big {
font-size: 1.25em;
}
hr {
border: 0;
clear: both;
display: block;
height: 1px;
margin: 3.2rem auto;
text-align: center;
width: 100%;
}
h2 + hr,
h3 + hr {
margin-bottom: 4.8rem;
}
p + hr {
margin-bottom: 4rem;
}
dfn,
cite,
em,
i {
font-style: italic;
}
abbr,
acronym {
cursor: help;
}
mark,
ins {
padding: 0 4px;
text-decoration: none;
text-shadow: none;
}
::-moz-selection {
text-shadow: none;
}
::selection {
text-shadow: none;
}
img {
border: 0;
height: auto;
max-width: 100%;
}
img:hover {
opacity: 0.9;
}
svg:not(:root) {
overflow: hidden;
}
figure {
line-height: 0;
margin: 0;
position: relative;
}
optgroup {
font-weight: bold;
}
td,
th {
padding: 0;
}
dt {
font-weight: bold;
}
dd {
margin: 0;
}
================================================
FILE: packages/nodeppt-js/index.js
================================================
import WebSlides from 'webslides/src/js/modules/webslides';
import './assets/less/full.less';
import './assets/less/index.less';
import 'animate.css';
// import ItemBuild from './lib/item-build';
import Keyboard from './plugins/keyboard';
import SpeakerMode from './plugins/speaker-mode';
import SpeakerNote from './plugins/speaker-note';
import Echarts from './plugins/echarts';
import Mermaid from './plugins/mermaid';
WebSlides.registerPlugin('echarts', Echarts);
WebSlides.registerPlugin('mermaid', Mermaid);
WebSlides.registerPlugin('keyboard', Keyboard);
WebSlides.registerPlugin('speakermode', SpeakerMode);
WebSlides.registerPlugin('speakernote', SpeakerNote);
export default WebSlides;
================================================
FILE: packages/nodeppt-js/package.json
================================================
{
"name": "nodeppt-js",
"version": "2.2.1",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": {
"name": "Theo Wang",
"email": "ksky521@gmail.com"
},
"repository": {
"type": "git",
"url": "git://github.com/ksky521/nodeppt"
},
"license": "MIT",
"keywords": [
"presentation",
"powerpoint",
"slideshow",
"keynote",
"ppt",
"slide",
"revealjs",
"impressjs",
"markdown-it",
"posthtml",
"webpack",
"nodeppt",
"markdown"
],
"dependencies": {
"animate.css": "^3.7.0",
"nodeppt-template-default": "^1.0.1",
"username": "^5.1.0",
"webslides": "1.5.0"
},
"gitHead": "9fba34ba1a8cc3ab149c2447c313e25b1e25093e"
}
================================================
FILE: packages/nodeppt-js/plugins/echarts.js
================================================
import DOM from 'webslides/src/js/utils/dom';
import {default as Slide, Events as SlideEvents} from 'webslides/src/js/modules/slide';
/* global echarts */
export default class Echarts {
constructor(wsInstance) {
this.ws_ = wsInstance;
const echartsNode = DOM.toArray(this.ws_.el.querySelectorAll('.echarts'));
const echartsData = DOM.toArray(this.ws_.el.querySelectorAll('.echarts-data'));
if (echartsNode.length) {
echartsNode.forEach((chart, j) => {
const {i} = Slide.getSectionFromEl(chart);
const slide = wsInstance.slides[i - 1];
slide.echartsInit = false;
slide.echartsNode = chart;
slide.echartsData = echartsData[j];
// slide.el.addEventListener(SlideEvents.ENTER, Echarts.onSectionEnter);
slide.el.addEventListener(SlideEvents.ENABLE, Echarts.onSectionEnter);
});
}
}
static onSectionEnter(event) {
const slide = event.detail.slide || {};
const {echartsNode, echartsInit, echartsData} = slide;
if (!echartsInit) {
setTimeout(() => {
const theme =
window.pluginsOptions && window.pluginsOptions.echarts
? window.pluginsOptions.echarts.theme
: undefined;
const et = echarts.init(echartsNode, theme);
try {
const data = JSON.parse(echartsData.innerHTML.trim());
et.setOption(data);
slide.echartsInit = true;
} catch (e) {}
}, 800);
}
}
}
================================================
FILE: packages/nodeppt-js/plugins/keyboard.js
================================================
import Keys from 'webslides/src/js//utils/keys';
import DOM from 'webslides/src/js/utils/dom';
/**
* Keyboard interaction plugin.
* 修改原生的 keyboard,支持单条 build
*/
export default class Keyboard {
/**
* @param {WebSlides} wsInstance The WebSlides instance
* @constructor
*/
constructor(wsInstance) {
/**
* @type {WebSlides}
* @private
*/
this.ws_ = wsInstance;
this.enable_ = false;
this.init_();
this.bindEvent_();
}
bindEvent_() {
const el = this.ws_.el;
el.addEventListener('ws:slide-change', this.slideBuild_.bind(this), false);
document.addEventListener('keydown', this.onKeyPress_.bind(this), false);
// 接受远程控制事件
document.addEventListener('control:keydown', this.onKeyPress_.bind(this), false);
}
init_() {
const toBuildNode = toArray(this.ws_.el.querySelectorAll('.build>*'));
if (toBuildNode.length) {
toBuildNode.forEach(node => {
node.classList.add('tobuild');
});
}
}
/**
* Reacts to the keydown event. It reacts to the arrows and space key
* depending on the layout of the page.
* @param {KeyboardEvent} event The key event.
* @private
*/
onKeyPress_(event) {
let method;
let argument;
if (DOM.isFocusableElement() || this.ws_.isDisabled()) {
return;
}
switch (event.which) {
case Keys.AV_PAGE:
method = this.enable_ ? this.goNext : this.ws_.goNext;
break;
case Keys.SPACE:
if (event.shiftKey) {
method = this.enable_ ? this.goPrev : this.ws_.goPrev;
} else {
method = this.enable_ ? this.goNext : this.ws_.goNext;
}
break;
case Keys.RE_PAGE:
method = this.enable_ ? this.goPrev : this.ws_.goPrev;
break;
case Keys.HOME:
method = this.ws_.goToSlide;
argument = 0;
break;
case Keys.END:
method = this.ws_.goToSlide;
argument = this.ws_.maxSlide_ - 1;
break;
case Keys.DOWN:
method = this.ws_.isVertical ? (this.enable_ ? this.goNext : this.ws_.goNext) : null;
break;
case Keys.UP:
method = this.ws_.isVertical ? (this.enable_ ? this.goPrev : this.ws_.goPrev) : null;
break;
case Keys.RIGHT:
method = !this.ws_.isVertical ? (this.enable_ ? this.goNext : this.ws_.goNext) : null;
break;
case Keys.LEFT:
method = !this.ws_.isVertical ? (this.enable_ ? this.goPrev : this.ws_.goPrev) : null;
break;
case Keys.F:
if (!event.metaKey && !event.ctrlKey) {
method = this.ws_.fullscreen;
}
break;
}
if (method) {
method.call(this.enable_ ? this : this.ws_, argument);
// Prevents Firefox key events.
event.preventDefault();
}
}
//单行前进
goNext() {
const $curSlide = this.curSlide_.el;
const subBuilded = toArray($curSlide.querySelectorAll('.building'));
let list;
if (subBuilded.length) {
while ((list = subBuilded.shift())) {
list = list.classList;
list.remove('building');
list.add('builded');
}
}
const toBuild = toArray($curSlide.querySelectorAll('.tobuild'));
if (!toBuild.length) {
// 继续下一页
this.enable_ = false;
this.ws_.goNext();
return false;
}
const item = toBuild[0];
list = item.classList;
list.remove('tobuild');
list.add('building');
return true;
}
//单条往后走
goPrev() {
const $curSlide = this.curSlide_.el;
const subBuilded = toArray($curSlide.querySelectorAll('.building'));
let list;
let buildingLen = subBuilded.length;
let curList;
if (buildingLen) {
while ((list = subBuilded.shift())) {
let clist = list.classList;
clist.remove('building');
clist.add('tobuild');
curList = list;
}
}
const builded = toArray($curSlide.querySelectorAll('.builded'));
if (!builded.length && !buildingLen) {
// 继续下一页
this.enable_ = false;
this.ws_.goPrev();
return false;
}
let item = builded.pop();
if (item) {
if (!curList) {
curList = item;
}
list = item.classList;
list.remove('builded');
if (buildingLen === 0) {
list.add('tobuild');
item = builded.pop();
if (item) {
item.classList.remove('builded');
item.classList.add('building');
}
} else {
list.add('building');
}
}
return true;
}
slideBuild_(e) {
// 处理现在的内容
if (e && e.detail) {
const idx = e.detail.currentSlide0;
const slide = this.ws_.slides[idx];
this.curSlide_ = slide;
const buildNode = toArray(slide.el.querySelectorAll('.tobuild,.builded'));
if (buildNode.length) {
this.enable_ = true;
return;
}
}
this.enable_ = false;
}
}
const emptyArr = [];
//泛数组转换为数组
function toArray(arrayLike) {
return emptyArr.slice.call(arrayLike);
}
================================================
FILE: packages/nodeppt-js/plugins/mermaid.js
================================================
import DOM from 'webslides/src/js/utils/dom';
import {default as Slide, Events as SlideEvents} from 'webslides/src/js/modules/slide';
export default class Echarts {
constructor(wsInstance) {
this.ws_ = wsInstance;
const mermaidNode = DOM.toArray(this.ws_.el.querySelectorAll('.lang-mermaid'));
if (mermaidNode.length) {
mermaidNode.forEach((node, j) => {
const {i} = Slide.getSectionFromEl(node);
const slide = wsInstance.slides[i - 1];
slide.mermaidInit = false;
slide.mermaidNode = node;
slide.el.addEventListener(SlideEvents.ENABLE, Echarts.onSectionEnter);
});
}
}
static onSectionEnter(event) {
const slide = event.detail.slide || {};
const {mermaidNode, mermaidInit} = slide;
if (!mermaidInit && window.mermaid) {
setTimeout(() => {
const theme =
window.pluginsOptions && window.pluginsOptions.mermaid
? window.pluginsOptions.mermaid.theme
: undefined;
mermaid.initialize({
theme: theme ? theme : 'default'
});
mermaidNode.style.visibility = 'visible';
mermaid.init(undefined, mermaidNode);
slide.mermaidInit = true;
}, 800);
}
}
}
================================================
FILE: packages/nodeppt-js/plugins/speaker-mode.js
================================================
// import Keyboard from 'webslides/src/js/plugins/keyboard';
export default class SpeakerMode {
constructor(wsInstance) {
this.ws_ = wsInstance;
this.init_();
}
bindEvent_() {
window.addEventListener('message', this.evtHandler_, false);
document.addEventListener('keydown', this.onKeyPress_.bind(this), false);
}
onKeyPress_(e) {
if ((e.detail && e.detail.salt) || !this.listener_) {
// 处理过了,防止事件重复处理
return;
}
this.listener_.postMessage({which: e.which, shiftKey: e.shiftKey}, '*');
}
evtHandler_(e) {
// 发送自定义事件
const data = e.data;
const {which, shiftKey} = data;
const event = new CustomEvent('control:keydown', {
detail: {
salt: true
}
});
event.which = which;
event.shiftKey = shiftKey;
document.dispatchEvent(event);
}
init_() {
const params = parseQuery();
if (params.mode === 'speaker') {
this.ws_.el.classList.add('with-note');
const url = location.href.replace('mode=speaker', 'mode=audience');
const sWidth = screen.width;
const sHeight = screen.height;
const tWidth = sWidth * 0.8;
const tHeight = sHeight * 0.8;
const temp =
`height=${tHeight},width=${tWidth},top=10,left=${(sWidth - tWidth) / 2}` +
',toolbar=no,menubar=no,location=yes,resizable=yes,scrollbars=no,status=no';
this.listener_ = this.popup_ = window.open(url, 'ppt', temp);
window.addEventListener('beforeunload', this.closeClient_.bind(this), false);
this.bindEvent_();
} else if (params.mode === 'audience') {
this.listener_ = window.opener;
this.bindEvent_();
}
}
closeClient_() {
if (this.popup_ && this.popup_.close) {
this.popup_.close();
}
}
}
function parseQuery(url) {
let back = {};
(url || location.search.substring(1)).split('&').forEach(v => {
v = v.split('=');
back[v[0].toLowerCase()] = v[1];
});
return back;
}
================================================
FILE: packages/nodeppt-js/plugins/speaker-note.js
================================================
import DOM from 'webslides/src/js/utils/dom';
import {default as Slide, Events as SlideEvents} from 'webslides/src/js/modules/slide';
const HEIGHT = 0.2;
const SCALE = 1.5;
export default class SpeakerNote {
constructor(wsInstance) {
this.ws_ = wsInstance;
this.isSpeakerMode_ = this.ws_.el.classList.contains('with-note');
const $note = DOM.toArray(this.ws_.el.querySelectorAll('.speaker-note'));
if ($note.length) {
$note.forEach((note, j) => {
const {i} = Slide.getSectionFromEl(note);
const slide = wsInstance.slides[i - 1];
slide.noteNode = note;
if (!this.isSpeakerMode_) {
slide.el.addEventListener(SlideEvents.ENABLE, SpeakerNote.onSectionEnter);
slide.el.addEventListener(SlideEvents.DISABLE, SpeakerNote.onSectionDisabled);
}
});
}
}
static toggleNote(e) {
// console.log(e);
if (e.which === 110 && !e.metaKey && !e.ctrlKey && !e.shiftKey) {
// toggleNote
this.classList.toggle('show');
}
}
static onSectionDisabled(event) {
const $slide = event.detail.slide;
document.removeEventListener('keypress', SpeakerNote.toggleNote.bind($slide.noteNode));
}
static onSectionEnter(event) {
const $slide = event.detail.slide;
document.addEventListener('keypress', SpeakerNote.toggleNote.bind($slide.noteNode));
}
}
================================================
FILE: packages/nodeppt-parser/.npmignore
================================================
__tests__
__mocks__
================================================
FILE: packages/nodeppt-parser/__tests__/classes.md
================================================
title: nodeppt Classes 演示
speaker: 三水清
url: https://github.com/ksky521/nodeppt
css:
- https://fonts.googleapis.com/css?family=Roboto:100,100i,300,300i,400,400i,700,700i%7CMaitree:200,300,400,600,700&subset=latin-ext
<slide :class="size-50">
## :fa-heart-o: CSS Syntax
WebSlides is so easy to understand and love. Baseline\: 8. {.text-intro}
* :Typography\::{.text-label} .text-landing, .text-subtitle, .text-data, .text-intro...
* :BG Colors\::{.text-label} .bg-primary, .bg-blue,.bg-apple...
* :BG Images\::{.text-label} .background, .background-center-bottom...
* :Cards\::{.text-label} .card-60, .card-50, .card-40...
* :Sizes\::{.text-label} .size-50, .size-40...
* :Flex Blocks\::{.text-label} .flexblock.clients, .flexblock.gallery, .flexblock.metrics...
{.description}
<slide>
:::column {.vertical-align}
### **WebSlides is really easy**
Each parent `<section>` in the #webslides element is an individual slide. {.text-intro}
Code is neat, scalable, and well documented. It uses **intuitive markup with popular naming conventions**. There's no need to overuse classes or nesting. **Based on** [SimpleSlides](https://github.com/jennschiffer/SimpleSlides) , by [Jenn Schiffer](http://jennmoney.biz) :)
----
```html
<article id="webslides">
<!-- Slide 1 -->
<section>
<h1>Design for trust</h1>
</section>
<!-- Slide 2 -->
<section class="bg-primary">
<div class="wrap">
<h2>.wrap = container (width: 90%) with fadein</h2>
</div>
</section>
</article>
```
:::
---
Vertical sliding? `<article id="webslides" class="vertical">` {.aligncenter}
<slide>
:::{.aligncenter}
### Simple CSS Alignments
Put content wherever you want.
:::
:::footer
Footer: logo, credits... (.alignleft) {.alignleft}
[:fa-twitter: @username .alignright](){.alignright}
:::
:::header
Header (logo) :.alignright:{.alignright}
:::
<slide>
!
## img.alignleft
`img.alignleft.size-50`
Jobs unveiled the iPhone to the public on January 9, 2007, at the Macworld 2007 convention at the Moscone Center in San Francisco. Apple sold 6.1 million first generation iPhone units over five quarters.
**Image size recommended**:<br> 800x600px / 600x450px.
<slide>
!
## img.alignright
`img.alignright.size-50`
Jobs unveiled the iPhone to the public on January 9, 2007, at the Macworld 2007 convention at the Moscone Center in San Francisco. Apple sold 6.1 million first generation iPhone units over five quarters.
**Image size recommended**:<br> 800x600px / 600x450px.
<slide>
!
`img.aligncenter.size-40` {.aligncenter}
<slide class="slide-top">
:::{.content-left}
### 1/9 left top
Put content wherever you want. Have less. Do more. Create beautiful solutions.
`.slide-top and .content-left`
<slide class="slide-top">
:::{.content-center}
### 2/9 center top
In a village of La Mancha, the name of which I have no desire to call to mind,
`.slide-top and .content-center`
<slide class="slide-top">
:::{.content-right}
### 3/9 right top
there lived not long since one of those gentlemen that keep a lance in the lance-rack, an old buckler, a lean hack, and a greyhound for coursing.
`.slide-top and .content-right`
<slide>
:::{.content-left}
### 4/9 left top
An olla of rather more beef than mutton, a salad on most nights, scraps on Saturdays,
`.content-left`
<slide>
:::{.content-center}
### 5/9 center top
lentils on Fridays, and a pigeon or so extra on Sundays, made away with three-quarters of his income.
`.content-center`
<slide>
:::{.content-right}
### 6/9 right top
he rest of it went in a doublet of fine cloth and velvet breeches and shoes to match for holidays,
`.content-right`
<slide class="slide-bottom">
:::{.content-left}
### 7/9 left bottom
while on week-days he made a brave figure in his best homespun.
`.slide-bottom` and `.content-left`
<slide class="slide-bottom">
:::{.content-center}
### 8/9 center bottom
He had in his house a housekeeper past forty, a niece under twenty, and a lad for the field and market-place,
`.slide-bottom` and `.content-center`
<slide class="slide-bottom">
:::{.content-right}
### 9/9 right bottom
who used to saddle the hack as well as handle the bill-hook.
`.slide-bottom` and `.content-right`
<slide class="aligncenter">
## .grid + .column
Basic Grid (auto-fill and equal height). {.text-intro}
:::column
###### Why WebSlides?
There're excellent presentation tools out there. WebSlides is about good karma and sharing content. Hypertext, clean code, and beauty as narrative elements.
----
!
---
###### How easy is WebSlides?
You can create your own presentation instantly. Just a basic knowledge of HTML and CSS is required. Simply choose a demo and customize it.
:::
<slide class="aligncenter">
## .grid.**vertical-align** + .column
Basic Grid (auto-fill and equal height). {.text-intro}
:::column {.vertical-align}
###### Why WebSlides?
There're excellent presentation tools out there. WebSlides is about good karma and sharing content. Hypertext, clean code, and beauty as narrative elements.
----
!
---
###### How easy is WebSlides?
You can create your own presentation instantly. Just a basic knowledge of HTML and CSS is required. Simply choose a demo and customize it.
:::
<slide>
## .grid.**sm** (sidebar + main)
----
:::column {.sm}
### .column 1
Stendhal syndrome is a psychosomatic disorder that causes rapid heartbeat, dizziness, fainting, confusion and even hallucinations when an individual is exposed to an experience of great personal significance, particularly viewing art.
---
## .column 2
The illness is named after the 19th-century French author Stendhal (pseudonym of Marie-Henri Beyle), who described his experience with the phenomenon during his 1817 visit to Florence in his book Naples and Florence: A Journey from Milan to Reggio.
When he visited the Basilica of Santa Croce, where Niccolò Machiavelli, Michelangelo and Galileo Galilei are buried, he saw Giotto's frescoes for the first time and was overcome with emotion.
:::
<slide>
## .grid.**ms** ( main + sidebar)
----
:::column {.ms}
### .column 1
The illness is named after the 19th-century French author Stendhal (pseudonym of Marie-Henri Beyle), who described his experience with the phenomenon during his 1817 visit to Florence in his book Naples and Florence: A Journey from Milan to Reggio.
When he visited the Basilica of Santa Croce, where Niccolò Machiavelli, Michelangelo and Galileo Galilei are buried, he saw Giotto's frescoes for the first time and was overcome with emotion.
---
## .column 2
Stendhal syndrome is a psychosomatic disorder that causes rapid heartbeat, dizziness, fainting, confusion and even hallucinations when an individual is exposed to an experience of great personal significance, particularly viewing art.
:::
<slide>
## .grid.**sms** ( sidebar + main + sidebar)
----
:::column {.sms}
### .column 1
Information architecture is considered to have been founded by Richard Saul Wurman.
----
### .column 2
Information architecture (IA) is the structural design of shared information environments; the art and science of organizing and labelling websites, intranets, online communities and software to support usability and findability; and an emerging community of practice focused on bringing principles of design and architecture to the digital landscape.
---
## .column 3
The difficulty in establishing a common definition for "information architecture" arises partly from the term's existence in multiple fields.
:::
<slide>
:::card
## Unsplash
.card-50.bg-white
[Unsplash](http://Unsplash.com) is a really cool resource. It is a collection of Creative Commons Zero licensed photos that are really great. {.text-intro}
* :Role\::{.text-label} Frontend
* :client\::{.text-label} Acme
* :year\::{.text-label} 2018
{.description}
---

:::
<slide>
:::card-50

---
## Bonsai
Bonsai is a Japanese art form using trees grown in containers — .fullscreen > .card-50. {.text-intro}
Similar practices exist in other cultures, including the Chinese tradition of penjing from which the art originated, and the miniature living landscapes of Vietnamese hòn non bộ.
\* \* \* {.text-symbols}
Similar practices exist in other cultures, including the Chinese tradition of penjing from which the art originated, and the miniature living landscapes of Vietnamese hòn non
:::
<slide class="fullscreen">
:::card

---
## Bonsai
Bonsai is a Japanese art form using trees grown in containers — .fullscreen > .card-50. {.text-intro}
Similar practices exist in other cultures, including the Chinese tradition of penjing from which the art originated, and the miniature living landscapes of Vietnamese hòn non bộ.
:::
<slide class="bg-apple aligncenter">
# Backgrounds
<slide class="bg-apple">
<slide>
## Corporate Backgrounds
:::flexblock {.blink.border}
## .bg-primary {..bg-primary}
\#44d
----
## .bg-secondary {..bg-secondary}
\#67d
----
## .bg-light {..bg-light}
\#edf2f7
----
## body
\#f7f9fb
:::
----
## General Colors
:::flexblock {.blink.border}
## .bg-black {..bg-black}
\#111
----
## .bg-black-blue {..bg-black-blue}
\#123
----
## .bg-white {..bg-white}
\#fff
:::
<slide>
## Colorful
:::flexblock {.border.blink}
## .bg-red {..bg-red}
\#c23
----
## .bg-green {..bg-green}
\#077
----
## .bg-blue {..bg-blue}
\#346
----
## .bg-purple {..bg-purple}
\#62b
:::
----
### Transparent Backgrounds
:::flexblock {.border.blink}
## .bg-trans-dark {..bg-trans-dark}
rgba(0, 0, 0, 0.5)
----
## .bg-trans-light {..bg-trans-light}
rgba(255, 255, 255, 0.2)
:::
<slide class="bg-gradient-h">
# Gradients
:::flexblock {.border}
Horizontal
`.bg-gradient-h`
----
Radial
`.bg-gradient-r`
----
Vertical
`.bg-gradient-v`
:::
<slide class="bg-gradient-v aligncenter">
## Vertical Gradient
`.bg-gradient-v`
<slide class="bg-gradient-r aligncenter">
## Radial Gradient
`.bg-gradient-r`
<slide class="bg-black" video="https://webslides.tv/static/videos/working.mp4 poster='https://webslides.tv/static/images/working.jpg'" >
`.background-video`
## **WebSlides is the easiest way to make HTML presentations. Inspire and engage.**
<slide class="bg-blue aligncenter" video="https://webslides.tv/static/videos/working.mp4 poster='https://webslides.tv/static/images/working.jpg' .dark">
## BG Video with Overlay {.text-landing}
`<slide class="bg-blue aligncenter" video="https://webslides.tv/static/videos/working.mp4 poster='https://webslides.tv/static/images/working.jpg' .dark">` or `.light`
<slide image="https://webslides.tv/static/images/iphone-hand.png .right-bottom">
:::{.content-left}
### .background-(position)
:::flexblock {.specs}
::fa-wifi::
## Ultra-Fast WiFi
Simple and secure file sharing.
---
::fa-battery-full::
## All day battery life
Your battery worries may be over.
---
::fa-life-ring::
## All day battery life
We'll fix it or if we can't, we'll replace it.
:::
<slide class="bg-black aligncenter" image="https://source.unsplash.com/UJbHNoVPZW0/ .dark">
# Iceland{.text-landing.text-shadow}
`slide[class*="bg-"] > .background.dark`
<slide class="bg-black aligncenter" image="https://source.unsplash.com/UJbHNoVPZW0/ .light">
# Iceland{.text-landing.text-shadow}
`slide[class*="bg-"] > .background.light`
<slide class="bg-black aligncenter" image="https://source.unsplash.com/n9WPPWiPPJw/ .anim">
## .background.anim
<slide class="aligncenter">
## **Flexible blocks**
`:::flexblock` = Flexible blocks with auto-fill and equal height.
---
:::flexblock
## :fa-bar-chart: Purpose
Businesses that people love1
---
## :fa-bar-chart: Purpose
Businesses that people love2
---
## :fa-balance-scale: Purpose
Businesses that people love3
---
## :fa-cog: Purpose
Businesses that people love4
:::
<slide>
## flexblock
:::flexblock
## :fa-bar-chart: Purpose
Businesses that people love1
---
## :fa-bar-chart: Purpose
Businesses that people love2
---
## :fa-balance-scale: Purpose
Businesses that people love3
---
## :fa-cog: Purpose
Businesses that people love4
:::
## flexblock
`{.blink.border}`
:::flexblock {.blink.border}
## :fa-bar-chart: Purpose
Businesses that people love5
---
## :fa-bar-chart: Purpose
Businesses that people love6
---
## :fa-balance-scale: Purpose
Businesses that people love7
---
## :fa-cog: Purpose
Businesses that people love8
:::
<slide>
## flexblock
`{.blink.border}`
:::flexblock {.blink.border}
## :fa-bar-chart: Purpose
Businesses that people love1
---
## :fa-bar-chart: Purpose
Businesses that people love2
---
## :fa-balance-scale: Purpose
Businesses that people love3
---
## :fa-cog: Purpose
Businesses that people love4
---
## :fa-bar-chart: Purpose
Businesses that people love5
---
## :fa-bar-chart: Purpose
Businesses that people love6
---
## :fa-balance-scale: Purpose
Businesses that people love7
---
## :fa-cog: Purpose
Businesses that people love8
:::
<slide>
## flexblock clients
`{.clients}`
:::flexblock {.clients}
{.blacklogo}
### Interfaces
Collaboration with the Acme team to design their mobile apps.
---
 {.blacklogo}
### Interfaces
Collaboration with the Acme team to design their mobile apps.
---
{.blacklogo}
### Interfaces
Collaboration with the Acme team to design their mobile apps.
---
{.blacklogo}
### Interfaces
Collaboration with the Acme team to design their mobile apps.
:::
<slide>
## flexblock clients
`{.clients.border}`
:::flexblock {.clients.border}
{.blacklogo}
### Interfaces
Collaboration with the Acme team to design their mobile apps.
---
 {.blacklogo}
### Interfaces
Collaboration with the Acme team to design their mobile apps.
---
{.blacklogo}
### Interfaces
Collaboration with the Acme team to design their mobile apps.
---
{.blacklogo}
### Interfaces
Collaboration with the Acme team to design their mobile apps.
:::
<slide>
### ul.flexblock.features
:::flexblock {.features}
## :100 ^%^: customizable
Well documented
----
:^$^48:
## EXTRA VIRGIN OLIVE OIL
The Spanish caviar.
----
## :fa-wifi: Ultra-fast Wifi
Simple file sharing.
:::
---
## ul.flexblock.features.blink
:::flexblock {.features.blink}
## :100 ^%^: customizable
Well documented
----
:^$^48:
## EXTRA VIRGIN OLIVE OIL
The Spanish caviar.
----
## :fa-wifi: Ultra-fast Wifi
Simple file sharing.
:::
---
<slide class="bg-green">
## flexblock .Metrics
:::flexblock {.border.metrics}
Founded
::1972::
----
::fa-users::
24M Subscribers
---
Founded
::64%::
----
:~fa-line-chart~:
Revenue: $16M
---
:~fa-building-o~:
Covers, cards, quotes...
----
:~fa-smile-o~:
Use multiples of 8.
---
:~fa-usd~:
Font Awesome Kit.
---
:~fa-university~:
Bank: $32M
:::
<slide :class="size-60">
### shadowbox
---
:::shadowbox
## We're web people.
There're excellent presentation tools out there. WebSlides is about telling the story, and sharing it in a beautiful way. Hypertext and clean code as narrative elements.
---
## Work better, faster.
Designers, marketers, and journalists can now focus on the content. Simply [choose a demo](https://webslides.tv/demos) and customize it in minutes.
:::
<slide>
## steps
:::steps
:~fa-file~:
## Interfaces
When you're really passionate about your job, you can change the world.
---
## Interfaces
1. Architecture
2. Design
3. Development
---
## Interfaces
1. Architecture
2. Design
3. Development
---
## Interfaces
1. Architecture
2. Design
3. Development
:::
<slide>
### gallery
:::gallery

## Alicia Jiménez
Founder & CEO
---

## Sam Trololovitz
Master of nothing
---

## Erin Gustafson
VP of Design
:::
<slide>
### gallery overlay
:::gallery-overlay

## Alicia Jiménez
Founder & CEO
---

## Sam Trololovitz
CTO
---

## Erin Gustafson
VP of Design
:::
<slide class="bg-red" image="https://source.unsplash.com/R1J6Z1cnJZc/ .dark">
:::cta
!
---
## Watch TV shows anytime, anywhere
.frame.bg-red
:::
<slide class="bg-red frame">
:::cta
::^$^40::
---
## Watch TV shows anytime, anywhere
.frame.bg-red
:::
<slide class="aligncenter">
# Landings {.text-landing}
`.text-landing`
<slide class="aligncenter">
# Landings {.text-landing}
Create a simple web presence. {.text-intro}
`.text-intro`
<slide class="aligncenter">
POWERED BY [#WEBSLIDES](https://twitter.com/search?f=tweets&vertical=default&q=%23WebSlides&src=typd) `.text-subtitle` {.text-subtitle}
# Landings {.text-landing}
Create a simple web presence. {.text-intro}
`.text-intro`
<slide class="bg-black aligncenter" image="https://source.unsplash.com/C1HhAQrbykQ/">
# **Landings** {.text-landing.text-shadow}
`.text-shadow` {.text-intro}
<slide class="bg-apple aligncenter">
## 4,235,678 {.text-data}
`.text-data`
<slide>
Why WebSlides? .text-context {.text-content}
## WebSlides is incredibly easy and versatile. The easiest way to make HTML presentations.
<slide>
`.text-cols (2 columns)`
:::div {.text-cols}
**Why WebSlides?** There are excellent presentation tools out there. WebSlides is about sharing content, essential features, and clean markup. **Each parent <slide>** in the #webslides element is an individual slide.
**WebSlides help you build a culture of innovation and excellence**. When you're really passionate about your job, you can change the world. How to manage a design-driven organization? Leadership through usefulness, openness, empathy, and good taste.
:::
:::flexblock {.metrics}
:fa-phone:
Call us at 555.345.6789
----
:fa-twitter:
@username
----
:fa-envelope:
Send us an email
:::
<slide>
:::column {.vertical-align}
## A Phone by Google
Pixel's camera lets you take brilliant photos in low light, bright light or any light. {.text-intro}
* :Typography\::{.text-label} .text-landing, .text-subtitle, .text-data, .text-intro...
* :BG Colors\::{.text-label} .bg-primary, .bg-blue,.bg-apple...
* :BG Images\::{.text-label} .background, .background-center-bottom...
* :Sizes\::{.text-label} .size-50, .size-40...
* :Flex Blocks\::{.text-label} .flexblock.clients, .flexblock.gallery, .flexblock.metrics...
{.description}
----

:::
<slide class="aligncenter text-serif">
:::div {.content-left}
## WebSlides is incredibly easy and versatile.
`.text-serif` (Maitree)
:::
:::div {.content-left}
Each parent `<slide>` in the #webslides element is an individual slide.
Clean markup with popular naming conventions. Minimum effort. Just focus on your content.
:::
<slide :class="size-50">
### **What is Stendhal Syndrome?**
Beauty overdose. `.text-pull-right` {.text-intro}
Imagine that you are in Florence. If you suddenly start to feel that you literally cannot breathe, you may be experiencing Stendhal Syndrome.
Psychiatrists have long debated whether it really exists. {.text-pull-right}
The syndrome is not only associated with viewing a beautiful place, but also good art.
The beauty of Italian art has a concentrated perfection and transcendent sensuality that is incredibly addictive.
<slide class="bg-primary">
# Design :for: understanding
:::flexblock {.features.fadeInUp}
:100^%^: purpose
## Businesses that people love
---
## :fa-heart-o: Principles
Useful → Easy → Fast → Beautiful
:::
<slide image="https://source.unsplash.com/yssUhIxbUZA/">
::: div {.content-left.bg-trans-dark.fadeInUp}
!
---
## **Designing Experiences**
Meet locals who share your interests.
:::
<slide class="bg-black slide-bottom" image="https://source.unsplash.com/RSOxw9X-suY/">
:::div {.content-left}
:fa-tree large:
## 1,000,000
### We're working to protect up to a million acres of sustainable forest.
:::
<slide class="bg-black-blue">
:::column
### **:fa-line-chart: Interface**
Design for growth. We've built a team of world-class designers, developers, and managers.
---
### **:fa-film: Videos**
We connect your audience needs, business goals, and brand values into a strategy.
---
### **:fa-users: Recruiting**
We offer personalized services with deep expertise in design and technology.
---
### **:fa-graduation-cap: Formation**
We train teams to help organizations succeed in the digital age.
:::
<slide>
## table
| Left-aligned | Center-aligned | Right-aligned |
| :----------- | :------------: | ------------: |
| git status | git status | git status |
| git diff | git diff | git diff |
| git status | git status | git status |
<slide class="bg-black-blue" :class="size-60">
> I have always appreciated designers who dare to reinterpret fabrics and proportions, so I follow the Japanese and Belgian designers.
> ==Zaha Hadid==
> {.text-quote}
<slide image="https://webslides.tv/static/images/satya.png .left-bottom">
:::div {.content-right}
> "There is something only a CEO uniquely can do, which is set that tone, which can then capture the soul of the collective."
> ==Satya Nadella, CEO of Microsoft.==
:::
<slide>
:::card {.quote}

---
> “WebSlides helped us build a culture of innovation and excellence.”
> ==Leonardo da Vinci==
<slide>
::: {.content-left}
## button
[.button](){.button} [.button.radius](){.button.radius}
[.button.ghost](){.button.ghost} [:fa-github: svg-icon](){.button}
:::
================================================
FILE: packages/nodeppt-parser/__tests__/demo.md
================================================
title: nodeppt markdown 演示
speaker: 三水清
url: https://github.com/ksky521/nodeppt
js:
- https://www.echartsjs.com/asset/theme/shine.js
prismTheme: solarizedlight
plugins:
- echarts
- katex
<slide>
## Corporate Backgrounds
:::blink
## .bg-primary {..bg-primary ..href="abc"}
\#44d
----
## .bg-secondary {..bg-secondary}
\#67d
----
## .bg-light {..bg-light}
\#edf2f7
----
## body
\#f7f9fb
:::
<slide>
## Corporate Backgrounds
:::flexbox
## .bg-primary {..bg-primary}
\#44d
----
## .bg-secondary {..bg-secondary}
\#67d
----
## .bg-light {..bg-light}
\#edf2f7
----
## body
\#f7f9fb
:::
----
## General Colors
:::flexbox
## .bg-black {..bg-black}
\#111
----
## .bg-black-blue {..bg-black-blue}
\#123
----
## .bg-white {..bg-white}
\#fff
:::
<slide>
## Colorful
:::flexbox
## .bg-red {..bg-red}
\#c23
----
## .bg-green {..bg-green}
\#077
----
## .bg-blue {..bg-blue}
\#346
----
## .bg-purple {..bg-purple}
\#62b
:::
----
### Transparent Backgrounds
:::flexbox
## .bg-trans-dark {..bg-trans-dark}
rgba(0, 0, 0, 0.5)
----
## .bg-trans-light {..bg-trans-light}
rgba(255, 255, 255, 0.2)
:::
<slide class="bg-gradient-h">
# Gradients
:::flexbox {.border}
Horizontal
`.bg-gradient-h`
----
Radial
`.bg-gradient-r`
----
Vertical
`.bg-gradient-v`
:::
<slide class="bg-gradient-v aligncenter">
## Vertical Gradient
`.bg-gradient-v`
<slide class="bg-gradient-r aligncenter">
## Radial Gradient
`.bg-gradient-r`
<slide class="bg-apple aligncenter">
## One more background :)
`.bg-apple`
<slide class="bg-purple aligncenter" image="https://source.unsplash.com/C1HhAQrbykQ/ .dark">
# nodeppt
## 这可能是迄今为止最好的网页版演示库
<slide class="bg-blue aligncenter" video='https://webslides.tv/static/videos/peggy.mp4 .dark poster="https://webslides.tv/static/images/peggy.jpg"'>
# 为什么选择 nodeppt
`section.bg-blue > .background-video.dark` or `.light`
<slide class="" :class="size-40">
### 为什么选择 nodeppt
- 基于 GFM 的 markdown 语法编写
- 支持 html 混排,再复杂的 demo 也可以做!
- 导出网页或者 pdf 更容易分享
- 支持单页背景图片
- 多种模式:纵览模式,双屏模式,远程控制
- 可以使用画板,可以使用 note 做备注
- 支持语法高亮,自由选择 highlight 样式
- 可以单页 ppt 内部动效,单步动效
- 支持进入/退出回调,做在线 demo 很方便
{.build.fadeIn}
<slide>
## 为什么选择 nodeppt
:::column {.vertical-align}
- 基于 GFM 的 markdown 语法编写
- 支持 html 混排,再复杂的 demo 也可以做!
- 导出网页或者 pdf 更容易分享
- 支持单页背景图片
- 多种模式:纵览模式,双屏模式,远程控制
- 可以使用画板,可以使用 note 做备注
- 支持语法高亮,自由选择 highlight 样式
- 可以单页 ppt 内部动效,单步动效
- 支持进入/退出回调,做在线 demo 很方便
---
```html {..fadeInUp..slow}
<article id="webslides">
<!-- Slide 1 -->
<section>
<h1>Design for trust</h1>
</section>
<!-- Slide 2 -->
<section class="bg-primary">
<div class="wrap">
<h2>.wrap = container (width: 90%)</h2>
</div>
</section>
</article>
```
:::
<slide class="frame moveIn" :class="size-60 bg-white tobuild">
### :fa-info-circle large: **Autoplay Feature**
Autoplay is generally disabled on all mobile devices to prevent bandwidth consumption. User must execute the play manually. {.text-intro}
<slide>
## Header & Footer
:::header {.abeee}
### Header
:::
:::footer
### Footer
:::
:::note
### Note
:::
<slide class="bg-brown">
:::column
::fa-heart large::
### **Feature 1**
Test your web and mobile designs, and quickly incorporate user feedback.
---
::fa-heart large::
### **Feature 1**
Test your web and mobile designs, and quickly incorporate user feedback.
---
::fa-heart large::
### **Feature 1**
Test your web and mobile designs, and quickly incorporate user feedback.
:::
<slide>
::: {.content-left}
## button
[.button](){.button} [.button.radius](){.button.radius}
[.button.ghost](){.button.ghost} [:fa-github: svg-icon](){.button}
:::
<slide :class="size-50">
### Let's check out some examples.
All content is for demo purposes only.
---
1. Welcomes
2. Covers
3. Abouts & Teams
4. Features & Benefits
5. Cards
6. Metrics & Data
7. Pricing & Offers
8. Quotes
9. Buttons & Badges
10. Forms
11. SVG Icons
12. Logos
13. CSS Animations
14. Embedding videos, maps, charts...
{.text-cols}
<slide class="aligncenter">
## Welcomes {.text-landing}
**WebSlides** is an open source tool for telling stories. {.text-intro}
<nav>
* [Twitter](https://twitter.com/webslides)
* [Dribbble](https://twitter.com/webslides)
* [Github](https://twitter.com/webslides)
</nav>
<slide class="bg-secondary" :class="size-50 frame">
## How to Tell Your Story? {.text-serif.aligncenter}
\* \* \* {.text-symbols}
Stories have the power to change the world. WebSlides helps you write better content, faster. Your slides are there to support your story. Choose words wisely, create meaning with them, keep it simple.
<slide :class="size-60">
### **Why WebSlides**? Good karma and productivity.
---
:::shadowbox
## We're web people.
There're excellent presentation tools out there. WebSlides is about telling the story, and sharing it in a beautiful way. Hypertext and clean code as narrative elements.
---
## Work better, faster.
Designers, marketers, and journalists can now focus on the content. Simply [choose a demo](https://webslides.tv/demos) and customize it in minutes.
:::
<slide image="https://source.unsplash.com/Vti8XHv2XjU/" class="bg-black aligncenter">
# **California** {.text-shadow}
<slide class="bg-gradient-v" :class="size-60" image="https://source.unsplash.com/nxfuA21kNHY/1440x1440 .dark">
GOOD KARMA {.text-context}
## WebSlides is about **telling the story**, and sharing it in a beautiful way.
<slide class="bg-black aligncenter" image="https://source.unsplash.com/mGYxAWITqMg/">
Plan your next trip {.text-subtitle}
# Summ.er {.text-shadow}
The best places at the best price. {.text-intro}
<slide class="bg-black" image="https://source.unsplash.com/7waHOTcvcT4/">
\$975 {.text-data}
<slide class="bg-black slide-bottom" image="https://source.unsplash.com/Q1p7bh3SHj8/">
Location Intelligence {.text-subtitle}
## **The application of geographic mapping to data**
<slide image="https://source.unsplash.com/YMOHw3F1Hdk/">
::: {.alignright.size-50.bg-trans-dark}
New in London {.text-subtitle.text-serif}
### **Hotel Daenerys**
The Daenerys has facilities such as a 24-hour front desk, an elevator with access to all rooms, and a terrace with a garden where guests can enjoy breakfast during the summer.
[More info]()
:::
<slide :class="aligncenter">
## **Abouts & Teams**
<slide class="bg-primary">
:::flexbox
!
---
!
---
!
:::
<slide>
::: {.content-center}
### ul.flexblock.specs
:::specs
## :fa-long-arrow-right: SIMPLE NAVIGATION
with arrow keys and swipe.
----
## :fa-link: Permalinks
Go to a specific slide. URL: #slide=number
---
## :fa-text-height: SVG ICONS
Font Awesome Kit.
:::
:::
<slide class="bg-red" image="https://source.unsplash.com/R1J6Z1cnJZc/ .dark">
:::cta
!
---
## Watch TV shows anytime, anywhere
.frame.bg-red
:::
<slide class="bg-red frame">
:::cta
::^$^40::
---
## Watch TV shows anytime, anywhere
.frame.bg-red
:::
<slide class="bg-dark">
## Flexbox
:::flexbox
Founded
----
24M Subscribers
---
Founded
----
Revenue: $16M
---
Covers, cards, quotes...
----
Use multiples of 8.
---
Font Awesome Kit.
---
Bank: $32M
:::
<slide>
<slide class="bg-green">
## Metrics
:::flexbox {.border.metrics}
Founded
::1972::
----
::fa-users::
24M Subscribers
---
Founded
::64%::
----
:~fa-line-chart~:
Revenue: $16M
---
:~fa-building-o~:
Covers, cards, quotes...
----
:~fa-smile-o~:
Use multiples of 8.
---
:~fa-usd~:
Font Awesome Kit.
---
:~fa-university~:
Bank: $32M
:::
<slide>
## Features
:::features
## ::→:: SIMPLE NAVIGATION
with arrow keys and swipe.
----
## :fa-link: Permalinks
Go to a specific slide.
---
## :fa-clock-o: Permalinks
Go to a specific slide.
----
## ::40+:: BEAUTIFUL COMPONENTS
Covers, cards, quotes...
----
## :fa-text-height: VERTICAL RHYTHM
Use multiples of 8.
---
## ::500+:: SVG ICONS
Font Awesome Kit.
:::
<slide>
## About/Services/Clients
`ul.flexblock.blink.border`
:::blink
## Interfaces
When you're really passionate about your job, you can change the world.
---
## Interfaces
1. Architecture
2. Design
3. Development
---
## Interfaces
1. Architecture
2. Design
3. Development
---
## Interfaces
1. Architecture
2. Design
3. Development
---
## Interfaces
When you're really passionate about your job, you can change the world.
---
!
Acme hired us to help make the reading experience totally engaging.
---
!
Acme hired us to help make the reading experience totally engaging.
---
## Interfaces
1. Architecture
2. Design
3. Development
:::
<slide>
## ul.flexblock.steps
:::steps
:~fa-file~:
## Interfaces
When you're really passionate about your job, you can change the world.
---
## Interfaces
1. Architecture
2. Design
3. Development
---
## Interfaces
1. Architecture
2. Design
3. Development
---
## Interfaces
1. Architecture
2. Design
3. Development
:::
<slide>
:::column
### FAQs {.text-context}
WebSlides is an open source solution by
---
###### Why WebSlides?
There are excellent presentation tools out there. WebSlides is about good karma and sharing content. Hypertext, clean code, and beauty as narrative elements.
\* \* \* {.text-symbols}
###### Is WebSlides a framework?
We're all tired of heavy CSS frameworks. WebSlides is a starting point that provides basic
---
###### Why WebSlides?
There are excellent presentation tools out there. WebSlides is about good karma and sharing content. Hypertext, clean code, and beauty as narrative elements.
\* \* \* {.text-symbols}
###### Is WebSlides a framework?
We're all tired of heavy CSS frameworks. WebSlides is a starting point that provides basic
:::
<slide>
### Team
:::gallery

## Alicia Jiménez
Founder & CEO
---

## Sam Trololovitz
Master of nothing
---

## Erin Gustafson
VP of Design
:::
<slide>
### Team
:::gallery overlay

## Alicia Jiménez
Founder & CEO
---

## Sam Trololovitz
CTO
---

## Erin Gustafson
VP of Design
:::
<slide>
## echarts {.aligncenter}
```echarts {style="height:400px;"}
{
tooltip: {
trigger: 'item',
formatter: "{a} <br/>{b}: {c} ({d}%)"
},
legend: {
orient: 'vertical',
x: 'left',
data:['直达','营销广告','搜索引擎','邮件营销','联盟广告','视频广告','百度','谷歌','必应','其他']
},
series: [
{
name:'访问来源',
type:'pie',
selectedMode: 'single',
radius: [0, '30%'],
label: {
normal: {
position: 'inner'
}
},
labelLine: {
normal: {
show: false
}
},
data:[
{value:335, name:'直达', selected:true},
{value:679, name:'营销广告'},
{value:1548, name:'搜索引擎'}
]
},
{
name:'访问来源',
type:'pie',
radius: ['40%', '55%'],
label: {
normal: {
formatter: '{a|{a}}{abg|}\n{hr|}\n {b|{b}:}{c} {per|{d}%} ',
backgroundColor: '#eee',
borderColor: '#aaa',
borderWidth: 1,
borderRadius: 4,
// shadowBlur:3,
// shadowOffsetX: 2,
// shadowOffsetY: 2,
// shadowColor: '#999',
// padding: [0, 7],
rich: {
a: {
color: '#999',
lineHeight: 22,
align: 'center'
},
// abg: {
// backgroundColor: '#333',
// width: '100%',
// align: 'right',
// height: 22,
// borderRadius: [4, 4, 0, 0]
// },
hr: {
borderColor: '#aaa',
width: '100%',
borderWidth: 0.5,
height: 0
},
b: {
fontSize: 16,
lineHeight: 33
},
per: {
color: '#eee',
backgroundColor: '#334455',
padding: [2, 4],
borderRadius: 2
}
}
}
},
data:[
{value:335, name:'直达'},
{value:310, name:'邮件营销'},
{value:234, name:'联盟广告'},
{value:135, name:'视频广告'},
{value:1048, name:'百度'},
{value:251, name:'谷歌'},
{value:147, name:'必应'},
{value:102, name:'其他'}
]
}
]
}
```
<slide>
:::card-50

---
## Bonsai
Bonsai is a Japanese art form using trees grown in containers — .fullscreen > .card-50. {.text-intro}
Similar practices exist in other cultures, including the Chinese tradition of penjing from which the art originated, and the miniature living landscapes of Vietnamese hòn non bộ.
\* \* \* {.text-symbols}
Similar practices exist in other cultures, including the Chinese tradition of penjing from which the art originated, and the miniature living landscapes of Vietnamese hòn non
:::
<slide class="fullscreen">
:::card

---
## Bonsai
Bonsai is a Japanese art form using trees grown in containers — .fullscreen > .card-50. {.text-intro}
Similar practices exist in other cultures, including the Chinese tradition of penjing from which the art originated, and the miniature living landscapes of Vietnamese hòn non bộ.
\* \* \* {.text-symbols}
dfdasfs
:::
<slide class="bg-gradient-v">
## table
| Left-aligned | Center-aligned | Right-aligned |
| :----------- | :------------: | ------------: |
| git status | git status | git status |
| git diff | git diff | git diff |
<slide class="bg-gradient-v">
## KaTex {.aligncenter}
| equation | description |
| ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------- |
| $\nabla \cdot \vec{\mathbf{B}} = 0$ | divergence of $\vec{\mathbf{B}}$ is zero |
| $\nabla \times \vec{\mathbf{E}}\, +\, \frac1c\, \frac{\partial\vec{\mathbf{B}}}{\partial t} = \vec{\mathbf{0}}$ | curl of $\vec{\mathbf{E}}$ is proportional to the rate of change of $\vec{\mathbf{B}}$ |
| $\nabla \times \vec{\mathbf{B}} -\, \frac1c\, \frac{\partial\vec{\mathbf{E}}}{\partial t} = \frac{4\pi}{c}\vec{\mathbf{j}} \nabla \cdot \vec{\mathbf{E}} = 4 \pi \rho$ | _wha?_ |
<slide>
## **Why WebSlides?**
> "I feel guilty as a web designer when I have to use PowerPoint and Keynote. So I made #WebSlides."
<slide class="bg-black-blue">
> I have always appreciated designers who dare to reinterpret fabrics and proportions, so I follow the Japanese and Belgian designers.
> ==Zaha Hadid==
> {.text-quote}
<slide :class="aligncenter fadeInUp">
## The little things mean the most
.fadeInUp
<slide :class="aligncenter zoomIn size-40">

<slide :class="aligncenter">
## h2.fadeIn.slow {.fadeIn.slow}
================================================
FILE: packages/nodeppt-parser/__tests__/public/demo.js
================================================
console.log('demo');
================================================
FILE: packages/nodeppt-parser/defaults.js
================================================
module.exports = {
title: 'nodeppt markdown',
url: '',
speaker: '',
js: '',
theme: 'moon',
transition: 'move',
highlightStyle: 'monokai_sublime',
date: Date.now(),
htmlWebpackPlugin: `
<% for (var chunk in htmlWebpackPlugin.files.chunks) { %>
<script src="<%= htmlWebpackPlugin.files.chunks[chunk].entry %>"></script>
<% } %>
`
};
================================================
FILE: packages/nodeppt-parser/index.js
================================================
const path = require('path');
const fs = require('fs-extra');
const defaultDeep = require('lodash.defaultsdeep');
const ejs = require('ejs');
const loaderUtils = require('loader-utils');
const getParser = require('./lib/get-parser');
// parsers
const yamlParser = require('./lib/yaml-parser');
const defaults = require('./defaults');
// 模板
const defaultTemplate = fs.readFileSync(path.join(__dirname, './template/index.ejs')).toString();
// 这里不要用箭头函数,this 指向问题!
/* eslint-disable space-before-function-paren */
module.exports = function (content) {
/* eslint-enable space-before-function-paren */
const {plugins = []} = loaderUtils.getOptions(this);
const resourcePath = this.resourcePath;
const parser = getParser(plugins);
const settings = content.split(/<slide.*>/i)[0];
const yamlSettings = yamlParser(settings);
// 支持baseTemplate,传入ejs模板
let template = defaultTemplate;
if (yamlSettings.baseTemplate && typeof yamlSettings.baseTemplate === 'string') {
const baseTemplate = path.resolve(path.dirname(resourcePath), yamlSettings.baseTemplate);
if (fs.existsSync(baseTemplate)) {
template = fs.readFileSync(baseTemplate).toString();
}
}
// 首部 yaml 设置部分
const globalSettings = defaultDeep(yamlSettings, defaults);
content = parser(content);
return ejs.render(template, {...globalSettings, content});
};
================================================
FILE: packages/nodeppt-parser/lib/get-markdown-parser.js
================================================
const mdIt = require('markdown-it')();
// const prism = require('markdown-it-prism');
const prism = require('./markdown/prism');
mdIt.use(prism, {
defaultLanguageForUnknown: 'textile'
});
mdIt.use(require('markdown-it-sup'));
mdIt.use(require('markdown-it-br'));
mdIt.use(require('@ksky521/markdown-it-katex'));
mdIt.use(require('./markdown/jsx'));
mdIt.use(require('./markdown/echarts'));
// mermaid 流程图
mdIt.use(require('./markdown/mermaid'));
mdIt.use(require('./markdown/fa'));
// mdIt.use(require('./markdown/plus-list'));
mdIt.use(require('./markdown/link'));
// 注意attrs顺序
mdIt.use(require('./markdown/attrs'));
mdIt.use(require('./markdown/img'));
mdIt.use(require('./markdown/cite'));
mdIt.use(require('./markdown/span'));
mdIt.use(require('./markdown/container'), 'column', require('./markdown/containers/column'));
mdIt.use(require('./markdown/container'), 'shadowbox', require('./markdown/containers/shadow'));
mdIt.use(require('./markdown/container'), 'steps', require('./markdown/containers/steps'));
mdIt.use(require('./markdown/container'), 'card', require('./markdown/containers/card'));
// 不用了
// mdIt.use(require('./markdown/container'), 'flexbox', require('./markdown/containers/flexbox')('flexbox'));
mdIt.use(require('./markdown/container'), 'flexblock', require('./markdown/containers/flexblock'));
// 不用了
// mdIt.use(require('./markdown/container'), 'blink', require('./markdown/containers/blink'));
// mdIt.use(require('./markdown/container'), 'features', require('./markdown/containers/features'));
// 不用了
// mdIt.use(require('./markdown/container'), 'specs', require('./markdown/containers/specs'));
mdIt.use(require('./markdown/container'), 'cta', require('./markdown/containers/cta'));
mdIt.use(require('./markdown/container'), 'gallery', require('./markdown/containers/gallery'));
mdIt.use(require('./markdown/container'), 'div', require('./markdown/containers/div'));
function getMdParser(plugins) {
plugins.forEach(plugin => {
mdIt.use(plugin);
});
return mdIt.render.bind(mdIt);
}
module.exports = getMdParser;
================================================
FILE: packages/nodeppt-parser/lib/get-parser.js
================================================
const posthtml = require('posthtml');
const getMdParser = require('./get-markdown-parser');
// 内置 posthtml 插件
const buildInPlugins = [
'./tags/slide.js',
'./tags/note.js',
'./tags/header-footer.js',
// attrs放到最后
'./tags/attrs.js',
];
const buildInPosthtmlPlugins = buildInPlugins.map((file) => {
return require(file);
});
module.exports = (plugins) => {
const markdownPlugins = [];
const posthtmlPlugins = [];
plugins.forEach((p) => {
if (p && typeof p.apply === 'function') {
if (p.id.indexOf('markdown') === 0) {
markdownPlugins.push(p.apply);
} else if (p.id.indexOf('posthtml') === 0) {
posthtmlPlugins.push(p.apply);
}
}
});
const mdRender = getMdParser(markdownPlugins);
return (str) => {
const slideTag = str.match(/\n<slide\s*(.*)>/gim) || [];
const contents = str.split(/\n<slide.*>/im);
contents.shift();
return contents
.map((c, i) => {
// 生成 attr
const html = `
${slideTag[i]}
<div class="wrap" wrap="true">
${mdRender(c)}
</div>
</slide>
`;
// 生成 content ast
return posthtml(buildInPosthtmlPlugins.concat(posthtmlPlugins)).process(html, {sync: true}).html;
})
.join('\n');
};
};
================================================
FILE: packages/nodeppt-parser/lib/markdown/attrs/index.js
================================================
'use strict';
// from https://github.com/arve0/markdown-it-attrs
// 增加多个 class 支持
const patternsConfig = require('./patterns.js');
const utils = require('./utils');
const defaultOptions = {
leftDelimiter: '{',
rightDelimiter: '}'
};
module.exports = function attributes(md, options) {
if (!options) {
options = defaultOptions;
}
utils.setOptions(options);
const patterns = patternsConfig(options);
function curlyAttrs(state) {
let tokens = state.tokens;
for (let i = 0; i < tokens.length; i++) {
for (let p = 0; p < patterns.length; p++) {
let pattern = patterns[p];
gitextract_k4sj6t2_/
├── .editorconfig
├── .github/
│ └── ISSUE_TEMPLATE.md
├── .gitignore
├── .prettierrc
├── MIT-LICENSE.txt
├── README.md
├── gh-page.sh
├── lerna.json
├── package.json
├── packages/
│ ├── nodeppt/
│ │ ├── .npmignore
│ │ ├── README.md
│ │ ├── __tests__/
│ │ │ └── demo.md
│ │ ├── bin/
│ │ │ └── nodeppt
│ │ ├── commands/
│ │ │ └── new.js
│ │ ├── lib/
│ │ │ ├── ask.js
│ │ │ └── generate.js
│ │ └── package.json
│ ├── nodeppt-js/
│ │ ├── .npmignore
│ │ ├── assets/
│ │ │ └── less/
│ │ │ ├── _base.less
│ │ │ ├── _color.less
│ │ │ ├── _typography.less
│ │ │ ├── _vars.less
│ │ │ ├── full.less
│ │ │ ├── index.less
│ │ │ ├── modules/
│ │ │ │ ├── _animation.less
│ │ │ │ ├── _avatars.less
│ │ │ │ ├── _badges.less
│ │ │ │ ├── _browser.less
│ │ │ │ ├── _build.less
│ │ │ │ ├── _button.less
│ │ │ │ ├── _cards.less
│ │ │ │ ├── _flexblock-activity.less
│ │ │ │ ├── _flexblock-clients.less
│ │ │ │ ├── _flexblock-features.less
│ │ │ │ ├── _flexblock-gallery.less
│ │ │ │ ├── _flexblock-metrics.less
│ │ │ │ ├── _flexblock-plans.less
│ │ │ │ ├── _flexblock-reasons.less
│ │ │ │ ├── _flexblock-specs.less
│ │ │ │ ├── _flexblock-steps.less
│ │ │ │ ├── _flexblock.less
│ │ │ │ ├── _form.less
│ │ │ │ ├── _grid.less
│ │ │ │ ├── _header-footer.less
│ │ │ │ ├── _logo.less
│ │ │ │ ├── _longform.less
│ │ │ │ ├── _media.less
│ │ │ │ ├── _navigation.less
│ │ │ │ ├── _print.less
│ │ │ │ ├── _promos.less
│ │ │ │ ├── _quotes.less
│ │ │ │ ├── _slides-bg.less
│ │ │ │ ├── _slides-navigation.less
│ │ │ │ ├── _slides.less
│ │ │ │ ├── _speaker-note.less
│ │ │ │ ├── _tables.less
│ │ │ │ ├── _toc.less
│ │ │ │ ├── _with-note.less
│ │ │ │ ├── _work.less
│ │ │ │ └── _zoom.less
│ │ │ └── utils/
│ │ │ ├── _animations.less
│ │ │ ├── _bugs.less
│ │ │ ├── _clear.less
│ │ │ └── _reset.less
│ │ ├── index.js
│ │ ├── package.json
│ │ └── plugins/
│ │ ├── echarts.js
│ │ ├── keyboard.js
│ │ ├── mermaid.js
│ │ ├── speaker-mode.js
│ │ └── speaker-note.js
│ ├── nodeppt-parser/
│ │ ├── .npmignore
│ │ ├── __tests__/
│ │ │ ├── classes.md
│ │ │ ├── demo.md
│ │ │ └── public/
│ │ │ └── demo.js
│ │ ├── defaults.js
│ │ ├── index.js
│ │ ├── lib/
│ │ │ ├── get-markdown-parser.js
│ │ │ ├── get-parser.js
│ │ │ ├── markdown/
│ │ │ │ ├── attrs/
│ │ │ │ │ ├── index.js
│ │ │ │ │ ├── patterns.js
│ │ │ │ │ └── utils.js
│ │ │ │ ├── cite.js
│ │ │ │ ├── container.js
│ │ │ │ ├── containers/
│ │ │ │ │ ├── blink.js
│ │ │ │ │ ├── card.js
│ │ │ │ │ ├── column.js
│ │ │ │ │ ├── cta.js
│ │ │ │ │ ├── div.js
│ │ │ │ │ ├── features.js
│ │ │ │ │ ├── flexblock.js
│ │ │ │ │ ├── flexbox.js
│ │ │ │ │ ├── gallery.js
│ │ │ │ │ ├── shadow.js
│ │ │ │ │ ├── specs.js
│ │ │ │ │ └── steps.js
│ │ │ │ ├── echarts.js
│ │ │ │ ├── fa.js
│ │ │ │ ├── img.js
│ │ │ │ ├── jsx.js
│ │ │ │ ├── link.js
│ │ │ │ ├── mermaid.js
│ │ │ │ ├── plus-list.js
│ │ │ │ ├── prism.js
│ │ │ │ ├── regexp/
│ │ │ │ │ ├── index.js
│ │ │ │ │ └── utils.js
│ │ │ │ └── span.js
│ │ │ ├── tags/
│ │ │ │ ├── attrs.js
│ │ │ │ ├── header-footer.js
│ │ │ │ ├── note.js
│ │ │ │ ├── slide.js
│ │ │ │ └── utils.js
│ │ │ ├── utils.js
│ │ │ └── yaml-parser.js
│ │ ├── package.json
│ │ └── template/
│ │ └── index.ejs
│ ├── nodeppt-serve/
│ │ ├── .npmignore
│ │ ├── PluginAPI.js
│ │ ├── Service.js
│ │ ├── commands/
│ │ │ ├── build.js
│ │ │ └── serve.js
│ │ ├── config/
│ │ │ ├── app.js
│ │ │ ├── base.js
│ │ │ ├── css.js
│ │ │ ├── dev.js
│ │ │ └── prod.js
│ │ ├── index.js
│ │ ├── lib/
│ │ │ ├── globalConfigPlugin.js
│ │ │ └── utils.js
│ │ ├── options.js
│ │ ├── package.json
│ │ └── template/
│ │ ├── main.js
│ │ └── reload.js
│ └── nodeppt-shared-utils/
│ ├── .npmignore
│ ├── index.js
│ ├── lib/
│ │ ├── download-repo.js
│ │ ├── eval.js
│ │ ├── find-existing.js
│ │ ├── get-debug.js
│ │ ├── get-latest-version.js
│ │ ├── git-user.js
│ │ ├── logger.js
│ │ ├── new-version-log.js
│ │ ├── path.js
│ │ ├── plugin.js
│ │ ├── prepare-urls.js
│ │ ├── spinner.js
│ │ └── webpack-error.js
│ └── package.json
└── site/
├── animation.md
├── background.md
├── classes.md
├── component.md
├── echarts.md
├── index.md
├── layout.md
├── media.md
├── mermaid.md
└── public/
└── background.js
SYMBOL INDEX (141 symbols across 40 files)
FILE: packages/nodeppt-js/plugins/echarts.js
class Echarts (line 4) | class Echarts {
method constructor (line 5) | constructor(wsInstance) {
method onSectionEnter (line 24) | static onSectionEnter(event) {
FILE: packages/nodeppt-js/plugins/keyboard.js
class Keyboard (line 8) | class Keyboard {
method constructor (line 13) | constructor(wsInstance) {
method bindEvent_ (line 23) | bindEvent_() {
method init_ (line 31) | init_() {
method onKeyPress_ (line 45) | onKeyPress_(event) {
method goNext (line 102) | goNext() {
method goPrev (line 133) | goPrev() {
method slideBuild_ (line 179) | slideBuild_(e) {
function toArray (line 198) | function toArray(arrayLike) {
FILE: packages/nodeppt-js/plugins/mermaid.js
class Echarts (line 4) | class Echarts {
method constructor (line 5) | constructor(wsInstance) {
method onSectionEnter (line 22) | static onSectionEnter(event) {
FILE: packages/nodeppt-js/plugins/speaker-mode.js
class SpeakerMode (line 3) | class SpeakerMode {
method constructor (line 4) | constructor(wsInstance) {
method bindEvent_ (line 8) | bindEvent_() {
method onKeyPress_ (line 12) | onKeyPress_(e) {
method evtHandler_ (line 19) | evtHandler_(e) {
method init_ (line 32) | init_() {
method closeClient_ (line 55) | closeClient_() {
function parseQuery (line 62) | function parseQuery(url) {
FILE: packages/nodeppt-js/plugins/speaker-note.js
constant HEIGHT (line 3) | const HEIGHT = 0.2;
constant SCALE (line 4) | const SCALE = 1.5;
class SpeakerNote (line 5) | class SpeakerNote {
method constructor (line 6) | constructor(wsInstance) {
method toggleNote (line 25) | static toggleNote(e) {
method onSectionDisabled (line 32) | static onSectionDisabled(event) {
method onSectionEnter (line 36) | static onSectionEnter(event) {
FILE: packages/nodeppt-parser/lib/get-markdown-parser.js
function getMdParser (line 42) | function getMdParser(plugins) {
FILE: packages/nodeppt-parser/lib/markdown/attrs/index.js
function curlyAttrs (line 19) | function curlyAttrs(state) {
function test (line 55) | function test(tokens, i, t) {
function isArrayOfObjects (line 144) | function isArrayOfObjects(arr) {
function isArrayOfFunctions (line 148) | function isArrayOfFunctions(arr) {
function get (line 158) | function get(arr, n) {
function last (line 163) | function last(arr) {
FILE: packages/nodeppt-parser/lib/markdown/attrs/patterns.js
function last (line 488) | function last(arr) {
FILE: packages/nodeppt-parser/lib/markdown/attrs/utils.js
function validCurlyLength (line 184) | function validCurlyLength(curly) {
function escapeRegExp (line 253) | function escapeRegExp(s) {
constant HTML_ESCAPE_TEST_RE (line 286) | let HTML_ESCAPE_TEST_RE = /[&<>"]/;
constant HTML_ESCAPE_REPLACE_RE (line 287) | let HTML_ESCAPE_REPLACE_RE = /[&<>"]/g;
constant HTML_REPLACEMENTS (line 288) | let HTML_REPLACEMENTS = {
function replaceUnsafeChar (line 295) | function replaceUnsafeChar(ch) {
FILE: packages/nodeppt-parser/lib/markdown/cite.js
function tokenize (line 3) | function tokenize(state, silent) {
function postProcess (line 56) | function postProcess(state) {
FILE: packages/nodeppt-parser/lib/markdown/container.js
function validateDefault (line 3) | function validateDefault(params) {
function renderDefault (line 7) | function renderDefault(tokens, idx, _options, env, slf) {
function emptyFn (line 15) | function emptyFn(t) {
function container (line 29) | function container(state, startLine, endLine, silent) {
FILE: packages/nodeppt-parser/lib/markdown/containers/blink.js
method validate (line 4) | validate(params) {
method handler (line 7) | handler(state, opts, start) {
method render (line 66) | render(tokens, idx) {
FILE: packages/nodeppt-parser/lib/markdown/containers/card.js
method validate (line 6) | validate(params) {
method handler (line 9) | handler(state, opts, start) {
method render (line 94) | render(tokens, idx) {
FILE: packages/nodeppt-parser/lib/markdown/containers/column.js
method validate (line 4) | validate(params) {
method handler (line 7) | handler(state, opts) {
method render (line 55) | render(tokens, idx) {
FILE: packages/nodeppt-parser/lib/markdown/containers/cta.js
method validate (line 3) | validate(params) {
method handler (line 6) | handler(state, opts) {
method render (line 83) | render(tokens, idx) {
FILE: packages/nodeppt-parser/lib/markdown/containers/div.js
method validate (line 4) | validate(params) {
method handler (line 7) | handler(state, opts) {
method render (line 10) | render(tokens, idx) {
FILE: packages/nodeppt-parser/lib/markdown/containers/features.js
method validate (line 4) | validate(params) {
method handler (line 7) | handler(state, opts, start) {
method render (line 61) | render(tokens, idx) {
FILE: packages/nodeppt-parser/lib/markdown/containers/flexblock.js
method validate (line 4) | validate(params) {
method handler (line 7) | handler(state, opts, start, len) {
method render (line 149) | render(tokens, idx) {
FILE: packages/nodeppt-parser/lib/markdown/containers/flexbox.js
method validate (line 7) | validate(params) {
method handler (line 10) | handler(state, opts, start, end) {
method render (line 67) | render(tokens, idx) {
FILE: packages/nodeppt-parser/lib/markdown/containers/gallery.js
method validate (line 4) | validate(params) {
method handler (line 7) | handler(state, opts) {
method render (line 105) | render(tokens, idx) {
FILE: packages/nodeppt-parser/lib/markdown/containers/shadow.js
method validate (line 4) | validate(params) {
method handler (line 7) | handler(state, opts) {
method render (line 54) | render(tokens, idx) {
FILE: packages/nodeppt-parser/lib/markdown/containers/specs.js
method validate (line 4) | validate(params) {
method handler (line 7) | handler(state, opts, start) {
method render (line 61) | render(tokens, idx) {
FILE: packages/nodeppt-parser/lib/markdown/containers/steps.js
method validate (line 4) | validate(params) {
method handler (line 7) | handler(state, opts, start) {
method render (line 63) | render(tokens, idx) {
FILE: packages/nodeppt-parser/lib/markdown/plus-list.js
function findChecklists (line 1) | function findChecklists(state) {
function applyClass (line 17) | function applyClass(token) {
FILE: packages/nodeppt-parser/lib/markdown/prism.js
constant DEFAULTS (line 28) | const DEFAULTS = {
function loadPrismLang (line 43) | function loadPrismLang(lang) {
function loadPrismPlugin (line 63) | function loadPrismPlugin(name) {
function selectLanguage (line 80) | function selectLanguage(options, lang) {
function highlight (line 106) | function highlight(markdownit, options, text, lang, attrs = []) {
function checkLanguageOption (line 152) | function checkLanguageOption(options, optionName) {
function replaceFence (line 183) | function replaceFence(md, prismHighlight) {
FILE: packages/nodeppt-parser/lib/markdown/regexp/index.js
function Plugin (line 29) | function Plugin(regexp, replacer, id) {
FILE: packages/nodeppt-parser/lib/markdown/span.js
function tokenize (line 9) | function tokenize(state, silent) {
function postProcess (line 77) | function postProcess(state) {
FILE: packages/nodeppt-parser/lib/yaml-parser.js
function getSettings (line 2) | function getSettings(str) {
FILE: packages/nodeppt-serve/PluginAPI.js
class PluginAPI (line 6) | class PluginAPI {
method constructor (line 7) | constructor(id, service) {
method getEntry (line 11) | getEntry() {
method getEntryName (line 14) | getEntryName() {
method getNodepptOptions (line 17) | getNodepptOptions() {
method getCwd (line 24) | getCwd() {
method getProjectOptions (line 31) | getProjectOptions(name) {
method resolve (line 44) | resolve(p) {
method registerCommand (line 48) | registerCommand(name, opts, fn) {
method chainWebpack (line 56) | chainWebpack(fn) {
method configureWebpack (line 60) | configureWebpack(fn) {
method configureDevServer (line 64) | configureDevServer(fn) {
method resolveWebpackConfig (line 68) | resolveWebpackConfig(chainableConfig) {
method resolveChainableWebpackConfig (line 81) | resolveChainableWebpackConfig() {
FILE: packages/nodeppt-serve/Service.js
method constructor (line 16) | constructor(context, entry, {plugins, pkg, useBuiltIn, nodepptOptions} =...
method init (line 34) | init(mode) {
method loadUserOptions (line 58) | loadUserOptions() {
method run (line 89) | async run(name, args = {}, rawArgv = []) {
method resolvePlugins (line 112) | resolvePlugins(inlinePlugins, useBuiltIn) {
method resolveChainableWebpackConfig (line 143) | resolveChainableWebpackConfig() {
method resolveWebpackConfig (line 149) | resolveWebpackConfig(chainableConfig = this.resolveChainableWebpackConfi...
function cloneRuleNames (line 181) | function cloneRuleNames(to, from) {
function ensureSlash (line 195) | function ensureSlash(config, key) {
function removeSlash (line 205) | function removeSlash(config, key) {
FILE: packages/nodeppt-serve/commands/serve.js
method before (line 120) | before(app, server) {
function addDevClientToEntry (line 179) | function addDevClientToEntry(config, devClient) {
FILE: packages/nodeppt-serve/config/app.js
function ensureRelative (line 9) | function ensureRelative(outputDir, p) {
method webpack (line 74) | get webpack() {
FILE: packages/nodeppt-serve/config/css.js
function createCSSRule (line 36) | function createCSSRule(lang, test, loader, options) {
FILE: packages/nodeppt-serve/index.js
function resolveEntry (line 12) | function resolveEntry(entry) {
function createService (line 45) | function createService(context, entry, nodepptOptions, asLib, plugins = ...
FILE: packages/nodeppt-shared-utils/lib/download-repo.js
function normalize (line 24) | function normalize(repo, opts) {
FILE: packages/nodeppt-shared-utils/lib/get-latest-version.js
function getLatestVersion (line 9) | function getLatestVersion(name = 'nodeppt', registry = 'https://registry...
FILE: packages/nodeppt-shared-utils/lib/spinner.js
function getDefaultSymbol (line 10) | function getDefaultSymbol() {
FILE: packages/nodeppt/commands/new.js
constant ALIAS_MAP (line 27) | const ALIAS_MAP = process.env.alias || {
FILE: packages/nodeppt/lib/ask.js
function render (line 26) | function render(content, data) {
function prompt (line 38) | async function prompt(data, key, prompt, tplData) {
FILE: packages/nodeppt/lib/generate.js
function logMessage (line 109) | function logMessage(message, data) {
function getMetadata (line 128) | function getMetadata(dir) {
function getTemplateContent (line 148) | function getTemplateContent(dir) {
function isHandlebarTPL (line 162) | function isHandlebarTPL(content) {
function template (line 165) | function template(content, data) {
Condensed preview — 159 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (477K chars).
[
{
"path": ".editorconfig",
"chars": 249,
"preview": "root = true\n\n[*]\ncharset = utf-8\nindent_style = space\nindent_size = 4\nend_of_line = lf\ninsert_final_newline = true\ntrim_"
},
{
"path": ".github/ISSUE_TEMPLATE.md",
"chars": 455,
"preview": "\n<!--\n提issue,请注意:\n1. 请按照下面模板填写,否则issue会直接被关闭!\n2. 请使用Chrome浏览器查看样式问题,不再做其他浏览器兼容性支持;\n3. Node版本需要大于8.9,不再解决低版本问题;\n4. 请使用bui"
},
{
"path": ".gitignore",
"chars": 2325,
"preview": "yarn.lock\n/node_modules\n/.sass-cache\n/src/index.html\n/test\n/3th\n/.idea\n/.vscode\n.DS_Store\n/npm-debug.log\ndist\npublish\nou"
},
{
"path": ".prettierrc",
"chars": 223,
"preview": "{\n \"singleQuote\": true,\n \"printWidth\": 120,\n \"tabWidth\": 4,\n \"bracketSpacing\": false,\n \"overrides\": [\n "
},
{
"path": "MIT-LICENSE.txt",
"chars": 1061,
"preview": "Copyright 2013 Theowang http://js8.in\n\nPermission is hereby granted, free of charge, to any person obtaining\na copy of t"
},
{
"path": "README.md",
"chars": 10635,
"preview": "<h1 align=\"center\">nodeppt 2.0</h1>\n\n> 累死累活干不过做 PPT 的!<br/> > **查看效果:https://nodeppt.js.org**\n\n[;\nconst chalk = require('chalk');\nconst semver = require('semver"
},
{
"path": "packages/nodeppt/commands/new.js",
"chars": 3382,
"preview": "/**\n * @file init 初始化项目\n */\nconst path = require('path');\nconst fs = require('fs-extra');\n\nconst home = require('user-ho"
},
{
"path": "packages/nodeppt/lib/ask.js",
"chars": 1978,
"preview": "/**\n * @file 修改字 vue-cli,prompt 收集答案\n */\n\nconst inquirer = require('inquirer');\nconst {evaluate} = require('nodeppt-shar"
},
{
"path": "packages/nodeppt/lib/generate.js",
"chars": 4177,
"preview": "/**\n * @file 根据模板生成项目目录结构\n */\nconst path = require('path');\nconst fs = require('fs');\n\nconst exists = fs.existsSync;\n\nco"
},
{
"path": "packages/nodeppt/package.json",
"chars": 1388,
"preview": "{\n \"name\": \"nodeppt\",\n \"jsname\": \"nodeppt\",\n \"description\": \"A simple, in-browser, markdown-driven presentation"
},
{
"path": "packages/nodeppt-js/.npmignore",
"chars": 48,
"preview": "__tests__\n__mocks__\npackage-lock.json\nyarn.lock\n"
},
{
"path": "packages/nodeppt-js/assets/less/_base.less",
"chars": 3048,
"preview": "// sass-lint:disable no-vendor-prefixes\n\n/*=========================================\n1. Base --> Baseline: 8px = .8rem\n="
},
{
"path": "packages/nodeppt-js/assets/less/_color.less",
"chars": 18030,
"preview": "// sass-lint:disable no-color-literals\n// sass-lint:disable no-vendor-prefixes\n/*======================================="
},
{
"path": "packages/nodeppt-js/assets/less/_typography.less",
"chars": 8335,
"preview": "/*============================\n2. TYPOGRAPHY & LISTS\n============================== */\nhtml,\nbody {\n line-height: 1;\n"
},
{
"path": "packages/nodeppt-js/assets/less/_vars.less",
"chars": 944,
"preview": "// sass-lint:disable no-color-literals\n\n// =========\n// Colors. Names from http://chir.ag/projects/name-that-color/\n// ="
},
{
"path": "packages/nodeppt-js/assets/less/full.less",
"chars": 3276,
"preview": "/*-----------------------------------------------------------------------------------\n\t0. CSS Reset & Normalize\n\t1. Base"
},
{
"path": "packages/nodeppt-js/assets/less/index.less",
"chars": 2208,
"preview": "#webslides {\n opacity: 0;\n}\n\n.ws-ready #webslides {\n opacity: 1;\n}\n\ni.fa {\n display: inline-block;\n vertical"
},
{
"path": "packages/nodeppt-js/assets/less/modules/_animation.less",
"chars": 544,
"preview": "// 翻页效果\n\n.slide.pagedown[data-transition='slide'].past {\n animation: slideOutScaleLeft 1s forwards cubic-bezier(1, 0,"
},
{
"path": "packages/nodeppt-js/assets/less/modules/_avatars.less",
"chars": 456,
"preview": "/*=========================================\n12. Avatars - uifaces.com\n=========================================== */\n\nci"
},
{
"path": "packages/nodeppt-js/assets/less/modules/_badges.less",
"chars": 668,
"preview": "/*=== App Store Badges === */\n/* Change width and height: 216x64px, 162x48px, 135x40... */\n\n[class*='badge-'] {\n back"
},
{
"path": "packages/nodeppt-js/assets/less/modules/_browser.less",
"chars": 685,
"preview": "/*=== HTML Browser (Screenshots) ================ */\n/* <figure class=\"browser\"> img </figure> */\n\n.browser {\n border"
},
{
"path": "packages/nodeppt-js/assets/less/modules/_build.less",
"chars": 975,
"preview": "/* Builds */\n\n.build.fadeIn {\n > * {\n transition: opacity 0.5s ease-in-out 0.2s;\n }\n .tobuild {\n "
},
{
"path": "packages/nodeppt-js/assets/less/modules/_button.less",
"chars": 237,
"preview": "/* Buttons/Badges */\n[class*='button'] {\n @media (min-width: 500px) {\n & + & {\n margin-left: 1.8rem"
},
{
"path": "packages/nodeppt-js/assets/less/modules/_cards.less",
"chars": 2602,
"preview": "/*===========================================\n10. Cards\n============================================= */\n\n[class*='card-"
},
{
"path": "packages/nodeppt-js/assets/less/modules/_flexblock-activity.less",
"chars": 866,
"preview": "/*===========================================\n6.9 Block Activity <ul class=\"activity\">\nCV / News\n======================="
},
{
"path": "packages/nodeppt-js/assets/less/modules/_flexblock-clients.less",
"chars": 717,
"preview": "/*=====================================================================\n6.2 Clients Logos <ul class=\"flexblock clients\">"
},
{
"path": "packages/nodeppt-js/assets/less/modules/_flexblock-features.less",
"chars": 1387,
"preview": "/*====================================================================\n6.1 Features <ul class=\"flexblock features\">\n===="
},
{
"path": "packages/nodeppt-js/assets/less/modules/_flexblock-gallery.less",
"chars": 2484,
"preview": "/*=================================================\n6.7 Gallery - <ul class=\"flexblock gallery\">\nBlock Thumbnails li+.ov"
},
{
"path": "packages/nodeppt-js/assets/less/modules/_flexblock-metrics.less",
"chars": 563,
"preview": "/*=================================================\n6.4 Block Numbers - <ul class=\"flexblock metrics\">\n================="
},
{
"path": "packages/nodeppt-js/assets/less/modules/_flexblock-plans.less",
"chars": 1593,
"preview": "/*===============================================\n6.8 Plans / Pricing <ul class=\"flexblock plans\">\n====================="
},
{
"path": "packages/nodeppt-js/assets/less/modules/_flexblock-reasons.less",
"chars": 938,
"preview": "/*=================================================\n6.6 Reasons/Why/Numbers (counter-increment)\n<ul class=\"flexblock rea"
},
{
"path": "packages/nodeppt-js/assets/less/modules/_flexblock-specs.less",
"chars": 842,
"preview": "/*=====================================================\n6.5 Specs/Items: <ul class=\"flexblock specs\">\n=================="
},
{
"path": "packages/nodeppt-js/assets/less/modules/_flexblock-steps.less",
"chars": 660,
"preview": "/*==================================================\n6.3 flexblock.steps <ul class=\"flexblock steps\">\nAbout, Philosophy."
},
{
"path": "packages/nodeppt-js/assets/less/modules/_flexblock.less",
"chars": 1768,
"preview": "/*===============================================================\n6. Magic blocks with flexbox (Auto-fill & Equal Height"
},
{
"path": "packages/nodeppt-js/assets/less/modules/_form.less",
"chars": 2340,
"preview": "/*=========================================\n14. Forms\n=========================================== */\n\nform {\n text-al"
},
{
"path": "packages/nodeppt-js/assets/less/modules/_grid.less",
"chars": 1018,
"preview": "/*=== 1.4. Basic Grid (Flexible blocks)\nAuto-fill & Equal height === */\n\n.grid {\n clear: both;\n display: flex;\n "
},
{
"path": "packages/nodeppt-js/assets/less/modules/_header-footer.less",
"chars": 987,
"preview": "/*=========================================\n3. Header & Footer\n=========================================== */\n\n/* -- If "
},
{
"path": "packages/nodeppt-js/assets/less/modules/_logo.less",
"chars": 393,
"preview": "/*=== 3.1. Logo === */\n\n.logo {\n text-transform: lowercase;\n\n a {\n background: url('../../images/logos/logo"
},
{
"path": "packages/nodeppt-js/assets/less/modules/_longform.less",
"chars": 1225,
"preview": "/*=========================================\n15. Longform\n=========================================== */\n/* -- Posts = .w"
},
{
"path": "packages/nodeppt-js/assets/less/modules/_media.less",
"chars": 1372,
"preview": "/*=== 1.3 Responsive Media (videos, iframe...) === */\n\n.embed {\n height: 0;\n overflow: hidden;\n /*aspect ratio:"
},
{
"path": "packages/nodeppt-js/assets/less/modules/_navigation.less",
"chars": 1390,
"preview": "/*=========================================\n4. Navigation\n=========================================== */\n\n/*=== 4.1. Nav"
},
{
"path": "packages/nodeppt-js/assets/less/modules/_print.less",
"chars": 1042,
"preview": "/*=========================================\n17. PRINT\n=========================================== */\n\n// sass-lint:disab"
},
{
"path": "packages/nodeppt-js/assets/less/modules/_promos.less",
"chars": 1573,
"preview": "/*=============================================\n7. Promos/Offers (pricing, tagline, CTA...)\n============================"
},
{
"path": "packages/nodeppt-js/assets/less/modules/_quotes.less",
"chars": 1267,
"preview": "/*=========================================\n11. Quotes\n=========================================== */\n\nblockquote {\n "
},
{
"path": "packages/nodeppt-js/assets/less/modules/_slides-bg.less",
"chars": 2283,
"preview": "/*=== 5.3 Slides - Background Images/Videos === */\n\n.background,\n[class*='background-'] {\n background-repeat: no-repe"
},
{
"path": "packages/nodeppt-js/assets/less/modules/_slides-navigation.less",
"chars": 1098,
"preview": "/* === 5.2 Counter / Navigation Slides === */\n\n#navigation {\n animation: fadeIn 8s;\n bottom: 0;\n left: 0;\n "
},
{
"path": "packages/nodeppt-js/assets/less/modules/_slides.less",
"chars": 2323,
"preview": "/*============================================\n5. SLIDES (Full Screen)\nVertically and horizontally centered\n============"
},
{
"path": "packages/nodeppt-js/assets/less/modules/_speaker-note.less",
"chars": 613,
"preview": "section .speaker-note {\n animation: none;\n display: none;\n position: absolute;\n width: 100%;\n height: 100"
},
{
"path": "packages/nodeppt-js/assets/less/modules/_tables.less",
"chars": 589,
"preview": "/*=========================================\n13. Tables\n=========================================== */\n\ntable {\n margi"
},
{
"path": "packages/nodeppt-js/assets/less/modules/_toc.less",
"chars": 1434,
"preview": "/*===========================================\n9. Table of contents\n============================================= */\n\n.to"
},
{
"path": "packages/nodeppt-js/assets/less/modules/_with-note.less",
"chars": 1112,
"preview": ".with-note {\n background: rgba(0, 0, 0, 0.3);\n .slide.current,\n .slide {\n &:not([class*='bg-']) {\n "
},
{
"path": "packages/nodeppt-js/assets/less/modules/_work.less",
"chars": 1836,
"preview": "/*=========================================\n8. Work/Resumé/CV <ul class=\"work\">\n========================================"
},
{
"path": "packages/nodeppt-js/assets/less/modules/_zoom.less",
"chars": 3527,
"preview": "/*==============================================\n18. Slides Index: Thumbnails navigation gallery\n======================="
},
{
"path": "packages/nodeppt-js/assets/less/utils/_animations.less",
"chars": 2160,
"preview": "/* === 1.2 Animations ================\nJust 5 basic animations:\n.fadeIn, .fadeInUp, .zoomIn, .slideInLeft, and .slideInR"
},
{
"path": "packages/nodeppt-js/assets/less/utils/_bugs.less",
"chars": 302,
"preview": "/*=========================================\n16. SAFARI BUGS (flex-wrap)\nSolution: stackoverflow.com/questions/34250282/f"
},
{
"path": "packages/nodeppt-js/assets/less/utils/_clear.less",
"chars": 200,
"preview": "/*=== Clearing === */\n\nheader,\nmain,\nsection,\naside,\nfooter,\n.clear,\n.wrap {\n &:before,\n &:after {\n content"
},
{
"path": "packages/nodeppt-js/assets/less/utils/_reset.less",
"chars": 2755,
"preview": "// sass-lint:disable no-vendor-prefixes\n/*\n=========================================\n0. CSS Reset & Normalize\n=========="
},
{
"path": "packages/nodeppt-js/index.js",
"chars": 697,
"preview": "import WebSlides from 'webslides/src/js/modules/webslides';\nimport './assets/less/full.less';\nimport './assets/less/inde"
},
{
"path": "packages/nodeppt-js/package.json",
"chars": 907,
"preview": "{\n \"name\": \"nodeppt-js\",\n \"version\": \"2.2.1\",\n \"description\": \"\",\n \"main\": \"index.js\",\n \"scripts\": {\n "
},
{
"path": "packages/nodeppt-js/plugins/echarts.js",
"chars": 1687,
"preview": "import DOM from 'webslides/src/js/utils/dom';\nimport {default as Slide, Events as SlideEvents} from 'webslides/src/js/mo"
},
{
"path": "packages/nodeppt-js/plugins/keyboard.js",
"chars": 5918,
"preview": "import Keys from 'webslides/src/js//utils/keys';\nimport DOM from 'webslides/src/js/utils/dom';\n\n/**\n * Keyboard interact"
},
{
"path": "packages/nodeppt-js/plugins/mermaid.js",
"chars": 1435,
"preview": "import DOM from 'webslides/src/js/utils/dom';\nimport {default as Slide, Events as SlideEvents} from 'webslides/src/js/mo"
},
{
"path": "packages/nodeppt-js/plugins/speaker-mode.js",
"chars": 2211,
"preview": "// import Keyboard from 'webslides/src/js/plugins/keyboard';\n\nexport default class SpeakerMode {\n constructor(wsInsta"
},
{
"path": "packages/nodeppt-js/plugins/speaker-note.js",
"chars": 1514,
"preview": "import DOM from 'webslides/src/js/utils/dom';\nimport {default as Slide, Events as SlideEvents} from 'webslides/src/js/mo"
},
{
"path": "packages/nodeppt-parser/.npmignore",
"chars": 20,
"preview": "__tests__\n__mocks__\n"
},
{
"path": "packages/nodeppt-parser/__tests__/classes.md",
"chars": 22615,
"preview": "\ntitle: nodeppt Classes 演示\nspeaker: 三水清\nurl: https://github.com/ksky521/nodeppt\ncss:\n - https://fonts.googleapis.com/css"
},
{
"path": "packages/nodeppt-parser/__tests__/demo.md",
"chars": 16954,
"preview": "title: nodeppt markdown 演示\nspeaker: 三水清\nurl: https://github.com/ksky521/nodeppt\njs:\n - https://www.echartsjs.com/asse"
},
{
"path": "packages/nodeppt-parser/__tests__/public/demo.js",
"chars": 21,
"preview": "console.log('demo');\n"
},
{
"path": "packages/nodeppt-parser/defaults.js",
"chars": 379,
"preview": "module.exports = {\n title: 'nodeppt markdown',\n url: '',\n speaker: '',\n js: '',\n theme: 'moon',\n trans"
},
{
"path": "packages/nodeppt-parser/index.js",
"chars": 1401,
"preview": "const path = require('path');\nconst fs = require('fs-extra');\nconst defaultDeep = require('lodash.defaultsdeep');\nconst "
},
{
"path": "packages/nodeppt-parser/lib/get-markdown-parser.js",
"chars": 2073,
"preview": "const mdIt = require('markdown-it')();\n// const prism = require('markdown-it-prism');\nconst prism = require('./markdown/"
},
{
"path": "packages/nodeppt-parser/lib/get-parser.js",
"chars": 1369,
"preview": "const posthtml = require('posthtml');\nconst getMdParser = require('./get-markdown-parser');\n// 内置 posthtml 插件\nconst buil"
},
{
"path": "packages/nodeppt-parser/lib/markdown/attrs/index.js",
"chars": 4930,
"preview": "'use strict';\n// from https://github.com/arve0/markdown-it-attrs\n// 增加多个 class 支持\nconst patternsConfig = require('./patt"
},
{
"path": "packages/nodeppt-parser/lib/markdown/attrs/patterns.js",
"chars": 17428,
"preview": "'use strict';\n/**\n * If a pattern matches the token stream,\n * then run transform.\n */\n\nconst utils = require('./utils.j"
},
{
"path": "packages/nodeppt-parser/lib/markdown/attrs/utils.js",
"chars": 9374,
"preview": "'use strict';\nexports.findAttrs = (attrArray, name, getValueOnly = true) => {\n let rs = (attrArray || []).find(([key,"
},
{
"path": "packages/nodeppt-parser/lib/markdown/cite.js",
"chars": 3390,
"preview": "module.exports = function ins_plugin(md) {\n // https://github.com/markdown-it/markdown-it-mark/blob/master/index.js\n "
},
{
"path": "packages/nodeppt-parser/lib/markdown/container.js",
"chars": 5103,
"preview": "// 参考 markdown-it-container\nmodule.exports = function container_plugin(md, name, options) {\n function validateDefault"
},
{
"path": "packages/nodeppt-parser/lib/markdown/containers/blink.js",
"chars": 3367,
"preview": "const name = 'blink';\n\nmodule.exports = {\n validate(params) {\n return params.trim().match(new RegExp('^' + nam"
},
{
"path": "packages/nodeppt-parser/lib/markdown/containers/card.js",
"chars": 4585,
"preview": "const utils = require('../attrs/utils');\nconst attrOptions = utils.getOptions();\nconst name = 'card';\n\nmodule.exports = "
},
{
"path": "packages/nodeppt-parser/lib/markdown/containers/column.js",
"chars": 2692,
"preview": "const name = 'column';\n\nmodule.exports = {\n validate(params) {\n return params.trim().match(/^column\\s*(.*)$/);"
},
{
"path": "packages/nodeppt-parser/lib/markdown/containers/cta.js",
"chars": 3655,
"preview": "const name = 'cta';\nmodule.exports = {\n validate(params) {\n return params.trim().match(new RegExp('^' + name +"
},
{
"path": "packages/nodeppt-parser/lib/markdown/containers/div.js",
"chars": 744,
"preview": "const {getAttrs, getAttrsString} = require('../attrs/utils');\n\nmodule.exports = {\n validate(params) {\n return "
},
{
"path": "packages/nodeppt-parser/lib/markdown/containers/features.js",
"chars": 3157,
"preview": "const name = 'features';\n\nmodule.exports = {\n validate(params) {\n return params.trim().match(new RegExp('^' + "
},
{
"path": "packages/nodeppt-parser/lib/markdown/containers/flexblock.js",
"chars": 6772,
"preview": "const utils = require('../attrs/utils');\nconst attrOptions = utils.getOptions();\nmodule.exports = {\n validate(params)"
},
{
"path": "packages/nodeppt-parser/lib/markdown/containers/flexbox.js",
"chars": 3633,
"preview": "module.exports = (name, clss) => {\n if (!clss) {\n // 默认是 name\n clss = name;\n }\n return {\n "
},
{
"path": "packages/nodeppt-parser/lib/markdown/containers/gallery.js",
"chars": 5099,
"preview": "const name = 'gallery';\n\nmodule.exports = {\n validate(params) {\n return params.trim().match(/^gallery(|-overla"
},
{
"path": "packages/nodeppt-parser/lib/markdown/containers/shadow.js",
"chars": 2730,
"preview": "const name = 'shadowbox';\n\nmodule.exports = {\n validate(params) {\n return params.trim().match(/^shadowbox\\s*(."
},
{
"path": "packages/nodeppt-parser/lib/markdown/containers/specs.js",
"chars": 3138,
"preview": "const name = 'specs';\n\nmodule.exports = {\n validate(params) {\n return params.trim().match(new RegExp('^' + nam"
},
{
"path": "packages/nodeppt-parser/lib/markdown/containers/steps.js",
"chars": 3106,
"preview": "const name = 'steps';\n\nmodule.exports = {\n validate(params) {\n return params.trim().match(new RegExp('^' + nam"
},
{
"path": "packages/nodeppt-parser/lib/markdown/echarts.js",
"chars": 937,
"preview": "module.exports = md => {\n const temp = md.renderer.rules.fence.bind(md.renderer.rules);\n md.renderer.rules.fence ="
},
{
"path": "packages/nodeppt-parser/lib/markdown/fa.js",
"chars": 2980,
"preview": "const mditr = require('./regexp');\n\nmodule.exports = md => {\n // FA4 style.\n md.use(\n mditr(\n /\\"
},
{
"path": "packages/nodeppt-parser/lib/markdown/img.js",
"chars": 3091,
"preview": "const mditr = require('./regexp');\n\nconst {getAttrs, getAttrsString} = require('./attrs/utils');\n\nmodule.exports = md =>"
},
{
"path": "packages/nodeppt-parser/lib/markdown/jsx.js",
"chars": 3383,
"preview": "'use strict';\n// from https://github.com/osnr/markdown-it-jsx/\nvar jsx_inline = require('markdown-it-jsx/lib/jsx_inline'"
},
{
"path": "packages/nodeppt-parser/lib/markdown/link.js",
"chars": 1796,
"preview": "module.exports = md => {\n const defLinkOpen =\n md.renderer.rules.link_open ||\n function(tokens, idx, op"
},
{
"path": "packages/nodeppt-parser/lib/markdown/mermaid.js",
"chars": 738,
"preview": "module.exports = md => {\n const temp = md.renderer.rules.fence.bind(md.renderer.rules);\n md.renderer.rules.fence ="
},
{
"path": "packages/nodeppt-parser/lib/markdown/plus-list.js",
"chars": 1247,
"preview": "function findChecklists(state) {\n // console.log(state.tokens);\n state.tokens.forEach((token, i) => {\n if ("
},
{
"path": "packages/nodeppt-parser/lib/markdown/prism.js",
"chars": 7535,
"preview": "// https://github.com/jGleitz/markdown-it-prism/\n// 增加attrs支持\nconst Prism = require('prismjs');\n\n/**\n * A callback that "
},
{
"path": "packages/nodeppt-parser/lib/markdown/regexp/index.js",
"chars": 1918,
"preview": "/*!\n * markdown-it-regexp\n * Copyright (c) 2014 Alex Kocharin\n * MIT Licensed\n */\n\n/**\n * Module dependencies.\n */\n\nvar "
},
{
"path": "packages/nodeppt-parser/lib/markdown/regexp/utils.js",
"chars": 426,
"preview": "/*!\n * markdown-it-regexp\n * Copyright (c) 2014 Alex Kocharin\n * MIT Licensed\n */\n\n/**\n * Escape special characters in t"
},
{
"path": "packages/nodeppt-parser/lib/markdown/span.js",
"chars": 4505,
"preview": "const Utils = require('./attrs/utils');\n\nconst hasDelimiters = Utils.hasDelimiters('only', Utils.getOptions());\n\n// 修改 h"
},
{
"path": "packages/nodeppt-parser/lib/tags/attrs.js",
"chars": 1421,
"preview": "const {mergeAttrs} = require('../utils');\n\nmodule.exports = tree => {\n tree.walk(node => {\n if (\n n"
},
{
"path": "packages/nodeppt-parser/lib/tags/header-footer.js",
"chars": 863,
"preview": "const utils = require('./utils');\n\nmodule.exports = tree => {\n let {slideNode, wrapNode} = utils(tree);\n\n if (wrap"
},
{
"path": "packages/nodeppt-parser/lib/tags/note.js",
"chars": 1028,
"preview": "const utils = require('./utils');\n\nmodule.exports = tree => {\n let {slideNode, wrapNode} = utils(tree);\n\n if (wrap"
},
{
"path": "packages/nodeppt-parser/lib/tags/slide.js",
"chars": 5886,
"preview": "const {mergeAttrs} = require('../utils');\n\nconst {getAttrs, getAttrsString} = require('../markdown/attrs/utils');\n\n/**\n "
},
{
"path": "packages/nodeppt-parser/lib/tags/utils.js",
"chars": 431,
"preview": "module.exports = tree => {\n let slide;\n tree.match({tag: 'section'}, node => {\n if (node.attrs && node.attr"
},
{
"path": "packages/nodeppt-parser/lib/utils.js",
"chars": 465,
"preview": "exports.mergeAttrs = (attrs1, attrs2 = {}) => {\n for (let i in attrs2) {\n switch (i) {\n case 'class"
},
{
"path": "packages/nodeppt-parser/lib/yaml-parser.js",
"chars": 615,
"preview": "const yaml = require('js-yaml');\nfunction getSettings(str) {\n const settings = yaml.load(str);\n const pluginSettin"
},
{
"path": "packages/nodeppt-parser/package.json",
"chars": 1295,
"preview": "{\n \"name\": \"nodeppt-parser\",\n \"version\": \"2.2.1\",\n \"description\": \"\",\n \"main\": \"index.js\",\n \"scripts\": {\n"
},
{
"path": "packages/nodeppt-parser/template/index.ejs",
"chars": 2944,
"preview": "<!--\n Powered By nodeppt - This is probably the best web presentation tool so far!\n date: <%= date %>\n-->\n<!doctyp"
},
{
"path": "packages/nodeppt-serve/.npmignore",
"chars": 48,
"preview": "__tests__\n__mocks__\npackage-lock.json\nyarn.lock\n"
},
{
"path": "packages/nodeppt-serve/PluginAPI.js",
"chars": 2083,
"preview": "/**\n * @file pluginAPI from vue cli\n */\nconst path = require('path');\n\nclass PluginAPI {\n constructor(id, service) {\n"
},
{
"path": "packages/nodeppt-serve/Service.js",
"chars": 7034,
"preview": "/**\n * @file 简版Service\n */\nconst path = require('path');\nconst fs = require('fs');\nconst Config = require('webpack-chain"
},
{
"path": "packages/nodeppt-serve/commands/build.js",
"chars": 1133,
"preview": "/**\n * @file build 主要内容\n */\nconst {info} = require('nodeppt-shared-utils');\nconst path = require('path');\nmodule.exports"
},
{
"path": "packages/nodeppt-serve/commands/serve.js",
"chars": 7203,
"preview": "/**\n * 部分代码来自 vue cli\n * @file serve 主要内容\n */\nconst {info, prepareUrls, getLatestVersion, newVersionLog} = require('node"
},
{
"path": "packages/nodeppt-serve/config/app.js",
"chars": 6659,
"preview": "/**\n * @file app\n */\nconst fs = require('fs');\nconst path = require('path');\n\n// ensure the filename passed to html-webp"
},
{
"path": "packages/nodeppt-serve/config/base.js",
"chars": 4608,
"preview": "/**\n * @file base\n */\n// const path = require('path');\nconst webpack = require('webpack');\nconst {transformer, formatter"
},
{
"path": "packages/nodeppt-serve/config/css.js",
"chars": 3231,
"preview": "/**\n * @file css webpack\n */\n\n// const {findExisting} = require('nodeppt-shared-utils');\nconst getAssetPath = require('."
},
{
"path": "packages/nodeppt-serve/config/dev.js",
"chars": 801,
"preview": "/**\n * @file dev webpack\n */\nmodule.exports = (api, options) => {\n api.chainWebpack(webpackConfig => {\n if (pr"
},
{
"path": "packages/nodeppt-serve/config/prod.js",
"chars": 1257,
"preview": "/**\n * @file prod webpack\n */\nconst OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin');\nconst Terse"
},
{
"path": "packages/nodeppt-serve/index.js",
"chars": 1576,
"preview": "/**\n * @file hulk -serve\n */\nconst fs = require('fs');\nconst path = require('path');\nconst chalk = require('chalk');\n\nco"
},
{
"path": "packages/nodeppt-serve/lib/globalConfigPlugin.js",
"chars": 1042,
"preview": "/**\n * @file global config plugin\n */\nconst path = require('path');\nconst {findExisting} = require('nodeppt-shared-utils"
},
{
"path": "packages/nodeppt-serve/lib/utils.js",
"chars": 1042,
"preview": "const fs = require('fs');\nconst path = require('path');\nconst {findExisting, chalk} = require('nodeppt-shared-utils');\n\n"
},
{
"path": "packages/nodeppt-serve/options.js",
"chars": 1541,
"preview": "/**\n * @file 默认配置\n */\nmodule.exports = () => ({\n // project deployment base\n baseUrl: '/',\n\n // where to output"
},
{
"path": "packages/nodeppt-serve/package.json",
"chars": 1839,
"preview": "{\n \"name\": \"nodeppt-serve\",\n \"version\": \"2.2.1\",\n \"description\": \"\",\n \"main\": \"index.js\",\n \"scripts\": {\n "
},
{
"path": "packages/nodeppt-serve/template/main.js",
"chars": 346,
"preview": "/**\n * 页面的 main.js\n */\nimport Slide from 'nodeppt-js';\nif (typeof window === 'object' && Array.isArray(window.WSPlugins_"
},
{
"path": "packages/nodeppt-serve/template/reload.js",
"chars": 238,
"preview": "if (module.hot) {\n var hotEmitter = require('webpack/hot/emitter');\n hotEmitter.on('webpackHotUpdate', currentHash"
},
{
"path": "packages/nodeppt-shared-utils/.npmignore",
"chars": 48,
"preview": "__tests__\n__mocks__\npackage-lock.json\nyarn.lock\n"
},
{
"path": "packages/nodeppt-shared-utils/index.js",
"chars": 351,
"preview": "/**\n * @file 工具函数导出\n */\n\n[\n 'logger',\n 'spinner',\n 'get-debug',\n 'eval',\n 'path',\n 'new-version-log',\n"
},
{
"path": "packages/nodeppt-shared-utils/lib/download-repo.js",
"chars": 1804,
"preview": "/**\n * @file 下载 icon repo\n */\nconst gitclone = require('git-clone');\nconst rm = require('fs-extra').removeSync;\nconst de"
},
{
"path": "packages/nodeppt-shared-utils/lib/eval.js",
"chars": 353,
"preview": "/**\n * @file 用于计算判断条件\n */\n\nconst chalk = require('chalk');\n\nexports.evaluate = (exp, data) => {\n /* eslint-disable no"
},
{
"path": "packages/nodeppt-shared-utils/lib/find-existing.js",
"chars": 258,
"preview": "/**\n * @file 查找存在的文件\n */\nconst fs = require('fs');\nconst path = require('path');\n\nexports.findExisting = (context, files"
},
{
"path": "packages/nodeppt-shared-utils/lib/get-debug.js",
"chars": 229,
"preview": "/**\n * @file get debug\n */\nconst {name} = require('../package.json');\nconst debug = require('debug');\nexports.getDebugLo"
},
{
"path": "packages/nodeppt-shared-utils/lib/get-latest-version.js",
"chars": 847,
"preview": "/**\n * @file check version\n */\n\nconst request = require('request');\nconst debug = require('./get-debug').getDebugLogger("
},
{
"path": "packages/nodeppt-shared-utils/lib/git-user.js",
"chars": 584,
"preview": "/**\n * @file 获取 git 用户名和邮箱\n */\n\nconst exec = require('child_process').execSync;\n\nexports.getGitUser = () => {\n let na"
},
{
"path": "packages/nodeppt-shared-utils/lib/logger.js",
"chars": 1894,
"preview": "/**\n * @file logger 封装\n */\n\nconst chalk = require('chalk');\nconst readline = require('readline');\nconst padStart = requi"
},
{
"path": "packages/nodeppt-shared-utils/lib/new-version-log.js",
"chars": 546,
"preview": "const chalk = require('chalk');\nconst boxen = require('boxen');\nexports.newVersionLog = (currentVersion, newVersion) => "
},
{
"path": "packages/nodeppt-shared-utils/lib/path.js",
"chars": 332,
"preview": "/**\n * @file 跟路径相关\n */\nconst path = require('path');\n\nexports.isLocalPath = templatePath => {\n return /^[./]|(^[a-zA-"
},
{
"path": "packages/nodeppt-shared-utils/lib/plugin.js",
"chars": 723,
"preview": "/**\n * @file plugin 相关\n */\nconst pluginRE = /^nodeppt-plugin-/;\nconst scopeRE = /^@[\\w-]+\\//;\n\nexports.isPlugin = id => "
},
{
"path": "packages/nodeppt-shared-utils/lib/prepare-urls.js",
"chars": 1774,
"preview": "const chalk = require('chalk');\nconst url = require('url');\nconst address = require('address');\n\nexports.prepareUrls = ("
},
{
"path": "packages/nodeppt-shared-utils/lib/spinner.js",
"chars": 1350,
"preview": "/**\n * @file loading 转圈效果\n */\nconst ora = require('ora');\nconst chalk = require('chalk');\n\nconst spinner = ora();\nlet la"
},
{
"path": "packages/nodeppt-shared-utils/lib/webpack-error.js",
"chars": 1369,
"preview": "const chalk = require('chalk');\nconst rules = [\n {\n type: 'cant-resolve-loader',\n re: /Can't resolve '("
},
{
"path": "packages/nodeppt-shared-utils/package.json",
"chars": 1081,
"preview": "{\n \"name\": \"nodeppt-shared-utils\",\n \"version\": \"2.2.1\",\n \"description\": \"\",\n \"main\": \"index.js\",\n \"script"
},
{
"path": "site/animation.md",
"chars": 3842,
"preview": "\ntitle: nodeppt 动效演示\nspeaker: 三水清\nurl: https://github.com/ksky521/nodeppt\n\n<slide class=\"bg-gradient-v\" image=\"https://s"
},
{
"path": "site/background.md",
"chars": 5023,
"preview": "title: nodeppt 背景效果演示\nspeaker: 三水清\nurl: https://github.com/ksky521/nodeppt\njs:\n - background.js\n\n<slide class=\"bg-bla"
},
{
"path": "site/classes.md",
"chars": 9205,
"preview": "\ntitle: nodeppt 样式演示\nspeaker: 三水清\nurl: https://github.com/ksky521/nodeppt\nwebslidesOptions:\n autoslide: 5000\n\n<slide "
},
{
"path": "site/component.md",
"chars": 12172,
"preview": "title: nodeppt 组件演示\nspeaker: 三水清\nurl: https://github.com/ksky521/nodeppt\n\n<slide class=\"bg-black-blue aligncenter\" image"
},
{
"path": "site/echarts.md",
"chars": 4263,
"preview": "title: nodeppt 富媒体&插件演示\nspeaker: 三水清\nurl: https://github.com/ksky521/nodeppt\njs:\n - https://echarts.cdn.apache.org/zh"
},
{
"path": "site/index.md",
"chars": 24893,
"preview": "title: nodeppt - 这可能是迄今为止最好的网页版演示库\nspeaker: 三水清\nurl: https://github.com/ksky521/nodeppt\njs:\n - https://echarts.cdn.ap"
},
{
"path": "site/layout.md",
"chars": 3900,
"preview": "title: nodeppt Layout 布局演示\nspeaker: 三水清\nurl: https://github.com/ksky521/nodeppt\n\n<slide class=\"bg-black-blue aligncenter"
},
{
"path": "site/media.md",
"chars": 8880,
"preview": "title: nodeppt 富媒体&插件演示\nspeaker: 三水清\nurl: https://github.com/ksky521/nodeppt\njs:\n - https://www.echartsjs.com/asset/t"
},
{
"path": "site/mermaid.md",
"chars": 3640,
"preview": "title: nodeppt - 这可能是迄今为止最好的网页版演示库\nspeaker: 三水清\nurl: https://github.com/ksky521/nodeppt\nplugins:\n - mermaid: {theme: "
},
{
"path": "site/public/background.js",
"chars": 294,
"preview": "(function() {\n window.changeBackgroundColor = cls => {\n const classList = wsInstance.currentSlide_.el.classLis"
}
]
About this extraction
This page contains the full source code of the ksky521/nodeppt GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 159 files (434.6 KB), approximately 118.0k tokens, and a symbol index with 141 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.