Browse Source

[frontend-next] Refactored fronted

0xJacky 2 years ago
parent
commit
2fff1f5181
100 changed files with 144 additions and 10440 deletions
  1. 4 3
      .github/workflows/build.yml
  2. 0 2
      frontend-next/.env.development
  3. 0 2
      frontend-next/.env.production
  4. 0 24
      frontend-next/.gitignore
  5. 0 23
      frontend-next/README.md
  6. 0 18
      frontend-next/index.html
  7. 0 48
      frontend-next/package.json
  8. BIN
      frontend-next/public/favicon.ico
  9. 0 34
      frontend-next/src/App.vue
  10. BIN
      frontend-next/src/assets/img/logo.png
  11. 0 46
      frontend-next/src/components/Breadcrumb/Breadcrumb.vue
  12. 0 95
      frontend-next/src/components/Chart/RadialBarChart.vue
  13. 0 52
      frontend-next/src/components/FooterToolbar/FooterToolBar.vue
  14. 0 3
      frontend-next/src/components/FooterToolbar/index.js
  15. 0 42
      frontend-next/src/components/Logo/Logo.vue
  16. 0 187
      frontend-next/src/components/PageHeader/PageHeader.vue
  17. 0 38
      frontend-next/src/components/SetLanguage/SetLanguage.vue
  18. 0 160
      frontend-next/src/components/StdDataDisplay/StdCurd.vue
  19. 0 51
      frontend-next/src/components/StdDataDisplay/StdPagination.vue
  20. 0 285
      frontend-next/src/components/StdDataDisplay/StdTable.vue
  21. 0 53
      frontend-next/src/components/StdDataEntry/StdCheckGroup.vue
  22. 0 65
      frontend-next/src/components/StdDataEntry/StdCheckTag.vue
  23. 0 237
      frontend-next/src/components/StdDataEntry/StdDataEntry.vue
  24. 0 52
      frontend-next/src/components/StdDataEntry/StdDatePicker.vue
  25. 0 75
      frontend-next/src/components/StdDataEntry/StdMultiCheckTag.vue
  26. 0 153
      frontend-next/src/components/StdDataEntry/StdMultiFilesUpload.vue
  27. 0 49
      frontend-next/src/components/StdDataEntry/StdRadioGroup.vue
  28. 0 47
      frontend-next/src/components/StdDataEntry/StdSelectOption.vue
  29. 0 156
      frontend-next/src/components/StdDataEntry/StdSelector.vue
  30. 0 105
      frontend-next/src/components/StdDataEntry/StdSingleFileUpload.vue
  31. 0 75
      frontend-next/src/components/StdDataEntry/StdTransfer.vue
  32. 0 266
      frontend-next/src/components/StdDataEntry/StdUpload.vue
  33. 0 390
      frontend-next/src/language/translations.json
  34. 0 639
      frontend-next/src/language/zh_CN/app.po
  35. 0 642
      frontend-next/src/language/zh_TW/app.po
  36. 0 229
      frontend-next/src/layouts/BaseLayout.vue
  37. 0 13
      frontend-next/src/layouts/BaseRouterView.vue
  38. 0 22
      frontend-next/src/layouts/FooterLayout.vue
  39. 0 85
      frontend-next/src/layouts/HeaderLayout.vue
  40. 0 33
      frontend-next/src/layouts/Loading.vue
  41. 0 112
      frontend-next/src/layouts/SideBar.vue
  42. 0 47
      frontend-next/src/views/config/Config.vue
  43. 0 66
      frontend-next/src/views/config/ConfigEdit.vue
  44. 0 291
      frontend-next/src/views/dashboard/DashBoard.vue
  45. 0 168
      frontend-next/src/views/domain/DomainAdd.vue
  46. 0 219
      frontend-next/src/views/domain/DomainEdit.vue
  47. 0 121
      frontend-next/src/views/domain/DomainList.vue
  48. 0 44
      frontend-next/src/views/domain/cert/Cert.vue
  49. 0 61
      frontend-next/src/views/domain/cert/CertInfo.vue
  50. 0 169
      frontend-next/src/views/domain/cert/IssueCert.vue
  51. 0 37
      frontend-next/src/views/domain/methods.js
  52. 0 81
      frontend-next/src/views/domain/ngx_conf/LocationEditor.vue
  53. 0 169
      frontend-next/src/views/domain/ngx_conf/NgxConfigEditor.vue
  54. 0 77
      frontend-next/src/views/domain/ngx_conf/directive/DirectiveAdd.vue
  55. 0 94
      frontend-next/src/views/domain/ngx_conf/directive/DirectiveEditor.vue
  56. 0 49
      frontend-next/src/views/other/About.vue
  57. 0 62
      frontend-next/src/views/other/Error.vue
  58. 0 146
      frontend-next/src/views/other/Install.vue
  59. 0 132
      frontend-next/src/views/other/Login.vue
  60. 0 102
      frontend-next/src/views/pty/Terminal.vue
  61. 0 52
      frontend-next/src/views/user/User.vue
  62. 0 1
      frontend-next/version.json
  63. 0 2703
      frontend-next/yarn.lock
  64. 12 10
      frontend/.gitignore
  65. 0 0
      frontend/.vscode/extensions.json
  66. 0 65
      frontend/Makefile
  67. 16 22
      frontend/README.md
  68. 0 9
      frontend/alias.config.js
  69. 0 10
      frontend/babel.config.js
  70. 0 12
      frontend/components.d.ts
  71. 0 19
      frontend/conversion.log
  72. 0 8
      frontend/frontend.go
  73. 0 0
      frontend/gettext.config.js
  74. 7 13
      frontend/index.html
  75. 42 86
      frontend/package.json
  76. 0 23
      frontend/public/index.html
  77. 0 0
      frontend/public/vite.svg
  78. 28 7
      frontend/src/App.vue
  79. 0 9
      frontend/src/api/analytic.js
  80. 0 0
      frontend/src/api/analytic.ts
  81. 0 20
      frontend/src/api/auth.js
  82. 1 1
      frontend/src/api/auth.ts
  83. 0 23
      frontend/src/api/config.js
  84. 0 0
      frontend/src/api/config.ts
  85. 0 0
      frontend/src/api/curd.ts
  86. 0 47
      frontend/src/api/domain.js
  87. 0 0
      frontend/src/api/domain.ts
  88. 0 19
      frontend/src/api/index.js
  89. 0 12
      frontend/src/api/install.js
  90. 0 13
      frontend/src/api/ngx.js
  91. 0 0
      frontend/src/api/ngx.ts
  92. 0 9
      frontend/src/api/settings.js
  93. 0 23
      frontend/src/api/user.js
  94. 0 0
      frontend/src/api/user.ts
  95. 0 74
      frontend/src/assets/css/dark.less
  96. 0 49
      frontend/src/assets/css/manage.less
  97. 0 181
      frontend/src/assets/css/style.less
  98. 33 33
      frontend/src/components/Breadcrumb/Breadcrumb.vue
  99. 1 1
      frontend/src/components/Chart/AreaChart.vue
  100. 0 140
      frontend/src/components/Chart/CPUChart.vue

+ 4 - 3
.github/workflows/build.yml

@@ -2,7 +2,8 @@ name: Build
 
 on:
     push:
-        branches: [ master ]
+        branches:
+            - '*'
         paths:
             - "**/*.js"
             - "**/*.vue"
@@ -37,7 +38,7 @@ jobs:
             - name: Set up nodejs
               uses: actions/setup-node@v2
               with:
-                  node-version: '16.x'
+                  node-version: '18.x'
                   cache: 'yarn'
                   cache-dependency-path: 'frontend/yarn.lock'
 
@@ -46,7 +47,7 @@ jobs:
               working-directory: frontend
 
             - name: Update tranlations
-              run: make translations
+              run: yarn gettext:compile
               working-directory: frontend
 
             - name: Build

+ 0 - 2
frontend-next/.env.development

@@ -1,2 +0,0 @@
-VITE_API_ROOT = /api
-VITE_API_WSS_ROOT = wss://nginx.jackyu.cn/api

+ 0 - 2
frontend-next/.env.production

@@ -1,2 +0,0 @@
-VUE_APP_API_ROOT = /api
-VUE_APP_API_WSS_ROOT = /api

+ 0 - 24
frontend-next/.gitignore

@@ -1,24 +0,0 @@
-# Logs
-logs
-*.log
-npm-debug.log*
-yarn-debug.log*
-yarn-error.log*
-pnpm-debug.log*
-lerna-debug.log*
-
-node_modules
-dist
-dist-ssr
-*.local
-
-# Editor directories and files
-.vscode/*
-!.vscode/extensions.json
-.idea
-.DS_Store
-*.suo
-*.ntvs*
-*.njsproj
-*.sln
-*.sw?

+ 0 - 23
frontend-next/README.md

@@ -1,23 +0,0 @@
-# Vue 3 + TypeScript + Vite
-
-This template should help get you started developing with Vue 3 and TypeScript in Vite. The template uses Vue
-3 `<script setup>` SFCs, check out
-the [script setup docs](https://v3.vuejs.org/api/sfc-script-setup.html#sfc-script-setup) to learn more.
-
-## Recommended IDE Setup
-
-- [VS Code](https://code.visualstudio.com/) + [Volar](https://marketplace.visualstudio.com/items?itemName=Vue.volar)
-
-## Type Support For `.vue` Imports in TS
-
-Since TypeScript cannot handle type information for `.vue` imports, they are shimmed to be a generic Vue component type
-by default. In most cases this is fine if you don't really care about component prop types outside of templates.
-However, if you wish to get actual prop types in `.vue` imports (for example to get props validation when using
-manual `h(...)` calls), you can enable Volar's Take Over mode by following these steps:
-
-1. Run `Extensions: Show Built-in Extensions` from VS Code's command palette, look
-   for `TypeScript and JavaScript Language Features`, then right click and select `Disable (Workspace)`. By default,
-   Take Over mode will enable itself if the default TypeScript extension is disabled.
-2. Reload the VS Code window by running `Developer: Reload Window` from the command palette.
-
-You can learn more about Take Over mode [here](https://github.com/johnsoncodehk/volar/discussions/471).

+ 0 - 18
frontend-next/index.html

@@ -1,18 +0,0 @@
-<!DOCTYPE html>
-<html lang="en">
-<head>
-    <meta charset="UTF-8"/>
-    <link href="/favicon.ico" rel="icon">
-    <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
-    <style type="text/css">
-        #app {
-            height: 100%;
-        }
-    </style>
-    <title><%- title %></title>
-</head>
-<body>
-<div id="app"></div>
-<script type="module" src="/src/main.ts"></script>
-</body>
-</html>

+ 0 - 48
frontend-next/package.json

@@ -1,48 +0,0 @@
-{
-    "name": "nginx-ui-frontend-next",
-    "private": true,
-    "version": "1.5.0",
-    "type": "commonjs",
-    "scripts": {
-        "dev": "vite",
-        "build": "vite build",
-        "preview": "vite preview",
-        "gettext:extract": "vue-gettext-extract",
-        "gettext:compile": "vue-gettext-compile"
-    },
-    "dependencies": {
-        "@ant-design/icons-vue": "^6.1.0",
-        "ant-design-vue": "^3.2.10",
-        "apexcharts": "^3.35.4",
-        "axios": "^0.27.2",
-        "dayjs": "^1.11.4",
-        "lodash": "^4.17.21",
-        "path": "^0.12.7",
-        "pinia": "^2.0.17",
-        "pinia-plugin-persistedstate": "^1.6.3",
-        "reconnecting-websocket": "^4.4.0",
-        "vite-plugin-build-id": "^0.1.1",
-        "vue": "^3.2.37",
-        "vue-chartjs": "^4.1.1",
-        "vue-router": "4",
-        "vue3-ace-editor": "^2.2.2",
-        "vue3-apexcharts": "^1.4.1",
-        "vue3-gettext": "^2.3.0",
-        "vuex": "^4.0.2",
-        "xterm": "^4.19.0",
-        "xterm-addon-attach": "^0.6.0",
-        "xterm-addon-fit": "^0.5.0"
-    },
-    "devDependencies": {
-        "@types/lodash": "^4.14.182",
-        "@vitejs/plugin-vue": "^3.0.0",
-        "@vitejs/plugin-vue-jsx": "^2.0.0",
-        "@zougt/vite-plugin-theme-preprocessor": "^1.4.5",
-        "less": "^4.1.3",
-        "typescript": "^4.6.4",
-        "unplugin-vue-components": "^0.21.2",
-        "vite": "^3.0.0",
-        "vite-plugin-html": "^3.2.0",
-        "vue-tsc": "^0.38.4"
-    }
-}

BIN
frontend-next/public/favicon.ico


+ 0 - 34
frontend-next/src/App.vue

@@ -1,34 +0,0 @@
-<script setup lang="ts">
-// This starter template is using Vue 3 <script setup> SFCs
-// Check out https://vuejs.org/api/sfc-script-setup.html#script-setup
-//@ts-ignore
-import {useSettingsStore} from '@/pinia/settings'
-import {dark_mode} from '@/lib/theme'
-
-let media = window.matchMedia('(prefers-color-scheme: dark)')
-const callback = (media: { matches: any; }) => {
-    const settings = useSettingsStore()
-    if (media.matches) {
-        dark_mode(true)
-        settings.set_theme('dark')
-    } else {
-        dark_mode(false)
-        settings.set_theme('default')
-    }
-}
-callback(media)
-if (typeof media.addEventListener === 'function') {
-    media.addEventListener('change', callback)
-} else if (typeof media.addListener === 'function') {
-    media.addListener(callback)
-}
-
-</script>
-
-<template>
-    <router-view/>
-</template>
-
-<style lang="less" scoped>
-
-</style>

BIN
frontend-next/src/assets/img/logo.png


+ 0 - 46
frontend-next/src/components/Breadcrumb/Breadcrumb.vue

@@ -1,46 +0,0 @@
-<script setup lang="ts">
-import {computed, ref} from 'vue'
-import {useRoute} from 'vue-router'
-
-interface bread {
-    name: any
-    path: string
-}
-
-const name = ref()
-const route = useRoute()
-
-const breadList = computed(() => {
-    let _breadList: bread[] = []
-
-    name.value = route.name
-
-    route.matched.forEach(item => {
-        //item.name !== 'index' && this.breadList.push(item)
-        _breadList.push({
-            name: item.name,
-            path: item.path
-        })
-    })
-
-    return _breadList
-})
-
-
-</script>
-
-<template>
-    <a-breadcrumb class="breadcrumb">
-        <a-breadcrumb-item v-for="(item, index) in breadList" :key="item.name">
-            <router-link
-                v-if="item.name !== name && index !== 1"
-                :to="{ path: item.path === '' ? '/' : item.path }"
-            >{{ item.name() }}
-            </router-link>
-            <span v-else>{{ item.name() }}</span>
-        </a-breadcrumb-item>
-    </a-breadcrumb>
-</template>
-
-<style scoped>
-</style>

+ 0 - 95
frontend-next/src/components/Chart/RadialBarChart.vue

@@ -1,95 +0,0 @@
-<script setup lang="ts">
-import VueApexCharts from 'vue3-apexcharts'
-import {reactive} from 'vue'
-
-const {series, centerText, colors, name, bottomText}
-    = defineProps(['series', 'centerText', 'colors', 'name', 'bottomText'])
-
-const chartOptions = reactive({
-    series: series,
-    chart: {
-        type: 'radialBar',
-        offsetY: 0
-    },
-    plotOptions: {
-        radialBar: {
-            startAngle: -135,
-            endAngle: 135,
-            dataLabels: {
-                name: {
-                    fontSize: '14px',
-                    color: colors,
-                    offsetY: 36
-                },
-                value: {
-                    offsetY: 50,
-                    fontSize: '14px',
-                    color: undefined,
-                    formatter: () => {
-                        return ''
-                    }
-                }
-            }
-        }
-    },
-    fill: {
-        colors: colors
-    },
-    labels: [name],
-    states: {
-        hover: {
-            filter: {
-                type: 'none'
-            }
-        },
-        active: {
-            filter: {
-                type: 'none'
-            }
-        }
-    }
-})
-</script>
-
-<template>
-    <div class="radial-bar-container">
-        <p class="text">{{ centerText }}</p>
-        <p class="bottom_text">{{ bottomText }}</p>
-        <VueApexCharts v-if="centerText" class="radialBar" type="radialBar" height="205" :options="chartOptions"
-                       :series="series"
-                       ref="chart"/>
-    </div>
-</template>
-
-
-<style lang="less" scoped>
-.radial-bar-container {
-    position: relative;
-    margin: 0 auto;
-    height: 112px !important;
-
-    .radialBar {
-        position: absolute;
-        top: -30px;
-        @media (max-width: 768px) and (min-width: 290px) {
-            left: 50%;
-            transform: translateX(-50%);
-        }
-    }
-
-    .text {
-        position: absolute;
-        top: calc(50% - 5px);
-        width: 100%;
-        text-align: center;
-    }
-
-    .bottom_text {
-        position: absolute;
-        top: calc(106px);
-        font-weight: 600;
-        width: 100%;
-        text-align: center;
-    }
-}
-</style>

+ 0 - 52
frontend-next/src/components/FooterToolbar/FooterToolBar.vue

@@ -1,52 +0,0 @@
-<template>
-    <div class="ant-pro-footer-toolbar">
-        <div style="float: left">
-            <slot name="extra">{{ extra }}</slot>
-        </div>
-        <div style="float: right">
-            <slot></slot>
-        </div>
-    </div>
-</template>
-
-<script>
-export default {
-    name: 'FooterToolBar',
-    props: {
-        prefixCls: {
-            type: String,
-            default: 'ant-pro-footer-toolbar'
-        },
-        extra: {
-            type: [String, Object],
-            default: ''
-        }
-    }
-}
-</script>
-
-<style lang="less" scoped>
-.ant-pro-footer-toolbar {
-    position: fixed;
-    width: 100%;
-    bottom: 0;
-    right: 0;
-    height: 56px;
-    line-height: 56px;
-    box-shadow: 0 -1px 2px rgba(0, 0, 0, 0.03);
-    background: #ffffff8c;
-    border-top: 1px solid #e8e8e8;
-    @media (prefers-color-scheme: dark) {
-        background: rgba(24, 24, 24, 0.62);
-        border-top: unset;
-    }
-    padding: 0 24px;
-    z-index: 9;
-
-    &:after {
-        content: "";
-        display: block;
-        clear: both;
-    }
-}
-</style>

+ 0 - 3
frontend-next/src/components/FooterToolbar/index.js

@@ -1,3 +0,0 @@
-import FooterToolBar from './FooterToolBar'
-
-export default FooterToolBar

+ 0 - 42
frontend-next/src/components/Logo/Logo.vue

@@ -1,42 +0,0 @@
-<script setup lang="ts">
-import logo from '@/assets/img/logo.png'</script>
-
-<template>
-    <div class="logo">
-        <img :src="logo" alt="logo"/>
-        <p class="text">Nginx UI</p>
-        <div class="clear"></div>
-    </div>
-</template>
-
-<style lang="less" scoped>
-.logo {
-    padding: 8px 25px;
-    -webkit-box-shadow: 1px 1px 0 0 #e8e8e8;
-    box-shadow: 1px 1px 0 0 #e8e8e8;
-    transition: all 0.3s;
-    height: 64px;
-    width: 100%;
-    overflow: hidden;
-    display: inline-block;
-    background-color: #ffffff;
-    @media (prefers-color-scheme: dark) {
-        background-color: transparent;
-        -webkit-box-shadow: 1px 1px 0 0 #404040;
-        box-shadow: 1px 1px 0 0 #404040;
-    }
-
-    img {
-        height: 46px;
-        float: left;
-    }
-
-    .text {
-        float: left;
-        font-size: 22px;
-        line-height: 48px;
-        height: 48px;
-        display: inline-block;
-    }
-}
-</style>

+ 0 - 187
frontend-next/src/components/PageHeader/PageHeader.vue

@@ -1,187 +0,0 @@
-<script setup lang="ts">
-import Breadcrumb from '@/components/Breadcrumb/Breadcrumb.vue'
-import {useRoute} from 'vue-router'
-import {computed, ref, watch} from 'vue'
-
-const {title, logo, avatar} = defineProps(['title', 'logo', 'avatar'])
-
-const route = useRoute()
-
-const display = computed(() => {
-    return !route.meta.hiddenHeaderContent
-})
-
-const name = ref(route.name)
-watch(() => route.name, () => {
-    name.value = route.name
-})
-
-</script>
-
-<template>
-    <div v-if="display" class="page-header">
-        <div class="page-header-index-wide">
-            <Breadcrumb/>
-            <div class="detail">
-                <div class="main">
-                    <div class="row">
-                        <img v-if="logo" :src="logo" class="logo"/>
-                        <h1 class="title">
-                            {{ name() }}
-                        </h1>
-                        <div class="action">
-                            <slot name="action"></slot>
-                        </div>
-                    </div>
-                </div>
-            </div>
-        </div>
-    </div>
-</template>
-
-<style lang="less" scoped>
-.page-header {
-    background: #fff;
-    padding: 16px 32px 0;
-    border-bottom: 1px solid #e8e8e8;
-    @media (prefers-color-scheme: dark) {
-        background: #28292c !important;
-        border-bottom: unset;
-        h1 {
-            color: #fafafa;
-        }
-    }
-
-
-    .breadcrumb {
-        margin-bottom: 16px;
-    }
-
-    .detail {
-        display: flex;
-        /*margin-bottom: 16px;*/
-
-        .avatar {
-            flex: 0 1 72px;
-            margin: 0 24px 8px 0;
-
-            & > span {
-                border-radius: 72px;
-                display: block;
-                width: 72px;
-                height: 72px;
-            }
-        }
-
-        .main {
-            width: 100%;
-            flex: 0 1 auto;
-
-            .row {
-                display: flex;
-                width: 100%;
-
-                .avatar {
-                    margin-bottom: 16px;
-                }
-            }
-
-            .title {
-                font-size: 20px;
-                font-weight: 500;
-                line-height: 28px;
-                margin-bottom: 16px;
-                flex: auto;
-            }
-
-            .logo {
-                width: 28px;
-                height: 28px;
-                border-radius: 4px;
-                margin-right: 16px;
-            }
-
-            .content,
-            .headerContent {
-                flex: auto;
-                line-height: 22px;
-
-                .link {
-                    margin-top: 16px;
-                    line-height: 24px;
-
-                    a {
-                        font-size: 14px;
-                        margin-right: 32px;
-                    }
-                }
-            }
-
-            .extra {
-                flex: 0 1 auto;
-                margin-left: 88px;
-                min-width: 242px;
-                text-align: right;
-            }
-
-            .action {
-                margin-left: 56px;
-                min-width: 266px;
-                flex: 0 1 auto;
-                text-align: right;
-
-                &:empty {
-                    display: none;
-                }
-            }
-        }
-    }
-}
-
-.mobile .page-header {
-    .main {
-        .row {
-            flex-wrap: wrap;
-
-            .avatar {
-                flex: 0 1 25%;
-                margin: 0 2% 8px 0;
-            }
-
-            .content,
-            .headerContent {
-                flex: 0 1 70%;
-
-                .link {
-                    margin-top: 16px;
-                    line-height: 24px;
-
-                    a {
-                        font-size: 14px;
-                        margin-right: 10px;
-                    }
-                }
-            }
-
-            .extra {
-                flex: 1 1 auto;
-                margin-left: 0;
-                min-width: 0;
-                text-align: right;
-            }
-
-            .action {
-                margin-left: unset;
-                min-width: 266px;
-                flex: 0 1 auto;
-                text-align: left;
-                margin-bottom: 12px;
-
-                &:empty {
-                    display: none;
-                }
-            }
-        }
-    }
-}
-</style>

+ 0 - 38
frontend-next/src/components/SetLanguage/SetLanguage.vue

@@ -1,38 +0,0 @@
-<script setup lang="ts">
-import gettext from '@/gettext'
-
-
-import {ref, watch} from 'vue'
-
-import {useSettingsStore} from '@/pinia/settings'
-import {useRoute} from 'vue-router'
-
-const settings = useSettingsStore()
-
-const route = useRoute()
-
-const current = ref(gettext.current)
-
-const languageAvailable = gettext.available
-watch(current, (v) => {
-    settings.set_language(v)
-    gettext.current = v
-    // @ts-ignored
-    document.title = route.name() + ' | Nginx UI'
-})
-
-</script>
-
-<template>
-    <div>
-        <a-select v-model:value="current" size="small" style="width: 60px">
-            <a-select-option v-for="(language, key) in languageAvailable" :value="key" :key="key">
-                {{ language }}
-            </a-select-option>
-        </a-select>
-    </div>
-</template>
-
-<style lang="less" scoped>
-
-</style>

+ 0 - 160
frontend-next/src/components/StdDataDisplay/StdCurd.vue

@@ -1,160 +0,0 @@
-<script lang="ts">
-import gettext from '@/gettext'
-
-const {$gettext, interpolate} = gettext
-</script>
-<script setup lang="ts">
-import StdTable from './StdTable.vue'
-// import StdDataEntry from '@/components/StdDataEntry/StdDataEntry'
-
-import {reactive, ref} from 'vue'
-import {message} from 'ant-design-vue'
-
-const props = defineProps({
-    api: Object,
-    columns: Array,
-    title: {
-        type: String,
-        default: $gettext('Table')
-    },
-    data_key: {
-        type: String,
-        default: 'data'
-    },
-    disable_search: {
-        type: Boolean,
-        default: false
-    },
-    disable_add: {
-        type: Boolean,
-        default: false
-    },
-    soft_delete: {
-        type: Boolean,
-        default: false
-    },
-    edit_text: String,
-    deletable: {
-        type: Boolean,
-        default: true
-    },
-    get_params: {
-        type: Object,
-        default() {
-            return {}
-        }
-    },
-    editable: {
-        type: Boolean,
-        default: true
-    },
-})
-
-const visible = ref(false)
-const update = ref(0)
-let data = reactive({id: null})
-let error = reactive({})
-const params = reactive({})
-const selected = reactive([])
-
-function onSelect(keys: any) {
-    selected.concat(...keys)
-}
-
-function editableColumns() {
-    return props.columns!.filter((c: any) => {
-        return c.edit
-    })
-}
-
-function add() {
-    data = reactive({
-        id: null
-    })
-    visible.value = true
-}
-
-const table = ref(null)
-
-interface Table {
-    get_list(): void
-}
-
-const ok = async () => {
-    error = reactive({})
-    props.api!.save(data.id, data).then((r: any) => {
-        message.success($gettext('Save Successfully'))
-        Object.assign(data, r)
-        const t: Table | null = table.value
-        t!.get_list()
-
-    }).catch((e: any) => {
-        message.error((e?.message ?? $gettext('Server error')), 5)
-        error = e.errors
-    })
-}
-
-function cancel() {
-    visible.value = false
-    error = reactive({})
-}
-
-function edit(id: any) {
-    props.api!.get(id).then((r: any) => {
-        Object.assign(data, r)
-        visible.value = true
-    }).catch((e: any) => {
-        message.error((e?.message ?? $gettext('Server error')), 5)
-    })
-}
-
-</script>
-
-<template>
-    <div class="std-curd">
-        <a-card :title="title">
-            <template v-if="!disable_add" #extra>
-                <a @click="add" v-translate>Add</a>
-            </template>
-
-            <std-table
-                ref="table"
-                v-bind="this.$props"
-                @clickEdit="edit"
-                @selected="onSelect"
-                :key="update"
-            >
-                <template v-slot:actions="slotProps">
-                    <slot name="actions" :actions="slotProps.record"/>
-                </template>
-            </std-table>
-        </a-card>
-
-        <a-modal
-            class="std-curd-edit-modal"
-            :mask="false"
-            :title="data.id ? $gettext('Modify') : $gettext('Add')"
-            :visible="visible"
-            :cancel-text="$gettext('Cancel')"
-            :ok-text="$gettext('OK')"
-            @cancel="cancel"
-            @ok="ok"
-            :width="600"
-            destroyOnClose
-        >
-            <!--            <std-data-entry ref="std_data_entry" :data-list="editableColumns()" :data-source="data"-->
-            <!--                            :error="error">-->
-            <!--                <div slot="supplement">-->
-            <!--                    <slot name="supplement"></slot>-->
-            <!--                </div>-->
-            <!--                <div slot="action">-->
-            <!--                    <slot name="action"></slot>-->
-            <!--                </div>-->
-            <!--            </std-data-entry>-->
-        </a-modal>
-    </div>
-</template>
-
-<style lang="less" scoped>
-
-</style>

+ 0 - 51
frontend-next/src/components/StdDataDisplay/StdPagination.vue

@@ -1,51 +0,0 @@
-<template>
-    <div v-if="Object.keys(pagination).length !== 0">
-        <a-pagination
-            :current="pagination.current_page"
-            :hideOnSinglePage="true"
-            :pageSize="pagination.per_page"
-            :size="size"
-            :total="pagination.total"
-            :show-total="(total, range) => `当前显示${range[0]}-${range[1]}条数据,共${total}条数据`"
-            class="pagination"
-            @change="changePage"
-        />
-        <div class="clear"></div>
-    </div>
-</template>
-
-<script>
-export default {
-    name: 'StdPagination',
-    props: {
-        pagination: Object,
-        size: {
-            default: ''
-        }
-    },
-    methods: {
-        changePage(num) {
-            return this.$emit('changePage', num)
-        }
-    }
-}
-</script>
-
-<style lang="less">
-.ant-pagination-total-text {
-    @media (max-width: 450px) {
-        display: block;
-    }
-}
-</style>
-
-<style lang="less" scoped>
-.pagination {
-    padding: 10px 0 0 0;
-    float: right;
-    @media (max-width: 450px) {
-        float: unset;
-        text-align: center;
-    }
-}
-</style>

+ 0 - 285
frontend-next/src/components/StdDataDisplay/StdTable.vue

@@ -1,285 +0,0 @@
-<script setup lang="ts">
-import gettext from '@/gettext'
-
-const {$gettext, interpolate} = gettext
-
-import StdPagination from './StdPagination.vue'
-import {nextTick, reactive, ref} from 'vue'
-import {useRoute} from 'vue-router'
-import {message} from 'ant-design-vue'
-
-const props = defineProps({
-    api: Object,
-    columns: Array,
-    data_key: {
-        type: String,
-        default: 'data'
-    },
-    disable_search: {
-        type: Boolean,
-        default: false
-    },
-    disable_add: {
-        type: Boolean,
-        default: false
-    },
-    edit_text: String,
-    deletable: {
-        type: Boolean,
-        default: true
-    },
-    get_params: {
-        type: Object,
-        default() {
-            return {}
-        }
-    },
-    editable: {
-        type: Boolean,
-        default: true
-    },
-    selectionType: {
-        type: String,
-        default: 'checkbox',
-        validator: function (value: string) {
-            return ['checkbox', 'radio'].indexOf(value) !== -1
-        }
-    },
-    pithy: {
-        type: Boolean,
-        default: false
-    },
-    scrollX: {
-        type: [Number, Boolean],
-        default: true
-    },
-    rowKey: {
-        type: String,
-        default: 'id'
-    }
-})
-
-
-const data_source = reactive([])
-const loading = ref(true)
-const pagination = ({
-    total: 1,
-    per_page: 10,
-    current_page: 1,
-    total_pages: 1
-})
-const route = useRoute()
-const params = reactive({
-    ...route.query,
-    ...props.get_params
-})
-let selectedRowKeys = ref([])
-const rowSelection = reactive({})
-
-const searchColumns = getSearchColumns()
-const pithyColumns = getPithyColumns()
-
-
-get_list()
-
-defineExpose({
-    get_list
-})
-
-function destroy(id: any) {
-    props.api!.destroy(id).then(() => {
-        get_list()
-        message.success(interpolate($gettext('Delete ID: %{id}'), {id: id}))
-    }).catch((e: any) => {
-        message.error(e?.message ?? $gettext('Server error'))
-    })
-}
-
-function get_list(page_num = null) {
-    loading.value = true
-    if (page_num) {
-        params['page'] = page_num
-    }
-    props.api!.get_list(params).then((r: any) => {
-        Object.assign(data_source, r.data)
-
-        if (r.pagination !== undefined) {
-            Object.assign(pagination, r.pagination)
-        }
-
-        loading.value = false
-    }).catch((e: any) => {
-        message.error(e?.message ?? $gettext('Server error'))
-    })
-}
-
-function stdChange(pagination: any, filters: any, sorter: any) {
-    if (sorter) {
-        params['order_by'] = sorter.field
-        params['sort'] = sorter.order === 'ascend' ? 'asc' : 'desc'
-        nextTick(() => {
-            get_list()
-        })
-    }
-}
-
-function getSearchColumns() {
-    let searchColumns: any = []
-    props.columns!.forEach((column: any) => {
-        if (column.search) {
-            if (column.edit && column.edit.type !== 'upload'
-                && column.edit.type !== 'transfer') {
-                const tmp = Object.assign({}, column)
-                tmp.edit = Object.assign({}, column.edit)
-                if (typeof column.search === 'string') {
-                    tmp.edit.type = column.search
-                } else if (typeof column.search === 'object') {
-                    tmp.edit = column.search
-                }
-                searchColumns.push(tmp)
-            }
-            // search 覆盖 edit
-            if (!column.edit) {
-                const tmp = Object.assign({}, column)
-                tmp.edit = Object.assign({}, column.edit)
-                if (typeof column.search === 'object') {
-                    tmp.edit = column.search
-                }
-                searchColumns.push(tmp)
-            }
-        }
-    })
-    return searchColumns
-}
-
-function getPithyColumns() {
-    if (props.pithy) {
-        return props.columns!.filter((c: any, index: any, columns: any) => {
-            return c.pithy === true && c.display !== false
-        })
-    }
-    return props.columns!.filter((c: any, index: any, columns: any) => {
-        return c.display !== false
-    })
-}
-
-function checked(c: any) {
-    params[c.target.value] = c.target.checked
-}
-
-function onSelectChange(_selectedRowKeys: any) {
-    selectedRowKeys = reactive(_selectedRowKeys)
-    // this.$emit('selected', selectedRowKeys)
-}
-
-function onSelect(record) {
-    // this.$emit('selectedRecord', record)
-}
-
-function handleClick(data, index, method = '', path = '') {
-    if (method === 'router') {
-        this.$router.push(path + '/' + data).then()
-    } else {
-        this.params[index] = data
-        this.get_list()
-    }
-}
-
-function row(record) {
-    return {
-        on: {
-            click: () => {
-                this.$emit('clickRow', record.id)
-            }
-        }
-    }
-}
-
-const reset_search = async () => {
-    this.params = {}
-    await this.$router.push({query: {}}).catch(() => {
-    })
-}
-</script>
-
-<template>
-    <div class="std-table">
-        <!--        <std-data-entry-->
-        <!--            v-if="!disable_search"-->
-        <!--            :data-list="searchColumns"-->
-        <!--            v-model="params"-->
-        <!--            layout="inline"-->
-        <!--        >-->
-        <!--            <div slot="action">-->
-        <!--                <a-form-item :wrapper-col="{span:8}">-->
-        <!--                    <a-button type="primary" @click="$router.push({-->
-        <!--                        query: Object.assign({}, params),-->
-        <!--                    }).catch(() => {})">查询-->
-        <!--                    </a-button>-->
-        <!--                </a-form-item>-->
-        <!--                <a-form-item :wrapper-col="{span:8}">-->
-        <!--                    <a-button @click="reset_search">重置</a-button>-->
-        <!--                </a-form-item>-->
-        <!--            </div>-->
-        <!--        </std-data-entry>-->
-        <a-table
-            :columns="pithyColumns"
-            :customRow="row"
-            :data-source="data_source"
-            :loading="loading"
-            :pagination="false"
-            :row-key="rowKey"
-            :rowSelection="{selectedRowKeys: selectedRowKeys, onChange: onSelectChange,
-            onSelect: onSelect, type: selectionType,}"
-            @change="stdChange"
-            :scroll="{ x: scrollX }"
-        >
-            <template
-                v-slot:bodyCell="{text, record, index, column}"
-            >
-                <template v-if="column.dataIndex === 'action'">
-                    <a v-if="props.editable" @click="$emit('clickEdit', record[props.rowKey], record)">
-                        {{ props.edit_text || $gettext('Modify') }}
-                    </a>
-                    <slot name="actions" :record="record"/>
-                    <template v-if="props.deletable">
-                        <a-divider type="vertical"/>
-                        <a-popconfirm
-                            :cancelText="$gettext('No')"
-                            :okText="$gettext('OK')"
-                            :title="$gettext('Are you sure you want to delete ?')"
-                            @confirm="destroy(record[rowKey])">
-                            <a v-translate>Delete</a>
-                        </a-popconfirm>
-                    </template>
-                </template>
-            </template>
-
-        </a-table>
-        <std-pagination :pagination="pagination" @changePage="get_list"/>
-    </div>
-</template>
-
-<style lang="less">
-.ant-table-scroll {
-    .ant-table-body {
-        overflow-x: auto !important;
-    }
-}
-</style>
-
-<style lang="less" scoped>
-.ant-form {
-    margin: 10px 0 20px 0;
-}
-
-.ant-slider {
-    min-width: 90px;
-}
-
-.std-table {
-    .ant-table-wrapper {
-        // overflow-x: scroll;
-    }
-}
-</style>

+ 0 - 53
frontend-next/src/components/StdDataEntry/StdCheckGroup.vue

@@ -1,53 +0,0 @@
-<template>
-    <div>
-        <a-checkbox-group v-model="checkedList" :options="options" @change="onChange"/>
-        <template v-if="allowOther&&checkedList.indexOf('其他')>0">
-            <a-form-item label="其他">
-                <a-input v-model="other" @change="onChangeOther"/>
-            </a-form-item>
-        </template>
-    </div>
-</template>
-<script>
-export default {
-    name: 'StdCheckGroup',
-    props: {
-        options: Array,
-        allowOther: Boolean,
-        data: {
-            type: Object,
-            default() {
-                return {
-                    checkedList: [],
-                    other: ''
-                }
-            }
-        }
-    },
-    model: {
-        prop: 'data',
-        event: 'changeData'
-    },
-    watch: {
-        data() {
-            this.checkedList = this.data.checkedList
-            this.other = this.data.other
-        }
-    },
-    data() {
-        return {
-            checkedList: this.data.checkedList,
-            other: this.data.other
-        }
-    },
-    methods: {
-        onChange(checkedList) {
-            this.checkedList = checkedList
-            this.$emit('changeData', this.$data)
-        },
-        onChangeOther() {
-            this.$emit('changeData', this.$data)
-        }
-    },
-}
-</script>

+ 0 - 65
frontend-next/src/components/StdDataEntry/StdCheckTag.vue

@@ -1,65 +0,0 @@
-<template>
-    <div>
-        <template v-for="(v,k) in options">
-            <a-checkable-tag
-                :key="k"
-                :checked="selectedTag === k"
-                @change="() => handleChange(k)"
-            >
-                {{ v }}
-            </a-checkable-tag>
-        </template>
-    </div>
-</template>
-
-<script>
-export default {
-    name: 'StdCheckTag',
-    data() {
-        return {
-            selectedTag: '',
-        }
-    },
-    props: {
-        disabled: [Boolean],
-        value: [Number, String, Boolean],
-        options: [Array, Object],
-        keyType: {
-            type: String,
-            default() {
-                return 'int'
-            }
-        }
-    },
-    model: {
-        prop: 'value',
-        event: 'change'
-    },
-    methods: {
-        handleChange(tag) {
-            if (!this.disabled) {
-                this.selectedTag = tag
-                this.$emit('change', isNaN(parseInt(tag)) || this.keyType === 'string' ? tag : parseInt(tag))
-            }
-        }
-    },
-    watch: {
-        value() {
-            this.selectedTag = this.value != null ? this.value.toString() : null
-        }
-    },
-    created() {
-        this.selectedTag = this.value != null ? this.value.toString() : null
-    }
-}
-</script>
-
-<style lang="less" scoped>
-.ant-tag {
-    background-color: rgba(0, 0, 0, 0.05);
-}
-
-.ant-tag-checkable-checked {
-    background-color: #1890ff;
-}
-</style>

+ 0 - 237
frontend-next/src/components/StdDataEntry/StdDataEntry.vue

@@ -1,237 +0,0 @@
-<template>
-    <a-form :layout="layout" class="std-data-entry">
-        <a-form-item
-            v-for="d in M_dataList" :key="d.dataIndex" :help="error[d.dataIndex] ? error[d.dataIndex].toString() : null"
-            :label="d.title"
-            :labelCol="d.edit.labelCol"
-            :validate-status="error[d.dataIndex] ? 'error' :'success'"
-            :wrapperCol="d.edit.wrapperCol"
-        >
-            <p v-if="d.description" v-html="d.description+'<br/>'"/>
-            <a-input
-                v-if="d.edit.type==='input'"
-                v-model="dataSource[d.dataIndex]"
-                :placeholder="getInputPlaceholder(d, dataSource)"
-            />
-            <a-textarea v-else-if="d.edit.type==='textarea'" v-model="dataSource[d.dataIndex]"
-                        :rows="d.edit.row?d.edit.row:5"/>
-            <std-select-option
-                v-else-if="d.edit.type==='select'"
-                v-model="temp[d.dataIndex]"
-                :options="d.mask"
-                :key-type="d.edit.key_type ? d.edit.key_type : 'int'"
-                style="min-width: 120px"
-            />
-
-            <std-check-tag
-                v-else-if="d.edit.type==='check-tag'"
-                v-model="temp[d.dataIndex]"
-                :options="d.mask"
-            />
-
-            <std-multi-check-tag
-                v-else-if="d.edit.type==='multi-check-tag'"
-                v-model="temp[d.dataIndex]"
-                :data-object="temp"
-                :options="d.mask"
-            />
-
-            <std-selector
-                v-else-if="d.edit.type==='selector'" v-model="temp[d.dataIndex]" :api="d.edit.api"
-                :columns="d.edit.columns"
-                :data_key="d.edit.data_key"
-                :disable_search="d.edit.disable_search" :pagination_method="d.edit.pagination_method"
-                :record-value-index="d.edit.recordValueIndex" :value="fn(temp, d.edit.valueIndex)"
-                :get_params="get_params_fn(d)"
-                :description="d.edit.description"
-                selection-type="radio"
-            />
-
-            <a-input-number v-else-if="d.edit.type==='number'" v-model="temp[d.dataIndex]"
-                            :min="d.edit.min" :step="d.edit.step" :max="d.edit.max"
-            />
-
-            <std-upload v-else-if="d.edit.type==='upload'" :id="temp.id?temp.id:null" :ref="'std_upload_'+d.dataIndex"
-                        v-model="temp[d.dataIndex]" :api="d.edit.api"
-                        :api_delete="d.edit.api_delete"
-                        :list="temp[d.dataIndex]"
-                        :crop="d.edit.crop"
-                        :auto-upload="d.edit.auto_upload"
-                        :crop-options="d.edit.cropOptions" :type="d.edit.upload_type ? d.edit.upload_type : 'img'"
-                        @uploaded="url => {$emit('uploaded', url)}"
-            />
-
-            <std-date-picker v-else-if="d.edit.type==='date_picker'" v-model="temp[d.dataIndex]"
-                             :show-time="d.edit.showTime"/>
-
-            <a-slider
-                v-else-if="d.edit.type==='slider'"
-                v-model="temp[d.dataIndex]"
-                :marks="d.mask"
-                :max="d.edit.max"
-                :min="d.edit.min"
-            />
-
-            <a-switch
-                v-else-if="d.edit.type==='switch'"
-                v-model="temp[d.dataIndex]"
-            />
-
-            <a-checkbox
-                v-else-if="d.edit.type==='checkbox'"
-                v-model="temp[d.dataIndex]"
-            >
-                {{ d.text }}
-            </a-checkbox>
-
-            <std-check-group
-                v-else-if="d.edit.type==='check-group'"
-                v-model="temp[d.dataIndex]"
-                :options="d.options"
-                :allow-other="d.edit.allow_other"
-            />
-
-            <std-radio-group
-                v-else-if="d.edit.type==='radio-group'"
-                v-model="temp[d.dataIndex]"
-                :options="d.options"
-                :key-type="d.edit.key_type"
-            />
-
-            <std-transfer
-                v-else-if="d.edit.type==='transfer'"
-                v-model="temp[d.dataIndex]"
-                :api="d.edit.api"
-                :data-key="d.edit.dataKey"
-            />
-
-            <p v-else-if="d.edit.type==='readonly'">
-                {{ d.mask ? d.mask[fn(temp, d.dataIndex)] : fn(temp, d.dataIndex) }}
-            </p>
-
-            <p v-else>{{ 'edit.type 参数非法 ' + d.edit.type }}</p>
-
-            <p v-if="!dataSource[d.dataIndex] && d.empty_description" v-html="d.empty_description"/>
-        </a-form-item>
-        <a-form-item v-if="$slots.supplement||$slots.action">
-            <slot name="supplement"/>
-            <slot name="action"/>
-        </a-form-item>
-    </a-form>
-</template>
-
-<script>
-import StdSelectOption from './StdSelectOption'
-import StdSelector from './StdSelector'
-import StdUpload from './StdUpload'
-import StdDatePicker from './StdDatePicker'
-import StdTransfer from './StdTransfer'
-import StdCheckTag from '@/components/StdDataEntry/StdCheckTag'
-import StdMultiCheckTag from '@/components/StdDataEntry/StdMultiCheckTag'
-import StdCheckGroup from '@/components/StdDataEntry/StdCheckGroup'
-import StdRadioGroup from '@/components/StdDataEntry/StdRadioGroup'
-
-export default {
-    name: 'StdDataEntry',
-    components: {
-        StdRadioGroup,
-        StdCheckGroup,
-        StdMultiCheckTag,
-        StdCheckTag,
-        StdTransfer,
-        StdDatePicker,
-        StdSelectOption,
-        StdSelector,
-        StdUpload
-    },
-    props: {
-        dataList: [Array, Object],
-        dataSource: Object,
-        error: {
-            type: Object,
-            default() {
-                return {}
-            }
-        },
-        layout: {
-            default: 'vertical',
-            validator: value => {
-                return ['horizontal', 'vertical', 'inline'].indexOf(value) !== -1
-            }
-        }
-    },
-    model: {
-        prop: 'dataSource',
-        event: 'changeDataSource'
-    },
-    data() {
-        return {
-            temp: null,
-            i: 0,
-            M_dataList: {}
-        }
-    },
-    watch: {
-        dataSource() {
-            this.temp = this.dataSource ?? []
-        },
-        dataList() {
-            this.M_dataList = this.editableColumns(this.dataList ?? [])
-        }
-    },
-    created() {
-        this.temp = this.dataSource ?? []
-        if (this.layout === 'horizontal') {
-            this.labelCol = {span: 4}
-            this.wrapperCol = {span: 18}
-        }
-        this.M_dataList = this.editableColumns(this.dataList)
-    },
-    methods: {
-        get_params_fn(d) {
-            return {...d.edit.get_params, ...this.bindModel(d.edit.bind, this.temp)}
-        },
-        fn: (obj, desc) => {
-            const arr = desc.split('.')
-            while (arr.length) {
-                const top = obj[arr.shift()]
-                if (top === undefined) {
-                    return null
-                }
-                obj = top
-            }
-            return obj
-        },
-        editableColumns(columns) {
-            if (typeof columns === 'object') {
-                columns = Object.values(columns)
-            }
-            return columns.filter((c) => {
-                return c.edit
-            })
-        },
-        bindModel(bind, dataSource) {
-            let object = {}
-            if (bind) {
-                for (const [key, value] of Object.entries(bind)) {
-                    object[key] = this.fn(dataSource, value)
-                }
-            }
-            return object
-        },
-        getInputPlaceholder(d, dataSource) {
-            // edit 模式
-            if (dataSource.id) {
-                return d.edit.placeholder?.edit ?? d.edit.placeholder
-            } else {
-                // add 模式
-                return d.edit.placeholder?.add ?? d.edit.placeholder
-            }
-        }
-    }
-}
-</script>
-
-<style scoped>
-
-</style>

+ 0 - 52
frontend-next/src/components/StdDataEntry/StdDatePicker.vue

@@ -1,52 +0,0 @@
-<template>
-    <a-date-picker
-        v-model="dateModel"
-        :show-time="showTime"
-        @change="r => {changeDate(r.format())}"
-    />
-</template>
-
-<script>
-import moment from 'moment'
-import 'moment/locale/zh-cn'
-
-moment.locale('zh-cn')
-
-export default {
-    name: 'StdDatePicker',
-    props: {
-        date: String,
-        showTime: {
-            type: [Object, Boolean],
-            default() {
-                return false
-            }
-        }
-
-    },
-    model: {
-        prop: 'date',
-        event: 'changeDate'
-    },
-    data() {
-        return {
-            moment,
-            dateModel: this.date ? moment(this.date) : null
-        }
-    },
-    watch: {
-        date() {
-            this.dateModel = this.date ? moment(this.date) : null
-        }
-    },
-    methods: {
-        changeDate(d) {
-            this.$emit('changeDate', d)
-        }
-    }
-}
-</script>
-
-<style scoped>
-
-</style>

+ 0 - 75
frontend-next/src/components/StdDataEntry/StdMultiCheckTag.vue

@@ -1,75 +0,0 @@
-<template>
-    <div>
-        <template v-for="(v,k) in options">
-            <a-checkable-tag
-                :key="k"
-                :checked="selectedTags.indexOf(k) > -1"
-                @change="checked => handleChange(k, checked)"
-            >
-                {{ v }}
-            </a-checkable-tag>
-        </template>
-    </div>
-</template>
-
-<script>
-export default {
-    name: 'StdMultiCheckTag',
-    data() {
-        return {
-            selectedTags: [],
-        }
-    },
-    props: {
-        disabled: [Boolean],
-        value: [Array],
-        dataObject: [Object],
-        options: {
-            type: Object,
-            default() {
-                return {}
-            }
-        },
-    },
-    model: {
-        prop: 'value',
-        event: 'change'
-    },
-    methods: {
-        handleChange(tag, checked) {
-            const {selectedTags} = this
-            this.selectedTags = checked
-                ? [...selectedTags, tag]
-                : selectedTags.filter(t => t !== tag)
-            this.$emit('change', this.selectedTags)
-        },
-        loadData() {
-            for (const [k] of Object.entries(this.options)) {
-                if (this.dataObject[k] === 1) {
-                    if (this.selectedTags.indexOf(k) === -1)
-                        this.selectedTags.push(k)
-                }
-            }
-        }
-    },
-    watch: {
-        value() {
-            this.selectedTag = this.value ?? []
-        },
-    },
-    created() {
-        this.selectedTag = this.value ?? []
-        this.loadData()
-    },
-}
-</script>
-
-<style lang="less" scoped>
-.ant-tag {
-    background-color: rgba(0, 0, 0, 0.05);
-}
-
-.ant-tag-checkable-checked {
-    background-color: #1890ff;
-}
-</style>

+ 0 - 153
frontend-next/src/components/StdDataEntry/StdMultiFilesUpload.vue

@@ -1,153 +0,0 @@
-<template>
-    <div>
-        <a-upload
-            :before-upload="beforeUpload"
-            :multiple="true"
-            :show-upload-list="true"
-            :file-list="uploadList"
-            :remove="remove"
-        >
-            <a-button :disabled="disabled">
-                <a-icon type="upload"/>
-                选择文件
-            </a-button>
-        </a-upload>
-        <a-progress
-            v-if="show_progress"
-            :stroke-color="{
-        from: '#108ee9',
-        to: '#87d068',
-      }"
-            :percent="progress"
-        />
-        <a-button
-            type="primary"
-            :disabled="uploadList.length === 0 && !id"
-            :loading="uploading"
-            style="margin: 16px 0"
-            @click="upload"
-            v-if="id"
-        >
-            {{ uploading ? '上传中' : '开始上传' }}
-        </a-button>
-        <p style="margin: 15px 0" v-for="file in uploaded" :key="file.id">
-            <a-icon type="paper-clip" style="margin-right: 5px"/>
-            <a :href="server + '/' + file.path" target="_blank" @click="()=>{}">{{ getFileName(file.path) }}</a>
-            <a-popconfirm
-                title="确定要删除文件吗"
-                ok-text="确认"
-                cancel-text="取消"
-                @confirm="deleteFile(file.id)"
-                style="float: right"
-            >
-                <a-button type="link">删除</a-button>
-            </a-popconfirm>
-        </p>
-    </div>
-</template>
-
-<script>
-export default {
-    name: 'StdMultiFilesUpload',
-    props: {
-        api: Function,
-        id: {
-            type: Number,
-            default: null
-        },
-        fileList: {
-            default: null
-        },
-        autoUpload: {
-            type: Boolean,
-            default: false
-        },
-        api_delete: {
-            type: Function,
-            default: null
-        },
-        disabled: {
-            type: Boolean,
-            default: false
-        }
-    },
-    watch: {
-        fileList() {
-            this.uploaded = this.fileList
-        }
-    },
-    data() {
-        return {
-            show_progress: false,
-            uploadList: [],
-            uploaded: this.fileList,
-            lastFileTime: 0,
-            server: process.env['VUE_APP_API_UPLOAD_ROOT'],
-            uploading: false,
-            progress: 0
-        }
-    },
-    model: {
-        prop: 'fileUrl',
-        event: 'changeFileUrl'
-    },
-    methods: {
-        async upload() {
-            if (this.uploadList.length) {
-                this.uploading = true
-                this.show_progress = true
-                this.progress = 0
-                let formData = new FormData()
-                this.uploadList.forEach(v => {
-                    formData.append('file[]', v)
-                })
-                this.visible = false
-                this.uploading = true
-                this.$message.info('正在上传附件, 请不要关闭本页')
-                let config = {
-                    onUploadProgress: (progressEvent) => {
-                        // 使用本地 progress 事件
-                        if (progressEvent.lengthComputable) {
-                            this.progress = Math.round((progressEvent.loaded / progressEvent.total) * 100) // 使用某种 UI 进度条组件会用到的百分比
-                        }
-                    }
-                }
-                return this.api(this.id, formData, config).then(r => {
-                    this.uploadList = []
-                    this.uploaded = [...this.uploaded, ...r]
-                    this.uploading = false
-                    this.$emit('uploaded', r)
-                    this.uploading = false
-                    this.orig = false
-                    this.$message.success('上传成功')
-                }).catch(e => {
-                    this.$message.error(e.message ? e.message : '上传失败')
-                })
-            }
-        },
-        beforeUpload(file) {
-            this.uploadList.push(file)
-            return false
-        },
-        deleteFile(file_id) {
-            this.api_delete(this.id, file_id).then(r => {
-                this.uploaded = r
-            })
-        },
-        getFileName(path) {
-            // 从15开始找
-            const idx = path.indexOf('/', 15)
-            return path.substring(idx + 1)
-        },
-        remove(r) {
-            this.uploadList = this.uploadList.filter(value => {
-                return value !== r
-            })
-        },
-    }
-}
-</script>
-
-<style scoped>
-
-</style>

+ 0 - 49
frontend-next/src/components/StdDataEntry/StdRadioGroup.vue

@@ -1,49 +0,0 @@
-<template>
-    <a-radio-group name="radioGroup" v-model="data" @change="onChange">
-        <a-radio :value="k" v-for="(v,k) in options" :key="k">
-            {{ v }}
-        </a-radio>
-    </a-radio-group>
-</template>
-
-
-<script>
-export default {
-    name: 'StdRadioGroup',
-    props: {
-        options: [Object, Array],
-        value: {
-            type: [String, Number]
-        },
-        keyType: String
-    },
-    model: {
-        prop: 'value',
-        event: 'changeValue'
-    },
-    data() {
-        return {
-            data: this.value?.toString() ?? '',
-        }
-    },
-    watch: {
-        value() {
-            this.data = this.value.toString()
-        }
-    },
-    methods: {
-        onChange(e) {
-            if (this.keyType === 'int') {
-                this.data = e.target.value
-                this.$emit('changeValue', parseInt(e.target.value))
-            } else {
-                this.$emit('changeValue', e.target.value)
-            }
-        }
-    }
-}
-</script>
-
-<style scoped>
-
-</style>

+ 0 - 47
frontend-next/src/components/StdDataEntry/StdSelectOption.vue

@@ -1,47 +0,0 @@
-<template>
-    <a-select
-        v-model="tempValue"
-        :defaultValue="Object.keys(options)[0]"
-        @change="$emit('change', isNaN(parseInt(tempValue)) || keyType === 'string' ? tempValue : parseInt(tempValue) )">
-        <a-select-option v-for="(v,k) in options" :key="k">{{ v }}</a-select-option>
-    </a-select>
-</template>
-
-<script>
-export default {
-    name: 'StdSelectOption',
-    props: {
-        value: [Number, String, Boolean],
-        options: [Array, Object],
-        keyType: {
-            type: String,
-            default() {
-                return 'int'
-            }
-        }
-    },
-    model: {
-        prop: 'value',
-        event: 'change'
-    },
-    data() {
-        return {
-            tempValue: null
-        }
-    },
-    watch: {
-        value() {
-            this.tempValue = this.value != null ? this.value.toString() : null
-        }
-    },
-    created() {
-        this.tempValue = this.value != null ? this.value.toString() : null
-    }
-}
-</script>
-
-<style lang="less" scoped>
-.ant-select {
-    min-width: 80px;
-}
-</style>

+ 0 - 156
frontend-next/src/components/StdDataEntry/StdSelector.vue

@@ -1,156 +0,0 @@
-<template>
-    <div class="std-selector" @click="show()">
-        <a-input v-model="_key" disabled hidden/>
-        <div class="value">
-            <p>{{ M_value }}</p>
-        </div>
-        <a-modal
-            :mask="false"
-            :visible="visible"
-            cancel-text="取消"
-            ok-text="选择"
-            title="选择器"
-            @cancel="visible=false"
-            @ok="ok()"
-            :width="600"
-            destroyOnClose
-        >
-            {{ description }}
-            <std-table
-                :api="api"
-                :columns="columns"
-                :data_key="data_key"
-                :disable_search="disable_search"
-                :pithy="true"
-                :get_params="get_params"
-                :selectionType="selectionType"
-                :disable_query_params="true"
-                @selected="onSelect"
-                @selectedRecord="onSelectedRecord"
-            />
-        </a-modal>
-    </div>
-</template>
-
-<script>
-
-export default {
-    name: 'StdSelector',
-    components: {
-        StdTable: () => import('@/components/StdDataDisplay/StdTable')
-    },
-    props: {
-        _key: [Number, String],
-        value: String,
-        recordValueIndex: [Number, String],
-        selectionType: {
-            type: String,
-            default: 'checkbox',
-            validator: function (value) {
-                return ['checkbox', 'radio'].indexOf(value) !== -1
-            }
-        },
-        api: Object,
-        columns: Array,
-        data_key: String,
-        disable_search: {
-            type: Boolean,
-            default: false
-        },
-        get_params: {
-            type: Object,
-            default() {
-                return {}
-            }
-        },
-        description: String
-    },
-    model: {
-        prop: '_key',
-        event: 'changeSelect'
-    },
-    data() {
-        return {
-            visible: false,
-            selected: [],
-            record: {},
-            M_value: this.value
-        }
-    },
-    watch: {
-        _key() {
-            if (!this._key) {
-                this.M_value = null
-            }
-        },
-        value() {
-            this.M_value = this.value
-        }
-    },
-    methods: {
-        show() {
-            this.visible = true
-        },
-        onSelect(selected) {
-            this.selected = selected
-        },
-        onSelectedRecord(r) {
-            this.record = r
-        },
-        ok() {
-            this.visible = false
-            let selected = this.selected
-            if (this.selectionType === 'radio') {
-                selected = this.selected[0]
-            }
-            this.M_value = this.record[this.recordValueIndex]
-            this.$emit('changeSelect', selected)
-        }
-    }
-}
-</script>
-
-<style scoped>
-.ant-form-inline .std-selector {
-    height: 40px;
-}
-</style>
-
-<style lang="less" scoped>
-.std-selector {
-    height: 38px;
-    min-width: 180px;
-    position: relative;
-
-    .value {
-        box-sizing: border-box;
-        font-variant: tabular-nums;
-        list-style: none;
-        font-feature-settings: 'tnum';
-        position: absolute;
-        top: 50%;
-        bottom: 50%;
-        left: 50%;
-        -webkit-transform: translateX(-50%) translateY(-50%);
-        display: inline-block;
-        width: 100%;
-        height: 32px;
-        padding: 4px 11px;
-        color: rgba(0, 0, 0, 0.65);
-        font-size: 14px;
-        line-height: 1.5;
-        background-color: #fff;
-        background-image: none;
-        border: 1px solid #d9d9d9;
-        border-radius: 4px;
-        transition: all 0.3s;
-        margin: 0 10px 0 0;
-        cursor: pointer;
-        @media (prefers-color-scheme: dark) {
-            background-color: #1e1f20;
-            border: 1px solid #666666;
-            color: rgba(255, 255, 255, 0.99);
-        }
-    }
-}
-</style>

+ 0 - 105
frontend-next/src/components/StdDataEntry/StdSingleFileUpload.vue

@@ -1,105 +0,0 @@
-<template>
-    <div>
-        <a-upload
-            :before-upload="beforeUpload"
-            :multiple="false"
-            :file-list="uploadList"
-            :remove="remove"
-        >
-            <a-button :disabled="disabled">
-                <a-icon type="upload"/>
-                上传
-            </a-button>
-        </a-upload>
-        <a-progress
-            v-if="show_progress"
-            :stroke-color="{from: '#108ee9',to: '#87d068'}"
-            :percent="progress"
-        />
-        <p style="margin: 15px 0" v-show="fileUrl">
-            <a-icon type="paper-clip" style="margin-right: 5px"/>
-            <a :href="server + '/' + fileUrl" target="_blank" @click="()=>{}">下载附件</a>
-        </p>
-    </div>
-</template>
-
-<script>
-export default {
-    name: 'StdSingleFileUpload',
-    props: {
-        api: Function,
-        id: {
-            type: Number,
-            default: null
-        },
-        fileUrl: {
-            default: null
-        },
-        autoUpload: {
-            type: Boolean,
-            default: false
-        },
-        disabled: {
-            type: Boolean,
-            default: false
-        }
-    },
-    data() {
-        return {
-            uploadList: [],
-            server: process.env['VUE_APP_API_UPLOAD_ROOT'],
-            progress: 0,
-            show_progress: false,
-        }
-    },
-    model: {
-        prop: 'fileUrl',
-        event: 'changeFileUrl'
-    },
-    methods: {
-        remove() {
-            this.uploadList.shift()
-        },
-        async upload() {
-            if (this.uploadList.length) {
-                this.show_progress = true
-                this.progress = 0
-                const formData = new FormData()
-                formData.append('file', this.uploadList.shift())
-                this.visible = false
-                this.uploading = true
-                this.$message.info('正在上传附件, 请不要关闭本页')
-                let config = {
-                    onUploadProgress: (progressEvent) => {
-                        // 使用本地 progress 事件
-                        if (progressEvent.lengthComputable) {
-                            this.progress = Math.round((progressEvent.loaded / progressEvent.total) * 100)
-                        }
-                    }
-                }
-                return this.api(this.id, formData, config).then(r => {
-                    this.$emit('uploaded', r.url)
-                    this.$emit('changeFileUrl', r.url)
-                    this.uploading = false
-                    this.$message.success('上传成功')
-                }).catch(e => {
-                    this.$message.error(e.message ? e.message : '上传失败')
-                })
-            }
-        },
-        beforeUpload(file) {
-            this.uploadList = [file]
-            this.$emit('changeFileUrl', file.name)
-            // 有自动上传参数就自动上传,没有就看 id, 没有 id 就不上传
-            if (this.autoUpload ? this.autoUpload : (!!this.id)) {
-                this.upload()
-            }
-            return false
-        },
-    }
-}
-</script>
-
-<style scoped>
-
-</style>

+ 0 - 75
frontend-next/src/components/StdDataEntry/StdTransfer.vue

@@ -1,75 +0,0 @@
-<template>
-    <a-transfer
-        :data-source="dataSource"
-        :render="item=>item.title"
-        :selectedKeys="selectedKeys"
-        :targetKeys="targetKeys"
-        :titles="['可添加', '已添加']"
-        @change="handleChange"
-        @selectChange="handleSelectChange"
-    />
-</template>
-
-<script>
-const mockData = []
-for (let i = 0; i < 20; i++) {
-    mockData.push({
-        key: i.toString(),
-        title: `content${i + 1}`,
-        description: `description of content${i + 1}`
-    })
-}
-export default {
-    name: 'StdTransfer',
-    props: {
-        api: Function,
-        dataKey: String,
-        target: String
-    },
-    model: {
-        prop: 'target',
-        event: 'changeTarget'
-    },
-    data() {
-        return {
-            targetKeys: [],
-            selectedKeys: [],
-            dataSource: []
-        }
-    },
-    created() {
-        this.targetKeys = this.target.split(',')
-        if (this.api) {
-            this.api().then(r => {
-                const dataSource = []
-                r[this.dataKey ? this.dataKey : 'data'].forEach(v => {
-                    dataSource.push({
-                        key: v.id.toString(),
-                        title: `${v.title}`,
-                        description: `${v.description}`
-                    })
-                })
-                this.dataSource = dataSource
-            })
-        }
-    },
-    watch: {
-        targetKeys() {
-            this.$emit('changeTarget', this.targetKeys.toString())
-        }
-    },
-    methods: {
-        handleChange(nextTargetKeys) {
-            this.targetKeys = nextTargetKeys
-        },
-        handleSelectChange(sourceSelectedKeys, targetSelectedKeys) {
-            this.selectedKeys = [...sourceSelectedKeys, ...targetSelectedKeys]
-
-        },
-    }
-}
-</script>
-
-<style scoped>
-
-</style>

+ 0 - 266
frontend-next/src/components/StdDataEntry/StdUpload.vue

@@ -1,266 +0,0 @@
-<template>
-    <div v-if="type==='img'">
-        <a-upload
-            :before-upload="beforeUpload"
-            :show-upload-list="false"
-            class="avatar-uploader"
-            list-type="picture-card"
-        >
-            <img v-if="fileUrl" :src="getFileUrl()" width="100">
-            <div v-else>
-                <a-icon :type="uploading ? 'loading' : 'plus'"/>
-                <div class="ant-upload-text">
-                    上传图片
-                </div>
-            </div>
-        </a-upload>
-
-        <a-modal
-            v-if="crop"
-            v-model="visible"
-            cancelText="取消上传"
-            class="cropper"
-            okText="裁切"
-            title="图片裁切"
-            @cancel="visible=false;$emit('changeFileUrl', orig)"
-            @ok="handleCropSuccess"
-        >
-            <div class="vue-cropper" v-if="fileUrl.substring(0,5) === 'data:'">
-                <VueCropper
-                    ref="cropper"
-                    :autoCrop="true"
-                    :autoCropHeight="cropOptions.autoCropHeight"
-                    :autoCropWidth="cropOptions.autoCropWidth"
-                    :fixed="cropOptions.fixed"
-                    :fixedNumber="cropOptions.fixedNumber"
-                    :img="getFileUrl()"
-                    outputType="png"
-                />
-            </div>
-            <div style="margin: 10px 0">
-                <a-button @click="handleSingleUpload">不剪裁</a-button>
-            </div>
-        </a-modal>
-    </div>
-
-    <div v-else-if="type==='file'">
-        <std-single-file-upload
-            :file-url="fileUrl"
-            :id="id"
-            :api="api"
-            :auto-upload="autoUpload"
-            @changeFileUrl="url => {$emit('changeFileUrl', url)}"
-            @uploaded="url => {$emit('uploaded', url)}"
-            :disabled="disabled"
-            ref="single-file"
-        />
-    </div>
-
-    <div v-else-if="type==='multi-file'">
-        <std-multi-files-upload
-            :file-list="M_list"
-            :id="id"
-            :api="api"
-            :auto-upload="autoUpload"
-            :api_delete="api_delete"
-            @changeFileUrl="url => {$emit('changeFileUrl', url)}"
-            @uploaded="url => {$emit('uploaded', url)}"
-            :disabled="disabled"
-            ref="multi-file"
-        />
-    </div>
-
-</template>
-
-<script>
-import Vue from 'vue'
-import VueCropper from 'vue-cropper'
-import StdSingleFileUpload from '@/components/StdDataEntry/StdSingleFileUpload'
-import StdMultiFilesUpload from '@/components/StdDataEntry/StdMultiFilesUpload'
-import {v4 as uuidv4} from 'uuid'
-
-Vue.use(VueCropper)
-
-export default {
-    name: 'StdUpload',
-    components: {StdMultiFilesUpload, StdSingleFileUpload},
-    props: {
-        id: {
-            type: Number,
-            default: null
-        },
-        api: Function,
-        api_delete: {
-            type: Function,
-            default: null
-        },
-        fileUrl: {
-            default: ''
-        },
-        autoUpload: {
-            type: Boolean,
-            default: false
-        },
-        type: {
-            default: 'img',
-            validator: value => {
-                return ['img', 'file', 'multi-file'].indexOf(value) !== -1
-            }
-        },
-        crop: {
-            type: Boolean,
-            default: false
-        },
-        cropOptions: {
-            type: Object,
-            default: () => {
-                return {
-                    fixed: true,
-                    autoCropWidth: 200,
-                    autoCropHeight: 200,
-                }
-            }
-        },
-        list: {
-            default: null
-        },
-        disabled: {
-            type: Boolean,
-            default: false
-        }
-    },
-    data() {
-        return {
-            uploading: false,
-            orig: '',
-            visible: false,
-            fileList: [],
-            M_list: this.list,
-            server: process.env['VUE_APP_API_UPLOAD_ROOT']
-        }
-    },
-    created() {
-        this.orig = this.fileUrl
-    },
-    model: {
-        prop: 'fileUrl',
-        event: 'changeFileUrl'
-    },
-    watch: {
-        list() {
-            this.M_list = this.list
-        }
-    },
-    methods: {
-        getFileUrl() {
-            return this.fileUrl.substring(0, 5) === 'data:' ? this.fileUrl :
-                this.server + '/' + this.fileUrl
-        },
-        async upload() {
-            if (this.type === 'multi-file') {
-                return await this.$refs['multi-file'].upload()
-            }
-            if (this.orig && this.fileUrl !== this.orig) {
-                return this.handleSingleUpload()
-            }
-            if (this.$refs['single-file']) {
-                return await this.$refs['single-file'].upload()
-            }
-        },
-        handleSingleUpload() {
-            const formData = new FormData()
-            formData.append('file', this.fileList[0])
-            this.visible = false
-            this.uploading = true
-            this.$message.info('正在上传附件, 请不要关闭本页')
-
-            return this.api(this.id, formData).then(r => {
-                this.$emit('uploaded', r.url)
-                this.$emit('changeFileUrl', r.url)
-                this.uploading = false
-                this.$message.success('上传成功')
-                this.orig = r.url
-            })
-
-        },
-        beforeUpload(file) {
-            // 赋予新值之前做个备份 emm 生气了哼!!!
-            this.orig = this.fileUrl ? this.fileUrl : 'orig_is_empty'
-            this.fileList = [file]
-            if (this.type === 'img') {
-                this.visible = true
-                const r = new FileReader()
-                r.readAsDataURL(file)
-                r.onload = e => {
-                    file.thumbUrl = e.target.result
-                    this.$emit('changeFileUrl', e.target.result)
-                }
-                if (this.autoUpload) {
-                    this.handleSingleUpload()
-                    return false
-                }
-            } else {
-                this.$emit('changeFileUrl', file.name)
-            }
-            return false
-        },
-        afterCropUpload(file) {
-            this.visible = true
-            const r = new FileReader()
-            r.readAsDataURL(file)
-            r.onload = e => {
-                file.thumbUrl = e.target.result
-                this.$emit('changeFileUrl', e.target.result)
-            }
-            this.fileList = [file]
-            this.$nextTick(() => {
-                this.handleSingleUpload()
-            })
-        },
-        handleCropSuccess() {
-            this.$refs.cropper.getCropBlob((data) => {
-                let file = new window.File([data], uuidv4() + '.png', {type: data.type})
-                this.afterCropUpload(file)
-                this.visible = false
-            })
-        },
-        remove(r) {
-            this.fileList = this.fileList.filter(value => {
-                return value !== r
-            })
-        },
-    }
-}
-</script>
-
-<style lang="less" scoped>
-.upload-picture-btn {
-    font-size: 20px;
-    color: #999999;
-}
-
-.cropper {
-    .ant-modal-body {
-        min-height: 256px;
-    }
-}
-
-.vue-cropper {
-    min-height: 200px;
-    background-image: unset;
-}
-
-.img-preview {
-    float: left;
-    border: 1px solid #8e8e904d;
-    border-radius: 5px;
-    margin: 5px;
-    padding: 5px;
-
-    img {
-        height: 90px;
-        width: 90px;
-        object-fit: cover;
-    }
-}
-</style>

+ 0 - 390
frontend-next/src/language/translations.json

@@ -1,390 +0,0 @@
-{
-    "zh_TW": {
-        "404 Not Found": "404 未找到頁面",
-        "About": "關於",
-        "Action": "操作",
-        "Add Directive Below": "在下面新增指令",
-        "Add Location": "新增 Location",
-        "Add Site": "新增站點",
-        "Advance Mode": "高階模式",
-        "Are you sure you want to destroy?": "您确定要删除?",
-        "Are you sure you want to remove this directive?": "您確定要刪除這條指令?",
-        "Are you sure you want to restore?": "您确定要恢復?",
-        "Auto-renewal disabled for %{name}": "已關閉 %{name} 自動續簽",
-        "Auto-renewal enabled for %{name}": "已啟用 %{name} 自動續簽",
-        "Back": "返回",
-        "Base information": "基本訊息",
-        "Basic Mode": "基本模式",
-        "Build with": "構建基於",
-        "Cancel": "取消",
-        "Certificate has expired": "此憑證已過期",
-        "Certificate is valid": "此憑證有效",
-        "Certificate Status": "憑證狀態",
-        "Comments": "註釋",
-        "Configuration Name": "配置名稱",
-        "Configurations": "配置",
-        "Configure SSL": "配置 SSL",
-        "Content": "內容",
-        "CPU Status": "中央處理器狀態",
-        "CPU:": "中央處理器:",
-        "Create Another": "再創建一個",
-        "Created at": "建立時間",
-        "Dashboard": "儀表盤",
-        "Database (Optional, default: database)": "資料庫 (可選,預設: database)",
-        "Delete ID: %{id}": "刪除 ID: %{id}",
-        "Destroy": "删除",
-        "Detected version update, this page will refresh.": "檢測到版本更新,頁面將會重新整理。",
-        "Development Mode": "開發模式",
-        "Directive": "指令",
-        "Directives": "指令",
-        "Disable auto-renewal failed for %{name}": "關閉 %{name} 自動續簽失敗",
-        "Disabled": "禁用",
-        "Disabled successfully": "禁用成功",
-        "Disk IO": "磁碟 IO",
-        "Domain Config Created Successfully": "域名配置文件創建成功",
-        "Edit": "编辑",
-        "Edit %{n}": "編輯 %{n}",
-        "Edit Configuration": "編輯配置",
-        "Edit Site": "編輯站點",
-        "Email (*)": "郵箱 (*)",
-        "Enable auto-renewal failed for %{name}": "啟用 %{name} 自動續簽失敗",
-        "Enable failed": "啟用失敗",
-        "Enable TLS": "啟用 TLS",
-        "Enabled": "啟用",
-        "Enabled successfully": "啟用成功",
-        "Encrypt website with Let's Encrypt": "用 Let's Encrypt 對網站進行加密",
-        "Expiration Date: %{date}": "過期時間: %{date}",
-        "Failed to disable %{msg}": "禁用失敗 %{msg}",
-        "Failed to enable %{msg}": "啟用失敗 %{msg}",
-        "File Not Found": "未找到檔案",
-        "Finished": "完成",
-        "Getting the certificate, please wait...": "正在獲取憑證,請稍等...",
-        "Home": "首頁",
-        "Install": "安裝",
-        "Intermediate Certification Authorities: %{issuer}": "中級憑證頒發機構: %{issuer}",
-        "Invalid E-mail!": "無效的郵箱!",
-        "Leave blank for no change": "留空表示不修改",
-        "License": {
-            "Project": "開源軟體授權條款"
-        },
-        "Load Averages:": "系統負載:",
-        "Location": "Location",
-        "Locations": "Locations",
-        "Login": "登入",
-        "Login successful": "登入成功",
-        "Logout successful": "登出成功",
-        "Make sure you have configured a reverse proxy for .well-known\n            directory to HTTPChallengePort (default: 9180) before getting the certificate.": "在獲取憑證前,請確保配置檔案中已將 .well-known 目錄反向代理到 HTTPChallengePort (預設: 9180)",
-        "Manage Configs": "配置管理",
-        "Manage Sites": "網站管理",
-        "Manage Users": "使用者管理",
-        "Memory": "記憶體",
-        "Memory and Storage": "記憶體和存儲",
-        "Modify Config": "修改配置",
-        "Name": "名稱",
-        "Network": "網路",
-        "Network Statistics": "網路統計",
-        "Network Total Receive": "下載流量",
-        "Network Total Send": "上傳流量",
-        "Next": "下一步",
-        "No": "取消",
-        "No, I'm rethink": "再想想",
-        "Not Found": "找不到頁面",
-        "Not Valid Before: %{date}": "此前無效: %{date}",
-        "Note: The server_name in the current configuration must be the domain name you need to get the\n            certificate.": "注意:當前配置中的 server_name 必須為需要申請憑證的域名。",
-        "OK": "確定",
-        "OS:": "作業系統:",
-        "Params": "參數",
-        "Password": "密碼",
-        "Password (*)": "密碼 (*)",
-        "Path": "路徑",
-        "Please input your E-mail!": "請輸入您的郵箱!",
-        "Please input your password!": "請輸入您的密碼!",
-        "Please input your username!": "請輸入您的使用者名稱!",
-        "Project Team": "專案團隊",
-        "Reads": "讀",
-        "Receive": "下載",
-        "Restore": "恢復",
-        "Save": "儲存",
-        "Save Directive": "儲存指令",
-        "Save error %{msg}": "儲存錯誤 %{msg}",
-        "Saved successfully": "儲存成功",
-        "Send": "上傳",
-        "Server error": "伺服器錯誤",
-        "Server Info": "伺服器資訊",
-        "server_name not found in directives": "未在指令集合中找到 server_name",
-        "server_name parameter is required": "必須為 server_name 指令指明參數",
-        "server_name parameters more than one": "server_name 指令包含多個參數",
-        "Single Directive": "單行指令",
-        "Sites List": "站點列表",
-        "Status": "狀態",
-        "Storage": "儲存",
-        "Subject Name: %{name}": "主體名稱: %{name}",
-        "Swap": "交換空間",
-        "System message": "系統訊息",
-        "Terminal": "終端",
-        "The certificate for the domain will be checked every hour,\n            and will be renewed if it has been more than 1 month since it was last issued.": "系統將會每小時檢測一次該域名憑證,若距離上次簽發已超過1個月,則將自動續簽。<br/>如果您之前沒有憑證,請先點選「從 Let's Encrypt 獲取憑證」。",
-        "The filename cannot contain the following characters: %{c}": "檔名不能包含以下字元: %{c}",
-        "Updated at": "修改時間",
-        "Uptime:": "執行時間:",
-        "Username": "使用者名稱",
-        "Username (*)": "使用者名稱 (*)",
-        "Warning": "警告",
-        "Writes": "寫",
-        "Yes": "是的",
-        "Yes, I'm sure": "是的"
-    },
-    "en": {
-        "404 Not Found": "404 Not Found",
-        "About": "About",
-        "Action": "Action",
-        "Add Directive Below": "Add Directive Below",
-        "Add Location": "Add Location",
-        "Add Site": "Add Site",
-        "Advance Mode": "Advance Mode",
-        "Are you sure you want to remove this directive?": "Are you sure you want to remove this directive?",
-        "Auto-renewal disabled for %{name}": "Auto-renewal disabled for %{name}",
-        "Auto-renewal enabled for %{name}": "Auto-renewal enabled for %{name}",
-        "Back": "Back",
-        "Base information": "Base information",
-        "Basic Mode": "Basic Mode",
-        "Build with": "Build with",
-        "Cancel": "Cancel",
-        "Certificate has expired": "Certificate has expired",
-        "Certificate is valid": "Certificate is valid",
-        "Certificate Status": "Certificate Status",
-        "Comments": "Comments",
-        "Configuration Name": "Configuration Name",
-        "Configurations": "Configurations",
-        "Configure SSL": "Configure SSL",
-        "Content": "Content",
-        "CPU Status": "CPU Status",
-        "CPU:": "CPU:",
-        "Create Another": "Create Another",
-        "Created at": "Created at",
-        "Dashboard": "Dashboard",
-        "Database (Optional, default: database)": "Database (Optional, default: database)",
-        "Development Mode": "Development Mode",
-        "Directive": "Directive",
-        "Directives": "Directives",
-        "Disable auto-renewal failed for %{name}": "Disable auto-renewal failed for %{name}",
-        "Disabled": "Disabled",
-        "Disabled successfully": "Disabled successfully",
-        "Disk IO": "Disk IO",
-        "Domain Config Created Successfully": "Domain Config Created Successfully",
-        "Edit %{n}": "Edit %{n}",
-        "Edit Configuration": "Edit Configuration",
-        "Edit Site": "Edit Site",
-        "Email (*)": "Email (*)",
-        "Enable auto-renewal failed for %{name}": "Enable auto-renewal failed for %{name}",
-        "Enable failed": "Enable failed",
-        "Enable TLS": "Enable TLS",
-        "Enabled": "Enabled",
-        "Enabled successfully": "Enabled successfully",
-        "Encrypt website with Let's Encrypt": "Encrypt website with Let's Encrypt",
-        "Expiration Date: %{date}": "Expiration Date: %{date}",
-        "Failed to disable %{msg}": "Failed to disable %{msg}",
-        "Failed to enable %{msg}": "Failed to enable %{msg}",
-        "File Not Found": "File Not Found",
-        "Finished": "Finished",
-        "Getting the certificate, please wait...": "Getting the certificate, please wait...",
-        "Home": "Home",
-        "Install": "Install",
-        "Intermediate Certification Authorities: %{issuer}": "Intermediate Certification Authorities: %{issuer}",
-        "Invalid E-mail!": "Invalid E-mail!",
-        "Leave blank for no change": "Leave blank for no change",
-        "Load Averages:": "Load Averages:",
-        "Location": "Location",
-        "Locations": "Locations",
-        "Login": "Login",
-        "Login successful": "Login successful",
-        "Logout successful": "Logout successful",
-        "Make sure you have configured a reverse proxy for .well-known directory to HTTPChallengePort (default: 9180) before getting the certificate.": "Make sure you have configured a reverse proxy for .well-known directory to HTTPChallengePort (default: 9180) before getting the certificate.",
-        "Manage Configs": "Manage Configs",
-        "Manage Sites": "Manage Sites",
-        "Manage Users": "Manage Users",
-        "Memory": "Memory",
-        "Memory and Storage": "Memory and Storage",
-        "Modify Config": "Modify Config",
-        "Name": "Name",
-        "Network": "Network",
-        "Network Statistics": "Network Statistics",
-        "Network Total Receive": "Network Total Receive",
-        "Network Total Send": "Network Total Send",
-        "Next": "Next",
-        "No": "No",
-        "Not Found": "Not Found",
-        "Not Valid Before: %{date}": "Not Valid Before: %{date}",
-        "Note: The server_name in the current configuration must be the domain name you need to get the certificate.": "Note: The server_name in the current configuration must be the domain name you need to get the certificate.",
-        "OS:": "OS:",
-        "Params": "Params",
-        "Password": "Password",
-        "Password (*)": "Password (*)",
-        "Path": "Path",
-        "Please input your E-mail!": "Please input your E-mail!",
-        "Please input your password!": "Please input your password!",
-        "Please input your username!": "Please input your username!",
-        "Project Team": "Project Team",
-        "Reads": "Reads",
-        "Receive": "Receive",
-        "Save": "Save",
-        "Save Directive": "Save Directive",
-        "Save error %{msg}": "Save error %{msg}",
-        "Saved successfully": "Saved successfully",
-        "Send": "Send",
-        "Server error": "Server error",
-        "Server Info": "Server Info",
-        "server_name not found in directives": "server_name not found in directives",
-        "server_name parameter is required": "server_name parameter is required",
-        "server_name parameters more than one": "server_name parameters more than one",
-        "Single Directive": "Single Directive",
-        "Sites List": "Sites List",
-        "Status": "Status",
-        "Storage": "Storage",
-        "Subject Name: %{name}": "Subject Name: %{name}",
-        "Swap": "Swap",
-        "Terminal": "Terminal",
-        "The certificate for the domain will be checked every hour, and will be renewed if it has been more than 1 month since it was last issued.": "The certificate for the domain will be checked every hour, and will be renewed if it has been more than 1 month since it was last issued.",
-        "The filename cannot contain the following characters: %{c}": "The filename cannot contain the following characters: %{c}",
-        "Updated at": "Updated at",
-        "Uptime:": "Uptime:",
-        "Username": "Username",
-        "Username (*)": "Username (*)",
-        "Warning": "Warning",
-        "Writes": "Writes",
-        "Yes": "Yes",
-        "License": {
-            "Project": "License"
-        }
-    },
-    "zh_CN": {
-        "404 Not Found": "404 未找到页面",
-        "About": "关于",
-        "Action": "操作",
-        "Add Directive Below": "在下面添加指令",
-        "Add Location": "添加 Location",
-        "Add Site": "添加站点",
-        "Advance Mode": "高级模式",
-        "Are you sure you want to destroy?": "您确定要删除?",
-        "Are you sure you want to remove this directive?": "您确定要删除这条指令?",
-        "Are you sure you want to restore?": "您确定要反删除?",
-        "Auto-renewal disabled for %{name}": "成功关闭 %{name} 自动续签",
-        "Auto-renewal enabled for %{name}": "成功启用 %{name} 自动续签",
-        "Back": "返回",
-        "Base information": "基本信息",
-        "Basic Mode": "基本模式",
-        "Build with": "构建基于",
-        "Cancel": "取消",
-        "Certificate has expired": "此证书已过期",
-        "Certificate is valid": "此证书有效",
-        "Certificate Status": "证书状态",
-        "Comments": "注释",
-        "Configuration Name": "配置名称",
-        "Configurations": "配置",
-        "Configure SSL": "配置 SSL",
-        "Content": "内容",
-        "CPU Status": "CPU 状态",
-        "Create Another": "再创建一个",
-        "Created at": "创建时间",
-        "Dashboard": "仪表盘",
-        "Database (Optional, default: database)": "数据库 (可选,默认: database)",
-        "Delete ID: %{id}": "删除 ID: %{id}",
-        "Destroy": "删除",
-        "Detected version update, this page will refresh.": "检测到版本更新,页面将会刷新。",
-        "Development Mode": "开发模式",
-        "Directive": "指令",
-        "Directives": "指令",
-        "Disable auto-renewal failed for %{name}": "关闭 %{name} 自动续签失败",
-        "Disabled": "禁用",
-        "Disabled successfully": "禁用成功",
-        "Disk IO": "磁盘 IO",
-        "Domain Config Created Successfully": "域名配置文件创建成功",
-        "Edit": "编辑",
-        "Edit %{n}": "编辑 %{n}",
-        "Edit Configuration": "编辑配置",
-        "Edit Site": "编辑站点",
-        "Email (*)": "邮箱 (*)",
-        "Enable auto-renewal failed for %{name}": "启用 %{name} 自动续签失败",
-        "Enable failed": "启用失败",
-        "Enable TLS": "启用 TLS",
-        "Enabled": "启用",
-        "Enabled successfully": "启用成功",
-        "Encrypt website with Let's Encrypt": "用 Let's Encrypt 对网站进行加密",
-        "Expiration Date: %{date}": "过期时间: %{date}",
-        "Failed to disable %{msg}": "禁用失败 %{msg}",
-        "Failed to enable %{msg}": "启用失败 %{msg}",
-        "File Not Found": "未找到文件",
-        "Finished": "完成",
-        "Getting the certificate, please wait...": "正在获取证书,请稍等...",
-        "Home": "首页",
-        "Install": "安装",
-        "Intermediate Certification Authorities: %{issuer}": "中级证书颁发机构: %{issuer}",
-        "Invalid E-mail!": "无效的邮箱!",
-        "Leave blank for no change": "留空表示不修改",
-        "License": {
-            "Project": "开源许可"
-        },
-        "Load Averages:": "系统负载:",
-        "Location": "Location",
-        "Locations": "Locations",
-        "Login": "登录",
-        "Login successful": "登录成功",
-        "Logout successful": "登出成功",
-        "Make sure you have configured a reverse proxy for .well-known\n            directory to HTTPChallengePort (default: 9180) before getting the certificate.": "在获取签发证书前,请确保配置文件中已将 .well-known 目录反向代理到 HTTPChallengePort (默认: 9180)",
-        "Manage Configs": "配置管理",
-        "Manage Sites": "网站管理",
-        "Manage Users": "用户管理",
-        "Memory": "内存",
-        "Memory and Storage": "内存与存储",
-        "Modify Config": "修改配置文件",
-        "Name": "名称",
-        "Network": "网络",
-        "Network Statistics": "流量统计",
-        "Network Total Receive": "下载流量",
-        "Network Total Send": "上传流量",
-        "Next": "下一步",
-        "No": "取消",
-        "No, I'm rethink": "再想想",
-        "Not Found": "找不到页面",
-        "Not Valid Before: %{date}": "此前无效: %{date}",
-        "Note: The server_name in the current configuration must be the domain name\n            you need to get the certificate.": "注意:当前配置中的 server_name 必须为需要申请证书的域名。",
-        "OK": "确定",
-        "Params": "参数",
-        "Password": "密码",
-        "Password (*)": "密码 (*)",
-        "Path": "路径",
-        "Please input your E-mail!": "请输入您的邮箱!",
-        "Please input your password!": "请输入您的密码!",
-        "Please input your username!": "请输入您的用户名!",
-        "Project Team": "项目团队",
-        "Reads": "读",
-        "Receive": "下载",
-        "Restore": "反删除",
-        "Save": "保存",
-        "Save Directive": "保存指令",
-        "Save error %{msg}": "保存错误 %{msg}",
-        "Saved successfully": "保存成功",
-        "Send": "上传",
-        "Server error": "服务器错误",
-        "Server Info": "服务器信息",
-        "server_name not found in directives": "未在指令集合中找到 server_name",
-        "server_name parameter is required": "必须为 server_name 指令指明参数",
-        "server_name parameters more than one": "server_name 指令包含多个参数",
-        "Single Directive": "单行指令",
-        "Sites List": "站点列表",
-        "Status": "状态",
-        "Storage": "存储",
-        "Subject Name: %{name}": "主体名称: %{name}",
-        "System message": "系统消息",
-        "Terminal": "终端",
-        "The certificate for the domain will be checked every hour,\n            and will be renewed if it has been more than 1 month since it was last issued.": "系统将会每小时检测一次该域名证书,若距离上次签发已超过1个月,则将自动续签。",
-        "The filename cannot contain the following characters: %{c}": "文件名不能包含以下字符: %{c}",
-        "Updated at": "修改时间",
-        "Uptime:": "运行时间:",
-        "Username": "用户名",
-        "Username (*)": "用户名 (*)",
-        "Warning": "警告",
-        "Writes": "写",
-        "Yes": "是的",
-        "Yes, I'm sure": "是的"
-    }
-}

+ 0 - 639
frontend-next/src/language/zh_CN/app.po

@@ -1,639 +0,0 @@
-msgid ""
-msgstr ""
-"Project-Id-Version: \n"
-"POT-Creation-Date: \n"
-"PO-Revision-Date: \n"
-"Last-Translator: Hintay <hintay@me.com>\n"
-"Language-Team: none\n"
-"Language: zh_CN\n"
-"MIME-Version: 1.0\n"
-"Content-Type: text/plain; charset=UTF-8\n"
-"Content-Transfer-Encoding: 8bit\n"
-"Generated-By: easygettext\n"
-"X-Generator: Poedit 2.2\n"
-
-#: src/router/index.js:107
-msgid "404 Not Found"
-msgstr "404 未找到页面"
-
-#: src/router/index.js:85
-msgid "About"
-msgstr "关于"
-
-#: src/views/config/Config.vue:18 src/views/domain/DomainList.vue:29
-#: src/views/user/User.vue:35
-msgid "Action"
-msgstr "操作"
-
-#: src/views/domain/ngx_conf/directive/DirectiveAdd.vue:89
-msgid "Add Directive Below"
-msgstr "在下面添加指令"
-
-#: src/views/domain/ngx_conf/LocationEditor.vue:70
-#: src/views/domain/ngx_conf/LocationEditor.vue:120
-msgid "Add Location"
-msgstr "添加 Location"
-
-#: src/router/index.js:47 src/views/domain/DomainAdd.vue:31
-msgid "Add Site"
-msgstr "添加站点"
-
-#: src/views/domain/DomainEdit.vue:57
-msgid "Advance Mode"
-msgstr "高级模式"
-
-#: src/components/StdDataDisplay/StdTable.vue:68
-msgid "Are you sure you want to destroy?"
-msgstr "您确定要删除?"
-
-#: src/views/domain/ngx_conf/directive/DirectiveEditor.vue:46
-msgid "Are you sure you want to remove this directive?"
-msgstr "您确定要删除这条指令?"
-
-#: src/components/StdDataDisplay/StdTable.vue:44
-msgid "Are you sure you want to restore?"
-msgstr "您确定要反删除?"
-
-#: src/views/domain/cert/IssueCert.vue:82
-msgid "Auto-renewal disabled for %{name}"
-msgstr "成功关闭 %{name} 自动续签"
-
-#: src/views/domain/cert/IssueCert.vue:76
-msgid "Auto-renewal enabled for %{name}"
-msgstr "成功启用 %{name} 自动续签"
-
-#: src/views/domain/DomainEdit.vue:41
-msgid "Back"
-msgstr "返回"
-
-#: src/views/domain/DomainAdd.vue:41
-msgid "Base information"
-msgstr "基本信息"
-
-#: src/views/domain/DomainEdit.vue:60
-msgid "Basic Mode"
-msgstr "基本模式"
-
-#: src/views/other/About.vue:11
-msgid "Build with"
-msgstr "构建基于"
-
-#: src/views/config/ConfigEdit.vue:5
-msgid "Cancel"
-msgstr "取消"
-
-#: src/views/domain/cert/CertInfo.vue:12 src/views/domain/cert/CertInfo.vue:2
-msgid "Certificate has expired"
-msgstr "此证书已过期"
-
-#: src/views/domain/cert/CertInfo.vue:16 src/views/domain/cert/CertInfo.vue:2
-msgid "Certificate is valid"
-msgstr "此证书有效"
-
-#: src/views/domain/cert/CertInfo.vue:2
-msgid "Certificate Status"
-msgstr "证书状态"
-
-#: src/views/domain/ngx_conf/LocationEditor.vue:33
-#: src/views/domain/ngx_conf/LocationEditor.vue:77
-#: src/views/domain/ngx_conf/NgxConfigEditor.vue:65
-#: src/views/domain/ngx_conf/directive/DirectiveEditor.vue:67
-msgid "Comments"
-msgstr "注释"
-
-#: src/views/domain/DomainAdd.vue:55
-msgid "Configuration Name"
-msgstr "配置名称"
-
-#: src/views/config/Config.vue:8
-msgid "Configurations"
-msgstr "配置"
-
-#: src/views/domain/DomainAdd.vue:44
-msgid "Configure SSL"
-msgstr "配置 SSL"
-
-#: src/views/domain/ngx_conf/LocationEditor.vue:54
-#: src/views/domain/ngx_conf/LocationEditor.vue:100
-msgid "Content"
-msgstr "内容"
-
-#: src/views/dashboard/DashBoard.vue:211
-msgid "CPU Status"
-msgstr "CPU 状态"
-
-#: src/views/dashboard/DashBoard.vue:22
-msgid "CPU:"
-msgstr ""
-
-#: src/views/domain/DomainAdd.vue:46 src/views/domain/DomainAdd.vue:5
-msgid "Create Another"
-msgstr "再创建一个"
-
-#: src/views/user/User.vue:23
-msgid "Created at"
-msgstr "创建时间"
-
-#: src/router/index.js:19
-msgid "Dashboard"
-msgstr "仪表盘"
-
-#: src/views/other/Install.vue:105
-msgid "Database (Optional, default: database)"
-msgstr "数据库 (可选,默认: database)"
-
-#: src/components/StdDataDisplay/StdTable.vue:142
-msgid "Delete ID: %{id}"
-msgstr "删除 ID: %{id}"
-
-#: src/components/StdDataDisplay/StdTable.vue:74
-msgid "Destroy"
-msgstr "删除"
-
-#: src/router/index.js:133
-msgid "Detected version update, this page will refresh."
-msgstr "检测到版本更新,页面将会刷新。"
-
-#: src/views/other/About.vue:11
-msgid "Development Mode"
-msgstr "开发模式"
-
-#: src/views/domain/ngx_conf/directive/DirectiveAdd.vue:57
-msgid "Directive"
-msgstr "指令"
-
-#: src/views/domain/ngx_conf/directive/DirectiveEditor.vue:20
-msgid "Directives"
-msgstr "指令"
-
-#: src/views/domain/cert/IssueCert.vue:84
-msgid "Disable auto-renewal failed for %{name}"
-msgstr "关闭 %{name} 自动续签失败"
-
-#: src/views/domain/DomainEdit.vue:43 src/views/domain/DomainList.vue:17
-#: src/views/domain/DomainList.vue:32
-msgid "Disabled"
-msgstr "禁用"
-
-#: src/views/domain/DomainEdit.vue:106 src/views/domain/DomainList.vue:55
-msgid "Disabled successfully"
-msgstr "禁用成功"
-
-#: src/views/dashboard/DashBoard.vue:289
-msgid "Disk IO"
-msgstr "磁盘 IO"
-
-#: src/views/domain/DomainAdd.vue:125
-msgid "Domain Config Created Successfully"
-msgstr "域名配置文件创建成功"
-
-#: src/components/StdDataDisplay/StdTable.vue:38
-msgid "Edit"
-msgstr "编辑"
-
-#: src/views/domain/DomainEdit.vue:27
-msgid "Edit %{n}"
-msgstr "编辑 %{n}"
-
-#: src/router/index.js:69 src/views/config/ConfigEdit.vue:15
-msgid "Edit Configuration"
-msgstr "编辑配置"
-
-#: src/router/index.js:51
-msgid "Edit Site"
-msgstr "编辑站点"
-
-#: src/views/other/Install.vue:31
-msgid "Email (*)"
-msgstr "邮箱 (*)"
-
-#: src/views/domain/cert/IssueCert.vue:78
-msgid "Enable auto-renewal failed for %{name}"
-msgstr "启用 %{name} 自动续签失败"
-
-#: src/views/domain/DomainAdd.vue:39
-msgid "Enable failed"
-msgstr "启用失败"
-
-#: src/views/domain/ngx_conf/NgxConfigEditor.vue:20
-msgid "Enable TLS"
-msgstr "启用 TLS"
-
-#: src/views/domain/DomainEdit.vue:34 src/views/domain/DomainEdit.vue:75
-#: src/views/domain/DomainList.vue:16 src/views/domain/DomainList.vue:36
-msgid "Enabled"
-msgstr "启用"
-
-#: src/views/domain/DomainAdd.vue:36 src/views/domain/DomainEdit.vue:98
-#: src/views/domain/DomainList.vue:46
-msgid "Enabled successfully"
-msgstr "启用成功"
-
-#: src/views/domain/cert/IssueCert.vue:36
-msgid "Encrypt website with Let's Encrypt"
-msgstr "用 Let's Encrypt 对网站进行加密"
-
-#: src/views/domain/cert/CertInfo.vue:5
-msgid "Expiration Date: %{date}"
-msgstr "过期时间: %{date}"
-
-#: src/views/domain/DomainEdit.vue:109 src/views/domain/DomainList.vue:59
-msgid "Failed to disable %{msg}"
-msgstr "禁用失败 %{msg}"
-
-#: src/views/domain/DomainEdit.vue:101 src/views/domain/DomainList.vue:50
-msgid "Failed to enable %{msg}"
-msgstr "启用失败 %{msg}"
-
-#: src/views/other/Error.vue:9
-msgid "File Not Found"
-msgstr "未找到文件"
-
-#: src/views/domain/DomainAdd.vue:47
-msgid "Finished"
-msgstr "完成"
-
-#: src/views/domain/methods.js:6
-msgid "Getting the certificate, please wait..."
-msgstr "正在获取证书,请稍等..."
-
-#: src/router/index.js:12
-msgid "Home"
-msgstr "首页"
-
-#: src/router/index.js:95 src/views/other/Install.vue:51
-msgid "Install"
-msgstr "安装"
-
-#: src/views/domain/cert/CertInfo.vue:3
-msgid "Intermediate Certification Authorities: %{issuer}"
-msgstr "中级证书颁发机构: %{issuer}"
-
-#: src/views/other/Install.vue:46
-msgid "Invalid E-mail!"
-msgstr "无效的邮箱!"
-
-#: src/views/user/User.vue:19
-msgid "Leave blank for no change"
-msgstr "留空表示不修改"
-
-#: src/views/other/About.vue:16
-msgctxt "Project"
-msgid "License"
-msgstr "开源许可"
-
-#: src/views/dashboard/DashBoard.vue:10
-msgid "Load Averages:"
-msgstr "系统负载:"
-
-#: src/views/domain/ngx_conf/LocationEditor.vue:26
-msgid "Location"
-msgstr "Location"
-
-#: src/views/domain/ngx_conf/LocationEditor.vue:16
-msgid "Locations"
-msgstr "Locations"
-
-#: src/router/index.js:101 src/views/other/Login.vue:25
-msgid "Login"
-msgstr "登录"
-
-#: src/views/other/Login.vue:30
-msgid "Login successful"
-msgstr "登录成功"
-
-#: src/layouts/HeaderLayout.vue:9
-msgid "Logout successful"
-msgstr "登出成功"
-
-#: src/views/domain/cert/IssueCert.vue:23
-msgid ""
-"Make sure you have configured a reverse proxy for .well-known\n"
-"            directory to HTTPChallengePort (default: 9180) before getting "
-"the certificate."
-msgstr ""
-"在获取签发证书前,请确保配置文件中已将 .well-known 目录反向代理到 "
-"HTTPChallengePort (默认: 9180)"
-
-#: src/router/index.js:60
-msgid "Manage Configs"
-msgstr "配置管理"
-
-#: src/router/index.js:35 src/views/domain/DomainList.vue:12
-msgid "Manage Sites"
-msgstr "网站管理"
-
-#: src/router/index.js:27
-msgid "Manage Users"
-msgstr "用户管理"
-
-#: src/views/dashboard/DashBoard.vue:105
-msgid "Memory"
-msgstr "内存"
-
-#: src/views/dashboard/DashBoard.vue:93
-msgid "Memory and Storage"
-msgstr "内存与存储"
-
-#: src/views/domain/DomainAdd.vue:43 src/views/domain/DomainAdd.vue:2
-msgid "Modify Config"
-msgstr "修改配置文件"
-
-#: src/views/config/Config.vue:5 src/views/domain/DomainList.vue:5
-msgid "Name"
-msgstr "名称"
-
-#: src/views/dashboard/DashBoard.vue:238
-msgid "Network"
-msgstr "网络"
-
-#: src/views/dashboard/DashBoard.vue:163
-msgid "Network Statistics"
-msgstr "流量统计"
-
-#: src/views/dashboard/DashBoard.vue:172
-msgid "Network Total Receive"
-msgstr "下载流量"
-
-#: src/views/dashboard/DashBoard.vue:181
-msgid "Network Total Send"
-msgstr "上传流量"
-
-#: src/views/domain/DomainAdd.vue:36
-msgid "Next"
-msgstr "下一步"
-
-#: src/views/domain/ngx_conf/directive/DirectiveEditor.vue:48
-msgid "No"
-msgstr "取消"
-
-#: src/components/StdDataDisplay/StdTable.vue:62
-msgid "No, I'm rethink"
-msgstr "再想想"
-
-#: src/router/index.js:113
-msgid "Not Found"
-msgstr "找不到页面"
-
-#: src/views/domain/cert/CertInfo.vue:7
-msgid "Not Valid Before: %{date}"
-msgstr "此前无效: %{date}"
-
-#: src/views/domain/cert/IssueCert.vue:15
-msgid ""
-"Note: The server_name in the current configuration must be the domain name\n"
-"            you need to get the certificate."
-msgstr "注意:当前配置中的 server_name 必须为需要申请证书的域名。"
-
-#: src/router/index.js:137
-msgid "OK"
-msgstr "确定"
-
-#: src/views/dashboard/DashBoard.vue:16
-msgid "OS:"
-msgstr ""
-
-#: src/views/domain/ngx_conf/directive/DirectiveAdd.vue:63
-msgid "Params"
-msgstr "参数"
-
-#: src/views/other/Login.vue:56 src/views/user/User.vue:13
-msgid "Password"
-msgstr "密码"
-
-#: src/views/other/Install.vue:83
-msgid "Password (*)"
-msgstr "密码 (*)"
-
-#: src/views/domain/ngx_conf/LocationEditor.vue:42
-#: src/views/domain/ngx_conf/LocationEditor.vue:88
-msgid "Path"
-msgstr "路径"
-
-#: src/views/other/Install.vue:50
-msgid "Please input your E-mail!"
-msgstr "请输入您的邮箱!"
-
-#: src/views/other/Install.vue:96 src/views/other/Login.vue:69
-msgid "Please input your password!"
-msgstr "请输入您的密码!"
-
-#: src/views/other/Install.vue:73 src/views/other/Login.vue:46
-msgid "Please input your username!"
-msgstr "请输入您的用户名!"
-
-#: src/views/other/About.vue:8
-msgid "Project Team"
-msgstr "项目团队"
-
-#: src/views/dashboard/DashBoard.vue:61 src/views/dashboard/DashBoard.vue:312
-msgid "Reads"
-msgstr "读"
-
-#: src/views/dashboard/DashBoard.vue:51 src/views/dashboard/DashBoard.vue:247
-msgid "Receive"
-msgstr "下载"
-
-#: src/components/StdDataDisplay/StdTable.vue:50
-msgid "Restore"
-msgstr "反删除"
-
-#: src/views/config/ConfigEdit.vue:6 src/views/domain/DomainEdit.vue:44
-msgid "Save"
-msgstr "保存"
-
-#: src/views/domain/ngx_conf/directive/DirectiveAdd.vue:101
-msgid "Save Directive"
-msgstr "保存指令"
-
-#: src/views/config/ConfigEdit.vue:47 src/views/domain/DomainAdd.vue:43
-#: src/views/domain/DomainEdit.vue:90
-msgid "Save error %{msg}"
-msgstr "保存错误 %{msg}"
-
-#: src/views/config/ConfigEdit.vue:44 src/views/domain/DomainAdd.vue:33
-#: src/views/domain/DomainEdit.vue:85
-msgid "Saved successfully"
-msgstr "保存成功"
-
-#: src/views/dashboard/DashBoard.vue:54 src/views/dashboard/DashBoard.vue:261
-msgid "Send"
-msgstr "上传"
-
-#: src/components/StdDataDisplay/StdTable.vue:145
-#: src/views/config/ConfigEdit.vue:35 src/views/domain/DomainEdit.vue:52
-#: src/views/domain/DomainEdit.vue:63 src/views/domain/DomainEdit.vue:71
-#: src/views/other/Login.vue:35
-msgid "Server error"
-msgstr "服务器错误"
-
-#: src/views/dashboard/DashBoard.vue:38
-msgid "Server Info"
-msgstr "服务器信息"
-
-#: src/views/domain/cert/IssueCert.vue:33
-msgid "server_name not found in directives"
-msgstr "未在指令集合中找到 server_name"
-
-#: src/views/domain/DomainAdd.vue:20 src/views/domain/DomainAdd.vue:11
-#: src/views/domain/DomainAdd.vue:1 src/views/domain/cert/IssueCert.vue:6
-#: src/views/domain/cert/IssueCert.vue:1
-msgid "server_name parameter is required"
-msgstr "必须为 server_name 指令指明参数"
-
-#: src/views/domain/cert/IssueCert.vue:9 src/views/domain/cert/IssueCert.vue:4
-#: src/views/domain/cert/IssueCert.vue:39
-msgid "server_name parameters more than one"
-msgstr "server_name 指令包含多个参数"
-
-#: src/views/domain/ngx_conf/directive/DirectiveAdd.vue:30
-msgid "Single Directive"
-msgstr "单行指令"
-
-#: src/router/index.js:43
-msgid "Sites List"
-msgstr "站点列表"
-
-#: src/views/domain/DomainList.vue:11
-msgid "Status"
-msgstr "状态"
-
-#: src/views/dashboard/DashBoard.vue:137
-msgid "Storage"
-msgstr "存储"
-
-#: src/views/domain/cert/CertInfo.vue:4
-msgid "Subject Name: %{name}"
-msgstr "主体名称: %{name}"
-
-#: src/views/dashboard/DashBoard.vue:121
-msgid "Swap"
-msgstr ""
-
-#: src/router/index.js:132
-msgid "System message"
-msgstr "系统消息"
-
-#: src/router/index.js:77 src/views/pty/Terminal.vue:12
-msgid "Terminal"
-msgstr "终端"
-
-#: src/views/domain/cert/IssueCert.vue:19
-msgid ""
-"The certificate for the domain will be checked every hour,\n"
-"            and will be renewed if it has been more than 1 month since it "
-"was last issued."
-msgstr ""
-"系统将会每小时检测一次该域名证书,若距离上次签发已超过1个月,则将自动续签。"
-
-#: src/views/other/Install.vue:120
-msgid "The filename cannot contain the following characters: %{c}"
-msgstr "文件名不能包含以下字符: %{c}"
-
-#: src/views/config/Config.vue:11 src/views/domain/DomainList.vue:22
-#: src/views/user/User.vue:29
-msgid "Updated at"
-msgstr "修改时间"
-
-#: src/views/dashboard/DashBoard.vue:6
-msgid "Uptime:"
-msgstr "运行时间:"
-
-#: src/views/other/Login.vue:33 src/views/user/User.vue:5
-msgid "Username"
-msgstr "用户名"
-
-#: src/views/other/Install.vue:60
-msgid "Username (*)"
-msgstr "用户名 (*)"
-
-#: src/views/domain/DomainAdd.vue:74 src/views/domain/cert/IssueCert.vue:49
-msgid "Warning"
-msgstr "警告"
-
-#: src/views/dashboard/DashBoard.vue:58 src/views/dashboard/DashBoard.vue:298
-msgid "Writes"
-msgstr "写"
-
-#: src/views/domain/ngx_conf/directive/DirectiveEditor.vue:47
-msgid "Yes"
-msgstr "是的"
-
-#: src/components/StdDataDisplay/StdTable.vue:56
-msgid "Yes, I'm sure"
-msgstr "是的"
-
-#~ msgid "Certificate Auto-renewal"
-#~ msgstr "证书自动续签"
-
-#~ msgid "Certificate Path (ssl_certificate)"
-#~ msgstr "TLS 证书路径 (ssl_certificate)"
-
-#~ msgid "HTTP Listen Port"
-#~ msgstr "HTTP 监听端口"
-
-#~ msgid "HTTPS Listen Port"
-#~ msgstr "HTTPS 监听端口"
-
-#~ msgid "Index (index)"
-#~ msgstr "网站首页 (index)"
-
-#~ msgid "Private Key Path (ssl_certificate_key)"
-#~ msgstr "私钥路径 (ssl_certificate_key)"
-
-#~ msgid "Root Directory (root)"
-#~ msgstr "网站根目录 (root)"
-
-#~ msgid "Server Names (server_name)"
-#~ msgstr "网站域名 (server_name)"
-
-#~ msgid ""
-#~ "The certificate for the domain will be checked every hour, and will be "
-#~ "renewed if it has been more than 1 month since it was last issued.<br/>If "
-#~ "you do not have a certificate before, please click \"Getting Certificate "
-#~ "from Let's Encrypt\" first."
-#~ msgstr ""
-#~ "系统将会每小时检测一次该域名证书,若距离上次签发已超过1个月,则将自动续"
-#~ "签。<br/>如果您之前没有证书,请先点击 \"从 Let's Encrypt 获取证书\"。"
-
-#~ msgid "Do you want to change the template to support the TLS?"
-#~ msgstr "你想要改变模板以支持 TLS 吗?"
-
-#~ msgid "Edit Configuration File"
-#~ msgstr "编辑配置文件"
-
-#~ msgid "Getting Certificate from Let's Encrypt"
-#~ msgstr "从 Let's Encrypt 获取证书"
-
-#~ msgid "Skip"
-#~ msgstr "跳过"
-
-#~ msgid ""
-#~ "The following values will only take effect if you have the corresponding "
-#~ "fields in your configuration file. The configuration filename cannot be "
-#~ "changed after it has been created."
-#~ msgstr ""
-#~ "只有在您的配置文件中有相应字段时,下列的配置才能生效。配置文件名称创建后不"
-#~ "可修改。"
-
-#~ msgid "This feature is not available in demo."
-#~ msgstr "该功能在 Demo 中不可用。"
-
-#~ msgid "This operation will lose the custom configuration."
-#~ msgstr "该操作将会丢失自定义配置。"
-
-#~ msgid ""
-#~ "Add site here first, then you can configure TLS on the domain edit page."
-#~ msgstr "在这里添加站点,完成后可进入编辑页面配置 TLS。"
-
-#~ msgid "Server Status"
-#~ msgstr "服务器状态"
-
-#~ msgid "Used: %{u}, Cached: %{c}, Free: %{f}, Physical Memory: %{p}"
-#~ msgstr "已使用: %{u}, 缓存: %{c}, 空闲: %{f}, 物理内存: %{p}"
-
-#~ msgid "Used: %{used} / Total: %{total}"
-#~ msgstr "已使用: %{used} / 总共: %{total}"
-
-#~ msgid "CPU"
-#~ msgstr "CPU"

+ 0 - 642
frontend-next/src/language/zh_TW/app.po

@@ -1,642 +0,0 @@
-#
-msgid ""
-msgstr ""
-"Project-Id-Version: \n"
-"POT-Creation-Date: \n"
-"PO-Revision-Date: \n"
-"Last-Translator: Hintay <hintay@me.com>\n"
-"Language-Team: none\n"
-"Language: zh_TW\n"
-"MIME-Version: 1.0\n"
-"Content-Type: text/plain; charset=UTF-8\n"
-"Content-Transfer-Encoding: 8bit\n"
-"Generated-By: easygettext\n"
-"X-Generator: Poedit 2.2\n"
-
-#: src/router/index.js:107
-msgid "404 Not Found"
-msgstr "404 未找到頁面"
-
-#: src/router/index.js:85
-msgid "About"
-msgstr "關於"
-
-#: src/views/config/Config.vue:18 src/views/domain/DomainList.vue:29
-#: src/views/user/User.vue:35
-msgid "Action"
-msgstr "操作"
-
-#: src/views/domain/ngx_conf/directive/DirectiveAdd.vue:89
-msgid "Add Directive Below"
-msgstr "在下面新增指令"
-
-#: src/views/domain/ngx_conf/LocationEditor.vue:70
-#: src/views/domain/ngx_conf/LocationEditor.vue:120
-msgid "Add Location"
-msgstr "新增 Location"
-
-#: src/router/index.js:47 src/views/domain/DomainAdd.vue:32
-msgid "Add Site"
-msgstr "新增站點"
-
-#: src/views/domain/DomainEdit.vue:57
-msgid "Advance Mode"
-msgstr "高階模式"
-
-#: src/components/StdDataDisplay/StdTable.vue:68
-msgid "Are you sure you want to destroy?"
-msgstr "您确定要删除?"
-
-#: src/views/domain/ngx_conf/directive/DirectiveEditor.vue:46
-msgid "Are you sure you want to remove this directive?"
-msgstr "您確定要刪除這條指令?"
-
-#: src/components/StdDataDisplay/StdTable.vue:44
-msgid "Are you sure you want to restore?"
-msgstr "您确定要恢復?"
-
-#: src/views/domain/cert/IssueCert.vue:82
-msgid "Auto-renewal disabled for %{name}"
-msgstr "已關閉 %{name} 自動續簽"
-
-#: src/views/domain/cert/IssueCert.vue:76
-msgid "Auto-renewal enabled for %{name}"
-msgstr "已啟用 %{name} 自動續簽"
-
-#: src/views/domain/DomainEdit.vue:41
-msgid "Back"
-msgstr "返回"
-
-#: src/views/domain/DomainAdd.vue:42
-msgid "Base information"
-msgstr "基本訊息"
-
-#: src/views/domain/DomainEdit.vue:60
-msgid "Basic Mode"
-msgstr "基本模式"
-
-#: src/views/other/About.vue:11
-msgid "Build with"
-msgstr "構建基於"
-
-#: src/views/config/ConfigEdit.vue:5
-msgid "Cancel"
-msgstr "取消"
-
-#: src/views/domain/cert/CertInfo.vue:12 src/views/domain/cert/CertInfo.vue:2
-msgid "Certificate has expired"
-msgstr "此憑證已過期"
-
-#: src/views/domain/cert/CertInfo.vue:16 src/views/domain/cert/CertInfo.vue:2
-msgid "Certificate is valid"
-msgstr "此憑證有效"
-
-#: src/views/domain/cert/CertInfo.vue:2
-msgid "Certificate Status"
-msgstr "憑證狀態"
-
-#: src/views/domain/ngx_conf/LocationEditor.vue:33
-#: src/views/domain/ngx_conf/LocationEditor.vue:77
-#: src/views/domain/ngx_conf/NgxConfigEditor.vue:52
-#: src/views/domain/ngx_conf/directive/DirectiveEditor.vue:67
-msgid "Comments"
-msgstr "註釋"
-
-#: src/views/domain/DomainAdd.vue:56
-msgid "Configuration Name"
-msgstr "配置名稱"
-
-#: src/views/config/Config.vue:8
-msgid "Configurations"
-msgstr "配置"
-
-#: src/views/domain/DomainAdd.vue:45
-msgid "Configure SSL"
-msgstr "配置 SSL"
-
-#: src/views/domain/ngx_conf/LocationEditor.vue:54
-#: src/views/domain/ngx_conf/LocationEditor.vue:100
-msgid "Content"
-msgstr "內容"
-
-#: src/views/dashboard/DashBoard.vue:211
-msgid "CPU Status"
-msgstr "中央處理器狀態"
-
-#: src/views/dashboard/DashBoard.vue:22
-msgid "CPU:"
-msgstr "中央處理器:"
-
-#: src/views/domain/DomainAdd.vue:50 src/views/domain/DomainAdd.vue:5
-msgid "Create Another"
-msgstr "再創建一個"
-
-#: src/views/user/User.vue:23
-msgid "Created at"
-msgstr "建立時間"
-
-#: src/router/index.js:19
-msgid "Dashboard"
-msgstr "儀表盤"
-
-#: src/views/other/Install.vue:105
-msgid "Database (Optional, default: database)"
-msgstr "資料庫 (可選,預設: database)"
-
-#: src/components/StdDataDisplay/StdTable.vue:142
-msgid "Delete ID: %{id}"
-msgstr "刪除 ID: %{id}"
-
-#: src/components/StdDataDisplay/StdTable.vue:74
-msgid "Destroy"
-msgstr "删除"
-
-#: src/router/index.js:133
-msgid "Detected version update, this page will refresh."
-msgstr "檢測到版本更新,頁面將會重新整理。"
-
-#: src/views/other/About.vue:11
-msgid "Development Mode"
-msgstr "開發模式"
-
-#: src/views/domain/ngx_conf/directive/DirectiveAdd.vue:57
-msgid "Directive"
-msgstr "指令"
-
-#: src/views/domain/ngx_conf/directive/DirectiveEditor.vue:20
-msgid "Directives"
-msgstr "指令"
-
-#: src/views/domain/cert/IssueCert.vue:84
-msgid "Disable auto-renewal failed for %{name}"
-msgstr "關閉 %{name} 自動續簽失敗"
-
-#: src/views/domain/DomainEdit.vue:43 src/views/domain/DomainList.vue:17
-#: src/views/domain/DomainList.vue:32
-msgid "Disabled"
-msgstr "禁用"
-
-#: src/views/domain/DomainEdit.vue:106 src/views/domain/DomainList.vue:55
-msgid "Disabled successfully"
-msgstr "禁用成功"
-
-#: src/views/dashboard/DashBoard.vue:289
-msgid "Disk IO"
-msgstr "磁碟 IO"
-
-#: src/views/domain/DomainAdd.vue:135
-msgid "Domain Config Created Successfully"
-msgstr "域名配置文件創建成功"
-
-#: src/components/StdDataDisplay/StdTable.vue:38
-msgid "Edit"
-msgstr "编辑"
-
-#: src/views/domain/DomainEdit.vue:27
-msgid "Edit %{n}"
-msgstr "編輯 %{n}"
-
-#: src/router/index.js:69 src/views/config/ConfigEdit.vue:15
-msgid "Edit Configuration"
-msgstr "編輯配置"
-
-#: src/router/index.js:51
-msgid "Edit Site"
-msgstr "編輯站點"
-
-#: src/views/other/Install.vue:31
-msgid "Email (*)"
-msgstr "郵箱 (*)"
-
-#: src/views/domain/cert/IssueCert.vue:78
-msgid "Enable auto-renewal failed for %{name}"
-msgstr "啟用 %{name} 自動續簽失敗"
-
-#: src/views/domain/DomainAdd.vue:39
-msgid "Enable failed"
-msgstr "啟用失敗"
-
-#: src/views/domain/DomainAdd.vue:94
-msgid "Enable TLS"
-msgstr "啟用 TLS"
-
-#: src/views/domain/DomainEdit.vue:34 src/views/domain/DomainEdit.vue:75
-#: src/views/domain/DomainList.vue:16 src/views/domain/DomainList.vue:36
-msgid "Enabled"
-msgstr "啟用"
-
-#: src/views/domain/DomainAdd.vue:36 src/views/domain/DomainEdit.vue:98
-#: src/views/domain/DomainList.vue:46
-msgid "Enabled successfully"
-msgstr "啟用成功"
-
-#: src/views/domain/cert/IssueCert.vue:36
-msgid "Encrypt website with Let's Encrypt"
-msgstr "用 Let's Encrypt 對網站進行加密"
-
-#: src/views/domain/cert/CertInfo.vue:5
-msgid "Expiration Date: %{date}"
-msgstr "過期時間: %{date}"
-
-#: src/views/domain/DomainEdit.vue:109 src/views/domain/DomainList.vue:59
-msgid "Failed to disable %{msg}"
-msgstr "禁用失敗 %{msg}"
-
-#: src/views/domain/DomainEdit.vue:101 src/views/domain/DomainList.vue:50
-msgid "Failed to enable %{msg}"
-msgstr "啟用失敗 %{msg}"
-
-#: src/views/other/Error.vue:9
-msgid "File Not Found"
-msgstr "未找到檔案"
-
-#: src/views/domain/DomainAdd.vue:48
-msgid "Finished"
-msgstr "完成"
-
-#: src/views/domain/methods.js:6
-msgid "Getting the certificate, please wait..."
-msgstr "正在獲取憑證,請稍等..."
-
-#: src/router/index.js:12
-msgid "Home"
-msgstr "首頁"
-
-#: src/router/index.js:95 src/views/other/Install.vue:51
-msgid "Install"
-msgstr "安裝"
-
-#: src/views/domain/cert/CertInfo.vue:3
-msgid "Intermediate Certification Authorities: %{issuer}"
-msgstr "中級憑證頒發機構: %{issuer}"
-
-#: src/views/other/Install.vue:46
-msgid "Invalid E-mail!"
-msgstr "無效的郵箱!"
-
-#: src/views/user/User.vue:19
-msgid "Leave blank for no change"
-msgstr "留空表示不修改"
-
-#: src/views/other/About.vue:16
-msgctxt "Project"
-msgid "License"
-msgstr "開源軟體授權條款"
-
-#: src/views/dashboard/DashBoard.vue:10
-msgid "Load Averages:"
-msgstr "系統負載:"
-
-#: src/views/domain/ngx_conf/LocationEditor.vue:26
-msgid "Location"
-msgstr "Location"
-
-#: src/views/domain/ngx_conf/LocationEditor.vue:16
-msgid "Locations"
-msgstr "Locations"
-
-#: src/router/index.js:101 src/views/other/Login.vue:25
-msgid "Login"
-msgstr "登入"
-
-#: src/views/other/Login.vue:30
-msgid "Login successful"
-msgstr "登入成功"
-
-#: src/layouts/HeaderLayout.vue:9
-msgid "Logout successful"
-msgstr "登出成功"
-
-#: src/views/domain/cert/IssueCert.vue:19
-msgid ""
-"Make sure you have configured a reverse proxy for .well-known\n"
-"            directory to HTTPChallengePort (default: 9180) before getting "
-"the certificate."
-msgstr ""
-"在獲取憑證前,請確保配置檔案中已將 .well-known 目錄反向代理到 "
-"HTTPChallengePort (預設: 9180)"
-
-#: src/router/index.js:60
-msgid "Manage Configs"
-msgstr "配置管理"
-
-#: src/router/index.js:35 src/views/domain/DomainList.vue:12
-msgid "Manage Sites"
-msgstr "網站管理"
-
-#: src/router/index.js:27
-msgid "Manage Users"
-msgstr "使用者管理"
-
-#: src/views/dashboard/DashBoard.vue:105
-msgid "Memory"
-msgstr "記憶體"
-
-#: src/views/dashboard/DashBoard.vue:93
-msgid "Memory and Storage"
-msgstr "記憶體和存儲"
-
-#: src/views/domain/DomainAdd.vue:47 src/views/domain/DomainAdd.vue:2
-msgid "Modify Config"
-msgstr "修改配置"
-
-#: src/views/config/Config.vue:5 src/views/domain/DomainList.vue:5
-msgid "Name"
-msgstr "名稱"
-
-#: src/views/dashboard/DashBoard.vue:238
-msgid "Network"
-msgstr "網路"
-
-#: src/views/dashboard/DashBoard.vue:163
-msgid "Network Statistics"
-msgstr "網路統計"
-
-#: src/views/dashboard/DashBoard.vue:172
-msgid "Network Total Receive"
-msgstr "下載流量"
-
-#: src/views/dashboard/DashBoard.vue:181
-msgid "Network Total Send"
-msgstr "上傳流量"
-
-#: src/views/domain/DomainAdd.vue:40
-msgid "Next"
-msgstr "下一步"
-
-#: src/views/domain/ngx_conf/directive/DirectiveEditor.vue:48
-msgid "No"
-msgstr "取消"
-
-#: src/components/StdDataDisplay/StdTable.vue:62
-msgid "No, I'm rethink"
-msgstr "再想想"
-
-#: src/router/index.js:113
-msgid "Not Found"
-msgstr "找不到頁面"
-
-#: src/views/domain/cert/CertInfo.vue:7
-msgid "Not Valid Before: %{date}"
-msgstr "此前無效: %{date}"
-
-#: src/views/domain/cert/IssueCert.vue:15
-msgid ""
-"Note: The server_name in the current configuration must be the domain name "
-"you need to get the\n"
-"            certificate."
-msgstr "注意:當前配置中的 server_name 必須為需要申請憑證的域名。"
-
-#: src/router/index.js:137
-msgid "OK"
-msgstr "確定"
-
-#: src/views/dashboard/DashBoard.vue:16
-msgid "OS:"
-msgstr "作業系統:"
-
-#: src/views/domain/ngx_conf/directive/DirectiveAdd.vue:63
-msgid "Params"
-msgstr "參數"
-
-#: src/views/other/Login.vue:56 src/views/user/User.vue:13
-msgid "Password"
-msgstr "密碼"
-
-#: src/views/other/Install.vue:83
-msgid "Password (*)"
-msgstr "密碼 (*)"
-
-#: src/views/domain/ngx_conf/LocationEditor.vue:42
-#: src/views/domain/ngx_conf/LocationEditor.vue:88
-msgid "Path"
-msgstr "路徑"
-
-#: src/views/other/Install.vue:50
-msgid "Please input your E-mail!"
-msgstr "請輸入您的郵箱!"
-
-#: src/views/other/Install.vue:96 src/views/other/Login.vue:69
-msgid "Please input your password!"
-msgstr "請輸入您的密碼!"
-
-#: src/views/other/Install.vue:73 src/views/other/Login.vue:46
-msgid "Please input your username!"
-msgstr "請輸入您的使用者名稱!"
-
-#: src/views/other/About.vue:8
-msgid "Project Team"
-msgstr "專案團隊"
-
-#: src/views/dashboard/DashBoard.vue:61 src/views/dashboard/DashBoard.vue:312
-msgid "Reads"
-msgstr "讀"
-
-#: src/views/dashboard/DashBoard.vue:51 src/views/dashboard/DashBoard.vue:247
-msgid "Receive"
-msgstr "下載"
-
-#: src/components/StdDataDisplay/StdTable.vue:50
-msgid "Restore"
-msgstr "恢復"
-
-#: src/views/config/ConfigEdit.vue:6 src/views/domain/DomainEdit.vue:44
-msgid "Save"
-msgstr "儲存"
-
-#: src/views/domain/ngx_conf/directive/DirectiveAdd.vue:101
-msgid "Save Directive"
-msgstr "儲存指令"
-
-#: src/views/config/ConfigEdit.vue:47 src/views/domain/DomainAdd.vue:43
-#: src/views/domain/DomainEdit.vue:90
-msgid "Save error %{msg}"
-msgstr "儲存錯誤 %{msg}"
-
-#: src/views/config/ConfigEdit.vue:44 src/views/domain/DomainAdd.vue:33
-#: src/views/domain/DomainEdit.vue:85
-msgid "Saved successfully"
-msgstr "儲存成功"
-
-#: src/views/dashboard/DashBoard.vue:54 src/views/dashboard/DashBoard.vue:261
-msgid "Send"
-msgstr "上傳"
-
-#: src/components/StdDataDisplay/StdTable.vue:145
-#: src/views/config/ConfigEdit.vue:35 src/views/domain/DomainEdit.vue:52
-#: src/views/domain/DomainEdit.vue:63 src/views/domain/DomainEdit.vue:71
-#: src/views/other/Login.vue:35
-msgid "Server error"
-msgstr "伺服器錯誤"
-
-#: src/views/dashboard/DashBoard.vue:38
-msgid "Server Info"
-msgstr "伺服器資訊"
-
-#: src/views/domain/cert/IssueCert.vue:33
-msgid "server_name not found in directives"
-msgstr "未在指令集合中找到 server_name"
-
-#: src/views/domain/DomainAdd.vue:20 src/views/domain/DomainAdd.vue:11
-#: src/views/domain/DomainAdd.vue:1 src/views/domain/cert/IssueCert.vue:6
-#: src/views/domain/cert/IssueCert.vue:1
-msgid "server_name parameter is required"
-msgstr "必須為 server_name 指令指明參數"
-
-#: src/views/domain/cert/IssueCert.vue:9 src/views/domain/cert/IssueCert.vue:4
-#: src/views/domain/cert/IssueCert.vue:39
-msgid "server_name parameters more than one"
-msgstr "server_name 指令包含多個參數"
-
-#: src/views/domain/ngx_conf/directive/DirectiveAdd.vue:30
-msgid "Single Directive"
-msgstr "單行指令"
-
-#: src/router/index.js:43
-msgid "Sites List"
-msgstr "站點列表"
-
-#: src/views/domain/DomainList.vue:11
-msgid "Status"
-msgstr "狀態"
-
-#: src/views/dashboard/DashBoard.vue:137
-msgid "Storage"
-msgstr "儲存"
-
-#: src/views/domain/cert/CertInfo.vue:4
-msgid "Subject Name: %{name}"
-msgstr "主體名稱: %{name}"
-
-#: src/views/dashboard/DashBoard.vue:121
-msgid "Swap"
-msgstr "交換空間"
-
-#: src/router/index.js:132
-msgid "System message"
-msgstr "系統訊息"
-
-#: src/router/index.js:77 src/views/pty/Terminal.vue:12
-msgid "Terminal"
-msgstr "終端"
-
-#: src/views/domain/cert/IssueCert.vue:17
-msgid ""
-"The certificate for the domain will be checked every hour,\n"
-"            and will be renewed if it has been more than 1 month since it "
-"was last issued."
-msgstr ""
-"系統將會每小時檢測一次該域名憑證,若距離上次簽發已超過1個月,則將自動續簽。"
-"<br/>如果您之前沒有憑證,請先點選「從 Let's Encrypt 獲取憑證」。"
-
-#: src/views/other/Install.vue:120
-msgid "The filename cannot contain the following characters: %{c}"
-msgstr "檔名不能包含以下字元: %{c}"
-
-#: src/views/config/Config.vue:11 src/views/domain/DomainList.vue:22
-#: src/views/user/User.vue:29
-msgid "Updated at"
-msgstr "修改時間"
-
-#: src/views/dashboard/DashBoard.vue:6
-msgid "Uptime:"
-msgstr "執行時間:"
-
-#: src/views/other/Login.vue:33 src/views/user/User.vue:5
-msgid "Username"
-msgstr "使用者名稱"
-
-#: src/views/other/Install.vue:60
-msgid "Username (*)"
-msgstr "使用者名稱 (*)"
-
-#: src/views/domain/DomainAdd.vue:75 src/views/domain/cert/IssueCert.vue:49
-msgid "Warning"
-msgstr "警告"
-
-#: src/views/dashboard/DashBoard.vue:58 src/views/dashboard/DashBoard.vue:298
-msgid "Writes"
-msgstr "寫"
-
-#: src/views/domain/ngx_conf/directive/DirectiveEditor.vue:47
-msgid "Yes"
-msgstr "是的"
-
-#: src/components/StdDataDisplay/StdTable.vue:56
-msgid "Yes, I'm sure"
-msgstr "是的"
-
-#~ msgid "Certificate Auto-renewal"
-#~ msgstr "證書自動續簽"
-
-#~ msgid "Certificate Path (ssl_certificate)"
-#~ msgstr "TLS 證書路徑 (ssl_certificate)"
-
-#~ msgid "HTTP Listen Port"
-#~ msgstr "HTTP 監聽埠"
-
-#~ msgid "HTTPS Listen Port"
-#~ msgstr "HTTPS 監聽埠"
-
-#~ msgid "Index (index)"
-#~ msgstr "網站首頁 (index)"
-
-#~ msgid "Private Key Path (ssl_certificate_key)"
-#~ msgstr "私鑰路徑 (ssl_certificate_key)"
-
-#~ msgid "Root Directory (root)"
-#~ msgstr "網站根目錄 (root)"
-
-#~ msgid "Server Names (server_name)"
-#~ msgstr "網站域名 (server_name)"
-
-#~ msgid ""
-#~ "The certificate for the domain will be checked every hour, and will be "
-#~ "renewed if it has been more than 1 month since it was last issued.<br/>If "
-#~ "you do not have a certificate before, please click \"Getting Certificate "
-#~ "from Let's Encrypt\" first."
-#~ msgstr ""
-#~ "系統將會每小時檢測一次該域名證書,若距離上次簽發已超過1個月,則將自動續"
-#~ "簽。<br/>如果您之前沒有證書,請先點選「從 Let's Encrypt 獲取證書」。"
-
-#~ msgid "Do you want to change the template to support the TLS?"
-#~ msgstr "你想要改變模板以支援 TLS 嗎?"
-
-#~ msgid "Edit Configuration File"
-#~ msgstr "編輯配置檔案"
-
-#~ msgid "Getting Certificate from Let's Encrypt"
-#~ msgstr "從 Let's Encrypt 獲取證書"
-
-#~ msgid "Skip"
-#~ msgstr "跳過"
-
-#~ msgid ""
-#~ "The following values will only take effect if you have the corresponding "
-#~ "fields in your configuration file. The configuration filename cannot be "
-#~ "changed after it has been created."
-#~ msgstr ""
-#~ "只有在您的配置檔案中有相應欄位時,下列的配置才能生效。配置檔名稱建立後不可"
-#~ "修改。"
-
-#~ msgid "This feature is not available in demo."
-#~ msgstr "此功能在演示中不可用。"
-
-#~ msgid "This operation will lose the custom configuration."
-#~ msgstr "該操作將會丟失自定義配置。"
-
-#~ msgid ""
-#~ "Add site here first, then you can configure TLS on the domain edit page."
-#~ msgstr "在這裡新增站點,完成後可進入編輯頁面配置 TLS。"
-
-#~ msgid "Server Status"
-#~ msgstr "伺服器狀態"
-
-#~ msgid "Used: %{u}, Cached: %{c}, Free: %{f}, Physical Memory: %{p}"
-#~ msgstr "已使用: %{u}, 快取: %{c}, 空閒: %{f}, 物理記憶體: %{p}"
-
-#~ msgid "Used: %{used} / Total: %{total}"
-#~ msgstr "已使用: %{used} / 總共: %{total}"
-
-#~ msgid "CPU"
-#~ msgstr "CPU"

+ 0 - 229
frontend-next/src/layouts/BaseLayout.vue

@@ -1,229 +0,0 @@
-<template>
-    <a-config-provider :locale="lang">
-        <a-layout style="min-height: 100%;">
-            <a-drawer
-                v-show="clientWidth<512"
-                :closable="false"
-                :visible="collapsed"
-                placement="left"
-                @close="collapsed=false"
-            >
-                <side-bar/>
-            </a-drawer>
-
-            <a-layout-sider
-                v-show="clientWidth>=512"
-                v-model="collapsed"
-                :collapsible="true"
-                :style="{zIndex: 11}"
-                theme="light"
-                class="layout-sider"
-            >
-                <side-bar/>
-            </a-layout-sider>
-
-            <a-layout>
-                <a-layout-header :style="{position: 'fixed', zIndex: 10, width:'100%'}">
-                    <header-layout @clickUnFold="collapsed=true"/>
-                </a-layout-header>
-
-                <a-layout-content>
-                    <page-header/>
-                    <div class="router-view">
-                        <router-view/>
-                    </div>
-                </a-layout-content>
-
-                <a-layout-footer>
-                    <footer-layout/>
-                </a-layout-footer>
-            </a-layout>
-
-        </a-layout>
-    </a-config-provider>
-</template>
-
-<script>
-import HeaderLayout from './HeaderLayout.vue'
-import SideBar from './SideBar.vue'
-import FooterLayout from './FooterLayout.vue'
-import PageHeader from '@/components/PageHeader/PageHeader.vue'
-import zh_CN from 'ant-design-vue/es/locale/zh_CN'
-import zh_TW from 'ant-design-vue/es/locale/zh_TW'
-import en_US from 'ant-design-vue/es/locale/en_US'
-
-export default {
-    name: 'BaseLayout',
-    data() {
-        return {
-            collapsed: this.collapse(),
-            clientWidth: document.body.clientWidth,
-        }
-    },
-    mounted() {
-        window.onresize = () => {
-            this.collapsed = this.collapse()
-            this.clientWidth = this.getClientWidth()
-        }
-    },
-    components: {
-        SideBar,
-        PageHeader,
-        HeaderLayout,
-        FooterLayout
-    },
-    methods: {
-        getClientWidth() {
-            return document.body.clientWidth
-        },
-        collapse() {
-            return !(this.getClientWidth() > 768 || this.getClientWidth() < 512)
-        }
-    },
-    computed: {
-        lang: {
-            get() {
-                switch (this.$language.current) {
-                    case 'zh_CN':
-                        return zh_CN
-                    case 'zh_TW':
-                        return zh_TW
-                    default:
-                        return en_US
-                }
-            }
-        }
-    }
-}
-</script>
-<style lang="less">
-.layout-sider .sidebar {
-    //position: fixed;
-    //width: 200px;
-
-    ul.ant-menu-inline.ant-menu-root {
-        height: calc(100vh - 120px);
-        overflow-y: auto;
-        overflow-x: hidden;
-
-        .ant-menu-item {
-            width: unset;
-        }
-    }
-
-    ul.ant-menu-inline-collapsed {
-        height: calc(100vh - 200px);
-        overflow-y: auto;
-        overflow-x: hidden;
-    }
-}
-</style>
-
-<style lang="less">
-@dark: ~"(prefers-color-scheme: dark)";
-
-body {
-    overflow: unset !important;
-}
-
-@media @dark {
-    h1, h2, h3, h4, h5, h6, p {
-        color: #fafafa !important;
-    }
-
-}
-
-.ant-layout-header {
-    background-color: #fff;
-    @media @dark {
-        background-color: #1f1f1f !important;
-    }
-}
-
-.ant-card {
-    @media @dark {
-        background-color: #1f1f1f !important;
-    }
-}
-
-.ant-layout-sider {
-    background-color: #ffffff;
-    @media @dark {
-        background-color: rgb(20, 20, 20) !important;
-        .ant-layout-sider-trigger {
-            background-color: rgb(20, 20, 20) !important;
-        }
-
-        .ant-menu {
-            border-right: 0 !important;
-        }
-    }
-
-    &.ant-layout-sider-has-trigger {
-        padding-bottom: 0;
-    }
-
-    box-shadow: 2px 0 8px rgba(29, 35, 41, 0.05);
-}
-
-.ant-drawer-body {
-    .sidebar .logo {
-        box-shadow: 0 1px 0 0 #e8e8e8;
-    }
-
-    .ant-menu-inline .ant-menu-selected::after, .ant-menu-inline .ant-menu-item-selected::after {
-        border-right: 0 !important;
-    }
-}
-
-@media @dark {
-    .ant-checkbox-indeterminate {
-        .ant-checkbox-inner {
-            background-color: transparent !important;
-        }
-    }
-}
-
-.ant-layout-header {
-    padding: 0 !important;
-}
-
-.ant-table-small {
-    font-size: 13px;
-}
-
-.ant-card-bordered {
-
-}
-
-.header-notice-wrapper .ant-tabs-content {
-    max-height: 250px;
-}
-
-.header-notice-wrapper .ant-tabs-tabpane-active {
-    overflow-y: scroll;
-}
-
-.ant-layout-footer {
-    @media (max-width: 320px) {
-        padding: 10px;
-    }
-}
-
-.ant-layout-content {
-    margin: 64px 0;
-    min-height: auto;
-
-    .router-view {
-        padding: 20px;
-        @media (max-width: 512px) {
-            padding: 20px 0;
-        }
-        position: relative;
-    }
-}
-
-.ant-layout-footer {
-    text-align: center;
-}
-</style>

+ 0 - 13
frontend-next/src/layouts/BaseRouterView.vue

@@ -1,13 +0,0 @@
-<template>
-    <router-view/>
-</template>
-
-<script>
-export default {
-    name: 'BaseRouterView'
-}
-</script>
-
-<style scoped>
-
-</style>

+ 0 - 22
frontend-next/src/layouts/FooterLayout.vue

@@ -1,22 +0,0 @@
-<template>
-    <div class="footer center">
-        Copyright © 2020 - {{ thisYear }} Nginx UI
-    </div>
-</template>
-
-<script>
-export default {
-    name: 'FooterComponent',
-    data() {
-        return {
-            thisYear: new Date().getFullYear()
-        }
-    }
-}
-</script>
-
-<style scoped>
-.footer {
-
-}
-</style>

+ 0 - 85
frontend-next/src/layouts/HeaderLayout.vue

@@ -1,85 +0,0 @@
-<script setup lang="ts">
-import SetLanguage from '@/components/SetLanguage/SetLanguage.vue'
-import gettext from '@/gettext'
-import {message} from 'ant-design-vue'
-import auth from '@/api/auth'
-import {HomeOutlined, LogoutOutlined, MenuUnfoldOutlined} from '@ant-design/icons-vue'
-import {useRouter} from 'vue-router'
-
-const {$gettext} = gettext
-
-const router = useRouter()
-
-function logout() {
-    auth.logout().then(() => {
-        message.success($gettext('Logout successful'))
-    }).then(() => {
-        router.push('/login')
-    })
-}
-
-</script>
-
-<template>
-    <div class="header">
-        <div class="tool">
-            <MenuUnfoldOutlined @click="$emit('clickUnFold')"/>
-        </div>
-
-        <div class="user-wrapper">
-            <set-language class="set_lang"/>
-
-            <a href="/">
-                <HomeOutlined/>
-            </a>
-
-            <a @click="logout" style="margin-left: 20px">
-                <LogoutOutlined/>
-            </a>
-        </div>
-    </div>
-</template>
-
-
-<style lang="less" scoped>
-.header {
-    height: 64px;
-    padding: 0 20px 0 0;
-    background: transparent;
-    box-shadow: 0 0 20px 0 rgba(0, 0, 0, 0.05);
-    position: fixed;
-    width: 100%;
-
-    a {
-        color: #000000;
-    }
-}
-
-@media (prefers-color-scheme: dark) {
-    .header {
-        box-shadow: 1px 1px 0 0 #404040;
-
-        a {
-            color: #fafafa;
-        }
-    }
-}
-
-.tool {
-    position: fixed;
-    left: 20px;
-    @media (min-width: 512px) {
-        display: none;
-    }
-}
-
-.user-wrapper {
-    position: fixed;
-    right: 20px;
-}
-
-.set_lang {
-    display: inline;
-    margin-right: 25px;
-}
-</style>

+ 0 - 33
frontend-next/src/layouts/Loading.vue

@@ -1,33 +0,0 @@
-<template>
-    <div
-        v-show="loading"
-        class="loading"
-    >
-        <div class="wrapper center">
-            <a-spin>
-                <a-icon
-                    slot="indicator"
-                    spin
-                    style="font-size: 30px"
-                    type="loading"
-                />
-            </a-spin>
-        </div>
-    </div>
-</template>
-
-<script>
-export default {
-    name: 'Loading',
-    props: {
-        loading: {
-            type: [Boolean, String],
-            default: false
-        }
-    }
-}
-</script>
-
-<style scoped>
-
-</style>

+ 0 - 112
frontend-next/src/layouts/SideBar.vue

@@ -1,112 +0,0 @@
-<script setup lang="ts">
-import Logo from '@/components/Logo/Logo.vue'
-import {routes} from '@/routes'
-import {useRoute} from 'vue-router'
-import {computed, ref, watch} from 'vue'
-
-const route = useRoute()
-
-let openKeys = [openSub()]
-
-const selectedKey = ref([route.name])
-
-function openSub() {
-    let path = route.path
-    let lastSepIndex = path.lastIndexOf('/')
-    return path.substring(1, lastSepIndex)
-}
-
-watch(route, () => {
-    selectedKey.value = [route.name]
-    const sub = openSub()
-    const p = openKeys.indexOf(sub)
-    if (p === -1) openKeys.push(sub)
-})
-
-const sidebars = computed(() => {
-    return routes[0]['children']
-})
-
-interface meta {
-    icon: any
-    hiddenInSidebar: boolean
-}
-
-interface sidebar {
-    path: string
-    name: Function
-    meta: meta,
-    children: sidebar[]
-}
-
-const visible = computed(() => {
-
-    const res: sidebar[] = [];
-
-    (sidebars.value || []).forEach((s) => {
-        if (s.meta && s.meta.hiddenInSidebar) {
-            return
-        }
-        const t: sidebar = {
-            path: s.path,
-            name: s.name,
-            meta: s.meta as meta,
-            children: []
-        };
-
-        (s.children || []).forEach((c: any) => {
-            if (c.meta && c.meta.hiddenInSidebar) {
-                return
-            }
-            t.children.push((c as sidebar))
-        })
-        res.push(t)
-    })
-
-
-    return res
-})
-</script>
-
-<template>
-    <div class="sidebar">
-        <logo/>
-        <a-menu
-            :openKeys="openKeys"
-            mode="inline"
-            v-model:openKeys="openKeys"
-            v-model:selectedKeys="selectedKey"
-        >
-            <template v-for="sidebar in visible">
-                <a-menu-item v-if="sidebar.children.length===0 || sidebar.meta.hideChildren === true"
-                             :key="sidebar.name"
-                             @click="$router.push('/'+sidebar.path).catch(() => {})">
-                    <component :is="sidebar.meta.icon"/>
-                    <span>{{ sidebar.name() }}</span>
-                </a-menu-item>
-
-                <a-sub-menu v-else :key="sidebar.path">
-                    <template #title>
-                        <component :is="sidebar.meta.icon"/>
-                        <span>{{ sidebar.name() }}</span>
-                    </template>
-                    <a-menu-item v-for="child in sidebar.children" :key="child.name">
-                        <router-link :to="'/'+sidebar.path+'/'+child.path">
-                            {{ child.name() }}
-                        </router-link>
-                    </a-menu-item>
-                </a-sub-menu>
-            </template>
-        </a-menu>
-    </div>
-</template>
-
-<style lang="less">
-.ant-layout-sider-collapsed .logo {
-    overflow: hidden;
-}
-
-.ant-menu-inline, .ant-menu-vertical, .ant-menu-vertical-left {
-    border-right: unset;
-}
-</style>

+ 0 - 47
frontend-next/src/views/config/Config.vue

@@ -1,47 +0,0 @@
-<script setup lang="ts">
-import StdTable from '@/components/StdDataDisplay/StdTable.vue'
-import gettext from '@/gettext'
-import config from '@/api/config'
-import {datetime} from '@/components/StdDataDisplay/StdTableTransformer'
-
-const {$gettext} = gettext
-
-const api = config
-
-const columns = [{
-    title: () => $gettext('Name'),
-    dataIndex: 'name',
-    sorter: true,
-    pithy: true
-}, {
-    title: () => $gettext('Updated at'),
-    dataIndex: 'modify',
-    customRender: datetime,
-    datetime: true,
-    sorter: true,
-    pithy: true
-}, {
-    title: () => $gettext('Action'),
-    dataIndex: 'action'
-}]
-</script>
-<template>
-    <a-card :title="$gettext('Configurations')">
-        <std-table
-            :api="api"
-            :columns="columns"
-            :deletable="false"
-            :disable_search="true"
-            row-key="name"
-            @clickEdit="r => {
-                $router.push({
-                    path: '/config/' + r
-                })
-            }"
-        />
-    </a-card>
-</template>
-
-<style scoped>
-
-</style>

+ 0 - 66
frontend-next/src/views/config/ConfigEdit.vue

@@ -1,66 +0,0 @@
-<script setup lang="ts">
-import FooterToolBar from '@/components/FooterToolbar/FooterToolBar.vue'
-import gettext from '@/gettext'
-import {useRoute} from 'vue-router'
-import {ref} from 'vue'
-import config from '@/api/config'
-import {message} from 'ant-design-vue'
-import CodeEditor from '@/components/CodeEditor/CodeEditor.vue'
-
-const {$gettext, interpolate} = gettext
-const route = useRoute()
-
-const name = ref(route.params.name)
-
-const configText = ref('')
-
-function init() {
-    if (name.value) {
-        config.get(name.value).then(r => {
-            configText.value = r.config
-        }).catch(r => {
-            message.error(r.message ?? $gettext('Server error'))
-        })
-    } else {
-        configText.value = ''
-    }
-}
-
-init()
-
-function save() {
-    config.save(name.value, {content: configText.value}).then(r => {
-        configText.value = r.config
-        message.success($gettext('Saved successfully'))
-    }).catch(r => {
-        message.error(interpolate($gettext('Save error %{msg}'), {msg: r.message ?? ''}))
-    })
-}
-
-</script>
-
-
-<template>
-    <a-card :title="$gettext('Edit Configuration')">
-        <code-editor v-model:content="configText"/>
-        <footer-tool-bar>
-            <a-space>
-                <a-button @click="$router.go(-1)">
-                    <translate>Cancel</translate>
-                </a-button>
-                <a-button type="primary" @click="save">
-                    <translate>Save</translate>
-                </a-button>
-            </a-space>
-        </footer-tool-bar>
-    </a-card>
-</template>
-
-<style lang="less" scoped>
-.ant-card {
-    margin: 10px;
-    @media (max-width: 512px) {
-        margin: 10px 0;
-    }
-}
-</style>

+ 0 - 291
frontend-next/src/views/dashboard/DashBoard.vue

@@ -1,291 +0,0 @@
-<script setup lang="ts">
-import AreaChart from '@/components/Chart/AreaChart.vue'
-
-import RadialBarChart from '@/components/Chart/RadialBarChart.vue'
-import {useGettext} from 'vue3-gettext'
-import {onMounted, onUnmounted, reactive, ref} from 'vue'
-import analytic from '@/api/analytic'
-import ws from '@/lib/websocket'
-import {bytesToSize} from '@/lib/helper'
-
-const {$gettext} = useGettext()
-
-const websocket = ws('/api/analytic')
-websocket.onmessage = wsOnMessage
-
-const host = reactive({})
-const cpu = ref('0.0')
-const cpu_info = reactive([])
-const cpu_analytic_series = reactive([{name: 'User', data: <any>[]}, {name: 'Total', data: <any>[]}])
-const net_analytic = reactive([{name: $gettext('Receive'), data: <any>[]},
-    {name: $gettext('Send'), data: <any>[]}])
-const disk_io_analytic = reactive([{name: $gettext('Writes'), data: <any>[]},
-    {name: $gettext('Writes'), data: <any>[]}])
-const memory = reactive({})
-const disk = reactive({})
-const disk_io = reactive({writes: 0, reads: 0})
-const uptime = ref('')
-const loadavg = reactive({})
-const net = reactive({recv: 0, sent: 0, last_recv: 0, last_sent: 0})
-
-const net_formatter = (bytes: number) => {
-    return bytesToSize(bytes) + '/s'
-}
-
-interface Usage {
-    x: number
-    y: number
-}
-
-onMounted(() => {
-    analytic.init().then(r => {
-        Object.assign(host, r.host)
-        Object.assign(cpu_info, r.cpu.info)
-        Object.assign(memory, r.memory)
-        Object.assign(disk, r.disk)
-
-        net.last_recv = r.network.init.bytesRecv
-        net.last_sent = r.network.init.bytesSent
-        r.cpu.user.forEach((u: Usage) => {
-            cpu_analytic_series[0].data.push([u.x, u.y.toFixed(2)])
-        })
-        r.cpu.total.forEach((u: Usage) => {
-            cpu_analytic_series[1].data.push([u.x, u.y.toFixed(2)])
-        })
-        r.network.bytesRecv.forEach((u: Usage) => {
-            net_analytic[0].data.push([u.x, u.y.toFixed(2)])
-        })
-        r.network.bytesSent.forEach((u: Usage) => {
-            net_analytic[1].data.push([u.x, u.y.toFixed(2)])
-        })
-        disk_io_analytic[0].data = disk_io_analytic[0].data.concat(r.disk_io.writes)
-        disk_io_analytic[1].data = disk_io_analytic[1].data.concat(r.disk_io.reads)
-
-    })
-})
-
-onUnmounted(() => {
-    websocket.close()
-})
-
-function wsOnMessage(m: { data: any }) {
-    const r = JSON.parse(m.data)
-
-    const cpu_usage = r.cpu.system + r.cpu.user
-    cpu.value = cpu_usage.toFixed(2)
-
-    const time = new Date().getTime()
-
-    cpu_analytic_series[0].data.push([time, r.cpu.user.toFixed(2)])
-    cpu_analytic_series[1].data.push([time, cpu.value])
-
-    if (cpu_analytic_series[0].data.length > 100) {
-        cpu_analytic_series[0].data.shift()
-        cpu_analytic_series[1].data.shift()
-    }
-
-    // mem
-    Object.assign(memory, r.memory)
-
-    // disk
-    Object.assign(disk, r.disk)
-    disk_io.writes = r.disk.writes.y
-    disk_io.reads = r.disk.reads.y
-
-    // uptime
-    let _uptime = Math.floor(r.uptime)
-    let uptime_days = Math.floor(_uptime / 86400)
-    _uptime -= uptime_days * 86400
-    let uptime_hours = Math.floor(_uptime / 3600)
-    _uptime -= uptime_hours * 3600
-    uptime.value = uptime_days + 'd ' + uptime_hours + 'h ' + Math.floor(_uptime / 60) + 'm'
-
-    // loadavg
-    Object.assign(loadavg, r.loadavg)
-
-    // network
-    Object.assign(net, r.network)
-    net.recv = r.network.bytesRecv - net.last_recv
-    net.sent = r.network.bytesSent - net.last_sent
-    net.last_recv = r.network.bytesRecv
-    net.last_sent = r.network.bytesSent
-
-    net_analytic[0].data.push([time, net.recv])
-    net_analytic[1].data.push([time, net.sent])
-
-    if (net_analytic[0].data.length > 100) {
-        net_analytic[0].data.shift()
-        net_analytic[1].data.shift()
-    }
-
-    disk_io_analytic[0].data.push(r.disk.writes)
-    disk_io_analytic[1].data.push(r.disk.reads)
-
-    if (disk_io_analytic[0].data.length > 100) {
-        disk_io_analytic[0].data.shift()
-        disk_io_analytic[1].data.shift()
-    }
-}
-</script>
-
-<template>
-    <div>
-        <a-row :gutter="[16,16]" class="first-row">
-            <a-col :xl="7" :lg="24" :md="24">
-                <a-card :title="$gettext('Server Info')" :bordered="false">
-                    <p>
-                        <translate>Uptime:</translate>
-                        {{ uptime }}
-                    </p>
-                    <p>
-                        <translate>Load Averages:</translate>
-                        1min:{{ loadavg?.load1?.toFixed(2) }} |
-                        5min:{{ loadavg?.load5?.toFixed(2) }} |
-                        15min:{{ loadavg?.load15?.toFixed(2) }}
-                    </p>
-                    <p>
-                        <translate>OS:</translate>
-                        {{ host.platform }} ({{ host.platformVersion }}
-                        {{ host.os }} {{ host.kernelVersion }}
-                        {{ host.kernelArch }})
-                    </p>
-                    <p v-if="cpu_info">
-                        <translate>CPU:</translate>
-                        {{ cpu_info[0]?.modelName }} * {{ cpu_info.length }}
-                    </p>
-                </a-card>
-            </a-col>
-            <a-col :xl="10" :lg="16" :md="24" class="chart_dashboard">
-                <a-card :title="$gettext('Memory and Storage')" :bordered="false">
-                    <a-row :gutter="[0,16]">
-                        <a-col :xs="24" :sm="24" :md="8">
-                            <radial-bar-chart :name="$gettext('Memory')" :series="[memory.pressure]"
-                                              :centerText="memory.used" :bottom-text="memory.total" colors="#36a3eb"/>
-                        </a-col>
-                        <a-col :xs="24" :sm="12" :md="8">
-                            <radial-bar-chart :name="$gettext('Swap')" :series="[memory.swap_percent]"
-                                              :centerText="memory.swap_used"
-                                              :bottom-text="memory.swap_total" colors="#ff6385"/>
-                        </a-col>
-                        <a-col :xs="24" :sm="12" :md="8">
-                            <radial-bar-chart :name="$gettext('Storage')" :series="[disk.percentage]"
-                                              :centerText="disk.used" :bottom-text="disk.total" colors="#87d068"/>
-                        </a-col>
-                    </a-row>
-                </a-card>
-            </a-col>
-            <a-col :xl="7" :lg="8" :sm="24" class="chart_dashboard">
-                <a-card :title="$gettext('Network Statistics')" :bordered="false">
-                    <a-row :gutter="16">
-                        <a-col :span="12">
-                            <a-statistic :value="bytesToSize(net.last_recv)"
-                                         :title="$gettext('Network Total Receive')"/>
-                        </a-col>
-                        <a-col :span="12">
-                            <a-statistic :value="bytesToSize(net.last_sent)"
-                                         :title="$gettext('Network Total Send')"/>
-                        </a-col>
-                    </a-row>
-                </a-card>
-            </a-col>
-        </a-row>
-        <a-row class="row-two" :gutter="[16,32]">
-            <a-col :xl="8" :lg="24" :md="24" :sm="24">
-                <a-card :title="$gettext('CPU Status')" :bordered="false">
-                    <a-statistic :value="cpu" title="CPU">
-                        <template v-slot:suffix>
-                            <span>%</span>
-                        </template>
-                    </a-statistic>
-                    <area-chart :series="cpu_analytic_series" :max="100"/>
-                </a-card>
-            </a-col>
-            <a-col :xl="8" :lg="12" :md="24" :sm="24">
-                <a-card :title="$gettext('Network')">
-                    <a-row :gutter="16">
-                        <a-col :span="12">
-                            <a-statistic :value="bytesToSize(net.recv)"
-                                         :title="$gettext('Receive')">
-                                <template v-slot:suffix>
-                                    <span>/s</span>
-                                </template>
-                            </a-statistic>
-                        </a-col>
-                        <a-col :span="12">
-                            <a-statistic :value="bytesToSize(net.sent)" :title="$gettext('Send')">
-                                <template v-slot:suffix>
-                                    <span>/s</span>
-                                </template>
-                            </a-statistic>
-                        </a-col>
-                    </a-row>
-                    <area-chart :series="net_analytic" :y_formatter="net_formatter"/>
-                </a-card>
-            </a-col>
-            <a-col :xl="8" :lg="12" :md="24" :sm="24">
-                <a-card :title="$gettext('Disk IO')">
-                    <a-row :gutter="16">
-                        <a-col :span="12">
-                            <a-statistic :value="disk_io.writes"
-                                         :title="$gettext('Writes')">
-                                <template v-slot:suffix>
-                                    <span>/s</span>
-                                </template>
-                            </a-statistic>
-                        </a-col>
-                        <a-col :span="12">
-                            <a-statistic :value="disk_io.reads" :title="$gettext('Reads')">
-                                <template v-slot:suffix>
-                                    <span>/s</span>
-                                </template>
-                            </a-statistic>
-                        </a-col>
-                    </a-row>
-                    <area-chart :series="disk_io_analytic"/>
-                </a-card>
-            </a-col>
-        </a-row>
-    </div>
-</template>
-
-<style lang="less" scoped>
-.first-row {
-    .ant-card {
-        min-height: 227px;
-
-        p {
-            margin-bottom: 8px;
-        }
-    }
-
-    margin-bottom: 20px;
-}
-
-.ant-card {
-    .ant-statistic {
-        margin: 0 50px 10px 10px
-    }
-
-    .chart {
-        max-width: 800px;
-        max-height: 350px;
-    }
-
-    .chart_dashboard {
-        padding: 60px;
-
-        .description {
-            width: 120px;
-            text-align: center
-        }
-    }
-
-    @media (max-width: 512px) {
-        margin: 10px 0;
-        .chart_dashboard {
-            padding: 20px;
-        }
-    }
-}
-</style>
-

+ 0 - 168
frontend-next/src/views/domain/DomainAdd.vue

@@ -1,168 +0,0 @@
-<script setup lang="ts">
-import DirectiveEditor from '@/views/domain/ngx_conf/directive/DirectiveEditor.vue'
-import LocationEditor from '@/views/domain/ngx_conf/LocationEditor.vue'
-import NgxConfigEditor from '@/views/domain/ngx_conf/NgxConfigEditor.vue'
-import {useGettext} from 'vue3-gettext'
-import domain from '@/api/domain'
-import ngx from '@/api/ngx'
-import {computed, reactive, ref} from 'vue'
-import {message} from 'ant-design-vue'
-import {useRouter} from 'vue-router'
-
-const {$gettext, interpolate} = useGettext()
-
-const config = reactive({name: ''})
-let ngx_config = reactive({
-    servers: [{
-        directives: [],
-        locations: []
-    }]
-})
-
-const error = reactive({})
-
-const current_step = ref(0)
-
-const enabled = ref(true)
-
-const auto_cert = ref(false)
-
-const update = ref(0)
-
-init()
-
-function init() {
-    domain.get_template().then(r => {
-        Object.assign(ngx_config, r.tokenized)
-    })
-}
-
-function save() {
-    ngx.build_config(ngx_config).then(r => {
-        domain.save(config.name, {content: r.content, enabled: true}).then(() => {
-            message.success($gettext('Saved successfully'))
-
-            domain.enable(config.name).then(() => {
-                message.success($gettext('Enabled successfully'))
-                current_step.value++
-                window.scroll({top: 0, left: 0, behavior: 'smooth'})
-            }).catch(r => {
-                message.error(r.message ?? $gettext('Enable failed'), 10)
-            })
-
-        }).catch(r => {
-            message.error(interpolate($gettext('Save error %{msg}'), {msg: r.message ?? ''}), 10)
-        })
-    })
-}
-
-const router = useRouter()
-
-function goto_modify() {
-    router.push('/domain/' + config.name)
-}
-
-function create_another() {
-    router.go(0)
-}
-
-const has_server_name = computed(() => {
-    const servers = ngx_config.servers
-    for (const server_key in servers) {
-        for (const k in servers[server_key].directives) {
-            const v = servers[server_key].directives[k]
-            if (v.directive === 'server_name' && v.params.trim() !== '') {
-                return true
-            }
-        }
-    }
-
-    return false
-})
-</script>
-
-<template>
-    <a-card :title="$gettext('Add Site')">
-        <div class="domain-add-container">
-            <a-steps :current="current_step" size="small">
-                <a-step :title="$gettext('Base information')"/>
-                <a-step :title="$gettext('Configure SSL')"/>
-                <a-step :title="$gettext('Finished')"/>
-            </a-steps>
-
-            <template v-if="current_step===0">
-                <a-form layout="vertical">
-                    <a-form-item :label="$gettext('Configuration Name')">
-                        <a-input v-model:value="config.name"/>
-                    </a-form-item>
-                </a-form>
-
-
-                <directive-editor :ngx_directives="ngx_config.servers[0].directives"/>
-                <br/>
-                <location-editor :locations="ngx_config.servers[0].locations"/>
-                <br/>
-                <a-alert
-                    v-if="!has_server_name"
-                    :message="$gettext('Warning')"
-                    type="warning"
-                    show-icon
-                >
-                    <template #description>
-                        <span v-translate>server_name parameter is required</span>
-                    </template>
-                </a-alert>
-                <br/>
-            </template>
-
-            <template v-else-if="current_step===1">
-
-                <ngx-config-editor
-                    ref="ngx-config-editor"
-                    :ngx_config="ngx_config"
-                    v-model:auto_cert="auto_cert"
-                    :enabled="enabled"
-                />
-
-                <br/>
-
-            </template>
-
-            <a-space v-if="current_step<2">
-                <a-button
-                    type="primary"
-                    @click="save"
-                    :disabled="!config.name||!has_server_name"
-                >
-                    <translate>Next</translate>
-                </a-button>
-            </a-space>
-            <a-result
-                v-else-if="current_step===2"
-                status="success"
-                :title="$gettext('Domain Config Created Successfully')"
-            >
-                <template #extra>
-                    <a-button type="primary" @click="goto_modify">
-                        <translate>Modify Config</translate>
-                    </a-button>
-                    <a-button @click="create_another">
-                        <translate>Create Another</translate>
-                    </a-button>
-                </template>
-            </a-result>
-
-        </div>
-    </a-card>
-</template>
-
-<style lang="less" scoped>
-.ant-steps {
-    padding: 10px 0 20px 0;
-}
-
-.domain-add-container {
-    max-width: 800px;
-    margin: 0 auto
-}
-</style>

+ 0 - 219
frontend-next/src/views/domain/DomainEdit.vue

@@ -1,219 +0,0 @@
-<script setup lang="ts">
-import FooterToolBar from '@/components/FooterToolbar/FooterToolBar.vue'
-import CodeEditor from '@/components/CodeEditor/CodeEditor.vue'
-
-import NgxConfigEditor from '@/views/domain/ngx_conf/NgxConfigEditor'
-import {useGettext} from 'vue3-gettext'
-import {reactive, ref} from 'vue'
-import {useRoute} from 'vue-router'
-import domain from '@/api/domain'
-import ngx from '@/api/ngx'
-import {message} from 'ant-design-vue'
-
-
-const {$gettext, interpolate} = useGettext()
-
-const route = useRoute()
-
-const name = ref(route.params.name.toString())
-const update = ref(0)
-
-const ngx_config = reactive({
-    filename: '',
-    upstreams: [],
-    servers: []
-})
-
-const auto_cert = ref(false)
-const enabled = ref(false)
-const configText = ref('')
-const ok = ref(false)
-const advance_mode = ref(false)
-const saving = ref(false)
-
-init()
-
-function init() {
-    if (name.value) {
-        domain.get(name.value).then((r: any) => {
-            configText.value = r.config
-            enabled.value = r.enabled
-            auto_cert.value = r.auto_cert
-            Object.assign(ngx_config, r.tokenized)
-        }).catch(r => {
-            message.error(r.message ?? $gettext('Server error'))
-        })
-    }
-}
-
-function on_mode_change(advance_mode: boolean) {
-    if (advance_mode) {
-        build_config()
-    } else {
-        return ngx.tokenize_config(configText.value).then((r: any) => {
-            Object.assign(ngx_config, r.tokenized)
-        }).catch((e: any) => {
-            message.error(e?.message ?? $gettext('Server error'))
-        })
-    }
-}
-
-function build_config() {
-    return ngx.build_config(ngx_config).then((r: any) => {
-        configText.value = r.content
-    }).catch((e: any) => {
-        message.error(e?.message ?? $gettext('Server error'))
-    })
-}
-
-const save = async () => {
-    saving.value = true
-
-    if (!advance_mode.value) {
-        await build_config()
-    }
-
-    domain.save(name.value, {content: configText.value}).then(r => {
-        configText.value = r.config
-        enabled.value = r.enabled
-        Object.assign(ngx_config, r.tokenized)
-        message.success($gettext('Saved successfully'))
-
-        // TODO this.$refs.ngx_config.update_cert_info()
-
-    }).catch((e: any) => {
-        message.error(e?.message ?? $gettext('Server error'))
-    }).finally(() => {
-        saving.value = false
-    })
-
-}
-
-function enable() {
-    domain.enable(name.value).then(() => {
-        message.success($gettext('Enabled successfully'))
-        enabled.value = true
-    }).catch(r => {
-        message.error(interpolate($gettext('Failed to enable %{msg}'), {msg: r.message ?? ''}), 10)
-    })
-}
-
-function disable() {
-    domain.disable(name.value).then(() => {
-        message.success($gettext('Disabled successfully'))
-        enabled.value = false
-    }).catch(r => {
-        message.error(interpolate($gettext('Failed to disable %{msg}'), {msg: r.message ?? ''}))
-    })
-}
-</script>
-<template>
-    <div>
-        <a-card :bordered="false">
-            <template #title>
-                <span style="margin-right: 10px">{{ interpolate($gettext('Edit %{n}'), {n: name}) }}</span>
-                <a-tag color="blue" v-if="enabled">
-                    {{ $gettext('Enabled') }}
-                </a-tag>
-                <a-tag color="orange" v-else>
-                    {{ $gettext('Disabled') }}
-                </a-tag>
-            </template>
-            <template #extra>
-                <div class="mode-switch">
-                    <div class="switch">
-                        <a-switch size="small" v-model:checked="advance_mode" @change="on_mode_change"/>
-                    </div>
-                    <template v-if="advance_mode">
-                        <div>{{ $gettext('Advance Mode') }}</div>
-                    </template>
-                    <template v-else>
-                        <div>{{ $gettext('Basic Mode') }}</div>
-                    </template>
-                </div>
-            </template>
-
-            <transition name="slide-fade">
-                <div v-if="advance_mode" key="advance">
-                    <code-editor v-model:content="configText"/>
-                </div>
-
-                <div class="domain-edit-container" key="basic" v-else>
-                    <a-form-item :label="$gettext('Enabled')">
-                        <a-switch v-model:checked="enabled" @change="checked=>{checked?enable():disable()}"/>
-                    </a-form-item>
-                    <ngx-config-editor
-                        ref="ngx_config_editor"
-                        :ngx_config="ngx_config"
-                        v-model:auto_cert="auto_cert"
-                        :enabled="enabled"
-                    />
-                </div>
-            </transition>
-
-        </a-card>
-
-        <footer-tool-bar>
-            <a-space>
-                <a-button @click="$router.go(-1)">
-                    <translate>Back</translate>
-                </a-button>
-                <a-button type="primary" @click="save" :loading="saving">
-                    <translate>Save</translate>
-                </a-button>
-            </a-space>
-        </footer-tool-bar>
-    </div>
-</template>
-
-<style lang="less">
-
-</style>
-
-<style lang="less" scoped>
-.ant-card {
-    margin: 10px 0;
-    box-shadow: unset;
-}
-
-.mode-switch {
-    display: flex;
-
-    .switch {
-        display: flex;
-        align-items: center;
-        margin-right: 5px;
-    }
-}
-
-.domain-edit-container {
-    max-width: 800px;
-    margin: 0 auto;
-}
-
-.slide-fade-enter-active {
-    transition: all .5s ease-in-out;
-}
-
-.slide-fade-leave-active {
-    transition: all .5s cubic-bezier(1.0, 0.5, 0.8, 1.0);
-}
-
-.slide-fade-enter, .slide-fade-leave-to
-    /* .slide-fade-leave-active for below version 2.1.8 */ {
-    transform: translateX(10px);
-    opacity: 0;
-}
-
-.location-block {
-
-}
-
-.directive-params-wrapper {
-    margin: 10px 0;
-}
-
-.tab-content {
-    padding: 10px;
-}
-</style>

+ 0 - 121
frontend-next/src/views/domain/DomainList.vue

@@ -1,121 +0,0 @@
-<script setup lang="tsx">
-import StdTable from '@/components/StdDataDisplay/StdTable.vue'
-
-import {badge, customRender, datetime} from '@/components/StdDataDisplay/StdTableTransformer'
-import {useGettext} from 'vue3-gettext'
-
-const {$gettext, interpolate} = useGettext()
-
-import domain from '@/api/domain'
-import {Badge, message} from 'ant-design-vue'
-import {h, ref} from 'vue'
-
-const columns = [{
-    title: () => $gettext('Name'),
-    dataIndex: 'name',
-    sorter: true,
-    pithy: true
-}, {
-    title: () => $gettext('Status'),
-    dataIndex: 'enabled',
-    customRender: (args: customRender) => {
-        const template: any = []
-        const {text, column} = args
-        if (text === true || text > 0) {
-            template.push(<Badge status="success"/>)
-            template.push($gettext('Enabled'))
-        } else {
-            template.push(<Badge status="error"/>)
-            template.push($gettext('Disabled'))
-        }
-        return h('div', template)
-    },
-    sorter: true,
-    pithy: true
-}, {
-    title: () => $gettext('Updated at'),
-    dataIndex: 'modify',
-    customRender: datetime,
-    sorter: true,
-    pithy: true
-}, {
-    title: () => $gettext('Action'),
-    dataIndex: 'action',
-}]
-
-const table = ref(null)
-
-interface Table {
-    get_list(): void
-}
-
-function enable(name: any) {
-    domain.enable(name).then(() => {
-        message.success($gettext('Enabled successfully'))
-        const t: Table | null = table.value
-        t!.get_list()
-    }).catch(r => {
-        message.error(interpolate($gettext('Failed to enable %{msg}'), {msg: r.message ?? ''}), 10)
-    })
-}
-
-function disable(name: any) {
-    domain.disable(name).then(() => {
-        message.success($gettext('Disabled successfully'))
-        const t: Table | null = table.value
-        t!.get_list()
-    }).catch(r => {
-        message.error(interpolate($gettext('Failed to disable %{msg}'), {msg: r.message ?? ''}))
-    })
-}
-
-function destroy(site_name: any) {
-    domain.destroy(site_name).then(() => {
-        const t: Table | null = table.value
-        t!.get_list()
-        message.success(interpolate($gettext('Delete site: %{site_name}'), {site_name: site_name}))
-    }).catch((e: any) => {
-        message.error(e?.message ?? $gettext('Server error'))
-    })
-}
-</script>
-
-<template>
-    <a-card :title="$gettext('Manage Sites')">
-        <std-table
-            :api="domain"
-            :columns="columns"
-            :disable_search="true"
-            row-key="name"
-            ref="table"
-            @clickEdit="r => this.$router.push({
-                path: '/domain/' + r
-            })"
-            :deletable="false"
-        >
-            <template #actions="{record}">
-                <template v-if="!record.enabled">
-                    <a-divider type="vertical"/>
-                    <a-popconfirm
-                        :cancelText="$gettext('No')"
-                        :okText="$gettext('OK')"
-                        :title="$gettext('Are you sure you want to delete ?')"
-                        @confirm="destroy(record['name'])">
-                        <a v-translate>Delete</a>
-                    </a-popconfirm>
-                </template>
-                <a-divider type="vertical"/>
-                <a v-if="record.enabled" @click="disable(record.name)">
-                    {{ $gettext('Disabled') }}
-                </a>
-                <a v-else @click="enable(record.name)">
-                    {{ $gettext('Enabled') }}
-                </a>
-            </template>
-        </std-table>
-    </a-card>
-</template>
-
-<style scoped>
-
-</style>

+ 0 - 44
frontend-next/src/views/domain/cert/Cert.vue

@@ -1,44 +0,0 @@
-<template>
-    <div>
-        <cert-info ref="info" :domain="name" v-if="name"/>
-        <issue-cert
-            :current_server_directives="current_server_directives"
-            :directives-map="directivesMap"
-            v-model="auto_cert"
-            @callback="callback"
-        />
-    </div>
-</template>
-
-<script>
-import CertInfo from '@/views/domain/cert/CertInfo'
-import IssueCert from '@/views/domain/cert/IssueCert'
-
-export default {
-    name: 'Cert',
-    components: {IssueCert, CertInfo},
-    props: {
-        directivesMap: Object,
-        current_server_directives: Array,
-        auto_cert: Boolean
-    },
-    model: {
-        prop: 'auto_cert',
-        event: 'change_auto_cert'
-    },
-    methods: {
-        callback() {
-            this.$refs.info.get()
-        }
-    },
-    computed: {
-        name() {
-            return this.directivesMap['server_name'][0].params.trim()
-        }
-    }
-}
-</script>
-
-<style scoped>
-
-</style>

+ 0 - 61
frontend-next/src/views/domain/cert/CertInfo.vue

@@ -1,61 +0,0 @@
-<script setup lang="ts">
-import {CloseCircleOutlined, CheckCircleOutlined} from '@ant-design/icons-vue'
-import dayjs from 'dayjs'
-import {defineProps, reactive, ref} from 'vue'
-import domain from '@/api/domain'
-
-const props = defineProps(['domain'])
-
-const ok = ref(false)
-const cert = reactive({issuer_name: '', subject_name: '', not_after: '', not_before: ''})
-
-get()
-
-function get() {
-    domain.cert_info(props.domain).then((r: any) => {
-        Object.assign(cert, r)
-        ok.value = true
-    }).catch(() => {
-        ok.value = false
-    })
-}
-</script>
-
-<template>
-    <div class="cert-info" v-if="ok">
-        <h2 v-translate>Certificate Status</h2>
-        <p v-translate="{issuer: cert.issuer_name}">Intermediate Certification Authorities: %{issuer}</p>
-        <p v-translate="{name: cert.subject_name}">Subject Name: %{name}</p>
-        <p v-translate="{date: dayjs(cert.not_after).format('YYYY-MM-DD HH:mm:ss').toString()}">
-            Expiration Date: %{date}</p>
-        <p v-translate="{date: dayjs(cert.not_before).format('YYYY-MM-DD HH:mm:ss').toString()}">
-            Not Valid Before: %{date}</p>
-        <div class="status">
-            <template v-if="new Date().toISOString() < cert.not_before || new Date().toISOString() > cert.not_after">
-                <close-circle-outlined style="color: red"/>
-                <span v-translate>Certificate has expired</span>
-            </template>
-            <template v-else>
-                <check-circle-outlined style="color: green"/>
-                <span v-translate>Certificate is valid</span>
-            </template>
-        </div>
-    </div>
-</template>
-
-<style lang="less" scoped>
-h4 {
-    padding-bottom: 10px;
-}
-
-.cert-info {
-    padding-bottom: 10px;
-}
-
-.status {
-    span {
-        margin-right: 10px;
-    }
-}
-
-</style>

+ 0 - 169
frontend-next/src/views/domain/cert/IssueCert.vue

@@ -1,169 +0,0 @@
-<template>
-    <div>
-        <a-form-item :label="$gettext('Encrypt website with Let\'s Encrypt')">
-            <a-switch
-                :loading="issuing_cert"
-                v-model="M_enabled"
-                @change="onchange"
-                :disabled="no_server_name||server_name_more_than_one"
-            />
-            <a-alert
-                v-if="no_server_name||server_name_more_than_one"
-                :message="$gettext('Warning')"
-                type="warning"
-                show-icon
-            >
-                <template slot="description">
-                    <span v-if="no_server_name" v-translate>
-                        server_name parameter is required
-                    </span>
-                    <span v-if="server_name_more_than_one" v-translate>
-                        server_name parameters more than one
-                    </span>
-                </template>
-            </a-alert>
-        </a-form-item>
-        <p v-translate>
-            Note: The server_name in the current configuration must be the domain name
-            you need to get the certificate.
-        </p>
-        <p v-if="enabled" v-translate>
-            The certificate for the domain will be checked every hour,
-            and will be renewed if it has been more than 1 month since it was last issued.
-        </p>
-        <p v-translate>
-            Make sure you have configured a reverse proxy for .well-known
-            directory to HTTPChallengePort (default: 9180) before getting the certificate.
-        </p>
-    </div>
-</template>
-
-<script>
-import {issue_cert} from '@/views/domain/methods'
-import $gettext, {$interpolate} from '@/lib/translate/gettext'
-
-export default {
-    name: 'IssueCert',
-    props: {
-        directivesMap: Object,
-        current_server_directives: Array,
-        enabled: Boolean
-    },
-    model: {
-        prop: 'enabled',
-        event: 'changeEnabled'
-    },
-    data() {
-        return {
-            issuing_cert: false,
-            M_enabled: this.enabled,
-        }
-    },
-    methods: {
-        onchange(r) {
-            this.$emit('changeEnabled', r)
-            this.change_auto_cert(r)
-            if (r) {
-                this.job()
-            }
-        },
-        job() {
-            this.issuing_cert = true
-
-            if (this.no_server_name) {
-                this.$message.error($gettext('server_name not found in directives'))
-                this.issuing_cert = false
-                return
-            }
-
-            if (this.server_name_more_than_one) {
-                this.$message.error($gettext('server_name parameters more than one'))
-                this.issuing_cert = false
-                return
-            }
-
-            const server_name = this.directivesMap['server_name'][0]
-
-            if (!this.directivesMap['ssl_certificate']) {
-                this.current_server_directives.splice(server_name.idx + 1, 0, {
-                    directive: 'ssl_certificate',
-                    params: ''
-                })
-            }
-
-            this.$nextTick(() => {
-                if (!this.directivesMap['ssl_certificate_key']) {
-                    const ssl_certificate = this.directivesMap['ssl_certificate'][0]
-                    this.current_server_directives.splice(ssl_certificate.idx + 1, 0, {
-                        directive: 'ssl_certificate_key',
-                        params: ''
-                    })
-                }
-            })
-
-            setTimeout(() => {
-                issue_cert(this.name, this.callback)
-            }, 100)
-        },
-        callback(ssl_certificate, ssl_certificate_key) {
-            this.$set(this.directivesMap['ssl_certificate'][0], 'params', ssl_certificate)
-            this.$set(this.directivesMap['ssl_certificate_key'][0], 'params', ssl_certificate_key)
-            this.issuing_cert = false
-            this.$emit('callback')
-        },
-        change_auto_cert(r) {
-            if (r) {
-                this.$api.domain.add_auto_cert(this.name).then(() => {
-                    this.$message.success($interpolate($gettext('Auto-renewal enabled for %{name}'), {name: this.name}))
-                }).catch(e => {
-                    this.$message.error(e.message ?? $interpolate($gettext('Enable auto-renewal failed for %{name}'), {name: this.name}))
-                })
-            } else {
-                this.$api.domain.remove_auto_cert(this.name).then(() => {
-                    this.$message.success($interpolate($gettext('Auto-renewal disabled for %{name}'), {name: this.name}))
-                }).catch(e => {
-                    this.$message.error(e.message ?? $interpolate($gettext('Disable auto-renewal failed for %{name}'), {name: this.name}))
-                })
-            }
-        },
-    },
-    watch: {
-        server_name_more_than_one() {
-            this.M_enabled = false
-            this.onchange(false)
-        },
-        no_server_name() {
-            this.M_enabled = false
-            this.onchange(false)
-        }
-    },
-    computed: {
-        is_demo() {
-            return this.$store.getters.env.demo === true
-        },
-        server_name_more_than_one() {
-            return this.directivesMap['server_name'] && (this.directivesMap['server_name'].length > 1 ||
-                this.directivesMap['server_name'][0].params.trim().indexOf(' ') > 0)
-        },
-        no_server_name() {
-            return !this.directivesMap['server_name']
-        },
-        name() {
-            return this.directivesMap['server_name'][0].params.trim()
-        }
-    }
-}
-</script>
-
-<style lang="less" scoped>
-.switch-wrapper {
-    position: relative;
-
-    .text {
-        position: absolute;
-        top: 50%;
-        transform: translateY(-50%);
-        margin-left: 10px;
-    }
-}
-</style>

+ 0 - 37
frontend-next/src/views/domain/methods.js

@@ -1,37 +0,0 @@
-import $gettext from '@/lib/translate/gettext'
-import store from '@/lib/store'
-import Vue from 'vue'
-
-const issue_cert = (server_name, callback) => {
-    Vue.prototype.$message.info($gettext('Getting the certificate, please wait...'), 15)
-    const ws = new WebSocket(Vue.prototype.getWebSocketRoot() + '/cert/issue/' + server_name
-        + '?token=' + btoa(store.state.user.token))
-
-    ws.onopen = () => {
-        ws.send('go')
-    }
-
-    ws.onmessage = m => {
-        const r = JSON.parse(m.data)
-        switch (r.status) {
-            case 'success':
-                Vue.prototype.$message.success(r.message, 10)
-                break
-            case 'info':
-                Vue.prototype.$message.info(r.message, 10)
-                break
-            case 'error':
-                Vue.prototype.$message.error(r.message, 10)
-                break
-        }
-
-        if (r.status === 'success' && r.ssl_certificate !== undefined && r.ssl_certificate_key !== undefined) {
-            callback(r.ssl_certificate, r.ssl_certificate_key)
-        }
-    }
-    // setTimeout(() => {
-    //     callback('a', 'b')
-    // }, 10000)
-}
-
-export {issue_cert}

+ 0 - 81
frontend-next/src/views/domain/ngx_conf/LocationEditor.vue

@@ -1,81 +0,0 @@
-<script setup lang="ts">
-import CodeEditor from '@/components/CodeEditor'
-import {useGettext} from 'vue3-gettext'
-import {reactive, ref} from 'vue'
-
-const {$gettext} = useGettext()
-
-const {locations} = defineProps<{
-    locations?: any[]
-}>()
-
-let location = reactive({
-    comments: '',
-    path: '',
-    content: '',
-})
-
-const adding = ref(false)
-
-function add() {
-    adding.value = true
-    location = reactive({
-        comments: '',
-        path: '',
-        content: '',
-    })
-}
-
-function save() {
-    adding.value = false
-    locations.push(this.location)
-}
-
-function remove(index) {
-    locations.splice(index, 1)
-}
-</script>
-
-<template>
-    <h2 v-translate>Locations</h2>
-    <a-empty v-if="!locations"/>
-    <a-card v-for="(v,k) in locations" :key="k"
-            :title="$gettext('Location')" size="small">
-        <a-form layout="vertical">
-            <a-form-item :label="$gettext('Comments')">
-                <a-textarea v-model:value="v.comments"/>
-            </a-form-item>
-            <a-form-item :label="$gettext('Path')">
-                <a-input addon-before="location" v-model:value="v.path"/>
-            </a-form-item>
-            <a-form-item :label="$gettext('Content')">
-                <code-editor v-model:content="v.content" default-height="200px"/>
-            </a-form-item>
-        </a-form>
-    </a-card>
-
-    <a-modal :title="$gettext('Add Location')" v-model:visible="adding" @ok="save">
-        <a-form layout="vertical">
-            <a-form-item :label="$gettext('Comments')">
-                <a-textarea v-model:value="location.comments"/>
-            </a-form-item>
-            <a-form-item :label="$gettext('Path')">
-                <a-input addon-before="location" v-model:value="location.path"/>
-            </a-form-item>
-            <a-form-item :label="$gettext('Content')">
-                <code-editor v-model:content="location.content" default-height="200px"/>
-            </a-form-item>
-        </a-form>
-    </a-modal>
-
-    <div>
-        <a-button block @click="add">{{ $gettext('Add Location') }}</a-button>
-    </div>
-</template>
-
-<style lang="less" scoped>
-.ant-card {
-    margin: 10px 0;
-    box-shadow: unset;
-}
-</style>

+ 0 - 169
frontend-next/src/views/domain/ngx_conf/NgxConfigEditor.vue

@@ -1,169 +0,0 @@
-<script setup lang="ts">
-import CertInfo from '@/views/domain/cert/CertInfo'
-// import IssueCert from '@/views/domain/cert/IssueCert'
-import DirectiveEditor from '@/views/domain/ngx_conf/directive/DirectiveEditor'
-import LocationEditor from '@/views/domain/ngx_conf/LocationEditor'
-import {computed, ref} from 'vue'
-import {useRoute} from 'vue-router'
-import {useGettext} from 'vue3-gettext'
-
-const {$gettext} = useGettext()
-
-const {ngx_config, auto_cert, enabled} = defineProps(['ngx_config', 'auto_cert', 'enabled'])
-
-const route = useRoute()
-
-const current_server_index = ref(0)
-const name = ref(route.params.name)
-
-const init_ssl_status = ref(false)
-
-function update_cert_info() {
-    // TODO
-    // if (name.value && this.$refs['cert-info' + this.current_server_index]) {
-    //     this.$refs['cert-info' + this.current_server_index].get()
-    // }
-}
-
-function change_tls(r: any) {
-    if (r) {
-        // deep copy servers[0] to servers[1]
-        const server = JSON.parse(JSON.stringify(ngx_config.servers[0]))
-
-        ngx_config.servers.push(server)
-
-        current_server_index.value = 1
-
-        const servers = ngx_config.servers
-
-        let i = 0
-        while (i < servers[1].directives.length) {
-            const v = servers[1].directives[i]
-            if (v.directive === 'listen') {
-                servers[1].directives.splice(i, 1)
-            } else {
-                i++
-            }
-        }
-
-        servers[1].directives.splice(0, 0, {
-            directive: 'listen',
-            params: '443 ssl http2'
-        }, {
-            directive: 'listen',
-            params: '[::]:443 ssl http2'
-        })
-
-        const server_name = directivesMap.value['server_name'][0]
-
-        if (!directivesMap.value['ssl_certificate']) {
-            servers[1].directives.splice(server_name.idx + 1, 0, {
-                directive: 'ssl_certificate',
-                params: ''
-            })
-        }
-
-        setTimeout(() => {
-            if (!directivesMap.value['ssl_certificate_key']) {
-                servers[1].directives.splice(server_name.idx + 2, 0, {
-                    directive: 'ssl_certificate_key',
-                    params: ''
-                })
-            }
-        }, 100)
-
-    } else {
-        // remove servers[1]
-        current_server_index.value = 0
-        if (ngx_config.servers.length === 2) {
-            ngx_config.servers.splice(1, 1)
-        }
-    }
-}
-
-const current_server_directives = computed(() => {
-    return ngx_config.servers[current_server_index.value].directives
-})
-
-const directivesMap = computed(() => {
-    const map = <any>{}
-
-    current_server_directives.value.forEach((v: any, k: any) => {
-        v.idx = k
-        if (map[v.directive]) {
-            map[v.directive].push(v)
-        } else {
-            map[v.directive] = [v]
-        }
-    })
-
-    return map
-})
-
-
-const support_ssl = computed(() => {
-    const servers = ngx_config.servers
-    for (const server_key in servers) {
-        for (const k in servers[server_key].directives) {
-            const v = servers[server_key].directives[k]
-            if (v.directive === 'listen' && v.params.indexOf('ssl') > 0) {
-                return true
-            }
-        }
-    }
-    return false
-})
-
-
-const current_support_ssl = computed(() => {
-    if (directivesMap.value.listen) {
-        for (const v of directivesMap.value.listen) {
-            if (v?.params.indexOf('ssl') > 0) {
-                return true
-            }
-        }
-    }
-    return false
-
-})
-
-</script>
-
-<template>
-    <div>
-        <a-form-item :label="$gettext('Enable TLS')" v-if="!support_ssl">
-            <a-switch @change="change_tls"/>
-        </a-form-item>
-
-        <a-tabs v-model:activeKey="current_server_index">
-            <a-tab-pane :tab="'Server '+(k+1)" v-for="(v,k) in ngx_config.servers" :key="k">
-
-                <div class="tab-content">
-                    <template v-if="current_support_ssl&&enabled">
-                        <cert-info :domain="name" v-if="current_support_ssl"/>
-                        <!--                        <issue-cert-->
-                        <!--                            :current_server_directives="current_server_directives"-->
-                        <!--                            :directives-map="directivesMap"-->
-                        <!--                            v-model="auto_cert"-->
-                        <!--                        />-->
-                    </template>
-
-                    <template v-if="v.comments">
-                        <h3 v-translate>Comments</h3>
-                        <p style="white-space: pre-wrap;">{{ v.comments }}</p>
-                    </template>
-
-                    <directive-editor :ngx_directives="v.directives"/>
-                    <br/>
-                    <location-editor :locations="v.locations"/>
-                </div>
-
-            </a-tab-pane>
-        </a-tabs>
-    </div>
-
-</template>
-
-<style scoped>
-
-</style>

+ 0 - 77
frontend-next/src/views/domain/ngx_conf/directive/DirectiveAdd.vue

@@ -1,77 +0,0 @@
-<script setup lang="ts">
-import {If} from '@/views/domain/ngx_conf'
-import CodeEditor from '@/components/CodeEditor'
-import {reactive, ref} from 'vue'
-import {useGettext} from 'vue3-gettext'
-import {CloseOutlined} from '@ant-design/icons-vue'
-
-const {$gettext} = useGettext()
-
-const emit = defineEmits(['save'])
-
-const {ngx_directives, idx} = defineProps(['ngx_directives', 'idx'])
-
-let directive = reactive({directive: '', params: ''})
-const adding = ref(false)
-const mode = ref('default')
-
-
-function add() {
-    adding.value = true
-    directive = reactive({directive: '', params: ''})
-}
-
-function save() {
-    adding.value = false
-    if (mode.value === If) {
-        directive.directive = If
-    }
-
-    if (idx) {
-        ngx_directives.splice(idx + 1, 0, directive)
-    } else {
-        ngx_directives.push(directive)
-    }
-
-    emit('save', idx)
-}
-</script>
-
-<template>
-    <div>
-        <div class="add-directive-temp" v-if="adding">
-            <a-form-item>
-                <a-select v-model:value="mode" default-value="default" style="width: 150px">
-                    <a-select-option value="default">
-                        {{ $gettext('Single Directive') }}
-                    </a-select-option>
-                    <a-select-option value="if">
-                        if
-                    </a-select-option>
-                </a-select>
-            </a-form-item>
-            <a-form-item>
-                <code-editor v-if="mode===If" default-height="100px" v-model:content="directive.params"/>
-
-                <a-input-group compact v-else>
-
-                    <a-input style="width: 30%" :placeholder="$gettext('Directive')" v-model="directive.directive"/>
-
-                    <a-input style="width: 70%" :placeholder="$gettext('Params')" v-model="directive.params">
-                        <template #suffix>
-                            <CloseOutlined @click="adding=false" style="color: rgba(0,0,0,.45);font-size: 10px;"/>
-                        </template>
-                    </a-input>
-                </a-input-group>
-            </a-form-item>
-        </div>
-        <a-button block v-if="!adding" @click="add">{{ $gettext('Add Directive Below') }}</a-button>
-        <a-button type="primary" v-else block @click="save"
-                  :disabled="!directive.directive&&!directive.params">{{ $gettext('Save Directive') }}
-        </a-button>
-    </div>
-</template>
-
-<style lang="less" scoped>
-
-</style>

+ 0 - 94
frontend-next/src/views/domain/ngx_conf/directive/DirectiveEditor.vue

@@ -1,94 +0,0 @@
-<script setup lang="ts">
-import CodeEditor from '@/components/CodeEditor'
-import {If} from '@/views/domain/ngx_conf'
-import DirectiveAdd from '@/views/domain/ngx_conf/directive/DirectiveAdd'
-import {useGettext} from 'vue3-gettext'
-import {reactive, ref} from 'vue'
-import {CloseOutlined} from '@ant-design/icons-vue'
-
-const {$gettext} = useGettext()
-
-const {ngx_directives} = defineProps<{
-    ngx_directives: any[]
-}>()
-
-const adding = ref(false)
-
-let directive = reactive({})
-
-const current_idx = ref(-1)
-
-function add() {
-    adding.value = true
-    directive = reactive({})
-}
-
-function save() {
-    adding.value = false
-    ngx_directives.push(directive)
-}
-
-function remove(index: number) {
-    ngx_directives.splice(index, 1)
-}
-
-function onSave(idx: number) {
-    setTimeout(() => {
-        current_idx.value = idx + 1
-    }, 50)
-}
-</script>
-
-<template>
-    <h2>{{ $gettext('Directives') }}</h2>
-
-    <a-form-item v-for="(directive,index) in ngx_directives" @click="current_idx=index">
-        <code-editor v-if="directive.directive === If" v-model:content="directive.params"
-                     defaultHeight="100px"/>
-        <a-input :addon-before="directive.directive" v-model:value="directive.params" @click="current_idx=k"
-                 v-else>
-            <template #suffix>
-                <a-popconfirm @confirm="remove(index)"
-                              :title="$gettext('Are you sure you want to remove this directive?')"
-                              :ok-text="$gettext('Yes')"
-                              :cancel-text="$gettext('No')">
-                    <CloseOutlined style="color: rgba(0,0,0,.45);font-size: 10px;"/>
-                </a-popconfirm>
-            </template>
-        </a-input>
-        <transition name="slide">
-            <div v-if="current_idx===index" class="extra">
-                <div class="extra-content">
-                    <a-form layout="vertical">
-                        <a-form-item :label="$gettext('Comments')">
-                            <a-textarea v-model:value="directive.comments"/>
-                        </a-form-item>
-                    </a-form>
-                    <directive-add :ngx_directives="ngx_directives" :idx="index" @save="onSave(index)"/>
-                </div>
-            </div>
-        </transition>
-    </a-form-item>
-
-    <directive-add :ngx_directives="ngx_directives"/>
-</template>
-
-<style lang="less" scoped>
-.extra {
-    background-color: #fafafa;
-    padding: 10px 20px 20px;
-    margin-bottom: 10px;
-}
-
-.slide-enter-active, .slide-leave-active {
-    transition: max-height .3s ease;
-}
-
-.slide-enter-from, .slide-leave-to {
-    max-height: 0;
-}
-
-.slide-enter-to, .slide-leave-from {
-    max-height: 600px;
-}
-</style>

+ 0 - 49
frontend-next/src/views/other/About.vue

@@ -1,49 +0,0 @@
-<script setup lang="ts">
-import gettext from '@/gettext'
-import logo from '@/assets/img/logo.png'
-
-const {$gettext} = gettext
-
-const this_year = new Date().getFullYear()
-const version = import.meta.env.VITE_APP_VERSION // import.meta.env.VITE_APP_VERSION
-const build_id = import.meta.env.VITE_APP_TOTAL_BUILD ?? $gettext('Development Mode')
-console.log(import.meta)
-</script>
-
-<template>
-    <a-card style="text-align: center" :bordered="false">
-        <div class="logo">
-            <img :src="logo" alt="logo"/>
-        </div>
-        <h2>Nginx UI</h2>
-        <p>Yet another WebUI for Nginx</p>
-        <p>Version: {{ version }} ({{ build_id }})</p>
-        <h3 v-translate>Project Team</h3>
-        <p><a href="https://jackyu.cn/">@0xJacky</a> <a href="https://blog.kugeek.com/">@Hintay</a></p>
-        <h3 v-translate>Build with</h3>
-        <p>❤️</p>
-        <p>Go</p>
-        <p>Gin</p>
-        <p>Vue3 + Vite + TypeScript</p>
-        <p>Websocket</p>
-        <h3 v-translate translate-context="Project">License</h3>
-        <p>GNU General Public License v3.0</p>
-        <p>Copyright © 2020 - {{ this_year }} Nginx UI </p>
-    </a-card>
-</template>
-
-<style lang="less" scoped>
-.logo {
-    img {
-        max-width: 120px
-    }
-}
-
-.egg {
-    padding: 10px 0;
-}
-
-.ant-btn {
-    margin: 10px 10px 0 0;
-}
-</style>

+ 0 - 62
frontend-next/src/views/other/Error.vue

@@ -1,62 +0,0 @@
-<template>
-    <div class="wrapper">
-        <h1 class="title">{{ $route.meta.status_code ? $route.meta.status_code : 404 }}</h1>
-        <p>{{ $route.meta.error ? $route.meta.error : $gettext('File Not Found') }}</p>
-    </div>
-</template>
-
-<script>
-export default {
-    name: 'Error'
-}
-</script>
-
-<style lang="less" scoped>
-body, div, h1, html {
-    padding: 0;
-    margin: 0
-}
-
-body, html {
-    color: #444;
-    position: relative;
-    font-family: "PingFang SC", "Helvetica Neue", Helvetica, Arial, CustomFont, "Microsoft YaHei UI", "Microsoft YaHei", "Hiragino Sans GB", sans-serif;
-    background: #fcfcfc;
-    height: 100%
-}
-
-h1 {
-    font-size: 8em;
-    font-weight: 100
-}
-
-a {
-    color: #4181b9;
-    text-decoration: none;
-    -webkit-transition: all .3s ease;
-    -moz-transition: all .3s ease;
-    -ms-transition: all .3s ease;
-    -o-transition: all .3s ease;
-    transition: all .3s ease;
-
-    &:active, &:hover {
-        color: #5bb0ed
-    }
-
-}
-
-.wrapper {
-    position: absolute;
-    top: 0;
-    bottom: 0;
-    left: 0;
-    right: 0;
-    font-size: 1em;
-    font-weight: 400;
-    width: 100%;
-    height: 30%;
-    line-height: 1;
-    margin: auto;
-    text-align: center
-}
-</style>

+ 0 - 146
frontend-next/src/views/other/Install.vue

@@ -1,146 +0,0 @@
-<template>
-    <div class="login-form">
-        <div class="project-title">
-            <h1>Nginx UI</h1>
-        </div>
-        <a-form
-            id="components-form-install"
-            :form="form"
-            class="login-form"
-            @submit="handleSubmit"
-        >
-            <a-form-item>
-                <a-input
-                    v-decorator="[
-          'email',
-          { rules: [{
-                type: 'email',
-                message: $gettext('Invalid E-mail!'),
-              },
-              {
-                required: true,
-                message: $gettext('Please input your E-mail!'),
-              },] },
-        ]"
-                    :placeholder="$gettext('Email (*)')"
-                >
-                    <a-icon slot="prefix" type="mail" style="color: rgba(0,0,0,.25)"/>
-                </a-input>
-            </a-form-item>
-            <a-form-item>
-                <a-input
-                    v-decorator="[
-          'username',
-          { rules: [{ required: true, message: $gettext('Please input your username!') }] },
-        ]"
-                    :placeholder="$gettext('Username (*)')"
-                >
-                    <a-icon slot="prefix" type="user" style="color: rgba(0,0,0,.25)"/>
-                </a-input>
-            </a-form-item>
-            <a-form-item>
-                <a-input
-                    v-decorator="[
-          'password',
-          { rules: [{ required: true, message: $gettext('Please input your password!') }] },
-        ]"
-                    type="password"
-                    :placeholder="$gettext('Password (*)')"
-                >
-                    <a-icon slot="prefix" type="lock" style="color: rgba(0,0,0,.25)"/>
-                </a-input>
-            </a-form-item>
-            <a-form-item>
-                <a-input
-                    v-decorator="[
-          'database',
-          { rules: [{ pattern: /^[^\\/:*?\x22<>|]{1,120}$/,
-          message: $gettextInterpolate(
-              $gettext('The filename cannot contain the following characters: %{c}'),
-              {c: '& &quot; ? < > # {} % ~ / \\'}
-          )}] },
-        ]"
-                    :placeholder="$gettext('Database (Optional, default: database)')"
-                >
-                    <a-icon slot="prefix" type="database" style="color: rgba(0,0,0,.25)"/>
-                </a-input>
-            </a-form-item>
-            <a-form-item>
-                <a-button type="primary" :block="true" html-type="submit" :loading="loading">
-                    <translate>Install</translate>
-                </a-button>
-            </a-form-item>
-        </a-form>
-        <footer>
-            Copyright © 2020 - {{ thisYear }} Nginx UI | Language
-            <set-language class="set_lang" style="display: inline"/>
-        </footer>
-    </div>
-
-</template>
-
-<script>
-import SetLanguage from '@/components/SetLanguage/SetLanguage'
-
-export default {
-    name: 'Login',
-    components: {SetLanguage},
-    data() {
-        return {
-            form: {},
-            lock: true,
-            thisYear: new Date().getFullYear(),
-            loading: false
-        }
-    },
-    created() {
-        this.form = this.$form.createForm(this)
-    },
-    mounted() {
-        this.$api.install.get_lock().then(r => {
-            if (r.lock) {
-                this.$router.push('/login')
-            }
-        })
-    },
-    methods: {
-        handleSubmit: async function (e) {
-            e.preventDefault()
-            this.loading = true
-            await this.form.validateFields(async (err, values) => {
-                if (!err) {
-                    this.$api.install.install_nginx_ui(values).then(() => {
-                        this.$router.push('/login')
-                    })
-                }
-                this.loading = false
-            })
-        },
-    },
-}
-</script>
-<style lang="less">
-.project-title {
-    margin: 50px;
-
-    h1 {
-        font-size: 50px;
-        font-weight: 100;
-        text-align: center;
-    }
-}
-
-.login-form {
-    max-width: 500px;
-    margin: 0 auto;
-}
-
-.login-form-button {
-
-}
-
-footer {
-    padding: 30px;
-    text-align: center;
-}
-</style>

+ 0 - 132
frontend-next/src/views/other/Login.vue

@@ -1,132 +0,0 @@
-<script setup lang="ts">
-const thisYear = new Date().getFullYear()
-
-import {LockOutlined, UserOutlined} from '@ant-design/icons-vue'
-import {reactive, ref} from 'vue'
-import {useRoute, useRouter} from 'vue-router'
-import gettext from '@/gettext'
-import {Form, message} from 'ant-design-vue'
-import auth from '@/api/auth'
-
-const route = useRoute()
-const router = useRouter()
-
-const {$gettext} = gettext
-const loading = ref(false)
-
-const modelRef = reactive({
-    username: '',
-    password: ''
-})
-
-const rulesRef = reactive({
-    username: [
-        {
-            required: true,
-            message: $gettext('Please input your username!'),
-        }
-    ],
-    password: [
-        {
-            required: true,
-            message: $gettext('Please input your password!'),
-        }
-    ]
-})
-
-const {validate, validateInfos} = Form.useForm(modelRef, rulesRef)
-
-const onSubmit = () => {
-    validate().then(() => {
-        // modelRef
-        auth.login(modelRef.username, modelRef.password).then(async () => {
-            message.success($gettext('Login successful'), 1)
-            const next = (route.query?.next || '').toString() || '/'
-            await router.push(next)
-        }).catch(e => {
-            message.error(e.message)
-        })
-    })
-}
-
-</script>
-
-<template>
-    <div class="container">
-        <div class="login-form">
-            <div class="project-title">
-                <h1>Nginx UI</h1>
-            </div>
-            <a-form id="components-form-demo-normal-login">
-                <a-form-item v-bind="validateInfos.username">
-                    <a-input
-                        v-model:value="modelRef.username"
-                        :placeholder="$gettext('Username')"
-                    >
-                        <template #prefix>
-                            <UserOutlined style="color: rgba(0, 0, 0, 0.25)"/>
-                        </template>
-                    </a-input>
-                </a-form-item>
-                <a-form-item v-bind="validateInfos.password">
-                    <a-input-password
-                        v-model:value="modelRef.password"
-                        :placeholder="$gettext('Password')"
-                    >
-                        <template #prefix>
-                            <LockOutlined style="color: rgba(0, 0, 0, 0.25)"/>
-                        </template>
-                    </a-input-password>
-                </a-form-item>
-                <a-form-item>
-                    <a-button @click="onSubmit" type="primary" :block="true" html-type="submit" :loading="loading">
-                        <translate>Login</translate>
-                    </a-button>
-                </a-form-item>
-            </a-form>
-            <div class="footer">
-                <p>Copyright © 2020 - {{ thisYear }} Nginx UI</p>
-                Language
-                <set-language class="set_lang" style="display: inline"/>
-            </div>
-        </div>
-    </div>
-</template>
-
-<style lang="less">
-.container {
-    display: flex;
-    align-items: center;
-    justify-content: center;
-    height: 100%;
-
-    .login-form {
-        max-width: 400px;
-        width: 80%;
-
-        .project-title {
-            margin: 50px;
-
-            h1 {
-                font-size: 50px;
-                font-weight: 100;
-                text-align: center;
-            }
-        }
-
-        .anticon {
-            color: #a8a5a5 !important;
-        }
-
-        .login-form-button {
-
-        }
-
-        .footer {
-            padding: 30px;
-            text-align: center;
-        }
-    }
-}
-
-</style>

+ 0 - 102
frontend-next/src/views/pty/Terminal.vue

@@ -1,102 +0,0 @@
-<script setup lang="ts">
-import 'xterm/css/xterm.css'
-import {Terminal} from 'xterm'
-import {FitAddon} from 'xterm-addon-fit'
-import {onMounted, onUnmounted} from 'vue'
-import _ from 'lodash'
-import ws from '@/lib/websocket'
-
-let term: Terminal | null
-let ping: null | NodeJS.Timer
-
-
-const websocket = ws('/api/pty')
-
-onMounted(() => {
-    initTerm()
-
-    websocket.onmessage = wsOnMessage
-    websocket.onopen = wsOnOpen
-})
-
-interface Message {
-    Type: Number,
-    Data: any | null
-}
-
-const fitAddon = new FitAddon()
-
-const fit = _.throttle(function () {
-    fitAddon.fit()
-}, 50)
-
-function initTerm() {
-    term = new Terminal({
-        rendererType: 'canvas',
-        convertEol: true,
-        fontSize: 14,
-        cursorStyle: 'block',
-        scrollback: 1000,
-        theme: {
-            background: 'rgba(3,14,32,0.7)'
-        },
-    })
-
-    term.loadAddon(fitAddon)
-    // this.fitAddon = fitAddon
-    term.open(document.getElementById('terminal')!)
-    setTimeout(() => {
-        fitAddon.fit()
-    }, 60)
-    window.addEventListener('resize', fit)
-    term.focus()
-
-    term.onData(function (key) {
-        let order: Message = {
-            Data: key,
-            Type: 1
-        }
-        sendMessage(order)
-    })
-    term.onBinary(data => {
-        sendMessage({Type: 1, Data: data})
-    })
-    term.onResize(data => {
-        sendMessage({Type: 2, Data: {Cols: data.cols, Rows: data.rows}})
-    })
-}
-
-function sendMessage(data: Message) {
-    websocket.send(JSON.stringify(data))
-}
-
-function wsOnMessage(msg: { data: any }) {
-    term!.write(msg.data)
-}
-
-function wsOnOpen() {
-    ping = setInterval(function () {
-        sendMessage({Type: 3, Data: null})
-    }, 30000)
-}
-
-onUnmounted(() => {
-    window.removeEventListener('resize', fit)
-    clearInterval(ping!)
-    ping = null
-    websocket.close()
-})
-
-</script>
-
-<template>
-    <a-card :title="$gettext('Terminal')">
-        <div class="console" id="terminal"></div>
-    </a-card>
-</template>
-
-<style lang="less" scoped>
-.console {
-    min-height: calc(100vh - 300px);
-}
-</style>

+ 0 - 52
frontend-next/src/views/user/User.vue

@@ -1,52 +0,0 @@
-<script setup lang="ts">
-import StdCurd from '@/components/StdDataDisplay/StdCurd.vue'
-import gettext from '@/gettext'
-import user from '@/api/user'
-import {datetime} from '@/components/StdDataDisplay/StdTableTransformer'
-
-const {$gettext} = gettext
-
-const columns = [{
-    title: $gettext('Username'),
-    dataIndex: 'name',
-    sorter: true,
-    pithy: true,
-    edit: {
-        type: 'input'
-    }
-}, {
-    title: $gettext('Password'),
-    dataIndex: 'password',
-    sorter: true,
-    pithy: true,
-    edit: {
-        type: 'input',
-        placeholder: $gettext('Leave blank for no change')
-    },
-    display: false
-}, {
-    title: $gettext('Created at'),
-    dataIndex: 'created_at',
-    customRender: datetime,
-    sorter: true,
-    pithy: true
-}, {
-    title: $gettext('Updated at'),
-    dataIndex: 'updated_at',
-    customRender: datetime,
-    sorter: true,
-    pithy: true
-}, {
-    title: $gettext('Action'),
-    dataIndex: 'action'
-}]
-</script>
-
-<template>
-    <std-curd :columns="columns" :api="user" :disable_search="true"/>
-</template>
-
-
-<style scoped>
-
-</style>

+ 0 - 1
frontend-next/version.json

@@ -1 +0,0 @@
-{"version":"1.5.0","build_id":9,"total_build":79}

+ 0 - 2703
frontend-next/yarn.lock

@@ -1,2703 +0,0 @@
-# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
-# yarn lockfile v1
-
-
-"@ampproject/remapping@^2.1.0":
-  version "2.2.0"
-  resolved "https://registry.yarnpkg.com/@ampproject/remapping/-/remapping-2.2.0.tgz#56c133824780de3174aed5ab6834f3026790154d"
-  integrity sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w==
-  dependencies:
-    "@jridgewell/gen-mapping" "^0.1.0"
-    "@jridgewell/trace-mapping" "^0.3.9"
-
-"@ant-design/colors@^6.0.0":
-  version "6.0.0"
-  resolved "https://registry.yarnpkg.com/@ant-design/colors/-/colors-6.0.0.tgz#9b9366257cffcc47db42b9d0203bb592c13c0298"
-  integrity sha512-qAZRvPzfdWHtfameEGP2Qvuf838NhergR35o+EuVyB5XvSA98xod5r4utvi4TJ3ywmevm290g9nsCG5MryrdWQ==
-  dependencies:
-    "@ctrl/tinycolor" "^3.4.0"
-
-"@ant-design/icons-svg@^4.2.1":
-  version "4.2.1"
-  resolved "https://registry.yarnpkg.com/@ant-design/icons-svg/-/icons-svg-4.2.1.tgz#8630da8eb4471a4aabdaed7d1ff6a97dcb2cf05a"
-  integrity sha512-EB0iwlKDGpG93hW8f85CTJTs4SvMX7tt5ceupvhALp1IF44SeUFOMhKUOYqpsoYWQKAOuTRDMqn75rEaKDp0Xw==
-
-"@ant-design/icons-vue@^6.1.0":
-  version "6.1.0"
-  resolved "https://registry.yarnpkg.com/@ant-design/icons-vue/-/icons-vue-6.1.0.tgz#f9324fdc0eb4cea943cf626d2bf3db9a4ff4c074"
-  integrity sha512-EX6bYm56V+ZrKN7+3MT/ubDkvJ5rK/O2t380WFRflDcVFgsvl3NLH7Wxeau6R8DbrO5jWR6DSTC3B6gYFp77AA==
-  dependencies:
-    "@ant-design/colors" "^6.0.0"
-    "@ant-design/icons-svg" "^4.2.1"
-
-"@antfu/utils@^0.5.2":
-  version "0.5.2"
-  resolved "https://registry.yarnpkg.com/@antfu/utils/-/utils-0.5.2.tgz#8c2d931ff927be0ebe740169874a3d4004ab414b"
-  integrity sha512-CQkeV+oJxUazwjlHD0/3ZD08QWKuGQkhnrKo3e6ly5pd48VUpXbb77q0xMU4+vc2CkJnDS02Eq/M9ugyX20XZA==
-
-"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.18.6":
-  version "7.18.6"
-  resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.18.6.tgz#3b25d38c89600baa2dcc219edfa88a74eb2c427a"
-  integrity sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==
-  dependencies:
-    "@babel/highlight" "^7.18.6"
-
-"@babel/compat-data@^7.18.8":
-  version "7.18.8"
-  resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.18.8.tgz#2483f565faca607b8535590e84e7de323f27764d"
-  integrity sha512-HSmX4WZPPK3FUxYp7g2T6EyO8j96HlZJlxmKPSh6KAcqwyDrfx7hKjXpAW/0FhFfTJsR0Yt4lAjLI2coMptIHQ==
-
-"@babel/core@^7.18.6":
-  version "7.18.9"
-  resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.18.9.tgz#805461f967c77ff46c74ca0460ccf4fe933ddd59"
-  integrity sha512-1LIb1eL8APMy91/IMW+31ckrfBM4yCoLaVzoDhZUKSM4cu1L1nIidyxkCgzPAgrC5WEz36IPEr/eSeSF9pIn+g==
-  dependencies:
-    "@ampproject/remapping" "^2.1.0"
-    "@babel/code-frame" "^7.18.6"
-    "@babel/generator" "^7.18.9"
-    "@babel/helper-compilation-targets" "^7.18.9"
-    "@babel/helper-module-transforms" "^7.18.9"
-    "@babel/helpers" "^7.18.9"
-    "@babel/parser" "^7.18.9"
-    "@babel/template" "^7.18.6"
-    "@babel/traverse" "^7.18.9"
-    "@babel/types" "^7.18.9"
-    convert-source-map "^1.7.0"
-    debug "^4.1.0"
-    gensync "^1.0.0-beta.2"
-    json5 "^2.2.1"
-    semver "^6.3.0"
-
-"@babel/generator@^7.18.9":
-  version "7.18.9"
-  resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.18.9.tgz#68337e9ea8044d6ddc690fb29acae39359cca0a5"
-  integrity sha512-wt5Naw6lJrL1/SGkipMiFxJjtyczUWTP38deiP1PO60HsBjDeKk08CGC3S8iVuvf0FmTdgKwU1KIXzSKL1G0Ug==
-  dependencies:
-    "@babel/types" "^7.18.9"
-    "@jridgewell/gen-mapping" "^0.3.2"
-    jsesc "^2.5.1"
-
-"@babel/helper-annotate-as-pure@^7.18.6":
-  version "7.18.6"
-  resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.18.6.tgz#eaa49f6f80d5a33f9a5dd2276e6d6e451be0a6bb"
-  integrity sha512-duORpUiYrEpzKIop6iNbjnwKLAKnJ47csTyRACyEmWj0QdUrm5aqNJGHSSEQSUAvNW0ojX0dOmK9dZduvkfeXA==
-  dependencies:
-    "@babel/types" "^7.18.6"
-
-"@babel/helper-compilation-targets@^7.18.9":
-  version "7.18.9"
-  resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.18.9.tgz#69e64f57b524cde3e5ff6cc5a9f4a387ee5563bf"
-  integrity sha512-tzLCyVmqUiFlcFoAPLA/gL9TeYrF61VLNtb+hvkuVaB5SUjW7jcfrglBIX1vUIoT7CLP3bBlIMeyEsIl2eFQNg==
-  dependencies:
-    "@babel/compat-data" "^7.18.8"
-    "@babel/helper-validator-option" "^7.18.6"
-    browserslist "^4.20.2"
-    semver "^6.3.0"
-
-"@babel/helper-create-class-features-plugin@^7.18.6":
-  version "7.18.9"
-  resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.18.9.tgz#d802ee16a64a9e824fcbf0a2ffc92f19d58550ce"
-  integrity sha512-WvypNAYaVh23QcjpMR24CwZY2Nz6hqdOcFdPbNpV56hL5H6KiFheO7Xm1aPdlLQ7d5emYZX7VZwPp9x3z+2opw==
-  dependencies:
-    "@babel/helper-annotate-as-pure" "^7.18.6"
-    "@babel/helper-environment-visitor" "^7.18.9"
-    "@babel/helper-function-name" "^7.18.9"
-    "@babel/helper-member-expression-to-functions" "^7.18.9"
-    "@babel/helper-optimise-call-expression" "^7.18.6"
-    "@babel/helper-replace-supers" "^7.18.9"
-    "@babel/helper-split-export-declaration" "^7.18.6"
-
-"@babel/helper-environment-visitor@^7.18.9":
-  version "7.18.9"
-  resolved "https://registry.yarnpkg.com/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.9.tgz#0c0cee9b35d2ca190478756865bb3528422f51be"
-  integrity sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg==
-
-"@babel/helper-function-name@^7.18.9":
-  version "7.18.9"
-  resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.18.9.tgz#940e6084a55dee867d33b4e487da2676365e86b0"
-  integrity sha512-fJgWlZt7nxGksJS9a0XdSaI4XvpExnNIgRP+rVefWh5U7BL8pPuir6SJUmFKRfjWQ51OtWSzwOxhaH/EBWWc0A==
-  dependencies:
-    "@babel/template" "^7.18.6"
-    "@babel/types" "^7.18.9"
-
-"@babel/helper-hoist-variables@^7.18.6":
-  version "7.18.6"
-  resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz#d4d2c8fb4baeaa5c68b99cc8245c56554f926678"
-  integrity sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q==
-  dependencies:
-    "@babel/types" "^7.18.6"
-
-"@babel/helper-member-expression-to-functions@^7.18.9":
-  version "7.18.9"
-  resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.18.9.tgz#1531661e8375af843ad37ac692c132841e2fd815"
-  integrity sha512-RxifAh2ZoVU67PyKIO4AMi1wTenGfMR/O/ae0CCRqwgBAt5v7xjdtRw7UoSbsreKrQn5t7r89eruK/9JjYHuDg==
-  dependencies:
-    "@babel/types" "^7.18.9"
-
-"@babel/helper-module-imports@^7.0.0", "@babel/helper-module-imports@^7.18.6":
-  version "7.18.6"
-  resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.18.6.tgz#1e3ebdbbd08aad1437b428c50204db13c5a3ca6e"
-  integrity sha512-0NFvs3VkuSYbFi1x2Vd6tKrywq+z/cLeYC/RJNFrIX/30Bf5aiGYbtvGXolEktzJH8o5E5KJ3tT+nkxuuZFVlA==
-  dependencies:
-    "@babel/types" "^7.18.6"
-
-"@babel/helper-module-transforms@^7.18.9":
-  version "7.18.9"
-  resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.18.9.tgz#5a1079c005135ed627442df31a42887e80fcb712"
-  integrity sha512-KYNqY0ICwfv19b31XzvmI/mfcylOzbLtowkw+mfvGPAQ3kfCnMLYbED3YecL5tPd8nAYFQFAd6JHp2LxZk/J1g==
-  dependencies:
-    "@babel/helper-environment-visitor" "^7.18.9"
-    "@babel/helper-module-imports" "^7.18.6"
-    "@babel/helper-simple-access" "^7.18.6"
-    "@babel/helper-split-export-declaration" "^7.18.6"
-    "@babel/helper-validator-identifier" "^7.18.6"
-    "@babel/template" "^7.18.6"
-    "@babel/traverse" "^7.18.9"
-    "@babel/types" "^7.18.9"
-
-"@babel/helper-optimise-call-expression@^7.18.6":
-  version "7.18.6"
-  resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.18.6.tgz#9369aa943ee7da47edab2cb4e838acf09d290ffe"
-  integrity sha512-HP59oD9/fEHQkdcbgFCnbmgH5vIQTJbxh2yf+CdM89/glUNnuzr87Q8GIjGEnOktTROemO0Pe0iPAYbqZuOUiA==
-  dependencies:
-    "@babel/types" "^7.18.6"
-
-"@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.18.6":
-  version "7.18.9"
-  resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.18.9.tgz#4b8aea3b069d8cb8a72cdfe28ddf5ceca695ef2f"
-  integrity sha512-aBXPT3bmtLryXaoJLyYPXPlSD4p1ld9aYeR+sJNOZjJJGiOpb+fKfh3NkcCu7J54nUJwCERPBExCCpyCOHnu/w==
-
-"@babel/helper-replace-supers@^7.18.9":
-  version "7.18.9"
-  resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.18.9.tgz#1092e002feca980fbbb0bd4d51b74a65c6a500e6"
-  integrity sha512-dNsWibVI4lNT6HiuOIBr1oyxo40HvIVmbwPUm3XZ7wMh4k2WxrxTqZwSqw/eEmXDS9np0ey5M2bz9tBmO9c+YQ==
-  dependencies:
-    "@babel/helper-environment-visitor" "^7.18.9"
-    "@babel/helper-member-expression-to-functions" "^7.18.9"
-    "@babel/helper-optimise-call-expression" "^7.18.6"
-    "@babel/traverse" "^7.18.9"
-    "@babel/types" "^7.18.9"
-
-"@babel/helper-simple-access@^7.18.6":
-  version "7.18.6"
-  resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.18.6.tgz#d6d8f51f4ac2978068df934b569f08f29788c7ea"
-  integrity sha512-iNpIgTgyAvDQpDj76POqg+YEt8fPxx3yaNBg3S30dxNKm2SWfYhD0TGrK/Eu9wHpUW63VQU894TsTg+GLbUa1g==
-  dependencies:
-    "@babel/types" "^7.18.6"
-
-"@babel/helper-split-export-declaration@^7.18.6":
-  version "7.18.6"
-  resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz#7367949bc75b20c6d5a5d4a97bba2824ae8ef075"
-  integrity sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA==
-  dependencies:
-    "@babel/types" "^7.18.6"
-
-"@babel/helper-validator-identifier@^7.18.6":
-  version "7.18.6"
-  resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.18.6.tgz#9c97e30d31b2b8c72a1d08984f2ca9b574d7a076"
-  integrity sha512-MmetCkz9ej86nJQV+sFCxoGGrUbU3q02kgLciwkrt9QqEB7cP39oKEY0PakknEO0Gu20SskMRi+AYZ3b1TpN9g==
-
-"@babel/helper-validator-option@^7.18.6":
-  version "7.18.6"
-  resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.18.6.tgz#bf0d2b5a509b1f336099e4ff36e1a63aa5db4db8"
-  integrity sha512-XO7gESt5ouv/LRJdrVjkShckw6STTaB7l9BrpBaAHDeF5YZT+01PCwmR0SJHnkW6i8OwW/EVWRShfi4j2x+KQw==
-
-"@babel/helpers@^7.18.9":
-  version "7.18.9"
-  resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.18.9.tgz#4bef3b893f253a1eced04516824ede94dcfe7ff9"
-  integrity sha512-Jf5a+rbrLoR4eNdUmnFu8cN5eNJT6qdTdOg5IHIzq87WwyRw9PwguLFOWYgktN/60IP4fgDUawJvs7PjQIzELQ==
-  dependencies:
-    "@babel/template" "^7.18.6"
-    "@babel/traverse" "^7.18.9"
-    "@babel/types" "^7.18.9"
-
-"@babel/highlight@^7.18.6":
-  version "7.18.6"
-  resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.18.6.tgz#81158601e93e2563795adcbfbdf5d64be3f2ecdf"
-  integrity sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==
-  dependencies:
-    "@babel/helper-validator-identifier" "^7.18.6"
-    chalk "^2.0.0"
-    js-tokens "^4.0.0"
-
-"@babel/parser@^7.16.4", "@babel/parser@^7.18.6", "@babel/parser@^7.18.9":
-  version "7.18.9"
-  resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.18.9.tgz#f2dde0c682ccc264a9a8595efd030a5cc8fd2539"
-  integrity sha512-9uJveS9eY9DJ0t64YbIBZICtJy8a5QrDEVdiLCG97fVLpDTpGX7t8mMSb6OWw6Lrnjqj4O8zwjELX3dhoMgiBg==
-
-"@babel/plugin-syntax-import-meta@^7.10.4":
-  version "7.10.4"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz#ee601348c370fa334d2207be158777496521fd51"
-  integrity sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==
-  dependencies:
-    "@babel/helper-plugin-utils" "^7.10.4"
-
-"@babel/plugin-syntax-jsx@^7.0.0":
-  version "7.18.6"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.18.6.tgz#a8feef63b010150abd97f1649ec296e849943ca0"
-  integrity sha512-6mmljtAedFGTWu2p/8WIORGwy+61PLgOMPOdazc7YoJ9ZCWUyFy3A6CpPkRKLKD1ToAesxX8KGEViAiLo9N+7Q==
-  dependencies:
-    "@babel/helper-plugin-utils" "^7.18.6"
-
-"@babel/plugin-syntax-typescript@^7.18.6":
-  version "7.18.6"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.18.6.tgz#1c09cd25795c7c2b8a4ba9ae49394576d4133285"
-  integrity sha512-mAWAuq4rvOepWCBid55JuRNvpTNf2UGVgoz4JV0fXEKolsVZDzsa4NqCef758WZJj/GDu0gVGItjKFiClTAmZA==
-  dependencies:
-    "@babel/helper-plugin-utils" "^7.18.6"
-
-"@babel/plugin-transform-typescript@^7.18.8":
-  version "7.18.8"
-  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.18.8.tgz#303feb7a920e650f2213ef37b36bbf327e6fa5a0"
-  integrity sha512-p2xM8HI83UObjsZGofMV/EdYjamsDm6MoN3hXPYIT0+gxIoopE+B7rPYKAxfrz9K9PK7JafTTjqYC6qipLExYA==
-  dependencies:
-    "@babel/helper-create-class-features-plugin" "^7.18.6"
-    "@babel/helper-plugin-utils" "^7.18.6"
-    "@babel/plugin-syntax-typescript" "^7.18.6"
-
-"@babel/runtime@^7.10.5":
-  version "7.18.9"
-  resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.18.9.tgz#b4fcfce55db3d2e5e080d2490f608a3b9f407f4a"
-  integrity sha512-lkqXDcvlFT5rvEjiu6+QYO+1GXrEHRo2LOtS7E4GtX5ESIZOgepqsZBVIj6Pv+a6zqsya9VCgiK1KAK4BvJDAw==
-  dependencies:
-    regenerator-runtime "^0.13.4"
-
-"@babel/template@^7.0.0", "@babel/template@^7.18.6":
-  version "7.18.6"
-  resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.18.6.tgz#1283f4993e00b929d6e2d3c72fdc9168a2977a31"
-  integrity sha512-JoDWzPe+wgBsTTgdnIma3iHNFC7YVJoPssVBDjiHfNlyt4YcunDtcDOUmfVDfCK5MfdsaIoX9PkijPhjH3nYUw==
-  dependencies:
-    "@babel/code-frame" "^7.18.6"
-    "@babel/parser" "^7.18.6"
-    "@babel/types" "^7.18.6"
-
-"@babel/traverse@^7.0.0", "@babel/traverse@^7.18.9":
-  version "7.18.9"
-  resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.18.9.tgz#deeff3e8f1bad9786874cb2feda7a2d77a904f98"
-  integrity sha512-LcPAnujXGwBgv3/WHv01pHtb2tihcyW1XuL9wd7jqh1Z8AQkTd+QVjMrMijrln0T7ED3UXLIy36P9Ao7W75rYg==
-  dependencies:
-    "@babel/code-frame" "^7.18.6"
-    "@babel/generator" "^7.18.9"
-    "@babel/helper-environment-visitor" "^7.18.9"
-    "@babel/helper-function-name" "^7.18.9"
-    "@babel/helper-hoist-variables" "^7.18.6"
-    "@babel/helper-split-export-declaration" "^7.18.6"
-    "@babel/parser" "^7.18.9"
-    "@babel/types" "^7.18.9"
-    debug "^4.1.0"
-    globals "^11.1.0"
-
-"@babel/types@^7.0.0", "@babel/types@^7.18.6", "@babel/types@^7.18.9":
-  version "7.18.9"
-  resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.18.9.tgz#7148d64ba133d8d73a41b3172ac4b83a1452205f"
-  integrity sha512-WwMLAg2MvJmt/rKEVQBBhIVffMmnilX4oe0sRe7iPOHIGsqpruFHHdrfj4O1CMMtgMtCU4oPafZjDPCRgO57Wg==
-  dependencies:
-    "@babel/helper-validator-identifier" "^7.18.6"
-    to-fast-properties "^2.0.0"
-
-"@ctrl/tinycolor@^3.4.0":
-  version "3.4.1"
-  resolved "https://registry.yarnpkg.com/@ctrl/tinycolor/-/tinycolor-3.4.1.tgz#75b4c27948c81e88ccd3a8902047bcd797f38d32"
-  integrity sha512-ej5oVy6lykXsvieQtqZxCOaLT+xD4+QNarq78cIYISHmZXshCvROLudpQN3lfL8G0NL7plMSSK+zlyvCaIJ4Iw==
-
-"@jridgewell/gen-mapping@^0.1.0":
-  version "0.1.1"
-  resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz#e5d2e450306a9491e3bd77e323e38d7aff315996"
-  integrity sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w==
-  dependencies:
-    "@jridgewell/set-array" "^1.0.0"
-    "@jridgewell/sourcemap-codec" "^1.4.10"
-
-"@jridgewell/gen-mapping@^0.3.0", "@jridgewell/gen-mapping@^0.3.2":
-  version "0.3.2"
-  resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz#c1aedc61e853f2bb9f5dfe6d4442d3b565b253b9"
-  integrity sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==
-  dependencies:
-    "@jridgewell/set-array" "^1.0.1"
-    "@jridgewell/sourcemap-codec" "^1.4.10"
-    "@jridgewell/trace-mapping" "^0.3.9"
-
-"@jridgewell/resolve-uri@^3.0.3":
-  version "3.1.0"
-  resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz#2203b118c157721addfe69d47b70465463066d78"
-  integrity sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==
-
-"@jridgewell/set-array@^1.0.0", "@jridgewell/set-array@^1.0.1":
-  version "1.1.2"
-  resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.1.2.tgz#7c6cf998d6d20b914c0a55a91ae928ff25965e72"
-  integrity sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==
-
-"@jridgewell/source-map@^0.3.2":
-  version "0.3.2"
-  resolved "https://registry.yarnpkg.com/@jridgewell/source-map/-/source-map-0.3.2.tgz#f45351aaed4527a298512ec72f81040c998580fb"
-  integrity sha512-m7O9o2uR8k2ObDysZYzdfhb08VuEml5oWGiosa1VdaPZ/A6QyPkAJuwN0Q1lhULOf6B7MtQmHENS743hWtCrgw==
-  dependencies:
-    "@jridgewell/gen-mapping" "^0.3.0"
-    "@jridgewell/trace-mapping" "^0.3.9"
-
-"@jridgewell/sourcemap-codec@^1.4.10":
-  version "1.4.14"
-  resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz#add4c98d341472a289190b424efbdb096991bb24"
-  integrity sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==
-
-"@jridgewell/trace-mapping@^0.3.9":
-  version "0.3.14"
-  resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.14.tgz#b231a081d8f66796e475ad588a1ef473112701ed"
-  integrity sha512-bJWEfQ9lPTvm3SneWwRFVLzrh6nhjwqw7TUFFBEMzwvg7t7PCDenf2lDwqo4NQXzdpgBXyFgDWnQA+2vkruksQ==
-  dependencies:
-    "@jridgewell/resolve-uri" "^3.0.3"
-    "@jridgewell/sourcemap-codec" "^1.4.10"
-
-"@nodelib/fs.scandir@2.1.5":
-  version "2.1.5"
-  resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5"
-  integrity sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==
-  dependencies:
-    "@nodelib/fs.stat" "2.0.5"
-    run-parallel "^1.1.9"
-
-"@nodelib/fs.stat@2.0.5", "@nodelib/fs.stat@^2.0.2":
-  version "2.0.5"
-  resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz#5bd262af94e9d25bd1e71b05deed44876a222e8b"
-  integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==
-
-"@nodelib/fs.walk@^1.2.3":
-  version "1.2.8"
-  resolved "https://registry.yarnpkg.com/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz#e95737e8bb6746ddedf69c556953494f196fe69a"
-  integrity sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==
-  dependencies:
-    "@nodelib/fs.scandir" "2.1.5"
-    fastq "^1.6.0"
-
-"@rollup/pluginutils@^4.2.0", "@rollup/pluginutils@^4.2.1":
-  version "4.2.1"
-  resolved "https://registry.yarnpkg.com/@rollup/pluginutils/-/pluginutils-4.2.1.tgz#e6c6c3aba0744edce3fb2074922d3776c0af2a6d"
-  integrity sha512-iKnFXr7NkdZAIHiIWE+BX5ULi/ucVFYWD6TbAV+rZctiRTY2PL6tsIKhoIOaoskiWAkgu+VsbXgUVDNLHf+InQ==
-  dependencies:
-    estree-walker "^2.0.1"
-    picomatch "^2.2.2"
-
-"@simonwep/pickr@~1.8.0":
-  version "1.8.2"
-  resolved "https://registry.yarnpkg.com/@simonwep/pickr/-/pickr-1.8.2.tgz#96dc86675940d7cad63d69c22083dd1cbb9797cb"
-  integrity sha512-/l5w8BIkrpP6n1xsetx9MWPWlU6OblN5YgZZphxan0Tq4BByTCETL6lyIeY8lagalS2Nbt4F2W034KHLIiunKA==
-  dependencies:
-    core-js "^3.15.1"
-    nanopop "^2.1.0"
-
-"@trysound/sax@0.2.0":
-  version "0.2.0"
-  resolved "https://registry.yarnpkg.com/@trysound/sax/-/sax-0.2.0.tgz#cccaab758af56761eb7bf37af6f03f326dd798ad"
-  integrity sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA==
-
-"@types/glob@5 - 7":
-  version "7.2.0"
-  resolved "https://registry.yarnpkg.com/@types/glob/-/glob-7.2.0.tgz#bc1b5bf3aa92f25bd5dd39f35c57361bdce5b2eb"
-  integrity sha512-ZUxbzKl0IfJILTS6t7ip5fQQM/J3TJYubDm3nMbgubNNYS62eXeUpoLUC8/7fJNiFYHTrGPQn7hspDUzIHX3UA==
-  dependencies:
-    "@types/minimatch" "*"
-    "@types/node" "*"
-
-"@types/lodash@^4.14.182":
-  version "4.14.182"
-  resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.182.tgz#05301a4d5e62963227eaafe0ce04dd77c54ea5c2"
-  integrity sha512-/THyiqyQAP9AfARo4pF+aCGcyiQ94tX/Is2I7HofNRqoYLgN1PBoOWu2/zTA5zMxzP5EFutMtWtGAFRKUe961Q==
-
-"@types/minimatch@*":
-  version "3.0.5"
-  resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.5.tgz#1001cc5e6a3704b83c236027e77f2f58ea010f40"
-  integrity sha512-Klz949h02Gz2uZCMGwDUSDS1YBlTdDDgbWHi+81l29tQALUtvz4rAYi5uoVhE5Lagoq6DeqAUlbrHvW/mXDgdQ==
-
-"@types/node@*", "@types/node@^18.6.3":
-  version "18.6.3"
-  resolved "https://registry.yarnpkg.com/@types/node/-/node-18.6.3.tgz#4e4a95b6fe44014563ceb514b2598b3e623d1c98"
-  integrity sha512-6qKpDtoaYLM+5+AFChLhHermMQxc3TOEFIDzrZLPRGHPrLEwqFkkT5Kx3ju05g6X7uDPazz3jHbKPX0KzCjntg==
-
-"@types/parse-json@^4.0.0":
-  version "4.0.0"
-  resolved "https://registry.yarnpkg.com/@types/parse-json/-/parse-json-4.0.0.tgz#2f8bb441434d163b35fb8ffdccd7138927ffb8c0"
-  integrity sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==
-
-"@types/parse5@^5":
-  version "5.0.3"
-  resolved "https://registry.yarnpkg.com/@types/parse5/-/parse5-5.0.3.tgz#e7b5aebbac150f8b5fdd4a46e7f0bd8e65e19109"
-  integrity sha512-kUNnecmtkunAoQ3CnjmMkzNU/gtxG8guhi+Fk2U/kOpIKjIMKnXGp4IJCgQJrXSgMsWYimYG4TGjz/UzbGEBTw==
-
-"@vitejs/plugin-vue-jsx@^2.0.0":
-  version "2.0.0"
-  resolved "https://registry.yarnpkg.com/@vitejs/plugin-vue-jsx/-/plugin-vue-jsx-2.0.0.tgz#9947c72f9ead40cb7950ba5a9e9f7ac4c5b74df1"
-  integrity sha512-WF9ApZ/ivyyW3volQfu0Td0KNPhcccYEaRNzNY1NxRLVJQLSX0nFqquv3e2g7MF74p1XZK4bGtDL2y5i5O5+1A==
-  dependencies:
-    "@babel/core" "^7.18.6"
-    "@babel/plugin-syntax-import-meta" "^7.10.4"
-    "@babel/plugin-transform-typescript" "^7.18.8"
-    "@vue/babel-plugin-jsx" "^1.1.1"
-
-"@vitejs/plugin-vue@^3.0.0":
-  version "3.0.1"
-  resolved "https://registry.yarnpkg.com/@vitejs/plugin-vue/-/plugin-vue-3.0.1.tgz#b6af8f782485374bbb5fe09edf067a845bf4caae"
-  integrity sha512-Ll9JgxG7ONIz/XZv3dssfoMUDu9qAnlJ+km+pBA0teYSXzwPCIzS/e1bmwNYl5dcQGs677D21amgfYAnzMl17A==
-
-"@volar/code-gen@0.38.9":
-  version "0.38.9"
-  resolved "https://registry.yarnpkg.com/@volar/code-gen/-/code-gen-0.38.9.tgz#8fed2c6a472c8f11ce695b08789bcc22b08e7fa6"
-  integrity sha512-n6LClucfA+37rQeskvh9vDoZV1VvCVNy++MAPKj2dT4FT+Fbmty/SDQqnsEBtdEe6E3OQctFvA/IcKsx3Mns0A==
-  dependencies:
-    "@volar/source-map" "0.38.9"
-
-"@volar/source-map@0.38.9":
-  version "0.38.9"
-  resolved "https://registry.yarnpkg.com/@volar/source-map/-/source-map-0.38.9.tgz#935d6def4b4342e8e2d63cd8e6bf9bf1155c58d8"
-  integrity sha512-ba0UFoHDYry+vwKdgkWJ6xlQT+8TFtZg1zj9tSjj4PykW1JZDuM0xplMotLun4h3YOoYfY9K1huY5gvxmrNLIw==
-
-"@volar/vue-code-gen@0.38.9":
-  version "0.38.9"
-  resolved "https://registry.yarnpkg.com/@volar/vue-code-gen/-/vue-code-gen-0.38.9.tgz#878f00fec82a2fc300396d70e26b0ea29952f740"
-  integrity sha512-tzj7AoarFBKl7e41MR006ncrEmNPHALuk8aG4WdDIaG387X5//5KhWC5Ff3ZfB2InGSeNT+CVUd74M0gS20rjA==
-  dependencies:
-    "@volar/code-gen" "0.38.9"
-    "@volar/source-map" "0.38.9"
-    "@vue/compiler-core" "^3.2.37"
-    "@vue/compiler-dom" "^3.2.37"
-    "@vue/shared" "^3.2.37"
-
-"@volar/vue-typescript@0.38.9":
-  version "0.38.9"
-  resolved "https://registry.yarnpkg.com/@volar/vue-typescript/-/vue-typescript-0.38.9.tgz#e5dfdc6f0d6dbea683647cd477fafbd483983b35"
-  integrity sha512-iJMQGU91ADi98u8V1vXd2UBmELDAaeSP0ZJaFjwosClQdKlJQYc6MlxxKfXBZisHqfbhdtrGRyaryulnYtliZw==
-  dependencies:
-    "@volar/code-gen" "0.38.9"
-    "@volar/source-map" "0.38.9"
-    "@volar/vue-code-gen" "0.38.9"
-    "@vue/compiler-sfc" "^3.2.37"
-    "@vue/reactivity" "^3.2.37"
-
-"@vue/babel-helper-vue-transform-on@^1.0.2":
-  version "1.0.2"
-  resolved "https://registry.yarnpkg.com/@vue/babel-helper-vue-transform-on/-/babel-helper-vue-transform-on-1.0.2.tgz#9b9c691cd06fc855221a2475c3cc831d774bc7dc"
-  integrity sha512-hz4R8tS5jMn8lDq6iD+yWL6XNB699pGIVLk7WSJnn1dbpjaazsjZQkieJoRX6gW5zpYSCFqQ7jUquPNY65tQYA==
-
-"@vue/babel-plugin-jsx@^1.1.1":
-  version "1.1.1"
-  resolved "https://registry.yarnpkg.com/@vue/babel-plugin-jsx/-/babel-plugin-jsx-1.1.1.tgz#0c5bac27880d23f89894cd036a37b55ef61ddfc1"
-  integrity sha512-j2uVfZjnB5+zkcbc/zsOc0fSNGCMMjaEXP52wdwdIfn0qjFfEYpYZBFKFg+HHnQeJCVrjOeO0YxgaL7DMrym9w==
-  dependencies:
-    "@babel/helper-module-imports" "^7.0.0"
-    "@babel/plugin-syntax-jsx" "^7.0.0"
-    "@babel/template" "^7.0.0"
-    "@babel/traverse" "^7.0.0"
-    "@babel/types" "^7.0.0"
-    "@vue/babel-helper-vue-transform-on" "^1.0.2"
-    camelcase "^6.0.0"
-    html-tags "^3.1.0"
-    svg-tags "^1.0.0"
-
-"@vue/compiler-core@3.2.37", "@vue/compiler-core@^3.2.37":
-  version "3.2.37"
-  resolved "https://registry.yarnpkg.com/@vue/compiler-core/-/compiler-core-3.2.37.tgz#b3c42e04c0e0f2c496ff1784e543fbefe91e215a"
-  integrity sha512-81KhEjo7YAOh0vQJoSmAD68wLfYqJvoiD4ulyedzF+OEk/bk6/hx3fTNVfuzugIIaTrOx4PGx6pAiBRe5e9Zmg==
-  dependencies:
-    "@babel/parser" "^7.16.4"
-    "@vue/shared" "3.2.37"
-    estree-walker "^2.0.2"
-    source-map "^0.6.1"
-
-"@vue/compiler-dom@3.2.37", "@vue/compiler-dom@^3.2.37":
-  version "3.2.37"
-  resolved "https://registry.yarnpkg.com/@vue/compiler-dom/-/compiler-dom-3.2.37.tgz#10d2427a789e7c707c872da9d678c82a0c6582b5"
-  integrity sha512-yxJLH167fucHKxaqXpYk7x8z7mMEnXOw3G2q62FTkmsvNxu4FQSu5+3UMb+L7fjKa26DEzhrmCxAgFLLIzVfqQ==
-  dependencies:
-    "@vue/compiler-core" "3.2.37"
-    "@vue/shared" "3.2.37"
-
-"@vue/compiler-sfc@3.2.37", "@vue/compiler-sfc@^3.2.37":
-  version "3.2.37"
-  resolved "https://registry.yarnpkg.com/@vue/compiler-sfc/-/compiler-sfc-3.2.37.tgz#3103af3da2f40286edcd85ea495dcb35bc7f5ff4"
-  integrity sha512-+7i/2+9LYlpqDv+KTtWhOZH+pa8/HnX/905MdVmAcI/mPQOBwkHHIzrsEsucyOIZQYMkXUiTkmZq5am/NyXKkg==
-  dependencies:
-    "@babel/parser" "^7.16.4"
-    "@vue/compiler-core" "3.2.37"
-    "@vue/compiler-dom" "3.2.37"
-    "@vue/compiler-ssr" "3.2.37"
-    "@vue/reactivity-transform" "3.2.37"
-    "@vue/shared" "3.2.37"
-    estree-walker "^2.0.2"
-    magic-string "^0.25.7"
-    postcss "^8.1.10"
-    source-map "^0.6.1"
-
-"@vue/compiler-ssr@3.2.37":
-  version "3.2.37"
-  resolved "https://registry.yarnpkg.com/@vue/compiler-ssr/-/compiler-ssr-3.2.37.tgz#4899d19f3a5fafd61524a9d1aee8eb0505313cff"
-  integrity sha512-7mQJD7HdXxQjktmsWp/J67lThEIcxLemz1Vb5I6rYJHR5vI+lON3nPGOH3ubmbvYGt8xEUaAr1j7/tIFWiEOqw==
-  dependencies:
-    "@vue/compiler-dom" "3.2.37"
-    "@vue/shared" "3.2.37"
-
-"@vue/devtools-api@^6.0.0-beta.11", "@vue/devtools-api@^6.1.4", "@vue/devtools-api@^6.2.1":
-  version "6.2.1"
-  resolved "https://registry.yarnpkg.com/@vue/devtools-api/-/devtools-api-6.2.1.tgz#6f2948ff002ec46df01420dfeff91de16c5b4092"
-  integrity sha512-OEgAMeQXvCoJ+1x8WyQuVZzFo0wcyCmUR3baRVLmKBo1LmYZWMlRiXlux5jd0fqVJu6PfDbOrZItVqUEzLobeQ==
-
-"@vue/reactivity-transform@3.2.37":
-  version "3.2.37"
-  resolved "https://registry.yarnpkg.com/@vue/reactivity-transform/-/reactivity-transform-3.2.37.tgz#0caa47c4344df4ae59f5a05dde2a8758829f8eca"
-  integrity sha512-IWopkKEb+8qpu/1eMKVeXrK0NLw9HicGviJzhJDEyfxTR9e1WtpnnbYkJWurX6WwoFP0sz10xQg8yL8lgskAZg==
-  dependencies:
-    "@babel/parser" "^7.16.4"
-    "@vue/compiler-core" "3.2.37"
-    "@vue/shared" "3.2.37"
-    estree-walker "^2.0.2"
-    magic-string "^0.25.7"
-
-"@vue/reactivity@3.2.37", "@vue/reactivity@^3.2.37":
-  version "3.2.37"
-  resolved "https://registry.yarnpkg.com/@vue/reactivity/-/reactivity-3.2.37.tgz#5bc3847ac58828e2b78526e08219e0a1089f8848"
-  integrity sha512-/7WRafBOshOc6m3F7plwzPeCu/RCVv9uMpOwa/5PiY1Zz+WLVRWiy0MYKwmg19KBdGtFWsmZ4cD+LOdVPcs52A==
-  dependencies:
-    "@vue/shared" "3.2.37"
-
-"@vue/runtime-core@3.2.37":
-  version "3.2.37"
-  resolved "https://registry.yarnpkg.com/@vue/runtime-core/-/runtime-core-3.2.37.tgz#7ba7c54bb56e5d70edfc2f05766e1ca8519966e3"
-  integrity sha512-JPcd9kFyEdXLl/i0ClS7lwgcs0QpUAWj+SKX2ZC3ANKi1U4DOtiEr6cRqFXsPwY5u1L9fAjkinIdB8Rz3FoYNQ==
-  dependencies:
-    "@vue/reactivity" "3.2.37"
-    "@vue/shared" "3.2.37"
-
-"@vue/runtime-dom@3.2.37":
-  version "3.2.37"
-  resolved "https://registry.yarnpkg.com/@vue/runtime-dom/-/runtime-dom-3.2.37.tgz#002bdc8228fa63949317756fb1e92cdd3f9f4bbd"
-  integrity sha512-HimKdh9BepShW6YozwRKAYjYQWg9mQn63RGEiSswMbW+ssIht1MILYlVGkAGGQbkhSh31PCdoUcfiu4apXJoPw==
-  dependencies:
-    "@vue/runtime-core" "3.2.37"
-    "@vue/shared" "3.2.37"
-    csstype "^2.6.8"
-
-"@vue/server-renderer@3.2.37":
-  version "3.2.37"
-  resolved "https://registry.yarnpkg.com/@vue/server-renderer/-/server-renderer-3.2.37.tgz#840a29c8dcc29bddd9b5f5ffa22b95c0e72afdfc"
-  integrity sha512-kLITEJvaYgZQ2h47hIzPh2K3jG8c1zCVbp/o/bzQOyvzaKiCquKS7AaioPI28GNxIsE/zSx+EwWYsNxDCX95MA==
-  dependencies:
-    "@vue/compiler-ssr" "3.2.37"
-    "@vue/shared" "3.2.37"
-
-"@vue/shared@3.2.37", "@vue/shared@^3.2.37":
-  version "3.2.37"
-  resolved "https://registry.yarnpkg.com/@vue/shared/-/shared-3.2.37.tgz#8e6adc3f2759af52f0e85863dfb0b711ecc5c702"
-  integrity sha512-4rSJemR2NQIo9Klm1vabqWjD8rs/ZaJSzMxkMNeJS6lHiUjjUeYFbooN19NgFjztubEKh3WlZUeOLVdbbUWHsw==
-
-"@zougt/some-loader-utils@^1.4.3":
-  version "1.4.3"
-  resolved "https://registry.yarnpkg.com/@zougt/some-loader-utils/-/some-loader-utils-1.4.3.tgz#41cf762b291ab9697f8c008bdeebaf80eaee4714"
-  integrity sha512-0FsoqSTQ+qOyp6x5Q6LZQ7xVwquEgLYiIStG3L8p0Q2GsGGYKDkOZ0mIpMt67aNdr8XLsbxXjzTl/iHtTz5zcA==
-  dependencies:
-    cac "^6.7.12"
-    color "^4.0.1"
-    cssnano "^5.0.11"
-    cssnano-preset-lite "^2.0.1"
-    fs-extra "^10.0.0"
-    postcss "^8.2.9"
-    prettier "^2.5.0"
-    uuid "^8.3.2"
-
-"@zougt/vite-plugin-theme-preprocessor@^1.4.5":
-  version "1.4.5"
-  resolved "https://registry.yarnpkg.com/@zougt/vite-plugin-theme-preprocessor/-/vite-plugin-theme-preprocessor-1.4.5.tgz#557b80592a5d131cb856338f0422b2df428566f9"
-  integrity sha512-pG+4Iz4rtA7AS+EZnRuoFler6SxlbL7ii6IqepQq1XWmGeZTzbRCjjYr9uteBYSdwHHW90A9gcAxhqadLXUnEg==
-  dependencies:
-    "@zougt/some-loader-utils" "^1.4.3"
-    cac "^6.7.12"
-    chalk "^5.0.0"
-    fs-extra "^10.0.0"
-    string-hash "^1.1.3"
-
-ace-builds@^1.4.13:
-  version "1.8.1"
-  resolved "https://registry.yarnpkg.com/ace-builds/-/ace-builds-1.8.1.tgz#5d318fa13d7e6ea947f8a50e42c570c573b29529"
-  integrity sha512-wjEQ4khMQYg9FfdEDoOtqdoHwcwFL48H0VB3te5b5A3eqHwxsTw8IX6+xzfisgborIb8dYU+1y9tcmtGFrCPIg==
-
-acorn@^8.5.0, acorn@^8.7.1:
-  version "8.8.0"
-  resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.8.0.tgz#88c0187620435c7f6015803f5539dae05a9dbea8"
-  integrity sha512-QOxyigPVrpZ2GXT+PFyZTl6TtOFc5egxHIP9IlQ+RbupQuX4RkT/Bee4/kQuC02Xkzg84JcT7oLYtDIQxp+v7w==
-
-ansi-styles@^3.2.1:
-  version "3.2.1"
-  resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d"
-  integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==
-  dependencies:
-    color-convert "^1.9.0"
-
-ansi-styles@^4.1.0:
-  version "4.3.0"
-  resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937"
-  integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==
-  dependencies:
-    color-convert "^2.0.1"
-
-ant-design-vue@^3.2.10:
-  version "3.2.10"
-  resolved "https://registry.yarnpkg.com/ant-design-vue/-/ant-design-vue-3.2.10.tgz#938260177126cf7ab0dc476dd9e3e9d06ab17bae"
-  integrity sha512-aqa0kjJzVQ74MfVw5w7rTOdJQL2JN9V/O6Ro+VQQMq/tY7q91JiomhI9TRKAK3tFdBDXJpUoBCVOsosbbxMzRw==
-  dependencies:
-    "@ant-design/colors" "^6.0.0"
-    "@ant-design/icons-vue" "^6.1.0"
-    "@babel/runtime" "^7.10.5"
-    "@ctrl/tinycolor" "^3.4.0"
-    "@simonwep/pickr" "~1.8.0"
-    array-tree-filter "^2.1.0"
-    async-validator "^4.0.0"
-    dayjs "^1.10.5"
-    dom-align "^1.12.1"
-    dom-scroll-into-view "^2.0.0"
-    lodash "^4.17.21"
-    lodash-es "^4.17.15"
-    resize-observer-polyfill "^1.5.1"
-    scroll-into-view-if-needed "^2.2.25"
-    shallow-equal "^1.0.0"
-    vue-types "^3.0.0"
-    warning "^4.0.0"
-
-anymatch@~3.1.2:
-  version "3.1.2"
-  resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.2.tgz#c0557c096af32f106198f4f4e2a383537e378716"
-  integrity sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==
-  dependencies:
-    normalize-path "^3.0.0"
-    picomatch "^2.0.4"
-
-apexcharts@^3.35.4:
-  version "3.35.4"
-  resolved "https://registry.yarnpkg.com/apexcharts/-/apexcharts-3.35.4.tgz#347140240fad6e646a76c7bc8e7e75294c2206b2"
-  integrity sha512-dsXjETHF2OmKtxNv66wBeFGU2qtZQnr6kp/vcNY05GWs4vcBepg54qNgOJ2Gp/gXskiGw/frrmIKGi8lJ/UDnQ==
-  dependencies:
-    svg.draggable.js "^2.2.2"
-    svg.easing.js "^2.0.0"
-    svg.filter.js "^2.0.2"
-    svg.pathmorphing.js "^0.1.3"
-    svg.resize.js "^1.4.3"
-    svg.select.js "^3.0.1"
-
-array-back@^3.0.1, array-back@^3.1.0:
-  version "3.1.0"
-  resolved "https://registry.yarnpkg.com/array-back/-/array-back-3.1.0.tgz#b8859d7a508871c9a7b2cf42f99428f65e96bfb0"
-  integrity sha512-TkuxA4UCOvxuDK6NZYXCalszEzj+TLszyASooky+i742l9TqsOdYCMJJupxRic61hwquNtppB3hgcuq9SVSH1Q==
-
-array-tree-filter@^2.1.0:
-  version "2.1.0"
-  resolved "https://registry.yarnpkg.com/array-tree-filter/-/array-tree-filter-2.1.0.tgz#873ac00fec83749f255ac8dd083814b4f6329190"
-  integrity sha512-4ROwICNlNw/Hqa9v+rk5h22KjmzB1JGTMVKP2AKJBOCgb0yL0ASf0+YvCcLNNwquOHNX48jkeZIJ3a+oOQqKcw==
-
-async-validator@^4.0.0:
-  version "4.2.5"
-  resolved "https://registry.yarnpkg.com/async-validator/-/async-validator-4.2.5.tgz#c96ea3332a521699d0afaaceed510a54656c6339"
-  integrity sha512-7HhHjtERjqlNbZtqNqy2rckN/SpOOlmDliet+lP7k+eKZEjPk3DgyeU9lIXLdeLz0uBbbVp+9Qdow9wJWgwwfg==
-
-async@^3.2.3:
-  version "3.2.4"
-  resolved "https://registry.yarnpkg.com/async/-/async-3.2.4.tgz#2d22e00f8cddeb5fde5dd33522b56d1cf569a81c"
-  integrity sha512-iAB+JbDEGXhyIUavoDl9WP/Jj106Kz9DEn1DPgYw5ruDn0e3Wgi3sKFm55sASdGBNOQB8F59d9qQ7deqrHA8wQ==
-
-asynckit@^0.4.0:
-  version "0.4.0"
-  resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79"
-  integrity sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==
-
-axios@^0.27.2:
-  version "0.27.2"
-  resolved "https://registry.yarnpkg.com/axios/-/axios-0.27.2.tgz#207658cc8621606e586c85db4b41a750e756d972"
-  integrity sha512-t+yRIyySRTp/wua5xEr+z1q60QmLq8ABsS5O9Me1AsE5dfKqgnCFzwiCZZ/cGNd1lq4/7akDWMxdhVlucjmnOQ==
-  dependencies:
-    follow-redirects "^1.14.9"
-    form-data "^4.0.0"
-
-balanced-match@^1.0.0:
-  version "1.0.2"
-  resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee"
-  integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==
-
-binary-extensions@^2.0.0:
-  version "2.2.0"
-  resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.2.0.tgz#75f502eeaf9ffde42fc98829645be4ea76bd9e2d"
-  integrity sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==
-
-boolbase@^1.0.0:
-  version "1.0.0"
-  resolved "https://registry.yarnpkg.com/boolbase/-/boolbase-1.0.0.tgz#68dff5fbe60c51eb37725ea9e3ed310dcc1e776e"
-  integrity sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==
-
-brace-expansion@^1.1.7:
-  version "1.1.11"
-  resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd"
-  integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==
-  dependencies:
-    balanced-match "^1.0.0"
-    concat-map "0.0.1"
-
-brace-expansion@^2.0.1:
-  version "2.0.1"
-  resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-2.0.1.tgz#1edc459e0f0c548486ecf9fc99f2221364b9a0ae"
-  integrity sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==
-  dependencies:
-    balanced-match "^1.0.0"
-
-braces@^3.0.2, braces@~3.0.2:
-  version "3.0.2"
-  resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107"
-  integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==
-  dependencies:
-    fill-range "^7.0.1"
-
-browserslist@^4.0.0, browserslist@^4.16.6, browserslist@^4.20.2, browserslist@^4.20.3:
-  version "4.21.3"
-  resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.21.3.tgz#5df277694eb3c48bc5c4b05af3e8b7e09c5a6d1a"
-  integrity sha512-898rgRXLAyRkM1GryrrBHGkqA5hlpkV5MhtZwg9QXeiyLUYs2k00Un05aX5l2/yJIOObYKOpS2JNo8nJDE7fWQ==
-  dependencies:
-    caniuse-lite "^1.0.30001370"
-    electron-to-chromium "^1.4.202"
-    node-releases "^2.0.6"
-    update-browserslist-db "^1.0.5"
-
-buffer-from@^1.0.0:
-  version "1.1.2"
-  resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5"
-  integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==
-
-cac@^6.7.12:
-  version "6.7.12"
-  resolved "https://registry.yarnpkg.com/cac/-/cac-6.7.12.tgz#6fb5ea2ff50bd01490dbda497f4ae75a99415193"
-  integrity sha512-rM7E2ygtMkJqD9c7WnFU6fruFcN3xe4FM5yUmgxhZzIKJk4uHl9U/fhwdajGFQbQuv43FAUo1Fe8gX/oIKDeSA==
-
-callsites@^3.0.0:
-  version "3.1.0"
-  resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73"
-  integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==
-
-camel-case@^4.1.2:
-  version "4.1.2"
-  resolved "https://registry.yarnpkg.com/camel-case/-/camel-case-4.1.2.tgz#9728072a954f805228225a6deea6b38461e1bd5a"
-  integrity sha512-gxGWBrTT1JuMx6R+o5PTXMmUnhnVzLQ9SNutD4YqKtI6ap897t3tKECYla6gCWEkplXnlNybEkZg9GEGxKFCgw==
-  dependencies:
-    pascal-case "^3.1.2"
-    tslib "^2.0.3"
-
-camelcase@^6.0.0:
-  version "6.3.0"
-  resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.3.0.tgz#5685b95eb209ac9c0c177467778c9c84df58ba9a"
-  integrity sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==
-
-caniuse-api@^3.0.0:
-  version "3.0.0"
-  resolved "https://registry.yarnpkg.com/caniuse-api/-/caniuse-api-3.0.0.tgz#5e4d90e2274961d46291997df599e3ed008ee4c0"
-  integrity sha512-bsTwuIg/BZZK/vreVTYYbSWoe2F+71P7K5QGEX+pT250DZbfU1MQ5prOKpPR+LL6uWKK3KMwMCAS74QB3Um1uw==
-  dependencies:
-    browserslist "^4.0.0"
-    caniuse-lite "^1.0.0"
-    lodash.memoize "^4.1.2"
-    lodash.uniq "^4.5.0"
-
-caniuse-lite@^1.0.0, caniuse-lite@^1.0.30001370:
-  version "1.0.30001373"
-  resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001373.tgz#2dc3bc3bfcb5d5a929bec11300883040d7b4b4be"
-  integrity sha512-pJYArGHrPp3TUqQzFYRmP/lwJlj8RCbVe3Gd3eJQkAV8SAC6b19XS9BjMvRdvaS8RMkaTN8ZhoHP6S1y8zzwEQ==
-
-chalk@^2.0.0:
-  version "2.4.2"
-  resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424"
-  integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==
-  dependencies:
-    ansi-styles "^3.2.1"
-    escape-string-regexp "^1.0.5"
-    supports-color "^5.3.0"
-
-chalk@^4.0.2, chalk@^4.1.2:
-  version "4.1.2"
-  resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01"
-  integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==
-  dependencies:
-    ansi-styles "^4.1.0"
-    supports-color "^7.1.0"
-
-chalk@^5.0.0:
-  version "5.0.1"
-  resolved "https://registry.yarnpkg.com/chalk/-/chalk-5.0.1.tgz#ca57d71e82bb534a296df63bbacc4a1c22b2a4b6"
-  integrity sha512-Fo07WOYGqMfCWHOzSXOt2CxDbC6skS/jO9ynEcmpANMoPrD+W1r1K6Vx7iNm+AQmETU1Xr2t+n8nzkV9t6xh3w==
-
-chokidar@^3.5.3:
-  version "3.5.3"
-  resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.3.tgz#1cf37c8707b932bd1af1ae22c0432e2acd1903bd"
-  integrity sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==
-  dependencies:
-    anymatch "~3.1.2"
-    braces "~3.0.2"
-    glob-parent "~5.1.2"
-    is-binary-path "~2.1.0"
-    is-glob "~4.0.1"
-    normalize-path "~3.0.0"
-    readdirp "~3.6.0"
-  optionalDependencies:
-    fsevents "~2.3.2"
-
-clean-css@^5.2.2:
-  version "5.3.1"
-  resolved "https://registry.yarnpkg.com/clean-css/-/clean-css-5.3.1.tgz#d0610b0b90d125196a2894d35366f734e5d7aa32"
-  integrity sha512-lCr8OHhiWCTw4v8POJovCoh4T7I9U11yVsPjMWWnnMmp9ZowCxyad1Pathle/9HjaDp+fdQKjO9fQydE6RHTZg==
-  dependencies:
-    source-map "~0.6.0"
-
-color-convert@^1.9.0:
-  version "1.9.3"
-  resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8"
-  integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==
-  dependencies:
-    color-name "1.1.3"
-
-color-convert@^2.0.1:
-  version "2.0.1"
-  resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3"
-  integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==
-  dependencies:
-    color-name "~1.1.4"
-
-color-name@1.1.3:
-  version "1.1.3"
-  resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25"
-  integrity sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==
-
-color-name@^1.0.0, color-name@~1.1.4:
-  version "1.1.4"
-  resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2"
-  integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==
-
-color-string@^1.9.0:
-  version "1.9.1"
-  resolved "https://registry.yarnpkg.com/color-string/-/color-string-1.9.1.tgz#4467f9146f036f855b764dfb5bf8582bf342c7a4"
-  integrity sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==
-  dependencies:
-    color-name "^1.0.0"
-    simple-swizzle "^0.2.2"
-
-color@^4.0.1:
-  version "4.2.3"
-  resolved "https://registry.yarnpkg.com/color/-/color-4.2.3.tgz#d781ecb5e57224ee43ea9627560107c0e0c6463a"
-  integrity sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==
-  dependencies:
-    color-convert "^2.0.1"
-    color-string "^1.9.0"
-
-colord@^2.9.1:
-  version "2.9.2"
-  resolved "https://registry.yarnpkg.com/colord/-/colord-2.9.2.tgz#25e2bacbbaa65991422c07ea209e2089428effb1"
-  integrity sha512-Uqbg+J445nc1TKn4FoDPS6ZZqAvEDnwrH42yo8B40JSOgSLxMZ/gt3h4nmCtPLQeXhjJJkqBx7SCY35WnIixaQ==
-
-colorette@^2.0.16:
-  version "2.0.19"
-  resolved "https://registry.yarnpkg.com/colorette/-/colorette-2.0.19.tgz#cdf044f47ad41a0f4b56b3a0d5b4e6e1a2d5a798"
-  integrity sha512-3tlv/dIP7FWvj3BsbHrGLJ6l/oKh1O3TcgBqMn+yyCagOxc23fyzDS6HypQbgxWbkpDnf52p1LuR4eWDQ/K9WQ==
-
-combined-stream@^1.0.8:
-  version "1.0.8"
-  resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f"
-  integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==
-  dependencies:
-    delayed-stream "~1.0.0"
-
-command-line-args@^5.2.1:
-  version "5.2.1"
-  resolved "https://registry.yarnpkg.com/command-line-args/-/command-line-args-5.2.1.tgz#c44c32e437a57d7c51157696893c5909e9cec42e"
-  integrity sha512-H4UfQhZyakIjC74I9d34fGYDwk3XpSr17QhEd0Q3I9Xq1CETHo4Hcuo87WyWHpAF1aSLjLRf5lD9ZGX2qStUvg==
-  dependencies:
-    array-back "^3.1.0"
-    find-replace "^3.0.0"
-    lodash.camelcase "^4.3.0"
-    typical "^4.0.0"
-
-commander@^2.20.0:
-  version "2.20.3"
-  resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33"
-  integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==
-
-commander@^7.2.0:
-  version "7.2.0"
-  resolved "https://registry.yarnpkg.com/commander/-/commander-7.2.0.tgz#a36cb57d0b501ce108e4d20559a150a391d97ab7"
-  integrity sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==
-
-commander@^8.3.0:
-  version "8.3.0"
-  resolved "https://registry.yarnpkg.com/commander/-/commander-8.3.0.tgz#4837ea1b2da67b9c616a67afbb0fafee567bca66"
-  integrity sha512-OkTL9umf+He2DZkUq8f8J9of7yL6RJKI24dVITBmNfZBmri9zYZQrKkuXiKhyfPSu8tUhnVBB1iKXevvnlR4Ww==
-
-compute-scroll-into-view@^1.0.17:
-  version "1.0.17"
-  resolved "https://registry.yarnpkg.com/compute-scroll-into-view/-/compute-scroll-into-view-1.0.17.tgz#6a88f18acd9d42e9cf4baa6bec7e0522607ab7ab"
-  integrity sha512-j4dx+Fb0URmzbwwMUrhqWM2BEWHdFGx+qZ9qqASHRPqvTYdqvWnHg0H1hIbcyLnvgnoNAVMlwkepyqM3DaIFUg==
-
-concat-map@0.0.1:
-  version "0.0.1"
-  resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
-  integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==
-
-connect-history-api-fallback@^1.6.0:
-  version "1.6.0"
-  resolved "https://registry.yarnpkg.com/connect-history-api-fallback/-/connect-history-api-fallback-1.6.0.tgz#8b32089359308d111115d81cad3fceab888f97bc"
-  integrity sha512-e54B99q/OUoH64zYYRf3HBP5z24G38h5D3qXu23JGRoigpX5Ss4r9ZnDk3g0Z8uQC2x2lPaJ+UlWBc1ZWBWdLg==
-
-consola@^2.15.3:
-  version "2.15.3"
-  resolved "https://registry.yarnpkg.com/consola/-/consola-2.15.3.tgz#2e11f98d6a4be71ff72e0bdf07bd23e12cb61550"
-  integrity sha512-9vAdYbHj6x2fLKC4+oPH0kFzY/orMZyG2Aj+kNylHxKGJ/Ed4dpNyAQYwJOdqO4zdM7XpVHmyejQDcQHrnuXbw==
-
-convert-source-map@^1.7.0:
-  version "1.8.0"
-  resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.8.0.tgz#f3373c32d21b4d780dd8004514684fb791ca4369"
-  integrity sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA==
-  dependencies:
-    safe-buffer "~5.1.1"
-
-copy-anything@^2.0.1:
-  version "2.0.6"
-  resolved "https://registry.yarnpkg.com/copy-anything/-/copy-anything-2.0.6.tgz#092454ea9584a7b7ad5573062b2a87f5900fc480"
-  integrity sha512-1j20GZTsvKNkc4BY3NpMOM8tt///wY3FpIzozTOFO2ffuZcV61nojHXVKIy3WM+7ADCy5FVhdZYHYDdgTU0yJw==
-  dependencies:
-    is-what "^3.14.1"
-
-core-js@^3.15.1:
-  version "3.24.1"
-  resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.24.1.tgz#cf7724d41724154010a6576b7b57d94c5d66e64f"
-  integrity sha512-0QTBSYSUZ6Gq21utGzkfITDylE8jWC9Ne1D2MrhvlsZBI1x39OdDIVbzSqtgMndIy6BlHxBXpMGqzZmnztg2rg==
-
-cosmiconfig@^7.0.1:
-  version "7.0.1"
-  resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-7.0.1.tgz#714d756522cace867867ccb4474c5d01bbae5d6d"
-  integrity sha512-a1YWNUV2HwGimB7dU2s1wUMurNKjpx60HxBB6xUM8Re+2s1g1IIfJvFR0/iCF+XHdE0GMTKTuLR32UQff4TEyQ==
-  dependencies:
-    "@types/parse-json" "^4.0.0"
-    import-fresh "^3.2.1"
-    parse-json "^5.0.0"
-    path-type "^4.0.0"
-    yaml "^1.10.0"
-
-css-declaration-sorter@^6.3.0:
-  version "6.3.0"
-  resolved "https://registry.yarnpkg.com/css-declaration-sorter/-/css-declaration-sorter-6.3.0.tgz#72ebd995c8f4532ff0036631f7365cce9759df14"
-  integrity sha512-OGT677UGHJTAVMRhPO+HJ4oKln3wkBTwtDFH0ojbqm+MJm6xuDMHp2nkhh/ThaBqq20IbraBQSWKfSLNHQO9Og==
-
-css-select@^4.1.3, css-select@^4.2.1:
-  version "4.3.0"
-  resolved "https://registry.yarnpkg.com/css-select/-/css-select-4.3.0.tgz#db7129b2846662fd8628cfc496abb2b59e41529b"
-  integrity sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ==
-  dependencies:
-    boolbase "^1.0.0"
-    css-what "^6.0.1"
-    domhandler "^4.3.1"
-    domutils "^2.8.0"
-    nth-check "^2.0.1"
-
-css-selector-parser@^1.3:
-  version "1.4.1"
-  resolved "https://registry.yarnpkg.com/css-selector-parser/-/css-selector-parser-1.4.1.tgz#03f9cb8a81c3e5ab2c51684557d5aaf6d2569759"
-  integrity sha512-HYPSb7y/Z7BNDCOrakL4raGO2zltZkbeXyAd6Tg9obzix6QhzxCotdBl6VT0Dv4vZfJGVz3WL/xaEI9Ly3ul0g==
-
-css-tree@^1.1.2, css-tree@^1.1.3:
-  version "1.1.3"
-  resolved "https://registry.yarnpkg.com/css-tree/-/css-tree-1.1.3.tgz#eb4870fb6fd7707327ec95c2ff2ab09b5e8db91d"
-  integrity sha512-tRpdppF7TRazZrjJ6v3stzv93qxRcSsFmW6cX0Zm2NVKpxE1WV1HblnghVv9TreireHkqI/VDEsfolRF1p6y7Q==
-  dependencies:
-    mdn-data "2.0.14"
-    source-map "^0.6.1"
-
-css-what@^6.0.1:
-  version "6.1.0"
-  resolved "https://registry.yarnpkg.com/css-what/-/css-what-6.1.0.tgz#fb5effcf76f1ddea2c81bdfaa4de44e79bac70f4"
-  integrity sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==
-
-cssesc@^3.0.0:
-  version "3.0.0"
-  resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-3.0.0.tgz#37741919903b868565e1c09ea747445cd18983ee"
-  integrity sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==
-
-cssnano-preset-default@^5.2.12:
-  version "5.2.12"
-  resolved "https://registry.yarnpkg.com/cssnano-preset-default/-/cssnano-preset-default-5.2.12.tgz#ebe6596ec7030e62c3eb2b3c09f533c0644a9a97"
-  integrity sha512-OyCBTZi+PXgylz9HAA5kHyoYhfGcYdwFmyaJzWnzxuGRtnMw/kR6ilW9XzlzlRAtB6PLT/r+prYgkef7hngFew==
-  dependencies:
-    css-declaration-sorter "^6.3.0"
-    cssnano-utils "^3.1.0"
-    postcss-calc "^8.2.3"
-    postcss-colormin "^5.3.0"
-    postcss-convert-values "^5.1.2"
-    postcss-discard-comments "^5.1.2"
-    postcss-discard-duplicates "^5.1.0"
-    postcss-discard-empty "^5.1.1"
-    postcss-discard-overridden "^5.1.0"
-    postcss-merge-longhand "^5.1.6"
-    postcss-merge-rules "^5.1.2"
-    postcss-minify-font-values "^5.1.0"
-    postcss-minify-gradients "^5.1.1"
-    postcss-minify-params "^5.1.3"
-    postcss-minify-selectors "^5.2.1"
-    postcss-normalize-charset "^5.1.0"
-    postcss-normalize-display-values "^5.1.0"
-    postcss-normalize-positions "^5.1.1"
-    postcss-normalize-repeat-style "^5.1.1"
-    postcss-normalize-string "^5.1.0"
-    postcss-normalize-timing-functions "^5.1.0"
-    postcss-normalize-unicode "^5.1.0"
-    postcss-normalize-url "^5.1.0"
-    postcss-normalize-whitespace "^5.1.1"
-    postcss-ordered-values "^5.1.3"
-    postcss-reduce-initial "^5.1.0"
-    postcss-reduce-transforms "^5.1.0"
-    postcss-svgo "^5.1.0"
-    postcss-unique-selectors "^5.1.1"
-
-cssnano-preset-lite@^2.0.1:
-  version "2.1.3"
-  resolved "https://registry.yarnpkg.com/cssnano-preset-lite/-/cssnano-preset-lite-2.1.3.tgz#da458cd8749443eb22f4253f187fd1dafa73547a"
-  integrity sha512-samvnCll/DUVZu0Qc+JH36nt7dlaOT7WjOgg8SbLJ78sp51JZ12s2hyerxrarjPBG4O53rErUtOY2IYLYgBGEQ==
-  dependencies:
-    cssnano-utils "^3.1.0"
-    postcss-discard-comments "^5.1.2"
-    postcss-discard-empty "^5.1.1"
-    postcss-normalize-whitespace "^5.1.1"
-
-cssnano-utils@^3.1.0:
-  version "3.1.0"
-  resolved "https://registry.yarnpkg.com/cssnano-utils/-/cssnano-utils-3.1.0.tgz#95684d08c91511edfc70d2636338ca37ef3a6861"
-  integrity sha512-JQNR19/YZhz4psLX/rQ9M83e3z2Wf/HdJbryzte4a3NSuafyp9w/I4U+hx5C2S9g41qlstH7DEWnZaaj83OuEA==
-
-cssnano@^5.0.11:
-  version "5.1.12"
-  resolved "https://registry.yarnpkg.com/cssnano/-/cssnano-5.1.12.tgz#bcd0b64d6be8692de79332c501daa7ece969816c"
-  integrity sha512-TgvArbEZu0lk/dvg2ja+B7kYoD7BBCmn3+k58xD0qjrGHsFzXY/wKTo9M5egcUCabPol05e/PVoIu79s2JN4WQ==
-  dependencies:
-    cssnano-preset-default "^5.2.12"
-    lilconfig "^2.0.3"
-    yaml "^1.10.2"
-
-csso@^4.2.0:
-  version "4.2.0"
-  resolved "https://registry.yarnpkg.com/csso/-/csso-4.2.0.tgz#ea3a561346e8dc9f546d6febedd50187cf389529"
-  integrity sha512-wvlcdIbf6pwKEk7vHj8/Bkc0B4ylXZruLvOgs9doS5eOsOpuodOV2zJChSpkp+pRpYQLQMeF04nr3Z68Sta9jA==
-  dependencies:
-    css-tree "^1.1.2"
-
-csstype@^2.6.8:
-  version "2.6.20"
-  resolved "https://registry.yarnpkg.com/csstype/-/csstype-2.6.20.tgz#9229c65ea0b260cf4d3d997cb06288e36a8d6dda"
-  integrity sha512-/WwNkdXfckNgw6S5R125rrW8ez139lBHWouiBvX8dfMFtcn6V81REDqnH7+CRpRipfYlyU1CmOnOxrmGcFOjeA==
-
-dayjs@^1.10.5, dayjs@^1.11.4:
-  version "1.11.4"
-  resolved "https://registry.yarnpkg.com/dayjs/-/dayjs-1.11.4.tgz#3b3c10ca378140d8917e06ebc13a4922af4f433e"
-  integrity sha512-Zj/lPM5hOvQ1Bf7uAvewDaUcsJoI6JmNqmHhHl3nyumwe0XHwt8sWdOVAPACJzCebL8gQCi+K49w7iKWnGwX9g==
-
-debug@^3.2.6:
-  version "3.2.7"
-  resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.7.tgz#72580b7e9145fb39b6676f9c5e5fb100b934179a"
-  integrity sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==
-  dependencies:
-    ms "^2.1.1"
-
-debug@^4.1.0, debug@^4.3.4:
-  version "4.3.4"
-  resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865"
-  integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==
-  dependencies:
-    ms "2.1.2"
-
-delayed-stream@~1.0.0:
-  version "1.0.0"
-  resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619"
-  integrity sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==
-
-dom-align@^1.12.1:
-  version "1.12.3"
-  resolved "https://registry.yarnpkg.com/dom-align/-/dom-align-1.12.3.tgz#a36d02531dae0eefa2abb0c4db6595250526f103"
-  integrity sha512-Gj9hZN3a07cbR6zviMUBOMPdWxYhbMI+x+WS0NAIu2zFZmbK8ys9R79g+iG9qLnlCwpFoaB+fKy8Pdv470GsPA==
-
-dom-scroll-into-view@^2.0.0:
-  version "2.0.1"
-  resolved "https://registry.yarnpkg.com/dom-scroll-into-view/-/dom-scroll-into-view-2.0.1.tgz#0decc8522801fd8d3f1c6ba355a74d382c5f989b"
-  integrity sha512-bvVTQe1lfaUr1oFzZX80ce9KLDlZ3iU+XGNE/bz9HnGdklTieqsbmsLHe+rT2XWqopvL0PckkYqN7ksmm5pe3w==
-
-dom-serializer@^1.0.1:
-  version "1.4.1"
-  resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-1.4.1.tgz#de5d41b1aea290215dc45a6dae8adcf1d32e2d30"
-  integrity sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag==
-  dependencies:
-    domelementtype "^2.0.1"
-    domhandler "^4.2.0"
-    entities "^2.0.0"
-
-domelementtype@^2.0.1, domelementtype@^2.2.0:
-  version "2.3.0"
-  resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-2.3.0.tgz#5c45e8e869952626331d7aab326d01daf65d589d"
-  integrity sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==
-
-domhandler@^4.2.0, domhandler@^4.3.1:
-  version "4.3.1"
-  resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-4.3.1.tgz#8d792033416f59d68bc03a5aa7b018c1ca89279c"
-  integrity sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ==
-  dependencies:
-    domelementtype "^2.2.0"
-
-domutils@^2.8.0:
-  version "2.8.0"
-  resolved "https://registry.yarnpkg.com/domutils/-/domutils-2.8.0.tgz#4437def5db6e2d1f5d6ee859bd95ca7d02048135"
-  integrity sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A==
-  dependencies:
-    dom-serializer "^1.0.1"
-    domelementtype "^2.2.0"
-    domhandler "^4.2.0"
-
-dot-case@^3.0.4:
-  version "3.0.4"
-  resolved "https://registry.yarnpkg.com/dot-case/-/dot-case-3.0.4.tgz#9b2b670d00a431667a8a75ba29cd1b98809ce751"
-  integrity sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==
-  dependencies:
-    no-case "^3.0.4"
-    tslib "^2.0.3"
-
-dotenv-expand@^8.0.2:
-  version "8.0.3"
-  resolved "https://registry.yarnpkg.com/dotenv-expand/-/dotenv-expand-8.0.3.tgz#29016757455bcc748469c83a19b36aaf2b83dd6e"
-  integrity sha512-SErOMvge0ZUyWd5B0NXMQlDkN+8r+HhVUsxgOO7IoPDOdDRD2JjExpN6y3KnFR66jsJMwSn1pqIivhU5rcJiNg==
-
-dotenv@^16.0.0:
-  version "16.0.1"
-  resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-16.0.1.tgz#8f8f9d94876c35dac989876a5d3a82a267fdce1d"
-  integrity sha512-1K6hR6wtk2FviQ4kEiSjFiH5rpzEVi8WW0x96aztHVMhEspNpc4DVOUTEHtEva5VThQ8IaBX1Pe4gSzpVVUsKQ==
-
-ejs@^3.1.6:
-  version "3.1.8"
-  resolved "https://registry.yarnpkg.com/ejs/-/ejs-3.1.8.tgz#758d32910c78047585c7ef1f92f9ee041c1c190b"
-  integrity sha512-/sXZeMlhS0ArkfX2Aw780gJzXSMPnKjtspYZv+f3NiKLlubezAHDU5+9xz6gd3/NhG3txQCo6xlglmTS+oTGEQ==
-  dependencies:
-    jake "^10.8.5"
-
-electron-to-chromium@^1.4.202:
-  version "1.4.206"
-  resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.206.tgz#580ff85b54d7ec0c05f20b1e37ea0becdd7b0ee4"
-  integrity sha512-h+Fadt1gIaQ06JaIiyqPsBjJ08fV5Q7md+V8bUvQW/9OvXfL2LRICTz2EcnnCP7QzrFTS6/27MRV6Bl9Yn97zA==
-
-entities@^2.0.0:
-  version "2.2.0"
-  resolved "https://registry.yarnpkg.com/entities/-/entities-2.2.0.tgz#098dc90ebb83d8dffa089d55256b351d34c4da55"
-  integrity sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==
-
-errno@^0.1.1:
-  version "0.1.8"
-  resolved "https://registry.yarnpkg.com/errno/-/errno-0.1.8.tgz#8bb3e9c7d463be4976ff888f76b4809ebc2e811f"
-  integrity sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A==
-  dependencies:
-    prr "~1.0.1"
-
-error-ex@^1.3.1:
-  version "1.3.2"
-  resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf"
-  integrity sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==
-  dependencies:
-    is-arrayish "^0.2.1"
-
-esbuild-android-64@0.14.51:
-  version "0.14.51"
-  resolved "https://registry.yarnpkg.com/esbuild-android-64/-/esbuild-android-64-0.14.51.tgz#414a087cb0de8db1e347ecca6c8320513de433db"
-  integrity sha512-6FOuKTHnC86dtrKDmdSj2CkcKF8PnqkaIXqvgydqfJmqBazCPdw+relrMlhGjkvVdiiGV70rpdnyFmA65ekBCQ==
-
-esbuild-android-arm64@0.14.51:
-  version "0.14.51"
-  resolved "https://registry.yarnpkg.com/esbuild-android-arm64/-/esbuild-android-arm64-0.14.51.tgz#55de3bce2aab72bcd2b606da4318ad00fb9c8151"
-  integrity sha512-vBtp//5VVkZWmYYvHsqBRCMMi1MzKuMIn5XDScmnykMTu9+TD9v0NMEDqQxvtFToeYmojdo5UCV2vzMQWJcJ4A==
-
-esbuild-darwin-64@0.14.51:
-  version "0.14.51"
-  resolved "https://registry.yarnpkg.com/esbuild-darwin-64/-/esbuild-darwin-64-0.14.51.tgz#4259f23ed6b4cea2ec8a28d87b7fb9801f093754"
-  integrity sha512-YFmXPIOvuagDcwCejMRtCDjgPfnDu+bNeh5FU2Ryi68ADDVlWEpbtpAbrtf/lvFTWPexbgyKgzppNgsmLPr8PA==
-
-esbuild-darwin-arm64@0.14.51:
-  version "0.14.51"
-  resolved "https://registry.yarnpkg.com/esbuild-darwin-arm64/-/esbuild-darwin-arm64-0.14.51.tgz#d77b4366a71d84e530ba019d540b538b295d494a"
-  integrity sha512-juYD0QnSKwAMfzwKdIF6YbueXzS6N7y4GXPDeDkApz/1RzlT42mvX9jgNmyOlWKN7YzQAYbcUEJmZJYQGdf2ow==
-
-esbuild-freebsd-64@0.14.51:
-  version "0.14.51"
-  resolved "https://registry.yarnpkg.com/esbuild-freebsd-64/-/esbuild-freebsd-64-0.14.51.tgz#27b6587b3639f10519c65e07219d249b01f2ad38"
-  integrity sha512-cLEI/aXjb6vo5O2Y8rvVSQ7smgLldwYY5xMxqh/dQGfWO+R1NJOFsiax3IS4Ng300SVp7Gz3czxT6d6qf2cw0g==
-
-esbuild-freebsd-arm64@0.14.51:
-  version "0.14.51"
-  resolved "https://registry.yarnpkg.com/esbuild-freebsd-arm64/-/esbuild-freebsd-arm64-0.14.51.tgz#63c435917e566808c71fafddc600aca4d78be1ec"
-  integrity sha512-TcWVw/rCL2F+jUgRkgLa3qltd5gzKjIMGhkVybkjk6PJadYInPtgtUBp1/hG+mxyigaT7ib+od1Xb84b+L+1Mg==
-
-esbuild-linux-32@0.14.51:
-  version "0.14.51"
-  resolved "https://registry.yarnpkg.com/esbuild-linux-32/-/esbuild-linux-32-0.14.51.tgz#c3da774143a37e7f11559b9369d98f11f997a5d9"
-  integrity sha512-RFqpyC5ChyWrjx8Xj2K0EC1aN0A37H6OJfmUXIASEqJoHcntuV3j2Efr9RNmUhMfNE6yEj2VpYuDteZLGDMr0w==
-
-esbuild-linux-64@0.14.51:
-  version "0.14.51"
-  resolved "https://registry.yarnpkg.com/esbuild-linux-64/-/esbuild-linux-64-0.14.51.tgz#5d92b67f674e02ae0b4a9de9a757ba482115c4ae"
-  integrity sha512-dxjhrqo5i7Rq6DXwz5v+MEHVs9VNFItJmHBe1CxROWNf4miOGoQhqSG8StStbDkQ1Mtobg6ng+4fwByOhoQoeA==
-
-esbuild-linux-arm64@0.14.51:
-  version "0.14.51"
-  resolved "https://registry.yarnpkg.com/esbuild-linux-arm64/-/esbuild-linux-arm64-0.14.51.tgz#dac84740516e859d8b14e1ecc478dd5241b10c93"
-  integrity sha512-D9rFxGutoqQX3xJPxqd6o+kvYKeIbM0ifW2y0bgKk5HPgQQOo2k9/2Vpto3ybGYaFPCE5qTGtqQta9PoP6ZEzw==
-
-esbuild-linux-arm@0.14.51:
-  version "0.14.51"
-  resolved "https://registry.yarnpkg.com/esbuild-linux-arm/-/esbuild-linux-arm-0.14.51.tgz#b3ae7000696cd53ed95b2b458554ff543a60e106"
-  integrity sha512-LsJynDxYF6Neg7ZC7748yweCDD+N8ByCv22/7IAZglIEniEkqdF4HCaa49JNDLw1UQGlYuhOB8ZT/MmcSWzcWg==
-
-esbuild-linux-mips64le@0.14.51:
-  version "0.14.51"
-  resolved "https://registry.yarnpkg.com/esbuild-linux-mips64le/-/esbuild-linux-mips64le-0.14.51.tgz#dad10770fac94efa092b5a0643821c955a9dd385"
-  integrity sha512-vS54wQjy4IinLSlb5EIlLoln8buh1yDgliP4CuEHumrPk4PvvP4kTRIG4SzMXm6t19N0rIfT4bNdAxzJLg2k6A==
-
-esbuild-linux-ppc64le@0.14.51:
-  version "0.14.51"
-  resolved "https://registry.yarnpkg.com/esbuild-linux-ppc64le/-/esbuild-linux-ppc64le-0.14.51.tgz#b68c2f8294d012a16a88073d67e976edd4850ae0"
-  integrity sha512-xcdd62Y3VfGoyphNP/aIV9LP+RzFw5M5Z7ja+zdpQHHvokJM7d0rlDRMN+iSSwvUymQkqZO+G/xjb4/75du8BQ==
-
-esbuild-linux-riscv64@0.14.51:
-  version "0.14.51"
-  resolved "https://registry.yarnpkg.com/esbuild-linux-riscv64/-/esbuild-linux-riscv64-0.14.51.tgz#608a318b8697123e44c1e185cdf6708e3df50b93"
-  integrity sha512-syXHGak9wkAnFz0gMmRBoy44JV0rp4kVCEA36P5MCeZcxFq8+fllBC2t6sKI23w3qd8Vwo9pTADCgjTSf3L3rA==
-
-esbuild-linux-s390x@0.14.51:
-  version "0.14.51"
-  resolved "https://registry.yarnpkg.com/esbuild-linux-s390x/-/esbuild-linux-s390x-0.14.51.tgz#c9e7791170a3295dba79b93aa452beb9838a8625"
-  integrity sha512-kFAJY3dv+Wq8o28K/C7xkZk/X34rgTwhknSsElIqoEo8armCOjMJ6NsMxm48KaWY2h2RUYGtQmr+RGuUPKBhyw==
-
-esbuild-netbsd-64@0.14.51:
-  version "0.14.51"
-  resolved "https://registry.yarnpkg.com/esbuild-netbsd-64/-/esbuild-netbsd-64-0.14.51.tgz#0abd40b8c2e37fda6f5cc41a04cb2b690823d891"
-  integrity sha512-ZZBI7qrR1FevdPBVHz/1GSk1x5GDL/iy42Zy8+neEm/HA7ma+hH/bwPEjeHXKWUDvM36CZpSL/fn1/y9/Hb+1A==
-
-esbuild-openbsd-64@0.14.51:
-  version "0.14.51"
-  resolved "https://registry.yarnpkg.com/esbuild-openbsd-64/-/esbuild-openbsd-64-0.14.51.tgz#4adba0b7ea7eb1428bb00d8e94c199a949b130e8"
-  integrity sha512-7R1/p39M+LSVQVgDVlcY1KKm6kFKjERSX1lipMG51NPcspJD1tmiZSmmBXoY5jhHIu6JL1QkFDTx94gMYK6vfA==
-
-esbuild-sunos-64@0.14.51:
-  version "0.14.51"
-  resolved "https://registry.yarnpkg.com/esbuild-sunos-64/-/esbuild-sunos-64-0.14.51.tgz#4b8a6d97dfedda30a6e39607393c5c90ebf63891"
-  integrity sha512-HoHaCswHxLEYN8eBTtyO0bFEWvA3Kdb++hSQ/lLG7TyKF69TeSG0RNoBRAs45x/oCeWaTDntEZlYwAfQlhEtJA==
-
-esbuild-windows-32@0.14.51:
-  version "0.14.51"
-  resolved "https://registry.yarnpkg.com/esbuild-windows-32/-/esbuild-windows-32-0.14.51.tgz#d31d8ca0c1d314fb1edea163685a423b62e9ac17"
-  integrity sha512-4rtwSAM35A07CBt1/X8RWieDj3ZUHQqUOaEo5ZBs69rt5WAFjP4aqCIobdqOy4FdhYw1yF8Z0xFBTyc9lgPtEg==
-
-esbuild-windows-64@0.14.51:
-  version "0.14.51"
-  resolved "https://registry.yarnpkg.com/esbuild-windows-64/-/esbuild-windows-64-0.14.51.tgz#7d3c09c8652d222925625637bdc7e6c223e0085d"
-  integrity sha512-HoN/5HGRXJpWODprGCgKbdMvrC3A2gqvzewu2eECRw2sYxOUoh2TV1tS+G7bHNapPGI79woQJGV6pFH7GH7qnA==
-
-esbuild-windows-arm64@0.14.51:
-  version "0.14.51"
-  resolved "https://registry.yarnpkg.com/esbuild-windows-arm64/-/esbuild-windows-arm64-0.14.51.tgz#0220d2304bfdc11bc27e19b2aaf56edf183e4ae9"
-  integrity sha512-JQDqPjuOH7o+BsKMSddMfmVJXrnYZxXDHsoLHc0xgmAZkOOCflRmC43q31pk79F9xuyWY45jDBPolb5ZgGOf9g==
-
-esbuild@^0.14.47:
-  version "0.14.51"
-  resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.14.51.tgz#1c8ecbc8db3710da03776211dc3ee3448f7aa51e"
-  integrity sha512-+CvnDitD7Q5sT7F+FM65sWkF8wJRf+j9fPcprxYV4j+ohmzVj2W7caUqH2s5kCaCJAfcAICjSlKhDCcvDpU7nw==
-  optionalDependencies:
-    esbuild-android-64 "0.14.51"
-    esbuild-android-arm64 "0.14.51"
-    esbuild-darwin-64 "0.14.51"
-    esbuild-darwin-arm64 "0.14.51"
-    esbuild-freebsd-64 "0.14.51"
-    esbuild-freebsd-arm64 "0.14.51"
-    esbuild-linux-32 "0.14.51"
-    esbuild-linux-64 "0.14.51"
-    esbuild-linux-arm "0.14.51"
-    esbuild-linux-arm64 "0.14.51"
-    esbuild-linux-mips64le "0.14.51"
-    esbuild-linux-ppc64le "0.14.51"
-    esbuild-linux-riscv64 "0.14.51"
-    esbuild-linux-s390x "0.14.51"
-    esbuild-netbsd-64 "0.14.51"
-    esbuild-openbsd-64 "0.14.51"
-    esbuild-sunos-64 "0.14.51"
-    esbuild-windows-32 "0.14.51"
-    esbuild-windows-64 "0.14.51"
-    esbuild-windows-arm64 "0.14.51"
-
-escalade@^3.1.1:
-  version "3.1.1"
-  resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40"
-  integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==
-
-escape-string-regexp@^1.0.5:
-  version "1.0.5"
-  resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4"
-  integrity sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==
-
-estree-walker@^2.0.1, estree-walker@^2.0.2:
-  version "2.0.2"
-  resolved "https://registry.yarnpkg.com/estree-walker/-/estree-walker-2.0.2.tgz#52f010178c2a4c117a7757cfe942adb7d2da4cac"
-  integrity sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==
-
-fast-glob@^3.2.11:
-  version "3.2.11"
-  resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.2.11.tgz#a1172ad95ceb8a16e20caa5c5e56480e5129c1d9"
-  integrity sha512-xrO3+1bxSo3ZVHAnqzyuewYT6aMFHRAd4Kcs92MAonjwQZLsK9d0SF1IyQ3k5PoirxTW0Oe/RqFgMQ6TcNE5Ew==
-  dependencies:
-    "@nodelib/fs.stat" "^2.0.2"
-    "@nodelib/fs.walk" "^1.2.3"
-    glob-parent "^5.1.2"
-    merge2 "^1.3.0"
-    micromatch "^4.0.4"
-
-fastq@^1.6.0:
-  version "1.13.0"
-  resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.13.0.tgz#616760f88a7526bdfc596b7cab8c18938c36b98c"
-  integrity sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==
-  dependencies:
-    reusify "^1.0.4"
-
-filelist@^1.0.1:
-  version "1.0.4"
-  resolved "https://registry.yarnpkg.com/filelist/-/filelist-1.0.4.tgz#f78978a1e944775ff9e62e744424f215e58352b5"
-  integrity sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q==
-  dependencies:
-    minimatch "^5.0.1"
-
-fill-range@^7.0.1:
-  version "7.0.1"
-  resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40"
-  integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==
-  dependencies:
-    to-regex-range "^5.0.1"
-
-find-replace@^3.0.0:
-  version "3.0.0"
-  resolved "https://registry.yarnpkg.com/find-replace/-/find-replace-3.0.0.tgz#3e7e23d3b05167a76f770c9fbd5258b0def68c38"
-  integrity sha512-6Tb2myMioCAgv5kfvP5/PkZZ/ntTpVK39fHY7WkWBgvbeE+VHd/tZuZ4mrC+bxh4cfOZeYKVPaJIZtZXV7GNCQ==
-  dependencies:
-    array-back "^3.0.1"
-
-follow-redirects@^1.14.9:
-  version "1.15.1"
-  resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.15.1.tgz#0ca6a452306c9b276e4d3127483e29575e207ad5"
-  integrity sha512-yLAMQs+k0b2m7cVxpS1VKJVvoz7SS9Td1zss3XRwXj+ZDH00RJgnuLx7E44wx02kQLrdM3aOOy+FpzS7+8OizA==
-
-form-data@^4.0.0:
-  version "4.0.0"
-  resolved "https://registry.yarnpkg.com/form-data/-/form-data-4.0.0.tgz#93919daeaf361ee529584b9b31664dc12c9fa452"
-  integrity sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==
-  dependencies:
-    asynckit "^0.4.0"
-    combined-stream "^1.0.8"
-    mime-types "^2.1.12"
-
-fs-extra@^10.0.0, fs-extra@^10.0.1:
-  version "10.1.0"
-  resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-10.1.0.tgz#02873cfbc4084dde127eaa5f9905eef2325d1abf"
-  integrity sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==
-  dependencies:
-    graceful-fs "^4.2.0"
-    jsonfile "^6.0.1"
-    universalify "^2.0.0"
-
-fs.realpath@^1.0.0:
-  version "1.0.0"
-  resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f"
-  integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==
-
-fsevents@~2.3.2:
-  version "2.3.2"
-  resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a"
-  integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==
-
-function-bind@^1.1.1:
-  version "1.1.1"
-  resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d"
-  integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==
-
-gensync@^1.0.0-beta.2:
-  version "1.0.0-beta.2"
-  resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0"
-  integrity sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==
-
-gettext-extractor@^3.5.4:
-  version "3.5.4"
-  resolved "https://registry.yarnpkg.com/gettext-extractor/-/gettext-extractor-3.5.4.tgz#bd36c65b4d26014ffd925f9ac7b4738d6893d6b2"
-  integrity sha512-iK4tSnteSw+pFMts43OP8hUnsOklbkxz3ytWqru7dPf8Ec3uzTYv1aw70ojAvKItmofpj1ibfY7sZWsdSN6zIw==
-  dependencies:
-    "@types/glob" "5 - 7"
-    "@types/parse5" "^5"
-    css-selector-parser "^1.3"
-    glob "5 - 7"
-    parse5 "5 - 6"
-    pofile "1.0.x"
-    typescript "2 - 4"
-
-glob-parent@^5.1.2, glob-parent@~5.1.2:
-  version "5.1.2"
-  resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4"
-  integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==
-  dependencies:
-    is-glob "^4.0.1"
-
-"glob@5 - 7", glob@^7.1.3, glob@^7.2.0:
-  version "7.2.3"
-  resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b"
-  integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==
-  dependencies:
-    fs.realpath "^1.0.0"
-    inflight "^1.0.4"
-    inherits "2"
-    minimatch "^3.1.1"
-    once "^1.3.0"
-    path-is-absolute "^1.0.0"
-
-globals@^11.1.0:
-  version "11.12.0"
-  resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e"
-  integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==
-
-graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.0:
-  version "4.2.10"
-  resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.10.tgz#147d3a006da4ca3ce14728c7aefc287c367d7a6c"
-  integrity sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==
-
-has-flag@^3.0.0:
-  version "3.0.0"
-  resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd"
-  integrity sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==
-
-has-flag@^4.0.0:
-  version "4.0.0"
-  resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b"
-  integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==
-
-has@^1.0.3:
-  version "1.0.3"
-  resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796"
-  integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==
-  dependencies:
-    function-bind "^1.1.1"
-
-he@1.2.0, he@^1.2.0:
-  version "1.2.0"
-  resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f"
-  integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==
-
-html-minifier-terser@^6.1.0:
-  version "6.1.0"
-  resolved "https://registry.yarnpkg.com/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz#bfc818934cc07918f6b3669f5774ecdfd48f32ab"
-  integrity sha512-YXxSlJBZTP7RS3tWnQw74ooKa6L9b9i9QYXY21eUEvhZ3u9XLfv6OnFsQq6RxkhHygsaUMvYsZRV5rU/OVNZxw==
-  dependencies:
-    camel-case "^4.1.2"
-    clean-css "^5.2.2"
-    commander "^8.3.0"
-    he "^1.2.0"
-    param-case "^3.0.4"
-    relateurl "^0.2.7"
-    terser "^5.10.0"
-
-html-tags@^3.1.0:
-  version "3.2.0"
-  resolved "https://registry.yarnpkg.com/html-tags/-/html-tags-3.2.0.tgz#dbb3518d20b726524e4dd43de397eb0a95726961"
-  integrity sha512-vy7ClnArOZwCnqZgvv+ddgHgJiAFXe3Ge9ML5/mBctVJoUoYPCdxVucOywjDARn6CVoh3dRSFdPHy2sX80L0Wg==
-
-iconv-lite@^0.6.3:
-  version "0.6.3"
-  resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.6.3.tgz#a52f80bf38da1952eb5c681790719871a1a72501"
-  integrity sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==
-  dependencies:
-    safer-buffer ">= 2.1.2 < 3.0.0"
-
-image-size@~0.5.0:
-  version "0.5.5"
-  resolved "https://registry.yarnpkg.com/image-size/-/image-size-0.5.5.tgz#09dfd4ab9d20e29eb1c3e80b8990378df9e3cb9c"
-  integrity sha512-6TDAlDPZxUFCv+fuOkIoXT/V/f3Qbq8e37p+YOiYrUv3v9cc3/6x78VdfPgFVaB9dZYeLUfKgHRebpkm/oP2VQ==
-
-import-fresh@^3.2.1:
-  version "3.3.0"
-  resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b"
-  integrity sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==
-  dependencies:
-    parent-module "^1.0.0"
-    resolve-from "^4.0.0"
-
-inflight@^1.0.4:
-  version "1.0.6"
-  resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9"
-  integrity sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==
-  dependencies:
-    once "^1.3.0"
-    wrappy "1"
-
-inherits@2:
-  version "2.0.4"
-  resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c"
-  integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==
-
-inherits@2.0.3:
-  version "2.0.3"
-  resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de"
-  integrity sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==
-
-is-arrayish@^0.2.1:
-  version "0.2.1"
-  resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d"
-  integrity sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==
-
-is-arrayish@^0.3.1:
-  version "0.3.2"
-  resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.3.2.tgz#4574a2ae56f7ab206896fb431eaeed066fdf8f03"
-  integrity sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==
-
-is-binary-path@~2.1.0:
-  version "2.1.0"
-  resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09"
-  integrity sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==
-  dependencies:
-    binary-extensions "^2.0.0"
-
-is-core-module@^2.9.0:
-  version "2.9.0"
-  resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.9.0.tgz#e1c34429cd51c6dd9e09e0799e396e27b19a9c69"
-  integrity sha512-+5FPy5PnwmO3lvfMb0AsoPaBG+5KHUI0wYFXOtYPnVVVspTFUuMZNfNaNVRt3FZadstu2c8x23vykRW/NBoU6A==
-  dependencies:
-    has "^1.0.3"
-
-is-extglob@^2.1.1:
-  version "2.1.1"
-  resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2"
-  integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==
-
-is-glob@^4.0.1, is-glob@~4.0.1:
-  version "4.0.3"
-  resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084"
-  integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==
-  dependencies:
-    is-extglob "^2.1.1"
-
-is-number@^7.0.0:
-  version "7.0.0"
-  resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b"
-  integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==
-
-is-plain-object@3.0.1:
-  version "3.0.1"
-  resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-3.0.1.tgz#662d92d24c0aa4302407b0d45d21f2251c85f85b"
-  integrity sha512-Xnpx182SBMrr/aBik8y+GuR4U1L9FqMSojwDQwPMmxyC6bvEqly9UBCxhauBF5vNh2gwWJNX6oDV7O+OM4z34g==
-
-is-what@^3.14.1:
-  version "3.14.1"
-  resolved "https://registry.yarnpkg.com/is-what/-/is-what-3.14.1.tgz#e1222f46ddda85dead0fd1c9df131760e77755c1"
-  integrity sha512-sNxgpk9793nzSs7bA6JQJGeIuRBQhAaNGG77kzYQgMkrID+lS6SlK07K5LaptscDlSaIgH+GPFzf+d75FVxozA==
-
-jake@^10.8.5:
-  version "10.8.5"
-  resolved "https://registry.yarnpkg.com/jake/-/jake-10.8.5.tgz#f2183d2c59382cb274226034543b9c03b8164c46"
-  integrity sha512-sVpxYeuAhWt0OTWITwT98oyV0GsXyMlXCF+3L1SuafBVUIr/uILGRB+NqwkzhgXKvoJpDIpQvqkUALgdmQsQxw==
-  dependencies:
-    async "^3.2.3"
-    chalk "^4.0.2"
-    filelist "^1.0.1"
-    minimatch "^3.0.4"
-
-"js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0:
-  version "4.0.0"
-  resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499"
-  integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==
-
-jsesc@^2.5.1:
-  version "2.5.2"
-  resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4"
-  integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==
-
-json-parse-even-better-errors@^2.3.0:
-  version "2.3.1"
-  resolved "https://registry.yarnpkg.com/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz#7c47805a94319928e05777405dc12e1f7a4ee02d"
-  integrity sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==
-
-json5@^2.2.1:
-  version "2.2.1"
-  resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.1.tgz#655d50ed1e6f95ad1a3caababd2b0efda10b395c"
-  integrity sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==
-
-jsonfile@^6.0.1:
-  version "6.1.0"
-  resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-6.1.0.tgz#bc55b2634793c679ec6403094eb13698a6ec0aae"
-  integrity sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==
-  dependencies:
-    universalify "^2.0.0"
-  optionalDependencies:
-    graceful-fs "^4.1.6"
-
-less@^4.1.3:
-  version "4.1.3"
-  resolved "https://registry.yarnpkg.com/less/-/less-4.1.3.tgz#175be9ddcbf9b250173e0a00b4d6920a5b770246"
-  integrity sha512-w16Xk/Ta9Hhyei0Gpz9m7VS8F28nieJaL/VyShID7cYvP6IL5oHeL6p4TXSDJqZE/lNv0oJ2pGVjJsRkfwm5FA==
-  dependencies:
-    copy-anything "^2.0.1"
-    parse-node-version "^1.0.1"
-    tslib "^2.3.0"
-  optionalDependencies:
-    errno "^0.1.1"
-    graceful-fs "^4.1.2"
-    image-size "~0.5.0"
-    make-dir "^2.1.0"
-    mime "^1.4.1"
-    needle "^3.1.0"
-    source-map "~0.6.0"
-
-lilconfig@^2.0.3:
-  version "2.0.6"
-  resolved "https://registry.yarnpkg.com/lilconfig/-/lilconfig-2.0.6.tgz#32a384558bd58af3d4c6e077dd1ad1d397bc69d4"
-  integrity sha512-9JROoBW7pobfsx+Sq2JsASvCo6Pfo6WWoUW79HuB1BCoBXD4PLWJPqDF6fNj67pqBYTbAHkE57M1kS/+L1neOg==
-
-lines-and-columns@^1.1.6:
-  version "1.2.4"
-  resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.2.4.tgz#eca284f75d2965079309dc0ad9255abb2ebc1632"
-  integrity sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==
-
-local-pkg@^0.4.2:
-  version "0.4.2"
-  resolved "https://registry.yarnpkg.com/local-pkg/-/local-pkg-0.4.2.tgz#13107310b77e74a0e513147a131a2ba288176c2f"
-  integrity sha512-mlERgSPrbxU3BP4qBqAvvwlgW4MTg78iwJdGGnv7kibKjWcJksrG3t6LB5lXI93wXRDvG4NpUgJFmTG4T6rdrg==
-
-lodash-es@^4.17.15:
-  version "4.17.21"
-  resolved "https://registry.yarnpkg.com/lodash-es/-/lodash-es-4.17.21.tgz#43e626c46e6591b7750beb2b50117390c609e3ee"
-  integrity sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==
-
-lodash.camelcase@^4.3.0:
-  version "4.3.0"
-  resolved "https://registry.yarnpkg.com/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz#b28aa6288a2b9fc651035c7711f65ab6190331a6"
-  integrity sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==
-
-lodash.memoize@^4.1.2:
-  version "4.1.2"
-  resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe"
-  integrity sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==
-
-lodash.uniq@^4.5.0:
-  version "4.5.0"
-  resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773"
-  integrity sha512-xfBaXQd9ryd9dlSDvnvI0lvxfLJlYAZzXomUYzLKtUeOQvOP5piqAWuGtrhWeqaXK9hhoM/iyJc5AV+XfsX3HQ==
-
-lodash@^4.17.21:
-  version "4.17.21"
-  resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c"
-  integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==
-
-loose-envify@^1.0.0:
-  version "1.4.0"
-  resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf"
-  integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==
-  dependencies:
-    js-tokens "^3.0.0 || ^4.0.0"
-
-lower-case@^2.0.2:
-  version "2.0.2"
-  resolved "https://registry.yarnpkg.com/lower-case/-/lower-case-2.0.2.tgz#6fa237c63dbdc4a82ca0fd882e4722dc5e634e28"
-  integrity sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==
-  dependencies:
-    tslib "^2.0.3"
-
-magic-string@^0.25.7:
-  version "0.25.9"
-  resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.25.9.tgz#de7f9faf91ef8a1c91d02c2e5314c8277dbcdd1c"
-  integrity sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ==
-  dependencies:
-    sourcemap-codec "^1.4.8"
-
-magic-string@^0.26.2:
-  version "0.26.2"
-  resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.26.2.tgz#5331700e4158cd6befda738bb6b0c7b93c0d4432"
-  integrity sha512-NzzlXpclt5zAbmo6h6jNc8zl2gNRGHvmsZW4IvZhTC4W7k4OlLP+S5YLussa/r3ixNT66KOQfNORlXHSOy/X4A==
-  dependencies:
-    sourcemap-codec "^1.4.8"
-
-make-dir@^2.1.0:
-  version "2.1.0"
-  resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-2.1.0.tgz#5f0310e18b8be898cc07009295a30ae41e91e6f5"
-  integrity sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==
-  dependencies:
-    pify "^4.0.1"
-    semver "^5.6.0"
-
-mdn-data@2.0.14:
-  version "2.0.14"
-  resolved "https://registry.yarnpkg.com/mdn-data/-/mdn-data-2.0.14.tgz#7113fc4281917d63ce29b43446f701e68c25ba50"
-  integrity sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow==
-
-merge2@^1.3.0:
-  version "1.4.1"
-  resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae"
-  integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==
-
-micromatch@^4.0.4:
-  version "4.0.5"
-  resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.5.tgz#bc8999a7cbbf77cdc89f132f6e467051b49090c6"
-  integrity sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==
-  dependencies:
-    braces "^3.0.2"
-    picomatch "^2.3.1"
-
-mime-db@1.52.0:
-  version "1.52.0"
-  resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70"
-  integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==
-
-mime-types@^2.1.12:
-  version "2.1.35"
-  resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a"
-  integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==
-  dependencies:
-    mime-db "1.52.0"
-
-mime@^1.4.1:
-  version "1.6.0"
-  resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1"
-  integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==
-
-minimatch@^3.0.4, minimatch@^3.1.1:
-  version "3.1.2"
-  resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b"
-  integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==
-  dependencies:
-    brace-expansion "^1.1.7"
-
-minimatch@^5.0.1, minimatch@^5.1.0:
-  version "5.1.0"
-  resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-5.1.0.tgz#1717b464f4971b144f6aabe8f2d0b8e4511e09c7"
-  integrity sha512-9TPBGGak4nHfGZsPBohm9AWg6NoT7QTCehS3BIJABslyZbzxfV78QM2Y6+i741OPZIafFAaiiEMh5OyIrJPgtg==
-  dependencies:
-    brace-expansion "^2.0.1"
-
-ms@2.1.2:
-  version "2.1.2"
-  resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009"
-  integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==
-
-ms@^2.1.1:
-  version "2.1.3"
-  resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2"
-  integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==
-
-nanoid@^3.3.4:
-  version "3.3.4"
-  resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.4.tgz#730b67e3cd09e2deacf03c027c81c9d9dbc5e8ab"
-  integrity sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==
-
-nanopop@^2.1.0:
-  version "2.1.0"
-  resolved "https://registry.yarnpkg.com/nanopop/-/nanopop-2.1.0.tgz#23476513cee2405888afd2e8a4b54066b70b9e60"
-  integrity sha512-jGTwpFRexSH+fxappnGQtN9dspgE2ipa1aOjtR24igG0pv6JCxImIAmrLRHX+zUF5+1wtsFVbKyfP51kIGAVNw==
-
-needle@^3.1.0:
-  version "3.1.0"
-  resolved "https://registry.yarnpkg.com/needle/-/needle-3.1.0.tgz#3bf5cd090c28eb15644181ab6699e027bd6c53c9"
-  integrity sha512-gCE9weDhjVGCRqS8dwDR/D3GTAeyXLXuqp7I8EzH6DllZGXSUyxuqqLh+YX9rMAWaaTFyVAg6rHGL25dqvczKw==
-  dependencies:
-    debug "^3.2.6"
-    iconv-lite "^0.6.3"
-    sax "^1.2.4"
-
-no-case@^3.0.4:
-  version "3.0.4"
-  resolved "https://registry.yarnpkg.com/no-case/-/no-case-3.0.4.tgz#d361fd5c9800f558551a8369fc0dcd4662b6124d"
-  integrity sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==
-  dependencies:
-    lower-case "^2.0.2"
-    tslib "^2.0.3"
-
-node-html-parser@^5.3.3:
-  version "5.3.3"
-  resolved "https://registry.yarnpkg.com/node-html-parser/-/node-html-parser-5.3.3.tgz#2845704f3a7331a610e0e551bf5fa02b266341b6"
-  integrity sha512-ncg1033CaX9UexbyA7e1N0aAoAYRDiV8jkTvzEnfd1GDvzFdrsXLzR4p4ik8mwLgnaKP/jyUFWDy9q3jvRT2Jw==
-  dependencies:
-    css-select "^4.2.1"
-    he "1.2.0"
-
-node-releases@^2.0.6:
-  version "2.0.6"
-  resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.6.tgz#8a7088c63a55e493845683ebf3c828d8c51c5503"
-  integrity sha512-PiVXnNuFm5+iYkLBNeq5211hvO38y63T0i2KKh2KnUs3RpzJ+JtODFjkD8yjLwnDkTYF1eKXheUwdssR+NRZdg==
-
-normalize-path@^3.0.0, normalize-path@~3.0.0:
-  version "3.0.0"
-  resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65"
-  integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==
-
-normalize-url@^6.0.1:
-  version "6.1.0"
-  resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-6.1.0.tgz#40d0885b535deffe3f3147bec877d05fe4c5668a"
-  integrity sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==
-
-nth-check@^2.0.1:
-  version "2.1.1"
-  resolved "https://registry.yarnpkg.com/nth-check/-/nth-check-2.1.1.tgz#c9eab428effce36cd6b92c924bdb000ef1f1ed1d"
-  integrity sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==
-  dependencies:
-    boolbase "^1.0.0"
-
-once@^1.3.0:
-  version "1.4.0"
-  resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1"
-  integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==
-  dependencies:
-    wrappy "1"
-
-param-case@^3.0.4:
-  version "3.0.4"
-  resolved "https://registry.yarnpkg.com/param-case/-/param-case-3.0.4.tgz#7d17fe4aa12bde34d4a77d91acfb6219caad01c5"
-  integrity sha512-RXlj7zCYokReqWpOPH9oYivUzLYZ5vAPIfEmCTNViosC78F8F0H9y7T7gG2M39ymgutxF5gcFEsyZQSph9Bp3A==
-  dependencies:
-    dot-case "^3.0.4"
-    tslib "^2.0.3"
-
-parent-module@^1.0.0:
-  version "1.0.1"
-  resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2"
-  integrity sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==
-  dependencies:
-    callsites "^3.0.0"
-
-parse-json@^5.0.0:
-  version "5.2.0"
-  resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-5.2.0.tgz#c76fc66dee54231c962b22bcc8a72cf2f99753cd"
-  integrity sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==
-  dependencies:
-    "@babel/code-frame" "^7.0.0"
-    error-ex "^1.3.1"
-    json-parse-even-better-errors "^2.3.0"
-    lines-and-columns "^1.1.6"
-
-parse-node-version@^1.0.1:
-  version "1.0.1"
-  resolved "https://registry.yarnpkg.com/parse-node-version/-/parse-node-version-1.0.1.tgz#e2b5dbede00e7fa9bc363607f53327e8b073189b"
-  integrity sha512-3YHlOa/JgH6Mnpr05jP9eDG254US9ek25LyIxZlDItp2iJtwyaXQb57lBYLdT3MowkUFYEV2XXNAYIPlESvJlA==
-
-parse5-htmlparser2-tree-adapter@^6.0.1:
-  version "6.0.1"
-  resolved "https://registry.yarnpkg.com/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-6.0.1.tgz#2cdf9ad823321140370d4dbf5d3e92c7c8ddc6e6"
-  integrity sha512-qPuWvbLgvDGilKc5BoicRovlT4MtYT6JfJyBOMDsKoiT+GiuP5qyrPCnR9HcPECIJJmZh5jRndyNThnhhb/vlA==
-  dependencies:
-    parse5 "^6.0.1"
-
-"parse5@5 - 6", parse5@^6.0.1:
-  version "6.0.1"
-  resolved "https://registry.yarnpkg.com/parse5/-/parse5-6.0.1.tgz#e1a1c085c569b3dc08321184f19a39cc27f7c30b"
-  integrity sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==
-
-pascal-case@^3.1.2:
-  version "3.1.2"
-  resolved "https://registry.yarnpkg.com/pascal-case/-/pascal-case-3.1.2.tgz#b48e0ef2b98e205e7c1dae747d0b1508237660eb"
-  integrity sha512-uWlGT3YSnK9x3BQJaOdcZwrnV6hPpd8jFH1/ucpiLRPh/2zCVJKS19E4GvYHvaCcACn3foXZ0cLB9Wrx1KGe5g==
-  dependencies:
-    no-case "^3.0.4"
-    tslib "^2.0.3"
-
-path-is-absolute@^1.0.0:
-  version "1.0.1"
-  resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f"
-  integrity sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==
-
-path-parse@^1.0.7:
-  version "1.0.7"
-  resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735"
-  integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==
-
-path-type@^4.0.0:
-  version "4.0.0"
-  resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b"
-  integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==
-
-path@^0.12.7:
-  version "0.12.7"
-  resolved "https://registry.yarnpkg.com/path/-/path-0.12.7.tgz#d4dc2a506c4ce2197eb481ebfcd5b36c0140b10f"
-  integrity sha512-aXXC6s+1w7otVF9UletFkFcDsJeO7lSZBPUQhtb5O0xJe8LtYhj/GxldoL09bBj9+ZmE2hNoHqQSFMN5fikh4Q==
-  dependencies:
-    process "^0.11.1"
-    util "^0.10.3"
-
-pathe@^0.2.0:
-  version "0.2.0"
-  resolved "https://registry.yarnpkg.com/pathe/-/pathe-0.2.0.tgz#30fd7bbe0a0d91f0e60bae621f5d19e9e225c339"
-  integrity sha512-sTitTPYnn23esFR3RlqYBWn4c45WGeLcsKzQiUpXJAyfcWkolvlYpV8FLo7JishK946oQwMFUCHXQ9AjGPKExw==
-
-picocolors@^1.0.0:
-  version "1.0.0"
-  resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c"
-  integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==
-
-picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.2.2, picomatch@^2.3.1:
-  version "2.3.1"
-  resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42"
-  integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==
-
-pify@^4.0.1:
-  version "4.0.1"
-  resolved "https://registry.yarnpkg.com/pify/-/pify-4.0.1.tgz#4b2cd25c50d598735c50292224fd8c6df41e3231"
-  integrity sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==
-
-pinia-plugin-persistedstate@^1.6.3:
-  version "1.6.3"
-  resolved "https://registry.yarnpkg.com/pinia-plugin-persistedstate/-/pinia-plugin-persistedstate-1.6.3.tgz#6cd691f96814603c70ec5bb756f9f4d037b1aec8"
-  integrity sha512-vwxUca3DZKW6+wnGsgu6hA0ESVKoLovF8vH1jMOPBhaH4VpCSTgn5AsprTxXyg3uMk047m0B+NggeMTcCC8H6w==
-
-pinia@^2.0.17:
-  version "2.0.17"
-  resolved "https://registry.yarnpkg.com/pinia/-/pinia-2.0.17.tgz#f925e5e4f73c15e16dfb4838176a9ca50752f26b"
-  integrity sha512-AtwLwEWQgIjofjgeFT+nxbnK5lT2QwQjaHNEDqpsi2AiCwf/NY78uWTeHUyEhiiJy8+sBmw0ujgQMoQbWiZDfA==
-  dependencies:
-    "@vue/devtools-api" "^6.2.1"
-    vue-demi "*"
-
-pofile@1.0.x:
-  version "1.0.11"
-  resolved "https://registry.yarnpkg.com/pofile/-/pofile-1.0.11.tgz#35aff58c17491d127a07336d5522ebc9df57c954"
-  integrity sha512-Vy9eH1dRD9wHjYt/QqXcTz+RnX/zg53xK+KljFSX30PvdDMb2z+c6uDUeblUGqqJgz3QFsdlA0IJvHziPmWtQg==
-
-pofile@^1.1.3:
-  version "1.1.3"
-  resolved "https://registry.yarnpkg.com/pofile/-/pofile-1.1.3.tgz#e2c0d4052b9829f171b888bfb35c87791dbea297"
-  integrity sha512-sk96pUvpNwDV6PLrnhr68Uu1S5NohsxqLKz0GuracgrDo40BdF/r1RhHnjakUk6Q4Z0OKIybOQ7GevLKGN1iYw==
-
-postcss-calc@^8.2.3:
-  version "8.2.4"
-  resolved "https://registry.yarnpkg.com/postcss-calc/-/postcss-calc-8.2.4.tgz#77b9c29bfcbe8a07ff6693dc87050828889739a5"
-  integrity sha512-SmWMSJmB8MRnnULldx0lQIyhSNvuDl9HfrZkaqqE/WHAhToYsAvDq+yAsA/kIyINDszOp3Rh0GFoNuH5Ypsm3Q==
-  dependencies:
-    postcss-selector-parser "^6.0.9"
-    postcss-value-parser "^4.2.0"
-
-postcss-colormin@^5.3.0:
-  version "5.3.0"
-  resolved "https://registry.yarnpkg.com/postcss-colormin/-/postcss-colormin-5.3.0.tgz#3cee9e5ca62b2c27e84fce63affc0cfb5901956a"
-  integrity sha512-WdDO4gOFG2Z8n4P8TWBpshnL3JpmNmJwdnfP2gbk2qBA8PWwOYcmjmI/t3CmMeL72a7Hkd+x/Mg9O2/0rD54Pg==
-  dependencies:
-    browserslist "^4.16.6"
-    caniuse-api "^3.0.0"
-    colord "^2.9.1"
-    postcss-value-parser "^4.2.0"
-
-postcss-convert-values@^5.1.2:
-  version "5.1.2"
-  resolved "https://registry.yarnpkg.com/postcss-convert-values/-/postcss-convert-values-5.1.2.tgz#31586df4e184c2e8890e8b34a0b9355313f503ab"
-  integrity sha512-c6Hzc4GAv95B7suy4udszX9Zy4ETyMCgFPUDtWjdFTKH1SE9eFY/jEpHSwTH1QPuwxHpWslhckUQWbNRM4ho5g==
-  dependencies:
-    browserslist "^4.20.3"
-    postcss-value-parser "^4.2.0"
-
-postcss-discard-comments@^5.1.2:
-  version "5.1.2"
-  resolved "https://registry.yarnpkg.com/postcss-discard-comments/-/postcss-discard-comments-5.1.2.tgz#8df5e81d2925af2780075840c1526f0660e53696"
-  integrity sha512-+L8208OVbHVF2UQf1iDmRcbdjJkuBF6IS29yBDSiWUIzpYaAhtNl6JYnYm12FnkeCwQqF5LeklOu6rAqgfBZqQ==
-
-postcss-discard-duplicates@^5.1.0:
-  version "5.1.0"
-  resolved "https://registry.yarnpkg.com/postcss-discard-duplicates/-/postcss-discard-duplicates-5.1.0.tgz#9eb4fe8456706a4eebd6d3b7b777d07bad03e848"
-  integrity sha512-zmX3IoSI2aoenxHV6C7plngHWWhUOV3sP1T8y2ifzxzbtnuhk1EdPwm0S1bIUNaJ2eNbWeGLEwzw8huPD67aQw==
-
-postcss-discard-empty@^5.1.1:
-  version "5.1.1"
-  resolved "https://registry.yarnpkg.com/postcss-discard-empty/-/postcss-discard-empty-5.1.1.tgz#e57762343ff7f503fe53fca553d18d7f0c369c6c"
-  integrity sha512-zPz4WljiSuLWsI0ir4Mcnr4qQQ5e1Ukc3i7UfE2XcrwKK2LIPIqE5jxMRxO6GbI3cv//ztXDsXwEWT3BHOGh3A==
-
-postcss-discard-overridden@^5.1.0:
-  version "5.1.0"
-  resolved "https://registry.yarnpkg.com/postcss-discard-overridden/-/postcss-discard-overridden-5.1.0.tgz#7e8c5b53325747e9d90131bb88635282fb4a276e"
-  integrity sha512-21nOL7RqWR1kasIVdKs8HNqQJhFxLsyRfAnUDm4Fe4t4mCWL9OJiHvlHPjcd8zc5Myu89b/7wZDnOSjFgeWRtw==
-
-postcss-merge-longhand@^5.1.6:
-  version "5.1.6"
-  resolved "https://registry.yarnpkg.com/postcss-merge-longhand/-/postcss-merge-longhand-5.1.6.tgz#f378a8a7e55766b7b644f48e5d8c789ed7ed51ce"
-  integrity sha512-6C/UGF/3T5OE2CEbOuX7iNO63dnvqhGZeUnKkDeifebY0XqkkvrctYSZurpNE902LDf2yKwwPFgotnfSoPhQiw==
-  dependencies:
-    postcss-value-parser "^4.2.0"
-    stylehacks "^5.1.0"
-
-postcss-merge-rules@^5.1.2:
-  version "5.1.2"
-  resolved "https://registry.yarnpkg.com/postcss-merge-rules/-/postcss-merge-rules-5.1.2.tgz#7049a14d4211045412116d79b751def4484473a5"
-  integrity sha512-zKMUlnw+zYCWoPN6yhPjtcEdlJaMUZ0WyVcxTAmw3lkkN/NDMRkOkiuctQEoWAOvH7twaxUUdvBWl0d4+hifRQ==
-  dependencies:
-    browserslist "^4.16.6"
-    caniuse-api "^3.0.0"
-    cssnano-utils "^3.1.0"
-    postcss-selector-parser "^6.0.5"
-
-postcss-minify-font-values@^5.1.0:
-  version "5.1.0"
-  resolved "https://registry.yarnpkg.com/postcss-minify-font-values/-/postcss-minify-font-values-5.1.0.tgz#f1df0014a726083d260d3bd85d7385fb89d1f01b"
-  integrity sha512-el3mYTgx13ZAPPirSVsHqFzl+BBBDrXvbySvPGFnQcTI4iNslrPaFq4muTkLZmKlGk4gyFAYUBMH30+HurREyA==
-  dependencies:
-    postcss-value-parser "^4.2.0"
-
-postcss-minify-gradients@^5.1.1:
-  version "5.1.1"
-  resolved "https://registry.yarnpkg.com/postcss-minify-gradients/-/postcss-minify-gradients-5.1.1.tgz#f1fe1b4f498134a5068240c2f25d46fcd236ba2c"
-  integrity sha512-VGvXMTpCEo4qHTNSa9A0a3D+dxGFZCYwR6Jokk+/3oB6flu2/PnPXAh2x7x52EkY5xlIHLm+Le8tJxe/7TNhzw==
-  dependencies:
-    colord "^2.9.1"
-    cssnano-utils "^3.1.0"
-    postcss-value-parser "^4.2.0"
-
-postcss-minify-params@^5.1.3:
-  version "5.1.3"
-  resolved "https://registry.yarnpkg.com/postcss-minify-params/-/postcss-minify-params-5.1.3.tgz#ac41a6465be2db735099bbd1798d85079a6dc1f9"
-  integrity sha512-bkzpWcjykkqIujNL+EVEPOlLYi/eZ050oImVtHU7b4lFS82jPnsCb44gvC6pxaNt38Els3jWYDHTjHKf0koTgg==
-  dependencies:
-    browserslist "^4.16.6"
-    cssnano-utils "^3.1.0"
-    postcss-value-parser "^4.2.0"
-
-postcss-minify-selectors@^5.2.1:
-  version "5.2.1"
-  resolved "https://registry.yarnpkg.com/postcss-minify-selectors/-/postcss-minify-selectors-5.2.1.tgz#d4e7e6b46147b8117ea9325a915a801d5fe656c6"
-  integrity sha512-nPJu7OjZJTsVUmPdm2TcaiohIwxP+v8ha9NehQ2ye9szv4orirRU3SDdtUmKH+10nzn0bAyOXZ0UEr7OpvLehg==
-  dependencies:
-    postcss-selector-parser "^6.0.5"
-
-postcss-normalize-charset@^5.1.0:
-  version "5.1.0"
-  resolved "https://registry.yarnpkg.com/postcss-normalize-charset/-/postcss-normalize-charset-5.1.0.tgz#9302de0b29094b52c259e9b2cf8dc0879879f0ed"
-  integrity sha512-mSgUJ+pd/ldRGVx26p2wz9dNZ7ji6Pn8VWBajMXFf8jk7vUoSrZ2lt/wZR7DtlZYKesmZI680qjr2CeFF2fbUg==
-
-postcss-normalize-display-values@^5.1.0:
-  version "5.1.0"
-  resolved "https://registry.yarnpkg.com/postcss-normalize-display-values/-/postcss-normalize-display-values-5.1.0.tgz#72abbae58081960e9edd7200fcf21ab8325c3da8"
-  integrity sha512-WP4KIM4o2dazQXWmFaqMmcvsKmhdINFblgSeRgn8BJ6vxaMyaJkwAzpPpuvSIoG/rmX3M+IrRZEz2H0glrQNEA==
-  dependencies:
-    postcss-value-parser "^4.2.0"
-
-postcss-normalize-positions@^5.1.1:
-  version "5.1.1"
-  resolved "https://registry.yarnpkg.com/postcss-normalize-positions/-/postcss-normalize-positions-5.1.1.tgz#ef97279d894087b59325b45c47f1e863daefbb92"
-  integrity sha512-6UpCb0G4eofTCQLFVuI3EVNZzBNPiIKcA1AKVka+31fTVySphr3VUgAIULBhxZkKgwLImhzMR2Bw1ORK+37INg==
-  dependencies:
-    postcss-value-parser "^4.2.0"
-
-postcss-normalize-repeat-style@^5.1.1:
-  version "5.1.1"
-  resolved "https://registry.yarnpkg.com/postcss-normalize-repeat-style/-/postcss-normalize-repeat-style-5.1.1.tgz#e9eb96805204f4766df66fd09ed2e13545420fb2"
-  integrity sha512-mFpLspGWkQtBcWIRFLmewo8aC3ImN2i/J3v8YCFUwDnPu3Xz4rLohDO26lGjwNsQxB3YF0KKRwspGzE2JEuS0g==
-  dependencies:
-    postcss-value-parser "^4.2.0"
-
-postcss-normalize-string@^5.1.0:
-  version "5.1.0"
-  resolved "https://registry.yarnpkg.com/postcss-normalize-string/-/postcss-normalize-string-5.1.0.tgz#411961169e07308c82c1f8c55f3e8a337757e228"
-  integrity sha512-oYiIJOf4T9T1N4i+abeIc7Vgm/xPCGih4bZz5Nm0/ARVJ7K6xrDlLwvwqOydvyL3RHNf8qZk6vo3aatiw/go3w==
-  dependencies:
-    postcss-value-parser "^4.2.0"
-
-postcss-normalize-timing-functions@^5.1.0:
-  version "5.1.0"
-  resolved "https://registry.yarnpkg.com/postcss-normalize-timing-functions/-/postcss-normalize-timing-functions-5.1.0.tgz#d5614410f8f0b2388e9f240aa6011ba6f52dafbb"
-  integrity sha512-DOEkzJ4SAXv5xkHl0Wa9cZLF3WCBhF3o1SKVxKQAa+0pYKlueTpCgvkFAHfk+Y64ezX9+nITGrDZeVGgITJXjg==
-  dependencies:
-    postcss-value-parser "^4.2.0"
-
-postcss-normalize-unicode@^5.1.0:
-  version "5.1.0"
-  resolved "https://registry.yarnpkg.com/postcss-normalize-unicode/-/postcss-normalize-unicode-5.1.0.tgz#3d23aede35e160089a285e27bf715de11dc9db75"
-  integrity sha512-J6M3MizAAZ2dOdSjy2caayJLQT8E8K9XjLce8AUQMwOrCvjCHv24aLC/Lps1R1ylOfol5VIDMaM/Lo9NGlk1SQ==
-  dependencies:
-    browserslist "^4.16.6"
-    postcss-value-parser "^4.2.0"
-
-postcss-normalize-url@^5.1.0:
-  version "5.1.0"
-  resolved "https://registry.yarnpkg.com/postcss-normalize-url/-/postcss-normalize-url-5.1.0.tgz#ed9d88ca82e21abef99f743457d3729a042adcdc"
-  integrity sha512-5upGeDO+PVthOxSmds43ZeMeZfKH+/DKgGRD7TElkkyS46JXAUhMzIKiCa7BabPeIy3AQcTkXwVVN7DbqsiCew==
-  dependencies:
-    normalize-url "^6.0.1"
-    postcss-value-parser "^4.2.0"
-
-postcss-normalize-whitespace@^5.1.1:
-  version "5.1.1"
-  resolved "https://registry.yarnpkg.com/postcss-normalize-whitespace/-/postcss-normalize-whitespace-5.1.1.tgz#08a1a0d1ffa17a7cc6efe1e6c9da969cc4493cfa"
-  integrity sha512-83ZJ4t3NUDETIHTa3uEg6asWjSBYL5EdkVB0sDncx9ERzOKBVJIUeDO9RyA9Zwtig8El1d79HBp0JEi8wvGQnA==
-  dependencies:
-    postcss-value-parser "^4.2.0"
-
-postcss-ordered-values@^5.1.3:
-  version "5.1.3"
-  resolved "https://registry.yarnpkg.com/postcss-ordered-values/-/postcss-ordered-values-5.1.3.tgz#b6fd2bd10f937b23d86bc829c69e7732ce76ea38"
-  integrity sha512-9UO79VUhPwEkzbb3RNpqqghc6lcYej1aveQteWY+4POIwlqkYE21HKWaLDF6lWNuqCobEAyTovVhtI32Rbv2RQ==
-  dependencies:
-    cssnano-utils "^3.1.0"
-    postcss-value-parser "^4.2.0"
-
-postcss-reduce-initial@^5.1.0:
-  version "5.1.0"
-  resolved "https://registry.yarnpkg.com/postcss-reduce-initial/-/postcss-reduce-initial-5.1.0.tgz#fc31659ea6e85c492fb2a7b545370c215822c5d6"
-  integrity sha512-5OgTUviz0aeH6MtBjHfbr57tml13PuedK/Ecg8szzd4XRMbYxH4572JFG067z+FqBIf6Zp/d+0581glkvvWMFw==
-  dependencies:
-    browserslist "^4.16.6"
-    caniuse-api "^3.0.0"
-
-postcss-reduce-transforms@^5.1.0:
-  version "5.1.0"
-  resolved "https://registry.yarnpkg.com/postcss-reduce-transforms/-/postcss-reduce-transforms-5.1.0.tgz#333b70e7758b802f3dd0ddfe98bb1ccfef96b6e9"
-  integrity sha512-2fbdbmgir5AvpW9RLtdONx1QoYG2/EtqpNQbFASDlixBbAYuTcJ0dECwlqNqH7VbaUnEnh8SrxOe2sRIn24XyQ==
-  dependencies:
-    postcss-value-parser "^4.2.0"
-
-postcss-selector-parser@^6.0.4, postcss-selector-parser@^6.0.5, postcss-selector-parser@^6.0.9:
-  version "6.0.10"
-  resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-6.0.10.tgz#79b61e2c0d1bfc2602d549e11d0876256f8df88d"
-  integrity sha512-IQ7TZdoaqbT+LCpShg46jnZVlhWD2w6iQYAcYXfHARZ7X1t/UGhhceQDs5X0cGqKvYlHNOuv7Oa1xmb0oQuA3w==
-  dependencies:
-    cssesc "^3.0.0"
-    util-deprecate "^1.0.2"
-
-postcss-svgo@^5.1.0:
-  version "5.1.0"
-  resolved "https://registry.yarnpkg.com/postcss-svgo/-/postcss-svgo-5.1.0.tgz#0a317400ced789f233a28826e77523f15857d80d"
-  integrity sha512-D75KsH1zm5ZrHyxPakAxJWtkyXew5qwS70v56exwvw542d9CRtTo78K0WeFxZB4G7JXKKMbEZtZayTGdIky/eA==
-  dependencies:
-    postcss-value-parser "^4.2.0"
-    svgo "^2.7.0"
-
-postcss-unique-selectors@^5.1.1:
-  version "5.1.1"
-  resolved "https://registry.yarnpkg.com/postcss-unique-selectors/-/postcss-unique-selectors-5.1.1.tgz#a9f273d1eacd09e9aa6088f4b0507b18b1b541b6"
-  integrity sha512-5JiODlELrz8L2HwxfPnhOWZYWDxVHWL83ufOv84NrcgipI7TaeRsatAhK4Tr2/ZiYldpK/wBvw5BD3qfaK96GA==
-  dependencies:
-    postcss-selector-parser "^6.0.5"
-
-postcss-value-parser@^4.2.0:
-  version "4.2.0"
-  resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz#723c09920836ba6d3e5af019f92bc0971c02e514"
-  integrity sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==
-
-postcss@^8.1.10, postcss@^8.2.9, postcss@^8.4.14:
-  version "8.4.14"
-  resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.4.14.tgz#ee9274d5622b4858c1007a74d76e42e56fd21caf"
-  integrity sha512-E398TUmfAYFPBSdzgeieK2Y1+1cpdxJx8yXbK/m57nRhKSmk1GB2tO4lbLBtlkfPQTDKfe4Xqv1ASWPpayPEig==
-  dependencies:
-    nanoid "^3.3.4"
-    picocolors "^1.0.0"
-    source-map-js "^1.0.2"
-
-prettier@^2.5.0:
-  version "2.7.1"
-  resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.7.1.tgz#e235806850d057f97bb08368a4f7d899f7760c64"
-  integrity sha512-ujppO+MkdPqoVINuDFDRLClm7D78qbDt0/NR+wp5FqEZOoTNAjPHWj17QRhu7geIHJfcNhRk1XVQmF8Bp3ye+g==
-
-process@^0.11.1:
-  version "0.11.10"
-  resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182"
-  integrity sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==
-
-prr@~1.0.1:
-  version "1.0.1"
-  resolved "https://registry.yarnpkg.com/prr/-/prr-1.0.1.tgz#d3fc114ba06995a45ec6893f484ceb1d78f5f476"
-  integrity sha512-yPw4Sng1gWghHQWj0B3ZggWUm4qVbPwPFcRG8KyxiU7J2OHFSoEHKS+EZ3fv5l1t9CyCiop6l/ZYeWbrgoQejw==
-
-queue-microtask@^1.2.2:
-  version "1.2.3"
-  resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243"
-  integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==
-
-readdirp@~3.6.0:
-  version "3.6.0"
-  resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.6.0.tgz#74a370bd857116e245b29cc97340cd431a02a6c7"
-  integrity sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==
-  dependencies:
-    picomatch "^2.2.1"
-
-reconnecting-websocket@^4.4.0:
-  version "4.4.0"
-  resolved "https://registry.yarnpkg.com/reconnecting-websocket/-/reconnecting-websocket-4.4.0.tgz#3b0e5b96ef119e78a03135865b8bb0af1b948783"
-  integrity sha512-D2E33ceRPga0NvTDhJmphEgJ7FUYF0v4lr1ki0csq06OdlxKfugGzN0dSkxM/NfqCxYELK4KcaTOUOjTV6Dcng==
-
-regenerator-runtime@^0.13.4:
-  version "0.13.9"
-  resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz#8925742a98ffd90814988d7566ad30ca3b263b52"
-  integrity sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==
-
-relateurl@^0.2.7:
-  version "0.2.7"
-  resolved "https://registry.yarnpkg.com/relateurl/-/relateurl-0.2.7.tgz#54dbf377e51440aca90a4cd274600d3ff2d888a9"
-  integrity sha512-G08Dxvm4iDN3MLM0EsP62EDV9IuhXPR6blNz6Utcp7zyV3tr4HVNINt6MpaRWbxoOHT3Q7YN2P+jaHX8vUbgog==
-
-resize-observer-polyfill@^1.5.1:
-  version "1.5.1"
-  resolved "https://registry.yarnpkg.com/resize-observer-polyfill/-/resize-observer-polyfill-1.5.1.tgz#0e9020dd3d21024458d4ebd27e23e40269810464"
-  integrity sha512-LwZrotdHOo12nQuZlHEmtuXdqGoOD0OhaxopaNFxWzInpEgaLWoVuAMbTzixuosCx2nEG58ngzW3vxdWoxIgdg==
-
-resolve-from@^4.0.0:
-  version "4.0.0"
-  resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6"
-  integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==
-
-resolve@^1.22.1:
-  version "1.22.1"
-  resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.1.tgz#27cb2ebb53f91abb49470a928bba7558066ac177"
-  integrity sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==
-  dependencies:
-    is-core-module "^2.9.0"
-    path-parse "^1.0.7"
-    supports-preserve-symlinks-flag "^1.0.0"
-
-reusify@^1.0.4:
-  version "1.0.4"
-  resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76"
-  integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==
-
-rimraf@^3.0.2:
-  version "3.0.2"
-  resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a"
-  integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==
-  dependencies:
-    glob "^7.1.3"
-
-rollup@^2.75.6:
-  version "2.77.2"
-  resolved "https://registry.yarnpkg.com/rollup/-/rollup-2.77.2.tgz#6b6075c55f9cc2040a5912e6e062151e42e2c4e3"
-  integrity sha512-m/4YzYgLcpMQbxX3NmAqDvwLATZzxt8bIegO78FZLl+lAgKJBd1DRAOeEiZcKOIOPjxE6ewHWHNgGEalFXuz1g==
-  optionalDependencies:
-    fsevents "~2.3.2"
-
-run-parallel@^1.1.9:
-  version "1.2.0"
-  resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.2.0.tgz#66d1368da7bdf921eb9d95bd1a9229e7f21a43ee"
-  integrity sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==
-  dependencies:
-    queue-microtask "^1.2.2"
-
-safe-buffer@~5.1.1:
-  version "5.1.2"
-  resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d"
-  integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==
-
-"safer-buffer@>= 2.1.2 < 3.0.0":
-  version "2.1.2"
-  resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a"
-  integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==
-
-sax@^1.2.4:
-  version "1.2.4"
-  resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9"
-  integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==
-
-scroll-into-view-if-needed@^2.2.25:
-  version "2.2.29"
-  resolved "https://registry.yarnpkg.com/scroll-into-view-if-needed/-/scroll-into-view-if-needed-2.2.29.tgz#551791a84b7e2287706511f8c68161e4990ab885"
-  integrity sha512-hxpAR6AN+Gh53AdAimHM6C8oTN1ppwVZITihix+WqalywBeFcQ6LdQP5ABNl26nX8GTEL7VT+b8lKpdqq65wXg==
-  dependencies:
-    compute-scroll-into-view "^1.0.17"
-
-semver@^5.6.0:
-  version "5.7.1"
-  resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7"
-  integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==
-
-semver@^6.3.0:
-  version "6.3.0"
-  resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d"
-  integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==
-
-shallow-equal@^1.0.0:
-  version "1.2.1"
-  resolved "https://registry.yarnpkg.com/shallow-equal/-/shallow-equal-1.2.1.tgz#4c16abfa56043aa20d050324efa68940b0da79da"
-  integrity sha512-S4vJDjHHMBaiZuT9NPb616CSmLf618jawtv3sufLl6ivK8WocjAo58cXwbRV1cgqxH0Qbv+iUt6m05eqEa2IRA==
-
-simple-swizzle@^0.2.2:
-  version "0.2.2"
-  resolved "https://registry.yarnpkg.com/simple-swizzle/-/simple-swizzle-0.2.2.tgz#a4da6b635ffcccca33f70d17cb92592de95e557a"
-  integrity sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==
-  dependencies:
-    is-arrayish "^0.3.1"
-
-source-map-js@^1.0.2:
-  version "1.0.2"
-  resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-1.0.2.tgz#adbc361d9c62df380125e7f161f71c826f1e490c"
-  integrity sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==
-
-source-map-support@~0.5.20:
-  version "0.5.21"
-  resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.21.tgz#04fe7c7f9e1ed2d662233c28cb2b35b9f63f6e4f"
-  integrity sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==
-  dependencies:
-    buffer-from "^1.0.0"
-    source-map "^0.6.0"
-
-source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.0:
-  version "0.6.1"
-  resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263"
-  integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==
-
-sourcemap-codec@^1.4.8:
-  version "1.4.8"
-  resolved "https://registry.yarnpkg.com/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz#ea804bd94857402e6992d05a38ef1ae35a9ab4c4"
-  integrity sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==
-
-stable@^0.1.8:
-  version "0.1.8"
-  resolved "https://registry.yarnpkg.com/stable/-/stable-0.1.8.tgz#836eb3c8382fe2936feaf544631017ce7d47a3cf"
-  integrity sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w==
-
-string-hash@^1.1.3:
-  version "1.1.3"
-  resolved "https://registry.yarnpkg.com/string-hash/-/string-hash-1.1.3.tgz#e8aafc0ac1855b4666929ed7dd1275df5d6c811b"
-  integrity sha512-kJUvRUFK49aub+a7T1nNE66EJbZBMnBgoC1UbCZ5n6bsZKBRga4KgBRTMn/pFkeCZSYtNeSyMxPDM0AXWELk2A==
-
-stylehacks@^5.1.0:
-  version "5.1.0"
-  resolved "https://registry.yarnpkg.com/stylehacks/-/stylehacks-5.1.0.tgz#a40066490ca0caca04e96c6b02153ddc39913520"
-  integrity sha512-SzLmvHQTrIWfSgljkQCw2++C9+Ne91d/6Sp92I8c5uHTcy/PgeHamwITIbBW9wnFTY/3ZfSXR9HIL6Ikqmcu6Q==
-  dependencies:
-    browserslist "^4.16.6"
-    postcss-selector-parser "^6.0.4"
-
-supports-color@^5.3.0:
-  version "5.5.0"
-  resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f"
-  integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==
-  dependencies:
-    has-flag "^3.0.0"
-
-supports-color@^7.1.0:
-  version "7.2.0"
-  resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da"
-  integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==
-  dependencies:
-    has-flag "^4.0.0"
-
-supports-preserve-symlinks-flag@^1.0.0:
-  version "1.0.0"
-  resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09"
-  integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==
-
-svg-tags@^1.0.0:
-  version "1.0.0"
-  resolved "https://registry.yarnpkg.com/svg-tags/-/svg-tags-1.0.0.tgz#58f71cee3bd519b59d4b2a843b6c7de64ac04764"
-  integrity sha512-ovssysQTa+luh7A5Weu3Rta6FJlFBBbInjOh722LIt6klpU2/HtdUbszju/G4devcvk8PGt7FCLv5wftu3THUA==
-
-svg.draggable.js@^2.2.2:
-  version "2.2.2"
-  resolved "https://registry.yarnpkg.com/svg.draggable.js/-/svg.draggable.js-2.2.2.tgz#c514a2f1405efb6f0263e7958f5b68fce50603ba"
-  integrity sha512-JzNHBc2fLQMzYCZ90KZHN2ohXL0BQJGQimK1kGk6AvSeibuKcIdDX9Kr0dT9+UJ5O8nYA0RB839Lhvk4CY4MZw==
-  dependencies:
-    svg.js "^2.0.1"
-
-svg.easing.js@^2.0.0:
-  version "2.0.0"
-  resolved "https://registry.yarnpkg.com/svg.easing.js/-/svg.easing.js-2.0.0.tgz#8aa9946b0a8e27857a5c40a10eba4091e5691f12"
-  integrity sha512-//ctPdJMGy22YoYGV+3HEfHbm6/69LJUTAqI2/5qBvaNHZ9uUFVC82B0Pl299HzgH13rKrBgi4+XyXXyVWWthA==
-  dependencies:
-    svg.js ">=2.3.x"
-
-svg.filter.js@^2.0.2:
-  version "2.0.2"
-  resolved "https://registry.yarnpkg.com/svg.filter.js/-/svg.filter.js-2.0.2.tgz#91008e151389dd9230779fcbe6e2c9a362d1c203"
-  integrity sha512-xkGBwU+dKBzqg5PtilaTb0EYPqPfJ9Q6saVldX+5vCRy31P6TlRCP3U9NxH3HEufkKkpNgdTLBJnmhDHeTqAkw==
-  dependencies:
-    svg.js "^2.2.5"
-
-svg.js@>=2.3.x, svg.js@^2.0.1, svg.js@^2.2.5, svg.js@^2.4.0, svg.js@^2.6.5:
-  version "2.7.1"
-  resolved "https://registry.yarnpkg.com/svg.js/-/svg.js-2.7.1.tgz#eb977ed4737001eab859949b4a398ee1bb79948d"
-  integrity sha512-ycbxpizEQktk3FYvn/8BH+6/EuWXg7ZpQREJvgacqn46gIddG24tNNe4Son6omdXCnSOaApnpZw6MPCBA1dODA==
-
-svg.pathmorphing.js@^0.1.3:
-  version "0.1.3"
-  resolved "https://registry.yarnpkg.com/svg.pathmorphing.js/-/svg.pathmorphing.js-0.1.3.tgz#c25718a1cc7c36e852ecabc380e758ac09bb2b65"
-  integrity sha512-49HWI9X4XQR/JG1qXkSDV8xViuTLIWm/B/7YuQELV5KMOPtXjiwH4XPJvr/ghEDibmLQ9Oc22dpWpG0vUDDNww==
-  dependencies:
-    svg.js "^2.4.0"
-
-svg.resize.js@^1.4.3:
-  version "1.4.3"
-  resolved "https://registry.yarnpkg.com/svg.resize.js/-/svg.resize.js-1.4.3.tgz#885abd248e0cd205b36b973c4b578b9a36f23332"
-  integrity sha512-9k5sXJuPKp+mVzXNvxz7U0uC9oVMQrrf7cFsETznzUDDm0x8+77dtZkWdMfRlmbkEEYvUn9btKuZ3n41oNA+uw==
-  dependencies:
-    svg.js "^2.6.5"
-    svg.select.js "^2.1.2"
-
-svg.select.js@^2.1.2:
-  version "2.1.2"
-  resolved "https://registry.yarnpkg.com/svg.select.js/-/svg.select.js-2.1.2.tgz#e41ce13b1acff43a7441f9f8be87a2319c87be73"
-  integrity sha512-tH6ABEyJsAOVAhwcCjF8mw4crjXSI1aa7j2VQR8ZuJ37H2MBUbyeqYr5nEO7sSN3cy9AR9DUwNg0t/962HlDbQ==
-  dependencies:
-    svg.js "^2.2.5"
-
-svg.select.js@^3.0.1:
-  version "3.0.1"
-  resolved "https://registry.yarnpkg.com/svg.select.js/-/svg.select.js-3.0.1.tgz#a4198e359f3825739226415f82176a90ea5cc917"
-  integrity sha512-h5IS/hKkuVCbKSieR9uQCj9w+zLHoPh+ce19bBYyqF53g6mnPB8sAtIbe1s9dh2S2fCmYX2xel1Ln3PJBbK4kw==
-  dependencies:
-    svg.js "^2.6.5"
-
-svgo@^2.7.0:
-  version "2.8.0"
-  resolved "https://registry.yarnpkg.com/svgo/-/svgo-2.8.0.tgz#4ff80cce6710dc2795f0c7c74101e6764cfccd24"
-  integrity sha512-+N/Q9kV1+F+UeWYoSiULYo4xYSDQlTgb+ayMobAXPwMnLvop7oxKMo9OzIrX5x3eS4L4f2UHhc9axXwY8DpChg==
-  dependencies:
-    "@trysound/sax" "0.2.0"
-    commander "^7.2.0"
-    css-select "^4.1.3"
-    css-tree "^1.1.3"
-    csso "^4.2.0"
-    picocolors "^1.0.0"
-    stable "^0.1.8"
-
-terser@^5.10.0:
-  version "5.14.2"
-  resolved "https://registry.yarnpkg.com/terser/-/terser-5.14.2.tgz#9ac9f22b06994d736174f4091aa368db896f1c10"
-  integrity sha512-oL0rGeM/WFQCUd0y2QrWxYnq7tfSuKBiqTjRPWrRgB46WD/kiwHwF8T23z78H6Q6kGCuuHcPB+KULHRdxvVGQA==
-  dependencies:
-    "@jridgewell/source-map" "^0.3.2"
-    acorn "^8.5.0"
-    commander "^2.20.0"
-    source-map-support "~0.5.20"
-
-to-fast-properties@^2.0.0:
-  version "2.0.0"
-  resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e"
-  integrity sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==
-
-to-regex-range@^5.0.1:
-  version "5.0.1"
-  resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4"
-  integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==
-  dependencies:
-    is-number "^7.0.0"
-
-tslib@^2.0.3, tslib@^2.3.0, tslib@^2.3.1:
-  version "2.4.0"
-  resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.4.0.tgz#7cecaa7f073ce680a05847aa77be941098f36dc3"
-  integrity sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==
-
-"typescript@2 - 4", typescript@^4.6.4, typescript@^4.7.4:
-  version "4.7.4"
-  resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.7.4.tgz#1a88596d1cf47d59507a1bcdfb5b9dfe4d488235"
-  integrity sha512-C0WQT0gezHuw6AdY1M2jxUO83Rjf0HP7Sk1DtXj6j1EwkQNZrHAg2XPWlq62oqEhYvONq5pkC2Y9oPljWToLmQ==
-
-typical@^4.0.0:
-  version "4.0.0"
-  resolved "https://registry.yarnpkg.com/typical/-/typical-4.0.0.tgz#cbeaff3b9d7ae1e2bbfaf5a4e6f11eccfde94fc4"
-  integrity sha512-VAH4IvQ7BDFYglMd7BPRDfLgxZZX4O4TFcRDA6EN5X7erNJJq+McIEp8np9aVtxrCJ6qx4GTYVfOWNjcqwZgRw==
-
-universalify@^2.0.0:
-  version "2.0.0"
-  resolved "https://registry.yarnpkg.com/universalify/-/universalify-2.0.0.tgz#75a4984efedc4b08975c5aeb73f530d02df25717"
-  integrity sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==
-
-unplugin-vue-components@^0.21.2:
-  version "0.21.2"
-  resolved "https://registry.yarnpkg.com/unplugin-vue-components/-/unplugin-vue-components-0.21.2.tgz#d5b04b05e0521aa71fdfdba0b4ca392e3caa964d"
-  integrity sha512-HBU+EuesDj/HRs7EtYH7gBACljVhqLylltrCLModRmCToIIrrNvMh54aylUt4AD4qiwylgOx4Vgb9sBlrIcRDw==
-  dependencies:
-    "@antfu/utils" "^0.5.2"
-    "@rollup/pluginutils" "^4.2.1"
-    chokidar "^3.5.3"
-    debug "^4.3.4"
-    fast-glob "^3.2.11"
-    local-pkg "^0.4.2"
-    magic-string "^0.26.2"
-    minimatch "^5.1.0"
-    resolve "^1.22.1"
-    unplugin "^0.7.2"
-
-unplugin@^0.7.2:
-  version "0.7.2"
-  resolved "https://registry.yarnpkg.com/unplugin/-/unplugin-0.7.2.tgz#4127012fdc2c84ea4ce03ce75e3d4f54ea47bba1"
-  integrity sha512-m7thX4jP8l5sETpLdUASoDOGOcHaOVtgNyrYlToyQUvILUtEzEnngRBrHnAX3IKqooJVmXpoa/CwQ/QqzvGaHQ==
-  dependencies:
-    acorn "^8.7.1"
-    chokidar "^3.5.3"
-    webpack-sources "^3.2.3"
-    webpack-virtual-modules "^0.4.4"
-
-update-browserslist-db@^1.0.5:
-  version "1.0.5"
-  resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.0.5.tgz#be06a5eedd62f107b7c19eb5bcefb194411abf38"
-  integrity sha512-dteFFpCyvuDdr9S/ff1ISkKt/9YZxKjI9WlRR99c180GaztJtRa/fn18FdxGVKVsnPY7/a/FDN68mcvUmP4U7Q==
-  dependencies:
-    escalade "^3.1.1"
-    picocolors "^1.0.0"
-
-util-deprecate@^1.0.2:
-  version "1.0.2"
-  resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"
-  integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==
-
-util@^0.10.3:
-  version "0.10.4"
-  resolved "https://registry.yarnpkg.com/util/-/util-0.10.4.tgz#3aa0125bfe668a4672de58857d3ace27ecb76901"
-  integrity sha512-0Pm9hTQ3se5ll1XihRic3FDIku70C+iHUdT/W926rSgHV5QgXsYbKZN8MSC3tJtSkhuROzvsQjAaFENRXr+19A==
-  dependencies:
-    inherits "2.0.3"
-
-uuid@^8.3.2:
-  version "8.3.2"
-  resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2"
-  integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==
-
-vite-plugin-build-id@^0.1.1:
-  version "0.1.1"
-  resolved "https://registry.yarnpkg.com/vite-plugin-build-id/-/vite-plugin-build-id-0.1.1.tgz#dbd95512f2e53949d06e426216b4893b624a828a"
-  integrity sha512-dnrAlSxq9yzhCM+31nMOUh8pYnhuNk76BZuT31d5GtTD7ilr+SrJoqK5NOQTAZe1+Zkp3kq8xFlgOoVpS4RCCg==
-  dependencies:
-    "@types/node" "^18.6.3"
-    rimraf "^3.0.2"
-    typescript "^4.7.4"
-    vite "^3.0.4"
-
-vite-plugin-html@^3.2.0:
-  version "3.2.0"
-  resolved "https://registry.yarnpkg.com/vite-plugin-html/-/vite-plugin-html-3.2.0.tgz#0d4df9900642a321a139f1c25c05195ba9d0ec79"
-  integrity sha512-2VLCeDiHmV/BqqNn5h2V+4280KRgQzCFN47cst3WiNK848klESPQnzuC3okH5XHtgwHH/6s1Ho/YV6yIO0pgoQ==
-  dependencies:
-    "@rollup/pluginutils" "^4.2.0"
-    colorette "^2.0.16"
-    connect-history-api-fallback "^1.6.0"
-    consola "^2.15.3"
-    dotenv "^16.0.0"
-    dotenv-expand "^8.0.2"
-    ejs "^3.1.6"
-    fast-glob "^3.2.11"
-    fs-extra "^10.0.1"
-    html-minifier-terser "^6.1.0"
-    node-html-parser "^5.3.3"
-    pathe "^0.2.0"
-
-vite@^3.0.0, vite@^3.0.4:
-  version "3.0.4"
-  resolved "https://registry.yarnpkg.com/vite/-/vite-3.0.4.tgz#c61688d6b97573e96cf5ac25f2d68597b5ce68e8"
-  integrity sha512-NU304nqnBeOx2MkQnskBQxVsa0pRAH5FphokTGmyy8M3oxbvw7qAXts2GORxs+h/2vKsD+osMhZ7An6yK6F1dA==
-  dependencies:
-    esbuild "^0.14.47"
-    postcss "^8.4.14"
-    resolve "^1.22.1"
-    rollup "^2.75.6"
-  optionalDependencies:
-    fsevents "~2.3.2"
-
-vue-chartjs@^4.1.1:
-  version "4.1.1"
-  resolved "https://registry.yarnpkg.com/vue-chartjs/-/vue-chartjs-4.1.1.tgz#b1ffc2845e09d14cb5255305b11bd3e8df8058ab"
-  integrity sha512-rKIQ3jPrjhwxjKdNJppnYxRuBSrx4QeM3nNHsfIxEqjX6QS4Jq6e6vnZBxh2MDpURDC2uvuI2N0eIt1cWXbBVA==
-
-vue-demi@*:
-  version "0.13.6"
-  resolved "https://registry.yarnpkg.com/vue-demi/-/vue-demi-0.13.6.tgz#f9433cbd75e68a970dec066647f4ba6c08ced48f"
-  integrity sha512-02NYpxgyGE2kKGegRPYlNQSL1UWfA/+JqvzhGCOYjhfbLWXU5QQX0+9pAm/R2sCOPKr5NBxVIab7fvFU0B1RxQ==
-
-vue-router@4:
-  version "4.1.3"
-  resolved "https://registry.yarnpkg.com/vue-router/-/vue-router-4.1.3.tgz#f8dc7931a2253cc5aa9b740f8b98969d08ca283c"
-  integrity sha512-XvK81bcYglKiayT7/vYAg/f36ExPC4t90R/HIpzrZ5x+17BOWptXLCrEPufGgZeuq68ww4ekSIMBZY1qdUdfjA==
-  dependencies:
-    "@vue/devtools-api" "^6.1.4"
-
-vue-tsc@^0.38.4:
-  version "0.38.9"
-  resolved "https://registry.yarnpkg.com/vue-tsc/-/vue-tsc-0.38.9.tgz#9e945937667f704325328db8af1cc6bc7314b85e"
-  integrity sha512-Yoy5phgvGqyF98Fb4mYqboR4Q149jrdcGv5kSmufXJUq++RZJ2iMVG0g6zl+v3t4ORVWkQmRpsV4x2szufZ0LQ==
-  dependencies:
-    "@volar/vue-typescript" "0.38.9"
-
-vue-types@^3.0.0:
-  version "3.0.2"
-  resolved "https://registry.yarnpkg.com/vue-types/-/vue-types-3.0.2.tgz#ec16e05d412c038262fc1efa4ceb9647e7fb601d"
-  integrity sha512-IwUC0Aq2zwaXqy74h4WCvFCUtoV0iSWr0snWnE9TnU18S66GAQyqQbRf2qfJtUuiFsBf6qp0MEwdonlwznlcrw==
-  dependencies:
-    is-plain-object "3.0.1"
-
-vue3-ace-editor@^2.2.2:
-  version "2.2.2"
-  resolved "https://registry.yarnpkg.com/vue3-ace-editor/-/vue3-ace-editor-2.2.2.tgz#7fd694df2f556e8859edd2322703e039461c9ecc"
-  integrity sha512-fZ6OWosbU+odLrtrcGC/536QjCigujYJB0Hf6/tBp+ef/ohTadwQAqyBlVzOmvrmzZyubphpV9zkaZcx5Fuivw==
-  dependencies:
-    ace-builds "^1.4.13"
-    resize-observer-polyfill "^1.5.1"
-    vue "^3.2.26"
-
-vue3-apexcharts@^1.4.1:
-  version "1.4.1"
-  resolved "https://registry.yarnpkg.com/vue3-apexcharts/-/vue3-apexcharts-1.4.1.tgz#ea561308430a1c5213b7f17c44ba3c845f6c490d"
-  integrity sha512-96qP8JDqB9vwU7bkG5nVU+E0UGQn7yYQVqUUCLQMYWDuQyu2vE77H/UFZ1yI+hwzlSTBKT9BqnNG8JsFegB3eg==
-
-vue3-gettext@^2.3.0:
-  version "2.3.0"
-  resolved "https://registry.yarnpkg.com/vue3-gettext/-/vue3-gettext-2.3.0.tgz#5825949e3978aa576e035128de46c97e59b65a5b"
-  integrity sha512-06zNnOGsGxdX8BT675eOipxKX6lwfS1D3X2nJBBE26GpMLHhqUIuKxU8gkXwOFnXDnaoqphitWnV9R/qV2Sl/Q==
-  dependencies:
-    chalk "^4.1.2"
-    command-line-args "^5.2.1"
-    cosmiconfig "^7.0.1"
-    gettext-extractor "^3.5.4"
-    glob "^7.2.0"
-    parse5 "^6.0.1"
-    parse5-htmlparser2-tree-adapter "^6.0.1"
-    pofile "^1.1.3"
-    tslib "^2.3.1"
-
-vue@^3.2.26, vue@^3.2.37:
-  version "3.2.37"
-  resolved "https://registry.yarnpkg.com/vue/-/vue-3.2.37.tgz#da220ccb618d78579d25b06c7c21498ca4e5452e"
-  integrity sha512-bOKEZxrm8Eh+fveCqS1/NkG/n6aMidsI6hahas7pa0w/l7jkbssJVsRhVDs07IdDq7h9KHswZOgItnwJAgtVtQ==
-  dependencies:
-    "@vue/compiler-dom" "3.2.37"
-    "@vue/compiler-sfc" "3.2.37"
-    "@vue/runtime-dom" "3.2.37"
-    "@vue/server-renderer" "3.2.37"
-    "@vue/shared" "3.2.37"
-
-vuex@^4.0.2:
-  version "4.0.2"
-  resolved "https://registry.yarnpkg.com/vuex/-/vuex-4.0.2.tgz#f896dbd5bf2a0e963f00c67e9b610de749ccacc9"
-  integrity sha512-M6r8uxELjZIK8kTKDGgZTYX/ahzblnzC4isU1tpmEuOIIKmV+TRdc+H4s8ds2NuZ7wpUTdGRzJRtoj+lI+pc0Q==
-  dependencies:
-    "@vue/devtools-api" "^6.0.0-beta.11"
-
-warning@^4.0.0:
-  version "4.0.3"
-  resolved "https://registry.yarnpkg.com/warning/-/warning-4.0.3.tgz#16e9e077eb8a86d6af7d64aa1e05fd85b4678ca3"
-  integrity sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w==
-  dependencies:
-    loose-envify "^1.0.0"
-
-webpack-sources@^3.2.3:
-  version "3.2.3"
-  resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-3.2.3.tgz#2d4daab8451fd4b240cc27055ff6a0c2ccea0cde"
-  integrity sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==
-
-webpack-virtual-modules@^0.4.4:
-  version "0.4.4"
-  resolved "https://registry.yarnpkg.com/webpack-virtual-modules/-/webpack-virtual-modules-0.4.4.tgz#a19fcf371923c59c4712d63d7d194b1e4d8262cc"
-  integrity sha512-h9atBP/bsZohWpHnr+2sic8Iecb60GxftXsWNLLLSqewgIsGzByd2gcIID4nXcG+3tNe4GQG3dLcff3kXupdRA==
-
-wrappy@1:
-  version "1.0.2"
-  resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"
-  integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==
-
-xterm-addon-attach@^0.6.0:
-  version "0.6.0"
-  resolved "https://registry.yarnpkg.com/xterm-addon-attach/-/xterm-addon-attach-0.6.0.tgz#220c23addd62ab88c9914e2d4c06f7407e44680e"
-  integrity sha512-Mo8r3HTjI/EZfczVCwRU6jh438B4WLXxdFO86OB7bx0jGhwh2GdF4ifx/rP+OB+Cb2vmLhhVIZ00/7x3YSP3dg==
-
-xterm-addon-fit@^0.5.0:
-  version "0.5.0"
-  resolved "https://registry.yarnpkg.com/xterm-addon-fit/-/xterm-addon-fit-0.5.0.tgz#2d51b983b786a97dcd6cde805e700c7f913bc596"
-  integrity sha512-DsS9fqhXHacEmsPxBJZvfj2la30Iz9xk+UKjhQgnYNkrUIN5CYLbw7WEfz117c7+S86S/tpHPfvNxJsF5/G8wQ==
-
-xterm@^4.19.0:
-  version "4.19.0"
-  resolved "https://registry.yarnpkg.com/xterm/-/xterm-4.19.0.tgz#c0f9d09cd61de1d658f43ca75f992197add9ef6d"
-  integrity sha512-c3Cp4eOVsYY5Q839dR5IejghRPpxciGmLWWaP9g+ppfMeBChMeLa1DCA+pmX/jyDZ+zxFOmlJL/82qVdayVoGQ==
-
-yaml@^1.10.0, yaml@^1.10.2:
-  version "1.10.2"
-  resolved "https://registry.yarnpkg.com/yaml/-/yaml-1.10.2.tgz#2301c5ffbf12b467de8da2333a459e29e7920e4b"
-  integrity sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==

+ 12 - 10
frontend/.gitignore

@@ -1,20 +1,22 @@
-.DS_Store
-node_modules
-
-
-# local env files
-.env.local
-.env.*.local
-
-# Log files
+# Logs
+logs
+*.log
 npm-debug.log*
 yarn-debug.log*
 yarn-error.log*
 pnpm-debug.log*
+lerna-debug.log*
+
+node_modules
+dist
+dist-ssr
+*.local
 
 # Editor directories and files
+.vscode/*
+!.vscode/extensions.json
 .idea
-.vscode
+.DS_Store
 *.suo
 *.ntvs*
 *.njsproj

+ 0 - 0
frontend-next/.vscode/extensions.json → frontend/.vscode/extensions.json


+ 0 - 65
frontend/Makefile

@@ -1,65 +0,0 @@
-# On OSX the PATH variable isn't exported unless "SHELL" is also set, see: http://stackoverflow.com/a/25506676
-SHELL = /bin/bash
-NODE_BINDIR = ./node_modules/.bin
-export PATH := $(NODE_BINDIR):$(PATH)
-LOGNAME ?= $(shell logname)
-
-# adding the name of the user's login name to the template file, so that
-# on a multi-user system several users can run this without interference
-ifeq ($(OS),Windows_NT)
-TEMPLATE_POT ?=  ./template-$(LOGNAME).pot
-else
-TEMPLATE_POT ?= /tmp/template-$(LOGNAME).pot
-endif
-
-# Where to find input files (it can be multiple paths).
-INPUT_FILES = ./src
-
-# Where to write the files generated by this makefile.
-OUTPUT_DIR = ./src
-
-# Available locales for the app.
-LOCALES = zh_CN zh_TW en
-
-# Name of the generated .po files for each available locale.
-LOCALE_FILES ?= $(patsubst %,$(OUTPUT_DIR)/locale/%/LC_MESSAGES/app.po,$(LOCALES))
-
-GETTEXT_SOURCES ?= $(shell find $(INPUT_FILES) -name '*.jade' -o -name '*.html' -o -name '*.js' -o -name '*.vue' 2> /dev/null)
-
-# Makefile Targets
-.PHONY: clean makemessages translations all
-
-all:
-	@echo choose a target from: clean makemessages translations
-
-clean:
-	rm -f $(TEMPLATE_POT) $(OUTPUT_DIR)/translations.json
-
-makemessages: $(TEMPLATE_POT)
-
-translations: ./$(OUTPUT_DIR)/translations.json
-# Create a main .pot template, then generate .po files for each available language.
-# Thanx to Systematic: https://github.com/Polyconseil/systematic/blob/866d5a/mk/main.mk#L167-L183
-$(TEMPLATE_POT): $(GETTEXT_SOURCES)
-# `dir` is a Makefile built-in expansion function which extracts the directory-part of `$@`.
-# `$@` is a Makefile automatic variable: the file name of the target of the rule.
-# => `mkdir -p /tmp/`
-	mkdir -p $(dir $@)
-# Extract gettext strings from templates files and create a POT dictionary template.
-	gettext-extract --quiet --attribute v-translate --output $@ $(GETTEXT_SOURCES)
-# Generate .po files for each available language.
-	@for lang in $(LOCALES); do \
-		export PO_FILE=$(OUTPUT_DIR)/locale/$$lang/LC_MESSAGES/app.po; \
-		mkdir -p $$(dirname $$PO_FILE); \
-		if [ -f $$PO_FILE ]; then  \
-			echo "msgmerge --update $$PO_FILE $@"; \
-			msgmerge --lang=$$lang --update $$PO_FILE $@ || break ;\
-		else \
-			msginit --no-translator --locale=$$lang --input=$@ --output-file=$$PO_FILE || break ; \
-			msgattrib --no-wrap --no-obsolete -o $$PO_FILE $$PO_FILE || break; \
-		fi; \
-	done;
-
-$(OUTPUT_DIR)/translations.json: $(LOCALE_FILES)
-	mkdir -p $(OUTPUT_DIR)
-	gettext-compile --output $@ $(LOCALE_FILES)

+ 16 - 22
frontend/README.md

@@ -1,29 +1,23 @@
-# nginx-ui-frontend
+# Vue 3 + TypeScript + Vite
 
-## Project setup
+This template should help get you started developing with Vue 3 and TypeScript in Vite. The template uses Vue
+3 `<script setup>` SFCs, check out
+the [script setup docs](https://v3.vuejs.org/api/sfc-script-setup.html#sfc-script-setup) to learn more.
 
-```
-yarn install
-```
+## Recommended IDE Setup
 
-### Compiles and hot-reloads for development
+- [VS Code](https://code.visualstudio.com/) + [Volar](https://marketplace.visualstudio.com/items?itemName=Vue.volar)
 
-```
-yarn serve
-```
+## Type Support For `.vue` Imports in TS
 
-### Compiles and minifies for production
+Since TypeScript cannot handle type information for `.vue` imports, they are shimmed to be a generic Vue component type
+by default. In most cases this is fine if you don't really care about component prop types outside of templates.
+However, if you wish to get actual prop types in `.vue` imports (for example to get props validation when using
+manual `h(...)` calls), you can enable Volar's Take Over mode by following these steps:
 
-```
-yarn build
-```
+1. Run `Extensions: Show Built-in Extensions` from VS Code's command palette, look
+   for `TypeScript and JavaScript Language Features`, then right click and select `Disable (Workspace)`. By default,
+   Take Over mode will enable itself if the default TypeScript extension is disabled.
+2. Reload the VS Code window by running `Developer: Reload Window` from the command palette.
 
-### Lints and fixes files
-
-```
-yarn lint
-```
-
-### Customize configuration
-
-See [Configuration Reference](https://cli.vuejs.org/config/).
+You can learn more about Take Over mode [here](https://github.com/johnsoncodehk/volar/discussions/471).

+ 0 - 9
frontend/alias.config.js

@@ -1,9 +0,0 @@
-const resolve = dir => require('path').join(__dirname, dir)
-
-module.exports = {
-    resolve: {
-        alias: {
-            '@': resolve('src')
-        }
-    }
-}

+ 0 - 10
frontend/babel.config.js

@@ -1,10 +0,0 @@
-module.exports = {
-    presets: [
-        '@vue/cli-plugin-babel/preset'
-    ],
-    'plugins': [
-        '@babel/plugin-proposal-optional-chaining',
-        '@babel/plugin-proposal-nullish-coalescing-operator',
-        ['import', {'libraryName': 'ant-design-vue', 'libraryDirectory': 'es', 'style': true}, 'syntax-dynamic-import']
-    ],
-}

+ 0 - 12
frontend-next/components.d.ts → frontend/components.d.ts

@@ -57,20 +57,8 @@ declare module '@vue/runtime-core' {
     RouterLink: typeof import('vue-router')['RouterLink']
     RouterView: typeof import('vue-router')['RouterView']
     SetLanguage: typeof import('./src/components/SetLanguage/SetLanguage.vue')['default']
-    StdCheckGroup: typeof import('./src/components/StdDataEntry/StdCheckGroup.vue')['default']
-    StdCheckTag: typeof import('./src/components/StdDataEntry/StdCheckTag.vue')['default']
     StdCurd: typeof import('./src/components/StdDataDisplay/StdCurd.vue')['default']
-    StdDataEntry: typeof import('./src/components/StdDataEntry/StdDataEntry.vue')['default']
-    StdDatePicker: typeof import('./src/components/StdDataEntry/StdDatePicker.vue')['default']
-    StdMultiCheckTag: typeof import('./src/components/StdDataEntry/StdMultiCheckTag.vue')['default']
-    StdMultiFilesUpload: typeof import('./src/components/StdDataEntry/StdMultiFilesUpload.vue')['default']
     StdPagination: typeof import('./src/components/StdDataDisplay/StdPagination.vue')['default']
-    StdRadioGroup: typeof import('./src/components/StdDataEntry/StdRadioGroup.vue')['default']
-    StdSelectOption: typeof import('./src/components/StdDataEntry/StdSelectOption.vue')['default']
-    StdSelector: typeof import('./src/components/StdDataEntry/StdSelector.vue')['default']
-    StdSingleFileUpload: typeof import('./src/components/StdDataEntry/StdSingleFileUpload.vue')['default']
     StdTable: typeof import('./src/components/StdDataDisplay/StdTable.vue')['default']
-    StdTransfer: typeof import('./src/components/StdDataEntry/StdTransfer.vue')['default']
-    StdUpload: typeof import('./src/components/StdDataEntry/StdUpload.vue')['default']
   }
 }

+ 0 - 19
frontend/conversion.log

@@ -1,19 +0,0 @@
---------------------------------------------------
-conversion items successful conversion: 
-
-╔════════╤═════════════════════════════════════╤══════════════════╗
-║ Number │ Conversion item                     │ Conversion count ║
-╟────────┼─────────────────────────────────────┼──────────────────╢
-║  B01   │ add package.json                    │        1         ║
-║  B02   │ add index.html                      │        1         ║
-║  B03   │ add vite.config.js                  │        1         ║
-║  B04   │ required plugins                    │        1         ║
-║  B11   │ html-webpack-plugin is supported    │        1         ║
-║  V01   │ base public path                    │        1         ║
-║  V02   │ css options                         │        1         ║
-║  V03   │ server options                      │        2         ║
-║  V05   │ resolve.alias options               │        1         ║
-║  V06   │ client-side env variables           │        1         ║
-║  V08   │ transform functional webpack config │        3         ║
-╚════════╧═════════════════════════════════════╧══════════════════╝
-

+ 0 - 8
frontend/frontend.go

@@ -1,8 +0,0 @@
-package frontend
-
-import (
-	"embed"
-)
-
-//go:embed dist
-var DistFS embed.FS

+ 0 - 0
frontend-next/gettext.config.js → frontend/gettext.config.js


+ 7 - 13
frontend/index.html

@@ -1,24 +1,18 @@
 <!DOCTYPE html>
-<html lang="">
+<html lang="en">
 <head>
-    <meta charset="utf-8">
-    <meta content="IE=edge" http-equiv="X-UA-Compatible">
-    <meta content="width=device-width,initial-scale=1.0,user-scalable=0" name="viewport">
+    <meta charset="UTF-8"/>
     <link href="/favicon.ico" rel="icon">
-    <title>Nginx UI</title>
+    <meta name="viewport" content="width=device-width, initial-scale=1.0"/>
     <style type="text/css">
-        body {
-            width: 100% !important;
+        #app {
+            height: 100%;
         }
     </style>
+    <title><%- title %></title>
 </head>
 <body>
-<noscript>
-    <strong>We're sorry but Nginx UI doesn't work properly without JavaScript enabled.
-        Please enable it to continue.</strong>
-</noscript>
 <div id="app"></div>
-<!-- built files will be auto injected -->
-<script type="module" src="/src/main.js"></script>
+<script type="module" src="/src/main.ts"></script>
 </body>
 </html>

+ 42 - 86
frontend/package.json

@@ -1,91 +1,47 @@
 {
-  "name": "nginx-ui-frontend",
-  "version": "1.5.0",
-  "private": true,
-  "scripts": {
-    "serve": "vue-cli-service serve --port 8021",
-    "build": "vue-cli-service build --dest dist --modern",
-    "lint": "vue-cli-service lint",
-    "serve-vite": "vite",
-    "build-vite": "vite build",
-    "preview-vite": "vite preview"
-  },
-  "dependencies": {
-    "@vitejs/plugin-react": "^2.0.0",
-    "ant-design-vue": "^1.7.3",
-    "apexcharts": "^3.33.1",
-    "axios": "^0.21.2",
-    "brace": "https://github.com/nightwing/brace",
-    "chart.js": "^2.9.4",
-    "core-js": "^3.9.0",
-    "less": "^3.11.1",
-    "less-loader": "^5.0.0",
-    "lodash": "^4.17.21",
-    "moment": "^2.24.0",
-    "node-sass": "^6.0.1",
-    "nprogress": "^0.2.0",
-    "reconnecting-websocket": "^4.4.0",
-    "vite-plugin-antdv1-momentjs-resolver": "^1.1.1",
-    "vue": "^2.7.8",
-    "vue-apexcharts": "^1.6.2",
-    "vue-chartjs": "^3.5.1",
-    "vue-cli-plugin-generate-build-id": "^0.2.0",
-    "vue-codemirror": "^4.0.6",
-    "vue-cropper": "^0.5.8",
-    "vue-gettext": "^2.1.12",
-    "vue-itextarea": "^1.0.9",
-    "vue-router": "^3.5.1",
-    "vue-template-babel-compiler": "^1.1.3",
-    "vue-template-compiler": "^2.7.8",
-    "vue2-ace-editor": "^0.0.15",
-    "vuex": "^3.6.2",
-    "vuex-persist": "^3.1.3",
-    "xterm": "^4.19.0",
-    "xterm-addon-attach": "^0.6.0",
-    "xterm-addon-fit": "^0.5.0"
-  },
-  "devDependencies": {
-    "@originjs/vite-plugin-commonjs": "^1.0.1",
-    "@vue/cli-plugin-babel": "~4.5.15",
-    "@vue/cli-plugin-eslint": "~4.5.15",
-    "@vue/cli-plugin-router": "~4.5.15",
-    "@vue/cli-plugin-vuex": "~4.5.15",
-    "@vue/cli-service": "~4.5.0",
-    "babel-eslint": "^10.1.0",
-    "babel-plugin-import": "^1.13.3",
-    "easygettext": "^2.17.0",
-    "eslint": "^6.7.2",
-    "eslint-plugin-vue": "^6.2.2",
-    "vite": "^3.0.3",
-    "vite-plugin-env-compatible": "^1.1.1",
-    "vite-plugin-html": "^3.2.0",
-    "vite-plugin-importer": "^0.2.5",
-    "vite-plugin-style-import": "^1.4.1",
-    "vite-plugin-vue2": "^1.9.0",
-    "yarn-audit-fix": "^9.3.2"
-  },
-  "eslintConfig": {
-    "root": true,
-    "env": {
-      "node": true
+    "name": "nginx-ui-frontend-next",
+    "private": true,
+    "version": "1.5.0",
+    "type": "commonjs",
+    "scripts": {
+        "dev": "vite",
+        "build": "vite build",
+        "preview": "vite preview",
+        "gettext:extract": "vue-gettext-extract",
+        "gettext:compile": "vue-gettext-compile"
     },
-    "extends": [
-      "plugin:vue/essential",
-      "eslint:recommended"
-    ],
-    "parserOptions": {
-      "parser": "babel-eslint"
+    "dependencies": {
+        "@ant-design/icons-vue": "^6.1.0",
+        "ant-design-vue": "^3.2.10",
+        "apexcharts": "^3.35.4",
+        "axios": "^0.27.2",
+        "dayjs": "^1.11.4",
+        "lodash": "^4.17.21",
+        "pinia": "^2.0.17",
+        "pinia-plugin-persistedstate": "^1.6.3",
+        "reconnecting-websocket": "^4.4.0",
+        "vite-plugin-build-id": "^0.1.1",
+        "vue": "^3.2.37",
+        "vue-chartjs": "^4.1.1",
+        "vue-router": "4",
+        "vue3-ace-editor": "^2.2.2",
+        "vue3-apexcharts": "^1.4.1",
+        "vue3-gettext": "^2.3.0",
+        "vuex": "^4.0.2",
+        "xterm": "^4.19.0",
+        "xterm-addon-attach": "^0.6.0",
+        "xterm-addon-fit": "^0.5.0"
     },
-    "rules": {}
-  },
-  "postcss": {
-    "plugins": {
-      "autoprefixer": {}
+    "devDependencies": {
+        "@types/lodash": "^4.14.182",
+        "@vitejs/plugin-vue": "^3.0.0",
+        "@vitejs/plugin-vue-jsx": "^2.0.0",
+        "@zougt/vite-plugin-theme-preprocessor": "^1.4.5",
+        "less": "^4.1.3",
+        "typescript": "^4.6.4",
+        "unplugin-vue-components": "^0.21.2",
+        "vite": "^3.0.0",
+        "vite-plugin-html": "^3.2.0",
+        "vue-tsc": "^0.38.4"
     }
-  },
-  "browserslist": [
-    "> 1%",
-    "last 2 versions",
-    "not dead"
-  ]
 }

+ 0 - 23
frontend/public/index.html

@@ -1,23 +0,0 @@
-<!DOCTYPE html>
-<html lang="">
-<head>
-    <meta charset="utf-8">
-    <meta content="IE=edge" http-equiv="X-UA-Compatible">
-    <meta content="width=device-width,initial-scale=1.0,user-scalable=0" name="viewport">
-    <link href="<%= BASE_URL %>favicon.ico" rel="icon">
-    <title><%= htmlWebpackPlugin.options.title %></title>
-    <style type="text/css">
-        body {
-            width: 100% !important;
-        }
-    </style>
-</head>
-<body>
-<noscript>
-    <strong>We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work properly without JavaScript enabled.
-        Please enable it to continue.</strong>
-</noscript>
-<div id="app"></div>
-<!-- built files will be auto injected -->
-</body>
-</html>

+ 0 - 0
frontend-next/public/vite.svg → frontend/public/vite.svg


+ 28 - 7
frontend/src/App.vue

@@ -1,12 +1,33 @@
+<script setup lang="ts">
+// This starter template is using Vue 3 <script setup> SFCs
+// Check out https://vuejs.org/api/sfc-script-setup.html#script-setup
+import {useSettingsStore} from '@/pinia'
+import {dark_mode} from '@/lib/theme'
+
+let media = window.matchMedia('(prefers-color-scheme: dark)')
+const callback = (media: { matches: any; }) => {
+    const settings = useSettingsStore()
+    if (media.matches) {
+        dark_mode(true)
+        settings.set_theme('dark')
+    } else {
+        dark_mode(false)
+        settings.set_theme('default')
+    }
+}
+callback(media)
+if (typeof media.addEventListener === 'function') {
+    media.addEventListener('change', callback)
+} else if (typeof media.addListener === 'function') {
+    media.addListener(callback)
+}
+
+</script>
+
 <template>
-    <div id="app">
-        <router-view/>
-    </div>
+    <router-view/>
 </template>
 
-<style lang="less">
-#app {
-    height: 100%;
-}
+<style lang="less" scoped>
 
 </style>

+ 0 - 9
frontend/src/api/analytic.js

@@ -1,9 +0,0 @@
-import http from '@/lib/http'
-
-const analytic = {
-    init() {
-        return http.get('/analytic/init')
-    }
-}
-
-export default analytic

+ 0 - 0
frontend-next/src/api/analytic.ts → frontend/src/api/analytic.ts


+ 0 - 20
frontend/src/api/auth.js

@@ -1,20 +0,0 @@
-import http from '@/lib/http'
-import store from '@/lib/store'
-
-const auth = {
-    async login(name, password) {
-        return http.post('/login', {
-            name: name,
-            password: password
-        }).then(r => {
-            store.dispatch('login', r)
-        })
-    },
-    logout() {
-        return http.delete('/logout').then(async () => {
-            await store.dispatch('logout')
-        })
-    }
-}
-
-export default auth

+ 1 - 1
frontend-next/src/api/auth.ts → frontend/src/api/auth.ts

@@ -1,5 +1,5 @@
 import http from '@/lib/http'
-import {useUserStore} from '@/pinia/user'
+import {useUserStore} from '@/pinia'
 
 const user = useUserStore()
 const {login, logout} = user

+ 0 - 23
frontend/src/api/config.js

@@ -1,23 +0,0 @@
-import http from '@/lib/http'
-
-const base_url = '/config'
-
-const config = {
-    get_list(params) {
-        return http.get(base_url + 's', {params: params})
-    },
-
-    get(id) {
-        return http.get(base_url + '/' + id)
-    },
-
-    save(id = null, data) {
-        return http.post(base_url + (id ? '/' + id : ''), data)
-    },
-
-    destroy(id) {
-        return http.delete(base_url + '/' + id)
-    }
-}
-
-export default config

+ 0 - 0
frontend-next/src/api/config.ts → frontend/src/api/config.ts


+ 0 - 0
frontend-next/src/api/curd.ts → frontend/src/api/curd.ts


+ 0 - 47
frontend/src/api/domain.js

@@ -1,47 +0,0 @@
-import http from '@/lib/http'
-
-const base_url = '/domain'
-
-const domain = {
-    get_list(params) {
-        return http.get(base_url + 's', {params: params})
-    },
-
-    get(id) {
-        return http.get(base_url + '/' + id)
-    },
-
-    save(id = null, data) {
-        return http.post(base_url + (id ? '/' + id : ''), data)
-    },
-
-    destroy(id) {
-        return http.delete(base_url + '/' + id)
-    },
-
-    enable(name) {
-        return http.post(base_url + '/' + name + '/enable')
-    },
-
-    disable(name) {
-        return http.post(base_url + '/' + name + '/disable')
-    },
-
-    get_template() {
-        return http.get('template')
-    },
-
-    cert_info(domain) {
-        return http.get('cert/' + domain + '/info')
-    },
-
-    add_auto_cert(domain) {
-        return http.post('cert/' + domain)
-    },
-
-    remove_auto_cert(domain) {
-        return http.delete('cert/' + domain)
-    }
-}
-
-export default domain

+ 0 - 0
frontend-next/src/api/domain.ts → frontend/src/api/domain.ts


+ 0 - 19
frontend/src/api/index.js

@@ -1,19 +0,0 @@
-import domain from './domain'
-import config from './config'
-import auth from './auth'
-import user from './user'
-import install from './install'
-import analytic from './analytic'
-import settings from './settings'
-import ngx from './ngx'
-
-export default {
-    domain,
-    config,
-    auth,
-    user,
-    install,
-    analytic,
-    settings,
-    ngx
-}

+ 0 - 12
frontend/src/api/install.js

@@ -1,12 +0,0 @@
-import http from '@/lib/http'
-
-const install = {
-    get_lock() {
-        return http.get('/install')
-    },
-    install_nginx_ui(data) {
-        return http.post('/install', data)
-    }
-}
-
-export default install

+ 0 - 13
frontend/src/api/ngx.js

@@ -1,13 +0,0 @@
-import http from '@/lib/http'
-
-const ngx = {
-    build_config(ngxConfig) {
-        return http.post('/ngx/build_config', ngxConfig)
-    },
-
-    tokenize_config(content) {
-        return http.post('/ngx/tokenize_config', {content})
-    }
-}
-
-export default ngx

+ 0 - 0
frontend-next/src/api/ngx.ts → frontend/src/api/ngx.ts


+ 0 - 9
frontend/src/api/settings.js

@@ -1,9 +0,0 @@
-import http from '@/lib/http'
-
-const settings = {
-    get() {
-        return http.get('/settings')
-    }
-}
-
-export default settings

+ 0 - 23
frontend/src/api/user.js

@@ -1,23 +0,0 @@
-import http from '@/lib/http'
-
-const base_url = '/user'
-
-const user = {
-    get_list(params) {
-        return http.get(base_url + 's', {params: params})
-    },
-
-    get(id) {
-        return http.get(base_url + '/' + id)
-    },
-
-    save(id = null, data) {
-        return http.post(base_url + (id ? '/' + id : ''), data)
-    },
-
-    destroy(id) {
-        return http.delete(base_url + '/' + id)
-    }
-}
-
-export default user

+ 0 - 0
frontend-next/src/api/user.ts → frontend/src/api/user.ts


+ 0 - 74
frontend/src/assets/css/dark.less

@@ -1,74 +0,0 @@
-@media (prefers-color-scheme: dark) {
-    @import '~ant-design-vue/dist/antd.less';
-    @black_bg: #1e1f20;
-    @background-color-base: @black_bg;
-    @background-color-light: @black_bg;
-    @btn-default-bg: @black_bg;
-    @black_content: #28292c;
-    @text-color: #fff;
-    @text-color-secondary: #bdbdbd;
-    @heading-color: #fff;
-
-    @item-hover-bg: @black_bg;
-
-    @body-background: @black_bg;
-    @component-background: @black_content;
-    @layout-body-background: @black_bg;
-    @layout-header-background: @black_bg;
-    @layout-sider-background: @black_content;
-    @ant-layout-sider-light: @black_content;
-    @menu-bg: @black_content;
-    @layout-trigger-background: @black_content;
-    @layout-sider-background-light: @black_content;
-    @layout-trigger-background-light: @black_content;
-
-    @item-active-bg: #161717;
-
-    @link-color: #bcbcbc;
-    @table-row-hover-bg: @black_bg;
-    @table-selected-row-bg: @black_bg;
-
-    @input-bg: @black_bg;
-    @disabled-bg: #363636;
-    @btn-default-bg: @black_bg;
-    @table-header-bg: @black_bg;
-    @border-color-base: #666666;
-    @disabled-color: #bcbcbc;
-    @radio-button-bg: @black_bg;
-    @checkbox-check-color: @black_bg;
-    @popover-bg: @black_bg;
-
-    @background-color-light: fade(@white, 4%); // background of header and selected item
-    // Descriptions
-    // ---
-    @descriptions-bg: @background-color-light;
-
-    // Alert
-    // ---
-    @alert-message-color: @black;
-
-    .ant-select-dropdown-menu-item:hover {
-        background: @black_bg;
-    }
-
-    .ant-layout-sider {
-        background-color: @black_content;
-    }
-
-    .ant-checkbox-indeterminate {
-        .ant-checkbox-inner {
-            background-color: transparent !important;
-        }
-    }
-
-    .ant-transfer-list-content-item:not(.ant-transfer-list-content-item-disabled):hover,
-    .ant-transfer-list-content-item-highlight-enter, .ant-transfer-list-content-item-highlight-enter-active {
-        background-color: @black_bg !important;
-    }
-
-    .ant-card {
-        // box-shadow: 0 0 30px rgb(0, 0, 0, 10%) !important;
-        box-shadow: none !important;
-    }
-
-}

+ 0 - 49
frontend/src/assets/css/manage.less

@@ -1,49 +0,0 @@
-/* Copyright 2019 - 2020 0xJacky */
-
-@dark: ~"(prefers-color-scheme: dark)";
-
-p {
-    padding: 0 0 10px 0;
-}
-
-.ant-layout-sider {
-    background-color: #ffffff;
-    @media @dark {
-        background-color: #28292c;
-    }
-    box-shadow: 2px 0 6px rgba(0, 21, 41, 0.01);
-}
-
-@media @dark {
-    .ant-checkbox-indeterminate {
-        .ant-checkbox-inner {
-            background-color: transparent !important;
-        }
-    }
-}
-
-.ant-layout-header {
-    padding: 0;
-}
-
-.ant-table-small {
-    font-size: 13px;
-}
-
-.ant-card-bordered {
-    border: unset;
-}
-
-.header-notice-wrapper .ant-tabs-content {
-    max-height: 250px;
-}
-
-.header-notice-wrapper .ant-tabs-tabpane-active {
-    overflow-y: scroll;
-}
-
-.ant-layout-footer {
-    @media (max-width: 320px) {
-        padding: 10px;
-    }
-}

+ 0 - 181
frontend/src/assets/css/style.less

@@ -1,181 +0,0 @@
-/* 基准 */
-* {
-    -webkit-tap-highlight-color: transparent
-}
-
-body {
-    margin: 0;
-    padding: 0;
-    //cursor: default;
-    //-webkit-user-select: none;
-    -webkit-text-size-adjust: none;
-    -webkit-font-smoothing: antialiased;
-    font-family: "Myriad Pro", "PingFang SC", "Helvetica Neue", Helvetica, Arial, sans-serif
-}
-
-::selection {
-    background: #5aaafc;
-    //color: unset;
-}
-
-::-moz-selection {
-    background: #5aaafc;
-    //color: unset;
-}
-
-a {
-    color: #444;
-    @media (prefers-color-scheme: dark) {
-        color: #f5f5f5;
-    }
-    text-decoration: none;
-    -webkit-transition: all .3s ease;
-    -moz-transition: all .3s ease;
-    -o-transition: all .3s ease;
-    transition: all .3s ease;
-
-    &:hover {
-        color: #19B5FE;
-        text-decoration: none;
-    }
-
-    &:focus {
-        outline: 0;
-        text-decoration: none;
-    }
-}
-
-b {
-    font-weight: normal
-}
-
-i {
-    font-style: normal
-}
-
-p {
-    margin: 0
-}
-
-h1, h2, h4 {
-    margin: 0;
-    font-weight: normal;
-}
-
-h3 {
-    font-size: 17px;
-    font-weight: 400
-}
-
-h4 {
-    font-size: 15px;
-}
-
-ul {
-    margin: 0;
-    padding: 0;
-    list-style: none
-}
-
-img {
-    border: 0
-}
-
-code {
-    font-family: Menlo, monospace;
-    font-size: 90%
-}
-
-p > code {
-    padding: 0.2em 0.4em;
-    background: #e1e9ed
-}
-
-pre {
-    text-align: left;
-    overflow-x: scroll;
-    background-color: #f5f5f5;
-    padding: 10pt 15pt;
-    font-size: 13px;
-    border-radius: 4px;
-    color: #333;
-    border: 1px solid rgba(0, 0, 0, 0.15)
-}
-
-button {
-    box-shadow: unset !important;
-}
-
-.clear {
-    clear: both
-}
-
-.center {
-    display: flex;
-    justify-content: center;
-}
-
-.limit-max {
-    max-width: 1000px;
-}
-
-.ant-notification {
-    z-index: 2100
-}
-
-.ant-comment-actions {
-    margin-top: unset;
-}
-
-.ant-input:hover {
-
-}
-
-#nprogress .bar {
-    z-index: 2030 !important;
-    background: #1890ff !important;
-}
-
-.grecaptcha-badge {
-    visibility: hidden;
-}
-
-.std-border-radius {
-    border-radius: 25px;
-}
-
-.ant-card {
-    box-shadow: 0 0 30px rgba(200, 200, 200, 0.25);
-}
-
-.ant-list-item-action {
-    margin-left: 0 !important;
-}
-
-/*@media (max-width: 900px) {
-
-    .ant-steps-navigation > .ant-steps-item::after {
-        position: relative;
-        top: -2px;
-        left: 50%;
-        display: block;
-        width: 8px;
-        height: 8px;
-        margin-bottom: 8px;
-        text-align: center;
-        transform: rotate(135deg);
-    }
-
-    .ant-steps-navigation > .ant-steps-item.ant-steps-item-active::before {
-        top: 0;
-        right: 0;
-        left: unset;
-        display: block;
-        width: 3px;
-        height: calc(100% - 24px);
-    }
-
-    .ant-steps-horizontal.ant-steps-label-horizontal .ant-steps-item, .ant-steps-horizontal.ant-steps-label-horizontal {
-        display: block;
-    }
-}*/

+ 33 - 33
frontend/src/components/Breadcrumb/Breadcrumb.vue

@@ -1,46 +1,46 @@
+<script setup lang="ts">
+import {computed, ref} from 'vue'
+import {useRoute} from 'vue-router'
+
+interface bread {
+    name: any
+    path: string
+}
+
+const name = ref()
+const route = useRoute()
+
+const breadList = computed(() => {
+    let _breadList: bread[] = []
+
+    name.value = route.name
+
+    route.matched.forEach(item => {
+        //item.name !== 'index' && this.breadList.push(item)
+        _breadList.push({
+            name: item.name,
+            path: item.path
+        })
+    })
+
+    return _breadList
+})
+
+
+</script>
+
 <template>
     <a-breadcrumb class="breadcrumb">
         <a-breadcrumb-item v-for="(item, index) in breadList" :key="item.name">
             <router-link
                 v-if="item.name !== name && index !== 1"
                 :to="{ path: item.path === '' ? '/' : item.path }"
-            >{{ item.name }}
+            >{{ item.name() }}
             </router-link>
-            <span v-else>{{ item.name }}</span>
+            <span v-else>{{ item.name() }}</span>
         </a-breadcrumb-item>
     </a-breadcrumb>
 </template>
 
-<script>
-export default {
-    data() {
-        return {
-            name: '',
-            breadList: []
-        }
-    },
-    created() {
-        this.getBreadcrumb()
-    },
-    methods: {
-        getBreadcrumb() {
-            this.breadList = []
-            //this.breadList.push({name: 'index', path: '/dashboard/', meta: {title: '首页'}})
-
-            this.name = this.$route.name
-            this.$route.matched.forEach(item => {
-                //item.name !== 'index' && this.breadList.push(item)
-                this.breadList.push(item)
-            })
-        }
-    },
-    watch: {
-        $route() {
-            this.getBreadcrumb()
-        }
-    }
-}
-</script>
-
 <style scoped>
 </style>

+ 1 - 1
frontend-next/src/components/Chart/AreaChart.vue → frontend/src/components/Chart/AreaChart.vue

@@ -1,7 +1,7 @@
 <script setup lang="ts">
 import VueApexCharts from 'vue3-apexcharts'
 import {ref, watch} from 'vue'
-import {useSettingsStore} from '@/pinia/settings'
+import {useSettingsStore} from '@/pinia'
 import {storeToRefs} from 'pinia'
 
 const {series, max, y_formatter} = defineProps(['series', 'max', 'y_formatter'])

+ 0 - 140
frontend/src/components/Chart/CPUChart.vue

@@ -1,140 +0,0 @@
-<template>
-    <apexchart type="area" height="200" :options="chartOptions" :series="series" ref="chart"/>
-</template>
-
-<script>
-import VueApexCharts from 'vue-apexcharts'
-import Vue from 'vue'
-
-Vue.use(VueApexCharts)
-Vue.component('apexchart', VueApexCharts)
-const fontColor = () => {
-    return window.matchMedia('(prefers-color-scheme: dark)').matches ? '#b4b4b4' : undefined
-}
-export default {
-    name: 'CPUChart',
-    props: {
-        series: Array
-    },
-    watch: {
-        series: {
-            deep: true,
-            handler() {
-                this.$refs.chart.updateSeries(this.series)
-            }
-        }
-    },
-    mounted() {
-        let media = window.matchMedia('(prefers-color-scheme: dark)')
-        let callback = () => {
-            this.chartOptions.xaxis = {
-                type: 'datetime',
-                labels: {
-                    datetimeUTC: false,
-                    style: {
-                        colors: fontColor()
-                    }
-                }
-            }
-            this.chartOptions.yaxis = {
-                max: 100,
-                tickAmount: 4,
-                min: 0,
-                labels: {
-                    style: {
-                        colors: fontColor()
-                    }
-                }
-            }
-            this.chartOptions.legend = {
-                labels: {
-                    colors: fontColor()
-                },
-                onItemClick: {
-                    toggleDataSeries: false
-                },
-                onItemHover: {
-                    highlightDataSeries: false
-                },
-            }
-            this.$refs.chart.updateOptions(this.chartOptions)
-        }
-        if (typeof media.addEventListener === 'function') {
-            media.addEventListener('change', callback)
-        } else if (typeof media.addListener === 'function') {
-            media.addListener(callback)
-        }
-    },
-    data() {
-        return {
-            chartOptions: {
-                series: this.series,
-                chart: {
-                    type: 'area',
-                    zoom: {
-                        enabled: false
-                    },
-                    animations: {
-                        enabled: false,
-                    },
-                    toolbar: {
-                        show: false
-                    },
-                },
-                colors: ['#ff6385', '#36a3eb'],
-                fill: {
-                    // type: ['solid', 'gradient'],
-                    gradient: {
-                        shade: 'light'
-                    }
-                    //colors:  ['#ff6385', '#36a3eb'],
-                },
-                dataLabels: {
-                    enabled: false
-                },
-                stroke: {
-                    curve: 'smooth',
-                    width: 0,
-                },
-                xaxis: {
-                    type: 'datetime',
-                    labels: {
-                        datetimeUTC: false,
-                        style: {
-                            colors: fontColor()
-                        }
-                    }
-                },
-                tooltip: {
-                    enabled: false
-                },
-                yaxis: {
-                    max: 100,
-                    tickAmount: 4,
-                    min: 0,
-                    labels: {
-                        style: {
-                            colors: fontColor()
-                        }
-                    }
-                },
-                legend: {
-                    labels: {
-                        colors: fontColor()
-                    },
-                    onItemClick: {
-                        toggleDataSeries: false
-                    },
-                    onItemHover: {
-                        highlightDataSeries: false
-                    },
-                }
-            },
-        }
-    },
-}
-</script>
-
-<style scoped>
-
-</style>

Some files were not shown because too many files changed in this diff