├── .editorconfig ├── .gitattributes ├── .github └── workflows │ └── ci.yml ├── .gitignore ├── .prettierrc ├── .releaserc.json ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── docs ├── README.md ├── index.html ├── main.ts └── vite.config.ts ├── package.json ├── pnpm-lock.yaml ├── postcss.config.js ├── scripts ├── build.ts └── utils.ts ├── src ├── components │ ├── App.tsx │ ├── Main.tsx │ ├── Navbar.tsx │ └── Sidebar.tsx ├── css │ ├── content.css │ ├── main.css │ ├── prism.css │ └── tailwind.css ├── docup.ts ├── markdown-component.ts ├── markdown.ts ├── renderer │ ├── fre.ts │ └── preact.ts └── utils.ts ├── tailwind.config.js ├── test_prod ├── README.md └── index.html ├── tsconfig.json └── types.d.ts /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | indent_style = space 5 | indent_size = 2 6 | end_of_line = lf 7 | charset = utf-8 8 | trim_trailing_whitespace = true 9 | insert_final_newline = true 10 | 11 | [*.md] 12 | trim_trailing_whitespace = false -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto 2 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: Node.js CI 2 | 3 | on: 4 | push: 5 | branches: [main, dev] 6 | pull_request: 7 | branches: [main, dev] 8 | 9 | jobs: 10 | test: 11 | # skip "ci skip" unless a issue comment explictly asks 12 | if: "!contains(github.event.head_commit.message, 'ci skip')" 13 | 14 | strategy: 15 | matrix: 16 | os: [ubuntu-latest] 17 | 18 | runs-on: ${{ matrix.os }} 19 | 20 | # Steps represent a sequence of tasks that will be executed as part of the job 21 | steps: 22 | # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it 23 | - uses: actions/checkout@v2 24 | 25 | - uses: actions/setup-node@v1 26 | with: 27 | node-version: 14.x 28 | 29 | - name: Cache ~/.pnpm-store 30 | uses: actions/cache@v2 31 | env: 32 | cache-name: cache-pnpm-store 33 | with: 34 | path: ~/.pnpm-store 35 | key: ${{ runner.os }}-${{ matrix.node-version }}-build-${{ env.cache-name }}-${{ hashFiles('**/pnpm-lock.yaml') }} 36 | restore-keys: | 37 | ${{ runner.os }}-${{ matrix.node-version }}-build-${{ env.cache-name }}- 38 | ${{ runner.os }}-${{ matrix.node-version }}-build- 39 | ${{ runner.os }}- 40 | - name: Install pnpm 41 | run: npm i -g pnpm 42 | 43 | - name: Install deps 44 | run: pnpm i 45 | 46 | # Runs a set of commands using the runners shell 47 | - name: Build and Test 48 | run: npm run test 49 | 50 | - name: Release 51 | if: "github.event_name != 'pull_request'" 52 | run: pnpx semantic-release --branches main 53 | env: 54 | GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} 55 | NPM_TOKEN: ${{ secrets.NPM_TOKEN }} 56 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | dist 3 | .DS_Store 4 | *.log 5 | yarn.lock 6 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "singleQuote": true, 3 | "semi": false 4 | } 5 | -------------------------------------------------------------------------------- /.releaserc.json: -------------------------------------------------------------------------------- 1 | { 2 | "branches": ["master"], 3 | "plugins": [ 4 | [ 5 | "@semantic-release/commit-analyzer", 6 | { 7 | "preset": "angular", 8 | "releaseRules": [ 9 | { "type": "refactor", "release": "patch" }, 10 | { "type": "style", "release": "patch" }, 11 | { "scope": "no-release", "release": false }, 12 | { "scope": "style", "release": "patch" } 13 | ] 14 | } 15 | ], 16 | "@semantic-release/release-notes-generator", 17 | "@semantic-release/npm", 18 | "@semantic-release/github" 19 | ] 20 | } 21 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | ## Local development 4 | 5 | ```bash 6 | yarn dev 7 | ``` 8 | 9 | ## Tests 10 | 11 | Soon. 12 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) EGOIST <0x142857@gmail.com> (https://github.com/egoist) 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Docup 2 | 3 | **Docup** is a single JavaScript file that fetches Markdown file and renders it as a beautiful one-page documentation. 4 | 5 | Docup is built with Preact, the entire bundle (with CSS) is just 30kB minified and gzipped. 6 | 7 | [View Documentation](https://docup.now.sh) 8 | 9 | [Donate](https://github.com/sponsors/egoist) 10 | 11 | ## Liense 12 | 13 | MIT © [EGOIST (Kevin Titor)](https://github.com/sponsors/egoist) 14 | -------------------------------------------------------------------------------- /docs/README.md: -------------------------------------------------------------------------------- 1 |
2 | 3 | **Docup** is a single JavaScript file that fetches Markdown file and renders it as a beautiful one-page documentation. 4 | 5 | Docup is built with Preact, the entire bundle (with CSS) is just 30kB minified and gzipped. 6 | 7 |
8 | 9 | ## Quick Start 10 | 11 | Create an HTML file: `index.html` which will be be homepage of your documentation website: 12 | 13 | ```html 14 | 15 | 16 | 17 | 18 | 19 | 23 | My Awesome Doc 24 | 25 | 29 | 30 | 31 | 32 | 39 | 40 | 41 | ``` 42 | 43 | Then populate a `README.md` file to the same directory where `index.html` is located. 44 | 45 | ```md 46 | ## Introduction 47 | 48 | How about this. 49 | 50 | ## Advanced 51 | 52 | How about that. 53 | ``` 54 | 55 | Finally serve this directory as a static website: 56 | 57 | - **node.js**: `npm i -g static-server && static-server .` 58 | - **deno**: `deno install --allow-net --allow-read https://deno.land/std/http/file_server.ts && file_server .` 59 | - **python**: `python -m SimpleHTTPServer` 60 | - ...etc, you can use any static file server, for real. 61 | 62 | ### How Files Are Resolved 63 | 64 | If current `location.pathname` is `/`, i.e. the homepage, it fetches `/README.md`. 65 | 66 | If current `location.pathname` is `/docs/`, it fetches `/docs/README.md`. 67 | 68 | If current `location.pathname` is `/docs/en`, it fetches `/docs/en.md`. 69 | 70 | Basically if the pathname ends with a slash, we treat it as a directory and try to load the `README.md` file under that path, you can also use [indexFile](#indexfile) option to change `README.md` to other file if you want. If the pathname does not end with slash, we would fetch `pathname + '.md'`. 71 | 72 | You can also use [root](#root) option to set the origin of the files, for example if you want to load files from other domain, you can set `root: 'https://sub.domain.com/data'`. 73 | 74 | ## Guide 75 | 76 | ### Site Title 77 | 78 | We use the value of `document.title` if it's not `undefined`, you can also set a title via options: 79 | 80 | ```js 81 | docup.init({ 82 | title: 'My Website', 83 | }) 84 | ``` 85 | 86 | ### Markdown Features 87 | 88 | We use the blazing fast [marked](https://marked.js.org) to parse Markdown, all [GitHub Flavored Markdown](https://github.github.com/gfm/) features are supported. 89 | 90 | ### Message Blocks 91 | 92 | To highlight some messages in your documentation, use the following format to write a `blockquote`: 93 | 94 | ```md 95 | > [TYPE]: This is a very dangerous action! 96 | ``` 97 | 98 | Where `[TYPE]` can be: 99 | 100 | - `Alert` 101 | - `Warning` 102 | - `Info` 103 | - `Success` 104 | - `Note` 105 | 106 | And they look like: 107 | 108 | > **Alert**: This is an alert! 109 | 110 | > **Warning**: This is a warning! 111 | 112 | > **Info**: This is a info! 113 | 114 | > **Success**: This is a success! 115 | 116 | > **Note**: This is just a note! 117 | 118 | ### Embedding 119 | 120 | Embedding and running code snippets is easy if your provider supports iframe, like [codesandbox.io](https://codesandbox.io): 121 | 122 | ```html 123 | 129 | ``` 130 | 131 | ### Highlight 132 | 133 | Docup uses [Prism.js](http://prismjs.com/) to highlight code blocks, by default only a few languages are supported, namely: `html` `css` `js` `markdown` `bash` `json`, you can manually load Prism language components to support more languages, e.g. for Go programming language: 134 | 135 | ```js 136 | docup.init({ 137 | highlightLanguages: ['go'], 138 | }) 139 | ``` 140 | 141 | Available languages: 142 | 143 | ```js preact 144 | import { useState, html } from 'docup' 145 | export default ({ langs }) => { 146 | return html`` 149 | } 150 | ``` 151 | 152 | ### Inline Component 153 | 154 | You can inline Preact, React and Vue 3 components inside Markdown file like this: 155 | 156 | ````markdown 157 | ```js preact 158 | import { useState, html } from 'docup' 159 | 160 | export default () => { 161 | const [count, setCount] = useState(0) 162 | return html`` 168 | } 169 | ``` 170 | ```` 171 | 172 | Write `preact` next to the language name and we will render the code as a Preact component in place: 173 | 174 | ```js preact 175 | import { useState, html } from 'docup' 176 | 177 | export default () => { 178 | const [count, setCount] = useState(0) 179 | return html`` 185 | } 186 | ``` 187 | 188 | > Warning: Note that you can't use JSX here, because it's not supported by browsers natively. But you can use the `html` function which is powered by [developit/htm](https://github.com/developit/htm). By default `docup` re-exports all functions from `preact` plus a preact-powered `html` function. 189 | 190 | See another example with React: 191 | 192 | ```js react,keep 193 | import React from 'react' 194 | import Trend from 'react-trend' 195 | import htm from 'htm' 196 | 197 | const html = htm.bind(React.createElement) 198 | 199 | export default () => html`<${Trend} 200 | smooth 201 | autoDraw 202 | autoDrawDuration="{3000}" 203 | autoDrawEasing="ease-out" 204 | data=${[0, 2, 5, 9, 5, 10, 3, 5, 0, 0, 1, 8, 2, 9, 0]} 205 | gradient=${['#00c6ff', '#F0F', '#FF0']} 206 | radius=${10} 207 | strokeWidth=${2} 208 | strokeLinecap=${'butt'} 209 | />` 210 | ``` 211 | 212 | When the code block is recognized as a component, the code itself will be removed from the markdown, if you want to show the code block below the rendered component, you can use the `keep` keyword: 213 | 214 | ````markdown 215 | ```js react,keep 216 | export default () => {} 217 | ``` 218 | ```` 219 | 220 | If you want to show the code block above the component, use `keepAbove` instead. 221 | 222 | ### CSS Variables 223 | 224 | ```js preact 225 | import { html } from 'docup' 226 | 227 | function getAllCSSVariableNames(styleSheets = document.styleSheets) { 228 | var cssVars = [] 229 | // loop each stylesheet 230 | for (var i = 0; i < styleSheets.length; i++) { 231 | // loop stylesheet's cssRules 232 | try { 233 | // try/catch used because 'hasOwnProperty' doesn't work 234 | for (var j = 0; j < styleSheets[i].cssRules.length; j++) { 235 | try { 236 | // loop stylesheet's cssRules' style (property names) 237 | for (var k = 0; k < styleSheets[i].cssRules[j].style.length; k++) { 238 | let name = styleSheets[i].cssRules[j].style[k] 239 | // test name for css variable signature and uniqueness 240 | if ( 241 | name.startsWith('--') && 242 | cssVars.indexOf(name) == -1 && 243 | !name.startsWith('--tw-') 244 | ) { 245 | cssVars.push(name) 246 | } 247 | } 248 | } catch (error) {} 249 | } 250 | } catch (error) {} 251 | } 252 | return cssVars 253 | } 254 | 255 | function getElementCSSVariables(allCSSVars, element = document.body, pseudo) { 256 | var elStyles = window.getComputedStyle(element, pseudo) 257 | var cssVars = {} 258 | for (var i = 0; i < allCSSVars.length; i++) { 259 | let key = allCSSVars[i] 260 | let value = elStyles.getPropertyValue(key) 261 | if (value) { 262 | cssVars[key] = value.trim() 263 | } 264 | } 265 | return cssVars 266 | } 267 | 268 | export default () => { 269 | const vars = getElementCSSVariables( 270 | getAllCSSVariableNames(), 271 | document.documentElement 272 | ) 273 | 274 | return html` 275 | 276 | 277 | 278 | 280 | 281 | 282 | 283 | ${Object.keys(vars).map((name) => { 284 | const value = vars[name] 285 | const isColor = /-(bg|fg)$/.test(name) 286 | return html` 287 | 290 | 311 | ` 312 | })} 313 | 314 |
Variable Name 279 | Value
288 | ${name} 289 | 291 | ${isColor 292 | ? html`
299 | ${value} 308 |
` 309 | : html`${value}`} 310 |
315 | ` 316 | } 317 | ``` 318 | 319 | ### Multiple Pages 320 | 321 | If your doc is too long to display in a single page, you can split it into multiple Markdown files, that works because Docup [fetches Markdown file based on the current `pathname`](#how-files-are-resolved). 322 | 323 | Then all you need is to route all requests to the `index.html`. (Also known as SPA fallback) 324 | 325 | If you host your docs on [Netlify](https://netlify.com), use following rule in `_redirects` file: 326 | 327 | ``` 328 | /* /index.html 301 329 | ``` 330 | 331 | Or if you're using [Vercel](https://vercel.com), use following config in `vercel.json`: 332 | 333 | ```json 334 | { 335 | "rewrites": [ 336 | { 337 | "source": "/(.*)", 338 | "destination": "/index.html" 339 | } 340 | ] 341 | } 342 | ``` 343 | 344 | Or Nginx config: 345 | 346 | ```nginx 347 | location / { 348 | try_files /index.html =404; 349 | } 350 | ``` 351 | 352 | ## Deploy 353 | 354 | ### GitHub Pages 355 | 356 | Simply put all your files in `docs` folder on `master` branch, or root directory on the `gh-pages` branch. 357 | 358 | Then enable it on repo's `settings` page: 359 | 360 | ![gh-pages enable](https://i.loli.net/2017/12/04/5a24edfb02a93.png) 361 | 362 | Don't forget to add `.nojekyll` file to tell GitHub to treat it as a normal static website. 363 | 364 | ### Netlify 365 | 366 | Set the public directory to where your `index.html` is located at. 367 | 368 | ### Vercel 369 | 370 | Set the public directory to where your `index.html` is located at. 371 | 372 | ## API 373 | 374 | ```js 375 | docup.init(options) 376 | ``` 377 | 378 | ### options 379 | 380 | #### title 381 | 382 | - Type: `string` 383 | 384 | The title that is shown in the navbar. It defaults to `document.title` 385 | 386 | 395 | 396 | #### navLinks 397 | 398 | - Type: `NavLink[]` 399 | 400 | Links in the navbar. 401 | 402 | ```ts 403 | interface NavLink { 404 | text: string 405 | link: string 406 | } 407 | ``` 408 | 409 | #### indexFile 410 | 411 | - Type: `string` 412 | - Default: `README.md` 413 | 414 | Used for path ending with a slash. 415 | 416 | #### base 417 | 418 | - Type: `string` 419 | - Default: `/` 420 | 421 | The base path your website is located at. If you are serving your docs under a sub path like `https://user.github.io/awesome-project`, you need to set this option to `/awesome-project`. 422 | 423 | #### root 424 | 425 | - Type: `string` 426 | - Default: `''` 427 | 428 | The root path we use to resolve files from. 429 | 430 | #### highlightLanguages 431 | 432 | - Type: `string[]` 433 | 434 | Extra languages to highlight. 435 | 436 | #### font 437 | 438 | - Type: `string` 439 | - Default: `Lato` 440 | 441 | Use a custom font from Google Fonts. We use [Lato](https://fonts.google.com/specimen/Lato) by default. 442 | 443 | #### props 444 | 445 | - Type: `any` 446 | 447 | Inject props to inlined components. 448 | 449 | For example: 450 | 451 | ```js 452 | docup.init({ 453 | props: { 454 | count: 0, 455 | }, 456 | }) 457 | ``` 458 | 459 | Then you can inline component and use props in Markdown: 460 | 461 | ````markdown 462 | ```js preact 463 | import { html } from 'docup' 464 | export default ({ count }) => { 465 | return html`` 466 | } 467 | ``` 468 | ```` 469 | 470 | #### useSystemTheme 471 | 472 | - Type: `boolean` 473 | - Default: `true` 474 | 475 | Follow system theme, i.e. use dark theme when system theme is dark. 476 | 477 | #### beforeSidebar 478 | 479 | - Type: `string` 480 | 481 | HTML string to display before sidebar. 482 | 483 | ## Browser support 484 | 485 | Last 2 versions of modern browsers. 486 | 487 | ## Resources 488 | 489 | ### Discord Chat 490 | 491 | Join my [Discord Community](https://chat.egoist.sh). 492 | 493 | ### GitHub Sponsors 494 | 495 | Support this project via [GitHub Sponsors](https://github.com/sponsors/egoist). 496 | 497 | ## License 498 | 499 | MIT © EGOIST 500 | -------------------------------------------------------------------------------- /docs/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Docup 7 | 11 | 12 | 13 | 14 | 18 | 19 | 20 |
21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /docs/main.ts: -------------------------------------------------------------------------------- 1 | import { init } from '../src/docup' 2 | 3 | export * from '../src/docup' 4 | 5 | init({ 6 | title: 'Docup', 7 | highlightLanguages: ['nginx'], 8 | props: { 9 | langs: PRISM_LANGUAGES, 10 | }, 11 | beforeSidebar: `
12 |
13 | SPONSOR 14 |
15 | 19 |
`, 20 | navLinks: [ 21 | { 22 | text: 'Guide', 23 | link: '#guide', 24 | }, 25 | { 26 | text: 'API', 27 | link: '#api', 28 | }, 29 | { 30 | text: 'Resources', 31 | link: '#resources', 32 | }, 33 | { 34 | text: 'GitHub', 35 | link: 'https://github.com/egoist/docup', 36 | }, 37 | { 38 | text: 'Donate', 39 | link: 'https://github.com/sponsors/egoist', 40 | }, 41 | ], 42 | }) 43 | -------------------------------------------------------------------------------- /docs/vite.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite' 2 | import prefresh from '@prefresh/vite' 3 | import { createConfig } from '../scripts/utils' 4 | 5 | export default defineConfig((ctx) => { 6 | const config = createConfig( 7 | 'preact', 8 | ctx.mode === 'production' && !process.env.DEBUG, 9 | true 10 | ) 11 | return { 12 | ...config, 13 | plugins: [...(config.plugins || []), prefresh()], 14 | } 15 | }) 16 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@egoist/docup", 3 | "version": "1.0.0", 4 | "description": "Simple yet elegant docs.", 5 | "repository": { 6 | "url": "https://github.com/egoist/docup.git", 7 | "type": "git" 8 | }, 9 | "files": [ 10 | "dist" 11 | ], 12 | "types": "dist/docup.d.ts", 13 | "unpkg": "dist/docup.min.js", 14 | "cdn": "dist/docup.min.js", 15 | "jsdelivr": "dist/docup.min.js", 16 | "main": "dist/docup.js", 17 | "module": "dist/docup.js", 18 | "publishConfig": { 19 | "access": "public" 20 | }, 21 | "scripts": { 22 | "test": "echo skip", 23 | "build": "rm -rf dist && cross-env NODE_ENV=production node -r esbuild-register scripts/build.ts", 24 | "dev": "vite docs", 25 | "dev:fre": "cross-env vite docs NODE_ENV=fre", 26 | "build:website": "vite build docs && cp docs/README.md docs/dist/", 27 | "prepublishOnly": "npm run build" 28 | }, 29 | "author": "egoist <0x142857@gmail.com>", 30 | "license": "MIT", 31 | "dependencies": { 32 | "element-in-view": "^0.1.0", 33 | "htm": "^3.0.4", 34 | "marked": "^2.0.0", 35 | "preact": "^10.5.12", 36 | "prismjs": "^1.23.0" 37 | }, 38 | "devDependencies": { 39 | "@egoist/rollup-plugin-ts-resolve": "^0.1.0", 40 | "@prefresh/vite": "^2.2.8", 41 | "@rollup/plugin-alias": "^3.1.2", 42 | "@rollup/plugin-commonjs": "^17.1.0", 43 | "@rollup/plugin-node-resolve": "^11.2.0", 44 | "@types/debug": "^4.1.5", 45 | "@types/marked": "^1.2.2", 46 | "@types/prismjs": "^1.16.3", 47 | "cross-env": "7.0.3", 48 | "debug": "^4.3.1", 49 | "esbuild": "^0.14.51", 50 | "esbuild-register": "^3.2.0", 51 | "fre": "^2.0.4", 52 | "postcss-nested": "^5.0.6", 53 | "prettier": "^2.2.1", 54 | "rollup": "^2.61.0", 55 | "rollup-plugin-dts": "^4.0.1", 56 | "tailwindcss": "^3.1.7", 57 | "type-fest": "^0.21.2", 58 | "typescript": "^4.2.3", 59 | "vite": "^3.0.4" 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /pnpm-lock.yaml: -------------------------------------------------------------------------------- 1 | lockfileVersion: 5.4 2 | 3 | specifiers: 4 | '@egoist/rollup-plugin-ts-resolve': ^0.1.0 5 | '@prefresh/vite': ^2.2.8 6 | '@rollup/plugin-alias': ^3.1.2 7 | '@rollup/plugin-commonjs': ^17.1.0 8 | '@rollup/plugin-node-resolve': ^11.2.0 9 | '@types/debug': ^4.1.5 10 | '@types/marked': ^1.2.2 11 | '@types/prismjs': ^1.16.3 12 | cross-env: 7.0.3 13 | debug: ^4.3.1 14 | element-in-view: ^0.1.0 15 | esbuild: ^0.14.51 16 | esbuild-register: ^3.2.0 17 | fre: ^2.0.4 18 | htm: ^3.0.4 19 | marked: ^2.0.0 20 | postcss-nested: ^5.0.6 21 | preact: ^10.5.12 22 | prettier: ^2.2.1 23 | prismjs: ^1.23.0 24 | rollup: ^2.61.0 25 | rollup-plugin-dts: ^4.0.1 26 | tailwindcss: ^3.1.7 27 | type-fest: ^0.21.2 28 | typescript: ^4.2.3 29 | vite: ^3.0.4 30 | 31 | dependencies: 32 | element-in-view: 0.1.0 33 | htm: 3.0.4 34 | marked: 2.0.1 35 | preact: 10.5.13 36 | prismjs: 1.23.0 37 | 38 | devDependencies: 39 | '@egoist/rollup-plugin-ts-resolve': 0.1.0 40 | '@prefresh/vite': 2.2.8_preact@10.5.13+vite@3.0.4 41 | '@rollup/plugin-alias': 3.1.2_rollup@2.61.0 42 | '@rollup/plugin-commonjs': 17.1.0_rollup@2.61.0 43 | '@rollup/plugin-node-resolve': 11.2.0_rollup@2.61.0 44 | '@types/debug': 4.1.5 45 | '@types/marked': 1.2.2 46 | '@types/prismjs': 1.16.4 47 | cross-env: 7.0.3 48 | debug: 4.3.1 49 | esbuild: 0.14.51 50 | esbuild-register: 3.2.0_esbuild@0.14.51 51 | fre: 2.0.4 52 | postcss-nested: 5.0.6 53 | prettier: 2.2.1 54 | rollup: 2.61.0 55 | rollup-plugin-dts: 4.0.1_yd2cn43vjkyhfubwloxl6r5ft4 56 | tailwindcss: 3.1.7 57 | type-fest: 0.21.3 58 | typescript: 4.2.3 59 | vite: 3.0.4 60 | 61 | packages: 62 | 63 | /@babel/code-frame/7.16.0: 64 | resolution: {integrity: sha512-IF4EOMEV+bfYwOmNxGzSnjR2EmQod7f1UXOpZM3l4i4o4QNwzjtJAu/HxdjHq0aYBvdqMuQEY1eg0nqW9ZPORA==} 65 | engines: {node: '>=6.9.0'} 66 | requiresBuild: true 67 | dependencies: 68 | '@babel/highlight': 7.16.0 69 | dev: true 70 | 71 | /@babel/compat-data/7.13.12: 72 | resolution: {integrity: sha512-3eJJ841uKxeV8dcN/2yGEUy+RfgQspPEgQat85umsE1rotuquQ2AbIub4S6j7c50a2d+4myc+zSlnXeIHrOnhQ==} 73 | dev: true 74 | 75 | /@babel/core/7.13.10: 76 | resolution: {integrity: sha512-bfIYcT0BdKeAZrovpMqX2Mx5NrgAckGbwT982AkdS5GNfn3KMGiprlBAtmBcFZRUmpaufS6WZFP8trvx8ptFDw==} 77 | engines: {node: '>=6.9.0'} 78 | dependencies: 79 | '@babel/code-frame': 7.16.0 80 | '@babel/generator': 7.13.9 81 | '@babel/helper-compilation-targets': 7.13.10_@babel+core@7.13.10 82 | '@babel/helper-module-transforms': 7.13.12 83 | '@babel/helpers': 7.13.10 84 | '@babel/parser': 7.13.12 85 | '@babel/template': 7.12.13 86 | '@babel/traverse': 7.13.0 87 | '@babel/types': 7.13.12 88 | convert-source-map: 1.7.0 89 | debug: 4.3.1 90 | gensync: 1.0.0-beta.2 91 | json5: 2.2.0 92 | lodash: 4.17.21 93 | semver: 6.3.0 94 | source-map: 0.5.7 95 | transitivePeerDependencies: 96 | - supports-color 97 | dev: true 98 | 99 | /@babel/generator/7.13.9: 100 | resolution: {integrity: sha512-mHOOmY0Axl/JCTkxTU6Lf5sWOg/v8nUa+Xkt4zMTftX0wqmb6Sh7J8gvcehBw7q0AhrhAR+FDacKjCZ2X8K+Sw==} 101 | dependencies: 102 | '@babel/types': 7.13.12 103 | jsesc: 2.5.2 104 | source-map: 0.5.7 105 | dev: true 106 | 107 | /@babel/helper-compilation-targets/7.13.10_@babel+core@7.13.10: 108 | resolution: {integrity: sha512-/Xju7Qg1GQO4mHZ/Kcs6Au7gfafgZnwm+a7sy/ow/tV1sHeraRUHbjdat8/UvDor4Tez+siGKDk6zIKtCPKVJA==} 109 | peerDependencies: 110 | '@babel/core': ^7.0.0 111 | dependencies: 112 | '@babel/compat-data': 7.13.12 113 | '@babel/core': 7.13.10 114 | '@babel/helper-validator-option': 7.12.17 115 | browserslist: 4.16.3 116 | semver: 6.3.0 117 | dev: true 118 | 119 | /@babel/helper-function-name/7.12.13: 120 | resolution: {integrity: sha512-TZvmPn0UOqmvi5G4vvw0qZTpVptGkB1GL61R6lKvrSdIxGm5Pky7Q3fpKiIkQCAtRCBUwB0PaThlx9vebCDSwA==} 121 | dependencies: 122 | '@babel/helper-get-function-arity': 7.12.13 123 | '@babel/template': 7.12.13 124 | '@babel/types': 7.13.12 125 | dev: true 126 | 127 | /@babel/helper-get-function-arity/7.12.13: 128 | resolution: {integrity: sha512-DjEVzQNz5LICkzN0REdpD5prGoidvbdYk1BVgRUOINaWJP2t6avB27X1guXK1kXNrX0WMfsrm1A/ZBthYuIMQg==} 129 | dependencies: 130 | '@babel/types': 7.13.12 131 | dev: true 132 | 133 | /@babel/helper-member-expression-to-functions/7.13.12: 134 | resolution: {integrity: sha512-48ql1CLL59aKbU94Y88Xgb2VFy7a95ykGRbJJaaVv+LX5U8wFpLfiGXJJGUozsmA1oEh/o5Bp60Voq7ACyA/Sw==} 135 | dependencies: 136 | '@babel/types': 7.13.12 137 | dev: true 138 | 139 | /@babel/helper-module-imports/7.13.12: 140 | resolution: {integrity: sha512-4cVvR2/1B693IuOvSI20xqqa/+bl7lqAMR59R4iu39R9aOX8/JoYY1sFaNvUMyMBGnHdwvJgUrzNLoUZxXypxA==} 141 | dependencies: 142 | '@babel/types': 7.13.12 143 | dev: true 144 | 145 | /@babel/helper-module-transforms/7.13.12: 146 | resolution: {integrity: sha512-7zVQqMO3V+K4JOOj40kxiCrMf6xlQAkewBB0eu2b03OO/Q21ZutOzjpfD79A5gtE/2OWi1nv625MrDlGlkbknQ==} 147 | dependencies: 148 | '@babel/helper-module-imports': 7.13.12 149 | '@babel/helper-replace-supers': 7.13.12 150 | '@babel/helper-simple-access': 7.13.12 151 | '@babel/helper-split-export-declaration': 7.12.13 152 | '@babel/helper-validator-identifier': 7.15.7 153 | '@babel/template': 7.12.13 154 | '@babel/traverse': 7.13.0 155 | '@babel/types': 7.13.12 156 | transitivePeerDependencies: 157 | - supports-color 158 | dev: true 159 | 160 | /@babel/helper-optimise-call-expression/7.12.13: 161 | resolution: {integrity: sha512-BdWQhoVJkp6nVjB7nkFWcn43dkprYauqtk++Py2eaf/GRDFm5BxRqEIZCiHlZUGAVmtwKcsVL1dC68WmzeFmiA==} 162 | dependencies: 163 | '@babel/types': 7.13.12 164 | dev: true 165 | 166 | /@babel/helper-replace-supers/7.13.12: 167 | resolution: {integrity: sha512-Gz1eiX+4yDO8mT+heB94aLVNCL+rbuT2xy4YfyNqu8F+OI6vMvJK891qGBTqL9Uc8wxEvRW92Id6G7sDen3fFw==} 168 | dependencies: 169 | '@babel/helper-member-expression-to-functions': 7.13.12 170 | '@babel/helper-optimise-call-expression': 7.12.13 171 | '@babel/traverse': 7.13.0 172 | '@babel/types': 7.13.12 173 | transitivePeerDependencies: 174 | - supports-color 175 | dev: true 176 | 177 | /@babel/helper-simple-access/7.13.12: 178 | resolution: {integrity: sha512-7FEjbrx5SL9cWvXioDbnlYTppcZGuCY6ow3/D5vMggb2Ywgu4dMrpTJX0JdQAIcRRUElOIxF3yEooa9gUb9ZbA==} 179 | dependencies: 180 | '@babel/types': 7.13.12 181 | dev: true 182 | 183 | /@babel/helper-split-export-declaration/7.12.13: 184 | resolution: {integrity: sha512-tCJDltF83htUtXx5NLcaDqRmknv652ZWCHyoTETf1CXYJdPC7nohZohjUgieXhv0hTJdRf2FjDueFehdNucpzg==} 185 | dependencies: 186 | '@babel/types': 7.13.12 187 | dev: true 188 | 189 | /@babel/helper-validator-identifier/7.15.7: 190 | resolution: {integrity: sha512-K4JvCtQqad9OY2+yTU8w+E82ywk/fe+ELNlt1G8z3bVGlZfn/hOcQQsUhGhW/N+tb3fxK800wLtKOE/aM0m72w==} 191 | engines: {node: '>=6.9.0'} 192 | dev: true 193 | 194 | /@babel/helper-validator-option/7.12.17: 195 | resolution: {integrity: sha512-TopkMDmLzq8ngChwRlyjR6raKD6gMSae4JdYDB8bByKreQgG0RBTuKe9LRxW3wFtUnjxOPRKBDwEH6Mg5KeDfw==} 196 | dev: true 197 | 198 | /@babel/helpers/7.13.10: 199 | resolution: {integrity: sha512-4VO883+MWPDUVRF3PhiLBUFHoX/bsLTGFpFK/HqvvfBZz2D57u9XzPVNFVBTc0PW/CWR9BXTOKt8NF4DInUHcQ==} 200 | dependencies: 201 | '@babel/template': 7.12.13 202 | '@babel/traverse': 7.13.0 203 | '@babel/types': 7.13.12 204 | transitivePeerDependencies: 205 | - supports-color 206 | dev: true 207 | 208 | /@babel/highlight/7.16.0: 209 | resolution: {integrity: sha512-t8MH41kUQylBtu2+4IQA3atqevA2lRgqA2wyVB/YiWmsDSuylZZuXOUy9ric30hfzauEFfdsuk/eXTRrGrfd0g==} 210 | engines: {node: '>=6.9.0'} 211 | dependencies: 212 | '@babel/helper-validator-identifier': 7.15.7 213 | chalk: 2.4.2 214 | js-tokens: 4.0.0 215 | dev: true 216 | 217 | /@babel/parser/7.13.12: 218 | resolution: {integrity: sha512-4T7Pb244rxH24yR116LAuJ+adxXXnHhZaLJjegJVKSdoNCe4x1eDBaud5YIcQFcqzsaD5BHvJw5BQ0AZapdCRw==} 219 | engines: {node: '>=6.0.0'} 220 | hasBin: true 221 | dependencies: 222 | '@babel/types': 7.13.12 223 | dev: true 224 | 225 | /@babel/template/7.12.13: 226 | resolution: {integrity: sha512-/7xxiGA57xMo/P2GVvdEumr8ONhFOhfgq2ihK3h1e6THqzTAkHbkXgB0xI9yeTfIUoH3+oAeHhqm/I43OTbbjA==} 227 | dependencies: 228 | '@babel/code-frame': 7.16.0 229 | '@babel/parser': 7.13.12 230 | '@babel/types': 7.13.12 231 | dev: true 232 | 233 | /@babel/traverse/7.13.0: 234 | resolution: {integrity: sha512-xys5xi5JEhzC3RzEmSGrs/b3pJW/o87SypZ+G/PhaE7uqVQNv/jlmVIBXuoh5atqQ434LfXV+sf23Oxj0bchJQ==} 235 | dependencies: 236 | '@babel/code-frame': 7.16.0 237 | '@babel/generator': 7.13.9 238 | '@babel/helper-function-name': 7.12.13 239 | '@babel/helper-split-export-declaration': 7.12.13 240 | '@babel/parser': 7.13.12 241 | '@babel/types': 7.13.12 242 | debug: 4.3.1 243 | globals: 11.12.0 244 | lodash: 4.17.21 245 | transitivePeerDependencies: 246 | - supports-color 247 | dev: true 248 | 249 | /@babel/types/7.13.12: 250 | resolution: {integrity: sha512-K4nY2xFN4QMvQwkQ+zmBDp6ANMbVNw6BbxWmYA4qNjhR9W+Lj/8ky5MEY2Me5r+B2c6/v6F53oMndG+f9s3IiA==} 251 | dependencies: 252 | '@babel/helper-validator-identifier': 7.15.7 253 | lodash: 4.17.21 254 | to-fast-properties: 2.0.0 255 | dev: true 256 | 257 | /@egoist/rollup-plugin-ts-resolve/0.1.0: 258 | resolution: {integrity: sha512-phXCP0MXwRL0S01IbmuAXa2oVqcJZVhs9xyPsIh3oO6A6FCb9xyfMwbe7Zq93/+S8bplx0/7BicOFAKOJlIxvw==} 259 | dependencies: 260 | debug: 4.3.1 261 | resolve: 1.20.0 262 | transitivePeerDependencies: 263 | - supports-color 264 | dev: true 265 | 266 | /@nodelib/fs.scandir/2.1.5: 267 | resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} 268 | engines: {node: '>= 8'} 269 | dependencies: 270 | '@nodelib/fs.stat': 2.0.5 271 | run-parallel: 1.2.0 272 | dev: true 273 | 274 | /@nodelib/fs.stat/2.0.5: 275 | resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==} 276 | engines: {node: '>= 8'} 277 | dev: true 278 | 279 | /@nodelib/fs.walk/1.2.8: 280 | resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} 281 | engines: {node: '>= 8'} 282 | dependencies: 283 | '@nodelib/fs.scandir': 2.1.5 284 | fastq: 1.13.0 285 | dev: true 286 | 287 | /@prefresh/babel-plugin/0.4.3: 288 | resolution: {integrity: sha512-fYAWbU1WDSLn108kKY4eDaaeUcnszFqXjgaGKYXNZ5NLulpRTpsrY+Sbfo9q8LDpWrBpqIgzjrwNnvglWI1xNQ==} 289 | dev: true 290 | 291 | /@prefresh/core/1.3.4_preact@10.5.13: 292 | resolution: {integrity: sha512-s7iNsnyJ3lZEUrYIgmVIB/hKtp4U6mdD91a31Zg7Q8M49O0x2KThrbrMQYraoDDrs4STdFB8Zv6bceUguOoX1A==} 293 | peerDependencies: 294 | preact: ^10.0.0 295 | dependencies: 296 | preact: 10.5.13 297 | dev: true 298 | 299 | /@prefresh/utils/1.1.3: 300 | resolution: {integrity: sha512-Mb9abhJTOV4yCfkXrMrcgFiFT7MfNOw8sDa+XyZBdq/Ai2p4Zyxqsb3EgHLOEdHpMj6J9aiZ54W8H6FTam1u+A==} 301 | dev: true 302 | 303 | /@prefresh/vite/2.2.8_preact@10.5.13+vite@3.0.4: 304 | resolution: {integrity: sha512-yGGa+PKPYPTzMlxgQ8aBgxw9K69I8X4iQ0E6KOcIvls96WKqKLLOYZW9SUgCve446jpUXvc9udviPBZjCeZIIQ==} 305 | peerDependencies: 306 | preact: ^10.4.0 307 | vite: '>=2.0.0-beta.3' 308 | dependencies: 309 | '@babel/core': 7.13.10 310 | '@prefresh/babel-plugin': 0.4.3 311 | '@prefresh/core': 1.3.4_preact@10.5.13 312 | '@prefresh/utils': 1.1.3 313 | '@rollup/pluginutils': 4.1.1 314 | preact: 10.5.13 315 | vite: 3.0.4 316 | transitivePeerDependencies: 317 | - supports-color 318 | dev: true 319 | 320 | /@rollup/plugin-alias/3.1.2_rollup@2.61.0: 321 | resolution: {integrity: sha512-wzDnQ6v7CcoRzS0qVwFPrFdYA4Qlr+ookA217Y2Z3DPZE1R8jrFNM3jvGgOf6o6DMjbnQIn5lCIJgHPe1Bt3uw==} 322 | engines: {node: '>=8.0.0'} 323 | peerDependencies: 324 | rollup: ^1.20.0||^2.0.0 325 | dependencies: 326 | rollup: 2.61.0 327 | slash: 3.0.0 328 | dev: true 329 | 330 | /@rollup/plugin-commonjs/17.1.0_rollup@2.61.0: 331 | resolution: {integrity: sha512-PoMdXCw0ZyvjpCMT5aV4nkL0QywxP29sODQsSGeDpr/oI49Qq9tRtAsb/LbYbDzFlOydVEqHmmZWFtXJEAX9ew==} 332 | engines: {node: '>= 8.0.0'} 333 | peerDependencies: 334 | rollup: ^2.30.0 335 | dependencies: 336 | '@rollup/pluginutils': 3.1.0_rollup@2.61.0 337 | commondir: 1.0.1 338 | estree-walker: 2.0.2 339 | glob: 7.1.6 340 | is-reference: 1.2.1 341 | magic-string: 0.25.7 342 | resolve: 1.20.0 343 | rollup: 2.61.0 344 | dev: true 345 | 346 | /@rollup/plugin-node-resolve/11.2.0_rollup@2.61.0: 347 | resolution: {integrity: sha512-qHjNIKYt5pCcn+5RUBQxK8krhRvf1HnyVgUCcFFcweDS7fhkOLZeYh0mhHK6Ery8/bb9tvN/ubPzmfF0qjDCTA==} 348 | engines: {node: '>= 10.0.0'} 349 | peerDependencies: 350 | rollup: ^1.20.0||^2.0.0 351 | dependencies: 352 | '@rollup/pluginutils': 3.1.0_rollup@2.61.0 353 | '@types/resolve': 1.17.1 354 | builtin-modules: 3.2.0 355 | deepmerge: 4.2.2 356 | is-module: 1.0.0 357 | resolve: 1.20.0 358 | rollup: 2.61.0 359 | dev: true 360 | 361 | /@rollup/pluginutils/3.1.0_rollup@2.61.0: 362 | resolution: {integrity: sha512-GksZ6pr6TpIjHm8h9lSQ8pi8BE9VeubNT0OMJ3B5uZJ8pz73NPiqOtCog/x2/QzM1ENChPKxMDhiQuRHsqc+lg==} 363 | engines: {node: '>= 8.0.0'} 364 | peerDependencies: 365 | rollup: ^1.20.0||^2.0.0 366 | dependencies: 367 | '@types/estree': 0.0.39 368 | estree-walker: 1.0.1 369 | picomatch: 2.2.2 370 | rollup: 2.61.0 371 | dev: true 372 | 373 | /@rollup/pluginutils/4.1.1: 374 | resolution: {integrity: sha512-clDjivHqWGXi7u+0d2r2sBi4Ie6VLEAzWMIkvJLnDmxoOhBYOTfzGbOQBA32THHm11/LiJbd01tJUpJsbshSWQ==} 375 | engines: {node: '>= 8.0.0'} 376 | dependencies: 377 | estree-walker: 2.0.2 378 | picomatch: 2.3.0 379 | dev: true 380 | 381 | /@types/debug/4.1.5: 382 | resolution: {integrity: sha512-Q1y515GcOdTHgagaVFhHnIFQ38ygs/kmxdNpvpou+raI9UO3YZcHDngBSYKQklcKlvA7iuQlmIKbzvmxcOE9CQ==} 383 | dev: true 384 | 385 | /@types/estree/0.0.39: 386 | resolution: {integrity: sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==} 387 | dev: true 388 | 389 | /@types/estree/0.0.47: 390 | resolution: {integrity: sha512-c5ciR06jK8u9BstrmJyO97m+klJrrhCf9u3rLu3DEAJBirxRqSCvDQoYKmxuYwQI5SZChAWu+tq9oVlGRuzPAg==} 391 | dev: true 392 | 393 | /@types/marked/1.2.2: 394 | resolution: {integrity: sha512-wLfw1hnuuDYrFz97IzJja0pdVsC0oedtS4QsKH1/inyW9qkLQbXgMUqEQT0MVtUBx3twjWeInUfjQbhBVLECXw==} 395 | dev: true 396 | 397 | /@types/node/14.14.36: 398 | resolution: {integrity: sha512-kjivUwDJfIjngzbhooRnOLhGYz6oRFi+L+EpMjxroDYXwDw9lHrJJ43E+dJ6KAd3V3WxWAJ/qZE9XKYHhjPOFQ==} 399 | dev: true 400 | 401 | /@types/prismjs/1.16.4: 402 | resolution: {integrity: sha512-9B+DlSSelvKZMKkAgm1SjBV19XbPIL113GIKl18XgJV+06QvnbykeqeizZrr14b4TWf1deWLu9XZivPD8zMoHA==} 403 | dev: true 404 | 405 | /@types/resolve/1.17.1: 406 | resolution: {integrity: sha512-yy7HuzQhj0dhGpD8RLXSZWEkLsV9ibvxvi6EiJ3bkqLAO1RGo0WbkWQiwpRlSFymTJRz0d3k5LM3kkx8ArDbLw==} 407 | dependencies: 408 | '@types/node': 14.14.36 409 | dev: true 410 | 411 | /acorn-node/1.8.2: 412 | resolution: {integrity: sha512-8mt+fslDufLYntIoPAaIMUe/lrbrehIiwmR3t2k9LljIzoigEPF27eLk2hy8zSGzmR/ogr7zbRKINMo1u0yh5A==} 413 | dependencies: 414 | acorn: 7.4.1 415 | acorn-walk: 7.2.0 416 | xtend: 4.0.2 417 | dev: true 418 | 419 | /acorn-walk/7.2.0: 420 | resolution: {integrity: sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==} 421 | engines: {node: '>=0.4.0'} 422 | dev: true 423 | 424 | /acorn/7.4.1: 425 | resolution: {integrity: sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==} 426 | engines: {node: '>=0.4.0'} 427 | hasBin: true 428 | dev: true 429 | 430 | /ansi-styles/3.2.1: 431 | resolution: {integrity: sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==} 432 | engines: {node: '>=4'} 433 | dependencies: 434 | color-convert: 1.9.3 435 | dev: true 436 | 437 | /anymatch/3.1.2: 438 | resolution: {integrity: sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==} 439 | engines: {node: '>= 8'} 440 | dependencies: 441 | normalize-path: 3.0.0 442 | picomatch: 2.3.0 443 | dev: true 444 | 445 | /arg/5.0.2: 446 | resolution: {integrity: sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==} 447 | dev: true 448 | 449 | /balanced-match/1.0.0: 450 | resolution: {integrity: sha1-ibTRmasr7kneFk6gK4nORi1xt2c=} 451 | dev: true 452 | 453 | /binary-extensions/2.2.0: 454 | resolution: {integrity: sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==} 455 | engines: {node: '>=8'} 456 | dev: true 457 | 458 | /brace-expansion/1.1.11: 459 | resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} 460 | dependencies: 461 | balanced-match: 1.0.0 462 | concat-map: 0.0.1 463 | dev: true 464 | 465 | /braces/3.0.2: 466 | resolution: {integrity: sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==} 467 | engines: {node: '>=8'} 468 | dependencies: 469 | fill-range: 7.0.1 470 | dev: true 471 | 472 | /browserslist/4.16.3: 473 | resolution: {integrity: sha512-vIyhWmIkULaq04Gt93txdh+j02yX/JzlyhLYbV3YQCn/zvES3JnY7TifHHvvr1w5hTDluNKMkV05cs4vy8Q7sw==} 474 | engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} 475 | hasBin: true 476 | dependencies: 477 | caniuse-lite: 1.0.30001204 478 | colorette: 1.2.2 479 | electron-to-chromium: 1.3.700 480 | escalade: 3.1.1 481 | node-releases: 1.1.71 482 | dev: true 483 | 484 | /builtin-modules/3.2.0: 485 | resolution: {integrity: sha512-lGzLKcioL90C7wMczpkY0n/oART3MbBa8R9OFGE1rJxoVI86u4WAGfEk8Wjv10eKSyTHVGkSo3bvBylCEtk7LA==} 486 | engines: {node: '>=6'} 487 | dev: true 488 | 489 | /camelcase-css/2.0.1: 490 | resolution: {integrity: sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==} 491 | engines: {node: '>= 6'} 492 | dev: true 493 | 494 | /caniuse-lite/1.0.30001204: 495 | resolution: {integrity: sha512-JUdjWpcxfJ9IPamy2f5JaRDCaqJOxDzOSKtbdx4rH9VivMd1vIzoPumsJa9LoMIi4Fx2BV2KZOxWhNkBjaYivQ==} 496 | dev: true 497 | 498 | /chalk/2.4.2: 499 | resolution: {integrity: sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==} 500 | engines: {node: '>=4'} 501 | dependencies: 502 | ansi-styles: 3.2.1 503 | escape-string-regexp: 1.0.5 504 | supports-color: 5.5.0 505 | dev: true 506 | 507 | /chokidar/3.5.3: 508 | resolution: {integrity: sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==} 509 | engines: {node: '>= 8.10.0'} 510 | dependencies: 511 | anymatch: 3.1.2 512 | braces: 3.0.2 513 | glob-parent: 5.1.2 514 | is-binary-path: 2.1.0 515 | is-glob: 4.0.3 516 | normalize-path: 3.0.0 517 | readdirp: 3.6.0 518 | optionalDependencies: 519 | fsevents: 2.3.2 520 | dev: true 521 | 522 | /clipboard/2.0.8: 523 | resolution: {integrity: sha512-Y6WO0unAIQp5bLmk1zdThRhgJt/x3ks6f30s3oE3H1mgIEU33XyQjEf8gsf6DxC7NPX8Y1SsNWjUjL/ywLnnbQ==} 524 | requiresBuild: true 525 | dependencies: 526 | good-listener: 1.2.2 527 | select: 1.1.2 528 | tiny-emitter: 2.1.0 529 | dev: false 530 | optional: true 531 | 532 | /color-convert/1.9.3: 533 | resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==} 534 | dependencies: 535 | color-name: 1.1.3 536 | dev: true 537 | 538 | /color-name/1.1.3: 539 | resolution: {integrity: sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==} 540 | dev: true 541 | 542 | /color-name/1.1.4: 543 | resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} 544 | dev: true 545 | 546 | /colorette/1.2.2: 547 | resolution: {integrity: sha512-MKGMzyfeuutC/ZJ1cba9NqcNpfeqMUcYmyF1ZFY6/Cn7CNSAKx6a+s48sqLqyAiZuaP2TcqMhoo+dlwFnVxT9w==} 548 | dev: true 549 | 550 | /commondir/1.0.1: 551 | resolution: {integrity: sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=} 552 | dev: true 553 | 554 | /concat-map/0.0.1: 555 | resolution: {integrity: sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=} 556 | dev: true 557 | 558 | /convert-source-map/1.7.0: 559 | resolution: {integrity: sha512-4FJkXzKXEDB1snCFZlLP4gpC3JILicCpGbzG9f9G7tGqGCzETQ2hWPrcinA9oU4wtf2biUaEH5065UnMeR33oA==} 560 | dependencies: 561 | safe-buffer: 5.1.2 562 | dev: true 563 | 564 | /cross-env/7.0.3: 565 | resolution: {integrity: sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw==} 566 | engines: {node: '>=10.14', npm: '>=6', yarn: '>=1'} 567 | hasBin: true 568 | dependencies: 569 | cross-spawn: 7.0.3 570 | dev: true 571 | 572 | /cross-spawn/7.0.3: 573 | resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==} 574 | engines: {node: '>= 8'} 575 | dependencies: 576 | path-key: 3.1.1 577 | shebang-command: 2.0.0 578 | which: 2.0.2 579 | dev: true 580 | 581 | /cssesc/3.0.0: 582 | resolution: {integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==} 583 | engines: {node: '>=4'} 584 | hasBin: true 585 | dev: true 586 | 587 | /debug/4.3.1: 588 | resolution: {integrity: sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==} 589 | engines: {node: '>=6.0'} 590 | peerDependencies: 591 | supports-color: '*' 592 | peerDependenciesMeta: 593 | supports-color: 594 | optional: true 595 | dependencies: 596 | ms: 2.1.2 597 | dev: true 598 | 599 | /deepmerge/4.2.2: 600 | resolution: {integrity: sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==} 601 | engines: {node: '>=0.10.0'} 602 | dev: true 603 | 604 | /defined/1.0.0: 605 | resolution: {integrity: sha512-Y2caI5+ZwS5c3RiNDJ6u53VhQHv+hHKwhkI1iHvceKUHw9Df6EK2zRLfjejRgMuCuxK7PfSWIMwWecceVvThjQ==} 606 | dev: true 607 | 608 | /delegate/3.2.0: 609 | resolution: {integrity: sha512-IofjkYBZaZivn0V8nnsMJGBr4jVLxHDheKSW88PyxS5QC4Vo9ZbZVvhzlSxY87fVq3STR6r+4cGepyHkcWOQSw==} 610 | dev: false 611 | optional: true 612 | 613 | /detective/5.2.1: 614 | resolution: {integrity: sha512-v9XE1zRnz1wRtgurGu0Bs8uHKFSTdteYZNbIPFVhUZ39L/S79ppMpdmVOZAnoz1jfEFodc48n6MX483Xo3t1yw==} 615 | engines: {node: '>=0.8.0'} 616 | hasBin: true 617 | dependencies: 618 | acorn-node: 1.8.2 619 | defined: 1.0.0 620 | minimist: 1.2.6 621 | dev: true 622 | 623 | /didyoumean/1.2.2: 624 | resolution: {integrity: sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==} 625 | dev: true 626 | 627 | /dlv/1.1.3: 628 | resolution: {integrity: sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==} 629 | dev: true 630 | 631 | /electron-to-chromium/1.3.700: 632 | resolution: {integrity: sha512-wQtaxVZzpOeCjW1CGuC5W3bYjE2jglvk076LcTautBOB9UtHztty7wNzjVsndiMcSsdUsdMy5w76w5J1U7OPTQ==} 633 | dev: true 634 | 635 | /element-in-view/0.1.0: 636 | resolution: {integrity: sha1-Zi9B+ajTuMpFh8HdtCe30nr4i8k=} 637 | dev: false 638 | 639 | /esbuild-android-64/0.14.51: 640 | resolution: {integrity: sha512-6FOuKTHnC86dtrKDmdSj2CkcKF8PnqkaIXqvgydqfJmqBazCPdw+relrMlhGjkvVdiiGV70rpdnyFmA65ekBCQ==} 641 | engines: {node: '>=12'} 642 | cpu: [x64] 643 | os: [android] 644 | requiresBuild: true 645 | dev: true 646 | optional: true 647 | 648 | /esbuild-android-arm64/0.14.51: 649 | resolution: {integrity: sha512-vBtp//5VVkZWmYYvHsqBRCMMi1MzKuMIn5XDScmnykMTu9+TD9v0NMEDqQxvtFToeYmojdo5UCV2vzMQWJcJ4A==} 650 | engines: {node: '>=12'} 651 | cpu: [arm64] 652 | os: [android] 653 | requiresBuild: true 654 | dev: true 655 | optional: true 656 | 657 | /esbuild-darwin-64/0.14.51: 658 | resolution: {integrity: sha512-YFmXPIOvuagDcwCejMRtCDjgPfnDu+bNeh5FU2Ryi68ADDVlWEpbtpAbrtf/lvFTWPexbgyKgzppNgsmLPr8PA==} 659 | engines: {node: '>=12'} 660 | cpu: [x64] 661 | os: [darwin] 662 | requiresBuild: true 663 | dev: true 664 | optional: true 665 | 666 | /esbuild-darwin-arm64/0.14.51: 667 | resolution: {integrity: sha512-juYD0QnSKwAMfzwKdIF6YbueXzS6N7y4GXPDeDkApz/1RzlT42mvX9jgNmyOlWKN7YzQAYbcUEJmZJYQGdf2ow==} 668 | engines: {node: '>=12'} 669 | cpu: [arm64] 670 | os: [darwin] 671 | requiresBuild: true 672 | dev: true 673 | optional: true 674 | 675 | /esbuild-freebsd-64/0.14.51: 676 | resolution: {integrity: sha512-cLEI/aXjb6vo5O2Y8rvVSQ7smgLldwYY5xMxqh/dQGfWO+R1NJOFsiax3IS4Ng300SVp7Gz3czxT6d6qf2cw0g==} 677 | engines: {node: '>=12'} 678 | cpu: [x64] 679 | os: [freebsd] 680 | requiresBuild: true 681 | dev: true 682 | optional: true 683 | 684 | /esbuild-freebsd-arm64/0.14.51: 685 | resolution: {integrity: sha512-TcWVw/rCL2F+jUgRkgLa3qltd5gzKjIMGhkVybkjk6PJadYInPtgtUBp1/hG+mxyigaT7ib+od1Xb84b+L+1Mg==} 686 | engines: {node: '>=12'} 687 | cpu: [arm64] 688 | os: [freebsd] 689 | requiresBuild: true 690 | dev: true 691 | optional: true 692 | 693 | /esbuild-linux-32/0.14.51: 694 | resolution: {integrity: sha512-RFqpyC5ChyWrjx8Xj2K0EC1aN0A37H6OJfmUXIASEqJoHcntuV3j2Efr9RNmUhMfNE6yEj2VpYuDteZLGDMr0w==} 695 | engines: {node: '>=12'} 696 | cpu: [ia32] 697 | os: [linux] 698 | requiresBuild: true 699 | dev: true 700 | optional: true 701 | 702 | /esbuild-linux-64/0.14.51: 703 | resolution: {integrity: sha512-dxjhrqo5i7Rq6DXwz5v+MEHVs9VNFItJmHBe1CxROWNf4miOGoQhqSG8StStbDkQ1Mtobg6ng+4fwByOhoQoeA==} 704 | engines: {node: '>=12'} 705 | cpu: [x64] 706 | os: [linux] 707 | requiresBuild: true 708 | dev: true 709 | optional: true 710 | 711 | /esbuild-linux-arm/0.14.51: 712 | resolution: {integrity: sha512-LsJynDxYF6Neg7ZC7748yweCDD+N8ByCv22/7IAZglIEniEkqdF4HCaa49JNDLw1UQGlYuhOB8ZT/MmcSWzcWg==} 713 | engines: {node: '>=12'} 714 | cpu: [arm] 715 | os: [linux] 716 | requiresBuild: true 717 | dev: true 718 | optional: true 719 | 720 | /esbuild-linux-arm64/0.14.51: 721 | resolution: {integrity: sha512-D9rFxGutoqQX3xJPxqd6o+kvYKeIbM0ifW2y0bgKk5HPgQQOo2k9/2Vpto3ybGYaFPCE5qTGtqQta9PoP6ZEzw==} 722 | engines: {node: '>=12'} 723 | cpu: [arm64] 724 | os: [linux] 725 | requiresBuild: true 726 | dev: true 727 | optional: true 728 | 729 | /esbuild-linux-mips64le/0.14.51: 730 | resolution: {integrity: sha512-vS54wQjy4IinLSlb5EIlLoln8buh1yDgliP4CuEHumrPk4PvvP4kTRIG4SzMXm6t19N0rIfT4bNdAxzJLg2k6A==} 731 | engines: {node: '>=12'} 732 | cpu: [mips64el] 733 | os: [linux] 734 | requiresBuild: true 735 | dev: true 736 | optional: true 737 | 738 | /esbuild-linux-ppc64le/0.14.51: 739 | resolution: {integrity: sha512-xcdd62Y3VfGoyphNP/aIV9LP+RzFw5M5Z7ja+zdpQHHvokJM7d0rlDRMN+iSSwvUymQkqZO+G/xjb4/75du8BQ==} 740 | engines: {node: '>=12'} 741 | cpu: [ppc64] 742 | os: [linux] 743 | requiresBuild: true 744 | dev: true 745 | optional: true 746 | 747 | /esbuild-linux-riscv64/0.14.51: 748 | resolution: {integrity: sha512-syXHGak9wkAnFz0gMmRBoy44JV0rp4kVCEA36P5MCeZcxFq8+fllBC2t6sKI23w3qd8Vwo9pTADCgjTSf3L3rA==} 749 | engines: {node: '>=12'} 750 | cpu: [riscv64] 751 | os: [linux] 752 | requiresBuild: true 753 | dev: true 754 | optional: true 755 | 756 | /esbuild-linux-s390x/0.14.51: 757 | resolution: {integrity: sha512-kFAJY3dv+Wq8o28K/C7xkZk/X34rgTwhknSsElIqoEo8armCOjMJ6NsMxm48KaWY2h2RUYGtQmr+RGuUPKBhyw==} 758 | engines: {node: '>=12'} 759 | cpu: [s390x] 760 | os: [linux] 761 | requiresBuild: true 762 | dev: true 763 | optional: true 764 | 765 | /esbuild-netbsd-64/0.14.51: 766 | resolution: {integrity: sha512-ZZBI7qrR1FevdPBVHz/1GSk1x5GDL/iy42Zy8+neEm/HA7ma+hH/bwPEjeHXKWUDvM36CZpSL/fn1/y9/Hb+1A==} 767 | engines: {node: '>=12'} 768 | cpu: [x64] 769 | os: [netbsd] 770 | requiresBuild: true 771 | dev: true 772 | optional: true 773 | 774 | /esbuild-openbsd-64/0.14.51: 775 | resolution: {integrity: sha512-7R1/p39M+LSVQVgDVlcY1KKm6kFKjERSX1lipMG51NPcspJD1tmiZSmmBXoY5jhHIu6JL1QkFDTx94gMYK6vfA==} 776 | engines: {node: '>=12'} 777 | cpu: [x64] 778 | os: [openbsd] 779 | requiresBuild: true 780 | dev: true 781 | optional: true 782 | 783 | /esbuild-register/3.2.0_esbuild@0.14.51: 784 | resolution: {integrity: sha512-i1sYwESrRHJz15Cl1u2OgLjBBp/bWtGoDdFXVLL1clsp+pFdqIpRfHIQGkgvQAlAecP5IC/bObYrKCyx/lE50Q==} 785 | peerDependencies: 786 | esbuild: '>=0.12 <1' 787 | dependencies: 788 | esbuild: 0.14.51 789 | jsonc-parser: 3.0.0 790 | dev: true 791 | 792 | /esbuild-sunos-64/0.14.51: 793 | resolution: {integrity: sha512-HoHaCswHxLEYN8eBTtyO0bFEWvA3Kdb++hSQ/lLG7TyKF69TeSG0RNoBRAs45x/oCeWaTDntEZlYwAfQlhEtJA==} 794 | engines: {node: '>=12'} 795 | cpu: [x64] 796 | os: [sunos] 797 | requiresBuild: true 798 | dev: true 799 | optional: true 800 | 801 | /esbuild-windows-32/0.14.51: 802 | resolution: {integrity: sha512-4rtwSAM35A07CBt1/X8RWieDj3ZUHQqUOaEo5ZBs69rt5WAFjP4aqCIobdqOy4FdhYw1yF8Z0xFBTyc9lgPtEg==} 803 | engines: {node: '>=12'} 804 | cpu: [ia32] 805 | os: [win32] 806 | requiresBuild: true 807 | dev: true 808 | optional: true 809 | 810 | /esbuild-windows-64/0.14.51: 811 | resolution: {integrity: sha512-HoN/5HGRXJpWODprGCgKbdMvrC3A2gqvzewu2eECRw2sYxOUoh2TV1tS+G7bHNapPGI79woQJGV6pFH7GH7qnA==} 812 | engines: {node: '>=12'} 813 | cpu: [x64] 814 | os: [win32] 815 | requiresBuild: true 816 | dev: true 817 | optional: true 818 | 819 | /esbuild-windows-arm64/0.14.51: 820 | resolution: {integrity: sha512-JQDqPjuOH7o+BsKMSddMfmVJXrnYZxXDHsoLHc0xgmAZkOOCflRmC43q31pk79F9xuyWY45jDBPolb5ZgGOf9g==} 821 | engines: {node: '>=12'} 822 | cpu: [arm64] 823 | os: [win32] 824 | requiresBuild: true 825 | dev: true 826 | optional: true 827 | 828 | /esbuild/0.14.51: 829 | resolution: {integrity: sha512-+CvnDitD7Q5sT7F+FM65sWkF8wJRf+j9fPcprxYV4j+ohmzVj2W7caUqH2s5kCaCJAfcAICjSlKhDCcvDpU7nw==} 830 | engines: {node: '>=12'} 831 | hasBin: true 832 | requiresBuild: true 833 | optionalDependencies: 834 | esbuild-android-64: 0.14.51 835 | esbuild-android-arm64: 0.14.51 836 | esbuild-darwin-64: 0.14.51 837 | esbuild-darwin-arm64: 0.14.51 838 | esbuild-freebsd-64: 0.14.51 839 | esbuild-freebsd-arm64: 0.14.51 840 | esbuild-linux-32: 0.14.51 841 | esbuild-linux-64: 0.14.51 842 | esbuild-linux-arm: 0.14.51 843 | esbuild-linux-arm64: 0.14.51 844 | esbuild-linux-mips64le: 0.14.51 845 | esbuild-linux-ppc64le: 0.14.51 846 | esbuild-linux-riscv64: 0.14.51 847 | esbuild-linux-s390x: 0.14.51 848 | esbuild-netbsd-64: 0.14.51 849 | esbuild-openbsd-64: 0.14.51 850 | esbuild-sunos-64: 0.14.51 851 | esbuild-windows-32: 0.14.51 852 | esbuild-windows-64: 0.14.51 853 | esbuild-windows-arm64: 0.14.51 854 | dev: true 855 | 856 | /escalade/3.1.1: 857 | resolution: {integrity: sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==} 858 | engines: {node: '>=6'} 859 | dev: true 860 | 861 | /escape-string-regexp/1.0.5: 862 | resolution: {integrity: sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=} 863 | engines: {node: '>=0.8.0'} 864 | dev: true 865 | 866 | /estree-walker/1.0.1: 867 | resolution: {integrity: sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg==} 868 | dev: true 869 | 870 | /estree-walker/2.0.2: 871 | resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==} 872 | dev: true 873 | 874 | /fast-glob/3.2.11: 875 | resolution: {integrity: sha512-xrO3+1bxSo3ZVHAnqzyuewYT6aMFHRAd4Kcs92MAonjwQZLsK9d0SF1IyQ3k5PoirxTW0Oe/RqFgMQ6TcNE5Ew==} 876 | engines: {node: '>=8.6.0'} 877 | dependencies: 878 | '@nodelib/fs.stat': 2.0.5 879 | '@nodelib/fs.walk': 1.2.8 880 | glob-parent: 5.1.2 881 | merge2: 1.4.1 882 | micromatch: 4.0.4 883 | dev: true 884 | 885 | /fastq/1.13.0: 886 | resolution: {integrity: sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==} 887 | dependencies: 888 | reusify: 1.0.4 889 | dev: true 890 | 891 | /fill-range/7.0.1: 892 | resolution: {integrity: sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==} 893 | engines: {node: '>=8'} 894 | dependencies: 895 | to-regex-range: 5.0.1 896 | dev: true 897 | 898 | /fre/2.0.4: 899 | resolution: {integrity: sha512-4PhECDE2LC7WGxKEIeY/1fnQ6mGVGSGwy2IR42WL/w4iq16Z/rGmFuwkBnKEWyLHZEieZg1oqUVUPSDzLbBzSA==} 900 | dev: true 901 | 902 | /fs.realpath/1.0.0: 903 | resolution: {integrity: sha1-FQStJSMVjKpA20onh8sBQRmU6k8=} 904 | dev: true 905 | 906 | /fsevents/2.3.2: 907 | resolution: {integrity: sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==} 908 | engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} 909 | os: [darwin] 910 | requiresBuild: true 911 | dev: true 912 | optional: true 913 | 914 | /function-bind/1.1.1: 915 | resolution: {integrity: sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==} 916 | dev: true 917 | 918 | /gensync/1.0.0-beta.2: 919 | resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} 920 | engines: {node: '>=6.9.0'} 921 | dev: true 922 | 923 | /glob-parent/5.1.2: 924 | resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} 925 | engines: {node: '>= 6'} 926 | dependencies: 927 | is-glob: 4.0.3 928 | dev: true 929 | 930 | /glob-parent/6.0.2: 931 | resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} 932 | engines: {node: '>=10.13.0'} 933 | dependencies: 934 | is-glob: 4.0.3 935 | dev: true 936 | 937 | /glob/7.1.6: 938 | resolution: {integrity: sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==} 939 | dependencies: 940 | fs.realpath: 1.0.0 941 | inflight: 1.0.6 942 | inherits: 2.0.4 943 | minimatch: 3.0.4 944 | once: 1.4.0 945 | path-is-absolute: 1.0.1 946 | dev: true 947 | 948 | /globals/11.12.0: 949 | resolution: {integrity: sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==} 950 | engines: {node: '>=4'} 951 | dev: true 952 | 953 | /good-listener/1.2.2: 954 | resolution: {integrity: sha1-1TswzfkxPf+33JoNR3CWqm0UXFA=} 955 | dependencies: 956 | delegate: 3.2.0 957 | dev: false 958 | optional: true 959 | 960 | /has-flag/3.0.0: 961 | resolution: {integrity: sha1-tdRU3CGZriJWmfNGfloH87lVuv0=} 962 | engines: {node: '>=4'} 963 | dev: true 964 | 965 | /has/1.0.3: 966 | resolution: {integrity: sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==} 967 | engines: {node: '>= 0.4.0'} 968 | dependencies: 969 | function-bind: 1.1.1 970 | dev: true 971 | 972 | /htm/3.0.4: 973 | resolution: {integrity: sha512-VRdvxX3tmrXuT/Ovt59NMp/ORMFi4bceFMDjos1PV4E0mV+5votuID8R60egR9A4U8nLt238R/snlJGz3UYiTQ==} 974 | dev: false 975 | 976 | /inflight/1.0.6: 977 | resolution: {integrity: sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=} 978 | dependencies: 979 | once: 1.4.0 980 | wrappy: 1.0.2 981 | dev: true 982 | 983 | /inherits/2.0.4: 984 | resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} 985 | dev: true 986 | 987 | /is-binary-path/2.1.0: 988 | resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==} 989 | engines: {node: '>=8'} 990 | dependencies: 991 | binary-extensions: 2.2.0 992 | dev: true 993 | 994 | /is-core-module/2.2.0: 995 | resolution: {integrity: sha512-XRAfAdyyY5F5cOXn7hYQDqh2Xmii+DEfIcQGxK/uNwMHhIkPWO0g8msXcbzLe+MpGoR951MlqM/2iIlU4vKDdQ==} 996 | dependencies: 997 | has: 1.0.3 998 | dev: true 999 | 1000 | /is-core-module/2.9.0: 1001 | resolution: {integrity: sha512-+5FPy5PnwmO3lvfMb0AsoPaBG+5KHUI0wYFXOtYPnVVVspTFUuMZNfNaNVRt3FZadstu2c8x23vykRW/NBoU6A==} 1002 | dependencies: 1003 | has: 1.0.3 1004 | dev: true 1005 | 1006 | /is-extglob/2.1.1: 1007 | resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} 1008 | engines: {node: '>=0.10.0'} 1009 | dev: true 1010 | 1011 | /is-glob/4.0.3: 1012 | resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} 1013 | engines: {node: '>=0.10.0'} 1014 | dependencies: 1015 | is-extglob: 2.1.1 1016 | dev: true 1017 | 1018 | /is-module/1.0.0: 1019 | resolution: {integrity: sha1-Mlj7afeMFNW4FdZkM2tM/7ZEFZE=} 1020 | dev: true 1021 | 1022 | /is-number/7.0.0: 1023 | resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} 1024 | engines: {node: '>=0.12.0'} 1025 | dev: true 1026 | 1027 | /is-reference/1.2.1: 1028 | resolution: {integrity: sha512-U82MsXXiFIrjCK4otLT+o2NA2Cd2g5MLoOVXUZjIOhLurrRxpEXzI8O0KZHr3IjLvlAH1kTPYSuqer5T9ZVBKQ==} 1029 | dependencies: 1030 | '@types/estree': 0.0.47 1031 | dev: true 1032 | 1033 | /isexe/2.0.0: 1034 | resolution: {integrity: sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=} 1035 | dev: true 1036 | 1037 | /js-tokens/4.0.0: 1038 | resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} 1039 | dev: true 1040 | 1041 | /jsesc/2.5.2: 1042 | resolution: {integrity: sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==} 1043 | engines: {node: '>=4'} 1044 | hasBin: true 1045 | dev: true 1046 | 1047 | /json5/2.2.0: 1048 | resolution: {integrity: sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA==} 1049 | engines: {node: '>=6'} 1050 | hasBin: true 1051 | dependencies: 1052 | minimist: 1.2.6 1053 | dev: true 1054 | 1055 | /jsonc-parser/3.0.0: 1056 | resolution: {integrity: sha512-fQzRfAbIBnR0IQvftw9FJveWiHp72Fg20giDrHz6TdfB12UH/uue0D3hm57UB5KgAVuniLMCaS8P1IMj9NR7cA==} 1057 | dev: true 1058 | 1059 | /lilconfig/2.0.6: 1060 | resolution: {integrity: sha512-9JROoBW7pobfsx+Sq2JsASvCo6Pfo6WWoUW79HuB1BCoBXD4PLWJPqDF6fNj67pqBYTbAHkE57M1kS/+L1neOg==} 1061 | engines: {node: '>=10'} 1062 | dev: true 1063 | 1064 | /lodash/4.17.21: 1065 | resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} 1066 | dev: true 1067 | 1068 | /magic-string/0.25.7: 1069 | resolution: {integrity: sha512-4CrMT5DOHTDk4HYDlzmwu4FVCcIYI8gauveasrdCu2IKIFOJ3f0v/8MDGJCDL9oD2ppz/Av1b0Nj345H9M+XIA==} 1070 | dependencies: 1071 | sourcemap-codec: 1.4.8 1072 | dev: true 1073 | 1074 | /marked/2.0.1: 1075 | resolution: {integrity: sha512-5+/fKgMv2hARmMW7DOpykr2iLhl0NgjyELk5yn92iE7z8Se1IS9n3UsFm86hFXIkvMBmVxki8+ckcpjBeyo/hw==} 1076 | engines: {node: '>= 8.16.2'} 1077 | hasBin: true 1078 | dev: false 1079 | 1080 | /merge2/1.4.1: 1081 | resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} 1082 | engines: {node: '>= 8'} 1083 | dev: true 1084 | 1085 | /micromatch/4.0.4: 1086 | resolution: {integrity: sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg==} 1087 | engines: {node: '>=8.6'} 1088 | dependencies: 1089 | braces: 3.0.2 1090 | picomatch: 2.3.0 1091 | dev: true 1092 | 1093 | /minimatch/3.0.4: 1094 | resolution: {integrity: sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==} 1095 | dependencies: 1096 | brace-expansion: 1.1.11 1097 | dev: true 1098 | 1099 | /minimist/1.2.6: 1100 | resolution: {integrity: sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==} 1101 | dev: true 1102 | 1103 | /ms/2.1.2: 1104 | resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==} 1105 | dev: true 1106 | 1107 | /nanoid/3.3.4: 1108 | resolution: {integrity: sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==} 1109 | engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} 1110 | hasBin: true 1111 | dev: true 1112 | 1113 | /node-releases/1.1.71: 1114 | resolution: {integrity: sha512-zR6HoT6LrLCRBwukmrVbHv0EpEQjksO6GmFcZQQuCAy139BEsoVKPYnf3jongYW83fAa1torLGYwxxky/p28sg==} 1115 | dev: true 1116 | 1117 | /normalize-path/3.0.0: 1118 | resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} 1119 | engines: {node: '>=0.10.0'} 1120 | dev: true 1121 | 1122 | /object-hash/3.0.0: 1123 | resolution: {integrity: sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==} 1124 | engines: {node: '>= 6'} 1125 | dev: true 1126 | 1127 | /once/1.4.0: 1128 | resolution: {integrity: sha1-WDsap3WWHUsROsF9nFC6753Xa9E=} 1129 | dependencies: 1130 | wrappy: 1.0.2 1131 | dev: true 1132 | 1133 | /path-is-absolute/1.0.1: 1134 | resolution: {integrity: sha1-F0uSaHNVNP+8es5r9TpanhtcX18=} 1135 | engines: {node: '>=0.10.0'} 1136 | dev: true 1137 | 1138 | /path-key/3.1.1: 1139 | resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} 1140 | engines: {node: '>=8'} 1141 | dev: true 1142 | 1143 | /path-parse/1.0.6: 1144 | resolution: {integrity: sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==} 1145 | dev: true 1146 | 1147 | /path-parse/1.0.7: 1148 | resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} 1149 | dev: true 1150 | 1151 | /picocolors/1.0.0: 1152 | resolution: {integrity: sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==} 1153 | dev: true 1154 | 1155 | /picomatch/2.2.2: 1156 | resolution: {integrity: sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==} 1157 | engines: {node: '>=8.6'} 1158 | dev: true 1159 | 1160 | /picomatch/2.3.0: 1161 | resolution: {integrity: sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==} 1162 | engines: {node: '>=8.6'} 1163 | dev: true 1164 | 1165 | /pify/2.3.0: 1166 | resolution: {integrity: sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==} 1167 | engines: {node: '>=0.10.0'} 1168 | dev: true 1169 | 1170 | /postcss-import/14.1.0_postcss@8.4.14: 1171 | resolution: {integrity: sha512-flwI+Vgm4SElObFVPpTIT7SU7R3qk2L7PyduMcokiaVKuWv9d/U+Gm/QAd8NDLuykTWTkcrjOeD2Pp1rMeBTGw==} 1172 | engines: {node: '>=10.0.0'} 1173 | peerDependencies: 1174 | postcss: ^8.0.0 1175 | dependencies: 1176 | postcss: 8.4.14 1177 | postcss-value-parser: 4.2.0 1178 | read-cache: 1.0.0 1179 | resolve: 1.22.1 1180 | dev: true 1181 | 1182 | /postcss-js/4.0.0_postcss@8.4.14: 1183 | resolution: {integrity: sha512-77QESFBwgX4irogGVPgQ5s07vLvFqWr228qZY+w6lW599cRlK/HmnlivnnVUxkjHnCu4J16PDMHcH+e+2HbvTQ==} 1184 | engines: {node: ^12 || ^14 || >= 16} 1185 | peerDependencies: 1186 | postcss: ^8.3.3 1187 | dependencies: 1188 | camelcase-css: 2.0.1 1189 | postcss: 8.4.14 1190 | dev: true 1191 | 1192 | /postcss-load-config/3.1.4_postcss@8.4.14: 1193 | resolution: {integrity: sha512-6DiM4E7v4coTE4uzA8U//WhtPwyhiim3eyjEMFCnUpzbrkK9wJHgKDT2mR+HbtSrd/NubVaYTOpSpjUl8NQeRg==} 1194 | engines: {node: '>= 10'} 1195 | peerDependencies: 1196 | postcss: '>=8.0.9' 1197 | ts-node: '>=9.0.0' 1198 | peerDependenciesMeta: 1199 | postcss: 1200 | optional: true 1201 | ts-node: 1202 | optional: true 1203 | dependencies: 1204 | lilconfig: 2.0.6 1205 | postcss: 8.4.14 1206 | yaml: 1.10.2 1207 | dev: true 1208 | 1209 | /postcss-nested/5.0.6: 1210 | resolution: {integrity: sha512-rKqm2Fk0KbA8Vt3AdGN0FB9OBOMDVajMG6ZCf/GoHgdxUJ4sBFp0A/uMIRm+MJUdo33YXEtjqIz8u7DAp8B7DA==} 1211 | engines: {node: '>=12.0'} 1212 | peerDependencies: 1213 | postcss: ^8.2.14 1214 | dependencies: 1215 | postcss-selector-parser: 6.0.6 1216 | dev: true 1217 | 1218 | /postcss-nested/5.0.6_postcss@8.4.14: 1219 | resolution: {integrity: sha512-rKqm2Fk0KbA8Vt3AdGN0FB9OBOMDVajMG6ZCf/GoHgdxUJ4sBFp0A/uMIRm+MJUdo33YXEtjqIz8u7DAp8B7DA==} 1220 | engines: {node: '>=12.0'} 1221 | peerDependencies: 1222 | postcss: ^8.2.14 1223 | dependencies: 1224 | postcss: 8.4.14 1225 | postcss-selector-parser: 6.0.6 1226 | dev: true 1227 | 1228 | /postcss-selector-parser/6.0.10: 1229 | resolution: {integrity: sha512-IQ7TZdoaqbT+LCpShg46jnZVlhWD2w6iQYAcYXfHARZ7X1t/UGhhceQDs5X0cGqKvYlHNOuv7Oa1xmb0oQuA3w==} 1230 | engines: {node: '>=4'} 1231 | dependencies: 1232 | cssesc: 3.0.0 1233 | util-deprecate: 1.0.2 1234 | dev: true 1235 | 1236 | /postcss-selector-parser/6.0.6: 1237 | resolution: {integrity: sha512-9LXrvaaX3+mcv5xkg5kFwqSzSH1JIObIx51PrndZwlmznwXRfxMddDvo9gve3gVR8ZTKgoFDdWkbRFmEhT4PMg==} 1238 | engines: {node: '>=4'} 1239 | dependencies: 1240 | cssesc: 3.0.0 1241 | util-deprecate: 1.0.2 1242 | dev: true 1243 | 1244 | /postcss-value-parser/4.2.0: 1245 | resolution: {integrity: sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==} 1246 | dev: true 1247 | 1248 | /postcss/8.4.14: 1249 | resolution: {integrity: sha512-E398TUmfAYFPBSdzgeieK2Y1+1cpdxJx8yXbK/m57nRhKSmk1GB2tO4lbLBtlkfPQTDKfe4Xqv1ASWPpayPEig==} 1250 | engines: {node: ^10 || ^12 || >=14} 1251 | dependencies: 1252 | nanoid: 3.3.4 1253 | picocolors: 1.0.0 1254 | source-map-js: 1.0.2 1255 | dev: true 1256 | 1257 | /preact/10.5.13: 1258 | resolution: {integrity: sha512-q/vlKIGNwzTLu+jCcvywgGrt+H/1P/oIRSD6mV4ln3hmlC+Aa34C7yfPI4+5bzW8pONyVXYS7SvXosy2dKKtWQ==} 1259 | 1260 | /prettier/2.2.1: 1261 | resolution: {integrity: sha512-PqyhM2yCjg/oKkFPtTGUojv7gnZAoG80ttl45O6x2Ug/rMJw4wcc9k6aaf2hibP7BGVCCM33gZoGjyvt9mm16Q==} 1262 | engines: {node: '>=10.13.0'} 1263 | hasBin: true 1264 | dev: true 1265 | 1266 | /prismjs/1.23.0: 1267 | resolution: {integrity: sha512-c29LVsqOaLbBHuIbsTxaKENh1N2EQBOHaWv7gkHN4dgRbxSREqDnDbtFJYdpPauS4YCplMSNCABQ6Eeor69bAA==} 1268 | optionalDependencies: 1269 | clipboard: 2.0.8 1270 | dev: false 1271 | 1272 | /queue-microtask/1.2.3: 1273 | resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} 1274 | dev: true 1275 | 1276 | /quick-lru/5.1.1: 1277 | resolution: {integrity: sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==} 1278 | engines: {node: '>=10'} 1279 | dev: true 1280 | 1281 | /read-cache/1.0.0: 1282 | resolution: {integrity: sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==} 1283 | dependencies: 1284 | pify: 2.3.0 1285 | dev: true 1286 | 1287 | /readdirp/3.6.0: 1288 | resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} 1289 | engines: {node: '>=8.10.0'} 1290 | dependencies: 1291 | picomatch: 2.3.0 1292 | dev: true 1293 | 1294 | /resolve/1.20.0: 1295 | resolution: {integrity: sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==} 1296 | dependencies: 1297 | is-core-module: 2.2.0 1298 | path-parse: 1.0.6 1299 | dev: true 1300 | 1301 | /resolve/1.22.1: 1302 | resolution: {integrity: sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==} 1303 | hasBin: true 1304 | dependencies: 1305 | is-core-module: 2.9.0 1306 | path-parse: 1.0.7 1307 | supports-preserve-symlinks-flag: 1.0.0 1308 | dev: true 1309 | 1310 | /reusify/1.0.4: 1311 | resolution: {integrity: sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==} 1312 | engines: {iojs: '>=1.0.0', node: '>=0.10.0'} 1313 | dev: true 1314 | 1315 | /rollup-plugin-dts/4.0.1_yd2cn43vjkyhfubwloxl6r5ft4: 1316 | resolution: {integrity: sha512-DNv5F8pro/r0Hkx3JWKRtJZocDnqXfgypoajeiaNq134rYaFcEIl/oas5PogD1qexMadVijsHyVko1Chig0OOQ==} 1317 | engines: {node: '>=v12.22.6'} 1318 | peerDependencies: 1319 | rollup: ^2.56.3 1320 | typescript: ^4.4.2 1321 | dependencies: 1322 | magic-string: 0.25.7 1323 | rollup: 2.61.0 1324 | typescript: 4.2.3 1325 | optionalDependencies: 1326 | '@babel/code-frame': 7.16.0 1327 | dev: true 1328 | 1329 | /rollup/2.61.0: 1330 | resolution: {integrity: sha512-teQ+T1mUYbyvGyUavCodiyA9hD4DxwYZJwr/qehZGhs1Z49vsmzelMVYMxGU4ZhGRKxYPupHuz5yzm/wj7VpWA==} 1331 | engines: {node: '>=10.0.0'} 1332 | hasBin: true 1333 | optionalDependencies: 1334 | fsevents: 2.3.2 1335 | dev: true 1336 | 1337 | /rollup/2.77.2: 1338 | resolution: {integrity: sha512-m/4YzYgLcpMQbxX3NmAqDvwLATZzxt8bIegO78FZLl+lAgKJBd1DRAOeEiZcKOIOPjxE6ewHWHNgGEalFXuz1g==} 1339 | engines: {node: '>=10.0.0'} 1340 | hasBin: true 1341 | optionalDependencies: 1342 | fsevents: 2.3.2 1343 | dev: true 1344 | 1345 | /run-parallel/1.2.0: 1346 | resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} 1347 | dependencies: 1348 | queue-microtask: 1.2.3 1349 | dev: true 1350 | 1351 | /safe-buffer/5.1.2: 1352 | resolution: {integrity: sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==} 1353 | dev: true 1354 | 1355 | /select/1.1.2: 1356 | resolution: {integrity: sha1-DnNQrN7ICxEIUoeG7B1EGNEbOW0=} 1357 | dev: false 1358 | optional: true 1359 | 1360 | /semver/6.3.0: 1361 | resolution: {integrity: sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==} 1362 | hasBin: true 1363 | dev: true 1364 | 1365 | /shebang-command/2.0.0: 1366 | resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} 1367 | engines: {node: '>=8'} 1368 | dependencies: 1369 | shebang-regex: 3.0.0 1370 | dev: true 1371 | 1372 | /shebang-regex/3.0.0: 1373 | resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} 1374 | engines: {node: '>=8'} 1375 | dev: true 1376 | 1377 | /slash/3.0.0: 1378 | resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==} 1379 | engines: {node: '>=8'} 1380 | dev: true 1381 | 1382 | /source-map-js/1.0.2: 1383 | resolution: {integrity: sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==} 1384 | engines: {node: '>=0.10.0'} 1385 | dev: true 1386 | 1387 | /source-map/0.5.7: 1388 | resolution: {integrity: sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==} 1389 | engines: {node: '>=0.10.0'} 1390 | dev: true 1391 | 1392 | /sourcemap-codec/1.4.8: 1393 | resolution: {integrity: sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==} 1394 | dev: true 1395 | 1396 | /supports-color/5.5.0: 1397 | resolution: {integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==} 1398 | engines: {node: '>=4'} 1399 | dependencies: 1400 | has-flag: 3.0.0 1401 | dev: true 1402 | 1403 | /supports-preserve-symlinks-flag/1.0.0: 1404 | resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} 1405 | engines: {node: '>= 0.4'} 1406 | dev: true 1407 | 1408 | /tailwindcss/3.1.7: 1409 | resolution: {integrity: sha512-r7mgumZ3k0InfVPpGWcX8X/Ut4xBfv+1O/+C73ar/m01LxGVzWvPxF/w6xIUPEztrCoz7axfx0SMdh8FH8ZvRQ==} 1410 | engines: {node: '>=12.13.0'} 1411 | hasBin: true 1412 | dependencies: 1413 | arg: 5.0.2 1414 | chokidar: 3.5.3 1415 | color-name: 1.1.4 1416 | detective: 5.2.1 1417 | didyoumean: 1.2.2 1418 | dlv: 1.1.3 1419 | fast-glob: 3.2.11 1420 | glob-parent: 6.0.2 1421 | is-glob: 4.0.3 1422 | lilconfig: 2.0.6 1423 | normalize-path: 3.0.0 1424 | object-hash: 3.0.0 1425 | picocolors: 1.0.0 1426 | postcss: 8.4.14 1427 | postcss-import: 14.1.0_postcss@8.4.14 1428 | postcss-js: 4.0.0_postcss@8.4.14 1429 | postcss-load-config: 3.1.4_postcss@8.4.14 1430 | postcss-nested: 5.0.6_postcss@8.4.14 1431 | postcss-selector-parser: 6.0.10 1432 | postcss-value-parser: 4.2.0 1433 | quick-lru: 5.1.1 1434 | resolve: 1.22.1 1435 | transitivePeerDependencies: 1436 | - ts-node 1437 | dev: true 1438 | 1439 | /tiny-emitter/2.1.0: 1440 | resolution: {integrity: sha512-NB6Dk1A9xgQPMoGqC5CVXn123gWyte215ONT5Pp5a0yt4nlEoO1ZWeCwpncaekPHXO60i47ihFnZPiRPjRMq4Q==} 1441 | dev: false 1442 | optional: true 1443 | 1444 | /to-fast-properties/2.0.0: 1445 | resolution: {integrity: sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==} 1446 | engines: {node: '>=4'} 1447 | dev: true 1448 | 1449 | /to-regex-range/5.0.1: 1450 | resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} 1451 | engines: {node: '>=8.0'} 1452 | dependencies: 1453 | is-number: 7.0.0 1454 | dev: true 1455 | 1456 | /type-fest/0.21.3: 1457 | resolution: {integrity: sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==} 1458 | engines: {node: '>=10'} 1459 | dev: true 1460 | 1461 | /typescript/4.2.3: 1462 | resolution: {integrity: sha512-qOcYwxaByStAWrBf4x0fibwZvMRG+r4cQoTjbPtUlrWjBHbmCAww1i448U0GJ+3cNNEtebDteo/cHOR3xJ4wEw==} 1463 | engines: {node: '>=4.2.0'} 1464 | hasBin: true 1465 | dev: true 1466 | 1467 | /util-deprecate/1.0.2: 1468 | resolution: {integrity: sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=} 1469 | dev: true 1470 | 1471 | /vite/3.0.4: 1472 | resolution: {integrity: sha512-NU304nqnBeOx2MkQnskBQxVsa0pRAH5FphokTGmyy8M3oxbvw7qAXts2GORxs+h/2vKsD+osMhZ7An6yK6F1dA==} 1473 | engines: {node: ^14.18.0 || >=16.0.0} 1474 | hasBin: true 1475 | peerDependencies: 1476 | less: '*' 1477 | sass: '*' 1478 | stylus: '*' 1479 | terser: ^5.4.0 1480 | peerDependenciesMeta: 1481 | less: 1482 | optional: true 1483 | sass: 1484 | optional: true 1485 | stylus: 1486 | optional: true 1487 | terser: 1488 | optional: true 1489 | dependencies: 1490 | esbuild: 0.14.51 1491 | postcss: 8.4.14 1492 | resolve: 1.22.1 1493 | rollup: 2.77.2 1494 | optionalDependencies: 1495 | fsevents: 2.3.2 1496 | dev: true 1497 | 1498 | /which/2.0.2: 1499 | resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} 1500 | engines: {node: '>= 8'} 1501 | hasBin: true 1502 | dependencies: 1503 | isexe: 2.0.0 1504 | dev: true 1505 | 1506 | /wrappy/1.0.2: 1507 | resolution: {integrity: sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=} 1508 | dev: true 1509 | 1510 | /xtend/4.0.2: 1511 | resolution: {integrity: sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==} 1512 | engines: {node: '>=0.4'} 1513 | dev: true 1514 | 1515 | /yaml/1.10.2: 1516 | resolution: {integrity: sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==} 1517 | engines: {node: '>= 6'} 1518 | dev: true 1519 | -------------------------------------------------------------------------------- /postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | 'postcss-nested': {}, 4 | tailwindcss: {}, 5 | }, 6 | } 7 | -------------------------------------------------------------------------------- /scripts/build.ts: -------------------------------------------------------------------------------- 1 | import { build } from 'vite' 2 | import { buildTypes, createConfig } from './utils' 3 | 4 | async function main() { 5 | for (const config of [ 6 | createConfig('preact', true), 7 | createConfig('preact'), 8 | createConfig('fre', true), 9 | createConfig('fre'), 10 | ]) { 11 | await build(config) 12 | } 13 | await buildTypes() 14 | } 15 | 16 | main().catch((error) => { 17 | console.error(error) 18 | process.exit(1) 19 | }) 20 | -------------------------------------------------------------------------------- /scripts/utils.ts: -------------------------------------------------------------------------------- 1 | import fs from 'fs' 2 | import path from 'path' 3 | import { rollup } from 'rollup' 4 | import dts from 'rollup-plugin-dts' 5 | import tsResolve from '@egoist/rollup-plugin-ts-resolve' 6 | import { UserConfig } from 'vite' 7 | 8 | const pkg = JSON.parse(fs.readFileSync('./package.json', 'utf8')) 9 | 10 | function getPrismLanguages() { 11 | const files = fs.readdirSync('node_modules/prismjs/components') 12 | return files 13 | .filter((file) => file.endsWith('.min.js')) 14 | .map((file) => { 15 | const [, name] = /\-([^\.]+)/.exec(file)! 16 | return name 17 | }) 18 | } 19 | 20 | export const createConfig = ( 21 | renderer: 'preact' | 'fre', 22 | minify?: boolean, 23 | isWebsite?: boolean 24 | ): UserConfig => { 25 | return { 26 | esbuild: { 27 | jsxFactory: 'h', 28 | jsxFragment: 'Fragment', 29 | legalComments: 'none', 30 | }, 31 | define: { 32 | DOCUP_VERSION: JSON.stringify(pkg.version), 33 | PRISM_VERSION: JSON.stringify(require('prismjs/package').version), 34 | PRISM_LANGUAGES: JSON.stringify(getPrismLanguages()), 35 | }, 36 | 37 | build: { 38 | emptyOutDir: false, 39 | minify, 40 | sourcemap: true, 41 | target: 'esnext', 42 | rollupOptions: { 43 | preserveEntrySignatures: 'strict', 44 | input: isWebsite 45 | ? [path.resolve('./docs/index.html'), path.resolve('./docs/main.ts')] 46 | : ['./src/docup.ts'], 47 | output: { 48 | format: 'esm', 49 | manualChunks: undefined, 50 | ...(isWebsite 51 | ? {} 52 | : { 53 | entryFileNames() { 54 | return (renderer === 'fre' 55 | ? 'docup.fre.js' 56 | : 'docup.js' 57 | ).replace(/\.js$/, () => (minify ? '.min.js' : '.js')) 58 | }, 59 | assetFileNames(chunk) { 60 | if (chunk.name?.endsWith('docup.css')) { 61 | return `docup${minify ? '.min' : ''}.css` 62 | } 63 | return chunk.name! 64 | }, 65 | }), 66 | }, 67 | }, 68 | }, 69 | resolve: { 70 | alias: { 71 | renderer: path.resolve('src/renderer/' + renderer + '.ts'), 72 | }, 73 | }, 74 | } 75 | } 76 | 77 | export async function buildTypes() { 78 | const deps = [ 79 | ...Object.keys(pkg.dependencies || {}), 80 | ...Object.keys(pkg.peerDependencies || {}), 81 | ] 82 | const bundle = await rollup({ 83 | input: ['./src/docup.ts'], 84 | plugins: [ 85 | { 86 | name: 'ignore', 87 | resolveId(id) { 88 | if (id === 'renderer') return false 89 | if (deps.some((dep) => id === dep || id.startsWith(dep + '/'))) 90 | return false 91 | }, 92 | load(id) { 93 | if (/\.css$/.test(id)) return '' 94 | }, 95 | }, 96 | // @ts-expect-error 97 | tsResolve(), 98 | dts(), 99 | ], 100 | }) 101 | await bundle.write({ 102 | format: 'esm', 103 | dir: './dist', 104 | }) 105 | } 106 | -------------------------------------------------------------------------------- /src/components/App.tsx: -------------------------------------------------------------------------------- 1 | import { h, FC, useEffect, useState, useCallback } from 'renderer' 2 | import inView from 'element-in-view' 3 | import { InstanceOptions } from '../docup' 4 | import { Navbar } from './Navbar' 5 | import { Sidebar } from './Sidebar' 6 | import { Main } from './Main' 7 | import { renderMarkdown, SidebarMenuItem } from '../markdown' 8 | import { 9 | loadLanguages, 10 | scrollToHash, 11 | updateURLHash, 12 | throttle, 13 | getFileUrl, 14 | } from '../utils' 15 | import { initMarkdownComponentsProxy, setMdProps } from '../markdown-component' 16 | 17 | const handleScroll = throttle(() => { 18 | const headings = document.querySelectorAll('.content .heading') 19 | for (let i = 0; i < headings.length; i++) { 20 | const heading = headings[i] 21 | if ( 22 | inView(heading, { 23 | offset: 58 /* height of navbar + 10px */, 24 | }) 25 | ) { 26 | const id = heading.id 27 | if (id) { 28 | // Updating URL in browser address without adding it to history 29 | updateURLHash(`#${id}`, true) 30 | } 31 | break 32 | } 33 | } 34 | }, 200) 35 | 36 | export type LoadingState = 'loading' | 'success' | 'error' 37 | 38 | export const App: FC<{ options: InstanceOptions }> = ({ options }) => { 39 | const navLinks = options.navLinks || [] 40 | const [html, setHtml] = useState('') 41 | const [loadingState, setLoadingState] = useState('loading') 42 | const [menu, setMenu] = useState([]) 43 | const [showSidebar, setShowSidebar] = useState(false) 44 | 45 | const toggleSidebar = () => setShowSidebar(!showSidebar) 46 | 47 | useEffect(() => { 48 | setMdProps(options.props) 49 | initMarkdownComponentsProxy() 50 | Promise.all([ 51 | fetch(getFileUrl(options.root, options.indexFile, location.pathname)), 52 | options.highlightLanguages && loadLanguages(options.highlightLanguages), 53 | ]) 54 | .then(([res]) => { 55 | return res.text() 56 | }) 57 | .then((text) => { 58 | const { html, menu, fns } = renderMarkdown(text) 59 | setHtml(html) 60 | setMenu(menu) 61 | setLoadingState('success') 62 | setTimeout(() => { 63 | fns.forEach((fn) => fn()) 64 | setTimeout(() => { 65 | if (location.hash) { 66 | scrollToHash(location.hash) 67 | } 68 | }) 69 | }) 70 | }) 71 | }, []) 72 | 73 | useEffect(() => { 74 | document.body.style.overflow = showSidebar ? 'hidden' : 'auto' 75 | }, [showSidebar]) 76 | 77 | // Scroll to element on click 78 | useEffect(() => { 79 | const handleClick = (e: MouseEvent) => { 80 | let target = e.target as any 81 | if (target.closest) { 82 | target = target.closest('a') 83 | if (!target) { 84 | return 85 | } 86 | } else { 87 | while (target && target.tagName !== 'A') { 88 | target = target.parentNode 89 | if (!target) { 90 | return 91 | } 92 | } 93 | } 94 | const href = target.getAttribute('href') 95 | if (href && /^#.+/.test(href)) { 96 | e.preventDefault() 97 | updateURLHash(href, false) 98 | scrollToHash(href) 99 | } 100 | } 101 | window.addEventListener('click', handleClick) 102 | return () => window.removeEventListener('click', handleClick) 103 | }, []) 104 | 105 | useEffect(() => { 106 | // Update location.hash on scrolling 107 | window.addEventListener('scroll', handleScroll) 108 | return () => window.removeEventListener('scroll', handleScroll) 109 | }, []) 110 | 111 | const mediaQuery = '(prefers-color-scheme: dark)' 112 | const updateDarkModeClass = useCallback(() => { 113 | if (options.useSystemTheme === false) return 114 | 115 | if (window.matchMedia(mediaQuery).matches) { 116 | document.documentElement.classList.add('dark') 117 | } else { 118 | document.documentElement.classList.remove('dark') 119 | } 120 | }, [options.useSystemTheme]) 121 | 122 | useEffect(() => { 123 | updateDarkModeClass() 124 | 125 | const listener = () => updateDarkModeClass() 126 | const m = window.matchMedia(mediaQuery) 127 | m.addEventListener('change', listener) 128 | 129 | return () => { 130 | m.removeEventListener('change', listener) 131 | } 132 | }, []) 133 | 134 | return ( 135 |
136 | {showSidebar && ( 137 |
setShowSidebar(false)} 139 | class="sidebar_overlay fixed top-0 bottom-0 w-full bg-gray-200 bg-opacity-50" 140 | >
141 | )} 142 | 148 | 156 |
157 |
158 | ) 159 | } 160 | -------------------------------------------------------------------------------- /src/components/Main.tsx: -------------------------------------------------------------------------------- 1 | import { h, FC, setHtml } from 'renderer' 2 | import { LoadingState } from './App' 3 | 4 | export const Main: FC<{ 5 | html: string 6 | loadingState: LoadingState 7 | }> = ({ html, loadingState }) => { 8 | return ( 9 |
10 |
11 | {loadingState === 'loading' ? ( 12 |
13 |
14 |
15 |
16 |
17 | ) : ( 18 |
19 | )} 20 |
21 |
22 | ) 23 | } 24 | -------------------------------------------------------------------------------- /src/components/Navbar.tsx: -------------------------------------------------------------------------------- 1 | import { FC, h } from 'renderer' 2 | import { NavLink } from '../docup' 3 | 4 | export const Navbar: FC<{ 5 | navLinks: NavLink[] 6 | title: string 7 | base: string 8 | toggleSidebar: () => void 9 | }> = ({ title, base, navLinks, toggleSidebar }) => { 10 | return ( 11 | 40 | ) 41 | } 42 | -------------------------------------------------------------------------------- /src/components/Sidebar.tsx: -------------------------------------------------------------------------------- 1 | import { h, FC, useEffect, useState, useRef, setHtml } from 'renderer' 2 | import { SidebarMenuItem } from '../markdown' 3 | import { NavLink } from '../docup' 4 | 5 | export const Sidebar: FC<{ 6 | menu: SidebarMenuItem[] 7 | title: string 8 | base: string 9 | showSidebar: boolean 10 | navLinks: NavLink[] 11 | beforeSidebar?: string 12 | }> = ({ menu, title, base, showSidebar, navLinks, beforeSidebar }) => { 13 | const [hash, setHash] = useState('') 14 | const sidebarRef = useRef(null) 15 | let sidebarItemClicked = false 16 | 17 | const handleSidebarItemClick = () => { 18 | sidebarItemClicked = true 19 | } 20 | 21 | useEffect(() => { 22 | setHash(decodeURIComponent(location.hash)) 23 | const onHashChange = () => { 24 | const decodedHash = decodeURIComponent(location.hash) 25 | setHash(decodedHash) 26 | 27 | // Don't change scroll position when the hashchange is triggered click, that's bad user experience 28 | if (location.hash && !sidebarItemClicked) { 29 | const el: HTMLAnchorElement | null = document.querySelector( 30 | `.sidebar .menu_item[href="${decodedHash}"]` 31 | ) 32 | if (el) { 33 | if (sidebarRef.current) { 34 | sidebarRef.current.scrollTop = el.offsetTop - 100 35 | } 36 | } 37 | } 38 | sidebarItemClicked = false 39 | } 40 | window.addEventListener('hashchange', onHashChange) 41 | return () => window.removeEventListener('hashchange', onHashChange) 42 | }, []) 43 | 44 | return ( 45 |
52 | 72 | {beforeSidebar && ( 73 |
74 |
75 |
76 | )} 77 |
78 | {menu.map((item, index) => { 79 | return ( 80 | 92 | ) 93 | })} 94 |
95 |
96 | ) 97 | } 98 | -------------------------------------------------------------------------------- /src/css/content.css: -------------------------------------------------------------------------------- 1 | .content { 2 | font-size: 1.175rem; 3 | } 4 | 5 | .content pre { 6 | overflow: auto; 7 | } 8 | 9 | .content img { 10 | max-width: 100%; 11 | } 12 | 13 | .content > *, 14 | .content p { 15 | @apply my-5; 16 | } 17 | 18 | .content > *:first-child, 19 | .content > *:first-child > *:first-child { 20 | @apply mt-0; 21 | } 22 | 23 | .content > *:last-child, 24 | .content > *:last-child > *:last-child { 25 | @apply mb-0; 26 | } 27 | 28 | .content a { 29 | color: var(--content-link-fg); 30 | } 31 | 32 | .content a:hover { 33 | text-decoration: var(--content-link-hover-decoration); 34 | } 35 | 36 | .content h2 { 37 | font-size: 2.3rem; 38 | font-weight: 700; 39 | @apply border-b-2; 40 | @apply border-yellow-300; 41 | @apply pb-1; 42 | @apply mt-10; 43 | @apply mb-8; 44 | } 45 | 46 | .content h3 { 47 | @apply font-normal; 48 | @apply mt-10; 49 | font-size: 2rem; 50 | } 51 | 52 | .content h4 { 53 | font-size: 1.5rem; 54 | @apply mt-10; 55 | } 56 | 57 | .content h5 { 58 | font-size: 1.1rem; 59 | } 60 | 61 | .content h6 { 62 | font-size: 1rem; 63 | font-weight: bold; 64 | } 65 | 66 | .content ul { 67 | @apply list-disc; 68 | margin-left: 1.25rem; 69 | } 70 | 71 | .content blockquote { 72 | padding: 10px 15px; 73 | border-left: 3px solid rgb(0, 0, 0); 74 | margin: 20px 0px; 75 | } 76 | .content blockquote p, 77 | .message p { 78 | margin: 0; 79 | } 80 | blockquote p:not(:first-child), 81 | .message p:not(:first-child) { 82 | margin-top: 20px; 83 | } 84 | .message { 85 | background: whitesmoke; 86 | border: 1px solid #dbdbdb; 87 | border-radius: 3px; 88 | color: #4a4a4a; 89 | padding: 1em 1.25em; 90 | margin: 25px 0; 91 | @apply dark:text-gray-200 dark:border-gray-600 dark:bg-gray-500 dark:bg-opacity-25; 92 | } 93 | .message.message_type__alert { 94 | background: #fff5f7; 95 | border-color: #ff3860; 96 | color: #cd0930; 97 | @apply dark:border-red-900 dark:bg-red-700 dark:bg-opacity-25; 98 | } 99 | .message.message_type__info { 100 | background: #f6fbfe; 101 | border-color: #209cee; 102 | color: #12537e; 103 | @apply dark:text-blue-500 dark:border-blue-800 dark:bg-blue-600 dark:bg-opacity-25; 104 | } 105 | .message.message_type__warning { 106 | background: #fffdf5; 107 | border-color: #ffdd57; 108 | color: #3b3108; 109 | @apply dark:text-yellow-500 dark:border-yellow-700 dark:bg-yellow-500 dark:bg-opacity-25; 110 | } 111 | .message.message_type__success { 112 | background: #f6fef9; 113 | border-color: #23d160; 114 | color: #0e301a; 115 | @apply dark:text-green-300 dark:border-green-900 dark:bg-green-800 dark:bg-opacity-25; 116 | } 117 | 118 | .anchor { 119 | position: relative; 120 | margin-left: -14px; 121 | opacity: 0.5; 122 | display: inline-block; 123 | width: 14px; 124 | height: 14px; 125 | visibility: hidden; 126 | } 127 | .anchor:hover { 128 | opacity: 1; 129 | } 130 | .anchor svg { 131 | position: absolute; 132 | right: 5px; 133 | top: 0; 134 | } 135 | .content h2:hover .anchor, 136 | .content h3:hover .anchor, 137 | .content h4:hover .anchor { 138 | visibility: visible; 139 | } 140 | 141 | .task_list__item { 142 | @apply list-none; 143 | } 144 | 145 | .task_list__item input[type='checkbox']:first-child { 146 | @apply mr-2; 147 | } 148 | 149 | table { 150 | font-size: 0.95rem; 151 | } 152 | table code { 153 | font-size: 0.85rem; 154 | } 155 | 156 | table td, 157 | table th { 158 | border: 1px solid var(--table-border-fg); 159 | padding: 7px 10px; 160 | } 161 | 162 | table > tbody > tr > td:first-child { 163 | padding-right: 5px; 164 | } 165 | table > tbody > tr > td:not(:first-child) { 166 | padding-left: 5px; 167 | } 168 | 169 | table code { 170 | background: unset; 171 | padding: unset; 172 | } 173 | 174 | .content select { 175 | @apply border rounded; 176 | } 177 | -------------------------------------------------------------------------------- /src/css/main.css: -------------------------------------------------------------------------------- 1 | :root { 2 | --fg: #000; 3 | --bg: #fff; 4 | --border-fg: rgb(218, 218, 218); 5 | --navbar-bg: #ffffff; 6 | --navbar-fg: inherit; 7 | --navlink-fg: inherit; 8 | --navlink-hover-fg: inherit; 9 | --navlink-hover-bg: #d8d8d8; 10 | 11 | --sidebar-bg: #ffffff; 12 | --sidebar-width: 300px; 13 | --sidebar-text-fg: #6b6867; 14 | 15 | --sidebar-menu-item-active-fg: #3e2723; 16 | 17 | --code-block-bg: #f8f8f8; 18 | --code-block-border-fg: rgb(201, 201, 201); 19 | --code-span-bg: #f8f3f0; 20 | --code-block-fg: rgb(94, 94, 94); 21 | --code-span-fg: inherit; 22 | --code-font: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace; 23 | 24 | --content-link-fg: rgb(20, 121, 20); 25 | --content-link-hover-decoration: underline; 26 | 27 | --table-border-fg: #e2e2e2; 28 | 29 | --loader-start-bg: #eeeeee; 30 | --loader-end-bg: #e4e2e1; 31 | } 32 | 33 | .dark { 34 | --bg: #121212; 35 | --fg: #eaeaea; 36 | --border-fg: rgb(68, 68, 68); 37 | --navbar-bg: var(--bg); 38 | --sidebar-bg: var(--bg); 39 | --sidebar-text-fg: var(--fg); 40 | --code-block-fg: rgb(182, 182, 182); 41 | --code-block-bg: rgb(30, 30, 30); 42 | --code-block-border-fg: rgb(42, 42, 42); 43 | --code-span-bg: #3b3b3b; 44 | --navlink-hover-bg: rgba(103, 103, 103, 0.29); 45 | --sidebar-menu-item-active-fg: #ffe77a; 46 | --content-link-fg: #ffe77a; 47 | --table-border-fg: rgb(59, 59, 59); 48 | 49 | --loader-start-bg: #2b2c2e; 50 | --loader-end-bg: #252525; 51 | } 52 | 53 | *, 54 | *::before, 55 | *::after { 56 | border-color: var(--border-fg); 57 | } 58 | 59 | body { 60 | font-family: Lato; 61 | background: var(--bg); 62 | color: var(--fg); 63 | } 64 | 65 | .navbar { 66 | background: var(--navbar-bg); 67 | color: var(--navbar-fg); 68 | z-index: 999; 69 | } 70 | 71 | .navlink { 72 | color: var(--navlink-fg); 73 | @apply flex; 74 | @apply items-center; 75 | @apply px-5; 76 | @apply h-8; 77 | } 78 | 79 | @screen md { 80 | .navlink { 81 | @apply p-2; 82 | @apply rounded; 83 | @apply h-8; 84 | } 85 | } 86 | 87 | .navlink:hover { 88 | color: var(--navlink-hover-fg); 89 | background: var(--navlink-hover-bg); 90 | } 91 | 92 | .sidebar { 93 | background: var(--sidebar-bg); 94 | z-index: 9999; 95 | width: 60%; 96 | min-width: 300px; 97 | color: var(--sidebar-text-fg); 98 | overflow: auto; 99 | transform: translateX(-100%); 100 | transition: transform ease-in-out 150ms; 101 | } 102 | 103 | .sidebar_overlay { 104 | z-index: 9990; 105 | } 106 | 107 | .sidebar_navbar { 108 | background: var(--navbar-bg); 109 | color: var(--navbar-fg); 110 | } 111 | 112 | @screen md { 113 | .sidebar { 114 | z-index: 990; 115 | width: var(--sidebar-width); 116 | transform: none; 117 | } 118 | } 119 | 120 | .sidebar.sidebar_show { 121 | display: block; 122 | transform: translateX(0); 123 | } 124 | 125 | .main { 126 | @apply px-5; 127 | @apply py-5; 128 | } 129 | 130 | @screen md { 131 | .main { 132 | @apply px-8; 133 | margin-left: var(--sidebar-width); 134 | } 135 | } 136 | 137 | .loader { 138 | animation: loader 3s infinite ease-in-out; 139 | } 140 | 141 | @keyframes loader { 142 | 0% { 143 | background-color: var(--loader-start-bg); 144 | } 145 | 50% { 146 | background-color: var(--loader-end-bg); 147 | } 148 | 100% { 149 | background-color: var(--loader-start-bg); 150 | } 151 | } 152 | 153 | .menu_item__active { 154 | color: var(--sidebar-menu-item-active-fg); 155 | font-weight: bold; 156 | } 157 | 158 | .menu_item[data-depth='3'] { 159 | @apply pl-8; 160 | } 161 | 162 | .menu_item[data-depth='4'] { 163 | @apply pl-8; 164 | } 165 | 166 | .menu_item[data-depth='4']:before { 167 | content: '-'; 168 | @apply opacity-25; 169 | @apply pr-2; 170 | } 171 | -------------------------------------------------------------------------------- /src/css/prism.css: -------------------------------------------------------------------------------- 1 | /** 2 | * prism.js tomorrow night eighties for JavaScript, CoffeeScript, CSS and HTML 3 | * Based on https://github.com/chriskempson/tomorrow-theme 4 | * @author Rose Pritchard 5 | */ 6 | 7 | pre { 8 | color: var(--code-block-fg); 9 | border: 1px solid var(--code-block-border-fg); 10 | background: none; 11 | font-family: var(--code-font); 12 | font-size: 1rem; 13 | text-align: left; 14 | white-space: pre; 15 | word-spacing: normal; 16 | word-break: normal; 17 | word-wrap: normal; 18 | line-height: 1.5; 19 | 20 | -moz-tab-size: 4; 21 | -o-tab-size: 4; 22 | tab-size: 4; 23 | 24 | -webkit-hyphens: none; 25 | -moz-hyphens: none; 26 | -ms-hyphens: none; 27 | hyphens: none; 28 | } 29 | 30 | /* Code blocks */ 31 | pre { 32 | @apply rounded-lg; 33 | @apply p-5; 34 | margin: 0.5em 0; 35 | overflow: auto; 36 | } 37 | 38 | :not(pre) > code { 39 | background: var(--code-span-bg); 40 | font-family: var(--code-font); 41 | color: var(--code-span-fg); 42 | padding: 2px 4px; 43 | @apply rounded; 44 | @apply text-sm; 45 | } 46 | 47 | pre { 48 | background: var(--code-block-bg); 49 | } 50 | 51 | /* Inline code */ 52 | :not(pre) > code[class*='language-'] { 53 | padding: 0.1em; 54 | border-radius: 0.4em; 55 | white-space: normal; 56 | } 57 | 58 | .token.comment, 59 | .token.prolog, 60 | .token.cdata { 61 | color: hsl(230, 4%, 64%); 62 | } 63 | 64 | .token.doctype, 65 | .token.punctuation, 66 | .token.entity { 67 | color: hsl(230, 8%, 24%); 68 | } 69 | 70 | .token.attr-name, 71 | .token.class-name, 72 | .token.boolean, 73 | .token.constant, 74 | .token.number, 75 | .token.atrule { 76 | color: hsl(35, 99%, 36%); 77 | } 78 | 79 | .token.keyword { 80 | color: hsl(301, 63%, 40%); 81 | } 82 | 83 | .token.property, 84 | .token.tag, 85 | .token.symbol, 86 | .token.deleted, 87 | .token.important { 88 | color: hsl(5, 74%, 59%); 89 | } 90 | 91 | .token.selector, 92 | .token.string, 93 | .token.char, 94 | .token.builtin, 95 | .token.inserted, 96 | .token.regex, 97 | .token.attr-value, 98 | .token.attr-value > .token.punctuation { 99 | color: hsl(119, 34%, 47%); 100 | } 101 | 102 | .token.variable, 103 | .token.operator, 104 | .token.function { 105 | color: hsl(221, 87%, 60%); 106 | } 107 | 108 | .token.url { 109 | color: hsl(198, 99%, 37%); 110 | } 111 | 112 | .dark { 113 | .token.comment, 114 | .token.block-comment, 115 | .token.prolog, 116 | .token.doctype, 117 | .token.cdata { 118 | color: #999; 119 | } 120 | 121 | .token.punctuation { 122 | color: #ccc; 123 | } 124 | 125 | .token.tag, 126 | .token.attr-name, 127 | .token.namespace, 128 | .token.deleted { 129 | color: #e2777a; 130 | } 131 | 132 | .token.function-name { 133 | color: #6196cc; 134 | } 135 | 136 | .token.boolean, 137 | .token.number, 138 | .token.function { 139 | color: #f08d49; 140 | } 141 | 142 | .token.property, 143 | .token.class-name, 144 | .token.constant, 145 | .token.symbol { 146 | color: #f8c555; 147 | } 148 | 149 | .token.selector, 150 | .token.important, 151 | .token.atrule, 152 | .token.keyword, 153 | .token.builtin { 154 | color: #cc99cd; 155 | } 156 | 157 | .token.string, 158 | .token.char, 159 | .token.attr-value, 160 | .token.regex, 161 | .token.variable { 162 | color: #7ec699; 163 | } 164 | 165 | .token.operator, 166 | .token.entity, 167 | .token.url { 168 | color: #67cdcc; 169 | } 170 | 171 | .token.important, 172 | .token.bold { 173 | font-weight: bold; 174 | } 175 | .token.italic { 176 | font-style: italic; 177 | } 178 | 179 | .token.entity { 180 | cursor: help; 181 | } 182 | 183 | .token.inserted { 184 | color: green; 185 | } 186 | } 187 | -------------------------------------------------------------------------------- /src/css/tailwind.css: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; 4 | -------------------------------------------------------------------------------- /src/docup.ts: -------------------------------------------------------------------------------- 1 | import './css/tailwind.css' 2 | import './css/prism.css' 3 | import './css/main.css' 4 | import './css/content.css' 5 | import { SetRequired } from 'type-fest' 6 | import htm from 'htm' 7 | import { h, render } from 'renderer' 8 | import { App } from './components/App' 9 | 10 | export interface NavLink { 11 | text: string 12 | link: string 13 | } 14 | 15 | export interface Options { 16 | title?: string 17 | indexFile?: string 18 | root?: string 19 | highlight?: boolean 20 | highlightLanguages?: string[] 21 | navLinks?: NavLink[] 22 | props?: any 23 | font?: string 24 | base?: string 25 | useSystemTheme?: boolean 26 | beforeSidebar?: string 27 | } 28 | 29 | export type InstanceOptions = SetRequired< 30 | Options, 31 | 'indexFile' | 'root' | 'highlight' | 'title' | 'base' 32 | > 33 | 34 | export class Docup { 35 | options: InstanceOptions 36 | 37 | constructor(options: Options = {}) { 38 | this.options = { 39 | title: options.title || document.title || 'Docup', 40 | indexFile: 'README.md', 41 | root: '', 42 | base: '/', 43 | highlight: true, 44 | ...options, 45 | } 46 | } 47 | 48 | init() { 49 | // const isDark = window.matchMedia('(prefers-color-scheme: dark)') 50 | // if (isDark) { 51 | // document.body.dataset.theme = 'dark' 52 | // } 53 | 54 | const font = this.options.font || 'Lato' 55 | const link = document.createElement('link') 56 | link.rel = 'stylesheet' 57 | link.href = `https://fonts.googleapis.com/css2?family=${font}:wght@400;700&display=swap` 58 | document.head.appendChild(link) 59 | 60 | render(h(App, { options: this.options }), document.body) 61 | } 62 | } 63 | 64 | export function init(options: Options) { 65 | const docup = new Docup(options) 66 | docup.init() 67 | } 68 | 69 | export const version = DOCUP_VERSION 70 | 71 | export * from 'renderer' 72 | 73 | export const html = htm.bind(h) 74 | -------------------------------------------------------------------------------- /src/markdown-component.ts: -------------------------------------------------------------------------------- 1 | export const MD_PROPS_KEY = `MD_C_PROPS` 2 | 3 | // prevent vite from shimming import.meta.url 4 | let docupUrl = import.meta.url 5 | if (import.meta.env.DEV) { 6 | // During dev it's not bundled 7 | // So we resolve to docup.ts instead 8 | docupUrl = docupUrl.replace('markdown-component.ts', 'docup.ts') 9 | } 10 | 11 | export { docupUrl } 12 | 13 | export const setMdProps = (props: any) => { 14 | window[MD_PROPS_KEY] = props 15 | } 16 | 17 | export const getSkypackUrl = (name: string) => 18 | `https://cdn.skypack.dev/${name}?min` 19 | 20 | const IMPORT_RE = /(^|\s|;)import(?:['"\s]*([\w*${}\s,]+)from\s*)?['"\s]['"\s](.*[@\w_-]+)['"\s].*/g 21 | 22 | const getNewUrl = (url: string) => { 23 | if (url === 'preact' || url === 'fre' || url === 'docup') { 24 | return docupUrl 25 | } 26 | if (/^([\.\/]|https?:\/\/)/.test(url)) return url 27 | 28 | return getSkypackUrl(url) 29 | } 30 | 31 | export const rewriteImports = (code: string) => { 32 | return code.replace(IMPORT_RE, (m, prefix, specs, name) => { 33 | return prefix + `import ` + specs + ` from '${getNewUrl(name)}'` 34 | }) 35 | } 36 | 37 | export const initMarkdownComponentsProxy = () => { 38 | window._MD_COMPONENTS = new Proxy>( 39 | {}, 40 | { 41 | set: function (target, prop: string, value) { 42 | const [info, index] = prop.split('_') 43 | const appScript = document.createElement('script') 44 | appScript.type = 'module' 45 | const importRenderFunction = 46 | info === 'react' 47 | ? `import {createElement as h} from "${getSkypackUrl('react')}"; 48 | import {render} from "${getSkypackUrl('react-dom')}"` 49 | : info === 'vue' 50 | ? `import {createApp,h} from '${getSkypackUrl( 51 | 'vue@next' 52 | )}';var render=(app,el)=>createApp(app).mount(el)` 53 | : `import {render,h} from "${docupUrl}"` 54 | appScript.textContent = ` 55 | ${importRenderFunction} 56 | render(h(_MD_COMPONENTS.${prop},${MD_PROPS_KEY}), document.getElementById(\`md_components_${index}\`))` 57 | 58 | document.body.append(appScript) 59 | 60 | return Reflect.set(target, prop, value) 61 | }, 62 | } 63 | ) 64 | } 65 | -------------------------------------------------------------------------------- /src/markdown.ts: -------------------------------------------------------------------------------- 1 | import marked from 'marked' 2 | import Prism from 'prismjs' 3 | import 'prismjs/components/prism-bash' 4 | import 'prismjs/components/prism-javascript' 5 | import 'prismjs/components/prism-typescript' 6 | import 'prismjs/components/prism-json' 7 | import 'prismjs/components/prism-css' 8 | import 'prismjs/components/prism-markdown' 9 | import { isExternalLink, slugify, ANCHOR_ICON } from './utils' 10 | import { rewriteImports } from './markdown-component' 11 | 12 | const BLOCKQUOTE_TAG_RE = /^

(?:)?(Note|Alert|Info|Warning|Success|Alert)(?:<\/strong>)?\:\s*/i 13 | 14 | export interface SidebarMenuItem { 15 | text: string 16 | slug: string 17 | depth: number 18 | } 19 | 20 | export function renderMarkdown(text: string) { 21 | const renderer = new marked.Renderer() 22 | const fns: Array<() => void> = [] 23 | 24 | const originalBlockquote = renderer.blockquote 25 | renderer.blockquote = (quote) => { 26 | const m = BLOCKQUOTE_TAG_RE.exec(quote) 27 | if (m) { 28 | const [, type] = m 29 | return `

${quote.replace( 30 | BLOCKQUOTE_TAG_RE, 31 | '' 32 | )}

` 33 | } 34 | return originalBlockquote.call(renderer, quote) 35 | } 36 | 37 | const originalCode = renderer.code 38 | let codeReplacementIndex = 0 39 | 40 | renderer.code = (code, _lang = '', escaped) => { 41 | let [lang, info] = _lang.split(' ') 42 | let keep: string | boolean = false 43 | if (info) { 44 | const splits = info.split(',') 45 | info = splits[0] 46 | keep = splits.includes('keepAbove') ? 'above' : splits.includes('keep') 47 | } 48 | 49 | const renderCode = () => originalCode.call(renderer, code, lang, escaped) 50 | 51 | if ( 52 | info === 'preact' || 53 | info === 'fre' || 54 | info === 'react' || 55 | info === 'vue' 56 | ) { 57 | const index = codeReplacementIndex++ 58 | fns.push(() => { 59 | const componentScript = document.createElement('script') 60 | componentScript.type = 'module' 61 | componentScript.textContent = ` 62 | ${rewriteImports(code).replace( 63 | /\bexport default\b/, 64 | `window._MD_COMPONENTS.${info}_${index}=` 65 | )}` 66 | setTimeout(() => document.body.append(componentScript)) 67 | }) 68 | return `${ 69 | keep === 'above' ? renderCode() : '' 70 | }
${ 71 | keep === true ? renderCode() : '' 72 | }` 73 | } 74 | 75 | return renderCode() 76 | } 77 | 78 | renderer.link = (href, title, text) => { 79 | let attrs = ` href="${href}"` 80 | if (title) { 81 | attrs += ` title="${title}"` 82 | } 83 | if (href && isExternalLink(href)) { 84 | attrs += ` target="_blank" rel="nofollow noopener"` 85 | } 86 | return `${text}` 87 | } 88 | 89 | // @ts-ignore 90 | renderer.listitem = (text, task) => { 91 | return `${text}` 92 | } 93 | 94 | const menu: Array = [] 95 | const slugs: string[] = [] 96 | renderer.heading = (text, depth, raw) => { 97 | // Hide h1 98 | if (depth === 1) { 99 | return '' 100 | } 101 | let slug = slugify(raw) 102 | const existingCount = slugs.filter((s) => s === slug).length 103 | slugs.push(slug) 104 | if (existingCount > 0) { 105 | slug = `${slug}-${existingCount}` 106 | } 107 | if (depth < 5) { 108 | menu.push({ 109 | text, 110 | slug, 111 | depth: depth, 112 | }) 113 | } 114 | text = `${ANCHOR_ICON}${text}` 115 | return `${text}` 116 | } 117 | 118 | const html = marked(text, { 119 | renderer, 120 | gfm: true, 121 | highlight(code, lang) { 122 | const prismLang = Prism.languages[lang] || Prism.languages.markup 123 | return Prism.highlight(code, prismLang, prismLang ? lang : 'markup') 124 | }, 125 | }) 126 | 127 | return { 128 | html, 129 | menu, 130 | fns, 131 | } 132 | } 133 | -------------------------------------------------------------------------------- /src/renderer/fre.ts: -------------------------------------------------------------------------------- 1 | export * from 'fre' 2 | 3 | export function setHtml(html: string) { 4 | return { ref: (dom: any) => (dom.innerHTML = html) } 5 | } 6 | -------------------------------------------------------------------------------- /src/renderer/preact.ts: -------------------------------------------------------------------------------- 1 | export { h, render } from 'preact' 2 | 3 | export type { FunctionComponent as FC } from 'preact' 4 | 5 | export * from 'preact/hooks' 6 | 7 | export function setHtml(html: string) { 8 | return { dangerouslySetInnerHTML: { __html: html } } 9 | } 10 | -------------------------------------------------------------------------------- /src/utils.ts: -------------------------------------------------------------------------------- 1 | export function slugify(input: string) { 2 | return ( 3 | input // Remove html tags 4 | .replace(/<(?:.|\n)*?>/gm, '') // Remove special characters 5 | .replace(/[!\"#$%&'\(\)\*\+,\/:;<=>\?\@\[\\\]\^`\{\|\}~]/g, '') // eslint-disable-line no-useless-escape 6 | // Replace dots and spaces with a short dash 7 | .replace(/(\s|\.)/g, '-') // Replace long dash with two short dashes 8 | .replace(/—/g, '--') // Make the whole thing lowercase 9 | .toLowerCase() 10 | ) 11 | } 12 | 13 | export function isExternalLink(href: string) { 14 | return /^https?:\/\//.test(href) 15 | } 16 | 17 | export const ANCHOR_ICON = ` 18 | ` 19 | 20 | export function scrollToHash(hash: string) { 21 | const el = document.querySelector(decodeURIComponent(hash)) as HTMLDivElement 22 | if (el) { 23 | window.scrollTo({ 24 | top: el.offsetTop - 60, 25 | }) 26 | } 27 | } 28 | 29 | export function updateURLHash(hash: string, replace: boolean) { 30 | if (replace) { 31 | history.replaceState({}, '', hash) 32 | } else { 33 | history.pushState({}, '', hash) 34 | } 35 | window.dispatchEvent(new HashChangeEvent('hashchange')) 36 | } 37 | 38 | const scriptCaches: string[] = [] 39 | 40 | export function loadScript(url: string) { 41 | if (scriptCaches.indexOf(url) !== -1) { 42 | return Promise.resolve() 43 | } 44 | return new Promise((resolve, reject) => { 45 | const script = document.createElement('script') 46 | script.src = url 47 | script.onload = resolve 48 | script.onerror = reject 49 | document.head.appendChild(script) 50 | }) 51 | } 52 | 53 | export async function loadLanguages(langs: string[]) { 54 | await Promise.all( 55 | langs.map((lang) => 56 | loadScript( 57 | `https://cdn.jsdelivr.net/npm/prismjs@${PRISM_VERSION}/components/prism-${lang}.min.js` 58 | ) 59 | ) 60 | ) 61 | } 62 | 63 | /** 64 | * Returns a new function that, when invoked, invokes `func` at most once per `wait` milliseconds. 65 | * Taken from https://github.com/component/throttle/blob/master/index.js MIT licensed 66 | * 67 | * @param func Function to wrap. 68 | * @param wait Number of milliseconds that must elapse between `func` invocations. 69 | * @return A new function that wraps the `func` function passed in. 70 | */ 71 | 72 | export function throttle(func: T, wait: number) { 73 | // caching 74 | let ctx: any | undefined, 75 | args: IArguments | undefined, 76 | rtn: Function | undefined, 77 | timeoutID: number | undefined 78 | let last = 0 79 | 80 | return function (this: any) { 81 | ctx = this 82 | args = arguments 83 | var delta = Date.now() - last 84 | if (!timeoutID) 85 | if (delta >= wait) call() 86 | else timeoutID = self.setTimeout(call, wait - delta) 87 | return rtn 88 | } 89 | 90 | function call() { 91 | timeoutID = 0 92 | last = +new Date() 93 | rtn = func.apply(ctx, args) 94 | ctx = undefined 95 | args = undefined 96 | } 97 | } 98 | 99 | const TRAILING_SLASH_RE = /\/$/ 100 | const MD_RE = /\.md$/ 101 | 102 | export function getFileUrl(root: string, indexFile: string, pathname: string) { 103 | let url = root 104 | // Remove trailing slash 105 | // Becuase pathname always starts with slash 106 | .replace(TRAILING_SLASH_RE, '') 107 | // `pathname` ends with slash 108 | // this is a directory 109 | // use `indexFile` 110 | if (TRAILING_SLASH_RE.test(pathname)) { 111 | url += `${pathname}${indexFile}` 112 | } else if (!MD_RE.test(pathname)) { 113 | url += `${pathname}.md` 114 | } 115 | return url 116 | } 117 | -------------------------------------------------------------------------------- /tailwind.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | darkMode: 'class', 3 | content: ['./src/**/*.tsx'], 4 | theme: { 5 | extend: { 6 | borderColor: { 7 | border: 'var(--border-fg)', 8 | }, 9 | }, 10 | }, 11 | variants: {}, 12 | plugins: [], 13 | } 14 | -------------------------------------------------------------------------------- /test_prod/README.md: -------------------------------------------------------------------------------- 1 | # hi 2 | 3 | this is a test 4 | 5 | ## heading 2 6 | 7 | some text 8 | 9 | ### 中文 10 | 11 | some other text 12 | -------------------------------------------------------------------------------- /test_prod/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Document 8 | 9 | 10 | 11 |
12 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | /* Visit https://aka.ms/tsconfig.json to read more about this file */ 4 | 5 | /* Basic Options */ 6 | // "incremental": true, /* Enable incremental compilation */ 7 | "target": "es2020" /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', or 'ESNEXT'. */, 8 | "module": "esnext" /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */, 9 | "lib": [ 10 | "es2019", 11 | "dom" 12 | ] /* Specify library files to be included in the compilation. */, 13 | // "allowJs": true, /* Allow javascript files to be compiled. */ 14 | // "checkJs": true, /* Report errors in .js files. */ 15 | "jsx": "preserve" /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */, 16 | "jsxFactory": "h", 17 | // "declaration": true, /* Generates corresponding '.d.ts' file. */ 18 | // "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */ 19 | // "sourceMap": true, /* Generates corresponding '.map' file. */ 20 | // "outFile": "./", /* Concatenate and emit output to single file. */ 21 | // "outDir": "./", /* Redirect output structure to the directory. */ 22 | // "rootDir": "./", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */ 23 | // "composite": true, /* Enable project compilation */ 24 | // "tsBuildInfoFile": "./", /* Specify file to store incremental compilation information */ 25 | // "removeComments": true, /* Do not emit comments to output. */ 26 | // "noEmit": true, /* Do not emit outputs. */ 27 | // "importHelpers": true, /* Import emit helpers from 'tslib'. */ 28 | // "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */ 29 | // "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */ 30 | 31 | /* Strict Type-Checking Options */ 32 | "strict": true /* Enable all strict type-checking options. */, 33 | // "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */ 34 | // "strictNullChecks": true, /* Enable strict null checks. */ 35 | // "strictFunctionTypes": true, /* Enable strict checking of function types. */ 36 | // "strictBindCallApply": true, /* Enable strict 'bind', 'call', and 'apply' methods on functions. */ 37 | // "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */ 38 | // "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */ 39 | // "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */ 40 | 41 | /* Additional Checks */ 42 | // "noUnusedLocals": true, /* Report errors on unused locals. */ 43 | // "noUnusedParameters": true, /* Report errors on unused parameters. */ 44 | // "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */ 45 | // "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */ 46 | 47 | /* Module Resolution Options */ 48 | "moduleResolution": "node" /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */, 49 | "baseUrl": "./" /* Base directory to resolve non-absolute module names. */, 50 | "paths": { 51 | "renderer": ["src/renderer/preact"] 52 | } /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */, 53 | // "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */ 54 | // "typeRoots": [], /* List of folders to include type definitions from. */ 55 | // "types": [], /* Type declaration files to be included in compilation. */ 56 | // "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */ 57 | "esModuleInterop": true /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */, 58 | // "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */ 59 | // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ 60 | 61 | /* Source Map Options */ 62 | // "sourceRoot": "", /* Specify the location where debugger should locate TypeScript files instead of source locations. */ 63 | // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ 64 | // "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */ 65 | // "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */ 66 | 67 | /* Experimental Options */ 68 | // "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */ 69 | // "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */ 70 | 71 | /* Advanced Options */ 72 | "skipLibCheck": true /* Skip type checking of declaration files. */, 73 | "forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */ 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /types.d.ts: -------------------------------------------------------------------------------- 1 | declare const DOCUP_VERSION: string 2 | declare const PRISM_VERSION: string 3 | declare const PRISM_LANGUAGES: string 4 | 5 | declare module 'element-in-view' { 6 | type Options = { 7 | offset?: number 8 | } 9 | const inView: (el: Element, options?: Options) => boolean 10 | export default inView 11 | } 12 | 13 | declare interface ImportMeta { 14 | env: { 15 | DEV: boolean 16 | } 17 | } 18 | 19 | interface Window { 20 | MD_C_PROPS: any 21 | _MD_COMPONENTS: Record 22 | } 23 | 24 | declare const import_meta_url: string 25 | --------------------------------------------------------------------------------