Browse Source

Merge pull request #884 from transloadit/fix/website-highlight

Improve syntax highlighting on the website
Artur Paikin 6 years ago
parent
commit
4fafee8681

+ 2 - 2
package.json

@@ -134,8 +134,8 @@
     "build:lib": "babel --version && babel src --source-maps -d lib",
     "build": "npm-run-all --parallel build:js build:css --serial build:gzip size",
     "clean": "rm -rf lib && rm -rf dist",
-    "lint:fix": "eslint src test website/build-examples.js website/update.js website/themes/uppy/source/js/common.js --fix",
-    "lint": "eslint src test website/build-examples.js website/update.js website/themes/uppy/source/js/common.js",
+    "lint:fix": "eslint src test website/scripts website/build-examples.js website/update.js website/themes/uppy/source/js/common.js --fix",
+    "lint": "eslint src test website/scripts website/build-examples.js website/update.js website/themes/uppy/source/js/common.js",
     "lint-staged": "lint-staged",
     "release:major": "env SEMANTIC=major npm run release",
     "release:minor": "env SEMANTIC=minor npm run release",

+ 1 - 2
website/_config.yml

@@ -51,9 +51,8 @@ filename_case: 0
 render_drafts: false
 post_asset_folder: false
 highlight:
-  enable: true
+  enable: false
   line_number: false
-  tab_replace:
 
 # Category & Tag
 default_category: uncategorized

+ 51 - 0
website/package-lock.json

@@ -2860,6 +2860,17 @@
         "restore-cursor": "^1.0.1"
       }
     },
+    "clipboard": {
+      "version": "2.0.1",
+      "resolved": "https://registry.npmjs.org/clipboard/-/clipboard-2.0.1.tgz",
+      "integrity": "sha512-7yhQBmtN+uYZmfRjjVjKa0dZdWuabzpSKGtyQZN+9C8xlC788SSJjOHWh7tzurfwTqTD5UDYAhIv5fRJg3sHjQ==",
+      "optional": true,
+      "requires": {
+        "good-listener": "^1.2.2",
+        "select": "^1.1.2",
+        "tiny-emitter": "^2.0.0"
+      }
+    },
     "cliui": {
       "version": "3.2.0",
       "resolved": "https://registry.npmjs.org/cliui/-/cliui-3.2.0.tgz",
@@ -3508,6 +3519,12 @@
       "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
       "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk="
     },
+    "delegate": {
+      "version": "3.2.0",
+      "resolved": "https://registry.npmjs.org/delegate/-/delegate-3.2.0.tgz",
+      "integrity": "sha512-IofjkYBZaZivn0V8nnsMJGBr4jVLxHDheKSW88PyxS5QC4Vo9ZbZVvhzlSxY87fVq3STR6r+4cGepyHkcWOQSw==",
+      "optional": true
+    },
     "delegates": {
       "version": "1.0.0",
       "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz",
@@ -5737,6 +5754,15 @@
         }
       }
     },
+    "good-listener": {
+      "version": "1.2.2",
+      "resolved": "https://registry.npmjs.org/good-listener/-/good-listener-1.2.2.tgz",
+      "integrity": "sha1-1TswzfkxPf+33JoNR3CWqm0UXFA=",
+      "optional": true,
+      "requires": {
+        "delegate": "^3.1.2"
+      }
+    },
     "graceful-fs": {
       "version": "4.1.11",
       "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz",
@@ -5878,6 +5904,11 @@
         "sntp": "1.x.x"
       }
     },
+    "he": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/he/-/he-1.1.1.tgz",
+      "integrity": "sha1-k0EP0hsAlzUVH4howvJx80J+I/0="
+    },
     "header-case": {
       "version": "1.0.1",
       "resolved": "https://registry.npmjs.org/header-case/-/header-case-1.0.1.tgz",
@@ -9708,6 +9739,14 @@
       "resolved": "https://registry.npmjs.org/pretty-hrtime/-/pretty-hrtime-1.0.3.tgz",
       "integrity": "sha1-t+PqQkNaTJsnWdmeDyAesZWALuE="
     },
+    "prismjs": {
+      "version": "1.14.0",
+      "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.14.0.tgz",
+      "integrity": "sha512-sa2s4m60bXs+kU3jcuUwx3ZCrUH7o0kuqnOOINbODqlRrDB7KY8SRx+xR/D7nHLlgfDdG7zXbRO8wJ+su5Ls0A==",
+      "requires": {
+        "clipboard": "^2.0.0"
+      }
+    },
     "private": {
       "version": "0.1.8",
       "resolved": "https://registry.npmjs.org/private/-/private-0.1.8.tgz",
@@ -10419,6 +10458,12 @@
         }
       }
     },
+    "select": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/select/-/select-1.1.2.tgz",
+      "integrity": "sha1-DnNQrN7ICxEIUoeG7B1EGNEbOW0=",
+      "optional": true
+    },
     "semver": {
       "version": "5.4.1",
       "resolved": "https://registry.npmjs.org/semver/-/semver-5.4.1.tgz",
@@ -11232,6 +11277,12 @@
         "process": "~0.11.0"
       }
     },
+    "tiny-emitter": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/tiny-emitter/-/tiny-emitter-2.0.2.tgz",
+      "integrity": "sha512-2NM0auVBGft5tee/OxP4PI3d8WItkDM+fPnaRAVo6xTDI2knbz9eC5ArWGqtGlYqiH3RU5yMpdyTTO7MguC4ow==",
+      "optional": true
+    },
     "tiny-lr": {
       "version": "0.2.1",
       "resolved": "https://registry.npmjs.org/tiny-lr/-/tiny-lr-0.2.1.tgz",

+ 3 - 1
website/package.json

@@ -8,6 +8,7 @@
   "dependencies": {
     "autoprefixer": "^7.2.6",
     "cssnano": "^3.10.0",
+    "he": "^1.1.1",
     "hexo": "^3.7.1",
     "hexo-browsersync": "^0.3.0",
     "hexo-deployer-git": "^0.3.1",
@@ -26,7 +27,8 @@
     "hexo-util": "^0.6.3",
     "js-yaml": "^3.11.0",
     "mkdirp": "0.5.1",
-    "postcss-inline-svg": "^3.1.1"
+    "postcss-inline-svg": "^3.1.1",
+    "prismjs": "^1.14.0"
   },
   "devDependencies": {
     "aliasify": "^2.1.0",

+ 58 - 0
website/scripts/highlight.js

@@ -0,0 +1,58 @@
+/* global hexo */
+const Prism = require('prismjs')
+const entities = require('he')
+const { promisify } = require('util')
+const readFile = promisify(require('fs').readFile)
+const path = require('path')
+
+const unhighlightedCodeRx = /<pre><code class="(.*)?">([\s\S]*?)<\/code><\/pre>/igm
+
+function highlight (lang, code) {
+  const startTag = `<figure class="highlight ${lang}"><table><tr><td class="code"><pre>`
+  const endTag = `</pre></td></tr></table></figure>`
+  let parsedCode = ''
+  if (Prism.languages[lang]) {
+    parsedCode = Prism.highlight(code, Prism.languages[lang])
+  } else {
+    parsedCode = code
+  }
+
+  return startTag + parsedCode + endTag
+}
+
+function prismify (data) {
+  data.content = data.content.replace(unhighlightedCodeRx,
+    (_, lang, code) => highlight(lang, entities.decode(code)))
+
+  return data
+}
+
+function code (args, content) {
+  let lang = ''
+  if (args[0].startsWith('lang:')) {
+    lang = args.shift().replace(/^lang:/, '')
+  }
+
+  return highlight(lang, content)
+}
+
+function includeCode (args) {
+  let lang = ''
+  if (args[0].startsWith('lang:')) {
+    lang = args.shift().replace(/^lang:/, '')
+  }
+
+  const file = path.join(hexo.source_dir, hexo.config.code_dir, args.join(' '))
+  return readFile(file, 'utf8').then((code) => highlight(lang, code.trim()))
+}
+
+// Highlight as many things as we possibly can
+hexo.extend.tag.register('code', code, true)
+hexo.extend.tag.register('codeblock', code, true)
+hexo.extend.tag.register('include_code', includeCode, { async: true })
+hexo.extend.tag.register('include-code', includeCode, { async: true })
+
+// Hexo includes its own code block handling by default which may
+// cause the above to miss some things, so do another pass when the page
+// is done rendering to pick up any code blocks we may have missed.
+hexo.extend.filter.register('after_post_render', prismify)

+ 1 - 1
website/src/api-usage-example.ejs → website/src/api-usage-example.js

@@ -1,7 +1,7 @@
 import Uppy from 'uppy/lib/core'
 import Dashboard from 'uppy/lib/plugins/Dashboard'
 import Tus from 'uppy/lib/plugins/Tus'
- 
+
 Uppy({ autoProceed: false })
   .use(Dashboard, { trigger: '#select-files' })
   .use(Tus, { endpoint: 'https://master.tus.io/files/' })

+ 0 - 149
website/src/docs/architecture.md

@@ -1,149 +0,0 @@
----
-type: api
-order: 10
-title: "Architecture"
-permalink: api/architecture/
-published: false
----
-
-Uppy file uploader consists of a lean [Core](https://github.com/transloadit/uppy/blob/master/src/core/Core.js) module and [Plugins](https://github.com/transloadit/uppy/tree/master/src/plugins) (see simple [Input](https://github.com/transloadit/uppy/blob/master/src/plugins/Formtag.js) as an example) that extend it’s functionality. Like this:
-
-{% include_code lang:js ../api-usage-example.ejs %}
-
-## Core
-
-1. Core module orchestrates Uppy plugins, stores `state` with `files`, and exposes useful methods like `addFile`, `setState`, `upload` to the user and plugins. Plugins are added to Uppy with `.use(Plugin, opts)` API, like so: `.use(DragDrop, {target: 'body'})`.
-
-2. Internally Core then instantiates plugins via `new Plugin(this, opts)`, passing options to them, then places them in `plugins` object, nested by type: `uploader`, `progressindicator`, `acquirer`, etc. Core then iterates over `plugins` and calls `install` on each of them. In it’s `install` method a plugin can set event listeners to react to things happening in Uppy (upload progress, file was removed), or do anything else needed on init.
-
-3. Each time `state` is updated with `setState(statePatch)`, Core runs `updateAll()` method that re-renders all of the view plugins (components) that have been mounted in the DOM somewhere, passing the new state to each of them.
-
-Core is very lean (at least we try to keep it sobe), and acts as a glue that ties together all the plugins, shared data and functionality together. It keeps `state` with `files`, `capabilities`, plus exposes a few methods that are called by plugins to update state — adding files, adding preview thumbnails to images, updating progress for each file and total progress, etc.
-
-*Comment: There is a discussion that these methods could in theory all live in Utils or be standalone modules used by plugins and the user directly, see https://github.com/transloadit/uppy/issues/116#issuecomment-247695921.*
-
-### getState()
-
-Returns current state.
-
-### setState({itemToUpdate: data})
-
-Updates state with new state (Object.assign({}, this.state, newState)) and then runs `updateAll()`.
-
-### updateAll()
-
-Iterates over all `plugins` and runs `update()` on each of them.
-
-### updateMeta(data, fileID)
-
-Given `{ size: 1200 }` adds that metadata to a file.
-
-### addFile(file)
-
-Adds a new file to `state`. This method is used by `acquirer` plugins like Drag & Drop, Webcam and Google Drive,
-or can be called by the user on uppy instance directly: `uppy.addFile(myFile)`.
-
-Normalizes that file too: tries to figure out file type by extension if mime is missing, use noname if name is missing, sets progress: 0  and so on.
-
-### removeFile(fileID)
-
-Removes file from `state.files`.
-
-### addThumbnail(fileID)
-
-Reads image from file’s data object in base64 and resizes that, using canvas. Then `state` is updated with a file that has thumbnail in it. Thumbnails are used for file previews by plugins like Dashboard.
-
-### state.capabilities
-
-Core (or plugins) check and set capabilities, like: `resumable: true` (this is set by Tus Plugin), `touch: false`, `dragdrop: true`, that could possibly be used by all plugins.
-
-### log(msg)
-
-Logs stuff to console only if user specified `debug: true`, silent in production.
-
-### core.on('event', action), core.emit('event')
-
-An event emitter embedded into Core that is passed to Plugins, and can be used directly on the instance. Used by Plugins for communicating with other Plugins and Core.
-
-## Events
-
-- Core listens for `core:upload-progress` event and calculates speed & ETA for all files currently in progress. *Uploader plugins could just call core.updateProgress().*
-- Core checks if browser in offline or online and emits `core:is-offline` or `core:is-online` that other plugins can listen to.
-- Any plugin can emit `informer` event that `Informer` plugin can use to display info bubbles. Currently only used in the Dashboard plugin. Example: `core.emitter.emit('informer', 'Connected!', 'success', 3000)`. *(Should this be a Core method instead of Plugin? Could be replaced by core.inform(info) method that will just update state with info)*
-- Uploader plugins listen to `core:upload` event (can be emitted after a file has been added or when upload button has been pressed), get files via `core.getState().files`, filter those that are not marked as complete and upload them, emitting progress events.
-
-*See discussion about Core and Event Emitter: https://github.com/transloadit/uppy/issues/116#issuecomment-247695921*
-
-## Plugins
-
-Plugins extend the functionality of Core (which itself is very much barebones, does almost nothing). Plugins actually do the work — select files, modify and upload them, and show the UI.
-
-Plugins that have some UI can be mounted anywhere in the dom. With current design you can have a Drag & Drop area in `#dragdrop` and Progressbar in `body`. Plugins can also be mounted into other plugins that support that, like Dashboard.
-
-Each plugin extends `Plugin` class with default methods that can be overridden:
-
-### update()
-
-Gets called when state changes and `updateAll()` is called from Core. Checks if a DOM element (tree) has been created with a reference for it stored in plugin’s `this.el`. If so, creates a new element (tree) `const newEl = this.render(currentState)` for current plugin and then calls `yo.update(this.el, newEl)` to effectively update the existing element to match the new one (morphdom is behind that).
-
-All together now:
-
-``` javascript
-const newEl = this.render(currentState)
-yo.update(this.el, newEl)
-```
-
-### mount(target, plugin)
-
-Called by the plugin itself, if it is a UI plugin that needs to do something in DOM. A `target` is passed as an argument. There are two possible scenarios for mounting:
-
-1\. If `typeof target === 'string'`, then the element (tree) is rendered and gets mounted to the DOM:
-
-``` javascript
-this.el = plugin.render(this.core.state)
-document.querySelector(target).appendChild(this.el)
-```
-
-2\. If `typeof target === 'object'`, then that plugin is found in `plugins` object of Core and `addTarget()` is called on that plugin.
-
-``` javascript
-const targetPlugin = this.core.getPlugin(targetPluginName)
-const selectorTarget = targetPlugin.addTarget(plugin)
-```
-
-### focus()
-
-Called when plugin is in focus, like when that plugin’s tab is selected in the Dashboard.
-
-### install()
-
-Called by Core when it instantiates new plugins. In `install`
-a plugin can extend global state with its own state (like `{ modal: { isHidden: true } }`), or do anything needed on initialization, including `mount()`.
-
-### Plugins are currently of the following types:
-
-### acquirer
-
-- **DragDrop** — simple DragDrop, once file is dropped on a target, it gets added to state.files. “click here to select” too
-- **GoogleDrive** — GoogleDrive UI, uses uppy-server component. Files are downloaded from Google Drive to uppy-server, without having to go through the client, saving bandwidth and space
-- **Formtag** — simple input[type=file] element
-- **Webcam** — allows to take pictures with your webcam, works in most browsers, except Safari. Flash (ugh) is used for fallback
-
-### orchestrator
-
-*Should probably be called UI*
-
-- **Dashboard** — the full-featured interface for interacting with Uppy. Supports drag & dropping files, provides UI for Google Drive, Webcam and any other plugin, shows selected files, shows progress on them.
-
-### progressindicator
-
-- **ProgressBar** — tiny progressbar that can be mounted anywhere.
-
-### uploader
-
-- **Tus** — tus resumable file uploads, see http://tus.io
-- **Multipart** — regular form/multipart/xhr uploads
-
-### modifier
-
-- **Metadata** — allows adding custom metadata fields, data from each field is then added to a file

+ 1 - 1
website/src/frontpage-code-sample.ejs

@@ -9,4 +9,4 @@ save it as a layout partial
 $ npm install uppy
 {% endcodeblock %}
 
-{% include_code lang:js ../api-usage-example.ejs %}
+{% include_code lang:js ../api-usage-example.js %}

+ 11 - 2
website/themes/uppy/layout/partials/frontpage-code-sample.html

@@ -2,6 +2,15 @@
 You can `npm run web:update:frontpage:code:sample` to render this code snippet and
 save it as a layout partial
 -->
-<figure class="highlight bash"><table><tr><td class="code"><pre><div class="line">$ npm install uppy</div></pre></td></tr></table></figure>
+<figure class="highlight bash"><table><tr><td class="code"><pre>$ npm install uppy</pre></td></tr></table></figure>
 
-<figure class="highlight js"><figcaption><span>api-usage-example.ejs</span><a href="/examples/../api-usage-example.ejs">view raw</a></figcaption><table><tr><td class="code"><pre><div class="line"><span class="keyword">import</span> Uppy <span class="keyword">from</span> <span class="string">'uppy/lib/core'</span></div><div class="line"><span class="keyword">import</span> Dashboard <span class="keyword">from</span> <span class="string">'uppy/lib/plugins/Dashboard'</span></div><div class="line"><span class="keyword">import</span> Tus <span class="keyword">from</span> <span class="string">'uppy/lib/plugins/Tus'</span></div><div class="line"> </div><div class="line">Uppy({ autoProceed: <span class="literal">false</span> })</div><div class="line">  .use(Dashboard, { trigger: <span class="string">'#select-files'</span> })</div><div class="line">  .use(Tus, { endpoint: <span class="string">'https://master.tus.io/files/'</span> })</div><div class="line">  .run()</div><div class="line">  .on(<span class="string">'complete'</span>, (result) =&gt; {</div><div class="line">    <span class="built_in">console</span>.log(<span class="string">'Upload result:'</span>, result)</div><div class="line">  })</div></pre></td></tr></table></figure>
+<figure class="highlight js"><table><tr><td class="code"><pre><span class="token keyword">import</span> Uppy <span class="token keyword">from</span> <span class="token string">'uppy/lib/core'</span>
+<span class="token keyword">import</span> Dashboard <span class="token keyword">from</span> <span class="token string">'uppy/lib/plugins/Dashboard'</span>
+<span class="token keyword">import</span> Tus <span class="token keyword">from</span> <span class="token string">'uppy/lib/plugins/Tus'</span>
+ 
+<span class="token function">Uppy</span><span class="token punctuation">(</span><span class="token punctuation">{</span> autoProceed<span class="token punctuation">:</span> <span class="token boolean">false</span> <span class="token punctuation">}</span><span class="token punctuation">)</span>
+  <span class="token punctuation">.</span><span class="token function">use</span><span class="token punctuation">(</span>Dashboard<span class="token punctuation">,</span> <span class="token punctuation">{</span> trigger<span class="token punctuation">:</span> <span class="token string">'#select-files'</span> <span class="token punctuation">}</span><span class="token punctuation">)</span>
+  <span class="token punctuation">.</span><span class="token function">use</span><span class="token punctuation">(</span>Tus<span class="token punctuation">,</span> <span class="token punctuation">{</span> endpoint<span class="token punctuation">:</span> <span class="token string">'https://master.tus.io/files/'</span> <span class="token punctuation">}</span><span class="token punctuation">)</span>
+  <span class="token punctuation">.</span><span class="token function">on</span><span class="token punctuation">(</span><span class="token string">'complete'</span><span class="token punctuation">,</span> <span class="token punctuation">(</span>result<span class="token punctuation">)</span> <span class="token operator">=></span> <span class="token punctuation">{</span>
+    console<span class="token punctuation">.</span><span class="token function">log</span><span class="token punctuation">(</span><span class="token string">'Upload result:'</span><span class="token punctuation">,</span> result<span class="token punctuation">)</span>
+  <span class="token punctuation">}</span><span class="token punctuation">)</span></pre></td></tr></table></figure>

+ 16 - 97
website/themes/uppy/source/css/_syntax.scss

@@ -4,101 +4,20 @@
 
 pre {
   color: #525252;
-
-  .function .keyword,
-  .constant {
-    color: #0092db;
-  }
-
-  .line {
-    min-height: 1em;
-  }
-
-  .keyword,
-  .attribute {
-    color: #e96900;
-  }
-
-  .number,
-  .literal {
-    color: #AE81FF;
-  }
-
-  .tag,
-  .tag .title,
-  .change,
-  .winutils,
-  .flow,
-  .lisp .title,
-  .clojure .built_in,
-  .nginx .title,
-  .tex .special {
-    color: #2973b7;
-  }
-
-  .class .title {
-    color: white;
-  }
-
-  .symbol,
-  .symbol .string,
-  .value,
-  .regexp {
-    color: $color-green;
-  }
-
-  .title {
-    color: #A6E22E;
-  }
-
-  .tag .value,
-  .string,
-  .subst,
-  .haskell .type,
-  .preprocessor,
-  .ruby .class .parent,
-  .built_in,
-  .sql .aggregate,
-  .django .template_tag,
-  .django .variable,
-  .smalltalk .class,
-  .javadoc,
-  .django .filter .argument,
-  .smalltalk .localvars,
-  .smalltalk .array,
-  .attr_selector,
-  .pseudo,
-  .addition,
-  .stream,
-  .envvar,
-  .apache .tag,
-  .apache .cbracket,
-  .tex .command,
-  .prompt {
-    color: $color-green;
-  }
-
-  .comment,
-  .java .annotation,
-  .python .decorator,
-  .template_comment,
-  .pi,
-  .doctype,
-  .deletion,
-  .shebang,
-  .apache .sqbracket,
-  .tex .formula {
-    color: #b3b3b3;
-  }
-
-  .coffeescript .javascript,
-  .javascript .xml,
-  .tex .formula,
-  .xml .javascript,
-  .xml .vbscript,
-  .xml .css,
-  .xml .cdata {
-    opacity: 0.5
-  }
-
+  // background-color: #f8f8f8 !important;
+  // font-size: .8em !important;
+  // .token.function, .token.punctuation { color: inherit; }
+
+  // Generic
+  .token.comment { color: #b3b3b3; }
+
+  // JS
+  .token.keyword { color: #e96900; }
+  .token.number, .token.boolean { color: #AE81FF; }
+  .token.class-name { color: #2973b7; }
+  .token.string { color: $color-green; }
+
+  // HTML
+  .token.tag { color: #2973b7; }
+  .token.attr-value { color: $color-green; }
 }