diff --git a/.gitignore b/.gitignore index 823fa54176b8ea13151564a76d9d2bfe31b6cbc5..b75792848b1a805691cfa32727c8e1cf3f0d5580 100644 --- a/.gitignore +++ b/.gitignore @@ -16,6 +16,7 @@ dist-ssr # Editor directories and files .idea .DS_Store +.vscode *.suo *.ntvs* *.njsproj diff --git a/.ls-lint.yml b/.ls-lint.yml index 4e9dea31fc467951cc09abff87318bb3d6dd8767..4ac1a74fcb4d14f92bb36aea20b42f20f87437c5 100644 --- a/.ls-lint.yml +++ b/.ls-lint.yml @@ -40,6 +40,16 @@ ignore: - packages/ui-vue/package - packages/ui-vue/demos - packages/ui-vue/designer + # mobile-ui-vue + - packages/mobile-ui-vue/.vscode + - packages/mobile-ui-vue/docs/.vitepress + - packages/mobile-ui-vue/node_modules + - packages/mobile-ui-vue/dist + - packages/mobile-ui-vue/public + - packages/mobile-ui-vue/docs + - packages/mobile-ui-vue/package + - packages/mobile-ui-vue/demos + - packages/mobile-ui-vue/designer # eslint-config - packages/eslint-config/node_modules - packages/eslint-config/test diff --git a/.prettierrc b/.prettierrc index b387dad3396a9c8715baad311dc83f0cd81b9e97..bedfc16c83eb9215d71f30656f12b2b231f747a5 100644 --- a/.prettierrc +++ b/.prettierrc @@ -3,7 +3,7 @@ "jsxBracketSameLine": true, "jsxSingleQuote": false, "printWidth": 140, - "semi": true, + "semi": false, "useTabs": false, "trailingComma": "none", "singleQuote": true, diff --git a/lerna.json b/lerna.json index 8bd8090d93f349456844cba10cb267d46d1386e1..c599682e451ddf4f4a5120018d6118e4dde646de 100644 --- a/lerna.json +++ b/lerna.json @@ -4,7 +4,8 @@ "packages/f-theme-editor-project", "packages/farris-theme", "packages/renderer", - "packages/ui-vue" + "packages/ui-vue", + "packages/mobile-ui-vue" ], "version": "0.0.0", "useWorkspaces": true, diff --git a/package.json b/package.json index a16cc27eb826756e96f56ee29753701489467fd4..155a80a8dca84b92d67f7043622e3f87808715d1 100644 --- a/package.json +++ b/package.json @@ -53,7 +53,6 @@ "cors": "^2.8.4", "cpy-cli": "^2.0.0", "crypto-js": "^4.2.0", - "crypto-js": "^4.2.0", "date-fns": "^2.16.1", "del-cli": "^1.1.0", "esbuild-register": "^3.3.0", @@ -102,7 +101,6 @@ "tslint": "~5.11.0", "typescript": "^4.9.5", "urlencode": "^2.0.0", - "urlencode": "^2.0.0", "vite": "^4.4.1", "vite-plugin-dts": "2.1.0", "vite-plugin-md": "^0.20.0", diff --git a/packages/farris-theme/src/assets/themes/default/default/iteration.css b/packages/farris-theme/src/assets/themes/default/default/iteration.css index 201a8e8c709b5301ab74774fb47bfb0c5e56e561..171531320b72238c23ecb0a46beafd22a467dcab 100644 --- a/packages/farris-theme/src/assets/themes/default/default/iteration.css +++ b/packages/farris-theme/src/assets/themes/default/default/iteration.css @@ -1 +1 @@ -@charset "UTF-8";article,aside,figcaption,figure,footer,header,hgroup,legend,main,nav,section{display:block}.dropdown-menu,.form-control,body{font-size:.8125rem}.popover,.tooltip,address{font-style:normal}.collapsing,.dropdown-divider,.modal-open,.progress,svg{overflow:hidden}img,svg{vertical-align:middle}.dropdown-menu,body,caption{text-align:left}.popover,.tooltip,button,select{text-transform:none}pre,textarea{overflow:auto}progress,sub,sup{vertical-align:baseline}label,output{display:inline-block}.close:not(:disabled):not(.disabled),.dropdown-item,.navbar-toggler:not(:disabled):not(.disabled),.page-link:not(:disabled):not(.disabled),summary{cursor:pointer}:root{--blue:#007bff;--indigo:#6610f2;--purple:#6f42c1;--pink:#e83e8c;--red:#dc3545;--orange:#fd7e14;--yellow:#ffc107;--green:#28a745;--teal:#20c997;--cyan:#17a2b8;--white:#fff;--gray:#6c757d;--gray-dark:#343a40;--primary:#2A87FF;--secondary:#6c757d;--success:#6CC77F;--info:#5EA4FF;--warning:#F5A144;--danger:#dc3545;--light:#f8f9fa;--dark:#343a40;--breakpoint-xs:0;--breakpoint-sm:576px;--breakpoint-md:768px;--breakpoint-lg:888px;--breakpoint-xl:1200px;--breakpoint-el:1690px;--font-family-sans-serif:f-inspect(-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji");--font-family-monospace:f-inspect(SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace)}*,::after,::before{box-sizing:border-box}html{font-family:sans-serif;line-height:1.15;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%;-ms-overflow-style:scrollbar;-webkit-tap-highlight-color:transparent}body{margin:0;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI","PingFang SC","Hiragino Sans GB","Microsoft YaHei","Helvetica Neue",Helvetica,Arial,sans-serif;font-weight:400;line-height:1.4286;color:#2D2F33;background-color:#fff}.f-text-monospace,code,kbd,pre,samp{font-family:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace}.close,.f-alert-link,dt,kbd kbd{font-weight:700}[tabindex="-1"]:focus{outline:0!important}h1,h2,h3,h4,h5,h6{margin-top:0;margin-bottom:.5rem}dl,ol,p,ul{margin-top:0;margin-bottom:1rem}abbr[data-original-title],abbr[title]{-webkit-text-decoration:underline dotted;text-decoration:underline dotted;cursor:help;border-bottom:0}address{margin-bottom:1rem;line-height:inherit}ol ol,ol ul,ul ol,ul ul{margin-bottom:0}dd{margin-bottom:.5rem;margin-left:0}blockquote,figure{margin:0 0 1rem}dfn{font-style:italic}b,strong{font-weight:bolder}small{font-size:80%}sub,sup{position:relative;font-size:75%;line-height:0}sub{bottom:-.25em}sup{top:-.5em}a{color:#2A87FF;text-decoration:none;background-color:transparent;-webkit-text-decoration-skip:objects}a:hover{color:#529DFF;text-decoration:none}a:not([href]):not([tabindex]),a:not([href]):not([tabindex]):focus,a:not([href]):not([tabindex]):hover{color:inherit;text-decoration:none}a:not([href]):not([tabindex]):focus{outline:0}code,kbd,pre,samp{font-size:1em}pre{margin-top:0;margin-bottom:1rem;-ms-overflow-style:scrollbar}img{border-style:none}table{border-collapse:collapse}caption{padding-top:.75rem;padding-bottom:.75rem;color:#A8ADB8;caption-side:bottom}th{text-align:inherit}label{margin-bottom:.3125rem}button{border-radius:0}button:focus{outline:dotted 1px;outline:-webkit-focus-ring-color auto 5px}button,input,optgroup,select,textarea{margin:0;font-family:inherit;font-size:inherit;line-height:inherit}button,input{overflow:visible}button [type=reset],button [type=submit],button button,button html [type=button],select [type=reset],select [type=submit],select button,select html [type=button]{-webkit-appearance:button}[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner,button::-moz-focus-inner{padding:0;border-style:none}input[type=radio],input[type=checkbox]{box-sizing:border-box;padding:0}input[type=date],input[type=time],input[type=datetime-local],input[type=month]{-webkit-appearance:listbox}textarea{resize:vertical}fieldset{min-width:0;padding:0;margin:0;border:0}legend{width:100%;max-width:100%;padding:0;margin-bottom:.5rem;font-size:1.5rem;line-height:inherit;color:inherit;white-space:normal}[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}[type=search]{outline-offset:-2px;-webkit-appearance:none}[type=search]::-webkit-search-cancel-button,[type=search]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{font:inherit;-webkit-appearance:button}summary{display:list-item}template{display:none}[hidden]{display:none!important}.h1,.h2,.h3,.h4,.h5,.h6,h1,h2,h3,h4,h5,h6{margin-bottom:.5rem;font-family:inherit;font-weight:400;line-height:1.2;color:inherit}.blockquote,.table,hr{margin-bottom:1rem}.display-1,.display-2,.display-3,.display-4,.lead{font-weight:300}.h1,h1{font-size:1.625rem}.h2,h2{font-size:1.5rem}.h3,h3{font-size:1.375rem}.h4,h4{font-size:1.25rem}.h5,h5{font-size:1rem}.h6,h6{font-size:.875rem}.lead{font-size:1.01562rem}.display-1{font-size:6rem;line-height:1.2}.display-2{font-size:5.5rem;line-height:1.2}.display-3{font-size:4.5rem;line-height:1.2}.display-4{font-size:3.5rem;line-height:1.2}hr{box-sizing:content-box;height:0;overflow:visible;margin-top:1rem;border:0;border-top:1px solid rgba(0,0,0,.1)}.img-fluid,.img-thumbnail{max-width:100%;height:auto}.small,small{font-size:80%;font-weight:400}.mark,mark{padding:.2em;background-color:#fcf8e3}.list-inline,.list-unstyled{padding-left:0;list-style:none}.list-inline-item{display:inline-block}.list-inline-item:not(:last-child){margin-right:.5rem}.initialism{font-size:90%;text-transform:uppercase}.blockquote{font-size:1.01562rem}.blockquote-footer{display:block;font-size:80%;color:#6c757d}.blockquote-footer::before{content:"\2014 \00A0"}.img-thumbnail{padding:.25rem;background-color:#fff;border:1px solid #dee2e6;border-radius:3px;box-shadow:0 1px 2px rgba(0,0,0,.075)}.figure{display:inline-block}.figure-img{margin-bottom:.5rem;line-height:1}.figure-caption{font-size:90%;color:#6c757d}code,kbd{font-size:87.5%}.f-alert-dismissible .f-close,.f-alert-heading,.popover-header,a>code,pre code{color:inherit}code{color:#e83e8c;word-break:break-word}kbd{padding:.2rem .4rem;color:#fff;background-color:#212529;border-radius:3px;box-shadow:inset 0 -.1rem 0 rgba(0,0,0,.25)}.table,.table .table{background-color:#fff}kbd kbd{padding:0;font-size:100%;box-shadow:none}.container,.container-fluid{padding-right:14px;padding-left:14px;margin-right:auto;margin-left:auto;width:100%}pre{display:block;font-size:87.5%;color:#212529}pre code{font-size:inherit;word-break:normal}.pre-scrollable{max-height:21.25rem;overflow-y:scroll}@media (min-width:576px){.container{max-width:540px}}@media (min-width:768px){.container{max-width:720px}}@media (min-width:888px){.container{max-width:960px}}@media (min-width:1200px){.container{max-width:1140px}}.row{display:flex;flex-wrap:wrap;margin-right:-14px;margin-left:-14px}.no-gutters{margin-right:0;margin-left:0}.no-gutters>.col,.no-gutters>[class*=col-]{padding-right:0;padding-left:0}.col,.col-1,.col-10,.col-11,.col-12,.col-2,.col-3,.col-4,.col-5,.col-6,.col-7,.col-8,.col-9,.col-auto,.col-el,.col-el-1,.col-el-10,.col-el-11,.col-el-12,.col-el-2,.col-el-3,.col-el-4,.col-el-5,.col-el-6,.col-el-7,.col-el-8,.col-el-9,.col-el-auto,.col-lg,.col-lg-1,.col-lg-10,.col-lg-11,.col-lg-12,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9,.col-lg-auto,.col-md,.col-md-1,.col-md-10,.col-md-11,.col-md-12,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9,.col-md-auto,.col-sm,.col-sm-1,.col-sm-10,.col-sm-11,.col-sm-12,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9,.col-sm-auto,.col-xl,.col-xl-1,.col-xl-10,.col-xl-11,.col-xl-12,.col-xl-2,.col-xl-3,.col-xl-4,.col-xl-5,.col-xl-6,.col-xl-7,.col-xl-8,.col-xl-9,.col-xl-auto{position:relative;width:100%;min-height:1px;padding-right:14px;padding-left:14px}.col{flex-basis:0;flex-grow:1;max-width:100%}.col-auto{flex-grow:0;flex-shrink:0;flex-basis:auto;width:auto;max-width:none}.col-1{flex-grow:0;flex-shrink:0;flex-basis:8.33333%;max-width:8.33333%}.col-2{flex-grow:0;flex-shrink:0;flex-basis:16.66667%;max-width:16.66667%}.col-3{flex-grow:0;flex-shrink:0;flex-basis:25%;max-width:25%}.col-4{flex-grow:0;flex-shrink:0;flex-basis:33.33333%;max-width:33.33333%}.col-5{flex-grow:0;flex-shrink:0;flex-basis:41.66667%;max-width:41.66667%}.col-6{flex-grow:0;flex-shrink:0;flex-basis:50%;max-width:50%}.col-7{flex-grow:0;flex-shrink:0;flex-basis:58.33333%;max-width:58.33333%}.col-8{flex-grow:0;flex-shrink:0;flex-basis:66.66667%;max-width:66.66667%}.col-9{flex-grow:0;flex-shrink:0;flex-basis:75%;max-width:75%}.col-10{flex-grow:0;flex-shrink:0;flex-basis:83.33333%;max-width:83.33333%}.col-11{flex-grow:0;flex-shrink:0;flex-basis:91.66667%;max-width:91.66667%}.col-12{flex-grow:0;flex-shrink:0;flex-basis:100%;max-width:100%}.order-first{order:-1}.order-last{order:13}.order-0{order:0}.order-1{order:1}.order-2{order:2}.order-3{order:3}.order-4{order:4}.order-5{order:5}.order-6{order:6}.order-7{order:7}.order-8{order:8}.order-9{order:9}.order-10{order:10}.order-11{order:11}.order-12{order:12}.offset-1{margin-left:8.33333%}.offset-2{margin-left:16.66667%}.offset-3{margin-left:25%}.offset-4{margin-left:33.33333%}.offset-5{margin-left:41.66667%}.offset-6{margin-left:50%}.offset-7{margin-left:58.33333%}.offset-8{margin-left:66.66667%}.offset-9{margin-left:75%}.offset-10{margin-left:83.33333%}.offset-11{margin-left:91.66667%}.f-area-response [class*=col-xs]{flex:none;max-width:none}.f-area-response.f-area-response--xs .col-xs-1{flex-grow:0;flex-shrink:0;flex-basis:8.33333%;max-width:8.33333%}.f-area-response.f-area-response--xs .col-xs-2{flex-grow:0;flex-shrink:0;flex-basis:16.66667%;max-width:16.66667%}.f-area-response.f-area-response--xs .col-xs-3{flex-grow:0;flex-shrink:0;flex-basis:25%;max-width:25%}.f-area-response.f-area-response--xs .col-xs-4{flex-grow:0;flex-shrink:0;flex-basis:33.33333%;max-width:33.33333%}.f-area-response.f-area-response--xs .col-xs-5{flex-grow:0;flex-shrink:0;flex-basis:41.66667%;max-width:41.66667%}.f-area-response.f-area-response--xs .col-xs-6{flex-grow:0;flex-shrink:0;flex-basis:50%;max-width:50%}.f-area-response.f-area-response--xs .col-xs-7{flex-grow:0;flex-shrink:0;flex-basis:58.33333%;max-width:58.33333%}.f-area-response.f-area-response--xs .col-xs-8{flex-grow:0;flex-shrink:0;flex-basis:66.66667%;max-width:66.66667%}.f-area-response.f-area-response--xs .col-xs-9{flex-grow:0;flex-shrink:0;flex-basis:75%;max-width:75%}.f-area-response.f-area-response--xs .col-xs-10{flex-grow:0;flex-shrink:0;flex-basis:83.33333%;max-width:83.33333%}.f-area-response.f-area-response--xs .col-xs-11{flex-grow:0;flex-shrink:0;flex-basis:91.66667%;max-width:91.66667%}.f-area-response.f-area-response--xs .col-xs-12{flex-grow:0;flex-shrink:0;flex-basis:100%;max-width:100%}@media (min-width:576px){.col-sm{flex-basis:0;flex-grow:1;max-width:100%}.col-sm-auto{flex-grow:0;flex-shrink:0;flex-basis:auto;width:auto;max-width:none}.col-sm-1{flex-grow:0;flex-shrink:0;flex-basis:8.33333%;max-width:8.33333%}.col-sm-2{flex-grow:0;flex-shrink:0;flex-basis:16.66667%;max-width:16.66667%}.col-sm-3{flex-grow:0;flex-shrink:0;flex-basis:25%;max-width:25%}.col-sm-4{flex-grow:0;flex-shrink:0;flex-basis:33.33333%;max-width:33.33333%}.col-sm-5{flex-grow:0;flex-shrink:0;flex-basis:41.66667%;max-width:41.66667%}.col-sm-6{flex-grow:0;flex-shrink:0;flex-basis:50%;max-width:50%}.col-sm-7{flex-grow:0;flex-shrink:0;flex-basis:58.33333%;max-width:58.33333%}.col-sm-8{flex-grow:0;flex-shrink:0;flex-basis:66.66667%;max-width:66.66667%}.col-sm-9{flex-grow:0;flex-shrink:0;flex-basis:75%;max-width:75%}.col-sm-10{flex-grow:0;flex-shrink:0;flex-basis:83.33333%;max-width:83.33333%}.col-sm-11{flex-grow:0;flex-shrink:0;flex-basis:91.66667%;max-width:91.66667%}.col-sm-12{flex-grow:0;flex-shrink:0;flex-basis:100%;max-width:100%}.order-sm-first{order:-1}.order-sm-last{order:13}.order-sm-0{order:0}.order-sm-1{order:1}.order-sm-2{order:2}.order-sm-3{order:3}.order-sm-4{order:4}.order-sm-5{order:5}.order-sm-6{order:6}.order-sm-7{order:7}.order-sm-8{order:8}.order-sm-9{order:9}.order-sm-10{order:10}.order-sm-11{order:11}.order-sm-12{order:12}.offset-sm-0{margin-left:0}.offset-sm-1{margin-left:8.33333%}.offset-sm-2{margin-left:16.66667%}.offset-sm-3{margin-left:25%}.offset-sm-4{margin-left:33.33333%}.offset-sm-5{margin-left:41.66667%}.offset-sm-6{margin-left:50%}.offset-sm-7{margin-left:58.33333%}.offset-sm-8{margin-left:66.66667%}.offset-sm-9{margin-left:75%}.offset-sm-10{margin-left:83.33333%}.offset-sm-11{margin-left:91.66667%}}.f-area-response [class*=col-sm]{flex:none;max-width:none}.f-area-response.f-area-response--sm .col-sm-1{flex-grow:0;flex-shrink:0;flex-basis:8.33333%;max-width:8.33333%}.f-area-response.f-area-response--sm .col-sm-2{flex-grow:0;flex-shrink:0;flex-basis:16.66667%;max-width:16.66667%}.f-area-response.f-area-response--sm .col-sm-3{flex-grow:0;flex-shrink:0;flex-basis:25%;max-width:25%}.f-area-response.f-area-response--sm .col-sm-4{flex-grow:0;flex-shrink:0;flex-basis:33.33333%;max-width:33.33333%}.f-area-response.f-area-response--sm .col-sm-5{flex-grow:0;flex-shrink:0;flex-basis:41.66667%;max-width:41.66667%}.f-area-response.f-area-response--sm .col-sm-6{flex-grow:0;flex-shrink:0;flex-basis:50%;max-width:50%}.f-area-response.f-area-response--sm .col-sm-7{flex-grow:0;flex-shrink:0;flex-basis:58.33333%;max-width:58.33333%}.f-area-response.f-area-response--sm .col-sm-8{flex-grow:0;flex-shrink:0;flex-basis:66.66667%;max-width:66.66667%}.f-area-response.f-area-response--sm .col-sm-9{flex-grow:0;flex-shrink:0;flex-basis:75%;max-width:75%}.f-area-response.f-area-response--sm .col-sm-10{flex-grow:0;flex-shrink:0;flex-basis:83.33333%;max-width:83.33333%}.f-area-response.f-area-response--sm .col-sm-11{flex-grow:0;flex-shrink:0;flex-basis:91.66667%;max-width:91.66667%}.f-area-response.f-area-response--sm .col-sm-12{flex-grow:0;flex-shrink:0;flex-basis:100%;max-width:100%}@media (min-width:768px){.col-md{flex-basis:0;flex-grow:1;max-width:100%}.col-md-auto{flex-grow:0;flex-shrink:0;flex-basis:auto;width:auto;max-width:none}.col-md-1{flex-grow:0;flex-shrink:0;flex-basis:8.33333%;max-width:8.33333%}.col-md-2{flex-grow:0;flex-shrink:0;flex-basis:16.66667%;max-width:16.66667%}.col-md-3{flex-grow:0;flex-shrink:0;flex-basis:25%;max-width:25%}.col-md-4{flex-grow:0;flex-shrink:0;flex-basis:33.33333%;max-width:33.33333%}.col-md-5{flex-grow:0;flex-shrink:0;flex-basis:41.66667%;max-width:41.66667%}.col-md-6{flex-grow:0;flex-shrink:0;flex-basis:50%;max-width:50%}.col-md-7{flex-grow:0;flex-shrink:0;flex-basis:58.33333%;max-width:58.33333%}.col-md-8{flex-grow:0;flex-shrink:0;flex-basis:66.66667%;max-width:66.66667%}.col-md-9{flex-grow:0;flex-shrink:0;flex-basis:75%;max-width:75%}.col-md-10{flex-grow:0;flex-shrink:0;flex-basis:83.33333%;max-width:83.33333%}.col-md-11{flex-grow:0;flex-shrink:0;flex-basis:91.66667%;max-width:91.66667%}.col-md-12{flex-grow:0;flex-shrink:0;flex-basis:100%;max-width:100%}.order-md-first{order:-1}.order-md-last{order:13}.order-md-0{order:0}.order-md-1{order:1}.order-md-2{order:2}.order-md-3{order:3}.order-md-4{order:4}.order-md-5{order:5}.order-md-6{order:6}.order-md-7{order:7}.order-md-8{order:8}.order-md-9{order:9}.order-md-10{order:10}.order-md-11{order:11}.order-md-12{order:12}.offset-md-0{margin-left:0}.offset-md-1{margin-left:8.33333%}.offset-md-2{margin-left:16.66667%}.offset-md-3{margin-left:25%}.offset-md-4{margin-left:33.33333%}.offset-md-5{margin-left:41.66667%}.offset-md-6{margin-left:50%}.offset-md-7{margin-left:58.33333%}.offset-md-8{margin-left:66.66667%}.offset-md-9{margin-left:75%}.offset-md-10{margin-left:83.33333%}.offset-md-11{margin-left:91.66667%}}.f-area-response [class*=col-md]{flex:none;max-width:none}.f-area-response.f-area-response--md .col-md-1{flex-grow:0;flex-shrink:0;flex-basis:8.33333%;max-width:8.33333%}.f-area-response.f-area-response--md .col-md-2{flex-grow:0;flex-shrink:0;flex-basis:16.66667%;max-width:16.66667%}.f-area-response.f-area-response--md .col-md-3{flex-grow:0;flex-shrink:0;flex-basis:25%;max-width:25%}.f-area-response.f-area-response--md .col-md-4{flex-grow:0;flex-shrink:0;flex-basis:33.33333%;max-width:33.33333%}.f-area-response.f-area-response--md .col-md-5{flex-grow:0;flex-shrink:0;flex-basis:41.66667%;max-width:41.66667%}.f-area-response.f-area-response--md .col-md-6{flex-grow:0;flex-shrink:0;flex-basis:50%;max-width:50%}.f-area-response.f-area-response--md .col-md-7{flex-grow:0;flex-shrink:0;flex-basis:58.33333%;max-width:58.33333%}.f-area-response.f-area-response--md .col-md-8{flex-grow:0;flex-shrink:0;flex-basis:66.66667%;max-width:66.66667%}.f-area-response.f-area-response--md .col-md-9{flex-grow:0;flex-shrink:0;flex-basis:75%;max-width:75%}.f-area-response.f-area-response--md .col-md-10{flex-grow:0;flex-shrink:0;flex-basis:83.33333%;max-width:83.33333%}.f-area-response.f-area-response--md .col-md-11{flex-grow:0;flex-shrink:0;flex-basis:91.66667%;max-width:91.66667%}.f-area-response.f-area-response--md .col-md-12{flex-grow:0;flex-shrink:0;flex-basis:100%;max-width:100%}@media (min-width:888px){.col-lg{flex-basis:0;flex-grow:1;max-width:100%}.col-lg-auto{flex-grow:0;flex-shrink:0;flex-basis:auto;width:auto;max-width:none}.col-lg-1{flex-grow:0;flex-shrink:0;flex-basis:8.33333%;max-width:8.33333%}.col-lg-2{flex-grow:0;flex-shrink:0;flex-basis:16.66667%;max-width:16.66667%}.col-lg-3{flex-grow:0;flex-shrink:0;flex-basis:25%;max-width:25%}.col-lg-4{flex-grow:0;flex-shrink:0;flex-basis:33.33333%;max-width:33.33333%}.col-lg-5{flex-grow:0;flex-shrink:0;flex-basis:41.66667%;max-width:41.66667%}.col-lg-6{flex-grow:0;flex-shrink:0;flex-basis:50%;max-width:50%}.col-lg-7{flex-grow:0;flex-shrink:0;flex-basis:58.33333%;max-width:58.33333%}.col-lg-8{flex-grow:0;flex-shrink:0;flex-basis:66.66667%;max-width:66.66667%}.col-lg-9{flex-grow:0;flex-shrink:0;flex-basis:75%;max-width:75%}.col-lg-10{flex-grow:0;flex-shrink:0;flex-basis:83.33333%;max-width:83.33333%}.col-lg-11{flex-grow:0;flex-shrink:0;flex-basis:91.66667%;max-width:91.66667%}.col-lg-12{flex-grow:0;flex-shrink:0;flex-basis:100%;max-width:100%}.order-lg-first{order:-1}.order-lg-last{order:13}.order-lg-0{order:0}.order-lg-1{order:1}.order-lg-2{order:2}.order-lg-3{order:3}.order-lg-4{order:4}.order-lg-5{order:5}.order-lg-6{order:6}.order-lg-7{order:7}.order-lg-8{order:8}.order-lg-9{order:9}.order-lg-10{order:10}.order-lg-11{order:11}.order-lg-12{order:12}.offset-lg-0{margin-left:0}.offset-lg-1{margin-left:8.33333%}.offset-lg-2{margin-left:16.66667%}.offset-lg-3{margin-left:25%}.offset-lg-4{margin-left:33.33333%}.offset-lg-5{margin-left:41.66667%}.offset-lg-6{margin-left:50%}.offset-lg-7{margin-left:58.33333%}.offset-lg-8{margin-left:66.66667%}.offset-lg-9{margin-left:75%}.offset-lg-10{margin-left:83.33333%}.offset-lg-11{margin-left:91.66667%}}.f-area-response [class*=col-lg]{flex:none;max-width:none}.f-area-response.f-area-response--lg .col-lg-1{flex-grow:0;flex-shrink:0;flex-basis:8.33333%;max-width:8.33333%}.f-area-response.f-area-response--lg .col-lg-2{flex-grow:0;flex-shrink:0;flex-basis:16.66667%;max-width:16.66667%}.f-area-response.f-area-response--lg .col-lg-3{flex-grow:0;flex-shrink:0;flex-basis:25%;max-width:25%}.f-area-response.f-area-response--lg .col-lg-4{flex-grow:0;flex-shrink:0;flex-basis:33.33333%;max-width:33.33333%}.f-area-response.f-area-response--lg .col-lg-5{flex-grow:0;flex-shrink:0;flex-basis:41.66667%;max-width:41.66667%}.f-area-response.f-area-response--lg .col-lg-6{flex-grow:0;flex-shrink:0;flex-basis:50%;max-width:50%}.f-area-response.f-area-response--lg .col-lg-7{flex-grow:0;flex-shrink:0;flex-basis:58.33333%;max-width:58.33333%}.f-area-response.f-area-response--lg .col-lg-8{flex-grow:0;flex-shrink:0;flex-basis:66.66667%;max-width:66.66667%}.f-area-response.f-area-response--lg .col-lg-9{flex-grow:0;flex-shrink:0;flex-basis:75%;max-width:75%}.f-area-response.f-area-response--lg .col-lg-10{flex-grow:0;flex-shrink:0;flex-basis:83.33333%;max-width:83.33333%}.f-area-response.f-area-response--lg .col-lg-11{flex-grow:0;flex-shrink:0;flex-basis:91.66667%;max-width:91.66667%}.f-area-response.f-area-response--lg .col-lg-12{flex-grow:0;flex-shrink:0;flex-basis:100%;max-width:100%}@media (min-width:1200px){.col-xl{flex-basis:0;flex-grow:1;max-width:100%}.col-xl-auto{flex-grow:0;flex-shrink:0;flex-basis:auto;width:auto;max-width:none}.col-xl-1{flex-grow:0;flex-shrink:0;flex-basis:8.33333%;max-width:8.33333%}.col-xl-2{flex-grow:0;flex-shrink:0;flex-basis:16.66667%;max-width:16.66667%}.col-xl-3{flex-grow:0;flex-shrink:0;flex-basis:25%;max-width:25%}.col-xl-4{flex-grow:0;flex-shrink:0;flex-basis:33.33333%;max-width:33.33333%}.col-xl-5{flex-grow:0;flex-shrink:0;flex-basis:41.66667%;max-width:41.66667%}.col-xl-6{flex-grow:0;flex-shrink:0;flex-basis:50%;max-width:50%}.col-xl-7{flex-grow:0;flex-shrink:0;flex-basis:58.33333%;max-width:58.33333%}.col-xl-8{flex-grow:0;flex-shrink:0;flex-basis:66.66667%;max-width:66.66667%}.col-xl-9{flex-grow:0;flex-shrink:0;flex-basis:75%;max-width:75%}.col-xl-10{flex-grow:0;flex-shrink:0;flex-basis:83.33333%;max-width:83.33333%}.col-xl-11{flex-grow:0;flex-shrink:0;flex-basis:91.66667%;max-width:91.66667%}.col-xl-12{flex-grow:0;flex-shrink:0;flex-basis:100%;max-width:100%}.order-xl-first{order:-1}.order-xl-last{order:13}.order-xl-0{order:0}.order-xl-1{order:1}.order-xl-2{order:2}.order-xl-3{order:3}.order-xl-4{order:4}.order-xl-5{order:5}.order-xl-6{order:6}.order-xl-7{order:7}.order-xl-8{order:8}.order-xl-9{order:9}.order-xl-10{order:10}.order-xl-11{order:11}.order-xl-12{order:12}.offset-xl-0{margin-left:0}.offset-xl-1{margin-left:8.33333%}.offset-xl-2{margin-left:16.66667%}.offset-xl-3{margin-left:25%}.offset-xl-4{margin-left:33.33333%}.offset-xl-5{margin-left:41.66667%}.offset-xl-6{margin-left:50%}.offset-xl-7{margin-left:58.33333%}.offset-xl-8{margin-left:66.66667%}.offset-xl-9{margin-left:75%}.offset-xl-10{margin-left:83.33333%}.offset-xl-11{margin-left:91.66667%}}.f-area-response [class*=col-xl]{flex:none;max-width:none}.f-area-response.f-area-response--xl .col-xl-1{flex-grow:0;flex-shrink:0;flex-basis:8.33333%;max-width:8.33333%}.f-area-response.f-area-response--xl .col-xl-2{flex-grow:0;flex-shrink:0;flex-basis:16.66667%;max-width:16.66667%}.f-area-response.f-area-response--xl .col-xl-3{flex-grow:0;flex-shrink:0;flex-basis:25%;max-width:25%}.f-area-response.f-area-response--xl .col-xl-4{flex-grow:0;flex-shrink:0;flex-basis:33.33333%;max-width:33.33333%}.f-area-response.f-area-response--xl .col-xl-5{flex-grow:0;flex-shrink:0;flex-basis:41.66667%;max-width:41.66667%}.f-area-response.f-area-response--xl .col-xl-6{flex-grow:0;flex-shrink:0;flex-basis:50%;max-width:50%}.f-area-response.f-area-response--xl .col-xl-7{flex-grow:0;flex-shrink:0;flex-basis:58.33333%;max-width:58.33333%}.f-area-response.f-area-response--xl .col-xl-8{flex-grow:0;flex-shrink:0;flex-basis:66.66667%;max-width:66.66667%}.f-area-response.f-area-response--xl .col-xl-9{flex-grow:0;flex-shrink:0;flex-basis:75%;max-width:75%}.f-area-response.f-area-response--xl .col-xl-10{flex-grow:0;flex-shrink:0;flex-basis:83.33333%;max-width:83.33333%}.f-area-response.f-area-response--xl .col-xl-11{flex-grow:0;flex-shrink:0;flex-basis:91.66667%;max-width:91.66667%}.f-area-response.f-area-response--xl .col-xl-12{flex-grow:0;flex-shrink:0;flex-basis:100%;max-width:100%}@media (min-width:1690px){.col-el{flex-basis:0;flex-grow:1;max-width:100%}.col-el-auto{flex-grow:0;flex-shrink:0;flex-basis:auto;width:auto;max-width:none}.col-el-1{flex-grow:0;flex-shrink:0;flex-basis:8.33333%;max-width:8.33333%}.col-el-2{flex-grow:0;flex-shrink:0;flex-basis:16.66667%;max-width:16.66667%}.col-el-3{flex-grow:0;flex-shrink:0;flex-basis:25%;max-width:25%}.col-el-4{flex-grow:0;flex-shrink:0;flex-basis:33.33333%;max-width:33.33333%}.col-el-5{flex-grow:0;flex-shrink:0;flex-basis:41.66667%;max-width:41.66667%}.col-el-6{flex-grow:0;flex-shrink:0;flex-basis:50%;max-width:50%}.col-el-7{flex-grow:0;flex-shrink:0;flex-basis:58.33333%;max-width:58.33333%}.col-el-8{flex-grow:0;flex-shrink:0;flex-basis:66.66667%;max-width:66.66667%}.col-el-9{flex-grow:0;flex-shrink:0;flex-basis:75%;max-width:75%}.col-el-10{flex-grow:0;flex-shrink:0;flex-basis:83.33333%;max-width:83.33333%}.col-el-11{flex-grow:0;flex-shrink:0;flex-basis:91.66667%;max-width:91.66667%}.col-el-12{flex-grow:0;flex-shrink:0;flex-basis:100%;max-width:100%}.order-el-first{order:-1}.order-el-last{order:13}.order-el-0{order:0}.order-el-1{order:1}.order-el-2{order:2}.order-el-3{order:3}.order-el-4{order:4}.order-el-5{order:5}.order-el-6{order:6}.order-el-7{order:7}.order-el-8{order:8}.order-el-9{order:9}.order-el-10{order:10}.order-el-11{order:11}.order-el-12{order:12}.offset-el-0{margin-left:0}.offset-el-1{margin-left:8.33333%}.offset-el-2{margin-left:16.66667%}.offset-el-3{margin-left:25%}.offset-el-4{margin-left:33.33333%}.offset-el-5{margin-left:41.66667%}.offset-el-6{margin-left:50%}.offset-el-7{margin-left:58.33333%}.offset-el-8{margin-left:66.66667%}.offset-el-9{margin-left:75%}.offset-el-10{margin-left:83.33333%}.offset-el-11{margin-left:91.66667%}}.f-area-response [class*=col-el]{flex:none;max-width:none}.f-area-response.f-area-response--el .col-el-1{flex-grow:0;flex-shrink:0;flex-basis:8.33333%;max-width:8.33333%}.f-area-response.f-area-response--el .col-el-2{flex-grow:0;flex-shrink:0;flex-basis:16.66667%;max-width:16.66667%}.f-area-response.f-area-response--el .col-el-3{flex-grow:0;flex-shrink:0;flex-basis:25%;max-width:25%}.f-area-response.f-area-response--el .col-el-4{flex-grow:0;flex-shrink:0;flex-basis:33.33333%;max-width:33.33333%}.f-area-response.f-area-response--el .col-el-5{flex-grow:0;flex-shrink:0;flex-basis:41.66667%;max-width:41.66667%}.f-area-response.f-area-response--el .col-el-6{flex-grow:0;flex-shrink:0;flex-basis:50%;max-width:50%}.f-area-response.f-area-response--el .col-el-7{flex-grow:0;flex-shrink:0;flex-basis:58.33333%;max-width:58.33333%}.f-area-response.f-area-response--el .col-el-8{flex-grow:0;flex-shrink:0;flex-basis:66.66667%;max-width:66.66667%}.f-area-response.f-area-response--el .col-el-9{flex-grow:0;flex-shrink:0;flex-basis:75%;max-width:75%}.f-area-response.f-area-response--el .col-el-10{flex-grow:0;flex-shrink:0;flex-basis:83.33333%;max-width:83.33333%}.f-area-response.f-area-response--el .col-el-11{flex-grow:0;flex-shrink:0;flex-basis:91.66667%;max-width:91.66667%}.f-area-response.f-area-response--el .col-el-12{flex-grow:0;flex-shrink:0;flex-basis:100%;max-width:100%}.table{width:100%}.table td,.table th{padding:.75rem;vertical-align:top;border-top:1px solid #EAECF3}.table thead th{vertical-align:middle;border-bottom:2px solid #EAECF3}.table tbody+tbody{border-top:2px solid #EAECF3}.table-sm td,.table-sm th{padding:.3rem}.table-bordered,.table-bordered td,.table-bordered th{border:1px solid #EAECF3}.table-bordered thead td,.table-bordered thead th{border-bottom-width:2px}.table-borderless tbody+tbody,.table-borderless td,.table-borderless th,.table-borderless thead th{border:0}.table-striped tbody tr:nth-of-type(even){background-color:#F7F8FB}.table-hover tbody tr:hover{background-color:#EDF5FF}.table-primary,.table-primary>td,.table-primary>th{background-color:#c3ddff}.table-hover .table-primary:hover,.table-hover .table-primary:hover>td,.table-hover .table-primary:hover>th{background-color:#aacfff}.table-secondary,.table-secondary>td,.table-secondary>th{background-color:#d6d8db}.table-hover .table-secondary:hover,.table-hover .table-secondary:hover>td,.table-hover .table-secondary:hover>th{background-color:#c8cbcf}.table-success,.table-success>td,.table-success>th{background-color:#d6efdb}.table-hover .table-success:hover,.table-hover .table-success:hover>td,.table-hover .table-success:hover>th{background-color:#c4e8cb}.table-info,.table-info>td,.table-info>th{background-color:#d2e6ff}.table-hover .table-info:hover,.table-hover .table-info:hover>td,.table-hover .table-info:hover>th{background-color:#b9d8ff}.table-warning,.table-warning>td,.table-warning>th{background-color:#fce5cb}.table-hover .table-warning:hover,.table-hover .table-warning:hover>td,.table-hover .table-warning:hover>th{background-color:#fbd9b3}.table-danger,.table-danger>td,.table-danger>th{background-color:#f5c6cb}.table-hover .table-danger:hover,.table-hover .table-danger:hover>td,.table-hover .table-danger:hover>th{background-color:#f1b0b7}.table-light,.table-light>td,.table-light>th{background-color:#fdfdfe}.table-hover .table-light:hover,.table-hover .table-light:hover>td,.table-hover .table-light:hover>th{background-color:#ececf6}.table-dark,.table-dark>td,.table-dark>th{background-color:#c6c8ca}.table-hover .table-dark:hover,.table-hover .table-dark:hover>td,.table-hover .table-dark:hover>th{background-color:#b9bbbe}.table-active,.table-active>td,.table-active>th{background-color:#EDF5FF}.table-hover .table-active:hover,.table-hover .table-active:hover>td,.table-hover .table-active:hover>th{background-color:#d4e7ff}.table .thead-dark th{color:#fff;background-color:#212529;border-color:f-color-offset(#212529,7.5%,"lighten")}.table .thead-light th{color:#495057;background-color:#e9ecef;border-color:#EAECF3}.table-dark{color:#fff;background-color:#212529}.table-dark td,.table-dark th,.table-dark thead th{border-color:f-color-offset(#212529,7.5%,"lighten")}.table-dark.table-bordered,.table-responsive>.table-bordered{border:0}.table-dark.table-striped tbody tr:nth-of-type(odd){background-color:rgba(255,255,255,.05)}.table-dark.table-hover tbody tr:hover{background-color:rgba(255,255,255,.075)}@media (max-width:575.98px){.table-responsive-sm{display:block;width:100%;overflow-x:auto;-webkit-overflow-scrolling:touch;-ms-overflow-style:-ms-autohiding-scrollbar}.table-responsive-sm>.table-bordered{border:0}}@media (max-width:767.98px){.table-responsive-md{display:block;width:100%;overflow-x:auto;-webkit-overflow-scrolling:touch;-ms-overflow-style:-ms-autohiding-scrollbar}.table-responsive-md>.table-bordered{border:0}}@media (max-width:887.98px){.table-responsive-lg{display:block;width:100%;overflow-x:auto;-webkit-overflow-scrolling:touch;-ms-overflow-style:-ms-autohiding-scrollbar}.table-responsive-lg>.table-bordered{border:0}}@media (max-width:1199.98px){.table-responsive-xl{display:block;width:100%;overflow-x:auto;-webkit-overflow-scrolling:touch;-ms-overflow-style:-ms-autohiding-scrollbar}.table-responsive-xl>.table-bordered{border:0}}@media (max-width:1689.98px){.table-responsive-el{display:block;width:100%;overflow-x:auto;-webkit-overflow-scrolling:touch;-ms-overflow-style:-ms-autohiding-scrollbar}.table-responsive-el>.table-bordered{border:0}}.table-responsive{display:block;width:100%;overflow-x:auto;-webkit-overflow-scrolling:touch;-ms-overflow-style:-ms-autohiding-scrollbar}.form-control{display:block;width:100%;height:calc(1.5rem + .125rem);padding:.1875rem .5rem;line-height:1.4286;color:#2D2F33;background-color:#fff;background-clip:padding-box;border:1px solid #D8DCE6;border-radius:3px;box-shadow:0 0 0;transition:border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media screen and (prefers-reduced-motion:reduce){.form-control{transition:none}}.form-control::-ms-expand{background-color:transparent;border:0}.form-control:focus{color:#2D2F33;background-color:#fff;border-color:#529DFF;outline:0;box-shadow:0 0 0,0 0 4px 2px rgba(82,157,255,.12)}.form-control::-moz-placeholder{color:#B4BCCC;opacity:1}.form-control::placeholder{color:#B4BCCC;opacity:1}.form-control:disabled,.form-control[readonly]{background-color:#fff;opacity:1}select.form-control:focus::-ms-value{color:#2D2F33;background-color:#fff}.form-control-file,.form-control-range{display:block;width:100%}.col-form-label{padding-top:calc(.1875rem + 1px);padding-bottom:calc(.1875rem + 1px);margin-bottom:0;font-size:inherit;line-height:1.4286}.col-form-label-lg{padding-top:calc(.25rem + 1px);padding-bottom:calc(.25rem + 1px);font-size:.875rem;line-height:1.4286}.col-form-label-sm{padding-top:calc(.125rem + 1px);padding-bottom:calc(.125rem + 1px);font-size:.75rem;line-height:1.4286}.form-control-plaintext{display:block;width:100%;padding-top:.1875rem;padding-bottom:.1875rem;margin-bottom:0;line-height:1.4286;color:#000;background-color:transparent;border:solid transparent;border-width:1px 0}.form-control-lg,.form-control-sm{line-height:1.4286;border-radius:3px}.form-control-plaintext.form-control-lg,.form-control-plaintext.form-control-sm{padding-right:0;padding-left:0}.form-control-sm{height:calc(1.32145rem + 1px);padding:.125rem .4375rem;font-size:.75rem}.form-control-lg{height:calc(1.75003rem + 1px);padding:.25rem .3125rem;font-size:.875rem}select.form-control[multiple],select.form-control[size],textarea.form-control{height:auto}.form-group{margin-bottom:.375rem}.form-text{display:block;margin-top:.25rem}.form-row{display:flex;flex-wrap:wrap;margin-right:-.3125rem;margin-left:-.3125rem}.form-row>.col,.form-row>[class*=col-]{padding-right:.3125rem;padding-left:.3125rem}.form-check{position:relative;display:block;padding-left:1.25rem}.form-check-input{position:absolute;margin-top:.3rem;margin-left:-1.25rem}.form-check-input:disabled~.form-check-label{color:#A8ADB8}.form-check-label{margin-bottom:0}.form-check-inline{display:inline-flex;align-items:center;padding-left:0;margin-right:.75rem}.invalid-tooltip,.valid-tooltip{max-width:100%;padding:.5rem .625rem;line-height:1.4286;border-radius:3px;top:100%}.form-check-inline .form-check-input{position:static;margin-top:0;margin-right:.3125rem;margin-left:0}.valid-feedback{display:none;width:100%;margin-top:.25rem;font-size:80%;color:#6CC77F}.valid-tooltip{position:absolute;z-index:5;display:none;margin-top:.1rem;font-size:.75rem;color:#212529;background-color:#6cc77f}.custom-control-input.is-valid~.valid-feedback,.custom-control-input.is-valid~.valid-tooltip,.custom-file-input.is-valid~.valid-feedback,.custom-file-input.is-valid~.valid-tooltip,.custom-select.is-valid~.valid-feedback,.custom-select.is-valid~.valid-tooltip,.form-check-input.is-valid~.valid-feedback,.form-check-input.is-valid~.valid-tooltip,.form-control-file.is-valid~.valid-feedback,.form-control-file.is-valid~.valid-tooltip,.form-control.is-valid~.valid-feedback,.form-control.is-valid~.valid-tooltip,.was-validated .custom-control-input:valid~.valid-feedback,.was-validated .custom-control-input:valid~.valid-tooltip,.was-validated .custom-file-input:valid~.valid-feedback,.was-validated .custom-file-input:valid~.valid-tooltip,.was-validated .custom-select:valid~.valid-feedback,.was-validated .custom-select:valid~.valid-tooltip,.was-validated .form-check-input:valid~.valid-feedback,.was-validated .form-check-input:valid~.valid-tooltip,.was-validated .form-control-file:valid~.valid-feedback,.was-validated .form-control-file:valid~.valid-tooltip,.was-validated .form-control:valid~.valid-feedback,.was-validated .form-control:valid~.valid-tooltip{display:block}.custom-control-input.is-valid~.custom-control-label,.form-check-input.is-valid~.form-check-label,.was-validated .custom-control-input:valid~.custom-control-label,.was-validated .form-check-input:valid~.form-check-label{color:#6CC77F}.custom-select.is-valid,.form-control.is-valid,.was-validated .custom-select:valid,.was-validated .form-control:valid{border-color:#6CC77F}.custom-select.is-valid:focus,.form-control.is-valid:focus,.was-validated .custom-select:valid:focus,.was-validated .form-control:valid:focus{border-color:#6CC77F;box-shadow:0 0 0 .2rem rgba(108,199,127,.25)}.custom-control-input.is-valid~.custom-control-label::before,.was-validated .custom-control-input:valid~.custom-control-label::before{background-color:#c8eacf}.custom-control-input.is-valid:checked~.custom-control-label::before,.was-validated .custom-control-input:valid:checked~.custom-control-label::before{background-color:#91d59f}.custom-control-input.is-valid:focus~.custom-control-label::before,.was-validated .custom-control-input:valid:focus~.custom-control-label::before{box-shadow:0 0 0 1px #fff,0 0 0 .2rem rgba(108,199,127,.25)}.custom-file-input.is-valid~.custom-file-label,.was-validated .custom-file-input:valid~.custom-file-label{border-color:#6CC77F}.custom-file-input.is-valid~.custom-file-label::after,.was-validated .custom-file-input:valid~.custom-file-label::after{border-color:inherit}.custom-file-input.is-valid:focus~.custom-file-label,.was-validated .custom-file-input:valid:focus~.custom-file-label{box-shadow:0 0 0 .2rem rgba(108,199,127,.25)}.invalid-feedback{display:none;width:100%;margin-top:.25rem;font-size:80%;color:#dc3545}.invalid-tooltip{position:absolute;z-index:5;display:none;margin-top:.1rem;font-size:.75rem;color:#fff;background-color:#dc3545}.collapsing,.dropdown,.dropdown-left,.dropleft,.dropleft-up,.dropright,.dropright-up,.dropup,.dropup-left{position:relative}.custom-control-input.is-invalid~.invalid-feedback,.custom-control-input.is-invalid~.invalid-tooltip,.custom-file-input.is-invalid~.invalid-feedback,.custom-file-input.is-invalid~.invalid-tooltip,.custom-select.is-invalid~.invalid-feedback,.custom-select.is-invalid~.invalid-tooltip,.form-check-input.is-invalid~.invalid-feedback,.form-check-input.is-invalid~.invalid-tooltip,.form-control-file.is-invalid~.invalid-feedback,.form-control-file.is-invalid~.invalid-tooltip,.form-control.is-invalid~.invalid-feedback,.form-control.is-invalid~.invalid-tooltip,.was-validated .custom-control-input:invalid~.invalid-feedback,.was-validated .custom-control-input:invalid~.invalid-tooltip,.was-validated .custom-file-input:invalid~.invalid-feedback,.was-validated .custom-file-input:invalid~.invalid-tooltip,.was-validated .custom-select:invalid~.invalid-feedback,.was-validated .custom-select:invalid~.invalid-tooltip,.was-validated .form-check-input:invalid~.invalid-feedback,.was-validated .form-check-input:invalid~.invalid-tooltip,.was-validated .form-control-file:invalid~.invalid-feedback,.was-validated .form-control-file:invalid~.invalid-tooltip,.was-validated .form-control:invalid~.invalid-feedback,.was-validated .form-control:invalid~.invalid-tooltip{display:block}.custom-control-input.is-invalid~.custom-control-label,.form-check-input.is-invalid~.form-check-label,.was-validated .custom-control-input:invalid~.custom-control-label,.was-validated .form-check-input:invalid~.form-check-label{color:#dc3545}.custom-select.is-invalid,.form-control.is-invalid,.was-validated .custom-select:invalid,.was-validated .form-control:invalid{border-color:#dc3545}.custom-select.is-invalid:focus,.form-control.is-invalid:focus,.was-validated .custom-select:invalid:focus,.was-validated .form-control:invalid:focus{border-color:#dc3545;box-shadow:0 0 0 .2rem rgba(220,53,69,.25)}.custom-control-input.is-invalid~.custom-control-label::before,.was-validated .custom-control-input:invalid~.custom-control-label::before{background-color:#efa2a9}.custom-control-input.is-invalid:checked~.custom-control-label::before,.was-validated .custom-control-input:invalid:checked~.custom-control-label::before{background-color:#e4606d}.custom-control-input.is-invalid:focus~.custom-control-label::before,.was-validated .custom-control-input:invalid:focus~.custom-control-label::before{box-shadow:0 0 0 1px #fff,0 0 0 .2rem rgba(220,53,69,.25)}.custom-file-input.is-invalid~.custom-file-label,.was-validated .custom-file-input:invalid~.custom-file-label{border-color:#dc3545}.custom-file-input.is-invalid~.custom-file-label::after,.was-validated .custom-file-input:invalid~.custom-file-label::after{border-color:inherit}.custom-file-input.is-invalid:focus~.custom-file-label,.was-validated .custom-file-input:invalid:focus~.custom-file-label{box-shadow:0 0 0 .2rem rgba(220,53,69,.25)}.form-inline{display:flex;flex-flow:row wrap;align-items:center}.form-inline .form-check{width:100%}@media (min-width:576px){.form-inline label{display:flex;align-items:center;justify-content:center;margin-bottom:0}.form-inline .form-group{display:flex;flex-grow:0;flex-shrink:0;flex-basis:auto;flex-flow:row wrap;align-items:center;margin-bottom:0}.form-inline .form-control{display:inline-block;width:auto;vertical-align:middle}.form-inline .form-control-plaintext{display:inline-block}.form-inline .custom-select,.form-inline .input-group{width:auto}.form-inline .form-check{display:flex;align-items:center;justify-content:center;width:auto;padding-left:0}.form-inline .form-check-input{position:relative;margin-top:0;margin-right:.25rem;margin-left:0}.form-inline .custom-control{align-items:center;justify-content:center}.form-inline .custom-control-label{margin-bottom:0}}.fade{transition:opacity .15s linear}@media screen and (prefers-reduced-motion:reduce){.fade{transition:none}}.fade:not(.show){opacity:0}.collapse:not(.show){display:none}.collapsing{height:0;transition:height .35s ease}@media screen and (prefers-reduced-motion:reduce){.collapsing{transition:none}}.dropdown-toggle::after{display:inline-block;width:0;height:0;margin-left:.125rem;vertical-align:.125rem;content:"";border-top:.25rem solid;border-right:.25rem solid transparent;border-bottom:0;border-left:.25rem solid transparent}.dropdown-toggle:empty::after{margin-left:0}.dropdown-menu{position:absolute;top:100%;left:0;z-index:300;display:none;float:left;min-width:10rem;padding:.25rem;margin:.25rem 0 0;color:#2D2F33;background-color:#fff;background-clip:padding-box;border:0 solid rgba(0,0,0,.15);border-radius:3px;box-shadow:0 2px 8px 0 rgba(0,0,0,.15)}.dropup .dropdown-toggle::after,.dropup-left .dropdown-toggle::after{display:inline-block;width:0;height:0;vertical-align:.125rem;content:"";border-top:0;border-right:.25rem solid transparent;border-bottom:.25rem solid;border-left:.25rem solid transparent}.dropdown-menu-right{right:0;left:auto}.dropup .dropdown-menu{top:auto;bottom:100%;margin-top:0;margin-bottom:.25rem}.dropup .dropdown-toggle::after{margin-left:.125rem}.dropup .dropdown-toggle:empty::after{margin-left:0}.dropup-left .dropdown-menu{top:auto;right:0;left:auto;bottom:100%;margin-top:0;margin-bottom:.25rem}.dropup-left .dropdown-toggle::after{margin-left:.125rem}.dropright .dropdown-toggle::after,.dropright-up .dropdown-toggle::after{display:inline-block;width:0;height:0;content:"";border-top:.25rem solid transparent;border-right:0;border-left:.25rem solid;vertical-align:0}.dropup-left .dropdown-toggle:empty::after{margin-left:0}.dropright .dropdown-menu{top:0;right:auto;left:100%;margin-top:0;margin-left:.25rem}.dropright .dropdown-toggle::after{margin-left:.125rem;border-bottom:.25rem solid transparent}.dropright .dropdown-toggle:empty::after{margin-left:0}.dropright-up .dropdown-menu{top:auto;right:auto;left:100%;bottom:0;margin-top:0;margin-left:.25rem}.dropright-up .dropdown-toggle::after{margin-left:.125rem;border-bottom:.25rem solid transparent}.dropleft .dropdown-toggle::before,.dropleft-up .dropdown-toggle::before{width:0;content:"";border-top:.25rem solid transparent;border-right:.25rem solid;border-bottom:.25rem solid transparent;height:0}.dropright-up .dropdown-toggle:empty::after{margin-left:0}.dropleft-up .dropdown-menu{top:auto;right:100%;left:auto;bottom:0;margin-top:0;margin-bottom:.25rem}.dropleft-up .dropdown-toggle::after{width:0;height:0;margin-left:.125rem;vertical-align:.125rem;content:"";display:none}.dropleft-up .dropdown-toggle::before{display:inline-block;margin-right:.125rem;vertical-align:0}.dropleft-up .dropdown-toggle:empty::after{margin-left:0}.dropleft .dropdown-menu{top:0;right:100%;left:auto;margin-top:0;margin-right:.25rem}.dropleft .dropdown-toggle::after{width:0;height:0;margin-left:.125rem;vertical-align:.125rem;content:"";display:none}.dropleft .dropdown-toggle::before{display:inline-block;margin-right:.125rem;vertical-align:0}.dropleft .dropdown-toggle:empty::after{margin-left:0}.dropdown-menu[x-placement^=top],.dropdown-menu[x-placement^=right],.dropdown-menu[x-placement^=bottom],.dropdown-menu[x-placement^=left]{right:auto;bottom:auto}.dropdown-divider{height:0;margin:null 0;border-top:1px solid #E6E9F0}.dropdown-item{display:block;line-height:1.25rem;padding:.25rem .5rem;clear:both;font-weight:400;color:#5A5E66;text-align:inherit;white-space:nowrap;background-color:transparent;border:0;border-radius:3px}.btn-group>.btn-group:not(:last-child)>.btn,.btn-group>.btn:not(:last-child):not(.dropdown-toggle),.input-group>.custom-file:not(:last-child) .custom-file-label,.input-group>.custom-file:not(:last-child) .custom-file-label::after,.input-group>.custom-select:not(:last-child),.input-group>.form-control:not(:last-child){border-top-right-radius:0;border-bottom-right-radius:0}.btn-group>.btn-group:not(:first-child)>.btn,.btn-group>.btn:not(:first-child),.input-group>.custom-file:not(:first-child) .custom-file-label,.input-group>.custom-select:not(:first-child),.input-group>.form-control:not(:first-child){border-top-left-radius:0;border-bottom-left-radius:0}.dropdown-item:focus,.dropdown-item:hover{color:#2D2F33;text-decoration:none;background-color:#EDF5FF}.dropdown-item.active,.dropdown-item:active{color:#2D2F33;text-decoration:none;background-color:#DAE9FF}.dropdown-item.disabled,.dropdown-item:disabled{color:#B4BCCC;background-color:transparent;cursor:default}.dropdown-menu.show{display:block}.dropdown-header{display:block;padding:.25rem .5rem;margin-bottom:0;font-size:.75rem;color:#6c757d;white-space:nowrap}.dropdown-item-text{display:block;padding:.25rem .5rem;color:#5A5E66}.btn-group,.btn-group-vertical{position:relative;display:inline-flex;vertical-align:middle}.btn-group-vertical>.btn,.btn-group>.btn{position:relative;flex-grow:0;flex-shrink:1;flex-basis:auto}.btn-group-vertical>.btn.active,.btn-group-vertical>.btn:active,.btn-group-vertical>.btn:focus,.btn-group-vertical>.btn:hover,.btn-group>.btn.active,.btn-group>.btn:active,.btn-group>.btn:focus,.btn-group>.btn:hover{z-index:1}.btn-group .btn+.btn,.btn-group .btn+.btn-group,.btn-group .btn-group+.btn,.btn-group .btn-group+.btn-group,.btn-group-vertical .btn+.btn,.btn-group-vertical .btn+.btn-group,.btn-group-vertical .btn-group+.btn,.btn-group-vertical .btn-group+.btn-group{margin-left:-1px}.btn-toolbar{display:flex;flex-wrap:wrap;justify-content:flex-start}.btn-toolbar .input-group{width:auto}.btn-group>.btn:first-child{margin-left:0}.dropdown-toggle-split{padding-right:.65625rem;padding-left:.65625rem}.dropdown-toggle-split::after,.dropright .dropdown-toggle-split::after,.dropright-top .dropdown-toggle-split::after,.dropup .dropdown-toggle-split::after,.dropup-left .dropdown-toggle-split::after{margin-left:0}.dropleft .dropdown-toggle-split::before,.dropleft-up .dropdown-toggle-split::before{margin-right:0}.btn-group-sm>.btn+.dropdown-toggle-split,.btn-sm+.dropdown-toggle-split{padding-right:.375rem;padding-left:.375rem}.btn-group-lg>.btn+.dropdown-toggle-split,.btn-lg+.dropdown-toggle-split{padding-right:.84375rem;padding-left:.84375rem}.btn-group.show .dropdown-toggle{box-shadow:0 1px 0 0 rgba(31,35,41,.12)}.btn-group.show .dropdown-toggle.btn-link{box-shadow:none}.btn-group-vertical{flex-direction:column;align-items:flex-start;justify-content:center}.input-group,.nav,.navbar{flex-wrap:wrap}.btn-group-vertical .btn,.btn-group-vertical .btn-group{width:100%}.btn-group-vertical>.btn+.btn,.btn-group-vertical>.btn+.btn-group,.btn-group-vertical>.btn-group+.btn,.btn-group-vertical>.btn-group+.btn-group{margin-top:-1px;margin-left:0}.input-group-append,.input-group-append .btn+.btn,.input-group-append .btn+.input-group-text,.input-group-append .input-group-text+.btn,.input-group-append .input-group-text+.input-group-text,.input-group-prepend .btn+.btn,.input-group-prepend .btn+.input-group-text,.input-group-prepend .input-group-text+.btn,.input-group-prepend .input-group-text+.input-group-text,.input-group>.custom-file+.custom-file,.input-group>.custom-file+.custom-select,.input-group>.custom-file+.form-control,.input-group>.custom-select+.custom-file,.input-group>.custom-select+.custom-select,.input-group>.custom-select+.form-control,.input-group>.form-control+.custom-file,.input-group>.form-control+.custom-select,.input-group>.form-control+.form-control,.page-link{margin-left:-1px}.btn-group-vertical>.btn-group:not(:last-child)>.btn,.btn-group-vertical>.btn:not(:last-child):not(.dropdown-toggle){border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn-group:not(:first-child)>.btn,.btn-group-vertical>.btn:not(:first-child){border-top-left-radius:0;border-top-right-radius:0}.btn-group-toggle>.btn,.btn-group-toggle>.btn-group>.btn{margin-bottom:0}.btn-group-toggle>.btn input[type=radio],.btn-group-toggle>.btn input[type=checkbox],.btn-group-toggle>.btn-group>.btn input[type=radio],.btn-group-toggle>.btn-group>.btn input[type=checkbox]{position:absolute;clip:rect(0,0,0,0);pointer-events:none}.input-group{position:relative;display:flex;align-items:stretch;width:100%}.input-group>.custom-file,.input-group>.custom-select,.input-group>.form-control{position:relative;flex-grow:1;flex-shrink:1;flex-basis:0;width:1%;margin-bottom:0}.input-group>.custom-file .custom-file-input:focus~.custom-file-label,.input-group>.custom-select:focus,.input-group>.form-control:focus{z-index:3}.input-group>.custom-file .custom-file-input:focus{z-index:4}.input-group>.custom-file{display:flex;align-items:center}.input-group-append,.input-group-prepend{display:flex}.input-group-append .btn,.input-group-prepend .btn{position:relative;z-index:2}.input-group-prepend{margin-right:-1px}.input-group-text{display:flex;align-items:center;padding:.1875rem .5rem;margin-bottom:0;font-size:.8125rem;font-weight:400;line-height:1.4286;color:#2D2F33;text-align:center;white-space:nowrap;background-color:#e9ecef;border:1px solid #D8DCE6;border-radius:3px}.input-group-text input[type=radio],.input-group-text input[type=checkbox]{margin-top:0}.input-group-lg>.form-control,.input-group-lg>.input-group-append>.btn,.input-group-lg>.input-group-append>.input-group-text,.input-group-lg>.input-group-prepend>.btn,.input-group-lg>.input-group-prepend>.input-group-text{height:calc(1.75003rem + 1px);padding:.25rem .3125rem;font-size:.875rem;line-height:1.4286;border-radius:3px}.input-group-sm>.form-control,.input-group-sm>.input-group-append>.btn,.input-group-sm>.input-group-append>.input-group-text,.input-group-sm>.input-group-prepend>.btn,.input-group-sm>.input-group-prepend>.input-group-text{height:calc(1.32145rem + 1px);padding:.125rem .4375rem;font-size:.75rem;line-height:1.4286;border-radius:3px}.input-group>.input-group-append:last-child>.btn:not(:last-child):not(.dropdown-toggle),.input-group>.input-group-append:last-child>.input-group-text:not(:last-child),.input-group>.input-group-append:not(:last-child)>.btn,.input-group>.input-group-append:not(:last-child)>.input-group-text,.input-group>.input-group-prepend>.btn,.input-group>.input-group-prepend>.input-group-text{border-top-right-radius:0;border-bottom-right-radius:0}.input-group>.input-group-append>.btn,.input-group>.input-group-append>.input-group-text,.input-group>.input-group-prepend:first-child>.btn:not(:first-child),.input-group>.input-group-prepend:first-child>.input-group-text:not(:first-child),.input-group>.input-group-prepend:not(:first-child)>.btn,.input-group>.input-group-prepend:not(:first-child)>.input-group-text{border-top-left-radius:0;border-bottom-left-radius:0}.custom-control{position:relative;display:block;min-height:1.16074rem;padding-left:1.5rem}.custom-control-inline{display:inline-flex;margin-right:1rem}.custom-control-input{position:absolute;z-index:-1;opacity:0}.custom-control-input:checked~.custom-control-label::before{color:#2A87FF;background-color:#fff;box-shadow:none}.custom-control-input:focus~.custom-control-label::before{box-shadow:0 0 0 1px #fff,0 0 4px 2px rgba(82,157,255,.12);color:#2A87FF}.custom-control-input:active~.custom-control-label::before{color:#fff;background-color:f-color-offset(#2A87FF,35%,"lighten");box-shadow:none}.custom-checkbox .custom-control-input:checked~.custom-control-label::before,.custom-checkbox .custom-control-input:disabled:checked~.custom-control-label::before,.custom-checkbox .custom-control-input:disabled:indeterminate~.custom-control-label::before,.custom-control-input:disabled~.custom-control-label::before,.custom-control-label::before,.custom-radio .custom-control-input:checked~.custom-control-label::before,.custom-radio .custom-control-input:disabled:checked~.custom-control-label::before{background-color:#fff}.custom-control-input:disabled~.custom-control-label{color:#E6E9F0}.custom-control-label{position:relative;margin-bottom:0}.custom-control-label::after,.custom-control-label::before{position:absolute;top:.08037rem;left:-1.5rem;display:block;width:1rem;height:1rem;content:""}.custom-control-label::before{pointer-events:none;-webkit-user-select:none;-moz-user-select:none;user-select:none;box-shadow:0 0 0}.custom-control-label::after{background-repeat:no-repeat;background-position:center center;background-size:50% 50%}.custom-checkbox .custom-control-label::before{border-radius:3px}.custom-checkbox .custom-control-input:checked~.custom-control-label::after{background-image:none}.custom-checkbox .custom-control-input:indeterminate~.custom-control-label::before{box-shadow:none}.custom-checkbox .custom-control-input:indeterminate~.custom-control-label::after{background-image:none}.custom-radio .custom-control-label::before{border-radius:50%}.custom-radio .custom-control-input:checked~.custom-control-label::after{background-image:none}.custom-select{display:inline-block;width:100%;height:calc(1.5rem + .125rem);padding:.1875rem 1.5rem .1875rem .5rem;line-height:1.4286;color:#2D2F33;vertical-align:middle;background:f-str-replace(url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 4 5'%3E%3Cpath fill='#343a40' d='M2 0L0 2h4zm0 5L0 3h4z'/%3E%3C/svg%3E") ,"#","%23") right .5rem center no-repeat #fff;background-size:.5rem .625rem;border:1px solid #D8DCE6;border-radius:3px;box-shadow:0 0 0;-webkit-appearance:none;-moz-appearance:none;appearance:none}.custom-select-lg,.custom-select-sm{padding-top:.1875rem;padding-bottom:.1875rem}.custom-select:focus{border-color:#529DFF;outline:0;box-shadow:0 0 0,0 0 4px 2px rgba(82,157,255,.12)}.custom-select:focus::-ms-value{color:#2D2F33;background-color:#fff}.custom-select[multiple],.custom-select[size]:not([size="1"]){height:auto;padding-right:.5rem;background-image:none}.custom-select:disabled{color:#6c757d;background-color:#e9ecef}.custom-file-input:disabled~.custom-file-label,.custom-file-label{background-color:#fff}.custom-select::-ms-expand{opacity:0}.custom-select-sm{height:calc(1.32145rem + 1px);font-size:75%}.custom-select-lg{height:calc(1.75003rem + 1px);font-size:125%}.custom-file,.custom-file-input,.custom-file-label{height:calc(1.5rem + .125rem)}.custom-file-label,.custom-file-label::after{padding:.1875rem .5rem;color:#2D2F33;right:0;line-height:1.4286}.custom-file{position:relative;display:inline-block;width:100%;margin-bottom:0}.custom-file-input{position:relative;z-index:2;width:100%;margin:0;opacity:0}.custom-file-input:focus~.custom-file-label{border-color:#529DFF;box-shadow:0 0 4px 2px rgba(82,157,255,.12)}.custom-file-input:focus~.custom-file-label::after{border-color:#529DFF}.custom-file-input:lang(en)~.custom-file-label::after{content:"Browse"}.custom-file-label{position:absolute;top:0;left:0;z-index:1;border:1px solid #D8DCE6;border-radius:3px;box-shadow:0 0 0}.custom-file-label::after{position:absolute;top:0;bottom:0;z-index:3;display:block;height:1.5rem;content:"Browse";background-color:#e9ecef;border-left:1px solid #D8DCE6;border-radius:0 3px 3px 0}.custom-range{width:100%;padding-left:0;background-color:transparent;-webkit-appearance:none;-moz-appearance:none;appearance:none}.custom-range:focus{outline:0}.custom-range:focus::-webkit-slider-thumb{box-shadow:0 0 0 1px #fff,0 0 4px 2px rgba(82,157,255,.12)}.custom-range:focus::-moz-range-thumb{box-shadow:0 0 0 1px #fff,0 0 4px 2px rgba(82,157,255,.12)}.custom-range:focus::-ms-thumb{box-shadow:0 0 0 1px #fff,0 0 4px 2px rgba(82,157,255,.12)}.custom-range::-moz-focus-outer{border:0}.custom-range::-webkit-slider-thumb{width:1rem;height:1rem;margin-top:-.25rem;background-color:#2A87FF;border:0;border-radius:1rem;box-shadow:0 .1rem .25rem rgba(0,0,0,.1);-webkit-transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;-webkit-appearance:none;appearance:none}@media screen and (prefers-reduced-motion:reduce){.custom-range::-webkit-slider-thumb{-webkit-transition:none;transition:none}}.custom-range::-webkit-slider-thumb:active{background-color:f-color-offset(#2A87FF,35%,"lighten")}.custom-range::-webkit-slider-runnable-track{width:100%;height:.5rem;color:transparent;cursor:pointer;background-color:#dee2e6;border-color:transparent;border-radius:1rem;box-shadow:inset 0 .25rem .25rem rgba(0,0,0,.1)}.custom-range::-moz-range-thumb{width:1rem;height:1rem;background-color:#2A87FF;border:0;border-radius:1rem;box-shadow:0 .1rem .25rem rgba(0,0,0,.1);-moz-transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;-moz-appearance:none;appearance:none}@media screen and (prefers-reduced-motion:reduce){.custom-range::-moz-range-thumb{-moz-transition:none;transition:none}}.custom-range::-moz-range-thumb:active{background-color:f-color-offset(#2A87FF,35%,"lighten")}.custom-range::-moz-range-track{width:100%;height:.5rem;color:transparent;cursor:pointer;background-color:#dee2e6;border-color:transparent;border-radius:1rem;box-shadow:inset 0 .25rem .25rem rgba(0,0,0,.1)}.custom-range::-ms-thumb{width:1rem;height:1rem;margin-top:0;margin-right:.2rem;margin-left:.2rem;background-color:#2A87FF;border:0;border-radius:1rem;box-shadow:0 .1rem .25rem rgba(0,0,0,.1);-ms-transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;appearance:none}@media screen and (prefers-reduced-motion:reduce){.custom-range::-ms-thumb{-ms-transition:none;transition:none}}.custom-range::-ms-thumb:active{background-color:f-color-offset(#2A87FF,35%,"lighten")}.custom-range::-ms-track{width:100%;height:.5rem;color:transparent;cursor:pointer;background-color:transparent;border-color:transparent;border-width:.5rem;box-shadow:inset 0 .25rem .25rem rgba(0,0,0,.1)}.custom-range::-ms-fill-lower{background-color:#dee2e6;border-radius:1rem}.custom-range::-ms-fill-upper{margin-right:.9375rem;background-color:#dee2e6;border-radius:1rem}.custom-control-label::before,.custom-file-label,.custom-select{transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media screen and (prefers-reduced-motion:reduce){.custom-control-label::before,.custom-file-label,.custom-select{transition:none}}.nav{display:flex;padding-left:0;margin-bottom:0;list-style:none}.nav-link,.navbar{padding:.5rem 1rem}.nav-link{display:block}.nav-link:focus,.nav-link:hover{text-decoration:none}.nav-link.disabled{color:#6c757d}.nav-tabs{border-bottom:1px solid #dee2e6}.nav-tabs .nav-item{margin-bottom:-1px}.nav-tabs .nav-link{border:1px solid transparent;border-top-left-radius:3px;border-top-right-radius:3px}.nav-tabs .nav-link:focus,.nav-tabs .nav-link:hover{border-color:#e9ecef #e9ecef #dee2e6}.nav-tabs .nav-link.disabled{color:#6c757d;background-color:transparent;border-color:transparent}.nav-tabs .nav-item.show .nav-link,.nav-tabs .nav-link.active{color:#495057;background-color:#fff;border-color:#dee2e6 #dee2e6 #fff}.nav-tabs .dropdown-menu{margin-top:-1px;border-top-left-radius:0;border-top-right-radius:0}.nav-pills .nav-link{border-radius:3px}.nav-pills .nav-link.active,.nav-pills .show>.nav-link{color:#fff;background:#2A87FF}.nav-fill .nav-item{flex-grow:1;flex-shrink:1;flex-basis:auto;text-align:center}.nav-justified .nav-item{flex-basis:0;flex-grow:1;text-align:center}.tab-content>.tab-pane{display:none}.tab-content>.active{display:block}.navbar{position:relative;display:flex;align-items:center;justify-content:space-between}.navbar>.container,.navbar>.container-fluid{display:flex;flex-wrap:wrap;align-items:center;justify-content:space-between}.navbar-brand{display:inline-block;padding-top:.45536rem;padding-bottom:.45536rem;margin-right:1rem;font-size:.875rem;line-height:inherit;white-space:nowrap}.navbar-brand:focus,.navbar-brand:hover{text-decoration:none}.navbar-nav{display:flex;flex-direction:column;padding-left:0;margin-bottom:0;list-style:none}.navbar-nav .nav-link{padding-right:0;padding-left:0}.navbar-nav .dropdown-menu{position:static;float:none}.navbar-text{display:inline-block;padding-top:.5rem;padding-bottom:.5rem}.navbar-collapse{flex-basis:100%;flex-grow:1;align-items:center}.navbar-toggler{padding:.25rem .75rem;font-size:.875rem;line-height:1;background-color:transparent;border:1px solid transparent;border-radius:3px}.navbar-toggler:focus,.navbar-toggler:hover{text-decoration:none}.navbar-toggler-icon{display:inline-block;width:1.5em;height:1.5em;vertical-align:middle;content:"";background:center center no-repeat;background-size:100% 100%}@media (max-width:575.98px){.navbar-expand-sm>.container,.navbar-expand-sm>.container-fluid{padding-right:0;padding-left:0}}@media (min-width:576px){.navbar-expand-sm{flex-flow:row nowrap;justify-content:flex-start}.navbar-expand-sm .navbar-nav{flex-direction:row}.navbar-expand-sm .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-sm .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand-sm>.container,.navbar-expand-sm>.container-fluid{flex-wrap:nowrap}.navbar-expand-sm .navbar-collapse{display:flex!important;flex-basis:auto}.navbar-expand-sm .navbar-toggler{display:none}}@media (max-width:767.98px){.navbar-expand-md>.container,.navbar-expand-md>.container-fluid{padding-right:0;padding-left:0}}@media (min-width:768px){.navbar-expand-md{flex-flow:row nowrap;justify-content:flex-start}.navbar-expand-md .navbar-nav{flex-direction:row}.navbar-expand-md .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-md .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand-md>.container,.navbar-expand-md>.container-fluid{flex-wrap:nowrap}.navbar-expand-md .navbar-collapse{display:flex!important;flex-basis:auto}.navbar-expand-md .navbar-toggler{display:none}}@media (max-width:887.98px){.navbar-expand-lg>.container,.navbar-expand-lg>.container-fluid{padding-right:0;padding-left:0}}@media (min-width:888px){.navbar-expand-lg{flex-flow:row nowrap;justify-content:flex-start}.navbar-expand-lg .navbar-nav{flex-direction:row}.navbar-expand-lg .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-lg .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand-lg>.container,.navbar-expand-lg>.container-fluid{flex-wrap:nowrap}.navbar-expand-lg .navbar-collapse{display:flex!important;flex-basis:auto}.navbar-expand-lg .navbar-toggler{display:none}}@media (max-width:1199.98px){.navbar-expand-xl>.container,.navbar-expand-xl>.container-fluid{padding-right:0;padding-left:0}}@media (min-width:1200px){.navbar-expand-xl{flex-flow:row nowrap;justify-content:flex-start}.navbar-expand-xl .navbar-nav{flex-direction:row}.navbar-expand-xl .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-xl .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand-xl>.container,.navbar-expand-xl>.container-fluid{flex-wrap:nowrap}.navbar-expand-xl .navbar-collapse{display:flex!important;flex-basis:auto}.navbar-expand-xl .navbar-toggler{display:none}}@media (max-width:1689.98px){.navbar-expand-el>.container,.navbar-expand-el>.container-fluid{padding-right:0;padding-left:0}}@media (min-width:1690px){.navbar-expand-el{flex-flow:row nowrap;justify-content:flex-start}.navbar-expand-el .navbar-nav{flex-direction:row}.navbar-expand-el .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-el .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand-el>.container,.navbar-expand-el>.container-fluid{flex-wrap:nowrap}.navbar-expand-el .navbar-collapse{display:flex!important;flex-basis:auto}.navbar-expand-el .navbar-toggler{display:none}}.navbar-expand{flex-flow:row nowrap;justify-content:flex-start}.navbar-expand>.container,.navbar-expand>.container-fluid{padding-right:0;padding-left:0}.navbar-expand .navbar-nav{flex-direction:row}.navbar-expand .navbar-nav .dropdown-menu{position:absolute}.navbar-expand .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand>.container,.navbar-expand>.container-fluid{flex-wrap:nowrap}.navbar-expand .navbar-collapse{display:flex!important;flex-basis:auto}.modal,.navbar-expand .navbar-toggler{display:none}.navbar-light .navbar-brand,.navbar-light .navbar-brand:focus,.navbar-light .navbar-brand:hover{color:rgba(0,0,0,.9)}.navbar-light .navbar-nav .nav-link{color:rgba(0,0,0,.5)}.navbar-light .navbar-nav .nav-link:focus,.navbar-light .navbar-nav .nav-link:hover{color:rgba(0,0,0,.7)}.navbar-light .navbar-nav .nav-link.disabled{color:rgba(0,0,0,.3)}.navbar-light .navbar-nav .active>.nav-link,.navbar-light .navbar-nav .nav-link.active,.navbar-light .navbar-nav .nav-link.show,.navbar-light .navbar-nav .show>.nav-link{color:rgba(0,0,0,.9)}.navbar-light .navbar-toggler{color:rgba(0,0,0,.5);border-color:rgba(0,0,0,.1)}.navbar-light .navbar-toggler-icon{background-image:f-str-replace(url("data:image/svg+xml;charset=utf8,%3Csvg viewBox='0 0 30 30' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath stroke='rgba(0, 0, 0, 0.5)' stroke-width='2' stroke-linecap='round' stroke-miterlimit='10' d='M4 7h22M4 15h22M4 23h22'/%3E%3C/svg%3E") ,"#","%23")}.navbar-light .navbar-text{color:rgba(0,0,0,.5)}.navbar-light .navbar-text a,.navbar-light .navbar-text a:focus,.navbar-light .navbar-text a:hover{color:rgba(0,0,0,.9)}.navbar-dark .navbar-brand,.navbar-dark .navbar-brand:focus,.navbar-dark .navbar-brand:hover{color:#fff}.navbar-dark .navbar-nav .nav-link{color:rgba(255,255,255,.5)}.navbar-dark .navbar-nav .nav-link:focus,.navbar-dark .navbar-nav .nav-link:hover{color:rgba(255,255,255,.75)}.navbar-dark .navbar-nav .nav-link.disabled{color:rgba(255,255,255,.25)}.navbar-dark .navbar-nav .active>.nav-link,.navbar-dark .navbar-nav .nav-link.active,.navbar-dark .navbar-nav .nav-link.show,.navbar-dark .navbar-nav .show>.nav-link{color:#fff}.navbar-dark .navbar-toggler{color:rgba(255,255,255,.5);border-color:rgba(255,255,255,.1)}.navbar-dark .navbar-toggler-icon{background-image:f-str-replace(url("data:image/svg+xml;charset=utf8,%3Csvg viewBox='0 0 30 30' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath stroke='rgba(255, 255, 255, 0.5)' stroke-width='2' stroke-linecap='round' stroke-miterlimit='10' d='M4 7h22M4 15h22M4 23h22'/%3E%3C/svg%3E") ,"#","%23")}.navbar-dark .navbar-text{color:rgba(255,255,255,.5)}.navbar-dark .navbar-text a,.navbar-dark .navbar-text a:focus,.navbar-dark .navbar-text a:hover{color:#fff}.card{position:relative;display:flex;flex-direction:column;min-width:0;word-wrap:break-word;background-color:#fff;background-clip:border-box;border:1px solid rgba(0,0,0,.125);border-radius:3px}.card>hr{margin-right:0;margin-left:0}.card>.list-group:first-child .list-group-item:first-child{border-top-left-radius:3px;border-top-right-radius:3px}.card>.list-group:last-child .list-group-item:last-child{border-bottom-right-radius:3px;border-bottom-left-radius:3px}.card-body{flex-grow:1;flex-shrink:1;flex-basis:auto;padding:1.25rem}.card-footer,.card-header{padding:.75rem 1.25rem;background-color:rgba(0,0,0,.03)}.card-title{margin-bottom:.75rem}.card-header,.card-subtitle,.card-text:last-child{margin-bottom:0}.card-subtitle{margin-top:-.375rem}.card-link:hover{text-decoration:none}.card-link+.card-link{margin-left:1.25rem}.card-header-pills,.card-header-tabs{margin-right:-.625rem;margin-left:-.625rem}.card-header{border-bottom:1px solid rgba(0,0,0,.125)}.card-header:first-child{border-radius:calc(3px - 1px) calc(3px - 1px) 0 0}.card-header+.list-group .list-group-item:first-child{border-top:0}.card-footer{border-top:1px solid rgba(0,0,0,.125)}.card-footer:last-child{border-radius:0 0 calc(3px - 1px) calc(3px - 1px)}.card-header-tabs{margin-bottom:-.75rem;border-bottom:0}.card-img-overlay{position:absolute;top:0;right:0;bottom:0;left:0;padding:1.25rem}.card-img{width:100%;border-radius:calc(3px - 1px)}.card-img-top{width:100%;border-top-left-radius:calc(3px - 1px);border-top-right-radius:calc(3px - 1px)}.card-img-bottom{width:100%;border-bottom-right-radius:calc(3px - 1px);border-bottom-left-radius:calc(3px - 1px)}.card-deck{display:flex;flex-direction:column}.card-deck .card{margin-bottom:14px}@media (min-width:576px){.card-deck{flex-flow:row wrap;margin-right:-14px;margin-left:-14px}.card-deck .card{display:flex;flex-grow:1;flex-shrink:0;flex-basis:0%;flex-direction:column;margin-right:14px;margin-bottom:0;margin-left:14px}}.card-group{display:flex;flex-direction:column}.card-group>.card{margin-bottom:14px}@media (min-width:576px){.card-group{flex-flow:row wrap}.card-group>.card{flex-grow:1;flex-shrink:0;flex-basis:0%;margin-bottom:0}.card-group>.card+.card{margin-left:0;border-left:0}.card-group>.card:first-child{border-top-right-radius:0;border-bottom-right-radius:0}.card-group>.card:first-child .card-header,.card-group>.card:first-child .card-img-top{border-top-right-radius:0}.card-group>.card:first-child .card-footer,.card-group>.card:first-child .card-img-bottom{border-bottom-right-radius:0}.card-group>.card:last-child{border-top-left-radius:0;border-bottom-left-radius:0}.card-group>.card:last-child .card-header,.card-group>.card:last-child .card-img-top{border-top-left-radius:0}.card-group>.card:last-child .card-footer,.card-group>.card:last-child .card-img-bottom{border-bottom-left-radius:0}.card-group>.card:only-child{border-radius:3px}.card-group>.card:only-child .card-header,.card-group>.card:only-child .card-img-top{border-top-left-radius:3px;border-top-right-radius:3px}.card-group>.card:only-child .card-footer,.card-group>.card:only-child .card-img-bottom{border-bottom-right-radius:3px;border-bottom-left-radius:3px}.card-group>.card:not(:first-child):not(:last-child):not(:only-child),.card-group>.card:not(:first-child):not(:last-child):not(:only-child) .card-footer,.card-group>.card:not(:first-child):not(:last-child):not(:only-child) .card-header,.card-group>.card:not(:first-child):not(:last-child):not(:only-child) .card-img-bottom,.card-group>.card:not(:first-child):not(:last-child):not(:only-child) .card-img-top{border-radius:0}.card-columns{-moz-column-count:3;column-count:3;-moz-column-gap:1.25rem;column-gap:1.25rem;orphans:1;widows:1}.card-columns .card{display:inline-block;width:100%}}.card-columns .card{margin-bottom:.75rem}.accordion .card:not(:first-of-type):not(:last-of-type){border-bottom:0;border-radius:0}.accordion .card:not(:first-of-type) .card-header:first-child{border-radius:0}.accordion .card:first-of-type{border-bottom:0;border-bottom-right-radius:0;border-bottom-left-radius:0}.accordion .card:last-of-type{border-top-left-radius:0;border-top-right-radius:0}.pagination,.progress{border-radius:3px;display:flex}.pagination{padding-left:0;list-style:none}.page-link{position:relative;display:block;padding:.1875rem;line-height:1rem;color:#2D2F33;background-color:#fff;border:1px solid #EAECF3}.page-item:first-child .page-link,.pagination-lg .f-page-item:first-child .f-page-link,.pagination-sm .f-page-item:first-child .f-page-link{border-top-left-radius:3px;border-bottom-left-radius:3px}.page-item:last-child .page-link,.pagination-lg .f-page-item:last-child .f-page-link,.pagination-sm .f-page-item:last-child .f-page-link{border-top-right-radius:3px;border-bottom-right-radius:3px}.page-link:hover{z-index:2;color:#529DFF;text-decoration:none;background-color:#fff;border-color:#529DFF}.page-link:focus{z-index:2;outline:0;box-shadow:0 0 4px 2px rgba(82,157,255,.12)}.page-item:first-child .page-link{margin-left:0}.page-item.active .page-link{z-index:1;color:#2A87FF;background:#EFF5FF!important;border-color:#EFF5FF}.page-item.disabled .page-link{color:#878D99;pointer-events:none;cursor:auto;background:#F4F5F9;border-color:#DEE1EA;box-shadow:none}.pagination-lg .f-page-link{font-size:.875rem;line-height:1.5;padding:.75rem}.pagination-sm .f-page-link{font-size:.75rem;line-height:1.5;padding:.1875rem}.f-alert{position:relative;padding:.75rem 1.25rem;margin-bottom:1rem;border:1px solid transparent;border-radius:3px}.f-alert-dismissible{padding-right:3.71875rem}.f-alert-dismissible .f-close{position:absolute;top:0;right:0;padding:.75rem 1.25rem}.alert-primary{background-color:#d4e7ff;border-color:#c3ddff;color:#164685}.alert-primary .f-alert-link{color:#0f2f59}.alert-primary hr{border-top-color:#aacfff}.alert-secondary{background-color:#e2e3e5;border-color:#d6d8db;color:#383d41}.alert-secondary .f-alert-link{color:#202326}.alert-secondary hr{border-top-color:#c8cbcf}.alert-success{background-color:#e2f4e5;border-color:#d6efdb;color:#386742}.alert-success .f-alert-link{color:#26462d}.alert-success hr{border-top-color:#c4e8cb}.alert-info{background-color:#dfedff;border-color:#d2e6ff;color:#315585}.alert-info .f-alert-link{color:#233d60}.alert-info hr{border-top-color:#b9d8ff}.alert-warning{background-color:#fdecda;border-color:#fce5cb;color:#7f5423}.alert-warning .f-alert-link{color:#573a18}.alert-warning hr{border-top-color:#fbd9b3}.alert-danger{background-color:#f8d7da;border-color:#f5c6cb;color:#721c24}.alert-danger .f-alert-link{color:#491217}.alert-danger hr{border-top-color:#f1b0b7}.alert-light{background-color:#fefefe;border-color:#fdfdfe;color:#818182}.alert-light .f-alert-link{color:#686868}.alert-light hr{border-top-color:#ececf6}.alert-dark{background-color:#d6d8d9;border-color:#c6c8ca;color:#1b1e21}.alert-dark .f-alert-link{color:#040505}.alert-dark hr{border-top-color:#b9bbbe}@keyframes progress-bar-stripes{from{background-position:1rem 0}to{background-position:0 0}}.progress{height:1rem;font-size:.60938rem;background-color:#e9ecef;box-shadow:inset 0 .1rem .1rem rgba(0,0,0,.1)}.progress-bar{display:flex;flex-direction:column;justify-content:center;color:#fff;text-align:center;white-space:nowrap;background-color:#2A87FF;transition:width .6s ease}@media screen and (prefers-reduced-motion:reduce){.progress-bar{transition:none}}.progress-bar-striped{background-image:linear-gradient(45deg,rgba(255,255,255,.25),transparent 25%,transparent 50%,rgba(255,255,255,.5),rgba(255,255,255,.75),transparent 75%,transparent);background-size:1rem 1rem}.progress-bar-animated{animation:progress-bar-stripes 1s linear infinite}.media{display:flex;align-items:flex-start}.media-body{flex-grow:1;flex-shrink:1;flex-basis:0%}.f-list-group{display:flex;flex-direction:column;padding-left:0;margin-bottom:0}.f-list-group-item-action{width:100%;color:#495057;text-align:inherit}.f-list-group-item-action:focus,.f-list-group-item-action:hover{color:#495057;text-decoration:none;background-color:#f8f9fa}.f-list-group-item-action:active{color:#2D2F33;background-color:#e9ecef}.f-list-group-item{position:relative;display:block;padding:.75rem 1.25rem;margin-bottom:-1px;background-color:#fff;border:1px solid rgba(0,0,0,.125)}.f-list-group-item:first-child{border-top-left-radius:3px;border-top-right-radius:3px}.f-list-group-item:last-child{margin-bottom:0;border-bottom-right-radius:3px;border-bottom-left-radius:3px}.f-list-group-item:focus,.f-list-group-item:hover{z-index:1;text-decoration:none}.f-list-group-item.disabled,.f-list-group-item:disabled{color:#6c757d;background-color:#fff}.f-list-group-item.active{z-index:2;color:#fff;background-color:#2A87FF;border-color:#2A87FF}.f-list-group-flush .f-list-group-item{border-right:0;border-left:0;border-radius:0}.f-list-group-flush:first-child .f-list-group-item:first-child{border-top:0}.f-list-group-flush:last-child .f-list-group-item:last-child{border-bottom:0}.list-group-item-primary{color:#164685;background-color:#c3ddff}.list-group-item-primary.list-group-item-action:focus,.list-group-item-primary.list-group-item-action:hover{color:#164685;background-color:#aacfff}.list-group-item-primary.list-group-item-action.active{color:#fff;background-color:#164685;border-color:#164685}.list-group-item-secondary{color:#383d41;background-color:#d6d8db}.list-group-item-secondary.list-group-item-action:focus,.list-group-item-secondary.list-group-item-action:hover{color:#383d41;background-color:#c8cbcf}.list-group-item-secondary.list-group-item-action.active{color:#fff;background-color:#383d41;border-color:#383d41}.list-group-item-success{color:#386742;background-color:#d6efdb}.list-group-item-success.list-group-item-action:focus,.list-group-item-success.list-group-item-action:hover{color:#386742;background-color:#c4e8cb}.list-group-item-success.list-group-item-action.active{color:#fff;background-color:#386742;border-color:#386742}.list-group-item-info{color:#315585;background-color:#d2e6ff}.list-group-item-info.list-group-item-action:focus,.list-group-item-info.list-group-item-action:hover{color:#315585;background-color:#b9d8ff}.list-group-item-info.list-group-item-action.active{color:#fff;background-color:#315585;border-color:#315585}.list-group-item-warning{color:#7f5423;background-color:#fce5cb}.list-group-item-warning.list-group-item-action:focus,.list-group-item-warning.list-group-item-action:hover{color:#7f5423;background-color:#fbd9b3}.list-group-item-warning.list-group-item-action.active{color:#fff;background-color:#7f5423;border-color:#7f5423}.list-group-item-danger{color:#721c24;background-color:#f5c6cb}.list-group-item-danger.list-group-item-action:focus,.list-group-item-danger.list-group-item-action:hover{color:#721c24;background-color:#f1b0b7}.list-group-item-danger.list-group-item-action.active{color:#fff;background-color:#721c24;border-color:#721c24}.list-group-item-light{color:#818182;background-color:#fdfdfe}.list-group-item-light.list-group-item-action:focus,.list-group-item-light.list-group-item-action:hover{color:#818182;background-color:#ececf6}.list-group-item-light.list-group-item-action.active{color:#fff;background-color:#818182;border-color:#818182}.list-group-item-dark{color:#1b1e21;background-color:#c6c8ca}.list-group-item-dark.list-group-item-action:focus,.list-group-item-dark.list-group-item-action:hover{color:#1b1e21;background-color:#b9bbbe}.list-group-item-dark.list-group-item-action.active{color:#fff;background-color:#1b1e21;border-color:#1b1e21}.close{float:right;font-size:1.21875rem;line-height:1;color:#000;text-shadow:0 1px 0 #fff;opacity:.5}.popover,.tooltip{font-family:-apple-system,BlinkMacSystemFont,"Segoe UI","PingFang SC","Hiragino Sans GB","Microsoft YaHei","Helvetica Neue",Helvetica,Arial,sans-serif;font-weight:400;text-decoration:none;letter-spacing:normal;word-spacing:normal;white-space:normal;line-break:auto;font-size:.75rem;word-wrap:break-word}.close:not(:disabled):not(.disabled):focus,.close:not(:disabled):not(.disabled):hover{color:#000;text-decoration:none;opacity:.75}button.close{padding:0;background-color:transparent;border:0;-webkit-appearance:none}.modal-open .modal{overflow-x:hidden;overflow-y:auto}.modal{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1050;overflow:hidden;outline:0}.modal-dialog{position:relative;width:auto;margin:.5rem;pointer-events:none}.modal.fade .modal-dialog{transition:transform .3s ease-out;transform:translate(0,-25%)}@media screen and (prefers-reduced-motion:reduce){.modal.fade .modal-dialog{transition:none}}.modal.show .modal-dialog{transform:translate(0,0)}.modal-dialog-centered{display:flex;align-items:center;min-height:calc(100% - (.5rem * 2))}.modal-dialog-centered::before{display:block;height:calc(100vh - (.5rem * 2));content:""}.modal-content{position:relative;display:flex;flex-direction:column;width:100%;pointer-events:auto;background-color:#fff;background-clip:padding-box;border:0 solid #E5E9EF;border-radius:3px;box-shadow:0 .125rem .75rem rgba(0,0,0,.06);outline:0}.modal-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1040;background-color:#000}.modal-backdrop.fade{opacity:0}.modal-backdrop.show{opacity:.15}.modal-title{margin-bottom:0;line-height:1.375rem}.modal-body{position:relative;flex-grow:1;flex-shrink:1;flex-basis:auto;padding:.625rem}.modal-scrollbar-measure{position:absolute;top:-9999px;width:3.125rem;height:3.125rem;overflow:scroll}@media (min-width:576px){.modal-dialog{max-width:31.25rem;margin:1.75rem auto}.modal-dialog-centered{min-height:calc(100% - (1.75rem * 2))}.modal-dialog-centered::before{height:calc(100vh - (1.75rem * 2))}.modal-content{box-shadow:0 .125rem .75rem 0 rgba(0,0,0,.06)}.modal-sm{max-width:18.75rem}}@media (min-width:888px){.modal-lg{max-width:50rem}}.tooltip{position:absolute;z-index:1070;display:block;margin:0;line-height:1.4286;text-align:left;text-align:start;text-shadow:none;word-break:normal;opacity:0}.tooltip.show{opacity:1}.tooltip .arrow{position:absolute;display:block;width:.8rem;height:.4rem}.tooltip .arrow::before{position:absolute;content:"";border-color:transparent;border-style:solid}.f-bs-tooltip-auto[x-placement^=top],.f-bs-tooltip-top{padding:.4rem 0}.f-bs-tooltip-auto[x-placement^=top] .arrow,.f-bs-tooltip-top .arrow{bottom:0}.f-bs-tooltip-auto[x-placement^=top] .arrow::before,.f-bs-tooltip-top .arrow::before{top:0;border-width:.4rem .4rem 0;border-top-color:#303C53}.f-bs-tooltip-auto[x-placement^=right],.f-bs-tooltip-right{padding:0 .4rem}.f-bs-tooltip-auto[x-placement^=right] .arrow,.f-bs-tooltip-right .arrow{left:0;width:.4rem;height:.8rem}.f-bs-tooltip-auto[x-placement^=right] .arrow::before,.f-bs-tooltip-right .arrow::before{right:0;border-width:.4rem .4rem .4rem 0;border-right-color:#303C53}.f-bs-tooltip-auto[x-placement^=bottom],.f-bs-tooltip-bottom{padding:.4rem 0}.f-bs-tooltip-auto[x-placement^=bottom] .arrow,.f-bs-tooltip-bottom .arrow{top:0}.f-bs-tooltip-auto[x-placement^=bottom] .arrow::before,.f-bs-tooltip-bottom .arrow::before{bottom:0;border-width:0 .4rem .4rem;border-bottom-color:#303C53}.f-bs-tooltip-auto[x-placement^=left],.f-bs-tooltip-left{padding:0 .4rem}.f-bs-tooltip-auto[x-placement^=left] .arrow,.f-bs-tooltip-left .arrow{right:0;width:.4rem;height:.8rem}.f-bs-tooltip-auto[x-placement^=left] .arrow::before,.f-bs-tooltip-left .arrow::before{left:0;border-width:.4rem 0 .4rem .4rem;border-left-color:#303C53}.tooltip-inner{max-width:18.75rem;max-height:6.25rem;overflow:hidden;padding:.5rem .625rem;color:#fff;text-align:left;background-color:#303C53;box-shadow:0 2px 8px 0 rgba(0,0,0,.15);border-radius:3px}.tooltip-inner-lg{max-width:37.5rem;max-height:initial;overflow:initial}.popover{position:absolute;top:0;left:0;z-index:1060;display:block;line-height:1.4286;text-align:left;text-align:start;text-shadow:none;word-break:normal;background-color:#fff;background-clip:padding-box;border:1px solid #fff;border-radius:4px;box-shadow:0 2px 8px 0 rgba(0,32,74,.15)}.popover .arrow{position:absolute;display:block;width:1rem;height:.5rem;margin:0 3px}.popover .arrow::after,.popover .arrow::before{position:absolute;display:block;content:"";border-color:transparent;border-style:solid}.f-bs-popover-auto[x-placement^=top],.f-bs-popover-top{margin-bottom:.5rem}.f-bs-popover-auto[x-placement^=top] .arrow,.f-bs-popover-top .arrow{bottom:calc((.5rem + 1px) * -1)}.f-bs-popover-auto[x-placement^=top] .arrow::after,.f-bs-popover-auto[x-placement^=top] .arrow::before,.f-bs-popover-top .arrow::after,.f-bs-popover-top .arrow::before{border-width:.5rem .5rem 0}.f-bs-popover-auto[x-placement^=top] .arrow::before,.f-bs-popover-top .arrow::before{bottom:0;border-top-color:rgba(255,255,255,.4)}.f-bs-popover-auto[x-placement^=top] .arrow::after,.f-bs-popover-top .arrow::after{bottom:1px;border-top-color:#fff}.f-bs-popover-auto[x-placement^=right],.f-bs-popover-right{margin-left:.5rem}.f-bs-popover-auto[x-placement^=right] .arrow,.f-bs-popover-right .arrow{left:calc((.5rem + 1px) * -1);width:.5rem;height:1rem;margin:3px 0}.f-bs-popover-auto[x-placement^=right] .arrow::after,.f-bs-popover-auto[x-placement^=right] .arrow::before,.f-bs-popover-right .arrow::after,.f-bs-popover-right .arrow::before{border-width:.5rem .5rem .5rem 0}.f-bs-popover-auto[x-placement^=right] .arrow::before,.f-bs-popover-right .arrow::before{left:0;border-right-color:rgba(255,255,255,.4)}.f-bs-popover-auto[x-placement^=right] .arrow::after,.f-bs-popover-right .arrow::after{left:1px;border-right-color:#fff}.f-bs-popover-auto[x-placement^=bottom],.f-bs-popover-bottom{margin-top:.5rem}.f-bs-popover-auto[x-placement^=bottom] .arrow,.f-bs-popover-bottom .arrow{top:calc((.5rem + 1px) * -1)}.f-bs-popover-auto[x-placement^=bottom] .arrow::after,.f-bs-popover-auto[x-placement^=bottom] .arrow::before,.f-bs-popover-bottom .arrow::after,.f-bs-popover-bottom .arrow::before{border-width:0 .5rem .5rem}.f-bs-popover-auto[x-placement^=bottom] .arrow::before,.f-bs-popover-bottom .arrow::before{top:0;border-bottom-color:rgba(255,255,255,.4)}.f-bs-popover-auto[x-placement^=bottom] .arrow::after,.f-bs-popover-bottom .arrow::after{top:1px;border-bottom-color:#fff}.f-bs-popover-auto[x-placement^=bottom] .popover-header::before,.f-bs-popover-bottom .popover-header::before{position:absolute;top:0;left:50%;display:block;width:1rem;margin-left:-.5rem;content:"";border-bottom:1px solid #f7f7f7}.f-bs-popover-auto[x-placement^=left],.f-bs-popover-left{margin-right:.5rem}.f-bs-popover-auto[x-placement^=left] .arrow,.f-bs-popover-left .arrow{right:calc((.5rem + 1px) * -1);width:.5rem;height:1rem;margin:3px 0}.f-bs-popover-auto[x-placement^=left] .arrow::after,.f-bs-popover-auto[x-placement^=left] .arrow::before,.f-bs-popover-left .arrow::after,.f-bs-popover-left .arrow::before{border-width:.5rem 0 .5rem .5rem}.f-bs-popover-auto[x-placement^=left] .arrow::before,.f-bs-popover-left .arrow::before{right:0;border-left-color:rgba(255,255,255,.4)}.f-bs-popover-auto[x-placement^=left] .arrow::after,.f-bs-popover-left .arrow::after{right:1px;border-left-color:#fff}.popover-header{padding:.5rem .75rem;margin-bottom:0;font-size:.8125rem;background-color:#f7f7f7;border-bottom:1px solid #ebebeb;border-top-left-radius:calc(3px - 1px);border-top-right-radius:calc(3px - 1px)}.popover-header:empty{display:none}.popover-body{max-width:17.25rem;padding:.5rem .75rem;color:#2D2F33}.align-baseline{vertical-align:baseline!important}.align-top{vertical-align:top!important}.align-middle{vertical-align:middle!important}.align-bottom{vertical-align:bottom!important}.align-text-bottom{vertical-align:text-bottom!important}.align-text-top{vertical-align:text-top!important}.bg-primary{background-color:#2A87FF!important}a.bg-primary:focus,a.bg-primary:hover,button.bg-primary:focus,button.bg-primary:hover{background-color:#006bf6!important}.bg-secondary{background-color:#6c757d!important}a.bg-secondary:focus,a.bg-secondary:hover,button.bg-secondary:focus,button.bg-secondary:hover{background-color:#545b62!important}.bg-success{background-color:#6CC77F!important}a.bg-success:focus,a.bg-success:hover,button.bg-success:focus,button.bg-success:hover{background-color:#47b95f!important}.bg-info{background-color:#5EA4FF!important}a.bg-info:focus,a.bg-info:hover,button.bg-info:focus,button.bg-info:hover{background-color:#2b87ff!important}.bg-warning{background-color:#F5A144!important}a.bg-warning:focus,a.bg-warning:hover,button.bg-warning:focus,button.bg-warning:hover{background-color:#f28914!important}.bg-danger{background-color:#dc3545!important}a.bg-danger:focus,a.bg-danger:hover,button.bg-danger:focus,button.bg-danger:hover{background-color:#bd2130!important}.bg-light{background-color:#f8f9fa!important}a.bg-light:focus,a.bg-light:hover,button.bg-light:focus,button.bg-light:hover{background-color:#dae0e5!important}.bg-dark{background-color:#343a40!important}a.bg-dark:focus,a.bg-dark:hover,button.bg-dark:focus,button.bg-dark:hover{background-color:#1d2124!important}.bg-white{background-color:#fff!important}.bg-transparent{background-color:transparent!important}.border{border:1px solid #E6E9F0!important}.border-top{border-top:1px solid #E6E9F0!important}.border-right{border-right:1px solid #E6E9F0!important}.border-bottom{border-bottom:1px solid #E6E9F0!important}.border-left{border-left:1px solid #E6E9F0!important}.border-0{border:0!important}.rounded-right,.rounded-top{border-top-right-radius:3px!important}.rounded-bottom,.rounded-right{border-bottom-right-radius:3px!important}.rounded-left,.rounded-top{border-top-left-radius:3px!important}.rounded-bottom,.rounded-left{border-bottom-left-radius:3px!important}.border-top-0{border-top:0!important}.border-right-0{border-right:0!important}.border-bottom-0{border-bottom:0!important}.border-left-0{border-left:0!important}.border-primary{border-color:#2A87FF!important}.border-secondary{border-color:#6c757d!important}.border-success{border-color:#6CC77F!important}.border-info{border-color:#5EA4FF!important}.border-warning{border-color:#F5A144!important}.border-danger{border-color:#dc3545!important}.border-light{border-color:#f8f9fa!important}.border-dark{border-color:#343a40!important}.border-white{border-color:#fff!important}.rounded{border-radius:3px!important}.rounded-circle{border-radius:50%!important}.rounded-0{border-radius:0!important}.f-clearfix::after{display:block;clear:both;content:""}.d-none{display:none!important}.d-inline{display:inline!important}.d-inline-block{display:inline-block!important}.d-block{display:block!important}.d-table{display:table!important}.d-table-row{display:table-row!important}.d-table-cell{display:table-cell!important}.d-flex{display:flex!important}.d-inline-flex{display:inline-flex!important}.flex-row{flex-direction:row!important}.flex-column{flex-direction:column!important}.flex-row-reverse{flex-direction:row-reverse!important}.flex-column-reverse{flex-direction:column-reverse!important}.flex-wrap{flex-wrap:wrap!important}.flex-nowrap{flex-wrap:nowrap!important}.flex-wrap-reverse{flex-wrap:wrap-reverse!important}.flex-fill{flex-grow:1!important;flex-shrink:1!important;flex-basis:auto!important}.flex-grow-0{flex-grow:0!important}.flex-grow-1{flex-grow:1!important}.flex-shrink-0{flex-shrink:0!important}.flex-shrink-1{flex-shrink:1!important}.justify-content-start{justify-content:flex-start!important}.justify-content-end{justify-content:flex-end!important}.justify-content-center{justify-content:center!important}.justify-content-between{justify-content:space-between!important}.justify-content-around{justify-content:space-around!important}.align-items-start{align-items:flex-start!important}.align-items-end{align-items:flex-end!important}.align-items-center{align-items:center!important}.align-items-baseline{align-items:baseline!important}.align-items-stretch{align-items:stretch!important}.align-content-start{align-content:flex-start!important}.align-content-end{align-content:flex-end!important}.align-content-center{align-content:center!important}.align-content-between{align-content:space-between!important}.align-content-around{align-content:space-around!important}.align-content-stretch{align-content:stretch!important}.align-self-auto{align-self:auto!important}.align-self-start{align-self:flex-start!important}.align-self-end{align-self:flex-end!important}.align-self-center{align-self:center!important}.align-self-baseline{align-self:baseline!important}.align-self-stretch{align-self:stretch!important}.float-left{float:left!important}.float-right{float:right!important}.float-none{float:none!important}.position-static{position:static!important}.position-relative{position:relative!important}.position-absolute{position:absolute!important}.position-fixed{position:fixed!important}.position-sticky{position:sticky!important}.fixed-bottom,.fixed-top{position:fixed;right:0;left:0;z-index:1030}.fixed-top{top:0}.fixed-bottom{bottom:0}@supports (position:sticky){.sticky-top{position:sticky;top:0;z-index:1020}}.shadow-sm{box-shadow:0 .125rem .25rem rgba(0,0,0,.075)!important}.shadow{box-shadow:0 .5rem 1rem rgba(0,0,0,.15)!important}.shadow-lg{box-shadow:0 1rem 3rem rgba(0,0,0,.175)!important}.shadow-none{box-shadow:none!important}.w-25{width:25%!important}.w-50{width:50%!important}.w-75{width:75%!important}.w-100{width:100%!important}.w-auto{width:auto!important}.h-25{height:25%!important}.h-50{height:50%!important}.h-75{height:75%!important}.h-100{height:100%!important}.h-auto{height:auto!important}.mw-100{max-width:100%!important}.mh-100{max-height:100%!important}.m-0{margin:0!important}.mt-0,.my-0{margin-top:0!important}.mr-0,.mx-0{margin-right:0!important}.mb-0,.my-0{margin-bottom:0!important}.ml-0,.mx-0{margin-left:0!important}.m-1{margin:.25rem!important}.mt-1,.my-1{margin-top:.25rem!important}.mr-1,.mx-1{margin-right:.25rem!important}.mb-1,.my-1{margin-bottom:.25rem!important}.ml-1,.mx-1{margin-left:.25rem!important}.m-2{margin:.5rem!important}.mt-2,.my-2{margin-top:.5rem!important}.mr-2,.mx-2{margin-right:.5rem!important}.mb-2,.my-2{margin-bottom:.5rem!important}.ml-2,.mx-2{margin-left:.5rem!important}.m-3{margin:1rem!important}.mt-3,.my-3{margin-top:1rem!important}.mr-3,.mx-3{margin-right:1rem!important}.mb-3,.my-3{margin-bottom:1rem!important}.ml-3,.mx-3{margin-left:1rem!important}.m-4{margin:1.5rem!important}.mt-4,.my-4{margin-top:1.5rem!important}.mr-4,.mx-4{margin-right:1.5rem!important}.mb-4,.my-4{margin-bottom:1.5rem!important}.ml-4,.mx-4{margin-left:1.5rem!important}.m-5{margin:3rem!important}.mt-5,.my-5{margin-top:3rem!important}.mr-5,.mx-5{margin-right:3rem!important}.mb-5,.my-5{margin-bottom:3rem!important}.ml-5,.mx-5{margin-left:3rem!important}.p-0{padding:0!important}.pt-0,.py-0{padding-top:0!important}.pr-0,.px-0{padding-right:0!important}.pb-0,.py-0{padding-bottom:0!important}.pl-0,.px-0{padding-left:0!important}.p-1{padding:.25rem!important}.pt-1,.py-1{padding-top:.25rem!important}.pr-1,.px-1{padding-right:.25rem!important}.pb-1,.py-1{padding-bottom:.25rem!important}.pl-1,.px-1{padding-left:.25rem!important}.p-2{padding:.5rem!important}.pt-2,.py-2{padding-top:.5rem!important}.pr-2,.px-2{padding-right:.5rem!important}.pb-2,.py-2{padding-bottom:.5rem!important}.pl-2,.px-2{padding-left:.5rem!important}.p-3{padding:1rem!important}.pt-3,.py-3{padding-top:1rem!important}.pr-3,.px-3{padding-right:1rem!important}.pb-3,.py-3{padding-bottom:1rem!important}.pl-3,.px-3{padding-left:1rem!important}.p-4{padding:1.5rem!important}.pt-4,.py-4{padding-top:1.5rem!important}.pr-4,.px-4{padding-right:1.5rem!important}.pb-4,.py-4{padding-bottom:1.5rem!important}.pl-4,.px-4{padding-left:1.5rem!important}.p-5{padding:3rem!important}.pt-5,.py-5{padding-top:3rem!important}.pr-5,.px-5{padding-right:3rem!important}.pb-5,.py-5{padding-bottom:3rem!important}.pl-5,.px-5{padding-left:3rem!important}.m-auto{margin:auto!important}.mt-auto,.my-auto{margin-top:auto!important}.mr-auto,.mx-auto{margin-right:auto!important}.mb-auto,.my-auto{margin-bottom:auto!important}.ml-auto,.mx-auto{margin-left:auto!important}.f-text-justify{text-align:justify!important}.f-text-nowrap{white-space:nowrap!important}.f-text-overflow{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.text-left{text-align:left!important}.text-right{text-align:right!important}.text-center{text-align:center!important}@media (min-width:576px){.d-sm-none{display:none!important}.d-sm-inline{display:inline!important}.d-sm-inline-block{display:inline-block!important}.d-sm-block{display:block!important}.d-sm-table{display:table!important}.d-sm-table-row{display:table-row!important}.d-sm-table-cell{display:table-cell!important}.d-sm-flex{display:flex!important}.d-sm-inline-flex{display:inline-flex!important}.flex-sm-row{flex-direction:row!important}.flex-sm-column{flex-direction:column!important}.flex-sm-row-reverse{flex-direction:row-reverse!important}.flex-sm-column-reverse{flex-direction:column-reverse!important}.flex-sm-wrap{flex-wrap:wrap!important}.flex-sm-nowrap{flex-wrap:nowrap!important}.flex-sm-wrap-reverse{flex-wrap:wrap-reverse!important}.flex-sm-fill{flex-grow:1!important;flex-shrink:1!important;flex-basis:auto!important}.flex-sm-grow-0{flex-grow:0!important}.flex-sm-grow-1{flex-grow:1!important}.flex-sm-shrink-0{flex-shrink:0!important}.flex-sm-shrink-1{flex-shrink:1!important}.justify-content-sm-start{justify-content:flex-start!important}.justify-content-sm-end{justify-content:flex-end!important}.justify-content-sm-center{justify-content:center!important}.justify-content-sm-between{justify-content:space-between!important}.justify-content-sm-around{justify-content:space-around!important}.align-items-sm-start{align-items:flex-start!important}.align-items-sm-end{align-items:flex-end!important}.align-items-sm-center{align-items:center!important}.align-items-sm-baseline{align-items:baseline!important}.align-items-sm-stretch{align-items:stretch!important}.align-content-sm-start{align-content:flex-start!important}.align-content-sm-end{align-content:flex-end!important}.align-content-sm-center{align-content:center!important}.align-content-sm-between{align-content:space-between!important}.align-content-sm-around{align-content:space-around!important}.align-content-sm-stretch{align-content:stretch!important}.align-self-sm-auto{align-self:auto!important}.align-self-sm-start{align-self:flex-start!important}.align-self-sm-end{align-self:flex-end!important}.align-self-sm-center{align-self:center!important}.align-self-sm-baseline{align-self:baseline!important}.align-self-sm-stretch{align-self:stretch!important}.float-sm-left{float:left!important}.float-sm-right{float:right!important}.float-sm-none{float:none!important}.m-sm-0{margin:0!important}.mt-sm-0,.my-sm-0{margin-top:0!important}.mr-sm-0,.mx-sm-0{margin-right:0!important}.mb-sm-0,.my-sm-0{margin-bottom:0!important}.ml-sm-0,.mx-sm-0{margin-left:0!important}.m-sm-1{margin:.25rem!important}.mt-sm-1,.my-sm-1{margin-top:.25rem!important}.mr-sm-1,.mx-sm-1{margin-right:.25rem!important}.mb-sm-1,.my-sm-1{margin-bottom:.25rem!important}.ml-sm-1,.mx-sm-1{margin-left:.25rem!important}.m-sm-2{margin:.5rem!important}.mt-sm-2,.my-sm-2{margin-top:.5rem!important}.mr-sm-2,.mx-sm-2{margin-right:.5rem!important}.mb-sm-2,.my-sm-2{margin-bottom:.5rem!important}.ml-sm-2,.mx-sm-2{margin-left:.5rem!important}.m-sm-3{margin:1rem!important}.mt-sm-3,.my-sm-3{margin-top:1rem!important}.mr-sm-3,.mx-sm-3{margin-right:1rem!important}.mb-sm-3,.my-sm-3{margin-bottom:1rem!important}.ml-sm-3,.mx-sm-3{margin-left:1rem!important}.m-sm-4{margin:1.5rem!important}.mt-sm-4,.my-sm-4{margin-top:1.5rem!important}.mr-sm-4,.mx-sm-4{margin-right:1.5rem!important}.mb-sm-4,.my-sm-4{margin-bottom:1.5rem!important}.ml-sm-4,.mx-sm-4{margin-left:1.5rem!important}.m-sm-5{margin:3rem!important}.mt-sm-5,.my-sm-5{margin-top:3rem!important}.mr-sm-5,.mx-sm-5{margin-right:3rem!important}.mb-sm-5,.my-sm-5{margin-bottom:3rem!important}.ml-sm-5,.mx-sm-5{margin-left:3rem!important}.p-sm-0{padding:0!important}.pt-sm-0,.py-sm-0{padding-top:0!important}.pr-sm-0,.px-sm-0{padding-right:0!important}.pb-sm-0,.py-sm-0{padding-bottom:0!important}.pl-sm-0,.px-sm-0{padding-left:0!important}.p-sm-1{padding:.25rem!important}.pt-sm-1,.py-sm-1{padding-top:.25rem!important}.pr-sm-1,.px-sm-1{padding-right:.25rem!important}.pb-sm-1,.py-sm-1{padding-bottom:.25rem!important}.pl-sm-1,.px-sm-1{padding-left:.25rem!important}.p-sm-2{padding:.5rem!important}.pt-sm-2,.py-sm-2{padding-top:.5rem!important}.pr-sm-2,.px-sm-2{padding-right:.5rem!important}.pb-sm-2,.py-sm-2{padding-bottom:.5rem!important}.pl-sm-2,.px-sm-2{padding-left:.5rem!important}.p-sm-3{padding:1rem!important}.pt-sm-3,.py-sm-3{padding-top:1rem!important}.pr-sm-3,.px-sm-3{padding-right:1rem!important}.pb-sm-3,.py-sm-3{padding-bottom:1rem!important}.pl-sm-3,.px-sm-3{padding-left:1rem!important}.p-sm-4{padding:1.5rem!important}.pt-sm-4,.py-sm-4{padding-top:1.5rem!important}.pr-sm-4,.px-sm-4{padding-right:1.5rem!important}.pb-sm-4,.py-sm-4{padding-bottom:1.5rem!important}.pl-sm-4,.px-sm-4{padding-left:1.5rem!important}.p-sm-5{padding:3rem!important}.pt-sm-5,.py-sm-5{padding-top:3rem!important}.pr-sm-5,.px-sm-5{padding-right:3rem!important}.pb-sm-5,.py-sm-5{padding-bottom:3rem!important}.pl-sm-5,.px-sm-5{padding-left:3rem!important}.m-sm-auto{margin:auto!important}.mt-sm-auto,.my-sm-auto{margin-top:auto!important}.mr-sm-auto,.mx-sm-auto{margin-right:auto!important}.mb-sm-auto,.my-sm-auto{margin-bottom:auto!important}.ml-sm-auto,.mx-sm-auto{margin-left:auto!important}.text-sm-left{text-align:left!important}.text-sm-right{text-align:right!important}.text-sm-center{text-align:center!important}}@media (min-width:768px){.d-md-none{display:none!important}.d-md-inline{display:inline!important}.d-md-inline-block{display:inline-block!important}.d-md-block{display:block!important}.d-md-table{display:table!important}.d-md-table-row{display:table-row!important}.d-md-table-cell{display:table-cell!important}.d-md-flex{display:flex!important}.d-md-inline-flex{display:inline-flex!important}.flex-md-row{flex-direction:row!important}.flex-md-column{flex-direction:column!important}.flex-md-row-reverse{flex-direction:row-reverse!important}.flex-md-column-reverse{flex-direction:column-reverse!important}.flex-md-wrap{flex-wrap:wrap!important}.flex-md-nowrap{flex-wrap:nowrap!important}.flex-md-wrap-reverse{flex-wrap:wrap-reverse!important}.flex-md-fill{flex-grow:1!important;flex-shrink:1!important;flex-basis:auto!important}.flex-md-grow-0{flex-grow:0!important}.flex-md-grow-1{flex-grow:1!important}.flex-md-shrink-0{flex-shrink:0!important}.flex-md-shrink-1{flex-shrink:1!important}.justify-content-md-start{justify-content:flex-start!important}.justify-content-md-end{justify-content:flex-end!important}.justify-content-md-center{justify-content:center!important}.justify-content-md-between{justify-content:space-between!important}.justify-content-md-around{justify-content:space-around!important}.align-items-md-start{align-items:flex-start!important}.align-items-md-end{align-items:flex-end!important}.align-items-md-center{align-items:center!important}.align-items-md-baseline{align-items:baseline!important}.align-items-md-stretch{align-items:stretch!important}.align-content-md-start{align-content:flex-start!important}.align-content-md-end{align-content:flex-end!important}.align-content-md-center{align-content:center!important}.align-content-md-between{align-content:space-between!important}.align-content-md-around{align-content:space-around!important}.align-content-md-stretch{align-content:stretch!important}.align-self-md-auto{align-self:auto!important}.align-self-md-start{align-self:flex-start!important}.align-self-md-end{align-self:flex-end!important}.align-self-md-center{align-self:center!important}.align-self-md-baseline{align-self:baseline!important}.align-self-md-stretch{align-self:stretch!important}.float-md-left{float:left!important}.float-md-right{float:right!important}.float-md-none{float:none!important}.m-md-0{margin:0!important}.mt-md-0,.my-md-0{margin-top:0!important}.mr-md-0,.mx-md-0{margin-right:0!important}.mb-md-0,.my-md-0{margin-bottom:0!important}.ml-md-0,.mx-md-0{margin-left:0!important}.m-md-1{margin:.25rem!important}.mt-md-1,.my-md-1{margin-top:.25rem!important}.mr-md-1,.mx-md-1{margin-right:.25rem!important}.mb-md-1,.my-md-1{margin-bottom:.25rem!important}.ml-md-1,.mx-md-1{margin-left:.25rem!important}.m-md-2{margin:.5rem!important}.mt-md-2,.my-md-2{margin-top:.5rem!important}.mr-md-2,.mx-md-2{margin-right:.5rem!important}.mb-md-2,.my-md-2{margin-bottom:.5rem!important}.ml-md-2,.mx-md-2{margin-left:.5rem!important}.m-md-3{margin:1rem!important}.mt-md-3,.my-md-3{margin-top:1rem!important}.mr-md-3,.mx-md-3{margin-right:1rem!important}.mb-md-3,.my-md-3{margin-bottom:1rem!important}.ml-md-3,.mx-md-3{margin-left:1rem!important}.m-md-4{margin:1.5rem!important}.mt-md-4,.my-md-4{margin-top:1.5rem!important}.mr-md-4,.mx-md-4{margin-right:1.5rem!important}.mb-md-4,.my-md-4{margin-bottom:1.5rem!important}.ml-md-4,.mx-md-4{margin-left:1.5rem!important}.m-md-5{margin:3rem!important}.mt-md-5,.my-md-5{margin-top:3rem!important}.mr-md-5,.mx-md-5{margin-right:3rem!important}.mb-md-5,.my-md-5{margin-bottom:3rem!important}.ml-md-5,.mx-md-5{margin-left:3rem!important}.p-md-0{padding:0!important}.pt-md-0,.py-md-0{padding-top:0!important}.pr-md-0,.px-md-0{padding-right:0!important}.pb-md-0,.py-md-0{padding-bottom:0!important}.pl-md-0,.px-md-0{padding-left:0!important}.p-md-1{padding:.25rem!important}.pt-md-1,.py-md-1{padding-top:.25rem!important}.pr-md-1,.px-md-1{padding-right:.25rem!important}.pb-md-1,.py-md-1{padding-bottom:.25rem!important}.pl-md-1,.px-md-1{padding-left:.25rem!important}.p-md-2{padding:.5rem!important}.pt-md-2,.py-md-2{padding-top:.5rem!important}.pr-md-2,.px-md-2{padding-right:.5rem!important}.pb-md-2,.py-md-2{padding-bottom:.5rem!important}.pl-md-2,.px-md-2{padding-left:.5rem!important}.p-md-3{padding:1rem!important}.pt-md-3,.py-md-3{padding-top:1rem!important}.pr-md-3,.px-md-3{padding-right:1rem!important}.pb-md-3,.py-md-3{padding-bottom:1rem!important}.pl-md-3,.px-md-3{padding-left:1rem!important}.p-md-4{padding:1.5rem!important}.pt-md-4,.py-md-4{padding-top:1.5rem!important}.pr-md-4,.px-md-4{padding-right:1.5rem!important}.pb-md-4,.py-md-4{padding-bottom:1.5rem!important}.pl-md-4,.px-md-4{padding-left:1.5rem!important}.p-md-5{padding:3rem!important}.pt-md-5,.py-md-5{padding-top:3rem!important}.pr-md-5,.px-md-5{padding-right:3rem!important}.pb-md-5,.py-md-5{padding-bottom:3rem!important}.pl-md-5,.px-md-5{padding-left:3rem!important}.m-md-auto{margin:auto!important}.mt-md-auto,.my-md-auto{margin-top:auto!important}.mr-md-auto,.mx-md-auto{margin-right:auto!important}.mb-md-auto,.my-md-auto{margin-bottom:auto!important}.ml-md-auto,.mx-md-auto{margin-left:auto!important}.text-md-left{text-align:left!important}.text-md-right{text-align:right!important}.text-md-center{text-align:center!important}}@media (min-width:888px){.d-lg-none{display:none!important}.d-lg-inline{display:inline!important}.d-lg-inline-block{display:inline-block!important}.d-lg-block{display:block!important}.d-lg-table{display:table!important}.d-lg-table-row{display:table-row!important}.d-lg-table-cell{display:table-cell!important}.d-lg-flex{display:flex!important}.d-lg-inline-flex{display:inline-flex!important}.flex-lg-row{flex-direction:row!important}.flex-lg-column{flex-direction:column!important}.flex-lg-row-reverse{flex-direction:row-reverse!important}.flex-lg-column-reverse{flex-direction:column-reverse!important}.flex-lg-wrap{flex-wrap:wrap!important}.flex-lg-nowrap{flex-wrap:nowrap!important}.flex-lg-wrap-reverse{flex-wrap:wrap-reverse!important}.flex-lg-fill{flex-grow:1!important;flex-shrink:1!important;flex-basis:auto!important}.flex-lg-grow-0{flex-grow:0!important}.flex-lg-grow-1{flex-grow:1!important}.flex-lg-shrink-0{flex-shrink:0!important}.flex-lg-shrink-1{flex-shrink:1!important}.justify-content-lg-start{justify-content:flex-start!important}.justify-content-lg-end{justify-content:flex-end!important}.justify-content-lg-center{justify-content:center!important}.justify-content-lg-between{justify-content:space-between!important}.justify-content-lg-around{justify-content:space-around!important}.align-items-lg-start{align-items:flex-start!important}.align-items-lg-end{align-items:flex-end!important}.align-items-lg-center{align-items:center!important}.align-items-lg-baseline{align-items:baseline!important}.align-items-lg-stretch{align-items:stretch!important}.align-content-lg-start{align-content:flex-start!important}.align-content-lg-end{align-content:flex-end!important}.align-content-lg-center{align-content:center!important}.align-content-lg-between{align-content:space-between!important}.align-content-lg-around{align-content:space-around!important}.align-content-lg-stretch{align-content:stretch!important}.align-self-lg-auto{align-self:auto!important}.align-self-lg-start{align-self:flex-start!important}.align-self-lg-end{align-self:flex-end!important}.align-self-lg-center{align-self:center!important}.align-self-lg-baseline{align-self:baseline!important}.align-self-lg-stretch{align-self:stretch!important}.float-lg-left{float:left!important}.float-lg-right{float:right!important}.float-lg-none{float:none!important}.m-lg-0{margin:0!important}.mt-lg-0,.my-lg-0{margin-top:0!important}.mr-lg-0,.mx-lg-0{margin-right:0!important}.mb-lg-0,.my-lg-0{margin-bottom:0!important}.ml-lg-0,.mx-lg-0{margin-left:0!important}.m-lg-1{margin:.25rem!important}.mt-lg-1,.my-lg-1{margin-top:.25rem!important}.mr-lg-1,.mx-lg-1{margin-right:.25rem!important}.mb-lg-1,.my-lg-1{margin-bottom:.25rem!important}.ml-lg-1,.mx-lg-1{margin-left:.25rem!important}.m-lg-2{margin:.5rem!important}.mt-lg-2,.my-lg-2{margin-top:.5rem!important}.mr-lg-2,.mx-lg-2{margin-right:.5rem!important}.mb-lg-2,.my-lg-2{margin-bottom:.5rem!important}.ml-lg-2,.mx-lg-2{margin-left:.5rem!important}.m-lg-3{margin:1rem!important}.mt-lg-3,.my-lg-3{margin-top:1rem!important}.mr-lg-3,.mx-lg-3{margin-right:1rem!important}.mb-lg-3,.my-lg-3{margin-bottom:1rem!important}.ml-lg-3,.mx-lg-3{margin-left:1rem!important}.m-lg-4{margin:1.5rem!important}.mt-lg-4,.my-lg-4{margin-top:1.5rem!important}.mr-lg-4,.mx-lg-4{margin-right:1.5rem!important}.mb-lg-4,.my-lg-4{margin-bottom:1.5rem!important}.ml-lg-4,.mx-lg-4{margin-left:1.5rem!important}.m-lg-5{margin:3rem!important}.mt-lg-5,.my-lg-5{margin-top:3rem!important}.mr-lg-5,.mx-lg-5{margin-right:3rem!important}.mb-lg-5,.my-lg-5{margin-bottom:3rem!important}.ml-lg-5,.mx-lg-5{margin-left:3rem!important}.p-lg-0{padding:0!important}.pt-lg-0,.py-lg-0{padding-top:0!important}.pr-lg-0,.px-lg-0{padding-right:0!important}.pb-lg-0,.py-lg-0{padding-bottom:0!important}.pl-lg-0,.px-lg-0{padding-left:0!important}.p-lg-1{padding:.25rem!important}.pt-lg-1,.py-lg-1{padding-top:.25rem!important}.pr-lg-1,.px-lg-1{padding-right:.25rem!important}.pb-lg-1,.py-lg-1{padding-bottom:.25rem!important}.pl-lg-1,.px-lg-1{padding-left:.25rem!important}.p-lg-2{padding:.5rem!important}.pt-lg-2,.py-lg-2{padding-top:.5rem!important}.pr-lg-2,.px-lg-2{padding-right:.5rem!important}.pb-lg-2,.py-lg-2{padding-bottom:.5rem!important}.pl-lg-2,.px-lg-2{padding-left:.5rem!important}.p-lg-3{padding:1rem!important}.pt-lg-3,.py-lg-3{padding-top:1rem!important}.pr-lg-3,.px-lg-3{padding-right:1rem!important}.pb-lg-3,.py-lg-3{padding-bottom:1rem!important}.pl-lg-3,.px-lg-3{padding-left:1rem!important}.p-lg-4{padding:1.5rem!important}.pt-lg-4,.py-lg-4{padding-top:1.5rem!important}.pr-lg-4,.px-lg-4{padding-right:1.5rem!important}.pb-lg-4,.py-lg-4{padding-bottom:1.5rem!important}.pl-lg-4,.px-lg-4{padding-left:1.5rem!important}.p-lg-5{padding:3rem!important}.pt-lg-5,.py-lg-5{padding-top:3rem!important}.pr-lg-5,.px-lg-5{padding-right:3rem!important}.pb-lg-5,.py-lg-5{padding-bottom:3rem!important}.pl-lg-5,.px-lg-5{padding-left:3rem!important}.m-lg-auto{margin:auto!important}.mt-lg-auto,.my-lg-auto{margin-top:auto!important}.mr-lg-auto,.mx-lg-auto{margin-right:auto!important}.mb-lg-auto,.my-lg-auto{margin-bottom:auto!important}.ml-lg-auto,.mx-lg-auto{margin-left:auto!important}.text-lg-left{text-align:left!important}.text-lg-right{text-align:right!important}.text-lg-center{text-align:center!important}}@media (min-width:1200px){.d-xl-none{display:none!important}.d-xl-inline{display:inline!important}.d-xl-inline-block{display:inline-block!important}.d-xl-block{display:block!important}.d-xl-table{display:table!important}.d-xl-table-row{display:table-row!important}.d-xl-table-cell{display:table-cell!important}.d-xl-flex{display:flex!important}.d-xl-inline-flex{display:inline-flex!important}.flex-xl-row{flex-direction:row!important}.flex-xl-column{flex-direction:column!important}.flex-xl-row-reverse{flex-direction:row-reverse!important}.flex-xl-column-reverse{flex-direction:column-reverse!important}.flex-xl-wrap{flex-wrap:wrap!important}.flex-xl-nowrap{flex-wrap:nowrap!important}.flex-xl-wrap-reverse{flex-wrap:wrap-reverse!important}.flex-xl-fill{flex-grow:1!important;flex-shrink:1!important;flex-basis:auto!important}.flex-xl-grow-0{flex-grow:0!important}.flex-xl-grow-1{flex-grow:1!important}.flex-xl-shrink-0{flex-shrink:0!important}.flex-xl-shrink-1{flex-shrink:1!important}.justify-content-xl-start{justify-content:flex-start!important}.justify-content-xl-end{justify-content:flex-end!important}.justify-content-xl-center{justify-content:center!important}.justify-content-xl-between{justify-content:space-between!important}.justify-content-xl-around{justify-content:space-around!important}.align-items-xl-start{align-items:flex-start!important}.align-items-xl-end{align-items:flex-end!important}.align-items-xl-center{align-items:center!important}.align-items-xl-baseline{align-items:baseline!important}.align-items-xl-stretch{align-items:stretch!important}.align-content-xl-start{align-content:flex-start!important}.align-content-xl-end{align-content:flex-end!important}.align-content-xl-center{align-content:center!important}.align-content-xl-between{align-content:space-between!important}.align-content-xl-around{align-content:space-around!important}.align-content-xl-stretch{align-content:stretch!important}.align-self-xl-auto{align-self:auto!important}.align-self-xl-start{align-self:flex-start!important}.align-self-xl-end{align-self:flex-end!important}.align-self-xl-center{align-self:center!important}.align-self-xl-baseline{align-self:baseline!important}.align-self-xl-stretch{align-self:stretch!important}.float-xl-left{float:left!important}.float-xl-right{float:right!important}.float-xl-none{float:none!important}.m-xl-0{margin:0!important}.mt-xl-0,.my-xl-0{margin-top:0!important}.mr-xl-0,.mx-xl-0{margin-right:0!important}.mb-xl-0,.my-xl-0{margin-bottom:0!important}.ml-xl-0,.mx-xl-0{margin-left:0!important}.m-xl-1{margin:.25rem!important}.mt-xl-1,.my-xl-1{margin-top:.25rem!important}.mr-xl-1,.mx-xl-1{margin-right:.25rem!important}.mb-xl-1,.my-xl-1{margin-bottom:.25rem!important}.ml-xl-1,.mx-xl-1{margin-left:.25rem!important}.m-xl-2{margin:.5rem!important}.mt-xl-2,.my-xl-2{margin-top:.5rem!important}.mr-xl-2,.mx-xl-2{margin-right:.5rem!important}.mb-xl-2,.my-xl-2{margin-bottom:.5rem!important}.ml-xl-2,.mx-xl-2{margin-left:.5rem!important}.m-xl-3{margin:1rem!important}.mt-xl-3,.my-xl-3{margin-top:1rem!important}.mr-xl-3,.mx-xl-3{margin-right:1rem!important}.mb-xl-3,.my-xl-3{margin-bottom:1rem!important}.ml-xl-3,.mx-xl-3{margin-left:1rem!important}.m-xl-4{margin:1.5rem!important}.mt-xl-4,.my-xl-4{margin-top:1.5rem!important}.mr-xl-4,.mx-xl-4{margin-right:1.5rem!important}.mb-xl-4,.my-xl-4{margin-bottom:1.5rem!important}.ml-xl-4,.mx-xl-4{margin-left:1.5rem!important}.m-xl-5{margin:3rem!important}.mt-xl-5,.my-xl-5{margin-top:3rem!important}.mr-xl-5,.mx-xl-5{margin-right:3rem!important}.mb-xl-5,.my-xl-5{margin-bottom:3rem!important}.ml-xl-5,.mx-xl-5{margin-left:3rem!important}.p-xl-0{padding:0!important}.pt-xl-0,.py-xl-0{padding-top:0!important}.pr-xl-0,.px-xl-0{padding-right:0!important}.pb-xl-0,.py-xl-0{padding-bottom:0!important}.pl-xl-0,.px-xl-0{padding-left:0!important}.p-xl-1{padding:.25rem!important}.pt-xl-1,.py-xl-1{padding-top:.25rem!important}.pr-xl-1,.px-xl-1{padding-right:.25rem!important}.pb-xl-1,.py-xl-1{padding-bottom:.25rem!important}.pl-xl-1,.px-xl-1{padding-left:.25rem!important}.p-xl-2{padding:.5rem!important}.pt-xl-2,.py-xl-2{padding-top:.5rem!important}.pr-xl-2,.px-xl-2{padding-right:.5rem!important}.pb-xl-2,.py-xl-2{padding-bottom:.5rem!important}.pl-xl-2,.px-xl-2{padding-left:.5rem!important}.p-xl-3{padding:1rem!important}.pt-xl-3,.py-xl-3{padding-top:1rem!important}.pr-xl-3,.px-xl-3{padding-right:1rem!important}.pb-xl-3,.py-xl-3{padding-bottom:1rem!important}.pl-xl-3,.px-xl-3{padding-left:1rem!important}.p-xl-4{padding:1.5rem!important}.pt-xl-4,.py-xl-4{padding-top:1.5rem!important}.pr-xl-4,.px-xl-4{padding-right:1.5rem!important}.pb-xl-4,.py-xl-4{padding-bottom:1.5rem!important}.pl-xl-4,.px-xl-4{padding-left:1.5rem!important}.p-xl-5{padding:3rem!important}.pt-xl-5,.py-xl-5{padding-top:3rem!important}.pr-xl-5,.px-xl-5{padding-right:3rem!important}.pb-xl-5,.py-xl-5{padding-bottom:3rem!important}.pl-xl-5,.px-xl-5{padding-left:3rem!important}.m-xl-auto{margin:auto!important}.mt-xl-auto,.my-xl-auto{margin-top:auto!important}.mr-xl-auto,.mx-xl-auto{margin-right:auto!important}.mb-xl-auto,.my-xl-auto{margin-bottom:auto!important}.ml-xl-auto,.mx-xl-auto{margin-left:auto!important}.text-xl-left{text-align:left!important}.text-xl-right{text-align:right!important}.text-xl-center{text-align:center!important}}@media (min-width:1690px){.d-el-none{display:none!important}.d-el-inline{display:inline!important}.d-el-inline-block{display:inline-block!important}.d-el-block{display:block!important}.d-el-table{display:table!important}.d-el-table-row{display:table-row!important}.d-el-table-cell{display:table-cell!important}.d-el-flex{display:flex!important}.d-el-inline-flex{display:inline-flex!important}.flex-el-row{flex-direction:row!important}.flex-el-column{flex-direction:column!important}.flex-el-row-reverse{flex-direction:row-reverse!important}.flex-el-column-reverse{flex-direction:column-reverse!important}.flex-el-wrap{flex-wrap:wrap!important}.flex-el-nowrap{flex-wrap:nowrap!important}.flex-el-wrap-reverse{flex-wrap:wrap-reverse!important}.flex-el-fill{flex-grow:1!important;flex-shrink:1!important;flex-basis:auto!important}.flex-el-grow-0{flex-grow:0!important}.flex-el-grow-1{flex-grow:1!important}.flex-el-shrink-0{flex-shrink:0!important}.flex-el-shrink-1{flex-shrink:1!important}.justify-content-el-start{justify-content:flex-start!important}.justify-content-el-end{justify-content:flex-end!important}.justify-content-el-center{justify-content:center!important}.justify-content-el-between{justify-content:space-between!important}.justify-content-el-around{justify-content:space-around!important}.align-items-el-start{align-items:flex-start!important}.align-items-el-end{align-items:flex-end!important}.align-items-el-center{align-items:center!important}.align-items-el-baseline{align-items:baseline!important}.align-items-el-stretch{align-items:stretch!important}.align-content-el-start{align-content:flex-start!important}.align-content-el-end{align-content:flex-end!important}.align-content-el-center{align-content:center!important}.align-content-el-between{align-content:space-between!important}.align-content-el-around{align-content:space-around!important}.align-content-el-stretch{align-content:stretch!important}.align-self-el-auto{align-self:auto!important}.align-self-el-start{align-self:flex-start!important}.align-self-el-end{align-self:flex-end!important}.align-self-el-center{align-self:center!important}.align-self-el-baseline{align-self:baseline!important}.align-self-el-stretch{align-self:stretch!important}.float-el-left{float:left!important}.float-el-right{float:right!important}.float-el-none{float:none!important}.m-el-0{margin:0!important}.mt-el-0,.my-el-0{margin-top:0!important}.mr-el-0,.mx-el-0{margin-right:0!important}.mb-el-0,.my-el-0{margin-bottom:0!important}.ml-el-0,.mx-el-0{margin-left:0!important}.m-el-1{margin:.25rem!important}.mt-el-1,.my-el-1{margin-top:.25rem!important}.mr-el-1,.mx-el-1{margin-right:.25rem!important}.mb-el-1,.my-el-1{margin-bottom:.25rem!important}.ml-el-1,.mx-el-1{margin-left:.25rem!important}.m-el-2{margin:.5rem!important}.mt-el-2,.my-el-2{margin-top:.5rem!important}.mr-el-2,.mx-el-2{margin-right:.5rem!important}.mb-el-2,.my-el-2{margin-bottom:.5rem!important}.ml-el-2,.mx-el-2{margin-left:.5rem!important}.m-el-3{margin:1rem!important}.mt-el-3,.my-el-3{margin-top:1rem!important}.mr-el-3,.mx-el-3{margin-right:1rem!important}.mb-el-3,.my-el-3{margin-bottom:1rem!important}.ml-el-3,.mx-el-3{margin-left:1rem!important}.m-el-4{margin:1.5rem!important}.mt-el-4,.my-el-4{margin-top:1.5rem!important}.mr-el-4,.mx-el-4{margin-right:1.5rem!important}.mb-el-4,.my-el-4{margin-bottom:1.5rem!important}.ml-el-4,.mx-el-4{margin-left:1.5rem!important}.m-el-5{margin:3rem!important}.mt-el-5,.my-el-5{margin-top:3rem!important}.mr-el-5,.mx-el-5{margin-right:3rem!important}.mb-el-5,.my-el-5{margin-bottom:3rem!important}.ml-el-5,.mx-el-5{margin-left:3rem!important}.p-el-0{padding:0!important}.pt-el-0,.py-el-0{padding-top:0!important}.pr-el-0,.px-el-0{padding-right:0!important}.pb-el-0,.py-el-0{padding-bottom:0!important}.pl-el-0,.px-el-0{padding-left:0!important}.p-el-1{padding:.25rem!important}.pt-el-1,.py-el-1{padding-top:.25rem!important}.pr-el-1,.px-el-1{padding-right:.25rem!important}.pb-el-1,.py-el-1{padding-bottom:.25rem!important}.pl-el-1,.px-el-1{padding-left:.25rem!important}.p-el-2{padding:.5rem!important}.pt-el-2,.py-el-2{padding-top:.5rem!important}.pr-el-2,.px-el-2{padding-right:.5rem!important}.pb-el-2,.py-el-2{padding-bottom:.5rem!important}.pl-el-2,.px-el-2{padding-left:.5rem!important}.p-el-3{padding:1rem!important}.pt-el-3,.py-el-3{padding-top:1rem!important}.pr-el-3,.px-el-3{padding-right:1rem!important}.pb-el-3,.py-el-3{padding-bottom:1rem!important}.pl-el-3,.px-el-3{padding-left:1rem!important}.p-el-4{padding:1.5rem!important}.pt-el-4,.py-el-4{padding-top:1.5rem!important}.pr-el-4,.px-el-4{padding-right:1.5rem!important}.pb-el-4,.py-el-4{padding-bottom:1.5rem!important}.pl-el-4,.px-el-4{padding-left:1.5rem!important}.p-el-5{padding:3rem!important}.pt-el-5,.py-el-5{padding-top:3rem!important}.pr-el-5,.px-el-5{padding-right:3rem!important}.pb-el-5,.py-el-5{padding-bottom:3rem!important}.pl-el-5,.px-el-5{padding-left:3rem!important}.m-el-auto{margin:auto!important}.mt-el-auto,.my-el-auto{margin-top:auto!important}.mr-el-auto,.mx-el-auto{margin-right:auto!important}.mb-el-auto,.my-el-auto{margin-bottom:auto!important}.ml-el-auto,.mx-el-auto{margin-left:auto!important}.text-el-left{text-align:left!important}.text-el-right{text-align:right!important}.text-el-center{text-align:center!important}}.f-text-lowercase{text-transform:lowercase!important}.f-text-uppercase{text-transform:uppercase!important}.f-text-capitalize{text-transform:capitalize!important}.f-font-weight-light{font-weight:300!important}.f-font-weight-normal{font-weight:400!important}.f-font-weight-bold{font-weight:700!important}.f-font-italic{font-style:italic!important}.f-text-white{color:#fff!important}.text-primary{color:#2A87FF!important}a.text-primary:focus,a.text-primary:hover{color:#006bf6!important}.text-secondary{color:#6c757d!important}a.text-secondary:focus,a.text-secondary:hover{color:#545b62!important}.text-success{color:#6CC77F!important}a.text-success:focus,a.text-success:hover{color:#47b95f!important}.text-info{color:#5EA4FF!important}a.text-info:focus,a.text-info:hover{color:#2b87ff!important}.text-warning{color:#F5A144!important}a.text-warning:focus,a.text-warning:hover{color:#f28914!important}.text-danger{color:#dc3545!important}a.text-danger:focus,a.text-danger:hover{color:#bd2130!important}.text-light{color:#f8f9fa!important}a.text-light:focus,a.text-light:hover{color:#dae0e5!important}.text-dark{color:#343a40!important}a.text-dark:focus,a.text-dark:hover{color:#1d2124!important}.f-text-body{color:#2D2F33!important}.f-text-muted{color:#A8ADB8!important}.f-text-black-50{color:rgba(0,0,0,.5)!important}.f-text-white-50{color:rgba(255,255,255,.5)!important}.f-text-hide{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}.visible{visibility:visible!important}.invisible{visibility:hidden!important}@media print{.d-print-none{display:none!important}.d-print-inline{display:inline!important}.d-print-inline-block{display:inline-block!important}.d-print-block{display:block!important}.d-print-table{display:table!important}.d-print-table-row{display:table-row!important}.d-print-table-cell{display:table-cell!important}.d-print-flex{display:flex!important}.d-print-inline-flex{display:inline-flex!important}blockquote,img,pre,tr{page-break-inside:avoid}*,::after,::before{text-shadow:none!important;box-shadow:none!important}a:not(.btn){text-decoration:underline}abbr[title]::after{content:" (" f-attr(title) ")"}pre{white-space:pre-wrap!important}blockquote,pre{border:1px solid #adb5bd}thead{display:table-header-group}h2,h3,p{orphans:3;widows:3}h2,h3{page-break-after:avoid}.container,body{min-width:888px!important}.navbar{display:none}.badge{border:1px solid #000}.table{border-collapse:collapse!important}.table td,.table th{background-color:#fff!important}.table-bordered td,.table-bordered th{border:1px solid #dee2e6!important}.table-dark{color:inherit}.table-dark tbody+tbody,.table-dark td,.table-dark th,.table-dark thead th{border-color:#EAECF3}.table .thead-dark th{color:inherit;border-color:#EAECF3}} \ No newline at end of file +@charset "UTF-8";article,aside,figcaption,figure,footer,header,hgroup,legend,main,nav,section{display:block}.dropdown-menu,.form-control,body{font-size:.8125rem}.popover,.tooltip,address{font-style:normal}.collapsing,.dropdown-divider,.modal-open,.progress,svg{overflow:hidden}img,svg{vertical-align:middle}.dropdown-menu,body,caption{text-align:left}.popover,.tooltip,button,select{text-transform:none}pre,textarea{overflow:auto}progress,sub,sup{vertical-align:baseline}label,output{display:inline-block}.close:not(:disabled):not(.disabled),.dropdown-item,.navbar-toggler:not(:disabled):not(.disabled),.page-link:not(:disabled):not(.disabled),summary{cursor:pointer}:root{--blue:#007bff;--indigo:#6610f2;--purple:#6f42c1;--pink:#e83e8c;--red:#dc3545;--orange:#fd7e14;--yellow:#ffc107;--green:#28a745;--teal:#20c997;--cyan:#17a2b8;--white:#fff;--gray:#6c757d;--gray-dark:#343a40;--primary:#2A87FF;--secondary:#6c757d;--success:#6CC77F;--info:#5EA4FF;--warning:#F5A144;--danger:#dc3545;--light:#f8f9fa;--dark:#343a40;--breakpoint-xs:0;--breakpoint-sm:576px;--breakpoint-md:768px;--breakpoint-lg:888px;--breakpoint-xl:1200px;--breakpoint-el:1690px;--font-family-sans-serif:f-inspect(-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji");--font-family-monospace:f-inspect(SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace)}*,::after,::before{box-sizing:border-box}html{font-family:sans-serif;line-height:1.15;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%;-ms-overflow-style:scrollbar;-webkit-tap-highlight-color:transparent}body{margin:0;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI","PingFang SC","Hiragino Sans GB","Microsoft YaHei","Helvetica Neue",Helvetica,Arial,sans-serif;font-weight:400;line-height:1.4286;color:#2D2F33;background-color:#fff}.f-text-monospace,code,kbd,pre,samp{font-family:SFMono-Regular,Menlo,Monaco,Consolas,"Liberation Mono","Courier New",monospace}.close,.f-alert-link,dt,kbd kbd{font-weight:700}[tabindex="-1"]:focus{outline:0!important}h1,h2,h3,h4,h5,h6{margin-top:0;margin-bottom:.5rem}dl,ol,p,ul{margin-top:0;margin-bottom:1rem}abbr[data-original-title],abbr[title]{-webkit-text-decoration:underline dotted;text-decoration:underline dotted;cursor:help;border-bottom:0}address{margin-bottom:1rem;line-height:inherit}ol ol,ol ul,ul ol,ul ul{margin-bottom:0}dd{margin-bottom:.5rem;margin-left:0}blockquote,figure{margin:0 0 1rem}dfn{font-style:italic}b,strong{font-weight:bolder}small{font-size:80%}sub,sup{position:relative;font-size:75%;line-height:0}sub{bottom:-.25em}sup{top:-.5em}a{color:#2A87FF;text-decoration:none;background-color:transparent;-webkit-text-decoration-skip:objects}a:hover{color:#529DFF;text-decoration:none}a:not([href]):not([tabindex]),a:not([href]):not([tabindex]):focus,a:not([href]):not([tabindex]):hover{color:inherit;text-decoration:none}a:not([href]):not([tabindex]):focus{outline:0}code,kbd,pre,samp{font-size:1em}pre{margin-top:0;margin-bottom:1rem;-ms-overflow-style:scrollbar}img{border-style:none}table{border-collapse:collapse}caption{padding-top:.75rem;padding-bottom:.75rem;color:#A8ADB8;caption-side:bottom}th{text-align:inherit}label{margin-bottom:.3125rem}button{border-radius:0}button:focus{outline:dotted 1px;outline:-webkit-focus-ring-color auto 5px}button,input,optgroup,select,textarea{margin:0;font-family:inherit;font-size:inherit;line-height:inherit}button,input{overflow:visible}button [type=reset],button [type=submit],button button,button html [type=button],select [type=reset],select [type=submit],select button,select html [type=button]{-webkit-appearance:button}[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner,button::-moz-focus-inner{padding:0;border-style:none}input[type=radio],input[type=checkbox]{box-sizing:border-box;padding:0}input[type=date],input[type=time],input[type=datetime-local],input[type=month]{-webkit-appearance:listbox}textarea{resize:vertical}fieldset{min-width:0;padding:0;margin:0;border:0}legend{width:100%;max-width:100%;padding:0;margin-bottom:.5rem;font-size:1.5rem;line-height:inherit;color:inherit;white-space:normal}[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}[type=search]{outline-offset:-2px;-webkit-appearance:none}[type=search]::-webkit-search-cancel-button,[type=search]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{font:inherit;-webkit-appearance:button}summary{display:list-item}template{display:none}[hidden]{display:none!important}.h1,.h2,.h3,.h4,.h5,.h6,h1,h2,h3,h4,h5,h6{margin-bottom:.5rem;font-family:inherit;font-weight:400;line-height:1.2;color:inherit}.blockquote,.table,hr{margin-bottom:1rem}.display-1,.display-2,.display-3,.display-4,.lead{font-weight:300}.h1,h1{font-size:1.625rem}.h2,h2{font-size:1.5rem}.h3,h3{font-size:1.375rem}.h4,h4{font-size:1.25rem}.h5,h5{font-size:1rem}.h6,h6{font-size:.875rem}.lead{font-size:1.01563rem}.display-1{font-size:6rem;line-height:1.2}.display-2{font-size:5.5rem;line-height:1.2}.display-3{font-size:4.5rem;line-height:1.2}.display-4{font-size:3.5rem;line-height:1.2}hr{box-sizing:content-box;height:0;overflow:visible;margin-top:1rem;border:0;border-top:1px solid rgba(0,0,0,.1)}.img-fluid,.img-thumbnail{max-width:100%;height:auto}.small,small{font-size:80%;font-weight:400}.mark,mark{padding:.2em;background-color:#fcf8e3}.list-inline,.list-unstyled{padding-left:0;list-style:none}.list-inline-item{display:inline-block}.list-inline-item:not(:last-child){margin-right:.5rem}.initialism{font-size:90%;text-transform:uppercase}.blockquote{font-size:1.01563rem}.blockquote-footer{display:block;font-size:80%;color:#6c757d}.blockquote-footer::before{content:"\2014 \00A0"}.img-thumbnail{padding:.25rem;background-color:#fff;border:1px solid #dee2e6;border-radius:3px;box-shadow:0 1px 2px rgba(0,0,0,.075)}.figure{display:inline-block}.figure-img{margin-bottom:.5rem;line-height:1}.figure-caption{font-size:90%;color:#6c757d}code,kbd{font-size:87.5%}.f-alert-dismissible .f-close,.f-alert-heading,.popover-header,a>code,pre code{color:inherit}code{color:#e83e8c;word-break:break-word}kbd{padding:.2rem .4rem;color:#fff;background-color:#212529;border-radius:3px;box-shadow:inset 0 -.1rem 0 rgba(0,0,0,.25)}.table,.table .table{background-color:#fff}kbd kbd{padding:0;font-size:100%;box-shadow:none}.container,.container-fluid{padding-right:14px;padding-left:14px;margin-right:auto;margin-left:auto;width:100%}pre{display:block;font-size:87.5%;color:#212529}pre code{font-size:inherit;word-break:normal}.pre-scrollable{max-height:21.25rem;overflow-y:scroll}@media (min-width:576px){.container{max-width:540px}}@media (min-width:768px){.container{max-width:720px}}@media (min-width:888px){.container{max-width:960px}}@media (min-width:1200px){.container{max-width:1140px}}.row{display:flex;flex-wrap:wrap;margin-right:-14px;margin-left:-14px}.no-gutters{margin-right:0;margin-left:0}.no-gutters>.col,.no-gutters>[class*=col-]{padding-right:0;padding-left:0}.col,.col-1,.col-10,.col-11,.col-12,.col-2,.col-3,.col-4,.col-5,.col-6,.col-7,.col-8,.col-9,.col-auto,.col-el,.col-el-1,.col-el-10,.col-el-11,.col-el-12,.col-el-2,.col-el-3,.col-el-4,.col-el-5,.col-el-6,.col-el-7,.col-el-8,.col-el-9,.col-el-auto,.col-lg,.col-lg-1,.col-lg-10,.col-lg-11,.col-lg-12,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9,.col-lg-auto,.col-md,.col-md-1,.col-md-10,.col-md-11,.col-md-12,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9,.col-md-auto,.col-sm,.col-sm-1,.col-sm-10,.col-sm-11,.col-sm-12,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9,.col-sm-auto,.col-xl,.col-xl-1,.col-xl-10,.col-xl-11,.col-xl-12,.col-xl-2,.col-xl-3,.col-xl-4,.col-xl-5,.col-xl-6,.col-xl-7,.col-xl-8,.col-xl-9,.col-xl-auto{position:relative;width:100%;min-height:1px;padding-right:14px;padding-left:14px}.col{flex-basis:0;flex-grow:1;max-width:100%}.col-auto{flex-grow:0;flex-shrink:0;flex-basis:auto;width:auto;max-width:none}.col-1{flex-grow:0;flex-shrink:0;flex-basis:8.33333%;max-width:8.33333%}.col-2{flex-grow:0;flex-shrink:0;flex-basis:16.66667%;max-width:16.66667%}.col-3{flex-grow:0;flex-shrink:0;flex-basis:25%;max-width:25%}.col-4{flex-grow:0;flex-shrink:0;flex-basis:33.33333%;max-width:33.33333%}.col-5{flex-grow:0;flex-shrink:0;flex-basis:41.66667%;max-width:41.66667%}.col-6{flex-grow:0;flex-shrink:0;flex-basis:50%;max-width:50%}.col-7{flex-grow:0;flex-shrink:0;flex-basis:58.33333%;max-width:58.33333%}.col-8{flex-grow:0;flex-shrink:0;flex-basis:66.66667%;max-width:66.66667%}.col-9{flex-grow:0;flex-shrink:0;flex-basis:75%;max-width:75%}.col-10{flex-grow:0;flex-shrink:0;flex-basis:83.33333%;max-width:83.33333%}.col-11{flex-grow:0;flex-shrink:0;flex-basis:91.66667%;max-width:91.66667%}.col-12{flex-grow:0;flex-shrink:0;flex-basis:100%;max-width:100%}.order-first{order:-1}.order-last{order:13}.order-0{order:0}.order-1{order:1}.order-2{order:2}.order-3{order:3}.order-4{order:4}.order-5{order:5}.order-6{order:6}.order-7{order:7}.order-8{order:8}.order-9{order:9}.order-10{order:10}.order-11{order:11}.order-12{order:12}.offset-1{margin-left:8.33333%}.offset-2{margin-left:16.66667%}.offset-3{margin-left:25%}.offset-4{margin-left:33.33333%}.offset-5{margin-left:41.66667%}.offset-6{margin-left:50%}.offset-7{margin-left:58.33333%}.offset-8{margin-left:66.66667%}.offset-9{margin-left:75%}.offset-10{margin-left:83.33333%}.offset-11{margin-left:91.66667%}.f-area-response [class*=col-xs]{flex:none;max-width:none}.f-area-response.f-area-response--xs .col-xs-1{flex-grow:0;flex-shrink:0;flex-basis:8.33333%;max-width:8.33333%}.f-area-response.f-area-response--xs .col-xs-2{flex-grow:0;flex-shrink:0;flex-basis:16.66667%;max-width:16.66667%}.f-area-response.f-area-response--xs .col-xs-3{flex-grow:0;flex-shrink:0;flex-basis:25%;max-width:25%}.f-area-response.f-area-response--xs .col-xs-4{flex-grow:0;flex-shrink:0;flex-basis:33.33333%;max-width:33.33333%}.f-area-response.f-area-response--xs .col-xs-5{flex-grow:0;flex-shrink:0;flex-basis:41.66667%;max-width:41.66667%}.f-area-response.f-area-response--xs .col-xs-6{flex-grow:0;flex-shrink:0;flex-basis:50%;max-width:50%}.f-area-response.f-area-response--xs .col-xs-7{flex-grow:0;flex-shrink:0;flex-basis:58.33333%;max-width:58.33333%}.f-area-response.f-area-response--xs .col-xs-8{flex-grow:0;flex-shrink:0;flex-basis:66.66667%;max-width:66.66667%}.f-area-response.f-area-response--xs .col-xs-9{flex-grow:0;flex-shrink:0;flex-basis:75%;max-width:75%}.f-area-response.f-area-response--xs .col-xs-10{flex-grow:0;flex-shrink:0;flex-basis:83.33333%;max-width:83.33333%}.f-area-response.f-area-response--xs .col-xs-11{flex-grow:0;flex-shrink:0;flex-basis:91.66667%;max-width:91.66667%}.f-area-response.f-area-response--xs .col-xs-12{flex-grow:0;flex-shrink:0;flex-basis:100%;max-width:100%}@media (min-width:576px){.col-sm{flex-basis:0;flex-grow:1;max-width:100%}.col-sm-auto{flex-grow:0;flex-shrink:0;flex-basis:auto;width:auto;max-width:none}.col-sm-1{flex-grow:0;flex-shrink:0;flex-basis:8.33333%;max-width:8.33333%}.col-sm-2{flex-grow:0;flex-shrink:0;flex-basis:16.66667%;max-width:16.66667%}.col-sm-3{flex-grow:0;flex-shrink:0;flex-basis:25%;max-width:25%}.col-sm-4{flex-grow:0;flex-shrink:0;flex-basis:33.33333%;max-width:33.33333%}.col-sm-5{flex-grow:0;flex-shrink:0;flex-basis:41.66667%;max-width:41.66667%}.col-sm-6{flex-grow:0;flex-shrink:0;flex-basis:50%;max-width:50%}.col-sm-7{flex-grow:0;flex-shrink:0;flex-basis:58.33333%;max-width:58.33333%}.col-sm-8{flex-grow:0;flex-shrink:0;flex-basis:66.66667%;max-width:66.66667%}.col-sm-9{flex-grow:0;flex-shrink:0;flex-basis:75%;max-width:75%}.col-sm-10{flex-grow:0;flex-shrink:0;flex-basis:83.33333%;max-width:83.33333%}.col-sm-11{flex-grow:0;flex-shrink:0;flex-basis:91.66667%;max-width:91.66667%}.col-sm-12{flex-grow:0;flex-shrink:0;flex-basis:100%;max-width:100%}.order-sm-first{order:-1}.order-sm-last{order:13}.order-sm-0{order:0}.order-sm-1{order:1}.order-sm-2{order:2}.order-sm-3{order:3}.order-sm-4{order:4}.order-sm-5{order:5}.order-sm-6{order:6}.order-sm-7{order:7}.order-sm-8{order:8}.order-sm-9{order:9}.order-sm-10{order:10}.order-sm-11{order:11}.order-sm-12{order:12}.offset-sm-0{margin-left:0}.offset-sm-1{margin-left:8.33333%}.offset-sm-2{margin-left:16.66667%}.offset-sm-3{margin-left:25%}.offset-sm-4{margin-left:33.33333%}.offset-sm-5{margin-left:41.66667%}.offset-sm-6{margin-left:50%}.offset-sm-7{margin-left:58.33333%}.offset-sm-8{margin-left:66.66667%}.offset-sm-9{margin-left:75%}.offset-sm-10{margin-left:83.33333%}.offset-sm-11{margin-left:91.66667%}}.f-area-response [class*=col-sm]{flex:none;max-width:none}.f-area-response.f-area-response--sm .col-sm-1{flex-grow:0;flex-shrink:0;flex-basis:8.33333%;max-width:8.33333%}.f-area-response.f-area-response--sm .col-sm-2{flex-grow:0;flex-shrink:0;flex-basis:16.66667%;max-width:16.66667%}.f-area-response.f-area-response--sm .col-sm-3{flex-grow:0;flex-shrink:0;flex-basis:25%;max-width:25%}.f-area-response.f-area-response--sm .col-sm-4{flex-grow:0;flex-shrink:0;flex-basis:33.33333%;max-width:33.33333%}.f-area-response.f-area-response--sm .col-sm-5{flex-grow:0;flex-shrink:0;flex-basis:41.66667%;max-width:41.66667%}.f-area-response.f-area-response--sm .col-sm-6{flex-grow:0;flex-shrink:0;flex-basis:50%;max-width:50%}.f-area-response.f-area-response--sm .col-sm-7{flex-grow:0;flex-shrink:0;flex-basis:58.33333%;max-width:58.33333%}.f-area-response.f-area-response--sm .col-sm-8{flex-grow:0;flex-shrink:0;flex-basis:66.66667%;max-width:66.66667%}.f-area-response.f-area-response--sm .col-sm-9{flex-grow:0;flex-shrink:0;flex-basis:75%;max-width:75%}.f-area-response.f-area-response--sm .col-sm-10{flex-grow:0;flex-shrink:0;flex-basis:83.33333%;max-width:83.33333%}.f-area-response.f-area-response--sm .col-sm-11{flex-grow:0;flex-shrink:0;flex-basis:91.66667%;max-width:91.66667%}.f-area-response.f-area-response--sm .col-sm-12{flex-grow:0;flex-shrink:0;flex-basis:100%;max-width:100%}@media (min-width:768px){.col-md{flex-basis:0;flex-grow:1;max-width:100%}.col-md-auto{flex-grow:0;flex-shrink:0;flex-basis:auto;width:auto;max-width:none}.col-md-1{flex-grow:0;flex-shrink:0;flex-basis:8.33333%;max-width:8.33333%}.col-md-2{flex-grow:0;flex-shrink:0;flex-basis:16.66667%;max-width:16.66667%}.col-md-3{flex-grow:0;flex-shrink:0;flex-basis:25%;max-width:25%}.col-md-4{flex-grow:0;flex-shrink:0;flex-basis:33.33333%;max-width:33.33333%}.col-md-5{flex-grow:0;flex-shrink:0;flex-basis:41.66667%;max-width:41.66667%}.col-md-6{flex-grow:0;flex-shrink:0;flex-basis:50%;max-width:50%}.col-md-7{flex-grow:0;flex-shrink:0;flex-basis:58.33333%;max-width:58.33333%}.col-md-8{flex-grow:0;flex-shrink:0;flex-basis:66.66667%;max-width:66.66667%}.col-md-9{flex-grow:0;flex-shrink:0;flex-basis:75%;max-width:75%}.col-md-10{flex-grow:0;flex-shrink:0;flex-basis:83.33333%;max-width:83.33333%}.col-md-11{flex-grow:0;flex-shrink:0;flex-basis:91.66667%;max-width:91.66667%}.col-md-12{flex-grow:0;flex-shrink:0;flex-basis:100%;max-width:100%}.order-md-first{order:-1}.order-md-last{order:13}.order-md-0{order:0}.order-md-1{order:1}.order-md-2{order:2}.order-md-3{order:3}.order-md-4{order:4}.order-md-5{order:5}.order-md-6{order:6}.order-md-7{order:7}.order-md-8{order:8}.order-md-9{order:9}.order-md-10{order:10}.order-md-11{order:11}.order-md-12{order:12}.offset-md-0{margin-left:0}.offset-md-1{margin-left:8.33333%}.offset-md-2{margin-left:16.66667%}.offset-md-3{margin-left:25%}.offset-md-4{margin-left:33.33333%}.offset-md-5{margin-left:41.66667%}.offset-md-6{margin-left:50%}.offset-md-7{margin-left:58.33333%}.offset-md-8{margin-left:66.66667%}.offset-md-9{margin-left:75%}.offset-md-10{margin-left:83.33333%}.offset-md-11{margin-left:91.66667%}}.f-area-response [class*=col-md]{flex:none;max-width:none}.f-area-response.f-area-response--md .col-md-1{flex-grow:0;flex-shrink:0;flex-basis:8.33333%;max-width:8.33333%}.f-area-response.f-area-response--md .col-md-2{flex-grow:0;flex-shrink:0;flex-basis:16.66667%;max-width:16.66667%}.f-area-response.f-area-response--md .col-md-3{flex-grow:0;flex-shrink:0;flex-basis:25%;max-width:25%}.f-area-response.f-area-response--md .col-md-4{flex-grow:0;flex-shrink:0;flex-basis:33.33333%;max-width:33.33333%}.f-area-response.f-area-response--md .col-md-5{flex-grow:0;flex-shrink:0;flex-basis:41.66667%;max-width:41.66667%}.f-area-response.f-area-response--md .col-md-6{flex-grow:0;flex-shrink:0;flex-basis:50%;max-width:50%}.f-area-response.f-area-response--md .col-md-7{flex-grow:0;flex-shrink:0;flex-basis:58.33333%;max-width:58.33333%}.f-area-response.f-area-response--md .col-md-8{flex-grow:0;flex-shrink:0;flex-basis:66.66667%;max-width:66.66667%}.f-area-response.f-area-response--md .col-md-9{flex-grow:0;flex-shrink:0;flex-basis:75%;max-width:75%}.f-area-response.f-area-response--md .col-md-10{flex-grow:0;flex-shrink:0;flex-basis:83.33333%;max-width:83.33333%}.f-area-response.f-area-response--md .col-md-11{flex-grow:0;flex-shrink:0;flex-basis:91.66667%;max-width:91.66667%}.f-area-response.f-area-response--md .col-md-12{flex-grow:0;flex-shrink:0;flex-basis:100%;max-width:100%}@media (min-width:888px){.col-lg{flex-basis:0;flex-grow:1;max-width:100%}.col-lg-auto{flex-grow:0;flex-shrink:0;flex-basis:auto;width:auto;max-width:none}.col-lg-1{flex-grow:0;flex-shrink:0;flex-basis:8.33333%;max-width:8.33333%}.col-lg-2{flex-grow:0;flex-shrink:0;flex-basis:16.66667%;max-width:16.66667%}.col-lg-3{flex-grow:0;flex-shrink:0;flex-basis:25%;max-width:25%}.col-lg-4{flex-grow:0;flex-shrink:0;flex-basis:33.33333%;max-width:33.33333%}.col-lg-5{flex-grow:0;flex-shrink:0;flex-basis:41.66667%;max-width:41.66667%}.col-lg-6{flex-grow:0;flex-shrink:0;flex-basis:50%;max-width:50%}.col-lg-7{flex-grow:0;flex-shrink:0;flex-basis:58.33333%;max-width:58.33333%}.col-lg-8{flex-grow:0;flex-shrink:0;flex-basis:66.66667%;max-width:66.66667%}.col-lg-9{flex-grow:0;flex-shrink:0;flex-basis:75%;max-width:75%}.col-lg-10{flex-grow:0;flex-shrink:0;flex-basis:83.33333%;max-width:83.33333%}.col-lg-11{flex-grow:0;flex-shrink:0;flex-basis:91.66667%;max-width:91.66667%}.col-lg-12{flex-grow:0;flex-shrink:0;flex-basis:100%;max-width:100%}.order-lg-first{order:-1}.order-lg-last{order:13}.order-lg-0{order:0}.order-lg-1{order:1}.order-lg-2{order:2}.order-lg-3{order:3}.order-lg-4{order:4}.order-lg-5{order:5}.order-lg-6{order:6}.order-lg-7{order:7}.order-lg-8{order:8}.order-lg-9{order:9}.order-lg-10{order:10}.order-lg-11{order:11}.order-lg-12{order:12}.offset-lg-0{margin-left:0}.offset-lg-1{margin-left:8.33333%}.offset-lg-2{margin-left:16.66667%}.offset-lg-3{margin-left:25%}.offset-lg-4{margin-left:33.33333%}.offset-lg-5{margin-left:41.66667%}.offset-lg-6{margin-left:50%}.offset-lg-7{margin-left:58.33333%}.offset-lg-8{margin-left:66.66667%}.offset-lg-9{margin-left:75%}.offset-lg-10{margin-left:83.33333%}.offset-lg-11{margin-left:91.66667%}}.f-area-response [class*=col-lg]{flex:none;max-width:none}.f-area-response.f-area-response--lg .col-lg-1{flex-grow:0;flex-shrink:0;flex-basis:8.33333%;max-width:8.33333%}.f-area-response.f-area-response--lg .col-lg-2{flex-grow:0;flex-shrink:0;flex-basis:16.66667%;max-width:16.66667%}.f-area-response.f-area-response--lg .col-lg-3{flex-grow:0;flex-shrink:0;flex-basis:25%;max-width:25%}.f-area-response.f-area-response--lg .col-lg-4{flex-grow:0;flex-shrink:0;flex-basis:33.33333%;max-width:33.33333%}.f-area-response.f-area-response--lg .col-lg-5{flex-grow:0;flex-shrink:0;flex-basis:41.66667%;max-width:41.66667%}.f-area-response.f-area-response--lg .col-lg-6{flex-grow:0;flex-shrink:0;flex-basis:50%;max-width:50%}.f-area-response.f-area-response--lg .col-lg-7{flex-grow:0;flex-shrink:0;flex-basis:58.33333%;max-width:58.33333%}.f-area-response.f-area-response--lg .col-lg-8{flex-grow:0;flex-shrink:0;flex-basis:66.66667%;max-width:66.66667%}.f-area-response.f-area-response--lg .col-lg-9{flex-grow:0;flex-shrink:0;flex-basis:75%;max-width:75%}.f-area-response.f-area-response--lg .col-lg-10{flex-grow:0;flex-shrink:0;flex-basis:83.33333%;max-width:83.33333%}.f-area-response.f-area-response--lg .col-lg-11{flex-grow:0;flex-shrink:0;flex-basis:91.66667%;max-width:91.66667%}.f-area-response.f-area-response--lg .col-lg-12{flex-grow:0;flex-shrink:0;flex-basis:100%;max-width:100%}@media (min-width:1200px){.col-xl{flex-basis:0;flex-grow:1;max-width:100%}.col-xl-auto{flex-grow:0;flex-shrink:0;flex-basis:auto;width:auto;max-width:none}.col-xl-1{flex-grow:0;flex-shrink:0;flex-basis:8.33333%;max-width:8.33333%}.col-xl-2{flex-grow:0;flex-shrink:0;flex-basis:16.66667%;max-width:16.66667%}.col-xl-3{flex-grow:0;flex-shrink:0;flex-basis:25%;max-width:25%}.col-xl-4{flex-grow:0;flex-shrink:0;flex-basis:33.33333%;max-width:33.33333%}.col-xl-5{flex-grow:0;flex-shrink:0;flex-basis:41.66667%;max-width:41.66667%}.col-xl-6{flex-grow:0;flex-shrink:0;flex-basis:50%;max-width:50%}.col-xl-7{flex-grow:0;flex-shrink:0;flex-basis:58.33333%;max-width:58.33333%}.col-xl-8{flex-grow:0;flex-shrink:0;flex-basis:66.66667%;max-width:66.66667%}.col-xl-9{flex-grow:0;flex-shrink:0;flex-basis:75%;max-width:75%}.col-xl-10{flex-grow:0;flex-shrink:0;flex-basis:83.33333%;max-width:83.33333%}.col-xl-11{flex-grow:0;flex-shrink:0;flex-basis:91.66667%;max-width:91.66667%}.col-xl-12{flex-grow:0;flex-shrink:0;flex-basis:100%;max-width:100%}.order-xl-first{order:-1}.order-xl-last{order:13}.order-xl-0{order:0}.order-xl-1{order:1}.order-xl-2{order:2}.order-xl-3{order:3}.order-xl-4{order:4}.order-xl-5{order:5}.order-xl-6{order:6}.order-xl-7{order:7}.order-xl-8{order:8}.order-xl-9{order:9}.order-xl-10{order:10}.order-xl-11{order:11}.order-xl-12{order:12}.offset-xl-0{margin-left:0}.offset-xl-1{margin-left:8.33333%}.offset-xl-2{margin-left:16.66667%}.offset-xl-3{margin-left:25%}.offset-xl-4{margin-left:33.33333%}.offset-xl-5{margin-left:41.66667%}.offset-xl-6{margin-left:50%}.offset-xl-7{margin-left:58.33333%}.offset-xl-8{margin-left:66.66667%}.offset-xl-9{margin-left:75%}.offset-xl-10{margin-left:83.33333%}.offset-xl-11{margin-left:91.66667%}}.f-area-response [class*=col-xl]{flex:none;max-width:none}.f-area-response.f-area-response--xl .col-xl-1{flex-grow:0;flex-shrink:0;flex-basis:8.33333%;max-width:8.33333%}.f-area-response.f-area-response--xl .col-xl-2{flex-grow:0;flex-shrink:0;flex-basis:16.66667%;max-width:16.66667%}.f-area-response.f-area-response--xl .col-xl-3{flex-grow:0;flex-shrink:0;flex-basis:25%;max-width:25%}.f-area-response.f-area-response--xl .col-xl-4{flex-grow:0;flex-shrink:0;flex-basis:33.33333%;max-width:33.33333%}.f-area-response.f-area-response--xl .col-xl-5{flex-grow:0;flex-shrink:0;flex-basis:41.66667%;max-width:41.66667%}.f-area-response.f-area-response--xl .col-xl-6{flex-grow:0;flex-shrink:0;flex-basis:50%;max-width:50%}.f-area-response.f-area-response--xl .col-xl-7{flex-grow:0;flex-shrink:0;flex-basis:58.33333%;max-width:58.33333%}.f-area-response.f-area-response--xl .col-xl-8{flex-grow:0;flex-shrink:0;flex-basis:66.66667%;max-width:66.66667%}.f-area-response.f-area-response--xl .col-xl-9{flex-grow:0;flex-shrink:0;flex-basis:75%;max-width:75%}.f-area-response.f-area-response--xl .col-xl-10{flex-grow:0;flex-shrink:0;flex-basis:83.33333%;max-width:83.33333%}.f-area-response.f-area-response--xl .col-xl-11{flex-grow:0;flex-shrink:0;flex-basis:91.66667%;max-width:91.66667%}.f-area-response.f-area-response--xl .col-xl-12{flex-grow:0;flex-shrink:0;flex-basis:100%;max-width:100%}@media (min-width:1690px){.col-el{flex-basis:0;flex-grow:1;max-width:100%}.col-el-auto{flex-grow:0;flex-shrink:0;flex-basis:auto;width:auto;max-width:none}.col-el-1{flex-grow:0;flex-shrink:0;flex-basis:8.33333%;max-width:8.33333%}.col-el-2{flex-grow:0;flex-shrink:0;flex-basis:16.66667%;max-width:16.66667%}.col-el-3{flex-grow:0;flex-shrink:0;flex-basis:25%;max-width:25%}.col-el-4{flex-grow:0;flex-shrink:0;flex-basis:33.33333%;max-width:33.33333%}.col-el-5{flex-grow:0;flex-shrink:0;flex-basis:41.66667%;max-width:41.66667%}.col-el-6{flex-grow:0;flex-shrink:0;flex-basis:50%;max-width:50%}.col-el-7{flex-grow:0;flex-shrink:0;flex-basis:58.33333%;max-width:58.33333%}.col-el-8{flex-grow:0;flex-shrink:0;flex-basis:66.66667%;max-width:66.66667%}.col-el-9{flex-grow:0;flex-shrink:0;flex-basis:75%;max-width:75%}.col-el-10{flex-grow:0;flex-shrink:0;flex-basis:83.33333%;max-width:83.33333%}.col-el-11{flex-grow:0;flex-shrink:0;flex-basis:91.66667%;max-width:91.66667%}.col-el-12{flex-grow:0;flex-shrink:0;flex-basis:100%;max-width:100%}.order-el-first{order:-1}.order-el-last{order:13}.order-el-0{order:0}.order-el-1{order:1}.order-el-2{order:2}.order-el-3{order:3}.order-el-4{order:4}.order-el-5{order:5}.order-el-6{order:6}.order-el-7{order:7}.order-el-8{order:8}.order-el-9{order:9}.order-el-10{order:10}.order-el-11{order:11}.order-el-12{order:12}.offset-el-0{margin-left:0}.offset-el-1{margin-left:8.33333%}.offset-el-2{margin-left:16.66667%}.offset-el-3{margin-left:25%}.offset-el-4{margin-left:33.33333%}.offset-el-5{margin-left:41.66667%}.offset-el-6{margin-left:50%}.offset-el-7{margin-left:58.33333%}.offset-el-8{margin-left:66.66667%}.offset-el-9{margin-left:75%}.offset-el-10{margin-left:83.33333%}.offset-el-11{margin-left:91.66667%}}.f-area-response [class*=col-el]{flex:none;max-width:none}.f-area-response.f-area-response--el .col-el-1{flex-grow:0;flex-shrink:0;flex-basis:8.33333%;max-width:8.33333%}.f-area-response.f-area-response--el .col-el-2{flex-grow:0;flex-shrink:0;flex-basis:16.66667%;max-width:16.66667%}.f-area-response.f-area-response--el .col-el-3{flex-grow:0;flex-shrink:0;flex-basis:25%;max-width:25%}.f-area-response.f-area-response--el .col-el-4{flex-grow:0;flex-shrink:0;flex-basis:33.33333%;max-width:33.33333%}.f-area-response.f-area-response--el .col-el-5{flex-grow:0;flex-shrink:0;flex-basis:41.66667%;max-width:41.66667%}.f-area-response.f-area-response--el .col-el-6{flex-grow:0;flex-shrink:0;flex-basis:50%;max-width:50%}.f-area-response.f-area-response--el .col-el-7{flex-grow:0;flex-shrink:0;flex-basis:58.33333%;max-width:58.33333%}.f-area-response.f-area-response--el .col-el-8{flex-grow:0;flex-shrink:0;flex-basis:66.66667%;max-width:66.66667%}.f-area-response.f-area-response--el .col-el-9{flex-grow:0;flex-shrink:0;flex-basis:75%;max-width:75%}.f-area-response.f-area-response--el .col-el-10{flex-grow:0;flex-shrink:0;flex-basis:83.33333%;max-width:83.33333%}.f-area-response.f-area-response--el .col-el-11{flex-grow:0;flex-shrink:0;flex-basis:91.66667%;max-width:91.66667%}.f-area-response.f-area-response--el .col-el-12{flex-grow:0;flex-shrink:0;flex-basis:100%;max-width:100%}.table{width:100%}.table td,.table th{padding:.75rem;vertical-align:top;border-top:1px solid #EAECF3}.table thead th{vertical-align:middle;border-bottom:2px solid #EAECF3}.table tbody+tbody{border-top:2px solid #EAECF3}.table-sm td,.table-sm th{padding:.3rem}.table-bordered,.table-bordered td,.table-bordered th{border:1px solid #EAECF3}.table-bordered thead td,.table-bordered thead th{border-bottom-width:2px}.table-borderless tbody+tbody,.table-borderless td,.table-borderless th,.table-borderless thead th{border:0}.table-striped tbody tr:nth-of-type(even){background-color:#F7F8FB}.table-hover tbody tr:hover{background-color:#EDF5FF}.table-primary,.table-primary>td,.table-primary>th{background-color:#c3ddff}.table-hover .table-primary:hover,.table-hover .table-primary:hover>td,.table-hover .table-primary:hover>th{background-color:#aacfff}.table-secondary,.table-secondary>td,.table-secondary>th{background-color:#d6d8db}.table-hover .table-secondary:hover,.table-hover .table-secondary:hover>td,.table-hover .table-secondary:hover>th{background-color:#c8cbcf}.table-success,.table-success>td,.table-success>th{background-color:#d6efdb}.table-hover .table-success:hover,.table-hover .table-success:hover>td,.table-hover .table-success:hover>th{background-color:#c4e8cb}.table-info,.table-info>td,.table-info>th{background-color:#d2e6ff}.table-hover .table-info:hover,.table-hover .table-info:hover>td,.table-hover .table-info:hover>th{background-color:#b9d8ff}.table-warning,.table-warning>td,.table-warning>th{background-color:#fce5cb}.table-hover .table-warning:hover,.table-hover .table-warning:hover>td,.table-hover .table-warning:hover>th{background-color:#fbd9b3}.table-danger,.table-danger>td,.table-danger>th{background-color:#f5c6cb}.table-hover .table-danger:hover,.table-hover .table-danger:hover>td,.table-hover .table-danger:hover>th{background-color:#f1b0b7}.table-light,.table-light>td,.table-light>th{background-color:#fdfdfe}.table-hover .table-light:hover,.table-hover .table-light:hover>td,.table-hover .table-light:hover>th{background-color:#ececf6}.table-dark,.table-dark>td,.table-dark>th{background-color:#c6c8ca}.table-hover .table-dark:hover,.table-hover .table-dark:hover>td,.table-hover .table-dark:hover>th{background-color:#b9bbbe}.table-active,.table-active>td,.table-active>th{background-color:#EDF5FF}.table-hover .table-active:hover,.table-hover .table-active:hover>td,.table-hover .table-active:hover>th{background-color:#d4e7ff}.table .thead-dark th{color:#fff;background-color:#212529;border-color:f-color-offset(#212529,7.5%,"lighten")}.table .thead-light th{color:#495057;background-color:#e9ecef;border-color:#EAECF3}.table-dark{color:#fff;background-color:#212529}.table-dark td,.table-dark th,.table-dark thead th{border-color:f-color-offset(#212529,7.5%,"lighten")}.table-dark.table-bordered,.table-responsive>.table-bordered{border:0}.table-dark.table-striped tbody tr:nth-of-type(odd){background-color:rgba(255,255,255,.05)}.table-dark.table-hover tbody tr:hover{background-color:rgba(255,255,255,.075)}@media (max-width:575.98px){.table-responsive-sm{display:block;width:100%;overflow-x:auto;-webkit-overflow-scrolling:touch;-ms-overflow-style:-ms-autohiding-scrollbar}.table-responsive-sm>.table-bordered{border:0}}@media (max-width:767.98px){.table-responsive-md{display:block;width:100%;overflow-x:auto;-webkit-overflow-scrolling:touch;-ms-overflow-style:-ms-autohiding-scrollbar}.table-responsive-md>.table-bordered{border:0}}@media (max-width:887.98px){.table-responsive-lg{display:block;width:100%;overflow-x:auto;-webkit-overflow-scrolling:touch;-ms-overflow-style:-ms-autohiding-scrollbar}.table-responsive-lg>.table-bordered{border:0}}@media (max-width:1199.98px){.table-responsive-xl{display:block;width:100%;overflow-x:auto;-webkit-overflow-scrolling:touch;-ms-overflow-style:-ms-autohiding-scrollbar}.table-responsive-xl>.table-bordered{border:0}}@media (max-width:1689.98px){.table-responsive-el{display:block;width:100%;overflow-x:auto;-webkit-overflow-scrolling:touch;-ms-overflow-style:-ms-autohiding-scrollbar}.table-responsive-el>.table-bordered{border:0}}.table-responsive{display:block;width:100%;overflow-x:auto;-webkit-overflow-scrolling:touch;-ms-overflow-style:-ms-autohiding-scrollbar}.form-control{display:block;width:100%;height:calc(1.5rem + .125rem);padding:.1875rem .5rem;line-height:1.4286;color:#2D2F33;background-color:#fff;background-clip:padding-box;border:1px solid #D8DCE6;border-radius:3px;box-shadow:0 0 0;transition:border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media screen and (prefers-reduced-motion:reduce){.form-control{transition:none}}.form-control::-ms-expand{background-color:transparent;border:0}.form-control:focus{color:#2D2F33;background-color:#fff;border-color:#529DFF;outline:0;box-shadow:0 0 0,0 0 4px 2px rgba(82,157,255,.12)}.form-control::-moz-placeholder{color:#B4BCCC;opacity:1}.form-control::placeholder{color:#B4BCCC;opacity:1}.form-control:disabled,.form-control[readonly]{background-color:#fff;opacity:1}select.form-control:focus::-ms-value{color:#2D2F33;background-color:#fff}.form-control-file,.form-control-range{display:block;width:100%}.col-form-label{padding-top:calc(.1875rem + 1px);padding-bottom:calc(.1875rem + 1px);margin-bottom:0;font-size:inherit;line-height:1.4286}.col-form-label-lg{padding-top:calc(.25rem + 1px);padding-bottom:calc(.25rem + 1px);font-size:.875rem;line-height:1.4286}.col-form-label-sm{padding-top:calc(.125rem + 1px);padding-bottom:calc(.125rem + 1px);font-size:.75rem;line-height:1.4286}.form-control-plaintext{display:block;width:100%;padding-top:.1875rem;padding-bottom:.1875rem;margin-bottom:0;line-height:1.4286;color:#000;background-color:transparent;border:solid transparent;border-width:1px 0}.form-control-lg,.form-control-sm{line-height:1.4286;border-radius:3px}.form-control-plaintext.form-control-lg,.form-control-plaintext.form-control-sm{padding-right:0;padding-left:0}.form-control-sm{height:calc(1.32145rem + 1px);padding:.125rem .4375rem;font-size:.75rem}.form-control-lg{height:calc(1.75003rem + 1px);padding:.25rem .3125rem;font-size:.875rem}select.form-control[multiple],select.form-control[size],textarea.form-control{height:auto}.form-group{margin-bottom:.375rem}.form-text{display:block;margin-top:.25rem}.form-row{display:flex;flex-wrap:wrap;margin-right:-.3125rem;margin-left:-.3125rem}.form-row>.col,.form-row>[class*=col-]{padding-right:.3125rem;padding-left:.3125rem}.form-check{position:relative;display:block;padding-left:1.25rem}.form-check-input{position:absolute;margin-top:.3rem;margin-left:-1.25rem}.form-check-input:disabled~.form-check-label{color:#A8ADB8}.form-check-label{margin-bottom:0}.form-check-inline{display:inline-flex;align-items:center;padding-left:0;margin-right:.75rem}.invalid-tooltip,.valid-tooltip{max-width:100%;padding:.5rem .625rem;line-height:1.4286;border-radius:3px;top:100%}.form-check-inline .form-check-input{position:static;margin-top:0;margin-right:.3125rem;margin-left:0}.valid-feedback{display:none;width:100%;margin-top:.25rem;font-size:80%;color:#6CC77F}.valid-tooltip{position:absolute;z-index:5;display:none;margin-top:.1rem;font-size:.75rem;color:#212529;background-color:#6cc77f}.custom-control-input.is-valid~.valid-feedback,.custom-control-input.is-valid~.valid-tooltip,.custom-file-input.is-valid~.valid-feedback,.custom-file-input.is-valid~.valid-tooltip,.custom-select.is-valid~.valid-feedback,.custom-select.is-valid~.valid-tooltip,.form-check-input.is-valid~.valid-feedback,.form-check-input.is-valid~.valid-tooltip,.form-control-file.is-valid~.valid-feedback,.form-control-file.is-valid~.valid-tooltip,.form-control.is-valid~.valid-feedback,.form-control.is-valid~.valid-tooltip,.was-validated .custom-control-input:valid~.valid-feedback,.was-validated .custom-control-input:valid~.valid-tooltip,.was-validated .custom-file-input:valid~.valid-feedback,.was-validated .custom-file-input:valid~.valid-tooltip,.was-validated .custom-select:valid~.valid-feedback,.was-validated .custom-select:valid~.valid-tooltip,.was-validated .form-check-input:valid~.valid-feedback,.was-validated .form-check-input:valid~.valid-tooltip,.was-validated .form-control-file:valid~.valid-feedback,.was-validated .form-control-file:valid~.valid-tooltip,.was-validated .form-control:valid~.valid-feedback,.was-validated .form-control:valid~.valid-tooltip{display:block}.custom-control-input.is-valid~.custom-control-label,.form-check-input.is-valid~.form-check-label,.was-validated .custom-control-input:valid~.custom-control-label,.was-validated .form-check-input:valid~.form-check-label{color:#6CC77F}.custom-select.is-valid,.form-control.is-valid,.was-validated .custom-select:valid,.was-validated .form-control:valid{border-color:#6CC77F}.custom-select.is-valid:focus,.form-control.is-valid:focus,.was-validated .custom-select:valid:focus,.was-validated .form-control:valid:focus{border-color:#6CC77F;box-shadow:0 0 0 .2rem rgba(108,199,127,.25)}.custom-control-input.is-valid~.custom-control-label::before,.was-validated .custom-control-input:valid~.custom-control-label::before{background-color:#c8eacf}.custom-control-input.is-valid:checked~.custom-control-label::before,.was-validated .custom-control-input:valid:checked~.custom-control-label::before{background-color:#91d59f}.custom-control-input.is-valid:focus~.custom-control-label::before,.was-validated .custom-control-input:valid:focus~.custom-control-label::before{box-shadow:0 0 0 1px #fff,0 0 0 .2rem rgba(108,199,127,.25)}.custom-file-input.is-valid~.custom-file-label,.was-validated .custom-file-input:valid~.custom-file-label{border-color:#6CC77F}.custom-file-input.is-valid~.custom-file-label::after,.was-validated .custom-file-input:valid~.custom-file-label::after{border-color:inherit}.custom-file-input.is-valid:focus~.custom-file-label,.was-validated .custom-file-input:valid:focus~.custom-file-label{box-shadow:0 0 0 .2rem rgba(108,199,127,.25)}.invalid-feedback{display:none;width:100%;margin-top:.25rem;font-size:80%;color:#dc3545}.invalid-tooltip{position:absolute;z-index:5;display:none;margin-top:.1rem;font-size:.75rem;color:#fff;background-color:#dc3545}.collapsing,.dropdown,.dropdown-left,.dropleft,.dropleft-up,.dropright,.dropright-up,.dropup,.dropup-left{position:relative}.custom-control-input.is-invalid~.invalid-feedback,.custom-control-input.is-invalid~.invalid-tooltip,.custom-file-input.is-invalid~.invalid-feedback,.custom-file-input.is-invalid~.invalid-tooltip,.custom-select.is-invalid~.invalid-feedback,.custom-select.is-invalid~.invalid-tooltip,.form-check-input.is-invalid~.invalid-feedback,.form-check-input.is-invalid~.invalid-tooltip,.form-control-file.is-invalid~.invalid-feedback,.form-control-file.is-invalid~.invalid-tooltip,.form-control.is-invalid~.invalid-feedback,.form-control.is-invalid~.invalid-tooltip,.was-validated .custom-control-input:invalid~.invalid-feedback,.was-validated .custom-control-input:invalid~.invalid-tooltip,.was-validated .custom-file-input:invalid~.invalid-feedback,.was-validated .custom-file-input:invalid~.invalid-tooltip,.was-validated .custom-select:invalid~.invalid-feedback,.was-validated .custom-select:invalid~.invalid-tooltip,.was-validated .form-check-input:invalid~.invalid-feedback,.was-validated .form-check-input:invalid~.invalid-tooltip,.was-validated .form-control-file:invalid~.invalid-feedback,.was-validated .form-control-file:invalid~.invalid-tooltip,.was-validated .form-control:invalid~.invalid-feedback,.was-validated .form-control:invalid~.invalid-tooltip{display:block}.custom-control-input.is-invalid~.custom-control-label,.form-check-input.is-invalid~.form-check-label,.was-validated .custom-control-input:invalid~.custom-control-label,.was-validated .form-check-input:invalid~.form-check-label{color:#dc3545}.custom-select.is-invalid,.form-control.is-invalid,.was-validated .custom-select:invalid,.was-validated .form-control:invalid{border-color:#dc3545}.custom-select.is-invalid:focus,.form-control.is-invalid:focus,.was-validated .custom-select:invalid:focus,.was-validated .form-control:invalid:focus{border-color:#dc3545;box-shadow:0 0 0 .2rem rgba(220,53,69,.25)}.custom-control-input.is-invalid~.custom-control-label::before,.was-validated .custom-control-input:invalid~.custom-control-label::before{background-color:#efa2a9}.custom-control-input.is-invalid:checked~.custom-control-label::before,.was-validated .custom-control-input:invalid:checked~.custom-control-label::before{background-color:#e4606d}.custom-control-input.is-invalid:focus~.custom-control-label::before,.was-validated .custom-control-input:invalid:focus~.custom-control-label::before{box-shadow:0 0 0 1px #fff,0 0 0 .2rem rgba(220,53,69,.25)}.custom-file-input.is-invalid~.custom-file-label,.was-validated .custom-file-input:invalid~.custom-file-label{border-color:#dc3545}.custom-file-input.is-invalid~.custom-file-label::after,.was-validated .custom-file-input:invalid~.custom-file-label::after{border-color:inherit}.custom-file-input.is-invalid:focus~.custom-file-label,.was-validated .custom-file-input:invalid:focus~.custom-file-label{box-shadow:0 0 0 .2rem rgba(220,53,69,.25)}.form-inline{display:flex;flex-flow:row wrap;align-items:center}.form-inline .form-check{width:100%}@media (min-width:576px){.form-inline label{display:flex;align-items:center;justify-content:center;margin-bottom:0}.form-inline .form-group{display:flex;flex-grow:0;flex-shrink:0;flex-basis:auto;flex-flow:row wrap;align-items:center;margin-bottom:0}.form-inline .form-control{display:inline-block;width:auto;vertical-align:middle}.form-inline .form-control-plaintext{display:inline-block}.form-inline .custom-select,.form-inline .input-group{width:auto}.form-inline .form-check{display:flex;align-items:center;justify-content:center;width:auto;padding-left:0}.form-inline .form-check-input{position:relative;margin-top:0;margin-right:.25rem;margin-left:0}.form-inline .custom-control{align-items:center;justify-content:center}.form-inline .custom-control-label{margin-bottom:0}}.fade{transition:opacity .15s linear}@media screen and (prefers-reduced-motion:reduce){.fade{transition:none}}.fade:not(.show){opacity:0}.collapse:not(.show){display:none}.collapsing{height:0;transition:height .35s ease}@media screen and (prefers-reduced-motion:reduce){.collapsing{transition:none}}.dropdown-toggle::after{display:inline-block;width:0;height:0;margin-left:.125rem;vertical-align:.125rem;content:"";border-top:.25rem solid;border-right:.25rem solid transparent;border-bottom:0;border-left:.25rem solid transparent}.dropdown-toggle:empty::after{margin-left:0}.dropdown-menu{position:absolute;top:100%;left:0;z-index:300;display:none;float:left;min-width:10rem;padding:.25rem;margin:.25rem 0 0;color:#2D2F33;background-color:#fff;background-clip:padding-box;border:0 solid rgba(0,0,0,.15);border-radius:3px;box-shadow:0 2px 8px 0 rgba(0,0,0,.15)}.dropup .dropdown-toggle::after,.dropup-left .dropdown-toggle::after{display:inline-block;width:0;height:0;vertical-align:.125rem;content:"";border-top:0;border-right:.25rem solid transparent;border-bottom:.25rem solid;border-left:.25rem solid transparent}.dropdown-menu-right{right:0;left:auto}.dropup .dropdown-menu{top:auto;bottom:100%;margin-top:0;margin-bottom:.25rem}.dropup .dropdown-toggle::after{margin-left:.125rem}.dropup .dropdown-toggle:empty::after{margin-left:0}.dropup-left .dropdown-menu{top:auto;right:0;left:auto;bottom:100%;margin-top:0;margin-bottom:.25rem}.dropup-left .dropdown-toggle::after{margin-left:.125rem}.dropright .dropdown-toggle::after,.dropright-up .dropdown-toggle::after{display:inline-block;width:0;height:0;content:"";border-top:.25rem solid transparent;border-right:0;border-left:.25rem solid;vertical-align:0}.dropup-left .dropdown-toggle:empty::after{margin-left:0}.dropright .dropdown-menu{top:0;right:auto;left:100%;margin-top:0;margin-left:.25rem}.dropright .dropdown-toggle::after{margin-left:.125rem;border-bottom:.25rem solid transparent}.dropright .dropdown-toggle:empty::after{margin-left:0}.dropright-up .dropdown-menu{top:auto;right:auto;left:100%;bottom:0;margin-top:0;margin-left:.25rem}.dropright-up .dropdown-toggle::after{margin-left:.125rem;border-bottom:.25rem solid transparent}.dropleft .dropdown-toggle::before,.dropleft-up .dropdown-toggle::before{width:0;content:"";border-top:.25rem solid transparent;border-right:.25rem solid;border-bottom:.25rem solid transparent;height:0}.dropright-up .dropdown-toggle:empty::after{margin-left:0}.dropleft-up .dropdown-menu{top:auto;right:100%;left:auto;bottom:0;margin-top:0;margin-bottom:.25rem}.dropleft-up .dropdown-toggle::after{width:0;height:0;margin-left:.125rem;vertical-align:.125rem;content:"";display:none}.dropleft-up .dropdown-toggle::before{display:inline-block;margin-right:.125rem;vertical-align:0}.dropleft-up .dropdown-toggle:empty::after{margin-left:0}.dropleft .dropdown-menu{top:0;right:100%;left:auto;margin-top:0;margin-right:.25rem}.dropleft .dropdown-toggle::after{width:0;height:0;margin-left:.125rem;vertical-align:.125rem;content:"";display:none}.dropleft .dropdown-toggle::before{display:inline-block;margin-right:.125rem;vertical-align:0}.dropleft .dropdown-toggle:empty::after{margin-left:0}.dropdown-menu[x-placement^=top],.dropdown-menu[x-placement^=right],.dropdown-menu[x-placement^=bottom],.dropdown-menu[x-placement^=left]{right:auto;bottom:auto}.dropdown-divider{height:0;margin:null 0;border-top:1px solid #E6E9F0}.dropdown-item{display:block;line-height:1.25rem;padding:.25rem .5rem;clear:both;font-weight:400;color:#5A5E66;text-align:inherit;white-space:nowrap;background-color:transparent;border:0;border-radius:3px}.btn-group>.btn-group:not(:last-child)>.btn,.btn-group>.btn:not(:last-child):not(.dropdown-toggle),.input-group>.custom-file:not(:last-child) .custom-file-label,.input-group>.custom-file:not(:last-child) .custom-file-label::after,.input-group>.custom-select:not(:last-child),.input-group>.form-control:not(:last-child){border-top-right-radius:0;border-bottom-right-radius:0}.btn-group>.btn-group:not(:first-child)>.btn,.btn-group>.btn:not(:first-child),.input-group>.custom-file:not(:first-child) .custom-file-label,.input-group>.custom-select:not(:first-child),.input-group>.form-control:not(:first-child){border-top-left-radius:0;border-bottom-left-radius:0}.dropdown-item:focus,.dropdown-item:hover{color:#2D2F33;text-decoration:none;background-color:#EDF5FF}.dropdown-item.active,.dropdown-item:active{color:#2D2F33;text-decoration:none;background-color:#DAE9FF}.dropdown-item.disabled,.dropdown-item:disabled{color:#B4BCCC;background-color:transparent;cursor:default}.dropdown-menu.show{display:block}.dropdown-header{display:block;padding:.25rem .5rem;margin-bottom:0;font-size:.75rem;color:#6c757d;white-space:nowrap}.dropdown-item-text{display:block;padding:.25rem .5rem;color:#5A5E66}.btn-group,.btn-group-vertical{position:relative;display:inline-flex;vertical-align:middle}.btn-group-vertical>.btn,.btn-group>.btn{position:relative;flex-grow:0;flex-shrink:1;flex-basis:auto}.btn-group-vertical>.btn.active,.btn-group-vertical>.btn:active,.btn-group-vertical>.btn:focus,.btn-group-vertical>.btn:hover,.btn-group>.btn.active,.btn-group>.btn:active,.btn-group>.btn:focus,.btn-group>.btn:hover{z-index:1}.btn-group .btn+.btn,.btn-group .btn+.btn-group,.btn-group .btn-group+.btn,.btn-group .btn-group+.btn-group,.btn-group-vertical .btn+.btn,.btn-group-vertical .btn+.btn-group,.btn-group-vertical .btn-group+.btn,.btn-group-vertical .btn-group+.btn-group{margin-left:-1px}.btn-toolbar{display:flex;flex-wrap:wrap;justify-content:flex-start}.btn-toolbar .input-group{width:auto}.btn-group>.btn:first-child{margin-left:0}.dropdown-toggle-split{padding-right:.65625rem;padding-left:.65625rem}.dropdown-toggle-split::after,.dropright .dropdown-toggle-split::after,.dropright-top .dropdown-toggle-split::after,.dropup .dropdown-toggle-split::after,.dropup-left .dropdown-toggle-split::after{margin-left:0}.dropleft .dropdown-toggle-split::before,.dropleft-up .dropdown-toggle-split::before{margin-right:0}.btn-group-sm>.btn+.dropdown-toggle-split,.btn-sm+.dropdown-toggle-split{padding-right:.375rem;padding-left:.375rem}.btn-group-lg>.btn+.dropdown-toggle-split,.btn-lg+.dropdown-toggle-split{padding-right:.84375rem;padding-left:.84375rem}.btn-group.show .dropdown-toggle{box-shadow:0 1px 0 0 rgba(31,35,41,.12)}.btn-group.show .dropdown-toggle.btn-link{box-shadow:none}.btn-group-vertical{flex-direction:column;align-items:flex-start;justify-content:center}.input-group,.nav,.navbar{flex-wrap:wrap}.btn-group-vertical .btn,.btn-group-vertical .btn-group{width:100%}.btn-group-vertical>.btn+.btn,.btn-group-vertical>.btn+.btn-group,.btn-group-vertical>.btn-group+.btn,.btn-group-vertical>.btn-group+.btn-group{margin-top:-1px;margin-left:0}.input-group-append,.input-group-append .btn+.btn,.input-group-append .btn+.input-group-text,.input-group-append .input-group-text+.btn,.input-group-append .input-group-text+.input-group-text,.input-group-prepend .btn+.btn,.input-group-prepend .btn+.input-group-text,.input-group-prepend .input-group-text+.btn,.input-group-prepend .input-group-text+.input-group-text,.input-group>.custom-file+.custom-file,.input-group>.custom-file+.custom-select,.input-group>.custom-file+.form-control,.input-group>.custom-select+.custom-file,.input-group>.custom-select+.custom-select,.input-group>.custom-select+.form-control,.input-group>.form-control+.custom-file,.input-group>.form-control+.custom-select,.input-group>.form-control+.form-control,.page-link{margin-left:-1px}.btn-group-vertical>.btn-group:not(:last-child)>.btn,.btn-group-vertical>.btn:not(:last-child):not(.dropdown-toggle){border-bottom-right-radius:0;border-bottom-left-radius:0}.btn-group-vertical>.btn-group:not(:first-child)>.btn,.btn-group-vertical>.btn:not(:first-child){border-top-left-radius:0;border-top-right-radius:0}.btn-group-toggle>.btn,.btn-group-toggle>.btn-group>.btn{margin-bottom:0}.btn-group-toggle>.btn input[type=radio],.btn-group-toggle>.btn input[type=checkbox],.btn-group-toggle>.btn-group>.btn input[type=radio],.btn-group-toggle>.btn-group>.btn input[type=checkbox]{position:absolute;clip:rect(0,0,0,0);pointer-events:none}.input-group{position:relative;display:flex;align-items:stretch;width:100%}.input-group>.custom-file,.input-group>.custom-select,.input-group>.form-control{position:relative;flex-grow:1;flex-shrink:1;flex-basis:0;width:1%;margin-bottom:0}.input-group>.custom-file .custom-file-input:focus~.custom-file-label,.input-group>.custom-select:focus,.input-group>.form-control:focus{z-index:3}.input-group>.custom-file .custom-file-input:focus{z-index:4}.input-group>.custom-file{display:flex;align-items:center}.input-group-append,.input-group-prepend{display:flex}.input-group-append .btn,.input-group-prepend .btn{position:relative;z-index:2}.input-group-prepend{margin-right:-1px}.input-group-text{display:flex;align-items:center;padding:.1875rem .5rem;margin-bottom:0;font-size:.8125rem;font-weight:400;line-height:1.4286;color:#2D2F33;text-align:center;white-space:nowrap;background-color:#e9ecef;border:1px solid #D8DCE6;border-radius:3px}.input-group-text input[type=radio],.input-group-text input[type=checkbox]{margin-top:0}.input-group-lg>.form-control,.input-group-lg>.input-group-append>.btn,.input-group-lg>.input-group-append>.input-group-text,.input-group-lg>.input-group-prepend>.btn,.input-group-lg>.input-group-prepend>.input-group-text{height:calc(1.75003rem + 1px);padding:.25rem .3125rem;font-size:.875rem;line-height:1.4286;border-radius:3px}.input-group-sm>.form-control,.input-group-sm>.input-group-append>.btn,.input-group-sm>.input-group-append>.input-group-text,.input-group-sm>.input-group-prepend>.btn,.input-group-sm>.input-group-prepend>.input-group-text{height:calc(1.32145rem + 1px);padding:.125rem .4375rem;font-size:.75rem;line-height:1.4286;border-radius:3px}.input-group>.input-group-append:last-child>.btn:not(:last-child):not(.dropdown-toggle),.input-group>.input-group-append:last-child>.input-group-text:not(:last-child),.input-group>.input-group-append:not(:last-child)>.btn,.input-group>.input-group-append:not(:last-child)>.input-group-text,.input-group>.input-group-prepend>.btn,.input-group>.input-group-prepend>.input-group-text{border-top-right-radius:0;border-bottom-right-radius:0}.input-group>.input-group-append>.btn,.input-group>.input-group-append>.input-group-text,.input-group>.input-group-prepend:first-child>.btn:not(:first-child),.input-group>.input-group-prepend:first-child>.input-group-text:not(:first-child),.input-group>.input-group-prepend:not(:first-child)>.btn,.input-group>.input-group-prepend:not(:first-child)>.input-group-text{border-top-left-radius:0;border-bottom-left-radius:0}.custom-control{position:relative;display:block;min-height:1.16074rem;padding-left:1.5rem}.custom-control-inline{display:inline-flex;margin-right:1rem}.custom-control-input{position:absolute;z-index:-1;opacity:0}.custom-control-input:checked~.custom-control-label::before{color:#2A87FF;background-color:#fff;box-shadow:none}.custom-control-input:focus~.custom-control-label::before{box-shadow:0 0 0 1px #fff,0 0 4px 2px rgba(82,157,255,.12);color:#2A87FF}.custom-control-input:active~.custom-control-label::before{color:#fff;background-color:f-color-offset(#2A87FF,35%,"lighten");box-shadow:none}.custom-checkbox .custom-control-input:checked~.custom-control-label::before,.custom-checkbox .custom-control-input:disabled:checked~.custom-control-label::before,.custom-checkbox .custom-control-input:disabled:indeterminate~.custom-control-label::before,.custom-control-input:disabled~.custom-control-label::before,.custom-control-label::before,.custom-radio .custom-control-input:checked~.custom-control-label::before,.custom-radio .custom-control-input:disabled:checked~.custom-control-label::before{background-color:#fff}.custom-control-input:disabled~.custom-control-label{color:#E6E9F0}.custom-control-label{position:relative;margin-bottom:0}.custom-control-label::after,.custom-control-label::before{position:absolute;top:.08037rem;left:-1.5rem;display:block;width:1rem;height:1rem;content:""}.custom-control-label::before{pointer-events:none;-webkit-user-select:none;-moz-user-select:none;user-select:none;box-shadow:0 0 0}.custom-control-label::after{background-repeat:no-repeat;background-position:center center;background-size:50% 50%}.custom-checkbox .custom-control-label::before{border-radius:3px}.custom-checkbox .custom-control-input:checked~.custom-control-label::after{background-image:none}.custom-checkbox .custom-control-input:indeterminate~.custom-control-label::before{box-shadow:none}.custom-checkbox .custom-control-input:indeterminate~.custom-control-label::after{background-image:none}.custom-radio .custom-control-label::before{border-radius:50%}.custom-radio .custom-control-input:checked~.custom-control-label::after{background-image:none}.custom-select{display:inline-block;width:100%;height:calc(1.5rem + .125rem);padding:.1875rem 1.5rem .1875rem .5rem;line-height:1.4286;color:#2D2F33;vertical-align:middle;background:f-str-replace(url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 4 5'%3E%3Cpath fill='#343a40' d='M2 0L0 2h4zm0 5L0 3h4z'/%3E%3C/svg%3E") ,"#","%23") right .5rem center no-repeat #fff;background-size:.5rem .625rem;border:1px solid #D8DCE6;border-radius:3px;box-shadow:0 0 0;-webkit-appearance:none;-moz-appearance:none;appearance:none}.custom-select-lg,.custom-select-sm{padding-top:.1875rem;padding-bottom:.1875rem}.custom-select:focus{border-color:#529DFF;outline:0;box-shadow:0 0 0,0 0 4px 2px rgba(82,157,255,.12)}.custom-select:focus::-ms-value{color:#2D2F33;background-color:#fff}.custom-select[multiple],.custom-select[size]:not([size="1"]){height:auto;padding-right:.5rem;background-image:none}.custom-select:disabled{color:#6c757d;background-color:#e9ecef}.custom-file-input:disabled~.custom-file-label,.custom-file-label{background-color:#fff}.custom-select::-ms-expand{opacity:0}.custom-select-sm{height:calc(1.32145rem + 1px);font-size:75%}.custom-select-lg{height:calc(1.75003rem + 1px);font-size:125%}.custom-file,.custom-file-input,.custom-file-label{height:calc(1.5rem + .125rem)}.custom-file-label,.custom-file-label::after{padding:.1875rem .5rem;color:#2D2F33;right:0;line-height:1.4286}.custom-file{position:relative;display:inline-block;width:100%;margin-bottom:0}.custom-file-input{position:relative;z-index:2;width:100%;margin:0;opacity:0}.custom-file-input:focus~.custom-file-label{border-color:#529DFF;box-shadow:0 0 4px 2px rgba(82,157,255,.12)}.custom-file-input:focus~.custom-file-label::after{border-color:#529DFF}.custom-file-input:lang(en)~.custom-file-label::after{content:"Browse"}.custom-file-label{position:absolute;top:0;left:0;z-index:1;border:1px solid #D8DCE6;border-radius:3px;box-shadow:0 0 0}.custom-file-label::after{position:absolute;top:0;bottom:0;z-index:3;display:block;height:1.5rem;content:"Browse";background-color:#e9ecef;border-left:1px solid #D8DCE6;border-radius:0 3px 3px 0}.custom-range{width:100%;padding-left:0;background-color:transparent;-webkit-appearance:none;-moz-appearance:none;appearance:none}.custom-range:focus{outline:0}.custom-range:focus::-webkit-slider-thumb{box-shadow:0 0 0 1px #fff,0 0 4px 2px rgba(82,157,255,.12)}.custom-range:focus::-moz-range-thumb{box-shadow:0 0 0 1px #fff,0 0 4px 2px rgba(82,157,255,.12)}.custom-range:focus::-ms-thumb{box-shadow:0 0 0 1px #fff,0 0 4px 2px rgba(82,157,255,.12)}.custom-range::-moz-focus-outer{border:0}.custom-range::-webkit-slider-thumb{width:1rem;height:1rem;margin-top:-.25rem;background-color:#2A87FF;border:0;border-radius:1rem;box-shadow:0 .1rem .25rem rgba(0,0,0,.1);-webkit-transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;-webkit-appearance:none;appearance:none}@media screen and (prefers-reduced-motion:reduce){.custom-range::-webkit-slider-thumb{-webkit-transition:none;transition:none}}.custom-range::-webkit-slider-thumb:active{background-color:f-color-offset(#2A87FF,35%,"lighten")}.custom-range::-webkit-slider-runnable-track{width:100%;height:.5rem;color:transparent;cursor:pointer;background-color:#dee2e6;border-color:transparent;border-radius:1rem;box-shadow:inset 0 .25rem .25rem rgba(0,0,0,.1)}.custom-range::-moz-range-thumb{width:1rem;height:1rem;background-color:#2A87FF;border:0;border-radius:1rem;box-shadow:0 .1rem .25rem rgba(0,0,0,.1);-moz-transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;-moz-appearance:none;appearance:none}@media screen and (prefers-reduced-motion:reduce){.custom-range::-moz-range-thumb{-moz-transition:none;transition:none}}.custom-range::-moz-range-thumb:active{background-color:f-color-offset(#2A87FF,35%,"lighten")}.custom-range::-moz-range-track{width:100%;height:.5rem;color:transparent;cursor:pointer;background-color:#dee2e6;border-color:transparent;border-radius:1rem;box-shadow:inset 0 .25rem .25rem rgba(0,0,0,.1)}.custom-range::-ms-thumb{width:1rem;height:1rem;margin-top:0;margin-right:.2rem;margin-left:.2rem;background-color:#2A87FF;border:0;border-radius:1rem;box-shadow:0 .1rem .25rem rgba(0,0,0,.1);-ms-transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;appearance:none}@media screen and (prefers-reduced-motion:reduce){.custom-range::-ms-thumb{-ms-transition:none;transition:none}}.custom-range::-ms-thumb:active{background-color:f-color-offset(#2A87FF,35%,"lighten")}.custom-range::-ms-track{width:100%;height:.5rem;color:transparent;cursor:pointer;background-color:transparent;border-color:transparent;border-width:.5rem;box-shadow:inset 0 .25rem .25rem rgba(0,0,0,.1)}.custom-range::-ms-fill-lower{background-color:#dee2e6;border-radius:1rem}.custom-range::-ms-fill-upper{margin-right:.9375rem;background-color:#dee2e6;border-radius:1rem}.custom-control-label::before,.custom-file-label,.custom-select{transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media screen and (prefers-reduced-motion:reduce){.custom-control-label::before,.custom-file-label,.custom-select{transition:none}}.nav{display:flex;padding-left:0;margin-bottom:0;list-style:none}.nav-link,.navbar{padding:.5rem 1rem}.nav-link{display:block}.nav-link:focus,.nav-link:hover{text-decoration:none}.nav-link.disabled{color:#6c757d}.nav-tabs{border-bottom:1px solid #dee2e6}.nav-tabs .nav-item{margin-bottom:-1px}.nav-tabs .nav-link{border:1px solid transparent;border-top-left-radius:3px;border-top-right-radius:3px}.nav-tabs .nav-link:focus,.nav-tabs .nav-link:hover{border-color:#e9ecef #e9ecef #dee2e6}.nav-tabs .nav-link.disabled{color:#6c757d;background-color:transparent;border-color:transparent}.nav-tabs .nav-item.show .nav-link,.nav-tabs .nav-link.active{color:#495057;background-color:#fff;border-color:#dee2e6 #dee2e6 #fff}.nav-tabs .dropdown-menu{margin-top:-1px;border-top-left-radius:0;border-top-right-radius:0}.nav-pills .nav-link{border-radius:3px}.nav-pills .nav-link.active,.nav-pills .show>.nav-link{color:#fff;background:#2A87FF}.nav-fill .nav-item{flex-grow:1;flex-shrink:1;flex-basis:auto;text-align:center}.nav-justified .nav-item{flex-basis:0;flex-grow:1;text-align:center}.tab-content>.tab-pane{display:none}.tab-content>.active{display:block}.navbar{position:relative;display:flex;align-items:center;justify-content:space-between}.navbar>.container,.navbar>.container-fluid{display:flex;flex-wrap:wrap;align-items:center;justify-content:space-between}.navbar-brand{display:inline-block;padding-top:.45536rem;padding-bottom:.45536rem;margin-right:1rem;font-size:.875rem;line-height:inherit;white-space:nowrap}.navbar-brand:focus,.navbar-brand:hover{text-decoration:none}.navbar-nav{display:flex;flex-direction:column;padding-left:0;margin-bottom:0;list-style:none}.navbar-nav .nav-link{padding-right:0;padding-left:0}.navbar-nav .dropdown-menu{position:static;float:none}.navbar-text{display:inline-block;padding-top:.5rem;padding-bottom:.5rem}.navbar-collapse{flex-basis:100%;flex-grow:1;align-items:center}.navbar-toggler{padding:.25rem .75rem;font-size:.875rem;line-height:1;background-color:transparent;border:1px solid transparent;border-radius:3px}.navbar-toggler:focus,.navbar-toggler:hover{text-decoration:none}.navbar-toggler-icon{display:inline-block;width:1.5em;height:1.5em;vertical-align:middle;content:"";background:center center no-repeat;background-size:100% 100%}@media (max-width:575.98px){.navbar-expand-sm>.container,.navbar-expand-sm>.container-fluid{padding-right:0;padding-left:0}}@media (min-width:576px){.navbar-expand-sm{flex-flow:row nowrap;justify-content:flex-start}.navbar-expand-sm .navbar-nav{flex-direction:row}.navbar-expand-sm .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-sm .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand-sm>.container,.navbar-expand-sm>.container-fluid{flex-wrap:nowrap}.navbar-expand-sm .navbar-collapse{display:flex!important;flex-basis:auto}.navbar-expand-sm .navbar-toggler{display:none}}@media (max-width:767.98px){.navbar-expand-md>.container,.navbar-expand-md>.container-fluid{padding-right:0;padding-left:0}}@media (min-width:768px){.navbar-expand-md{flex-flow:row nowrap;justify-content:flex-start}.navbar-expand-md .navbar-nav{flex-direction:row}.navbar-expand-md .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-md .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand-md>.container,.navbar-expand-md>.container-fluid{flex-wrap:nowrap}.navbar-expand-md .navbar-collapse{display:flex!important;flex-basis:auto}.navbar-expand-md .navbar-toggler{display:none}}@media (max-width:887.98px){.navbar-expand-lg>.container,.navbar-expand-lg>.container-fluid{padding-right:0;padding-left:0}}@media (min-width:888px){.navbar-expand-lg{flex-flow:row nowrap;justify-content:flex-start}.navbar-expand-lg .navbar-nav{flex-direction:row}.navbar-expand-lg .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-lg .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand-lg>.container,.navbar-expand-lg>.container-fluid{flex-wrap:nowrap}.navbar-expand-lg .navbar-collapse{display:flex!important;flex-basis:auto}.navbar-expand-lg .navbar-toggler{display:none}}@media (max-width:1199.98px){.navbar-expand-xl>.container,.navbar-expand-xl>.container-fluid{padding-right:0;padding-left:0}}@media (min-width:1200px){.navbar-expand-xl{flex-flow:row nowrap;justify-content:flex-start}.navbar-expand-xl .navbar-nav{flex-direction:row}.navbar-expand-xl .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-xl .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand-xl>.container,.navbar-expand-xl>.container-fluid{flex-wrap:nowrap}.navbar-expand-xl .navbar-collapse{display:flex!important;flex-basis:auto}.navbar-expand-xl .navbar-toggler{display:none}}@media (max-width:1689.98px){.navbar-expand-el>.container,.navbar-expand-el>.container-fluid{padding-right:0;padding-left:0}}@media (min-width:1690px){.navbar-expand-el{flex-flow:row nowrap;justify-content:flex-start}.navbar-expand-el .navbar-nav{flex-direction:row}.navbar-expand-el .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-el .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand-el>.container,.navbar-expand-el>.container-fluid{flex-wrap:nowrap}.navbar-expand-el .navbar-collapse{display:flex!important;flex-basis:auto}.navbar-expand-el .navbar-toggler{display:none}}.navbar-expand{flex-flow:row nowrap;justify-content:flex-start}.navbar-expand>.container,.navbar-expand>.container-fluid{padding-right:0;padding-left:0}.navbar-expand .navbar-nav{flex-direction:row}.navbar-expand .navbar-nav .dropdown-menu{position:absolute}.navbar-expand .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand>.container,.navbar-expand>.container-fluid{flex-wrap:nowrap}.navbar-expand .navbar-collapse{display:flex!important;flex-basis:auto}.modal,.navbar-expand .navbar-toggler{display:none}.navbar-light .navbar-brand,.navbar-light .navbar-brand:focus,.navbar-light .navbar-brand:hover{color:rgba(0,0,0,.9)}.navbar-light .navbar-nav .nav-link{color:rgba(0,0,0,.5)}.navbar-light .navbar-nav .nav-link:focus,.navbar-light .navbar-nav .nav-link:hover{color:rgba(0,0,0,.7)}.navbar-light .navbar-nav .nav-link.disabled{color:rgba(0,0,0,.3)}.navbar-light .navbar-nav .active>.nav-link,.navbar-light .navbar-nav .nav-link.active,.navbar-light .navbar-nav .nav-link.show,.navbar-light .navbar-nav .show>.nav-link{color:rgba(0,0,0,.9)}.navbar-light .navbar-toggler{color:rgba(0,0,0,.5);border-color:rgba(0,0,0,.1)}.navbar-light .navbar-toggler-icon{background-image:f-str-replace(url("data:image/svg+xml;charset=utf8,%3Csvg viewBox='0 0 30 30' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath stroke='rgba(0, 0, 0, 0.5)' stroke-width='2' stroke-linecap='round' stroke-miterlimit='10' d='M4 7h22M4 15h22M4 23h22'/%3E%3C/svg%3E") ,"#","%23")}.navbar-light .navbar-text{color:rgba(0,0,0,.5)}.navbar-light .navbar-text a,.navbar-light .navbar-text a:focus,.navbar-light .navbar-text a:hover{color:rgba(0,0,0,.9)}.navbar-dark .navbar-brand,.navbar-dark .navbar-brand:focus,.navbar-dark .navbar-brand:hover{color:#fff}.navbar-dark .navbar-nav .nav-link{color:rgba(255,255,255,.5)}.navbar-dark .navbar-nav .nav-link:focus,.navbar-dark .navbar-nav .nav-link:hover{color:rgba(255,255,255,.75)}.navbar-dark .navbar-nav .nav-link.disabled{color:rgba(255,255,255,.25)}.navbar-dark .navbar-nav .active>.nav-link,.navbar-dark .navbar-nav .nav-link.active,.navbar-dark .navbar-nav .nav-link.show,.navbar-dark .navbar-nav .show>.nav-link{color:#fff}.navbar-dark .navbar-toggler{color:rgba(255,255,255,.5);border-color:rgba(255,255,255,.1)}.navbar-dark .navbar-toggler-icon{background-image:f-str-replace(url("data:image/svg+xml;charset=utf8,%3Csvg viewBox='0 0 30 30' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath stroke='rgba(255, 255, 255, 0.5)' stroke-width='2' stroke-linecap='round' stroke-miterlimit='10' d='M4 7h22M4 15h22M4 23h22'/%3E%3C/svg%3E") ,"#","%23")}.navbar-dark .navbar-text{color:rgba(255,255,255,.5)}.navbar-dark .navbar-text a,.navbar-dark .navbar-text a:focus,.navbar-dark .navbar-text a:hover{color:#fff}.card{position:relative;display:flex;flex-direction:column;min-width:0;word-wrap:break-word;background-color:#fff;background-clip:border-box;border:1px solid rgba(0,0,0,.125);border-radius:3px}.card>hr{margin-right:0;margin-left:0}.card>.list-group:first-child .list-group-item:first-child{border-top-left-radius:3px;border-top-right-radius:3px}.card>.list-group:last-child .list-group-item:last-child{border-bottom-right-radius:3px;border-bottom-left-radius:3px}.card-body{flex-grow:1;flex-shrink:1;flex-basis:auto;padding:1.25rem}.card-footer,.card-header{padding:.75rem 1.25rem;background-color:rgba(0,0,0,.03)}.card-title{margin-bottom:.75rem}.card-header,.card-subtitle,.card-text:last-child{margin-bottom:0}.card-subtitle{margin-top:-.375rem}.card-link:hover{text-decoration:none}.card-link+.card-link{margin-left:1.25rem}.card-header-pills,.card-header-tabs{margin-right:-.625rem;margin-left:-.625rem}.card-header{border-bottom:1px solid rgba(0,0,0,.125)}.card-header:first-child{border-radius:calc(3px - 1px) calc(3px - 1px) 0 0}.card-header+.list-group .list-group-item:first-child{border-top:0}.card-footer{border-top:1px solid rgba(0,0,0,.125)}.card-footer:last-child{border-radius:0 0 calc(3px - 1px) calc(3px - 1px)}.card-header-tabs{margin-bottom:-.75rem;border-bottom:0}.card-img-overlay{position:absolute;top:0;right:0;bottom:0;left:0;padding:1.25rem}.card-img{width:100%;border-radius:calc(3px - 1px)}.card-img-top{width:100%;border-top-left-radius:calc(3px - 1px);border-top-right-radius:calc(3px - 1px)}.card-img-bottom{width:100%;border-bottom-right-radius:calc(3px - 1px);border-bottom-left-radius:calc(3px - 1px)}.card-deck{display:flex;flex-direction:column}.card-deck .card{margin-bottom:14px}@media (min-width:576px){.card-deck{flex-flow:row wrap;margin-right:-14px;margin-left:-14px}.card-deck .card{display:flex;flex-grow:1;flex-shrink:0;flex-basis:0%;flex-direction:column;margin-right:14px;margin-bottom:0;margin-left:14px}}.card-group{display:flex;flex-direction:column}.card-group>.card{margin-bottom:14px}@media (min-width:576px){.card-group{flex-flow:row wrap}.card-group>.card{flex-grow:1;flex-shrink:0;flex-basis:0%;margin-bottom:0}.card-group>.card+.card{margin-left:0;border-left:0}.card-group>.card:first-child{border-top-right-radius:0;border-bottom-right-radius:0}.card-group>.card:first-child .card-header,.card-group>.card:first-child .card-img-top{border-top-right-radius:0}.card-group>.card:first-child .card-footer,.card-group>.card:first-child .card-img-bottom{border-bottom-right-radius:0}.card-group>.card:last-child{border-top-left-radius:0;border-bottom-left-radius:0}.card-group>.card:last-child .card-header,.card-group>.card:last-child .card-img-top{border-top-left-radius:0}.card-group>.card:last-child .card-footer,.card-group>.card:last-child .card-img-bottom{border-bottom-left-radius:0}.card-group>.card:only-child{border-radius:3px}.card-group>.card:only-child .card-header,.card-group>.card:only-child .card-img-top{border-top-left-radius:3px;border-top-right-radius:3px}.card-group>.card:only-child .card-footer,.card-group>.card:only-child .card-img-bottom{border-bottom-right-radius:3px;border-bottom-left-radius:3px}.card-group>.card:not(:first-child):not(:last-child):not(:only-child),.card-group>.card:not(:first-child):not(:last-child):not(:only-child) .card-footer,.card-group>.card:not(:first-child):not(:last-child):not(:only-child) .card-header,.card-group>.card:not(:first-child):not(:last-child):not(:only-child) .card-img-bottom,.card-group>.card:not(:first-child):not(:last-child):not(:only-child) .card-img-top{border-radius:0}.card-columns{-moz-column-count:3;column-count:3;-moz-column-gap:1.25rem;column-gap:1.25rem;orphans:1;widows:1}.card-columns .card{display:inline-block;width:100%}}.card-columns .card{margin-bottom:.75rem}.accordion .card:not(:first-of-type):not(:last-of-type){border-bottom:0;border-radius:0}.accordion .card:not(:first-of-type) .card-header:first-child{border-radius:0}.accordion .card:first-of-type{border-bottom:0;border-bottom-right-radius:0;border-bottom-left-radius:0}.accordion .card:last-of-type{border-top-left-radius:0;border-top-right-radius:0}.pagination,.progress{border-radius:3px;display:flex}.pagination{padding-left:0;list-style:none}.page-link{position:relative;display:block;padding:.1875rem;line-height:1rem;color:#2D2F33;background-color:#fff;border:1px solid #EAECF3}.page-item:first-child .page-link,.pagination-lg .f-page-item:first-child .f-page-link,.pagination-sm .f-page-item:first-child .f-page-link{border-top-left-radius:3px;border-bottom-left-radius:3px}.page-item:last-child .page-link,.pagination-lg .f-page-item:last-child .f-page-link,.pagination-sm .f-page-item:last-child .f-page-link{border-top-right-radius:3px;border-bottom-right-radius:3px}.page-link:hover{z-index:2;color:#529DFF;text-decoration:none;background-color:#fff;border-color:#529DFF}.page-link:focus{z-index:2;outline:0;box-shadow:0 0 4px 2px rgba(82,157,255,.12)}.page-item:first-child .page-link{margin-left:0}.page-item.active .page-link{z-index:1;color:#2A87FF;background:#EFF5FF!important;border-color:#EFF5FF}.page-item.disabled .page-link{color:#878D99;pointer-events:none;cursor:auto;background:#F4F5F9;border-color:#DEE1EA;box-shadow:none}.pagination-lg .f-page-link{font-size:.875rem;line-height:1.5;padding:.75rem}.pagination-sm .f-page-link{font-size:.75rem;line-height:1.5;padding:.1875rem}.f-alert{position:relative;padding:.75rem 1.25rem;margin-bottom:1rem;border:1px solid transparent;border-radius:3px}.f-alert-dismissible{padding-right:3.71875rem}.f-alert-dismissible .f-close{position:absolute;top:0;right:0;padding:.75rem 1.25rem}.alert-primary{background-color:#d4e7ff;border-color:#c3ddff;color:#164685}.alert-primary .f-alert-link{color:#0f2f59}.alert-primary hr{border-top-color:#aacfff}.alert-secondary{background-color:#e2e3e5;border-color:#d6d8db;color:#383d41}.alert-secondary .f-alert-link{color:#202326}.alert-secondary hr{border-top-color:#c8cbcf}.alert-success{background-color:#e2f4e5;border-color:#d6efdb;color:#386742}.alert-success .f-alert-link{color:#26462d}.alert-success hr{border-top-color:#c4e8cb}.alert-info{background-color:#dfedff;border-color:#d2e6ff;color:#315585}.alert-info .f-alert-link{color:#233d60}.alert-info hr{border-top-color:#b9d8ff}.alert-warning{background-color:#fdecda;border-color:#fce5cb;color:#7f5423}.alert-warning .f-alert-link{color:#573a18}.alert-warning hr{border-top-color:#fbd9b3}.alert-danger{background-color:#f8d7da;border-color:#f5c6cb;color:#721c24}.alert-danger .f-alert-link{color:#491217}.alert-danger hr{border-top-color:#f1b0b7}.alert-light{background-color:#fefefe;border-color:#fdfdfe;color:#818182}.alert-light .f-alert-link{color:#686868}.alert-light hr{border-top-color:#ececf6}.alert-dark{background-color:#d6d8d9;border-color:#c6c8ca;color:#1b1e21}.alert-dark .f-alert-link{color:#040505}.alert-dark hr{border-top-color:#b9bbbe}@keyframes progress-bar-stripes{from{background-position:1rem 0}to{background-position:0 0}}.progress{height:1rem;font-size:.60938rem;background-color:#e9ecef;box-shadow:inset 0 .1rem .1rem rgba(0,0,0,.1)}.progress-bar{display:flex;flex-direction:column;justify-content:center;color:#fff;text-align:center;white-space:nowrap;background-color:#2A87FF;transition:width .6s ease}@media screen and (prefers-reduced-motion:reduce){.progress-bar{transition:none}}.progress-bar-striped{background-image:linear-gradient(45deg,rgba(255,255,255,.25),transparent 25%,transparent 50%,rgba(255,255,255,.5),rgba(255,255,255,.75),transparent 75%,transparent);background-size:1rem 1rem}.progress-bar-animated{animation:progress-bar-stripes 1s linear infinite}.media{display:flex;align-items:flex-start}.media-body{flex-grow:1;flex-shrink:1;flex-basis:0%}.f-list-group{display:flex;flex-direction:column;padding-left:0;margin-bottom:0}.f-list-group-item-action{width:100%;color:#495057;text-align:inherit}.f-list-group-item-action:focus,.f-list-group-item-action:hover{color:#495057;text-decoration:none;background-color:#f8f9fa}.f-list-group-item-action:active{color:#2D2F33;background-color:#e9ecef}.f-list-group-item{position:relative;display:block;padding:.75rem 1.25rem;margin-bottom:-1px;background-color:#fff;border:1px solid rgba(0,0,0,.125)}.f-list-group-item:first-child{border-top-left-radius:3px;border-top-right-radius:3px}.f-list-group-item:last-child{margin-bottom:0;border-bottom-right-radius:3px;border-bottom-left-radius:3px}.f-list-group-item:focus,.f-list-group-item:hover{z-index:1;text-decoration:none}.f-list-group-item.disabled,.f-list-group-item:disabled{color:#6c757d;background-color:#fff}.f-list-group-item.active{z-index:2;color:#fff;background-color:#2A87FF;border-color:#2A87FF}.f-list-group-flush .f-list-group-item{border-right:0;border-left:0;border-radius:0}.f-list-group-flush:first-child .f-list-group-item:first-child{border-top:0}.f-list-group-flush:last-child .f-list-group-item:last-child{border-bottom:0}.list-group-item-primary{color:#164685;background-color:#c3ddff}.list-group-item-primary.list-group-item-action:focus,.list-group-item-primary.list-group-item-action:hover{color:#164685;background-color:#aacfff}.list-group-item-primary.list-group-item-action.active{color:#fff;background-color:#164685;border-color:#164685}.list-group-item-secondary{color:#383d41;background-color:#d6d8db}.list-group-item-secondary.list-group-item-action:focus,.list-group-item-secondary.list-group-item-action:hover{color:#383d41;background-color:#c8cbcf}.list-group-item-secondary.list-group-item-action.active{color:#fff;background-color:#383d41;border-color:#383d41}.list-group-item-success{color:#386742;background-color:#d6efdb}.list-group-item-success.list-group-item-action:focus,.list-group-item-success.list-group-item-action:hover{color:#386742;background-color:#c4e8cb}.list-group-item-success.list-group-item-action.active{color:#fff;background-color:#386742;border-color:#386742}.list-group-item-info{color:#315585;background-color:#d2e6ff}.list-group-item-info.list-group-item-action:focus,.list-group-item-info.list-group-item-action:hover{color:#315585;background-color:#b9d8ff}.list-group-item-info.list-group-item-action.active{color:#fff;background-color:#315585;border-color:#315585}.list-group-item-warning{color:#7f5423;background-color:#fce5cb}.list-group-item-warning.list-group-item-action:focus,.list-group-item-warning.list-group-item-action:hover{color:#7f5423;background-color:#fbd9b3}.list-group-item-warning.list-group-item-action.active{color:#fff;background-color:#7f5423;border-color:#7f5423}.list-group-item-danger{color:#721c24;background-color:#f5c6cb}.list-group-item-danger.list-group-item-action:focus,.list-group-item-danger.list-group-item-action:hover{color:#721c24;background-color:#f1b0b7}.list-group-item-danger.list-group-item-action.active{color:#fff;background-color:#721c24;border-color:#721c24}.list-group-item-light{color:#818182;background-color:#fdfdfe}.list-group-item-light.list-group-item-action:focus,.list-group-item-light.list-group-item-action:hover{color:#818182;background-color:#ececf6}.list-group-item-light.list-group-item-action.active{color:#fff;background-color:#818182;border-color:#818182}.list-group-item-dark{color:#1b1e21;background-color:#c6c8ca}.list-group-item-dark.list-group-item-action:focus,.list-group-item-dark.list-group-item-action:hover{color:#1b1e21;background-color:#b9bbbe}.list-group-item-dark.list-group-item-action.active{color:#fff;background-color:#1b1e21;border-color:#1b1e21}.close{float:right;font-size:1.21875rem;line-height:1;color:#000;text-shadow:0 1px 0 #fff;opacity:.5}.popover,.tooltip{font-family:-apple-system,BlinkMacSystemFont,"Segoe UI","PingFang SC","Hiragino Sans GB","Microsoft YaHei","Helvetica Neue",Helvetica,Arial,sans-serif;font-weight:400;text-decoration:none;letter-spacing:normal;word-spacing:normal;white-space:normal;line-break:auto;font-size:.75rem;word-wrap:break-word}.close:not(:disabled):not(.disabled):focus,.close:not(:disabled):not(.disabled):hover{color:#000;text-decoration:none;opacity:.75}button.close{padding:0;background-color:transparent;border:0;-webkit-appearance:none}.modal-open .modal{overflow-x:hidden;overflow-y:auto}.modal{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1050;overflow:hidden;outline:0}.modal-dialog{position:relative;width:auto;margin:.5rem;pointer-events:none}.modal.fade .modal-dialog{transition:transform .3s ease-out;transform:translate(0,-25%)}@media screen and (prefers-reduced-motion:reduce){.modal.fade .modal-dialog{transition:none}}.modal.show .modal-dialog{transform:translate(0,0)}.modal-dialog-centered{display:flex;align-items:center;min-height:calc(100% - (.5rem * 2))}.modal-dialog-centered::before{display:block;height:calc(100vh - (.5rem * 2));content:""}.modal-content{position:relative;display:flex;flex-direction:column;width:100%;pointer-events:auto;background-color:#fff;background-clip:padding-box;border:0 solid #E5E9EF;border-radius:3px;box-shadow:0 .125rem .75rem rgba(0,0,0,.06);outline:0}.modal-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1040;background-color:#000}.modal-backdrop.fade{opacity:0}.modal-backdrop.show{opacity:.15}.modal-title{margin-bottom:0;line-height:1.375rem}.modal-body{position:relative;flex-grow:1;flex-shrink:1;flex-basis:auto;padding:.625rem}.modal-scrollbar-measure{position:absolute;top:-9999px;width:3.125rem;height:3.125rem;overflow:scroll}@media (min-width:576px){.modal-dialog{max-width:31.25rem;margin:1.75rem auto}.modal-dialog-centered{min-height:calc(100% - (1.75rem * 2))}.modal-dialog-centered::before{height:calc(100vh - (1.75rem * 2))}.modal-content{box-shadow:0 .125rem .75rem 0 rgba(0,0,0,.06)}.modal-sm{max-width:18.75rem}}@media (min-width:888px){.modal-lg{max-width:50rem}}.tooltip{position:absolute;z-index:1070;display:block;margin:0;line-height:1.4286;text-align:left;text-align:start;text-shadow:none;word-break:normal;opacity:0}.tooltip.show{opacity:1}.tooltip .arrow{position:absolute;display:block;width:.8rem;height:.4rem}.tooltip .arrow::before{position:absolute;content:"";border-color:transparent;border-style:solid}.f-bs-tooltip-auto[x-placement^=top],.f-bs-tooltip-top{padding:.4rem 0}.f-bs-tooltip-auto[x-placement^=top] .arrow,.f-bs-tooltip-top .arrow{bottom:0}.f-bs-tooltip-auto[x-placement^=top] .arrow::before,.f-bs-tooltip-top .arrow::before{top:0;border-width:.4rem .4rem 0;border-top-color:#303C53}.f-bs-tooltip-auto[x-placement^=right],.f-bs-tooltip-right{padding:0 .4rem}.f-bs-tooltip-auto[x-placement^=right] .arrow,.f-bs-tooltip-right .arrow{left:0;width:.4rem;height:.8rem}.f-bs-tooltip-auto[x-placement^=right] .arrow::before,.f-bs-tooltip-right .arrow::before{right:0;border-width:.4rem .4rem .4rem 0;border-right-color:#303C53}.f-bs-tooltip-auto[x-placement^=bottom],.f-bs-tooltip-bottom{padding:.4rem 0}.f-bs-tooltip-auto[x-placement^=bottom] .arrow,.f-bs-tooltip-bottom .arrow{top:0}.f-bs-tooltip-auto[x-placement^=bottom] .arrow::before,.f-bs-tooltip-bottom .arrow::before{bottom:0;border-width:0 .4rem .4rem;border-bottom-color:#303C53}.f-bs-tooltip-auto[x-placement^=left],.f-bs-tooltip-left{padding:0 .4rem}.f-bs-tooltip-auto[x-placement^=left] .arrow,.f-bs-tooltip-left .arrow{right:0;width:.4rem;height:.8rem}.f-bs-tooltip-auto[x-placement^=left] .arrow::before,.f-bs-tooltip-left .arrow::before{left:0;border-width:.4rem 0 .4rem .4rem;border-left-color:#303C53}.tooltip-inner{max-width:18.75rem;max-height:6.25rem;overflow:hidden;padding:.5rem .625rem;color:#fff;text-align:left;background-color:#303C53;box-shadow:0 2px 8px 0 rgba(0,0,0,.15);border-radius:3px}.tooltip-inner-lg{max-width:37.5rem;max-height:initial;overflow:initial}.popover{position:absolute;top:0;left:0;z-index:1060;display:block;line-height:1.4286;text-align:left;text-align:start;text-shadow:none;word-break:normal;background-color:#fff;background-clip:padding-box;border:1px solid #fff;border-radius:4px;box-shadow:0 2px 8px 0 rgba(0,32,74,.15)}.popover .arrow{position:absolute;display:block;width:1rem;height:.5rem;margin:0 3px}.popover .arrow::after,.popover .arrow::before{position:absolute;display:block;content:"";border-color:transparent;border-style:solid}.f-bs-popover-auto[x-placement^=top],.f-bs-popover-top{margin-bottom:.5rem}.f-bs-popover-auto[x-placement^=top] .arrow,.f-bs-popover-top .arrow{bottom:calc((.5rem + 1px) * -1)}.f-bs-popover-auto[x-placement^=top] .arrow::after,.f-bs-popover-auto[x-placement^=top] .arrow::before,.f-bs-popover-top .arrow::after,.f-bs-popover-top .arrow::before{border-width:.5rem .5rem 0}.f-bs-popover-auto[x-placement^=top] .arrow::before,.f-bs-popover-top .arrow::before{bottom:0;border-top-color:rgba(255,255,255,.4)}.f-bs-popover-auto[x-placement^=top] .arrow::after,.f-bs-popover-top .arrow::after{bottom:1px;border-top-color:#fff}.f-bs-popover-auto[x-placement^=right],.f-bs-popover-right{margin-left:.5rem}.f-bs-popover-auto[x-placement^=right] .arrow,.f-bs-popover-right .arrow{left:calc((.5rem + 1px) * -1);width:.5rem;height:1rem;margin:3px 0}.f-bs-popover-auto[x-placement^=right] .arrow::after,.f-bs-popover-auto[x-placement^=right] .arrow::before,.f-bs-popover-right .arrow::after,.f-bs-popover-right .arrow::before{border-width:.5rem .5rem .5rem 0}.f-bs-popover-auto[x-placement^=right] .arrow::before,.f-bs-popover-right .arrow::before{left:0;border-right-color:rgba(255,255,255,.4)}.f-bs-popover-auto[x-placement^=right] .arrow::after,.f-bs-popover-right .arrow::after{left:1px;border-right-color:#fff}.f-bs-popover-auto[x-placement^=bottom],.f-bs-popover-bottom{margin-top:.5rem}.f-bs-popover-auto[x-placement^=bottom] .arrow,.f-bs-popover-bottom .arrow{top:calc((.5rem + 1px) * -1)}.f-bs-popover-auto[x-placement^=bottom] .arrow::after,.f-bs-popover-auto[x-placement^=bottom] .arrow::before,.f-bs-popover-bottom .arrow::after,.f-bs-popover-bottom .arrow::before{border-width:0 .5rem .5rem}.f-bs-popover-auto[x-placement^=bottom] .arrow::before,.f-bs-popover-bottom .arrow::before{top:0;border-bottom-color:rgba(255,255,255,.4)}.f-bs-popover-auto[x-placement^=bottom] .arrow::after,.f-bs-popover-bottom .arrow::after{top:1px;border-bottom-color:#fff}.f-bs-popover-auto[x-placement^=bottom] .popover-header::before,.f-bs-popover-bottom .popover-header::before{position:absolute;top:0;left:50%;display:block;width:1rem;margin-left:-.5rem;content:"";border-bottom:1px solid #f7f7f7}.f-bs-popover-auto[x-placement^=left],.f-bs-popover-left{margin-right:.5rem}.f-bs-popover-auto[x-placement^=left] .arrow,.f-bs-popover-left .arrow{right:calc((.5rem + 1px) * -1);width:.5rem;height:1rem;margin:3px 0}.f-bs-popover-auto[x-placement^=left] .arrow::after,.f-bs-popover-auto[x-placement^=left] .arrow::before,.f-bs-popover-left .arrow::after,.f-bs-popover-left .arrow::before{border-width:.5rem 0 .5rem .5rem}.f-bs-popover-auto[x-placement^=left] .arrow::before,.f-bs-popover-left .arrow::before{right:0;border-left-color:rgba(255,255,255,.4)}.f-bs-popover-auto[x-placement^=left] .arrow::after,.f-bs-popover-left .arrow::after{right:1px;border-left-color:#fff}.popover-header{padding:.5rem .75rem;margin-bottom:0;font-size:.8125rem;background-color:#f7f7f7;border-bottom:1px solid #ebebeb;border-top-left-radius:calc(3px - 1px);border-top-right-radius:calc(3px - 1px)}.popover-header:empty{display:none}.popover-body{max-width:17.25rem;padding:.5rem .75rem;color:#2D2F33}.align-baseline{vertical-align:baseline!important}.align-top{vertical-align:top!important}.align-middle{vertical-align:middle!important}.align-bottom{vertical-align:bottom!important}.align-text-bottom{vertical-align:text-bottom!important}.align-text-top{vertical-align:text-top!important}.bg-primary{background-color:#2A87FF!important}a.bg-primary:focus,a.bg-primary:hover,button.bg-primary:focus,button.bg-primary:hover{background-color:#006bf6!important}.bg-secondary{background-color:#6c757d!important}a.bg-secondary:focus,a.bg-secondary:hover,button.bg-secondary:focus,button.bg-secondary:hover{background-color:#545b62!important}.bg-success{background-color:#6CC77F!important}a.bg-success:focus,a.bg-success:hover,button.bg-success:focus,button.bg-success:hover{background-color:#47b95f!important}.bg-info{background-color:#5EA4FF!important}a.bg-info:focus,a.bg-info:hover,button.bg-info:focus,button.bg-info:hover{background-color:#2b87ff!important}.bg-warning{background-color:#F5A144!important}a.bg-warning:focus,a.bg-warning:hover,button.bg-warning:focus,button.bg-warning:hover{background-color:#f28914!important}.bg-danger{background-color:#dc3545!important}a.bg-danger:focus,a.bg-danger:hover,button.bg-danger:focus,button.bg-danger:hover{background-color:#bd2130!important}.bg-light{background-color:#f8f9fa!important}a.bg-light:focus,a.bg-light:hover,button.bg-light:focus,button.bg-light:hover{background-color:#dae0e5!important}.bg-dark{background-color:#343a40!important}a.bg-dark:focus,a.bg-dark:hover,button.bg-dark:focus,button.bg-dark:hover{background-color:#1d2124!important}.bg-white{background-color:#fff!important}.bg-transparent{background-color:transparent!important}.border{border:1px solid #E6E9F0!important}.border-top{border-top:1px solid #E6E9F0!important}.border-right{border-right:1px solid #E6E9F0!important}.border-bottom{border-bottom:1px solid #E6E9F0!important}.border-left{border-left:1px solid #E6E9F0!important}.border-0{border:0!important}.rounded-right,.rounded-top{border-top-right-radius:3px!important}.rounded-bottom,.rounded-right{border-bottom-right-radius:3px!important}.rounded-left,.rounded-top{border-top-left-radius:3px!important}.rounded-bottom,.rounded-left{border-bottom-left-radius:3px!important}.border-top-0{border-top:0!important}.border-right-0{border-right:0!important}.border-bottom-0{border-bottom:0!important}.border-left-0{border-left:0!important}.border-primary{border-color:#2A87FF!important}.border-secondary{border-color:#6c757d!important}.border-success{border-color:#6CC77F!important}.border-info{border-color:#5EA4FF!important}.border-warning{border-color:#F5A144!important}.border-danger{border-color:#dc3545!important}.border-light{border-color:#f8f9fa!important}.border-dark{border-color:#343a40!important}.border-white{border-color:#fff!important}.rounded{border-radius:3px!important}.rounded-circle{border-radius:50%!important}.rounded-0{border-radius:0!important}.f-clearfix::after{display:block;clear:both;content:""}.d-none{display:none!important}.d-inline{display:inline!important}.d-inline-block{display:inline-block!important}.d-block{display:block!important}.d-table{display:table!important}.d-table-row{display:table-row!important}.d-table-cell{display:table-cell!important}.d-flex{display:flex!important}.d-inline-flex{display:inline-flex!important}.flex-row{flex-direction:row!important}.flex-column{flex-direction:column!important}.flex-row-reverse{flex-direction:row-reverse!important}.flex-column-reverse{flex-direction:column-reverse!important}.flex-wrap{flex-wrap:wrap!important}.flex-nowrap{flex-wrap:nowrap!important}.flex-wrap-reverse{flex-wrap:wrap-reverse!important}.flex-fill{flex-grow:1!important;flex-shrink:1!important;flex-basis:auto!important}.flex-grow-0{flex-grow:0!important}.flex-grow-1{flex-grow:1!important}.flex-shrink-0{flex-shrink:0!important}.flex-shrink-1{flex-shrink:1!important}.justify-content-start{justify-content:flex-start!important}.justify-content-end{justify-content:flex-end!important}.justify-content-center{justify-content:center!important}.justify-content-between{justify-content:space-between!important}.justify-content-around{justify-content:space-around!important}.align-items-start{align-items:flex-start!important}.align-items-end{align-items:flex-end!important}.align-items-center{align-items:center!important}.align-items-baseline{align-items:baseline!important}.align-items-stretch{align-items:stretch!important}.align-content-start{align-content:flex-start!important}.align-content-end{align-content:flex-end!important}.align-content-center{align-content:center!important}.align-content-between{align-content:space-between!important}.align-content-around{align-content:space-around!important}.align-content-stretch{align-content:stretch!important}.align-self-auto{align-self:auto!important}.align-self-start{align-self:flex-start!important}.align-self-end{align-self:flex-end!important}.align-self-center{align-self:center!important}.align-self-baseline{align-self:baseline!important}.align-self-stretch{align-self:stretch!important}.float-left{float:left!important}.float-right{float:right!important}.float-none{float:none!important}.position-static{position:static!important}.position-relative{position:relative!important}.position-absolute{position:absolute!important}.position-fixed{position:fixed!important}.position-sticky{position:sticky!important}.fixed-bottom,.fixed-top{position:fixed;right:0;left:0;z-index:1030}.fixed-top{top:0}.fixed-bottom{bottom:0}@supports (position:sticky){.sticky-top{position:sticky;top:0;z-index:1020}}.shadow-sm{box-shadow:0 .125rem .25rem rgba(0,0,0,.075)!important}.shadow{box-shadow:0 .5rem 1rem rgba(0,0,0,.15)!important}.shadow-lg{box-shadow:0 1rem 3rem rgba(0,0,0,.175)!important}.shadow-none{box-shadow:none!important}.w-25{width:25%!important}.w-50{width:50%!important}.w-75{width:75%!important}.w-100{width:100%!important}.w-auto{width:auto!important}.h-25{height:25%!important}.h-50{height:50%!important}.h-75{height:75%!important}.h-100{height:100%!important}.h-auto{height:auto!important}.mw-100{max-width:100%!important}.mh-100{max-height:100%!important}.m-0{margin:0!important}.mt-0,.my-0{margin-top:0!important}.mr-0,.mx-0{margin-right:0!important}.mb-0,.my-0{margin-bottom:0!important}.ml-0,.mx-0{margin-left:0!important}.m-1{margin:.25rem!important}.mt-1,.my-1{margin-top:.25rem!important}.mr-1,.mx-1{margin-right:.25rem!important}.mb-1,.my-1{margin-bottom:.25rem!important}.ml-1,.mx-1{margin-left:.25rem!important}.m-2{margin:.5rem!important}.mt-2,.my-2{margin-top:.5rem!important}.mr-2,.mx-2{margin-right:.5rem!important}.mb-2,.my-2{margin-bottom:.5rem!important}.ml-2,.mx-2{margin-left:.5rem!important}.m-3{margin:1rem!important}.mt-3,.my-3{margin-top:1rem!important}.mr-3,.mx-3{margin-right:1rem!important}.mb-3,.my-3{margin-bottom:1rem!important}.ml-3,.mx-3{margin-left:1rem!important}.m-4{margin:1.5rem!important}.mt-4,.my-4{margin-top:1.5rem!important}.mr-4,.mx-4{margin-right:1.5rem!important}.mb-4,.my-4{margin-bottom:1.5rem!important}.ml-4,.mx-4{margin-left:1.5rem!important}.m-5{margin:3rem!important}.mt-5,.my-5{margin-top:3rem!important}.mr-5,.mx-5{margin-right:3rem!important}.mb-5,.my-5{margin-bottom:3rem!important}.ml-5,.mx-5{margin-left:3rem!important}.p-0{padding:0!important}.pt-0,.py-0{padding-top:0!important}.pr-0,.px-0{padding-right:0!important}.pb-0,.py-0{padding-bottom:0!important}.pl-0,.px-0{padding-left:0!important}.p-1{padding:.25rem!important}.pt-1,.py-1{padding-top:.25rem!important}.pr-1,.px-1{padding-right:.25rem!important}.pb-1,.py-1{padding-bottom:.25rem!important}.pl-1,.px-1{padding-left:.25rem!important}.p-2{padding:.5rem!important}.pt-2,.py-2{padding-top:.5rem!important}.pr-2,.px-2{padding-right:.5rem!important}.pb-2,.py-2{padding-bottom:.5rem!important}.pl-2,.px-2{padding-left:.5rem!important}.p-3{padding:1rem!important}.pt-3,.py-3{padding-top:1rem!important}.pr-3,.px-3{padding-right:1rem!important}.pb-3,.py-3{padding-bottom:1rem!important}.pl-3,.px-3{padding-left:1rem!important}.p-4{padding:1.5rem!important}.pt-4,.py-4{padding-top:1.5rem!important}.pr-4,.px-4{padding-right:1.5rem!important}.pb-4,.py-4{padding-bottom:1.5rem!important}.pl-4,.px-4{padding-left:1.5rem!important}.p-5{padding:3rem!important}.pt-5,.py-5{padding-top:3rem!important}.pr-5,.px-5{padding-right:3rem!important}.pb-5,.py-5{padding-bottom:3rem!important}.pl-5,.px-5{padding-left:3rem!important}.m-auto{margin:auto!important}.mt-auto,.my-auto{margin-top:auto!important}.mr-auto,.mx-auto{margin-right:auto!important}.mb-auto,.my-auto{margin-bottom:auto!important}.ml-auto,.mx-auto{margin-left:auto!important}.f-text-justify{text-align:justify!important}.f-text-nowrap{white-space:nowrap!important}.f-text-overflow{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.text-left{text-align:left!important}.text-right{text-align:right!important}.text-center{text-align:center!important}@media (min-width:576px){.d-sm-none{display:none!important}.d-sm-inline{display:inline!important}.d-sm-inline-block{display:inline-block!important}.d-sm-block{display:block!important}.d-sm-table{display:table!important}.d-sm-table-row{display:table-row!important}.d-sm-table-cell{display:table-cell!important}.d-sm-flex{display:flex!important}.d-sm-inline-flex{display:inline-flex!important}.flex-sm-row{flex-direction:row!important}.flex-sm-column{flex-direction:column!important}.flex-sm-row-reverse{flex-direction:row-reverse!important}.flex-sm-column-reverse{flex-direction:column-reverse!important}.flex-sm-wrap{flex-wrap:wrap!important}.flex-sm-nowrap{flex-wrap:nowrap!important}.flex-sm-wrap-reverse{flex-wrap:wrap-reverse!important}.flex-sm-fill{flex-grow:1!important;flex-shrink:1!important;flex-basis:auto!important}.flex-sm-grow-0{flex-grow:0!important}.flex-sm-grow-1{flex-grow:1!important}.flex-sm-shrink-0{flex-shrink:0!important}.flex-sm-shrink-1{flex-shrink:1!important}.justify-content-sm-start{justify-content:flex-start!important}.justify-content-sm-end{justify-content:flex-end!important}.justify-content-sm-center{justify-content:center!important}.justify-content-sm-between{justify-content:space-between!important}.justify-content-sm-around{justify-content:space-around!important}.align-items-sm-start{align-items:flex-start!important}.align-items-sm-end{align-items:flex-end!important}.align-items-sm-center{align-items:center!important}.align-items-sm-baseline{align-items:baseline!important}.align-items-sm-stretch{align-items:stretch!important}.align-content-sm-start{align-content:flex-start!important}.align-content-sm-end{align-content:flex-end!important}.align-content-sm-center{align-content:center!important}.align-content-sm-between{align-content:space-between!important}.align-content-sm-around{align-content:space-around!important}.align-content-sm-stretch{align-content:stretch!important}.align-self-sm-auto{align-self:auto!important}.align-self-sm-start{align-self:flex-start!important}.align-self-sm-end{align-self:flex-end!important}.align-self-sm-center{align-self:center!important}.align-self-sm-baseline{align-self:baseline!important}.align-self-sm-stretch{align-self:stretch!important}.float-sm-left{float:left!important}.float-sm-right{float:right!important}.float-sm-none{float:none!important}.m-sm-0{margin:0!important}.mt-sm-0,.my-sm-0{margin-top:0!important}.mr-sm-0,.mx-sm-0{margin-right:0!important}.mb-sm-0,.my-sm-0{margin-bottom:0!important}.ml-sm-0,.mx-sm-0{margin-left:0!important}.m-sm-1{margin:.25rem!important}.mt-sm-1,.my-sm-1{margin-top:.25rem!important}.mr-sm-1,.mx-sm-1{margin-right:.25rem!important}.mb-sm-1,.my-sm-1{margin-bottom:.25rem!important}.ml-sm-1,.mx-sm-1{margin-left:.25rem!important}.m-sm-2{margin:.5rem!important}.mt-sm-2,.my-sm-2{margin-top:.5rem!important}.mr-sm-2,.mx-sm-2{margin-right:.5rem!important}.mb-sm-2,.my-sm-2{margin-bottom:.5rem!important}.ml-sm-2,.mx-sm-2{margin-left:.5rem!important}.m-sm-3{margin:1rem!important}.mt-sm-3,.my-sm-3{margin-top:1rem!important}.mr-sm-3,.mx-sm-3{margin-right:1rem!important}.mb-sm-3,.my-sm-3{margin-bottom:1rem!important}.ml-sm-3,.mx-sm-3{margin-left:1rem!important}.m-sm-4{margin:1.5rem!important}.mt-sm-4,.my-sm-4{margin-top:1.5rem!important}.mr-sm-4,.mx-sm-4{margin-right:1.5rem!important}.mb-sm-4,.my-sm-4{margin-bottom:1.5rem!important}.ml-sm-4,.mx-sm-4{margin-left:1.5rem!important}.m-sm-5{margin:3rem!important}.mt-sm-5,.my-sm-5{margin-top:3rem!important}.mr-sm-5,.mx-sm-5{margin-right:3rem!important}.mb-sm-5,.my-sm-5{margin-bottom:3rem!important}.ml-sm-5,.mx-sm-5{margin-left:3rem!important}.p-sm-0{padding:0!important}.pt-sm-0,.py-sm-0{padding-top:0!important}.pr-sm-0,.px-sm-0{padding-right:0!important}.pb-sm-0,.py-sm-0{padding-bottom:0!important}.pl-sm-0,.px-sm-0{padding-left:0!important}.p-sm-1{padding:.25rem!important}.pt-sm-1,.py-sm-1{padding-top:.25rem!important}.pr-sm-1,.px-sm-1{padding-right:.25rem!important}.pb-sm-1,.py-sm-1{padding-bottom:.25rem!important}.pl-sm-1,.px-sm-1{padding-left:.25rem!important}.p-sm-2{padding:.5rem!important}.pt-sm-2,.py-sm-2{padding-top:.5rem!important}.pr-sm-2,.px-sm-2{padding-right:.5rem!important}.pb-sm-2,.py-sm-2{padding-bottom:.5rem!important}.pl-sm-2,.px-sm-2{padding-left:.5rem!important}.p-sm-3{padding:1rem!important}.pt-sm-3,.py-sm-3{padding-top:1rem!important}.pr-sm-3,.px-sm-3{padding-right:1rem!important}.pb-sm-3,.py-sm-3{padding-bottom:1rem!important}.pl-sm-3,.px-sm-3{padding-left:1rem!important}.p-sm-4{padding:1.5rem!important}.pt-sm-4,.py-sm-4{padding-top:1.5rem!important}.pr-sm-4,.px-sm-4{padding-right:1.5rem!important}.pb-sm-4,.py-sm-4{padding-bottom:1.5rem!important}.pl-sm-4,.px-sm-4{padding-left:1.5rem!important}.p-sm-5{padding:3rem!important}.pt-sm-5,.py-sm-5{padding-top:3rem!important}.pr-sm-5,.px-sm-5{padding-right:3rem!important}.pb-sm-5,.py-sm-5{padding-bottom:3rem!important}.pl-sm-5,.px-sm-5{padding-left:3rem!important}.m-sm-auto{margin:auto!important}.mt-sm-auto,.my-sm-auto{margin-top:auto!important}.mr-sm-auto,.mx-sm-auto{margin-right:auto!important}.mb-sm-auto,.my-sm-auto{margin-bottom:auto!important}.ml-sm-auto,.mx-sm-auto{margin-left:auto!important}.text-sm-left{text-align:left!important}.text-sm-right{text-align:right!important}.text-sm-center{text-align:center!important}}@media (min-width:768px){.d-md-none{display:none!important}.d-md-inline{display:inline!important}.d-md-inline-block{display:inline-block!important}.d-md-block{display:block!important}.d-md-table{display:table!important}.d-md-table-row{display:table-row!important}.d-md-table-cell{display:table-cell!important}.d-md-flex{display:flex!important}.d-md-inline-flex{display:inline-flex!important}.flex-md-row{flex-direction:row!important}.flex-md-column{flex-direction:column!important}.flex-md-row-reverse{flex-direction:row-reverse!important}.flex-md-column-reverse{flex-direction:column-reverse!important}.flex-md-wrap{flex-wrap:wrap!important}.flex-md-nowrap{flex-wrap:nowrap!important}.flex-md-wrap-reverse{flex-wrap:wrap-reverse!important}.flex-md-fill{flex-grow:1!important;flex-shrink:1!important;flex-basis:auto!important}.flex-md-grow-0{flex-grow:0!important}.flex-md-grow-1{flex-grow:1!important}.flex-md-shrink-0{flex-shrink:0!important}.flex-md-shrink-1{flex-shrink:1!important}.justify-content-md-start{justify-content:flex-start!important}.justify-content-md-end{justify-content:flex-end!important}.justify-content-md-center{justify-content:center!important}.justify-content-md-between{justify-content:space-between!important}.justify-content-md-around{justify-content:space-around!important}.align-items-md-start{align-items:flex-start!important}.align-items-md-end{align-items:flex-end!important}.align-items-md-center{align-items:center!important}.align-items-md-baseline{align-items:baseline!important}.align-items-md-stretch{align-items:stretch!important}.align-content-md-start{align-content:flex-start!important}.align-content-md-end{align-content:flex-end!important}.align-content-md-center{align-content:center!important}.align-content-md-between{align-content:space-between!important}.align-content-md-around{align-content:space-around!important}.align-content-md-stretch{align-content:stretch!important}.align-self-md-auto{align-self:auto!important}.align-self-md-start{align-self:flex-start!important}.align-self-md-end{align-self:flex-end!important}.align-self-md-center{align-self:center!important}.align-self-md-baseline{align-self:baseline!important}.align-self-md-stretch{align-self:stretch!important}.float-md-left{float:left!important}.float-md-right{float:right!important}.float-md-none{float:none!important}.m-md-0{margin:0!important}.mt-md-0,.my-md-0{margin-top:0!important}.mr-md-0,.mx-md-0{margin-right:0!important}.mb-md-0,.my-md-0{margin-bottom:0!important}.ml-md-0,.mx-md-0{margin-left:0!important}.m-md-1{margin:.25rem!important}.mt-md-1,.my-md-1{margin-top:.25rem!important}.mr-md-1,.mx-md-1{margin-right:.25rem!important}.mb-md-1,.my-md-1{margin-bottom:.25rem!important}.ml-md-1,.mx-md-1{margin-left:.25rem!important}.m-md-2{margin:.5rem!important}.mt-md-2,.my-md-2{margin-top:.5rem!important}.mr-md-2,.mx-md-2{margin-right:.5rem!important}.mb-md-2,.my-md-2{margin-bottom:.5rem!important}.ml-md-2,.mx-md-2{margin-left:.5rem!important}.m-md-3{margin:1rem!important}.mt-md-3,.my-md-3{margin-top:1rem!important}.mr-md-3,.mx-md-3{margin-right:1rem!important}.mb-md-3,.my-md-3{margin-bottom:1rem!important}.ml-md-3,.mx-md-3{margin-left:1rem!important}.m-md-4{margin:1.5rem!important}.mt-md-4,.my-md-4{margin-top:1.5rem!important}.mr-md-4,.mx-md-4{margin-right:1.5rem!important}.mb-md-4,.my-md-4{margin-bottom:1.5rem!important}.ml-md-4,.mx-md-4{margin-left:1.5rem!important}.m-md-5{margin:3rem!important}.mt-md-5,.my-md-5{margin-top:3rem!important}.mr-md-5,.mx-md-5{margin-right:3rem!important}.mb-md-5,.my-md-5{margin-bottom:3rem!important}.ml-md-5,.mx-md-5{margin-left:3rem!important}.p-md-0{padding:0!important}.pt-md-0,.py-md-0{padding-top:0!important}.pr-md-0,.px-md-0{padding-right:0!important}.pb-md-0,.py-md-0{padding-bottom:0!important}.pl-md-0,.px-md-0{padding-left:0!important}.p-md-1{padding:.25rem!important}.pt-md-1,.py-md-1{padding-top:.25rem!important}.pr-md-1,.px-md-1{padding-right:.25rem!important}.pb-md-1,.py-md-1{padding-bottom:.25rem!important}.pl-md-1,.px-md-1{padding-left:.25rem!important}.p-md-2{padding:.5rem!important}.pt-md-2,.py-md-2{padding-top:.5rem!important}.pr-md-2,.px-md-2{padding-right:.5rem!important}.pb-md-2,.py-md-2{padding-bottom:.5rem!important}.pl-md-2,.px-md-2{padding-left:.5rem!important}.p-md-3{padding:1rem!important}.pt-md-3,.py-md-3{padding-top:1rem!important}.pr-md-3,.px-md-3{padding-right:1rem!important}.pb-md-3,.py-md-3{padding-bottom:1rem!important}.pl-md-3,.px-md-3{padding-left:1rem!important}.p-md-4{padding:1.5rem!important}.pt-md-4,.py-md-4{padding-top:1.5rem!important}.pr-md-4,.px-md-4{padding-right:1.5rem!important}.pb-md-4,.py-md-4{padding-bottom:1.5rem!important}.pl-md-4,.px-md-4{padding-left:1.5rem!important}.p-md-5{padding:3rem!important}.pt-md-5,.py-md-5{padding-top:3rem!important}.pr-md-5,.px-md-5{padding-right:3rem!important}.pb-md-5,.py-md-5{padding-bottom:3rem!important}.pl-md-5,.px-md-5{padding-left:3rem!important}.m-md-auto{margin:auto!important}.mt-md-auto,.my-md-auto{margin-top:auto!important}.mr-md-auto,.mx-md-auto{margin-right:auto!important}.mb-md-auto,.my-md-auto{margin-bottom:auto!important}.ml-md-auto,.mx-md-auto{margin-left:auto!important}.text-md-left{text-align:left!important}.text-md-right{text-align:right!important}.text-md-center{text-align:center!important}}@media (min-width:888px){.d-lg-none{display:none!important}.d-lg-inline{display:inline!important}.d-lg-inline-block{display:inline-block!important}.d-lg-block{display:block!important}.d-lg-table{display:table!important}.d-lg-table-row{display:table-row!important}.d-lg-table-cell{display:table-cell!important}.d-lg-flex{display:flex!important}.d-lg-inline-flex{display:inline-flex!important}.flex-lg-row{flex-direction:row!important}.flex-lg-column{flex-direction:column!important}.flex-lg-row-reverse{flex-direction:row-reverse!important}.flex-lg-column-reverse{flex-direction:column-reverse!important}.flex-lg-wrap{flex-wrap:wrap!important}.flex-lg-nowrap{flex-wrap:nowrap!important}.flex-lg-wrap-reverse{flex-wrap:wrap-reverse!important}.flex-lg-fill{flex-grow:1!important;flex-shrink:1!important;flex-basis:auto!important}.flex-lg-grow-0{flex-grow:0!important}.flex-lg-grow-1{flex-grow:1!important}.flex-lg-shrink-0{flex-shrink:0!important}.flex-lg-shrink-1{flex-shrink:1!important}.justify-content-lg-start{justify-content:flex-start!important}.justify-content-lg-end{justify-content:flex-end!important}.justify-content-lg-center{justify-content:center!important}.justify-content-lg-between{justify-content:space-between!important}.justify-content-lg-around{justify-content:space-around!important}.align-items-lg-start{align-items:flex-start!important}.align-items-lg-end{align-items:flex-end!important}.align-items-lg-center{align-items:center!important}.align-items-lg-baseline{align-items:baseline!important}.align-items-lg-stretch{align-items:stretch!important}.align-content-lg-start{align-content:flex-start!important}.align-content-lg-end{align-content:flex-end!important}.align-content-lg-center{align-content:center!important}.align-content-lg-between{align-content:space-between!important}.align-content-lg-around{align-content:space-around!important}.align-content-lg-stretch{align-content:stretch!important}.align-self-lg-auto{align-self:auto!important}.align-self-lg-start{align-self:flex-start!important}.align-self-lg-end{align-self:flex-end!important}.align-self-lg-center{align-self:center!important}.align-self-lg-baseline{align-self:baseline!important}.align-self-lg-stretch{align-self:stretch!important}.float-lg-left{float:left!important}.float-lg-right{float:right!important}.float-lg-none{float:none!important}.m-lg-0{margin:0!important}.mt-lg-0,.my-lg-0{margin-top:0!important}.mr-lg-0,.mx-lg-0{margin-right:0!important}.mb-lg-0,.my-lg-0{margin-bottom:0!important}.ml-lg-0,.mx-lg-0{margin-left:0!important}.m-lg-1{margin:.25rem!important}.mt-lg-1,.my-lg-1{margin-top:.25rem!important}.mr-lg-1,.mx-lg-1{margin-right:.25rem!important}.mb-lg-1,.my-lg-1{margin-bottom:.25rem!important}.ml-lg-1,.mx-lg-1{margin-left:.25rem!important}.m-lg-2{margin:.5rem!important}.mt-lg-2,.my-lg-2{margin-top:.5rem!important}.mr-lg-2,.mx-lg-2{margin-right:.5rem!important}.mb-lg-2,.my-lg-2{margin-bottom:.5rem!important}.ml-lg-2,.mx-lg-2{margin-left:.5rem!important}.m-lg-3{margin:1rem!important}.mt-lg-3,.my-lg-3{margin-top:1rem!important}.mr-lg-3,.mx-lg-3{margin-right:1rem!important}.mb-lg-3,.my-lg-3{margin-bottom:1rem!important}.ml-lg-3,.mx-lg-3{margin-left:1rem!important}.m-lg-4{margin:1.5rem!important}.mt-lg-4,.my-lg-4{margin-top:1.5rem!important}.mr-lg-4,.mx-lg-4{margin-right:1.5rem!important}.mb-lg-4,.my-lg-4{margin-bottom:1.5rem!important}.ml-lg-4,.mx-lg-4{margin-left:1.5rem!important}.m-lg-5{margin:3rem!important}.mt-lg-5,.my-lg-5{margin-top:3rem!important}.mr-lg-5,.mx-lg-5{margin-right:3rem!important}.mb-lg-5,.my-lg-5{margin-bottom:3rem!important}.ml-lg-5,.mx-lg-5{margin-left:3rem!important}.p-lg-0{padding:0!important}.pt-lg-0,.py-lg-0{padding-top:0!important}.pr-lg-0,.px-lg-0{padding-right:0!important}.pb-lg-0,.py-lg-0{padding-bottom:0!important}.pl-lg-0,.px-lg-0{padding-left:0!important}.p-lg-1{padding:.25rem!important}.pt-lg-1,.py-lg-1{padding-top:.25rem!important}.pr-lg-1,.px-lg-1{padding-right:.25rem!important}.pb-lg-1,.py-lg-1{padding-bottom:.25rem!important}.pl-lg-1,.px-lg-1{padding-left:.25rem!important}.p-lg-2{padding:.5rem!important}.pt-lg-2,.py-lg-2{padding-top:.5rem!important}.pr-lg-2,.px-lg-2{padding-right:.5rem!important}.pb-lg-2,.py-lg-2{padding-bottom:.5rem!important}.pl-lg-2,.px-lg-2{padding-left:.5rem!important}.p-lg-3{padding:1rem!important}.pt-lg-3,.py-lg-3{padding-top:1rem!important}.pr-lg-3,.px-lg-3{padding-right:1rem!important}.pb-lg-3,.py-lg-3{padding-bottom:1rem!important}.pl-lg-3,.px-lg-3{padding-left:1rem!important}.p-lg-4{padding:1.5rem!important}.pt-lg-4,.py-lg-4{padding-top:1.5rem!important}.pr-lg-4,.px-lg-4{padding-right:1.5rem!important}.pb-lg-4,.py-lg-4{padding-bottom:1.5rem!important}.pl-lg-4,.px-lg-4{padding-left:1.5rem!important}.p-lg-5{padding:3rem!important}.pt-lg-5,.py-lg-5{padding-top:3rem!important}.pr-lg-5,.px-lg-5{padding-right:3rem!important}.pb-lg-5,.py-lg-5{padding-bottom:3rem!important}.pl-lg-5,.px-lg-5{padding-left:3rem!important}.m-lg-auto{margin:auto!important}.mt-lg-auto,.my-lg-auto{margin-top:auto!important}.mr-lg-auto,.mx-lg-auto{margin-right:auto!important}.mb-lg-auto,.my-lg-auto{margin-bottom:auto!important}.ml-lg-auto,.mx-lg-auto{margin-left:auto!important}.text-lg-left{text-align:left!important}.text-lg-right{text-align:right!important}.text-lg-center{text-align:center!important}}@media (min-width:1200px){.d-xl-none{display:none!important}.d-xl-inline{display:inline!important}.d-xl-inline-block{display:inline-block!important}.d-xl-block{display:block!important}.d-xl-table{display:table!important}.d-xl-table-row{display:table-row!important}.d-xl-table-cell{display:table-cell!important}.d-xl-flex{display:flex!important}.d-xl-inline-flex{display:inline-flex!important}.flex-xl-row{flex-direction:row!important}.flex-xl-column{flex-direction:column!important}.flex-xl-row-reverse{flex-direction:row-reverse!important}.flex-xl-column-reverse{flex-direction:column-reverse!important}.flex-xl-wrap{flex-wrap:wrap!important}.flex-xl-nowrap{flex-wrap:nowrap!important}.flex-xl-wrap-reverse{flex-wrap:wrap-reverse!important}.flex-xl-fill{flex-grow:1!important;flex-shrink:1!important;flex-basis:auto!important}.flex-xl-grow-0{flex-grow:0!important}.flex-xl-grow-1{flex-grow:1!important}.flex-xl-shrink-0{flex-shrink:0!important}.flex-xl-shrink-1{flex-shrink:1!important}.justify-content-xl-start{justify-content:flex-start!important}.justify-content-xl-end{justify-content:flex-end!important}.justify-content-xl-center{justify-content:center!important}.justify-content-xl-between{justify-content:space-between!important}.justify-content-xl-around{justify-content:space-around!important}.align-items-xl-start{align-items:flex-start!important}.align-items-xl-end{align-items:flex-end!important}.align-items-xl-center{align-items:center!important}.align-items-xl-baseline{align-items:baseline!important}.align-items-xl-stretch{align-items:stretch!important}.align-content-xl-start{align-content:flex-start!important}.align-content-xl-end{align-content:flex-end!important}.align-content-xl-center{align-content:center!important}.align-content-xl-between{align-content:space-between!important}.align-content-xl-around{align-content:space-around!important}.align-content-xl-stretch{align-content:stretch!important}.align-self-xl-auto{align-self:auto!important}.align-self-xl-start{align-self:flex-start!important}.align-self-xl-end{align-self:flex-end!important}.align-self-xl-center{align-self:center!important}.align-self-xl-baseline{align-self:baseline!important}.align-self-xl-stretch{align-self:stretch!important}.float-xl-left{float:left!important}.float-xl-right{float:right!important}.float-xl-none{float:none!important}.m-xl-0{margin:0!important}.mt-xl-0,.my-xl-0{margin-top:0!important}.mr-xl-0,.mx-xl-0{margin-right:0!important}.mb-xl-0,.my-xl-0{margin-bottom:0!important}.ml-xl-0,.mx-xl-0{margin-left:0!important}.m-xl-1{margin:.25rem!important}.mt-xl-1,.my-xl-1{margin-top:.25rem!important}.mr-xl-1,.mx-xl-1{margin-right:.25rem!important}.mb-xl-1,.my-xl-1{margin-bottom:.25rem!important}.ml-xl-1,.mx-xl-1{margin-left:.25rem!important}.m-xl-2{margin:.5rem!important}.mt-xl-2,.my-xl-2{margin-top:.5rem!important}.mr-xl-2,.mx-xl-2{margin-right:.5rem!important}.mb-xl-2,.my-xl-2{margin-bottom:.5rem!important}.ml-xl-2,.mx-xl-2{margin-left:.5rem!important}.m-xl-3{margin:1rem!important}.mt-xl-3,.my-xl-3{margin-top:1rem!important}.mr-xl-3,.mx-xl-3{margin-right:1rem!important}.mb-xl-3,.my-xl-3{margin-bottom:1rem!important}.ml-xl-3,.mx-xl-3{margin-left:1rem!important}.m-xl-4{margin:1.5rem!important}.mt-xl-4,.my-xl-4{margin-top:1.5rem!important}.mr-xl-4,.mx-xl-4{margin-right:1.5rem!important}.mb-xl-4,.my-xl-4{margin-bottom:1.5rem!important}.ml-xl-4,.mx-xl-4{margin-left:1.5rem!important}.m-xl-5{margin:3rem!important}.mt-xl-5,.my-xl-5{margin-top:3rem!important}.mr-xl-5,.mx-xl-5{margin-right:3rem!important}.mb-xl-5,.my-xl-5{margin-bottom:3rem!important}.ml-xl-5,.mx-xl-5{margin-left:3rem!important}.p-xl-0{padding:0!important}.pt-xl-0,.py-xl-0{padding-top:0!important}.pr-xl-0,.px-xl-0{padding-right:0!important}.pb-xl-0,.py-xl-0{padding-bottom:0!important}.pl-xl-0,.px-xl-0{padding-left:0!important}.p-xl-1{padding:.25rem!important}.pt-xl-1,.py-xl-1{padding-top:.25rem!important}.pr-xl-1,.px-xl-1{padding-right:.25rem!important}.pb-xl-1,.py-xl-1{padding-bottom:.25rem!important}.pl-xl-1,.px-xl-1{padding-left:.25rem!important}.p-xl-2{padding:.5rem!important}.pt-xl-2,.py-xl-2{padding-top:.5rem!important}.pr-xl-2,.px-xl-2{padding-right:.5rem!important}.pb-xl-2,.py-xl-2{padding-bottom:.5rem!important}.pl-xl-2,.px-xl-2{padding-left:.5rem!important}.p-xl-3{padding:1rem!important}.pt-xl-3,.py-xl-3{padding-top:1rem!important}.pr-xl-3,.px-xl-3{padding-right:1rem!important}.pb-xl-3,.py-xl-3{padding-bottom:1rem!important}.pl-xl-3,.px-xl-3{padding-left:1rem!important}.p-xl-4{padding:1.5rem!important}.pt-xl-4,.py-xl-4{padding-top:1.5rem!important}.pr-xl-4,.px-xl-4{padding-right:1.5rem!important}.pb-xl-4,.py-xl-4{padding-bottom:1.5rem!important}.pl-xl-4,.px-xl-4{padding-left:1.5rem!important}.p-xl-5{padding:3rem!important}.pt-xl-5,.py-xl-5{padding-top:3rem!important}.pr-xl-5,.px-xl-5{padding-right:3rem!important}.pb-xl-5,.py-xl-5{padding-bottom:3rem!important}.pl-xl-5,.px-xl-5{padding-left:3rem!important}.m-xl-auto{margin:auto!important}.mt-xl-auto,.my-xl-auto{margin-top:auto!important}.mr-xl-auto,.mx-xl-auto{margin-right:auto!important}.mb-xl-auto,.my-xl-auto{margin-bottom:auto!important}.ml-xl-auto,.mx-xl-auto{margin-left:auto!important}.text-xl-left{text-align:left!important}.text-xl-right{text-align:right!important}.text-xl-center{text-align:center!important}}@media (min-width:1690px){.d-el-none{display:none!important}.d-el-inline{display:inline!important}.d-el-inline-block{display:inline-block!important}.d-el-block{display:block!important}.d-el-table{display:table!important}.d-el-table-row{display:table-row!important}.d-el-table-cell{display:table-cell!important}.d-el-flex{display:flex!important}.d-el-inline-flex{display:inline-flex!important}.flex-el-row{flex-direction:row!important}.flex-el-column{flex-direction:column!important}.flex-el-row-reverse{flex-direction:row-reverse!important}.flex-el-column-reverse{flex-direction:column-reverse!important}.flex-el-wrap{flex-wrap:wrap!important}.flex-el-nowrap{flex-wrap:nowrap!important}.flex-el-wrap-reverse{flex-wrap:wrap-reverse!important}.flex-el-fill{flex-grow:1!important;flex-shrink:1!important;flex-basis:auto!important}.flex-el-grow-0{flex-grow:0!important}.flex-el-grow-1{flex-grow:1!important}.flex-el-shrink-0{flex-shrink:0!important}.flex-el-shrink-1{flex-shrink:1!important}.justify-content-el-start{justify-content:flex-start!important}.justify-content-el-end{justify-content:flex-end!important}.justify-content-el-center{justify-content:center!important}.justify-content-el-between{justify-content:space-between!important}.justify-content-el-around{justify-content:space-around!important}.align-items-el-start{align-items:flex-start!important}.align-items-el-end{align-items:flex-end!important}.align-items-el-center{align-items:center!important}.align-items-el-baseline{align-items:baseline!important}.align-items-el-stretch{align-items:stretch!important}.align-content-el-start{align-content:flex-start!important}.align-content-el-end{align-content:flex-end!important}.align-content-el-center{align-content:center!important}.align-content-el-between{align-content:space-between!important}.align-content-el-around{align-content:space-around!important}.align-content-el-stretch{align-content:stretch!important}.align-self-el-auto{align-self:auto!important}.align-self-el-start{align-self:flex-start!important}.align-self-el-end{align-self:flex-end!important}.align-self-el-center{align-self:center!important}.align-self-el-baseline{align-self:baseline!important}.align-self-el-stretch{align-self:stretch!important}.float-el-left{float:left!important}.float-el-right{float:right!important}.float-el-none{float:none!important}.m-el-0{margin:0!important}.mt-el-0,.my-el-0{margin-top:0!important}.mr-el-0,.mx-el-0{margin-right:0!important}.mb-el-0,.my-el-0{margin-bottom:0!important}.ml-el-0,.mx-el-0{margin-left:0!important}.m-el-1{margin:.25rem!important}.mt-el-1,.my-el-1{margin-top:.25rem!important}.mr-el-1,.mx-el-1{margin-right:.25rem!important}.mb-el-1,.my-el-1{margin-bottom:.25rem!important}.ml-el-1,.mx-el-1{margin-left:.25rem!important}.m-el-2{margin:.5rem!important}.mt-el-2,.my-el-2{margin-top:.5rem!important}.mr-el-2,.mx-el-2{margin-right:.5rem!important}.mb-el-2,.my-el-2{margin-bottom:.5rem!important}.ml-el-2,.mx-el-2{margin-left:.5rem!important}.m-el-3{margin:1rem!important}.mt-el-3,.my-el-3{margin-top:1rem!important}.mr-el-3,.mx-el-3{margin-right:1rem!important}.mb-el-3,.my-el-3{margin-bottom:1rem!important}.ml-el-3,.mx-el-3{margin-left:1rem!important}.m-el-4{margin:1.5rem!important}.mt-el-4,.my-el-4{margin-top:1.5rem!important}.mr-el-4,.mx-el-4{margin-right:1.5rem!important}.mb-el-4,.my-el-4{margin-bottom:1.5rem!important}.ml-el-4,.mx-el-4{margin-left:1.5rem!important}.m-el-5{margin:3rem!important}.mt-el-5,.my-el-5{margin-top:3rem!important}.mr-el-5,.mx-el-5{margin-right:3rem!important}.mb-el-5,.my-el-5{margin-bottom:3rem!important}.ml-el-5,.mx-el-5{margin-left:3rem!important}.p-el-0{padding:0!important}.pt-el-0,.py-el-0{padding-top:0!important}.pr-el-0,.px-el-0{padding-right:0!important}.pb-el-0,.py-el-0{padding-bottom:0!important}.pl-el-0,.px-el-0{padding-left:0!important}.p-el-1{padding:.25rem!important}.pt-el-1,.py-el-1{padding-top:.25rem!important}.pr-el-1,.px-el-1{padding-right:.25rem!important}.pb-el-1,.py-el-1{padding-bottom:.25rem!important}.pl-el-1,.px-el-1{padding-left:.25rem!important}.p-el-2{padding:.5rem!important}.pt-el-2,.py-el-2{padding-top:.5rem!important}.pr-el-2,.px-el-2{padding-right:.5rem!important}.pb-el-2,.py-el-2{padding-bottom:.5rem!important}.pl-el-2,.px-el-2{padding-left:.5rem!important}.p-el-3{padding:1rem!important}.pt-el-3,.py-el-3{padding-top:1rem!important}.pr-el-3,.px-el-3{padding-right:1rem!important}.pb-el-3,.py-el-3{padding-bottom:1rem!important}.pl-el-3,.px-el-3{padding-left:1rem!important}.p-el-4{padding:1.5rem!important}.pt-el-4,.py-el-4{padding-top:1.5rem!important}.pr-el-4,.px-el-4{padding-right:1.5rem!important}.pb-el-4,.py-el-4{padding-bottom:1.5rem!important}.pl-el-4,.px-el-4{padding-left:1.5rem!important}.p-el-5{padding:3rem!important}.pt-el-5,.py-el-5{padding-top:3rem!important}.pr-el-5,.px-el-5{padding-right:3rem!important}.pb-el-5,.py-el-5{padding-bottom:3rem!important}.pl-el-5,.px-el-5{padding-left:3rem!important}.m-el-auto{margin:auto!important}.mt-el-auto,.my-el-auto{margin-top:auto!important}.mr-el-auto,.mx-el-auto{margin-right:auto!important}.mb-el-auto,.my-el-auto{margin-bottom:auto!important}.ml-el-auto,.mx-el-auto{margin-left:auto!important}.text-el-left{text-align:left!important}.text-el-right{text-align:right!important}.text-el-center{text-align:center!important}}.f-text-lowercase{text-transform:lowercase!important}.f-text-uppercase{text-transform:uppercase!important}.f-text-capitalize{text-transform:capitalize!important}.f-font-weight-light{font-weight:300!important}.f-font-weight-normal{font-weight:400!important}.f-font-weight-bold{font-weight:700!important}.f-font-italic{font-style:italic!important}.f-text-white{color:#fff!important}.text-primary{color:#2A87FF!important}a.text-primary:focus,a.text-primary:hover{color:#006bf6!important}.text-secondary{color:#6c757d!important}a.text-secondary:focus,a.text-secondary:hover{color:#545b62!important}.text-success{color:#6CC77F!important}a.text-success:focus,a.text-success:hover{color:#47b95f!important}.text-info{color:#5EA4FF!important}a.text-info:focus,a.text-info:hover{color:#2b87ff!important}.text-warning{color:#F5A144!important}a.text-warning:focus,a.text-warning:hover{color:#f28914!important}.text-danger{color:#dc3545!important}a.text-danger:focus,a.text-danger:hover{color:#bd2130!important}.text-light{color:#f8f9fa!important}a.text-light:focus,a.text-light:hover{color:#dae0e5!important}.text-dark{color:#343a40!important}a.text-dark:focus,a.text-dark:hover{color:#1d2124!important}.f-text-body{color:#2D2F33!important}.f-text-muted{color:#A8ADB8!important}.f-text-black-50{color:rgba(0,0,0,.5)!important}.f-text-white-50{color:rgba(255,255,255,.5)!important}.f-text-hide{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0}.visible{visibility:visible!important}.invisible{visibility:hidden!important}@media print{.d-print-none{display:none!important}.d-print-inline{display:inline!important}.d-print-inline-block{display:inline-block!important}.d-print-block{display:block!important}.d-print-table{display:table!important}.d-print-table-row{display:table-row!important}.d-print-table-cell{display:table-cell!important}.d-print-flex{display:flex!important}.d-print-inline-flex{display:inline-flex!important}blockquote,img,pre,tr{page-break-inside:avoid}*,::after,::before{text-shadow:none!important;box-shadow:none!important}a:not(.btn){text-decoration:underline}abbr[title]::after{content:" (" f-attr(title) ")"}pre{white-space:pre-wrap!important}blockquote,pre{border:1px solid #adb5bd}thead{display:table-header-group}h2,h3,p{orphans:3;widows:3}h2,h3{page-break-after:avoid}.container,body{min-width:888px!important}.navbar{display:none}.badge{border:1px solid #000}.table{border-collapse:collapse!important}.table td,.table th{background-color:#fff!important}.table-bordered td,.table-bordered th{border:1px solid #dee2e6!important}.table-dark{color:inherit}.table-dark tbody+tbody,.table-dark td,.table-dark th,.table-dark thead th{border-color:#EAECF3}.table .thead-dark th{color:inherit;border-color:#EAECF3}} \ No newline at end of file diff --git a/packages/farris-theme/src/assets/themes/default/default/temp/farris-iteration-b.css b/packages/farris-theme/src/assets/themes/default/default/temp/farris-iteration-b.css new file mode 100644 index 0000000000000000000000000000000000000000..c59cd004b92e96227d0e1b441dea86c3dac4e940 --- /dev/null +++ b/packages/farris-theme/src/assets/themes/default/default/temp/farris-iteration-b.css @@ -0,0 +1,968 @@ +@charset "UTF-8"; +/** 暗黑主题新增变量——————开始*/ +/** 暗黑主题新增变量——————结束*/ +/** 暗黑主题新增变量——————开始*/ +/** 暗黑主题新增变量——————结束*/ +/** 暗黑主题新增变量——————开始*/ +/** 暗黑主题新增变量——————结束*/ +/** 暗黑主题新增变量——————开始*/ +/** 暗黑主题新增变量——————结束*/ +/******************************* + 页头(S M) +*******************************/ +/******************************* + 表单 +*******************************/ +/******************************* + 带筛选方案 +*******************************/ +/******************************* + 按钮 +*******************************/ +/******************************* + Tabs +*******************************/ +/******************************* + Tabs +*******************************/ +/******************************* + OnePage(S M) +*******************************/ +/******************************* + 左右页面(S M) +*******************************/ +/******************************* + Section(S M) +*******************************/ +/******************************* + 导航页 (S M) +*******************************/ +/******************************* + 简单查询页 +*******************************/ +/*表格分页高度*/ +/******************************* + 多选 +*******************************/ +/******************************* + 单选 +*******************************/ +/*按钮——————开始*/ +/*按钮——————结束*/ +/*输入控件按钮icon图标*/ +body { + background: #f0f3f6; } + +input::-ms-clear { + display: none; } + +h1, +.h1 { + line-height: 2.125rem; } + +h2, +.h2 { + line-height: 2; } + +h3, +.h3 { + line-height: 1.875rem; } + +h4, +.h4 { + line-height: 1.75rem; } + +h5, +.h5 { + line-height: 1.375rem; } + +h6, +.h6 { + line-height: 1.25rem; } + +.text-dark { + color: #000; } + +.text-danger { + color: #F46160 !important; } + +.text-info { + color: #529DFF !important; } + +.pagination { + font-size: 0.75rem; + padding: 0.625rem 0.625rem; } + +.page-link { + border-radius: 3px; + min-width: calc(1rem + 0.375rem + 2px); + height: calc(1rem + 0.375rem + 2px); + text-align: center; + margin-left: 0px; + overflow: hidden; + box-shadow: 0px 2px 6px 0px rgba(31, 35, 41, 0.06); } + .page-link .k-icon { + vertical-align: top; } + .page-link:focus { + color: #0E6DED; + border-color: #0E6DED; } + .page-link.disabled { + color: #878D99; + background-color: #F4F5F9; + border-color: #DEE1EA; + box-shadow: none; } + .page-link:hover { + color: #529DFF; + background-color: #fff; + border-color: #529DFF; } + .page-link:active { + color: #0E6DED; + background-color: #fff; + border-color: #0E6DED; } + +.page-item { + margin: 0rem 0.25rem; } + +.pagination-lg .page-link { + height: auto; + width: auto; } + +.table { + table-layout: fixed; } + .table thead { + background: #F4F5F9; + color: #5A5E66; } + .table thead th { + padding: 0.4375rem 0.75rem; + line-height: 1.25rem; + border-width: 0 0 1px 0; + font-weight: normal; + border-color: #E4E7EF; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + position: relative; } + .table thead th::after { + content: ''; + position: absolute; + right: 0; + top: 50%; + margin-top: calc(-1.125rem / 2); + display: block; + height: 1.125rem; + width: 1px; + background-color: #E6E9F0; } + .table thead th:last-child::after { + display: none; } + .table td { + border-top-width: 0; + border-bottom: 1px solid #EAECF3; + border-color: #EAECF3; + padding: 0.25rem 0.75rem; + height: calc( 0.5rem + 1px + 1.16074rem); + line-height: 1.25rem; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; } + .table tr.selected, + .table td.selected, + .table th.selected { + border-color: #95BEF1; + color: #424347; + background-color: #DAE9FF; } + +.form-control:disabled, .form-control:disabled:hover { + border-color: #D8DCE6; + color: #2D2F33; + background: #fff; } + +.form-control[readonly], .form-control[readonly]:hover { + border-color: #D8DCE6; + color: #2D2F33; + background: #fff; } + +.form-control:hover { + background-color: #fff; + color: #2D2F33; + border-color: #529DFF; + box-shadow: none; } + +.form-control[readonly]:focus { + box-shadow: none; } + +.custom-control { + padding-left: 0; } + .custom-control.custom-checkbox, .custom-control.custom-radio { + padding-right: 0.8125rem; + margin-bottom: 0.25rem; } + .custom-control .custom-control-label::before { + color: #AEB5C6; } + .custom-control .custom-control-label:hover { + cursor: pointer; } + .custom-control .custom-control-label:hover::before { + color: #529DFF; } + .custom-control .custom-control-input:checked ~ .custom-control-label::before { + color: #2A87FF; } + .custom-control .custom-control-input[readonly] ~ .custom-control-label { + color: #2D2F33; } + .custom-control .custom-control-input[readonly] ~ .custom-control-label::before { + color: #E6E9F0; } + .custom-control .custom-control-input[readonly] ~ .custom-control-label:hover { + cursor: default; } + .custom-control .custom-control-input:disabled ~ .custom-control-label { + color: #2D2F33; } + .custom-control .custom-control-input:disabled ~ .custom-control-label::before { + color: #E6E9F0; } + .custom-control .custom-control-input:disabled ~ .custom-control-label:hover { + cursor: default; } + .custom-control .custom-control-input[readonly]:checked ~ .custom-control-label::before, + .custom-control .custom-control-input[disabled]:checked ~ .custom-control-label::before { + color: rgba(42, 135, 255, 0.2); } + +.custom-control-input { + clip: rect(0, 0, 0, 0); + overflow: hidden; + opacity: 0; } + +.custom-control-label { + padding-left: 1.5rem; + color: #2D2F33; + display: inline; } + .custom-control-label::before { + width: 1em; + height: 1em; + -moz-osx-font-smoothing: grayscale; + -webkit-font-smoothing: antialiased; + font-size: 1rem; + font-family: "FarrisIcons"; + font-style: normal; + font-variant: normal; + font-weight: 400; + line-height: 1; + speak: none; + text-transform: none; + display: inline-block; + vertical-align: middle; + color: #AEB5C6; + font-size: 14px; + line-height: 1; + top: 2px; + left: 0; + top: 3px; + left: 0; + position: absolute; } + .custom-control-label::after { + display: none; + content: ''; } + +.custom-checkbox .custom-control-label::before { + content: '\e304'; } + +.custom-checkbox .custom-control-input:checked ~ .custom-control-label::before { + content: '\e305'; } + +.custom-checkbox .custom-control-input:indeterminate ~ .custom-control-label::before { + font-family: 'FarrisIcons'; + content: '\e306'; + color: #2A87FF; } + +.custom-radio .custom-control-label::before { + content: '\e309'; } + +.custom-radio .custom-control-input:checked ~ .custom-control-label::before { + content: '\e30a'; } + +.was-validated .farris-input-wrap .form-control:valid, .farris-input-wrap .form-control.is-valid, .was-validated +.farris-input-wrap .custom-select:valid, +.farris-input-wrap .custom-select.is-valid { + border-color: #D8DCE6; } + .was-validated .farris-input-wrap .form-control:valid:focus, .farris-input-wrap .form-control.is-valid:focus, .was-validated + .farris-input-wrap .custom-select:valid:focus, + .farris-input-wrap .custom-select.is-valid:focus { + border-color: #D8DCE6; + box-shadow: 0 0 0 0.2rem rgba(216, 220, 230, 0.25); } + +.was-validated .farris-input-wrap .form-check-input:valid ~ .form-check-label { + color: #D8DCE6; } + +.was-validated .farris-input-wrap .form-check-input:valid ~ .valid-feedback, +.was-validated .farris-input-wrap .form-check-input:valid ~ .valid-tooltip { + display: block; } + +.was-validated .farris-input-wrap .custom-control-input:valid ~ .custom-control-label { + color: #D8DCE6; } + .was-validated .farris-input-wrap .custom-control-input:valid ~ .custom-control-label::before { + background-color: white; } + +.was-validated .farris-input-wrap .custom-control-input:valid:checked ~ .custom-control-label::before { + background-color: #f7f8fa; } + +.was-validated .farris-input-wrap .custom-control-input:valid:focus ~ .custom-control-label::before { + box-shadow: 0 0 0 1px #fff, 0 0 0 0.2rem rgba(216, 220, 230, 0.25); } + +.was-validated .farris-input-wrap .custom-file-input:valid ~ .custom-file-label { + border-color: #D8DCE6; } + .was-validated .farris-input-wrap .custom-file-input:valid ~ .custom-file-label::after { + border-color: inherit; } + +.was-validated .farris-input-wrap .custom-file-input:valid:focus ~ .custom-file-label { + box-shadow: 0 0 0 0.2rem rgba(216, 220, 230, 0.25); } + +.was-validated .farris-input-wrap .form-control:invalid, .farris-input-wrap .form-control.is-invalid, .was-validated +.farris-input-wrap .custom-select:invalid, +.farris-input-wrap .custom-select.is-invalid { + border-color: #D8DCE6; } + .was-validated .farris-input-wrap .form-control:invalid:focus, .farris-input-wrap .form-control.is-invalid:focus, .was-validated + .farris-input-wrap .custom-select:invalid:focus, + .farris-input-wrap .custom-select.is-invalid:focus { + border-color: #D8DCE6; + box-shadow: 0 0 0 0.2rem rgba(216, 220, 230, 0.25); } + +.was-validated .farris-input-wrap .form-check-input:invalid ~ .form-check-label { + color: #D8DCE6; } + +.was-validated .farris-input-wrap .form-check-input:invalid ~ .invalid-feedback, +.was-validated .farris-input-wrap .form-check-input:invalid ~ .invalid-tooltip { + display: block; } + +.was-validated .farris-input-wrap .custom-control-input:invalid ~ .custom-control-label { + color: #D8DCE6; } + .was-validated .farris-input-wrap .custom-control-input:invalid ~ .custom-control-label::before { + background-color: white; } + +.was-validated .farris-input-wrap .custom-control-input:invalid:checked ~ .custom-control-label::before { + background-color: #f7f8fa; } + +.was-validated .farris-input-wrap .custom-control-input:invalid:focus ~ .custom-control-label::before { + box-shadow: 0 0 0 1px #fff, 0 0 0 0.2rem rgba(216, 220, 230, 0.25); } + +.was-validated .farris-input-wrap .custom-file-input:invalid ~ .custom-file-label { + border-color: #D8DCE6; } + .was-validated .farris-input-wrap .custom-file-input:invalid ~ .custom-file-label::after { + border-color: inherit; } + +.was-validated .farris-input-wrap .custom-file-input:invalid:focus ~ .custom-file-label { + box-shadow: 0 0 0 0.2rem rgba(216, 220, 230, 0.25); } + +.modal-header { + display: flex; + align-items: flex-start; + justify-content: space-between; + flex-shrink: 0; + padding: 0.75rem 0.5rem 0.75rem 1.125rem; + background: #fff; + color: #000; + align-items: center; + border-top-left-radius: 3px; + border-top-right-radius: 3px; + border-bottom: none; } + .modal-header .close { + color: #000; + opacity: 1; + padding: 0.1875rem 0.1875rem; + margin: -0.25rem 0; + border: 1px solid transparent; + font-size: 1rem; + width: 1.66074rem; + height: 1.66074rem; } + .modal-header .close:not(:disabled):not(.disabled):hover, .modal-header .close:not(:disabled):not(.disabled):focus { + color: #000; } + +.modal-title { + font-size: 1rem; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; } + +.modal-footer, +.showtype-modal .fe-modal-footer-base { + display: flex; + align-items: center; + justify-content: flex-end; + flex-shrink: 0; + background: #fff; + padding: 0.875rem 1.5rem; + box-shadow: none; } + .modal-footer > :not(:first-child), + .showtype-modal .fe-modal-footer-base > :not(:first-child) { + margin-left: 0.3125rem; } + .modal-footer > :not(:last-child), + .showtype-modal .fe-modal-footer-base > :not(:last-child) { + margin-right: 0.3125rem; } + +.modal-open .modal { + overflow-x: auto; } + +.form-row { + margin-right: -0.5rem; + margin-left: -0.5rem; } + .form-row > .col, + .form-row > [class*='col-'] { + padding-right: 0.5rem; + padding-left: 0.5rem; } + +.col-form-label { + padding-top: 0; + padding-bottom: 0; + margin-bottom: 0.375rem; + margin-left: 0; } + +.farris-form-inline .col-form-label, +.farris-form-controls-inline .farris-group-wrap .col-form-label { + padding-top: calc(0.1875rem + 1px); + padding-bottom: calc(0.1875rem + 1px); + margin-bottom: 0; } + +.form-control { + height: calc(1.5rem + 0.125rem); + padding: 0.1875rem 0.5rem; } + .form-control.k-textarea { + padding: .1875rem .8rem; } + +.btn { + display: inline-block; + font-weight: 400; + text-align: center; + white-space: nowrap; + vertical-align: middle; + -webkit-user-select: none; + -moz-user-select: none; + user-select: none; + border: 1px solid transparent; + padding: 0.1875rem 0.875rem; + font-size: 0.8125rem; + line-height: 1.4286; + border-radius: 3px; + transition: color 0.15s ease-in-out, background-color 0.15s ease-in-out, box-shadow 0.15s ease-in-out; } + @media screen and (prefers-reduced-motion: reduce) { + .btn { + transition: none; } } + .btn:hover, .btn:focus { + text-decoration: none; } + .btn:focus, .btn.focus { + outline: 0; + box-shadow: 0px 1px 0px 0px rgba(31, 35, 41, 0.12); } + .btn.disabled, .btn:disabled { + opacity: 1; + box-shadow: none; } + .btn:not(:disabled):not(.disabled) { + cursor: pointer; } + .btn:not(:disabled):not(.disabled):active, .btn:not(:disabled):not(.disabled).active { + box-shadow: 0px 1px 0px 0px rgba(31, 35, 41, 0.12); } + .btn:not(:disabled):not(.disabled):active:focus, .btn:not(:disabled):not(.disabled).active:focus { + box-shadow: 0px 1px 0px 0px rgba(31, 35, 41, 0.12); } + +a.btn.disabled, +fieldset:disabled a.btn { + pointer-events: none; } + +.btn-primary { + color: #fff; + background: #2A87FF; + border-color: #2A87FF; + box-shadow: 0px 1px 0px 0px rgba(31, 35, 41, 0.12); } + .btn-primary:hover { + color: #fff; + background: #529DFF; + border-color: #529DFF; + box-shadow: 0px 1px 0px 0px rgba(31, 35, 41, 0.12); } + .btn-primary:not(:disabled):not(.disabled):focus, .btn-primary:not(:disabled):not(.disabled).focus { + box-shadow: 0px 1px 0px 0px rgba(31, 35, 41, 0.12); } + .btn-primary.disabled, .btn-primary:disabled { + color: #878D99; + background: #EAECF3; + border-color: #DEE1EA; + box-shadow: none; } + .btn-primary:not(:disabled):not(.disabled):active, .btn-primary:not(:disabled):not(.disabled).active, + .show > .btn-primary.dropdown-toggle { + color: #fff; + background: #0E6DED; + border-color: #0E6DED; + box-shadow: 0px 1px 0px 0px rgba(31, 35, 41, 0.12); } + .btn-primary:not(:disabled):not(.disabled):active:focus, .btn-primary:not(:disabled):not(.disabled).active:focus, + .show > .btn-primary.dropdown-toggle:focus { + box-shadow: 0px 1px 0px 0px rgba(31, 35, 41, 0.12); } + +.btn-secondary { + color: #2D2F33; + background: #FFFFFF; + border-color: #EAECF3; + box-shadow: 0px 2px 6px 0px rgba(31, 35, 41, 0.06); } + .btn-secondary:hover { + color: #529DFF; + background: #FFFFFF; + border-color: #529DFF; + box-shadow: 0px 2px 6px 0px rgba(31, 35, 41, 0.06); } + .btn-secondary:not(:disabled):not(.disabled):focus, .btn-secondary:not(:disabled):not(.disabled).focus { + box-shadow: 0px 2px 6px 0px rgba(31, 35, 41, 0.06); } + .btn-secondary.disabled, .btn-secondary:disabled { + color: #878D99; + background: #EAECF3; + border-color: #DEE1EA; + box-shadow: none; } + .btn-secondary:not(:disabled):not(.disabled):active, .btn-secondary:not(:disabled):not(.disabled).active, + .show > .btn-secondary.dropdown-toggle { + color: #0E6DED; + background: #FFFFFF; + border-color: #0E6DED; + box-shadow: 0px 2px 6px 0px rgba(31, 35, 41, 0.06); } + .btn-secondary:not(:disabled):not(.disabled):active:focus, .btn-secondary:not(:disabled):not(.disabled).active:focus, + .show > .btn-secondary.dropdown-toggle:focus { + box-shadow: 0px 2px 6px 0px rgba(31, 35, 41, 0.06); } + +.btn-danger { + color: #F46160; + background: #fff; + border-color: #F9B0AF; + box-shadow: 0px 2px 6px 0px rgba(31, 35, 41, 0.06); } + .btn-danger:hover { + color: #F46160; + background: rgba(244, 97, 96, 0.06); + border-color: #F46160; + box-shadow: 0px 2px 6px 0px rgba(31, 35, 41, 0.06); } + .btn-danger:not(:disabled):not(.disabled):focus, .btn-danger:not(:disabled):not(.disabled).focus { + box-shadow: 0px 2px 6px 0px rgba(31, 35, 41, 0.06); } + .btn-danger.disabled, .btn-danger:disabled { + color: #878D99; + background: #EAECF3; + border-color: #DEE1EA; + box-shadow: none; } + .btn-danger:not(:disabled):not(.disabled):active, .btn-danger:not(:disabled):not(.disabled).active, + .show > .btn-danger.dropdown-toggle { + color: #F46160; + background: rgba(244, 97, 96, 0.1); + border-color: #F46160; + box-shadow: 0px 2px 6px 0px rgba(31, 35, 41, 0.06); } + .btn-danger:not(:disabled):not(.disabled):active:focus, .btn-danger:not(:disabled):not(.disabled).active:focus, + .show > .btn-danger.dropdown-toggle:focus { + box-shadow: 0px 2px 6px 0px rgba(31, 35, 41, 0.06); } + +.btn-success { + color: #fff; + background: #6CC77F; + border-color: #6CC77F; + box-shadow: 0px 1px 0px 0px rgba(31, 35, 41, 0.12); } + .btn-success:hover { + color: #fff; + background: #6CC77F; + border-color: #6CC77F; + box-shadow: 0px 1px 0px 0px rgba(31, 35, 41, 0.12); } + .btn-success:not(:disabled):not(.disabled):focus, .btn-success:not(:disabled):not(.disabled).focus { + box-shadow: 0px 1px 0px 0px rgba(31, 35, 41, 0.12); } + .btn-success.disabled, .btn-success:disabled { + color: #878D99; + background: #EAECF3; + border-color: #DEE1EA; + box-shadow: none; } + .btn-success:not(:disabled):not(.disabled):active, .btn-success:not(:disabled):not(.disabled).active, + .show > .btn-success.dropdown-toggle { + color: #fff; + background: #6CC77F; + border-color: #6CC77F; + box-shadow: 0px 1px 0px 0px rgba(31, 35, 41, 0.12); } + .btn-success:not(:disabled):not(.disabled):active:focus, .btn-success:not(:disabled):not(.disabled).active:focus, + .show > .btn-success.dropdown-toggle:focus { + box-shadow: 0px 1px 0px 0px rgba(31, 35, 41, 0.12); } + +.btn-warning { + color: #fff; + background: #F5A144; + border-color: #F5A144; + box-shadow: 0px 1px 0px 0px rgba(31, 35, 41, 0.12); } + .btn-warning:hover { + color: #fff; + background: #F5A144; + border-color: #F5A144; + box-shadow: 0px 1px 0px 0px rgba(31, 35, 41, 0.12); } + .btn-warning:not(:disabled):not(.disabled):focus, .btn-warning:not(:disabled):not(.disabled).focus { + box-shadow: 0px 1px 0px 0px rgba(31, 35, 41, 0.12); } + .btn-warning.disabled, .btn-warning:disabled { + color: #878D99; + background: #EAECF3; + border-color: #DEE1EA; + box-shadow: none; } + .btn-warning:not(:disabled):not(.disabled):active, .btn-warning:not(:disabled):not(.disabled).active, + .show > .btn-warning.dropdown-toggle { + color: #fff; + background: #F5A144; + border-color: #F5A144; + box-shadow: 0px 1px 0px 0px rgba(31, 35, 41, 0.12); } + .btn-warning:not(:disabled):not(.disabled):active:focus, .btn-warning:not(:disabled):not(.disabled).active:focus, + .show > .btn-warning.dropdown-toggle:focus { + box-shadow: 0px 1px 0px 0px rgba(31, 35, 41, 0.12); } + +.btn-dark { + color: #fff; + background: #343a40; + border-color: #343a40; + box-shadow: 0px 1px 0px 0px rgba(31, 35, 41, 0.12); } + .btn-dark:hover { + color: #fff; + background: #23272b; + border-color: #23272b; + box-shadow: 0px 1px 0px 0px rgba(31, 35, 41, 0.12); } + .btn-dark:not(:disabled):not(.disabled):focus, .btn-dark:not(:disabled):not(.disabled).focus { + box-shadow: 0px 1px 0px 0px rgba(31, 35, 41, 0.12); } + .btn-dark.disabled, .btn-dark:disabled { + color: #878D99; + background: #EAECF3; + border-color: #DEE1EA; + box-shadow: none; } + .btn-dark:not(:disabled):not(.disabled):active, .btn-dark:not(:disabled):not(.disabled).active, + .show > .btn-dark.dropdown-toggle { + color: #fff; + background: #1d2124; + border-color: #171a1d; + box-shadow: 0px 1px 0px 0px rgba(31, 35, 41, 0.12); } + .btn-dark:not(:disabled):not(.disabled):active:focus, .btn-dark:not(:disabled):not(.disabled).active:focus, + .show > .btn-dark.dropdown-toggle:focus { + box-shadow: 0px 1px 0px 0px rgba(31, 35, 41, 0.12); } + +.btn-light { + color: #212529; + background: #f8f9fa; + border-color: #f8f9fa; + box-shadow: 0px 1px 0px 0px rgba(31, 35, 41, 0.12); } + .btn-light:hover { + color: #212529; + background: #e2e6ea; + border-color: #dae0e5; + box-shadow: 0px 1px 0px 0px rgba(31, 35, 41, 0.12); } + .btn-light:not(:disabled):not(.disabled):focus, .btn-light:not(:disabled):not(.disabled).focus { + box-shadow: 0px 1px 0px 0px rgba(31, 35, 41, 0.12); } + .btn-light.disabled, .btn-light:disabled { + color: #878D99; + background: #EAECF3; + border-color: #DEE1EA; + box-shadow: none; } + .btn-light:not(:disabled):not(.disabled):active, .btn-light:not(:disabled):not(.disabled).active, + .show > .btn-light.dropdown-toggle { + color: #212529; + background: #dae0e5; + border-color: #d3d9df; + box-shadow: 0px 1px 0px 0px rgba(31, 35, 41, 0.12); } + .btn-light:not(:disabled):not(.disabled):active:focus, .btn-light:not(:disabled):not(.disabled).active:focus, + .show > .btn-light.dropdown-toggle:focus { + box-shadow: 0px 1px 0px 0px rgba(31, 35, 41, 0.12); } + +.btn-info { + color: #fff; + background: #2A87FF; + border-color: #2A87FF; + box-shadow: 0px 1px 0px 0px rgba(31, 35, 41, 0.12); } + .btn-info:hover { + color: #fff; + background: #529DFF; + border-color: #529DFF; + box-shadow: 0px 1px 0px 0px rgba(31, 35, 41, 0.12); } + .btn-info:not(:disabled):not(.disabled):focus, .btn-info:not(:disabled):not(.disabled).focus { + box-shadow: 0px 1px 0px 0px rgba(31, 35, 41, 0.12); } + .btn-info.disabled, .btn-info:disabled { + color: #878D99; + background: #EAECF3; + border-color: #DEE1EA; + box-shadow: none; } + .btn-info:not(:disabled):not(.disabled):active, .btn-info:not(:disabled):not(.disabled).active, + .show > .btn-info.dropdown-toggle { + color: #fff; + background: #0E6DED; + border-color: #0E6DED; + box-shadow: 0px 1px 0px 0px rgba(31, 35, 41, 0.12); } + .btn-info:not(:disabled):not(.disabled):active:focus, .btn-info:not(:disabled):not(.disabled).active:focus, + .show > .btn-info.dropdown-toggle:focus { + box-shadow: 0px 1px 0px 0px rgba(31, 35, 41, 0.12); } + +.btn-outline-primary { + color: #2A87FF; + background-color: transparent; + background-image: none; + border-color: #2A87FF; + box-shadow: 0px 2px 6px 0px rgba(31, 35, 41, 0.06); } + .btn-outline-primary:hover { + color: #fff; + background-color: #2A87FF; + border-color: #2A87FF; } + .btn-outline-primary:focus, .btn-outline-primary.focus { + box-shadow: 0px 2px 6px 0px rgba(31, 35, 41, 0.06); } + .btn-outline-primary:active, .btn-outline-primary.active { + box-shadow: 0px 2px 6px 0px rgba(31, 35, 41, 0.06); } + .btn-outline-primary.disabled, .btn-outline-primary:disabled { + color: #2A87FF; + background-color: transparent; } + .btn-outline-primary:not(:disabled):not(.disabled):active, .btn-outline-primary:not(:disabled):not(.disabled).active, + .show > .btn-outline-primary.dropdown-toggle { + color: #fff; + background-color: #2A87FF; + border-color: #2A87FF; } + .btn-outline-primary:not(:disabled):not(.disabled):active:focus, .btn-outline-primary:not(:disabled):not(.disabled).active:focus, + .show > .btn-outline-primary.dropdown-toggle:focus { + box-shadow: 0px 2px 6px 0px rgba(31, 35, 41, 0.06); } + +.btn-outline-secondary { + color: #6c757d; + background-color: transparent; + background-image: none; + border-color: #6c757d; + box-shadow: 0px 2px 6px 0px rgba(31, 35, 41, 0.06); } + .btn-outline-secondary:hover { + color: #fff; + background-color: #6c757d; + border-color: #6c757d; } + .btn-outline-secondary:focus, .btn-outline-secondary.focus { + box-shadow: 0px 2px 6px 0px rgba(31, 35, 41, 0.06); } + .btn-outline-secondary:active, .btn-outline-secondary.active { + box-shadow: 0px 2px 6px 0px rgba(31, 35, 41, 0.06); } + .btn-outline-secondary.disabled, .btn-outline-secondary:disabled { + color: #6c757d; + background-color: transparent; } + .btn-outline-secondary:not(:disabled):not(.disabled):active, .btn-outline-secondary:not(:disabled):not(.disabled).active, + .show > .btn-outline-secondary.dropdown-toggle { + color: #fff; + background-color: #6c757d; + border-color: #6c757d; } + .btn-outline-secondary:not(:disabled):not(.disabled):active:focus, .btn-outline-secondary:not(:disabled):not(.disabled).active:focus, + .show > .btn-outline-secondary.dropdown-toggle:focus { + box-shadow: 0px 2px 6px 0px rgba(31, 35, 41, 0.06); } + +.btn-outline-success { + color: #6CC77F; + background-color: transparent; + background-image: none; + border-color: #6CC77F; + box-shadow: 0px 2px 6px 0px rgba(31, 35, 41, 0.06); } + .btn-outline-success:hover { + color: #212529; + background-color: #6CC77F; + border-color: #6CC77F; } + .btn-outline-success:focus, .btn-outline-success.focus { + box-shadow: 0px 2px 6px 0px rgba(31, 35, 41, 0.06); } + .btn-outline-success:active, .btn-outline-success.active { + box-shadow: 0px 2px 6px 0px rgba(31, 35, 41, 0.06); } + .btn-outline-success.disabled, .btn-outline-success:disabled { + color: #6CC77F; + background-color: transparent; } + .btn-outline-success:not(:disabled):not(.disabled):active, .btn-outline-success:not(:disabled):not(.disabled).active, + .show > .btn-outline-success.dropdown-toggle { + color: #212529; + background-color: #6CC77F; + border-color: #6CC77F; } + .btn-outline-success:not(:disabled):not(.disabled):active:focus, .btn-outline-success:not(:disabled):not(.disabled).active:focus, + .show > .btn-outline-success.dropdown-toggle:focus { + box-shadow: 0px 2px 6px 0px rgba(31, 35, 41, 0.06); } + +.btn-outline-info { + color: #5EA4FF; + background-color: transparent; + background-image: none; + border-color: #5EA4FF; + box-shadow: 0px 2px 6px 0px rgba(31, 35, 41, 0.06); } + .btn-outline-info:hover { + color: #212529; + background-color: #5EA4FF; + border-color: #5EA4FF; } + .btn-outline-info:focus, .btn-outline-info.focus { + box-shadow: 0px 2px 6px 0px rgba(31, 35, 41, 0.06); } + .btn-outline-info:active, .btn-outline-info.active { + box-shadow: 0px 2px 6px 0px rgba(31, 35, 41, 0.06); } + .btn-outline-info.disabled, .btn-outline-info:disabled { + color: #5EA4FF; + background-color: transparent; } + .btn-outline-info:not(:disabled):not(.disabled):active, .btn-outline-info:not(:disabled):not(.disabled).active, + .show > .btn-outline-info.dropdown-toggle { + color: #212529; + background-color: #5EA4FF; + border-color: #5EA4FF; } + .btn-outline-info:not(:disabled):not(.disabled):active:focus, .btn-outline-info:not(:disabled):not(.disabled).active:focus, + .show > .btn-outline-info.dropdown-toggle:focus { + box-shadow: 0px 2px 6px 0px rgba(31, 35, 41, 0.06); } + +.btn-outline-warning { + color: #F5A144; + background-color: transparent; + background-image: none; + border-color: #F5A144; + box-shadow: 0px 2px 6px 0px rgba(31, 35, 41, 0.06); } + .btn-outline-warning:hover { + color: #212529; + background-color: #F5A144; + border-color: #F5A144; } + .btn-outline-warning:focus, .btn-outline-warning.focus { + box-shadow: 0px 2px 6px 0px rgba(31, 35, 41, 0.06); } + .btn-outline-warning:active, .btn-outline-warning.active { + box-shadow: 0px 2px 6px 0px rgba(31, 35, 41, 0.06); } + .btn-outline-warning.disabled, .btn-outline-warning:disabled { + color: #F5A144; + background-color: transparent; } + .btn-outline-warning:not(:disabled):not(.disabled):active, .btn-outline-warning:not(:disabled):not(.disabled).active, + .show > .btn-outline-warning.dropdown-toggle { + color: #212529; + background-color: #F5A144; + border-color: #F5A144; } + .btn-outline-warning:not(:disabled):not(.disabled):active:focus, .btn-outline-warning:not(:disabled):not(.disabled).active:focus, + .show > .btn-outline-warning.dropdown-toggle:focus { + box-shadow: 0px 2px 6px 0px rgba(31, 35, 41, 0.06); } + +.btn-outline-danger { + color: #dc3545; + background-color: transparent; + background-image: none; + border-color: #dc3545; + box-shadow: 0px 2px 6px 0px rgba(31, 35, 41, 0.06); } + .btn-outline-danger:hover { + color: #fff; + background-color: #dc3545; + border-color: #dc3545; } + .btn-outline-danger:focus, .btn-outline-danger.focus { + box-shadow: 0px 2px 6px 0px rgba(31, 35, 41, 0.06); } + .btn-outline-danger:active, .btn-outline-danger.active { + box-shadow: 0px 2px 6px 0px rgba(31, 35, 41, 0.06); } + .btn-outline-danger.disabled, .btn-outline-danger:disabled { + color: #dc3545; + background-color: transparent; } + .btn-outline-danger:not(:disabled):not(.disabled):active, .btn-outline-danger:not(:disabled):not(.disabled).active, + .show > .btn-outline-danger.dropdown-toggle { + color: #fff; + background-color: #dc3545; + border-color: #dc3545; } + .btn-outline-danger:not(:disabled):not(.disabled):active:focus, .btn-outline-danger:not(:disabled):not(.disabled).active:focus, + .show > .btn-outline-danger.dropdown-toggle:focus { + box-shadow: 0px 2px 6px 0px rgba(31, 35, 41, 0.06); } + +.btn-outline-light { + color: #f8f9fa; + background-color: transparent; + background-image: none; + border-color: #f8f9fa; + box-shadow: 0px 2px 6px 0px rgba(31, 35, 41, 0.06); } + .btn-outline-light:hover { + color: #212529; + background-color: #f8f9fa; + border-color: #f8f9fa; } + .btn-outline-light:focus, .btn-outline-light.focus { + box-shadow: 0px 2px 6px 0px rgba(31, 35, 41, 0.06); } + .btn-outline-light:active, .btn-outline-light.active { + box-shadow: 0px 2px 6px 0px rgba(31, 35, 41, 0.06); } + .btn-outline-light.disabled, .btn-outline-light:disabled { + color: #f8f9fa; + background-color: transparent; } + .btn-outline-light:not(:disabled):not(.disabled):active, .btn-outline-light:not(:disabled):not(.disabled).active, + .show > .btn-outline-light.dropdown-toggle { + color: #212529; + background-color: #f8f9fa; + border-color: #f8f9fa; } + .btn-outline-light:not(:disabled):not(.disabled):active:focus, .btn-outline-light:not(:disabled):not(.disabled).active:focus, + .show > .btn-outline-light.dropdown-toggle:focus { + box-shadow: 0px 2px 6px 0px rgba(31, 35, 41, 0.06); } + +.btn-outline-dark { + color: #343a40; + background-color: transparent; + background-image: none; + border-color: #343a40; + box-shadow: 0px 2px 6px 0px rgba(31, 35, 41, 0.06); } + .btn-outline-dark:hover { + color: #fff; + background-color: #343a40; + border-color: #343a40; } + .btn-outline-dark:focus, .btn-outline-dark.focus { + box-shadow: 0px 2px 6px 0px rgba(31, 35, 41, 0.06); } + .btn-outline-dark:active, .btn-outline-dark.active { + box-shadow: 0px 2px 6px 0px rgba(31, 35, 41, 0.06); } + .btn-outline-dark.disabled, .btn-outline-dark:disabled { + color: #343a40; + background-color: transparent; } + .btn-outline-dark:not(:disabled):not(.disabled):active, .btn-outline-dark:not(:disabled):not(.disabled).active, + .show > .btn-outline-dark.dropdown-toggle { + color: #fff; + background-color: #343a40; + border-color: #343a40; } + .btn-outline-dark:not(:disabled):not(.disabled):active:focus, .btn-outline-dark:not(:disabled):not(.disabled).active:focus, + .show > .btn-outline-dark.dropdown-toggle:focus { + box-shadow: 0px 2px 6px 0px rgba(31, 35, 41, 0.06); } + +.btn-link { + font-weight: 400; + color: #2A87FF; + background-color: transparent; + padding: 0; + border: 0; + line-height: 1.25rem; } + .btn-link:hover { + color: #529DFF; + text-decoration: none; + background-color: transparent; + border-color: transparent; } + .btn-link:focus, .btn-link.focus { + text-decoration: none; + border-color: transparent; + box-shadow: none; + color: #0E6DED; + box-shadow: none; } + .btn-link:active, .btn-link.active { + box-shadow: none !important; + color: #0E6DED; } + .btn-link:disabled, .btn-link.disabled { + color: #878D99; + pointer-events: none; } + .btn-link + .btn-link { + margin-right: 0.875rem; } + +.btn-lg { + padding: 0.25rem 1.125rem; + font-size: 0.875rem; + line-height: 1.4286; + border-radius: 3px; } + +.btn-sm { + padding: 0.125rem 0.5rem; + font-size: 0.75rem; + line-height: 1.4286; + border-radius: 3px; } + +.btn-block { + display: block; + width: 100%; } + .btn-block + .btn-block { + margin-top: 0.5rem; } + +input[type='submit'].btn-block, +input[type='reset'].btn-block, +input[type='button'].btn-block { + width: 100%; } + +.btn-warning { + color: #fff; } + +.btn-outline-primary.disabled, .btn-outline-primary:disabled, +.btn-outline-secondary.disabled, +.btn-outline-secondary:disabled, +.btn-outline-success.disabled, +.btn-outline-success:disabled, +.btn-outline-danger.disabled, +.btn-outline-danger:disabled, +.btn-outline-warning.disabled, +.btn-outline-warning:disabled, +.btn-outline-info.disabled, +.btn-outline-info:disabled, +.btn-outline-light.disabled, +.btn-outline-light:disabled, +.btn-outline-dark.disabled, +.btn-outline-dark:disabled, +.btn-outline-link.disabled, +.btn-outline-link:disabled { + color: #878D99; + border-color: #DEE1EA; + background: transparent; } + +.dropdown-divider { + margin: 0.25rem 0; } + +.btn-group .btn + .dropdown-toggle-split { + margin-left: -1px; } + +.btn-group .btn-primary + .dropdown-toggle-split { + margin-left: -1px; + border-left-color: #E6E9F0; } + +.dropdown-item { + padding: 0.25rem 0.5rem; } diff --git a/packages/mobile-ui-vue/.eslintrc b/packages/mobile-ui-vue/.eslintrc new file mode 100644 index 0000000000000000000000000000000000000000..66f0bf50a046fb7e326419bd7d56e1e15e721f95 --- /dev/null +++ b/packages/mobile-ui-vue/.eslintrc @@ -0,0 +1,9 @@ +{ + "root": true, + "extends": ["@farris"], + "rules": { + "semi": "off", + "prefer-object-spread": "off", + "@typescript-eslint/indent": ["error", 2] + } +} \ No newline at end of file diff --git a/packages/mobile-ui-vue/.gitignore b/packages/mobile-ui-vue/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..a547bf36d8d11a4f89c59c144f24795749086dd1 --- /dev/null +++ b/packages/mobile-ui-vue/.gitignore @@ -0,0 +1,24 @@ +# 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? diff --git a/packages/mobile-ui-vue/.prettierrc b/packages/mobile-ui-vue/.prettierrc new file mode 100644 index 0000000000000000000000000000000000000000..e34771e9cce290242513733c570d6b874594fd20 --- /dev/null +++ b/packages/mobile-ui-vue/.prettierrc @@ -0,0 +1,13 @@ +{ + "bracketSpacing": true, + "jsxBracketSameLine": true, + "jsxSingleQuote": false, + "printWidth": 140, + "semi": true, + "useTabs": false, + "trailingComma": "none", + "singleQuote": true, + "tabWidth": 2, + "endOfLine": "auto", + "proseWrap": "preserve" +} diff --git a/packages/mobile-ui-vue/.vscode/extensions.json b/packages/mobile-ui-vue/.vscode/extensions.json new file mode 100644 index 0000000000000000000000000000000000000000..c0a6e5a48110e472b09d68afa2a030af6ab3208b --- /dev/null +++ b/packages/mobile-ui-vue/.vscode/extensions.json @@ -0,0 +1,3 @@ +{ + "recommendations": ["Vue.volar", "Vue.vscode-typescript-vue-plugin"] +} diff --git a/packages/mobile-ui-vue/README.md b/packages/mobile-ui-vue/README.md new file mode 100644 index 0000000000000000000000000000000000000000..ef72fd524245587c08546207b8a2166ebcca3361 --- /dev/null +++ b/packages/mobile-ui-vue/README.md @@ -0,0 +1,18 @@ +# Vue 3 + TypeScript + Vite + +This template should help get you started developing with Vue 3 and TypeScript in Vite. The template uses Vue 3 ` diff --git a/packages/mobile-ui-vue/components/adv-uploader/index.ts b/packages/mobile-ui-vue/components/adv-uploader/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..92a76ae2e91d107921751b935d8b993d4ca8ccd8 --- /dev/null +++ b/packages/mobile-ui-vue/components/adv-uploader/index.ts @@ -0,0 +1,17 @@ +import type { App } from 'vue'; +import AdvUploader from './src/adv-uploader.component'; +import { FilePicker } from './src/components/file-picker'; +import { defaultFilePickerInjectKey, defaultUploadFileContextMenuInjectKey } from './src/composition/types'; + +export { + AdvUploader, + FilePicker, + defaultFilePickerInjectKey, + defaultUploadFileContextMenuInjectKey, +}; + +export default { + install(app: App): void { + app.component(AdvUploader.name, AdvUploader); + } +}; diff --git a/packages/mobile-ui-vue/components/adv-uploader/src/adv-uploader.component.tsx b/packages/mobile-ui-vue/components/adv-uploader/src/adv-uploader.component.tsx new file mode 100644 index 0000000000000000000000000000000000000000..d33713811205c2e2b07a360d7d3615cbe2448beb --- /dev/null +++ b/packages/mobile-ui-vue/components/adv-uploader/src/adv-uploader.component.tsx @@ -0,0 +1,284 @@ +/** + * Copyright (c) 2020 - present, Inspur Genersoft Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * defination + */ +import { defineComponent, ComputedRef, computed, withModifiers, withDirectives, getCurrentInstance, ref } from 'vue'; +import { advUploaderProps, AdvUploaderProps } from './adv-uploader.props'; +import useUploader from './composition/use-uploader'; +import usePopupHandler from './composition/use-popup-handler'; +import useContextMenu from './composition/use-context-menu'; +import { FileItemCtx } from './composition/types'; +import config from '../../config'; +import { UploadFileItem } from './common/types'; +import { useLocale, vOnLongPress } from '../../hook'; +import { formatFileSize } from './common/upload'; +import { toRefsWithOverrideValue } from './common/to-refs'; + +export default defineComponent({ + name: 'FmAdvUploader', + + props: advUploaderProps, + + emit: [ + 'update:files', + 'validate', + 'progress', + 'oneFileSuccess', + 'oneFileFail', + 'uploadFinish', + 'delete', + 'popupOpen', + 'popupClose', + 'longPress', + 'fileItemClick', + ], + + setup(originalProps: AdvUploaderProps, context) { + const { prefix } = config; + const t = useLocale(`advUploader`); + const name = `${prefix}-adv-uploader`; + const { attrs, slots, expose, emit } = context; + + const overrideValue = ref<{ [key: string]: any }>({}); + const setPropValue = (key: string, val: any) => { + overrideValue.value = { ...overrideValue.value, [key]: val }; + }; + const props = toRefsWithOverrideValue(originalProps, overrideValue); + + const { popupHandler } = usePopupHandler(props, context); + + const { + displayFiles, + toUploadFiles, + uploading, + uploaderContext, + triggerUpload, + uploadFiles, + handleInnerDelete, + } = useUploader(props, context, popupHandler); + + const { + renderContextMenuList, + openContextMenuList, + executeContextMenuItem: innerExecContextMenuItem, + handleLongPress, + } = useContextMenu(props, context, popupHandler); + + const isImageCardList: ComputedRef = computed(() => { + return props.listType.value === 'image-card'; + }); + + const getFileItemCtx = (file: UploadFileItem, index: number): FileItemCtx => { + return { file, index, fileList: displayFiles.value, ctx: uploaderContext }; + }; + + const executeContextMenuItem = (file: UploadFileItem, ...keys: string[]): boolean => { + const index = displayFiles.value.findIndex((f) => { + if (file.id) { + return file.id === f.id; + } + return file.name === f.name; + }); + const ctx = getFileItemCtx(file, index); + return innerExecContextMenuItem(ctx, ...keys); + }; + + const handleDeleteClick = (item: UploadFileItem, index: number, e?: MouseEvent) => { + handleInnerDelete(getFileItemCtx(item, index), e); + }; + + const doDefaultPreview = (item: UploadFileItem, index: number) => { + if (!props.preventDefaultPreview.value) { + console.log(`[@todo] Default file preview:`, item, index); + } + }; + + const handleFileItemClick = (item: UploadFileItem, index: number, e: MouseEvent) => { + doDefaultPreview(item, index); + props.onFileItemClick?.value?.({ ctx: getFileItemCtx(item, index), e }); + emit("fileItemClick", { ctx: getFileItemCtx(item, index), e }); + }; + + const handleMoreBtnClick = (item: UploadFileItem, index: number, e: MouseEvent) => { + e.stopPropagation(); + openContextMenuList(getFileItemCtx(item, index)); + }; + + const renderImage = (item: UploadFileItem, _index: number) => { + return ( + + ); + }; + + const renderFileName = (item: UploadFileItem, _index: number) => { + return ( +
{item.name}
+ ); + }; + + const renderImageCardItem = (item: UploadFileItem, index: number) => { + const imageCard = ( +
+ {item.thumbnailUrl ? renderImage(item, index) : renderFileName(item, index)} + {(item.status === "waiting" || item.status === "progress" || item.status === "fail") && ( +
+ {item.status === "waiting" && ( +
{t('waiting')}
+ )} + {item.status === "progress" && ( + <> + +
+ {item.percent ? `${item.percent}%` : t('uploading')} +
+ + )} + {item.status === "fail" && ( + <> + +
{t('failed')}
+ + )} +
+ )} +
+ ); + return ( +
handleFileItemClick(item, index, e), + }}> + {withDirectives(imageCard, [[ + vOnLongPress, + (evt: TouchEvent) => handleLongPress(getFileItemCtx(item, index), evt), + '', + { interceptClick: true, preventDefaultContextMenu: props.longPressAction.value !== 'none' }, + ]])} + {!props.readonly.value && ( +
!props.disabled.value && handleDeleteClick(item, index, e), ["stop"]) + }>
+ )} +
+ ); + }; + + const renderDetailItem = (item: UploadFileItem, index: number) => { + const detailItem = ( +
+
+ +
+
+
+ {item.name || t('unnamedFile')} +
+
+ {item.status === "waiting" ? ( + {t('waiting')} + ) : item.status === "progress" ? ( + + {t('uploading') + (item.percent ? ` - ${item.percent}%` : "")} + + ) : item.status === "fail" ? ( + {t('failed')} + ) : ( + <> + {item.size && {formatFileSize(item.size)}} + {item.uploadTime && {item.uploadTime || ""}} + + )} +
+
+
+ ); + return ( +
handleFileItemClick(item, index, e), + }}> + {withDirectives(detailItem, [[ + vOnLongPress, + (evt: TouchEvent) => handleLongPress(getFileItemCtx(item, index), evt), + '', + { interceptClick: true, preventDefaultContextMenu: props.longPressAction.value !== 'none' }, + ]])} +
handleMoreBtnClick(item, index, e)}> + +
+
+ ); + }; + + const renderAddBtn = () => { + if (props.readonly.value || props.maxCount.value > 0 && props.maxCount.value <= displayFiles.value.length) { + return; + } + const defaultAddBtn = ( +
+ {slots.addBtnContent ? slots.addBtnContent() : ( +
+ )} +
+ ); + return ( +
+ {slots.addBtn ? slots.addBtn() : (slots.default ? slots.default : defaultAddBtn)} +
+ ); + }; + + expose({ + displayFiles, + toUploadFiles, + uploading, + uploaderContext, + triggerUpload, + uploadFiles, + executeContextMenuItem, + + setPropValue, + instance: getCurrentInstance(), + }); + + return () => { + return ( + <> +
+
+ {props.addBtnPosition.value === "start" && renderAddBtn()} + {displayFiles.value.map((item, index) => + isImageCardList.value ? renderImageCardItem(item, index) : renderDetailItem(item, index) + )} + {props.addBtnPosition.value !== "start" && renderAddBtn()} +
+
+ {renderContextMenuList({ + onDelete: (ctx) => handleDeleteClick(ctx.file, ctx.index), + onPreview: (ctx) => doDefaultPreview(ctx.file, ctx.index), + })} + + ); + }; + } + +}); diff --git a/packages/mobile-ui-vue/components/adv-uploader/src/adv-uploader.props.ts b/packages/mobile-ui-vue/components/adv-uploader/src/adv-uploader.props.ts new file mode 100644 index 0000000000000000000000000000000000000000..2adff9885557cfb45e6982954ac558051021a98b --- /dev/null +++ b/packages/mobile-ui-vue/components/adv-uploader/src/adv-uploader.props.ts @@ -0,0 +1,320 @@ +/** + * Copyright (c) 2020 - present, Inspur Genersoft Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { ExtractPropTypes, PropType } from 'vue'; +import { + UploadFileItem, FileValidationProblem, HttpMethod, UploadResponseData, CustomUploadFileContext, + FileReadType, UploadResult, UploadResponseContext, UploadProgressContext, +} from './common/types'; +import { + FilePickerItem, ListType, UploaderContext, FileContextMenuItem, FileItemCtx, UploaderPopupType, +} from './composition/types'; + +export const advUploaderProps = { + + /** + * 已上传文件列表 + * @description 支持语法糖`v-model:files` + */ + files: { type: Array as PropType, default: () => [] }, + + /** + * 是否只读 + * @description 只读状态下将隐藏上传按钮和删除按钮 + */ + readonly: { type: Boolean, default: false }, + + /** + * 是否禁用 + * @description 禁用状态下将禁用上传按钮和删除按钮,优先级低于`readonly`属性 + */ + disabled: { type: Boolean, default: false }, + + /** + * 文件列表的内建样式 + * @description 支持两种基础样式:`details`(文件详情列表)、`image-card`(图片列表) + */ + listType: { type: String as PropType, default: "details" }, + + /** + * 上传按钮的位置 + * @description 默认在图片列表的右侧或文件详情列表的下方 + */ + addBtnPosition: { type: String as PropType<"start" | "end">, default: "end" }, + + /** + * 图片属性 + * @description 透传给缩略图的图片相关属性 + */ + imageProps: { type: Object as PropType>, default: {} }, + + /** + * 文件读取的结果类型 + * @description 指定用户所选文件是以`File`对象的形式返回,还是以base64格式的字符串的形式返回 + */ + fileReadType: { type: String as PropType, default: "file" }, + + /** + * 自定义的文件获取方式列表 + * @description 如果为空,则用户点击上传按钮后通过h5选择文件,如果非空,则通过列表中定义的方式获取文件 + */ + filePickerItems: { type: Array as PropType, default: undefined }, + + /** + * 自定义的上下文菜单 + * @description + * 1. 当`listType='details'`时,长按文件条目或者点击`更多`按钮,弹出上下文菜单; + * 2. 传入`longPressAction`属性,可以使得长按文件条目时弹出上下文菜单。 + */ + contextMenuItems: { type: Array as PropType, default: undefined }, + + /** + * 阻止默认的预览行为 + * @description 默认情况下,如果点击了图片类型的文件条目,则进行预览,其它类型的文件没有默认的预览。 + * 可以将本属性置为`true`,然后通过`fileItemClick`事件或回调方法实现自定义的文件预览。 + */ + preventDefaultPreview: { type: Boolean, default: false }, + + /** + * 获取文件的预览图片地址 + * @description 用户选择文件后,被选择的文件将被加入到文件列表中,此时文件的预览图地址可以根据本回调方法指定 + */ + getThumbnailUrl: { type: Function as PropType<(file: UploadFileItem) => string | Promise>, default: undefined }, + + /** + * 是否将原图作为缩略图 + * @description 如果文件是图片类型,则直接将之作为缩略图显示出来,不再调用`getThumbnailUrl`方法 + */ + useOriginalImageAsThumbnail: { type: Boolean, default: true }, + + /** + * 接受上传的文件类型 + * @description 仅影响默认的文件获取方式,自定义的文件获取方式可以读取该属性,但是不一定受约束 + */ + accept: { type: String, default: undefined }, + + /** + * 是否启用文件多选 + * @description 仅影响默认的文件获取方式,自定义的文件获取方式可以读取该属性,但是不一定受约束 + */ + multiple: { type: Boolean, default: true }, + + /** + * 文件数量上限 + * @description 值小于等于0则不限制 + */ + maxCount: { type: Number, default: -1 }, + + /** + * 单个文件的大小上限 + * @description 值小于等于0则不限制,单位:字节 + */ + maxSize: { type: Number, default: -1 }, + + /** + * 是否允许上传同名文件 + * @description 如果值为`false`,则过滤掉被选择的重名文件 + */ + allowDuplicateFile: { type: Boolean, default: true }, + + /** + * 单文件上传前回调 + * @description 如果返回`false`则将文件过滤掉 + */ + beforeUpload: { + type: Function as PropType<(file: UploadFileItem, ctx: UploaderContext) => boolean | Promise>, + default: undefined, + }, + + /** + * 处理校验问题的回调方法 + * @description 通常用来向用户提示错误信息 + */ + onValidate: { type: Function as PropType<(problems: FileValidationProblem[]) => void>, default: undefined }, + + /** + * 是否在选择文件后自动上传 + * @description 默认自动上传,如果手动上传,则文件被选中后处于等待状态,调用组件的上传方法后上传 + */ + autoUpload: { type: Boolean, default: true }, + + /** + * 上传请求的地址 + * @description `action`非空且`customUploadMethod`为空时,启用内置的文件上传方式 + */ + action: { type: String, default: "" }, + + /** + * HTTP的请求方法 + * @description 随`action`生效,可选值:POST/GET/PUT/OPTION/PATCH/post/get/put/option/patch + */ + method: { + type: String as PropType, + default: "POST", + validator(val: string): boolean { + if (!val) return true; + return ['POST', 'GET', 'PUT', 'OPTION', 'PATCH', 'post', 'get', 'put', 'option', 'patch'].includes(val); + }, + }, + + /** + * 文件在上传请求数据中的字段名 + * @description 随`action`生效,指定文件在请求数据中的字段名。 + * 如果`fileReadType`的值为`file`(默认)则文件作为`File`对象上传,如果`fileReadType`的值为`dataUrl`则文件作为base64格式的字符串上传。 + * 如果`singleRequestUpload=true`且用户选择了多个文件,所有文件将使用相同的字段名。 + * 如果默认的规则不能满足业务需求,请使用`formatRequestData`属性来自定义请求数据,或者通过`customUploadMethod`属性自定义上传方法。 + */ + name: { type: String, default: "file" }, + + /** + * 上传请求所需的额外字段 + * @description 随`action`生效,用于添加文件字段之外的其它字段。 + * 如果默认的规则不能满足业务需求,请使用`formatRequestData`属性来自定义请求数据。 + */ + data: { type: Object as PropType<{ [key: string]: any }>, default: undefined }, + + /** + * 自定义HTTP请求头 + * @description 随`action`生效 + */ + headers: { type: Object as PropType<{ [key: string]: string }>, default: undefined }, + + /** + * 是否携带cookie + * @description 随`action`生效,默认不携带 + */ + withCredentials: { type: Boolean, default: false }, + + /** + * 上传请求的超时时间 + * @description 随`action`生效,单位:毫秒,默认不设置 + */ + timeout: { type: Number, default: undefined }, + + /** + * 自定义上传请求的参数 + * @description 随`action`生效,用于自定义上传请求参数,本方法非空时,`name`和`data`字段均失效 + */ + formatRequestData: { + type: Function as PropType<(files: UploadFileItem[], data: { [key: string]: any }) => { [key: string]: any }>, + default: undefined, + }, + + /** + * 格式化上传请求的响应数据 + * @description 随`action`生效,用于将上传请求返回的数据格式化为规定的结构。 + * 如果请求失败或者`error`字段非空,则认为文件上传失败。 + * 如果请求成功并且`error`字段为空,则认为文件上传成功。 + * 如果未设置本回调方法,则根据请求是否成功以及请求的原始响应数据中的`error`字段是否为空判断文件是否上传成功。 + * 如果`singleRequestUpload=true`单次请求上传多个文件,则所有上传的文件只能一起成功或者一起失败。 + * 如果既要单次请求上传多个文件,又要单独记录每个文件的上传成功和失败状态,请通过自定义上传方法`customUploadMethod`实现。 + */ + formatResponseData: { + type: Function as PropType<(response: any, uploadFiles: UploadFileItem[]) => UploadResponseData>, + default: undefined, + }, + + /** + * 自定义上传方法 + * @description 如果非空,则使用本方法进行自定义上传,`action`等内置上传的相关字段均失效。 + * 本属性受`singleRequestUpload`字段影响:如果`singleRequestUpload=true`则用户选择多个文件时只会调用一次`customUploadMethod`,否则将调用多次。 + */ + customUploadMethod: { + type: Function as PropType<(uploadCtx: CustomUploadFileContext | CustomUploadFileContext[]) => void>, + default: undefined, + }, + + /** + * 单次请求上传所有文件 + * @description 如果有多个文件需要上传,若启用该属性则通过一个请求上传所有文件,否则每个文件发一次请求 + */ + singleRequestUpload: { type: Boolean, default: false }, + + /** + * 是否模拟上传进度 + */ + useMockProgress: { type: Boolean, default: true }, + + /** + * 单文件上传成功回调方法 + * @description 每个文件上传成功后都会调用该方法(`singleRequestUpload=true`时无效) + */ + onOneFileSuccess: { type: Function as PropType<(ctx: UploadResponseContext) => void>, default: undefined }, + + /** + * 单文件上传失败回调方法 + * @description 每个文件上传失败后都会调用该方法(`singleRequestUpload=true`时无效) + */ + onOneFileFail: { type: Function as PropType<(ctx: UploadResponseContext) => void>, default: undefined }, + + /** + * 上传进度变化回调方法 + * @description 当文件的上传进度发生变化时回调该方法 + */ + onProgress: { type: Function as PropType<(ctx: UploadProgressContext) => void>, default: undefined }, + + /** + * 上传完成后回调方法 + * @description 将用户单次选择的文件全部上传结束后回调 + */ + onUploadFinish: { type: Function as PropType<(res: UploadResult) => void>, default: undefined }, + + /** + * 文件条目点击事件回调方法 + * @description 当文件条目被点击时回调该方法,注意:点击文件条目上的删除按钮、菜单按钮不会回调该方法 + */ + onFileItemClick: { type: Function as PropType<(p: { ctx: FileItemCtx; e: MouseEvent }) => void>, default: undefined }, + + /** + * 文件条目长按事件回调方法 + * @description 允许定制文件条目被长按后的具体行为。 + * 1. `none`(不进行处理):可能会弹出浏览器默认的上下文菜单; + * 2. `preventDefault`(阻止默认行为):阻止浏览器默认的上下文菜单; + * 3. `showMenu`(显示自定义的上下文菜单):通过下方弹出的动作列表显示自定义的上下文菜单; + * 4. `showMenuInTooltip`(显示自定义的上下文菜单):通过`Tooltip`组件显示自定义的上下文菜单。 + */ + longPressAction: { type: String as PropType<"none" | "preventDefault" | "showMenu" | "showMenuInTooltip">, default: "none" }, + + /** + * 文件条目长按事件回调方法 + */ + onLongPress: { type: Function as PropType<(p: { ctx: FileItemCtx; e: TouchEvent }) => void>, default: undefined }, + + /** + * 删除回调方法 + * @description 当用户点击文件条目上的删除按钮时回调该方法 + */ + onDelete: { type: Function as PropType<(p: { ctx: FileItemCtx; e?: MouseEvent }) => void>, default: undefined }, + + /** + * 打开弹层时回调方法 + * @description 调用`close`方法可以主动关闭对应的弹层,且不会触发关闭弹层事件或回调。 + * 结合`onPopupOpen`和`onPopupClose`,可以实现对弹层的原生返回处理。 + */ + onPopupOpen: { + type: Function as PropType<(p: { close: () => void; type: UploaderPopupType; uid: string }) => void>, + default: undefined, + }, + + /** + * 关闭弹层时回调方法 + */ + onPopupClose: { + type: Function as PropType<(p: { type: UploaderPopupType; uid: string }) => void>, + default: undefined, + }, +}; + +export type AdvUploaderProps = ExtractPropTypes; diff --git a/packages/mobile-ui-vue/components/adv-uploader/src/common/to-refs.ts b/packages/mobile-ui-vue/components/adv-uploader/src/common/to-refs.ts new file mode 100644 index 0000000000000000000000000000000000000000..2f6bce0a2faa5f3e6004992acd989d1c5647546c --- /dev/null +++ b/packages/mobile-ui-vue/components/adv-uploader/src/common/to-refs.ts @@ -0,0 +1,27 @@ +import { ComputedRef, computed, Ref, toRefs } from 'vue'; + +type IfAny = 0 extends 1 & T ? Y : N; + +type ToComputedRef = IfAny, [T] extends [ComputedRef] ? T : ComputedRef>; + +export type ToComputedRefs = { + [K in keyof T]: ToComputedRef +}; + +export function toRefsWithOverrideValue(object: T, overrideValue: Ref<{ [key: string]: any }>): ToComputedRefs { + if (typeof overrideValue.value !== "object") { + throw new Error("The value of overrideValue should be an object."); + } + const refs = toRefs(object); + const ret: any = Array.isArray(object) ? new Array(object.length) : {}; + Object.keys(refs).forEach((key) => { + ret[key] = computed(() => { + if (overrideValue.value[key] !== undefined) { + return overrideValue.value[key]; + } + const ogRef = (refs as any)[key]; + return typeof ogRef === "object" ? ogRef.value : ogRef; + }); + }); + return ret; +} diff --git a/packages/mobile-ui-vue/components/adv-uploader/src/common/types.ts b/packages/mobile-ui-vue/components/adv-uploader/src/common/types.ts new file mode 100644 index 0000000000000000000000000000000000000000..fd0a8f2ca32044b7c9a5cf4391fd24d9016498ca --- /dev/null +++ b/packages/mobile-ui-vue/components/adv-uploader/src/common/types.ts @@ -0,0 +1,320 @@ +/** + * 文件读取的结果类型 + * @description 值为`file`时返回文件的`File`对象,值为`dataUrl`时返回文件对应的base64编码 + */ +export type FileReadType = "file" | "dataUrl"; + +export type HttpMethod = 'POST' | 'GET' | 'PUT' | 'OPTION' | 'PATCH' | 'post' | 'get' | 'put' | 'option' | 'patch'; + +/** + * 文件条目 + */ +export interface FileItem { + + /** + * 文件名称 + */ + name?: string; + + /** + * 原始文件对象 + */ + rawFile?: File; + + /** + * base64格式的文件内容 + */ + dataUrl?: string; + + /** 原始文件的MIME类型 */ + type?: string; + + /** + * 文件的大小 + * @description 单位:字节 + */ + size?: number; + + /** 上次修改时间 */ + lastModified?: number; +} + +/** + * 上传文件条目 + */ +export interface UploadFileItem extends FileItem { + + /** + * 文件名称 + * @description 将根据文件的后缀名判断文件类型,影响预览等功能 + */ + name?: string; + + /** 文件的预览图片的地址 */ + thumbnailUrl?: string; + + /** 文件的下载地址 */ + url?: string; + + /** 文件的上传时间 */ + uploadTime?: string; + + /** + * 文件的大小 + * @description 单位:字节 + */ + size?: number; + + /** + * 文件上传状态 + * @description 上传成功、上传失败、上传中、等待上传 + */ + status?: 'success' | 'fail' | 'progress' | 'waiting'; + + /** + * 文件上传进度 + * @description [0, 100] + */ + percent?: number; + + /** + * 文件ID + * @description 用于在文件名称重复时唯一标识一个文件,允许为空 + */ + id?: string; + + /** 用户自定义的上下文数据 */ + [key: string]: any; +} + +/** 文件上传前校验参数 */ +export interface BeforeUploadValidationParam { + /** 待上传的(需要校验的)文件列表 */ + files: FileItem[]; + /** 已上传的文件列表 */ + uploadedFiles?: UploadFileItem[]; + /** 文件数量上限 */ + maxCount?: number; + /** 单个文件的大小上限 */ + maxSize?: number; + /** 是否允许重名文件 */ + allowDuplicateFile?: boolean; + /** 单个文件上传前回调 */ + beforeUpload?: (file: UploadFileItem, context: any) => boolean | Promise; + /** 上下文 */ + context?: any; +} + +/** 校验发现问题的类型 */ +export type FileValidationProblemType = + | 'SINGLE_FILE_OVER_SIZE_LIMIT' + | 'FILE_LIST_OVER_LENGTH_LIMIT' + | 'DUPLICATE_FILE_NAMES' + | 'BEFORE_UPLOAD_CALLBACK'; + +/** 校验发现的问题 */ +export interface FileValidationProblem { + + /** 问题类型 */ + type: FileValidationProblemType; + + /** + * 相关的文件列表 + * @description + * 1. 当`type="SINGLE_FILE_OVER_SIZE_LIMIT"`时,是本次所选文件中所有超过单文件大小上限的文件 + * 2. 当`type="FILE_LIST_OVER_LENGTH_LIMIT"`时,是本次所选的所有文件 + * 3. 当`type="DUPLICATE_FILE_NAMES"`时,是本次所选的文件中所有重名的文件 + * 4. 当`type="BEFORE_UPLOAD_CALLBACK"`时,是本次所选的文件中所有未通过`beforeUpload`自定义校验的文件 + */ + files: UploadFileItem[]; + + /** + * 校验参数 + * @description 包含本次校验的上下文参数,禁止修改 + */ + validationParam: BeforeUploadValidationParam; +} + +/** 文件上传前校验结果 */ +export interface BeforeUploadValidationResult { + + /** 通过校验的文件列表 */ + validFiles: UploadFileItem[]; + + /** 检测到的问题列表 */ + problems?: FileValidationProblem[]; +} + +export interface UploadProgressContext { + + /** 上传进度类型 */ + type: 'real' | 'mock'; + + /** + * 相关文件 + * @description 如果单请求上传多个文件,则长度大于一 + */ + files: UploadFileItem[]; + + /** 进度值 */ + percent: number; + + [key: string]: any; +} + +/** + * 上传请求响应数据 + * @description 后端上传接口响应的数据 + */ +export interface UploadResponseData { + + /** + * 错误信息 + * @description 如果本字段非空,则认为文件上传失败了 + */ + error?: string; + + /** + * 上传后的文件访问地址 + * @description 将被赋值给对应文件的`url`字段(单请求上传多个文件`singleRequestUpload=true`时无效) + */ + url?: string; + + /** + * 上传后的文件缩略图地址 + * @description 将被赋值给对应文件的`thumbnailUrl`字段(单请求上传多个文件`singleRequestUpload=true`时无效) + */ + thumbnailUrl?: string; + + [key: string]: any; +} + +/** + * 单个文件上传结果的上下文 + */ +export interface UploadResponseContext { + + /** + * 上传的文件 + */ + file: UploadFileItem; + + /** + * 是否上传成功 + */ + success: boolean; + + /** + * 上传请求的响应数据 + * @description 如果是单请求上传多个文件的模式(`singleRequestUpload=true`时),则该字段为空 + */ + responseData?: UploadResponseData; +} + +/** + * 自定义文件上传上下文 + * @description 当用户自定义文件上传方法时,可以通过本上下文中的回调方法通知文件的上传状态 + */ +export interface CustomUploadFileContext { + + /** 待上传的文件 */ + file: UploadFileItem; + + /** + * 更新上传进度回调 + * @description 用于更新当前文件的上传进度 + */ + onProgress: (e: { percent: number } & Record) => void; + + /** + * 上传成功回调 + * @description 文件上传成功后回调,允许将请求响应数据作为参数 + */ + onSuccess: (e?: UploadResponseData) => void; + + /** + * 上传失败回调 + * @description 文件上传失败后回调,允许将请求响应数据作为参数 + */ + onFail: (e?: UploadResponseData) => void; +} + +export interface UploadRequestContext { + /** 待上传的文件 */ + toUploadFiles: UploadFileItem[]; + /** 文件格式 */ + fileReadType?: FileReadType; + /** 上传请求所需的额外字段 */ + data?: { [key: string]: any }; + /** 单次请求上传所有文件 */ + singleRequestUpload?: boolean; + /** 上传请求的地址 */ + action?: string; + /** 文件在上传请求数据中的字段名 */ + name?: string; + /** 是否模拟上传进度 */ + useMockProgress?: boolean; + /** 自定义HTTP请求头 */ + headers?: { [key: string]: string }; + /** 是否携带cookie */ + withCredentials?: boolean; + /** HTTP的请求方法 */ + method?: HttpMethod; + /** 自定义上传请求的参数 */ + formatRequestData?: (files: UploadFileItem[], data: { [key: string]: any }) => { [key: string]: any }; + /** 格式化上传请求的响应数据 */ + formatResponseData?: (response: any, uploadFiles: UploadFileItem[]) => UploadResponseData; + /** 自定义上传方法 */ + customUploadMethod?: (uploadCtx: CustomUploadFileContext | CustomUploadFileContext[]) => void; + /** 单文件上传成功回调方法 */ + onOneFileSuccess?: (ctx: UploadResponseContext) => void; + /** 单文件上传失败回调方法 */ + onOneFileFail?: (ctx: UploadResponseContext) => void; + /** 上传进度变化回调方法 */ + onProgress?: (ctx?: UploadProgressContext) => void; +} + +export interface UploadResult { + + /** + * 单请求多文件上传的响应数据 + * @description 上传请求的响应数据,仅当单请求上传多个文件`singleRequestUpload=true`时非空 + */ + responseData?: UploadResponseData; + + /** + * 上传成功的文件及其响应数据 + * @description 如果没有文件上传成功,则为空 + */ + successItems?: UploadResponseContext[]; + + /** + * 上传失败的文件及其响应数据 + * @description 如果没有文件上传失败,则为空 + */ + failedItems?: UploadResponseContext[]; +} + +export interface XhrResponseContext { + event?: ProgressEvent; + files?: UploadFileItem[]; + XMLHttpRequest?: XMLHttpRequest; + response?: any; +} + +export interface XhrOptions { + action: string; + method?: string; + fileReadType?: FileReadType; + withCredentials?: boolean; + headers?: { [key: string]: string }; + data?: { [key: string]: any }; + name?: string; + files?: UploadFileItem[]; + useMockProgress?: boolean; + mockProgressDuration?: number; + formatRequestData?: (files: UploadFileItem[], data: { [key: string]: any }) => { [key: string]: any }; + onError: (context: XhrResponseContext) => void; + onSuccess: (context: XhrResponseContext) => void; + onProgress?: (context: UploadProgressContext) => void; +} diff --git a/packages/mobile-ui-vue/components/adv-uploader/src/common/upload.ts b/packages/mobile-ui-vue/components/adv-uploader/src/common/upload.ts new file mode 100644 index 0000000000000000000000000000000000000000..62b56d453ac7b877944be2639ba404eb8d4a1bc0 --- /dev/null +++ b/packages/mobile-ui-vue/components/adv-uploader/src/common/upload.ts @@ -0,0 +1,265 @@ +import { + FileItem, UploadFileItem, BeforeUploadValidationParam, BeforeUploadValidationResult, FileReadType, + UploadRequestContext, UploadResult, CustomUploadFileContext, XhrResponseContext, +} from './types'; +import xhr from './xhr'; + +export function initUploadFileItems(fileItems: FileItem[]): UploadFileItem[] { + fileItems.forEach((item: UploadFileItem) => { + item.status = "waiting"; + item.percent = 0; + }); + return fileItems; +} + +/** + * 校验待上传的文件 + * @param params 上传前校验上下文 + * @returns 上传前校验结果 + */ +export function validateFiles(params: BeforeUploadValidationParam): Promise { + const files = initUploadFileItems(params.files); + // @todo 对待上传的文件列表进行校验 + return Promise.resolve({ + validFiles: files + }); +} + +function file2DataUrl(fileItem: UploadFileItem): Promise { + return new Promise((resolve) => { + const reader = new FileReader(); + reader.onload = (event) => { + fileItem.dataUrl = (event.target as FileReader).result as string; + resolve(fileItem); + }; + reader.onerror = () => { + resolve(fileItem); + }; + const file = fileItem.rawFile as File; + reader.readAsDataURL(file); + }); +} + +function dataUrl2File(fileItem: UploadFileItem): Promise { + const base64 = fileItem.dataUrl as string; + const strArr = base64.split(','); + const bstr = atob(strArr[1]); + const u8arr = new Uint8Array(bstr.length); + let n = bstr.length; + while (n--) { + u8arr[n] = bstr.charCodeAt(n); + } + fileItem.rawFile = new File([u8arr], fileItem.name || "", { type: fileItem.type || undefined }); + return Promise.resolve(fileItem); +} + +export function readFile(fileItem: UploadFileItem, type: FileReadType): Promise { + if (type === "dataUrl" && fileItem && fileItem.rawFile && !fileItem.dataUrl) { + return file2DataUrl(fileItem); + } + if (type === "file" && fileItem && fileItem.dataUrl && !fileItem.rawFile) { + return dataUrl2File(fileItem); + } + return Promise.resolve(fileItem); +} + +function getFileTypeFromDataUrl(dataUrl: string): string | null { + if (!dataUrl || !dataUrl.startsWith("data:")) { + return null; + } + const parts = dataUrl.split(";"); + if (parts.length < 2) { + return null; + } + const mimeType = parts[0].substring(5); + return mimeType || null; +} + +/** + * 获取文件的MIME类型 + * @param fileItem 文件条目 + * @returns 文件的MIME类型 + */ +export function getFileType(fileItem: UploadFileItem): string | null { + return fileItem?.type || fileItem?.rawFile?.type || getFileTypeFromDataUrl(fileItem?.dataUrl || ""); +} + +/** 判断文件是否为图片 */ +export function isImage(fileItem: UploadFileItem): boolean { + const mimeType = getFileType(fileItem); + return !!mimeType && mimeType.includes("image"); +} + +function handleXhrResponseContext(xhrResponseContext: XhrResponseContext, error: boolean, uploadCtx: UploadRequestContext): UploadResult { + const files = xhrResponseContext.files || []; + let responseData = xhrResponseContext.response; + if (uploadCtx.formatResponseData) { + responseData = uploadCtx.formatResponseData(responseData, files); + } + if (responseData.error) { + error = true; + } + const res: UploadResult = {}; + if (files.length > 1 || uploadCtx.singleRequestUpload) { + res.responseData = responseData; + } + if (error) { + files.forEach(file => { file.status = "fail"; }); + res.failedItems = []; + } else { + files.forEach(file => { file.status = "success"; file.percent = 100; }); + res.successItems = []; + } + const tgtItemArr = error ? res.failedItems : res.successItems; + files.forEach(file => { + tgtItemArr?.push({ file, success: !error, responseData: files.length > 1 ? undefined : responseData }); + }); + if (files.length === 1 && !uploadCtx.singleRequestUpload) { + if (error) { + uploadCtx.onOneFileFail && uploadCtx.onOneFileFail({ file: files[0], success: false, responseData }); + } else { + uploadCtx.onOneFileSuccess && uploadCtx.onOneFileSuccess({ file: files[0], success: true, responseData }); + } + } + return res; +} + +/** + * 单次请求上传所有文件 + * @param ctx 文件上传上下文 + * @returns 上传结果 + */ +export function uploadAllAtOnce(ctx: UploadRequestContext): Promise { + const { toUploadFiles, action, customUploadMethod, singleRequestUpload } = ctx; + return new Promise((resolve) => { + if (!action && !customUploadMethod) { + console.error(`[FmAdvUploader] Upload failed, 'action' and 'customUploadMethod' cannot both be empty.`); + resolve({}); + return; + } + if (!toUploadFiles || !toUploadFiles.length) { + resolve({}); + return; + } + toUploadFiles.forEach((file) => { + file.status = 'progress'; + file.percent = 0; + }); + ctx.onProgress?.(); + if (customUploadMethod) { + const uploadResult: UploadResult = {}; + const uploadCtxArr: CustomUploadFileContext[] = []; + const uploadPromiseArr: Promise[] = []; + toUploadFiles.forEach((file) => { + let resolveFunc: (value: void | PromiseLike) => void; + const uploadPromise = new Promise((_resolve) => { + resolveFunc = _resolve; + }); + const uploadCtx: CustomUploadFileContext = { + file, + onSuccess: (responseData) => { + uploadResult.successItems = uploadResult.successItems || []; + uploadResult.successItems.push({ file, success: true, responseData }); + file.status = "success"; + file.percent = 100; + file.thumbnailUrl = responseData?.thumbnailUrl || file.thumbnailUrl; + file.url = responseData?.url || file.url; + ctx.onOneFileSuccess?.({ file, success: true, responseData }); + resolveFunc(); + }, + onFail: (responseData) => { + uploadResult.failedItems = uploadResult.failedItems || []; + uploadResult.failedItems.push({ file, success: false, responseData }); + file.status = "fail"; + ctx.onOneFileFail?.({ file, success: false, responseData }); + resolveFunc(); + }, + onProgress: (e) => { + if (!e.percent || typeof e.percent !== "number") { + return; + } + file.percent = e.percent; + ctx.onProgress?.({ ...e, type: 'real', files: [file] }); + }, + }; + uploadCtxArr.push(uploadCtx); + uploadPromiseArr.push(uploadPromise); + }); + customUploadMethod(singleRequestUpload ? uploadCtxArr : uploadCtxArr[0]); + Promise.all(uploadPromiseArr).then(() => { + resolve(uploadResult); + }).catch(() => { + resolve({}); + }); + } else { + xhr({ + action: action || "", + method: ctx.method, + fileReadType: ctx.fileReadType, + withCredentials: ctx.withCredentials, + headers: ctx.headers, + data: ctx.data, + files: ctx.toUploadFiles, + name: ctx.name, + useMockProgress: ctx.useMockProgress, + formatRequestData: ctx.formatRequestData, + onSuccess: (p) => { + const res = handleXhrResponseContext(p, false, ctx); + resolve(res); + }, + onError: (p) => { + const res = handleXhrResponseContext(p, true, ctx); + resolve(res); + }, + onProgress: ctx.onProgress, + }); + } + }); +} + +/** + * 上传多个文件 + * @description 根据`singleRequestUpload`参数决定分多次请求上传每个文件还是一次请求上传所有文件 + * @param ctx 文件上传上下文 + * @returns 上传结果 + */ +export function upload(ctx: UploadRequestContext): Promise { + const { singleRequestUpload, toUploadFiles } = ctx; + return new Promise((resolve) => { + if (singleRequestUpload) { + uploadAllAtOnce(ctx).then((res) => { + resolve(res); + }); + } else { + const pList = toUploadFiles.map((file) => ( + uploadAllAtOnce({ ...ctx, toUploadFiles: [file] }) + )); + Promise.all(pList).then(resArr => { + const result: UploadResult = {}; + resArr.forEach(r => { + if (r.failedItems && r.failedItems.length) { + result.failedItems = result.failedItems || []; + result.failedItems.push(...r.failedItems); + } + if (r.successItems && r.successItems.length) { + result.successItems = result.successItems || []; + result.successItems.push(...r.successItems); + } + }); + resolve(result); + }); + } + }); +} + +export const formatFileSize = (size: number): string => { + if (typeof size !== "number") { + return ""; + } + if (size < 1024 ** 2) { + return (size / 1024).toFixed(2) + "KB"; + } if (size >= 1024 ** 2 && size < 1024 ** 3) { + return (size / 1024 ** 2).toFixed(2) + "MB"; + } + return (size / 1024 ** 3).toFixed(2) + "GB"; +}; diff --git a/packages/mobile-ui-vue/components/adv-uploader/src/common/xhr.ts b/packages/mobile-ui-vue/components/adv-uploader/src/common/xhr.ts new file mode 100644 index 0000000000000000000000000000000000000000..5ded6cd5dad718460655e7215588b9b32e9ec8ab --- /dev/null +++ b/packages/mobile-ui-vue/components/adv-uploader/src/common/xhr.ts @@ -0,0 +1,149 @@ +import { UploadFileItem, XhrOptions } from './types'; + +export function xhr({ + action, + method = 'POST', + fileReadType = 'file', + withCredentials = false, + headers = {}, + data = {}, + files = [], + name = 'file', + useMockProgress = true, + mockProgressDuration = 300, + formatRequestData, + onSuccess, + onError, + onProgress, +}: XhrOptions) { + // support files + const innerFiles: UploadFileItem[] = files || []; + let percent = 0; + + // eslint-disable-next-line no-shadow + const xhr = new XMLHttpRequest(); + if (withCredentials) { + xhr.withCredentials = true; + } + + let timer1: NodeJS.Timeout; + let timer2: NodeJS.Timeout; + if (useMockProgress && files[0]?.status === 'progress') { + // 超过 500 毫秒再开启虚拟进度 + const timer2 = setTimeout(() => { + // 只有真实进度一直不存在时才需要模拟进度 + timer1 = setInterval(() => { + if (percent + 10 < 100) { + percent = Math.max(percent + 10, percent); + if (files[0] && percent !== files[0].percent) { + files[0].percent = percent; + onProgress && onProgress({ + percent, + files: innerFiles.map((file) => ({ ...file, percent })), + type: 'mock', + XMLHttpRequest: xhr, + }); + } + } else { + clearInterval(timer1); + } + }, mockProgressDuration) as NodeJS.Timeout; + clearTimeout(timer2); + }, mockProgressDuration); + } + + // set send data + const formData = new FormData(); + if (formatRequestData) { + const requestData = formatRequestData(innerFiles, { ...data }) || { ...data }; + Object.keys(requestData).forEach((key) => { + formData.append(key, requestData[key]); + }); + } else { + Object.keys(data).forEach((key) => { + formData.append(key, data[key]); + }); + innerFiles.forEach(file => { + formData.append(name, (fileReadType === "dataUrl" ? file.dataUrl : file.rawFile) || ""); + }); + } + + xhr.open(method, action, true); + // custom request headers + Object.keys(headers).forEach((key) => { + xhr.setRequestHeader(key, headers[key]); + }); + + xhr.onerror = (event: ProgressEvent) => { + onError({ event, files: innerFiles, XMLHttpRequest: xhr }); + clearInterval(timer1); + clearTimeout(timer2); + }; + + xhr.ontimeout = (event) => { + onError({ event, files: innerFiles, XMLHttpRequest: xhr }); + }; + + if (xhr.upload) { + xhr.upload.onprogress = (event: ProgressEvent) => { + let realPercent = 0; + if (event.total > 0) { + realPercent = Math.round((event.loaded / event.total) * 100); + } + percent = Math.max(realPercent, percent); + if (percent !== realPercent && innerFiles[0]?.percent !== percent) { + const progressFiles = innerFiles.map((item) => ({ ...item, percent })); + onProgress && onProgress({ + event, + percent, + files: progressFiles, + type: 'real', + XMLHttpRequest: xhr, + }); + } + }; + } + + // eslint-disable-next-line consistent-return + xhr.onload = (event: ProgressEvent) => { + let response: { [key: string]: any } = {}; + response.XMLHttpRequest = xhr; + const isFail = xhr.status < 200 || xhr.status >= 300; + if (isFail) { + return onError({ + event, + files: innerFiles, + response, + XMLHttpRequest: xhr, + }); + } + const text = xhr.responseText || xhr.response; + try { + response = JSON.parse(text); + } catch (e) { + response = text; + console.error(`Upload response is not a valid json`); + } + clearInterval(timer1); + clearTimeout(timer2); + innerFiles.forEach((file) => { + file.percent = 100; + file.status = 'success'; + file.uploadTime = response?.uploadTime; + }); + if (typeof response === 'object') { + response.XMLHttpRequest = xhr; + } + onSuccess({ + event, + files: [...innerFiles], + XMLHttpRequest: xhr, + response, + }); + }; + + xhr.send(formData); + return xhr; +} + +export default xhr; diff --git a/packages/mobile-ui-vue/components/adv-uploader/src/components/action-sheet.component.tsx b/packages/mobile-ui-vue/components/adv-uploader/src/components/action-sheet.component.tsx new file mode 100644 index 0000000000000000000000000000000000000000..bf7debf9d1b3e732a0f3ac5755966a0cefdda9b7 --- /dev/null +++ b/packages/mobile-ui-vue/components/adv-uploader/src/components/action-sheet.component.tsx @@ -0,0 +1,87 @@ +import { PropType, defineComponent, withModifiers } from 'vue'; +import { ActionSheetItem } from '../composition/types'; +import config from '../../../config'; +import { ActionSheet } from '../../../action-sheet'; + +export default defineComponent({ + name: 'FmAdvUploaderActionSheet', + + components: { + [ActionSheet.name]: ActionSheet, + }, + + props: { + show: { type: Boolean, default: false }, + + actions: { type: Array as PropType, default: () => [] }, + + cancelText: { type: String }, + + zIndex: [Number, String], + + teleport: null, + }, + + emits: { + 'update:show': function (_value: boolean) { + return true; + }, + + select(_item: ActionSheetItem) { + return true; + } + }, + + setup(props, { emit }) { + const { prefix } = config; + const name = `${prefix}-adv-uploader-actionsheet`; + + const onUpdateShow = (show: boolean) => { + emit("update:show", show); + }; + + const handleItemClick = (item: ActionSheetItem) => { + if (!item.__disabled__) { + emit('select', item); + } + }; + + const handleCancelBtnClick = () => { + onUpdateShow(false); + }; + + return () => ( + + +
+ {props.actions.filter((item) => + item.__visible__ !== false && item.__name__ + ).map((item, index) => ( +
handleItemClick(item), ['stop'])} + class={[ + `${name}__item`, + item.__disabled__ ? `${name}__item--disabled` : null, + item.__tip__ ? `${name}__item--has-tip` : null + ]}> +
{item.__name__}
+ {item.__tip__ &&
{item.__tip__}
} +
+ ))} + + {props.cancelText && ( +
+ +
+ {props.cancelText} +
+
+ )} +
+ +
+ ); + } +}); diff --git a/packages/mobile-ui-vue/components/adv-uploader/src/components/context-menu-list.component.tsx b/packages/mobile-ui-vue/components/adv-uploader/src/components/context-menu-list.component.tsx new file mode 100644 index 0000000000000000000000000000000000000000..91d4ab7d57f8ee9650d4c4605ffc6d49db8a7810 --- /dev/null +++ b/packages/mobile-ui-vue/components/adv-uploader/src/components/context-menu-list.component.tsx @@ -0,0 +1,76 @@ +import { defineComponent, PropType } from 'vue'; +import { useLocale } from '../../../hook'; +import { FileContextMenuItem, FileItemCtx } from '../composition/types'; +import FmAdvUploaderActionSheet from './action-sheet.component'; + +export default defineComponent({ + name: 'FmFileContextMenuList', + + props: { + show: { type: Boolean, default: false }, + + contextMenuItems: { type: Array as PropType }, + + fileItemCtx: { type: Object as PropType }, + + teleport: { type: null, default: "body" }, + + zIndex: { type: Number, default: 110 }, + }, + + emits: { + cancel() { + return true; + }, + + 'update:show': function (_value: boolean) { + return true; + }, + + delete(_ctx: FileItemCtx) { + return true; + }, + + preview(_ctx: FileItemCtx) { + return true; + }, + }, + + setup(props, { emit }) { + const t = useLocale('adv-uploader'); + + const onUpdateShow = (show: boolean) => { + emit("update:show", show); + }; + + const handleSelect = (menuItem: FileContextMenuItem) => { + onUpdateShow(false); + if (!props.fileItemCtx) { + return; + } + if (menuItem.handler) { + const uploaderCtx = props.fileItemCtx.ctx || {}; + uploaderCtx.options = menuItem.options || {}; + menuItem.handler({ ...props.fileItemCtx, ctx: uploaderCtx }); + } + if (menuItem.key === "delete") { + emit("delete", props.fileItemCtx); + } + if (menuItem.key === "preview") { + emit("preview", props.fileItemCtx); + } + }; + + return () => ( + handleSelect(item as FileContextMenuItem) + }}> + + ); + } + +}); diff --git a/packages/mobile-ui-vue/components/adv-uploader/src/components/file-picker-list.component.tsx b/packages/mobile-ui-vue/components/adv-uploader/src/components/file-picker-list.component.tsx new file mode 100644 index 0000000000000000000000000000000000000000..4eade91d4634a8d60c43626f2448ead7b8b2ccba --- /dev/null +++ b/packages/mobile-ui-vue/components/adv-uploader/src/components/file-picker-list.component.tsx @@ -0,0 +1,77 @@ +import { defineComponent, PropType } from 'vue'; +import { isPromise } from '../../../utils'; +import { useLocale } from '../../../hook'; +import { FileItem } from '../common/types'; +import { FilePickerItem, UploaderContext } from '../composition/types'; +import FmAdvUploaderActionSheet from './action-sheet.component'; + +export default defineComponent({ + name: 'FmFilePickerList', + + props: { + show: { type: Boolean, default: false }, + + filePickerItems: { type: Array as PropType }, + + ctx: { type: Object as PropType, default: () => { } }, + + teleport: { type: null, default: "body" }, + + zIndex: { type: Number, default: 110 }, + }, + + emits: { + cancel() { + return true; + }, + + 'update:show': function (_value: boolean) { + return true; + }, + + chooseFile(_files: FileItem[] | null) { + return true; + }, + + needChooseLocalFile() { + return true; + }, + }, + + setup(props, { emit }) { + const t = useLocale('adv-uploader'); + + const onUpdateShow = (show: boolean) => { + emit("update:show", show); + }; + + const handleSelect = (item: FilePickerItem) => { + onUpdateShow(false); + if (!item || !item.handler) { + emit("needChooseLocalFile"); + return; + } + const result = item.handler({ ...props.ctx, options: item.options || {} }); + if (!isPromise(result)) { + return; + } + result.then((files) => { + emit('chooseFile', files || null); + }).catch(() => { + emit('chooseFile', null); + }); + }; + + return () => ( + handleSelect(item as FilePickerItem), + }}> + + ); + } + +}); diff --git a/packages/mobile-ui-vue/components/adv-uploader/src/components/file-picker.tsx b/packages/mobile-ui-vue/components/adv-uploader/src/components/file-picker.tsx new file mode 100644 index 0000000000000000000000000000000000000000..80f0b154ee53c8ee518314367089adbe1f0fa08d --- /dev/null +++ b/packages/mobile-ui-vue/components/adv-uploader/src/components/file-picker.tsx @@ -0,0 +1,222 @@ +import { ComponentPublicInstance, reactive, defineComponent, ref } from 'vue'; +import { isFunction } from '../../../utils'; +import { mountComponent, useCurrentLang } from '../../../hook'; +import { FileItem } from '../common/types'; +import { FilePickerItem, FilePickerOption, UploaderContext } from '../composition/types'; +import FmFilePickerList from './file-picker-list.component'; + +export class FilePicker { + + /** 文件选取后回调 */ + public onChooseFile: ((files: FileItem[]) => void) | undefined; + + /** 显示文件选取列表后回调 */ + public onOpen: ((close: () => void, uid: string) => void) | undefined; + + /** 关闭文件选取列表后回调 */ + public onClose: ((uid: string) => void) | undefined; + + private pickerListState: { + show: boolean; + filePickerItems: FilePickerItem[]; + ctx: FilePickerOption; + teleport: HTMLElement; + zIndex: number; + }; + + private fileInputState: { + accept: string; + multiple: boolean; + }; + + private filePickerInstance: ComponentPublicInstance | undefined; + + private chooseLocalFile: (() => void) | undefined; + + private popupUID: string; + + constructor() { + this.popupUID = ""; + this.pickerListState = reactive({ + show: false, + filePickerItems: [], + ctx: {}, + teleport: document.body, + zIndex: 110, + }); + this.fileInputState = reactive({ + accept: "*", + multiple: true, + }); + } + + private close(): void { + this.pickerListState.show = false; + } + + private toggle(show: boolean): void { + if (!!this.pickerListState.show === !!show) { + return; + } + this.pickerListState.show = !!show; + if (show) { + this.popupUID = (new Date()).getTime().toString(); + this.onOpen?.(() => this.close(), this.popupUID); + } else { + this.onClose?.(this.popupUID); + } + } + + private handleFileChoosed(files: FileItem[] | null): void { + if (!files) { + files = []; + } + this.onChooseFile?.(files); + } + + /** + * 设置文件获取方式列表 + * @param items 文件获取方式列表 + */ + public setFilePickerItems(items: FilePickerItem[]): void { + if (!items || !Array.isArray(items)) { + return; + } + this.pickerListState.filePickerItems = [...items]; + if (items.length === 0) { + this.toggle(false); + } + } + + /** + * 触发本地文件选取 + * @description 通过h5方式选取本地文件 + */ + public triggerChooseLocalFile(): void { + this.chooseLocalFile?.(); + } + + /** + * 选取文件 + * @description + * 1. 如果文件获取方式列表非空,则调用本方法后将弹出文件获取方式列表,用户可以从列表中选择一种文件获取方式 + * 2. 如果文件获取方式列表为空,则调用本方法后,将通过h5方式获取文件(由于浏览器安全限制,需要在用户操作的上下文调用本方法,否则无效) + * 3. 用户通过任意一种方式选取文件后,回调方法`onChooseFile`将被调用 + * @param options 文件获取相关参数 + * @param zIndex 文件获取方式列表的`z-index`,默认为`110` + * @param teleportDest 弹出的文件获取方式列表将被挂到哪个元素上,默认为`document.body` + */ + public pickFile(options?: FilePickerOption, zIndex?: number, teleportDest?: HTMLElement): void { + if (options) { + this.pickerListState.ctx = options; + options.accept && (this.fileInputState.accept = options.accept); + (typeof options.multiple === "boolean") && (this.fileInputState.multiple = options.multiple); + } + (typeof zIndex === 'number') && (this.pickerListState.zIndex = zIndex); + teleportDest && (this.pickerListState.teleport = teleportDest); + + if (!this.filePickerInstance) { + const self = this; + const mountResult = mountComponent(defineComponent({ + setup() { + const inputRef = ref(); + + const resetInput = () => { + if (inputRef.value) { + inputRef.value.value = ''; + } + }; + + const toResolve = (files: File[]) => { + const results: FileItem[] = []; + files.forEach((file) => { + results.push({ + name: file.name, + rawFile: file, + type: file.type, + size: file.size, + lastModified: file.lastModified, + }); + }); + self.handleFileChoosed(results); + }; + + const onChange = (event: Event) => { + const { files } = event.target as HTMLInputElement; + if (!files || !files.length) { + return; + } + const fileArr = Array.from(files); + toResolve(fileArr); + resetInput(); + }; + + const handleInputClick = (evt: MouseEvent) => { + evt?.stopPropagation?.(); + }; + + const chooseLocalFile = () => { + if (inputRef.value) { + inputRef.value.click(); + } + }; + + self.chooseLocalFile = chooseLocalFile; + + return () => ( + <> + + + + + ); + } + })); + this.filePickerInstance = mountResult.instance; + } + this.updateActionSheetProps(); + if (this.pickerListState.filePickerItems.length > 0) { + this.toggle(true); + } else { + this.triggerChooseLocalFile(); + } + } + + private updateActionSheetProps(): void { + const items = this.pickerListState.filePickerItems || []; + const lang = useCurrentLang(); + const ctx: UploaderContext = { ...this.pickerListState.ctx }; + ctx.lang = lang.value; + items.forEach((item) => { + ctx.options = item.options || {}; + let name = item.nameI18n?.[lang.value] || item.name; + if (isFunction(name)) { + name = name(ctx); + } + let visible = typeof item.visible === "boolean" ? item.visible : true; + if (isFunction(item.visible)) { + visible = item.visible(ctx); + } + const tip = isFunction(item.tip) ? item.tip(ctx) : item.tip || ""; + + item.__key__ = item.key; + item.__name__ = name; + item.__visible__ = visible; + item.__disabled__ = false; + item.__tip__ = tip; + }); + } + +} diff --git a/packages/mobile-ui-vue/components/adv-uploader/src/composition/types.ts b/packages/mobile-ui-vue/components/adv-uploader/src/composition/types.ts new file mode 100644 index 0000000000000000000000000000000000000000..a04069b4d3196db3eab3ea6d1db6d4f8b11d1bfe --- /dev/null +++ b/packages/mobile-ui-vue/components/adv-uploader/src/composition/types.ts @@ -0,0 +1,304 @@ +import { InjectionKey } from 'vue'; +import { FileItem, UploadFileItem, FileReadType } from '../common/types'; + +/** + * 内建的列表样式 + * @description `文件详情列表`或者`图片列表` + */ +export type ListType = "details" | "image-card"; + +/** + * 文件获取相关参数 + */ +export interface FilePickerOption { + + /** + * 接受上传的文件类型 + * @description 默认不限制 + */ + accept?: string; + + /** + * 是否启用文件多选 + * @description 是否允许用户一次选择多个文件 + */ + multiple?: boolean; + + /** + * 文件读取的结果类型 + * @description 用户选择的文件将被转化为本字段所指定的格式 + */ + fileReadType?: FileReadType; + + /** + * 单个文件的大小限制 + * @description 单位:字节 + */ + maxSize?: number; + + /** + * 最大文件数量 + * @description 最多可以上传多少个文件 + */ + maxCount?: number; + + /** + * 已上传文件的数量 + * @description 已经上传了多少个文件,用`maxCount - uploadedFileCount`可以得到还能上传的最大文件数量 + */ + uploadedFileCount?: number; + + [key: string]: any; +} + +/** + * 上下文参数 + * @description 组件的相关属性,只读,禁止修改 + */ +export interface UploaderContext extends FilePickerOption { + + /** + * 当前环境的语言代码 + * @description 如果需要支持国际化,请根据语言代码使用对应的国际化资源 + */ + lang?: string; + + /** + * 文件列表的内建样式 + * @description 值来源:组件的`listType`属性 + */ + listType?: ListType; + + /** + * 组件是否处于只读状态 + * @description 值来源:组件的`readonly`属性 + */ + readonly?: boolean; + + /** + * 组件是否处于禁用状态 + * @description 值来源:组件的`disabled`属性 + */ + disabled?: boolean; + + /** + * 接受上传的文件类型 + * @description 值来源:组件的`accept`属性 + */ + accept?: string; + + /** + * 是否启用文件多选 + * @description 值来源:组件的`multiple`属性 + */ + multiple?: boolean; + + /** + * 文件读取的结果类型 + * @description 值来源:组件的`fileReadType`属性 + */ + fileReadType?: FileReadType; + + /** + * 单个文件的大小限制 + * @description 单位:字节,值来源:组件的`maxSize`属性 + */ + maxSize?: number; + + /** + * 最大文件数量 + * @description 值来源:组件的`maxCount`属性 + */ + maxCount?: number; + + /** + * 已上传文件的数量 + * @description 值来源:组件的`files`的长度,即`files.length` + */ + uploadedFileCount?: number; + + /** + * 显示的文件列表 + * @description 值来源:组件正在显示的文件列表 + */ + displayFiles?: UploadFileItem[]; + + /** + * 触发本地文件选择 + * @description 触发h5本地文件选择,只能在用户操作上下文调用 + */ + chooseLocalFile?: () => void; + + /** + * 自定义选项 + */ + options?: Record; +} + +/** 动作列表条目 */ +export interface ActionSheetItem { + __key__?: string; + __name__?: string; + __visible__?: boolean; + __disabled__?: boolean; + __tip__?: string; + [key: string]: any; +} + +/** + * 自定义文件获取方式 + */ +export interface FilePickerItem extends ActionSheetItem { + + /** + * 方式编号 + * @description 唯一标识,不可重复 + */ + key: string; + + /** + * 显示的名称 + */ + name?: string | ((ctx: UploaderContext) => string); + + /** + * 显示的名称(国际化) + * @description 优先级高于字符串类型的`name`字段,低于回调方法类型的`name`字段 + */ + nameI18n?: { [lang: string]: string }; + + /** + * 文件获取的实现方法 + * @description 当用户选择本方式后,将调用本方法来获取文件。 + * 如果`handler`字段为空,且不存在默认配置,则用户选择此方式后将通过h5方式选取文件。 + * 当存在默认配置时,`handler`方法返回`值为空的Promise`和返回`undefined`是有区别的: + * 1. 当返回`值为空的Promise`时,认为用户选取了0个文件 + * 2. 当返回`undefined`时,认为当前`handler`方法希望通过默认的配置来获取文件,此时将执行默认配置的`handler`方法并返回其返回值 + */ + handler?: (ctx: UploaderContext) => (Promise | undefined); + + /** + * 是否显示 + * @description 如果本方式仅部分平台支持,则应该根据平台的能力决定是否显示本方式 + */ + visible?: boolean | ((ctx: UploaderContext) => boolean); + + /** + * 提示文本 + * @description 显示在名称下方的一行文本 + */ + tip?: string | ((ctx: UploaderContext) => string); + + /** + * 自定义选项 + * @description 将被赋值给`UploaderContext`中的`options`字段,一般不需要配置 + */ + options?: Record; +} + +/** 文件条目的上下文数据 */ +export interface FileItemCtx { + + /** 被选中的文件 */ + file: UploadFileItem; + + /** 在文件列表中的下标 */ + index: number; + + /** 文件列表 */ + fileList: UploadFileItem[]; + + /** 上传组件的上下文 */ + ctx: UploaderContext; +} + +/** + * 文件条目的上下文菜单项 + */ +export interface FileContextMenuItem extends ActionSheetItem { + + /** + * 选项编号 + * @description + * 唯一标识,不可重复。 + * 1. 当`key='preview'`时,点击选项将触发预览,组件将进行默认的预览(可通过`preventDefaultPreview`禁用)并抛出预览事件; + * 2. 当`key='delete'`时,点击选项将触发删除,组件将向外抛出删除事件; + * 3. 当`key`等于其它值时,没有默认行为。 + */ + key: "preview" | "delete" | string; + + /** + * 显示的名称 + */ + name?: string | ((options: FileItemCtx) => string); + + /** + * 显示的名称(国际化) + * @description 优先级高于字符串类型的`name`字段,低于回调方法类型的`name`字段 + */ + nameI18n?: { [lang: string]: string }; + + /** + * 选项行为的实现方法 + * @description 当用户选择本选项后,将调用本方法 + */ + handler?: ((options: FileItemCtx) => boolean | void); + + /** + * 是否显示 + * @description 默认显示,可以用来隐藏不被支持的选项 + */ + visible?: boolean | ((options: FileItemCtx) => boolean | void); + + /** + * 是否禁用 + * @description 默认不禁用,当回调方法返回`true`或非空字符串时禁用,返回的字符串将被作为提示文本显示在名称下方,具有比`tip`更高的优先级 + */ + disabled?: boolean | ((options: FileItemCtx) => boolean | string | void); + + /** + * 提示文本 + * @description 显示在名称下方的一行文本 + */ + tip?: string | ((options: FileItemCtx) => string); + + /** + * 自定义选项 + * @description 将被赋值给`UploaderContext`中的`options`字段,一般不需要配置 + */ + options?: Record; +} + +/** 文件获取方式缺省实现的注入标识 */ +export const defaultFilePickerInjectKey: InjectionKey> = Symbol("defaultFilePicker"); + +/** 文件上下文菜单选项默认实现的注入标识 */ +export const defaultUploadFileContextMenuInjectKey: InjectionKey> + = Symbol("defaultUploadFileContextMenu"); + +export type UploaderPopupType = "FilePickerActionSheet" | "ContextMenuActionSheet" | "ContextMenuTooltip"; + +export interface PopupHandler { + + /** + * 打开弹层时回调 + * @description 调用`close`方法可以主动关闭弹层,且不会触发`onClose`回调 + */ + onOpen: (p: { close: () => void; type: UploaderPopupType; uid: string }) => void; + + /** + * 关闭弹层时回调 + */ + onClose: (p: { type: UploaderPopupType; uid: string }) => void; +} + +export interface FileListUpdateContext { + + /** + * 变更来源 + * @description + * 1. `add` 上传后新增文件 + * 2. `delete` 点击删除按钮或者上下文菜单中的删除选项后删除文件 + */ + trigger: "add" | "delete"; +} diff --git a/packages/mobile-ui-vue/components/adv-uploader/src/composition/use-context-menu.tsx b/packages/mobile-ui-vue/components/adv-uploader/src/composition/use-context-menu.tsx new file mode 100644 index 0000000000000000000000000000000000000000..1a5826a968c06aebc25dc2eefc08d17eb47aea8c --- /dev/null +++ b/packages/mobile-ui-vue/components/adv-uploader/src/composition/use-context-menu.tsx @@ -0,0 +1,232 @@ +/* eslint-disable no-continue, no-use-before-define */ +import { SetupContext, computed, ref, inject, Ref } from 'vue'; +import { isPromise, isFunction } from '../../../utils'; +import { useCurrentLang } from '../../../hook'; +import { AdvUploaderProps } from '../adv-uploader.props'; +import { FileContextMenuItem, FileItemCtx, defaultUploadFileContextMenuInjectKey, PopupHandler } from './types'; +import FmFileContextMenuList from '../components/context-menu-list.component'; +import { ToComputedRefs } from '../common/to-refs'; + +export default function useContextMenu(props: ToComputedRefs, context: SetupContext, popupHandler: PopupHandler) { + + const _defaultMenuItems = inject(defaultUploadFileContextMenuInjectKey, []); + + const defaultMenuItems: Ref = ref([]); + + const waitingDefaultMenuItemsResolve = ref(false); + + if (isPromise(_defaultMenuItems)) { + waitingDefaultMenuItemsResolve.value = true; + _defaultMenuItems.then((items) => { + defaultMenuItems.value = items; + waitingDefaultMenuItemsResolve.value = false; + }).catch(() => { + defaultMenuItems.value = []; + waitingDefaultMenuItemsResolve.value = false; + }); + } else if (Array.isArray(_defaultMenuItems)) { + defaultMenuItems.value = _defaultMenuItems; + } + + const setComponentDefaultAction = (menuItem: FileContextMenuItem): void => { + if (menuItem.key !== "delete") { + return; + } + if (menuItem.visible === undefined || menuItem.visible === null) { + menuItem.visible = (itemCtx) => { + return !itemCtx.ctx.readonly; + }; + } + if (menuItem.disabled === undefined || menuItem.disabled === null) { + menuItem.disabled = (itemCtx) => { + return !!itemCtx.ctx.disabled; + }; + } + }; + + const fileItemCtx = ref(); + + /** + * 根据当前文件条目更新菜单选项状态 + * @param menuItem 文件的上下文菜单选项 + * @param curFileItemCtx 当前被选中的文件条目 + */ + const updateMenuItemState = (menuItem: FileContextMenuItem, curFileItemCtx: FileItemCtx | undefined): void => { + if (!curFileItemCtx) { + return; + } + const lang = useCurrentLang(); + const uploaderContext = { ...curFileItemCtx.ctx }; + const itemCtx: FileItemCtx = { ...curFileItemCtx, ctx: uploaderContext }; + uploaderContext.options = menuItem.options || {}; + let name = menuItem.nameI18n?.[lang.value] || menuItem.name; + if (isFunction(name)) { + name = name(itemCtx); + } + let visible = typeof menuItem.visible === "boolean" ? menuItem.visible : true; + if (isFunction(menuItem.visible)) { + visible = menuItem.visible(itemCtx) !== false; + } + const tip = isFunction(menuItem.tip) ? menuItem.tip(itemCtx) : menuItem.tip || ""; + let disabled: string | boolean = typeof menuItem.disabled === "boolean" ? menuItem.disabled : false; + if (isFunction(menuItem.disabled)) { + disabled = menuItem.disabled(itemCtx) === true; + } + + menuItem.__key__ = menuItem.key; + menuItem.__name__ = name; + menuItem.__visible__ = visible; + menuItem.__disabled__ = !!disabled; + menuItem.__tip__ = typeof disabled === "string" ? (disabled || tip) : tip; + }; + + const mergedMenuItems = computed(() => { + waitingDefaultMenuItemsResolve.value; + const items: FileContextMenuItem[] = []; + const userCusItems = props.contextMenuItems?.value || []; + userCusItems.forEach((userCusItem) => { + if (!userCusItem || !userCusItem.key) { + return; + } + const newItem: FileContextMenuItem = { ...userCusItem }; + const defaultItem = defaultMenuItems.value.find(i => i && i.key === newItem.key); + if (defaultItem) { + newItem.name = newItem.name || defaultItem.name; + newItem.nameI18n = Object.assign({}, defaultItem.nameI18n || {}, newItem.nameI18n || {}); + if (newItem.handler && defaultItem.handler) { + const cusHandler = newItem.handler; + const defaultHandler = defaultItem.handler; + newItem.handler = (ctx) => { + const success = cusHandler(ctx); + if (success === false) { + return defaultHandler(ctx); + } + return success; + }; + } else { + newItem.handler = newItem.handler || defaultItem.handler; + } + if (isFunction(newItem.visible)) { + const cusVisibleFunc = newItem.visible; + newItem.visible = (ctx) => { + const val = cusVisibleFunc(ctx); + if (val === undefined) { + return isFunction(defaultItem.visible) ? defaultItem.visible(ctx) : defaultItem.visible; + } + return val; + }; + } else { + newItem.visible = (newItem.visible === false) ? false : (newItem.visible || defaultItem.visible); + } + if (isFunction(newItem.disabled)) { + const cusDisabledFunc = newItem.disabled; + newItem.disabled = (ctx) => { + const val = cusDisabledFunc(ctx); + if (val === undefined) { + return isFunction(defaultItem.disabled) ? defaultItem.disabled(ctx) : defaultItem.disabled; + } + return val; + }; + } else { + newItem.disabled = (newItem.disabled === false) ? false : (newItem.disabled || defaultItem.disabled); + } + newItem.tip = newItem.tip || defaultItem.tip; + newItem.options = Object.assign({}, defaultItem.options || {}, newItem.options || {}); + } + setComponentDefaultAction(newItem); + updateMenuItemState(newItem, fileItemCtx.value); + items.push(newItem); + }); + return items; + }); + + const show = ref(false); + + const popupUID = ref(""); + + const close = (): void => { + show.value = false; + }; + + const toggle = (val: boolean): void => { + if (!!show.value === !!val) { + return; + } + show.value = !!val; + if (val) { + popupUID.value = (new Date()).getTime().toString(); + popupHandler.onOpen({ close, type: "ContextMenuActionSheet", uid: popupUID.value }); + } else { + popupHandler.onClose({ type: "ContextMenuActionSheet", uid: popupUID.value }); + } + }; + + const openContextMenuList = (ctx: FileItemCtx): void => { + fileItemCtx.value = { ...ctx }; + toggle(true); + }; + + const renderContextMenuList = (p: { + onDelete: (ctx: FileItemCtx) => void; + onPreview: (ctx: FileItemCtx) => void; + }) => { + return ( + + + ); + }; + + /** + * 执行指定的菜单项操作 + * @description + * 最多只执行一个菜单项操作,如果传入了多个编号,则依次尝试执行,如果成功则返回 + * (菜单项隐藏、禁用或者回调方法返回`false`都认为执行失败) + * @param ctx 文件条目上下文 + * @param key 菜单选项编号 + * @returns 是否执行成功 + */ + const executeContextMenuItem = (ctx: FileItemCtx, ...keys: string[]): boolean => { + if (!ctx || !keys || keys.length === 0) { + return false; + } + for (let i = 0; i < keys.length; i++) { + const key = keys[i]; + const menuItem = mergedMenuItems.value.find(item => item.key === key); + if (!menuItem) { + continue; + } + const copyItem: FileContextMenuItem = { ...menuItem }; + updateMenuItemState(copyItem, ctx); + if (!copyItem.__disabled__ || copyItem.__visible__ !== false) { + const success = copyItem.handler?.(ctx); + if (success !== false) { + return true; + } + } + } + return false; + }; + + const handleLongPress = (ctx: FileItemCtx, e: TouchEvent): void => { + props.onLongPress?.value?.({ ctx, e }); + context.emit('longPress', { ctx, e }); + const longPressAction = props.longPressAction.value; + if (longPressAction === 'showMenu' || longPressAction === 'showMenuInTooltip') { + openContextMenuList(ctx); + } + }; + + return { + openContextMenuList, + renderContextMenuList, + executeContextMenuItem, + handleLongPress, + }; +} diff --git a/packages/mobile-ui-vue/components/adv-uploader/src/composition/use-popup-handler.ts b/packages/mobile-ui-vue/components/adv-uploader/src/composition/use-popup-handler.ts new file mode 100644 index 0000000000000000000000000000000000000000..fb7adc334b4c6da046aac17d04c64e2993adb340 --- /dev/null +++ b/packages/mobile-ui-vue/components/adv-uploader/src/composition/use-popup-handler.ts @@ -0,0 +1,23 @@ +import { SetupContext } from 'vue'; +import { AdvUploaderProps } from '../adv-uploader.props'; +import { PopupHandler } from './types'; +import { ToComputedRefs } from '../common/to-refs'; + +export default function usePopupHandler(props: ToComputedRefs, context: SetupContext) { + + const popupHandler: PopupHandler = { + onOpen: (p) => { + props.onPopupOpen?.value?.(p); + context.emit("popupOpen", p); + }, + + onClose: (p) => { + props.onPopupClose?.value?.(p); + context.emit("popupClose", p); + }, + }; + + return { + popupHandler, + }; +} diff --git a/packages/mobile-ui-vue/components/adv-uploader/src/composition/use-uploader.ts b/packages/mobile-ui-vue/components/adv-uploader/src/composition/use-uploader.ts new file mode 100644 index 0000000000000000000000000000000000000000..e2e2a367bfcee8119b5c24db8e842b246436d184 --- /dev/null +++ b/packages/mobile-ui-vue/components/adv-uploader/src/composition/use-uploader.ts @@ -0,0 +1,303 @@ +/* eslint-disable no-use-before-define */ +import { SetupContext, computed, ref, inject, Ref } from 'vue'; +import { useCurrentLang } from '../../../hook'; +import { isPromise } from '../../../utils'; +import { AdvUploaderProps } from '../adv-uploader.props'; +import { FileItem, UploadFileItem, UploadProgressContext, UploadResponseContext } from '../common/types'; +import { + FilePickerItem, UploaderContext, defaultFilePickerInjectKey, PopupHandler, FileItemCtx, FileListUpdateContext, +} from './types'; +import { FilePicker } from '../components/file-picker'; +import { validateFiles, readFile, isImage, upload } from '../common/upload'; +import { ToComputedRefs } from '../common/to-refs'; + +export default function useUploader(props: ToComputedRefs, context: SetupContext, popupHandler: PopupHandler) { + + const { files: uploadFileList, autoUpload } = props; + + const setUploadFileList = (newValue: UploadFileItem[], updateContext: FileListUpdateContext) => { + context.emit(`update:files`, newValue, updateContext); + }; + + const _defaultFilePickers = inject(defaultFilePickerInjectKey, []); + + const defaultFilePickers: Ref = ref([]); + + const waitingDefaultFilePickersResolve = ref(false); + + if (isPromise(_defaultFilePickers)) { + waitingDefaultFilePickersResolve.value = true; + _defaultFilePickers.then((pickers) => { + defaultFilePickers.value = pickers; + waitingDefaultFilePickersResolve.value = false; + }).catch(() => { + defaultFilePickers.value = []; + waitingDefaultFilePickersResolve.value = false; + }); + } else if (Array.isArray(_defaultFilePickers)) { + defaultFilePickers.value = _defaultFilePickers; + } + + const mergedFilePickers = computed(() => { + waitingDefaultFilePickersResolve.value; + const items: FilePickerItem[] = []; + const userCusItems = props.filePickerItems?.value || []; + userCusItems.forEach((userCusItem) => { + if (!userCusItem || !userCusItem.key) { + return; + } + const newItem: FilePickerItem = { ...userCusItem }; + const defaultItem = defaultFilePickers.value.find(p => p && p.key === newItem.key); + if (defaultItem) { + newItem.name = newItem.name || defaultItem.name; + newItem.nameI18n = Object.assign({}, defaultItem.nameI18n || {}, newItem.nameI18n || {}); + if (newItem.handler && defaultItem.handler) { + const cusHandler = newItem.handler; + const defaultHandler = defaultItem.handler; + newItem.handler = (ctx) => { + const result = cusHandler(ctx); + return result || defaultHandler(ctx); + }; + } else { + newItem.handler = newItem.handler || defaultItem.handler; + } + newItem.visible = (newItem.visible === false) ? false : (newItem.visible || defaultItem.visible); + newItem.tip = newItem.tip || defaultItem.tip; + newItem.options = Object.assign({}, defaultItem.options || {}, newItem.options || {}); + } + items.push(newItem); + }); + return items; + }); + + /** + * 待上传的文件列表 + * @description + * 自动上传模式下`autoUpload=true`,用户选中的文件将首先作为`待上传的文件`添加到`toUploadFiles`中,待上传完毕后再移到`files`中 + */ + const toUploadFiles = ref([]); + + /** 是否正在上传 */ + const uploading = ref(false); + + /** 显示的文件列表 */ + const displayFiles = computed(() => { + // 手动上传模式下,`files`作为`文件列表`,完全受控 + if (!autoUpload.value) { + return uploadFileList.value || []; + } + // 自动上传模式下,`files`仅作为`已上传的文件列表`,而`待上传的文件列表`是不受控的 + return (uploadFileList.value || []).concat(toUploadFiles.value || []); + }); + + const disableAddBtn = computed(() => { + return props.disabled.value || props.readonly.value || waitingDefaultFilePickersResolve.value; + }); + + const uploaderContext = computed(() => { + const lang = useCurrentLang(); + return { + lang: lang.value, + accept: props.accept?.value, + multiple: props.multiple.value, + fileReadType: props.fileReadType.value, + maxSize: props.maxSize.value, + maxCount: props.maxCount.value, + uploadedFileCount: displayFiles.value.length, + listType: props.listType.value, + readonly: props.readonly.value, + disabled: props.disabled.value, + displayFiles: displayFiles.value, + chooseLocalFile: () => filePicker?.triggerChooseLocalFile(), + }; + }); + + const addWaitingFiles = async (files: UploadFileItem[]) => { + // 转化文件格式 + await Promise.all(files.map((fileItem) => readFile(fileItem, props.fileReadType.value))); + // 获取文件的临时缩略图 + const pList = files.map((fileItem) => ( + new Promise((resolve) => { + const setResult = (url?: string) => { + fileItem.thumbnailUrl = url; + resolve(fileItem); + }; + if (props.useOriginalImageAsThumbnail.value && isImage(fileItem)) { + readFile(fileItem, "dataUrl").then(() => { + setResult(fileItem.dataUrl); + }); + } else { + const thumbnail = props.getThumbnailUrl?.value?.(fileItem); + if (typeof thumbnail === "string") { + setResult(thumbnail); + } else if (isPromise(thumbnail)) { + thumbnail.then((url) => { + setResult(url); + }).catch(() => { + setResult(); + }); + } else { + setResult(); + } + } + }) + )); + const toFiles = await Promise.all(pList); + // 更新文件列表 + if (autoUpload.value) { + toUploadFiles.value = toFiles; + } else { + const newFileList = uploadFileList.value.concat(toFiles); + setUploadFileList(newFileList, { trigger: "add" }); + } + }; + + const onChooseFile = async (files: FileItem[]) => { + if (props.disabled.value || props.readonly.value) { + return; + } + const { validFiles, problems } = await validateFiles({ + files: [...files], + uploadedFiles: uploadFileList.value, + maxCount: props.maxCount.value, + maxSize: props.maxSize.value, + allowDuplicateFile: props.allowDuplicateFile.value, + beforeUpload: props.beforeUpload?.value, + context: uploaderContext.value, + }); + if (problems && problems.length) { + props.onValidate?.value?.(problems); + context.emit("validate", problems); + } + await addWaitingFiles(validFiles); + if (props.autoUpload.value) { + uploadFiles(validFiles); + } + }; + + const triggerFileProgressUpdate = () => { + // 仅处理自动上传模式下的进度更新,手动上传模式下需要调用者自行处理 + if (props.autoUpload.value) { + toUploadFiles.value = [...toUploadFiles.value]; + } + }; + + const handleProgress = (ctx?: UploadProgressContext) => { + triggerFileProgressUpdate(); + if (ctx) { + props.onProgress?.value?.(ctx); + context.emit("progress", ctx); + } + }; + + const handleOneFileSuccess = (ctx: UploadResponseContext) => { + triggerFileProgressUpdate(); + if (!props.singleRequestUpload.value) { + props.onOneFileSuccess?.value?.(ctx); + context.emit("oneFileSuccess", ctx); + } + }; + + const handleOneFileFail = (ctx: UploadResponseContext) => { + triggerFileProgressUpdate(); + if (!props.singleRequestUpload.value) { + props.onOneFileFail?.value?.(ctx); + context.emit("oneFileFail", ctx); + } + }; + + /** + * 上传文件 + * @description 在手动上传`autoUpload=false`模式下,调用本方法使得文件上传 + * @param files 指定要上传的文件 + */ + function uploadFiles(files?: UploadFileItem[]) { + const notUploadedFiles = uploadFileList.value.filter(f => f.status !== 'success'); + const toFiles = autoUpload.value ? files || toUploadFiles.value : notUploadedFiles; + if (!toFiles || !toFiles.length) { + return; + } + uploading.value = true; + upload({ + toUploadFiles: toFiles, + data: props.data?.value, + singleRequestUpload: props.singleRequestUpload.value, + action: props.action.value, + name: props.name.value, + useMockProgress: props.useMockProgress.value, + headers: props.headers?.value, + withCredentials: props.withCredentials.value, + method: props.method.value, + fileReadType: props.fileReadType.value, + formatRequestData: props.formatRequestData?.value, + formatResponseData: props.formatResponseData?.value, + customUploadMethod: props.customUploadMethod?.value, + onOneFileSuccess: handleOneFileSuccess, + onOneFileFail: handleOneFileFail, + onProgress: handleProgress, + }).then((result) => { + uploading.value = false; + if (autoUpload.value) { + const newUploadFileList = uploadFileList.value.concat( + (result.successItems || []).map(item => item.file) + ); + setUploadFileList(newUploadFileList, { trigger: "add" }); + toUploadFiles.value = (result.failedItems || []).map(item => item.file); + } + props.onUploadFinish?.value?.(result); + context.emit("uploadFinish", result); + }).catch(() => { + uploading.value = false; + }); + } + + const filePicker = new FilePicker(); + filePicker.onChooseFile = onChooseFile; + filePicker.onOpen = (close, uid) => { + popupHandler.onOpen({ close, type: 'FilePickerActionSheet', uid }); + }; + filePicker.onClose = (uid) => { + popupHandler.onClose({ type: 'FilePickerActionSheet', uid }); + }; + + const triggerUpload = () => { + if (disableAddBtn.value) { + return; + } + filePicker.setFilePickerItems(mergedFilePickers.value); + filePicker.pickFile(uploaderContext.value, 110, document.body); + }; + + const handleInnerDelete = (fileItemCtx: FileItemCtx, e?: MouseEvent) => { + e?.stopPropagation(); + const { index } = fileItemCtx; + const updateContext: FileListUpdateContext = { trigger: "delete" }; + if (props.autoUpload.value) { + if (index < uploadFileList.value.length) { + const newFileList = [...uploadFileList.value]; + newFileList.splice(index, 1); + setUploadFileList(newFileList, updateContext); + } else { + toUploadFiles.value.splice(index - uploadFileList.value.length, 1); + toUploadFiles.value = [...toUploadFiles.value]; + } + } else { + const newFileList = [...uploadFileList.value]; + newFileList.splice(index, 1); + setUploadFileList(newFileList, updateContext); + } + props.onDelete?.value?.({ ctx: fileItemCtx, e }); + context.emit("delete", { ctx: fileItemCtx, e }); + }; + + return { + displayFiles, + toUploadFiles, + uploading, + disableAddBtn, + uploaderContext, + triggerUpload, + uploadFiles, + handleInnerDelete, + }; +} diff --git a/packages/mobile-ui-vue/components/button/index.ts b/packages/mobile-ui-vue/components/button/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..39c0c78173e04fa55a731cc2db29695b2999ff13 --- /dev/null +++ b/packages/mobile-ui-vue/components/button/index.ts @@ -0,0 +1,9 @@ +import { App } from 'vue'; +import Button from './src/button.vue'; + +Button.install = (app: App) => { + app.component(Button.name || 'FmButton', Button); +}; + +export { Button }; +export default Button; diff --git a/packages/mobile-ui-vue/components/button/src/button.vue b/packages/mobile-ui-vue/components/button/src/button.vue new file mode 100644 index 0000000000000000000000000000000000000000..efbf0abdc2c20567eaca6e44b9611d54224d0e84 --- /dev/null +++ b/packages/mobile-ui-vue/components/button/src/button.vue @@ -0,0 +1,123 @@ + + diff --git a/packages/mobile-ui-vue/components/cell/index.ts b/packages/mobile-ui-vue/components/cell/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..b3f0838892ec39337e11f5345529c3a236c30c8d --- /dev/null +++ b/packages/mobile-ui-vue/components/cell/index.ts @@ -0,0 +1,9 @@ +import { App } from 'vue'; +import Cell from './src/index.vue'; + +Cell.install = (app: App) => { + app.component(Cell.name || 'FmCell', Cell); +}; + +export { Cell }; +export default Cell; diff --git a/packages/mobile-ui-vue/components/cell/src/index.vue b/packages/mobile-ui-vue/components/cell/src/index.vue new file mode 100644 index 0000000000000000000000000000000000000000..314522b3ae4b63116f0cb897a2e26dd91e7d7fbd --- /dev/null +++ b/packages/mobile-ui-vue/components/cell/src/index.vue @@ -0,0 +1,136 @@ + + + + diff --git a/packages/mobile-ui-vue/components/checkbox/README.md b/packages/mobile-ui-vue/components/checkbox/README.md new file mode 100644 index 0000000000000000000000000000000000000000..816486b842b2e4e91a323048a8017ec10752e19f --- /dev/null +++ b/packages/mobile-ui-vue/components/checkbox/README.md @@ -0,0 +1,30 @@ +# fm-checkbox +## API + +### Props + +| 参数 | 说明 | 类型 | 默认值 | +| :--: | :--: | :--: | :--: | +|name|名称|any|-| +|shape|形状|string|'square'| +|checked-color|选中时颜色|string|'#189fa'| + +# fm-cgroup +## API + +### Props + +| 参数 | 说明 | 类型 | 默认值 | +| :--: | :--: | :--: | :--: | +|v-model(value)|绑定值|any|-| +|label|标题|any|-| +|disabled|禁用|boolean|false| +|required|必需|boolean|false| +|direction|排列方向|string|'vertical'| + +### Events + +| 事件 | 说明 | 回调参数 | +| :--: | :--: | :--: | +| input | 选择选项时触发 | value: 选择的选项值 | +| change | 选项改变时触发 | value: 改变值 | diff --git a/packages/mobile-ui-vue/components/checkbox/index.ts b/packages/mobile-ui-vue/components/checkbox/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..2f88d40aed332a1c391ac9ef492e356174813bf6 --- /dev/null +++ b/packages/mobile-ui-vue/components/checkbox/index.ts @@ -0,0 +1,13 @@ +import { App } from 'vue'; +import CheckboxGroup from './src/checkbox-group.vue'; +import Checker from './src/checker.vue'; + +CheckboxGroup.install = function (app: App) { + app.component(CheckboxGroup.name || 'FmCheckboxGroup', CheckboxGroup); +}; +Checker.install = function (app: App) { + app.component(Checker.name || 'FmChecker', Checker); +}; + +export { CheckboxGroup, Checker }; +export default CheckboxGroup; diff --git a/packages/mobile-ui-vue/components/checkbox/src/checkbox-group.vue b/packages/mobile-ui-vue/components/checkbox/src/checkbox-group.vue new file mode 100644 index 0000000000000000000000000000000000000000..4fac2956a921b71bc171ee8584760b5d144d9161 --- /dev/null +++ b/packages/mobile-ui-vue/components/checkbox/src/checkbox-group.vue @@ -0,0 +1,103 @@ + + + diff --git a/packages/mobile-ui-vue/components/checkbox/src/checkbox-props.ts b/packages/mobile-ui-vue/components/checkbox/src/checkbox-props.ts new file mode 100644 index 0000000000000000000000000000000000000000..5fbed35df0474cd394748b312960acb8e5e052b5 --- /dev/null +++ b/packages/mobile-ui-vue/components/checkbox/src/checkbox-props.ts @@ -0,0 +1,67 @@ +import { CSSProperties, PropType } from "vue"; + +export const checkerProps = { + label: { + type: String, + default: '', + }, + labelLimit: Number, + disabled: { + type: Boolean, + default: false, + }, + readonly: { + type: Boolean, + default: false, + }, + shape: { + type: String, + default: 'round', + }, + modelValue: { + type: Boolean, + default: false, + }, + checkedColor: { + type: String, + default: '#3A90FF', + }, + role: { + type: String, + default: 'check', + }, + labelClass: String, + size: { + type: String, + default: 'normal', + }, +} +export const checkboxInputProps = { + ...checkerProps, + shape: { + type: String, + default: 'square', + }, + type: { + type: String, + default: 'check', + }, + direction: { + type: String, + default: 'vertical', + }, + valueField: { + type: String, + default: 'value', + }, + textField: { + type: String, + default: 'text', + }, + showDisabledItem: { + type: Boolean, + default: true + }, + items: Array as PropType>, + checkerStyle: Object as PropType, +} \ No newline at end of file diff --git a/packages/mobile-ui-vue/components/checkbox/src/checker.vue b/packages/mobile-ui-vue/components/checkbox/src/checker.vue new file mode 100644 index 0000000000000000000000000000000000000000..9cb2462fefe925a662ac886188b6307c59189f2a --- /dev/null +++ b/packages/mobile-ui-vue/components/checkbox/src/checker.vue @@ -0,0 +1,56 @@ + + + diff --git a/packages/mobile-ui-vue/components/config.ts b/packages/mobile-ui-vue/components/config.ts new file mode 100644 index 0000000000000000000000000000000000000000..d4a96f605f63ed4643c09e60b4bc0613ebc9af9a --- /dev/null +++ b/packages/mobile-ui-vue/components/config.ts @@ -0,0 +1,3 @@ +export default { + prefix: 'fm' +}; diff --git a/packages/mobile-ui-vue/components/hook/index.ts b/packages/mobile-ui-vue/components/hook/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..56003f650d03dfd8b7c89bcd0a8774776f711dd2 --- /dev/null +++ b/packages/mobile-ui-vue/components/hook/index.ts @@ -0,0 +1,18 @@ +export * from './use-lay-render'; +export * from './use-event-listener'; +export * from './use-click-away'; +export * from './use-lock-scroll'; +export * from './use-expose'; +export * from './use-mount-component'; +export * from './use-touch-move'; +export * from './use-element-rect'; +export * from './use-dynamic-template'; +export * from './use-bem'; +export * from './use-touch'; +export * from './use-back'; +export * from './use-state'; +export * from './use-md5'; +export * from './use-props'; +export * from './use-queue'; +export * from './use-locale'; +export * from './use-long-press'; diff --git a/packages/mobile-ui-vue/components/hook/use-back/index.ts b/packages/mobile-ui-vue/components/hook/use-back/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..e953de5ca6c1d20b4ea973284bd892d5c93834e7 --- /dev/null +++ b/packages/mobile-ui-vue/components/hook/use-back/index.ts @@ -0,0 +1,19 @@ +/* eslint-disable dot-notation */ +export function useBack(enableShow?: any) { + const pushBack = (cb: () => void) => { + // @ts-ignore + window['MOBILE_ORIGIN_BACK'] && window['MOBILE_ORIGIN_BACK'].pushOriginGoback(cb); + }; + const popBack = () => { + // @ts-ignore + window['MOBILE_ORIGIN_BACK'] && window['MOBILE_ORIGIN_BACK'].popOriginGoback(); + }; + const pushOrPop = (cb = () => { enableShow.value = false; }) => { + if (enableShow.value) { + pushBack(cb); + } else { + popBack(); + } + }; + return { pushBack, popBack, pushOrPop }; +} diff --git a/packages/mobile-ui-vue/components/hook/use-bem/index.ts b/packages/mobile-ui-vue/components/hook/use-bem/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..db69614988596529f3f9e8faac1714e50f479dcc --- /dev/null +++ b/packages/mobile-ui-vue/components/hook/use-bem/index.ts @@ -0,0 +1,3 @@ +export function useBem(prefix: string) { + return (className: string) => `${prefix}-${className}`; +} diff --git a/packages/mobile-ui-vue/components/hook/use-click-away/index.ts b/packages/mobile-ui-vue/components/hook/use-click-away/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..408c25b0ce9c51a57f1a53dec7128e6103dbf53b --- /dev/null +++ b/packages/mobile-ui-vue/components/hook/use-click-away/index.ts @@ -0,0 +1,34 @@ +import { Ref, unref } from 'vue'; +import { inBrowser, initNodePath } from '../../utils'; +import { useEventListener } from '../use-event-listener'; + +export type UseClickAwayOptions = { + eventName?: string; + active?: Ref | boolean; +}; + +export function useClickAway( + target: Element | Ref, + listener: EventListener, + options: UseClickAwayOptions = {}, +) { + if (!inBrowser) { + return; + } + + const { eventName = 'click', active = true } = options; + + const onClick = (event: Event | any) => { + const _active = unref(active); + const element = unref(target); + let flag = _active && element && !element.contains(event.target as Node); + if (flag) { + const path = event.path ? event.path : initNodePath(event); + flag = !path.find((item: Element) => item === element); + } + if (flag) { + listener(event); + } + }; + useEventListener(eventName, onClick, { target: document }); +} diff --git a/packages/mobile-ui-vue/components/hook/use-dynamic-template/index.ts b/packages/mobile-ui-vue/components/hook/use-dynamic-template/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..ec41379182a43ce7603546a27a3b1c2293b0e9d3 --- /dev/null +++ b/packages/mobile-ui-vue/components/hook/use-dynamic-template/index.ts @@ -0,0 +1,52 @@ +/* eslint-disable no-new-func */ +import { + baseParse, + getBaseTransformPreset, + transform, +} from '@vue/compiler-core'; +import * as Vue from 'vue'; +import { isHTMLTag, VueCodeGenerate } from '../../utils'; + +export const dynamicTemplate = Vue.defineComponent({ + name: 'dynamic-template', + props: { + props: { + type: Object, + default: () => { + return {}; + }, + }, + }, + render() { }, +}); + +function createFunction(code: string) { + try { + return new Function('Vue', code); + } catch (err) { + console.warn(err, code); + return () => { }; + } +} + +export function useDynamicTemplate(template: string) { + const ast = baseParse(template, { + // 判断是否是元素标签 + isNativeTag: isHTMLTag, + }); + const prefixIdentifiers = true; + + const [nodeTransforms, directiveTransforms] = getBaseTransformPreset(prefixIdentifiers); + + transform(ast, { + prefixIdentifiers, + nodeTransforms: [...nodeTransforms], + directiveTransforms + }); + const dynamicRender = VueCodeGenerate(ast); + dynamicTemplate.render = createFunction(dynamicRender.code)(Vue); + return { + dynamicRender, + dynamicTemplate, + }; +} diff --git a/packages/mobile-ui-vue/components/hook/use-element-rect/index.ts b/packages/mobile-ui-vue/components/hook/use-element-rect/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..64b1f228db48917f3e19ed92f19fa1bcfbb89bfb --- /dev/null +++ b/packages/mobile-ui-vue/components/hook/use-element-rect/index.ts @@ -0,0 +1,14 @@ +import { ref, Ref, unref } from "vue"; +import { onMountedOrActivated } from "../../utils"; + +export const useElementRect = (el: Ref) => { + const rect: Ref = ref(); + const hook = () => { + const target: Element | undefined = unref(el); + rect.value = target?.getBoundingClientRect(); + }; + onMountedOrActivated(hook); + return { + rect + }; +}; diff --git a/packages/mobile-ui-vue/components/hook/use-event-listener/index.ts b/packages/mobile-ui-vue/components/hook/use-event-listener/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..729c8b335f275e4f8c3a746c1c68151ae5bad4bb --- /dev/null +++ b/packages/mobile-ui-vue/components/hook/use-event-listener/index.ts @@ -0,0 +1,45 @@ +import { onMountedOrActivated, inBrowser } from '../../utils'; +import { unref, onUnmounted, onDeactivated, Ref } from 'vue'; + +export const supportsPassive = false; + +export type UseEventListenerOptions = { + target?: EventTarget | Ref; + capture?: boolean; + passive?: boolean; + immediate?: boolean; +}; + +export function useEventListener(type: string, listener: EventListener, options: UseEventListenerOptions = {}) { + if (!inBrowser) { + return; + } + + const { target = window, passive = false, capture = false, immediate = false } = options; + let attached = false; + + const add = () => { + const element = unref(target); + + if (element && !attached) { + element.addEventListener(type, listener, supportsPassive ? { + capture, + passive + } : capture); + attached = true; + } + }; + + const remove = () => { + const element = unref(target); + + if (element && attached) { + element.removeEventListener(type, listener, capture); + attached = false; + } + }; + + immediate ? add() : onMountedOrActivated(add); + onUnmounted(remove); + onDeactivated(remove); +} diff --git a/packages/mobile-ui-vue/components/hook/use-expose/index.ts b/packages/mobile-ui-vue/components/hook/use-expose/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..b7d83800c7912d8d07b121bfbc89be0ed003d31a --- /dev/null +++ b/packages/mobile-ui-vue/components/hook/use-expose/index.ts @@ -0,0 +1,9 @@ +import { getCurrentInstance } from 'vue'; + +// expose public api +export function useExpose(apis: Record) { + const instance = getCurrentInstance(); + if (instance) { + Object.assign(instance.proxy as any, apis); + } +} diff --git a/packages/mobile-ui-vue/components/hook/use-lay-render/index.ts b/packages/mobile-ui-vue/components/hook/use-lay-render/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..3f505e7a0ad0086b0bd44c42c8b8f53cc881ef9c --- /dev/null +++ b/packages/mobile-ui-vue/components/hook/use-lay-render/index.ts @@ -0,0 +1,17 @@ +import { ref, watch, WatchSource } from 'vue'; + +export function useLazyRender(show: WatchSource) { + const inited = ref(false); + + watch( + show, + (value) => { + if (value) { + inited.value = value; + } + }, + { immediate: true } + ); + + return (render: () => JSX.Element) => () => (inited.value ? render() : null); +} diff --git a/packages/mobile-ui-vue/components/hook/use-locale/index.ts b/packages/mobile-ui-vue/components/hook/use-locale/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..a2373f51990ca1eba4999559443d284b849a36a1 --- /dev/null +++ b/packages/mobile-ui-vue/components/hook/use-locale/index.ts @@ -0,0 +1,5 @@ +import Locale from "../../locale"; + +export const useLocale = (name: string) => Locale.createTranslate(name); + +export const useCurrentLang = () => Locale.getCurrentLang(); diff --git a/packages/mobile-ui-vue/components/hook/use-lock-scroll/index.ts b/packages/mobile-ui-vue/components/hook/use-lock-scroll/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..ac2888dbc2918d48c468432ea82f22fdb7b9e84d --- /dev/null +++ b/packages/mobile-ui-vue/components/hook/use-lock-scroll/index.ts @@ -0,0 +1,25 @@ +let count = 0; + +const CLASSNAME = 'fm-overflow-hidden'; + +export function useLockScroll(shouldLock: () => boolean) { + const lock = () => { + if (shouldLock()) { + if (!count) { + document.body.classList.add(CLASSNAME); + } + count++; + } + }; + + const unlock = () => { + if (shouldLock() && count) { + count--; + if (!count) { + document.body.classList.remove(CLASSNAME); + } + } + }; + + return [lock, unlock]; +} diff --git a/packages/mobile-ui-vue/components/hook/use-long-press/index.ts b/packages/mobile-ui-vue/components/hook/use-long-press/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..c029294f2e5ba7c2492555dbee3a14fd944c813e --- /dev/null +++ b/packages/mobile-ui-vue/components/hook/use-long-press/index.ts @@ -0,0 +1,141 @@ +/* eslint-disable no-use-before-define */ +import { ObjectDirective } from 'vue'; + +const DEFAULT_DELAY = 600; +const DEFAULT_THRESHOLD = 10; + +export interface OnLongPressModifiers { + stop?: boolean; + once?: boolean; + prevent?: boolean; + capture?: boolean; + self?: boolean; + preventDefaultContextMenu?: boolean; + interceptClick?: boolean; +} + +export interface OnLongPressOptions { + + delay?: number; + + modifiers?: OnLongPressModifiers; + + distanceThreshold?: number | false; +} + +interface Position { + x: number; + y: number; +} + +function addEventListener(el: HTMLElement, event: string, listener: any, options: any): () => void { + el.addEventListener(event, listener, options); + return () => el.removeEventListener(event, listener, options); +} + +export function onLongPress( + target: HTMLElement, + handler: (evt: TouchEvent) => void, + options?: OnLongPressOptions, +) { + let timeout: ReturnType | undefined; + let posStart: Position | undefined; + + function clear() { + if (timeout) { + clearTimeout(timeout); + timeout = undefined; + } + posStart = undefined; + } + + function onStart(ev: TouchEvent) { + if (options?.modifiers?.self && ev.target !== target) { + return; + } + + clear(); + + options?.modifiers?.prevent && ev.preventDefault(); + options?.modifiers?.stop && ev.stopPropagation(); + + posStart = { + x: ev.touches[0].pageX, + y: ev.touches[0].pageY, + }; + timeout = setTimeout( + () => { + timeout = undefined; + handler(ev); + }, + options?.delay ?? DEFAULT_DELAY, + ); + } + + function onMove(ev: TouchEvent) { + if (options?.modifiers?.self && ev.target !== target) { + return; + } + + if (!posStart || options?.distanceThreshold === false) { + return; + } + + options?.modifiers?.prevent && ev.preventDefault(); + options?.modifiers?.stop && ev.stopPropagation(); + + const dx = ev.touches[0].pageX - posStart.x; + const dy = ev.touches[0].pageY - posStart.y; + const distance = Math.sqrt(dx * dx + dy * dy); + if (distance >= (options?.distanceThreshold ?? DEFAULT_THRESHOLD)) { + clear(); + } + } + + function onEnd() { + if (options?.modifiers?.interceptClick && !timeout) { + addAutoDisappearMask(); + } + clear(); + } + + function onContextmenu(ev: Event) { + options?.modifiers?.preventDefaultContextMenu && ev.preventDefault(); + } + + const listenerOptions = { + capture: options?.modifiers?.capture, + once: options?.modifiers?.once, + }; + const cleanup = [ + addEventListener(target, 'touchstart', onStart, listenerOptions), + addEventListener(target, 'touchmove', onMove, listenerOptions), + addEventListener(target, 'touchend', onEnd, listenerOptions), + addEventListener(target, 'touchcancel', clear, listenerOptions), + addEventListener(target, 'contextmenu', onContextmenu, listenerOptions), + ]; + const stop = () => cleanup.forEach(fn => fn()); + return stop; +} + +type BindingValue = (evt: TouchEvent) => void; + +export const vOnLongPress: ObjectDirective = { + mounted(el, binding) { + onLongPress(el, binding.value, { modifiers: binding.modifiers }); + } +}; + +function addAutoDisappearMask(duration?: number): void { + const mask = document.createElement('div'); + mask.style.position = 'fixed'; + mask.style.top = '0'; + mask.style.right = '0'; + mask.style.bottom = '0'; + mask.style.left = '0'; + mask.style.zIndex = '99999'; + document.body.appendChild(mask); + setTimeout(() => { + document.body.removeChild(mask); + }, duration || 25); +} diff --git a/packages/mobile-ui-vue/components/hook/use-md5/index.ts b/packages/mobile-ui-vue/components/hook/use-md5/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..3e609cfe7ed0dbf4f41979b33fc61e0e4f78ea25 --- /dev/null +++ b/packages/mobile-ui-vue/components/hook/use-md5/index.ts @@ -0,0 +1,315 @@ +/* eslint-disable camelcase */ +/* eslint-disable no-use-before-define */ +/* + * Configurable variables. You may need to tweak these to be compatible with + * the server-side, but the defaults work in most cases. + */ +const hexcase = 0; /* hex output format. 0 - lowercase; 1 - uppercase */ +const b64pad = ''; /* base-64 pad character. "=" for strict RFC compliance */ +const chrsz = 8; /* bits per input character. 8 - ASCII; 16 - Unicode */ + +export const useMd5 = () => { + return { + md5, + hex_md5, + b64_md5, + str_md5, + hex_hmac_md5, + b64_hmac_md5, + str_hmac_md5 + }; +}; +const md5 = (s: string, type = 'hex') => { + let result = ''; + switch (type) { + case 'hex': + result = hex_md5(s); + break; + case 'b64': + result = b64_md5(s); + break; + case 'str': + result = str_md5(s); + return; + default: + result = hex_md5(s); + break; + } + return result; +}; +/* + * These are the functions you'll usually want to call + * They take string arguments and return either hex or base-64 encoded strings + */ +function hex_md5(s: string) { + return binl2hex(core_md5(str2binl(s), s.length * chrsz)); +} +function b64_md5(s: string) { + return binl2b64(core_md5(str2binl(s), s.length * chrsz)); +} +function str_md5(s: string) { + return binl2str(core_md5(str2binl(s), s.length * chrsz)); +} +function hex_hmac_md5(key: string, data: string) { + return binl2hex(core_hmac_md5(key, data)); +} +function b64_hmac_md5(key: string, data: string) { + return binl2b64(core_hmac_md5(key, data)); +} +function str_hmac_md5(key: string, data: string) { + return binl2str(core_hmac_md5(key, data)); +} + +/* + * Perform a simple self-test to see if the VM is working + */ +// function md5_vm_test() { +// return hex_md5('abc') == '900150983cd24fb0d6963f7d28e17f72' +// } + +/* + * Calculate the MD5 of an array of little-endian words, and a bit length + */ +function core_md5(x: number[], len: number) { + /* append padding */ + x[len >> 5] |= 0x80 << len % 32; + x[(((len + 64) >>> 9) << 4) + 14] = len; + + let a = 1732584193; + let b = -271733879; + let c = -1732584194; + let d = 271733878; + + for (let i = 0; i < x.length; i += 16) { + const olda = a; + const oldb = b; + const oldc = c; + const oldd = d; + + a = md5_ff(a, b, c, d, x[i + 0], 7, -680876936); + d = md5_ff(d, a, b, c, x[i + 1], 12, -389564586); + c = md5_ff(c, d, a, b, x[i + 2], 17, 606105819); + b = md5_ff(b, c, d, a, x[i + 3], 22, -1044525330); + a = md5_ff(a, b, c, d, x[i + 4], 7, -176418897); + d = md5_ff(d, a, b, c, x[i + 5], 12, 1200080426); + c = md5_ff(c, d, a, b, x[i + 6], 17, -1473231341); + b = md5_ff(b, c, d, a, x[i + 7], 22, -45705983); + a = md5_ff(a, b, c, d, x[i + 8], 7, 1770035416); + d = md5_ff(d, a, b, c, x[i + 9], 12, -1958414417); + c = md5_ff(c, d, a, b, x[i + 10], 17, -42063); + b = md5_ff(b, c, d, a, x[i + 11], 22, -1990404162); + a = md5_ff(a, b, c, d, x[i + 12], 7, 1804603682); + d = md5_ff(d, a, b, c, x[i + 13], 12, -40341101); + c = md5_ff(c, d, a, b, x[i + 14], 17, -1502002290); + b = md5_ff(b, c, d, a, x[i + 15], 22, 1236535329); + + a = md5_gg(a, b, c, d, x[i + 1], 5, -165796510); + d = md5_gg(d, a, b, c, x[i + 6], 9, -1069501632); + c = md5_gg(c, d, a, b, x[i + 11], 14, 643717713); + b = md5_gg(b, c, d, a, x[i + 0], 20, -373897302); + a = md5_gg(a, b, c, d, x[i + 5], 5, -701558691); + d = md5_gg(d, a, b, c, x[i + 10], 9, 38016083); + c = md5_gg(c, d, a, b, x[i + 15], 14, -660478335); + b = md5_gg(b, c, d, a, x[i + 4], 20, -405537848); + a = md5_gg(a, b, c, d, x[i + 9], 5, 568446438); + d = md5_gg(d, a, b, c, x[i + 14], 9, -1019803690); + c = md5_gg(c, d, a, b, x[i + 3], 14, -187363961); + b = md5_gg(b, c, d, a, x[i + 8], 20, 1163531501); + a = md5_gg(a, b, c, d, x[i + 13], 5, -1444681467); + d = md5_gg(d, a, b, c, x[i + 2], 9, -51403784); + c = md5_gg(c, d, a, b, x[i + 7], 14, 1735328473); + b = md5_gg(b, c, d, a, x[i + 12], 20, -1926607734); + + a = md5_hh(a, b, c, d, x[i + 5], 4, -378558); + d = md5_hh(d, a, b, c, x[i + 8], 11, -2022574463); + c = md5_hh(c, d, a, b, x[i + 11], 16, 1839030562); + b = md5_hh(b, c, d, a, x[i + 14], 23, -35309556); + a = md5_hh(a, b, c, d, x[i + 1], 4, -1530992060); + d = md5_hh(d, a, b, c, x[i + 4], 11, 1272893353); + c = md5_hh(c, d, a, b, x[i + 7], 16, -155497632); + b = md5_hh(b, c, d, a, x[i + 10], 23, -1094730640); + a = md5_hh(a, b, c, d, x[i + 13], 4, 681279174); + d = md5_hh(d, a, b, c, x[i + 0], 11, -358537222); + c = md5_hh(c, d, a, b, x[i + 3], 16, -722521979); + b = md5_hh(b, c, d, a, x[i + 6], 23, 76029189); + a = md5_hh(a, b, c, d, x[i + 9], 4, -640364487); + d = md5_hh(d, a, b, c, x[i + 12], 11, -421815835); + c = md5_hh(c, d, a, b, x[i + 15], 16, 530742520); + b = md5_hh(b, c, d, a, x[i + 2], 23, -995338651); + + a = md5_ii(a, b, c, d, x[i + 0], 6, -198630844); + d = md5_ii(d, a, b, c, x[i + 7], 10, 1126891415); + c = md5_ii(c, d, a, b, x[i + 14], 15, -1416354905); + b = md5_ii(b, c, d, a, x[i + 5], 21, -57434055); + a = md5_ii(a, b, c, d, x[i + 12], 6, 1700485571); + d = md5_ii(d, a, b, c, x[i + 3], 10, -1894986606); + c = md5_ii(c, d, a, b, x[i + 10], 15, -1051523); + b = md5_ii(b, c, d, a, x[i + 1], 21, -2054922799); + a = md5_ii(a, b, c, d, x[i + 8], 6, 1873313359); + d = md5_ii(d, a, b, c, x[i + 15], 10, -30611744); + c = md5_ii(c, d, a, b, x[i + 6], 15, -1560198380); + b = md5_ii(b, c, d, a, x[i + 13], 21, 1309151649); + a = md5_ii(a, b, c, d, x[i + 4], 6, -145523070); + d = md5_ii(d, a, b, c, x[i + 11], 10, -1120210379); + c = md5_ii(c, d, a, b, x[i + 2], 15, 718787259); + b = md5_ii(b, c, d, a, x[i + 9], 21, -343485551); + + a = safe_add(a, olda); + b = safe_add(b, oldb); + c = safe_add(c, oldc); + d = safe_add(d, oldd); + } + return [a, b, c, d]; +} + +/* + * These functions implement the four basic operations the algorithm uses. + */ +function md5_cmn( + q: number, + a: number, + b: number, + x: number, + s: number, + t: number, +) { + return safe_add(bit_rol(safe_add(safe_add(a, q), safe_add(x, t)), s), b); +} +function md5_ff( + a: number, + b: number, + c: number, + d: number, + x: number, + s: number, + t: number, +) { + return md5_cmn((b & c) | (~b & d), a, b, x, s, t); +} +function md5_gg( + a: number, + b: number, + c: number, + d: number, + x: number, + s: number, + t: number, +) { + return md5_cmn((b & d) | (c & ~d), a, b, x, s, t); +} +function md5_hh( + a: number, + b: number, + c: number, + d: number, + x: number, + s: number, + t: number, +) { + return md5_cmn(b ^ c ^ d, a, b, x, s, t); +} +function md5_ii( + a: number, + b: number, + c: number, + d: number, + x: number, + s: number, + t: number, +) { + return md5_cmn(c ^ (b | ~d), a, b, x, s, t); +} + +/* + * Calculate the HMAC-MD5, of a key and some data + */ +function core_hmac_md5(key: string, data: string) { + let bkey = str2binl(key); + if (bkey.length > 16) { + bkey = core_md5(bkey, key.length * chrsz); + } + + const ipad = Array(16); + const opad = Array(16); + for (let i = 0; i < 16; i++) { + ipad[i] = bkey[i] ^ 0x36363636; + opad[i] = bkey[i] ^ 0x5c5c5c5c; + } + + const hash = core_md5(ipad.concat(str2binl(data)), 512 + data.length * chrsz); + return core_md5(opad.concat(hash), 512 + 128); +} + +/* + * Add integers, wrapping at 2^32. This uses 16-bit operations internally + * to work around bugs in some JS interpreters. + */ +function safe_add(x: number, y: number) { + const lsw = (x & 0xffff) + (y & 0xffff); + const msw = (x >> 16) + (y >> 16) + (lsw >> 16); + return (msw << 16) | (lsw & 0xffff); +} + +/* + * Bitwise rotate a 32-bit number to the left. + */ +function bit_rol(num: number, cnt: number) { + return (num << cnt) | (num >>> (32 - cnt)); +} + +/* + * Convert a string to an array of little-endian words + * If chrsz is ASCII, characters >255 have their hi-byte silently ignored. + */ +function str2binl(str: string) { + const bin: number[] = []; + const mask = (1 << chrsz) - 1; + for (let i = 0; i < str.length * chrsz; i += chrsz) { + bin[i >> 5] |= (str.charCodeAt(i / chrsz) & mask) << i % 32; + } + return bin; +} + +/* + * Convert an array of little-endian words to a string + */ +function binl2str(bin: number[]) { + let str = ''; + const mask = (1 << chrsz) - 1; + for (let i = 0; i < bin.length * 32; i += chrsz) + {str += String.fromCharCode((bin[i >> 5] >>> i % 32) & mask);} + return str; +} + +/* + * Convert an array of little-endian words to a hex string. + */ +function binl2hex(binarray: number[]) { + const hex_tab = hexcase ? '0123456789ABCDEF' : '0123456789abcdef'; + let str = ''; + for (let i = 0; i < binarray.length * 4; i++) { + str += + hex_tab.charAt((binarray[i >> 2] >> ((i % 4) * 8 + 4)) & 0xf) + + hex_tab.charAt((binarray[i >> 2] >> ((i % 4) * 8)) & 0xf); + } + return str; +} + +/* + * Convert an array of little-endian words to a base-64 string + */ +function binl2b64(binarray: number[]) { + const tab = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'; + let str = ''; + for (let i = 0; i < binarray.length * 4; i += 3) { + const triplet = + (((binarray[i >> 2] >> (8 * (i % 4))) & 0xff) << 16) | + (((binarray[(i + 1) >> 2] >> (8 * ((i + 1) % 4))) & 0xff) << 8) | + ((binarray[(i + 2) >> 2] >> (8 * ((i + 2) % 4))) & 0xff); + for (let j = 0; j < 4; j++) { + if (i * 8 + j * 6 > binarray.length * 32) str += b64pad; + else str += tab.charAt((triplet >> (6 * (3 - j))) & 0x3f); + } + } + return str; +} diff --git a/packages/mobile-ui-vue/components/hook/use-mount-component/index.ts b/packages/mobile-ui-vue/components/hook/use-mount-component/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..34b274715cddf99f8d12278a2c72e56dee4520b6 --- /dev/null +++ b/packages/mobile-ui-vue/components/hook/use-mount-component/index.ts @@ -0,0 +1,55 @@ +import { useExpose } from "../use-expose"; +import { Component, createApp, nextTick, reactive, App } from "vue"; + +export function usePopupState() { + const state = reactive({ + show: false, + }); + + const toggle = (show: boolean) => { + state.show = show; + }; + + const open = (props: Record) => { + Object.assign(state, props); + + nextTick(() => { + toggle(true); + }); + }; + + const close = () => { + toggle(false); + }; + + useExpose({ open, close, toggle }); + + return { + open, + close, + state, + toggle, + }; +} + +export function mountComponent(RootComponent: Component, props?: Record, enhanceApp?: (app: App) => void) { + const app = createApp(RootComponent, props); + if (enhanceApp && typeof enhanceApp === "function") { + try { + enhanceApp(app); + } catch (err) { + console.error(`[mountComponent] Error occurred during enhanceApp`, err); + } + } + const root = document.createElement('div'); + + document.body.appendChild(root); + + return { + instance: app.mount(root), + unmount() { + app.unmount(); + document.body.removeChild(root); + }, + }; +} diff --git a/packages/mobile-ui-vue/components/hook/use-props/index.ts b/packages/mobile-ui-vue/components/hook/use-props/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..d130c811f66f7e2112ef0bda5ec0bb9f3260bad8 --- /dev/null +++ b/packages/mobile-ui-vue/components/hook/use-props/index.ts @@ -0,0 +1,19 @@ +import { inject, provide } from "vue"; + +export const useRootProps = (key: string | symbol, props?: Record)=> { + const setProps = (value: Record)=>{ + provide(key,value); + }; + const getProps = (defaultValue: Record = {}): Record=>{ + return inject(key, defaultValue); + }; + if(props) { + setProps(props); + } + const rootProps = props || getProps(); + return { + rootProps, + setProps, + getProps + }; +}; diff --git a/packages/mobile-ui-vue/components/hook/use-queue/index.ts b/packages/mobile-ui-vue/components/hook/use-queue/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..c97d319ec765062a637a8674ab62c9c5db9d044e --- /dev/null +++ b/packages/mobile-ui-vue/components/hook/use-queue/index.ts @@ -0,0 +1,22 @@ +export const useQueue = (options: any) => { + const { queueStartCb, queueEndCb } = options; + const queue = new Map(); + const taskStart = (key: any) => { + queue.set(key, null); + queueStartCb(); + }; + const taskEnd = (key: any) => { + queue.delete(key); + if (queue.size === 0) { + queueEndCb(); + } + }; + const taskClear = () => { + queue.clear(); + }; + return { + taskStart, + taskEnd, + taskClear + }; +}; diff --git a/packages/mobile-ui-vue/components/hook/use-state/index.ts b/packages/mobile-ui-vue/components/hook/use-state/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..8726ea775185ef4762c3408446b5f1085c0e8d8c --- /dev/null +++ b/packages/mobile-ui-vue/components/hook/use-state/index.ts @@ -0,0 +1,14 @@ +import { reactive, provide, inject } from 'vue'; + +export const stateSymbol = Symbol('state'); +export const createState = (initState: Record) => reactive(initState); + +export const useState: (arg: string | symbol) => T = (key?: string | symbol) => inject(key || stateSymbol, { a: 1 }); +export const provideState = (key?: string | symbol, initState: Record = {}) => { + const state = createState(initState); + provide( + key || stateSymbol, + initState + ); + return state; +}; diff --git a/packages/mobile-ui-vue/components/hook/use-touch-move/index.ts b/packages/mobile-ui-vue/components/hook/use-touch-move/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..d79873a031e550736d0d7781aaa85c3bff93955e --- /dev/null +++ b/packages/mobile-ui-vue/components/hook/use-touch-move/index.ts @@ -0,0 +1,117 @@ +import { throttle } from '../../utils'; +import { reactive, ref, Ref } from 'vue'; +import { useEventListener } from '../use-event-listener'; + +const MIN_DISTANCE = 10; + +type TouchDirection = 'horizontal' | 'vertical' | ''; + +export type TouchOffset = { + startX: number; + startY: number; + endX: number; + endY: number; + offsetX: number; + offsetY: number; + direction: TouchDirection; +}; + +type TouchListener = { + onTouchStart?: (event: Event) => void; + onTouchMove?: (event: Event) => void; + onTouchEnd?: (event: Event) => void; + onTouchCancel?: (event: Event) => void; +}; + +function getDirection(x: number, y: number): TouchDirection { + if (x > y && x > MIN_DISTANCE) { + return 'horizontal'; + } + + if (y > x && y > MIN_DISTANCE) { + return 'vertical'; + } + return ''; +} + +const defaultTouchOffset: () => TouchOffset = () => { + return { + startX: 0, + startY: 0, + endX: 0, + endY: 0, + offsetX: 0, + offsetY: 0, + direction: '', + }; +}; + +export enum DragStatus { + NotStarted, + Started, + Dragging, + End, +} + +export function useTouchMove( + target: Ref, + listener?: TouchListener, + wait = 0 +) { + let beginOffset = { offsetX: 0, offsetY: 0 }; + const offset: TouchOffset = reactive(defaultTouchOffset()); + const dragStatus = ref(DragStatus.NotStarted); + + const touchStart = (event: any) => { + if (!event.touches || !event.touches[0]) { + return; + } + offset.startX = event.touches[0].clientX; + offset.startY = event.touches[0].clientY; + listener?.onTouchStart && listener.onTouchStart(event); + dragStatus.value = DragStatus.Started; + }; + + const touchMove = (event: any) => { + if (!event.touches || !event.touches[0]) { + return; + } + const touch = event.touches[0]; + offset.offsetX = touch.clientX - offset.startX + beginOffset.offsetX; + offset.offsetY = touch.clientY - offset.startY + beginOffset.offsetY; + offset.endX = event.touches[0].clientX; + offset.endY = event.touches[0].clientY; + offset.direction = getDirection(offset.offsetX, offset.offsetY); + listener?.onTouchMove && listener.onTouchMove(event); + dragStatus.value = DragStatus.Dragging; + }; + + const touchEnd = (event: Event) => { + beginOffset = { offsetX: offset.offsetX, offsetY: offset.offsetY }; + listener?.onTouchEnd && listener.onTouchEnd(event); + listener?.onTouchCancel && listener.onTouchCancel(event); + dragStatus.value = DragStatus.End; + }; + + const resetTouchStatus = () => { + offset.endX = 0; + offset.endY = 0; + offset.offsetX = 0; + offset.offsetY = 0; + offset.direction = ''; + beginOffset = { offsetX: 0, offsetY: 0 }; + dragStatus.value = DragStatus.NotStarted; + }; + + if (target) { + useEventListener('touchstart', touchStart, { target }); + useEventListener('touchmove', wait > 0 ? throttle(touchMove, wait) : touchMove, { target, passive: false }); + useEventListener('touchend', touchEnd, { target }); + } + + return { + offset, + dragStatus, + resetTouchStatus, + }; +} diff --git a/packages/mobile-ui-vue/components/hook/use-touch/index.ts b/packages/mobile-ui-vue/components/hook/use-touch/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..824161b9563c9874514efd4439d396177944a291 --- /dev/null +++ b/packages/mobile-ui-vue/components/hook/use-touch/index.ts @@ -0,0 +1,69 @@ +import { ref } from 'vue'; + +const MIN_DISTANCE = 10; + +type Direction = '' | 'vertical' | 'horizontal'; + +function getDirection(x: number, y: number) { + if (x > y && x > MIN_DISTANCE) { + return 'horizontal'; + } + if (y > x && y > MIN_DISTANCE) { + return 'vertical'; + } + return ''; +} + +export function useTouch() { + const startX = ref(0); + const startY = ref(0); + const deltaX = ref(0); + const deltaY = ref(0); + const offsetX = ref(0); + const offsetY = ref(0); + const direction = ref(''); + + const isVertical = () => direction.value === 'vertical'; + const isHorizontal = () => direction.value === 'horizontal'; + + const reset = () => { + deltaX.value = 0; + deltaY.value = 0; + offsetX.value = 0; + offsetY.value = 0; + direction.value = ''; + }; + + const start = ((event: TouchEvent) => { + reset(); + startX.value = event.touches[0].clientX; + startY.value = event.touches[0].clientY; + }) as EventListener; + + const move = ((event: TouchEvent) => { + const touch = event.touches[0]; + deltaX.value = touch.clientX - startX.value; + deltaY.value = touch.clientY - startY.value; + offsetX.value = Math.abs(deltaX.value); + offsetY.value = Math.abs(deltaY.value); + + if (!direction.value) { + direction.value = getDirection(offsetX.value, offsetY.value); + } + }) as EventListener; + + return { + move, + start, + reset, + startX, + startY, + deltaX, + deltaY, + offsetX, + offsetY, + direction, + isVertical, + isHorizontal, + }; +} diff --git a/packages/mobile-ui-vue/components/icon/index.ts b/packages/mobile-ui-vue/components/icon/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..d4b3b1987ff399bd8c47623d616582ac460ac2e3 --- /dev/null +++ b/packages/mobile-ui-vue/components/icon/index.ts @@ -0,0 +1,9 @@ +import type { App } from 'vue'; +import Icon from './src/index.vue'; + +Icon.install = (app: App) => { + app.component(Icon.name || 'FmIcon', Icon); +}; + +export { Icon }; +export default Icon; diff --git a/packages/mobile-ui-vue/components/icon/src/index.vue b/packages/mobile-ui-vue/components/icon/src/index.vue new file mode 100644 index 0000000000000000000000000000000000000000..3f22c75cfd70ee27f404e484c0ec0d30822db57b --- /dev/null +++ b/packages/mobile-ui-vue/components/icon/src/index.vue @@ -0,0 +1,45 @@ + + + + + diff --git a/packages/mobile-ui-vue/components/image/index.ts b/packages/mobile-ui-vue/components/image/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..901cc7b19fd857dc1fb3e604e6733a2a339c94b4 --- /dev/null +++ b/packages/mobile-ui-vue/components/image/index.ts @@ -0,0 +1,9 @@ +import { App } from 'vue'; +import Image from './src/index.vue'; + +Image.install = (app: App) => { + app.component(Image.name || 'FmImage', Image); +}; + +export { Image }; +export default Image; diff --git a/packages/mobile-ui-vue/components/image/src/index.html b/packages/mobile-ui-vue/components/image/src/index.html new file mode 100644 index 0000000000000000000000000000000000000000..3fae970df4065f06c8eeff798501dfbbc2786841 --- /dev/null +++ b/packages/mobile-ui-vue/components/image/src/index.html @@ -0,0 +1,24 @@ +
+ +
+ + + +
+
+ + + +
+
diff --git a/packages/mobile-ui-vue/components/image/src/index.vue b/packages/mobile-ui-vue/components/image/src/index.vue new file mode 100644 index 0000000000000000000000000000000000000000..06e635d771eca8897c4766294f80cc533476f62c --- /dev/null +++ b/packages/mobile-ui-vue/components/image/src/index.vue @@ -0,0 +1,89 @@ + + + diff --git a/packages/mobile-ui-vue/components/index.ts b/packages/mobile-ui-vue/components/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..a23272632f544bc8a6e4f671e56de770280396a2 --- /dev/null +++ b/packages/mobile-ui-vue/components/index.ts @@ -0,0 +1,48 @@ +/** + * Copyright (c) 2020 - present, Inspur Genersoft Co., Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { App } from 'vue'; + +import Scroll from './scroll'; +import Navbar from './navbar'; +import Overlay from './overlay'; +import Popup from './popup'; +import ActionSheet from './action-sheet'; +import Icon from './icon'; +import Image from './image'; +import Cell from './cell'; +import Button from './button'; +import AdvUploader from './adv-uploader'; +import ListView from './listview'; +import Locale from './locale'; +import { Checker } from "./checkbox"; + +const Components = [Scroll, Navbar, Overlay, Popup, ActionSheet, Icon, Image, Cell, Button, AdvUploader, Locale, ListView, Checker]; + +const install = (app: App): void => { + Components.forEach((component: any) => { + if (component.install) { + app.use(component); + } else { + app.component(component.name, component); + } + }); +}; + +export { Scroll, Navbar, Overlay, Popup, ActionSheet, Icon, Image, Cell, Button, AdvUploader, Locale, ListView , Checker}; + +export default { + install +}; diff --git a/packages/mobile-ui-vue/components/listview/README.md b/packages/mobile-ui-vue/components/listview/README.md new file mode 100644 index 0000000000000000000000000000000000000000..d36ee8d0f0eb1aac6a1108decffbdec8655599b7 --- /dev/null +++ b/packages/mobile-ui-vue/components/listview/README.md @@ -0,0 +1,112 @@ +# fm-listview 列表 + +### 介绍 + +瀑布流滚动加载,用于展示长列表,当列表即将滚动到底部时,会触发事件并加载更多列表项。 + +### 基础用法 + +List 组件通过`loading`和`finished`两个变量控制加载状态,当组件滚动到底部时,会触发`load`事件并将`loading`设置成`true`。此时可以发起异步操作并更新数据,数据更新完毕后,将`loading`设置成`false`即可。若数据已全部加载完毕,则直接将`finished`设置成`true`即可。 + +## API + +### Props + +| 参数 | 说明 | 类型 | 默认值 | +| --- | --- | --- | --- | +| list-data | 列表数据 | Array | - +| multiple | 是否支持多选 | boolean | `false`| +| loading | 是否处于加载状态,加载过程中不触发`load`事件,支持`v-model` | boolean | `false` | +| finished | 是否已加载完成,加载完成后不再触发`load`事件 | boolean | `false` | +| error | 是否加载失败,加载失败后点击错误提示可以重新
触发`load`事件,必须使用`sync`修饰符,支持`v-model` | boolean | `false` | +| offset | 滚动条与底部距离小于 offset 时触发`load`事件 | number | `30` | +| loadingText | 加载过程中的提示文案 | string | `加载中...` | +| finishedText | 加载完成后的提示文案 | string | `没有更多了` | +| errorText | 加载失败后的提示文案 | string | `加载错误,请重试...` | +| immediateCheck | 是否在初始化时立即执行滚动位置检查 | boolean | `true` | +| direction | 滚动触发加载的方向,可选值为`up` | string | `down` | +| btns | 多选操作按钮组 | Array\ | `[]`| +| initMultiSelect | 初始化多选 | boolean | `false` | +| fill | 是否填充模式 | boolean | `false` | +| enablePullRefresh | 是否开启上拉加载下页 | boolean | `false` | +| idField | 判定是否选中得标识 | string | `id` | +| textField | 开启子级列表得菜单文本 | string | `-` | +| childField | 子级列表得标识字段 | string | `-` | + +#### ListviewBtnOptions Props + +| 属性 | 说明 | 类型 | 默认值 | +| ---| ----- | ------ | ------ | +| text | 按钮文案 | string | - | +| handler | 点击回调 | function() | - | +| plain | 是否为线框按钮 | boolean | `false` | +| disabled | 禁用按钮 | boolean | `false` | + +### Events + +| 事件名 | 说明 | 回调参数 | +| ------ | ---------------------------------- | -------- | +| load | 滚动条与底部距离小于 offset 时触发 | - | +| itemClick | 行点击触发 | `{data:当前行数据,index:当前行索引值}` | +| selectChange | 选中事件 | `{data:当前行数据,index:当前行索引值}` | +| refresh | 下拉刷新事件 | `-` | + +### 方法 + +通过 ref 可以获取到 List 实例并调用实例方法 + +| 方法名 | 说明 | 参数 | 返回值 | +| --- | --- | --- | --- | +| check | 检查当前的滚动位置,若已滚动至底部,则会触发 load 事件 | - | - | +| listCheckStart | 列表多选 | - | -| +| listCheckCancel | 取消多选 | - | - | +| listCheckAll | 列表全选| - | - | +| listCheckAllCancel | 取消全选 | - | - | +| getCheckeds | 获取选中值 | - | Array\ | + +### Slots + +| 名称 | 说明 | +| -------- | -------------------------- | +| default | 列表内容 | +| loading | 自定义底部加载中提示 | +| finished | 自定义加载完成后的提示文案 | +| error | 自定义加载失败后的提示文案 | + +## 常见问题 + +### List 的运行机制是什么? + +List 会监听浏览器的滚动事件并计算列表的位置,当列表底部与可视区域的距离小于`offset`时,List 会触发一次 load 事件。 + +### 为什么 List 初始化后会立即触发 load 事件? + +List 初始化后会触发一次 load 事件,用于加载第一屏的数据,这个特性可以通过`immediate-check`属性关闭。 + +### 为什么会连续触发 load 事件? + +如果一次请求加载的数据条数较少,导致列表内容无法铺满当前屏幕,List 会继续触发 load 事件,直到内容铺满屏幕或数据全部加载完成。因此你需要调整每次获取的数据条数,理想情况下每次请求获取的数据条数应能够填满一屏高度。 + +### loading 和 finished 分别是什么含义? + +`List`有以下三种状态,理解这些状态有助于你正确地使用`List`组件: + +- 非加载中,`loading`为`false`,此时会根据列表滚动位置判断是否触发`load`事件(列表内容不足一屏幕时,会直接触发) +- 加载中,`loading`为`true`,表示正在发送异步请求,此时不会触发`load`事件 +- 加载完成,`finished`为`true`,此时不会触发`load`事件 + +在每次请求完毕后,需要手动将`loading`设置为`false`,表示加载结束 + + +### 在 html、body 上设置 overflow 后一直触发加载? + +如果在 html 和 body 标签上设置了`overflow-x: hidden`样式,会导致 List 一直触发加载。 + +```css +html, +body { + overflow-x: hidden; +} +``` + +这个问题的原因是当元素设置了`overflow-x: hidden`样式时,该元素的`overflow-y`会被浏览器设置为`auto`,而不是默认值`visible`,导致 List 无法正确地判断滚动容器。解决方法是去除该样式,或者在 html 和 body 标签上添加`height: 100%`样式。 diff --git a/packages/mobile-ui-vue/components/listview/index.ts b/packages/mobile-ui-vue/components/listview/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..5978dc7e5f35cbc8055a6d380f2d7aeab43db2df --- /dev/null +++ b/packages/mobile-ui-vue/components/listview/index.ts @@ -0,0 +1,9 @@ +import { App } from 'vue'; +import Listview from './src/listview'; + +Listview.install = function (app: App) { + app.component(Listview.name || 'FmListview', Listview); +}; + +export { Listview }; +export default Listview; diff --git a/packages/mobile-ui-vue/components/listview/src/listview-container.vue b/packages/mobile-ui-vue/components/listview/src/listview-container.vue new file mode 100644 index 0000000000000000000000000000000000000000..d2b509191bdafd68a275c80e876e93b5156cf4e1 --- /dev/null +++ b/packages/mobile-ui-vue/components/listview/src/listview-container.vue @@ -0,0 +1,134 @@ + + + diff --git a/packages/mobile-ui-vue/components/listview/src/listview-list.vue b/packages/mobile-ui-vue/components/listview/src/listview-list.vue new file mode 100644 index 0000000000000000000000000000000000000000..dcc5302b896ecc52fc3c1a777703d9d3b2d19ecd --- /dev/null +++ b/packages/mobile-ui-vue/components/listview/src/listview-list.vue @@ -0,0 +1,120 @@ + + + diff --git a/packages/mobile-ui-vue/components/listview/src/listview-props.ts b/packages/mobile-ui-vue/components/listview/src/listview-props.ts new file mode 100644 index 0000000000000000000000000000000000000000..26443446ef8d80165df340340e19453c5d8c47c4 --- /dev/null +++ b/packages/mobile-ui-vue/components/listview/src/listview-props.ts @@ -0,0 +1,89 @@ +import { PropType } from 'vue'; +import { Direction, ListViewToolbarItem } from './listview-types'; + +export const listViewProps = { + listData: { + type: Array as PropType[]>, + default() { + return []; + } + }, + error: { + type: Boolean, + default: false + }, + finished: { + type: Boolean, + default: false + }, + loading: { + type: Boolean, + default: false + }, + errorText: String, + loadingText: { + type: String, + default: '' + }, + finishedText: String, + showFinishedText: { + type: Boolean, + default: false + }, + immediateCheck: { + type: Boolean, + default: true + }, + offset: { + type: Number, + default: 30 + }, + direction: { + type: String as PropType, + default: 'down' + }, + multiple: { + type: Boolean, + default: false + }, + btns: { + type: Array as PropType, + default() { + return []; + } + }, + showSubmitBtn: { + type: Boolean, + default: true + }, + className: { + type: String + }, + idField: { + type: String, + default: 'id' + }, + fill: { + type: Boolean, + default: false + }, + initMultiSelect: { + type: Boolean, + default: false + }, + enablePullRefresh: { + type: Boolean, + default: false + }, + listRefreshing: { + type: Boolean, + default: false + }, + childField: { + type: String + }, + textField: { + type: String + }, + selecteds: Object as PropType +}; diff --git a/packages/mobile-ui-vue/components/listview/src/listview-types.ts b/packages/mobile-ui-vue/components/listview/src/listview-types.ts new file mode 100644 index 0000000000000000000000000000000000000000..39cbd936f745b23cd2bfdd3882d4a44cc23d9394 --- /dev/null +++ b/packages/mobile-ui-vue/components/listview/src/listview-types.ts @@ -0,0 +1,48 @@ +import { ComputedRef, Ref } from 'vue'; + +export type Direction = 'up' | 'down'; + +export type ListViewContainerProps = { + finished: boolean; + loading: boolean; + error: boolean; + listRefreshing: boolean; + direction: Direction; + contentClass?: string; + errorText: string; + finishedText: string; + loadingText: string; + showFinishedText: boolean; +}; + +export type LsitViewItemProps = { + multiple: boolean; + initMultiSelect: boolean; + textField?: string; + idField: string; +}; + +export type ListViewState = { + listData: Ref[]>; + notEmptyListData: ComputedRef; + selecteds: Ref[]>; + isSelected: (item: Record) => boolean; + toggleSelected: (item: Record) => void; + clearSelecteds: () => void; + selectedAll: () => void; + selecte: (id: string) => void; +}; + +export type ListViewToolbarItem = { + text: string; + type: string; + handler: (btn: ListViewToolbarItem, value: any) => void; + disabled: boolean; + visible: boolean; + plain: boolean; +}; + +export type ScrollerPosition = { + scrollLeft: number; + scrollTop: number; +}; diff --git a/packages/mobile-ui-vue/components/listview/src/listview.tsx b/packages/mobile-ui-vue/components/listview/src/listview.tsx new file mode 100644 index 0000000000000000000000000000000000000000..6243c6d1cd775d7b03eb5b102a511b995830307d --- /dev/null +++ b/packages/mobile-ui-vue/components/listview/src/listview.tsx @@ -0,0 +1,73 @@ +import { useExpose } from '@/hook'; +import { defineComponent, ref } from 'vue'; +import { listViewProps } from './listview-props'; +import ListView from './listview.vue'; +import { ScrollerPosition } from './listview-types'; + +export default defineComponent({ + name: 'FmListview', + components: { + listview: ListView + }, + inheritAttrs: false, + props: listViewProps, + emits: ['refresh', 'load', 'itemClick', 'selectChange', 'update:loading', 'update:error'], + setup(props, { emit, attrs, slots }) { + const listviewRef = ref(); + const pullRefreshDisabled = ref(false); + + // get listviewRef 暴露的函数 + const getlistviewRefFC = (name: string) => { + return () => listviewRef.value && listviewRef.value[name](); + }; + const checkSubmit = () => { + listviewRef.value.checkCancel(); + return listviewRef.value.getCheckeds(); + }; + // 暴露内部函数 + useExpose({ + checkSubmit, + checkCancel: getlistviewRefFC('checkCancel'), + listCheckStart: getlistviewRefFC('checkStart'), + listCheckCancel: getlistviewRefFC('checkCancel'), + listCheckAll: getlistviewRefFC('checkAll'), + listCheckAllCancel: getlistviewRefFC('checkAllCancel'), + getCheckeds: getlistviewRefFC('getCheckeds'), + getSelectDataList: getlistviewRefFC('getCheckeds'), + check: getlistviewRefFC('check'), + setScrollerPosition: (position: ScrollerPosition) => listviewRef.value && listviewRef.value.setScrollerPosition(position), + getScrollerPosition: getlistviewRefFC('getScrollerPosition') + }); + + const { onRefresh, ...listviewAttrs } = attrs; + + const listviewProps = { + ...listviewAttrs, + onLoad: () => emit('load'), + onItemClick: (event: any) => emit('itemClick', event), + onSelectChange: (event: any) => emit('selectChange', event), + 'onUpdate:error': (value: boolean) => emit('update:error', value), + 'onUpdate:loading': (value: boolean) => emit('update:loading', value), + onScroll: (event: number) => { pullRefreshDisabled.value = !!event; } + }; + + const renderListView = () => { + return ; + }; + + const renderPullRrefresh = () => { + const className = props.fill ? 'fm-pull-refresh-wrapper fm-pull-refresh-fill' : 'fm-pull-refresh-wrapper'; + return ( + emit('refresh')} + loading-text=" "> + {renderListView()} + + ); + }; + return props.enablePullRefresh ? renderPullRrefresh : renderListView; + } +}); diff --git a/packages/mobile-ui-vue/components/listview/src/listview.vue b/packages/mobile-ui-vue/components/listview/src/listview.vue new file mode 100644 index 0000000000000000000000000000000000000000..449e6665225d8c55980930c1b2034dd3d3a6a149 --- /dev/null +++ b/packages/mobile-ui-vue/components/listview/src/listview.vue @@ -0,0 +1,172 @@ + + + diff --git a/packages/mobile-ui-vue/components/listview/src/use-data.ts b/packages/mobile-ui-vue/components/listview/src/use-data.ts new file mode 100644 index 0000000000000000000000000000000000000000..f275c29fae54e43be6c66e710e4cd456b2173bca --- /dev/null +++ b/packages/mobile-ui-vue/components/listview/src/use-data.ts @@ -0,0 +1,56 @@ +import { provideState } from '@/hook'; +import { getValue, notEmptyArray } from '@/utils'; +import { computed, ref, Ref } from 'vue'; +import { ListViewState } from './listview-types'; + +export const ListViewToken = Symbol('list-view'); +export const useData = (listData: Ref[]>, idField = 'id') => { + const selecteds = ref[]>([]); + + const isSelected = (item: Record) => { + return !!selecteds.value.find((selected) => { + return getValue(idField, selected) && getValue(idField, selected) === getValue(idField, item); + }); + }; + + const toggleSelected = (item: Record) => { + if (isSelected(item)) { + selecteds.value = selecteds.value.filter((selected) => getValue(idField, selected) !== getValue(idField, item)); + } else { + selecteds.value.push(item); + } + }; + + const selectedAll = () => { + selecteds.value = listData.value; + }; + + const selecte = (id: string) => { + const target = listData.value.find((item) => getValue(idField, item) === id); + if (target) { + selecteds.value.push(target); + } + }; + + const clearSelecteds = () => { + selecteds.value = []; + }; + + const notEmptyListData = computed(() => { + return notEmptyArray(listData.value); + }); + + const state: ListViewState = { + listData, + notEmptyListData, + selecteds, + isSelected, + toggleSelected, + clearSelecteds, + selecte, + selectedAll + }; + provideState(ListViewToken, state); + + return state; +}; diff --git a/packages/mobile-ui-vue/components/listview/src/use-scroll-check.ts b/packages/mobile-ui-vue/components/listview/src/use-scroll-check.ts new file mode 100644 index 0000000000000000000000000000000000000000..dbddd7240204f6392bb5287ba2644e04c71555b4 --- /dev/null +++ b/packages/mobile-ui-vue/components/listview/src/use-scroll-check.ts @@ -0,0 +1,77 @@ +import { useEventListener } from '@/hook'; +import { getScroller, throttle } from '@/utils'; +import { nextTick, onMounted, Ref, ref } from 'vue'; +import { Direction, ScrollerPosition } from './listview-types'; + +export const useScrollCheck = ( + options: { + containerRef: Ref; + placeholderRef: Ref; + direction?: Direction; + offset?: number; + }, + listener: () => void +) => { + const { containerRef, placeholderRef, direction = 'down', offset = 30 } = options; + let actived = true; + let scroller: Element | Window; + const isReachEdge = ref(false); + const scrollTop = ref(0); + console.log('useScrollCheck'); + + const check = () => { + nextTick(() => { + scrollTop.value = (scroller as Element).scrollTop; + + if (!actived || !placeholderRef.value) { + return; + } + + const scrollerRect = (scroller as Element).getBoundingClientRect + ? (scroller as Element).getBoundingClientRect() + : { top: 0, bottom: (scroller as Window).innerHeight }; + + // 在界面上隐藏,不需要处理 + if (scrollerRect.bottom === 0) { + return; + } + + const placeholderRect = placeholderRef.value?.getBoundingClientRect(); + + isReachEdge.value = + direction === 'up' ? scrollerRect.top - placeholderRect.top <= offset : placeholderRect.bottom - scrollerRect.bottom <= offset; + isReachEdge.value && listener(); + }); + }; + + onMounted(() => { + scroller = getScroller(containerRef.value); + useEventListener('scroll', throttle(check, 300), { + target: scroller, + immediate: true + }); + }); + + const setActived = (value: boolean) => { + actived = value; + }; + + const setScrollerPosition = (scrollerPosition: ScrollerPosition) => { + scrollerPosition?.scrollLeft && ((scroller as Element).scrollLeft = scrollerPosition.scrollLeft); + scrollerPosition?.scrollTop && ((scroller as Element).scrollTop = scrollerPosition.scrollTop); + }; + + const getScrollerPosition = (): ScrollerPosition => { + const { scrollLeft = 0, scrollTop = 0 } = scroller ? (scroller as Element) : {}; + return { scrollLeft, scrollTop }; + }; + + return { + isReachEdge, + scrollTop, + check, + setActived, + setScrollerPosition, + getScrollerPosition + }; +}; diff --git a/packages/mobile-ui-vue/components/listview/src/use-touch-hold.ts b/packages/mobile-ui-vue/components/listview/src/use-touch-hold.ts new file mode 100644 index 0000000000000000000000000000000000000000..ae50f26c5a7a1635e600032f0696c5ae22bfe9b0 --- /dev/null +++ b/packages/mobile-ui-vue/components/listview/src/use-touch-hold.ts @@ -0,0 +1,27 @@ +import { useEventListener } from '@/hook'; +import { throttle } from '@/utils'; +import { Ref } from 'vue'; + +export function useTouchHold(target: Element | Ref, listener: () => void, wait = 200) { + let timer = 0; + const onTouchStart = () => { + timer = window.setTimeout(() => { + listener(); + }, 700); + return false; + }; + const onTouchMove = () => { + clearTimeout(timer); + timer = 0; + }; + const onTouchEnd = () => { + clearTimeout(timer); + }; + if (target) { + useEventListener('touchstart', onTouchStart, { target }); + useEventListener('touchmove', throttle(onTouchMove, wait), { + target + }); + useEventListener('touchend', onTouchEnd, { target }); + } +} diff --git a/packages/mobile-ui-vue/components/locale/index.ts b/packages/mobile-ui-vue/components/locale/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..d6c08a50f8a8d95342420a1cd15a719e4d15c2cc --- /dev/null +++ b/packages/mobile-ui-vue/components/locale/index.ts @@ -0,0 +1,58 @@ +import { ref, reactive, App } from 'vue'; +import zhCHS from './lang/zh-CHS'; +import zhCHT from './lang/zh-CHT'; +import en from './lang/en'; +import { deepAssign, isFunction } from '../utils'; + +type Message = Record; +type Messages = Record; + +const lang = ref('zh-CHS'); +const messages = reactive({ + 'zh-CHS': zhCHS, + 'zh-CHT': zhCHT, + en +}); + +export const Locale = { + messages(): Message { + return messages[lang.value] ? messages[lang.value] : messages['zh-CHS']; + }, + message(key: string): Message { + return this.messages()[key]; + }, + use(newLang: string, newMessages?: Message) { + lang.value = newLang; + this.add({ [newLang]: newMessages }); + }, + + add(newMessages: Message = {}) { + deepAssign(messages, newMessages); + }, + getCurrentLang() { + return lang; + }, + createTranslate(name: string) { + return (path: string, ...args: any[]) => { + const messages = this.messages(); + const message = messages[name] ? messages[name] : messages.common; + const text = isFunction(message[path]) ? message[path](...args) : message[path]; + if (!text) { + const commonMessage = messages.common; + return isFunction(commonMessage) ? message(path, args) : commonMessage[path]; + } + return text; + }; + }, + install(app: App) { + app.config.globalProperties.$t = (name: string, path: string, ...args: any[]) => this.createTranslate(name)(path, ...args); + } +}; + +declare module '@vue/runtime-core' { + interface ComponentCustomProperties { + $t: (name: string, path: string, ...args: any[]) => string; + } +} + +export default Locale; diff --git a/packages/mobile-ui-vue/components/locale/lang/en/index.ts b/packages/mobile-ui-vue/components/locale/lang/en/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..a2d95b61c3f7ba76938b0ad681ff364d89ed2590 --- /dev/null +++ b/packages/mobile-ui-vue/components/locale/lang/en/index.ts @@ -0,0 +1,156 @@ +/* eslint-disable max-len */ +export default { + common: { + cancelText: 'Cancel', + confirmText: 'Confirm', + continueText: 'Continue', + loaddingText: 'Loadding', + selecteText: 'Click to select', + selectedText: 'Selected', + emptyText: 'No data available', + moreText: 'More', + etcText: 'etc.', + sendText: "Send", + resetText: "Reset", + }, + advUploader: { + uploading: 'Uploading', + failed: 'Failed', + waiting: 'Waiting', + unnamedFile: 'Unnamed file', + }, + calendar: { + todayText: 'Today', + yearText: 'Year', + monthText: 'Month', + dayLabelsText: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'], + monthLabelsText: ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'], + defaultTitle: (year: number, month: number) => { + const monthTextArr = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December']; + return `${monthTextArr[month - 1]} ${year}`; + }, + }, + collapse: { + expandText: 'Expand', + collapseText: 'Collapse', + }, + datetimePicker: { + placeholder: 'Click to choose date', + }, + filter: { + placeholder: 'Search', + startText: (value: string) => `From ${value}`, + endText: (value: string) => `To ${value}`, + start2EndText: (start: string, end: string) => `${start} to ${end}`, + }, + input: { + placeholder: { + number: 'Please enter the number', + text: 'Please enter the text', + common: 'Please enter', + }, + }, + listview: { + errorText: 'Request failed, click to reload', + finishedText: 'No more' + }, + search: { + placeholder: "Enter keywords", + }, + lookupPanel: { + placeholder: 'Search', + navTitle: 'Unnamed', + breadcrumbRootText: 'All', + recentText: 'Recent', + favoriteText: 'Favorites', + clearText: 'Clear', + SelectAllText: 'All', + clearAllText: 'Cancel All', + emptyText: 'No Data', + httpError: 'Unexcepted return value', + httpResponseError: (name: string) => `Data service not found ${name}`, + selectedAppendText: (_count: number) => `etc.`, + selectedLimitText: (selectedLimit: number) => `No more than ${selectedLimit} items can be selected`, + totalNumberOfPeople: (count: number) => `${count} people`, + }, + upload: { + title: 'Attachment', + unnamedFile: 'Unnamed file', + previewTitle: 'Preview attachment', + previewActName: 'Online preview', + deleteActName: 'Delete', + downloadActName: 'Download', + noFileSelectionMethod: 'File selection method is not defined.', + cannotPreview: 'The file cannot be previewed online', + separator: ', ', + warning: 'Warning', + fileOversizeTip: ( + sizeLimit: string, + amount: number, + invalidNames: string + ) => + `The size of each file is limited to ${sizeLimit}. ${amount} files exceed the limit and cannot be uploaded (${invalidNames}). Do you want to continue uploading other files?`, + allFileOversizeTip: (sizeLimit: string) => + `The size limit for a single file is ${sizeLimit}. The selected files are all larger than the limit and cannot be uploaded. Please select again.`, + }, + attach: { + defaultTitle: "Attachment", + onlinePreview: "Online preview", + downloadOnlyTip: "The current file does not support preview, please download!", + download: "Download", + delete: "Delete", + preview: "Preview", + selectFromAlbum: "Select from Album", + takePhoto: "Take photo", + takeShortVideo: "Take short video", + selectFile: "Select from local files", + uploadFailedTipTitle: "Upload failed", + uploadFailedTip: "The file is too large. Please choose again!", + uploadingText: "Uploading attachment", + attachmentPreviewTitle: "Attachment Preview", + goToDownload: "Download", + }, + text: { + trueText: "True", + falseText: "False", + }, + discussionGroup: { + comments: "Comments", + reply: "Reply", + noComments: "No comments yet", + commentCountSuffix: " replies", + allReplies: "All replies", + colon: ": ", + writeComment: "Write comment", + defaultPlaceholder: "Leave a comment", + cannotBeEmptyTip: "Comment field cannot be empty", + replyTo: "Reply to ", + }, + filterPanel: { + validationFailedTip: "Validation failed", + fieldNotEmptyTip: (fieldName: string) => `${fieldName} cannot be empty`, + lastWeek: "Last week", + lastMonth: "Last month", + lastThreeMonths: "Last three months", + lastSixMonths: "Last six months", + datePickerTitle: "Select Date", + more: "More", + numberDefaultPlaceholder: "Please enter a number", + }, + pagination: { + defaultPrevText: "Previous page", + defaultNextText: "Next page", + }, + scheadule: { + title: (count: number) => `${count} Agenda Items`, + allDay: "All day", + beforeDawn: "Before dawn", + morning: "Morning", + afternoon: "Afternoon", + }, + tags: { + add: "Add", + placeholder: "Please enter", + }, + shareSheet: {}, +}; diff --git a/packages/mobile-ui-vue/components/locale/lang/zh-CHS/index.ts b/packages/mobile-ui-vue/components/locale/lang/zh-CHS/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..464e9ba6fe34fbcda468671ab8157703a7973cd2 --- /dev/null +++ b/packages/mobile-ui-vue/components/locale/lang/zh-CHS/index.ts @@ -0,0 +1,154 @@ +export default { + common: { + cancelText: '取消', + confirmText: '确定', + continueText: '继续', + loaddingText: '加载中', + selectedText: '已选择', + selecteText: '点击选择', + emptyText: '暂无数据', + moreText: '更多', + etcText: '等', + sendText: '发送', + resetText: "重置", + }, + advUploader: { + uploading: '上传中', + failed: '上传失败', + waiting: '准备上传', + unnamedFile: '未命名文件', + }, + calendar: { + todayText: '今', + yearText: '年', + monthText: '月', + dayLabelsText: ['一', '二', '三', '四', '五', '六', '日'], + monthLabelsText: ['一月', '二月', '三月', '四月', '五月', '六月', '七月', '八月', '九月', '十月', '十一月', '十二月'], + defaultTitle: (year: number, month: number) => { + return `${year}年${month}月`; + }, + }, + collapse: { + expandText: '展开', + collapseText: '收起', + }, + datetimePicker: { + placeholder: '点击选择日期', + }, + filter: { + placeholder: '搜索', + startText: (value: string) => `从${value}起`, + endText: (value: string) => `到${value}止`, + start2EndText: (start: string, end: string) => `${start} 至 ${end}`, + }, + input: { + placeholder: { + number: '请输入数字', + text: '请输入文本', + common: '请输入', + } + }, + listview: { + errorText: '请求失败,点击重新加载', + finishedText: '没有更多了' + }, + search: { + placeholder: '请输入搜索关键词', + }, + lookupPanel: { + placeholder: '搜索', + navTitle: '未命名', + breadcrumbRootText: '全部', + recentText: '最近联系人', + favoriteText: '我的收藏', + clearText: '清空选择', + SelectAllText: '全选', + clearAllText: '取消全选', + emptyText: '暂无数据', + httpError: 'Http服务返回值异常', + httpResponseError: (name: string) => `Http服务缺少${name}方法`, + selectedAppendText: (count: number) => `等${count}个`, + selectedLimitText: (selectedLimit: number) => `最多选中${selectedLimit}条`, + totalNumberOfPeople: (count: number) => `${count}人`, + }, + upload: { + title: '附件', + unnamedFile: '未命名文件', + previewTitle: '附件预览', + previewActName: '在线预览', + deleteActName: '删除', + downloadActName: '下载', + noFileSelectionMethod: '文件选择方式未定义', + cannotPreview: '不支持在线预览该文件', + separator: '、', + warning: '警告', + fileOversizeTip: ( + sizeLimit: string, + amount: number, + invalidNames: string + ) => + `单个文件大小限制为${sizeLimit},有${amount}个文件的大小超过限制(${invalidNames}),无法上传,是否继续上传其它文件?`, + allFileOversizeTip: (sizeLimit: string) => + `单个文件大小限制为${sizeLimit},所选文件的大小都超过了限制,无法上传,请重新选择。`, + }, + attach: { + defaultTitle: "附件", + onlinePreview: "在线预览", + downloadOnlyTip: "当前文件不支持预览,请下载", + download: "下载", + delete: "删除", + preview: "预览", + selectFromAlbum: "从相册选择", + takePhoto: "相机", + takeShortVideo: "短视频", + selectFile: "手机文件", + uploadFailedTipTitle: "上传失败", + uploadFailedTip: "上传文件太大,请重新选择!", + uploadingText: "附件上传中", + attachmentPreviewTitle: "附件预览", + goToDownload: "去下载", + }, + text: { + trueText: "是", + falseText: "否", + }, + discussionGroup: { + comments: "评论", + reply: "回复", + noComments: "暂无评论", + commentCountSuffix: "条回复", + allReplies: "全部回复", + colon: ":", + writeComment: "写评论", + defaultPlaceholder: "评一下", + cannotBeEmptyTip: "评论区内容不能为空", + replyTo: "回复 ", + }, + filterPanel: { + validationFailedTip: "校验失败", + fieldNotEmptyTip: (fieldName: string) => `${fieldName}不允许为空`, + lastWeek: "近一周", + lastMonth: "近一月", + lastThreeMonths: "近三月", + lastSixMonths: "近半年", + datePickerTitle: "选择年月日", + more: "更多", + numberDefaultPlaceholder: "请输入数字", + }, + pagination: { + defaultPrevText: "上一页", + defaultNextText: "下一页", + }, + scheadule: { + title: (count: number) => `${count}项日程`, + allDay: "全天", + beforeDawn: "凌晨", + morning: "上午", + afternoon: "下午", + }, + tags: { + add: "添加", + placeholder: "请输入", + }, + shareSheet: {}, +}; diff --git a/packages/mobile-ui-vue/components/locale/lang/zh-CHT/index.ts b/packages/mobile-ui-vue/components/locale/lang/zh-CHT/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..74f21fa8476720130d5b2f238ac2fba7b53eb839 --- /dev/null +++ b/packages/mobile-ui-vue/components/locale/lang/zh-CHT/index.ts @@ -0,0 +1,154 @@ +export default { + common: { + cancelText: '取消', + confirmText: '確定', + continueText: '繼續', + loaddingText: '加載中', + selectedText: '已選擇', + selecteText: '點擊選擇', + emptyText: '暫無數據', + moreText: '更多', + etcText: '等', + sendText: '發送', + resetText: "重置", + }, + advUploader: { + uploading: '上傳中', + failed: '上傳失敗', + waiting: '准備上傳', + unnamedFile: '未命名文件', + }, + calendar: { + todayText: '今', + yearText: '年', + monthText: '月', + dayLabelsText: ['一', '二', '三', '四', '五', '六', '日'], + monthLabelsText: ['一月', '二月', '三月', '四月', '五月', '六月', '七月', '八月', '九月', '十月', '十一月', '十二月'], + defaultTitle: (year: number, month: number) => { + return `${year}年${month}月`; + }, + }, + collapse: { + expandText: '展開', + collapseText: '收起', + }, + datetimePicker: { + placeholder: '點擊選擇日期', + }, + filter: { + placeholder: '搜尋', + startText: (value: string) => `從${value}起`, + endText: (value: string) => `到${value}止`, + start2EndText: (start: string, end: string) => `${start} 至 ${end}`, + }, + input: { + placeholder: { + number: '請輸入數字', + text: '請輸入文本', + common: '請輸入', + } + }, + listview: { + errorText: '請求失敗,點擊重新加載', + finishedText: '沒有更多了' + }, + search: { + placeholder: "請輸入搜索關鍵詞", + }, + lookupPanel: { + placeholder: '搜索', + navTitle: '未命名', + breadcrumbRootText: '全部', + recentText: '最近聯繫人', + favoriteText: '我的收藏', + clearText: '清空選擇', + SelectAllText: '全選', + clearAllText: '取消全選', + emptyText: '暫無數據', + httpError: 'Http服務返回值異常', + httpResponseError: (name: string) => `Http服務缺少${name}方法`, + selectedAppendText: (count: number) => `等${count}個`, + selectedLimitText: (selectedLimit: number) => `最多選中${selectedLimit}條`, + totalNumberOfPeople: (count: number) => `${count}人`, + }, + upload: { + title: '附件', + unnamedFile: '未命名文件', + previewTitle: '附件預覽', + previewActName: '在線預覽', + deleteActName: '删除', + downloadActName: '下載', + noFileSelectionMethod: '文件選擇方式未定義', + cannotPreview: '不支持在線預覽該文件', + separator: '、', + warning: '警告', + fileOversizeTip: ( + sizeLimit: string, + amount: number, + invalidNames: string + ) => + `單個文件大小限制爲${sizeLimit},有${amount}個文件的大小超過限制(${invalidNames}),無法上傳,是否繼續上傳其它文件?`, + allFileOversizeTip: (sizeLimit: string) => + `單個文件大小限制爲${sizeLimit},所選文件的大小都超過了限制,無法上傳,請重新選擇。`, + }, + attach: { + defaultTitle: "附件", + onlinePreview: "在線預覽", + downloadOnlyTip: "當前文件不支持預覽,請下載", + download: "下載", + delete: "刪除", + preview: "預覽", + selectFromAlbum: "從相冊選擇", + takePhoto: "相機", + takeShortVideo: "短視頻", + selectFile: "手機文件", + uploadFailedTipTitle: "上傳失敗", + uploadFailedTip: "上傳文件太大,請重新選擇!", + uploadingText: "附件上傳中", + attachmentPreviewTitle: "附件預覽", + goToDownload: "去下載", + }, + text: { + trueText: "是", + falseText: "否", + }, + discussionGroup: { + comments: "評論", + reply: "回複", + noComments: "暫無評論", + commentCountSuffix: "條回複", + allReplies: "全部回複", + colon: ":", + writeComment: "寫評論", + defaultPlaceholder: "評一下", + cannotBeEmptyTip: "評論區內容不能爲空", + replyTo: "回複 ", + }, + filterPanel: { + validationFailedTip: "校驗失敗", + fieldNotEmptyTip: (fieldName: string) => `${fieldName}不允許爲空`, + lastWeek: "近一周", + lastMonth: "近一月", + lastThreeMonths: "近三月", + lastSixMonths: "近半年", + datePickerTitle: "選擇年月日", + more: "更多", + numberDefaultPlaceholder: "請輸入數字", + }, + pagination: { + defaultPrevText: "上一頁", + defaultNextText: "下一頁", + }, + scheadule: { + title: (count: number) => `${count}項日程`, + allDay: "全天", + beforeDawn: "淩晨", + morning: "上午", + afternoon: "下午", + }, + tags: { + add: "添加", + placeholder: "請輸入", + }, + shareSheet: {}, +}; diff --git a/packages/mobile-ui-vue/components/navbar/index.ts b/packages/mobile-ui-vue/components/navbar/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..01080a5016c95518f468bd3d640327326f66430b --- /dev/null +++ b/packages/mobile-ui-vue/components/navbar/index.ts @@ -0,0 +1,9 @@ +import type { App } from 'vue'; +import Navbar from './src/navbar.vue'; + +Navbar.install = function (app: App) { + app.component(Navbar.name || 'FmNavbar', Navbar); +}; + +export { Navbar }; +export default Navbar; diff --git a/packages/mobile-ui-vue/components/navbar/src/navbar.vue b/packages/mobile-ui-vue/components/navbar/src/navbar.vue new file mode 100644 index 0000000000000000000000000000000000000000..4d8309e042a1914a6188c0f4a1f1cc2e9f4db1f8 --- /dev/null +++ b/packages/mobile-ui-vue/components/navbar/src/navbar.vue @@ -0,0 +1,75 @@ + + + + diff --git a/packages/mobile-ui-vue/components/overlay/index.ts b/packages/mobile-ui-vue/components/overlay/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..fda22ac7c19d9c1b7c8f4fc61dbc4f9beff82366 --- /dev/null +++ b/packages/mobile-ui-vue/components/overlay/index.ts @@ -0,0 +1,9 @@ +import type { App } from 'vue'; +import Overlay from './src/index'; + +Overlay.install = function (app: App) { + app.component(Overlay.name || 'FmOverlay', Overlay); +}; + +export { Overlay }; +export default Overlay; diff --git a/packages/mobile-ui-vue/components/overlay/src/index.tsx b/packages/mobile-ui-vue/components/overlay/src/index.tsx new file mode 100644 index 0000000000000000000000000000000000000000..3183b4957f67fcb12eb95a821766ef35817a0324 --- /dev/null +++ b/packages/mobile-ui-vue/components/overlay/src/index.tsx @@ -0,0 +1,43 @@ +import { useLazyRender } from '../../hook'; +import { CSSProperties, defineComponent, PropType, Transition } from 'vue'; +import { preventDefault, noop } from '../../utils'; + +export default defineComponent({ + name: 'FmOverlay', + props: { + show: Boolean, + zIndex: [Number, String], + duration: [Number, String], + className: null, + customStyle: Object as PropType, + lockScroll: { + type: Boolean, + default: true, + }, + }, + setup(props, { slots }) { + const lazyRender = useLazyRender(() => props.show); + const preventTouchMove = (event: TouchEvent) => { + preventDefault(event, true); + }; + + const renderOverlay = lazyRender(() => { + const style: CSSProperties = { + zIndex: props.zIndex !== undefined ? +props.zIndex : undefined, + animationDuration: props.duration ? `${props.duration}s` : '', + ...props.customStyle, + }; + return ( +
+ {slots.default?.()} +
+ ); + }); + return () => {renderOverlay()}; + }, +}); diff --git a/packages/mobile-ui-vue/components/popup/index.ts b/packages/mobile-ui-vue/components/popup/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..452b525a44b8c89aaa7e3e95cb272cfc0b78c09a --- /dev/null +++ b/packages/mobile-ui-vue/components/popup/index.ts @@ -0,0 +1,9 @@ +import type { App } from 'vue'; +import Popup from './src/index'; + +Popup.install = function (app: App) { + app.component(Popup.name || 'FmPopup', Popup); +}; + +export { Popup }; +export default Popup; diff --git a/packages/mobile-ui-vue/components/popup/src/index.tsx b/packages/mobile-ui-vue/components/popup/src/index.tsx new file mode 100644 index 0000000000000000000000000000000000000000..fbbe8fb709f6b7644c64332ba0fc4193a540eefd --- /dev/null +++ b/packages/mobile-ui-vue/components/popup/src/index.tsx @@ -0,0 +1,171 @@ +import { useClickAway, useLockScroll } from '../../hook'; +import { + CSSProperties, + defineComponent, + Transition, + Teleport, + watch, + ref, +} from 'vue'; +import { Overlay } from '../../overlay'; + +export default defineComponent({ + name: 'FmPopup', + components: { + [Overlay.name]: Overlay, + }, + inheritAttrs: false, + props: { + show: Boolean, + // z-index + zIndex: [Number, String], + width: String, + height: String, + // transition duration + duration: [Number, String], + // teleport + teleport: null, + position: String, + overlay: { + type: Boolean, + default: true, + }, + closeOnClickOverlay: { + type: Boolean, + default: true, + }, + lockScroll: { + type: Boolean, + default: true, + }, + round: { + type: Boolean, + default: false, + }, + useClickAway: { + type: Boolean, + default: true, + }, + transition: String, + overlayClass: String, + className: String, + overlayStyle: Object, + + }, + emit: ['click', 'opened', 'closed', 'update:show'], + setup(props, { emit, attrs, slots }) { + const getTransitionName = (position: string | undefined) => { + switch (position) { + case 'bottom': + return 'fm-slide-up'; + case 'top': + return 'fm-slide-down'; + case 'left': + return 'fm-slide-left'; + case 'right': + return 'fm-slide-right'; + default: + return 'fm-fade'; + } + }; + + const className = { + 'fm-popup': true, + 'fm-popup-round': props.round, + [`fm-popup-${props.position}`]: props.position, + [`${props.className}`]: !!props.className + }; + + const [lockScroll, unlockScroll] = useLockScroll(() => props.lockScroll); + + const close = () => { + props.show && emit('update:show', false); + }; + + const clickAwayActive = ref(false); + const popupRef = ref(); + props.useClickAway && useClickAway(popupRef, close, { active: clickAwayActive }); + + watch( + () => props.show, + (value) => { + if (value) { + lockScroll(); + setTimeout(() => { + clickAwayActive.value = true; + }); + } else { + unlockScroll(); + clickAwayActive.value = false; + } + }, + ); + + const renderTransition = () => { + const name = getTransitionName(props.position); + const style: CSSProperties = { + width: props.width ? props.width : undefined, + height: props.height ? props.height : undefined, + zIndex: props.zIndex !== undefined ? +props.zIndex : undefined, + transitionDuration: `${props.duration}s`, + }; + return ( + emit('opened')} + onAfterLeave={() => emit('closed')} + > +
emit('click', evt)} + {...attrs} + > + {slots.default?.()} +
+
+ ); + }; + + const onOverlayClick = (event: Event) => { + event.stopPropagation(); + props.closeOnClickOverlay && close(); + }; + + const renderOverlay = () => { + const overlayIndex = + props.zIndex !== undefined ? Number(props.zIndex) - 1 : undefined; + if (props.overlay) { + return ( + + ); + } + }; + + return () => { + if (props.teleport) { + return ( + + {renderOverlay()} + {renderTransition()} + + ); + } + return ( + <> + {renderOverlay()} + {renderTransition()} + + ); + }; + }, +}); diff --git a/packages/mobile-ui-vue/components/scroll/index.ts b/packages/mobile-ui-vue/components/scroll/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..98c90e3bf4e4c8c343d5c834f45e63f070dbe80d --- /dev/null +++ b/packages/mobile-ui-vue/components/scroll/index.ts @@ -0,0 +1,9 @@ +import type { App } from 'vue'; +import Scroll from './src/scroll.vue'; + +Scroll.install = function (app: App) { + app.component(Scroll.name || 'FmScroll', Scroll); +}; + +export { Scroll }; +export default Scroll; diff --git a/packages/mobile-ui-vue/components/scroll/src/scroll.vue b/packages/mobile-ui-vue/components/scroll/src/scroll.vue new file mode 100644 index 0000000000000000000000000000000000000000..520a3463e0b4eaa33134b67737ecfc66c7754831 --- /dev/null +++ b/packages/mobile-ui-vue/components/scroll/src/scroll.vue @@ -0,0 +1,83 @@ + + + diff --git a/packages/mobile-ui-vue/components/theme/fonts/farris-mobile-icon.ttf b/packages/mobile-ui-vue/components/theme/fonts/farris-mobile-icon.ttf new file mode 100644 index 0000000000000000000000000000000000000000..7d450d9876c7df282718db3dab7ab1c38a21b725 Binary files /dev/null and b/packages/mobile-ui-vue/components/theme/fonts/farris-mobile-icon.ttf differ diff --git a/packages/mobile-ui-vue/components/theme/index.scss b/packages/mobile-ui-vue/components/theme/index.scss new file mode 100644 index 0000000000000000000000000000000000000000..7738cdd9c79a2bba4c8161ddbaede78ec3274c00 --- /dev/null +++ b/packages/mobile-ui-vue/components/theme/index.scss @@ -0,0 +1,59 @@ +@import './src/animation'; +@import './src/variables'; +@import './src/action-bar.scss'; +@import './src/action-sheet.scss'; +@import './src/attach.scss'; +@import './src/badge.scss'; +@import './src/base.scss'; +@import './src/button.scss'; +@import "./src/calendar.scss"; +@import './src/card.scss'; +@import './src/cell.scss'; +@import './src/checkbox.scss'; +@import './src/checker.scss'; +@import './src/collapse.scss'; +@import './src/dialog.scss'; +@import './src/discussion-group.scss'; +@import './src/dropdown.scss'; +@import './src/filter.scss'; +@import './src/html-panel.scss'; +@import './src/icon.scss'; +@import './src/image-preview.scss'; +@import './src/image.scss'; +@import './src/index-list.scss'; +@import './src/input-template.scss'; +@import './src/input.scss'; +@import './src/listview.scss'; +@import './src/loading.scss'; +@import './src/lookup.scss'; +@import './src/navbar.scss'; +@import './src/notice-bar.scss'; +@import './src/notify.scss'; +@import './src/overlay.scss'; +@import './src/pagination.scss'; +@import './src/picker.scss'; +@import './src/popup.scss'; +@import './src/popover.scss'; +@import './src/radio.scss'; +@import './src/rich-editor.scss'; +@import './src/scheadule.scss'; +@import './src/scroll-view.scss'; +@import './src/scroll.scss'; +@import './src/search.scss'; +@import './src/share-sheet.scss'; +@import './src/sidebar.scss'; +@import './src/skeleton.scss'; +@import './src/steps.scss'; +@import './src/swipe.scss'; +@import './src/swipecell.scss'; +@import './src/switch.scss'; +@import './src/tab-bar.scss'; +@import './src/tab.scss'; +@import './src/tabs.scss'; +@import './src/tag.scss'; +@import './src/tags.scss'; +@import './src/text-area.scss'; +@import './src/text.scss'; +@import './src/toast.scss'; +@import './src/tree-bar.scss'; +@import './src/upload.scss'; diff --git a/packages/mobile-ui-vue/components/theme/src/_animation.scss b/packages/mobile-ui-vue/components/theme/src/_animation.scss new file mode 100644 index 0000000000000000000000000000000000000000..891caf7a2fed49d35ba4b6aff796b536a426507c --- /dev/null +++ b/packages/mobile-ui-vue/components/theme/src/_animation.scss @@ -0,0 +1,150 @@ +@keyframes fm-fade-in { + from { + opacity: 0; + } + + to { + opacity: 1; + } +} + +@keyframes fm-fade-out { + from { + opacity: 1; + } + + to { + opacity: 0; + } +} + +.fm-fade { + &-enter-active { + animation: 0.3s fm-fade-in both ease-out; + } + + &-leave-active { + animation: 0.3s fm-fade-out both ease-in; + } +} + +.fm-slide-up { + &-enter-from, + &-leave-to { + transform: translate3d(0, 100%, 0); + } +} + +.fm-slide-down { + &-enter-from, + &-leave-to { + transform: translate3d(0, -100%, 0); + } +} + +.fm-slide-left { + &-enter-from, + &-leave-to { + transform: translate3d(-100%, 0, 0); + } +} + +.fm-slide-right { + &-enter-from, + &-leave-to { + transform: translate3d(100%, 0, 0); + } +} + +.fm-slide-up-enter-active, +.fm-slide-down-enter-active, +.fm-slide-left-enter-active, +.fm-slide-right-enter-active { + transition-timing-function: ease-out; +} +.fm-slide-up-leave-active, +.fm-slide-down-leave-active, +.fm-slide-left-leave-active, +.fm-slide-right-leave-active { + transition-timing-function: ease-in; +} + +.fm-slide-in-enter-active, +.fm-slide-in-leave-active, +.fm-slide-out-enter-active, +.fm-slide-out-leave-active { + will-change: transform; + transition: all 0.3s; + height: 100%; + width: 100%; + top: 0px; + position: absolute; + backface-visibility: hidden; + perspective: 1000; +} + +.fm-slide-in-leave-to, +.fm-slide-out-enter-from { + transform: translateX(-100%); + opacity: 0; +} +.fm-slide-in-enter-from, +.fm-slide-out-leave-to { + transform: translateX(100%); + opacity: 0; +} + +@keyframes fm-drop-down-in { + from { + height: 0; + opacity: 0; + } + + to { + opacity: 1; + } +} +@keyframes fm-drop-down-out { + from { + opacity: 1; + } + to { + height: 0; + opacity: 0; + } +} +.fm-drop-down { + &-enter-active { + animation: 0.3s fm-drop-down-in both ease-out; + } + &-leave-active { + animation: 0.3s fm-drop-down-out both ease-in; + } +} +@keyframes fm-circular { + 0% { + stroke-dasharray: 1, 200; + stroke-dashoffset: 0 + } + + 50% { + stroke-dasharray: 90, 150; + stroke-dashoffset: -40 + } + + 100% { + stroke-dasharray: 90, 150; + stroke-dashoffset: -120 + } +} +@keyframes fm-rotate { + from { + -webkit-transform: rotate(0); + transform: rotate(0) + } + + to { + -webkit-transform: rotate(360deg); + transform: rotate(360deg) + } +} \ No newline at end of file diff --git a/packages/mobile-ui-vue/components/theme/src/_variables.scss b/packages/mobile-ui-vue/components/theme/src/_variables.scss new file mode 100644 index 0000000000000000000000000000000000000000..39d0462ceba488410eb192056d15094f10a03499 --- /dev/null +++ b/packages/mobile-ui-vue/components/theme/src/_variables.scss @@ -0,0 +1,141 @@ +:root { + // Color Palette + --fm-black: #000; + --fm-white: #fff; + --fm-gray-1: #f7f8fa; + --fm-gray-2: #f2f3f5; + --fm-gray-3: #eee; + --fm-gray-4: #ddd; + --fm-gray-5: #ccc; + --fm-gray-6: #999; + --fm-gray-7: #666; + --fm-gray-8: #333; + --fm-red: #F24645; + --fm-red-light: #f9e8e8; + --fm-blue: #3A90FF; + --fm-blue-2: #65a7ff; + --fm-blue-light: #ecf2fe; + --fm-green: #5CC171; + --fm-green-2: #5AC1C3; + --fm-green-light: #e9f5ed; + --fm-orange: #FF9800; + --fm-orange-2: #FA6400; + --fm-orange-light: #faf0e1; + --fm-orange-dark: #ed6a0c; + + + // Component Colors + --fm-primary-color: var(--fm-blue); + --fm-success-color: var(--fm-green); + --fm-danger-color: var(--fm-red); + --fm-warning-color: var(--fm-orange); + --fm-submit-color: var(--fm-green-2); + --fm-primary-color-light: var(--fm-blue-light); + --fm-success-color-light: var(--fm-green-light); + --fm-danger-color-light: var(--fm-red-light); + --fm-warning-color-light: var(--fm-orange-light); + --fm-text-color: var(--fm-gray-8); + --fm-text-color-2: var(--fm-gray-6); + --fm-text-color-3: var(--fm-gray-5); + --fm-text-color-light: var(--fm-gray-7); + --fm-active-color: var(--fm-gray-2); + --fm-disabled-color: var(--fm-gray-5); + --fm-active-opacity: 0.7; + --fm-readonly-opacity: 0.6; + --fm-disabled-opacity: 0.5; + --fm-background: var(--fm-gray-1); + --fm-background-2: var(--fm-white); + --fm-background-3: var(--fm-gray-2); + --fm-box-shadow-color: var(--fm-gray-2); + --fm-box-shadow-color-2: var(--fm-gray-6); + + // Padding + --fm-padding-base: 4px; + --fm-padding-xs: 8px; + --fm-padding-sm: 12px; + --fm-padding-md: 16px; + --fm-padding-lg: 24px; + --fm-padding-xl: 32px; + --fm-padding-horizontal-xs: 0 var(--fm-padding-xs); + --fm-padding-horizontal-sm: 0 var(--fm-padding-sm); + --fm-padding-horizontal-md: 0 var(--fm-padding-md); + --fm-padding-horizontal-lg: 0 var(--fm-padding-lg); + // Margin + --fm-margin-base: 4px; + --fm-margin-xs: 8px; + --fm-margin-sm: 12px; + --fm-margin-md: 16px; + --fm-margin-lg: 24px; + --fm-margin-xl: 32px; + --fm-margin-horizontal-xs: 0 var(--fm-margin-xs); + --fm-margin-horizontal-sm: 0 var(--fm-margin-sm); + --fm-margin-horizontal-md: 0 var(--fm-margin-md); + --fm-margin-horizontal-lg: 0 var(--fm-margin-lg); + + // Font + --fm-font-bold-light: 500; + --fm-font-bold: 600; + --fm-font-size-base: 16px; + --fm-font-size-xs: 10px; + --fm-font-size-sm: 12px; + --fm-font-size-md: 14px; + --fm-font-size-lg: 18px; + --fm-line-height-xs: 14px; + --fm-line-height-sm: 18px; + --fm-line-height-md: 20px; + --fm-line-height-lg: 22px; + --fm-line-height: 1.2; + + --fm-font-size-icon-1: 10px; + --fm-font-size-icon-2: 12px; + --fm-font-size-icon-3: 14px; + --fm-font-size-icon-4: 16px; + --fm-font-size-icon-5: 18px; + --fm-font-size-icon-6: 20px; + + // Gradient Colors + --fm-gradient-blue: linear-gradient(-45deg,var(--fm-blue-2) 0%, var(--fm-blue) 100%); + --fm-gradient-orange: linear-gradient(-45deg,var(--fm-orange) 0%, var(--fm-orange-2) 100%); + + /* stylelint-disable */ + --fm-base-font: -apple-system, BlinkMacSystemFont, 'Helvetica Neue', + Helvetica, Segoe UI, Arial, Roboto, 'PingFang SC', 'miui', + 'Hiragino Sans GB', 'Microsoft Yahei', sans-serif; + --fm-price-font: avenir-heavy, 'PingFang SC', helvetica neue, arial, + sans-serif; + /* stylelint-enable */ + + // Animation + --fm-duration-base: 0.3s; + --fm-duration-fast: 0.2s; + --fm-ease-out: ease-out; + --fm-ease-in: ease-in; + + // Border + --fm-border-color: var(--fm-gray-4); + --fm-border-color-2: var(--fm-gray-3); + --fm-border-width: 1px; + --fm-noborder: none; + --fm-radius-sm: 2px; + --fm-radius-md: 4px; + --fm-radius-lg: 8px; + --fm-radius-max: 999px; + + --fm-zindex-1: 9; + --fm-zindex-2: 10; + --fm-zindex-3: 99; + --fm-zindex-4: 100; + --fm-zindex-5: 999; + --fm-zindex-6: 1000; +} + +.fm-theme-dark { + --fm-text-color: #f5f5f5; + --fm-text-color-2: #707070; + --fm-text-color-3: #4d4d4d; + --fm-border-color: #3a3a3c; + --fm-active-color: #3a3a3c; + --fm-background: #000; + --fm-background-2: #1c1c1e; + --fm-background-3: #37363b; +} diff --git a/packages/mobile-ui-vue/components/theme/src/action-bar.scss b/packages/mobile-ui-vue/components/theme/src/action-bar.scss new file mode 100644 index 0000000000000000000000000000000000000000..4486789d10880853ab4e369797b62bb687820f02 --- /dev/null +++ b/packages/mobile-ui-vue/components/theme/src/action-bar.scss @@ -0,0 +1,104 @@ +@import './mixins/hairline'; + +:root { + --fm-action-bar-border-color: var(--fm-border-color); + --fm-action-bar-btn-icon-font-size: var(--fm-font-size-icon-6); + --fm-action-bar-btn-color: var(--fm-gray-7); + --fm-action-bar-btn-color-white: var(--fm-white); + --fm-action-bar-btn-color-disabled: var(--fm-disabled-color); + --fm-action-bar-btn-font-size: var(--fm-font-size-xs); + --fm-action-bar-btn-margin-top: var(--fm-margin-base); + --fm-action-bar-btn-padding: var(--fm-padding-xs) 0; +} + +.fm-action-bar { + width: 100%; +} +.fm-action-bar-btns { + @include hairline('top', var(--fm-action-bar-border-color)); + display: flex; + align-items: center; + flex-wrap: nowrap; + text-align: center; + .fm-action-bar-btn-item { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + flex: 1; + padding: var(--fm-action-bar-btn-padding); + .btn-item-icon { + .fm-icon { + font-size: var(--fm-action-bar-btn-icon-font-size); + } + } + .btn-item-text { + margin-top: var(--fm-action-bar-btn-margin-top); + font-size: var(--fm-action-bar-btn-font-size); + color: var(--fm-action-bar-btn-color); + } + &-primary, + &-danger, + &-warning, + &-success, + &.fm-action-bar-btn-item-has-color + { + .btn-item-icon, + .btn-item-text { + color: var(--fm-action-bar-btn-color-white); + } + } + &-primary { + background-color: var(--fm-primary-color); + } + &-danger { + background-color: var(--fm-danger-color); + } + &-warning { + background-color: var(--fm-warning-color); + } + &-success { + background-color: var(--fm-success-color); + } + + &.fm-action-bar-btn-item-disabled { + .btn-item-icon, + .btn-item-text { + color: var(--fm-action-bar-btn-color-disabled); + } + } + &:not(.fm-action-bar-btn-item-disabled):active { + background-color: var(--fm-active-color); + } + &.fm-action-bar-btn-item-primary:active { + background-color: var(--fm-primary-color); + } + } +} +.fm-action-bar-popover { + .fm-popover-arrow { + display: none; + } + .fm-popover-item-container { + &-primary, + &-primary .fm-popover-item-content { + color: var(--fm-primary-color); + } + &-danger, + &-danger .fm-popover-item-content { + color: var(--fm-danger-color); + } + &-warning, + &-warning .fm-popover-item-content { + color: var(--fm-warning-color); + } + &-success, + &-success .fm-popover-item-content { + color: var(--fm-success-color); + } + &-disabled, + &-disabled .fm-popover-item-content { + color: var(--fm-action-bar-btn-color-disabled); + } + } +} diff --git a/packages/mobile-ui-vue/components/theme/src/action-sheet.scss b/packages/mobile-ui-vue/components/theme/src/action-sheet.scss new file mode 100644 index 0000000000000000000000000000000000000000..53f4cec7c2451503baa3d264996071f69ba72c77 --- /dev/null +++ b/packages/mobile-ui-vue/components/theme/src/action-sheet.scss @@ -0,0 +1,99 @@ +@import './mixins/hairline'; +:root { + --fm-actionsheet-max-height: 80%; + --fm-actionsheet-color: var(--fm-text-color); + --fm-actionsheet-background-color: var(--fm-gray-2); + --fm-actionsheet-font-size: var(--fm-font-size-base); + --fm-actionsheet-sub-font-size: var(--fm-font-size-sm); + --fm-actionsheet-sub-color: var(--fm-text-color-2); + --fm-actionsheet-round: 16px 16px 0 0 ; + --fm-actionsheet-header-height: 48px; + --fm-actionsheet-header-height: 48px; + --fm-actionsheet-item-height: 22px; + --fm-actionsheet-sub-height: 20px; +} + +.fm-actionsheet{ + display: flex; + flex-direction: column; + overflow: hidden; + max-height: var(--fm-actionsheet-max-height); + color: var(--fm-actionsheet-color); + font-size: var(--fm-actionsheet-font-size); + background-color: var(--fm-actionsheet-background-color); + &.fm-actionsheet-round{ + border-radius: var(--fm-actionsheet-round); + } + &-header { + flex-shrink: 0; + height: var(--fm-actionsheet-header-height); + line-height: var(--fm-actionsheet-header-height); + text-align: center; + background-color: var(--fm-white); + &-title{ + font-weight: 500; + } + &-close{ + position: absolute; + top: 0; + right: 0; + line-height: inherit; + padding: var(--fm-padding-horizontal-md); + .fm-icon{ + color: var(--fm-gray-5); + font-size: var(--fm-font-size-icon-5); + } + &:active{ + .fm-icon{ + color: var(--fm-gray-7); + } + } + } + } + .fm-actionsheet-item,.fm-actionsheet-cancel-inner{ + display: block; + width: 100%; + padding: 14px 16px; + text-align: center; + background-color: var(--fm-white); + border: none; + cursor: pointer; + &:active{ + background-color: var(--fm-actionsheet-background-color); + } + } + &-content{ + flex: 1 auto; + overflow-y: auto; + -webkit-overflow-scrolling: touch; + .fm-actionsheet-item{ + line-height: var(--fm-actionsheet-item-height); + &-subname{ + margin-top: var(--fm-margin-xs); + color: var(--fm-actionsheet-sub-color); + font-size: var(--fm-actionsheet-sub-font-size); + line-height: var(--fm-actionsheet-sub-font-size); + } + &.fm-actionsheet-item-disabled{ + color: var(--fm-disabled-color); + } + } + } + &-cancel{ + flex-shrink: 0; + margin-top: var(--fm-margin-xs); + background-color: var(--fm-white); + } + &-description{ + background-color: var(--fm-white); + &-inner{ + @include hairline('bottom', var(--fm-border-color)); + flex-shrink: 0; + padding: var(--fm-padding-md); + color: var(--fm-actionsheet-sub-color); + font-size: var(--fm-actionsheet-sub-font-size); + line-height: var(--fm-actionsheet-sub-height); + text-align: center; + } + } +} \ No newline at end of file diff --git a/packages/mobile-ui-vue/components/theme/src/attach.scss b/packages/mobile-ui-vue/components/theme/src/attach.scss new file mode 100644 index 0000000000000000000000000000000000000000..331e964f06b566b9563c9aa8605e8965ff8f374f --- /dev/null +++ b/packages/mobile-ui-vue/components/theme/src/attach.scss @@ -0,0 +1,419 @@ +.attachment-bg { + background: #fff; + user-select: none; + -webkit-user-select: none; + + .fm-button { + user-select: none; + -webkit-user-select: none; + } + + div { + user-select: none; + -webkit-user-select: none; + } + + span { + user-select: none; + -webkit-user-select: none; + } + + img { + -webkit-user-select: none; + -webkit-touch-callout: none; + user-select: none; + } + + button { + user-select: none; + -webkit-user-select: none; + } +} + +.listview-content { + .fm-listview-item { + margin: 12px 0; + } + + .fm-tmpl-attachment-img { + width: 48px; + height: 48px; + margin: auto 0; + + .item-img { + width: 100%; + height: 100%; + } + + img { + border-radius: 3px; + width: 48px; + height: 48px; + } + } + + .attachment-text { + flex: 1; + margin: auto 12px; + + &>div { + display: flex; + justify-content: space-between; + margin-bottom: 5px; + } + } + + .fm-tmpl-attachment-name { + line-height: 22px; + font-family: PingFangSC-Regular; + font-size: 16px; + color: #333333; + letter-spacing: 0.21px; + margin-bottom: 2px; + word-break: break-all; + } + + .fm-tmpl-attachment-footer { + line-height: 18px; + font-family: PingFangSC-Regular; + font-size: 12px; + color: #888888; + letter-spacing: 0; + } + + .fm-tmpl-listview-attachment { + padding: 0; + display: flex; + justify-content: space-between; + -webkit-user-select: none; + user-select: none; + } + + .attachment-button { + .attachment-button-custom { + padding: 0; + width: 50px; + height: 20px; + font-family: PingFangSC-Regular; + font-size: 12px; + letter-spacing: 0; + border-radius: 10px; + } + } + + .attachment-icon { + margin: auto 0; + width: 16px; + height: 16px; + transform: rotate(90deg); + } +} + +.panzoom { + transform: none; + backface-visibility: hidden; + transform-origin: 50% 50% 0px; + display: flex; + justify-content: center; + flex-wrap: wrap; +} + +.page { + display: inline-block; + background-color: #ffffff; + margin: 20px; + -webkit-box-shadow: 0px 4px 12px -4px rgba(0, 0, 0, 0.38); + -moz-box-shadow: 0px 4px 12px -4px rgba(0, 0, 0, 0.38); + box-shadow: 0px 4px 12px -4px rgba(0, 0, 0, 0.38); + transition: all 0.3s; +} + +.farris-attachment-entry-vertical { + flex-direction: column; +} + +.farris-attachment-entry { + display: flex; + clear: both; + + & .fm-attachment-disabled { + cursor: not-allowed; + pointer-events: none; + } + + & .attachment-navigation { + overflow: inherit; + white-space: nowrap; + } + + & .attachment-navigation .attachment-navigation-item { + position: relative; + display: inline-block; + + & .item-img { + width: 100%; + height: 100%; + position: absolute; + top: 0; + left: 0; + } + + & .item-icon-delete { + display: flex; + align-items: center; + justify-content: center; + position: absolute; + right: 0; + top: 0; + width: 16px; + height: 16px; + background: #888; + + & .fm-icon { + color: #fff; + font-size: 12px; + } + } + + & .item-icon { + position: absolute; + } + } + + & .fm-attachment-container { + box-sizing: border-box; + float: left; + position: relative; + margin: 0 100px 0 0; + padding: 0 52px 0 0; + max-width: 100%; + height: 54px; + + & .fm-attachment-files-list { + padding-top: 6px; + overflow: auto; + max-width: 100%; + } + + & .fm-attachment-files-item { + position: relative; + width: 48px; + height: 48px; + margin-right: 20px; + + & .item-icon-delete { + display: flex; + align-items: center; + justify-content: center; + position: absolute; + right: -6px; + top: -6px; + width: 16px; + height: 16px; + background: #888; + border-radius: 50%; + + & .fm-icon { + color: #fff; + font-size: 12px; + } + } + + & .van-image__img { + border-radius: 5px; + } + } + + & .fm-attachment-upload-btn-container { + position: absolute; + right: 0; + top: 50%; + margin-top: -20px; + z-index: 8; + width: 48px; + height: 48px; + background: #f6f6f6; + border-radius: 3px; + + & .fm-attachment-upload-btn { + & .fm-icon { + display: block; + font-size: 20px; + color: #ddd; + line-height: 48px; + margin: 0 auto; + } + } + } + } + + & .fm-attachment-upload-listview-btn-container { + z-index: 8; + width: 48px; + height: 48px; + background: #f6f6f6; + border-radius: 3px; + + & .fm-attachment-upload-btn { + & .fm-icon { + display: block; + font-size: 20px; + color: #ddd; + line-height: 48px; + margin: 0 auto; + } + } + } +} + + +.attachment-actionsheet-content { + flex: 1 auto; + overflow-y: auto; + + .attachment-actionsheet-item-disabled { + color: #ccc; + padding: 0; + } + + .attachment-actionsheet-item { + font-family: PingFangSC-Regular; + letter-spacing: 0; + display: block; + width: 100%; + padding: 14px 0; + font-size: 16px; + background-color: #fff; + border: none; + cursor: pointer; + text-align: center; + } +} + +.actionsheet-content__remark { + font-family: PingFangSC-Regular; + font-size: 12px; + color: #999999; + letter-spacing: 0; + margin-top: 5px; +} + +.tooltip-container { + position: absolute; + z-index: 3000; + min-width: 150px; + margin: 0; + background: #333333; + border-radius: 5px; + font-family: PingFangSC-Medium; + font-size: 13px; + color: #cccccc; + letter-spacing: 0; + + div { + user-select: none; + -webkit-user-select: none; + } + + span { + user-select: none; + -webkit-user-select: none; + } + + .tooltip-content__item { + line-height: 3; + margin: 0 10px; + } + + .tooltip-content__item-first { + line-height: 3; + margin: 0 10px; + } + + .tooltip-content__item:not(:last-child) { + border-bottom: 1px solid rgba(102, 102, 102, 0.5); + } + + .tooltip-content__line { + background: rgba(102, 102, 102, 0.5); + height: 1px; + margin: 0 10px; + } + + .tooltip-container__arrow { + position: absolute; + border: 5px solid transparent; + width: 0; + height: 0; + } + + .tooltip-content__remark { + font-size: 10px; + margin-top: -20px; + } + + .tooltip-content__first-item { + line-height: 2; + } + + .tooltip-content__item__preview { + line-height: 3; + margin: 0 10px; + } + + .tooltip-content__item__disabled { + opacity: 0.4; + } + + .tooltip-arrow__top { + border-top-color: #333333; + left: 50%; + top: 100%; + } + + .tooltip-arrow__top-start { + border-top-color: #333333; + left: 80%; + top: 100%; + } + + .tooltip-arrow__top-end { + border-top-color: #333; + left: 20%; + top: 100%; + } + + .tooltip-arrow__right {} + + .tooltip-arrow__right-start { + border-right-color: #333; + right: 100%; + top: 30px; + } + + .tooltip-arrow__right-end { + border-right-color: #333; + right: 100%; + bottom: 30px; + } + + .tooltip-arrow__bottom {} + + .tooltip-arrow__bottom-start {} + + .tooltip-arrow__bottom-end {} + + .tooltip-arrow__left {} + + .tooltip-arrow__left-start { + border-left-color: #333; + left: 100%; + top: 30px; + } + + .tooltip-arrow__left-end { + border-left-color: #333; + left: 100%; + bottom: 30px; + } +} \ No newline at end of file diff --git a/packages/mobile-ui-vue/components/theme/src/badge.scss b/packages/mobile-ui-vue/components/theme/src/badge.scss new file mode 100644 index 0000000000000000000000000000000000000000..63b46716e61aecc3b28fc15985ea017395e013c0 --- /dev/null +++ b/packages/mobile-ui-vue/components/theme/src/badge.scss @@ -0,0 +1,47 @@ +:root { + --fm-badge-padding: 2px 4px; + --fm-badge-font-size: var(--fm-font-size-xs); + --fm-badge-text-color: var(--fm-white); + --fm-badge-primary-color: var(--fm-primary-color); + --fm-badge-secondary-color: var(--fm-blue-light); + --fm-badge-success-color: var(--fm-success-color); + --fm-badge-danger-color: var(--fm-danger-color); + --fm-badge-warning-color: var(--fm-warning-color); +} + +.fm-badge { + position: relative; + display: inline-block; + color: var(--fm-badge-text-color); + font-size: var(--fm-badge-font-size); + &-content { + position: absolute; + right: 0; + top: 0; + z-index: 99; + transform: translate(50%,-50%); + padding: var(--fm-badge-padding); + border-radius: 99px; + &-primary, + &-info { + background: var(--fm-badge-primary-color); + } + + &-secondary { + color: var(--fm-badge-primary-color); + background: var(--fm-badge-secondary-color); + } + + &-danger { + background-color: var(--fm-danger-color); + } + + &-warning { + background-color: var(--fm-warning-color); + } + + &-success { + background-color: var(--fm-success-color); + } + } +} \ No newline at end of file diff --git a/packages/mobile-ui-vue/components/theme/src/base.scss b/packages/mobile-ui-vue/components/theme/src/base.scss new file mode 100644 index 0000000000000000000000000000000000000000..6d4885e06f1a6aa23f6137123f28c8913d4d57e0 --- /dev/null +++ b/packages/mobile-ui-vue/components/theme/src/base.scss @@ -0,0 +1,17 @@ +@import './mixins/hairline'; + +.fm-overflow-hidden { + overflow: hidden !important; +} +.fm-hairline { + @include hairline('all'); +} +.fm-hairline-top { + @include hairline('top'); +} +.fm-hairline-bottom { + @include hairline('bottom'); +} +.fm-no-hairline::after { + display: none!important; +} diff --git a/packages/mobile-ui-vue/components/theme/src/button-group.scss b/packages/mobile-ui-vue/components/theme/src/button-group.scss new file mode 100644 index 0000000000000000000000000000000000000000..9e39a6607ddec5c7ea79aa2f63434ea45174b450 --- /dev/null +++ b/packages/mobile-ui-vue/components/theme/src/button-group.scss @@ -0,0 +1,66 @@ +:root { + --button-group-color: var(--fm-primary-color); + --button-group-background: var(--fm-primary-color); + --button-group-background-first: var(--fm-white); + --button-group-background-last: var(--fm-gradient-blue); + --button-group-icon-color: var(--fm-gray-7); + --button-group-icon-font-size: var(--fm-font-size-icon-6); + --button-group-icon-text-font-size: var(--fm-font-size-xs); +} + +.fm-button-group { + display: flex; + .button-item { + display: flex; + flex: 1; + } + .button-wrapper { + flex: 1; + .fm-button { + height: 100%; + background: var(--button-group-background-last); + } + &:not(:last-child) { + .fm-button { + border-radius: 999px 0 0 999px; + background: var(--button-group-background-first); + border: 1px solid var(--button-group-color); + color: var(--button-group-color); + } + } + &:not(:first-child) { + .fm-button { + border-radius: 0 999px 999px 0; + background: var(--button-group-background); + } + } + } + .icon-wrapper { + display: flex; + flex-direction: column; + align-items: center; + justify-content: space-between; + color: var(--button-group-icon-color); + .fm-icon { + font-size: var(--button-group-icon-font-size); + } + .icon-text { + font-size: var(--button-group-icon-text-font-size); + line-height: 16px; + } + &:not(:last-child) { + padding-right: var(--fm-padding-md); + } + + &.button-disabled { + cursor: not-allowed; + opacity: var(--fm-disabled-opacity); + } + } + &:not(:last-child) { + padding-right: var(--fm-padding-md); + } + &.fm-button-group-block { + flex: 1; + } +} diff --git a/packages/mobile-ui-vue/components/theme/src/button.scss b/packages/mobile-ui-vue/components/theme/src/button.scss new file mode 100644 index 0000000000000000000000000000000000000000..57079ba71fdce9bdfdd3402ea89e9a07f7cd149d --- /dev/null +++ b/packages/mobile-ui-vue/components/theme/src/button.scss @@ -0,0 +1,199 @@ +:root { + --fm-button-height: 42px; + --fm-button-padding: 0 15px; + --fm-button-color: var(--fm-white); + --fm-button-round: var(--fm-radius-max); + --fm-button-radius: var(--fm-radius-sm); + --fm-button-plain-background: var(--fm-white); + --fm-button-line-height: var(--fm-line-height); + --fm-button-border-width: var(--fm-border-width); + --fm-button-font-size: var(--fm-font-size-base); + --fm-button-lg-height: 46px; + --fm-button-lg-font-size: var(--fm-font-size-lg); + --fm-button-md-height: 38px; + --fm-button-md-font-size: var(--fm-font-size-md); + --fm-button-sm-height: 34px; + --fm-button-sm-padding: 0 8px; + --fm-button-sm-font-size: var(--fm-font-size-sm); + --fm-button-xs-height: 28px; + --fm-button-xs-font-size: var(--fm-font-size-xs); + --fm-button-primary-color: var(--fm-primary-color); + --fm-button-secondary-color: var(--fm-blue-light); + --fm-button-success-color: var(--fm-success-color); + --fm-button-danger-color: var(--fm-danger-color); + --fm-button-warning-color: var(--fm-warning-color); +} + +.fm-button { + position: relative; + cursor: pointer; + display: inline-flex; + align-items: center; + justify-content: center; + box-sizing: border-box; + text-align: center; + margin: 0; + border: none; + transition: opacity 0.2s; + color: var(--fm-button-color); + height: var(--fm-button-height); + padding: var(--fm-button-padding); + font-size: var(--fm-button-font-size); + line-height: var(--fm-button-line-height); + border-radius: var(--fm-button-radius); + &-primary, + &-info { + background: var(--fm-button-primary-color); + } + + &-secondary { + color: var(--fm-button-primary-color); + background: var(--fm-button-secondary-color); + } + + &-danger { + background-color: var(--fm-danger-color); + } + + &-warning { + background-color: var(--fm-warning-color); + } + + &-success { + background-color: var(--fm-success-color); + } + + &-gradient-blue { + background: var(--fm-gradient-blue); + } + &-gradient-orange { + background: var(--fm-gradient-blue); + } + + &-add { + height: 48px; + width: 48px; + color: var(--fm-button-color); + background: var(--fm-button-primary-color); + box-shadow: var(--fm-button-box-shadow); + border-radius: var(--fm-button-round); + .fm-icon { + font-size: var(--fm-font-size-icon-6); + } + } + + &-plain { + background: var(--fm-button-plain-background); + box-shadow: none; + &.fm-button-primary, + &.fm-button-info { + color: var(--fm-button-primary-color); + border: var(--fm-button-border-width) solid var(--fm-button-primary-color); + } + + &.fm-button-success { + color: var(--fm-button-success-color); + border: var(--fm-button-border-width) solid var(--fm-button-success-color); + } + + &.fm-button-danger { + color: var(--fm-button-danger-color); + border: var(--fm-button-border-width) solid var(--fm-button-danger-color); + } + + &.fm-button-warning { + color: var(--fm-button-warning-color); + border: var(--fm-button-border-width) solid var(--fm-button-warning-color); + } + } + + &-noborder { + border: var(--fm-noborder) !important; + } + + &-large { + height: var(--fm-button-lg-height); + font-size: var(--fm-button-lg-font-size); + } + &-normal { + height: var(--fm-button-md-height); + font-size: var(--fm-button-md-font-size); + } + &-small { + height: var(--fm-button-sm-height); + padding: var(--fm-button-sm-padding); + font-size: var(--fm-button-sm-font-size); + } + &-mini { + height: var(--fm-button-xs-height); + padding: var(--fm-button-sm-padding); + font-size: var(--fm-button-xs-font-size); + } + + &-block { + display: flex; + width: 100%; + } + + &-disabled { + cursor: not-allowed; + opacity: var(--fm-disabled-opacity); + } + + &-round { + border-radius: var(--fm-button-round); + } + + &-square { + border-radius: 0; + } + .fm-button-loading { + display: inline-block; + width: 20px; + max-width: 100%; + height: 20px; + max-height: 100%; + vertical-align: middle; + animation: fm-rotate 2s linear infinite; + circle { + animation: fm-circular 1.5s ease-in-out infinite; + stroke: currentColor; + stroke-width: 4; + stroke-linecap: round; + } + &-icon-circular { + color: #fff; + } + } + .fm-button-loading-text { + margin-left: 6px; + } + .fm-button-icon:not(:last-child) { + margin-right: 6px; + } + + &::before { + position: absolute; + top: 50%; + left: 50%; + width: 100%; + height: 100%; + background-color: #000; + border: inherit; + border-color: #000; + border-radius: inherit; + -webkit-transform: translate(-50%, -50%); + transform: translate(-50%, -50%); + opacity: 0; + content: ' '; + } + &:active::before { + opacity: 0.1; + } + &-loading, + &-disabled { + &::before { + display: none; + } + } +} diff --git a/packages/mobile-ui-vue/components/theme/src/calendar.scss b/packages/mobile-ui-vue/components/theme/src/calendar.scss new file mode 100644 index 0000000000000000000000000000000000000000..a9cadbdb1a49d4e864f4a6017f7ae42bc37e211e --- /dev/null +++ b/packages/mobile-ui-vue/components/theme/src/calendar.scss @@ -0,0 +1,205 @@ +:root { + --fm-calendar-font-size: var(--fm-font-size-base); + --fm-calendar-color: var(--fm-text-color); + --fm-calendar-background: var(--fm-background); + --fm-calendar-background-range: var(--fm-blue-2); + --fm-calendar-sub-font-size: var(--fm-font-size-xs); + --fm-calendar-sub-color: var(--fm-text-color-2); + --fm-calendar-radius: var(--fm-radius-max); + --fm-calendar-primary-color: var(--fm-primary-color); +} + +.fm-calendar-day-cell { + flex: 1; + display: flex; + align-items: center; + justify-content: center; + text-align: center; + color: var(--fm-calendar-color); + cursor: pointer; + position: relative; + &:after { + content: ''; + display: block; + padding-top: 100%; + } + .text { + width: 34px; + height: 34px; + border-radius: var(--fm-calendar-radius); + text-align: center; + display: flex; + align-items: center; + justify-content: center; + flex-direction: column; + .day-lunar { + font-size: var(--fm-calendar-sub-font-size); + color: var(--fm-calendar-sub-color); + transform: scale(0.87); + white-space: nowrap; + } + } + .mark { + position: absolute; + top: 2px; + right: 2px; + font-size: 8px; + color: var(--fm-calendar-primary-color); + letter-spacing: 0.21px; + transform: scale(0.75); + } + .event { + position: absolute; + bottom: 2px; + left: 50%; + width: 5px; + height: 5px; + transform: translateX(-50%); + border-radius: var(--fm-calendar-radius); + background: var(--fm-calendar-primary-color); + } + &.fm-calendar-day-cell-current { + .text { + .day, + .day-lunar { + color: var(--fm-calendar-primary-color); + } + } + } + &.fm-calendar-day-cell-selected { + .text { + .day, + .day-lunar { + color: var(--fm-calendar-background); + } + } + } +} + + +.fm-calendar { + display: flex; + flex-direction: column; + background-color: var(--fm-calendar-background); + font-size: var(--fm-calendar-font-size); + .fm-calendar-header { + flex-shrink: 0; + .fm-calendar-header-title, + .fm-calendar-header-subtitle { + height: 44px; + line-height: 44px; + font-weight: 500; + text-align: center; + padding: 0 8px; + } + .fm-calendar-header-subtitle, + .fm-calendar-header-weekdays, + .fm-calendar-header-subtitle .left, + .fm-calendar-header-subtitle .right { + display: flex; + } + .fm-calendar-header-subtitle { + justify-content: space-between; + .fm-calendar-header-button { + padding: 0 8px; + } + } + .fm-calendar-header-weekdays { + .fm-calendar-weekday { + flex: 1; + line-height: 30px; + text-align: center; + } + } + } + .fm-calendar-body { + flex: 1; + overflow: hidden; + position: relative; + .content-box { + display: flex; + .content { + width: 100%; + flex-shrink:0; + } + } + .back-ground{ + position: absolute; + left: 50%; + top: 50%; + transform: translate(-50%, -50%); + font-size: 160px; + color: rgba(51,51,51,0.05); + z-index: 0; + pointer-events: none; + } + .fm-calendar-collapse { + display: flex; + justify-content: center; + .icon { + font-size: 20px; + color: #888; + } + } + } +} + +.fm-calendar-month { + display: flex; + user-select: none; + flex-direction: column; +} +.fm-calendar-week { + display: flex; +} +.fm-calendar-theme-card { + .fm-calendar-day-cell-selected { + .text { + background-color: var(--fm-calendar-primary-color); + } + } +} +.fm-calendar-theme-form { + .fm-calendar-header { + box-shadow: 0 2px 10px rgba(125, 126, 128, 0.16); + } + .fm-calendar-day-cell { + height: 64px; + } + .fm-calendar-day-cell-selected { + background-color: var(--fm-calendar-primary-color); + border-radius: 4px; + } + .fm-calendar-day-cell-begin { + border-radius: 4px 0 0 4px; + } + .fm-calendar-day-cell-end { + border-radius: 0 4px 4px 0; + } + .fm-calendar-day-cell-range { + background-color: var(--fm-calendar-background-range); + opacity: var(--fm-active-opacity); + } + .fm-calendar-day-cell-opacity:not(.fm-calendar-day-cell-selected):not(.fm-calendar-day-cell-range):not(.fm-calendar-day-cell-begin):not(.fm-calendar-day-cell-end) { + .text { + .day, + .day-lunar { + color: var(--fm-calendar-sub-color); + } + } + } +} +.fm-calendar-header-button-disabled, +.fm-calendar-day-cell-disabled{ + opacity: var(--fm-disabled-opacity); +} + +.fm-calendar-pop-wrapper { + .footer { + padding: 0 16px; + .confirm { + height: 36px; + margin: 7px 0; + } + } +} \ No newline at end of file diff --git a/packages/mobile-ui-vue/components/theme/src/card.scss b/packages/mobile-ui-vue/components/theme/src/card.scss new file mode 100644 index 0000000000000000000000000000000000000000..4fa2d3fe4d4265a18d538ab31bd689c1469d87ec --- /dev/null +++ b/packages/mobile-ui-vue/components/theme/src/card.scss @@ -0,0 +1,65 @@ +:root { + --fm-card-background: var(--fm-background); + --fm-card-header-font-bold: var(--fm-font-bold); + --fm-card-header-icon-color: var(--fm-green); + --fm-card-header-icon-radius: var(--fm-radius-max); + --fm-card-footer-font-size: var(--fm-font-size-md); + --fm-card-footer-color: var(--fm-primary-color); +} + +.fm-card { + background-color: var(--fm-card-background); + &-header { + &-cell { + font-weight: var(--fm-card-font-bold); + } + &-left-icon { + display: flex; + align-items: center; + justify-content: center; + color: var(--fm-card-header-icon-color); + border-radius: var(--fm-card-header-icon-radius); + width: 20px; + height: 20px; + } + &-right-icon { + transition: transform var(--fm-duration-base); + } + } + &-content-wrapper { + display: block; + overflow: hidden; + transition: height var(--fm-duration-base) ease-in-out; + will-change: height; + .fm-card-content { + display: block; + } + } + &-footer { + display: flex; + @include hairline('top', var(--fm-border-color)); + &-btn { + color: var(--fm-card-footer-color); + font-size: var(--fm-card-footer-font-size); + .fm-icon { + color: var(--fm-card-footer-color); + font-size: var(--fm-card-footer-font-size); + } + + &:not(:last-child) { + &::after { + position: relative; + content: ''; + display: block; + margin-top: -8px; + height: 16px; + width: 1px; + background-color: var(--fm-border-color); + position: absolute; + top: 50%; + right: 0; + } + } + } + } +} diff --git a/packages/mobile-ui-vue/components/theme/src/cell.scss b/packages/mobile-ui-vue/components/theme/src/cell.scss new file mode 100644 index 0000000000000000000000000000000000000000..48b645e121de56036be5054030ac23d15227b99a --- /dev/null +++ b/packages/mobile-ui-vue/components/theme/src/cell.scss @@ -0,0 +1,129 @@ +@import './mixins/hairline'; +:root { + --fm-cell-padding: 10px 16px; + --fm-cell-margin: 5px; + --fm-cell-background: var(--fm-background-2); + --fm-cell-color: var(--fm-text-color); + --fm-cell-font-size: var(--fm-font-size-base); + --fm-cell-line-height: 24px; + --cell-required-color: var(--fm-danger-color); + --cell-required-font-size: var(--fm-font-size-sm); + --cell-value-color: var(--fm-text-color); + --cell-label-color: var(--fm-text-color-2); + --cell-label-font-size: var(--fm-font-size-sm); + --cell-label-line-height: var(--fm-line-height-sm); +} +.fm-cell { + width: 100%; + padding: 10px 16px; + background-color: var(--fm-cell-background); + box-sizing: border-box; + color: var(--fm-cell-color); + font-size: var(--fm-cell-font-size); + line-height: var(--fm-cell-line-height); + position: relative; + display: flex; + overflow: hidden; + &-bottom-border, + &:not(:last-child) { + @include hairline('bottom', var(--fm-border-color)); + &::after { + left: 16px !important; + } + } + &.fm-cell-all-width:not(:last-child) { + &::after { + left: 0 !important; + } + } + &-clickable { + cursor: pointer; + } + &-clickable:active { + background-color: var(--fm-active-color); + } + &-required { + .fm-cell-title { + position: relative; + .fm-cell-title-text { + &::after { + padding-left: 2px; + color: var(--cell-required-color); + font-size: var(--cell-required-font-size); + content: '*'; + } + } + } + } + &-flex-fill, + &-title, + &-value { + flex: 1; + font-size: inherit; + } + &-title { + display: inline-block; + overflow: hidden; + &-text { + display: flex; + word-break: break-all; + span { + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; + } + } + } + &-right { + display: flex; + overflow: hidden; + flex-direction: column; + &-content { + display: flex; + flex: 1; + } + } + &-value { + position: relative; + overflow: hidden; + color: var(--cell-value-color); + text-align: right; + vertical-align: middle; + word-wrap: break-word; + + &-alone { + color: var(--cell-value-color); + text-align: left; + } + } + &-label { + margin-top: var(--fm-cell-margin); + color: var(--cell-label-color); + font-size: var(--cell-label-font-size); + line-height: var(--cell-label-line-height); + } + &-center { + align-items: center; + } + &-extra, + &-left-icon, + &-right-icon { + min-width: 1em; + font-size: var(--fm-cell-font-size); + line-height: var(--fm-cell-line-height); + display: flex; + align-items: center; + } + &-left-icon { + margin-right: var(--fm-cell-margin); + } + &-extra, + &-right-icon { + margin-left: var(--fm-cell-margin); + } + &-noborder { + .fm-cell::after { + display: none !important; + } + } +} diff --git a/packages/mobile-ui-vue/components/theme/src/checkbox.scss b/packages/mobile-ui-vue/components/theme/src/checkbox.scss new file mode 100644 index 0000000000000000000000000000000000000000..7ee8ce523d340535bd693be86263a43ac18e0a59 --- /dev/null +++ b/packages/mobile-ui-vue/components/theme/src/checkbox.scss @@ -0,0 +1,22 @@ + +.fm-checkbox-group { + .fm-checkbox-horizontal { + display: flex; + overflow: visible; + text-align: left; + flex-wrap: wrap; + .fm-checkbox { + margin-top: 4px; + margin-bottom: 4px; + } + } +} +.fm-cell .fm-checkbox-group .fm-checkbox-vertical { + padding-left: 0; +} +.fm-input-control-right { + .fm-checkbox-horizontal { + justify-content: flex-end; + } +} + diff --git a/packages/mobile-ui-vue/components/theme/src/checker.scss b/packages/mobile-ui-vue/components/theme/src/checker.scss new file mode 100644 index 0000000000000000000000000000000000000000..48e9bba92bbbeb41f39ba47db0d380a3a92f2c2d --- /dev/null +++ b/packages/mobile-ui-vue/components/theme/src/checker.scss @@ -0,0 +1,94 @@ +:root { + --fm-checker-color: var(--fm-text-color); + --fm-checker-icon-color: var(--fm-text-color-2); + --fm-checker-icon-background: var(--fm-background-2); + --fm-checker-icon-radius: var(--fm-radius-md); + --fm-checker-checked-icon-color: var(--fm-primary-color); + --fm-checker-button-background: var(--fm-gray-2); + --fm-checker-disabled-color: var(--fm-disabled-color); + --fm-checker-disabled-icon-color: var(--fm-gray-1); +} + +.fm-checker { + display: flex; + align-items: center; + color: var(--fm-checker-color); + &-icon { + display: inline-block; + align-items: center; + .fm-icon { + display: block; + height: 20px; + width: 20px; + line-height: 18px; + font-size: 12px; + text-align: center; + border-radius: var(--fm-checker-icon-radius); + border: 1px solid var(--fm-checker-icon-color); + color: var(--fm-checker-icon-background); + background-color: var(--fm-checker-icon-background); + } + &-checked .fm-icon { + color: var(--fm-checker-icon-background); + border-color: var(--fm-checker-checked-icon-color); + background-color: var(--fm-checker-checked-icon-color); + } + &-round .fm-icon { + border-radius: 100%; + } + } + &-button { + font-size: 13px; + text-align: center; + border-radius: 14px; + color: var(--fm-checker-color); + background: var(--fm-checker-button-background); + &-checked { + color: var(--fm-checker-icon-background); + border-color: var(--fm-checker-color); + background-color: var(--fm-checker-checked-icon-color); + } + } + .fm-checker-label { + margin-left: 8px; + margin-right: 8px; + display: inline-block; + line-height: 20px; + } + &:first-child .fm-checker-button { + margin-left: 0; + } + .fm-checker-button { + line-height: 28px; + padding: 0 12px; + min-width: 60px; + margin-right: 0; + } + &-small { + .fm-checker-button { + line-height: 24px; + min-width: 45px; + padding: 0 9.5px; + } + } + &-readonly { + opacity: var(--fm-readonly-opacity); + } + &-disabled { + color: var(--fm-checker-disabled-color); + .fm-checker-icon { + .fm-icon { + border-color: var(--fm-checker-disabled-color); + background-color: var(--fm-checker-disabled-icon-color); + color: var(--fm-checker-disabled-icon-color); + } + } + .fm-checker-icon-checked { + .fm-icon { + background-color: var(--fm-checker-disabled-color); + border-color: var(--fm-checker-disabled-color); + } + } + } +} + diff --git a/packages/mobile-ui-vue/components/theme/src/collapse.scss b/packages/mobile-ui-vue/components/theme/src/collapse.scss new file mode 100644 index 0000000000000000000000000000000000000000..de845a3e34f33b4295bc9731a43a8d61ef5c359a --- /dev/null +++ b/packages/mobile-ui-vue/components/theme/src/collapse.scss @@ -0,0 +1,38 @@ +:root { + --fm-collapse-background: var(--fm-white); + --fm-collapse-title-color: var(--fm-text-color-2); +} + +.fm-collapse-item { + &-title { + font-weight: 500; + &-state-icon { + transition: transform var(--fm-duration-base); + } + } + &-content-wrapper { + display: block; + overflow: hidden; + transition: height var(--fm-duration-base) ease-in-out; + will-change: height; + .fm-collapse-item-content { + display: block; + } + } +} +.fm-collapse-item-bottom { + .fm-collapse-item-title { + .fm-collapse-item-cell { + display: flex; + justify-content: center; + align-items: center; + padding: 12px 16px; + color: var(--fm-collapse-title-color); + font-size: 13px; + background-color: var(--fm-collapse-background); + } + &-state-icon{ + margin-right: 6px; + } + } +} diff --git a/packages/mobile-ui-vue/components/theme/src/dialog.scss b/packages/mobile-ui-vue/components/theme/src/dialog.scss new file mode 100644 index 0000000000000000000000000000000000000000..5fe933dba1351a93421c8f6dc28493e3ee8b878d --- /dev/null +++ b/packages/mobile-ui-vue/components/theme/src/dialog.scss @@ -0,0 +1,107 @@ +@import './mixins/hairline'; + +:root { + --fm-dialog-background: var(--fm-background-2); + --fm-dialog-padding-top: 24px; + --fm-dialog-padding-left: 16px; + --fm-dialog-header-font-size: 17px; + --fm-dialog-header-line-height: 24px; + --fm-dialog-content-font-size: 15px; + --fm-dialog-content-line-height: 20px; + --fm-dialog-footer-height: 50px; +} + +@media screen and (min-width: 375px) { + .fm-dialog { + width: 320px; + } +} +@media screen and (min-width: 280px) and (max-width: 375px) { + .fm-dialog { + width: 240px; + } +} +.fm-dialog{ + display: flex; + flex-direction: column; + background-color: var(--fm-dialog-background); + overflow: hidden; + &-header{ + padding-top: var(--fm-dialog-padding-top); + padding-left: var(--fm-dialog-header-padding-left); + padding-right: var(--fm-dialog-header-padding-left); + font-weight: var(--fm-font-bold-light); + font-size: var(--fm-dialog-header-font-size); + color: var(--fm-text-color); + line-height: var(--fm-dialog-header-line-height); + text-align: center; + } + &-content{ + max-height: 70vh; + overflow-y: auto; + &-message{ + padding: var(--fm-dialog-padding-top) var(--fm-dialog-padding-left); + font-size: var(--fm-dialog-content-font-size); + line-height: var(--fm-dialog-content-line-height); + white-space: pre-wrap; + text-align: center; + word-wrap: break-word; + } + &-message-has-title{ + padding-top: 11px; + color: var(--fm-text-color-light); + } + } + &-content-prompt{ + padding: 14px; + &-input{ + display: block; + } + } + &-footer{ + display: flex; + flex-direction: row; + align-items: center; + @include hairline('top', var(--fm-border-color)); + .fm-button{ + border:0; + height: var(--fm-dialog-footer-height); + @include hairline('right', var(--fm-border-color)); + &:last-child{ + @include hairline-remove('right'); + } + &.fm-button-default{ + color: var(--fm-text-color); + } + } + &.fm-dialog-footer-is-column{ + flex-direction: column; + .fm-button{ + @include hairline('top', var(--fm-border-color)); + @include hairline-remove('right'); + &:first-child{ + @include hairline-remove('top'); + } + } + } + } + &.fm-dialog-relative{ + position: relative; + .fm-dialog-header{ + padding-right: 40px; + } + } + .fm-dialog-close{ + position: absolute; + right: 16px; + top: 16px; + width: 22px; + height: 22px; + line-height: 22px; + text-align: center; + .fm-icon{ + font-size: 15px; + color: var(--fm-text-color-2); + } + } +} \ No newline at end of file diff --git a/packages/mobile-ui-vue/components/theme/src/discussion-group.scss b/packages/mobile-ui-vue/components/theme/src/discussion-group.scss new file mode 100644 index 0000000000000000000000000000000000000000..0701f00d2df9ed801b7e1633315ce784179621a3 --- /dev/null +++ b/packages/mobile-ui-vue/components/theme/src/discussion-group.scss @@ -0,0 +1,271 @@ +@import './mixins/hairline'; + +:root { + --fm-discussion-editor-primary-color: var(--fm-primary-color); +} + +.fm-discussion-editor{ + padding: 0 16px; + color: #333; + font-size: 16px; + &-reply{ + padding-bottom: 10px; + font-size: 14px; + .editor-reply-text{ + color: var(--fm-discussion-editor-primary-color); + } + } + &-input{ + background-color: #fff; + // @include hairline('all', $border-color-base); + .fm-discussion-editor-textarea{ + height: 130px; + padding: 10px; + line-height: 24px; + background-color: #f6f6f6; + outline: none; + overflow-y: auto; + word-break: break-all; + white-space: normal; + a{ + color: var(--fm-discussion-editor-primary-color); + } + &:empty::before{ + content:attr(placeholder); + color: #cccccc; + } + } + } + &-buttom{ + display: flex; + flex-direction: row; + justify-content: space-between; + align-items: center; + // padding: 8px 14px 8px 0; + height: 44px; + // background-color: $discussion-editor-buttom-background; + .fm-discussion-editor-toolbar{ + padding-right: 20px; + line-height: 44px; + font-size: 16px; + .fm-icon{ + font-size: 24px; + color: #666666; + } + } + .fm-discussion-editor-text{ + padding-right: 10px; + font-size: 16px; + color: var(--fm-discussion-editor-primary-color); + } + } +} + +.fm-discussion-list{ + padding: 0 16px; + background-color: #fff; + &-item{ + display: flex; + flex-direction: row; + align-items: flex-start; + padding-bottom: 20px; + .list-item-avatar{ + width: 36px; + height: 36px; + margin-right: 14px; + &-image{ + display: block; + width: 100%; + height: 100%; + border-radius: 50%; + } + &-image-tip{ + width: 100%; + height: 100%; + line-height: 36px; + font-size: 14px; + color: #fff; + text-align: center; + border-radius: 50%; + background-color: var(--fm-discussion-editor-primary-color); + } + } + .list-item-content{ + flex: 1 1 0; + .list-item-name{ + line-height: 18px; + margin-bottom: 6px; + font-size: 13px; + font-weight: 600; + } + .list-item-text{ + margin-bottom: 4px; + line-height: 22px; + font-size: 15px; + a{ + color: var(--fm-discussion-editor-primary-color); + } + } + .list-item-reply{ + margin-bottom: 6px; + padding: 8px; + font-size: 0; + background: #f7f8fb; + border-radius: 4px; + &-title{ + font-size: 14px; + .list-item-reply-name{ + color: var(--fm-discussion-editor-primary-color); + } + } + &-content{ + line-height: 20px; + font-size: 14px; + color: #666666; + } + } + .list-item-buttom{ + display: flex; + align-items: center; + align-items: center; + .list-item-date{ + line-height: 18px; + margin-right: 12px; + color: #999999; + } + .list-item-btn{ + padding: 0 12px; + background: #EBF6FF; + border-radius: 10px; + line-height: 20px; + color: var(--fm-discussion-editor-primary-color); + &-tip{ + padding: 0 2px; + } + } + } + } + } + &-title{ + padding: 12px 0 16px; + font-size: 16px; + color: #000000; + } +} + +.fm-discussion-group{ + padding: 7px 19px 6px; + background: #ffffff; + @include hairline('top'); + .fm-discussion-group-main{ + display: flex; + flex-direction: row; + align-items: center; + .fm-discussion-group-text{ + flex: 1 1 0; + padding: 0 12px; + line-height: 32px; + background: #f6f6f6; + font-size: 16px; + color: #999; + border-radius: 16px; + } + .fm-discussion-group-message{ + flex-shrink: 0; + padding-left: 20px; + font-size: 16px; + color: #333; + .fm-icon{ + margin-right: 6px; + font-size: 18px; + } + } + } +} + +.fm-discussion-group-toolbar{ + display: flex; + flex-direction: row; + align-items: center; + justify-content: space-between; + padding: 12px 16px; + @include hairline('top'); + .fm-toolbar-btn{ + line-height: 24px; + font-size: 17px; + color: #3A90FF; + } + .fm-toolbar-text{ + line-height: 26px; + font-size: 19px; + } +} + +.fm-discussion-group-close{ + display: flex; + justify-content: flex-end; + position: absolute; + right: 16px; + top: 7px; + .fm-close-btn{ + height: 30px; + width: 30px; + line-height: 30px; + text-align: center; + .fm-icon{ + font-size: 16px; + color: #999; + } + } +} +.fm-discussion-list-popup{ + top: 20px; + border-radius: 14px 14px 0 0; + .fm-discussion-list-content{ + display: flex; + flex-direction: column; + // justify-content: space-between; + height: 100%; + padding-bottom: 50px; + position: relative; + padding-top: 44px; + .fm-discussion-footer{ + position: absolute; + left: 0; + right: 0; + bottom: 0; + } + } + .fm-discussion-list-count{ + position: absolute; + left: 50%; + top: 10px; + transform: translateX(-50%); + line-height: 24px; + font-size: 17px; + color: #333; + } + .fm-discussion-list-main{ + .fm-discussion-list-item{ + padding: 12px 16px 16px; + @include hairline('top'); + @include hairline('bottom'); + } + } + .fm-discussion-list-reply-text{ + padding: 12px 16px 16px; + color: #000; + font-size: 16px; + font-weight: 600; + } + .fm-discussion-footer{ + flex-shrink: 0; + } +} +.fm-discussion-list{ + // max-height: calc(100vh - 99px); + overflow-y: auto; +} +.fm-discussion-list-overlay{ + height: calc( 100% - 45px); +} \ No newline at end of file diff --git a/packages/mobile-ui-vue/components/theme/src/dropdown.scss b/packages/mobile-ui-vue/components/theme/src/dropdown.scss new file mode 100644 index 0000000000000000000000000000000000000000..a7bc9ee4c06fa2411d6263e3e418d852aba5ebf7 --- /dev/null +++ b/packages/mobile-ui-vue/components/theme/src/dropdown.scss @@ -0,0 +1,132 @@ +.fm-dropdown-menu { + user-select: none; + color: #333333; + &-bar { + position: relative; + display: flex; + height: 48px; + background-color: #fff; + box-shadow: 0 2px 12px rgba(100,101,102,0.12); + + &-opened { + z-index: 10; + } + } + + &-item { + display: flex; + flex: 1; + align-items: center; + justify-content: center; + min-width: 0; // hack for flex ellipsis + cursor: pointer; + + &:active { + opacity: 1; + } + + &.fm-dropdown-menu-item-disabled { + &:active { + opacity: 1; + } + + .fm-dropdown-menu-title { + color: #ccc; + &::after{ + color: #ccc; + } + } + } + } + + &-title { + position: relative; + box-sizing: border-box; + max-width: 100%; + padding: 0 8px; + font-size: 16px; + line-height: 22px; + + &::after { + position: absolute; + top: 50%; + right: -4px; + margin-top: -5px; + border: 3px solid; + border-color: transparent transparent #888 #888; + transform: rotate(-45deg); + opacity: 0.8; + content: ''; + } + + &-active { + color: var(--fm-primary-color); + + &::after { + border-color: transparent transparent currentColor currentColor; + } + } + + &-down { + &::after { + margin-top: -1px; + transform: rotate(135deg); + } + } + + &-text{ + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; + } + } + } + + + .fm-dropdown-item { + position: fixed; + right: 0; + left: 0; + z-index: 10; + overflow: hidden; + &-icon { + display: block; + line-height: inherit; + } + + &-option { + text-align: left; + + &-active { + color: var(--fm-primary-color); + + .fm-dropdown-item-icon { + color: var(--fm-primary-color); + } + } + &-disabled{ + color: --fm-disabled-color + } + .fm-cell-value{ + .fm-icon{ + color: var(--fm-primary-color); + } + } + } + + &-up { + top: 0; + } + + &-down { + bottom: 0; + } + + &-content { + position: absolute; + max-height: 80%; + } + .fm-dropdown-item-overlay{ + position: absolute; + } + } \ No newline at end of file diff --git a/packages/mobile-ui-vue/components/theme/src/filter.scss b/packages/mobile-ui-vue/components/theme/src/filter.scss new file mode 100644 index 0000000000000000000000000000000000000000..d066b3b98b1c1fb8a046b00ecfcf6e67bf9d3b2d --- /dev/null +++ b/packages/mobile-ui-vue/components/theme/src/filter.scss @@ -0,0 +1,347 @@ +@import './mixins/hairline'; +@import './mixins/ellipsis'; + +:root { + --fm-filter-color: var(--fm-text-color); + --fm-filter-color-sub: var(--fm-text-color-2); + --fm-filter-primary-color: var(--fm-primary-color); + --fm-filter-panel-background: var(--fm-background-2); + --fm-filter-panel-sub-font-size: 13px; + --fm-filter-panel-sub-icon-font-size: 12px; +} + +.fm-filter-panel { + width: 100%; + height: 100%; + background-color: var(--fm-filter-panel-background); + overflow: auto; + transform: translate3d(0,0,0); + &-content { + height: 100%; + box-sizing: border-box; + padding-bottom: 250px; + overflow-y: auto; + } + &-field { + padding: 8px 16px 16px 16px;; + overflow-x: hidden; + &-title { + display:flex; + align-items: center; + justify-content: space-between; + color: var(--fm-filter-color); + line-height: 22px; + // position: relative; + &-text{ + flex-shrink:0; + padding-right:10px; + } + &-text-required::after{ + padding-left: 2px; + color: var(--fm-danger-color); + font-size: var(--fm-filter-panel-sub-font-size); + content: '*'; + } + + &-sub { + display: flex; + justify-content: flex-end; + flex: 1 1 0; + align-items: center; + height: 100%; + font-size: var(--fm-filter-panel-sub-font-size); + overflow:hidden; + &-text { + color: var(--fm-filter-primary-color); + max-width: 160px; + @include ellipsis + } + + &-button { + display: flex; + align-items: center; + flex-shrink: 0; + margin-left: 8px; + &-text { + display: flex; + margin-right: 4px; + color: var(--fm-filter-color-sub); + } + } + &-icon { + font-size: var(--fm-filter-panel-sub-icon-font-size); + } + &-lookup { + display: flex; + align-items: center; + } + } + } + + &-content { + padding-top: 12px; + } + &-input { + padding: 6px 8px; + line-height: 18px; + background: var(--fm-background); + font-size: var(--fm-filter-panel-sub-font-size); + border-radius: var(--fm-radius-md); + color: var(--fm-filter-primary-color); + text-align: center; + .fm-input-value .fm-input-body .fm-input-control { + font-size: var(--fm-filter-panel-sub-font-size); + color: var(--fm-filter-primary-color); + } + } + &-range { + display: flex; + align-items: center; + width: 100%; + } + &-split { + width: 8px; + margin: 0 8px; + border: 1px solid var(--fm-filter-color-sub); + } + &-lookup-panel { + width: 320px; + } + &-number-list { + padding-top: 10px; + } + &-error-message { + font-size: var(--fm-filter-panel-sub-font-size);; + line-height: 24px; + color: var(--fm-danger-color); + } + } + &-footer { + position: absolute; + bottom: 0; + left: 0; + right: 0; + height: 54px; + + padding: 8px 16px; + background: var(--fm-background-2); + box-shadow: 0 -2px 6px 0 var(--fm-box-shadow-color); + z-index: var(--fm-zindex-1); + .button-wrapper { + width: 100%; + display: flex; + align-items: center; + justify-content: space-between; + .button { + flex: 1; + height: 38px; + &:first-child { + color: var(--fm-filter-primary-color); + border: 1px solid var(--fm-filter-primary-color); + border-radius: 20px 0 20px 20px; + z-index: var(--fm-zindex-3); + } + &:last-child { + margin-left: -15px; + border-radius: 0 20px 20px 0; + } + } + } + } + .bgc-red { + background-color: var(--fm-danger-color); + color: var(--fm-background-2); + } + .bgc-blue { + background-color: var(--fm-filter-primary-color); + color: var(--fm-background-2); + } + &-list { + &-line { + display: flex; + &:not(:last-child) { + margin-bottom: 10px; + } + } + &-item { + display: flex; + align-items: center; + justify-content: center; + height: 30px; + width: 90px; + padding: 6px 8px; + line-height: 18px; + background: var(--fm-background); + font-size: var(--fm-filter-panel-sub-font-size); + border-radius: var(--fm-radius-md); + color: var(--fm-filter-primary-color); + overflow: hidden; + &:not(:first-child) { + margin-left: 10px; + } + &-selected { + background: var(--fm-filter-primary-color); + color: var(--fm-background-2); + } + } + } +} +.fm-filter-simple-panel { + height: 100%; + .content { + display: flex; + height: 100%; + .menu { + width: 105px; + height: 100%; + display: flex; + flex-direction: column; + background: #F1F2F5; + overflow: auto; + .menu-item { + background-color: #fff; + .menu-item-cell { + background-color: #F1F2F5; + } + } + .menu-item-selected { + .menu-item-cell { + background-color: #fff; + } + } + .menu-item-selected-prev { + .menu-item-cell { + border-radius: 0 0 12px 0; + } + } + .menu-item-selected-next { + .menu-item-cell { + border-radius: 0 12px 0 0; + } + } + } + .list{ + display: flex; + flex: 1; + flex-direction: column; + .list-item { + display: flex; + width: 100%; + .list-item-icon { + color: var(--fm-filter-primary-color); + } + } + } + } + +} +.fm-filter-bar-panel { + position: relative; + padding-bottom: 54px; + background-color: var(--fm-background-2); + .fm-filter-panel-extra { + padding-top: 12px; + } +} +.fm-filter { + .fm-filter-search-button { + display: flex; + align-items: center; + flex-shrink: 0; + color: var(--fm-gray-7); + font-size: 14px; + line-height: 20px; + .fm-filter-button-text { + padding-right: 2px; + } + .fm-filter-icon { + font-size: 20px; + } + } + .fm-filter-search-container { + position: relative; + padding: 0 16px; + display: flex; + flex-direction: row; + align-items: center; + background: var(--fm-background-2); + .fm-filter-search-button { + margin: 0 8px 0 0; + } + .fm-filter-search-input { + flex: 1 1 0; + .fm-search { + padding: 8px 0; + } + } + } + .fm-filter-only-icon { + display: inline-block; + } + + .fm-state-active { + color: var(--fm-filter-primary-color); + } +} +.fm-filter-popup { + width: 320px; +} +.fm-filter-popup-drop { + width: 100%; + height: 200px; + overflow: hidden; +} + +.filter-cell.van-cell:last-child::after, +.filter-cell .van-cell:last-child::after { + display: block; +} +.fm-filter-right { + .fm-filter-search-container { + flex-direction: row-reverse; + .fm-filter-search-button { + margin: 0 0 0 8px; + } + } +} + +.fm-filter-bar { + display: flex; + padding: 11px 16px; + &-item { + display: flex; + align-items: center; + height: 28px; + font-size: 13px; + line-height: 18px; + background: rgba(42,135,255,0.06); + overflow: hidden; + border-radius: 13px; + padding: 0 12px; + &-value, + &-name { + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + } + &-value { + color: var(--fm-filter-primary-color); + } + &-name { + color: var(--fm-gray-7); + } + &-noshrink { + flex-shrink: 0; + } + &:not(:first-child) { + margin-left: 12px; + } + } + &-item { + .fm-icon { + color: var(--fm-filter-color-sub); + margin-left: 8px; + font-size: 12px; + } + } +} \ No newline at end of file diff --git a/packages/mobile-ui-vue/components/theme/src/html-panel.scss b/packages/mobile-ui-vue/components/theme/src/html-panel.scss new file mode 100644 index 0000000000000000000000000000000000000000..d305731c75a94037d855cdbc4fa96c2bdf032431 --- /dev/null +++ b/packages/mobile-ui-vue/components/theme/src/html-panel.scss @@ -0,0 +1,35 @@ +.fm-html-panel { + box-sizing: border-box; + line-height: 1.42; + outline: none; + overflow-y: auto; + tab-size: 4; + text-align: left; + white-space: pre-wrap; + word-wrap: break-word; + img { + max-width: 100%; + } + li::before { + display: inline-block; + white-space: nowrap; + width: 1.2em; + } + ul, + ol { + padding-left: 1.5em; + } + ul > li::before { + content: '\2022'; + } + ol { + li { + counter-reset: list-1 list-2 list-3 list-4 list-5 list-6 list-7 list-8 + list-9; + counter-increment: list-0; + } + li:before { + content: counter(list-0, decimal) '. '; + } + } +} diff --git a/packages/mobile-ui-vue/components/theme/src/icon.scss b/packages/mobile-ui-vue/components/theme/src/icon.scss new file mode 100644 index 0000000000000000000000000000000000000000..e6b2f5e188d80eaa19ee7488604654bf1eb9c351 --- /dev/null +++ b/packages/mobile-ui-vue/components/theme/src/icon.scss @@ -0,0 +1,727 @@ +@font-face { + font-family: 'farrisMobile'; + font-style: normal; + font-weight: normal; + src: url('./fonts/farris-mobile-icon.ttf?v=20230515') format('truetype'); +} +:root { + --fm-icon-font-size: 14px; + --fm-icon-color: inherit; +} +.fm-icon { + font-family: 'farrisMobile' !important; + font-size: 14px; + font-style: normal; + color: var(--fm-icon-color); + display: inline-block; + width: 1em; + height: 1em; + font-weight: 400; + line-height: 1; + vertical-align: middle; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} +.fm-icon::before{ + display: inline-block; +} + +.fm-icon-filter::before { + content: '\e697'; +} +.fm-icon-cardfold::before { + content: '\e6b7'; +} + +.fm-icon-cardunfold::before { + content: '\e6b8'; +} + +.fm-icon-trafficother::before { + content: '\e6b9'; +} + +.fm-icon-bottomsave::before { + content: '\e6ba'; +} + +.fm-icon-trafficboat::before { + content: '\e6bb'; +} + +.fm-icon-trafficcar::before { + content: '\e6bc'; +} + +.fm-icon-trafficplane::before { + content: '\e6bd'; +} + +.fm-icon-traffictrain::before { + content: '\e6be'; +} + +.fm-icon-trafficbus::before { + content: '\e6bf'; +} + +.fm-icon-addgray::before { + content: '\e6a7'; +} + +.fm-icon-close::before { + content: '\e6a8'; +} + +.fm-icon-add-line::before { + content: '\e6a9'; +} + +.fm-icon-more::before { + content: '\e6aa'; +} + +.fm-icon-check::before { + content: '\e6ab'; +} + +.fm-icon-backcircle::before { + content: '\e6ac'; +} + +.fm-icon-agree::before { + content: '\e6ad'; +} + +.fm-icon-loading::before { + content: '\e6ae'; +} + +.fm-icon-filedel::before { + content: '\e6af'; +} + +.fm-icon-file::before { + content: '\e6b0'; +} + +.fm-icon-processflow::before { + content: '\e6b1'; +} + +.fm-icon-redstar::before { + content: '\e6b2'; +} + +.fm-icon-rightcircle::before { + content: '\e6b3'; +} + +.fm-icon-timecircle::before { + content: '\e6b4'; +} + +.fm-icon-screening::before { + content: '\e6b5'; +} + +.fm-icon-uncheck::before { + content: '\e6b6'; +} + +.fm-icon-operation::before { + content: '\e02c'; +} + +.fm-icon-approvalamount::before { + content: '\e02b'; +} + +.fm-icon-agreed::before { + content: '\e02a'; +} + +.fm-icon-loading::before { + content: '\e6ae'; +} + +.fm-icon-filedel::before { + content: '\e6af'; +} + +.fm-icon-file::before { + content: '\e6b0'; +} + +.fm-icon-processflow::before { + content: '\e6b1'; +} + +.fm-icon-redstar::before { + content: '\e6b2'; +} + +.fm-icon-rightcircle::before { + content: '\e6b3'; +} + +.fm-icon-timecircle::before { + content: '\e6b4'; +} + +.fm-icon-screening::before { + content: '\e6b5'; +} + +.fm-icon-uncheck::before { + content: '\e6b6'; +} + +.fm-icon-operation::before { + content: '\e02c'; +} + +.fm-icon-approvalamount::before { + content: '\e02b'; +} + +.fm-icon-agreed::before { + content: '\e02a'; +} + +.fm-icon-inprocess::before { + content: '\e029'; +} + +.fm-icon-feedback::before { + content: '\e028'; +} + +.fm-icon-print::before { + content: '\e027'; +} + +.fm-icon-important::before { + content: '\e026'; +} + +.fm-icon-amountofreimbursement::before { + content: '\e025'; +} + +.fm-icon-safetyassistant::before { + content: '\e024'; +} + +.fm-icon-remind::before { + content: '\e023'; +} + +.fm-icon-eyeoppen::before { + content: '\e022'; +} + +.fm-icon-eyeclose::before { + content: '\e01e'; +} + +.fm-icon-photography::before { + content: '\e021'; +} + +.fm-icon-photograph::before { + content: '\e020'; +} + +.fm-icon-addpicture::before { + content: '\e01f'; +} + +.fm-icon-top_other-face::before { + content: '\e01d'; +} + +.fm-icon-top_other::before { + content: '\e01c'; +} + +.fm-icon-delete::before { + content: '\e01b'; +} + +.fm-icon-nextpage::before { + content: '\e01a'; +} + +.fm-icon-addbutton::before { + content: '\e019'; +} + +.fm-icon-waitforprocessing::before { + content: '\e018'; +} + +.fm-icon-warningmessage::before { + content: '\e017'; +} + +.fm-icon-failureprompt::before { + content: '\e016'; +} + +.fm-icon-successfulhints::before { + content: '\e015'; +} + +.fm-icon-other::before { + content: '\e014'; +} + +.fm-icon-retract::before { + content: '\e013'; +} + +.fm-icon-drop-down::before { + content: '\e012'; +} + +.fm-icon-cancel::before { + content: '\e011'; +} + +.fm-icon-search::before { + content: '\e010'; +} + +.fm-icon-multiplechoice::before { + content: '\e00f'; +} + +.fm-icon-singlechoice::before { + content: '\e00e'; +} + +.fm-icon-microphone::before { + content: '\e00d'; +} + +.fm-icon-arrow-chevron-left::before { + content: '\e00c'; +} + +.fm-icon-helpcenter::before { + content: '\e00b'; +} + +.fm-icon-sweepcode::before { + content: '\e00a'; +} + +.fm-icon-groupchat::before { + content: '\e009'; +} + +.fm-icon-addfriend::before { + content: '\e008'; +} + +.fm-icon-top_my::before { + content: '\e007'; +} + +.fm-icon-top_my-face::before { + content: '\e006'; +} + +.fm-icon-top_friend::before { + content: '\e005'; +} + +.fm-icon-top_friend-face::before { + content: '\e004'; +} + +.fm-icon-top_publicpraise::before { + content: '\e003'; +} + +.fm-icon-top_publicpraise-face::before { + content: '\e002'; +} + +.fm-icon-top_home::before { + content: '\e001'; +} + +.fm-icon-top_home-face::before { + content: '\e000'; +} + +/* 标准模板内图标 */ +.fm-icon-s-agree-o::before { + content: '\e655'; +} + +.fm-icon-s-arrow-down::before { + content: '\e656'; +} + +.fm-icon-s-add-o::before { + content: '\e657'; +} + +.fm-icon-s-annex::before { + content: '\e658'; +} + +.fm-icon-s-arrow::before { + content: '\e659'; +} + +.fm-icon-s-arrow-up::before { + content: '\e65e'; +} + +.fm-icon-s-checkbox-checked::before { + content: '\e65f'; +} + +.fm-icon-s-checkbox::before { + content: '\e660'; +} + +.fm-icon-s-arrow-left::before { + content: '\e661'; +} + +.fm-icon-s-exchange::before { + content: '\e662'; +} + +.fm-icon-s-clear::before { + content: '\e663'; +} + +.fm-icon-s-checked::before { + content: '\e664'; +} + +.fm-icon-s-eye-o::before { + content: '\e665'; +} + +.fm-icon-s-close-eye::before { + content: '\e666'; +} + +.fm-icon-s-at::before { + content: '\e667'; +} + +.fm-icon-s-feedback-o::before { + content: '\e668'; +} + +.fm-icon-s-fold-circle-o::before { + content: '\e669'; +} + +.fm-icon-s-cross::before { + content: '\e66a'; +} + +.fm-icon-s-minus::before { + content: '\e66b'; +} + +.fm-icon-s-file::before { + content: '\e66c'; +} + +.fm-icon-s-fold-triangle::before { + content: '\e66d'; +} + +.fm-icon-s-filter::before { + content: '\e66e'; +} + +.fm-icon-s-forword::before { + content: '\e66f'; +} + +.fm-icon-s-plus::before { + content: '\e670'; +} + +.fm-icon-s-filedel::before { + content: '\e671'; +} + +.fm-icon-s-fold-o::before { + content: '\e672'; +} + +.fm-icon-s-image-o::before { + content: '\e673'; +} + +.fm-icon-s-more-o::before { + content: '\e674'; +} + +.fm-icon-s-redio-circle::before { + content: '\e675'; +} + +.fm-icon-s-reject-o::before { + content: '\e676'; +} + +.fm-icon-s-success::before { + content: '\e677'; +} + +.fm-icon-s-refresh::before { + content: '\e678'; +} + +.fm-icon-s-star::before { + content: '\e679'; +} +.fm-icon-s-star-o::before { + content: '\e612'; +} + +.fm-icon-s-processflow::before { + content: '\e67a'; +} + +.fm-icon-s-unfold-circle-o::before { + content: '\e67b'; +} + +.fm-icon-s-rewind::before { + content: '\e67c'; +} + +.fm-icon-s-unfold-o::before { + content: '\e67d'; +} + +.fm-icon-s-save-o::before { + content: '\e67e'; +} + +.fm-icon-s-warning-o::before { + content: '\e67f'; +} + +.fm-icon-s-unfold-triangle::before { + content: '\e680'; +} + +.fm-icon-s-print-o::before { + content: '\e681'; +} + +.fm-icon-s-search-o::before { + content: '\e682'; +} + + +.fm-icon-s-news::before { + content: '\e683'; +} + +.fm-icon-s-news-o::before { + content: '\e684'; +} + +.fm-icon-s-shop::before { + content: '\e68c'; +} + +.fm-icon-s-sending::before { + content: '\e60b'; +} + +.fm-icon-s-import-o::before { + content: '\e60c'; +} + +.fm-icon-s-edit-o::before { + content: '\e60d'; +} + +.fm-icon-s-qrcode::before { + content: '\e60e'; +} + +.fm-icon-s-briefcase::before { + content: '\e60f'; +} + +.fm-icon-s-notificationoff::before { + content: '\e610'; +} + +.fm-icon-s-pencil::before { + content: '\e611'; +} + +.fm-icon-s-star-o::before { + content: '\e612'; +} + +.fm-icon-s-barcode::before { + content: '\e613'; +} + +.fm-icon-s-salemessage-o::before { + content: '\e614'; +} + +.fm-icon-s-listview-o::before { + content: '\e615'; +} + +.fm-icon-s-picture-o::before { + content: '\e616'; +} + +.fm-icon-s-savefillet-o::before { + content: '\e617'; +} + +.fm-icon-s-shoppingcart::before { + content: '\e618'; +} + +.fm-icon-s-pending::before { + content: '\e61d'; +} + +.fm-icon-s-expandview-o::before { + content: '\e61e'; +} + +.fm-icon-s-lock-o::before { + content: '\e623'; +} + +.fm-icon-s-my::before { + content: '\e692'; +} + +.fm-icon-s-service::before { + content: '\e633'; +} + +.fm-icon-s-wallet-o::before { + content: '\e634'; +} + +.fm-icon-s-shoppingcart-o::before { + content: '\e636'; +} + +.fm-icon-s-setting-o::before { + content: '\e637'; +} + +.fm-icon-s-my-o::before { + content: '\e696'; +} + +.fm-icon-s-unfoldrec-o::before { + content: '\e639'; +} + +.fm-icon-s-profile::before { + content: '\e63a'; +} + +.fm-icon-s-link-o::before { + content: '\e609'; +} + +.fm-icon-s-usersetting-o::before { + content: '\e632'; +} + +.fm-icon-s-shop-o::before { + content: '\e68a'; +} + +.fm-icon-s-list::before { + content: '\e62a'; +} + +.fm-icon-s-location-o::before { + content: '\e685'; +} + +.fm-icon-s-location::before { + content: '\e686'; +} + +.fm-icon-s-moment::before { + content: '\e689'; +} + +.fm-icon-s-moment-o::before { + content: '\e68b'; +} + +.fm-icon-s-revoke-o::before { + content: '\e687'; +} + +.fm-icon-s-submit-o::before { + content: '\e688'; +} + +.fm-icon-s-app-o::before { + content: '\e68f'; +} + +.fm-icon-s-app::before { + content: '\e691'; +} + +.fm-icon-s-book-o::before { + content: '\e695'; +} + +.fm-icon-s-book::before { + content: '\e690'; +} + +.fm-icon-s-comment::before { + content: '\e693'; +} + +.fm-icon-s-comment-o::before { + content: '\e694'; +} + +.fm-icon-s-illustrate-o::before { + content: '\e68d'; +} + +.fm-icon-s-clear-o::before { + content: '\e68e'; +} +.fm-icon-friend::before { + content: '\e005'; +} +.fm-icon-scan::before { + content: '\e69a'; +} +.fm-icon-back::before { + content: '\e69b'; +} +.fm-icon-menu::before { + content: '\e69d'; +} \ No newline at end of file diff --git a/packages/mobile-ui-vue/components/theme/src/image-preview.scss b/packages/mobile-ui-vue/components/theme/src/image-preview.scss new file mode 100644 index 0000000000000000000000000000000000000000..7c9bbd259cb0bb1733031758746e83611cbcee5e --- /dev/null +++ b/packages/mobile-ui-vue/components/theme/src/image-preview.scss @@ -0,0 +1,107 @@ +.fm-image-preview { + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + background-color: transparent; + transform: none; + + &-swipe { + height: 100%; + + &-item { + display: flex; + align-items: center; + justify-content: center; + overflow: hidden; + } + } + + &-cover { + position: absolute; + top: 0; + left: 0; + } + + &-image { + width: 100%; + transition-property: transform; + + &-vertical { + width: auto; + height: 100%; + } + + img { + // disable desktop browser image drag + -webkit-user-drag: none; + } + + .fm-image { + &-error { + top: 30%; + height: 40%; + } + + &-error-icon { + font-size: 36px; + } + + &-loading { + background-color: transparent; + } + } + } + + &-index { + position: absolute; + top: 16px; + left: 50%; + color: #ffffff; + font-size: 13px; + line-height: 22px; + text-shadow: 0 1px 1px #333; + transform: translate(-50%, 0); + } + + &-overlay { + background-color: rgba(0, 0, 0, 0.9); + } + + &-close-icon { + position: absolute; + z-index: 1; + cursor: pointer; + .fm-icon{ + color: #ccc; + font-size: 22px; + } + + &:active { + .fm-icon{ + color: #999999; + } + } + + &-top-left { + top: 16px; + left: 16px; + } + + &-top-right { + top: 16px; + right: 16px; + } + + &-bottom-left { + bottom: 16px; + left: 16px; + } + + &-bottom-right { + right: 16px; + bottom: 16px; + } + } +} diff --git a/packages/mobile-ui-vue/components/theme/src/image.scss b/packages/mobile-ui-vue/components/theme/src/image.scss new file mode 100644 index 0000000000000000000000000000000000000000..822b48e966e35c0104f7f1ef0ea3cc116556ac60 --- /dev/null +++ b/packages/mobile-ui-vue/components/theme/src/image.scss @@ -0,0 +1,38 @@ +@import './mixins/hairline'; + +.fm-image { + position: relative; + display: inline-block; + + &-round { + overflow: hidden; + border-radius: 50%; + img { + border-radius: inherit; + } + } + &-img, + &-error, + &-loading { + display: block; + width: 100%; + height: 100%; + } + &-error, + &-loading { + position: absolute; + top: 0; + left: 0; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + color: var(--fm-text-color-2); + font-size: 14px; + background-color: var(--fm-background); + .fm-image-icon{ + font-size: var(--fm-font-size-icon-4); + color: var(--fm-text-color-2); + } + } +} diff --git a/packages/mobile-ui-vue/components/theme/src/index-list.scss b/packages/mobile-ui-vue/components/theme/src/index-list.scss new file mode 100644 index 0000000000000000000000000000000000000000..1ae04d1d87c22448fa1c443ed93dcdd1271c4e02 --- /dev/null +++ b/packages/mobile-ui-vue/components/theme/src/index-list.scss @@ -0,0 +1,33 @@ +.fm-index-list { + position: relative; + background: #fff; + height: 100%; + overflow: auto; + .fm-index-content{ + overflow: hidden; + .fm-index-group-title{ + background: #F7F8FA; + line-height: 32px; + padding: 0 16px; + } + } + .fm-index-bar { + position: fixed; + right: 4px; + top: 50%; + transform: translateY(-50%); + font-size: 12px; + line-height: 14px; + text-align: center; + z-index: 9; + .fm-index-bar-item { + padding: 2px 4px; + } + .fm-index-bar-item-selected { + color: #3A90FF; + } + } +} +.fm-index-list-fill { + height: 100%; +} \ No newline at end of file diff --git a/packages/mobile-ui-vue/components/theme/src/input-template.scss b/packages/mobile-ui-vue/components/theme/src/input-template.scss new file mode 100644 index 0000000000000000000000000000000000000000..c9997a0833b09b8497556815d8b622d3267d3c75 --- /dev/null +++ b/packages/mobile-ui-vue/components/theme/src/input-template.scss @@ -0,0 +1,81 @@ +.fm-lookup-input-template { + width: 100%; + height: 24px; + overflow: hidden; + display: flex; + align-items: flex-start; + justify-content: flex-end; + will-change: height; + transition: all .3s ease; + .text { + display: inline-block; + color: #007aff; + white-space: nowrap; + } + .text-ellipsis { + overflow: hidden; + flex: 1; + } + .append-text { + padding-left: 4px; + } + .hide-text { + position: absolute; + left: 0; + height: 100%; + opacity: 0; + } + .title { + width: 100%; + display: flex; + justify-content: flex-end; + position: relative; + } + .items { + flex: 1; + display: flex; + flex-shrink: 0; + flex-wrap: wrap; + width: 100%; + .item { + display: flex; + align-items: center; + margin: 2px; + padding: 1px 4px; + background-image: linear-gradient(-45deg, #f0f7ff 0%, #eef7ff 100%); + border-radius: 6px; + max-width: 100%; + .text { + line-height: 18px; + font-size: 14px; + } + } + } +} +.fm-lookup-input-template-expand { + justify-content: flex-start; + .text { + white-space: normal; + } + .items { + .item { + .text { + text-align: left; + } + } + } + +} +.fm-input-control-readonly { + .fm-lookup-input-template { + .title { + .text { + color: #333; + } + } + } +} +.fm-input-template-right-icon { + margin-right: -16px; + padding-right: 16px; +} \ No newline at end of file diff --git a/packages/mobile-ui-vue/components/theme/src/input.scss b/packages/mobile-ui-vue/components/theme/src/input.scss new file mode 100644 index 0000000000000000000000000000000000000000..e581f9a4ad97a6f1e7498eb79447a4afc99628c0 --- /dev/null +++ b/packages/mobile-ui-vue/components/theme/src/input.scss @@ -0,0 +1,131 @@ +@import './mixins/hairline'; + +:root { + --fm-input-size: 16px; + --fm-input-sub-size: 13px; + --fm-input-color: var(--fm-text-color); + --fm-input-sub-color: var(--fm-text-color-2); + --fm-input-readonly-color: var(--fm-gray-7); + --fm-input-disabled-color: var(--fm-gray-5); + --fm-input-border-color: var(--fm-gray-3); + --fm-input-label-width: 105px; + --fm-input-label-size: 16px; +} + +.fm-input { + &-label { + flex: none; + text-align: left; + width: var(--fm-input-label-width); + font-size: var(--fm-input-label-size); + color: var(--fm-input-color); + } + &-value { + overflow-y: visible; + .fm-input-body { + flex: 1; + display: flex; + align-items: center; + .fm-input-control { + display: flex; + width: 100%; + min-width: 0; + margin: 0; + padding: 0; + border: 0; + resize: none; + line-height: inherit; + background-color: transparent; + color: var(--fm-input-color); + font-size: var(--fm-input-size); + &::placeholder { + color: var(--fm-input-sub-color); + } + &:disabled { + opacity: 1; + cursor: not-allowed; + color: var(--fm-input-disabled-color); + -webkit-text-fill-color: currentColor; + } + &-readonly { + cursor: default; + color: var(--fm-input-readonly-color); + } + &-left { + justify-content: flex-start; + text-align: left; + } + &-center { + justify-content: center; + text-align: center; + } + + &-right { + justify-content: flex-end; + text-align: right; + } + } + } + .fm-input-body-with-border { + border: 1px solid var(--fm-input-border-color); + padding: 4px 8px; + border-radius: 4px; + } + } + &-clear, + &-button { + flex-shrink: 0; + } + &-clear { + margin-right: -8px; + // padding: 0 8px; + padding: 4px 8px; + color: var(--fm-input-sub-color); + font-size: var(--fm-input-size); + cursor: pointer; + box-sizing: content-box; + } + &-button { + padding-left: 8px; + } + &-min-height { + .fm-input-control { + min-height: 60px; + } + } + &-vertical { + flex-direction: column; + align-items: flex-start; + .fm-input-label { + width: auto!important; + } + .fm-cell-right { + width: 100%; + padding-top: 4px; + } + .fm-cell-value .fm-input-body .fm-input-control { + text-align: left; + justify-content: flex-start; + } + } + &-word-limit { + margin-top: 4px; + line-height: 18px; + text-align: right; + font-size: var(--fm-input-sub-size); + color: var(--fm-input-sub-color); + } + &-error-message { + color: var(--fm-danger-color); + font-size: var(--fm-input-sub-size); + } + &-error-message-left { + text-align: left; + } + &-error-message-center { + text-align: center; + } + &-error-message-right { + text-align: right; + } +} diff --git a/packages/mobile-ui-vue/components/theme/src/listview.scss b/packages/mobile-ui-vue/components/theme/src/listview.scss new file mode 100644 index 0000000000000000000000000000000000000000..c12af350558a4fce47ac2371841e2918fb81d534 --- /dev/null +++ b/packages/mobile-ui-vue/components/theme/src/listview.scss @@ -0,0 +1,106 @@ +@import './mixins/safe-area'; +:root { + +} + +.fm-listview-container { + .fm-listview-main { + user-select: none; + -webkit-user-select: none; + } + .fm-listview-item { + overflow: hidden; + display: flex; + position: relative; + .fm-listview-item-content { + flex: 1; + transform: translateX(0); + } + .checker-wrapper { + display: flex; + height: 100%; + padding: 12px 16px; + position: absolute; + } + } + .fm-listview-toolbar { + position: absolute; + bottom: 0; + left: 0; + right: 0; + display: flex; + flex-direction: row; + align-items: center; + .fm-listview-toolbar-item { + flex: 1; + } + } + .fm-listview-footer { + flex-shrink: 0; + } + .fm-listview-placeholder { + height: 0; + pointer-events: none; + } + .fm-listview-loading, + .fm-listview-finished, + .fm-listview-error, + .fm-listview-empty-text { + display: block; + color: #969799; + font-size: 14px; + line-height: 50px; + text-align: center; + } +} +.fm-listview-container-fill { + display: flex; + flex-direction: column; + flex-shrink: 1; + flex-grow: 1; + flex-basis: 0; + height: 100%; + overflow: hidden; + .fm-listview-main { + flex-shrink: 1; + flex-grow: 1; + flex-basis: 0; + overflow: auto; + -webkit-overflow-scrolling: touch; + } +} +.fm-listview-container-with-btn .fm-listview-main{ + padding-bottom: 42px; +} + +.fm-listview-container .fm-listview-subitem { + display: initial !important; + .fm-listview-subitem-title { + padding: 10px 16px; + line-height: 20px; + font-size: 14px; + color: #999999; + } + .fm-listview-sub-item { + position: relative; + overflow: hidden; + .fm-listview-subitem-content { + flex: 1; + transform: translateX(0); + } + &.fm-listview-sub-item-padding { + .fm-listview-subitem-content { + transform: translateX(40px); + } + } + &.fm-listview-sub-item-padding-none { + .fm-listview-subitem-content { + transform: translateX(0); + padding-left: 40px; + } + } + } +} +.fm-pull-refresh-fill { + flex: 1; +} \ No newline at end of file diff --git a/packages/mobile-ui-vue/components/theme/src/loading.scss b/packages/mobile-ui-vue/components/theme/src/loading.scss new file mode 100644 index 0000000000000000000000000000000000000000..b4aedb043512b789d098e1dfe7acf55d6a434468 --- /dev/null +++ b/packages/mobile-ui-vue/components/theme/src/loading.scss @@ -0,0 +1,69 @@ +@import './mixins/hairline'; + +:root { + --fm-loading-mask-zindex: var(--fm-zindex-4); + --fm-loading-zindex: var(--fm-zindex-5); + --fm-loading-color: var(--fm-text-color-3); + --fm-loading-text-color: var(--fm-text-color-2); + --fm-loading-text-size: 16px; +} + +.fm-loading-mask{ + position: absolute; + left: 0; + right: 0; + bottom: 0; + top: 0; + z-index: var(--fm-loading-mask-zindex); +} +.fm-loading { + display: flex; + flex-direction: row; + align-items: center; + position: absolute; + left: 50%; + top: 50%; + z-index: var(--fm-loading-zindex); + max-width: 70%; + padding: 16px; + color: var(--fm-loading-color); + font-size: 0; + line-height: 20px; + white-space: pre-wrap; + text-align: center; + word-wrap: break-word; + transform: translate3d(-50%, -50%, 0); + &-icon { + position: relative; + display: inline-block; + width: 30px; + height: 30px; + max-width: 100%; + max-height: 100%; + vertical-align: middle; + animation: fm-rotate 2s linear infinite; + circle { + animation: fm-circular 1.5s ease-in-out infinite; + stroke: currentColor; + stroke-width: 4; + stroke-linecap: round; + } + } + &-text { + display: inline-block; + margin-left: 8px; + color: var(--fm-loading-text-color); + font-size: var(--fm-loading-text-size); + line-height: 22px; + vertical-align: middle; + } + &.fm-loading-vertical{ + display: flex; + flex-direction: column; + align-items: center; + + .fm-loading-text { + margin: 9px 0 0; + } + } +} diff --git a/packages/mobile-ui-vue/components/theme/src/lookup.scss b/packages/mobile-ui-vue/components/theme/src/lookup.scss new file mode 100644 index 0000000000000000000000000000000000000000..14586939708ceab3e6eab331533889fb585ff762 --- /dev/null +++ b/packages/mobile-ui-vue/components/theme/src/lookup.scss @@ -0,0 +1,458 @@ +@import './mixins/hairline'; +:root { + --fm-lookup-panel-font-size: 16px; + --fm-lookup-panel-background: var(--fm-background); + --fm-lookup-panel-background-2: var(--fm-background-2); + --fm-lookup-panel-color: var(--fm-text-color); + --fm-lookup-panel-sub-color: var(--fm-text-color-2); + --fm-lookup-panel-primary-color: var(--fm-primary-color); + --fm-lookup-panel-primary-background: #ebf6ff; +} + +.fm-lookup-panel { + height: 100%; + display: flex; + flex-direction: column; + transform: translate3d(0, 0, 0); + overflow: hidden; + background-color: var(--fm-lookup-panel-background); + color: var(--fm-lookup-panel-color); + font-size: var(--fm-lookup-panel-font-size); + &-header { + background-color: var(--fm-lookup-panel-background-2); + .nav-bar { + position: relative; + display: flex; + margin: 0 16px; + .nav-left { + position: absolute; + top: 0; + left: 0; + height: 44px; + display: flex; + align-items: center; + .fm-icon { + font-size: 20px; + } + } + .nav-content { + flex: 1; + display: flex; + flex-direction: column; + padding: 10px 30px; + min-height: 44px; + justify-content: center; + .nav-title { + font-size: 17px; + line-height: 24px; + font-weight: 400; + } + .nav-sub-title { + font-size: 12px; + line-height: 17px; + color: var(--fm-lookup-panel-sub-color); + } + } + .fm-lookup-panel-sub-title { + position: absolute; + left: 50%; + transform: translateX(-50%); + bottom: 5px; + font-size: 12px; + z-index: var(--fm-zindex-2); + color: var(--fm-lookup-panel-sub-color); + } + } + .search-wrapper { + display: flex; + padding: 0 16px; + align-items: center; + @include hairline('bottom', var(--fm-border-color)); + .search-selected { + display: flex; + align-items: center; + .search-selected-item-wrapper { + display: flex; + align-items: center; + overflow-x: auto; + flex-shrink: 0; + width: 100%; + } + .search-selected-item { + padding: 4px 6px; + border-radius: 4px; + display: flex; + font-size: 14px; + line-height: 20px; + word-break: keep-all; + white-space: nowrap; + color: var(--fm-lookup-panel-primary-color); + background: var(--fm-lookup-panel-primary-background); + &:not(:last-child) { + margin-right: 8px; + } + &-text:not(:first-child) { + padding-left: 4px; + } + } + } + .search-input { + .fm-cell-left-icon .fm-icon { + color: var(--fm-lookup-panel-sub-color); + } + } + } + .search-wrapper-horizontal { + .search-selected { + padding-right: 8px; + } + .search-input { + padding-left: 0; + padding-right: 0; + } + } + .search-wrapper-vertical { + flex-direction: column; + padding: 0; + .search-selected { + width: 100%; + padding: 6px 16px; + @include hairline('bottom', var(--fm-border-color)); + .avatar-wrapper { + max-width: calc(100% - 65px); + } + } + } + .header-portal { + display: flex; + align-items: center; + background-color: var(--fm-lookup-panel-background-2); + padding-left: 16px; + .header-portal-icon { + width: 32px; + height: 32px; + font-size: 18px; + display: flex; + align-items: center; + justify-content: center; + background: var(--fm-lookup-panel-background); + border-radius: 100%; + color: var(--fm-lookup-panel-primary-color); + } + .header-portal-cell { + flex: 1; + } + } + } + &-content { + flex: 1; + overflow: hidden; + background-color: var(--fm-lookup-panel-background-2); + position: relative; + margin-top: 10px; + .content-tabs { + display: flex; + flex-direction: column; + height: 100%; + } + .content-tab-personal, + .content-tab-data { + position: relative; + flex: 1; + } + .content-tab-data { + .breadcrumb-wrapper { + position: absolute; + top: 0; + left: 0; + right: 0; + } + } + .list-wrapper { + position: absolute; + left: 0; + right: 0; + bottom: 0; + top: 0; + overflow-x: hidden; + overflow-y: auto; + } + .list { + background-color: var(--fm-lookup-panel-background-2); + } + &-list-item { + display: flex; + // flex-direction: row-reverse; + position: relative; + overflow: hidden; + .list-item-cell-disabled { + color: var(--fm-lookup-panel-sub-color); + .list-item-cell{ + color: var(--fm-lookup-panel-sub-color); + } + } + &:not(:last-child) { + .fm-cell { + @include hairline('bottom', var(--fm-border-color)); + &::after { + left: 16px !important; + } + } + } + &-icon { + .fm-check-icon:not(.fm-check-icon-checked) { + color: var(--fm-gray-4); + } + } + &-cell-warpper { + width: 100%; + overflow: hidden; + } + .list-item-cell-title { + width: 100%; + overflow: hidden; + .fm-cell-title-text { + display: block; + width: 100%; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + } + } + .list-item-cell-favorite, + .list-item-cell-arrow { + height: 100%; + display: flex; + align-items: center; + } + .list-item-cell-favorite { + color: var(--fm-warning-color); + } + .list-item-cell-arrow { + color: var(--fm-lookup-panel-sub-color); + } + .list-item-cell-favorite:not(:last-child) { + padding-right: 8px; + } + .list-item-cell-favorite.selected { + .fm-icon { + background-color: var(--fm-warning-color); + } + } + } + &-list-item-selected { + &-icon { + color: var(--fm-lookup-panel-primary-color); + } + } + &-list-item-checker, + &-list-item-children { + margin-left: 16px; + } + &-list-item-checker:not(&-list-item-children) { + .fm-cell { + padding-left: 0; + } + &:not(:last-child) { + .fm-cell { + &::after { + left: 0 !important; + } + } + } + } + } + .list-checker-wrapper { + display: flex; + padding-right: 10px; + } + &-footer { + padding: 0 16px; + height: 48px; + display: flex; + align-items: center; + justify-content: space-between; + box-shadow: 0 0 7px 0 var(--fm-box-shadow-color); + border-top: 1px solid var(--fm-border-color-2); + background-color: var(--fm-background-2); + } + .list-wrapper { + position: absolute; + left: 0; + right: 0; + bottom: 0; + top: 0; + overflow-x: hidden; + overflow-y: auto; + } + .search-panel { + .list-wrapper { + top: 44px; + } + } + .selected-panel { + .popup-wrapper { + width: 100%; + height: calc(100% - 48px); + background-color: var(--fm-background); + .nav-bar { + @include hairline('bottom', #eee); + } + .list-wrapper { + top: 44px; + background-color: var(--fm-background-2); + } + } + } + .home-panel { + height: 100%; + display: flex; + flex-direction: column; + .home-portal { + display: flex; + align-items: center; + background-color: var(--fm-background-2); + padding-left: 16px; + .home-portal-icon { + width: 32px; + height: 32px; + display: flex; + align-items: center; + justify-content: center; + background: var(--fm-background); + border-radius: 100%; + color: var(--fm-lookup-panel-primary-color); + } + } + .home-group { + flex: 1; + margin-top: 10px; + background-color: var(--fm-background-2); + position: relative; + .home-group-nav { + height: 44px; + display: flex; + align-items: center; + padding: 0 16px; + .nav-title { + font-size: 14px; + color: #666666; + padding-right: 16px; + } + .nav-title.selected { + font-size: 17px; + color: var(--fm-lookup-panel-primary-color); + } + } + .list-wrapper { + top: 44px; + } + } + } + .lookup-tabbar { + height: 44px; + display: flex; + padding: 0 16px; + background-color: var(--fm-background-2); + .tabbar-item { + position: relative; + height: 100%; + display: flex; + align-items: center; + font-size: 14px; + color: #666666; + margin-right: 16px; + } + .tabbar-item.selected { + font-size: 17px; + color: var(--fm-lookup-panel-primary-color); + } + .tabbar-item-bar { + position: absolute; + bottom: 0; + width: 100%; + height: 4px; + background: var(--fm-lookup-panel-primary-color); + border-radius: 2px; + } + } + .fm-lookup-list-empty { + .fm-lookup-list-empty-text { + display: block; + color: var(--fm-lookup-panel-sub-color); + font-size: 14px; + line-height: 50px; + text-align: center; + } + } + .fm-lookup-breadcrumb { + display: flex; + align-items: center; + height: 42px; + padding: 0 16px; + overflow: auto; + background-color: var(--fm-background-2); + @include hairline('bottom', var(--fm-border-color)); + &-item { + display: flex; + flex-shrink: 0; + align-items: center; + color: var(--fm-lookup-panel-primary-color); + padding-right: 8px; + &-text { + padding-right: 8px; + } + &-icon { + font-size: 10px; + } + &:last-child { + color: var(--fm-lookup-panel-sub-color);; + padding-right: 0; + } + } + } + .avatar-wrapper { + display: flex; + align-items: center; + overflow-x: auto; + max-width: 220px; + flex-shrink: 0; + .avatar { + display: flex; + justify-content: center; + flex-shrink: 0; + width: 32px; + height: 32px; + line-height: 32px; + border-radius: 100%; + background: var(--fm-gradient-blue); + color: var(--fm-background-2); + font-size: 12px; + &:not(:last-child) { + margin-right: 8px; + } + .avatar-image { + width: 100%; + height: 100%; + .fm-image-error { + color: var(--fm-background-2); + background: var(--fm-gradient-blue); + } + } + } + &:not(:last-child) { + margin-right: 14px; + } + } + .icon-wrapper { + display: flex; + padding-right: 16px; + & { + @include hairline('bottom', var(--fm-border-color)); + } + } +} +.lookup-favorite-icon { + line-height: 24px; + font-size: 18px; +} \ No newline at end of file diff --git a/packages/mobile-ui-vue/components/theme/src/mixins/_border-radius.scss b/packages/mobile-ui-vue/components/theme/src/mixins/_border-radius.scss new file mode 100644 index 0000000000000000000000000000000000000000..d2e69ceb6c1e06205092c2ab74e60c7a0ebd767c --- /dev/null +++ b/packages/mobile-ui-vue/components/theme/src/mixins/_border-radius.scss @@ -0,0 +1,13 @@ +@mixin borderRadius($size, $position: '') { + @if ($position == 'top') { + border-radius: 0 0 $size $size; + } @else if($position == 'bottom') { + border-radius: $size $size 0 0; + } @else if($position == 'left') { + border-radius: 0 $size $size 0; + } @else if($position == 'right') { + border-radius: $size 0 0 $size; + } @else { + border-radius: $size + } +} diff --git a/packages/mobile-ui-vue/components/theme/src/mixins/_ellipsis.scss b/packages/mobile-ui-vue/components/theme/src/mixins/_ellipsis.scss new file mode 100644 index 0000000000000000000000000000000000000000..24ced1ecccb3fccf129a1d2019b47ba9faa6fa18 --- /dev/null +++ b/packages/mobile-ui-vue/components/theme/src/mixins/_ellipsis.scss @@ -0,0 +1,15 @@ +@mixin multi-ellipsis($lines) { + display: -webkit-box; + overflow: hidden; + text-overflow: ellipsis; + -webkit-line-clamp: $lines; + + /* autoprefixer: ignore next */ + -webkit-box-orient: vertical; +} + +@mixin ellipsis { + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; +} diff --git a/packages/mobile-ui-vue/components/theme/src/mixins/_flex.scss b/packages/mobile-ui-vue/components/theme/src/mixins/_flex.scss new file mode 100644 index 0000000000000000000000000000000000000000..efa5dc993ae9d0b1f532e90cc3f9249ad7401c23 --- /dev/null +++ b/packages/mobile-ui-vue/components/theme/src/mixins/_flex.scss @@ -0,0 +1,17 @@ +@mixin fm-utils-flex($direction: column, $showImportant: false) { + @if $showImportant { + display: flex!important; + flex-direction: $direction!important; + } @else { + display: flex; + flex-direction: $direction; + } + overflow: hidden; + } +@mixin fm-utils-absolute-all { + top: 0; + bottom: 0; + position: absolute; + right: 0; + left: 0; +} \ No newline at end of file diff --git a/packages/mobile-ui-vue/components/theme/src/mixins/_hairline.scss b/packages/mobile-ui-vue/components/theme/src/mixins/_hairline.scss new file mode 100644 index 0000000000000000000000000000000000000000..7362068549d94c2c29b662387d3be06d1bf2051f --- /dev/null +++ b/packages/mobile-ui-vue/components/theme/src/mixins/_hairline.scss @@ -0,0 +1,150 @@ +@mixin scale-hairline-common($color, $top, $right, $bottom, $left) { + content: ''; + position: absolute; + background-color: $color; + display: block; + z-index: 1; + top: $top; + right: $right; + bottom: $bottom; + left: $left; +} + +@mixin hairline( + $direction, + $color: var(--fm-border-color), + $radius: 0, + $type: solid +) { + @if ($direction == 'top') { + border-top: 1px $type $color; + position: relative; + html:not([data-scale]) & { + @media (min-resolution: 1dppx) { + border-top: none; + &::before { + @include scale-hairline-common($color, 0, auto, auto, 0); + width: 100%; + height: 1px; + transform-origin: 50% 50%; + + @media (min-resolution: 2dppx) { + transform: scaleY(0.5); + } + } + } + } + } @else if ($direction == 'bottom') { + border-bottom: 1px $type $color; + position: relative; + html:not([data-scale]) & { + @media (min-resolution: 1dppx) { + border-bottom: none; + &::after { + @include scale-hairline-common($color, auto, auto, 0, 0); + width: 100%; + height: 1px; + transform-origin: 50% 100%; + @media (min-resolution: 2dppx) { + transform: scaleY(0.5); + } + } + } + } + } @else if ($direction == 'left') { + border-left: 1px $type $color; + position: relative; + html:not([data-scale]) & { + @media (min-resolution: 1dppx) { + border-left: none; + &::before { + @include scale-hairline-common($color, 0, auto, auto, 0); + width: 1px; + height: 100%; + transform-origin: 100% 50%; + @media (min-resolution: 2dppx) { + transform: scaleX(0.5); + } + } + } + } + } @else if ($direction == 'right') { + border-right: 1px $type $color; + position: relative; + html:not([data-scale]) & { + @media (min-resolution: 1dppx) { + border-right: none; + &::after { + @include scale-hairline-common($color, 0, 0, auto, auto); + width: 1px; + height: 100%; + background: $color; + transform-origin: 100% 50%; + transform: scaleX(0.5); + @media (min-resolution: 2dppx) { + transform: scaleX(0.5); + } + } + } + } + } @else if ($direction == 'all') { + border: 1px $type $color; + border-radius: $radius; + html:not([data-scale]) & { + @media (min-resolution: 2dppx) { + position: relative; + border: none; + &::before { + content: ''; + position: absolute; + left: 0; + top: 0; + width: 200%; + height: 200%; + border: 1px $type $color; + border-radius: $radius * 2; + transform-origin: 0 0; + transform: scale(0.5); + box-sizing: border-box; + pointer-events: none; + + // @media (min-resolution: 3dppx) { + // width: 300%; + // height: 300%; + // border-radius: @radius * 3; + // transform: scale(0.33); + // } + } + } + } + } +} + +@mixin hairline-remove($position) { + @if $position == 'left' { + border-left: 0; + &:before { + display: none !important; + } + } @else if $position == 'right' { + border-right: 0; + &:after { + display: none !important; + } + } @else if $position == 'top' { + border-top: 0; + &:before { + display: none !important; + } + } @else if $position == 'bottom' { + border-bottom: 0; + &:after { + display: none !important; + } + } @else if $position == 'all' { + border: 0; + &:before { + display: none !important; + } + } +} diff --git a/packages/mobile-ui-vue/components/theme/src/mixins/_safe-area.scss b/packages/mobile-ui-vue/components/theme/src/mixins/_safe-area.scss new file mode 100644 index 0000000000000000000000000000000000000000..393f7a49206d04b9588bba552861434dbc1edc05 --- /dev/null +++ b/packages/mobile-ui-vue/components/theme/src/mixins/_safe-area.scss @@ -0,0 +1,9 @@ +@mixin safeArea($styleName) { + @if($styleName){ + #{$styleName}: 0; + @supports ((bottom: constant(safe-area-inset-bottom)) or (bottom: env(safe-area-inset-bottom))) and (-webkit-overflow-scrolling: touch) { + #{$styleName}: constant(safe-area-inset-bottom); + #{$styleName}: env(safe-area-inset-bottom); + } + } +} diff --git a/packages/mobile-ui-vue/components/theme/src/mixins/_splitline.scss b/packages/mobile-ui-vue/components/theme/src/mixins/_splitline.scss new file mode 100644 index 0000000000000000000000000000000000000000..e099dbebea0f343f652739d7ed08ab09582ed376 --- /dev/null +++ b/packages/mobile-ui-vue/components/theme/src/mixins/_splitline.scss @@ -0,0 +1,10 @@ +@import './hairline'; +@mixin hairline($direction, $color:$border-color-base,$radius:0,$type:solid){ + @if ($direction == 'horizontal') { + + } @else if($direction == 'vertical') { + &::after { + @include scale-hairline-common($color,0,auto,auto,0); + } + } +} \ No newline at end of file diff --git a/packages/mobile-ui-vue/components/theme/src/navbar.scss b/packages/mobile-ui-vue/components/theme/src/navbar.scss new file mode 100644 index 0000000000000000000000000000000000000000..7de18a051151dda711e9ee16e38306a4925796e2 --- /dev/null +++ b/packages/mobile-ui-vue/components/theme/src/navbar.scss @@ -0,0 +1,73 @@ +@import './mixins/hairline'; +@import './mixins/ellipsis'; + +:root { + --fm-navbar-background: var(--fm-background-2); + --fm-navbar-color: var(--fm-text-color); + --fm-navbar-height: 44px; + --fm-navbar-title-size: 17px; + --fm-navbar-side-size: 16px; + --fm-navbar-arrow-size: 18px; +} +.fm-navbar{ + position: relative; + z-index: 9; + display: flex; + align-items: center; + line-height: 1.5; + text-align: center; + user-select: none; + height: var(--fm-navbar-height); + color: var(--fm-navbar-color); + background-color: var(--fm-navbar-background); + &.fm-navbar-fixed { + position: fixed; + top: 0; + left: 0; + width: 100%; + } + &.fm-navbar-border-bottom{ + @include hairline('bottom', var(--fm-border-color-2)); + } + &-title { + max-width: 60%; + margin: 0 auto; + font-weight: 500; + font-size: var(--fm-navbar-title-size); + @include ellipsis(); + } + + &-left, + &-right { + position: absolute; + top: 0; + bottom: 0; + display: flex; + align-items: center; + max-width: 30%; + padding: 0 16px; + font-size: var(--fm-navbar-side-size); + @include ellipsis(); + cursor: pointer; + } + &-left { + left: 0; + &:active{ + opacity: var(--fm-active-opacity); + } + &.fm-navbar-left-padding{ + padding-left: 14px; + } + } + &-right { + right: 0; + .fm-navbar-text:active { + opacity: var(--fm-active-opacity); + } + } + .fm-navbar-left-arrow{ + min-width: 1em; + margin-right: 4px; + font-size: var(--fm-navbar-arrow-size); + } +} \ No newline at end of file diff --git a/packages/mobile-ui-vue/components/theme/src/notice-bar.scss b/packages/mobile-ui-vue/components/theme/src/notice-bar.scss new file mode 100644 index 0000000000000000000000000000000000000000..a442d8f72b2c719af7c1e3f38349ccb121770877 --- /dev/null +++ b/packages/mobile-ui-vue/components/theme/src/notice-bar.scss @@ -0,0 +1,75 @@ + +:root { + --fm-notice-bar-height: 40px; + --fm-notice-bar-zindex: var(--fm-zindex-3); + --fm-notice-bar-color: var(--fm-orange-2); + --fm-notice-bar-background: rgba(251, 185, 2, 0.1); +} + +.fm-notice-bar { + display: flex; + position: relative; + padding: 0 16px; + color: var(--fm-notice-bar-color); + z-index: var(--fm-notice-bar-zindex); + min-height: var(--fm-notice-bar-height); + background-color: var(--fm-notice-bar-background); +} +.fm-notice-bar-left, +.fm-notice-bar-right { + display: flex; + align-items: center; +} +.fm-notice-bar-left { + padding-right: 6px; +} +.fm-notice-bar-right { + padding-left: 6px; +} +.fm-notice-bar-empty { + padding-right: 0; +} +.fm-notice-bar-content { + flex: 1; + margin: auto; + width: auto; + font-size: 14px; + line-height: var(--fm-notice-bar-height); + white-space: nowrap; + overflow: hidden; + &.fm-notice-bar-multi-content { + padding: 16px 0; + font-size: 14px; + line-height: 20px; + white-space: normal; + } + .fm-notice-bar-content-animate { + padding-left: 100%; + display: inline-block; + animation: fm-notice-bar-animation 16s linear infinite both; + -webkit-animation: fm-notice-bar-animation 16s linear infinite both; + } +} +@-webkit-keyframes fm-notice-bar-animation { + 0% { + -webkit-transform: translateZ(0); + transform: translateZ(0); + } + + to { + -webkit-transform: translate3d(-100%, 0, 0); + transform: translate3d(-100%, 0, 0); + } +} + +@keyframes fm-notice-bar-animation { + 0% { + -webkit-transform: translateZ(0); + transform: translateZ(0); + } + + to { + -webkit-transform: translate3d(-100%, 0, 0); + transform: translate3d(-100%, 0, 0); + } +} diff --git a/packages/mobile-ui-vue/components/theme/src/notify.scss b/packages/mobile-ui-vue/components/theme/src/notify.scss new file mode 100644 index 0000000000000000000000000000000000000000..21a2000aeb8b2d74392c27a60d64188c7bd9640e --- /dev/null +++ b/packages/mobile-ui-vue/components/theme/src/notify.scss @@ -0,0 +1,42 @@ + +:root { + --fm-notify-color: var(--fm-white); + --fm-notify-zindex: var(--fm-zindex-5); + --fm-notify-info-background: var(--fm-primary-color); + --fm-notify-success-background: var(--fm-success-color); + --fm-notify-warning-background: var(--fm-warning-color); + --fm-notify-error-background: var(--fm-danger-color); +} + +.fm-notify{ + position: fixed; + left: 0; + top: 0; + z-index: var(--fm-notify-zindex); + display: flex; + align-items: center; + justify-content: center; + width: 100%; + max-height: 100%; + padding: 8px 16px; + box-sizing: border-box; + color: var(--fm-notify-color); + font-size: 14px; + line-height: 20px; + white-space: pre-wrap; + text-align: center; + word-wrap: break-word; + overflow-y: auto; + &-info{ + background-color: var(--fm-notify-info-background); + } + &-success{ + background-color: var(--fm-notify-success-background); + } + &-warning{ + background-color: var(--fm-notify-warning-background); + } + &-error{ + background-color: var(--fm-notify-error-background); + } +} \ No newline at end of file diff --git a/packages/mobile-ui-vue/components/theme/src/overlay.scss b/packages/mobile-ui-vue/components/theme/src/overlay.scss new file mode 100644 index 0000000000000000000000000000000000000000..8b6b05a232249d0070c9e3f1733a7284e352223b --- /dev/null +++ b/packages/mobile-ui-vue/components/theme/src/overlay.scss @@ -0,0 +1,9 @@ +.fm-overlay { + width: 100%; + position: fixed; + top: 0; + left: 0; + z-index: 98; + @include safeArea('bottom'); + background-color: rgba(0, 0, 0, 0.4); +} diff --git a/packages/mobile-ui-vue/components/theme/src/pagination.scss b/packages/mobile-ui-vue/components/theme/src/pagination.scss new file mode 100644 index 0000000000000000000000000000000000000000..f91040b75df5d92f212b416e37bc70a4bf7ccf32 --- /dev/null +++ b/packages/mobile-ui-vue/components/theme/src/pagination.scss @@ -0,0 +1,84 @@ +@import './mixins/hairline'; + +.fm-pagination { + display: flex; + font-size: 16px; + padding: 5px 0; + &-item, + &-page-desc { + display: flex; + align-items: center; + justify-content: center; + } + + &-item { + flex: 1; + box-sizing: border-box; + min-width: 34px; + height: 34px; + color: var(--fm-primary-color); + background-color: #fff; + cursor: pointer; + user-select: none; + &.fm-hairline{ + position: relative; + } + &:active { + color: #fff; + background-color: var(--fm-primary-color); + } + + &::before { + border-width: 1px 0 1px 1px!important; + } + + &:last-child::before { + border-right-width: 1px!important; + } + + &-active { + color: #fff; + background-color: var(--fm-primary-color); + } + } + + &-prev, + &-next { + padding: 0 4px; + border-radius: 5px; + cursor: pointer; + } + + &-item-disabled { + &, + &:active { + color: #cccccc; + background-color: #ffffff; + cursor: not-allowed; + opacity: 0.5; + } + } + + &-page { + flex-grow: 0; + } + + &-page-desc { + flex: 1; + height: 40px; + color: #333333; + .page-desc-text{ + color: var(--fm-primary-color); + } + } + + &-simple { + .fm-pagination-prev, + .fm-pagination-next { + &::before { + border-width: 1px!important; + } + } + } + } + \ No newline at end of file diff --git a/packages/mobile-ui-vue/components/theme/src/picker.scss b/packages/mobile-ui-vue/components/theme/src/picker.scss new file mode 100644 index 0000000000000000000000000000000000000000..d340276fc746b62dce800229b2c26ae4cf8f861e --- /dev/null +++ b/packages/mobile-ui-vue/components/theme/src/picker.scss @@ -0,0 +1,88 @@ +@import './mixins/hairline'; +:root { + --fm-picker-panel-background: var(--fm-background-2); + --fm-picker-panel-toolbar-height: 44px; +} +.fm-picker-panel { + position: relative; + background-color: var(--fm-picker-panel-background); + user-select: none; + &-toolbar { + display: flex; + justify-content: space-between; + align-items: center; + height: var(--fm-picker-panel-toolbar-height); + &-left, + &-right { + padding: 0 16px; + } + &-title { + font-weight: 500; + font-size: 16px; + max-width: 50%; + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; + } + } + &-content { + position: relative; + display: flex; + cursor: grab; + .fm-picker-panel-cols { + display: flex; + flex: 1; + .fm-picker-panel-col { + flex: 1; + overflow: hidden; + &-item{ + display: flex; + align-items: center; + justify-content: center; + height: 44px; + } + } + &-mask { + content: ''; + position: absolute; + top: 0; + left: 0; + z-index: 1; + width: 100%; + height: 100%; + background-image: linear-gradient(180deg, rgba(255, 255, 255, .9), rgba(255, 255, 255, .4)), linear-gradient(0deg, rgba(255, 255, 255, .9), rgba(255, 255, 255, .4));; + background-repeat: no-repeat; + background-position: top,bottom; + transform: translateZ(0); + pointer-events: none; + } + &::after { + content: ''; + position: absolute; + top: 50%; + left: 16px; + right: 16px; + height: 88px; + z-index: 2; + pointer-events: none; + border-width: 1px 0; + border-style: solid; + border-color: #ebedf0; + transform: translateY(-50%) scaleY(.5); + } + } + } +} +.fm-picker { + &:not(:last-child):not(.fm-picker-row) { + .fm-picker-input { + @include hairline('bottom'); + &::after { + left: 16px !important; + } + } + } + .fm-popup-bottom{ + border-radius: 14px 14px 0 0; + } +} \ No newline at end of file diff --git a/packages/mobile-ui-vue/components/theme/src/popover.scss b/packages/mobile-ui-vue/components/theme/src/popover.scss new file mode 100644 index 0000000000000000000000000000000000000000..77275bb1bf776be259ac4227ad610f1ec1e7664e --- /dev/null +++ b/packages/mobile-ui-vue/components/theme/src/popover.scss @@ -0,0 +1,134 @@ +@import './mixins/hairline'; +:root { + --fm-popover-background: var(--fm-background-2); + --fm-popover-font-size: var(--fm-font-size-base); + --fm-popover-color: var(--fm-text-color); +} +.fm-popover-template { + display: inline-block; +} +.fm-popover { + background-color: transparent; + padding: 10px; + font-size: var(--fm-text-font-size); + color: var(--fm-text-color); + .fm-popover-arrow { + position: absolute; + width: 11px; + height: 11px; + border-radius: 1px; + background-color: var(--fm-popover-background); + transform: rotate(45deg); + z-index: 0; + } + .fm-popover-inner { + background-color: var(--fm-popover-background); + box-shadow: 0 2px 8px 0 var(--fm-box-shadow-color-2); + border-radius: 6px; + overflow: hidden; + &-wrapper { + position: relative; + padding: 0; + background-color: var(--fm-popover-background); + .fm-popover-item { + padding: 0 6px 0 8px; + @include hairline('bottom'); + &-container { + position: relative; + display: flex; + align-items: center; + height: 46px; + line-height: 46px; + box-sizing: border-box; + padding: 0 2px; + .fm-popover-item-icon { + margin-right: 16px; + } + } + &:active { + background: var(--fm-active-color); + } + } + .fm-popover-item-disabled { + opacity: var(--fm-disabled-opacity); + } + } + } + &.fm-popover-placement-top, + &.fm-popover-placement-topLeft, + &.fm-popover-placement-topRight { + .fm-popover-arrow { + transform: rotate(225deg); + bottom: 5.5px; + } + } + &.fm-popover-placement-top { + .fm-popover-arrow { + left: 50%; + transform: translateX(-50%) rotate(225deg); + } + } + &.fm-popover-placement-topLeft { + .fm-popover-arrow { + left: 21px; + } + } + &.fm-popover-placement-topRight { + .fm-popover-arrow { + right: 21px; + } + } + &.fm-popover-placement-right, + &.fm-popover-placement-rightBottom, + &.fm-popover-placement-rightTop { + .fm-popover-arrow { + transform: rotate(-45deg); + left: 5.5px; + } + } + &.fm-popover-placement-right .fm-popover-arrow { + top: 50%; + transform: translateY(-50%) rotate(-45deg); + } + &.fm-popover-placement-rightTop .fm-popover-arrow { + top: 21px; + } + &.fm-popover-placement-rightBottom .fm-popover-arrow { + bottom: 21px; + } + &.fm-popover-placement-left, + &.fm-popover-placement-leftBottom, + &.fm-popover-placement-leftTop { + .fm-popover-arrow { + transform: rotate(135deg); + right: 4.5px; + } + } + &.fm-popover-placement-left .fm-popover-arrow { + top: 50%; + transform: translateY(-50%) rotate(135deg); + } + &.fm-popover-placement-leftTop .fm-popover-arrow { + top: 21px; + } + &.fm-popover-placement-leftBottom .fm-popover-arrow { + bottom: 21px; + } + &.fm-popover-placement-bottom, + &.fm-popover-placement-bottomLeft, + &.fm-popover-placement-bottomRight { + .fm-popover-arrow { + top: 4.5px; + } + } + &.fm-popover-placement-bottom .fm-popover-arrow { + left: 50%; + transform: translateX(-50%) rotate(45deg); + } + &.fm-popover-placement-bottomLeft .fm-popover-arrow { + left: 21px; + } + &.fm-popover-placement-bottomRight .fm-popover-arrow { + right: 21px; + } +} diff --git a/packages/mobile-ui-vue/components/theme/src/popup.scss b/packages/mobile-ui-vue/components/theme/src/popup.scss new file mode 100644 index 0000000000000000000000000000000000000000..36a41897ea766c8716a4b6f80def33ff97b83df1 --- /dev/null +++ b/packages/mobile-ui-vue/components/theme/src/popup.scss @@ -0,0 +1,58 @@ +@import './mixins/safe-area'; +@import './mixins/border-radius'; +:root { + --fm-popup-background: var(--fm-background-2); + --fm-popup-zindex: var(--fm-zindex-3); + --fm-popup-radius: 16px; +} + +.fm-popup { + position: fixed; + max-height: 100%; + overflow-y: auto; + background-color: var(--fm-popup-background); + transition: all var(--fm-duration-base); + z-index: var(--fm-popup-zindex); + &-center { + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + &.fm-popup-round { + @include borderRadius(var(--fm-popup-radius)); + } + } + &-top, + &-bottom { + left: 0; + right: 0; + } + &-top { + top: 0; + &.fm-popup-round { + @include borderRadius(var(--fm-popup-radius),'top'); + } + } + &-bottom { + @include safeArea('bottom'); + &.fm-popup-round { + @include borderRadius(var(--fm-popup-radius),'bottom'); + } + } + &-left, + &-right { + top: 0; + @include safeArea('bottom'); + } + &-left { + left: 0; + &.fm-popup-round { + @include borderRadius(var(--fm-popup-radius),'left'); + } + } + &-right { + right: 0; + &.fm-popup-round { + @include borderRadius(var(--fm-popup-radius),'right'); + } + } +} diff --git a/packages/mobile-ui-vue/components/theme/src/radio.scss b/packages/mobile-ui-vue/components/theme/src/radio.scss new file mode 100644 index 0000000000000000000000000000000000000000..aeaa016c6b24744c911563148263493ff314e841 --- /dev/null +++ b/packages/mobile-ui-vue/components/theme/src/radio.scss @@ -0,0 +1,21 @@ +.fm-radio-group { + .fm-radio-horizontal { + display: flex; + overflow: visible; + text-align: left; + flex-wrap: wrap; + .fm-radio { + margin-top: 4px; + margin-bottom: 4px; + } + } +} +.fm-cell .fm-radio-group .fm-radio-vertical { + padding-left: 0; +} + +.fm-input-control-right { + .fm-radio-horizontal { + justify-content: flex-end; + } +} \ No newline at end of file diff --git a/packages/mobile-ui-vue/components/theme/src/rich-editor.scss b/packages/mobile-ui-vue/components/theme/src/rich-editor.scss new file mode 100644 index 0000000000000000000000000000000000000000..13621d83a6dc80a35d82890553c78ac45f37766a --- /dev/null +++ b/packages/mobile-ui-vue/components/theme/src/rich-editor.scss @@ -0,0 +1,998 @@ +@import './mixins/hairline'; + +.fm-editor { + width: 100%; + .fm-editor-no-border.ql-container, + .fm-editor-toobar-wrapper.ql-toolbar { + border: none; + } + .fm-editor-no-border { + .ql-editor { + padding: 12px 0; + } + .ql-editor.ql-blank::before { + left: 0; + right: 0; + } + } + .fm-editor-toobar { + .fm-editor-toobar-row { + display: flex; + justify-content: space-between; + padding: 8px; + &:not(:last-child) { + @include hairline('bottom'); + } + .fm-editor-font-slider { + flex: 1; + display: flex; + align-items: center; + padding: 0 8px; + } + .fm-toolbar-color { + height: 24px; + width: 24px; + background-color: #000; + border-radius: 50%; + position: relative; + } + .fm-toolbar-color.fm-active { + &::after { + content: ''; + position: absolute; + left: 0; + top: 0; + height: 14px; + width: 14px; + background-color: #fff; + border-radius: 50%; + transform: translate(5px, 5px); + } + } + } + } +} + + + + +.ql-container { + box-sizing: border-box; + font-family: Helvetica, Arial, sans-serif; + font-size: 14px; + height: 100%; + margin: 0px; + position: relative; + white-space: pre; +} +.ql-container.ql-disabled .ql-tooltip { + visibility: hidden; +} +.ql-container.ql-disabled .ql-editor ul[data-checked] > li::before { + pointer-events: none; +} +.ql-clipboard { + left: -100000px; + height: 1px; + overflow-y: hidden; + position: absolute; + top: 50%; +} +.ql-clipboard p { + margin: 0; + padding: 0; +} +.ql-editor { + box-sizing: border-box; + line-height: 1.42; + height: 100%; + outline: none; + overflow-y: auto; + padding: 12px 15px; + tab-size: 4; + -moz-tab-size: 4; + text-align: left; + white-space: pre-wrap; + word-wrap: break-word; +} +.ql-editor > * { + cursor: text; +} +.ql-editor p, +.ql-editor ol, +.ql-editor ul, +.ql-editor pre, +.ql-editor blockquote, +.ql-editor h1, +.ql-editor h2, +.ql-editor h3, +.ql-editor h4, +.ql-editor h5, +.ql-editor h6 { + margin: 0; + padding: 0; + counter-reset: list-1 list-2 list-3 list-4 list-5 list-6 list-7 list-8 list-9; +} +.ql-editor ol, +.ql-editor ul { + padding-left: 1.5em; +} +.ql-editor ol > li, +.ql-editor ul > li { + list-style-type: none; +} +.ql-editor ul > li::before { + content: '\2022'; +} +.ql-editor ul[data-checked=true], +.ql-editor ul[data-checked=false] { + pointer-events: none; +} +.ql-editor ul[data-checked=true] > li *, +.ql-editor ul[data-checked=false] > li * { + pointer-events: all; +} +.ql-editor ul[data-checked=true] > li::before, +.ql-editor ul[data-checked=false] > li::before { + color: #777; + cursor: pointer; + pointer-events: all; +} +.ql-editor ul[data-checked=true] > li::before { + content: '\2611'; +} +.ql-editor ul[data-checked=false] > li::before { + content: '\2610'; +} +.ql-editor li::before { + display: inline-block; + white-space: nowrap; + width: 1.2em; +} +.ql-editor li:not(.ql-direction-rtl)::before { + margin-left: -1.5em; + margin-right: 0.3em; + text-align: right; +} +.ql-editor li.ql-direction-rtl::before { + margin-left: 0.3em; + margin-right: -1.5em; +} +.ql-editor ol li:not(.ql-direction-rtl), +.ql-editor ul li:not(.ql-direction-rtl) { + padding-left: 1.5em; +} +.ql-editor ol li.ql-direction-rtl, +.ql-editor ul li.ql-direction-rtl { + padding-right: 1.5em; +} +.ql-editor ol li { + counter-reset: list-1 list-2 list-3 list-4 list-5 list-6 list-7 list-8 list-9; + counter-increment: list-0; +} +.ql-editor ol li:before { + content: counter(list-0, decimal) '. '; +} +.ql-editor ol li.ql-indent-1 { + counter-increment: list-1; +} +.ql-editor ol li.ql-indent-1:before { + content: counter(list-1, lower-alpha) '. '; +} +.ql-editor ol li.ql-indent-1 { + counter-reset: list-2 list-3 list-4 list-5 list-6 list-7 list-8 list-9; +} +.ql-editor ol li.ql-indent-2 { + counter-increment: list-2; +} +.ql-editor ol li.ql-indent-2:before { + content: counter(list-2, lower-roman) '. '; +} +.ql-editor ol li.ql-indent-2 { + counter-reset: list-3 list-4 list-5 list-6 list-7 list-8 list-9; +} +.ql-editor ol li.ql-indent-3 { + counter-increment: list-3; +} +.ql-editor ol li.ql-indent-3:before { + content: counter(list-3, decimal) '. '; +} +.ql-editor ol li.ql-indent-3 { + counter-reset: list-4 list-5 list-6 list-7 list-8 list-9; +} +.ql-editor ol li.ql-indent-4 { + counter-increment: list-4; +} +.ql-editor ol li.ql-indent-4:before { + content: counter(list-4, lower-alpha) '. '; +} +.ql-editor ol li.ql-indent-4 { + counter-reset: list-5 list-6 list-7 list-8 list-9; +} +.ql-editor ol li.ql-indent-5 { + counter-increment: list-5; +} +.ql-editor ol li.ql-indent-5:before { + content: counter(list-5, lower-roman) '. '; +} +.ql-editor ol li.ql-indent-5 { + counter-reset: list-6 list-7 list-8 list-9; +} +.ql-editor ol li.ql-indent-6 { + counter-increment: list-6; +} +.ql-editor ol li.ql-indent-6:before { + content: counter(list-6, decimal) '. '; +} +.ql-editor ol li.ql-indent-6 { + counter-reset: list-7 list-8 list-9; +} +.ql-editor ol li.ql-indent-7 { + counter-increment: list-7; +} +.ql-editor ol li.ql-indent-7:before { + content: counter(list-7, lower-alpha) '. '; +} +.ql-editor ol li.ql-indent-7 { + counter-reset: list-8 list-9; +} +.ql-editor ol li.ql-indent-8 { + counter-increment: list-8; +} +.ql-editor ol li.ql-indent-8:before { + content: counter(list-8, lower-roman) '. '; +} +.ql-editor ol li.ql-indent-8 { + counter-reset: list-9; +} +.ql-editor ol li.ql-indent-9 { + counter-increment: list-9; +} +.ql-editor ol li.ql-indent-9:before { + content: counter(list-9, decimal) '. '; +} +.ql-editor .ql-indent-1:not(.ql-direction-rtl) { + padding-left: 3em; +} +.ql-editor li.ql-indent-1:not(.ql-direction-rtl) { + padding-left: 4.5em; +} +.ql-editor .ql-indent-1.ql-direction-rtl.ql-align-right { + padding-right: 3em; +} +.ql-editor li.ql-indent-1.ql-direction-rtl.ql-align-right { + padding-right: 4.5em; +} +.ql-editor .ql-indent-2:not(.ql-direction-rtl) { + padding-left: 6em; +} +.ql-editor li.ql-indent-2:not(.ql-direction-rtl) { + padding-left: 7.5em; +} +.ql-editor .ql-indent-2.ql-direction-rtl.ql-align-right { + padding-right: 6em; +} +.ql-editor li.ql-indent-2.ql-direction-rtl.ql-align-right { + padding-right: 7.5em; +} +.ql-editor .ql-indent-3:not(.ql-direction-rtl) { + padding-left: 9em; +} +.ql-editor li.ql-indent-3:not(.ql-direction-rtl) { + padding-left: 10.5em; +} +.ql-editor .ql-indent-3.ql-direction-rtl.ql-align-right { + padding-right: 9em; +} +.ql-editor li.ql-indent-3.ql-direction-rtl.ql-align-right { + padding-right: 10.5em; +} +.ql-editor .ql-indent-4:not(.ql-direction-rtl) { + padding-left: 12em; +} +.ql-editor li.ql-indent-4:not(.ql-direction-rtl) { + padding-left: 13.5em; +} +.ql-editor .ql-indent-4.ql-direction-rtl.ql-align-right { + padding-right: 12em; +} +.ql-editor li.ql-indent-4.ql-direction-rtl.ql-align-right { + padding-right: 13.5em; +} +.ql-editor .ql-indent-5:not(.ql-direction-rtl) { + padding-left: 15em; +} +.ql-editor li.ql-indent-5:not(.ql-direction-rtl) { + padding-left: 16.5em; +} +.ql-editor .ql-indent-5.ql-direction-rtl.ql-align-right { + padding-right: 15em; +} +.ql-editor li.ql-indent-5.ql-direction-rtl.ql-align-right { + padding-right: 16.5em; +} +.ql-editor .ql-indent-6:not(.ql-direction-rtl) { + padding-left: 18em; +} +.ql-editor li.ql-indent-6:not(.ql-direction-rtl) { + padding-left: 19.5em; +} +.ql-editor .ql-indent-6.ql-direction-rtl.ql-align-right { + padding-right: 18em; +} +.ql-editor li.ql-indent-6.ql-direction-rtl.ql-align-right { + padding-right: 19.5em; +} +.ql-editor .ql-indent-7:not(.ql-direction-rtl) { + padding-left: 21em; +} +.ql-editor li.ql-indent-7:not(.ql-direction-rtl) { + padding-left: 22.5em; +} +.ql-editor .ql-indent-7.ql-direction-rtl.ql-align-right { + padding-right: 21em; +} +.ql-editor li.ql-indent-7.ql-direction-rtl.ql-align-right { + padding-right: 22.5em; +} +.ql-editor .ql-indent-8:not(.ql-direction-rtl) { + padding-left: 24em; +} +.ql-editor li.ql-indent-8:not(.ql-direction-rtl) { + padding-left: 25.5em; +} +.ql-editor .ql-indent-8.ql-direction-rtl.ql-align-right { + padding-right: 24em; +} +.ql-editor li.ql-indent-8.ql-direction-rtl.ql-align-right { + padding-right: 25.5em; +} +.ql-editor .ql-indent-9:not(.ql-direction-rtl) { + padding-left: 27em; +} +.ql-editor li.ql-indent-9:not(.ql-direction-rtl) { + padding-left: 28.5em; +} +.ql-editor .ql-indent-9.ql-direction-rtl.ql-align-right { + padding-right: 27em; +} +.ql-editor li.ql-indent-9.ql-direction-rtl.ql-align-right { + padding-right: 28.5em; +} +.ql-editor .ql-video { + display: block; + max-width: 100%; +} +.ql-editor .ql-video.ql-align-center { + margin: 0 auto; +} +.ql-editor .ql-video.ql-align-right { + margin: 0 0 0 auto; +} +.ql-editor .ql-bg-black { + background-color: #000; +} +.ql-editor .ql-bg-red { + background-color: #e60000; +} +.ql-editor .ql-bg-orange { + background-color: #f90; +} +.ql-editor .ql-bg-yellow { + background-color: #ff0; +} +.ql-editor .ql-bg-green { + background-color: #008a00; +} +.ql-editor .ql-bg-blue { + background-color: #06c; +} +.ql-editor .ql-bg-purple { + background-color: #93f; +} +.ql-editor .ql-color-white { + color: #fff; +} +.ql-editor .ql-color-red { + color: #e60000; +} +.ql-editor .ql-color-orange { + color: #f90; +} +.ql-editor .ql-color-yellow { + color: #ff0; +} +.ql-editor .ql-color-green { + color: #008a00; +} +.ql-editor .ql-color-blue { + color: #06c; +} +.ql-editor .ql-color-purple { + color: #93f; +} +.ql-editor .ql-font-serif { + font-family: Georgia, Times New Roman, serif; +} +.ql-editor .ql-font-monospace { + font-family: Monaco, Courier New, monospace; +} +.ql-editor .ql-size-small { + font-size: 0.75em; +} +.ql-editor .ql-size-large { + font-size: 1.5em; +} +.ql-editor .ql-size-huge { + font-size: 2.5em; +} +.ql-editor .ql-direction-rtl { + direction: rtl; + text-align: inherit; +} +.ql-editor .ql-align-center { + text-align: center; +} +.ql-editor .ql-align-justify { + text-align: justify; +} +.ql-editor .ql-align-right { + text-align: right; +} +.ql-editor.ql-blank::before { + color: rgba(0,0,0,0.6); + content: attr(data-placeholder); + font-style: italic; + left: 15px; + pointer-events: none; + position: absolute; + right: 15px; +} +.ql-snow.ql-toolbar:after, +.ql-snow .ql-toolbar:after { + clear: both; + content: ''; + display: table; +} +.ql-snow.ql-toolbar button, +.ql-snow .ql-toolbar button { + background: none; + border: none; + cursor: pointer; + display: inline-block; + float: left; + height: 24px; + padding: 3px 5px; + width: 28px; +} +.ql-snow.ql-toolbar button svg, +.ql-snow .ql-toolbar button svg { + float: left; + height: 100%; +} +.ql-snow.ql-toolbar button:active:hover, +.ql-snow .ql-toolbar button:active:hover { + outline: none; +} +.ql-snow.ql-toolbar input.ql-image[type=file], +.ql-snow .ql-toolbar input.ql-image[type=file] { + display: none; +} +.ql-snow.ql-toolbar button:hover, +.ql-snow .ql-toolbar button:hover, +.ql-snow.ql-toolbar button:focus, +.ql-snow .ql-toolbar button:focus, +.ql-snow.ql-toolbar button.ql-active, +.ql-snow .ql-toolbar button.ql-active, +.ql-snow.ql-toolbar .ql-picker-label:hover, +.ql-snow .ql-toolbar .ql-picker-label:hover, +.ql-snow.ql-toolbar .ql-picker-label.ql-active, +.ql-snow .ql-toolbar .ql-picker-label.ql-active, +.ql-snow.ql-toolbar .ql-picker-item:hover, +.ql-snow .ql-toolbar .ql-picker-item:hover, +.ql-snow.ql-toolbar .ql-picker-item.ql-selected, +.ql-snow .ql-toolbar .ql-picker-item.ql-selected { + color: #06c; +} +.ql-snow.ql-toolbar button:hover .ql-fill, +.ql-snow .ql-toolbar button:hover .ql-fill, +.ql-snow.ql-toolbar button:focus .ql-fill, +.ql-snow .ql-toolbar button:focus .ql-fill, +.ql-snow.ql-toolbar button.ql-active .ql-fill, +.ql-snow .ql-toolbar button.ql-active .ql-fill, +.ql-snow.ql-toolbar .ql-picker-label:hover .ql-fill, +.ql-snow .ql-toolbar .ql-picker-label:hover .ql-fill, +.ql-snow.ql-toolbar .ql-picker-label.ql-active .ql-fill, +.ql-snow .ql-toolbar .ql-picker-label.ql-active .ql-fill, +.ql-snow.ql-toolbar .ql-picker-item:hover .ql-fill, +.ql-snow .ql-toolbar .ql-picker-item:hover .ql-fill, +.ql-snow.ql-toolbar .ql-picker-item.ql-selected .ql-fill, +.ql-snow .ql-toolbar .ql-picker-item.ql-selected .ql-fill, +.ql-snow.ql-toolbar button:hover .ql-stroke.ql-fill, +.ql-snow .ql-toolbar button:hover .ql-stroke.ql-fill, +.ql-snow.ql-toolbar button:focus .ql-stroke.ql-fill, +.ql-snow .ql-toolbar button:focus .ql-stroke.ql-fill, +.ql-snow.ql-toolbar button.ql-active .ql-stroke.ql-fill, +.ql-snow .ql-toolbar button.ql-active .ql-stroke.ql-fill, +.ql-snow.ql-toolbar .ql-picker-label:hover .ql-stroke.ql-fill, +.ql-snow .ql-toolbar .ql-picker-label:hover .ql-stroke.ql-fill, +.ql-snow.ql-toolbar .ql-picker-label.ql-active .ql-stroke.ql-fill, +.ql-snow .ql-toolbar .ql-picker-label.ql-active .ql-stroke.ql-fill, +.ql-snow.ql-toolbar .ql-picker-item:hover .ql-stroke.ql-fill, +.ql-snow .ql-toolbar .ql-picker-item:hover .ql-stroke.ql-fill, +.ql-snow.ql-toolbar .ql-picker-item.ql-selected .ql-stroke.ql-fill, +.ql-snow .ql-toolbar .ql-picker-item.ql-selected .ql-stroke.ql-fill { + fill: #06c; +} +.ql-snow.ql-toolbar button:hover .ql-stroke, +.ql-snow .ql-toolbar button:hover .ql-stroke, +.ql-snow.ql-toolbar button:focus .ql-stroke, +.ql-snow .ql-toolbar button:focus .ql-stroke, +.ql-snow.ql-toolbar button.ql-active .ql-stroke, +.ql-snow .ql-toolbar button.ql-active .ql-stroke, +.ql-snow.ql-toolbar .ql-picker-label:hover .ql-stroke, +.ql-snow .ql-toolbar .ql-picker-label:hover .ql-stroke, +.ql-snow.ql-toolbar .ql-picker-label.ql-active .ql-stroke, +.ql-snow .ql-toolbar .ql-picker-label.ql-active .ql-stroke, +.ql-snow.ql-toolbar .ql-picker-item:hover .ql-stroke, +.ql-snow .ql-toolbar .ql-picker-item:hover .ql-stroke, +.ql-snow.ql-toolbar .ql-picker-item.ql-selected .ql-stroke, +.ql-snow .ql-toolbar .ql-picker-item.ql-selected .ql-stroke, +.ql-snow.ql-toolbar button:hover .ql-stroke-miter, +.ql-snow .ql-toolbar button:hover .ql-stroke-miter, +.ql-snow.ql-toolbar button:focus .ql-stroke-miter, +.ql-snow .ql-toolbar button:focus .ql-stroke-miter, +.ql-snow.ql-toolbar button.ql-active .ql-stroke-miter, +.ql-snow .ql-toolbar button.ql-active .ql-stroke-miter, +.ql-snow.ql-toolbar .ql-picker-label:hover .ql-stroke-miter, +.ql-snow .ql-toolbar .ql-picker-label:hover .ql-stroke-miter, +.ql-snow.ql-toolbar .ql-picker-label.ql-active .ql-stroke-miter, +.ql-snow .ql-toolbar .ql-picker-label.ql-active .ql-stroke-miter, +.ql-snow.ql-toolbar .ql-picker-item:hover .ql-stroke-miter, +.ql-snow .ql-toolbar .ql-picker-item:hover .ql-stroke-miter, +.ql-snow.ql-toolbar .ql-picker-item.ql-selected .ql-stroke-miter, +.ql-snow .ql-toolbar .ql-picker-item.ql-selected .ql-stroke-miter { + stroke: #06c; +} +@media (pointer: coarse) { + .ql-snow.ql-toolbar button:hover:not(.ql-active), + .ql-snow .ql-toolbar button:hover:not(.ql-active) { + color: #444; + } + .ql-snow.ql-toolbar button:hover:not(.ql-active) .ql-fill, + .ql-snow .ql-toolbar button:hover:not(.ql-active) .ql-fill, + .ql-snow.ql-toolbar button:hover:not(.ql-active) .ql-stroke.ql-fill, + .ql-snow .ql-toolbar button:hover:not(.ql-active) .ql-stroke.ql-fill { + fill: #444; + } + .ql-snow.ql-toolbar button:hover:not(.ql-active) .ql-stroke, + .ql-snow .ql-toolbar button:hover:not(.ql-active) .ql-stroke, + .ql-snow.ql-toolbar button:hover:not(.ql-active) .ql-stroke-miter, + .ql-snow .ql-toolbar button:hover:not(.ql-active) .ql-stroke-miter { + stroke: #444; + } +} +.ql-snow { + box-sizing: border-box; +} +.ql-snow * { + box-sizing: border-box; +} +.ql-snow .ql-hidden { + display: none; +} +.ql-snow .ql-out-bottom, +.ql-snow .ql-out-top { + visibility: hidden; +} +.ql-snow .ql-tooltip { + position: absolute; + transform: translateY(10px); +} +.ql-snow .ql-tooltip a { + cursor: pointer; + text-decoration: none; +} +.ql-snow .ql-tooltip.ql-flip { + transform: translateY(-10px); +} +.ql-snow .ql-formats { + display: inline-block; + vertical-align: middle; +} +.ql-snow .ql-formats:after { + clear: both; + content: ''; + display: table; +} +.ql-snow .ql-stroke { + fill: none; + stroke: #444; + stroke-linecap: round; + stroke-linejoin: round; + stroke-width: 2; +} +.ql-snow .ql-stroke-miter { + fill: none; + stroke: #444; + stroke-miterlimit: 10; + stroke-width: 2; +} +.ql-snow .ql-fill, +.ql-snow .ql-stroke.ql-fill { + fill: #444; +} +.ql-snow .ql-empty { + fill: none; +} +.ql-snow .ql-even { + fill-rule: evenodd; +} +.ql-snow .ql-thin, +.ql-snow .ql-stroke.ql-thin { + stroke-width: 1; +} +.ql-snow .ql-transparent { + opacity: 0.4; +} +.ql-snow .ql-direction svg:last-child { + display: none; +} +.ql-snow .ql-direction.ql-active svg:last-child { + display: inline; +} +.ql-snow .ql-direction.ql-active svg:first-child { + display: none; +} +.ql-snow .ql-editor h1 { + font-size: 2em; +} +.ql-snow .ql-editor h2 { + font-size: 1.5em; +} +.ql-snow .ql-editor h3 { + font-size: 1.17em; +} +.ql-snow .ql-editor h4 { + font-size: 1em; +} +.ql-snow .ql-editor h5 { + font-size: 0.83em; +} +.ql-snow .ql-editor h6 { + font-size: 0.67em; +} +.ql-snow .ql-editor a { + text-decoration: underline; +} +.ql-snow .ql-editor blockquote { + border-left: 4px solid #ccc; + margin-bottom: 5px; + margin-top: 5px; + padding-left: 16px; +} +.ql-snow .ql-editor code, +.ql-snow .ql-editor pre { + background-color: #f0f0f0; + border-radius: 3px; +} +.ql-snow .ql-editor pre { + white-space: pre-wrap; + margin-bottom: 5px; + margin-top: 5px; + padding: 5px 10px; +} +.ql-snow .ql-editor code { + font-size: 85%; + padding: 2px 4px; +} +.ql-snow .ql-editor pre.ql-syntax { + background-color: #23241f; + color: #f8f8f2; + overflow: visible; +} +.ql-snow .ql-editor img { + max-width: 100%; +} +.ql-snow .ql-picker { + color: #444; + display: inline-block; + float: left; + font-size: 14px; + font-weight: 500; + height: 24px; + position: relative; + vertical-align: middle; +} +.ql-snow .ql-picker-label { + cursor: pointer; + display: inline-block; + height: 100%; + padding-left: 8px; + padding-right: 2px; + position: relative; + width: 100%; +} +.ql-snow .ql-picker-label::before { + display: inline-block; + line-height: 22px; +} +.ql-snow .ql-picker-options { + background-color: #fff; + display: none; + min-width: 100%; + padding: 4px 8px; + position: absolute; + white-space: nowrap; +} +.ql-snow .ql-picker-options .ql-picker-item { + cursor: pointer; + display: block; + padding-bottom: 5px; + padding-top: 5px; +} +.ql-snow .ql-picker.ql-expanded .ql-picker-label { + color: #ccc; + z-index: 2; +} +.ql-snow .ql-picker.ql-expanded .ql-picker-label .ql-fill { + fill: #ccc; +} +.ql-snow .ql-picker.ql-expanded .ql-picker-label .ql-stroke { + stroke: #ccc; +} +.ql-snow .ql-picker.ql-expanded .ql-picker-options { + display: block; + margin-top: -1px; + top: 100%; + z-index: 1; +} +.ql-snow .ql-color-picker, +.ql-snow .ql-icon-picker { + width: 28px; +} +.ql-snow .ql-color-picker .ql-picker-label, +.ql-snow .ql-icon-picker .ql-picker-label { + padding: 2px 4px; +} +.ql-snow .ql-color-picker .ql-picker-label svg, +.ql-snow .ql-icon-picker .ql-picker-label svg { + right: 4px; +} +.ql-snow .ql-icon-picker .ql-picker-options { + padding: 4px 0px; +} +.ql-snow .ql-icon-picker .ql-picker-item { + height: 24px; + width: 24px; + padding: 2px 4px; +} +.ql-snow .ql-color-picker .ql-picker-options { + padding: 3px 5px; + width: 152px; +} +.ql-snow .ql-color-picker .ql-picker-item { + border: 1px solid transparent; + float: left; + height: 16px; + margin: 2px; + padding: 0px; + width: 16px; +} +.ql-snow .ql-picker:not(.ql-color-picker):not(.ql-icon-picker) svg { + position: absolute; + margin-top: -9px; + right: 0; + top: 50%; + width: 18px; +} +.ql-snow .ql-picker.ql-header .ql-picker-label[data-label]:not([data-label=''])::before, +.ql-snow .ql-picker.ql-font .ql-picker-label[data-label]:not([data-label=''])::before, +.ql-snow .ql-picker.ql-size .ql-picker-label[data-label]:not([data-label=''])::before, +.ql-snow .ql-picker.ql-header .ql-picker-item[data-label]:not([data-label=''])::before, +.ql-snow .ql-picker.ql-font .ql-picker-item[data-label]:not([data-label=''])::before, +.ql-snow .ql-picker.ql-size .ql-picker-item[data-label]:not([data-label=''])::before { + content: attr(data-label); +} +.ql-snow .ql-picker.ql-header { + width: 98px; +} +.ql-snow .ql-picker.ql-header .ql-picker-label::before, +.ql-snow .ql-picker.ql-header .ql-picker-item::before { + content: 'Normal'; +} +.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="1"]::before, +.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="1"]::before { + content: 'Heading 1'; +} +.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="2"]::before, +.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="2"]::before { + content: 'Heading 2'; +} +.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="3"]::before, +.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="3"]::before { + content: 'Heading 3'; +} +.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="4"]::before, +.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="4"]::before { + content: 'Heading 4'; +} +.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="5"]::before, +.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="5"]::before { + content: 'Heading 5'; +} +.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="6"]::before, +.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="6"]::before { + content: 'Heading 6'; +} +.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="1"]::before { + font-size: 2em; +} +.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="2"]::before { + font-size: 1.5em; +} +.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="3"]::before { + font-size: 1.17em; +} +.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="4"]::before { + font-size: 1em; +} +.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="5"]::before { + font-size: 0.83em; +} +.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="6"]::before { + font-size: 0.67em; +} +.ql-snow .ql-picker.ql-font { + width: 108px; +} +.ql-snow .ql-picker.ql-font .ql-picker-label::before, +.ql-snow .ql-picker.ql-font .ql-picker-item::before { + content: 'Sans Serif'; +} +.ql-snow .ql-picker.ql-font .ql-picker-label[data-value=serif]::before, +.ql-snow .ql-picker.ql-font .ql-picker-item[data-value=serif]::before { + content: 'Serif'; +} +.ql-snow .ql-picker.ql-font .ql-picker-label[data-value=monospace]::before, +.ql-snow .ql-picker.ql-font .ql-picker-item[data-value=monospace]::before { + content: 'Monospace'; +} +.ql-snow .ql-picker.ql-font .ql-picker-item[data-value=serif]::before { + font-family: Georgia, Times New Roman, serif; +} +.ql-snow .ql-picker.ql-font .ql-picker-item[data-value=monospace]::before { + font-family: Monaco, Courier New, monospace; +} +.ql-snow .ql-picker.ql-size { + width: 98px; +} +.ql-snow .ql-picker.ql-size .ql-picker-label::before, +.ql-snow .ql-picker.ql-size .ql-picker-item::before { + content: 'Normal'; +} +.ql-snow .ql-picker.ql-size .ql-picker-label[data-value=small]::before, +.ql-snow .ql-picker.ql-size .ql-picker-item[data-value=small]::before { + content: 'Small'; +} +.ql-snow .ql-picker.ql-size .ql-picker-label[data-value=large]::before, +.ql-snow .ql-picker.ql-size .ql-picker-item[data-value=large]::before { + content: 'Large'; +} +.ql-snow .ql-picker.ql-size .ql-picker-label[data-value=huge]::before, +.ql-snow .ql-picker.ql-size .ql-picker-item[data-value=huge]::before { + content: 'Huge'; +} +.ql-snow .ql-picker.ql-size .ql-picker-item[data-value=small]::before { + font-size: 10px; +} +.ql-snow .ql-picker.ql-size .ql-picker-item[data-value=large]::before { + font-size: 18px; +} +.ql-snow .ql-picker.ql-size .ql-picker-item[data-value=huge]::before { + font-size: 32px; +} +.ql-snow .ql-color-picker.ql-background .ql-picker-item { + background-color: #fff; +} +.ql-snow .ql-color-picker.ql-color .ql-picker-item { + background-color: #000; +} +.ql-toolbar.ql-snow { + border: 1px solid #ccc; + box-sizing: border-box; + font-family: 'Helvetica Neue', 'Helvetica', 'Arial', sans-serif; + padding: 8px; +} +.ql-toolbar.ql-snow .ql-formats { + margin-right: 15px; +} +.ql-toolbar.ql-snow .ql-picker-label { + border: 1px solid transparent; +} +.ql-toolbar.ql-snow .ql-picker-options { + border: 1px solid transparent; + box-shadow: rgba(0,0,0,0.2) 0 2px 8px; +} +.ql-toolbar.ql-snow .ql-picker.ql-expanded .ql-picker-label { + border-color: #ccc; +} +.ql-toolbar.ql-snow .ql-picker.ql-expanded .ql-picker-options { + border-color: #ccc; +} +.ql-toolbar.ql-snow .ql-color-picker .ql-picker-item.ql-selected, +.ql-toolbar.ql-snow .ql-color-picker .ql-picker-item:hover { + border-color: #000; +} +.ql-toolbar.ql-snow + .ql-container.ql-snow { + border-top: 0px; +} +.ql-snow .ql-tooltip { + background-color: #fff; + border: 1px solid #ccc; + box-shadow: 0px 0px 5px #ddd; + color: #444; + padding: 5px 12px; + white-space: nowrap; +} +.ql-snow .ql-tooltip::before { + content: "Visit URL:"; + line-height: 26px; + margin-right: 8px; +} +.ql-snow .ql-tooltip input[type=text] { + display: none; + border: 1px solid #ccc; + font-size: 13px; + height: 26px; + margin: 0px; + padding: 3px 5px; + width: 170px; +} +.ql-snow .ql-tooltip a.ql-preview { + display: inline-block; + max-width: 200px; + overflow-x: hidden; + text-overflow: ellipsis; + vertical-align: top; +} +.ql-snow .ql-tooltip a.ql-action::after { + border-right: 1px solid #ccc; + content: 'Edit'; + margin-left: 16px; + padding-right: 8px; +} +.ql-snow .ql-tooltip a.ql-remove::before { + content: 'Remove'; + margin-left: 8px; +} +.ql-snow .ql-tooltip a { + line-height: 26px; +} +.ql-snow .ql-tooltip.ql-editing a.ql-preview, +.ql-snow .ql-tooltip.ql-editing a.ql-remove { + display: none; +} +.ql-snow .ql-tooltip.ql-editing input[type=text] { + display: inline-block; +} +.ql-snow .ql-tooltip.ql-editing a.ql-action::after { + border-right: 0px; + content: 'Save'; + padding-right: 0px; +} +.ql-snow .ql-tooltip[data-mode=link]::before { + content: "Enter link:"; +} +.ql-snow .ql-tooltip[data-mode=formula]::before { + content: "Enter formula:"; +} +.ql-snow .ql-tooltip[data-mode=video]::before { + content: "Enter video:"; +} +.ql-snow a { + color: #06c; +} +.ql-container.ql-snow { + border: 1px solid #ccc; +} diff --git a/packages/mobile-ui-vue/components/theme/src/scheadule.scss b/packages/mobile-ui-vue/components/theme/src/scheadule.scss new file mode 100644 index 0000000000000000000000000000000000000000..ef8d9aadbff1386790de6747c1a0bedd50193378 --- /dev/null +++ b/packages/mobile-ui-vue/components/theme/src/scheadule.scss @@ -0,0 +1,210 @@ +@import './mixins/hairline'; + +.fm-scheadule { + display: flex; + flex-direction: column; + background-color: #fff; + .header { + .title { + display: flex; + position: relative; + justify-content: space-between; + align-items: center; + font-size: 15px; + line-height: 38px; + color: #333333; + padding: 0 16px; + } + } + .content { + position: relative; + margin-right: 20px; + margin-left: 4px; + .label { + width: 32px; + display: flex; + align-items: center; + font-size: 11px; + color: #888888; + } + .allDate { + display: flex; + position: relative; + min-height: 28px; + } + .hour-list { + position: relative; + .hour-cell { + display: flex; + height: 40px; + position: relative; + .hour-cell-label { + height: 50%; + justify-content: flex-end; + padding-right: 8px; + } + } + } + } + .event-list { + position: absolute; + left: 36px; + right: 0; + top: 0; + .event-container-absolute { + position: absolute; + left: 0; + right: 0; + top: 0; + z-index: 9; + } + .event-info { + position: absolute; + left: 36px; + right: 0; + display: block; + box-shadow: 0 1px 8px 0 rgba(0, 0, 0, 0.3); + background-color: #fff; + z-index: 99; + .event-info-content { + min-height: 40px; + position: relative; + padding: 9px 12px; + font-size: 15px; + color: #333333; + .event-info-item { + padding: 3px 0; + } + } + .event-info-footer { + height: 40px; + display: flex; + background: #f8f9fb; + .button { + flex: 1; + display: flex; + justify-content: center; + align-items: center; + } + } + .triangle { + position: absolute; + left: 50%; + top: -6px; + width: 8px; + height: 8px; + transform: translateX(-50%) rotate(45deg); + box-shadow: 0 1px 8px 0 rgba(0, 0, 0, 0.3); + background-color: #fff; + &::after { + position: absolute; + width: 180%; + height: 180%; + content: ' '; + pointer-events: none; + left: 0; + right: 0; + top: 0; + bottom: 0; + background-color: #fff; + border: none; + } + } + } + } + .boder-bottom { + &::after { + position: absolute; + box-sizing: border-box; + content: ' '; + pointer-events: none; + right: 0; + bottom: 0; + left: 0; + border-bottom: 1px solid #ddd; + transform: scaleY(0.5); + } + } + .event-container { + border-radius: 2px; + height: 35px; + overflow: hidden; + .event-bg { + position: absolute; + box-sizing: border-box; + content: ' '; + pointer-events: none; + right: 0; + top: 0; + bottom: 0; + left: 0; + opacity: 0.2; + } + .event { + width: 100%; + min-height: 30px; + display: flex; + padding-left: 10px; + padding-bottom: 10px; + .left { + padding-top: 2px; + padding-right: 6px; + } + .right { + display: flex; + flex-direction: column; + font-size: 12px; + color: #333333; + .event-title { + font-weight: 700; + line-height: 18px; + display: flex; + align-items: center; + } + .event-content { + transform: scaleY(0.91); + } + } + } + } + .event-container-focus { + // border-left: 2px solid #7ed321; + .event-bg { + // background: #7ed321; + opacity: 0.4; + } + } + .event-list-all { + position: relative; + width: 100%; + flex: 1; + padding-left: 4px; + .event-container { + position: relative; + &::after { + height: 1px; + width: 100%; + @include scale-hairline-common(#fff, auto, auto, 0, -1px); + } + } + } +} +.event-panel { + max-height: 300px; + overflow-y: auto; + .event-left { + display: flex; + align-items: center; + .event-left-text{ + font-size: 14px; + color: #888888; + } + .event-left-spliter{ + display: inline-block; + margin: 0 4px; + width: 8px; + height: 2px; + background-color: #888888; + } + } +} \ No newline at end of file diff --git a/packages/mobile-ui-vue/components/theme/src/scroll-view.scss b/packages/mobile-ui-vue/components/theme/src/scroll-view.scss new file mode 100644 index 0000000000000000000000000000000000000000..f75b0069e9504fde8a747595a25f9d0490353064 --- /dev/null +++ b/packages/mobile-ui-vue/components/theme/src/scroll-view.scss @@ -0,0 +1,52 @@ +.fm-scroll-view { + position: relative; + display: block; + height: 100%; + overflow: hidden; + -webkit-user-select: none; + user-select: none; + touch-action: pan-y; + .scroll-view-header { + top: 0; + } + .scroll-view-footer { + bottom: 0; + } + .scroll-view-container { + position: relative; + z-index: 1; + &:after { + content: ''; + display: table; + clear: both; + } + .scroll-view-refresh { + position: absolute; + left: 0; + right: 0; + -webkit-transform: translate3d(0, -100%, 0); + transform: translate3d(0, -100%, 0); + &:after { + content: ''; + display: table; + clear: both; + } + } + .scroll-view-more { + visibility: hidden; + &.active { + visibility: visible; + } + } + &.horizon { + display: inline-block; + } + } +} +.md-scroll-view .scroll-view-footer, +.md-scroll-view .scroll-view-header { + position: absolute; + left: 0; + right: 0; + z-index: 2; +} diff --git a/packages/mobile-ui-vue/components/theme/src/scroll.scss b/packages/mobile-ui-vue/components/theme/src/scroll.scss new file mode 100644 index 0000000000000000000000000000000000000000..3473ad52f49c7d6ec37dfe00de56a7787cfe9b87 --- /dev/null +++ b/packages/mobile-ui-vue/components/theme/src/scroll.scss @@ -0,0 +1,8 @@ +.fm-scroll { + width: 100%; + height: 100%; + overflow-y: auto; + display: flex; + flex-direction: column; + -webkit-overflow-scrolling: touch; +} \ No newline at end of file diff --git a/packages/mobile-ui-vue/components/theme/src/search.scss b/packages/mobile-ui-vue/components/theme/src/search.scss new file mode 100644 index 0000000000000000000000000000000000000000..551ac0c0753b94068e256b1fff3c7bb9704cb670 --- /dev/null +++ b/packages/mobile-ui-vue/components/theme/src/search.scss @@ -0,0 +1,62 @@ +@import './mixins/hairline'; + +:root { + --fm-search-background: var(--fm-background-2); + --fm-search-color: var(--fm-text-color); + --fm-search-content-background: var(--fm-background-3); + --fm-search-sub-color: var(--fm-text-color-2); + --fm-search-radius: 17px; +} + +.fm-search { + display: flex; + align-items: center; + padding: 8px 12px; + background-color: var(--fm-search-background); + color: var(--fm-search-color); + &-content { + display: flex; + flex: 1; + padding-left: 8px; + background-color: var(--fm-search-content-background); + .fm-search-wrapper { + display: flex; + flex: 1; + } + .fm-cell { + flex: 1; + background-color: transparent; + padding: 5px 8px 5px 0; + .fm-input-value .fm-input-body .fm-input-control { + font-size: 14px; + &::-webkit-search-cancel-button { + display: none; + } + } + } + .fm-search-left-icon { + color: var(--fm-search-sub-color); + } + &-square { + border-radius: 6px; + } + &-round { + border-radius: 17px; + } + .fm-search-label { + padding: 0 5px; + font-size: 14px; + line-height: 36px; + } + } + &-action { + padding-left: 10px; + font-size: 16px; + line-height: 34px; + cursor: pointer; + user-select: none; + } +} +.fm-search-wrapper { + flex: 1; +} diff --git a/packages/mobile-ui-vue/components/theme/src/share-sheet.scss b/packages/mobile-ui-vue/components/theme/src/share-sheet.scss new file mode 100644 index 0000000000000000000000000000000000000000..be7a95ddf73b12606426fb13f24d7f04eaf126db --- /dev/null +++ b/packages/mobile-ui-vue/components/theme/src/share-sheet.scss @@ -0,0 +1,88 @@ +@import './mixins/hairline'; + +.fm-sharesheet { + display: flex; + flex-direction: column; + max-height: 80%; + overflow: hidden; + &.fm-sharesheet-round { + border-radius: 16px 16px 0 0; + } + &-header { + flex-shrink: 0; + padding: 21px 16px 4px; + text-align: center; + &-title { + font-weight: 500; + font-size: 16px; + } + } + &-description { + display: block; + margin-top: 8px; + color: #999999; + font-size: 12px; + line-height: 16px; + text-align: center; + } + &-cancel { + flex-shrink: 0; + padding-top: 8px; + background-color:#f7f8fa; + &-inner { + display: block; + width: 100%; + padding: 14px 16px; + font-size: 16px; + text-align: center; + background-color: #fff; + border: none; + cursor: pointer; + &:active { + background-color: #f2f3f5; + } + } + } + &-options { + position: relative; + display: flex; + padding: 16px 0 16px 8px; + overflow-x: auto; + overflow-y: visible; + -webkit-overflow-scrolling: touch; + &::-webkit-scrollbar { + display: none; + } + .fm-sharesheet-option { + display: flex; + flex-direction: column; + align-items: center; + cursor: pointer; + user-select: none; + .fm-sharesheet-icon{ + width: 48px; + height: 48px; + margin: 0 16px; + } + .fm-sharesheet-name{ + margin-top: 8px; + padding: 0 4px; + color: #646566; + font-size: 12px; + } + .fm-sharesheet-description{ + padding: 0 4px; + color: #ccc; + font-size: 12px; + } + } + &.fm-sharesheet-options-border{ + @include hairline('top'); + &::before{ + left: 16px!important; + right: 16px!important; + width: calc(100% - 32px)!important; + } + } + } +} diff --git a/packages/mobile-ui-vue/components/theme/src/sidebar.scss b/packages/mobile-ui-vue/components/theme/src/sidebar.scss new file mode 100644 index 0000000000000000000000000000000000000000..91e3f834a8c610b3a2157dffe23f68f1417e31e4 --- /dev/null +++ b/packages/mobile-ui-vue/components/theme/src/sidebar.scss @@ -0,0 +1,53 @@ +@import './mixins/hairline'; + +:root { + --fm-sidebar-color: var(--fm-text-color); + --fm-sidebar-font-size: 14px; + --fm-sidebar-list-background: var(--fm-background-3); + --fm-sidebar-item-background: var(--fm-background); + --fm-sidebar-item-active-background: var(--fm-blue-2); + --fm-sidebar-item-active-color: var(--fm-white); +} +.fm-sidebar{ + display: flex; + flex-direction: row; + width: 100%; + height: 100%; + overflow: hidden; + color: var(--fm-sidebar-color); + font-size: var(--fm-sidebar-font-size); + &-list{ + flex-shrink: 0; + position: relative; + height: 100%; + overflow-y: auto; + background-color: var(--fm-sidebar-list-background); + } + .fm-sidebar-item{ + position: relative; + display: block; + box-sizing: border-box; + padding: 16px 10px; + overflow: hidden; + line-height: 20px; + background-color: var(--fm-sidebar-item-background); + text-align: center; + cursor: pointer; + user-select: none; + &-active{ + background: var(--fm-sidebar-item-active-background); + color: var(--fm-sidebar-item-active-color); + } + } + &-content{ + flex: 1 1 0; + position: relative; + height: 100%; + overflow-y: auto; + } + &-list,&-content{ + &::-webkit-scrollbar { + display: none; + } + } +} \ No newline at end of file diff --git a/packages/mobile-ui-vue/components/theme/src/skeleton.scss b/packages/mobile-ui-vue/components/theme/src/skeleton.scss new file mode 100644 index 0000000000000000000000000000000000000000..43e4372f523c44b9ccd3e681997f60dd9211bc37 --- /dev/null +++ b/packages/mobile-ui-vue/components/theme/src/skeleton.scss @@ -0,0 +1,59 @@ +:root { + --fm-skeleton-background: var(--fm-background-3); +} +.fm-skeleton { + display: flex; + padding: 0 16px; + + &-avatar { + flex-shrink: 0; + margin-right: 10px; + background-color: var(--fm-skeleton-background); + + &-round { + border-radius: 100%; + } + } + + &-content { + width: 100%; + } + + + &-row, + &-title { + height: 16px; + background-color: var(--fm-skeleton-background); + } + + &-title { + margin: 0; + } + + &-row { + &:not(:first-child) { + margin-top: 16px; + } + } + + &-title + &-row { + margin-top: 20px; + } + + &-animate { + animation: fm-skeleton-blink 1.2s ease-in-out infinite; + } + + &-round { + .fm-skeleton-row, + .fm-skeleton-title { + border-radius: 100%; + } + } +} + +@keyframes fm-skeleton-blink { + 50% { + opacity: 0.6; + } +} diff --git a/packages/mobile-ui-vue/components/theme/src/steps.scss b/packages/mobile-ui-vue/components/theme/src/steps.scss new file mode 100644 index 0000000000000000000000000000000000000000..0853484381ff6934bee629036864de7b204f2d58 --- /dev/null +++ b/packages/mobile-ui-vue/components/theme/src/steps.scss @@ -0,0 +1,170 @@ +@import './mixins/hairline'; + +:root { + --fm-steps-primary-color: var(--fm-primary-color); +} + +.fm-steps { + &-list { + display: flex; + justify-content: space-around; + align-items: center; + } + &-item { + display: flex; + flex-direction: column; + align-items: center; + position: relative; + margin: 0 8px; + .item-icon { + width: 20px; + height: 20px; + background-color: #ccc; + border-radius: 50%; + color: #fff; + .fm-icon, + .item-icon-text { + display: block; + line-height: 20px; + font-size: 12px; + margin: 0 auto; + text-align: center; + transform: scale(0.83); + } + } + .item-text { + position: absolute; + .name { + white-space: nowrap; + line-height: 18px; + font-size: 13px; + color: #999; + } + .desc { + margin-top: 4px; + font-size: 12px; + line-height: 20px; + color: #ccc; + } + .sub-desc { + line-height: 18px; + font-size: 13px; + color: #999999; + } + } + &-finish, + &-current { + .item-icon { + background-color: var(--fm-steps-primary-color); + } + .item-text .name { + color: #333333; + } + .item-icon-text { + color: #fff; + } + } + &-current { + .item-text .name { + color: var(--fm-steps-primary-color); + } + } + } + &-line { + position: relative; + background: #e8e8e8; + overflow: hidden; + .line-inner { + position: absolute; + z-index: 10; + position: absolute; + top: 0; + left: 0; + display: block; + } + &-horizontal { + flex: 1; + height: 1px; + .line-inner { + width: 100%; + height: 1px; + background-color: var(--fm-steps-primary-color); + transition: all 0.3s linear; + transform: translate3d(-100%, 0px, 0px); + } + &.fm-steps-line-finish { + .line-inner { + transform: translate3d(0%, 0px, 0px); + transition: all 0.3s linear 0s; + } + } + } + } + &-horizontal { + padding-top: 26px; + .fm-steps-list { + .fm-steps-item { + .item-text { + top: calc(-100% - 6px); + margin-bottom: 11px; + text-align: center; + } + } + } + } + &-vertical { + padding-left: 32px; + .fm-steps-list { + height: 100%; + flex-direction: column; + align-items: flex-start; + .fm-steps-item { + flex-direction: row; + width: 100%; + margin: 0; + padding: 15px 10px 15px 0; + align-items: stretch; + .item-icon { + position: absolute; + top: 15px; + left: -18px; + z-index: 2; + } + .item-text { + position: static; + padding-left: 14px; + .name { + font-size: 16px; + font-weight: 600; + color: #333; + white-space: normal; + } + .desc { + line-height: 20px; + font-size: 14px; + color: #333; + } + } + .item-line { + position: absolute; + top: 16px; + left: -8px; + width: 1px; + height: 100%; + background-color: #e8e8e8; + } + &-finish { + .item-line { + background-color: var(--fm-steps-primary-color); + } + } + } + } + &.fm-steps-fill { + height: 100%; + .fm-steps-list .fm-steps-item { + flex: 1; + } + } + } +} diff --git a/packages/mobile-ui-vue/components/theme/src/swipe.scss b/packages/mobile-ui-vue/components/theme/src/swipe.scss new file mode 100644 index 0000000000000000000000000000000000000000..8b90ce9506ad3aaab5b62099a253daf4983c7a57 --- /dev/null +++ b/packages/mobile-ui-vue/components/theme/src/swipe.scss @@ -0,0 +1,66 @@ +@import './mixins/hairline'; + +:root { + --fm-swipe-indicator-width: 6px; + --fm-swipe-indicator-height: 6px; + --fm-swipe-indicator-margin: 6px; + --fm-swipe-indicator-background: #ebedf0; +} + +.fm-swipe { + position: relative; + overflow: hidden; + cursor: grab; + user-select: none; + + &-box { + display: flex; + height: 100%; + + &-vertical { + flex-direction: column; + } + } + + &-indicators { + position: absolute; + bottom: 12px; + left: 50%; + display: flex; + transform: translateX(-50%); + + &-vertical { + top: 50%; + bottom: auto; + left: 12px; + flex-direction: column; + transform: translateY(-50%); + + .fm-swipe-indicator:not(:last-child) { + margin-bottom: var(--fm-swipe-indicator-margin); + } + } + } + + &-indicator { + width: var(--fm-swipe-indicator-width); + height: var(--fm-swipe-indicator-width); + background-color: var(--fm-swipe-indicator-background); + border-radius: var(--fm-radius-max); + transition: opacity var(--fm-duration-fast); + &:not(:last-child) { + margin-right: var(--fm-swipe-indicator-margin); + } + + &-active { + background-color: var(--fm-primary-color); + opacity: .3; + } + } + &-item { + position: relative; + flex-shrink: 0; + width: 100%; + height: 100%; + } +} diff --git a/packages/mobile-ui-vue/components/theme/src/swipecell.scss b/packages/mobile-ui-vue/components/theme/src/swipecell.scss new file mode 100644 index 0000000000000000000000000000000000000000..d176983987ad066ce87aff3e54f65261d20bdff3 --- /dev/null +++ b/packages/mobile-ui-vue/components/theme/src/swipecell.scss @@ -0,0 +1,28 @@ +.fm-swipe-cell{ + position: relative; + overflow: hidden; + cursor: grab; + + &-wrapper { + transition-timing-function: cubic-bezier(0.18, 0.89, 0.32, 1); + transition-property: transform; + } + + &-left, + &-right { + position: absolute; + top: 0; + height: 100%; + display: flex; + } + + &-left { + left: 0; + transform: translate3d(-100%, 0, 0); + } + + &-right { + right: 0; + transform: translate3d(100%, 0, 0); + } +} \ No newline at end of file diff --git a/packages/mobile-ui-vue/components/theme/src/switch.scss b/packages/mobile-ui-vue/components/theme/src/switch.scss new file mode 100644 index 0000000000000000000000000000000000000000..9261c19ae24a30c29fa093a8190b0d671e55a921 --- /dev/null +++ b/packages/mobile-ui-vue/components/theme/src/switch.scss @@ -0,0 +1,70 @@ +@import './mixins/hairline'; + +:root { + --fm-switch-background: var(--fm-gray-5); + --fm-switch-on-color: var(--fm-primary-color); +} + +.fm-switch { + position: relative; + display: inline-block; + width: 50px; + height: 30px; + font-size: 30px; + border-radius: 40px; + cursor: pointer; + transition: background-color var(--fm-duration-base); + background-color: var(--fm-switch-background); + &-node { + position: absolute; + top: 1px; + left: 1px; + z-index: 1; + width: 28px; + height: 28px; + border-radius: 100%; + background-color: var(--fm-white); + transition: transform var(--fm-duration-base) + cubic-bezier(0.3, 1.05, 0.4, 1.05); + .fm-switch-loading-icon { + position: absolute; + top: 25%; + left: 25%; + width: 50%; + height: 50%; + line-height: 1; + color: var(--fm-switch-on-color); + circle { + animation: fm-circular 1.5s ease-in-out infinite; + stroke: currentColor; + stroke-width: 3; + stroke-linecap: round; + } + &-circular { + vertical-align: super; + } + } + } + + &-on { + background-color: var(--fm-switch-on-color); + .fm-switch-node { + transform: translateX(calc(50px - 30px)); + } + .fm-switch-loading { + color: var(--fm-switch-on-color); + } + } + &-disabled { + cursor: not-allowed; + opacity: var(--fm-disabled-opacity); + } + &-readonly { + cursor: default; + opacity: var(--fm-readonly-opacity); + } + + &-loading { + cursor: default; + } +} diff --git a/packages/mobile-ui-vue/components/theme/src/tab-bar.scss b/packages/mobile-ui-vue/components/theme/src/tab-bar.scss new file mode 100644 index 0000000000000000000000000000000000000000..f5370de340be7ef70853570fb3cdfe46fd1d1844 --- /dev/null +++ b/packages/mobile-ui-vue/components/theme/src/tab-bar.scss @@ -0,0 +1,225 @@ +@import './mixins/hairline'; + +:root { + --fm-tab-bar-height: 44px; + --fm-tab-bar-background: var(--fm-background-2); + --fm-tab-bar-color: var(--fm-text-color); + --fm-tab-bar-active-color: var(--fm-primary-color); + --fm-tab-bar-font-size: 16px; +} + +.fm-tab-bar { + position: relative; + background: var(--fm-tab-bar-background); + color: var(--fm-tab-bar-color); + font-size: var(--fm-tab-bar-font-size); + @include hairline('bottom'); + .fm-scroll-view { + display: block; + } + .scroll-view-container { + min-width: 100%; + } + .fm-tab-bar-inner { + position: relative; + width: 100%; + } + .fm-tab-bar-extendable { + width: calc(100% - 30px); + } + .fm-tab-bar-list { + display: flex; + justify-content: space-between; + min-width: 100%; + } + .fm-tab-bar-item { + flex: auto; + flex-shrink: 0; + position: relative; + display: inline-flex; + align-items: center; + justify-content: center; + min-height: var(--fm-tab-bar-height); + padding: 0 12px; + margin: 0 auto; + box-sizing: border-box; + &.is-active { + color: var(--fm-tab-bar-active-color); + } + &.is-disabled { + color: var(--fm-disabled-color); + } + + &-content .fm-tab-bar-icon { + position: relative; + display: flex; + align-items: center; + justify-content: center; + .fm-tab-bar-info { + position: absolute; + top: 0; + right: 0; + padding: 0 3px; + margin-top: 4px; + font-weight: 500; + font-size: 12px; + line-height: 14px; + color: var(--fm-background-2); + border-radius: 16px; + background-color: var(--fm-danger-color); + transform: translate(50%, -50%); + &.fm-tab-bar-dot { + width: 8px; + height: 8px; + background-color: var(--fm-danger-color); + border-radius: 100%; + } + } + } + } + .fm-tab-bar-ink { + position: absolute; + bottom: 0; + left: 0; + display: block; + height: 4px; + background-color: var(--fm-tab-bar-active-color); + transition: all var(--fm-duration-base); + border-radius: 2px; + &.is-disabled { + background-color: var(--fm-disabled-color); + } + } + .fm-tab-bar-extend, + .fm-tab-bar-end, + .fm-tab-bar-start { + position: absolute; + top: 0; + left: 0; + bottom: 0; + width: 14px; + overflow: hidden; + } + .fm-tab-bar-end:after, + .fm-tab-bar-start:after { + content: ''; + display: block; + position: absolute; + left: -14px; + top: 50%; + width: 14px; + margin-top: -22px; + height: var(--fm-tab-bar-height); + border-radius: 50%; + box-shadow: -1px 0 12px 0 var(--fm-box-shadow-color); + } + .fm-tab-bar-end { + left: auto; + right: 0; + -webkit-transform: rotate(180deg); + transform: rotate(180deg); + } + .fm-tab-bar-extend { + left: auto; + right: -30px; + width: 42px; + margin: 4px 0; + display: flex; + align-items: center; + justify-content: center; + background-image: linear-gradient( + 270deg, + #ffffff 74%, + rgba(255, 255, 255, 0) 100% + ); + border-radius: 2px; + z-index: 2; + } + &.fm-tab-bar-tab { + .fm-tab-bar-item-content { + display: flex; + align-items: center; + justify-content: center; + .fm-tab-bar-icon { + margin-right: 6px; + } + } + } + &.fm-tab-bar-nav { + @include hairline('top'); + @include hairline-remove('bottom'); + .fm-tab-bar-item { + flex-direction: column; + min-height: 49px; + &.is-active { + color: var(--fm-tab-bar-active-color); + .fm-tab-bar-icon { + .fm-icon { + color: var(--fm-gradient-blue); + } + } + .text { + color: var(--fm-primary-color); + } + } + .fm-tab-bar-icon { + font-size: 20px; + margin: 4px 0; + text-align: center; + .fm-icon { + font-size: 24px; + color: var(--fm-text-color-3); + } + } + .text { + line-height: 13px; + font-size: 10px; + color: var(--fm-text-color-2); + } + } + } +} +.fm-tab-bar-panel { + height: 60vh; + padding: 0 16px; + background-color: #fff; + &-header { + height: 44px; + font-size: 16px; + display: flex; + justify-content: center; + align-items: center; + padding-bottom: 10px; + } + &-content { + display: flex; + flex-wrap: wrap; + } + &-item { + height: 30px; + width: calc(33.3% - 8px); + padding: 0 8px; + margin-bottom: 8px; + display: flex; + justify-content: center; + align-items: center; + border-radius: 4px; + background: #f6f6f6; + &-text { + font-size: 13px; + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; + } + } + &-item:nth-child(3n+1) { + margin-right: 12px; + } + &-item:nth-child(3n+3) { + margin-left: 12px; + } + &-item-active { + background: #3a90ff; + color: #fff; + } +} diff --git a/packages/mobile-ui-vue/components/theme/src/tab.scss b/packages/mobile-ui-vue/components/theme/src/tab.scss new file mode 100644 index 0000000000000000000000000000000000000000..be1116f959fc4efcd22f71b6193b30d4949d59b2 --- /dev/null +++ b/packages/mobile-ui-vue/components/theme/src/tab.scss @@ -0,0 +1,46 @@ +.fm-tab-pane { + display: flex; + flex-direction: column; + overflow: hidden; + flex: 1; + position: relative; + width: 100%; + transform: translateZ(0); + &.fm-tab-slide-left, + &.fm-tab-slide-right { + &-enter-from { + opacity: 0.01; + } + &-enter-active { + transition: all 300ms; + } + &-leave-active { + position: absolute; + top: 0; + transition: all 300ms; + } + &-leave-to { + opacity: 0.01; + } + } + &.fm-tab-slide-left { + &-enter-from { + transform: translateX(100%); + } + &-leave-to { + transform: translateX(-100%); + } + } + &.fm-tab-slide-right { + &-enter-from { + transform: translateX(-100%); + } + &-leave-to { + transform: translateX(100%); + } + } +} + +[v-cloak] { + display: none; +} \ No newline at end of file diff --git a/packages/mobile-ui-vue/components/theme/src/tabs.scss b/packages/mobile-ui-vue/components/theme/src/tabs.scss new file mode 100644 index 0000000000000000000000000000000000000000..7956110b8f4fadbe5d3c0762a832f4587265abff --- /dev/null +++ b/packages/mobile-ui-vue/components/theme/src/tabs.scss @@ -0,0 +1,22 @@ +.fm-tabs { + .fm-tabs-content{ + position: relative; + width: 100%; + overflow: hidden; + } +} +.fm-tabs-fill{ + flex: 1; + display: flex; + flex-direction: column; + .fm-tab-bar{ + flex-shrink: 0; + } + .fm-tabs-content{ + display: flex; + flex-direction: column; + flex-grow: 1; + flex-shrink: 1; + flex-basis: 0; + } +} diff --git a/packages/mobile-ui-vue/components/theme/src/tag.scss b/packages/mobile-ui-vue/components/theme/src/tag.scss new file mode 100644 index 0000000000000000000000000000000000000000..dc7ee488fa6ee694c7f38ca2cbccd02886d6ec21 --- /dev/null +++ b/packages/mobile-ui-vue/components/theme/src/tag.scss @@ -0,0 +1,37 @@ +@import './mixins/hairline'; + +:root { + --fm-tag-color: var(--fm-white); +} + +.fm-tag{ + position: relative; + display: inline-flex; + align-items: center; + white-space: nowrap; + padding: 0 6px; + font-size: 13px; + line-height: 20px; + border-radius: 4px; + color: var(--fm-tag-color); + background-color: var(--fm-primary-color); + &-info{ + background-color: var(--fm-primary-color); + } + &-submit{ + background-color: var(--fm-submit-color); + } + &-success{ + background-color: var(--fm-success-color); + } + &-danger{ + background-color: var(--fm-danger-color); + } + &-warning{ + background-color: var(--fm-warning-color); + } + &-sign{ + font-size: 10px; + border-radius: 0 100px 100px 0; + } +} \ No newline at end of file diff --git a/packages/mobile-ui-vue/components/theme/src/tags.scss b/packages/mobile-ui-vue/components/theme/src/tags.scss new file mode 100644 index 0000000000000000000000000000000000000000..cc91f7c97a03ad0e4edb3d835308106b02563f60 --- /dev/null +++ b/packages/mobile-ui-vue/components/theme/src/tags.scss @@ -0,0 +1,129 @@ +@import './mixins/hairline'; + +:root { + --fm-tags-delete-color: var(--fm-gray-5); +} + +.fm-tags{ + .fm-tags-item-container{ + .fm-tag-item{ + display: inline-block; + padding: 0 10px; + margin: 0 4px 4px 0; + line-height: 24px; + font-size: 16px; + white-space: nowrap; + border-radius: var(--fm-radius-max); + cursor: default; + color: var(--fm-tags-color); + a{ + color: rgba(0,0,0,.85); + } + &>a:first-child:last-child{ + display: inline-block; + margin: 0 -4px; + padding: 0 10px; + } + .tag-delete{ + font-size: 16px; + margin-left: 6px; + color: var(--fm-tags-delete-color); + cursor: pointer; + display: inline-block; + .fm-icon{ + vertical-align: baseline; + } + } + &>.fm-icon{ + font-size: 12px; + } + &>.fm-icon+span, &>span+.fm-icon{ + margin-left: 7px; + } + &.fm-tag-item-success { + background-color: var(--fm-success-color-light); + color: var(--fm-success-color); + .tag-delete{ + color: var(--fm-success-color); + } + } + &.fm-tag-item-info { + color: var(--fm-primary-color); + background-color: var(--fm-primary-color-light); + .tag-delete{ + color: var(--fm-primary-color); + } + } + &.fm-tag-item-danger { + background-color: var(--fm-danger-color-light); + color: var(--fm-danger-color); + .tag-delete{ + color: var(--fm-danger-color); + } + } + &.fm-tag-item-warning { + color: var(--fm-warning-color); + background-color: var(--fm-warning-color-light); + .tag-delete{ + color: var(--fm-warning-color); + } + } + &.fm-tag-item-has-color{ + color: var(--fm-background-2); + border-color: transparent; + .tag-delete,a{ + color: var(--fm-background-2); + } + } + &.fm-tag-item-checkable:not(.fm-tag-item-checked) { + background-color: transparent; + border-color: transparent; + cursor: pointer; + &:active{ + color: var(--fm-primary-color); + } + } + &.fm-tag-item-checkdisabled{ + background-color: transparent; + border-color: transparent; + cursor: not-allowed; + color: #ccc; + } + &.fm-tag-item-checked{ + background-color: var(--fm-background-2); + border-color: var(--fm-primary-color); + color: var(--fm-primary-color); + } + &:last-child{ + margin-right: 0; + } + } + .fm-tag-add-button{ + line-height: 22px; + cursor: pointer; + background: #F9F9F9; + border: 1px dashed #ddd; + .fm-tag-add-text{ + color: #999; + } + .fm-icon{ + color: rgba(0,0,0,.2); + } + } + .fm-tag-input-box{ + display: inline-block; + .fm-form-control{ + width: 100px; + &:focus{ + box-shadow: none; + } + } + } + } + &.fm-tags-checkable{ + .fm-tag-item{ + line-height: 22px; + border:1px solid #f6f6f6; + } + } +} \ No newline at end of file diff --git a/packages/mobile-ui-vue/components/theme/src/text-area.scss b/packages/mobile-ui-vue/components/theme/src/text-area.scss new file mode 100644 index 0000000000000000000000000000000000000000..5ad734a73284bcdfce18f4ac5f76d8db9497b9c1 --- /dev/null +++ b/packages/mobile-ui-vue/components/theme/src/text-area.scss @@ -0,0 +1,3 @@ +.fm-field-textarea { + flex-direction: column; +} \ No newline at end of file diff --git a/packages/mobile-ui-vue/components/theme/src/text.scss b/packages/mobile-ui-vue/components/theme/src/text.scss new file mode 100644 index 0000000000000000000000000000000000000000..396aa6e75d613bbad5c4c3b5940061996bd946e4 --- /dev/null +++ b/packages/mobile-ui-vue/components/theme/src/text.scss @@ -0,0 +1,24 @@ + +.fm-text { + display: flex; + flex-direction: row; + align-items: center; + margin: 8px 16px; + line-height: 22px; + .label { + width: 92px; + font-size: 14px; + color: #999999; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + } + .text { + flex-grow: 1; + flex-basis: 0; + padding-left: 8px; + font-size: 14px; + color: #333333; + flex-shrink: 1; + } +} \ No newline at end of file diff --git a/packages/mobile-ui-vue/components/theme/src/toast.scss b/packages/mobile-ui-vue/components/theme/src/toast.scss new file mode 100644 index 0000000000000000000000000000000000000000..abd14b1b35b024bd8e8f65c53a99e96e5b056d65 --- /dev/null +++ b/packages/mobile-ui-vue/components/theme/src/toast.scss @@ -0,0 +1,76 @@ +@import './mixins/hairline'; + +:root { + --fm-toast-zindex: var(--fm-zindex-5); + --fm-toast-color: var(--fm-white); + --fm-toast-font-size: 16px; + --fm-toast-background: var(--fm-gray-8); + --fm-toast-icon-font-size: 48px; +} + +.fm-toast { + position: fixed; + top: 50%; + left: 50%; + display: -webkit-box; + display: -webkit-flex; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + box-sizing: content-box; + max-width: 70%; + padding: 16px; + line-height: 20px; + white-space: pre-wrap; + text-align: center; + word-wrap: break-word; + border-radius: 7px; + transform: translate(-50%, -50%); + color: var(--fm-toast-color); + z-index: var(--fm-toast-zindex); + font-size: var(--fm-toast-font-size); + background-color: var(--fm-toast-background); + &-top { + top: 50px; + transform: translate(-50%, 0); + } + &-bottom { + top: auto; + bottom: 50px; + } + &-info, + &-success, + &-warning, + &-error { + width: 88px; + min-height: 88px; + } + + &-icon { + margin-bottom: 8px; + font-size: var(--fm-toast-icon-font-size); + } + &-default { + padding: 8px 16px; + } + &-loading { + min-width: 84px; + min-height: 84px; + } + &-loading-icon { + position: relative; + display: inline-block; + width: 30px; + height: 30px; + margin-bottom: 8px; + vertical-align: middle; + animation: fm-rotate 2s linear infinite; + circle { + animation: fm-circular 1.5s ease-in-out infinite; + stroke: currentColor; + stroke-width: 4; + stroke-linecap: round; + } + } +} diff --git a/packages/mobile-ui-vue/components/theme/src/tree-bar.scss b/packages/mobile-ui-vue/components/theme/src/tree-bar.scss new file mode 100644 index 0000000000000000000000000000000000000000..156a23a2145604c33ffe16bfdd5722c1cc89ed8f --- /dev/null +++ b/packages/mobile-ui-vue/components/theme/src/tree-bar.scss @@ -0,0 +1,102 @@ +:root { + --fm-tree-bar-height: 100%; + --fm-tree-bar-width: 80vw; + --fm-tree-bar-background: var(--fm-background); + --fm-tree-bar-color: var(--fm-text-color); + --fm-tree-bar-active-background: var(--fm-background-2); + --fm-tree-bar-active-color: var(--fm-primary-color); + --fm-tree-bar-item-active-background: var(--fm-blue-light); +} +.fm-tree-bar { + height: var(--fm-tree-bar-height); +} +.tree-level-one-wrapper { + width: var(--fm-tree-bar-width); +} +.tree-level-two-wrapper, +.tree-level-three-wrapper { + display: flex; + .level-menu { + display: flex; + flex-direction: column; + background: var(--fm-tree-bar-background); + .level-menu-item { + position: relative; + display: flex; + align-items: center; + justify-content: center; + width: 80px; + height: 48px; + font-size: 12px; + line-height: 16px; + color: var(--fm-tree-bar-color); + } + .level-menu-item-selected { + font-weight: var(--fm-font-bold); + color: var(--fm-tree-bar-active-color); + background-color: var(--fm-tree-bar-active-background); + &::before { + content: ''; + height: 20px; + width: 4px; + position: absolute; + left: 0; + top: 14px; + border-radius: 2px; + background-image: var(--fm-gradient-blue); + } + } + } + .level-list { + width: 268px; + } +} +.tree-level-one-wrapper, +.tree-level-two-wrapper { + .fm-cell { + .fm-cell-title-text { + font-size: 12px; + line-height: 28px; + } + } +} +.tree-level-three-wrapper { + .level-list { + padding: 12px 16px; + } + .level-item-panel { + line-height: 16px; + padding-bottom: 12px; + .level-item-title { + font-size: 12px; + font-weight: 500; + } + .level-item-sub-list { + padding-top: 11px; + display: flex; + flex-wrap: wrap; + .level-item-sub-item { + width: 72px; + padding: 0 4px; + margin-bottom: 10px; + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; + flex-shrink: 0; + font-size: 11px; + line-height: 28px; + border-radius: 4px; + text-align: center; + background: var(--fm-background); + &:not(:nth-child(3n)) { + margin-right: 10px; + } + } + .level-item-selected { + color: var(--fm-tree-bar-active-color); + border: 0 solid var(--fm-tree-bar-active-color); + background: var(--fm-tree-bar-item-active-background); + } + } + } +} diff --git a/packages/mobile-ui-vue/components/theme/src/upload.scss b/packages/mobile-ui-vue/components/theme/src/upload.scss new file mode 100644 index 0000000000000000000000000000000000000000..e28b4de5f43a6373c7afb43c1407432917384ddf --- /dev/null +++ b/packages/mobile-ui-vue/components/theme/src/upload.scss @@ -0,0 +1,276 @@ +.fm-upload-actionsheet-content { + flex: 1 auto; + overflow-y: auto; + + &__item { + font-family: PingFangSC-Regular; + display: block; + width: 100%; + padding: 14px 16px; + font-size: 16px; + text-align: center; + background-color: #ffffff; + border: none; + cursor: pointer; + text-align: center; + -webkit-user-select: none; + user-select: none; + + &-tip { + font-size: 12px; + color: #999999; + letter-spacing: 0; + margin-top: 5px; + } + + &--disabled { + color: #cccccc; + cursor: not-allowed; + } + } +} + +.fm-preview-file-popup { + display: flex; + flex-direction: column; + overflow: hidden; + width: 100%; + height: 100%; + + &__preview-iframe { + border: none; + + &-wrapper { + flex: 1; + } + } +} + +.fm-upload { + background: #ffffff; + -webkit-user-select: none; + user-select: none; + + &--single-btn { + display: inline-block; + } + + &--has-list { + padding: 16px; + } + + div { + -webkit-user-select: none; + user-select: none; + } + span { + -webkit-user-select: none; + user-select: none; + } + img { + -webkit-user-select: none; + -webkit-touch-callout: none; + user-select: none; + } + button { + -webkit-user-select: none; + user-select: none; + } + + &__default-header { + padding: 0.5rem 0; + font-size: 16px; + } + + &__file-list { + .fm-listview-item { + margin: 12px 0; + } + } + + &__file-item { + display: flex; + justify-content: space-between; + + &-thumbnail { + width: 100%; + height: 100%; + + &-wrapper { + width: 48px; + height: 48px; + margin: auto 0; + img { + border-radius: 3px; + width: 48px; + height: 48px; + } + } + } + + &-info { + flex: 1; + margin: auto 12px; + font-family: PingFangSC-Regular; + &-row { + display: flex; + justify-content: space-between; + margin-bottom: 5px; + } + } + + &-name { + display: block; + line-height: 22px; + font-size: 16px; + color: #333333; + letter-spacing: 0.21px; + margin-bottom: 2px; + word-break: break-all; + } + + &-text { + display: block; + line-height: 18px; + font-size: 12px; + color: #888888; + letter-spacing: 0; + } + + &-action-button { + margin: auto 0; + width: 16px; + height: 16px; + transform: rotate(90deg); + cursor: pointer; + } + } + + &__upload-button { + width: 48px; + height: 48px; + background-color: #f6f6f6; + border-radius: 3px; + cursor: pointer; + .fm-icon { + display: block; + font-size: 20px; + line-height: 48px; + color: #dddddd; + margin: 0 auto; + } + + &-wrapper { + display: inline-block; + position: relative; + z-index: 8; + } + + &--readonly { + opacity: 0.6; + cursor: not-allowed; + } + } +} + +$tooltip-bg-color: #333333; +$tooltip-text-color: #cccccc; + +.fm-file-action-tooltip { + font-family: PingFangSC-Medium; + position: absolute; + z-index: 3000; + min-width: 150px; + margin: 0; + background: $tooltip-bg-color; + border-radius: 5px; + font-size: 13px; + color: $tooltip-text-color; + letter-spacing: 0; + + &--hidden { + z-index: -9999; + left: -9999px !important; + top: -99999px !important; + } + + div { + -webkit-user-select: none; + user-select: none; + } + span { + -webkit-user-select: none; + user-select: none; + } + + &__arrow { + position: absolute; + border: 5px solid transparent; + width: 0; + height: 0; + + &--top { + border-top-color: $tooltip-bg-color; + left: 50%; + top: 100%; + } + &--top-start { + border-top-color: $tooltip-bg-color; + left: 80%; + top: 100%; + } + &--top-end { + border-top-color: $tooltip-bg-color; + left: 20%; + top: 100%; + } + &--right-start { + border-right-color: $tooltip-bg-color; + right: 100%; + top: 30px; + } + &--right-end { + border-right-color: $tooltip-bg-color; + right: 100%; + bottom: 30px; + } + &--left-start { + border-left-color: $tooltip-bg-color; + left: 100%; + top: 30px; + } + &--left-end { + border-left-color: $tooltip-bg-color; + left: 100%; + bottom: 30px; + } + } + + &__item { + line-height: 3; + margin: 0 10px; + + &-tip { + font-size: 10px; + margin-top: -20px; + } + + &--disabled { + opacity: 0.4; + } + + &:not(:last-child) { + border-bottom: 1px solid rgba(102, 102, 102, 0.5); + } + } + + &__mask { + display: block; + position: fixed; + top: 0; + right: 0; + bottom: 0; + left: 0; + z-index: 2999; + } +} diff --git a/packages/mobile-ui-vue/components/utils/index.ts b/packages/mobile-ui-vue/components/utils/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..97e4c4554a12151cf3a9701ae2f16f05492d7a23 --- /dev/null +++ b/packages/mobile-ui-vue/components/utils/index.ts @@ -0,0 +1,17 @@ +export * from './src/dom/event'; +export * from './src/dom/element'; +export * from './src/dom/style'; +export * from './src/dom/scroller'; +export * from './src/common'; +export * from './src/hook'; +export * from './src/date'; +export * from './src/number'; +export * from './src/vue-compile/codegen'; +export * from './src/array'; +export * from './src/type'; +export * from './src/interceptor'; +export * from './src/string'; +export * from './src/throttle'; +export * from './src/debounce'; +export * from './src/bem'; +export * from './src/deep-assign'; diff --git a/packages/mobile-ui-vue/components/utils/src/array.ts b/packages/mobile-ui-vue/components/utils/src/array.ts new file mode 100644 index 0000000000000000000000000000000000000000..99aa7e60d623b327bce0bd664c9968e2fd361d67 --- /dev/null +++ b/packages/mobile-ui-vue/components/utils/src/array.ts @@ -0,0 +1,15 @@ +export const toMultidimensional = (arr: any[], num = 0) => { + const resArr: any[] = []; + arr.forEach((item, index) => { + const page = Math.floor(index / num); // 计算该元素为第几个素组内 + if (!resArr[page]) { // 判断是否存在 + resArr[page] = []; + } + resArr[page].push(item); + }); + return resArr; +}; + +export const notEmptyArray = (value: any) => { + return Array.isArray(value) && value.length > 0; +}; diff --git a/packages/mobile-ui-vue/components/utils/src/bem.ts b/packages/mobile-ui-vue/components/utils/src/bem.ts new file mode 100644 index 0000000000000000000000000000000000000000..3fff8b91ea25f9e7688de659722a39cd4e09d28f --- /dev/null +++ b/packages/mobile-ui-vue/components/utils/src/bem.ts @@ -0,0 +1,55 @@ +export type Mod = string | { [key: string]: any }; +export type Mods = Mod | Mod[]; + +function genBem(name: string, mods?: Mods): string { + if (!mods) { + return ''; + } + + if (typeof mods === 'string') { + return ` ${name}--${mods}`; + } + + if (Array.isArray(mods)) { + return (mods as Mod[]).reduce( + (ret, item) => ret + genBem(name, item), + '' + ); + } + + return Object.keys(mods).reduce( + (ret, key) => ret + (mods[key] ? genBem(name, key) : ''), + '' + ); +} + +/** + * bem helper + * b() // 'button' + * b('text') // 'button__text' + * b({ disabled }) // 'button button--disabled' + * b('text', { disabled }) // 'button__text button__text--disabled' + * b(['disabled', 'primary']) // 'button button--disabled button--primary' + */ +export function createBEM(name: string) { + return (el?: Mods, mods?: Mods): string => { + if (el && typeof el !== 'string') { + mods = el; + el = ''; + } + + el = el ? `${name}__${el}` : name; + + return `${el}${genBem(el, mods)}`; + }; +} + +export type BEM = ReturnType; + +export function createNamespace(name: string) { + const prefixedName = `fm-${name}`; + return [ + createBEM(prefixedName), + prefixedName, + ] as const; +} diff --git a/packages/mobile-ui-vue/components/utils/src/common.ts b/packages/mobile-ui-vue/components/utils/src/common.ts new file mode 100644 index 0000000000000000000000000000000000000000..53b850a6187ec7bd894b9c78ebba0f99c7c5c88d --- /dev/null +++ b/packages/mobile-ui-vue/components/utils/src/common.ts @@ -0,0 +1,115 @@ +/* eslint-disable no-useless-escape */ +/* eslint-disable @typescript-eslint/ban-types */ +/* eslint-disable no-return-assign */ +/* eslint-disable no-use-before-define */ +import { ComponentPublicInstance } from 'vue'; +import { isDef, isNumeric } from './type'; + +export function noop() { } + +export type ComponentInstance = ComponentPublicInstance<{}, any>; + +export type RawObject = { + [key: string]: T; +}; + +export function makeMap(str: string, expectsLowerCase = false) { + const map = Object.create(null); + const list = str.split(','); + for (let i = 0; i < list.length; i++) { + map[list[i]] = true; + } + return expectsLowerCase + ? (val: string) => !!map[val.toLowerCase()] + : (val: string) => !!map[val]; +} + +export function addUnit(value: any) { + if (!isDef(value)) { + return undefined; + } + value = String(value); + return isNumeric(value) ? `${value}px` : value; +} + +export const getValue = (field: string, data: any, safe = false) => { + if (!data) { + return ''; + } + let resultVal = ''; + if (field.indexOf('.') === -1) { + resultVal = data[field]; + } else { + resultVal = field.split('.').reduce((obj, key) => { + if (obj) { + return obj[key]; + } + return null; + + }, data); + } + + if (safe) { + return formatterValue(resultVal); + } + return resultVal; + +}; + +export const setValue = ( + obj: { [key: string]: any }, + field: string, + val: any, +) => { + if (field) { + if (field.indexOf('.') > -1) { + let lastObj: { [key: string]: any } | null = null; + const _fields = field.split('.'); + _fields.reduce((c, p) => { + lastObj = c; + return c && c[p] ? c[p] : (c[p] = {}); + }, obj); + + if (lastObj) { + const index = _fields.pop(); + if (index) { + ; (lastObj as any)[index] = val; + } + } + } else { + obj[field] = val; + } + } +}; + +export const escapeHtml = (str: string) => { + return str + .replace(/&/g, '&') + .replace(//g, '>') + .replace(/\"/g, '"') + .replace(/\'/g, ''') + .replace(/\//g, '/'); +}; + +export const unescapeHtml = (str: string) => { + return str + .replace(/&/g, '&') + .replace(/</g, '<') + .replace(/>/g, '>') + .replace(/"/g, '"') + .replace(/'/g, "'") + .replace(///g, '/'); +}; + +const formatterValue = (val: any) => { + if (val === null || val === undefined || val === '') { + return ''; + } + + if (typeof val === 'string') { + return escapeHtml(val); + } + + return val; +}; diff --git a/packages/mobile-ui-vue/components/utils/src/date.ts b/packages/mobile-ui-vue/components/utils/src/date.ts new file mode 100644 index 0000000000000000000000000000000000000000..505158ca131a4191bfa676ba74b6a4c1c7df1ada --- /dev/null +++ b/packages/mobile-ui-vue/components/utils/src/date.ts @@ -0,0 +1,44 @@ +/* eslint-disable no-use-before-define */ +import dayjs from 'dayjs'; +import { isDate } from './type'; + +export const format = (date: Date | string, format: string) => { + return dayjs(date).format(initFormatForDayjs(format)); +}; + +export const parse = (date: string | Date, format?: string) => { + return isDate(date) ? date : dayjs(date, format).toDate(); +}; + +export const initFormatForDayjs = (format: string) => { + if (!format) { + return 'YYYY-MM-DD'; + } + const formatArr = format.split(' '); + const dateFormat = formatArr[0] ? formatArr[0] : ''; + const timeFormat = formatArr[1] ? ' ' + formatArr[1] : ''; + return `${dateFormat.toUpperCase()}${timeFormat}`; +}; + +export function isEqualDate(prevDate: Date, nextDate: Date | undefined) { + nextDate = nextDate || new Date(); + return dayjs(prevDate).isSame(nextDate, 'date'); +} + +export function isSameDay(prevDate: Date, nextDate: Date) { + return dayjs(prevDate).isSame(nextDate, 'day'); +} + +export function isBefore(prevDate: Date, nextDate: Date, unit: dayjs.OpUnitType = 'milliseconds') { + nextDate = nextDate || new Date(); + return dayjs(prevDate).isBefore(nextDate, unit); +} + +export function isAfter(prevDate: Date, nextDate: Date, unit: dayjs.OpUnitType = 'milliseconds') { + nextDate = nextDate || new Date(); + return dayjs(prevDate).isAfter(nextDate, unit); +} + +export function isValidDate(date: Date) { + return date instanceof Date && !isNaN(date.getTime()); +} diff --git a/packages/mobile-ui-vue/components/utils/src/debounce.ts b/packages/mobile-ui-vue/components/utils/src/debounce.ts new file mode 100644 index 0000000000000000000000000000000000000000..cb5f4b1fd324f066a69e20994b5804f04a9cd661 --- /dev/null +++ b/packages/mobile-ui-vue/components/utils/src/debounce.ts @@ -0,0 +1,33 @@ +/* eslint-disable prefer-arrow-callback */ +/* eslint-disable @typescript-eslint/ban-types */ +export const debounce = (fn: Function, wait: number, immediate?: boolean) => { + let timeout: any; + + const debounced = (...args: any[]) => { + if (timeout) { + clearTimeout(timeout); + } + if (immediate) { + timeout = setTimeout(() => { + timeout = null; + fn(...args); + }, wait); + if (!timeout) { + fn(args); + } + } else { + // 设置定时器 + timeout = setTimeout(function () { + fn(...args); + }, wait); + } + }; + + // 新增 手动取消 + debounced.cancel = function () { + clearTimeout(timeout); + timeout = null; + }; + + return debounced; +}; diff --git a/packages/mobile-ui-vue/components/utils/src/deep-assign.ts b/packages/mobile-ui-vue/components/utils/src/deep-assign.ts new file mode 100644 index 0000000000000000000000000000000000000000..83441b8c65f3cf7a1ef0c6da19d4ed5568a669c6 --- /dev/null +++ b/packages/mobile-ui-vue/components/utils/src/deep-assign.ts @@ -0,0 +1,28 @@ +import { isDef, isObject } from "./type"; + +type ObjectIndex = Record; + +const { hasOwnProperty } = Object.prototype; + +function assignKey(to: ObjectIndex, from: ObjectIndex, key: string) { + const val = from[key]; + + if (!isDef(val)) { + return; + } + + if (!hasOwnProperty.call(to, key) || !isObject(val)) { + to[key] = val; + } else { + // eslint-disable-next-line no-use-before-define + to[key] = deepAssign(Object(to[key]), val); + } +} + +export function deepAssign(to: ObjectIndex, from: ObjectIndex): ObjectIndex { + Object.keys(from).forEach((key) => { + assignKey(to, from, key); + }); + + return to; +} diff --git a/packages/mobile-ui-vue/components/utils/src/dom/element.ts b/packages/mobile-ui-vue/components/utils/src/dom/element.ts new file mode 100644 index 0000000000000000000000000000000000000000..7e6f6be63a083b675cc67c8c61660bb438ec3f00 --- /dev/null +++ b/packages/mobile-ui-vue/components/utils/src/dom/element.ts @@ -0,0 +1,120 @@ +import { Ref, unref } from 'vue'; +import { makeMap } from '../common'; + +type Position = { + top?: number; + bottom?: number; + left?: number; + right?: number; + height?: number; + width?: number; +}; + +/** + * 获得相对位置 + */ +export const getPosition = ( + target: Ref | HTMLElement | undefined, + wrapper: HTMLElement = document.body, +) => { + const initPosition = { + top: 0, + left: 0, + bottom: 0, + right: 0, + height: 0, + width: 0, + }; + const _target = unref(target); + const _wrapper = unref(wrapper); + const _targetPosition = _target + ? _target.getBoundingClientRect() + : initPosition; + const _wrapperPosition = _wrapper + ? _wrapper.getBoundingClientRect() + : initPosition; + return { + top: _targetPosition.top - _wrapperPosition.top, + bottom: _wrapperPosition.bottom - _targetPosition.bottom, + left: _targetPosition.left - _wrapperPosition.left, + right: _wrapperPosition.right - _targetPosition.right, + height: _targetPosition.height, + width: _targetPosition.width, + }; +}; + +export const getDeviation = (root: Ref | HTMLElement, placement = 'bottomLeft') => { + let result: Position = {}; + const rootPosition = getPosition(root); + switch (placement) { + case 'left': + result = { + top: rootPosition.top, + right: rootPosition.right + rootPosition.width, + }; + break; + case 'right': + result = { + top: rootPosition.top, + left: rootPosition.left + rootPosition.width, + }; + break; + case 'top': + result = { + bottom: rootPosition.bottom + rootPosition.height, + left: rootPosition.left + rootPosition.width / 2, + }; + break; + case 'bottom': + result = { + top: rootPosition.top + rootPosition.height, + left: rootPosition.left + rootPosition.width / 2, + }; + break; + case 'topLeft': + result = { + bottom: rootPosition.bottom + rootPosition.height, + left: rootPosition.left, + }; + break; + case 'topRight': + result = { + bottom: rootPosition.bottom + rootPosition.height, + right: rootPosition.right, + }; + break; + case 'bottomLeft': + result = { + top: rootPosition.top + rootPosition.height, + left: rootPosition.left, + }; + break; + case 'bottomRight': + result = { + top: rootPosition.top + rootPosition.height, + right: rootPosition.right, + }; + break; + default: + result = rootPosition; + } + return result; +}; + +export const getRectByRef = (ref: Ref) => { + const target: Element | undefined = unref(ref); + return target?.getBoundingClientRect(); +}; + +const HTML_TAGS = + 'html,body,base,head,link,meta,style,title,address,article,aside,footer,' + + 'header,h1,h2,h3,h4,h5,h6,hgroup,nav,section,div,dd,dl,dt,figcaption,' + + 'figure,picture,hr,img,li,main,ol,p,pre,ul,a,b,abbr,bdi,bdo,br,cite,code,' + + 'data,dfn,em,i,kbd,mark,q,rp,rt,rtc,ruby,s,samp,small,span,strong,sub,sup,' + + 'time,u,var,wbr,area,audio,map,track,video,embed,object,param,source,' + + 'canvas,script,noscript,del,ins,caption,col,colgroup,table,thead,tbody,td,' + + 'th,tr,button,datalist,fieldset,form,input,label,legend,meter,optgroup,' + + 'option,output,progress,select,textarea,details,dialog,menu,' + + 'summary,template,blockquote,iframe,tfoot'; + +export const isHTMLTag = makeMap(HTML_TAGS); diff --git a/packages/mobile-ui-vue/components/utils/src/dom/event.ts b/packages/mobile-ui-vue/components/utils/src/dom/event.ts new file mode 100644 index 0000000000000000000000000000000000000000..371efca36039fe4131c73a834d49a3479f83cd08 --- /dev/null +++ b/packages/mobile-ui-vue/components/utils/src/dom/event.ts @@ -0,0 +1,37 @@ +export function stopPropagation(event: Event) { + event.stopPropagation(); +} + +export function preventDefault(event: Event, isStopPropagation?: boolean) { + /* istanbul ignore else */ + if (typeof event.cancelable !== 'boolean' || event.cancelable) { + event.preventDefault(); + } + + if (isStopPropagation) { + stopPropagation(event); + } +} + +export function trigger(target: Element, type: string) { + const inputEvent = document.createEvent('HTMLEvents'); + inputEvent.initEvent(type, true, true); + target.dispatchEvent(inputEvent); +} + +// ios event没有path属性 +export const initNodePath = (event: Event) => { + const path: any[] = []; + let currentElem: any = event.target; + while (currentElem) { + path.push(currentElem); + currentElem = currentElem.parentElement; + } + if (path.indexOf(window) === -1 && path.indexOf(document) === -1) { + path.push(document); + } + if (path.indexOf(window) === -1) { + path.push(window); + } + return path; +}; diff --git a/packages/mobile-ui-vue/components/utils/src/dom/scroller.ts b/packages/mobile-ui-vue/components/utils/src/dom/scroller.ts new file mode 100644 index 0000000000000000000000000000000000000000..ad4d8a437e3c2524951ef50157b9242094ca8318 --- /dev/null +++ b/packages/mobile-ui-vue/components/utils/src/dom/scroller.ts @@ -0,0 +1,30 @@ +const overflowScrollReg = /scroll|auto/i; + +export function getScroller(el: Element | undefined): Element | Window { + const root = window; + let node: any = el; + + while ( + node && + node.tagName !== 'HTML' && + node.nodeType === 1 && + node !== root + ) { + const { overflowY } = window.getComputedStyle(node); + + if (overflowScrollReg.test(overflowY)) { + if (node.tagName !== 'BODY') { + return node; + } + const { overflowY: htmlOverflowY } = window.getComputedStyle( + node.parentNode + ); + + if (overflowScrollReg.test(htmlOverflowY)) { + return node; + } + } + node = node.parentNode; + } + return root; +} diff --git a/packages/mobile-ui-vue/components/utils/src/dom/style.ts b/packages/mobile-ui-vue/components/utils/src/dom/style.ts new file mode 100644 index 0000000000000000000000000000000000000000..a5d8ac7c60b4d95ebbe93ee188bc0cbea57f1dd3 --- /dev/null +++ b/packages/mobile-ui-vue/components/utils/src/dom/style.ts @@ -0,0 +1,20 @@ +import { unref, Ref } from 'vue'; + +export function isHidden( + elementRef: HTMLElement | Ref +) { + const el = unref(elementRef); + if (!el) { + return false; + } + + const style = window.getComputedStyle(el); + const hidden = style.display === 'none'; + + // offsetParent returns null in the following situations: + // 1. The element or its parent element has the display property set to none. + // 2. The element has the position property set to fixed + const parentHidden = el.offsetParent === null && style.position !== 'fixed'; + + return hidden || parentHidden; +} diff --git a/packages/mobile-ui-vue/components/utils/src/hook.ts b/packages/mobile-ui-vue/components/utils/src/hook.ts new file mode 100644 index 0000000000000000000000000000000000000000..378e53fec0cc85771a7088d983ca865ef8906304 --- /dev/null +++ b/packages/mobile-ui-vue/components/utils/src/hook.ts @@ -0,0 +1,18 @@ +import { nextTick, onMounted, onActivated } from 'vue'; + +export function onMountedOrActivated(hook: () => any) { + let mounted: boolean; + + onMounted(() => { + hook(); + nextTick(() => { + mounted = true; + }); + }); + + onActivated(() => { + if (mounted) { + hook(); + } + }); +} diff --git a/packages/mobile-ui-vue/components/utils/src/interceptor.ts b/packages/mobile-ui-vue/components/utils/src/interceptor.ts new file mode 100644 index 0000000000000000000000000000000000000000..36b05f4fdf114b47ab5f485cfffaa5c2d6074284 --- /dev/null +++ b/packages/mobile-ui-vue/components/utils/src/interceptor.ts @@ -0,0 +1,36 @@ +import { noop } from "./common"; +import { isPromise } from "./type"; + +export type Interceptor = (...args: any[]) => Promise | boolean; + +export function callInterceptor(options: { + interceptor?: Interceptor; + args?: any[]; + done: () => void; + canceled?: () => void; +}) { + const { interceptor, args, done, canceled } = options; + + if (interceptor) { + // eslint-disable-next-line prefer-spread + const returnVal = interceptor.apply(null, args || []); + + if (isPromise(returnVal)) { + returnVal + .then((value) => { + if (value) { + done(); + } else if (canceled) { + canceled(); + } + }) + .catch(noop); + } else if (returnVal) { + done(); + } else if (canceled) { + canceled(); + } + } else { + done(); + } +} diff --git a/packages/mobile-ui-vue/components/utils/src/number.ts b/packages/mobile-ui-vue/components/utils/src/number.ts new file mode 100644 index 0000000000000000000000000000000000000000..42dc626ac0bf523e02b5c437ec286e1c37d6b638 --- /dev/null +++ b/packages/mobile-ui-vue/components/utils/src/number.ts @@ -0,0 +1,28 @@ +import { trimExtraChar } from './string'; +import { isDef } from './type'; + +export function formatToNumber(value: string, allowDot: boolean) { + value = isDef(value) ? value : ''; + let regExp = /[^-0-9]/g; + value = trimExtraChar(value, '-', /-/g); + if (allowDot) { + value = trimExtraChar(value, '.', /\./g); + regExp = /[^-0-9.]/g; + } else { + value = value.split('.')[0]; + } + // eslint-disable-next-line no-return-assign + return value = value.replace(regExp, ''); +} + +export function parseFloat(value: string | number, precision = 0) { + return Number.parseFloat(value ? String(value) : '0').toFixed(precision); +} + +export function range(num: number, min: number, max: number): number { + return Math.min(Math.max(num, min), max); +} + +export function random(min: number, max: number) { + return Math.round(Math.random() * (max - min) + min); +} diff --git a/packages/mobile-ui-vue/components/utils/src/string.ts b/packages/mobile-ui-vue/components/utils/src/string.ts new file mode 100644 index 0000000000000000000000000000000000000000..bdbe9ab3baad001d986e8e457f0cbf273cb66f4b --- /dev/null +++ b/packages/mobile-ui-vue/components/utils/src/string.ts @@ -0,0 +1,43 @@ +/* eslint-disable default-param-last */ +import { isString } from "./type"; + +export function trimExtraChar(value: string, char: string, regExp: RegExp) { + const index = value.indexOf(char); + + if (index === -1) { + return value; + } + + if (char === '-' && index !== 0) { + return value.slice(0, index); + } + + return value.slice(0, index + 1) + value.slice(index).replace(regExp, ''); +} + +const slice = (value: string, begin = 0, end?: number) => { + if (!value) { + return ''; + } + const innerValue = String(value); + end = end || innerValue.length; + return { + before: innerValue.slice(0, begin), + target: innerValue.slice(begin, end), + after: innerValue.slice(end, innerValue.length) + }; +}; + +export function toUpperCase(value: string, begin = 0, end?: number) { + const result = slice(value, begin, end); + return result ? result.before + result.target.toUpperCase() + result.after : result; +} + +export function toLowerCase(value: string, begin = 0, end?: number) { + const result = slice(value, begin, end); + return result ? result.before + result.target.toLowerCase() + result.after : result; +} + +export function toObject(value: string) { + return value ? isString(value) ? JSON.parse(value.replace(/'/g, '"')) : value : {}; +} diff --git a/packages/mobile-ui-vue/components/utils/src/throttle.ts b/packages/mobile-ui-vue/components/utils/src/throttle.ts new file mode 100644 index 0000000000000000000000000000000000000000..2e7627c7597f40f89ea6496386fc7136aa938a4f --- /dev/null +++ b/packages/mobile-ui-vue/components/utils/src/throttle.ts @@ -0,0 +1,44 @@ +/* eslint-disable @typescript-eslint/ban-types */ +/* eslint-disable semi */ +/* eslint-disable @typescript-eslint/semi */ +export const throttle = ( + fn: Function, + wait: number, + options: { leading?: boolean; trailing?: boolean } = {}, +) => { + let timeout: any = null + let previous = 0 + + const throttled = (...args: any[]) => { + const now = +new Date() + + if (!previous && options.leading === false) { + previous = now + } + + const remaining = wait - (now - previous) + + if (remaining <= 0 || remaining > wait) { + if (timeout) { + clearTimeout(timeout) + timeout = null + } + previous = now + fn(...args) + } else if (!timeout && options.trailing !== false) { + timeout = setTimeout(() => { + previous = options.leading === false ? 0 : +new Date() + timeout = null + fn(...args) + }, remaining) + } + } + + // 手动取消 + throttled.cancel = function () { + clearTimeout(timeout) + previous = 0 + timeout = null + } + return throttled +} diff --git a/packages/mobile-ui-vue/components/utils/src/type.ts b/packages/mobile-ui-vue/components/utils/src/type.ts new file mode 100644 index 0000000000000000000000000000000000000000..b8dfa82b0fade1e86e47aacae5614e3949dfce0f --- /dev/null +++ b/packages/mobile-ui-vue/components/utils/src/type.ts @@ -0,0 +1,88 @@ +/* eslint-disable @typescript-eslint/ban-types */ +export const inBrowser = typeof window !== 'undefined'; + +export const inIOS = () => /(iPhone|iPad|iPod|iOS)/i.test(navigator.userAgent); +export const inAndroid = () => /(Android|Adr)/i.test(navigator.userAgent); + +export function isDef(val: T): val is NonNullable { + return val !== undefined && val !== null; +} + +export function isNull(val: unknown): val is null { + return val === null; +} + +export function isUndefined(val: unknown): val is undefined { + return val === undefined; +} + +export function isString(val: unknown): val is string { + return typeof val === 'string'; +} + +export function isNumber(val: unknown): val is number { + return typeof val === 'number'; +} + +export function isBoolean(val: unknown): val is null { + return typeof val === 'boolean'; +} + +export const { isArray } = Array; + +export function isSymbol(val: unknown): val is symbol { + return typeof val === 'symbol'; +} + +export function isFunction(val: unknown): val is Function { + return typeof val === 'function'; +} + +export function isObject(val: unknown): val is Record { + return val !== null && typeof val === 'object'; +} + +export function isPromise(val: unknown): val is Promise { + return isObject(val) && isFunction(val.then) && isFunction(val.catch); +} + +export function isNumeric(val: string) { + return /^\d+(\.\d+)?$/.test(val); +} + +export function isDate(val: unknown): val is Date { + return typeof val === 'object' && val instanceof Date; +} + +export function getType(val: unknown) { + if (isString(val)) { + return 'string'; + } + if (isNumber(val)) { + return 'number'; + } + if (isDate(val)) { + return 'date'; + } + if (isNull(val)) { + return 'null'; + } + if (isUndefined(val)) { + return 'undefined'; + } + if (isArray(val)) { + return 'array'; + } + if (isSymbol(val)) { + return 'symbol'; + } + if (isFunction(val)) { + return 'function'; + } + if (isPromise(val)) { + return 'promise'; + } + if (isObject(val)) { + return 'object'; + } +} diff --git a/packages/mobile-ui-vue/components/utils/src/vue-compile/codegen.ts b/packages/mobile-ui-vue/components/utils/src/vue-compile/codegen.ts new file mode 100644 index 0000000000000000000000000000000000000000..00de91c22467b69feba46129b33c9c95741f0738 --- /dev/null +++ b/packages/mobile-ui-vue/components/utils/src/vue-compile/codegen.ts @@ -0,0 +1,553 @@ +/* eslint-disable no-lone-blocks */ +/* eslint-disable @typescript-eslint/indent */ +/* eslint-disable no-use-before-define */ +import { + helperNameMap, + assert, + isSimpleIdentifier, + TO_DISPLAY_STRING, + CREATE_COMMENT, + WITH_DIRECTIVES, + OPEN_BLOCK, + CREATE_BLOCK, + CREATE_VNODE, + WITH_CTX, + SET_BLOCK_TRACKING, + RESOLVE_COMPONENT, + RESOLVE_DIRECTIVE +} from '@vue/compiler-core'; +import { isString, isSymbol, isArray } from '../type'; + +export function VueCodeGenerate(ast: any) { + + const context = createCodegenContext(); + + const { push, indent, deindent, newline } = context; + + // enter render function + const functionName = `render`; + const args = ['_ctx', '_cache']; + + const signature = args.join(', '); + + genModulePreamble(ast, context); + + push(`return `); + push(`function ${functionName}(${signature}) {`); + indent(); + push(`const { props } = _ctx`); + newline(); + // generate asset resolution statements + if (ast.components.length) { + genAssets(ast.components, 'component', context); + if (ast.directives.length || ast.temps > 0) { + newline(); + } + } + if (ast.directives.length) { + console.log(ast); + genAssets(ast.directives, 'directive', context); + if (ast.temps > 0) { + newline(); + } + } + newline(); + + push(`return `); + + if (ast.codegenNode) { + genNode(ast.codegenNode, context); + } else { + push(`null`); + } + deindent(); + push(`}`); + + return { + ast, + code: context.code, + }; +} + +function createCodegenContext() { + const context = { + code: ``, + indentLevel: 0, + pure: false, + helper(key: string) { + return `_${helperNameMap[key as any]}`; + }, + push(code: string) { + context.code += code; + }, + indent() { + newline(++context.indentLevel); + }, + deindent(withoutNewLine = false) { + if (withoutNewLine) { + --context.indentLevel; + } else { + newline(--context.indentLevel); + } + }, + newline() { + newline(context.indentLevel); + }, + }; + + function newline(n: number) { + context.push('\n' + ` `.repeat(n)); + } + + return context; +} + +function genModulePreamble(ast: any, context: any) { + const { push, newline } = context; + // generate import statements for helpers + if (ast.helpers.length) { + push( + `const { ${ast.helpers + .map((s: any) => `${helperNameMap[s]}: _${helperNameMap[s]}`) + .join(', ')} } = Vue\n`, + ); + } + newline(); +} + +function genAssets(assets: any, type: any, { helper, push, newline }: any) { + const resolver = helper(type === 'component' ? RESOLVE_COMPONENT : RESOLVE_DIRECTIVE); + for (let i = 0; i < assets.length; i++) { + const id = assets[i]; + push(`const ${toValidAssetId(id, type)} = ${resolver}(${JSON.stringify(id)})`); + if (i < assets.length - 1) { + newline(); + } + } +} + +const PURE_ANNOTATION = `/*#__PURE__*/`; + +function genNode(node: any, context: any) { + if (isString(node)) { + context.push(node); + return; + } + if (isSymbol(node)) { + context.push(context.helper(node)); + return; + } + switch (node.type) { + case 1 /* ELEMENT */: + case 9 /* IF */: + case 11 /* FOR */: + assert( + node.codegenNode != null, + `Codegen node is missing for element/if/for node. ` + + `Apply appropriate transforms first.`, + ); + genNode(node.codegenNode, context); + break; + case 2 /* TEXT */: + genText(node, context); + break; + case 4 /* SIMPLE_EXPRESSION */: + genExpression(node, context); + break; + case 5 /* INTERPOLATION */: + genInterpolation(node, context); + break; + case 12 /* TEXT_CALL */: + genNode(node.codegenNode, context); + break; + case 8 /* COMPOUND_EXPRESSION */: + genCompoundExpression(node, context); + break; + case 3 /* COMMENT */: + genComment(node, context); + break; + case 13 /* VNODE_CALL */: + genVNodeCall(node, context); + break; + case 14 /* JS_CALL_EXPRESSION */: + genCallExpression(node, context); + break; + case 15 /* JS_OBJECT_EXPRESSION */: + genObjectExpression(node, context); + break; + case 17 /* JS_ARRAY_EXPRESSION */: + genArrayExpression(node, context); + break; + case 18 /* JS_FUNCTION_EXPRESSION */: + genFunctionExpression(node, context); + break; + case 19 /* JS_CONDITIONAL_EXPRESSION */: + genConditionalExpression(node, context); + break; + case 20 /* JS_CACHE_EXPRESSION */: + genCacheExpression(node, context); + break; + // SSR only types + case 21 /* JS_BLOCK_STATEMENT */: + genNodeList(node.body, context, true, false); + break; + case 22 /* JS_TEMPLATE_LITERAL */: + genTemplateLiteral(node, context); + break; + case 23 /* JS_IF_STATEMENT */: + genIfStatement(node, context); + break; + case 24 /* JS_ASSIGNMENT_EXPRESSION */: + genAssignmentExpression(node, context); + break; + case 25 /* JS_SEQUENCE_EXPRESSION */: + genSequenceExpression(node, context); + break; + case 26 /* JS_RETURN_STATEMENT */: + genReturnStatement(node, context); + break; + /* istanbul ignore next */ + case 10 /* IF_BRANCH */: + // noop + break; + default: { + assert(false, `unhandled codegen node type: ${node.type}`); + // make sure we exhaust all possible types + const exhaustiveCheck = node; + return exhaustiveCheck; + } + } +} + +function genText(node: any, context: any) { + context.push(JSON.stringify(node.content), node); +} + +function genExpression(node: any, context: any) { + const { content, isStatic } = node; + context.push(isStatic ? JSON.stringify(content) : content, node); +} + +function genInterpolation(node: any, context: any) { + const { push, helper, pure } = context; + if (pure) push(PURE_ANNOTATION); + push(`${helper(TO_DISPLAY_STRING)}(`); + genNode(node.content, context); + push(`)`); +} + +function genCompoundExpression(node: any, context: any) { + for (let i = 0; i < node.children.length; i++) { + const child = node.children[i]; + if (isString(child)) { + context.push(child); + } else { + genNode(child, context); + } + } +} + +function genExpressionAsPropertyKey(node: any, context: any) { + const { push } = context; + if (node.type === 8 /* COMPOUND_EXPRESSION */) { + push(`[`); + genCompoundExpression(node, context); + push(`]`); + } else if (node.isStatic) { + // only quote keys if necessary + const text = isSimpleIdentifier(node.content) + ? node.content + : JSON.stringify(node.content); + push(text, node); + } else { + push(`[${node.content}]`, node); + } +} + +function genComment(node: any, context: any) { + { + const { push, helper, pure } = context; + if (pure) { + push(PURE_ANNOTATION); + } + push(`${helper(CREATE_COMMENT)}(${JSON.stringify(node.content)})`, node); + } +} +function genNodeList(nodes: any, context: any, multilines = false, comma = true) { + const { push, newline } = context; + + for (let i = 0; i < nodes.length; i++) { + const node = nodes[i]; + if (isString(node)) { + push(node); + } else if (isArray(node)) { + genNodeListAsArray(node, context); + } else { + genNode(node, context); + } + if (i < nodes.length - 1) { + if (multilines) { + comma && push(','); + newline(); + } else { + comma && push(', '); + } + } + } +} +function genVNodeCall(node: any, context: any) { + const { push, helper, pure } = context; + const { + tag, + props, + children, + patchFlag, + dynamicProps, + directives, + isBlock, + disableTracking, + } = node; + if (directives) { + push(helper(WITH_DIRECTIVES) + `(`); + } + if (isBlock) { + push(`(${helper(OPEN_BLOCK)}(${disableTracking ? `true` : ``}), `); + } + if (pure) { + push(PURE_ANNOTATION); + } + push(helper(isBlock ? CREATE_BLOCK : CREATE_VNODE) + `(`, node); + genNodeList( + genNullableArgs([tag, props, children, patchFlag, dynamicProps]), + context, + ); + + push(`)`); + if (isBlock) { + push(`)`); + } + if (directives) { + console.log(directives); + push(`, `); + genNode(directives, context); + push(`)`); + } +} +function genNullableArgs(args: any) { + let i = args.length; + while (i--) { + if (args[i] != null) break; + } + return args.slice(0, i + 1).map((arg: any) => arg || `null`); +} +// JavaScript +function genCallExpression(node: any, context: any) { + const { push, helper, pure } = context; + const callee = isString(node.callee) ? node.callee : helper(node.callee); + if (pure) { + push(PURE_ANNOTATION); + } + push(callee + `(`, node); + genNodeList(node.arguments, context); + push(`)`); +} +function genObjectExpression(node: any, context: any) { + const { push, indent, deindent, newline } = context; + const { properties } = node; + if (!properties.length) { + push(`{}`, node); + return; + } + const multilines = + properties.length > 1 || + properties.some((p: any) => p.value.type !== 4 /* SIMPLE_EXPRESSION */); + push(multilines ? `{` : `{ `); + multilines && indent(); + for (let i = 0; i < properties.length; i++) { + const { key, value } = properties[i]; + // key + genExpressionAsPropertyKey(key, context); + push(`: `); + // value + genNode(value, context); + if (i < properties.length - 1) { + // will only reach this if it's multilines + push(`,`); + newline(); + } + } + multilines && deindent(); + push(multilines ? `}` : ` }`); +} +function isText$1(n: any) { + return ( + isString(n) || + n.type === 4 /* SIMPLE_EXPRESSION */ || + n.type === 2 /* TEXT */ || + n.type === 5 /* INTERPOLATION */ || + n.type === 8 /* COMPOUND_EXPRESSION */ + ); +} +function genNodeListAsArray(nodes: any, context: any) { + const multilines = + nodes.length > 3 || nodes.some((n: any) => isArray(n) || !isText$1(n)); + context.push(`[`); + multilines && context.indent(); + genNodeList(nodes, context, multilines); + multilines && context.deindent(); + context.push(`]`); +} +function genArrayExpression(node: any, context: any) { + genNodeListAsArray(node.elements, context); +} +function genFunctionExpression(node: any, context: any) { + const { push, indent, deindent } = context; + const { params, returns, body, newline, isSlot } = node; + // slot functions also need to push scopeId before rendering its content + + if (isSlot) { + push(`_${helperNameMap[WITH_CTX]}(`); + } + push(`(`, node); + if (isArray(params)) { + genNodeList(params, context); + } else if (params) { + genNode(params, context); + } + push(`) => `); + if (newline || body) { + push(`{`); + indent(); + } + if (returns) { + if (newline) { + push(`return `); + } + if (isArray(returns)) { + genNodeListAsArray(returns, context); + } else { + genNode(returns, context); + } + } else if (body) { + genNode(body, context); + } + if (newline || body) { + deindent(); + push(`}`); + } +} +function genConditionalExpression(node: any, context: any) { + const { test, consequent, alternate, newline: needNewline } = node; + const { push, indent, deindent, newline } = context; + if (test.type === 4 /* SIMPLE_EXPRESSION */) { + const needsParens = !isSimpleIdentifier(test.content); + needsParens && push(`(`); + genExpression(test, context); + needsParens && push(`)`); + } else { + push(`(`); + genNode(test, context); + push(`)`); + } + needNewline && indent(); + context.indentLevel++; + needNewline || push(` `); + push(`? `); + genNode(consequent, context); + context.indentLevel--; + needNewline && newline(); + needNewline || push(` `); + push(`: `); + const isNested = alternate.type === 19; /* JS_CONDITIONAL_EXPRESSION */ + if (!isNested) { + context.indentLevel++; + } + genNode(alternate, context); + if (!isNested) { + context.indentLevel--; + } + needNewline && deindent(true /* without newline */); +} +function genCacheExpression(node: any, context: any) { + const { push, helper, indent, deindent, newline } = context; + push(`_cache[${node.index}] || (`); + if (node.isVNode) { + indent(); + push(`${helper(SET_BLOCK_TRACKING)}(-1),`); + newline(); + } + push(`_cache[${node.index}] = `); + genNode(node.value, context); + if (node.isVNode) { + push(`,`); + newline(); + push(`${helper(SET_BLOCK_TRACKING)}(1),`); + newline(); + push(`_cache[${node.index}]`); + deindent(); + } + push(`)`); +} +function genTemplateLiteral(node: any, context: any) { + const { push, indent, deindent } = context; + push('`'); + const l = node.elements.length; + const multilines = l > 3; + for (let i = 0; i < l; i++) { + const e = node.elements[i]; + if (isString(e)) { + push(e.replace(/(`|\$|\\)/g, '\\$1')); + } else { + push('${'); + if (multilines) indent(); + genNode(e, context); + if (multilines) deindent(); + push('}'); + } + } + push('`'); +} +function genIfStatement(node: any, context: any) { + const { push, indent, deindent } = context; + const { test, consequent, alternate } = node; + push(`if (`); + genNode(test, context); + push(`) {`); + indent(); + genNode(consequent, context); + deindent(); + push(`}`); + if (alternate) { + push(` else `); + if (alternate.type === 23 /* JS_IF_STATEMENT */) { + genIfStatement(alternate, context); + } else { + push(`{`); + indent(); + genNode(alternate, context); + deindent(); + push(`}`); + } + } +} +function genAssignmentExpression(node: any, context: any) { + genNode(node.left, context); + context.push(` = `); + genNode(node.right, context); +} +function genSequenceExpression(node: any, context: any) { + context.push(`(`); + genNodeList(node.expressions, context); + context.push(`)`); +} +function genReturnStatement({ returns }: any, context: any) { + context.push(`return `); + if (isArray(returns)) { + genNodeListAsArray(returns, context); + } else { + genNode(returns, context); + } +} +function toValidAssetId(name: any, type: any) { + return `_${type}_${name.replace(/[^\w]/g, '_')}`; +} diff --git a/packages/mobile-ui-vue/demos/actionsheet/index.html b/packages/mobile-ui-vue/demos/actionsheet/index.html new file mode 100644 index 0000000000000000000000000000000000000000..888e963a478161cfeb76b7249b1901a82d0744f5 --- /dev/null +++ b/packages/mobile-ui-vue/demos/actionsheet/index.html @@ -0,0 +1,40 @@ +
+

基本使用

+
+ + + + +
+

选项状态

+
+ + +
+

自定义面板

+
+ + + + + + + + +
+
+ + 选项一 +
+
+ + 选项二 +
+
+ + 选项三 +
+
+
diff --git a/packages/mobile-ui-vue/demos/actionsheet/index.js b/packages/mobile-ui-vue/demos/actionsheet/index.js new file mode 100644 index 0000000000000000000000000000000000000000..ea0fd0c9550220ad270f253cf8fbd87157d9a4a0 --- /dev/null +++ b/packages/mobile-ui-vue/demos/actionsheet/index.js @@ -0,0 +1,54 @@ +import { + reactive, + toRefs +} from 'vue'; + +export default { + name: 'action-sheet-demo', + setup(_props) { + const state = reactive({ + show: { + basic: false, + cancel: false, + title: false, + status: false, + description: false, + }, + }); + const actions = [{ + name: '选项一' + }, + { + name: '选项二' + }, + { + name: '选项三', + subname: '描述信息' + }, + ]; + const actions2 = [{ + name: '着色选项', + color: '#ee0a24' + }, + { + name: '禁用选项', + disabled: true + } + ]; + const onSelect = (item) => { + state.show.basic = false; + console.log("--> [select]", item.name); + }; + const onCancel = () => { + console.log("--> [cancel]"); + }; + + return { + ...toRefs(state), + actions, + actions2, + onSelect, + onCancel + }; + } +}; diff --git a/packages/mobile-ui-vue/demos/actionsheet/index.scss b/packages/mobile-ui-vue/demos/actionsheet/index.scss new file mode 100644 index 0000000000000000000000000000000000000000..6fbd00a8b62afeb447caeddfbc12d0ea0abf958a --- /dev/null +++ b/packages/mobile-ui-vue/demos/actionsheet/index.scss @@ -0,0 +1,28 @@ +.demo-actionsheet-content { + .demo-actionsheet-item { + display: flex; + padding-left: 16px; + line-height: 22px; + align-items: center; + &-text { + flex: 1 1 0; + padding: 14px 16px 14px 0; + font-size: 16px; + color: #333; + border-bottom: 1px solid #ddd; + } + .fm-icon { + flex-shrink: 0; + margin-right: 10px; + font-size: 20px; + } + &:active { + background-color: #f2f3f5; + } + &:last-child { + .demo-actionsheet-item-text { + border-bottom: none; + } + } + } +} diff --git a/packages/mobile-ui-vue/demos/actionsheet/index.vue b/packages/mobile-ui-vue/demos/actionsheet/index.vue new file mode 100644 index 0000000000000000000000000000000000000000..44447ba31593d1e5bca406831d8c9a17c4b5c6c9 --- /dev/null +++ b/packages/mobile-ui-vue/demos/actionsheet/index.vue @@ -0,0 +1,5 @@ + + + + + diff --git a/packages/mobile-ui-vue/demos/adv-uploader/index.vue b/packages/mobile-ui-vue/demos/adv-uploader/index.vue new file mode 100644 index 0000000000000000000000000000000000000000..e01579ae928301c0396b136c76d7e0ae0b20db8d --- /dev/null +++ b/packages/mobile-ui-vue/demos/adv-uploader/index.vue @@ -0,0 +1,134 @@ + + + + + diff --git a/packages/mobile-ui-vue/demos/home/index.vue b/packages/mobile-ui-vue/demos/home/index.vue new file mode 100644 index 0000000000000000000000000000000000000000..48be715e216134d8630bc141bf9e9765c398a8bd --- /dev/null +++ b/packages/mobile-ui-vue/demos/home/index.vue @@ -0,0 +1,102 @@ + + + + + diff --git a/packages/mobile-ui-vue/demos/index.vue b/packages/mobile-ui-vue/demos/index.vue new file mode 100644 index 0000000000000000000000000000000000000000..f3fbb19f21cf478f0001ce1c6560013988ee3e27 --- /dev/null +++ b/packages/mobile-ui-vue/demos/index.vue @@ -0,0 +1,45 @@ + + + + diff --git a/packages/mobile-ui-vue/demos/listview/filter-bar-panel-enum.vue b/packages/mobile-ui-vue/demos/listview/filter-bar-panel-enum.vue new file mode 100644 index 0000000000000000000000000000000000000000..308bf06aeb736f6de0aad7e0aa148fd458cf9b97 --- /dev/null +++ b/packages/mobile-ui-vue/demos/listview/filter-bar-panel-enum.vue @@ -0,0 +1,149 @@ + + + + \ No newline at end of file diff --git a/packages/mobile-ui-vue/demos/listview/filter-bar-panel.vue b/packages/mobile-ui-vue/demos/listview/filter-bar-panel.vue new file mode 100644 index 0000000000000000000000000000000000000000..949cdb721323fab2de2ff13bbf29ebce48e409ef --- /dev/null +++ b/packages/mobile-ui-vue/demos/listview/filter-bar-panel.vue @@ -0,0 +1,42 @@ + + + diff --git a/packages/mobile-ui-vue/demos/listview/filter-bar.vue b/packages/mobile-ui-vue/demos/listview/filter-bar.vue new file mode 100644 index 0000000000000000000000000000000000000000..0b7a4d1420f769b5bde708a12c8f3c40f38648b0 --- /dev/null +++ b/packages/mobile-ui-vue/demos/listview/filter-bar.vue @@ -0,0 +1,107 @@ + + + + diff --git a/packages/mobile-ui-vue/demos/listview/index.html b/packages/mobile-ui-vue/demos/listview/index.html new file mode 100644 index 0000000000000000000000000000000000000000..b73ce60ad965d17c87405de143a154f5d2ae5018 --- /dev/null +++ b/packages/mobile-ui-vue/demos/listview/index.html @@ -0,0 +1,113 @@ +
+ +
+ +
+ +
+ + +
+
+ + + + + + + +
+
+
+ +
+
+ + + +
+
+
+ + +
+
+ +
+
+
+ +
+
+ 下拉刷新 + +
+
+
+
+
+
\ No newline at end of file diff --git a/packages/mobile-ui-vue/demos/listview/index.js b/packages/mobile-ui-vue/demos/listview/index.js new file mode 100644 index 0000000000000000000000000000000000000000..bb8320b1bd5d4990699b1068ed4839e4f8d1541b --- /dev/null +++ b/packages/mobile-ui-vue/demos/listview/index.js @@ -0,0 +1,360 @@ +import Vue from 'vue'; +// export interface item { +// "id": string, +// "title": string, +// "label":String, +// "checked":Boolean +// } +// import FilterBar from './filter-bar.vue'; +export default { + name: 'listview-demo', + components: { + // FilterBar + }, + data() { + return { + childValidatorResults: [{"id":"111","index":0},{"id":"222","index":1}], + list: [ + { + items: undefined, + refreshing: false, + loading: false, + error: false, + finished: false, + multiple: true, + checkSubmitBtn: { + text: '提交' + }, + checkCancelBtn: { + text: '撤销' + }, + btns: [ + { + text: '取消', + type: 'primary', + plain: true, + handler: this.cancelCheck + }, + { + text: '确认', + type: 'primary', + plain: false, + handler: this.getList + } + ], + // showSubmitBtn: false + }, + { + items: [], + refreshing: false, + loading: false, + error: false, + finished: false, + multiple: true + }, + { + items: [], + refreshing: false, + loading: false, + error: false, + finished: false, + multiple: true + }, + { + items: [], + refreshing: false, + loading: false, + error: false, + finished: false, + multiple: true + } + ], + listdata: [ + { + id: '1', + text: '行为管理', + menus: [ + { + id: '1-1', + icon: 'print', + text: '拜访路线', + color: '#40A9FF', + isLink: true + }, + { + id: '1-2', + icon: 'addpicture', + text: '拜访计划', + color: '#73D13D', + isLink: true + }, + { + id: '1-3', + icon: 'print', + text: '拜访', + color: '#13C2C2', + isLink: true + }, + { + id: '1-4', + icon: 'print', + text: '工作汇报', + color: '#FF7A45', + isLink: true + }, + { + id: '1-5', + icon: 'print', + text: '签到', + color: '#85A5FF', + isLink: true + }, + { + id: '1-6', + icon: 'print', + text: '经销商', + color: '#73D13D', + isLink: true + } + ] + }, + { + id: '2', + text: '拜访管理', + menus: [ + { + id: '2-1', + icon: 'print', + text: '拜访路线' + }, + { + id: '2-2', + icon: 'print', + text: '拜访计划', + checked: true + }, + { + id: '2-3', + icon: 'print', + text: '拜访' + }, + { + id: '2-4', + icon: 'print', + text: '工作汇报' + }, + { + id: '2-5', + icon: 'print', + text: '签到' + }, + { + id: '2-6', + icon: 'print', + text: '经销商', + checked: true + } + ] + }, + { + id: '3', + text: '工作管理', + menus: [ + { + id: '3-1', + icon: 'print', + text: '拜访路线' + }, + { + id: '3-2', + icon: 'print', + text: '拜访计划' + }, + { + id: '3-3', + icon: 'print', + text: '拜访' + }, + { + id: '3-4', + icon: 'print', + text: '工作汇报' + }, + { + id: '3-4', + icon: 'print', + text: '工作汇报' + } + ] + } + ], + listMultiple:false, + checkAll:false, + filterBarData: [{ + value: 'billType', + text: '单据类型', + type: 'enum', + enumData: [{ + text: '报销单', + value: 'expense', + children: [{ + text: '普通差旅报销单', + value: '111', + },{ + text: '交通费报销单', + value: '222', + },{ + text: '通讯费报销单', + value: '333', + },{ + text: '国外差旅报销', + value: '444', + },{ + text: '通用差旅报销', + value: '555', + }] + },{ + text: '行政审批', + value: 'approval', + children: [] + }] + },{ + value: 'submitDate', + text: '提交时间', + type: 'date' + }] + }; + }, + methods: { + onLoad(index) { + + const list = this.list[index]; + list.loading = true; + + setTimeout(() => { + if (list.refreshing) { + list.items = []; + list.refreshing = false; + } + + for (let i = 0; i < 5; i++) { + list.items = list?.items?.length ? list.items : [] + const text = list.items.length + 1; + if ((i + 1) % 5 === 0) { + list.items.push({ + id: 'listview' + text, + title: '标题' + text, + label: 'label' + text, + isLink: true, + checked: true + }); + } else { + list.items.push({ + id: 'listview' + text, + title: '标题' + text, + label: 'label' + text, + isLink: true + }); + } + } + + list.loading = false; + list.refreshing = false; + // console.log(index === 2 && list.items.length === 10 && !list.error) + if (index === 1 && list.items.length === 10 && !list.error) { + list.error = true; + } else { + list.error = false; + } + + if (list.items.length >= 40) { + list.finished = true; + } + console.log(list); + }, 1000); + }, + onLoadData(){ + const list = this.list[3]; + list.loading = true; + setTimeout(() => { + this.listdata.push({ + id: '4', + text: '新增管理', + menus: [ + { + id: '4-1', + icon: 'print', + text: '拜访路线' + } + ] + }) + list.finished = true; + list.loading = false; + list.refreshing = false; + }, 1000); + }, + onRefresh(index) { + this.list[index].finished = false; + this.list[index].refreshing = true; + this.onLoad(index); + }, + submit(data) { + console.log(data); + console.log(this.$refs.listView1); + console.log(this.$refs.listView1.getScrollerPosition()); + this.$refs.listView1.setScrollerPosition({scrollTop: 20}) + }, + multipleCancel(data) { + console.log(data); + }, + viewChecked() { + this.$refs.listview.checkSubmit(); + console.log('提交成功'); + }, + getList(btn, data) { + console.log(data); + console.log(btn); + this.$refs.listView1.checkSubmit() + }, + cancelCheck(btn) { + console.log(btn); + console.log(this.$refs.listView1); + this.$refs.listView1.listCheckCancel() + }, + listItemClick(event) { + console.log(event); + }, + selectItemChange(event) { + console.log(event); + }, + deleteItem(item) { + console.log(item); + }, + listMultipleStart(){ + this.listMultiple = true; + this.checkAll = false; + this.$refs.listview.listCheckStart(); + }, + listMultipleCancel(){ + this.listMultiple = false; + this.$refs.listview.listCheckCancel(); + }, + checkAllChange(checked){ + if(checked){ + this.$refs.listview.listCheckAll(); + } + else{ + this.$refs.listview.listCheckAllCancel(); + } + }, + checkSubmit(){ + console.log(this.$refs.listview.getSelectDataList()); + }, + listclick(e,disabled){ + if(!disabled){ + e.stopPropagation(); + } + console.log('列表点击'); + } + } +}; \ No newline at end of file diff --git a/packages/mobile-ui-vue/demos/listview/index.scss b/packages/mobile-ui-vue/demos/listview/index.scss new file mode 100644 index 0000000000000000000000000000000000000000..d57d491f7c1378c18f876e0590080d1fa1cbd728 --- /dev/null +++ b/packages/mobile-ui-vue/demos/listview/index.scss @@ -0,0 +1,85 @@ +.container { + box-sizing: border-box; + height: calc(100% - 26px); + padding-bottom: 20px; +} +.fm-swipecell-demo-right { + display: flex; +} +.fm-tmpl-list { + height: 40px; + line-height: 40px; + border-bottom: 1px solid #ddd; + text-align: center; + color: #666; +} +.demo-listview-menu{ + .fm-listview-item-content{ + display: flex; + align-items: center; + flex-wrap: wrap; + .fm-listview-sub-item{ + flex: 0 0 25%; + display: flex; + flex-direction: column; + align-items: center; + margin-bottom: 10px; + .fm-listview-subitem-content{ + display: flex; + flex-direction: column; + align-items: center; + } + .menu-list-item-icon{ + width: 46px; + height: 46px; + margin-bottom: 6px; + line-height: 46px; + text-align: center; + color: #fff; + border-radius: 16px; + background-color: #40A9FF; + .fm-icon{ + font-size: 26px; + } + } + .menu-list-item-text{ + text-align: center; + line-height: 20px; + font-size: 14px; + color: #666; + } + } + } +} +.fm-tmpl-list-footer{ + display: flex; + flex-direction: row; + align-items: center; + height: 54px; + padding: 0 16px; + background: #fff; + box-shadow: 0 -2px 8px 0 rgba(81,120,159,0.12); + .fm-tmpl-list-footer-btn{ + flex: 1; + text-align: center; + } +} +.fm-demo-listview-tabs{ + display: flex; + flex-direction: column; + height: 100%; + .fm-tab-bar{ + flex-shrink: 0; + } + .fm-tabs-content,.fm-tab-pane,.fm-listview-wrapper{ + display: flex; + flex-direction: column; + flex: 1 1 0; + overflow: hidden; + } + .fm-listview-wrapper .van-pull-refresh__track{ + display: flex; + flex-direction: column; + flex: 1 1 0; + } +} diff --git a/packages/mobile-ui-vue/demos/listview/index.vue b/packages/mobile-ui-vue/demos/listview/index.vue new file mode 100644 index 0000000000000000000000000000000000000000..3039e4edf3d35fb14d01d3cb51200779fcc16e8a --- /dev/null +++ b/packages/mobile-ui-vue/demos/listview/index.vue @@ -0,0 +1,75 @@ + + + diff --git a/packages/mobile-ui-vue/demos/navbar/index.html b/packages/mobile-ui-vue/demos/navbar/index.html new file mode 100644 index 0000000000000000000000000000000000000000..98b30ddfd530bf1a981d31f01b51e88aca2b9195 --- /dev/null +++ b/packages/mobile-ui-vue/demos/navbar/index.html @@ -0,0 +1,30 @@ +
+

基础用法

+
+ + + + +
+

多个按钮

+
+ + + + diff --git a/packages/mobile-ui-vue/demos/navbar/index.js b/packages/mobile-ui-vue/demos/navbar/index.js new file mode 100644 index 0000000000000000000000000000000000000000..c60b33312df276620175c0e5061a5a14538e3845 --- /dev/null +++ b/packages/mobile-ui-vue/demos/navbar/index.js @@ -0,0 +1,11 @@ +export default { + name: 'navbar-demo', + methods: { + leftClick(e) { + console.log(e); + }, + rightClick(e) { + console.log(e); + } + } +}; diff --git a/packages/mobile-ui-vue/demos/navbar/index.scss b/packages/mobile-ui-vue/demos/navbar/index.scss new file mode 100644 index 0000000000000000000000000000000000000000..959491b332bc50c2fa26b045b2fa8b9e2b227af2 --- /dev/null +++ b/packages/mobile-ui-vue/demos/navbar/index.scss @@ -0,0 +1,8 @@ +.fm-navbar-tmpl-text { + padding-left: 10px; + margin-left: 6px; + &:first-child { + padding-left: 0; + margin-left: 0; + } +} diff --git a/packages/mobile-ui-vue/demos/navbar/index.vue b/packages/mobile-ui-vue/demos/navbar/index.vue new file mode 100644 index 0000000000000000000000000000000000000000..406c2ce9e4b76d51577b628ae9148b2699355331 --- /dev/null +++ b/packages/mobile-ui-vue/demos/navbar/index.vue @@ -0,0 +1,5 @@ + + + + + diff --git a/packages/mobile-ui-vue/demos/popup/index.vue b/packages/mobile-ui-vue/demos/popup/index.vue new file mode 100644 index 0000000000000000000000000000000000000000..40f44f4c9e5b4637150f2e903d96d9e2e79c0755 --- /dev/null +++ b/packages/mobile-ui-vue/demos/popup/index.vue @@ -0,0 +1,73 @@ + + + + diff --git a/packages/mobile-ui-vue/docs/.vitepress/config.ts b/packages/mobile-ui-vue/docs/.vitepress/config.ts new file mode 100644 index 0000000000000000000000000000000000000000..6c1cca6b3e2e44adbf24f0b06224e2c9430dc4c3 --- /dev/null +++ b/packages/mobile-ui-vue/docs/.vitepress/config.ts @@ -0,0 +1,33 @@ +import { defineConfig, HeadConfig } from 'vitepress'; + +const head: HeadConfig[] = [ + ['link', { rel: 'icon', type: 'image/svg+xml', href: '/assets/logo.svg' }], +]; + +// https://vitepress.dev/reference/site-config +export default defineConfig({ + title: "Farris Design Mobile", + description: "Farris Design Mobile By Vue3", + head, + themeConfig: { + // https://vitepress.dev/reference/default-theme-config + nav: [ + { text: '设计原则', link: '/' }, + { text: '组件', link: '/markdown-examples' } + ], + + sidebar: [ + { + text: 'Examples', + items: [ + { text: 'Markdown Examples', link: '/markdown-examples' }, + { text: 'Runtime API Examples', link: '/api-examples' } + ] + } + ], + + socialLinks: [ + { icon: 'github', link: 'https://github.com/vuejs/vitepress' } + ] + } +}) diff --git a/packages/mobile-ui-vue/docs/.vitepress/theme/index.ts b/packages/mobile-ui-vue/docs/.vitepress/theme/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..907eafdd9b4de9fddeb93b5939502b1893a07204 --- /dev/null +++ b/packages/mobile-ui-vue/docs/.vitepress/theme/index.ts @@ -0,0 +1,9 @@ +import FarrisMobile from '../../../components'; +import DefaultTheme from 'vitepress/theme'; + +export default { + ...DefaultTheme, + enhanceApp({ app }) { + app.use(FarrisMobile); + } +}; diff --git a/packages/mobile-ui-vue/docs/api-examples.md b/packages/mobile-ui-vue/docs/api-examples.md new file mode 100644 index 0000000000000000000000000000000000000000..6bd8bb5c170045bc49274714f72541d6346dab7a --- /dev/null +++ b/packages/mobile-ui-vue/docs/api-examples.md @@ -0,0 +1,49 @@ +--- +outline: deep +--- + +# Runtime API Examples + +This page demonstrates usage of some of the runtime APIs provided by VitePress. + +The main `useData()` API can be used to access site, theme, and page data for the current page. It works in both `.md` and `.vue` files: + +```md + + +## Results + +### Theme Data +
{{ theme }}
+ +### Page Data +
{{ page }}
+ +### Page Frontmatter +
{{ frontmatter }}
+``` + + + +## Results + +### Theme Data +
{{ theme }}
+ +### Page Data +
{{ page }}
+ +### Page Frontmatter +
{{ frontmatter }}
+ +## More + +Check out the documentation for the [full list of runtime APIs](https://vitepress.dev/reference/runtime-api#usedata). diff --git a/packages/mobile-ui-vue/docs/assets/farris_design_dark.png b/packages/mobile-ui-vue/docs/assets/farris_design_dark.png new file mode 100644 index 0000000000000000000000000000000000000000..cba7c29f887f770cd577967304b719edd743d488 Binary files /dev/null and b/packages/mobile-ui-vue/docs/assets/farris_design_dark.png differ diff --git a/packages/mobile-ui-vue/docs/assets/farris_design_light.png b/packages/mobile-ui-vue/docs/assets/farris_design_light.png new file mode 100644 index 0000000000000000000000000000000000000000..bdce3482e283bec8e6f0a8ed55c4890ae70d2bbb Binary files /dev/null and b/packages/mobile-ui-vue/docs/assets/farris_design_light.png differ diff --git a/packages/mobile-ui-vue/docs/index.md b/packages/mobile-ui-vue/docs/index.md new file mode 100644 index 0000000000000000000000000000000000000000..200f31d93eb8546ec08bb468c3d80a98b5047289 --- /dev/null +++ b/packages/mobile-ui-vue/docs/index.md @@ -0,0 +1,25 @@ +--- +# https://vitepress.dev/reference/default-theme-home-page +layout: home + +hero: + name: "Farris Design Mobile" + text: "By Vue3" + tagline: Farris移动端组件库 + actions: + - theme: brand + text: 快速开始 + link: /markdown-examples + - theme: alt + text: 文档 + link: /api-examples + +features: + - title: Feature A + details: Lorem ipsum dolor sit amet, consectetur adipiscing elit + - title: Feature B + details: Lorem ipsum dolor sit amet, consectetur adipiscing elit + - title: Feature C + details: Lorem ipsum dolor sit amet, consectetur adipiscing elit +--- + diff --git a/packages/mobile-ui-vue/docs/markdown-examples.md b/packages/mobile-ui-vue/docs/markdown-examples.md new file mode 100644 index 0000000000000000000000000000000000000000..f9258a5503610e768817fe650aa5eab3ddacd514 --- /dev/null +++ b/packages/mobile-ui-vue/docs/markdown-examples.md @@ -0,0 +1,85 @@ +# Markdown Extension Examples + +This page demonstrates some of the built-in markdown extensions provided by VitePress. + +## Syntax Highlighting + +VitePress provides Syntax Highlighting powered by [Shiki](https://github.com/shikijs/shiki), with additional features like line-highlighting: + +**Input** + +````md +```js{4} +export default { + data () { + return { + msg: 'Highlighted!' + } + } +} +``` +```` + +**Output** + +```js{4} +export default { + data () { + return { + msg: 'Highlighted!' + } + } +} +``` + +## Custom Containers + +**Input** + +```md +::: info +This is an info box. +::: + +::: tip +This is a tip. +::: + +::: warning +This is a warning. +::: + +::: danger +This is a dangerous warning. +::: + +::: details +This is a details block. +::: +``` + +**Output** + +::: info +This is an info box. +::: + +::: tip +This is a tip. +::: + +::: warning +This is a warning. +::: + +::: danger +This is a dangerous warning. +::: + +::: details +This is a details block. +::: + +## More + +Check out the documentation for the [full list of markdown extensions](https://vitepress.dev/guide/markdown). diff --git a/packages/mobile-ui-vue/docs/vite.config.ts b/packages/mobile-ui-vue/docs/vite.config.ts new file mode 100644 index 0000000000000000000000000000000000000000..a8065bb836df03f8e08e7769973d6941f58e972c --- /dev/null +++ b/packages/mobile-ui-vue/docs/vite.config.ts @@ -0,0 +1,12 @@ +import { defineConfig } from 'vite'; +import vueJsx from '@vitejs/plugin-vue-jsx'; +import svgLoader from 'vite-svg-loader'; + +export default defineConfig({ + plugins: [vueJsx({}), svgLoader()], + server: { + fs: { + strict: false + } + } +}); diff --git a/packages/mobile-ui-vue/index.html b/packages/mobile-ui-vue/index.html new file mode 100644 index 0000000000000000000000000000000000000000..f5a88564284140f6a0e2d1d37d7450600afd6c3e --- /dev/null +++ b/packages/mobile-ui-vue/index.html @@ -0,0 +1,24 @@ + + + + + + + + + Farris Mobile + + + +
+ + + + + diff --git a/packages/mobile-ui-vue/package.json b/packages/mobile-ui-vue/package.json new file mode 100644 index 0000000000000000000000000000000000000000..aaa577caa56b0f6b4ecbc84207ef9feda0fef05a --- /dev/null +++ b/packages/mobile-ui-vue/package.json @@ -0,0 +1,63 @@ +{ + "name": "@farris/mobile-ui-vue", + "private": true, + "version": "0.0.0", + "scripts": { + "dev": "vite", + "build": "vue-tsc && vite build", + "preview": "vite preview", + "docs:dev": "vitepress dev docs", + "docs:build": "vitepress build docs", + "docs:preview": "vitepress preview docs" + }, + "dependencies": { + "lodash": "^4.17.21", + "lodash-es": "^4.17.20", + "vite-plugin-dts": "^2.1.0", + "vue": "^3.2.37", + "dayjs": "~1.11.10" + }, + "devDependencies": { + "@babel/parser": "^7.19.0", + "@babel/preset-env": "^7.19.0", + "@babel/preset-typescript": "^7.18.0", + "@babel/traverse": "^7.19.0", + "@commitlint/cli": "^17.1.0", + "@commitlint/config-conventional": "^17.1.0", + "@testing-library/vue": "^7.0.0", + "@types/chalk": "^2.2.0", + "@types/commander": "^2.12.2", + "@types/jest": "^26.0.24", + "@types/lodash.debounce": "^4.0.7", + "@types/ora": "^3.2.0", + "@typescript-eslint/eslint-plugin": "^5.37.0", + "@typescript-eslint/parser": "^5.37.0", + "@vitejs/plugin-vue": "^4.2.3", + "@vitejs/plugin-vue-jsx": "^3.0.1", + "@vue/babel-plugin-jsx": "^1.1.1", + "@vue/compiler-sfc": "^3.2.0", + "@vue/test-utils": "^2.0.0", + "@vuedx/typecheck": "^0.7.5", + "@vuedx/typescript-plugin-vue": "^0.7.5", + "babel-jest": "^29.0.3", + "chalk": "^5.0.0", + "commander": "^9.4.0", + "conventional-changelog-cli": "^2.2.2", + "happy-dom": "^8.9.0", + "inquirer": "^9.1.1", + "jest": "^29.0.0", + "ora": "^6.1.2", + "patch-vue-directive-ssr": "^0.0.1", + "sass": "^1.32.2", + "shelljs": "^0.8.4", + "typescript": "^4.6.4", + "vite": "^4.4.1", + "vite-plugin-md": "^0.20.0", + "vite-svg-loader": "^4.0.0", + "vitepress": "1.0.0-alpha.10", + "vitepress-theme-demoblock": "1.4.2", + "vitest": "^0.29.2", + "vue-router": "^4.3.0", + "vue-tsc": "^1.2.0" + } +} diff --git a/packages/mobile-ui-vue/public/assets/demo/images/city.jpg b/packages/mobile-ui-vue/public/assets/demo/images/city.jpg new file mode 100644 index 0000000000000000000000000000000000000000..6492a83d5633b6205518b7ac6e58eb27b33096ee Binary files /dev/null and b/packages/mobile-ui-vue/public/assets/demo/images/city.jpg differ diff --git a/packages/mobile-ui-vue/public/assets/demo/images/ice.jpg b/packages/mobile-ui-vue/public/assets/demo/images/ice.jpg new file mode 100644 index 0000000000000000000000000000000000000000..bcea2da900aa25757c19405b7e586dae20b2f33a Binary files /dev/null and b/packages/mobile-ui-vue/public/assets/demo/images/ice.jpg differ diff --git a/packages/mobile-ui-vue/public/assets/demo/images/leaf.jpg b/packages/mobile-ui-vue/public/assets/demo/images/leaf.jpg new file mode 100644 index 0000000000000000000000000000000000000000..fc29595bfd3b90d4f89db8dcbde45531cf1663dc Binary files /dev/null and b/packages/mobile-ui-vue/public/assets/demo/images/leaf.jpg differ diff --git a/packages/mobile-ui-vue/public/assets/demo/images/sand.jpg b/packages/mobile-ui-vue/public/assets/demo/images/sand.jpg new file mode 100644 index 0000000000000000000000000000000000000000..f7738e95de45de8bce0b3dff7096be4d2be09854 Binary files /dev/null and b/packages/mobile-ui-vue/public/assets/demo/images/sand.jpg differ diff --git a/packages/mobile-ui-vue/public/assets/demo/images/tree.jpg b/packages/mobile-ui-vue/public/assets/demo/images/tree.jpg new file mode 100644 index 0000000000000000000000000000000000000000..aafd37d754b5c99a09966a04db867a87a3684941 Binary files /dev/null and b/packages/mobile-ui-vue/public/assets/demo/images/tree.jpg differ diff --git a/packages/mobile-ui-vue/public/assets/farris-mobile-page.css b/packages/mobile-ui-vue/public/assets/farris-mobile-page.css new file mode 100644 index 0000000000000000000000000000000000000000..b8115616c75b2c939bf24aa295fa6abfcd61d308 --- /dev/null +++ b/packages/mobile-ui-vue/public/assets/farris-mobile-page.css @@ -0,0 +1 @@ +@charset "UTF-8";a,abbr,acronym,address,applet,article,aside,audio,b,big,blockquote,body,canvas,caption,center,cite,code,dd,del,details,dfn,div,dl,dt,em,embed,fieldset,figcaption,figure,footer,form,h1,h2,h3,h4,h5,h6,header,hgroup,html,i,iframe,img,ins,kbd,label,legend,li,mark,menu,nav,object,ol,output,p,pre,q,ruby,s,samp,section,small,span,strike,strong,sub,summary,sup,table,tbody,td,tfoot,th,thead,time,tr,tt,u,ul,var,video{margin:0;padding:0}html{line-height:1;-webkit-tap-highlight-color:transparent}ol,ul{list-style:none}table{border-collapse:collapse;border-spacing:0}caption,td,th{font-weight:400;vertical-align:middle}blockquote,q{quotes:none}blockquote::after,blockquote::before,q::after,q::before{content:'';content:none}a img{border:none}article,aside,details,figcaption,figure,footer,header,hgroup,menu,nav,section,summary{display:block}*,::after,::before{box-sizing:border-box}body{min-height:100vh;color:#333;background-color:#fff}@supports ((height:constant(safe-area-inset-top)) or (height:env(safe-area-inset-top))) and (-webkit-overflow-scrolling:touch){body{padding-top:env(safe-area-inset-top);padding-bottom:env(safe-area-inset-bottom)}}a{text-decoration:none;background:0 0}button,input[type=number],input[type=text],input[type=password],input[type=email],input[type=search],select,textarea{margin:0;font-family:inherit;-webkit-appearance:none}.fm-text-light{color:#888}.fm-text-lighter{color:#777}.fm-text-lightest{color:#666}.fm-text-emph{color:#333}.fm-text-primary{color:#3A90FF}.fm-utils-clearfix::after{content:'';clear:both;overflow:hidden}.fm-page{position:absolute;top:0;left:0;bottom:0;right:0;display:flex;flex-direction:column;background:#f9fafb;overflow:hidden}.fm-page-header{flex-shrink:0}.fm-page-main{flex-basis:0;flex-shrink:1;flex-grow:1;padding-bottom:12px;overflow:auto;display:flex;flex-direction:column}.fm-page-navbar{flex-shrink:0}.fm-page-footer{background-color:#fff}.fm-page-footer-btns{display:flex;flex-direction:row;align-items:center;height:100%}.fm-page-footer-btns-item{flex:1;display:flex;flex-direction:column;text-align:center;justify-content:center}.fm-page-footer-btns-item-icon{margin-bottom:4px;font-size:18px}.fm-page-footer-btns-item-text{font-size:12px;color:#999}.fm-page-footer-btns-item:hover .fm-page-footer-btns-item-icon{font-size:22px;color:#3a90ff}.fm-page-footer-btns-item:hover .fm-page-footer-btns-item-text{color:#3a90ff}.fm-form-control,.fm-textarea{width:100%;font-size:14px;color:#333}.fm-form-control{display:block;min-width:0;height:22px;margin:0;padding:0 4px;line-height:inherit;text-align:left;background-color:transparent;border:1px solid #ddd;border-radius:3px;resize:none}.fm-form-control:focus{border-color:#3499f6}.fm-textarea{border-radius:4px;padding:6px 16px;border:1px solid #ddd;outline:0;line-height:24px;display:inline-flex;vertical-align:middle}.fm-textarea:focus{border-color:#3499f6}.align-baseline{vertical-align:baseline!important}.align-top{vertical-align:top!important}.align-middle{vertical-align:middle!important}.align-bottom{vertical-align:bottom!important}.align-text-bottom{vertical-align:text-bottom!important}.align-text-top{vertical-align:text-top!important}.bg-info{background-color:#4D9AFF!important}.bg-submit{background-color:#5AC1C3!important}.bg-success{background-color:#5CC171!important}.bg-warning{background-color:#FF9800!important}.bg-danger{background-color:#F24645!important}.bg-white{background-color:#fff!important}.bg-transparent{background-color:transparent!important}.border{border:1px solid #DDD;border-radius:0}@media (-webkit-min-device-pixel-ratio:2),(min-resolution:2dppx){html:not([data-scale]) .border{position:relative;border:none}html:not([data-scale]) .border::before{content:'';position:absolute;left:0;top:0;width:200%;height:200%;border:1px solid #DDD;border-radius:0;transform-origin:0 0;transform:scale(.5);box-sizing:border-box;pointer-events:none}}.border-top{border-top:1px solid #DDD;position:relative}@media (-webkit-min-device-pixel-ratio:2),(min-resolution:2dppx){html:not([data-scale]) .border-top{border-top:none}html:not([data-scale]) .border-top::before{content:'';position:absolute;background-color:#DDD;display:block;z-index:1;top:0;right:auto;bottom:auto;left:0;width:100%;height:1PX;transform-origin:50% 50%;transform:scaleY(.5)}}.border-right{border-right:1px solid #DDD;position:relative}@media (-webkit-min-device-pixel-ratio:2),(min-resolution:2dppx){html:not([data-scale]) .border-right{border-right:none}html:not([data-scale]) .border-right::after{content:'';position:absolute;display:block;z-index:1;top:0;right:0;bottom:auto;left:auto;width:1PX;height:100%;background:#DDD;transform-origin:100% 50%;transform:scaleX(.5)}}.border-bottom{border-bottom:1px solid #DDD;position:relative}@media (-webkit-min-device-pixel-ratio:2),(min-resolution:2dppx){html:not([data-scale]) .border-bottom{border-bottom:none}html:not([data-scale]) .border-bottom::after{content:'';position:absolute;background-color:#DDD;display:block;z-index:1;top:auto;right:auto;bottom:0;left:0;width:100%;height:1PX;transform-origin:50% 100%;transform:scaleY(.5)}}.border-left{border-left:1px solid #DDD;position:relative}@media (-webkit-min-device-pixel-ratio:2),(min-resolution:2dppx){html:not([data-scale]) .border-left{border-left:none}html:not([data-scale]) .border-left::before{content:'';position:absolute;background-color:#DDD;display:block;z-index:1;top:0;right:auto;bottom:auto;left:0;width:1PX;height:100%;transform-origin:100% 50%;transform:scaleX(.5)}}.border-0::before,.border-bottom-0::after,.border-left-0::before,.border-right-0::after,.border-top-0::before{display:none!important}.border-0{border:0}.border-top-0{border-top:0}.border-right-0{border-right:0}.border-bottom-0{border-bottom:0}.border-left-0{border-left:0}.clearfix::after{display:block;clear:both;content:""}.display-none{display:none!important}.display-inline{display:inline!important}.display-inline-block{display:inline-block!important}.display-block{display:block!important}.display-table{display:table!important}.display-table-row{display:table-row!important}.display-table-cell{display:table-cell!important}.display-flex,.fm-utils-flex-column{display:flex!important}.display-inline-flex{display:inline-flex!important}.flex-direction-row{flex-direction:row!important}.flex-direction-column{flex-direction:column!important}.flex-direction-row-reverse{flex-direction:row-reverse!important}.flex-direction-column-reverse{flex-direction:column-reverse!important}.flex-row,.fm-utils-flex-row{flex-direction:row!important}.float-left{float:left!important}.float-right{float:right!important}.float-none{float:none!important}.position-static{position:static!important}.position-relative{position:relative!important}.position-absolute{position:absolute!important}.position-fixed{position:fixed!important}.position-sticky{position:-webkit-sticky!important;position:sticky!important}.fixed-bottom,.fixed-top{position:fixed;z-index:1030;right:0;left:0}.fixed-top{top:0}.fixed-bottom{bottom:0}.shadow-none{box-shadow:none!important}.w-25{width:25%!important}.w-50{width:50%!important}.w-75{width:75%!important}.w-100{width:100%!important}.w-auto{width:auto!important}.h-25{height:25%!important}.h-50{height:50%!important}.h-75{height:75%!important}.h-100{height:100%!important}.h-auto{height:auto!important}.mw-100{max-width:100%!important}.mh-100{max-height:100%!important}.m-0{margin:0!important}.mt-0,.my-0{margin-top:0!important}.mr-0,.mx-0{margin-right:0!important}.mb-0,.my-0{margin-bottom:0!important}.ml-0,.mx-0{margin-left:0!important}.p-0{padding:0!important}.pt-0,.py-0{padding-top:0!important}.pr-0,.px-0{padding-right:0!important}.pb-0,.py-0{padding-bottom:0!important}.pl-0,.px-0{padding-left:0!important}.m-base{margin:4px!important}.mt-base,.my-base{margin-top:4px!important}.mr-base,.mx-base{margin-right:4px!important}.mb-base,.my-base{margin-bottom:4px!important}.ml-base,.mx-base{margin-left:4px!important}.p-base{padding:4px!important}.pt-base,.py-base{padding-top:4px!important}.pr-base,.px-base{padding-right:4px!important}.pb-base,.py-base{padding-bottom:4px!important}.pl-base,.px-base{padding-left:4px!important}.m-xs{margin:8px!important}.mt-xs,.my-xs{margin-top:8px!important}.mr-xs,.mx-xs{margin-right:8px!important}.mb-xs,.my-xs{margin-bottom:8px!important}.ml-xs,.mx-xs{margin-left:8px!important}.p-xs{padding:8px!important}.pt-xs,.py-xs{padding-top:8px!important}.pr-xs,.px-xs{padding-right:8px!important}.pb-xs,.py-xs{padding-bottom:8px!important}.pl-xs,.px-xs{padding-left:8px!important}.m-sm{margin:12px!important}.mt-sm,.my-sm{margin-top:12px!important}.mr-sm,.mx-sm{margin-right:12px!important}.mb-sm,.my-sm{margin-bottom:12px!important}.ml-sm,.mx-sm{margin-left:12px!important}.p-sm{padding:12px!important}.pt-sm,.py-sm{padding-top:12px!important}.pr-sm,.px-sm{padding-right:12px!important}.pb-sm,.py-sm{padding-bottom:12px!important}.pl-sm,.px-sm{padding-left:12px!important}.m-md{margin:16px!important}.mt-md,.my-md{margin-top:16px!important}.mr-md,.mx-md{margin-right:16px!important}.mb-md,.my-md{margin-bottom:16px!important}.ml-md,.mx-md{margin-left:16px!important}.p-md{padding:16px!important}.pt-md,.py-md{padding-top:16px!important}.pr-md,.px-md{padding-right:16px!important}.pb-md,.py-md{padding-bottom:16px!important}.pl-md,.px-md{padding-left:16px!important}.m-lg{margin:24px!important}.mt-lg,.my-lg{margin-top:24px!important}.mr-lg,.mx-lg{margin-right:24px!important}.mb-lg,.my-lg{margin-bottom:24px!important}.ml-lg,.mx-lg{margin-left:24px!important}.p-lg{padding:24px!important}.pt-lg,.py-lg{padding-top:24px!important}.pr-lg,.px-lg{padding-right:24px!important}.pb-lg,.py-lg{padding-bottom:24px!important}.pl-lg,.px-lg{padding-left:24px!important}.m-xl{margin:32px!important}.mt-xl,.my-xl{margin-top:32px!important}.mr-xl,.mx-xl{margin-right:32px!important}.mb-xl,.my-xl{margin-bottom:32px!important}.ml-xl,.mx-xl{margin-left:32px!important}.p-xl{padding:32px!important}.pt-xl,.py-xl{padding-top:32px!important}.pr-xl,.px-xl{padding-right:32px!important}.pb-xl,.py-xl{padding-bottom:32px!important}.pl-xl,.px-xl{padding-left:32px!important}.m-auto{margin:auto!important}.mt-auto,.my-auto{margin-top:auto!important}.mr-auto,.mx-auto{margin-right:auto!important}.mb-auto,.my-auto{margin-bottom:auto!important}.ml-auto,.mx-auto{margin-left:auto!important}.text-justify{text-align:justify!important}.text-nowrap{white-space:nowrap!important}.text-align-left{text-align:left!important}.text-align-right{text-align:right!important}.text-align-center{text-align:center!important}.text-lowercase{text-transform:lowercase!important}.text-uppercase{text-transform:uppercase!important}.text-capitalize{text-transform:capitalize!important}.font-weight-light{font-weight:300!important}.font-weight-normal{font-weight:400!important}.font-weight-bold{font-weight:700!important}.font-italic{font-style:italic!important}.text-white{color:#fff!important}.visible{visibility:visible}.invisible{visibility:hidden}.d-flex{display:flex}.d-inline-flex{display:inline-flex}.d-block{display:block}.d-inline-block{display:inline-block}.d-inline{display:inline}.flex-column{flex-direction:column!important}.flex-row-reverse{flex-direction:row-reverse!important}.flex-column-reverse{flex-direction:column-reverse!important}.flex-wrap{flex-wrap:wrap!important}.flex-nowrap{flex-wrap:nowrap!important}.flex-wrap-reverse{flex-wrap:wrap-reverse!important}.flex-fill{flex:1 1 auto!important}.flex-grow-0{flex-grow:0!important}.flex-grow-1{flex-grow:1!important}.flex-shrink-0{flex-shrink:0!important}.flex-shrink-1{flex-shrink:1!important}.justify-content-start{justify-content:flex-start!important}.justify-content-end{justify-content:flex-end!important}.justify-content-center{justify-content:center!important}.justify-content-between{justify-content:space-between!important}.justify-content-around{justify-content:space-around!important}.align-items-start{align-items:flex-start!important}.align-items-end{align-items:flex-end!important}.align-items-center{align-items:center!important}.align-items-baseline{align-items:baseline!important}.align-items-stretch{align-items:stretch!important}.align-content-start{align-content:flex-start!important}.align-content-end{align-content:flex-end!important}.align-content-center{align-content:center!important}.align-content-between{align-content:space-between!important}.align-content-around{align-content:space-around!important}.align-content-stretch{align-content:stretch!important}.align-self-auto{align-self:auto!important}.align-self-start{align-self:flex-start!important}.align-self-end{align-self:flex-end!important}.align-self-center{align-self:center!important}.align-self-baseline{align-self:baseline!important}.align-self-stretch{align-self:stretch!important}.fm-utils-absolute-all{top:0;bottom:0;position:absolute;right:0;left:0}.fm-utils-flex-column{flex-direction:column!important;overflow:hidden}.fm-utils-fill-flex-column,.fm-utils-fill-flex-row{flex-shrink:1;display:flex!important;overflow:hidden}.fm-utils-fill-flex-column{flex-grow:1;flex-basis:0;flex-direction:column!important}.fm-utils-flex-row{display:flex!important;overflow:hidden;flex-wrap:nowrap}.fm-utils-flex-row-wrap{display:flex!important;flex-direction:row!important;overflow:hidden;flex-wrap:wrap!important}.fm-utils-fill-flex-row{flex-grow:1;flex-basis:0;flex-direction:row!important;flex-wrap:nowrap!important}.fm-utils-fill-flex-row-wrap{flex-shrink:1;flex-grow:1;flex-basis:0;display:flex!important;flex-direction:row!important;overflow:hidden;flex-wrap:wrap!important}.fm-utils-fill{flex-shrink:1;flex-grow:1;flex-basis:0;overflow:hidden}.fm-utils-fill-auto{flex-shrink:1;flex-grow:1;flex-basis:0;overflow-x:hidden;overflow-y:auto}.fm-utils-overflow-xhya{overflow-x:hidden!important;overflow-y:auto!important}.fm-utils-overflow-xayh{overflow-y:hidden!important;overflow-x:auto!important}.fm-utils-overflow-xaya{overflow:auto!important}.fm-utils-overflow-hidden{overflow:hidden!important}.fm-utils-overflow-auto{overflow:auto!important}.fm-overflow-x-auto{overflow-x:auto!important}.fm-overflow-x-hidden,.fm-overflow-y-auto,.fm-overflow-y-hidden{overflow-x:hidden!important}.fm-overflow-y-auto{overflow-y:auto!important}.fm-overflow-y-hidden{overflow-y:hidden!important}.fm-overflow-hidden{overflow:hidden!important}.fm-utils-text-break{white-space:normal!important;word-break:break-all!important}.fm-utils-display-none{display:none!important}.fm-multi-ellipsis-l2,.fm-multi-ellipsis-l3{display:-webkit-box;-webkit-box-orient:vertical;text-overflow:ellipsis;overflow:hidden}.fm-ellipsis{overflow:hidden;white-space:nowrap;text-overflow:ellipsis}.fm-multi-ellipsis-l2{-webkit-line-clamp:2}.fm-multi-ellipsis-l3{-webkit-line-clamp:3}.fm-float-button-wrapper{position:absolute;right:16px;bottom:50px}.fm-listview-error{background:#fff;box-shadow:0 2px 6px 0 rgba(0,0,0,.12)}.fm-error-cell{position:relative;display:flex;justify-content:space-between;align-items:center;padding:0 16px;height:32px}.fm-error-cell:not(:last-child)::after{content:'';height:1px;position:absolute;background-color:#f1f1f1;display:block;z-index:1;bottom:0;left:16px;right:0;transform:translateY(.5)}.fm-error-text{font-size:13px;color:#f24645;line-height:22px}.fm-error-icon{background:#F24645;color:#fff;border-radius:100%;margin-right:4px}.fm-tmpl-single-header{height:32px;display:flex;align-items:center;padding:0 0 0 16px;background:#F8F9FB}.fm-tmpl-single-header h6{color:#999;font-size:15px;font-weight:400;margin:0}.fm-tmpl-singlelist-with-iconarea{background:#fff;overflow:hidden}.fm-tmpl-singlelist-with-iconarea .singlelist--item{align-items:center;padding:0 0 0 16px;display:flex}.fm-tmpl-singlelist-with-iconarea .singlelist--item:last-child .singlelist--item-title-wrapper{border-bottom:none}.fm-tmpl-singlelist-with-iconarea .singlelist--item .item-img-round--wrapper .item-img-round--img{width:26px;height:26px;border-radius:13px}.fm-tmpl-singlelist-with-iconarea .singlelist--item .item-img-round--wrapper .item-img-round--img .fm-icon{line-height:26px}.fm-tmpl-singlelist-with-iconarea .singlelist--item-title-wrapper{flex-shrink:1;flex-grow:1;flex-basis:0;color:#333;font-size:16px;line-height:22px;padding:11px 0 10px;border-bottom:1px solid #ddd;position:relative}@media (-webkit-min-device-pixel-ratio:2),(min-resolution:2dppx){html:not([data-scale]) .fm-tmpl-singlelist-with-iconarea .singlelist--item-title-wrapper{border-bottom:none}html:not([data-scale]) .fm-tmpl-singlelist-with-iconarea .singlelist--item-title-wrapper::after{content:'';position:absolute;background-color:#ddd;display:block;z-index:1;top:auto;right:auto;bottom:0;left:0;width:100%;height:1PX;transform-origin:50% 100%;transform:scaleY(.5)}}.item-img-round--wrapper{margin:0 10px 0 0}.item-img-round--wrapper .item-img-round--img{width:30px;height:30px;border-radius:15px;text-align:center;color:#fff}.item-img-round--wrapper .item-img-round--img .fm-icon{font-size:18px;line-height:30px}.item-img-round--wrapper .fm-bg-yellow{background:#FBB902}.item-img-round--wrapper .fm-bg-orange{background:#FF9800}.item-img-round--wrapper .fm-bg-blue{background:#4D9AFF}.item-img-round--wrapper .fm-bg-lightblue{background:#5ACBCD}.item-img-round--wrapper .fm-bg-purple{background:#817EFF}.item-img-round--wrapper .fm-bg-darkgreen{background:#51BD78}.fm-tmpl-header-with-img{display:flex;align-items:center}.fm-tmpl-header-with-img h5{font-size:16px;color:#333;margin:0;font-weight:400}.fm-tmpl-header-with-img .header-with-img--img-wrapper{margin:0 8px 0 0}.fm-tmpl-header-with-img .header-with-img--img-wrapper .header-with-img--img{width:20px;height:20px;border-radius:10px;line-height:20px;text-align:center;color:#fff;background-image:linear-gradient(180deg,#64CDFB 1%,#3A90FF 100%)}.fm-tmpl-header-with-img .header-with-img--img-wrapper .header-with-img--img .fm-icon{font-size:12px}.fm-tmpl-header-with-img .header-with-img--img-wrapper .fm-bg-blue{color:#fff;background-image:linear-gradient(180deg,#64CDFB 1%,#3A90FF 100%)}.fm-tmpl-header-with-img .header-with-img--img-wrapper .fm-bg-orange{color:#fff;background-image:linear-gradient(180deg,#FFB951 15%,#FF9800 100%)}.fm-tmpl-header-with-img .header-with-img--img-wrapper .fm-bg-green{color:#fff;background-image:linear-gradient(180deg,#7ACC8D 15%,#51BD78 100%)}.fm-cmp-collapse-style::after{display:none}.fm-cmp-collapse-style .van-collapse-item__title{align-items:center}.fm-cmp-collapse-style .van-collapse-item__content{padding:0}.fm-cmp-collapse-style.van-collapse{margin:0 0 12px}.fm-cmp-collapse-style.van-collapse:last-child{margin-bottom:0}.fm-tmpl-collapse-sub::after{border-bottom:0}.fm-tmpl-collapse-sub-header{display:flex;flex-direction:column-reverse}.fm-tmpl-collapse-sub-header .van-collapse-item__title .expand,.fm-tmpl-collapse-sub-header .van-collapse-item__title--expanded .collapse{display:none}.fm-tmpl-collapse-sub-header .van-collapse-item__title{color:#888;flex-direction:row-reverse;justify-content:center}.fm-tmpl-collapse-sub-header .van-collapse-item__title h6{color:#888;font-size:13px;font-weight:400}.fm-tmpl-collapse-sub-header .van-collapse-item__title .collapse-icon{margin:0 8px;transition:transform .3s}.fm-tmpl-collapse-sub-header .van-collapse-item__title--expanded .expand{display:inline-block}.fm-tmpl-collapse-sub-header .van-collapse-item__title--expanded .collapse-icon{transform:rotate(180deg)}.fm-btn-block-wrapper{height:42px;background:#fff;display:flex;align-items:center}.fm-btn-block-wrapper .fm-button{font-size:14px!important;height:100%}.fm-btn-with-icon .fm-btn-text{margin:0 8px}.fm-btn-with-icon .fm-btn-icon{font-size:14px}.fm-tmpl-list-with-img-detail.fm-tmpl-list-with-border{margin-bottom:12px}.fm-tmpl-list-with-img-detail.fm-tmpl-list-with-border .img-detail--item{margin-bottom:0;border-bottom:1px solid #ddd;position:relative}@media (-webkit-min-device-pixel-ratio:2),(min-resolution:2dppx){html:not([data-scale]) .fm-tmpl-list-with-img-detail.fm-tmpl-list-with-border .img-detail--item{border-bottom:none}html:not([data-scale]) .fm-tmpl-list-with-img-detail.fm-tmpl-list-with-border .img-detail--item::after{content:'';position:absolute;background-color:#ddd;display:block;z-index:1;top:auto;right:auto;bottom:0;left:0;width:100%;height:1PX;transform-origin:50% 100%;transform:scaleY(.5)}}.fm-round-bg{margin:4px auto 0;width:36px;height:36px;background:#3A90FF;border-radius:20px;line-height:36px;font-size:13px;text-align:center;overflow:hidden;white-space:nowrap}.fm-round-bg-text{color:#FFF}.fm-tmpl-list-with-img-detail .img-detail--item{padding:12px 16px;background:#fff;border-bottom:1px solid #ddd;position:relative}@media (-webkit-min-device-pixel-ratio:2),(min-resolution:2dppx){html:not([data-scale]) .fm-tmpl-list-with-img-detail .img-detail--item{border-bottom:none}html:not([data-scale]) .fm-tmpl-list-with-img-detail .img-detail--item::after{content:'';position:absolute;background-color:#ddd;display:block;z-index:1;top:auto;right:auto;bottom:0;left:0;width:100%;height:1PX;transform-origin:50% 100%;transform:scaleY(.5)}}.fm-tmpl-list-with-img-detail .img-detail--item .img-detail--item-content{display:flex;position:relative}.fm-tmpl-list-with-img-detail .img-detail--item .img-detail--status{position:absolute;right:0;top:23px}.fm-tmpl-list-with-img-detail .img-detail--item .img-detail--content{position:relative;flex-shrink:1;flex-grow:1;flex-basis:0}.fm-tmpl-list-with-img-detail .img-detail--item .img-detail--header{display:flex;align-items:center;justify-content:space-between;margin:0 0 6px}.fm-tmpl-list-with-img-detail .img-detail--item .img-detail--header .title{line-height:22px;font-weight:400;font-size:16px;color:#333}.fm-tmpl-list-with-img-detail .img-detail--item .img-detail--header .time{line-height:18px;color:#999;font-size:13px}.fm-tmpl-list-with-img-detail .img-detail--item .img-detail--info{line-height:18px;color:#999;font-size:13px;margin:0 0 4px}.fm-tmpl-list-with-img-detail .img-detail--item .img-detail--info>.gutter{margin:0 14px 0 0}.fm-tmpl-list-with-img-detail .img-detail--item .img-detail--actions{padding:18px 0 0;text-align:right}.fm-tmpl-list-with-img-detail .img-detail--item .img-detail--actions .fm-button{margin-left:13px}.fm-tmpl-list-with-img-detail .img-detail--item .img-detail--actions .fm-button:first-child{margin-left:0}.fm-tmpl-result{display:flex;flex-direction:column;padding-top:40px;align-items:center}.fm-tmpl-result-header .fm-result-title{display:flex;flex-direction:row;font-size:20px;color:#333}.fm-tmpl-result-header .fm-result-title .fm-result-title-number{color:#FF9800}.fm-tmpl-result-content{max-width:84%;padding-top:30px;padding-bottom:30px;text-align:center}.fm-tmpl-result-content .fm-result-img{width:140px;height:140px;margin:0 auto}.fm-tmpl-result-content .fm-result-img img{display:block;width:140px;height:140px}.fm-tmpl-result-content .fm-result-text{padding-top:30px;padding-bottom:10px;font-size:16px;color:#333;text-align:center}.fm-tmpl-result-content .fm-result-tip{line-height:22px;font-size:16px;color:#888;text-align:center}.fm-tmpl-result-footer{width:140px;margin:0 auto}.fm-tmpl-result-footer .fm-result-btn{margin-bottom:16px}.fm-tmpl-result-footer .fm-result-btn:last-child{margin-bottom:0}.fm-tabbar-style{border-top:1px solid #ddd;position:relative}@media (-webkit-min-device-pixel-ratio:2),(min-resolution:2dppx){html:not([data-scale]) .fm-tabbar-style{border-top:none}html:not([data-scale]) .fm-tabbar-style::before{content:'';position:absolute;background-color:#ddd;display:block;z-index:1;top:0;right:auto;bottom:auto;left:0;width:100%;height:1PX;transform-origin:50% 50%;transform:scaleY(.5)}}.fm-tabbar-style .show-fixed-width{padding:0 17px;flex-shrink:0;flex-grow:0;flex-basis:auto}.fm-tabbar-style .show-fixed-width+.show-left-width{padding:7px 16px 7px 0}.fm-tabbar-style .show-fixed-width .van-tabbar-item__icon .fm-icon{font-size:19px}.fm-tabbar-style .show-fixed-width .van-tabbar-item__text{font-size:12px;transform:scale(.8333)}.fm-tabbar-style .show-left-width{padding:7px 16px}.fm-tabbar-style .show-left-width .fm-button{height:100%}.fm-tmpl-detail-header{padding-left:16px;background-color:#fff}.fm-tmpl-detail-header-inner{display:flex;flex-direction:row;align-items:center;padding:16px 16px 16px 0;border-bottom:1px solid #DDD;position:relative}@media (-webkit-min-device-pixel-ratio:2),(min-resolution:2dppx){html:not([data-scale]) .fm-tmpl-detail-header-inner{border-bottom:none}html:not([data-scale]) .fm-tmpl-detail-header-inner::after{content:'';position:absolute;background-color:#DDD;display:block;z-index:1;top:auto;right:auto;bottom:0;left:0;width:100%;height:1PX;transform-origin:50% 100%;transform:scaleY(.5)}}.fm-approve-flow-wrapper .fm-approve-flow-item .fm-approve-flow-item-header-icon .header-icon::before,.fm-approve-flow-wrapper .fm-approve-flow-item-content .fm-approve-flow-item-main-avatar .avatar-icon::before{content:"\e6b4"}.fm-tmpl-detail-header-inner .detail-header--avatar{width:40px;margin-right:10px;border-radius:50%;overflow:hidden}.fm-tmpl-detail-header-inner .detail-header--avatar img{display:block;width:40px;height:40px}.fm-tmpl-detail-header-inner .detail-header--content{flex:1}.fm-tmpl-detail-header-inner .detail-header--content-title{margin-bottom:3px;font-size:15px;color:#333}.fm-tmpl-detail-header-inner .detail-header--content-subtitle{font-size:13px;color:#888}.fm-static-input-list{padding:16px 0 16px 16px;background-color:#fff;margin:0 0 8px}.fm-static-input-list .fm-listview-item:last-child .fm-static-input-info{margin-bottom:0}.fm-static-input-info{display:flex;flex-direction:row;align-items:center;margin-bottom:8px;line-height:20px}.fm-static-input-info .input-info--label{width:92px;font-size:14px;color:#999;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.fm-static-input-info .input-info--text{flex-shrink:1;flex-grow:1;flex-basis:0;padding-left:8px;font-size:14px;color:#333}.fm-static-input-info .input-info--accessory{display:flex;flex-direction:row;align-items:center;flex-wrap:wrap}.fm-static-input-info .input-info--accessory-item{flex-shrink:0;width:28px;height:28px;margin-right:12px;border-radius:3px;overflow:hidden}.fm-static-input-info .input-info--accessory-item img{display:block;width:28px}.fm-static-input-info .input-info--accessory-item:last-child{margin-right:0}.fm-approve-flow-wrapper{padding:12px 16px;background-color:#fff}.fm-approve-flow-wrapper .fm-approve-flow-item{padding-left:7px}.fm-approve-flow-wrapper .fm-approve-flow-item-header{position:relative;border-left:1px dashed #D4D4D4}.fm-approve-flow-wrapper .fm-approve-flow-item-header-inner{position:relative;display:flex;flex-direction:row;align-items:center;padding-left:28px}.fm-approve-flow-wrapper .fm-approve-flow-item-header-inner .fm-approve-flow-item-header-icon{position:absolute;left:-8px;top:0;z-index:100}.fm-approve-flow-wrapper .fm-approve-flow-item-header-inner .fm-approve-flow-item-header-icon .fm-icon{background-color:#fff;font-size:15px;color:#34AAFF;border-radius:50%}.fm-approve-flow-wrapper .fm-approve-flow-item-header-inner .fm-approve-flow-item-header-icon img{background:#fff}.fm-approve-flow-wrapper .fm-approve-flow-item-header-inner .fm-approve-flow-item-header-content{flex-shrink:1;flex-grow:1;flex-basis:0;line-height:21px;font-size:15px;color:#4C4C4C;font-weight:700}.fm-approve-flow-wrapper .fm-approve-flow-item-header-inner .fm-approve-flow-item-header-right{flex-shrink:0;padding-left:6px}.fm-approve-flow-wrapper .fm-approve-flow-item-header-inner .fm-approve-flow-item-header-right .fm-icon{color:#979797}.fm-approve-flow-wrapper .fm-approve-flow-item-header-state{margin-top:6px;padding-left:28px;font-size:13px;color:#FF9002}.fm-approve-flow-wrapper .fm-approve-flow-item-content{display:flex;flex-direction:row;align-items:flex-start;padding:12px 0 30px 28px;border-left:1px dashed #D4D4D4}.fm-approve-flow-wrapper .fm-approve-flow-item-content .fm-approve-flow-item-main{flex-shrink:1;flex-grow:1;flex-basis:0;display:flex;flex-direction:row;align-items:flex-start}.fm-approve-flow-wrapper .fm-approve-flow-item-content .fm-approve-flow-item-main-avatar{position:relative;display:flex;flex-direction:row;align-items:center;width:36px;height:36px}.fm-approve-flow-wrapper .fm-approve-flow-item-content .fm-approve-flow-item-main-avatar-img{display:block;width:36px;height:36px;border-radius:50%}.fm-approve-flow-wrapper .fm-approve-flow-item-content .fm-approve-flow-item-main-avatar-icon{position:absolute;right:4px;bottom:-4px;font-size:14px;color:#34AAFF;background-color:#fff;border-radius:50%}.fm-approve-flow-wrapper .fm-approve-flow-item-content .fm-approve-flow-item-main-text{flex-shrink:1;flex-grow:1;flex-basis:0;padding:0 6px 0 9px}.fm-approve-flow-wrapper .fm-approve-flow-item-content .fm-approve-flow-item-main-text-title{font-size:13px;color:rgba(51,51,51,.65)}.fm-approve-flow-wrapper .fm-approve-flow-item-content .fm-approve-flow-item-main-text-subtitle{margin-top:2px;line-height:20px;font-size:14px;color:#333}.fm-approve-flow-wrapper .fm-approve-flow-item-content .fm-approve-flow-item-date{font-size:13px;color:rgba(51,51,51,.65)}.fm-approve-flow-wrapper .fm-approve-flow-item.fm-approve-flow-item-approved .fm-approve-flow-item-content .fm-approve-flow-item-main-avatar-icon,.fm-approve-flow-wrapper .fm-approve-flow-item.fm-approve-flow-item-approved .fm-approve-flow-item-header .fm-approve-flow-item-header-icon .fm-icon,.fm-approve-flow-wrapper .fm-approve-flow-item.fm-approve-flow-item-approved .fm-approve-flow-item-header .fm-approve-flow-item-header-state{color:#1AD0C8}.fm-approve-flow-wrapper .fm-approve-flow-item.fm-approve-flow-item-approved .fm-approve-flow-item-content .fm-approve-flow-item-main-avatar .avatar-icon::before,.fm-approve-flow-wrapper .fm-approve-flow-item.fm-approve-flow-item-approved .fm-approve-flow-item-header .fm-approve-flow-item-header-icon .header-icon::before{content:"\e6b3"}.fm-approve-flow-wrapper .fm-approve-flow-item:last-child .fm-approve-flow-item-header{border-left:0}.fm-approve-flow-wrapper .fm-approve-flow-item:last-child .fm-approve-flow-item-header::before{display:none!important}.fm-approve-flow-wrapper .fm-approve-flow-item:last-child .fm-approve-flow-item-content{padding-bottom:12px;border-left:none}.fm-approve-nopass,.fm-approve-pass{position:fixed;top:48px;right:14px;width:110px;height:110px;z-index:1000}.fm-approve--detail-header{padding-left:16px;background-color:#fff}.fm-approve--detail-header-inner{display:flex;flex-direction:row;align-items:center;padding:17px 16px 17px 0;border-bottom:1px solid #DDD;position:relative}@media (-webkit-min-device-pixel-ratio:2),(min-resolution:2dppx){html:not([data-scale]) .fm-approve--detail-header-inner{border-bottom:none}html:not([data-scale]) .fm-approve--detail-header-inner::after{content:'';position:absolute;background-color:#DDD;display:block;z-index:1;top:auto;right:auto;bottom:0;left:0;width:100%;height:1PX;transform-origin:50% 100%;transform:scaleY(.5)}}.fm-approve--detail-header-inner .detail-header--avatar{width:40px;margin-right:10px;border-radius:50%;overflow:hidden}.fm-approve--detail-header-inner .detail-header--avatar img{display:block;width:40px;height:40px}.fm-approve--detail-header-inner .detail-header---info{flex:1}.fm-approve--detail-header-inner .detail-header---info-title{margin-bottom:3px;font-size:15px;color:#333}.fm-approve--detail-header-inner .detail-header---info-subtitle{font-size:13px;color:#888}.fm-apply-list-wrapper{padding:0 16px 16px;background-color:#fff;margin:0 0 12px}.fm-apply-list-item{display:flex;flex-direction:row;align-items:flex-start;margin-bottom:8px;line-height:20px}.fm-apply-list-item-label{width:92px;font-size:14px;color:#999;text-align:right;word-break:break-all}.fm-apply-list-item-text{flex-shrink:1;flex-grow:1;flex-basis:0;padding-left:14px;font-size:14px;color:#333;word-break:break-all}.fm-apply-list-item-accessory{display:flex;flex-direction:row;align-items:center;flex-wrap:wrap}.fm-apply-list-item-accessory-item{flex-shrink:0;width:28px;height:28px;margin-right:12px;border-radius:3px;overflow:hidden}.fm-apply-list-item-accessory-item img{display:block;width:28px}.fm-apply-list-item-accessory-item:last-child{margin-right:0}.fm-apply-list-item:last-child{margin-bottom:0}.fm-apply-panel-title,.fm-apply-plate-title{height:28px;line-height:28px;padding-left:10px;margin-bottom:0;background:#F6F6F6;border-radius:2px}.fm-apply-panel-action,.fm-apply-plate-action{padding:0 6px;margin:0 0 0 auto;color:#D8D8D8}.fm-apply-panel-action:hover,.fm-apply-plate-action:hover{background:#3A90FF;color:#fff}.fm-apply-panel{padding-top:0}.fm-apply-panel .fm-apply-list{padding-top:10px;padding-bottom:14px}.fm-apply-panel .fm-apply-list+.fm-apply-list{border-top:1px solid #E8E8E8}.fm-apply-panel-list{padding:0 16px;background-color:#fff;margin:0;border-bottom:1px solid #E8E8E8}.fm-apply-panel-list:last-child{border-bottom:none}.fm-apply-panel-list .panel-list--header{height:42px;display:flex;align-items:center}.fm-apply-panel-list .panel-list--header .panel-list--header-title{font-size:15px;line-height:21px;color:#333;padding:0 0 0 10px;position:relative}.fm-apply-panel-list .panel-list--header .panel-list--header-title::before{content:'';position:absolute;left:0;top:50%;width:3px;height:14px;margin:-7px 0 0;background:#55BBF6}.fm-apply-details{margin:0 0 14px;background:#fff}.fm-apply-main{border-bottom:1px solid #E8E8E8}.fm-avatar-with-state{position:relative;display:flex;flex-direction:row;align-items:center;width:36px;height:36px}.fm-avatar-with-state--img{display:block;width:36px;height:36px;border-radius:50%}.fm-avatar-with-state--icon{position:absolute;right:4px;bottom:-4px;font-size:14px;color:#34AAFF;background-color:#fff;border-radius:50%}.fm-avatar-with-state .avatar-icon::before{content:"\e6b3"}.fm-avatar-with-state .fm-round-bg{background:rgba(77,154,255,.6)}.fm-avatar-with-state.fm-state-running .avatar-icon::before{content:"\e6b4"}.fm-feature-select-person{display:flex;flex-direction:row;flex-wrap:wrap;padding:0 0 14px}.fm-feature-select-person .select-person--item{position:relative;display:flex;align-items:center;margin:0 16px 0 0}.fm-feature-select-person .select-person--item .fm-avatar-with-state{width:48px;height:48px}.fm-feature-select-person .select-person--item .fm-avatar-with-state .fm-avatar-with-state--img{width:48px;height:48px;border-radius:24px}.fm-feature-select-person .select-person--item .fm-avatar-with-state .fm-avatar-with-state--icon{right:0;top:0;cursor:pointer}.fm-feature-select-person .select-person--item .fm-avatar-with-state .fm-avatar-with-state--icon::before{content:"\e016"}.fm-feature-select-person .select-person--item .fm-avatar-with-state .fm-avatar-with-state--icon:hover{background:#F24645;color:#fff}.fm-feature-select-person .select-person--item .fm-round-bg{width:48px;height:48px;border-radius:24px;line-height:48px}.fm-feature-select-person .select-person--icon{margin:0 0 0 3px;color:#A6A6A6}.fm-feature-select-person .select-person--icon::before{content:"→"}.fm-tmpl-search-container{position:relative;padding:7px 16px;display:flex;flex-direction:row;align-items:center;background:#fff}.fm-tmpl-search-container .fm-tmpl-search-type{flex-shrink:0;margin:0 10px 0 0}.fm-tmpl-search-container .fm-tmpl-search-type.fm-state-active{color:#3A90FF}.fm-tmpl-search-container .fm-tmpl-search-inner{flex:1 1 0}.fm-tmpl-search-container .fm-tmpl-search-inner .van-search{padding:0}.fm-tmpl-search-container .fm-tmpl-search-tree-select{position:absolute;left:0;right:0;top:100%;z-index:10}.fm-page-listview{display:flex;flex-direction:column}.fm-page-listview .fm-page-main{padding-bottom:0;flex-shrink:1;flex-grow:1;flex-basis:0;overflow:hidden}.fm-page-listview .fm-page-main .fm-tmpl-list-extend,.fm-page-listview .fm-page-main .fm-tmpl-search-container{flex-shrink:0}.fm-page-listview .fm-page-main .fm-tmpl-list-container{display:flex;flex-direction:column;flex-shrink:1;flex-grow:1;flex-basis:0;overflow:hidden}.fm-page-listview .fm-page-main .fm-tmpl-list-container .fm-tmpl-list-footer{display:flex;flex-direction:row;align-items:center;height:54px;padding:0 16px;background:#fff;box-shadow:0 -2px 8px 0 rgba(81,120,159,.12)}.fm-page-listview .fm-page-main .fm-tmpl-list-container .fm-tmpl-list-footer .fm-tmpl-list-footer-btn{flex:1;text-align:center}.fm-page-listview .fm-page-main .fm-tmpl-list-container .fm-tmpl-search-tree-overlay{position:absolute;left:0;bottom:0;right:0;top:0;z-index:9;background-color:rgba(0,0,0,.4)}.fm-page-listview .fm-page-main .fm-tmpl-list-container .fm-tmpl-add-btn{position:absolute;right:16px;bottom:50px}.fm-page-listview .fm-page-main .fm-tmpl-list-container .fm-tmpl-add-btn-inner{width:48px;height:48px;text-align:center;line-height:48px;border-radius:50%;background-image:linear-gradient(-45deg,#65A7FF 0,#3A90FF 100%);box-shadow:0 2px 5px 0 rgba(124,163,254,.57)}.fm-page-listview .fm-page-main .fm-tmpl-list-container .fm-tmpl-add-btn-inner .fm-icon{color:#fff;font-size:16px}.fm-page-listview .fm-page-main .fm-tmpl-list-container .van-pull-refresh{display:flex;flex-direction:column;flex-shrink:1;flex-grow:1;flex-basis:0;overflow:hidden}.fm-page-listview .fm-page-main .fm-tmpl-list-container .van-pull-refresh .van-pull-refresh__track{display:flex;flex-direction:column;flex-shrink:1;flex-grow:1;flex-basis:0}.fm-page-listview .fm-page-main .fm-tmpl-list-add .fm-tmpl-add-btn{bottom:16px}.fm-page-listview .fm-page-main .fm-tmpl-list-add .fm-listview-container.fm-listview-container-fill .fm-listview-main{padding-bottom:70px}.fm-page-listview .fm-page-main .fm-tmpl-tabs{flex:1;display:flex;flex-direction:column}.fm-page-listview .fm-page-main .fm-tmpl-tabs .fm-tab-bar,.fm-page-listview .fm-page-main .fm-tmpl-tabs .van-tabs__wrap{flex-shrink:0}.fm-page-listview .fm-page-main .fm-tmpl-tabs .fm-tabs-content,.fm-page-listview .fm-page-main .fm-tmpl-tabs .fm-tabs-content .fm-tab-pane,.fm-page-listview .fm-page-main .fm-tmpl-tabs .van-tabs__content{display:flex;flex-direction:column;flex-shrink:1;flex-grow:1;flex-basis:0;overflow:hidden}.fm-page-listview .fm-page-main .fm-tmpl-tabs .van-tabs__content .van-tab__pane{display:flex;flex-direction:column;flex:1}.fm-page-listview .fm-page-main .fm-tmpl-tabs .fm-tmpl-tabs-content{display:flex;flex-direction:column;flex-shrink:1;flex-grow:1;flex-basis:0;overflow:hidden}.fm-page-card .fm-page-footer,.fm-tmpl-list-extend{flex-shrink:0}.fm-btn-link{color:#3A90FF}.fm-page-card{display:flex;flex-direction:column}.fm-page-card .fm-page-main{flex-shrink:1;flex-grow:1;flex-basis:0;overflow:auto}.fm-page-card .fm-page-main .fm-page-card-btns{padding:30px 16px 0}.fm-tmpl-struct-wrapper{flex-shrink:0;margin-top:12px}.fm-tmpl-struct-wrapper .fm-tmpl-section{margin-top:12px}.fm-tmpl-struct-wrapper .fm-tmpl-section:first-child{margin-top:0}.fm-tmpl-section{background-color:#fff}.fm-title::before,.fm-tmpl-section-header .fm-title::before{content:'';background:#3A90FF}.fm-tmpl-section-header{display:flex;align-items:center;justify-content:space-between;padding:11px 16px 10px}.fm-tmpl-section-header .fm-title{position:relative;padding-left:16px}.fm-tmpl-section-header .fm-title::before{position:absolute;left:0;top:50%;width:3px;height:14px;margin:-7px 0 0}.fm-tmpl-section-header .fm-title-text{font-size:15px;line-height:21px;color:#333}.fm-tmpl-section-header .fm-toolbar{display:flex;align-items:center}.fm-tmpl-section-header .fm-toolbar-item{display:flex;align-items:center;padding-left:16px;font-size:15px;color:#3A90FF}.fm-tmpl-section-header .fm-toolbar-item-text{margin-left:4px}.fm-tmpl-section-header .fm-toolbar-item-icon{font-size:16px}.fm-tmpl-section-content{padding:0 16px}.fm-tmpl-button-wrapper{padding:30px 16px 0;flex-shrink:0}.fm-tmpl-button-wrapper .fm-tmpl-btns{display:flex;align-items:center}.fm-tmpl-button-wrapper .fm-tmpl-btns .fm-button{flex:1;margin-right:11px}.fm-tmpl-button-wrapper .fm-tmpl-btns.fm-button:last-child{margin-right:0}.fm-tmpl-section-btn{display:flex;flex-direction:row;align-items:center;padding:0 16px;border-top:1px solid #ddd;position:relative}@media (-webkit-min-device-pixel-ratio:2),(min-resolution:2dppx){html:not([data-scale]) .fm-tmpl-section-btn{border-top:none}html:not([data-scale]) .fm-tmpl-section-btn::before{content:'';position:absolute;background-color:#ddd;display:block;z-index:1;top:0;right:auto;bottom:auto;left:0;width:100%;height:1PX;transform-origin:50% 50%;transform:scaleY(.5)}}.fm-tmpl-section-btn .fm-button{flex:1;position:relative}.fm-tmpl-section-btn .fm-button::after{position:absolute;right:0;top:50%;width:1px;height:16px;margin-top:-8px;background:#ddd;transform:scaleX(.5);content:''}.fm-tmpl-section-btn .fm-button:last-child::after{display:none}.fm-card-tmpl-header{height:36px;line-height:36px;background-color:#f9f9fb;padding-left:16px}.fm-edit-input-list{position:relative}.fm-banner-warpper{position:relative;background:url(imgs/questionnaire-header.png) center/cover no-repeat;display:flex;flex-direction:column;align-items:center;justify-content:center}.fm-banner-warpper .fm-banner-title,.fm-banner-warpper .fm-banner-title-sub{color:#fff;text-shadow:0 2px 8px rgba(0,26,123,.52)}.fm-banner-warpper .fm-banner-title{font-size:24px;line-height:33px}.fm-banner-warpper .fm-banner-title-sub{font-size:12px;line-height:17px;padding-top:4px}@media screen and (max-width:375px){.fm-banner-warpper{height:98px}}@media screen and (min-width:375px) and (max-width:414px){.fm-banner-warpper{height:116px}}@media screen and (min-width:414px){.fm-banner-warpper{height:128px}}.fm-stamp-wrapper{width:68px;height:68px;position:absolute;right:16px;top:12px;background:url(imgs/questionnaire-submitted.png) center/contain no-repeat;z-index:9}.fm-card-uploader-content{padding:10px 16px}.fm-page-header-staff{background:linear-gradient(90deg,#2899F6 0,#3E76F9 50%,#4384F8 100%)}.fm-page-header-staff .fm-navbar{background:0 0}.fm-page-header-staff .fm-navbar .fm-navbar-left-arrow,.fm-page-header-staff .fm-navbar .fm-navbar-title{color:#fff}.fm-navbar-right-text{color:#333;font-size:16px}.fm-input-wrapper:not(:last-child) .van-cell::after{display:block}.fm-inner-cell .van-checkbox__label::after,.fm-inner-cell .van-radio__label::after,.fm-input-wrapper:last-child .van-cell::after{display:none}.fm-radio-readonly .fm-inner-cell .van-radio .van-radio__icon .van-icon{background-color:#fff}.fm-radio-readonly .fm-inner-cell .van-radio .van-radio__icon--checked .van-icon{background-color:#1989fa;border-color:#1989fa}html:not([data-scale]) .fm-input-wrapper:not(:last-child) .fm-cell:not(.fm-no-hairline)::after{content:'';position:absolute;background-color:#ddd;display:block;z-index:1;top:auto;right:auto;bottom:0;left:0;width:100%;height:1px;transform-origin:50% 100%}.fm-input-wrapper:not(:last-child) .fm-cell::after{left:16px!important}.fm-input-label-tips{display:flex;align-items:center;padding-left:4px}.fm-input-label-tips-content{font-size:14px;color:#333;line-height:20px;padding:6px 16px}.fm-tmpl-listview-timeline{margin-left:5px}.fm-tmpl-listview-timeline .fm-tmpl-timeline-text{position:relative;padding-left:22px;padding-bottom:2px;line-height:20px;font-size:14px;color:#666}.fm-tmpl-listview-timeline .fm-tmpl-timeline-text::after{position:absolute;left:-5px;top:5px;width:10px;height:10px;background-color:#ddd;border-radius:50%;content:''}.fm-tmpl-listview-timeline .fm-tmpl-timeline-text::before{position:absolute;left:0;top:0;bottom:0;width:1px;background-color:#ddd;content:''}.fm-tmpl-listview-timeline .fm-tmpl-timeline-date{padding-bottom:20px;padding-left:22px;font-size:12px;color:#999;border-left:1px solid #ddd}.fm-tmpl-listview-timeline.fm-tmpl-listview-timeline-first .fm-tmpl-timeline-text:before{top:5px}.fm-tmpl-listview-timeline.fm-tmpl-listview-timeline-last .fm-tmpl-timeline-text:before{height:5px}.fm-tmpl-listview-timeline.fm-tmpl-listview-timeline-last .fm-tmpl-timeline-date{border-color:transparent}.fm-tmpl-listview-goods{padding-left:16px;display:flex;padding-top:10px}.fm-tmpl-listview-goods .fm-tmpl-goods-img{flex-shrink:0;width:86px;height:86px;margin-right:10px;overflow:hidden}.fm-tmpl-listview-goods .fm-tmpl-goods-img img{display:block;width:86px;height:86px}.fm-tmpl-listview-goods .fm-tmpl-goods-content{flex-shrink:1;flex-grow:1;flex-basis:0;overflow:hidden;padding-right:16px;padding-bottom:10px;border-bottom:1px solid #ddd;position:relative}@media (-webkit-min-device-pixel-ratio:2),(min-resolution:2dppx){html:not([data-scale]) .fm-input-wrapper:not(:last-child) .fm-cell:not(.fm-no-hairline)::after{transform:scaleY(.5)}html:not([data-scale]) .fm-tmpl-listview-goods .fm-tmpl-goods-content{border-bottom:none}html:not([data-scale]) .fm-tmpl-listview-goods .fm-tmpl-goods-content::after{content:'';position:absolute;background-color:#ddd;display:block;z-index:1;top:auto;right:auto;bottom:0;left:0;width:100%;height:1PX;transform-origin:50% 100%;transform:scaleY(.5)}}.fm-tmpl-listview-goods .fm-tmpl-goods-content .fm-tmpl-goods-name{position:relative;min-height:40px;padding-right:28px;margin-bottom:4px;line-height:20px;font-size:16px;color:#666}.fm-tmpl-listview-goods .fm-tmpl-goods-content .fm-tmpl-goods-name .fm-tmpl-goods-add{position:absolute;right:0;top:30px;width:24px;height:24px;line-height:24px;text-align:center;background-color:#ececec;border-radius:50%}.fm-tmpl-listview-goods .fm-tmpl-goods-content .fm-tmpl-goods-name .fm-tmpl-goods-add .fm-icon{font-size:12px;color:#999}.fm-tmpl-listview-goods .fm-tmpl-goods-content .fm-tmpl-goods-price{display:flex;align-items:flex-end;line-height:22px;margin-bottom:3px;color:#fa6400}.fm-tmpl-listview-goods .fm-tmpl-goods-content .fm-tmpl-goods-price-prefix{font-size:12px}.fm-tmpl-listview-goods .fm-tmpl-goods-content .fm-tmpl-goods-price-text{font-size:16px}.fm-tmpl-listview-goods .fm-tmpl-goods-content .fm-tmpl-goods-shop{display:flex;align-items:center;line-height:16px;font-size:12px;color:#888}.fm-tmpl-listview-goods .fm-tmpl-goods-content .fm-tmpl-goods-shop .fm-icon{margin-right:3px;font-size:12px}.fm-tmpl-listview-order{padding-left:16px}.fm-tmpl-listview-order-inner{padding:12px 16px 12px 0;border-bottom:1px solid #ddd;position:relative}@media (-webkit-min-device-pixel-ratio:2),(min-resolution:2dppx){html:not([data-scale]) .fm-tmpl-listview-order-inner{border-bottom:none}html:not([data-scale]) .fm-tmpl-listview-order-inner::after{content:'';position:absolute;background-color:#ddd;display:block;z-index:1;top:auto;right:auto;bottom:0;left:0;width:100%;height:1PX;transform-origin:50% 100%;transform:scaleY(.5)}}.fm-tmpl-listview-order .fm-tmpl-listview-order-name{margin-bottom:3px;line-height:21px;font-size:15px;color:#333}.fm-tmpl-listview-order .order-line-item{display:flex;flex-direction:row;align-items:center}.fm-tmpl-listview-order .order-line-item-left{flex-shrink:1;flex-grow:1;flex-basis:0;overflow:hidden}.fm-tmpl-listview-order .order-line-item-right{flex-shrink:0}.fm-tmpl-listview-order .fm-tmpl-listview-order-number{line-height:20px;margin-bottom:10px}.fm-tmpl-listview-order .fm-tmpl-listview-order-number .order-number-text{font-size:14px;color:#888}.fm-tmpl-listview-order .fm-tmpl-listview-order-msg{line-height:18px;font-size:13px}.fm-tmpl-listview-order .fm-tmpl-listview-order-msg .order-msg-date{color:#888}.fm-tmpl-listview-order .fm-tmpl-listview-order-msg .order-msg-price{color:#ff7300}.fm-tmpl-listview-shop{padding:0 8px 10px;background:#f9fafb}.fm-tmpl-listview-shop-inner{background:#fff}.fm-tmpl-listview-shop-header{padding:10px 10px 18px;display:flex;flex-direction:row}.fm-tmpl-listview-shop-header .shop-header-img{flex-shrink:0;width:46px;height:46px;margin-right:10px}.fm-tmpl-listview-shop-header .shop-header-img img{display:block;width:100%;height:100%}.fm-tmpl-listview-shop-header .shop-header-msg{flex-shrink:1;flex-grow:1;flex-basis:0;overflow:hidden}.fm-tmpl-listview-shop-header .shop-header-msg .shop-header-name{display:flex;justify-content:space-between;margin-bottom:6px}.fm-tmpl-listview-shop-header .shop-header-msg .shop-header-name-text{padding-right:6px;line-height:22px;font-size:16px;color:#333}.fm-tmpl-listview-shop .shop-content-item,.fm-tmpl-listview-shop-header .shop-header-msg .shop-header-site{line-height:18px;font-size:13px;color:#999}.fm-tmpl-listview-shop-header .shop-header-msg .shop-header-name-status{flex-shrink:0}.fm-tmpl-listview-shop .shop-content-item{margin-bottom:8px;padding:0 10px}.fm-tmpl-listview-shop-footer{border-top:1px solid #ddd;position:relative}@media (-webkit-min-device-pixel-ratio:2),(min-resolution:2dppx){html:not([data-scale]) .fm-tmpl-listview-shop-footer{border-top:none}html:not([data-scale]) .fm-tmpl-listview-shop-footer::before{content:'';position:absolute;background-color:#ddd;display:block;z-index:1;top:0;right:auto;bottom:auto;left:0;width:100%;height:1PX;transform-origin:50% 50%;transform:scaleY(.5)}.fm-tmpl-listview-shop-footer .shop-footer-btns .shop-footer-btn-item::after{transform:scaleX(.5)}}.fm-tmpl-listview-shop-footer .shop-footer-btns{display:flex;flex-direction:row;align-items:center}.fm-tmpl-listview-shop-footer .shop-footer-btns .shop-footer-btn-item{position:relative;flex:1;height:44px;padding:0 6px;line-height:44px;font-size:12px;color:#999;text-align:center;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.fm-tmpl-listview-shop-footer .shop-footer-btns .shop-footer-btn-item .fm-icon{font-size:14px;margin-right:4px}.fm-tmpl-listview-shop-footer .shop-footer-btns .shop-footer-btn-item::after{position:absolute;right:0;top:50%;width:1px;height:22px;margin-top:-11px;background-color:#ddd;content:''}.fm-tmpl-listview-shop-footer .shop-footer-btns .shop-footer-btn-item:last-child::after{display:none}.fm-tmpl-listview-shop-first{padding-top:10px}.fm-tmpl-listview-menu{padding-bottom:10px;background:#f9fafb}.fm-tmpl-listview-menu-inner{padding:10px 16px 0;background-color:#fff}.fm-tmpl-listview-menu-text{margin-bottom:10px;line-height:20px;font-size:14px;color:#666}.fm-tmpl-listview-menu-content .menu-list{display:flex;align-items:center;flex-wrap:wrap}.fm-tmpl-listview-menu-content .menu-list-item{flex:0 0 25%;display:flex;flex-direction:column;align-items:center;margin-bottom:10px}.fm-tmpl-listview-menu-content .menu-list-item-icon{width:46px;height:46px;margin-bottom:6px;line-height:46px;text-align:center;color:#fff;border-radius:16px;background-color:#40a9ff}.fm-tmpl-listview-menu-content .menu-list-item-icon .fm-icon{font-size:26px}.fm-tmpl-listview-menu-content .menu-list-item-text{line-height:20px;font-size:14px;color:#666}.fm-tmpl-listview-menu-last{padding-bottom:0}.fm-tmpl-listview-menus.fm-listview-content{display:flex;align-items:center;flex-wrap:wrap}.fm-tmpl-listview-menus .fm-listview-item{flex:0 0 33.3333%}.fm-tmpl-listview-menus-item{display:flex;flex-direction:column;align-items:center;margin-bottom:16px}.fm-tmpl-listview-menus-item .menu-list-item-icon{width:46px;height:46px;margin-bottom:6px;line-height:46px;text-align:center;color:#fff;border-radius:16px;background-color:#40a9ff}.fm-tmpl-listview-menus-item .menu-list-item-icon .fm-icon{font-size:26px}.fm-tmpl-listview-menus-item .menu-list-item-text{line-height:20px;font-size:14px;color:#666}.fm-tmpl-listview-basic{display:flex;align-items:flex-start;padding:0 16px;margin-bottom:8px;font-size:14px;line-height:20px}.fm-tmpl-listview-basic .basic-lable{flex-shrink:0;width:82px;margin-right:14px;color:#999;text-align:right}.fm-tmpl-listview-basic .basic-text{flex-shrink:1;flex-grow:1;flex-basis:0;overflow:hidden;color:#333}.fm-tmpl-listview-basic-last{margin-bottom:0}.fm-tmpl-listview-list{padding-left:16px}.fm-tmpl-listview-list .fm-tmpl-listview-list-inner{display:flex;justify-content:space-between;height:44px;padding-right:16px;font-size:15px;color:#333;line-height:44px;border-bottom:1px solid #ddd;position:relative}@media (-webkit-min-device-pixel-ratio:2),(min-resolution:2dppx){html:not([data-scale]) .fm-tmpl-listview-list .fm-tmpl-listview-list-inner{border-bottom:none}html:not([data-scale]) .fm-tmpl-listview-list .fm-tmpl-listview-list-inner::after{content:'';position:absolute;background-color:#ddd;display:block;z-index:1;top:auto;right:auto;bottom:0;left:0;width:100%;height:1PX;transform-origin:50% 100%;transform:scaleY(.5)}}.fm-tmpl-listview-list .fm-tmpl-listview-list-inner .list-text{color:#FBB902}.fm-tmpl-listview-list-last .fm-tmpl-listview-list-inner{border-bottom:0}.fm-tmpl-listview-list-last .fm-tmpl-listview-list-inner::after{display:none!important}.fm-tmpl-listview-sign{padding:0 16px;background:#fff}.fm-tmpl-listview-sign .fm-tmpl-listview-sign-inner{margin-left:12px}.fm-tmpl-listview-sign .fm-tmpl-sign-text{position:relative;padding-left:18px}.fm-tmpl-listview-sign .fm-tmpl-sign-text .fm-tmpl-sign-circle{position:absolute;left:-8px;top:2px;width:18px;height:18px;border-radius:50%;background-color:rgba(54,165,246,.2)}.fm-tmpl-listview-sign .fm-tmpl-sign-text .text{line-height:22px;font-size:16px;color:#333;font-weight:600}.fm-tmpl-listview-sign .fm-tmpl-sign-text::after{position:absolute;left:-5px;top:5px;width:6px;height:6px;border:3px solid #fff;background-color:#36a5f6;border-radius:50%;content:'';box-sizing:content-box}.fm-tmpl-listview-sign .fm-tmpl-sign-text::before{position:absolute;left:-.5px;top:0;bottom:0;width:1px;border:1px dashed #ddd;background-color:transparent;content:'';transform:scaleX(.5)}.fm-tmpl-listview-sign .fm-tmpl-sign-content{padding:10px 0 10px 18px;border-left:1px dashed #ddd}.fm-tmpl-listview-sign .fm-tmpl-sign-content-inner{padding:10px 12px;background:#f4f7f9}.fm-tmpl-listview-sign .fm-tmpl-sign-content-name{display:flex;align-items:center;padding-bottom:6px;line-height:20px}.fm-tmpl-listview-sign .fm-tmpl-sign-content-name .fm-icon{margin-right:6px;font-size:16px;color:#36a5f6}.fm-tmpl-listview-sign .fm-tmpl-sign-content-name .name-text{font-size:15px;color:#333}.fm-tmpl-listview-sign .fm-tmpl-sign-content-label{padding-bottom:10px;font-size:14px;color:#999}.fm-tmpl-listview-sign .fm-tmpl-sign-content-imgs{display:flex;align-items:center;flex-wrap:wrap}.fm-tmpl-listview-sign .fm-tmpl-sign-content-imgs .fm-tmpl-sign-content-img{width:60px;height:60px;margin-right:10px;margin-bottom:10px;overflow:hidden}.fm-tmpl-listview-sign .fm-tmpl-sign-content-imgs .fm-tmpl-sign-content-img img{display:block;width:100%;height:100%;-o-object-fit:scale-down;object-fit:scale-down}.fm-tmpl-listview-sign.fm-tmpl-listview-sign-last{padding-bottom:12px}.fm-tmpl-listview-sign.fm-tmpl-listview-sign-last .fm-tmpl-sign-content{border-left:none}.fm-tmpl-listview-sign.fm-tmpl-listview-sign-last .fm-tmpl-sign-text::before{height:6px}.fm-tmpl-listview-sign.fm-tmpl-listview-sign-first{padding-top:12px}.fm-tmpl-listview-sign.fm-tmpl-listview-sign-first .fm-tmpl-sign-text::before{top:6px}.fm-tmpl-listview-bill{padding-left:12px}.fm-tmpl-listview-bill-content{display:flex}.fm-tmpl-listview-bill-content .bill-img-round-wrapper{padding-top:12px;margin-right:10px}.fm-tmpl-listview-bill-content .bill-img-round-wrapper .bill-img-round-img{width:30px;height:30px;border-radius:50%;text-align:center;color:#fff;background:#3a90ff}.fm-tmpl-listview-bill-content .bill-img-round-wrapper .bill-img-round-img .fm-icon{font-size:18px;line-height:30px}.fm-tmpl-listview-bill-content .bill-detail-content{flex-shrink:1;flex-grow:1;flex-basis:0;padding:12px 16px 8px 0;border-bottom:1px solid #ddd;position:relative}@media (-webkit-min-device-pixel-ratio:2),(min-resolution:2dppx){html:not([data-scale]) .fm-tmpl-listview-bill-content .bill-detail-content{border-bottom:none}html:not([data-scale]) .fm-tmpl-listview-bill-content .bill-detail-content::after{content:'';position:absolute;background-color:#ddd;display:block;z-index:1;top:auto;right:auto;bottom:0;left:0;width:100%;height:1PX;transform-origin:50% 100%;transform:scaleY(.5)}}.fm-tmpl-listview-bill-content .bill-detail-content .bill-detail-header{display:flex;align-items:center;justify-content:space-between;margin:0 0 6px}.fm-tmpl-listview-bill-content .bill-detail-content .bill-detail-header .title{line-height:22px;font-weight:400;font-size:16px;color:#333}.fm-tmpl-listview-bill-content .bill-detail-content .bill-detail-header .time{line-height:18px;color:#999;font-size:13px}.fm-tmpl-listview-bill-content .bill-detail-content .bill-detail-info{display:flex;margin-bottom:4px}.fm-tmpl-listview-bill-content .bill-detail-content .bill-detail-info-text{display:flex;flex-shrink:1;flex-grow:1;flex-basis:0;align-items:flex-start;line-height:18px;font-size:13px;color:#999}.fm-tmpl-listview-bill-content .bill-detail-content .bill-detail-info-text .title{flex-shrink:0}.fm-tmpl-listview-bill-content .bill-detail-content .bill-detail-info-text .text-orange{color:#FF9800}.fm-tmpl-listview-bill-content .bill-detail-content .bill-detail-info-status{padding-left:6px;margin-top:-2px}.fm-tmpl-listview-client{padding:0 8px 10px;background:#f9fafb}.fm-tmpl-listview-client-inner{background:#fff}.fm-tmpl-listview-client-header{padding:10px 10px 18px;display:flex;flex-direction:row}.fm-tmpl-listview-client-header .client-header-icon{flex-shrink:0;width:46px;height:46px;line-height:46px;margin-right:10px;text-align:center;background-color:#3a90ff;border-radius:6px}.fm-tmpl-listview-client-header .client-header-icon .fm-icon{font-size:24px;color:#fff}.fm-tmpl-listview-client-header .client-header-msg{flex-shrink:1;flex-grow:1;flex-basis:0;overflow:hidden}.fm-tmpl-listview-client-header .client-header-msg .client-header-name{display:flex;justify-content:space-between;margin-bottom:6px}.fm-tmpl-listview-client-header .client-header-msg .client-header-name-text{padding-right:6px;line-height:22px;font-size:16px;color:#333}.fm-tmpl-listview-client-header .client-header-msg .client-header-name-status{flex-shrink:0}.fm-tmpl-listview-client-header .client-header-msg .client-header-name-time{font-size:13px;color:#999}.fm-tmpl-listview-client-header .client-header-msg .client-header-site{line-height:18px;font-size:13px;color:#999}.fm-tmpl-listview-client-content .client-content-info{display:flex;align-items:center}.fm-tmpl-listview-client-content .text-orange{font-size:14px;color:#FF9800}.fm-tmpl-listview-client .client-content-item{display:flex;align-items:center;flex:1;margin-bottom:8px;padding:0 10px;line-height:18px;font-size:13px;color:#999}.fm-tmpl-listview-client .client-content-item .fm-icon{font-size:14px;margin-right:2px}.fm-tmpl-listview-client-first{padding-top:10px}.fm-tmpl-listview-client.fm-tmpl-listview-client-simple .fm-tmpl-listview-client-header{padding-bottom:10px}.fm-tmpl-listview-client.fm-tmpl-listview-client-simple .fm-tmpl-listview-client-header .client-header-msg .client-header-name{margin-bottom:0}.fm-tmpl-listview-client .text-success{color:#5CC171}.fm-tmpl-listview-client .text-warning{color:#FF9800}.fm-tmpl-listview-client .text-danger{color:#F24645}.fm-tmpl-listview-client .text-submit{color:#5AC1C3}.fm-tmpl-listview-client .text-info{color:#4D9AFF}.fm-tmpl-extend-card{padding:12px 16px}.fm-tmpl-extend-card-inner{position:relative;background-image:linear-gradient(152deg,#53bdfd 0,#287cf3 97%);box-shadow:0 2px 4px 0 rgba(57,66,100,.04);border-radius:10px;overflow:hidden}.fm-tmpl-extend-card-inner .fm-tmpl-extend-card-list{display:flex;justify-content:space-between;align-items:center;padding:20px}.fm-tmpl-extend-card-inner .fm-tmpl-extend-card-list .fm-tmpl-extend-card-item{display:flex;flex-direction:column;align-items:center;flex:1;color:#fff}.fm-tmpl-extend-card-inner .fm-tmpl-extend-card-list .fm-tmpl-extend-card-item .extend-card-item-text{display:flex;align-items:baseline}.fm-tmpl-extend-card-inner .fm-tmpl-extend-card-list .fm-tmpl-extend-card-item .extend-card-item-text .item-text{display:block;font-size:24px;line-height:32px}.fm-tmpl-extend-card-inner .fm-tmpl-extend-card-list .fm-tmpl-extend-card-item .extend-card-item-text .item-text-tip{font-size:12px}.fm-tmpl-extend-card-inner .fm-tmpl-extend-card-list .fm-tmpl-extend-card-item .extend-card-item-text .card-item-title{font-size:14px}.fm-tmpl-extend-card-inner::before{right:-7%;top:20%;width:80%;height:340%;border-radius:50%;opacity:.23;background-image:linear-gradient(180deg,#63ccfa 0,#36a5f6 100%);z-index:1}.fm-tmpl-extend-card-inner::after{right:-37%;bottom:-10%;width:60%;height:240%;border-radius:50%;opacity:.15;background-image:linear-gradient(134deg,#3addd5 0,#24c2d8 100%);z-index:0}.fm-tmpl-listview-liaison{padding-left:16px;margin-top:10px;background-color:#fff}.fm-tmpl-listview-liaison .liaison-header{display:flex;flex-direction:row;justify-content:space-between;padding:12px 16px 12px 0;border-bottom:1px solid #ddd;position:relative}@media (-webkit-min-device-pixel-ratio:2),(min-resolution:2dppx){html:not([data-scale]) .fm-tmpl-listview-liaison .liaison-header{border-bottom:none}html:not([data-scale]) .fm-tmpl-listview-liaison .liaison-header::after{content:'';position:absolute;background-color:#ddd;display:block;z-index:1;top:auto;right:auto;bottom:0;left:0;width:100%;height:1PX;transform-origin:50% 100%;transform:scaleY(.5)}}.fm-tmpl-listview-liaison .liaison-header-title{flex:1 1 0;padding-right:16px;font-size:16px;color:#333;overflow:hidden;white-space:nowrap;text-overflow:ellipsis}.fm-tmpl-listview-liaison .liaison-header-tag{flex-shrink:0}.fm-tmpl-listview-liaison .liaison-content{padding:10px 0}.fm-tmpl-listview-liaison .liaison-content-info{display:flex;flex-direction:row;align-items:center;line-height:18px;color:#999;font-size:13px;margin:0 0 6px}.fm-tmpl-listview-booklist .booklist-btns .fm-button,.fm-tmpl-listview-liaison .liaison-actions .fm-button{margin-left:13px}.fm-tmpl-listview-liaison .liaison-content-info-title{flex-shrink:0;width:100px;padding-right:10px}.fm-tmpl-listview-liaison .liaison-content-info-text{flex:1 1 0;color:#333}.fm-tmpl-listview-liaison .liaison-actions{padding:0 16px 10px;text-align:right}.fm-tmpl-listview-liaison .liaison-actions .fm-button:first-child{margin-left:0}.fm-tmpl-listview-approve{padding:10px 0 10px 16px;background-color:#fff}.fm-tmpl-listview-approve .fm-approve-flow-item{padding-left:7px}.fm-tmpl-listview-approve .fm-approve-flow-item-header{border-left:1px dashed #ddd;position:relative}@media (-webkit-min-device-pixel-ratio:2),(min-resolution:2dppx){html:not([data-scale]) .fm-tmpl-listview-approve .fm-approve-flow-item-header{border-left:none}html:not([data-scale]) .fm-tmpl-listview-approve .fm-approve-flow-item-header::before{content:'';position:absolute;background-color:#ddd;display:block;z-index:1;top:0;right:auto;bottom:auto;left:0;width:1PX;height:100%;transform-origin:100% 50%;transform:scaleX(.5)}}.fm-tmpl-listview-approve .fm-approve-flow-item-header-inner{position:relative;display:flex;flex-direction:row;align-items:center;padding-left:20px}.fm-tmpl-listview-approve .fm-approve-flow-item-header-inner .fm-approve-flow-item-header-icon{position:absolute;left:-7px;top:0;z-index:100;display:flex;align-items:center;justify-content:center;width:15px;height:15px;background-color:rgba(58,144,255,.4);border-radius:50%}.fm-tmpl-listview-approve .fm-approve-flow-item-header-inner .fm-approve-flow-item-header-icon-inner{width:7px;height:7px;background-color:#3a90ff;border-radius:50%}.fm-tmpl-listview-approve .fm-approve-flow-item-header-inner .fm-approve-flow-item-header-content{flex-shrink:1;flex-grow:1;flex-basis:0;line-height:21px;font-size:15px;color:#4c4c4c;font-weight:700}.fm-tmpl-listview-approve .fm-approve-flow-item-header-inner .fm-approve-flow-item-header-right{flex-shrink:0;padding-left:6px}.fm-tmpl-listview-approve .fm-approve-flow-item-header-inner .fm-approve-flow-item-header-right .fm-icon{color:#979797}.fm-tmpl-listview-approve .fm-approve-flow-item-content{padding:12px 0 30px 20px;border-left:1px dashed #d4d4d4;position:relative}@media (-webkit-min-device-pixel-ratio:2),(min-resolution:2dppx){html:not([data-scale]) .fm-tmpl-listview-approve .fm-approve-flow-item-content{border-left:none}html:not([data-scale]) .fm-tmpl-listview-approve .fm-approve-flow-item-content::before{content:'';position:absolute;background-color:#d4d4d4;display:block;z-index:1;top:0;right:auto;bottom:auto;left:0;width:1PX;height:100%;transform-origin:100% 50%;transform:scaleX(.5)}}.fm-tmpl-listview-approve .fm-approve-flow-item-content .fm-approve-flow-item-list{display:flex;flex-direction:row;align-items:flex-start;margin-bottom:14px}.fm-tmpl-listview-approve .fm-approve-flow-item-content .fm-approve-flow-item-list:last-child{margin-bottom:0}.fm-tmpl-listview-approve .fm-approve-flow-item-content .fm-approve-flow-item-list-avatar{position:relative;display:flex;flex-direction:row;align-items:center;width:36px;height:36px}.fm-tmpl-listview-approve .fm-approve-flow-item-content .fm-approve-flow-item-list-avatar-img{display:block;width:36px;height:36px;border-radius:50%}.fm-tmpl-listview-approve .fm-approve-flow-item-content .fm-approve-flow-item-list-content{flex:1 1 0;margin-left:10px}.fm-tmpl-listview-approve .fm-approve-flow-item-content .fm-approve-flow-item-list-content .item-list-content-main{display:flex;align-items:center;justify-content:space-between;height:36px}.fm-tmpl-listview-approve .fm-approve-flow-item-last .fm-approve-flow-item-content::before,.fm-tmpl-listview-approve .fm-approve-flow-item-last .fm-approve-flow-item-header::before{display:none!important}.fm-tmpl-listview-approve .fm-approve-flow-item-content .fm-approve-flow-item-list-content .item-list-content-left,.fm-tmpl-listview-approve .fm-approve-flow-item-content .fm-approve-flow-item-list-content .item-list-content-left .item-list-content-name{font-size:14px;color:#666}.fm-tmpl-listview-approve .fm-approve-flow-item-content .fm-approve-flow-item-list-content .item-list-content-left .item-list-content-status{margin-left:8px;color:#3a90ff}.fm-tmpl-listview-approve .fm-approve-flow-item-content .fm-approve-flow-item-list-content .item-list-content-left .item-list-content-status-success{color:#5cc171}.fm-tmpl-listview-approve .fm-approve-flow-item-content .fm-approve-flow-item-list-content .item-list-content-left .item-list-content-status-apply{color:#3a90ff}.fm-tmpl-listview-approve .fm-approve-flow-item-content .fm-approve-flow-item-list-content .item-list-content-left .item-list-content-status-running{color:#ff9800}.fm-tmpl-listview-approve .fm-approve-flow-item-content .fm-approve-flow-item-list-content .item-list-content-date{flex-shrink:0;font-size:13px;color:#999}.fm-tmpl-listview-approve .fm-approve-flow-item-content .fm-approve-flow-item-list-content .item-list-content-message{line-height:20px;font-size:14px;color:#333}.fm-tmpl-listview-approve .fm-approve-flow-item-content .fm-approve-flow-item-date{font-size:13px;color:rgba(51,51,51,.65)}.fm-tmpl-listview-approve .fm-approve-flow-item-running .fm-approve-flow-item .fm-approve-flow-item-header-inner .fm-approve-flow-item-header-icon{background-color:rgba(255,152,0,.4)}.fm-tmpl-listview-approve .fm-approve-flow-item-running .fm-approve-flow-item .fm-approve-flow-item-header-inner .fm-approve-flow-item-header-icon .fm-approve-flow-item-header-icon-inner{background-color:#ff9800}.fm-tmpl-listview-approve .fm-approve-flow-item-last .fm-approve-flow-item-header{border-left:0}.fm-tmpl-listview-approve .fm-approve-flow-item-last .fm-approve-flow-item-content{padding-bottom:12px;border-left:0}.fm-tmpl-listview-product-header{padding:12px 14px;line-height:20px;font-size:14px;color:#3a90ff}.fm-tmpl-listview-product-item .fm-listview-item .fm-listview-item-content{transform:none}.fm-tmpl-listview-product{padding:12px 16px 0}.fm-tmpl-listview-product .fm-tmpl-listview-product-inner{padding-bottom:12px;border-bottom:1px solid #ddd;position:relative}@media (-webkit-min-device-pixel-ratio:2),(min-resolution:2dppx){html:not([data-scale]) .fm-tmpl-listview-product .fm-tmpl-listview-product-inner{border-bottom:none}html:not([data-scale]) .fm-tmpl-listview-product .fm-tmpl-listview-product-inner::after{content:'';position:absolute;background-color:#ddd;display:block;z-index:1;top:auto;right:auto;bottom:0;left:0;width:100%;height:1PX;transform-origin:50% 100%;transform:scaleY(.5)}}.fm-tmpl-listview-product .tmpl-product-title{display:flex;align-items:center;justify-content:space-between;margin-bottom:12px}.fm-tmpl-listview-product .tmpl-product-title .tmpl-product-title-collect{flex-shrink:0}.fm-tmpl-listview-product .tmpl-product-title-text{font-size:17px;color:#333}.fm-tmpl-listview-product .tmpl-product-title-collect{flex-shrink:0;font-size:14px;color:#666}.fm-tmpl-listview-product .tmpl-product-title-collect .collect-text{margin-left:4px}.fm-tmpl-listview-product .tmpl-product-title-collect.tmpl-product-title-collected .fm-icon{color:#ff9800}.fm-tmpl-listview-product .tmpl-product-content{position:relative;padding-right:40px}.fm-tmpl-listview-product .tmpl-product-content-item{display:flex;align-items:center;margin-bottom:10px;font-size:14px;color:#666}.fm-tmpl-listview-product .tmpl-product-content .tmpl-product-add-btn{position:absolute;right:0;bottom:0}.fm-tmpl-listview-product .tmpl-product-content .tmpl-product-add-btn .fm-button-add{width:30px;height:30px}.fm-tmpl-listview-product .tmpl-product-content .tmpl-product-add-btn .fm-button-add .fm-icon{font-size:14px}.fm-tmpl-listview-product .tmpl-product-footer{display:flex;align-items:center;justify-content:space-between;margin-top:6px}.fm-tmpl-listview-product .tmpl-product-footer .tmpl-product-price{margin-right:10px;font-size:17px;color:red;font-weight:600}.fm-tmpl-listview-product .tmpl-product-footer .fm-popover .fm-popover-inner{border-radius:10px;box-shadow:none}.fm-tmpl-listview-product .tmpl-product-footer .fm-popover .fm-popover-arrow,.fm-tmpl-listview-product .tmpl-product-footer .fm-popover .fm-popover-inner{border:1px solid #ddd}.fm-tmpl-listview-product .tmpl-product-footer .fm-popover .fm-popover-inner-wrapper{padding:0}.fm-tmpl-listview-product .tmpl-product-footer .fm-popover .fm-popover-inner-wrapper .fm-popover-item{min-width:50px;height:46px;line-height:46px;text-align:center;font-size:16px;color:#666}.fm-tmpl-listview-product .tmpl-product-footer .fm-overlay{background:0 0}.fm-tmpl-listview-product .tmpl-product-footer .tmpl-product-unit{padding:3px 6px;border-radius:6px;background-color:rgba(58,144,255,.2);font-size:14px;color:#333}.fm-tmpl-listview-product .tmpl-product-footer .tmpl-product-unit-text{margin-right:4px}.fm-tmpl-listview-product .tmpl-product-footer .tmpl-product-unit .fm-icon{font-size:12px;color:#666}.fm-tmpl-listview-product .tmpl-product-footer .tmpl-product-footer-right{flex-shrink:0;font-size:12px;color:#666}.fm-tmpl-listview-product.fm-tmpl-listview-product-first{padding-top:0}.fm-card-tmpl-booklist-header{padding:11px 16px;line-height:22px;font-size:16px;color:#333;font-weight:600}.fm-tmpl-listview-booklist{padding:0 16px;color:#333;border-bottom:1px solid #ddd;position:relative}@media (-webkit-min-device-pixel-ratio:2),(min-resolution:2dppx){html:not([data-scale]) .fm-tmpl-listview-booklist{border-bottom:none}html:not([data-scale]) .fm-tmpl-listview-booklist::after{content:'';position:absolute;background-color:#ddd;display:block;z-index:1;top:auto;right:auto;bottom:0;left:0;width:100%;height:1PX;transform-origin:50% 100%;transform:scaleY(.5)}}.fm-tmpl-listview-booklist-last{border-bottom:0}.fm-tmpl-listview-booklist-last::after{display:none!important}.fm-tmpl-listview-booklist .booklist-header{display:flex;flex-direction:row;align-items:flex-start;justify-content:space-between;padding:12px 0 6px;line-height:22px;font-size:16px}.fm-tmpl-listview-booklist .booklist-header-price{flex-shrink:0;color:#fa6400}.fm-tmpl-listview-booklist .booklist-main{padding-bottom:8px}.fm-tmpl-listview-booklist .booklist-main-item{line-height:18px;padding-bottom:4px;font-size:13px;color:#999}.fm-tmpl-listview-booklist .booklist-btns{padding:8px 0 6px;text-align:right}.fm-tmpl-dialog-plan,.fm-tmpl-dialog-type{border-radius:5px!important}.fm-tmpl-dialog-plan .fm-dialog-footer,.fm-tmpl-dialog-type .fm-dialog-footer{border-top:1px solid #ddd;position:relative}@media (-webkit-min-device-pixel-ratio:2),(min-resolution:2dppx){html:not([data-scale]) .fm-tmpl-dialog-plan .fm-dialog-footer,html:not([data-scale]) .fm-tmpl-dialog-type .fm-dialog-footer{border-top:none}html:not([data-scale]) .fm-tmpl-dialog-plan .fm-dialog-footer::before,html:not([data-scale]) .fm-tmpl-dialog-type .fm-dialog-footer::before{content:'';position:absolute;background-color:#ddd;display:block;z-index:1;top:0;right:auto;bottom:auto;left:0;width:100%;height:1PX;transform-origin:50% 50%;transform:scaleY(.5)}}.fm-tmpl-dialog-plan .fm-dialog-footer .fm-button,.fm-tmpl-dialog-type .fm-dialog-footer .fm-button{font-size:14px;color:#666}.fm-tmpl-dialog-type-content{padding:20px}.fm-tmpl-dialog-type-content .fm-dialog-type-list{display:flex;align-items:center;justify-content:center}.fm-tmpl-dialog-type-content .fm-dialog-type-list-item{flex:1}.fm-tmpl-dialog-type-content .fm-dialog-type-list-item .type-list-item-icon{width:60px;height:60px;margin:0 auto;line-height:60px;text-align:center;border:1px solid #3D91FF;border-radius:50%}@media (-webkit-min-device-pixel-ratio:2),(min-resolution:2dppx){html:not([data-scale]) .fm-tmpl-dialog-type-content .fm-dialog-type-list-item .type-list-item-icon{position:relative;border:none}html:not([data-scale]) .fm-tmpl-dialog-type-content .fm-dialog-type-list-item .type-list-item-icon::before{content:'';position:absolute;left:0;top:0;width:200%;height:200%;border:1px solid #3D91FF;border-radius:100%;transform-origin:0 0;transform:scale(.5);box-sizing:border-box;pointer-events:none}}.fm-tmpl-dialog-type-content .fm-dialog-type-list-item .type-list-item-icon .fm-icon{font-size:26px;color:#3D91FF}.fm-tmpl-dialog-type-content .fm-dialog-type-list-item .type-list-item-text{margin-top:12px;font-size:16px;text-align:center;color:#666}.fm-tmpl-dialog-type-content .fm-dialog-type-list-item:active .type-list-item-icon{background-color:#3D91FF}.fm-tmpl-dialog-type-content .fm-dialog-type-list-item:active .type-list-item-icon .fm-icon{color:#fff}.fm-tmpl-dialog-plan-content{padding:20px 30px}.fm-tmpl-dialog-plan-content .fm-dialog-plan-item{display:flex;justify-content:center;height:40px;line-height:40px;margin-bottom:16px;align-items:center;color:#666;border:1px solid #ddd;border-radius:4px}@media (-webkit-min-device-pixel-ratio:2),(min-resolution:2dppx){html:not([data-scale]) .fm-tmpl-dialog-plan-content .fm-dialog-plan-item{position:relative;border:none}html:not([data-scale]) .fm-tmpl-dialog-plan-content .fm-dialog-plan-item::before{content:'';position:absolute;left:0;top:0;width:200%;height:200%;border:1px solid #ddd;border-radius:8px;transform-origin:0 0;transform:scale(.5);box-sizing:border-box;pointer-events:none}}.fm-tmpl-dialog-plan-content .fm-dialog-plan-item .plan-item-icon{margin-right:14px}.fm-tmpl-dialog-plan-content .fm-dialog-plan-item .fm-icon{color:#666}.fm-tmpl-dialog-plan-content .fm-dialog-plan-item:active,.fm-tmpl-dialog-plan-content .fm-dialog-plan-item:active .fm-icon{color:#3D91FF}.fm-tmpl-dialog-plan-content .fm-dialog-plan-item:active::before{border-color:#3D91FF!important}.fm-title{position:relative;padding-left:16px}.fm-title::before{position:absolute;left:0;top:50%;width:5px;height:16px;margin:-8px 0 0}.fm-title-text{font-size:16px;line-height:21px;color:#333}.fm-tmpl-search-action{position:relative}.fm-tmpl-search-action .fm-icon{font-size:20px;color:#666}.fm-tmpl-search-action-badge{position:absolute;top:0;right:0;min-width:16px;padding:0 3px;margin-top:4px;color:#fff;font-weight:500;font-size:12px;line-height:14px;text-align:center;background-color:#ee0a24;border:1px solid #fff;border-radius:16px;transform:translate(50%,-50%);transform-origin:100%}.fm-list-view-swipe-toolbar{display:flex;align-items:center;justify-content:center;padding:0 12px;height:100%;background-color:#f24645;font-size:16px;color:#fff}.fm-static-text-common{padding:12px 16px;background-color:#fff;margin-bottom:10px;font-size:13px;line-height:1.42;-moz-tab-size:4;-o-tab-size:4;tab-size:4;text-align:left;white-space:pre-wrap;word-wrap:break-word}.fm-static-text-common p:not(:last-child){padding-bottom:18px}.fm-tmpl-listview-common{font-size:16px;color:#333;padding:12px 16px 12px 0;margin-left:16px;border-bottom:1px solid #ddd;position:relative}.fm-tmpl-listview-common .fm-tmpl-row{display:flex;justify-content:space-between}.fm-tmpl-listview-common .fm-tmpl-row:not(:last-child){padding-bottom:8px}.fm-tmpl-listview-common .fm-tmpl-col{display:flex;align-items:center}.fm-tmpl-listview-common .fm-tmpl-title{line-height:22px}.fm-tmpl-listview-common .fm-tmpl-price{font-size:18px;color:#fa6400}.fm-tmpl-listview-common .fm-tmpl-label{font-size:14px;line-height:20px;display:flex;overflow:hidden}.fm-tmpl-listview-common .fm-tmpl-label .fm-tmpl-label-title{color:#999;width:92px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.fm-tmpl-listview-common .fm-tmpl-label .fm-tmpl-label-text{flex:1;overflow:hidden;text-overflow:ellipsis}.fm-tmpl-listview-common .fm-tmpl-col-1{flex:1;overflow:hidden}.fm-tmpl-listview-common .fm-tmpl-col-1:not(:last-child){padding-right:10px}@media (-webkit-min-device-pixel-ratio:2),(min-resolution:2dppx){html:not([data-scale]) .fm-tmpl-listview-common{border-bottom:none}html:not([data-scale]) .fm-tmpl-listview-common::after{content:'';position:absolute;background-color:#ddd;display:block;z-index:1;top:auto;right:auto;bottom:0;left:0;width:100%;height:1PX;transform-origin:50% 100%;transform:scaleY(.5)}}.fm-tmpl-listview-cell .fm-tmpl-row:not(:last-child){padding-bottom:3px}.fm-tmpl-listview-cell .fm-tmpl-label{font-size:13px;line-height:18px;color:#999}.fm-tmpl-listview-cell .fm-tmpl-label .fm-tmpl-label-title{width:auto} \ No newline at end of file diff --git a/packages/mobile-ui-vue/public/vite.svg b/packages/mobile-ui-vue/public/vite.svg new file mode 100644 index 0000000000000000000000000000000000000000..e7b8dfb1b2a60bd50538bec9f876511b9cac21e3 --- /dev/null +++ b/packages/mobile-ui-vue/public/vite.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/mobile-ui-vue/src/app.vue b/packages/mobile-ui-vue/src/app.vue new file mode 100644 index 0000000000000000000000000000000000000000..2a024f821f3ec301588db27f56d68d4664496b85 --- /dev/null +++ b/packages/mobile-ui-vue/src/app.vue @@ -0,0 +1,160 @@ + + + + + diff --git a/packages/mobile-ui-vue/src/assets/vue.svg b/packages/mobile-ui-vue/src/assets/vue.svg new file mode 100644 index 0000000000000000000000000000000000000000..770e9d333ee70e75fe7c0bad7fb13e4f6ed4627a --- /dev/null +++ b/packages/mobile-ui-vue/src/assets/vue.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/packages/mobile-ui-vue/src/main.ts b/packages/mobile-ui-vue/src/main.ts new file mode 100644 index 0000000000000000000000000000000000000000..2fdabf742373ddaa8cc54946a76bc7fa7c3e0d6a --- /dev/null +++ b/packages/mobile-ui-vue/src/main.ts @@ -0,0 +1,9 @@ +import { createApp } from 'vue'; +import './style.css'; +import '../components/theme/index.scss'; +import App from './app.vue'; +import router from './router'; +import FarrisMobile from '../components'; + +const app = createApp(App); +app.use(router).use(FarrisMobile).mount('#app'); diff --git a/packages/mobile-ui-vue/src/menu-data.ts b/packages/mobile-ui-vue/src/menu-data.ts new file mode 100644 index 0000000000000000000000000000000000000000..2c317a5a935cb1f79963023d7f7f7134d802519b --- /dev/null +++ b/packages/mobile-ui-vue/src/menu-data.ts @@ -0,0 +1,54 @@ +export default { + views: [ + { + title: '表单组件', + subMenu: [ + { + title: '文件上传', + name: 'adv-uploader', + url: '/demos/adv-uploader', + component: '/adv-uploader' + } + ] + }, + { + title: '基础组件', + subMenu: [ + { + title: '弹出层', + name: 'popup', + url: '/demos/popup', + component: '/popup' + } + ] + }, + { + title: '反馈组件', + subMenu: [ + { + title: '动作面板', + name: 'actionsheet', + url: '/demos/actionsheet', + component: '/actionsheet' + } + ] + }, + { + title: '展示组件', + subMenu: [ + { + title: '导航栏', + name: 'navbar', + url: '/demos/navbar', + component: '/navbar' + }, + { + title: 'Listview', + name: 'listview', + url: '/demos/listview', + component: '/listview' + } + ] + } + ] +}; diff --git a/packages/mobile-ui-vue/src/router/index.ts b/packages/mobile-ui-vue/src/router/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..6a31592f1838717b308377a2c858c7721138039a --- /dev/null +++ b/packages/mobile-ui-vue/src/router/index.ts @@ -0,0 +1,38 @@ +import { createRouter, createWebHashHistory, RouteRecordRaw } from 'vue-router'; +import menuData from '../menu-data'; + +// @ts-ignore +const modules = import.meta.glob([`../../demos/**/index.vue`, `../../demos/index.vue`]); + +const allDemos: RouteRecordRaw[] = []; +menuData.views.forEach(view => { + if (!view.subMenu) { + return; + } + view.subMenu.forEach((menuItem) => { + allDemos.push({ + name: menuItem.name, + path: menuItem.name, + component: modules[`../../demos/${menuItem.name}/index.vue`] + }); + }); +}); + +const routes: RouteRecordRaw[] = [{ + name: 'home', + path: '/home', + component: modules["../../demos/home/index.vue"] +}, { + name: 'demos', + path: '/demos', + component: modules["../../demos/index.vue"], + children: allDemos +}, { + path: '/', + redirect: '/home' +}]; + +export default createRouter({ + history: createWebHashHistory(), + routes, +}); diff --git a/packages/mobile-ui-vue/src/style.css b/packages/mobile-ui-vue/src/style.css new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/packages/mobile-ui-vue/src/vite-env.d.ts b/packages/mobile-ui-vue/src/vite-env.d.ts new file mode 100644 index 0000000000000000000000000000000000000000..f23102e81edeb05f97228eb3d77c60728259b077 --- /dev/null +++ b/packages/mobile-ui-vue/src/vite-env.d.ts @@ -0,0 +1,9 @@ +/* eslint-disable @typescript-eslint/ban-types */ +// + +declare module '*.vue' { + import type { DefineComponent } from 'vue'; + + const component: DefineComponent<{}, {}, any>; + export default component; +} diff --git a/packages/mobile-ui-vue/tsconfig.json b/packages/mobile-ui-vue/tsconfig.json new file mode 100644 index 0000000000000000000000000000000000000000..204b057fd5033ed19ddfc0a55c659519d02881cb --- /dev/null +++ b/packages/mobile-ui-vue/tsconfig.json @@ -0,0 +1,36 @@ +{ + "compilerOptions": { + "target": "ESNext", + "useDefineForClassFields": true, + "module": "ESNext", + "lib": ["ESNext", "DOM", "dom.iterable", "scripthost"], + "skipLibCheck": true, + "importHelpers": true, + "sourceMap": true, + "esModuleInterop": true, + "experimentalDecorators": true, + "allowSyntheticDefaultImports": true, + "forceConsistentCasingInFileNames": true, + + /* Bundler mode */ + "moduleResolution": "Node", + "allowImportingTsExtensions": true, + "resolveJsonModule": true, + "isolatedModules": true, + "noEmit": true, + "jsx": "preserve", + + /* Linting */ + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noFallthroughCasesInSwitch": true, + "types": ["vitest/globals"], + "baseUrl": "./", + "paths": { + "@/*": ["components/*"] + } + }, + "include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.vue", "components/**/*.ts", "components/**/*.tsx", "components/**/*.vue", "demos/**/*.ts", "demos/**/*.tsx", "demos/**/*.vue",], + "references": [{ "path": "./tsconfig.node.json" }] +} diff --git a/packages/mobile-ui-vue/tsconfig.node.json b/packages/mobile-ui-vue/tsconfig.node.json new file mode 100644 index 0000000000000000000000000000000000000000..08015cbb6fd05bf0b08a33573cec40f42ec2bda1 --- /dev/null +++ b/packages/mobile-ui-vue/tsconfig.node.json @@ -0,0 +1,12 @@ +{ + "compilerOptions": { + "strict": true, + "composite": true, + "skipLibCheck": true, + "module": "ESNext", + "moduleResolution": "Node", + "allowSyntheticDefaultImports": true, + "forceConsistentCasingInFileNames": true + }, + "include": ["vite.config.ts"] +} diff --git a/packages/mobile-ui-vue/upload-mock.js b/packages/mobile-ui-vue/upload-mock.js new file mode 100644 index 0000000000000000000000000000000000000000..927089115675430cc78fdf19110fde129901c862 --- /dev/null +++ b/packages/mobile-ui-vue/upload-mock.js @@ -0,0 +1,26 @@ +self.addEventListener('fetch', (event) => { + if (event.request.url.endsWith('/mock/upload')) { + + event.respondWith( + (async () => { + await new Promise((resolve) => { + setTimeout(() => { + resolve(); + }, 4000); + }); + return new Response(JSON.stringify({ + success: true + }), { + headers: { + 'Content-type': 'application/json' + } + }); + })() + ); + + } else { + event.respondWith(caches.match(event.request).then((response) => { + return response || fetch(event.request); + })); + } +}); diff --git a/packages/mobile-ui-vue/vite.config.ts b/packages/mobile-ui-vue/vite.config.ts new file mode 100644 index 0000000000000000000000000000000000000000..d3d5a441c7760768c5fe5b2d9de9c33826eaef2b --- /dev/null +++ b/packages/mobile-ui-vue/vite.config.ts @@ -0,0 +1,12 @@ +import { defineConfig } from 'vite'; +import { resolve } from 'path'; +import vue from '@vitejs/plugin-vue'; +import vueJsx from '@vitejs/plugin-vue-jsx'; + +// https://vitejs.dev/config/ +export default defineConfig({ + plugins: [vue(), vueJsx()], + resolve: { + alias: [{ find: '@', replacement: resolve(__dirname, 'components') }] + } +}); diff --git a/yarn.lock b/yarn.lock index 04582edc6753cb53ebceb708bf3c4019cb8940d6..1245c08700692a9d91165061ca0953df4db03adb 100644 --- a/yarn.lock +++ b/yarn.lock @@ -5047,6 +5047,11 @@ dependencies: commander "*" +"@types/crypto-js@^4.2.2": + version "4.2.2" + resolved "https://registry.npmmirror.com/@types/crypto-js/-/crypto-js-4.2.2.tgz#771c4a768d94eb5922cc202a3009558204df0cea" + integrity sha512-sDOLlVbHhXpAUAL0YHDUUwDZf3iN4Bwi4W6a0W0b+QcAezUbRtH4FVb+9J4h+XFPW7l/gQ9F8qC7P+Ec4k8QVQ== + "@types/echarts@^4.1.11": version "4.9.16" resolved "https://registry.yarnpkg.com/@types/echarts/-/echarts-4.9.16.tgz#7156aea4623f3543b083200f6c65e04d3693bcc8" @@ -5312,6 +5317,11 @@ resolved "https://registry.yarnpkg.com/@types/unist/-/unist-2.0.6.tgz#250a7b16c3b91f672a24552ec64678eeb1d3a08d" integrity sha512-PBjIUxZHOuj0R15/xuwJYjFi+KZdNFrehocChv4g5hu6aFroHue8m0lBP0POdK2nKzbw0cgV1mws8+V/JAcEkQ== +"@types/urlencode@^1.1.4": + version "1.1.4" + resolved "https://registry.npmmirror.com/@types/urlencode/-/urlencode-1.1.4.tgz#44097bdb08014d4c16eb98919e8cbd3d95ceff67" + integrity sha512-eBIJ1j50IlTOCd9Xq7Jd4XTinD0LRZkJfEbx8RXCRuVkOwWTenfEWquT5XlOXfpjFw3dP1U7vxxXExlU8R/rWA== + "@types/vfile-message@*": version "2.0.0" resolved "https://registry.yarnpkg.com/@types/vfile-message/-/vfile-message-2.0.0.tgz#690e46af0fdfc1f9faae00cd049cc888957927d5" @@ -5744,6 +5754,11 @@ resolved "https://registry.yarnpkg.com/@vue/devtools-api/-/devtools-api-6.5.0.tgz#98b99425edee70b4c992692628fa1ea2c1e57d07" integrity sha512-o9KfBeaBmCKl10usN4crU53fYtC1r7jJwdGKjPT24t348rHxgfpZ0xL3Xm/gLUYnc0oTp8LAmrxOeLyu6tbk2Q== +"@vue/devtools-api@^6.5.1": + version "6.6.1" + resolved "https://registry.npmmirror.com/@vue/devtools-api/-/devtools-api-6.6.1.tgz#7c14346383751d9f6ad4bea0963245b30220ef83" + integrity sha512-LgPscpE3Vs0x96PzSSB4IGVSZXZBZHpfxs+ZA1d+VEPwHdOXowy/Y2CsvCAIFrf+ssVU1pD1jidj505EpUnfbA== + "@vue/reactivity-transform@3.2.47": version "3.2.47" resolved "https://registry.yarnpkg.com/@vue/reactivity-transform/-/reactivity-transform-3.2.47.tgz#e45df4d06370f8abf29081a16afd25cffba6d84e" @@ -6163,11 +6178,6 @@ dependencies: argparse "^2.0.1" -D@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/D/-/D-1.0.0.tgz#c348a4e034f72847be51206fc530fc089e9cc2a9" - integrity sha512-nQvrCBu7K2pSSEtIM0EEF03FVjcczCXInMt3moLNFbjlWx6bZrX72uT6/1uAXDbnzGUAx9gTyDiQ+vrFi663oA== - JSONStream@^1.0.4, JSONStream@^1.3.4: version "1.3.5" resolved "https://registry.yarnpkg.com/JSONStream/-/JSONStream-1.3.5.tgz#3208c1f08d3a4d99261ab64f92302bc15e111ca0" @@ -6975,11 +6985,6 @@ aws4@^1.8.0: resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.12.0.tgz#ce1c9d143389679e253b314241ea9aa5cec980d3" integrity sha512-NmWvPnx0F1SfrQbYwOi7OeaNGokp9XhzNioJ/CSBs8Qa4vxug81mhJEAVZwxXuBmYB5KDRfMq/F3RR0BIU7sWg== -axios-jsonp@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/axios-jsonp/-/axios-jsonp-1.0.4.tgz#28878a48bbf38dbf07875fa283d9cf958c63b498" - integrity sha512-KI5Fc4ery6DR+oneXG09hPZfGuNUW8Lblhe750h53Z0Eh5MRsrHn49YitDU4RsMk0HV+12zcvL2Q51QkOLGdIQ== - axios@^1.0.0: version "1.3.4" resolved "https://registry.yarnpkg.com/axios/-/axios-1.3.4.tgz#f5760cefd9cfb51fd2481acf88c05f67c4523024" @@ -9287,6 +9292,11 @@ crypto-browserify@^3.11.0: randombytes "^2.0.0" randomfill "^1.0.3" +crypto-js@^4.2.0: + version "4.2.0" + resolved "https://registry.npmmirror.com/crypto-js/-/crypto-js-4.2.0.tgz#4d931639ecdfd12ff80e8186dba6af2c2e856631" + integrity sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q== + crypto-random-string@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/crypto-random-string/-/crypto-random-string-1.0.0.tgz#a230f64f568310e1498009940790ec99545bca7e" @@ -9500,6 +9510,11 @@ dateformat@^3.0.0: resolved "https://registry.yarnpkg.com/dateformat/-/dateformat-3.0.3.tgz#a6e37499a4d9a9cf85ef5872044d62901c9889ae" integrity sha512-jyCETtSl3VMZMWeRo7iY1FL19ges1t55hMo5yaam4Jrsm5EPL89UQkoQRyiI+Yf4k8r2ZpdngkV8hr1lIdjb3Q== +dayjs@~1.11.10: + version "1.11.10" + resolved "https://registry.npmmirror.com/dayjs/-/dayjs-1.11.10.tgz#68acea85317a6e164457d6d6947564029a6a16a0" + integrity sha512-vjAczensTgRcqDERK0SR2XMwsF/tSvnvlv6VcF2GIhg6Sx4yOIt/irsr1RDJsKiIyBzJDpCoXiWWq28MqH2cnQ== + de-indent@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/de-indent/-/de-indent-1.0.2.tgz#b2038e846dc33baa5796128d0804b455b8c1e21d" @@ -13175,7 +13190,7 @@ iconv-lite@0.4.24, iconv-lite@^0.4.24: dependencies: safer-buffer ">= 2.1.2 < 3" -iconv-lite@0.6.3, iconv-lite@^0.6.2, iconv-lite@^0.6.3: +iconv-lite@0.6.3, iconv-lite@^0.6.2, iconv-lite@^0.6.3, 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== @@ -22521,6 +22536,13 @@ url@^0.11.0: punycode "^1.4.1" qs "^6.11.2" +urlencode@^2.0.0: + version "2.0.0" + resolved "https://registry.npmmirror.com/urlencode/-/urlencode-2.0.0.tgz#dd0c884d5cfb08adc76607ca3b9431165468695f" + integrity sha512-K4+koEq4II9FqKKdLyMwfVFiWvTLJsdsIihXCprumjlOwpviO44E4hAhLYBLb6CEVTZh9hXXMTQHIT+Hwv5BPw== + dependencies: + iconv-lite "~0.6.3" + use@^3.1.0: version "3.1.1" resolved "https://registry.yarnpkg.com/use/-/use-3.1.1.tgz#d50c8cac79a19fbc20f2911f56eb973f4e10070f" @@ -23081,6 +23103,13 @@ vue-eslint-parser@^9.0.1: lodash "^4.17.21" semver "^7.3.6" +vue-router@^4.3.0: + version "4.3.2" + resolved "https://registry.npmmirror.com/vue-router/-/vue-router-4.3.2.tgz#08096c7765dacc6832f58e35f7a081a8b34116a7" + integrity sha512-hKQJ1vDAZ5LVkKEnHhmm1f9pMiWIBNGF5AwU67PdH7TyXCj/a4hTccuUuYCAMgJK6rO/NVYtQIEN3yL8CECa7Q== + dependencies: + "@vue/devtools-api" "^6.5.1" + vue-template-compiler@^2.7.14: version "2.7.14" resolved "https://registry.yarnpkg.com/vue-template-compiler/-/vue-template-compiler-2.7.14.tgz#4545b7dfb88090744c1577ae5ac3f964e61634b1"