diff --git a/.eslintrc.cjs b/.eslintrc.cjs index e4b256c2..59254bc9 100644 --- a/.eslintrc.cjs +++ b/.eslintrc.cjs @@ -21,6 +21,7 @@ module.exports = { '@typescript-eslint/no-explicit-any': 'off', '@typescript-eslint/no-non-null-assertion': 'off', '@typescript-eslint/no-var-requires': 'off', + '@typescript-eslint/explicit-function-return-type': 'off', 'vue/component-tags-order': [ 'error', { diff --git a/.gitignore b/.gitignore index 2cbb5c79..8d5c023e 100644 --- a/.gitignore +++ b/.gitignore @@ -13,3 +13,5 @@ dist/ *.log *.tsbuildinfo .mind + +packages/theme-back diff --git a/.vscode/settings.json b/.vscode/settings.json index d5ec9547..3db9580f 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -24,6 +24,7 @@ "composables", "Docsearch", "esbuild", + "frontmatter", "gsap", "iarna", "leancloud", diff --git a/docs/.vuepress/config.ts b/docs/.vuepress/config.ts index 262f6920..99834511 100644 --- a/docs/.vuepress/config.ts +++ b/docs/.vuepress/config.ts @@ -1,5 +1,5 @@ import * as path from 'path' -import { themePlume } from '@vuepress-plume/vuepress-theme-plume' +import themePlume from '@vuepress-plume/vuepress-theme-plume' import { viteBundler } from '@vuepress/bundler-vite' import { webpackBundler } from '@vuepress/bundler-webpack' import { defineUserConfig } from '@vuepress/cli' @@ -19,31 +19,33 @@ export default defineUserConfig({ theme: themePlume({ logo: 'https://pengzhanbo.cn/g.gif', hostname: 'https://pengzhanbo.cn', + appearance: true, avatar: { url: '/images/blogger.jpg', name: 'Plume Theme', description: 'The Theme for Vuepress 2.0', }, - social: { - email: 'volodymyr@foxmail.com', - github: 'pengzhanbo', - QQ: '942450674', - weiBo: 'https://weibo.com', - zhiHu: 'https://zhihu.com', - facebook: 'https://baidu.com', - twitter: 'https://baidu.com', - linkedin: 'https://baidu.com', - }, + social: [{ icon: 'github', link: 'https://github.com/pengzhanbo' }], + // { + // email: 'volodymyr@foxmail.com', + // github: 'pengzhanbo', + // QQ: '942450674', + // weiBo: 'https://weibo.com', + // zhiHu: 'https://zhihu.com', + // facebook: 'https://baidu.com', + // twitter: 'https://baidu.com', + // linkedin: 'https://baidu.com', + // }, notes, - darkMode: true, navbar: [ + { text: 'Blog', link: '/blog/', activeMatch: '/blog/' }, { text: 'VuePress', - children: [ + items: [ { text: 'theme-plume', link: '/note/vuepress-theme-plume/' }, { text: 'Plugin', - children: [ + items: [ { text: 'caniuse', link: '/note/vuepress-plugin/caniuse/' }, { text: 'netlify-functions', @@ -56,7 +58,7 @@ export default defineUserConfig({ ], footer: { copyright: 'Copyright © 2022-present pengzhanbo', - content: '', + message: '', }, themePlugins: { search: { diff --git a/docs/.vuepress/notes.ts b/docs/.vuepress/notes.ts index 0d49d09c..97712243 100644 --- a/docs/.vuepress/notes.ts +++ b/docs/.vuepress/notes.ts @@ -1,6 +1,8 @@ import { definePlumeNotesConfig } from '@vuepress-plume/vuepress-theme-plume' export default definePlumeNotesConfig({ + dir: 'notes', + link: '/note', notes: [ { text: '', @@ -10,22 +12,22 @@ export default definePlumeNotesConfig({ '', { text: '指南', - children: ['快速开始', '编写文章'], + items: ['快速开始', '编写文章'], }, { text: '配置', - children: [ + items: [ { text: '主题配置', link: '主题配置', - children: ['主题插件配置', 'notes配置'], + items: ['主题插件配置', 'notes配置'], }, '页面配置', ], }, { text: '功能', - children: ['基础功能', 'markdown增强'], + items: ['基础功能', 'markdown增强'], }, ], }, @@ -39,7 +41,7 @@ export default definePlumeNotesConfig({ dir: 'netlify-functions', text: 'plugin-netlify-functions', link: 'netlify-functions', - children: ['', '介绍', '使用', '功能', 'API', 'functions开发指南'], + items: ['', '介绍', '使用', '功能', 'API', 'functions开发指南'], }, ], }, diff --git a/docs/.vuepress/public/images/bg-home.jpg b/docs/.vuepress/public/images/bg-home.jpg new file mode 100644 index 00000000..f3ff127e Binary files /dev/null and b/docs/.vuepress/public/images/bg-home.jpg differ diff --git a/docs/1.前端/1.基础/BFC 块级格式化上下文.md b/docs/1.前端/1.基础/BFC 块级格式化上下文.md index e30eb547..53d0f2d0 100644 --- a/docs/1.前端/1.基础/BFC 块级格式化上下文.md +++ b/docs/1.前端/1.基础/BFC 块级格式化上下文.md @@ -1,16 +1,14 @@ --- title: BFC 块级格式化上下文 createTime: 2018/05/17 12:28:33 -permalink: /article/o5g7ggvf +permalink: /article/o5g7ggvf/ author: pengzhanbo -top: false tags: - html -type: null --- ## 概念 -BFC, Block Formating Context。是 W3C CSS2.1规范中的一个概念。 是页面中的一块块级渲染区域,并且有一套渲染规则,它决定了其子元素将如何定位,以及和其他元素的关系和作用。 +BFC, Block Formatting Context。是 W3C CSS2.1规范中的一个概念。 是页面中的一块块级渲染区域,并且有一套渲染规则,它决定了其子元素将如何定位,以及和其他元素的关系和作用。 具有BFC特性的元素,可以看做是一个被隔离了的独立容器,容器内的元素不会在布局上影响到外面的元素,并且BFC具有普通容器所没有的一些特性。 @@ -35,4 +33,4 @@ BFC, Block Formating Context。是 W3C CSS2.1规范中的一个概念。 是页 1. 同一个BFC的外边距会发生折叠(合并), 通过将其放在不同的BFC中规避折叠。 2. BFC可以包含浮动元素,即清除浮动。 -3. BFC可以阻止元素被浮动元素覆盖。 \ No newline at end of file +3. BFC可以阻止元素被浮动元素覆盖。 diff --git a/docs/1.前端/1.基础/CSS at-rule.md b/docs/1.前端/1.基础/CSS at-rule.md index 6d7bbbc0..dbc6c1db 100644 --- a/docs/1.前端/1.基础/CSS at-rule.md +++ b/docs/1.前端/1.基础/CSS at-rule.md @@ -1,12 +1,10 @@ --- title: CSS At-Rules createTime: 2018/10/06 08:16:38 -permalink: /article/btkqop1a +permalink: /article/btkqop1a/ author: pengzhanbo tags: - css -top: false -type: null --- ## @charset @@ -160,4 +158,4 @@ type: null ## @media -媒体查询,详见 [CSS @media 媒体查询](/post/fe5ruia1/) \ No newline at end of file +媒体查询,详见 [CSS @media 媒体查询](/post/fe5ruia1/) diff --git a/docs/1.前端/1.基础/CSS media媒体查询.md b/docs/1.前端/1.基础/CSS media媒体查询.md index eb4c18fd..a489c01c 100644 --- a/docs/1.前端/1.基础/CSS media媒体查询.md +++ b/docs/1.前端/1.基础/CSS media媒体查询.md @@ -1,12 +1,10 @@ --- title: CSS 媒体查询 createTime: 2018/08/18 08:43:02 -permalink: /article/fe5ruia1 +permalink: /article/fe5ruia1/ author: pengzhanbo tags: - css -top: false -type: null --- 开发响应式网站时,常常需要使用到 media 媒体查询。这里总结下媒体查询的使用方法。 diff --git a/docs/1.前端/1.基础/CSS选择器.md b/docs/1.前端/1.基础/CSS选择器.md index c1ef7350..c8d129ad 100644 --- a/docs/1.前端/1.基础/CSS选择器.md +++ b/docs/1.前端/1.基础/CSS选择器.md @@ -1,12 +1,10 @@ --- title: CSS选择器 createTime: 2018/09/20 03:29:20 -permalink: /article/8vev8ixl +permalink: /article/8vev8ixl/ author: pengzhanbo tags: - css -top: false -type: null --- ## Basic Selectors 基础选择器 @@ -644,4 +642,4 @@ type: null } ... -``` \ No newline at end of file +``` diff --git a/docs/1.前端/1.基础/DOCTYPE 文档类型声明.md b/docs/1.前端/1.基础/DOCTYPE 文档类型声明.md index 331d0e65..46d81447 100644 --- a/docs/1.前端/1.基础/DOCTYPE 文档类型声明.md +++ b/docs/1.前端/1.基础/DOCTYPE 文档类型声明.md @@ -1,12 +1,10 @@ --- title: 文档类型声明 createTime: 2018/03/14 01:06:52 -permalink: /article/s8udp6vp +permalink: /article/s8udp6vp/ author: pengzhanbo tags: - html -top: false -type: null --- Web世界中,随着历史的发展,技术的迭代,发展出了许多不同的文档,只有了解文档的类型,浏览器才能正确的解析渲染文档。 @@ -105,4 +103,4 @@ http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> ``` html -``` \ No newline at end of file +``` diff --git a/docs/1.前端/1.基础/HTML5新特性.md b/docs/1.前端/1.基础/HTML5新特性.md index 4f2791af..93f6c32f 100644 --- a/docs/1.前端/1.基础/HTML5新特性.md +++ b/docs/1.前端/1.基础/HTML5新特性.md @@ -1,12 +1,10 @@ --- title: HTML5新特性 createTime: 2018/02/17 12:49:58 -permalink: /article/8rv45yuy +permalink: /article/8rv45yuy/ author: pengzhanbo tags: - html -top: false -type: null --- ## 语义标签 @@ -272,4 +270,4 @@ history.replaceState({}, 'bar', 'bar.html') }) ``` -[History API - Web API 接口参考 | MDN](https://developer.mozilla.org/zh-CN/docs/Web/API/History_API) \ No newline at end of file +[History API - Web API 接口参考 | MDN](https://developer.mozilla.org/zh-CN/docs/Web/API/History_API) diff --git a/docs/1.前端/1.基础/WebComponent-template.md b/docs/1.前端/1.基础/WebComponent-template.md index c941a8b2..2df5e385 100644 --- a/docs/1.前端/1.基础/WebComponent-template.md +++ b/docs/1.前端/1.基础/WebComponent-template.md @@ -2,13 +2,11 @@ title: WebComponent——template lang: zh-CN tags: - - html + - WebComponent - javascript createTime: 2018/8/2 11:15:27 -permalink: /article/5fmy4kla +permalink: /article/5fmy4kla/ author: pengzhanbo -top: false -type: null --- 在web开发领域中,模板并不少见。从服务器端的模板语言,如`Django`、`jsp`等,应用十分广泛,存在了很长时间。又如前端,早期例如`art(artTemplate)`,以及近年来,大多数的MV*框架涌现,绝大多数在展现层使用了同样的渲染机制:模板。 diff --git a/docs/1.前端/1.基础/WebComponent自定义元素.md b/docs/1.前端/1.基础/WebComponent自定义元素.md index 2012d504..26937359 100644 --- a/docs/1.前端/1.基础/WebComponent自定义元素.md +++ b/docs/1.前端/1.基础/WebComponent自定义元素.md @@ -1,13 +1,11 @@ --- title: WebComponent——custom elements tags: - - html + - WebComponent - javascript createTime: 2018/08/01 11:15:27 -permalink: /article/m63fd7lf +permalink: /article/m63fd7lf/ author: pengzhanbo -top: false -type: null --- diff --git a/docs/1.前端/1.基础/javascript模块化.md b/docs/1.前端/1.基础/javascript模块化.md new file mode 100644 index 00000000..9c9dc4dd --- /dev/null +++ b/docs/1.前端/1.基础/javascript模块化.md @@ -0,0 +1,239 @@ +--- +title: javascript模块化 发展历程 +createTime: 2022/04/10 03:00:41 +author: pengzhanbo +permalink: /article/javascript-modules/ +--- + +javascript模块化的发展,距今已有10个年头左右。 + +## 无模块化 + +在早期,javascript作为一门脚本语言,仅为协助表单校验等界面辅助增强,那时候的前端也比较简单, javascript不需要模块化。 + +## 命名空间 + +后来随着 javascript 需要承担更多的功能,代码量开始上升,为了避免全局命名冲突等问题,提出了使用命名空间的方案,将符合某种规则或者约定的代码,放到同一个命名空间下。 这算是 javascript模块化最早期的雏形。 + +``` js +YAHOO.util.Event.stopPropagation(e); +``` + +## 基本的模块化 + +在这个时期,出现了比较清晰的模块定义,通过闭包来做模块运行空间 +``` js +// 定义模块 +YUI.add('hello', function(Y) { + Y.sayHello = function() { + Y.DOM.set(el, 'innerHTML', 'hello!'); + } +}, '1.0.0', + requires: ['dom']); + +... +// 使用模块 +YUI().use('hello', function(Y) { + Y.sayHello('entry'); //
hello!
+}) +``` + +## CommonJs + +CommonJs 其实是一个项目,其目标是为 JavaScript 在网页浏览器之外创建模块约定, 在当年 javascript 的模块化思想还在官方的讨论中, 缺乏普遍可接受形式的javascript脚本模块单元。 + +CommonJs规范和当时出现的NodeJs相得益彰,共同走入了开发者的实现。 + +但 CommonJs 其实是面向网页浏览器之外的(如NodeJs,即面向服务端的模块化规范),并不适用于浏览器端。 + +### CommonJs 规范简介 + +在CommonJs 规范中, 每个文件都是一个模块,有自己的作用域,在文件中定义的变量、函数、类等,都是私有的,对其他文件不可见。 + +在每个模块中,有两个内部变量可以使用, `require` 和 `module` + +- `require` 用于加载某个模块。 +- `module` 表示当前模块,是一个对象。这个对象中保存了当前模块的信息。`exports` 是 `module` 上的一个属性,保存了当前模块要导出的接口或者变量,使用 `require` 加载的某个模块获取到的值就是那个模块使用 `exports` 导出的值。 + +::: code-tabs + +@tab a.js +``` js +var name = 'Mark'; +var age = 18; + +module.exports.name = name; +module.exports.getAge = function () { + return age; +} +``` + +@tab:active b.js +``` js +var moduleA = require('./a.js') +console.log(moduleA.a); // Mark +// 使用了未导出的变量,获取不到值 +console.log(moduleA.age) // undefined +console.log(moduleA.getAge()); // 18 +``` +::: + + +在NodeJs环境中,CommonJs的模块由于在服务器环境下,可以从本地进行加载,即 同步加载。 + +## AMD、CMD + +::: note 注释 +在我的印象中, CommonJs规范 和 AMD规范 出现的时间点 相差不远。 + +*AMD 早于 CommonJs* + +按我个人理解,CMD 在当年算是从 AMD 衍生出来的一个方案。 +::: +::: warning 注意 +CommonJs 和 CMD 是两种方案!不是一样的! +::: + +### AMD规范 +AMD规范,即 异步模块定义([Asynchronous Module Definition](https://github.com/amdjs/amdjs-api/wiki/AMD))。 + +AMD 采用 __异步加载模块__ 的方式。 + +AMD规范仅定义了一个 `define` 函数,它是一个全局变量: +``` +define(id?, dependencies?, factory); +``` +- `id` 描述的是当前模块的标识符; +- `dependencies` 则是当前模块的依赖数组, 它们会在 factory工厂方法被调用前被加载并执行, + 并且执行的结果必须以依赖数组定义的顺序,依此顺序作为参数传入 factory工厂方法。 +- `factory`为模块初始化要执行的函数或者对象。如果函数返回一个值,则该值应该设置为该模块的输出值。 + +### CMD规范 + +CMD规范,即 公共模块定义([Common Module Definition](https://github.com/cmdjs/specification/blob/master/draft/module.md)) + +CMD规范 定义了 一个 `define` 函数,它是一个全局变量: + +``` +define(id?, dependencies?, factory); +``` + +- `id` 描述的是当前模块的标识符; +- `dependencies` 是当前模块的依赖数组, 他们会在 factory 工厂方法被调用前完成加载,但并不立即执行。 +- `factory`为模块初始化要执行的函数或者对象。 + - 如果是一个函数,则函数接受三个参数: + ``` js + define(function (require, exports, module)) + ``` + `require` 用于同步加载并执行已经定义好的其他模块;获取模块的输出值, + `exports`是`module.exports`的别名,用于导出当前模块的输出值;`module`存储了当前模块的信息。 + - 如果是一个对象,则直接作为当前模块的输出值。 + +::: tip 两者的差异 + +AMD规范 和 CMD规范 从规范定义上来看,主要的差异为: + +- AMD 的模块在加载后是立即执行的,并且会按照依赖顺序依次传入 factory, + 而 CMD的模块在加载后并不立即执行,而是在 factory方法中,通过 `require` 方法调用执行模块获取结果; +::: + +### 规范的实现 + +- AMD流行的实现库是 [require.js](https://github.com/requirejs/requirejs); +- CMD流行的实现库是 [sea.js](https://github.com/seajs/seajs); + +::: warning 提示 +由于在当下已经越来越少会去选择使用 `require.js` 以及 `sea.js`, 这里就不多对这两个库做介绍说明。 +::: + +## NodeJs前端工具链 + +得益于 NodeJs 的能力,开源社区在模块化方面又再次向前继续迈进。 特别是在推出了 `NPM` 包管理工具后,前端的工具、模块化出现了井喷式发展。 + +### grunt gulp + +既然 CommonJs 不适用于 浏览器端的一个主要原因是同步加载和异步加载之间的问题,那么借助于 `grunt` 或 `gulp` 提供的前端工具,在开发时,还是以文件一模块,然后构建时,将模块文件打包在一起,那么由于都是在同一个文件中,则模块之间的加载则可以是同步的。 + +在这个时期,`grunt`、`gulp` 并没有提供直接的模块化打包能力,但是在其基础上,通过插件实现了文件合并,从而能够在开发时,以 某种模块规范进行项目架构和管理,再进行打包构建。 + +### webpack NPM + +真正让 前端模块化得到质的飞跃的,是 NPM的推出,内置到了 NodeJS 中。 + +而 webpack 的出现,这块 真正意义上的 模块打包工具,配合 NPM, 让模块化越来越得以更方便的运用于应用开发中。 + +webpack 作为一个 模块打包器, 在内部根据 CommonJs规范实现了 模块加载器,使得应用于浏览器端的javascript代码,也能够像 Node端的 javascript代码,拥有类似甚至相同的文件组织结构。 + +实现了一文件一模块,模块之间通过 `require` 函数进行 访问。 + +而 NPM的推出与流行,在前端引入了 `package` 包的概念,模块以包的形式进行管理, 让越来越多的开发者,能够共享各自开发的模块,开发者可以通过 NPM 安装其他开发者已开发好的模块,然后通过 `webpack` 实现开发时加载这些模块。 + +webpack 内部实现了 不同的 模块化规范,包括 匿名函数闭包`iife`, `AMD`, `CMD`,`CommonJs`等。 + +`webpack` 不仅将 javascript 作为模块,而是将一切资源都作为模块进行处理。 + +### 其他的模块打包工具 + +- [rollup](https://github.com/rollup/rollup) 轻量且快速的模块打包工具 +- [parcel](https://github.com/parcel-bundler/parcel) 零配置的开箱即用的模块打包工具 +- [vite](https://github.com/vitejs/vite) 基于rollup的前端工具 +- more... + +### 其他包管理工具 + +- [yarn](https://classic.yarnpkg.com/lang/en/) +- [pnpm](https://pnpm.io/) +- more... + +::: info 说明 +与`npm` 对比,都是社区对于 包管理 的不同理念、不同实践 下所产生的工具。 +三者互相发展,并都有各自的特色。 +::: + +## ES Modules + +[ES Modules](https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Guide/Modules) + +随着 javascript的发展,ECMAScript将模块加载添加到了标准之中,浏览器也开始支持 模块加载。 + +使用 Javascript 模块依赖于 `import` 和 `export` 进行导入和导出。 + +在 `html` 导入 javascript模块脚本是,需要在 ` +``` +::: code-tabs + +@tab moduleA.js +``` js +import { name, getAge } from './moduleB.js'; + +console.log(name); +console.log(getAge()); +``` + +@tab moduleB.js +``` js +export const name = 'Mark'; + +const age = 18; + +export function getAge() { + return age; +} +``` +::: + + + +## Deno模块加载 + +Deno与 Node在模块加载上最大的差别, 就是 放弃了 项目中的`node_modules` 作为第三方包的存放目录,也抛弃了 类似于 NPM 的中心化管理的 模块管理工具。 + +Deno 推荐使用的是 去中心化的模块加载管理,支持直接从远程的任意站点加载提供的模块。 + +如从 官方的 [deno.lang](https://deno.land/),或者从 [unpkg.com](https://unpkg.com/) 加载第三方模块。 + +::: info 说明 +这种去中心化模块管理的模块加载方案,相对来说会比较依赖于网络环境,虽然远程的模块首次加载后也会被缓存,但进行生产部署时,往往生产服务器跟公网是隔离的,在这种情况下,就需要自建一个内部服务器作为代理,托管第三方的模块包。 +::: diff --git a/docs/1.前端/1.基础/meta 标签说明.md b/docs/1.前端/1.基础/meta 标签说明.md index a918dfea..e5b9ce6c 100644 --- a/docs/1.前端/1.基础/meta 标签说明.md +++ b/docs/1.前端/1.基础/meta 标签说明.md @@ -1,12 +1,10 @@ --- title: meta 标签说明 createTime: 2018/03/15 01:21:48 -permalink: /article/bp1nxjs6 +permalink: /article/bp1nxjs6/ author: pengzhanbo tags: - html -top: false -type: null --- 标签提供关于 HTML 文档的元数据。它不会显示在页面上,但是对于机器是可读的。可用于浏览器(如何显示内容或重新加载页面),搜索引擎(关键词),或其他 web 服务。 @@ -216,4 +214,4 @@ content="app-id=APP_ID,affiliate-data=AFFILIATE_ID,app-argument=SOME_TEXT"> -``` \ No newline at end of file +``` diff --git a/docs/1.前端/1.基础/原型链与继承.md b/docs/1.前端/1.基础/原型链与继承.md index 250080fa..575ccaf8 100644 --- a/docs/1.前端/1.基础/原型链与继承.md +++ b/docs/1.前端/1.基础/原型链与继承.md @@ -1,17 +1,15 @@ --- title: 继承与原型链 createTime: 2018/07/06 09:40:54 -permalink: /article/extends-prototype +permalink: /article/extends-prototype/ author: pengzhanbo tags: - javascript -top: false -type: null --- 当谈到继承时,javascript只有一种结构:对象。 -每个实例对象(object)都有一个私有属性(\_\_proto\_\_)指向它的构造函数的原型对象(__prototype__)。 -该原型对象也有自己的原型对象((\_\_proto\_\_),层层向上,直到有一个的原型对象为null。根据定义,null没有原型,并作为这个原型链的最后一个环节。 +每个实例对象(object)都有一个私有属性`__proto__`指向它的构造函数的原型对象 __prototype__。 +该原型对象也有自己的原型对象`__proto__`,层层向上,直到有一个的原型对象为null。根据定义,null没有原型,并作为这个原型链的最后一个环节。 @@ -20,3 +18,165 @@ type: null ## 基于原型链的继承 ### 继承属性 + +`javascript` 对象是动态的属性"包裹"(指自身的属性)。同时,对象还有一个指向一个原型对象的链。 +当访问一个对象的属性时,不仅会在该对象上查找,也会在该对象的原型上查找,进而在该对象的原型的原型上查找, +依次层层向上查找,直到找到匹配的属性,或者到达原型链的末尾。 + +::: info ECMAScript标准 +`obj.[[Prototype]]`符号用于指向`obj`的原型。从`ES6`开始`[[Prototype]]` +可以通过`Object.getPrototypeof()`和 `Object.setPrototypeof()` 访问器进行访问。 +等同于许多浏览器实现的属性`__proto__`。 +::: + +从代码示例来分析继承属性: + +在这个示例中,定义了一个函数`Foo`, 它拥有自身属性 `a`和`b`。 + +然后创建一个 `Foo` 的示例 `foo`。 +``` js +function Foo() { + this.a = 1 + this.b = 2 +} +let foo = new Foo() + +Foo.prototype.c = 3 +Foo.prototype.d = 4 + +// 输出自身的所有属性 +console.log(foo) // { a: 1, b: 2 } + +// 自身拥有属性 a +console.log(foo.a) // 1 +// 自身拥有属性 b +console.log(foo.b) // 2 +// 自身没有属性 c, 但其原型上有属性 c +console.log(foo.c) // 3 +// 自身没有属性 d,但其原型上有属性 d +console.log(foo.d) // 4 + +``` +在这个示例中, 整个原型链如下 +``` js +// { a: 1, b: 2 } => { c: 3, d: 4 } => Object.prototype => null +``` + +### 继承方法 + +在`Javascript` 中,并没有其他基于类的语言所定义的 方法。 +任何函数都可以添加到对象上做为对象的属性。 +函数属性的继承与其他属性的继承没有差别。 + +当继承的函数被调用时,`this`指向的是当前继承的对象,而不是继承的函数所在的原型对象。 + +``` js +var o = { + a: 1, + f: function() { + return this.a + 1 + } +} + +// 此时 函数f 中的 this 指向了 o +console.log(o.f()) // 2 + +var p = Object.create(0) +p.a = 3 + +// p从o上继承了函数f, 此时函数f中的 this 指向了 p +console.log(p.f()) // 4 +``` + +## 创建对象和生成原型链 + +### 使用语法结构创建的对象 +``` js +var o = { a: 1 } +// 原型链: o => Object.prototype => null + +var arr = ['a', 'b'] +// 原型链: arr => Array.prototype => Object.prototype => null + +function f() {} +// 原型链: f => Function.prototype => Object.prototype => null +``` + +### 使用构造器创建对象 +``` js +function Person() { + this.a = 1 +} +Person.prototype = { + f: function () { + return this.a + } +} +var p = new Person() +// 原型链: p => Person.prototype => Object.prototype => null +``` + +### 使用`Object.create`创建的对象 +``` js +var a = { a: 1 } +var b = Object.create(a) +// 原型链 b => a => Object.prototype => null + +var c = Object.create(null) +// 原型链 c => null +``` + + +## 扩展原型链的方法 + +### 构造器创建对象,原型赋值给另一个构造函数原型 +``` js +function foo() {} +foo.prototype = { + a: 'foo' +} + +function bar() {} + +var proto = new foo() +proto.b = 'bar' +bar.prototype = proto + +var p = new bar() +console.log(p.a) // foo +console.log(p.b) // bar +``` + +### Object.create +``` js +function foo() {} +foo.prototype = { + a: 'foo' +} +function bar() {} + +var proto = Object.create(foo.prototype) +proto.b = 'bar' +bar.prototype = proto + +var p = new bar() +console.log(p.a) // foo +console.log(p.b) // bar + +``` + +``` js +function foo() {} +foo.prototype = { + a: 'foo' +} + +function bar() {} + +var proto = Object.create(foo.prototype, { b: 'bar' }) +bar.prototype = proto + +var p = new bar() +console.log(p.a) // foo +console.log(p.b) // bar +``` diff --git a/docs/1.前端/1.基础/正则表达式使用手册.md b/docs/1.前端/1.基础/正则表达式使用手册.md index 05b2e8de..b09884f3 100644 --- a/docs/1.前端/1.基础/正则表达式使用手册.md +++ b/docs/1.前端/1.基础/正则表达式使用手册.md @@ -2,7 +2,7 @@ title: 正则表达式 lang: zh-CN createTime: 2018/11/26 11:15:27 -permalink: /article/e8qbp0dh +permalink: /article/e8qbp0dh/ author: pengzhanbo tags: - javascript @@ -56,7 +56,7 @@ _以下讨论以正则表达式字面量来创建正则表达式_ 元字符也叫特殊字符,是正则表达式规定的,对符合特定的单一的规则的字符的描述。 | 字符 | 含义 | |:----:|-----| -|\\|在非特殊字符的前面加反斜杠,表示这个字符是特殊的,不能从字面上解释。比如在`\d`描述的不是一个普通的字符`d`,而是正则表达式中的数值`0-9`。
如果在特殊字符前面加反斜杠,这表示将这个字符转义为普通字符,比如`?`在正则中有其特殊含义,前面加反斜杠\?,这可以将其转为普通的`?`。| +| \\ |在非特殊字符的前面加反斜杠,表示这个字符是特殊的,不能从字面上解释。比如在`\d`描述的不是一个普通的字符`d`,而是正则表达式中的数值`0-9`。
如果在特殊字符前面加反斜杠,这表示将这个字符转义为普通字符,比如`?`在正则中有其特殊含义,前面加反斜杠\?,这可以将其转为普通的`?`。| |^|匹配文本开始的位置,如果开启了多行标志,也会匹配换行符后紧跟的位置。
比如`^a`会匹配`abc`,但不会匹配到`bac`。| |$|匹配文本结束的位置,如果开启了多行标志,也会匹配换行符前紧跟的位置。
比如`b$`会匹配`acb`,但不会匹配到`abc`。| |*|匹配前一个表达式0次到多次。
比如,`ab*`会匹配到`abbbbbbc`中的`abbbbbb`,以及`acbbbbb`中的`a`。| diff --git a/docs/1.前端/1.基础/浏览器端的事件循环.md b/docs/1.前端/1.基础/浏览器端的事件循环.md index 40300585..e9cd6d59 100644 --- a/docs/1.前端/1.基础/浏览器端的事件循环.md +++ b/docs/1.前端/1.基础/浏览器端的事件循环.md @@ -1,8 +1,189 @@ --- title: Event Loop 浏览器端的事件循环 createTime: 2021/06/03 01:53:17 -permalink: /article/browser-event-loop +permalink: /article/browser-event-loop/ author: pengzhanbo -top: false -type: null +tags: + - javascript --- + +事件循环,即 Event-Loop。 + +## 什么是 Event-Loop ? + +Event-Loop 是一个执行模型,在 [html5规范](https://html.spec.whatwg.org/multipage/webappapis.html#event-loops) 中进行了浏览器端的 Event-Loop 的明确定义。 + +## 宏任务与微任务 + +javascript 有两种异步任务,分别是`宏任务`和`微任务` + +### 宏任务 + +宏任务,`macro task`,也叫 `tasks`,一些异步任务的回调会依次进入 `macro task queue`,等待后续被调用。 + +这些异步任务包括: +- setTimeout +- setInterval +- setImmediate (Node独有) +- requestAnimationFrame (浏览器独有) +- I/O +- UI rendering + +### 微任务 + +微任务, `micro task`, 也叫 `jobs`,另一些异步任务的回调会依次进入`micro task queue`,等待后续被调用。 + +这些异步任务包括: +- process.nextTick(Node独有) +- Promise +- Object.observe +- MutationObserver + +## 事件循环 Event Loop + +1. 执行全局 `script` 代码,这些代码有一些是同步语句,有一些是异步语句(如: setTimeout); +2. 全局`script`同步代码执行完毕后,调用栈Stack会清空; +3. 从微任务`micro task queue` 中取出位于队首的任务,放入调用栈Stack中执行,执行完后`micro task queue`长度减一; +4. 继续取出微任务`micro task queue`位于队首的任务,放入调用栈Stack中执行, + 以此类推,直到把`micro task queue`中的所有任务都执行完毕。__注意,如果在执行micro task的过程中,产生了`micro task`那么会加入到队列的末尾,也会在这个周期被调用执行__; +5. `micro task`中的所有无人都执行完毕,此时 `micro task queue` 为空队列,调用栈Stack也为空; +6. 取出宏队列 `macro task queue` 中位于队首的任务,放入Stack中执行; +7. 执行完毕后,调用栈Stack为空; +8. 重复第3-7个步骤; +9. 以此继续循环重复; + +::: tip 重点 +1. 宏任务`marco task` 一次只从队列中取出一个任务执行,执行后就去执行微任务队列中的任务; +2. 微任务队列中所有的任务都会依次取出来执行,直到`micro task queue`为空, + 且当前微任务执行过程中产生新的`micro task`,也会加入到当前`micro task queue`; +3. `UI Rendering`由浏览器自定判断决定执行节点。但是只要执行`UI Rendering`,它的节点是在执行完所有 + `micro task`之后,下一个`macro task`之前,紧跟着执行`UI Rendering` +::: + +尝试从代码层面来分析 event-loop: + +::: note 抖个机灵 +代码人看代码应该比看流程图要来得好理解了吧(bushi) +::: + +``` js +// 执行器 +// 接收一段javascript代码 +class Execution { + constructor(code) { + this.code = code + this.macroTaskQueue = [] + this.microTaskQueue = [] + } + + // 启动执行 + exec() { + // 首次运行,将 传入的 code 推入到 Track中执行 + // 并获取其中的 宏任务和 微任务 + const { macroTaskQueue, microTaskQueue } = this.run(this.code) + // 将宏任务和微任务 推入到 各自的 队列中 + this.macroTaskQueue.push(...macroTaskQueue) + this.microTaskQueue.push(...microTaskQueue) + // 开始执行微任务 + this.runMicroTaskQueue() + } + + // 执行微任务队列 + runMicroTaskQueue() { + // 遍历 微任务队列中的所有任务 + // 当当前的 微任务队列清空时,遍历才结束 + while (this.microTaskQueue.length) { + // 取出 队首的微任务 + const task = this.microTaskQueue.shift() + // 将 当前微任务 推入到 执行栈中执行 + // 并将返回的 宏任务和微任务 继续 推入到 各自的队列中 + const { macroTaskQueue, microTaskQueue } = this.run(task) + this.macroTaskQueue.push(...macroTaskQueue) + this.microTaskQueue.push(...microTaskQueue) + } + // 当前微任务执行完毕,继续执行宏任务 + this.runMacroTaskQueue() + } + + // 执行宏任务队列 + runMacroTaskQueue() { + // 从 宏任务队列队首 取出一个 宏任务 + const task = this.macroTaskQueue.shift() + // 将当前 宏任务 推入到 执行栈中执行 + // 并将返回的 宏任务和微任务 继续 推入到 各自的队列中 + const { macroTaskQueue, microTaskQueue } = this.run(task) + this.macroTaskQueue.push(...macroTaskQueue) + this.microTaskQueue.push(...microTaskQueue) + // 再一次执行 微任务队列中的任务 + this.runMicroTaskQueue() + } + + // 执行栈调用 + run(task) { + // track 函数表示 执行栈 + // 执行完毕返回 产生的 微任务队列 和 宏任务队列 + const { macroTaskQueue, microTaskQueue } = track(task) + return { macroTaskQueue, microTaskQueue } + } +} +const execute = new Execution(scriptCode) +execute.exec() +``` + +`event-loop` 概念性的内容大体就这么多,接下来从示例中来实际执行情况。 + +## 示例 + +::: warning 注意 +以下示例是在 `Chrome` 中执行后获得的结果,在其他浏览器的表现并不一定完全相同。 +::: + + +可以尝试自己心中执行这段代码后的打印顺序,再切换到`Console`中看实际的运行结果,是否符合你的预期结果。 + +::: code-tabs + +@tab javascript +``` js +console.log('script') + +setTimeout(() => { + console.log('timeout 1') + Promise.resolve().then(() => { + console.log('promise 1') + }) +}) + +new Promise((resolve) => { + console.log('promise resolver') + + Promise.resolve().then(() => { + console.log('promise 3') + }) + + resolve('promise 2') +}).then((data) => { + console.log(data) +}) + +setTimeout(() => { + console.log('timeout 2') +}) + +console.log('end') +``` + + +@tab Console +``` txt +script +promise resolver +end +promise 3 +promise 2 +timeout 1 +promise 1 +timeout 2 +``` +::: + diff --git a/docs/1.前端/1.基础/详解Promise.md b/docs/1.前端/1.基础/详解Promise.md index 91aba9b0..3ccec921 100644 --- a/docs/1.前端/1.基础/详解Promise.md +++ b/docs/1.前端/1.基础/详解Promise.md @@ -1,10 +1,10 @@ --- title: 详解 Promise createTime: 2020/11/22 12:58:28 -permalink: /article/q40nq4hv +permalink: /article/q40nq4hv/ author: pengzhanbo -sticky: true -type: null +tags: + - javascript --- ## 概述 @@ -47,6 +47,8 @@ Promise 创建后,必然处于以下几种状态 *then()* 接收两个函数参数(也可以仅接收一个函数参数 onFulfilled)。 - onFulfilled 函数参数,表示当 promise的状态从 `pending` 更新为`fulfilled` 时触发,并将成功的结果 value 作为`onFulfilled`函数的参数。 - onRejected 函数参数,表示当promise的状态从 `pending` 更新为`rejected` 时触发,并将失败的原因 reason 作为 `onRejected`函数的参数。 + + *then()* 方法返回的结果会被包装为一个新的promise实例。 #### `.catch(onRejected)` *catch()* 可以相当于 *.then(null, onRejected)*,即仅处理当promise的状态从 `pending` 更新为`rejected` 时触发。 @@ -90,6 +92,162 @@ promise }) ``` +## Promise代码实现 +```js +const PENDING = "pending"; +const FULFILLED = "fulfilled"; +const REJECTED = "rejected"; +const microtask = globalThis.queueMicrotask || ((cb) => setTimeout(cb, 0)); + +function LikePromise(resolver) { + if (typeof resolver !== "function") { + throw new TypeError(`Promise resolver ${resolver} is not a function`); + } + this.state = PENDING; + this.value = undefined; + this.reason = undefined; + this.fulfillQueue = []; + this.rejectQueue = []; + + const that = this; + + function reject(reason) { + if (that.state === PENDING) { + that.state = REJECTED; + that.reason = reason; + that.rejectQueue.forEach((cb) => cb(reason)); + } + } + + function resolve(value) { + if (that.state === PENDING) { + that.state = FULFILLED; + that.value = value; + that.fulfillQueue.forEach((cb) => cb(value)); + } + } + + try { + resolver(resolve, reject); + } catch (e) { + reject(e); + } +} + +function resolvePromise(promise, x, resolve, reject) { + if (promise === x) { + reject(new TypeError("chaining cycle")); + } else if (x !== null && (typeof x === "object" || typeof x === "function")) { + let used = false; + try { + const then = x.then; + if (typeof then === "function") { + then.call( + x, + (y) => { + if (used) return; + used = true; + resolvePromise(promise, y, resolve, reject); + }, + (r) => { + if (used) return; + used = true; + reject(r); + } + ); + } else { + if (used) return; + used = true; + resolve(x); + } + } catch (e) { + if (used) return; + used = true; + reject(e); + } + } else { + resolve(x); + } +} + +LikePromise.prototype.then = function (onFulfilled, onRejected) { + onFulfilled = + typeof onFulfilled === "function" ? onFulfilled : (value) => value; + onRejected = + typeof onRejected === "function" + ? onRejected + : (reason) => { + throw reason; + }; + const that = this; + const promise = new LikePromise((resolve, reject) => { + if (that.state === FULFILLED) { + microtask(() => { + try { + const x = onFulfilled(that.value); + resolvePromise(promise, x, resolve, reject); + } catch (e) { + reject(e); + } + }); + } else if (that.state === REJECTED) { + microtask(() => { + try { + const x = onRejected(that.reason); + resolvePromise(promise, x, resolve, reject); + } catch (e) { + reject(e); + } + }); + } else { + that.fulfillQueue.push(() => { + microtask(() => { + try { + const x = onFulfilled(that.value); + resolvePromise(promise, x, resolve, reject); + } catch (e) { + reject(e); + } + }); + }); + that.rejectQueue.push(() => { + microtask(() => { + try { + const x = onRejected(that.reason); + resolvePromise(promise, x, resolve, reject); + } catch (e) { + reject(e); + } + }); + }); + } + }); + return promise; +}; + +LikePromise.prototype.catch = function (onRejected) { + return this.then(null, onRejected); +}; + +LikePromise.prototype.finally = function (onFinally) { + return this.then( + (value) => LikePromise.resolve(onFinally()).then(() => value), + (reason) => + LikePromise.resolve(onFinally()).then(() => { + throw reason; + }) + ); +}; + +LikePromise.resolve = function (value) { + return new LikePromise((resolve) => resolve(value)); +}; + +LikePromise.reject = function (reason) { + return new LikePromise((_, reject) => reject(reason)); +}; +``` + ## `Promise` 静态方法 diff --git a/docs/1.前端/10.开发/1px解决方案.md b/docs/1.前端/10.开发/1px解决方案.md index 786cf2cc..5191ff4b 100644 --- a/docs/1.前端/10.开发/1px解决方案.md +++ b/docs/1.前端/10.开发/1px解决方案.md @@ -1,13 +1,12 @@ --- title: 1px解决方案 createTime: 2019/05/15 10:41:32 -permalink: /article/tz7ncicn +permalink: /article/tz7ncicn/ author: pengzhanbo tags: - html - css - develop -banner: /images/big-banner.jpg --- 在日常移动端前端应用开发中,经常遇到一个问题就是 1px的线在移动端 Retina屏下的渲染并未达到预期。以下总几种不同场景下的 1px解决方案。 diff --git a/docs/1.前端/10.开发/lerna使用.md b/docs/1.前端/10.开发/lerna使用.md index c95ad70b..532ccf7b 100644 --- a/docs/1.前端/10.开发/lerna使用.md +++ b/docs/1.前端/10.开发/lerna使用.md @@ -1,13 +1,13 @@ --- title: lerna使用 createTime: 2021/11/26 06:28:37 -permalink: /article/i1wc1uld +permalink: /article/i1wc1uld/ author: pengzhanbo -top: false -type: null --- -![lerna](https://user-images.githubusercontent.com/645641/79596653-38f81200-80e1-11ea-98cd-1c6a3bb5de51.png) +::: center +![lerna](https://user-images.githubusercontent.com/645641/79596653-38f81200-80e1-11ea-98cd-1c6a3bb5de51.png){ style="width: 50%" } +::: ## 概述 @@ -118,4 +118,4 @@ lerna run build # 相当于在 package1、package2 中执行 npm run build ``` ### lerna clean - 删除所有包的node_modules \ No newline at end of file + 删除所有包的node_modules diff --git a/docs/1.前端/10.开发/pnpm.md b/docs/1.前端/10.开发/pnpm.md new file mode 100644 index 00000000..1feac4f0 --- /dev/null +++ b/docs/1.前端/10.开发/pnpm.md @@ -0,0 +1,280 @@ +--- +title: pnpm 包管理器 +createTime: 2022/05/10 03:50:47 +author: pengzhanbo +permalink: /article/84nu27cz/ +--- + +`pnpm` 是一款新兴不久的包管理器,相比于 `npm` 和 `yarn`,`pnpm` 拥有更快的安装速度,同时节约磁盘空间。 + + + +## 介绍 + +![pnpm](https://pnpm.io/zh/img/pnpm-no-name-with-frame.svg) + +`pnpm` 是一个类似于 `npm` 、`yarn` 的包管理器。 + +`pnpm` 安装的包都会被存储在硬盘的某个相同位置,软甲包通过硬链接到这个位置,实现共享同一版本的依赖, +对于同一依赖的不同版本,`pnpm update` 时,只会向存储中心添加新版本更新的文件,而不是仅仅应为一个文件的改变而复制整个新版本包的内容。 + +`pnpm` 内置支持 `monorepo`,即单仓库多包。 + +## 比较 + +### pnpm/yarn/npm + +| 功能 | pnpm | yarn | npm | +| -- | :--: | :--: | :--: | +| 工作空间支持(monorepo)| ✔️ | ✔️ | ✔️ | +| 隔离的`node_modules` | ✔️ - 默认 | ✔️ | ❌ | +| 提升的`node_modules` | ✔️ | ✔️ | ✔️ -默认 | +| 自动安装peers | ✔️ - `auto-install-peers=true` | ❌ | ✔️ | +| Plug'n'Play | ✔️ | ✔️ - 默认 | ❌ | +| 零安装 | ❌ | ✔️ | ❌ | +| 修复依赖项 | ✔️ | ✔️ | ❌ | +| 管理nodejs版本 | ✔️ | ❌ | ❌ | +| 有锁文件 | ✔️ - `pnpm-lock.yaml` | ✔️ - `yarn.lock` | ✔️ - `package-lock.json` | +| 支持覆盖 | ✔️ | ✔️ - `resolutions` | ✔️ | +| 内容可寻址存储 | ✔️ | ❌ | ❌ | +| 动态包执行 | ✔️ - `pnpm dlx` | ✔️ - `yarn dlx` | ✔️ - `npx` | +| Side-effects cache | ✔️ | ❌ | ❌ | + +### 区别 + +与 `yarn/npm` 不同的是,`pnpm` 并非采用 *扁平的`node_modules`* 来管理依赖项, +而是基于符号链接的`node_modules` 结构。 + +`node_modules` 中每个包的每个文件都是来自内容可寻址存储的硬链接。 假设安装了依赖于 `bar@1.0.0` 的 `foo@1.0.0`。 `pnpm` 会将两个包硬链接到 `node_modules` 如下所示: + +```sh +node_modules +└── .pnpm + ├── bar@1.0.0 + │ └── node_modules + │ └── bar -> /bar + │ ├── index.js + │ └── package.json + └── foo@1.0.0 + └── node_modules + └── foo -> /foo + ├── index.js + └── package.json +``` +这是 `node_modules` 中的唯一的“真实”文件。 一旦所有包都硬链接到 `node_modules`, +就会创建符号链接来构建嵌套的依赖关系图结构。 + +`bar` 将被符号链接到 `foo@1.0.0/node_modules` 文件夹,然后处理依赖关系,`foo` 将被符号链接至根目录的 `node_modules` 文件夹: + +```sh +node_modules +├── foo -> ./.pnpm/foo@1.0.0/node_modules/foo +└── .pnpm + ├── bar@1.0.0 + │ └── node_modules + │ └── bar -> /bar + └── foo@1.0.0 + └── node_modules + ├── foo -> /foo + └── bar -> ../../bar@1.0.0/node_modules/bar +``` + +这种布局的好处在于,只有真正在依赖项中的包才能访问。 +如果是平铺的 `node_modules` 结构,所有被提升的包都可以访问。 + +### 优势 + +- 节约磁盘空间 + + 包存储在全局存储中,pnpm 创建从全局存储到项目下 `node_modules` 文件夹的 硬链接,硬链接指向磁盘上原始文件所在的同一位置。不同软件包可以共享相同依赖项所占用的空间。 + + 如果是单个依赖的不同版本,如版本更新,`pnpm` 仅安装版本更新的文件,而不是全量安装整个新版本的包。 + +- 安装速度快 + + 软件包中安装依赖时,如果检索到在本地的全局存储中已安装过该依赖,那么不会从网络下重新安装,而是直接创建硬链接到软件包中。 + +- 内置支持 monorepo + + 支持 单仓库多包,通过 `pnpm-workspace.yaml` 配置工作空间,通过 `workspace:*` 协议引用工作空间的依赖包。 + +## 安装 + +### 通过 npm 安装 + +```sh +npm install -g pnpm +``` + +### 通过 Corepack 安装 + +从 v16.13 开始,Node.js 发布了 `Corepack` 来管理包管理器。 这是一项实验性功能,因此需要通过运行如下脚本来启用它: + +```sh +corpack enabled +``` + +这将自动在系统上安装 pnpm。 但是,它可能不是最新版本的 pnpm。 +若要升级,请检查 [最新的 pnpm 版本](https://github.com/pnpm/pnpm/releases/tag/v7.9.1) 并运行: + +```sh +corepack prepare pnpm@ --activate +``` +### 使用独立脚本安装 + +在 POSIX 系统上,即使没有安装 Node.js,也可以使用以下脚本安装 pnpm: + +```sh +curl -fsSL https://get.pnpm.io/install.sh | sh - +``` + +如果没有安装 `curl` ,也可以使用 `wget`: + +```sh +wget -qO- https://get.pnpm.io/install.sh | sh - +``` + +在 Windows 系统中,如果使用 Powershell: + +```sh +iwr https://get.pnpm.io/install.ps1 -useb | iex +``` + +### 使用 Homebrew 安装 + +```sh +brew install pnpm +``` + +### 使用 Scoop 安装 + +```sh +scoop install nodejs-lts pnpm +``` + +## 使用 + +`pnpm` 在使用上 与 `npm` 、`yarn` 的使用上差别不大,但需要注意的区别,`pnpm` 会严格校验所有参数, +比如,`pnpm install --target_arch x64` 会执行失败,因为 `--target_arch x64` 不是 `pnpm install` 的有效参数。 + +### 常用命令 + +#### `pnpm install` + +别名 `pnpm i` + +等效于 `npm install` / `yarn` + +用于安装项目所有依赖。 + +[pnpm install 官方文档](https://pnpm.io/zh/cli/install) + +#### `pnpm add ` + +安装软件包及其依赖的任何软件包。 默认情况下,任何新软件包都安装为生产依赖项。 + +[pnpm add 官方文档](https://pnpm.io/zh/cli/add) + +#### `pnpm remove` + +别名: `rm` `uninstall` `un` + +从 `node_modules` 和项目的 `package.json` 中删除相关 packages。 + +[pnpm remove 官方文档](https://pnpm.io/zh/cli/remove) + +#### `pnpm update` + +别名: `up` `upgrade` + +`pnpm update` 根据指定的范围更新软件包的最新版本。 + +在不带参数的情况下使用时,将更新所有依赖关系。 您可以使用一些模式来更新特定的依赖项。 + +[pnpm update 官方文档](https://pnpm.io/zh/cli/update) + +更多命令请查阅[官方文档](https://pnpm.io/zh/cli/add) + +### 配置 + +#### `.npmrc` + +`pnpm` 从命令行、环境变量和 `.npmrc` 文件中获取其配置。 + +`pnpm config` 命令可用于更新和编辑 用户和全局 .npmrc 文件的内容。 + +四个相关文件分别为: + +- 每个项目的配置文件(`/path/to/my/project/.npmrc`) +- 每个工作区的配置文件(包含 `pnpm-workspace.yaml` 文件的目录) +- 每位用户的配置文件( `~/.npmrc` ) +- 全局配置文件( `/etc/.npmrc` ) + +#### `pnpm-workspace.yaml` + +`pnpm-workspace.yaml` 定义了 工作空间 的根目录,并能够使工作空间中包含 / 排除目录 。 默认情况下,包含所有子目录。 + +``` yaml +packages: + # 定义 packages 目录下的所有子目录都为一个 package + - 'packages/*' + # 定义 components 目录下的所有子目录都为一个 package + - 'components/**' + # 排除任何目录中的 test 目录下的所有目录 + - '!**/test/**' +``` + +## 工作空间 + +pnpm 内置了对单一存储库(也称为多包存储库、多项目存储库或单体存储库)的支持, 你可以创建一个 workspace 以将多个项目合并到一个仓库中。 + +一个 workspace 的根目录下必须有 `pnpm-workspace.yaml` 文件, 也可能会有 `.npmrc` 文件。 + +### Workspace 协议 (workspace:) + +默认情况下,如果可用的 packages 与已声明的可用范围相匹配,pnpm 将从工作区链接这些 packages。 例如,如果 `bar` 中有 `"foo":"^1.0.0"` 的这个依赖项,则 `foo@1.0.0` 链接到 `bar。` 但是,如果 `bar` 的依赖项中有 `"foo": "2.0.0"`,而 `foo@2.0.0` 在工作空间中并不存在,则将从 `npm registry` 安装 `foo@2.0.0` 。 这种行为带来了一些不确定性。 + +幸运的是,pnpm 支持 workspace 协议 `workspace:` 。 当使用此协议时,pnpm 将拒绝解析除本地 workspace 包含的 package 之外的任何内容。 因此,如果设置为 `"foo": "workspace:2.0.0"` 时,安装将会失败,因为 `"foo@2.0.0"` 不存在于此 workspace 中。 + +使用示例: + +工作空间中存在以下项目: +```sh ++ packages/ + + foo/ + + bar/ + + qar/ + + zoo/ +``` + +如果各个项目以其目录名作为其 package name,那么可以在其他项目中如下引入依赖: + +``` json +{ + "dependencies": { + "foo": "workspace:*", + "bar": "workspace:~", + "qar": "workspace:^", + "zoo": "workspace:^1.5.0" + } +} +``` + +::: tip +引入依赖的包名,是由包的 `package.json name` 确定,而不是 workspace 目录下的目录名确定。 +::: + +### 发布 Workspace + +当以上示例进行发布时,会被转换为 +```json +{ + "dependencies": { + "foo": "1.5.0", + "bar": "~1.5.0", + "qar": "^1.5.0", + "zoo": "^1.5.0" + } +} +``` +这个功能允许你发布转化之后的包到远端,并且可以正常使用本地 workspace 中的 packages,而不需要其它中间步骤。包的使用者也可以像常规的包那样正常使用,且仍然可以受益于语义化版本。 diff --git a/docs/1.前端/10.开发/前端路由.md b/docs/1.前端/10.开发/前端路由.md new file mode 100644 index 00000000..7bbdd88b --- /dev/null +++ b/docs/1.前端/10.开发/前端路由.md @@ -0,0 +1,135 @@ +--- +title: 前端路由 +createTime: 2019/09/13 04:13:56 +author: pengzhanbo +permalink: /article/xhb2iacu/ +--- + +在现代前端中,SPA应用是一种主流的前端应用交互方案,其中,前端路由是实现SPA应用的关键技术之一。 + + + +## 路由 + +**路由(Router)** 一般指的是 URI 中 pathname + basename + hash + query 所组成的 路径。 + +在前端中, **路由** 一般指的是 **随着浏览器中的地址栏的变化,呈现不同的内容给用户**。 +浏览器地址栏的变化,即是 访问链接的变化,具体指的就是 pathname + basename + hash + query 部分的变化。 + +示例: + +``` +/a/b +/a/b/#/hash +/a/b/#/hash?c=1 +``` + +对于前端路由,一般会选择 监听 hash 部分的变化, 或者监听 pathname 部分的变化,从而一般有两种路由模式: + + +### hash 模式 + +通过监听 地址栏中 hash 部分的变化,从而呈现不同的内容。 + +::: center +**https://example.com/index.html ==#/a/b/==** +::: + +在浏览器中,通过注册 **hashchange** 事件,监听 **hash** 变化。 + +``` js +window.addEventListener('hashchange', () => { + const hash = window.location.hash; + console.log(hash) // #/a/b/ +}) +``` + +通过 hash 实现路由的优势在于, hash 仅依赖于浏览器,且hash的变化不会直接导致页面刷新,天然适合于实现 前端路由。 + +### history 模式 + +通过监听 地址栏中 pathname 部分的变化,从而呈现不同的内容。 + +history模式是依赖于 浏览器端的 History API 而实现。 +History API 允许我们对浏览器会话历史记录进行访问并操作。 + +::: center +**https://example.com ==/a/b/==** +::: + +History API 通过 history.pushState() 和 history.replaceState() 方法,新增或者替换历史记录, +通过 popState 事件监听历史记录的变化。 + + +直接操作历史记录的变化,结果会改变浏览器地址栏的显示内容,但不会引起浏览器刷新页面。 +但是由于变化的部分一般是 `pathname + basename` 的部分,如果手动刷新页面,可能会导致浏览器通过当前路径 +向服务器发起请求找不到对应的资源而返回404,所以一般需要在服务器端的HTTP服务器进行配置,将相关的路径请求资源, +都指向同一个html资源文件。 + +> [History API](https://developer.mozilla.org/zh-CN/docs/Web/API/History_API) + +### 其他模式 + +除了上述两种一般用于浏览器端中的路由模式,为了满足其他的场景,比如 在SSR场景下,需要在服务端模拟路由在生成页面内容, +或者在 electron 桌面应用中。一般会基于 memory 实现一种 仅通过 memory 的变化的路由的模式。 + +在这个模式中,通过一个普通的 JavaScript 字符串或者对象,来实现模拟 路由路径地址以及相关功能。 + +## Router解析 + +前端路由在不同的库或者框架中实现,一般会采用一套通用的解析规则,在实现细节上有所差异。 + +一个路由地址,一般包含如下几个部分: + +- **path** 表示路由的路径 +- **params** 表示路由的路径动态匹配结果 +- **query** 表示路由携带的参数,未解析前为 queryString, 解析后为 queryObject + +如一个 路由地址: `/a/b/?c=1` 中, `/a/b/` 部分一般称为 **path** , `?c=1` 部分一般被称为 `query`。 + +### 具名路由 + +具名路由,也称 静态路由 指在声明一个路由时,对地址栏路径地址使用 全等匹配,仅当声明的路由与路径地址全等时,才命中路由。 + +``` js +// 浏览器地址栏: https://example.com/a/b/ +// 声明路由: +const routes = [ + { + path: '/a/b', // 命中当前路由 + }, + { + path: '/a/c', // 不一致,未命中 + }, + { + path: '/a', // 不一致,未命中 + }, + { + path: '/a/b/c', // 不一致,未命中 + } +] +``` + +### 路由匹配 + +路由匹配,指通过 一套匹配规则,对地址栏路径地址 进行 规则匹配,当命中匹配规则时,则命中路由。 +一般场景下, 通过 `/:pathname` 的格式来表示路由路径中的动态部分。 + +如 `/user/:id`, 则可以匹配 `/user/123`,`/user/456` 等满足规则的地址栏路径。 + +`/:pathname` 部分会被解析到 `params` 对象中,如上述的 通过`/user/:id`规则解析 `/user/123`,表示为: + +```js +const currentRoute = { + path: '/user/123', + params: { id: 123 } +} +``` + +### 其他 + +在不同的框架或库中, 对路由解析会在基于上述的规则的基础上,进行补充和扩展,提供更加丰富的功能,以满足更多的场景。 + +比如, **Vue-Router** 使用了 `path-to-regexp` 库作为其路由解析的依赖,该库提供了非常丰富且灵活的路径匹配功能, +能够适配非常多的从简单到复杂的场景。**React-Router** 则在其内部实现了和扩展了相关的规则。 + diff --git a/docs/1.前端/10.开发/微前端.md b/docs/1.前端/10.开发/微前端.md new file mode 100644 index 00000000..142587f2 --- /dev/null +++ b/docs/1.前端/10.开发/微前端.md @@ -0,0 +1,285 @@ +--- +title: 谈谈微前端 +createTime: 2019/08/31 05:13:33 +author: pengzhanbo +permalink: /article/vpqgx0t7/ +--- + +微前端 是最近比较新兴的一个话题,它不具体指某个库某个框架,而是一个思想,一种概念,运用这种思想, +根据自身的需求,从而实现适用于自身的 微前端 。 + + + +> 本文根据最近我在公司内部举行的 微前端技术解决方案 分享而写。 +> 提供的 微前端方案 也应用于公司内部的项目,并取得了良好的反馈,获得广泛好评。 +> 本文不具体谈如何实现微前端,仅讲述微前端的概念,期望能够通过本文理解微前端。 + +## 前言 + +微前端 目前在行业内是一个新兴的思想。 + +诞生这个思想的背景是,在公司内部,常常会有一类项目,这类项目很大、很重, +涉及的业务内容多而杂,还涉及了跨部门共同维护,积累的庞大的技术债 等各种问题。 +这类项目在维护成本上、部署成本上等,都会花费巨大的开销,前端开发人员对于维护这类项目,苦不堪言, +急需找到解决这类问题的方案。 + +基于这样的背景下,开始探讨 解决方案的可行性, 微前端 正是基于此 开始慢慢 出现在人们的视野中。 + +## 现状 + +### 发展历程 + +在 Web 的发展初期,还没有所谓的前端的概念,网页的内容也相对简单,大多仅涉及文字图片信息的展示和表单内容, +这些工作可能网站负责人自己就包办了。 +然后微软推出了 **Ajax** 技术,引起了网页的技术变革,从此网站开始具备了动态交互性, +能够在网页发起请求动态获取服务器的内容,这丰富了网页的可交互性,网页的开发也从UI界面和表单交互,进一步增加了 +数据和逻辑的开发,前端也慢慢的被划分一个相对独立的职能。 + +而伴随着 nodejs 的出现,以及 angular 的出现,还包括 vue/react 等库,以及建立在 nodejs 上的生态, +包括grunt、gulp、webpack 等工具的诞生,前端进入了一个喷井式爆发的时期,也是我们所处的时期。前端越来越专业化, +包含的技术内容越来越丰富,依托于nodejs 以及众多的技术框架等,向着工程化进一步的发展,前端项目也越来越大。 + +### 浮现的问题 + +你是否维护过一个可能有着四五年以上历史的项目?是否维护过一个糅杂了各种各样的库的项目? +是否维护过一个多个公司部门参与的跨团队联合开发的项目? + +对于很多人来说,入职的某个公司,最怕被安排去维护一个这样的项目。因为每一次维护迭代,就如同开盲盒一样, +永远不知道有什么惊喜在等着自己。 + +对于这类项目,可能存在的问题包括: + +- 跨部门,夸团队联合开发,如何沟通?如何协作? +- 业务线多,页面多,如何管理? +- 如何进行代码管理? +- 如何进行分支管理? +- 多部门进行迭代,如何把控版本? +- 存在发布冲突,如何解决? +- 如何进行测试? +- 如何管理公共代码? +- ... + +可能改动某一行代码,都会带来意想不到的结果,种种问题的积累,技术债的、业务债的,使得项目越来越臃肿,越来越难以维护。 + +亟需寻找一种方案,能够解决这些问题。 + +### iframe嵌入 + +于是,在大多数时候,我们不得不去选择通过 iframe嵌入 的方式,先把臃肿的项目一点一点的拆开给回各个部门或者团队自行维护, +再提供一个 系统门户应用,用 iframe嵌入 的方式,加上维护一个菜单列表与其他项目入口链接的映射,来糅合成一个 网站应用。 + +![iframe嵌入](//assets.processon.com/chart_image/630f92445653bb0c5d1040ab.png) + +通过 iframe嵌入,在一定程度上,满足了 各部门各团队各业务线 独立开发独立部署的需求,只需要提供对应的页面链接就可以接入到 +整个系统中。但也存在着一些问题 + +**安全问题** + +然而,我们知道, iframe是存在安全问题的,如果攻击者使用 iframe访问一个 未知来源的链接,有可能被注入恶意脚本,从而盗取 +系统的隐私信息,这需要我们去严格配置 SCP,以及配置 sandbox,尽可能的保证 iframe 的安全性。 + +**资源加载过多** + +而由于仅需要提供链接就可以嵌入,那么对于各自的项目来说,灵活度就很高,各个项目可以随意的选择各种技术框架来实现自己的业务, +又或者即使使用了相同的技术框架,但各项目的资源相对独立,对于整个系统而言,需要加载的资源量会十分庞大, +从而导致了页面访问速度变慢,经常会出现页面部分区域白屏等待时间过长等,这也带来了体验问题。 + +**访问地图丢失** + +由于 iframe 嵌入的站点,独享访问历史记录,与外部的历史记录是相互独立的,即通过浏览器的 前进/回退 按钮来访问历史记录并 +不能得到预期的结果,这在一定程度上影响了用户的操作。 + +## 寻找解决方案 + +有没有什么其他的方案,来进一步解决这些问题呢? + + +首先我们明确的知道,单项目管理目前来看不是一个可行的方案,需要在多项目管理上寻求解决方案。 + +### 多项目公共业务组件 + +对于多数的大型系统项目而言,大体上都采用以下布局结构: + +![微前端-2](//assets.processon.com/chart_image/6311781d079129320755bec5.png) + +主体布局结构包括: + +- 导航栏 (可选) +- 左侧菜单栏 (可选) +- 内容区域 +- 页脚 (可选) + +在这种布局结构下,各个业务板块通常通过 导航栏 或者 左侧菜单栏 进行 导航切换,在 内容区域 展示 业务板块。 +即,总体上看,对于业务来说,导航栏、左侧菜单栏、页脚,这几个都是可能 共同的,主要的不同点在于 内容区域。 + +那么我们可以把 共同的部分,如 导航栏、左侧菜单栏、页脚 这几个部分,抽离为公共业务组件, +对于每个业务板块,独立为单独的项目进行开发维护,并在项目中引入这些 公共业务组件。 +公共业务组件其中主要负责之一是提供 链接到各个业务板块。 + +![微前端-3](//assets.processon.com/chart_image/631301e65653bb40f833b613.png) + +这种方案具有如下的优点: + +- 整体系统根据业务板块拆分为了多个项目; +- 实现了项目的独立性,可独立进行开发、发布; +- 通过在主项目重载渲染,实现类似 **SPA应用** 的访问体验; + +但同样也带来了新的问题: + +- 公共业务组件 + + - 公共业务组件 如何进行管理; + - 公共业务组件 如何在业务板块项目之间保持同步更新; + +以及没有解决的问题: + +- 资源加载过多; + +  各个业务板块项目重复加载公共业务组件,重复加载各种库资源。 + +- 项目无法实现统一管理; + +### 主项目重载业务项目资源 + +在上一个方案中,公共业务组件的引入解决了一部分问题,也带来了一部分问题,如何把公共业务组件进行统一管理,并保持一致性? + +我们回到 iframe方案,在这个 iframe方案中,有一个主项目用于管理这些 菜单栏、导航栏等。 同样的,可以借鉴这个思路, +也抽象一个主项目,用于管理这些 公共业务组件,然后寻找另一种方式来加载渲染其他的业务板块项目。 + +我们知道,业务板块的项目,也是通过链接去访问的,而每个链接都对应着一个 html 资源文件,通过加载这个资源,以及HTML内的 css资源、js资源等来渲染页面。那么,我们可以通过解析这个 html资源,然后将得到的 html内容、css文件、js文件,在主项目中加载后渲染到特定的区域, +那么就可以做到在主项目中加载业务板块项目。 + +![微前端-4](//assets.processon.com/chart_image/6314ea9cf346fb55d89d4e77.png) + +在主项目中,实现一个 资源加载器与解析器,通过业务板块项目的访问链接,获取 html资源文件,并解析 html 的内容,包括: + +- `` 标签中的 ``, `<link>`, `<script>` 等; +- `<body>` 标签中的 html 内容,`<script>` 等 + +然后加载 解析得到的 CSS资源、JS资源,将 html内容 插入到 特定的区域中,并进行渲染。 +从而呈现完整的网页内容。 + +这种方案,进一步解决了如下的问题: + +- 公共业务组件交由 主项目进行统一管理,直接避免了同步问题; +- 业务板块均在主项目中渲染,提高了用户体验; + +然而,也引入了新的问题: + +- 业务板块都运行在同一个环境中,多个板块之间切换,加载的资源容易对环境产生污染, + 如污染了某个全局变量、polyfill相互污染等。 +- 可能存在 加载资源跨域问题。 + +但是也拥有了如下的优点: + +- 拆分项目,可独立开发和部署; +- 主项目统一管理 公共业务组件,更易于维护; +- 项目间的切换得到体验优化; + +当方案思考到了这里,发现,主项目是通过 解析 **链接** 来加载业务板块项目, +而 **链接** 对于现代前端来说,更多的意义是可能是 **路由**。那么我们顺着这个思路,继续优化, + + +## 新的方案 + + +说起路由,我们很容易想到,像如今的 `react`, `vue`, `angular` 等主流的库/框架, 通过 路由 来实现 `SPA` 应用, +或者说, 通过 **路由分发页面**。 + +那么,我们可以进一步的扩展这个思路,是否可以通过 **路由分发应用** ? + +### 路由 + +在前端的范畴中,路由指 随着浏览器的地址栏变化,而呈现不同的内容给用户。 + +通常使用 **hash** 或者 **history API** 实现前端路由。 + +``` js +// hash +`https://pengzhanbo.com/#route` + +// history API +`https://pengzhanbo.com/route` +``` +路由进一步细化,通过 `/` ,又可以 划分为 一级路由、二级路由、三级路由... 等多级路由。 + +在现代的前端框架如 `React` / `Vue` / `Angular` 等,均有通过 路由 实现 SPA应用 的技术方案。 +而 SPA应用 就是 **路由分发页面** 。 + +### 路由分发应用 + +与 **路由分发页面** 类似,我们也可以通过 **路由分发应用** 。 + +类似于 主项目重载业务项目资源,通过 实现 路由与业务板块项目的映射关系, +在主项目中通过路由寻找业务板块项目,加载相关资源并渲染在相关区域。 + +### 主应用与子应用 + +从这里开始, 我们将 主项目 定位为 主应用, 将各个 业务板块项目 定义为 子应用。 +在主应用中实现 子应用加载器,加载器通过 解析路由来获取加载对应的子应用。 + +**主应用:** 作为独立的项目,整个系统的入口应用,负责统一管理公共业务组件(如 菜单栏、导航栏、页脚等),负责实现子应用加载器,负责实现渲染子应用的容器。 + +**子应用:** 作为独立的项目,系统的各个业务板块分别独立为单独的项目,单独开发维护与部署。 + +### 注册子应用 + +主应用需要通过路由发现子应用,需要建议起 路由与子应用的映射关系,所以需要有一套机制,用于向主应用注册子应用, +并关联相关资源文件等。 +``` json +[ + { + "AppName": "Sub Application", + "route": "/sub-app-route", + "resource": { + "js": [ + "https://example.com/index.js" + ], + "css": [ + "https://example.com/style.css" + ] + } + }, + // more ... +] +``` + +## 微前端 + +通过将整个系统拆分为一个个小型的项目,小型项目即为子应用,通过细化,将整个系统细化为一个个微小的应用, +从而实现了降低整个系统的复杂性。 +一个小型项目可以是某个部门的业务项目,可以是某个业务项目中的某个板块,也可以是一个单独的页面。 + +这也是为什么将新的方案称之为 **微前端**。 + +微前端是指,通过将一个系统,拆分为一个个 微小的独立的子应用,通过主应用聚合为一个完整的系统。 +微前端是一个与框架无强关联的概念,可以类比于服务端的微服务,是浏览器端的微服务。 + +![](//assets.processon.com/chart_image/6318b7297d9c0833ec81b2cd.png) + +由于子应用是独立的,理论上是支持使用任意的技术框架进行开发,无论是使用 jQuery开发,还是使用 Vue、React、Angular等。 +然而在实际中,对于整个系统而言,技术框架的选择应该保持统一性,以保证整个系统的可维护性。 + + +## 微前端的局限性 + +微前端的技术方案,更适合于 中大型的项目中使用,而对于小型项目而言,由于本身体量不大,没有必要对整个系统进行进一步的细化, +细化反而增加了项目的复杂度。 + +而对于中大型项目而言,如果是老系统迁移到微前端的方案,那么不可避免的,还需考虑新旧方案之间的迁移过渡的方案以及规划。 +如果老系统中存在应用了多种不同的技术框架,或者同框架的不同版本,由于主应用、所有子应用均运行在同一个浏览器环境中, +不可避免的存在环境污染问题,如全局环境污染,polyfill对于原生对象的多次污染等,还包括CSS的命名污染等问题。 +所以如何保证子应用的正确渲染,如何避免环境污染问题,也是亟需解决的问题。 + +## 微前端的未来 + +目前来看,微前端主要分为 主应用 和 子应用,在 **微** 上,也仅细化到页面级别,然而,对于微前端而已,还可以进一步的细化, +如,细化到页面的某一个区块,细化到某一个逻辑功能,均可以通过微前端的技术方案,共享到主应用以及子应用中使用。 +整个系统愈加化整为零,将复杂度进一步的拆解,细化,令每一块功能、逻辑等都能使用通过某个项目提供,甚至独立的项目进行维护和部署。 + +微前端是一个与框架无关的概念,但在实现微前端时,如果允许多技术框架共存,所带来的问题的,反而比不使用微前端时所存在的问题,要更难以预料,难以解决。在实际的场景中,最好还是限定在统一的技术框架范畴中,避免由于共存不同的技术框架,而引入更为复杂的问题, + +## 结语 + +微前端是一个相对新兴的技术概念,适用于一些前端场景,但最好是你已经考虑清楚了,微前端是解决你的场景问题的最好方案,否则,除非必要, +无需选择微前端方案。 diff --git a/docs/1.前端/10.开发/浅谈前端低代码.md b/docs/1.前端/10.开发/浅谈前端低代码.md new file mode 100644 index 00000000..03ef65c6 --- /dev/null +++ b/docs/1.前端/10.开发/浅谈前端低代码.md @@ -0,0 +1,60 @@ +--- +title: 浅谈前端低代码 +createTime: 2022/09/13 08:15:38 +author: pengzhanbo +permalink: /article/ecdgrife/ +article: false +--- + +前端低代码在最近的这两年,不少的公司或技术团队都对此青睐有佳,并各自实现了各自的低代码平台。 + +<!-- more --> + +## 前言 + +前端低代码,是指 无需代码或者仅需少量的代码,即可生成可交互的应用。 + +这个概念的兴起,期望于能够更快的去构建、部署新的应用,并降低门槛,让非技术开发人员也能够构建新的应用。 + +## 为什么做低代码 + +传统的应用开发从启动到发布的过程,大致的流程如下: +::: center +![low-code-1](//assets.processon.com/chart_image/6320a2fb637689341d579d34.png) +::: + +在这个过程中,我们需要花费大量的时间用于 代码开发 -> 测试 这个过程,在这个过程,还需要根据项目大小,组织多个开发人员、测试人员等参与到项目中,包括制定开发规范、测试规范等。 + +而对于某些场景的应用,可能整个应用的生命周期相对较短,多个应用之间存在着类似的功能、需求、设计等等,然而在传统的项目开发中, +我们仍然需要按照上述的流程,完整的走一遍,才能正式发布上线,这无疑会花费大量的时间。一般我们会通过抽离重复的功能、需求、UI等为 +独立的库、组件等,在新项目中实现复用,从而减少开发时间,然而这并不能对项目的发布速度有质的提升。 + +而对于一些小型企业,或者个体经营户,期望做一个线上应用,但并没有多余的资金资源去组建一个开发团队,对购买服务器、上线应用等更是一知半解,成为了制约他们发展的一道坎。 + +对于这些场景、存在的问题,需要需要一种方案,能够实现快速的实现从创建项目到发布部署为可访问的项目,并且能够面向更广泛的用户群体。 +这成为了一个非常具有市场潜力的需求。 + +## 如何做低代码 + +对于一个前端应用,通常由多个页面组成,在现代前端开发中,我们将页面拆分为一个个组件来进行组合: + +![](//assets.processon.com/chart_image/6320ccbf1efad46b0aa9d631.png) + +在 前端低代码 中,我们同样的,可以通过 组件来组装页面,通过可视化的交互方式,将组件拖拽到 页面容器中, +这种交互方式相对来说更加适用于更多的群体。 + +![](//assets.processon.com/chart_image/6320d1830e3e743f58315ed7.png) + +同时,需要提供能够对组件进行编辑状态的能力,以支持应用的个性化配置。 + +![](//assets.processon.com/chart_image/6321b4420e3e743f5833bbc8.png) + +在初步确定好 基础的功能、交互方式后,就可以围绕它们,来完善 实现低代码平台的技术方案。 + +---- + +初步明确的,我们需要 通过 **组件** 来组装 应用,围绕这一块,需要实现: + +- 低代码组件的规范:开发规范、接入规范; +- 用于承载组件、组装组件并渲染的应用容器; +- 组件的状态的更新与保存; diff --git a/docs/1.前端/10.开发/移动端适配方案.md b/docs/1.前端/10.开发/移动端适配方案.md index 057db3f8..54b1c77e 100644 --- a/docs/1.前端/10.开发/移动端适配方案.md +++ b/docs/1.前端/10.开发/移动端适配方案.md @@ -1,12 +1,10 @@ --- title: 移动端适配方案 createTime: 2020/08/14 01:54:29 -permalink: /article/vhpmovsm +permalink: /article/vhpmovsm/ author: pengzhanbo tags: - develop -top: false -type: null --- ## 背景 @@ -108,4 +106,4 @@ css像素是一个抽象单位,主要用在浏览器上,用来精确的度 1. 容器适配 2. 文本适配 3. 大于1px的边框、圆角、阴影 -4. 内边距和外边距 \ No newline at end of file +4. 内边距和外边距 diff --git a/docs/1.前端/10.开发/表单配置化生成.md b/docs/1.前端/10.开发/表单配置化生成.md new file mode 100644 index 00000000..ac0ce4e6 --- /dev/null +++ b/docs/1.前端/10.开发/表单配置化生成.md @@ -0,0 +1,143 @@ +--- +title: 表单配置化生成方案 +createTime: 2022/03/17 10:10:04 +author: pengzhanbo +permalink: /article/y979pp8x/ +--- + +一个简单的基于 vue3 的表单配置化生成方案,可以作为思路参考。 + +<!-- more --> + +## 前言 + +本方案是个人在做某个项目时,需要实现一个简单的表单配置化生成,而做的一个方案。 +最终结果是通过一份表单配置,渲染为一个表单,并支持: + +- 支持多种表单字段类型 (单行文本/多行文本/数字/下拉/多选/单选 等),并支持嵌套字段(对象/数组) +- 支持字段校验 +- 支持条件判断显示/隐藏 表单字段 +- 支持字段分组展示 + + +::: tip +完整代码仓库地址: [formative](https://github.com/pengzhanbo/formative) +::: + +## 效果展示 + +**通过配置生成表单:** +![](/images/formative-demo-1.png) + +**配置的字段为对象或者数组时:** +![](/images/formative-demo-2.png) + +**对配置的字段进行分组展示:** +![](/images/formative-demo-3.png) + +## 方案说明 + +通过配置生成表单,需要明确如何实现 **表单字段** 与对应的表单组件进行关联,并实现**数据绑定**。 + +### 协议配置 + +约定一个协议,通过一个对象来表示 表单中某一个字段: + +**FieldSchema:** +```json +{ + "type": "表示字段的类型,比如单选、多选、单行文本、多行文本等", + "field": "表示字段的名", + "label": "表示字段显示的标签", + "default": "字段默认值", + "description": "字段描述信息,作为提示信息使用" +} +``` + +对于完整的表单,则使用 `FieldSchema[]` 的数组形式进行配置。 + +### 表单字段与组件关联 + +在 vue 中, 组件可以通过 `h(component, attrs[, children])` 渲染函数 进行渲染, +通过 `h()` 函数,可以实现动态渲染不同的组件。 + +我们可以利用这一特性,首先 字段类型与对应的组件进行映射,通过映射关系,用 字段类型获取对应的组件, +然后调用 `h()` 进行渲染。 + +``` ts +// 字段类型 与 组件 映射 +const componentMap = { + radio: RadioField, + checkbox: CheckboxField, + text: TextField, + select: SelectField, +} +``` +``` tsx +{ + name: 'Field', + props: ['fieldType'], + setup(props) { + return () => h(componentMap[props.fieldType]) + } +} +``` + +### 表单数据绑定 + +对于表单数据,需要实现 数据初始化,以及 对应的 Field组件对数据的可读写。 + +在vue中,我们可以使用 `provide/inject` API, 在 表单组件的根组件,通过 `provide()` 进行注入,在内部的 +`FieldComponent` 中通过 `inject()` 获取对应的数据,进行读写。 + +``` ts +/** + * 通过 provide 输入数据 + */ +const useFormDataProvide = (formData: FormData): FormInjectKey => { + const key: FormInjectKey = Symbol('formData') + provide(key, formData) + + return key +} + +/** + * 通过 inject 获取数据 + */ +const useFormData = (key: FormInjectKey): FormData => inject<FormData>(key)! +``` + +由于需要支持 字段为对象/数组时产生的 多层级数据结构,还需要考虑 `FieldComponent` 对 `FormData.a.b` 的 +深层数据的读写。 + +可以通过实现 `dotPath`, 通过 `FormData['a.b']` 的形式来读写 `FormData.a.b`,这样 `FieldComponent` +只需要知道 `a.b` 的 `dotPath` 字段路径即可配合 `inject()` 获取的表单数据进行读写。 + +``` ts +const useDotPath = <T = any>(model: FormData, dotKey: ComputedRef<string>) => { + const binding = computed<T>({ + set(data) { + setDotPath(model.value, dotKey.value, data) + }, + get() { + return getDotPath(model.value, dotKey.value) + }, + }) + + return binding +} +``` + +## 技术实现 + +在 [formative](https://github.com/pengzhanbo/formative) 仓库中, 通过本方案实现了一个 配置化生成表单的库。 + +- `src/components/Formative.tsx` 文件作为表单根组件。 +- `src/components/Field.tsx` 文件作为根据表单字段动态选择对应组件进行表单字段渲染。 +- `src/components/Group.tsx` 文件实现了对表单字段进行分组。 +- `src/components/[other].tsx` 其他文件实现了 各种表单字段组件。 + +有兴趣了解细节的,可以阅读 [formative 源码](https://github.com/pengzhanbo/formative), +我在关键位置进行了相关的代码注释说明。 + +同时,你可以直接拉取 源码,在本地进行运行。并授权代码使用。 diff --git a/docs/1.前端/2.工具/Jenkinss使用.md b/docs/1.前端/2.工具/Jenkinss使用.md index dad69fdb..bf7bd8f7 100644 --- a/docs/1.前端/2.工具/Jenkinss使用.md +++ b/docs/1.前端/2.工具/Jenkinss使用.md @@ -2,12 +2,10 @@ title: Jenkins 使用 lang: zh-CN createTime: 2018/09/16 11:15:27 -permalink: /article/bmtl5ah4 +permalink: /article/bmtl5ah4/ author: pengzhanbo tags: - 工具 -top: false -type: null --- [Jenkins](https://jenkins.io/) 是一款功能强大的应用程序,允许持续集成和持续交付项目。这里记录一些 Jenkins 使用的方法。 diff --git a/docs/1.前端/2.工具/NPMBinary镜像配置.md b/docs/1.前端/2.工具/NPMBinary镜像配置.md new file mode 100644 index 00000000..5c15240b --- /dev/null +++ b/docs/1.前端/2.工具/NPMBinary镜像配置.md @@ -0,0 +1,35 @@ +--- +title: NPM Binary 镜像配置 +createTime: 2021/03/15 08:54:32 +author: pengzhanbo +tags: + - 工具 +permalink: /article/hsgdhlah/ +--- + +在 NPM 安装 Electron, Puppeteer 等包时,他们会通过 `postinstall` 脚本下载对应的二进制文件。因为一些不得而知的原因这个过程在某些网络下可能会很慢或不可用。你可以复制以下配置至 `.bashrc` 或 `.zshrc` 中,使用 [npmmirror.com](https://npmmirror.com) 提供的二进制镜像。 + +<!-- more --> + +数据来源于 `binary-mirror-config`。 + +```sh +# === NPM BINRAY CHINA === +# https://github.com/cnpm/binary-mirror-config/blob/main/package.json#L48 +export NODEJS_ORG_MIRROR="https://cdn.npmmirror.com/binaries/node" +export NVM_NODEJS_ORG_MIRROR="https://cdn.npmmirror.com/binaries/node" +export PHANTOMJS_CDNURL="https://cdn.npmmirror.com/binaries/phantomjs" +export CHROMEDRIVER_CDNURL="https://cdn.npmmirror.com/binaries/chromedriver" +export OPERADRIVER_CDNURL="https://cdn.npmmirror.com/binaries/operadriver" +export ELECTRON_MIRROR="https://cdn.npmmirror.com/binaries/electron/" +export ELECTRON_BUILDER_BINARIES_MIRROR="https://cdn.npmmirror.com/binaries/electron-builder-binaries/" +export SASS_BINARY_SITE="https://cdn.npmmirror.com/binaries/node-sass" +export SWC_BINARY_SITE="https://cdn.npmmirror.com/binaries/node-swc" +export NWJS_URLBASE="https://cdn.npmmirror.com/binaries/nwjs/v" +export PUPPETEER_DOWNLOAD_HOST="https://cdn.npmmirror.com/binaries" +export SENTRYCLI_CDNURL="https://cdn.npmmirror.com/binaries/sentry-cli" +export SAUCECTL_INSTALL_BINARY_MIRROR="https://cdn.npmmirror.com/binaries/saucectl" +export npm_config_sharp_binary_host="https://cdn.npmmirror.com/binaries/sharp" +export npm_config_sharp_libvips_binary_host="https://cdn.npmmirror.com/binaries/sharp-libvips" +export npm_config_robotjs_binary_host="https://cdn.npmmirror.com/binaries/robotj" +``` diff --git a/docs/1.前端/2.工具/caniuse.md b/docs/1.前端/2.工具/caniuse.md index 17a17fad..48ff7083 100644 --- a/docs/1.前端/2.工具/caniuse.md +++ b/docs/1.前端/2.工具/caniuse.md @@ -1,13 +1,12 @@ --- title: caniuse -createTime: 2021/02/07 06:41:12 -permalink: /article/h4z91gyz +createTime: 2020/11/01 06:41:12 +permalink: /article/h4z91gyz/ author: pengzhanbo -top: false -type: null +article: false --- ### 工具 将caniuse 的feature 结果,以图片或者iframe的形式,嵌入到站点。 -[https://caniuse.bitsofco.de/](https://caniuse.bitsofco.de/) \ No newline at end of file +[https://caniuse.bitsofco.de/](https://caniuse.bitsofco.de/) diff --git a/docs/1.前端/2.工具/git工作流实践.md b/docs/1.前端/2.工具/git工作流实践.md new file mode 100644 index 00000000..121b2693 --- /dev/null +++ b/docs/1.前端/2.工具/git工作流实践.md @@ -0,0 +1,136 @@ +--- +title: git工作流实践 +createTime: 2022/04/18 12:26:46 +author: pengzhanbo +permalink: /article/cjeo0sia/ +tags: + - 工具 +banner: https://assets.processon.com/chart_image/6251bfce1efad407891be6c8.png +--- + +这是一篇在我个人工作实践中,在我参与的,负责的项目、团队协作中,逐步调整,适合于一些实际场景的 git 工作流实践。 + +众所周知,在软件开发中, git 是目前使用最广泛的 软件版本管理工具,它足够高效,足够安全,也足够灵活, +对于团队协作和软件管理提供了很大的帮助。 + +而一个良好的合适的 分支管理方案,可以更好的帮助我们通过 git 进行 软件版本管理。 + +在过去, git-flow 是一个很流行的 分支管理方案。对于多人协作,中大型项目,提供了一个较为满意的解决方案。 + +但在我过去的实践中,逐渐感受到 git-flow 对于我来说还是太过于繁杂了,虽然在事实上满足了 我对于项目的软件版本管理, +但认为还是可以做一些简化,调整 分支管理策略,以更好的适配实际的开发工作。 + +## 场景 + +试想一下,在我们实际的软件开发过程中,迭代一个软件的版本,正常来说是: + +``` +需求评审 -> 需求确认 -> 开发阶段 -> +测试环境测试 -> 预生产发布验证 -> 生产环境发布验证 -> 发布完成 +``` + +### 从开发到发布 + +在这个过程中,如果在 测试环境发现了 bug,需要重新回归到 开发阶段进行修复, +同样的,在预生产发布验证环节发现了问题,也需要重新回归到 开发阶段修复后,重新测试和发布预生产。 + +而如果 生产环境发布验证 出现了问题, 需要紧急回滚到上一个版本,并重新回到开发阶段修复,测试,预生产验证,再生产发布。 + +### 需求明确 or 变更 + +虽然我们一直强调,版本迭代进入开发后,这个版本的需求应该是明确的。 + +然而,这仅仅只是理想情况下,实际过程中经常会遇到 需求变更,甚至是 添加新的功能,删除功能等。 +这种变更,还很难控制会发生在开发阶段还是测试阶段。 + +也许我们会吐槽甚至抱怨这样的容易变更需求的项目管理很糟糕,很不专业。但是,这也是确确实实存在的场景, +即使再成熟的团队,也会不可避免的遇到这种问题。 + +然而需求变更也不代表着一定是上面这种场景。 + +### 周期性版本发布,需求池 + +有些项目可能相对来说比较成熟,或者采用了不同的版本迭代方式。 + +周期性版本发布指,采用某个固定的周期内,仅会也一定会发布一个版本,如 每两周发布一个版本。 +那么在这种模式下,每个版本上线哪些功能,上线多少功能,实际上是以各个功能的开发进度,和进入到当前周期后, +明确下来的版本计划再决定的。 + +将产品 明确划分为一个个需求,建立一个需求池,并指定了每个需求的按时间的线性迭代预期计划, +在预期的未来的周期性的版本发布中,会上线哪些需求功能。 + +在这种场景下,我们不可能把需求都集中在某个分支上进行开发,仅有的一个 develop分支也很难满足所有的 +开发合并和测试。 + + +### 开发人员对于 git的掌握 + +很多时候,对于工具能够使用到什么程度,对于项目能够有多少帮助,其实不在于 工具有多优秀,而是在于团队成员 +对于工具的平均掌握程度,已经是否有成熟的规范化的操作流程。 + +早期我认为 成员对于 git 的掌握是大差不差的,只要说明一些操作流程即可,未加以限制和规范 + +然而,这会也给项目带来了潜在的风险:主要分支可能会被误操作污染,多个功能直接在同一个分支开发等等。 + +而为了解决这些问题,需要建立一套足够完善,同时低复杂度的操作规范,并对人员和分支加以权限控制。 + + +## 分支管理实践 + +在以上的场景中,逐渐摸索出了一套合适的分支管理方案: + +- `master` 分支: 主分支,正式版本的代码提交记录。 + + 永远不会在上面做任何改动提交,也仅接受来自 `release` 分支的合并请求,合并后打上版本tag。 + +- `release` 分支:发布分支,用于发布版本到预生产和生产环境,发布完成后合并到 master分支。 + + 永远不会咋上面做任何改动提交,也仅接受来自 prerelease 分支的合并请求。 + +- `prerelease/*` 分支组: 预发布分支,根据版本号创建新的分支。 + + 仅合并当前版本关联的 `feature/*` 分支,用于合并开发完成的需求,进入到版本测试阶段,发布到测试环境。 + 不会或者尽可能少的在上面做任何改动提交。 + +- `feature/*` 分支组: 功能开发分支(包括hotfix),从 master 分支拉取创建的分支, + + 每个分支仅针对某一个单一的业务或者功能,所有的改动都应该在 feature 分支上进行。 + 仅能合并到 prerelease 分支。 master有更新后需要及时拉取合并同步。 + + +流程图: +![git-work-flow](https://assets.processon.com/chart_image/6251bfce1efad407891be6c8.png) + +可以看出,整个方案只有四条主要的分支,且不同功能分支到其他分支都是单向的。 + +这样的好处是足够的简单,足够的好理解,也保证了一定的灵活性。 + +删除了 develop分支的原因是,单一的develop分支并不能很好的满足 需求变更后导致的 develop分支无效, +选择使用 prerelease 分支组作为替代,可以灵活的根据版本规划创建分支,即使发生需求变更,也可以灵活的直接抛弃 +当前已创建的分支,重新新建一条 prerelease分支再次从feature分支合并代码。 + +从 develop 改名为 prerelease 也是因为,功能分支开发完后并不是马上合并的,而是根据迭代计划再合并的,理解起来就是 +预期上线的功能,即 prerelease。 + +从分支的行为上看, master分支和 release分支 似乎可以在简化仅保留一条。但这里是考虑到 如果有发布回滚操作,如果 +都在 master 分支上进行,那么master分支的操作记录看起来就不够的干净,简洁,而把发布、回滚等策略都放到了 release分支 +,而 master仅保留干净的版本历史,那么会更加的友好,便于维护。 + +在这个方案中,最好是配合上 git分支的权限控制,对 master分支、release分支进行保护,确保这两个分支仅接受来自对应 +分支的合并请求。 + +分支合并,选择 `merge` 还是 `rebase`,这个需要对 commit记录有何要求去考量。 +如果需要保证所有提交记录都可追踪,建议使用 merge,如果希望 提交记录线性、整洁,建议使用 rebase。 + +同时,feature分支 合并到 prerelease 分支,最好是通过 pull requests 的操作模式,在进入测试阶段前,接受来自其他 +有用审查权限的开发人员的code review。 + +::: warning 说明 +该实践方案仅是我过去在我的工作实践中总结的,并在团队内部经历过超过2年的验证和调整所得出的,适合于当时团队的实践方案。 + +是否与您的团队或所在的团队契合,还需要重新考量。 + +分支管理方案 需要从实际的情况触发考虑,包括团队人数,产品规模等等。 + +没有最好的方案,只有合适自己的方案。 +::: diff --git a/docs/1.前端/2.工具/vsCode插件推荐.md b/docs/1.前端/2.工具/vsCode插件推荐.md index 37900877..c5c75a20 100644 --- a/docs/1.前端/2.工具/vsCode插件推荐.md +++ b/docs/1.前端/2.工具/vsCode插件推荐.md @@ -2,12 +2,10 @@ title: VSCode 常用插件推荐 lang: zh-CN createTime: 2018/12/29 11:15:27 -permalink: /article/ofp08jd8 +permalink: /article/ofp08jd8/ author: pengzhanbo tags: - VSCode -top: false -type: null --- `VS Code` 作为我现在工作中最常用的编辑器,也是我十分喜欢的编辑器。它强大的功能和插件系统,对我的工作提供了很多帮助和支持。将我在工作中经常使用的插件,推荐给大家。 @@ -126,3 +124,5 @@ type: null 2. [minapp](https://github.com/wx-minapp/minapp-vscode) 微信小程序 支持。 + + diff --git a/docs/1.前端/2.工具/小徽章制作.md b/docs/1.前端/2.工具/小徽章制作.md new file mode 100644 index 00000000..2099625b --- /dev/null +++ b/docs/1.前端/2.工具/小徽章制作.md @@ -0,0 +1,36 @@ +--- +title: 小徽章制作 +createTime: 2021/07/20 04:37:25 +author: pengzhanbo +permalink: /article/qrfeqp1q/ +--- + +用于制作 小徽章的在线网站 或项目 + +- [https://shields.io/](https://shields.io/) +- [https://badgen.net/](https://badgen.net/) +- [https://forthebadge.com/](https://forthebadge.com/) +- [https://badge.fury.io/](https://badge.fury.io/) +- [https://github.com/boennemann/badges](https://github.com/boennemann/badges) + +## example + +``` md +![npm version](https://badge.fury.io/js/@vuepress-plume%2Fvuepress-theme-plume.svg) + +![npm version](https://badge.fury.io/js/@vuepress-plume%2Fvuepress-theme-plume.svg) + +![github version](https://badge.fury.io/gh/pengzhanbo%2Fvuepress-theme-plume.svg) + +![release](https://badgen.net/github/release/pengzhanbo/vuepress-theme-plume/) + +![npm](https://img.shields.io/npm/dw/@vuepress-plume/vuepress-theme-plume?style=plastic) + +``` +![npm version](https://badge.fury.io/js/@vuepress-plume%2Fvuepress-theme-plume.svg) + +![github version](https://badge.fury.io/gh/pengzhanbo%2Fvuepress-theme-plume.svg) + +![release](https://badgen.net/github/release/pengzhanbo/vuepress-theme-plume/) + +![npm](https://img.shields.io/npm/dw/@vuepress-plume/vuepress-theme-plume?style=plastic) diff --git a/docs/1.前端/2.工具/有用的工具列表.md b/docs/1.前端/2.工具/有用的工具列表.md new file mode 100644 index 00000000..200b76ce --- /dev/null +++ b/docs/1.前端/2.工具/有用的工具列表.md @@ -0,0 +1,108 @@ +--- +title: 有用的工具列表 +createTime: 2021/02/10 09:55:09 +author: pengzhanbo +permalink: /article/xb4woxjg/ +sticky: 10 +--- + +## 浏览器插件 + +- [Vue.js devtools](https://chrome.google.com/webstore/detail/vuejs-devtools/nhdogjmejiglipccpnnnanhbledajbpd?) 顾名思义,非常有用的浏览器 vue开发调试插件 +- [React Developer Tools](https://chrome.google.com/webstore/detail/react-developer-tools/fmkadmapgofadopljbjfkapdkoienihi) React 开发调试插件 +- [Octotree - GitHub code tree](https://chrome.google.com/webstore/detail/octotree-github-code-tree/bkhaagjahfmjljalopjnoealnfndnagc) 对github仓库的文件tree生成侧边栏,方便在线查阅浏览/跳转 +- [XPath Helper](https://chrome.google.com/webstore/detail/xpath-helper/hgimnogjllphhhkhlmebbmlgjoejdpjl) 提取当前网站选中的 DOM 元素的 XPath,做埋点测试之类时有用 + + +## cli开发 + +- [commander](https://www.npmjs.com/package/commander) 完整的命令行解决方案 +- [cac](https://www.npmjs.com/package/cac) 轻量级的用于构建cli工具的解决方案 +---- +- [minimist](https://www.npmjs.com/package/minimist) 命令行参数解析工具 +- [yargs](https://www.npmjs.com/package/yargs) 命令行参数解析工具 +---- +- [Inquirer](https://www.npmjs.com/package/inquirer) 交互式命令行工具 +- [prompt](https://www.npmjs.com/package/prompt) 命令行 对话工具 +---- +- [shelljs](https://www.npmjs.com/package/shelljs) shell调用工具 +- [execa](https://www.npmjs.com/package/execa) shell 调用工具 +- [chalk](https://www.npmjs.com/package/chalk) node终端输出美化工具 +- [ora](https://www.npmjs.com/package/ora) 终端 loading 工具 +- [chokidar](https://www.npmjs.com/package/chokidar) 文件监听工具 + +- [is-ci](https://www.npmjs.com/package/is-ci) 检查当前环境是否是集成环境 + +## Http server + +- [express](http://expressjs.com/) +- [connect](https://github.com/senchalabs/connect) +- [koa](https://koajs.com/) +- [fastify](https://www.fastify.io/) + +## Server Framework + +- [Nestjs](https://nestjs.com/) 类Spring boot的 Node端开发框架 +- [Next.js](https://nextjs.org/) React 应用开发框架 +- [Nuxt.js](https://nuxtjs.org/) Vue 应用开发框架 +- [Think.js](https://thinkjs.org/) Node端开发框架 + +- [Egg.js](https://www.eggjs.org/index) 阿里开源的Node端开发框架 + +## VSCode 插件 + +### 皮肤 + +- [One Dark Pro](https://marketplace.visualstudio.com/items?itemName=zhuangtongfa.Material-theme) 个人觉得非常耐看,好用,舒服的一个皮肤。 +- [Material Icon Theme](https://marketplace.visualstudio.com/items?itemName=PKief.material-icon-theme) 非常全面又好看的文件图标主题 + +### 辅助开发 +- [IntelliCode](https://marketplace.visualstudio.com/items?itemName=VisualStudioExptTeam.vscodeintellicode) 辅助代码提示 +- [Code Spell Checker](https://marketplace.visualstudio.com/items?itemName=streetsidesoftware.code-spell-checker) 拼写检查插件 +- [Error Lens](https://marketplace.visualstudio.com/items?itemName=usernamehw.errorlens) 用更友好更直观的方式,将错误信息显示出来 +- [Better Comments](https://marketplace.visualstudio.com/items?itemName=aaron-bond.better-comments) 更加友好的注释高亮 +- [Bracket Pair Colorizer](https://marketplace.visualstudio.com/items?itemName=CoenraadS.bracket-pair-colorizer) 代码缩进高亮 +- [Import Cost](https://marketplace.visualstudio.com/items?itemName=wix.vscode-import-cost) 显示包体积 +- [Todo Tree](https://marketplace.visualstudio.com/items?itemName=Gruntfuggly.todo-tree) TODO注释高亮 +- [indent-rainbow](https://marketplace.visualstudio.com/items?itemName=oderwat.indent-rainbow) 缩进高亮标识 +- [Path Intellisense](https://marketplace.visualstudio.com/items?itemName=christian-kohler.path-intellisense) 文件路径提示 +- [TypeScript Hero](https://marketplace.visualstudio.com/items?itemName=rbbit.typescript-hero) typescript 辅助开发工具 +--- +- [any-rule](https://marketplace.visualstudio.com/items?itemName=russell.any-rule) 正则表达式大全 +--- +- [Rest Client](https://marketplace.visualstudio.com/items?itemName=humao.rest-client) 类 Postman 的 Rest工具 + + +## 测试工具 + +### assertion +- [chai](https://www.npmjs.com/package/chai) +- [should](https://www.npmjs.com/package/should) + +### unit +- [jest](https://www.npmjs.com/package/jest) +- [ava](https://www.npmjs.com/package/ava) +- [mocha](https://www.npmjs.com/package/mocha) +- [karma](https://www.npmjs.com/package/karma) +- [tape](https://www.npmjs.com/package/tape) +- [@vue/test-utils](https://www.npmjs.com/package/@vue/test-utils) + +### 2e2 +- [nightwatch](https://www.npmjs.com/package/nightwatch) +- [cypress](https://www.npmjs.com/package/cypress) + + +## GIT相关 + +- [@commitlint/cli](https://www.npmjs.com/package/@commitlint/cli) +- [@commitlint/config-conventional](https://www.npmjs.com/package/@commitlint/config-conventional) +- [commitizen](https://www.npmjs.com/package/commitizen) +- [conventional-changelog-cli](https://www.npmjs.com/package/conventional-changelog-cli) +- [cz-conventional-changelog](https://www.npmjs.com/package/cz-conventional-changelog) +- [husky](https://www.npmjs.com/package/husky) +- [lint-staged](https://www.npmjs.com/package/lint-staged) + +## 其他 + +- [Slidev](https://github.com/slidevjs/slidev) 为开发者打造的演示文稿工具 +- [loupe](http://latentflip.com/loupe/) 代码执行流程可视化 diff --git a/docs/1.前端/3.Vue/Vue组件间通信.md b/docs/1.前端/3.Vue/Vue组件间通信.md index 9203fdc4..dd8865cf 100644 --- a/docs/1.前端/3.Vue/Vue组件间通信.md +++ b/docs/1.前端/3.Vue/Vue组件间通信.md @@ -4,10 +4,8 @@ lang: zh-CN tags: - vue createTime: 2018/07/20 11:15:27 -permalink: /article/iezlvhvg +permalink: /article/iezlvhvg/ author: pengzhanbo -top: false -type: null --- 在我们在进行基于[Vue](https://cn.vuejs.org/)的项目开发时,组件间的数据通信,是我们必须考虑的。 diff --git a/docs/1.前端/5.Node/单仓库导出ES和CJS.md b/docs/1.前端/5.Node/单仓库导出ES和CJS.md new file mode 100644 index 00000000..6e6dbb88 --- /dev/null +++ b/docs/1.前端/5.Node/单仓库导出ES和CJS.md @@ -0,0 +1,211 @@ +--- +title: 单仓库实现同时导出esm、cjs +createTime: 2022/04/06 08:33:04 +author: pengzhanbo +permalink: /article/exports-esm-and-cjs/ +--- + +在开发一些公共模块作为一个独立仓库时,有时候可能会在一个使用 es 的项目中通过 `import` 导入, +有可能在一个 cjs 项目中通过 `require` 导入。 + +如何实现单个仓库能够同时被 cjs 和 esm 项目导入呢? + +<!-- more --> + +## 为什么这么做? + +在过去的时间里,JavaScript 并没有一套标准的模块化系统,并且在过去的时间里,逐渐发展出了各种模块化解决方案, +其中最主流的有两种模块化方案: + +- `CommonJs`: 即`cjs`,通过 `require('package')` 导出,`module.exports` 导入。 + 这套模块化系统应用与在`NodeJs` 和 `NPM packages`。 + + ```js + // in cjs + const _ = require('lodash') + console.log(`assignIn: ` _.assignIn({ b: '2'}, { a: '1' })) + // { a: '1', b: '2' } + ``` + +- `Ecmascript modules`: 即`esm`,在2015年,`esm` 最终确定为标准模块化系统,浏览器以及各个社区开始逐渐 + 迁移并支持`esm`。 + + ```js + import { assignIn } from 'lodash' + console.log(`assignIn: ` assignIn({ b: '2'}, { a: '1' })) + // { a: '1', b: '2' } + ``` + + `ESM`使用 `named exports`,能够更好的支持静态分析,对各种打包工具有利于做`tree-shaking`, + 而且浏览器原生支持,作为一个标准,代表的是JavaScript的未来。 + + 同时,在`NodeJs` 的 `v12.22.0`、`v14.17.0`版本,开始实验性的支持`ESM`,并在`16.0.0`版本开始正式支持`ESM`。 + + +::: note +- ESM - [ECMAScrip modules](https://nodejs.org/api/esm.html) +- CJS - [CommonJs](https://nodejs.org/api/modules.html#modules-commonjs-modules) +::: + +目前有很多包仅支持 `CJS` 或者 `ESM` 格式。 但同时,也有越来越多的包推荐并仅支持导出 `ESM` 格式。 + +但是相对来说,就目前而言,作为一个库,仅支持`ESM` 格式还是过于激进了。即使在 `NodeJs v16`已开始正式支持`ESM`, +但是整个社区的迁移还是需要大量的时间成本和人力成本的,如果某个版本破坏性的从`CJS`支持迁移到`ESM`, +那么可能导致一系列问题。 + +所以,如果一个库,能够同时支持`ESM`以及`CJS`,是一种相对来说更为安全的迁移方案。 + +## 共存问题 + +我们知道,`Nodejs` 能够很好的同时支持 `ESM` 和 `CJS` 进行工作,但是,有一个最主要的问题是,不能在一个 `CJS` 中 +导入`ESM`,这时候会抛出一个错误: +```js +// cjs package +const pkg = require('esm-only-package') +``` +``` +Error [ERR_REQUIRE_ESM]: require() of ES Module esm-only-package not supported. +``` + +因为`ESM` 模块本质上是一个异步模块,所以不能用 `require()` 方法同步的导入一个异步的模块。 +但是这并不意味着完全不能在 `CJS` 模块中使用`ESM` 模块,我们可以使用 动态 `import()` 的方式,来异步的导入`ESM` 模块。 +`import()` 会返回一个 `Promise`: + +```js +// CJS +const { default: pkg } = await import ('esm-only-package') +``` + +但是,这并不是一个令人满意的解决方案,它与我们日常使用的模块导入方式来说,显得有点笨拙,不符合一般使用习惯, +我们还是更期望能够符合一般习惯的导入方式: + +```js +// ESM +import { named } from 'esm-package' +import cjs from 'cjs-package' +``` + +## 如何做? + +### package.json + +在现在的稳定版本的`NodeJs` 中,已经支持同时在一个包中导出两种不同的格式。 +在`package.json` 文件中,有一个`exports` 字段,提供给我们有条件的导出不同格式。 + +``` js +{ + "name": "package", + "exports": { + ".": { + "require": "./index.js", + "import": "./index.mjs" + } + } +} +``` + +这一段声明描述了, 当进行导入包的默认模块时,如果是通过 `require('package')` 进行导入,那么引入的是 `./index.js` 文件,如果是通过`import pkg from 'package'`进行导入,那么引入的是 `./index.mjs` 文件。 + +`Nodejs` 会根据当前运行环境,选择合适的导入方式将包进行导入。 + +所以我们可以借助这一特性,来完成我们单仓库支持两个格式的第一步。 + +然后,下一个要解决的,就是如何构建两个格式的导出文件。 + +### Building + +我们当然不可能为了同时支持`CJS`和 `ESM`,而编写两份代码。 + +但我们可以借助一些构建打包工具,来生成`ESM`和`CJS`代码。 + +通常情况下,我们可能会使用 `rollup` 来构建打包我们的模块。 +或者也可以使用 `tsup` 来构建。 + +#### rollup + +当我们会选择 `rollup` 来构建一个库时,可能配置如下: + +```js +// rollup.config.js +export default { + input: 'src/index.js', + output: { + file: './dist/index.js', + } +} +``` + +由于`rollup` 是支持多配置打包的,所以我们可以使用多配置的方式,同时打包输出两种格式的文件: +```js +// rollup.config.js +export default [ + { + input: 'src/index.js', + output: { + file: './dist/index.js', + format: 'cjs', + } + }, + { + input: 'src/index.js', + output: { + file: './dist/index.mjs', + format: 'es', + } + } +] +``` + + +#### tsup + +`tsup` 是一个面向 `TypeScript` 的打包工具,基于 `esbuild`, 可以很方便的将我们的库打包成多种模式进行输出: + +`tsup` 可以支持零配置,直接使用命令行即可输出两种格式 + +``` sh +tsup src/index.ts --format esm,cjs +``` + +执行完成后,将会得到两个文件:`cjs` 格式文件`dist/index.js` 和 `esm`格式文件`dist/index.mjs` 。 + + +使用构建工具构建完成后,接下来就是完善 `package.json`, + +建议在使用 `type` 字段声明为 `module`, 来声明当前库时一个标准的 esm 库,以及添加 `main`,`module`,`exports`字段, +以便向下兼容: + +```json +{ + "name": "my-package", + "type": "module", + "main": "./dist/index.js", + "module": "./dist/index.mjs", + "exports": { + ".": { + "require": "./dist/index.js", + "import": "./dist/index.mjs" + } + }, + "types": "./dist/index.d.ts", + "files": ["dist"] +} +``` + +最后,你的 `CJS` 项目中,或者 `ESM` 项目中,均可以根据环境要求,导入这个包。 + +```js +// cjs +const pkg = require('my-package') +``` + +```js +// esm +import pkg from 'my-package' +``` + +## 总结 + +虽然 `Nodejs` 从 `v14.22.0` 版本开始试验性的支持 `esm` ,并且到 `v16` 版本,正式支持 `esm`。 +但将库升级到仅支持`esm` 还是一个比较激进的做法,建议从相对安全的 双格式支持 开始迁移,在合适的时机,过渡到仅支持`esm`。 + diff --git a/docs/1.前端/5.Node/在node项目中使用esm.md b/docs/1.前端/5.Node/在node项目中使用esm.md new file mode 100644 index 00000000..48676167 --- /dev/null +++ b/docs/1.前端/5.Node/在node项目中使用esm.md @@ -0,0 +1,149 @@ +--- +title: 在NodeJs项目中使用ECMAScript module +createTime: 2022/06/17 02:04:57 +author: pengzhanbo +permalink: /article/7jzjudus/ +--- + +随着 `Nodejs v16` 成为长期稳定支持的版本,`ESM` 也随之成为 `NodeJs` 正式支持的标准化模块系统,这允许我们通过 +`ESM` 来开发我们的 `NodeJs` 项目,并在项目中通过`ESM` 来导入其他的`ESM`包。 + +<!-- more --> + +## 创建项目 + +我们以新建一个 NodeJs 项目为例, 它有如下的结构: +```sh +./my-esm-package +├── lib +│ ├── resolve.js +│ └── index.js +└── package.json +``` + +这个项目的功能是导出一个 resolve 方法,是 `path.resolve` 的封装实现。 + +::: code-tabs +@tab lib/index.js +```js +export * from './resolve.js' + +``` + +@tab lib/resolve.js +```js +import path from 'path' + +export const resolve = (...arg) => path.resolve(...arg) +``` +::: + +## package.json + +在 `package.json` 中,我们需要进行以下声明: + +- 声明 `type` 字段值为 `module` + + 这个字段声明了你的包将作为一个 `ECMAScript module` 被`NodeJs` 加载并解析,并允许使用`.mjs`格式的文件。 + +- 声明 `exports` 字段 + + 该字段描述了 项目如何导出模块给到其他包使用。 + + - 默认导出 + + ::: code-tabs + @tab package.json + ```json + { + "exports": "./lib/index.js" + } + ``` + ::: + + 即当使用`import { resolve } from 'my-esm-package'`时,默认引入的文件是 `lib/index.js`。 + + - 导出多个模块 + + ::: code-tabs + @tab package.json + ```json + { + "exports": { + ".": "./lib/index.js", + "resolve": "./lib/resolve.js" + } + } + ``` + ::: + + 声明了导出了两种模块:一个是默认导出,使用`"."` 作为key;一个是具名导出。 + + 当使用`import { resolve } from 'my-esm-package'`时,默认引入的文件是 `lib/index.js`。 + + 当使用`import { resolve } from 'my-esm-package/resolve'` 时,引入的文件是 `lib/resolve.js`。 + + - `exports` 还支持其他形式的值,这里暂不赘述。 + +- 声明 `engines` 字段 + + 由于 `Nodejs` 并不是全版本支持`esm`的,而是从`v14.16.0`版本开始试验性的支持,并到了`v16`版本才作为正式支持, + 且当前`v16`版本作为目前的长期稳定支持的版本。这个项目运行环境的`NodeJs` 版本,最低应该推荐使用 `v16` 以上的版本。 + 即它的值应该为 `{ "node": ">=16" }` + +到这里,这个项目的`package.json` 文件,包含以下内容: + +::: code-tabs +@tab package.json +```json +{ + "name": "my-esm-package", + "description": "My first esm package.", + "type": "module", + "exports": { + ".": "./lib/index.js", + "resolve": "./lib/resolve.js" + }, + "engines": { + "node": ">=16" + } +} +``` +::: + +## 编写项目代码 + +1. 由于是一个 `esm` 项目,所以理所当然的不能项目中使用 `require()`/`module.exports` 来导入导出模块。 +而是应该全部使用`import`/`export` 的方式来导入导出模块。 + +2. 不需要在项目代码中 使用 `use strict`。 + +3. 由于 `esm` 项目中,`NodeJs` 不再支持 `__dirname`/`__filename`,所以有相关场景需要使用时,需要使用其他的方式来实现相同功能: + ```js + import { dirname, basename } from 'path' + import { fileURLToPath } from 'url' + + const _dirname = typeof __dirname !== 'undefined' + ? __dirname + : dirname(fileURLToPath(import.meta.url)) + + const _filename = typeof __filename !== 'undefined' + ? __filename + : basename(fileURLToPath(import.meta.url)) + ``` +## TypeScript + +如果在项目中使用了 `TypeScript`,那么除了需要遵循以上的内容,还需要在 `tsconfig.json` 配置文件中补充以下配置: + +```json +{ + "module": "node16", + "moduleResolution": "node16" +} +``` + +并且,应该将 `.ts` 文件,编译为 `.js` 文件,`package.json` 配置的 `exports` 导出的,是编译后的 `.js` 文件。 + +## 最后 + +当完成了以上步骤,就可以得到一个`NodeJs ESM` 项目。它也只能在另一个支持 `esm` 的项目中使用。 diff --git a/docs/1.前端/6.JavaScript/2.进阶/函数参数按值传递.md b/docs/1.前端/6.JavaScript/2.进阶/函数参数按值传递.md new file mode 100644 index 00000000..0523006c --- /dev/null +++ b/docs/1.前端/6.JavaScript/2.进阶/函数参数按值传递.md @@ -0,0 +1,108 @@ +--- +title: JavaScript进阶(五)— 函数参数按值传递 +createTime: 2020/02/12 11:27:54 +author: pengzhanbo +permalink: /article/m4a92nl5/ +--- + +我们知道,在 `ECMAScrip` 中, 函数的参数是 **按值传递** 的。 + +那么怎么理解 **按值传递** ? + +简单来说, **把函数外部的值复制给函数内部的参数**,即 **把值从一个变量复制到另一个变量**。 + +那么也就是说,在函数内部,修改函数参数的值,不会改变外部变量的值。 + +我们来看一个例子:2 + +**示例1** +```js + +var a = 1 +function foo(arg) { + arg = 2 + console.log(arg) +} +foo(a) // 2 +console.log(a) // 1 +``` + +可以看出,外部变量`a`作为 函数 `foo` 的执行时参数值, 在函数内部修改传入的参数值进行修改, +函数执行后,并不会对外部变量`a` 发生修改。 + +这个例子确实说明了函数参数是按值传递的。 + +但是再来看另一个例子: + +**示例2** +```js +var obj1 = { + a: 1 +} +function foo(arg) { + arg.a = 2 + console.log(arg) +} +foo(obj1) // { a: 2 } +console.log(obj1) // { a: 2 } + +var obj2 = { + a: 1 +} +function bar(arg) { + arg = 2 + console.log(arg) +} +bar(obj2) // 2 +console.log(obj2) // { a: 1 } +``` + +在这个例子中, 函数`foo` 执行完后, 打印的 `obj1` 值发生了变化,说明函数`foo` 内部修改了外部变量`obj1`, +为什么会发生修改?而在 函数`bar` 执行后,`obj2` 值保持不变,这又是为什么? 函数参数是否真的是 **按值传递**? + +那么该如何理解 `函数参数是按值传递的`? + +在理解这个之前,我们首先需要知道,`JavaScript` 的数据类型,以及不同数据类型的存储方式。 + +## 数据类型及其存储方式 + +我们知道, 在 `JavaScript` 中, 有两种 数据类型,分别是:**(1)基本数据类型**和 **(2)引用数据类型**, + +- 基本数据类型:值 直接保存在 **栈(stack)** 中。 + ```js + let a = 1 + let b = a + a = 2 + console.log(a, b) // 2 1 + ``` + 基本类型在 **栈** 中的赋值变动如下: + ::: center + ![function-value-stack](/images/func-value-stack.png){ style=width:500px; } + ::: + +- 引用数据类型:值 保存在 **堆(heap)** 中, 并在 **栈(stack)** 中保存 值 在 **堆(heap)** 中的内存地址。 + + ```js + let a = { name: 'Mark' } + let b = a + b.name = 'John' + console.log(a) // { name: 'John' } + ``` + 引用类型在 **栈** 和 **堆** 中的复制变动如下: + ::: center + ![function-value-stack](/images/func-value-heap.png){ style=width:680px; } + ::: + +## 按值传递 + +我们从 数据类型来理解 `按值传递`, 那么可以发现, **传递** 的值, 是指在 **栈(stack)** 中保存的值。 + +即, 无论 **参数值** 是 基本数据类型还是引用数据类型, **传递** 的是 **栈(stack)** 中的值。 + +- 对于基本数据类型, 函数内部修改参数的值,实际上是修改的是 函数参数重新在 **栈(stack)** 中的内存片段保存的值。 + +- 对于引用数据类型, 函数参数 传递是的 引用类型在 **栈(stack)** 中的内存地址: + - 如果直接修改参数的值,函数参数在 **栈(stack)** 中的内存片段保存的内存地址被覆盖。 + - 如果修改 参数对象的属性值,修改的是根据 函数参数在 **栈(stack)** 中的内存片段保存的内存地址对应的在 **堆(heap)** 中的值。 + +所以回头重新看 **示例1** 和 **示例2**, 均正确表述了 函数的参数是 **按值传递** 的。 diff --git a/docs/1.前端/6.JavaScript/2.进阶/原型到原型链.md b/docs/1.前端/6.JavaScript/2.进阶/原型到原型链.md new file mode 100644 index 00000000..500d5504 --- /dev/null +++ b/docs/1.前端/6.JavaScript/2.进阶/原型到原型链.md @@ -0,0 +1,159 @@ +--- +title: JavaScript进阶(一)— 原型到原型链 +createTime: 2020/02/09 09:27:29 +author: pengzhanbo +permalink: /article/hx3h2vvj/ +--- + +在 `JavaScript` 的世界中,我们常常会通过 构造函数 来创建一个 **实例对象**: + +```js +function Person(name) { + this.name = name +} +const person = new Person('Mark') +console.log(person.name) // Mark +``` + +我们使用构造函数`Person`,通过 `new` 创建了一个实例对象 `person`。 + +在实例对象 `person` 上, 有一个私有属性 `__proto__` 指向了它的构造函数的原型对象`prototype`, + +那么,什么是 `prototype`, 什么是 `__proto__` ? + +接下来,我们开始进入正题。 + +## prototype + +在 `JavaScript` 中,每个函数都有一个 `prototype` 属性,这个属性指向了该函数的原型对象。 + +```js +function Person(name) { + this.name = name +} +Person.prototype.age = 18 + +const person1 = new Person('Mark') +const person2 = new Person('John') +console.log(person1.name, person1.age) // Mark 18 +console.log(person2.name, person2.age) // John 18 +``` +可以看到,当 `person1` 和 `person2` 均打印 `age` 属性值为 `18`。 + +这是因为 `Person.prototype` 正是 实例对象 `person1` 和 `person2` 的原型。 + +既然 `prototype` 指向的是原型, 那么,**原型** 又是什么? + +简单的理解,在 `JavaScript` 中,每一个对象在创建时,都有一个与之关联的另一个对象,这个关联的对象就是指原型。 + +::: warning 注意 +`null` 是没有原型的。 +::: + +对象会从其原型对象,**继承** 属性。这也是为什么 `person1` 和 `person2` 均打印 `age` 属性值为 `18`。 + +## \_\_proto\_\_ + +在 `JavaScript` 中,每个对象(`null` 除外)都有一个 私有属性 `__proto__`, +这个属性指向了该对象的构造函数的原型`prototype`。 + +```js +function Person(name) { + this.name = name +} +const person = new Person('Mark') +console.log(person.__proto__ === Person.prototype) // true +``` + +到这里就会发现,既然构造函数有原型 `prototype`,原型也是一个对象,而对象有 `__proto__` 指向它的构造函数的原型对象, +那么 构造函数的原型对象,是否也有其原型对象呢? + +## constructor + +在说明 原型的原型前,需要了解原型上的一个属性 `constructor`, 它指向了原型对象关联的构造函数: + +``` js +function Person(name) { + this.name = name +} +const person = new Person('Mark') +console.log(person.prototype.constructor === Person) // true +``` + +它有助于帮我们理解 找到原型的原型的构造函数。 + +## 原型的原型 + +当我们在控制台打印并输出 `Person.prototype.__proto__` 时,发现打印了一个对象: + +```js +function Person(name) { + this.name = name +} +console.log(Person.prototype.__proto__) +``` + +`output`: + +![Person.prototype.__proto__](/images/js-prototype-1.png) + +既然 `Person` 的原型也有原型, 那么 这个原型的原型对象,它的构造函数又是什么呢? + +我们可以使用 `constructor` 来获取 它的构造函数: + +```js +function Person(name) { + this.name = name +} +console.log(Person.prototype.__proto__.constructor) +``` + +`output`: +![Person.prototype.__proto__.constructor](/images/js-prototype-2.png) + +可以发现 `Person` 的原型对象的原型对象,指向的构造函数是 `Object`。 + +即 `Person.prototype` 的原型,指向的是 `Object.prototype`。 + +那么, `Object.prototype` 有没有自己的原型呢? + +![Object.prototype.__proto__](/images/js-prototype-3.png) + +可以发现,`Object.prototype` 的原型,指向的是 `null`。 + +而`null` 是表示 **没有对象**,它没有原型。 + +## 原型链 + +`Person.prototype` -> `Object.prototype` -> `null` + +(通过 `__proto__` 进行关联) + +这种 对象有一个原型对象,它的原型对象又有它的原型对象,一层层如同链式一样,向上关联,称为 `原型链`。 + +几乎所有 `JavaScript` 中的对象都是位于原型链顶端的 `Object` 的实例。 + +::: tip +`__proto__` 是一个非标准的属性,但绝大部分浏览器都支持通过这个属性来访问原型。 + +`__proto__` 在实现上是`Object` 上的一个 `getter/setter`访问器 ,使用 `obj.__proto__` 时,可以理解成返回了 `Object.getPrototypeOf(obj)`。 +::: + +## 基于原型链的继承 + +`JavaScript` 对象是动态的属性“包”(指其自己的属性)。`JavaScript` 对象有一个指向一个原型对象的链。当试图访问一个对象的属性时,它不仅仅在该对象上搜寻,还会搜寻该对象的原型,以及该对象的原型的原型,依次层层向上搜索,直到找到一个名字匹配的属性或到达原型链的末尾。 + +```js +function Person(name) { + this.name = name +} +Person.prototype.age = 18 + +const person1 = new Person('Mark') +const person2 = new Person('John') +console.log(person1.name, person1.age) // Mark 18 +console.log(person2.name, person2.age) // John 18 +``` + +在这个示例中, 虽然`Person` 的实例对象自身并没有`age` 属性,但由于它的原型对象上有 `age` 属性, +实例对象从它的原型对象 **继承** 了属性 `age` 。 从而其 `age` 属性的值为 `18`。 diff --git a/docs/1.前端/6.JavaScript/2.进阶/执行上下文.md b/docs/1.前端/6.JavaScript/2.进阶/执行上下文.md new file mode 100644 index 00000000..4d6b4c47 --- /dev/null +++ b/docs/1.前端/6.JavaScript/2.进阶/执行上下文.md @@ -0,0 +1,227 @@ +--- +title: JavaScript进阶(四)— 执行上下文 +createTime: 2020/02/12 04:35:52 +author: pengzhanbo +permalink: /article/d12xkizf/ +--- + +## 执行上下文 + +执行上下文是, `JavaScript` 代码被 **解析** 和 **执行** 时 **所在环境** 的抽象概念。 +`JavaScript` 的任何代码都是在执行上下文中执行的。 + +### 类型 + +`JavaScript` 有三种 执行上下文 类型: + +- **全局执行上下文** + + 默认的执行上下文,或者说基础执行上下文。 任何不在函数内部的代码,都是在 全局执行上下文中。 + 全局上下文执行两个事情: + - 创建一个全局的 `window`对象(在浏览器环境中)。 + - 设置 `this` 的值等于 全局的 `window` 对象。 + + 一个程序只会有一个全局执行上下文。 + +- **函数执行上下文** + + 每当函数被执行时,都会为该函数创建一个新的执行上下文。 + 每个函数都有它自己的执行上下文,且是在函数执行的时候进行创建。 + 函数上下文可以有任意多个,每当一个函数执行上下文被创建,它会按照定义的顺序,执行一系列步骤。 + +- **eval函数执行上下文** + + 执行在 `eval` 函数内部的代码也会有它属于自己的执行上下文。 + +### 创建执行上下文 + +创建执行上下文主要分为两个阶段: **创建阶段** 和 **执行阶段**。 + +## 创建阶段 + +在创建阶段,会做三件事: +- this 值的决定,即 This绑定 +- 创建词法环境组件 +- 创建变量环境组件 + +### This绑定 + +- 全局执行上下文 + + 在全局执行上下文中, `this` 的值指向全局对象。(在浏览器中, `this` 引用 `Window` 对象)。 + + +- 函数执行上下文 + + 在函数执行上下文中, `this` 的值取决于该函数是如何被调用的。如果它被一个引用对象调用,那么 `this` 会被设置成那个对象,否则 `this` 的值被设置为全局对象或者 `undefined` (在严格模式下)。 + + ```js + let foo = { + bar: function() { + console.log(this); + } + } + + // 'this' 引用 'foo', 因为 'baz' 被对象 'foo' 调用 + foo.bar(); + + let bar = foo.baz; + + // 'this' 指向全局 window 对象,因为没有指定引用对象 + bar(); + ``` + +### 词法环境 + +> [ECMAScript 标准](https://262.ecma-international.org/6.0/) +> +> 词法环境是一种规范类型,基于 ECMAScript 代码的词法嵌套结构来定义标识符和具体变量和函数的关联。 +> 一个词法环境由环境记录器和一个可能的引用外部词法环境的空值组成。 + +词法环境是一种 **持有标识符—变量映射** 的结构。 + +::: tip +这里的标识符指的是变量/函数的名字,而变量是对实际对象[包含函数类型对象]或原始数据的引用。 +::: + +在词法环境的内部有两个组件:**(1) 环境记录器**和 **(2) 一个外部环境的引用**。 + +- **环境记录器**是存储变量和函数声明的实际位置。 +- **外部环境的引用**意味着它可以访问其父级词法环境(作用域)。 + +词法环境有两种类型: + +- **全局环境**(在全局执行上下文中)是没有外部环境引用的词法环境。全局环境的外部环境引用是 `null`。它拥有内建的 Object/Array/等、在环境记录器内的原型函数(关联全局对象,比如 `window` 对象)还有任何用户定义的全局变量,并且 `this` 的值指向全局对象。 +- 在**函数环境**中,函数内部用户定义的变量存储在环境记录器中。并且引用的外部环境可能是全局环境,或者任何包含此内部函数的外部函数。 + +环境记录器也有两种类型: + +- **声明式环境记录器**: 存储变量、函数和参数。 +- **对象环境记录器**: 用来定义出现在全局上下文中的变量和函数的关系。 + +可以看出: + +- 在**全局环境**中,环境记录器是对象环境记录器。 +- 在**函数环境**中,环境记录器是声明式环境记录器。 + +::: tip 注意 +对于**函数环境**,**声明式环境记录器**还包含了一个传递给函数的 `arguments` 对象(此对象存储索引和参数的映射)和传递给函数的参数的 `length`。 +::: + +使用伪代码描述 词法环境,大致如下: +```js +GlobalExecutionContext = { + LexicalEnvironment: { + EnvironmentRecord: { + Type: "Object", + // 在这里绑定标识符 + } + outer: <null> + } +} + +FunctionExecutionContext = { + LexicalEnvironment: { + EnvironmentRecord: { + Type: "Declarative", + // 在这里绑定标识符 + } + outer: <Global or outer function environment reference> + } +} +``` + +### 变量环境 + +**变量环境** 同样是一个 **词法环境**,其环境记录器持有变量声明语句在执行上下文中创建的绑定关系。 + +**变量环境** 有着上面定义的词法环境的所有属性。 + +在 `ES6` 中,**词法环境**和**变量环境**的一个不同就是前者被用来存储函数声明和变量(`let` 和 `const`)绑定, +而后者只用来存储 `var` 变量绑定。 + +示例代码: +```js +let a = 20 +const b = 30 +var c + +function multiply(e, f) { + var g = 20 + return e * f * g +} + +c = multiply(20, 30) +``` + +示例代码 执行上下文伪代码: +```js +GlobalExectionContext = { + + ThisBinding: <Global Object>, + + LexicalEnvironment: { + EnvironmentRecord: { + Type: "Object", + // 在这里绑定标识符 + a: < uninitialized >, + b: < uninitialized >, + multiply: < func > + } + outer: <null> + }, + + VariableEnvironment: { + EnvironmentRecord: { + Type: "Object", + // 在这里绑定标识符 + c: undefined, + } + outer: <null> + } +} + +FunctionExectionContext = { + ThisBinding: <Global Object>, + + LexicalEnvironment: { + EnvironmentRecord: { + Type: "Declarative", + // 在这里绑定标识符 + Arguments: {0: 20, 1: 30, length: 2}, + }, + outer: <GlobalLexicalEnvironment> + }, + + VariableEnvironment: { + EnvironmentRecord: { + Type: "Declarative", + // 在这里绑定标识符 + g: undefined + }, + outer: <GlobalLexicalEnvironment> + } +} +``` + +::: warning +只有遇到调用函数 `multiply` 时,函数执行上下文才会被创建。 +::: + +**说明:** + +可能你已经注意到 `let` 和 `const` 定义的变量并没有关联任何值,但 `var` 定义的变量被设成了 `undefined。` + +这是因为在创建阶段时,引擎检查代码找出变量和函数声明,虽然函数声明完全存储在环境中,但是变量最初设置为 `undefined`(`var` 情况下),或者未初始化(`let` 和 `const` 情况下)。 + +这就是为什么你可以在声明之前访问 `var` 定义的变量(虽然是 `undefined`),但是在声明之前访问 `let` 和 `const` 的变量会得到一个引用错误。 + +这就是我们说的变量声明提升。 + +## 执行阶段 + +在此阶段,完成对所有这些变量的分配,最后执行代码。 + +::: warning +在执行阶段,如果 `JavaScript` 引擎不能在源码中声明的实际位置找到 `let` 变量的值,它会被赋值为 `undefined`。 +::: diff --git a/docs/1.前端/6.JavaScript/2.进阶/执行上下文栈.md b/docs/1.前端/6.JavaScript/2.进阶/执行上下文栈.md new file mode 100644 index 00000000..f0e3d2d2 --- /dev/null +++ b/docs/1.前端/6.JavaScript/2.进阶/执行上下文栈.md @@ -0,0 +1,138 @@ +--- +title: JavaScript进阶(三)— 执行上下文栈 +createTime: 2020/02/11 11:53:33 +author: pengzhanbo +permalink: /article/6snk1b6c/ +--- + +关于 执行上下文,请点击查看[这篇文章](/article/d12xkizf/)。 + +## 执行上下文栈 + +`JavaScript` 引擎 创建了 执行上下文栈 来存储并管理 代码执行时创建的所有 执行上下文。 + +执行上下文栈(Execution context stack,ECS) 是一个种拥有 LIFO(后进先出) 的栈。 + +我们使用一个数组 模拟 执行上下文栈: + +```js +const ECSStack = [] +``` + +当 `JavaScript` 执行时,首先遇到的是 全局代码,初始化时,会首先向 执行上下文栈中压入 全局执行上下文 +(global execution context)。它只有在整个程序结束时,才会被清空,所以在程序结束前, `ECSStack` 底部 +都会有一个 `globalExecutionContext` + +```js +const ECSStack = [ + globalExecutionContext +] +``` + +当 `JavaScript` 开始执行以下代码时: +``` js +function foo() { + console.log('foo') +} +function bar() { + foo() +} +function run() { + bar() +} + +run() +``` +在这段代码中,`JavaScript` 进行以下处理: +``` ts +// 伪代码: + +// run(), 创建 函数执行上下文,并压入 执行上下文栈 +ECSStack.push(functionExecutionContext<run>) + +// run() 中发现需要执行 bar(), 继续创建 函数执行上下文,并压入执行上下文栈 +ECSStack.push(functionExecutionContext<bar>) + +// bar() 中发现需要执行 foo(), 继续创建 函数执行上下文,并压入执行上下文栈 +ECSStack.push(functionExecutionContext<foo>) + +/** 此时, ECSStack 的结构,如下: + * [ + * globalExecutionContext, + * functionExecutionContext<run>, + * functionExecutionContext<bar>, + * functionExecutionContext<foo> + * ] + */ + +// 当 foo() 执行完毕,从执行上下文栈中移除 functionExecutionContext<foo> +ECSStack.pop() + +// 当 bar() 执行完毕,从执行上下文栈中移除 functionExecutionContext<bar> +ECSStack.pop() + +// 当 run() 执行完毕,从执行上下文栈中移除 functionExecutionContext<run> +ECSStack.pop() + +// 在程序未结束时, ECSStack 底部永远有一个 globalExecutionContext +``` + +再看下一个例子: + +```js +var scope = "global scope"; +function checkScope(){ + var scope = "local scope"; + function f(){ + return scope; + } + return f(); +} +checkScope(); +``` + +```js +var scope = "global scope"; +function checkScope(){ + var scope = "local scope"; + function f(){ + return scope; + } + return f; +} +checkScope()(); +``` + +这两段代码,虽然在执行结果是一样的,都是输出 `local scope`, 但是在 执行上下文栈 中的变化不同。 + +第一段代码, 在 执行上下文栈,模拟处理如下: + +```ts +// 执行checkScope() +ECSStack.push(functionExecutionContext<checkScope>) +// 在checkScope执行阶段中执行 f() +ECSStack.push(functionExecutionContext<f>) + +ECSStack.pop() +ECSStack.pop() +``` + +第二段代码, 在执行上下文栈,模拟处理如下: + +```ts +// 执行checkScope() +ECSStack.push(functionExecutionContext<checkScope>) +ECSStack.pop() +// 在checkScope 完成后,再执行 f() +ECSStack.push(functionExecutionContext<f>) +ECSStack.pop() +``` + +可以看出, 函数执行的时机不同,虽然最终结果一致,但是在 执行上下文栈 中的过程是不同的。 + +## 总结 + +1. 执行上下文栈,是用于存储和管理所有执行上下文。 +2. 在程序没有结束前,执行栈中永远有一个全局执行上下文。 +3. 函数执行时,会创建一个新的函数执行上下文,并按顺序压入到执行栈中。 +4. 函数执行完成后,对应的函数执行上下文会从执行栈中移除。 diff --git a/docs/1.前端/6.JavaScript/2.进阶/词法作用域.md b/docs/1.前端/6.JavaScript/2.进阶/词法作用域.md new file mode 100644 index 00000000..79cb5122 --- /dev/null +++ b/docs/1.前端/6.JavaScript/2.进阶/词法作用域.md @@ -0,0 +1,38 @@ +--- +title: JavaScript进阶(二)— 词法作用域 +createTime: 2020/02/10 11:37:25 +author: pengzhanbo +permalink: /article/fpcpgpod/ +--- + +## 作用域 + +作用域是指 程序源代码中,定义变量的区域。 + +作用域规定了如何查找变量,也就是确定当前执行代码对变量的访问权限。 + +## 词法作用域 + +在 `JavaScript` 中,采用的是 词法作用域, 即静态作用域。 + +词法作用域规定了,函数的作用域是在 **函数定义的时候就确定** 了。 + +### 示例 + +```js +var a = 1 +function foo() { + console.log(a) +} +function bar() { + var a = 2 + foo() +} +bar() +``` + +这个示例的执行结果为 `1`。 + +在这个例子中, 由于 函数`foo` 的作用域在 定义的时候就确定了,即使在 函数`bar` 中也有相同的变量名`a`的定义, +但是由于两个函数在定义时,作用域是相互独立的,函数`foo`在其作用域查找局部变量`a`,没有找到, +继续从它书写位置往上查找上一层的代码,所以输出的结果为 `1`。 diff --git a/docs/1.前端/7.构建工具/webpack-HMR.md b/docs/1.前端/7.构建工具/webpack-HMR.md new file mode 100644 index 00000000..27733b59 --- /dev/null +++ b/docs/1.前端/7.构建工具/webpack-HMR.md @@ -0,0 +1,94 @@ +--- +title: webpack模块热替换(HMR) +createTime: 2021/03/24 05:14:18 +author: pengzhanbo +permalink: /article/knagbtgd/ +--- + +**模块热替换(Hot Module Replacement)** 是 webpack 的一个 十分有用且强大的 特性。 +当我们对 文件代码进行修改并保存后,webpack 会重新编译打包文件代码,并将新的模块代码发送给客户端, +浏览器通过将旧模块替换为新模块,实现在浏览器不刷新的情况下,对应用进行更新。 + +<!-- more --> + +## 前言 + +在还没有 HMR 之前,我们对文件代码进行更新保存后,想要查看更新后的内容,常常需要手动刷新浏览器。 + +但还好的是,也有一些 **live reload** 的工具库,这些库能够监听文件的变化,通知浏览器刷新页面, +从而帮助我们减少了重复的操作。 + +但是为什么还需要 HMR 呢? + +当浏览器刷新,也意味着当前页面的状态丢失了。 +比如,我们打开了一个弹窗,然后我们对弹窗的代码逻辑进行了修改并保存,浏览器刷新后,弹窗被关闭了, +我们需要重新进行交互打开弹窗。 +这无疑会增加非常多的重复且无意义工作量、时间。 + +HMR 的作用,就是不仅帮助我们在无刷新的情况下更新了应用代码,同时还保留了应用的状态,让我们能避免了 +大量重复操作,从而提高开发效率。 + +## 模块热替换 + +模块热替换(HMR - Hot Module Replacement)功能会在应用程序运行过程中替换、添加或删除模块,而无需重新加载整个页面。 + +### 启用 +启用 HMR 的方式很简单,[查看官方文档](https://www.webpackjs.com/guides/hot-module-replacement/) + +### 特性 + +HMR有几个特性: + +- 保留在完全重新加载页面时丢失的应用程序状态。 +- 只更新变更内容,以节省宝贵的开发时间。 +- 调整样式更加快速 - 几乎相当于在浏览器调试器中更改样式。 + + +## HMR基本流程 + +- **Step 1:** + + webpack watch 模式下,监听文件系统中的某个文件是否发生修改。当监听到文件发生变更时, + 根据配置文件**对模块进行重新编译打包**,并将打包后的代码 通过 JavaScript 对象保存在内存中。 + +- **Step 2:** + + webpack-dev-middleware 调用 webpack 的API 对代码的变化进行监控,并通知webpack,将代码打包到内存中。 + +- **Step 3:** + + webpack-dev-server 监听文件变化,不同于第一步的是,这一步不监听代码变化进行重新编译打包。 + 当配置文件中配置了 `devServer.watchContentBase` 为 `true` 时, + Server会监听配置的文件夹中静态文件的变化,如果发生变化,通知浏览器进行 `live reload`,即刷新页面。 + +- **Step 4:** + + webpack-dev-server 通过 sockjs 在浏览器和服务器端之间建立一个 websocket 长连接, + 将webpack编译打包的各个阶段的状态信息告知浏览器端,也包括第三步中 Server 监听静态文件变化的信息。 + 浏览器端根据这些socket消息进行不同的操作。 + 其中,服务器传递的最主要的信息,是新模块的 hash 值,后续步骤根据 hash值 进行模块的替换。 + +- **Step 5:** + + webpack-dev-server 虽然会告知浏览器打包状态,但在 webpack-dev-server/client 端并不会去请求更新的代码, + 也不会执行热模块替换的操作,这些工作会交回给 webpack/hot/dev-server。 + webpack/hot/dev-server 根据 webpack-dev-server/client 传给它的信息,以及 dev-server 的配置信息, + 来决定是刷新浏览器,还是执行 热模块替换。 + +- **Step 6:** + + 在客户端中,HotModuleReplacement.runtime 接受到 上一步传递给它的新模块的 hash 值, + 通过 JsonpMainTemplate.runtime 向 server 端发送 Ajax 请求,server 端返回一个 json。 + 该 json 包含了所有要更新的模块的 hash 值,获取到需要更新的模块列表后,再发送一个 jsonp 请求, + 获取最新的模块代码。 + +- **Step 7:** + + HotModulePlugin 会对新旧模块进行对比,决定是否更新模块。 + 在决定更新模块后,检查模块之间的依赖关系,更新模块的同时,也更新模块间的依赖引用。 + 这个步骤也决定了 HMR 是否成功。 + +- **Step 8:** + + 如果 HMR 失败,则回退到 live reload 操作,通过刷新浏览器来获取最新打包的代码。 + diff --git a/docs/1.前端/7.构建工具/webpack原理.md b/docs/1.前端/7.构建工具/webpack原理.md new file mode 100644 index 00000000..899a632b --- /dev/null +++ b/docs/1.前端/7.构建工具/webpack原理.md @@ -0,0 +1,176 @@ +--- +title: webpack原理的简单入门 +createTime: 2021/03/21 06:13:07 +author: pengzhanbo +permalink: /article/gq88mn6a/ +--- + +::: center +![webpack](https://www.webpackjs.com/32dc115fbfd1340f919f0234725c6fb4.png){width="100px"} +::: + +## 前言 + +我们知道, `webpack` 作为前端工程化中,主流的模块打包工具之一,应用于各种各样的前端工程化项目中。 + +虽然大多数项目都或多或少会使用到 `webpack`, 但是可能对于大多数的 前端开发人员来说, +可能只是改改 `webpack` 的配置, 或者甚至从未动过 `webpack` 的相关文件, +或多或少对 `webpack` 的配置以及功能感到陌生。 + +还有类似于 `vue-cli`、`create-react-app` 、 `umi.js` 等各种基于 `webpack` 封装的 脚手架, +提供了各种开箱即用的功能,这使得 `webpack` 离我们好像越来越远。 + +但是当我们的某个项目面临了不得不去 深入 `webpack` 才能解决的问题,或者 面试时,被问起 `webpack` 相关的问题, +就难以解决或者回答。 + +所以我们需要对 `webpack` 至少有基本的了解,了解它的原理、如何编写 `loader` 、 `plugin` 等。 + +## webpack是什么 + +> 引用 [webpack官网](https://webpack.js.org/concepts/) : +> +> At its core, webpack is a static module bundler for modern JavaScript applications. When webpack processes your application, it internally builds a dependency graph from one or more entry points and then combines every module your project needs into one or more bundles, which are static assets to serve your content from. +> +> 本质上,webpack 是一个现代 JavaScript 应用程序的静态模块打包器(module bundler)。当 webpack 处理应用程序时,它会递归地构建一个依赖关系图(dependency graph),其中包含应用程序需要的每个模块,然后将所有这些模块打包成一个或多个 bundle。 + +从作用上讲,webpack 的功能就是将不同模块的文件,打包整合到一起,并且保证它们之间引用的正确,且有序执行。 +这使得我们在做项目架构时,能够从模块的角度去做文件拆分,然后交给 webpack 打包整合。 + +而一个项目中的文件,不仅有 html文件、CSS文件、JavaScript文件、图片资源、Vue特有的`.vue`文件,typescript的`.ts` 文件等,以及项目的中的代码还需要进行压缩混淆、浏览器兼容、等等必要的处理,启动一个本地的开发服务器、模块的热更新替换等, 可以通过`webpack` 提供的各种机制,来一一实现。 + +对于 `webpack` 来说, 它自身只能识别 JavaScript 文件, 而对于其他的资源,可以通过 webpack提供的 `Loader` 特性来实现 +识别。 通过 `Loader`,可以把其它类型的资源文件,转换为 webpack能够处理的有效模块。 + +而对于 代码混淆、本地开发服务器、模块热更新,则可以通过 webpack 提供的 `Plugin` 特性来实现功能上的扩展。 + +## 模块打包原理 + +在 webpack 中,有四个基础且核心的概念: + +- **入口(entry)** +- **输出(output)** +- **加载器(Loader)** +- **插件(Plugin)** + +### 入口(entry) + + 指示 webpack 应该使用哪个模块,来作为构建其内部依赖图的开始。 + +### 输出(output) + + 告诉 webpack 在哪里输出它所创建的 bundles,以及如何命名这些文件 + +### 加载器(Loader) + + webpack 自身只能理解 JavaScript 文件 和 json 文件, loader 可以将其他类型的资源文件转换为 webpack能够处理的有效模块。 + + 本质上,webpack loader 将所有类型的文件,转换为应用程序的依赖图(和最终的 bundle)可以直接引用的模块。 + +### 插件(Plugin) + + 用于执行范围更广的任务。插件的范围包括,从打包优化和压缩,一直到重新定义环境中的变量。 + 插件接口功能极其强大,可以用来处理各种各样的任务。 + + +### 模块(modules) + +在模块化编程中,开发者将程序分解成离散功能块(discrete chunks of functionality),并称之为模块。 + +对于 webpack ,任何文件都可以是一个模块。 + +### 模块打包运行原理 + +在说 webpack 的 **模块打包运行原理** 之前, 先看下 我们是如何使用 webpack的, +一般情况下, 我们通过编写一个 配置文件`webpack.config.js`, 对 webpack 进行本地化的配置, +大致的配置如下: +``` js +module.exports = { + // 声明模块的入口文件 + entry: './src/entry.js', + output: { + path: path.resolve(__dirname, 'dist'), // 输出目录 + filename: 'bundle.js', // 文件名称 + }, + module: { + rules: [ + // 配置 使用 babel-loader 对 .js 资源进行转换 + { + test: /\.js$/, + loader: 'babel-loader', + }, + // ...more loader + ], + }, + // 插件配置 + plugins: [ + new EslintWebpackPlugin(), + new webpack.NoEmitOnErrorsPlugin(), + // ...more plugin + ], + // ...more config +} +``` + +`webpack` 读取了 配置文件后,运行的流程大致如下: + +1. 读取 `webpack` 的配置参数; +2. 启动 `webpack` , 创建 `compiler` 对象,开始解析项目; +3. 从入口文件 `entry` 开始解析,并找到其导入的**依赖模块**,递归遍历分析,形成**依赖关系树**; +4. 对不同的文件类型资源的依赖模块文件,使用对应的 `Loader` 进行转换,最终转为 webpack的有效模块; +5. 在编译过程中, `webpack` 通过 发布订阅模式,向外抛出一些 `hooks` ,`webpack` 的 `Plugin` 通过监听各个 `hooks` , + 执行插件任务,扩展 `webpack` 的功能,干预输出结果。 +6. 根据 输出配置 `output` ,将打包构建好的资源文件 输出。 + +`compiler` 对象是一个全局单例,负责控制整个 webpack 构建流程。 + +在构建过程中,还会产生一个当前构建的上下文对象 `compilation`, 它包含了当前构建的所有信息,在每个热更新或重新构建时, `compiler` 都会产生一个新的`compilation` 对象,负责当前构建过程。 + +每个模块间的依赖关系,则依赖于`AST`语法树。每个模块文件在通过`Loader`解析完成之后, +会通过`acorn`库生成模块代码的`AST`语法树,通过语法树就可以分析这个模块是否还有依赖的模块, +进而继续循环执行下一个模块的编译解析。 + +最终, webpack 打包构建出来的 bundle 文件,是一个 IIFE 执行函数。 + +```js +// webpack5下进行的最小化打包输出文件 +(() => { + // webpack 模块文件内容 + var __webpack_modules__ = ({ + "entry.js": ((modules) => { /* ... */ }), + "other.js": ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => { /* ... */ }) + }); + + // 模块缓存 + var __webpack_module_cache__ = {}; + + // The require function + function __webpack_require__(moduleId) { + // Check if module is in cache + var cachedModule = __webpack_module_cache__[moduleId]; + if (cachedModule !== undefined) { + return cachedModule.exports; + } + // Create a new module (and put it into the cache) + var module = __webpack_module_cache__[moduleId] = { + // no module.id needed + // no module.loaded needed + exports: {} + }; + + // Execute the module function + __webpack_modules__[moduleId](module, module.exports, __webpack_require__); + + // Return the exports of the module + return module.exports; + } + + // startup + // Load entry module and return exports + // This entry module can't be inlined because the eval devtool is used. + var __webpack_exports__ = __webpack_require__("entry.js"); + +})(); +``` +在上面的打包demo中,整个立即执行函数里边只有三个变量和一个函数方法,`__webpack_modules__`存放了编译后的各个文件模块的JS内容,`__webpack_module_cache__` 用来做模块缓存,`__webpack_require__` 是Webpack内部实现的一套依赖引入函数。最后一句则是代码运行的起点,从入口文件开始,启动整个项目。 + +`__webpack_require__`模块引入函数,我们在模块化开发的时候,通常会使用`ES Module`或者`CommonJS`规范导出/引入依赖模块,webpack打包编译的时候,会统一替换成自己的`__webpack_require__`来实现模块的引入和导出,从而实现模块缓存机制,以及抹平不同模块规范之间的一些差异性。 diff --git a/docs/1.前端/8.HTTP/CORS.md b/docs/1.前端/8.HTTP/CORS.md new file mode 100644 index 00000000..ea5f2b5a --- /dev/null +++ b/docs/1.前端/8.HTTP/CORS.md @@ -0,0 +1,332 @@ +--- +title: 跨域资源共享(CORS) +createTime: 2020/08/29 07:40:31 +author: pengzhanbo +tags: + - http +permalink: /article/2f45bq9x/ +--- + +**跨域资源共享(CORS)** 是一种基于 **HTTP Header** 的机制。 +该机制通过允许服务器标示除了它自己的 origin(域,协议和端口),使这些 origin 有权限访问加载服务器上的资源。 + +<!-- more --> + +跨域资源共享 通过 **预检请求** 的机制,检查服务器是否允许要发送的真实请求。 +浏览器向服务器发送一个到服务器托管的跨域资源 **预检请求**, +在预检请求中,浏览器发送的头部中标示有HTTP方法和真实请求会用到的头。 + +## 前言 + +浏览器出于安全性的原因,会限制脚本内发起的跨域资源请求, +比如 **XMLHttpRequest** 和 **Fetch API** 遵循 **同源策略**,默认情况下不允许发起非同源的资源请求。 +使用这些API的Web应用,只能加载从应用程序的同一个域的请求HTTP资源, +**除非响应报文中包含了正确的CORS响应头** + +## 概述 + +跨域资源共享 新增了一组 HTTP首部字段,允许服务器声明哪些源站通过浏览器有权限访问哪些资源。 +同时,对于可能对服务器数据产生副作用的 HTTP 请求方法,浏览器必须首先使用 `OPTIONS` 方法发起一个预检请求, +从而获取服务器是否允许跨域请求,服务器确认允许之后,才发起实际的HTTP请求。 + +CORS 请求失败会产生错误,但是为了安全,在 JavaScript 代码中,是无法获取具体是哪里出了问题。 +我们只能通过查看浏览器的控制台来获取具体出现的错误。 + +若要开启 CORS ,我们需要配置 CORS 相关的 HTTP首部字段。 + +## HTTP 响应首部字段 + +在 CORS 中,HTTP 响应首部字段主要有以下几个: + +- **Access-Control-Allow-Origin** +- **Access-Control-Allow-Methods** +- **Access-Control-Allow-Headers** +- **Access-Control-Max-Age** +- **Access-Control-Expose-Headers** +- **Access-Control-Allow-Credentials** + +### Access-Control-Allow-Origin + +**Access-Control-Allow-Origin** 响应首部字段,用于 **指定允许访问该资源的外域URI**。 + +对于不需要携带身份凭证的请求,服务器可以指定改字段的值为通配符(`*`),表示允许来自所有域的请求。 + +语法: +``` +Access-Control-Allow-Origin: <origin> +Access-Control-Allow-Origin: * +``` + +如果服务器 指定了具体的域名而非 `*`,那么响应首部中的 **Vary** 字段的值必须包含 `Origin`。 +用于告诉客户端:服务器对不同的源站返回不同的内容。 + +::: info 注意 +当响应的是附带身份凭证的请求时,服务端 必须 明确 **Access-Control-Allow-Origin** 的值,而不能使用通配符`“*”`。 +::: + +**示例1:** + +允许所有域访问 +``` +Access-Control-Allow-Origin: * +``` + +**示例2:** + +允许来自 https://pengzhanbo.cn 的请求 +``` +Access-Control-Allow-Origin: https://pengzhanbo.cn +Vary: Origin +``` + +### Access-Control-Allow-Methods + +**Access-Control-Allow-Methods** 响应首部字段用于 预检请求的响应。 +**指明了实际请求所允许使用的HTTP方法或方法列表**。 + +语法: +``` +Access-Control-Allow-Methods: <method>[, <method>]* +``` + +示例: + +``` +Access-Control-Allow-Methods: POST, GET, OPTIONS +``` + +### Access-Control-Allow-Headers + +**Access-Control-Allow-Headers** 响应首部字段用于 预检请求的响应。 +**指明了实际请求中允许携带的首部字段**。 + +语法: +``` +Access-Control-Allow-Headers: <header-name>[, header-name]* +Access-Control-Allow-Headers: * +``` + +以下特定的首部是一直允许的,无需特意声明他们: +- Accept +- Accept-Language +- Content-Language +- Content-Type,但只在其值属于MIME类型 `application/x-www-form-urlencoded`,`multipart/form-data`,`text/pain` 中的一种。 + +**示例1:** + +自定义请求头。 除了 CORS 安全清单列出的请求头外,支持 自定义请求头 X-Custom-Header + +``` +Access-Control-Allow-Headers: X-Custom-Header +``` + +**示例2:** + +多个自定义请求头。 + +``` +Access-Control-Allow-Headers: X-Custom-Header, X-My-Header +``` + +### Access-Control-Max-Age + +**Access-Control-Max-Age** 响应首部字段表示 **预检请求的返回结果可以被缓存多久**。 + +返回结果是指: **Access-Control-Allow-Methods** 和 **Access-Control-Allow-Headers** 提供的信息。 + +语法: +``` +Access-Control-Max-Age: <delta-seconds> +``` + +**delta-seconds** 表示返回结果可以被缓存的最长时间(秒)。 +在 Firefox 中, 上限是 **24小时(86400秒)**。 +在 Chromium 中,上限是 **2小时(7200秒)**,同时 Chromium 还规定了默认值是 **5秒**。 +如果值为 **-1** , 表示禁用缓存,则每次请求前都需要使用 OPTIONS 预检请求。 + +**示例** + +将预检请求缓存 10分钟: +``` +Access-Control-Max-Age: 600 +``` + +### Access-Control-Expose-Headers + +**Access-Control-Expose-Headers** 响应首部字段,列出了 哪些首部可以作为响应的一部分暴露给外部。 + +在 跨源访问时,XMLHttpRequest 对象的 `getResponseHeader()` 方法默认只能拿到一些最基本的响应头。 + +默认情况下,只有七种 简单响应首部 可以暴露给外部: + +- Cache-Control +- Content-Language +- Content-Length +- Content-Type +- Expires +- Last-Modified +- Pragma + +如果期望让客户端可以访问到其他的首部信息,可以将它们 该字段受列出来。 + +语法: +``` +Access-Control-Expose-Headers: <header-name>[, <header-name>]* +``` + +**示例** + +暴露一个非简单响应首部: +``` +Access-Control-Expose-Headers: X-My-Header +``` + +暴露多个非简单响应首部: +``` +Access-Control-Expose-Headers: X-My-Header, X-Custom-Header +``` + +### Access-Control-Allow-Credentials + +**Access-Control-Allow-Credentials** 响应首部字段 用于在 请求包含 Credentials 时, +告知浏览器是否可以将对请求的响应暴露给前端 JavaScript 代码。 + +当请求的 Credentials 模式 (Request.credentials)为 `include` 时,浏览器尽在相应头 **Access-Control-Allow-Credentials** 的值为 `true` 时将响应暴露给前端的 JavaScript 代码。 + +Credentials 可以是 `cookies`、 `authorization headers` 或 `TLS client certificates`。 + +语法: +``` +Access-Control-Allow-Credentials: true +``` + +**Access-Control-Allow-Credentials** 需要与 `XMLHttpRequest.withCredentials` +或 **Fetch API** 的 `Request()` 构造函数中的 `credentials` 选项结合使用。 +Credentials 必须在前后端都被配置,才能使带 credentials 的 CORS 请求成功。 + +**示例:** + +允许 credentials + +``` +Access-Control-Allow-Credentials: true +``` + +使用带 credentials 的 XHR: + +``` js +const xhr = new XMLHttpRequest() +xhr.open('GET', 'https://pengzhanbo.cn', true) +xhr.withCredentials = true +xhr.send(null) +``` + +使用带 credentials 的 Fetch: + +``` js +fetch('https://pengzhanbo.cn', { + credentials: 'include' +}) +``` + +## HTTP 请求首部字段 + +在 CORS 中,可用于发起跨域请求的首部字段,如下: + +- Origin +- Access-Control-Request-Method +- Access-Control-Request-Headers + +这些首部字段无需手动设置。 + +当开发者使用 XMLHttpRequest 发起跨域请求时,它们已经被设置就绪。 + +### Origin + +**Origin** 请求首部字段表明预检请求或实际请求的源站。 + +语法: + +``` +Origin: <origin> +``` + +origin 参数的值为源站的URI。不包含任何路径信息,仅表示服务器名称。 + +### Access-Control-Request-Method + +**Access-Control-Request-Method** 请求首部字段用于预检请求。作用是 将实际情况所使用的HTTP方法告诉服务器。 + +语法: + +``` +Access-Control-Request-Method: <method> +``` + +### Access-Control-Request-Headers + +**Access-Control-Request-Headers** 请求首部字段用于预检请求。作用是 将实际请求所携带的首部字段告诉服务器。 + +语法: + +``` +Access-Control-Request-Headers: <header-name>[, <header-name>]* +``` + +## 预检请求 + +一个 CORS 预检请求时用于 检查服务器使用支持 CORS, 即 跨域资源共享。 + +预检请求 通过 发送一个 OPTIONS 请求,请求头部包含了以下字段: + +- Access-Control-Request-Method +- Access-Control-Request-Headers +- Origin + +浏览器会在有必要的时候,自动发出一个预检请求。 + +所以在正常情况下,前端开发者不需要自己去发送这样的请求。 + +### 预检请求与凭据 + +CORS 预检请求不能包含凭据。预检请求的响应必须指定 Access-Control-Allow-Credentials: true 来表明可以携带凭据进行实际的请求。 + +## 简单请求 + +某些情况下,不会触发 CORS预检请求,这样的请求,可表述为 _简单请求_。 + +若请求满足以下所有条件,则可视为 简单请求: + +- 使用 GET, HEAD POST 请求方法 +- 除了被用户代理自动设置的首部字段(Connection,User-Agent等), + 以及在 Fetch 规范中定义为 [禁用首部名称](https://fetch.spec.whatwg.org/#forbidden-header-name) 的其他首部, + 允许人为设置的字段为 Fetch 规范定义的 对 [CORS 安全的首部字段集合](https://fetch.spec.whatwg.org/#cors-safelisted-request-header) +- 请求中任意的 XMLHttpRequest 对象均没有注册任何监听事件, + XMLHttpRequest 对象可以使用 XMLHttpRequest.upload 属性访问。 +- 请求中没有使用 ReadableStream 对象。 + +## 附带身份的请求与通配符 + +在响应附带身份凭证的请求时: + +- 服务器不能将 **Access-Control-Allow-Origin** 的值设为通配符 `*`,而应将其设置为特定的域,如:Access-Control-Allow-Origin: https://pengzhanbo.cn。 + +- 服务器不能将 **Access-Control-Allow-Headers** 的值设为通配符 `*`,而应将其设置为首部名称的列表,如:Access-Control-Allow-Headers: X-Custom-Header, Content-Type + +- 服务器不能将 **Access-Control-Allow-Methods** 的值设为通配符 `*`,而应将其设置为特定请求方法名称的列表,如:Access-Control-Allow-Methods: POST, GET + + +## 需要CORS的场景 + +1. 使用 **XMLHttpRequest** 发起的 HTTP请求 +2. 使用 **Fetch API** 发起的 HTTP 请求 +3. Web字体,CSS通过 `@font-face` 使用的跨域字体资源 +4. WebGL 贴图 +5. 使用 drawImage 将 Images/video 画面绘制到 canvas +6. 来自图像的 CSS 图形 + + +## 安全 + +在实际的使用场景中,尽可能的少使用 通配符 `*`,来允许所有域访问,或允许所有自定义首部字段, +这可能在 web 安全上来带风险。 diff --git a/docs/1.前端/8.HTTP/CSP.md b/docs/1.前端/8.HTTP/CSP.md new file mode 100644 index 00000000..f38912b4 --- /dev/null +++ b/docs/1.前端/8.HTTP/CSP.md @@ -0,0 +1,256 @@ +--- +title: 内容安全策略(CSP) +createTime: 2020/08/28 03:25:32 +author: pengzhanbo +tags: + - http + - 安全 +permalink: /article/snkdmwsz/ +--- + + +内容安全策略(`Content-Security-Policy`),简称 `CSP`。是一种 计算机安全标准。 + +主要目标是 减少和报告XSS攻击、数据注入攻击等。这些攻击手段的主要目的是盗取网站数据、网站内容污染、散发恶意软件等。 + +几乎所有现在浏览器都支持 `CSP`, 对于不支持的浏览器,则会忽略 `CSP`。 + +<!-- more --> + +## XSS攻击 + +XSS攻击是一种常见的、危害极大的网络攻击手段。它利用浏览器对从服务器获取的内容的信任, +通过站点的 `script` 脚本、内联脚本、外部导入资源等方式进行注入攻击。 +恶意脚本在受害者浏览器中执行,以达成其目的。 + +## CSP + +`CSP` 通过 **有效域名**,即 **浏览器认可的可执行脚本的有效来源** ,使 服务器管理者有能力消除或减少 XSS 攻击所以来的载体。 +支持 `CSP` 的浏览器,仅会执行从白名单域名加载的脚本文件,忽略其他所有脚本,包括内联脚本和 HTML 事件处理属性。 + + +## 制定策略 + +`CSP` 通过 声明 HTTP 头部字段 `Content-Security-Policy` 来启用和配置策略: +``` +Content-Security-Policy: policy; +Content-Security-Policy: policy; policy; +``` + +参数 `[policy]` 是一个包含了描述 各种CSP策略指令的字符串。 + +## 策略指令 + +### default-src + +为其他CSP指令提供备选项,如果其他指令不存在,用户代理会查找并应用该值,如果其他指令有配置值,那么则不会应用 default-src的值。 + +default-src 策略允许指定一个或多个值: +``` +Content-Security-Policy: default-src <source>; +Content-Security-Policy: default-src <source> <source>; +``` + +### script-src + +脚本内容安全策略指令,包括限制 外部资源、内联脚本、eval函数。 + +``` +Content-Security-Policy: script-src <source> +``` + +### style-src + +CSS文件内容安全策略指令,包括限制 内联样式表、通过`<link>` 引入的css文件、样式中通过 `@import` 导入的css文件、 +元素的 `style` 属性、 `style.cssText` 属性、以及 `el.setAttribute('style', '')` + +``` +Content-Security-Policy: style-src <source> +``` + +### img-src + +图片资源内容安全策略指令, 限制通过 `<img>` 加载的图片资源 + +``` +Content-Security-Policy: img-src <source> +``` + +### media-src + +媒体资源内容安全策略指令,限制通过 `<audio>`、`<video>`、`<track>` 加载的媒体资源 + +``` +Content-Security-Policy: media-src <source> +``` + +### frame-src + +iframe内容安全策略指令,限制`<iframe>` 加载的页面资源 + +### 其他指令 + +- `manifest-src` 限制 manifest 资源(通过`<link>`引入的 manifest文件) +- `worker-src` 限制 `worker`资源,包括 `Worker`、`SharedWorker` 、`ServiceWorker` +- `child-src` 限制 `web worker`、`<frame>` 、`<iframe>` +- `connect-src` 限制允许通过脚本接口加载的链接地址,包括:`<a>`、`Fetch`、`XMLHttpRequest`、`WebSocket`、`EventSource` +- `font-src` 限制 `@font-face` 加载字体的有效源规则。 +- `object-src` 限制 `<object>`、`<embed>`、`<applet>` + + +### 指令`<source>`有效值 + +- `<host-source>` + + 以域名或者 IP 地址表示的主机名,外加可选的 URL 协议名(URL scheme)以及端口号。 + 支持前置通配符(星号 '*'),可以将通配符应用于站点地址、端口中,如应用于端口,则表示允许使用该域名下的所有端口。 + + - **example.com:443** 匹配 example.com 上 443 端口访问 + - **https://example.com** 匹配使用了 http: 的 example.com 的访问 + - ***.example.com** 匹配 example.com 下的所有子域名的访问 + +- `<scheme-source>` + + 协议名如'http:' 或者 'https:'。必须带有冒号,不要有单引号。 + +- `'self'` + + 指向与要保护的文件所在的源,包括相同的 URL scheme 与端口号。必须有单引号。 + +- `'unsafe-inline'` + + 允许使用内联资源,例如内联 `<script>` 元素(javascript: URL)、内联事件处理器以及内联 `<style>` 元素。必须有单引号。 + +- `'unsafe-eval'` + + 允许使用 eval() 以及相似的函数来从字符串创建代码。必须有单引号。 + +- `'none'` + + 不允许任何内容。 必须有单引号。 + +- `'nonce-<base64 值>'` + + 特定使用一次性加密内联脚本的白名单。服务器必须在每一次传输政策时生成唯一的一次性值。否则将存在绕过资源政策的可能。 + +- `<hash-source>` + + 使用 sha256、sha384 或 sha512 编码过的内联脚本或样式。其由用短划线分隔的两部分组成:用于创建哈希的加密算法,以及脚本或样式 base64 编码的哈希值。当生成哈希值的时候,不要包含 `<script>` 或 `<style>` 标签,同时注意字母大小写与空格——包括首尾空格——都是会影响生成的结果的。 + + ``` + Content-Security-Policy: default-src sha256-abcdef; + ``` +- `'strict-dynamic'` + + strict-dynamic 指定对于含有标记脚本 (通过附加一个随机数或散列) 的信任,应该传播到由该脚本加载的所有脚本。与此同时,任何白名单以及源表达式例如 'self' 或者 'unsafe-inline' 都会被忽略。 + +## 启用CSP + +启用CSP,可以在 HTTP服务器中,新增 Header 字段: +如,在nginx中: +``` nginx +http { + # ...more + server { + # ...more + location / { + index index.html; + Content-Security-Policy default-src 'self'; + # ...more + } + } +} +``` + +也可以在 html 文件中 添加 `<meta>` 标签 +``` html +<meta http-equiv="Content-Security-Policy" content="default-src 'self';" /> +``` + +## 示例 + +### 示例1 + +默认只允许加载本站资源 + +``` +Content-Security-Policy: default-src 'self'; +``` + +### 示例2 + +默认只允许加载本站资源,但允许任意来源图片资源 + +``` +Content-Security-Policy: default-src 'self'; img-src *; +``` + +### 示例3 + +默认只允许加载本站资源,允许 script资源、css资源、图片资源从指定cdn域名加载 +``` +Content-Security-Policy: default-src 'self'; script-src 'self' https://cdn.example.com; style-src 'self' https://cdn.example.com; img-src 'self' https://cdn.example.com; +``` + +### 示例4 + +阻止所有 iframe 窗口,允许本站加载其他资源 + +``` +Content-Security-Policy: default-src 'self'; frame-src 'none'; +``` + +### 示例5 + +执行特定 nonce 的内联脚本: + +``` +Content-Security-Policy: script-src 'nonce-abcdef' 'self'; +``` + +只有在`<script>`标签内带有特定 `nonce` 值的脚本才允许执行: + +``` html +<script nonce="abcdef" src="example.js"></script> +``` + +### 示例6 + +Hash 值相符的脚本才能执行: + +``` +Content-Security-Policy: script-src 'sha256-qznLcsROx4GACP2dm0UCKCzCG+HiZ1guq6ZZDob/Tng=' +``` +该hash值必须是 script 标签内容的 sha256 值,代码才能执行: +``` html +<script> + alert("Hello, world."); +</script> +``` + +## 违例报告 + +启用 CSP 后,默认情况下,违例报告不会发送。我们可以通过配置 `report-uri` 策略指令,并提供至少一个URI地址去递交报告。 + +``` +Content-Security-Policy: default-src 'self'; report-uri http://report.example.com/csp; +``` + +### 违例报告示例 + +违例报告将以 JSON 对象的数据结构进行递交: + +``` json +{ + "csp-report": { + "document-uri": "http://example.com/index.html", // 发生违规的文档的 URI + "referrer": "", // 违规发生处的文档引用(地址) + "blocked-uri": "http://example.com/css/style.css", // 被 CSP 阻止的资源 URI。 + "violated-directive": "style-src cdn.example.com", // 违反的策略名称。 + // 在 Content-Security-Policy HTTP 头部中指明的原始策略。 + "original-policy": "default-src 'none'; style-src cdn.example.com; report-uri /_/csp-reports" + } +} +``` + +当服务器接收到 违例报告,可以通过分析报告内容,来进行自定义的处理。 diff --git a/docs/1.前端/8.HTTP/HSTS.md b/docs/1.前端/8.HTTP/HSTS.md new file mode 100644 index 00000000..fe8ad940 --- /dev/null +++ b/docs/1.前端/8.HTTP/HSTS.md @@ -0,0 +1,90 @@ +--- +title: 为你的站点开启HSTS +createTime: 2020/11/12 07:08:12 +author: pengzhanbo +tags: + - http + - 安全 +permalink: /article/1w4onzn1/ +--- + +`HTTP-Strict-Transport-Security` 简称为 `HSTS`,是一个 HTTP 响应头。 +用于通知浏览器应该只通过 HTTPS 访问该站点,并且以后使用 HTTP 访问该站点的所有尝试都应自动转换为 HTTPS。 + +<!-- more --> + +## 中间人劫持 + +当用户在未知风险的网络环境中访问 某个网站的时候,如访问 `http://example.com`,在这个未知风险的网络环境中, +可能会被其他人拦截到用户发出的网络请求,然后跳转到一个一模一样的钓鱼网站,或者在请求内容中,注入有危害的代码、广告等, +这种攻击行为,被称为 **中间人劫持**。 + +当 `example.com` 也支持 `https` 协议进行访问后,如果用户直接通过 `https` 协议访问,那么在一定程度上可以有效防止 +`中间人劫持`。 + +如果用户依然通过 `http` 协议访问,虽然服务器可以重定向到 `https` 请求,然而在这个过程中,中间人依然可以 +通过拦截 `http` 请求,然后向服务器发起 `https` 请求获取内容,再注入新的内容 返回给用户。 + +用户在浏览器地址栏中 输入 `example.com`, 浏览器默认发起的是 `http` 请求,这导致了我们很难要求用户在通过域名访问 +网站时,一定要输入 `https://example.com`。 + +为了限制 `中间人劫持` 这种潜在的攻击手段,一种处理方式就是 强制浏览器使用 `https` 协议访问网站。 +为此,我们需要给网站开启 `HSTS`。 + +## HSTS + +`HSTS` 通过声明 `HTTP` 头部字段 `HTTP-Strict-Transport-Security` 来启用和配置策略: + +``` +Strict-Transport-Security: max-age=<expire-time> +Strict-Transport-Security: max-age=<expire-time>; includeSubDomains +Strict-Transport-Security: max-age=<expire-time>; preload +``` + +### 指令 + +#### `max-age=<expire-time>` + +设置在浏览器收到这个请求后的`<expire-time>`秒的时间内凡是访问这个域名下的请求都使用 HTTPS 请求。 + +#### `includeSubDomains` <Badge>可选</Badge> + +如果这个可选的参数被指定,那么说明此规则也适用于该网站的所有子域名。 + +#### `preload` <Badge>可选</Badge> + +查看 [预加载 HSTS](https://www.chromium.org/hsts/) 获得详情。不是标准的一部分。 + +### 浏览器处理 + +> 当网站已开启 `HSTS` + +用户在第一次通过 `https` 协议访问网站时,服务器响应`Strict-Transport-Security` 头,浏览器记录下信息, +在以后重新访问访问网站时,会把访问这个网站的 `http` 请求自动替换为 `https`。 + +当 `HSTS` 头设置的过期时间到了,后面通过 `HTTP` 的访问恢复到正常模式,不会再自动跳转到 `HTTPS。` + +每次浏览器接收到 `Strict-Transport-Security` 头,它都会更新这个网站的过期时间,所以网站可以刷新这些信息,防止过期发生。 + +Chrome、Firefox 等浏览器里,当尝试访问该域名下的内容时,会产生一个 307 Internal Redirect(内部跳转),自动跳转到 HTTPS 请求。 + + +## 预加载 + +如果用户首次访问网站时,依然使用的是 `http` 协议,浏览器会忽略`Strict-Transport-Security`,而且中间人依然可以劫持请求内容,删除 `Strict-Transport-Security`。 + +为了进一步处理这个问题, `Google`、`Firefox` 等浏览器厂商,维护了一个 `HSTS` 预加载服务。 + +你可以将你已开启了 `HSTS` 的 站点域名,提交到 预加载服务中,浏览器将会永不使用非安全的方式连接到你的域名。 + +但是,这不是 HSTS 标准的一部分,也不该被当作正式的内容。 + +[`HSTS`预加载服务](https://hstspreload.org/) + + +## 示例 + +当前域名,以及所有子域名,开启 `HSTS`, 过期时间为 一年。 +``` +Strict-Transport-Security: max-age=31536000; includeSubDomains +``` diff --git a/docs/1.前端/8.HTTP/浏览器HTTP缓存机制.md b/docs/1.前端/8.HTTP/浏览器HTTP缓存机制.md new file mode 100644 index 00000000..223272f3 --- /dev/null +++ b/docs/1.前端/8.HTTP/浏览器HTTP缓存机制.md @@ -0,0 +1,331 @@ +--- +title: HTTP缓存机制 +createTime: 2019/08/24 12:18:39 +author: pengzhanbo +permalink: /article/c3ez957l/ +--- + +::: note +老生常谈!老生常谈!老生常谈啊! +::: + +## 什么是HTTP缓存 + +当客户端向服务器发起资源请求时,会先抵达浏览器缓存,如果浏览器有要请求的资源的副本, +那么就可以直接从浏览器缓存中提取而不是从原始服务器中获取这个资源。 + +http缓存都是从对同一资源的第二次请求开始的。 +- 第一次请求时,服务器返回资源,并在`response header`中回传资源的缓存参数; +- 第二次请求时,浏览器会根据这些缓存参数,判断是否使用浏览器缓存的资源副本还是从服务器获取资源。 + +## HTTP缓存分类 + +HTTP缓存,根据是否需要重新向服务器发起请求,可分为两大类: +- 强缓存: 强制缓存,在缓存有效时间内,不再向服务器发起资源请求,直接使用浏览器缓存的资源副本 +- 协商缓存:在缓存有效时间内,需要向服务器询问资源是否需要更新,如果需要更新,则从服务器获取新的资源, + 如果不需要更新,则继续使用浏览器缓存的资源副本; + +::: tip 另一种缓存分类 +根据资源是否可以被单个用户或多个用户使用来分类,还可以分为 私有缓存和共享缓存。 + +这种一般是对于 代理服务器的,即 浏览器发起请求 -> 代理服务器 -> 原始服务器。 + +- 私有缓存: 在代理服务器中,仅针对单个用户使用的资源缓存,其他用户发起的对同一个资源的首次请求,仍然需要从原始服务器获取资源 + 并为该用户建立新的缓存资源。 + +- 共享缓存:只要有一个用户发起的对同一个资源的首次到达代理服务器的请求,代理服务器对该资源缓存后,其他用户请求代理服务器上的资源, + 在缓存有效时间内,代理服务器不再向原始服务器获取新的资源,返回代理服务为缓存的资源副本。 +::: + + +## 主要的HTTP Headers + +- 通用首部字段 + + | 字段 | 说明 | + | -- | -- | + | Cache-Control | 控制缓存行为 | + | Pragma | http1.0时代的产物,值为 no-cache 时禁用缓存 | + +- 请求头部字段 Request Headers + + | 字段 | 说明 | + | -- | -- | + | If-Match | 比较 ETag 是否一致 | + | If-None-Match | 比较 ETag 是否不一致 | + | If-Modified-Since | 比较资源最后更新时间是否一致 | + | If-Unmodified-Since | 比较资源最后更新时间是否不一致 | + +- 响应头部字段 Response Headers + + | 字段 | 说明 | + | -- | -- | + | ETag | 资源匹配信息 | + +- 实体头部字段 + + | 字段 | 说明 | + | -- | -- | + | Expires | http1.0时代的产物,实体主体过期时间 | + | Last-Modified | 资源的最后一次更新时间 | + + + +::: warning 提醒 +`Pragma`、`Expires` 这两个header是 http1.0中的内容,在 http1.1及往后的版本中逐步被弃用。 + +但为了能够对浏览器向下兼容,大多数网站在设置 缓存机制时,仍然在 response headers 中保留这两个字段的声明。 + +本文同样也会对这两个字段进行说明,以及为什么http1.1后会使用 `Cache-Control` 代替。 +::: + +::: warning 提醒 +在某些技术文章分享中,常常会直接把这些headers字段各自分类到 强缓存 或 协商缓存中, +个人认为这种简单粗暴的划分方式是有待商榷,就比如`Cache-Control`的不同取值,其行为会根据值表现为强缓存或协商缓存。 +::: + +### Pragma + +`Pragma` 字段仅有一个 `no-cache`的可选值,会告知客户端不要对该资源进行缓存读取,应该每次都向服务器发送资源请求。 + +在客户端使用时,通常做法是在 HTML中加上一个 meta 标签: +``` html +<meta http-equiv="Pragma" content="no-cache"> +``` +::: danger 警告 +- 这个标签声明仅有 IE才能识别含义,其他主流浏览器不兼容。 +- 在IE浏览器中,虽然能够识别含义,但并不一定会在请求Request Header中加上Pragma,但确实会让当前页面每次都发起新请求。 + (仅限页面html文件,页面内使用的其他资源不受影响。) +::: + +在服务端配置为 Response Header 时,浏览器读取到该字段,会禁用缓存行为,后续的对同一资源的请求会重新发起请求而不使用缓存。 + +::: warning 提醒 +由于`Pragma` 在浏览器端的兼容问题,在服务器端又有其他字段能更好的控制缓存行为,Pragma 字段基本已经被抛弃,不再使用, + +*除了部分网站出于兼容性考虑,还会带上该字段。* +::: + + +### Expires + +在 http1.0中,Pragma 用于禁用缓存,也需要有一个字段用于启用缓存和定义缓存时间。Expires 就是用于这个目的。 + +Expires 的值是一个 GMT时间, 如:`Thu Jun 07 2018 14:26:45 GMT`,用于告诉浏览器资源的缓存过期时间,如果还没有超过该时间 +则不发起新的资源请求。 + +在客户端,可以使用 meta标签来告知浏览器缓存时间 +``` html +<meta http-equiv="expires" content="Thu Jun 07 2018 14:26:45 GMT"> +``` +如果希望不走缓存,每次页面请求都发起新的请求,可以把 content 设置为 -1 或 0。 + +::: danger 提醒 +跟 Pragma 字段一样, 该 meta 标签只有 IE 能够正确识别。 +而且该方式仅是告知 IE 缓存时间的标记,并不能在 Request Header 中找到该字段。 +::: + +服务端在 Response Headers 中设置 Expires 字段,则在任何浏览器中都能正确设置资源缓存时间; + +::: info 说明 +如果同时使用 Pragma 和 Expires 字段, 则 Pragma 优先级会更好,页面会发起新的请求 +::: + +::: warning 提醒 +Expires 字段虽然能够定义缓存有效时间,但是这个时间的设置是相对于本地时间的。 +如果在服务端定义,则这个时间是相对于服务端时间的, +这个时间返回到客户端, 客户端是拿着客户端的本地时间与返回的服务端时间做对比。 +那么就会导致一种情况,当用户更改了客户端的时间,如超过了 Expires定义的缓存时间,那么缓存就立即失效了。 + +也正是应该存在着这样的问题,Expires并不能保证缓存能够达到预期的表现,所以也被逐步弃用。 +::: + +### Cache-Control + +`Cache-Control` 是从 `http1.1` 开始支持的 header 属性,该属性的值描述了使用缓存的行为以及缓存的有效时间。 + +`Cache-Control` 可以在 发起请求时,在`Request Headers` 中声明该属性,(如果资源请求是通过代理服务器再到原始服务器,) +通知代理服务器对资源的缓存方式,以及是否向原始服务器请求最新的资源。 + +`Cache-Control` 做为 `Response Headers` 属性返回时,通知浏览器对该资源的缓存方式和有效时间。 + +Cache-Control 语法如下: +``` +Cache-Control: <cache-directive> +``` + +- 作为 `Request Headers` 时, `cache-directive` 支持以下可选值 + +| 字段名称 | 说明 | +| -- | -- | +| no-cache | 告知(代理)服务器不直接使用缓存,要求从原始服务器发起请求 | +| no-store | 所有内容都不会被保存到缓存或 Internet临时文件中 | +| max-age=delta-seconds | 告知服务器 客户端希望接收一个存在时间(age)不大于 delta-seconds 秒的资源| +| max-stale\[=delta-seconds] | 告知(代理)服务器 客户端愿意接收一个超过缓存时间的资源,若有定义delta-seconds,则为delta-seconds秒,若没有则为超过任意时间 | +| min-fresh=delta-seconds | 告知(代理)服务器 客户端希望接收一个在delta-seconds秒内被更新过的资源 | +| no-transform | 告知(代理)服务器 客户端希望获取一个实体数据没有被转换(如压缩)过的资源 | +| only-if-cached | 告知(代理)服务器 客户端希望获取缓存的资源(若有),而不用向原服务器发起请求 | + +- 作为 `Response Headers`时,`cache-directive` 支持以下可选值 + +| 字段名称 | 说明 | +| -- | -- | +| public | 表明任何情况下都需要缓存该资源 | +| private[="file-name"] | 表明返回报文中全部或部分(若指定了*file-name*的字段数据)仅开放给某些用户(服务器指定的*share-use*)做缓存使用,其他用户则不能缓存这些数据 | +| no-cache | 不直接使用缓存,要求向服务器发起(新鲜度校验)请求 | +| no-store | 所有内容都不会被保存到缓存或 Internet临时文件中 | +| max-age=delta-seconds | 告知客户端该资源在*delta-seconds*秒内是新鲜的,无需向服务器发起请求 | +| s-max-age=delta-seconds| 同 max-age,但仅应用于 共享缓存 | +| no-transform | 告知客户端缓存文件时不得对实体数据做任何改变 | +| must-revalidate | 当前资源一定是向原始服务器发去验证请求的,若请求失败会返回504(而非代理服务器上的缓存) | +| proxy-revalidate | 和 must-revalidate类似,但仅应用于 共享缓存 | + + +- 可以直接在 HTML页面的`<head>` 中通过 meta标签来给请求头加上 `Cache-Control` 字段: + + ``` html + <meta http-equiv="Cache-Control" content="no-cache"> + ``` + +- `Cache-Control` 允许自由组合可选值: + ``` + Cache-Control: max-age=3600, must-revalidate + ``` + 这段声明表示,该资源必须从原始服务器获取,且其缓存有效时间为一个小时,在后续的一个小时内,用户重新访问该资源都无需发送请求。 + +### 缓存校验 + +`Pragma`、`Expires`、`Cache-Control` 字段能够让客户端决定是否向服务器发送请求,缓存未过期的从本地缓存获取资源,缓存过期的从服务器端获取资源。 + +但是,客户端向服务器发送了请求,是否以为着一定要读取并返回该资源的实体内容? + +- 如果一个资源在客户端的缓存时间过期了,但服务器并没有更新过这个资源,那服务端是否一定要重新把资源的实体内容返回? + +- 如果这个资源过大,虽然缓存过期,但又没有更新过,返回实体内容是否会浪费带宽和时间? + +对于这些问题,其实只要采取某种策略,让服务器知道客户端现在保存的缓存文件跟服务端的资源文件是一致的, +然后通知客户端该资源可以继续使用缓存文件,不需要重新返回资源实体内容。 +那么就可以解决上述的问题,同时为HTTP请求带来优化和加速。 + +http1.1 新增了 `Last-Modified`、`ETag`、 `If-Match`、`If-None-Match`、`If-Modified-Since`、 +`If-Unmodified-Since` 这些字段,用于对缓存资源的校验,提高缓存的复用率。 + +### Last-Modified + +服务器将资源发送给客户端时,会将资源的最后更新时间以如下格式加载实体首部,一起返回给客户端。 + +客户端会为该资源标记上该信息,下次在请求时,会把该信息添加在请求报文中发送给服务端去做检查。 +如果客户端上报字段时间值和服务端的对应资源的最后修改时间一致,则说明改资源没有被修改过,直接返回 304状态码。 + +客户端在上报 Last-Modified 时,可以使用的 Request Headers 字段有两个: + +- `If-Modified-Since`: 该字段格式如下 + ``` + If-Modified-Since: <Last-Modified-Value> + ``` + 字段告诉服务端,如果客户端上报的最后修改时间和服务器上的最后修改时间一致,则直接返回304和响应报头即可。 + + 当前各浏览器默认使用该字段用来向服务端上报保存的 Last-Modified 值。 + +- `If-Unmodified-Since`: 该字段格式如下 + ``` + If-Unmodified-Since: <Last-Modified-Value> + ``` + 字段告诉服务端,如果客户端上报的最后修改时间和服务端上的最后修改时间不一致, + 则应当返回 412(Precondition Failed)状态码给客户端。 + +Last-Modified 由于是使用的资源最后修改时间来确定资源是否有被修改, +但是在实际情况中,往往存在着一个资源被修改了但实际内容没有发生改变, +而由于资源最后修改时间已经发生改变,依然会返回整个实体内容给客户端,而其实内容跟客户端缓存内容一致。 + +### ETag + +为了解决 `Last-Modified` 可能存在的不准确的问题,http1.1 还推出了 ETag 实体首部字段。 + +服务器会通过某种算法,给资源计算得出一个唯一标识符,在把资源响应给客户端的时候,会在实体首部加上该字段一起返回给客户端。 +``` +ETag: ETag-Value +``` + +客户端为资源标记上该信息,下次在请求时,会把该信息添加在请求报文中发送给服务端去做检查。 +服务端只需要比较客户端传来的ETag和对应的该资源的ETag是否一致,就可以判断资源相对于客户端资源是否被修改过。 +如果ETag是一致的,那么就直接返回304状态码,否则就返回新的资源实体内容给客户端。 + +客户端在上报 ETag 时,可以使用的 Request Headers 字段有两个: + +- `If-None-Match` 该字段格式如下 + ``` + If-None-Match: <ETag-Value> + ``` + 字段告诉服务端,如果ETag没有匹配上,需要重新返回新的资源实体内容,否则直接返回 304 状态码。 + + 当前各浏览器默认使用该字段用来向服务端上报保存的 ETag 值。 + +- `If-Match` 该字段格式如下 + ``` + If-Match: <ETag-Value> + ``` + 字段告诉服务端,如果ETag没匹配到,或者收到了`"*"`值而当前没有该资源实体, + 则应当返回412(Precondition Failed)状态码给客户端。否则服务器直接忽略该字段。 + +::: tip 提醒 +如果 `Last-Modified` 和 `ETag` 同时被使用,则要求它们的验证必须同时通过才返回 304, +若其中一个没有通过,则服务器会按照常规返回资源的实体以及200状态码。 +::: + +## 次要的 HTTP Headers + +以下的字段虽然跟缓存有关系,但没有那么重要。 + +### Vary + +`Vary` 表示 服务端会以什么基准字段来区分、筛选缓存版本。 + +首先考虑一个问题,服务端有一个请求地址,如果是IE用户则返回针对IE开发的内容,否则返回另一个主流浏览器版本的内容。 + +一般来说,服务端获取到请求的 `User-Agent` 字段做处理即可。 +但是如果用户请求的是代理服务器而非原始服务器,且代理服务器如果直接把缓存的IE版本资源发给了非IE的客户端,那就出问题了。 + +而 Vary 则是用于处理这类问题的头部字段,只需要在响应报文加上: +``` +Vary: User-Agent +``` +字段告知代理服务器需要以 User-Agent 这个请求头部字段来区别缓存版本,确定传递给客户端的版本。 + +Vary 字段也接受条件组合的形式 +``` +Vary: User-Agent, Accept-Encoding +``` +字段告知代理服务器需要以 User-Agent 和 Accept-Encoding 两个请求头部字段来区别缓存版本。 + +### Date、Age + +Date 字段表示原始服务器发送该资源的响应报文时间(GMT时间)。 +该字段的作用可以帮助我们判断该资源命中的是原始服务器还是代理服务器。 + +- 如果`Date`的时间与当前时间差别较大,或者连续F5刷新发现Date值没有变化,那么说明当前请求命中的是代理服务器的缓存。 +- 如果每次刷新页面,浏览器每次都会重新发起这条请求,那么其Date的值会不断变化,说明该资源是直接从原始服务器返回的。 + +Age 字段表示某个文件在代理服务器中存在的时间(秒),如果文件被修改或替换,Age会重新从0开始累计。 + + +## 浏览器表现 + +### 强缓存 + +对于强缓存的资源: + +- 当用户第一次访问该资源时,服务器返回 200状态码,以及资源实体内容。 + +- 如果用户访问完第一次后,在没有关闭浏览器的前提下,进行了第二次或更多次资源访问,那么浏览器不再请求服务器, + 而是从 浏览器的内存缓存区取出资源,并且 状态码 标记为 `200 (memory cache)` + +- 如果用户访问完第一次后,关闭浏览器后,重新打开浏览器,进行第二次或更多次资源访问,那么浏览器也不会请求服务器, +- 而是从 浏览器的磁盘缓存区取出资源,并且 状态码 标记为 `200(disk cache)` + +### 协商缓存 + +- 当用户第一次访问该资源时,服务器返回 200状态码,以及资源实体内容。 + +- 如果用户进行第二次访问时,进行缓存校验。 或在缓存时间内,或 资源未被修改,那么 直接返回 304状态码 +- 如果用户进行第二次访问时,服务器资源已被更新,则返回 状态码 200 ,以及新的资源实体内容。 diff --git a/docs/1.前端/9.框架/一些好玩的库或者框架汇总.md b/docs/1.前端/9.框架/一些好玩的库或者框架汇总.md new file mode 100644 index 00000000..6e5f3e3c --- /dev/null +++ b/docs/1.前端/9.框架/一些好玩的库或者框架汇总.md @@ -0,0 +1,165 @@ +--- +title: 一些好玩的库或者框架汇总 +createTime: 2022/05/27 09:16:16 +author: pengzhanbo +permalink: /article/ci39ae1o/ +--- + +这里收集了一些各种类型的好玩的库或者框架。 + +<!-- more --> + +---- + +## Client Framework + +### Lit + +[![](https://lit.dev/images/logo.svg){style="width:40px"}](https://lit.dev/) + +**lit** 是一个简单的、高效的、用于构建 web component 的轻量级库。 + +它替代了 [polymer](https://github.com/Polymer/polymer) 成为 WebComponent/customElement开发的首选库。 + +::: code-tabs +@tab my-element.ts +```ts +import { LitElement, html, css } from 'lit'; +import { customElement, property } from 'lit/decorators.js'; + +@customElement("my-element") +export class MyTimer extends LitElement { + static styles = css`...`; + + @property() count = 0; + + render() { + return html`<div>${this.count}</div>`; + } +} +``` +@tab index.html +```html +<!doctype html> +<head>...</head> +<body> + <my-timer count="7"></my-timer> +</body> +``` +::: + + +### solid-js + +[solid-js](https://www.solidjs.com/) + +一个用于构建用户界面,简单高效、性能卓越的JavaScript库。 + +Solid 站在 React, Knockout 等巨人的肩膀上。如果你之前用 React Hooks 开发过,Solid 应该看起来很自然。事实上,Solid 模型更简单,没有 Hook 规则。每个组件执行一次,随着依赖项的更新,钩子和绑定会多次执行。 + +Solid 遵循与 React 相同的理念,具有单向数据流、读/写隔离和不可变接口。但是放弃了使用虚拟 DOM,使用了完全不同的实现。 + +> 号称比 react 还 react 的库 + +```ts +import { render } from "solid-js/web"; +import { onCleanup, createSignal } from "solid-js"; + +const CountingComponent = () => { + const [count, setCount] = createSignal(0); + const interval = setInterval( + () => setCount(count => count + 1), + 1000 + ); + onCleanup(() => clearInterval(interval)); + return <div>Count value is {count()}</div>; +}; + +render(() => <CountingComponent />, document.getElementById("app")); +``` + +### inferno + +[inferno](https://www.infernojs.org/) 是一个快速的、类似于 React 的库,用于在客户端和服务器上构建高性能用户界面。 + +```tsx +import { render, Component } from 'inferno'; + +class MyComponent extends Component { + constructor(props) { + super(props); + this.state = { + counter: 0 + }; + } + render() { + return ( + <div> + <h1>Header!</h1> + <span>Counter is at: { this.state.counter }</span> + </div> + ); + } +} + +render( + <MyComponent />, + document.getElementById("app") +); +``` + +### cycle-js + +[cycle.js](https://cycle.js.org/) + +Cycle.js是一个极简的JavaScript框架,提供了一种函数式,响应式的人机交互接口。 + +Cycle.js 有别于其他如 React/Vue 等框架,它提供的是一套完整的开发范式,需要在其范式基础上进行开发,相对来说并不 +容易入门,但其函数式、响应式的思想,会带来非常好的启示和学习。 + +```js +import {run} from '@cycle/run' +import {div, label, input, hr, h1, makeDOMDriver} from '@cycle/dom' + +function main(sources) { + const input$ = sources.DOM.select('.field').events('input') + + const name$ = input$.map(ev => ev.target.value).startWith('') + + const vdom$ = name$.map(name => + div([ + label('Name:'), + input('.field', {attrs: {type: 'text'}}), + hr(), + h1('Hello ' + name), + ]) + ) + + return { DOM: vdom$ } +} + +run(main, { DOM: makeDOMDriver('#app-container') }) +``` + + +### svelte + +[svelte](https://svelte.dev/) + +Svelte 是一种全新的构建用户界面的方法。传统框架如 React 和 Vue 在浏览器中需要做大量的工作,而 Svelte 将这些工作放到构建应用程序的编译阶段来处理。 + +与使用虚拟(virtual)DOM 差异对比不同。Svelte 编写的代码在应用程序的状态更改时就能像做外科手术一样更新 DOM。 + +```html +<script> + let count = 0; + + function handleClick() { + count += 1; + } +</script> + +<button on:click={handleClick}> + Clicked {count} {count === 1 ? 'time' : 'times'} +</button> +``` diff --git a/docs/10.面试/面试2.md b/docs/10.面试/面试2.md index d5f34b0a..06aabfef 100644 --- a/docs/10.面试/面试2.md +++ b/docs/10.面试/面试2.md @@ -1,6 +1,6 @@ --- title: 面试2 -createTime: 2022/04/04 01:48:00 +createTime: 2022/04/03 17:48:00 author: pengzhanbo permalink: /article/exavsmm1 --- diff --git a/docs/10.面试/面试题-JS篇.md b/docs/10.面试/面试题-JS篇.md index a849db66..571bc330 100644 --- a/docs/10.面试/面试题-JS篇.md +++ b/docs/10.面试/面试题-JS篇.md @@ -2,7 +2,7 @@ title: 面试题以及个人答案 JS篇 tags: - 面试 -createTime: 2018/08/23 11:15:27 +createTime: 2022/03/26 11:46:50 permalink: /article/4ml7z17g author: pengzhanbo top: false diff --git a/docs/10.面试/面试题—css篇.md b/docs/10.面试/面试题—css篇.md index 1a506875..5a8bdc91 100644 --- a/docs/10.面试/面试题—css篇.md +++ b/docs/10.面试/面试题—css篇.md @@ -2,7 +2,7 @@ title: 面试题以及个人答案 CSS篇 tags: - 面试 -createTime: 2018/08/22 11:15:27 +createTime: 2022/03/26 11:46:50 permalink: /article/565o1wn0 author: pengzhanbo top: false diff --git a/docs/README.md b/docs/README.md index 219152e7..19d4dede 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1,5 +1,17 @@ --- home: true -banner: /images/big-banner.jpg -motto: 世间的美好总是不期而遇,恬静而自然。 +banner: /images/bg-home.jpg +hero: + name: 鹏展博 + profession: 前端开发工程师 + text: 简单介绍专业技能信息相关的描述 + actions: + - + theme: brand + text: Blog + link: / + - + theme: alt + text: Github + link: / --- diff --git a/docs/home-banner.jpg b/docs/home-banner.jpg new file mode 100644 index 00000000..f81731a9 Binary files /dev/null and b/docs/home-banner.jpg differ diff --git a/docs/notes/vuepress-plugin/netlify-functions/API.md b/docs/notes/vuepress-plugin/netlify-functions/API.md index 59198b1a..6943f8d1 100644 --- a/docs/notes/vuepress-plugin/netlify-functions/API.md +++ b/docs/notes/vuepress-plugin/netlify-functions/API.md @@ -1,6 +1,6 @@ --- title: API -createTime: 2022/05/13 05:49:14 +createTime: 2022/05/14 10:43:53 author: pengzhanbo permalink: /note/vuepress-plugin/netlify-functions/api/ --- @@ -83,4 +83,3 @@ __类型:__ `{ directory: string }` 一般来说,它的值都设置为 `path.resolve(__dirname, 'functions')` - diff --git a/docs/notes/vuepress-plugin/netlify-functions/functions开发指南.md b/docs/notes/vuepress-plugin/netlify-functions/functions开发指南.md index 6e8cbde5..5b15a64e 100644 --- a/docs/notes/vuepress-plugin/netlify-functions/functions开发指南.md +++ b/docs/notes/vuepress-plugin/netlify-functions/functions开发指南.md @@ -1,6 +1,6 @@ --- title: functions开发指南 -createTime: 2022/05/13 05:45:24 +createTime: 2022/05/14 10:43:53 author: pengzhanbo permalink: /note/vuepress-plugin/netlify-functions/develop-functions/ --- diff --git a/docs/notes/vuepress-plugin/netlify-functions/介绍.md b/docs/notes/vuepress-plugin/netlify-functions/介绍.md index 758be541..6f6ea714 100644 --- a/docs/notes/vuepress-plugin/netlify-functions/介绍.md +++ b/docs/notes/vuepress-plugin/netlify-functions/介绍.md @@ -1,6 +1,6 @@ --- title: 介绍 -createTime: 2022/05/13 05:47:06 +createTime: 2022/05/14 10:43:53 author: pengzhanbo permalink: /note/vuepress-plugin/netlify-functions/intro/ --- diff --git a/docs/notes/vuepress-plugin/netlify-functions/使用.md b/docs/notes/vuepress-plugin/netlify-functions/使用.md index cd193237..274204c7 100644 --- a/docs/notes/vuepress-plugin/netlify-functions/使用.md +++ b/docs/notes/vuepress-plugin/netlify-functions/使用.md @@ -1,6 +1,6 @@ --- title: 使用 -createTime: 2022/05/13 05:45:01 +createTime: 2022/05/14 10:43:53 author: pengzhanbo permalink: /note/vuepress-plugin/netlify-functions/usage/ --- diff --git a/docs/notes/vuepress-plugin/netlify-functions/功能.md b/docs/notes/vuepress-plugin/netlify-functions/功能.md index 9f6ec622..5d248cfa 100644 --- a/docs/notes/vuepress-plugin/netlify-functions/功能.md +++ b/docs/notes/vuepress-plugin/netlify-functions/功能.md @@ -1,6 +1,6 @@ --- title: 功能 -createTime: 2022/05/13 05:45:11 +createTime: 2022/05/14 10:43:53 author: pengzhanbo permalink: /note/vuepress-plugin/netlify-functions/feature/ --- diff --git a/docs/notes/vuepress-theme-plume/markdown增强.md b/docs/notes/vuepress-theme-plume/markdown增强.md index 789f80dd..3f4199e7 100644 --- a/docs/notes/vuepress-theme-plume/markdown增强.md +++ b/docs/notes/vuepress-theme-plume/markdown增强.md @@ -1,6 +1,6 @@ --- title: markdown增强 -createTime: 2022/04/09 06:43:32 +createTime: 2022/05/14 10:43:53 author: pengzhanbo permalink: /note/vuepress-theme-plume/markdown-enhance/ --- diff --git a/docs/notes/vuepress-theme-plume/notes配置.md b/docs/notes/vuepress-theme-plume/notes配置.md index fce08199..9185eb46 100644 --- a/docs/notes/vuepress-theme-plume/notes配置.md +++ b/docs/notes/vuepress-theme-plume/notes配置.md @@ -1,6 +1,6 @@ --- title: notes配置 -createTime: 2022/04/09 02:48:41 +createTime: 2022/05/14 10:43:53 author: pengzhanbo permalink: /note/vuepress-theme-plume/notes-config/ --- diff --git a/docs/notes/vuepress-theme-plume/主题插件配置.md b/docs/notes/vuepress-theme-plume/主题插件配置.md index 7eb84cdd..f8789b44 100644 --- a/docs/notes/vuepress-theme-plume/主题插件配置.md +++ b/docs/notes/vuepress-theme-plume/主题插件配置.md @@ -1,6 +1,6 @@ --- title: 主题插件配置 -createTime: 2022/04/09 02:48:30 +createTime: 2022/05/14 10:43:53 author: pengzhanbo permalink: /note/vuepress-theme-plume/plugins-config/ --- diff --git a/docs/notes/vuepress-theme-plume/主题配置.md b/docs/notes/vuepress-theme-plume/主题配置.md index a685236c..0ba8d031 100644 --- a/docs/notes/vuepress-theme-plume/主题配置.md +++ b/docs/notes/vuepress-theme-plume/主题配置.md @@ -1,6 +1,6 @@ --- title: 主题配置 -createTime: 2022/04/09 12:18:12 +createTime: 2022/05/14 10:43:53 author: pengzhanbo permalink: /note/vuepress-theme-plume/theme-config/ --- diff --git a/docs/notes/vuepress-theme-plume/基础功能.md b/docs/notes/vuepress-theme-plume/基础功能.md index 208c1201..c567f5ee 100644 --- a/docs/notes/vuepress-theme-plume/基础功能.md +++ b/docs/notes/vuepress-theme-plume/基础功能.md @@ -1,6 +1,6 @@ --- title: 基础功能 -createTime: 2022/04/09 06:43:20 +createTime: 2022/05/14 10:43:53 author: pengzhanbo permalink: /note/vuepress-theme-plume/basis-power/ --- diff --git a/docs/notes/vuepress-theme-plume/快速开始.md b/docs/notes/vuepress-theme-plume/快速开始.md index 0ca87d31..367ee0d2 100644 --- a/docs/notes/vuepress-theme-plume/快速开始.md +++ b/docs/notes/vuepress-theme-plume/快速开始.md @@ -1,6 +1,6 @@ --- title: 快速开始 -createTime: 2022/04/08 09:43:20 +createTime: 2022/05/14 10:43:53 author: pengzhanbo permalink: /note/vuepress-theme-plume/quick-start/ --- diff --git a/docs/notes/vuepress-theme-plume/编写文章.md b/docs/notes/vuepress-theme-plume/编写文章.md index c5a1df40..873b1a61 100644 --- a/docs/notes/vuepress-theme-plume/编写文章.md +++ b/docs/notes/vuepress-theme-plume/编写文章.md @@ -1,6 +1,6 @@ --- title: 编写文章 -createTime: 2022/04/09 12:13:56 +createTime: 2022/05/14 10:43:53 author: pengzhanbo permalink: /note/vuepress-theme-plume/write-article/ --- diff --git a/docs/notes/vuepress-theme-plume/页面配置.md b/docs/notes/vuepress-theme-plume/页面配置.md index 2ee0c7b8..4713a448 100644 --- a/docs/notes/vuepress-theme-plume/页面配置.md +++ b/docs/notes/vuepress-theme-plume/页面配置.md @@ -1,6 +1,6 @@ --- title: 页面配置 -createTime: 2022/04/09 01:24:17 +createTime: 2022/05/14 10:43:53 author: pengzhanbo permalink: /note/vuepress-theme-plume/page-config/ --- diff --git a/docs/package.json b/docs/package.json index ccc13643..8ee7ef97 100644 --- a/docs/package.json +++ b/docs/package.json @@ -5,20 +5,20 @@ "scripts": { "docs:build": "vuepress-cli build --clean-cache", "docs:clean": "rimraf .vuepress/.temp .vuepress/.cache .vuepress/dist", - "docs:dev": "vuepress-cli dev --clean-cache", + "docs:dev": "vuepress-cli dev --clean-cache --clean-temp", "docs:serve": "anywhere -s -h localhost -d .vuepress/dist" }, "dependencies": { "@vuepress-plume/vuepress-theme-plume": "workspace:*", - "@vuepress/bundler-vite": "2.0.0-beta.51", - "@vuepress/bundler-webpack": "2.0.0-beta.51", - "@vuepress/cli": "2.0.0-beta.51", - "@vuepress/client": "2.0.0-beta.51", - "@vuepress/utils": "2.0.0-beta.51", + "@vuepress/bundler-vite": "2.0.0-beta.60", + "@vuepress/bundler-webpack": "2.0.0-beta.60", + "@vuepress/cli": "2.0.0-beta.60", + "@vuepress/client": "2.0.0-beta.60", + "@vuepress/utils": "2.0.0-beta.60", "anywhere": "^1.6.0", - "leancloud-storage": "^4.13.2", - "sass": "^1.55.0", - "sass-loader": "^13.1.0", - "vue": "^3.2.41" + "leancloud-storage": "^4.14.0", + "sass": "^1.57.1", + "sass-loader": "^13.2.0", + "vue": "^3.2.47" } } diff --git a/package.json b/package.json index b6248c73..96a185f9 100644 --- a/package.json +++ b/package.json @@ -33,7 +33,8 @@ "release:changelog": "conventional-changelog -p angular -i CHANGELOG.md -s", "release:check": "pnpm lint && pnpm build", "release:publish": "pnpm -r publish", - "release:version": "bumpp package.json packages/*/package.json --execute=\"pnpm release:changelog\" --commit \"build: publish v%s\" --all --tag --push" + "release:version": "bumpp package.json packages/*/package.json --execute=\"pnpm release:changelog\" --commit \"build: publish v%s\" --all --tag --push", + "up": "taze -r major" }, "lint-staged": { "*.{js,ts,vue}": "eslint --fix", @@ -47,37 +48,38 @@ }, "prettier": "prettier-config-vuepress", "devDependencies": { - "@commitlint/cli": "^17.1.2", - "@commitlint/config-conventional": "^17.1.0", + "@commitlint/cli": "^17.4.2", + "@commitlint/config-conventional": "^17.4.2", "@types/minimist": "^1.2.2", - "@types/node": "18.8.0", + "@types/node": "18.11.18", "@types/webpack-env": "^1.18.0", "bumpp": "^8.2.1", - "chalk": "^5.1.2", - "commitizen": "^4.2.5", - "concurrently": "^7.4.0", + "chalk": "^5.2.0", + "commitizen": "^4.2.6", + "concurrently": "^7.6.0", "conventional-changelog-cli": "^2.2.2", "cpx2": "^4.2.0", "cross-env": "^7.0.3", "cz-conventional-changelog": "^3.3.0", - "eslint": "^8.25.0", - "eslint-config-vuepress": "^4.0.3", - "eslint-config-vuepress-typescript": "^4.0.3", + "eslint": "^8.32.0", + "eslint-config-vuepress": "^4.0.4", + "eslint-config-vuepress-typescript": "^4.0.4", "execa": "^6.1.0", "handlebars": "^4.7.7", - "husky": "^8.0.1", - "lint-staged": "^13.0.3", + "husky": "^8.0.3", + "lint-staged": "^13.1.0", "minimist": "^1.2.7", "ora": "^6.1.2", - "pnpm": "^7.13.4", - "prettier": "^2.7.1", + "pnpm": "^7.25.0", + "prettier": "^2.8.3", "prettier-config-vuepress": "^4.0.0", "rimraf": "^3.0.2", - "sort-package-json": "^2.0.0", - "taze": "^0.8.2", + "sort-package-json": "^2.1.0", + "taze": "^0.8.5", "ts-node": "^10.9.1", - "typescript": "^4.8.4", - "vite": "^3.1.8" + "tsconfig-vuepress": "^4.0.4", + "typescript": "^4.9.4", + "vite": "^4.0.4" }, "packageManager": "pnpm@7.13.4", "engines": { diff --git a/packages/theme/LICENSE b/packages/plugin-auto-frontmatter/LICENSE similarity index 100% rename from packages/theme/LICENSE rename to packages/plugin-auto-frontmatter/LICENSE diff --git a/packages/plugin-auto-frontmatter/README.md b/packages/plugin-auto-frontmatter/README.md new file mode 100644 index 00000000..8002176c --- /dev/null +++ b/packages/plugin-auto-frontmatter/README.md @@ -0,0 +1,117 @@ +# `@vuepress-plume/vuepress-plugin-auto-frontmatter` + +自动生成 `*.md` 文件的 `frontmatter` 配置。 + +## Install +``` +yarn add @vuepress-plume/vuepress-plugin-auto-frontmatter +``` +## Usage +``` js +// .vuepress/config.js +import { autoFrontmatterPlugin } from '@vuepress-plume/vuepress-plugin-auto-frontmatter' +export default { + //... + plugins: [ + autoFrontmatterPlugin({ + formatter: { + createTime(formatTime, matter, file) { + if (formatTime) return formatTime + return file.createTime + } + } + }) + ] + // ... +} +``` + +## `autoFrontmatterPlugin([options])` + +### options + +`{ include?: string | string[]; exclude?: string | string[]; formatter: Formatter }` + +- `include` + include 匹配字符串或数组,匹配需要自动生成 `frontmatter` 的 md文件。 + 默认预设为 `['**/*.md']`。 + +- `exclude` + exclude 排除不需要的文件 + 默认预设为: `['!.vuepress/', '!node_modules/']` + +- `formatter` + 配置`frontmatter`每个字段的生成规则。 + ```ts + interface MarkdownFile { + filepath: string + relativePath: string + content: string + createTime: Date + } + + interface FormatterFn<T = any, K = object> { + (value: T, data: K, file: MarkdownFile): T + } + + type FormatterObject<K = object, T = any> = Record< + string, + FormatterFn<T, K> + > + + type FormatterArray = { + include: string + formatter: FormatterObject + }[] + + type Formatter = FormatterObject | FormatterArray + + /** + * formatterObj 对象中的 key 即为 frontmatter 配置中的key + * 其方法返回的值将作为 frontmatter[key] 的值 + * *.md + * --- + * createTime: 2022-03-26T11:46:50.000Z + * --- + */ + const formatterObj: Formatter = { + createTime(formatTime, matter, file) { + if (formatTime) return formatTime + return file.createTime + } + } + + const formatterArr: Formatter = [ + { + // 更精细化的匹配某个 md文件,支持glob 匹配字符串 + include: '**/{README,index}.md', + // formatter 仅对 glob命中的文件有效 + formatter: { + home(value, matter, file) { + return value + } + }, + { + // 通配,如果文件没有被其他精细glob命中, + // 则使用 通配 formatter + // 如果是数组,必须有且用一个 include 为 * 的 项 + include: '*', + formatter: { + title(title) { + return title || '默认标题' + } + } + } + } + ] + + ``` + +## Why ? + +- **为什么需要这个插件?** + + 有时候在开发一些主题时,期望使用户更专注于内容的编写,尽可能减少配置性的工作,可以将一些重复性的必要的配置 + 直接通过本插件自动生成。 + + 以及,我确实想在写新文章的时候,更少的做配置工作,于是便有了这个插件 diff --git a/packages/plugin-auto-frontmatter/package.json b/packages/plugin-auto-frontmatter/package.json new file mode 100644 index 00000000..75993e93 --- /dev/null +++ b/packages/plugin-auto-frontmatter/package.json @@ -0,0 +1,49 @@ +{ + "name": "@vuepress-plume/vuepress-plugin-auto-frontmatter", + "version": "1.0.0-beta.45", + "description": "The Plugin for VuePres 2", + "homepage": "https://github.com/pengzhanbo/vuepress-theme-plume#readme", + "bugs": { + "url": "https://github.com/pengzhanbo/vuepress-theme-plume/issues" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/pengzhanbo/vuepress-theme-plume.git" + }, + "license": "MIT", + "author": "pengzhanbo <volodymyr@foxmail.com>", + "type": "module", + "exports": { + ".": "./lib/node/index.js", + "./package.json": "./package.json" + }, + "main": "lib/node/index.js", + "types": "./lib/node/index.d.ts", + "files": [ + "lib" + ], + "scripts": { + "build": "pnpm run clean && pnpm run copy && pnpm run ts", + "clean": "rimraf lib *.tsbuildinfo", + "copy": "cpx \"src/**/*.{d.ts,vue,css,scss,jpg,png}\" lib", + "ts": "tsc -b tsconfig.build.json" + }, + "dependencies": { + "@vuepress/core": "2.0.0-beta.60", + "@vuepress/shared": "2.0.0-beta.60", + "chokidar": "^3.5.3", + "create-filter": "^1.0.0", + "fast-glob": "^3.2.12", + "gray-matter": "^4.0.3", + "json2yaml": "^1.1.0" + }, + "publishConfig": { + "access": "public" + }, + "keyword": [ + "VuePress", + "vuepress plugin", + "autoFrontmatter", + "vuepress-plugin-plugin-auto-frontmatter" + ] +} diff --git a/packages/theme/src/node/shims.d.ts b/packages/plugin-auto-frontmatter/src/node/env.d.ts similarity index 100% rename from packages/theme/src/node/shims.d.ts rename to packages/plugin-auto-frontmatter/src/node/env.d.ts diff --git a/packages/plugin-auto-frontmatter/src/node/index.ts b/packages/plugin-auto-frontmatter/src/node/index.ts new file mode 100644 index 00000000..9031d476 --- /dev/null +++ b/packages/plugin-auto-frontmatter/src/node/index.ts @@ -0,0 +1,8 @@ +import type { AutoFrontmatterOptions } from '../shared/index.js' +import { autoFrontmatterPlugin } from './plugin.js' + +export * from './plugin.js' + +export { AutoFrontmatterOptions } + +export default autoFrontmatterPlugin diff --git a/packages/plugin-auto-frontmatter/src/node/plugin.ts b/packages/plugin-auto-frontmatter/src/node/plugin.ts new file mode 100644 index 00000000..193a36ce --- /dev/null +++ b/packages/plugin-auto-frontmatter/src/node/plugin.ts @@ -0,0 +1,85 @@ +import fs from 'node:fs' +import type { Plugin } from '@vuepress/core' +import chokidar from 'chokidar' +import { createFilter } from 'create-filter' +import grayMatter from 'gray-matter' +import jsonToYaml from 'json2yaml' +import type { + AutoFrontmatterOptions, + FormatterArray, + FormatterObject, + MarkdownFile, +} from '../shared/index.js' +import { readMarkdown, readMarkdownList } from './readFiles.js' +import { ensureArray } from './utils.js' + +export const autoFrontmatterPlugin = ({ + include = ['**/*.{md,MD}'], + exclude = ['.vuepress/**/*', 'node_modules'], + formatter = {}, +}: AutoFrontmatterOptions = {}): Plugin => { + include = ensureArray(include) + exclude = ensureArray(exclude) + + const globFilter = createFilter(include, exclude, { resolve: false }) + + const matterFormatter: FormatterArray = Array.isArray(formatter) + ? formatter + : [{ include: '*', formatter }] + + const globFormatter: FormatterObject = + matterFormatter.find(({ include }) => include === '*')?.formatter || {} + + const otherFormatters = matterFormatter + .filter(({ include }) => include !== '*') + .map(({ include, formatter }) => { + return { + include, + filter: createFilter(ensureArray(include)), + formatter, + } + }) + + function formatMarkdown(file: MarkdownFile): void { + const { filepath, relativePath } = file + + const formatter = + otherFormatters.find(({ filter }) => filter(relativePath))?.formatter || + globFormatter + const { data, content } = grayMatter(file.content) + + Object.keys(formatter).forEach((key) => { + const value = formatter[key](data[key], data, file) + data[key] = value ?? data[key] + }) + const yaml = jsonToYaml + .stringify(data) + .replace(/\n\s{2}/g, '\n') + .replace(/"/g, '') + const newContent = `${yaml}---\n${content}` + + fs.writeFileSync(filepath, newContent, 'utf-8') + } + + return { + name: '@vuepress-plume/vuepress-plugin-auto-frontmatter', + onInitialized: async (app) => { + const markdownList = await readMarkdownList(app.dir.source(), globFilter) + markdownList.forEach((file) => formatMarkdown(file)) + }, + onWatched: async (app, watchers) => { + const watcher = chokidar.watch('**/*.md', { + cwd: app.dir.source(), + ignoreInitial: true, + ignored: /(node_modules|\.vuepress)\//, + }) + + watcher.on('add', (relativePath) => { + if (!globFilter(relativePath)) return + formatMarkdown(readMarkdown(app.dir.source(), relativePath)) + }) + + watchers.push(watcher) + }, + } +} diff --git a/packages/plugin-auto-frontmatter/src/node/readFiles.ts b/packages/plugin-auto-frontmatter/src/node/readFiles.ts new file mode 100644 index 00000000..fa9e227a --- /dev/null +++ b/packages/plugin-auto-frontmatter/src/node/readFiles.ts @@ -0,0 +1,37 @@ +import fs from 'node:fs' +import path from 'node:path' +import fg from 'fast-glob' +import type { MarkdownFile } from '../shared/index.js' + +type MarkdownFileList = MarkdownFile[] + +export const readMarkdownList = async ( + sourceDir: string, + filter: (id: string) => boolean +): Promise<MarkdownFileList> => { + const files: string[] = await fg(['**/*.md'], { + cwd: sourceDir, + ignore: ['node_modules', '.vuepress'], + }) + + return files + .filter((file) => filter(file)) + .map((file) => readMarkdown(sourceDir, file)) +} + +export const readMarkdown = ( + sourceDir: string, + relativePath: string +): MarkdownFile => { + const filepath = path.join(sourceDir, relativePath) + return { + filepath, + relativePath, + content: fs.readFileSync(filepath, 'utf-8'), + createTime: getFileCreateTime(fs.statSync(filepath)), + } +} + +export const getFileCreateTime = (stat: fs.Stats): Date => { + return stat.birthtime.getFullYear() !== 1970 ? stat.birthtime : stat.atime +} diff --git a/packages/plugin-auto-frontmatter/src/node/utils.ts b/packages/plugin-auto-frontmatter/src/node/utils.ts new file mode 100644 index 00000000..981a3c67 --- /dev/null +++ b/packages/plugin-auto-frontmatter/src/node/utils.ts @@ -0,0 +1,5 @@ +export function ensureArray<T>(thing: T | T[] | null | undefined): T[] { + if (Array.isArray(thing)) return thing + if (thing === null || thing === undefined) return [] + return [thing] +} diff --git a/packages/plugin-auto-frontmatter/src/shared/index.ts b/packages/plugin-auto-frontmatter/src/shared/index.ts new file mode 100644 index 00000000..c02c2680 --- /dev/null +++ b/packages/plugin-auto-frontmatter/src/shared/index.ts @@ -0,0 +1,38 @@ +export interface MarkdownFile { + filepath: string + relativePath: string + content: string + createTime: Date +} + +export interface FormatterFn<T = any, K = object> { + (value: T, data: K, file: MarkdownFile): T +} + +export type FormatterObject<K = object, T = any> = Record< + string, + FormatterFn<T, K> +> + +export type FormatterArray = { + include: string + formatter: FormatterObject +}[] + +export interface AutoFrontmatterOptions { + /** + * FilterPattern + */ + include?: string | string[] + + exclude?: string | string[] + + /** + * { + * key(value, data, file) { + * return value + * } + * } + */ + formatter?: FormatterObject | FormatterArray +} diff --git a/packages/plugin-auto-frontmatter/tsconfig.build.json b/packages/plugin-auto-frontmatter/tsconfig.build.json new file mode 100644 index 00000000..e4e8ce38 --- /dev/null +++ b/packages/plugin-auto-frontmatter/tsconfig.build.json @@ -0,0 +1,9 @@ +{ + "extends": "../tsconfig.build.json", + "compilerOptions": { + "rootDir": "./src", + "outDir": "./lib" + }, + "include": ["./src"], + "files": [] +} diff --git a/packages/plugin-baidu-tongji/package.json b/packages/plugin-baidu-tongji/package.json index ce7c76b4..873aabc9 100644 --- a/packages/plugin-baidu-tongji/package.json +++ b/packages/plugin-baidu-tongji/package.json @@ -29,10 +29,10 @@ "ts": "tsc -b tsconfig.build.json" }, "dependencies": { - "@vuepress/client": "2.0.0-beta.51", - "@vuepress/core": "2.0.0-beta.51", - "@vuepress/shared": "2.0.0-beta.51", - "@vuepress/utils": "2.0.0-beta.51" + "@vuepress/client": "2.0.0-beta.60", + "@vuepress/core": "2.0.0-beta.60", + "@vuepress/shared": "2.0.0-beta.60", + "@vuepress/utils": "2.0.0-beta.60" }, "publishConfig": { "access": "public" diff --git a/packages/plugin-baidu-tongji/tsconfig.build.json b/packages/plugin-baidu-tongji/tsconfig.build.json index 3395ea55..9a9c1efa 100644 --- a/packages/plugin-baidu-tongji/tsconfig.build.json +++ b/packages/plugin-baidu-tongji/tsconfig.build.json @@ -2,7 +2,8 @@ "extends": "../../tsconfig.base.json", "compilerOptions": { "rootDir": "./src", - "outDir": "./lib" + "outDir": "./lib", + "composite": true }, "include": ["./src"], "files": [] diff --git a/packages/plugin-blog-data/LICENSE b/packages/plugin-blog-data/LICENSE new file mode 100644 index 00000000..9f677c90 --- /dev/null +++ b/packages/plugin-blog-data/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (C) 2021 - PRESENT by pengzhanbo + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/packages/plugin-blog-data/package.json b/packages/plugin-blog-data/package.json new file mode 100644 index 00000000..d50c2cf3 --- /dev/null +++ b/packages/plugin-blog-data/package.json @@ -0,0 +1,51 @@ +{ + "name": "@vuepress-plume/vuepress-plugin-blog-data", + "version": "1.0.0-beta.45", + "description": "The Plugin for VuePres 2", + "homepage": "https://github.com/pengzhanbo/vuepress-theme-plume#readme", + "bugs": { + "url": "https://github.com/pengzhanbo/vuepress-theme-plume/issues" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/pengzhanbo/vuepress-theme-plume.git" + }, + "license": "MIT", + "author": "pengzhanbo <volodymyr@foxmail.com>", + "type": "module", + "exports": { + ".": "./lib/node/index.js", + "./client": "./lib/client/index.js", + "./package.json": "./package.json" + }, + "main": "lib/node/index.js", + "types": "./lib/node/index.d.ts", + "files": [ + "lib" + ], + "scripts": { + "build": "pnpm run clean && pnpm run copy && pnpm run ts", + "clean": "rimraf lib *.tsbuildinfo", + "copy": "cpx \"src/**/*.{d.ts,vue,css,scss,jpg,png}\" lib", + "ts": "tsc -b tsconfig.build.json" + }, + "dependencies": { + "@vue/devtools-api": "^6.4.5", + "@vuepress/client": "2.0.0-beta.60", + "@vuepress/core": "2.0.0-beta.60", + "@vuepress/shared": "2.0.0-beta.60", + "@vuepress/utils": "2.0.0-beta.60", + "chokidar": "^3.5.3", + "create-filter": "^1.0.0", + "vue": "^3.2.47" + }, + "publishConfig": { + "access": "public" + }, + "keyword": [ + "VuePress", + "vuepress plugin", + "blogData", + "vuepress-plugin-plugin-blog-data" + ] +} diff --git a/packages/plugin-blog-data/src/client/blogPostData.d.ts b/packages/plugin-blog-data/src/client/blogPostData.d.ts new file mode 100644 index 00000000..52fa5598 --- /dev/null +++ b/packages/plugin-blog-data/src/client/blogPostData.d.ts @@ -0,0 +1,7 @@ +import type { BlogPostData } from '../shared/index.js' + +declare module '@internal/blogData' { + const blogPostData: BlogPostData + + export { blogPostData } +} diff --git a/packages/plugin-blog-data/src/client/composables/index.ts b/packages/plugin-blog-data/src/client/composables/index.ts new file mode 100644 index 00000000..43aec1ef --- /dev/null +++ b/packages/plugin-blog-data/src/client/composables/index.ts @@ -0,0 +1 @@ +export * from './useBlogPostData.js' diff --git a/packages/plugin-blog-data/src/client/composables/useBlogPostData.ts b/packages/plugin-blog-data/src/client/composables/useBlogPostData.ts new file mode 100644 index 00000000..222caea7 --- /dev/null +++ b/packages/plugin-blog-data/src/client/composables/useBlogPostData.ts @@ -0,0 +1,20 @@ +import { blogPostData as blogPostDataRaw } from '@internal/blogData' +import { ref } from 'vue' +import type { Ref } from 'vue' +import type { BlogPostData } from '../../shared/index.js' + +declare const __VUE_HMR_RUNTIME__: Record<string, any> + +export type BlogDataRef<T extends BlogPostData = BlogPostData> = Ref<T> + +export const blogPostData: BlogDataRef = ref(blogPostDataRaw) + +export const useBlogPostData = < + T extends BlogPostData = BlogPostData +>(): BlogDataRef<T> => blogPostData as BlogDataRef<T> + +if (import.meta.webpackHot || import.meta.hot) { + __VUE_HMR_RUNTIME__.updateBlogData = (data: BlogPostData) => { + blogPostData.value = data + } +} diff --git a/packages/plugin-blog-data/src/client/config.ts b/packages/plugin-blog-data/src/client/config.ts new file mode 100644 index 00000000..162c3523 --- /dev/null +++ b/packages/plugin-blog-data/src/client/config.ts @@ -0,0 +1,37 @@ +import { setupDevtoolsPlugin } from '@vue/devtools-api' +import { defineClientConfig } from '@vuepress/client' +import { useBlogPostData } from './composables/index.js' + +declare const __VUE_PROD_DEVTOOLS__: boolean + +export default defineClientConfig({ + enhance({ app }) { + const blogPostData = useBlogPostData() + + // setup devtools in dev mode + if (__VUEPRESS_DEV__ || __VUE_PROD_DEVTOOLS__) { + setupDevtoolsPlugin( + { + // fix recursive reference + app: app as any, + id: 'org.vuepress-plume.plugin-blog-data', + label: 'VuePress Blog Data Plugin', + packageName: '@vuepress/plugin-blog-data', + homepage: 'https://pengzhanbo.cn', + logo: 'https://v2.vuepress.vuejs.org/images/hero.png', + componentStateTypes: ['VuePress'], + }, + (api) => { + api.on.inspectComponent((payload) => { + payload.instanceData.state.push({ + type: 'VuePress', + key: 'blogPostData', + editable: false, + value: blogPostData.value, + }) + }) + } + ) + } + }, +}) diff --git a/packages/plugin-blog-data/src/client/index.ts b/packages/plugin-blog-data/src/client/index.ts new file mode 100644 index 00000000..b9acdbce --- /dev/null +++ b/packages/plugin-blog-data/src/client/index.ts @@ -0,0 +1,4 @@ +import type { BlogPostData, BlogPostDataItem } from '../shared/index.js' +export * from './composables/index.js' + +export { BlogPostData, BlogPostDataItem } diff --git a/packages/plugin-blog-data/src/node/index.ts b/packages/plugin-blog-data/src/node/index.ts new file mode 100644 index 00000000..289ed329 --- /dev/null +++ b/packages/plugin-blog-data/src/node/index.ts @@ -0,0 +1,6 @@ +import { blogDataPlugin } from './plugin.js' + +export * from '../shared/index.js' +export { blogDataPlugin } + +export default blogDataPlugin diff --git a/packages/plugin-blog-data/src/node/plugin.ts b/packages/plugin-blog-data/src/node/plugin.ts new file mode 100644 index 00000000..e7ed341f --- /dev/null +++ b/packages/plugin-blog-data/src/node/plugin.ts @@ -0,0 +1,58 @@ +import type { Plugin } from '@vuepress/core' +import { getDirname, path } from '@vuepress/utils' +import chokidar from 'chokidar' +import { createFilter } from 'create-filter' +import { preparedBlogData } from './prepareBlogData.js' +import type { BlogDataPluginOptions } from './index.js' + +const __dirname = getDirname(import.meta.url) + +export type PluginOption = Omit<BlogDataPluginOptions, 'include' | 'exclude'> + +export const blogDataPlugin = ({ + include, + exclude, + ...pluginOptions +}: BlogDataPluginOptions = {}): Plugin => { + const pageFilter = createFilter(toArray(include), toArray(exclude), { + resolve: false, + }) + + return { + name: '@vuepress-plume/vuepress-plugin-blog-data', + clientConfigFile: path.resolve(__dirname, '../client/config.js'), + extendsPage(page) { + if (page.filePathRelative && pageFilter(page.filePathRelative)) { + ;(page.data as any).isBlogPost = true + } + }, + onPrepared: async (app) => + await preparedBlogData(app, pageFilter, pluginOptions), + onWatched(app, watchers) { + const watcher = chokidar.watch('pages/**/*', { + cwd: app.dir.temp(), + ignoreInitial: true, + }) + + watcher.on( + 'add', + async () => await preparedBlogData(app, pageFilter, pluginOptions) + ) + watcher.on( + 'change', + async () => await preparedBlogData(app, pageFilter, pluginOptions) + ) + watcher.on( + 'unlink', + async () => await preparedBlogData(app, pageFilter, pluginOptions) + ) + + watchers.push(watcher) + }, + } +} + +function toArray(likeArr: string | string[] | undefined): string[] { + if (Array.isArray(likeArr)) return likeArr + return likeArr ? [likeArr] : [] +} diff --git a/packages/plugin-blog-data/src/node/prepareBlogData.ts b/packages/plugin-blog-data/src/node/prepareBlogData.ts new file mode 100644 index 00000000..ed045732 --- /dev/null +++ b/packages/plugin-blog-data/src/node/prepareBlogData.ts @@ -0,0 +1,81 @@ +import type { App, Page } from '@vuepress/core' +import type { BlogPostData, BlogPostDataItem } from '../shared/index.js' +import type { PluginOption } from './plugin.js' + +const HMR_CODE = ` +if (import.meta.webpackHot) { + import.meta.webpackHot.accept() + if (__VUE_HMR_RUNTIME__.updateBlogData) { + __VUE_HMR_RUNTIME__.updateBlogData(blogPostData) + } +} + +if (import.meta.hot) { + import.meta.hot.accept(({ blogPostData }) => { + __VUE_HMR_RUNTIME__.updateBlogData(blogPostData) + }) +} +` + +const getTimestamp = (time: Date): number => { + return new Date(time).getTime() +} + +const EXCERPT_SPLIT = '<!-- more -->' + +export const preparedBlogData = async ( + app: App, + pageFilter: (id: string) => boolean, + options: PluginOption +): Promise<void> => { + let pages = app.pages.filter((page) => { + return page.filePathRelative && pageFilter(page.filePathRelative) + }) + if (options.sortBy) { + pages = pages.sort((prev, next) => { + if (options.sortBy === 'createTime') { + return getTimestamp(prev.frontmatter.createTime as Date) < + getTimestamp(next.frontmatter.createTime as Date) + ? 1 + : -1 + } else { + return typeof options.sortBy === 'function' && + options.sortBy(prev, next) + ? 1 + : -1 + } + }) + } + + const blogData: BlogPostData = pages.map((page: Page) => { + let extended: Partial<BlogPostDataItem> = {} + if (typeof options.extendBlogData === 'function') { + extended = options.extendBlogData(page) + } + const data = { + path: page.path, + title: page.title, + ...extended, + } + + if (options.excerpt && page.contentRendered.includes(EXCERPT_SPLIT)) { + const contents = page.contentRendered.split(EXCERPT_SPLIT) + data.excerpt = contents[0] + } + + return data as BlogPostDataItem + }) + + let content = `\ +export const blogPostData = JSON.parse(${JSON.stringify( + JSON.stringify(blogData) + )}) +` + + // inject HMR code + if (app.env.isDev) { + content += HMR_CODE + } + + await app.writeTemp('internal/blogData.js', content) +} diff --git a/packages/plugin-blog-data/src/shared/index.ts b/packages/plugin-blog-data/src/shared/index.ts new file mode 100644 index 00000000..adcc2d67 --- /dev/null +++ b/packages/plugin-blog-data/src/shared/index.ts @@ -0,0 +1,16 @@ +export interface BlogDataPluginOptions { + include?: string | string[] + exclude?: string | string[] + sortBy?: 'createTime' | false | (<T>(prev: T, next: T) => boolean) + excerpt?: boolean + extendBlogData?: <T = any>(page: T) => Record<string, any> +} + +export type BlogPostData<T extends object = object> = BlogPostDataItem<T>[] + +export type BlogPostDataItem<T extends object = object> = { + path: string + title: string + excerpt: string + [x: string]: any +} & T diff --git a/packages/plugin-blog-data/tsconfig.build.json b/packages/plugin-blog-data/tsconfig.build.json new file mode 100644 index 00000000..2f53b066 --- /dev/null +++ b/packages/plugin-blog-data/tsconfig.build.json @@ -0,0 +1,13 @@ +{ + "extends": "../tsconfig.build.json", + "compilerOptions": { + "rootDir": "./src", + "outDir": "./lib", + "baseUrl": ".", + "paths": { + "@internal/blogData": ["./src/client/blogPostData.d.ts"] + }, + "types": ["@vuepress/client/types", "vite/client", "webpack-env"] + }, + "include": ["./src"] +} diff --git a/packages/plugin-caniuse/package.json b/packages/plugin-caniuse/package.json index 3984ba0c..85929dcc 100644 --- a/packages/plugin-caniuse/package.json +++ b/packages/plugin-caniuse/package.json @@ -37,10 +37,10 @@ }, "dependencies": { "@types/markdown-it": "^12.2.3", - "@vuepress/cli": "2.0.0-beta.51", - "@vuepress/client": "2.0.0-beta.51", - "@vuepress/core": "2.0.0-beta.51", - "@vuepress/utils": "2.0.0-beta.51", + "@vuepress/cli": "2.0.0-beta.60", + "@vuepress/client": "2.0.0-beta.60", + "@vuepress/core": "2.0.0-beta.60", + "@vuepress/utils": "2.0.0-beta.60", "markdown-it-container": "^3.0.0" }, "publishConfig": { diff --git a/packages/plugin-copy-code/package.json b/packages/plugin-copy-code/package.json index 7cee5f5a..24a8b091 100644 --- a/packages/plugin-copy-code/package.json +++ b/packages/plugin-copy-code/package.json @@ -30,12 +30,12 @@ "ts": "tsc -b tsconfig.build.json" }, "dependencies": { - "@vuepress/client": "2.0.0-beta.51", - "@vuepress/core": "2.0.0-beta.51", - "@vuepress/shared": "2.0.0-beta.51", - "@vuepress/utils": "2.0.0-beta.51", - "vue": "^3.2.41", - "vue-router": "4.1.5" + "@vuepress/client": "2.0.0-beta.60", + "@vuepress/core": "2.0.0-beta.60", + "@vuepress/shared": "2.0.0-beta.60", + "@vuepress/utils": "2.0.0-beta.60", + "vue": "^3.2.47", + "vue-router": "4.1.6" }, "publishConfig": { "access": "public" diff --git a/packages/plugin-netlify-functions/package.json b/packages/plugin-netlify-functions/package.json index d88b1d13..68a4b439 100644 --- a/packages/plugin-netlify-functions/package.json +++ b/packages/plugin-netlify-functions/package.json @@ -38,21 +38,21 @@ }, "dependencies": { "@iarna/toml": "^2.2.5", - "@netlify/functions": "^1.3.0", - "@vuepress/core": "2.0.0-beta.51", - "@vuepress/shared": "2.0.0-beta.51", - "@vuepress/utils": "2.0.0-beta.51", - "chalk": "^5.1.2", + "@netlify/functions": "^1.4.0", + "@vuepress/core": "2.0.0-beta.60", + "@vuepress/shared": "2.0.0-beta.60", + "@vuepress/utils": "2.0.0-beta.60", + "chalk": "^5.2.0", "chokidar": "^3.5.3", "cpx2": "^4.2.0", "dotenv": "^16.0.3", - "esbuild": "^0.15.11", + "esbuild": "^0.16.17", "execa": "^6.1.0", - "netlify-cli": "^12.0.9", + "netlify-cli": "^12.7.2", "portfinder": "^1.0.32" }, "devDependencies": { - "@types/node": "^18.8.5" + "@types/node": "^18.11.18" }, "publishConfig": { "access": "public" diff --git a/packages/plugin-notes-data/LICENSE b/packages/plugin-notes-data/LICENSE new file mode 100644 index 00000000..9f677c90 --- /dev/null +++ b/packages/plugin-notes-data/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (C) 2021 - PRESENT by pengzhanbo + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/packages/plugin-notes-data/README.md b/packages/plugin-notes-data/README.md new file mode 100644 index 00000000..f13efb9e --- /dev/null +++ b/packages/plugin-notes-data/README.md @@ -0,0 +1,18 @@ +# `@vuepress-plume/vuepress-plugin-notes-data` + +## Install +``` +yarn add @vuepress-plume/vuepress-plugin-notes-data +``` +## Usage +``` js +// .vuepress/config.js +const notesDataPlugin = require('@vuepress-plume/vuepress-plugin-notes-data') +module.exports = { + //... + plugins: [ + notesDataPlugin() + ] + // ... +} +``` diff --git a/packages/plugin-notes-data/package.json b/packages/plugin-notes-data/package.json new file mode 100644 index 00000000..20d745c4 --- /dev/null +++ b/packages/plugin-notes-data/package.json @@ -0,0 +1,51 @@ +{ + "name": "@vuepress-plume/vuepress-plugin-notes-data", + "version": "1.0.0-beta.45", + "description": "The Plugin for VuePres 2", + "homepage": "https://github.com/pengzhanbo/vuepress-theme-plume#readme", + "bugs": { + "url": "https://github.com/pengzhanbo/vuepress-theme-plume/issues" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/pengzhanbo/vuepress-theme-plume.git" + }, + "license": "MIT", + "author": "pengzhanbo <volodymyr@foxmail.com>", + "type": "module", + "exports": { + ".": "./lib/node/index.js", + "./client": "./lib/client/index.js", + "./package.json": "./package.json" + }, + "main": "lib/node/index.js", + "types": "./lib/node/index.d.ts", + "scripts": { + "build": "pnpm run clean && pnpm run copy && pnpm run ts", + "clean": "rimraf lib *.tsbuildinfo", + "copy": "cpx \"src/**/*.{d.ts,vue,css,scss,jpg,png}\" lib", + "copy:watch": "cpx \"src/**/*.{d.ts,vue,css,scss,jpg,png}\" lib -w", + "dev": "concurrently \"pnpm copy:watch\" \"pnpm ts:watch\"", + "ts": "tsc -b tsconfig.build.json", + "ts:watch": "tsc -b tsconfig.build.json --watch" + }, + "dependencies": { + "@vue/devtools-api": "^6.4.5", + "@vuepress/client": "2.0.0-beta.60", + "@vuepress/core": "2.0.0-beta.60", + "@vuepress/shared": "2.0.0-beta.60", + "@vuepress/utils": "2.0.0-beta.60", + "chokidar": "^3.5.3", + "create-filter": "^1.0.0", + "vue": "^3.2.47" + }, + "publishConfig": { + "access": "public" + }, + "keyword": [ + "VuePress", + "vuepress plugin", + "notesData", + "vuepress-plugin-plugin-notes-data" + ] +} diff --git a/packages/plugin-notes-data/src/client/clientConfig.ts b/packages/plugin-notes-data/src/client/clientConfig.ts new file mode 100644 index 00000000..fc251e8f --- /dev/null +++ b/packages/plugin-notes-data/src/client/clientConfig.ts @@ -0,0 +1,37 @@ +import { setupDevtoolsPlugin } from '@vue/devtools-api' +import { defineClientConfig } from '@vuepress/client' +import { useNotesData } from './composables/index.js' + +declare const __VUE_PROD_DEVTOOLS__: boolean + +export default defineClientConfig({ + enhance({ app }) { + const notesData = useNotesData() + + // setup devtools in dev mode + if (__VUEPRESS_DEV__ || __VUE_PROD_DEVTOOLS__) { + setupDevtoolsPlugin( + { + // fix recursive reference + app: app as any, + id: 'org.vuepress-plume.plugin-notes-data', + label: 'VuePress Notes Data Plugin', + packageName: '@vuepress/plugin-notes-data', + homepage: 'https://pengzhanbo.cn', + logo: 'https://v2.vuepress.vuejs.org/images/hero.png', + componentStateTypes: ['VuePress'], + }, + (api) => { + api.on.inspectComponent((payload) => { + payload.instanceData.state.push({ + type: 'VuePress', + key: 'notesData', + editable: false, + value: notesData.value, + }) + }) + } + ) + } + }, +}) diff --git a/packages/plugin-notes-data/src/client/composables/index.ts b/packages/plugin-notes-data/src/client/composables/index.ts new file mode 100644 index 00000000..6434f5b2 --- /dev/null +++ b/packages/plugin-notes-data/src/client/composables/index.ts @@ -0,0 +1 @@ +export * from './notesDate.js' diff --git a/packages/plugin-notes-data/src/client/composables/notesDate.ts b/packages/plugin-notes-data/src/client/composables/notesDate.ts new file mode 100644 index 00000000..c9d54087 --- /dev/null +++ b/packages/plugin-notes-data/src/client/composables/notesDate.ts @@ -0,0 +1,20 @@ +import { notesData as notesDataRaw } from '@internal/notesData' +import { ref } from 'vue' +import type { Ref } from 'vue' +import type { NotesData } from '../../shared/index.js' + +declare const __VUE_HMR_RUNTIME__: Record<string, any> + +export type NotesDataRef<T extends NotesData = NotesData> = Ref<T> + +export const notesData: NotesDataRef = ref(notesDataRaw) + +export const useNotesData = < + T extends NotesData = NotesData +>(): NotesDataRef<T> => notesData as NotesDataRef<T> + +if (import.meta.webpackHot || import.meta.hot) { + __VUE_HMR_RUNTIME__.updateNotesData = (data: NotesData) => { + notesData.value = data + } +} diff --git a/packages/plugin-notes-data/src/client/index.ts b/packages/plugin-notes-data/src/client/index.ts new file mode 100644 index 00000000..f419aa80 --- /dev/null +++ b/packages/plugin-notes-data/src/client/index.ts @@ -0,0 +1,2 @@ +export { NotesData, NotesSidebarItem } from '../shared/index.js' +export * from './composables/index.js' diff --git a/packages/plugin-notes-data/src/client/notesData.d.ts b/packages/plugin-notes-data/src/client/notesData.d.ts new file mode 100644 index 00000000..f5258ec2 --- /dev/null +++ b/packages/plugin-notes-data/src/client/notesData.d.ts @@ -0,0 +1,7 @@ +import type { NotesData } from '../shared/index.js' + +declare module '@internal/notesData' { + const notesData: NotesData + + export { notesData } +} diff --git a/packages/plugin-notes-data/src/node/index.ts b/packages/plugin-notes-data/src/node/index.ts new file mode 100644 index 00000000..69e663e0 --- /dev/null +++ b/packages/plugin-notes-data/src/node/index.ts @@ -0,0 +1,6 @@ +import { notesDataPlugin } from './plugin.js' + +export * from './plugin.js' +export * from '../shared/index.js' + +export default notesDataPlugin diff --git a/packages/plugin-notes-data/src/node/plugin.ts b/packages/plugin-notes-data/src/node/plugin.ts new file mode 100644 index 00000000..1a9b64af --- /dev/null +++ b/packages/plugin-notes-data/src/node/plugin.ts @@ -0,0 +1,18 @@ +import type { App, Plugin } from '@vuepress/core' +import { getDirname, path } from '@vuepress/utils' +import type { NotesDataOptions } from '../shared/index.js' +import { prepareNotesData, watchNotesData } from './prepareNotesData.js' + +export const notesDataPlugin = (options: NotesDataOptions): Plugin => { + return (app: App) => { + return { + name: '@vuepress-plume/vuepress-plugin-notes-data', + clientConfigFile: path.resolve( + getDirname(import.meta.url), + '../client/clientConfig.js' + ), + onPrepared: () => prepareNotesData(app, options), + onWatched: (app, watchers) => watchNotesData(app, watchers, options), + } + } +} diff --git a/packages/plugin-notes-data/src/node/prepareNotesData.ts b/packages/plugin-notes-data/src/node/prepareNotesData.ts new file mode 100644 index 00000000..caa73e94 --- /dev/null +++ b/packages/plugin-notes-data/src/node/prepareNotesData.ts @@ -0,0 +1,157 @@ +import path from 'node:path' +import type { App } from '@vuepress/core' +import * as chokidar from 'chokidar' +import { createFilter } from 'create-filter' +import type { + NotesData, + NotesDataOptions, + NotesItem, + NotesSidebar, + NotesSidebarItem, +} from '../shared/index.js' +import { ensureArray } from './utils.js' + +const HMR_CODE = ` +if (import.meta.webpackHot) { + import.meta.webpackHot.accept() + if (__VUE_HMR_RUNTIME__.updateNotesData) { + __VUE_HMR_RUNTIME__.updateNotesData(notesData) + } +} + +if (import.meta.hot) { + import.meta.hot.accept(({ notesData }) => { + __VUE_HMR_RUNTIME__.updateNotesData(notesData) + }) +} +` + +interface NotePage { + relativePath: string + title: string + link: string +} + +export const prepareNotesData = async ( + app: App, + { include, exclude, notes, dir, link }: NotesDataOptions +) => { + if (!notes || notes.length === 0) return + const filter = createFilter(ensureArray(include), ensureArray(exclude), { + resolve: false, + }) + const DIR_PATTERN = new RegExp(`^${path.join(dir, '/')}`) + const notesPageList: NotePage[] = app.pages + .filter( + (page) => + page.filePathRelative && + page.filePathRelative.startsWith(dir) && + filter(page.filePathRelative) + ) + .map((page) => { + return { + relativePath: page.filePathRelative?.replace(DIR_PATTERN, '') || '', + title: page.title, + link: page.path, + } + }) + + const notesData: NotesData = {} + notes.forEach((note) => { + notesData[path.join('/', link, note.link)] = initSidebar( + note, + notesPageList.filter((page) => + page.relativePath.startsWith(note.dir.trim().replace(/^\/|\/$/g, '')) + ) + ) + }) + let content = ` +export const notesData = ${JSON.stringify(notesData, null, 2)} +` + if (app.env.isDev) { + content += HMR_CODE + } + + await app.writeTemp('internal/notesData.js', content) +} + +export const watchNotesData = ( + app: App, + watchers: any[], + options: NotesDataOptions +): void => { + if (!options.notes || options.notes.length === 0 || !options.dir) return + const dir = path.join('pages', options.dir, '**/*') + const watcher = chokidar.watch(dir, { + cwd: app.dir.temp(), + ignoreInitial: true, + }) + + watcher.on('add', () => prepareNotesData(app, options)) + watcher.on('change', () => prepareNotesData(app, options)) + watcher.on('unlink', () => prepareNotesData(app, options)) + watchers.push(watcher) +} + +function initSidebar(note: NotesItem, pages: NotePage[]): NotesSidebarItem[] { + if (!note.sidebar) return [] + if (note.sidebar === 'auto') return [] + return initSidebarByConfig(note, pages) +} + +function initSidebarByConfig( + { text, dir, sidebar }: NotesItem, + pages: NotePage[] +): NotesSidebarItem[] { + return (sidebar as NotesSidebar).map((item) => { + if (typeof item === 'string') { + const current = findNotePage(item, dir, pages) + return { + text: current?.title || text, + link: current?.link, + items: [], + } + } else { + const current = findNotePage(item.link || '', dir, pages) + return { + text: item.text || item.dir || current?.title, + link: current?.link, + collapsed: item.collapsed, + items: initSidebarByConfig( + { + link: item.link || '', + text: item.text || '', + sidebar: item.items, + dir: path.join(dir, item.dir || ''), + }, + pages + ), + } + } + }) +} + +function findNotePage( + sidebar: string, + dir: string, + notePageList: NotePage[] +): NotePage | undefined { + if (sidebar === '' || sidebar === 'README.md' || sidebar === 'index.md') { + return notePageList.find((page) => { + const relative = page.relativePath + return ( + relative === path.join(dir, 'README.md') || + relative === path.join(dir, 'index.md') + ) + }) + } else { + return notePageList.find((page) => { + const relative = page.relativePath + return ( + relative === path.join(dir, sidebar) || + relative === path.join(dir, sidebar + '.md') || + page.link === sidebar + ) + }) + } +} diff --git a/packages/plugin-notes-data/src/node/utils.ts b/packages/plugin-notes-data/src/node/utils.ts new file mode 100644 index 00000000..981a3c67 --- /dev/null +++ b/packages/plugin-notes-data/src/node/utils.ts @@ -0,0 +1,5 @@ +export function ensureArray<T>(thing: T | T[] | null | undefined): T[] { + if (Array.isArray(thing)) return thing + if (thing === null || thing === undefined) return [] + return [thing] +} diff --git a/packages/plugin-notes-data/src/shared/index.ts b/packages/plugin-notes-data/src/shared/index.ts new file mode 100644 index 00000000..ea4a16fc --- /dev/null +++ b/packages/plugin-notes-data/src/shared/index.ts @@ -0,0 +1,26 @@ +export type NotesDataOptions = { + dir: string + link: string + include?: string | string[] + exclude?: string | string[] + notes: NotesItem[] +} + +export type NotesItem = { + dir: string + link: string + text: string + sidebar?: NotesSidebar | 'auto' +} + +export type NotesSidebar = (NotesSidebarItem | string)[] + +export type NotesSidebarItem = { + text?: string + link?: string + dir?: string + collapsed?: boolean + items?: NotesSidebar +} + +export type NotesData = Record<string, NotesSidebarItem[]> diff --git a/packages/plugin-notes-data/tsconfig.build.json b/packages/plugin-notes-data/tsconfig.build.json new file mode 100644 index 00000000..a08fdad2 --- /dev/null +++ b/packages/plugin-notes-data/tsconfig.build.json @@ -0,0 +1,12 @@ +{ + "extends": "../tsconfig.build.json", + "compilerOptions": { + "rootDir": "./src", + "outDir": "./lib", + "paths": { + "@internal/notesData": ["./src/client/notesData.d.ts"] + }, + "types": ["@vuepress/client/types", "vite/client", "webpack-env"] + }, + "include": ["./src"] +} diff --git a/packages/plugin-page-collection/package.json b/packages/plugin-page-collection/package.json index 6a226d60..90a71d93 100644 --- a/packages/plugin-page-collection/package.json +++ b/packages/plugin-page-collection/package.json @@ -31,15 +31,15 @@ "ts": "tsc -b tsconfig.build.json" }, "dependencies": { - "@netlify/functions": "^1.3.0", + "@netlify/functions": "^1.4.0", "@vuepress-plume/vuepress-plugin-netlify-functions": "workspace:*", - "@vuepress/client": "2.0.0-beta.51", - "@vuepress/core": "2.0.0-beta.51", - "@vuepress/shared": "2.0.0-beta.51", - "@vuepress/utils": "2.0.0-beta.51", - "leancloud-storage": "^4.13.2", - "vue": "^3.2.41", - "vue-router": "4.1.5" + "@vuepress/client": "2.0.0-beta.60", + "@vuepress/core": "2.0.0-beta.60", + "@vuepress/shared": "2.0.0-beta.60", + "@vuepress/utils": "2.0.0-beta.60", + "leancloud-storage": "^4.14.0", + "vue": "^3.2.47", + "vue-router": "4.1.6" }, "publishConfig": { "access": "public" diff --git a/packages/plugin-windicss/package.json b/packages/plugin-windicss/package.json index c7cccfe4..b3dbc1e0 100644 --- a/packages/plugin-windicss/package.json +++ b/packages/plugin-windicss/package.json @@ -29,13 +29,13 @@ "ts": "tsc -b tsconfig.build.json" }, "dependencies": { - "@vuepress/client": "2.0.0-beta.51", - "@vuepress/core": "2.0.0-beta.51", - "@vuepress/shared": "2.0.0-beta.51", - "@vuepress/utils": "2.0.0-beta.51", - "vite-plugin-windicss": "^1.8.8", + "@vuepress/client": "2.0.0-beta.60", + "@vuepress/core": "2.0.0-beta.60", + "@vuepress/shared": "2.0.0-beta.60", + "@vuepress/utils": "2.0.0-beta.60", + "vite-plugin-windicss": "^1.8.10", "windicss": "^3.5.6", - "windicss-webpack-plugin": "^1.7.6" + "windicss-webpack-plugin": "^1.7.7" }, "publishConfig": { "access": "public" diff --git a/packages/plugin-windicss/src/client/config.vite.ts b/packages/plugin-windicss/src/client/config.vite.ts index 0bf9dc52..6558b17a 100644 --- a/packages/plugin-windicss/src/client/config.vite.ts +++ b/packages/plugin-windicss/src/client/config.vite.ts @@ -1,5 +1,6 @@ import { defineClientConfig } from '@vuepress/client' +// import 'virtual:windi-devtools' import 'virtual:windi.css' export default defineClientConfig({}) diff --git a/packages/plugin-windicss/src/node/plugin.ts b/packages/plugin-windicss/src/node/plugin.ts index 8d23f8f3..35185eb2 100644 --- a/packages/plugin-windicss/src/node/plugin.ts +++ b/packages/plugin-windicss/src/node/plugin.ts @@ -14,7 +14,10 @@ export const windiCSSPlugin = (options?: WindiCSSOptions | string): Plugin => { let userOptions: UserOptions | undefined let utilsOptions: WindiPluginUtilsOptions | undefined if (typeof options === 'string') { - userOptions = { config: options } + userOptions = { + config: options, + include: ['**/.vuepress/**/*.{vue,jsx,tsx}', '**/*.md'], + } } else { options = options || {} userOptions = options.userOptions @@ -39,7 +42,9 @@ export const windiCSSPlugin = (options?: WindiCSSOptions | string): Plugin => { if (app.options.bundler.name === '@vuepress/bundler-webpack') { bundlerOptions.configureWebpack && bundlerOptions.configureWebpack((config: any) => { - config.plugins.push(new WebpackWindiCSSPlugin(userOptions)) + config.plugins.push( + new (WebpackWindiCSSPlugin as any)(userOptions) + ) }) } }, diff --git a/packages/plugin-windicss/src/node/windicss.d.ts b/packages/plugin-windicss/src/node/windicss.d.ts index 1e309ec4..50c54b58 100644 --- a/packages/plugin-windicss/src/node/windicss.d.ts +++ b/packages/plugin-windicss/src/node/windicss.d.ts @@ -1,17 +1,17 @@ -declare module 'windicss-webpack-plugin' { - const result: any +// declare module 'windicss-webpack-plugin' { +// const result: any - export default result -} +// export default result +// } -declare module 'vite-plugin-windicss' { - const result: any +// declare module 'vite-plugin-windicss' { +// const result: any - type UserOptions = any +// type UserOptions = any - type WindiPluginUtilsOptions = any +// type WindiPluginUtilsOptions = any - export default result +// export default result - export { UserOptions, WindiPluginUtilsOptions } -} +// export { UserOptions, WindiPluginUtilsOptions } +// } diff --git a/packages/theme/CHANGELOG.md b/packages/theme/CHANGELOG.md deleted file mode 100644 index 1339fd8f..00000000 --- a/packages/theme/CHANGELOG.md +++ /dev/null @@ -1,229 +0,0 @@ -# Change Log - -All notable changes to this project will be documented in this file. -See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. - -# [1.0.0-beta.26](https://github.com/pengzhanbo/vuepress-theme-plume/compare/v1.0.0-beta.25...v1.0.0-beta.26) (2022-04-25) - - -### Features - -* support sitemap and seo ([a57af59](https://github.com/pengzhanbo/vuepress-theme-plume/commit/a57af599e649d1f7ce357f704a222c7babc77b06)) - - - - - -# [1.0.0-beta.25](https://github.com/pengzhanbo/vuepress-theme-plume/compare/v1.0.0-beta.24...v1.0.0-beta.25) (2022-04-25) - - -### Bug Fixes - -* fix define config ([00bca40](https://github.com/pengzhanbo/vuepress-theme-plume/commit/00bca40d895499017308359bfce682cec055f42b)) - - - - - -# [1.0.0-beta.24](https://github.com/pengzhanbo/vuepress-theme-plume/compare/v1.0.0-beta.23...v1.0.0-beta.24) (2022-04-25) - - -### Features - -* 主题配置函数 ([844feea](https://github.com/pengzhanbo/vuepress-theme-plume/commit/844feeae7406f5aee8edef35bce4a08e808f692e)) - - - - - -# [1.0.0-beta.23](https://github.com/pengzhanbo/vuepress-theme-plume/compare/v1.0.0-beta.22...v1.0.0-beta.23) (2022-04-23) - -**Note:** Version bump only for package @vuepress-plume/vuepress-theme-plume - - - - - -# [1.0.0-beta.22](https://github.com/pengzhanbo/vuepress-theme-plume/compare/v1.0.0-beta.21...v1.0.0-beta.22) (2022-04-18) - -**Note:** Version bump only for package @vuepress-plume/vuepress-theme-plume - - - - - -# [1.0.0-beta.21](https://github.com/pengzhanbo/vuepress-theme-plume/compare/v1.0.0-beta.20...v1.0.0-beta.21) (2022-04-18) - -**Note:** Version bump only for package @vuepress-plume/vuepress-theme-plume - - - - - -# [1.0.0-beta.20](https://github.com/pengzhanbo/vuepress-theme-plume/compare/v1.0.0-beta.19...v1.0.0-beta.20) (2022-04-18) - -**Note:** Version bump only for package @vuepress-plume/vuepress-theme-plume - - - - - -# [1.0.0-beta.19](https://github.com/pengzhanbo/vuepress-theme-plume/compare/v1.0.0-beta.18...v1.0.0-beta.19) (2022-04-18) - -**Note:** Version bump only for package @vuepress-plume/vuepress-theme-plume - - - - - -# [1.0.0-beta.18](https://github.com/pengzhanbo/vuepress-theme-plume/compare/v1.0.0-beta.17...v1.0.0-beta.18) (2022-04-14) - -**Note:** Version bump only for package @vuepress-plume/vuepress-theme-plume - - - - - -# [1.0.0-beta.17](https://github.com/pengzhanbo/vuepress-theme-plume/compare/v1.0.0-beta.16...v1.0.0-beta.17) (2022-04-12) - -**Note:** Version bump only for package @vuepress-plume/vuepress-theme-plume - - - - - -# [1.0.0-beta.16](https://github.com/pengzhanbo/vuepress-theme-plume/compare/v1.0.0-beta.15...v1.0.0-beta.16) (2022-04-12) - - -### Bug Fixes - -* sidebar ([a2794d7](https://github.com/pengzhanbo/vuepress-theme-plume/commit/a2794d72ea7a276d8fd876475f5e9c77c33f5e90)) - - - - - -# [1.0.0-beta.15](https://github.com/pengzhanbo/vuepress-theme-plume/compare/v1.0.0-beta.14...v1.0.0-beta.15) (2022-04-12) - -**Note:** Version bump only for package @vuepress-plume/vuepress-theme-plume - - - - - -# [1.0.0-beta.14](https://github.com/pengzhanbo/vuepress-theme-plume/compare/v1.0.0-beta.13...v1.0.0-beta.14) (2022-04-12) - - -### Bug Fixes - -* 修复sidebar问题 ([420ec9f](https://github.com/pengzhanbo/vuepress-theme-plume/commit/420ec9fb663793fe2d4fd7e9e61f12ca0d05217e)) - - - - - -# [1.0.0-beta.13](https://github.com/pengzhanbo/vuepress-theme-plume/compare/v1.0.0-beta.12...v1.0.0-beta.13) (2022-04-12) - - -### Bug Fixes - -* 修复note生成sidebar时目录嵌套时未正确识别路径 ([7b3a6e2](https://github.com/pengzhanbo/vuepress-theme-plume/commit/7b3a6e2252582a19bdbf42c1ddf85dfab199d57b)) - - - - - -# [1.0.0-beta.12](https://github.com/pengzhanbo/vuepress-theme-plume/compare/v1.0.0-beta.11...v1.0.0-beta.12) (2022-04-08) - - -### Bug Fixes - -* 修复page页toc问题 ([2d44799](https://github.com/pengzhanbo/vuepress-theme-plume/commit/2d4479909f4c84a8d71c8a97c93f21bde3b8208c)) - - - - - -# [1.0.0-beta.11](https://github.com/pengzhanbo/vuepress-theme-plume/compare/v1.0.0-beta.10...v1.0.0-beta.11) (2022-04-08) - -**Note:** Version bump only for package @vuepress-plume/vuepress-theme-plume - - - - - -# [1.0.0-beta.10](https://github.com/pengzhanbo/vuepress-theme-plume/compare/v1.0.0-beta.9...v1.0.0-beta.10) (2022-04-08) - -**Note:** Version bump only for package @vuepress-plume/vuepress-theme-plume - - - - - -# [1.0.0-beta.9](https://github.com/pengzhanbo/vuepress-theme-plume/compare/v1.0.0-beta.8...v1.0.0-beta.9) (2022-04-06) - -**Note:** Version bump only for package @vuepress-plume/vuepress-theme-plume - - - - - -# [1.0.0-beta.8](https://github.com/pengzhanbo/vuepress-theme-plume/compare/v1.0.0-beta.7...v1.0.0-beta.8) (2022-04-06) - -**Note:** Version bump only for package @vuepress-plume/vuepress-theme-plume - - - - - -# [1.0.0-beta.7](https://github.com/pengzhanbo/vuepress-theme-plume/compare/v1.0.0-beta.6...v1.0.0-beta.7) (2022-04-05) - -**Note:** Version bump only for package @vuepress-plume/vuepress-theme-plume - - - - - -# [1.0.0-beta.6](https://github.com/pengzhanbo/vuepress-theme-plume/compare/v1.0.0-beta.5...v1.0.0-beta.6) (2022-04-05) - -**Note:** Version bump only for package @vuepress-plume/vuepress-theme-plume - - - - - -# [1.0.0-beta.5](https://github.com/pengzhanbo/vuepress-theme-plume/compare/v1.0.0-beta.4...v1.0.0-beta.5) (2022-04-05) - -**Note:** Version bump only for package @vuepress-plume/vuepress-theme-plume - - - - - -# [1.0.0-beta.4](https://github.com/pengzhanbo/vuepress-theme-plume/compare/v1.0.0-beta.3...v1.0.0-beta.4) (2022-04-05) - -**Note:** Version bump only for package @vuepress-plume/vuepress-theme-plume - - - - - -# [1.0.0-beta.3](https://github.com/pengzhanbo/vuepress-theme-plume/compare/v1.0.0-beta.2...v1.0.0-beta.3) (2022-04-05) - -**Note:** Version bump only for package @vuepress-plume/vuepress-theme-plume - - - - - -# [1.0.0-beta.2](https://github.com/pengzhanbo/vuepress-theme-plume/compare/v1.0.0-beta.1...v1.0.0-beta.2) (2022-04-05) - -**Note:** Version bump only for package @vuepress-plume/vuepress-theme-plume - - - - - -# 1.0.0-beta.1 (2022-04-05) - -**Note:** Version bump only for package @vuepress-plume/vuepress-theme-plume diff --git a/packages/theme/package.json b/packages/theme/package.json index 8f1231de..6d3409f7 100644 --- a/packages/theme/package.json +++ b/packages/theme/package.json @@ -19,7 +19,7 @@ "url": "git+https://github.com/pengzhanbo/vuepress-theme-plume.git" }, "license": "MIT", - "author": "pengzhanbo <volodymyr@foxmail.com>", + "author": "pengzhanbo <q942450674@outlook.com> (https://github.com/pengzhanbo/)", "type": "module", "exports": { ".": "./lib/node/index.js", @@ -35,59 +35,48 @@ "scripts": { "build": "pnpm run clean && pnpm run copy && pnpm run ts", "clean": "rimraf lib *.tsbuildinfo", - "copy": "cpx \"src/**/*.{d.ts,vue,css,scss,jpg,png}\" lib", - "copy:watch": "cpx \"src/**/*.{d.ts,vue,css,scss,jpg,png}\" lib -w", + "copy": "cpx \"src/**/*.{d.ts,vue,css,scss,jpg,png,woff2}\" lib", + "copy:watch": "cpx \"src/**/*.{d.ts,vue,css,scss,jpg,png,woff2}\" lib -w", "dev": "concurrently \"pnpm copy:watch\" \"pnpm ts:watch\"", "ts": "tsc -b tsconfig.build.json", "ts:watch": "tsc -b tsconfig.build.json --watch" }, "dependencies": { "@types/lodash.merge": "^4.6.7", + "@vuepress-plume/vuepress-plugin-auto-frontmatter": "workspace:*", "@vuepress-plume/vuepress-plugin-baidu-tongji": "workspace:*", + "@vuepress-plume/vuepress-plugin-blog-data": "workspace:*", "@vuepress-plume/vuepress-plugin-caniuse": "workspace:*", "@vuepress-plume/vuepress-plugin-copy-code": "workspace:*", - "@vuepress/client": "2.0.0-beta.51", - "@vuepress/core": "2.0.0-beta.51", - "@vuepress/plugin-active-header-links": "2.0.0-beta.51", - "@vuepress/plugin-container": "2.0.0-beta.51", - "@vuepress/plugin-docsearch": "2.0.0-beta.51", - "@vuepress/plugin-external-link-icon": "2.0.0-beta.51", - "@vuepress/plugin-git": "2.0.0-beta.51", - "@vuepress/plugin-medium-zoom": "2.0.0-beta.51", - "@vuepress/plugin-nprogress": "2.0.0-beta.51", - "@vuepress/plugin-palette": "2.0.0-beta.51", - "@vuepress/plugin-prismjs": "2.0.0-beta.51", - "@vuepress/plugin-search": "2.0.0-beta.51", - "@vuepress/plugin-theme-data": "2.0.0-beta.51", - "@vuepress/plugin-toc": "2.0.0-beta.51", - "@vuepress/shared": "2.0.0-beta.51", - "@vuepress/utils": "2.0.0-beta.51", - "@vueuse/core": "^9.3.0", - "chokidar": "^3.5.3", + "@vuepress-plume/vuepress-plugin-notes-data": "workspace:*", + "@vuepress/client": "2.0.0-beta.60", + "@vuepress/core": "2.0.0-beta.60", + "@vuepress/plugin-active-header-links": "2.0.0-beta.60", + "@vuepress/plugin-container": "2.0.0-beta.60", + "@vuepress/plugin-docsearch": "2.0.0-beta.60", + "@vuepress/plugin-external-link-icon": "2.0.0-beta.60", + "@vuepress/plugin-git": "2.0.0-beta.60", + "@vuepress/plugin-medium-zoom": "2.0.0-beta.60", + "@vuepress/plugin-nprogress": "2.0.0-beta.60", + "@vuepress/plugin-palette": "2.0.0-beta.60", + "@vuepress/plugin-prismjs": "2.0.0-beta.60", + "@vuepress/plugin-search": "2.0.0-beta.60", + "@vuepress/plugin-shiki": "2.0.0-beta.60", + "@vuepress/plugin-theme-data": "2.0.0-beta.60", + "@vuepress/plugin-toc": "2.0.0-beta.60", + "@vuepress/shared": "2.0.0-beta.60", + "@vuepress/utils": "2.0.0-beta.60", + "@vueuse/core": "^9.10.0", + "body-scroll-lock": "4.0.0-beta.0", "date-fns": "^2.29.3", - "gray-matter": "^4.0.3", - "json2yaml": "^1.1.0", - "lodash.merge": "^4.6.2", "nanoid": "^4.0.0", - "sass": "^1.55.0", - "sass-loader": "^13.1.0", "ts-debounce": "^4.0.0", - "vue": "^3.2.41", - "vue-router": "4.1.5", - "vuepress-plugin-comment2": "2.0.0-beta.110", - "vuepress-plugin-md-enhance": "2.0.0-beta.110", - "vuepress-plugin-seo2": "2.0.0-beta.110", - "vuepress-plugin-sitemap2": "2.0.0-beta.110" - }, - "peerDependencies": { - "sass-loader": "^13.0.2" - }, - "peerDependenciesMeta": { - "sass-loader": { - "optional": true - } - }, - "publishConfig": { - "access": "public" + "vue": "^3.2.47", + "vue-router": "4.1.6", + "vuepress-plugin-comment2": "2.0.0-beta.166", + "vuepress-plugin-md-enhance": "2.0.0-beta.166", + "vuepress-plugin-seo2": "2.0.0-beta.166", + "vuepress-plugin-sitemap2": "2.0.0-beta.166", + "windicss": "^3.5.6" } } diff --git a/packages/theme/src/client/components/Archive.vue b/packages/theme/src/client/components/Archive.vue deleted file mode 100644 index abf9f2b7..00000000 --- a/packages/theme/src/client/components/Archive.vue +++ /dev/null @@ -1,171 +0,0 @@ -<script lang="ts" setup> -import BlogInfo from '@theme-plume/BlogInfo.vue' -import DropdownTransition from '@theme-plume/DropdownTransition.vue' -import type { PageHeader } from '@vuepress/client' -import { computed } from 'vue' -import { useArchive } from '../composables/index.js' -import Toc from './Toc.js' - -const archiveList = useArchive() - -const headers = computed(() => { - return archiveList.value.map(({ year }) => { - return { - level: 2, - slug: year, - title: year, - link: '', - children: [], - } as PageHeader - }) -}) -</script> -<template> - <div class="archive-wrapper"> - <div class="archive-container"> - <DropdownTransition> - <div class="archive-content"> - <div class="archive-box"> - <div - v-for="archive in archiveList" - :key="archive.year" - class="archive-items" - > - <h2> - <a - class="header-anchor" - :href="'#' + archive.year" - aria-hidden="true" - >#</a - > - {{ archive.year }} - </h2> - <ul class="archive-list"> - <li v-for="child in archive.children" :key="child.link"> - <span>{{ child.date }}</span> - <RouterLink :to="child.link">{{ child.text }}</RouterLink> - </li> - </ul> - </div> - </div> - <div class="archive-toc"> - <Toc :headers="headers" /> - </div> - </div> - </DropdownTransition> - <BlogInfo></BlogInfo> - </div> - </div> -</template> -<style lang="scss"> -@import '../styles/_mixins'; - -.archive-wrapper { - @include wrapper; - - .archive-container { - @include container_wrapper; - display: flex; - align-items: flex-start; - padding: 1.25rem 0; - } - - .archive-content { - display: flex; - align-items: flex-start; - flex: 1; - - .archive-box { - flex: 1; - } - } - - .archive-items { - h2 { - position: relative; - margin: 0 0 0 4rem; - border-left: solid 4px var(--c-border); - border-bottom: none; - padding: 1.25rem; - - &::before { - content: ''; - display: inline-block; - width: 0.75rem; - height: 0.75rem; - background-color: var(--c-bg-container); - border-radius: 6px; - border: solid 2px var(--c-border-dark); - position: absolute; - top: 50%; - left: -2px; - transform: translate(-50%, -50%); - } - } - } - - .archive-list { - list-style: none; - padding-left: 0; - margin: 0; - - li { - position: relative; - margin-left: 4rem; - border-left: solid 4px var(--c-border); - padding: 0.75rem 1.25rem; - - &::before { - content: ''; - display: inline-block; - width: 0.625rem; - height: 0.625rem; - background-color: var(--c-bg-container); - border-radius: 5px; - border: solid 2px var(--c-border-dark); - position: absolute; - top: 50%; - left: -2px; - transform: translate(-50%, -50%); - transition: border-color var(--t-color); - } - - > span { - position: absolute; - left: -1.25rem; - top: 50%; - transform: translate(-100%, -50%); - color: var(--c-text-light); - font-size: 14px; - transition: color var(--t-color); - } - - > a { - display: inline-block; - width: 100%; - padding: 0.5rem 1.25rem; - background-color: var(--c-bg-container); - border-radius: var(--p-around); - // box-shadow: var(--shadow-sm); - color: var(--c-text); - transition: color var(--t-color), box-shadow var(--t-color); - } - - &:hover { - > span, - > a { - color: var(--c-text-accent); - } - - // > a { - // box-shadow: var(--shadow); - // } - - &::before { - border-color: var(--c-text-accent); - } - } - } - } -} -</style> diff --git a/packages/theme/src/client/components/AsideNavbar.vue b/packages/theme/src/client/components/AsideNavbar.vue deleted file mode 100644 index 5861cc2b..00000000 --- a/packages/theme/src/client/components/AsideNavbar.vue +++ /dev/null @@ -1,47 +0,0 @@ -<script lang="ts" setup> -import Sidebar from '@theme-plume/Sidebar.vue' -// eslint-disable-next-line @typescript-eslint/consistent-type-imports -import type { SidebarOptions } from '../../shared/index.js' -import { useAsideNavbar, useNavbarConfig } from '../composables/index.js' - -const navbarConfig = useNavbarConfig() -const { asideNavbarShow, triggerAsideNavbar } = useAsideNavbar() -</script> -<template> - <Transition name="fade"> - <div - v-show="asideNavbarShow" - class="aside-navbar-wrapper" - @click.self="triggerAsideNavbar(false)" - > - <Sidebar :aside="(navbarConfig as SidebarOptions)" /> - </div> - </Transition> -</template> -<style lang="scss"> -@import '../styles/variables'; -.aside-navbar-wrapper { - position: fixed; - top: 0; - left: 0; - right: 0; - bottom: 0; - background-color: rgba(0, 0, 0, 0.75); - z-index: 30; - - .plume-theme-sidebar-wrapper { - display: block; - position: relative; - top: 0; - right: 0; - width: 70%; - height: 100%; - padding: 1.25rem 0 1.25rem 2.25rem; - } -} -@media (min-width: $MQMobile) { - .aside-navbar-wrapper { - display: none; - } -} -</style> diff --git a/packages/theme/src/client/components/AutoLink.vue b/packages/theme/src/client/components/AutoLink.vue index 94bd8995..ee8c11bc 100644 --- a/packages/theme/src/client/components/AutoLink.vue +++ b/packages/theme/src/client/components/AutoLink.vue @@ -1,105 +1,42 @@ -<script lang="ts"> -/* eslint-disable import/first, import/no-duplicates, import/order */ -import { defineComponent } from 'vue' - -export default defineComponent({ - inheritAttrs: false, -}) -</script> - <script lang="ts" setup> -import { computed, toRefs } from 'vue' -import type { PropType } from 'vue' -import { useRoute } from 'vue-router' -import { useSiteData } from '@vuepress/client' -import type { NavLink } from '../../shared/index.js' -import { isLinkHttp, isLinkMailto, isLinkTel } from '@vuepress/shared' +import { computed } from 'vue' +import { EXTERNAL_URL_RE, normalizeLink } from '../utils/index.js' +import IconExternalLink from './icons/IconExternalLink.vue' -const props = defineProps({ - item: { - type: Object as PropType<NavLink>, - require: true, - default: () => ({ text: '' }), - }, -}) +const props = defineProps<{ + tag?: string + href?: string + noIcon?: boolean +}>() -const route = useRoute() -const site = useSiteData() -const { item } = toRefs(props) - -const hasHttpProtocol = computed(() => isLinkHttp(item.value.link)) -const hasNonHttpProtocol = computed( - () => isLinkMailto(item.value.link) || isLinkTel(item.value.link) +const tag = computed(() => (props.tag ?? props.href ? 'a' : 'span')) +const isExternal = computed( + () => props.href && EXTERNAL_URL_RE.test(props.href) ) - -const linkTarget = computed(() => { - if (hasNonHttpProtocol.value) return undefined - if (item.value.target) return item.value.target - if (hasHttpProtocol.value) return '_blank' - return undefined -}) - -const isBlankTarget = computed(() => linkTarget.value === '_blank') -const isRouterLink = computed( - () => - !hasHttpProtocol.value && !hasNonHttpProtocol.value && !isBlankTarget.value -) - -const linkRel = computed(() => { - if (hasNonHttpProtocol.value) return undefined - if (item.value.rel) return item.value.rel - if (isBlankTarget.value) return 'noopener noreferrer' - return undefined -}) - -const linkAriaLabel = computed(() => item.value.ariaLabel || item.value.text) - -const shouldBeActiveInSubpath = computed(() => { - const localeKeys = Object.keys(site.value.locales) - if (localeKeys.length) { - return !localeKeys.some((key) => key === item.value.link) - } - return item.value.link !== '/' -}) - -const isActiveInSubpath = computed(() => { - if (!shouldBeActiveInSubpath.value) return false - return route.path.startsWith(item.value.link) -}) - -const isActive = computed(() => { - if (isRouterLink.value) return false - if (item.value.activeMatch) { - return new RegExp(item.value.activeMatch).test(route.path) - } - return isActiveInSubpath.value -}) </script> <template> - <RouterLink - v-if="isRouterLink" - :class="{ 'router-link-active': isActive }" - :to="item.link" - :aria-label="linkAriaLabel" - v-bind="$attrs" + <Component + :is="tag" + class="auto-link" + :class="{ link: href }" + :href="href ? normalizeLink(href) : undefined" + :target="isExternal ? '_blank' : undefined" + :rel="isExternal ? 'noreferrer' : undefined" > - <slot name="before" /> - {{ item.text }} - <slot name="after" /> - </RouterLink> - <a - v-else - class="external-link" - :href="item.link" - :rel="linkRel" - :target="linkTarget" - :aria-label="linkAriaLabel" - v-bind="$attrs" - > - <slot name="before" /> - {{ item.text }} - <ExternalLinkIcon v-if="isBlankTarget" /> - <slot name="after" /> - </a> + <slot /> + <IconExternalLink v-if="isExternal && !noIcon" class="icon" /> + </Component> </template> + +<style scoped> +.icon { + display: inline-block; + margin-top: -1px; + margin-left: 4px; + width: 11px; + height: 11px; + fill: var(--vp-c-text-3); + transition: fill 0.25s; +} +</style> diff --git a/packages/theme/src/client/components/BackToTop.vue b/packages/theme/src/client/components/BackToTop.vue deleted file mode 100644 index b1ee97ac..00000000 --- a/packages/theme/src/client/components/BackToTop.vue +++ /dev/null @@ -1,65 +0,0 @@ -<script lang="ts" setup> -import { debounce } from 'ts-debounce' -import { onMounted, ref } from 'vue' -import { getScrollTop, scrollTo } from '../utils/index.js' -import { BackTopIcon } from './icons/index.js' - -const opacity = ref<number>(0) -const MAX_TOP = 300 - -const canShow = debounce((): void => { - opacity.value = getScrollTop(document) >= MAX_TOP ? 1 : 0 -}) - -const scrollToTop = (): void => { - scrollTo(document, 0) -} - -onMounted(() => { - if (__VUEPRESS_SSR__) return - canShow() - window.addEventListener('scroll', () => canShow(), false) -}) -</script> -<template> - <div class="btn-back-top" :style="{ opacity: opacity }" @click="scrollToTop"> - <BackTopIcon /> - </div> -</template> -<style lang="scss"> -@import '../styles/variables'; -.btn-back-top { - position: fixed; - right: 3rem; - bottom: 2.1rem; - width: 3rem; - height: 3rem; - text-align: center; - padding: 0.75rem 0; - border-radius: 50%; - background-color: var(--c-bg-container); - box-shadow: var(--shadow-md); - cursor: pointer; - transition: opacity var(--t-color); - z-index: 99; - - .back-top-icon { - width: 1.75rem; - height: 1.75rem; - color: var(--c-brand); - transition: color var(--t-color); - } - - &:hover { - .back-top-icon { - color: var(--c-brand-light); - } - } -} -@media (max-width: $MQMobile) { - .btn-back-top { - right: 1.25rem; - bottom: 2rem; - } -} -</style> diff --git a/packages/theme/src/client/components/Backdrop.vue b/packages/theme/src/client/components/Backdrop.vue new file mode 100644 index 00000000..94bc0567 --- /dev/null +++ b/packages/theme/src/client/components/Backdrop.vue @@ -0,0 +1,41 @@ +<script lang="ts" setup> +defineProps<{ + show: boolean +}>() +</script> + +<template> + <Transition name="fade"> + <div v-if="show" class="backdrop" /> + </Transition> +</template> + +<style scoped> +.backdrop { + position: fixed; + top: 0; + /*rtl:ignore*/ + right: 0; + bottom: 0; + /*rtl:ignore*/ + left: 0; + z-index: var(--vp-z-index-backdrop); + background: var(--vp-backdrop-bg-color); + transition: opacity 0.5s; +} + +.backdrop.fade-enter-from, +.backdrop.fade-leave-to { + opacity: 0; +} + +.backdrop.fade-leave-active { + transition-duration: 0.25s; +} + +@media (min-width: 1280px) { + .backdrop { + display: none; + } +} +</style> diff --git a/packages/theme/src/client/components/Blog.vue b/packages/theme/src/client/components/Blog.vue new file mode 100644 index 00000000..fd6f311e --- /dev/null +++ b/packages/theme/src/client/components/Blog.vue @@ -0,0 +1,34 @@ +<script lang="ts" setup> +import BlogAvatar from './BlogAvatar.vue' +import PostList from './PostList.vue' +</script> +<template> + <div class="blog-wrapper"> + <PostList /> + <BlogAvatar /> + </div> +</template> + +<style scoped> +.blog-wrapper { + display: flex; + align-items: flex-start; + justify-content: flex-start; + width: 100%; + margin: 0 auto; + padding-top: var(--vp-nav-height); +} + +@media (min-width: 960px) { + .blog-wrapper { + max-width: 784px; + padding-top: 0; + } +} + +@media (min-width: 1440px) { + .blog-wrapper { + max-width: 1104px; + } +} +</style> diff --git a/packages/theme/src/client/components/BlogAvatar.vue b/packages/theme/src/client/components/BlogAvatar.vue new file mode 100644 index 00000000..1ba61122 --- /dev/null +++ b/packages/theme/src/client/components/BlogAvatar.vue @@ -0,0 +1,52 @@ +<script lang="ts" setup> +import { computed } from 'vue' +import { useThemeLocaleData } from '../composables/index.js' + +const theme = useThemeLocaleData() + +const avatar = computed(() => theme.value.avatar) +</script> + +<template> + <div v-if="avatar" class="blog-avatar-wrapper"> + <div class="avatar-profile"> + <p v-if="avatar.url"> + <img :src="avatar.url" :alt="avatar.name" /> + </p> + <div> + <h3>{{ avatar.name }}</h3> + <p>{{ avatar.description }}</p> + </div> + </div> + </div> +</template> + +<style lang="scss" scoped> +.blog-avatar-wrapper { + position: sticky; + top: calc(var(--vp-nav-height) + 2rem); + width: 270px; + margin-left: 2rem; + margin-top: 2rem; + border-left: solid 1px var(--vp-c-divider); + text-align: center; + padding: 1rem 0; + + img { + width: 50%; + margin: auto; + } + + h3 { + font-size: 16px; + font-weight: 600; + margin-top: 1.5rem; + } +} + +@media (max-width: 768px) { + .blog-avatar-wrapper { + display: none; + } +} +</style> diff --git a/packages/theme/src/client/components/BlogInfo.vue b/packages/theme/src/client/components/BlogInfo.vue deleted file mode 100644 index 6beb2a6a..00000000 --- a/packages/theme/src/client/components/BlogInfo.vue +++ /dev/null @@ -1,32 +0,0 @@ -<script lang="ts" setup> -import { computed } from 'vue' -import { useThemeLocaleData } from '../composables/index.js' -import BloggerInfo from './BloggerInfo.vue' -const themeLocale = useThemeLocaleData() - -const showInfo = computed(() => { - const avatar = themeLocale.value.avatar || {} - return avatar.name || avatar.url -}) -</script> -<template> - <aside v-if="showInfo" class="blog-info-wrapper"> - <BloggerInfo /> - </aside> -</template> -<style lang="scss"> -@import '../styles/variables'; -.blog-info-wrapper { - width: 18.75rem; - margin-left: 1.25rem; - position: sticky; - top: calc(var(--navbar-height) + 1.25rem); - border-left: solid 1px var(--c-border); -} - -@media (max-width: $MQMobile) { - .blog-info-wrapper { - display: none; - } -} -</style> diff --git a/packages/theme/src/client/components/BloggerInfo.vue b/packages/theme/src/client/components/BloggerInfo.vue deleted file mode 100644 index da0cb09e..00000000 --- a/packages/theme/src/client/components/BloggerInfo.vue +++ /dev/null @@ -1,195 +0,0 @@ -<script lang="ts" setup> -import DropdownTransition from '@theme-plume/DropdownTransition.vue' -import { isLinkHttp, isLinkMailto } from '@vuepress/shared' -import type { FunctionalComponent, Ref } from 'vue' -import { computed, ref } from 'vue' -import { usePostStat, useThemeLocaleData } from '../composables/index.js' -import { - EmailIcon, - FacebookIcon, - FolderIcon, - GithubIcon, - LinkedinIcon, - PostIcon, - QQIcon, - TagIcon, - TwitterIcon, - WeiBoIcon, - ZhiHuIcon, -} from './icons/index.js' - -interface SocialItem { - url: string - icon: FunctionalComponent -} -type SocialData = SocialItem[] -type SocialRef = Ref<SocialData> - -const themeLocale = useThemeLocaleData() -const avatar = computed(() => themeLocale.value.avatar || {}) - -const useSocialList = (): SocialRef => { - const list: SocialRef = ref([]) - const social = themeLocale.value.social || {} - if (social.QQ) { - const url = isLinkHttp(social.QQ) - ? social.QQ - : `https://wpa.qq.com/msgrd?v=3&uin=${social.QQ}&site=qq&menu=yes` - list.value.push({ url, icon: QQIcon }) - } - if (social.email) { - const url = isLinkMailto(social.email) - ? social.email - : `mailto:${social.email}` - list.value.push({ url, icon: EmailIcon }) - } - if (social.github) { - const url = isLinkHttp(social.github) - ? social.github - : `https://github.com/${social.github}` - list.value.push({ url, icon: GithubIcon }) - } - if (social.linkedin) { - list.value.push({ url: social.linkedin, icon: LinkedinIcon }) - } - if (social.weiBo) { - list.value.push({ url: social.weiBo, icon: WeiBoIcon }) - } - if (social.zhiHu) { - list.value.push({ url: social.zhiHu, icon: ZhiHuIcon }) - } - if (social.facebook) { - list.value.push({ url: social.facebook, icon: FacebookIcon }) - } - if (social.twitter) { - list.value.push({ url: social.twitter, icon: TwitterIcon }) - } - return list -} -const socialList = useSocialList() - -const postStat = usePostStat() -</script> -<template> - <DropdownTransition> - <section class="blogger-info"> - <div class="blogger-profile"> - <p v-if="avatar.url" class="avatar-img"> - <img :src="avatar.url" :alt="avatar.name" /> - </p> - <div> - <h3>{{ avatar.name }}</h3> - <p>{{ avatar.description }}</p> - </div> - </div> - <p class="blogger-social"> - <a - v-for="item in socialList" - :key="item.url" - target="_blank" - :href="item.url" - > - <Component :is="item.icon" /> - </a> - </p> - <div class="post-stat"> - <div class="post-stat-item"> - <PostIcon /> - <span>{{ postStat.postTotal }}</span> - </div> - <div class="post-stat-item"> - <FolderIcon /> - <span>{{ postStat.categoryTotal }}</span> - </div> - <div class="post-stat-item"> - <TagIcon /> - <span>{{ postStat.tagTotal }}</span> - </div> - </div> - </section> - </DropdownTransition> -</template> -<style lang="scss"> -.blogger-info { - padding: 1.25rem; - // border-radius: var(--p-around); - // background-color: var(--c-bg-container); - // box-shadow: var(--shadow); - - .blogger-profile { - display: flex; - align-items: center; - - p { - font-size: 14px; - } - } - - .avatar-img { - width: 30%; - padding-right: 0.8rem; - img { - width: 100%; - } - } - - p, - h3 { - text-align: left; - margin: 0; - } - - h3 { - padding-bottom: 0.5rem; - font-size: 18px; - } - - .blogger-social { - vertical-align: middle; - text-align: center; - a { - display: inline-block; - margin: 0.5rem 0.15rem 0; - vertical-align: middle; - } - - .icon { - width: 28px; - height: 28px; - } - - .email-icon, - .github-icon, - .weiBo-icon { - width: 1.5rem; - height: 1.5rem; - } - } - - .post-stat { - // display: flex; - display: none; - justify-content: space-around; - align-items: center; - border-top: 1px solid var(--c-border); - margin-top: 1.75rem; - padding-top: 1rem; - - .post-stat-item { - text-align: center; - color: var(--c-text-quote); - .icon { - width: 2rem; - height: 2rem; - color: var(--c-text-lightest); - } - span { - display: inline-block; - width: 100%; - font-size: 1.25rem; - font-weight: 500; - } - } - } -} -</style> diff --git a/packages/theme/src/client/components/Category.vue b/packages/theme/src/client/components/Category.vue deleted file mode 100644 index 1f09e4b7..00000000 --- a/packages/theme/src/client/components/Category.vue +++ /dev/null @@ -1,43 +0,0 @@ -<script lang="ts" setup> -import BlogInfo from '@theme-plume/BlogInfo.vue' -import DropdownTransition from '@theme-plume/DropdownTransition.vue' -import { useCategoryList } from '../composables/index.js' -import CategoryGroup from './CategoryGroup.vue' - -const categoryList = useCategoryList() -</script> -<template> - <div class="category-wrapper"> - <div class="category-container"> - <DropdownTransition> - <div class="category-content"> - <CategoryGroup - v-for="(category, index) in categoryList" - :key="category.type + '_' + index" - :category="category" - :index="index" - /> - </div> - </DropdownTransition> - <BlogInfo></BlogInfo> - </div> - </div> -</template> -<style lang="scss"> -@import '../styles/_mixins'; - -.category-wrapper { - @include wrapper; - - .category-container { - @include container_wrapper; - display: flex; - align-items: flex-start; - padding: 1.25rem 0; - } - - .category-content { - flex: 1; - } -} -</style> diff --git a/packages/theme/src/client/components/CategoryGroup.vue b/packages/theme/src/client/components/CategoryGroup.vue deleted file mode 100644 index e510b54f..00000000 --- a/packages/theme/src/client/components/CategoryGroup.vue +++ /dev/null @@ -1,98 +0,0 @@ -<script lang="ts" setup> -import DropdownTransition from '@theme-plume/DropdownTransition.vue' -import type { FunctionalComponent, PropType } from 'vue' -import { h } from 'vue' -import type { CategoryItem } from '../composables/index.js' -const props = defineProps({ - category: { - type: Object as PropType<CategoryItem>, - required: true, - }, - head: { - type: Number, - default: 2, - }, - index: { - type: Number, - required: true, - }, -}) -const Heading: FunctionalComponent = () => { - const head = props.head > 4 ? 4 : props.head - return h( - `h${head}`, - { id: props.category.label.trim().replace(/\s+/g, '-') }, - [props.category.label] - ) -} -</script> -<template> - <DropdownTransition :delay="index * 0.04"> - <section class="category-group-wrapper"> - <Heading /> - <ul class="category-list"> - <li - v-for="post in category.postList" - :key="post.path" - class="category-item" - > - <span>[{{ post.createTime }}]</span> - <RouterLink :to="post.path">{{ post.title }}</RouterLink> - </li> - </ul> - <CategoryGroup - v-for="(cate, i) in category.children" - :key="cate.type + '__' + i" - :category="cate" - :head="head + 1" - :index="i" - /> - </section> - </DropdownTransition> -</template> -<style lang="scss"> -.category-group-wrapper { - padding: 1.25rem 1.5rem; - background-color: var(--c-bg-container); - border-radius: var(--p-around); - margin-bottom: 1.25rem; - // box-shadow: var(--shadow); - transition: box-shadow var(--t-color); - - .category-group-wrapper { - box-shadow: none; - border-radius: 0; - padding: 0; - margin-left: 1.25rem; - border-bottom: solid 1px var(--c-border); - - &:last-child { - border-bottom: none; - } - - .category-group-wrapper { - margin-left: 0; - } - } - - .category-list { - list-style: none; - padding-left: 1.25rem; - } - - .category-item { - span { - color: var(--c-text-lighter); - margin-right: 1.25rem; - } - - a { - color: var(--c-text); - - &:hover { - color: var(--c-text-accent); - } - } - } -} -</style> diff --git a/packages/theme/src/client/components/DarkModeButton.vue b/packages/theme/src/client/components/DarkModeButton.vue deleted file mode 100644 index 3d7abcc5..00000000 --- a/packages/theme/src/client/components/DarkModeButton.vue +++ /dev/null @@ -1,76 +0,0 @@ -<script setup lang="ts"> -import { useDarkMode, useThemeLocaleData } from '../composables/index.js' -const themeLocale = useThemeLocaleData() -const isDarkMode = useDarkMode() -const toggleDarkMode = (): void => { - isDarkMode.value = !isDarkMode.value -} -</script> - -<template> - <button - class="toggle-dark-button" - :title="themeLocale.toggleDarkMode" - @click="toggleDarkMode" - > - <svg - v-show="!isDarkMode" - class="icon" - focusable="false" - viewBox="0 0 32 32" - > - <path - d="M16 12.005a4 4 0 1 1-4 4a4.005 4.005 0 0 1 4-4m0-2a6 6 0 1 0 6 6a6 6 0 0 0-6-6z" - fill="currentColor" - /> - <path - d="M5.394 6.813l1.414-1.415l3.506 3.506L8.9 10.318z" - fill="currentColor" - /> - <path d="M2 15.005h5v2H2z" fill="currentColor" /> - <path - d="M5.394 25.197L8.9 21.691l1.414 1.415l-3.506 3.505z" - fill="currentColor" - /> - <path d="M15 25.005h2v5h-2z" fill="currentColor" /> - <path - d="M21.687 23.106l1.414-1.415l3.506 3.506l-1.414 1.414z" - fill="currentColor" - /> - <path d="M25 15.005h5v2h-5z" fill="currentColor" /> - <path - d="M21.687 8.904l3.506-3.506l1.414 1.415l-3.506 3.505z" - fill="currentColor" - /> - <path d="M15 2.005h2v5h-2z" fill="currentColor" /> - </svg> - - <svg v-show="isDarkMode" class="icon" focusable="false" viewBox="0 0 32 32"> - <path - d="M13.502 5.414a15.075 15.075 0 0 0 11.594 18.194a11.113 11.113 0 0 1-7.975 3.39c-.138 0-.278.005-.418 0a11.094 11.094 0 0 1-3.2-21.584M14.98 3a1.002 1.002 0 0 0-.175.016a13.096 13.096 0 0 0 1.825 25.981c.164.006.328 0 .49 0a13.072 13.072 0 0 0 10.703-5.555a1.01 1.01 0 0 0-.783-1.565A13.08 13.08 0 0 1 15.89 4.38A1.015 1.015 0 0 0 14.98 3z" - fill="currentColor" - /> - </svg> - </button> -</template> - -<style lang="scss"> -.toggle-dark-button { - display: flex; - margin-left: 1rem; - border: 0; - background: none; - color: var(--c-text); - opacity: 0.8; - cursor: pointer; - - &:hover { - opacity: 1; - } - - .icon { - width: 1.25rem; - height: 1.25rem; - } -} -</style> diff --git a/packages/theme/src/client/components/DropdownTransition.vue b/packages/theme/src/client/components/DropdownTransition.vue deleted file mode 100644 index 0b4bb50d..00000000 --- a/packages/theme/src/client/components/DropdownTransition.vue +++ /dev/null @@ -1,59 +0,0 @@ -<script lang="ts"> -import { defineComponent, Transition, TransitionGroup } from 'vue' -import type { PropType } from 'vue' -export default defineComponent({ - name: 'DropdownTransition', - components: { - Transition, - TransitionGroup, - }, - props: { - type: { type: String as PropType<'single' | 'group'>, default: 'single' }, - delay: { type: Number, default: 0 }, - duration: { type: Number, default: 0.25 }, - }, - setup(props) { - const setStyle = (item: Element): void => { - ;( - item as HTMLElement - ).style.transition = `transform ${props.duration}s ease-in-out ${props.delay}s, opacity ${props.duration}s ease-in-out ${props.delay}s` - ;(item as HTMLElement).style.transform = 'translateY(-20px)' - ;(item as HTMLElement).style.opacity = '0' - } - const unsetStyle = (item: Element): void => { - ;(item as HTMLElement).style.transform = 'translateY(0)' - ;(item as HTMLElement).style.opacity = '1' - } - return { - setStyle, - unsetStyle, - } - }, -}) -</script> -<template> - <Transition - v-if="type === 'single'" - name="drop" - appear - @appear="setStyle" - @after-appear="unsetStyle" - @enter="setStyle" - @after-enter="unsetStyle" - @before-leave="setStyle" - > - <slot /> - </Transition> - <TransitionGroup - v-if="type === 'group'" - name="drop" - appear - @appear="setStyle" - @after-appear="unsetStyle" - @enter="setStyle" - @after-enter="unsetStyle" - @before-leave="setStyle" - > - <slot /> - </TransitionGroup> -</template> diff --git a/packages/theme/src/client/components/Flyout/MenuGroup.vue b/packages/theme/src/client/components/Flyout/MenuGroup.vue new file mode 100644 index 00000000..dc12f21e --- /dev/null +++ b/packages/theme/src/client/components/Flyout/MenuGroup.vue @@ -0,0 +1,46 @@ +<script lang="ts" setup> +import MenuLink from './MenuLink.vue' + +defineProps<{ + text?: string + items: any[] +}>() +</script> + +<template> + <div class="menu-group"> + <p v-if="text" class="title">{{ text }}</p> + + <template v-for="item in items"> + <MenuLink v-if="'link' in item" :key="item?.link" :item="item" /> + </template> + </div> +</template> + +<style scoped> +.menu-group { + margin: 12px -12px 0; + border-top: 1px solid var(--vp-c-divider); + padding: 12px 12px 0; +} + +.menu-group:first-child { + margin-top: 0; + border-top: 0; + padding-top: 0; +} + +.menu-group + .menu-group { + margin-top: 12px; + border-top: 1px solid var(--vp-c-divider); +} + +.title { + padding: 0 12px; + line-height: 32px; + font-size: 14px; + font-weight: 600; + color: var(--vp-c-text-2); + transition: color 0.25s; +} +</style> diff --git a/packages/theme/src/client/components/Flyout/MenuLink.vue b/packages/theme/src/client/components/Flyout/MenuLink.vue new file mode 100644 index 00000000..aa43cf43 --- /dev/null +++ b/packages/theme/src/client/components/Flyout/MenuLink.vue @@ -0,0 +1,57 @@ +<script lang="ts" setup> +import { usePageData } from '@vuepress/client' +import { isActive } from '../../utils/index.js' +import AutoLink from '../AutoLink.vue' + +defineProps<{ + item: any +}>() + +const page = usePageData() +</script> + +<template> + <div class="menu-link"> + <AutoLink + :class="{ + active: isActive( + page.path, + item.activeMatch || item.link, + !!item.activeMatch + ), + }" + :href="item.link" + > + {{ item.text }} + </AutoLink> + </div> +</template> + +<style scoped> +.menu-group + .menu-link { + margin: 12px -12px 0; + border-top: 1px solid var(--vp-c-divider); + padding: 12px 12px 0; +} + +.link { + display: block; + border-radius: 6px; + padding: 0 12px; + line-height: 32px; + font-size: 14px; + font-weight: 500; + color: var(--vp-c-text-1); + white-space: nowrap; + transition: background-color 0.25s, color 0.25s; +} + +.link:hover { + color: var(--vp-c-brand); + background-color: var(--vp-c-bg-elv-mute); +} + +.link.active { + color: var(--vp-c-brand); +} +</style> diff --git a/packages/theme/src/client/components/Flyout/VMenu.vue b/packages/theme/src/client/components/Flyout/VMenu.vue new file mode 100644 index 00000000..91c3f491 --- /dev/null +++ b/packages/theme/src/client/components/Flyout/VMenu.vue @@ -0,0 +1,72 @@ +<script lang="ts" setup> +import MenuGroup from './MenuGroup.vue' +import MenuLink from './MenuLink.vue' + +defineProps<{ + items?: any[] +}>() +</script> + +<template> + <div class="menu-wrapper"> + <div v-if="items" class="items"> + <template v-for="item in items" :key="item.text"> + <MenuLink v-if="'link' in item" :item="item" /> + <MenuGroup v-else :text="item.text" :items="item.items" /> + </template> + </div> + + <slot /> + </div> +</template> + +<style scoped> +.menu-wrapper { + border-radius: 12px; + padding: 12px; + min-width: 128px; + border: 1px solid var(--vp-c-divider); + background-color: var(--vp-c-bg-elv); + box-shadow: var(--vp-shadow-3); + transition: background-color 0.5s; + max-height: calc(100vh - var(--vp-nav-height)); + overflow-y: auto; +} + +.menu-wrapper :deep(.group) { + margin: 0 -12px; + padding: 0 12px 12px; +} + +.menu-wrapper :deep(.group + .group) { + border-top: 1px solid var(--vp-c-divider); + padding: 11px 12px 12px; +} + +.menu-wrapper :deep(.group:last-child) { + padding-bottom: 0; +} + +.menu-wrapper :deep(.group + .item) { + border-top: 1px solid var(--vp-c-divider); + padding: 11px 16px 0; +} + +.menu-wrapper :deep(.item) { + padding: 0 16px; + white-space: nowrap; +} + +.menu-wrapper :deep(.label) { + flex-grow: 1; + line-height: 28px; + font-size: 12px; + font-weight: 500; + color: var(--vp-c-text-2); + transition: color 0.5s; +} + +.menu-wrapper :deep(.action) { + padding-left: 24px; +} +</style> diff --git a/packages/theme/src/client/components/Flyout/index.vue b/packages/theme/src/client/components/Flyout/index.vue new file mode 100644 index 00000000..f4456911 --- /dev/null +++ b/packages/theme/src/client/components/Flyout/index.vue @@ -0,0 +1,138 @@ +<script lang="ts" setup> +import { ref } from 'vue' +import { useFlyout } from '../../composables/flyout.js' +import IconChevronDown from '../icons/IconChevronDown.vue' +import IconMoreHorizontal from '../icons/IconMoreHorizontal.vue' +import VMenu from './VMenu.vue' + +defineProps<{ + icon?: any + button?: string + label?: string + items?: any[] +}>() + +const open = ref(false) +const el = ref<HTMLElement>() + +useFlyout({ el, onBlur }) + +function onBlur() { + open.value = false +} +</script> + +<template> + <div + ref="el" + class="flyout-wrapper" + @mouseenter="open = true" + @mouseleave="open = false" + > + <button + type="button" + class="button" + aria-haspopup="true" + :aria-expanded="open" + :aria-label="label" + @click="open = !open" + > + <span v-if="button || icon" class="text"> + <Component :is="icon" v-if="icon" class="option-icon" /> + {{ button }} + <IconChevronDown class="text-icon" /> + </span> + + <IconMoreHorizontal v-else class="icon" /> + </button> + + <div class="menu"> + <VMenu :items="items"> + <slot /> + </VMenu> + </div> + </div> +</template> + +<style scoped> +.flyout-wrapper { + position: relative; +} + +.flyout-wrapper:hover { + color: var(--vp-c-brand); + transition: color 0.25s; +} + +.flyout-wrapper:hover .text { + color: var(--vp-c-text-2); +} + +.flyout-wrapper:hover .icon { + fill: var(--vp-c-text-2); +} + +.flyout-wrapper.active .text { + color: var(--vp-c-brand); +} + +.flyout-wrapper.active:hover .text { + color: var(--vp-c-brand-dark); +} + +.flyout-wrapper:hover .menu, +.button[aria-expanded='true'] + .menu { + opacity: 1; + visibility: visible; + transform: translateY(0); +} + +.button { + display: flex; + align-items: center; + padding: 0 12px; + height: var(--vp-nav-height); + color: var(--vp-c-text-1); + transition: color 0.5s; +} + +.text { + display: flex; + align-items: center; + line-height: var(--vp-nav-height); + font-size: 14px; + font-weight: 500; + color: var(--vp-c-text-1); + transition: color 0.25s; +} + +.option-icon { + margin-right: 0px; + width: 16px; + height: 16px; + fill: currentColor; +} + +.text-icon { + margin-left: 4px; + width: 14px; + height: 14px; + fill: currentColor; +} + +.icon { + width: 20px; + height: 20px; + fill: currentColor; + transition: fill 0.25s; +} + +.menu { + position: absolute; + top: calc(var(--vp-nav-height) / 2 + 20px); + right: 0; + opacity: 0; + visibility: hidden; + transition: opacity 0.25s, visibility 0.25s, transform 0.25s; +} +</style> diff --git a/packages/theme/src/client/components/Home.vue b/packages/theme/src/client/components/Home.vue index 5a2b00bb..f70353f5 100644 --- a/packages/theme/src/client/components/Home.vue +++ b/packages/theme/src/client/components/Home.vue @@ -1,28 +1,138 @@ <script lang="ts" setup> -import BlogInfo from '@theme-plume/BlogInfo.vue' -import HomeBigBanner from '@theme-plume/HomeBigBanner.vue' -import PostList from '@theme-plume/PostList.vue' +import { usePageFrontmatter, withBase } from '@vuepress/client' +import { computed } from 'vue' +import type { PlumeThemeHomeFrontmatter } from '../../shared/index.js' +import { useThemeLocaleData } from '../composables/index.js' +import VButton from './VButton.vue' + +const matter = usePageFrontmatter<PlumeThemeHomeFrontmatter>() +const theme = useThemeLocaleData() + +const homeStyle = computed(() => { + return { + 'background-image': `url(${withBase(matter.value.banner || '')})`, + } +}) + +const name = computed(() => matter.value.hero?.name) +const profession = computed(() => matter.value.hero?.profession) +const text = computed(() => matter.value.hero?.text) + +const actions = computed(() => { + return matter.value.hero?.actions ?? [] +}) </script> <template> - <div class="plume-theme-home"> - <HomeBigBanner></HomeBigBanner> - <div class="plume-theme-container"> - <PostList></PostList> - <BlogInfo></BlogInfo> + <div class="plume-home" :style="homeStyle"> + <div class="container"> + <div v-if="matter.hero" class="content"> + <h2 v-if="name" class="hero-name">{{ name }}</h2> + <p v-if="profession" class="hero-profession"> + <span class="line"></span> <span>{{ profession }}</span> + </p> + <p v-if="text" class="hero-text">{{ text }}</p> + <div v-if="actions" class="actions"> + <div v-for="action in actions" :key="action.link" class="action"> + <VButton + tag="a" + size="medium" + :theme="action.theme" + :text="action.text" + :href="action.link" + /> + </div> + </div> + </div> </div> </div> </template> -<style lang="scss"> -@import '../styles/_mixins'; -.plume-theme-home { - @include wrapper; - .plume-theme-container { - @include container_wrapper; - display: flex; - justify-content: flex-start; - align-items: flex-start; - padding: 1.25rem 0; +<style scoped> +.plume-home { + width: 100%; + background-size: cover; + background-repeat: no-repeat; + background-position: center; + min-height: calc(100vh - var(--vp-nav-height)); + filter: var(--vp-home-hero-image-filter); +} + +.plume-home .container { + display: flex; + align-items: center; + justify-content: flex-start; + width: 100%; + margin: 0 auto; + padding-top: 4rem; +} + +.plume-home .content { + padding: 0 2rem; +} + +@media (min-width: 960px) { + .plume-home .container { + max-width: 768px; + padding-top: 8rem; } } + +@media (min-width: 1440px) { + .plume-home .container { + max-width: 1104px; + padding-top: 8rem; + } + + .plume-home .content .hero-profession { + font-size: 32px; + } +} + +.plume-home .content .hero-name { + font-size: 100px; + font-weight: 600; + line-height: 1; + color: var(--vp-c-text-hero-name); +} +.plume-home .content .hero-profession { + display: flex; + align-items: center; + font-size: 24px; + font-weight: 500; + margin-top: 1rem; + color: var(--vp-c-text-hero-profession); + line-height: 1.25; +} + +.plume-home .content .hero-profession .line { + display: inline-block; + width: 80px; + height: 0; + border-top: solid 1px var(--vp-c-text-hero-profession); + margin-right: 1rem; +} + +.plume-home .content .hero-text { + width: 100%; + max-width: 700px; + font-size: 16px; + font-weight: 500; + margin-top: 1.5rem; + color: var(--vp-c-text-hero-text); + padding: 6px 20px; + border-radius: 5px; + background-color: rgba(0, 0, 0, 0.25); +} + +.actions { + display: flex; + flex-wrap: wrap; + margin: -6px; + padding-top: 24px; +} + +.action { + flex-shrink: 0; + padding: 6px; +} </style> diff --git a/packages/theme/src/client/components/HomeBigBanner.vue b/packages/theme/src/client/components/HomeBigBanner.vue deleted file mode 100644 index f6dd81c1..00000000 --- a/packages/theme/src/client/components/HomeBigBanner.vue +++ /dev/null @@ -1,166 +0,0 @@ -<script lang="ts" setup> -import { usePageFrontmatter, withBase } from '@vuepress/client' -import { isLinkHttp } from '@vuepress/shared' -import { computed, onMounted, ref } from 'vue' -import type { PlumeThemeHomeFrontmatter } from '../../shared/index.js' -import { useThemeLocaleData } from '../composables/index.js' -import { scrollTo } from '../utils/index.js' -import { ArrowBottomIcon } from './icons/index.js' - -const frontmatter = usePageFrontmatter<PlumeThemeHomeFrontmatter>() -const MOBILE_WIDTH = 716 - -const bannerImg = ref(frontmatter.value.banner || '') -const hasBanner = computed(() => !!bannerImg.value) -const bannerStyle = computed(() => { - if (!hasBanner.value) return '' - const url = isLinkHttp(bannerImg.value) - ? bannerImg.value - : withBase(bannerImg.value) - return { - 'background-image': `url(${url})`, - } -}) - -function handleResize(): void { - if (__VUEPRESS_SSR__) return - const width = document.documentElement.offsetWidth - if (!hasBanner.value) return - if (width < MOBILE_WIDTH) { - bannerImg.value = - frontmatter.value.mobileBanner || frontmatter.value.banner || '' - } else { - bannerImg.value = frontmatter.value.banner || '' - } -} -onMounted(() => { - handleResize() - window.addEventListener('resize', handleResize, false) - window.addEventListener('orientationchange', handleResize, false) -}) -let screenHeight = 0 -const arrowHandle = (): void => { - if (!screenHeight) { - screenHeight = - document.documentElement.clientHeight || document.body.clientHeight - screenHeight -= - document.querySelector<HTMLElement>('.navbar-wrapper')?.offsetHeight || 0 - } - scrollTo(document, screenHeight) -} - -const themeLocale = useThemeLocaleData() -const avatar = themeLocale.value.avatar || {} -</script> -<template> - <div v-if="hasBanner" class="home-big-banner-wrapper" :style="bannerStyle"> - <ArrowBottomIcon @click="arrowHandle" /> - <div class="home-blogger-info"> - <div class="blogger-img"> - <img :src="avatar.url" :alt="avatar.name" /> - </div> - <h3>{{ avatar.name }}</h3> - <p v-if="frontmatter.motto" class="blogger-motto"> - {{ frontmatter.motto }} - </p> - </div> - </div> -</template> -<style lang="scss"> -@import '../styles/_variables'; - -.home-big-banner-wrapper { - position: relative; - display: flex; - width: 100%; - height: calc(100vh - var(--navbar-height)); - background-color: transparent; - background-position: 0 0; - background-size: cover; - background-repeat: no-repeat; - background-attachment: fixed; - - .arrow-bottom-icon { - position: absolute; - bottom: 1.25rem; - left: 50%; - width: 3rem; - height: 3rem; - color: var(--c-home-arrow-bottom); - animation: home-banner-arrow 1.5s ease 0.3s infinite; - cursor: pointer; - } - - .home-blogger-info { - margin: auto; - text-align: center; - .blogger-img { - width: 15rem; - height: 15rem; - border-radius: 50%; - overflow: hidden; - padding: 1.25rem; - background-color: rgba(0, 0, 0, 0.25); - margin: auto; - - img { - width: 100%; - border-radius: 50%; - } - } - - h3 { - display: inline-block; - font-size: 4rem; - max-width: var(--content-width); - color: rgba(255, 255, 255, 0.85); - padding: 0 1.25rem; - margin: 1rem 0; - } - - .blogger-motto { - max-width: var(--content-width); - font-size: 2rem; - color: rgba(255, 255, 255, 0.75); - padding: 0 1.25rem; - border-radius: var(--p-around); - } - } -} - -@media (max-width: $MQMobile) { - .home-big-banner-wrapper .home-blogger-info { - .blogger-img { - width: 50vw; - height: 50vw; - } - h3 { - font-size: 3rem; - } - .blogger-motto { - font-size: 1.5rem; - } - } -} - -@keyframes home-banner-arrow { - 0% { - opacity: 0; - transform: translateX(-50%) translateY(-10px); - } - - 10% { - opacity: 0.45; - } - - 95% { - opacity: 1; - transform: translateX(-50%) translateY(0); - } - - 100% { - opacity: 0.25; - transform: translateX(-50%) translateY(-7px); - } -} -</style> diff --git a/packages/theme/src/client/components/LayoutContent.vue b/packages/theme/src/client/components/LayoutContent.vue new file mode 100644 index 00000000..37ae20e7 --- /dev/null +++ b/packages/theme/src/client/components/LayoutContent.vue @@ -0,0 +1,52 @@ +<script lang="ts" setup> +import { useSidebar } from '../composables/index.js' + +const { hasSidebar } = useSidebar() +</script> +<template> + <div + id="LayoutContent" + class="layout-content" + :class="{ 'has-sidebar': hasSidebar }" + > + <slot /> + </div> +</template> + +<style scoped> +.layout-content { + flex-grow: 1; + flex-shrink: 0; + margin: var(--vp-layout-top-height, 0px) auto 0; + width: 100%; +} + +.layout-content.is-home { + width: 100%; + max-width: 100%; +} + +.layout-content.has-sidebar { + margin: 0; +} + +@media (min-width: 960px) { + .layout-content { + padding-top: var(--vp-nav-height); + } + + .layout-content.has-sidebar { + margin: var(--vp-layout-top-height, 0px) 0 0; + padding-left: var(--vp-sidebar-width); + } +} + +@media (min-width: 1440px) { + .layout-content.has-sidebar { + padding-right: calc((100vw - var(--vp-layout-max-width)) / 2); + padding-left: calc( + (100vw - var(--vp-layout-max-width)) / 2 + var(--vp-sidebar-width) + ); + } +} +</style> diff --git a/packages/theme/src/client/components/LocalNav.vue b/packages/theme/src/client/components/LocalNav.vue new file mode 100644 index 00000000..3a7b5fa6 --- /dev/null +++ b/packages/theme/src/client/components/LocalNav.vue @@ -0,0 +1,109 @@ +<script lang="ts" setup> +import { useSidebar, useThemeLocaleData } from '../composables/index.js' +import IconAlignLeft from './icons/IconAlignLeft.vue' + +defineProps<{ + open: boolean +}>() + +defineEmits<{ + (e: 'open-menu'): void +}>() + +const theme = useThemeLocaleData() +const { hasSidebar } = useSidebar() + +function scrollToTop() { + window.scrollTo({ top: 0, left: 0, behavior: 'smooth' }) +} +</script> + +<template> + <div v-if="hasSidebar" class="local-nav"> + <button + class="menu" + :aria-expanded="open" + aria-controls="SidebarNav" + @click="$emit('open-menu')" + > + <IconAlignLeft class="menu-icon" /> + <span class="menu-text"> Menu </span> + </button> + + <a class="top-link" href="#" @click="scrollToTop"> Return to top </a> + </div> +</template> + +<style scoped> +.local-nav { + position: sticky; + top: 0; + /*rtl:ignore*/ + left: 0; + z-index: var(--vp-z-index-local-nav); + display: flex; + justify-content: space-between; + align-items: center; + border-bottom: 1px solid var(--vp-c-gutter); + padding-top: var(--vp-layout-top-height, 0px); + width: 100%; + background-color: var(--vp-local-nav-bg-color); + transition: border-color 0.5s, background-color 0.5s; +} + +@media (min-width: 960px) { + .local-nav { + display: none; + } +} + +.menu { + display: flex; + align-items: center; + padding: 12px 24px 11px; + line-height: 24px; + font-size: 12px; + font-weight: 500; + color: var(--vp-c-text-2); + transition: color 0.5s; +} + +.menu:hover { + color: var(--vp-c-text-1); + transition: color 0.25s; +} + +@media (min-width: 768px) { + .menu { + padding: 0 32px; + } +} + +.menu-icon { + margin-right: 8px; + width: 16px; + height: 16px; + fill: currentColor; +} + +.top-link { + display: block; + padding: 12px 24px 11px; + line-height: 24px; + font-size: 12px; + font-weight: 500; + color: var(--vp-c-text-2); + transition: color 0.5s; +} + +.top-link:hover { + color: var(--vp-c-text-1); + transition: color 0.25s; +} + +@media (min-width: 768px) { + .top-link { + padding: 12px 32px 11px; + } +} +</style> diff --git a/packages/theme/src/client/components/Nav/NavBar.vue b/packages/theme/src/client/components/Nav/NavBar.vue new file mode 100644 index 00000000..bd517d53 --- /dev/null +++ b/packages/theme/src/client/components/Nav/NavBar.vue @@ -0,0 +1,228 @@ +<script lang="ts" setup> +import { useWindowScroll } from '@vueuse/core' +import { computed } from 'vue' +import { useSidebar } from '../../composables/sidebar.js' +import NavBarAppearance from './NavBarAppearance.vue' +import NavBarExtra from './NavBarExtra.vue' +import NavBarHamburger from './NavBarHamburger.vue' +import NavBarMenu from './NavBarMenu.vue' +import NavBarSearch from './NavBarSearch.vue' +import NavBarSocialLinks from './NavBarSocialLinks.vue' +import NavBarTitle from './NavBarTitle.vue' + +defineProps<{ + isScreenOpen: boolean +}>() +defineEmits<{ + (e: 'toggle-screen'): void +}>() + +const { y } = useWindowScroll() +const { hasSidebar } = useSidebar() + +const classes = computed(() => ({ + 'has-sidebar': hasSidebar.value, + 'fill': y.value > 0, +})) +</script> + +<template> + <div class="navbar-wrapper" :class="classes"> + <div class="container"> + <div class="title"> + <NavBarTitle /> + </div> + + <div class="content"> + <div class="curtain"></div> + <div class="content-body"> + <NavBarSearch class="search" /> + <NavBarMenu class="menu" /> + <NavBarAppearance class="appearance" /> + <NavBarSocialLinks class="social-links" /> + <NavBarExtra class="extra" /> + <NavBarHamburger + class="hamburger" + :active="isScreenOpen" + @click="$emit('toggle-screen')" + /> + </div> + </div> + </div> + </div> +</template> + +<style scoped> +.navbar-wrapper { + position: relative; + border-bottom: 1px solid transparent; + padding: 0 8px 0 24px; + height: var(--vp-nav-height); + transition: border-color 0.5s, background-color 0.5s; + pointer-events: none; +} + +.navbar-wrapper.has-sidebar { + border-bottom-color: var(--vp-c-gutter); +} + +@media (min-width: 768px) { + .navbar-wrapper { + padding: 0 32px; + } +} + +@media (min-width: 960px) { + .navbar-wrapper.has-sidebar { + border-bottom-color: transparent; + padding: 0; + } + + .navbar-wrapper.fill:not(.has-sidebar) { + border-bottom-color: var(--vp-c-gutter); + background-color: var(--vp-nav-bg-color); + } +} + +.container { + display: flex; + justify-content: space-between; + margin: 0 auto; + max-width: calc(var(--vp-layout-max-width) - 64px); + height: var(--vp-nav-height); + pointer-events: none; +} + +.container :deep(*) { + pointer-events: auto; +} + +@media (min-width: 960px) { + .navbar-wrapper.has-sidebar .container { + max-width: 100%; + } +} + +.title { + flex-shrink: 0; + height: calc(var(--vp-nav-height) - 1px); + transition: background-color 0.5s; +} + +@media (min-width: 960px) { + .navbar-wrapper.has-sidebar .title { + position: absolute; + top: 0; + left: 0; + z-index: 2; + padding: 0 32px; + width: var(--vp-sidebar-width); + height: var(--vp-nav-height); + background-color: transparent; + } +} + +@media (min-width: 1440px) { + .navbar-wrapper.has-sidebar .title { + padding-left: max( + 32px, + calc((100% - (var(--vp-layout-max-width) - 64px)) / 2) + ); + width: calc( + (100% - (var(--vp-layout-max-width) - 64px)) / 2 + var(--vp-sidebar-width) - + 32px + ); + } +} + +.content { + flex-grow: 1; +} + +@media (min-width: 960px) { + .navbar-wrapper.has-sidebar .content { + position: relative; + z-index: 1; + padding-right: 32px; + padding-left: var(--vp-sidebar-width); + } +} + +@media (min-width: 1440px) { + .navbar-wrapper.has-sidebar .content { + padding-right: calc((100vw - var(--vp-layout-max-width)) / 2 + 32px); + padding-left: calc( + (100vw - var(--vp-layout-max-width)) / 2 + var(--vp-sidebar-width) + ); + } +} + +.content-body { + display: flex; + justify-content: flex-end; + align-items: center; + height: calc(var(--vp-nav-height) - 1px); + transition: background-color 0.5s; +} + +@media (min-width: 960px) { + .navbar-wrapper.has-sidebar .content-body, + .navbar-wrapper.fill .content-body { + position: relative; + background-color: var(--vp-nav-bg-color); + } +} + +.menu + .translations::before, +.menu + .appearance::before, +.menu + .social-links::before, +.translations + .appearance::before, +.appearance + .social-links::before { + margin-right: 8px; + margin-left: 8px; + width: 1px; + height: 24px; + background-color: var(--vp-c-divider); + content: ''; +} + +.menu + .appearance::before, +.translations + .appearance::before { + margin-right: 16px; +} + +.appearance + .social-links::before { + margin-left: 16px; +} + +.social-links { + margin-right: -8px; +} + +@media (min-width: 960px) { + .navbar-wrapper.has-sidebar .curtain { + position: absolute; + right: 0; + bottom: -31px; + width: calc(100% - var(--vp-sidebar-width)); + height: 32px; + } + + .navbar-wrapper.has-sidebar .curtain::before { + display: block; + width: 100%; + height: 32px; + background: linear-gradient(var(--vp-c-bg), transparent 70%); + content: ''; + } +} + +@media (min-width: 1440px) { + .navbar-wrapper.has-sidebar .curtain { + width: calc( + 100% - + ((100vw - var(--vp-layout-max-width)) / 2 + var(--vp-sidebar-width)) + ); + } +} +</style> diff --git a/packages/theme/src/client/components/Nav/NavBarAppearance.vue b/packages/theme/src/client/components/Nav/NavBarAppearance.vue new file mode 100644 index 00000000..b04ed1fd --- /dev/null +++ b/packages/theme/src/client/components/Nav/NavBarAppearance.vue @@ -0,0 +1,25 @@ +<script lang="ts" setup> +import { useThemeLocaleData } from '../../composables/index.js' +import SwitchAppearance from '../SwitchAppearance.vue' + +const theme = useThemeLocaleData() +</script> + +<template> + <div v-if="theme.appearance" class="navbar-appearance"> + <SwitchAppearance /> + </div> +</template> + +<style scoped> +.navbar-appearance { + display: none; +} + +@media (min-width: 1280px) { + .navbar-appearance { + display: flex; + align-items: center; + } +} +</style> diff --git a/packages/theme/src/client/components/Nav/NavBarExtra.vue b/packages/theme/src/client/components/Nav/NavBarExtra.vue new file mode 100644 index 00000000..fc8f22a7 --- /dev/null +++ b/packages/theme/src/client/components/Nav/NavBarExtra.vue @@ -0,0 +1,78 @@ +<script lang="ts" setup> +import { computed } from 'vue' +import { useThemeLocaleData } from '../../composables/index.js' +import Flyout from '../Flyout/index.vue' +import SocialLinks from '../SocialLinks.vue' +import SwitchAppearance from '../SwitchAppearance.vue' + +const theme = useThemeLocaleData() + +const hasExtraContent = computed( + () => theme.value.appearance || theme.value.social +) +</script> + +<template> + <Flyout v-if="hasExtraContent" class="navbar-extra" label="extra navigation"> + <div v-if="theme.appearance" class="group"> + <div class="item appearance"> + <p class="label">Appearance</p> + <div class="appearance-action"> + <SwitchAppearance /> + </div> + </div> + </div> + + <div v-if="theme.social" class="group"> + <div class="item social-links"> + <SocialLinks class="social-links-list" :links="theme.social" /> + </div> + </div> + </Flyout> +</template> + +<style scoped> +.navbar-extra { + display: none; + margin-right: -12px; +} + +@media (min-width: 768px) { + .navbar-extra { + display: block; + } +} + +@media (min-width: 1280px) { + .navbar-extra { + display: none; + } +} + +.trans-title { + padding: 0 24px 0 12px; + line-height: 32px; + font-size: 14px; + font-weight: 700; + color: var(--vp-c-text-1); +} + +.item.appearance, +.item.social-links { + display: flex; + align-items: center; + padding: 0 12px; +} + +.item.appearance { + min-width: 176px; +} + +.appearance-action { + margin-right: -2px; +} + +.social-links-list { + margin: -4px -8px; +} +</style> diff --git a/packages/theme/src/client/components/Nav/NavBarHamburger.vue b/packages/theme/src/client/components/Nav/NavBarHamburger.vue new file mode 100644 index 00000000..f4129e2a --- /dev/null +++ b/packages/theme/src/client/components/Nav/NavBarHamburger.vue @@ -0,0 +1,118 @@ +<script lang="ts" setup> +defineProps<{ + active: boolean +}>() + +defineEmits<{ + (e: 'click'): void +}>() +</script> + +<template> + <button + type="button" + class="navbar-hamburger" + :class="{ active }" + aria-label="mobile navigation" + :aria-expanded="active" + aria-controls="nav-screen" + @click="$emit('click')" + > + <span class="container"> + <span class="top" /> + <span class="middle" /> + <span class="bottom" /> + </span> + </button> +</template> + +<style scoped> +.navbar-hamburger { + display: flex; + justify-content: center; + align-items: center; + width: 48px; + height: var(--vp-nav-height); +} + +@media (min-width: 768px) { + .navbar-hamburger { + display: none; + } +} + +.container { + position: relative; + width: 16px; + height: 14px; + overflow: hidden; +} + +.navbar-hamburger:hover .top { + top: 0; + left: 0; + transform: translateX(4px); +} + +.navbar-hamburger:hover .middle { + top: 6px; + left: 0; + transform: translateX(0); +} + +.navbar-hamburger:hover .bottom { + top: 12px; + left: 0; + transform: translateX(8px); +} + +.navbar-hamburger.active .top { + top: 6px; + transform: translateX(0) rotate(225deg); +} + +.navbar-hamburger.active .middle { + top: 6px; + transform: translateX(16px); +} + +.navbar-hamburger.active .bottom { + top: 6px; + transform: translateX(0) rotate(135deg); +} + +.navbar-hamburger.active:hover .top, +.navbar-hamburger.active:hover .middle, +.navbar-hamburger.active:hover .bottom { + background-color: var(--vp-c-text-2); + transition: top 0.25s, background-color 0.25s, transform 0.25s; +} + +.top, +.middle, +.bottom { + position: absolute; + width: 16px; + height: 2px; + background-color: var(--vp-c-text-1); + transition: top 0.25s, background-color 0.5s, transform 0.25s; +} + +.top { + top: 0; + left: 0; + transform: translateX(0); +} + +.middle { + top: 6px; + left: 0; + transform: translateX(8px); +} + +.bottom { + top: 12px; + left: 0; + transform: translateX(4px); +} +</style> diff --git a/packages/theme/src/client/components/Nav/NavBarMenu.vue b/packages/theme/src/client/components/Nav/NavBarMenu.vue new file mode 100644 index 00000000..10c45b53 --- /dev/null +++ b/packages/theme/src/client/components/Nav/NavBarMenu.vue @@ -0,0 +1,35 @@ +<script lang="ts" setup> +import { useThemeLocaleData } from '../../composables/themeData.js' +import NavBarMenuGroup from './NavBarMenuGroup.vue' +import NavBarMenuLink from './NavBarMenuLink.vue' + +const theme = useThemeLocaleData() +</script> + +<template> + <nav + v-if="theme.navbar" + aria-labelledby="main-nav-aria-label" + class="navbar-menu" + > + <span id="main-nav-aria-label" class="visually-hidden" + >Main Navigation</span + > + <template v-for="item in theme.navbar" :key="item.text"> + <NavBarMenuLink v-if="'link' in item" :item="item" /> + <NavBarMenuGroup v-else :item="item" /> + </template> + </nav> +</template> + +<style scoped> +.navbar-menu { + display: none; +} + +@media (min-width: 768px) { + .navbar-menu { + display: flex; + } +} +</style> diff --git a/packages/theme/src/client/components/Nav/NavBarMenuGroup.vue b/packages/theme/src/client/components/Nav/NavBarMenuGroup.vue new file mode 100644 index 00000000..deb023ee --- /dev/null +++ b/packages/theme/src/client/components/Nav/NavBarMenuGroup.vue @@ -0,0 +1,23 @@ +<script lang="ts" setup> +import { usePageData } from '@vuepress/client' +import type { NavItemWithChildren } from '../../../shared/index.js' +import { isActive } from '../../utils/index.js' +import Flyout from '../Flyout/index.vue' + +defineProps<{ + item: NavItemWithChildren +}>() + +const page = usePageData() +</script> + +<template> + <Flyout + :class="{ + 'navbar-menu-group': true, + 'active': isActive(page.path, item.activeMatch, !!item.activeMatch), + }" + :button="item.text" + :items="item.items" + /> +</template> diff --git a/packages/theme/src/client/components/Nav/NavBarMenuLink.vue b/packages/theme/src/client/components/Nav/NavBarMenuLink.vue new file mode 100644 index 00000000..0b5bd0a5 --- /dev/null +++ b/packages/theme/src/client/components/Nav/NavBarMenuLink.vue @@ -0,0 +1,50 @@ +<script lang="ts" setup> +import { usePageData } from '@vuepress/client' +import type { NavItemWithLink } from '../../../shared/index.js' +import { isActive } from '../../utils/index.js' +import AutoLink from '../AutoLink.vue' + +defineProps<{ + item: NavItemWithLink +}>() + +const page = usePageData() +</script> + +<template> + <AutoLink + :class="{ + 'navbar-menu-link': true, + 'active': isActive( + page.path, + item.activeMatch || item.link, + !!item.activeMatch + ), + }" + :href="item.link" + :no-icon="true" + > + {{ item.text }} + </AutoLink> +</template> + +<style scoped> +.navbar-menu-link { + display: flex; + align-items: center; + padding: 0 12px; + line-height: var(--vp-nav-height); + font-size: 14px; + font-weight: 500; + color: var(--vp-c-text-1); + transition: color 0.25s; +} + +.navbar-menu-link.active { + color: var(--vp-c-brand); +} + +.navbar-menu-link:hover { + color: var(--vp-c-brand); +} +</style> diff --git a/packages/theme/src/client/components/Nav/NavBarSearch.vue b/packages/theme/src/client/components/Nav/NavBarSearch.vue new file mode 100644 index 00000000..ee7497a3 --- /dev/null +++ b/packages/theme/src/client/components/Nav/NavBarSearch.vue @@ -0,0 +1,209 @@ +<template> + <div class="navbar-search"> + <DocSearch /> + </div> +</template> + +<style> +.navbar-search { + display: flex; + align-items: center; +} + +@media (min-width: 768px) { + .navbar-search { + flex-grow: 1; + padding-left: 24px; + } +} + +@media (min-width: 960px) { + .navbar-search { + padding-left: 32px; + } +} + +.DocSearch { + --docsearch-primary-color: var(--vp-c-brand); + --docsearch-highlight-color: var(--docsearch-primary-color); + --docsearch-text-color: var(--vp-c-text-1); + --docsearch-muted-color: var(--vp-c-text-2); + --docsearch-searchbox-shadow: none; + --docsearch-searchbox-focus-background: transparent; + --docsearch-key-gradient: transparent; + --docsearch-key-shadow: none; + --docsearch-modal-background: var(--vp-c-bg-soft); + --docsearch-footer-background: var(--vp-c-bg); +} + +.dark .DocSearch { + --docsearch-modal-shadow: none; + --docsearch-footer-shadow: none; + --docsearch-logo-color: var(--vp-c-text-2); + --docsearch-hit-background: var(--vp-c-bg-soft-mute); + --docsearch-hit-color: var(--vp-c-text-2); + --docsearch-hit-shadow: none; +} + +.DocSearch-Button { + display: flex; + justify-content: center; + align-items: center; + margin: 0; + padding: 0; + width: 32px; + height: 55px; + background: transparent; + transition: border-color 0.25s; +} + +.DocSearch-Button:hover { + background: transparent; +} + +.DocSearch-Button:focus { + outline: 1px dotted; + outline: 5px auto -webkit-focus-ring-color; +} + +.DocSearch-Button:focus:not(:focus-visible) { + outline: none !important; +} + +@media (min-width: 768px) { + .DocSearch-Button { + justify-content: flex-start; + border: 1px solid transparent; + border-radius: 8px; + padding: 0 10px 0 12px; + width: 100%; + height: 40px; + background-color: var(--vp-c-bg-alt); + } + + .DocSearch-Button:hover { + border-color: var(--vp-c-brand); + background: var(--vp-c-bg-alt); + } +} + +.DocSearch-Button .DocSearch-Button-Container { + display: flex; + align-items: center; +} + +.DocSearch-Button .DocSearch-Search-Icon { + position: relative; + width: 16px; + height: 16px; + color: var(--vp-c-text-1); + fill: currentColor; + transition: color 0.5s; +} + +.DocSearch-Button:hover .DocSearch-Search-Icon { + color: var(--vp-c-text-1); +} + +@media (min-width: 768px) { + .DocSearch-Button .DocSearch-Search-Icon { + top: 1px; + margin-right: 8px; + width: 14px; + height: 14px; + color: var(--vp-c-text-2); + } +} + +.DocSearch-Button .DocSearch-Button-Placeholder { + display: none; + margin-top: 2px; + padding: 0 16px 0 0; + font-size: 13px; + font-weight: 500; + color: var(--vp-c-text-2); + transition: color 0.5s; +} + +.DocSearch-Button:hover .DocSearch-Button-Placeholder { + color: var(--vp-c-text-1); +} + +@media (min-width: 768px) { + .DocSearch-Button .DocSearch-Button-Placeholder { + display: inline-block; + } +} + +.DocSearch-Button .DocSearch-Button-Keys { + /*rtl:ignore*/ + direction: ltr; + display: none; + min-width: auto; +} + +@media (min-width: 768px) { + .DocSearch-Button .DocSearch-Button-Keys { + display: flex; + align-items: center; + } +} + +.DocSearch-Button .DocSearch-Button-Key { + display: block; + margin: 2px 0 0 0; + border: 1px solid var(--vp-c-divider); + /*rtl:begin:ignore*/ + border-right: none; + border-radius: 4px 0 0 4px; + padding-left: 6px; + /*rtl:end:ignore*/ + min-width: 0; + width: auto; + height: 22px; + line-height: 22px; + font-family: var(--vp-font-family-base); + font-size: 12px; + font-weight: 500; + transition: color 0.5s, border-color 0.5s; +} + +.DocSearch-Button .DocSearch-Button-Key + .DocSearch-Button-Key { + /*rtl:begin:ignore*/ + border-right: 1px solid var(--vp-c-divider); + border-left: none; + border-radius: 0 4px 4px 0; + padding-left: 2px; + padding-right: 6px; + /*rtl:end:ignore*/ +} + +.DocSearch-Button .DocSearch-Button-Key:first-child { + font-size: 1px; + letter-spacing: -12px; + color: transparent; +} + +.DocSearch-Button .DocSearch-Button-Key:first-child:after { + font-size: 12px; + letter-spacing: normal; + color: var(--docsearch-muted-color); +} + +.DocSearch-Button .DocSearch-Button-Key:first-child > * { + display: none; +} + +.dark .DocSearch-Footer { + border-top: 1px solid var(--vp-c-divider); +} + +.DocSearch-Form { + border: 1px solid var(--vp-c-brand); + background-color: var(--vp-c-white); +} + +.dark .DocSearch-Form { + background-color: var(--vp-c-bg-soft-mute); +} +</style> diff --git a/packages/theme/src/client/components/Nav/NavBarSocialLinks.vue b/packages/theme/src/client/components/Nav/NavBarSocialLinks.vue new file mode 100644 index 00000000..9f1f494c --- /dev/null +++ b/packages/theme/src/client/components/Nav/NavBarSocialLinks.vue @@ -0,0 +1,27 @@ +<script lang="ts" setup> +import { useThemeLocaleData } from '../../composables/index.js' +import SocialLinks from '../SocialLinks.vue' + +const theme = useThemeLocaleData() +</script> + +<template> + <SocialLinks + v-if="theme.social" + class="navbar-social-links" + :links="theme.social" + /> +</template> + +<style scoped> +.navbar-social-links { + display: none; +} + +@media (min-width: 1280px) { + .navbar-social-links { + display: flex; + align-items: center; + } +} +</style> diff --git a/packages/theme/src/client/components/Nav/NavBarTitle.vue b/packages/theme/src/client/components/Nav/NavBarTitle.vue new file mode 100644 index 00000000..b1025613 --- /dev/null +++ b/packages/theme/src/client/components/Nav/NavBarTitle.vue @@ -0,0 +1,57 @@ +<script lang="ts" setup> +import { useSiteLocaleData, withBase } from '@vuepress/client' +import { useSidebar } from '../../composables/index.js' +import { useThemeLocaleData } from '../../composables/themeData.js' +import AutoLink from '../AutoLink.vue' +import VImage from '../VImage.vue' + +const theme = useThemeLocaleData() +const site = useSiteLocaleData() +const { hasSidebar } = useSidebar() +</script> + +<template> + <div class="navbar-title" :class="{ 'has-sidebar': hasSidebar }"> + <AutoLink class="title" :href="theme.home || withBase('/')"> + <VImage + v-if="theme.logo" + class="logo" + :image="{ light: theme.logo, dark: theme.logoDark || '' }" + /> + {{ site.title }} + </AutoLink> + </div> +</template> + +<style scoped> +.title { + display: flex; + align-items: center; + border-bottom: 1px solid transparent; + width: 100%; + height: var(--vp-nav-height); + font-size: 16px; + font-weight: 600; + color: var(--vp-c-text-1); + transition: opacity 0.25s; +} + +.title:hover { + opacity: 0.6; +} + +@media (min-width: 960px) { + .title { + flex-shrink: 0; + } + + .navbar-title.has-sidebar .title { + border-bottom-color: var(--vp-c-divider); + } +} + +:deep(.logo) { + margin-right: 8px; + height: 24px; +} +</style> diff --git a/packages/theme/src/client/components/Nav/NavScreen.vue b/packages/theme/src/client/components/Nav/NavScreen.vue new file mode 100644 index 00000000..e4cb866c --- /dev/null +++ b/packages/theme/src/client/components/Nav/NavScreen.vue @@ -0,0 +1,101 @@ +<script setup lang="ts"> +import { clearAllBodyScrollLocks, disableBodyScroll } from 'body-scroll-lock' +import { ref } from 'vue' +import NavScreenAppearance from './NavScreenAppearance.vue' +import NavScreenMenu from './NavScreenMenu.vue' +import NavScreenSocialLinks from './NavScreenSocialLinks.vue' + +defineProps<{ + open: boolean +}>() + +const screen = ref<HTMLElement | null>(null) + +function lockBodyScroll() { + disableBodyScroll(screen.value!, { reserveScrollBarGap: true }) +} + +function unlockBodyScroll() { + clearAllBodyScrollLocks() +} +</script> + +<template> + <Transition + name="fade" + @enter="lockBodyScroll" + @after-leave="unlockBodyScroll" + > + <div v-if="open" ref="screen" class="nav-screen"> + <div class="container"> + <NavScreenMenu class="menu" /> + <NavScreenAppearance class="appearance" /> + <NavScreenSocialLinks class="social-links" /> + </div> + </div> + </Transition> +</template> + +<style scoped> +.nav-screen { + position: fixed; + top: calc(var(--vp-nav-height) + var(--vp-layout-top-height, 0px) + 1px); + /*rtl:ignore*/ + right: 0; + bottom: 0; + /*rtl:ignore*/ + left: 0; + padding: 0 32px; + width: 100%; + background-color: var(--vp-nav-screen-bg-color); + overflow-y: auto; + transition: background-color 0.5s; + pointer-events: auto; +} + +.nav-screen.fade-enter-active, +.nav-screen.fade-leave-active { + transition: opacity 0.25s; +} + +.nav-screen.fade-enter-active .container, +.nav-screen.fade-leave-active .container { + transition: transform 0.25s ease; +} + +.nav-screen.fade-enter-from, +.nav-screen.fade-leave-to { + opacity: 0; +} + +.nav-screen.fade-enter-from .container, +.nav-screen.fade-leave-to .container { + transform: translateY(-8px); +} + +@media (min-width: 768px) { + .nav-screen { + display: none; + } +} + +.container { + margin: 0 auto; + padding: 24px 0 96px; + max-width: 288px; +} + +.menu + .translations, +.menu + .appearance, +.translations + .appearance { + margin-top: 24px; +} + +.menu + .social-links { + margin-top: 16px; +} + +.appearance + .social-links { + margin-top: 16px; +} +</style> diff --git a/packages/theme/src/client/components/Nav/NavScreenAppearance.vue b/packages/theme/src/client/components/Nav/NavScreenAppearance.vue new file mode 100644 index 00000000..2707f14a --- /dev/null +++ b/packages/theme/src/client/components/Nav/NavScreenAppearance.vue @@ -0,0 +1,31 @@ +<script lang="ts" setup> +import { useThemeLocaleData } from '../../composables/index.js' +import SwitchAppearance from '../SwitchAppearance.vue' + +const theme = useThemeLocaleData() +</script> + +<template> + <div v-if="theme.appearance" class="nav-screen-appearance"> + <p class="text">Appearance</p> + <SwitchAppearance /> + </div> +</template> + +<style scoped> +.nav-screen-appearance { + display: flex; + justify-content: space-between; + align-items: center; + border-radius: 8px; + padding: 12px 14px 12px 16px; + background-color: var(--vp-c-bg-soft); +} + +.text { + line-height: 24px; + font-size: 12px; + font-weight: 500; + color: var(--vp-c-text-2); +} +</style> diff --git a/packages/theme/src/client/components/Nav/NavScreenMenu.vue b/packages/theme/src/client/components/Nav/NavScreenMenu.vue new file mode 100644 index 00000000..a6a8873b --- /dev/null +++ b/packages/theme/src/client/components/Nav/NavScreenMenu.vue @@ -0,0 +1,20 @@ +<script lang="ts" setup> +import { useThemeLocaleData } from '../../composables/index.js' +import NavScreenMenuGroup from './NavScreenMenuGroup.vue' +import NavScreenMenuLink from './NavScreenMenuLink.vue' + +const theme = useThemeLocaleData() +</script> + +<template> + <nav v-if="theme.navbar" class="nav-screen-menu"> + <template v-for="item in theme.navbar" :key="item.text"> + <NavScreenMenuLink + v-if="'link' in item" + :text="item.text" + :link="item.link" + /> + <NavScreenMenuGroup v-else :text="item.text || ''" :items="item.items" /> + </template> + </nav> +</template> diff --git a/packages/theme/src/client/components/Nav/NavScreenMenuGroup.vue b/packages/theme/src/client/components/Nav/NavScreenMenuGroup.vue new file mode 100644 index 00000000..65bcd0c1 --- /dev/null +++ b/packages/theme/src/client/components/Nav/NavScreenMenuGroup.vue @@ -0,0 +1,112 @@ +<script lang="ts" setup> +import { computed, ref } from 'vue' +import IconPlus from '../icons/IconPlus.vue' +import NavScreenMenuGroupLink from './NavScreenMenuGroupLink.vue' +import NavScreenMenuGroupSection from './NavScreenMenuGroupSection.vue' + +const props = defineProps<{ + text: string + items: any[] +}>() + +const isOpen = ref(false) + +const groupId = computed( + () => `nav-screen-menu-group-${props.text.replace(' ', '-').toLowerCase()}` +) + +function toggle() { + isOpen.value = !isOpen.value +} +</script> + +<template> + <div class="nav-screen-menu-group" :class="{ open: isOpen }"> + <button + class="button" + :aria-controls="groupId" + :aria-expanded="isOpen" + @click="toggle" + > + <span class="button-text">{{ text }}</span> + <IconPlus class="button-icon" /> + </button> + + <div :id="groupId" class="items"> + <template v-for="item in items" :key="item.text"> + <div v-if="'link' in item" :key="item.text" class="item"> + <NavScreenMenuGroupLink :text="item.text" :link="item.link" /> + </div> + + <div v-else class="group"> + <NavScreenMenuGroupSection :text="item.text" :items="item.items" /> + </div> + </template> + </div> + </div> +</template> + +<style scoped> +.nav-screen-menu-group { + border-bottom: 1px solid var(--vp-c-divider); + height: 48px; + overflow: hidden; + transition: border-color 0.5s; +} + +.nav-screen-menu-group .items { + visibility: hidden; +} + +.nav-screen-menu-group.open .items { + visibility: visible; +} + +.nav-screen-menu-group.open { + padding-bottom: 10px; + height: auto; +} + +.nav-screen-menu-group.open .button { + padding-bottom: 6px; + color: var(--vp-c-brand); +} + +.nav-screen-menu-group.open .button-icon { + /*rtl:ignore*/ + transform: rotate(45deg); +} + +.button { + display: flex; + justify-content: space-between; + align-items: center; + padding: 12px 4px 11px 0; + width: 100%; + line-height: 24px; + font-size: 14px; + font-weight: 500; + color: var(--vp-c-text-1); + transition: color 0.25s; +} + +.button:hover { + color: var(--vp-c-brand); +} + +.button-icon { + width: 14px; + height: 14px; + fill: var(--vp-c-text-2); + transition: fill 0.5s, transform 0.25s; +} + +.group:first-child { + padding-top: 0px; +} + +.group + .group, +.group + .item { + padding-top: 4px; +} +</style> diff --git a/packages/theme/src/client/components/Nav/NavScreenMenuGroupLink.vue b/packages/theme/src/client/components/Nav/NavScreenMenuGroupLink.vue new file mode 100644 index 00000000..a8c277d2 --- /dev/null +++ b/packages/theme/src/client/components/Nav/NavScreenMenuGroupLink.vue @@ -0,0 +1,37 @@ +<script lang="ts" setup> +import { inject } from 'vue' +import AutoLink from '../AutoLink.vue' + +defineProps<{ + text: string + link: string +}>() + +const closeScreen = inject('close-screen') as () => void +</script> + +<template> + <AutoLink + class="nav-screen-menu-group-link" + :href="link" + @click="closeScreen" + > + {{ text }} + </AutoLink> +</template> + +<style scoped> +.nav-screen-menu-group-link { + display: block; + margin-left: 12px; + line-height: 32px; + font-size: 14px; + font-weight: 400; + color: var(--vp-c-text-1); + transition: color 0.25s; +} + +.nav-screen-menu-group-link:hover { + color: var(--vp-c-brand); +} +</style> diff --git a/packages/theme/src/client/components/Nav/NavScreenMenuGroupSection.vue b/packages/theme/src/client/components/Nav/NavScreenMenuGroupSection.vue new file mode 100644 index 00000000..1255f75e --- /dev/null +++ b/packages/theme/src/client/components/Nav/NavScreenMenuGroupSection.vue @@ -0,0 +1,35 @@ +<script lang="ts" setup> +import type { NavItemWithLink } from '../../../shared/index.js' +import NavScreenMenuGroupLink from './NavScreenMenuGroupLink.vue' + +defineProps<{ + text?: string + items: NavItemWithLink[] +}>() +</script> + +<template> + <div class="nav-screen-menu-group-section"> + <p v-if="text" class="title">{{ text }}</p> + <NavScreenMenuGroupLink + v-for="item in items" + :key="item.text" + :text="item.text" + :link="item.link" + /> + </div> +</template> + +<style scoped> +.nav-screen-menu-group-section { + display: block; +} + +.title { + line-height: 32px; + font-size: 13px; + font-weight: 700; + color: var(--vp-c-text-2); + transition: color 0.25s; +} +</style> diff --git a/packages/theme/src/client/components/Nav/NavScreenMenuLink.vue b/packages/theme/src/client/components/Nav/NavScreenMenuLink.vue new file mode 100644 index 00000000..96a503d5 --- /dev/null +++ b/packages/theme/src/client/components/Nav/NavScreenMenuLink.vue @@ -0,0 +1,34 @@ +<script lang="ts" setup> +import { inject } from 'vue' +import AutoLink from '../AutoLink.vue' + +defineProps<{ + text: string + link: string +}>() + +const closeScreen = inject('close-screen') as () => void +</script> + +<template> + <AutoLink class="nav-screen-menu-link" :href="link" @click="closeScreen"> + {{ text }} + </AutoLink> +</template> + +<style scoped> +.nav-screen-menu-link { + display: block; + border-bottom: 1px solid var(--vp-c-divider); + padding: 12px 0 11px; + line-height: 24px; + font-size: 14px; + font-weight: 500; + color: var(--vp-c-text-1); + transition: border-color 0.25s, color 0.25s; +} + +.nav-screen-menu-link:hover { + color: var(--vp-c-brand); +} +</style> diff --git a/packages/theme/src/client/components/Nav/NavScreenSocialLinks.vue b/packages/theme/src/client/components/Nav/NavScreenSocialLinks.vue new file mode 100644 index 00000000..10584b92 --- /dev/null +++ b/packages/theme/src/client/components/Nav/NavScreenSocialLinks.vue @@ -0,0 +1,14 @@ +<script lang="ts" setup> +import { useThemeData } from '../../composables/index.js' +import SocialLinks from '../SocialLinks.vue' + +const theme = useThemeData() +</script> + +<template> + <SocialLinks + v-if="theme.social" + class="VPNavScreenSocialLinks" + :links="theme.social" + /> +</template> diff --git a/packages/theme/src/client/components/Nav/index.vue b/packages/theme/src/client/components/Nav/index.vue new file mode 100644 index 00000000..c3f6561b --- /dev/null +++ b/packages/theme/src/client/components/Nav/index.vue @@ -0,0 +1,52 @@ +<script lang="ts" setup> +import { usePageData } from '@vuepress/client' +import { computed, provide } from 'vue' +import type { PlumeThemePageData } from '../../../shared/index.js' +import { useNav } from '../../composables/nav.js' +import Navbar from './NavBar.vue' +import NavScreen from './NavScreen.vue' + +const page = usePageData<PlumeThemePageData>() + +const { isScreenOpen, closeScreen, toggleScreen } = useNav() + +const fixed = computed(() => { + return page.value.isBlogPost || page.value.type === 'blog' +}) + +provide('close-screen', closeScreen) +</script> +<template> + <div class="nav-wrapper" :class="{ fixed }"> + <Navbar :is-screen-open="isScreenOpen" @toggle-screen="toggleScreen" /> + <NavScreen :open="isScreenOpen" /> + </div> +</template> + +<style scoped> +.nav-wrapper { + position: relative; + top: var(--vp-layout-top-height, 0px); + /*rtl:ignore*/ + left: 0; + z-index: var(--vp-z-index-nav); + width: 100%; + pointer-events: none; + transition: background-color 0.5s; +} + +.nav-wrapper.fixed { + position: fixed; +} + +.nav-wrapper.fixed :deep(.navbar-wrapper) { + border-bottom-color: var(--vp-c-gutter); + background-color: var(--vp-nav-bg-color); +} + +@media (min-width: 960px) { + .nav-wrapper { + position: fixed; + } +} +</style> diff --git a/packages/theme/src/client/components/Navbar.vue b/packages/theme/src/client/components/Navbar.vue deleted file mode 100644 index d8f3da8f..00000000 --- a/packages/theme/src/client/components/Navbar.vue +++ /dev/null @@ -1,160 +0,0 @@ -<script lang="ts" setup> -import DarkModeButton from '@theme-plume/DarkModeButton.vue' -import NavbarBrand from '@theme-plume/NavbarBrand.vue' -import NavbarItems from '@theme-plume/NavbarItems.vue' -import ToggleSidebarButton from '@theme-plume/ToggleSidebarButton.vue' -import { computed, onMounted, ref } from 'vue' -import { useAsideNavbar, useThemeLocaleData } from '../composables/index.js' -import { getCssValue } from '../utils/index.js' - -const themeLocale = useThemeLocaleData() - -const { triggerAsideNavbar } = useAsideNavbar() - -const navbar = ref<HTMLElement | null>(null) -const navbarBrand = ref<HTMLElement | null>(null) - -const linksWrapperMaxWith = ref(0) -const linksWrapperStyle = computed(() => { - if (!linksWrapperMaxWith.value) { - return {} - } - return { - maxWidth: linksWrapperMaxWith.value + 'px', - } -}) -const enableDarkMode = computed(() => themeLocale.value.darkMode) - -onMounted(() => { - const MOBILE_DESKTOP_BREAKPOINT = 719 - const navbarHorizontalPadding = - getCssValue(navbar.value, 'paddingLeft') + - getCssValue(navbar.value, 'paddingRight') - const handleLinkWrapWidth = (): void => { - if (window.innerWidth <= MOBILE_DESKTOP_BREAKPOINT) { - linksWrapperMaxWith.value = 0 - } else { - linksWrapperMaxWith.value = - navbar.value!.offsetWidth - - navbarHorizontalPadding - - (navbarBrand.value?.offsetWidth || 0) - } - } - handleLinkWrapWidth() - window.addEventListener('resize', handleLinkWrapWidth, false) - window.addEventListener('orientationchange', handleLinkWrapWidth, false) -}) -</script> -<template> - <header ref="navbar" class="navbar-wrapper"> - <ToggleSidebarButton @toggle="triggerAsideNavbar(true)" /> - <span ref="navbarBrand" class="navbar-brand-wrapper"> - <NavbarBrand /> - </span> - <div class="navbar-items-wrapper" :style="linksWrapperStyle"> - <slot name="before" /> - <div class="navbar-item-search"> - <NavbarSearch /> - </div> - <NavbarItems class="can-hide" is-header /> - <slot name="after" /> - <DarkModeButton v-if="enableDarkMode" /> - </div> - </header> -</template> -<style lang="scss"> -@import '../styles/variables'; -.navbar-wrapper { - --navbar-line-height: calc( - var(--navbar-height) - 2 * var(--navbar-padding-v) - ); - position: fixed; - top: 0; - left: 0; - right: 0; - z-index: 10; - display: flex; - justify-content: space-between; - align-items: center; - width: 100%; - height: var(--navbar-height); - padding: 0 0 0 var(--navbar-padding-h); - background-color: var(--c-bg-navbar); - backdrop-filter: saturate(50%) blur(8px); - // box-shadow: var(--shadow); - line-height: var(--navbar-line-height); - transition: background-color 0.3s ease; - - .navbar-brand-wrapper { - display: inline-block; - height: 100%; - } - .logo { - height: var(--navbar-line-height); - margin-right: var(--navbar-padding-v); - vertical-align: top; - } - - .site-name { - font-size: 1.3rem; - font-weight: 600; - color: var(--c-text); - position: relative; - transition: color 0.3s ease; - } - - .navbar-items-wrapper { - display: flex; - align-items: center; - flex-grow: 1; - white-space: nowrap; - font-size: 0.9rem; - height: 100%; - padding-right: var(--navbar-padding-h); - - .navbar-item-search { - flex-grow: 1; - padding-left: 1.5rem; - } - - .search-box { - flex: 0 0 auto; - vertical-align: top; - } - - .navbar-items .navbar-item { - & > .router-link-active { - color: var(--c-text-accent); - } - } - } -} - -.DocSearch { - transition: background-color var(--t-color); -} - -@media (max-width: $MQMobile) { - .navbar-wrapper { - padding-left: 4rem; - - .can-hide { - display: none; - } - - .site-name { - width: calc(100vw - 9.4rem); - overflow: hidden; - white-space: nowrap; - text-overflow: ellipsis; - } - - .navbar-items-wrapper { - justify-content: flex-end; - .navbar-item-search { - flex-grow: 0; - } - } - } -} -</style> diff --git a/packages/theme/src/client/components/NavbarBrand.vue b/packages/theme/src/client/components/NavbarBrand.vue deleted file mode 100644 index cb3901c7..00000000 --- a/packages/theme/src/client/components/NavbarBrand.vue +++ /dev/null @@ -1,84 +0,0 @@ -<script lang="ts" setup> -import { - ClientOnly, - useRouteLocale, - useSiteLocaleData, - withBase, -} from '@vuepress/client' -import { computed, h } from 'vue' -import type { FunctionalComponent } from 'vue' -import type { NavLink } from '../../shared/index.js' -import { - useDarkMode, - useSidebarIndex, - useThemeLocaleData, -} from '../composables/index.js' - -const routeLocale = useRouteLocale() -const siteLocale = useSiteLocaleData() -const themeLocale = useThemeLocaleData() -const isDarkMode = useDarkMode() -const { hasSidebar } = useSidebarIndex() - -const navbarBrandLink = computed( - () => (themeLocale.value.home as NavLink)?.link || routeLocale.value -) -const navbarBrandTitle = computed(() => siteLocale.value.title) -const navbarBrandLogo = computed(() => { - if (isDarkMode.value && themeLocale.value.logoDark !== undefined) { - return themeLocale.value.logoDark - } - return themeLocale.value.logo -}) -const NavbarBrandLogo: FunctionalComponent = () => { - if (!navbarBrandLogo.value) return null - const img = h('img', { - class: 'logo', - src: withBase(navbarBrandLogo.value), - alt: navbarBrandTitle.value, - }) - if (themeLocale.value.logoDark === undefined) { - return img - } - return h(ClientOnly, img) -} -</script> - -<template> - <RouterLink - :to="navbarBrandLink" - :class="{ - 'navbar-brand': true, - 'has-sidebar': hasSidebar, - }" - > - <NavbarBrandLogo /> - <span - v-if="navbarBrandTitle" - class="site-name" - :class="{ 'can-hide': navbarBrandLogo }" - > - {{ navbarBrandTitle }} - </span> - </RouterLink> -</template> -<style lang="scss"> -@import '../styles/variables'; -.navbar-brand { - display: flex; - height: 100%; - align-items: center; - - &.has-sidebar { - width: calc(18rem - var(--navbar-padding-h)); - border-bottom: solid 1px var(--c-border); - } -} - -@media (max-width: $MQMobile) { - .navbar-brand.has-sidebar { - width: auto; - border-bottom: none; - } -} -</style> diff --git a/packages/theme/src/client/components/NavbarDropdown.vue b/packages/theme/src/client/components/NavbarDropdown.vue deleted file mode 100644 index be1e4dfe..00000000 --- a/packages/theme/src/client/components/NavbarDropdown.vue +++ /dev/null @@ -1,334 +0,0 @@ -<script lang="ts" setup> -import AutoLink from '@theme-plume/AutoLink.vue' -import DropdownTransition from '@theme-plume/DropdownTransition.vue' -import type { PropType } from 'vue' -import { computed, ref, toRefs, watch } from 'vue' -import { useRoute } from 'vue-router' -// eslint-disable-next-line @typescript-eslint/consistent-type-imports -import type { - NavbarItem, - NavGroup, - ResolveNavbarItem, -} from '../../shared/index.js' - -const props = defineProps({ - item: { - type: Object as PropType<Exclude<ResolveNavbarItem, NavbarItem>>, - required: true, - }, - isHeader: { - type: Boolean, - required: true, - }, -}) -const { item } = toRefs(props) - -const dropdownAriaLabel = computed( - () => item.value.ariaLabel || item.value.text -) -const open = ref(false) -const route = useRoute() - -watch( - () => route.path, - () => { - open.value = false - } -) - -const handleDropdown = (e: MouseEvent): void => { - const isTriggerByTab = e.detail === 0 - if (isTriggerByTab || props.isHeader) { - open.value = !open.value - } else { - open.value = false - } -} -const isLastItemOfArray = (item: unknown, arr: unknown[]): boolean => - arr[arr.length - 1] === item - -const onSubTitleFocusout = (child: any): void => { - if ( - isLastItemOfArray(child, item.value.children) && - child.children && - child.children.length === 0 - ) { - open.value = false - } -} - -const onGrandChildFocusout = (grandchild: unknown, child: any): void => { - if ( - isLastItemOfArray(grandchild, child.children) && - isLastItemOfArray(child, item.value.children) - ) { - open.value = false - } -} -</script> - -<template> - <div - class="navbar-dropdown-wrapper" - :class="{ open }" - @mouseleave="open = false" - > - <button - v-if="isHeader" - class="navbar-dropdown-title" - type="button" - :aria-label="dropdownAriaLabel" - @click="handleDropdown" - @mouseenter="open = true" - > - <span class="title">{{ item.text }}</span> - <span class="arrow down"></span> - </button> - - <button - v-else - class="navbar-dropdown-title-mobile" - type="button" - :aria-label="dropdownAriaLabel" - @click="open = !open" - > - <span class="title">{{ item.text }}</span> - <span class="arrow" :class="open ? 'down' : 'right'"></span> - </button> - - <DropdownTransition> - <ul v-show="open" class="navbar-dropdown"> - <li - v-for="child in item.children" - :key="child.text" - class="navbar-dropdown-item" - > - <template v-if="(child as NavGroup<NavbarItem>).children"> - <h4 class="navbar-dropdown-subtitle"> - <AutoLink - v-if="(child as NavbarItem).link" - :item="(child as NavbarItem)" - @focusout="onSubTitleFocusout(child)" - /> - <span v-else>{{ child.text }}</span> - </h4> - - <ul class="navbar-dropdown-subitem-wrapper"> - <li - v-for="grandchild in (child as unknown as NavGroup<NavbarItem>).children" - :key="grandchild.link" - class="navbar-dropdown-subitem" - > - <AutoLink - :item="grandchild" - @focusout="onGrandChildFocusout(grandchild, child)" - /> - </li> - </ul> - </template> - - <template v-else> - <AutoLink - :item="(child as NavbarItem)" - @focusout=" - isLastItemOfArray(child, item.children) && (open = false) - " - /> - </template> - </li> - </ul> - </DropdownTransition> - </div> -</template> - -<style lang="scss"> -@import '../styles/_variables'; -@import '../styles/_mixins'; - -.navbar-dropdown-wrapper { - cursor: pointer; - - .navbar-dropdown-title { - display: block; - font-size: 1rem; - font-family: inherit; - cursor: inherit; - padding: inherit; - line-height: 1.4rem; - background: transparent; - border: none; - font-weight: 500; - color: var(--c-text); - - &:hover { - border-color: transparent; - } - - .arrow { - vertical-align: middle; - margin-top: -1px; - margin-left: 0.4rem; - } - } - - .navbar-dropdown-title-mobile { - @extend .navbar-dropdown-title; - display: none; - font-weight: 600; - font-size: inherit; - - &:hover { - color: var(--c-text-accent); - } - } - - .navbar-dropdown { - list-style: none; - .navbar-dropdown-item { - color: inherit; - line-height: 1.7rem; - cursor: default; - - .navbar-dropdown-subtitle { - margin: 0.45rem 0 0; - border-top: 1px solid var(--c-border); - padding: 1rem 0 0.45rem 0; - font-size: 1rem; - color: var(--c-text-light); - - & > span { - padding: 0 1.5rem; - } - - & > a { - font-weight: inherit; - - &.router-link-active { - &::after { - display: none; - } - } - } - } - - .navbar-dropdown-subitem-wrapper { - padding: 0; - list-style: none; - - .navbar-dropdown-subitem { - font-size: 1em; - } - } - - a { - display: block; - line-height: 1.7rem; - position: relative; - border-bottom: none; - font-weight: 400; - margin-bottom: 0; - padding: 0 1.5rem 0 1.25rem; - - &:hover { - color: var(--c-text-accent); - } - - &.router-link-active { - color: var(--c-text-accent); - - &::after { - content: ''; - width: 0; - height: 0; - border-left: 5px solid var(--c-text-accent); - border-top: 3px solid transparent; - border-bottom: 3px solid transparent; - position: absolute; - top: calc(50% - 2px); - left: 9px; - } - } - } - - &:first-child .navbar-dropdown-subtitle { - margin-top: 0; - padding-top: 0; - border-top: 0; - } - } - } -} - -@media (max-width: $MQMobile) { - .navbar-dropdown-wrapper { - &.open .navbar-dropdown-title { - margin-bottom: 0.5rem; - } - - .navbar-dropdown-title { - display: none; - } - - .navbar-dropdown-title-mobile { - display: block; - } - - .navbar-dropdown { - @include dropdown_wrapper; - - .navbar-dropdown-item { - .navbar-dropdown-subtitle { - padding-top: 0; - margin-top: 0; - border-top: 0; - padding-bottom: 0; - } - - .navbar-dropdown-subtitle, - & > a { - font-size: 1rem; - line-height: 2rem; - } - - .navbar-dropdown-subitem { - font-size: 1rem; - padding-left: 1rem; - } - } - } - } -} - -@media (min-width: ($MQMobile + 1)) { - .navbar-dropdown-wrapper { - height: 1.8rem; - - &.open .navbar-dropdown { - opacity: 1; - transform: none; - } - - .navbar-dropdown { - opacity: 0; - transform: translateY(-0.5rem); - transition: opacity 0.3s ease, transform 0.3s ease; - height: auto !important; - max-height: calc(100vh - 2.7rem); - overflow-y: auto; - position: absolute; - top: 100%; - right: 0; - box-sizing: border-box; - background-color: var(--c-bg-container); - padding: 1.5rem 0.75rem; - border: 1px solid var(--c-border); - border-bottom-color: var(--c-border-dark); - text-align: left; - border-radius: 0.25rem; - white-space: nowrap; - margin: 0; - box-shadow: var(--shadow); - } - } -} -</style> diff --git a/packages/theme/src/client/components/NavbarItems.vue b/packages/theme/src/client/components/NavbarItems.vue deleted file mode 100644 index e55e837e..00000000 --- a/packages/theme/src/client/components/NavbarItems.vue +++ /dev/null @@ -1,79 +0,0 @@ -<script lang="ts" setup> -import AutoLink from '@theme-plume/AutoLink.vue' -import NavbarDropdown from '@theme-plume/NavbarDropdown.vue' -import { computed } from 'vue' -// eslint-disable-next-line @typescript-eslint/consistent-type-imports -import type { - NavGroup, - NavLink, - ResolveNavbarItem, -} from '../../shared/index.js' -import { - useNavbarConfig, - useNavbarRepo, - useNavbarSelectLanguage, -} from '../composables/index.js' - -defineProps({ - isHeader: { - type: Boolean, - required: false, - default: false, - }, -}) - -const navbarConfig = useNavbarConfig() -const navbarSelectLanguage = useNavbarSelectLanguage() -const navbarRepo = useNavbarRepo() -const navbarLinks = computed(() => [ - ...navbarConfig.value, - ...navbarSelectLanguage.value, - ...navbarRepo.value, -]) -</script> - -<template> - <nav v-if="navbarLinks.length" class="navbar-items"> - <div v-for="item in navbarLinks" :key="item.text" class="navbar-item"> - <NavbarDropdown - v-if="(item as NavGroup<ResolveNavbarItem>).children" - :item="(item as NavGroup<ResolveNavbarItem>)" - :is-header="isHeader" - /> - <AutoLink v-else :item="(item as NavLink)" /> - </div> - </nav> -</template> - -<style lang="scss"> -.navbar-wrapper { - .navbar-items { - --navbar-line-height: calc( - var(--navbar-height) - 2 * var(--navbar-padding-v) - ); - display: inline-block; - - a { - display: inline-block; - line-height: 1.4rem; - color: inherit; - - &:hover, - &.router-lint-active { - color: var(--c-text-accent); - } - } - - .navbar-item { - position: relative; - display: inline-block; - margin-left: 1.5rem; - line-height: var(--navbar-line-height); - - &:first-child { - margin-left: 0; - } - } - } -} -</style> diff --git a/packages/theme/src/client/components/Page.vue b/packages/theme/src/client/components/Page.vue index b7ed818d..cbf0caa8 100644 --- a/packages/theme/src/client/components/Page.vue +++ b/packages/theme/src/client/components/Page.vue @@ -1,110 +1,180 @@ <script lang="ts" setup> -import DropdownTransition from '@theme-plume/DropdownTransition.vue' -import PostMeta from '@theme-plume/PostMeta.vue' -import Sidebar from '@theme-plume/Sidebar.vue' import { usePageData } from '@vuepress/client' -import { computed } from 'vue' import type { PlumeThemePageData } from '../../shared/index.js' -import { useDarkMode } from '../composables/index.js' -import Toc from './Toc.js' +import { useDarkMode, useSidebar } from '../composables/index.js' +import PageAside from './PageAside.vue' +import PageMeta from './PageMeta.vue' +const { hasSidebar, hasAside } = useSidebar() +const isDark = useDarkMode() const page = usePageData<PlumeThemePageData>() -const isDarkMode = useDarkMode() - -const isNote = computed(() => { - return page.value.isNote || false -}) - -const enabledSidebar = computed(() => { - return isNote.value -}) </script> <template> - <DropdownTransition> - <main class="page-wrapper"> - <slot name="top"></slot> - <div class="page-container" :class="{ 'has-sidebar': enabledSidebar }"> - <main class="plume-theme-content"> - <Sidebar v-if="enabledSidebar" /> - <div class="page-content" :class="{ 'note-content': isNote }"> - <h1>{{ page.title }}</h1> - <PostMeta :post="page" type="post" border /> - <Content class="post-content" /> - <div class="comment-container"> - <Comment :darkmode="isDarkMode" /> - </div> + <div + class="plume-page" + :class="{ + 'has-sidebar': hasSidebar, + 'has-aside': hasAside, + 'is-blog': page.isBlogPost, + }" + > + <div class="container"> + <div v-if="hasAside" class="aside"> + <div class="aside-curtain" /> + <div class="aside-container"> + <div class="aside-content"> + <PageAside /> </div> - <div v-if="page.headers?.length > 0" class="plume-theme-page-toc"> - <Toc /> - </div> - </main> + </div> </div> - <slot name="bottom"></slot> - </main> - </DropdownTransition> + <div class="content"> + <div class="content-container"> + <main class="main"> + <PageMeta /> + <Content class="plume-content" /> + <PageComment :darkmode="isDark" /> + </main> + </div> + </div> + </div> + </div> </template> -<style lang="scss"> -@import '../styles/_mixins'; -@import '../styles/variables'; -.page-wrapper { - @include wrapper; - .page-container { +<style scoped> +.plume-page { + position: relative; + display: flex; +} +.plume-page { + padding: 32px 24px 96px; + width: 100%; +} + +.plume-page.is-blog { + padding-top: calc(var(--vp-nav-height) + 32px); +} + +@media (min-width: 768px) { + .plume-page { + padding: 48px 32px 128px; + } +} + +@media (min-width: 960px) { + .plume-page, + .plume-page.is-blog { + padding: 32px 32px 0; + } + + .plume-page:not(.has-sidebar) .container { display: flex; - // padding-top: 1.25rem; - padding-bottom: 1.25rem; + justify-content: center; + max-width: 992px; + } - .plume-theme-content { - @include container_wrapper; - @include content; - display: flex; - flex: 1; - } - - .page-content { - flex: 1; - width: 100%; - max-width: var(--content-width); - padding: 0 2rem 1rem; - margin: 0 auto; - - &.note-content { - max-width: var(--content-note-width); - } - } - - .post-content { - padding-top: 2rem; - } - - img { - max-width: 100%; - } - - &.has-sidebar { - padding-top: 0; - padding-bottom: 0; - - .plume-theme-content { - max-width: 100%; - } - } + .plume-page:not(.has-sidebar) .content { + max-width: 752px; } } -.comment-container { - margin-top: 8rem; + +@media (min-width: 1280px) { + .plume-page .container { + display: flex; + justify-content: center; + } + + .plume-page .aside { + display: block; + } } -@media (max-width: $MQMobile) { - .page-wrapper .page-container .page-content { - padding: 0 0.75rem 1rem; +@media (min-width: 1440px) { + .plume-page:not(.has-sidebar) .content { + max-width: 784px; + } - h1 { - font-size: 1.5rem; - } + .plume-page:not(.has-sidebar) .container { + max-width: 1204px; } - .plume-theme-page-toc { - display: none; +} + +.container { + margin: 0 auto; + width: 100%; +} + +.aside { + position: relative; + display: none; + order: 2; + flex-grow: 1; + padding-left: 32px; + width: 100%; + max-width: 256px; +} + +.aside-container { + position: sticky; + top: 0; + margin-top: calc( + (var(--vp-nav-height) + var(--vp-layout-top-height, 0px)) * -1 - 32px + ); + padding-top: calc( + var(--vp-nav-height) + var(--vp-layout-top-height, 0px) + 32px + ); + height: 100vh; + overflow-x: hidden; + overflow-y: auto; + scrollbar-width: none; +} + +.aside-container::-webkit-scrollbar { + display: none; +} + +.aside-curtain { + position: fixed; + bottom: 0; + z-index: 10; + width: 224px; + height: 32px; + background: linear-gradient(transparent, var(--vp-c-bg) 70%); +} + +.aside-content { + display: flex; + flex-direction: column; + min-height: calc( + 100vh - (var(--vp-nav-height) + var(--vp-layout-top-height, 0px) + 32px) + ); + padding-bottom: 32px; +} + +.content { + position: relative; + margin: 0 auto; + width: 100%; +} + +@media (min-width: 960px) { + .content { + padding: 0 32px 128px; } } + +@media (min-width: 1280px) { + .content { + order: 1; + margin: 0; + min-width: 640px; + } +} + +.content-container { + margin: 0 auto; +} + +.plume-page.has-aside .content-container { + max-width: 688px; +} </style> diff --git a/packages/theme/src/client/components/PageAside.vue b/packages/theme/src/client/components/PageAside.vue new file mode 100644 index 00000000..8e7d4d0a --- /dev/null +++ b/packages/theme/src/client/components/PageAside.vue @@ -0,0 +1,94 @@ +<script lang="ts" setup> +import { usePageData } from '@vuepress/client' +import { computed, ref } from 'vue' +import { useActiveAnchor } from '../composables/aside.js' +import PageAsideItem from './PageAsideItem.vue' + +const page = usePageData() + +const headers = computed(() => page.value.headers) +const hasOutline = computed(() => headers.value.length > 0) + +const container = ref() +const marker = ref() + +useActiveAnchor(container, marker) + +function handleClick({ target: el }: Event) { + const id = '#' + (el as HTMLAnchorElement).href!.split('#')[1] + const heading = document.querySelector<HTMLAnchorElement>( + decodeURIComponent(id) + ) + heading?.focus() +} +</script> +<template> + <div class="page-aside"> + <div + ref="container" + class="page-aside-outline" + :class="{ 'has-outline': hasOutline }" + > + <div class="content"> + <div ref="marker" class="outline-marker" /> + + <div class="outline-title">On this page</div> + + <nav aria-labelledby="doc-outline-aria-label"> + <span id="doc-outline-aria-label" class="visually-hidden"> + Table of Contents for current page + </span> + <PageAsideItem + :headers="headers" + :root="true" + :on-click="handleClick" + /> + </nav> + </div> + </div> + </div> +</template> + +<style scoped> +.page-aside { + display: flex; + flex-direction: column; + flex-grow: 1; +} + +.page-aside-outline { + display: none; +} + +.page-aside-outline.has-outline { + display: block; +} + +.content { + position: relative; + border-left: 1px solid var(--vp-c-divider); + padding-left: 16px; + font-size: 13px; + font-weight: 500; +} + +.outline-marker { + position: absolute; + top: 32px; + left: -1px; + z-index: 0; + opacity: 0; + width: 1px; + height: 18px; + background-color: var(--vp-c-brand); + transition: top 0.25s cubic-bezier(0, 1, 0.5, 1), background-color 0.5s, + opacity 0.25s; +} + +.outline-title { + letter-spacing: 0.4px; + line-height: 28px; + font-size: 13px; + font-weight: 600; +} +</style> diff --git a/packages/theme/src/client/components/PageAsideItem.vue b/packages/theme/src/client/components/PageAsideItem.vue new file mode 100644 index 00000000..b9257d11 --- /dev/null +++ b/packages/theme/src/client/components/PageAsideItem.vue @@ -0,0 +1,51 @@ +<script setup lang="ts"> +import type { PageHeader } from '@vuepress/client' + +defineProps<{ + headers: PageHeader[] + onClick: (e: MouseEvent) => void + root?: boolean +}>() +</script> + +<template> + <ul :class="root ? 'root' : 'nested'"> + <li v-for="{ children, link, title } in headers" :key="link"> + <a class="outline-link" :href="link" @click="onClick">{{ title }}</a> + <template v-if="children?.length"> + <PageAsideItem :headers="children" :on-click="onClick" /> + </template> + </li> + </ul> +</template> + +<style scoped> +.root { + position: relative; + z-index: 1; +} + +.nested { + padding-left: 13px; +} + +.outline-link { + display: block; + line-height: 28px; + color: var(--vp-c-text-2); + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + transition: color 0.5s; +} + +.outline-link:hover, +.outline-link.active { + color: var(--vp-c-text-1); + transition: color 0.25s; +} + +.outline-link.nested { + padding-left: 13px; +} +</style> diff --git a/packages/theme/src/client/components/PageFooter.vue b/packages/theme/src/client/components/PageFooter.vue deleted file mode 100644 index 840be680..00000000 --- a/packages/theme/src/client/components/PageFooter.vue +++ /dev/null @@ -1,49 +0,0 @@ -<script lang="ts" setup> -import { computed } from 'vue' -import { useThemeLocaleData } from '../composables/index.js' - -const themeLocale = useThemeLocaleData() - -const footer = computed(() => { - return themeLocale.value.footer -}) -</script> -<template> - <footer v-if="footer" class="theme-plume-footer"> - <!-- eslint-disable vue/no-v-html --> - <div - v-if="footer.content" - class="theme-plume-footer-content" - v-html="footer.content" - ></div> - <div - v-if="footer.copyright" - class="theme-plume-footer-copyright" - v-html="footer.copyright" - ></div> - </footer> -</template> -<style lang="scss"> -.theme-plume-footer { - position: absolute; - left: 0; - bottom: 0; - display: flex; - justify-content: flex-start; - align-items: flex-start; - width: 100%; - padding: 1.25rem; - background-color: var(--c-bg-container); - // box-shadow: var(--shadow-footer); - font-size: 0.875rem; - text-align: center; - - .theme-plume-footer-content { - flex: 1; - } - .theme-plume-footer-copyright { - margin: auto; - padding: 0 1.25rem; - } -} -</style> diff --git a/packages/theme/src/client/components/PageMeta.vue b/packages/theme/src/client/components/PageMeta.vue new file mode 100644 index 00000000..8b33f988 --- /dev/null +++ b/packages/theme/src/client/components/PageMeta.vue @@ -0,0 +1,131 @@ +<script lang="ts" setup> +import { usePageData, usePageFrontmatter } from '@vuepress/client' +import { computed } from 'vue' +import type { + PlumeThemePageData, + PlumeThemePostFrontmatter, +} from '../../shared/index.js' +import IconClock from './icons/IconClock.vue' +import IconTag from './icons/IconTag.vue' + +const page = usePageData<PlumeThemePageData>() +const matter = usePageFrontmatter<PlumeThemePostFrontmatter>() + +const createTime = computed(() => { + if (matter.value.createTime) { + return matter.value.createTime.split(' ')[0].replace(/\//g, '-') + } + return '' +}) + +const categoryList = computed(() => { + return page.value.categoryList ?? [] +}) + +const tags = computed(() => { + if (matter.value.tags) { + return matter.value.tags.slice(0, 4) + } + return [] +}) + +const hasMeta = computed(() => tags.value.length || createTime.value) +</script> +<template> + <div + v-if="page.isBlogPost && categoryList.length" + class="page-category-wrapper" + > + <template + v-for="({ type, name }, index) in categoryList" + :key="index + '-' + type" + > + <span class="category">{{ name }}</span> + <span v-if="index !== categoryList.length - 1" class="dot">›</span> + </template> + </div> + <h2 v-if="page.isBlogPost" class="page-title" :class="{ padding: !hasMeta }"> + {{ page.title }} + </h2> + <div v-if="hasMeta" class="page-meta-wrapper"> + <p v-if="tags.length > 0"> + <IconTag class="icon" /> + <span v-for="tag in tags" :key="tag" class="tag"> + {{ tag }} + </span> + </p> + <p v-if="createTime"> + <IconClock class="icon" /><span>{{ createTime }}</span> + </p> + </div> +</template> + +<style scoped> +.page-category-wrapper { + font-size: 16px; + font-weight: 400; + margin-bottom: 2rem; + border-left: solid 4px var(--vp-c-brand); + padding-left: 1rem; +} + +.page-category-wrapper .category { + color: var(--vp-c-text-2); + transition: color var(--t-color); +} + +.page-category-wrapper .category:hover { + color: var(--vp-c-brand); +} + +.page-category-wrapper .dot { + margin: 0 0.2rem; + color: var(--vp-c-text-3); +} + +.page-title { + font-size: 28px; + font-weight: 600; + margin-bottom: 1rem; +} + +.page-title.padding { + padding-bottom: 4rem; +} +.page-meta-wrapper { + display: flex; + align-items: center; + justify-content: space-between; + padding: 1rem 0 0.5rem; + margin-bottom: 2rem; + color: var(--vp-c-text-3); + font-size: 14px; + border-bottom: solid 1px var(--vp-c-divider); +} + +.page-meta-wrapper p { + display: flex; + align-items: center; + margin-right: 1rem; +} + +.page-meta-wrapper .icon { + width: 14px; + height: 14px; + margin-right: 0.3rem; +} + +.page-meta-wrapper .tag { + display: inline-block; + line-height: 1; + margin-right: 0.3rem; + padding: 3px 6px; + color: var(--vp-c-text-2); + background-color: var(--vp-c-mute); + border-radius: 4px; +} + +.page-meta-wrapper .tag:last-of-type { + margin-right: 0; +} +</style> diff --git a/packages/theme/src/client/components/Pagination.vue b/packages/theme/src/client/components/Pagination.vue deleted file mode 100644 index 1504f353..00000000 --- a/packages/theme/src/client/components/Pagination.vue +++ /dev/null @@ -1,203 +0,0 @@ -<script lang="ts" setup> -import { useOffsetPagination } from '@vueuse/core' -import { computed, ref, toRefs } from 'vue' -import { ArrowDoubleLeftIcon, ArrowDoubleRightIcon } from './icons/index.js' - -const emit = defineEmits(['togglePage']) -const props = defineProps({ - page: { - type: Number, - required: true, - }, - total: { - type: Number, - required: true, - }, -}) -const { page, total } = toRefs(props) - -function handlePage({ currentPage }: { currentPage: number }): void { - emit('togglePage', currentPage) -} -const { currentPage, pageCount, isFirstPage, isLastPage, prev, next } = - useOffsetPagination({ - total: total.value, - page: page.value, - pageSize: 10, - onPageChange: handlePage, - onPageCountChange: handlePage, - }) - -const pageList = computed(() => { - const list: (number | '')[] = [] - const count = pageCount.value - const current = currentPage.value - if (count <= 3 || current <= 2) { - new Array(Math.min(3, count)).fill(0).forEach((_, i) => list.push(i + 1)) - if (count > 3) { - list.push('') - list.push(count) - } - } else if (current > count - 2) { - list.push(1) - list.push('') - new Array(3).fill(count - 2).forEach((_, i) => list.push(_ + i)) - } else { - list.push(1) - current > 3 && list.push('') - ;[current - 1, current, current + 1].forEach((page: number) => - list.push(page) - ) - current < count - 2 && list.push('') - list.push(count) - } - return list -}) - -const inputPage = ref(1) -function handleJump(): void { - if ( - inputPage.value && - inputPage.value >= 1 && - inputPage.value <= pageCount.value && - currentPage.value !== Number(inputPage.value) - ) { - currentPage.value = Number(inputPage.value) - emit('togglePage', inputPage.value) - } -} -</script> -<template> - <div v-if="pageCount > 1" class="pagination-wrapper"> - <div class="pagination-container"> - <button - type="button" - class="btn-prev" - :disabled="isFirstPage" - @click="prev" - > - <ArrowDoubleLeftIcon /> - </button> - <template v-for="count in pageList" :key="count"> - <button - v-if="count" - type="button" - :disabled="count === currentPage" - @click="currentPage = count" - > - {{ count }} - </button> - <button v-else type="button" disabled>..</button> - </template> - <button - type="button" - class="btn-next" - :disabled="isLastPage" - @click="next" - > - <ArrowDoubleRightIcon /> - </button> - </div> - <div class="pagination-form can-hide"> - <span>跳转到:</span> - <input v-model="inputPage" type="number" :min="1" :max="pageCount" /> - <span>/{{ pageCount }}</span> - <button type="button" class="btn-jump" @click="handleJump">确认</button> - </div> - </div> -</template> -<style lang="scss"> -@import '../styles/variables'; -.pagination-wrapper { - display: flex; - justify-content: flex-start; - align-items: center; - text-align: center; - font-size: 0.875rem; - - .pagination-container { - flex: 1; - - button { - // border-right: solid 1px var(--c-border); - - &:last-of-type { - border-right: none; - } - } - } - - button { - background-color: var(--c-bg-container); - cursor: pointer; - font-size: inherit; - padding: 0 0.8rem; - height: 2.125rem; - line-height: 2.125rem; - border: solid 1px transparent; - color: var(--c-text); - // box-shadow: var(--shadow-sm); - - &:disabled { - color: var(--c-text-accent); - cursor: unset; - } - - &.btn-prev, - &.btn-next, - &.btn-jump { - color: var(--c-text-accent); - - &:disabled { - color: var(--c-text); - } - } - - &.btn-prev, - &.btn-next { - .icon { - width: 0.875rem; - height: 0.875rem; - vertical-align: text-top; - } - } - } - - .pagination-form { - input { - font-size: inherit; - padding: 0.5rem; - width: 3.25rem; - height: 2.125rem; - line-height: 2.125rem; - border: solid 1px transparent; - color: var(--c-text); - // box-shadow: var(--shadow-sm); - outline: 0; - background-color: var(--c-bg-light); - margin-right: 0.5rem; - - &:focus { - border-color: var(--c-brand); - } - } - - span { - margin-right: 0.5rem; - } - } -} - -@media (max-width: $MQMobile) { - .pagination-wrapper { - .can-hide { - display: none; - } - // .pagination-container { - // display: flex; - // justify-content: space-between; - // padding: 0 2rem; - // } - } -} -</style> diff --git a/packages/theme/src/client/components/PostItem.vue b/packages/theme/src/client/components/PostItem.vue index a37781d2..8f133efd 100644 --- a/packages/theme/src/client/components/PostItem.vue +++ b/packages/theme/src/client/components/PostItem.vue @@ -1,59 +1,126 @@ <script lang="ts" setup> -import DropdownTransition from '@theme-plume/DropdownTransition.vue' -import type { PropType } from 'vue' -import { useRouter } from 'vue-router' -import type { PostItem } from '../../shared/index.js' +import { computed } from 'vue' +import type { PlumeThemeBlogPostItem } from '../../shared/index.js' import AutoLink from './AutoLink.vue' -import { TopIcon } from './icons/index.js' -import PostMeta from './PostMeta.vue' +import IconClock from './icons/IconClock.vue' +import IconFolder from './icons/IconFolder.vue' +import IconTag from './icons/IconTag.vue' -defineProps({ - post: { - type: Object as PropType<PostItem>, - required: true, - }, - index: { - type: Number, - default: 0, - }, +const props = defineProps<{ + post: PlumeThemeBlogPostItem +}>() + +const categoryList = computed(() => { + return props.post.categoryList ?? [] }) -const router = useRouter() +const tags = computed(() => { + return (props.post.tags ?? []).slice(0, 4) +}) -const handlePost = (path: string): void => { - router.push({ path }) -} +const createTime = computed(() => { + return props.post.createTime?.split(' ')[0].replace(/\//g, '-') +}) </script> <template> - <DropdownTransition :delay="index * 0.04"> - <section :key="post.path" class="post-list-item"> - <div :class="{ sticky: post.sticky }"> - <TopIcon v-if="post.sticky" /> - <!-- <div - v-if="post.banner" - class="post-banner" - @click="handlePost(post.path)" - > - <div - :style="{ - 'background-image': `url(${post.banner})`, - }" - ></div> - </div> --> - <h3> - <AutoLink :item="{ text: post.title, link: post.path }" /> - </h3> - <PostMeta :post="post" :show-author="false" /> - <!--eslint-disable vue/no-v-html--> - <div - v-if="post.excerpt" - class="post-excerpt" - v-html="post.excerpt" - ></div> - <div v-if="post.excerpt" class="post-more"> - <AutoLink :item="{ text: '阅读全文', link: post.path }" /> - </div> + <div class="post-item"> + <h3> + <AutoLink :href="post.path">{{ post.title }}</AutoLink> + <div + v-if="typeof post.sticky === 'boolean' ? post.sticky : post.sticky >= 0" + class="sticky" + > + TOP </div> - </section> - </DropdownTransition> + </h3> + <div class="post-meta"> + <div v-if="categoryList.length" class="category-list"> + <IconFolder class="icon" /> + <template v-for="(cate, i) in categoryList" :key="i"> + <span>{{ cate.name }}</span> + <span v-if="i !== categoryList.length - 1">/</span> + </template> + </div> + <div v-if="tags.length" class="tag-list"> + <IconTag class="icon" /> + <span v-for="tag in tags" :key="tag">{{ tag }}</span> + </div> + <div v-if="createTime" class="create-time"> + <IconClock class="icon" /> + <span>{{ createTime }}</span> + </div> + </div> + <!-- eslint-disable vue/no-v-html --> + <div v-if="post.excerpt" class="plume-content" v-html="post.excerpt"></div> + </div> </template> + +<style lang="scss" scoped> +.post-item { + padding-top: 1rem; + margin: 0 1.75rem 3rem; + // border-bottom: solid 1px var(--vp-c-divider); + + &:last-of-type { + border-bottom: none; + } + + h3 { + display: flex; + align-items: center; + font-size: 18px; + font-weight: 600; + transition: color var(--t-color); + margin-bottom: 1rem; + } + + h3:hover { + color: var(--vp-c-brand); + + .sticky { + color: var(--vp-c-text-2); + } + } + + .sticky { + display: inline-block; + font-weight: 600; + padding: 3px 6px; + margin-left: 0.5rem; + border-radius: 4px; + line-height: 1; + font-size: 13px; + color: var(--vp-c-text-2); + background-color: var(--vp-c-bg-soft-mute); + } +} + +.post-meta { + display: flex; + align-items: center; + justify-content: flex-start; + flex-wrap: wrap; + font-size: 14px; + font-weight: 400; + color: var(--vp-c-text-2); + margin-bottom: 1rem; + + > div { + display: flex; + align-items: center; + justify-content: flex-start; + margin-right: 1rem; + + &:last-of-type { + margin-right: 0; + } + } + + .icon { + width: 14px; + height: 14px; + margin: 0.3rem; + color: var(--vp-c-text-3); + } +} +</style> diff --git a/packages/theme/src/client/components/PostList.vue b/packages/theme/src/client/components/PostList.vue index 3af4988e..82fc6c35 100644 --- a/packages/theme/src/client/components/PostList.vue +++ b/packages/theme/src/client/components/PostList.vue @@ -1,195 +1,38 @@ <script lang="ts" setup> -import DropdownTransition from '@theme-plume/DropdownTransition.vue' -import PostItem from '@theme-plume/PostItem.vue' -import { usePageFrontmatter } from '@vuepress/client' -import type { PropType } from 'vue' -import { nextTick, onMounted, toRefs, watch } from 'vue' -import { onBeforeRouteUpdate, useRoute, useRouter } from 'vue-router' -import type { PlumeThemeHomeFrontmatter } from '../../shared/index.js' -import type { PostListData } from '../composables/index.js' -import { usePostList } from '../composables/index.js' -import { scrollTo } from '../utils/index.js' -import Pagination from './Pagination.vue' +import { useBlogPostData } from '@vuepress-plume/vuepress-plugin-blog-data/client' +import { computed } from 'vue' +import type { Ref } from 'vue' +import type { PlumeThemeBlogPostItem } from '../../shared/index.js' +import PostItem from './PostItem.vue' -const props = defineProps({ - postList: { - type: Array as PropType<PostListData | undefined>, - required: false, - default: () => undefined, - }, +const list = useBlogPostData() as unknown as Ref<PlumeThemeBlogPostItem[]> + +const postList = computed(() => { + const stickyList = list.value.filter((item) => + typeof item.sticky === 'boolean' ? item.sticky : item.sticky >= 0 + ) + const otherList = list.value.filter( + (item) => item.sticky === undefined || item.sticky === false + ) + + return [ + ...stickyList.sort((prev, next) => { + if (next.sticky === true && prev.sticky === true) return 0 + return next.sticky > prev.sticky ? 1 : -1 + }), + ...otherList, + ] }) -const router = useRouter() -const frontmatter = usePageFrontmatter<PlumeThemeHomeFrontmatter>() - -const propsRef = toRefs(props) -const { postList, total, page, setPostListPage, resetPostIndex } = usePostList() - -watch( - [propsRef.postList], - ([newPostList]) => { - newPostList && resetPostIndex(newPostList as unknown as PostListData) - }, - { immediate: true } -) - -const route = useRoute() -let offsetHeight = 0 -onBeforeRouteUpdate((to, from) => { - if (__VUEPRESS_SSR__) return - if (to.fullPath === from.fullPath) return - setPostListPage((to.query.p as unknown as number) || 1) - const { home, banner, mobileBanner } = frontmatter.value - let top = 0 - if (home && (banner || mobileBanner)) { - offsetHeight = - offsetHeight || - document.querySelector<HTMLElement>('.navbar-wrapper')?.offsetHeight || - 0 - top = document.documentElement.clientHeight - offsetHeight - } - setTimeout(() => scrollTo(document, top), 0) -}) - -onMounted(async () => { - if (__VUEPRESS_SSR__) return - await nextTick() - setPostListPage((route.query.p as unknown as number) || 1) -}) -const togglePage = (currentPage: number): void => { - router.push({ - path: route.path, - query: { - ...route.query, - p: currentPage, - }, - }) -} </script> <template> - <div class="post-list-wrapper"> - <DropdownTransition> - <div> - <PostItem - v-for="(post, index) in postList" - :key="post.path" - :post="post" - :index="index" - ></PostItem> - </div> - </DropdownTransition> - <Pagination :page="page" :total="total" @toggle-page="togglePage" /> + <div class="post-list"> + <PostItem v-for="post in postList" :key="post.path" :post="post" /> </div> </template> -<style lang="scss"> -@import '../styles/_variables'; -.post-list-wrapper { - flex: 1; + +<style scoped> +.post-list { padding-top: 2rem; - - .post-list-item { - > div { - position: relative; - padding: 1.25rem 1.5rem; - background-color: var(--c-bg-container); - border-radius: var(--p-around); - margin-bottom: 2.25rem; - // box-shadow: var(--shadow); - transition: box-shadow var(--t-color); - overflow: hidden; - - &.sticky { - background-color: var(--c-bg-sticky); - } - - // &:hover { - // box-shadow: var(--shadow-lg); - // } - } - - .top-icon { - position: absolute; - top: 0; - left: 0; - width: 2.65rem; - height: 2.65rem; - color: var(--c-brand); - } - } - - .post-banner { - position: relative; - height: 18.75rem; - margin: -1.25rem -1.5rem 1.25rem -1.5rem; - overflow: hidden; - cursor: pointer; - - > div { - width: 100%; - height: 100%; - background-position: center; - background-size: cover; - background-repeat: no-repeat; - transform: scale(100%); - transition: transform var(--t-transform); - - &:hover { - transform: scale(120%); - } - } - - &::after { - content: ''; - position: absolute; - bottom: 0; - left: 1.5rem; - width: 0; - height: 0; - border: solid 1.25rem; - border-color: transparent transparent var(--c-bg-container) transparent; - z-index: 1; - } - } - - h3 { - width: 100%; - margin-top: 0; - overflow: hidden; - text-overflow: ellipsis; - - a { - color: var(--c-text); - } - } - - .post-excerpt { - padding-top: 1.25rem; - - :first-child { - margin-top: 0; - } - :last-child { - margin-bottom: 1rem; - } - } - - .post-more { - text-align: right; - - a { - display: inline-block; - padding: 0.5rem 0.75rem; - border-radius: var(--p-around); - background-color: var(--c-bg); - color: var(--c-brand); - } - } -} - -@media (max-width: $MQMobile) { - .post-list-wrapper { - .post-list-item { - border-radius: 0; - } - } + flex: 1; } </style> diff --git a/packages/theme/src/client/components/PostMeta.vue b/packages/theme/src/client/components/PostMeta.vue deleted file mode 100644 index 075ca41c..00000000 --- a/packages/theme/src/client/components/PostMeta.vue +++ /dev/null @@ -1,126 +0,0 @@ -<script lang="ts" setup> -import type { PropType } from 'vue' -import { computed } from 'vue' -import { useRoute, useRouter } from 'vue-router' -import type { PostItem } from '../../shared/index.js' -import { useThemeLocaleData } from '../composables/index.js' -import { getColor, normalizePath } from '../utils/index.js' -import { ClockIcon, FolderIcon, TagIcon, UserIcon } from './icons/index.js' - -const props = defineProps({ - post: { - type: Object as PropType<PostItem>, - required: true, - }, - border: { - type: Boolean, - required: false, - default: false, - }, - showAuthor: { - type: Boolean, - default: true, - }, -}) -const route = useRoute() -const router = useRouter() -const themeLocale = useThemeLocaleData() - -const tags = computed(() => { - return (props.post.tags || []).filter((_, i) => i < 4) -}) - -const category = computed(() => { - return (props.post.category || []).filter((cate) => - Boolean(cate.name?.trim()) - ) -}) - -const handleTag = (tag: string): void => { - const tagConfig = themeLocale.value.tag - if (!tagConfig) return - const link = tagConfig.link.replace(/^\/|\/$/g, '') - router.replace({ - path: `/${link}/`, - query: { tag: normalizePath(tag) }, - }) -} -</script> -<template> - <div class="post-meta" :class="{ border: post.excerpt || border }"> - <div v-if="post.author && showAuthor" class="post-meta-author"> - <UserIcon /> - <span>{{ post.author }}</span> - </div> - <div v-if="category.length > 0" class="post-meta-category"> - <FolderIcon /> - <template v-for="(cate, i) in category" :key="cate.type"> - <span>{{ cate.name }}</span> - <span v-if="i < category.length - 1"> / </span> - </template> - </div> - <div v-if="tags.length > 0"> - <TagIcon /> - <template v-for="tag in tags" :key="tag"> - <span - class="post-meta-tag" - :style="{ 'background-color': getColor() }" - @click="handleTag(tag)" - > - {{ tag }} - </span> - </template> - </div> - <div class="post-meta-create-time"> - <ClockIcon /> - <span>{{ post.createTime }}</span> - </div> - </div> -</template> -<style lang="scss"> -.post-meta { - color: var(--c-text-light); - overflow: hidden; - font-size: 14px; - - &.border { - border-bottom: solid 1px var(--c-border); - } - - & > div { - float: left; - display: flex; - justify-content: flex-start; - align-items: center; - margin-right: 1.25rem; - height: 2rem; - line-height: 1.5rem; - padding-bottom: 0.5rem; - } - - .icon { - width: 0.875rem; - height: 0.875rem; - margin-right: 0.2rem; - color: var(--c-text-lighter); - } - - .post-meta-tag { - display: inline-block; - height: 1.25rem; - line-height: 1.25rem; - padding: 0 0.4rem; - color: #fff; - border-radius: 0.75rem; - margin: 0 0.15rem; - cursor: pointer; - - &:first-child { - margin-left: 0; - } - &:last-child { - margin-right: 0; - } - } -} -</style> diff --git a/packages/theme/src/client/components/Sidebar.vue b/packages/theme/src/client/components/Sidebar.vue index c7c3e40c..a0eef293 100644 --- a/packages/theme/src/client/components/Sidebar.vue +++ b/packages/theme/src/client/components/Sidebar.vue @@ -1,94 +1,148 @@ <script lang="ts" setup> -import SidebarItems from '@theme-plume/SidebarItems.vue' -import type { PropType } from 'vue' -import { onMounted, ref, watchEffect } from 'vue' -import { useRoute } from 'vue-router' -import type { SidebarOptions } from '../../shared/index.js' -import { useAsideNavbar, useSidebarIndex } from '../composables/index.js' +import { clearAllBodyScrollLocks, disableBodyScroll } from 'body-scroll-lock' +import { ref, watchPostEffect } from 'vue' +import { useSidebar } from '../composables/sidebar.js' +import SidebarItem from './SidebarItem.vue' -defineProps({ - aside: { - type: Array as PropType<SidebarOptions>, - required: false, - default: () => [], - }, -}) -const route = useRoute() -const { sidebarList } = useSidebarIndex() -const { triggerAsideNavbar } = useAsideNavbar() -watchEffect(() => { - triggerAsideNavbar(false) -}) +const { sidebarGroups, hasSidebar } = useSidebar() -const el = ref<HTMLElement | null>(null) -onMounted(() => { - const activeEl = el.value?.querySelector<HTMLElement>('.router-link-active') - activeEl && activeEl.scrollIntoView(false) +const props = defineProps<{ + open: boolean +}>() + +// a11y: focus Nav element when menu has opened +const navEl = ref<HTMLElement | null>(null) + +function lockBodyScroll() { + disableBodyScroll(navEl.value!, { reserveScrollBarGap: true }) +} + +function unlockBodyScroll() { + clearAllBodyScrollLocks() +} + +watchPostEffect(async () => { + if (props.open) { + lockBodyScroll() + navEl.value?.focus() + } else { + unlockBodyScroll() + } }) </script> + <template> <aside - :ref="(e) => (el = e as HTMLElement)" - class="plume-theme-sidebar-wrapper" + v-if="hasSidebar" + ref="navEl" + class="sidebar-wrapper" + :class="{ open }" + @click.stop > - <SidebarItems - v-if="aside.length" - class="aside-navbar" - :sidebar-list="aside" - /> - <SidebarItems :sidebar-list="sidebarList" /> + <div class="curtain" /> + + <nav + id="SidebarNav" + class="nav" + aria-labelledby="sidebar-aria-label" + tabindex="-1" + > + <span id="sidebar-aria-label" class="visually-hidden"> + Sidebar Navigation + </span> + + <div v-for="item in sidebarGroups" :key="item.text" class="group"> + <SidebarItem :item="item" :depth="0" /> + </div> + </nav> </aside> </template> -<style lang="scss"> -@import '../styles/variables'; -.plume-theme-sidebar-wrapper { - position: sticky; - top: calc(var(--navbar-height) + 1.25rem); - width: 18rem; - flex-shrink: 0; - height: calc(100vh - var(--navbar-height) - 1.25rem); - border-right: solid 1px var(--c-border); - font-size: 1.125rem; - padding-left: 1.25rem; +<style scoped> +.sidebar-wrapper { + position: fixed; + top: var(--vp-layout-top-height, 0px); + bottom: 0; + left: 0; + z-index: var(--vp-z-index-sidebar); + padding: 32px 32px 96px; + width: calc(100vw - 64px); + max-width: 320px; + background-color: var(--vp-sidebar-bg-color); + opacity: 0; + box-shadow: var(--vp-c-shadow-3); + overflow-x: hidden; overflow-y: auto; - scrollbar-width: thin; - scrollbar-color: var(--c-brand) var(--c-border); - background-color: var(--c-bg-container); - transition: transform var(--t-color), background-color var(--t-color); + transform: translateX(-100%); + transition: opacity 0.5s, transform 0.25s ease; +} - &::-webkit-scrollbar { - width: 7px; - } +.sidebar-wrapper.open { + opacity: 1; + visibility: visible; + transform: translateX(0); + transition: opacity 0.25s, transform 0.5s cubic-bezier(0.19, 1, 0.22, 1); +} - &::-webkit-scrollbar-track { - background-color: var(--c-border); - } +.dark .sidebar-wrapper { + box-shadow: var(--vp-shadow-1); +} - &::-webkit-scrollbar-thumb { - border-radius: 3.5px; - background-color: rgba(34, 34, 34, 0.75); - } - - > .aside-navbar { - position: relative; - padding-bottom: 0.75rem; - margin-bottom: 1.25rem; - - &::after { - content: ''; - position: absolute; - left: -1.25rem; - bottom: -0.25rem; - right: 0; - border-bottom: solid 4px var(--c-border); - } +@media (min-width: 960px) { + .sidebar-wrapper { + z-index: 1; + padding-top: var(--vp-nav-height); + padding-bottom: 128px; + width: var(--vp-sidebar-width); + max-width: 100%; + background-color: var(--vp-sidebar-bg-color); + opacity: 1; + visibility: visible; + box-shadow: none; + transform: translateX(0); } } -@media (max-width: $MQMobile) { - .plume-theme-sidebar-wrapper { - display: none; +@media (min-width: 1440px) { + .sidebar-wrapper { + padding-left: max( + 32px, + calc((100% - (var(--vp-layout-max-width) - 64px)) / 2) + ); + width: calc( + (100% - (var(--vp-layout-max-width) - 64px)) / 2 + var(--vp-sidebar-width) - + 32px + ); + } +} + +@media (min-width: 960px) { + .curtain { + position: sticky; + top: -64px; + left: 0; + z-index: 1; + margin-top: calc(var(--vp-nav-height) * -1); + margin-right: -32px; + margin-left: -32px; + height: var(--vp-nav-height); + background-color: var(--vp-sidebar-bg-color); + } +} + +.nav { + outline: 0; +} + +.group + .group { + border-top: 1px solid var(--vp-c-divider); + padding-top: 10px; +} + +@media (min-width: 960px) { + .group { + padding-top: 10px; + width: calc(var(--vp-sidebar-width) - 64px); } } </style> diff --git a/packages/theme/src/client/components/SidebarItem.vue b/packages/theme/src/client/components/SidebarItem.vue new file mode 100644 index 00000000..75c17662 --- /dev/null +++ b/packages/theme/src/client/components/SidebarItem.vue @@ -0,0 +1,223 @@ +<script setup lang="ts"> +// eslint-disable-next-line @typescript-eslint/consistent-type-imports +import type { NotesSidebarItem } from '@vuepress-plume/vuepress-plugin-notes-data' +import { computed } from 'vue' +import { useSidebarControl } from '../composables/sidebar.js' +import AutoLink from './AutoLink.vue' +import IconChevronRight from './icons/IconChevronRight.vue' + +const props = defineProps<{ + item: NotesSidebarItem + depth: number +}>() + +const { + collapsed, + collapsible, + isLink, + isActiveLink, + hasActiveLink, + hasChildren, + toggle, +} = useSidebarControl(computed(() => props.item)) + +const sectionTag = computed(() => (hasChildren.value ? 'section' : `div`)) + +const linkTag = computed(() => (isLink.value ? 'a' : 'div')) + +const textTag = computed(() => { + return !hasChildren.value + ? 'p' + : props.depth + 2 === 7 + ? 'p' + : `h${props.depth + 2}` +}) + +const itemRole = computed(() => (isLink.value ? undefined : 'button')) + +const classes = computed(() => [ + [`level-${props.depth}`], + { collapsible: collapsible.value }, + { collapsed: collapsed.value }, + { 'is-link': isLink.value }, + { 'is-active': isActiveLink.value }, + { 'has-active': hasActiveLink.value }, +]) + +function onItemClick() { + !props.item.link && toggle() +} + +function onCaretClick() { + props.item.link && toggle() +} +</script> + +<template> + <Component :is="sectionTag" class="sidebar-item" :class="classes"> + <div v-if="item.text" class="item" :role="itemRole" @click="onItemClick"> + <div class="indicator" /> + + <AutoLink :tag="linkTag" class="link" :href="item.link"> + <!-- eslint-disable vue/no-v-text-v-html-on-component --> + <!-- eslint-disable-next-line vue/no-v-html --> + <Component :is="textTag" class="text" v-html="item.text" /> + </AutoLink> + + <div + v-if="item.collapsed != null" + class="caret" + role="button" + @click="onCaretClick" + > + <IconChevronRight class="caret-icon" /> + </div> + </div> + + <div v-if="item.items && item.items.length" class="items"> + <template v-if="depth < 5"> + <SidebarItem + v-for="i in (item.items as NotesSidebarItem[])" + :key="i.text" + :item="i" + :depth="depth + 1" + /> + </template> + </div> + </Component> +</template> + +<style scoped> +.sidebar-item.level-0 { + padding-bottom: 24px; +} + +.sidebar-item.collapsed.level-0 { + padding-bottom: 10px; +} + +.item { + position: relative; + display: flex; + width: 100%; +} + +.sidebar-item.collapsible > .item { + cursor: pointer; +} + +.indicator { + position: absolute; + top: 6px; + bottom: 6px; + left: -17px; + width: 1px; + transition: background-color 0.25s; +} + +.sidebar-item.level-2.is-active > .item > .indicator, +.sidebar-item.level-3.is-active > .item > .indicator, +.sidebar-item.level-4.is-active > .item > .indicator, +.sidebar-item.level-5.is-active > .item > .indicator { + background-color: var(--vp-c-brand); +} + +.link { + display: block; + flex-grow: 1; +} + +.text { + flex-grow: 1; + padding: 4px 0; + line-height: 24px; + font-size: 14px; + transition: color 0.25s; +} + +.sidebar-item.level-0 .text { + font-weight: 700; + color: var(--vp-c-text-1); +} + +.sidebar-item.level-1 .text, +.sidebar-item.level-2 .text, +.sidebar-item.level-3 .text, +.sidebar-item.level-4 .text, +.sidebar-item.level-5 .text { + font-weight: 500; + color: var(--vp-c-text-2); +} + +.sidebar-item.level-0.is-link > .item > .link:hover .text, +.sidebar-item.level-1.is-link > .item > .link:hover .text, +.sidebar-item.level-2.is-link > .item > .link:hover .text, +.sidebar-item.level-3.is-link > .item > .link:hover .text, +.sidebar-item.level-4.is-link > .item > .link:hover .text, +.sidebar-item.level-5.is-link > .item > .link:hover .text { + color: var(--vp-c-brand); +} + +.sidebar-item.level-0.has-active > .item > .link > .text, +.sidebar-item.level-1.has-active > .item > .link > .text, +.sidebar-item.level-2.has-active > .item > .link > .text, +.sidebar-item.level-3.has-active > .item > .link > .text, +.sidebar-item.level-4.has-active > .item > .link > .text, +.sidebar-item.level-5.has-active > .item > .link > .text { + color: var(--vp-c-text-1); +} + +.sidebar-item.level-0.is-active > .item .link > .text, +.sidebar-item.level-1.is-active > .item .link > .text, +.sidebar-item.level-2.is-active > .item .link > .text, +.sidebar-item.level-3.is-active > .item .link > .text, +.sidebar-item.level-4.is-active > .item .link > .text, +.sidebar-item.level-5.is-active > .item .link > .text { + color: var(--vp-c-brand); +} + +.caret { + display: flex; + justify-content: center; + align-items: center; + margin-right: -7px; + width: 32px; + height: 32px; + color: var(--vp-c-text-3); + cursor: pointer; + transition: color 0.25s; +} + +.item:hover .caret { + color: var(--vp-c-text-2); +} + +.item:hover .caret:hover { + color: var(--vp-c-text-1); +} + +.caret-icon { + width: 18px; + height: 18px; + fill: currentColor; + transform: rotate(90deg); + transition: transform 0.25s; +} + +.sidebar-item.collapsed .caret-icon { + transform: rotate(0); +} + +.sidebar-item.level-1 .items, +.sidebar-item.level-2 .items, +.sidebar-item.level-3 .items, +.sidebar-item.level-4 .items, +.sidebar-item.level-5 .items { + border-left: 1px solid var(--vp-c-divider); + padding-left: 16px; +} + +.sidebar-item.collapsed .items { + display: none; +} +</style> diff --git a/packages/theme/src/client/components/SidebarItems.vue b/packages/theme/src/client/components/SidebarItems.vue deleted file mode 100644 index 3310fa92..00000000 --- a/packages/theme/src/client/components/SidebarItems.vue +++ /dev/null @@ -1,157 +0,0 @@ -<script lang="ts" setup> -import AutoLink from '@theme-plume/AutoLink.vue' -import { computed, ref, watchEffect } from 'vue' -import type { PropType } from 'vue' -import type { SidebarItem, SidebarOptions } from '../../shared/index.js' -import { useThemeLocaleData } from '../composables/index.js' -import { hasOwn } from '../utils/index.js' -import { ArrowRightIcon } from './icons/index.js' - -type SidebarListComputed = SidebarItem & { open: boolean } - -const props = defineProps({ - sidebarList: { - type: Array as PropType<SidebarOptions>, - required: true, - }, - deep: { - type: Number, - required: false, - default: 1, - }, -}) -const themeLocale = useThemeLocaleData() - -const collapsible = computed(() => { - if ( - !themeLocale.value.notes || - !hasOwn(themeLocale.value.notes, 'collapsible') - ) { - return true - } else { - return themeLocale.value.notes.collapsible - } -}) - -const sidebarList = ref<SidebarListComputed[]>([]) -watchEffect(() => { - sidebarList.value = props.sidebarList.map((sidebar) => { - return { ...sidebar, open: !!collapsible.value } - }) -}) -const sidebarClick = (sidebar: SidebarListComputed): void => { - if (props.deep === 1) { - sidebar.open = !sidebar.open - } -} -</script> -<template> - <ul class="sidebar-items"> - <li - v-for="sidebar in sidebarList" - :key="sidebar.text" - :class="{ line: deep === 1 }" - > - <p - :class="{ - 'sidebar-items-title': deep === 1, - 'sidebar-items-subtitle': - deep > 1 && sidebar.children && sidebar.children.length, - }" - @click.self="sidebarClick(sidebar)" - > - <ArrowRightIcon - v-if="deep === 1 && sidebar.children && sidebar.children.length" - :class="{ open: sidebar.open }" - @click.self="sidebarClick(sidebar)" - /> - <AutoLink - v-if="sidebar.link" - :item="{ text: sidebar.text, link: sidebar.link }" - /> - <span v-else @click.self="sidebarClick(sidebar)"> - {{ sidebar.text }} - </span> - </p> - <SidebarItems - v-if="sidebar.children && sidebar.children.length" - v-show="sidebar.open" - :sidebar-list="sidebar.children" - :deep="deep + 1" - /> - </li> - </ul> -</template> -<style lang="scss"> -.plume-theme-sidebar-wrapper { - .sidebar-items { - list-style: none; - margin: 0; - padding: 0; - li { - a { - color: var(--c-sidebar-text); - margin: 0.25rem 0; - font-weight: 500; - flex: 1; - - &:hover { - color: var(--c-text-accent); - } - - &.router-link-active { - color: var(--c-text-accent); - } - } - span { - font-weight: 600; - margin: 0.25rem 0; - flex: 1; - } - - p { - margin: 0.25rem 0; - } - - p.sidebar-items-title { - position: relative; - margin: 0; - padding: 0.25rem 0; - line-height: 1.55; - cursor: pointer; - - .arrow-right-icon { - position: absolute; - left: -1.5rem; - top: 8px; - width: 1.25rem; - height: 1.25rem; - transform: rotate(0); - transition: transform var(--t-color); - color: var(--c-text-quote); - - &.open { - transform: rotate(90deg); - } - } - } - - p.sidebar-items-subtitle { - color: var(--c-text); - font-weight: bolder; - } - - &.line { - // border-bottom: solid 1px var(--c-border); - - &:last-child { - border-bottom: none; - } - } - } - .sidebar-items { - font-size: 16px; - } - } -} -</style> diff --git a/packages/theme/src/client/components/SkipLink.vue b/packages/theme/src/client/components/SkipLink.vue new file mode 100644 index 00000000..44aba3cc --- /dev/null +++ b/packages/theme/src/client/components/SkipLink.vue @@ -0,0 +1,75 @@ +<script lang="ts" setup> +import { ref, watch } from 'vue' +import { useRoute } from 'vue-router' + +const route = useRoute() +const backToTop = ref() + +watch( + () => route.path, + () => backToTop.value.focus() +) + +function focusOnTargetAnchor({ target }: Event) { + const el = document.querySelector<HTMLAnchorElement>( + (target as HTMLAnchorElement).hash + ) + + if (el) { + const removeTabIndex = () => { + el.removeAttribute('tabindex') + el.removeEventListener('blur', removeTabIndex) + } + + el.setAttribute('tabindex', '-1') + el.addEventListener('blur', removeTabIndex) + el.focus() + window.scrollTo(0, 0) + } +} +</script> + +<template> + <span ref="backToTop" tabindex="-1" /> + <a + href="#LayoutContent" + class="skip-link visually-hidden" + @click="focusOnTargetAnchor" + > + Skip to content + </a> +</template> + +<style scoped> +.skip-link { + top: 8px; + left: 8px; + padding: 8px 16px; + z-index: 999; + border-radius: 8px; + font-size: 12px; + font-weight: bold; + text-decoration: none; + color: var(--vp-c-brand); + box-shadow: var(--vp-shadow-3); + background-color: var(--vp-c-bg); +} + +.skip-link:focus { + height: auto; + width: auto; + clip: auto; + clip-path: none; +} + +.dark .skip-link { + color: var(--vp-c-green); +} + +@media (min-width: 1280px) { + .skip-link { + top: 14px; + left: 16px; + } +} +</style> diff --git a/packages/theme/src/client/components/SocialLink.vue b/packages/theme/src/client/components/SocialLink.vue new file mode 100644 index 00000000..687ac3fe --- /dev/null +++ b/packages/theme/src/client/components/SocialLink.vue @@ -0,0 +1,50 @@ +<script lang="ts" setup> +import { computed } from 'vue' +import type { SocialLinkIcon } from '../../shared/index.js' +import { icons } from '../utils/index.js' + +const props = defineProps<{ + icon: SocialLinkIcon + link: string +}>() + +const svg = computed(() => { + if (typeof props.icon === 'object') return props.icon.svg + return icons[props.icon] +}) +</script> + +<template> + <!-- eslint-disable vue/no-v-html --> + <a + class="social-link" + :href="link" + target="_blank" + rel="noopener" + v-html="svg" + > + </a> +</template> + +<style scoped> +.social-link { + display: flex; + justify-content: center; + align-items: center; + width: 36px; + height: 36px; + color: var(--vp-c-text-2); + transition: color 0.5s; +} + +.social-link:hover { + color: var(--vp-c-text-1); + transition: color 0.25s; +} + +.social-link > :deep(svg) { + width: 20px; + height: 20px; + fill: currentColor; +} +</style> diff --git a/packages/theme/src/client/components/SocialLinks.vue b/packages/theme/src/client/components/SocialLinks.vue new file mode 100644 index 00000000..dcbee7a0 --- /dev/null +++ b/packages/theme/src/client/components/SocialLinks.vue @@ -0,0 +1,27 @@ +<script lang="ts" setup> +import type { SocialLink as SocialLinkType } from '../../shared/index.js' +import SocialLink from './SocialLink.vue' + +defineProps<{ + links: SocialLinkType[] +}>() +</script> + +<template> + <div class="social-links"> + <SocialLink + v-for="{ link, icon } in links" + :key="link" + :icon="icon" + :link="link" + /> + </div> +</template> + +<style scoped> +.social-links { + display: flex; + flex-wrap: wrap; + justify-content: center; +} +</style> diff --git a/packages/theme/src/client/components/Switch.vue b/packages/theme/src/client/components/Switch.vue new file mode 100644 index 00000000..174313fc --- /dev/null +++ b/packages/theme/src/client/components/Switch.vue @@ -0,0 +1,63 @@ +<template> + <button class="switch-wrapper" type="button" role="switch"> + <span class="check"> + <span v-if="$slots.default" class="icon"> + <slot /> + </span> + </span> + </button> +</template> + +<style scoped> +.switch-wrapper { + position: relative; + border-radius: 11px; + display: block; + width: 40px; + height: 22px; + flex-shrink: 0; + border: 1px solid var(--vp-input-border-color); + background-color: var(--vp-input-switch-bg-color); + transition: border-color 0.25s; +} + +.switch-wrapper:hover { + border-color: var(--vp-input-hover-border-color); +} + +.check { + position: absolute; + top: 1px; + /*rtl:ignore*/ + left: 1px; + width: 18px; + height: 18px; + border-radius: 50%; + background-color: var(--vp-c-neutral-inverse); + box-shadow: var(--vp-shadow-1); + transition: transform 0.25s; +} + +.icon { + position: relative; + display: block; + width: 18px; + height: 18px; + border-radius: 50%; + overflow: hidden; +} + +.icon :deep(svg) { + position: absolute; + top: 3px; + left: 3px; + width: 12px; + height: 12px; + fill: var(--vp-c-text-2); +} + +.dark .icon :deep(svg) { + fill: var(--vp-c-text-1); + transition: opacity 0.25s; +} +</style> diff --git a/packages/theme/src/client/components/SwitchAppearance.vue b/packages/theme/src/client/components/SwitchAppearance.vue new file mode 100644 index 00000000..d496fb24 --- /dev/null +++ b/packages/theme/src/client/components/SwitchAppearance.vue @@ -0,0 +1,118 @@ +<script lang="ts" setup> +import { onMounted, ref, watch } from 'vue' +import { useDarkMode } from '../composables/index.js' +import { useThemeLocaleData } from '../composables/themeData.js' +import { APPEARANCE_KEY } from '../utils/index.js' +import IconMoon from './icons/IconMoon.vue' +import IconSun from './icons/IconSun.vue' +import Switch from './Switch.vue' + +const theme = useThemeLocaleData() +const checked = ref(false) +const isDark = useDarkMode() + +// eslint-disable-next-line @typescript-eslint/no-empty-function +const toggle = typeof localStorage !== 'undefined' ? useAppearance() : () => {} + +onMounted(() => { + checked.value = document.documentElement.classList.contains('dark') +}) + +function useAppearance() { + const query = window.matchMedia('(prefers-color-scheme: dark)') + const classList = document.documentElement.classList + + let userPreference = localStorage.getItem(APPEARANCE_KEY) + + let isDark = + (theme.value.appearance === 'dark' && userPreference == null) || + (userPreference === 'auto' || userPreference == null + ? query.matches + : userPreference === 'dark') + + query.onchange = (e) => { + if (userPreference === 'auto') { + setClass((isDark = e.matches)) + } + } + + function toggle() { + setClass((isDark = !isDark)) + + userPreference = isDark + ? query.matches + ? 'auto' + : 'dark' + : query.matches + ? 'light' + : 'auto' + + localStorage.setItem(APPEARANCE_KEY, userPreference) + } + + function setClass(dark: boolean): void { + const css = document.createElement('style') + css.type = 'text/css' + css.appendChild( + document.createTextNode( + `:not(.VPSwitchAppearance):not(.VPSwitchAppearance *) { + -webkit-transition: none !important; + -moz-transition: none !important; + -o-transition: none !important; + -ms-transition: none !important; + transition: none !important; +}` + ) + ) + document.head.appendChild(css) + + checked.value = dark + classList[dark ? 'add' : 'remove']('dark') + + // eslint-disable-next-line @typescript-eslint/naming-convention + const _ = window.getComputedStyle(css).opacity + document.head.removeChild(css) + } + + return toggle +} + +watch(checked, (newIsDark) => { + isDark.value = newIsDark +}) +</script> + +<template> + <Switch + class="switch-appearance" + aria-label="toggle dark mode" + :aria-checked="checked" + @click="toggle" + > + <IconSun class="sun" /> + <IconMoon class="moon" /> + </Switch> +</template> + +<style scoped> +.sun { + opacity: 1; +} + +.moon { + opacity: 0; +} + +.dark .sun { + opacity: 0; +} + +.dark .moon { + opacity: 1; +} + +.dark .switch-appearance :deep(.check) { + /*rtl:ignore*/ + transform: translateX(18px); +} +</style> diff --git a/packages/theme/src/client/components/Tag.vue b/packages/theme/src/client/components/Tag.vue deleted file mode 100644 index 8845cc91..00000000 --- a/packages/theme/src/client/components/Tag.vue +++ /dev/null @@ -1,100 +0,0 @@ -<script lang="ts" setup> -import BlogInfo from '@theme-plume/BlogInfo.vue' -import DropdownTransition from '@theme-plume/DropdownTransition.vue' -import PostList from '@theme-plume/PostList.vue' -import { computed, ref, watch } from 'vue' -import { useRoute, useRouter } from 'vue-router' -import type { PostListRef } from '../composables/index.js' -import { usePostAllIndex, useTagList } from '../composables/index.js' -import { normalizePath } from '../utils/index.js' - -const tagList = useTagList() -const route = useRoute() -const router = useRouter() -const postList: PostListRef = ref([]) -const postAllList = usePostAllIndex() -const currentTag = computed(() => { - return route.query.tag || '' -}) - -watch( - [currentTag, route], - ([nowTag]) => { - if (nowTag) { - postList.value = postAllList.value.filter((post) => { - return post.tags.some((tag) => normalizePath(tag) === nowTag) - }) - } else { - postList.value = [] - } - }, - { immediate: true } -) - -const handleTag = (tag: string): void => { - router.replace({ - path: route.path, - query: { tag: normalizePath(tag) }, - }) -} -</script> -<template> - <main class="tag-wrapper"> - <div class="tag-container"> - <div class="tag-content"> - <DropdownTransition> - <section class="tag-list"> - <span - v-for="{ tag, color } in tagList" - :key="tag" - class="tag" - :style="{ 'background-color': color }" - @click="handleTag(tag)" - >{{ tag }}</span - > - </section> - </DropdownTransition> - <PostList :post-list="postList"></PostList> - </div> - <BlogInfo></BlogInfo> - </div> - </main> -</template> -<style lang="scss"> -@import '../styles/_mixins'; - -.tag-wrapper { - @include wrapper; - - .tag-container { - @include container_wrapper; - display: flex; - align-items: flex-start; - padding: 1.25rem 0; - } - - .tag-content { - flex: 1; - } - - .tag-list { - width: 100%; - padding: 0 1.25rem 0.75rem; - margin: 0 -0.25rem; - - .tag { - height: 1.75rem; - font-size: 16px; - line-height: 1.75rem; - display: inline-block; - padding: 0 0.75rem; - border-radius: 0.85rem; - margin: 0 0.25rem 0.5rem; - background-color: var(--c-bg-lighter); - cursor: pointer; - color: #fff; - // box-shadow: var(--shadow-sm); - } - } -} -</style> diff --git a/packages/theme/src/client/components/ToggleSidebarButton.vue b/packages/theme/src/client/components/ToggleSidebarButton.vue deleted file mode 100644 index 32756a2d..00000000 --- a/packages/theme/src/client/components/ToggleSidebarButton.vue +++ /dev/null @@ -1,65 +0,0 @@ -<script setup lang="ts"> -import { useThemeLocaleData } from '../composables/index.js' - -defineEmits(['toggle']) - -const themeLocale = useThemeLocaleData() -</script> - -<template> - <div - class="toggle-sidebar-button" - :title="themeLocale.toggleSidebar || ''" - aria-expanded="false" - role="button" - tabindex="0" - @click="$emit('toggle')" - > - <div class="icon" aria-hidden="true"> - <span></span> - <span></span> - <span></span> - </div> - </div> -</template> -<style lang="scss"> -@import '../styles/_mixins'; - -.toggle-sidebar-button { - position: absolute; - top: 0.6rem; - left: 1rem; - display: none; - padding: 0.6rem; - cursor: pointer; -} - -.toggle-sidebar-button .icon { - display: flex; - flex-direction: column; - justify-content: center; - align-items: center; - width: 1.25rem; - height: 1.25rem; - cursor: inherit; - - span { - display: inline-block; - width: 100%; - height: 2px; - border-radius: 2px; - background-color: var(--c-text); - transition: transform var(--t-transform); - - &:nth-child(2) { - margin: 6px 0; - } - } -} - -@media screen and (max-width: $MQMobile) { - .toggle-sidebar-button { - display: block; - } -} -</style> diff --git a/packages/theme/src/client/components/VButton.vue b/packages/theme/src/client/components/VButton.vue new file mode 100644 index 00000000..a1566daa --- /dev/null +++ b/packages/theme/src/client/components/VButton.vue @@ -0,0 +1,122 @@ +<script setup lang="ts"> +import { computed } from 'vue' +import { EXTERNAL_URL_RE } from '../utils/index.js' + +const props = defineProps<{ + tag?: string + size?: 'medium' | 'big' + theme?: 'brand' | 'alt' | 'sponsor' + text: string + href?: string +}>() + +const classes = computed(() => [props.size ?? 'medium', props.theme ?? 'brand']) + +const isExternal = computed( + () => props.href && EXTERNAL_URL_RE.test(props.href) +) + +const component = computed(() => { + if (props.tag) { + return props.tag + } + + return props.href ? 'a' : 'button' +}) +</script> + +<template> + <Component + :is="component" + class="VPButton" + :class="classes" + :href="href" + :target="isExternal ? '_blank' : undefined" + :rel="isExternal ? 'noreferrer' : undefined" + > + {{ text }} + </Component> +</template> + +<style scoped> +.VPButton { + display: inline-block; + border: 1px solid transparent; + text-align: center; + font-weight: 600; + white-space: nowrap; + transition: color 0.25s, border-color 0.25s, background-color 0.25s; +} + +.VPButton:active { + transition: color 0.1s, border-color 0.1s, background-color 0.1s; +} + +.VPButton.medium { + border-radius: 20px; + padding: 0 20px; + line-height: 38px; + font-size: 14px; +} + +.VPButton.big { + border-radius: 24px; + padding: 0 24px; + line-height: 46px; + font-size: 16px; +} + +.VPButton.brand { + border-color: var(--vp-button-brand-border); + color: var(--vp-button-brand-text); + background-color: var(--vp-button-brand-bg); +} + +.VPButton.brand:hover { + border-color: var(--vp-button-brand-hover-border); + color: var(--vp-button-brand-hover-text); + background-color: var(--vp-button-brand-hover-bg); +} + +.VPButton.brand:active { + border-color: var(--vp-button-brand-active-border); + color: var(--vp-button-brand-active-text); + background-color: var(--vp-button-brand-active-bg); +} + +.VPButton.alt { + border-color: var(--vp-button-alt-border); + color: var(--vp-button-alt-text); + background-color: var(--vp-button-alt-bg); +} + +.VPButton.alt:hover { + border-color: var(--vp-button-alt-hover-border); + color: var(--vp-button-alt-hover-text); + background-color: var(--vp-button-alt-hover-bg); +} + +.VPButton.alt:active { + border-color: var(--vp-button-alt-active-border); + color: var(--vp-button-alt-active-text); + background-color: var(--vp-button-alt-active-bg); +} + +.VPButton.sponsor { + border-color: var(--vp-button-sponsor-border); + color: var(--vp-button-sponsor-text); + background-color: var(--vp-button-sponsor-bg); +} + +.VPButton.sponsor:hover { + border-color: var(--vp-button-sponsor-hover-border); + color: var(--vp-button-sponsor-hover-text); + background-color: var(--vp-button-sponsor-hover-bg); +} + +.VPButton.sponsor:active { + border-color: var(--vp-button-sponsor-active-border); + color: var(--vp-button-sponsor-active-text); + background-color: var(--vp-button-sponsor-active-bg); +} +</style> diff --git a/packages/theme/src/client/components/VFooter.vue b/packages/theme/src/client/components/VFooter.vue new file mode 100644 index 00000000..3baa7442 --- /dev/null +++ b/packages/theme/src/client/components/VFooter.vue @@ -0,0 +1,70 @@ +<script setup lang="ts"> +import { useSidebar, useThemeLocaleData } from '../composables/index.js' + +const theme = useThemeLocaleData() +const { hasSidebar } = useSidebar() +</script> + +<template> + <!-- eslint-disable vue/no-v-html --> + <footer + v-if="theme.footer" + class="plume-footer" + :class="{ 'has-sidebar': hasSidebar }" + > + <div class="container"> + <p + v-if="theme.footer.message" + class="message" + v-html="theme.footer.message" + ></p> + <p + v-if="theme.footer.copyright" + class="copyright" + v-html="theme.footer.copyright" + ></p> + </div> + </footer> +</template> + +<style scoped> +.plume-footer { + position: relative; + z-index: var(--vp-z-index-footer); + border-top: 1px solid var(--vp-c-gutter); + padding: 32px 24px; + background-color: var(--vp-c-bg); +} + +.plume-footer.has-sidebar { + display: none; +} + +@media (min-width: 768px) { + .plume-footer { + padding: 32px; + } +} + +.container { + margin: 0 auto; + max-width: var(--vp-layout-max-width); + text-align: center; +} + +.message, +.copyright { + line-height: 24px; + font-size: 14px; + font-weight: 500; + color: var(--vp-c-text-2); +} + +.message { + order: 2; +} + +.copyright { + order: 1; +} +</style> diff --git a/packages/theme/src/client/components/VImage.vue b/packages/theme/src/client/components/VImage.vue new file mode 100644 index 00000000..466a6789 --- /dev/null +++ b/packages/theme/src/client/components/VImage.vue @@ -0,0 +1,50 @@ +<script lang="ts" setup> +import { withBase } from '@vuepress/client' +defineProps<{ + image: + | string + | { src: string; alt?: string } + | { dark: string; light: string; alt?: string } + alt?: string +}>() +</script> +<script lang="ts"> +export default { + inheritAttrs: false, +} +</script> +<template> + <template v-if="image"> + <img + v-if="typeof image === 'string' || 'src' in image" + class="plume-image" + v-bind="typeof image === 'string' ? $attrs : { ...image, ...$attrs }" + :src="withBase(typeof image === 'string' ? image : image.src)" + :alt="alt ?? (typeof image === 'string' ? '' : image.alt || '')" + /> + <template v-else> + <VImage + class="dark" + :image="image.dark" + :alt="image.alt" + v-bind="$attrs" + /> + <VImage + class="light" + :image="image.light" + :alt="image.alt" + v-bind="$attrs" + /> + </template> + </template> +</template> + +<style scoped> +html:not(.dark) .plume-image.dark { + display: none; +} + +.dark .plume-image.light { + display: none; +} +</style> diff --git a/packages/theme/src/client/components/global/Badge.vue b/packages/theme/src/client/components/global/Badge.vue deleted file mode 100644 index 8266c5d3..00000000 --- a/packages/theme/src/client/components/global/Badge.vue +++ /dev/null @@ -1,57 +0,0 @@ -<script lang="ts" setup> -defineProps({ - type: { - type: String, - required: false, - default: 'tip', - }, - text: { - type: String, - required: false, - default: '', - }, - vertical: { - type: String, - required: false, - default: undefined, - }, -}) -</script> -<template> - <span class="badge" :class="type" :style="{ verticalAlign: vertical }"> - <slot>{{ text }}</slot> - </span> -</template> -<style lang="scss"> -.badge { - display: inline-block; - font-size: 14px; - height: 18px; - line-height: 18px; - border-radius: 3px; - padding: 0 6px; - color: var(--c-bg); - vertical-align: top; - transition: color var(--t-color), background-color var(--t-color); - - &.tip { - background-color: var(--c-badge-tip); - } - - &.warning { - background-color: var(--c-badge-warning); - } - - &.danger { - background-color: var(--c-badge-danger); - } - - .table-of-contents & { - vertical-align: middle; - } - - & + & { - margin-left: 5px; - } -} -</style> diff --git a/packages/theme/src/client/components/icons/IconAlignJustify.vue b/packages/theme/src/client/components/icons/IconAlignJustify.vue new file mode 100644 index 00000000..b213f61b --- /dev/null +++ b/packages/theme/src/client/components/icons/IconAlignJustify.vue @@ -0,0 +1,21 @@ +<template> + <svg + xmlns="http://www.w3.org/2000/svg" + aria-hidden="true" + focusable="false" + viewBox="0 0 24 24" + > + <path + d="M21,11H3c-0.6,0-1-0.4-1-1s0.4-1,1-1h18c0.6,0,1,0.4,1,1S21.6,11,21,11z" + /> + <path + d="M21,7H3C2.4,7,2,6.6,2,6s0.4-1,1-1h18c0.6,0,1,0.4,1,1S21.6,7,21,7z" + /> + <path + d="M21,15H3c-0.6,0-1-0.4-1-1s0.4-1,1-1h18c0.6,0,1,0.4,1,1S21.6,15,21,15z" + /> + <path + d="M21,19H3c-0.6,0-1-0.4-1-1s0.4-1,1-1h18c0.6,0,1,0.4,1,1S21.6,19,21,19z" + /> + </svg> +</template> diff --git a/packages/theme/src/client/components/icons/IconAlignLeft.vue b/packages/theme/src/client/components/icons/IconAlignLeft.vue new file mode 100644 index 00000000..bd3510d9 --- /dev/null +++ b/packages/theme/src/client/components/icons/IconAlignLeft.vue @@ -0,0 +1,21 @@ +<template> + <svg + xmlns="http://www.w3.org/2000/svg" + aria-hidden="true" + focusable="false" + viewBox="0 0 24 24" + > + <path + d="M17,11H3c-0.6,0-1-0.4-1-1s0.4-1,1-1h14c0.6,0,1,0.4,1,1S17.6,11,17,11z" + /> + <path + d="M21,7H3C2.4,7,2,6.6,2,6s0.4-1,1-1h18c0.6,0,1,0.4,1,1S21.6,7,21,7z" + /> + <path + d="M21,15H3c-0.6,0-1-0.4-1-1s0.4-1,1-1h18c0.6,0,1,0.4,1,1S21.6,15,21,15z" + /> + <path + d="M17,19H3c-0.6,0-1-0.4-1-1s0.4-1,1-1h14c0.6,0,1,0.4,1,1S17.6,19,17,19z" + /> + </svg> +</template> diff --git a/packages/theme/src/client/components/icons/IconAlignRight.vue b/packages/theme/src/client/components/icons/IconAlignRight.vue new file mode 100644 index 00000000..4434f6c0 --- /dev/null +++ b/packages/theme/src/client/components/icons/IconAlignRight.vue @@ -0,0 +1,21 @@ +<template> + <svg + xmlns="http://www.w3.org/2000/svg" + aria-hidden="true" + focusable="false" + viewBox="0 0 24 24" + > + <path + d="M21,11H7c-0.6,0-1-0.4-1-1s0.4-1,1-1h14c0.6,0,1,0.4,1,1S21.6,11,21,11z" + /> + <path + d="M21,7H3C2.4,7,2,6.6,2,6s0.4-1,1-1h18c0.6,0,1,0.4,1,1S21.6,7,21,7z" + /> + <path + d="M21,15H3c-0.6,0-1-0.4-1-1s0.4-1,1-1h18c0.6,0,1,0.4,1,1S21.6,15,21,15z" + /> + <path + d="M21,19H7c-0.6,0-1-0.4-1-1s0.4-1,1-1h14c0.6,0,1,0.4,1,1S21.6,19,21,19z" + /> + </svg> +</template> diff --git a/packages/theme/src/client/components/icons/IconArrowLeft.vue b/packages/theme/src/client/components/icons/IconArrowLeft.vue new file mode 100644 index 00000000..3f65b866 --- /dev/null +++ b/packages/theme/src/client/components/icons/IconArrowLeft.vue @@ -0,0 +1,7 @@ +<template> + <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"> + <path + d="M19,11H7.4l5.3-5.3c0.4-0.4,0.4-1,0-1.4s-1-0.4-1.4,0l-7,7c-0.1,0.1-0.2,0.2-0.2,0.3c-0.1,0.2-0.1,0.5,0,0.8c0.1,0.1,0.1,0.2,0.2,0.3l7,7c0.2,0.2,0.5,0.3,0.7,0.3s0.5-0.1,0.7-0.3c0.4-0.4,0.4-1,0-1.4L7.4,13H19c0.6,0,1-0.4,1-1S19.6,11,19,11z" + /> + </svg> +</template> diff --git a/packages/theme/src/client/components/icons/IconArrowRight.vue b/packages/theme/src/client/components/icons/IconArrowRight.vue new file mode 100644 index 00000000..ed89263f --- /dev/null +++ b/packages/theme/src/client/components/icons/IconArrowRight.vue @@ -0,0 +1,7 @@ +<template> + <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"> + <path + d="M19.9,12.4c0.1-0.2,0.1-0.5,0-0.8c-0.1-0.1-0.1-0.2-0.2-0.3l-7-7c-0.4-0.4-1-0.4-1.4,0s-0.4,1,0,1.4l5.3,5.3H5c-0.6,0-1,0.4-1,1s0.4,1,1,1h11.6l-5.3,5.3c-0.4,0.4-0.4,1,0,1.4c0.2,0.2,0.5,0.3,0.7,0.3s0.5-0.1,0.7-0.3l7-7C19.8,12.6,19.9,12.5,19.9,12.4z" + /> + </svg> +</template> diff --git a/packages/theme/src/client/components/icons/IconBase.ts b/packages/theme/src/client/components/icons/IconBase.ts deleted file mode 100644 index 29dfb55f..00000000 --- a/packages/theme/src/client/components/icons/IconBase.ts +++ /dev/null @@ -1,39 +0,0 @@ -import { defineComponent, h } from 'vue' -import type { VNode } from 'vue' - -export const IconBase = defineComponent({ - name: 'IconBase', - props: { - name: { - type: String, - required: false, - default: '', - }, - color: { - type: String, - required: false, - default: 'currentColor', - }, - viewBox: { - type: String, - required: false, - default: '0 0 20 20', - }, - }, - setup: - (props, { slots }) => - (): VNode => - h( - 'svg', - { - xmlns: 'http://www.w3.org/2000/svg', - class: ['icon', `${props.name}-icon`], - viewBox: props.viewBox, - ariaLabelledby: props.name, - }, - [ - h('title', { id: props.name, lang: 'en' }, `${props.name}`), - h('g', { fill: props.color }, slots.default?.()), - ] - ), -}) diff --git a/packages/theme/src/client/components/icons/IconChevronDown.vue b/packages/theme/src/client/components/icons/IconChevronDown.vue new file mode 100644 index 00000000..7d5904f0 --- /dev/null +++ b/packages/theme/src/client/components/icons/IconChevronDown.vue @@ -0,0 +1,12 @@ +<template> + <svg + xmlns="http://www.w3.org/2000/svg" + aria-hidden="true" + focusable="false" + viewBox="0 0 24 24" + > + <path + d="M12,16c-0.3,0-0.5-0.1-0.7-0.3l-6-6c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l5.3,5.3l5.3-5.3c0.4-0.4,1-0.4,1.4,0s0.4,1,0,1.4l-6,6C12.5,15.9,12.3,16,12,16z" + /> + </svg> +</template> diff --git a/packages/theme/src/client/components/icons/IconChevronLeft.vue b/packages/theme/src/client/components/icons/IconChevronLeft.vue new file mode 100644 index 00000000..16234040 --- /dev/null +++ b/packages/theme/src/client/components/icons/IconChevronLeft.vue @@ -0,0 +1,12 @@ +<template> + <svg + xmlns="http://www.w3.org/2000/svg" + aria-hidden="true" + focusable="false" + viewBox="0 0 24 24" + > + <path + d="M15,19c-0.3,0-0.5-0.1-0.7-0.3l-6-6c-0.4-0.4-0.4-1,0-1.4l6-6c0.4-0.4,1-0.4,1.4,0s0.4,1,0,1.4L10.4,12l5.3,5.3c0.4,0.4,0.4,1,0,1.4C15.5,18.9,15.3,19,15,19z" + /> + </svg> +</template> diff --git a/packages/theme/src/client/components/icons/IconChevronRight.vue b/packages/theme/src/client/components/icons/IconChevronRight.vue new file mode 100644 index 00000000..72f7cfdc --- /dev/null +++ b/packages/theme/src/client/components/icons/IconChevronRight.vue @@ -0,0 +1,12 @@ +<template> + <svg + xmlns="http://www.w3.org/2000/svg" + aria-hidden="true" + focusable="false" + viewBox="0 0 24 24" + > + <path + d="M9,19c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l5.3-5.3L8.3,6.7c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l6,6c0.4,0.4,0.4,1,0,1.4l-6,6C9.5,18.9,9.3,19,9,19z" + /> + </svg> +</template> diff --git a/packages/theme/src/client/components/icons/IconChevronUp.vue b/packages/theme/src/client/components/icons/IconChevronUp.vue new file mode 100644 index 00000000..25cca7c0 --- /dev/null +++ b/packages/theme/src/client/components/icons/IconChevronUp.vue @@ -0,0 +1,12 @@ +<template> + <svg + xmlns="http://www.w3.org/2000/svg" + aria-hidden="true" + focusable="false" + viewBox="0 0 24 24" + > + <path + d="M18,16c-0.3,0-0.5-0.1-0.7-0.3L12,10.4l-5.3,5.3c-0.4,0.4-1,0.4-1.4,0s-0.4-1,0-1.4l6-6c0.4-0.4,1-0.4,1.4,0l6,6c0.4,0.4,0.4,1,0,1.4C18.5,15.9,18.3,16,18,16z" + /> + </svg> +</template> diff --git a/packages/theme/src/client/components/icons/IconClock.vue b/packages/theme/src/client/components/icons/IconClock.vue new file mode 100644 index 00000000..586e1db0 --- /dev/null +++ b/packages/theme/src/client/components/icons/IconClock.vue @@ -0,0 +1,11 @@ +<template> + <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20"> + <g fill="currentColor"> + <path + fill-rule="evenodd" + clip-rule="evenodd" + d="M10 18a8 8 0 100-16 8 8 0 000 16zm1-12a1 1 0 10-2 0v4a1 1 0 00.293.707l2.828 2.829a1 1 0 101.415-1.415L11 9.586V6z" + /> + </g> + </svg> +</template> diff --git a/packages/theme/src/client/components/icons/IconEdit.vue b/packages/theme/src/client/components/icons/IconEdit.vue new file mode 100644 index 00000000..ae60f486 --- /dev/null +++ b/packages/theme/src/client/components/icons/IconEdit.vue @@ -0,0 +1,10 @@ +<template> + <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"> + <path + d="M18,23H4c-1.7,0-3-1.3-3-3V6c0-1.7,1.3-3,3-3h7c0.6,0,1,0.4,1,1s-0.4,1-1,1H4C3.4,5,3,5.4,3,6v14c0,0.6,0.4,1,1,1h14c0.6,0,1-0.4,1-1v-7c0-0.6,0.4-1,1-1s1,0.4,1,1v7C21,21.7,19.7,23,18,23z" + /> + <path + d="M8,17c-0.3,0-0.5-0.1-0.7-0.3C7,16.5,6.9,16.1,7,15.8l1-4c0-0.2,0.1-0.3,0.3-0.5l9.5-9.5c1.2-1.2,3.2-1.2,4.4,0c1.2,1.2,1.2,3.2,0,4.4l-9.5,9.5c-0.1,0.1-0.3,0.2-0.5,0.3l-4,1C8.2,17,8.1,17,8,17zM9.9,12.5l-0.5,2.1l2.1-0.5l9.3-9.3c0.4-0.4,0.4-1.1,0-1.6c-0.4-0.4-1.2-0.4-1.6,0l0,0L9.9,12.5z M18.5,2.5L18.5,2.5L18.5,2.5z" + /> + </svg> +</template> diff --git a/packages/theme/src/client/components/icons/IconExternalLink.vue b/packages/theme/src/client/components/icons/IconExternalLink.vue new file mode 100644 index 00000000..72459909 --- /dev/null +++ b/packages/theme/src/client/components/icons/IconExternalLink.vue @@ -0,0 +1,13 @@ +<template> + <svg + xmlns="http://www.w3.org/2000/svg" + aria-hidden="true" + focusable="false" + height="24px" + viewBox="0 0 24 24" + width="24px" + > + <path d="M0 0h24v24H0V0z" fill="none" /> + <path d="M9 5v2h6.59L4 18.59 5.41 20 17 8.41V15h2V5H9z" /> + </svg> +</template> diff --git a/packages/theme/src/client/components/icons/IconFolder.vue b/packages/theme/src/client/components/icons/IconFolder.vue new file mode 100644 index 00000000..5a333249 --- /dev/null +++ b/packages/theme/src/client/components/icons/IconFolder.vue @@ -0,0 +1,11 @@ +<template> + <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20"> + <g fill="currentColor"> + <path + fill-rule="evenodd" + clip-rule="evenodd" + d="M2 6a2 2 0 012-2h5l2 2h5a2 2 0 012 2v6a2 2 0 01-2 2H4a2 2 0 01-2-2V6z" + /> + </g> + </svg> +</template> diff --git a/packages/theme/src/client/components/icons/IconHeart.vue b/packages/theme/src/client/components/icons/IconHeart.vue new file mode 100644 index 00000000..61ec6ff6 --- /dev/null +++ b/packages/theme/src/client/components/icons/IconHeart.vue @@ -0,0 +1,7 @@ +<template> + <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"> + <path + d="M12,22.2c-0.3,0-0.5-0.1-0.7-0.3l-8.8-8.8c-2.5-2.5-2.5-6.7,0-9.2c2.5-2.5,6.7-2.5,9.2,0L12,4.3l0.4-0.4c0,0,0,0,0,0C13.6,2.7,15.2,2,16.9,2c0,0,0,0,0,0c1.7,0,3.4,0.7,4.6,1.9l0,0c1.2,1.2,1.9,2.9,1.9,4.6c0,1.7-0.7,3.4-1.9,4.6l-8.8,8.8C12.5,22.1,12.3,22.2,12,22.2zM7,4C5.9,4,4.7,4.4,3.9,5.3c-1.8,1.8-1.8,4.6,0,6.4l8.1,8.1l8.1-8.1c0.9-0.9,1.3-2,1.3-3.2c0-1.2-0.5-2.3-1.3-3.2l0,0C19.3,4.5,18.2,4,17,4c0,0,0,0,0,0c-1.2,0-2.3,0.5-3.2,1.3c0,0,0,0,0,0l-1.1,1.1c-0.4,0.4-1,0.4-1.4,0l-1.1-1.1C9.4,4.4,8.2,4,7,4z" + /> + </svg> +</template> diff --git a/packages/theme/src/client/components/icons/IconLanguages.vue b/packages/theme/src/client/components/icons/IconLanguages.vue new file mode 100644 index 00000000..126c58d3 --- /dev/null +++ b/packages/theme/src/client/components/icons/IconLanguages.vue @@ -0,0 +1,14 @@ +<template> + <svg + xmlns="http://www.w3.org/2000/svg" + aria-hidden="true" + focusable="false" + viewBox="0 0 24 24" + > + <path d="M0 0h24v24H0z" fill="none"></path> + <path + d=" M12.87 15.07l-2.54-2.51.03-.03c1.74-1.94 2.98-4.17 3.71-6.53H17V4h-7V2H8v2H1v1.99h11.17C11.5 7.92 10.44 9.75 9 11.35 8.07 10.32 7.3 9.19 6.69 8h-2c.73 1.63 1.73 3.17 2.98 4.56l-5.09 5.02L4 19l5-5 3.11 3.11.76-2.04zM18.5 10h-2L12 22h2l1.12-3h4.75L21 22h2l-4.5-12zm-2.62 7l1.62-4.33L19.12 17h-3.24z " + class="css-c4d79v" + ></path> + </svg> +</template> diff --git a/packages/theme/src/client/components/icons/IconMinus.vue b/packages/theme/src/client/components/icons/IconMinus.vue new file mode 100644 index 00000000..e0229195 --- /dev/null +++ b/packages/theme/src/client/components/icons/IconMinus.vue @@ -0,0 +1,5 @@ +<template> + <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"> + <path d="M22,13H2a1,1,0,0,1,0-2H22a1,1,0,0,1,0,2Z" /> + </svg> +</template> diff --git a/packages/theme/src/client/components/icons/IconMinusSquare.vue b/packages/theme/src/client/components/icons/IconMinusSquare.vue new file mode 100644 index 00000000..0c7c82f6 --- /dev/null +++ b/packages/theme/src/client/components/icons/IconMinusSquare.vue @@ -0,0 +1,14 @@ +<template> + <svg + xmlns="http://www.w3.org/2000/svg" + xmlns:xlink="http://www.w3.org/1999/xlink" + viewBox="0 0 24 24" + > + <path + d="M19,2H5C3.3,2,2,3.3,2,5v14c0,1.7,1.3,3,3,3h14c1.7,0,3-1.3,3-3V5C22,3.3,20.7,2,19,2zM20,19c0,0.6-0.4,1-1,1H5c-0.6,0-1-0.4-1-1V5c0-0.6,0.4-1,1-1h14c0.6,0,1,0.4,1,1V19z" + /> + <path + d="M16,11H8c-0.6,0-1,0.4-1,1s0.4,1,1,1h8c0.6,0,1-0.4,1-1S16.6,11,16,11z" + /> + </svg> +</template> diff --git a/packages/theme/src/client/components/icons/IconMoon.vue b/packages/theme/src/client/components/icons/IconMoon.vue new file mode 100644 index 00000000..b74a8dad --- /dev/null +++ b/packages/theme/src/client/components/icons/IconMoon.vue @@ -0,0 +1,12 @@ +<template> + <svg + xmlns="http://www.w3.org/2000/svg" + aria-hidden="true" + focusable="false" + viewBox="0 0 24 24" + > + <path + d="M12.1,22c-0.3,0-0.6,0-0.9,0c-5.5-0.5-9.5-5.4-9-10.9c0.4-4.8,4.2-8.6,9-9c0.4,0,0.8,0.2,1,0.5c0.2,0.3,0.2,0.8-0.1,1.1c-2,2.7-1.4,6.4,1.3,8.4c2.1,1.6,5,1.6,7.1,0c0.3-0.2,0.7-0.3,1.1-0.1c0.3,0.2,0.5,0.6,0.5,1c-0.2,2.7-1.5,5.1-3.6,6.8C16.6,21.2,14.4,22,12.1,22zM9.3,4.4c-2.9,1-5,3.6-5.2,6.8c-0.4,4.4,2.8,8.3,7.2,8.7c2.1,0.2,4.2-0.4,5.8-1.8c1.1-0.9,1.9-2.1,2.4-3.4c-2.5,0.9-5.3,0.5-7.5-1.1C9.2,11.4,8.1,7.7,9.3,4.4z" + /> + </svg> +</template> diff --git a/packages/theme/src/client/components/icons/IconMoreHorizontal.vue b/packages/theme/src/client/components/icons/IconMoreHorizontal.vue new file mode 100644 index 00000000..1d89acd4 --- /dev/null +++ b/packages/theme/src/client/components/icons/IconMoreHorizontal.vue @@ -0,0 +1,12 @@ +<template> + <svg + xmlns="http://www.w3.org/2000/svg" + aria-hidden="true" + focusable="false" + viewBox="0 0 24 24" + > + <circle cx="12" cy="12" r="2" /> + <circle cx="19" cy="12" r="2" /> + <circle cx="5" cy="12" r="2" /> + </svg> +</template> diff --git a/packages/theme/src/client/components/icons/IconPlus.vue b/packages/theme/src/client/components/icons/IconPlus.vue new file mode 100644 index 00000000..cac062d2 --- /dev/null +++ b/packages/theme/src/client/components/icons/IconPlus.vue @@ -0,0 +1,12 @@ +<template> + <svg + xmlns="http://www.w3.org/2000/svg" + aria-hidden="true" + focusable="false" + viewBox="0 0 24 24" + > + <path + d="M18.9,10.9h-6v-6c0-0.6-0.4-1-1-1s-1,0.4-1,1v6h-6c-0.6,0-1,0.4-1,1s0.4,1,1,1h6v6c0,0.6,0.4,1,1,1s1-0.4,1-1v-6h6c0.6,0,1-0.4,1-1S19.5,10.9,18.9,10.9z" + /> + </svg> +</template> diff --git a/packages/theme/src/client/components/icons/IconPlusSquare.vue b/packages/theme/src/client/components/icons/IconPlusSquare.vue new file mode 100644 index 00000000..6a739ac8 --- /dev/null +++ b/packages/theme/src/client/components/icons/IconPlusSquare.vue @@ -0,0 +1,10 @@ +<template> + <svg version="1.1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"> + <path + d="M19,2H5C3.3,2,2,3.3,2,5v14c0,1.7,1.3,3,3,3h14c1.7,0,3-1.3,3-3V5C22,3.3,20.7,2,19,2z M20,19c0,0.6-0.4,1-1,1H5c-0.6,0-1-0.4-1-1V5c0-0.6,0.4-1,1-1h14c0.6,0,1,0.4,1,1V19z" + /> + <path + d="M16,11h-3V8c0-0.6-0.4-1-1-1s-1,0.4-1,1v3H8c-0.6,0-1,0.4-1,1s0.4,1,1,1h3v3c0,0.6,0.4,1,1,1s1-0.4,1-1v-3h3c0.6,0,1-0.4,1-1S16.6,11,16,11z" + /> + </svg> +</template> diff --git a/packages/theme/src/client/components/icons/IconSun.vue b/packages/theme/src/client/components/icons/IconSun.vue new file mode 100644 index 00000000..d846bad3 --- /dev/null +++ b/packages/theme/src/client/components/icons/IconSun.vue @@ -0,0 +1,36 @@ +<template> + <svg + xmlns="http://www.w3.org/2000/svg" + aria-hidden="true" + focusable="false" + viewBox="0 0 24 24" + > + <path + d="M12,18c-3.3,0-6-2.7-6-6s2.7-6,6-6s6,2.7,6,6S15.3,18,12,18zM12,8c-2.2,0-4,1.8-4,4c0,2.2,1.8,4,4,4c2.2,0,4-1.8,4-4C16,9.8,14.2,8,12,8z" + /> + <path + d="M12,4c-0.6,0-1-0.4-1-1V1c0-0.6,0.4-1,1-1s1,0.4,1,1v2C13,3.6,12.6,4,12,4z" + /> + <path + d="M12,24c-0.6,0-1-0.4-1-1v-2c0-0.6,0.4-1,1-1s1,0.4,1,1v2C13,23.6,12.6,24,12,24z" + /> + <path + d="M5.6,6.6c-0.3,0-0.5-0.1-0.7-0.3L3.5,4.9c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l1.4,1.4c0.4,0.4,0.4,1,0,1.4C6.2,6.5,5.9,6.6,5.6,6.6z" + /> + <path + d="M19.8,20.8c-0.3,0-0.5-0.1-0.7-0.3l-1.4-1.4c-0.4-0.4-0.4-1,0-1.4s1-0.4,1.4,0l1.4,1.4c0.4,0.4,0.4,1,0,1.4C20.3,20.7,20,20.8,19.8,20.8z" + /> + <path + d="M3,13H1c-0.6,0-1-0.4-1-1s0.4-1,1-1h2c0.6,0,1,0.4,1,1S3.6,13,3,13z" + /> + <path + d="M23,13h-2c-0.6,0-1-0.4-1-1s0.4-1,1-1h2c0.6,0,1,0.4,1,1S23.6,13,23,13z" + /> + <path + d="M4.2,20.8c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l1.4-1.4c0.4-0.4,1-0.4,1.4,0s0.4,1,0,1.4l-1.4,1.4C4.7,20.7,4.5,20.8,4.2,20.8z" + /> + <path + d="M18.4,6.6c-0.3,0-0.5-0.1-0.7-0.3c-0.4-0.4-0.4-1,0-1.4l1.4-1.4c0.4-0.4,1-0.4,1.4,0s0.4,1,0,1.4l-1.4,1.4C18.9,6.5,18.6,6.6,18.4,6.6z" + /> + </svg> +</template> diff --git a/packages/theme/src/client/components/icons/IconTag.vue b/packages/theme/src/client/components/icons/IconTag.vue new file mode 100644 index 00000000..d9050f57 --- /dev/null +++ b/packages/theme/src/client/components/icons/IconTag.vue @@ -0,0 +1,11 @@ +<template> + <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20"> + <g fill="currentColor"> + <path + fill-rule="evenodd" + clip-rule="evenodd" + d="M17.707 9.293a1 1 0 010 1.414l-7 7a1 1 0 01-1.414 0l-7-7A.997.997 0 012 10V5a3 3 0 013-3h5c.256 0 .512.098.707.293l7 7zM5 6a1 1 0 100-2 1 1 0 000 2z" + /> + </g> + </svg> +</template> diff --git a/packages/theme/src/client/components/icons/icon.ts b/packages/theme/src/client/components/icons/icon.ts deleted file mode 100644 index f49dfa72..00000000 --- a/packages/theme/src/client/components/icons/icon.ts +++ /dev/null @@ -1,109 +0,0 @@ -import { h } from 'vue' -import type { FunctionalComponent } from 'vue' -import { IconBase } from './IconBase.js' - -export const UserIcon: FunctionalComponent = () => - h(IconBase, { name: 'user' }, () => - h('path', { - 'fill-rule': 'evenodd', - 'clip-rule': 'evenodd', - 'd': 'M10 9a3 3 0 100-6 3 3 0 000 6zm-7 9a7 7 0 1114 0H3z', - }) - ) -UserIcon.displayName = 'UserIcon' - -export const FolderIcon: FunctionalComponent = () => - h(IconBase, { name: 'folder' }, () => - h('path', { - d: 'M2 6a2 2 0 012-2h5l2 2h5a2 2 0 012 2v6a2 2 0 01-2 2H4a2 2 0 01-2-2V6z', - }) - ) -FolderIcon.displayName = 'FolderIcon' - -export const ClockIcon: FunctionalComponent = () => - h(IconBase, { name: 'clock' }, () => - h('path', { - 'fill-rule': 'evenodd', - 'clip-rule': 'evenodd', - 'd': 'M10 18a8 8 0 100-16 8 8 0 000 16zm1-12a1 1 0 10-2 0v4a1 1 0 00.293.707l2.828 2.829a1 1 0 101.415-1.415L11 9.586V6z', - }) - ) -ClockIcon.displayName = 'ClockIcon' - -export const TagIcon: FunctionalComponent = () => - h(IconBase, { name: 'tag' }, () => - h('path', { - 'fill-rule': 'evenodd', - 'clip-rule': 'evenodd', - 'd': 'M17.707 9.293a1 1 0 010 1.414l-7 7a1 1 0 01-1.414 0l-7-7A.997.997 0 012 10V5a3 3 0 013-3h5c.256 0 .512.098.707.293l7 7zM5 6a1 1 0 100-2 1 1 0 000 2z', - }) - ) -TagIcon.displayName = 'TagIcon' - -export const TopIcon: FunctionalComponent = () => - h(IconBase, { name: 'top', viewBox: '0 0 1024 1024' }, () => [ - h('path', { - d: 'M80.96 449.194667l37.696-37.717334 19.626667 19.605334-37.717334 37.717333zM197.205333 541.44l116.16-116.138667 13.568 13.568-116.16 116.16zM220.565333 565.162667l116.16-116.16 13.568 13.589333-116.16 116.138667zM173.845333 517.738667l116.16-116.16 13.568 13.589333-116.16 116.138667zM245.354667 587.477333l116.202666-116.096 13.568 13.589334-116.202666 116.096z', - // fill: '#FA8D14', - }), - h('path', { - d: 'M339.2 0L0 345.6V1024L1024 0H339.2z m-115.2 283.733333l46.933333 46.933334-14.933333 12.8-4.266667-4.266667-140.8 140.8 4.266667 4.266667-14.933333 14.933333-46.933334-46.933333 170.666667-168.533334z m2.133333 375.466667l-12.8-12.8 29.866667-29.866667L149.333333 520.533333l64-64-12.8-12.8L108.8 533.333333l-10.666667-10.666666 89.6-89.6-10.666666-10.666667 14.933333-14.933333 10.666667 10.666666 91.733333-91.733333 10.666667 10.666667-91.733334 91.733333 12.8 12.8 68.266667-68.266667 96 96 27.733333-27.733333 12.8 12.8-204.8 204.8z m232.533334-236.8l-17.066667 17.066667c-6.4-6.4-14.933333-10.666667-21.333333-14.933334 8.533333-4.266667 14.933333-10.666667 21.333333-17.066666 6.4-6.4 6.4-12.8 0-19.2l-136.533333-136.533334-34.133334 34.133334-14.933333-17.066667L332.8 192l14.933333 14.933333-25.6 27.733334 138.666667 138.666666c14.933333 14.933333 14.933333 32-2.133333 49.066667z m-81.066667-200.533333l38.4-38.4-21.333333-34.133334-46.933334 46.933334-14.933333-14.933334 123.733333-123.733333 12.8 17.066667-59.733333 59.733333 21.333333 34.133333 57.6-57.6 98.133334 98.133334-14.933334 14.933333-83.2-83.2-78.933333 78.933333 85.333333 85.333334-14.933333 14.933333-102.4-98.133333z m138.666667 162.133333c-6.4-2.133333-14.933333-4.266667-25.6-4.266667 19.2-34.133333 25.6-61.866667 23.466666-85.333333-2.133333-21.333333-17.066667-44.8-42.666666-70.4L448 200.533333l14.933333-14.933333 23.466667 23.466667c17.066667 17.066667 29.866667 34.133333 38.4 49.066666 38.4-8.533333 74.666667-14.933333 106.666667-19.2l2.133333 25.6c-34.133333 2.133333-68.266667 8.533333-100.266667 14.933334 2.133333 4.266667 2.133333 8.533333 2.133334 12.8 6.4 23.466667 0 55.466667-19.2 91.733333z', - // fill: '#FA8D14', - }), - h('path', { - d: 'M183.765333 346.965333l37.696-37.717333 19.626667 19.584-37.696 37.738667zM132.288 398.037333l37.76-37.674666 19.584 19.626666-37.738667 37.674667z', - // fill: '#FA8D14', - }), - ]) -TopIcon.displayName = 'TopIcon' - -export const ArrowRightIcon: FunctionalComponent = () => - h(IconBase, { name: 'arrow-right', viewBox: '0 0 1024 1024' }, () => - h('path', { - d: 'M709.546667 560.256c-2.389333 2.474667-11.52 13.056-19.968 21.76-49.706667 54.741333-179.370667 144.341333-247.253334 171.690667-10.325333 4.394667-36.394667 13.696-50.304 14.293333-13.354667 0-26.026667-3.072-38.186666-9.301333a79.957333 79.957333 0 0 1-33.92-38.570667c-4.266667-11.221333-10.922667-44.8-10.922667-45.397333-6.656-36.736-10.325333-96.426667-10.325333-162.389334 0-62.848 3.669333-120.106667 9.088-157.397333 0.64-0.597333 7.253333-42.325333 14.549333-56.618667A76.16 76.16 0 0 1 389.632 256h2.389333c18.176 0.64 56.362667 16.853333 56.362667 17.450667 64.213333 27.392 190.890667 112.597333 241.834667 169.216 0 0 14.336 14.549333 20.565333 23.637333 9.728 13.056 14.549333 29.226667 14.549333 45.397333 0 18.048-5.461333 34.858667-15.786666 48.554667z', - }) - ) -ArrowRightIcon.displayName = 'ArrowRightIcon' - -export const ArrowBottomIcon: FunctionalComponent = () => - h(IconBase, { name: 'arrow-bottom', viewBox: '0 0 1024 1024' }, () => - h('path', { - d: 'M150.001 502.111a22.487 22.487 0 0 1 13.185 4.245l348.86 250.152 348.858-250.152a22.577 22.577 0 0 1 26.28 36.665L525.14 802.656a22.577 22.577 0 0 1-26.28 0L136.816 543.02a22.577 22.577 0 0 1 13.185-40.91z m737.183-257.196L525.14 504.55a22.577 22.577 0 0 1-26.28 0L136.816 244.915a22.577 22.577 0 1 1 26.28-36.665l348.859 250.152L860.814 208.25a22.577 22.577 0 1 1 26.28 36.665z', - }) - ) -ArrowBottomIcon.displayName = 'ArrowBottomIcon' - -export const BackTopIcon: FunctionalComponent = () => - h(IconBase, { name: 'back-top', viewBox: '0 0 1024 1024' }, () => - h('path', { - d: 'M725.902 498.916c18.205-251.45-93.298-410.738-205.369-475.592l-6.257-3.982-6.258 3.414c-111.502 64.853-224.711 224.142-204.8 475.59-55.751 53.476-80.214 116.623-80.214 204.8v15.36l179.2-35.27c11.378 40.39 58.596 69.973 113.21 69.973 54.613 0 101.262-29.582 112.64-68.836l180.337 36.41v-15.36c-0.569-89.885-25.031-153.6-82.489-206.507zM571.733 392.533c-33.564 31.29-87.04 28.445-118.329-5.12s-28.444-87.04 5.12-117.76c33.565-31.289 87.04-28.444 118.33 5.12s28.444 86.471-5.12 117.76z m-56.32 368.64c-35.84 0-64.284 29.014-64.284 64.285 0 35.84 54.044 182.613 64.284 182.613s64.285-146.773 64.285-182.613c0-35.271-29.014-64.285-64.285-64.285z', - }) - ) -BackTopIcon.displayName = 'BackTopIcon' - -export const PostIcon: FunctionalComponent = () => - h(IconBase, { name: 'post', viewBox: '0 0 1024 1024' }, () => - h('path', { - d: 'M805.376 81.0496 188.7232 81.0496c-52.6336 0-94.8736 42.3936-94.8736 94.6176l0 664.576c0 52.2752 42.496 94.6176 94.8736 94.6176L805.376 934.8608c52.6336 0 94.8736-42.3936 94.8736-94.6176L900.2496 175.7184C900.2496 123.392 857.8048 81.0496 805.376 81.0496zM288.768 204.8c39.3216 0 71.168 31.5904 71.168 71.168 0 39.3216-31.5904 71.168-71.168 71.168-39.3216 0-71.168-31.5904-71.168-71.168C217.6 236.6464 249.1904 204.8 288.768 204.8zM506.368 741.0176 217.6 741.0176l0-47.4112L506.368 693.6064 506.368 741.0176zM671.3344 617.2672 217.6 617.2672 217.6 569.856l453.7344 0L671.3344 617.2672zM671.3344 493.568 217.6 493.568 217.6 446.1056l453.7344 0L671.3344 493.568z', - }) - ) -PostIcon.displayName = 'PostIcon' - -export const ArrowDoubleRightIcon: FunctionalComponent = () => - h(IconBase, { name: 'arrow-double-right', viewBox: '0 0 1024 1024' }, () => - h('path', { - d: 'M160.117 212.026v-82.233a8 8 0 0 1 13.33-5.966l407.697 364.298c0.9 0.804 1.753 1.658 2.556 2.558 11.764 13.186 10.62 33.419-2.556 45.192L173.448 900.173a8 8 0 0 1-13.33-5.966v-82.233a16 16 0 0 1 5.338-11.93L487.814 512 165.456 223.957a16 16 0 0 1-5.339-11.931z m272.057 0v-82.233a8 8 0 0 1 13.33-5.966l407.697 364.298c0.9 0.804 1.753 1.658 2.556 2.558 11.764 13.186 10.62 33.419-2.556 45.192L445.505 900.173a8 8 0 0 1-13.33-5.966v-82.233a16 16 0 0 1 5.339-11.93L759.87 512 437.514 223.957a16 16 0 0 1-5.34-11.931z', - }) - ) -ArrowDoubleRightIcon.displayName = 'ArrowDoubleRightIcon' - -export const ArrowDoubleLeftIcon: FunctionalComponent = () => - h(IconBase, { name: 'arrow-double-left', viewBox: '0 0 1024 1024' }, () => [ - h('path', { - d: 'M495.976 476.195c19.777 17.656 21.494 48 3.837 67.774a48.003 48.003 0 0 1-3.837 3.836L536.082 512l-40.106-35.805zM864 212.083v-82.217a8 8 0 0 0-13.328-5.967L442.69 488.13c-0.9 0.804-1.754 1.657-2.558 2.557-11.772 13.184-10.626 33.412 2.558 45.183l407.983 364.231A8 8 0 0 0 864 894.134v-82.217a16 16 0 0 0-5.344-11.936L536.082 512l322.574-287.981A16 16 0 0 0 864 212.083zM495.976 476.195c19.777 17.656 21.494 48 3.837 67.774a48.003 48.003 0 0 1-3.837 3.836L536.082 512l-40.106-35.805zM864 212.083v-82.217a8 8 0 0 0-13.328-5.967L442.69 488.13c-0.9 0.804-1.754 1.657-2.558 2.557-11.772 13.184-10.626 33.412 2.558 45.183l407.983 364.231A8 8 0 0 0 864 894.134v-82.217a16 16 0 0 0-5.344-11.936L536.082 512l322.574-287.981A16 16 0 0 0 864 212.083z', - }), - h('path', { - d: 'M223.976 476.195c19.777 17.656 21.494 48 3.837 67.774a48.003 48.003 0 0 1-3.837 3.836L264.082 512l-40.106-35.805zM592 212.083v-82.217a8 8 0 0 0-13.328-5.967L170.69 488.13c-0.9 0.804-1.754 1.657-2.558 2.557-11.772 13.184-10.626 33.412 2.558 45.183l407.983 364.231A8 8 0 0 0 592 894.134v-82.217a16 16 0 0 0-5.344-11.936L264.082 512l322.574-287.981A16 16 0 0 0 592 212.083zM223.976 476.195c19.777 17.656 21.494 48 3.837 67.774a48.003 48.003 0 0 1-3.837 3.836L264.082 512l-40.106-35.805zM592 212.083v-82.217a8 8 0 0 0-13.328-5.967L170.69 488.13c-0.9 0.804-1.754 1.657-2.558 2.557-11.772 13.184-10.626 33.412 2.558 45.183l407.983 364.231A8 8 0 0 0 592 894.134v-82.217a16 16 0 0 0-5.344-11.936L264.082 512l322.574-287.981A16 16 0 0 0 592 212.083z', - }), - ]) -ArrowDoubleLeftIcon.displayName = 'ArrowDoubleLeftIcon' diff --git a/packages/theme/src/client/components/icons/index.ts b/packages/theme/src/client/components/icons/index.ts deleted file mode 100644 index dba30023..00000000 --- a/packages/theme/src/client/components/icons/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -export * from './IconBase.js' -export * from './icon.js' -export * from './socialIcon.js' diff --git a/packages/theme/src/client/components/icons/socialIcon.ts b/packages/theme/src/client/components/icons/socialIcon.ts deleted file mode 100644 index 910d7119..00000000 --- a/packages/theme/src/client/components/icons/socialIcon.ts +++ /dev/null @@ -1,126 +0,0 @@ -import { h } from 'vue' -import type { FunctionalComponent } from 'vue' -import { IconBase } from './IconBase.js' - -export const GithubIcon: FunctionalComponent = () => - h(IconBase, { name: 'github', viewBox: '0 0 1024 1024' }, () => - h('path', { - d: 'M512 0C229.283787 0 0.142041 234.942803 0.142041 524.867683c0 231.829001 146.647305 428.553077 350.068189 497.952484 25.592898 4.819996 34.976961-11.38884 34.976961-25.294314 0-12.45521-0.469203-45.470049-0.725133-89.276559-142.381822 31.735193-172.453477-70.380469-172.453477-70.380469-23.246882-60.569859-56.816233-76.693384-56.816234-76.693385-46.493765-32.58829 3.540351-31.948468 3.540351-31.948467 51.356415 3.71097 78.356923 54.086324 78.356923 54.086324 45.683323 80.19108 119.817417 57.072162 148.993321 43.593236 4.649376-33.91059 17.915029-57.029508 32.50298-70.167195-113.675122-13.222997-233.151301-58.223843-233.1513-259.341366 0-57.285437 19.919806-104.163095 52.678715-140.846248-5.246544-13.265652-22.820334-66.626844 4.990615-138.884127 0 0 42.996069-14.076094 140.760939 53.787741 40.863327-11.644769 84.627183-17.445825 128.177764-17.6591 43.465272 0.213274 87.271782 6.014331 128.135109 17.6591 97.679561-67.906489 140.59032-53.787741 140.59032-53.787741 27.938914 72.257282 10.407779 125.618474 5.118579 138.884127 32.844219 36.683154 52.593405 83.560812 52.593405 140.846248 0 201.586726-119.646798 245.990404-233.663158 258.957473 18.341577 16.208835 34.721032 48.199958 34.721032 97.210357 0 70.167195-0.639822 126.7275-0.639823 143.960051 0 14.033439 9.213443 30.370239 35.190235 25.209005 203.250265-69.527373 349.769606-266.123484 349.769605-497.867175C1023.857959 234.942803 794.673558 0 512 0', - fill: '#3E75C3', - }) - ) -GithubIcon.displayName = 'GithubIcon' - -export const EmailIcon: FunctionalComponent = () => - h(IconBase, { name: 'email', viewBox: '0 0 1024 1024' }, () => [ - [ - h('path', { - d: 'M848.76288 333.62432H164.99712C99.32288 333.62432 46.08 386.87232 46.08 452.54144v297.28768c0 65.67424 53.24288 118.92224 118.91712 118.92224h683.77088c65.66912 0 118.91712-53.24288 118.91712-118.92224V452.54144c-0.00512-65.66912-53.248-118.91712-118.92224-118.91712z', - fill: '#96383D', - }), - h('path', { - d: 'M639.8208 51.2h-474.8288a44.58496 44.58496 0 0 0-44.59008 44.59008v609.44896a44.57984 44.57984 0 0 0 44.59008 44.59008h683.776a44.58496 44.58496 0 0 0 44.59008-44.59008V304.73728L639.8208 51.2z', - fill: '#EBE2CE', - }), - h('path', { - d: 'M551.4752 229.57568H209.59232v44.59008h341.88288v-44.59008zM209.59232 794.42432h594.58048v-44.5952H209.59232v44.5952z m0-89.18528h594.58048v-44.5952H209.59232v44.5952z m0-178.37568h594.58048v-44.5952H209.59232v44.5952z m0 89.18528h594.58048v-44.59008H209.59232v44.59008z m0-222.96576v44.59008h594.58048v-44.59008H209.59232z', - fill: '#C9C1B1', - }), - h('path', { - d: 'M941.83936 393.31328L75.60704 955.02848c12.89216 10.93632 29.29664 17.77152 47.44192 17.77152H893.5936c40.91904 0 74.09152-33.4592 74.09152-74.74688V449.60768c-0.00512-22.58432-10.14784-42.58816-25.84576-56.2944z', - fill: '#D54D54', - }), - h('path', { - d: 'M71.99232 396.5696C56.25344 410.18368 46.08 430.08512 46.08 452.54144v445.93152C46.08 939.53024 79.34976 972.8 120.40192 972.8h772.95104c18.20672 0 34.65216-6.79424 47.56992-17.664L71.99232 396.5696z', - fill: '#EA5455', - }), - h('path', { - d: 'M655.52384 66.90816v236.8l237.82912 74.89024V304.73728z', - fill: '', - }), - h('path', { - d: 'M640.66048 52.0448v207.2576a44.58496 44.58496 0 0 0 44.5952 44.5952h207.2576l-251.8528-251.8528z', - fill: '#FFFBF2', - }), - ], - ]) -EmailIcon.displayName = 'EmailIcon' - -export const ZhiHuIcon: FunctionalComponent = () => - h(IconBase, { name: 'zhiHu', viewBox: '0 0 1024 1024' }, () => [ - h('path', { - d: 'M512 73.28A438.72 438.72 0 1 0 950.72 512 438.72 438.72 0 0 0 512 73.28z m-98.56 458.88l-16.8 66.88 23.68-20.8s53.92 61.28 64 76.48 1.44 68.96 1.44 68.96l-92.48-113.12s-29.12 101.12-68.48 124.16a97.6 97.6 0 0 1-80 6.56 342.08 342.08 0 0 0 85.44-89.76 382.88 382.88 0 0 0 39.52-119.36h-115.04s8.8-40.48 24.16-41.6 90.88 0 90.88 0l-1.76-124.8-43.2 2.24a96 96 0 0 1-32 48c-24.16 17.44-38.4 10.88-38.4 10.88s42.72-118.24 55.84-141.28 50.4-25.12 50.4-25.12l-23.04 66.72h147.84c17.6 0 18.56 40.64 18.56 40.64h-90.56v122.56s61.28-2.24 81.12 0 19.68 41.6 19.68 41.6z m329.44 160h-91.52l-65.12 46.24-13.6-46.24h-36.96v-368h208z', - fill: '#49C0FB', - }), - h('path', { - d: 'M602.88 691.68l54.88-41.44h43.04V364.64h-121.12v285.6h11.2l12 41.44z', - fill: '#49C0FB', - }), - ]) -ZhiHuIcon.displayName = 'ZhiHuIcon' - -export const WeiBoIcon: FunctionalComponent = () => - h(IconBase, { name: 'weiBo', viewBox: '0 0 1024 1024' }, () => [ - h('path', { - d: 'M448.698182 482.210909c-96.814545 4.654545-175.010909 56.785455-175.010909 121.949091s78.196364 114.501818 175.010909 109.847273S623.709091 647.912727 623.709091 582.749091c-0.930909-64.232727-79.127273-105.192727-175.010909-100.538182z m65.163636 164.770909c-29.789091 39.098182-88.436364 57.716364-145.221818 26.065455-26.996364-14.894545-26.065455-43.752727-26.065455-43.752728s-11.170909-92.16 85.643637-103.330909c97.745455-12.101818 115.432727 81.92 85.643636 121.018182z', - fill: '#EA5D5C', - }), - h('path', { - d: 'M448.698182 584.610909c-6.516364 4.654545-7.447273 13.032727-3.723637 18.618182 2.792727 5.585455 11.170909 6.516364 16.756364 1.861818 5.585455-4.654545 8.378182-13.032727 4.654546-18.618182-2.792727-5.585455-10.24-6.516364-17.687273-1.861818zM403.083636 597.643636c-18.618182 1.861818-30.72 17.687273-30.72 33.512728 0 14.894545 14.894545 26.065455 32.581819 24.203636 17.687273-1.861818 32.581818-15.825455 32.581818-31.650909s-13.963636-27.927273-34.443637-26.065455z', - fill: '#EA5D5C', - }), - h('path', { - d: 'M512 0C229.003636 0 0 229.003636 0 512s229.003636 512 512 512 512-229.003636 512-512S794.996364 0 512 0z m197.352727 626.501818C669.323636 712.145455 538.065455 754.036364 441.250909 746.589091c-92.16-7.447273-211.316364-38.167273-223.418182-151.738182 0 0-6.516364-51.2 42.821818-117.294545 0 0 70.749091-99.607273 152.669091-128.465455 82.850909-27.927273 92.16 19.549091 92.16 48.407273-4.654545 24.203636-12.101818 38.167273 18.618182 28.858182 0 0 80.989091-38.167273 114.501818-4.654546 26.996364 26.996364 4.654545 65.163636 4.654546 65.163637s-11.170909 12.101818 12.101818 16.756363c21.410909 3.723636 94.021818 37.236364 53.992727 122.88z m-80.058182-236.450909c-8.378182 0-15.825455-7.447273-15.825454-15.825454 0-9.309091 7.447273-15.825455 15.825454-15.825455 0 0 99.607273-18.618182 87.505455 89.367273v1.861818c-0.930909 7.447273-7.447273 13.963636-15.825455 13.963636-9.309091 0-15.825455-7.447273-15.825454-15.825454 0-1.861818 15.825455-73.541818-55.854546-57.716364zM797.789091 493.381818c-2.792727 18.618182-12.101818 11.170909-22.341818 11.170909-13.032727 0-23.272727-16.756364-23.272728-29.789091 0-11.170909 4.654545-22.341818 4.654546-22.341818 0.930909-4.654545 12.101818-34.443636-7.447273-78.196363-35.374545-60.509091-106.123636-60.509091-114.501818-57.716364-8.378182 3.723636-21.410909 5.585455-21.410909 5.585454-13.032727 0-23.272727-10.24-23.272727-23.272727 0-11.170909 7.447273-19.549091 16.756363-22.341818 0 0 0 0.930909 0.930909 0.930909s1.861818 0.930909 1.861819 0.930909c10.24-1.861818 45.614545-4.654545 79.127272 3.723637 62.370909 14.894545 146.152727 83.781818 108.916364 211.316363z', - fill: '#EA5D5C', - }), - ]) -WeiBoIcon.displayName = 'WeiBoIcon' - -// <svg t="1648887372594" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="3602" width="200" height="200"><path d="" fill="#68A5E1" p-id="3603"></path></svg> -export const QQIcon: FunctionalComponent = () => - h(IconBase, { name: 'qq', viewBox: '0 0 1024 1024' }, () => - h('path', { - d: 'M512.268258 64.433103c-247.183323 0-447.569968 200.380501-447.569968 447.563825 0 247.189467 200.385621 447.570992 447.569968 447.570992s447.569968-200.380501 447.569968-447.569968c0-247.184347-200.386645-447.564849-447.569968-447.564849z m252.85872 584.692787c-18.997168 16.287968-43.668709-53.628042-47.2134-42.875198-8.642616 26.161294-12.695154 43.646184-38.148944 72.127602-1.35972 1.521494 29.43056 12.647032 38.148944 36.396051 8.346713 22.756875 24.596797 58.811973-81.725503 70.125906-62.389428 6.635801-107.471099-33.244533-111.964932-32.85648-8.325212 0.734126-4.618747 0-13.568528 0-7.321804 0-7.807126 0.534468-14.69685 0-1.899307-0.140272-22.632985 32.85648-115.364231 32.85648-71.878798 0-90.48177-45.243445-76.032701-70.125906 14.464428-24.877342 38.579999-32.122354 35.176604-36.06636-16.73643-19.39546-28.287904-40.1404-35.176604-58.882621-1.705793-4.666869-3.135137-9.209848-4.262434-13.574672-2.611931-10.008479-22.627866 58.76385-44.111028 42.875198-21.483162-15.883533-19.567472-56.309597-5.659014-95.003248 14.033372-39.006959 49.37687-76.562049 49.771065-84.854496 1.412962-30.849665-3.044011-35.975235 0-44.078263 6.780169-18.149391 15.034732-11.190043 15.034733-20.609788 0-118.64476 88.172909-214.829571 196.933079-214.829571 108.755051 0 196.928984 96.184811 196.928984 214.829571 0 4.554242 11.815637 0 17.474651 20.609788 1.165181 4.256291 1.968931 20.684531 0.58771 44.078263-0.658358 11.238165 29.954789 24.914202 45.777913 84.854496 15.845649 59.945414 0 88.215912-7.909514 95.003248z', - fill: '#68A5E1', - }) - ) -QQIcon.displayName = 'QQIcon' - -export const TwitterIcon: FunctionalComponent = () => - h(IconBase, { name: 'twitter', viewBox: '0 0 1024 1024' }, () => [ - h('path', { - d: 'M512.274401 959.556658c247.17718 0 447.556658-200.366167 447.556658-447.556658 0-247.16387-200.379477-447.556658-447.556658-447.556658-247.188443 0-447.569968 200.392788-447.569968 447.556658 0 247.190491 200.382549 447.556658 447.569968 447.556658', - fill: '#78CBEF', - }), - h('path', { - d: 'M736.810405 394.754891c-16.48353 7.310541-34.227463 12.256931-52.82122 14.478763 19.004336-11.383557 33.588558-29.396772 40.435279-50.868671-17.780793 10.536804-37.440415 18.183179-58.42392 22.294079-16.741549-17.872942-40.666677-29.038412-67.134113-29.038412-50.766282 0-91.948998 41.192954-91.948998 91.972548 0 7.220439 0.784296 14.222791 2.366199 20.943574-76.439183-3.841618-144.191723-40.421969-189.587726-96.109044-7.915657 13.630985-12.452493 29.422369-12.452493 46.282688 0 31.877646 16.241893 60.042683 40.924696 76.552835-15.072616-0.460748-29.26981-4.637177-41.682371-11.485946v1.131393c0 44.585086 31.698466 81.757243 73.804725 90.185867-7.723167 2.160398-15.841554 3.239573-24.246628 3.239574a91.24866 91.24866 0 0 1-17.294447-1.63105c11.691747 36.527109 45.654023 63.139936 85.90705 63.845394-31.477307 24.682804-71.144672 39.382725-114.227718 39.382725-7.42624 0-14.762379-0.410578-21.946982-1.270642 40.706609 26.070168 89.057546 41.308653 140.992081 41.308653 169.209337 0 261.697922-140.132017 261.697922-261.695874 0-3.997248-0.078839-7.979138-0.244709-11.899595a186.466924 186.466924 0 0 0 45.883373-47.618859', - fill: '#FFFFFF', - }), - ]) -TwitterIcon.displayName = 'TwitterIcon' - -export const FacebookIcon: FunctionalComponent = () => - h(IconBase, { name: 'facebook', viewBox: '0 0 1024 1024' }, () => [ - h('path', { - d: 'M512.262115 959.556658c247.175132 0 447.569968-200.366167 447.569968-447.556658 0-247.16387-200.394836-447.556658-447.569968-447.556658-247.17718 0-447.556658 200.392788-447.556658 447.556658-0.001024 247.190491 200.378454 447.556658 447.556658 447.556658', - fill: '#537BBC', - }), - h('path', { - d: 'M404.292383 436.216104h46.269378v-44.969044c0-19.828563 0.499656-50.408946 14.904699-69.347753 15.172957-20.05689 36.000832-33.690947 71.826579-33.690946 58.371702 0 82.952117 8.326235 82.952118 8.326235l-11.564785 68.550147s-19.285904-5.576079-37.275569-5.57608c-17.99888 0-34.111763 6.449454-34.111764 24.438095v52.269346h73.791416l-5.152191 66.958004h-68.639225v232.604221h-86.731278V503.174108h-46.269378v-66.958004z', - fill: '#FFFFFF', - }), - ]) -FacebookIcon.displayName = 'FacebookIcon' - -export const LinkedinIcon: FunctionalComponent = () => - h(IconBase, { name: 'linkedin', viewBox: '0 0 1024 1024' }, () => [ - h('path', { - d: 'M512.267234 959.569968c247.223255 0 447.572016-200.400979 447.572016-447.582255 0-247.171037-200.347737-447.558705-447.572016-447.558705-247.194586 0-447.568944 200.387669-447.568944 447.558705 0 247.1823 200.373334 447.582255 447.568944 447.582255', - fill: '#1284C7', - }), - h('path', { - d: 'M387.013295 699.188763h-87.249365V419.999808h87.249365v279.188955z m-45.860848-314.114707h-0.628666c-31.57048 0-52.042043-21.341866-52.042043-48.378582 0-27.573232 21.086918-48.478922 53.286064-48.478922 32.175596 0 51.975491 20.852449 52.607228 48.402131 0.001024 27.046955-20.430608 48.455373-53.222583 48.455373z m394.899259 314.114707H637.125954V554.711376c0-37.815157-15.457597-63.618091-49.496664-63.61809-26.03126 0-40.488521 17.410146-47.233878 34.204937-2.518758 6.013279-2.133777 14.405043-2.133777 22.820356v151.06916h-98.001184s1.273713-255.921161 0-279.188955h98.001184v43.815125c5.794167-19.157918 37.097413-46.5018 87.093733-46.5018 61.986018 0 110.696338 40.168045 110.696338 126.630041v155.246613z', - fill: '#FFFFFF', - }), - ]) -LinkedinIcon.displayName = 'LinkedinIcon' diff --git a/packages/theme/src/client/composables/archive.ts b/packages/theme/src/client/composables/archive.ts deleted file mode 100644 index 28d657eb..00000000 --- a/packages/theme/src/client/composables/archive.ts +++ /dev/null @@ -1,42 +0,0 @@ -import { ref } from 'vue' -import type { Ref } from 'vue' -import { usePostAllIndex } from './postIndex.js' - -export interface ArchiveItem { - year: string - children: ArchiveChild[] -} - -export interface ArchiveChild { - date: string - text: string - link: string -} - -export type ArchiveData = ArchiveItem[] - -export type ArchiveListRef = Ref<ArchiveData> - -export const useArchive = (): ArchiveListRef => { - let archiveList: ArchiveData = [] - const postList = usePostAllIndex().value - postList.forEach((post) => { - const [year, month, day] = post.createTime.split('-') - let current = archiveList.find((arch) => arch.year === year) - if (!current) { - current = { year, children: [] } - archiveList.push(current) - } - current.children.push({ - date: `${month}-${day}`, - text: post.title, - link: post.path, - }) - }) - - archiveList = archiveList.sort((left, right) => { - return left.year > right.year ? -1 : 1 - }) - - return ref(archiveList) -} diff --git a/packages/theme/src/client/composables/aside.ts b/packages/theme/src/client/composables/aside.ts new file mode 100644 index 00000000..9e8ea367 --- /dev/null +++ b/packages/theme/src/client/composables/aside.ts @@ -0,0 +1,140 @@ +import { useMediaQuery } from '@vueuse/core' +import type { Ref } from 'vue' +import { computed, onMounted, onUnmounted, onUpdated } from 'vue' +import { throttleAndDebounce } from '../utils/index.js' +import { useSidebar } from './sidebar.js' + +const PAGE_OFFSET = 71 + +export function useAside() { + const { hasSidebar } = useSidebar() + const is960 = useMediaQuery('(min-width: 960px)') + const is1280 = useMediaQuery('(min-width: 1280px)') + + const isAsideEnabled = computed(() => { + if (!is1280.value && !is960.value) { + return false + } + + return hasSidebar.value ? is1280.value : is960.value + }) + + return { + isAsideEnabled, + } +} + +export function useActiveAnchor( + container: Ref<HTMLElement>, + marker: Ref<HTMLElement> +) { + const { isAsideEnabled } = useAside() + + const onScroll = throttleAndDebounce(setActiveLink, 100) + + let prevActiveLink: HTMLAnchorElement | null = null + + onMounted(() => { + requestAnimationFrame(setActiveLink) + window.addEventListener('scroll', onScroll) + }) + + onUpdated(() => { + // sidebar update means a route change + activateLink(location.hash) + }) + + onUnmounted(() => { + window.removeEventListener('scroll', onScroll) + }) + + function setActiveLink() { + if (!isAsideEnabled.value) { + return + } + + const links = [].slice.call( + container.value.querySelectorAll('.outline-link') + ) as HTMLAnchorElement[] + + const anchors = [].slice + .call(document.querySelectorAll('.content .header-anchor')) + .filter((anchor: HTMLAnchorElement) => { + return links.some((link) => { + return link.hash === anchor.hash && anchor.offsetParent !== null + }) + }) as HTMLAnchorElement[] + + const scrollY = window.scrollY + const innerHeight = window.innerHeight + const offsetHeight = document.body.offsetHeight + const isBottom = Math.abs(scrollY + innerHeight - offsetHeight) < 1 + + // page bottom - highlight last one + if (anchors.length && isBottom) { + activateLink(anchors[anchors.length - 1].hash) + return + } + + for (let i = 0; i < anchors.length; i++) { + const anchor = anchors[i] + const nextAnchor = anchors[i + 1] + + const [isActive, hash] = isAnchorActive(i, anchor, nextAnchor) + + if (isActive) { + activateLink(hash) + return + } + } + } + + function activateLink(hash: string | null) { + if (prevActiveLink) { + prevActiveLink.classList.remove('active') + } + + if (hash !== null) { + prevActiveLink = container.value.querySelector( + `a[href="${decodeURIComponent(hash)}"]` + ) + } + + const activeLink = prevActiveLink + + if (activeLink) { + activeLink.classList.add('active') + marker.value.style.top = activeLink.offsetTop + 33 + 'px' + marker.value.style.opacity = '1' + } else { + marker.value.style.top = '33px' + marker.value.style.opacity = '0' + } + } +} + +function getAnchorTop(anchor: HTMLAnchorElement): number { + return anchor.parentElement!.offsetTop - PAGE_OFFSET +} + +function isAnchorActive( + index: number, + anchor: HTMLAnchorElement, + nextAnchor: HTMLAnchorElement | undefined +): [boolean, string | null] { + const scrollTop = window.scrollY + + if (index === 0 && scrollTop === 0) { + return [true, null] + } + + if (scrollTop < getAnchorTop(anchor)) { + return [false, null] + } + + if (!nextAnchor || scrollTop < getAnchorTop(nextAnchor)) { + return [true, anchor.hash] + } + + return [false, null] +} diff --git a/packages/theme/src/client/composables/asideNavbar.ts b/packages/theme/src/client/composables/asideNavbar.ts deleted file mode 100644 index 368e9d65..00000000 --- a/packages/theme/src/client/composables/asideNavbar.ts +++ /dev/null @@ -1,23 +0,0 @@ -import type { Ref } from 'vue' -import { ref } from 'vue' - -const asideNavbarShow = ref<boolean>(false) - -const triggerAsideNavbar = (show?: boolean): void => { - if (typeof show === 'boolean') { - asideNavbarShow.value = show - } else { - asideNavbarShow.value = !asideNavbarShow.value - } -} - -interface UseAsideNavbar { - asideNavbarShow: Ref<boolean> - triggerAsideNavbar: (show?: boolean) => void -} -export const useAsideNavbar = (): UseAsideNavbar => { - return { - asideNavbarShow, - triggerAsideNavbar, - } -} diff --git a/packages/theme/src/client/composables/blogger.ts b/packages/theme/src/client/composables/blogger.ts deleted file mode 100644 index e69de29b..00000000 diff --git a/packages/theme/src/client/composables/category.ts b/packages/theme/src/client/composables/category.ts deleted file mode 100644 index bc5e3fa4..00000000 --- a/packages/theme/src/client/composables/category.ts +++ /dev/null @@ -1,89 +0,0 @@ -import { ref } from 'vue' -import type { Ref } from 'vue' -import type { PostItem } from '../../shared/index.js' -import { usePostIndex } from './postIndex.js' - -export interface CategoryItem { - label: string - type: string | number - children: CategoryList - postList: PostItem[] -} - -export type CategoryList = CategoryItem[] - -export type CategoryListRef = Ref<CategoryList> - -export const useCategoryList = (): CategoryListRef => { - let categoryListRaw: CategoryList = [] - usePostIndex().value.forEach((post: PostItem) => { - if (post.category.length === 0) return - const category = post.category.map((cate, index) => { - if (index > 0) { - return { - type: post.category - .slice(0, index + 1) - .map((c) => c.type) - .join('-'), - name: cate.name, - } - } else { - return cate - } - }) - let index = 1 - let cate = category[0] - let first = categoryListRaw.find((c) => c.type === cate.type) - if (!first) { - first = { - label: cate.name, - type: cate.type, - children: [], - postList: [], - } - categoryListRaw.push(first) - } - - if (category.length === 1) { - first.postList.push(post) - } - let children = first.children - while ((cate = category[index])) { - let current = children.find((c) => c.type === cate.type) - if (!current) { - current = { - label: cate.name, - type: cate.type, - children: [], - postList: [], - } - children.push(current) - } - children = current.children - if (index === category.length - 1) { - current.postList.push(post) - } - index++ - } - }) - categoryListRaw = categorySort(categoryListRaw) - sortChildren(categoryListRaw, 1) - function sortChildren(list: CategoryList, deep: number): void { - list.forEach((category) => { - if (category.children.length > 0) { - category.children = categorySort(category.children, deep) - sortChildren(category.children, deep + 1) - } - }) - } - - return ref(categoryListRaw) -} - -function categorySort(children: CategoryList, deep = 0): CategoryList { - return children.sort((left, right) => { - const leftType = Number((left.type + '').split('-')[deep]) - const rightType = Number((right.type + '').split('-')[deep]) - return leftType > rightType ? 1 : -1 - }) -} diff --git a/packages/theme/src/client/composables/darkMode.ts b/packages/theme/src/client/composables/darkMode.ts index 789c03aa..4a190911 100644 --- a/packages/theme/src/client/composables/darkMode.ts +++ b/packages/theme/src/client/composables/darkMode.ts @@ -1,7 +1,5 @@ -import { usePreferredDark, useStorage } from '@vueuse/core' -import { computed, inject, onMounted, onUnmounted, provide, watch } from 'vue' +import { inject, provide, ref } from 'vue' import type { InjectionKey, WritableComputedRef } from 'vue' -import { useThemeLocaleData } from './themeData.js' export type DarkModeRef = WritableComputedRef<boolean> @@ -9,48 +7,21 @@ export const darkModeSymbol: InjectionKey<DarkModeRef> = Symbol( __VUEPRESS_DEV__ ? 'darkMode' : '' ) +/** + * Inject dark mode global computed + */ export const useDarkMode = (): DarkModeRef => { - const isDarkMode = inject(darkModeSymbol) - if (!isDarkMode) { - throw new Error('useDarkMode() is called without provider') + const isDark = inject(darkModeSymbol) + if (isDark === undefined) { + throw new Error('useDarkMode() is called without provider.') } - return isDarkMode + return isDark } +/** + * Create dark mode ref and provide as global computed in setup + */ export const setupDarkMode = (): void => { - const themeLocale = useThemeLocaleData() - const isDarkPreferred = usePreferredDark() - const darkStorage = useStorage('vuepress-color-scheme', 'auto') - - const isDarkMode = computed<boolean>({ - get() { - if (!themeLocale.value.darkMode) { - return false - } - if (darkStorage.value === 'auto') { - return isDarkPreferred.value - } - return darkStorage.value === 'dark' - }, - set(val) { - if (val === isDarkPreferred.value) { - darkStorage.value = 'auto' - } else { - darkStorage.value = val ? 'dark' : 'light' - } - }, - }) - provide(darkModeSymbol, isDarkMode) - updateHtmlDarkClass(isDarkMode) -} - -export const updateHtmlDarkClass = (isDarkMode: DarkModeRef): void => { - const update = (value = isDarkMode.value): void => { - const htmlEl = window?.document.querySelector('html') - htmlEl?.classList.toggle('dark', value) - } - onMounted(() => { - watch(isDarkMode, update, { immediate: true }) - }) - onUnmounted(() => update()) + const isDark = ref<boolean>(false) + provide(darkModeSymbol, isDark) } diff --git a/packages/theme/src/client/composables/flyout.ts b/packages/theme/src/client/composables/flyout.ts new file mode 100644 index 00000000..cecc2520 --- /dev/null +++ b/packages/theme/src/client/composables/flyout.ts @@ -0,0 +1,59 @@ +import { onUnmounted, readonly, ref, type Ref, watch } from 'vue' +import { inBrowser } from '../utils/index.js' + +interface UseFlyoutOptions { + el: Ref<HTMLElement | undefined> + onFocus?(): void + onBlur?(): void +} + +export const focusedElement = ref<HTMLElement>() + +let active = false +let listeners = 0 + +export function useFlyout(options: UseFlyoutOptions) { + const focus = ref(false) + + if (inBrowser) { + !active && activateFocusTracking() + + listeners++ + + const unwatch = watch(focusedElement, (el) => { + if (el === options.el.value || options.el.value?.contains(el!)) { + focus.value = true + options.onFocus?.() + } else { + focus.value = false + options.onBlur?.() + } + }) + + onUnmounted(() => { + unwatch() + + listeners-- + + if (!listeners) { + deactivateFocusTracking() + } + }) + } + + return readonly(focus) +} + +function activateFocusTracking() { + document.addEventListener('focusin', handleFocusIn) + active = true + focusedElement.value = document.activeElement as HTMLElement +} + +function deactivateFocusTracking() { + document.removeEventListener('focusin', handleFocusIn) +} + +function handleFocusIn() { + focusedElement.value = document.activeElement as HTMLElement +} diff --git a/packages/theme/src/client/composables/index.ts b/packages/theme/src/client/composables/index.ts index e831b794..124f8dbe 100644 --- a/packages/theme/src/client/composables/index.ts +++ b/packages/theme/src/client/composables/index.ts @@ -1,16 +1,6 @@ -export * from './themeData.js' export * from './darkMode.js' -export * from './navbar.js' -export * from './navLink.js' -export * from './resolveRouteWithRedirect.js' - -export * from './postIndex.js' -export * from './sidebarIndex.js' -export * from './postList.js' -export * from './scrollPromise.js' -export * from './asideNavbar.js' -export * from './postStat.js' - -export * from './tag.js' -export * from './category.js' -export * from './archive.js' +export * from './useScrollPromise.js' +export * from './themeData.js' +export * from './useResolveRouteWithRedirect.js' +export * from './sidebar.js' +export * from './aside.js' diff --git a/packages/theme/src/client/composables/nav.ts b/packages/theme/src/client/composables/nav.ts new file mode 100644 index 00000000..1fe0244f --- /dev/null +++ b/packages/theme/src/client/composables/nav.ts @@ -0,0 +1,45 @@ +import type { Ref } from 'vue' +import { ref, watch } from 'vue' +import { useRoute } from 'vue-router' + +export interface UseNavReturn { + isScreenOpen: Ref<boolean> + openScreen: () => void + closeScreen: () => void + toggleScreen: () => void +} + +export function useNav(): UseNavReturn { + const isScreenOpen = ref(false) + + function openScreen(): void { + isScreenOpen.value = true + window.addEventListener('resize', closeScreenOnTabletWindow) + } + + function closeScreen(): void { + isScreenOpen.value = false + window.removeEventListener('resize', closeScreenOnTabletWindow) + } + + function toggleScreen(): void { + isScreenOpen.value ? closeScreen() : openScreen() + } + + /** + * Close screen when the user resizes the window wider than tablet size. + */ + function closeScreenOnTabletWindow(): void { + window.outerWidth >= 768 && closeScreen() + } + + const route = useRoute() + watch(() => route.path, closeScreen) + + return { + isScreenOpen, + openScreen, + closeScreen, + toggleScreen, + } +} diff --git a/packages/theme/src/client/composables/navLink.ts b/packages/theme/src/client/composables/navLink.ts deleted file mode 100644 index b467fe9c..00000000 --- a/packages/theme/src/client/composables/navLink.ts +++ /dev/null @@ -1,16 +0,0 @@ -import type { NavLink } from '../../shared/index.js' -import { useResolveRouteWithRedirect } from './resolveRouteWithRedirect.js' - -declare module 'vue-router' { - interface RouteMeta { - title?: string - } -} - -export const useNavLink = (item: string): NavLink => { - const resolved = useResolveRouteWithRedirect(item) - return { - text: resolved.meta.title || item, - link: resolved.name === '404' ? item : resolved.fullPath, - } -} diff --git a/packages/theme/src/client/composables/navbar.ts b/packages/theme/src/client/composables/navbar.ts deleted file mode 100644 index 8fbc0d8d..00000000 --- a/packages/theme/src/client/composables/navbar.ts +++ /dev/null @@ -1,128 +0,0 @@ -import { useRouteLocale, useSiteLocaleData } from '@vuepress/client' -import { isLinkHttp, isString } from '@vuepress/shared' -import type { ComputedRef } from 'vue' -import { computed } from 'vue' -import { useRouter } from 'vue-router' -import type { - NavbarGroup, - NavbarItem, - NavLink, - ResolveNavbarItem, -} from '../../shared/index.js' -import { resolveRepoType } from '../utils/index.js' -import { useNavLink } from './navLink.js' -import { useThemeLocaleData } from './themeData.js' - -export const useNavbarSelectLanguage = (): ComputedRef<ResolveNavbarItem[]> => { - const router = useRouter() - const routeLocale = useRouteLocale() - const siteLocale = useSiteLocaleData() - const themeLocale = useThemeLocaleData() - - return computed<ResolveNavbarItem[]>(() => { - const localePaths = Object.keys(siteLocale.value.locales) - if (localePaths.length < 2) { - return [] - } - - const currentPath = router.currentRoute.value.path - const currentFullPath = router.currentRoute.value.fullPath - - const languageDropdown: ResolveNavbarItem = { - text: themeLocale.value.selectLanguageText ?? 'unknown language', - ariaLabel: - themeLocale.value.selectLanguageAriaLabel ?? 'unknown language', - children: localePaths.map((targetLocalPath) => { - const targetSiteLocale = - siteLocale.value.locales?.[targetLocalPath] ?? {} - const targetThemeLocale = - themeLocale.value.locales?.[targetLocalPath] ?? {} - const targetLang = `${targetSiteLocale.lang}` - - const text = targetThemeLocale.selectLanguageName ?? targetLang - let link: string - - if (targetLang === siteLocale.value.lang) { - link = currentFullPath - } else { - const targetLocalePage = currentPath.replace( - routeLocale.value, - targetLocalPath - ) - if ( - router.getRoutes().some((item) => item.path === targetLocalPath) - ) { - link = targetLocalePage - } else { - link = (targetThemeLocale.home as NavLink)?.link ?? targetLocalPath - } - } - return { text, link } - }), - } - return [languageDropdown] - }) -} - -export const useNavbarRepo = (): ComputedRef<ResolveNavbarItem[]> => { - const themeLocale = useThemeLocaleData() - - const repo = computed(() => themeLocale.value.repo) - const repoType = computed(() => { - return repo.value ? resolveRepoType(repo.value) : null - }) - - const repoLink = computed(() => { - if (repo.value && !isLinkHttp(repo.value)) { - return `https://github.com/${repo.value}` - } - return repo.value - }) - - const repoLabel = computed(() => { - if (!repoLink.value) return null - if (themeLocale.value.repoLabel) return themeLocale.value.repoLabel - if (repoType.value === null) return 'Source' - return repoType.value - }) - - return computed(() => { - if (!repoLink.value || !repoLabel.value) { - return [] - } - return [ - { - text: repoLabel.value, - link: repoLink.value, - }, - ] - }) -} - -const resolveNavbarItem = ( - item: NavbarItem | NavbarGroup | string -): ResolveNavbarItem => { - if (isString(item)) { - return useNavLink(item) - } - if ((item as NavbarGroup).children) { - return { - ...item, - children: (item as NavbarGroup).children.map(resolveNavbarItem), - } - } - return item as ResolveNavbarItem -} - -export const useNavbarConfig = (): ComputedRef<ResolveNavbarItem[]> => { - const themeLocale = useThemeLocaleData() - const { navbar, home, category, archive, tag } = themeLocale.value - const config: NavbarItem[] = [ - home as NavbarItem, - ...((navbar || []) as unknown as NavbarItem[]), - category as NavbarItem, - tag as NavbarItem, - archive as NavbarItem, - ].filter((nav) => nav) - return computed(() => config.map(resolveNavbarItem)) -} diff --git a/packages/theme/src/client/composables/postIndex.ts b/packages/theme/src/client/composables/postIndex.ts deleted file mode 100644 index de48b271..00000000 --- a/packages/theme/src/client/composables/postIndex.ts +++ /dev/null @@ -1,47 +0,0 @@ -import { postIndex as postIndexRaw } from '@internal/postIndex' -import { ref } from 'vue' -import type { Ref } from 'vue' -import type { PostIndex } from '../../shared/index.js' - -const isBoolean = (arg: unknown): boolean => { - return typeof arg === 'boolean' -} - -export type PostIndexRef = Ref<PostIndex> - -export const postIndex: PostIndexRef = ref(postIndexRaw) - -export const usePostAllIndex = (): PostIndexRef => postIndex - -// 在首页文章列表的,默认排除掉 note中的文章,除非显示声明 article -export const usePostIndex = (): PostIndexRef => { - const postIndexData = [ - ...postIndex.value - .filter((post) => post.sticky) - .sort((left, right) => { - const leftSticky = isBoolean(left.sticky) ? 1 : (left.sticky as number) - const rightSticky = isBoolean(right.sticky) - ? 1 - : (right.sticky as number) - return leftSticky < rightSticky ? 1 : -1 - }), - ...postIndex.value.filter((post) => !post.sticky), - ] - const postList = postIndexData.filter((post) => { - if (post.isNote) { - return post.article === true - } else { - return post.article !== false - } - }) - return ref(postList) -} - -export type PostTotalRef = Ref<number> -export const postTotal: PostTotalRef = ref(0) - -if (import.meta.hot) { - __VUE_HMR_RUNTIME__.updatePostIndex = (data: PostIndex) => { - postIndex.value = data - } -} diff --git a/packages/theme/src/client/composables/postList.ts b/packages/theme/src/client/composables/postList.ts deleted file mode 100644 index 7bc8c4d0..00000000 --- a/packages/theme/src/client/composables/postList.ts +++ /dev/null @@ -1,45 +0,0 @@ -import type { Ref } from 'vue' -import { ref } from 'vue' -import type { PostItem } from '../../shared/index.js' -import { usePostIndex } from './postIndex.js' - -export type PostListData = PostItem[] -export type PostListRef = Ref<PostListData> - -interface UsePostList { - postList: PostListRef - total: Ref<number> - page: Ref<number> - setPostListPage: (page: number) => void - resetPostIndex: (postIndex: PostListData) => void -} - -export const usePostList = (): UsePostList => { - const postIndex = ref(usePostIndex().value) - const pageNum = 10 - const total = ref(postIndex.value.length) - let totalPage = Math.ceil(postIndex.value.length / pageNum) - const postList = ref<PostListData>([]) - const page = ref(1) - - const setPostListPage = (_page = 1): void => { - _page = _page - 1 - if (_page < 0) _page = 0 - if (_page > totalPage) _page = totalPage - 1 - const start = _page * pageNum - const end = start + pageNum - postList.value = postIndex.value.filter((_: PostItem, index: number) => { - return start <= index && index < end - }) - page.value = _page + 1 - } - const resetPostIndex = (_postIndex: PostListData): void => { - postIndex.value = _postIndex - totalPage = Math.ceil(postIndex.value.length / pageNum) - total.value = postIndex.value.length - setPostListPage(1) - } - setPostListPage(1) - - return { postList, setPostListPage, page, total, resetPostIndex } -} diff --git a/packages/theme/src/client/composables/postStat.ts b/packages/theme/src/client/composables/postStat.ts deleted file mode 100644 index 888c87db..00000000 --- a/packages/theme/src/client/composables/postStat.ts +++ /dev/null @@ -1,31 +0,0 @@ -import { reactive } from 'vue' -import { usePostAllIndex } from './postIndex.js' -import { useTagList } from './tag.js' - -export interface PostStatData { - postTotal: number - tagTotal: number - categoryTotal: number -} - -export const usePostStat = (): PostStatData => { - const data: PostStatData = Object.create(null) - - const postIndex = usePostAllIndex() - const tagList = useTagList() - - data.postTotal = postIndex.value.length - data.tagTotal = tagList.value.length - - const categorySet = new Set() - - postIndex.value.forEach((post) => { - const category = post.category || [] - category.forEach((cate) => categorySet.add(cate.name)) - }) - - data.categoryTotal = categorySet.size - - const stat = reactive<PostStatData>(data) - return stat -} diff --git a/packages/theme/src/client/composables/sidebar.ts b/packages/theme/src/client/composables/sidebar.ts new file mode 100644 index 00000000..12dbc467 --- /dev/null +++ b/packages/theme/src/client/composables/sidebar.ts @@ -0,0 +1,208 @@ +import type { + NotesData, + NotesSidebarItem, +} from '@vuepress-plume/vuepress-plugin-notes-data' +import { useNotesData } from '@vuepress-plume/vuepress-plugin-notes-data/client' +import type { PageData } from '@vuepress/client' +import { usePageData, usePageFrontmatter, withBase } from '@vuepress/client' +import { useMediaQuery } from '@vueuse/core' +import type { ComputedRef, Ref } from 'vue' +import { computed, onMounted, onUnmounted, ref, watchEffect } from 'vue' +import { useRoute } from 'vue-router' +import type { PlumeThemePageData } from '../../shared/index.js' +import { isActive } from '../utils/index.js' +import { useThemeLocaleData } from './themeData.js' + +export function getSidebarList(path: string, notesData: NotesData) { + const link = Object.keys(notesData).find((link) => + path.startsWith(withBase(link)) + ) + return link ? notesData[link] : [] +} + +export function useSidebar() { + const route = useRoute() + const notesData = useNotesData() + const theme = useThemeLocaleData() + const frontmatter = usePageFrontmatter() + const page = usePageData<PlumeThemePageData>() + + const is960 = useMediaQuery('(min-width: 960px)') + + const isOpen = ref(false) + + const sidebar = computed(() => { + return theme.value.notes ? getSidebarList(route.path, notesData.value) : [] + }) + const hasSidebar = computed(() => { + return ( + !frontmatter.value.home && + !page.value.isBlogPost && + sidebar.value.length > 0 + ) + }) + + const hasAside = computed(() => { + return !frontmatter.value.home && frontmatter.value.aside !== false + }) + + const isSidebarEnabled = computed(() => hasSidebar.value && is960.value) + + const sidebarGroups = computed(() => { + return hasSidebar.value ? getSidebarGroups(sidebar.value) : [] + }) + + function open() { + isOpen.value = true + } + + function close() { + isOpen.value = false + } + + function toggle() { + isOpen.value ? close() : open() + } + + return { + isOpen, + sidebar, + hasSidebar, + hasAside, + isSidebarEnabled, + sidebarGroups, + open, + close, + toggle, + } +} + +export function useCloseSidebarOnEscape( + isOpen: Ref<boolean>, + close: () => void +) { + let triggerElement: HTMLButtonElement | undefined + + watchEffect(() => { + triggerElement = isOpen.value + ? (document.activeElement as HTMLButtonElement) + : undefined + }) + + onMounted(() => { + window.addEventListener('keyup', onEscape) + }) + + onUnmounted(() => { + window.removeEventListener('keyup', onEscape) + }) + + function onEscape(e: KeyboardEvent) { + if (e.key === 'Escape' && isOpen.value) { + close() + triggerElement?.focus() + } + } +} + +export function useSidebarControl(item: ComputedRef<NotesSidebarItem>) { + const page = usePageData<PageData>() + + const collapsed = ref(false) + + const collapsible = computed(() => { + return item.value.collapsed != null + }) + + const isLink = computed(() => { + return !!item.value.link + }) + + const isActiveLink = computed(() => { + return isActive(page.value.path, item.value.link) + }) + + const hasActiveLink = computed(() => { + if (isActiveLink.value) { + return true + } + + return item.value.items + ? containsActiveLink( + page.value.path, + item.value.items as NotesSidebarItem[] + ) + : false + }) + + const hasChildren = computed(() => { + return !!(item.value.items && item.value.items.length) + }) + + watchEffect(() => { + collapsed.value = !!(collapsible.value && item.value.collapsed) + }) + + watchEffect(() => { + ;(isActiveLink.value || hasActiveLink.value) && (collapsed.value = false) + }) + + function toggle() { + if (collapsible.value) { + collapsed.value = !collapsed.value + } + } + + return { + collapsed, + collapsible, + isLink, + isActiveLink, + hasActiveLink, + hasChildren, + toggle, + } +} + +export function containsActiveLink( + path: string, + items: NotesSidebarItem | NotesSidebarItem[] +): boolean { + if (Array.isArray(items)) { + return items.some((item) => containsActiveLink(path, item)) + } + + return isActive(path, items.link) + ? true + : items.items + ? containsActiveLink(path, items.items as NotesSidebarItem[]) + : false +} + +/** + * Get or generate sidebar group from the given sidebar items. + */ +export function getSidebarGroups( + sidebar: NotesSidebarItem[] +): NotesSidebarItem[] { + const groups: NotesSidebarItem[] = [] + + let lastGroupIndex = 0 + + for (const index in sidebar) { + const item = sidebar[index] + + if (item.items) { + lastGroupIndex = groups.push(item) + continue + } + + if (!groups[lastGroupIndex]) { + groups.push({ items: [] }) + } + + groups[lastGroupIndex]!.items!.push(item) + } + + return groups +} diff --git a/packages/theme/src/client/composables/sidebarIndex.ts b/packages/theme/src/client/composables/sidebarIndex.ts deleted file mode 100644 index 172157fb..00000000 --- a/packages/theme/src/client/composables/sidebarIndex.ts +++ /dev/null @@ -1,49 +0,0 @@ -import { sidebarIndex as sidebarIndexRaw } from '@internal/sidebarIndex' -import { usePageFrontmatter } from '@vuepress/client' -import { computed, ref } from 'vue' -import type { ComputedRef, Ref } from 'vue' -import { useRoute } from 'vue-router' -import type { SidebarOptions } from '../../shared/index.js' -import { useThemeLocaleData } from './themeData.js' - -export type SidebarIndexRef = Ref<Record<string, SidebarOptions>> - -export type SidebarRef = ComputedRef<SidebarOptions> - -export const sidebarIndex: SidebarIndexRef = ref(sidebarIndexRaw) - -interface UseSidebarIndex { - sidebarList: SidebarRef - hasSidebar: ComputedRef<boolean> -} - -export const useSidebarIndex = (): UseSidebarIndex => { - // const sidebarList: SidebarRef = ref([]) - const themeLocale = useThemeLocaleData() - const route = useRoute() - const frontmatter = usePageFrontmatter() - const sidebarList = computed(() => { - const notes = themeLocale.value.notes - if (!notes) return [] - const prefix = notes.link?.replace(/^\/|\/$/g, '') - if (route.path.startsWith(`/${prefix}`)) { - const key = Object.keys(sidebarIndex.value).find((key) => - route.path.startsWith(key) - ) - if (key) return sidebarIndex.value[key] - } - return [] - }) - const hasSidebar = computed(() => { - return !frontmatter.value.home && sidebarList.value.length > 0 - }) - return { sidebarList, hasSidebar } -} - -if (import.meta.hot) { - __VUE_HMR_RUNTIME__.updateSidebarIndex = ( - data: Record<string, SidebarOptions> - ) => { - sidebarIndex.value = data - } -} diff --git a/packages/theme/src/client/composables/tag.ts b/packages/theme/src/client/composables/tag.ts deleted file mode 100644 index 53c4457e..00000000 --- a/packages/theme/src/client/composables/tag.ts +++ /dev/null @@ -1,25 +0,0 @@ -import type { Ref } from 'vue' -import { ref } from 'vue' -import { getColor } from '../utils/index.js' -import { usePostAllIndex } from './postIndex.js' - -export interface TagItem { - tag: string - color: string -} -export type TagRaw = TagItem[] - -export type TagRef = Ref<TagRaw> - -export const tagList: TagRef = ref([]) - -export const useTagList = (): TagRef => { - const postList = usePostAllIndex().value - let list: string[] = [] - postList.forEach((post) => { - list.push(...post.tags) - }) - list = Array.from(new Set(list)) - tagList.value = list.map((tag) => ({ tag, color: getColor() })) - return tagList -} diff --git a/packages/theme/src/client/composables/themeData.ts b/packages/theme/src/client/composables/themeData.ts index 829d968b..59e41440 100644 --- a/packages/theme/src/client/composables/themeData.ts +++ b/packages/theme/src/client/composables/themeData.ts @@ -10,6 +10,5 @@ import type { PlumeThemeData } from '../../shared/index.js' export const useThemeData = (): ThemeDataRef<PlumeThemeData> => _useThemeData<PlumeThemeData>() - export const useThemeLocaleData = (): ThemeLocaleDataRef<PlumeThemeData> => _useThemeLocaleData<PlumeThemeData>() diff --git a/packages/theme/src/client/composables/resolveRouteWithRedirect.ts b/packages/theme/src/client/composables/useResolveRouteWithRedirect.ts similarity index 69% rename from packages/theme/src/client/composables/resolveRouteWithRedirect.ts rename to packages/theme/src/client/composables/useResolveRouteWithRedirect.ts index b807a9c4..297b0e95 100644 --- a/packages/theme/src/client/composables/resolveRouteWithRedirect.ts +++ b/packages/theme/src/client/composables/useResolveRouteWithRedirect.ts @@ -1,7 +1,10 @@ import { isFunction, isString } from '@vuepress/shared' -import type { Router } from 'vue-router' import { useRouter } from 'vue-router' +import type { Router } from 'vue-router' +/** + * Resolve a route with redirection + */ export const useResolveRouteWithRedirect = ( ...args: Parameters<Router['resolve']> ): ReturnType<Router['resolve']> => { @@ -12,15 +15,14 @@ export const useResolveRouteWithRedirect = ( return route } const { redirect } = lastMatched - const resolveRedirect = isFunction(redirect) ? redirect(route) : redirect - const resolveRedirectObj = isString(resolveRedirect) - ? { path: resolveRedirect } - : resolveRedirect - + const resolvedRedirect = isFunction(redirect) ? redirect(route) : redirect + const resolvedRedirectObj = isString(resolvedRedirect) + ? { path: resolvedRedirect } + : resolvedRedirect return useResolveRouteWithRedirect({ hash: route.hash, query: route.query, params: route.params, - ...resolveRedirectObj, + ...resolvedRedirectObj, }) } diff --git a/packages/theme/src/client/composables/scrollPromise.ts b/packages/theme/src/client/composables/useScrollPromise.ts similarity index 99% rename from packages/theme/src/client/composables/scrollPromise.ts rename to packages/theme/src/client/composables/useScrollPromise.ts index aecad269..0405f8c7 100644 --- a/packages/theme/src/client/composables/scrollPromise.ts +++ b/packages/theme/src/client/composables/useScrollPromise.ts @@ -3,6 +3,7 @@ export interface ScrollPromise { pending: () => void resolve: () => void } + let promise: Promise<void> | null = null let promiseResolve: (() => void) | null = null diff --git a/packages/theme/src/client/config.ts b/packages/theme/src/client/config.ts index bcfd07eb..b9739d8a 100644 --- a/packages/theme/src/client/config.ts +++ b/packages/theme/src/client/config.ts @@ -1,19 +1,15 @@ import { defineClientConfig } from '@vuepress/client' import { h } from 'vue' -import Badge from './components/global/Badge.vue' -import { setupDarkMode, useScrollPromise } from './composables/index.js' -import NotFound from './layouts/404.vue' +import { setupDarkMode } from './composables/index.js' import Layout from './layouts/Layout.vue' +import NotFound from './layouts/NotFound.vue' import './styles/index.scss' export default defineClientConfig({ - enhance({ app, router }) { + enhance({ app }) { // eslint-disable-next-line vue/match-component-file-name - app.component('Badge', Badge) - - // eslint-disable-next-line vue/match-component-file-name - app.component('NavbarSearch', () => { + app.component('DocSearch', () => { const SearchComponent = app.component('Docsearch') || app.component('SearchBox') if (SearchComponent) { @@ -21,20 +17,15 @@ export default defineClientConfig({ } return null }) + // eslint-disable-next-line vue/match-component-file-name - app.component('Comment', (props) => { + app.component('PageComment', (props) => { const CommentService = app.component('CommentService') if (CommentService) { return h(CommentService, props) } return null }) - - const scrollBehavior = router.options.scrollBehavior! - router.options.scrollBehavior = async (...args) => { - await useScrollPromise().wait() - return scrollBehavior(...args) - } }, setup() { setupDarkMode() diff --git a/packages/theme/src/client/fonts/inter-italic-cyrillic-ext.woff2 b/packages/theme/src/client/fonts/inter-italic-cyrillic-ext.woff2 new file mode 100644 index 00000000..2a687296 Binary files /dev/null and b/packages/theme/src/client/fonts/inter-italic-cyrillic-ext.woff2 differ diff --git a/packages/theme/src/client/fonts/inter-italic-cyrillic.woff2 b/packages/theme/src/client/fonts/inter-italic-cyrillic.woff2 new file mode 100644 index 00000000..f6403515 Binary files /dev/null and b/packages/theme/src/client/fonts/inter-italic-cyrillic.woff2 differ diff --git a/packages/theme/src/client/fonts/inter-italic-greek-ext.woff2 b/packages/theme/src/client/fonts/inter-italic-greek-ext.woff2 new file mode 100644 index 00000000..00218960 Binary files /dev/null and b/packages/theme/src/client/fonts/inter-italic-greek-ext.woff2 differ diff --git a/packages/theme/src/client/fonts/inter-italic-greek.woff2 b/packages/theme/src/client/fonts/inter-italic-greek.woff2 new file mode 100644 index 00000000..71c265f8 Binary files /dev/null and b/packages/theme/src/client/fonts/inter-italic-greek.woff2 differ diff --git a/packages/theme/src/client/fonts/inter-italic-latin-ext.woff2 b/packages/theme/src/client/fonts/inter-italic-latin-ext.woff2 new file mode 100644 index 00000000..9c1b9440 Binary files /dev/null and b/packages/theme/src/client/fonts/inter-italic-latin-ext.woff2 differ diff --git a/packages/theme/src/client/fonts/inter-italic-latin.woff2 b/packages/theme/src/client/fonts/inter-italic-latin.woff2 new file mode 100644 index 00000000..01fcf207 Binary files /dev/null and b/packages/theme/src/client/fonts/inter-italic-latin.woff2 differ diff --git a/packages/theme/src/client/fonts/inter-italic-vietnamese.woff2 b/packages/theme/src/client/fonts/inter-italic-vietnamese.woff2 new file mode 100644 index 00000000..e4f788ee Binary files /dev/null and b/packages/theme/src/client/fonts/inter-italic-vietnamese.woff2 differ diff --git a/packages/theme/src/client/fonts/inter-roman-cyrillic-ext.woff2 b/packages/theme/src/client/fonts/inter-roman-cyrillic-ext.woff2 new file mode 100644 index 00000000..28593ccb Binary files /dev/null and b/packages/theme/src/client/fonts/inter-roman-cyrillic-ext.woff2 differ diff --git a/packages/theme/src/client/fonts/inter-roman-cyrillic.woff2 b/packages/theme/src/client/fonts/inter-roman-cyrillic.woff2 new file mode 100644 index 00000000..a20adc16 Binary files /dev/null and b/packages/theme/src/client/fonts/inter-roman-cyrillic.woff2 differ diff --git a/packages/theme/src/client/fonts/inter-roman-greek-ext.woff2 b/packages/theme/src/client/fonts/inter-roman-greek-ext.woff2 new file mode 100644 index 00000000..e3b0be76 Binary files /dev/null and b/packages/theme/src/client/fonts/inter-roman-greek-ext.woff2 differ diff --git a/packages/theme/src/client/fonts/inter-roman-greek.woff2 b/packages/theme/src/client/fonts/inter-roman-greek.woff2 new file mode 100644 index 00000000..f790e047 Binary files /dev/null and b/packages/theme/src/client/fonts/inter-roman-greek.woff2 differ diff --git a/packages/theme/src/client/fonts/inter-roman-latin-ext.woff2 b/packages/theme/src/client/fonts/inter-roman-latin-ext.woff2 new file mode 100644 index 00000000..715bd903 Binary files /dev/null and b/packages/theme/src/client/fonts/inter-roman-latin-ext.woff2 differ diff --git a/packages/theme/src/client/fonts/inter-roman-latin.woff2 b/packages/theme/src/client/fonts/inter-roman-latin.woff2 new file mode 100644 index 00000000..a540b7af Binary files /dev/null and b/packages/theme/src/client/fonts/inter-roman-latin.woff2 differ diff --git a/packages/theme/src/client/fonts/inter-roman-vietnamese.woff2 b/packages/theme/src/client/fonts/inter-roman-vietnamese.woff2 new file mode 100644 index 00000000..5a9f9cb9 Binary files /dev/null and b/packages/theme/src/client/fonts/inter-roman-vietnamese.woff2 differ diff --git a/packages/theme/src/client/layouts/404.vue b/packages/theme/src/client/layouts/404.vue deleted file mode 100644 index 1224c780..00000000 --- a/packages/theme/src/client/layouts/404.vue +++ /dev/null @@ -1,33 +0,0 @@ -<script lang="ts" setup> -import { useRouteLocale } from '@vuepress/client' -import { useThemeLocaleData } from '../composables/index.js' - -const routeLocale = useRouteLocale() -const themeLocale = useThemeLocaleData() - -const message = themeLocale.value.notFound ?? ['Not Found'] -const getMsg = (): string => message[Math.floor(Math.random() * message.length)] -const homeLink = themeLocale.value.home - ? themeLocale.value.home.link - : routeLocale.value -const homeText = themeLocale.value.backToHome ?? 'Back to home' -</script> -<template> - <div class="theme-plume not-found"> - <div class="not-found-content"> - <blockquote>{{ getMsg() }}</blockquote> - - <RouterLink :to="homeLink">{{ homeText }}</RouterLink> - </div> - </div> -</template> - -<style lang="scss"> -.not-found { - width: 100%; - - &-content { - padding: 1.25rem; - } -} -</style> diff --git a/packages/theme/src/client/layouts/Layout.vue b/packages/theme/src/client/layouts/Layout.vue index 43fd14a8..04752342 100644 --- a/packages/theme/src/client/layouts/Layout.vue +++ b/packages/theme/src/client/layouts/Layout.vue @@ -1,70 +1,65 @@ <script setup lang="ts"> -import Archive from '@theme-plume/Archive.vue' -import AsideNavbar from '@theme-plume/AsideNavbar.vue' -import BackToTop from '@theme-plume/BackToTop.vue' -import Category from '@theme-plume/Category.vue' -import Home from '@theme-plume/Home.vue' -import Navbar from '@theme-plume/Navbar.vue' -import Page from '@theme-plume/Page.vue' -import PageFooter from '@theme-plume/PageFooter.vue' -import Tag from '@theme-plume/Tag.vue' -import { usePageFrontmatter } from '@vuepress/client' -import type { Component } from 'vue' -import { computed } from 'vue' -import { useThemeLocaleData } from '../composables/index.js' +import { usePageData } from '@vuepress/client' +import { provide, watch } from 'vue' +import { useRoute } from 'vue-router' +import type { PlumeThemePageData } from '../../shared/index.js' +import Backdrop from '../components/Backdrop.vue' +import Blog from '../components/Blog.vue' +import Home from '../components/Home.vue' +import LayoutContent from '../components/LayoutContent.vue' +import LocalNav from '../components/LocalNav.vue' +import Nav from '../components/Nav/index.vue' +import Page from '../components/Page.vue' +import Sidebar from '../components/Sidebar.vue' +import SkipLink from '../components/SkipLink.vue' +import VFooter from '../components/VFooter.vue' +import { + useCloseSidebarOnEscape, + useScrollPromise, + useSidebar, +} from '../composables/index.js' -const frontmatter = usePageFrontmatter() -const themeLocale = useThemeLocaleData() +const page = usePageData<PlumeThemePageData>() -const pageType = computed<string>(() => { - const matter = frontmatter.value - let type = '' - if (matter.home) { - type = 'home' - } else { - type = (frontmatter.value.pageType as string) || '' - } - return type -}) +const { + isOpen: isSidebarOpen, + open: openSidebar, + close: closeSidebar, +} = useSidebar() -const footer = computed(() => { - return themeLocale.value.footer -}) +const route = useRoute() +watch(() => route.path, closeSidebar) -const pageMap: Record<string, Component> = { - category: Category, - archive: Archive, - tag: Tag, - home: Home, -} +useCloseSidebarOnEscape(isSidebarOpen, closeSidebar) + +provide('close-sidebar', closeSidebar) +provide('is-sidebar-open', isSidebarOpen) + +// handle scrollBehavior with transition +const scrollPromise = useScrollPromise() +const onBeforeEnter = scrollPromise.resolve +const onBeforeLeave = scrollPromise.pending </script> <template> - <div class="plume-theme" :class="footer ? 'bottom' : ''"> - <slot name="navbar"> - <Navbar> - <template #before> - <slot name="navbar-before"></slot> - </template> - <template #after> - <slot name="navbar-after"></slot> - </template> - </Navbar> - </slot> - <AsideNavbar /> - <slot name="page"> - <Component :is="pageMap[pageType]" v-if="pageType" /> - <Page v-else> - <template #top> - <slot name="page-top" /> - </template> - <template #bottom> - <slot name="page-bottom" /> - </template> - </Page> - </slot> - <BackToTop /> - <slot name="footer"> - <PageFooter></PageFooter> - </slot> + <div class="theme-plume"> + <SkipLink /> + <Backdrop :show="isSidebarOpen" @click="closeSidebar" /> + <Nav /> + <LocalNav :open="isSidebarOpen" @open-menu="openSidebar" /> + <Sidebar :open="isSidebarOpen" /> + <LayoutContent> + <Home v-if="page.frontmatter.home" /> + <Blog v-else-if="page.type === 'blog'" /> + <Page v-else /> + <VFooter /> + </LayoutContent> </div> </template> + +<style scoped> +.theme-plume { + display: flex; + flex-direction: column; + min-height: 100vh; +} +</style> diff --git a/packages/theme/src/client/layouts/NotFound.vue b/packages/theme/src/client/layouts/NotFound.vue new file mode 100644 index 00000000..071571d2 --- /dev/null +++ b/packages/theme/src/client/layouts/NotFound.vue @@ -0,0 +1,3 @@ +<template> + <div>404</div> +</template> diff --git a/packages/theme/src/client/shim.d.ts b/packages/theme/src/client/shim.d.ts index 390043ae..91c813d9 100644 --- a/packages/theme/src/client/shim.d.ts +++ b/packages/theme/src/client/shim.d.ts @@ -4,18 +4,4 @@ declare module '*.vue' { export default comp } -declare const __VUEPRESS_DEV__: boolean -declare const __VUEPRESS_SSR__: boolean -declare const __VUE_HMR_RUNTIME__: Record<string, unknown> - -declare module '@internal/postIndex' { - import type { PostIndex } from '../shared' - const postIndex: PostIndex - export { postIndex } -} - -declare module '@internal/sidebarIndex' { - import type { SidebarOptions } from '../shared' - const sidebarIndex: Record<string, SidebarOptions> - export { sidebarIndex } -} +declare const __VUEPRESS_DEV__: string diff --git a/packages/theme/src/client/styles/_mixins.scss b/packages/theme/src/client/styles/_mixins.scss deleted file mode 100644 index 1d245dea..00000000 --- a/packages/theme/src/client/styles/_mixins.scss +++ /dev/null @@ -1,38 +0,0 @@ -@import '_variables'; - -@mixin content_wrapper { - max-width: var(--content-width); - margin: 0 auto; - padding: 2rem 2.5rem; - - @media (max-width: $MQNarrow) { - padding: 2rem; - } - - @media (max-width: $MQMobileNarrow) { - padding: 1.5rem; - } -} - -@mixin dropdown_wrapper { - transition: height 0.1s ease-out; - overflow: hidden; -} - -@mixin wrapper { - width: 100%; - padding-top: var(--navbar-height); -} - -@mixin container_wrapper { - width: 100%; - max-width: $containerWith; - margin: auto; -} - -@mixin content { - padding: 1.25rem; - background-color: var(--c-bg-container); - // border-radius: var(--p-around); - // box-shadow: var(--shadow); -} diff --git a/packages/theme/src/client/styles/_variables.scss b/packages/theme/src/client/styles/_variables.scss index 948203a9..f66580e6 100644 --- a/packages/theme/src/client/styles/_variables.scss +++ b/packages/theme/src/client/styles/_variables.scss @@ -1,11 +1,5 @@ @import '@vuepress/plugin-palette/palette'; -$MQNarrow: 959px !default; -$MQMobile: 719px !default; -$MQMobileNarrow: 419px !default; - -$containerWith: 1200px !default; - $codeLang: 'c' 'cpp' 'cs' 'dart' 'docker' 'fs' 'go' 'java' 'kt' 'makefile' 'css' 'less' 'sass' 'scss' 'styl' 'html' 'js' 'json' 'ts' 'vue' 'jsx' 'md' 'php' 'py' 'rb' 'rs' 'sh' 'toml' 'yml' !default; diff --git a/packages/theme/src/client/styles/arrow.scss b/packages/theme/src/client/styles/arrow.scss deleted file mode 100644 index 94a4f796..00000000 --- a/packages/theme/src/client/styles/arrow.scss +++ /dev/null @@ -1,37 +0,0 @@ -.arrow { - display: inline-block; - width: 0; - height: 0; - - &.up { - border: { - left: 4px solid transparent; - right: 4px solid transparent; - bottom: 6px solid var(--c-bg-arrow); - } - } - - &.down { - border: { - left: 4px solid transparent; - right: 4px solid transparent; - top: 6px solid var(--c-bg-arrow); - } - } - - &.right { - border: { - top: 4px solid transparent; - bottom: 4px solid transparent; - left: 6px solid var(--c-bg-arrow); - } - } - - &.left { - border: { - top: 4px solid transparent; - bottom: 4px solid transparent; - right: 6px solid var(--c-bg-arrow); - } - } -} diff --git a/packages/theme/src/client/styles/code.scss b/packages/theme/src/client/styles/code.scss index 3478ccf9..10409e76 100644 --- a/packages/theme/src/client/styles/code.scss +++ b/packages/theme/src/client/styles/code.scss @@ -1,20 +1,18 @@ -@import '_variables'; - // =============================== // Forked and modified from prismjs/themes/prism-tomorrow.css code[class*='language-'], pre[class*='language-'] { - color: #ccc; + color: var(--vp-code-block-color); background: none; - font-family: var(--font-family-code); - font-size: 1em; + font-family: var(--vp-font-family-mono); + font-size: var(--vp-code-font-size); text-align: left; white-space: pre; word-spacing: normal; word-break: normal; word-wrap: normal; - line-height: 1.5; + line-height: var(--vp-code-line-height); -moz-tab-size: 4; -o-tab-size: 4; @@ -33,17 +31,17 @@ pre[class*='language-'] { overflow: auto; } -:not(pre) > code[class*='language-'], -pre[class*='language-'] { - background: #2d2d2d; -} +// :not(pre) > code[class*='language-'], +// pre[class*='language-'] { +// background: var(--vp-code-block-bg); +// } -/* Inline code */ -:not(pre) > code[class*='language-'] { - padding: 0.1em; - border-radius: 0.3em; - white-space: normal; -} +// /* Inline code */ +// :not(pre) > code[class*='language-'] { +// padding: 0.1em; +// border-radius: 0.3em; +// white-space: normal; +// } .token.comment, .token.block-comment, @@ -121,12 +119,12 @@ pre[class*='language-'] { // =============================== -.plume-theme-content { +.plume-content { pre, pre[class*='language-'] { - line-height: 1.4; + // line-height: 1.4; padding: 1.3rem 1.5rem; - margin: 0.85rem 0; + margin: 0 0 0.85rem 0; border-radius: 6px; overflow: auto; scrollbar-width: thin; @@ -138,7 +136,7 @@ pre[class*='language-'] { } &::-webkit-scrollbar-track { - background-color: var(--code-bg-color); + background-color: var(--vp-code-block-bg); } &::-webkit-scrollbar-thumb { @@ -158,22 +156,34 @@ pre[class*='language-'] { } .line-number { - font-family: var(--font-family-code); + font-family: var(--vp-font-family-mono); } + + .code-tabs { + .div[class*='language-'] { + border-top-left-radius: 0; + border-top-right-radius: 0; + } + } +} + +.code-tabs-nav { + margin-bottom: 0rem; } div[class*='language-'] { position: relative; - background-color: var(--code-bg-color); + background-color: var(--vp-code-block-bg); border-radius: 6px; &::before { + content: attr(data-ext); position: absolute; z-index: 3; top: 0.8em; right: 1em; font-size: 0.75rem; - color: var(--code-ln-color); + color: var(--vp-code-line-number-color); } pre, @@ -194,7 +204,7 @@ div[class*='language-'] { line-height: 1.4; .highlight-line { - background-color: var(--code-hl-bg-color); + background-color: var(--vp-code-block-bg); } } @@ -215,13 +225,13 @@ div[class*='language-'] { left: 0; top: 0; display: block; - width: var(--code-ln-wrapper-width); + // width: var(--code-ln-wrapper-width); height: 100%; } } pre { - margin-left: var(--code-ln-wrapper-width); + margin-left: 2rem; padding-left: 1rem; vertical-align: middle; } @@ -229,18 +239,22 @@ div[class*='language-'] { .line-numbers { position: absolute; top: 0; - width: var(--code-ln-wrapper-width); + left: 0; + width: 2rem; + height: 100%; text-align: center; - color: var(--code-ln-color); - padding-top: 1.25rem; - line-height: 1.4; + z-index: 1; + color: var(--vp-code-line-number-color); + padding-top: 1.14rem; + line-height: var(--vp-code-line-height); counter-reset: line-number; + border-right: var(--vp-code-block-divider-color) 1px solid; .line-number { position: relative; z-index: 3; user-select: none; - height: 1.4em; + height: 1.5rem; &::before { counter-increment: line-number; @@ -249,34 +263,19 @@ div[class*='language-'] { } } } - - &::after { - content: ''; - position: absolute; - top: 0; - left: 0; - width: var(--code-ln-wrapper-width); - height: 100%; - border-radius: 6px 0 0 6px; - border-right: 1px solid var(--code-hl-bg-color); - } - } -} - -@each $lang in $codeLang { - div[class*='language-'].ext-#{$lang} { - &:before { - content: '' + $lang; - } } } // narrow mobile -@media (max-width: $MQMobileNarrow) { - .plume-theme-content { +@media (max-width: 419px) { + .plume-content { div[class*='language-'] { margin: 0.85rem -1.5rem; border-radius: 0; } } + + .code-tabs-nav { + margin-bottom: -0.85rem; + } } diff --git a/packages/theme/src/client/styles/content.scss b/packages/theme/src/client/styles/content.scss new file mode 100644 index 00000000..ee7377d7 --- /dev/null +++ b/packages/theme/src/client/styles/content.scss @@ -0,0 +1,517 @@ +/** + * Headings + * -------------------------------------------------------------------------- */ + +.plume-content h1, +.plume-content h2, +.plume-content h3, +.plume-content h4, +.plume-content h5, +.plume-content h6 { + position: relative; + font-weight: 600; + outline: none; +} + +.plume-content h1 { + letter-spacing: -0.02em; + line-height: 40px; + font-size: 28px; +} + +.plume-content h2 { + margin: 48px 0 16px; + border-top: 1px solid var(--vp-c-divider); + padding-top: 24px; + letter-spacing: -0.02em; + line-height: 32px; + font-size: 24px; +} + +.plume-content h2:first-of-type { + border-top: none; +} + +.plume-content h3 { + margin: 32px 0 0; + letter-spacing: -0.01em; + line-height: 28px; + font-size: 20px; +} + +.plume-content .header-anchor { + float: left; + margin-left: -0.87em; + padding-right: 0.23em; + font-weight: 500; + user-select: none; + opacity: 0; + transition: color 0.25s, opacity 0.25s; +} + +.plume-content h1:hover .header-anchor, +.plume-content h1 .header-anchor:focus, +.plume-content h2:hover .header-anchor, +.plume-content h2 .header-anchor:focus, +.plume-content h3:hover .header-anchor, +.plume-content h3 .header-anchor:focus, +.plume-content h4:hover .header-anchor, +.plume-content h4 .header-anchor:focus, +.plume-content h5:hover .header-anchor, +.plume-content h5 .header-anchor:focus, +.plume-content h6:hover .header-anchor, +.plume-content h6 .header-anchor:focus { + opacity: 1; +} + +@media (min-width: 768px) { + .plume-content h1 { + letter-spacing: -0.02em; + line-height: 40px; + font-size: 32px; + } +} + +.plume-content img { + display: inline-block; +} + +.plume-content img + img { + margin-left: 0.5rem; +} + +.plume-content a img + span { + margin-left: 0.2rem; +} + +/** + * Paragraph and inline elements + * -------------------------------------------------------------------------- */ + +.plume-content p, +.plume-content summary { + margin: 16px 0; +} + +.plume-content p { + line-height: 28px; +} + +.plume-content blockquote { + margin: 16px 0; + border-left: 2px solid var(--vp-c-divider); + padding-left: 16px; + transition: border-color 0.5s; +} + +.plume-content blockquote > p { + margin: 0; + font-size: 16px; + color: var(--vp-c-text-2); + transition: color 0.5s; +} + +.plume-content a { + font-weight: 500; + color: var(--vp-c-brand); + text-decoration-style: dotted; + transition: color 0.25s; +} + +.plume-content a:hover { + color: var(--vp-c-brand-dark); +} + +.plume-content strong { + font-weight: 600; +} + +/** + * Lists + * -------------------------------------------------------------------------- */ + +.plume-content ul, +.plume-content ol { + padding-left: 1.25rem; + margin: 16px 0; +} + +.plume-content ul { + list-style: disc; +} + +.plume-content ol { + list-style: decimal; +} + +.plume-content li + li { + margin-top: 8px; +} + +.plume-content li > ol, +.plume-content li > ul { + margin: 8px 0 0; +} + +/** + * Table + * -------------------------------------------------------------------------- */ + +.plume-content table { + display: block; + border-collapse: collapse; + margin: 20px 0; + overflow-x: auto; +} + +.plume-content tr { + border-top: 1px solid var(--vp-c-divider); + transition: background-color 0.5s; +} + +.plume-content tr:nth-child(2n) { + background-color: var(--vp-c-bg-soft); +} + +.plume-content th, +.plume-content td { + border: 1px solid var(--vp-c-divider); + padding: 8px 16px; +} + +.plume-content th { + text-align: left; + font-size: 14px; + font-weight: 600; + color: var(--vp-c-text-2); + background-color: var(--vp-c-bg-soft); +} + +.plume-content td { + font-size: 14px; +} + +/** + * Decorational elements + * -------------------------------------------------------------------------- */ + +.plume-content hr { + margin: 16px 0; + border: none; + border-top: 1px solid var(--vp-c-divider); +} + +/** + * Custom Block + * -------------------------------------------------------------------------- */ + +.plume-content .custom-block { + margin: 16px 0; +} + +.plume-content .custom-block p { + margin: 8px 0; + line-height: 24px; +} + +.plume-content .custom-block p:first-child { + margin: 0; +} + +.plume-content .custom-block a { + color: inherit; + font-weight: 600; + text-decoration: underline; + transition: opacity 0.25s; +} + +.plume-content .custom-block a:hover { + opacity: 0.6; +} + +.plume-content .custom-block code { + font-size: var(--vp-custom-block-code-font-size); + font-weight: 700; + color: inherit; +} + +.plume-content .custom-block div[class*='language-'] { + margin: 8px 0; +} + +.plume-content .custom-block div[class*='language-'] code { + font-weight: 400; + background-color: transparent; +} + +/** + * Code + * -------------------------------------------------------------------------- */ + +/* inline code */ +.plume-content :not(pre, h1, h2, h3, h4, h5, h6) > code { + font-size: var(--vp-code-font-size); +} + +.plume-content :not(pre) > code { + border-radius: 4px; + padding: 3px 6px; + color: var(--vp-c-text-code); + background-color: var(--vp-c-mute); + transition: color 0.5s, background-color 0.5s; +} + +.plume-content h1 > code, +.plume-content h2 > code, +.plume-content h3 > code { + font-size: 0.9em; +} + +.plume-content a > code { + color: var(--vp-c-brand); + transition: color 0.25s; +} + +.plume-content a:hover > code { + color: var(--vp-c-brand-dark); +} + +// .plume-content div[class*='language-'] { +// position: relative; +// margin: 16px -24px; +// background-color: var(--vp-code-block-bg); +// overflow-x: auto; +// transition: background-color 0.5s; +// } + +// @media (min-width: 640px) { +// .plume-content div[class*='language-'] { +// border-radius: 8px; +// margin: 16px 0; +// } +// } + +// @media (max-width: 639px) { +// .plume-content li div[class*='language-'] { +// border-radius: 8px 0 0 8px; +// } +// } + +// .plume-content div[class*='language-'] + div[class*='language-'], +// .plume-content div[class$='-api'] + div[class*='language-'], +// .plume-content +// div[class*='language-'] +// + div[class$='-api'] +// > div[class*='language-'] { +// margin-top: -8px; +// } + +// .plume-content [class*='language-'] pre, +// .plume-content [class*='language-'] code { +// /*rtl:ignore*/ +// direction: ltr; +// /*rtl:ignore*/ +// text-align: left; +// white-space: pre; +// word-spacing: normal; +// word-break: normal; +// word-wrap: normal; +// -moz-tab-size: 4; +// -o-tab-size: 4; +// tab-size: 4; +// -webkit-hyphens: none; +// -moz-hyphens: none; +// -ms-hyphens: none; +// hyphens: none; +// } + +// .plume-content [class*='language-'] pre { +// position: relative; +// z-index: 1; +// margin: 0; +// padding: 16px 0; +// background: transparent; +// overflow-x: auto; +// } + +// .plume-content [class*='language-'] code { +// display: block; +// padding: 0 24px; +// width: fit-content; +// min-width: 100%; +// line-height: var(--vp-code-line-height); +// font-size: var(--vp-code-font-size); +// color: var(--vp-code-block-color); +// transition: color 0.5s; +// } + +// .plume-content [class*='language-'] code .highlighted { +// background-color: var(--vp-code-line-highlight-color); +// transition: background-color 0.5s; +// margin: 0 -24px; +// padding: 0 24px; +// width: calc(100% + 2 * 24px); +// display: inline-block; +// } + +// .plume-content [class*='language-'] code .highlighted.error { +// background-color: var(--vp-code-line-error-color); +// } + +// .plume-content [class*='language-'] code .highlighted.warning { +// background-color: var(--vp-code-line-warning-color); +// } + +// .plume-content [class*='language-'] code .diff { +// transition: background-color 0.5s; +// margin: 0 -24px; +// padding: 0 24px; +// width: calc(100% + 2 * 24px); +// display: inline-block; +// } + +// .plume-content [class*='language-'] code .diff::before { +// position: absolute; +// left: 10px; +// } + +// .plume-content [class*='language-'] .has-focused-lines .line:not(.has-focus) { +// filter: blur(0.095rem); +// opacity: 0.4; +// transition: filter 0.35s, opacity 0.35s; +// } + +// .plume-content [class*='language-'] .has-focused-lines .line:not(.has-focus) { +// opacity: 0.7; +// transition: filter 0.35s, opacity 0.35s; +// } + +// .plume-content +// [class*='language-']:hover +// .has-focused-lines +// .line:not(.has-focus) { +// filter: blur(0); +// opacity: 1; +// } + +// .plume-content [class*='language-'] code .diff.remove { +// background-color: var(--vp-code-line-diff-remove-color); +// opacity: 0.7; +// } + +// .plume-content [class*='language-'] code .diff.remove::before { +// content: '-'; +// color: var(--vp-code-line-diff-remove-symbol-color); +// } + +// .plume-content [class*='language-'] code .diff.add { +// background-color: var(--vp-code-line-diff-add-color); +// } + +// .plume-content [class*='language-'] code .diff.add::before { +// content: '+'; +// color: var(--vp-code-line-diff-add-symbol-color); +// } + +// .plume-content div[class*='language-'].line-numbers-mode { +// /*rtl:ignore*/ +// padding-left: 32px; +// } + +// .plume-content .line-numbers { +// position: absolute; +// top: 0; +// bottom: 0; +// /*rtl:ignore*/ +// left: 0; +// z-index: 3; +// /*rtl:ignore*/ +// border-right: 1px solid var(--vp-code-block-divider-color); +// padding-top: 16px; +// width: 32px; +// text-align: center; +// font-family: var(--vp-font-family-mono); +// line-height: var(--vp-code-line-height); +// font-size: var(--vp-code-font-size); +// color: var(--vp-code-line-number-color); +// transition: border-color 0.5s, color 0.5s; +// } + +// .plume-content [class*='language-'] > button.copy { +// /*rtl:ignore*/ +// direction: ltr; +// position: absolute; +// top: 8px; +// /*rtl:ignore*/ +// right: 8px; +// z-index: 3; +// display: block; +// justify-content: center; +// align-items: center; +// border-radius: 4px; +// width: 40px; +// height: 40px; +// background-color: var(--vp-code-block-bg); +// opacity: 0; +// cursor: pointer; +// background-image: var(--vp-icon-copy); +// background-position: 50%; +// background-size: 20px; +// background-repeat: no-repeat; +// transition: opacity 0.4s; +// } + +// .plume-content [class*='language-']:hover > button.copy, +// .plume-content [class*='language-'] > button.copy:focus { +// opacity: 1; +// } + +// .plume-content [class*='language-'] > button.copy:hover { +// background-color: var(--vp-code-copy-code-hover-bg); +// } + +// .plume-content [class*='language-'] > button.copy.copied, +// .plume-content [class*='language-'] > button.copy:hover.copied { +// /*rtl:ignore*/ +// border-radius: 0 4px 4px 0; +// background-color: var(--vp-code-copy-code-hover-bg); +// background-image: var(--vp-icon-copied); +// } + +// .plume-content [class*='language-'] > button.copy.copied::before, +// .plume-content [class*='language-'] > button.copy:hover.copied::before { +// position: relative; +// /*rtl:ignore*/ +// left: -65px; +// display: flex; +// justify-content: center; +// align-items: center; +// /*rtl:ignore*/ +// border-radius: 4px 0 0 4px; +// width: 64px; +// height: 40px; +// text-align: center; +// font-size: 12px; +// font-weight: 500; +// color: var(--vp-code-copy-code-active-text); +// background-color: var(--vp-code-copy-code-hover-bg); +// white-space: nowrap; +// content: 'Copied'; +// } + +// .plume-content [class*='language-'] > span.lang { +// position: absolute; +// top: 6px; +// /*rtl:ignore*/ +// right: 12px; +// z-index: 2; +// font-size: 12px; +// font-weight: 500; +// color: var(--vp-c-text-dark-3); +// transition: color 0.4s, opacity 0.4s; +// } + +// .plume-content [class*='language-']:hover > button.copy + span.lang, +// .plume-content [class*='language-'] > button.copy:focus + span.lang { +// opacity: 0; +// } diff --git a/packages/theme/src/client/styles/fonts.scss b/packages/theme/src/client/styles/fonts.scss new file mode 100644 index 00000000..c99c665c --- /dev/null +++ b/packages/theme/src/client/styles/fonts.scss @@ -0,0 +1,157 @@ +/* webfont-marker-begin */ +@import url('https://fonts.googleapis.com/css2?family=Inter:wght@100..900&display=swap'); + +html body { + font-synthesis: style; +} +/* webfont-marker-end */ + +@font-face { + font-family: 'Inter var'; + font-weight: 100 900; + font-display: swap; + font-style: normal; + font-named-instance: 'Regular'; + src: url('../fonts/inter-roman-cyrillic.woff2') format('woff2'); + unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; +} + +@font-face { + font-family: 'Inter var'; + font-weight: 100 900; + font-display: swap; + font-style: normal; + font-named-instance: 'Regular'; + src: url('../fonts/inter-roman-cyrillic-ext.woff2') format('woff2'); + unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, + U+FE2E-FE2F; +} + +@font-face { + font-family: 'Inter var'; + font-weight: 100 900; + font-display: swap; + font-style: normal; + font-named-instance: 'Regular'; + src: url('../fonts/inter-roman-greek.woff2') format('woff2'); + unicode-range: U+0370-03FF; +} + +@font-face { + font-family: 'Inter var'; + font-weight: 100 900; + font-display: swap; + font-style: normal; + font-named-instance: 'Regular'; + src: url('../fonts/inter-roman-greek-ext.woff2') format('woff2'); + unicode-range: U+1F00-1FFF; +} + +@font-face { + font-family: 'Inter var'; + font-weight: 100 900; + font-display: swap; + font-style: normal; + font-named-instance: 'Regular'; + src: url('../fonts/inter-roman-latin.woff2') format('woff2'); + unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, + U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, + U+FEFF, U+FFFD; +} + +@font-face { + font-family: 'Inter var'; + font-weight: 100 900; + font-display: swap; + font-style: normal; + font-named-instance: 'Regular'; + src: url('../fonts/inter-roman-latin-ext.woff2') format('woff2'); + unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, + U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF; +} + +@font-face { + font-family: 'Inter var'; + font-weight: 100 900; + font-display: swap; + font-style: normal; + font-named-instance: 'Regular'; + src: url('../fonts/inter-roman-vietnamese.woff2') format('woff2'); + unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, + U+01AF-01B0, U+1EA0-1EF9, U+20AB; +} + +@font-face { + font-family: 'Inter var'; + font-weight: 100 900; + font-display: swap; + font-style: italic; + font-named-instance: 'Italic'; + src: url('../fonts/inter-italic-cyrillic.woff2') format('woff2'); + unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116; +} + +@font-face { + font-family: 'Inter var'; + font-weight: 100 900; + font-display: swap; + font-style: italic; + font-named-instance: 'Italic'; + src: url('../fonts/inter-italic-cyrillic-ext.woff2') format('woff2'); + unicode-range: U+0460-052F, U+1C80-1C88, U+20B4, U+2DE0-2DFF, U+A640-A69F, + U+FE2E-FE2F; +} + +@font-face { + font-family: 'Inter var'; + font-weight: 100 900; + font-display: swap; + font-style: italic; + font-named-instance: 'Italic'; + src: url('../fonts/inter-italic-greek.woff2') format('woff2'); + unicode-range: U+0370-03FF; +} + +@font-face { + font-family: 'Inter var'; + font-weight: 100 900; + font-display: swap; + font-style: italic; + font-named-instance: 'Italic'; + src: url('../fonts/inter-italic-greek-ext.woff2') format('woff2'); + unicode-range: U+1F00-1FFF; +} + +@font-face { + font-family: 'Inter var'; + font-weight: 100 900; + font-display: swap; + font-style: italic; + font-named-instance: 'Italic'; + src: url('../fonts/inter-italic-latin.woff2') format('woff2'); + unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, + U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, + U+FEFF, U+FFFD; +} + +@font-face { + font-family: 'Inter var'; + font-weight: 100 900; + font-display: swap; + font-style: italic; + font-named-instance: 'Italic'; + src: url('../fonts/inter-italic-latin-ext.woff2') format('woff2'); + unicode-range: U+0100-024F, U+0259, U+1E00-1EFF, U+2020, U+20A0-20AB, + U+20AD-20CF, U+2113, U+2C60-2C7F, U+A720-A7FF; +} + +@font-face { + font-family: 'Inter var'; + font-weight: 100 900; + font-display: swap; + font-style: italic; + font-named-instance: 'Italic'; + src: url('../fonts/inter-italic-vietnamese.woff2') format('woff2'); + unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, + U+01AF-01B0, U+1EA0-1EF9, U+20AB; +} diff --git a/packages/theme/src/client/styles/icons.scss b/packages/theme/src/client/styles/icons.scss deleted file mode 100644 index baaad858..00000000 --- a/packages/theme/src/client/styles/icons.scss +++ /dev/null @@ -1,4 +0,0 @@ -.icon { - width: 20px; - height: 20px; -} diff --git a/packages/theme/src/client/styles/index.scss b/packages/theme/src/client/styles/index.scss index 4eb29e20..42649489 100644 --- a/packages/theme/src/client/styles/index.scss +++ b/packages/theme/src/client/styles/index.scss @@ -1,13 +1,10 @@ @use 'vars'; -@use 'vars-dark'; - +@use 'fonts'; @use 'normalize'; -@use 'arrow'; -@use 'transition'; -@use 'icons'; - -@use 'layout'; -@use 'code'; +@use 'nprogress'; +@use 'utils'; +@use 'content'; @use 'toc'; +@use 'code'; -@use'@vuepress/plugin-palette/style'; +@use '@vuepress/plugin-palette/style'; diff --git a/packages/theme/src/client/styles/layout.scss b/packages/theme/src/client/styles/layout.scss deleted file mode 100644 index 04d950af..00000000 --- a/packages/theme/src/client/styles/layout.scss +++ /dev/null @@ -1,13 +0,0 @@ -.plume-theme { - position: relative; - min-height: 100vh; - padding-bottom: 2rem; - - &.bottom { - padding-bottom: 6rem; - } -} - -.task-list-container { - list-style: none; -} diff --git a/packages/theme/src/client/styles/normalize.scss b/packages/theme/src/client/styles/normalize.scss index 8fd91a1b..5ccb5d8b 100644 --- a/packages/theme/src/client/styles/normalize.scss +++ b/packages/theme/src/client/styles/normalize.scss @@ -1,19 +1,13 @@ -html, -body { - padding: 0; - margin: 0; - background-color: var(--c-bg); - transition: background-color var(--t-color); -} - *, -*::after, -*::before { +::before, +::after { box-sizing: border-box; } -:root { - scroll-behavior: smooth; +html { + line-height: 1.4; + font-size: 16px; + -webkit-text-size-adjust: 100%; } html.dark { @@ -21,65 +15,25 @@ html.dark { } body { - font-family: var(--font-family); - -webkit-font-smoothing: antialiased; - -moz-font-smoothing: grayscale; - font-size: 16px; - color: var(--c-text); -} - -a { - font-weight: 500; - color: var(--c-text-accent); - text-decoration: none; - overflow-wrap: break-word; - transition: color var(--t-color); -} - -p a code { - font-weight: 400; - color: var(--c-text-accent); -} - -kbd { - font-family: var(--font-family-code); - color: var(--c-text); - background: var(--c-bg-lighter); - border: solid 0.15rem var(--c-border-dark); - border-bottom: solid 0.25rem var(--c-border-dark); - padding: 0 0.15em; -} - -code { - font-family: var(--font-family-code); - color: var(--c-text-lighter); - padding: 0.25rem 0.5rem; margin: 0; - font-size: 0.85rem; - background-color: var(--c-bg-light); - border-radius: 3px; - overflow-wrap: break-word; + width: 100%; + min-width: 320px; + min-height: 100vh; + line-height: 24px; + font-family: var(--vp-font-family-base); + font-size: 16px; + font-weight: 400; + color: var(--vp-c-text-1); + background-color: var(--vp-c-bg); + direction: ltr; + font-synthesis: none; + text-rendering: optimizeLegibility; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; } -blockquote { - font-size: 1rem; - color: var(--c-text-quote); - border-left: 0.2rem solid var(--c-border-dark); - margin: 1rem 0; - padding: 0.25rem 0 0.25rem 1rem; - - & > p { - margin: 0; - } -} - -ul, -ol { - padding-left: 1.2em; -} - -strong { - font-weight: 600; +main { + display: block; } h1, @@ -88,100 +42,190 @@ h3, h4, h5, h6 { + margin: 0; + line-height: 24px; + font-size: 16px; + font-weight: 400; +} + +p { + margin: 0; +} + +strong, +b { font-weight: 600; - line-height: 1.25; - transition: color var(--t-color); - - &:focus-visible { - outline: none; - } - - &:hover .header-anchor { - opacity: 1; - } } -h1 { - font-size: 2.2rem; +/** + * Avoid 300ms click delay on touch devices that support the `touch-action` + * CSS property. + * + * In particular, unlike most other browsers, IE11+Edge on Windows 10 on + * touch devices and IE Mobile 10-11 DON'T remove the click delay when + * `<meta name="viewport" content="width=device-width">` is present. + * However, they DO support removing the click delay via + * `touch-action: manipulation`. + * + * See: + * - http://v4-alpha.getbootstrap.com/content/reboot/#click-delay-optimization-for-touch + * - http://caniuse.com/#feat=css-touch-action + * - http://patrickhlauke.github.io/touch/tests/results/#suppressing-300ms-delay + */ +a, +area, +button, +[role='button'], +input, +label, +select, +summary, +textarea { + touch-action: manipulation; } -h2 { - font-size: 1.65rem; - padding-bottom: 0.5rem; - border-bottom: solid 1px var(--c-border); - transition: border-color var(--t-color); - margin-top: 2.75rem; +a { + color: inherit; + text-decoration: inherit; } -h3 { - font-size: 1.35rem; +ol, +ul { + list-style: none; + margin: 0; + padding: 0; } -h4 { - font-size: 1.15rem; +blockquote { + margin: 0; } -h5 { - font-size: 1.05rem; +pre, +code, +kbd, +samp { + font-family: var(--vp-font-family-mono); } -h6 { - font-size: 1rem; +img, +svg, +video, +canvas, +audio, +iframe, +embed, +object { + display: block; } -a.header-anchor { - font-size: 0.85rem; - float: left; - margin-left: -0.87rem; - padding-right: 0.23rem; - margin-top: 0.125rem; - opacity: 0; - - &:hover { - text-decoration: none; - - &:focus-visible { - opacity: 1; - } - } +figure { + margin: 0; } -p, -ul, -ol { - line-height: 1.7; +img, +video { + max-width: 100%; + height: auto; } -hr { +button, +input, +optgroup, +select, +textarea { border: 0; - border-top: solid 1px var(--c-border); + padding: 0; + line-height: inherit; + color: inherit; +} + +button { + padding: 0; + font-family: inherit; + background-color: transparent; + background-image: none; +} + +button:enabled, +[role='button']:enabled { + cursor: pointer; +} + +button:focus, +button:focus-visible { + outline: 1px dotted; + outline: 4px auto -webkit-focus-ring-color; +} + +button:focus:not(:focus-visible) { + outline: none !important; +} + +input:focus, +textarea:focus, +select:focus { + outline: none; } table { border-collapse: collapse; - margin: 1rem 0; - display: block; - overflow-x: auto; - transition: border-color var(--t-color); } -tr { - border-top: solid 1px var(--c-border-dark); - transition: border-color var(--t-color); - - &:nth-child(2n) { - background-color: var(--c-bg-light); - transition: background-color var(--t-color); - - code { - background-color: var(--c-bg-lighter); - } - } +input { + background-color: transparent; } -th, -td { - padding: 0.6em 1em; - border: 1px solid var(--c-border-dark); - transition: border-color var(--t-color); +input:-ms-input-placeholder, +textarea:-ms-input-placeholder { + color: var(--vp-c-text-3); +} + +input::-ms-input-placeholder, +textarea::-ms-input-placeholder { + color: var(--vp-c-text-3); +} + +input::placeholder, +textarea::placeholder { + color: var(--vp-c-text-3); +} + +input::-webkit-outer-spin-button, +input::-webkit-inner-spin-button { + -webkit-appearance: none; + margin: 0; +} + +input[type='number'] { + -moz-appearance: textfield; + appearance: textfield; +} + +textarea { + resize: vertical; +} + +select { + -webkit-appearance: none; + appearance: none; +} + +fieldset { + margin: 0; + padding: 0; +} + +h1, +h2, +h3, +h4, +h5, +h6, +li, +p { + overflow-wrap: break-word; +} + +vite-error-overlay { + z-index: 9999; } diff --git a/packages/theme/src/client/styles/nprogress.scss b/packages/theme/src/client/styles/nprogress.scss new file mode 100644 index 00000000..477703ce --- /dev/null +++ b/packages/theme/src/client/styles/nprogress.scss @@ -0,0 +1,12 @@ +#nprogress .bar { + background: var(--vp-c-brand); +} + +#nprogress .spinner-icon { + border-top-color: var(--vp-c-brand); + border-left-color: var(--vp-c-brand); +} + +#nprogress .peg { + box-shadow: 0 0 10px var(--vp-c-brand), 0 0 5px var(--vp-c-brand); +} diff --git a/packages/theme/src/client/styles/toc.scss b/packages/theme/src/client/styles/toc.scss index 27ddd3c6..503f3614 100644 --- a/packages/theme/src/client/styles/toc.scss +++ b/packages/theme/src/client/styles/toc.scss @@ -1,7 +1,5 @@ .theme-plume-toc { - border-left: solid 1px var(--c-border); - max-height: calc(100vh - var(--navbar-height) - (1.25rem * 3)); - overflow-y: auto; + border-left: solid 1px var(--vp-c-divider); &::-webkit-scrollbar { width: 0; @@ -14,20 +12,23 @@ .theme-plume-toc-list { list-style: none; + font-size: 13px; + font-weight: 500; .theme-plume-toc-link { width: 100%; display: inline-block; - color: var(--c-text-light); + color: var(--vp-c-text-2); border-left: solid 3px transparent; padding-left: 1rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; - transition: color var(--t-color), border-color var(--t-color); + line-height: 28px; + transition: color 0.25s, border-color 0.25s; &.active { - color: var(--c-text-accent); + color: var(--vp-c-text-1); border-color: var((--c-text-accent)); } } diff --git a/packages/theme/src/client/styles/transition.scss b/packages/theme/src/client/styles/transition.scss deleted file mode 100644 index 3c816cd2..00000000 --- a/packages/theme/src/client/styles/transition.scss +++ /dev/null @@ -1,30 +0,0 @@ -.fade-slide-y { - &-enter-active { - transition: all 0.3s ease; - } - - &-leave-active { - transition: all 0.3s cubic-bezier(1, 0.5, 0.8, 1); - } - - &-enter-from, - &-leave-to { - transform: translateY(10px); - opacity: 0; - } -} - -.fade { - &-enter-active { - transition: all 0.3s ease; - } - - &-leave-active { - transition: all 0.3s cubic-bezier(1, 0.5, 0.8, 1); - } - - &-enter-from, - &-leave-to { - opacity: 0; - } -} diff --git a/packages/theme/src/client/styles/utils.scss b/packages/theme/src/client/styles/utils.scss new file mode 100644 index 00000000..d3adb683 --- /dev/null +++ b/packages/theme/src/client/styles/utils.scss @@ -0,0 +1,14 @@ +.visually-hidden { + position: absolute; + width: 1px; + height: 1px; + white-space: nowrap; + clip: rect(0 0 0 0); + clip-path: inset(50%); + overflow: hidden; +} + +.icon { + width: 20px; + height: 20px; +} diff --git a/packages/theme/src/client/styles/vars-dark.scss b/packages/theme/src/client/styles/vars-dark.scss deleted file mode 100644 index 33104026..00000000 --- a/packages/theme/src/client/styles/vars-dark.scss +++ /dev/null @@ -1,46 +0,0 @@ -html.dark { - --c-brand: #0094c8; - --c-brand-light: #007bbb; - - --c-bg: #22272e; - --c-bg-light: #2b313a; - --c-bg-lighter: #262c34; - --c-bg-container: #22272e; - --c-bg-navbar: rgba(34, 39, 46, 0.75); - --c-bg-sticky: var(--c-bg-light); - - --c-text: #adbac7; - --c-text-light: #96a7b7; - --c-text-lighter: #8b94a8; - --c-text-lightest: #8094a8; - - --c-sidebar-text: rgba(195, 195, 195, 0.7); - - --c-border: #3e4c5a; - --c-border-dark: #34404c; - - --c-tip: #318a62; - --c-warning: #ceab00; - --c-warning-bg: #7e755b; - --c-warning-title: #ceac03; - --c-warning-text: #362e00; - --c-danger: #940000; - --c-danger-bg: #806161; - --c-danger-title: #610000; - --c-danger-text: #3a0000; - --c-details-bg: #323843; - - --c-hl-bg-color: #363b46; - - --c-home-arrow-bottom: rgba(196, 205, 216, 0.75); -} - -html.dark .DocSearch { - --docsearch-logo-color: var(--c-text); - --docsearch-modal-shadow: inset 1px 1px 0 0 #2c2e40, 0 3px 8px 0 #000309; - --docsearch-key-shadow: inset 0 -2px 0 0 #282d55, inset 0 0 1px 1px #51577d, - 0 2px 2px 0 rgba(3, 4, 9, 0.3); - --docsearch-key-gradient: linear-gradient(-225deg, #444950, #1c1e21); - --docsearch-footer-shadow: inset 0 1px 0 0 rgba(73, 76, 106, 0.5), - 0 -4px 8px 0 rgba(0, 0, 0, 0.2); -} diff --git a/packages/theme/src/client/styles/vars.scss b/packages/theme/src/client/styles/vars.scss index ebc33cae..7ff33a96 100644 --- a/packages/theme/src/client/styles/vars.scss +++ b/packages/theme/src/client/styles/vars.scss @@ -1,129 +1,411 @@ +/** + * Colors Base + * + * These are the pure base color presets. Most of the time, you should not be + * using these colors directly in the theme but rather use "Colors Theme" + * instead because those are "Theme (light or dark)" dependant. + * -------------------------------------------------------------------------- */ + :root { - // brand color - --c-brand: #0095d9; - --c-brand-light: #2ca9e1; + --vp-c-white: #ffffff; + --vp-c-black: #000000; - // background color - --c-bg: #fff; - --c-bg-light: #e5e7eb; - --c-bg-lighter: #d1d5db; - --c-bg-container: #fff; - --c-bg-navbar: rgba(255, 255, 255, 0.7); - --c-bg-sidebar: var(--c-bg-container); - --c-bg-arrow: #ccc; - --c-bg-sticky: #f1f2f3; + --vp-c-gray: #8e8e93; - // text color-scheme - --c-text: #2c3e50; - --c-text-accent: var(--c-brand); - --c-text-light: #3a5169; - --c-text-lighter: #4e6e8e; - --c-text-lightest: #6a8bad; - --c-text-quote: #999; + --vp-c-text-light-1: rgba(60, 60, 67, 0.92); + --vp-c-text-light-2: rgba(60, 60, 67, 0.7); + --vp-c-text-light-3: rgba(60, 60, 67, 0.33); - --c-sidebar-text: rgba(60, 60, 60, 0.7); + --vp-c-text-dark-1: rgba(255, 255, 245, 0.86); + --vp-c-text-dark-2: rgba(235, 235, 245, 0.6); + --vp-c-text-dark-3: rgba(235, 235, 245, 0.38); - // border colors - --c-border: #eaecef; - --c-border-dark: #dfe2e5; + --vp-c-green: #10b981; + --vp-c-green-light: #34d399; + --vp-c-green-lighter: #6ee7b7; + --vp-c-green-dark: #059669; + --vp-c-green-darker: #047857; + --vp-c-green-dimm-1: rgba(16, 185, 129, 0.05); + --vp-c-green-dimm-2: rgba(16, 185, 129, 0.2); + --vp-c-green-dimm-3: rgba(16, 185, 129, 0.5); - // container color - --c-tip: #60a5fa; - --c-tip-bg: var(--c-bg-light); - --c-tip-title: var(--c-text); - --c-tip-text: var(--c-text); - --c-tip-text-accent: var(--c-text-accent); - --c-warning: #e7c000; - --c-warning-bg: #fffae3; - --c-warning-title: #ad9000; - --c-warning-text: #746000; - --c-warning-text-accent: var(--c-text); - --c-danger: #cc0000; - --c-danger-bg: #ffe0e0; - --c-danger-title: #990000; - --c-danger-text: #600; - --c-danger-text-accent: var(--c-text); - --c-detail-bg: #eee; + --vp-c-yellow: #eab308; + --vp-c-yellow-light: #facc15; + --vp-c-yellow-lighter: #fde047; + --vp-c-yellow-dark: #ca8a04; + --vp-c-yellow-darker: #a16207; + --vp-c-yellow-dimm-1: rgba(234, 179, 8, 0.05); + --vp-c-yellow-dimm-2: rgba(234, 179, 8, 0.2); + --vp-c-yellow-dimm-3: rgba(234, 179, 8, 0.5); - // badge component colors - --c-badge-tip: var(--c-tip); - --c-badge-warning: var(--c-warning); - --c-badge-danger: var(--c-danger); + --vp-c-red: #f43f5e; + --vp-c-red-light: #fb7185; + --vp-c-red-lighter: #fda4af; + --vp-c-red-dark: #e11d48; + --vp-c-red-darker: #be123c; + --vp-c-red-dimm-1: rgba(244, 63, 94, 0.05); + --vp-c-red-dimm-2: rgba(244, 63, 94, 0.2); + --vp-c-red-dimm-3: rgba(244, 63, 94, 0.5); - --c-home-arrow-bottom: rgba(255, 255, 255, 0.75); - - // transition - --t-color: 0.3s ease; - --t-transform: 0.3s ease; - - // box-shadow - --shadow-sm: 0 0 #0000, 0 0 #0000, 0 1px 2px 0 rgba(0, 0, 0, 0.05); - --shadow: 0 0 #0000, 0 0 #0000, 0 1px 3px 0 rgba(0, 0, 0, 0.1), - 0 1px 2px 0 rgba(0, 0, 0, 0.06); - --shadow-md: 0 0 #0000, 0 0 #0000, 0 4px 6px -1px rgba(0, 0, 0, 0.1), - 0 2px 4px -1px rgba(0, 0, 0, 0.06); - --shadow-lg: 0 0 #0000, 0 0 #0000, 0 6px 8px -1px rgba(0, 0, 0, 0.1), - 0 3px 6px -1px rgba(0, 0, 0, 0.06); - - --shadow-footer: 0 -1px 3px 0px rgba(0, 0, 0, 0.1), 0 0 #0000, 0 0 #0000, - 0 -1px 2px 0px rgba(0, 0, 0, 0.06); - - // border-radius - --p-around: 4px; - - // code block - --code-bg-color: #282c34; - --code-hl-bg-color: rgba(0, 0, 0, 0.66); - --code-ln-color: #9e9e9e; - --code-ln-wrapper-width: 3.5rem; - - // font vars - --font-family: -apple-system, BlinkMackSystemFont, 'Segoe UI', Roboto, Oxygen, - Ubuntu, Cantarell, 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif; - --font-family-code: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace; - - --navbar-height: 3.6rem; - --navbar-padding-v: 0.7rem; - --navbar-padding-h: 1.5rem; - --sidebar-width: 20rem; - --sidebar-width-mobile: calc(var(--sidebar-width) * 0.82); - --content-width: 850px; - --content-note-width: 1000px; - - // search box vars - --search-bg-color: var(--c-bg-container); - --search-accent-color: var(--c-text-accent); - --search-text-color: var(--c-text); - --search-border-color: var(--c-border); - - --search-item-text-color: var(--c-brand); - --search-item-focus-bg-color: var(--c-bg-light); - - --search-input-width: 8rem; - --search-result-width: 20rem; + --vp-c-sponsor: #db2777; } -.DocSearch { - --docsearch-primary-color: var(--c-brand); - --docsearch-text-color: var(--c-text); - --docsearch-highlight-color: var(--c-brand); - --docsearch-muted-color: var(--c-text-quote); - --docsearch-container-background: rgba(9, 10, 17, 0.8); - --docsearch-modal-background: var(--c-bg-light); - --docsearch-searchbox-background: var(--c-bg-lighter); - --docsearch-searchbox-focus-background: var(--c-bg); - --docsearch-searchbox-shadow: var(--shadow); - --docsearch-hit-color: var(--c-text-light); - --docsearch-hit-active-color: var(--c-bg); - --docsearch-hit-background: var(--c-bg); - --docsearch-hit-shadow: 0 1px 3px 0 var(--c-border-dark); - --docsearch-footer-background: var(--c-bg); +/** + * Colors Theme + * -------------------------------------------------------------------------- */ + +:root { + --vp-c-bg: #ffffff; + + --vp-c-bg-elv: #ffffff; + --vp-c-bg-elv-up: #ffffff; + --vp-c-bg-elv-down: #f6f6f7; + --vp-c-bg-elv-mute: #f6f6f7; + + --vp-c-bg-soft: #f6f6f7; + --vp-c-bg-soft-up: #ffffff; + --vp-c-bg-soft-down: #e3e3e5; + --vp-c-bg-soft-mute: #e3e3e5; + + --vp-c-bg-alt: #f6f6f7; + + --vp-c-border: rgba(60, 60, 67, 0.29); + --vp-c-divider: rgba(60, 60, 67, 0.12); + --vp-c-gutter: rgba(60, 60, 67, 0.12); + + --vp-c-neutral: var(--vp-c-black); + --vp-c-neutral-inverse: var(--vp-c-white); + + --vp-c-text-1: var(--vp-c-text-light-1); + --vp-c-text-2: var(--vp-c-text-light-2); + --vp-c-text-3: var(--vp-c-text-light-3); + + --vp-c-text-inverse-1: var(--vp-c-text-dark-1); + --vp-c-text-inverse-2: var(--vp-c-text-dark-2); + --vp-c-text-inverse-3: var(--vp-c-text-dark-3); + + --vp-c-text-hero-name: var(--vp-c-text-dark-1); + --vp-c-text-hero-profession: var(--vp-c-text-dark-2); + --vp-c-text-hero-text: var(--vp-c-text-dark-1); + + --vp-c-text-code: #476582; + + --vp-c-brand: var(--vp-c-green); + --vp-c-brand-light: var(--vp-c-green-light); + --vp-c-brand-lighter: var(--vp-c-green-lighter); + --vp-c-brand-dark: var(--vp-c-green-dark); + --vp-c-brand-darker: var(--vp-c-green-darker); + + --vp-c-mute: #f6f6f7; + --vp-c-mute-light: #f9f9fc; + --vp-c-mute-lighter: #ffffff; + --vp-c-mute-dark: #e3e3e5; + --vp-c-mute-darker: #d7d7d9; } -.external-link-icon { - --external-link-icon-color: var(--c-text-quote); +.dark { + --vp-c-bg: #1e1e20; + + --vp-c-bg-elv: #252529; + --vp-c-bg-elv-up: #313136; + --vp-c-bg-elv-down: #1e1e20; + --vp-c-bg-elv-mute: #313136; + + --vp-c-bg-soft: #252529; + --vp-c-bg-soft-up: #313136; + --vp-c-bg-soft-down: #1e1e20; + --vp-c-bg-soft-mute: #313136; + + --vp-c-bg-alt: #161618; + + --vp-c-border: rgba(82, 82, 89, 0.68); + --vp-c-divider: rgba(82, 82, 89, 0.32); + --vp-c-gutter: #000000; + + --vp-c-neutral: var(--vp-c-white); + --vp-c-neutral-inverse: var(--vp-c-black); + + --vp-c-text-1: var(--vp-c-text-dark-1); + --vp-c-text-2: var(--vp-c-text-dark-2); + --vp-c-text-3: var(--vp-c-text-dark-3); + + --vp-c-text-inverse-1: var(--vp-c-text-light-1); + --vp-c-text-inverse-2: var(--vp-c-text-light-2); + --vp-c-text-inverse-3: var(--vp-c-text-light-3); + + --vp-c-text-code: #c9def1; + + --vp-c-mute: #313136; + --vp-c-mute-light: #3a3a3c; + --vp-c-mute-lighter: #505053; + --vp-c-mute-dark: #2c2c30; + --vp-c-mute-darker: #252529; } -.medium-zoom-overlay { - --medium-zoom-bg-color: var(--c-bg); +/** + * Typography + * -------------------------------------------------------------------------- */ + +:root { + --vp-font-family-base: 'Inter var', 'Inter', ui-sans-serif, system-ui, + -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', + Helvetica, Arial, 'Noto Sans', sans-serif, 'Apple Color Emoji', + 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji'; + --vp-font-family-mono: ui-monospace, SFMono-Regular, 'SF Mono', Menlo, Monaco, + Consolas, 'Liberation Mono', 'Courier New', monospace; +} + +/** + * Shadows + * -------------------------------------------------------------------------- */ + +:root { + --vp-shadow-1: 0 1px 2px rgba(0, 0, 0, 0.04), 0 1px 2px rgba(0, 0, 0, 0.06); + --vp-shadow-2: 0 3px 12px rgba(0, 0, 0, 0.07), 0 1px 4px rgba(0, 0, 0, 0.07); + --vp-shadow-3: 0 12px 32px rgba(0, 0, 0, 0.1), 0 2px 6px rgba(0, 0, 0, 0.08); + --vp-shadow-4: 0 14px 44px rgba(0, 0, 0, 0.12), 0 3px 9px rgba(0, 0, 0, 0.12); + --vp-shadow-5: 0 18px 56px rgba(0, 0, 0, 0.16), 0 4px 12px rgba(0, 0, 0, 0.16); +} + +/** + * Z-indexes + * -------------------------------------------------------------------------- */ + +:root { + --vp-z-index-local-nav: 10; + --vp-z-index-nav: 20; + --vp-z-index-layout-top: 30; + --vp-z-index-backdrop: 40; + --vp-z-index-sidebar: 50; + --vp-z-index-footer: 60; +} + +/** + * Icons + * -------------------------------------------------------------------------- */ + +:root { + --vp-icon-copy: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' height='20' width='20' stroke='rgba(128,128,128,1)' stroke-width='2' viewBox='0 0 24 24'%3E%3Cpath stroke-linecap='round' stroke-linejoin='round' d='M9 5H7a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V7a2 2 0 0 0-2-2h-2M9 5a2 2 0 0 0 2 2h2a2 2 0 0 0 2-2M9 5a2 2 0 0 1 2-2h2a2 2 0 0 1 2 2'/%3E%3C/svg%3E"); + --vp-icon-copied: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' height='20' width='20' stroke='rgba(128,128,128,1)' stroke-width='2' viewBox='0 0 24 24'%3E%3Cpath stroke-linecap='round' stroke-linejoin='round' d='M9 5H7a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V7a2 2 0 0 0-2-2h-2M9 5a2 2 0 0 0 2 2h2a2 2 0 0 0 2-2M9 5a2 2 0 0 1 2-2h2a2 2 0 0 1 2 2m-6 9 2 2 4-4'/%3E%3C/svg%3E"); +} + +/** + * Layouts + * -------------------------------------------------------------------------- */ + +:root { + --vp-layout-max-width: 1440px; +} + +/** + * Component: Code + * -------------------------------------------------------------------------- */ + +:root { + --vp-code-line-height: 1.7; + --vp-code-font-size: 0.875em; + + --vp-code-block-color: var(--vp-c-text-dark-1); + --vp-code-block-bg: #292b30; + --vp-code-block-divider-color: #000000; + + --vp-code-line-highlight-color: rgba(0, 0, 0, 0.5); + --vp-code-line-number-color: var(--vp-c-text-dark-3); + + --vp-code-line-diff-add-color: var(--vp-c-green-dimm-2); + --vp-code-line-diff-add-symbol-color: var(--vp-c-green); + + --vp-code-line-diff-remove-color: var(--vp-c-red-dimm-2); + --vp-code-line-diff-remove-symbol-color: var(--vp-c-red); + + --vp-code-line-warning-color: var(--vp-c-yellow-dimm-2); + --vp-code-line-error-color: var(--vp-c-red-dimm-2); + + --vp-code-copy-code-hover-bg: rgba(255, 255, 255, 0.05); + --vp-code-copy-code-active-text: var(--vp-c-text-dark-2); + + --vp-code-tab-divider: var(--vp-code-block-divider-color); + --vp-code-tab-text-color: var(--vp-c-text-dark-2); + --vp-code-tab-bg: var(--vp-code-block-bg); + --vp-code-tab-hover-text-color: var(--vp-c-text-dark-1); + --vp-code-tab-active-text-color: var(--vp-c-text-dark-1); + --vp-code-tab-active-bar-color: var(--vp-c-brand); +} + +.dark { + --vp-code-block-bg: #161618; +} + +/** + * Component: Button + * -------------------------------------------------------------------------- */ + +:root { + --vp-button-brand-border: var(--vp-c-brand-lighter); + --vp-button-brand-text: var(--vp-c-white); + --vp-button-brand-bg: var(--vp-c-brand); + --vp-button-brand-hover-border: var(--vp-c-brand-lighter); + --vp-button-brand-hover-text: var(--vp-c-white); + --vp-button-brand-hover-bg: var(--vp-c-brand-dark); + --vp-button-brand-active-border: var(--vp-c-brand-lighter); + --vp-button-brand-active-text: var(--vp-c-white); + --vp-button-brand-active-bg: var(--vp-c-brand-darker); + + --vp-button-alt-border: var(--vp-c-border); + --vp-button-alt-text: var(--vp-c-neutral); + --vp-button-alt-bg: var(--vp-c-mute); + --vp-button-alt-hover-border: var(--vp-c-border); + --vp-button-alt-hover-text: var(--vp-c-neutral); + --vp-button-alt-hover-bg: var(--vp-c-mute-dark); + --vp-button-alt-active-border: var(--vp-c-border); + --vp-button-alt-active-text: var(--vp-c-neutral); + --vp-button-alt-active-bg: var(--vp-c-mute-darker); + + --vp-button-sponsor-border: var(--vp-c-gray-light-3); + --vp-button-sponsor-text: var(--vp-c-text-light-2); + --vp-button-sponsor-bg: transparent; + --vp-button-sponsor-hover-border: var(--vp-c-sponsor); + --vp-button-sponsor-hover-text: var(--vp-c-sponsor); + --vp-button-sponsor-hover-bg: transparent; + --vp-button-sponsor-active-border: var(--vp-c-sponsor); + --vp-button-sponsor-active-text: var(--vp-c-sponsor); + --vp-button-sponsor-active-bg: transparent; +} + +.dark { + --vp-button-sponsor-border: var(--vp-c-gray-dark-1); + --vp-button-sponsor-text: var(--vp-c-text-dark-2); +} + +/** + * Component: Custom Block + * -------------------------------------------------------------------------- */ + +:root { + --vp-custom-block-font-size: 14px; + --vp-custom-block-code-font-size: 13px; + + --vp-custom-block-info-border: var(--vp-c-border); + --vp-custom-block-info-text: var(--vp-c-text-2); + --vp-custom-block-info-bg: var(--vp-c-bg-soft); + --vp-custom-block-info-code-bg: var(--vp-c-mute); + + --vp-custom-block-tip-border: var(--vp-c-green-dimm-3); + --vp-custom-block-tip-text: var(--vp-c-green); + --vp-custom-block-tip-bg: var(--vp-c-green-dimm-1); + --vp-custom-block-tip-code-bg: var(--vp-custom-block-tip-bg); + + --vp-custom-block-warning-border: var(--vp-c-yellow-dimm-3); + --vp-custom-block-warning-text: var(--vp-c-yellow); + --vp-custom-block-warning-bg: var(--vp-c-yellow-dimm-1); + --vp-custom-block-warning-code-bg: var(--vp-custom-block-warning-bg); + + --vp-custom-block-danger-border: var(--vp-c-red-dimm-3); + --vp-custom-block-danger-text: var(--vp-c-red); + --vp-custom-block-danger-bg: var(--vp-c-red-dimm-1); + --vp-custom-block-danger-code-bg: var(--vp-custom-block-danger-bg); + + --vp-custom-block-details-border: var(--vp-custom-block-info-border); + --vp-custom-block-details-text: var(--vp-custom-block-info-text); + --vp-custom-block-details-bg: var(--vp-custom-block-info-bg); + --vp-custom-block-details-code-bg: var(--vp-custom-block-details-bg); +} + +/** + * Component: Input + * -------------------------------------------------------------------------- */ + +:root { + --vp-input-border-color: var(--vp-c-border); + --vp-input-bg-color: var(--vp-c-bg-alt); + --vp-input-hover-border-color: var(--vp-c-gray); + + --vp-input-switch-bg-color: var(--vp-c-mute); +} + +/** + * Component: Nav + * -------------------------------------------------------------------------- */ + +:root { + --vp-nav-height: 64px; + --vp-nav-bg-color: var(--vp-c-bg); + --vp-nav-screen-bg-color: var(--vp-c-bg); +} + +/** + * Component: Local Nav + * -------------------------------------------------------------------------- */ + +:root { + --vp-local-nav-bg-color: var(--vp-c-bg); +} + +/** + * Component: Sidebar + * -------------------------------------------------------------------------- */ + +:root { + --vp-sidebar-width: 272px; + --vp-sidebar-bg-color: var(--vp-c-bg-alt); +} + +/** + * Colors Backdrop + * -------------------------------------------------------------------------- */ + +:root { + --vp-backdrop-bg-color: rgba(0, 0, 0, 0.6); +} + +/** + * Component: Home + * -------------------------------------------------------------------------- */ + +:root { + --vp-home-hero-name-color: var(--vp-c-brand); + --vp-home-hero-name-background: transparent; + + --vp-home-hero-image-background-image: none; + --vp-home-hero-image-filter: none; +} + +/** + * Component: Badge + * -------------------------------------------------------------------------- */ + +:root { + --vp-badge-info-border: var(--vp-c-border); + --vp-badge-info-text: var(--vp-c-text-2); + --vp-badge-info-bg: var(--vp-c-bg-soft); + + --vp-badge-tip-border: var(--vp-c-green-dark); + --vp-badge-tip-text: var(--vp-c-green); + --vp-badge-tip-bg: var(--vp-c-green-dimm-1); + + --vp-badge-warning-border: var(--vp-c-yellow-dark); + --vp-badge-warning-text: var(--vp-c-yellow); + --vp-badge-warning-bg: var(--vp-c-yellow-dimm-1); + + --vp-badge-danger-border: var(--vp-c-red-dark); + --vp-badge-danger-text: var(--vp-c-red); + --vp-badge-danger-bg: var(--vp-c-red-dimm-1); +} + +/** + * Component: CarbonAds + * -------------------------------------------------------------------------- */ + +:root { + --vp-carbon-ads-text-color: var(--vp-c-text-1); + --vp-carbon-ads-poweredby-color: var(--vp-c-text-2); + --vp-carbon-ads-bg-color: var(--vp-c-bg-soft); + --vp-carbon-ads-hover-text-color: var(--vp-c-brand); + --vp-carbon-ads-hover-poweredby-color: var(--vp-c-text-1); +} + +:root { + --t-color: 0.25s; + --code-tabs-nav-bg-color: var(--vp-code-tab-b); + --code-bg-color: var(--vp-code-block-bg); } diff --git a/packages/theme/src/client/utils/check.ts b/packages/theme/src/client/utils/check.ts deleted file mode 100644 index eb70b2dc..00000000 --- a/packages/theme/src/client/utils/check.ts +++ /dev/null @@ -1,3 +0,0 @@ -export const hasOwn = (val: object, key: string): key is never => { - return Object.prototype.hasOwnProperty.call(val, key) -} diff --git a/packages/theme/src/client/utils/color.ts b/packages/theme/src/client/utils/color.ts deleted file mode 100644 index d6fdcef9..00000000 --- a/packages/theme/src/client/utils/color.ts +++ /dev/null @@ -1,24 +0,0 @@ -export const colorList = [ - '#CC9999', - '#FF9900', - '#0099CC', - '#FF6666', - '#009966', - '#CC0066', - '#666699', - '#99CC33', - '#336699', - '#33CC99', - '#FF99CC', - '#FF6666', - '#CC6699', -] - -let uuid = 0 -export const getColor = (): string => { - const len = colorList.length - if (uuid > len - 1) { - uuid = 0 - } - return colorList[uuid++] -} diff --git a/packages/theme/src/client/utils/index.ts b/packages/theme/src/client/utils/index.ts index a5cf5864..7d319f6e 100644 --- a/packages/theme/src/client/utils/index.ts +++ b/packages/theme/src/client/utils/index.ts @@ -1,5 +1,4 @@ +export * from './shared.js' +export * from './normalizeLink.js' +export * from './socialIcons.js' export * from './dom.js' -export * from './resolveRepoType.js' -export * from './path.js' -export * from './color.js' -export * from './check.js' diff --git a/packages/theme/src/client/utils/normalizeLink.ts b/packages/theme/src/client/utils/normalizeLink.ts new file mode 100644 index 00000000..cddb372e --- /dev/null +++ b/packages/theme/src/client/utils/normalizeLink.ts @@ -0,0 +1,20 @@ +import { withBase } from '@vuepress/client' +import { isExternal, PATHNAME_PROTOCOL_RE } from './shared.js' + +export function normalizeLink(url: string): string { + if (isExternal(url)) { + return url.replace(PATHNAME_PROTOCOL_RE, '') + } + + const { pathname, search, hash } = new URL(url, 'http://example.com') + + const normalizedPath = + pathname.endsWith('/') || pathname.endsWith('.html') + ? url + : url.replace( + /(?:(^\.+)\/)?.*$/, + `$1${pathname.replace(/(\.md)?$/, '.html')}${search}${hash}` + ) + + return withBase(normalizedPath) +} diff --git a/packages/theme/src/client/utils/path.ts b/packages/theme/src/client/utils/path.ts deleted file mode 100644 index bcd47129..00000000 --- a/packages/theme/src/client/utils/path.ts +++ /dev/null @@ -1,3 +0,0 @@ -export const normalizePath = (url: string): string => { - return url.trim().replace(/\s+/g, '-') -} diff --git a/packages/theme/src/client/utils/resolveRepoType.ts b/packages/theme/src/client/utils/resolveRepoType.ts deleted file mode 100644 index a5497760..00000000 --- a/packages/theme/src/client/utils/resolveRepoType.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { isLinkHttp } from '@vuepress/shared' - -export type RepoType = 'Github' | 'GitLab' | 'Gitee' | 'Bitbucket' | null - -export const resolveRepoType = (repo: string): RepoType => { - if (isLinkHttp(repo) || /github\.com/.test(repo)) return 'Github' - if (/bitbucket\.org/.test(repo)) return 'Bitbucket' - if (/gitlab\.com/.test(repo)) return 'GitLab' - if (/gitee\.com/.test(repo)) return 'Gitee' - return null -} diff --git a/packages/theme/src/client/utils/shared.ts b/packages/theme/src/client/utils/shared.ts new file mode 100644 index 00000000..c7802c81 --- /dev/null +++ b/packages/theme/src/client/utils/shared.ts @@ -0,0 +1,65 @@ +export const EXTERNAL_URL_RE = /^[a-z]+:/i +export const PATHNAME_PROTOCOL_RE = /^pathname:\/\// +export const APPEARANCE_KEY = 'vuepress-theme-appearance' +export const HASH_RE = /#.*$/ +export const EXT_RE = /(index)?\.(md|html)$/ + +export const inBrowser = typeof document !== 'undefined' + +export function isActive( + currentPath: string, + matchPath?: string, + asRegex = false +): boolean { + if (matchPath === undefined) { + return false + } + + currentPath = normalize(`/${currentPath}`) + + if (asRegex) { + return new RegExp(matchPath).test(currentPath) + } + + if (normalize(matchPath) !== currentPath) { + return false + } + + const hashMatch = matchPath.match(HASH_RE) + + if (hashMatch) { + return (inBrowser ? location.hash : '') === hashMatch[0] + } + + return true +} + +export function normalize(path: string): string { + return decodeURI(path).replace(HASH_RE, '').replace(EXT_RE, '') +} + +export function isExternal(path: string): boolean { + return EXTERNAL_URL_RE.test(path) +} + +export function throttleAndDebounce(fn: () => void, delay: number): () => void { + // eslint-disable-next-line no-undef + let timeoutId: NodeJS.Timeout + let called = false + + return () => { + if (timeoutId) { + clearTimeout(timeoutId) + } + + if (!called) { + fn() + called = true + setTimeout(() => { + called = false + }, delay) + } else { + timeoutId = setTimeout(fn, delay) + } + } +} diff --git a/packages/theme/src/client/utils/socialIcons.ts b/packages/theme/src/client/utils/socialIcons.ts new file mode 100644 index 00000000..54a91e6e --- /dev/null +++ b/packages/theme/src/client/utils/socialIcons.ts @@ -0,0 +1,22 @@ +// Used under CC0 1.0 from https://simpleicons.org/ + +export const icons = { + discord: + '<svg role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><title>Discord', + facebook: + 'Facebook', + github: + 'GitHub', + instagram: + 'Instagram', + linkedin: + 'LinkedIn', + mastodon: + 'Mastodon', + slack: + 'Slack', + twitter: + 'Twitter', + youtube: + 'YouTube', +} as const diff --git a/packages/theme/src/node/alias.ts b/packages/theme/src/node/alias.ts deleted file mode 100644 index 5a036df2..00000000 --- a/packages/theme/src/node/alias.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { fs } from '@vuepress/utils' -import { resolveClient } from './utils/index.js' - -export const getAlias = (): Record => { - return Object.fromEntries( - fs - .readdirSync(resolveClient('components')) - .filter((file) => file.endsWith('.vue')) - .map((file) => [ - `@theme-plume/${file}`, - resolveClient('components', file), - ]) - ) -} diff --git a/packages/theme/src/node/autoFrontmatter.ts b/packages/theme/src/node/autoFrontmatter.ts new file mode 100644 index 00000000..06dc356d --- /dev/null +++ b/packages/theme/src/node/autoFrontmatter.ts @@ -0,0 +1,45 @@ +import { createRequire } from 'node:module' +import type { AutoFrontmatterOptions } from '@vuepress-plume/vuepress-plugin-auto-frontmatter' +import type { App } from '@vuepress/core' +import { format } from 'date-fns' +import type { PlumeThemeLocaleOptions } from '../shared/index.js' + +export default function ( + app: App, + localeOption: PlumeThemeLocaleOptions +): AutoFrontmatterOptions { + // const sourceDir = app.dir.source() + const require = createRequire(process.cwd()) + const pkg = require('./package.json') || {} + + return { + include: [], + formatter: [ + { + include: '**/{readme,README,index}.md', + formatter: {}, + }, + { + include: '*', + formatter: { + title(title: string) { + if (title) return title + return title + }, + author(author: string) { + if (author) return author + return localeOption.avatar?.name || pkg.author || '' + }, + createTime(formatTime: string, _, { createTime }) { + if (formatTime) return formatTime + return format(new Date(createTime), 'yyyy/MM/dd hh:mm:ss') + }, + permalink(permalink: string, _, { filepath }) { + if (permalink) return permalink + return permalink + }, + }, + }, + ], + } +} diff --git a/packages/theme/src/node/createPage/archive.ts b/packages/theme/src/node/createPage/archive.ts deleted file mode 100644 index 27816a0e..00000000 --- a/packages/theme/src/node/createPage/archive.ts +++ /dev/null @@ -1,18 +0,0 @@ -import type { App } from '@vuepress/core' -import { createPage } from '@vuepress/core' -import type { PlumeThemeLocaleOptions } from '../../shared/index.js' - -export const createArchivePage = async ( - app: App, - localeOption: PlumeThemeLocaleOptions -): Promise => { - const { archive } = localeOption - if (!archive) return - const archivePage = await createPage(app, { - path: archive.link, - frontmatter: { - pageType: 'archive', - }, - }) - app.pages.push(archivePage) -} diff --git a/packages/theme/src/node/createPage/category.ts b/packages/theme/src/node/createPage/category.ts deleted file mode 100644 index c884a662..00000000 --- a/packages/theme/src/node/createPage/category.ts +++ /dev/null @@ -1,18 +0,0 @@ -import type { App } from '@vuepress/core' -import { createPage } from '@vuepress/core' -import type { PlumeThemeLocaleOptions } from '../../shared/index.js' - -export const createCategoryPage = async ( - app: App, - localeOption: PlumeThemeLocaleOptions -): Promise => { - const { category } = localeOption - if (!category) return - const categoryPage = await createPage(app, { - path: category.link, - frontmatter: { - pageType: 'category', - }, - }) - app.pages.push(categoryPage) -} diff --git a/packages/theme/src/node/createPage/index.ts b/packages/theme/src/node/createPage/index.ts deleted file mode 100644 index d0a88024..00000000 --- a/packages/theme/src/node/createPage/index.ts +++ /dev/null @@ -1,14 +0,0 @@ -import type { App } from '@vuepress/core' -import type { PlumeThemeLocaleOptions } from '../../shared/index.js' -import { createArchivePage } from './archive.js' -import { createCategoryPage } from './category.js' -import { createTagPage } from './tag.js' - -export const createPage = async ( - app: App, - localeOption: PlumeThemeLocaleOptions -): Promise => { - await createCategoryPage(app, localeOption) - await createArchivePage(app, localeOption) - await createTagPage(app, localeOption) -} diff --git a/packages/theme/src/node/createPage/note.ts b/packages/theme/src/node/createPage/note.ts deleted file mode 100644 index e69de29b..00000000 diff --git a/packages/theme/src/node/createPage/tag.ts b/packages/theme/src/node/createPage/tag.ts deleted file mode 100644 index 7a98a812..00000000 --- a/packages/theme/src/node/createPage/tag.ts +++ /dev/null @@ -1,18 +0,0 @@ -import type { App } from '@vuepress/core' -import { createPage } from '@vuepress/core' -import type { PlumeThemeLocaleOptions } from '../../shared/index.js' - -export const createTagPage = async ( - app: App, - localeOption: PlumeThemeLocaleOptions -): Promise => { - const { tag } = localeOption - if (!tag) return - const tagPage = await createPage(app, { - path: tag.link, - frontmatter: { - pageType: 'tag', - }, - }) - app.pages.push(tagPage) -} diff --git a/packages/theme/src/node/defaultLocaleOption.ts b/packages/theme/src/node/defaultLocaleOption.ts deleted file mode 100644 index 4ee9cb48..00000000 --- a/packages/theme/src/node/defaultLocaleOption.ts +++ /dev/null @@ -1,11 +0,0 @@ -import type { PlumeThemeLocaleOptions } from '../shared/index.js' - -export const defaultLocaleOption: Partial = { - darkMode: true, - home: { text: '首页', link: '/' }, - article: '/article', - tag: { text: '标签', link: '/tag' }, - category: { text: '分类', link: '/category' }, - notes: { link: '/note', dir: 'notes', notes: [] }, - archive: { link: '/timeline', text: '归档' }, -} diff --git a/packages/theme/src/node/define.ts b/packages/theme/src/node/define.ts deleted file mode 100644 index 27fd166e..00000000 --- a/packages/theme/src/node/define.ts +++ /dev/null @@ -1,12 +0,0 @@ -import type { - PlumeThemeNotesItem, - PlumeThemeNotesOptions, -} from '../shared/index.js' - -export const definePlumeNotesConfig = ( - notes: PlumeThemeNotesOptions -): PlumeThemeNotesOptions => notes - -export const definePlumeNotesItemConfig = ( - item: PlumeThemeNotesItem -): PlumeThemeNotesItem => item diff --git a/packages/theme/src/node/defineConfig.ts b/packages/theme/src/node/defineConfig.ts new file mode 100644 index 00000000..4d7ca91c --- /dev/null +++ b/packages/theme/src/node/defineConfig.ts @@ -0,0 +1,10 @@ +import type { + NotesDataOptions, + NotesItem, +} from '@vuepress-plume/vuepress-plugin-notes-data' + +export const definePlumeNotesConfig = ( + notes: NotesDataOptions +): NotesDataOptions => notes + +export const definePlumeNotesItemConfig = (item: NotesItem): NotesItem => item diff --git a/packages/theme/src/node/extendsPage.ts b/packages/theme/src/node/extendsPage.ts deleted file mode 100644 index ff527520..00000000 --- a/packages/theme/src/node/extendsPage.ts +++ /dev/null @@ -1,60 +0,0 @@ -import type { Page } from '@vuepress/core' -import { path } from '@vuepress/utils' -import type { - CategoryData, - PlumeThemeLocaleOptions, - PlumeThemePageData, - PlumeThemePostFrontmatter, -} from '../shared/index.js' -import { formatDate } from './utils/index.js' - -function normalizePath(filepath: string): string { - return filepath.replace(/^\//, '') -} - -let uuid = 10000 -const cache: Record = {} -export const extendsPage = ( - page: Page>, - localeOption: PlumeThemeLocaleOptions -): void => { - const pagePath = page.filePathRelative || '' - if (page.frontmatter.pageType) return - const { notes } = localeOption - const frontmatter = page.frontmatter as PlumeThemePostFrontmatter - let category: CategoryData = [] - if (notes && notes.dir && pagePath.startsWith(normalizePath(notes.dir))) { - page.data.isNote = true - const filepath = path.relative(notes.dir, pagePath) - if (filepath) { - const note = filepath.split('/')[0] - const currentNote = notes.notes.find(({ link }) => - normalizePath(link).startsWith(note) - ) - if (currentNote) { - !cache[currentNote.text] && (cache[currentNote.text] = uuid++) - category.push({ - type: cache[currentNote.text], - name: currentNote.text, - }) - } - } - } else { - category = pagePath - .split('/') - .slice(0, -1) - .map((category) => { - const match = category.match(/^(\d+)?(?:\.?)([^]+)$/) || [] - !cache[match[2]] && !match[1] && (cache[match[2]] = uuid++) - return { - type: Number(match[1] || cache[match[2]]), - name: match[2], - } - }) - } - page.data.category = category || [] - page.data.createTime = formatDate(frontmatter.createTime) - page.data.tags = frontmatter.tags || [] - page.data.path = page.path - page.data.author = frontmatter.author || '' -} diff --git a/packages/theme/src/node/generateFrontmatter.ts b/packages/theme/src/node/generateFrontmatter.ts deleted file mode 100644 index 09566804..00000000 --- a/packages/theme/src/node/generateFrontmatter.ts +++ /dev/null @@ -1,147 +0,0 @@ -import { createRequire } from 'module' -import type { App } from '@vuepress/core' -import { fs, path } from '@vuepress/utils' -import chokidar from 'chokidar' -import { format } from 'date-fns' -import matter from 'gray-matter' -import jsonToYaml from 'json2yaml' -import { customAlphabet } from 'nanoid' -import type { - PlumeThemeLocaleOptions, - PlumeThemeNotesItem, - PlumeThemeNotesOptions, -} from '../shared/index.js' -import type { MarkdownFile } from './utils/index.js' -import { readFile, readFileList } from './utils/index.js' - -const require = createRequire(import.meta.url) - -export interface GenerateFrontmatter { - formatFrontmatter: () => Promise - watchNewMarkDown: (app: App, watchers: unknown) => void -} - -const nanoid = customAlphabet('0123456789abcdefghijklmnopqrstuvwxyz', 8) - -const isReadme = function (filepath: string): boolean { - return /((readme)|(index))\.md$/i.test(filepath) -} - -export const generateFrontmatter = ( - sourceDir: string, - localeOption: PlumeThemeLocaleOptions -): GenerateFrontmatter => { - const { article, notes } = localeOption - const { - notes: noteList, - link: notesLink, - dir: notesDir, - } = notes as PlumeThemeNotesOptions - const matterTask: Record = { - title: ({ filepath }: MarkdownFile, title: string): string => { - if (title) return title - const file = path.relative(sourceDir, filepath) - let currentNote: PlumeThemeNotesItem | undefined - if ( - notesDir && - file.startsWith(notesDir.replace(/^\//, '')) && - isReadme(filepath) && - (currentNote = noteList.find((note) => - file.startsWith(path.join(notesDir.replace(/^\//, ''), note.dir)) - )) - ) { - return currentNote.text || currentNote.dir - } - const basename = path.basename(filepath) - if (isReadme(basename)) { - return path.dirname(filepath).split('/').slice(-1)[0] - } - return basename.replace(/^\d+\./, '').replace(path.extname(filepath), '') - }, - createTime: ({ createTime }: MarkdownFile, formatTime: string): string => { - if (formatTime) return formatTime - return format(new Date(createTime), 'yyyy/MM/dd hh:mm:ss') - }, - author: (_: any, author: string): string => { - if (author) return author - const pkg = require(path.join(process.cwd(), 'package.json')) - return pkg.author - }, - // 自动生成永久链接 - permalink: ({ filepath }: MarkdownFile, permalink: string): string => { - const file = path.relative(sourceDir, filepath) - if (permalink) { - if (notes && notesDir && file.startsWith(notesDir.replace(/^\//, ''))) { - return permalink - } else { - if ( - article && - permalink.startsWith('/' + article.replace(/^\//, '')) - ) { - return permalink - } else { - const per = permalink.split('/') - return path.join(article, per[per.length - 1]) - } - } - } - let prefix = '' - if (notes) { - // 表示是以笔记开头的 - if (notesDir && file.startsWith(notesDir.replace(/^\//, ''))) { - prefix = notesLink || '' - const currentNote = noteList.find((note) => - file.startsWith(path.join(notesDir.replace(/^\//, ''), note.dir)) - ) - currentNote && (prefix = path.join(prefix, currentNote.link)) - } else { - prefix = article as string - } - } else { - prefix = article as string - } - return path.join(prefix, isReadme(filepath) ? '' : nanoid(), '/') - }, - } - - const formatMarkdown = async (file: MarkdownFile): Promise => { - const { data, content } = matter(file.content) - for (const key of Object.keys(matterTask)) { - const value = await matterTask[key](file, data[key]) - data[key] = value ?? data[key] - } - const yaml = jsonToYaml - .stringify(data) - .replace(/\n\s{2}/g, '\n') - .replace(/"/g, '') - return `${yaml}---\n${content}` - } - - const formatFrontmatter = async (): Promise => { - const files = readFileList(sourceDir) - for (const file of files) { - const relativePath = path.relative(sourceDir, file.filepath) - if (isReadme(relativePath)) return - const content = await formatMarkdown(file) - await fs.writeFile(file.filepath, content, 'utf-8') - } - } - - const watchNewMarkDown = (app: App, watchers: any): void => { - const watcher = chokidar.watch('**/*.md', { - ignored: /node_modules/, - cwd: app.options.source, - ignoreInitial: true, - }) - watcher.on('add', async (file, stat) => { - const filepath = path.join(app.options.source, file) - stat = stat || fs.statSync(filepath) - const newFile = readFile(filepath, stat) - const content = await formatMarkdown(newFile) - fs.writeFileSync(filepath, content, 'utf-8') - }) - watchers.push(watcher) - } - - return { formatFrontmatter, watchNewMarkDown } -} diff --git a/packages/theme/src/node/index.ts b/packages/theme/src/node/index.ts index 6cb4b71c..a89a69bb 100644 --- a/packages/theme/src/node/index.ts +++ b/packages/theme/src/node/index.ts @@ -1,18 +1,8 @@ -import type { - PlumeThemeNotesItem, - PlumeThemeNotesOptions, - PlumeThemeOptions, - PlumeThemeSidebarConfigOptions, -} from '../shared/index.js' -import { themePlume } from './theme.js' -export * from './theme.js' -export * from './define.js' +import { plumeTheme } from './theme.js' -export { - PlumeThemeOptions, - PlumeThemeNotesOptions, - PlumeThemeNotesItem, - PlumeThemeSidebarConfigOptions, -} +export * from './defineConfig.js' +export * from '../shared/index.js' -export default themePlume +export { plumeTheme } + +export default plumeTheme diff --git a/packages/theme/src/node/plugins.ts b/packages/theme/src/node/plugins.ts new file mode 100644 index 00000000..8e65c600 --- /dev/null +++ b/packages/theme/src/node/plugins.ts @@ -0,0 +1,171 @@ +import { autoFrontmatterPlugin } from '@vuepress-plume/vuepress-plugin-auto-frontmatter' +import { baiduTongjiPlugin } from '@vuepress-plume/vuepress-plugin-baidu-tongji' +import { blogDataPlugin } from '@vuepress-plume/vuepress-plugin-blog-data' +import { caniusePlugin } from '@vuepress-plume/vuepress-plugin-caniuse' +import { copyCodePlugin } from '@vuepress-plume/vuepress-plugin-copy-code' +import { notesDataPlugin } from '@vuepress-plume/vuepress-plugin-notes-data' +import type { App, PluginConfig } from '@vuepress/core' +import { activeHeaderLinksPlugin } from '@vuepress/plugin-active-header-links' +import { docsearchPlugin } from '@vuepress/plugin-docsearch' +import { externalLinkIconPlugin } from '@vuepress/plugin-external-link-icon' +import { gitPlugin } from '@vuepress/plugin-git' +import { mediumZoomPlugin } from '@vuepress/plugin-medium-zoom' +import { nprogressPlugin } from '@vuepress/plugin-nprogress' +import { palettePlugin } from '@vuepress/plugin-palette' +import { prismjsPlugin } from '@vuepress/plugin-prismjs' +import { searchPlugin } from '@vuepress/plugin-search' +import { shikiPlugin } from '@vuepress/plugin-shiki' +import { themeDataPlugin } from '@vuepress/plugin-theme-data' +import { commentPlugin } from 'vuepress-plugin-comment2' +import { mdEnhancePlugin } from 'vuepress-plugin-md-enhance' +import { seoPlugin } from 'vuepress-plugin-seo2' +import { sitemapPlugin } from 'vuepress-plugin-sitemap2' +import type { + PlumeThemeLocaleOptions, + PlumeThemePluginOptions, +} from '../shared/index.js' +import autoFrontmatter from './autoFrontmatter.js' + +export const setupPlugins = ( + app: App, + options: PlumeThemePluginOptions, + localeOptions: PlumeThemeLocaleOptions +): PluginConfig => { + const isProd = !app.env.isDev + + return [ + palettePlugin({ preset: 'sass' }), + themeDataPlugin({ + themeData: { + ...localeOptions, + notes: localeOptions.notes + ? { dir: localeOptions.notes.dir, link: localeOptions.notes.link } + : undefined, + } as any, + }), + autoFrontmatterPlugin(autoFrontmatter(app, localeOptions)), + blogDataPlugin({ + include: ['**/*.md'], + exclude: ['**/{README,index}.md', 'notes/**'], + sortBy: 'createTime', + excerpt: true, + extendBlogData(page: any) { + return { + categoryList: page.data.categoryList, + tags: page.frontmatter.tags, + sticky: page.frontmatter.sticky, + createTime: page.data.frontmatter.createTime, + } + }, + }), + localeOptions.notes ? notesDataPlugin(localeOptions.notes) : [], + activeHeaderLinksPlugin({ + headerLinkSelector: 'a.outline-link', + headerAnchorSelector: '.header-anchor', + delay: 200, + offset: 20, + }), + + options.nprogress !== false ? nprogressPlugin() : [], + + options.git !== false + ? gitPlugin({ + createdTime: true, + updatedTime: true, + contributors: false, + }) + : [], + + options.mediumZoom !== false + ? mediumZoomPlugin({ + selector: '.plume-content > img, .plume-content :not(a) > img', + zoomOptions: { + background: 'var(--c-bg)', + }, + delay: 300, + }) + : [], + + options.caniuse !== false + ? caniusePlugin( + options.caniuse || { + mode: 'embed', + } + ) + : [], + + options.externalLinkIcon !== false + ? externalLinkIconPlugin({ + locales: Object.entries(localeOptions.locales || {}).reduce( + (result: Record, [key, value]) => { + result[key] = { + openInNewWindow: + value.openInNewWindow ?? localeOptions.openInNewWindow, + } + return result + }, + {} + ), + }) + : [], + + options.search !== false ? searchPlugin(options.search) : [], + options.docsearch !== false && !options.search + ? docsearchPlugin(options.docsearch!) + : [], + options.prismjs !== false && !isProd ? prismjsPlugin() : [], + options.prismjs !== false && isProd + ? shikiPlugin({ + theme: 'material-palenight', + }) + : [], + options.copyCode !== false + ? copyCodePlugin({ + selector: '.plume-content div[class*="language-"] pre', + locales: { + '/': { + copy: '复制成功', + hint: '复制代码', + }, + }, + ...options.copyCode, + }) + : [], + + options.markdownEnhance !== false + ? mdEnhancePlugin( + Object.assign( + { + container: true, // info note tip warning danger details + codetabs: true, + tabs: true, + align: true, + mark: true, + tasklist: true, + demo: true, + attrs: true, + }, + options.markdownEnhance || {} + ) + ) + : [], + + options.comment !== false ? commentPlugin(options.comment || {}) : [], + + options.baiduTongji !== false && options.baiduTongji?.key + ? baiduTongjiPlugin(options.baiduTongji) + : [], + + options.sitemap !== false && localeOptions.hostname && isProd + ? sitemapPlugin({ + hostname: localeOptions.hostname, + }) + : [], + options.seo !== false && localeOptions.hostname && isProd + ? seoPlugin({ + hostname: localeOptions.hostname || '', + author: localeOptions.avatar?.name, + }) + : [], + ] +} diff --git a/packages/theme/src/node/plugins/activeHeaderLink.ts b/packages/theme/src/node/plugins/activeHeaderLink.ts deleted file mode 100644 index fc9dcda8..00000000 --- a/packages/theme/src/node/plugins/activeHeaderLink.ts +++ /dev/null @@ -1,11 +0,0 @@ -import type { PluginObject } from '@vuepress/core' -import { activeHeaderLinksPlugin } from '@vuepress/plugin-active-header-links' - -export const resolveActiveHeaderLink = (): PluginObject => { - return activeHeaderLinksPlugin({ - headerLinkSelector: 'a.theme-plume-toc-link', - headerAnchorSelector: '.header-anchor', - delay: 200, - offset: 20, - }) -} diff --git a/packages/theme/src/node/plugins/baiduTongji.ts b/packages/theme/src/node/plugins/baiduTongji.ts deleted file mode 100644 index 446aa47b..00000000 --- a/packages/theme/src/node/plugins/baiduTongji.ts +++ /dev/null @@ -1,12 +0,0 @@ -// 8a4e65dd3f2d30e64c828481295e09d1 -import type { BaiduTongjiOptions } from '@vuepress-plume/vuepress-plugin-baidu-tongji' -import { baiduTongjiPlugin } from '@vuepress-plume/vuepress-plugin-baidu-tongji' -import type { Plugin } from '@vuepress/core' -import type { PlumeThemePluginOptions } from '../../shared/index.js' - -export const resolveBaiduTongji = ({ - baiduTongji, -}: PlumeThemePluginOptions): Plugin => { - if (baiduTongji === false || !baiduTongji?.key) return [] as unknown as Plugin - return baiduTongjiPlugin(baiduTongji as BaiduTongjiOptions) -} diff --git a/packages/theme/src/node/plugins/caniuse.ts b/packages/theme/src/node/plugins/caniuse.ts deleted file mode 100644 index 44834a34..00000000 --- a/packages/theme/src/node/plugins/caniuse.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { caniusePlugin } from '@vuepress-plume/vuepress-plugin-caniuse' -import type { Plugin } from '@vuepress/core' -import type { PlumeThemePluginOptions } from '../../shared/index.js' - -export const resolveCanIUse = (plugins: PlumeThemePluginOptions): Plugin => { - if (plugins.caniuse === false) return [] as unknown as Plugin - return caniusePlugin( - plugins.caniuse || { - mode: 'embed', - } - ) -} diff --git a/packages/theme/src/node/plugins/comment.ts b/packages/theme/src/node/plugins/comment.ts deleted file mode 100644 index 30c5c899..00000000 --- a/packages/theme/src/node/plugins/comment.ts +++ /dev/null @@ -1,9 +0,0 @@ -import type { Plugin } from '@vuepress/core' -import { commentPlugin } from 'vuepress-plugin-comment2' -import type { CommentOptions } from 'vuepress-plugin-comment2' -import type { PlumeThemePluginOptions } from '../../shared/index.js' - -export const resolveComment = (plugins: PlumeThemePluginOptions): Plugin => { - if (!plugins.comment) return [] as unknown as Plugin - return commentPlugin(plugins.comment as CommentOptions) -} diff --git a/packages/theme/src/node/plugins/copyCode.ts b/packages/theme/src/node/plugins/copyCode.ts deleted file mode 100644 index f75f7361..00000000 --- a/packages/theme/src/node/plugins/copyCode.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { copyCodePlugin } from '@vuepress-plume/vuepress-plugin-copy-code' -import type { Plugin } from '@vuepress/core' -import type { PlumeThemePluginOptions } from '../../shared/index.js' - -export const resolveCopyCode = (plugins: PlumeThemePluginOptions): Plugin => { - if (plugins.copyCode === false) return [] as unknown as Plugin - return copyCodePlugin( - plugins.copyCode || { - selector: '.page-content div[class*="language-"] pre', - locales: { - '/': { - copy: '复制成功', - hint: '复制代码', - }, - }, - } - ) -} diff --git a/packages/theme/src/node/plugins/externalLinkIcon.ts b/packages/theme/src/node/plugins/externalLinkIcon.ts deleted file mode 100644 index 1e7100be..00000000 --- a/packages/theme/src/node/plugins/externalLinkIcon.ts +++ /dev/null @@ -1,25 +0,0 @@ -import type { Plugin } from '@vuepress/core' -import { externalLinkIconPlugin } from '@vuepress/plugin-external-link-icon' -import type { - PlumeThemeLocaleOptions, - PlumeThemePluginOptions, -} from '../../shared/index.js' - -export const resolveExternalLinkIconPlugin = ( - plugins: PlumeThemePluginOptions, - localeOptions: PlumeThemeLocaleOptions -): Plugin => { - if (plugins.externalLinkIcon === false) return [] as unknown as Plugin - return externalLinkIconPlugin({ - locales: Object.entries(localeOptions.locales || {}).reduce( - (result: Record, [key, value]) => { - result[key] = { - openInNewWindow: - value.openInNewWindow ?? localeOptions.openInNewWindow, - } - return result - }, - {} - ), - }) -} diff --git a/packages/theme/src/node/plugins/git.ts b/packages/theme/src/node/plugins/git.ts deleted file mode 100644 index 71b9dfb6..00000000 --- a/packages/theme/src/node/plugins/git.ts +++ /dev/null @@ -1,14 +0,0 @@ -import type { Plugin } from '@vuepress/core' -import { gitPlugin } from '@vuepress/plugin-git' -import type { PlumeThemePluginOptions } from '../../shared/index.js' - -const isProd = process.env.NODE_ENV === 'production' - -export const resolveGit = (plugins: PlumeThemePluginOptions): Plugin => { - if (plugins.git === false || !isProd) return [] as unknown as Plugin - return gitPlugin({ - createdTime: true, - updatedTime: true, - contributors: false, - }) -} diff --git a/packages/theme/src/node/plugins/index.ts b/packages/theme/src/node/plugins/index.ts deleted file mode 100644 index 2db321d2..00000000 --- a/packages/theme/src/node/plugins/index.ts +++ /dev/null @@ -1,46 +0,0 @@ -import type { PluginConfig } from '@vuepress/core' -import type { - PlumeThemeLocaleOptions, - PlumeThemePluginOptions, -} from '../../shared/index.js' -import { resolveActiveHeaderLink } from './activeHeaderLink.js' -import { resolveBaiduTongji } from './baiduTongji.js' -import { resolveCanIUse } from './caniuse.js' -import { resolveComment } from './comment.js' -import { resolveCopyCode } from './copyCode.js' -import { resolveExternalLinkIconPlugin } from './externalLinkIcon.js' -import { resolveGit } from './git.js' -import { resolveMarkdownEnhance } from './markdownEnhance.js' -import { resolveMediumZoom } from './mediumZoom.js' -import { resolveNprogress } from './nprogress.js' -import { resolvePalette } from './palette.js' -import { resolvePrismjs } from './prismjs.js' -import { resolveSearch } from './search.js' -import { resolveSeo } from './seo.js' -import { resolveSitemap } from './sitemap.js' -import { resolveThemeData } from './themeData.js' - -export const getPlugins = ( - plugins: PlumeThemePluginOptions, - localeOptions: PlumeThemeLocaleOptions -): PluginConfig => { - const resolvePlugins: PluginConfig = [ - resolvePalette(), - resolveActiveHeaderLink(), - resolveNprogress(plugins), - resolveMediumZoom(plugins), - resolveCanIUse(plugins), - resolveExternalLinkIconPlugin(plugins, localeOptions), - resolveSearch(plugins), - resolvePrismjs(plugins), - resolveGit(plugins), - resolveCopyCode(plugins), - resolveMarkdownEnhance(plugins), - resolveComment(plugins), - resolveSitemap(plugins, localeOptions), - resolveSeo(plugins, localeOptions), - resolveThemeData(localeOptions), - resolveBaiduTongji(plugins), - ] - return resolvePlugins -} diff --git a/packages/theme/src/node/plugins/markdownEnhance.ts b/packages/theme/src/node/plugins/markdownEnhance.ts deleted file mode 100644 index ec17c30a..00000000 --- a/packages/theme/src/node/plugins/markdownEnhance.ts +++ /dev/null @@ -1,24 +0,0 @@ -import type { Plugin } from '@vuepress/core' -import { mdEnhancePlugin } from 'vuepress-plugin-md-enhance' -import type { PlumeThemePluginOptions } from '../../shared/index.js' - -export const resolveMarkdownEnhance = ( - plugins: PlumeThemePluginOptions -): Plugin => { - if (plugins.markdownEnhance === false) return [] as unknown as Plugin - return mdEnhancePlugin( - Object.assign( - { - container: true, // info note tip warning danger details - codetabs: true, - tabs: true, - align: true, - mark: true, - tasklist: true, - demo: true, - attrs: true, - }, - plugins.markdownEnhance || {} - ) - ) -} diff --git a/packages/theme/src/node/plugins/mediumZoom.ts b/packages/theme/src/node/plugins/mediumZoom.ts deleted file mode 100644 index bd27d968..00000000 --- a/packages/theme/src/node/plugins/mediumZoom.ts +++ /dev/null @@ -1,12 +0,0 @@ -import type { Plugin } from '@vuepress/core' -import { mediumZoomPlugin } from '@vuepress/plugin-medium-zoom' -import type { PlumeThemePluginOptions } from '../../shared/index.js' - -export const resolveMediumZoom = (plugins: PlumeThemePluginOptions): Plugin => { - if (plugins.mediumZoom === false) return [] as unknown as Plugin - return mediumZoomPlugin({ - selector: '.page-content > img, .page-content :not(a) > img', - zoomOptions: {}, - delay: 300, - }) -} diff --git a/packages/theme/src/node/plugins/nprogress.ts b/packages/theme/src/node/plugins/nprogress.ts deleted file mode 100644 index f24b8820..00000000 --- a/packages/theme/src/node/plugins/nprogress.ts +++ /dev/null @@ -1,8 +0,0 @@ -import type { Plugin } from '@vuepress/core' -import { nprogressPlugin } from '@vuepress/plugin-nprogress' -import type { PlumeThemePluginOptions } from '../../shared/index.js' - -export const resolveNprogress = (plugins: PlumeThemePluginOptions): Plugin => { - if (plugins.nprogress === false) return [] as unknown as Plugin - return nprogressPlugin() -} diff --git a/packages/theme/src/node/plugins/palette.ts b/packages/theme/src/node/plugins/palette.ts deleted file mode 100644 index a1e2cd94..00000000 --- a/packages/theme/src/node/plugins/palette.ts +++ /dev/null @@ -1,6 +0,0 @@ -import type { Plugin } from '@vuepress/core' -import { palettePlugin } from '@vuepress/plugin-palette' - -export const resolvePalette = (): Plugin => { - return palettePlugin({ preset: 'sass' }) -} diff --git a/packages/theme/src/node/plugins/prismjs.ts b/packages/theme/src/node/plugins/prismjs.ts deleted file mode 100644 index ca6a3ff2..00000000 --- a/packages/theme/src/node/plugins/prismjs.ts +++ /dev/null @@ -1,8 +0,0 @@ -import type { Plugin } from '@vuepress/core' -import { prismjsPlugin } from '@vuepress/plugin-prismjs' -import type { PlumeThemePluginOptions } from '../../shared/index.js' - -export const resolvePrismjs = (plugins: PlumeThemePluginOptions): Plugin => { - if (plugins.prismjs === false) return [] as unknown as Plugin - return prismjsPlugin() -} diff --git a/packages/theme/src/node/plugins/search.ts b/packages/theme/src/node/plugins/search.ts deleted file mode 100644 index f39765fb..00000000 --- a/packages/theme/src/node/plugins/search.ts +++ /dev/null @@ -1,14 +0,0 @@ -import type { Plugin } from '@vuepress/core' -import { docsearchPlugin } from '@vuepress/plugin-docsearch' -import { searchPlugin } from '@vuepress/plugin-search' -import type { PlumeThemePluginOptions } from '../../shared/index.js' - -export const resolveSearch = (plugins: PlumeThemePluginOptions): Plugin => { - if (plugins.search) { - return searchPlugin(plugins.search) - } - if (plugins.docsearch) { - return docsearchPlugin(plugins.docsearch) - } - return [] as unknown as Plugin -} diff --git a/packages/theme/src/node/plugins/seo.ts b/packages/theme/src/node/plugins/seo.ts deleted file mode 100644 index 3329f9e1..00000000 --- a/packages/theme/src/node/plugins/seo.ts +++ /dev/null @@ -1,20 +0,0 @@ -import type { Plugin } from '@vuepress/core' -import { seoPlugin } from 'vuepress-plugin-seo2' -import type { - PlumeThemeLocaleOptions, - PlumeThemePluginOptions, -} from '../../shared/index.js' - -const isProd = process.env.NODE_ENV === 'production' - -export const resolveSeo = ( - plugins: PlumeThemePluginOptions, - localeOptions: PlumeThemeLocaleOptions -): Plugin => { - if (plugins.sitemap === false || !localeOptions.hostname || !isProd) - return [] as unknown as Plugin - return seoPlugin({ - hostname: localeOptions.hostname || '', - author: localeOptions.avatar?.name, - }) -} diff --git a/packages/theme/src/node/plugins/sitemap.ts b/packages/theme/src/node/plugins/sitemap.ts deleted file mode 100644 index b13e52bf..00000000 --- a/packages/theme/src/node/plugins/sitemap.ts +++ /dev/null @@ -1,19 +0,0 @@ -import type { Plugin } from '@vuepress/core' -import { sitemapPlugin } from 'vuepress-plugin-sitemap2' -import type { - PlumeThemeLocaleOptions, - PlumeThemePluginOptions, -} from '../../shared/index.js' - -const isProd = process.env.NODE_ENV === 'production' - -export const resolveSitemap = ( - plugins: PlumeThemePluginOptions, - localeOptions: PlumeThemeLocaleOptions -): Plugin => { - if (plugins.sitemap === false || !localeOptions.hostname || !isProd) - return [] as unknown as Plugin - return sitemapPlugin({ - hostname: localeOptions.hostname, - }) -} diff --git a/packages/theme/src/node/plugins/themeData.ts b/packages/theme/src/node/plugins/themeData.ts deleted file mode 100644 index c6ddc929..00000000 --- a/packages/theme/src/node/plugins/themeData.ts +++ /dev/null @@ -1,8 +0,0 @@ -import type { PluginObject } from '@vuepress/core' -import { themeDataPlugin } from '@vuepress/plugin-theme-data' -import type { PlumeThemeLocaleOptions } from '../../shared/index.js' -export const resolveThemeData = ( - localeOptions: PlumeThemeLocaleOptions -): PluginObject => { - return themeDataPlugin({ themeData: localeOptions }) -} diff --git a/packages/theme/src/node/prepared/index.ts b/packages/theme/src/node/prepared/index.ts deleted file mode 100644 index 0718e219..00000000 --- a/packages/theme/src/node/prepared/index.ts +++ /dev/null @@ -1,21 +0,0 @@ -import type { App } from '@vuepress/core' -import type { PlumeThemeLocaleOptions } from '../../shared/index.js' -import { preparedPostIndex, watchPostIndex } from './postIndex.js' -import { preparedSidebarIndex, watchSidebarIndex } from './sidebarIndex.js' - -export const onPrepared = async ( - app: App, - localeOption: PlumeThemeLocaleOptions -): Promise => { - await preparedPostIndex(app, localeOption) - await preparedSidebarIndex(app, localeOption) -} - -export const preparedWatch = ( - app: App, - watchers: any[], - localeOption: PlumeThemeLocaleOptions -): void => { - watchPostIndex(app, watchers, localeOption) - watchSidebarIndex(app, watchers, localeOption) -} diff --git a/packages/theme/src/node/prepared/postIndex.ts b/packages/theme/src/node/prepared/postIndex.ts deleted file mode 100644 index 98af43e8..00000000 --- a/packages/theme/src/node/prepared/postIndex.ts +++ /dev/null @@ -1,87 +0,0 @@ -import type { App, Page } from '@vuepress/core' -import * as chokidar from 'chokidar' -import type { - PlumeThemeLocaleOptions, - PlumeThemePageData, - PlumeThemePostFrontmatter, - PostIndex, - PostItem, -} from '../../shared/index.js' -import { getCreateTime } from '../utils/index.js' - -const HMR_CODE = ` -if (import.meta.webpackHot) { - import.meta.webpackHot.accept() - if (__VUE_HMR_RUNTIME__.updatePostIndex) { - __VUE_HMR_RUNTIME__.updatePostIndex(postIndex) - } -} - -if (import.meta.hot) { - import.meta.hot.accept(({ postIndex }) => { - __VUE_HMR_RUNTIME__.updatePostIndex(postIndex) - }) -} -` - -export const preparedPostIndex = async ( - app: App, - localeOption: PlumeThemeLocaleOptions -): Promise => { - const postIndex: PostIndex = (app.pages as Page[]) - .filter((page) => { - return ( - !!page.pathInferred && - !!page.filePath && - page.path !== '/' && - page.path !== '/404.html' - ) - }) - .sort((left, right) => { - const leftMatter = left.frontmatter as PlumeThemePostFrontmatter - const rightMatter = right.frontmatter as PlumeThemePostFrontmatter - const leftTime = getCreateTime(leftMatter.createTime || '') - const rightTime = getCreateTime(rightMatter.createTime || '') - return leftTime < rightTime ? 1 : -1 - }) - .map((page: Page) => { - const frontmatter = page.frontmatter as PlumeThemePostFrontmatter - return { - title: page.title, - path: page.path, - excerpt: page.excerpt, - tags: frontmatter.tags || [], - createTime: page.data.createTime, - author: frontmatter.author, - sticky: frontmatter.sticky, - article: frontmatter.article, - category: page.data.category, - isNote: page.data.isNote, - banner: frontmatter.banner, - } as PostItem - }) - - let content = ` -export const postIndex = ${JSON.stringify(postIndex, null, 2)} -` - if (app.env.isDev) { - content += HMR_CODE - } - - await app.writeTemp('internal/postIndex.js', content) -} - -export const watchPostIndex = ( - app: App, - watchers: any[], - localeOption: PlumeThemeLocaleOptions -): void => { - const watcher = chokidar.watch('pages/**/*', { - cwd: app.dir.temp(), - ignoreInitial: true, - }) - watcher.on('add', () => preparedPostIndex(app, localeOption)) - watcher.on('change', () => preparedPostIndex(app, localeOption)) - watcher.on('unlink', () => preparedPostIndex(app, localeOption)) - watchers.push(watcher) -} diff --git a/packages/theme/src/node/prepared/sidebarIndex.ts b/packages/theme/src/node/prepared/sidebarIndex.ts deleted file mode 100644 index 5fe77fec..00000000 --- a/packages/theme/src/node/prepared/sidebarIndex.ts +++ /dev/null @@ -1,177 +0,0 @@ -import type { App, Page } from '@vuepress/core' -import { path } from '@vuepress/utils' -import * as chokidar from 'chokidar' -import type { - PlumeThemeLocaleOptions, - PlumeThemeNotesItem, - PlumeThemeNotesOptions, - PlumeThemePageData, - PlumeThemeSidebarConfigOptions, - SidebarItem, - SidebarOptions, -} from '../../shared/index.js' - -const HMR_CODE = ` -if (import.meta.webpackHot) { - import.meta.webpackHot.accept() - if (__VUE_HMR_RUNTIME__.updateSidebarIndex) { - __VUE_HMR_RUNTIME__.updatePostIndex(sidebarIndex) - } -} - -if (import.meta.hot) { - import.meta.hot.accept(({ sidebarIndex }) => { - __VUE_HMR_RUNTIME__.updateSidebarIndex(sidebarIndex) - }) -} -` - -interface NotePage { - relativePath: string[] - title: string - link: string -} - -export const preparedSidebarIndex = async ( - app: App, - { notes }: PlumeThemeLocaleOptions -): Promise => { - const pages = app.pages as Page[] - if (notes === false) return - const { - notes: noteList, - dir: rootDir, - link: rootLink, - } = notes as PlumeThemeNotesOptions - const notePageList: NotePage[] = pages - .filter((page) => page.filePathRelative?.startsWith(rootDir as string)) - .map((page) => { - return { - relativePath: page.filePathRelative?.split('/').slice(1) || [], - title: page.title, - link: page.path, - } - }) - - const sidebarMap: Record = {} - noteList.forEach((note) => { - sidebarMap[path.join('/', rootLink, note.link)] = noteSidebar( - note, - notePageList.filter( - (page) => - page.relativePath?.[0] === note.dir.trim().replace(/^\/|\/$/g, '') - ) - ) - }) - - let content = ` -export const sidebarIndex = ${JSON.stringify(sidebarMap, null, 2)} -` - if (app.env.isDev) { - content += HMR_CODE - } - - await app.writeTemp('internal/sidebarIndex.js', content) -} - -function noteSidebar( - note: PlumeThemeNotesItem, - notePageList: NotePage[] -): SidebarOptions { - if (note.sidebar === undefined) return [] - if (note.sidebar === 'auto') { - return autoSidebar(note, notePageList) - } - return sidebarByConfig( - note.text, - note.link, - note.dir, - note.sidebar, - notePageList - ) -} - -function autoSidebar( - note: PlumeThemeNotesItem, - notePageList: NotePage[] -): SidebarOptions { - return [] -} - -function sidebarByConfig( - text: string, - link: string | undefined, - dir: string, - sidebarConfig: PlumeThemeSidebarConfigOptions, - notePageList: NotePage[] -): SidebarOptions { - return sidebarConfig.map((sidebar) => { - if (typeof sidebar === 'string') { - const current = findNotePage(sidebar, dir, notePageList) - return { - text: current ? current.title : text, - link: current ? current.link : '', - children: [], - } as SidebarItem - } else { - link = path.join(link || '', sidebar.link || '') - const current = sidebar.link - ? findNotePage(sidebar.link, dir, notePageList) - : undefined - return { - text: sidebar.text || sidebar.dir || '', - link: current?.link, - children: sidebarByConfig( - sidebar.text, - sidebar.link, - path.join(dir, sidebar.dir || ''), - sidebar.children, - notePageList - ), - } - } - }) -} - -function findNotePage( - sidebar: string, - dir: string, - notePageList: NotePage[] -): NotePage | undefined { - if (sidebar === '' || sidebar === 'README.md' || sidebar === 'index.md') { - return notePageList.find((page) => { - const relative = page.relativePath.join('/') - return ( - relative === path.join(dir, 'README.md') || - relative === path.join(dir, 'index.md') - ) - }) - } else { - return notePageList.find((page) => { - const relative = page.relativePath.join('/') - return ( - relative === path.join(dir, sidebar) || - relative === path.join(dir, sidebar + '.md') || - page.link === sidebar - ) - }) - } -} - -export const watchSidebarIndex = ( - app: App, - watchers: any[], - localeOption: PlumeThemeLocaleOptions -): void => { - if (!localeOption.notes || !localeOption.notes.dir) return - const dir = path.join('pages', localeOption.notes.dir, '**/*') - const watcher = chokidar.watch(dir, { - cwd: app.dir.temp(), - ignoreInitial: true, - }) - - watcher.on('add', () => preparedSidebarIndex(app, localeOption)) - watcher.on('change', () => preparedSidebarIndex(app, localeOption)) - watcher.on('unlink', () => preparedSidebarIndex(app, localeOption)) - watchers.push(watcher) -} diff --git a/packages/theme/src/node/setupPages.ts b/packages/theme/src/node/setupPages.ts new file mode 100644 index 00000000..d45bc209 --- /dev/null +++ b/packages/theme/src/node/setupPages.ts @@ -0,0 +1,52 @@ +import type { App, Page } from '@vuepress/core' +import { createPage } from '@vuepress/core' +import type { + PageCategoryData, + PlumeThemeLocaleOptions, + PlumeThemePageData, +} from '../shared/index.js' + +export async function setupPage(app: App) { + const blogPage = await createPage(app, { + path: '/blog/', + }) + const productPage = await createPage(app, { + path: '/product/', + }) + + app.pages.push(blogPage, productPage) +} + +let uuid = 10000 +const cache: Record = {} + +export function autoCategory( + page: Page, + options: PlumeThemeLocaleOptions +) { + const pagePath = page.filePathRelative + if (page.data.type || !pagePath) return + + const { notes } = options + if (notes && notes.link && page.path.startsWith(notes.link)) return + const categoryList: PageCategoryData[] = pagePath + .split('/') + .slice(0, -1) + .map((category) => { + const match = category.match(/^(\d+)?(?:\.?)([^]+)$/) || [] + !cache[match[2]] && !match[1] && (cache[match[2]] = uuid++) + return { + type: Number(match[1] || cache[match[2]]), + name: match[2], + } + }) + page.data.categoryList = categoryList +} + +export function pageContentRendered(page: Page) { + const EXCERPT_SPLIT = '' + if (page.data.isBlogPost && page.contentRendered.includes(EXCERPT_SPLIT)) { + const [excerpt, content] = page.contentRendered.split(EXCERPT_SPLIT) + page.contentRendered = `
${excerpt}
${EXCERPT_SPLIT}${content}` + } +} diff --git a/packages/theme/src/node/theme.ts b/packages/theme/src/node/theme.ts index 88a7bb7c..6c4a3d43 100644 --- a/packages/theme/src/node/theme.ts +++ b/packages/theme/src/node/theme.ts @@ -1,42 +1,45 @@ import type { App, Page, Theme } from '@vuepress/core' -import merge from 'lodash.merge' +import { fs, getDirname, path } from '@vuepress/utils' import type { PlumeThemeOptions, PlumeThemePageData } from '../shared/index.js' -import { getAlias } from './alias.js' -import { createPage } from './createPage/index.js' -import { defaultLocaleOption } from './defaultLocaleOption.js' -import { extendsPage } from './extendsPage.js' -import { generateFrontmatter } from './generateFrontmatter.js' -import { getPlugins } from './plugins/index.js' -import { onPrepared, preparedWatch } from './prepared/index.js' -import { resolveClient, resolveTemplate } from './utils/index.js' +import { setupPlugins } from './plugins.js' +import { autoCategory, pageContentRendered, setupPage } from './setupPages.js' -export const themePlume = ({ +const __dirname = getDirname(import.meta.url) + +export const plumeTheme = ({ themePlugins = {}, - ...localeOption + ...localeOptions }: PlumeThemeOptions = {}): Theme => { - localeOption = merge(defaultLocaleOption, localeOption) - let watchMarkdown: null | ((app: App, watchers: unknown) => void) = null - return { - name: '@vuepress-plume/vuepress-theme-plume', - templateBuild: resolveTemplate('index.build.html'), - alias: getAlias(), - clientConfigFile: resolveClient('config.js'), - onInitialized: async (app) => { - const { formatFrontmatter, watchNewMarkDown } = generateFrontmatter( - app.options.source, - localeOption - ) - watchMarkdown = watchNewMarkDown - await formatFrontmatter() - await createPage(app, localeOption) - }, - onPrepared: async (app) => await onPrepared(app, localeOption), - extendsPage: (page: Page>) => - extendsPage(page, localeOption), - onWatched: (app, watchers) => { - preparedWatch(app, watchers, localeOption) - watchMarkdown && watchMarkdown(app, watchers) - }, - plugins: getPlugins(themePlugins, localeOption), + return (app: App) => { + return { + name: '@vuepress-plume/theme-plume', + templateBuild: path.resolve(__dirname, '../../templates/build.html'), + alias: { + ...Object.fromEntries( + fs + .readdirSync(path.resolve(__dirname, '../client/components')) + .filter((file) => file.endsWith('.vue')) + .map((file) => [ + `@theme/${file}`, + path.resolve(__dirname, '../client/components', file), + ]) + ), + }, + clientConfigFile: path.resolve(__dirname, '../client/config.js'), + plugins: setupPlugins(app, themePlugins, localeOptions), + onInitialized: async (app) => { + await setupPage(app) + }, + extendsPage: (page: Page) => { + if (page.path === '/blog/') { + page.data.type = 'blog' + } + if (page.path === '/product/') { + page.data.type = 'product' + } + autoCategory(page, localeOptions) + pageContentRendered(page) + }, + } } } diff --git a/packages/theme/src/node/utils/date.ts b/packages/theme/src/node/utils/date.ts deleted file mode 100644 index ce55d2a6..00000000 --- a/packages/theme/src/node/utils/date.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { format, getTime, parse } from 'date-fns' - -export const getCreateTime = (date: string): number => { - const d = parse(date, 'yyyy/MM/dd HH:mm:ss', new Date()) - return getTime(d) -} - -export const formatDate = (date: string | undefined): string => { - if (!date) return '' - const d = parse(date, 'yyyy/MM/dd HH:mm:ss', new Date()) - return format(d, 'yyyy-MM-dd') -} diff --git a/packages/theme/src/node/utils/index.ts b/packages/theme/src/node/utils/index.ts deleted file mode 100644 index 0f359eb3..00000000 --- a/packages/theme/src/node/utils/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -export * from './path.js' -export * from './date.js' -export * from './readFileList.js' diff --git a/packages/theme/src/node/utils/path.ts b/packages/theme/src/node/utils/path.ts deleted file mode 100644 index 65be7e04..00000000 --- a/packages/theme/src/node/utils/path.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { getDirname, path } from '@vuepress/utils' - -const __dirname = getDirname(import.meta.url) - -export const resolvePath = (...args: string[]): string => { - return path.resolve(__dirname, '../../', ...args) -} - -export const resolveClient = (...args: string[]): string => { - return resolvePath('client', ...args) -} - -export const resolveTemplate = (...args: string[]): string => { - return resolvePath('../', 'template', ...args) -} diff --git a/packages/theme/src/node/utils/readFileList.ts b/packages/theme/src/node/utils/readFileList.ts deleted file mode 100644 index 32216ce0..00000000 --- a/packages/theme/src/node/utils/readFileList.ts +++ /dev/null @@ -1,44 +0,0 @@ -import { fs, path } from '@vuepress/utils' - -export interface MarkdownFile { - filepath: string - content: string - createTime: Date -} - -export const readFileList = ( - sourceDir: string, - fileList: MarkdownFile[] = [] -): MarkdownFile[] => { - const files = fs.readdirSync(sourceDir) - files.forEach((file) => { - const filepath = path.join(sourceDir, file) - const stat = fs.statSync(filepath) - if (stat.isDirectory()) { - if (file !== '.vuepress' && file !== 'node_modules') - readFileList(filepath, fileList) - } else { - const extname = path.extname(file) - const basename = path.basename(file) - if ( - (extname === '.md' || extname === '.MD') && - basename !== 'CHANGELOG' - ) { - fileList.push(readFile(filepath, stat)) - } - } - }) - return fileList.filter((file) => file.filepath.endsWith('.md')) -} - -export const readFile = (filepath: string, stat: fs.Stats): MarkdownFile => { - return { - filepath, - content: fs.readFileSync(filepath, 'utf-8'), - createTime: getFileCreateTime(stat), - } -} - -export const getFileCreateTime = (stat: fs.Stats): Date => { - return stat.birthtime.getFullYear() !== 1970 ? stat.birthtime : stat.atime -} diff --git a/packages/theme/src/shared/base.ts b/packages/theme/src/shared/base.ts new file mode 100644 index 00000000..78ef99c4 --- /dev/null +++ b/packages/theme/src/shared/base.ts @@ -0,0 +1,4 @@ +export type PlumeThemeImage = + | string + | { src: string; alt?: string } + | { dark: string; light: string; alt?: string } diff --git a/packages/theme/src/shared/blog.ts b/packages/theme/src/shared/blog.ts new file mode 100644 index 00000000..b4a66078 --- /dev/null +++ b/packages/theme/src/shared/blog.ts @@ -0,0 +1,11 @@ +import type { BlogPostDataItem } from '@vuepress-plume/vuepress-plugin-blog-data' +import type { PageCategoryData } from './page.js' + +export interface PlumeThemeBlogPostItem extends BlogPostDataItem { + tags: string[] + sticky: boolean + categoryLost: PageCategoryData[] + createTime: string +} + +export type PlumeThemeBlogPostData = PlumeThemeBlogPostItem[] diff --git a/packages/theme/src/shared/frontmatter.ts b/packages/theme/src/shared/frontmatter.ts new file mode 100644 index 00000000..7e04bbdf --- /dev/null +++ b/packages/theme/src/shared/frontmatter.ts @@ -0,0 +1,29 @@ +export interface PlumeThemeHomeFrontmatter { + home?: true + banner?: string + hero: { + name: string + profession?: string + text?: string + actions: PlumeThemeHeroAction[] + } +} + +export interface PlumeThemeHeroAction { + theme?: 'brand' | 'alt' + text: string + link?: string +} +export interface PlumeThemePostFrontmatter { + createTime?: string + author?: string + tags?: string[] + sticky?: boolean | number + article?: boolean + banner?: string + bgBanner?: string +} + +export interface PlumeThemeNoteFrontmatter { + createTime?: string +} diff --git a/packages/theme/src/shared/frontmatter/home.ts b/packages/theme/src/shared/frontmatter/home.ts deleted file mode 100644 index d2e2a9f1..00000000 --- a/packages/theme/src/shared/frontmatter/home.ts +++ /dev/null @@ -1,18 +0,0 @@ -import type { PlumeThemeNormalFrontmatter } from './normal.js' - -export interface PlumeThemeProductItem { - link?: string - text: string - description?: string - logo?: string -} - -export type PlumeThemeProductList = PlumeThemeProductItem[] - -export interface PlumeThemeHomeFrontmatter extends PlumeThemeNormalFrontmatter { - home?: true - banner?: string - mobileBanner?: string - productList?: PlumeThemeProductList - motto?: string -} diff --git a/packages/theme/src/shared/frontmatter/index.ts b/packages/theme/src/shared/frontmatter/index.ts deleted file mode 100644 index 3cea147c..00000000 --- a/packages/theme/src/shared/frontmatter/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -export * from './normal.js' -export * from './post.js' -export * from './home.js' diff --git a/packages/theme/src/shared/frontmatter/normal.ts b/packages/theme/src/shared/frontmatter/normal.ts deleted file mode 100644 index 97db9ddb..00000000 --- a/packages/theme/src/shared/frontmatter/normal.ts +++ /dev/null @@ -1,3 +0,0 @@ -export interface PlumeThemeNormalFrontmatter { - home?: boolean -} diff --git a/packages/theme/src/shared/frontmatter/post.ts b/packages/theme/src/shared/frontmatter/post.ts deleted file mode 100644 index c96f0f20..00000000 --- a/packages/theme/src/shared/frontmatter/post.ts +++ /dev/null @@ -1,10 +0,0 @@ -export interface PlumeThemePostFrontmatter { - title?: string - createTime?: string - author?: string - tags?: string[] - sticky?: boolean | number - article?: boolean - banner?: string - bgBanner?: string -} diff --git a/packages/theme/src/shared/index.ts b/packages/theme/src/shared/index.ts index 93b78889..96b4786b 100644 --- a/packages/theme/src/shared/index.ts +++ b/packages/theme/src/shared/index.ts @@ -1,5 +1,6 @@ +export * from './base.js' +export * from './frontmatter.js' +export * from './note.js' export * from './options/index.js' -export * from './layout/index.js' -export * from './post.js' -export * from './frontmatter/index.js' export * from './page.js' +export * from './blog.js' diff --git a/packages/theme/src/shared/layout/index.ts b/packages/theme/src/shared/layout/index.ts deleted file mode 100644 index 1082a2ad..00000000 --- a/packages/theme/src/shared/layout/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -export * from './navbar.js' - -export * from './sidebar.js' diff --git a/packages/theme/src/shared/layout/navbar.ts b/packages/theme/src/shared/layout/navbar.ts deleted file mode 100644 index 58ae7487..00000000 --- a/packages/theme/src/shared/layout/navbar.ts +++ /dev/null @@ -1,22 +0,0 @@ -export interface NavItem { - text: string - ariaLabel?: string -} - -export interface NavGroup extends NavItem { - children: T[] -} - -export interface NavLink extends NavItem { - link: string - rel?: string - target?: string - activeMatch?: string -} - -export type NavbarItem = NavLink - -export type NavbarGroup = NavGroup - -export type NavbarConfig = (NavbarItem | NavbarGroup | string)[] -export type ResolveNavbarItem = NavbarItem | NavGroup diff --git a/packages/theme/src/shared/layout/sidebar.ts b/packages/theme/src/shared/layout/sidebar.ts deleted file mode 100644 index 72460ebb..00000000 --- a/packages/theme/src/shared/layout/sidebar.ts +++ /dev/null @@ -1,7 +0,0 @@ -export interface SidebarItem { - text: string - link?: string - children: SidebarOptions -} - -export type SidebarOptions = SidebarItem[] diff --git a/packages/theme/src/shared/options/notes.ts b/packages/theme/src/shared/note.ts similarity index 100% rename from packages/theme/src/shared/options/notes.ts rename to packages/theme/src/shared/note.ts diff --git a/packages/theme/src/shared/options/index.ts b/packages/theme/src/shared/options/index.ts index 62470d6c..4bba3d83 100644 --- a/packages/theme/src/shared/options/index.ts +++ b/packages/theme/src/shared/options/index.ts @@ -1,4 +1,50 @@ -export * from './plugin.js' +import type { ThemeData } from '@vuepress/plugin-theme-data' +import type { PlumeThemeLocaleData } from './locale.js' +import type { PlumeThemePluginOptions } from './plugins.js' + +export interface PlumeThemeOptions extends PlumeThemeLocaleOptions { + /** + * 对主题内部使用的插件进行配置 + */ + themePlugins?: PlumeThemePluginOptions + + /** + * 是否仅使用博客功能 + * + * @default false + */ + onlyBlog?: boolean + + blog?: { + /** + * blog 文章读取目录 + * + * @default './' 即 vuepress 配置的 source 目录 + */ + dir?: string + + /** + * 在 `blog.dir` 目录中,通过 glob string 配置包含文件 + * + * @default - ['**\*.md'] + */ + include?: string[] + + /** + * 在 `blog.dir` 目录中,通过 glob string 配置排除的文件 + * + * _README.md 文件一般作为主页或者某个目录下的主页,不应该被读取为 blog文章_ + * + * @default - ['.vuepress/', 'node_modules/', '{README,index}.md'] + */ + exclude?: string[] + } +} + +export type PlumeThemeLocaleOptions = PlumeThemeData + +export type PlumeThemeData = ThemeData + export * from './locale.js' -export * from './options.js' -export * from './notes.js' +export * from './plugins.js' +export * from './navbar.js' diff --git a/packages/theme/src/shared/options/locale.ts b/packages/theme/src/shared/options/locale.ts index e2970e6c..0d1186a9 100644 --- a/packages/theme/src/shared/options/locale.ts +++ b/packages/theme/src/shared/options/locale.ts @@ -1,6 +1,8 @@ +import type { NotesDataOptions } from '@vuepress-plume/vuepress-plugin-notes-data' import type { LocaleData } from '@vuepress/core' -import type { NavbarConfig, NavLink } from '../layout/index.js' -import type { PlumeThemeNotesOptions } from './notes.js' +import type { NavItem, NavItemWithLink } from './navbar.js' +// import type { NavbarConfig, NavLink } from '../layout/index.js' +// import type { PlumeThemeNotesOptions } from './notes.js' export interface PlumeThemeAvatar { /** @@ -17,46 +19,28 @@ export interface PlumeThemeAvatar { description?: string } -export interface PlumeThemeSocialOption { - /** - * 邮箱 - */ - email?: string - /** - * github链接 支持仅填写 organization / Repositories - */ - github?: string - /** - * 微博 - */ - weiBo?: string - /** - * 知乎 - */ - zhiHu?: string - /** - * QQ - */ - QQ?: string - /** - * facebook - */ - facebook?: string - /** - * twitter - */ - twitter?: string - /** - * linkedin 英领 - */ - linkedin?: string +export interface SocialLink { + icon: SocialLinkIcon + link: string } +export type SocialLinkIcon = + | 'discord' + | 'facebook' + | 'github' + | 'instagram' + | 'linkedin' + | 'mastodon' + | 'slack' + | 'twitter' + | 'youtube' + | { svg: string } + export interface PlumeThemeLocaleData extends LocaleData { /** * 网站站点首页 */ - home?: false | NavLink + home?: string /** * 网站站点logo */ @@ -66,13 +50,9 @@ export interface PlumeThemeLocaleData extends LocaleData { */ logoDark?: string /** - * 是否启用深色模式 + * 是否启用深色模式切换按钮 */ - darkMode?: boolean - - toggleDarkMode?: string - - toggleSidebar?: string + appearance?: boolean | 'dark' /** * 部署站点域名。 @@ -91,7 +71,7 @@ export interface PlumeThemeLocaleData extends LocaleData { /** * 社交账号配置 */ - social?: PlumeThemeSocialOption + social?: SocialLink[] /** * 文章链接前缀 @@ -105,14 +85,14 @@ export interface PlumeThemeLocaleData extends LocaleData { * * @def:{ text: '标签', link: '/tag/' } */ - tag?: false | NavLink + tag?: false | NavItemWithLink /** * 文章分类 与 navbar配置 * * @default: { text: '分类', link: '/category/ } */ - category?: false | NavLink + category?: false | NavItemWithLink /** * 归档页 链接与 navbar 配置 @@ -121,16 +101,14 @@ export interface PlumeThemeLocaleData extends LocaleData { * * @default: { text: '归档', link: '/timeline/' } */ - archive?: false | NavLink + archive?: false | NavItemWithLink /** * 笔记配置, 笔记中的文章默认不会出现在首页文章列表 * * 注:你也可以将notes配置到navbar中,默认自动生成在右侧栏目中 */ - notes?: false | PlumeThemeNotesOptions - - footer?: false | { content: string; copyright: string } + notes?: false | NotesDataOptions /** * language text @@ -158,7 +136,7 @@ export interface PlumeThemeLocaleData extends LocaleData { * * Set to `false` to disable navbar in current locale */ - navbar?: false | NavbarConfig + navbar?: false | NavItem[] /** * 外部链接打开方式 */ @@ -167,4 +145,11 @@ export interface PlumeThemeLocaleData extends LocaleData { notFound?: string[] backToHome?: string + + footer?: + | false + | { + message?: string + copyright?: string + } } diff --git a/packages/theme/src/shared/options/navbar.ts b/packages/theme/src/shared/options/navbar.ts new file mode 100644 index 00000000..b70ed4a8 --- /dev/null +++ b/packages/theme/src/shared/options/navbar.ts @@ -0,0 +1,28 @@ +export type NavItem = NavItemWithLink | NavItemWithChildren + +export type NavItemWithLink = { + text: string + link: string + + /** + * `activeMatch` is expected to be a regex string. We can't use actual + * RegExp object here because it isn't serializable + */ + activeMatch?: string +} + +export type NavItemChildren = { + text?: string + items: NavItemWithLink[] +} + +export interface NavItemWithChildren { + text?: string + items: (NavItemChildren | NavItemWithLink)[] + + /** + * `activeMatch` is expected to be a regex string. We can't use actual + * RegExp object here because it isn't serializable + */ + activeMatch?: string +} diff --git a/packages/theme/src/shared/options/options.ts b/packages/theme/src/shared/options/options.ts deleted file mode 100644 index 49e2160d..00000000 --- a/packages/theme/src/shared/options/options.ts +++ /dev/null @@ -1,14 +0,0 @@ -import type { ThemeData } from '@vuepress/plugin-theme-data' -import type { PlumeThemeLocaleData } from './locale.js' -import type { PlumeThemePluginOptions } from './plugin.js' - -export interface PlumeThemeOptions extends PlumeThemeLocaleOptions { - /** - * 对主题内部使用的插件进行配置 - */ - themePlugins?: PlumeThemePluginOptions -} - -export type PlumeThemeLocaleOptions = PlumeThemeData - -export type PlumeThemeData = ThemeData diff --git a/packages/theme/src/shared/options/plugin.ts b/packages/theme/src/shared/options/plugins.ts similarity index 98% rename from packages/theme/src/shared/options/plugin.ts rename to packages/theme/src/shared/options/plugins.ts index 38057636..2e860bae 100644 --- a/packages/theme/src/shared/options/plugin.ts +++ b/packages/theme/src/shared/options/plugins.ts @@ -5,6 +5,7 @@ import type { DocsearchOptions } from '@vuepress/plugin-docsearch' import type { SearchPluginOptions } from '@vuepress/plugin-search' import type { CommentOptions } from 'vuepress-plugin-comment2' import type { MarkdownEnhanceOptions } from 'vuepress-plugin-md-enhance' + export interface PlumeThemePluginOptions { /** * 是否启用 can-i-use 插件 @@ -42,5 +43,7 @@ export interface PlumeThemePluginOptions { sitemap?: false + seo?: false + baiduTongji?: false | BaiduTongjiOptions } diff --git a/packages/theme/src/shared/page.ts b/packages/theme/src/shared/page.ts index 83ec492c..331a4a68 100644 --- a/packages/theme/src/shared/page.ts +++ b/packages/theme/src/shared/page.ts @@ -1,3 +1,14 @@ -import type { PostItem } from './post.js' +export type PlumeThemePageData = { + git: { + createTime: number + updateTime: number + } + isBlogPost: boolean + type: 'blog' | 'product' + categoryList?: PageCategoryData[] +} -export type PlumeThemePageData = PostItem +export type PageCategoryData = { + type: string | number + name: string +} diff --git a/packages/theme/src/shared/post.ts b/packages/theme/src/shared/post.ts deleted file mode 100644 index 939139a8..00000000 --- a/packages/theme/src/shared/post.ts +++ /dev/null @@ -1,22 +0,0 @@ -export interface CategoryItem { - type: number | string - name: string -} - -export type CategoryData = CategoryItem[] - -export interface PostItem { - title: string - path: string - excerpt: string - tags: string[] - createTime: string - author: string - sticky?: boolean | number - article?: boolean - category: CategoryData - isNote?: boolean - banner?: string -} - -export type PostIndex = PostItem[] diff --git a/packages/theme/template/index.build.html b/packages/theme/templates/build.html similarity index 53% rename from packages/theme/template/index.build.html rename to packages/theme/templates/build.html index dbf2e687..eb399e3d 100644 --- a/packages/theme/template/index.build.html +++ b/packages/theme/templates/build.html @@ -1,9 +1,8 @@ - - - + + + - +
diff --git a/packages/tsconfig.build.json b/packages/tsconfig.build.json index 39125966..6c7a7811 100644 --- a/packages/tsconfig.build.json +++ b/packages/tsconfig.build.json @@ -5,11 +5,14 @@ }, "files": [], "references": [ + { "path": "./plugin-auto-frontmatter/tsconfig.build.json" }, { "path": "./plugin-baidu-tongji/tsconfig.build.json" }, + { "path": "./plugin-blog-data/tsconfig.build.json" }, { "path": "./plugin-caniuse/tsconfig.build.json" }, { "path": "./plugin-copy-code/tsconfig.build.json" }, { "path": "./plugin-netlify-functions/tsconfig.build.json" }, { "path": "./plugin-page-collection/tsconfig.build.json" }, - { "path": "./plugin-windicss/tsconfig.build.json" } + { "path": "./plugin-windicss/tsconfig.build.json" }, + { "path": "./theme/tsconfig.build.json" } ] } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index c06eef9c..37994637 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -4,364 +4,348 @@ importers: .: specifiers: - '@commitlint/cli': ^17.1.2 - '@commitlint/config-conventional': ^17.1.0 + '@commitlint/cli': ^17.4.2 + '@commitlint/config-conventional': ^17.4.2 '@types/minimist': ^1.2.2 - '@types/node': 18.8.0 + '@types/node': 18.11.18 '@types/webpack-env': ^1.18.0 bumpp: ^8.2.1 - chalk: ^5.1.2 - commitizen: ^4.2.5 - concurrently: ^7.4.0 + chalk: ^5.2.0 + commitizen: ^4.2.6 + concurrently: ^7.6.0 conventional-changelog-cli: ^2.2.2 cpx2: ^4.2.0 cross-env: ^7.0.3 cz-conventional-changelog: ^3.3.0 - eslint: ^8.25.0 - eslint-config-vuepress: ^4.0.3 - eslint-config-vuepress-typescript: ^4.0.3 + eslint: ^8.32.0 + eslint-config-vuepress: ^4.0.4 + eslint-config-vuepress-typescript: ^4.0.4 execa: ^6.1.0 handlebars: ^4.7.7 - husky: ^8.0.1 - lint-staged: ^13.0.3 + husky: ^8.0.3 + lint-staged: ^13.1.0 minimist: ^1.2.7 ora: ^6.1.2 - pnpm: ^7.13.4 - prettier: ^2.7.1 + pnpm: ^7.25.0 + prettier: ^2.8.3 prettier-config-vuepress: ^4.0.0 rimraf: ^3.0.2 - sort-package-json: ^2.0.0 - taze: ^0.8.2 + sort-package-json: ^2.1.0 + taze: ^0.8.5 ts-node: ^10.9.1 - typescript: ^4.8.4 - vite: ^3.1.8 + tsconfig-vuepress: ^4.0.4 + typescript: ^4.9.4 + vite: ^4.0.4 devDependencies: - '@commitlint/cli': 17.3.0 - '@commitlint/config-conventional': 17.3.0 + '@commitlint/cli': 17.4.2 + '@commitlint/config-conventional': 17.4.2 '@types/minimist': 1.2.2 - '@types/node': 18.8.0 + '@types/node': 18.11.18 '@types/webpack-env': 1.18.0 bumpp: 8.2.1 - chalk: 5.1.2 - commitizen: 4.2.5 + chalk: 5.2.0 + commitizen: 4.2.6 concurrently: 7.6.0 conventional-changelog-cli: 2.2.2 cpx2: 4.2.0 cross-env: 7.0.3 cz-conventional-changelog: 3.3.0 - eslint: 8.28.0 - eslint-config-vuepress: 4.0.4_qxidjfl7kplxks3jglwjyrcjce - eslint-config-vuepress-typescript: 4.0.4_jf7jfk5otr6om6scve5a6y6f5y + eslint: 8.32.0 + eslint-config-vuepress: 4.0.4_udtwlmtl3kiiub6agmjl3rmgge + eslint-config-vuepress-typescript: 4.0.4_otjudfky5iceznjpbxpmgilubi execa: 6.1.0 handlebars: 4.7.7 - husky: 8.0.2 - lint-staged: 13.0.4 + husky: 8.0.3 + lint-staged: 13.1.0 minimist: 1.2.7 ora: 6.1.2 - pnpm: 7.17.1 - prettier: 2.8.0 + pnpm: 7.25.0 + prettier: 2.8.3 prettier-config-vuepress: 4.0.0 rimraf: 3.0.2 sort-package-json: 2.1.0 - taze: 0.8.4 - ts-node: 10.9.1_cq27usnizs5s2sfjzl5zqe6ljq - typescript: 4.9.3 - vite: 3.2.4_@types+node@18.8.0 + taze: 0.8.5 + ts-node: 10.9.1_awa2wsr5thmg3i7jqycphctjfq + tsconfig-vuepress: 4.0.4 + typescript: 4.9.4 + vite: 4.0.4_@types+node@18.11.18 docs: specifiers: '@vuepress-plume/vuepress-theme-plume': workspace:* - '@vuepress/bundler-vite': 2.0.0-beta.51 - '@vuepress/bundler-webpack': 2.0.0-beta.51 - '@vuepress/cli': 2.0.0-beta.51 - '@vuepress/client': 2.0.0-beta.51 - '@vuepress/utils': 2.0.0-beta.51 + '@vuepress/bundler-vite': 2.0.0-beta.60 + '@vuepress/bundler-webpack': 2.0.0-beta.60 + '@vuepress/cli': 2.0.0-beta.60 + '@vuepress/client': 2.0.0-beta.60 + '@vuepress/utils': 2.0.0-beta.60 anywhere: ^1.6.0 - leancloud-storage: ^4.13.2 - sass: ^1.55.0 - sass-loader: ^13.1.0 - vue: ^3.2.41 + leancloud-storage: ^4.14.0 + sass: ^1.57.1 + sass-loader: ^13.2.0 + vue: ^3.2.47 dependencies: '@vuepress-plume/vuepress-theme-plume': link:../packages/theme - '@vuepress/bundler-vite': 2.0.0-beta.51_sass@1.56.1 - '@vuepress/bundler-webpack': 2.0.0-beta.51 - '@vuepress/cli': 2.0.0-beta.51 - '@vuepress/client': 2.0.0-beta.51 - '@vuepress/utils': 2.0.0-beta.51 + '@vuepress/bundler-vite': 2.0.0-beta.60_sass@1.57.1 + '@vuepress/bundler-webpack': 2.0.0-beta.60 + '@vuepress/cli': 2.0.0-beta.60 + '@vuepress/client': 2.0.0-beta.60 + '@vuepress/utils': 2.0.0-beta.60 anywhere: 1.6.0 - leancloud-storage: 4.13.4 - sass: 1.56.1 - sass-loader: 13.2.0_sass@1.56.1 - vue: 3.2.45 + leancloud-storage: 4.14.0 + sass: 1.57.1 + sass-loader: 13.2.0_sass@1.57.1 + vue: 3.2.47 + + packages/plugin-auto-frontmatter: + specifiers: + '@vuepress/core': 2.0.0-beta.60 + '@vuepress/shared': 2.0.0-beta.60 + chokidar: ^3.5.3 + create-filter: ^1.0.0 + fast-glob: ^3.2.12 + gray-matter: ^4.0.3 + json2yaml: ^1.1.0 + dependencies: + '@vuepress/core': 2.0.0-beta.60 + '@vuepress/shared': 2.0.0-beta.60 + chokidar: 3.5.3 + create-filter: 1.0.0 + fast-glob: 3.2.12 + gray-matter: 4.0.3 + json2yaml: 1.1.0 packages/plugin-baidu-tongji: specifiers: - '@vuepress/client': 2.0.0-beta.51 - '@vuepress/core': 2.0.0-beta.51 - '@vuepress/shared': 2.0.0-beta.51 - '@vuepress/utils': 2.0.0-beta.51 + '@vuepress/client': 2.0.0-beta.60 + '@vuepress/core': 2.0.0-beta.60 + '@vuepress/shared': 2.0.0-beta.60 + '@vuepress/utils': 2.0.0-beta.60 dependencies: - '@vuepress/client': 2.0.0-beta.51 - '@vuepress/core': 2.0.0-beta.51 - '@vuepress/shared': 2.0.0-beta.51 - '@vuepress/utils': 2.0.0-beta.51 + '@vuepress/client': 2.0.0-beta.60 + '@vuepress/core': 2.0.0-beta.60 + '@vuepress/shared': 2.0.0-beta.60 + '@vuepress/utils': 2.0.0-beta.60 + + packages/plugin-blog-data: + specifiers: + '@vue/devtools-api': ^6.4.5 + '@vuepress/client': 2.0.0-beta.60 + '@vuepress/core': 2.0.0-beta.60 + '@vuepress/shared': 2.0.0-beta.60 + '@vuepress/utils': 2.0.0-beta.60 + chokidar: ^3.5.3 + create-filter: ^1.0.0 + vue: ^3.2.47 + dependencies: + '@vue/devtools-api': 6.4.5 + '@vuepress/client': 2.0.0-beta.60 + '@vuepress/core': 2.0.0-beta.60 + '@vuepress/shared': 2.0.0-beta.60 + '@vuepress/utils': 2.0.0-beta.60 + chokidar: 3.5.3 + create-filter: 1.0.0 + vue: 3.2.47 packages/plugin-caniuse: specifiers: '@types/markdown-it': ^12.2.3 - '@vuepress/cli': 2.0.0-beta.51 - '@vuepress/client': 2.0.0-beta.51 - '@vuepress/core': 2.0.0-beta.51 - '@vuepress/utils': 2.0.0-beta.51 + '@vuepress/cli': 2.0.0-beta.60 + '@vuepress/client': 2.0.0-beta.60 + '@vuepress/core': 2.0.0-beta.60 + '@vuepress/utils': 2.0.0-beta.60 markdown-it-container: ^3.0.0 dependencies: '@types/markdown-it': 12.2.3 - '@vuepress/cli': 2.0.0-beta.51 - '@vuepress/client': 2.0.0-beta.51 - '@vuepress/core': 2.0.0-beta.51 - '@vuepress/utils': 2.0.0-beta.51 + '@vuepress/cli': 2.0.0-beta.60 + '@vuepress/client': 2.0.0-beta.60 + '@vuepress/core': 2.0.0-beta.60 + '@vuepress/utils': 2.0.0-beta.60 markdown-it-container: 3.0.0 packages/plugin-copy-code: specifiers: - '@vuepress/client': 2.0.0-beta.51 - '@vuepress/core': 2.0.0-beta.51 - '@vuepress/shared': 2.0.0-beta.51 - '@vuepress/utils': 2.0.0-beta.51 - vue: ^3.2.41 - vue-router: 4.1.5 + '@vuepress/client': 2.0.0-beta.60 + '@vuepress/core': 2.0.0-beta.60 + '@vuepress/shared': 2.0.0-beta.60 + '@vuepress/utils': 2.0.0-beta.60 + vue: ^3.2.47 + vue-router: 4.1.6 dependencies: - '@vuepress/client': 2.0.0-beta.51 - '@vuepress/core': 2.0.0-beta.51 - '@vuepress/shared': 2.0.0-beta.51 - '@vuepress/utils': 2.0.0-beta.51 - vue: 3.2.45 - vue-router: 4.1.5_vue@3.2.45 + '@vuepress/client': 2.0.0-beta.60 + '@vuepress/core': 2.0.0-beta.60 + '@vuepress/shared': 2.0.0-beta.60 + '@vuepress/utils': 2.0.0-beta.60 + vue: 3.2.47 + vue-router: 4.1.6_vue@3.2.47 packages/plugin-netlify-functions: specifiers: '@iarna/toml': ^2.2.5 - '@netlify/functions': ^1.3.0 - '@types/node': ^18.8.5 - '@vuepress/core': 2.0.0-beta.51 - '@vuepress/shared': 2.0.0-beta.51 - '@vuepress/utils': 2.0.0-beta.51 - chalk: ^5.1.2 + '@netlify/functions': ^1.4.0 + '@types/node': ^18.11.18 + '@vuepress/core': 2.0.0-beta.60 + '@vuepress/shared': 2.0.0-beta.60 + '@vuepress/utils': 2.0.0-beta.60 + chalk: ^5.2.0 chokidar: ^3.5.3 cpx2: ^4.2.0 dotenv: ^16.0.3 - esbuild: ^0.15.11 + esbuild: ^0.16.17 execa: ^6.1.0 - netlify-cli: ^12.0.9 + netlify-cli: ^12.7.2 portfinder: ^1.0.32 dependencies: '@iarna/toml': 2.2.5 - '@netlify/functions': 1.3.0 - '@vuepress/core': 2.0.0-beta.51 - '@vuepress/shared': 2.0.0-beta.51 - '@vuepress/utils': 2.0.0-beta.51 - chalk: 5.1.2 + '@netlify/functions': 1.4.0 + '@vuepress/core': 2.0.0-beta.60 + '@vuepress/shared': 2.0.0-beta.60 + '@vuepress/utils': 2.0.0-beta.60 + chalk: 5.2.0 chokidar: 3.5.3 cpx2: 4.2.0 dotenv: 16.0.3 - esbuild: 0.15.16 + esbuild: 0.16.17 execa: 6.1.0 - netlify-cli: 12.2.7_@types+node@18.11.9 + netlify-cli: 12.7.2_@types+node@18.11.18 portfinder: 1.0.32 devDependencies: - '@types/node': 18.11.9 + '@types/node': 18.11.18 + + packages/plugin-notes-data: + specifiers: + '@vue/devtools-api': ^6.4.5 + '@vuepress/client': 2.0.0-beta.60 + '@vuepress/core': 2.0.0-beta.60 + '@vuepress/shared': 2.0.0-beta.60 + '@vuepress/utils': 2.0.0-beta.60 + chokidar: ^3.5.3 + create-filter: ^1.0.0 + vue: ^3.2.47 + dependencies: + '@vue/devtools-api': 6.4.5 + '@vuepress/client': 2.0.0-beta.60 + '@vuepress/core': 2.0.0-beta.60 + '@vuepress/shared': 2.0.0-beta.60 + '@vuepress/utils': 2.0.0-beta.60 + chokidar: 3.5.3 + create-filter: 1.0.0 + vue: 3.2.47 packages/plugin-page-collection: specifiers: - '@netlify/functions': ^1.3.0 + '@netlify/functions': ^1.4.0 '@vuepress-plume/vuepress-plugin-netlify-functions': workspace:* - '@vuepress/client': 2.0.0-beta.51 - '@vuepress/core': 2.0.0-beta.51 - '@vuepress/shared': 2.0.0-beta.51 - '@vuepress/utils': 2.0.0-beta.51 - leancloud-storage: ^4.13.2 - vue: ^3.2.41 - vue-router: 4.1.5 + '@vuepress/client': 2.0.0-beta.60 + '@vuepress/core': 2.0.0-beta.60 + '@vuepress/shared': 2.0.0-beta.60 + '@vuepress/utils': 2.0.0-beta.60 + leancloud-storage: ^4.14.0 + vue: ^3.2.47 + vue-router: 4.1.6 dependencies: - '@netlify/functions': 1.3.0 + '@netlify/functions': 1.4.0 '@vuepress-plume/vuepress-plugin-netlify-functions': link:../plugin-netlify-functions - '@vuepress/client': 2.0.0-beta.51 - '@vuepress/core': 2.0.0-beta.51 - '@vuepress/shared': 2.0.0-beta.51 - '@vuepress/utils': 2.0.0-beta.51 - leancloud-storage: 4.13.4 - vue: 3.2.45 - vue-router: 4.1.5_vue@3.2.45 + '@vuepress/client': 2.0.0-beta.60 + '@vuepress/core': 2.0.0-beta.60 + '@vuepress/shared': 2.0.0-beta.60 + '@vuepress/utils': 2.0.0-beta.60 + leancloud-storage: 4.14.0 + vue: 3.2.47 + vue-router: 4.1.6_vue@3.2.47 packages/plugin-windicss: specifiers: - '@vuepress/client': 2.0.0-beta.51 - '@vuepress/core': 2.0.0-beta.51 - '@vuepress/shared': 2.0.0-beta.51 - '@vuepress/utils': 2.0.0-beta.51 - vite-plugin-windicss: ^1.8.8 + '@vuepress/client': 2.0.0-beta.60 + '@vuepress/core': 2.0.0-beta.60 + '@vuepress/shared': 2.0.0-beta.60 + '@vuepress/utils': 2.0.0-beta.60 + vite-plugin-windicss: ^1.8.10 windicss: ^3.5.6 - windicss-webpack-plugin: ^1.7.6 + windicss-webpack-plugin: ^1.7.7 dependencies: - '@vuepress/client': 2.0.0-beta.51 - '@vuepress/core': 2.0.0-beta.51 - '@vuepress/shared': 2.0.0-beta.51 - '@vuepress/utils': 2.0.0-beta.51 - vite-plugin-windicss: 1.8.8 + '@vuepress/client': 2.0.0-beta.60 + '@vuepress/core': 2.0.0-beta.60 + '@vuepress/shared': 2.0.0-beta.60 + '@vuepress/utils': 2.0.0-beta.60 + vite-plugin-windicss: 1.8.10 windicss: 3.5.6 windicss-webpack-plugin: 1.7.7 packages/theme: specifiers: '@types/lodash.merge': ^4.6.7 + '@vuepress-plume/vuepress-plugin-auto-frontmatter': workspace:* '@vuepress-plume/vuepress-plugin-baidu-tongji': workspace:* + '@vuepress-plume/vuepress-plugin-blog-data': workspace:* '@vuepress-plume/vuepress-plugin-caniuse': workspace:* '@vuepress-plume/vuepress-plugin-copy-code': workspace:* - '@vuepress/client': 2.0.0-beta.51 - '@vuepress/core': 2.0.0-beta.51 - '@vuepress/plugin-active-header-links': 2.0.0-beta.51 - '@vuepress/plugin-container': 2.0.0-beta.51 - '@vuepress/plugin-docsearch': 2.0.0-beta.51 - '@vuepress/plugin-external-link-icon': 2.0.0-beta.51 - '@vuepress/plugin-git': 2.0.0-beta.51 - '@vuepress/plugin-medium-zoom': 2.0.0-beta.51 - '@vuepress/plugin-nprogress': 2.0.0-beta.51 - '@vuepress/plugin-palette': 2.0.0-beta.51 - '@vuepress/plugin-prismjs': 2.0.0-beta.51 - '@vuepress/plugin-search': 2.0.0-beta.51 - '@vuepress/plugin-theme-data': 2.0.0-beta.51 - '@vuepress/plugin-toc': 2.0.0-beta.51 - '@vuepress/shared': 2.0.0-beta.51 - '@vuepress/utils': 2.0.0-beta.51 - '@vueuse/core': ^9.3.0 - chokidar: ^3.5.3 + '@vuepress-plume/vuepress-plugin-notes-data': workspace:* + '@vuepress/client': 2.0.0-beta.60 + '@vuepress/core': 2.0.0-beta.60 + '@vuepress/plugin-active-header-links': 2.0.0-beta.60 + '@vuepress/plugin-container': 2.0.0-beta.60 + '@vuepress/plugin-docsearch': 2.0.0-beta.60 + '@vuepress/plugin-external-link-icon': 2.0.0-beta.60 + '@vuepress/plugin-git': 2.0.0-beta.60 + '@vuepress/plugin-medium-zoom': 2.0.0-beta.60 + '@vuepress/plugin-nprogress': 2.0.0-beta.60 + '@vuepress/plugin-palette': 2.0.0-beta.60 + '@vuepress/plugin-prismjs': 2.0.0-beta.60 + '@vuepress/plugin-search': 2.0.0-beta.60 + '@vuepress/plugin-shiki': 2.0.0-beta.60 + '@vuepress/plugin-theme-data': 2.0.0-beta.60 + '@vuepress/plugin-toc': 2.0.0-beta.60 + '@vuepress/shared': 2.0.0-beta.60 + '@vuepress/utils': 2.0.0-beta.60 + '@vueuse/core': ^9.10.0 + body-scroll-lock: 4.0.0-beta.0 date-fns: ^2.29.3 - gray-matter: ^4.0.3 - json2yaml: ^1.1.0 - lodash.merge: ^4.6.2 nanoid: ^4.0.0 - sass: ^1.55.0 - sass-loader: ^13.1.0 ts-debounce: ^4.0.0 - vue: ^3.2.41 - vue-router: 4.1.5 - vuepress-plugin-comment2: 2.0.0-beta.110 - vuepress-plugin-md-enhance: 2.0.0-beta.110 - vuepress-plugin-seo2: 2.0.0-beta.110 - vuepress-plugin-sitemap2: 2.0.0-beta.110 + vue: ^3.2.47 + vue-router: 4.1.6 + vuepress-plugin-comment2: 2.0.0-beta.166 + vuepress-plugin-md-enhance: 2.0.0-beta.166 + vuepress-plugin-seo2: 2.0.0-beta.166 + vuepress-plugin-sitemap2: 2.0.0-beta.166 + windicss: ^3.5.6 dependencies: '@types/lodash.merge': 4.6.7 + '@vuepress-plume/vuepress-plugin-auto-frontmatter': link:../plugin-auto-frontmatter '@vuepress-plume/vuepress-plugin-baidu-tongji': link:../plugin-baidu-tongji + '@vuepress-plume/vuepress-plugin-blog-data': link:../plugin-blog-data '@vuepress-plume/vuepress-plugin-caniuse': link:../plugin-caniuse '@vuepress-plume/vuepress-plugin-copy-code': link:../plugin-copy-code - '@vuepress/client': 2.0.0-beta.51 - '@vuepress/core': 2.0.0-beta.51 - '@vuepress/plugin-active-header-links': 2.0.0-beta.51 - '@vuepress/plugin-container': 2.0.0-beta.51 - '@vuepress/plugin-docsearch': 2.0.0-beta.51 - '@vuepress/plugin-external-link-icon': 2.0.0-beta.51 - '@vuepress/plugin-git': 2.0.0-beta.51 - '@vuepress/plugin-medium-zoom': 2.0.0-beta.51 - '@vuepress/plugin-nprogress': 2.0.0-beta.51 - '@vuepress/plugin-palette': 2.0.0-beta.51 - '@vuepress/plugin-prismjs': 2.0.0-beta.51 - '@vuepress/plugin-search': 2.0.0-beta.51 - '@vuepress/plugin-theme-data': 2.0.0-beta.51 - '@vuepress/plugin-toc': 2.0.0-beta.51 - '@vuepress/shared': 2.0.0-beta.51 - '@vuepress/utils': 2.0.0-beta.51 - '@vueuse/core': 9.6.0_vue@3.2.45 - chokidar: 3.5.3 + '@vuepress-plume/vuepress-plugin-notes-data': link:../plugin-notes-data + '@vuepress/client': 2.0.0-beta.60 + '@vuepress/core': 2.0.0-beta.60 + '@vuepress/plugin-active-header-links': 2.0.0-beta.60 + '@vuepress/plugin-container': 2.0.0-beta.60 + '@vuepress/plugin-docsearch': 2.0.0-beta.60 + '@vuepress/plugin-external-link-icon': 2.0.0-beta.60 + '@vuepress/plugin-git': 2.0.0-beta.60 + '@vuepress/plugin-medium-zoom': 2.0.0-beta.60 + '@vuepress/plugin-nprogress': 2.0.0-beta.60 + '@vuepress/plugin-palette': 2.0.0-beta.60 + '@vuepress/plugin-prismjs': 2.0.0-beta.60 + '@vuepress/plugin-search': 2.0.0-beta.60 + '@vuepress/plugin-shiki': 2.0.0-beta.60 + '@vuepress/plugin-theme-data': 2.0.0-beta.60 + '@vuepress/plugin-toc': 2.0.0-beta.60 + '@vuepress/shared': 2.0.0-beta.60 + '@vuepress/utils': 2.0.0-beta.60 + '@vueuse/core': 9.10.0_vue@3.2.47 + body-scroll-lock: 4.0.0-beta.0 date-fns: 2.29.3 - gray-matter: 4.0.3 - json2yaml: 1.1.0 - lodash.merge: 4.6.2 nanoid: 4.0.0 - sass: 1.56.1 - sass-loader: 13.2.0_sass@1.56.1 ts-debounce: 4.0.0 - vue: 3.2.45 - vue-router: 4.1.5_vue@3.2.45 - vuepress-plugin-comment2: 2.0.0-beta.110_sass-loader@13.2.0 - vuepress-plugin-md-enhance: 2.0.0-beta.110_sass-loader@13.2.0 - vuepress-plugin-seo2: 2.0.0-beta.110 - vuepress-plugin-sitemap2: 2.0.0-beta.110 - - packages/theme-back: - specifiers: - '@types/lodash.merge': ^4.6.7 - '@vuepress-plume/vuepress-plugin-baidu-tongji': workspace:* - '@vuepress-plume/vuepress-plugin-caniuse': workspace:* - '@vuepress-plume/vuepress-plugin-copy-code': workspace:* - '@vuepress/client': 2.0.0-beta.51 - '@vuepress/core': 2.0.0-beta.51 - '@vuepress/plugin-active-header-links': 2.0.0-beta.51 - '@vuepress/plugin-container': 2.0.0-beta.51 - '@vuepress/plugin-docsearch': 2.0.0-beta.51 - '@vuepress/plugin-external-link-icon': 2.0.0-beta.51 - '@vuepress/plugin-git': 2.0.0-beta.51 - '@vuepress/plugin-medium-zoom': 2.0.0-beta.51 - '@vuepress/plugin-nprogress': 2.0.0-beta.51 - '@vuepress/plugin-palette': 2.0.0-beta.51 - '@vuepress/plugin-prismjs': 2.0.0-beta.51 - '@vuepress/plugin-search': 2.0.0-beta.51 - '@vuepress/plugin-theme-data': 2.0.0-beta.51 - '@vuepress/plugin-toc': 2.0.0-beta.51 - '@vuepress/shared': 2.0.0-beta.51 - '@vuepress/utils': 2.0.0-beta.51 - '@vueuse/core': ^9.3.0 - chokidar: ^3.5.3 - date-fns: ^2.29.3 - gray-matter: ^4.0.3 - json2yaml: ^1.1.0 - lodash.merge: ^4.6.2 - nanoid: ^4.0.0 - sass: ^1.55.0 - sass-loader: ^13.1.0 - ts-debounce: ^4.0.0 - vue: ^3.2.41 - vue-router: 4.1.5 - vuepress-plugin-comment2: 2.0.0-beta.110 - vuepress-plugin-md-enhance: 2.0.0-beta.110 - vuepress-plugin-seo2: 2.0.0-beta.110 - vuepress-plugin-sitemap2: 2.0.0-beta.110 - dependencies: - '@types/lodash.merge': 4.6.7 - '@vuepress-plume/vuepress-plugin-baidu-tongji': link:../plugin-baidu-tongji - '@vuepress-plume/vuepress-plugin-caniuse': link:../plugin-caniuse - '@vuepress-plume/vuepress-plugin-copy-code': link:../plugin-copy-code - '@vuepress/client': 2.0.0-beta.51 - '@vuepress/core': 2.0.0-beta.51 - '@vuepress/plugin-active-header-links': 2.0.0-beta.51 - '@vuepress/plugin-container': 2.0.0-beta.51 - '@vuepress/plugin-docsearch': 2.0.0-beta.51 - '@vuepress/plugin-external-link-icon': 2.0.0-beta.51 - '@vuepress/plugin-git': 2.0.0-beta.51 - '@vuepress/plugin-medium-zoom': 2.0.0-beta.51 - '@vuepress/plugin-nprogress': 2.0.0-beta.51 - '@vuepress/plugin-palette': 2.0.0-beta.51 - '@vuepress/plugin-prismjs': 2.0.0-beta.51 - '@vuepress/plugin-search': 2.0.0-beta.51 - '@vuepress/plugin-theme-data': 2.0.0-beta.51 - '@vuepress/plugin-toc': 2.0.0-beta.51 - '@vuepress/shared': 2.0.0-beta.51 - '@vuepress/utils': 2.0.0-beta.51 - '@vueuse/core': 9.6.0_vue@3.2.45 - chokidar: 3.5.3 - date-fns: 2.29.3 - gray-matter: 4.0.3 - json2yaml: 1.1.0 - lodash.merge: 4.6.2 - nanoid: 4.0.0 - sass: 1.56.1 - sass-loader: 13.2.0_sass@1.56.1 - ts-debounce: 4.0.0 - vue: 3.2.45 - vue-router: 4.1.5_vue@3.2.45 - vuepress-plugin-comment2: 2.0.0-beta.110_sass-loader@13.2.0 - vuepress-plugin-md-enhance: 2.0.0-beta.110_sass-loader@13.2.0 - vuepress-plugin-seo2: 2.0.0-beta.110 - vuepress-plugin-sitemap2: 2.0.0-beta.110 + vue: 3.2.47 + vue-router: 4.1.6_vue@3.2.47 + vuepress-plugin-comment2: 2.0.0-beta.166_aknydt7aotgymh3yxf7whaz6ti + vuepress-plugin-md-enhance: 2.0.0-beta.166_aknydt7aotgymh3yxf7whaz6ti + vuepress-plugin-seo2: 2.0.0-beta.166_aknydt7aotgymh3yxf7whaz6ti + vuepress-plugin-sitemap2: 2.0.0-beta.166_aknydt7aotgymh3yxf7whaz6ti + windicss: 3.5.6 packages: @@ -494,59 +478,64 @@ packages: /@antfu/utils/0.5.2: resolution: {integrity: sha512-CQkeV+oJxUazwjlHD0/3ZD08QWKuGQkhnrKo3e6ly5pd48VUpXbb77q0xMU4+vc2CkJnDS02Eq/M9ugyX20XZA==} + /@antfu/utils/0.7.2: + resolution: {integrity: sha512-vy9fM3pIxZmX07dL+VX1aZe7ynZ+YyB0jY+jE6r3hOK6GNY2t6W8rzpFC4tgpbXUYABkFQwgJq2XYXlxbXAI0g==} + dev: false + /@babel/code-frame/7.18.6: resolution: {integrity: sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==} engines: {node: '>=6.9.0'} dependencies: '@babel/highlight': 7.18.6 - /@babel/compat-data/7.20.5: - resolution: {integrity: sha512-KZXo2t10+/jxmkhNXc7pZTqRvSOIvVv/+lJwHS+B2rErwOyjuVRh60yVpb7liQ1U5t7lLJ1bz+t8tSypUZdm0g==} + /@babel/compat-data/7.20.10: + resolution: {integrity: sha512-sEnuDPpOJR/fcafHMjpcpGN5M2jbUGUHwmuWKM/YdPzeEDJg8bgmbcWQFUfE32MQjti1koACvoPVsDe8Uq+idg==} engines: {node: '>=6.9.0'} dev: false - /@babel/core/7.20.5: - resolution: {integrity: sha512-UdOWmk4pNWTm/4DlPUl/Pt4Gz4rcEMb7CY0Y3eJl5Yz1vI8ZJGmHWaVE55LoxRjdpx0z259GE9U5STA9atUinQ==} + /@babel/core/7.20.12: + resolution: {integrity: sha512-XsMfHovsUYHFMdrIHkZphTN/2Hzzi78R08NuHfDBehym2VsPDL6Zn/JAD/JQdnRvbSsbQc4mVaU1m6JgtTEElg==} engines: {node: '>=6.9.0'} dependencies: '@ampproject/remapping': 2.2.0 '@babel/code-frame': 7.18.6 - '@babel/generator': 7.20.5 - '@babel/helper-compilation-targets': 7.20.0_@babel+core@7.20.5 - '@babel/helper-module-transforms': 7.20.2 - '@babel/helpers': 7.20.6 - '@babel/parser': 7.20.5 - '@babel/template': 7.18.10 - '@babel/traverse': 7.20.5 - '@babel/types': 7.20.5 - convert-source-map: 1.9.0 + '@babel/generator': 7.20.7 + '@babel/helper-compilation-targets': 7.20.7_@babel+core@7.20.12 + '@babel/helper-module-transforms': 7.20.11 + '@babel/helpers': 7.20.7 + '@babel/parser': 7.20.7 + '@babel/template': 7.20.7 + '@babel/traverse': 7.20.12 + '@babel/types': 7.20.7 + convert-source-map: 1.8.0 debug: 4.3.4 gensync: 1.0.0-beta.2 - json5: 2.2.1 + json5: 2.2.3 semver: 6.3.0 transitivePeerDependencies: - supports-color dev: false - /@babel/generator/7.20.5: - resolution: {integrity: sha512-jl7JY2Ykn9S0yj4DQP82sYvPU+T3g0HFcWTqDLqiuA9tGRNIj9VfbtXGAYTTkyNEnQk1jkMGOdYka8aG/lulCA==} + /@babel/generator/7.20.7: + resolution: {integrity: sha512-7wqMOJq8doJMZmP4ApXTzLxSr7+oO2jroJURrVEp6XShrQUObV8Tq/D0NCcoYg2uHqUrjzO0zwBjoYzelxK+sw==} engines: {node: '>=6.9.0'} dependencies: - '@babel/types': 7.20.5 + '@babel/types': 7.20.7 '@jridgewell/gen-mapping': 0.3.2 jsesc: 2.5.2 dev: false - /@babel/helper-compilation-targets/7.20.0_@babel+core@7.20.5: - resolution: {integrity: sha512-0jp//vDGp9e8hZzBc6N/KwA5ZK3Wsm/pfm4CrY7vzegkVxc65SgSn6wYOnwHe9Js9HRQ1YTCKLGPzDtaS3RoLQ==} + /@babel/helper-compilation-targets/7.20.7_@babel+core@7.20.12: + resolution: {integrity: sha512-4tGORmfQcrc+bvrjb5y3dG9Mx1IOZjsHqQVUz7XCNHO+iTmqxWnVg3KRygjGmpRLJGdQSKuvFinbIb0CnZwHAQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 dependencies: - '@babel/compat-data': 7.20.5 - '@babel/core': 7.20.5 + '@babel/compat-data': 7.20.10 + '@babel/core': 7.20.12 '@babel/helper-validator-option': 7.18.6 browserslist: 4.21.4 + lru-cache: 5.1.1 semver: 6.3.0 dev: false @@ -559,26 +548,26 @@ packages: resolution: {integrity: sha512-WAwHBINyrpqywkUH0nTnNgI5ina5TFn85HKS0pbPDfxFfhyR/aNQEn4hGi1P1JyT//I0t4OgXUlofzWILRvS5w==} engines: {node: '>=6.9.0'} dependencies: - '@babel/template': 7.18.10 - '@babel/types': 7.20.5 + '@babel/template': 7.20.7 + '@babel/types': 7.20.7 dev: false /@babel/helper-hoist-variables/7.18.6: resolution: {integrity: sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q==} engines: {node: '>=6.9.0'} dependencies: - '@babel/types': 7.20.5 + '@babel/types': 7.20.7 dev: false /@babel/helper-module-imports/7.18.6: resolution: {integrity: sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA==} engines: {node: '>=6.9.0'} dependencies: - '@babel/types': 7.20.5 + '@babel/types': 7.20.7 dev: false - /@babel/helper-module-transforms/7.20.2: - resolution: {integrity: sha512-zvBKyJXRbmK07XhMuujYoJ48B5yvvmM6+wcpv6Ivj4Yg6qO7NOZOSnvZN9CRl1zz1Z4cKf8YejmCMh8clOoOeA==} + /@babel/helper-module-transforms/7.20.11: + resolution: {integrity: sha512-uRy78kN4psmji1s2QtbtcCSaj/LILFDp0f/ymhpQH5QY3nljUZCaNWz9X1dEj/8MBdBEFECs7yRhKn8i7NjZgg==} engines: {node: '>=6.9.0'} dependencies: '@babel/helper-environment-visitor': 7.18.9 @@ -586,9 +575,9 @@ packages: '@babel/helper-simple-access': 7.20.2 '@babel/helper-split-export-declaration': 7.18.6 '@babel/helper-validator-identifier': 7.19.1 - '@babel/template': 7.18.10 - '@babel/traverse': 7.20.5 - '@babel/types': 7.20.5 + '@babel/template': 7.20.7 + '@babel/traverse': 7.20.12 + '@babel/types': 7.20.7 transitivePeerDependencies: - supports-color dev: false @@ -597,14 +586,14 @@ packages: resolution: {integrity: sha512-+0woI/WPq59IrqDYbVGfshjT5Dmk/nnbdpcF8SnMhhXObpTq2KNBdLFRFrkVdbDOyUmHBCxzm5FHV1rACIkIbA==} engines: {node: '>=6.9.0'} dependencies: - '@babel/types': 7.20.5 + '@babel/types': 7.20.7 dev: false /@babel/helper-split-export-declaration/7.18.6: resolution: {integrity: sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA==} engines: {node: '>=6.9.0'} dependencies: - '@babel/types': 7.20.5 + '@babel/types': 7.20.7 dev: false /@babel/helper-string-parser/7.19.4: @@ -621,13 +610,13 @@ packages: engines: {node: '>=6.9.0'} dev: false - /@babel/helpers/7.20.6: - resolution: {integrity: sha512-Pf/OjgfgFRW5bApskEz5pvidpim7tEDPlFtKcNRXWmfHGn9IEI2W2flqRQXTFb7gIPTyK++N6rVHuwKut4XK6w==} + /@babel/helpers/7.20.7: + resolution: {integrity: sha512-PBPjs5BppzsGaxHQCDKnZ6Gd9s6xl8bBCluz3vEInLGRJmnZan4F6BYCeqtyXqkk4W5IlPmjK4JlOuZkpJ3xZA==} engines: {node: '>=6.9.0'} dependencies: - '@babel/template': 7.18.10 - '@babel/traverse': 7.20.5 - '@babel/types': 7.20.5 + '@babel/template': 7.20.7 + '@babel/traverse': 7.20.12 + '@babel/types': 7.20.7 transitivePeerDependencies: - supports-color dev: false @@ -645,15 +634,15 @@ packages: engines: {node: '>=6.0.0'} hasBin: true dependencies: - '@babel/types': 7.20.5 + '@babel/types': 7.20.7 dev: false - /@babel/parser/7.20.5: - resolution: {integrity: sha512-r27t/cy/m9uKLXQNWWebeCUHgnAZq0CpG1OwKRxzJMP1vpSU4bSIK2hq+/cp0bQxetkXx38n09rNu8jVkcK/zA==} + /@babel/parser/7.20.7: + resolution: {integrity: sha512-T3Z9oHybU+0vZlY9CiDSJQTD5ZapcW18ZctFMi0MOAl/4BjFF4ul7NVSARLdbGO5vDqy9eQiGTV0LtKfvCYvcg==} engines: {node: '>=6.0.0'} hasBin: true dependencies: - '@babel/types': 7.20.5 + '@babel/types': 7.20.7 dev: false /@babel/runtime-corejs3/7.20.6: @@ -671,35 +660,35 @@ packages: regenerator-runtime: 0.13.11 dev: false - /@babel/template/7.18.10: - resolution: {integrity: sha512-TI+rCtooWHr3QJ27kJxfjutghu44DLnasDMwpDqCXVTal9RLp3RSYNh4NdBrRP2cQAoG9A8juOQl6P6oZG4JxA==} + /@babel/template/7.20.7: + resolution: {integrity: sha512-8SegXApWe6VoNw0r9JHpSteLKTpTiLZ4rMlGIm9JQ18KiCtyQiAMEazujAHrUS5flrcqYZa75ukev3P6QmUwUw==} engines: {node: '>=6.9.0'} dependencies: '@babel/code-frame': 7.18.6 - '@babel/parser': 7.20.5 - '@babel/types': 7.20.5 + '@babel/parser': 7.20.7 + '@babel/types': 7.20.7 dev: false - /@babel/traverse/7.20.5: - resolution: {integrity: sha512-WM5ZNN3JITQIq9tFZaw1ojLU3WgWdtkxnhM1AegMS+PvHjkM5IXjmYEGY7yukz5XS4sJyEf2VzWjI8uAavhxBQ==} + /@babel/traverse/7.20.12: + resolution: {integrity: sha512-MsIbFN0u+raeja38qboyF8TIT7K0BFzz/Yd/77ta4MsUsmP2RAnidIlwq7d5HFQrH/OZJecGV6B71C4zAgpoSQ==} engines: {node: '>=6.9.0'} dependencies: '@babel/code-frame': 7.18.6 - '@babel/generator': 7.20.5 + '@babel/generator': 7.20.7 '@babel/helper-environment-visitor': 7.18.9 '@babel/helper-function-name': 7.19.0 '@babel/helper-hoist-variables': 7.18.6 '@babel/helper-split-export-declaration': 7.18.6 - '@babel/parser': 7.20.5 - '@babel/types': 7.20.5 + '@babel/parser': 7.20.7 + '@babel/types': 7.20.7 debug: 4.3.4 globals: 11.12.0 transitivePeerDependencies: - supports-color dev: false - /@babel/types/7.20.5: - resolution: {integrity: sha512-c9fst/h2/dcF7H+MJKZ2T0KjEQ8hY/BNnDk/H3XY8C4Aw/eWQXWn/lWntHF9ooUBnGmEvbfGrTgLWc+um0YDUg==} + /@babel/types/7.20.7: + resolution: {integrity: sha512-69OnhBxSSgK0OzTJai4kyPDiKTIe3j+ctaHdIGVbRahTLAT7L3R9oeXHC2aVSuGYt3cVnoAMDmOCgJ2yaiLMvg==} engines: {node: '>=6.9.0'} dependencies: '@babel/helper-string-parser': 7.19.4 @@ -758,16 +747,16 @@ packages: engines: {node: '>=0.1.90'} dev: false - /@commitlint/cli/17.3.0: - resolution: {integrity: sha512-/H0md7TsKflKzVPz226VfXzVafJFO1f9+r2KcFvmBu08V0T56lZU1s8WL7/xlxqLMqBTVaBf7Ixtc4bskdEEZg==} + /@commitlint/cli/17.4.2: + resolution: {integrity: sha512-0rPGJ2O1owhpxMIXL9YJ2CgPkdrFLKZElIZHXDN8L8+qWK1DGH7Q7IelBT1pchXTYTuDlqkOTdh//aTvT3bSUA==} engines: {node: '>=v14'} hasBin: true dependencies: - '@commitlint/format': 17.0.0 - '@commitlint/lint': 17.3.0 - '@commitlint/load': 17.3.0 - '@commitlint/read': 17.2.0 - '@commitlint/types': 17.0.0 + '@commitlint/format': 17.4.0 + '@commitlint/lint': 17.4.2 + '@commitlint/load': 17.4.2 + '@commitlint/read': 17.4.2 + '@commitlint/types': 17.4.0 execa: 5.1.1 lodash.isfunction: 3.0.9 resolve-from: 5.0.0 @@ -778,26 +767,26 @@ packages: - '@swc/wasm' dev: true - /@commitlint/config-conventional/17.3.0: - resolution: {integrity: sha512-hgI+fN5xF8nhS9uG/V06xyT0nlcyvHHMkq0kwRSr96vl5BFlRGaL2C0/YY4kQagfU087tmj01bJkG9Ek98Wllw==} + /@commitlint/config-conventional/17.4.2: + resolution: {integrity: sha512-JVo1moSj5eDMoql159q8zKCU8lkOhQ+b23Vl3LVVrS6PXDLQIELnJ34ChQmFVbBdSSRNAbbXnRDhosFU+wnuHw==} engines: {node: '>=v14'} dependencies: conventional-changelog-conventionalcommits: 5.0.0 dev: true - /@commitlint/config-validator/17.1.0: - resolution: {integrity: sha512-Q1rRRSU09ngrTgeTXHq6ePJs2KrI+axPTgkNYDWSJIuS1Op4w3J30vUfSXjwn5YEJHklK3fSqWNHmBhmTR7Vdg==} + /@commitlint/config-validator/17.4.0: + resolution: {integrity: sha512-Sa/+8KNpDXz4zT4bVbz2fpFjvgkPO6u2V2fP4TKgt6FjmOw2z3eEX859vtfeaTav/ukBw0/0jr+5ZTZp9zCBhA==} engines: {node: '>=v14'} dependencies: - '@commitlint/types': 17.0.0 + '@commitlint/types': 17.4.0 ajv: 8.11.2 dev: true - /@commitlint/ensure/17.3.0: - resolution: {integrity: sha512-kWbrQHDoW5veIUQx30gXoLOCjWvwC6OOEofhPCLl5ytRPBDAQObMbxTha1Bt2aSyNE/IrJ0s0xkdZ1Gi3wJwQg==} + /@commitlint/ensure/17.4.0: + resolution: {integrity: sha512-7oAxt25je0jeQ/E0O/M8L3ADb1Cvweu/5lc/kYF8g/kXatI0wxGE5La52onnAUAWeWlsuvBNar15WcrmDmr5Mw==} engines: {node: '>=v14'} dependencies: - '@commitlint/types': 17.0.0 + '@commitlint/types': 17.4.0 lodash.camelcase: 4.3.0 lodash.kebabcase: 4.1.1 lodash.snakecase: 4.1.1 @@ -805,122 +794,122 @@ packages: lodash.upperfirst: 4.3.1 dev: true - /@commitlint/execute-rule/17.0.0: - resolution: {integrity: sha512-nVjL/w/zuqjCqSJm8UfpNaw66V9WzuJtQvEnCrK4jDw6qKTmZB+1JQ8m6BQVZbNBcwfYdDNKnhIhqI0Rk7lgpQ==} + /@commitlint/execute-rule/17.4.0: + resolution: {integrity: sha512-LIgYXuCSO5Gvtc0t9bebAMSwd68ewzmqLypqI2Kke1rqOqqDbMpYcYfoPfFlv9eyLIh4jocHWwCK5FS7z9icUA==} engines: {node: '>=v14'} dev: true - /@commitlint/format/17.0.0: - resolution: {integrity: sha512-MZzJv7rBp/r6ZQJDEodoZvdRM0vXu1PfQvMTNWFb8jFraxnISMTnPBWMMjr2G/puoMashwaNM//fl7j8gGV5lA==} + /@commitlint/format/17.4.0: + resolution: {integrity: sha512-Z2bWAU5+f1YZh9W76c84J8iLIWIvvm+mzqogTz0Nsc1x6EHW0Z2gI38g5HAjB0r0I3ZjR15IDEJKhsxyblcyhA==} engines: {node: '>=v14'} dependencies: - '@commitlint/types': 17.0.0 + '@commitlint/types': 17.4.0 chalk: 4.1.2 dev: true - /@commitlint/is-ignored/17.2.0: - resolution: {integrity: sha512-rgUPUQraHxoMLxiE8GK430HA7/R2vXyLcOT4fQooNrZq9ERutNrP6dw3gdKLkq22Nede3+gEHQYUzL4Wu75ndg==} + /@commitlint/is-ignored/17.4.2: + resolution: {integrity: sha512-1b2Y2qJ6n7bHG9K6h8S4lBGUl6kc7mMhJN9gy1SQfUZqe92ToDjUTtgNWb6LbzR1X8Cq4SEus4VU8Z/riEa94Q==} engines: {node: '>=v14'} dependencies: - '@commitlint/types': 17.0.0 - semver: 7.3.7 + '@commitlint/types': 17.4.0 + semver: 7.3.8 dev: true - /@commitlint/lint/17.3.0: - resolution: {integrity: sha512-VilOTPg0i9A7CCWM49E9bl5jytfTvfTxf9iwbWAWNjxJ/A5mhPKbm3sHuAdwJ87tDk1k4j8vomYfH23iaY+1Rw==} + /@commitlint/lint/17.4.2: + resolution: {integrity: sha512-HcymabrdBhsDMNzIv146+ZPNBPBK5gMNsVH+el2lCagnYgCi/4ixrHooeVyS64Fgce2K26+MC7OQ4vVH8wQWVw==} engines: {node: '>=v14'} dependencies: - '@commitlint/is-ignored': 17.2.0 - '@commitlint/parse': 17.2.0 - '@commitlint/rules': 17.3.0 - '@commitlint/types': 17.0.0 + '@commitlint/is-ignored': 17.4.2 + '@commitlint/parse': 17.4.2 + '@commitlint/rules': 17.4.2 + '@commitlint/types': 17.4.0 dev: true - /@commitlint/load/17.3.0: - resolution: {integrity: sha512-u/pV6rCAJrCUN+HylBHLzZ4qj1Ew3+eN9GBPhNi9otGxtOfA8b+8nJSxaNbcC23Ins/kcpjGf9zPSVW7628Umw==} + /@commitlint/load/17.4.2: + resolution: {integrity: sha512-Si++F85rJ9t4hw6JcOw1i2h0fdpdFQt0YKwjuK4bk9KhFjyFkRxvR3SB2dPaMs+EwWlDrDBGL+ygip1QD6gmPw==} engines: {node: '>=v14'} dependencies: - '@commitlint/config-validator': 17.1.0 - '@commitlint/execute-rule': 17.0.0 - '@commitlint/resolve-extends': 17.3.0 - '@commitlint/types': 17.0.0 - '@types/node': 14.18.33 + '@commitlint/config-validator': 17.4.0 + '@commitlint/execute-rule': 17.4.0 + '@commitlint/resolve-extends': 17.4.0 + '@commitlint/types': 17.4.0 + '@types/node': 18.11.18 chalk: 4.1.2 - cosmiconfig: 7.1.0 - cosmiconfig-typescript-loader: 4.2.0_qoh33be55smklb2oyrgdyddh4a + cosmiconfig: 8.0.0 + cosmiconfig-typescript-loader: 4.3.0_bxtyj3et3xbsdyxhh3oblnfbj4 lodash.isplainobject: 4.0.6 lodash.merge: 4.6.2 lodash.uniq: 4.5.0 resolve-from: 5.0.0 - ts-node: 10.9.1_kluoused5zacjtflizwvdqgpom - typescript: 4.9.3 + ts-node: 10.9.1_awa2wsr5thmg3i7jqycphctjfq + typescript: 4.9.4 transitivePeerDependencies: - '@swc/core' - '@swc/wasm' dev: true - /@commitlint/message/17.2.0: - resolution: {integrity: sha512-/4l2KFKxBOuoEn1YAuuNNlAU05Zt7sNsC9H0mPdPm3chOrT4rcX0pOqrQcLtdMrMkJz0gC7b3SF80q2+LtdL9Q==} + /@commitlint/message/17.4.2: + resolution: {integrity: sha512-3XMNbzB+3bhKA1hSAWPCQA3lNxR4zaeQAQcHj0Hx5sVdO6ryXtgUBGGv+1ZCLMgAPRixuc6en+iNAzZ4NzAa8Q==} engines: {node: '>=v14'} dev: true - /@commitlint/parse/17.2.0: - resolution: {integrity: sha512-vLzLznK9Y21zQ6F9hf8D6kcIJRb2haAK5T/Vt1uW2CbHYOIfNsR/hJs0XnF/J9ctM20Tfsqv4zBitbYvVw7F6Q==} + /@commitlint/parse/17.4.2: + resolution: {integrity: sha512-DK4EwqhxfXpyCA+UH8TBRIAXAfmmX4q9QRBz/2h9F9sI91yt6mltTrL6TKURMcjUVmgaB80wgS9QybNIyVBIJA==} engines: {node: '>=v14'} dependencies: - '@commitlint/types': 17.0.0 + '@commitlint/types': 17.4.0 conventional-changelog-angular: 5.0.13 conventional-commits-parser: 3.2.4 dev: true - /@commitlint/read/17.2.0: - resolution: {integrity: sha512-bbblBhrHkjxra3ptJNm0abxu7yeAaxumQ8ZtD6GIVqzURCETCP7Dm0tlVvGRDyXBuqX6lIJxh3W7oyKqllDsHQ==} + /@commitlint/read/17.4.2: + resolution: {integrity: sha512-hasYOdbhEg+W4hi0InmXHxtD/1favB4WdwyFxs1eOy/DvMw6+2IZBmATgGOlqhahsypk4kChhxjAFJAZ2F+JBg==} engines: {node: '>=v14'} dependencies: - '@commitlint/top-level': 17.0.0 - '@commitlint/types': 17.0.0 - fs-extra: 10.1.0 + '@commitlint/top-level': 17.4.0 + '@commitlint/types': 17.4.0 + fs-extra: 11.1.0 git-raw-commits: 2.0.11 minimist: 1.2.7 dev: true - /@commitlint/resolve-extends/17.3.0: - resolution: {integrity: sha512-Lf3JufJlc5yVEtJWC8o4IAZaB8FQAUaVlhlAHRACd0TTFizV2Lk2VH70et23KgvbQNf7kQzHs/2B4QZalBv6Cg==} + /@commitlint/resolve-extends/17.4.0: + resolution: {integrity: sha512-3JsmwkrCzoK8sO22AzLBvNEvC1Pmdn/65RKXzEtQMy6oYMl0Snrq97a5bQQEFETF0VsvbtUuKttLqqgn99OXRQ==} engines: {node: '>=v14'} dependencies: - '@commitlint/config-validator': 17.1.0 - '@commitlint/types': 17.0.0 + '@commitlint/config-validator': 17.4.0 + '@commitlint/types': 17.4.0 import-fresh: 3.3.0 lodash.mergewith: 4.6.2 resolve-from: 5.0.0 resolve-global: 1.0.0 dev: true - /@commitlint/rules/17.3.0: - resolution: {integrity: sha512-s2UhDjC5yP2utx3WWqsnZRzjgzAX8BMwr1nltC0u0p8T/nzpkx4TojEfhlsOUj1t7efxzZRjUAV0NxNwdJyk+g==} + /@commitlint/rules/17.4.2: + resolution: {integrity: sha512-OGrPsMb9Fx3/bZ64/EzJehY9YDSGWzp81Pj+zJiY+r/NSgJI3nUYdlS37jykNIugzazdEXfMtQ10kmA+Kx2pZQ==} engines: {node: '>=v14'} dependencies: - '@commitlint/ensure': 17.3.0 - '@commitlint/message': 17.2.0 - '@commitlint/to-lines': 17.0.0 - '@commitlint/types': 17.0.0 + '@commitlint/ensure': 17.4.0 + '@commitlint/message': 17.4.2 + '@commitlint/to-lines': 17.4.0 + '@commitlint/types': 17.4.0 execa: 5.1.1 dev: true - /@commitlint/to-lines/17.0.0: - resolution: {integrity: sha512-nEi4YEz04Rf2upFbpnEorG8iymyH7o9jYIVFBG1QdzebbIFET3ir+8kQvCZuBE5pKCtViE4XBUsRZz139uFrRQ==} + /@commitlint/to-lines/17.4.0: + resolution: {integrity: sha512-LcIy/6ZZolsfwDUWfN1mJ+co09soSuNASfKEU5sCmgFCvX5iHwRYLiIuoqXzOVDYOy7E7IcHilr/KS0e5T+0Hg==} engines: {node: '>=v14'} dev: true - /@commitlint/top-level/17.0.0: - resolution: {integrity: sha512-dZrEP1PBJvodNWYPOYiLWf6XZergdksKQaT6i1KSROLdjf5Ai0brLOv5/P+CPxBeoj3vBxK4Ax8H1Pg9t7sHIQ==} + /@commitlint/top-level/17.4.0: + resolution: {integrity: sha512-/1loE/g+dTTQgHnjoCy0AexKAEFyHsR2zRB4NWrZ6lZSMIxAhBJnmCqwao7b4H8888PsfoTBCLBYIw8vGnej8g==} engines: {node: '>=v14'} dependencies: find-up: 5.0.0 dev: true - /@commitlint/types/17.0.0: - resolution: {integrity: sha512-hBAw6U+SkAT5h47zDMeOu3HSiD0SODw4Aq7rRNh1ceUmL7GyLKYhPbUvlRWqZ65XjBLPHZhFyQlRaPNz8qvUyQ==} + /@commitlint/types/17.4.0: + resolution: {integrity: sha512-2NjAnq5IcxY9kXtUeO2Ac0aPpvkuOmwbH/BxIm36XXK5LtWFObWJWjXOA+kcaABMrthjWu6la+FUpyYFMHRvbA==} engines: {node: '>=v14'} dependencies: chalk: 4.1.2 @@ -940,15 +929,15 @@ packages: kuler: 2.0.0 dev: false - /@docsearch/css/3.3.0: - resolution: {integrity: sha512-rODCdDtGyudLj+Va8b6w6Y85KE85bXRsps/R4Yjwt5vueXKXZQKYw0aA9knxLBT6a/bI/GMrAcmCR75KYOM6hg==} + /@docsearch/css/3.3.1: + resolution: {integrity: sha512-nznHXeFHpAYjyaSNFNFpU+IJPjQA7AINM8ONjDx/Zx4O/pGAvqwgmcLNc7zR8qXRutqnzLo06yN63xFn36KFBw==} dev: false - /@docsearch/js/3.3.0: - resolution: {integrity: sha512-oFXWRPNvPxAzBhnFJ9UCFIYZiQNc3Yrv6912nZHw/UIGxsyzKpNRZgHq8HDk1niYmOSoLKtVFcxkccpQmYGFyg==} + /@docsearch/js/3.3.1: + resolution: {integrity: sha512-BCVu7njUFJSUXDNvgK65xNYU1L7U3CKFJlawDXql17nQwfpBrNZHqp+eb8z9qu0SzauQKss9tsf/qwlFJ9BOGw==} dependencies: - '@docsearch/react': 3.3.0 - preact: 10.11.3 + '@docsearch/react': 3.3.1 + preact: 10.10.0 transitivePeerDependencies: - '@algolia/client-search' - '@types/react' @@ -956,8 +945,8 @@ packages: - react-dom dev: false - /@docsearch/react/3.3.0: - resolution: {integrity: sha512-fhS5adZkae2SSdMYEMVg6pxI5a/cE+tW16ki1V0/ur4Fdok3hBRkmN/H8VvlXnxzggkQIIRIVvYPn00JPjen3A==} + /@docsearch/react/3.3.1: + resolution: {integrity: sha512-wdeQBODPkue6yVEEg4ntt+TiGJ6iXMBUNjBQJ0s1WVoc1OdcCnks/lkQ5LEfXETYR/q9QSbCCBnMjvnSoILaag==} peerDependencies: '@types/react': '>= 16.8.0 < 19.0.0' react: '>= 16.8.0 < 19.0.0' @@ -972,7 +961,7 @@ packages: dependencies: '@algolia/autocomplete-core': 1.7.2 '@algolia/autocomplete-preset-algolia': 1.7.2_algoliasearch@4.14.2 - '@docsearch/css': 3.3.0 + '@docsearch/css': 3.3.1 algoliasearch: 4.14.2 transitivePeerDependencies: - '@algolia/client-search' @@ -984,15 +973,87 @@ packages: cpu: [arm] os: [android] requiresBuild: true + dev: false optional: true - /@esbuild/linux-loong64/0.14.54: - resolution: {integrity: sha512-bZBrLAIX1kpWelV0XemxBZllyRmM6vgFQQG2GdNb+r3Fkp0FOh1NJSvekXDs7jq70k4euu1cryLMfU+mTXlEpw==} + /@esbuild/android-arm/0.16.17: + resolution: {integrity: sha512-N9x1CMXVhtWEAMS7pNNONyA14f71VPQN9Cnavj1XQh6T7bskqiLLrSca4O0Vr8Wdcga943eThxnVp3JLnBMYtw==} engines: {node: '>=12'} - cpu: [loong64] + cpu: [arm] + os: [android] + requiresBuild: true + optional: true + + /@esbuild/android-arm64/0.16.17: + resolution: {integrity: sha512-MIGl6p5sc3RDTLLkYL1MyL8BMRN4tLMRCn+yRJJmEDvYZ2M7tmAf80hx1kbNEUX2KJ50RRtxZ4JHLvCfuB6kBg==} + engines: {node: '>=12'} + cpu: [arm64] + os: [android] + requiresBuild: true + optional: true + + /@esbuild/android-x64/0.16.17: + resolution: {integrity: sha512-a3kTv3m0Ghh4z1DaFEuEDfz3OLONKuFvI4Xqczqx4BqLyuFaFkuaG4j2MtA6fuWEFeC5x9IvqnX7drmRq/fyAQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [android] + requiresBuild: true + optional: true + + /@esbuild/darwin-arm64/0.16.17: + resolution: {integrity: sha512-/2agbUEfmxWHi9ARTX6OQ/KgXnOWfsNlTeLcoV7HSuSTv63E4DqtAc+2XqGw1KHxKMHGZgbVCZge7HXWX9Vn+w==} + engines: {node: '>=12'} + cpu: [arm64] + os: [darwin] + requiresBuild: true + optional: true + + /@esbuild/darwin-x64/0.16.17: + resolution: {integrity: sha512-2By45OBHulkd9Svy5IOCZt376Aa2oOkiE9QWUK9fe6Tb+WDr8hXL3dpqi+DeLiMed8tVXspzsTAvd0jUl96wmg==} + engines: {node: '>=12'} + cpu: [x64] + os: [darwin] + requiresBuild: true + optional: true + + /@esbuild/freebsd-arm64/0.16.17: + resolution: {integrity: sha512-mt+cxZe1tVx489VTb4mBAOo2aKSnJ33L9fr25JXpqQqzbUIw/yzIzi+NHwAXK2qYV1lEFp4OoVeThGjUbmWmdw==} + engines: {node: '>=12'} + cpu: [arm64] + os: [freebsd] + requiresBuild: true + optional: true + + /@esbuild/freebsd-x64/0.16.17: + resolution: {integrity: sha512-8ScTdNJl5idAKjH8zGAsN7RuWcyHG3BAvMNpKOBaqqR7EbUhhVHOqXRdL7oZvz8WNHL2pr5+eIT5c65kA6NHug==} + engines: {node: '>=12'} + cpu: [x64] + os: [freebsd] + requiresBuild: true + optional: true + + /@esbuild/linux-arm/0.16.17: + resolution: {integrity: sha512-iihzrWbD4gIT7j3caMzKb/RsFFHCwqqbrbH9SqUSRrdXkXaygSZCZg1FybsZz57Ju7N/SHEgPyaR0LZ8Zbe9gQ==} + engines: {node: '>=12'} + cpu: [arm] + os: [linux] + requiresBuild: true + optional: true + + /@esbuild/linux-arm64/0.16.17: + resolution: {integrity: sha512-7S8gJnSlqKGVJunnMCrXHU9Q8Q/tQIxk/xL8BqAP64wchPCTzuM6W3Ra8cIa1HIflAvDnNOt2jaL17vaW+1V0g==} + engines: {node: '>=12'} + cpu: [arm64] + os: [linux] + requiresBuild: true + optional: true + + /@esbuild/linux-ia32/0.16.17: + resolution: {integrity: sha512-kiX69+wcPAdgl3Lonh1VI7MBr16nktEvOfViszBSxygRQqSpzv7BffMKRPMFwzeJGPxcio0pdD3kYQGpqQ2SSg==} + engines: {node: '>=12'} + cpu: [ia32] os: [linux] requiresBuild: true - dev: false optional: true /@esbuild/linux-loong64/0.15.16: @@ -1001,17 +1062,114 @@ packages: cpu: [loong64] os: [linux] requiresBuild: true + dev: false optional: true - /@eslint/eslintrc/1.3.3: - resolution: {integrity: sha512-uj3pT6Mg+3t39fvLrj8iuCIJ38zKO9FpGtJ4BBJebJhEwjoT+KLVNCcHT5QC9NGRIEi7fZ0ZR8YRb884auB4Lg==} + /@esbuild/linux-loong64/0.16.17: + resolution: {integrity: sha512-dTzNnQwembNDhd654cA4QhbS9uDdXC3TKqMJjgOWsC0yNCbpzfWoXdZvp0mY7HU6nzk5E0zpRGGx3qoQg8T2DQ==} + engines: {node: '>=12'} + cpu: [loong64] + os: [linux] + requiresBuild: true + optional: true + + /@esbuild/linux-mips64el/0.16.17: + resolution: {integrity: sha512-ezbDkp2nDl0PfIUn0CsQ30kxfcLTlcx4Foz2kYv8qdC6ia2oX5Q3E/8m6lq84Dj/6b0FrkgD582fJMIfHhJfSw==} + engines: {node: '>=12'} + cpu: [mips64el] + os: [linux] + requiresBuild: true + optional: true + + /@esbuild/linux-ppc64/0.16.17: + resolution: {integrity: sha512-dzS678gYD1lJsW73zrFhDApLVdM3cUF2MvAa1D8K8KtcSKdLBPP4zZSLy6LFZ0jYqQdQ29bjAHJDgz0rVbLB3g==} + engines: {node: '>=12'} + cpu: [ppc64] + os: [linux] + requiresBuild: true + optional: true + + /@esbuild/linux-riscv64/0.16.17: + resolution: {integrity: sha512-ylNlVsxuFjZK8DQtNUwiMskh6nT0vI7kYl/4fZgV1llP5d6+HIeL/vmmm3jpuoo8+NuXjQVZxmKuhDApK0/cKw==} + engines: {node: '>=12'} + cpu: [riscv64] + os: [linux] + requiresBuild: true + optional: true + + /@esbuild/linux-s390x/0.16.17: + resolution: {integrity: sha512-gzy7nUTO4UA4oZ2wAMXPNBGTzZFP7mss3aKR2hH+/4UUkCOyqmjXiKpzGrY2TlEUhbbejzXVKKGazYcQTZWA/w==} + engines: {node: '>=12'} + cpu: [s390x] + os: [linux] + requiresBuild: true + optional: true + + /@esbuild/linux-x64/0.16.17: + resolution: {integrity: sha512-mdPjPxfnmoqhgpiEArqi4egmBAMYvaObgn4poorpUaqmvzzbvqbowRllQ+ZgzGVMGKaPkqUmPDOOFQRUFDmeUw==} + engines: {node: '>=12'} + cpu: [x64] + os: [linux] + requiresBuild: true + optional: true + + /@esbuild/netbsd-x64/0.16.17: + resolution: {integrity: sha512-/PzmzD/zyAeTUsduZa32bn0ORug+Jd1EGGAUJvqfeixoEISYpGnAezN6lnJoskauoai0Jrs+XSyvDhppCPoKOA==} + engines: {node: '>=12'} + cpu: [x64] + os: [netbsd] + requiresBuild: true + optional: true + + /@esbuild/openbsd-x64/0.16.17: + resolution: {integrity: sha512-2yaWJhvxGEz2RiftSk0UObqJa/b+rIAjnODJgv2GbGGpRwAfpgzyrg1WLK8rqA24mfZa9GvpjLcBBg8JHkoodg==} + engines: {node: '>=12'} + cpu: [x64] + os: [openbsd] + requiresBuild: true + optional: true + + /@esbuild/sunos-x64/0.16.17: + resolution: {integrity: sha512-xtVUiev38tN0R3g8VhRfN7Zl42YCJvyBhRKw1RJjwE1d2emWTVToPLNEQj/5Qxc6lVFATDiy6LjVHYhIPrLxzw==} + engines: {node: '>=12'} + cpu: [x64] + os: [sunos] + requiresBuild: true + optional: true + + /@esbuild/win32-arm64/0.16.17: + resolution: {integrity: sha512-ga8+JqBDHY4b6fQAmOgtJJue36scANy4l/rL97W+0wYmijhxKetzZdKOJI7olaBaMhWt8Pac2McJdZLxXWUEQw==} + engines: {node: '>=12'} + cpu: [arm64] + os: [win32] + requiresBuild: true + optional: true + + /@esbuild/win32-ia32/0.16.17: + resolution: {integrity: sha512-WnsKaf46uSSF/sZhwnqE4L/F89AYNMiD4YtEcYekBt9Q7nj0DiId2XH2Ng2PHM54qi5oPrQ8luuzGszqi/veig==} + engines: {node: '>=12'} + cpu: [ia32] + os: [win32] + requiresBuild: true + optional: true + + /@esbuild/win32-x64/0.16.17: + resolution: {integrity: sha512-y+EHuSchhL7FjHgvQL/0fnnFmO4T1bhvWANX6gcnqTjtnKWbTvUMCpGnv2+t+31d7RzyEAYAd4u2fnIhHL6N/Q==} + engines: {node: '>=12'} + cpu: [x64] + os: [win32] + requiresBuild: true + optional: true + + /@eslint/eslintrc/1.4.1: + resolution: {integrity: sha512-XXrH9Uarn0stsyldqDYq8r++mROmWRI1xKMXa640Bb//SY1+ECYX6VzT6Lcx5frD0V30XieqJ0oX9I2Xj5aoMA==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dependencies: ajv: 6.12.6 debug: 4.3.4 espree: 9.4.1 - globals: 13.18.0 - ignore: 5.2.1 + globals: 13.19.0 + ignore: 5.2.4 import-fresh: 3.3.0 js-yaml: 4.1.0 minimatch: 3.1.2 @@ -1020,12 +1178,74 @@ packages: - supports-color dev: true + /@fastify/accept-negotiator/1.1.0: + resolution: {integrity: sha512-OIHZrb2ImZ7XG85HXOONLcJWGosv7sIvM2ifAPQVhg9Lv7qdmMBNVaai4QTdyuaqbKM5eO6sLSQOYI7wEQeCJQ==} + engines: {node: '>=14'} + dev: false + + /@fastify/ajv-compiler/3.5.0: + resolution: {integrity: sha512-ebbEtlI7dxXF5ziNdr05mOY8NnDiPB1XvAlLHctRt/Rc+C3LCOVW5imUVX+mhvUhnNzmPBHewUkOFgGlCxgdAA==} + dependencies: + ajv: 8.11.2 + ajv-formats: 2.1.1 + fast-uri: 2.2.0 + dev: false + + /@fastify/deepmerge/1.3.0: + resolution: {integrity: sha512-J8TOSBq3SoZbDhM9+R/u77hP93gz/rajSA+K2kGyijPpORPWUXHUpTaleoj+92As0S9uPRP7Oi8IqMf0u+ro6A==} + dev: false + + /@fastify/error/3.2.0: + resolution: {integrity: sha512-KAfcLa+CnknwVi5fWogrLXgidLic+GXnLjijXdpl8pvkvbXU5BGa37iZO9FGvsh9ZL4y+oFi5cbHBm5UOG+dmQ==} + dev: false + + /@fastify/fast-json-stringify-compiler/4.2.0: + resolution: {integrity: sha512-ypZynRvXA3dibfPykQN3RB5wBdEUgSGgny8Qc6k163wYPLD4mEGEDkACp+00YmqkGvIm8D/xYoHajwyEdWD/eg==} + dependencies: + fast-json-stringify: 5.5.0 + dev: false + + /@fastify/send/1.0.0: + resolution: {integrity: sha512-jnj8ONIXiOLv4kPn5O7T4oSD5+ymhOg4dKHW3rnYkB/1PJ1942UH1/trvMUIr+fn1dJ20oatpWycZDkPiLcWfg==} + engines: {node: '>= 0.8.0'} + dependencies: + debug: 4.3.4 + depd: 2.0.0 + destroy: 1.2.0 + encodeurl: 1.0.2 + escape-html: 1.0.3 + etag: 1.8.1 + fresh: 0.5.2 + http-errors: 2.0.0 + mime: 1.6.0 + ms: 2.1.3 + on-finished: 2.4.1 + range-parser: 1.2.1 + statuses: 2.0.1 + transitivePeerDependencies: + - supports-color + dev: false + + /@fastify/static/6.6.1: + resolution: {integrity: sha512-sylhlmhclqwkyZy/SD5wzd4yjmMuqW8cRmfnuPXPhftZuEwJ8G2apm0kECQRnHJnk+W3Ksx2fpIHHcthzxNRTA==} + dependencies: + '@fastify/accept-negotiator': 1.1.0 + '@fastify/send': 1.0.0 + content-disposition: 0.5.4 + fastify-plugin: 4.5.0 + glob: 8.0.3 + p-limit: 3.1.0 + readable-stream: 4.3.0 + transitivePeerDependencies: + - supports-color + dev: false + /@gar/promisify/1.1.3: resolution: {integrity: sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw==} dev: true - /@humanwhocodes/config-array/0.11.7: - resolution: {integrity: sha512-kBbPWzN8oVMLb0hOUYXhmxggL/1cJE6ydvjDIGi9EnAGUyA7cLVKQg+d/Dsm+KZwx2czGHrCmMVLiyg8s5JPKw==} + /@humanwhocodes/config-array/0.11.8: + resolution: {integrity: sha512-UybHIJzJnR5Qc/MsD9Kr+RpO2h+/P1GhOwdiLPXK5TWk5sgTdu88bTD9UP+CKbPPh5Rni1u0GjAdYQLemG8g+g==} engines: {node: '>=10.10.0'} dependencies: '@humanwhocodes/object-schema': 1.2.1 @@ -1052,7 +1272,6 @@ packages: /@hutson/parse-repository-url/3.0.2: resolution: {integrity: sha512-H9XAx3hc0BQHY6l+IFSWHDySypcXsvsuLhgYLUGywmJ5pswRVQJUHpOsobnLYp2ZUaUlKiKDrgWWhosOwAEM8Q==} engines: {node: '>=6.9.0'} - dev: true /@iarna/toml/2.2.5: resolution: {integrity: sha512-trnsAYxU3xnS1gPHPyU961coFyLkh4gAD/0zQ5mymY4yOZ+CYvsPqUbOFSw0aDM4y0tV7tiFxL/1XfXPNC6IPg==} @@ -1078,7 +1297,7 @@ packages: dependencies: '@types/istanbul-lib-coverage': 2.0.4 '@types/istanbul-reports': 3.0.1 - '@types/node': 18.11.9 + '@types/node': 18.11.18 '@types/yargs': 16.0.4 chalk: 4.1.2 dev: false @@ -1140,7 +1359,10 @@ packages: cross-spawn: 7.0.3 string-argv: 0.3.1 type-detect: 4.0.8 - dev: true + + /@kurkle/color/0.3.1: + resolution: {integrity: sha512-hW0GwZj06z/ZFUW2Espl7toVDjghJN+EKqyXzPSV8NV89d5BYp5rRMBJoc+aUN0x5OXDMeRQHazejr2Xmqj2tw==} + dev: false /@leancloud/adapter-types/3.0.0: resolution: {integrity: sha512-/1l2PWJ6pXizHphBorMN7B0d2YjmxZJf1s+bitvLALt7wBid5qbGpHqGGKE/yRdNlCKwl9FbXG1x5wUFZfQwHQ==} @@ -1201,8 +1423,8 @@ packages: resolution: {integrity: sha512-Hcv+nVC0kZnQ3tD9GVu5xSMR4VVYOteQIr/hwFPVEvPdlXqgGEuRjiheChHgdM+JyqdgNcmzZOX/tnl0JOiI7A==} dev: false - /@lit/reactive-element/1.4.2: - resolution: {integrity: sha512-VMOxsWh/QDwrxPsgkSQnuZ+8mfNy1OTjzzUdLBvvZtpahwPTHTeVZ51RZRqO4xfKVrR+btIPA8D01IL3xeG66w==} + /@lit/reactive-element/1.5.0: + resolution: {integrity: sha512-fQh9FDK0LPTwDk+0HhSZEtb8K0LTN1wXerwpGrWA+a8tWulYRDLI4vQDWp4GOIsewn0572KYV/oZ3+492D7osA==} dev: false /@mapbox/node-pre-gyp/1.0.10: @@ -1217,7 +1439,7 @@ packages: npmlog: 5.0.1 rimraf: 3.0.2 semver: 7.3.8 - tar: 6.1.12 + tar: 6.1.13 transitivePeerDependencies: - encoding - supports-color @@ -1235,73 +1457,243 @@ packages: npmlog: 5.0.1 rimraf: 3.0.2 semver: 7.3.8 - tar: 6.1.12 + tar: 6.1.13 transitivePeerDependencies: - encoding - supports-color dev: false - /@mdit-vue/plugin-component/0.10.0: - resolution: {integrity: sha512-cfxmPVcp6880TRUgpT3eUjem1gCkg3vsBHOcjOoiD2gAu3hWg48d3woz5+F9WVrAhv8P6wpDYBzFqt29D6D4MQ==} + /@mdit-vue/plugin-component/0.11.2: + resolution: {integrity: sha512-ucFiEULCkLcCG1Tf1MfG5u5PS4BIXWIeKGHRGsXxz1ix2GbZWKFVgWEdNEckBu8s75Fv1WJLIOiAYZyri2f1nw==} dependencies: '@types/markdown-it': 12.2.3 markdown-it: 13.0.1 dev: false - /@mdit-vue/plugin-frontmatter/0.10.0: - resolution: {integrity: sha512-rJa4QM04YKRH9Edpr07BZvOjzOH2BwkPkalIa8YFIsZkCXLmrPpLsQteXbRLTkLGHLXnniW4V4tn5Y7bf7J74g==} + /@mdit-vue/plugin-frontmatter/0.11.1: + resolution: {integrity: sha512-AdZJInjD1pTJXlfhuoBS5ycuIQ3ewBfY0R/XHM3TRDEaDHQJHxouUCpCyijZmpdljTU45lFetIowaKtAi7GBog==} dependencies: - '@mdit-vue/types': 0.10.0 + '@mdit-vue/types': 0.11.0 '@types/markdown-it': 12.2.3 gray-matter: 4.0.3 markdown-it: 13.0.1 dev: false - /@mdit-vue/plugin-headers/0.10.0: - resolution: {integrity: sha512-DPrQyv83jVxX3FwmCnemVeBsSdtH4Hz+geDMwbzATtaqzaYDDpuAxoeiLGpTg41EpLe2SPDk94N3OOh0cdV0Lw==} + /@mdit-vue/plugin-headers/0.11.2: + resolution: {integrity: sha512-hH2zm4m+2tWe7dya/nxbbpB95pa9RjwYxl++kyZuRrqyhNTtsi2HWojX02peQ1nQMKKIWPDHtpeAHGP7dOLKFw==} dependencies: - '@mdit-vue/shared': 0.10.0 - '@mdit-vue/types': 0.10.0 + '@mdit-vue/shared': 0.11.2 + '@mdit-vue/types': 0.11.0 '@types/markdown-it': 12.2.3 markdown-it: 13.0.1 dev: false - /@mdit-vue/plugin-sfc/0.10.0: - resolution: {integrity: sha512-MoKnA8rApIyNeiIXbEUbQ+LAYr51YOWnNzJnum/ttX7kHmfh0+iMDAM1MnvmgVZWqhAzwdkEFOPTb9EVUI1dng==} + /@mdit-vue/plugin-sfc/0.11.1: + resolution: {integrity: sha512-3AjQXqExzT9FWGNOeTBqK1pbt1UA5anrZvjo7OO2PJ3lrfZd0rbjionFkmW/VW1912laHUraIP6n74mUNqPuWw==} dependencies: - '@mdit-vue/types': 0.10.0 + '@mdit-vue/types': 0.11.0 '@types/markdown-it': 12.2.3 markdown-it: 13.0.1 dev: false - /@mdit-vue/plugin-title/0.10.0: - resolution: {integrity: sha512-odJ9vIazAHiomjCEEFwHNuPnmDtx/FGOYrf9xUfi3tjG9r/JZW+G++AABxvevTozwpGlpU+wkpJ7mTr+rNtBrw==} + /@mdit-vue/plugin-title/0.11.2: + resolution: {integrity: sha512-R91WCN16CePWRT2bSXaDJGXvj0MuaCz4m2GbYqUbQxd+dqf18uuGPdbhr1rwhIqCvy7GD/g7hSgOFi3DNDAIzA==} dependencies: - '@mdit-vue/shared': 0.10.0 - '@mdit-vue/types': 0.10.0 + '@mdit-vue/shared': 0.11.2 + '@mdit-vue/types': 0.11.0 '@types/markdown-it': 12.2.3 markdown-it: 13.0.1 dev: false - /@mdit-vue/plugin-toc/0.10.0: - resolution: {integrity: sha512-P9aNy4jtqfjI08wUYGT/HVd5x/IpTjgSnNdJ3lU52qAO5AeFsW3v4gt+NmW0lO8We0S2YDEONRHBuBN6r40y6A==} + /@mdit-vue/plugin-toc/0.11.2: + resolution: {integrity: sha512-0OcGG4TnYIZJ6SLZtk24Nj0oP2vcLn0FyMTao/nB/2Z17/fP3whoo6dVV+0G4Oi8HZ+MMDi661lvS2b4b/glYA==} dependencies: - '@mdit-vue/shared': 0.10.0 - '@mdit-vue/types': 0.10.0 + '@mdit-vue/shared': 0.11.2 + '@mdit-vue/types': 0.11.0 '@types/markdown-it': 12.2.3 markdown-it: 13.0.1 dev: false - /@mdit-vue/shared/0.10.0: - resolution: {integrity: sha512-rUyu0NVNbaEg4DUiQenh/fam1MLdkItdzEVScN7vP0UzDWOwmGaKwkhlMmkSTW80H63ZlKst0fPe9LaGHImSZg==} + /@mdit-vue/shared/0.11.2: + resolution: {integrity: sha512-Z/GS/v9DURZE13Hv41meKzdnprMwenVJoM3t82OE5HIGvtE6QovsZ+mMF/rMvLgaLLMDjT3EwvrrBmemWkHYTQ==} dependencies: - '@mdit-vue/types': 0.10.0 + '@mdit-vue/types': 0.11.0 '@types/markdown-it': 12.2.3 markdown-it: 13.0.1 dev: false - /@mdit-vue/types/0.10.0: - resolution: {integrity: sha512-ROz5zVKt3COpuWUYFnpJh5kIXit9SQeMtimGBlwKJL1xEBNPG3QKD3VZzez5Ng/dBCApianCQhNVZGCza82Myw==} + /@mdit-vue/types/0.11.0: + resolution: {integrity: sha512-ygCGP7vFpqS02hpZwEe1uz8cfImWX06+zRs08J+tCZRKb6k+easIaIHFtY9ZSxt7j9L/gAPLDo/5RmOT6z0DPQ==} + dev: false + + /@mdit/plugin-align/0.2.3: + resolution: {integrity: sha512-TR4bR8qIg7tYSa62XspVzJKfUCCBJBiwTIAfKWtmeQALtDBClCZa26bL2EJnmdY5EdQVzU9sTHXWcR/p3AnVaw==} + engines: {node: '>= 14'} + dependencies: + '@mdit/plugin-container': 0.2.3 + '@types/markdown-it': 12.2.3 + markdown-it: 13.0.1 + dev: false + + /@mdit/plugin-attrs/0.2.3: + resolution: {integrity: sha512-iTqwXOAscDXL20Lt4do3wI6+MQz/iqvSqETpR57M20yl2L/rM02RdVex5BWbxdhqFtDylh+/qtI4X2H6JFv/OQ==} + engines: {node: '>= 14'} + dependencies: + '@types/markdown-it': 12.2.3 + markdown-it: 13.0.1 + dev: false + + /@mdit/plugin-container/0.2.3: + resolution: {integrity: sha512-psgaYyBX6Pq56R5S+NOIWhk8nz73LBaoputKq2NjQadIUgYlN7CmwOJeUjyg4ZK0wwBg1HzFFD5JaJ+C2jVssA==} + engines: {node: '>= 14'} + dependencies: + '@types/markdown-it': 12.2.3 + markdown-it: 13.0.1 + dev: false + + /@mdit/plugin-figure/0.2.3: + resolution: {integrity: sha512-d1KMMkQq9+0SxVMssnm28KDm1JVxozA8lh9fecKRlMnvN7B7NCnLbQZEe/l8Tj2yesOEgzSGL98+gfu/wdJimA==} + engines: {node: '>= 14'} + dependencies: + '@types/markdown-it': 12.2.3 + markdown-it: 13.0.1 + dev: false + + /@mdit/plugin-footnote/0.2.3: + resolution: {integrity: sha512-LiSxbIu5PJTEj+qUcULQViLvyLyDjmnyM/iRdN4Y2biZ2Is/iVsHfhrrOFoqfTIRUqMwZwvbNJdyFPNheTCQfg==} + engines: {node: '>= 14'} + dependencies: + '@types/markdown-it': 12.2.3 + markdown-it: 13.0.1 + dev: false + + /@mdit/plugin-img-lazyload/0.2.3: + resolution: {integrity: sha512-LQJ+mEDiRVyyUYIv4V5NXb3H8Mxp58OLEGJAyM5GV30ZnlsNQV/eyqLvrkaI/zzr0AULaI4RnwtZrUthsxmQZA==} + engines: {node: '>= 14'} + dependencies: + '@types/markdown-it': 12.2.3 + markdown-it: 13.0.1 + dev: false + + /@mdit/plugin-img-mark/0.2.3: + resolution: {integrity: sha512-bQyCeF1DH06MTb+bpjja5As/mkDMShoEWaZ2inc9knphkLA3EHYuHo+DU72RlhXvYv9AaUmlFl870Wu5OeNvZw==} + engines: {node: '>= 14'} + dependencies: + '@types/markdown-it': 12.2.3 + markdown-it: 13.0.1 + dev: false + + /@mdit/plugin-img-size/0.2.3: + resolution: {integrity: sha512-oIBWHMIqlMRp4ns/AQC9DwluV2x/aG+vnu1QhIBaUeuLcwZKp4IdmdDDMTqzASpvMpwqe+wRt4aVnyOmOzRF+w==} + engines: {node: '>= 14'} + dependencies: + '@types/markdown-it': 12.2.3 + markdown-it: 13.0.1 + dev: false + + /@mdit/plugin-include/0.2.3: + resolution: {integrity: sha512-ZCNKi5w+FYkwXXoaFyRqfohBz1uxkwCOWjuF8iHtI8PCXJrquoQz4ynXpLCtMXkg2ohgrcHcQriTOwoGM7xusA==} + dependencies: + '@types/markdown-it': 12.2.3 + markdown-it: 13.0.1 + upath: 2.0.1 + dev: false + + /@mdit/plugin-katex/0.2.3: + resolution: {integrity: sha512-BBeLtivXoGsxHLXqM6h0G661E3amnFBqGX3OuUO3pgVL/IU+yVkn1tFu6D0eFZkyN4juHHrqa1RP2MLQSlziug==} + engines: {node: '>= 14'} + dependencies: + '@mdit/plugin-tex': 0.2.3 + '@types/katex': 0.16.0 + '@types/markdown-it': 12.2.3 + katex: 0.16.4 + markdown-it: 13.0.1 + dev: false + + /@mdit/plugin-mark/0.2.3: + resolution: {integrity: sha512-ppGqi3hCV0yeswAK8K4mmTXrzLU/skBjzDQx8q02Ixt7ppE+T8Sh6A9Pir7pPDqhDTE5MHKWxl//KlUfyPQPMw==} + engines: {node: '>= 14'} + dependencies: + '@types/markdown-it': 12.2.3 + markdown-it: 13.0.1 + dev: false + + /@mdit/plugin-mathjax/0.2.3: + resolution: {integrity: sha512-8P5SqRQuyEQ2JBzIGG+Cl93eZU0rx+i1asELRDnz7t1NCTyIkyLCA57utZx5kC3UcuBo7Nog4N2L04zKup2AxQ==} + engines: {node: '>= 14'} + dependencies: + '@mdit/plugin-tex': 0.2.3 + '@types/markdown-it': 12.2.3 + markdown-it: 13.0.1 + mathjax-full: 3.2.2 + upath: 2.0.1 + dev: false + + /@mdit/plugin-stylize/0.2.3: + resolution: {integrity: sha512-EeRLwmEDwxB7NaF91OAqIJ5uUKHoPyZie4zFLbA3gKwqVXa6OC1XG1k3S8w9GuRnep/K7+e/5gPGFM68tI7v8g==} + engines: {node: '>= 14'} + dependencies: + '@types/markdown-it': 12.2.3 + markdown-it: 13.0.1 + dev: false + + /@mdit/plugin-sub/0.2.3: + resolution: {integrity: sha512-eWCOxASIU/Y1efzhJkb1y0XWa0yGVdtYm4SKfUd73rF4dNEYIYJiNKkQfefrGtMuQdeM7iBqBZfYtcq/nipkzg==} + engines: {node: '>= 14'} + dependencies: + '@types/markdown-it': 12.2.3 + markdown-it: 13.0.1 + dev: false + + /@mdit/plugin-sup/0.2.3: + resolution: {integrity: sha512-gqOOQo6lE2e8SFHpXhKCKiFGoVIO1JUDA97Ol5iIFZtXJ4lbObWKxtYa63KH+kOVwDUUGSojQ6s8+oGMxmtIDA==} + engines: {node: '>= 14'} + dependencies: + '@types/markdown-it': 12.2.3 + markdown-it: 13.0.1 + dev: false + + /@mdit/plugin-tab/0.2.3: + resolution: {integrity: sha512-J0LkcQ2Kb2fm+8Gnd1Ke8rKfJXMQPqwx3ZDa2AtLCcBEf5hWAKbLoc/cWjDVXiHjsdOklIs5AtCyNUkR5YbyOA==} + dependencies: + '@types/markdown-it': 12.2.3 + markdown-it: 13.0.1 + dev: false + + /@mdit/plugin-tasklist/0.2.3: + resolution: {integrity: sha512-szYn7pyaozAPhilrNeC5PNLR+Rm9qlPvRQsxMK88Sa4seSdDhQnPkDb+407QYtYdYpyrn0ZKCvnmuXc9CLlhmQ==} + engines: {node: '>= 14'} + dependencies: + '@types/markdown-it': 12.2.3 + markdown-it: 13.0.1 + dev: false + + /@mdit/plugin-tex/0.2.3: + resolution: {integrity: sha512-sD7dILLqwdPA3B89W5Ezj2vMjrYZKBFICLvPmp49crdAW51tcLUtjKK5nF86fUY7VULlsDG9h5+lQV9wc/HNYA==} + engines: {node: '>= 14'} + dependencies: + '@types/markdown-it': 12.2.3 + markdown-it: 13.0.1 + dev: false + + /@mdit/plugin-uml/0.2.3: + resolution: {integrity: sha512-bLo1R4f6xaXtToLLP4+7+x/i9p815NnuS+l63RkhE2juEagQYKaB2Ytw/91K0/sprWrrvOL3ESRlgFK14MAmHQ==} + engines: {node: '>= 14'} + dependencies: + '@types/markdown-it': 12.2.3 + markdown-it: 13.0.1 + dev: false + + /@mermaid-js/mermaid-mindmap/9.3.0: + resolution: {integrity: sha512-IhtYSVBBRYviH1Ehu8gk69pMDF8DSRqXBRDMWrEfHoaMruHeaP2DXA3PBnuwsMaCdPQhlUUcy/7DBLAEIXvCAw==} + dependencies: + '@braintree/sanitize-url': 6.0.0 + cytoscape: 3.23.0 + cytoscape-cose-bilkent: 4.1.0_cytoscape@3.23.0 + cytoscape-fcose: 2.1.0_cytoscape@3.23.0 + d3: 7.8.0 + khroma: 2.0.0 + non-layered-tidy-tree-layout: 2.0.2 dev: false /@mrmlnc/readdir-enhanced/2.2.1: @@ -1316,28 +1708,29 @@ packages: resolution: {integrity: sha512-4wMPu9iN3/HL97QblBsBay3E1etIciR84izI3U+4iALY+JHCrI+a2jO0qbAZ/nxKoegypYEaiiqWXylm+/zfrw==} dev: false - /@netlify/build/28.4.4_@types+node@18.11.9: - resolution: {integrity: sha512-Jk/O61co7YW1qF12x9sIqTpgDz3ugEwKYQ5fAznGCLxFcsj0cfVPrSWTEnM1U5f3pGziI1/t4td4gXhOCpV+Kw==} + /@netlify/build/29.4.5_@types+node@18.11.18: + resolution: {integrity: sha512-nPMVSBsJ62tO91TvD8UjsKyp8dPLxEH3mAI2I5FHztYBT8d43ISAtAc2FYaSVpm0ZMoUyRDGx+kQmOHfZAWOPQ==} engines: {node: ^14.16.0 || >=16.0.0} hasBin: true dependencies: - '@bugsnag/js': 7.18.0 - '@netlify/cache-utils': 5.0.2_supports-color@9.2.3 - '@netlify/config': 20.0.2 - '@netlify/edge-bundler': 4.4.3 - '@netlify/functions-utils': 5.0.4_supports-color@9.2.3 - '@netlify/git-utils': 5.0.2 - '@netlify/plugins-list': 6.57.0 - '@netlify/run-utils': 5.0.2 - '@netlify/zip-it-and-ship-it': 7.1.2_supports-color@9.2.3 - '@sindresorhus/slugify': 2.1.1 + '@bugsnag/js': 7.17.0 + '@netlify/cache-utils': 5.1.0_supports-color@9.2.2 + '@netlify/config': 20.3.0 + '@netlify/edge-bundler': 8.1.2 + '@netlify/functions-utils': 5.1.4_supports-color@9.2.2 + '@netlify/git-utils': 5.1.0 + '@netlify/plugins-list': 6.61.0 + '@netlify/run-utils': 5.1.0 + '@netlify/zip-it-and-ship-it': 8.4.0_supports-color@9.2.2 + '@sindresorhus/slugify': 2.1.0 ansi-escapes: 5.0.0 - chalk: 5.1.2 + chalk: 5.2.0 clean-stack: 4.2.0 execa: 6.1.0 figures: 4.0.1 filter-obj: 3.0.0 got: 10.7.0 + hot-shots: 9.3.0 indent-string: 5.0.0 is-plain-obj: 4.1.0 js-yaml: 4.1.0 @@ -1363,14 +1756,13 @@ packages: rfdc: 1.3.0 safe-json-stringify: 1.2.0 semver: 7.3.8 - statsd-client: 0.4.7 string-width: 5.1.2 strip-ansi: 7.0.1 - supports-color: 9.2.3 + supports-color: 9.2.2 terminal-link: 3.0.0 tmp-promise: 3.0.3 - ts-node: 10.9.1_wup25etrarvlqkprac7h35hj7u - typescript: 4.9.3 + ts-node: 10.9.1_awa2wsr5thmg3i7jqycphctjfq + typescript: 4.9.4 update-notifier: 5.1.0 uuid: 8.3.2 yargs: 17.6.2 @@ -1381,14 +1773,14 @@ packages: - encoding dev: false - /@netlify/cache-utils/5.0.2_supports-color@9.2.3: - resolution: {integrity: sha512-LuX+rmVah13OeQtZEd5TlDgYnnm0nL/dqjn1Q1CatryQumPM3L6QtDCYASbUXPzqZviWswy8nYEgQ3yHg0X2kw==} + /@netlify/cache-utils/5.1.0_supports-color@9.2.2: + resolution: {integrity: sha512-KmiklYOkj8j9riQU8ww/KlZDZmGUc0Nqfo7IVuPcjagp/Xb0/HiwuAS+z4buHXDRF2rQ/lMln5Wp+FGE7wbc+g==} engines: {node: ^14.16.0 || >=16.0.0} dependencies: cpy: 8.1.2_supports-color@9.2.3 del: 6.1.1 get-stream: 6.0.1 - globby: 13.1.2 + globby: 13.1.3 junk: 4.0.0 locate-path: 7.1.1 move-file: 3.0.0 @@ -1398,13 +1790,13 @@ packages: - supports-color dev: false - /@netlify/config/20.0.2: - resolution: {integrity: sha512-ZHEeuAC1Re5PyLd7BNmhAYtGmLhgeZKfSas6Q66X62n5Xem9omo9k74wP5hSIZ3Fs2fooU6lxLzvK58DdMUCsQ==} + /@netlify/config/20.3.0: + resolution: {integrity: sha512-XZJuvxcvYEq6ozZOpNs95HQO9cJ9/FBeWHyw+Fc8+EF5iPc4krjhAm7AqxmxKvqjVe02fxWTz0Vc8gjbbZIMeg==} engines: {node: ^14.16.0 || >=16.0.0} hasBin: true dependencies: - chalk: 5.1.2 - cron-parser: 4.7.0 + chalk: 5.2.0 + cron-parser: 4.6.0 deepmerge: 4.2.2 dot-prop: 7.2.0 execa: 6.1.0 @@ -1416,9 +1808,9 @@ packages: is-plain-obj: 4.1.0 js-yaml: 4.1.0 map-obj: 5.0.2 - netlify: 13.0.2 - netlify-headers-parser: 7.0.3 - netlify-redirect-parser: 14.0.2 + netlify: 13.1.0 + netlify-headers-parser: 7.1.0 + netlify-redirect-parser: 14.1.0 omit.js: 2.0.2 p-locate: 6.0.0 path-exists: 5.0.0 @@ -1429,8 +1821,8 @@ packages: yargs: 17.6.2 dev: false - /@netlify/edge-bundler/4.4.3: - resolution: {integrity: sha512-wELFNmsnst3ujgQ2KNv1ex07G4GLS6JwJcZfXuwC5aV3FOZAQApAIH/A3MzHNxIfoW6EmLD/PE6sVMdSB1U6uQ==} + /@netlify/edge-bundler/8.1.2: + resolution: {integrity: sha512-ODaWypy/vIEm8bDAUIT9P4x4EeK6M+P0/M+D4aHuxenrCBk1v37fIiz251jVnte8z2Obqrb+PG4et98oX+gOPw==} engines: {node: ^14.16.0 || >=16.0.0} dependencies: '@import-maps/resolve': 1.0.1 @@ -1444,7 +1836,8 @@ packages: find-up: 6.3.0 get-port: 6.1.2 glob-to-regexp: 0.4.1 - node-fetch: 3.3.0 + jsonc-parser: 3.2.0 + node-fetch: 3.2.10 node-stream-zip: 1.15.0 p-retry: 5.1.2 p-wait-for: 4.1.0 @@ -1662,8 +2055,8 @@ packages: '@netlify/esbuild-windows-arm64': 0.14.39 dev: false - /@netlify/framework-info/9.5.2: - resolution: {integrity: sha512-4gEP+02y6ueJEm/oLPfoFJGg/9TOQi/NCKcxZm1dwkLTVgCYmT47niXG7hVDWz3F3daqVm6lcCUSdrvkhDYgcQ==} + /@netlify/framework-info/9.5.3: + resolution: {integrity: sha512-b4UMooyad0FBIhDqehlSRQ5/5y6SmEAmtdtpOi/ien1TaN+c80rknkrCHw2mlXaw+quRWweGfMNw8oALxjxmLQ==} engines: {node: ^14.14.0 || >=16.0.0} dependencies: ajv: 8.11.2 @@ -1680,33 +2073,33 @@ packages: url: 0.11.0 dev: false - /@netlify/functions-utils/5.0.4_supports-color@9.2.3: - resolution: {integrity: sha512-FCxQIWGvB/PBLYfWDPUUoHEwbYpXcR7oBY0y7uXkbwCkMeb0iFq0ADFA140NwYLsFAZSa7PRL2U7HA6GPHsOGw==} + /@netlify/functions-utils/5.1.4_supports-color@9.2.2: + resolution: {integrity: sha512-iRg0wXWB/SUhirW20FZ0COP6WkoXfCcPKZb2AUKzkeduUE4WF1zUeX7gw/SYXFU9OkMHehD9NN5y7csp2oNUNg==} engines: {node: ^14.16.0 || >=16.0.0} dependencies: - '@netlify/zip-it-and-ship-it': 7.1.2_supports-color@9.2.3 - cpy: 8.1.2_supports-color@9.2.3 + '@netlify/zip-it-and-ship-it': 8.4.0_supports-color@9.2.2 + cpy: 8.1.2_supports-color@9.2.2 path-exists: 5.0.0 transitivePeerDependencies: - encoding - supports-color dev: false - /@netlify/functions/1.3.0: - resolution: {integrity: sha512-hN/Fgpz8XIOBfsBPLYUMxVKBlCopgeqGB0popayicnmkFLnvKByTTMYgF01wcF9DBtBQdV0H2h1kPFpMl34I8w==} + /@netlify/functions/1.4.0: + resolution: {integrity: sha512-gy7ULTIRroc2/jyFVGx1djCmmBMVisIwrvkqggq5B6iDcInRSy2Tpkm+V5C63hKJVkNRskKWtLQKm9ecCaQTjA==} engines: {node: '>=8.3.0'} dependencies: is-promise: 4.0.0 dev: false - /@netlify/git-utils/5.0.2: - resolution: {integrity: sha512-ri3KweO9gNXFAYJLiZNOQsffdNWFA1JjwSf2QSMScQMvAtWRNfZ6Xps890VRsjnUoSMQysSopB+bMVYOxD/pAw==} + /@netlify/git-utils/5.1.0: + resolution: {integrity: sha512-/OGTTH8wtnTit7ZTL4tUFbys3+zL9I7h82K0nIoQDeGNf4LMbjqgC5TFEsMbK3K/WE/yK5c4V8mQS8BHARHQOQ==} engines: {node: ^14.16.0 || >=16.0.0} dependencies: execa: 6.1.0 map-obj: 5.0.2 micromatch: 4.0.5 - moize: 6.1.3 + moize: 6.1.4 path-exists: 5.0.0 dev: false @@ -1839,21 +2232,21 @@ packages: resolution: {integrity: sha512-yWTh9DPO4Gku0JB6DZarUq8/p2jamvVjbWyeYkHcBX6LW89F2blIx8aA9eSJVSScMgrH/FSQ1I8y1JL/SC73bg==} dev: false - /@netlify/plugins-list/6.57.0: - resolution: {integrity: sha512-PEHF5QRXiGbL5dNT61iacbzmmcEdW8miVFYm9/P0yvXaRma4d20WLq1eydpXhQhk9tXljQpBEDjB0eDmJieOqg==} + /@netlify/plugins-list/6.61.0: + resolution: {integrity: sha512-76pkuMxDdRQcAKu5WXBl24fFCzjV8rQyBS2xh/xphAntPn57uLBtQYasncTzsgGjckWwDPjwoIkmxOzi3OeqFQ==} engines: {node: ^14.14.0 || >=16.0.0} dev: false - /@netlify/run-utils/5.0.2: - resolution: {integrity: sha512-otfFwuZEd6pm/i3wv5UMIB6t6UNY7NEWkgF3fgO6nx9uWLq9oRqzVYrff5pYSNm8YgdEBDxx8eHvv5mGMyXz2A==} + /@netlify/run-utils/5.1.0: + resolution: {integrity: sha512-fHBXEW35QmKB2MiSRXVBZ4t29t+QhvTClUfXsxLHLEPkEi9tE9N+d55ycZha/b5U8Tc1ZeyzzDFjjnKk+XHWbA==} engines: {node: ^14.16.0 || >=16.0.0} dependencies: execa: 6.1.0 dev: false - /@netlify/zip-it-and-ship-it/7.1.2_supports-color@9.2.3: - resolution: {integrity: sha512-WGCt5KDk5Zr+A0fhPGEgAAW2aNiGyLcZohBq4nu/4BoFtHkk+8vCZOH1lMytZiIFu0eAq00j2q4kdzyLFV0Wuw==} - engines: {node: ^12.20.0 || ^14.14.0 || >=16.0.0} + /@netlify/zip-it-and-ship-it/8.2.0: + resolution: {integrity: sha512-gaq+SnQB/VNCLPT1HfYbW1XmCRPG21d3ecOTyOf8ikDsGoypI4VaGVzjINVo8mu0uQWtRY+wWHcYeiQdN54GuQ==} + engines: {node: ^14.16.0 || >=16.0.0} hasBin: true dependencies: '@babel/parser': 7.16.8 @@ -1907,19 +2300,19 @@ packages: cp-file: 10.0.0 del: 7.0.0 end-of-stream: 1.4.4 - es-module-lexer: 1.1.0 - execa: 5.1.1 + es-module-lexer: 1.0.1 + execa: 6.1.0 filter-obj: 5.1.0 find-up: 6.3.0 glob: 8.0.3 is-builtin-module: 3.2.0 - is-path-inside: 3.0.3 - junk: 3.1.0 + is-path-inside: 4.0.0 + junk: 4.0.0 locate-path: 7.1.1 merge-options: 3.0.4 - minimatch: 5.1.0 + minimatch: 5.1.2 normalize-path: 3.0.0 - p-map: 4.0.0 + p-map: 5.5.0 path-exists: 5.0.0 precinct: 9.0.1 require-package-name: 2.0.1 @@ -1934,6 +2327,47 @@ packages: - supports-color dev: false + /@netlify/zip-it-and-ship-it/8.4.0_supports-color@9.2.2: + resolution: {integrity: sha512-5ctiK9p7+VgE89ZeYD9cMCU53IQNv+Bj0K9O9gkQBD40HIuJgFIU0Pb8LOh+eGbefICUC/wD73l7WgjN1Eu2RQ==} + engines: {node: ^14.16.0 || >=16.0.0} + hasBin: true + dependencies: + '@babel/parser': 7.16.8 + '@netlify/binary-info': 1.0.0 + '@netlify/esbuild': 0.14.39 + '@vercel/nft': 0.22.1_supports-color@9.2.2 + archiver: 5.3.1 + common-path-prefix: 3.0.0 + cp-file: 10.0.0 + del: 7.0.0 + end-of-stream: 1.4.4 + es-module-lexer: 1.0.1 + execa: 6.1.0 + filter-obj: 5.1.0 + find-up: 6.3.0 + glob: 8.0.3 + is-builtin-module: 3.2.0 + is-path-inside: 4.0.0 + junk: 4.0.0 + locate-path: 7.1.1 + merge-options: 3.0.4 + minimatch: 5.1.2 + normalize-path: 3.0.0 + p-map: 5.5.0 + path-exists: 5.0.0 + precinct: 9.0.1_supports-color@9.2.2 + require-package-name: 2.0.1 + resolve: 2.0.0-next.4 + semver: 7.3.8 + tmp-promise: 3.0.3 + toml: 3.0.0 + unixify: 1.0.0 + yargs: 17.6.2 + transitivePeerDependencies: + - encoding + - supports-color + dev: false + /@nodelib/fs.scandir/2.1.5: resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} engines: {node: '>= 8'} @@ -1955,7 +2389,20 @@ packages: engines: {node: '>= 8'} dependencies: '@nodelib/fs.scandir': 2.1.5 - fastq: 1.13.0 + fastq: 1.14.0 + + /@npmcli/config/6.1.0: + resolution: {integrity: sha512-fPVlvy6MmSN0zgJU1TOD0fimnKVmcFpK3WuPyIQfNtCE+HMkFDN1mIKBKhUNow5QYHmCzMvGbu7pAgwdlSoaQA==} + engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + dependencies: + '@npmcli/map-workspaces': 3.0.1 + ini: 3.0.1 + nopt: 7.0.0 + proc-log: 3.0.0 + read-package-json-fast: 3.0.2 + semver: 7.3.8 + walk-up-path: 1.0.0 + dev: true /@npmcli/config/6.1.0: resolution: {integrity: sha512-fPVlvy6MmSN0zgJU1TOD0fimnKVmcFpK3WuPyIQfNtCE+HMkFDN1mIKBKhUNow5QYHmCzMvGbu7pAgwdlSoaQA==} @@ -2004,14 +2451,14 @@ packages: npm-normalize-package-bin: 1.0.1 dev: true - /@npmcli/map-workspaces/3.0.0: - resolution: {integrity: sha512-aaEDwQ+fUH80iNYSDAcKv9lxIFWsgGkLjIPZENyep75hKeAk2CfSbCAZ6IHDDrVlNybvvNmlFjPap6GdTz9cCw==} + /@npmcli/map-workspaces/3.0.1: + resolution: {integrity: sha512-QXwE2p5zRTP6X8Irgf/swYwwdQEalSA1GBm0IGE/86R5EJbUGgKMOP0kOjaJWJxaWPkSqyhM8N50SPxFHTfkNg==} engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} dependencies: - '@npmcli/name-from-folder': 1.0.1 + '@npmcli/name-from-folder': 2.0.0 glob: 8.0.3 - minimatch: 5.1.0 - read-package-json-fast: 3.0.1 + minimatch: 5.1.2 + read-package-json-fast: 3.0.2 dev: true /@npmcli/move-file/2.0.1: @@ -2023,8 +2470,9 @@ packages: rimraf: 3.0.2 dev: true - /@npmcli/name-from-folder/1.0.1: - resolution: {integrity: sha512-qq3oEfcLFwNfEYOQ8HLimRGKlD8WSeGEdtUa7hmzpR8Sa7haL1KVQrvgO6wqMjhWFFVjgtrh1gIxDz+P8sjUaA==} + /@npmcli/name-from-folder/2.0.0: + resolution: {integrity: sha512-pwK+BfEBZJbKdNYpHHRTNBwBoqrN/iIMO0AiGvYsp3Hoaq0WbgGSWQR6SCldZovoDpY3yje5lkFUe6gsDgJ2vg==} + engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} dev: true /@npmcli/node-gyp/2.0.0: @@ -2045,7 +2493,7 @@ packages: dependencies: '@npmcli/node-gyp': 2.0.0 '@npmcli/promise-spawn': 3.0.0 - node-gyp: 9.3.0 + node-gyp: 9.3.1 read-package-json-fast: 2.0.3 which: 2.0.2 transitivePeerDependencies: @@ -2222,8 +2670,8 @@ packages: engines: {node: '>=14.16'} dev: false - /@sindresorhus/slugify/2.1.1: - resolution: {integrity: sha512-XokPHZ+q6FtQGEi1hnfvARVJJVPEhwHQTPHPPuNHaN6zcHjzYNynhhHMopa1wNPqLAFOwpsbintunEqWecXJMg==} + /@sindresorhus/slugify/2.1.0: + resolution: {integrity: sha512-gU3Gdm/V167BmUwIn8APHZ3SeeRVRUSOdXxnt7Q/JkUHLXaaTA/prYmoRumwsSitJZWUDYMzDWdWgrOdvE8IRQ==} engines: {node: '>=12'} dependencies: '@sindresorhus/transliterate': 1.5.0 @@ -2280,13 +2728,13 @@ packages: resolution: {integrity: sha512-ALYone6pm6QmwZoAgeyNksccT9Q4AWZQ6PvfwR37GT6r6FWUPguq6sUmNGSMV2Wr761oQoBxwGGa6DR5o1DC9g==} dependencies: '@types/connect': 3.4.35 - '@types/node': 18.11.9 + '@types/node': 18.11.18 dev: false /@types/bonjour/3.5.10: resolution: {integrity: sha512-p7ienRMiS41Nu2/igbJxxLDWrSZ0WxM8UQgCeO9KhoVF7cOVFkrKsiDr1EsJIla8vV3oEEjGcz11jc5yimhzZw==} dependencies: - '@types/node': 18.11.9 + '@types/node': 18.11.18 dev: false /@types/cacheable-request/6.0.3: @@ -2294,7 +2742,7 @@ packages: dependencies: '@types/http-cache-semantics': 4.0.1 '@types/keyv': 3.1.4 - '@types/node': 18.11.9 + '@types/node': 18.11.18 '@types/responselike': 1.0.0 dev: false @@ -2302,13 +2750,13 @@ packages: resolution: {integrity: sha512-h8QJa8xSb1WD4fpKBDcATDNGXghFj6/3GRWG6dhmRcu0RX1Ubasur2Uvx5aeEwlf0MwblEC2bMzzMQntxnw/Cw==} dependencies: '@types/express-serve-static-core': 4.17.31 - '@types/node': 18.11.9 + '@types/node': 18.11.18 dev: false /@types/connect/3.4.35: resolution: {integrity: sha512-cdeYyv4KWoEgpBISTxWvqYsVy444DOqehiF3fM3ne10AmJ62RSyNkUnxMJXHQWRQQX2eR94m5y1IZyDwBjV9FQ==} dependencies: - '@types/node': 18.11.9 + '@types/node': 18.11.18 dev: false /@types/cookiejar/2.1.2: @@ -2324,7 +2772,7 @@ packages: /@types/decompress/4.2.4: resolution: {integrity: sha512-/C8kTMRTNiNuWGl5nEyKbPiMv6HA+0RbEXzFhFBEzASM6+oa4tJro9b8nj7eRlOFfuLdzUU+DS/GPDlvvzMOhA==} dependencies: - '@types/node': 18.11.9 + '@types/node': 18.11.18 dev: false /@types/download/8.0.1: @@ -2332,7 +2780,7 @@ packages: dependencies: '@types/decompress': 4.2.4 '@types/got': 8.3.6 - '@types/node': 18.11.9 + '@types/node': 18.11.18 dev: false /@types/eslint-scope/3.7.4: @@ -2356,13 +2804,13 @@ packages: /@types/express-serve-static-core/4.17.31: resolution: {integrity: sha512-DxMhY+NAsTwMMFHBTtJFNp5qiHKJ7TeqOo23zVEM9alT1Ml27Q3xcTH0xwxn7Q0BbMcVEJOs/7aQtUWupUQN3Q==} dependencies: - '@types/node': 18.11.9 + '@types/node': 18.11.18 '@types/qs': 6.9.7 '@types/range-parser': 1.2.4 dev: false - /@types/express/4.17.14: - resolution: {integrity: sha512-TEbt+vaPFQ+xpxFLFssxUDXj5cWCxZJjIcB7Yg0k0GMHGtgtQgpvx/MUQUeAkNbA9AAGrwkAsoeItdTgS7FMyg==} + /@types/express/4.17.15: + resolution: {integrity: sha512-Yv0k4bXGOH+8a+7bELd2PqHQsuiANB+A8a4gnQrkRWzrkKlb6KHaVvyXhqs04sVW/OWlbPyYxRgYlIXLfrufMQ==} dependencies: '@types/body-parser': 1.19.2 '@types/express-serve-static-core': 4.17.31 @@ -2373,20 +2821,20 @@ packages: /@types/fs-extra/9.0.13: resolution: {integrity: sha512-nEnwB++1u5lVDM2UI4c1+5R+FYaKfaAzS4OococimjVm3nQw3TuzH5UNsocrcTBbhnerblyHj4A49qXbIiZdpA==} dependencies: - '@types/node': 18.11.9 + '@types/node': 18.11.18 dev: false /@types/glob/7.2.0: resolution: {integrity: sha512-ZUxbzKl0IfJILTS6t7ip5fQQM/J3TJYubDm3nMbgubNNYS62eXeUpoLUC8/7fJNiFYHTrGPQn7hspDUzIHX3UA==} dependencies: - '@types/minimatch': 5.1.2 - '@types/node': 18.11.9 + '@types/minimatch': 3.0.5 + '@types/node': 18.11.18 dev: false /@types/got/8.3.6: resolution: {integrity: sha512-nvLlj+831dhdm4LR2Ly+HTpdLyBaMynoOr6wpIxS19d/bPeHQxFU5XQ6Gp6ohBpxvCWZM1uHQIC2+ySRH1rGrQ==} dependencies: - '@types/node': 18.11.9 + '@types/node': 18.11.18 dev: false /@types/hash-sum/1.0.0: @@ -2404,7 +2852,7 @@ packages: /@types/http-proxy/1.17.9: resolution: {integrity: sha512-QsbSjA/fSk7xB+UXlCT3wHBy5ai9wOcNDWwZAtud+jXhwOM3l+EYZh8Lng4+/6n8uar0J7xILzqftJdJ/Wdfkw==} dependencies: - '@types/node': 18.11.9 + '@types/node': 18.11.18 dev: false /@types/istanbul-lib-coverage/2.0.4: @@ -2437,14 +2885,14 @@ packages: resolution: {integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==} dev: true - /@types/katex/0.14.0: - resolution: {integrity: sha512-+2FW2CcT0K3P+JMR8YG846bmDwplKUTsWgT2ENwdQ1UdVfRk3GQrh6Mi4sTopy30gI8Uau5CEqHTDZ6YvWIUPA==} + /@types/katex/0.16.0: + resolution: {integrity: sha512-hz+S3nV6Mym5xPbT9fnO8dDhBFQguMYpY0Ipxv06JMi1ORgnEM4M1ymWDUhUNer3ElLmT583opRo4RzxKmh9jw==} dev: false /@types/keyv/3.1.4: resolution: {integrity: sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg==} dependencies: - '@types/node': 18.11.9 + '@types/node': 18.11.18 dev: false /@types/linkify-it/3.0.2: @@ -2478,15 +2926,8 @@ packages: resolution: {integrity: sha512-eC4U9MlIcu2q0KQmXszyn5Akca/0jrQmwDRgpAMJai7qBWq4amIQhZyNau4VYGtCeALvW1/NtjzJJ567aZxfKA==} dev: false - /@types/mermaid/9.2.0: - resolution: {integrity: sha512-AlvLWYer6u4BkO4QzMkHo0t9RkvVIgqggVZmO+5snUiuX2caTKqtdqygX6GeE1VQa/TnXw9WoH0spcmHtG0inQ==} - deprecated: This is a stub types definition. mermaid provides its own type definitions, so you do not need this installed. - dependencies: - mermaid: 9.2.2 - dev: false - - /@types/mime/3.0.1: - resolution: {integrity: sha512-Y4XFY5VJAuw0FgAqPNd6NNoV44jbq9Bz2L7Rh/J6jLTiHBSBJa9fxqQIvkIld4GsoDOcCbvzOUAbLPsSKKg+uA==} + /@types/mime/3.0.0: + resolution: {integrity: sha512-fccbsHKqFDXClBZTDLA43zl0+TbxyIwyzIzwwhvoJvhNjOErCdeX2xJbURimv2EbSVUGav001PaCJg4mZxMl4w==} dev: false /@types/minimatch/5.1.2: @@ -2495,7 +2936,6 @@ packages: /@types/minimist/1.2.2: resolution: {integrity: sha512-jhuKLIRrhvCPLqwPcx6INqmKeiA5EWrsCOPhrlFSrbrmU4ZMPjj5Ul/oLCMDO98XRUIwVm78xICz4EPCektzeQ==} - dev: true /@types/ms/0.7.31: resolution: {integrity: sha512-iiUgKzV9AuaEkZqkOLDIvlQiL6ltuZd9tGcW3gwpnX8JbuiuhFlEGmmFXEXkN50Cvq7Os88IY2v0dkDqXYWVgA==} @@ -2504,30 +2944,23 @@ packages: /@types/node-fetch/2.6.2: resolution: {integrity: sha512-DHqhlq5jeESLy19TYhLakJ07kNumXWjcDdxXsLUMJZ6ue8VZJj4kLPQVE/2mdHh3xZziNF1xppu5lwmS53HR+A==} dependencies: - '@types/node': 18.11.9 + '@types/node': 18.11.18 form-data: 3.0.1 dev: false - /@types/node/14.18.33: - resolution: {integrity: sha512-qelS/Ra6sacc4loe/3MSjXNL1dNQ/GjxNHVzuChwMfmk7HuycRLVQN2qNY3XahK+fZc5E2szqQSKUyAF0E+2bg==} - dev: true - /@types/node/17.0.45: resolution: {integrity: sha512-w+tIMs3rq2afQdsPJlODhoUEKzFP1ayaoyl1CcnwtIlsVe7K7bA1NGm4s3PraqTLlXnbIN84zuBlxBWo1u9BLw==} dev: false - /@types/node/18.11.9: - resolution: {integrity: sha512-CRpX21/kGdzjOpFsZSkcrXMGIBWMGNIHXXBVFSH+ggkftxg+XYP20TESbh+zFvFj3EQOl5byk0HTRn1IL6hbqg==} - - /@types/node/18.8.0: - resolution: {integrity: sha512-u+h43R6U8xXDt2vzUaVP3VwjjLyOJk6uEciZS8OSyziUQGOwmk+l+4drxcsDboHXwyTaqS1INebghmWMRxq3LA==} - dev: true + /@types/node/18.11.18: + resolution: {integrity: sha512-DHQpWGjyQKSHj3ebjFI/wRKcqQcdR+MoFBygntYOZytCqNfkd2ZC4ARDJ2DQqhjH5p85Nnd3jhUJIXrszFX/JA==} /@types/normalize-package-data/2.4.1: resolution: {integrity: sha512-Gj7cI7z+98M282Tqmp2K5EIsoouUEzbBJhQQzDE3jSIRk6r9gsz0oUokqIUR4u1R3dMHo0pDHM7sNOHyhulypw==} /@types/parse-json/4.0.0: resolution: {integrity: sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==} + dev: false /@types/qs/6.9.7: resolution: {integrity: sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw==} @@ -2537,10 +2970,14 @@ packages: resolution: {integrity: sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw==} dev: false + /@types/raphael/2.3.3: + resolution: {integrity: sha512-Rhvq0q6wzyvipejki/9w87/pgapyE+s3gO66tdl1oD3qDrow+ek+4vVYAbRkeL58HCCK9EOZKwyjqYJ/TFkmtQ==} + dev: false + /@types/responselike/1.0.0: resolution: {integrity: sha512-85Y2BjiufFzaMIlvJDvTTB8Fxl2xfLo4HgmHzVBz08w4wDePCTjYw66PdrolO0kzli3yam/YCgRufyo1DdQVTA==} dependencies: - '@types/node': 18.11.9 + '@types/node': 18.11.18 dev: false /@types/retry/0.12.0: @@ -2554,7 +2991,7 @@ packages: /@types/sax/1.2.4: resolution: {integrity: sha512-pSAff4IAxJjfAXUG6tFkO7dsSbTmf8CtUpfhhZ5VhkRpC4628tJhh3+V6H1E+/Gs9piSzYKT5yzHO5M4GG9jkw==} dependencies: - '@types/node': 17.0.45 + '@types/node': 18.11.18 dev: false /@types/semver/7.3.13: @@ -2563,27 +3000,27 @@ packages: /@types/serve-index/1.9.1: resolution: {integrity: sha512-d/Hs3nWDxNL2xAczmOVZNj92YZCS6RGxfBPjKzuu/XirCgXdpKEb88dYNbrYGint6IVWLNP+yonwVAuRC0T2Dg==} dependencies: - '@types/express': 4.17.14 + '@types/express': 4.17.15 dev: false /@types/serve-static/1.15.0: resolution: {integrity: sha512-z5xyF6uh8CbjAu9760KDKsH2FcDxZ2tFCsA4HIMWE6IkiYMXfVoa+4f9KX+FN0ZLsaMw1WNG2ETLA6N+/YA+cg==} dependencies: - '@types/mime': 3.0.1 - '@types/node': 18.11.9 + '@types/mime': 3.0.0 + '@types/node': 18.11.18 dev: false /@types/sockjs/0.3.33: resolution: {integrity: sha512-f0KEEe05NvUnat+boPTZ0dgaLZ4SfSouXUgv5noUiefG2ajgKjmETo9ZJyuqsl7dfl2aHlLJUiki6B4ZYldiiw==} dependencies: - '@types/node': 18.11.9 + '@types/node': 18.11.18 dev: false /@types/superagent/4.1.16: resolution: {integrity: sha512-tLfnlJf6A5mB6ddqF159GqcDizfzbMUB1/DeT59/wBNqzRTNNKsaw79A/1TZ84X+f/EwWH8FeuSkjlCLyqS/zQ==} dependencies: '@types/cookiejar': 2.1.2 - '@types/node': 18.11.9 + '@types/node': 18.11.18 dev: false /@types/trusted-types/2.0.2: @@ -2600,13 +3037,13 @@ packages: /@types/ws/7.4.7: resolution: {integrity: sha512-JQbbmxZTZehdc2iszGKs5oC3NFnjeay7mtAWrdt7qNtAVK0g19muApzAy4bm9byz79xa2ZnO/BOBC2R8RC5Lww==} dependencies: - '@types/node': 18.11.9 + '@types/node': 18.11.18 dev: false /@types/ws/8.5.3: resolution: {integrity: sha512-6YOoWjruKj1uLf3INHH7D3qTXwFfEsg1kf3c0uDdSBJwfa/llkwIjrAGV7j7mVgGNbzTQ3HiHKKDXl6bJPD97w==} dependencies: - '@types/node': 18.11.9 + '@types/node': 18.11.18 dev: false /@types/yargs-parser/21.0.0: @@ -2625,8 +3062,16 @@ packages: '@types/yargs-parser': 21.0.0 dev: false - /@typescript-eslint/eslint-plugin/5.45.0_czs5uoqkd3podpy6vgtsxfc7au: - resolution: {integrity: sha512-CXXHNlf0oL+Yg021cxgOdMHNTXD17rHkq7iW6RFHoybdFgQBjU3yIXhhcPpGwr1CjZlo6ET8C6tzX5juQoXeGA==} + /@types/yauzl/2.10.0: + resolution: {integrity: sha512-Cn6WYCm0tXv8p6k+A8PvbDG763EDpBoTzHdA+Q/MF6H3sapGjCm9NzoaJncJS9tUKSuCoDs9XHxYYsQDgxR6kw==} + requiresBuild: true + dependencies: + '@types/node': 18.11.18 + dev: false + optional: true + + /@typescript-eslint/eslint-plugin/5.47.1_lxxchmivucqcmhzvhnmnywabcq: + resolution: {integrity: sha512-r4RZ2Jl9kcQN7K/dcOT+J7NAimbiis4sSM9spvWimsBvDegMhKLA5vri2jG19PmIPbDjPeWzfUPQ2hjEzA4Nmg==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: '@typescript-eslint/parser': ^5.0.0 @@ -2636,24 +3081,24 @@ packages: typescript: optional: true dependencies: - '@typescript-eslint/parser': 5.45.0_hsf322ms6xhhd4b5ne6lb74y4a - '@typescript-eslint/scope-manager': 5.45.0 - '@typescript-eslint/type-utils': 5.45.0_hsf322ms6xhhd4b5ne6lb74y4a - '@typescript-eslint/utils': 5.45.0_hsf322ms6xhhd4b5ne6lb74y4a + '@typescript-eslint/parser': 5.47.1_7uibuqfxkfaozanbtbziikiqje + '@typescript-eslint/scope-manager': 5.47.1 + '@typescript-eslint/type-utils': 5.47.1_7uibuqfxkfaozanbtbziikiqje + '@typescript-eslint/utils': 5.47.1_7uibuqfxkfaozanbtbziikiqje debug: 4.3.4 - eslint: 8.28.0 - ignore: 5.2.1 + eslint: 8.32.0 + ignore: 5.2.4 natural-compare-lite: 1.4.0 regexpp: 3.2.0 semver: 7.3.8 - tsutils: 3.21.0_typescript@4.9.3 - typescript: 4.9.3 + tsutils: 3.21.0_typescript@4.9.4 + typescript: 4.9.4 transitivePeerDependencies: - supports-color dev: true - /@typescript-eslint/parser/5.45.0_hsf322ms6xhhd4b5ne6lb74y4a: - resolution: {integrity: sha512-brvs/WSM4fKUmF5Ot/gEve6qYiCMjm6w4HkHPfS6ZNmxTS0m0iNN4yOChImaCkqc1hRwFGqUyanMXuGal6oyyQ==} + /@typescript-eslint/parser/5.47.1_7uibuqfxkfaozanbtbziikiqje: + resolution: {integrity: sha512-9Vb+KIv29r6GPu4EboWOnQM7T+UjpjXvjCPhNORlgm40a9Ia9bvaPJswvtae1gip2QEeVeGh6YquqAzEgoRAlw==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 @@ -2662,26 +3107,26 @@ packages: typescript: optional: true dependencies: - '@typescript-eslint/scope-manager': 5.45.0 - '@typescript-eslint/types': 5.45.0 - '@typescript-eslint/typescript-estree': 5.45.0_typescript@4.9.3 + '@typescript-eslint/scope-manager': 5.47.1 + '@typescript-eslint/types': 5.47.1 + '@typescript-eslint/typescript-estree': 5.47.1_typescript@4.9.4 debug: 4.3.4 - eslint: 8.28.0 - typescript: 4.9.3 + eslint: 8.32.0 + typescript: 4.9.4 transitivePeerDependencies: - supports-color dev: true - /@typescript-eslint/scope-manager/5.45.0: - resolution: {integrity: sha512-noDMjr87Arp/PuVrtvN3dXiJstQR1+XlQ4R1EvzG+NMgXi8CuMCXpb8JqNtFHKceVSQ985BZhfRdowJzbv4yKw==} + /@typescript-eslint/scope-manager/5.47.1: + resolution: {integrity: sha512-9hsFDsgUwrdOoW1D97Ewog7DYSHaq4WKuNs0LHF9RiCmqB0Z+XRR4Pf7u7u9z/8CciHuJ6yxNws1XznI3ddjEw==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dependencies: - '@typescript-eslint/types': 5.45.0 - '@typescript-eslint/visitor-keys': 5.45.0 + '@typescript-eslint/types': 5.47.1 + '@typescript-eslint/visitor-keys': 5.47.1 dev: true - /@typescript-eslint/type-utils/5.45.0_hsf322ms6xhhd4b5ne6lb74y4a: - resolution: {integrity: sha512-DY7BXVFSIGRGFZ574hTEyLPRiQIvI/9oGcN8t1A7f6zIs6ftbrU0nhyV26ZW//6f85avkwrLag424n+fkuoJ1Q==} + /@typescript-eslint/type-utils/5.47.1_7uibuqfxkfaozanbtbziikiqje: + resolution: {integrity: sha512-/UKOeo8ee80A7/GJA427oIrBi/Gd4osk/3auBUg4Rn9EahFpevVV1mUK8hjyQD5lHPqX397x6CwOk5WGh1E/1w==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: eslint: '*' @@ -2690,22 +3135,22 @@ packages: typescript: optional: true dependencies: - '@typescript-eslint/typescript-estree': 5.45.0_typescript@4.9.3 - '@typescript-eslint/utils': 5.45.0_hsf322ms6xhhd4b5ne6lb74y4a + '@typescript-eslint/typescript-estree': 5.47.1_typescript@4.9.4 + '@typescript-eslint/utils': 5.47.1_7uibuqfxkfaozanbtbziikiqje debug: 4.3.4 - eslint: 8.28.0 - tsutils: 3.21.0_typescript@4.9.3 - typescript: 4.9.3 + eslint: 8.32.0 + tsutils: 3.21.0_typescript@4.9.4 + typescript: 4.9.4 transitivePeerDependencies: - supports-color dev: true - /@typescript-eslint/types/5.45.0: - resolution: {integrity: sha512-QQij+u/vgskA66azc9dCmx+rev79PzX8uDHpsqSjEFtfF2gBUTRCpvYMh2gw2ghkJabNkPlSUCimsyBEQZd1DA==} + /@typescript-eslint/types/5.47.1: + resolution: {integrity: sha512-CmALY9YWXEpwuu6377ybJBZdtSAnzXLSQcxLSqSQSbC7VfpMu/HLVdrnVJj7ycI138EHqocW02LPJErE35cE9A==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - /@typescript-eslint/typescript-estree/5.45.0_4rfylzx7siyfhvklzx37rrckmi: - resolution: {integrity: sha512-maRhLGSzqUpFcZgXxg1qc/+H0bT36lHK4APhp0AEUVrpSwXiRAomm/JGjSG+kNUio5kAa3uekCYu/47cnGn5EQ==} + /@typescript-eslint/typescript-estree/5.47.1_typescript@4.9.4: + resolution: {integrity: sha512-4+ZhFSuISAvRi2xUszEj0xXbNTHceV9GbH9S8oAD2a/F9SW57aJNQVOCxG8GPfSWH/X4eOPdMEU2jYVuWKEpWA==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: typescript: '*' @@ -2713,70 +3158,70 @@ packages: typescript: optional: true dependencies: - '@typescript-eslint/types': 5.45.0 - '@typescript-eslint/visitor-keys': 5.45.0 - debug: 4.3.4_supports-color@9.2.3 - globby: 11.1.0 - is-glob: 4.0.3 - semver: 7.3.8 - tsutils: 3.21.0_typescript@4.9.3 - typescript: 4.9.3 - transitivePeerDependencies: - - supports-color - dev: false - - /@typescript-eslint/typescript-estree/5.45.0_typescript@4.9.3: - resolution: {integrity: sha512-maRhLGSzqUpFcZgXxg1qc/+H0bT36lHK4APhp0AEUVrpSwXiRAomm/JGjSG+kNUio5kAa3uekCYu/47cnGn5EQ==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - peerDependencies: - typescript: '*' - peerDependenciesMeta: - typescript: - optional: true - dependencies: - '@typescript-eslint/types': 5.45.0 - '@typescript-eslint/visitor-keys': 5.45.0 + '@typescript-eslint/types': 5.47.1 + '@typescript-eslint/visitor-keys': 5.47.1 debug: 4.3.4 globby: 11.1.0 is-glob: 4.0.3 semver: 7.3.8 - tsutils: 3.21.0_typescript@4.9.3 - typescript: 4.9.3 + tsutils: 3.21.0_typescript@4.9.4 + typescript: 4.9.4 transitivePeerDependencies: - supports-color - /@typescript-eslint/utils/5.45.0_hsf322ms6xhhd4b5ne6lb74y4a: - resolution: {integrity: sha512-OUg2JvsVI1oIee/SwiejTot2OxwU8a7UfTFMOdlhD2y+Hl6memUSL4s98bpUTo8EpVEr0lmwlU7JSu/p2QpSvA==} + /@typescript-eslint/typescript-estree/5.47.1_w6zgx7jig4ppjo57goygyg47o4: + resolution: {integrity: sha512-4+ZhFSuISAvRi2xUszEj0xXbNTHceV9GbH9S8oAD2a/F9SW57aJNQVOCxG8GPfSWH/X4eOPdMEU2jYVuWKEpWA==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + dependencies: + '@typescript-eslint/types': 5.47.1 + '@typescript-eslint/visitor-keys': 5.47.1 + debug: 4.3.4_supports-color@9.2.2 + globby: 11.1.0 + is-glob: 4.0.3 + semver: 7.3.8 + tsutils: 3.21.0_typescript@4.9.4 + typescript: 4.9.4 + transitivePeerDependencies: + - supports-color + dev: false + + /@typescript-eslint/utils/5.47.1_7uibuqfxkfaozanbtbziikiqje: + resolution: {integrity: sha512-l90SdwqfmkuIVaREZ2ykEfCezepCLxzWMo5gVfcJsJCaT4jHT+QjgSkYhs5BMQmWqE9k3AtIfk4g211z/sTMVw==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 dependencies: '@types/json-schema': 7.0.11 '@types/semver': 7.3.13 - '@typescript-eslint/scope-manager': 5.45.0 - '@typescript-eslint/types': 5.45.0 - '@typescript-eslint/typescript-estree': 5.45.0_typescript@4.9.3 - eslint: 8.28.0 + '@typescript-eslint/scope-manager': 5.47.1 + '@typescript-eslint/types': 5.47.1 + '@typescript-eslint/typescript-estree': 5.47.1_typescript@4.9.4 + eslint: 8.32.0 eslint-scope: 5.1.1 - eslint-utils: 3.0.0_eslint@8.28.0 + eslint-utils: 3.0.0_eslint@8.32.0 semver: 7.3.8 transitivePeerDependencies: - supports-color - typescript dev: true - /@typescript-eslint/visitor-keys/5.45.0: - resolution: {integrity: sha512-jc6Eccbn2RtQPr1s7th6jJWQHBHI6GBVQkCHoJFQ5UreaKm59Vxw+ynQUPPY2u2Amquc+7tmEoC2G52ApsGNNg==} + /@typescript-eslint/visitor-keys/5.47.1: + resolution: {integrity: sha512-rF3pmut2JCCjh6BLRhNKdYjULMb1brvoaiWDlHfLNVgmnZ0sBVJrs3SyaKE1XoDDnJuAx/hDQryHYmPUuNq0ig==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dependencies: - '@typescript-eslint/types': 5.45.0 + '@typescript-eslint/types': 5.47.1 eslint-visitor-keys: 3.3.0 /@vercel/nft/0.22.1: resolution: {integrity: sha512-lYYZIoxRurqDOSoVIdBicGnpUIpfyaS5qVjdPq+EfI285WqtZK3NK/dyCkiyBul+X2U2OEhRyeMdXPCHGJbohw==} hasBin: true dependencies: - '@mapbox/node-pre-gyp': 1.0.10 + '@mapbox/node-pre-gyp': 1.0.9 acorn: 8.8.1 async-sema: 3.1.1 bindings: 1.5.0 @@ -2796,7 +3241,7 @@ packages: resolution: {integrity: sha512-lYYZIoxRurqDOSoVIdBicGnpUIpfyaS5qVjdPq+EfI285WqtZK3NK/dyCkiyBul+X2U2OEhRyeMdXPCHGJbohw==} hasBin: true dependencies: - '@mapbox/node-pre-gyp': 1.0.10_supports-color@9.2.3 + '@mapbox/node-pre-gyp': 1.0.9_supports-color@9.2.2 acorn: 8.8.1 async-sema: 3.1.1 bindings: 1.5.0 @@ -2812,159 +3257,163 @@ packages: - supports-color dev: false - /@vitejs/plugin-vue/3.2.0_vite@3.0.9+vue@3.2.45: - resolution: {integrity: sha512-E0tnaL4fr+qkdCNxJ+Xd0yM31UwMkQje76fsDVBBUCoGOUPexu2VDUYHL8P4CwV+zMvWw6nlRw19OnRKmYAJpw==} + /@vitejs/plugin-vue/4.0.0_vite@4.0.4+vue@3.2.47: + resolution: {integrity: sha512-e0X4jErIxAB5oLtDqbHvHpJe/uWNkdpYV83AOG2xo2tEVSzCzewgJMtREZM30wXnM5ls90hxiOtAuVU6H5JgbA==} engines: {node: ^14.18.0 || >=16.0.0} peerDependencies: - vite: ^3.0.0 + vite: ^4.0.0 vue: ^3.2.25 dependencies: - vite: 3.0.9_sass@1.56.1 - vue: 3.2.45 + vite: 4.0.4_sass@1.57.1 + vue: 3.2.47 dev: false - /@vue/compiler-core/3.2.45: - resolution: {integrity: sha512-rcMj7H+PYe5wBV3iYeUgbCglC+pbpN8hBLTJvRiK2eKQiWqu+fG9F+8sW99JdL4LQi7Re178UOxn09puSXvn4A==} + /@vue/compiler-core/3.2.47: + resolution: {integrity: sha512-p4D7FDnQb7+YJmO2iPEv0SQNeNzcbHdGByJDsT4lynf63AFkOTFN07HsiRSvjGo0QrxR/o3d0hUyNCUnBU2Tig==} dependencies: - '@babel/parser': 7.20.5 - '@vue/shared': 3.2.45 + '@babel/parser': 7.20.7 + '@vue/shared': 3.2.47 estree-walker: 2.0.2 source-map: 0.6.1 dev: false - /@vue/compiler-dom/3.2.45: - resolution: {integrity: sha512-tyYeUEuKqqZO137WrZkpwfPCdiiIeXYCcJ8L4gWz9vqaxzIQRccTSwSWZ/Axx5YR2z+LvpUbmPNXxuBU45lyRw==} + /@vue/compiler-dom/3.2.47: + resolution: {integrity: sha512-dBBnEHEPoftUiS03a4ggEig74J2YBZ2UIeyfpcRM2tavgMWo4bsEfgCGsu+uJIL/vax9S+JztH8NmQerUo7shQ==} dependencies: - '@vue/compiler-core': 3.2.45 - '@vue/shared': 3.2.45 + '@vue/compiler-core': 3.2.47 + '@vue/shared': 3.2.47 dev: false - /@vue/compiler-sfc/3.2.45: - resolution: {integrity: sha512-1jXDuWah1ggsnSAOGsec8cFjT/K6TMZ0sPL3o3d84Ft2AYZi2jWJgRMjw4iaK0rBfA89L5gw427H4n1RZQBu6Q==} + /@vue/compiler-sfc/3.2.47: + resolution: {integrity: sha512-rog05W+2IFfxjMcFw10tM9+f7i/+FFpZJJ5XHX72NP9eC2uRD+42M3pYcQqDXVYoj74kHMSEdQ/WmCjt8JFksQ==} dependencies: - '@babel/parser': 7.20.5 - '@vue/compiler-core': 3.2.45 - '@vue/compiler-dom': 3.2.45 - '@vue/compiler-ssr': 3.2.45 - '@vue/reactivity-transform': 3.2.45 - '@vue/shared': 3.2.45 + '@babel/parser': 7.20.7 + '@vue/compiler-core': 3.2.47 + '@vue/compiler-dom': 3.2.47 + '@vue/compiler-ssr': 3.2.47 + '@vue/reactivity-transform': 3.2.47 + '@vue/shared': 3.2.47 estree-walker: 2.0.2 magic-string: 0.25.9 - postcss: 8.4.19 + postcss: 8.4.20 source-map: 0.6.1 dev: false - /@vue/compiler-ssr/3.2.45: - resolution: {integrity: sha512-6BRaggEGqhWht3lt24CrIbQSRD5O07MTmd+LjAn5fJj568+R9eUD2F7wMQJjX859seSlrYog7sUtrZSd7feqrQ==} + /@vue/compiler-ssr/3.2.47: + resolution: {integrity: sha512-wVXC+gszhulcMD8wpxMsqSOpvDZ6xKXSVWkf50Guf/S+28hTAXPDYRTbLQ3EDkOP5Xz/+SY37YiwDquKbJOgZw==} dependencies: - '@vue/compiler-dom': 3.2.45 - '@vue/shared': 3.2.45 + '@vue/compiler-dom': 3.2.47 + '@vue/shared': 3.2.47 dev: false /@vue/devtools-api/6.4.5: resolution: {integrity: sha512-JD5fcdIuFxU4fQyXUu3w2KpAJHzTVdN+p4iOX2lMWSHMOoQdMAcpFLZzm9Z/2nmsoZ1a96QEhZ26e50xLBsgOQ==} dev: false - /@vue/reactivity-transform/3.2.45: - resolution: {integrity: sha512-BHVmzYAvM7vcU5WmuYqXpwaBHjsS8T63jlKGWVtHxAHIoMIlmaMyurUSEs1Zcg46M4AYT5MtB1U274/2aNzjJQ==} + /@vue/reactivity-transform/3.2.47: + resolution: {integrity: sha512-m8lGXw8rdnPVVIdIFhf0LeQ/ixyHkH5plYuS83yop5n7ggVJU+z5v0zecwEnX7fa7HNLBhh2qngJJkxpwEEmYA==} dependencies: - '@babel/parser': 7.20.5 - '@vue/compiler-core': 3.2.45 - '@vue/shared': 3.2.45 + '@babel/parser': 7.20.7 + '@vue/compiler-core': 3.2.47 + '@vue/shared': 3.2.47 estree-walker: 2.0.2 magic-string: 0.25.9 dev: false - /@vue/reactivity/3.2.45: - resolution: {integrity: sha512-PRvhCcQcyEVohW0P8iQ7HDcIOXRjZfAsOds3N99X/Dzewy8TVhTCT4uXpAHfoKjVTJRA0O0K+6QNkDIZAxNi3A==} + /@vue/reactivity/3.2.47: + resolution: {integrity: sha512-7khqQ/75oyyg+N/e+iwV6lpy1f5wq759NdlS1fpAhFXa8VeAIKGgk2E/C4VF59lx5b+Ezs5fpp/5WsRYXQiKxQ==} dependencies: - '@vue/shared': 3.2.45 + '@vue/shared': 3.2.47 dev: false - /@vue/repl/1.3.2_vue@3.2.45: + /@vue/repl/1.3.2_vue@3.2.47: resolution: {integrity: sha512-5joGOuTFmjaugG3E1h/oP1EXSMcVXRUwLIoo8xvYQnqDrCT6g1SfsH1pfei5PpC5DUxMX1584CekZu6REgGYkQ==} peerDependencies: vue: ^3.2.13 dependencies: - vue: 3.2.45 + vue: 3.2.47 dev: false - /@vue/runtime-core/3.2.45: - resolution: {integrity: sha512-gzJiTA3f74cgARptqzYswmoQx0fIA+gGYBfokYVhF8YSXjWTUA2SngRzZRku2HbGbjzB6LBYSbKGIaK8IW+s0A==} + /@vue/runtime-core/3.2.47: + resolution: {integrity: sha512-RZxbLQIRB/K0ev0K9FXhNbBzT32H9iRtYbaXb0ZIz2usLms/D55dJR2t6cIEUn6vyhS3ALNvNthI+Q95C+NOpA==} dependencies: - '@vue/reactivity': 3.2.45 - '@vue/shared': 3.2.45 + '@vue/reactivity': 3.2.47 + '@vue/shared': 3.2.47 dev: false - /@vue/runtime-dom/3.2.45: - resolution: {integrity: sha512-cy88YpfP5Ue2bDBbj75Cb4bIEZUMM/mAkDMfqDTpUYVgTf/kuQ2VQ8LebuZ8k6EudgH8pYhsGWHlY0lcxlvTwA==} + /@vue/runtime-dom/3.2.47: + resolution: {integrity: sha512-ArXrFTjS6TsDei4qwNvgrdmHtD930KgSKGhS5M+j8QxXrDJYLqYw4RRcDy1bz1m1wMmb6j+zGLifdVHtkXA7gA==} dependencies: - '@vue/runtime-core': 3.2.45 - '@vue/shared': 3.2.45 - csstype: 2.6.21 + '@vue/runtime-core': 3.2.47 + '@vue/shared': 3.2.47 + csstype: 2.6.20 dev: false - /@vue/server-renderer/3.2.45_vue@3.2.45: - resolution: {integrity: sha512-ebiMq7q24WBU1D6uhPK//2OTR1iRIyxjF5iVq/1a5I1SDMDyDu4Ts6fJaMnjrvD3MqnaiFkKQj+LKAgz5WIK3g==} + /@vue/server-renderer/3.2.47_vue@3.2.47: + resolution: {integrity: sha512-dN9gc1i8EvmP9RCzvneONXsKfBRgqFeFZLurmHOveL7oH6HiFXJw5OGu294n1nHc/HMgTy6LulU/tv5/A7f/LA==} peerDependencies: - vue: 3.2.45 + vue: 3.2.47 dependencies: - '@vue/compiler-ssr': 3.2.45 - '@vue/shared': 3.2.45 - vue: 3.2.45 + '@vue/compiler-ssr': 3.2.47 + '@vue/shared': 3.2.47 + vue: 3.2.47 dev: false - /@vue/shared/3.2.45: - resolution: {integrity: sha512-Ewzq5Yhimg7pSztDV+RH1UDKBzmtqieXQlpTVm2AwraoRL/Rks96mvd8Vgi7Lj+h+TH8dv7mXD3FRZR3TUvbSg==} + /@vue/shared/3.2.47: + resolution: {integrity: sha512-BHGyyGN3Q97EZx0taMQ+OLNuZcW3d37ZEVmEAyeoA9ERdGvm9Irc/0Fua8SNyOtV1w6BS4q25wbMzJujO9HIfQ==} dev: false - /@vuepress/bundler-vite/2.0.0-beta.51_sass@1.56.1: - resolution: {integrity: sha512-HADQujwuj0KbONq6R0UGSiktMzG0iOFmI2OACgi7r5P4pHAEF06h333g0q4tSH6HQg6VuqelQrVgWwq/0puIfA==} + /@vuepress/bundler-vite/2.0.0-beta.60_sass@1.57.1: + resolution: {integrity: sha512-nf+UAKNlAEZXZqu2Ztvr8Hg/5CtevWxvQGfYKV4lhw8UmoDjKKHoHPpPhF1QTUbnZ8W+jPLzIVz+hjunzsxl/A==} dependencies: - '@vitejs/plugin-vue': 3.2.0_vite@3.0.9+vue@3.2.45 - '@vuepress/client': 2.0.0-beta.51 - '@vuepress/core': 2.0.0-beta.51 - '@vuepress/shared': 2.0.0-beta.51 - '@vuepress/utils': 2.0.0-beta.51 - autoprefixer: 10.4.13_postcss@8.4.19 + '@vitejs/plugin-vue': 4.0.0_vite@4.0.4+vue@3.2.47 + '@vuepress/client': 2.0.0-beta.60 + '@vuepress/core': 2.0.0-beta.60 + '@vuepress/shared': 2.0.0-beta.60 + '@vuepress/utils': 2.0.0-beta.60 + autoprefixer: 10.4.13_postcss@8.4.20 connect-history-api-fallback: 2.0.0 - postcss: 8.4.19 - rollup: 2.79.1 - vite: 3.0.9_sass@1.56.1 - vue: 3.2.45 - vue-router: 4.1.6_vue@3.2.45 + postcss: 8.4.20 + postcss-load-config: 4.0.1_postcss@8.4.20 + rollup: 3.9.0 + vite: 4.0.4_sass@1.57.1 + vue: 3.2.47 + vue-router: 4.1.6_vue@3.2.47 transitivePeerDependencies: + - '@types/node' - less - sass - stylus + - sugarss - supports-color - terser + - ts-node dev: false - /@vuepress/bundler-webpack/2.0.0-beta.51: - resolution: {integrity: sha512-ell4t2sNiGxtSZGk0m6ygapmrte5RKGEubW0D7qskYvmmCbwvB/g/orIjIVfU2aZSVA1QbuPspQ/N0KMCIzxPg==} + /@vuepress/bundler-webpack/2.0.0-beta.60: + resolution: {integrity: sha512-vHqRha7Dw3kktorC6s/dyeysf1tdYg01PiBzWP16e1UWejVr54O9HiqK0hG8fr469DYKIk5kHPwB1r5yu4hyqQ==} dependencies: - '@types/express': 4.17.14 + '@types/express': 4.17.15 '@types/webpack-env': 1.18.0 - '@vuepress/client': 2.0.0-beta.51 - '@vuepress/core': 2.0.0-beta.51 - '@vuepress/shared': 2.0.0-beta.51 - '@vuepress/utils': 2.0.0-beta.51 - autoprefixer: 10.4.13_postcss@8.4.19 + '@vuepress/client': 2.0.0-beta.60 + '@vuepress/core': 2.0.0-beta.60 + '@vuepress/shared': 2.0.0-beta.60 + '@vuepress/utils': 2.0.0-beta.60 + autoprefixer: 10.4.13_postcss@8.4.20 chokidar: 3.5.3 copy-webpack-plugin: 11.0.0_webpack@5.75.0 - css-loader: 6.7.2_webpack@5.75.0 - esbuild-loader: 2.19.0_webpack@5.75.0 + css-loader: 6.7.3_webpack@5.75.0 + esbuild-loader: 2.20.0_webpack@5.75.0 express: 4.18.2 html-webpack-plugin: 5.5.0_webpack@5.75.0 - mini-css-extract-plugin: 2.7.0_webpack@5.75.0 - postcss: 8.4.19 - postcss-csso: 6.0.1_postcss@8.4.19 - postcss-loader: 7.0.1_upg3rk2kpasnbk27hkqapxaxfq + mini-css-extract-plugin: 2.7.2_webpack@5.75.0 + postcss: 8.4.20 + postcss-csso: 6.0.1_postcss@8.4.20 + postcss-loader: 7.0.2_qxxfhhrl3yknjjmta266mo3u64 style-loader: 3.3.1_webpack@5.75.0 - vue: 3.2.45 - vue-loader: 17.0.1_vue@3.2.45+webpack@5.75.0 - vue-router: 4.1.6_vue@3.2.45 + vue: 3.2.47 + vue-loader: 17.0.1_vue@3.2.47+webpack@5.75.0 + vue-router: 4.1.6_vue@3.2.47 webpack: 5.75.0 webpack-chain: 6.5.1 webpack-dev-server: 4.11.1_webpack@5.75.0 @@ -2981,105 +3430,105 @@ packages: - webpack-cli dev: false - /@vuepress/cli/2.0.0-beta.51: - resolution: {integrity: sha512-NcMNpsGxdlPgrHhIMW+hkRd9l+E+89M8IoN9SnBJFTgokKrUOwLm2BEQPVuucebj4ff94IorG1WQR9iah/qOgQ==} + /@vuepress/cli/2.0.0-beta.60: + resolution: {integrity: sha512-ibC6ezsn1m+r3PB382ZZfmwBFlkR/9LVk5u2cUBmhBj4t+W2XPgWkKTTmG81ny7lnUJweloQc9fa1ww77se2Ug==} hasBin: true dependencies: - '@vuepress/core': 2.0.0-beta.51 - '@vuepress/shared': 2.0.0-beta.51 - '@vuepress/utils': 2.0.0-beta.51 + '@vuepress/core': 2.0.0-beta.60 + '@vuepress/shared': 2.0.0-beta.60 + '@vuepress/utils': 2.0.0-beta.60 cac: 6.7.14 chokidar: 3.5.3 envinfo: 7.8.1 - esbuild: 0.15.16 + esbuild: 0.16.17 transitivePeerDependencies: - supports-color dev: false - /@vuepress/client/2.0.0-beta.51: - resolution: {integrity: sha512-5iQV765kwR6/eIZPMlV5O34DUvHCMjF7zpr91x5i8BEAg7A0jfHvdrwNavAKWiQEU77f4dIBXtWy6nwX+lgmbw==} + /@vuepress/client/2.0.0-beta.60: + resolution: {integrity: sha512-WU5VGeDp41A2dVXqp18YBggflIjTq68mA+s5TCz93wk+7elAmPAkWKcobQBYQgvsuwHyg9nWulZAfMN6OEygKQ==} dependencies: '@vue/devtools-api': 6.4.5 - '@vuepress/shared': 2.0.0-beta.51 - vue: 3.2.45 - vue-router: 4.1.6_vue@3.2.45 + '@vuepress/shared': 2.0.0-beta.60 + vue: 3.2.47 + vue-router: 4.1.6_vue@3.2.47 dev: false - /@vuepress/core/2.0.0-beta.51: - resolution: {integrity: sha512-j0KI6PBsf0doMZPXa1H4Vi88NSTrpsnSVhMgcr9gw81atgKl+I13SykHpWZRRkugTRCgL1IOpyY68cond58eeA==} + /@vuepress/core/2.0.0-beta.60: + resolution: {integrity: sha512-HkUkqBnBI7GMVZGxdzV4C/iyFwPo215sVLYvZVEWpQIaLk/47WkK0sHtz/1i00ujwJC3uGOH1+f0IHkxzqjUmg==} dependencies: - '@vuepress/client': 2.0.0-beta.51 - '@vuepress/markdown': 2.0.0-beta.51 - '@vuepress/shared': 2.0.0-beta.51 - '@vuepress/utils': 2.0.0-beta.51 - vue: 3.2.45 + '@vuepress/client': 2.0.0-beta.60 + '@vuepress/markdown': 2.0.0-beta.60 + '@vuepress/shared': 2.0.0-beta.60 + '@vuepress/utils': 2.0.0-beta.60 + vue: 3.2.47 transitivePeerDependencies: - supports-color dev: false - /@vuepress/markdown/2.0.0-beta.51: - resolution: {integrity: sha512-q11+6j3OAutuV0LkH7BGdhh4jKOMKMiiX8bKD366mzr7JkjHb34xd+WhM394B7zh410CtYYWvAWS+m9RJGQ/5w==} + /@vuepress/markdown/2.0.0-beta.60: + resolution: {integrity: sha512-97AT4aZr1k1VrJZoUvzbrX6nU/TwxlFpLNi8KNtWK3TMZT6+hAU0aCg6TwuwirShvey8mr9GaMNSssAdpSK4mg==} dependencies: - '@mdit-vue/plugin-component': 0.10.0 - '@mdit-vue/plugin-frontmatter': 0.10.0 - '@mdit-vue/plugin-headers': 0.10.0 - '@mdit-vue/plugin-sfc': 0.10.0 - '@mdit-vue/plugin-title': 0.10.0 - '@mdit-vue/plugin-toc': 0.10.0 - '@mdit-vue/shared': 0.10.0 - '@mdit-vue/types': 0.10.0 + '@mdit-vue/plugin-component': 0.11.2 + '@mdit-vue/plugin-frontmatter': 0.11.1 + '@mdit-vue/plugin-headers': 0.11.2 + '@mdit-vue/plugin-sfc': 0.11.1 + '@mdit-vue/plugin-title': 0.11.2 + '@mdit-vue/plugin-toc': 0.11.2 + '@mdit-vue/shared': 0.11.2 + '@mdit-vue/types': 0.11.0 '@types/markdown-it': 12.2.3 '@types/markdown-it-emoji': 2.0.2 - '@vuepress/shared': 2.0.0-beta.51 - '@vuepress/utils': 2.0.0-beta.51 + '@vuepress/shared': 2.0.0-beta.60 + '@vuepress/utils': 2.0.0-beta.60 markdown-it: 13.0.1 - markdown-it-anchor: 8.6.5_ea7kj7wzjkld5jo2noyjqxi764 + markdown-it-anchor: 8.6.6_ea7kj7wzjkld5jo2noyjqxi764 markdown-it-emoji: 2.0.2 mdurl: 1.0.1 transitivePeerDependencies: - supports-color dev: false - /@vuepress/plugin-active-header-links/2.0.0-beta.51: - resolution: {integrity: sha512-AV9qLVSD3e9Xnp+2Vu9tegUdzbm9HD2bF6pRC3xEdW8GzRlsHBTfMpFwfsKvkKofk90+4ICkPWY9mY95P4mNSw==} + /@vuepress/plugin-active-header-links/2.0.0-beta.60: + resolution: {integrity: sha512-L+KijW7FvoDWMTd6wiIZhMA/uZYgMhiukL6IaVWtQ0COyWGIjaZUlX+mHd1munSzz4aWBMbck7no82bPswCh0g==} dependencies: - '@vuepress/client': 2.0.0-beta.51 - '@vuepress/core': 2.0.0-beta.51 - '@vuepress/utils': 2.0.0-beta.51 + '@vuepress/client': 2.0.0-beta.60 + '@vuepress/core': 2.0.0-beta.60 + '@vuepress/utils': 2.0.0-beta.60 ts-debounce: 4.0.0 - vue: 3.2.45 - vue-router: 4.1.5_vue@3.2.45 + vue: 3.2.47 + vue-router: 4.1.6_vue@3.2.47 transitivePeerDependencies: - supports-color dev: false - /@vuepress/plugin-container/2.0.0-beta.51: - resolution: {integrity: sha512-81FzcStQs5A0VTReWsS/CSVpaxfcAA5Gj0pzbcc6/QpNTa9Gaj2UywbcWOLIk3wozCrKucCLu8TSL31cj0+LqA==} + /@vuepress/plugin-container/2.0.0-beta.60: + resolution: {integrity: sha512-yQBAm7sFRGMvCz8Ju2qFG0iLQs/XvWd11UAsywSdvps3A0nZuANSb68QTYJPN3JJfZ5d0LCxlhJ4rbBWT49+wQ==} dependencies: '@types/markdown-it': 12.2.3 - '@vuepress/core': 2.0.0-beta.51 - '@vuepress/markdown': 2.0.0-beta.51 - '@vuepress/shared': 2.0.0-beta.51 - '@vuepress/utils': 2.0.0-beta.51 + '@vuepress/core': 2.0.0-beta.60 + '@vuepress/markdown': 2.0.0-beta.60 + '@vuepress/shared': 2.0.0-beta.60 + '@vuepress/utils': 2.0.0-beta.60 markdown-it: 13.0.1 markdown-it-container: 3.0.0 transitivePeerDependencies: - supports-color dev: false - /@vuepress/plugin-docsearch/2.0.0-beta.51: - resolution: {integrity: sha512-qVrsji7YgGqzOuxRdfeAtfJQL7hFCbc6W9pxNlxsYteIm3HR6V/SQ0xD3aetow/U0c3qJGTTm73i0IcRfdLjIg==} + /@vuepress/plugin-docsearch/2.0.0-beta.60: + resolution: {integrity: sha512-4aquipHuEd87KdFh2ufh5OTeU5qaREer4DqJShpXemY5JiJqvGpda5KmLUTkAis/WPo44GWeFsgtgOqiHevqcA==} dependencies: - '@docsearch/css': 3.3.0 - '@docsearch/js': 3.3.0 - '@docsearch/react': 3.3.0 - '@vuepress/client': 2.0.0-beta.51 - '@vuepress/core': 2.0.0-beta.51 - '@vuepress/shared': 2.0.0-beta.51 - '@vuepress/utils': 2.0.0-beta.51 + '@docsearch/css': 3.3.1 + '@docsearch/js': 3.3.1 + '@docsearch/react': 3.3.1 + '@vuepress/client': 2.0.0-beta.60 + '@vuepress/core': 2.0.0-beta.60 + '@vuepress/shared': 2.0.0-beta.60 + '@vuepress/utils': 2.0.0-beta.60 ts-debounce: 4.0.0 - vue: 3.2.45 - vue-router: 4.1.5_vue@3.2.45 + vue: 3.2.47 + vue-router: 4.1.6_vue@3.2.47 transitivePeerDependencies: - '@algolia/client-search' - '@types/react' @@ -3088,169 +3537,203 @@ packages: - supports-color dev: false - /@vuepress/plugin-external-link-icon/2.0.0-beta.51: - resolution: {integrity: sha512-6ITMmvD/6DX2MLCCnGOJBXkB+rFbRkVboWzBibCzITHfUORsmFwLMjmrDxnIbZl74F0VZ7533zk/BRJIy4uYLA==} + /@vuepress/plugin-external-link-icon/2.0.0-beta.60: + resolution: {integrity: sha512-We4YmS4G7sWoOec/FKYhTM86qRCMBbDThcxOiPm6sWHrhTdxk3bFgJq/DfqJU/ply1ta72AWep0rEY6fj6JJ2A==} dependencies: - '@vuepress/client': 2.0.0-beta.51 - '@vuepress/core': 2.0.0-beta.51 - '@vuepress/markdown': 2.0.0-beta.51 - '@vuepress/shared': 2.0.0-beta.51 - '@vuepress/utils': 2.0.0-beta.51 - vue: 3.2.45 + '@vuepress/client': 2.0.0-beta.60 + '@vuepress/core': 2.0.0-beta.60 + '@vuepress/markdown': 2.0.0-beta.60 + '@vuepress/shared': 2.0.0-beta.60 + '@vuepress/utils': 2.0.0-beta.60 + vue: 3.2.47 transitivePeerDependencies: - supports-color dev: false - /@vuepress/plugin-git/2.0.0-beta.51: - resolution: {integrity: sha512-lw45Vjg5pI25zNgPOTBcIrBNhNB9jU9o/j+fhb5TnW1j9hX3mwWDeJhdWLLErodSlmnTVdyL3e7qNKJpKo1Wmg==} + /@vuepress/plugin-git/2.0.0-beta.60: + resolution: {integrity: sha512-Yu+D8gItxD8BFueV5fQd7AxIgjcxyDY1AFCTmPsP9VDMJ0AuJuaPTLWOf5o0uKzWd5z1mDw0ZwWFh8j3FyHv+A==} dependencies: - '@vuepress/core': 2.0.0-beta.51 - '@vuepress/utils': 2.0.0-beta.51 + '@vuepress/core': 2.0.0-beta.60 + '@vuepress/utils': 2.0.0-beta.60 execa: 6.1.0 transitivePeerDependencies: - supports-color dev: false - /@vuepress/plugin-medium-zoom/2.0.0-beta.51: - resolution: {integrity: sha512-pgsKfsuEazHOLEE0xAWWi2McrygR5shQ1Xi4mZzn1MD9cn5o4JKbJxp2BlUs8q+yG5QMUQ0ugAJ9yRgCkMkUBw==} + /@vuepress/plugin-medium-zoom/2.0.0-beta.60: + resolution: {integrity: sha512-KiJui/sTIHa321jJ/dc11ysyqTMj4Sz9tWoTSnwBJ4nebaO/0OFGQcFajk2+1ELs4poUh/w0THxc+NskR+bf+g==} dependencies: - '@vuepress/client': 2.0.0-beta.51 - '@vuepress/core': 2.0.0-beta.51 - '@vuepress/utils': 2.0.0-beta.51 + '@vuepress/client': 2.0.0-beta.60 + '@vuepress/core': 2.0.0-beta.60 + '@vuepress/utils': 2.0.0-beta.60 medium-zoom: 1.0.8 - vue: 3.2.45 + vue: 3.2.47 transitivePeerDependencies: - supports-color dev: false - /@vuepress/plugin-nprogress/2.0.0-beta.51: - resolution: {integrity: sha512-eu3IxuiCS5y+Za9l86xKrNSo13VseoZCnAPSIqZj6I6wvyWI62ffCP5NztdR0Z9izp0g/FL6KBtBlwN1PnkY7A==} + /@vuepress/plugin-nprogress/2.0.0-beta.60: + resolution: {integrity: sha512-zRdJP39qFO8q9TAwlCS4tLOd2rLGtkKqkPTsfhjtWwDqSbtTHy0GqVBL8KJUy3H0+qSiyvtC647yLNRbJ9LOlw==} dependencies: - '@vuepress/client': 2.0.0-beta.51 - '@vuepress/core': 2.0.0-beta.51 - '@vuepress/utils': 2.0.0-beta.51 - vue: 3.2.45 - vue-router: 4.1.5_vue@3.2.45 + '@vuepress/client': 2.0.0-beta.60 + '@vuepress/core': 2.0.0-beta.60 + '@vuepress/utils': 2.0.0-beta.60 + vue: 3.2.47 + vue-router: 4.1.6_vue@3.2.47 transitivePeerDependencies: - supports-color dev: false - /@vuepress/plugin-palette/2.0.0-beta.51: - resolution: {integrity: sha512-Q3uFQxiPC7W3JKlyoAT0Nu1bZy6PXXUadjzwpk8dcHDsh+OmdUQqdNfeU1hc4pPQjHIiGdsBAnnGnb+8dNXqkw==} + /@vuepress/plugin-palette/2.0.0-beta.60: + resolution: {integrity: sha512-KPIQCLUEIsgsdxINR6mYJRhHmWCo0850QEvy9+ikdv+ds1z6wJ5xwq/xWy/pRJ6lXdgHQrtuVkroWl+IdppcRw==} dependencies: - '@vuepress/core': 2.0.0-beta.51 - '@vuepress/utils': 2.0.0-beta.51 + '@vuepress/core': 2.0.0-beta.60 + '@vuepress/utils': 2.0.0-beta.60 chokidar: 3.5.3 transitivePeerDependencies: - supports-color dev: false - /@vuepress/plugin-prismjs/2.0.0-beta.51: - resolution: {integrity: sha512-C1kyhWYlehZVuOQK6H8eyo2Mw8Lj3wAA9Lp3YbX9bt0qNf4kfzviEQL+mTrgzM+j1Jpaijjj6nZS0Ev42mO+kw==} + /@vuepress/plugin-prismjs/2.0.0-beta.60: + resolution: {integrity: sha512-yWRWAsUX6iO7uUN67yyy20x3H1clQZ519rHh2dvs6wMyXsO0E3vlNB8jrveOdr+0lfoUll58t2AsxpvzTObY0A==} dependencies: - '@vuepress/core': 2.0.0-beta.51 + '@vuepress/core': 2.0.0-beta.60 prismjs: 1.29.0 transitivePeerDependencies: - supports-color dev: false - /@vuepress/plugin-search/2.0.0-beta.51: - resolution: {integrity: sha512-LUKD1WOhesfbjRmy+3wPz27ZOat5sEL7nRVFrmoZNGjqGoUSuh/AFnd04z2utVEoceeuWWOluVmpoYKhxJVMFQ==} + /@vuepress/plugin-search/2.0.0-beta.60: + resolution: {integrity: sha512-9ENqni4H35/L6vab5DpQfy92DcKPL+36xxoOj1EqZfjU/IlIOFKz4TK8JwhaX+reswokF8NriPFcWol4xIa5IA==} dependencies: - '@vuepress/client': 2.0.0-beta.51 - '@vuepress/core': 2.0.0-beta.51 - '@vuepress/shared': 2.0.0-beta.51 - '@vuepress/utils': 2.0.0-beta.51 + '@vuepress/client': 2.0.0-beta.60 + '@vuepress/core': 2.0.0-beta.60 + '@vuepress/shared': 2.0.0-beta.60 + '@vuepress/utils': 2.0.0-beta.60 chokidar: 3.5.3 - vue: 3.2.45 - vue-router: 4.1.5_vue@3.2.45 + vue: 3.2.47 + vue-router: 4.1.6_vue@3.2.47 transitivePeerDependencies: - supports-color dev: false - /@vuepress/plugin-theme-data/2.0.0-beta.51: - resolution: {integrity: sha512-sfsZRhb7zZATqY1+BXkynZZ7HEZnBZEd4iuEyCNpWEnjwa7/qjPSKJyAb/M0a2SLgN2/UcPdM5URMfE1mV/4QQ==} + /@vuepress/plugin-shiki/2.0.0-beta.60: + resolution: {integrity: sha512-ENUZnuLPnXKqozA0sr2xrVuTWFBziYcXIi9sL6Dc1x3+AdBHxXA0oinPioJ/TJ5qgUF8rAFMZnUR/uwZQV+KQQ==} + dependencies: + '@vuepress/core': 2.0.0-beta.60 + shiki: 0.12.1 + transitivePeerDependencies: + - supports-color + dev: false + + /@vuepress/plugin-theme-data/2.0.0-beta.60: + resolution: {integrity: sha512-3b34sXEAzShvUzeEMA/0JE4VrLxoMqGJOGMl0I9m0DKg2apgjRG6nYYq6gUnJW0gcUVK+tOOOHsMT6mTMs3xdA==} dependencies: '@vue/devtools-api': 6.4.5 - '@vuepress/client': 2.0.0-beta.51 - '@vuepress/core': 2.0.0-beta.51 - '@vuepress/shared': 2.0.0-beta.51 - '@vuepress/utils': 2.0.0-beta.51 - vue: 3.2.45 + '@vuepress/client': 2.0.0-beta.60 + '@vuepress/core': 2.0.0-beta.60 + '@vuepress/shared': 2.0.0-beta.60 + '@vuepress/utils': 2.0.0-beta.60 + vue: 3.2.47 transitivePeerDependencies: - supports-color dev: false - /@vuepress/plugin-toc/2.0.0-beta.51: - resolution: {integrity: sha512-qpAVyCbjuFQlR3A8vsApgVxNuRrEoZovdf96q0e/L77KY85yqP2h5+Tv1z7R8CowsaDZBaABt6BFM+8THMHClA==} + /@vuepress/plugin-toc/2.0.0-beta.60: + resolution: {integrity: sha512-rl65GtYahh7Mm6JiOT7WKuvYgkPquhQCFOSOFKWFEH/4A+950XKfSARJVwu+bsn0xx25X3RMErWuS1l7hNkNgw==} dependencies: - '@vuepress/client': 2.0.0-beta.51 - '@vuepress/core': 2.0.0-beta.51 - '@vuepress/utils': 2.0.0-beta.51 - vue: 3.2.45 - vue-router: 4.1.5_vue@3.2.45 + '@vuepress/client': 2.0.0-beta.60 + '@vuepress/core': 2.0.0-beta.60 + '@vuepress/utils': 2.0.0-beta.60 + vue: 3.2.47 + vue-router: 4.1.6_vue@3.2.47 transitivePeerDependencies: - supports-color dev: false - /@vuepress/shared/2.0.0-beta.51: - resolution: {integrity: sha512-0dbJp0M+d/schkD+xUI7MwwoyJRtFxH3QEYMcLTKhgkaNFjgzlIEG/coh1QywVIoQGX9cGQSa8PZk8BeMeePug==} + /@vuepress/shared/2.0.0-beta.60: + resolution: {integrity: sha512-bwFksEtSQpbyAGJZkvRK9Z2zGmS144nv759vOzbRUZPPlGffeauzrPw9w7wxqp3gTJvIE/4Ufqt0AZTuSP/F/g==} dependencies: - '@mdit-vue/types': 0.10.0 - '@vue/shared': 3.2.45 + '@mdit-vue/types': 0.11.0 + '@vue/shared': 3.2.47 dev: false - /@vuepress/utils/2.0.0-beta.51: - resolution: {integrity: sha512-BtWK38047GNk3CnzAN9dxm8n7XplHqOU/DhW4BYO84Czl6XZh0NExPny3aPf7SL8roy03eAzF0dgPgmug6whIQ==} + /@vuepress/utils/2.0.0-beta.60: + resolution: {integrity: sha512-R5m5/AtKWAnlH+Su2yxoHQNp2JdJZ7gHV5531RbFySq9FTlKHtvE5RFceeppc0/UpzPE6KggRdaRqyjc77vg4g==} dependencies: '@types/debug': 4.1.7 '@types/fs-extra': 9.0.13 '@types/hash-sum': 1.0.0 - '@vuepress/shared': 2.0.0-beta.51 - chalk: 5.1.2 + '@vuepress/shared': 2.0.0-beta.60 debug: 4.3.4 - fs-extra: 10.1.0 - globby: 13.1.2 + fs-extra: 11.1.0 + globby: 13.1.3 hash-sum: 2.0.0 ora: 6.1.2 + picocolors: 1.0.0 upath: 2.0.1 transitivePeerDependencies: - supports-color dev: false - /@vueuse/core/9.6.0_vue@3.2.45: - resolution: {integrity: sha512-qGUcjKQXHgN+jqXEgpeZGoxdCbIDCdVPz3QiF1uyecVGbMuM63o96I1GjYx5zskKgRI0FKSNsVWM7rwrRMTf6A==} + /@vueuse/core/9.10.0_vue@3.2.47: + resolution: {integrity: sha512-CxMewME07qeuzuT/AOIQGv0EhhDoojniqU6pC3F8m5VC76L47UT18DcX88kWlP3I7d3qMJ4u/PD8iSRsy3bmNA==} dependencies: '@types/web-bluetooth': 0.0.16 - '@vueuse/metadata': 9.6.0 - '@vueuse/shared': 9.6.0_vue@3.2.45 - vue-demi: 0.13.11_vue@3.2.45 + '@vueuse/metadata': 9.10.0 + '@vueuse/shared': 9.10.0_vue@3.2.47 + vue-demi: 0.13.6_vue@3.2.47 transitivePeerDependencies: - '@vue/composition-api' - vue dev: false - /@vueuse/metadata/9.6.0: - resolution: {integrity: sha512-sIC8R+kWkIdpi5X2z2Gk8TRYzmczDwHRhEFfCu2P+XW2JdPoXrziqsGpDDsN7ykBx4ilwieS7JUIweVGhvZ93w==} - dev: false - - /@vueuse/shared/9.6.0_vue@3.2.45: - resolution: {integrity: sha512-/eDchxYYhkHnFyrb00t90UfjCx94kRHxc7J1GtBCqCG4HyPMX+krV9XJgVtWIsAMaxKVU4fC8NSUviG1JkwhUQ==} + /@vueuse/core/9.12.0_vue@3.2.47: + resolution: {integrity: sha512-h/Di8Bvf6xRcvS/PvUVheiMYYz3U0tH3X25YxONSaAUBa841ayMwxkuzx/DGUMCW/wHWzD8tRy2zYmOC36r4sg==} dependencies: - vue-demi: 0.13.11_vue@3.2.45 + '@types/web-bluetooth': 0.0.16 + '@vueuse/metadata': 9.12.0 + '@vueuse/shared': 9.12.0_vue@3.2.47 + vue-demi: 0.13.6_vue@3.2.47 transitivePeerDependencies: - '@vue/composition-api' - vue dev: false - /@waline/client/2.14.1: - resolution: {integrity: sha512-JnZidLAbuv9yf/+6LvLyv0t6dMHniIuFImgt4npctdCtG6cWuwIr8chhnJg4egiO5iVjlYbZeZYYvhwtjtPxwQ==} + /@vueuse/metadata/9.10.0: + resolution: {integrity: sha512-G5VZhgTCapzU9rv0Iq2HBrVOSGzOKb+OE668NxhXNcTjUjwYxULkEhAw70FtRLMZc+hxcFAzDZlKYA0xcwNMuw==} + dev: false + + /@vueuse/metadata/9.12.0: + resolution: {integrity: sha512-9oJ9MM9lFLlmvxXUqsR1wLt1uF7EVbP5iYaHJYqk+G2PbMjY6EXvZeTjbdO89HgoF5cI6z49o2zT/jD9SVoNpQ==} + dev: false + + /@vueuse/shared/9.10.0_vue@3.2.47: + resolution: {integrity: sha512-vakHJ2ZRklAzqmcVBL38RS7BxdBA4+5poG9NsSyqJxrt9kz0zX3P5CXMy0Hm6LFbZXUgvKdqAS3pUH1zX/5qTQ==} + dependencies: + vue-demi: 0.13.6_vue@3.2.47 + transitivePeerDependencies: + - '@vue/composition-api' + - vue + dev: false + + /@vueuse/shared/9.12.0_vue@3.2.47: + resolution: {integrity: sha512-TWuJLACQ0BVithVTRbex4Wf1a1VaRuSpVeyEd4vMUWl54PzlE0ciFUshKCXnlLuD0lxIaLK4Ypj3NXYzZh4+SQ==} + dependencies: + vue-demi: 0.13.6_vue@3.2.47 + transitivePeerDependencies: + - '@vue/composition-api' + - vue + dev: false + + /@waline/client/2.14.7: + resolution: {integrity: sha512-hTfh2AbWQCX/oS4Hgr0W9cf79pHYf7X6Km5AcBDAmOL6AI7a5kP9qo9y2mcEzdfn9LK06P5Uuk8HY8vxQbgcrA==} engines: {node: '>=14'} dependencies: - '@vueuse/core': 9.6.0_vue@3.2.45 + '@vueuse/core': 9.12.0_vue@3.2.47 autosize: 5.0.2 - marked: 4.2.3 - vue: 3.2.45 + marked: 4.2.5 + vue: 3.2.47 transitivePeerDependencies: - '@vue/composition-api' dev: false @@ -3361,6 +3844,16 @@ packages: '@xtuc/long': 4.2.2 dev: false + /@windicss/config/1.8.10: + resolution: {integrity: sha512-O9SsC110b1Ik3YYa4Ck/0TWuCo7YFfA9KDrwD5sAeqscT5COIGK1HszdCT3oh0MJFej2wNrvpfyW9h6yQaW6PA==} + dependencies: + debug: 4.3.4 + jiti: 1.16.0 + windicss: 3.5.6 + transitivePeerDependencies: + - supports-color + dev: false + /@windicss/config/1.8.8: resolution: {integrity: sha512-kNas/zMkwsDFMcJPmHoPDJlQi1MHvYwx8BSxo9JKcbCW7Gaj8Rg2CnEImX5YdT+ZcFQqQ+kUn0Vi/ScsAxhGEw==} dependencies: @@ -3371,6 +3864,20 @@ packages: - supports-color dev: false + /@windicss/plugin-utils/1.8.10: + resolution: {integrity: sha512-Phqk5OW1w+Mv+ry6t7BzAeDq3aMhbI94gR49j9vQCufFfDGCHndhhjtMK0sBv+NPJUsIAIh6qayb1iwBCXUGrw==} + dependencies: + '@antfu/utils': 0.7.2 + '@windicss/config': 1.8.10 + debug: 4.3.4 + fast-glob: 3.2.12 + magic-string: 0.27.0 + micromatch: 4.0.5 + windicss: 3.5.6 + transitivePeerDependencies: + - supports-color + dev: false + /@windicss/plugin-utils/1.8.8: resolution: {integrity: sha512-a+npbTKmdrAvnMqzVJvyPa29xyNcPaSkt6qQpgWY9m0WyVlYd9BM8V0+cbqt279fTlvlaZpUs9dqmilB1PUH6g==} dependencies: @@ -3378,7 +3885,7 @@ packages: '@windicss/config': 1.8.8 debug: 4.3.4 fast-glob: 3.2.12 - magic-string: 0.26.7 + magic-string: 0.26.2 micromatch: 4.0.5 windicss: 3.5.6 transitivePeerDependencies: @@ -3399,7 +3906,6 @@ packages: dependencies: jsonparse: 1.3.1 through: 2.3.8 - dev: true /abbrev/1.1.1: resolution: {integrity: sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==} @@ -3409,6 +3915,17 @@ packages: engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} dev: true + /abort-controller/3.0.0: + resolution: {integrity: sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==} + engines: {node: '>=6.5'} + dependencies: + event-target-shim: 5.0.1 + dev: false + + /abstract-logging/2.0.1: + resolution: {integrity: sha512-2BjRTZxTPvheOvGbBslFSYOUkr+SjPtOnrLP33f+VIWLzezQpZcqVg7ja3L4dBXmzzgwT+a029jRx5PCi3JuiA==} + dev: false + /accepts/1.3.8: resolution: {integrity: sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==} engines: {node: '>= 0.6'} @@ -3444,7 +3961,6 @@ packages: /add-stream/1.0.0: resolution: {integrity: sha512-qQLMr+8o0WC4FZGQTcJiKBVC59JylcPSrTtk6usvmIDFUOCKegapy1VHQwRbFMOFyb/inzUVqHs+eMYKDM1YeQ==} - dev: true /agent-base/6.0.2: resolution: {integrity: sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==} @@ -3578,11 +4094,6 @@ packages: string-width: 4.2.3 dev: false - /ansi-colors/4.1.3: - resolution: {integrity: sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==} - engines: {node: '>=6'} - dev: false - /ansi-escapes/3.2.0: resolution: {integrity: sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ==} engines: {node: '>=4'} @@ -3607,11 +4118,6 @@ packages: hasBin: true dev: false - /ansi-regex/0.2.1: - resolution: {integrity: sha512-sGwIGMjhYdW26/IhwK2gkWWI8DRCVO6uj3hYgHT+zD+QL1pa37tM3ujhyfcJIYSbsxp7Gxhy7zrRW/1AHm4BmA==} - engines: {node: '>=0.10.0'} - dev: false - /ansi-regex/2.1.1: resolution: {integrity: sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==} engines: {node: '>=0.10.0'} @@ -3635,11 +4141,6 @@ packages: resolution: {integrity: sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==} engines: {node: '>=12'} - /ansi-styles/1.1.0: - resolution: {integrity: sha512-f2PKUkN5QngiSemowa6Mrk9MPCdtFiOSmibjZ+j1qhLGHHYsqZwmBMRF3IRMVXo8sybDqx2fJl2d/8OphBoWkA==} - engines: {node: '>=0.10.0'} - dev: false - /ansi-styles/2.2.1: resolution: {integrity: sha512-kmCevFghRiWM7HB5zTPULl4r9bVFSWjz62MhqizDGUrq2NWuNMQyuv4tHHoKJHs69M/MF64lEcHdYIocrdWQYA==} engines: {node: '>=0.10.0'} @@ -3751,6 +4252,10 @@ packages: zip-stream: 4.1.0 dev: false + /archy/1.0.0: + resolution: {integrity: sha512-Xg+9RwCg/0p32teKdGMPTPnVXKD0w3DfHnFTficozsAgsvq2XenPJq/MYpzzQ/v8zrOyJn6Ds39VA4JIDwFfqw==} + dev: false + /are-we-there-yet/2.0.0: resolution: {integrity: sha512-Ci/qENmwHnsYo9xKIcUJN5LeDKdJ6R1Z1j9V/J5wyq8nh/mYPEpIKJbBZXtZjG04HiK7zV/p6Vs9952MrMeUIw==} engines: {node: '>=10'} @@ -3808,7 +4313,6 @@ packages: /array-ify/1.0.0: resolution: {integrity: sha512-c5AMf34bKdvPhQ7tBGhqkgKNUzMr4WUs+WDtC2ZUGOUncbxKMTvqxYctiseW3+L4bA8ec+GcZ6/A/FW4m8ukng==} - dev: true /array-includes/3.1.6: resolution: {integrity: sha512-sgTbLvL6cNnw24FnbaDyjmvddQ2ML8arZsgaJhoABMoplz/4QRhtrYS+alr1BUM1Bwp6dhx8vVCBSLG+StwOFw==} @@ -3816,7 +4320,7 @@ packages: dependencies: call-bind: 1.0.2 define-properties: 1.1.4 - es-abstract: 1.20.4 + es-abstract: 1.20.5 get-intrinsic: 1.1.3 is-string: 1.0.7 dev: true @@ -3848,14 +4352,13 @@ packages: dependencies: call-bind: 1.0.2 define-properties: 1.1.4 - es-abstract: 1.20.4 + es-abstract: 1.20.5 es-shim-unscopables: 1.0.0 dev: true /arrify/1.0.1: resolution: {integrity: sha512-3CYzex9M9FGQjCGMGyi6/31c8GJbgb0qGyrx5HWxPd0aCwh4cB2YjMb2Xf9UuoogrMrlO9cTqnB5rI5GHZTcUA==} engines: {node: '>=0.10.0'} - dev: true /arrify/2.0.1: resolution: {integrity: sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug==} @@ -3925,7 +4428,12 @@ packages: hasBin: true dev: false - /autoprefixer/10.4.13_postcss@8.4.19: + /atomic-sleep/1.0.0: + resolution: {integrity: sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ==} + engines: {node: '>=8.0.0'} + dev: false + + /autoprefixer/10.4.13_postcss@8.4.20: resolution: {integrity: sha512-49vKpMqcZYsJjwotvt4+h/BCjJVnhGwcLpDt5xkcaOG3eLrG/HUYLagrihYsQ+qrIBgIzX1Rw7a6L8I/ZA1Atg==} engines: {node: ^10 || ^12 || >=14} hasBin: true @@ -3936,11 +4444,11 @@ packages: optional: true dependencies: browserslist: 4.21.4 - caniuse-lite: 1.0.30001434 + caniuse-lite: 1.0.30001441 fraction.js: 4.2.0 normalize-range: 0.1.2 picocolors: 1.0.0 - postcss: 8.4.19 + postcss: 8.4.20 postcss-value-parser: 4.2.0 dev: false @@ -3948,6 +4456,16 @@ packages: resolution: {integrity: sha512-FPVt5ynkqUAA9gcMZnJHka1XfQgr1WNd/yRfIjmj5WGmjua+u5Hl9hn8M2nU5CNy2bEIcj1ZUwXq7IOHsfZG9w==} dev: false + /avvio/8.2.0: + resolution: {integrity: sha512-bbCQdg7bpEv6kGH41RO/3B2/GMMmJSo2iBK+X8AWN9mujtfUipMDfIjsgHCfpnKqoGEQrrmCDKSa5OQ19+fDmg==} + dependencies: + archy: 1.0.0 + debug: 4.3.4 + fastq: 1.14.0 + transitivePeerDependencies: + - supports-color + dev: false + /backoff/2.5.0: resolution: {integrity: sha512-wC5ihrnUXmR2douXmXLCe5O3zg3GKIyvRi/hi58a/XyRxVI+3/yM0PYueQOZXPXQ9pxBislYkw+sF9b7C/RuMA==} engines: {node: '>= 0.6'} @@ -4005,6 +4523,20 @@ packages: leven: 3.1.0 dev: false + /better-ajv-errors/1.2.0_ajv@8.11.2: + resolution: {integrity: sha512-UW+IsFycygIo7bclP9h5ugkNH8EjCSgqyFB/yQ4Hqqa1OEYDtb0uFIkYE0b6+CjkgJYVM5UKI/pJPxjYe9EZlA==} + engines: {node: '>= 12.13.0'} + peerDependencies: + ajv: 4.11.8 - 8 + dependencies: + '@babel/code-frame': 7.18.6 + '@humanwhocodes/momoa': 2.0.4 + ajv: 8.11.2 + chalk: 4.1.2 + jsonpointer: 5.0.1 + leven: 3.1.0 + dev: false + /better-opn/3.0.2: resolution: {integrity: sha512-aVNobHnJqLiUelTaHat9DZ1qM2w0C0Eym4LPI/3JxOnSokGVdsl1T1kN7TFvsEAD8G47A6VKQ0TVHqbBnYMJlQ==} engines: {node: '>=12.0.0'} @@ -4072,8 +4604,12 @@ packages: - supports-color dev: false - /bonjour-service/1.0.14: - resolution: {integrity: sha512-HIMbgLnk1Vqvs6B4Wq5ep7mxvj9sGz5d1JJyDNSGNIdA/w2MCz6GTjWTdjqOJV1bEPj+6IkxDvWNFKEBxNt4kQ==} + /body-scroll-lock/4.0.0-beta.0: + resolution: {integrity: sha512-a7tP5+0Mw3YlUJcGAKUqIBkYYGlYxk2fnCasq/FUph1hadxlTRjF+gAcZksxANnaMnALjxEddmSi/H3OR8ugcQ==} + dev: false + + /bonjour-service/1.0.13: + resolution: {integrity: sha512-LWKRU/7EqDUC9CTAQtuZl5HzBALoCYwtLhffW3et7vZMwv3bWLpJf8bRYlMD5OCcDpTfnPgNCV4yo9ZIaJGMiA==} dependencies: array-flatten: 2.1.2 dns-equal: 1.0.0 @@ -4098,16 +4634,16 @@ packages: wrap-ansi: 7.0.0 dev: false - /boxen/7.0.0: - resolution: {integrity: sha512-j//dBVuyacJbvW+tvZ9HuH03fZ46QcaKvvhZickZqtB271DxJ7SNRSNxrV/dZX0085m7hISRZWbzWlJvx/rHSg==} + /boxen/7.0.1: + resolution: {integrity: sha512-8k2eH6SRAK00NDl1iX5q17RJ8rfl53TajdYxE3ssMLehbg487dEVgsad4pIsZb/QqBgYWIl6JOauMTLGX2Kpkw==} engines: {node: '>=14.16'} dependencies: ansi-align: 3.0.1 - camelcase: 7.0.0 - chalk: 5.1.2 + camelcase: 7.0.1 + chalk: 5.2.0 cli-boxes: 3.0.0 string-width: 5.1.2 - type-fest: 2.19.0 + type-fest: 2.18.0 widest-line: 4.0.1 wrap-ansi: 8.0.1 dev: false @@ -4170,7 +4706,7 @@ packages: engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} hasBin: true dependencies: - caniuse-lite: 1.0.30001434 + caniuse-lite: 1.0.30001441 electron-to-chromium: 1.4.284 node-releases: 2.0.6 update-browserslist-db: 1.0.10_browserslist@4.21.4 @@ -4236,7 +4772,6 @@ packages: kleur: 4.1.5 prompts: 2.4.2 semver: 7.3.8 - dev: true /byline/5.0.0: resolution: {integrity: sha512-s6webAy+R4SR8XVuJWt2V2rGvhnrhxN+9S15GNuTK3wKPOXFF6RNc+8ug2XhH+2s4f+uudG4kUVYmYOQWL2g0Q==} @@ -4284,7 +4819,7 @@ packages: promise-inflight: 1.0.1 rimraf: 3.0.2 ssri: 9.0.1 - tar: 6.1.12 + tar: 6.1.13 unique-filename: 2.0.1 transitivePeerDependencies: - bluebird @@ -4318,11 +4853,10 @@ packages: engines: {node: '>=14.16'} dev: false - /cacheable-request/10.2.3: - resolution: {integrity: sha512-6BehRBOs7iurNjAYN9iPazTwFDaMQavJO8W1MEm3s2pH8q/tkPTtLDRUZaweWK87WFGf2Y5wLAlaCJlR5kOz3w==} + /cacheable-request/10.2.4: + resolution: {integrity: sha512-IWIea8ei1Ht4dBqvlvh7Gs7EYlMyBhlJybLDUB9sadEqHqftmdNieMLIR5ia3vs8gbjj9t8hXLBpUVg3vcQNbg==} engines: {node: '>=14.16'} dependencies: - '@types/http-cache-semantics': 4.0.1 get-stream: 6.0.1 http-cache-semantics: 4.1.0 keyv: 4.5.2 @@ -4404,7 +4938,6 @@ packages: camelcase: 5.3.1 map-obj: 4.3.0 quick-lru: 4.0.1 - dev: true /camelcase/2.1.1: resolution: {integrity: sha512-DLIsRzJVBQu72meAKPkWQOLcujdXT32hwdfnkI1frSiSRMK1MofjKHf+MEx0SB6fjEFXL8fBDv1dKymBlOp4Qw==} @@ -4420,24 +4953,13 @@ packages: engines: {node: '>=10'} dev: false - /camelcase/7.0.0: - resolution: {integrity: sha512-JToIvOmz6nhGsUhAYScbo2d6Py5wojjNfoxoc2mEVLUdJ70gJK2gnd+ABY1Tc3sVMyK7QDPtN0T/XdlCQWITyQ==} + /camelcase/7.0.1: + resolution: {integrity: sha512-xlx1yCK2Oc1APsPXDL2LdlNP6+uu8OCDdhOBSVT279M/S+y75O30C2VuD8T2ogdePBBl7PfPF4504tnLgX3zfw==} engines: {node: '>=14.16'} dev: false - /caniuse-lite/1.0.30001434: - resolution: {integrity: sha512-aOBHrLmTQw//WFa2rcF1If9fa3ypkC1wzqqiKHgfdrXTWcU8C4gKVZT77eQAPWN1APys3+uQ0Df07rKauXGEYA==} - dev: false - - /chalk/0.5.1: - resolution: {integrity: sha512-bIKA54hP8iZhyDT81TOsJiQvR1gW+ZYSXFaZUAvoD4wCHdbHY2actmpTE4x344ZlFqHbvoxKOaESULTZN2gstg==} - engines: {node: '>=0.10.0'} - dependencies: - ansi-styles: 1.1.0 - escape-string-regexp: 1.0.5 - has-ansi: 0.1.0 - strip-ansi: 0.3.0 - supports-color: 0.2.0 + /caniuse-lite/1.0.30001441: + resolution: {integrity: sha512-OyxRR4Vof59I3yGWXws6i908EtGbMzVUi3ganaZQHmydk1iwDhRnvaPG2WaR0KcqrDFKrxVZHULT396LEPhXfg==} dev: false /chalk/1.1.3: @@ -4474,8 +4996,8 @@ packages: ansi-styles: 4.3.0 supports-color: 7.2.0 - /chalk/5.1.2: - resolution: {integrity: sha512-E5CkT4jWURs1Vy5qGJye+XwCkNj7Od3Af7CP6SujMetSMkLs8Do2RWJK5yx1wamHV/op8Rz+9rltjaTQWDnEFQ==} + /chalk/5.2.0: + resolution: {integrity: sha512-ree3Gqw/nazQAPuJJEy+avdl7QfZMcUvmHIKgEZkGL+xOBzRvup5Hxo6LHuMceSxOabuJLJm5Yp/92R9eMmMvA==} engines: {node: ^12.17.0 || ^14.13 || >=16.0.0} /chardet/0.7.0: @@ -4485,31 +5007,35 @@ packages: resolution: {integrity: sha1-wKHS86cJLgN3S/qD8UwPxXkKhmc=} dev: false - /chart.js/3.9.1: - resolution: {integrity: sha512-Ro2JbLmvg83gXF5F4sniaQ+lTbSv18E+TIf2cOeiH1Iqd2PGFOtem+DUufMZsCJwFE7ywPOpfXFBwRTGq7dh6w==} + /chart.js/4.2.0: + resolution: {integrity: sha512-wbtcV+QKeH0F7gQZaCJEIpsNriFheacouJQTVIjITi3eQA8bTlIBoknz0+dgV79aeKLNMAX+nDslIVE/nJ3rzA==} + engines: {pnpm: ^7.0.0} + dependencies: + '@kurkle/color': 0.3.1 dev: false - /cheerio-select/1.6.0: - resolution: {integrity: sha512-eq0GdBvxVFbqWgmCm7M3XGs1I8oLy/nExUnh6oLqmBditPO9AqQJrkslDpMun/hZ0yyTs8L0m85OHp4ho6Qm9g==} + /cheerio-select/2.1.0: + resolution: {integrity: sha512-9v9kG0LvzrlcungtnJtpGNxY+fzECQKhK4EGJX2vByejiMX84MFNQw4UxPJl3bFbTMw+Dfs37XaIkCwTZfLh4g==} dependencies: - css-select: 4.3.0 + boolbase: 1.0.0 + css-select: 5.1.0 css-what: 6.1.0 domelementtype: 2.3.0 - domhandler: 4.3.1 - domutils: 2.8.0 + domhandler: 5.0.3 + domutils: 3.0.1 dev: false - /cheerio/1.0.0-rc.10: - resolution: {integrity: sha512-g0J0q/O6mW8z5zxQ3A8E8J1hUgp4SMOvEoW/x84OwyHKe/Zccz83PVT4y5Crcr530FV6NgmKI1qvGTKVl9XXVw==} + /cheerio/1.0.0-rc.12: + resolution: {integrity: sha512-VqR8m68vM46BNnuZ5NtnGBKIE/DfN0cRIzg9n40EIq9NOv90ayxLBXA8fXC5gquFRGJSTRqBq25Jt2ECLR431Q==} engines: {node: '>= 6'} dependencies: - cheerio-select: 1.6.0 - dom-serializer: 1.4.1 - domhandler: 4.3.1 - htmlparser2: 6.1.0 - parse5: 6.0.1 - parse5-htmlparser2-tree-adapter: 6.0.1 - tslib: 2.4.1 + cheerio-select: 2.1.0 + dom-serializer: 2.0.0 + domhandler: 5.0.3 + domutils: 3.0.1 + htmlparser2: 8.0.1 + parse5: 7.1.2 + parse5-htmlparser2-tree-adapter: 7.0.0 dev: false /chokidar/3.5.3: @@ -4679,6 +5205,14 @@ packages: strip-ansi: 6.0.1 wrap-ansi: 7.0.0 + /cliui/8.0.1: + resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==} + engines: {node: '>=12'} + dependencies: + string-width: 4.2.3 + strip-ansi: 6.0.1 + wrap-ansi: 7.0.0 + /clone-deep/4.0.1: resolution: {integrity: sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==} engines: {node: '>=6'} @@ -4759,7 +5293,7 @@ packages: resolution: {integrity: sha512-DP3FpjsiDDvnQC1OJBsdOJZPuy7r0o6sepY2T5M3L/d2nrE23O/ErFkEqyY3ngVL1ZhTj/H0pCMNObZGkEOaaQ==} engines: {node: '>=12.20.0'} dependencies: - chalk: 5.1.2 + chalk: 5.2.0 filter-obj: 3.0.0 is-plain-obj: 4.1.0 jest-validate: 27.5.1 @@ -4793,11 +5327,6 @@ packages: resolution: {integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==} dev: false - /commander/6.2.1: - resolution: {integrity: sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA==} - engines: {node: '>= 6'} - dev: false - /commander/7.2.0: resolution: {integrity: sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==} engines: {node: '>= 10'} @@ -4817,8 +5346,8 @@ packages: resolution: {integrity: sha512-5EEkTNyHNGFPD2H+c/dXXfQZYa/scCKasxWcXJaWnNJ99pnQN9Vnmqow+p+PlFPE63Q6mThaZws1T+HxfpgtPw==} engines: {node: ^12.20.0 || >=14} - /commitizen/4.2.5: - resolution: {integrity: sha512-9sXju8Qrz1B4Tw7kC5KhnvwYQN88qs2zbiB8oyMsnXZyJ24PPGiNM3nHr73d32dnE3i8VJEXddBFIbOgYSEXtQ==} + /commitizen/4.2.6: + resolution: {integrity: sha512-RyTM+EiD9GO01DJUn9MRRAet3XUHGfoUZoksLfr+1ym1Xt2q5EYJs9Fg2BtKSb5Mo53i0BtMBmWMHQXVlZ/L9w==} engines: {node: '>= 12'} hasBin: true dependencies: @@ -4850,7 +5379,6 @@ packages: dependencies: array-ify: 1.0.0 dot-prop: 5.3.0 - dev: true /component-emitter/1.3.0: resolution: {integrity: sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==} @@ -4913,7 +5441,7 @@ packages: chalk: 4.1.2 date-fns: 2.29.3 lodash: 4.17.21 - rxjs: 7.5.7 + rxjs: 7.8.0 shell-quote: 1.7.4 spawn-command: 0.0.2-1 supports-color: 8.1.1 @@ -4994,14 +5522,12 @@ packages: dependencies: compare-func: 2.0.0 q: 1.5.1 - dev: true /conventional-changelog-atom/2.0.8: resolution: {integrity: sha512-xo6v46icsFTK3bb7dY/8m2qvc8sZemRgdqLb/bjpBsH2UyOS8rKNTgcb5025Hri6IpANPApbXMg15QLb1LJpBw==} engines: {node: '>=10'} dependencies: q: 1.5.1 - dev: true /conventional-changelog-cli/2.2.2: resolution: {integrity: sha512-8grMV5Jo8S0kP3yoMeJxV2P5R6VJOqK72IiSV9t/4H5r/HiRqEBQ83bYGuz4Yzfdj4bjaAEhZN/FFbsFXr5bOA==} @@ -5013,14 +5539,12 @@ packages: lodash: 4.17.21 meow: 8.1.2 tempfile: 3.0.0 - dev: true /conventional-changelog-codemirror/2.0.8: resolution: {integrity: sha512-z5DAsn3uj1Vfp7po3gpt2Boc+Bdwmw2++ZHa5Ak9k0UKsYAO5mH1UBTN0qSCuJZREIhX6WU4E1p3IW2oRCNzQw==} engines: {node: '>=10'} dependencies: q: 1.5.1 - dev: true /conventional-changelog-conventionalcommits/4.6.3: resolution: {integrity: sha512-LTTQV4fwOM4oLPad317V/QNQ1FY4Hju5qeBIM1uTHbrnCE+Eg4CdRZ3gO2pUeR+tzWdp80M2j3qFFEDWVqOV4g==} @@ -5029,7 +5553,6 @@ packages: compare-func: 2.0.0 lodash: 4.17.21 q: 1.5.1 - dev: true /conventional-changelog-conventionalcommits/5.0.0: resolution: {integrity: sha512-lCDbA+ZqVFQGUj7h9QBKoIpLhl8iihkO0nCTyRNzuXtcd7ubODpYB04IFy31JloiJgG0Uovu8ot8oxRzn7Nwtw==} @@ -5058,35 +5581,30 @@ packages: read-pkg: 3.0.0 read-pkg-up: 3.0.0 through2: 4.0.2 - dev: true /conventional-changelog-ember/2.0.9: resolution: {integrity: sha512-ulzIReoZEvZCBDhcNYfDIsLTHzYHc7awh+eI44ZtV5cx6LVxLlVtEmcO+2/kGIHGtw+qVabJYjdI5cJOQgXh1A==} engines: {node: '>=10'} dependencies: q: 1.5.1 - dev: true /conventional-changelog-eslint/3.0.9: resolution: {integrity: sha512-6NpUCMgU8qmWmyAMSZO5NrRd7rTgErjrm4VASam2u5jrZS0n38V7Y9CzTtLT2qwz5xEChDR4BduoWIr8TfwvXA==} engines: {node: '>=10'} dependencies: q: 1.5.1 - dev: true /conventional-changelog-express/2.0.6: resolution: {integrity: sha512-SDez2f3iVJw6V563O3pRtNwXtQaSmEfTCaTBPCqn0oG0mfkq0rX4hHBq5P7De2MncoRixrALj3u3oQsNK+Q0pQ==} engines: {node: '>=10'} dependencies: q: 1.5.1 - dev: true /conventional-changelog-jquery/3.0.11: resolution: {integrity: sha512-x8AWz5/Td55F7+o/9LQ6cQIPwrCjfJQ5Zmfqi8thwUEKHstEn4kTIofXub7plf1xvFA2TqhZlq7fy5OmV6BOMw==} engines: {node: '>=10'} dependencies: q: 1.5.1 - dev: true /conventional-changelog-jshint/2.0.9: resolution: {integrity: sha512-wMLdaIzq6TNnMHMy31hql02OEQ8nCQfExw1SE0hYL5KvU+JCTuPaDO+7JiogGT2gJAxiUGATdtYYfh+nT+6riA==} @@ -5094,12 +5612,10 @@ packages: dependencies: compare-func: 2.0.0 q: 1.5.1 - dev: true /conventional-changelog-preset-loader/2.3.4: resolution: {integrity: sha512-GEKRWkrSAZeTq5+YjUZOYxdHq+ci4dNwHvpaBC3+ENalzFWuCWa9EZXSuZBpkr72sMdKB+1fyDV4takK1Lf58g==} engines: {node: '>=10'} - dev: true /conventional-changelog-writer/5.0.1: resolution: {integrity: sha512-5WsuKUfxW7suLblAbFnxAcrvf6r+0b7GvNaWUwUIk0bXMnENP/PEieGKVUQrjPqwPT4o3EPAASBXiY6iHooLOQ==} @@ -5115,7 +5631,6 @@ packages: semver: 6.3.0 split: 1.0.1 through2: 4.0.2 - dev: true /conventional-changelog/3.1.25: resolution: {integrity: sha512-ryhi3fd1mKf3fSjbLXOfK2D06YwKNic1nC9mWqybBHdObPd8KJ2vjaXZfYj1U23t+V8T8n0d7gwnc9XbIdFbyQ==} @@ -5132,7 +5647,6 @@ packages: conventional-changelog-jquery: 3.0.11 conventional-changelog-jshint: 2.0.9 conventional-changelog-preset-loader: 2.3.4 - dev: true /conventional-commit-types/3.0.0: resolution: {integrity: sha512-SmmCYnOniSsAa9GqWOeLqc179lfr5TRu5b4QFDkbsrJ5TZjPJx85wtOr3zn+1dbeNiXDKGPbZ72IKbPhLXh/Lg==} @@ -5144,7 +5658,6 @@ packages: dependencies: lodash.ismatch: 4.4.0 modify-values: 1.0.1 - dev: true /conventional-commits-parser/3.2.4: resolution: {integrity: sha512-nK7sAtfi+QXbxHCYfhpZsfRtaitZLIA6889kFIouLvz6repszQDgxBu7wf2WbU+Dco7sAnNCJYERCwt54WPC2Q==} @@ -5157,7 +5670,6 @@ packages: meow: 8.1.2 split2: 3.2.2 through2: 4.0.2 - dev: true /convert-source-map/1.9.0: resolution: {integrity: sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==} @@ -5208,7 +5720,7 @@ packages: dependencies: fast-glob: 3.2.12 glob-parent: 6.0.2 - globby: 13.1.2 + globby: 13.1.3 normalize-path: 3.0.0 schema-utils: 4.0.0 serialize-javascript: 6.0.0 @@ -5223,8 +5735,20 @@ packages: /core-util-is/1.0.3: resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==} - /cosmiconfig-typescript-loader/4.2.0_qoh33be55smklb2oyrgdyddh4a: - resolution: {integrity: sha512-NkANeMnaHrlaSSlpKGyvn2R4rqUDeE/9E5YHx+b4nwo0R8dZyAqcih8/gxpCZvqWP9Vf6xuLpMSzSgdVEIM78g==} + /cose-base/1.0.3: + resolution: {integrity: sha512-s9whTXInMSgAp/NVXVNuVxVKzGH2qck3aQlVHxDCdAEPgtMKwc4Wq6/QKhgdEdgbLSi9rBTAcPoRa6JpiG4ksg==} + dependencies: + layout-base: 1.0.2 + dev: false + + /cose-base/2.1.0: + resolution: {integrity: sha512-HTMm07dhxq1dIPGWwpiVrIk9n+DH7KYmqWA786mLe8jDS+1ZjGtJGIIsJVKoseZXS6/FxiUWCJ2B7XzqUCuhPw==} + dependencies: + layout-base: 2.0.1 + dev: false + + /cosmiconfig-typescript-loader/4.3.0_bxtyj3et3xbsdyxhh3oblnfbj4: + resolution: {integrity: sha512-NTxV1MFfZDLPiBMjxbHRwSh5LaLcPMwNdCutmnHJCKoVnlvldPWlllonKwrsRJ5pYZBIBGRWWU2tfvzxgeSW5Q==} engines: {node: '>=12', npm: '>=6'} peerDependencies: '@types/node': '*' @@ -5232,10 +5756,10 @@ packages: ts-node: '>=10' typescript: '>=3' dependencies: - '@types/node': 14.18.33 - cosmiconfig: 7.1.0 - ts-node: 10.9.1_kluoused5zacjtflizwvdqgpom - typescript: 4.9.3 + '@types/node': 18.11.18 + cosmiconfig: 8.0.0 + ts-node: 10.9.1_awa2wsr5thmg3i7jqycphctjfq + typescript: 4.9.4 dev: true /cosmiconfig/7.1.0: @@ -5247,6 +5771,26 @@ packages: parse-json: 5.2.0 path-type: 4.0.0 yaml: 1.10.2 + dev: false + + /cosmiconfig/8.0.0: + resolution: {integrity: sha512-da1EafcpH6b/TD8vDRaWV7xFINlHlF6zKsGwS1TsuVJTZRkquaS5HTMq7uq6h31619QjbsYl21gVDOm32KM1vQ==} + engines: {node: '>=14'} + dependencies: + import-fresh: 3.3.0 + js-yaml: 4.1.0 + parse-json: 5.2.0 + path-type: 4.0.0 + dev: true + + /cp-file/10.0.0: + resolution: {integrity: sha512-vy2Vi1r2epK5WqxOLnskeKeZkdZvTKfFZQCplE3XWsP+SUJyd5XAUFC9lFgTjjXJF2GMne/UML14iEmkAaDfFg==} + engines: {node: '>=14.16'} + dependencies: + graceful-fs: 4.2.10 + nested-error-stacks: 2.1.1 + p-event: 5.0.1 + dev: false /cp-file/10.0.0: resolution: {integrity: sha512-vy2Vi1r2epK5WqxOLnskeKeZkdZvTKfFZQCplE3XWsP+SUJyd5XAUFC9lFgTjjXJF2GMne/UML14iEmkAaDfFg==} @@ -5267,16 +5811,6 @@ packages: p-event: 4.2.0 dev: false - /cp-file/9.1.0: - resolution: {integrity: sha512-3scnzFj/94eb7y4wyXRWwvzLFaQp87yyfTnChIjlfYrVqp5lVO3E2hIJMeQIltUT0K2ZAB3An1qXcBmwGyvuwA==} - engines: {node: '>=10'} - dependencies: - graceful-fs: 4.2.10 - make-dir: 3.1.0 - nested-error-stacks: 2.1.1 - p-event: 4.2.0 - dev: false - /cpx2/4.2.0: resolution: {integrity: sha512-Ik81d7J849x0dGpR/8TBLXc1MwkFuv29kkstgLau8IOQwptrEENsXefC4o+tnkTjiFnXbsaz08/6YSZdJER+nQ==} engines: {node: '>=14'} @@ -5288,7 +5822,7 @@ packages: fs-extra: 10.1.0 glob-gitignore: 1.0.14 glob2base: 0.0.12 - ignore: 5.2.1 + ignore: 5.2.4 minimatch: 3.1.2 p-map: 4.0.0 resolve: 1.22.1 @@ -5329,6 +5863,14 @@ packages: readable-stream: 3.6.0 dev: false + /create-filter/1.0.0: + resolution: {integrity: sha512-GILntrcuvYbSs9LYP3dc5muWQFG/fBdrl/fUVr1Wexug94FwSQ+Ua5HCqp+ikTTi1+aaUgjQby3eXEHYauwNIQ==} + dependencies: + bumpp: 8.2.1 + conventional-changelog-cli: 2.2.2 + picomatch: 2.3.1 + dev: false + /create-require/1.1.1: resolution: {integrity: sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==} @@ -5371,8 +5913,8 @@ packages: type-fest: 1.4.0 dev: false - /css-loader/6.7.2_webpack@5.75.0: - resolution: {integrity: sha512-oqGbbVcBJkm8QwmnNzrFrWTnudnRZC+1eXikLJl0n4ljcfotgRifpg2a1lKy8jTrc4/d9A/ap1GFq1jDKG7J+Q==} + /css-loader/6.7.3_webpack@5.75.0: + resolution: {integrity: sha512-qhOH1KlBMnZP8FzRO6YCH9UHXQhVMcEGLyNdb7Hv2cpcmJbW0YrddO+tG1ab5nT41KpHIYGsbeHqxB9xPu1pKQ==} engines: {node: '>= 12.13.0'} peerDependencies: webpack: ^5.0.0 @@ -5380,12 +5922,12 @@ packages: webpack: optional: true dependencies: - icss-utils: 5.1.0_postcss@8.4.19 - postcss: 8.4.19 - postcss-modules-extract-imports: 3.0.0_postcss@8.4.19 - postcss-modules-local-by-default: 4.0.0_postcss@8.4.19 - postcss-modules-scope: 3.0.0_postcss@8.4.19 - postcss-modules-values: 4.0.0_postcss@8.4.19 + icss-utils: 5.1.0_postcss@8.4.20 + postcss: 8.4.20 + postcss-modules-extract-imports: 3.0.0_postcss@8.4.20 + postcss-modules-local-by-default: 4.0.0_postcss@8.4.20 + postcss-modules-scope: 3.0.0_postcss@8.4.20 + postcss-modules-values: 4.0.0_postcss@8.4.20 postcss-value-parser: 4.2.0 semver: 7.3.8 webpack: 5.75.0 @@ -5401,6 +5943,16 @@ packages: nth-check: 2.1.1 dev: false + /css-select/5.1.0: + resolution: {integrity: sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg==} + dependencies: + boolbase: 1.0.0 + css-what: 6.1.0 + domhandler: 5.0.3 + domutils: 3.0.1 + nth-check: 2.1.1 + dev: false + /css-tree/2.2.1: resolution: {integrity: sha512-OA0mILzGc1kCOCSJerOeqDxDQ4HOh+G8NbOJFOTgOCzpw7fCBubk0fEyxp8AgOL/jvLgYA/uV0cMbe43ElF1JA==} engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0, npm: '>=7.0.0'} @@ -5434,27 +5986,49 @@ packages: resolution: {integrity: sha512-NJGVKPS81XejHcLhaLJS7plab0fK3slPh11mESeeDq2W4ZI5kUKK/LRRdVDvjJseojbPB7ZwjnyOybg3Igea/A==} dev: false + /cytoscape-cose-bilkent/4.1.0_cytoscape@3.23.0: + resolution: {integrity: sha512-wgQlVIUJF13Quxiv5e1gstZ08rnZj2XaLHGoFMYXz7SkNfCDOOteKBE6SYRfA9WxxI/iBc3ajfDoc6hb/MRAHQ==} + peerDependencies: + cytoscape: ^3.2.0 + dependencies: + cose-base: 1.0.3 + cytoscape: 3.23.0 + dev: false + + /cytoscape-fcose/2.1.0_cytoscape@3.23.0: + resolution: {integrity: sha512-Q3apPl66jf8/2sMsrCjNP247nbDkyIPjA9g5iPMMWNLZgP3/mn9aryF7EFY/oRPEpv7bKJ4jYmCoU5r5/qAc1Q==} + peerDependencies: + cytoscape: ^3.2.0 + dependencies: + cose-base: 2.1.0 + cytoscape: 3.23.0 + dev: false + + /cytoscape/3.23.0: + resolution: {integrity: sha512-gRZqJj/1kiAVPkrVFvz/GccxsXhF3Qwpptl32gKKypO4IlqnKBjTOu+HbXtEggSGzC5KCaHp3/F7GgENrtsFkA==} + engines: {node: '>=0.10'} + dependencies: + heap: 0.2.7 + lodash: 4.17.21 + dev: false + /cz-conventional-changelog/3.3.0: resolution: {integrity: sha512-U466fIzU5U22eES5lTNiNbZ+d8dfcHcssH4o7QsdWaCcRs/feIPCxKYSWkYBNs5mny7MvEfwpTLWjvbm94hecw==} engines: {node: '>= 10'} dependencies: chalk: 2.4.2 - commitizen: 4.2.5 + commitizen: 4.2.6 conventional-commit-types: 3.0.0 lodash.map: 4.6.0 longest: 2.0.1 word-wrap: 1.2.3 optionalDependencies: - '@commitlint/load': 17.3.0 + '@commitlint/load': 17.4.2 transitivePeerDependencies: - '@swc/core' - '@swc/wasm' dev: true - /d3-array/1.2.4: - resolution: {integrity: sha512-KHW6M86R+FUPYGb3R5XiYjXPq7VzwxZ22buHhAEVG5ztoEcZZMLov530mmccaqA1GghZArjQV46fuc8kUqhhHw==} - dev: false - /d3-array/3.2.0: resolution: {integrity: sha512-3yXFQo0oG3QCxbF06rMPFyGRMGJNS7NvsV1+2joOjbBE+9xvWQ8+GcMJAjRCzw06zQ3/arXeJgbPYcjUCuC+3g==} engines: {node: '>=12'} @@ -5462,25 +6036,11 @@ packages: internmap: 2.0.3 dev: false - /d3-axis/1.0.12: - resolution: {integrity: sha512-ejINPfPSNdGFKEOAtnBtdkpr24c4d4jsei6Lg98mxf424ivoDP2956/5HDpIAtmHo85lqT4pruy+zEgvRUBqaQ==} - dev: false - /d3-axis/3.0.0: resolution: {integrity: sha512-IH5tgjV4jE/GhHkRV0HiVYPDtvfjHQlQfJHs0usq7M30XcSBvOotpmH1IgkcXsO/5gEQZD43B//fc7SRT5S+xw==} engines: {node: '>=12'} dev: false - /d3-brush/1.1.6: - resolution: {integrity: sha512-7RW+w7HfMCPyZLifTz/UnJmI5kdkXtpCbombUSs8xniAyo0vIbrDzDwUJB6eJOgl9u5DQOt2TQlYumxzD1SvYA==} - dependencies: - d3-dispatch: 1.0.6 - d3-drag: 1.2.5 - d3-interpolate: 1.4.0 - d3-selection: 1.4.2 - d3-transition: 1.3.2 - dev: false - /d3-brush/3.0.0: resolution: {integrity: sha512-ALnjWlVYkXsVIGlOsuWH1+3udkYFI48Ljihfnh8FZPF2QS9o+PzGLBslO0PjzVoHLZ2KCVgAM8NVkXPJB2aNnQ==} engines: {node: '>=12'} @@ -5492,13 +6052,6 @@ packages: d3-transition: 3.0.1_d3-selection@3.0.0 dev: false - /d3-chord/1.0.6: - resolution: {integrity: sha512-JXA2Dro1Fxw9rJe33Uv+Ckr5IrAa74TlfDEhE/jfLOaXegMQFQTAgAw9WnZL8+HxVBRXaRGCkrNU7pJeylRIuA==} - dependencies: - d3-array: 1.2.4 - d3-path: 1.0.9 - dev: false - /d3-chord/3.0.1: resolution: {integrity: sha512-VE5S6TNa+j8msksl7HwjxMHDM2yNK3XCkusIlpX5kwauBfXuyLAtNg9jCp/iHH61tgI4sb6R/EIMWCqEIdjT/g==} engines: {node: '>=12'} @@ -5506,25 +6059,11 @@ packages: d3-path: 3.0.1 dev: false - /d3-collection/1.0.7: - resolution: {integrity: sha512-ii0/r5f4sjKNTfh84Di+DpztYwqKhEyUlKoPrzUFfeSkWxjW49xU2QzO9qrPrNkpdI0XJkfzvmTu8V2Zylln6A==} - dev: false - - /d3-color/1.4.1: - resolution: {integrity: sha512-p2sTHSLCJI2QKunbGb7ocOh7DgTAn8IrLx21QRc/BSnodXM4sv6aLQlnfpvehFMLZEfBc6g9pH9SWQccFYfJ9Q==} - dev: false - /d3-color/3.1.0: resolution: {integrity: sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==} engines: {node: '>=12'} dev: false - /d3-contour/1.3.2: - resolution: {integrity: sha512-hoPp4K/rJCu0ladiH6zmJUEz6+u3lgR+GSm/QdM2BBvDraU39Vr7YdDCicJcxP1z8i9B/2dJLgDC1NcvlF8WCg==} - dependencies: - d3-array: 1.2.4 - dev: false - /d3-contour/4.0.0: resolution: {integrity: sha512-7aQo0QHUTu/Ko3cP9YK9yUTxtoDEiDGwnBHyLxG5M4vqlBkO/uixMRele3nfsfj6UXOcuReVpVXzAboGraYIJw==} engines: {node: '>=12'} @@ -5539,22 +6078,11 @@ packages: delaunator: 5.0.0 dev: false - /d3-dispatch/1.0.6: - resolution: {integrity: sha512-fVjoElzjhCEy+Hbn8KygnmMS7Or0a9sI2UzGwoB7cCtvI1XpVN9GpoYlnb3xt2YV66oXYb1fLJ8GMvP4hdU1RA==} - dev: false - /d3-dispatch/3.0.1: resolution: {integrity: sha512-rzUyPU/S7rwUflMyLc1ETDeBj0NRuHKKAcvukozwhshr6g6c5d8zh4c2gQjY2bZ0dXeGLWc1PF174P2tVvKhfg==} engines: {node: '>=12'} dev: false - /d3-drag/1.2.5: - resolution: {integrity: sha512-rD1ohlkKQwMZYkQlYVCrSFxsWPzI97+W+PaEIBNTMxRuxz9RF0Hi5nJWHGVJ3Om9d2fRTe1yOBINJyy/ahV95w==} - dependencies: - d3-dispatch: 1.0.6 - d3-selection: 1.4.2 - dev: false - /d3-drag/3.0.0: resolution: {integrity: sha512-pWbUJLdETVA8lQNJecMxoXfH6x+mO2UQo8rSmZ+QqxcbyA3hfeprFgIT//HW2nlHChWeIIMwS2Fq+gEARkhTkg==} engines: {node: '>=12'} @@ -5563,15 +6091,6 @@ packages: d3-selection: 3.0.0 dev: false - /d3-dsv/1.2.0: - resolution: {integrity: sha512-9yVlqvZcSOMhCYzniHE7EVUws7Fa1zgw+/EAV2BxJoG3ME19V6BQFBwI855XQDsxyOuG7NibqRMTtiF/Qup46g==} - hasBin: true - dependencies: - commander: 2.20.3 - iconv-lite: 0.4.24 - rw: 1.3.3 - dev: false - /d3-dsv/3.0.1: resolution: {integrity: sha512-UG6OvdI5afDIFP9w4G0mNq50dSOsXHJaRE8arAS5o9ApWnIElp8GZw1Dun8vP8OyHOZ/QJUKUJwxiiCCnUwm+Q==} engines: {node: '>=12'} @@ -5582,21 +6101,11 @@ packages: rw: 1.3.3 dev: false - /d3-ease/1.0.7: - resolution: {integrity: sha512-lx14ZPYkhNx0s/2HX5sLFUI3mbasHjSSpwO/KaaNACweVwxUruKyWVcb293wMv1RqTPZyZ8kSZ2NogUZNcLOFQ==} - dev: false - /d3-ease/3.0.1: resolution: {integrity: sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==} engines: {node: '>=12'} dev: false - /d3-fetch/1.2.0: - resolution: {integrity: sha512-yC78NBVcd2zFAyR/HnUiBS7Lf6inSCoWcSxFfw8FYL7ydiqe80SazNwoffcqOfs95XaLo7yebsmQqDKSsXUtvA==} - dependencies: - d3-dsv: 1.2.0 - dev: false - /d3-fetch/3.0.1: resolution: {integrity: sha512-kpkQIM20n3oLVBKGg6oHrUchHM3xODkTzjMoj7aWQFq5QEM+R6E4WkzT5+tojDY7yjez8KgCBRoj4aEr99Fdqw==} engines: {node: '>=12'} @@ -5604,15 +6113,6 @@ packages: d3-dsv: 3.0.1 dev: false - /d3-force/1.2.1: - resolution: {integrity: sha512-HHvehyaiUlVo5CxBJ0yF/xny4xoaxFxDnBXNvNcfW9adORGZfyNF1dj6DGLKyk4Yh3brP/1h3rnDzdIAwL08zg==} - dependencies: - d3-collection: 1.0.7 - d3-dispatch: 1.0.6 - d3-quadtree: 1.0.7 - d3-timer: 1.0.10 - dev: false - /d3-force/3.0.0: resolution: {integrity: sha512-zxV/SsA+U4yte8051P4ECydjD/S+qeYtnaIyAs9tgHCqfguma/aAQDjo85A9Z6EKhBirHRJHXIgJUlffT4wdLg==} engines: {node: '>=12'} @@ -5622,21 +6122,11 @@ packages: d3-timer: 3.0.1 dev: false - /d3-format/1.4.5: - resolution: {integrity: sha512-J0piedu6Z8iB6TbIGfZgDzfXxUFN3qQRMofy2oPdXzQibYGqPB/9iMcxr/TGalU+2RsyDO+U4f33id8tbnSRMQ==} - dev: false - /d3-format/3.1.0: resolution: {integrity: sha512-YyUI6AEuY/Wpt8KWLgZHsIU86atmikuoOmCfommt0LYHiQSPjvX2AcFc38PX0CBpr2RCyZhjex+NS/LPOv6YqA==} engines: {node: '>=12'} dev: false - /d3-geo/1.12.1: - resolution: {integrity: sha512-XG4d1c/UJSEX9NfU02KwBL6BYPj8YKHxgBEw5om2ZnTRSbIcego6dhHwcxuSR3clxh0EpE38os1DVPOmnYtTPg==} - dependencies: - d3-array: 1.2.4 - dev: false - /d3-geo/3.0.1: resolution: {integrity: sha512-Wt23xBych5tSy9IYAM1FR2rWIBFWa52B/oF/GYe5zbdHrg08FU8+BuI6X4PvTwPDdqdAdq04fuWJpELtsaEjeA==} engines: {node: '>=12'} @@ -5644,21 +6134,11 @@ packages: d3-array: 3.2.0 dev: false - /d3-hierarchy/1.1.9: - resolution: {integrity: sha512-j8tPxlqh1srJHAtxfvOUwKNYJkQuBFdM1+JAUfq6xqH5eAqf93L7oG1NVqDa4CpFZNvnNKtCYEUC8KY9yEn9lQ==} - dev: false - /d3-hierarchy/3.1.2: resolution: {integrity: sha512-FX/9frcub54beBdugHjDCdikxThEqjnR93Qt7PvQTOHxyiNCAlvMrHhclk3cD5VeAaq9fxmfRp+CnWw9rEMBuA==} engines: {node: '>=12'} dev: false - /d3-interpolate/1.4.0: - resolution: {integrity: sha512-V9znK0zc3jOPV4VD2zZn0sDhZU3WAE2bmlxdIwwQPPzPjvyLkd8B3JUVdS1IDUFDkWZ72c9qnv1GK2ZagTZ8EA==} - dependencies: - d3-color: 1.4.1 - dev: false - /d3-interpolate/3.0.1: resolution: {integrity: sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==} engines: {node: '>=12'} @@ -5666,49 +6146,26 @@ packages: d3-color: 3.1.0 dev: false - /d3-path/1.0.9: - resolution: {integrity: sha512-VLaYcn81dtHVTjEHd8B+pbe9yHWpXKZUC87PzoFmsFrJqgFwDe/qxfp5MlfsfM1V5E/iVt0MmEbWQ7FVIXh/bg==} - dev: false - /d3-path/3.0.1: resolution: {integrity: sha512-gq6gZom9AFZby0YLduxT1qmrp4xpBA1YZr19OI717WIdKE2OM5ETq5qrHLb301IgxhLwcuxvGZVLeeWc/k1I6w==} engines: {node: '>=12'} dev: false - /d3-polygon/1.0.6: - resolution: {integrity: sha512-k+RF7WvI08PC8reEoXa/w2nSg5AUMTi+peBD9cmFc+0ixHfbs4QmxxkarVal1IkVkgxVuk9JSHhJURHiyHKAuQ==} - dev: false - /d3-polygon/3.0.1: resolution: {integrity: sha512-3vbA7vXYwfe1SYhED++fPUQlWSYTTGmFmQiany/gdbiWgU/iEyQzyymwL9SkJjFFuCS4902BSzewVGsHHmHtXg==} engines: {node: '>=12'} dev: false - /d3-quadtree/1.0.7: - resolution: {integrity: sha512-RKPAeXnkC59IDGD0Wu5mANy0Q2V28L+fNe65pOCXVdVuTJS3WPKaJlFHer32Rbh9gIo9qMuJXio8ra4+YmIymA==} - dev: false - /d3-quadtree/3.0.1: resolution: {integrity: sha512-04xDrxQTDTCFwP5H6hRhsRcb9xxv2RzkcsygFzmkSIOJy3PeRJP7sNk3VRIbKXcog561P9oU0/rVH6vDROAgUw==} engines: {node: '>=12'} dev: false - /d3-random/1.1.2: - resolution: {integrity: sha512-6AK5BNpIFqP+cx/sreKzNjWbwZQCSUatxq+pPRmFIQaWuoD+NrbVWw7YWpHiXpCQ/NanKdtGDuB+VQcZDaEmYQ==} - dev: false - /d3-random/3.0.1: resolution: {integrity: sha512-FXMe9GfxTxqd5D6jFsQ+DJ8BJS4E/fT5mqqdjovykEB2oFbTMDVdg1MGFxfQW+FBOGoB++k8swBrgwSHT1cUXQ==} engines: {node: '>=12'} dev: false - /d3-scale-chromatic/1.5.0: - resolution: {integrity: sha512-ACcL46DYImpRFMBcpk9HhtIyC7bTBR4fNOPxwVSl0LfulDAwyiHyPOTqcDG1+t5d4P9W7t/2NAuWu59aKko/cg==} - dependencies: - d3-color: 1.4.1 - d3-interpolate: 1.4.0 - dev: false - /d3-scale-chromatic/3.0.0: resolution: {integrity: sha512-Lx9thtxAKrO2Pq6OO2Ua474opeziKr279P/TKZsMAhYyNDD3EnCffdbgeSYN5O7m2ByQsxtuP2CSDczNUIZ22g==} engines: {node: '>=12'} @@ -5717,17 +6174,6 @@ packages: d3-interpolate: 3.0.1 dev: false - /d3-scale/2.2.2: - resolution: {integrity: sha512-LbeEvGgIb8UMcAa0EATLNX0lelKWGYDQiPdHj+gLblGVhGLyNbaCn3EvrJf0A3Y/uOOU5aD6MTh5ZFCdEwGiCw==} - dependencies: - d3-array: 1.2.4 - d3-collection: 1.0.7 - d3-format: 1.4.5 - d3-interpolate: 1.4.0 - d3-time: 1.1.0 - d3-time-format: 2.3.0 - dev: false - /d3-scale/4.0.2: resolution: {integrity: sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==} engines: {node: '>=12'} @@ -5739,21 +6185,11 @@ packages: d3-time-format: 4.1.0 dev: false - /d3-selection/1.4.2: - resolution: {integrity: sha512-SJ0BqYihzOjDnnlfyeHT0e30k0K1+5sR3d5fNueCNeuhZTnGw4M4o8mqJchSwgKMXCNFo+e2VTChiSJ0vYtXkg==} - dev: false - /d3-selection/3.0.0: resolution: {integrity: sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==} engines: {node: '>=12'} dev: false - /d3-shape/1.3.7: - resolution: {integrity: sha512-EUkvKjqPFUAZyOlhY5gzCxCeI0Aep04LwIRpsZ/mLFelJiUfnK56jo5JMDSE7yyP2kLSb6LtF+S5chMk7uqPqw==} - dependencies: - d3-path: 1.0.9 - dev: false - /d3-shape/3.1.0: resolution: {integrity: sha512-tGDh1Muf8kWjEDT/LswZJ8WF85yDZLvVJpYU9Nq+8+yW1Z5enxrmXOhTArlkaElU+CTn0OTVNli+/i+HP45QEQ==} engines: {node: '>=12'} @@ -5761,12 +6197,6 @@ packages: d3-path: 3.0.1 dev: false - /d3-time-format/2.3.0: - resolution: {integrity: sha512-guv6b2H37s2Uq/GefleCDtbe0XZAuy7Wa49VGkPVPMfLL9qObgBST3lEHJBMUp8S7NdLQAGIvr2KXk8Hc98iKQ==} - dependencies: - d3-time: 1.1.0 - dev: false - /d3-time-format/4.1.0: resolution: {integrity: sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==} engines: {node: '>=12'} @@ -5774,10 +6204,6 @@ packages: d3-time: 3.0.0 dev: false - /d3-time/1.1.0: - resolution: {integrity: sha512-Xh0isrZ5rPYYdqhAVk8VLnMEidhz5aP7htAADH6MfzgmmicPkTo8LhkLxci61/lCB7n7UmE3bN0leRt+qvkLxA==} - dev: false - /d3-time/3.0.0: resolution: {integrity: sha512-zmV3lRnlaLI08y9IMRXSDshQb5Nj77smnfpnd2LrBa/2K281Jijactokeak14QacHs/kKq0AQ121nidNYlarbQ==} engines: {node: '>=12'} @@ -5785,26 +6211,11 @@ packages: d3-array: 3.2.0 dev: false - /d3-timer/1.0.10: - resolution: {integrity: sha512-B1JDm0XDaQC+uvo4DT79H0XmBskgS3l6Ve+1SBCfxgmtIb1AVrPIoqd+nPSv+loMX8szQ0sVUhGngL7D5QPiXw==} - dev: false - /d3-timer/3.0.1: resolution: {integrity: sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==} engines: {node: '>=12'} dev: false - /d3-transition/1.3.2: - resolution: {integrity: sha512-sc0gRU4PFqZ47lPVHloMn9tlPcv8jxgOQg+0zjhfZXMQuvppjG6YuwdMBE0TuqCZjeJkLecku/l9R0JPcRhaDA==} - dependencies: - d3-color: 1.4.1 - d3-dispatch: 1.0.6 - d3-ease: 1.0.7 - d3-interpolate: 1.4.0 - d3-selection: 1.4.2 - d3-timer: 1.0.10 - dev: false - /d3-transition/3.0.1_d3-selection@3.0.0: resolution: {integrity: sha512-ApKvfjsSR6tg06xrL434C0WydLr7JewBB3V+/39RMHsaXTOG0zmt/OAXeng5M5LBm0ojmxJrpomQVZ1aPvBL4w==} engines: {node: '>=12'} @@ -5819,20 +6230,6 @@ packages: d3-timer: 3.0.1 dev: false - /d3-voronoi/1.1.4: - resolution: {integrity: sha512-dArJ32hchFsrQ8uMiTBLq256MpnZjeuBtdHpaDlYuQyjU0CVzCJl/BVW+SkszaAeH95D/8gxqAhgx0ouAWAfRg==} - dev: false - - /d3-zoom/1.8.3: - resolution: {integrity: sha512-VoLXTK4wvy1a0JpH2Il+F2CiOhVu7VRXWF5M/LroMIh3/zBAC3WAt7QoIvPibOavVo20hN6/37vwAsdBejLyKQ==} - dependencies: - d3-dispatch: 1.0.6 - d3-drag: 1.2.5 - d3-interpolate: 1.4.0 - d3-selection: 1.4.2 - d3-transition: 1.3.2 - dev: false - /d3-zoom/3.0.0: resolution: {integrity: sha512-b8AmV3kfQaqWAuacbPuNbL6vahnOJflOhexLzMMNLga62+/nh0JzvJ0aO/5a5MVgUFGS7Hu1P9P03o3fJkDCyw==} engines: {node: '>=12'} @@ -5844,44 +6241,8 @@ packages: d3-transition: 3.0.1_d3-selection@3.0.0 dev: false - /d3/5.16.0: - resolution: {integrity: sha512-4PL5hHaHwX4m7Zr1UapXW23apo6pexCgdetdJ5kTmADpG/7T9Gkxw0M0tf/pjoB63ezCCm0u5UaFYy2aMt0Mcw==} - dependencies: - d3-array: 1.2.4 - d3-axis: 1.0.12 - d3-brush: 1.1.6 - d3-chord: 1.0.6 - d3-collection: 1.0.7 - d3-color: 1.4.1 - d3-contour: 1.3.2 - d3-dispatch: 1.0.6 - d3-drag: 1.2.5 - d3-dsv: 1.2.0 - d3-ease: 1.0.7 - d3-fetch: 1.2.0 - d3-force: 1.2.1 - d3-format: 1.4.5 - d3-geo: 1.12.1 - d3-hierarchy: 1.1.9 - d3-interpolate: 1.4.0 - d3-path: 1.0.9 - d3-polygon: 1.0.6 - d3-quadtree: 1.0.7 - d3-random: 1.1.2 - d3-scale: 2.2.2 - d3-scale-chromatic: 1.5.0 - d3-selection: 1.4.2 - d3-shape: 1.3.7 - d3-time: 1.1.0 - d3-time-format: 2.3.0 - d3-timer: 1.0.10 - d3-transition: 1.3.2 - d3-voronoi: 1.1.4 - d3-zoom: 1.8.3 - dev: false - - /d3/7.6.1: - resolution: {integrity: sha512-txMTdIHFbcpLx+8a0IFhZsbp+PfBBPt8yfbmukZTQFroKuFqIwqswF0qE5JXWefylaAVpSXFoKm3yP+jpNLFLw==} + /d3/7.8.0: + resolution: {integrity: sha512-a5rNemRadWkEfqnY5NsD4RdCP9vn8EIJ4I5Rl14U0uKH1SXqcNmk/h9aGaAF1O98lz6L9M0IeUcuPa9GUYbI5A==} engines: {node: '>=12'} dependencies: d3-array: 3.2.0 @@ -5916,26 +6277,16 @@ packages: d3-zoom: 3.0.0 dev: false - /dagre-d3/0.6.4: - resolution: {integrity: sha512-e/6jXeCP7/ptlAM48clmX4xTZc5Ek6T6kagS7Oz2HrYSdqcLZFLqpAfh7ldbZRFfxCZVyh61NEPR08UQRVxJzQ==} + /dagre-d3-es/7.0.6: + resolution: {integrity: sha512-CaaE/nZh205ix+Up4xsnlGmpog5GGm81Upi2+/SBHxwNwrccBb3K51LzjZ1U6hgvOlAEUsVWf1xSTzCyKpJ6+Q==} dependencies: - d3: 5.16.0 - dagre: 0.8.5 - graphlib: 2.1.8 - lodash: 4.17.21 - dev: false - - /dagre/0.8.5: - resolution: {integrity: sha512-/aTqmnRta7x7MCCpExk7HQL2O4owCT2h8NT//9I1OQ9vt29Pa0BzSAkR5lwFUcQ7491yVi/3CXU9jQ5o0Mn2Sw==} - dependencies: - graphlib: 2.1.8 - lodash: 4.17.21 + d3: 7.8.0 + lodash-es: 4.17.21 dev: false /dargs/7.0.0: resolution: {integrity: sha512-2iy1EkLdlBzQGvbweYRFxmFath8+K7+AKB0TlhHWkNuH+TmovaMH/Wp7V7R4u7f4SnX3OgLsU9t1NI9ioDnUpg==} engines: {node: '>=8'} - dev: true /data-uri-to-buffer/4.0.0: resolution: {integrity: sha512-Vr3mLBA8qWmcuschSLAOogKgQ/Jwxulv3RNE4FXnYWRGujzrRWQI4m12fQqRkwX06C0KanhLr4hK+GydchZsaA==} @@ -5959,10 +6310,9 @@ packages: /dateformat/3.0.3: resolution: {integrity: sha512-jyCETtSl3VMZMWeRo7iY1FL19ges1t55hMo5yaam4Jrsm5EPL89UQkoQRyiI+Yf4k8r2ZpdngkV8hr1lIdjb3Q==} - dev: true - /dayjs/1.11.6: - resolution: {integrity: sha512-zZbY5giJAinCG+7AGaw0wIhNZ6J8AhWuSXKvuc1KAyMiRsvGQWqh4L+MomvhdAYjN+lqvVCMq1I41e3YHvXkyQ==} + /dayjs/1.11.7: + resolution: {integrity: sha512-+Yw9U6YO5TQohxLcIkrXBeY73WP3ejHWVvx8XCk3gxvQDCTEmS48ZrSZCKciI7Bhl/uCMyxYtE9UqRILmFphkQ==} dev: false /debounce/1.2.1: @@ -6036,7 +6386,6 @@ packages: dependencies: decamelize: 1.2.0 map-obj: 1.0.1 - dev: true /decamelize/1.2.0: resolution: {integrity: sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==} @@ -6221,7 +6570,7 @@ packages: resolution: {integrity: sha512-tQbV/4u5WVB8HMJr08pgw0b6nG4RGt/tj+7Numvq+zqcvUFeMaIWWOUFltiU+6go8BSO2/ogsB4EasDaj0y68Q==} engines: {node: '>=14.16'} dependencies: - globby: 13.1.2 + globby: 13.1.3 graceful-fs: 4.2.10 is-glob: 4.0.3 is-path-cwd: 3.0.0 @@ -6345,8 +6694,8 @@ packages: engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} dependencies: is-url: 1.2.4 - postcss: 8.4.19 - postcss-values-parser: 6.0.2_postcss@8.4.19 + postcss: 8.4.20 + postcss-values-parser: 6.0.2_postcss@8.4.20 dev: false /detective-sass/4.0.1: @@ -6374,10 +6723,10 @@ packages: resolution: {integrity: sha512-lR78AugfUSBojwlSRZBeEqQ1l8LI7rbxOl1qTUnGLcjZQDjZmrZCb7R46rK8U8B5WzFvJrxa7fEBA8FoD/n5fA==} engines: {node: ^12.20.0 || ^14.14.0 || >=16.0.0} dependencies: - '@typescript-eslint/typescript-estree': 5.45.0_typescript@4.9.3 + '@typescript-eslint/typescript-estree': 5.47.1_typescript@4.9.4 ast-module-types: 3.0.0 node-source-walk: 5.0.0 - typescript: 4.9.3 + typescript: 4.9.4 transitivePeerDependencies: - supports-color dev: false @@ -6386,10 +6735,10 @@ packages: resolution: {integrity: sha512-lR78AugfUSBojwlSRZBeEqQ1l8LI7rbxOl1qTUnGLcjZQDjZmrZCb7R46rK8U8B5WzFvJrxa7fEBA8FoD/n5fA==} engines: {node: ^12.20.0 || ^14.14.0 || >=16.0.0} dependencies: - '@typescript-eslint/typescript-estree': 5.45.0_4rfylzx7siyfhvklzx37rrckmi + '@typescript-eslint/typescript-estree': 5.47.1_w6zgx7jig4ppjo57goygyg47o4 ast-module-types: 3.0.0 node-source-walk: 5.0.0 - typescript: 4.9.3 + typescript: 4.9.4 transitivePeerDependencies: - supports-color dev: false @@ -6450,15 +6799,16 @@ packages: entities: 2.2.0 dev: false - /domelementtype/2.3.0: - resolution: {integrity: sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==} - dev: false - - /domhandler/3.3.0: - resolution: {integrity: sha512-J1C5rIANUbuYK+FuFL98650rihynUOEzRLxW+90bKZRWB6A1X1Tf82GxR1qAWLyfNPRvjqfip3Q5tdYlmAa9lA==} - engines: {node: '>= 4'} + /dom-serializer/2.0.0: + resolution: {integrity: sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==} dependencies: domelementtype: 2.3.0 + domhandler: 5.0.3 + entities: 4.4.0 + dev: false + + /domelementtype/2.3.0: + resolution: {integrity: sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==} dev: false /domhandler/4.3.1: @@ -6468,8 +6818,15 @@ packages: domelementtype: 2.3.0 dev: false - /dompurify/2.4.0: - resolution: {integrity: sha512-Be9tbQMZds4a3C6xTmz68NlMfeONA//4dOavl/1rNw50E+/QO0KVpbcU0PcaW0nsQxurXls9ZocqFxk8R2mWEA==} + /domhandler/5.0.3: + resolution: {integrity: sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==} + engines: {node: '>= 4'} + dependencies: + domelementtype: 2.3.0 + dev: false + + /dompurify/2.4.1: + resolution: {integrity: sha512-ewwFzHzrrneRjxzmK6oVz/rZn9VWspGFRDb4/rRtIsM1n36t9AKma/ye8syCpcw+XJ25kOK/hOG7t1j2I2yBqA==} dev: false /domutils/2.8.0: @@ -6480,6 +6837,14 @@ packages: domhandler: 4.3.1 dev: false + /domutils/3.0.1: + resolution: {integrity: sha512-z08c1l761iKhDFtfXO04C7kTdPBLi41zwOZl00WS8b5eiaebNpY00HKbztwBq+e3vyqWNwWF3mP9YLUeqIrF+Q==} + dependencies: + dom-serializer: 2.0.0 + domelementtype: 2.3.0 + domhandler: 5.0.3 + dev: false + /dot-case/3.0.4: resolution: {integrity: sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==} dependencies: @@ -6545,11 +6910,11 @@ packages: safe-buffer: 5.2.1 dev: false - /echarts/5.4.0: - resolution: {integrity: sha512-uPsO9VRUIKAdFOoH3B0aNg7NRVdN7aM39/OjovjO9MwmWsAkfGyeXJhK+dbRi51iDrQWliXV60/XwLA7kg3z0w==} + /echarts/5.4.1: + resolution: {integrity: sha512-9ltS3M2JB0w2EhcYjCdmtrJ+6haZcW6acBolMGIuf01Hql1yrIV01L1aRj7jsaaIULJslEP9Z3vKlEmnJaWJVQ==} dependencies: tslib: 2.3.0 - zrender: 5.4.0 + zrender: 5.4.1 dev: false /ee-first/1.1.1: @@ -6616,6 +6981,11 @@ packages: engines: {node: '>=0.12'} dev: false + /entities/4.4.0: + resolution: {integrity: sha512-oYp7156SP8LkeGD0GF85ad1X9Ai79WtRsZ2gxJqtBuzH+98YUV6jkHEKlZkMbcrjJjIVJNIDP/3WL9wQkoPbWA==} + engines: {node: '>=0.12'} + dev: false + /env-paths/2.2.1: resolution: {integrity: sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==} engines: {node: '>=6'} @@ -6646,8 +7016,8 @@ packages: stackframe: 1.3.4 dev: false - /es-abstract/1.20.4: - resolution: {integrity: sha512-0UtvRN79eMe2L+UNEF1BwRe364sj/DXhQ/k5FmivgoSdpM90b8Jc0mDzKMGo7QS0BVbOP/bTwBKNnDc9rNzaPA==} + /es-abstract/1.20.5: + resolution: {integrity: sha512-7h8MM2EQhsCA7pU/Nv78qOXFpD8Rhqd12gYiSJVkrH9+e8VuA8JlPJK/hQjjlLv6pJvx/z1iRFKzYb0XT/RuAQ==} engines: {node: '>= 0.4'} dependencies: call-bind: 1.0.2 @@ -6656,10 +7026,11 @@ packages: function.prototype.name: 1.1.5 get-intrinsic: 1.1.3 get-symbol-description: 1.0.0 + gopd: 1.0.1 has: 1.0.3 has-property-descriptors: 1.0.0 has-symbols: 1.0.3 - internal-slot: 1.0.3 + internal-slot: 1.0.4 is-callable: 1.2.7 is-negative-zero: 2.0.2 is-regex: 1.1.4 @@ -6703,8 +7074,8 @@ packages: resolution: {integrity: sha512-HBL8I3mIki5C1Cc9QjKUenHtnG0A5/xA8Q/AllRcfiwl2CZFXGK7ddBiCoRwAix4i2KxcQfjtIVcrVbB3vbmwg==} dev: false - /esbuild-android-64/0.14.54: - resolution: {integrity: sha512-Tz2++Aqqz0rJ7kYBfz+iqyE3QMycD4vk7LBRyWaAVFgFtQ/O8EJOnVmTOiDWYZ/uYzB4kvP+bqejYdVKzE5lAQ==} + /esbuild-android-64/0.15.11: + resolution: {integrity: sha512-rrwoXEiuI1kaw4k475NJpexs8GfJqQUKcD08VR8sKHmuW9RUuTR2VxcupVvHdiGh9ihxL9m3lpqB1kju92Ialw==} engines: {node: '>=12'} cpu: [x64] os: [android] @@ -6712,37 +7083,12 @@ packages: dev: false optional: true - /esbuild-android-64/0.15.16: - resolution: {integrity: sha512-Vwkv/sT0zMSgPSVO3Jlt1pUbnZuOgtOQJkJkyyJFAlLe7BiT8e9ESzo0zQSx4c3wW4T6kGChmKDPMbWTgtliQA==} - engines: {node: '>=12'} - cpu: [x64] - os: [android] - requiresBuild: true - optional: true - - /esbuild-android-arm64/0.14.54: - resolution: {integrity: sha512-F9E+/QDi9sSkLaClO8SOV6etqPd+5DgJje1F9lOWoNncDdOBL2YF59IhsWATSt0TLZbYCf3pNlTHvVV5VfHdvg==} - engines: {node: '>=12'} - cpu: [arm64] - os: [android] - requiresBuild: true - dev: false - optional: true - /esbuild-android-arm64/0.15.16: resolution: {integrity: sha512-lqfKuofMExL5niNV3gnhMUYacSXfsvzTa/58sDlBET/hCOG99Zmeh+lz6kvdgvGOsImeo6J9SW21rFCogNPLxg==} engines: {node: '>=12'} cpu: [arm64] os: [android] requiresBuild: true - optional: true - - /esbuild-darwin-64/0.14.54: - resolution: {integrity: sha512-jtdKWV3nBviOd5v4hOpkVmpxsBy90CGzebpbO9beiqUYVMBtSc0AL9zGftFuBon7PNDcdvNCEuQqw2x0wP9yug==} - engines: {node: '>=12'} - cpu: [x64] - os: [darwin] - requiresBuild: true dev: false optional: true @@ -6752,14 +7098,6 @@ packages: cpu: [x64] os: [darwin] requiresBuild: true - optional: true - - /esbuild-darwin-arm64/0.14.54: - resolution: {integrity: sha512-OPafJHD2oUPyvJMrsCvDGkRrVCar5aVyHfWGQzY1dWnzErjrDuSETxwA2HSsyg2jORLY8yBfzc1MIpUkXlctmw==} - engines: {node: '>=12'} - cpu: [arm64] - os: [darwin] - requiresBuild: true dev: false optional: true @@ -6769,14 +7107,6 @@ packages: cpu: [arm64] os: [darwin] requiresBuild: true - optional: true - - /esbuild-freebsd-64/0.14.54: - resolution: {integrity: sha512-OKwd4gmwHqOTp4mOGZKe/XUlbDJ4Q9TjX0hMPIDBUWWu/kwhBAudJdBoxnjNf9ocIB6GN6CPowYpR/hRCbSYAg==} - engines: {node: '>=12'} - cpu: [x64] - os: [freebsd] - requiresBuild: true dev: false optional: true @@ -6786,14 +7116,6 @@ packages: cpu: [x64] os: [freebsd] requiresBuild: true - optional: true - - /esbuild-freebsd-arm64/0.14.54: - resolution: {integrity: sha512-sFwueGr7OvIFiQT6WeG0jRLjkjdqWWSrfbVwZp8iMP+8UHEHRBvlaxL6IuKNDwAozNUmbb8nIMXa7oAOARGs1Q==} - engines: {node: '>=12'} - cpu: [arm64] - os: [freebsd] - requiresBuild: true dev: false optional: true @@ -6803,14 +7125,6 @@ packages: cpu: [arm64] os: [freebsd] requiresBuild: true - optional: true - - /esbuild-linux-32/0.14.54: - resolution: {integrity: sha512-1ZuY+JDI//WmklKlBgJnglpUL1owm2OX+8E1syCD6UAxcMM/XoWd76OHSjl/0MR0LisSAXDqgjT3uJqT67O3qw==} - engines: {node: '>=12'} - cpu: [ia32] - os: [linux] - requiresBuild: true dev: false optional: true @@ -6820,14 +7134,6 @@ packages: cpu: [ia32] os: [linux] requiresBuild: true - optional: true - - /esbuild-linux-64/0.14.54: - resolution: {integrity: sha512-EgjAgH5HwTbtNsTqQOXWApBaPVdDn7XcK+/PtJwZLT1UmpLoznPd8c5CxqsH2dQK3j05YsB3L17T8vE7cp4cCg==} - engines: {node: '>=12'} - cpu: [x64] - os: [linux] - requiresBuild: true dev: false optional: true @@ -6837,14 +7143,6 @@ packages: cpu: [x64] os: [linux] requiresBuild: true - optional: true - - /esbuild-linux-arm/0.14.54: - resolution: {integrity: sha512-qqz/SjemQhVMTnvcLGoLOdFpCYbz4v4fUo+TfsWG+1aOu70/80RV6bgNpR2JCrppV2moUQkww+6bWxXRL9YMGw==} - engines: {node: '>=12'} - cpu: [arm] - os: [linux] - requiresBuild: true dev: false optional: true @@ -6854,14 +7152,6 @@ packages: cpu: [arm] os: [linux] requiresBuild: true - optional: true - - /esbuild-linux-arm64/0.14.54: - resolution: {integrity: sha512-WL71L+0Rwv+Gv/HTmxTEmpv0UgmxYa5ftZILVi2QmZBgX3q7+tDeOQNqGtdXSdsL8TQi1vIaVFHUPDe0O0kdig==} - engines: {node: '>=12'} - cpu: [arm64] - os: [linux] - requiresBuild: true dev: false optional: true @@ -6871,14 +7161,6 @@ packages: cpu: [arm64] os: [linux] requiresBuild: true - optional: true - - /esbuild-linux-mips64le/0.14.54: - resolution: {integrity: sha512-qTHGQB8D1etd0u1+sB6p0ikLKRVuCWhYQhAHRPkO+OF3I/iSlTKNNS0Lh2Oc0g0UFGguaFZZiPJdJey3AGpAlw==} - engines: {node: '>=12'} - cpu: [mips64el] - os: [linux] - requiresBuild: true dev: false optional: true @@ -6888,14 +7170,6 @@ packages: cpu: [mips64el] os: [linux] requiresBuild: true - optional: true - - /esbuild-linux-ppc64le/0.14.54: - resolution: {integrity: sha512-j3OMlzHiqwZBDPRCDFKcx595XVfOfOnv68Ax3U4UKZ3MTYQB5Yz3X1mn5GnodEVYzhtZgxEBidLWeIs8FDSfrQ==} - engines: {node: '>=12'} - cpu: [ppc64] - os: [linux] - requiresBuild: true dev: false optional: true @@ -6905,14 +7179,6 @@ packages: cpu: [ppc64] os: [linux] requiresBuild: true - optional: true - - /esbuild-linux-riscv64/0.14.54: - resolution: {integrity: sha512-y7Vt7Wl9dkOGZjxQZnDAqqn+XOqFD7IMWiewY5SPlNlzMX39ocPQlOaoxvT4FllA5viyV26/QzHtvTjVNOxHZg==} - engines: {node: '>=12'} - cpu: [riscv64] - os: [linux] - requiresBuild: true dev: false optional: true @@ -6922,14 +7188,6 @@ packages: cpu: [riscv64] os: [linux] requiresBuild: true - optional: true - - /esbuild-linux-s390x/0.14.54: - resolution: {integrity: sha512-zaHpW9dziAsi7lRcyV4r8dhfG1qBidQWUXweUjnw+lliChJqQr+6XD71K41oEIC3Mx1KStovEmlzm+MkGZHnHA==} - engines: {node: '>=12'} - cpu: [s390x] - os: [linux] - requiresBuild: true dev: false optional: true @@ -6939,27 +7197,28 @@ packages: cpu: [s390x] os: [linux] requiresBuild: true + dev: false optional: true - /esbuild-loader/2.19.0_webpack@5.75.0: - resolution: {integrity: sha512-urGNVE6Tl2rqx92ElKi/LiExXjGvcH6HfDBFzJ9Ppwqh4n6Jmx8x7RKAyMzSM78b6CAaJLhDncG5sPrL0ROh5Q==} + /esbuild-loader/2.20.0_webpack@5.75.0: + resolution: {integrity: sha512-dr+j8O4w5RvqZ7I4PPB4EIyVTd679EBQnMm+JBB7av+vu05Zpje2IpK5N3ld1VWa+WxrInIbNFAg093+E1aRsA==} peerDependencies: webpack: ^4.40.0 || ^5.0.0 peerDependenciesMeta: webpack: optional: true dependencies: - esbuild: 0.14.54 + esbuild: 0.15.11 joycon: 3.1.1 - json5: 2.2.1 - loader-utils: 2.0.4 + json5: 2.2.3 + loader-utils: 2.0.2 tapable: 2.2.1 webpack: 5.75.0 webpack-sources: 2.3.1 dev: false - /esbuild-netbsd-64/0.14.54: - resolution: {integrity: sha512-PR01lmIMnfJTgeU9VJTDY9ZerDWVFIUzAtJuDHwwceppW7cQWjBBqP48NdeRtoP04/AtO9a7w3viI+PIDr6d+w==} + /esbuild-netbsd-64/0.15.11: + resolution: {integrity: sha512-hUC9yN06K9sg7ju4Vgu9ChAPdsEgtcrcLfyNT5IKwKyfpLvKUwCMZSdF+gRD3WpyZelgTQfJ+pDx5XFbXTlB0A==} engines: {node: '>=12'} cpu: [x64] os: [netbsd] @@ -6967,37 +7226,12 @@ packages: dev: false optional: true - /esbuild-netbsd-64/0.15.16: - resolution: {integrity: sha512-ElQ9rhdY51et6MJTWrCPbqOd/YuPowD7Cxx3ee8wlmXQQVW7UvQI6nSprJ9uVFQISqSF5e5EWpwWqXZsECLvXg==} - engines: {node: '>=12'} - cpu: [x64] - os: [netbsd] - requiresBuild: true - optional: true - - /esbuild-openbsd-64/0.14.54: - resolution: {integrity: sha512-Qyk7ikT2o7Wu76UsvvDS5q0amJvmRzDyVlL0qf5VLsLchjCa1+IAvd8kTBgUxD7VBUUVgItLkk609ZHUc1oCaw==} - engines: {node: '>=12'} - cpu: [x64] - os: [openbsd] - requiresBuild: true - dev: false - optional: true - /esbuild-openbsd-64/0.15.16: resolution: {integrity: sha512-KgxMHyxMCT+NdLQE1zVJEsLSt2QQBAvJfmUGDmgEq8Fvjrf6vSKB00dVHUEDKcJwMID6CdgCpvYNt999tIYhqA==} engines: {node: '>=12'} cpu: [x64] os: [openbsd] requiresBuild: true - optional: true - - /esbuild-sunos-64/0.14.54: - resolution: {integrity: sha512-28GZ24KmMSeKi5ueWzMcco6EBHStL3B6ubM7M51RmPwXQGLe0teBGJocmWhgwccA1GeFXqxzILIxXpHbl9Q/Kw==} - engines: {node: '>=12'} - cpu: [x64] - os: [sunos] - requiresBuild: true dev: false optional: true @@ -7007,14 +7241,6 @@ packages: cpu: [x64] os: [sunos] requiresBuild: true - optional: true - - /esbuild-windows-32/0.14.54: - resolution: {integrity: sha512-T+rdZW19ql9MjS7pixmZYVObd9G7kcaZo+sETqNH4RCkuuYSuv9AGHUVnPoP9hhuE1WM1ZimHz1CIBHBboLU7w==} - engines: {node: '>=12'} - cpu: [ia32] - os: [win32] - requiresBuild: true dev: false optional: true @@ -7024,14 +7250,6 @@ packages: cpu: [ia32] os: [win32] requiresBuild: true - optional: true - - /esbuild-windows-64/0.14.54: - resolution: {integrity: sha512-AoHTRBUuYwXtZhjXZbA1pGfTo8cJo3vZIcWGLiUcTNgHpJJMC1rVA44ZereBHMJtotyN71S8Qw0npiCIkW96cQ==} - engines: {node: '>=12'} - cpu: [x64] - os: [win32] - requiresBuild: true dev: false optional: true @@ -7041,14 +7259,6 @@ packages: cpu: [x64] os: [win32] requiresBuild: true - optional: true - - /esbuild-windows-arm64/0.14.54: - resolution: {integrity: sha512-M0kuUvXhot1zOISQGXwWn6YtS+Y/1RT9WrVIOywZnJHo3jCDyewAc79aKNQWFCQm+xNHVTq9h8dZKvygoXQQRg==} - engines: {node: '>=12'} - cpu: [arm64] - os: [win32] - requiresBuild: true dev: false optional: true @@ -7058,36 +7268,8 @@ packages: cpu: [arm64] os: [win32] requiresBuild: true - optional: true - - /esbuild/0.14.54: - resolution: {integrity: sha512-Cy9llcy8DvET5uznocPyqL3BFRrFXSVqbgpMJ9Wz8oVjZlh/zUSNbPRbov0VX7VxN2JH1Oa0uNxZ7eLRb62pJA==} - engines: {node: '>=12'} - hasBin: true - requiresBuild: true - optionalDependencies: - '@esbuild/linux-loong64': 0.14.54 - esbuild-android-64: 0.14.54 - esbuild-android-arm64: 0.14.54 - esbuild-darwin-64: 0.14.54 - esbuild-darwin-arm64: 0.14.54 - esbuild-freebsd-64: 0.14.54 - esbuild-freebsd-arm64: 0.14.54 - esbuild-linux-32: 0.14.54 - esbuild-linux-64: 0.14.54 - esbuild-linux-arm: 0.14.54 - esbuild-linux-arm64: 0.14.54 - esbuild-linux-mips64le: 0.14.54 - esbuild-linux-ppc64le: 0.14.54 - esbuild-linux-riscv64: 0.14.54 - esbuild-linux-s390x: 0.14.54 - esbuild-netbsd-64: 0.14.54 - esbuild-openbsd-64: 0.14.54 - esbuild-sunos-64: 0.14.54 - esbuild-windows-32: 0.14.54 - esbuild-windows-64: 0.14.54 - esbuild-windows-arm64: 0.14.54 dev: false + optional: true /esbuild/0.15.16: resolution: {integrity: sha512-o6iS9zxdHrrojjlj6pNGC2NAg86ECZqIETswTM5KmJitq+R1YmahhWtMumeQp9lHqJaROGnsBi2RLawGnfo5ZQ==} @@ -7095,28 +7277,58 @@ packages: hasBin: true requiresBuild: true optionalDependencies: - '@esbuild/android-arm': 0.15.16 - '@esbuild/linux-loong64': 0.15.16 - esbuild-android-64: 0.15.16 - esbuild-android-arm64: 0.15.16 - esbuild-darwin-64: 0.15.16 - esbuild-darwin-arm64: 0.15.16 - esbuild-freebsd-64: 0.15.16 - esbuild-freebsd-arm64: 0.15.16 - esbuild-linux-32: 0.15.16 - esbuild-linux-64: 0.15.16 - esbuild-linux-arm: 0.15.16 - esbuild-linux-arm64: 0.15.16 - esbuild-linux-mips64le: 0.15.16 - esbuild-linux-ppc64le: 0.15.16 - esbuild-linux-riscv64: 0.15.16 - esbuild-linux-s390x: 0.15.16 - esbuild-netbsd-64: 0.15.16 - esbuild-openbsd-64: 0.15.16 - esbuild-sunos-64: 0.15.16 - esbuild-windows-32: 0.15.16 - esbuild-windows-64: 0.15.16 - esbuild-windows-arm64: 0.15.16 + '@esbuild/android-arm': 0.15.11 + '@esbuild/linux-loong64': 0.15.11 + esbuild-android-64: 0.15.11 + esbuild-android-arm64: 0.15.11 + esbuild-darwin-64: 0.15.11 + esbuild-darwin-arm64: 0.15.11 + esbuild-freebsd-64: 0.15.11 + esbuild-freebsd-arm64: 0.15.11 + esbuild-linux-32: 0.15.11 + esbuild-linux-64: 0.15.11 + esbuild-linux-arm: 0.15.11 + esbuild-linux-arm64: 0.15.11 + esbuild-linux-mips64le: 0.15.11 + esbuild-linux-ppc64le: 0.15.11 + esbuild-linux-riscv64: 0.15.11 + esbuild-linux-s390x: 0.15.11 + esbuild-netbsd-64: 0.15.11 + esbuild-openbsd-64: 0.15.11 + esbuild-sunos-64: 0.15.11 + esbuild-windows-32: 0.15.11 + esbuild-windows-64: 0.15.11 + esbuild-windows-arm64: 0.15.11 + dev: false + + /esbuild/0.16.17: + resolution: {integrity: sha512-G8LEkV0XzDMNwXKgM0Jwu3nY3lSTwSGY6XbxM9cr9+s0T/qSV1q1JVPBGzm3dcjhCic9+emZDmMffkwgPeOeLg==} + engines: {node: '>=12'} + hasBin: true + requiresBuild: true + optionalDependencies: + '@esbuild/android-arm': 0.16.17 + '@esbuild/android-arm64': 0.16.17 + '@esbuild/android-x64': 0.16.17 + '@esbuild/darwin-arm64': 0.16.17 + '@esbuild/darwin-x64': 0.16.17 + '@esbuild/freebsd-arm64': 0.16.17 + '@esbuild/freebsd-x64': 0.16.17 + '@esbuild/linux-arm': 0.16.17 + '@esbuild/linux-arm64': 0.16.17 + '@esbuild/linux-ia32': 0.16.17 + '@esbuild/linux-loong64': 0.16.17 + '@esbuild/linux-mips64el': 0.16.17 + '@esbuild/linux-ppc64': 0.16.17 + '@esbuild/linux-riscv64': 0.16.17 + '@esbuild/linux-s390x': 0.16.17 + '@esbuild/linux-x64': 0.16.17 + '@esbuild/netbsd-x64': 0.16.17 + '@esbuild/openbsd-x64': 0.16.17 + '@esbuild/sunos-x64': 0.16.17 + '@esbuild/win32-arm64': 0.16.17 + '@esbuild/win32-ia32': 0.16.17 + '@esbuild/win32-x64': 0.16.17 /escalade/3.1.1: resolution: {integrity: sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==} @@ -7127,9 +7339,9 @@ packages: engines: {node: '>=8'} dev: false - /escape-goat/3.0.0: - resolution: {integrity: sha512-w3PwNZJwRxlp47QGzhuEBldEqVHHhh8/tIPcl6ecf2Bou99cdAt0knihBV0Ecc7CGxYduXVBDheH1K2oADRlvw==} - engines: {node: '>=10'} + /escape-goat/4.0.0: + resolution: {integrity: sha512-2Sd4ShcWxbx6OY1IHyla/CVNwvg7XwZVoXZHcSu9w9SReNP1EzzD5T8NWKIR38fIqEns9kDWKUQTXXAmlDrdPg==} + engines: {node: '>=12'} dev: false /escape-goat/4.0.0: @@ -7168,16 +7380,16 @@ packages: source-map: 0.6.1 dev: false - /eslint-config-prettier/8.5.0_eslint@8.28.0: + /eslint-config-prettier/8.5.0_eslint@8.32.0: resolution: {integrity: sha512-obmWKLUNCnhtQRKc+tmnYuQl0pFU1ibYJQ5BGhTVB08bHe9wC8qUeG7c08dj9XX+AuPj1YSGSQIHl1pnDHZR0Q==} hasBin: true peerDependencies: eslint: '>=7.0.0' dependencies: - eslint: 8.28.0 + eslint: 8.32.0 dev: true - /eslint-config-standard/17.0.0_5dakk4wnrkkieagghiqvu5yn4y: + /eslint-config-standard/17.0.0_aknt3kx5mck5jnsactbk5g4gdy: resolution: {integrity: sha512-/2ks1GKyqSOkH7JFvXJicu0iMpoojkwB+f5Du/1SC0PtBL+s8v30k9njRZ21pm2drKYm2342jFnGWzttxPmZVg==} peerDependencies: eslint: ^8.0.1 @@ -7192,13 +7404,13 @@ packages: eslint-plugin-promise: optional: true dependencies: - eslint: 8.28.0 - eslint-plugin-import: 2.26.0_eslint@8.28.0 - eslint-plugin-n: 15.5.1_eslint@8.28.0 - eslint-plugin-promise: 6.1.1_eslint@8.28.0 + eslint: 8.32.0 + eslint-plugin-import: 2.26.0_eslint@8.32.0 + eslint-plugin-n: 15.6.0_eslint@8.32.0 + eslint-plugin-promise: 6.1.1_eslint@8.32.0 dev: true - /eslint-config-standard/17.0.0_eslint@8.28.0: + /eslint-config-standard/17.0.0_eslint@8.32.0: resolution: {integrity: sha512-/2ks1GKyqSOkH7JFvXJicu0iMpoojkwB+f5Du/1SC0PtBL+s8v30k9njRZ21pm2drKYm2342jFnGWzttxPmZVg==} peerDependencies: eslint: ^8.0.1 @@ -7213,17 +7425,17 @@ packages: eslint-plugin-promise: optional: true dependencies: - eslint: 8.28.0 + eslint: 8.32.0 dev: true - /eslint-config-vuepress-typescript/4.0.4_jf7jfk5otr6om6scve5a6y6f5y: + /eslint-config-vuepress-typescript/4.0.4_otjudfky5iceznjpbxpmgilubi: resolution: {integrity: sha512-nFotoEouFD/ok8GIyZChTASK1e0TVZFLwHnR16MXaIWCRdL2tjWJcud53323aEJ/8PcYrY/GgRLwhTJR4rMZ7Q==} dependencies: - '@typescript-eslint/eslint-plugin': 5.45.0_czs5uoqkd3podpy6vgtsxfc7au - '@typescript-eslint/parser': 5.45.0_hsf322ms6xhhd4b5ne6lb74y4a - eslint-config-standard: 17.0.0_eslint@8.28.0 - eslint-config-vuepress: 4.0.4_fbmhg2kfdxcti56udxye75pxam - eslint-plugin-vue: 9.8.0_eslint@8.28.0 + '@typescript-eslint/eslint-plugin': 5.47.1_lxxchmivucqcmhzvhnmnywabcq + '@typescript-eslint/parser': 5.47.1_7uibuqfxkfaozanbtbziikiqje + eslint-config-standard: 17.0.0_eslint@8.32.0 + eslint-config-vuepress: 4.0.4_kqi3nn3ekdmkwzfbevnojmb4b4 + eslint-plugin-vue: 9.8.0_eslint@8.32.0 transitivePeerDependencies: - eslint - eslint-import-resolver-typescript @@ -7237,7 +7449,7 @@ packages: - typescript dev: true - /eslint-config-vuepress/4.0.4_fbmhg2kfdxcti56udxye75pxam: + /eslint-config-vuepress/4.0.4_kqi3nn3ekdmkwzfbevnojmb4b4: resolution: {integrity: sha512-MUd3IYOTVQfzuL/lAvSJPGMrJEus2/PVbQHs01N5AQw5MXc7kdhbaTJU3melExmgRe08meH88On9lNBmzbw/SQ==} peerDependencies: prettier: ^2.8.0 @@ -7248,13 +7460,13 @@ packages: prettier-config-vuepress: optional: true dependencies: - eslint-config-prettier: 8.5.0_eslint@8.28.0 - eslint-config-standard: 17.0.0_5dakk4wnrkkieagghiqvu5yn4y - eslint-plugin-import: 2.26.0_vbnhqcxlbs7ynbxw44hu2vq7eq - eslint-plugin-n: 15.5.1_eslint@8.28.0 - eslint-plugin-prettier: 4.2.1_cwlo2dingkvfydnaculr42urve - eslint-plugin-promise: 6.1.1_eslint@8.28.0 - prettier: 2.8.0 + eslint-config-prettier: 8.5.0_eslint@8.32.0 + eslint-config-standard: 17.0.0_aknt3kx5mck5jnsactbk5g4gdy + eslint-plugin-import: 2.26.0_xr5b6h7hlz4fzi2dbv6u6mr45e + eslint-plugin-n: 15.6.0_eslint@8.32.0 + eslint-plugin-prettier: 4.2.1_uzdlkkftb3f76fa4on6dnxrnyi + eslint-plugin-promise: 6.1.1_eslint@8.32.0 + prettier: 2.8.3 prettier-config-vuepress: 4.0.0 transitivePeerDependencies: - '@typescript-eslint/parser' @@ -7264,7 +7476,7 @@ packages: - supports-color dev: true - /eslint-config-vuepress/4.0.4_qxidjfl7kplxks3jglwjyrcjce: + /eslint-config-vuepress/4.0.4_udtwlmtl3kiiub6agmjl3rmgge: resolution: {integrity: sha512-MUd3IYOTVQfzuL/lAvSJPGMrJEus2/PVbQHs01N5AQw5MXc7kdhbaTJU3melExmgRe08meH88On9lNBmzbw/SQ==} peerDependencies: prettier: ^2.8.0 @@ -7275,13 +7487,13 @@ packages: prettier-config-vuepress: optional: true dependencies: - eslint-config-prettier: 8.5.0_eslint@8.28.0 - eslint-config-standard: 17.0.0_5dakk4wnrkkieagghiqvu5yn4y - eslint-plugin-import: 2.26.0_eslint@8.28.0 - eslint-plugin-n: 15.5.1_eslint@8.28.0 - eslint-plugin-prettier: 4.2.1_cwlo2dingkvfydnaculr42urve - eslint-plugin-promise: 6.1.1_eslint@8.28.0 - prettier: 2.8.0 + eslint-config-prettier: 8.5.0_eslint@8.32.0 + eslint-config-standard: 17.0.0_aknt3kx5mck5jnsactbk5g4gdy + eslint-plugin-import: 2.26.0_eslint@8.32.0 + eslint-plugin-n: 15.6.0_eslint@8.32.0 + eslint-plugin-prettier: 4.2.1_uzdlkkftb3f76fa4on6dnxrnyi + eslint-plugin-promise: 6.1.1_eslint@8.32.0 + prettier: 2.8.3 prettier-config-vuepress: 4.0.0 transitivePeerDependencies: - '@typescript-eslint/parser' @@ -7300,7 +7512,37 @@ packages: - supports-color dev: true - /eslint-module-utils/2.7.4_kr6tb4mi2cmpd7whrqyyy67tyi: + /eslint-module-utils/2.7.4_7gr2yud7moko5ggdmscvhh4rd4: + resolution: {integrity: sha512-j4GT+rqzCoRKHwURX7pddtIPGySnX9Si/cgMI5ztrcqOPtk5dDEeZ34CQVPphnqkJytlc97Vuk05Um2mJ3gEQA==} + engines: {node: '>=4'} + peerDependencies: + '@typescript-eslint/parser': '*' + eslint: '*' + eslint-import-resolver-node: '*' + eslint-import-resolver-typescript: '*' + eslint-import-resolver-webpack: '*' + peerDependenciesMeta: + '@typescript-eslint/parser': + optional: true + eslint: + optional: true + eslint: + optional: true + eslint-import-resolver-node: + optional: true + eslint-import-resolver-typescript: + optional: true + eslint-import-resolver-webpack: + optional: true + dependencies: + debug: 3.2.7 + eslint: 8.32.0 + eslint-import-resolver-node: 0.3.6 + transitivePeerDependencies: + - supports-color + dev: true + + /eslint-module-utils/2.7.4_gus4c32aq4cur7bb6tlulemjma: resolution: {integrity: sha512-j4GT+rqzCoRKHwURX7pddtIPGySnX9Si/cgMI5ztrcqOPtk5dDEeZ34CQVPphnqkJytlc97Vuk05Um2mJ3gEQA==} engines: {node: '>=4'} peerDependencies: @@ -7321,54 +7563,26 @@ packages: eslint-import-resolver-webpack: optional: true dependencies: - '@typescript-eslint/parser': 5.45.0_hsf322ms6xhhd4b5ne6lb74y4a + '@typescript-eslint/parser': 5.47.1_7uibuqfxkfaozanbtbziikiqje debug: 3.2.7 - eslint: 8.28.0 + eslint: 8.32.0 eslint-import-resolver-node: 0.3.6 transitivePeerDependencies: - supports-color dev: true - /eslint-module-utils/2.7.4_sjge656jyd3rr27cepuzx7h5u4: - resolution: {integrity: sha512-j4GT+rqzCoRKHwURX7pddtIPGySnX9Si/cgMI5ztrcqOPtk5dDEeZ34CQVPphnqkJytlc97Vuk05Um2mJ3gEQA==} - engines: {node: '>=4'} - peerDependencies: - '@typescript-eslint/parser': '*' - eslint: '*' - eslint-import-resolver-node: '*' - eslint-import-resolver-typescript: '*' - eslint-import-resolver-webpack: '*' - peerDependenciesMeta: - '@typescript-eslint/parser': - optional: true - eslint: - optional: true - eslint-import-resolver-node: - optional: true - eslint-import-resolver-typescript: - optional: true - eslint-import-resolver-webpack: - optional: true - dependencies: - debug: 3.2.7 - eslint: 8.28.0 - eslint-import-resolver-node: 0.3.6 - transitivePeerDependencies: - - supports-color - dev: true - - /eslint-plugin-es/4.1.0_eslint@8.28.0: + /eslint-plugin-es/4.1.0_eslint@8.32.0: resolution: {integrity: sha512-GILhQTnjYE2WorX5Jyi5i4dz5ALWxBIdQECVQavL6s7cI76IZTDWleTHkxz/QT3kvcs2QlGHvKLYsSlPOlPXnQ==} engines: {node: '>=8.10.0'} peerDependencies: eslint: '>=4.19.1' dependencies: - eslint: 8.28.0 + eslint: 8.32.0 eslint-utils: 2.1.0 regexpp: 3.2.0 dev: true - /eslint-plugin-import/2.26.0_eslint@8.28.0: + /eslint-plugin-import/2.26.0_eslint@8.32.0: resolution: {integrity: sha512-hYfi3FXaM8WPLf4S1cikh/r4IxnO6zrhZbEGz2b660EJRbuxgpDS5gkCuYgGWg2xxh2rBuIr4Pvhve/7c31koA==} engines: {node: '>=4'} peerDependencies: @@ -7382,9 +7596,9 @@ packages: array.prototype.flat: 1.3.1 debug: 2.6.9 doctrine: 2.1.0 - eslint: 8.28.0 + eslint: 8.32.0 eslint-import-resolver-node: 0.3.6 - eslint-module-utils: 2.7.4_sjge656jyd3rr27cepuzx7h5u4 + eslint-module-utils: 2.7.4_7gr2yud7moko5ggdmscvhh4rd4 has: 1.0.3 is-core-module: 2.11.0 is-glob: 4.0.3 @@ -7398,7 +7612,7 @@ packages: - supports-color dev: true - /eslint-plugin-import/2.26.0_vbnhqcxlbs7ynbxw44hu2vq7eq: + /eslint-plugin-import/2.26.0_xr5b6h7hlz4fzi2dbv6u6mr45e: resolution: {integrity: sha512-hYfi3FXaM8WPLf4S1cikh/r4IxnO6zrhZbEGz2b660EJRbuxgpDS5gkCuYgGWg2xxh2rBuIr4Pvhve/7c31koA==} engines: {node: '>=4'} peerDependencies: @@ -7408,14 +7622,14 @@ packages: '@typescript-eslint/parser': optional: true dependencies: - '@typescript-eslint/parser': 5.45.0_hsf322ms6xhhd4b5ne6lb74y4a + '@typescript-eslint/parser': 5.47.1_7uibuqfxkfaozanbtbziikiqje array-includes: 3.1.6 array.prototype.flat: 1.3.1 debug: 2.6.9 doctrine: 2.1.0 - eslint: 8.28.0 + eslint: 8.32.0 eslint-import-resolver-node: 0.3.6 - eslint-module-utils: 2.7.4_kr6tb4mi2cmpd7whrqyyy67tyi + eslint-module-utils: 2.7.4_gus4c32aq4cur7bb6tlulemjma has: 1.0.3 is-core-module: 2.11.0 is-glob: 4.0.3 @@ -7429,24 +7643,24 @@ packages: - supports-color dev: true - /eslint-plugin-n/15.5.1_eslint@8.28.0: - resolution: {integrity: sha512-kAd+xhZm7brHoFLzKLB7/FGRFJNg/srmv67mqb7tto22rpr4wv/LV6RuXzAfv3jbab7+k1wi42PsIhGviywaaw==} + /eslint-plugin-n/15.6.0_eslint@8.32.0: + resolution: {integrity: sha512-Hd/F7wz4Mj44Jp0H6Jtty13NcE69GNTY0rVlgTIj1XBnGGVI6UTdDrpE6vqu3AHo07bygq/N+7OH/lgz1emUJw==} engines: {node: '>=12.22.0'} peerDependencies: eslint: '>=7.0.0' dependencies: builtins: 5.0.1 - eslint: 8.28.0 - eslint-plugin-es: 4.1.0_eslint@8.28.0 - eslint-utils: 3.0.0_eslint@8.28.0 - ignore: 5.2.1 + eslint: 8.32.0 + eslint-plugin-es: 4.1.0_eslint@8.32.0 + eslint-utils: 3.0.0_eslint@8.32.0 + ignore: 5.2.4 is-core-module: 2.11.0 minimatch: 3.1.2 resolve: 1.22.1 semver: 7.3.8 dev: true - /eslint-plugin-prettier/4.2.1_cwlo2dingkvfydnaculr42urve: + /eslint-plugin-prettier/4.2.1_uzdlkkftb3f76fa4on6dnxrnyi: resolution: {integrity: sha512-f/0rXLXUt0oFYs8ra4w49wYZBG5GKZpAYsJSm6rnYL5uVDjd+zowwMwVZHnAjf4edNrKpCDYfXDgmRE/Ak7QyQ==} engines: {node: '>=12.0.0'} peerDependencies: @@ -7457,34 +7671,34 @@ packages: eslint-config-prettier: optional: true dependencies: - eslint: 8.28.0 - eslint-config-prettier: 8.5.0_eslint@8.28.0 - prettier: 2.8.0 + eslint: 8.32.0 + eslint-config-prettier: 8.5.0_eslint@8.32.0 + prettier: 2.8.3 prettier-linter-helpers: 1.0.0 dev: true - /eslint-plugin-promise/6.1.1_eslint@8.28.0: + /eslint-plugin-promise/6.1.1_eslint@8.32.0: resolution: {integrity: sha512-tjqWDwVZQo7UIPMeDReOpUgHCmCiH+ePnVT+5zVapL0uuHnegBUs2smM13CzOs2Xb5+MHMRFTs9v24yjba4Oig==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: eslint: ^7.0.0 || ^8.0.0 dependencies: - eslint: 8.28.0 + eslint: 8.32.0 dev: true - /eslint-plugin-vue/9.8.0_eslint@8.28.0: + /eslint-plugin-vue/9.8.0_eslint@8.32.0: resolution: {integrity: sha512-E/AXwcTzunyzM83C2QqDHxepMzvI2y6x+mmeYHbVDQlKFqmKYvRrhaVixEeeG27uI44p9oKDFiyCRw4XxgtfHA==} engines: {node: ^14.17.0 || >=16.0.0} peerDependencies: eslint: ^6.2.0 || ^7.0.0 || ^8.0.0 dependencies: - eslint: 8.28.0 - eslint-utils: 3.0.0_eslint@8.28.0 + eslint: 8.32.0 + eslint-utils: 3.0.0_eslint@8.32.0 natural-compare: 1.4.0 nth-check: 2.1.1 postcss-selector-parser: 6.0.11 semver: 7.3.8 - vue-eslint-parser: 9.1.0_eslint@8.28.0 + vue-eslint-parser: 9.1.0_eslint@8.32.0 xml-name-validator: 4.0.0 transitivePeerDependencies: - supports-color @@ -7512,13 +7726,13 @@ packages: eslint-visitor-keys: 1.3.0 dev: true - /eslint-utils/3.0.0_eslint@8.28.0: + /eslint-utils/3.0.0_eslint@8.32.0: resolution: {integrity: sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==} engines: {node: ^10.0.0 || ^12.0.0 || >= 14.0.0} peerDependencies: eslint: '>=5' dependencies: - eslint: 8.28.0 + eslint: 8.32.0 eslint-visitor-keys: 2.1.0 dev: true @@ -7536,13 +7750,13 @@ packages: resolution: {integrity: sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - /eslint/8.28.0: - resolution: {integrity: sha512-S27Di+EVyMxcHiwDrFzk8dJYAaD+/5SoWKxL1ri/71CRHsnJnRDPNt2Kzj24+MT9FDupf4aqqyqPrvI8MvQ4VQ==} + /eslint/8.32.0: + resolution: {integrity: sha512-nETVXpnthqKPFyuY2FNjz/bEd6nbosRgKbkgS/y1C7LJop96gYHWpiguLecMHQ2XCPxn77DS0P+68WzG6vkZSQ==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} hasBin: true dependencies: - '@eslint/eslintrc': 1.3.3 - '@humanwhocodes/config-array': 0.11.7 + '@eslint/eslintrc': 1.4.1 + '@humanwhocodes/config-array': 0.11.8 '@humanwhocodes/module-importer': 1.0.1 '@nodelib/fs.walk': 1.2.8 ajv: 6.12.6 @@ -7552,7 +7766,7 @@ packages: doctrine: 3.0.0 escape-string-regexp: 4.0.0 eslint-scope: 7.1.1 - eslint-utils: 3.0.0_eslint@8.28.0 + eslint-utils: 3.0.0_eslint@8.32.0 eslint-visitor-keys: 3.3.0 espree: 9.4.1 esquery: 1.4.0 @@ -7561,9 +7775,9 @@ packages: file-entry-cache: 6.0.1 find-up: 5.0.0 glob-parent: 6.0.2 - globals: 13.18.0 + globals: 13.19.0 grapheme-splitter: 1.0.4 - ignore: 5.2.1 + ignore: 5.2.4 import-fresh: 3.3.0 imurmurhash: 0.1.4 is-glob: 4.0.3 @@ -7849,8 +8063,22 @@ packages: - supports-color dev: false - /fast-clone/1.5.13: - resolution: {integrity: sha512-0ez7coyFBQFjZtId+RJqJ+EQs61w9xARfqjqK0AD9vIUkSxWD4HvPt80+5evebZ1tTnv1GYKrPTipx7kOW5ipA==} + /extract-zip/2.0.1: + resolution: {integrity: sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==} + engines: {node: '>= 10.17.0'} + hasBin: true + dependencies: + debug: 4.3.4 + get-stream: 5.2.0 + yauzl: 2.10.0 + optionalDependencies: + '@types/yauzl': 2.10.0 + transitivePeerDependencies: + - supports-color + dev: false + + /fast-decode-uri-component/1.0.1: + resolution: {integrity: sha512-WKgKWg5eUxvRZGwW8FvfbaH7AXSh2cL+3j5fMGzUMCxWBJ3dV3a7Wz8y2f/uQ0e3B6WmodD3oS54jTQ9HVTIIg==} dev: false /fast-deep-equal/3.1.3: @@ -7890,15 +8118,67 @@ packages: /fast-json-stable-stringify/2.1.0: resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} + /fast-json-stringify/5.5.0: + resolution: {integrity: sha512-rmw2Z8/mLkND8zI+3KTYIkNPEoF5v6GqDP/o+g7H3vjdWjBwuKpgAYFHIzL6ORRB+iqDjjtJnLIW9Mzxn5szOA==} + dependencies: + '@fastify/deepmerge': 1.3.0 + ajv: 8.11.2 + ajv-formats: 2.1.1 + fast-deep-equal: 3.1.3 + fast-uri: 2.2.0 + rfdc: 1.3.0 + dev: false + /fast-levenshtein/2.0.6: resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} + /fast-querystring/1.1.0: + resolution: {integrity: sha512-LWkjBCZlxjnSanuPpZ6mHswjy8hQv3VcPJsQB3ltUF2zjvrycr0leP3TSTEEfvQ1WEMSRl5YNsGqaft9bjLqEw==} + dependencies: + fast-decode-uri-component: 1.0.1 + dev: false + + /fast-redact/3.1.2: + resolution: {integrity: sha512-+0em+Iya9fKGfEQGcd62Yv6onjBmmhV1uh86XVfOU8VwAe6kaFdQCWI9s0/Nnugx5Vd9tdbZ7e6gE2tR9dzXdw==} + engines: {node: '>=6'} + dev: false + /fast-safe-stringify/2.1.1: resolution: {integrity: sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==} dev: false - /fastq/1.13.0: - resolution: {integrity: sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==} + /fast-uri/2.2.0: + resolution: {integrity: sha512-cIusKBIt/R/oI6z/1nyfe2FvGKVTohVRfvkOhvx0nCEW+xf5NoCXjAHcWp93uOUBchzYcsvPlrapAdX1uW+YGg==} + dev: false + + /fastify-plugin/4.5.0: + resolution: {integrity: sha512-79ak0JxddO0utAXAQ5ccKhvs6vX2MGyHHMMsmZkBANrq3hXc1CHzvNPHOcvTsVMEPl5I+NT+RO4YKMGehOfSIg==} + dev: false + + /fastify/4.11.0: + resolution: {integrity: sha512-JteZ8pjEqd+6n+azQnQfSJV8MUMxAmxbvC2Dx/Mybj039Lf/u3kda9Kq84uy/huCpqCzZoyHIZS5JFGF3wLztw==} + dependencies: + '@fastify/ajv-compiler': 3.5.0 + '@fastify/error': 3.2.0 + '@fastify/fast-json-stringify-compiler': 4.2.0 + abstract-logging: 2.0.1 + avvio: 8.2.0 + content-type: 1.0.4 + find-my-way: 7.4.0 + light-my-request: 5.8.0 + pino: 8.8.0 + process-warning: 2.1.0 + proxy-addr: 2.0.7 + rfdc: 1.3.0 + secure-json-parse: 2.7.0 + semver: 7.3.8 + tiny-lru: 10.0.1 + transitivePeerDependencies: + - supports-color + dev: false + + /fastq/1.14.0: + resolution: {integrity: sha512-eR2D+V9/ExcbF9ls441yIuN6TI2ED1Y2ZcA5BmMtJsOkWOFRJQ0Jt0g1UwqXJJVAb+V+umH5Dfr8oh4EVP7VVg==} dependencies: reusify: 1.0.4 @@ -7979,10 +8259,6 @@ packages: flat-cache: 3.0.4 dev: true - /file-size/0.0.5: - resolution: {integrity: sha1-BX1Dw6Ptc12j+Q1gUqs4Dx5tXjs=} - dev: false - /file-type/11.1.0: resolution: {integrity: sha512-rM0UO7Qm9K7TWTtA6AShI/t7H5BPjDeGVDaNyg9BjHAj3PysKy7+8C8D137R88jnR3rFJZQB/tFgydl5sN5m7g==} engines: {node: '>=6'} @@ -8090,6 +8366,15 @@ packages: /find-index/0.1.1: resolution: {integrity: sha512-uJ5vWrfBKMcE6y2Z8834dwEZj9mNGxYa3t3I53OwFeuZ8D9oc2E5zcsrkuhX6h4iYrjhiv0T3szQmxlAV9uxDg==} + /find-my-way/7.4.0: + resolution: {integrity: sha512-JFT7eURLU5FumlZ3VBGnveId82cZz7UR7OUu+THQJOwdQXxmS/g8v0KLoFhv97HreycOrmAbqjXD/4VG2j0uMQ==} + engines: {node: '>=14'} + dependencies: + fast-deep-equal: 3.1.3 + fast-querystring: 1.1.0 + safe-regex2: 2.0.0 + dev: false + /find-node-modules/2.1.3: resolution: {integrity: sha512-UC2I2+nx1ZuOBclWVNdcnbDR5dlrOdVb7xNjmT/lHE+LsgztWks3dG7boJ37yTS/venXw84B/mAW9uHVoC5QRg==} dependencies: @@ -8106,7 +8391,6 @@ packages: engines: {node: '>=4'} dependencies: locate-path: 2.0.0 - dev: true /find-up/4.1.0: resolution: {integrity: sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==} @@ -8152,11 +8436,12 @@ packages: resolution: {integrity: sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==} dev: true - /flowchart.js/1.17.1: - resolution: {integrity: sha512-zphTaxdyqvHHu+8Cdf6HvamhArXpq9SyNe1zQ61maCIfTenaj3cMvjS1e/0gfPj7QTLTx3HroSzVqDXpL8naoQ==} - engines: {node: '>=4.0.0'} + /flowchart.ts/0.1.2: + resolution: {integrity: sha512-4N8U2gXTkWUYh57SkCYwnSBM2B9Djia+JjClx/rLA13m0xz2S5BZht/9DvTZH5yXGZkmk7NGxGB15tnbUSI6mg==} dependencies: + '@types/raphael': 2.3.3 raphael: 2.3.0 + tslib: 2.4.1 dev: false /flush-write-stream/2.0.0: @@ -8287,6 +8572,14 @@ packages: jsonfile: 6.1.0 universalify: 2.0.0 + /fs-extra/11.1.0: + resolution: {integrity: sha512-0rcTq621PD5jM/e0a3EJoGC/1TC5ZBCERW82LQuwfGnCa1V8w7dpYH1yNu+SLb6E5dkeCBzKEyLGlFrnr+dUyw==} + engines: {node: '>=14.14'} + dependencies: + graceful-fs: 4.2.10 + jsonfile: 6.1.0 + universalify: 2.0.0 + /fs-extra/9.1.0: resolution: {integrity: sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==} engines: {node: '>=10'} @@ -8326,7 +8619,7 @@ packages: dependencies: call-bind: 1.0.2 define-properties: 1.1.4 - es-abstract: 1.20.4 + es-abstract: 1.20.5 functions-have-names: 1.2.3 dev: true @@ -8401,7 +8694,6 @@ packages: hosted-git-info: 4.1.0 through2: 2.0.5 yargs: 16.2.0 - dev: true /get-port/5.1.1: resolution: {integrity: sha512-g/Q1aTSDOxFpchXC4i8ZWvxA1lnPqx/JHqcpIw0/LX9T8x/GBbi6YnlN5nhaKIFkT8oFsscUKgDJYxfwfS6QsQ==} @@ -8471,10 +8763,10 @@ packages: - encoding dev: false - /giscus/1.2.4: - resolution: {integrity: sha512-c//t+vrEDNJ3jcM2TLz6UG7gZHyRDdYtj2PV0TaKk8eKMfq4OB8K1BFclaQ0UbUh6UN6hp89BNJTTcnibkiILA==} + /giscus/1.2.6: + resolution: {integrity: sha512-VqMWmCdlUk9krX2M3oMgn9/Y6XEbRXRHtfhNTuRn/AdeGOeko54OFEIsizQ/nYWymuUNGZR48KGptCtYL77rtA==} dependencies: - lit: 2.4.1 + lit: 2.5.0 dev: false /git-hooks-list/3.0.0: @@ -8491,7 +8783,6 @@ packages: meow: 8.1.2 split2: 3.2.2 through2: 4.0.2 - dev: true /git-remote-origin-url/2.0.0: resolution: {integrity: sha512-eU+GGrZgccNJcsDH5LkXR3PB9M958hxc7sbA8DFJjrv9j4L2P/eZfKhM+QD6wyzpiv+b1BpK0XrYCxkovtjSLw==} @@ -8499,7 +8790,6 @@ packages: dependencies: gitconfiglocal: 1.0.0 pify: 2.3.0 - dev: true /git-repo-info/2.1.1: resolution: {integrity: sha512-8aCohiDo4jwjOwma4FmYFd3i97urZulL8XL24nIPxuE+GZnfsAyy/g2Shqx6OjUiFKUXZM+Yy+KHnOmmA3FVcg==} @@ -8513,13 +8803,11 @@ packages: dependencies: meow: 8.1.2 semver: 6.3.0 - dev: true /gitconfiglocal/1.0.0: resolution: {integrity: sha512-spLUXeTAVHxDtKsJc8FkFVgFtMdEN9qPGpL23VfSHx4fP4+Ds097IXLvymbnDH8FnmxX5Nr9bPw3A+AQ6mWEaQ==} dependencies: ini: 1.3.8 - dev: true /gitconfiglocal/2.1.0: resolution: {integrity: sha512-qoerOEliJn3z+Zyn1HW2F6eoYJqKwS6MgC9cztTLUB/xLWX8gD/6T60pKn4+t/d6tP7JlybI7Z3z+I572CR/Vg==} @@ -8532,7 +8820,7 @@ packages: engines: {node: '>= 6'} dependencies: glob: 7.2.3 - ignore: 5.2.1 + ignore: 5.2.4 lodash.difference: 4.5.0 lodash.union: 4.6.0 make-array: 1.0.5 @@ -8582,7 +8870,7 @@ packages: fs.realpath: 1.0.0 inflight: 1.0.6 inherits: 2.0.4 - minimatch: 5.1.0 + minimatch: 5.1.2 once: 1.4.0 /glob2base/0.0.12: @@ -8638,8 +8926,8 @@ packages: engines: {node: '>=4'} dev: false - /globals/13.18.0: - resolution: {integrity: sha512-/mR4KI8Ps2spmoc0Ulu9L7agOF0du1CZNQ3dke8yItYlyKNmGrkONemBbd6V8UTc1Wgcqn21t3WYB7dbRmh6/A==} + /globals/13.19.0: + resolution: {integrity: sha512-dkQ957uSRWHw7CFXLUtUHQI3g3aWApYhfNR2O6jn/907riyTYKVBmxYVROkBcY614FSSeSJh7Xm7SrUWCxvJMQ==} engines: {node: '>=8'} dependencies: type-fest: 0.20.2 @@ -8652,17 +8940,17 @@ packages: array-union: 2.1.0 dir-glob: 3.0.1 fast-glob: 3.2.12 - ignore: 5.2.1 + ignore: 5.2.4 merge2: 1.4.1 slash: 3.0.0 - /globby/13.1.2: - resolution: {integrity: sha512-LKSDZXToac40u8Q1PQtZihbNdTYSNMuWe+K5l+oa6KgDzSvVrHXlJy40hUP522RjAIoNLJYBJi7ow+rbFpIhHQ==} + /globby/13.1.3: + resolution: {integrity: sha512-8krCNHXvlCgHDpegPzleMq07yMYTO2sXKASmZmquEYWEmCx6J5UTRbp5RwMJkTJGtcQ44YpiUYUiN0b9mzy8Bw==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} dependencies: dir-glob: 3.0.1 fast-glob: 3.2.12 - ignore: 5.2.1 + ignore: 5.2.4 merge2: 1.4.1 slash: 4.0.0 @@ -8690,6 +8978,12 @@ packages: minimist: 1.2.7 dev: false + /gopd/1.0.1: + resolution: {integrity: sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==} + dependencies: + get-intrinsic: 1.1.3 + dev: true + /got/10.7.0: resolution: {integrity: sha512-aWTDeNw9g+XqEZNcTjMMZSy7B7yE9toWOFYip7ofFTLleJhvZwUxxTxkTpKvF+p1SAA4VHmuEy7PiHTHyq8tJg==} engines: {node: '>=10'} @@ -8720,7 +9014,7 @@ packages: '@sindresorhus/is': 5.3.0 '@szmarczak/http-timer': 5.0.1 cacheable-lookup: 7.0.0 - cacheable-request: 10.2.3 + cacheable-request: 10.2.4 decompress-response: 6.0.0 form-data-encoder: 2.1.4 get-stream: 6.0.1 @@ -8781,12 +9075,6 @@ packages: resolution: {integrity: sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==} dev: true - /graphlib/2.1.8: - resolution: {integrity: sha512-jcLLfkpoVGmH7/InMC/1hIvOPSUh38oJtGhvrOFGzioE1DZ+0YW16RgmOJhHiuWTvGiJQ9Z1Ik43JvkRPRvE+A==} - dependencies: - lodash: 4.17.21 - dev: false - /graphql/16.5.0: resolution: {integrity: sha512-qbHgh8Ix+j/qY+a/ZcJnFQ+j8ezakqPiHwPiZhV/3PgGlgf96QMBB5/f2rkiC9sgLoy/xvT6TSiaf2nTHJh5iA==} engines: {node: ^12.22.0 || ^14.16.0 || ^16.0.0 || >=17.0.0} @@ -8817,20 +9105,10 @@ packages: wordwrap: 1.0.0 optionalDependencies: uglify-js: 3.17.4 - dev: true /hard-rejection/2.1.0: resolution: {integrity: sha512-VIZB+ibDhx7ObhAe7OVtoEbuP4h/MuOTHJ+J8h/eBXotJYl0fBgR72xDFCKgIh22OJZIOVNxBMWuhAr10r8HdA==} engines: {node: '>=6'} - dev: true - - /has-ansi/0.1.0: - resolution: {integrity: sha512-1YsTg1fk2/6JToQhtZkArMkurq8UoWU1Qe0aR3VUHjgij4nOylSWLWAtBXoZ4/dXOmugfLGm1c+QhuD0JyedFA==} - engines: {node: '>=0.10.0'} - hasBin: true - dependencies: - ansi-regex: 0.2.1 - dev: false /has-ansi/2.0.0: resolution: {integrity: sha512-C8vBJ8DwUCx19vhm7urhTuUsr4/IyP6l4VzNQDv+ryHQObW3TTTp9yB68WpYgRe2bbaGuZ/se74IqFeVnMnLZg==} @@ -8959,6 +9237,10 @@ packages: hasBin: true dev: false + /heap/0.2.7: + resolution: {integrity: sha512-2bsegYkkHO+h/9MGbn6KWcE45cHZgPANo5LXF7EvWdT0yT2EguSVO1nDgU5c8+ZOPwp2vMNa7YFsJhVcDR9Sdg==} + dev: false + /homedir-polyfill/1.0.3: resolution: {integrity: sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA==} engines: {node: '>=0.10.0'} @@ -8982,6 +9264,13 @@ packages: lru-cache: 7.14.1 dev: true + /hot-shots/9.3.0: + resolution: {integrity: sha512-e4tgWptiBvlIMnAX0ORe+dNEt0HznD+T2ckzXDUwCBsU7uWr2mwq5UtoT+Df5r9hD5S/DuP8rTxJUQvqAFSFKA==} + engines: {node: '>=6.0.0'} + optionalDependencies: + unix-dgram: 2.0.6 + dev: false + /hpack.js/2.1.6: resolution: {integrity: sha512-zJxVehUdMGIKsRaNt7apO2Gqp0BdqW5yaiGHXXmbpvxgBYVZnAql+BJb4RO5ad2MgpbZKn5G6nMnegrH1FcNYQ==} dependencies: @@ -9026,15 +9315,6 @@ packages: webpack: 5.75.0 dev: false - /htmlparser2/5.0.1: - resolution: {integrity: sha512-vKZZra6CSe9qsJzh0BjBGXo8dvzNsq/oGvsjfRdOrrryfeD9UOBEEQdeoqCRmKZchF5h2zOBMQ6YuQ0uRUmdbQ==} - dependencies: - domelementtype: 2.3.0 - domhandler: 3.3.0 - domutils: 2.8.0 - entities: 2.2.0 - dev: false - /htmlparser2/6.1.0: resolution: {integrity: sha512-gyyPk6rgonLFEDGoeRgQNaEUvdJ4ktTmmUh/h2t7s+M8oPpIPxgNACWa+6ESR57kXstwqPiCut0V8NRpcwgU7A==} dependencies: @@ -9044,6 +9324,15 @@ packages: entities: 2.2.0 dev: false + /htmlparser2/8.0.1: + resolution: {integrity: sha512-4lVbmc1diZC7GUJQtRQ5yBAeUCL1exyMwmForWkRLnwyzWBFxN633SALPMGYaWZvKe9j1pRZJpauvmxENSp/EA==} + dependencies: + domelementtype: 2.3.0 + domhandler: 5.0.3 + domutils: 3.0.1 + entities: 4.4.0 + dev: false + /http-cache-semantics/3.8.1: resolution: {integrity: sha512-5ai2iksyV8ZXmnZhHH4rWPoxxistEexSi5936zIQ1bnNTW5VnA85B6P/VpXiRM017IgRvb2kKo1a//y+0wSp3w==} dev: false @@ -9115,7 +9404,7 @@ packages: - supports-color dev: false - /http-proxy-middleware/2.0.6_@types+express@4.17.14: + /http-proxy-middleware/2.0.6_@types+express@4.17.15: resolution: {integrity: sha512-ya/UeJ6HVBYxrgYotAZo1KvPWlgB48kUJLDePFeneHsVujFaW5WNj2NgWCAE//B1Dl02BIfYlpNgBy8Kf8Rjmw==} engines: {node: '>=12.0.0'} peerDependencies: @@ -9124,7 +9413,7 @@ packages: '@types/express': optional: true dependencies: - '@types/express': 4.17.14 + '@types/express': 4.17.15 '@types/http-proxy': 1.17.9 http-proxy: 1.18.1 is-glob: 4.0.3 @@ -9226,8 +9515,8 @@ packages: ms: 2.1.3 dev: true - /husky/8.0.2: - resolution: {integrity: sha512-Tkv80jtvbnkK3mYWxPZePGFpQ/tT3HNSs/sasF9P2YfkMezDl3ON37YN6jUUI4eTg5LcyVynlb6r4eyvOmspvg==} + /husky/8.0.3: + resolution: {integrity: sha512-+dQSyqPh4x1hlO1swXBiNb2HzTDN1I2IGLQx1GrBuiqFJfoMrnZWwVmatvSiO+Iz8fBUnf+lekwNo4c2LlXItg==} engines: {node: '>=14'} hasBin: true dev: true @@ -9244,7 +9533,7 @@ packages: dependencies: safer-buffer: 2.1.2 - /icss-utils/5.1.0_postcss@8.4.19: + /icss-utils/5.1.0_postcss@8.4.20: resolution: {integrity: sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA==} engines: {node: ^10 || ^12 || >= 14} peerDependencies: @@ -9253,7 +9542,7 @@ packages: postcss: optional: true dependencies: - postcss: 8.4.19 + postcss: 8.4.20 dev: false /ieee754/1.2.1: @@ -9263,7 +9552,7 @@ packages: resolution: {integrity: sha512-yemi4pMf51WKT7khInJqAvsIGzoqYXblnsz0ql8tM+yi1EKYTY1evX4NAbJrLL/Aanr2HyZeluqU+Oi7MGHokw==} engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} dependencies: - minimatch: 5.1.0 + minimatch: 5.1.2 dev: true /ignore/4.0.6: @@ -9271,8 +9560,8 @@ packages: engines: {node: '>= 4'} dev: false - /ignore/5.2.1: - resolution: {integrity: sha512-d2qQLzTJ9WxQftPAuEQpSPmKqzxePjzVbpAVv62AQ64NTL+wR4JkrVqR/LqFsFEUsHDAiId52mJteHDFuDkElA==} + /ignore/5.2.4: + resolution: {integrity: sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==} engines: {node: '>= 4'} /immutable/4.1.0: @@ -9391,15 +9680,15 @@ packages: mute-stream: 0.0.8 ora: 5.4.1 run-async: 2.4.1 - rxjs: 7.5.7 + rxjs: 7.8.0 string-width: 4.2.3 strip-ansi: 6.0.1 through: 2.3.8 wrap-ansi: 7.0.0 dev: true - /internal-slot/1.0.3: - resolution: {integrity: sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA==} + /internal-slot/1.0.4: + resolution: {integrity: sha512-tA8URYccNzMo94s5MQZgH8NB/XTa6HsOo0MLfXTKKEnHVVdegzaQoFZ7Jp44bdvLvY2waT5dc+j5ICEswhi7UQ==} engines: {node: '>= 0.4'} dependencies: get-intrinsic: 1.1.3 @@ -9508,7 +9797,7 @@ packages: resolution: {integrity: sha512-ZYvCgrefwqoQ6yTyYUbQu64HsITZ3NfKX1lzaEYdkTDcfKzzCI/wthRRYKkdjHKFVgNiXKAKm65Zo1pk2as/QQ==} hasBin: true dependencies: - ci-info: 3.7.0 + ci-info: 3.3.2 dev: false /is-core-module/2.11.0: @@ -9790,7 +10079,6 @@ packages: engines: {node: '>=0.10.0'} dependencies: text-extensions: 1.9.0 - dev: true /is-typedarray/1.0.0: resolution: {integrity: sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==} @@ -9827,11 +10115,6 @@ packages: resolution: {integrity: sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==} engines: {node: '>=0.10.0'} - /is-wsl/1.1.0: - resolution: {integrity: sha512-gfygJYZ2gLTDlmbWMI0CE2MwnFzSN/2SZfkMlItC4K/JBlsWVDB0bO6XhqcY13YXE7iMcAJnzTCJjPiTeJJ0Mw==} - engines: {node: '>=4'} - dev: false - /is-wsl/2.2.0: resolution: {integrity: sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==} engines: {node: '>=8'} @@ -9924,7 +10207,7 @@ packages: resolution: {integrity: sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==} engines: {node: '>= 10.13.0'} dependencies: - '@types/node': 18.11.9 + '@types/node': 18.11.18 merge-stream: 2.0.0 supports-color: 8.1.1 dev: false @@ -9980,7 +10263,6 @@ packages: /json-parse-better-errors/1.0.2: resolution: {integrity: sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==} - dev: true /json-parse-even-better-errors/2.3.1: resolution: {integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==} @@ -10002,7 +10284,6 @@ packages: /json-stringify-safe/5.0.1: resolution: {integrity: sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==} - dev: true /json2yaml/1.1.0: resolution: {integrity: sha512-/xse+m0SlllfZahQrNOelmLrFNfeZv4QG0QKlvg7VsPSGIxpB3X+ggLkdffwmI1DdQ3o9XjZX+K+EOI1epdKgg==} @@ -10019,12 +10300,16 @@ packages: minimist: 1.2.7 dev: true - /json5/2.2.1: - resolution: {integrity: sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==} + /json5/2.2.3: + resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==} engines: {node: '>=6'} hasBin: true dev: false + /jsonc-parser/3.2.0: + resolution: {integrity: sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==} + dev: false + /jsonfile/6.1.0: resolution: {integrity: sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==} dependencies: @@ -10035,41 +10320,20 @@ packages: /jsonparse/1.3.1: resolution: {integrity: sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg==} engines: {'0': node >= 0.2.0} - dev: true /jsonpointer/5.0.1: resolution: {integrity: sha512-p/nXbhSEcu3pZRdkW1OfJhpsVtW1gd4Wa1fnQc9YLiTfAjn0312eMKimbdIQzuZl9aa9xUGaRlP9T/CJE/ditQ==} engines: {node: '>=0.10.0'} dev: false - /jsonwebtoken/8.5.1: - resolution: {integrity: sha512-XjwVfRS6jTMsqYs0EsuJ4LGxXV14zQybNd4L2r0UvbVnSF9Af8x7p5MzbJ90Ioz/9TI41/hTCvznF/loiSzn8w==} - engines: {node: '>=4', npm: '>=1.4.28'} + /jsonwebtoken/9.0.0: + resolution: {integrity: sha512-tuGfYXxkQGDPnLJ7SibiQgVgeDgfbPq2k2ICcbgqW8WxWLBAxKQM/ZCu/IT8SOSwmaYl4dpTFCW5xZv7YbbWUw==} + engines: {node: '>=12', npm: '>=6'} dependencies: jws: 3.2.2 - lodash.includes: 4.3.0 - lodash.isboolean: 3.0.3 - lodash.isinteger: 4.0.4 - lodash.isnumber: 3.0.3 - lodash.isplainobject: 4.0.6 - lodash.isstring: 4.0.1 - lodash.once: 4.1.1 + lodash: 4.17.21 ms: 2.1.3 - semver: 5.7.1 - dev: false - - /juice/8.1.0: - resolution: {integrity: sha512-FLzurJrx5Iv1e7CfBSZH68dC04EEvXvvVvPYB7Vx1WAuhCp1ZPIMtqxc+WTWxVkpTIC2Ach/GAv0rQbtGf6YMA==} - engines: {node: '>=10.0.0'} - hasBin: true - dependencies: - cheerio: 1.0.0-rc.10 - commander: 6.2.1 - mensch: 0.3.4 - slick: 1.12.2 - web-resource-inliner: 6.0.1 - transitivePeerDependencies: - - encoding + semver: 7.3.8 dev: false /junk/3.1.0: @@ -10101,8 +10365,8 @@ packages: resolution: {integrity: sha512-UfpWE/VZn0iP50d8cz9NrZLM9lSWhcJ+0Gt/nm4by88UL+J1SiKN8/5dkjMmbEzwL2CAe+67GsegCbIKtbp75A==} dev: false - /katex/0.16.3: - resolution: {integrity: sha512-3EykQddareoRmbtNiNEDgl3IGjryyrp2eg/25fHDEnlHymIDi33bptkMv6K4EOC2LZCybLW/ZkEo6Le+EM9pmA==} + /katex/0.16.4: + resolution: {integrity: sha512-WudRKUj8yyBeVDI4aYMNxhx5Vhh2PjpzQw1GRu/LVGqL4m1AxwD1GcUp0IMbdJaf5zsjtj8ghP0DOQRYhroNkw==} hasBin: true dependencies: commander: 8.3.0 @@ -10163,12 +10427,10 @@ packages: /kleur/3.0.3: resolution: {integrity: sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==} engines: {node: '>=6'} - dev: true /kleur/4.1.5: resolution: {integrity: sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==} engines: {node: '>=6'} - dev: true /klona/2.0.5: resolution: {integrity: sha512-pJiBpiXMbt7dkzXe8Ghj/u4FfXOOa98fPW+bihOJ4SjnoijweJrNThJfd3ifXpXhREjpoF2mZVH1GfS9LV3kHQ==} @@ -10207,6 +10469,14 @@ packages: package-json: 8.1.0 dev: false + /layout-base/1.0.2: + resolution: {integrity: sha512-8h2oVEZNktL4BH2JCOI90iD1yXwL6iNW7KcCKT2QZgQJR2vbqDsldCTPRU9NifTCqHZci57XvQQ15YTu+sTYPg==} + dev: false + + /layout-base/2.0.1: + resolution: {integrity: sha512-dp3s92+uNI1hWIpPGH3jK2kxE2lMjdXdr+DH8ynZHpd6PUlH6x6cbuXnoMmiNumznqaNO31xu9e79F0uuZ0JFg==} + dev: false + /lazystream/1.0.1: resolution: {integrity: sha512-b94GiNHQNy6JNTrt5w6zNyffMrNkXZb3KTkCZJb2V1xaEGCk093vkZ2jk3tpaeP33/OiXC+WvK9AxUebnf5nbw==} engines: {node: '>= 0.6.3'} @@ -10251,8 +10521,8 @@ packages: - utf-8-validate dev: false - /leancloud-storage/4.13.4: - resolution: {integrity: sha512-U2kcuokRljC2uyeCcK11yW02hPNuAu5LVXOYCsfVM8K/inRSbq4nKQbkAuzBfZKQsDOsryq16ztAeOB3fItcYg==} + /leancloud-storage/4.14.0: + resolution: {integrity: sha512-DCJ67Dk6jrmCnoKZ/zTDwZSeBg2Gk2vHG8wnk2oWEJgcR290BB/2nDSe0H0xPT6nY36qfYYbNmM/tHPtLzRO0A==} dependencies: '@babel/runtime-corejs3': 7.20.6 '@leancloud/adapter-types': 5.0.0 @@ -10294,10 +10564,17 @@ packages: type-check: 0.4.0 dev: true + /light-my-request/5.8.0: + resolution: {integrity: sha512-4BtD5C+VmyTpzlDPCZbsatZMJVgUIciSOwYhJDCbLffPZ35KoDkDj4zubLeHDEb35b4kkPeEv5imbh+RJxK/Pg==} + dependencies: + cookie: 0.5.0 + process-warning: 2.1.0 + set-cookie-parser: 2.5.1 + dev: false + /lilconfig/2.0.6: resolution: {integrity: sha512-9JROoBW7pobfsx+Sq2JsASvCo6Pfo6WWoUW79HuB1BCoBXD4PLWJPqDF6fNj67pqBYTbAHkE57M1kS/+L1neOg==} engines: {node: '>=10'} - dev: true /lines-and-columns/1.2.4: resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} @@ -10308,8 +10585,8 @@ packages: uc.micro: 1.0.6 dev: false - /lint-staged/13.0.4: - resolution: {integrity: sha512-HxlHCXoYRsq9QCby5wFozmZW00hMs/9e3l+/dz6Qr8Kle4UH0kJTdABAbqhzG+3pcG6QjL9kz7NgGBfph+a5dw==} + /lint-staged/13.1.0: + resolution: {integrity: sha512-pn/sR8IrcF/T0vpWLilih8jmVouMlxqXxKuAojmbiGX5n/gDnz+abdPptlj0vYnbfE0SQNl3CY/HwtM0+yfOVQ==} engines: {node: ^14.13.1 || >=16.0.0} hasBin: true dependencies: @@ -10325,7 +10602,7 @@ packages: object-inspect: 1.12.2 pidtree: 0.6.0 string-argv: 0.3.1 - yaml: 2.1.3 + yaml: 2.2.0 transitivePeerDependencies: - enquirer - supports-color @@ -10395,7 +10672,7 @@ packages: log-update: 4.0.0 p-map: 4.0.0 rfdc: 1.3.0 - rxjs: 7.5.7 + rxjs: 7.8.0 through: 2.3.8 wrap-ansi: 7.0.0 dev: true @@ -10403,22 +10680,22 @@ packages: /lit-element/3.2.2: resolution: {integrity: sha512-6ZgxBR9KNroqKb6+htkyBwD90XGRiqKDHVrW/Eh0EZ+l+iC+u+v+w3/BA5NGi4nizAVHGYvQBHUDuSmLjPp7NQ==} dependencies: - '@lit/reactive-element': 1.4.2 - lit-html: 2.4.0 + '@lit/reactive-element': 1.5.0 + lit-html: 2.5.0 dev: false - /lit-html/2.4.0: - resolution: {integrity: sha512-G6qXu4JNUpY6aaF2VMfaszhO9hlWw0hOTRFDmuMheg/nDYGB+2RztUSOyrzALAbr8Nh0Y7qjhYkReh3rPnplVg==} + /lit-html/2.5.0: + resolution: {integrity: sha512-bLHosg1XL3JRUcKdSVI0sLCs0y1wWrj2sqqAN3cZ7bDDPNgmDHH29RV48x6Wz3ZmkxIupaE+z7uXSZ/pXWAO1g==} dependencies: '@types/trusted-types': 2.0.2 dev: false - /lit/2.4.1: - resolution: {integrity: sha512-qohSgLiyN1cFnJG26dIiY03S4F49857A0AHQfnS0zYtnUVnD2MFvx+UT52rtXsIuNFQrnUupX+zyGSATlk1f/A==} + /lit/2.5.0: + resolution: {integrity: sha512-DtnUP6vR3l4Q8nRPPNBD+UxbAhwJPeky+OVbi3pdgMqm0g57xFSl1Sj64D1rIB+nVNdiVVg8YxB0hqKjvdadZA==} dependencies: - '@lit/reactive-element': 1.4.2 + '@lit/reactive-element': 1.5.0 lit-element: 3.2.2 - lit-html: 2.4.0 + lit-html: 2.5.0 dev: false /load-json-file/4.0.0: @@ -10429,7 +10706,6 @@ packages: parse-json: 4.0.0 pify: 3.0.0 strip-bom: 3.0.0 - dev: true /loader-runner/4.3.0: resolution: {integrity: sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==} @@ -10442,7 +10718,7 @@ packages: dependencies: big.js: 5.2.2 emojis-list: 3.0.0 - json5: 2.2.1 + json5: 2.2.3 dev: false /localstorage-memory/1.0.3: @@ -10455,7 +10731,6 @@ packages: dependencies: p-locate: 2.0.0 path-exists: 3.0.0 - dev: true /locate-path/5.0.0: resolution: {integrity: sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==} @@ -10499,14 +10774,6 @@ packages: resolution: {integrity: sha512-C5N2Z3DgnnKr0LOpv/hKCgKdb7ZZwafIrsesve6lmzvZIRZRGaZ/l6Q8+2W7NaT+ZwO3fFlSCzCzrDCFdJfZ4g==} dev: false - /lodash.includes/4.3.0: - resolution: {integrity: sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==} - dev: false - - /lodash.isboolean/3.0.3: - resolution: {integrity: sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==} - dev: false - /lodash.isempty/4.4.0: resolution: {integrity: sha512-oKMuF3xEeqDltrGMfDxAPGIVMSSRv8tbRSODbrs4KGsRRLEhrW8N8Rd4DRgB2+621hY8A8XwwrTVhXWpxFvMzg==} dev: false @@ -10515,24 +10782,15 @@ packages: resolution: {integrity: sha512-AirXNj15uRIMMPihnkInB4i3NHeb4iBtNg9WRWuK2o31S+ePwwNmDPaTL3o7dTJ+VXNZim7rFs4rxN4YU1oUJw==} dev: true - /lodash.isinteger/4.0.4: - resolution: {integrity: sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==} - dev: false - /lodash.ismatch/4.4.0: resolution: {integrity: sha512-fPMfXjGQEV9Xsq/8MTSgUf255gawYRbjwMyDbcvDhXgV7enSZA0hynz6vMPnpAb5iONEzBHBPsT+0zes5Z301g==} - dev: true - - /lodash.isnumber/3.0.3: - resolution: {integrity: sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw==} - dev: false /lodash.isplainobject/4.0.6: resolution: {integrity: sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==} - /lodash.isstring/4.0.1: - resolution: {integrity: sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==} - dev: false + /lodash.kebabcase/4.1.1: + resolution: {integrity: sha512-N8XRTIMMqqDgSy4VLKPnJ/+hpGZN+PHQiJnSenYqPaVV/NCqEogTnAdZLQiGKhxX+JCs8waWq2t1XHWKOmlY8g==} + dev: true /lodash.kebabcase/4.1.1: resolution: {integrity: sha512-N8XRTIMMqqDgSy4VLKPnJ/+hpGZN+PHQiJnSenYqPaVV/NCqEogTnAdZLQiGKhxX+JCs8waWq2t1XHWKOmlY8g==} @@ -10544,14 +10802,19 @@ packages: /lodash.merge/4.6.2: resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} + dev: true /lodash.mergewith/4.6.2: resolution: {integrity: sha512-GK3g5RPZWTRSeLSpgP8Xhra+pnjBC56q9FZYe1d5RN3TJ35dbkGy3YqBSMbyCrlbi+CM9Z3Jk5yTL7RCsqboyQ==} dev: true - /lodash.once/4.1.1: - resolution: {integrity: sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==} - dev: false + /lodash.snakecase/4.1.1: + resolution: {integrity: sha512-QZ1d4xoBHYUeuouhEq3lk3Uq7ldgyFXGBhg04+oRLnIz8o9T65Eh+8YdroUwn846zchkA9yDsDl5CVVaV2nqYw==} + dev: true + + /lodash.startcase/4.4.0: + resolution: {integrity: sha512-+WKqsK294HMSc2jEbNgpHpd0JfIBhp7rEV4aqXWqFr6AlXov+SlcgB1Fv01y2kGe3Gc8nMW7VA0SrGuSkRfIEg==} + dev: true /lodash.snakecase/4.1.1: resolution: {integrity: sha512-QZ1d4xoBHYUeuouhEq3lk3Uq7ldgyFXGBhg04+oRLnIz8o9T65Eh+8YdroUwn846zchkA9yDsDl5CVVaV2nqYw==} @@ -10588,7 +10851,7 @@ packages: filter-obj: 3.0.0 jest-validate: 27.5.1 map-obj: 5.0.2 - moize: 6.1.3 + moize: 6.1.4 semver: 7.3.8 dev: false @@ -10610,7 +10873,7 @@ packages: resolution: {integrity: sha512-l0x2DvrW294C9uDCoQe1VSU4gf529FkSZ6leBl4TiqZH/e+0R7hSfHQBNut2mNygDgHwvYHfFLn6Oxb3VWj2rA==} engines: {node: '>=12'} dependencies: - chalk: 5.1.2 + chalk: 5.2.0 is-unicode-supported: 1.3.0 /log-update/2.3.0: @@ -10689,6 +10952,12 @@ packages: engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} dev: false + /lru-cache/5.1.1: + resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} + dependencies: + yallist: 3.1.1 + dev: false + /lru-cache/6.0.0: resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==} engines: {node: '>=10'} @@ -10723,6 +10992,13 @@ packages: sourcemap-codec: 1.4.8 dev: false + /magic-string/0.27.0: + resolution: {integrity: sha512-8UnnX2PeRAPZuN12svgR9j7M1uWMovg/CEnIwIG0LFkXSJJe4PdfUGiTGl8V9bsBHFUtfVINcSyYxd7q+kx9fA==} + engines: {node: '>=12'} + dependencies: + '@jridgewell/sourcemap-codec': 1.4.14 + dev: false + /make-array/1.0.5: resolution: {integrity: sha512-sgK2SAzxT19rWU+qxKUcn6PAh/swiIiz2F8C2cZjLc1z4iwYIfdoihqFIDQ8BDzAGtWPYJ6Sr13K1j/DXynDLA==} engines: {node: '>=0.10.0'} @@ -10785,12 +11061,10 @@ packages: /map-obj/1.0.1: resolution: {integrity: sha512-7N/q3lyZ+LVCp7PzuxrJr4KMbBE2hW7BT7YNia330OFxIf4d3r5zVpicP2650l7CPN6RM9zOJRl3NGpqSiw3Eg==} engines: {node: '>=0.10.0'} - dev: true /map-obj/4.3.0: resolution: {integrity: sha512-hdN1wVrZbb29eBGiGjJbeP8JbKjq1urkHJ/LIP/NY48MZ1QVXUsQBV1G1zvYFHn1XE06cwjBsOI2K3Ulnj1YXQ==} engines: {node: '>=8'} - dev: true /map-obj/5.0.2: resolution: {integrity: sha512-K6K2NgKnTXimT3779/4KxSvobxOtMmx1LBZ3NwRxT/MDIR3Br/fQ4Q+WCX5QxjyUR8zg5+RV9Tbf2c5pAWTD2A==} @@ -10804,8 +11078,8 @@ packages: object-visit: 1.0.1 dev: false - /markdown-it-anchor/8.6.5_ea7kj7wzjkld5jo2noyjqxi764: - resolution: {integrity: sha512-PI1qEHHkTNWT+X6Ip9w+paonfIQ+QZP9sCeMYi47oqhH+EsW8CrJ8J7CzV19QVOj6il8ATGbK2nTECj22ZHGvQ==} + /markdown-it-anchor/8.6.6_ea7kj7wzjkld5jo2noyjqxi764: + resolution: {integrity: sha512-jRW30YGywD2ESXDc+l17AiritL0uVaSnWsb26f+68qaW9zgbIIr1f4v2Nsvc0+s0Z2N3uX6t/yAw7BwCQ1wMsA==} peerDependencies: '@types/markdown-it': '*' markdown-it: '*' @@ -10833,8 +11107,8 @@ packages: uc.micro: 1.0.6 dev: false - /marked/4.2.3: - resolution: {integrity: sha512-slWRdJkbTZ+PjkyJnE30Uid64eHwbwa1Q25INCAYfZlK4o6ylagBy/Le9eWntqJFoFT93ikUKMv47GZ4gTwHkw==} + /marked/4.2.5: + resolution: {integrity: sha512-jPueVhumq7idETHkb203WDD4fMA3yV9emQ5vLwop58lu8bTclMghBWcYAavlDqIEMaisADinV1TooIFCfqOsYQ==} engines: {node: '>= 12'} hasBin: true dev: false @@ -10904,10 +11178,6 @@ packages: resolution: {integrity: sha512-rkpe71W0N0c0Xz6QD0eJETuWAJGnJ9afsl1srmwPrI+yBCkge5EycXXbYRyvL29zZVUWQCY7InPRCv3GDXuZNw==} dev: false - /mensch/0.3.4: - resolution: {integrity: sha512-IAeFvcOnV9V0Yk+bFhYR07O3yNina9ANIN5MoXBKYJ/RLYPurd2d0yw14MDhpr9/momp0WofT1bPUh3hkzdi/g==} - dev: false - /meow/8.1.2: resolution: {integrity: sha512-r85E3NdZ+mpYk1C6RjPFEMSE+s1iZMuHtsHAqY0DT3jZczl0diWUZ8g6oU7h0M9cD2EL+PzaYghhCLzR0ZNn5Q==} engines: {node: '>=10'} @@ -10923,7 +11193,6 @@ packages: trim-newlines: 3.0.1 type-fest: 0.18.1 yargs-parser: 20.2.9 - dev: true /merge-descriptors/1.0.1: resolution: {integrity: sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=} @@ -10947,19 +11216,16 @@ packages: resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} engines: {node: '>= 8'} - /mermaid/9.2.2: - resolution: {integrity: sha512-6s7eKMqFJGS+0MYjmx8f6ZigqKBJVoSx5ql2gw6a4Aa+WJ49QiEJg7gPwywaBg3DZMs79UP7trESp4+jmaQccw==} + /mermaid/9.3.0: + resolution: {integrity: sha512-mGl0BM19TD/HbU/LmlaZbjBi//tojelg8P/mxD6pPZTAYaI+VawcyBdqRsoUHSc7j71PrMdJ3HBadoQNdvP5cg==} dependencies: - '@braintree/sanitize-url': 6.0.2 - d3: 7.6.1 - dagre: 0.8.5 - dagre-d3: 0.6.4 - dompurify: 2.4.0 - fast-clone: 1.5.13 - graphlib: 2.1.8 + '@braintree/sanitize-url': 6.0.0 + d3: 7.8.0 + dagre-d3-es: 7.0.6 + dompurify: 2.4.1 khroma: 2.0.0 - lodash: 4.17.21 - moment-mini: 2.29.4 + lodash-es: 4.17.21 + moment-mini: 2.24.0 non-layered-tidy-tree-layout: 2.0.2 stylis: 4.1.3 uuid: 9.0.0 @@ -10978,8 +11244,8 @@ packages: resolution: {integrity: sha512-y0y6CUB9RLVsy3kfgayU28746QrNMpSm9O/AYGNsBgOkJr/X/Jk0VLGoO8Ude7Bpa8adywzF+MzXNZRFRsNPhg==} dev: false - /micro-memoize/4.0.11: - resolution: {integrity: sha512-CjxsaYe4j43df32DtzzNCwanPqZjZDwuQAZilsCYpa2ZVtSPDjHXbTlR4gsEZRyO9/twHs0b7HLjvy/sowl7sA==} + /micro-memoize/4.0.14: + resolution: {integrity: sha512-2tzWP1w2Hh+r7kCYa4f//jpBEA6dAueiuLco38NxfjF9Py3KCCI7wVOTdCvOhmTC043t+ulclVBdl3v+s+UJIQ==} dev: false /micromatch/3.1.10: @@ -11091,10 +11357,9 @@ packages: /min-indent/1.0.1: resolution: {integrity: sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==} engines: {node: '>=4'} - dev: true - /mini-css-extract-plugin/2.7.0_webpack@5.75.0: - resolution: {integrity: sha512-auqtVo8KhTScMsba7MbijqZTfibbXiBNlPAQbsVt7enQfcDYLdgG57eGxMqwVU3mfeWANY4F1wUg+rMF+ycZgw==} + /mini-css-extract-plugin/2.7.2_webpack@5.75.0: + resolution: {integrity: sha512-EdlUizq13o0Pd+uCp+WO/JpkLvHRVGt97RqfeGhXqAcorYo1ypJSpkV+WDT0vY/kmh/p7wRdJNJtuyK540PXDw==} engines: {node: '>= 12.13.0'} peerDependencies: webpack: ^5.0.0 @@ -11115,8 +11380,8 @@ packages: dependencies: brace-expansion: 1.1.11 - /minimatch/5.1.0: - resolution: {integrity: sha512-9TPBGGak4nHfGZsPBohm9AWg6NoT7QTCehS3BIJABslyZbzxfV78QM2Y6+i741OPZIafFAaiiEMh5OyIrJPgtg==} + /minimatch/5.1.2: + resolution: {integrity: sha512-bNH9mmM9qsJ2X4r2Nat1B//1dJVcn3+iBLa3IgqJ7EbGaDNepL9QSHOxN4ng33s52VMMhhIfgCYDk3C4ZmlDAg==} engines: {node: '>=10'} dependencies: brace-expansion: 2.0.1 @@ -11128,7 +11393,6 @@ packages: arrify: 1.0.1 is-plain-obj: 1.1.0 kind-of: 6.0.3 - dev: true /minimist/1.2.6: resolution: {integrity: sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==} @@ -11189,6 +11453,12 @@ packages: dependencies: yallist: 4.0.0 + /minipass/4.0.0: + resolution: {integrity: sha512-g2Uuh2jEKoht+zvO6vJqXmYpflPqzRBT+Th2h01DKh5z7wbY/AZ2gCQ78cP70YoHPyFdY30YBV5WxgLOEwOykw==} + engines: {node: '>=8'} + dependencies: + yallist: 4.0.0 + /miniprogram-api-typings/2.12.0: resolution: {integrity: sha512-ibvbqeslVFur0IAvTxLMvsbtvVcMo6gwvOnj0YZHV7aeDLu091VQRrETT2QuiG9P6aZWRcxeNGJChRKVPCp9VQ==} dev: false @@ -11227,7 +11497,6 @@ packages: /modify-values/1.0.1: resolution: {integrity: sha512-xV2bxeN6F7oYjZWTe/YPAy6MN2M+sL4u/Rlm2AHCIVGfo2p1yGmBHQ6vHehl4bRTZBdHu3TSkWdYgkwpYzAGSw==} engines: {node: '>=0.10.0'} - dev: true /module-definition/4.0.0: resolution: {integrity: sha512-wntiAHV4lDn24BQn2kX6LKq0y85phHLHiv3aOPDF+lIs06kVjEMTe/ZTdrbVLnQV5FQsjik21taknvMhKY1Cug==} @@ -11238,11 +11507,11 @@ packages: node-source-walk: 5.0.0 dev: false - /moize/6.1.3: - resolution: {integrity: sha512-Cn+1T5Ypieeo46fn8X98V2gHj2VSRohVPjvT8BRvNANJJC3UOeege/G84xA/3S9c5qA4p9jOdSB1jfhumwe8qw==} + /moize/6.1.4: + resolution: {integrity: sha512-Ga8V0iu7XHDz6GR50pAaGjc3hJ5CVmWUgQRyWFAn4pYrBzITx9dMlXOGhURP2qmO3WTeOC9Yu17MlFV6PY2m/g==} dependencies: fast-equals: 3.0.3 - micro-memoize: 4.0.11 + micro-memoize: 4.0.14 dev: false /moment-mini/2.29.4: @@ -11290,6 +11559,11 @@ packages: resolution: {integrity: sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==} dev: true + /nan/2.17.0: + resolution: {integrity: sha512-2ZTgtl0nJsO0KQCjEpxcIr5D+Yv90plTitZt9JBfQvVJDS5seMl3FOvsh3+9CoYWXf/1l5OaZzzF6nDm4cagaQ==} + dev: false + optional: true + /nanoid/3.3.4: resolution: {integrity: sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==} engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} @@ -11358,18 +11632,19 @@ packages: resolution: {integrity: sha512-9iN1ka/9zmX1ZvLV9ewJYEk9h7RyRRtqdK0woXcqohu8EWIerfPUjYJPg0ULy0UqP7cslmdGc8xKDJcojlKiaw==} dev: false - /netlify-cli/12.2.7_@types+node@18.11.9: - resolution: {integrity: sha512-p9xXsZqPyCJ+0aPqPVLEFmfWpkUb4RH9wJwdqPfdyNKAUKQsZs1JuMFY1ExzVmeUgGeROxK8wPrbTWgJ8upRYg==} + /netlify-cli/12.7.2_@types+node@18.11.18: + resolution: {integrity: sha512-6quAaycsIYKVA68upfUoSK1pkRUguR2oAED2vsZhXWNH1j3+O+1v6yYBgyCGewTPf/Z1ANlDh7c6pupW8/75iw==} engines: {node: ^14.16.0 || >=16.0.0} hasBin: true requiresBuild: true dependencies: - '@netlify/build': 28.4.4_@types+node@18.11.9 - '@netlify/config': 20.0.2 - '@netlify/edge-bundler': 4.4.3 - '@netlify/framework-info': 9.5.2 + '@fastify/static': 6.6.1 + '@netlify/build': 29.4.5_@types+node@18.11.18 + '@netlify/config': 20.3.0 + '@netlify/edge-bundler': 8.1.2 + '@netlify/framework-info': 9.5.3 '@netlify/local-functions-proxy': 1.1.1 - '@netlify/zip-it-and-ship-it': 8.1.0 + '@netlify/zip-it-and-ship-it': 8.2.0 '@octokit/rest': 19.0.5 ansi-escapes: 5.0.0 ansi-styles: 5.2.0 @@ -11391,7 +11666,6 @@ packages: cron-parser: 4.7.0 debug: 4.3.4 decache: 4.6.1 - del: 6.1.1 dot-prop: 6.0.1 dotenv: 16.0.3 env-paths: 2.2.1 @@ -11400,6 +11674,8 @@ packages: execa: 5.1.1 express: 4.18.2 express-logging: 1.1.1 + extract-zip: 2.0.1 + fastify: 4.11.0 find-up: 5.0.0 flush-write-stream: 2.0.0 folder-walker: 3.2.0 @@ -11420,7 +11696,7 @@ packages: is-plain-obj: 3.0.0 is-wsl: 2.2.0 isexe: 2.0.0 - jsonwebtoken: 8.5.1 + jsonwebtoken: 9.0.0 jwt-decode: 3.1.2 lambda-local: 2.0.3 listr: 0.14.3 @@ -11428,17 +11704,15 @@ packages: lodash: 4.17.21 log-symbols: 4.1.0 log-update: 5.0.1 - memoize-one: 6.0.0 minimist: 1.2.7 multiparty: 4.2.3 - netlify: 13.0.2 - netlify-headers-parser: 7.0.3 + netlify: 13.1.0 + netlify-headers-parser: 7.1.0 netlify-onegraph-internal: 0.10.1 - netlify-redirect-parser: 14.0.2 + netlify-redirect-parser: 14.1.0 netlify-redirector: 0.3.1 node-fetch: 2.6.7 node-version-alias: 1.0.1 - omit.js: 2.0.2 ora: 5.4.1 p-filter: 2.1.0 p-map: 4.0.0 @@ -11453,7 +11727,6 @@ packages: read-pkg-up: 7.0.1 semver: 7.3.8 source-map-support: 0.5.21 - static-server: 2.2.1 string-similarity: 4.0.4 strip-ansi-control-characters: 2.0.0 tabtab: 3.0.2 @@ -11480,8 +11753,8 @@ packages: - zenObservable dev: false - /netlify-headers-parser/7.0.3: - resolution: {integrity: sha512-vdpQl7gwgu1Lt0j+kgR7DXae0FOiHyuT0cwJgjr5YAAo5Lj+0ZNYsH2SbNZ0S4qzu+0xONqRwJAJ3gKE0Ocp4w==} + /netlify-headers-parser/7.1.0: + resolution: {integrity: sha512-KX+YETETcibTx/yNyzFJ+78GbXTG1kmEgORAPeKJFHQhRQWeix8Mfnu0a/NK4hJt7seOdQQOCAA6FaZer+LEBw==} engines: {node: ^14.16.0 || >=16.0.0} dependencies: escape-string-regexp: 5.0.0 @@ -11503,8 +11776,8 @@ packages: - encoding dev: false - /netlify-redirect-parser/14.0.2: - resolution: {integrity: sha512-mi1/NaCr0IBq8MiXbOFjkb4zmQCQp33OLDETn4OtXcpFn9EGiT//KlKu4kTCwzcw5K4i0/7t81Z1EC+8ToFMYg==} + /netlify-redirect-parser/14.1.0: + resolution: {integrity: sha512-shyZ9eg4984c7prN67/vQAcYu1Sco2iRfP+ne9pjcWFEVigREzGGitGvOQCChxVyT16TT0n1CrJW+aKlBqwPlA==} engines: {node: ^14.16.0 || >=16.0.0} dependencies: fast-safe-stringify: 2.1.1 @@ -11518,8 +11791,8 @@ packages: resolution: {integrity: sha512-+8x07Ukx8vgKkGqTDq1GrkuCRR0DqheZ9fF5PXk6VbIChp9Qi8+psmwBV3hjocoyUvUGH7CIHLUk05aVwLN3wA==} dev: false - /netlify/13.0.2: - resolution: {integrity: sha512-n3Wap1GA2r5UQ4a5nZkcF/lEJXYbLcsqkXA5rYbeygWb7PCYFxb55OI/7EBvIHFTBjtF8OXBOCP3XomuHlqQWw==} + /netlify/13.1.0: + resolution: {integrity: sha512-FkMXk0h7QuR1iR3MeSQFxadarHXWgXzYFoHvF3m7edsFUpJ2WdRH3xiOVEyJciQUGYwEAHycUyi8CkT/2aKzLA==} engines: {node: ^14.16.0 || >=16.0.0} dependencies: '@netlify/open-api': 2.12.2 @@ -11574,9 +11847,9 @@ packages: hasBin: true dev: false - /node-gyp/9.3.0: - resolution: {integrity: sha512-A6rJWfXFz7TQNjpldJ915WFb1LnhO4lIve3ANPbWreuEoLoKlFT3sxIepPBkLhM27crW8YmN+pjlgbasH6cH/Q==} - engines: {node: ^12.22 || ^14.13 || >=16} + /node-gyp/9.3.1: + resolution: {integrity: sha512-4Q16ZCqq3g8awk6UplT7AuxQ35XN4R/yf/+wSAwcBUAjg7l58RTactWaP8fIDTi0FzI7YcVLujwExakZlfWkXg==} + engines: {node: ^12.13 || ^14.13 || >=16} hasBin: true dependencies: env-paths: 2.2.1 @@ -11587,7 +11860,7 @@ packages: npmlog: 6.0.2 rimraf: 3.0.2 semver: 7.3.8 - tar: 6.1.12 + tar: 6.1.13 which: 2.0.2 transitivePeerDependencies: - bluebird @@ -11602,14 +11875,14 @@ packages: resolution: {integrity: sha512-8Q1hXew6ETzqKRAs3jjLioSxNfT1cx74ooiF8RlAONwVMcfq+UdzLC2eB5qcPldUxaE5w3ytLkrmV1TGddhZTA==} engines: {node: '>=6.0'} dependencies: - '@babel/parser': 7.16.8 + '@babel/parser': 7.20.7 dev: false /node-source-walk/5.0.0: resolution: {integrity: sha512-58APXoMXpmmU+oVBJFajhTCoD8d/OGtngnVAWzIo2A8yn0IXwBzvIVIsTzoie/SrA37u+1hnpNz2HMWx/VIqlw==} engines: {node: '>=12'} dependencies: - '@babel/parser': 7.16.8 + '@babel/parser': 7.20.7 dev: false /node-stream-zip/1.15.0: @@ -11760,6 +12033,7 @@ packages: /npm-normalize-package-bin/1.0.1: resolution: {integrity: sha512-EPfafl6JL5/rU+ot6P3gRSCpPDW5VmIzX959Ob1+ySFUuuYHWHekXpwdUZcKP5C+DS4GEtdJluwBjnsNDl+fSA==} + dev: true /npm-normalize-package-bin/2.0.0: resolution: {integrity: sha512-awzfKUO7v0FscrSpRoogyNm0sajikhBWpU0QMrW09AMi9n1PoKU6WaIqUzuJSQnpciZZmJ/jMZ2Egfmb/9LiWQ==} @@ -11911,7 +12185,7 @@ packages: dependencies: call-bind: 1.0.2 define-properties: 1.1.4 - es-abstract: 1.20.4 + es-abstract: 1.20.5 dev: true /obuf/1.1.2: @@ -11922,6 +12196,10 @@ packages: resolution: {integrity: sha512-hJmu9D+bNB40YpL9jYebQl4lsTW6yEHRTroJzNLqQJYHm7c+NQnJGfZmIWh8S3q3KoaxV1aLhV6B3+0N0/kyJg==} dev: false + /on-exit-leak-free/2.1.0: + resolution: {integrity: sha512-VuCaZZAjReZ3vUwgOB8LxAosIurDiAW0s13rI1YwmaP++jvcxP77AWoQvenZebpCA2m8WC1/EosPYPMjnRAp/w==} + dev: false + /on-finished/2.3.0: resolution: {integrity: sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww==} engines: {node: '>= 0.8'} @@ -11980,13 +12258,6 @@ packages: is-wsl: 2.2.0 dev: false - /opn/5.5.0: - resolution: {integrity: sha512-PqHpggC9bLV0VeWcdKhkpxY+3JTzetLSqTCWL/z/tFIbI6G8JCjondXklT1JinczLz2Xib62sSp0T/gKT4KksA==} - engines: {node: '>=4'} - dependencies: - is-wsl: 1.1.0 - dev: false - /optionator/0.8.3: resolution: {integrity: sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA==} engines: {node: '>= 0.8.0'} @@ -12034,7 +12305,7 @@ packages: engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} dependencies: bl: 5.1.0 - chalk: 5.1.2 + chalk: 5.2.0 cli-cursor: 4.0.0 cli-spinners: 2.7.0 is-interactive: 2.0.0 @@ -12146,7 +12417,6 @@ packages: engines: {node: '>=4'} dependencies: p-try: 1.0.0 - dev: true /p-limit/2.3.0: resolution: {integrity: sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==} @@ -12172,7 +12442,6 @@ packages: engines: {node: '>=4'} dependencies: p-limit: 1.3.0 - dev: true /p-locate/4.1.0: resolution: {integrity: sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==} @@ -12261,7 +12530,6 @@ packages: /p-try/1.0.0: resolution: {integrity: sha512-U1etNYuMJoIz3ZXSrrySFjsXQTWOx2/jdi86L+2pRvph/qMKL6sbcCYdH23fqsbm8TH2Gn0OybpT4eSFlCVHww==} engines: {node: '>=4'} - dev: true /p-try/2.2.0: resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==} @@ -12326,7 +12594,7 @@ packages: read-package-json-fast: 2.0.3 rimraf: 3.0.2 ssri: 9.0.1 - tar: 6.1.12 + tar: 6.1.13 transitivePeerDependencies: - bluebird - supports-color @@ -12370,7 +12638,6 @@ packages: dependencies: error-ex: 1.3.2 json-parse-better-errors: 1.0.2 - dev: true /parse-json/5.2.0: resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==} @@ -12391,14 +12658,17 @@ packages: engines: {node: '>=0.10.0'} dev: true - /parse5-htmlparser2-tree-adapter/6.0.1: - resolution: {integrity: sha512-qPuWvbLgvDGilKc5BoicRovlT4MtYT6JfJyBOMDsKoiT+GiuP5qyrPCnR9HcPECIJJmZh5jRndyNThnhhb/vlA==} + /parse5-htmlparser2-tree-adapter/7.0.0: + resolution: {integrity: sha512-B77tOZrqqfUfnVcOrUvfdLbz4pu4RopLD/4vmu3HUPswwTA8OH0EMW9BlWR2B0RCoiZRAHEUu7IxeP1Pd1UU+g==} dependencies: - parse5: 6.0.1 + domhandler: 5.0.3 + parse5: 7.1.2 dev: false - /parse5/6.0.1: - resolution: {integrity: sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==} + /parse5/7.1.2: + resolution: {integrity: sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==} + dependencies: + entities: 4.4.0 dev: false /parseurl/1.3.3: @@ -12425,7 +12695,6 @@ packages: /path-exists/3.0.0: resolution: {integrity: sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==} engines: {node: '>=4'} - dev: true /path-exists/4.0.0: resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} @@ -12516,6 +12785,34 @@ packages: engines: {node: '>=0.10.0'} dev: false + /pino-abstract-transport/1.0.0: + resolution: {integrity: sha512-c7vo5OpW4wIS42hUVcT5REsL8ZljsUfBjqV/e2sFxmFEFZiq1XLUp5EYLtuDH6PEHq9W1egWqRbnLUP5FuZmOA==} + dependencies: + readable-stream: 4.3.0 + split2: 4.1.0 + dev: false + + /pino-std-serializers/6.1.0: + resolution: {integrity: sha512-KO0m2f1HkrPe9S0ldjx7za9BJjeHqBku5Ch8JyxETxT8dEFGz1PwgrHaOQupVYitpzbFSYm7nnljxD8dik2c+g==} + dev: false + + /pino/8.8.0: + resolution: {integrity: sha512-cF8iGYeu2ODg2gIwgAHcPrtR63ILJz3f7gkogaHC/TXVVXxZgInmNYiIpDYEwgEkxZti2Se6P2W2DxlBIZe6eQ==} + hasBin: true + dependencies: + atomic-sleep: 1.0.0 + fast-redact: 3.1.2 + on-exit-leak-free: 2.1.0 + pino-abstract-transport: 1.0.0 + pino-std-serializers: 6.1.0 + process-warning: 2.1.0 + quick-format-unescaped: 4.0.4 + real-require: 0.2.0 + safe-stable-stringify: 2.3.1 + sonic-boom: 3.2.1 + thread-stream: 2.3.0 + dev: false + /pkg-dir/6.0.1: resolution: {integrity: sha512-C9R+PTCKGA32HG0n5I4JMYkdLL58ZpayVuncQHQrGeKa8o26A4o2x0u6BKekHG+Au0jv5ZW7Xfq1Cj6lm9Ag4w==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} @@ -12523,8 +12820,8 @@ packages: find-up: 6.3.0 dev: false - /pnpm/7.17.1: - resolution: {integrity: sha512-O76jPxzoeja81Z/8YyTfuXt+f7qkpsyEJsNBreWYBLHY5rJkjvNE/bIUGQ2uD/rcYPEtmrZZYox21OjAMC9EGw==} + /pnpm/7.25.0: + resolution: {integrity: sha512-FGFQUON8kJ6ma39elJ8lyD8wPIfgp3opGJD9sX0TgIJk4zSr556qCgC8AN+3BFHe4yuRkEauf4JVLW2RKyyEcA==} engines: {node: '>=14.6'} hasBin: true dev: true @@ -12545,7 +12842,7 @@ packages: engines: {node: '>=0.10.0'} dev: false - /postcss-csso/6.0.1_postcss@8.4.19: + /postcss-csso/6.0.1_postcss@8.4.20: resolution: {integrity: sha512-ZV4yEziMrx6CEiqabGLrDva0pMD7Fbw7yP+LzJvaynM4OJgTssGN6dHiMsJMJdpmNaLJltXVLsrb/5sxbFa8sA==} engines: {node: ^12.20.0 || ^14.13.0 || >=15.0.0, npm: '>=7.0.0'} peerDependencies: @@ -12555,11 +12852,28 @@ packages: optional: true dependencies: csso: 5.0.5 - postcss: 8.4.19 + postcss: 8.4.20 dev: false - /postcss-loader/7.0.1_upg3rk2kpasnbk27hkqapxaxfq: - resolution: {integrity: sha512-VRviFEyYlLjctSM93gAZtcJJ/iSkPZ79zWbN/1fSH+NisBByEiVLqpdVDrPLVSi8DX0oJo12kL/GppTBdKVXiQ==} + /postcss-load-config/4.0.1_postcss@8.4.20: + resolution: {integrity: sha512-vEJIc8RdiBRu3oRAI0ymerOn+7rPuMvRXslTvZUKZonDHFIczxztIyJ1urxM1x9JXEikvpWWTUUqal5j/8QgvA==} + engines: {node: '>= 14'} + peerDependencies: + postcss: '>=8.0.9' + ts-node: '>=9.0.0' + peerDependenciesMeta: + postcss: + optional: true + ts-node: + optional: true + dependencies: + lilconfig: 2.0.6 + postcss: 8.4.20 + yaml: 2.2.0 + dev: false + + /postcss-loader/7.0.2_qxxfhhrl3yknjjmta266mo3u64: + resolution: {integrity: sha512-fUJzV/QH7NXUAqV8dWJ9Lg4aTkDCezpTS5HgJ2DvqznexTbSTxgi/dTECvTZ15BwKTtk8G/bqI/QTu2HPd3ZCg==} engines: {node: '>= 14.15.0'} peerDependencies: postcss: ^7.0.0 || ^8.0.1 @@ -12572,12 +12886,12 @@ packages: dependencies: cosmiconfig: 7.1.0 klona: 2.0.5 - postcss: 8.4.19 + postcss: 8.4.20 semver: 7.3.8 webpack: 5.75.0 dev: false - /postcss-modules-extract-imports/3.0.0_postcss@8.4.19: + /postcss-modules-extract-imports/3.0.0_postcss@8.4.20: resolution: {integrity: sha512-bdHleFnP3kZ4NYDhuGlVK+CMrQ/pqUm8bx/oGL93K6gVwiclvX5x0n76fYMKuIGKzlABOy13zsvqjb0f92TEXw==} engines: {node: ^10 || ^12 || >= 14} peerDependencies: @@ -12586,10 +12900,10 @@ packages: postcss: optional: true dependencies: - postcss: 8.4.19 + postcss: 8.4.20 dev: false - /postcss-modules-local-by-default/4.0.0_postcss@8.4.19: + /postcss-modules-local-by-default/4.0.0_postcss@8.4.20: resolution: {integrity: sha512-sT7ihtmGSF9yhm6ggikHdV0hlziDTX7oFoXtuVWeDd3hHObNkcHRo9V3yg7vCAY7cONyxJC/XXCmmiHHcvX7bQ==} engines: {node: ^10 || ^12 || >= 14} peerDependencies: @@ -12598,13 +12912,13 @@ packages: postcss: optional: true dependencies: - icss-utils: 5.1.0_postcss@8.4.19 - postcss: 8.4.19 + icss-utils: 5.1.0_postcss@8.4.20 + postcss: 8.4.20 postcss-selector-parser: 6.0.11 postcss-value-parser: 4.2.0 dev: false - /postcss-modules-scope/3.0.0_postcss@8.4.19: + /postcss-modules-scope/3.0.0_postcss@8.4.20: resolution: {integrity: sha512-hncihwFA2yPath8oZ15PZqvWGkWf+XUfQgUGamS4LqoP1anQLOsOJw0vr7J7IwLpoY9fatA2qiGUGmuZL0Iqlg==} engines: {node: ^10 || ^12 || >= 14} peerDependencies: @@ -12613,11 +12927,11 @@ packages: postcss: optional: true dependencies: - postcss: 8.4.19 + postcss: 8.4.20 postcss-selector-parser: 6.0.11 dev: false - /postcss-modules-values/4.0.0_postcss@8.4.19: + /postcss-modules-values/4.0.0_postcss@8.4.20: resolution: {integrity: sha512-RDxHkAiEGI78gS2ofyvCsu7iycRv7oqw5xMWn9iMoR0N/7mf9D50ecQqUo5BZ9Zh2vH4bCUR/ktCqbB9m8vJjQ==} engines: {node: ^10 || ^12 || >= 14} peerDependencies: @@ -12626,8 +12940,8 @@ packages: postcss: optional: true dependencies: - icss-utils: 5.1.0_postcss@8.4.19 - postcss: 8.4.19 + icss-utils: 5.1.0_postcss@8.4.20 + postcss: 8.4.20 dev: false /postcss-selector-parser/6.0.11: @@ -12641,7 +12955,7 @@ packages: resolution: {integrity: sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==} dev: false - /postcss-values-parser/6.0.2_postcss@8.4.19: + /postcss-values-parser/6.0.2_postcss@8.4.20: resolution: {integrity: sha512-YLJpK0N1brcNJrs9WatuJFtHaV9q5aAOj+S4DI5S7jgHlRfm0PIbDCAFRYMQD5SHq7Fy6xsDhyutgS0QOAs0qw==} engines: {node: '>=10'} peerDependencies: @@ -12652,12 +12966,12 @@ packages: dependencies: color-name: 1.1.4 is-url-superb: 4.0.0 - postcss: 8.4.19 + postcss: 8.4.20 quote-unquote: 1.0.0 dev: false - /postcss/8.4.19: - resolution: {integrity: sha512-h+pbPsyhlYj6N2ozBmHhHrs9DzGmbaarbLvWipMRO7RLS+v4onj26MPFXA5OBYFxyqYhUJK456SwDcY9H2/zsA==} + /postcss/8.4.20: + resolution: {integrity: sha512-6Q04AXR1212bXr5fh03u8aAwbLxAQNGQ/Q1LNa0VfOI06ZAlhPHtQvE4OIdpj4kLThXilalPnmDSOD65DcHt+g==} engines: {node: ^10 || ^12 || >=14} dependencies: nanoid: 3.3.4 @@ -12741,8 +13055,8 @@ packages: fast-diff: 1.2.0 dev: true - /prettier/2.8.0: - resolution: {integrity: sha512-9Lmg8hTFZKG0Asr/kW9Bp8tJjRVluO8EJQVfY2T7FMw9T5jy4I/Uvx0Rca/XWf50QQ1/SS48+6IJWnrb+2yemA==} + /prettier/2.8.3: + resolution: {integrity: sha512-tJ/oJ4amDihPoufT5sM0Z1SKEuKay8LfVAMlbbhnnkvt6BUserZylqo2PN+p9KeljLr0OHa2rXHU1T8reeoTrw==} engines: {node: '>=10.13.0'} hasBin: true dev: true @@ -12806,6 +13120,10 @@ packages: /process-nextick-args/2.0.1: resolution: {integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==} + /process-warning/2.1.0: + resolution: {integrity: sha512-9C20RLxrZU/rFnxWncDkuF6O999NdIf3E1ws4B0ZeY3sRVPzWBMsYDE2lxjxhiXxg464cQTgKUGm8/i6y2YGXg==} + dev: false + /process/0.11.10: resolution: {integrity: sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==} engines: {node: '>= 0.6.0'} @@ -12838,7 +13156,10 @@ packages: dependencies: kleur: 3.0.3 sisteransi: 1.0.5 - dev: true + + /proto-list/1.2.4: + resolution: {integrity: sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA==} + dev: false /proto-list/1.2.4: resolution: {integrity: sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA==} @@ -12907,7 +13228,6 @@ packages: /q/1.5.1: resolution: {integrity: sha512-kV/CThkXo6xyFEZUugw/+pIOywXcDbFYgSct5cT3gqlbkBE1SJdwy6UQoZvodiWF/ckQLZyDE/Bu1M6gVu5lVw==} engines: {node: '>=0.6.0', teleport: '>=0.2.0'} - dev: true /qs/6.11.0: resolution: {integrity: sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==} @@ -12934,10 +13254,18 @@ packages: /queue-microtask/1.2.3: resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} + /quick-format-unescaped/4.0.4: + resolution: {integrity: sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg==} + dev: false + /quick-lru/4.0.1: resolution: {integrity: sha512-ARhCpm70fzdcvNQfPoy49IaanKkTlRWF2JMzqhcJbhSFRZv7nPTvZJdcY7301IPmvW+/p0RgIWnQDLJxifsQ7g==} engines: {node: '>=8'} - dev: true + + /quick-lru/5.1.1: + resolution: {integrity: sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==} + engines: {node: '>=10'} + dev: false /quick-lru/5.1.1: resolution: {integrity: sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==} @@ -13004,6 +13332,15 @@ packages: dependencies: json-parse-even-better-errors: 2.3.1 npm-normalize-package-bin: 1.0.1 + dev: true + + /read-package-json-fast/3.0.2: + resolution: {integrity: sha512-0J+Msgym3vrLOUB3hzQCuZHII0xkNGCtz/HJH9xZshwv9DbDwkw1KaE3gx/e2J5rpEY5rtOy6cyhKOPrkP7FZw==} + engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + dependencies: + json-parse-even-better-errors: 3.0.0 + npm-normalize-package-bin: 3.0.0 + dev: true /read-package-json-fast/3.0.1: resolution: {integrity: sha512-8+HW7Yo+cjfF+md8DqsZHgats2mxf7gGYow/+2JjxrftoHFZz9v4dzd0EubzYbkNaLxrTVcnllHwklXN2+7aTQ==} @@ -13029,7 +13366,6 @@ packages: dependencies: find-up: 2.1.0 read-pkg: 3.0.0 - dev: true /read-pkg-up/7.0.1: resolution: {integrity: sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==} @@ -13055,7 +13391,6 @@ packages: load-json-file: 4.0.0 normalize-package-data: 2.5.0 path-type: 3.0.0 - dev: true /read-pkg/5.2.0: resolution: {integrity: sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==} @@ -13095,10 +13430,20 @@ packages: string_decoder: 1.3.0 util-deprecate: 1.0.2 + /readable-stream/4.3.0: + resolution: {integrity: sha512-MuEnA0lbSi7JS8XM+WNJlWZkHAAdm7gETHdFK//Q/mChGyj2akEFtdLZh32jSdkWGbRwCW9pn6g3LWDdDeZnBQ==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + dependencies: + abort-controller: 3.0.0 + buffer: 6.0.3 + events: 3.3.0 + process: 0.11.10 + dev: false + /readdir-glob/1.1.2: resolution: {integrity: sha512-6RLVvwJtVwEDfPdn6X6Ille4/lxGl0ATOY4FN/B9nxQcgOazvvI0nodiD19ScKq0PvA/29VpaOQML36o5IzZWA==} dependencies: - minimatch: 5.1.0 + minimatch: 5.1.2 dev: false /readdirp/2.2.1: @@ -13119,13 +13464,17 @@ packages: picomatch: 2.3.1 dev: false + /real-require/0.2.0: + resolution: {integrity: sha512-57frrGM/OCTLqLOAh0mhVA9VBMHd+9U7Zb2THMGdBUoZVOtGbJzjxsYGDJ3A9AYYCP4hn6y1TVbaOfzWtm5GFg==} + engines: {node: '>= 12.13.0'} + dev: false + /redent/3.0.0: resolution: {integrity: sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==} engines: {node: '>=8'} dependencies: indent-string: 4.0.0 strip-indent: 3.0.0 - dev: true /regenerator-runtime/0.13.11: resolution: {integrity: sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==} @@ -13325,6 +13674,11 @@ packages: engines: {node: '>=0.12'} dev: false + /ret/0.2.2: + resolution: {integrity: sha512-M0b3YWQs7R3Z917WRQy1HHA7Ba7D8hvZg6UE5mLykJxQVE2ju0IXbGlaHPPlkY+WN7wFP+wUMXmBFA0aV6vYGQ==} + engines: {node: '>=4'} + dev: false + /retry/0.12.0: resolution: {integrity: sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==} engines: {node: '>= 4'} @@ -13363,17 +13717,9 @@ packages: estree-walker: 0.6.1 dev: false - /rollup/2.77.3: - resolution: {integrity: sha512-/qxNTG7FbmefJWoeeYJFbHehJ2HNWnjkAFRKzWN/45eNBBF/r8lo992CwcJXEzyVxs5FmfId+vTSTQDb+bxA+g==} - engines: {node: '>=10.0.0'} - hasBin: true - optionalDependencies: - fsevents: 2.3.2 - dev: false - - /rollup/2.79.1: - resolution: {integrity: sha512-uKxbd0IhMZOhjAiD5oAFp7BqvkA4Dv47qpOCtaNvng4HBwdbWtdOh8f5nZNuk2rp51PMGk3bzfWu5oayNEuYnw==} - engines: {node: '>=10.0.0'} + /rollup/3.9.0: + resolution: {integrity: sha512-nGGylpmblyjTpF4lEUPgmOw6OVxRvnI6Iuuh6Lz4O/X66cVOX1XJSsqP1YamxQ+mPuFE7qJxLFDSCk8rNv5dDw==} + engines: {node: '>=14.18.0', npm: '>=8.0.0'} hasBin: true optionalDependencies: fsevents: 2.3.2 @@ -13402,8 +13748,8 @@ packages: tslib: 1.14.1 dev: false - /rxjs/7.5.7: - resolution: {integrity: sha512-z9MzKh/UcOqB3i20H6rtrlaE/CgjLOvheWK/9ILrbhROGTweAi1BaFsTT9FbwZi5Trr1qNRs+MXkhmR06awzQA==} + /rxjs/7.8.0: + resolution: {integrity: sha512-F2+gxDshqmIub1KdvZkaEfGDwLNpPvk9Fs6LD/MyQxNgMds/WH9OdDDXOmxUZpME+iSK3rQCctkL0DYyytUqMg==} dependencies: tslib: 2.4.1 dev: true @@ -13432,15 +13778,21 @@ packages: ret: 0.1.15 dev: false - /safe-stable-stringify/2.4.1: - resolution: {integrity: sha512-dVHE6bMtS/bnL2mwualjc6IxEv1F+OCUpA46pKUj6F8uDbUM0jCCulPqRNPSnWwGNKx5etqMjZYdXtrm5KJZGA==} + /safe-regex2/2.0.0: + resolution: {integrity: sha512-PaUSFsUaNNuKwkBijoAPHAK6/eM6VirvyPWlZ7BAQy4D+hCvh4B6lIG+nPdhbFfIbP+gTGBcrdsOaUs0F+ZBOQ==} + dependencies: + ret: 0.2.2 + dev: false + + /safe-stable-stringify/2.3.1: + resolution: {integrity: sha512-kYBSfT+troD9cDA85VDnHZ1rpHC50O0g1e6WlGHVCz/g+JS+9WKLj+XwFYyR8UbrZN8ll9HUpDAAddY58MGisg==} engines: {node: '>=10'} dev: false /safer-buffer/2.1.2: resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} - /sass-loader/13.2.0_sass@1.56.1: + /sass-loader/13.2.0_sass@1.57.1: resolution: {integrity: sha512-JWEp48djQA4nbZxmgC02/Wh0eroSUutulROUusYJO9P9zltRbNN80JCBHqRGzjd4cmZCa/r88xgfkjGD0TXsHg==} engines: {node: '>= 14.15.0'} peerDependencies: @@ -13463,11 +13815,11 @@ packages: dependencies: klona: 2.0.5 neo-async: 2.6.2 - sass: 1.56.1 + sass: 1.57.1 dev: false - /sass/1.56.1: - resolution: {integrity: sha512-VpEyKpyBPCxE7qGDtOcdJ6fFbcpOM+Emu7uZLxVrkX8KVU/Dp5UF7WLvzqRuUhB6mqqQt1xffLoG+AndxTZrCQ==} + /sass/1.57.1: + resolution: {integrity: sha512-O2+LwLS79op7GI0xZ8fqzF7X2m/m8WFfI02dHOdsK5R2ECeS5F62zrwg/relM1rjSLy7Vd/DiMNIvPrQGsA0jw==} engines: {node: '>=12.0.0'} hasBin: true dependencies: @@ -13507,6 +13859,10 @@ packages: kind-of: 6.0.3 dev: false + /secure-json-parse/2.7.0: + resolution: {integrity: sha512-6aU+Rwsezw7VR8/nyvKTx8QpWH9FrcYiXXlqC4z5d5XQBDRqtbfsRjnwGyqbi3gddNtWHuEk9OANUotL26qKUw==} + dev: false + /seek-bzip/1.0.6: resolution: {integrity: sha512-e1QtP3YL5tWww8uKaOCQ18UxIT2laNBXHjV/S2WYCiK4udiv8lkG89KRIoCjUagnAmCBurjF4zEVX2ByBbnCjQ==} hasBin: true @@ -13547,8 +13903,8 @@ packages: resolution: {integrity: sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==} hasBin: true - /semver/7.3.7: - resolution: {integrity: sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==} + /semver/7.3.8: + resolution: {integrity: sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==} engines: {node: '>=10'} hasBin: true dependencies: @@ -13619,6 +13975,10 @@ packages: /set-blocking/2.0.0: resolution: {integrity: sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==} + /set-cookie-parser/2.5.1: + resolution: {integrity: sha512-1jeBGaKNGdEq4FgIrORu/N570dwoPYio8lSoYLWmX7sQ//0JY08Xh9o5pBcgmHQ/MbsYp/aZnOe1s1lIsbLprQ==} + dev: false + /set-value/2.0.1: resolution: {integrity: sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==} engines: {node: '>=0.10.0'} @@ -13657,6 +14017,14 @@ packages: /shell-quote/1.7.4: resolution: {integrity: sha512-8o/QEhSSRb1a5i7TFR0iM4G16Z0vYB2OQVs4G3aAFXjn3T6yEx8AZxy1PgDF7I00LZHYA3WxaSYIf5e5sAX8Rw==} + /shiki/0.12.1: + resolution: {integrity: sha512-aieaV1m349rZINEBkjxh2QbBvFFQOlgqYTNtCal82hHj4dDZ76oMlQIX+C7ryerBTDiga3e5NfH6smjdJ02BbQ==} + dependencies: + jsonc-parser: 3.2.0 + vscode-oniguruma: 1.7.0 + vscode-textmate: 8.0.0 + dev: false + /side-channel/1.0.4: resolution: {integrity: sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==} dependencies: @@ -13675,7 +14043,6 @@ packages: /sisteransi/1.0.5: resolution: {integrity: sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==} - dev: true /sitemap/7.1.1: resolution: {integrity: sha512-mK3aFtjz4VdJN0igpIJrinf3EO8U8mxOPsTBzSsy06UtjZQJ3YY3o3Xa7zSc5nMqcMrRwlChHZ18Kxg0caiPBg==} @@ -13731,10 +14098,6 @@ packages: ansi-styles: 6.2.1 is-fullwidth-code-point: 4.0.0 - /slick/1.12.2: - resolution: {integrity: sha512-4qdtOGcBjral6YIBCWJ0ljFSKNLz9KkhbWtuGvUyRowl1kxfuE1x/Z/aJcaiilpb3do9bl5K7/1h9XC5wWpY/A==} - dev: false - /smart-buffer/4.2.0: resolution: {integrity: sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==} engines: {node: '>= 6.0.0', npm: '>= 3.0.0'} @@ -13815,6 +14178,12 @@ packages: smart-buffer: 4.2.0 dev: true + /sonic-boom/3.2.1: + resolution: {integrity: sha512-iITeTHxy3B9FGu8aVdiDXUVAcHMF9Ss0cCsAOo2HfCrmVGT3/DT5oYaeu0M/YKZDlKTvChEyPq0zI9Hf33EX6A==} + dependencies: + atomic-sleep: 1.0.0 + dev: false + /sort-keys-length/1.0.1: resolution: {integrity: sha512-GRbEOUqCxemTAk/b32F2xa8wDTs+Z1QHOkbhJDQTvv/6G3ZkbJ+frYWsTcc7cBB3Fu4wy4XlLCuNtJuMn7Gsvw==} engines: {node: '>=0.10.0'} @@ -13847,7 +14216,7 @@ packages: detect-indent: 7.0.1 detect-newline: 4.0.0 git-hooks-list: 3.0.0 - globby: 13.1.2 + globby: 13.1.3 is-plain-obj: 4.1.0 sort-object-keys: 1.1.3 dev: true @@ -13894,6 +14263,7 @@ packages: /sourcemap-codec/1.4.8: resolution: {integrity: sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==} + deprecated: Please use @jridgewell/sourcemap-codec instead dev: false /spawn-command/0.0.2-1: @@ -13964,7 +14334,6 @@ packages: resolution: {integrity: sha512-mTyOoPbrivtXnwnIxZRFYRrPNtEFKlpB2fvjSnCQUiAA6qAZzqwna5envK4uk6OIeP17CsdF3rSBGYVBsU0Tkg==} dependencies: through: 2.3.8 - dev: true /split2/1.1.1: resolution: {integrity: sha512-cfurE2q8LamExY+lJ9Ex3ZfBwqAPduzOKVscPDXNCLLMvyaeD3DTz1yk7fVIs6Chco+12XeD0BB6HEoYzPYbXA==} @@ -13976,7 +14345,11 @@ packages: resolution: {integrity: sha512-9NThjpgZnifTkJpzTZ7Eue85S49QwpNhZTq6GRJwObb6jnLFNGB7Qm73V5HewTROPyxD0C29xqmaI68bQtV+hg==} dependencies: readable-stream: 3.6.0 - dev: true + + /split2/4.1.0: + resolution: {integrity: sha512-VBiJxFkxiXRlUIeyMQi8s4hgvKCSjtknJv/LVYbrgALPwf5zSKmEwV9Lst25AkvMDnvxODugjdl6KZgwKM1WYQ==} + engines: {node: '>= 10.x'} + dev: false /sprintf-js/1.0.3: resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==} @@ -14011,23 +14384,6 @@ packages: object-copy: 0.1.0 dev: false - /static-server/2.2.1: - resolution: {integrity: sha512-j5eeW6higxYNmXMIT8iHjsdiViTpQDthg7o+SHsRtqdbxscdHqBHXwrXjHC8hL3F0Tsu34ApUpDkwzMBPBsrLw==} - engines: {node: '>=4'} - hasBin: true - dependencies: - chalk: 0.5.1 - commander: 2.20.3 - file-size: 0.0.5 - mime: 1.6.0 - opn: 5.5.0 - dev: false - - /statsd-client/0.4.7: - resolution: {integrity: sha512-+sGCE6FednJ/vI7vywErOg/mhVqmf6Zlktz7cdGRnF/cQWXD9ifMgtqU1CIIXmhSwm11SCk4zDN+bwNCvIR/Kg==} - deprecated: Package no longer supported. Contact Support at https://www.npmjs.com/support for more info. - dev: false - /statuses/1.5.0: resolution: {integrity: sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==} engines: {node: '>= 0.6'} @@ -14046,7 +14402,6 @@ packages: /string-argv/0.3.1: resolution: {integrity: sha512-a1uQGz7IyVy9YwhqjZIZu1c8JO8dNIe20xBmSS6qu9kv++k3JGzCVmprbNN5Kn+BgzD5E7YYwg1CcjuJMRNsvg==} engines: {node: '>=0.6.19'} - dev: true /string-similarity/4.0.4: resolution: {integrity: sha512-/q/8Q4Bl4ZKAPjj8WerIBJWALKkaPRfrvhfF8k/B23i4nzrlRj2/go1m90In7nG/3XDSbOo0+pu6RvCTM9RGMQ==} @@ -14090,7 +14445,7 @@ packages: dependencies: call-bind: 1.0.2 define-properties: 1.1.4 - es-abstract: 1.20.4 + es-abstract: 1.20.5 dev: true /string.prototype.trimstart/1.0.6: @@ -14098,7 +14453,7 @@ packages: dependencies: call-bind: 1.0.2 define-properties: 1.1.4 - es-abstract: 1.20.4 + es-abstract: 1.20.5 dev: true /string_decoder/1.1.1: @@ -14115,14 +14470,6 @@ packages: resolution: {integrity: sha512-Q0/k5orrVGeaOlIOUn1gybGU0IcAbgHQT1faLo5hik4DqClKVSaka5xOhNNoRgtfztHVxCYxi7j71mrWom0bIw==} dev: false - /strip-ansi/0.3.0: - resolution: {integrity: sha512-DerhZL7j6i6/nEnVG0qViKXI0OKouvvpsAiaj7c+LfqZZZxdwZtv8+UiA/w4VUJpT8UzX0pR1dcHOii1GbmruQ==} - engines: {node: '>=0.10.0'} - hasBin: true - dependencies: - ansi-regex: 0.2.1 - dev: false - /strip-ansi/3.0.1: resolution: {integrity: sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==} engines: {node: '>=0.10.0'} @@ -14164,7 +14511,6 @@ packages: /strip-bom/3.0.0: resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==} engines: {node: '>=4'} - dev: true /strip-bom/4.0.0: resolution: {integrity: sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==} @@ -14190,7 +14536,6 @@ packages: engines: {node: '>=8'} dependencies: min-indent: 1.0.1 - dev: true /strip-json-comments/2.0.1: resolution: {integrity: sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==} @@ -14209,6 +14554,10 @@ packages: escape-string-regexp: 1.0.5 dev: false + /striptags/3.2.0: + resolution: {integrity: sha512-g45ZOGzHDMe2bdYMdIvdAfCQkCTDMGBazSw1ypMowwGIee7ZQ5dU0rBJ8Jqgl+jAKIv4dbeE1jscZq9wid1Tkw==} + dev: false + /style-loader/3.3.1_webpack@5.75.0: resolution: {integrity: sha512-GPcQ+LDJbrcxHORTRes6Jy2sfvK2kS6hpSfI/fXhPt+spVzxF6LJ1dHLN9zIGmVaaP044YKaIatFaufENRiDoQ==} engines: {node: '>= 12.13.0'} @@ -14250,12 +14599,6 @@ packages: - supports-color dev: false - /supports-color/0.2.0: - resolution: {integrity: sha512-tdCZ28MnM7k7cJDJc7Eq80A9CsRFAAOZUy41npOZCs++qSjfIy7o5Rh46CBk+Dk5FbKJ33X3Tqg4YrV07N5RaA==} - engines: {node: '>=0.10.0'} - hasBin: true - dev: false - /supports-color/2.0.0: resolution: {integrity: sha512-KKNVtd6pCYgPIKU4cp2733HWYCpplQhddZLBUryaAHou723x+FRzQ5Df824Fj+IyyuiQTRoub4SnIFfIcrp70g==} engines: {node: '>=0.8.0'} @@ -14343,19 +14686,19 @@ packages: readable-stream: 3.6.0 dev: false - /tar/6.1.12: - resolution: {integrity: sha512-jU4TdemS31uABHd+Lt5WEYJuzn+TJTCBLljvIAHZOz6M9Os5pJ4dD+vRFLxPa/n3T0iEFzpi+0x1UfuDZYbRMw==} + /tar/6.1.13: + resolution: {integrity: sha512-jdIBIN6LTIe2jqzay/2vtYLlBHa3JF42ot3h1dW8Q0PaAG4v8rm0cvpVePtau5C6OKXGGcgO9q2AMNSWxiLqKw==} engines: {node: '>=10'} dependencies: chownr: 2.0.0 fs-minipass: 2.1.0 - minipass: 3.3.6 + minipass: 4.0.0 minizlib: 2.1.2 mkdirp: 1.0.4 yallist: 4.0.0 - /taze/0.8.4: - resolution: {integrity: sha512-1dqNgQvNOJY4jPb37FpqOFseIXtezv5MBkTSdrdreX4daC/G+zEi/4PJvl0MiQmIHnBQ3byN8qYU1fM9/ViNKg==} + /taze/0.8.5: + resolution: {integrity: sha512-4aB/BEfBah5iJJUDY3vW7xjJl7AzV6bsQx0PHC1DxIVlCE+JUFfpE7dDPZv/4Z+ft4Eg3I69NWnMnaAUL++rDQ==} hasBin: true dependencies: '@antfu/ni': 0.18.8 @@ -14381,7 +14724,6 @@ packages: dependencies: temp-dir: 2.0.0 uuid: 3.4.0 - dev: true /tempy/1.0.1: resolution: {integrity: sha512-biM9brNqxSc04Ee71hzFbryD11nX7VPhQQY32AdDmjFvodsRFz/3ufeoTZ6uYkRFfGo188tENcASNs3vTdsM0w==} @@ -14407,11 +14749,11 @@ packages: engines: {node: '>=12'} dependencies: ansi-escapes: 5.0.0 - supports-hyperlinks: 2.3.0 + supports-hyperlinks: 2.2.0 dev: false - /terser-webpack-plugin/5.3.6_webpack@5.75.0: - resolution: {integrity: sha512-kfLFk+PoLUQIbLmB1+PZDMRSZS99Mp+/MHqDNmMA6tOItzRt+Npe3E+fsMs5mfcM0wCtrrdU387UnV+vnSffXQ==} + /terser-webpack-plugin/5.3.3_webpack@5.75.0: + resolution: {integrity: sha512-Fx60G5HNYknNTNQnzQ1VePRuu89ZVYWfjRAeT5rITuCY/1b08s49e5kSQwHDirKZWuoKOBRFS98EUUoZ9kLEwQ==} engines: {node: '>= 10.13.0'} peerDependencies: '@swc/core': '*' @@ -14432,7 +14774,7 @@ packages: jest-worker: 27.5.1 schema-utils: 3.1.1 serialize-javascript: 6.0.0 - terser: 5.16.0 + terser: 5.14.2 webpack: 5.75.0 dev: false @@ -14450,7 +14792,6 @@ packages: /text-extensions/1.9.0: resolution: {integrity: sha512-wiBrwC1EhBelW12Zy26JeOUkQ5mRu+5o8rpsJk5+2t+Y5vE7e842qtZDQ2g1NpX/29HdyFeJ4nSIhI47ENSxlQ==} engines: {node: '>=0.10'} - dev: true /text-hex/1.0.0: resolution: {integrity: sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg==} @@ -14460,6 +14801,12 @@ packages: resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==} dev: true + /thread-stream/2.3.0: + resolution: {integrity: sha512-kaDqm1DET9pp3NXwR8382WHbnpXnRkN9xGN9dQt3B2+dmXiW8X1SOwmFOxAErEQ47ObhZ96J6yhZNXuyCOL7KA==} + dependencies: + real-require: 0.2.0 + dev: false + /through/2.3.8: resolution: {integrity: sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==} @@ -14487,7 +14834,6 @@ packages: resolution: {integrity: sha512-iOqSav00cVxEEICeD7TjLB1sueEL+81Wpzp2bY17uZjZN0pWZPuo4suZ/61VujxmqSGFfgOcNuTZ85QJwNZQpw==} dependencies: readable-stream: 3.6.0 - dev: true /thunky/1.1.0: resolution: {integrity: sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==} @@ -14503,6 +14849,11 @@ packages: engines: {node: '>=0.10.0'} dev: false + /tiny-lru/10.0.1: + resolution: {integrity: sha512-Vst+6kEsWvb17Zpz14sRJV/f8bUWKhqm6Dc+v08iShmIJ/WxqWytHzCTd6m88pS33rE2zpX34TRmOpAJPloNCA==} + engines: {node: '>=6'} + dev: false + /tmp-promise/3.0.3: resolution: {integrity: sha512-RwM7MoPojPxsOBYnyd2hy0bxtIlVrihNs9pj5SUvY8Zz1sQcQG2tG1hSr8PDxfgEB8RNKDhqbIlroIarSNDNsQ==} dependencies: @@ -14597,7 +14948,6 @@ packages: /trim-newlines/3.0.1: resolution: {integrity: sha512-c1PTsA3tYrIsLGkJkzHF+w9F2EyxfXGo4UyJc4pFL++FMjnq0HJS69T3M7d//gKrFKwy429bouPescbjecU+Zw==} engines: {node: '>=8'} - dev: true /trim-repeated/1.0.0: resolution: {integrity: sha512-pkonvlKk8/ZuR0D5tLW8ljt5I8kmxp2XKymhepUeOdCEfKpZaktSArkLHZt76OB1ZvO9bssUsDty4SWhLvZpLg==} @@ -14614,7 +14964,7 @@ packages: resolution: {integrity: sha512-+1iDGY6NmOGidq7i7xZGA4cm8DAa6fqdYcvO5Z6yBevH++Bdo9Qt/mN0TzHUgcCcKv1gmh9+W5dHqz8pMWbCbg==} dev: false - /ts-node/10.9.1_cq27usnizs5s2sfjzl5zqe6ljq: + /ts-node/10.9.1_awa2wsr5thmg3i7jqycphctjfq: resolution: {integrity: sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==} hasBin: true peerDependencies: @@ -14633,79 +14983,16 @@ packages: '@tsconfig/node12': 1.0.11 '@tsconfig/node14': 1.0.3 '@tsconfig/node16': 1.0.3 - '@types/node': 18.8.0 + '@types/node': 18.11.18 acorn: 8.8.1 acorn-walk: 8.2.0 arg: 4.1.3 create-require: 1.1.1 diff: 4.0.2 make-error: 1.3.6 - typescript: 4.9.3 + typescript: 4.9.4 v8-compile-cache-lib: 3.0.1 yn: 3.1.1 - dev: true - - /ts-node/10.9.1_kluoused5zacjtflizwvdqgpom: - resolution: {integrity: sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==} - hasBin: true - peerDependencies: - '@swc/core': '>=1.2.50' - '@swc/wasm': '>=1.2.50' - '@types/node': '*' - typescript: '>=2.7' - peerDependenciesMeta: - '@swc/core': - optional: true - '@swc/wasm': - optional: true - dependencies: - '@cspotcode/source-map-support': 0.8.1 - '@tsconfig/node10': 1.0.9 - '@tsconfig/node12': 1.0.11 - '@tsconfig/node14': 1.0.3 - '@tsconfig/node16': 1.0.3 - '@types/node': 14.18.33 - acorn: 8.8.1 - acorn-walk: 8.2.0 - arg: 4.1.3 - create-require: 1.1.1 - diff: 4.0.2 - make-error: 1.3.6 - typescript: 4.9.3 - v8-compile-cache-lib: 3.0.1 - yn: 3.1.1 - dev: true - - /ts-node/10.9.1_wup25etrarvlqkprac7h35hj7u: - resolution: {integrity: sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==} - hasBin: true - peerDependencies: - '@swc/core': '>=1.2.50' - '@swc/wasm': '>=1.2.50' - '@types/node': '*' - typescript: '>=2.7' - peerDependenciesMeta: - '@swc/core': - optional: true - '@swc/wasm': - optional: true - dependencies: - '@cspotcode/source-map-support': 0.8.1 - '@tsconfig/node10': 1.0.9 - '@tsconfig/node12': 1.0.11 - '@tsconfig/node14': 1.0.3 - '@tsconfig/node16': 1.0.3 - '@types/node': 18.11.9 - acorn: 8.8.1 - acorn-walk: 8.2.0 - arg: 4.1.3 - create-require: 1.1.1 - diff: 4.0.2 - make-error: 1.3.6 - typescript: 4.9.3 - v8-compile-cache-lib: 3.0.1 - yn: 3.1.1 - dev: false /tsconfig-paths/3.14.1: resolution: {integrity: sha512-fxDhWnFSLt3VuTwtvJt5fpwxBHg5AdKWMsgcPOOIilyjymcYVZoCQF8fvFRezCNfblEXmi+PcM1eYHeOAgXCOQ==} @@ -14716,6 +15003,10 @@ packages: strip-bom: 3.0.0 dev: true + /tsconfig-vuepress/4.0.4: + resolution: {integrity: sha512-nK1NrYC1T0csgp0AM9qwcGSCRnmoapjrP4FrnnTaaTpaBzqJXbRrtrwHinOKHH2qKoHilurB/z1n0XBX4BlMcQ==} + dev: true + /tslib/1.14.1: resolution: {integrity: sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==} @@ -14726,14 +15017,14 @@ packages: /tslib/2.4.1: resolution: {integrity: sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA==} - /tsutils/3.21.0_typescript@4.9.3: + /tsutils/3.21.0_typescript@4.9.4: resolution: {integrity: sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==} engines: {node: '>= 6'} peerDependencies: typescript: '>=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta' dependencies: tslib: 1.14.1 - typescript: 4.9.3 + typescript: 4.9.4 /twikoo/1.6.8: resolution: {integrity: sha512-SkwO647kK2Ss+L2myp+7JmzmXAGsLt1e7zwTZdKuifDywgFfnaArPWkfp7ruvVBLb+13KQUsCneBUR5XzkV4Bg==} @@ -14756,7 +15047,6 @@ packages: /type-detect/4.0.8: resolution: {integrity: sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==} engines: {node: '>=4'} - dev: true /type-fest/0.10.0: resolution: {integrity: sha512-EUV9jo4sffrwlg8s0zDhP0T2WD3pru5Xi0+HTE3zTUmBaZNhfkite9PdSJwdXLwPVW0jnAHT56pZHIOYckPEiw==} @@ -14771,7 +15061,6 @@ packages: /type-fest/0.18.1: resolution: {integrity: sha512-OIAYXk8+ISY+qTOwkHtKqzAuxchoMiD9Udx+FSGQDuiRR+PJKJHc2NJAXlbhkGwTt/4/nKZxELY1w3ReWOL8mw==} engines: {node: '>=10'} - dev: true /type-fest/0.20.2: resolution: {integrity: sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==} @@ -14813,8 +15102,8 @@ packages: is-typedarray: 1.0.0 dev: false - /typescript/4.9.3: - resolution: {integrity: sha512-CIfGzTelbKNEnLpLdGFgdyKhG23CKdKgQPOBc+OUNrkJ2vr+KSzsSV5kq5iWhEQbok+quxgGzrAtGWCyU7tHnA==} + /typescript/4.9.4: + resolution: {integrity: sha512-Uz+dTXYzxXXbsFpM86Wh3dKCxrQqUcVMxwU54orwlJjOpO3ao8L7j5lH+dWfTwgCwIuM9GQ2kvVotzYJMXTBZg==} engines: {node: '>=4.2.0'} hasBin: true @@ -14827,7 +15116,6 @@ packages: engines: {node: '>=0.8.0'} hasBin: true requiresBuild: true - dev: true optional: true /uid-safe/2.1.5: @@ -14911,6 +15199,16 @@ packages: resolution: {integrity: sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==} engines: {node: '>= 10.0.0'} + /unix-dgram/2.0.6: + resolution: {integrity: sha512-AURroAsb73BZ6CdAyMrTk/hYKNj3DuYYEuOaB8bYMOHGKupRNScw90Q5C71tWJc3uE7dIeXRyuwN0xLLq3vDTg==} + engines: {node: '>=0.10.48'} + requiresBuild: true + dependencies: + bindings: 1.5.0 + nan: 2.17.0 + dev: false + optional: true + /unixify/1.0.0: resolution: {integrity: sha512-6bc58dPYhCMHHuwxldQxO3RRNZ4eCogZ/st++0+fcC1nr0jiGUtAdBJ2qzmLQWSxbtz42pWt4QQMiZ9HvZf5cg==} engines: {node: '>=0.10.0'} @@ -14976,8 +15274,8 @@ packages: resolution: {integrity: sha512-EDxhTEVPZZRLWYcJ4ZXjGFN0oP7qYvbXWzEgRm/Yql4dHX5wDbvh89YHP6PK1lzZJYrMtXUuZZz8XGK+U6U1og==} engines: {node: '>=14.16'} dependencies: - boxen: 7.0.0 - chalk: 5.1.2 + boxen: 7.0.1 + chalk: 5.2.0 configstore: 6.0.0 has-yarn: 3.0.0 import-lazy: 4.0.0 @@ -15060,11 +15358,6 @@ packages: /v8-compile-cache-lib/3.0.1: resolution: {integrity: sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==} - /valid-data-url/3.0.1: - resolution: {integrity: sha512-jOWVmzVceKlVVdwjNSenT4PbGghU0SBIizAev8ofZVgivk/TVHXSbNL8LP6M3spZvkR9/QolkyJavGSX5Cs0UA==} - engines: {node: '>=10'} - dev: false - /validate-npm-package-license/3.0.4: resolution: {integrity: sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==} dependencies: @@ -15082,12 +15375,12 @@ packages: engines: {node: '>= 0.8'} dev: false - /vite-plugin-windicss/1.8.8: - resolution: {integrity: sha512-iyu+ZX0NmhNEUaLPv7xtC+EFRBpWMmw0nhd9a9upayfuNG/thwslKiQKmRB7U/dG0k/2oWLvPDvN/B9i7oRgSA==} + /vite-plugin-windicss/1.8.10: + resolution: {integrity: sha512-scywsuzo46lcTBohspmF0WiwhWEte6p+OUVrX4yr7VMRvLHMHVfLtJReyD5pppjijG7YOwVsZn7XBWWZtF658Q==} peerDependencies: - vite: ^2.0.1 || ^3.0.0 + vite: ^2.0.1 || ^3.0.0 || ^4.0.0 dependencies: - '@windicss/plugin-utils': 1.8.8 + '@windicss/plugin-utils': 1.8.10 debug: 4.3.4 kolorist: 1.6.0 windicss: 3.5.6 @@ -15095,36 +15388,44 @@ packages: - supports-color dev: false - /vite/3.0.9_sass@1.56.1: - resolution: {integrity: sha512-waYABTM+G6DBTCpYAxvevpG50UOlZuynR0ckTK5PawNVt7ebX6X7wNXHaGIO6wYYFXSM7/WcuFuO2QzhBB6aMw==} + /vite/4.0.4_@types+node@18.11.18: + resolution: {integrity: sha512-xevPU7M8FU0i/80DMR+YhgrzR5KS2ORy1B4xcX/cXLsvnUWvfHuqMmVU6N0YiJ4JWGRJJsLCgjEzKjG9/GKoSw==} engines: {node: ^14.18.0 || >=16.0.0} hasBin: true peerDependencies: + '@types/node': '>= 14' less: '*' sass: '*' stylus: '*' + sugarss: '*' terser: ^5.4.0 peerDependenciesMeta: + '@types/node': + optional: true less: optional: true sass: optional: true stylus: optional: true + sugarss: + optional: true + sugarss: + optional: true terser: optional: true dependencies: - esbuild: 0.14.54 - postcss: 8.4.19 + '@types/node': 18.11.18 + esbuild: 0.16.17 + postcss: 8.4.20 resolve: 1.22.1 - rollup: 2.77.3 - sass: 1.56.1 + rollup: 3.9.0 optionalDependencies: fsevents: 2.3.2 - dev: false + dev: true - /vite/3.2.4_@types+node@18.8.0: - resolution: {integrity: sha512-Z2X6SRAffOUYTa+sLy3NQ7nlHFU100xwanq1WDwqaiFiCe+25zdxP1TfCS5ojPV2oDDcXudHIoPnI1Z/66B7Yw==} + /vite/4.0.4_sass@1.57.1: + resolution: {integrity: sha512-xevPU7M8FU0i/80DMR+YhgrzR5KS2ORy1B4xcX/cXLsvnUWvfHuqMmVU6N0YiJ4JWGRJJsLCgjEzKjG9/GKoSw==} engines: {node: ^14.18.0 || >=16.0.0} hasBin: true peerDependencies: @@ -15148,17 +15449,25 @@ packages: terser: optional: true dependencies: - '@types/node': 18.8.0 - esbuild: 0.15.16 - postcss: 8.4.19 + esbuild: 0.16.17 + postcss: 8.4.20 resolve: 1.22.1 - rollup: 2.79.1 + rollup: 3.9.0 + sass: 1.57.1 optionalDependencies: fsevents: 2.3.2 - dev: true + dev: false - /vue-demi/0.13.11_vue@3.2.45: - resolution: {integrity: sha512-IR8HoEEGM65YY3ZJYAjMlKygDQn25D5ajNFNoKh9RSDMQtlzCxtfQjdQgv9jjK+m3377SsJXY8ysq8kLCZL25A==} + /vscode-oniguruma/1.7.0: + resolution: {integrity: sha512-L9WMGRfrjOhgHSdOYgCt/yRMsXzLDJSL7BPrOZt73gU0iWO4mpqzqQzOz5srxqTvMBaR0XZTSrVWo4j55Rc6cA==} + dev: false + + /vscode-textmate/8.0.0: + resolution: {integrity: sha512-AFbieoL7a5LMqcnOF04ji+rpXadgOXnZsxQr//r83kLPr7biP7am3g9zbaZIaBGwBRWeSvoMD4mgPdX3e4NWBg==} + dev: false + + /vue-demi/0.13.6_vue@3.2.47: + resolution: {integrity: sha512-02NYpxgyGE2kKGegRPYlNQSL1UWfA/+JqvzhGCOYjhfbLWXU5QQX0+9pAm/R2sCOPKr5NBxVIab7fvFU0B1RxQ==} engines: {node: '>=12'} hasBin: true requiresBuild: true @@ -15169,17 +15478,17 @@ packages: '@vue/composition-api': optional: true dependencies: - vue: 3.2.45 + vue: 3.2.47 dev: false - /vue-eslint-parser/9.1.0_eslint@8.28.0: + /vue-eslint-parser/9.1.0_eslint@8.32.0: resolution: {integrity: sha512-NGn/iQy8/Wb7RrRa4aRkokyCZfOUWk19OP5HP6JEozQFX5AoS/t+Z0ZN7FY4LlmWc4FNI922V7cvX28zctN8dQ==} engines: {node: ^14.17.0 || >=16.0.0} peerDependencies: eslint: '>=6.0.0' dependencies: debug: 4.3.4 - eslint: 8.28.0 + eslint: 8.32.0 eslint-scope: 7.1.1 eslint-visitor-keys: 3.3.0 espree: 9.4.1 @@ -15190,7 +15499,7 @@ packages: - supports-color dev: true - /vue-loader/17.0.1_vue@3.2.45+webpack@5.75.0: + /vue-loader/17.0.1_vue@3.2.47+webpack@5.75.0: resolution: {integrity: sha512-/OOyugJnImKCkAKrAvdsWMuwoCqGxWT5USLsjohzWbMgOwpA5wQmzQiLMzZd7DjhIfunzAGIApTOgIylz/kwcg==} peerDependencies: '@vue/compiler-sfc': '*' @@ -15206,152 +15515,247 @@ packages: dependencies: chalk: 4.1.2 hash-sum: 2.0.0 - loader-utils: 2.0.4 - vue: 3.2.45 + loader-utils: 2.0.2 + vue: 3.2.47 webpack: 5.75.0 dev: false - /vue-router/4.1.5_vue@3.2.45: - resolution: {integrity: sha512-IsvoF5D2GQ/EGTs/Th4NQms9gd2NSqV+yylxIyp/OYp8xOwxmU8Kj/74E9DTSYAyH5LX7idVUngN3JSj1X4xcQ==} - peerDependencies: - vue: ^3.2.0 - dependencies: - '@vue/devtools-api': 6.4.5 - vue: 3.2.45 - dev: false - - /vue-router/4.1.6_vue@3.2.45: + /vue-router/4.1.6_vue@3.2.47: resolution: {integrity: sha512-DYWYwsG6xNPmLq/FmZn8Ip+qrhFEzA14EI12MsMgVxvHFDYvlr4NXpVF5hrRH1wVcDP8fGi5F4rxuJSl8/r+EQ==} peerDependencies: vue: ^3.2.0 dependencies: '@vue/devtools-api': 6.4.5 - vue: 3.2.45 + vue: 3.2.47 dev: false - /vue/3.2.45: - resolution: {integrity: sha512-9Nx/Mg2b2xWlXykmCwiTUCWHbWIj53bnkizBxKai1g61f2Xit700A1ljowpTIM11e3uipOeiPcSqnmBg6gyiaA==} + /vue/3.2.47: + resolution: {integrity: sha512-60188y/9Dc9WVrAZeUVSDxRQOZ+z+y5nO2ts9jWXSTkMvayiWxCWOWtBQoYjLeccfXkiiPZWAHcV+WTPhkqJHQ==} dependencies: - '@vue/compiler-dom': 3.2.45 - '@vue/compiler-sfc': 3.2.45 - '@vue/runtime-dom': 3.2.45 - '@vue/server-renderer': 3.2.45_vue@3.2.45 - '@vue/shared': 3.2.45 + '@vue/compiler-dom': 3.2.47 + '@vue/compiler-sfc': 3.2.47 + '@vue/runtime-dom': 3.2.47 + '@vue/server-renderer': 3.2.47_vue@3.2.47 + '@vue/shared': 3.2.47 dev: false - /vuepress-plugin-comment2/2.0.0-beta.110_sass-loader@13.2.0: - resolution: {integrity: sha512-P9WqGjoKfssFm1JodDahryzCPg94+9qamfrK2xnhe9X9uOaQsgtnH90eb6BsSXyu+apkTV8gPwEfrg3dbPhR4A==} + /vuepress-plugin-comment2/2.0.0-beta.166_aknydt7aotgymh3yxf7whaz6ti: + resolution: {integrity: sha512-EWWlRbD6a2hJcoI0Pf/Vyea6wqBHRvHS8RRi+jtly5WhxutmxhQA0Byy2qfrTb6sKpuQ0HqK9eIgTdn3KJBZRA==} + engines: {node: ^14.18.0 || >=16.0.0, npm: '>=8', pnpm: '>=7'} peerDependencies: - sass-loader: ^13.0.0 + '@vuepress/client': 2.0.0-beta.60 + sass-loader: ^13.2.0 + vuepress: 2.0.0-beta.60 + vuepress-vite: 2.0.0-beta.60 + vuepress-webpack: 2.0.0-beta.60 peerDependenciesMeta: + '@vuepress/client': + optional: true sass-loader: optional: true + vuepress: + optional: true + vuepress-plugin-sass-palette: + optional: true + vuepress-shared: + optional: true + vuepress-vite: + optional: true + vuepress-webpack: + optional: true dependencies: - '@vuepress/client': 2.0.0-beta.51 - '@vuepress/utils': 2.0.0-beta.51 - '@waline/client': 2.14.1 - giscus: 1.2.4 - sass-loader: 13.2.0_sass@1.56.1 + '@vuepress/client': 2.0.0-beta.60 + '@vuepress/shared': 2.0.0-beta.60 + '@vuepress/utils': 2.0.0-beta.60 + '@waline/client': 2.14.7 + giscus: 1.2.6 twikoo: 1.6.8 - vue: 3.2.45 - vue-router: 4.1.5_vue@3.2.45 - vuepress-plugin-sass-palette: 2.0.0-beta.110_sass-loader@13.2.0 - vuepress-shared: 2.0.0-beta.110 + vue: 3.2.47 + vue-router: 4.1.6_vue@3.2.47 + vuepress-plugin-sass-palette: 2.0.0-beta.166_aknydt7aotgymh3yxf7whaz6ti + vuepress-shared: 2.0.0-beta.166_aknydt7aotgymh3yxf7whaz6ti transitivePeerDependencies: - '@vue/composition-api' - supports-color dev: false - /vuepress-plugin-md-enhance/2.0.0-beta.110_sass-loader@13.2.0: - resolution: {integrity: sha512-e1AQQeyERo5SiZiEsPqtkjZ0e9Fy8kWdYx+VOUGUBoFGqIaokC/YWOtiUn4ItM+iC2l4e/VFbrJJjeye73UWHw==} + /vuepress-plugin-md-enhance/2.0.0-beta.166_aknydt7aotgymh3yxf7whaz6ti: + resolution: {integrity: sha512-t9tKfLR8c83y11CeUOjiSpl82ZdLgspDQKENHU0StHSsbNloG2VcvuO9zerebgYbA+59aCKlJS870qG+ajkNFg==} + engines: {node: ^14.18.0 || >=16.0.0, npm: '>=8', pnpm: '>=7'} peerDependencies: - sass-loader: ^13.0.0 + '@vuepress/client': 2.0.0-beta.60 + sass-loader: ^13.2.0 + vuepress: 2.0.0-beta.60 + vuepress-vite: 2.0.0-beta.60 + vuepress-webpack: 2.0.0-beta.60 peerDependenciesMeta: + '@vuepress/client': + optional: true sass-loader: optional: true + vuepress: + optional: true + vuepress-plugin-sass-palette: + optional: true + vuepress-shared: + optional: true + vuepress-vite: + optional: true + vuepress-webpack: + optional: true dependencies: - '@babel/core': 7.20.5 - '@types/katex': 0.14.0 + '@babel/core': 7.20.12 + '@mdit/plugin-align': 0.2.3 + '@mdit/plugin-attrs': 0.2.3 + '@mdit/plugin-container': 0.2.3 + '@mdit/plugin-figure': 0.2.3 + '@mdit/plugin-footnote': 0.2.3 + '@mdit/plugin-img-lazyload': 0.2.3 + '@mdit/plugin-img-mark': 0.2.3 + '@mdit/plugin-img-size': 0.2.3 + '@mdit/plugin-include': 0.2.3 + '@mdit/plugin-katex': 0.2.3 + '@mdit/plugin-mark': 0.2.3 + '@mdit/plugin-mathjax': 0.2.3 + '@mdit/plugin-stylize': 0.2.3 + '@mdit/plugin-sub': 0.2.3 + '@mdit/plugin-sup': 0.2.3 + '@mdit/plugin-tab': 0.2.3 + '@mdit/plugin-tasklist': 0.2.3 + '@mdit/plugin-tex': 0.2.3 + '@mdit/plugin-uml': 0.2.3 + '@mermaid-js/mermaid-mindmap': 9.3.0 '@types/markdown-it': 12.2.3 - '@types/mermaid': 9.2.0 - '@vue/repl': 1.3.2_vue@3.2.45 - '@vuepress/client': 2.0.0-beta.51 - '@vuepress/shared': 2.0.0-beta.51 - '@vuepress/utils': 2.0.0-beta.51 - '@vueuse/core': 9.6.0_vue@3.2.45 + '@vue/repl': 1.3.2_vue@3.2.47 + '@vuepress/client': 2.0.0-beta.60 + '@vuepress/shared': 2.0.0-beta.60 + '@vuepress/utils': 2.0.0-beta.60 + '@vueuse/core': 9.12.0_vue@3.2.47 balloon-css: 1.2.0 - chart.js: 3.9.1 - echarts: 5.4.0 - flowchart.js: 1.17.1 - juice: 8.1.0 - katex: 0.16.3 + chart.js: 4.2.0 + echarts: 5.4.1 + flowchart.ts: 0.1.2 + katex: 0.16.4 markdown-it: 13.0.1 - mathjax-full: 3.2.2 - mermaid: 9.2.2 + mermaid: 9.3.0 reveal.js: 4.4.0 - sass-loader: 13.2.0_sass@1.56.1 - vue: 3.2.45 - vue-router: 4.1.5_vue@3.2.45 - vuepress-plugin-sass-palette: 2.0.0-beta.110_sass-loader@13.2.0 - vuepress-shared: 2.0.0-beta.110 + vue: 3.2.47 + vue-router: 4.1.6_vue@3.2.47 + vuepress-plugin-sass-palette: 2.0.0-beta.166_aknydt7aotgymh3yxf7whaz6ti + vuepress-shared: 2.0.0-beta.166_aknydt7aotgymh3yxf7whaz6ti transitivePeerDependencies: - '@vue/composition-api' - - encoding - supports-color dev: false - /vuepress-plugin-sass-palette/2.0.0-beta.110_sass-loader@13.2.0: - resolution: {integrity: sha512-GKBdDQ4vo4NvUrf0+SKkcnUcAFZ9i0u4PGBpmsW+moVcSRZLHHS2uC+Am27X9r05em9XYmtd+0q62Zg1xXZznA==} + /vuepress-plugin-sass-palette/2.0.0-beta.166_aknydt7aotgymh3yxf7whaz6ti: + resolution: {integrity: sha512-sO8s0tbGMFHIKzeblDX29Ba/qHzyNbWtJqoKu+aTcMObc4uc1yVqmjrNTnvFDAmFaM4LmgxZ51iQqm0SZnfvSw==} + engines: {node: ^14.18.0 || >=16.0.0, npm: '>=8', pnpm: '>=7'} peerDependencies: - sass-loader: ^13.0.0 + sass-loader: ^13.2.0 + vuepress: 2.0.0-beta.60 + vuepress-vite: 2.0.0-beta.60 + vuepress-webpack: 2.0.0-beta.60 peerDependenciesMeta: sass-loader: optional: true + vuepress: + optional: true + vuepress-shared: + optional: true + vuepress-vite: + optional: true + vuepress-webpack: + optional: true dependencies: - '@vuepress/utils': 2.0.0-beta.51 + '@vuepress/shared': 2.0.0-beta.60 + '@vuepress/utils': 2.0.0-beta.60 chokidar: 3.5.3 - sass: 1.56.1 - sass-loader: 13.2.0_sass@1.56.1 - vuepress-shared: 2.0.0-beta.110 + sass: 1.57.1 + vuepress-shared: 2.0.0-beta.166_aknydt7aotgymh3yxf7whaz6ti transitivePeerDependencies: + - '@vuepress/client' - supports-color dev: false - /vuepress-plugin-seo2/2.0.0-beta.110: - resolution: {integrity: sha512-Ffd/HKEDTRZ2CW6Vo2Vi0+2kp401HI05xmwO/opWI9LzIdtoEBt9lOAWvcq33uycVy7dgggMAjyKyHU3KWszuQ==} + /vuepress-plugin-seo2/2.0.0-beta.166_aknydt7aotgymh3yxf7whaz6ti: + resolution: {integrity: sha512-+jC17xWqyEBMgbvWmGud6mzDmAHE7IaOY/S34izeq3ZTVm4hhW1KxjFRyv6tIhA/GMXq/yBWSqEx9NUI9oVg0g==} + engines: {node: ^14.18.0 || >=16.0.0, npm: '>=8', pnpm: '>=7'} + peerDependencies: + vuepress: 2.0.0-beta.60 + vuepress-vite: 2.0.0-beta.60 + vuepress-webpack: 2.0.0-beta.60 + peerDependenciesMeta: + vuepress: + optional: true + vuepress-vite: + optional: true + vuepress-webpack: + optional: true dependencies: - '@vuepress/shared': 2.0.0-beta.51 - '@vuepress/utils': 2.0.0-beta.51 - gray-matter: 4.0.3 - vuepress-shared: 2.0.0-beta.110 + '@vuepress/shared': 2.0.0-beta.60 + '@vuepress/utils': 2.0.0-beta.60 + vuepress-shared: 2.0.0-beta.166_aknydt7aotgymh3yxf7whaz6ti transitivePeerDependencies: + - '@vuepress/client' - supports-color dev: false - /vuepress-plugin-sitemap2/2.0.0-beta.110: - resolution: {integrity: sha512-F7diM66NKZk4pNr2EpUgrS6X9G4/+/+7KGHcspZdFnY7cexE1ZwFqQbcXiVRnsgdqLXKnDk2hCSN5eNeMafAPg==} + /vuepress-plugin-sitemap2/2.0.0-beta.166_aknydt7aotgymh3yxf7whaz6ti: + resolution: {integrity: sha512-mVruZNQYPuIA95C9AC73MCBoOqG4A87XbhpEA6hXgIDrPeJ8B5P8xD2OPbQ4yZx93o0hMyD8/L4huwpPSPFdAA==} + engines: {node: ^14.18.0 || >=16.0.0, npm: '>=8', pnpm: '>=7'} + peerDependencies: + vuepress: 2.0.0-beta.60 + vuepress-vite: 2.0.0-beta.60 + vuepress-webpack: 2.0.0-beta.60 + peerDependenciesMeta: + vuepress: + optional: true + vuepress-shared: + optional: true + vuepress-vite: + optional: true + vuepress-webpack: + optional: true dependencies: - '@vuepress/shared': 2.0.0-beta.51 - '@vuepress/utils': 2.0.0-beta.51 + '@vuepress/shared': 2.0.0-beta.60 + '@vuepress/utils': 2.0.0-beta.60 sitemap: 7.1.1 - vuepress-shared: 2.0.0-beta.110 + vuepress-shared: 2.0.0-beta.166_aknydt7aotgymh3yxf7whaz6ti transitivePeerDependencies: + - '@vuepress/client' - supports-color dev: false - /vuepress-shared/2.0.0-beta.110: - resolution: {integrity: sha512-3nqPOH4lLd1Vfl9EHs9m7u4XZRRwFGopfyANwdpt5Fl+llVYOQzG/zLbGSjKKcWkem4hjgGWY1olpyARjWGjlg==} + /vuepress-shared/2.0.0-beta.166_aknydt7aotgymh3yxf7whaz6ti: + resolution: {integrity: sha512-lfDVG2I5RbXrBGIVeF6WjcAzR8IT3nyWFMPtsmQVoO88v3ygQu4UxLla+apB0Wr4csR4M8PaBzhTVReJmeaAjQ==} + engines: {node: ^14.18.0 || >=16.0.0, npm: '>=8', pnpm: '>=7'} + peerDependencies: + '@vuepress/client': 2.0.0-beta.60 + vuepress: 2.0.0-beta.60 + vuepress-vite: 2.0.0-beta.60 + vuepress-webpack: 2.0.0-beta.60 + peerDependenciesMeta: + '@vuepress/client': + optional: true + vuepress: + optional: true + vuepress-vite: + optional: true + vuepress-webpack: + optional: true dependencies: - '@vuepress/client': 2.0.0-beta.51 - '@vuepress/plugin-git': 2.0.0-beta.51 - '@vuepress/shared': 2.0.0-beta.51 - '@vuepress/utils': 2.0.0-beta.51 - dayjs: 1.11.6 + '@vuepress/client': 2.0.0-beta.60 + '@vuepress/shared': 2.0.0-beta.60 + '@vuepress/utils': 2.0.0-beta.60 + cheerio: 1.0.0-rc.12 + dayjs: 1.11.7 execa: 6.1.0 fflate: 0.7.4 - ora: 6.1.2 - vue: 3.2.45 - vue-router: 4.1.5_vue@3.2.45 + gray-matter: 4.0.3 + striptags: 3.2.0 + vue: 3.2.47 + vue-router: 4.1.6_vue@3.2.47 transitivePeerDependencies: - supports-color dev: false @@ -15391,20 +15795,6 @@ packages: dependencies: defaults: 1.0.4 - /web-resource-inliner/6.0.1: - resolution: {integrity: sha512-kfqDxt5dTB1JhqsCUQVFDj0rmY+4HLwGQIsLPbyrsN9y9WV/1oFDSx3BQ4GfCv9X+jVeQ7rouTqwK53rA/7t8A==} - engines: {node: '>=10.0.0'} - dependencies: - ansi-colors: 4.1.3 - escape-goat: 3.0.0 - htmlparser2: 5.0.1 - mime: 2.6.0 - node-fetch: 2.6.7 - valid-data-url: 3.0.1 - transitivePeerDependencies: - - encoding - dev: false - /web-streams-polyfill/3.2.1: resolution: {integrity: sha512-e0MO3wdXWKrLbL0DgGnUV7WHVuw9OUvL4hjgnPkIeEvESk74gAITi5G606JtZPp39cd8HA9VQzCIvA49LpPN5Q==} engines: {node: '>= 8'} @@ -15454,7 +15844,7 @@ packages: dependencies: '@types/bonjour': 3.5.10 '@types/connect-history-api-fallback': 1.3.5 - '@types/express': 4.17.14 + '@types/express': 4.17.15 '@types/serve-index': 1.9.1 '@types/serve-static': 1.15.0 '@types/sockjs': 0.3.33 @@ -15469,7 +15859,7 @@ packages: express: 4.18.2 graceful-fs: 4.2.10 html-entities: 2.3.3 - http-proxy-middleware: 2.0.6_@types+express@4.17.14 + http-proxy-middleware: 2.0.6_@types+express@4.17.15 ipaddr.js: 2.0.1 open: 8.4.0 p-retry: 4.6.2 @@ -15481,7 +15871,7 @@ packages: spdy: 4.0.2 webpack: 5.75.0 webpack-dev-middleware: 5.3.3_webpack@5.75.0 - ws: 8.11.0 + ws: 8.8.1 transitivePeerDependencies: - bufferutil - debug @@ -15545,7 +15935,7 @@ packages: neo-async: 2.6.2 schema-utils: 3.1.1 tapable: 2.2.1 - terser-webpack-plugin: 5.3.6_webpack@5.75.0 + terser-webpack-plugin: 5.3.3_webpack@5.75.0 watchpack: 2.4.0 webpack-sources: 3.2.3 transitivePeerDependencies: @@ -15697,7 +16087,6 @@ packages: /wordwrap/1.0.0: resolution: {integrity: sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==} - dev: true /wrap-ansi/2.1.0: resolution: {integrity: sha512-vAaEaDM946gbNpH5pLVNR+vX2ht6n0Bt3GXwVB1AuAqZosOvHNF3P7wDnh8KLkSqgUh0uh77le7Owgoz+Z9XBw==} @@ -15820,22 +16209,25 @@ packages: resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} engines: {node: '>=10'} + /yallist/3.1.1: + resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} + dev: false + /yallist/4.0.0: resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==} /yaml/1.10.2: resolution: {integrity: sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==} engines: {node: '>= 6'} + dev: false - /yaml/2.1.3: - resolution: {integrity: sha512-AacA8nRULjKMX2DvWvOAdBZMOfQlypSFkjcOcu9FalllIDJ1kvlREzcdIZmidQUqqeMv7jorHjq2HlLv/+c2lg==} + /yaml/2.2.0: + resolution: {integrity: sha512-auf7Gi6QwO7HW//GA9seGvTXVGWl1CM/ADWh1+RxtXr6XOxnT65ovDl9fTi4e0monEyJxCHqDpF6QnFDXmJE4g==} engines: {node: '>= 14'} - dev: true /yargs-parser/20.2.9: resolution: {integrity: sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==} engines: {node: '>=10'} - dev: true /yargs-parser/21.1.1: resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==} @@ -15852,7 +16244,6 @@ packages: string-width: 4.2.3 y18n: 5.0.8 yargs-parser: 20.2.9 - dev: true /yargs/17.6.2: resolution: {integrity: sha512-1/9UrdHjDZc0eOU0HxOHoS78C69UD3JRMvzlJ7S79S2nTaWRA/whGCTV8o9e/N/1Va9YIV7Q4sOxD8VV4pCWOw==} @@ -15907,8 +16298,8 @@ packages: readable-stream: 3.6.0 dev: false - /zrender/5.4.0: - resolution: {integrity: sha512-rOS09Z2HSVGFs2dn/TuYk5BlCaZcVe8UDLLjj1ySYF828LATKKdxuakSZMvrDz54yiKPDYVfjdKqcX8Jky3BIA==} + /zrender/5.4.1: + resolution: {integrity: sha512-M4Z05BHWtajY2241EmMPHglDQAJ1UyHQcYsxDNzD9XLSkPDqMq4bB28v9Pb4mvHnVQ0GxyTklZ/69xCFP6RXBA==} dependencies: tslib: 2.3.0 dev: false diff --git a/scripts/autoInstall.js b/scripts/autoInstall.js index 44ab8014..4b8f2738 100644 --- a/scripts/autoInstall.js +++ b/scripts/autoInstall.js @@ -13,7 +13,7 @@ const _dirname = const packages = [ ...fs .readdirSync(path.join(_dirname, '../packages')) - .filter((file) => file !== '.DS_Store') + .filter((file) => file !== '.DS_Store' && file !== 'tsconfig.build.json') .map((dir) => path.join('../packages', dir)), '../docs', ] diff --git a/scripts/create/generator.js b/scripts/create/generator.js index 2f559d71..2c5e2325 100644 --- a/scripts/create/generator.js +++ b/scripts/create/generator.js @@ -39,8 +39,8 @@ const generatorFile = async (config) => { } const include = [ !client && 'client', - !client && 'tsconfig.esm.json', !shared && 'shared', + !shared && 'client/index.js' ] .filter(Boolean) .join('|') diff --git a/scripts/create/template/package.json.tpl b/scripts/create/template/package.json.tpl index 90bda795..d7beed33 100644 --- a/scripts/create/template/package.json.tpl +++ b/scripts/create/template/package.json.tpl @@ -18,10 +18,16 @@ }, "license": "MIT", "author": "pengzhanbo ", + "type": "module", + "exports": { + ".": "./lib/node/index.js", + {{#if shared }} + "./client": "./lib/client/index.js", + {{/if}} + "./package.json": "./package.json" + }, "main": "lib/node/index.js", - "files": [ - "lib" - ], + "types": "./lib/node/index.d.ts", "scripts": { "build": "pnpm run clean && pnpm run copy && pnpm run ts", "clean": "rimraf lib *.tsbuildinfo", diff --git a/scripts/create/template/src/client/clientAppEnhance.ts.tpl b/scripts/create/template/src/client/clientAppEnhance.ts.tpl deleted file mode 100644 index 1f8efeb1..00000000 --- a/scripts/create/template/src/client/clientAppEnhance.ts.tpl +++ /dev/null @@ -1,5 +0,0 @@ -import { defineClientAppEnhance } from '@vuepress/client' - -export default defineClientAppEnhance(({ router }) => { - // do something -}) diff --git a/scripts/create/template/src/client/clientConfig.ts.tpl b/scripts/create/template/src/client/clientConfig.ts.tpl new file mode 100644 index 00000000..e5214719 --- /dev/null +++ b/scripts/create/template/src/client/clientConfig.ts.tpl @@ -0,0 +1,8 @@ +import { defineClientConfig } from '@vuepress/client' + + +export default defineClientConfig({ + setup() { + // do something + }, +}) diff --git a/scripts/create/template/src/client/index.ts.tpl b/scripts/create/template/src/client/index.ts.tpl new file mode 100644 index 00000000..72593733 --- /dev/null +++ b/scripts/create/template/src/client/index.ts.tpl @@ -0,0 +1 @@ +export * from '../shared/index.js' diff --git a/scripts/create/template/src/node/index.ts.tpl b/scripts/create/template/src/node/index.ts.tpl index 3cc41374..cecc69ed 100644 --- a/scripts/create/template/src/node/index.ts.tpl +++ b/scripts/create/template/src/node/index.ts.tpl @@ -1,8 +1,8 @@ -import { {{ lowerName }}Plugin } from './plugin' +import { {{ lowerName }}Plugin } from './plugin.js' -export * from './plugin' +export * from './plugin.js' {{#if shared }} -export * from '../shared' +export * from '../shared/index.js' {{/if}} export default {{ lowerName }}Plugin diff --git a/scripts/create/template/src/node/plugin.ts.tpl b/scripts/create/template/src/node/plugin.ts.tpl index 49cc2a53..7c533057 100644 --- a/scripts/create/template/src/node/plugin.ts.tpl +++ b/scripts/create/template/src/node/plugin.ts.tpl @@ -3,7 +3,7 @@ import type { App, Plugin } from '@vuepress/core' import { path } from '@vuepress/utils' {{/if}} {{#if shared}} -import type { {{ upperName }}Options } from '../shared' +import type { {{ upperName }}Options } from '../shared/index.js' {{else}} export interface {{ upperName }}Options { @@ -16,10 +16,7 @@ export const {{ lowerName }}Plugin = (options: {{ upperName }}Options): Plugin = return { name: '@vuepress-plume/vuepress-{{ pkgName }}', {{#if client}} - clientAppEnhanceFiles: path.resolve( - __dirname, - '../client/clientAppEnhance.js' - ), + clientConfigFile: path.resolve(__dirname, '../client/clientConfig.js'), {{/if}} } } diff --git a/scripts/create/template/tsconfig.build.json.tpl b/scripts/create/template/tsconfig.build.json.tpl index ed748a05..66824ada 100644 --- a/scripts/create/template/tsconfig.build.json.tpl +++ b/scripts/create/template/tsconfig.build.json.tpl @@ -1,14 +1,8 @@ { - "extends": "../../tsconfig.base.json", - "references": [ - {{#if client}} - { - "path": "./tsconfig.esm.json" - }, - {{/if}} - { - "path": "./tsconfig.cjs.json" - } - ], - "files": [] +"extends": "../tsconfig.build.json", +"compilerOptions": { +"rootDir": "./src", +"outDir": "./lib" +}, +"include": ["./src"] } diff --git a/scripts/create/template/tsconfig.cjs.json.tpl b/scripts/create/template/tsconfig.cjs.json.tpl deleted file mode 100644 index c0c6d891..00000000 --- a/scripts/create/template/tsconfig.cjs.json.tpl +++ /dev/null @@ -1,14 +0,0 @@ -{ - "extends": "../../tsconfig.base.json", - "compilerOptions": { - "module": "CommonJS", - "rootDir": "./src", - "outDir": "./lib" - }, - "include": [ - {{#if shared}} - "./src/shared", - {{/if}} - "./src/node" - ] -} diff --git a/scripts/create/template/tsconfig.esm.json.tpl b/scripts/create/template/tsconfig.esm.json.tpl deleted file mode 100644 index eb18f932..00000000 --- a/scripts/create/template/tsconfig.esm.json.tpl +++ /dev/null @@ -1,17 +0,0 @@ -{ - "extends": "../../tsconfig.base.json", - "compilerOptions": { - "module": "ES2020", - "rootDir": "./src", - "outDir": "./lib", - "types": [ - "@vuepress/client/types" - ] - }, - "include": [ - {{#if shared}} - "./src/shared", - {{/if}} - "./src/client" - ] -} diff --git a/tsconfig.base.json b/tsconfig.base.json index 8ecec5a4..7dbe13db 100644 --- a/tsconfig.base.json +++ b/tsconfig.base.json @@ -1,47 +1,13 @@ { + "extends": "tsconfig-vuepress/base.json", "compilerOptions": { - "composite": true, "allowSyntheticDefaultImports": true, "lib": ["DOM", "ES2020"], - "module": "esnext", + "module": "ESNext", "moduleResolution": "NodeNext", "noEmitOnError": true, - "esModuleInterop": true, + "noImplicitAny": false, "skipLibCheck": true, - "target": "ES2020", - "allowJs": false, - "allowUmdGlobalAccess": false, - "allowUnreachableCode": false, - "allowUnusedLabels": false, - "alwaysStrict": true, - "checkJs": false, - "declaration": true, - "declarationMap": false, - "exactOptionalPropertyTypes": false, - "forceConsistentCasingInFileNames": true, - "importsNotUsedAsValues": "error", - "newLine": "lf", - "noFallthroughCasesInSwitch": false, - "noImplicitAny": true, - "noImplicitOverride": true, - "noImplicitReturns": true, - "noImplicitThis": true, - "noImplicitUseStrict": false, - "noPropertyAccessFromIndexSignature": false, - "noStrictGenericChecks": false, - "noUncheckedIndexedAccess": false, - "noUnusedLocals": false, - "noUnusedParameters": false, - "preserveValueImports": false, - "removeComments": false, - "resolveJsonModule": true, - "sourceMap": false, - "strict": true, - "strictBindCallApply": true, - "strictFunctionTypes": true, - "strictNullChecks": true, - "strictPropertyInitialization": true, - "stripInternal": true, - "useUnknownInCatchVariables": true + "target": "ES2020" } } diff --git a/tsconfig.json b/tsconfig.json index b1cb9e06..db24b07a 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -6,6 +6,12 @@ "jsx": "preserve", "paths": { "@theme-plume/*": ["./packages/theme/src/client/components/*"], + "@internal/blogData": [ + "./packages/plugin-blog-data/src/client/blogPostData.d.ts" + ], + "@internal/notesData": [ + "./packages/plugin-notes-data/src/client/notesData.d.ts" + ], "@internal/*": ["./docs/.vuepress/.temp/internal/*"], "@vuepress-plume/vuepress-*": ["./packages/*/src/node/index.ts"], "@vuepress-plume/vuepress-theme-plume": [ @@ -14,9 +20,6 @@ }, "types": ["webpack-env", "vite/client"] }, - "vueCompilerOptions": { - "experimentalDisableTemplateSupport": true - }, "include": ["packages/**/*", "docs/.vuepress/**/*", "scripts/**/*"], "exclude": ["node_modules", ".temp", "lib", "dist"], "ts-node": {