[其他] 初始化项目结构

This commit is contained in:
就眠仪式
2021-09-27 06:09:33 +08:00
commit b2fa2b90b8
73 changed files with 9752 additions and 0 deletions

View File

@@ -0,0 +1,700 @@
##### 基础
::: demo 传入 columns 数据,自动生成表格
<template>
<ele-table
:data="data"
:columns="columns"
/>
</template>
<script>
import { ref } from 'vue'
export default {
setup() {
const columns = ref([
{
label: '日期',
prop: 'date',
},
{
label: '姓名',
prop: 'name',
},
{
label: '地址',
prop: 'address',
},
])
const data = ref([
{
date: '2016-05-03',
name: 'Tom',
address: 'No. 189, Grove St, Los Angeles',
},
{
date: '2016-05-02',
name: 'Tom',
address: 'No. 189, Grove St, Los Angeles',
},
{
date: '2016-05-04',
name: 'Tom',
address: 'No. 189, Grove St, Los Angeles',
},
{
date: '2016-05-01',
name: 'Tom',
address: 'No. 189, Grove St, Los Angeles',
},
])
return {
data,
columns,
}
}
}
</script>
:::
##### 索引
::: demo 通过配置 index 显示索引列,支持 columns 的参数
<template>
<ele-table
:data="data"
:columns="columns"
:index="{ label: '#' }"
/>
</template>
<script>
import { ref } from 'vue'
export default {
setup() {
const columns = ref([
{
label: '日期',
prop: 'date',
},
{
label: '姓名',
prop: 'name',
},
{
label: '地址',
prop: 'address',
},
])
const data = ref([
{
date: '2016-05-03',
name: 'Tom',
address: 'No. 189, Grove St, Los Angeles',
},
{
date: '2016-05-02',
name: 'Tom',
address: 'No. 189, Grove St, Los Angeles',
},
{
date: '2016-05-04',
name: 'Tom',
address: 'No. 189, Grove St, Los Angeles',
},
{
date: '2016-05-01',
name: 'Tom',
address: 'No. 189, Grove St, Los Angeles',
},
])
return {
data,
columns,
}
}
}
</script>
:::
##### 多选
::: demo 通过配置 selection 显示多选框,支持 columns 的参数
<template>
<ele-table
:data="data"
:columns="columns"
selection
/>
</template>
<script>
import { ref } from 'vue'
export default {
setup() {
const columns = ref([
{
label: '日期',
prop: 'date',
},
{
label: '姓名',
prop: 'name',
},
{
label: '地址',
prop: 'address',
},
])
const data = ref([
{
date: '2016-05-03',
name: 'Tom',
address: 'No. 189, Grove St, Los Angeles',
},
{
date: '2016-05-02',
name: 'Tom',
address: 'No. 189, Grove St, Los Angeles',
},
{
date: '2016-05-04',
name: 'Tom',
address: 'No. 189, Grove St, Los Angeles',
},
{
date: '2016-05-01',
name: 'Tom',
address: 'No. 189, Grove St, Los Angeles',
},
])
return {
data,
columns,
}
}
}
</script>
:::
##### 展开
::: demo 通过配置 expand 开启展开插槽,通过 #expand 插槽定制显示内容,支持 columns 的参数
<template>
<ele-table
:data="data"
:columns="columns"
expand
>
<template #expand="{ row }">
{{ row }}
</template>
</ele-table>
</template>
<script>
import { ref } from 'vue'
export default {
setup() {
const columns = ref([
{
label: '日期',
prop: 'date',
},
{
label: '姓名',
prop: 'name',
},
{
label: '地址',
prop: 'address',
},
])
const data = ref([
{
date: '2016-05-03',
name: 'Tom',
address: 'No. 189, Grove St, Los Angeles',
},
{
date: '2016-05-02',
name: 'Tom',
address: 'No. 189, Grove St, Los Angeles',
},
{
date: '2016-05-04',
name: 'Tom',
address: 'No. 189, Grove St, Los Angeles',
},
{
date: '2016-05-01',
name: 'Tom',
address: 'No. 189, Grove St, Los Angeles',
},
])
return {
data,
columns,
}
}
}
</script>
:::
##### 操作
::: demo 通过配置 menu 开启按钮插槽,通过 #menu 插槽定制显示内容,支持 columns 的参数
<template>
<ele-table
:data="data"
:columns="columns"
:menu="menu"
>
<template #menu="{ size }">
<el-button
:size="size"
type="text"
>
详情
</el-button>
</template>
</ele-table>
</template>
<script>
import { ref } from 'vue'
export default {
setup() {
const menu = ref({
label: '操作',
align: 'center',
})
const columns = ref([
{
label: '日期',
prop: 'date',
},
{
label: '姓名',
prop: 'name',
},
{
label: '地址',
prop: 'address',
},
])
const data = ref([
{
date: '2016-05-03',
name: 'Tom',
address: 'No. 189, Grove St, Los Angeles',
},
{
date: '2016-05-02',
name: 'Tom',
address: 'No. 189, Grove St, Los Angeles',
},
{
date: '2016-05-04',
name: 'Tom',
address: 'No. 189, Grove St, Los Angeles',
},
{
date: '2016-05-01',
name: 'Tom',
address: 'No. 189, Grove St, Los Angeles',
},
])
return {
menu,
data,
columns,
}
}
}
</script>
:::
##### 插槽
::: demo
<template>
<ele-table
:data="data"
:columns="columns3"
>
<template #name-header="{ column }">
<s>{{ column.label }}</s>
</template>
<template #name="{ row, size }">
<el-tag :size="size">
{{ row?.name }}
</el-tag>
</template>
<template #menu="{ size }">
<el-button
:size="size"
type="text"
>
详情
</el-button>
</template>
</ele-table>
</template>
<script>
import { ref } from 'vue'
export default {
setup() {
const columns3 = ref([
{
label: '日期',
prop: 'date',
},
{
label: '姓名',
prop: 'name',
slot: true,
},
{
label: '地址',
prop: 'address',
},
])
const data = ref([
{
date: '2016-05-03',
name: 'Tom',
address: 'No. 189, Grove St, Los Angeles',
},
{
date: '2016-05-02',
name: 'Tom',
address: 'No. 189, Grove St, Los Angeles',
},
{
date: '2016-05-04',
name: 'Tom',
address: 'No. 189, Grove St, Los Angeles',
},
{
date: '2016-05-01',
name: 'Tom',
address: 'No. 189, Grove St, Los Angeles',
},
])
return {
data,
columns3,
}
}
}
</script>
:::
##### 分页
::: demo 当传入 total 数据时,将自动显示分页。可以通过 `v-model:current-page` 绑定当前页数、通过 `v-model:page-size` 绑定每页显示条目个数
<template>
<ele-table
v-model:current-page="currentPage"
v-model:page-size="pageSize"
:data="data"
:columns="columns"
:total="total"
/>
</template>
<script>
import { ref } from 'vue'
export default {
setup() {
const currentPage = ref(1)
const pageSize = ref(10)
const total = ref(50)
const columns = ref([
{
label: '日期',
prop: 'date',
},
{
label: '姓名',
prop: 'name',
},
{
label: '地址',
prop: 'address',
},
])
const data = ref([
{
date: '2016-05-03',
name: 'Tom',
address: 'No. 189, Grove St, Los Angeles',
},
{
date: '2016-05-02',
name: 'Tom',
address: 'No. 189, Grove St, Los Angeles',
},
{
date: '2016-05-04',
name: 'Tom',
address: 'No. 189, Grove St, Los Angeles',
},
{
date: '2016-05-01',
name: 'Tom',
address: 'No. 189, Grove St, Los Angeles',
},
])
return {
currentPage,
pageSize,
total,
data,
columns,
}
}
}
</script>
:::
##### 多级
::: demo 通过 columns 的 `children` 配置多级表头
<template>
<ele-table
:data="data"
:columns="columns2"
/>
</template>
<script>
import { ref } from 'vue'
export default {
setup() {
const columns2 = ref([
{
label: '日期',
prop: 'date',
},
{
label: '用户',
children: [
{
label: '姓名',
prop: 'name',
},
{
label: '地址',
prop: 'address',
},
],
},
])
const data = ref([
{
date: '2016-05-03',
name: 'Tom',
address: 'No. 189, Grove St, Los Angeles',
},
{
date: '2016-05-02',
name: 'Tom',
address: 'No. 189, Grove St, Los Angeles',
},
{
date: '2016-05-04',
name: 'Tom',
address: 'No. 189, Grove St, Los Angeles',
},
{
date: '2016-05-01',
name: 'Tom',
address: 'No. 189, Grove St, Los Angeles',
},
])
return {
data,
columns2,
}
}
}
</script>
:::
##### 配置
| 参数 | 说明 | 类型 | 可选值 | 默认值 |
| :---------------------- | :------------------------------------------------------------------ | :------------------------------------------------------ | :----------------------------- | :--------------------------------------------------- |
| data | 显示的数据 | array | - | - |
| columns | 自动生成表单的参数,参考下面 columns | array | - | - |
| selection | 显示多选框,支持 columns 的配置 | boolean / object | - | false |
| index | 显示索引,支持 columns 的配置 | boolean / object | - | false |
| expand | 开启展开插槽,支持 columns 的配置 | boolean / object | - | false |
| menu | 开启操作按钮插槽,支持 columns 的配置 | boolean / object | - | false |
| show-overflow-tooltip | 当内容过长被隐藏时显示 tooltip | boolean | - | false |
| align | 对齐方式 | string | left / center / right | left |
| header-align | 表头对齐方式 | string | left / center / right | 同 align |
| total | 总条目数 | number | - | - |
| current-page | 当前页数,可以通过 `v-model:current-page` 绑定值 | number | - | - |
| page-size | 每页显示条目个数,可以通过 `v-model:page-size` 绑定值 | number | - | - |
| pagination | pagination 的配置,同 el-pagination | object | - | [参考全局配置](../guide/index#全局配置) |
| height | Table 的高度 | string / number | - | 自动高度 |
| max-height | Table 的最大高度 | string / number | - | - |
| stripe | 是否为斑马纹 table | boolean | - | false |
| border | 是否带有纵向边框 | boolean | - | false |
| size | Table 的尺寸 | string | medium / small / mini | - |
| fit | 列的宽度是否自撑开 | boolean | - | true |
| show-header | 是否显示表头 | boolean | - | true |
| highlight-current-row | 是否要高亮当前行 | boolean | - | false |
| current-row-key | 当前行的 key只写属性 | string / number | - | - |
| row-class-name | 为行增加 className | Function({row, rowIndex}) / string | - | - |
| row-style | 为行增加 style | Function({row, rowIndex}) / object | - | - |
| cell-class-name | 为单元格增加 className | Function({row, column, rowIndex, columnIndex}) / string | - | - |
| cell-style | 为单元格增加 style | Function({row, column, rowIndex, columnIndex}) / object | - | - |
| header-row-class-name | 为表头行增加 className | Function({row, rowIndex}) / string | - | - |
| header-row-style | 为表头行增加 style | Function({row, rowIndex}) / object | - | - |
| header-cell-class-name | 为表头单元格增加 className | Function({row, column, rowIndex, columnIndex}) / string | - | - |
| header-cell-style | 为表头单元格增加 style | Function({row, column, rowIndex, columnIndex}) / object | - | - |
| row-key | 行数据的 Key使用 reserveSelection 功能时必填 | Function(row) / string | - | - |
| empty-text | 空数据时显示的文本内容 | string | - | 暂无数据 |
| default-expand-all | 是否默认展开所有行 | boolean | - | false |
| expand-row-keys | Table 目前的展开行,与 row-key 配合使用 | array | - | - |
| default-sort | 默认的排序列的 prop 和顺序 | Object | `order`: ascending, descending | ascending |
| tooltip-effect | tooltip `effect` 属性 | String | dark / light | - |
| show-summary | 是否在表尾显示合计行 | Boolean | - | false |
| sum-text | 合计行第一列的文本 | String | - | 合计 |
| summary-method | 自定义的合计计算方法 | Function({ columns, data }) | - | - |
| span-method | 合并行或列的计算方法 | Function({ row, column, rowIndex, columnIndex }) | - | - |
| select-on-indeterminate | 当仅有部分行被选中时,点击表头的多选框时的行为,配合 selection 使用 | boolean | - | true |
| indent | 展示树形数据时,树节点的缩进 | number | - | 16 |
| lazy | 是否懒加载子节点数据 | boolean | - | - |
| load | 加载子节点数据的函数lazy 为 true 时生效 | Function(row, treeNode, resolve) | - | - |
| tree-props | 渲染嵌套数据的配置选项 | Object | - | { hasChildren: 'hasChildren', children: 'children' } |
##### 参数
| 参数 | 说明 | 类型 | 可选值 | 默认值 |
| :------------------ | :-------------------------------------------------------------------- | :-------------------------------------- | :------------------------------------------------------------------------------------------------------------------------------ | :-------------------------------- |
| prop | 对应 data 的字段名 (**必填,需要是唯一值**) | string | - | - |
| label | 显示的标题 | string | - | - |
| slot | 是否开启自定义插槽功能 | boolean | - | false |
| hide | 是否在表格中隐藏 | boolean | - | false |
| children | 实现多级表头 | array | - | - |
| columnKey | 当前项的 key使用 filter-change 事件时需要 | string | - | - |
| width | 对应列的宽度 | string | - | - |
| minWidth | 对应列的最小宽度 | string | - | - |
| fixed | 列是否固定true 表示固定在左侧 | string / boolean | true / left / right | - |
| renderHeader | 列标题 Label 区域渲染使用的 Function | Function(h, { column, $index }) | - | - |
| sortable | 对应列是否可以排序 | boolean / string | true / false / 'custom' | false |
| sortMethod | 对数据进行排序的时候使用的方法 | Function(a, b) | - | - |
| sortBy | 指定数据按照哪个属性进行排序 | string / array / Function(row, index) | - | - |
| sortOrders | 数据在排序时所使用排序策略的轮转顺序 | array | `ascending` 表示升序,`descending` 表示降序,`null` 表示还原为原始顺序 | ['ascending', 'descending', null] |
| resizable | 对应列是否可以通过拖动改变宽度,配合 border 使用 | boolean | - | true |
| formatter | 用来格式化内容 | Function(row, column, cellValue, index) | - | - |
| showOverflowTooltip | 当内容过长被隐藏时显示 tooltip | Boolean | - | false |
| align | 对齐方式 | string | left / center / right | left |
| headerAlign | 表头对齐方式 | string | left / center / right | 同 align |
| className | 列的 className | string | - | - |
| labelClassName | 当前列标题的自定义类名 | string | - | - |
| filters | 数据过滤的选项 | Array[{ text, value }] | - | - |
| filterPlacement | 过滤弹出框的定位 | string | top / top-start / top-end / bottom / bottom-start / bottom-end / left / left-start / left-end / right / right-start / right-end | - |
| filterMultiple | 数据过滤的选项是否多选 | boolean | - | true |
| filterMethod | 数据过滤使用的方法 | Function(value, row, column) | - | - |
| filteredValue | 选中的数据过滤项 | array | - | - |
| index | 自定义索引,只能够在 index 中配置 | Function(index) / number | - | - |
| selectable | 这一行的 CheckBox 是否可以勾选,只能够在 selection 中配置 | Function(row, index) | - | - |
| reserveSelection | 是否保留之前选中的数据(需指定 `row-key`),只能够在 selection 中配置 | boolean | - | false |
##### 事件
| 事件名 | 说明 | 参数 |
| ------------------ | -------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------- |
| select | 当用户手动勾选数据行的 Checkbox 时触发的事件 | selection, row |
| select-all | 当用户手动勾选全选 Checkbox 时触发的事件 | selection |
| selection-change | 当选择项发生变化时会触发该事件 | selection |
| cell-mouse-enter | 当单元格 hover 进入时会触发该事件 | row, column, cell, event |
| cell-mouse-leave | 当单元格 hover 退出时会触发该事件 | row, column, cell, event |
| cell-click | 当某个单元格被点击时会触发该事件 | row, column, cell, event |
| cell-dblclick | 当某个单元格被双击击时会触发该事件 | row, column, cell, event |
| row-click | 当某一行被点击时会触发该事件 | row, column, event |
| row-contextmenu | 当某一行被鼠标右键点击时会触发该事件 | row, column, event |
| row-dblclick | 当某一行被双击时会触发该事件 | row, column, event |
| header-click | 当某一列的表头被点击时会触发该事件 | column, event |
| header-contextmenu | 当某一列的表头被鼠标右键点击时触发该事件 | column, event |
| sort-change | 当表格的排序条件发生变化的时候会触发该事件 | { column, prop, order } |
| filter-change | 当表格的筛选条件发生变化的时候会触发该事件,参数的值是一个对象,对象的 key 是 column 的 columnKey对应的 value 为用户选择的筛选条件的数组。 | filters |
| current-change | 当表格的当前行发生变化的时候会触发该事件,如果要高亮当前行,请打开表格的 highlight-current-row 属性 | currentRow, oldCurrentRow |
| header-dragend | 当拖动表头改变了列的宽度的时候会触发该事件 | newWidth, oldWidth, column, event |
| expand-change | 当用户对某一行展开或者关闭的时候会触发该事件(展开行时,回调的第二个参数为 expandedRows树形表格时第二参数为 expanded | row, (expandedRows \| expanded) |
| size-change | pageSize 改变时会触发 | 每页条数 |
| current-change | currentPage 改变时会触发 | 当前页 |
| prev-click | 用户点击上一页按钮改变当前页后触发 | 当前页 |
| next-click | 用户点击下一页按钮改变当前页后触发 | 当前页 |
##### 方法
| 方法名 | 说明 | 参数 |
| ------------------ | ----------------------------------------------------------------------------------------------------------------------- | --------------------------- |
| clearSelection | 用于多选表格,清空用户的选择 | - |
| toggleRowSelection | 用于多选表格切换某一行的选中状态如果使用了第二个参数则是设置这一行选中与否selected 为 true 则选中) | row, selected |
| toggleAllSelection | 用于多选表格,切换全选和全不选 | - |
| toggleRowExpansion | 用于可展开表格与树形表格切换某一行的展开状态如果使用了第二个参数则是设置这一行展开与否expanded 为 true 则展开) | row, expanded |
| setCurrentRow | 用于单选表格,设定某一行为选中行,如果调用时不加参数,则会取消目前高亮行的选中状态。 | row |
| clearSort | 用于清空排序条件,数据会恢复成未排序的状态 | - |
| clearFilter | 不传入参数时用于清空所有过滤条件,数据会恢复成未过滤的状态,也可传入由 columnKey 组成的数组以清除指定列的过滤条件 | columnKey |
| doLayout | 对 Table 进行重新布局。当 Table 或其祖先元素由隐藏切换为显示时,可能需要调用此方法 | - |
| sort | 手动对 Table 进行排序。参数`prop`属性指定排序列,`order`指定排序顺序。 | prop: string, order: string |
::: tip 提示
如果使用 `typescript` 可以从组件中导出 `ITableExpose` 提供更好的类型推导
:::
### 插槽
| name | 说明 |
| :------------ | :----------------------------------------------------------------------- |
| - | 在右侧菜单前插入的任意内容 |
| menu | 表格右侧自定义按钮,参数为 { size, row, column, $index } |
| expand | 当 expand 为 true 时,配置展开显示的内容,参数为 { row, column, $index } |
| append | 插入至表格最后一行之后的内容 |
| [prop] | 当前这列的内容,参数为 { size, row, column, $index } |
| [prop]-header | 当前这列表头的内容,参数为 { size, column, $index } |
::: tip 提示
[prop] 为 columns 中定义的 prop
:::

View File

@@ -0,0 +1 @@
##### 介绍

View File

@@ -0,0 +1,5 @@
##### 安装
```
npm install layui-vue --save
```

View File

@@ -0,0 +1,32 @@
##### 基础
::: demo 传入 columns 数据,自动生成表格
<template>
<lay-button type="primary">原始按钮</lay-button>
<lay-button type="default">默认按钮</lay-button>
<lay-button type="normal">百搭按钮</lay-button>
<lay-button type="warm">暖色按钮</lay-button>
<lay-button type="danger">警告按钮</lay-button>
<lay-button type="disabled">禁用按钮</lay-button>
</template>
<script>
import { ref } from 'vue'
export default {
setup() {
return {
}
}
}
</script>
:::
#### 插槽
| name | 说明 |
| :------------ | :----------------------------------------------------------------------- |
| type | 按钮类型 |

View File

@@ -0,0 +1 @@
##### 介绍

View File

@@ -0,0 +1,5 @@
##### 安装
```
npm install layui-vue --save
```

23
docs/index.html Normal file
View File

@@ -0,0 +1,23 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
<meta name="renderer" content="webkit" />
<meta name="force-rendering" content="webkit" />
<meta name="applicable-device" content="pc,mobile" />
<meta name="author" content="Jmys <jmys1992@gmail.com>" />
<meta
name="keywords"
content="element-pro,pro-components,admin,element-plus,components,vue,ui"
/>
<link rel="icon" href="/favicon.ico" />
<title></title>
<!--preload-links-->
</head>
<body>
<div id="app"><!--app-html--></div>
<script type="module" src="/src/entry-client.ts"></script>
</body>
</html>

47
docs/prerender.js Normal file
View File

@@ -0,0 +1,47 @@
/* eslint-disable @typescript-eslint/no-var-requires */
const fs = require('fs')
const path = require('path')
const toAbsolute = (p) => path.resolve(__dirname, p).replace(/\\/, '/')
const manifest = require('./dist/static/ssr-manifest.json')
const template = fs.readFileSync(toAbsolute('dist/static/index.html'), 'utf-8')
const { render } = require('./dist/server/entry-server.js')
const writeFileRecursive = function (path, buffer) {
const lastPath = path.substring(0, path.lastIndexOf('/'))
fs.mkdir(lastPath, { recursive: true }, () => {
fs.writeFileSync(path, buffer)
})
}
const fileDisplay = (file) => {
fs.readdirSync(toAbsolute(file)).forEach(async (filename) => {
const filedir = path.join(file, filename).replace(/\\/, '/')
if (fs.statSync(toAbsolute(filedir)).isDirectory()) {
fileDisplay(filedir)
} else {
const url = filedir
.replace(/^docs/, '')
.replace(/\.(vue|md)$/, '')
.replace(/index$/, '')
.replace(/\/([^/]*)$/, (item) =>
item.replace(/\B([A-Z])/g, '-$1').toLowerCase()
)
const [appHtml, preloadLinks] = await render(url, manifest)
const html = template
.replace('<!--preload-links-->', preloadLinks)
.replace('<!--app-html-->', appHtml)
const filePath = `dist/static${url.replace(/\/$/, '/index')}.html`
writeFileRecursive(toAbsolute(filePath), html)
console.log('pre-rendered:', filePath)
}
})
}
fileDisplay('docs')
fs.unlinkSync(toAbsolute('dist/static/ssr-manifest.json'))

BIN
docs/public/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

3
docs/src/App.vue Normal file
View File

@@ -0,0 +1,3 @@
<template>
<router-view />
</template>

View File

@@ -0,0 +1,152 @@
<template>
<div class="lay-code">
<div class="source">
<slot />
</div>
<div
ref="meta"
class="meta"
>
<div
v-if="$slots.description"
class="description"
>
<slot name="description" />
</div>
<div class="language-html">
<slot name="code" />
</div>
</div>
<div
:class="{ 'is-fixed': isFixContorl }"
class="control"
@click="toggleShow"
>
<i :class="[show ? 'el-icon-caret-top' : 'el-icon-caret-bottom']" />
</div>
</div>
</template>
<script setup lang="ts">
import { onMounted, onUnmounted, ref, watch } from 'vue'
const meta = ref<HTMLElement>({} as HTMLElement)
const isFixContorl = ref(false)
const codeAreaHeight = ref(0)
const show = ref(false);
const toggleShow = function() {
show.value = !show.value;
}
onMounted(() => {
const foundDescs = meta.value.getElementsByClassName('description')
const foundCodes = meta.value.getElementsByClassName('language-html')
if (foundDescs.length) {
codeAreaHeight.value =
foundDescs[0].clientHeight + foundCodes[0].clientHeight + 30
} else {
codeAreaHeight.value = foundCodes[0].clientHeight + 20
}
})
onUnmounted(() => {
window.removeEventListener('scroll', handleScroll)
})
watch(show, (value) => {
if (value) {
meta.value.style.height = `${codeAreaHeight.value}px`
window.addEventListener('scroll', handleScroll)
setTimeout(handleScroll, 100)
} else {
meta.value.style.height = '0'
window.removeEventListener('scroll', handleScroll)
}
})
function handleScroll() {
const { top, bottom } = meta.value.getBoundingClientRect()
isFixContorl.value =
bottom > window.innerHeight && top + 44 <= window.innerHeight
}
</script>
<style>
.lay-code {
margin: 1rem 0;
border: 1px solid whitesmoke;
border-radius: 3px;
background: var(--c-bg);
transition: all 0.2s;
}
.lay-code:hover {
box-shadow: var(--shadow-2);
}
.lay-code .source {
padding: 24px;
}
.lay-code .meta {
padding: 0 10px;
height: 0;
background-color: var(--c-page-background);
overflow: hidden;
transition: height 0.2s;
}
.lay-code .meta .description {
padding: 20px;
margin: 10px 0;
border: 1px solid var(--c-divider);
box-sizing: border-box;
background: var(--c-bg);
font-size: 14px;
line-height: 22px;
color: var(--c-text-light-1);
word-break: break-word;
}
.lay-code .meta .description p {
margin: 0 !important;
line-height: 26px !important;
}
.lay-code .meta .description code {
display: inline-block;
padding: 1px 5px;
margin: 0 4px;
height: 18px;
border-radius: 3px;
background-color: var(--code-inline-bg-color);
font-size: 12px;
line-height: 18px;
color: var(--c-text-light);
}
.lay-code .control {
height: 44px;
box-sizing: border-box;
border-top: 1px solid whitesmoke;
border-bottom-left-radius: 4px;
border-bottom-right-radius: 4px;
background: var(--c-bg);
text-align: center;
color: var(--c-text);
cursor: pointer;
width: 100%;
user-select: none;
}
.lay-code .control.is-fixed {
position: sticky;
z-index: 11;
bottom: 0;
}
.lay-code .control:hover {
background-color: var(--c-page-background);
color: var(--c-brand);
}
.lay-code .control > i {
display: inline-block;
font-size: 16px;
line-height: 44px;
transition: all 0.3s;
}
</style>

7
docs/src/entry-client.ts Normal file
View File

@@ -0,0 +1,7 @@
import { createApp } from './main'
const { app, router } = createApp()
router.isReady().then(() => {
app.mount('#app')
})

51
docs/src/entry-server.ts Normal file
View File

@@ -0,0 +1,51 @@
import { createApp } from './main'
import { renderToString } from '@vue/server-renderer'
export async function render(url, manifest): Promise<string[]> {
const { app, router } = createApp()
// set the router to the desired URL before rendering
router.push(url)
await router.isReady()
// passing SSR context object which will be available via useSSRContext()
// @vitejs/plugin-vue injects code into a component's setup() that registers
// itself on ctx.modules. After the render, ctx.modules would contain all the
// components that have been instantiated during this render call.
const ctx = {}
const html = await renderToString(app, ctx)
// the SSR manifest generated by Vite contains module -> chunk/asset mapping
// which we can then use to determine what files need to be preloaded for this
// request.
const preloadLinks = renderPreloadLinks(ctx.modules, manifest)
return [html, preloadLinks]
}
function renderPreloadLinks(modules, manifest) {
let links = ''
const seen = new Set()
modules.forEach((id) => {
const files = manifest[id]
if (files) {
files.forEach((file) => {
if (!seen.has(file)) {
seen.add(file)
links += renderPreloadLink(file)
}
})
}
})
return links
}
function renderPreloadLink(file) {
if (file.endsWith('.js')) {
return `<link rel="modulepreload" crossorigin href="${file}">`
} else if (file.endsWith('.css')) {
return `<link rel="stylesheet" href="${file}">`
} else {
// TODO
return ''
}
}

View File

@@ -0,0 +1,25 @@
<template>
<lay-layout>
<lay-header>
<lay-logo>layui-logo</lay-logo>
</lay-header>
<lay-side>
<router-link to="/zh-CN/components/layout">布局</router-link>
<router-link to="/zh-CN/components/button">按钮</router-link>
</lay-side>
<lay-body>
<div style="padding: 20px">
<router-view></router-view>
</div>
</lay-body>
<lay-footer></lay-footer>
</lay-layout>
</template>
<script>
import { ref } from 'vue'
export default {
setup() {
return {}
},
}
</script>

25
docs/src/main.ts Normal file
View File

@@ -0,0 +1,25 @@
import Layout from './App.vue'
import { App, createApp as _createApp, createSSRApp } from 'vue'
import { createRouter } from './router/index'
import { Router } from 'vue-router'
import Layui from '/@src/index'
import LayCode from './components/LayCode.vue'
import './styles/index.css'
export function createApp(): {
app: App<Element>
router: Router
} {
const app =
import.meta.env.MODE === 'production'
? createSSRApp(Layout)
: _createApp(Layout)
const router = createRouter()
app
.use(router)
.component('LayCode', LayCode)
.use(Layui)
return { app, router }
}

View File

@@ -0,0 +1,47 @@
import vue from '@vitejs/plugin-vue'
import Markdown from 'vite-plugin-md'
import container from 'markdown-it-container'
import highlight from './highlight'
import snippet from './snippet'
import demo from './demo'
import createContainer from './create-container'
import preWrapper from './pre-wrapper'
import type Token from 'markdown-it/lib/token'
const plugins = [
vue({
include: [/\.vue$/, /\.md$/],
}),
Markdown({
markdownItOptions: {
html: true,
linkify: true,
typographer: true,
highlight,
},
markdownItSetup(md) {
md.use(snippet)
.use(preWrapper)
.use(container, 'demo', demo)
.use(...createContainer('tip', 'TIP'))
.use(...createContainer('warning', 'WARNING'))
.use(...createContainer('danger', 'WARNING'))
.use(container, 'v-pre', {
render: (tokens: Token[], idx: number) =>
tokens[idx].nesting === 1 ? '<div v-pre>\n' : '</div>\n',
})
.use(container, 'details', {
render: (tokens: Token[], idx: number) => {
const info = tokens[idx].info.trim().slice(7).trim() // 7 = 'details'.length
return tokens[idx].nesting === 1
? `<details class="custom-block details">${
info ? `<summary>${info}</summary>` : ''
}\n`
: '</details>'
},
})
},
}),
]
export default plugins

View File

@@ -0,0 +1,33 @@
import container from 'markdown-it-container'
import type Token from 'markdown-it/lib/token'
type ContainerArgs = [
typeof container,
string,
{
render(tokens: Token[], idx: number): string
}
]
export default function createContainer(
klass: string,
defaultTitle: string
): ContainerArgs {
return [
container,
klass,
{
render(tokens, idx) {
const token = tokens[idx]
const info = token.info.trim().slice(klass.length).trim()
if (token.nesting === 1) {
return `<div class="${klass} custom-block"><p class="custom-block-title">${
info || defaultTitle
}</p>\n`
} else {
return '</div>\n'
}
},
},
]
}

146
docs/src/plugin/demo.ts Normal file
View File

@@ -0,0 +1,146 @@
import markdown from 'markdown-it'
import highlight from './highlight'
import type Token from 'markdown-it/lib/token'
/**
* Combine the script content
* @param {string} script script string
*/
function assignScript(script: string) {
const dependencies = {} as Record<string, string[]>
const attrs = {} as Record<string, string>
const content = script
// import { ref } from 'vue' -> ''
.replace(/import\s?\{.*\}.*/g, (item) => {
const key = getInnerString(item.replace(/'/g, '"'), '"', '"')
const value = getInnerString(item.replace(/\s+/g, ''), '{', '}')
const list = value ? value.split(',') : []
if (key && dependencies[key]) {
dependencies[key] = dependencies[key].concat(list)
} else if (key) {
dependencies[key] = list
}
return ''
})
/**
* const -> let
*
* const a = -> let a =
* const a = -> a =
*/
.replace(/(const|let|var)\s\w*\s?=/g, (item) => {
const attr = getInnerString(item, '\\s', '\\s?=')
if (attr && !(attr in attrs)) {
attrs[attr] = attr
return `let ${attr} =`
} else {
return attr + ' ='
}
})
// Remove extra line breaks
.replace(/\n+/gm, '\n')
// Combine the import
const reImport = Object.keys(dependencies).reduce((all, item) => {
const filterAttrs = [...new Set(dependencies[item])]
return all + `import {${filterAttrs + ','}} from '${item}';\n`
}, '')
return reImport + content
}
/**
* Extract part of the new string from the middle of the string
* @param {string} string string
* @param {string} prefix RegExp string
* @param {string} postfix RegExp string
* @param {string} type g | m | i
*/
function getInnerString(
string: string,
prefix: string,
postfix = '',
type: 'i' | 'g' | 'm' = 'i'
): string | undefined {
const result = new RegExp(`${prefix}(.*)${postfix}`, type)
const match = string.match(result)
return match ? match[1].trim() : undefined
}
let script = '' // Record the <script> label of the current page
export default {
render: (tokens: Token[], idx: number): string => {
// the `demo` block of the current page
const htmlBlock = tokens.filter((item) => item.type === 'html_block')
const { nesting, info = '', map } = tokens[idx]
if (nesting === -1) {
return '</lay-code>'
}
const matchedInfo = info.trim().match(/^demo\s+(.*)$/)
const description = matchedInfo && matchedInfo[1]
const descTemplate = markdown().render(description || '')
let str = '' // copy the current `demo` block code
let lastLine = NaN
for (let i = 0; i < htmlBlock.length; i++) {
const item = htmlBlock[i]
if (item.map && map && item.map[0] >= map[0] && item.map[1] <= map[1]) {
const { map, content } = item
const delta = map[0] - (lastLine || map[1])
if (delta > 0) {
str += '\n'.repeat(delta)
}
str += content
lastLine = map[1]
if (i === 0) {
script = ''
}
// Remove top <template>
if (/^<template>/.test(content)) {
const reContent = content.match(/^<template>((\s|\S)*)<\/template>/m)
htmlBlock[i].content = (reContent && reContent[1]) || ''
}
// Extract the <script> label content
if (content.includes('<script')) {
if (/export\sdefault\s?\{/m.test(content)) {
const setup = content.match(
/setup\s?\(\)\s?\{((\s|\S)*)return\s?\{/m
)
const reContent = content.replace(
/export\sdefault\s?\{((\s|\S)*)\}/m,
(setup && setup[1]) || ''
)
const reScript = reContent.match(
/^<script\s?.*?>((\s|\S)*)<\/script>/m
)
script += (reScript && reScript[1]) || ''
} else {
const reScript = content.match(
/^<script\s?.*?>((\s|\S)*)<\/script>/m
)
script += (reScript && reScript[1]) || ''
}
htmlBlock[i].content = ''
}
// Change the last content to <script> of the current page
if (i + 1 === htmlBlock.length) {
htmlBlock[i].content = `
<script setup>
${assignScript(script)}
</script>`
}
}
}
return `
<lay-code>
${description ? `<template #description>${descTemplate}</template>` : ''}
<template #code>${highlight(str, 'vue')}</template>
`
},
}

View File

@@ -0,0 +1,46 @@
// copy from [vitepress](https://github.com/vuejs/vitepress)
import prism from 'prismjs'
import loadLanguages from 'prismjs/components/index'
import escapeHtml from 'escape-html'
// required to make embedded highlighting work...
loadLanguages(['markup', 'css', 'javascript'])
function wrap(code: string, lang: string): string {
if (lang === 'text') {
code = escapeHtml(code)
}
return `<pre v-pre><code>${code}</code></pre>`
}
export default (str: string, lang: string): string => {
if (!lang) {
return wrap(str, 'text')
}
lang = lang.toLowerCase()
const rawLang = lang
if (lang === 'vue' || lang === 'html') {
lang = 'markup'
}
if (lang === 'md') {
lang = 'markdown'
}
if (lang === 'ts') {
lang = 'typescript'
}
if (lang === 'py') {
lang = 'python'
}
if (!prism.languages[lang]) {
try {
loadLanguages([lang])
} catch (e) {
console.warn(lang, e)
}
}
if (prism.languages[lang]) {
const code = prism.highlight(str, prism.languages[lang], lang)
return wrap(code, rawLang)
}
return wrap(str, 'text')
}

View File

@@ -0,0 +1,11 @@
import MarkdownIt from 'markdown-it'
export default (md: MarkdownIt): void => {
const fence = md.renderer.rules.fence!
md.renderer.rules.fence = (...args) => {
const [tokens, idx] = args
const token = tokens[idx]
const rawCode = fence(...args)
return `<div class="language-${token.info.trim()}">${rawCode}</div>`
}
}

View File

@@ -0,0 +1,49 @@
// copy from [vitepress](https://github.com/vuejs/vitepress)
import fs from 'fs'
import MarkdownIt from 'markdown-it'
import { RuleBlock } from 'markdown-it/lib/parser_block'
export default (md: MarkdownIt): void => {
const parser: RuleBlock = (state, startLine, endLine, silent) => {
const CH = '<'.charCodeAt(0)
const pos = state.bMarks[startLine] + state.tShift[startLine]
const max = state.eMarks[startLine]
// if it's indented more than 3 spaces, it should be a code block
if (state.sCount[startLine] - state.blkIndent >= 4) {
return false
}
for (let i = 0; i < 3; ++i) {
const ch = state.src.charCodeAt(pos + i)
if (ch !== CH || pos + i >= max) return false
}
if (silent) {
return true
}
const start = pos + 3
const end = state.skipSpacesBack(max, pos)
const rawPath = state.src
.slice(start, end)
.trim()
.replace(/^@/, process.cwd())
const content = fs.existsSync(rawPath)
? fs.readFileSync(rawPath).toString()
: 'Not found: ' + rawPath
const meta = rawPath.replace(rawPath, '')
state.line = startLine + 1
const token = state.push('fence', 'code', 0)
token.info = rawPath.split('.').pop() + meta
token.content = content
token.markup = '```'
token.map = [startLine, startLine + 1]
return true
}
md.block.ruler.before('fence', 'snippet', parser)
}

20
docs/src/router/index.ts Normal file
View File

@@ -0,0 +1,20 @@
import {
createMemoryHistory,
createRouter as _createRouter,
createWebHistory,
Router,
} from 'vue-router'
import zhCN from './zh-CN'
import type { IRouteRecordRaw } from '/@src/index'
const routes: IRouteRecordRaw[] = [...zhCN]
export function createRouter(): Router {
const baseUrl = import.meta.env.BASE_URL
return _createRouter({
history: import.meta.env.SSR
? createMemoryHistory(baseUrl)
: createWebHistory(baseUrl),
routes: routes
})
}

32
docs/src/router/zh-CN.ts Normal file
View File

@@ -0,0 +1,32 @@
import BaseLayout from '../layouts/Layout.vue'
const zhCN = [
{
path: '/',
redirect: '/zh-CN/guide/',
component: BaseLayout,
meta: { title: '指南', icon: 'el-icon-position' },
children: [
{
path: '/zh-CN/guide/',
component: () => import('../../docs/zh-CN/guide/home.md'),
meta: { title: '介绍' },
}
],
},
{
path: '/zh-CN/components/',
redirect: '/zh-CN/components/button',
component: BaseLayout,
meta: { title: '组件', icon: 'el-icon-copy-document' },
children: [
{
path: '/zh-CN/components/button',
component: () => import('../../docs/zh-CN/components/button.md'),
meta: { title: '按钮' },
}
],
},
]
export default zhCN

214
docs/src/styles/code.css Normal file
View File

@@ -0,0 +1,214 @@
/* copy from [vitepress](https://github.com/vuejs/vitepress) */
code {
margin: 0;
border-radius: 3px;
padding: 0.25rem 0.5rem;
font-family: var(--code-font-family);
font-size: 0.85em;
color: var(--c-text-light);
background-color: var(--code-inline-bg-color);
}
code .token.deleted {
color: #ec5975;
}
code .token.inserted {
color: var(--c-brand);
}
div[class*='language-'] {
position: relative;
margin: 1rem -1.5rem;
background-color: #fafafa;
overflow-x: auto;
border: 1px solid #eaeefb;
}
li > div[class*='language-'] {
border-radius: 6px 0 0 6px;
margin: 1rem -1.5rem 1rem -1.25rem;
}
@media (min-width: 420px) {
div[class*='language-'] {
margin: 1rem 0;
border-radius: 6px;
}
li > div[class*='language-'] {
margin: 1rem 0 1rem 0rem;
border-radius: 6px;
}
}
[class*='language-'] pre,
[class*='language-'] code {
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;
}
[class*='language-'] pre {
position: relative;
z-index: 1;
margin: 0;
padding: 1.25rem 1.5rem;
background: transparent;
overflow-x: auto;
}
[class*='language-'] pre p {
margin: auto !important;
}
[class*='language-'] code {
padding: 0;
line-height: var(--code-line-height);
font-size: var(--code-font-size);
color: #000;
background-color: #fafafa;
}
/* Line highlighting */
.highlight-lines {
position: absolute;
top: 0;
bottom: 0;
left: 0;
padding: 1.25rem 0;
width: 100%;
line-height: var(--code-line-height);
font-family: var(--code-font-family);
font-size: var(--code-font-size);
user-select: none;
overflow: hidden;
}
.highlight-lines .highlighted {
background-color: rgba(0, 0, 0, 0.66);
}
/* Line numbers mode */
div[class*='language-'].line-numbers-mode {
padding-left: 3.5rem;
}
.line-numbers-wrapper {
position: absolute;
top: 0;
bottom: 0;
left: 0;
z-index: 3;
border-right: 1px solid rgba(0, 0, 0, 0.5);
padding: 1.25rem 0;
width: 3.5rem;
text-align: center;
line-height: var(--code-line-height);
font-family: var(--code-font-family);
font-size: var(--code-font-size);
color: #888;
}
/* Language marker */
[class*='language-']:before {
position: absolute;
top: 0.6em;
right: 1em;
z-index: 2;
font-size: 0.8rem;
color: #888;
}
/**
* prism.js tomorrow night eighties for JavaScript, CoffeeScript, CSS and HTML.
* Based on https://github.com/chriskempson/tomorrow-theme
*
* @author Rose Pritchard
*/
.token.comment,
.token.block-comment,
.token.prolog,
.token.doctype,
.token.cdata {
color: #999;
}
.token.punctuation {
color: #ccc;
}
.token.tag,
.token.attr-name,
.token.namespace,
.token.deleted {
color: #e2777a;
}
.token.function-name {
color: #6196cc;
}
.token.boolean,
.token.number,
.token.function {
color: #f08d49;
}
.token.property,
.token.class-name,
.token.constant,
.token.symbol {
color: #f8c555;
}
.token.selector,
.token.important,
.token.atrule,
.token.keyword,
.token.builtin {
color: #cc99cd;
}
.token.string,
.token.char,
.token.attr-value,
.token.regex,
.token.variable {
color: #7ec699;
}
.token.operator,
.token.entity,
.token.url {
color: #67cdcc;
}
.token.important,
.token.bold {
font-weight: bold;
}
.token.italic {
font-style: italic;
}
.token.entity {
cursor: help;
}
.token.inserted {
color: green;
}

View File

@@ -0,0 +1,71 @@
.custom-block.tip,
.custom-block.warning,
.custom-block.danger {
margin: 1rem 0;
border-left: 0.3rem solid;
padding: 0.1rem 1.5rem;
overflow-x: auto;
border-radius: 4px;
}
.custom-block.tip {
background-color: #f3f5f7;
border-color: #409eff;
}
.custom-block.warning {
border-color: #e7c000;
color: #6b5900;
background-color: rgba(255, 229, 100, 0.3);
}
.custom-block.warning .custom-block-title {
color: #b29400;
}
.custom-block.warning a {
color: var(--c-text);
}
.custom-block.danger {
border-color: #c00;
color: #4d0000;
background-color: #ffe6e6;
}
.custom-block.danger .custom-block-title {
color: #900;
}
.custom-block.danger a {
color: var(--c-text);
}
.custom-block.details {
position: relative;
display: block;
border-radius: 2px;
margin: 1.6em 0;
padding: 1.6em;
background-color: #eee;
}
.custom-block.details h4 {
margin-top: 0;
}
.custom-block.details figure:last-child,
.custom-block.details p:last-child {
margin-bottom: 0;
padding-bottom: 0;
}
.custom-block.details summary {
outline: none;
cursor: pointer;
}
.custom-block-title {
margin-bottom: -0.4rem;
font-weight: 600;
}

View File

@@ -0,0 +1,4 @@
@import './code.css';
@import './custom-blocks.css';
@import './markdown.css';
@import './vars.css';

View File

@@ -0,0 +1,220 @@
html {
line-height: 1.4;
font-size: 16px;
-webkit-text-size-adjust: 100%;
}
h4 {
font-weight: 700 !important;
font-size: 16.8px !important;
margin-top: 20px !important;
margin-bottom: 20px !important;
}
h5 {
font-weight: 700;
font-size: 16.8px;
}
h1,
h2,
h3,
h4,
h5,
h6 {
margin: 0;
color: #303133;
line-height: 1.25;
}
h1,
h2,
h3,
h4,
h5,
h6,
strong,
b {
font-weight: 600;
}
h1:hover .header-anchor,
h1:focus .header-anchor,
h2:hover .header-anchor,
h2:focus .header-anchor,
h3:hover .header-anchor,
h3:focus .header-anchor,
h4:hover .header-anchor,
h4:focus .header-anchor,
h5:hover .header-anchor,
h5:focus .header-anchor,
h6:hover .header-anchor,
h6:focus .header-anchor {
opacity: 1;
}
h1 {
margin-top: 1.5rem;
font-size: 1.9rem;
}
@media screen and (min-width: 420px) {
h1 {
font-size: 2.2rem;
}
}
h2 {
margin-top: 2.25rem;
margin-bottom: 1.25rem;
border-bottom: 1px solid var(--c-divider);
padding-bottom: 0.3rem;
line-height: 1.25;
font-size: 1.65rem;
/* overflow-x: auto; */
}
h2 + h3 {
margin-top: 1.5rem;
}
h3 {
margin-top: 2rem;
font-size: 1.35rem;
}
h4 {
font-size: 1.15rem;
}
h1 {
margin-top: 4px !important;
margin-bottom: 22px !important;
color: #000000d9 !important;
font-weight: 500 !important;
font-size: 20px !important;
font-family: Avenir, -apple-system, BlinkMacSystemFont, segoe ui, Roboto,
helvetica neue, Arial, noto sans, sans-serif, apple color emoji,
segoe ui emoji, segoe ui symbol, noto color emoji, sans-serif;
line-height: 38px;
}
h2 {
margin-top: 4px !important;
margin-bottom: 16px !important;
color: #000000d9 !important;
font-weight: 500 !important;
font-size: 16px !important;
border-bottom: 0px;
font-family: Avenir, -apple-system, BlinkMacSystemFont, segoe ui, Roboto,
helvetica neue, Arial, noto sans, sans-serif, apple color emoji,
segoe ui emoji, segoe ui symbol, noto color emoji, sans-serif;
line-height: 38px;
}
p,
ol,
ul {
margin: 1rem 0;
line-height: 1.7;
}
p {
color: #454d64 !important;
margin-top: 20px !important;
font-size: 14px !important;
}
a,
area,
button,
[role='button'],
input,
label,
select,
summary,
textarea {
touch-action: manipulation;
}
a {
text-decoration: none;
color: var(--c-brand);
}
a:hover {
text-decoration: underline;
}
a.header-anchor {
float: left;
margin-top: 0.125em;
margin-left: -0.87em;
padding-right: 0.23em;
font-size: 0.85em;
opacity: 0;
}
a.header-anchor:hover,
a.header-anchor:focus {
text-decoration: none;
}
figure {
margin: 0;
}
img {
max-width: 100%;
}
ul,
ol {
padding-left: 1.25em;
}
li > ul,
li > ol {
margin: 0;
}
blockquote {
margin: 1rem 0;
border-left: 0.2rem solid #dfe2e5;
padding: 0.25rem 0 0.25rem 1rem;
font-size: 1rem;
color: #999;
}
blockquote > p {
margin: 0;
}
form {
margin: 0;
}
table {
width: 100%; /*表格宽度*/
border-collapse: collapse; /*使用单一线条的边框*/
empty-cells: show; /*单元格无内容依旧绘制边框*/
}
table th,
table td {
font-size: 14px;
color: #606266;
height: 50px; /*统一每一行的默认高度*/
border-top: 1px solid whitesmoke; /*内部边框样式*/
padding: 0 10px; /*内边距*/
}
table tr:hover {
background: #efefef;
}
table th {
white-space: nowrap; /*表头内容强制在一行显示*/
}
table td {
white-space: nowrap;
}

52
docs/src/styles/vars.css Normal file
View File

@@ -0,0 +1,52 @@
/* TODO: rebuild... copy from [vitepress](https://github.com/vuejs/vitepress) */
:root {
--c-white: #ffffff;
--c-black: #000000;
--c-divider-light: rgba(60, 60, 67, 0.12);
--c-divider-dark: rgba(84, 84, 88, 0.48);
--c-text-light-1: #2c3e50;
--c-text-light-2: #476582;
--c-text-light-3: #90a4b7;
--c-brand: #409eff;
--c-brand-light: #4abf8a;
/**
* Typography
* --------------------------------------------------------------------- */
--font-family-base: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto,
Oxygen, Ubuntu, Cantarell, 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
sans-serif;
--font-family-mono: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
monospace;
/**
* Shadows
* --------------------------------------------------------------------- */
--shadow-1: 0 1px 2px rgba(0, 0, 0, 0.04), 0 1px 2px rgba(0, 0, 0, 0.06);
--shadow-2: 0 3px 12px rgba(0, 0, 0, 0.07), 0 1px 4px rgba(0, 0, 0, 0.07);
--shadow-3: 0 12px 32px rgba(0, 0, 0, 0.1), 0 2px 6px rgba(0, 0, 0, 0.08);
--shadow-4: 0 14px 44px rgba(0, 0, 0, 0.12), 0 3px 9px rgba(0, 0, 0, 0.12);
--shadow-5: 0 18px 56px rgba(0, 0, 0, 0.16), 0 4px 12px rgba(0, 0, 0, 0.16);
}
/** Fallback Styles */
:root {
--c-divider: var(--c-divider-light);
--c-text: var(--c-text-light-1);
--c-text-light: var(--c-text-light-2);
--c-text-lighter: var(--c-text-light-3);
--c-bg: var(--c-white);
--code-line-height: 24px;
--code-font-family: var(--font-family-mono);
--code-font-size: 14px;
--code-inline-bg-color: rgba(27, 31, 35, 0.05);
--code-bg-color: #282c34;
}

4
docs/src/tsconfig.json Normal file
View File

@@ -0,0 +1,4 @@
{
"extends": "../../tsconfig.json",
"include": [".", "../../shims-vue.d.ts"]
}

13
docs/vite.config.ts Normal file
View File

@@ -0,0 +1,13 @@
import path from 'path'
import { defineConfig } from 'vite'
import plugins from './src/plugin/common-plugins'
export default defineConfig({
base: '/layui-vue/',
resolve: {
alias: {
'/@src': path.resolve(__dirname, '../src'),
},
},
plugins,
})