├── .gitignore ├── .jshintrc ├── .travis.yml ├── Gruntfile.js ├── LICENSE ├── README.md ├── TODO.md ├── bower.json ├── client ├── app │ ├── _temp │ │ ├── index.jade │ │ ├── styles │ │ │ ├── delivery │ │ │ │ ├── main.less │ │ │ │ └── mobile.less │ │ │ ├── role │ │ │ │ └── main.less │ │ │ └── stock │ │ │ │ └── main.less │ │ └── temapltes │ │ │ ├── delivery.jade │ │ │ ├── role.jade │ │ │ └── user.jade │ ├── docs │ │ ├── index.jade │ │ ├── scripts │ │ │ ├── app.js │ │ │ ├── charts.js │ │ │ ├── chat.js │ │ │ ├── header.js │ │ │ └── nav.js │ │ ├── styles │ │ │ ├── bootstrap.less │ │ │ ├── components │ │ │ │ └── example.less │ │ │ └── modules │ │ │ │ ├── admin │ │ │ │ └── main.less │ │ │ │ ├── badges-label │ │ │ │ └── main.less │ │ │ │ ├── buttons │ │ │ │ └── main.less │ │ │ │ ├── colors │ │ │ │ └── main.less │ │ │ │ ├── form-basic │ │ │ │ └── main.less │ │ │ │ ├── modals │ │ │ │ └── main.less │ │ │ │ ├── node │ │ │ │ └── main.less │ │ │ │ ├── orders │ │ │ │ └── main.less │ │ │ │ └── tooltips-popovers │ │ │ │ └── main.less │ │ └── templates │ │ │ ├── 404.jade │ │ │ ├── alert.jade │ │ │ ├── badges-label.jade │ │ │ ├── basic-table.jade │ │ │ ├── blank.jade │ │ │ ├── blockquotes.jade │ │ │ ├── breadcrumbs.jade │ │ │ ├── buttons.jade │ │ │ ├── carousel.jade │ │ │ ├── charts.jade │ │ │ ├── colors.jade │ │ │ ├── dashboard.jade │ │ │ ├── data-table.jade │ │ │ ├── demo-delivery.jade │ │ │ ├── demo-kitchen.jade │ │ │ ├── demo-role.jade │ │ │ ├── demo-user.jade │ │ │ ├── form-advanced.jade │ │ │ ├── form-basic.jade │ │ │ ├── form-multi-upload.jade │ │ │ ├── form-validation.jade │ │ │ ├── form-wizard.jade │ │ │ ├── mixins │ │ │ └── panel.jade │ │ │ ├── modals.jade │ │ │ ├── navbars.jade │ │ │ ├── pagination.jade │ │ │ ├── panels.jade │ │ │ ├── partials │ │ │ ├── chat.jade │ │ │ ├── header.jade │ │ │ └── nav.jade │ │ │ ├── progress-bar.jade │ │ │ ├── slide.jade │ │ │ ├── staff.jade │ │ │ ├── stock.jade │ │ │ ├── tabs-accordions.jade │ │ │ ├── thanks.jade │ │ │ ├── tiles.jade │ │ │ ├── tooltips-popovers.jade │ │ │ └── typography.jade │ ├── error │ │ └── index.jade │ ├── font-end │ │ └── index.jade │ ├── simulator │ │ ├── index.jade │ │ ├── scripts │ │ │ ├── app.js │ │ │ ├── decorate.js │ │ │ ├── header.js │ │ │ ├── nav.js │ │ │ └── simulator.js │ │ ├── styles │ │ │ ├── bootstrap.less │ │ │ ├── decorate │ │ │ │ └── main.less │ │ │ ├── effects │ │ │ │ └── animation.less │ │ │ └── simulator │ │ │ │ ├── main.less │ │ │ │ ├── mobile.less │ │ │ │ └── tablet.less │ │ └── templates │ │ │ ├── index.jade │ │ │ └── partials │ │ │ ├── header.jade │ │ │ ├── nav.jade │ │ │ └── simulator.jade │ └── welcome │ │ ├── index.jade │ │ ├── scripts │ │ └── app.js │ │ └── styles │ │ ├── bootstrap.less │ │ └── index │ │ └── main.less └── public │ ├── audio │ ├── alert.mp3 │ └── alert.ogg │ ├── fonts │ └── crimsontext │ │ ├── crimsontext-bolditalic.css │ │ ├── crimsontext-bolditalic.eot │ │ ├── crimsontext-bolditalic.svg │ │ └── crimsontext-bolditalic.woff │ ├── panels │ ├── david-logo.png │ ├── favicon.ico │ └── sprites.less.mustache │ ├── scripts │ ├── conf │ │ ├── config.js │ │ ├── constants.js │ │ └── validator.js │ ├── helpers │ │ ├── date.js │ │ ├── devices.js │ │ ├── file.js │ │ ├── queue.js │ │ ├── quickSort.js │ │ └── util.js │ ├── services │ │ ├── constant.js │ │ ├── model.js │ │ ├── screen.js │ │ ├── styles.js │ │ └── validator.js │ └── ui │ │ ├── checkbox.js │ │ ├── dropdownMenu.js │ │ ├── helper.js │ │ ├── ngIscroll.js │ │ ├── promptBox.js │ │ ├── radio.js │ │ ├── scrollpicker.js │ │ ├── selecter.js │ │ ├── slidedown.js │ │ ├── style.js │ │ ├── switch.js │ │ ├── templates │ │ ├── checkbox │ │ │ └── checkbox.jade │ │ ├── layout │ │ │ └── asidebar.jade │ │ ├── radio │ │ │ └── radio.jade │ │ ├── selecter │ │ │ └── selecter.jade │ │ └── switch │ │ │ └── switch.jade │ │ ├── timepicker.js │ │ └── warpperSlider.js │ └── styles │ ├── bootstrap.json │ ├── components │ ├── accordions.less │ ├── alerts.less │ ├── badges.less │ ├── blockquote.less │ ├── breadcrumbs.less │ ├── button-groups.less │ ├── dropdowns.less │ ├── input-groups.less │ ├── labels.less │ ├── list-group.less │ ├── loading.less │ ├── navbar.less │ ├── navs.less │ ├── notice-bar.less │ ├── notification.less │ ├── pagination.less │ ├── panels.less │ ├── progress-bars.less │ ├── tables.less │ └── tiles.less │ ├── core │ ├── buttons.less │ ├── forms.less │ ├── grid.less │ └── layout.less │ ├── effects │ └── fonts.less │ ├── mixins │ ├── alerts.less │ ├── arrow.less │ ├── background-variant.less │ ├── border-radius.less │ ├── buttons.less │ ├── center-block.less │ ├── clearfix.less │ ├── color.less │ ├── forms.less │ ├── gradients.less │ ├── grid-framework.less │ ├── grid.less │ ├── hide-text.less │ ├── image.less │ ├── labels.less │ ├── lesshat │ │ ├── lesshat-prefixed.less │ │ └── lesshat.less │ ├── list-group.less │ ├── nav-divider.less │ ├── nav-vertical-align.less │ ├── opacity.less │ ├── pagination.less │ ├── panels.less │ ├── progress-bar.less │ ├── reset-filter.less │ ├── resize.less │ ├── responsive-visibility.less │ ├── size.less │ ├── tab-focus.less │ ├── table-row.less │ ├── text-emphasis.less │ ├── text-overflow.less │ └── vendor-prefixes.less │ ├── partials │ ├── chat │ │ ├── main.less │ │ ├── mobile.less │ │ └── tablet.less │ ├── header │ │ ├── desktop.less │ │ ├── main.less │ │ ├── mobile.less │ │ └── tablet.less │ └── nav │ │ ├── desktop.less │ │ ├── main.less │ │ ├── mobile.less │ │ └── tablet.less │ ├── resets │ └── normalize.less │ ├── script-components │ ├── calendar.less │ ├── carousel.less │ ├── checkbox.less │ ├── iscroll.less │ ├── modals.less │ ├── pace.less │ ├── prompts.less │ ├── radio.less │ ├── scrollpicker.less │ ├── selectpicker.less │ ├── switch.less │ └── timepicker.less │ ├── utilities │ └── utilities.less │ └── variables │ ├── components.less │ └── defination.less ├── karma.conf.js └── package.json /.gitignore: -------------------------------------------------------------------------------- 1 | # Folders to ignore 2 | bower_components 3 | node_modules 4 | 5 | .build 6 | assets 7 | 8 | # Numerous always-ignore extensions 9 | *.bak 10 | *.diff 11 | *.err 12 | *.orig 13 | *.log 14 | *.rej 15 | *.swo 16 | *.swp 17 | *.zip 18 | *.vi 19 | *~ 20 | 21 | # OS or Editor folders 22 | .DS_Store 23 | ._* 24 | Thumbs.db 25 | .cache 26 | .project 27 | .settings 28 | .tmproj 29 | *.esproj 30 | nbproject 31 | *.sublime-project 32 | *.sublime-workspace 33 | .idea -------------------------------------------------------------------------------- /.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "asi": true, 3 | "expr": true, 4 | "browser": true, 5 | "laxcomma": true, 6 | "-W014": false, 7 | "globals": { 8 | 9 | } 10 | } -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - '0.10' -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 David Jones 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | ngAdmin 3 | ======= 4 | 5 | [Demo](http://davidkk.github.io/ngAdmin/) 6 | 7 | 请在发布版本后才使用 8 | 还是开发中 9 | 10 | -------------------------------------------------------------------------------- /TODO.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | - 完成所有控件 6 | 7 | - layout 样式修改 8 | - 最大化下 nav 可以缩小 9 | - chatbar 弹出可以不使得窗口整体左移 10 | - chatbar 弹出使 nav 缩小 11 | - nav 扩展使 chatbar 隐藏 12 | 13 | - 异步引入第三方插件 14 | - 项目生成流程优化 15 | - 样式,模板,脚本互不干扰 16 | - 脚本生成依赖文件,当修改文件的时候更新依赖文档,若依赖文档有变化则,重新构建公共模块 17 | - 样式生成依赖文件,当依赖的公共模块修改的时候,重新构架该需要依赖的模块 18 | 19 | - 添加页面加载中样式 20 | - 添加滑动事件 `swiftLeft` 21 | - 导航添加更多层树级 22 | - 完成聊天功能脚本 23 | - 添加上线离线切换功能 24 | - 添加登出弹框 25 | 26 | - 添加自定义UI单元测试 27 | - 使用 nodejs 做路由,撤掉 nginx 28 | -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ngAdmin", 3 | "version": "0.1.0", 4 | "license": "MIT", 5 | "dependencies": { 6 | "angular": "1.3.16-build.96+sha.abfbfd6", 7 | "angular-mocks": "1.3.16-build.96+sha.abfbfd6", 8 | "angular-route": "1.3.16-build.96+sha.abfbfd6", 9 | "angular-touch": "1.3.16-build.96+sha.abfbfd6", 10 | "angular-bootstrap": "0.13.0", 11 | 12 | "script": "https://github.com/ded/script.js.git#2.5.7", 13 | 14 | "font-awesome": "4.3.0", 15 | "bootstrap": "3.3.4", 16 | "iscroll": "5.1.3", 17 | 18 | "pace": "*" 19 | }, 20 | "devDependencies": { 21 | "lesshat": "3.0.2" 22 | }, 23 | "ignore": [ 24 | ".tmp", 25 | ".build", 26 | ".git", 27 | ".gitignore", 28 | 29 | "bower_components", 30 | "node_modules", 31 | "package.json", 32 | "Gruntfile.js", 33 | 34 | "*.bak", 35 | "*.diff", 36 | "*.err", 37 | "*.orig", 38 | "*.log", 39 | "*.rej", 40 | "*.swo", 41 | "*.swp", 42 | "*.zip", 43 | "*.vi", 44 | "*~", 45 | 46 | ".DS_Store", 47 | "._*", 48 | "Thumbs.db", 49 | ".cache", 50 | ".project", 51 | ".settings", 52 | ".tmproj", 53 | "*.esproj", 54 | "nbproject", 55 | "*.sublime-project", 56 | "*.sublime-workspace", 57 | ".idea" 58 | ] 59 | } 60 | -------------------------------------------------------------------------------- /client/app/_temp/index.jade: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DavidKk/ngAdmin/55664d50166333d4ddbe91b84bf6bbc3868067e9/client/app/_temp/index.jade -------------------------------------------------------------------------------- /client/app/_temp/styles/delivery/mobile.less: -------------------------------------------------------------------------------- 1 | 2 | 3 | @media (max-width: @screen-xs-max) { 4 | #demo-delivery-container { 5 | margin-top: -50px; 6 | padding-top: 50px !important; 7 | } 8 | } -------------------------------------------------------------------------------- /client/app/_temp/styles/role/main.less: -------------------------------------------------------------------------------- 1 | 2 | 3 | #demo-role-container { 4 | margin-top: 15px; 5 | } 6 | 7 | #demo-role-container .widgets-bar { 8 | margin-bottom: 14px; 9 | } 10 | 11 | #demo-role-container .widgets-bar .search-form { 12 | position: relative; 13 | 14 | input { 15 | .border-radius(3px); 16 | .transition(border-color ease-in-out .15s,box-shadow ease-in-out .15s); 17 | 18 | padding: 8px 12px; 19 | padding-right: 32px; 20 | border: 1px solid #ebebeb; 21 | background-image: none; 22 | background-color: #fff; 23 | line-height: @line-height-base; 24 | color: #555; 25 | font-size: 12px; 26 | } 27 | 28 | input:focus { 29 | .box-shadow(0 2px 1px rgba(203, 208, 217, 0.08)); 30 | 31 | border-color: #c8cdd7; 32 | outline: 0; 33 | } 34 | 35 | i { 36 | color: #999; 37 | position: absolute; 38 | top: 11px; 39 | right: 11px; 40 | } 41 | } 42 | 43 | #demo-role-container .role-list { 44 | border-top: 4px solid @cyan; 45 | background-color: #fff; 46 | 47 | tbody > tr > td { 48 | border-top-width: 0; 49 | 50 | a { 51 | margin: 0 2px; 52 | cursor: pointer; 53 | font-size: 13px; 54 | } 55 | } 56 | } 57 | 58 | #demo-role-container ul.permissions-list, 59 | #demo-role-container ul.sub-permissions-list { 60 | .user-select(none); 61 | 62 | padding-left: 0; 63 | background-color: #fff; 64 | list-style: none; 65 | 66 | & > li.name { margin-bottom: 4px; } 67 | 68 | & > li.name > span.p { 69 | font-size: 14px; 70 | font-weight: bold; 71 | } 72 | 73 | & > li.name > input { 74 | margin-right: 6px; 75 | float: right; 76 | } 77 | 78 | & > li { position: relative; } 79 | & > li > .collapse { 80 | width: 20px; 81 | height: 20px; 82 | display: inline-block; 83 | position: absolute; 84 | top: 6px; 85 | } 86 | 87 | & > li > a.collapse { cursor: pointer; } 88 | 89 | & > li > label { 90 | margin-bottom: 0; 91 | padding-left: 20px; 92 | height: 32px; 93 | display: block; 94 | line-height: 32px; 95 | font-size: 14px; 96 | } 97 | 98 | & > li > label > input { 99 | margin-top: 12px; 100 | margin-right: 6px; 101 | float: right; 102 | } 103 | } 104 | 105 | #demo-role-container ul.permissions-list { 106 | padding: 10px 15px; 107 | border-top: 4px solid @cyan; 108 | } 109 | 110 | #demo-role-container ul.sub-permissions-list { 111 | & > li { padding-left: 1.5em; } 112 | } -------------------------------------------------------------------------------- /client/app/_temp/styles/stock/main.less: -------------------------------------------------------------------------------- 1 | 2 | 3 | #stock-container {} 4 | #stock-container .widgets-bar { margin-bottom: 14px; } 5 | #stock-container .widgets-bar .search-form { 6 | position: relative; 7 | 8 | input { 9 | padding: 8px 12px; 10 | padding-right: 32px; 11 | border: 1px solid #ebebeb; 12 | .border-radius(3px); 13 | background-image: none; 14 | background-color: #fff; 15 | line-height: @line-height-base; 16 | color: #555; 17 | font-size: 12px; 18 | .transition(border-color ease-in-out .15s,box-shadow ease-in-out .15s); 19 | } 20 | 21 | input:focus { 22 | border-color: #c8cdd7; 23 | .box-shadow(0 2px 1px rgba(203, 208, 217, 0.08)); 24 | outline: 0; 25 | } 26 | 27 | i { 28 | color: #999; 29 | position: absolute; 30 | top: 11px; 31 | right: 11px; 32 | } 33 | } 34 | 35 | #stock-container .item { 36 | margin-bottom: 20px; 37 | } 38 | 39 | #stock-container .item > .pic { 40 | .border-radius(6px); 41 | background-color: @black; 42 | display: block; 43 | position: relative; 44 | overflow: hidden; 45 | 46 | &:before { 47 | content: ""; 48 | display: block; 49 | padding-top: 100%; 50 | } 51 | 52 | & > .name { 53 | padding: 10px 20px; 54 | height: 40px; 55 | background-color: fade(@green, 90%); 56 | .border-radius(4px); 57 | display: inline-block; 58 | position: absolute; 59 | top: 4px; 60 | right: 4px; 61 | z-index: 9; 62 | text-align: center; 63 | line-height: 20px; 64 | color: #fff; 65 | font-size: 18px; 66 | .transition(all .35s); 67 | } 68 | 69 | & > img { 70 | width: 100%; 71 | .border-radius(6px); 72 | position: absolute; 73 | top: 0; 74 | left: 0; 75 | overflow: hidden; 76 | .transition(all .35s); 77 | } 78 | 79 | & > .widgets-cover { 80 | .opacity(0); 81 | position: absolute; 82 | left: 10px; 83 | bottom: -40px; 84 | z-index: 9999; 85 | .transition(all .35s); 86 | } 87 | 88 | & > .widgets-cover > span.divider { margin: 0 2px; } 89 | 90 | & > .widgets-cover > a { 91 | padding: 4px; 92 | width: 26px; 93 | .border-radius(4px); 94 | background-color: fade(@black, 90%); 95 | display: inline-block; 96 | cursor: pointer; 97 | text-align: center; 98 | color: #fff; 99 | .transition(all .35s); 100 | } 101 | 102 | & > .widgets-cover > a:hover { background-color: @green; } 103 | 104 | &:hover > .name { top: -40px; } 105 | &:hover > img { .transform(scale(1.2)); } 106 | &:hover > .widgets-cover { 107 | .opacity(1); 108 | bottom: 10px; 109 | } 110 | } 111 | 112 | #stock-container .item > .stock { 113 | margin-top: 10px; 114 | margin-bottom: 10px; 115 | padding-left: 4px; 116 | color: #777; 117 | font-size: 12px; 118 | 119 | & > span.number { 120 | margin-left: 10px; 121 | margin-right: 10px; 122 | font: italic normal 26px/1em Georgia,serif; 123 | } 124 | 125 | & > span.unit { font-size: 12px; } 126 | } 127 | 128 | #stock-container .item > .input-group { 129 | & > input { 130 | padding: 8px 12px; 131 | width: 100%; 132 | border: 1px solid #ebebeb; 133 | .border-radius(3px); 134 | background-image: none; 135 | background-color: #fff; 136 | line-height: @line-height-base; 137 | color: #555; 138 | font-size: 12px; 139 | .transition(border-color ease-in-out .15s,box-shadow ease-in-out .15s); 140 | 141 | &:focus { 142 | border-color: #c8cdd7; 143 | .box-shadow(0 2px 1px rgba(203, 208, 217, 0.08)); 144 | outline: 0; 145 | } 146 | } 147 | } -------------------------------------------------------------------------------- /client/app/_temp/temapltes/role.jade: -------------------------------------------------------------------------------- 1 | 2 | 3 | main#demo-role-container.content-layout 4 | .widgets-bar.clearfix 5 | button.btn.btn-info(type="button", role="button", title="Crate new role") 6 | i.fa.fa-plus 7 | |  New 8 | 9 | form.search-form.pull-right(role="form") 10 | label 11 | input(type="search", placeholder="Search...") 12 | i.fa.fa-search 13 | 14 | .row 15 | .col-md-5 16 | table.role-list.table 17 | thead 18 | tr 19 | th Role Name 20 | th Status 21 | th Operation 22 | tbody 23 | tr 24 | td 25 | a(href, title="Administrator") Administrator 26 | td Normal 27 | td 28 | a(title="edit") Edit 29 | | | 30 | a(title="delete") Delete 31 | tr 32 | td 33 | a(href, title="Guest") Guest 34 | td Normal 35 | td 36 | a(title="edit") Edit 37 | | | 38 | a(title="delete") Delete 39 | 40 | .col-md-7 41 | ul.permissions-list 42 | li.name 43 | span.p Permissions 44 | input(type="checkbox") 45 | 46 | li 47 | a.collapse(title="Expand") 48 | i.fa.fa-folder-o 49 | 50 | label Administrator 51 | input(type="checkbox") 52 | 53 | ul.sub-permissions-list 54 | li 55 | span.collapse 56 | i.fa.fa-gavel 57 | label View User 58 | input(type="checkbox") 59 | li 60 | span.collapse 61 | i.fa.fa-gavel 62 | label Add User 63 | input(type="checkbox") 64 | li 65 | span.collapse 66 | i.fa.fa-gavel 67 | label Edit User 68 | input(type="checkbox") 69 | li 70 | span.collapse 71 | i.fa.fa-gavel 72 | label Delete User 73 | input(type="checkbox") 74 | 75 | li.permissions-list 76 | a.collapse(title="Expand") 77 | i.fa.fa-folder-o 78 | label Stock 79 | input(type="checkbox") 80 | 81 | ul.sub-permissions-list 82 | li 83 | span.collapse 84 | i.fa.fa-gavel 85 | label View Stock 86 | input(type="checkbox") 87 | li 88 | span.collapse 89 | i.fa.fa-gavel 90 | label Add Stock 91 | input(type="checkbox") 92 | li 93 | span.collapse 94 | i.fa.fa-gavel 95 | label Edit Stock 96 | input(type="checkbox") 97 | li 98 | span.collapse 99 | i.fa.fa-gavel 100 | label Delete Stock 101 | input(type="checkbox") 102 | -------------------------------------------------------------------------------- /client/app/_temp/temapltes/user.jade: -------------------------------------------------------------------------------- 1 | 2 | 3 | main#demo-user-container.content-layout -------------------------------------------------------------------------------- /client/app/docs/scripts/chat.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Chat Module 3 | * @author 4 | */ 5 | angular.module('chat', []) 6 | 7 | .directive('chatLayout', [ 8 | '$rootScope', 9 | function($rootScope) { 10 | return { 11 | restrict: 'A', 12 | link: function($scope, $element, $attrs, ctrl) { 13 | 'use strict' 14 | 15 | $rootScope.$on('chat.$toggle', function(event, isOpen) { 16 | $scope.isOpen = arguments.length > 1 ? !!isOpen : !$scope.isOpen 17 | $scope.isOpen ? open() : close() 18 | }) 19 | 20 | $scope.isOpen = !!$attrs.open 21 | $scope.isOpen ? open() : close() 22 | 23 | function open() { 24 | angular 25 | .element(document.body) 26 | .addClass('show-chat') 27 | } 28 | 29 | function close() { 30 | angular 31 | .element(document.body) 32 | .removeClass('show-chat') 33 | } 34 | } 35 | } 36 | } 37 | ]) 38 | 39 | .controller('ChatController', [ 40 | '$scope', 41 | function($scope) {'use strict'; 42 | $scope.isOpenBox = false 43 | 44 | $scope.openBox = function() { 45 | $scope.isOpenBox = true 46 | } 47 | 48 | $scope.closeBox = function() { 49 | $scope.isOpenBox = false 50 | } 51 | 52 | $scope.toggleBox = function() { 53 | $scope.isOpenBox = !$scope.isOpenBox 54 | } 55 | } 56 | ]) 57 | 58 | .controller('ChatboxController', [ 59 | '$scope', 60 | function($scope) { 61 | 'use strict' 62 | 63 | } 64 | ]) -------------------------------------------------------------------------------- /client/app/docs/scripts/header.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Header Module 3 | * @author 4 | */ 5 | angular.module('header', [ 6 | 'services.screen' 7 | , 'ui.ngIscroll', 'ui.dropdownMenu' 8 | ]) 9 | 10 | .controller('HeaderController', [ 11 | '$rootScope', '$scope', 12 | '$screenfull', 13 | function($rootScope, $scope, $screenfull) { 14 | $scope.isFullscreen = false 15 | 16 | $scope.toggleLeftSidebar = function() { 17 | $rootScope.$broadcast('nav.$toggle') 18 | }; 19 | 20 | $scope.toggleRightSidebar = function() { 21 | $rootScope.$broadcast('chat.$toggle') 22 | }; 23 | 24 | $scope.screenfull = function() { 25 | $screenfull.toggle() 26 | } 27 | 28 | $scope.logout = function() { 29 | window.location.reload() 30 | } 31 | 32 | $rootScope.$on('fullscreenchange', function() { 33 | $scope.isFullscreen = $screenfull.isFullscreen 34 | $scope.$digest() 35 | }) 36 | } 37 | ]) -------------------------------------------------------------------------------- /client/app/docs/scripts/nav.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Nav Module 3 | * @author 4 | */ 5 | angular.module('nav', [ 6 | 'ngRoute' 7 | , 'ui.slidedown', 'ui.ngIscroll' 8 | , 'conf.config' 9 | ]) 10 | 11 | .directive('navLayout', [ 12 | '$rootScope', 13 | function($rootScope) { 14 | return { 15 | restrict: 'A', 16 | link: function($scope, $element, $attrs, ctrl) { 17 | 'use strict' 18 | 19 | $rootScope.$on('nav.$toggle', function($event, isOpen) { 20 | $scope.isOpen = angular.isDefined(isOpen) ? !!isOpen : !$scope.isOpen 21 | $scope.isOpen ? open() : close() 22 | }) 23 | 24 | $scope.isOpen = !!$attrs.open 25 | $scope.isOpen ? open() : close() 26 | 27 | $scope.$on('$routeChangeStart', close) 28 | 29 | function open() { 30 | $scope.isOpen = true 31 | $element.removeClass('minify') 32 | angular.element(document.body).addClass('show-nav') 33 | } 34 | 35 | function close() { 36 | $scope.isOpen = false 37 | $element.addClass('minify') 38 | angular.element(document.body).removeClass('show-nav') 39 | } 40 | } 41 | } 42 | } 43 | ]) 44 | 45 | .controller('NavController', [ 46 | '$scope', '$http', '$route', '$location', 47 | 'NAVIGATION', 48 | function($scope, $http, $route, $location, NAVIGATION) { 49 | var exports = this; 50 | 51 | $scope.paths; 52 | $scope.navigations = NAVIGATION; 53 | $scope.navs = []; 54 | $scope.hasSub = false; 55 | $scope.filter = ''; 56 | 57 | exports.reload = function() { 58 | var i = 0 59 | , paths = $location.$$path 60 | .replace(/^\//, '') 61 | .replace(/\/$/, '') 62 | .split('\/') 63 | , cur = paths[1] 64 | , len = $scope.navigations.length 65 | , index 66 | , nav 67 | , j 68 | , c 69 | , clen 70 | , t; 71 | 72 | for (; i < len; i ++) { 73 | nav = $scope.navigations[i] 74 | 75 | if (cur === nav.key) { 76 | $scope.navs = [cur] 77 | break 78 | } 79 | else { 80 | for (j = 0, c = nav.child || [], clen = c.length; j < clen; j ++) { 81 | t = c[j].key.split('/') 82 | 83 | if (cur == t[0]) { 84 | $scope.navs = [nav.key, cur] 85 | break 86 | } 87 | } 88 | } 89 | } 90 | 91 | $scope.paths = paths 92 | } 93 | 94 | exports.filter = function(str) { 95 | var regexp = new RegExp(str, 'ig') 96 | 97 | angular.forEach($scope.navigations, function(nav) { 98 | if (angular.isArray(nav.child)) { 99 | nav.hidden = true 100 | nav.open = false 101 | 102 | angular.forEach(nav.child, function(item) { 103 | if (!item.name.match(regexp)) { 104 | item.hidden = true 105 | } 106 | else { 107 | nav.open = true 108 | nav.hidden = item.hidden = false 109 | } 110 | }) 111 | } 112 | else { 113 | nav.hidden = !nav.name.match(regexp) 114 | } 115 | }) 116 | } 117 | 118 | $scope.$watch('filter', function(filter) { 119 | exports.filter(filter) 120 | }) 121 | 122 | $scope.$on('$routeChangeSuccess', exports.reload) 123 | exports.reload() 124 | } 125 | ]) -------------------------------------------------------------------------------- /client/app/docs/styles/bootstrap.less: -------------------------------------------------------------------------------- 1 | // Index Page 2 | // @author 3 | 4 | @import "variables/defination"; 5 | @import "mixins/lesshat/lesshat"; 6 | @import "mixins/clearfix"; 7 | @import "mixins/arrow"; 8 | @import "mixins/text-overflow"; 9 | 10 | // Components 11 | @import "components/example"; 12 | 13 | // Other Modules 14 | @import "modules/admin/main"; 15 | @import "modules/badges-label/main"; 16 | @import "modules/buttons/main"; 17 | @import "modules/colors/main"; 18 | @import "modules/form-basic/main"; 19 | @import "modules/modals/main"; 20 | @import "modules/node/main"; 21 | @import "modules/orders/main"; 22 | @import "modules/tooltips-popovers/main"; -------------------------------------------------------------------------------- /client/app/docs/styles/components/example.less: -------------------------------------------------------------------------------- 1 | // Docs 2 | // ===================== 3 | 4 | .docs-example { 5 | display: block; 6 | .clearfix(); 7 | } -------------------------------------------------------------------------------- /client/app/docs/styles/modules/admin/main.less: -------------------------------------------------------------------------------- 1 | 2 | 3 | #admin-container { 4 | .widgets-bar { 5 | margin-bottom: 14px; 6 | } 7 | 8 | .widgets-bar .search-form { 9 | position: relative; 10 | 11 | input { 12 | padding: 8px 12px; 13 | padding-right: 32px; 14 | border: 1px solid #ebebeb; 15 | .border-radius(3px); 16 | background-image: none; 17 | background-color: #fff; 18 | line-height: @line-height-base; 19 | color: #555; 20 | font-size: 12px; 21 | .transition(border-color ease-in-out .15s,box-shadow ease-in-out .15s); 22 | } 23 | 24 | input:focus { 25 | border-color: #c8cdd7; 26 | .box-shadow(0 2px 1px rgba(203, 208, 217, 0.08)); 27 | outline: 0; 28 | } 29 | 30 | i { 31 | color: #999; 32 | position: absolute; 33 | top: 11px; 34 | right: 11px; 35 | } 36 | } 37 | 38 | .list-module .admin { 39 | margin-bottom: 20px; 40 | 41 | a.pic { 42 | width: 100%; 43 | background-color: @black; 44 | .border-radius(6px); 45 | display: block; 46 | position: relative; 47 | overflow: hidden; 48 | cursor: pointer; 49 | } 50 | 51 | a.pic i { 52 | margin-top: -12.5px; 53 | margin-left: -12.5px; 54 | display: block; 55 | position: absolute; 56 | left: 50%; 57 | top: 50%; 58 | z-index: 999999; 59 | color: #fff; 60 | font-size: 25px; 61 | .opacity(0); 62 | .transform(scale(0.5)); 63 | .transition(all 300ms ease-in-out); 64 | } 65 | 66 | a.pic:before { 67 | padding-top: 100%; 68 | display: block; 69 | content: ""; 70 | } 71 | 72 | a.pic > img { 73 | width: 100%; 74 | position: absolute; 75 | left: 0; 76 | top: 0; 77 | } 78 | 79 | a.pic:hover > i { 80 | .transform(scale(1)); 81 | .opacity(1); 82 | } 83 | 84 | a.name { 85 | margin-top: 6px; 86 | display: block; 87 | text-align: center; 88 | } 89 | 90 | .phone { padding-left: 4px; } 91 | .phone > .number { font-size: 16px; } 92 | } 93 | 94 | .detail-module > .tab-content { 95 | background-color: #fff; 96 | } 97 | 98 | .detail-module .profile-warp { 99 | h3.caption { 100 | margin-top: 0; 101 | } 102 | 103 | a.pic { 104 | margin-bottom: 10px; 105 | width: 100%; 106 | display: inline-block; 107 | position: relative; 108 | } 109 | 110 | a.pic:before { 111 | content: ""; 112 | padding-top: 100%; 113 | display: block; 114 | } 115 | 116 | a.pic > img { 117 | min-width: 100%; 118 | min-height: 100%; 119 | position: absolute; 120 | left: 0; 121 | top: 0; 122 | } 123 | 124 | .info-item > i { 125 | margin-right: 4px; 126 | width: 14px; 127 | height: 14px; 128 | display: inline-block; 129 | text-align: center; 130 | } 131 | } 132 | 133 | .detail-module .profile-edit-warp { 134 | .nav.nav-pills i { 135 | margin-right: 4px; 136 | width: 14px; 137 | height: 14px; 138 | display: inline-block; 139 | text-align: center; 140 | } 141 | } 142 | 143 | .detail-module .profile-edit-warp .face-change-warp { 144 | min-height: 600px; 145 | } 146 | 147 | .detail-module .setting-warp { 148 | label { 149 | margin-right: 10px; 150 | } 151 | 152 | label > input[type="checkbox"] { 153 | margin-right: 4px; 154 | } 155 | } 156 | } -------------------------------------------------------------------------------- /client/app/docs/styles/modules/badges-label/main.less: -------------------------------------------------------------------------------- 1 | // Badges & Label 2 | // ------------------ 3 | 4 | #badge-label-container { 5 | .docs-example p { 6 | margin-bottom: 10px; 7 | } 8 | } -------------------------------------------------------------------------------- /client/app/docs/styles/modules/buttons/main.less: -------------------------------------------------------------------------------- 1 | // Buttons 2 | // ------------------- 3 | 4 | #buttons-container { 5 | .docs-example { 6 | .btn { 7 | margin-right: 15px; 8 | } 9 | 10 | .btn.btn-block { 11 | margin-right: 0; 12 | } 13 | } 14 | } -------------------------------------------------------------------------------- /client/app/docs/styles/modules/colors/main.less: -------------------------------------------------------------------------------- 1 | 2 | 3 | #colors-container { 4 | padding-bottom: 0; 5 | height: 100%; 6 | 7 | .demo-color-block { 8 | height: percentage(1/3); 9 | color: #fff; 10 | cursor: pointer; 11 | .user-select(none); 12 | } 13 | 14 | .demo-color-block > span { 15 | position: absolute; 16 | bottom: 6px; 17 | left: 10px; 18 | font-size: 16px; 19 | } 20 | 21 | .blue { background-color: @blue; } 22 | .cyan { background-color: @cyan; } 23 | .green { background-color: @green; } 24 | .yellow { background-color: @yellow; } 25 | .orange { background-color: @orange; } 26 | .red { background-color: @red; } 27 | .pink { background-color: @pink; } 28 | .amethyst { background-color: @amethyst; } 29 | .black { background-color: @black; } 30 | .gray { background-color: @gray; color: darken(@gray, 30%); } 31 | } -------------------------------------------------------------------------------- /client/app/docs/styles/modules/form-basic/main.less: -------------------------------------------------------------------------------- 1 | // Form Basic 2 | // ------------------- 3 | 4 | #form-basic-container { 5 | .docs-example { 6 | .form-control { 7 | margin: 0 auto; 8 | } 9 | 10 | .switch { 11 | margin-right: 10px; 12 | } 13 | 14 | > .row { 15 | margin-bottom: 15px; 16 | } 17 | } 18 | } -------------------------------------------------------------------------------- /client/app/docs/styles/modules/modals/main.less: -------------------------------------------------------------------------------- 1 | // Modals 2 | // ------------------- 3 | 4 | #modals-container { 5 | .docs-example { 6 | .btn { 7 | margin-right: 15px; 8 | } 9 | 10 | .btn.btn-block { 11 | margin-right: 0; 12 | } 13 | } 14 | } -------------------------------------------------------------------------------- /client/app/docs/styles/modules/node/main.less: -------------------------------------------------------------------------------- 1 | 2 | #table-page-container { 3 | .widgets-bar { 4 | margin-bottom: 14px; 5 | } 6 | 7 | .widgets-bar .search-form { 8 | position: relative; 9 | 10 | input { 11 | padding: 8px 12px; 12 | padding-right: 32px; 13 | border: 1px solid #ebebeb; 14 | .border-radius(3px); 15 | background-image: none; 16 | background-color: #fff; 17 | line-height: @line-height-base; 18 | color: #555; 19 | font-size: 12px; 20 | .transition(border-color ease-in-out .15s,box-shadow ease-in-out .15s); 21 | } 22 | 23 | input:focus { 24 | border-color: #c8cdd7; 25 | .box-shadow(0 2px 1px rgba(203, 208, 217, 0.08)); 26 | outline: 0; 27 | } 28 | 29 | i { 30 | position: absolute; 31 | top: 11px; 32 | right: 11px; 33 | color: #999; 34 | } 35 | } 36 | } -------------------------------------------------------------------------------- /client/app/docs/styles/modules/orders/main.less: -------------------------------------------------------------------------------- 1 | 2 | #orders-container { 3 | .widgets-bar { 4 | margin-bottom: 14px; 5 | } 6 | 7 | .widgets-bar .search-form { 8 | position: relative; 9 | 10 | input { 11 | padding: 8px 12px; 12 | padding-right: 32px; 13 | border: 1px solid #ebebeb; 14 | .border-radius(3px); 15 | background-image: none; 16 | background-color: #fff; 17 | line-height: @line-height-base; 18 | color: #555; 19 | font-size: 12px; 20 | .transition(border-color ease-in-out .15s,box-shadow ease-in-out .15s); 21 | } 22 | 23 | input:focus { 24 | border-color: #c8cdd7; 25 | .box-shadow(0 2px 1px rgba(203, 208, 217, 0.08)); 26 | outline: 0; 27 | } 28 | 29 | i { 30 | position: absolute; 31 | top: 11px; 32 | right: 11px; 33 | color: #999; 34 | } 35 | } 36 | } -------------------------------------------------------------------------------- /client/app/docs/styles/modules/tooltips-popovers/main.less: -------------------------------------------------------------------------------- 1 | // Tooltips & Popovers 2 | // -------------------- 3 | 4 | #tooltips-popovers-container { 5 | .docs-example { 6 | .btn { 7 | margin-right: 15px; 8 | } 9 | 10 | .btn.btn-block { 11 | margin-right: 0; 12 | } 13 | } 14 | } -------------------------------------------------------------------------------- /client/app/docs/templates/404.jade: -------------------------------------------------------------------------------- 1 | 2 | section#404-container.content-layout -------------------------------------------------------------------------------- /client/app/docs/templates/alert.jade: -------------------------------------------------------------------------------- 1 | 2 | .content-layout 3 | section#alert-container 4 | h2 Alerts 5 | br 6 | 7 | .row 8 | .col-md-12 9 | .alert 10 | strong Default Style!  11 | | Choose from green, cyan, orange, red or others. 12 | 13 | .row 14 | .col-md-6 15 | .alert.alert-success 16 | strong Success Style!  17 | | Choose from green, cyan, orange, red or others. 18 | 19 | .col-md-6 20 | .alert.alert-info 21 | strong Info Style!  22 | | Choose from green, cyan, orange, red or others. 23 | 24 | .row 25 | .col-md-6 26 | .alert.alert-warning 27 | strong Warning Style!  28 | | Choose from green, cyan, orange, red or others. 29 | 30 | .col-md-6 31 | .alert.alert-danger 32 | strong Danger Style!  33 | | Choose from green, cyan, orange, red or others. 34 | -------------------------------------------------------------------------------- /client/app/docs/templates/badges-label.jade: -------------------------------------------------------------------------------- 1 | include mixins/panel 2 | 3 | .content-layout 4 | section#badge-label-container 5 | h3 Badges & Labels 6 | br 7 | 8 | table.table.table-bordered 9 | thead 10 | tr 11 | th(width='50%') Badges 12 | th Squared Badges 13 | tbody 14 | tr 15 | td.padding-lg 16 | .docs-example 17 | p 18 | a 19 | span.badge 1 20 | |  Default 21 | p 22 | a 23 | span.badge.badge-primary 2 24 | |  Primary 25 | p 26 | a 27 | span.badge.badge-success 3 28 | |  Success 29 | p 30 | a 31 | span.badge.badge-info 4 32 | |  Info 33 | p 34 | a 35 | span.badge.badge-warning 5 36 | |  Warning 37 | p 38 | a 39 | span.badge.badge-danger 6 40 | |  Danger 41 | 42 | td.padding-lg 43 | .docs-example 44 | p 45 | a 46 | span.badge.badge-square 1 47 | |  Default 48 | p 49 | a 50 | span.badge.badge-square.badge-primary 2 51 | |  Primary 52 | p 53 | a 54 | span.badge.badge-square.badge-success 3 55 | |  Success 56 | p 57 | a 58 | span.badge.badge-square.badge-info 4 59 | |  Info 60 | p 61 | a 62 | span.badge.badge-square.badge-warning 5 63 | |  Warning 64 | p 65 | a 66 | span.badge.badge-square.badge-danger 6 67 | |  Danger 68 | 69 | table.table.table-bordered 70 | thead 71 | tr 72 | th Labels 73 | tbody 74 | tr 75 | td.padding-lg 76 | .docs-example 77 | .label Default 78 | |   79 | .label.label-primary Primary 80 | |   81 | .label.label-success Success 82 | |   83 | .label.label-info Info 84 | |   85 | .label.label-warning Warning 86 | |   87 | .label.label-danger Danger 88 | -------------------------------------------------------------------------------- /client/app/docs/templates/blank.jade: -------------------------------------------------------------------------------- 1 | 2 | section#blank-container.content-layout 3 | -------------------------------------------------------------------------------- /client/app/docs/templates/blockquotes.jade: -------------------------------------------------------------------------------- 1 | include mixins/panel 2 | 3 | .content-layout 4 | section#blockquotes-container 5 | h3 Blockquotes 6 | br 7 | 8 | +panel('Simple Blockquotes') 9 | mixin body 10 | .col-md-12 11 | p 12 | strong Simple Blockquote (Native) 13 | blockquote 14 | p 15 | strong Blockquote 16 | br 17 | | Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer posuere erat a ante. 18 | hr 19 | p 20 | strong Cited 21 | blockquote 22 | p 23 | | Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer posuere erat a ante. 24 | small 25 | | Someone famous in 26 | cite(title='Source Title') Source Title 27 | hr 28 | p 29 | strong Pulled right 30 | blockquote.pull-right 31 | p 32 | | Lorem ipsum dolor sit amet, consectetur adipiscing elit. Integer posuere erat a ante. 33 | small 34 | | Someone famous in 35 | cite(title='Source Title') Source Title 36 | 37 | h3 Other Blockquotes Types 38 | br 39 | 40 | blockquote 41 | p 42 | strong Blockquote Default 43 | p 44 | small 45 | | Inquietude simplicity terminated she compliment remarkably few her nay. The weeks are ham asked jokes. Neglected perceived shy nay concluded. Not mile draw plan snug next all. Houses latter an valley be indeed wished merely in my. Money doubt oh drawn every or an china. Visited out friends for expense message set eat. 46 | 47 | blockquote.blockquote-success 48 | p 49 | strong Blockquote Success 50 | p 51 | small 52 | | Inquietude simplicity terminated she compliment remarkably few her nay. The weeks are ham asked jokes. Neglected perceived shy nay concluded. Not mile draw plan snug next all. Houses latter an valley be indeed wished merely in my. Money doubt oh drawn every or an china. Visited out friends for expense message set eat. 53 | 54 | blockquote.blockquote-info 55 | p 56 | strong Blockquote Info 57 | p 58 | small 59 | | Inquietude simplicity terminated she compliment remarkably few her nay. The weeks are ham asked jokes. Neglected perceived shy nay concluded. Not mile draw plan snug next all. Houses latter an valley be indeed wished merely in my. Money doubt oh drawn every or an china. Visited out friends for expense message set eat. 60 | 61 | blockquote.blockquote-warning 62 | p 63 | strong Blockquote Warning 64 | p 65 | small 66 | | Inquietude simplicity terminated she compliment remarkably few her nay. The weeks are ham asked jokes. Neglected perceived shy nay concluded. Not mile draw plan snug next all. Houses latter an valley be indeed wished merely in my. Money doubt oh drawn every or an china. Visited out friends for expense message set eat. 67 | 68 | blockquote.blockquote-danger 69 | p 70 | strong Blockquote Danger 71 | p 72 | small 73 | | Inquietude simplicity terminated she compliment remarkably few her nay. The weeks are ham asked jokes. Neglected perceived shy nay concluded. Not mile draw plan snug next all. Houses latter an valley be indeed wished merely in my. Money doubt oh drawn every or an china. Visited out friends for expense message set eat. 74 | -------------------------------------------------------------------------------- /client/app/docs/templates/breadcrumbs.jade: -------------------------------------------------------------------------------- 1 | include mixins/panel 2 | 3 | .content-layout 4 | section#breadcrumbs-container 5 | h3 Breadcrumbs 6 | br 7 | 8 | +panel('Breadcrumb Types') 9 | mixin body 10 | ol.breadcrumb.breadcrumb-pure 11 | li 12 | a(href='#') 13 | i.fa.fa-folder 14 | | Breadcrumb 15 | li 16 | a(href='#') Appearance 17 | li 18 | a(href='#') Plugins 19 | li.active Widgets 20 | 21 | ol.breadcrumb.breadcrumb-border 22 | li 23 | a(href='#') 24 | i.fa.fa-folder 25 | | Breadcrumb 26 | li 27 | a(href='#') Appearance 28 | li 29 | a(href='#') Plugins 30 | li.active Widgets 31 | 32 | ol.breadcrumb 33 | li 34 | a(href='#') 35 | i.fa.fa-folder 36 | | Breadcrumb 37 | li 38 | a(href='#') Appearance 39 | li 40 | a(href='#') Plugins 41 | li.active Widgets 42 | -------------------------------------------------------------------------------- /client/app/docs/templates/carousel.jade: -------------------------------------------------------------------------------- 1 | 2 | section#carousel-container.content-layout 3 | -------------------------------------------------------------------------------- /client/app/docs/templates/colors.jade: -------------------------------------------------------------------------------- 1 | section#colors-container.content-layout.no-padding 2 | .blue.demo-color-block.col-sm-3.col-xs-6 3 | span BLUE 4 | .cyan.demo-color-block.col-sm-3.col-xs-6 5 | span CYAN 6 | .green.demo-color-block.col-sm-3.col-xs-6 7 | span GREEN 8 | .yellow.demo-color-block.col-sm-3.col-xs-6 9 | span YELLOW 10 | .orange.demo-color-block.col-sm-3.col-xs-6 11 | span ORANGE 12 | .red.demo-color-block.col-sm-3.col-xs-6 13 | span RED 14 | .pink.demo-color-block.col-sm-3.col-xs-6 15 | span PINK 16 | .amethyst.demo-color-block.col-sm-3.col-xs-6 17 | span AMETHYST 18 | .black.demo-color-block.col-sm-3.col-xs-6 19 | span BLACK 20 | .gray.demo-color-block.col-sm-3.col-xs-6 21 | span GRAY 22 | -------------------------------------------------------------------------------- /client/app/docs/templates/dashboard.jade: -------------------------------------------------------------------------------- 1 | 2 | 3 | .content-layout 4 | section#dashboard-container 5 | -------------------------------------------------------------------------------- /client/app/docs/templates/data-table.jade: -------------------------------------------------------------------------------- 1 | 2 | .content-layout 3 | section#data-table-container 4 | h2 Data Tables 5 | 6 | .table-responsive(dataquilt, ng-controller='TableDemoAController') 7 | .table-header(dataquilt-header) 8 | table.table.table-bordered 9 | thead 10 | tr 11 | th(ng-repeat='(key, item) in dataTable[0]') {{key}} 12 | 13 | .table-body(dataquilt-body) 14 | table.table.table-bordered 15 | tbody 16 | tr(ng-repeat='row in dataTable') 17 | td(ng-repeat='item in row') {{item}} 18 | 19 | .table-footer 20 | -------------------------------------------------------------------------------- /client/app/docs/templates/demo-kitchen.jade: -------------------------------------------------------------------------------- 1 | 2 | #kitchen-container.content-layout.no-padding(ng-controller='Kitchen') 3 | ul.nav-bar 4 | li(ng-class='{ active: part == 0 }') 5 | a(ng-click='change(0)', title='合并订单') 合并订单 6 | li(ng-class='{ active: part == 1 }') 7 | a(ng-click='change(1)', title='当前订单') 当前订单 8 | li(ng-class='{ active: part == 2 }') 9 | a(ng-click='change(2)', title='待打包订单') 待打包订单 10 | .slider(wrapper-slider, number='3', ng-model='part') 11 | 12 | .wrapper.clearfix(wrapper-slider, number='3', ng-model='part', ng-controller='Kitchen.Order') 13 | .production-module 14 | .list(ng-if='combined.length > 0') 15 | .product.notice-bar(kitchen-product, ng-repeat='item in combined') 16 | .product-pic 17 | img(ng-src='{{ item.frontCover | image: "2/w/60/h/60" }}') 18 | 19 | .product-inner 20 | h5.title {{ item.productName }} 21 | .number {{ item.num }} 22 | 23 | ul.widgets-bar 24 | li.browse 25 | a(title='查看制作食谱') 26 | i.fa.fa-leaf 27 | 28 | .no-data(ng-if='1') 29 | | 暂时不支持此功能  30 | span ╮(╯▽╰)╭ 31 | 32 | .production-module 33 | .list(ng-if='unattended.length > 0') 34 | .product-order(ng-repeat='order in unattended') 35 | .header 36 | .time {{ order.createdAt*1000 | date: 'HH:mm MM-dd' }} 37 | .address {{ order.building.name }}, F{{ order.address.floor }}, {{ order.address.content }}, {{ order.address.name }} 38 | .widgets-bar(dropdown-menu) 39 | a.open-widgets(dropdown-menu-toggle, title='展开') 40 | i.fa.fa-chevron-down 41 | 42 | ul.dropdown-menu.pull-right(ng-click='stopPropagation($event)') 43 | //- li 44 | a(href, title='点击查看订单信息') 点击查看订单信息 45 | li 46 | a(ng-click='complete(order.id, $event)', title='完成订单') 完成订单 47 | 48 | .list-wrap 49 | .product.notice-bar(kitchen-product, ng-repeat='item in order.details') 50 | .product-pic 51 | img(ng-src='{{ item.frontCover | image: "2/w/60/h/60" }}') 52 | 53 | .product-inner 54 | h5.title {{ item.productName }} 55 | .number {{ item.num }} 56 | 57 | ul.widgets-bar 58 | li.amethyst 59 | a(title='查看制作食谱') 60 | i.fa.fa-leaf 61 | 62 | .no-data(ng-if='unattended.length === 0') 63 | | 暂无任何可接手的订单  64 | span ╮(╯▽╰)╭ 65 | 66 | .production-module(ng-if='orders.length > 0', ng-controller='Kitchen.Completed') 67 | button.package-submit(ng-show='selected', ng-click='package()', ng-disabled='{{ disabled }}', title='确认打包', role='button') 68 | i.fa.fa-inbox 69 | |  确认打包 70 | 71 | .list(ng-if='orders.length > 0') 72 | .order.notice-bar(kitchen-product, ng-repeat='order in orders', ng-class='{ selected: order.selected }') 73 | .order-select(ng-click='select(order.id, $event)') 74 | i.fa.fa-check 75 | 76 | .order-inner 77 | .address {{ order.building.name }} {{ order.address.floor }} {{ order.address.content }} 78 | .time {{ order.createdAt*1000 | date: 'HH:mm MM-dd' }} 79 | 80 | ul.widgets-bar 81 | li.amethyst 82 | a(title='查看订单中的商品') 83 | i.fa.fa-database 84 | 85 | li.orange 86 | a(ng-click='revoke(order.id, $event)', title='撤销订单') 87 | i.fa.fa-repeat 88 | 89 | .no-data(ng-if='orders.length === 0') 90 | | 暂无任何订单历史  91 | span ╮(╯▽╰)╭ 92 | 93 | audio(media-player='noticeAudio', data-playlist='playlistA') 94 | source(src='//cdn.xiaozhisong.com/work/audio/001.ogg', type='audio/ogg') 95 | -------------------------------------------------------------------------------- /client/app/docs/templates/demo-role.jade: -------------------------------------------------------------------------------- 1 | 2 | section#role-container.content-layout.no-padding(ng-controller='Roles') 3 | .widgets-bar.clearfix 4 | button.btn.btn-cyan(type='button', role='button', title='Crate new role') 5 | i.fa.fa-plus 6 | |  New 7 | 8 | form.search-form.pull-right(role='form') 9 | label 10 | input(type='search', placeholder='Search...') 11 | i.fa.fa-search 12 | 13 | .row 14 | .col-md-4 15 | table.role-list.table 16 | thead 17 | tr 18 | th Role Name 19 | th Operation 20 | tbody 21 | tr(ng-repeat='item in roles') 22 | td {{item.name}} 23 | td 24 | a(title='edit') Edit 25 | | | 26 | a(title='delete') Delete 27 | 28 | .col-md-8 29 | ul.permissions-list 30 | li.name 31 | span.p Permissions 32 | input(type='checkbox') 33 | 34 | li 35 | a.collapse(title='Expand') 36 | i.entypo.entypo-flow-line 37 | 38 | label Administrator 39 | input(type='checkbox') 40 | 41 | ul.sub-permissions-list 42 | li 43 | span.collapse 44 | i.entypo.entypo-flow-parallel 45 | label View User 46 | input(type='checkbox') 47 | li 48 | span.collapse 49 | i.entypo.entypo-flow-parallel 50 | label Add User 51 | input(type='checkbox') 52 | li 53 | span.collapse 54 | i.entypo.entypo-flow-parallel 55 | label Edit User 56 | input(type='checkbox') 57 | li 58 | span.collapse 59 | i.entypo.entypo-flow-parallel 60 | label Delete User 61 | input(type='checkbox') 62 | 63 | li.permissions-list 64 | a.collapse(title='Expand') 65 | i.entypo.entypo-flow-line 66 | label Stock 67 | input(type='checkbox') 68 | 69 | ul.sub-permissions-list 70 | li 71 | span.collapse 72 | i.entypo.entypo-flow-parallel 73 | label View Stock 74 | input(type='checkbox') 75 | li 76 | span.collapse 77 | i.entypo.entypo-flow-parallel 78 | label Add Stock 79 | input(type='checkbox') 80 | li 81 | span.collapse 82 | i.entypo.entypo-flow-parallel 83 | label Edit Stock 84 | input(type='checkbox') 85 | li 86 | span.collapse 87 | i.entypo.entypo-flow-parallel 88 | label Delete Stock 89 | input(type='checkbox') 90 | -------------------------------------------------------------------------------- /client/app/docs/templates/demo-user.jade: -------------------------------------------------------------------------------- 1 | 2 | section#user-container.content-layout -------------------------------------------------------------------------------- /client/app/docs/templates/form-advanced.jade: -------------------------------------------------------------------------------- 1 | 2 | .content-layout 3 | section#form-advanced-container 4 | -------------------------------------------------------------------------------- /client/app/docs/templates/form-multi-upload.jade: -------------------------------------------------------------------------------- 1 | 2 | .content-layout 3 | section#form-multi-upload-container 4 | -------------------------------------------------------------------------------- /client/app/docs/templates/form-validation.jade: -------------------------------------------------------------------------------- 1 | 2 | .content-layout 3 | section#form-validation-container 4 | -------------------------------------------------------------------------------- /client/app/docs/templates/form-wizard.jade: -------------------------------------------------------------------------------- 1 | 2 | .content-layout 3 | section#form-wizard-container 4 | -------------------------------------------------------------------------------- /client/app/docs/templates/mixins/panel.jade: -------------------------------------------------------------------------------- 1 | mixin panel(title) 2 | mixin controls 3 | a(ng-click='isCollapsed = !isCollapsed') 4 | i.fa.fa-chevron-down 5 | 6 | mixin body 7 | |   8 | 9 | if block 10 | block 11 | 12 | .panel(ng-controller='FooController')&attributes(attributes) 13 | .panel-heading 14 | .panel-title 15 | h4!= title || 'Panel Title' 16 | 17 | .panel-controls 18 | +controls 19 | 20 | .panel-collapse.in(collapse='isCollapsed') 21 | .panel-body 22 | +body -------------------------------------------------------------------------------- /client/app/docs/templates/modals.jade: -------------------------------------------------------------------------------- 1 | include mixins/panel 2 | 3 | .content-layout 4 | section#modals-container(ng-controller="ModalsController") 5 | h2 Modals Triggering 6 | 7 | +panel('Modals Examples') 8 | mixin body 9 | .docs-example 10 | button.btn.btn-success(ng-click='open()', type='button', role='button') Modal Toggle 11 | 12 | script(id='/templates/modal/modal.html', type='text/ng-template') 13 | .modal-header 14 | h3.modal-title I'm a modal! 15 | .modal-body 16 | p One fine body… 17 | .modal-footer 18 | button.btn.btn-default(type='button', data-dismiss='modal') Close 19 | button.btn.btn-primary(type='button') Ok 20 | -------------------------------------------------------------------------------- /client/app/docs/templates/pagination.jade: -------------------------------------------------------------------------------- 1 | include mixins/panel 2 | 3 | .content-layout 4 | section#pagination-container 5 | h3 Pagination 6 | br 7 | 8 | +panel('Pagination & Pager') 9 | mixin body 10 | .row 11 | .col-md-6 12 | h5 Normal Pagination 13 | ul.pagination 14 | li 15 | a(href='#') « 16 | li 17 | a(href='#') 1 18 | li.active 19 | a(href='#') 2 20 | li 21 | a(href='#') 3 22 | li.disabled 23 | a(href='#') 4 24 | li 25 | a(href='#') 5 26 | li 27 | a(href='#') 6 28 | li 29 | a(href='#') » 30 | p 31 | strong Sizes 32 | ul.pagination.pagination-sm 33 | li 34 | a(href='#') « 35 | li 36 | a(href='#') 1 37 | li.active 38 | a(href='#') 2 39 | li 40 | a(href='#') 3 41 | li.disabled 42 | a(href='#') 4 43 | li 44 | a(href='#') 5 45 | li 46 | a(href='#') 6 47 | li 48 | a(href='#') » 49 | 50 | div.clear 51 | ul.pagination.pagination-lg 52 | li 53 | a(href='#') « 54 | li 55 | a(href='#') 1 56 | li.active 57 | a(href='#') 2 58 | li 59 | a(href='#') 3 60 | li 61 | a(href='#') 4 62 | li 63 | a(href='#') » 64 | 65 | div.col-md-6 66 | h5 Pager 67 | ul.pager 68 | li 69 | a(href='#') 70 | i.entypo-left-thin 71 | | Previous 72 | |   73 | li 74 | a(href='#') 75 | | Next 76 | i.entypo-right-thin 77 | 78 | p 79 | strong Floated 80 | 81 | ul.pager 82 | li.previous 83 | a(href='#') 84 | i.entypo-left-thin 85 | | Previous 86 | li.next 87 | a(href='#') 88 | | Next 89 | i.entypo-right-thin 90 | 91 | p 92 | strong Disabled 93 | 94 | ul.pager 95 | li.previous.disabled 96 | a(href='#') 97 | i.entypo-left-thin 98 | | Previous 99 | li.next 100 | a(href='#') 101 | | Next 102 | i.entypo-right-thin 103 | -------------------------------------------------------------------------------- /client/app/docs/templates/partials/nav.jade: -------------------------------------------------------------------------------- 1 | nav#nav-container(ng-controller='NavController') 2 | .brand-sidebar 3 | a(href='./', target='_self') ngAdmin 4 | 5 | ul.nav.nav-stacked 6 | li.search-sidebar 7 | input(ng-model='filter', name='filter', type='search', placeholder='Search something...') 8 | a 9 | i.fa.fa-search 10 | 11 | li.profile-sidebar.online 12 | .face.dropdown-submenu.pull-left.open 13 | a.avator 14 | img(src='//q.qlogo.cn/qqapp/100229475/70F82D66FE3FD280B8BC8D789E5CE979/100') 15 | 16 | .info.dropdown-submenu 17 | a.name David Jones 18 | span.role Administrator 19 | a.status 20 | 21 | .scroll-viewport 22 | .viewport-scroll(ng-iscroll) 23 | ul.nav.nav-stacked(slidedown-group) 24 | li(slidedown, ng-repeat='nav in navigations', 25 | isopen='{{ nav.key == navs[0] && paths.length > 1 }}', 26 | ng-hide='nav.hidden', 27 | ng-class='{\ 28 | "dropdown-submenu": nav.child,\ 29 | "active": nav.key == navs[0] && paths.length === 1\ 30 | }') 31 | 32 | a(ng-if='!nav.child', ng-href='{{ nav.url || "/docs/" + nav.key }}/') 33 | i(class='fa fa-{{ nav.icon }}') 34 | span {{ nav.name }} 35 | 36 | a(ng-if='nav.child', slidedown-toggle) 37 | i(class='fa fa-{{ nav.icon }}') 38 | span {{ nav.name }} 39 | 40 | ul.nav-submenu(ng-if='nav.child', slidedown-list) 41 | li(ng-repeat='menu in nav.child', 42 | ng-hide='menu.hidden', 43 | ng-class="{\ 44 | active: menu.key == navs[1] || menu.key == paths.slice(1, paths.length).join('/')\ 45 | }") 46 | a(ng-href='{{ menu.url || "/docs/" + menu.key }}/', target='{{ menu.target }}') 47 | i(class='fa fa-circle-o') 48 | | {{ menu.name }} 49 | -------------------------------------------------------------------------------- /client/app/docs/templates/slide.jade: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DavidKk/ngAdmin/55664d50166333d4ddbe91b84bf6bbc3868067e9/client/app/docs/templates/slide.jade -------------------------------------------------------------------------------- /client/app/docs/templates/stock.jade: -------------------------------------------------------------------------------- 1 | 2 | .content-layout 3 | section#stock-container(ng-controller='Stock') 4 | .widgets-bar.clearfix 5 | button.btn.btn-cyan(type='button', role='button', title='Create class') 6 | i.fa.fa-plus 7 | |  New 8 | 9 | form.search-form.pull-right(role='form') 10 | label 11 | input(type='search', placeholder='Search...') 12 | i.fa.fa-search 13 | 14 | .row 15 | .col-md-3(ng-repeat='item in stocks') 16 | .item 17 | .pic 18 | .widgets-cover 19 | a(title='Chart') 20 | i.fa.fa-bar-chart-o 21 | span.divider 22 | a(title='Edit') 23 | i.fa.fa-edit 24 | span.divider 25 | a(title='Delete') 26 | i.fa.fa-trash-o 27 | 28 | .name {{item.name}} 29 | img(ng-src='{{item.image}}') 30 | 31 | .reserve Stock: 32 | span.number {{item.reserve}}/{{item.max_reserve}} 33 | span.unit (kg) 34 | 35 | .input-group 36 | input.input(min='-10000', max='10000', type='number', placeholder='in/out(kg)') 37 | .input-group-btn 38 | button.btn.btn-cyan(type='button', role='button') in/out 39 | -------------------------------------------------------------------------------- /client/app/docs/templates/thanks.jade: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DavidKk/ngAdmin/55664d50166333d4ddbe91b84bf6bbc3868067e9/client/app/docs/templates/thanks.jade -------------------------------------------------------------------------------- /client/app/docs/templates/tooltips-popovers.jade: -------------------------------------------------------------------------------- 1 | include mixins/panel 2 | 3 | .content-layout 4 | #tooltips-popovers-container 5 | h2 Popovers and Tooltips 6 | 7 | +panel('Popovers and Tooltips') 8 | mixin body 9 | .docs-example 10 | h4 Tooltips 11 | p 12 | button.btn.btn-primary(tooltip-placement='top', tooltip='It\'s so simple to create a tooltop for my website!', data-original-title='Twitter Bootstrap Tooltips') I'm a Tooltips 13 | button.btn.btn-success(tooltip-placement='bottom', tooltip='It\'s so simple to create a tooltop for my website!', data-original-title='Twitter Bootstrap Tooltips') I'm a Tooltips 14 | button.btn.btn-info(tooltip-placement='top', tooltip='It\'s so simple to create a tooltop for my website!', data-original-title='Twitter Bootstrap Tooltips') I'm a Tooltips 15 | button.btn.btn-warning(tooltip-placement='right', tooltip='It\'s so simple to create a tooltop for my website!', data-original-title='Twitter Bootstrap Tooltips') I'm a Tooltips 16 | button.btn.btn-danger(tooltip-placement='left', tooltip='It\'s so simple to create a tooltop for my website!', data-original-title='Twitter Bootstrap Tooltips') Click me! 17 | 18 | .docs-example 19 | h4 Popovers 20 | p 21 | button.btn.btn-primary(popover-placement='top', popover='It\'s so simple to create a tooltop for my website!', data-original-title='Twitter Bootstrap Popover') I'm a Popover 22 | button.btn.btn-success(popover-placement='bottom', popover='It\'s so simple to create a tooltop for my website!', data-original-title='Twitter Bootstrap Popover') I'm a Popover 23 | button.btn.btn-info(popover-placement='top', popover='It\'s so simple to create a tooltop for my website!', data-original-title='Twitter Bootstrap Popover') I'm a Popover 24 | button.btn.btn-warning(popover-placement='right', popover='It\'s so simple to create a tooltop for my website!', data-original-title='Twitter Bootstrap Popover') I'm a Popover 25 | button.btn.btn-danger(popover-placement='left', popover='It\'s so simple to create a tooltop for my website!', data-original-title='Twitter Bootstrap Popover') Click me! 26 | -------------------------------------------------------------------------------- /client/app/error/index.jade: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DavidKk/ngAdmin/55664d50166333d4ddbe91b84bf6bbc3868067e9/client/app/error/index.jade -------------------------------------------------------------------------------- /client/app/font-end/index.jade: -------------------------------------------------------------------------------- 1 | doctype 2 | html(lang="en-US") 3 | head 4 | meta(charset="utf-8") 5 | meta(name="viewport", content="width=device-width, initial-scale=1.0, maximum-scale=1, user-scalable=no") 6 | meta(name="description", value= pkg.description) 7 | meta(name="keywords", value= pkg.keywords) 8 | 9 | //- lt styles 10 | link(href= makeVersion('/assets/styles/bootstrap/bootstrap.min.css'), rel="stylesheet", media="screen") 11 | link(href= makeVersion('/assets/styles/font-awesome/font-awesome.min.css'), rel="stylesheet", media="screen") 12 | link(href= makeVersion('/assets/styles/ngAdmin/ngAdmin.min.css'), rel="stylesheet", media="screen") 13 | link(href= makeVersion('/assets/styles/app/font-end.min.css'), rel="stylesheet", media="screen") 14 | title Font-End | ngAdmin 15 | 16 | //- lt scripts 17 | script(src= makeVersion('/assets/scripts/script/script.min.js')) 18 | script. 19 | 'use strict' 20 | 21 | var jsfile = { 22 | angular: '#{ makeVersion("scripts/angular/angular.min.js") }' 23 | , ngRoute: '#{ makeVersion("scripts/angular-route/angular-route.min.js") }' 24 | , ngTouch: '#{ makeVersion("scripts/angular-touch/angular-touch.min.js") }' 25 | 26 | , jQuery: '//code.jquery.com/jquery-1.11.0.min.js' 27 | , highcharts: '#{ makeVersion("scripts/highcharts-4.0.4.min.js") }' 28 | , ngHeightcharts: '#{ makeVersion("scripts/highcharts-ng-0.0.8.min.js") }' 29 | 30 | , public: '#{ makeVersion("/scripts/main/" + pkg.name + ".js") }' 31 | , app: '#{ makeVersion("/scripts/main/apps/font-end.js") }' 32 | } 33 | 34 | $script(jsfile.angular, function() { 35 | //- jQuery load after angular, because the angular will auto load jQuery instead jqlit 36 | //- etc. $event or origin event, jQuery will redefine the event object. 37 | $script(jsfile.jQuery, function() { 38 | $script(jsfile.highcharts, function() { 39 | $script(jsfile.ngHeightcharts) 40 | }) 41 | }) 42 | 43 | //- Loading public module, and the page module before angular and it's plugin is ready. 44 | $script([jsfile.ngRoute, jsfile.ngTouch], function() { 45 | $script([jsfile.public, jsfile.app], function() { 46 | //- Because js file was loaded in async, we must bootstrap the extrance module. 47 | angular.bootstrap(document, ['font-end']) 48 | }) 49 | }) 50 | }) 51 | 52 | //- lt icons 53 | link(href= makeVersion("/assets/panels/ico/favicon.ico"), rel="shortcut icon") 54 | link(href= makeVersion("/assets/panels/ico/touch-icon-iphone.png"), rel="apple-touch-icon") 55 | link(href= makeVersion("/assets/panels/ico/touch-icon-ipad.png"), rel="apple-touch-icon", sizes="76x76") 56 | link(href= makeVersion("/assets/panels/ico/touch-icon-iphone-retina.png"), rel="apple-touch-icon", sizes="120x120") 57 | link(href= makeVersion("/assets/panels/ico/touch-icon-ipad-retina.png"), rel="apple-touch-icon", sizes="152x152") 58 | 59 | body -------------------------------------------------------------------------------- /client/app/simulator/scripts/app.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Entrance Module 3 | * @author 4 | */ 5 | angular.module('index', [ 6 | 'ngRoute' 7 | , 'conf.config', 'helpers.util' 8 | , 'header', 'nav' 9 | // , 'decorate' 10 | ]) 11 | 12 | .constant('TEMPLATE_PATH', '/assets/templates/simulator') 13 | 14 | .constant('NAVIGATION', [ 15 | { 16 | name: 'Simulator', key: 'index', icon: 'laptop' 17 | }, 18 | { 19 | name: 'Applications', key: 'applications', icon: 'cubes', 20 | child: [ 21 | { name: 'Docs', key: 'docs', url: '/docs', target: '_self' } 22 | ] 23 | }, 24 | { 25 | name: 'Contributors', key: 'contributors', icon: 'user-secret', 26 | child: [ 27 | { name: 'David Jones', key: 'davidjones', url: '//about.davidkk.com', target: '_self' } 28 | ] 29 | }, 30 | { 31 | name: 'Team', key: 'team', icon: 'group', 32 | child: [ 33 | { name: 'Blog', key: 'blog', url: '//blog.ishgo.cn', target: '_self' } 34 | ] 35 | } 36 | ]) 37 | 38 | .config([ 39 | '$routeProvider', '$locationProvider', 40 | 'TEMPLATE_PATH', 41 | function($routeProvider, $locationProvider, TEMPLATE_PATH) { 42 | var resolve = { 43 | checkin: [ 44 | '$q', 45 | function($q) { 46 | var deferred = $q.defer() 47 | 48 | deferred.resolve() 49 | return deferred.promise 50 | } 51 | ] 52 | } 53 | 54 | $routeProvider 55 | .when('/simulator/', { templateUrl: TEMPLATE_PATH + '/index.html', resolve: resolve }) 56 | .when('/simulator/index/', { templateUrl: TEMPLATE_PATH + '/index.html', resolve: resolve }) 57 | .when('/simulator/simulator', { templateUrl: TEMPLATE_PATH + '/index.html', resolve: resolve }) 58 | } 59 | ]) -------------------------------------------------------------------------------- /client/app/simulator/scripts/header.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Header Module 3 | * @author 4 | */ 5 | angular.module('header', [ 6 | 'services.screen' 7 | , 'ui.ngIscroll', 'ui.dropdownMenu' 8 | ]) 9 | 10 | .controller('HeaderController', [ 11 | '$rootScope', '$scope', 12 | '$screenfull', 13 | function($rootScope, $scope, $screenfull) { 14 | $scope.isFullscreen = false 15 | 16 | $scope.toggleLeftSidebar = function() { 17 | $rootScope.$broadcast('nav.$toggle') 18 | }; 19 | 20 | $scope.toggleRightSidebar = function() { 21 | $rootScope.$broadcast('chat.$toggle') 22 | }; 23 | 24 | $scope.screenfull = function() { 25 | $screenfull.toggle() 26 | } 27 | 28 | $scope.logout = function() { 29 | window.location.reload() 30 | } 31 | 32 | $rootScope.$on('fullscreenchange', function() { 33 | $scope.isFullscreen = $screenfull.isFullscreen 34 | $scope.$digest() 35 | }) 36 | } 37 | ]) -------------------------------------------------------------------------------- /client/app/simulator/scripts/nav.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Nav Module 3 | * @author 4 | */ 5 | angular.module('nav', [ 6 | 'ngRoute' 7 | , 'ui.slidedown', 'ui.ngIscroll' 8 | , 'conf.config' 9 | ]) 10 | 11 | .directive('navLayout', [ 12 | '$rootScope', 13 | function($rootScope) { 14 | return { 15 | restrict: 'A', 16 | link: function($scope, $element, $attrs, ctrl) { 17 | 'use strict' 18 | 19 | $rootScope.$on('nav.$toggle', function($event, isOpen) { 20 | $scope.isOpen = angular.isDefined(isOpen) ? !!isOpen : !$scope.isOpen 21 | $scope.isOpen ? open() : close() 22 | }) 23 | 24 | $scope.isOpen = !!$attrs.open 25 | $scope.isOpen ? open() : close() 26 | 27 | $scope.$on('$routeChangeStart', close) 28 | 29 | function open() { 30 | $scope.isOpen = true 31 | $element.removeClass('minify') 32 | angular.element(document.body).addClass('show-nav') 33 | } 34 | 35 | function close() { 36 | $scope.isOpen = false 37 | $element.addClass('minify') 38 | angular.element(document.body).removeClass('show-nav') 39 | } 40 | } 41 | } 42 | } 43 | ]) 44 | 45 | .controller('NavController', [ 46 | '$scope', '$http', '$route', '$location', 47 | 'NAVIGATION', 48 | function($scope, $http, $route, $location, NAVIGATION) { 49 | var exports = this; 50 | 51 | $scope.paths; 52 | $scope.navigations = NAVIGATION; 53 | $scope.navs = []; 54 | $scope.hasSub = false; 55 | $scope.filter = ''; 56 | 57 | exports.reload = function() { 58 | var i = 0 59 | , paths = $location.$$path 60 | .replace(/^\//, '') 61 | .replace(/\/$/, '') 62 | .split('\/') 63 | , cur = paths[1] 64 | , len = $scope.navigations.length 65 | , index 66 | , nav 67 | , j 68 | , c 69 | , clen 70 | , t; 71 | 72 | for (; i < len; i ++) { 73 | nav = $scope.navigations[i] 74 | 75 | if (cur === nav.key) { 76 | $scope.navs = [cur] 77 | break 78 | } 79 | else { 80 | for (j = 0, c = nav.child || [], clen = c.length; j < clen; j ++) { 81 | t = c[j].key.split('/') 82 | 83 | if (cur == t[0]) { 84 | $scope.navs = [nav.key, cur] 85 | break 86 | } 87 | } 88 | } 89 | } 90 | 91 | $scope.paths = paths 92 | } 93 | 94 | exports.filter = function(str) { 95 | var regexp = new RegExp(str, 'ig') 96 | 97 | angular.forEach($scope.navigations, function(nav) { 98 | if (angular.isArray(nav.child)) { 99 | nav.hidden = true 100 | nav.open = false 101 | 102 | angular.forEach(nav.child, function(item) { 103 | if (!item.name.match(regexp)) { 104 | item.hidden = true 105 | } 106 | else { 107 | nav.open = true 108 | nav.hidden = item.hidden = false 109 | } 110 | }) 111 | } 112 | else { 113 | nav.hidden = !nav.name.match(regexp) 114 | } 115 | }) 116 | } 117 | 118 | $scope.$watch('filter', function(filter) { 119 | exports.filter(filter) 120 | }) 121 | 122 | $scope.$on('$routeChangeSuccess', exports.reload) 123 | exports.reload() 124 | } 125 | ]) -------------------------------------------------------------------------------- /client/app/simulator/styles/bootstrap.less: -------------------------------------------------------------------------------- 1 | // Index Page 2 | // @author 3 | 4 | @import "variables/defination"; 5 | @import "mixins/lesshat/lesshat"; 6 | @import "mixins/gradients"; 7 | @import "mixins/clearfix"; 8 | @import "mixins/arrow"; 9 | @import "mixins/text-overflow"; 10 | @import "mixins/buttons"; 11 | @import "mixins/progress-bar"; 12 | 13 | // Effects 14 | @import "effects/animation"; 15 | 16 | // Partials Modules 17 | @import "simulator/main"; 18 | @import "simulator/tablet"; 19 | @import "simulator/mobile"; 20 | 21 | // Other Modules 22 | @import "decorate/main"; 23 | -------------------------------------------------------------------------------- /client/app/simulator/styles/decorate/main.less: -------------------------------------------------------------------------------- 1 | // Decoration 2 | // ----------------- 3 | 4 | #decorate-container { 5 | padding: 0; 6 | height: 100%; 7 | overflow: hidden; 8 | 9 | .carousel-setting { 10 | padding-bottom: 100px; 11 | 12 | .preview-block { 13 | .media { 14 | padding: 10px; 15 | position: relative; 16 | display: inline-block; 17 | float: left; 18 | 19 | .pic { 20 | position: relative; 21 | display: block; 22 | width: 80px; 23 | height: 80px; 24 | } 25 | 26 | img { 27 | position: absolute; 28 | top: 0; 29 | right: 0; 30 | bottom: 0; 31 | left: 0; 32 | display: block; 33 | max-width: 100%; 34 | max-height: 100%; 35 | } 36 | } 37 | 38 | .file { 39 | margin-left: 100px; 40 | padding: 15px 0; 41 | 42 | .name { 43 | .text-overflow(); 44 | margin-bottom: 6px; 45 | color: lighten(@text-color, 10%); 46 | font-size: 16px; 47 | } 48 | 49 | .size:after { 50 | content: " 像素"; 51 | } 52 | } 53 | } 54 | 55 | .album-group { 56 | } 57 | 58 | .album .media { 59 | > img { 60 | display: block; 61 | margin-bottom: 10px; 62 | width: 100%; 63 | } 64 | 65 | a.remove { 66 | position: absolute; 67 | top: 3px; 68 | right: 20px; 69 | z-index: 99; 70 | border: 2px solid #fff; 71 | border-radius: 100%; 72 | background-color: #666; 73 | width: 17px; 74 | height: 17px; 75 | cursor: pointer; 76 | text-align: center; 77 | color: #fff; 78 | font-size: 12px; 79 | line-height: 13px; 80 | } 81 | } 82 | 83 | .album-block .media { 84 | position: relative; 85 | display: inline-block; 86 | float: left; 87 | width: 160px; 88 | height: 80px; 89 | 90 | > img { 91 | position: absolute; 92 | left: 0; 93 | right: 0; 94 | top: 0; 95 | margin: 0 auto; 96 | width: auto; 97 | height: auto; 98 | max-width: 100%; 99 | max-height: 100%; 100 | } 101 | } 102 | 103 | .album-block .inner { 104 | margin-left: 170px; 105 | 106 | .selecter:last-child { 107 | margin-bottom: 0 !important; 108 | } 109 | } 110 | } 111 | 112 | .funcnav-setting { 113 | .style-group { 114 | 115 | } 116 | 117 | .style { 118 | display: inline-block; 119 | float: left; 120 | padding: 15px 15px 0 15px; 121 | width: 50%; 122 | min-height: 1px; 123 | cursor: pointer; 124 | 125 | img { 126 | margin-top: 10px; 127 | width: 100%; 128 | } 129 | } 130 | } 131 | 132 | .list-setting { 133 | 134 | } 135 | 136 | .photo-setting { 137 | 138 | } 139 | 140 | .photoes-setting { 141 | 142 | } 143 | 144 | .topic-setting { 145 | 146 | } 147 | 148 | .ad-setting { 149 | 150 | } 151 | 152 | .home-setting { 153 | 154 | } 155 | 156 | .split-setting { 157 | 158 | } 159 | } -------------------------------------------------------------------------------- /client/app/simulator/styles/effects/animation.less: -------------------------------------------------------------------------------- 1 | 2 | 3 | .keyframes(~'fade-up-in, 0% { opacity: 0; transform: translateY(40px); } 100% { opacity: 1; transform: translateY(0); }'); 4 | .keyframes(~'fade-up-out, 0% { opacity: 1; transform: translateY(0); } 100% { opacity: 0; transform: translateY(-40px); }'); 5 | .keyframes(~'fade-up-in-sm, 0% { opacity: 0; transform: translateY(10px); } 100% { opacity: 1; transform: translateY(0); }'); 6 | .keyframes(~'fade-up-out-sm, 0% { opacity: 1; transform: translateY(0); } 100% { opacity: 0; transform: translateY(-10px); }'); 7 | .keyframes(~'fade-in, 0% { opacity: 0; } 100% { opacity: 1; }'); 8 | .keyframes(~'fade-out, 0% { opacity: 1; } 100% { opacity: 0; }'); 9 | 10 | .keyframes(~'shake, 0% { transform: translate(2px, 1px) rotate(0deg); } 10% { transform: translate(-1px, -2px) rotate(-2deg); } 20% { transform: translate(-3px, 0px) rotate(3deg); } 30% { transform: translate(0px, 2px) rotate(0deg); } 40% { transform: translate(1px, -1px) rotate(1deg); } 50% { transform: translate(-1px, 2px) rotate(-1deg); } 60% { transform: translate(-3px, 1px) rotate(0deg); } 70% { transform: translate(2px, 1px) rotate(-2deg); } 80% { transform: translate(-1px, -1px) rotate(4deg); } 90% { transform: translate(2px, 2px) rotate(0deg); } 100% { transform: translate(1px, -2px) rotate(-1deg); }'); 11 | 12 | .animate-fade-up.in { 13 | .animation(.8s fade-up-in); 14 | } 15 | 16 | .animate-fade-up.out { 17 | .animation(.8s fade-up-out); 18 | } 19 | 20 | .animate-fade.in { 21 | .animation(.8s fade-in); 22 | } 23 | 24 | .animate-fade.out { 25 | .animation(.8s fade-out); 26 | } 27 | 28 | .animate-shake { 29 | .animation(.8s shake 0 infinite linear); 30 | // .transform-origin(50% 100%); 31 | } -------------------------------------------------------------------------------- /client/app/simulator/styles/simulator/mobile.less: -------------------------------------------------------------------------------- 1 | 2 | 3 | @media (max-width: @screen-xs-max) { 4 | #simulator-container { 5 | .phone-model { 6 | box-sizing: border-box; 7 | margin-bottom: 0; 8 | border-radius: 0; 9 | padding: 0; 10 | width: 100%; 11 | height: 100%; 12 | background-color: transparent; 13 | 14 | &:before, 15 | &:after { 16 | display: none; 17 | } 18 | } 19 | 20 | .simulator-heading { 21 | height: 50px; 22 | 23 | h1,h2,h3,h4,h5,h6 { 24 | display: none; 25 | } 26 | 27 | .btn.tt { 28 | width: 50px; 29 | height: 50px; 30 | line-height: 50px; 31 | } 32 | } 33 | 34 | .viewport-layout { 35 | .viewport-scroll { 36 | padding: 0; 37 | height: 100%; 38 | } 39 | } 40 | } 41 | } -------------------------------------------------------------------------------- /client/app/simulator/styles/simulator/tablet.less: -------------------------------------------------------------------------------- 1 | 2 | 3 | @media (max-width: unit((380 + 380 + 250 + 220), px)) { 4 | #simulator-container { 5 | .component-layout { 6 | .transform(translate(-250px, 0)); 7 | } 8 | 9 | .setting-layout { 10 | .transform(translate(380px, 0)); 11 | } 12 | 13 | .viewport-layout { 14 | margin: 0; 15 | } 16 | 17 | .setting-layout.opened, 18 | .component-layout.opened { 19 | .transform(translate(0, 0)); 20 | } 21 | } 22 | } -------------------------------------------------------------------------------- /client/app/simulator/templates/partials/header.jade: -------------------------------------------------------------------------------- 1 | header#header-container(ng-controller='HeaderController') 2 | .row 3 | .navbar 4 | ul.notify-header.pull-left 5 | li.bars 6 | a.menu-toggle(ng-click='toggleLeftSidebar()') 7 | i.fa.fa-navicon 8 | 9 | li.hidden-sm 10 | a(ng-click='screenfull()', title='{{ isFullscreen ? "Exit" : "Full Screen" }}') 11 | i.fa(ng-class='{ "fa-compress": isFullscreen, "fa-expand": !isFullscreen }') 12 | 13 | li.dropdown-submenu.profile(dropdown-menu) 14 | a.avator(dropdown-menu-toggle) 15 | img(src='//q.qlogo.cn/qqapp/100229475/70F82D66FE3FD280B8BC8D789E5CE979/100') 16 | span.name David Jones 17 | 18 | ul.dropdown-menu-profile.dropdown-menu.pull-right 19 | .dropdown-menu-arrow 20 | li 21 | a 22 | i.fa.fa-user 23 | | My Profile 24 | li 25 | a 26 | i.fa.fa-cog 27 | | Account Settings 28 | li 29 | a 30 | i.fa.fa-question 31 | | Help 32 | li 33 | a(ng-click='logout()') 34 | i.fa.fa-power-off 35 | | Log Out 36 | -------------------------------------------------------------------------------- /client/app/simulator/templates/partials/nav.jade: -------------------------------------------------------------------------------- 1 | nav#nav-container(ng-controller='NavController') 2 | .brand-sidebar 3 | a(href='./', target='_self') ngAdmin 4 | 5 | ul.nav.nav-stacked 6 | li.search-sidebar 7 | input(ng-model='filter', name='filter', type='search', placeholder='Search something...') 8 | a 9 | i.fa.fa-search 10 | 11 | li.profile-sidebar.online 12 | .face.dropdown-submenu.pull-left.open 13 | a.avator 14 | img(src='//q.qlogo.cn/qqapp/100229475/70F82D66FE3FD280B8BC8D789E5CE979/100') 15 | 16 | .info.dropdown-submenu 17 | a.name David Jones 18 | span.role Administrator 19 | a.status 20 | 21 | .scroll-viewport 22 | .viewport-scroll(ng-iscroll) 23 | ul.nav.nav-stacked(slidedown-group) 24 | li(slidedown, ng-repeat='nav in navigations', 25 | isopen='{{ nav.key == navs[0] && paths.length > 1 }}', 26 | ng-hide='nav.hidden', 27 | ng-class='{\ 28 | "dropdown-submenu": nav.child,\ 29 | "active": nav.key == navs[0] && paths.length === 1\ 30 | }') 31 | 32 | a(ng-if='!nav.child', ng-href='{{ nav.url || "/simulator/" + nav.key }}/') 33 | i(class='fa fa-{{ nav.icon }}') 34 | span {{ nav.name }} 35 | 36 | a(ng-if='nav.child', slidedown-toggle) 37 | i(class='fa fa-{{ nav.icon }}') 38 | span {{ nav.name }} 39 | 40 | ul.nav-submenu(ng-if='nav.child', slidedown-list) 41 | li(ng-repeat='menu in nav.child', 42 | ng-hide='menu.hidden', 43 | ng-class="{\ 44 | active: menu.key == navs[1] || menu.key == paths.slice(1, paths.length).join('/')\ 45 | }") 46 | a(ng-href='{{ menu.url || "/simulator/" + menu.key }}/', target='{{ menu.target }}') 47 | i(class='fa fa-circle-o') 48 | | {{ menu.name }} 49 | -------------------------------------------------------------------------------- /client/app/welcome/scripts/app.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Welcome 3 | * @author 4 | */ 5 | angular.module('welcome', ['ngRoute', 'conf.config']) 6 | 7 | .config([ 8 | '$routeProvider', 9 | function($routeProvider) { 10 | 'use strict' 11 | 12 | $routeProvider.when('/welcome/', { 13 | controller: 'WelcomeController' 14 | }) 15 | } 16 | ]) 17 | 18 | .controller('WelcomeController', [ 19 | '$scope', 20 | function($scope) { 21 | 'use strict' 22 | 23 | $scope.method = 'login' 24 | 25 | $scope.changeChannel = function(method) { 26 | $scope.method = method 27 | } 28 | } 29 | ]) 30 | 31 | .controller('FormController', [ 32 | '$rootScope', '$scope', 33 | function($rootScope, $scope) { 34 | 'use strict' 35 | 36 | $scope.username = '' // 用户名 37 | $scope.password = '' // 密码 38 | $scope.captcha = '' // 验证码 39 | $scope.captchaImage = '' // 验证码图片 40 | $scope.disabled = false // 当前是否可用 41 | 42 | $scope.newCaptcha = function() { 43 | if ($scope.disabled) { 44 | return 45 | } 46 | // $scope.captchaImage = 'http://api.xiaozhisong.com/captcha/?' + Date.now(); 47 | } 48 | 49 | $scope.submit = function(evt) { 50 | if ($scope.disabled || (evt && evt.keyCode && evt.keyCode !== 13)) { 51 | return 52 | } 53 | 54 | var validUsername = $scope.form.username.$viewValue 55 | , validPassword = $scope.form.password.$viewValue 56 | , validCaptcha = $scope.form.captcha.$viewValue 57 | 58 | if (validUsername && validPassword && validCaptcha) { 59 | $scope.disabled = true 60 | 61 | $user.login({ username: validUsername, password: validPassword, captcha: validCaptcha }) 62 | .then(function(data) { 63 | window.location.replace('/index/') 64 | }) 65 | .catch(function(msg) { 66 | $scope.disabled = false 67 | $scope.captcha = '' 68 | $scope.newCaptcha() 69 | }) 70 | } 71 | } 72 | 73 | $scope.newCaptcha() 74 | } 75 | ]) 76 | -------------------------------------------------------------------------------- /client/app/welcome/styles/bootstrap.less: -------------------------------------------------------------------------------- 1 | // Welcome Page 2 | // @author 3 | 4 | @import "./client/public/styles/variables/defination"; 5 | @import "./client/public/styles/mixins/lesshat/lesshat"; 6 | @import "./client/public/styles/mixins/clearfix"; 7 | @import "./client/public/styles/mixins/arrow"; 8 | 9 | @import "index/main"; -------------------------------------------------------------------------------- /client/app/welcome/styles/index/main.less: -------------------------------------------------------------------------------- 1 | .welcome-page { 2 | height: 100%; 3 | background-color: rgb(48, 54, 65); 4 | } 5 | 6 | #welcome-container { 7 | height: 100%; 8 | 9 | .header-module { 10 | .arrow-mixin(16px, rgb(55, 62, 74), bottom, 50%); 11 | 12 | padding: 80px 0 60px 0; 13 | background-color: rgb(55, 62, 74); 14 | position: relative; 15 | text-align: center; 16 | 17 | h1.caption { 18 | margin-bottom: 14px; 19 | color: rgba(255, 255, 255, 1); 20 | font-size: 42px; 21 | } 22 | 23 | p.desc { 24 | color: rgb(148, 148, 148); 25 | 26 | a { 27 | color: rgba(255, 255, 255, .7); 28 | 29 | &:hover { 30 | color: rgba(255, 255, 255, 1); 31 | } 32 | } 33 | } 34 | } 35 | 36 | .form-module { 37 | padding-top: 60px; 38 | 39 | .input-group { 40 | padding-top: 6px; 41 | padding-bottom: 6px; 42 | border: 1px solid rgb(55, 62, 74); 43 | .border-radius(3px); 44 | width: 100%; 45 | background: rgb(55, 62, 74); 46 | .transition(all 300ms ease-in-out); 47 | 48 | &:active { 49 | border-color: rgba(98, 111, 133, 0.5); 50 | } 51 | } 52 | 53 | .input-group .input-group-addon { 54 | position: relative; 55 | border: 0; 56 | width: 37px; 57 | text-align: center; 58 | color: rgb(145, 145, 145); 59 | font-size: 16px; 60 | background: rgba(0, 0, 0, 0); 61 | 62 | &:after { 63 | display: block; 64 | position: absolute; 65 | right: 0; 66 | top: 0; 67 | height: 100%; 68 | width: 1px; 69 | background: rgb(69, 74, 84); 70 | .transform(scaleY(.56)); 71 | content: ''; 72 | } 73 | } 74 | 75 | .input-group .form-control { 76 | display: block; 77 | padding: 6px 12px; 78 | width: 100%; 79 | height: 31px; 80 | .border-radius(0); 81 | border-width: 0; 82 | line-height: @line-height-base; 83 | color: rgb(255, 255, 255); 84 | font-size: 16px; 85 | outline: 0; 86 | .box-shadow(none); 87 | background: none transparent; 88 | .transition(border-color ease-in-out .15s,box-shadow ease-in-out .15s); 89 | } 90 | 91 | .captcha { 92 | position: absolute; 93 | right: 10px; 94 | width: 100px; 95 | height: 34px; 96 | cursor: pointer; 97 | } 98 | 99 | .btn-login { 100 | .border-radius(0); 101 | .transition(all 300ms ease-in-out); 102 | 103 | padding: 13px 20px; 104 | border: 1px solid rgb(69, 74, 84); 105 | background-color: rgb(48, 54, 65); 106 | outline: none !important; 107 | text-align: left; 108 | color: #fff; 109 | font-size: 16px; 110 | 111 | & > i { 112 | margin-top: 4px; 113 | float: right; 114 | font-size: 16px; 115 | } 116 | } 117 | 118 | .btn-login:active, 119 | .btn-login:focus { 120 | color: #fff; 121 | } 122 | 123 | .btn-login:hover { 124 | color: #fff; 125 | background-color: rgb(55, 62, 74); 126 | } 127 | } 128 | 129 | .divider-module { 130 | padding-top: 20px; 131 | text-align: center; 132 | color: rgb(148, 148, 148); 133 | font-size: 12px; 134 | 135 | .line { 136 | display: block; 137 | } 138 | } 139 | 140 | .footer-module { 141 | padding-top: 20px; 142 | padding-bottom: 30px; 143 | text-align: center; 144 | color: rgb(148, 148, 148); 145 | 146 | .channel { 147 | display: inline-block; 148 | margin-bottom: 10px; 149 | color: rgba(255, 255, 255, .7); 150 | 151 | &:hover { 152 | color: rgba(255, 255, 255, 1); 153 | } 154 | } 155 | 156 | .copyright { 157 | font-size: 14px; 158 | } 159 | } 160 | } -------------------------------------------------------------------------------- /client/public/audio/alert.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DavidKk/ngAdmin/55664d50166333d4ddbe91b84bf6bbc3868067e9/client/public/audio/alert.mp3 -------------------------------------------------------------------------------- /client/public/audio/alert.ogg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DavidKk/ngAdmin/55664d50166333d4ddbe91b84bf6bbc3868067e9/client/public/audio/alert.ogg -------------------------------------------------------------------------------- /client/public/fonts/crimsontext/crimsontext-bolditalic.css: -------------------------------------------------------------------------------- 1 | @font-face { 2 | font-family: 'CrimsonTextBoldItalic'; 3 | src: url('crimsontext-bolditalic.eot'); 4 | src: url('crimsontext-bolditalic.eot') format('embedded-opentype'), 5 | url('crimsontext-bolditalic.woff') format('woff'), 6 | url('crimsontext-bolditalic.ttf') format('truetype'), 7 | url('crimsontext-bolditalic.svg#CrimsonTextBoldItalic') format('svg'); 8 | } 9 | -------------------------------------------------------------------------------- /client/public/fonts/crimsontext/crimsontext-bolditalic.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DavidKk/ngAdmin/55664d50166333d4ddbe91b84bf6bbc3868067e9/client/public/fonts/crimsontext/crimsontext-bolditalic.eot -------------------------------------------------------------------------------- /client/public/fonts/crimsontext/crimsontext-bolditalic.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DavidKk/ngAdmin/55664d50166333d4ddbe91b84bf6bbc3868067e9/client/public/fonts/crimsontext/crimsontext-bolditalic.woff -------------------------------------------------------------------------------- /client/public/panels/david-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DavidKk/ngAdmin/55664d50166333d4ddbe91b84bf6bbc3868067e9/client/public/panels/david-logo.png -------------------------------------------------------------------------------- /client/public/panels/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DavidKk/ngAdmin/55664d50166333d4ddbe91b84bf6bbc3868067e9/client/public/panels/favicon.ico -------------------------------------------------------------------------------- /client/public/panels/sprites.less.mustache: -------------------------------------------------------------------------------- 1 | 2 | .sp-width(@sprite) { 3 | width: ~`"@{sprite}".split(', ')[4]`; 4 | } 5 | 6 | .sp-height(@sprite) { 7 | height: ~`"@{sprite}".split(', ')[5]`; 8 | } 9 | 10 | .sp-position(@sprite) { 11 | @sp-offset-x: ~`"@{sprite}".split(', ')[2]`; 12 | @sp-offset-y: ~`"@{sprite}".split(', ')[3]`; 13 | background-position: @sp-offset-x @sp-offset-y; 14 | } 15 | 16 | .sp-image(@sprite) { 17 | {{! DEV: We perform a slice due to a trailing brace from string coercion of arrays }} 18 | @sp-image: ~`"@{sprite}".split(', ')[8].slice(1, -2)`; 19 | background-image: url(@sp-image); 20 | } 21 | 22 | .sprite(@sprite) { 23 | .sp-width(@sprite); 24 | .sp-height(@sprite); 25 | 26 | &:before { 27 | .transform-origin(0 0); 28 | .sp-position(@sprite); 29 | .sp-width(@sprite); 30 | .sp-height(@sprite); 31 | } 32 | } 33 | 34 | .sprite { 35 | display: inline-block; 36 | vertical-align: middle; 37 | 38 | &:before { 39 | display: block; 40 | content: ''; 41 | background: url({{& options.basepath}}) no-repeat 0 0 transparent; 42 | } 43 | } 44 | 45 | .sp-loop() { 46 | {{#items}} 47 | @{{name}}: {{px.x}} {{px.y}} {{px.offset_x}} {{px.offset_y}} {{px.width}} {{px.height}} {{px.total_width}} {{px.total_height}} '{{{escaped_image}}}'; 48 | .{{name}} { 49 | .sprite(@{{name}}); 50 | } 51 | {{/items}} 52 | } 53 | 54 | .sp-loop(); -------------------------------------------------------------------------------- /client/public/scripts/conf/config.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Config 3 | * @author 4 | */ 5 | angular.module('conf.config', [ 6 | 'ngRoute' 7 | , 'helpers.util' 8 | ]) 9 | 10 | // Debug Config 11 | .config([ 12 | '$logProvider', 13 | function($logProvider) { 14 | 'use strict' 15 | 16 | var uri 17 | , params 18 | , isDebug; 19 | 20 | if (angular.isBoolean(angular.$debug)) { 21 | $logProvider.debugEnabled(angular.$debug) 22 | } 23 | else { 24 | uri = angular.parseUrl(window.location.href) 25 | params = angular.parseObject(uri.query) 26 | isDebug = 1 == params.debug 27 | 28 | $logProvider.debugEnabled(isDebug) 29 | angular.$debug = isDebug 30 | } 31 | } 32 | ]) 33 | 34 | // Setting ajax configuration. 35 | .config([ 36 | '$httpProvider', 37 | function ($httpProvider) { 38 | 'use strict' 39 | 40 | /** 41 | * Reset headers to avoid OPTIONS request (aka preflight) 42 | * Angular 默认没有设置 urlencoded 43 | */ 44 | $httpProvider.defaults.headers.common = {} 45 | $httpProvider.defaults.headers.post = { 46 | 'Content-Type': 'application/x-www-form-urlencoded' 47 | } 48 | 49 | $httpProvider.defaults.headers.put = {} 50 | $httpProvider.defaults.headers.patch = {} 51 | $httpProvider.defaults.withCredentials = true 52 | $httpProvider.defaults.transformRequest = [ 53 | function(data) { 54 | return angular.isObject(data) && String(data) !== '[object File]' 55 | ? angular.parseString(data) 56 | : data 57 | } 58 | ] 59 | 60 | $httpProvider.interceptors.push('httpInterceptor') 61 | } 62 | ]) 63 | 64 | // Setup the base router. 65 | .config([ 66 | '$routeProvider', '$locationProvider', 67 | function($routeProvider, $locationProvider) { 68 | 'use strict' 69 | 70 | /** 71 | * 默认路由 72 | * 默认路由跳转到404页面 73 | */ 74 | $routeProvider 75 | .when('/404/', { 76 | resolve: { 77 | redirect: function() { 78 | window.location.replace('/error/404/') 79 | } 80 | } 81 | }) 82 | .otherwise({ 83 | redirectTo: '/error/404/' 84 | }) 85 | 86 | $locationProvider.html5Mode({ 87 | enabled: true, 88 | requireBase: false 89 | }) 90 | } 91 | ]) 92 | 93 | // Setting the error response of ajax request. 94 | .factory('httpInterceptor', [ 95 | '$rootScope', '$q', 96 | function($rootScope, $q) { 97 | 'use strict' 98 | 99 | return { 100 | responseError: function(rejection) { 101 | 400 <= rejection.status && rejection.status < 500 102 | ? $rootScope.$broadcast('notify', 'sorry!系统无法访问,请刷新再试或联系客服人员。状态:' + rejection.status, 'error') 103 | : 500 <= rejection.status && rejection.status < 600 104 | ? $rootScope.$broadcast('notify', 'sorry!系统繁忙,请稍后再试或联系客服人员。状态:' + rejection.status, 'error') 105 | : $rootScope.$broadcast('notify', 'sorry!系统出错,请立即联系客服人员。状态:' + rejection.status, 'error') 106 | 107 | return $q.reject(rejection) 108 | } 109 | } 110 | } 111 | ]) -------------------------------------------------------------------------------- /client/public/scripts/conf/constants.js: -------------------------------------------------------------------------------- 1 | /** 2 | * constants 3 | * @author 4 | */ 5 | angular.module('conf.constants', []) -------------------------------------------------------------------------------- /client/public/scripts/conf/validator.js: -------------------------------------------------------------------------------- 1 | /** 2 | * validators 3 | * @author 4 | */ 5 | angular.module('conf.validator', []) -------------------------------------------------------------------------------- /client/public/scripts/helpers/date.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Date 3 | * @author 4 | */ 5 | angular.module('helpers.date', []) 6 | 7 | .run([ 8 | function() { 9 | 'use strict' 10 | 11 | /** 12 | * dateAdjust 调节时间,对时间进行加减运算 13 | * @param {Date} date Date 对象 14 | * @param {String} part 需要修改的类型 15 | * @param {Integer} amount 需要调整的值 16 | * 17 | * Example: 18 | * angular.dateAdjust(new Date(), 'years', +1); 19 | */ 20 | angular.dateAdjust = function(date, part, amount) { 21 | part = part.toLowerCase() 22 | amount = amount || 0 23 | 24 | var map = { 25 | years: 'FullYear', months: 'Month', weeks: 'Hours', days: 'Hours', hours: 'Hours', 26 | minutes: 'Minutes', seconds: 'Seconds', milliseconds: 'Milliseconds', 27 | utcyears: 'UTCFullYear', utcmonths: 'UTCMonth', utcweeks: 'UTCHours', utcdays: 'UTCHours', 28 | utchours: 'UTCHours', utcminutes: 'UTCMinutes', utcseconds: 'UTCSeconds', utcmilliseconds: 'UTCMilliseconds' 29 | } 30 | , mapPart = map[part] 31 | 32 | if (part == 'weeks' || part == 'utcweeks') { 33 | amount *= 168 34 | } 35 | 36 | if (part == 'days' || part == 'utcdays') { 37 | amount *= 24 38 | } 39 | 40 | var setFucName = 'set' + mapPart 41 | , getFuncName = 'get'+ mapPart 42 | 43 | date[setFucName](date[getFuncName]() + amount) 44 | } 45 | 46 | /** 47 | * dateEach 遍历日期 48 | * @param {Date} beginDate 开始时间 49 | * @param {Date} endDate 结束时间 50 | * @param {Function} callback 回调函数 51 | * @param {String} part(optional) 需要遍历的部分(默认为 'days') 52 | * @param {Number} step(optional) 每次跳跃数字(默认为 1) 53 | * @param {Object} bind(optional) 回调函数从属的对象(默认为 window) 54 | * 55 | * Example: 56 | * angular.dateEach(DateA, DateB, function(currentDate, times, beginDate, endDate) { 57 | * // Something to do... 58 | * }) 59 | */ 60 | angular.dateEach = function(beginDate, endDate, callback, part, step, bind) { 61 | var part = 'string' === typeof part ? part : 'days' 62 | , step = 'number' === typeof step ? step : 1 63 | , bind = bind || window 64 | , fromDate = new Date(beginDate.getTime()) 65 | , toDate = new Date(endDate.getTime()) 66 | , pm = fromDate <= toDate ? 1 : -1 67 | , i = 0 68 | 69 | while ((pm === 1 && fromDate <= toDate) || (pm === -1 && fromDate >= toDate)) { 70 | if (callback.call(bind, fromDate, i, beginDate, endDate) === false) { 71 | break 72 | } 73 | 74 | i += step 75 | angular.dateAdjust(fromDate, part, step*pm) 76 | } 77 | } 78 | } 79 | ]) 80 | -------------------------------------------------------------------------------- /client/public/scripts/helpers/devices.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Date 3 | * @author 4 | */ 5 | angular.module('helpers.devices', []) 6 | 7 | .config([ 8 | function() { 9 | 'use strict' 10 | 11 | // 移动端机器类型 12 | angular.device = (/android|webos|iphone|ipad|ipod|blackberry|iemobile|opera mini/i.test(navigator.userAgent.toLowerCase())) 13 | 14 | // 低版本安卓机 15 | angular.isBadAndroid = /Android /.test(window.navigator.appVersion) && !(/Chrome\/\d/.test(window.navigator.appVersion)) 16 | 17 | // PC浏览器类型 18 | angular.browser = (function() { 19 | var matched 20 | , browser 21 | , uaMatch = function(ua) { 22 | ua = ua.toLowerCase() 23 | 24 | var match = /(opr)[\/]([\w.]+)/.exec(ua) 25 | || /(chrome)[ \/]([\w.]+)/.exec( ua ) 26 | || /(version)[ \/]([\w.]+).*(safari)[ \/]([\w.]+)/.exec(ua) 27 | || /(webkit)[ \/]([\w.]+)/.exec( ua ) 28 | || /(opera)(?:.*version|)[ \/]([\w.]+)/.exec( ua ) 29 | || /(msie) ([\w.]+)/.exec( ua ) 30 | || ua.indexOf("trident") >= 0 && /(rv)(?::| )([\w.]+)/.exec( ua ) 31 | || ua.indexOf("compatible") < 0 && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec( ua ) 32 | || [] 33 | 34 | , platform_match = /(ipad)/.exec(ua) 35 | || /(iphone)/.exec( ua ) 36 | || /(android)/.exec( ua ) 37 | || /(windows phone)/.exec(ua) 38 | || /(win)/.exec( ua ) 39 | || /(mac)/.exec( ua ) 40 | || /(linux)/.exec( ua ) 41 | || [] 42 | 43 | return { 44 | browser: match[ 3 ] || match[ 1 ] || "", 45 | version: match[ 2 ] || "0", 46 | platform: platform_match[0] || "" 47 | } 48 | } 49 | 50 | matched = uaMatch(window.navigator.userAgent) 51 | browser = {} 52 | 53 | if (matched.browser) { 54 | browser[ matched.browser] = true 55 | browser.version = matched.version 56 | browser.versionNumber = parseInt(matched.version) 57 | } 58 | 59 | if (matched.platform) { 60 | browser[ matched.platform] = true 61 | } 62 | 63 | // Chrome, Opera 15+ and Safari are webkit based browsers 64 | if (browser.chrome || browser.opr || browser.safari) { 65 | browser.webkit = true 66 | } 67 | 68 | var ie 69 | , opera 70 | , android 71 | 72 | // IE11 has a new token so we will assign it msie to avoid breaking changes 73 | if (browser.rv) { 74 | ie = 'msie' 75 | matched.browser = ie 76 | browser[ie] = true 77 | } 78 | 79 | // Opera 15+ are identified as opr 80 | if (browser.opr) { 81 | opera = 'opera' 82 | matched.browser = opera 83 | browser[opera] = true 84 | } 85 | 86 | // Stock Android browsers are marked as safari on Android. 87 | if (browser.safari && browser.android) { 88 | android = 'android' 89 | matched.browser = android 90 | browser[android] = true 91 | } 92 | 93 | // Assign the name and platform variable 94 | browser.name = matched.browser 95 | browser.platform = matched.platform 96 | return browser 97 | })() 98 | } 99 | ]) -------------------------------------------------------------------------------- /client/public/scripts/helpers/file.js: -------------------------------------------------------------------------------- 1 | /** 2 | * File 3 | * @author 4 | */ 5 | angular.module('helpers.file', []) 6 | 7 | .config([ 8 | function() { 9 | 'use strict' 10 | 11 | /** 12 | * getFileExt 获取文件后缀名 13 | * @param {String} filename 文件名 14 | * @return {String} 15 | */ 16 | angular.getFileExt = function(filename) { 17 | var extStart = filename.lastIndexOf('.') + 1 18 | return filename.substring(extStart, filename.length) 19 | } 20 | 21 | /** 22 | * isImage 是否为图片 23 | * @param {String} filename 文件名称 24 | * @param {Array} allowType 允许类型 25 | * @return {Boolean} 26 | */ 27 | angular.isImage = function(filename, allowType) { 28 | allowType = $.isArray(allowType) 29 | ? allowType 30 | : ['JPG', 'JPEG', 'GIF', 'PNG', 'APNG', 'BMP'] 31 | 32 | var ext = angular.$getFileExt(filename) 33 | return -1 !== $.inArray(ext.toUpperCase(), allowType) 34 | } 35 | } 36 | ]) 37 | -------------------------------------------------------------------------------- /client/public/scripts/helpers/queue.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Queue 3 | * @author 4 | */ 5 | angular.module('helpers.queue', []) 6 | 7 | .config([ 8 | function() { 9 | 'use strict' 10 | 11 | /** 12 | * queue 异步队列 13 | * @param {Array} queue 队列方法 14 | * @return {Object} 异步队列 15 | * 16 | * Example: 17 | * var i = 0; 18 | * function f1(next) { 19 | * setTimeout(function() { 20 | * console.log(i ++); 21 | * next && next(); 22 | * }, 1000); 23 | * } 24 | * 25 | * angular.syncQueue([f1, f1, f1]); 26 | * run -> sleep 1s -> 1 -> sleep 1s -> 2 -> sleep 1s -> 3 -> end 27 | */ 28 | angular.syncQueue = (function() { 29 | var SyncQueue = function(queue) { 30 | this.length = 0 31 | Array.prototype.push.call(this) 32 | 33 | var l = queue.length 34 | , i = 0; 35 | 36 | for (; i < l; i ++) { 37 | this.add(queue[i]) 38 | } 39 | } 40 | 41 | SyncQueue.prototype.add = function(func) { 42 | var i = Array.prototype.push.call(this, function() { 43 | return func(this[i]) 44 | }) 45 | 46 | return this 47 | } 48 | 49 | SyncQueue.prototype.del = function(index) { 50 | index > -1 && Array.prototype.splice.call(this, index, 1) 51 | return this 52 | } 53 | 54 | SyncQueue.prototype.digest = function() { 55 | this[0]() 56 | return this 57 | } 58 | 59 | SyncQueue.prototype.destory = function() { 60 | Array.prototype.splice.call(this, 0, this.length) 61 | } 62 | 63 | return function(queue) { 64 | return queue && queue.length > 0 65 | ? (new SyncQueue(queue)).digest() 66 | : new SyncQueue() 67 | } 68 | 69 | })() 70 | } 71 | ]) 72 | -------------------------------------------------------------------------------- /client/public/scripts/services/constant.js: -------------------------------------------------------------------------------- 1 | /** 2 | * constant 常量配置服务 3 | * @author David Jones 4 | * @email qowera@qq.com 5 | */ 6 | angular.module('services.constant', []) 7 | 8 | .provider('$constant', [ 9 | '$provide', 10 | function($provide) {'use strict'; 11 | var CONSTANT = {}, 12 | MAP = {}, 13 | DATASOURCE = {}, 14 | ORGIN = {}; 15 | 16 | this.setItem = function(name, constant) { 17 | ORGIN[name] = constant; 18 | 19 | if (!angular.isArray(DATASOURCE[name])) { 20 | DATASOURCE[name] = []; 21 | } 22 | 23 | if (!angular.isObject(MAP[name])) { 24 | MAP[name] = {}; 25 | } 26 | 27 | angular.forEach(constant, function(item) { 28 | MAP[name][item.name] = item.value; 29 | DATASOURCE[name].push({ NAME: item.name, VALUE: item.value, TEXT: item.text }); 30 | }); 31 | 32 | var mapName = name + '_MAP', 33 | dataSourceName = name + '_DATASOURCE'; 34 | 35 | $provide.constant(mapName, CONSTANT[mapName] = MAP[name]); 36 | $provide.constant(dataSourceName, CONSTANT[dataSourceName] = DATASOURCE[name]); 37 | return this; 38 | }; 39 | 40 | this.getItem = function(name) { 41 | return ORGIN[name]; 42 | }; 43 | 44 | this.$get = [ 45 | function() { 46 | var $constant = {}; 47 | $constant.get = function(name) { 48 | return CONSTANT[name]; 49 | }; 50 | 51 | $constant.getMap = function(name) { 52 | return MAP[name]; 53 | }; 54 | 55 | $constant.getDatasource = function(name) { 56 | return DATASOURCE[name]; 57 | }; 58 | 59 | $constant.getOrigin = function(name) { 60 | return ORGIN[name]; 61 | }; 62 | 63 | return $constant; 64 | } 65 | ]; 66 | } 67 | ]) -------------------------------------------------------------------------------- /client/public/scripts/services/screen.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Screen 3 | * @author 4 | */ 5 | angular.module('services.screen', []) 6 | 7 | .factory('$screenfull', [ 8 | '$rootScope', 9 | function($rootScope) { 10 | 'use strict' 11 | 12 | var isCommonjs = typeof module !== 'undefined' && module.exports 13 | , keyboardAllowed = typeof Element !== 'undefined' && 'ALLOW_KEYBOARD_INPUT' in Element 14 | 15 | var fn = (function () { 16 | var val 17 | , valLength 18 | , fnMap = [ 19 | [ 20 | 'requestFullscreen', 21 | 'exitFullscreen', 22 | 'fullscreenElement', 23 | 'fullscreenEnabled', 24 | 'fullscreenchange', 25 | 'fullscreenerror' 26 | ], 27 | // new WebKit 28 | [ 29 | 'webkitRequestFullscreen', 30 | 'webkitExitFullscreen', 31 | 'webkitFullscreenElement', 32 | 'webkitFullscreenEnabled', 33 | 'webkitfullscreenchange', 34 | 'webkitfullscreenerror' 35 | ], 36 | // old WebKit (Safari 5.1) 37 | [ 38 | 'webkitRequestFullScreen', 39 | 'webkitCancelFullScreen', 40 | 'webkitCurrentFullScreenElement', 41 | 'webkitCancelFullScreen', 42 | 'webkitfullscreenchange', 43 | 'webkitfullscreenerror' 44 | ], 45 | [ 46 | 'mozRequestFullScreen', 47 | 'mozCancelFullScreen', 48 | 'mozFullScreenElement', 49 | 'mozFullScreenEnabled', 50 | 'mozfullscreenchange', 51 | 'mozfullscreenerror' 52 | ], 53 | [ 54 | 'msRequestFullscreen', 55 | 'msExitFullscreen', 56 | 'msFullscreenElement', 57 | 'msFullscreenEnabled', 58 | 'MSFullscreenChange', 59 | 'MSFullscreenError' 60 | ] 61 | ] 62 | 63 | var i = 0 64 | , l = fnMap.length 65 | , ret = {} 66 | 67 | for (; i < l; i++) { 68 | val = fnMap[i] 69 | 70 | if (val && val[1] in document) { 71 | for (i = 0, valLength = val.length; i < valLength; i++) { 72 | ret[fnMap[0][i]] = val[i] 73 | } 74 | 75 | return ret 76 | } 77 | } 78 | 79 | return false 80 | })() 81 | 82 | var screenfull = { 83 | request: function (elem) { 84 | var request = fn.requestFullscreen 85 | elem = elem || document.documentElement 86 | 87 | // Work around Safari 5.1 bug: reports support for 88 | // keyboard in fullscreen even though it doesn't. 89 | // Browser sniffing, since the alternative with 90 | // setTimeout is even worse. 91 | ;/5\.1[\.\d]* Safari/.test(navigator.userAgent) 92 | ? elem[request]() 93 | : elem[request](keyboardAllowed && Element.ALLOW_KEYBOARD_INPUT); 94 | }, 95 | exit: function () { 96 | document[fn.exitFullscreen]() 97 | }, 98 | toggle: function (elem) { 99 | this.isFullscreen 100 | ? this.exit() 101 | : this.request(elem) 102 | }, 103 | raw: fn 104 | } 105 | 106 | Object.defineProperties(screenfull, { 107 | isFullscreen: { 108 | get: function () { 109 | return !!document[fn.fullscreenElement] 110 | } 111 | }, 112 | element: { 113 | enumerable: true, 114 | get: function () { 115 | return document[fn.fullscreenElement] 116 | } 117 | }, 118 | enabled: { 119 | enumerable: true, 120 | get: function () { 121 | // Coerce to boolean in case of old WebKit 122 | return !!document[fn.fullscreenEnabled] 123 | } 124 | } 125 | }) 126 | 127 | angular.element(document) 128 | .on(screenfull.raw.fullscreenchange, function() { 129 | $rootScope.$broadcast('fullscreenchange', screenfull.isFullscreen) 130 | }) 131 | 132 | return screenfull 133 | } 134 | ]) -------------------------------------------------------------------------------- /client/public/scripts/ui/checkbox.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @name Checkbox 3 | * @author [] 4 | * @description 5 | * 6 | */ 7 | angular.module('ui.checkbox', ['templates/checkbox/checkbox.html']) 8 | 9 | .controller('CheckboxController', [ 10 | '$scope', 11 | function($scope) { 12 | 'use strict' 13 | 14 | $scope.checked = false 15 | } 16 | ]) 17 | 18 | .directive('checkbox', [ 19 | '$rootScope', 20 | function($rootScope) { 21 | return { 22 | restrict: 'EA', 23 | transclude: true, 24 | replace: true, 25 | controller: 'CheckboxController', 26 | templateUrl: 'templates/checkbox/checkbox.html', 27 | require: ['^checkbox', '^?ngModel'], 28 | scope: { 29 | model: '=?ngModel', 30 | ngChecked: '=?ngChecked', 31 | ngDisabled: '=?ngDisabled', 32 | }, 33 | link: function($scope, $element, $attrs, ctrls) { 34 | 'use strict' 35 | 36 | var CheckboxCtrl = ctrls[0] 37 | , ModelCtrl = ctrls[1] 38 | , attrValue = $attrs.value 39 | 40 | $scope.attrId = $attrs.id 41 | $scope.attrName = $attrs.ngModel || ('checkbox-' + Date.now() + Math.round(Math.random()*100)) 42 | $scope.attrValue = angular.isDefined($attrs.value) ? $attrs.value : true 43 | $scope.attrNgChecked = $attrs.ngChecked 44 | $scope.disabled = $attrs.hasOwnProperty('disabled') 45 | $scope.checked = angular.isBoolean($scope.ngModel) ? $scope.ngModel : $attrs.hasOwnProperty('checked') 46 | 47 | $scope.toggle = function(isChecked) { 48 | isChecked = angular.isDefined(isChecked) ? !!isChecked : !$scope.checked 49 | $scope.checked = isChecked 50 | } 51 | 52 | $element 53 | .removeAttr('id') 54 | .on('click', function(event) { 55 | if ($scope.disabled) { 56 | event.preventDefault() 57 | event.stopPropagation() 58 | return false 59 | } 60 | 61 | $scope.toggle() 62 | 63 | var isChecked = $scope.checked 64 | CheckboxCtrl.toggle && CheckboxCtrl.toggle(isChecked) 65 | $rootScope.$apply(function() { 66 | $scope.model = isChecked ? $scope.attrValue : false 67 | }) 68 | }) 69 | 70 | if (angular.isUndefined($scope.model)) { 71 | $scope.model = $scope.checked ? $scope.attrValue : false 72 | } 73 | 74 | $scope.$watch('ngChecked', function(isChecked) { 75 | if (angular.isDefined(isChecked)) { 76 | $element.attr('checked', isChecked) 77 | $scope.toggle(!!isChecked) 78 | CheckboxCtrl.toggle(isChecked) 79 | $scope.model = $scope.checked ? $scope.attrValue : false 80 | } 81 | }) 82 | 83 | $scope.$watch('ngDisabled', function(isDisabled) { 84 | if (angular.isBoolean(isDisabled)) { 85 | $scope.disabled = isDisabled 86 | } 87 | }) 88 | 89 | $scope.$watch('model', function(value, oldValue) { 90 | var isChecked = $scope.checked = value == $scope.attrValue 91 | 92 | $element.attr('checked', isChecked) 93 | $scope.toggle(isChecked) 94 | CheckboxCtrl.toggle(isChecked) 95 | }) 96 | } 97 | } 98 | } 99 | ]) 100 | 101 | .directive('checkboxOrigin', [ 102 | function() { 103 | return { 104 | restrict: 'A', 105 | require: '^checkbox', 106 | link: function($scope, $element, $attrs, ctrl) { 107 | 'use strict' 108 | 109 | ctrl.select = function(isCheck) { 110 | $element 111 | .prop('checked', isCheck) 112 | .attr('checked', isCheck) 113 | .triggerHandler('change') 114 | } 115 | 116 | ctrl.toggle = function(isCheck) { 117 | ctrl.select(isCheck) 118 | } 119 | 120 | $element 121 | .on('change', function() { 122 | $scope.toggle(!!angular.element(this).prop('checked')) 123 | }) 124 | } 125 | } 126 | } 127 | ]) -------------------------------------------------------------------------------- /client/public/scripts/ui/promptBox.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | angular.module('ui.promptBox', []) 4 | 5 | .constant('promptBoxConfig', { 6 | leaveClass: 'leave', 7 | enterClass: 'in', 8 | activeClass: 'active', 9 | delayTime: 3000 10 | }) 11 | 12 | .service('$promptStack', [ 13 | '$rootScope', 14 | function($rootScope) { 15 | var stackedMap = [], openScopes = []; 16 | this.createNew = function(openScope) { 17 | stackedMap = angular.isArray(openScope.notice) ? openScope.notice : (openScope.notice = []); 18 | }; 19 | 20 | this.add = function(scope) { 21 | openScopes.push(scope); 22 | if (openScopes.length > 5) { 23 | var i, l = openScopes.length - 5; 24 | for (i = 0; i < l; i ++) openScopes[i].leave(); 25 | } 26 | }; 27 | 28 | this.dismiss = function(scope) { 29 | var index = angular.inArray(scope, openScopes); 30 | openScopes.splice(index, 1); 31 | stackedMap.splice(index, 1); 32 | }; 33 | 34 | $rootScope.$on('notify', function(event, message, type, title) { 35 | stackedMap.push({ message: message, type: type, title: title }); 36 | }); 37 | } 38 | ]) 39 | 40 | .directive('promptBox', [ 41 | '$timeout', '$q', 42 | '$promptStack', 43 | 'promptBoxConfig', 44 | function($timeout, $q, $promptStack, config) { 45 | return { 46 | restrict: 'EA', 47 | link: function($scope, $element, $attrs) { 48 | $promptStack.add($scope); 49 | 50 | var transitionPromise, 51 | timeoutPromise; 52 | $scope.isClosed = false; 53 | 54 | $scope.fade = function() { 55 | var callbackDeferred = $q.defer(); 56 | $timeout(function() { 57 | $element.addClass(config.enterClass); 58 | }); 59 | 60 | $timeout(function() { 61 | callbackDeferred.resolve(); 62 | }, 500); 63 | 64 | return callbackDeferred.promise; 65 | }; 66 | 67 | $scope.leave = function(event) { 68 | if ($scope.isClosed) return false; 69 | if (!event) $scope.isClosed = true; 70 | $element.addClass(config.leaveClass); 71 | 72 | // 时间等于 css animation 时间 73 | // 若使用$timeout 会导致 fadeout 期间不断更改信息集合 notice, 而出现闪屏现象 74 | timeoutPromise = setTimeout(function() { 75 | $element.remove(); 76 | $promptStack.dismiss($scope); 77 | }, 500); 78 | }; 79 | 80 | $scope.pause = function() { 81 | $element.removeClass(config.leaveClass); 82 | transitionPromise && $timeout.cancel(transitionPromise); 83 | timeoutPromise && clearTimeout(timeoutPromise); 84 | transitionPromise = timeoutPromise = undefined; 85 | }; 86 | 87 | $scope.$watch('isClosed', function(value) { 88 | if (value === true) $scope.leave(); 89 | else $scope.pause(); 90 | }); 91 | 92 | $element.on('mouseenter', function() { 93 | if ($scope.isClosed) return false; 94 | $scope.pause(); 95 | }); 96 | 97 | $element.on('mouseleave', function() { 98 | if ($scope.isClosed) return false; 99 | 100 | $scope.pause(); 101 | transitionPromise = $timeout(function() { 102 | $scope.leave(true); 103 | }, config.delayTime); 104 | }); 105 | 106 | $scope.fade(). 107 | then(function() { 108 | $element.triggerHandler('mouseleave'); 109 | }); 110 | } 111 | }; 112 | } 113 | ]) -------------------------------------------------------------------------------- /client/public/scripts/ui/scrollpicker.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | angular.module('ui.scrollpicker', ['ui.helper']) 4 | 5 | .controller('ScrollpickerController', [ 6 | '$scope', '$transition', 7 | 'const-css3Transform', 8 | function($scope, $transition, css3Transform) { 9 | var exports = this, 10 | $list, $picker; 11 | 12 | $scope.next = function(event) { 13 | event && event.preventDefault(); 14 | if (angular.isUndefined($picker)) return; 15 | 16 | var $next = $picker.next(); 17 | $next.length > 0 && exports.select($next); 18 | }; 19 | 20 | $scope.prev = function(event) { 21 | event && event.preventDefault(); 22 | if (angular.isUndefined($picker)) return; 23 | 24 | var $prev = $picker.prev(); 25 | $prev.length > 0 && exports.select($prev); 26 | }; 27 | 28 | $scope.select = function(event) { 29 | var $select = angular.element(event.target); 30 | $select.length > 0 && exports.select($select); 31 | }; 32 | 33 | exports.setPicker = function($element) { 34 | $list = $element; 35 | }; 36 | 37 | exports.select = function($element) { 38 | if ($picker === $element) return; 39 | if ($picker) $picker.removeClass('selected'); 40 | $element.addClass('selected'); 41 | $picker = $element; 42 | 43 | var items = $list.children(), 44 | index = angular.inArray($element[0], items), 45 | height = $element[0].offsetHeight, 46 | offset = 'translate3d(0, ' + (-(index -1) * height) + 'px, 0)', 47 | $item; 48 | 49 | var style = {}; 50 | style[css3Transform] = offset; 51 | $transition($list, style); 52 | }; 53 | } 54 | ]) 55 | 56 | .directive('scrollpicker', [ 57 | function() { 58 | return { 59 | restrict: 'EA', 60 | transclude: true, 61 | replace: true, 62 | controller: 'ScrollpickerController', 63 | templateUrl: 'template/scrollpicker/scrollpicker.html', 64 | require: '^scrollpicker', 65 | scope: {} 66 | }; 67 | } 68 | ]) 69 | 70 | .directive('scrollList', [ 71 | function() { 72 | return { 73 | restrict: 'EA', 74 | require: '^scrollpicker', 75 | scope: {}, 76 | link: function($scope, $element, $attrs, scrollpickerCtrl) { 77 | scrollpickerCtrl.setPicker($element); 78 | } 79 | }; 80 | } 81 | ]) 82 | 83 | .directive('scrollItem', [ 84 | function() { 85 | return { 86 | restrict: 'EA', 87 | require: '^scrollpicker', 88 | link: function($scope, $element, $attrs, scrollpickerCtrl) { 89 | $element.on('click', function() { 90 | scrollpickerCtrl.select($element); 91 | }); 92 | 93 | setTimeout(function() { 94 | $element.hasClass('default') && scrollpickerCtrl.select($element); 95 | }, 300); 96 | } 97 | }; 98 | } 99 | ]) -------------------------------------------------------------------------------- /client/public/scripts/ui/selecter.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | angular.module('ui.selecter', ['ui.helper', 'ui.dropdownMenu']) 4 | 5 | .controller('selectpickerController', [ 6 | '$scope', '$document', 7 | function($scope, $document) { 8 | $scope.options = []; 9 | $scope.selected = {}; 10 | 11 | $scope.select = function(value) { 12 | var key = angular.inArrayBy(value, $scope.options, 'value'); 13 | if (-1 !== key) $scope.selected = $scope.options[key]; 14 | setTimeout(function() { $document.triggerHandler('click'); }, 10); 15 | }; 16 | } 17 | ]) 18 | 19 | .directive('selecter', [ 20 | '$http', '$compile', 21 | function($http, $compile) { 22 | return { 23 | restrict: 'EA', 24 | transclude: true, 25 | replace: true, 26 | controller: 'selectpickerController', 27 | templateUrl: 'templates/selecter/selecter.html', 28 | require: ['selecter', '?ngModel'], 29 | scope: { 30 | options: '=?' 31 | }, 32 | link: function($scope, $element, $attrs, ctrls, transclude) { 33 | var ngModel = ctrls[1], 34 | $selectElement = $element.children(). 35 | prepend(transclude()). 36 | find('select'). 37 | css('display', 'none'); 38 | 39 | $scope.selected = { text: $element.attr('placeholder'), value: '' }; 40 | $scope.$watch(function() { return $selectElement.html(); }, function() { 41 | var value, text; 42 | 43 | $scope.options = []; 44 | angular.forEach($selectElement.children(), function(option) { 45 | value = angular.element(option).val(); 46 | text = angular.element(option).html(); 47 | text && value && $scope.options.push({ value: value, text: text }); 48 | }); 49 | }); 50 | 51 | ngModel && $scope.$watch(function() { return ngModel.$viewValue; }, function(value) { 52 | var index = angular.inArrayBy(value, $scope.options, 'value'); 53 | if (-1 === index) $scope.selected = { text: $element.attr('placeholder'), value: '' }; 54 | else $scope.selected = $scope.options[index]; 55 | }); 56 | 57 | $scope.$watch(function() { return angular.fromJson($scope.selected); }, function() { 58 | $scope.selected && $selectElement.val($scope.selected.value); 59 | ngModel && ngModel.$setViewValue($scope.selected.value); 60 | }); 61 | } 62 | }; 63 | } 64 | ]) -------------------------------------------------------------------------------- /client/public/scripts/ui/switch.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @name switch 3 | * @author [] 4 | * @description 5 | * 6 | */ 7 | angular.module('ui.switch', ['templates/switch/switch.html']) 8 | 9 | .controller('SwitchController', [ 10 | '$scope', 11 | function($scope) { 12 | 'use strict' 13 | 14 | $scope.checked = false 15 | 16 | this.transclude = function(name, content) { 17 | this.transclude[name](content) 18 | } 19 | } 20 | ]) 21 | 22 | .directive('switch', [ 23 | '$rootScope', 24 | function($rootScope) { 25 | return { 26 | restrict: 'EA', 27 | transclude: true, 28 | replace: true, 29 | controller: 'SwitchController', 30 | templateUrl: 'templates/switch/switch.html', 31 | require: ['^switch', '^?ngModel'], 32 | scope: { 33 | model: '=?ngModel' 34 | , ngDisabled: '=?ngDisabled' 35 | }, 36 | link: function($scope, $element, $attrs, ctrls, $transclude) { 37 | 'use strict' 38 | 39 | var switchCtrl = ctrls[0] 40 | 41 | $scope.attrId = $attrs.id 42 | $scope.attrName = $attrs.ngModel || ('radio-' + Date.now() + Math.round(Math.random()*100)) 43 | $scope.attrValue = angular.isDefined($attrs.value) ? $attrs.value : true 44 | $scope.attrType = $attrs.type || 'checkbox' 45 | $scope.disabled = $attrs.hasOwnProperty('disabled') 46 | $scope.checked = angular.isBoolean($scope.ngModel) ? $scope.ngModel : $attrs.hasOwnProperty('checked') 47 | 48 | if ($scope.checked) { 49 | $scope.model = $scope.attrValue 50 | } 51 | 52 | $scope.$watch('ngDisabled', function(isDisabled) { 53 | if (angular.isBoolean(isDisabled)) { 54 | $scope.disabled = isDisabled 55 | } 56 | }) 57 | 58 | $scope.$watch('model', function(value, oldValue) { 59 | if (value !== oldValue) { 60 | $scope.checked = value == $scope.attrValue 61 | } 62 | }) 63 | 64 | angular.forEach($transclude(), function(element) { 65 | var name = element.tagName 66 | .toLowerCase() 67 | .replace(/\-[a-z]/g, function($1) { 68 | return $1.replace('-', '').toUpperCase() 69 | }) 70 | 71 | switchCtrl.transclude(name, element.innerHTML) 72 | }) 73 | } 74 | } 75 | } 76 | ]) 77 | 78 | .directive('switchTransclude', [ 79 | function() { 80 | return { 81 | restrict: 'EA', 82 | require: '^switch', 83 | link: function($scope, $element, $attrs, ctrl) { 84 | var transcludeName = $attrs.switchTransclude 85 | 86 | ctrl.transclude[transcludeName] = function(content) { 87 | $element.html(content) 88 | } 89 | } 90 | } 91 | } 92 | ]) -------------------------------------------------------------------------------- /client/public/scripts/ui/templates/checkbox/checkbox.jade: -------------------------------------------------------------------------------- 1 | .checkbox.checkbox-replace(ng-class='{ disabled: disabled }') 2 | input(checkbox-origin, 3 | ng-class='{ disabled: disabled }', 4 | ng-model='ngModel', 5 | ng-attr-id='{{ attrId }}', 6 | ng-attr-name='{{ attrName }}', 7 | ng-attr-value='{{ attrValue }}', 8 | ng-disabled='disabled', 9 | type='checkbox') 10 | .checkbox-icon 11 | .checkbox-inner(ng-transclude) -------------------------------------------------------------------------------- /client/public/scripts/ui/templates/layout/asidebar.jade: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DavidKk/ngAdmin/55664d50166333d4ddbe91b84bf6bbc3868067e9/client/public/scripts/ui/templates/layout/asidebar.jade -------------------------------------------------------------------------------- /client/public/scripts/ui/templates/radio/radio.jade: -------------------------------------------------------------------------------- 1 | .radio.radio-replace(ng-class='{ disabled: disabled }') 2 | input(radio-origin, 3 | ng-class='{ disabled: disabled }', 4 | ng-model='model', 5 | ng-attr-id='{{ attrId }}', 6 | ng-attr-name='{{ attrName }}', 7 | ng-attr-value='{{ attrValue }}', 8 | ng-disabled='disabled', 9 | type='radio') 10 | .radio-icon 11 | .radio-inner(ng-transclude) -------------------------------------------------------------------------------- /client/public/scripts/ui/templates/selecter/selecter.jade: -------------------------------------------------------------------------------- 1 | selectpicker 2 | .selectpicker(dropdown-menu) 3 | a.dropdown-toggle(dropdown-menu-toggle) {{ selected.text || selected.value || '' }} 4 | .dropdown-menu(dropdown-menu-dialog) 5 | .filter-bar 6 | i.fa.fa-search 7 | input.form-control(dropdown-menu-filter, type="search", placeholder="Search...") 8 | 9 | ul.menu-list(dropdown-menu-list) 10 | li(ng-repeat="item in options") 11 | a(ng-click="select(item.value)", title="item.text") {{ item.text }} 12 | -------------------------------------------------------------------------------- /client/public/scripts/ui/templates/switch/switch.jade: -------------------------------------------------------------------------------- 1 | label.switch(ng-class='{ disabled: disabled }') 2 | input(nng-model='model', 3 | ng-attr-type='{{ attrType }}', 4 | ng-attr-id='{{ attrId }}', 5 | ng-attr-name='{{ attrName }}', 6 | ng-attr-value='{{ attrValue }}', 7 | ng-checked='checked', 8 | ng-disabled='disabled') 9 | .switch-inner 10 | .switch-on 11 | .inner 12 | span.content(switch-transclude='on') on 13 | .switch-off 14 | .inner 15 | span.content(switch-transclude='off') off 16 | .switch-switch 17 | -------------------------------------------------------------------------------- /client/public/scripts/ui/warpperSlider.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | angular.module('ui.warpperSlider', []) 4 | 5 | .directive('wrapperSlider', [ 6 | '$transition', 7 | function($transition) {'use strict'; 8 | return { 9 | restrict: 'EA', 10 | require: '?ngModel', 11 | scope: {}, 12 | link: function($scope, $element, $attrs, ctrl) { 13 | var lastPercentage = 0, num = $attrs.number, 14 | isWrap = $element[0].offsetWidth > window.outerWidth, 15 | step = isWrap ? -100 : 100/num, 16 | minX = isWrap ? (num -1)*step : 0, 17 | maxX = isWrap ? 0 : (num -1)*step, 18 | startX, endX, deltaX, point, isDrag, part, 19 | percentage, currentTransition; 20 | 21 | function doTransition(change) { 22 | var newTransition = $transition($element, change); 23 | if (currentTransition) currentTransition.cancel(); 24 | 25 | currentTransition = newTransition; 26 | newTransition.then(newTransitionDone, newTransitionDone); 27 | return newTransition; 28 | 29 | function newTransitionDone() { 30 | if (currentTransition === newTransition) { 31 | currentTransition = undefined; 32 | } 33 | } 34 | } 35 | 36 | function moveTo(position) { 37 | $element.addClass('move'); 38 | position = Math.min(Math.max(position, minX), maxX); 39 | doTransition({ left: position + '%' }). 40 | then(function() { $element.removeClass('move'); }); 41 | } 42 | 43 | function moveToPart(part, isDrag) { 44 | if (part < 0) return; 45 | 46 | if (isDrag || Math.abs(percentage)%Math.abs(step) > Math.abs(step)/2) { 47 | part = part + (startX > endX ? 1 : 0); 48 | percentage = step*part; 49 | } 50 | else percentage = step*part; 51 | 52 | moveTo(percentage); 53 | ctrl.$setViewValue(part); 54 | lastPercentage = percentage; 55 | } 56 | 57 | function touchstart(event) { 58 | point = event.changedTouches ? event.changedTouches[0] : event; 59 | startX = point.pageX; 60 | angular.element(window).on('touchmove mousemove', touchmove); 61 | } 62 | 63 | function touchmove(event) { 64 | isDrag = true; 65 | 66 | point = event.changedTouches ? event.changedTouches[0] : event; 67 | deltaX = point.pageX - startX; 68 | 69 | if (isWrap) percentage = deltaX/window.outerWidth*100; 70 | else percentage = -(deltaX/window.outerWidth*100/num); 71 | 72 | percentage += lastPercentage; 73 | percentage = Math.max(Math.min(percentage, maxX), minX); 74 | $element.css('left', percentage + '%'); 75 | } 76 | 77 | function touchend(event) { 78 | if (!isDrag) return; 79 | point = event.changedTouches ? event.changedTouches[0] : event; 80 | endX = point.pageX; 81 | 82 | moveToPart(Math.floor(percentage/step), isWrap ? true : false); 83 | angular.element(window).off('touchmove', touchmove); 84 | } 85 | 86 | // angular.element(window). 87 | // on('touchstart', touchstart). 88 | // on('touchend', touchend); 89 | 90 | $scope.$watch(function() { return ctrl.$modelValue; }, function(value) { 91 | moveToPart(value || 0); 92 | }); 93 | } 94 | }; 95 | } 96 | ]) -------------------------------------------------------------------------------- /client/public/styles/bootstrap.json: -------------------------------------------------------------------------------- 1 | [ 2 | "/variables/**/*.less" 3 | , "/mixins/**/*.less" 4 | , "/mixins/**/*.less" 5 | , "/resets/**/*.less" 6 | , "/core/**/*.less" 7 | , "/effects/**/*.less" 8 | , "/utilities/**/*.less" 9 | , "/components/**/*.less" 10 | , "/script-components/**/*.less" 11 | , "/partials/**/main.less" 12 | , "/partials/**/desktop.less" 13 | , "/partials/**/tablet.less" 14 | , "/partials/**/mobile.less" 15 | ] -------------------------------------------------------------------------------- /client/public/styles/components/accordions.less: -------------------------------------------------------------------------------- 1 | 2 | 3 | // .accordion.accordion-icon .panel > .panel-heading { position: relative; } 4 | // .accordion.accordion-icon .panel > .panel-heading:before { 5 | // padding: 7px 15px; 6 | // height: 100%; 7 | // background-color: rgba(0, 0, 0, 0.05); 8 | // display: block; 9 | // content: "\f0da"; 10 | // font-family: 'FontAwesome'; 11 | // position: absolute; 12 | // left: 0; 13 | // top: 0; 14 | // .transition(all .35s); 15 | // } 16 | 17 | // .accordion.accordion-icon .panel.active > .panel-heading:before { .transform(rotate(90deg)); } 18 | // .accordion.accordion-icon .panel > .panel-heading > .panel-title { margin-left: 30px; } 19 | 20 | 21 | // // 误差 #fff 14% 都取反色 22 | // .accordion-anti-color(@color) when(lighten(@color, 14%) = #fff) { 23 | // color: negation(@color, #fff); 24 | // } 25 | 26 | // .accordion-palette(@arr-style, @index: 1) when (@index =< length(@arr-style)) { 27 | // @token: e(extract(@arr-style, @index)); 28 | // @bg: extract(@arr-style, @index + 1); 29 | 30 | // .accordion.accordion-@{token} .panel { border-color: @bg; } 31 | // .accordion.accordion-@{token} .panel > .panel-heading { 32 | // .accordion-anti-color(@bg); 33 | 34 | // background-color: @bg; 35 | // color: #fff; 36 | // } 37 | 38 | // .accordion-palette(@arr-style, @index + 2); 39 | // } 40 | 41 | // .accordion-palette(@arr-accordion); -------------------------------------------------------------------------------- /client/public/styles/components/alerts.less: -------------------------------------------------------------------------------- 1 | .alert { 2 | background-color: @gray; 3 | } 4 | 5 | .alert-palette(@arr-style, @index: 1) when (@index =< length(@arr-style)) { 6 | @token: e(extract(@arr-style, @index)); 7 | @color: extract(@arr-style, @index + 1); 8 | @bg: screen(@color, #aaa); 9 | 10 | .alert.alert-@{token} { 11 | background-color: @bg; 12 | color: darken(@color, 10%); 13 | } 14 | 15 | .alert-palette(@arr-style, @index + 2); 16 | } 17 | 18 | .alert-palette(@alert-palette); 19 | -------------------------------------------------------------------------------- /client/public/styles/components/badges.less: -------------------------------------------------------------------------------- 1 | .badge { 2 | display: inline-block; 3 | vertical-align: middle; 4 | line-height: @line-height-base; 5 | color: @black; 6 | font-weight: bold; 7 | cursor: default; 8 | background-color: @gray; 9 | } 10 | 11 | .badge-square { 12 | .border-radius(0); 13 | } 14 | 15 | .badge-palette(@arr-style, @index: 1) when (@index =< length(@arr-style)) { 16 | @token: e(extract(@arr-style, @index)); 17 | @color: extract(@arr-style, @index + 1); 18 | 19 | .badge.badge-@{token} { 20 | background-color: @color; 21 | color: #fff; 22 | } 23 | 24 | .badge-palette(@arr-style, @index + 2); 25 | } 26 | 27 | .badge-palette(@badge-palette); 28 | -------------------------------------------------------------------------------- /client/public/styles/components/blockquote.less: -------------------------------------------------------------------------------- 1 | .blockquote-palette(@arr-style, @index: 1) when (@index =< length(@arr-style)) { 2 | @token: e(extract(@arr-style, @index)); 3 | @color: extract(@arr-style, @index + 1); 4 | @bg: screen(@color, #aaa); 5 | 6 | blockquote.blockquote-@{token} { 7 | border-left-color: darken(@bg, 10%); 8 | background-color: @bg; 9 | color: darken(@color, 10%); 10 | } 11 | 12 | .blockquote-palette(@arr-style, @index + 2); 13 | } 14 | 15 | .blockquote-palette(@blockquote-palette); -------------------------------------------------------------------------------- /client/public/styles/components/breadcrumbs.less: -------------------------------------------------------------------------------- 1 | .breadcrumb { 2 | > li i { 3 | margin-right: 5px; 4 | color: rgb(115, 120, 129); 5 | } 6 | 7 | > li a { 8 | color: rgb(115, 120, 129); 9 | font-weight: 400; 10 | .transition(all 300ms ease-in-out); 11 | } 12 | } 13 | 14 | .breadcrumb.breadcrumb-pure { 15 | padding-left: 0; 16 | padding-right: 0; 17 | background-color: rgba(0, 0, 0, 0); 18 | } 19 | 20 | .breadcrumb.breadcrumb-border { 21 | background-color: transparent; 22 | border: 1px solid rgb(235, 235, 235); 23 | } 24 | -------------------------------------------------------------------------------- /client/public/styles/components/button-groups.less: -------------------------------------------------------------------------------- 1 | .btn-group { 2 | display: inline-flex; 3 | position: relative; 4 | white-space: nowrap; 5 | font-size: 0; 6 | } 7 | 8 | .btn-group > .btn + .dropdown-toggle { 9 | padding-left: 10px; 10 | padding-right: 10px; 11 | 12 | &:before { 13 | content: "|"; 14 | color: rgba(33, 33, 33, .1); 15 | position: relative; 16 | left: -10px; 17 | } 18 | } -------------------------------------------------------------------------------- /client/public/styles/components/dropdowns.less: -------------------------------------------------------------------------------- 1 | // Dropdown Menu 2 | // ----------------- 3 | 4 | .dropdown-menu { 5 | .border-radius(0); 6 | 7 | li > a { 8 | line-height: 20px; 9 | 10 | i { 11 | display: inline-block; 12 | margin-right: 4px; 13 | width: 20px; 14 | height: 20px; 15 | vertical-align: middle; 16 | line-height: 20px; 17 | text-align: center; 18 | font-size: 14px; 19 | } 20 | } 21 | } 22 | 23 | // Header Sub Menu 24 | .dropdown-menu-modal { 25 | margin: 0; 26 | padding-top: 0; 27 | padding-bottom: 0; 28 | max-width: 300px; 29 | min-width: 260px; 30 | border-width: 0; 31 | 32 | a.dropdown-more { 33 | display: block; 34 | padding: 10px; 35 | color: rgb(128, 128, 128); 36 | background-color: rgb(252, 252, 252); 37 | .transition(all .35s); 38 | } 39 | 40 | .caption { 41 | margin: 0; 42 | padding: 14px; 43 | border-bottom: 6px solid @black; 44 | color: #fff; 45 | font-size: 12px; 46 | font-weight: bold; 47 | background-color: @green; 48 | 49 | .dropdown-menu-caption-widgets { 50 | float: right; 51 | font-size: 12px; 52 | 53 | > a { 54 | cursor: pointer; 55 | color: #fff; 56 | font-size: 16px; 57 | } 58 | 59 | > a:hover { 60 | text-decoration: underline; 61 | } 62 | } 63 | 64 | .dropdown-menu-caption-arrow { 65 | .arrow-mixin(8px, #fff, top, 26px, 4px, @black); 66 | top: 33px; 67 | } 68 | } 69 | 70 | .dropdown-menu-arrow { 71 | .arrow-mixin(6px, @green, top, 10%); 72 | } 73 | 74 | &.pull-right .dropdown-menu-arrow { 75 | .arrow-mixin > .offset(-2em, top); 76 | } 77 | 78 | .dropdown-list { 79 | padding-left: 0; 80 | list-style: none; 81 | 82 | > li { 83 | border-bottom: 1px dotted rgba(0, 0, 0, 0.05); 84 | } 85 | 86 | > li:hover { 87 | background-color: rgb(252, 252, 252); 88 | } 89 | 90 | > li > a, 91 | > li > .item { 92 | display: block; 93 | padding: 10px !important; 94 | cursor: pointer; 95 | color: rgb(51, 51, 51); 96 | font-size: 12px; 97 | .transition(all .35s); 98 | } 99 | 100 | li .badge { 101 | display: none; 102 | float: right; 103 | } 104 | } 105 | 106 | .viewport-scroll { 107 | display: block; 108 | position: relative; 109 | max-height: 260px; 110 | overflow: hidden; 111 | } 112 | } 113 | 114 | .dropdown-menu-modal-palette(@arr-style, @index: 1) when (@index =< length(@arr-style)) { 115 | @token: e(extract(@arr-style, @index)); 116 | @color: extract(@arr-style, @index + 1); 117 | 118 | .dropdown-menu.dropdown-menu-modal.dropdown-menu-@{token} .dropdown-menu-arrow { 119 | .arrow-mixin > .color(@color, top); 120 | } 121 | 122 | .dropdown-menu.dropdown-menu-modal.dropdown-menu-@{token} .caption { 123 | background-color: @color; 124 | color: #fff; 125 | .anti-color(@color); 126 | } 127 | 128 | .dropdown-menu-modal-palette(@arr-style, @index + 2); 129 | } 130 | 131 | .dropdown-menu-modal-palette(@dropdown-palette); 132 | 133 | .dropdown-menu-modal .scroll-viewport.scroll-wrapper { 134 | padding-right: 8px; 135 | } 136 | 137 | .dropdown-menu-modal .scroll-viewport.scroll-wrapper .scroll-rails .scroll-bar { 138 | border-color: #d4d4d4; 139 | background-color: #d4d4d4; 140 | } -------------------------------------------------------------------------------- /client/public/styles/components/input-groups.less: -------------------------------------------------------------------------------- 1 | .input-group > .input-group-addon { 2 | .border-radius(0); 3 | 4 | background-color: @gray; 5 | border-width: 0; 6 | color: #999; 7 | font-size: 14px; 8 | max-width: 40px; 9 | min-width: 40px; 10 | padding: 0; 11 | } 12 | 13 | .input-group .form-control { 14 | &:focus { 15 | border-color: @gray; 16 | } 17 | 18 | &:last-child:not(:first-child) { 19 | border-left: 0; 20 | } 21 | 22 | &:first-child:not(:last-child) { 23 | border-right: 0; 24 | } 25 | } 26 | 27 | .input-group.minimal .input-group-addon { 28 | background-color: transparent; 29 | border: 1px solid @gray; 30 | border-radius: 4px; 31 | 32 | &:first-child { 33 | border-right: 0; 34 | } 35 | 36 | &:last-child { 37 | border-left: 0; 38 | } 39 | } 40 | 41 | .input-group.minimal .form-control { 42 | &:first-child:not(:last-child) { 43 | padding-right: 0; 44 | } 45 | 46 | &:last-child:not(:first-child) { 47 | padding-left: 0; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /client/public/styles/components/labels.less: -------------------------------------------------------------------------------- 1 | .label { 2 | display: inline-block; 3 | vertical-align: middle; 4 | padding: 4px 10px; 5 | line-height: @line-height-base; 6 | color: @black; 7 | font-weight: bold; 8 | cursor: default; 9 | background-color: @gray; 10 | } 11 | 12 | .label-palette(@arr-style, @index: 1) when (@index =< length(@arr-style)) { 13 | @token: e(extract(@arr-style, @index)); 14 | @bg: extract(@arr-style, @index + 1); 15 | 16 | .label.label-@{token} { 17 | background-color: @bg; 18 | color: #fff; 19 | } 20 | 21 | .label-palette(@arr-style, @index + 2); 22 | } 23 | 24 | .label-palette(@label-palette); -------------------------------------------------------------------------------- /client/public/styles/components/list-group.less: -------------------------------------------------------------------------------- 1 | a.list-group-item.active, 2 | a.list-group-item.active:hover, 3 | a.list-group-item.active:focus { 4 | border-color: @black; 5 | background-color: @black; 6 | 7 | .list-group-item-text { 8 | color: #909AAD; 9 | } 10 | } -------------------------------------------------------------------------------- /client/public/styles/components/loading.less: -------------------------------------------------------------------------------- 1 | .sitNSpin(@animationSpeed: 1000ms) { 2 | @sitNSpinSize: 10em; 3 | 4 | .transformThis(@X: 0, @Y: 0, @Z: 0) { transform: rotateX(unit(@X, deg)) rotateY(unit(@Y, deg)) rotateZ(unit(@Z, deg)); } 5 | .transformBefore(@Z) { .transformThis(60, 45, @Z); } 6 | .transformAfter(@Z) { .transformThis(240, 45, @Z); } 7 | 8 | &:before, 9 | &:after { 10 | box-sizing: border-box; 11 | content: ''; 12 | display: block; 13 | position: fixed; 14 | 15 | top: 50%; 16 | left: 50%; 17 | margin-top: (@sitNSpinSize * -.5); 18 | margin-left: (@sitNSpinSize * -.5); 19 | width: @sitNSpinSize; 20 | height: @sitNSpinSize; 21 | 22 | transform-style: preserve-3d; 23 | transform-origin: 50%; 24 | transform: rotateY(50%); 25 | perspective-origin: 50% 50%; 26 | perspective: 340px; 27 | 28 | background-size: @sitNSpinSize @sitNSpinSize; 29 | background-image: url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+Cjxzdmcgd2lkdGg9IjI2NnB4IiBoZWlnaHQ9IjI5N3B4IiB2aWV3Qm94PSIwIDAgMjY2IDI5NyIgdmVyc2lvbj0iMS4xIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB4bWxuczpza2V0Y2g9Imh0dHA6Ly93d3cuYm9oZW1pYW5jb2RpbmcuY29tL3NrZXRjaC9ucyI+CiAgICA8dGl0bGU+c3Bpbm5lcjwvdGl0bGU+CiAgICA8ZGVzY3JpcHRpb24+Q3JlYXRlZCB3aXRoIFNrZXRjaCAoaHR0cDovL3d3dy5ib2hlbWlhbmNvZGluZy5jb20vc2tldGNoKTwvZGVzY3JpcHRpb24+CiAgICA8ZGVmcz48L2RlZnM+CiAgICA8ZyBpZD0iUGFnZS0xIiBzdHJva2U9Im5vbmUiIHN0cm9rZS13aWR0aD0iMSIgZmlsbD0ibm9uZSIgZmlsbC1ydWxlPSJldmVub2RkIiBza2V0Y2g6dHlwZT0iTVNQYWdlIj4KICAgICAgICA8cGF0aCBkPSJNMTcxLjUwNzgxMywzLjI1MDAwMDM4IEMyMjYuMjA4MTgzLDEyLjg1NzcxMTEgMjk3LjExMjcyMiw3MS40OTEyODIzIDI1MC44OTU1OTksMTA4LjQxMDE1NSBDMjE2LjU4MjAyNCwxMzUuODIwMzEgMTg2LjUyODQwNSw5Ny4wNjI0OTY0IDE1Ni44MDA3NzQsODUuNzczNDM0NiBDMTI3LjA3MzE0Myw3NC40ODQzNzIxIDc2Ljg4ODQ2MzIsODQuMjE2MTQ2MiA2MC4xMjg5MDY1LDEwOC40MTAxNTMgQy0xNS45ODA0Njg1LDIxOC4yODEyNDcgMTQ1LjI3NzM0NCwyOTYuNjY3OTY4IDE0NS4yNzczNDQsMjk2LjY2Nzk2OCBDMTQ1LjI3NzM0NCwyOTYuNjY3OTY4IC0yNS40NDkyMTg3LDI1Ny4yNDIxOTggMy4zOTg0Mzc1LDEwOC40MTAxNTUgQzE2LjMwNzA2NjEsNDEuODExNDE3NCA4NC43Mjc1ODI5LC0xMS45OTIyOTg1IDE3MS41MDc4MTMsMy4yNTAwMDAzOCBaIiBpZD0iUGF0aC0xIiBmaWxsPSIjMDAwMDAwIiBza2V0Y2g6dHlwZT0iTVNTaGFwZUdyb3VwIj48L3BhdGg+CiAgICA8L2c+Cjwvc3ZnPg==); 30 | } 31 | 32 | &:before { 33 | .transformBefore(45); 34 | .animation(@animationSpeed rotateBefore infinite linear reverse); 35 | } 36 | 37 | &:after { 38 | .transformAfter(45); 39 | .animation(@animationSpeed rotateAfter infinite linear); 40 | } 41 | } 42 | 43 | .keyframes(~'rotateBefore, from { .sitNSpin > .transformBefore(0); } to { .sitNSpin > .transformBefore(-360); } '); 44 | .keyframes(~'rotateAfter, from { .sitNSpin > .transformAfter(0); } to { .sitNSpin > .transformAfter(360); } '); 45 | .spinner { .sitNSpin(750ms); } -------------------------------------------------------------------------------- /client/public/styles/components/navbar.less: -------------------------------------------------------------------------------- 1 | .navbar { 2 | background-color: #fff; 3 | border: 1px solid #f5f5f5; 4 | } 5 | 6 | .navbar .navbar-collapse .nav { 7 | li > a { 8 | font-size: 12px; 9 | } 10 | 11 | .disabled > a { 12 | color: darken(@gray, 20%); 13 | } 14 | 15 | .active > a, 16 | .active > a:hover { 17 | background-color: #eee; 18 | } 19 | } 20 | 21 | .navbar .navbar-collapse, 22 | .navbar .navbar-form { 23 | .form-group > .form-control { 24 | .placeholder(#ccc); 25 | .transition(border-color .35s); 26 | 27 | border-radius: 4px; 28 | background-color: #fff; 29 | border: 1px solid #f5f5f5; 30 | font-size: 12px; 31 | padding: 6px 15px; 32 | } 33 | 34 | .form-group > .form-control:focus { 35 | border-color: darken(#f5f5f5, 10%); 36 | } 37 | 38 | .btn { 39 | border-width: 0; 40 | } 41 | } 42 | 43 | .navbar-palette(@arr-style, @index: 1) when (@index =< length(@arr-style)) { 44 | @token: e(extract(@arr-style, @index)); 45 | @color: extract(@arr-style, @index + 1); 46 | 47 | .navbar.navbar-@{token} { 48 | background-color: @color; 49 | color: #fff; 50 | 51 | .navbar-brand, 52 | .navbar-collapse .nav > li > a { 53 | color: #fff; 54 | } 55 | 56 | .navbar-collapse .nav > .active > a, 57 | .navbar-collapse .nav > li > a:hover { 58 | background-color: rgba(0, 0, 0, .1); 59 | } 60 | } 61 | 62 | .navbar-palette(@arr-style, @index + 2); 63 | } 64 | 65 | .navbar-palette(@navbar-palette); 66 | -------------------------------------------------------------------------------- /client/public/styles/components/navs.less: -------------------------------------------------------------------------------- 1 | .nav-tabs > li, 2 | .nav-pills > li { 3 | float: none; 4 | display: inline-block; 5 | } 6 | 7 | .nav-tabs { 8 | > .active > a, 9 | > .active > a:focus, 10 | > .active > a:hover { 11 | color: inherit; 12 | } 13 | } 14 | 15 | .nav-tabs { margin-bottom: 10px; } 16 | .nav-tabs.right-aligned { text-align: right; } 17 | 18 | 19 | // Tabs Nav 20 | .nav-tabs.no-bordered, 21 | .nav-tabs.bordered { margin-bottom: 0; } 22 | 23 | .nav-tabs.no-bordered > li { margin-bottom: 0; } 24 | .nav-tabs.no-bordered > li > a { margin-right: 0; margin-left: 8px; } 25 | .nav-tabs.no-bordered.right-aligned > li > a { margin-left: 0; margin-right: 8px; } 26 | 27 | .nav-tabs.no-bordered, 28 | .nav-tabs.no-bordered > li > a, 29 | .nav-tabs.no-bordered > li > a:hover { border-width: 0; } 30 | 31 | .nav-tabs.bordered + .tab-content { 32 | .border-radius(0 0 3px 3px); 33 | 34 | padding: 10px 15px; 35 | margin-bottom: 20px; 36 | border: 1px solid rgb(235, 235, 235); 37 | border-top: 0; 38 | } 39 | 40 | .nav-tabs.tabs-bottom > li > a { .border-radius(0 0 4px 4px); } 41 | .nav-tabs.tabs-left > li > a { .border-radius(4px 0 0 4px); } 42 | .nav-tabs.tabs-right > li > a { .border-radius(0 4px 4px 0); } 43 | .nav-tabs.tabs-left > li { 44 | display: block; 45 | float: none; 46 | margin-left: 1px; 47 | } 48 | 49 | .nav-tabs.tabs-left.no-bordered > li > a, 50 | .nav-tabs.tabs-right.no-bordered > li > a { 51 | margin: 0; 52 | margin-top: 8px; 53 | } 54 | 55 | 56 | // Pills Nav 57 | .nav-pills { 58 | margin-bottom: 10px; 59 | 60 | > li > a { 61 | .transition(color .15s, background-color .15s); 62 | } 63 | 64 | > li > a:hover, 65 | > .active > a, 66 | > .active > a:hover { 67 | background-color: @black; 68 | color: #fff; 69 | } 70 | } 71 | 72 | .nav-pills.nav-stacked > li { 73 | display: block; 74 | } 75 | 76 | .nav-pills.right-aligned { 77 | text-align: right; 78 | } 79 | 80 | .nav-palette(@arr-style, @index: 1) when (@index =< length(@arr-style)) { 81 | @token: e(extract(@arr-style, @index)); 82 | @bg: extract(@arr-style, @index + 1); 83 | @color: extract(@arr-style, @index + 2); 84 | 85 | .nav.nav-@{token} > .active > a { 86 | background-color: @bg; 87 | color: @color; 88 | } 89 | 90 | .nav-palette(@arr-style, @index + 3); 91 | } 92 | 93 | .nav-palette(@nav-palette); -------------------------------------------------------------------------------- /client/public/styles/components/notice-bar.less: -------------------------------------------------------------------------------- 1 | .notice-bar { 2 | .user-select(none); 3 | .transition(background-color .35s); 4 | 5 | height: 60px; 6 | background-color: #fdfdfd; 7 | position: relative; 8 | overflow: hidden; 9 | cursor: default; 10 | 11 | &:hover { background-color: #fff; } 12 | } 13 | 14 | .notice-bar > ul.widgets-bar { 15 | .transition(right .35s); 16 | 17 | padding-left: 0; 18 | position: absolute; 19 | top: 0; 20 | right: -100%; 21 | list-style: none; 22 | 23 | > li { float: left; } 24 | > li > a { 25 | .box-shadow(inset 0 5px 10px rgba(100, 100, 100, 0.2)); 26 | .transition(background-color .35s); 27 | 28 | padding: 20px; 29 | width: 60px; 30 | display: inline-block; 31 | cursor: pointer; 32 | line-height: 20px; 33 | text-align: center; 34 | text-shadow: 2px 2px 2px #999; 35 | color: #fff; 36 | font-size: 16px; 37 | } 38 | 39 | > li.amethyst > a { background-color: @amethyst; } 40 | > li.cyan > a { background-color: @cyan; } 41 | > li.green > a { background-color: @green; } 42 | > li.orange > a { background-color: @orange; } 43 | > li.red > a { background-color: @red; } 44 | 45 | > li.amethyst > a:hover { background-color: lighten(@amethyst, 4%); } 46 | > li.cyan > a:hover { background-color: lighten(@cyan, 4%); } 47 | > li.green > a:hover { background-color: lighten(@green, 4%); } 48 | > li.orange > a:hover { background-color: lighten(@orange, 4%); } 49 | > li.red > a:hover { background-color: lighten(@red, 4%); } 50 | } 51 | 52 | .notice-bar.active > ul.widgets-bar { right: 0; } 53 | -------------------------------------------------------------------------------- /client/public/styles/components/notification.less: -------------------------------------------------------------------------------- 1 | .notification { 2 | // 取最浅色 3 | 4 | margin-bottom: 15px; 5 | padding: 15px; 6 | background-color: @gray; 7 | border-left: 3px solid darken(@gray, 20%); 8 | position: relative; 9 | overflow: hidden; 10 | color: darken(@gray, 20%); 11 | font-size: 15px; 12 | } 13 | 14 | .notification h1, 15 | .notification h2, 16 | .notification h3, 17 | .notification h4, 18 | .notification h5, 19 | .notification h6 { font-weight: bold; } 20 | 21 | 22 | // Other Style 23 | .notification-palette(@arr-style, @index: 1) when (@index =< length(@arr-style)) { 24 | @token: e(extract(@arr-style, @index)); 25 | @color: extract(@arr-style, @index + 1); 26 | @bg: screen(@color, #eee); 27 | 28 | .notification.notification-@{token} { 29 | border-left-color: darken(@bg, 10%); 30 | background-color: @bg; 31 | color: darken(@color, 2%); 32 | } 33 | 34 | .notification-palette(@arr-style, @index + 2); 35 | } 36 | 37 | .notification-palette(@notification-palette); -------------------------------------------------------------------------------- /client/public/styles/components/pagination.less: -------------------------------------------------------------------------------- 1 | .pagination { 2 | > li > a, 3 | > li > span { color: rgb(55, 62, 74); } 4 | 5 | > li > a { cursor: pointer; } 6 | 7 | > .active > a, 8 | > .active > span, 9 | > .active > a:hover, 10 | > .active > span:hover, 11 | > .active > a:focus, 12 | > .active > span:focus { 13 | background-color: rgb(48, 54, 65); 14 | border-color: rgb(48, 54, 65); 15 | cursor: default; 16 | } 17 | 18 | > .disabled > span, 19 | > .disabled > span:hover, 20 | > .disabled > span:focus, 21 | > .disabled > a, 22 | > .disabled > a:hover, 23 | > .disabled > a:focus { 24 | color: rgb(153, 153, 153); 25 | background-color: rgb(255, 255, 255); 26 | border-color: rgb(221, 221, 221); 27 | cursor: not-allowed; 28 | } 29 | } 30 | 31 | .pager { 32 | > li > a, 33 | > li > span { .border-radius(3px); } 34 | } -------------------------------------------------------------------------------- /client/public/styles/components/progress-bars.less: -------------------------------------------------------------------------------- 1 | .table { 2 | > thead > tr > th .progress, 3 | > tbody > tr > th .progress, 4 | > tfoot > tr > th .progress, 5 | > thead > tr > td .progress, 6 | > tbody > tr > td .progress, 7 | > tfoot > tr > td .progress { 8 | margin-bottom: 0; 9 | } 10 | } 11 | 12 | 13 | .progress-bar-palette(@arr-style, @index: 1) when (@index =< length(@arr-style)) { 14 | @token: e(extract(@arr-style, @index)); 15 | @color: extract(@arr-style, @index + 1); 16 | 17 | .progress-bar-@{token} { 18 | .progress-bar-variant(@color); 19 | } 20 | 21 | .progress-bar-palette(@arr-style, @index + 2); 22 | } 23 | 24 | .progress-bar-palette(@arr-progress); -------------------------------------------------------------------------------- /client/public/styles/core/buttons.less: -------------------------------------------------------------------------------- 1 | // Buttons 2 | // ----------------- 3 | 4 | .btn { 5 | border-width: 0; 6 | border-bottom: 3px solid darken(@gray, 10%); 7 | font-size: 14px; 8 | .button-variant(@black, @gray, @gray); 9 | .transition(background-color .35s, border-color .35s); 10 | 11 | > i { 12 | width: 14px; 13 | } 14 | } 15 | 16 | // Button With Icon 17 | // ================ 18 | 19 | .btn.btn-icon { 20 | position: relative; 21 | padding-right: 40px; 22 | border: 0; 23 | 24 | > i { 25 | background-color: darken(@gray, 12%); 26 | border-radius: 0 3px 3px 0; 27 | display: inline-block; 28 | font-size: 12px; 29 | height: 100%; 30 | line-height: 1.7em; 31 | margin-left: -3px; 32 | padding: 6px 6px; 33 | position: absolute; 34 | right: 0; 35 | top: 0; 36 | vertical-align: middle; 37 | width: 30px; 38 | } 39 | 40 | &.icon-left { 41 | padding-left: 40px; 42 | padding-right: 12px; 43 | } 44 | 45 | &.icon-left > i { 46 | float: left; 47 | right: auto; 48 | left: 3px; 49 | border-radius: 3px 0 0 3px !important; 50 | } 51 | } 52 | 53 | .input-group .input-group-btn .btn { 54 | border-color: @gray; 55 | border-width: 1px; 56 | } 57 | 58 | .btn-palette(@arr-style, @index: 1) when (@index =< length(@arr-style)) { 59 | @token: e(extract(@arr-style, @index)); 60 | @color: extract(@arr-style, @index + 1); 61 | 62 | .btn.btn-@{token} { 63 | .button-variant(#fff, @color, darken(@color, 12%)); 64 | 65 | &.btn-icon > i { 66 | background-color: darken(@color, 12%); 67 | } 68 | 69 | .input-group .input-group-btn & { 70 | border-color: @color; 71 | border-width: 1px; 72 | } 73 | } 74 | 75 | .btn-palette(@arr-style, @index + 2); 76 | } 77 | 78 | .btn-palette(@btn-palette); 79 | 80 | 81 | // Utilties 82 | // =============== 83 | 84 | .btn.btn-mini { 85 | font-size: 12px; 86 | padding: 3px 6px; 87 | } 88 | 89 | .btn.btn-square { 90 | .border-radius(0); 91 | } 92 | 93 | .btn.btn-purity { 94 | border-bottom-width: 0 !important; 95 | } -------------------------------------------------------------------------------- /client/public/styles/core/forms.less: -------------------------------------------------------------------------------- 1 | .form-group { 2 | position: relative; 3 | } 4 | 5 | .form-group > .control-label { 6 | color: #999; 7 | font-weight: normal; 8 | } 9 | 10 | .form-control { 11 | .border-radius(0); 12 | .box-shadow(none); 13 | .placeholder(#b5b5b5); 14 | .transition(border-color .2s); 15 | 16 | background-image: none; 17 | background-color: #fff; 18 | border: 1px solid #eee; 19 | border-radius: 4px; 20 | color: #666; 21 | display: block; 22 | font-size: 14px; 23 | line-height: @line-height-base; 24 | padding: 8px 15px; 25 | width: 100%; 26 | 27 | &:focus { 28 | .box-shadow(none); 29 | 30 | background-color: #fefefe; 31 | border-color: #bbb; 32 | outline: 0; 33 | } 34 | } 35 | 36 | .form-control-palette(@arr-style, @index: 1) when (@index =< length(@arr-style)) { 37 | @token: e(extract(@arr-style, @index)); 38 | @color: extract(@arr-style, @index + 1); 39 | 40 | .has-@{token} .control-label { 41 | color: @color; 42 | } 43 | 44 | .has-@{token} .form-control, 45 | .has-@{token} .form-control:focus { 46 | .box-shadow(none); 47 | border-color: @color; 48 | } 49 | 50 | .form-control-palette(@arr-style, @index + 2); 51 | } 52 | 53 | .form-control-palette(@form-control-palette); 54 | 55 | 56 | 57 | // 输入框提示 58 | .form-control-prompt { 59 | .border-radius(5px); 60 | 61 | width: 100%; 62 | display: none; 63 | border: 1px solid #5bc0de; 64 | background-color: #5bc0de; 65 | position: absolute; 66 | left: 0; 67 | top: 100%; 68 | z-index: 999; 69 | text-align: left; 70 | 71 | &.show { 72 | .animation(fadeIn .35s forwards); 73 | display: block; 74 | } 75 | } 76 | 77 | .form-control-prompt > .content { 78 | padding: 10px 16px; 79 | display: block; 80 | color: #fff; 81 | font-size: 14px; 82 | } 83 | 84 | .make-form-control-prompt-offset(@arr-offset, @size, @name, @color, @index: 1) when (@index =< length(@arr-offset)) { 85 | @direction: extract(@arr-offset, @index); 86 | @offset: extract(@arr-offset, @index + 1); 87 | 88 | .form-control-prompt.@{direction} > .arrow { .arrow-mixin(@size, @color, @direction, @offset); } 89 | 90 | .form-group.@{name} .form-control-prompt.@{direction} > .arrow, 91 | .form-control-prompt.@{name}.@{direction} > .arrow { .arrow-mixin > .color(@color, @direction); } 92 | 93 | .make-form-control-prompt-offset(@arr-offset, @size, @name, @color, @index + 2); 94 | } 95 | 96 | .make-form-control-prompt-arrow(@arr-style, @arr-offset, @size, @index: 1) when (@index =< length(@arr-style)) { 97 | @name: e(extract(@arr-style, @index)); 98 | @color: extract(@arr-style, @index + 1); 99 | 100 | .form-group.@{name} .form-control-prompt, 101 | .form-control-prompt.@{name} { 102 | border-color: @color; 103 | background-color: @color; 104 | } 105 | 106 | .make-form-control-prompt-offset(@arr-offset, @size, @name, @color); 107 | .make-form-control-prompt-arrow(@arr-style, @arr-offset, @size, @index + 2); 108 | } 109 | 110 | @form-control-prompt-size: 10px; 111 | @arr-form-control-prompt-offset: 112 | top 8% 113 | right 95% 114 | bottom 95% 115 | left 95% 116 | ; 117 | 118 | @arr-form-control-prompt-style: 119 | 'green' @green 120 | 'cyan' @cyan 121 | 'orange' @orange 122 | 'red' @red 123 | 'amethyst' @amethyst 124 | 'pink' @pink 125 | 'gray' @gray 126 | 'black' @black 127 | ; 128 | 129 | .make-form-control-prompt-arrow(@arr-form-control-prompt-style, @arr-form-control-prompt-offset, @form-control-prompt-size); 130 | 131 | -------------------------------------------------------------------------------- /client/public/styles/core/grid.less: -------------------------------------------------------------------------------- 1 | .container.container-sm { 2 | @media (max-width: @screen-xs-max) { 3 | width: 100%; 4 | } 5 | } 6 | 7 | .container.container-md { 8 | @media (max-width: @screen-sm-max) { 9 | width: 100%; 10 | } 11 | } 12 | 13 | .container.container-lg { 14 | @media (max-width: @screen-md-max) { 15 | width: 100%; 16 | } 17 | } -------------------------------------------------------------------------------- /client/public/styles/core/layout.less: -------------------------------------------------------------------------------- 1 | // Layout 2 | // --------------------- 3 | 4 | .container-layout { 5 | width: 100%; 6 | .clearfix(); 7 | overflow-x: hidden; 8 | 9 | .main-layout { 10 | position: relative; 11 | width: 100%; 12 | .transition(all .25s ease); 13 | 14 | .content-layout { 15 | padding: 15px 15px 30px 15px; 16 | } 17 | } 18 | } 19 | 20 | 21 | // Aside Layout 22 | // =========================== 23 | 24 | .container-layout { 25 | .aside-layout { 26 | display: block; 27 | position: absolute; 28 | top: 0; 29 | z-index: 4; 30 | .clearfix(); 31 | height: 100%; 32 | .transition(transform .25s ease); 33 | } 34 | 35 | .aside-layout.fixed-layout { 36 | position: fixed; 37 | } 38 | } 39 | 40 | .fixed-layout { 41 | &, 42 | .container-layout, 43 | .container-layout .main-layout, 44 | .container-layout .main-layout .viewport-layout { 45 | height: 100%; 46 | display: block; 47 | overflow-y: hidden; 48 | } 49 | 50 | .container-layout .main-layout { 51 | .transition(all .25s ease); 52 | } 53 | 54 | .container-layout .main-layout .content-layout { 55 | height: 100%; 56 | overflow-y: auto; 57 | } 58 | } -------------------------------------------------------------------------------- /client/public/styles/effects/fonts.less: -------------------------------------------------------------------------------- 1 | @cdn-font-path: '../../fonts'; 2 | 3 | @font-face { 4 | @fa-version: 4.3.0; 5 | font-family: 'FontAwesome'; 6 | src: url('@{cdn-font-path}/font-awesome/fontawesome-webfont.eot?v=@{fa-version}'); 7 | src: url('@{cdn-font-path}/font-awesome/fontawesome-webfont.eot?#iefix&v=@{fa-version}') format('embedded-opentype'), 8 | url('@{cdn-font-path}/font-awesome/fontawesome-webfont.woff?v=@{fa-version}') format('woff'), 9 | url('@{cdn-font-path}/font-awesome/fontawesome-webfont.ttf?v=@{fa-version}') format('truetype'), 10 | url('@{cdn-font-path}/font-awesome/fontawesome-webfont.svg?v=@{fa-version}#fontawesomeregular') format('svg'); 11 | font-weight: normal; 12 | font-style: normal; 13 | } 14 | 15 | @font-face { 16 | @fa-version: 1.0.0; 17 | font-family: 'Crimsontext'; 18 | src: url('@{cdn-font-path}/crimsontext/crimsontext-bolditalic.eot?v=@{fa-version}'); 19 | src: url('@{cdn-font-path}/crimsontext/crimsontext-bolditalic.eot?#iefix&v=@{fa-version}') format('embedded-opentype'), 20 | url('@{cdn-font-path}/crimsontext/crimsontext-bolditalic.woff?v=@{fa-version}') format('woff'), 21 | url('@{cdn-font-path}/crimsontext/crimsontext-bolditalic.ttf?v=@{fa-version}') format('truetype'), 22 | url('@{cdn-font-path}/crimsontext/crimsontext-bolditalic.svg?v=@{fa-version}#fontawesomeregular') format('svg'); 23 | font-weight: normal; 24 | font-style: normal; 25 | } -------------------------------------------------------------------------------- /client/public/styles/mixins/alerts.less: -------------------------------------------------------------------------------- 1 | // Alerts 2 | 3 | .alert-variant(@background; @border; @text-color) { 4 | background-color: @background; 5 | border-color: @border; 6 | color: @text-color; 7 | 8 | hr { 9 | border-top-color: darken(@border, 5%); 10 | } 11 | .alert-link { 12 | color: darken(@text-color, 10%); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /client/public/styles/mixins/background-variant.less: -------------------------------------------------------------------------------- 1 | // Contextual backgrounds 2 | 3 | .bg-variant(@color) { 4 | background-color: @color; 5 | a&:hover { 6 | background-color: darken(@color, 10%); 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /client/public/styles/mixins/border-radius.less: -------------------------------------------------------------------------------- 1 | // Single side border-radius 2 | 3 | .border-top-radius(@radius) { 4 | border-top-right-radius: @radius; 5 | border-top-left-radius: @radius; 6 | } 7 | .border-right-radius(@radius) { 8 | border-bottom-right-radius: @radius; 9 | border-top-right-radius: @radius; 10 | } 11 | .border-bottom-radius(@radius) { 12 | border-bottom-right-radius: @radius; 13 | border-bottom-left-radius: @radius; 14 | } 15 | .border-left-radius(@radius) { 16 | border-bottom-left-radius: @radius; 17 | border-top-left-radius: @radius; 18 | } 19 | -------------------------------------------------------------------------------- /client/public/styles/mixins/buttons.less: -------------------------------------------------------------------------------- 1 | // Button variants 2 | // 3 | // Easily pump out default styles, as well as :hover, :focus, :active, 4 | // and disabled options for all buttons 5 | 6 | .button-variant(@color; @background; @border) { 7 | color: @color; 8 | background-color: @background; 9 | border-color: @border; 10 | 11 | &:hover, 12 | &:focus, 13 | &.focus, 14 | &:active, 15 | &.active, 16 | .open > .dropdown-toggle& { 17 | color: @color; 18 | background-color: darken(@background, 10%); 19 | border-color: darken(@border, 12%); 20 | } 21 | &:active, 22 | &.active, 23 | .open > .dropdown-toggle& { 24 | background-image: none; 25 | } 26 | &.disabled, 27 | &[disabled], 28 | fieldset[disabled] & { 29 | &, 30 | &:hover, 31 | &:focus, 32 | &.focus, 33 | &:active, 34 | &.active { 35 | background-color: @background; 36 | border-color: @border; 37 | } 38 | } 39 | 40 | .badge { 41 | color: @background; 42 | background-color: @color; 43 | } 44 | } 45 | 46 | // Button sizes 47 | .button-size(@padding-vertical; @padding-horizontal; @font-size; @line-height; @border-radius) { 48 | padding: @padding-vertical @padding-horizontal; 49 | font-size: @font-size; 50 | line-height: @line-height; 51 | border-radius: @border-radius; 52 | } 53 | -------------------------------------------------------------------------------- /client/public/styles/mixins/center-block.less: -------------------------------------------------------------------------------- 1 | // Center-align a block level element 2 | 3 | .center-block() { 4 | display: block; 5 | margin-left: auto; 6 | margin-right: auto; 7 | } 8 | -------------------------------------------------------------------------------- /client/public/styles/mixins/clearfix.less: -------------------------------------------------------------------------------- 1 | // Clearfix 2 | // 3 | // For modern browsers 4 | // 1. The space content is one way to avoid an Opera bug when the 5 | // contenteditable attribute is included anywhere else in the document. 6 | // Otherwise it causes space to appear at the top and bottom of elements 7 | // that are clearfixed. 8 | // 2. The use of `table` rather than `block` is only necessary if using 9 | // `:before` to contain the top-margins of child elements. 10 | // 11 | // Source: http://nicolasgallagher.com/micro-clearfix-hack/ 12 | 13 | .clearfix() { 14 | &:before, 15 | &:after { 16 | content: " "; // 1 17 | display: table; // 2 18 | } 19 | &:after { 20 | clear: both; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /client/public/styles/mixins/color.less: -------------------------------------------------------------------------------- 1 | .anti-color(@bg-color) when(lighten(@bg-color, 14%) = #fff) { 2 | color: negation(@bg-color, #ccc); 3 | } 4 | -------------------------------------------------------------------------------- /client/public/styles/mixins/forms.less: -------------------------------------------------------------------------------- 1 | // Form validation states 2 | // 3 | // Used in forms.less to generate the form validation CSS for warnings, errors, 4 | // and successes. 5 | 6 | .form-control-validation(@text-color: #555; @border-color: #ccc; @background-color: #f5f5f5) { 7 | // Color the label and help text 8 | .help-block, 9 | .control-label, 10 | .radio, 11 | .checkbox, 12 | .radio-inline, 13 | .checkbox-inline, 14 | &.radio label, 15 | &.checkbox label, 16 | &.radio-inline label, 17 | &.checkbox-inline label { 18 | color: @text-color; 19 | } 20 | // Set the border and box shadow on specific inputs to match 21 | .form-control { 22 | border-color: @border-color; 23 | .box-shadow(inset 0 1px 1px rgba(0,0,0,.075)); // Redeclare so transitions work 24 | &:focus { 25 | border-color: darken(@border-color, 10%); 26 | @shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 6px lighten(@border-color, 20%); 27 | .box-shadow(@shadow); 28 | } 29 | } 30 | // Set validation states also for addons 31 | .input-group-addon { 32 | color: @text-color; 33 | border-color: @border-color; 34 | background-color: @background-color; 35 | } 36 | // Optional feedback icon 37 | .form-control-feedback { 38 | color: @text-color; 39 | } 40 | } 41 | 42 | 43 | // Form control focus state 44 | // 45 | // Generate a customized focus state and for any input with the specified color, 46 | // which defaults to the `@input-border-focus` variable. 47 | // 48 | // We highly encourage you to not customize the default value, but instead use 49 | // this to tweak colors on an as-needed basis. This aesthetic change is based on 50 | // WebKit's default styles, but applicable to a wider range of browsers. Its 51 | // usability and accessibility should be taken into account with any change. 52 | // 53 | // Example usage: change the default blue border and shadow to white for better 54 | // contrast against a dark gray background. 55 | .form-control-focus(@color: @input-border-focus) { 56 | @color-rgba: rgba(red(@color), green(@color), blue(@color), .6); 57 | &:focus { 58 | border-color: @color; 59 | outline: 0; 60 | .box-shadow(~"inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px @{color-rgba}"); 61 | } 62 | } 63 | 64 | // Form control sizing 65 | // 66 | // Relative text size, padding, and border-radii changes for form controls. For 67 | // horizontal sizing, wrap controls in the predefined grid classes. `