├── .editorconfig ├── .github ├── FUNDING.yml ├── ISSUE_TEMPLATE │ ├── bug_report.md │ └── feature_request.md └── workflows │ ├── ci.yml │ └── pr.yml ├── .gitignore ├── CNAME ├── LICENSE ├── README.md ├── SECURITY.md ├── _config.yml ├── angular.json ├── browserslist ├── e2e ├── protractor.conf.js ├── src │ ├── app.e2e-spec.ts │ └── app.po.ts └── tsconfig.json ├── karma.conf.js ├── package.json ├── projects └── @ledge-framework │ ├── render │ ├── .gitignore │ ├── README.md │ ├── gulpfile.js │ ├── karma.conf.js │ ├── ng-package.json │ ├── package.json │ ├── src │ │ ├── lib │ │ │ ├── chart │ │ │ │ ├── ledge-bar-chart │ │ │ │ │ ├── ledge-bar-chart.component.html │ │ │ │ │ ├── ledge-bar-chart.component.scss │ │ │ │ │ ├── ledge-bar-chart.component.spec.ts │ │ │ │ │ └── ledge-bar-chart.component.ts │ │ │ │ ├── ledge-fish-bone │ │ │ │ │ ├── fishbone.ts │ │ │ │ │ ├── ledge-fish-bone.component.html │ │ │ │ │ ├── ledge-fish-bone.component.scss │ │ │ │ │ ├── ledge-fish-bone.component.spec.ts │ │ │ │ │ └── ledge-fish-bone.component.ts │ │ │ │ ├── ledge-graphviz │ │ │ │ │ ├── ledge-graphviz.component.html │ │ │ │ │ ├── ledge-graphviz.component.scss │ │ │ │ │ └── ledge-graphviz.component.ts │ │ │ │ ├── ledge-heatmap │ │ │ │ │ ├── ledge-heatmap.component.html │ │ │ │ │ ├── ledge-heatmap.component.scss │ │ │ │ │ ├── ledge-heatmap.component.spec.ts │ │ │ │ │ └── ledge-heatmap.component.ts │ │ │ │ ├── ledge-mindmap │ │ │ │ │ ├── ledge-mindmap.component.html │ │ │ │ │ ├── ledge-mindmap.component.scss │ │ │ │ │ ├── ledge-mindmap.component.spec.ts │ │ │ │ │ └── ledge-mindmap.component.ts │ │ │ │ ├── ledge-pie │ │ │ │ │ ├── ledge-pie.component.html │ │ │ │ │ ├── ledge-pie.component.scss │ │ │ │ │ ├── ledge-pie.component.spec.ts │ │ │ │ │ └── ledge-pie.component.ts │ │ │ │ ├── ledge-pipeline │ │ │ │ │ ├── ledge-pipeline.component.html │ │ │ │ │ ├── ledge-pipeline.component.scss │ │ │ │ │ ├── ledge-pipeline.component.spec.ts │ │ │ │ │ ├── ledge-pipeline.component.ts │ │ │ │ │ └── ledge-pipeline.model.ts │ │ │ │ ├── ledge-pure-echarts │ │ │ │ │ ├── ledge-pure-echarts.component.html │ │ │ │ │ ├── ledge-pure-echarts.component.scss │ │ │ │ │ ├── ledge-pure-echarts.component.spec.ts │ │ │ │ │ └── ledge-pure-echarts.component.ts │ │ │ │ ├── ledge-pyramid │ │ │ │ │ ├── ledge-pyramid.component.html │ │ │ │ │ ├── ledge-pyramid.component.scss │ │ │ │ │ ├── ledge-pyramid.component.spec.ts │ │ │ │ │ └── ledge-pyramid.component.ts │ │ │ │ ├── ledge-quadrant │ │ │ │ │ ├── ledge-quadrant.component.html │ │ │ │ │ ├── ledge-quadrant.component.scss │ │ │ │ │ ├── ledge-quadrant.component.spec.ts │ │ │ │ │ └── ledge-quadrant.component.ts │ │ │ │ ├── ledge-radar │ │ │ │ │ ├── ledge-radar.component.html │ │ │ │ │ ├── ledge-radar.component.scss │ │ │ │ │ ├── ledge-radar.component.spec.ts │ │ │ │ │ └── ledge-radar.component.ts │ │ │ │ ├── ledge-sunburst │ │ │ │ │ ├── ledge-sunburst.component.html │ │ │ │ │ ├── ledge-sunburst.component.scss │ │ │ │ │ ├── ledge-sunburst.component.spec.ts │ │ │ │ │ └── ledge-sunburst.component.ts │ │ │ │ ├── ledge-tech-radar │ │ │ │ │ ├── ledge-tech-radar.component.html │ │ │ │ │ ├── ledge-tech-radar.component.scss │ │ │ │ │ ├── ledge-tech-radar.component.spec.ts │ │ │ │ │ └── ledge-tech-radar.component.ts │ │ │ │ └── ledge-tree │ │ │ │ │ ├── ledge-tree.component.html │ │ │ │ │ ├── ledge-tree.component.scss │ │ │ │ │ ├── ledge-tree.component.spec.ts │ │ │ │ │ └── ledge-tree.component.ts │ │ │ ├── components │ │ │ │ ├── component-checklist │ │ │ │ │ ├── component-checklist.component.html │ │ │ │ │ ├── component-checklist.component.scss │ │ │ │ │ ├── component-checklist.component.spec.ts │ │ │ │ │ └── component-checklist.component.ts │ │ │ │ ├── component-rating-item │ │ │ │ │ ├── component-rating-item.component.html │ │ │ │ │ ├── component-rating-item.component.scss │ │ │ │ │ ├── component-rating-item.component.spec.ts │ │ │ │ │ └── component-rating-item.component.ts │ │ │ │ ├── component-rating │ │ │ │ │ ├── component-rating.component.html │ │ │ │ │ ├── component-rating.component.scss │ │ │ │ │ ├── component-rating.component.spec.ts │ │ │ │ │ └── component-rating.component.ts │ │ │ │ ├── component-todo │ │ │ │ │ ├── component-todo.component.html │ │ │ │ │ ├── component-todo.component.scss │ │ │ │ │ ├── component-todo.component.spec.ts │ │ │ │ │ └── component-todo.component.ts │ │ │ │ ├── ledge-card │ │ │ │ │ ├── ledge-card.component.html │ │ │ │ │ ├── ledge-card.component.scss │ │ │ │ │ ├── ledge-card.component.spec.ts │ │ │ │ │ ├── ledge-card.component.ts │ │ │ │ │ └── lege-card-colors.ts │ │ │ │ ├── ledge-checklist │ │ │ │ │ ├── ledge-checklist.component.html │ │ │ │ │ ├── ledge-checklist.component.scss │ │ │ │ │ ├── ledge-checklist.component.spec.ts │ │ │ │ │ └── ledge-checklist.component.ts │ │ │ │ ├── ledge-dev-process │ │ │ │ │ ├── ledge-dev-process.component.html │ │ │ │ │ ├── ledge-dev-process.component.scss │ │ │ │ │ ├── ledge-dev-process.component.spec.ts │ │ │ │ │ └── ledge-dev-process.component.ts │ │ │ │ ├── ledge-kanban │ │ │ │ │ ├── README.md │ │ │ │ │ ├── ledge-kanban.component.html │ │ │ │ │ ├── ledge-kanban.component.scss │ │ │ │ │ ├── ledge-kanban.component.spec.ts │ │ │ │ │ ├── ledge-kanban.component.ts │ │ │ │ │ └── model │ │ │ │ │ │ ├── board.ts │ │ │ │ │ │ └── column.ts │ │ │ │ ├── ledge-maturity │ │ │ │ │ ├── ledge-maturity.component.html │ │ │ │ │ ├── ledge-maturity.component.scss │ │ │ │ │ ├── ledge-maturity.component.spec.ts │ │ │ │ │ └── ledge-maturity.component.ts │ │ │ │ ├── ledge-mermaid │ │ │ │ │ ├── ledge-mermaid.component.html │ │ │ │ │ ├── ledge-mermaid.component.scss │ │ │ │ │ ├── ledge-mermaid.component.spec.ts │ │ │ │ │ └── ledge-mermaid.component.ts │ │ │ │ ├── ledge-process-step │ │ │ │ │ ├── ledge-process-step.component.html │ │ │ │ │ ├── ledge-process-step.component.scss │ │ │ │ │ ├── ledge-process-step.component.spec.ts │ │ │ │ │ └── ledge-process-step.component.ts │ │ │ │ ├── ledge-step-line │ │ │ │ │ ├── ledge-step-line.component.html │ │ │ │ │ ├── ledge-step-line.component.scss │ │ │ │ │ ├── ledge-step-line.component.spec.ts │ │ │ │ │ └── ledge-step-line.component.ts │ │ │ │ ├── ledge-table-step │ │ │ │ │ ├── ledge-table-step.component.html │ │ │ │ │ ├── ledge-table-step.component.scss │ │ │ │ │ ├── ledge-table-step.component.spec.ts │ │ │ │ │ └── ledge-table-step.component.ts │ │ │ │ └── model │ │ │ │ │ ├── checklist.model.ts │ │ │ │ │ ├── ledge-chart-converter.ts │ │ │ │ │ ├── ledge-chart.model.ts │ │ │ │ │ ├── ledge-markdown-converter.spec.ts │ │ │ │ │ ├── ledge-markdown-converter.ts │ │ │ │ │ ├── markdown.helper.ts │ │ │ │ │ ├── markdown.model.ts │ │ │ │ │ ├── rating.model.ts │ │ │ │ │ └── todo.model.ts │ │ │ ├── custom-material.module.ts │ │ │ ├── ledge-render.component.html │ │ │ ├── ledge-render.component.scss │ │ │ ├── ledge-render.component.spec.ts │ │ │ ├── ledge-render.component.ts │ │ │ ├── ledge-render.module.ts │ │ │ ├── pipes │ │ │ │ ├── tohtml.pipe.spec.ts │ │ │ │ └── tohtml.pipe.ts │ │ │ ├── services │ │ │ │ └── ledge-storage.service.ts │ │ │ ├── styles │ │ │ │ └── _list-style.scss │ │ │ ├── support │ │ │ │ └── ledgeColors.ts │ │ │ ├── theme │ │ │ │ ├── base │ │ │ │ │ ├── _behavior.scss │ │ │ │ │ └── _type.scss │ │ │ │ ├── fish-bone.scss │ │ │ │ ├── graphviz.scss │ │ │ │ ├── index.scss │ │ │ │ ├── maturity.scss │ │ │ │ ├── mermaid.scss │ │ │ │ ├── process-table.scss │ │ │ │ ├── tech-radar.scss │ │ │ │ └── tree.scss │ │ │ └── toolset │ │ │ │ ├── toolset.component.html │ │ │ │ ├── toolset.component.scss │ │ │ │ ├── toolset.component.spec.ts │ │ │ │ ├── toolset.component.ts │ │ │ │ └── toolset.ts │ │ ├── public-api.ts │ │ └── test.ts │ ├── tsconfig.lib.json │ ├── tsconfig.lib.prod.json │ ├── tsconfig.spec.json │ ├── tslint.json │ └── yarn.lock │ └── view │ ├── README.md │ ├── karma.conf.js │ ├── ng-package.json │ ├── package.json │ ├── src │ ├── lib │ │ ├── custom-material.module.ts │ │ ├── ledge-markdown-render │ │ │ ├── ledge-markdown-render.component.html │ │ │ ├── ledge-markdown-render.component.scss │ │ │ ├── ledge-markdown-render.component.spec.ts │ │ │ ├── ledge-markdown-render.component.ts │ │ │ └── tocify.ts │ │ ├── ledge-multiple-docs │ │ │ ├── doc-route.model.ts │ │ │ ├── ledge-multiple-docs.component.html │ │ │ ├── ledge-multiple-docs.component.scss │ │ │ ├── ledge-multiple-docs.component.spec.ts │ │ │ └── ledge-multiple-docs.component.ts │ │ └── ledge-view.module.ts │ ├── public-api.ts │ └── test.ts │ ├── tsconfig.lib.json │ ├── tsconfig.lib.prod.json │ ├── tsconfig.spec.json │ ├── tslint.json │ └── yarn.lock ├── src ├── app │ ├── app-routing.module.ts │ ├── app.module.ts │ ├── globals.d.ts │ ├── ledge-editor │ │ ├── ledge-editor.component.html │ │ ├── ledge-editor.component.scss │ │ ├── ledge-editor.component.spec.ts │ │ ├── ledge-editor.component.ts │ │ └── ledge-editor.module.ts │ └── ledge │ │ ├── ledge.component.html │ │ ├── ledge.component.scss │ │ ├── ledge.component.spec.ts │ │ └── ledge.component.ts ├── assets │ ├── .gitkeep │ └── docs │ │ └── help.md ├── environments │ ├── environment.prod.ts │ └── environment.ts ├── favicon.ico ├── index.html ├── main.ts ├── polyfills.ts ├── styles.scss └── test.ts ├── stories └── 9qPuTQRMg-support-web-components.feature ├── tsconfig.app.json ├── tsconfig.json ├── tsconfig.spec.json ├── tslint.json └── yarn.lock /.editorconfig: -------------------------------------------------------------------------------- 1 | # Editor configuration, see https://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | charset = utf-8 6 | indent_style = space 7 | indent_size = 2 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | 11 | [*.md] 12 | max_line_length = off 13 | trim_trailing_whitespace = false 14 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: phodal 4 | patreon: phodal 5 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: 🐛 Bug Report 3 | about: Did something not work as expected? 4 | --- 5 | 6 | 11 | 12 | 21 | 22 | ## Bug Report 23 | 24 | 29 | 30 | ## Current Behavior? 31 | 32 | 37 | 38 | 43 | 44 | ## Expected Behavior? 45 | 46 | 51 | 52 | ## Steps to reproduce [Optional] 53 | 54 | 59 | 60 | 61 | ## Your Environment [Optional] 62 | 63 | 68 | 69 | 74 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: 🙋 Feature Request 3 | about: Want us to add something to Ledge? 4 | --- 5 | 6 | 11 | 12 | 21 | 22 | ## Feature Request 23 | 24 | 35 | 36 | ## What does the proposed API examples? 37 | 38 | 43 | 44 | ## Other reference [Optional] 45 | 46 | 51 | 52 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | # This is a basic workflow to help you get started with Actions 2 | 3 | name: CI 4 | 5 | # Controls when the action will run. Triggers the workflow on push or pull request 6 | # events but only for the master branch 7 | on: 8 | push: 9 | branches: [master] 10 | 11 | # A workflow run is made up of one or more jobs that can run sequentially or in parallel 12 | jobs: 13 | # This workflow contains a single job called "build" 14 | build: 15 | # The type of runner that the job will run on 16 | runs-on: ubuntu-latest 17 | 18 | steps: 19 | - name: Checkout 20 | uses: actions/checkout@v2 # If you're using actions/checkout@v2 you must set persist-credentials to false in most cases for the deployment to work correctly. 21 | with: 22 | persist-credentials: false 23 | 24 | - name: Use Node.js 12.x 25 | uses: actions/setup-node@v1 26 | with: 27 | node-version: "12.x" 28 | 29 | - name: Get yarn cache directory path 30 | id: yarn-cache-dir-path 31 | run: echo "::set-output name=dir::$(yarn cache dir)" 32 | 33 | - uses: actions/cache@v1 34 | id: yarn-cache # use this to check for `cache-hit` (`steps.yarn-cache.outputs.cache-hit != 'true'`) 35 | with: 36 | path: ${{ steps.yarn-cache-dir-path.outputs.dir }} 37 | key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }} 38 | restore-keys: | 39 | ${{ runner.os }}-yarn- 40 | 41 | - name: Install 42 | run: | 43 | yarn install 44 | 45 | - name: Lint 46 | run: | 47 | yarn lint 48 | 49 | - name: Build 50 | run: | 51 | yarn build:ci 52 | 53 | - name: Testing 54 | run: yarn test:ci 55 | 56 | - name: Upload coverage to Codecov 57 | uses: codecov/codecov-action@v1 58 | with: 59 | file: ./coverage/ledge/lcov.info 60 | flags: unittests 61 | name: codecov-umbrella 62 | fail_ci_if_error: false 63 | -------------------------------------------------------------------------------- /.github/workflows/pr.yml: -------------------------------------------------------------------------------- 1 | # This is a basic workflow to help you get started with Actions 2 | 3 | name: PULL REQUEST 4 | 5 | # Controls when the action will run. Triggers the workflow on push or pull request 6 | # events but only for the master branch 7 | on: 8 | pull_request: 9 | branches: [master] 10 | 11 | # A workflow run is made up of one or more jobs that can run sequentially or in parallel 12 | jobs: 13 | # This workflow contains a single job called "build" 14 | build: 15 | # The type of runner that the job will run on 16 | runs-on: ubuntu-latest 17 | 18 | steps: 19 | - name: Checkout 20 | uses: actions/checkout@v2 # If you're using actions/checkout@v2 you must set persist-credentials to false in most cases for the deployment to work correctly. 21 | with: 22 | persist-credentials: false 23 | 24 | - name: Use Node.js 12.x 25 | uses: actions/setup-node@v1 26 | with: 27 | node-version: "12.x" 28 | 29 | - name: Install 30 | run: | 31 | yarn install 32 | 33 | - name: Lint 34 | run: | 35 | yarn lint 36 | 37 | - name: Testing 38 | run: yarn test:ci 39 | 40 | - name: Build 41 | run: yarn build:ci 42 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See http://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # compiled output 4 | /dist 5 | /tmp 6 | /out-tsc 7 | prebuild-theme 8 | 9 | # Only exists if Bazel was run 10 | /bazel-out 11 | 12 | # dependencies 13 | /node_modules 14 | 15 | # profiling files 16 | chrome-profiler-events*.json 17 | speed-measure-plugin*.json 18 | 19 | # IDEs and editors 20 | /.idea 21 | .project 22 | .classpath 23 | .c9/ 24 | *.launch 25 | .settings/ 26 | *.sublime-workspace 27 | 28 | # IDE - VSCode 29 | .vscode/* 30 | !.vscode/settings.json 31 | !.vscode/tasks.json 32 | !.vscode/launch.json 33 | !.vscode/extensions.json 34 | .history/* 35 | 36 | # misc 37 | /.sass-cache 38 | /connect.lock 39 | /coverage 40 | /libpeerconnection.log 41 | npm-debug.log 42 | yarn-error.log 43 | testem.log 44 | /typings 45 | 46 | # System Files 47 | .DS_Store 48 | Thumbs.db 49 | package-lock.json 50 | .idea/ 51 | plugins/.idea 52 | */coverage/ 53 | -------------------------------------------------------------------------------- /CNAME: -------------------------------------------------------------------------------- 1 | jekyll.ledge.ink -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Ledge Framework Engine 2 | 3 | > Legde framework is a documentation as code practises framework. 4 | 5 | demo page: [https://devops.phodal.com/helper](https://devops.phodal.com/helper) 6 | 7 | online editor: [https://devops.phodal.com/helper](https://devops.phodal.com/helper) 8 | 9 | ![CI](https://github.com/ledge-framework/engine/workflows/CI/badge.svg) 10 | ![npm](https://img.shields.io/npm/v/@ledge-framework/render?label=%40ledge-framework%2Frender) 11 | ![npm](https://img.shields.io/npm/v/@ledge-framework/view?label=%40ledge-framework%2Fview) 12 | 13 | ## Syntax 14 | 15 | ### Ledge extend code syntax 16 | 17 | ```` 18 | ```process-step 19 | - step1 20 | - demo 21 | - kanban 22 | ``` 23 | ```` 24 | 25 | - Chart 26 | - echarts. Echarts chart. 27 | - chart. Echarts bar chart. 28 | - mindmap. Markdown List to mindmap. 29 | - radar. Markdown List to radar chart. 30 | - tech radar. Markdown list to tech radar chart. 31 | - pie。Pie chart 32 | - quadrant。quadrant chart 33 | - pyramid。pyramid chart 34 | - graphviz。dot to graph 35 | - process visualization 36 | - process-table。process chart 37 | - process-step。process chart 2 38 | - process-card。card process chart 39 | - dev-process。process with logo 40 | - step-line。title only line chart 41 | - table-step。with arrow table chart 42 | - checklist。checklists 43 | - mermaid。use [mermaid](https://mermaid-js.github.io/mermaid/) as visual tools 44 | - toolset。use toolset components to extends 45 | - slider 46 | - line-chart 47 | - pipeline。ci pipeline 48 | - maturity。check, rating with radrar for maturity 49 | 50 | ### slide examples 51 | 52 | ```` 53 | ```toolset 54 | - 用户体验 55 | - 时间 56 | - 成本 57 | - 安全 58 | - 范围 59 | 60 | config: {"type": "slider"} 61 | ``` 62 | ```` 63 | 64 | ## Usage 65 | 66 | ### Use with Web Components 67 | 68 | 1. import styles 69 | 70 | ```html 71 | 72 | ``` 73 | 74 | 2. import code 75 | 76 | ```html 77 |
78 | 86 | ``` 87 | 88 | 3. import script 89 | 90 | ```html 91 | 92 | 93 | 94 | ``` 95 | 96 | ### Use in Angular 97 | 98 | 1.install: `yarn add @ledge-framework/render` 99 | 2.import module 100 | 101 | ``` 102 | import { LedgeRenderModule } from '@ledge-framework/render'; 103 | 104 | @NgModule({ 105 | imports: [ 106 | ... 107 | LedgeRenderModule, 108 | ] 109 | ... 110 | }) 111 | ``` 112 | 113 | 3. import styles 114 | 115 | ``` 116 | @import "~@ledge-framework/render/prebuild-theme/index.css"; 117 | ``` 118 | 119 | or import in `angular.json` 120 | 121 | 4.use it 122 | 123 | ``` 124 | 125 | ``` 126 | 127 | 128 | ## LICENSE 129 | 130 | @ 2020 [LiuuY](https://github.com/LiuuY) && [Phodal Huang](https://github.com/phodal). This code is distributed under the MPL license. See `LICENSE` in this directory. 131 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | # Security Policy 2 | 3 | ## Supported Versions 4 | 5 | Use this section to tell people about which versions of your project are 6 | currently being supported with security updates. 7 | 8 | | Version | Supported | 9 | | ------- | ------------------ | 10 | | 0.6.x | :white_check_mark: | 11 | | < 0.6.0 | :x: | 12 | 13 | ## Reporting a Vulnerability 14 | 15 | Use this section to tell people how to report a vulnerability. 16 | 17 | Tell them where to go, how often they can expect to get an update on a 18 | reported vulnerability, what to expect if the vulnerability is accepted or 19 | declined, etc. 20 | -------------------------------------------------------------------------------- /_config.yml: -------------------------------------------------------------------------------- 1 | remote_theme: ledge-framework/jekyll 2 | -------------------------------------------------------------------------------- /browserslist: -------------------------------------------------------------------------------- 1 | # This file is used by the build system to adjust CSS and JS output to support the specified browsers below. 2 | # For additional information regarding the format and rule options, please see: 3 | # https://github.com/browserslist/browserslist#queries 4 | 5 | # You can see what browsers were selected by your queries by running: 6 | # npx browserslist 7 | 8 | > 0.5% 9 | last 2 versions 10 | Firefox ESR 11 | not dead 12 | not IE 9-11 # For IE 9-11 support, remove 'not'. -------------------------------------------------------------------------------- /e2e/protractor.conf.js: -------------------------------------------------------------------------------- 1 | // @ts-check 2 | // Protractor configuration file, see link for more information 3 | // https://github.com/angular/protractor/blob/master/lib/config.ts 4 | 5 | const { SpecReporter } = require('jasmine-spec-reporter'); 6 | 7 | /** 8 | * @type { import("protractor").Config } 9 | */ 10 | exports.config = { 11 | allScriptsTimeout: 11000, 12 | specs: [ 13 | './src/**/*.e2e-spec.ts' 14 | ], 15 | capabilities: { 16 | browserName: 'chrome' 17 | }, 18 | directConnect: true, 19 | baseUrl: 'http://localhost:4200/', 20 | framework: 'jasmine', 21 | jasmineNodeOpts: { 22 | showColors: true, 23 | defaultTimeoutInterval: 30000, 24 | print: function() {} 25 | }, 26 | onPrepare() { 27 | require('ts-node').register({ 28 | project: require('path').join(__dirname, './tsconfig.json') 29 | }); 30 | jasmine.getEnv().addReporter(new SpecReporter({ spec: { displayStacktrace: true } })); 31 | } 32 | }; -------------------------------------------------------------------------------- /e2e/src/app.e2e-spec.ts: -------------------------------------------------------------------------------- 1 | import { AppPage } from './app.po'; 2 | import { browser, logging } from 'protractor'; 3 | 4 | describe('workspace-project App', () => { 5 | let page: AppPage; 6 | 7 | beforeEach(() => { 8 | page = new AppPage(); 9 | }); 10 | 11 | it('should display welcome message', () => { 12 | page.navigateTo(); 13 | expect(page.getTitleText()).toEqual('ledge app is running!'); 14 | }); 15 | 16 | afterEach(async () => { 17 | // Assert that there are no errors emitted from the browser 18 | const logs = await browser.manage().logs().get(logging.Type.BROWSER); 19 | expect(logs).not.toContain(jasmine.objectContaining({ 20 | level: logging.Level.SEVERE, 21 | } as logging.Entry)); 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /e2e/src/app.po.ts: -------------------------------------------------------------------------------- 1 | import { browser, by, element } from 'protractor'; 2 | 3 | export class AppPage { 4 | navigateTo(): Promise { 5 | return browser.get(browser.baseUrl) as Promise; 6 | } 7 | 8 | getTitleText(): Promise { 9 | return element(by.css('app-root .content span')).getText() as Promise; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /e2e/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../out-tsc/e2e", 5 | "module": "commonjs", 6 | "target": "es5", 7 | "types": [ 8 | "jasmine", 9 | "jasminewd2", 10 | "node" 11 | ] 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /karma.conf.js: -------------------------------------------------------------------------------- 1 | // Karma configuration file, see link for more information 2 | // https://karma-runner.github.io/1.0/config/configuration-file.html 3 | 4 | module.exports = function (config) { 5 | config.set({ 6 | basePath: '', 7 | frameworks: ['jasmine', '@angular-devkit/build-angular'], 8 | plugins: [ 9 | require('karma-jasmine'), 10 | require('karma-chrome-launcher'), 11 | require('karma-jasmine-html-reporter'), 12 | require('karma-coverage-istanbul-reporter'), 13 | require('@angular-devkit/build-angular/plugins/karma') 14 | ], 15 | client: { 16 | clearContext: false // leave Jasmine Spec Runner output visible in browser 17 | }, 18 | coverageIstanbulReporter: { 19 | dir: require('path').join(__dirname, './coverage/ledge'), 20 | reports: ['html', 'lcovonly', 'text-summary'], 21 | fixWebpackSourcePaths: true 22 | }, 23 | reporters: ['progress', 'kjhtml'], 24 | port: 9876, 25 | colors: true, 26 | logLevel: config.LOG_INFO, 27 | autoWatch: true, 28 | browsers: ['Chrome'], 29 | customLaunchers: { 30 | ChromeHeadlessCI: { 31 | base: 'ChromeHeadless', 32 | flags: ['--no-sandbox', '--disable-gpu'] 33 | } 34 | }, 35 | singleRun: false, 36 | restartOnFileChange: true 37 | }); 38 | }; 39 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ledge", 3 | "version": "0.0.0", 4 | "scripts": { 5 | "ng": "ng", 6 | "start": "ng serve", 7 | "build": "ng build", 8 | "test": "ng test", 9 | "lint": "ng lint", 10 | "e2e": "ng e2e", 11 | "build:ci": "ng build --prod", 12 | "test:ci": "ng test --watch=false --progress=false --browsers=ChromeHeadlessCI --codeCoverage", 13 | "build:render": "yarn bundle-styles:render; ng build @ledge-framework/render --prod", 14 | "build:view": "ng build @ledge-framework/view --prod", 15 | "publish:render": "cd @ledge-framework/render && npm publish --access=public", 16 | "publish:view": "cd @ledge-framework/view && npm publish --access=public", 17 | "dev:render": "npm-run-all --parallel watch:render watch-styles:render", 18 | "watch:render": "ng build @ledge-framework/render --watch", 19 | "dev:view": "ng build @ledge-framework/view --watch", 20 | "bundle-styles:render": "gulp --gulpfile ./projects/@ledge-framework/render/gulpfile.js", 21 | "watch-styles:render": "gulp --gulpfile ./projects/@ledge-framework/render/gulpfile.js sass:watch", 22 | "deploy": "ng build --prod --output-hashing none && ng deploy --cname=theme.ledge.ink --no-build --repo https://github.com/ledge-framework/jekyll-dist" 23 | }, 24 | "private": true, 25 | "browser": { 26 | "crypto": false 27 | }, 28 | "dependencies": { 29 | "@angular/animations": "~9.0.3", 30 | "@angular/cdk": "^9.1.1", 31 | "@angular/common": "~9.0.3", 32 | "@angular/compiler": "~9.0.3", 33 | "@angular/core": "~9.0.3", 34 | "@angular/elements": "9.0.7", 35 | "@angular/forms": "~9.0.3", 36 | "@angular/material": "^9.1.1", 37 | "@angular/platform-browser": "~9.0.3", 38 | "@angular/platform-browser-dynamic": "~9.0.3", 39 | "@angular/router": "~9.0.3", 40 | "@ledge-framework/render": "1.0.0", 41 | "@ledge-framework/view": "latest", 42 | "angular-split": "^3.0.3", 43 | "brace": "^0.11.1", 44 | "d3": "^5.15.0", 45 | "d3-graphviz": "^3.0.4", 46 | "dagre-d3": "^0.6.4", 47 | "date-fns": "^2.12.0", 48 | "document-register-element": "^1.7.2", 49 | "echarts": "^4.6.0", 50 | "graphlib-dot": "^0.6.4", 51 | "marked": "^0.8.0", 52 | "material-design-icons": "^3.0.1", 53 | "mermaid": "^8.13.8", 54 | "ngx-ace-tern": "^1.2.2", 55 | "ngx-markdown": "^9.0.0", 56 | "ngx-virtual-scroller": "^4.0.3", 57 | "rxjs": "~6.5.4", 58 | "tslib": "^1.10.0", 59 | "zone.js": "~0.10.2" 60 | }, 61 | "devDependencies": { 62 | "@angular-devkit/build-angular": "~0.900.4", 63 | "@angular-devkit/build-ng-packagr": "~0.900.5", 64 | "@angular/cli": "~9.0.4", 65 | "@angular/compiler-cli": "~9.0.3", 66 | "@angular/language-service": "~9.0.3", 67 | "@types/jasmine": "~3.5.0", 68 | "@types/jasminewd2": "~2.0.3", 69 | "@types/node": "^12.11.1", 70 | "angular-cli-ghpages": "^0.6.2", 71 | "codelyzer": "^5.1.2", 72 | "fibers": "^5.0.0", 73 | "gulp": "^4.0.2", 74 | "gulp-sass": "^4.1.0", 75 | "jasmine-core": "~3.5.0", 76 | "jasmine-spec-reporter": "~4.2.1", 77 | "karma": "~4.3.0", 78 | "karma-chrome-launcher": "~3.1.0", 79 | "karma-coverage-istanbul-reporter": "~2.1.0", 80 | "karma-jasmine": "~2.0.1", 81 | "karma-jasmine-html-reporter": "^1.4.2", 82 | "ng-packagr": "^9.0.0", 83 | "npm-run-all": "^4.1.5", 84 | "protractor": "~5.4.3", 85 | "sass": "^1.26.5", 86 | "tslint": "~5.18.0", 87 | "typescript": "~3.7.5", 88 | "cz-conventional-changelog": "3.1.0", 89 | "husky": "^4.2.3", 90 | "lint-staged": ">=10", 91 | "prettier": "^2.0.2", 92 | "stylelint": "^13.3.0", 93 | "stylelint-config-standard": "^20.0.0", 94 | "stylelint-scss": "^3.16.0" 95 | }, 96 | "husky": { 97 | "hooks": { 98 | "pre-commit": "lint-staged", 99 | "pre-push": "yarn run test:ci" 100 | } 101 | }, 102 | "lint-staged": { 103 | "src/app/**/*.{css,scss}": [ 104 | "stylelint --syntax=scss", 105 | "prettier --parser --write" 106 | ], 107 | "{src,test}/**/*.ts": [ 108 | "prettier --write --single-quote" 109 | ], 110 | "*.{js,css,md}": "prettier --write" 111 | }, 112 | "config": { 113 | "commitizen": { 114 | "path": "./node_modules/cz-conventional-changelog" 115 | } 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /projects/@ledge-framework/render/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | -------------------------------------------------------------------------------- /projects/@ledge-framework/render/README.md: -------------------------------------------------------------------------------- 1 | # Ledge Framework Engine 2 | 3 | > Legde framework is a documentation as code practises framework. 4 | 5 | demo page: [https://devops.phodal.com/helper](https://devops.phodal.com/helper) 6 | 7 | online editor: [https://devops.phodal.com/helper](https://devops.phodal.com/helper) 8 | 9 | ![CI](https://github.com/ledge-framework/engine/workflows/CI/badge.svg) 10 | 11 | ## Syntax 12 | 13 | ### Ledge extend code syntax 14 | 15 | ```` 16 | ```process-step 17 | - step1 18 | - demo 19 | - kanban 20 | ``` 21 | ```` 22 | 23 | - Chart 24 | - echarts. Echarts chart. 25 | - chart. Echarts bar chart. 26 | - mindmap. Markdown List to mindmap. 27 | - radar. Markdown List to radar chart. 28 | - tech radar. Markdown list to tech radar chart. 29 | - pie。Pie chart 30 | - quadrant。quadrant chart 31 | - pyramid。pyramid chart 32 | - graphviz。dot to graph 33 | - process visualization 34 | - process-table。process chart 35 | - process-step。process chart 2 36 | - process-card。card process chart 37 | - dev-process。process with logo 38 | - step-line。title only line chart 39 | - table-step。with arrow table chart 40 | - checklist。checklists 41 | - mermaid。use [mermaid](https://mermaid-js.github.io/mermaid/) as visual tools 42 | - toolset。use toolset components to extends 43 | - slider 44 | - line-chart 45 | - pipeline。ci pipeline 46 | - maturity。check, rating with radrar for maturity 47 | 48 | ### slide examples 49 | 50 | ```` 51 | ```toolset 52 | - 用户体验 53 | - 时间 54 | - 成本 55 | - 安全 56 | - 范围 57 | 58 | config: {"type": "slider"} 59 | ``` 60 | ```` 61 | 62 | ## Usage 63 | 64 | ### Use with Web Components 65 | 66 | 1. import styles 67 | 68 | ```html 69 | 70 | ``` 71 | 72 | 2. import code 73 | 74 | ```html 75 |
76 | 84 | ``` 85 | 86 | 3. import script 87 | 88 | ```html 89 | 90 | 91 | 92 | ``` 93 | 94 | ### Use in Angular 95 | 96 | 1.install: `yarn add @ledge-framework/render` 97 | 2.import module 98 | 99 | ``` 100 | import { LedgeRenderModule } from '@ledge-framework/render'; 101 | 102 | @NgModule({ 103 | imports: [ 104 | ... 105 | LedgeRenderModule, 106 | ] 107 | ... 108 | }) 109 | ``` 110 | 111 | 3. import styles 112 | 113 | ``` 114 | @import "~@ledge-framework/render/prebuild-theme/index.css"; 115 | ``` 116 | 117 | or import in `angular.json` 118 | 119 | 4.use it 120 | 121 | ``` 122 | 123 | ``` 124 | 125 | ## LICENSE 126 | 127 | @ 2020 [LiuuY](https://github.com/LiuuY) && [Phodal Huang](https://github.com/phodal). This code is distributed under the MPL license. See `LICENSE` in this directory. 128 | -------------------------------------------------------------------------------- /projects/@ledge-framework/render/gulpfile.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var Fiber = require('fibers'); 4 | var gulp = require('gulp'); 5 | var sass = require('gulp-sass'); 6 | 7 | sass.compiler = require('sass'); 8 | 9 | gulp.task('sass', function () { 10 | return gulp.src('./src/lib/theme/index.scss') 11 | .pipe(sass({fiber: Fiber}).on('error', sass.logError)) 12 | .pipe(gulp.dest('./prebuild-theme')); 13 | }); 14 | 15 | gulp.task('sass:watch', () => { 16 | gulp.watch('./src/lib/theme/index.scss', (done) => { 17 | gulp.series(['sass'])(done); 18 | }); 19 | }); 20 | 21 | 22 | gulp.task('default', gulp.series(['sass'])); 23 | -------------------------------------------------------------------------------- /projects/@ledge-framework/render/karma.conf.js: -------------------------------------------------------------------------------- 1 | // Karma configuration file, see link for more information 2 | // https://karma-runner.github.io/1.0/config/configuration-file.html 3 | 4 | module.exports = function (config) { 5 | config.set({ 6 | basePath: '', 7 | frameworks: ['jasmine', '@angular-devkit/build-angular'], 8 | plugins: [ 9 | require('karma-jasmine'), 10 | require('karma-chrome-launcher'), 11 | require('karma-jasmine-html-reporter'), 12 | require('karma-coverage-istanbul-reporter'), 13 | require('@angular-devkit/build-angular/plugins/karma'), 14 | ], 15 | client: { 16 | clearContext: false, // leave Jasmine Spec Runner output visible in browser 17 | }, 18 | coverageIstanbulReporter: { 19 | dir: require('path').join(__dirname, '../../coverage/ledge-render'), 20 | reports: ['html', 'lcovonly', 'text-summary'], 21 | fixWebpackSourcePaths: true, 22 | }, 23 | reporters: ['progress', 'kjhtml'], 24 | port: 9876, 25 | colors: true, 26 | logLevel: config.LOG_INFO, 27 | autoWatch: true, 28 | browsers: ['Chrome'], 29 | singleRun: false, 30 | customLaunchers: { 31 | ChromeHeadlessCI: { 32 | base: 'ChromeHeadless', 33 | flags: ['--no-sandbox', '--disable-gpu'], 34 | }, 35 | }, 36 | restartOnFileChange: true, 37 | }); 38 | }; 39 | -------------------------------------------------------------------------------- /projects/@ledge-framework/render/ng-package.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "../../../node_modules/ng-packagr/ng-package.schema.json", 3 | "dest": "../../../dist/@ledge-framework/render", 4 | "assets": [ 5 | "prebuild-theme" 6 | ], 7 | "lib": { 8 | "entryFile": "src/public-api.ts" 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /projects/@ledge-framework/render/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@ledge-framework/render", 3 | "version": "1.0.2", 4 | "description": "Ledge Framework render, a powerful markdown render.", 5 | "license": "MPL-2.0", 6 | "repository": "https://github.com/phodal/ledge", 7 | "scirpts": { 8 | "build": "ng build --prod" 9 | }, 10 | "contributors": [ 11 | { 12 | "name": "LiuuY", 13 | "email": "mail4c59@gmail.com", 14 | "url": "https://github.com/LiuuY" 15 | }, 16 | { 17 | "name": "Phodal HUANG", 18 | "url": "https://github.com/phodal/" 19 | }, 20 | { 21 | "name": "giscafer", 22 | "url": "https://github.com/giscafer" 23 | }, 24 | { 25 | "name": "klxq", 26 | "url": "https://github.com/klxq" 27 | } 28 | ], 29 | "private": false, 30 | "peerDependencies": { 31 | "@angular/cdk": "^9.1.1", 32 | "@angular/common": "^9.0.5", 33 | "@angular/core": "^9.0.5", 34 | "@angular/forms": "^9.0.5", 35 | "@angular/material": "^9.1.1", 36 | "tslib": "^1.10.0", 37 | "d3": "^5.15.0", 38 | "d3-graphviz": "^3.0.4", 39 | "dagre-d3": "^0.6.4", 40 | "echarts": "^4.7.0", 41 | "graphlib-dot": "^0.6.4", 42 | "marked": "^0.8.2", 43 | "shortid": "^2.2.15" 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /projects/@ledge-framework/render/src/lib/chart/ledge-bar-chart/ledge-bar-chart.component.html: -------------------------------------------------------------------------------- 1 |
2 | 3 |
4 | -------------------------------------------------------------------------------- /projects/@ledge-framework/render/src/lib/chart/ledge-bar-chart/ledge-bar-chart.component.scss: -------------------------------------------------------------------------------- 1 | .chart { 2 | width: auto; 3 | height: auto; 4 | min-width: 500px; 5 | min-height: 500px; 6 | max-width: 800px; 7 | } 8 | -------------------------------------------------------------------------------- /projects/@ledge-framework/render/src/lib/chart/ledge-bar-chart/ledge-bar-chart.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { LedgeBarChartComponent } from './ledge-bar-chart.component'; 4 | 5 | describe('LedgeHeatmapComponent', () => { 6 | let component: LedgeBarChartComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [LedgeBarChartComponent] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(LedgeBarChartComponent); 18 | component = fixture.componentInstance; 19 | component.data = { 20 | header: ['h1', 'h1'], 21 | cells: [ 22 | ['a', 'b'], 23 | ['a', 'b'] 24 | ] 25 | }; 26 | fixture.detectChanges(); 27 | }); 28 | 29 | it('should create', () => { 30 | expect(component).toBeTruthy(); 31 | }); 32 | }); 33 | -------------------------------------------------------------------------------- /projects/@ledge-framework/render/src/lib/chart/ledge-bar-chart/ledge-bar-chart.component.ts: -------------------------------------------------------------------------------- 1 | import { 2 | AfterViewInit, 3 | Component, 4 | ElementRef, 5 | Input, 6 | OnInit, 7 | ViewChild 8 | } from '@angular/core'; 9 | import * as d3 from 'd3'; 10 | import * as echarts from 'echarts'; 11 | import { 12 | ChartData, 13 | LedgeChartModel, LedgeTable 14 | } from '../../components/model/ledge-chart.model'; 15 | 16 | @Component({ 17 | selector: 'ledge-bar-chart', 18 | templateUrl: './ledge-bar-chart.component.html', 19 | styleUrls: ['./ledge-bar-chart.component.scss'], 20 | }) 21 | export class LedgeBarChartComponent implements OnInit, AfterViewInit { 22 | @Input() data: LedgeTable; 23 | 24 | @ViewChild('chart', {}) reporter: ElementRef; 25 | 26 | constructor() {} 27 | 28 | ngOnInit(): void {} 29 | 30 | ngAfterViewInit(): void { 31 | const myChart = echarts.init(this.reporter.nativeElement); 32 | const builderJson = this.buildBarChartData(this.data); 33 | myChart.setOption(this.buildBarChartOption(builderJson) as any); 34 | } 35 | 36 | private getColorByIndex(i: number) { 37 | const colors = d3 38 | .scaleLinear() 39 | .domain([0, 8]) 40 | .range([d3.rgb('#7753df'), d3.rgb('#66C2A5')] as any); 41 | 42 | return colors(i); 43 | } 44 | 45 | private buildBarChartData(token: LedgeTable): LedgeChartModel { 46 | const chart: LedgeChartModel = { 47 | title: token.header[0], 48 | barChart: { 49 | xAxis: [], 50 | yAxis: [], 51 | }, 52 | }; 53 | 54 | chart.barChart.xAxis = token.cells[0]; 55 | 56 | this.buildYAxis(token, chart); 57 | return chart; 58 | } 59 | 60 | private buildYAxis(token: LedgeTable, chart: LedgeChartModel) { 61 | const tableColumnLength = token.cells.length; 62 | for (let i = 1; i < tableColumnLength; i++) { 63 | const row = []; 64 | const originRow = token.cells[i]; 65 | 66 | for (let j = 0; j < originRow.length; j++) { 67 | let color = this.getColorByIndex(i); 68 | if (tableColumnLength === 2) { 69 | color = this.getColorByIndex(j); 70 | } 71 | row.push({ 72 | value: originRow[j], 73 | itemStyle: { color }, 74 | }); 75 | } 76 | 77 | chart.barChart.yAxis.push(row); 78 | } 79 | } 80 | 81 | private buildBarChartOption(sortData: LedgeChartModel) { 82 | return { 83 | tooltip: {}, 84 | title: [ 85 | { 86 | text: sortData.title, 87 | left: '25%', 88 | textAlign: 'center', 89 | }, 90 | ], 91 | grid: [ 92 | { 93 | left: 10, 94 | containLabel: true, 95 | }, 96 | ], 97 | xAxis: [ 98 | { 99 | show: false, 100 | }, 101 | ], 102 | yAxis: [ 103 | { 104 | type: 'category', 105 | data: sortData.barChart.xAxis, 106 | }, 107 | ], 108 | series: this.buildSeries(sortData.barChart.yAxis), 109 | }; 110 | } 111 | 112 | private buildSeries(sortData: ChartData[][]) { 113 | const barSeries = []; 114 | 115 | for (const y of sortData) { 116 | if (typeof y[0].value === 'string') { 117 | y.map((item) => { 118 | item.value = parseFloat(item.value as string); 119 | }); 120 | } 121 | 122 | barSeries.push({ 123 | type: 'bar', 124 | data: y, 125 | label: { 126 | normal: { 127 | show: true, 128 | position: 'right', 129 | formatter: (data) => data.value + '%', 130 | }, 131 | }, 132 | }); 133 | } 134 | 135 | return barSeries; 136 | } 137 | } 138 | -------------------------------------------------------------------------------- /projects/@ledge-framework/render/src/lib/chart/ledge-fish-bone/ledge-fish-bone.component.html: -------------------------------------------------------------------------------- 1 |
2 | 3 |
4 | -------------------------------------------------------------------------------- /projects/@ledge-framework/render/src/lib/chart/ledge-fish-bone/ledge-fish-bone.component.scss: -------------------------------------------------------------------------------- 1 | .ledge-fish-bone { 2 | width: auto; 3 | height: auto; 4 | min-width: 500px; 5 | min-height: 500px; 6 | max-width: 800px; 7 | } 8 | -------------------------------------------------------------------------------- /projects/@ledge-framework/render/src/lib/chart/ledge-fish-bone/ledge-fish-bone.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { LedgeFishBoneComponent } from './ledge-fish-bone.component'; 4 | 5 | describe('LedgeFishboneComponent', () => { 6 | let component: LedgeFishBoneComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ LedgeFishBoneComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(LedgeFishBoneComponent); 18 | component = fixture.componentInstance; 19 | component.data = [{ 20 | children: [ 21 | { 22 | children: [ 23 | { 24 | children: [], 25 | name: '', 26 | }, 27 | ], 28 | name: '', 29 | }, 30 | ], 31 | }]; 32 | fixture.detectChanges(); 33 | }); 34 | 35 | it('should create', () => { 36 | expect(component).toBeTruthy(); 37 | }); 38 | }); 39 | -------------------------------------------------------------------------------- /projects/@ledge-framework/render/src/lib/chart/ledge-fish-bone/ledge-fish-bone.component.ts: -------------------------------------------------------------------------------- 1 | import { AfterViewInit, Component, ElementRef, Input, OnInit, ViewChild } from '@angular/core'; 2 | import { LedgeListItem } from '../../components/model/ledge-chart.model'; 3 | import fishbone from './fishbone'; 4 | import * as d3 from 'd3'; 5 | 6 | @Component({ 7 | selector: 'ledge-fish-bone', 8 | templateUrl: './ledge-fish-bone.component.html', 9 | styleUrls: ['./ledge-fish-bone.component.scss'] 10 | }) 11 | export class LedgeFishBoneComponent implements OnInit, AfterViewInit { 12 | @Input() 13 | data: LedgeListItem[]; 14 | 15 | @Input() 16 | config: any; 17 | 18 | @ViewChild('chart', {}) chart: ElementRef; 19 | 20 | constructor() { 21 | } 22 | 23 | ngOnInit(): void { 24 | 25 | } 26 | 27 | ngAfterViewInit(): void { 28 | const data = this.data[0]; 29 | const fb = fishbone(); 30 | let width = 1200; 31 | let height = 800; 32 | 33 | if (this.config) { 34 | if (this.config.width) { 35 | width = this.config.width; 36 | } 37 | if (this.config.height) { 38 | height = this.config.height; 39 | } 40 | } 41 | 42 | fb.setWidthHeight(width, height); 43 | d3.select(this.chart.nativeElement) 44 | .append('svg') 45 | .attr('width', width) 46 | .attr('height', height) 47 | .datum(data) 48 | .call(fb.defaultArrow) 49 | .call(fb); 50 | 51 | fb.force().restart(); 52 | } 53 | 54 | } 55 | -------------------------------------------------------------------------------- /projects/@ledge-framework/render/src/lib/chart/ledge-graphviz/ledge-graphviz.component.html: -------------------------------------------------------------------------------- 1 |
2 | 3 | 4 | 5 |
6 | -------------------------------------------------------------------------------- /projects/@ledge-framework/render/src/lib/chart/ledge-graphviz/ledge-graphviz.component.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ledge-framework/engine/66b893282ed856ee6db29130e1144eb4e4d415fc/projects/@ledge-framework/render/src/lib/chart/ledge-graphviz/ledge-graphviz.component.scss -------------------------------------------------------------------------------- /projects/@ledge-framework/render/src/lib/chart/ledge-graphviz/ledge-graphviz.component.ts: -------------------------------------------------------------------------------- 1 | import { AfterViewInit, Component, ElementRef, Input, OnInit, ViewChild } from '@angular/core'; 2 | import * as d3 from 'd3'; 3 | import * as dagreD3 from 'dagre-d3'; 4 | import * as graphlibDot from 'graphlib-dot'; 5 | 6 | @Component({ 7 | selector: 'ledge-graphviz', 8 | templateUrl: './ledge-graphviz.component.html', 9 | styleUrls: ['./ledge-graphviz.component.scss'], 10 | }) 11 | export class LedgeGraphvizComponent implements AfterViewInit { 12 | @Input() 13 | data: string; 14 | 15 | @ViewChild('chart', {}) reporter: ElementRef; 16 | 17 | ngAfterViewInit(): void { 18 | setTimeout(() => { 19 | const rootSvg = d3.select(this.reporter.nativeElement).select('svg'); 20 | const inner = d3.select(this.reporter.nativeElement).select('svg g'); 21 | const zoom = d3.zoom().on('zoom', () => { 22 | inner.attr('transform', d3.event.transform); 23 | }); 24 | 25 | rootSvg.call(zoom); 26 | 27 | const render = dagreD3.render(); 28 | const g = graphlibDot.read(this.data); 29 | d3.select(this.reporter.nativeElement).select('svg g').call(render, g); 30 | }); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /projects/@ledge-framework/render/src/lib/chart/ledge-heatmap/ledge-heatmap.component.html: -------------------------------------------------------------------------------- 1 |
2 | 3 |
4 | -------------------------------------------------------------------------------- /projects/@ledge-framework/render/src/lib/chart/ledge-heatmap/ledge-heatmap.component.scss: -------------------------------------------------------------------------------- 1 | .chart { 2 | width: auto; 3 | height: auto; 4 | min-width: 600px; 5 | min-height: 800px; 6 | max-width: 1600px; 7 | } 8 | -------------------------------------------------------------------------------- /projects/@ledge-framework/render/src/lib/chart/ledge-heatmap/ledge-heatmap.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { LedgeHeatmapComponent } from './ledge-heatmap.component'; 4 | 5 | describe('LedgeHeatmapComponent', () => { 6 | let component: LedgeHeatmapComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [LedgeHeatmapComponent] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(LedgeHeatmapComponent); 18 | component = fixture.componentInstance; 19 | component.data = { 20 | header: ['h1', 'h1'], 21 | cells: [ 22 | ['a', 'b'], 23 | ['a', 'b'] 24 | ] 25 | }; 26 | fixture.detectChanges(); 27 | }); 28 | 29 | it('should create', () => { 30 | expect(component).toBeTruthy(); 31 | }); 32 | }); 33 | -------------------------------------------------------------------------------- /projects/@ledge-framework/render/src/lib/chart/ledge-heatmap/ledge-heatmap.component.ts: -------------------------------------------------------------------------------- 1 | import { AfterViewInit, Component, ElementRef, Input, OnInit, ViewChild } from '@angular/core'; 2 | import echarts from 'echarts'; 3 | 4 | import { LedgeTable } from '../../components/model/ledge-chart.model'; 5 | 6 | @Component({ 7 | selector: 'ledge-heatmap', 8 | templateUrl: './ledge-heatmap.component.html', 9 | styleUrls: ['./ledge-heatmap.component.scss'] 10 | }) 11 | export class LedgeHeatmapComponent implements OnInit, AfterViewInit { 12 | @Input() data: LedgeTable; 13 | 14 | @Input() config: any; 15 | 16 | @ViewChild('chart', {}) chartEl: ElementRef; 17 | 18 | constructor() { 19 | } 20 | 21 | ngOnInit(): void { 22 | } 23 | 24 | ngAfterViewInit(): void { 25 | const myChart = echarts.init(this.chartEl.nativeElement); 26 | const option = this.buildOption(this.data); 27 | myChart.setOption(option as any); 28 | } 29 | 30 | private buildOption(treeData: LedgeTable) { 31 | const seriesData = this.buildSeriesData(JSON.parse(JSON.stringify(treeData))); 32 | return { 33 | title: { 34 | top: 30, 35 | left: 'center', 36 | name: treeData.header[0] 37 | }, 38 | visualMap: { 39 | min: 0, 40 | max: 100, 41 | calculable: true, 42 | orient: 'vertical', 43 | left: '90%', 44 | top: '35%', 45 | inRange: { 46 | color: ['white', 'rgb(166, 202, 102)'] 47 | } 48 | }, 49 | grid: { 50 | top: '10%', 51 | left: '20%' 52 | }, 53 | xAxis: { 54 | type: 'category', 55 | position: 'top', 56 | data: treeData.header.slice(1), 57 | axisLabel: { 58 | fontSize: 14 59 | }, 60 | splitArea: { 61 | show: false 62 | } 63 | }, 64 | yAxis: { 65 | type: 'category', 66 | axisLabel: { 67 | fontSize: 14 68 | }, 69 | data: treeData.cells[0].reverse(), 70 | splitArea: { 71 | show: true 72 | } 73 | }, 74 | series: [{ 75 | type: 'heatmap', 76 | data: seriesData, 77 | label: { 78 | show: true, 79 | color: '#000', 80 | formatter: (data) => data.value[2] + '%', 81 | }, 82 | emphasis: { 83 | itemStyle: { 84 | shadowBlur: 5, 85 | shadowColor: 'white' 86 | }, 87 | } 88 | }] 89 | }; 90 | } 91 | 92 | private buildSeriesData(data: LedgeTable) { 93 | const seriesData: any[][] = []; 94 | data.cells.shift(); 95 | const columnLength = data.cells[0].length; 96 | // tslint:disable-next-line:prefer-for-of 97 | for (let i = 0; i < data.cells.length; i++) { 98 | // tslint:disable-next-line:prefer-for-of 99 | for (let j = 0; j < (data.cells)[i].length; j++) { 100 | let value = (data.cells)[i][j]; 101 | if (typeof value === 'string') { 102 | if (value.endsWith('%')) { 103 | value = parseInt(value.slice(0, -1), 10); 104 | } 105 | } 106 | seriesData.push([i, columnLength - j - 1, value]); 107 | } 108 | } 109 | 110 | return seriesData.reverse(); 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /projects/@ledge-framework/render/src/lib/chart/ledge-mindmap/ledge-mindmap.component.html: -------------------------------------------------------------------------------- 1 |
2 | 3 |
4 | -------------------------------------------------------------------------------- /projects/@ledge-framework/render/src/lib/chart/ledge-mindmap/ledge-mindmap.component.scss: -------------------------------------------------------------------------------- 1 | .chart { 2 | width: auto; 3 | height: auto; 4 | min-width: 600px; 5 | min-height: 800px; 6 | max-width: 1600px; 7 | } 8 | -------------------------------------------------------------------------------- /projects/@ledge-framework/render/src/lib/chart/ledge-mindmap/ledge-mindmap.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | import { LedgeMindmapComponent } from './ledge-mindmap.component'; 3 | 4 | describe('LedgeMindmapComponent', () => { 5 | let component: LedgeMindmapComponent; 6 | let fixture: ComponentFixture; 7 | 8 | beforeEach(async(() => { 9 | TestBed.configureTestingModule({ 10 | declarations: [LedgeMindmapComponent], 11 | }).compileComponents(); 12 | })); 13 | 14 | beforeEach(() => { 15 | fixture = TestBed.createComponent(LedgeMindmapComponent); 16 | component = fixture.componentInstance; 17 | component.data = [ 18 | { 19 | children: [ 20 | { 21 | children: [], 22 | name: '', 23 | }, 24 | ], 25 | name: '', 26 | }, 27 | ]; 28 | fixture.detectChanges(); 29 | }); 30 | 31 | it('should create', () => { 32 | expect(component).toBeTruthy(); 33 | }); 34 | }); 35 | -------------------------------------------------------------------------------- /projects/@ledge-framework/render/src/lib/chart/ledge-mindmap/ledge-mindmap.component.ts: -------------------------------------------------------------------------------- 1 | import { 2 | AfterViewInit, 3 | Component, 4 | ElementRef, 5 | Input, 6 | OnInit, 7 | ViewChild 8 | } from '@angular/core'; 9 | import * as echarts from 'echarts'; 10 | import LedgeChartConverter from '../../components/model/ledge-chart-converter'; 11 | import { LedgeListItem } from '../../components/model/ledge-chart.model'; 12 | 13 | @Component({ 14 | selector: 'ledge-mindmap', 15 | templateUrl: './ledge-mindmap.component.html', 16 | styleUrls: ['./ledge-mindmap.component.scss'], 17 | }) 18 | export class LedgeMindmapComponent implements OnInit, AfterViewInit { 19 | @Input() 20 | data: LedgeListItem[]; 21 | 22 | chartData: any; 23 | dataLevel = 1; 24 | dataSize = 1; 25 | chartOption: any; 26 | 27 | @ViewChild('chart', {}) chart: ElementRef; 28 | 29 | constructor() { 30 | } 31 | 32 | ngOnInit(): void { 33 | this.chartData = LedgeChartConverter.toTreeData(this.data); 34 | 35 | const dataStr = JSON.stringify(this.chartData); 36 | const childLength = (dataStr.match(/:/g) || []).length; 37 | this.dataSize = childLength; 38 | this.getDataLevel(this.chartData); 39 | 40 | this.chartOption = this.buildMindmapOption(this.chartData); 41 | } 42 | 43 | ngAfterViewInit(): void { 44 | const myChart = echarts.init(this.chart.nativeElement); 45 | myChart.setOption(this.chartOption as any); 46 | } 47 | 48 | getDataLevel(data) { 49 | this.dataLevel++; 50 | if (data.children) { 51 | this.getDataLevel(data.children); 52 | } 53 | } 54 | 55 | getHeight() { 56 | const height = this.dataSize * 25; 57 | let width = (this.dataLevel + 1) * 320; 58 | if (width < 800) { 59 | width = 800; 60 | } 61 | 62 | return { 63 | height: height + 'px', 64 | width: width + 'px' 65 | }; 66 | } 67 | 68 | buildMindmapOption(data) { 69 | return { 70 | toolbox: { 71 | feature: { 72 | saveAsImage: {}, 73 | }, 74 | }, 75 | tooltip: { 76 | trigger: 'item', 77 | triggerOn: 'mousemove', 78 | }, 79 | series: [ 80 | { 81 | type: 'tree', 82 | roam: 'move', 83 | id: 0, 84 | name: 'tree1', 85 | data: [data], 86 | top: '12%', 87 | left: '20%', 88 | bottom: '12%', 89 | right: '40%', 90 | symbolSize: 12, 91 | edgeShape: 'polyline', 92 | edgeForkPosition: '63%', 93 | initialTreeDepth: 3, 94 | lineStyle: { 95 | width: 2, 96 | }, 97 | label: { 98 | position: 'left', 99 | verticalAlign: 'middle', 100 | align: 'right', 101 | fontSize: 14, 102 | }, 103 | leaves: { 104 | label: { 105 | position: 'right', 106 | verticalAlign: 'middle', 107 | align: 'left', 108 | }, 109 | }, 110 | expandAndCollapse: false, 111 | animationDuration: 550, 112 | animationDurationUpdate: 750, 113 | }, 114 | ], 115 | }; 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /projects/@ledge-framework/render/src/lib/chart/ledge-pie/ledge-pie.component.html: -------------------------------------------------------------------------------- 1 |
2 | 3 |
4 | -------------------------------------------------------------------------------- /projects/@ledge-framework/render/src/lib/chart/ledge-pie/ledge-pie.component.scss: -------------------------------------------------------------------------------- 1 | .chart { 2 | width: auto; 3 | height: auto; 4 | min-width: 500px; 5 | min-height: 500px; 6 | } 7 | -------------------------------------------------------------------------------- /projects/@ledge-framework/render/src/lib/chart/ledge-pie/ledge-pie.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { LedgePieComponent } from './ledge-pie.component'; 4 | 5 | describe('LedgePieComponent', () => { 6 | let component: LedgePieComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ LedgePieComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(LedgePieComponent); 18 | component = fixture.componentInstance; 19 | component.data = [{ 20 | name: '', 21 | children: [] 22 | }]; 23 | fixture.detectChanges(); 24 | }); 25 | 26 | it('should create', () => { 27 | expect(component).toBeTruthy(); 28 | }); 29 | }); 30 | -------------------------------------------------------------------------------- /projects/@ledge-framework/render/src/lib/chart/ledge-pie/ledge-pie.component.ts: -------------------------------------------------------------------------------- 1 | import { AfterViewInit, Component, ElementRef, Input, ViewChild } from '@angular/core'; 2 | import * as echarts from 'echarts'; 3 | import { LedgeListItem } from '../../components/model/ledge-chart.model'; 4 | 5 | @Component({ 6 | selector: 'ledge-pie', 7 | templateUrl: './ledge-pie.component.html', 8 | styleUrls: ['./ledge-pie.component.scss'] 9 | }) 10 | export class LedgePieComponent implements AfterViewInit { 11 | @Input() 12 | data: LedgeListItem[]; 13 | 14 | @Input() 15 | config: any; 16 | 17 | @ViewChild('chart', {}) chart: ElementRef; 18 | 19 | ngAfterViewInit(): void { 20 | const myChart = echarts.init(this.chart.nativeElement); 21 | const option = this.buildOption(this.data[0]); 22 | myChart.setOption(option as any); 23 | } 24 | 25 | private buildOption(data: any) { 26 | const ledgeData = []; 27 | const seriesData = []; 28 | 29 | if (data.children) { 30 | for (const child of (data.children as any[])) { 31 | const nameValueSplit = child.name.split(': '); 32 | ledgeData.push(nameValueSplit[0]); 33 | seriesData.push({ 34 | value: nameValueSplit[1], 35 | name: nameValueSplit[0] 36 | }); 37 | } 38 | } else { 39 | return {}; 40 | } 41 | 42 | return { 43 | title: { 44 | text: data.name, 45 | left: 'center' 46 | }, 47 | tooltip: { 48 | trigger: 'item', 49 | formatter: '{a}
{b} : {c} ({d}%)' 50 | }, 51 | legend: { 52 | orient: 'vertical', 53 | left: 'right', 54 | data: ledgeData 55 | }, 56 | series: [ 57 | { 58 | name: data.name, 59 | type: 'pie', 60 | radius: '60%', 61 | data: seriesData, 62 | animation: false, 63 | label: { 64 | normal: { 65 | show: true, 66 | position: 'inner', 67 | formatter: '{d}%' 68 | } 69 | } 70 | } 71 | ] 72 | }; 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /projects/@ledge-framework/render/src/lib/chart/ledge-pipeline/ledge-pipeline.component.html: -------------------------------------------------------------------------------- 1 |
2 | 3 |
-------------------------------------------------------------------------------- /projects/@ledge-framework/render/src/lib/chart/ledge-pipeline/ledge-pipeline.component.scss: -------------------------------------------------------------------------------- 1 | .pipeline { 2 | margin: 20px auto; 3 | 4 | * { 5 | box-sizing: border-box; 6 | } 7 | } -------------------------------------------------------------------------------- /projects/@ledge-framework/render/src/lib/chart/ledge-pipeline/ledge-pipeline.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { LedgePipelineComponent } from './ledge-pipeline.component'; 4 | 5 | describe('LedgePieComponent', () => { 6 | let component: LedgePipelineComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [LedgePipelineComponent] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(LedgePipelineComponent); 18 | component = fixture.componentInstance; 19 | component.data = [ 20 | { 21 | name: 'Initialize', 22 | children: [ 23 | { name: 'Initialize:success' } 24 | ] 25 | }, 26 | { 27 | name: 'Build', children: [ 28 | { name: 'Pull code:success' }, 29 | { name: 'Test:error' }, 30 | { name: 'Build:current' } 31 | ] 32 | }, 33 | { 34 | name: 'Deploy', children: [ 35 | { name: 'QA:pending' }, 36 | { name: 'UAT:processing' }, 37 | { name: 'STAGING:processing' }, 38 | { name: 'PROD:untouched' } 39 | ] 40 | }, 41 | { 42 | name: 'Finish', children: [ 43 | { name: 'Finish:untouched' } 44 | ] 45 | } 46 | ]; 47 | component.config = { 48 | connectionStrokeWidth: 4, 49 | stateStrokeWidth: 4, 50 | stateRadius: 16, 51 | stageSpace: 60, 52 | stageLabelHeight: 30, 53 | stageLabelSize: '16px', 54 | jobHeight: 60, 55 | jobLabelSize: '12px', 56 | startNodeRadius: 12, 57 | startNodeSpace: 40, 58 | endNodeRadius: 12, 59 | endNodeSpace: 40 60 | }; 61 | fixture.detectChanges(); 62 | }); 63 | 64 | it('should create', () => { 65 | expect(component).toBeTruthy(); 66 | }); 67 | }); 68 | -------------------------------------------------------------------------------- /projects/@ledge-framework/render/src/lib/chart/ledge-pipeline/ledge-pipeline.model.ts: -------------------------------------------------------------------------------- 1 | export interface PipelineConfig { 2 | connectionStrokeWidth: number; 3 | stateStrokeWidth: number; 4 | stateRadius: number; 5 | stageSpace: number; 6 | stageLabelHeight: number; 7 | stageLabelSize: string; 8 | jobHeight: number; 9 | jobLabelSize: string; 10 | startNodeRadius: number; 11 | startNodeSpace: number; 12 | endNodeRadius: number; 13 | endNodeSpace: number; 14 | } 15 | 16 | export interface Stage { 17 | label: string; 18 | jobs: Job[]; 19 | } 20 | 21 | export interface Job { 22 | label: string; 23 | state: JobState; 24 | } 25 | 26 | 27 | export enum JobState { 28 | UNTOUCHED = 'untouched', 29 | PROCESSING = 'processing', 30 | CURRENT = 'current', 31 | SUCCESS = 'success', 32 | ERROR = 'error', 33 | PENDING = 'pending', 34 | } 35 | 36 | export enum Color { 37 | GREEN = '#4A9900', 38 | RED = '#C4000A', 39 | GRAY = '#949393', 40 | WHITE = '#FFFFFF', 41 | } 42 | 43 | export enum PolygonPoints { 44 | checkMark = '-2.00 2.80 -4.80 0.00 -5.73 0.933 -2.00 4.67 6.00 -3.33 5.07 -4.27', 45 | crossMark = '4.67 -3.73 3.73 -4.67 0 -0.94 -3.73 -4.67 -4.67 -3.73 -0.94 0 -4.67 3.73 -3.73 4.67 0 0.94 3.73 4.67 4.67 3.73 0.94 0', 46 | } 47 | 48 | export const defaultPipelineConfig = { 49 | connectionStrokeWidth: 4, 50 | stateStrokeWidth: 4, 51 | stateRadius: 16, 52 | stageSpace: 60, 53 | stageLabelHeight: 30, 54 | stageLabelSize: '16px', 55 | jobHeight: 60, 56 | jobLabelSize: '12px', 57 | startNodeRadius: 12, 58 | startNodeSpace: 40, 59 | endNodeRadius: 12, 60 | endNodeSpace: 40, 61 | }; 62 | -------------------------------------------------------------------------------- /projects/@ledge-framework/render/src/lib/chart/ledge-pure-echarts/ledge-pure-echarts.component.html: -------------------------------------------------------------------------------- 1 |
2 | 3 |
4 | -------------------------------------------------------------------------------- /projects/@ledge-framework/render/src/lib/chart/ledge-pure-echarts/ledge-pure-echarts.component.scss: -------------------------------------------------------------------------------- 1 | .chart { 2 | width: auto; 3 | height: auto; 4 | min-width: 500px; 5 | min-height: 500px; 6 | max-width: 800px; 7 | } 8 | -------------------------------------------------------------------------------- /projects/@ledge-framework/render/src/lib/chart/ledge-pure-echarts/ledge-pure-echarts.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { LedgePureEchartsComponent } from './ledge-pure-echarts.component'; 4 | 5 | describe('LedgePureEchartsComponent', () => { 6 | let component: LedgePureEchartsComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [LedgePureEchartsComponent], 12 | }).compileComponents(); 13 | })); 14 | 15 | beforeEach(() => { 16 | fixture = TestBed.createComponent(LedgePureEchartsComponent); 17 | component = fixture.componentInstance; 18 | fixture.detectChanges(); 19 | }); 20 | 21 | it('should create', () => { 22 | expect(component).toBeTruthy(); 23 | }); 24 | }); 25 | -------------------------------------------------------------------------------- /projects/@ledge-framework/render/src/lib/chart/ledge-pure-echarts/ledge-pure-echarts.component.ts: -------------------------------------------------------------------------------- 1 | import { 2 | AfterViewInit, 3 | Component, 4 | ElementRef, 5 | Input, 6 | OnInit, 7 | ViewChild, 8 | } from '@angular/core'; 9 | import * as echarts from 'echarts'; 10 | 11 | @Component({ 12 | selector: 'ledge-pure-echarts', 13 | templateUrl: './ledge-pure-echarts.component.html', 14 | styleUrls: ['./ledge-pure-echarts.component.scss'], 15 | }) 16 | export class LedgePureEchartsComponent implements OnInit, AfterViewInit { 17 | @Input() 18 | data: string; 19 | 20 | @ViewChild('chart', {}) reporter: ElementRef; 21 | 22 | ngOnInit(): void {} 23 | 24 | ngAfterViewInit(): void { 25 | const mychart = echarts.init(this.reporter.nativeElement); 26 | try { 27 | mychart.setOption(JSON.parse(this.data)); 28 | } catch (e) { 29 | console.error(this.data); 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /projects/@ledge-framework/render/src/lib/chart/ledge-pyramid/ledge-pyramid.component.html: -------------------------------------------------------------------------------- 1 |
2 | 3 |
4 | -------------------------------------------------------------------------------- /projects/@ledge-framework/render/src/lib/chart/ledge-pyramid/ledge-pyramid.component.scss: -------------------------------------------------------------------------------- 1 | .chart { 2 | width: auto; 3 | height: auto; 4 | min-width: 500px; 5 | min-height: 500px; 6 | max-width: 800px; 7 | } 8 | -------------------------------------------------------------------------------- /projects/@ledge-framework/render/src/lib/chart/ledge-pyramid/ledge-pyramid.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | import { LedgePyramidComponent } from './ledge-pyramid.component'; 3 | 4 | describe('LedgePyramidComponent', () => { 5 | let component: LedgePyramidComponent; 6 | let fixture: ComponentFixture; 7 | 8 | beforeEach(async(() => { 9 | TestBed.configureTestingModule({ 10 | declarations: [LedgePyramidComponent], 11 | }).compileComponents(); 12 | })); 13 | 14 | beforeEach(() => { 15 | fixture = TestBed.createComponent(LedgePyramidComponent); 16 | component = fixture.componentInstance; 17 | component.data = [ 18 | { 19 | children: [ 20 | { 21 | children: [], 22 | name: '', 23 | }, 24 | ], 25 | name: '', 26 | }, 27 | ]; 28 | fixture.detectChanges(); 29 | }); 30 | 31 | it('should create', () => { 32 | expect(component).toBeTruthy(); 33 | }); 34 | }); 35 | -------------------------------------------------------------------------------- /projects/@ledge-framework/render/src/lib/chart/ledge-pyramid/ledge-pyramid.component.ts: -------------------------------------------------------------------------------- 1 | import { 2 | AfterViewInit, 3 | Component, 4 | ElementRef, 5 | Input, 6 | OnInit, 7 | ViewChild 8 | } from '@angular/core'; 9 | import * as echarts from 'echarts'; 10 | import LedgeChartConverter from '../../components/model/ledge-chart-converter'; 11 | import { LedgeListItem } from '../../components/model/ledge-chart.model'; 12 | 13 | @Component({ 14 | selector: 'ledge-pyramid', 15 | templateUrl: './ledge-pyramid.component.html', 16 | styleUrls: ['./ledge-pyramid.component.scss'], 17 | }) 18 | export class LedgePyramidComponent implements OnInit, AfterViewInit { 19 | @Input() 20 | data: LedgeListItem[]; 21 | 22 | @ViewChild('chart', {}) reporter: ElementRef; 23 | 24 | constructor() {} 25 | 26 | ngOnInit(): void {} 27 | 28 | ngAfterViewInit(): void { 29 | const myChart = echarts.init(this.reporter.nativeElement); 30 | const treeData = LedgeChartConverter.toTreeData(this.data); 31 | const pyramidLength = treeData.children.length; 32 | const CHART_MAX_VALUE = 100; 33 | for (let i = 0; i < pyramidLength; i++) { 34 | treeData.children[i].value = (CHART_MAX_VALUE / pyramidLength) * (i + 1); 35 | } 36 | 37 | const option = this.buildOption(treeData); 38 | myChart.setOption(option as any); 39 | } 40 | 41 | private buildOption(data) { 42 | const seriesData = { 43 | name: data.name, 44 | type: 'funnel', 45 | sort: 'ascending', 46 | label: { 47 | show: true, 48 | position: 'inside', 49 | fontSize: 14, 50 | }, 51 | labelLine: { 52 | length: 10, 53 | lineStyle: { 54 | width: 1, 55 | type: 'solid', 56 | }, 57 | show: false 58 | }, 59 | itemStyle: { 60 | borderColor: '#fff', 61 | borderWidth: 1, 62 | }, 63 | emphasis: { 64 | label: { 65 | fontSize: 24, 66 | }, 67 | }, 68 | data: data.children, 69 | }; 70 | const series = this.buildSeries(data, seriesData); 71 | 72 | return { 73 | title: { 74 | text: data.name, 75 | top: 'bottom', 76 | left: 'center' 77 | }, 78 | tooltip: { 79 | trigger: 'item', 80 | formatter: '{b}', 81 | }, 82 | series, 83 | }; 84 | } 85 | 86 | private buildSeries(data, seriesData: any) { 87 | const series = []; 88 | const split = data.children[0].name.split('、'); 89 | if (split.length === 2) { 90 | const centerData = JSON.parse(JSON.stringify(seriesData)); 91 | centerData.label = { 92 | position: 'center', 93 | fontSize: 14, 94 | lineHeight: 28, 95 | formatter: (params: any) => { 96 | params.data.name = params.data.name.replace(/
/, '\n'); 97 | return params.data.name; 98 | } 99 | }; 100 | series.push(centerData); 101 | 102 | const leftSeries = JSON.parse(JSON.stringify(seriesData)); 103 | leftSeries.label.position = 'left'; 104 | series.push(leftSeries); 105 | 106 | const rightSeries = JSON.parse(JSON.stringify(seriesData)); 107 | rightSeries.label.position = 'right'; 108 | series.push(rightSeries); 109 | 110 | // tslint:disable-next-line:prefer-for-of 111 | for (let i = 0; i < data.children.length; i++) { 112 | const item = data.children[i]; 113 | const center = item.name.split(':')[0]; 114 | const othersSplit = item.name.split(':')[1].split('、'); 115 | 116 | series[0].data[i].name = center; 117 | series[1].data[i].name = othersSplit[0]; 118 | series[2].data[i].name = othersSplit[1]; 119 | } 120 | 121 | // component-todo: remove hard code 122 | series[0].width = 'auto'; 123 | series[1].width = 'auto'; 124 | series[2].width = 'auto'; 125 | } else { 126 | series.push(seriesData); 127 | } 128 | return series; 129 | } 130 | } 131 | -------------------------------------------------------------------------------- /projects/@ledge-framework/render/src/lib/chart/ledge-quadrant/ledge-quadrant.component.html: -------------------------------------------------------------------------------- 1 |
2 | 3 |
4 | -------------------------------------------------------------------------------- /projects/@ledge-framework/render/src/lib/chart/ledge-quadrant/ledge-quadrant.component.scss: -------------------------------------------------------------------------------- 1 | .chart { 2 | width: auto; 3 | height: auto; 4 | min-width: 500px; 5 | min-height: 600px; 6 | max-width: 800px; 7 | } 8 | -------------------------------------------------------------------------------- /projects/@ledge-framework/render/src/lib/chart/ledge-quadrant/ledge-quadrant.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | import { LedgeQuadrantComponent } from './ledge-quadrant.component'; 3 | 4 | 5 | describe('LedgeQuadrantComponent', () => { 6 | let component: LedgeQuadrantComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [LedgeQuadrantComponent], 12 | }).compileComponents(); 13 | })); 14 | 15 | beforeEach(() => { 16 | fixture = TestBed.createComponent(LedgeQuadrantComponent); 17 | component = fixture.componentInstance; 18 | component.data = [ 19 | { 20 | name: 'parent', 21 | children: [ 22 | {name: 'child', children: [{name: ''}]}, 23 | {name: 'child', children: [{name: ''}]}, 24 | {name: 'child', children: [{name: ''}]}, 25 | {name: 'child', children: [{name: ''}]}, 26 | ], 27 | }, 28 | ]; 29 | 30 | fixture.detectChanges(); 31 | }); 32 | 33 | it('should create', () => { 34 | expect(component).toBeTruthy(); 35 | }); 36 | }); 37 | -------------------------------------------------------------------------------- /projects/@ledge-framework/render/src/lib/chart/ledge-radar/ledge-radar.component.html: -------------------------------------------------------------------------------- 1 |
2 | 3 |
4 | -------------------------------------------------------------------------------- /projects/@ledge-framework/render/src/lib/chart/ledge-radar/ledge-radar.component.scss: -------------------------------------------------------------------------------- 1 | .ledge-radar { 2 | width: auto; 3 | height: auto; 4 | min-width: 500px; 5 | min-height: 500px; 6 | max-width: 800px; 7 | } 8 | -------------------------------------------------------------------------------- /projects/@ledge-framework/render/src/lib/chart/ledge-radar/ledge-radar.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | import { LedgeRadarComponent } from './ledge-radar.component'; 3 | 4 | 5 | describe('LedgeRadarComponent', () => { 6 | let component: LedgeRadarComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [LedgeRadarComponent], 12 | }).compileComponents(); 13 | })); 14 | 15 | beforeEach(() => { 16 | fixture = TestBed.createComponent(LedgeRadarComponent); 17 | component = fixture.componentInstance; 18 | component.data = [ 19 | { 20 | children: [ 21 | { 22 | children: [], 23 | name: '', 24 | }, 25 | ], 26 | name: '', 27 | }, 28 | ]; 29 | 30 | fixture.detectChanges(); 31 | }); 32 | 33 | it('should create', () => { 34 | expect(component).toBeTruthy(); 35 | }); 36 | 37 | it('should success build option', () => { 38 | const data = {name: '团队技能图谱示例', children: [{name: 'Jenkins: 3.5'}, {name: 'Chef: 3.3'}]}; 39 | component.config = {}; 40 | 41 | const buildOption = component.buildOption(data); 42 | 43 | expect(buildOption.series[0].data[0].value).toEqual([3.5, 3.3]); 44 | }); 45 | }); 46 | -------------------------------------------------------------------------------- /projects/@ledge-framework/render/src/lib/chart/ledge-sunburst/ledge-sunburst.component.html: -------------------------------------------------------------------------------- 1 |
2 | 3 |
4 | -------------------------------------------------------------------------------- /projects/@ledge-framework/render/src/lib/chart/ledge-sunburst/ledge-sunburst.component.scss: -------------------------------------------------------------------------------- 1 | .ledge-sunburst { 2 | width: auto; 3 | height: auto; 4 | min-width: 960px; 5 | min-height: 960px; 6 | max-width: 1200px; 7 | } 8 | -------------------------------------------------------------------------------- /projects/@ledge-framework/render/src/lib/chart/ledge-sunburst/ledge-sunburst.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { LedgeSunburstComponent } from './ledge-sunburst.component'; 4 | 5 | describe('LedgeSunburstComponent', () => { 6 | let component: LedgeSunburstComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ LedgeSunburstComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(LedgeSunburstComponent); 18 | component = fixture.componentInstance; 19 | component.data = [{ 20 | children: [ 21 | { 22 | children: [ 23 | { 24 | children: [], 25 | name: '', 26 | }, 27 | ], 28 | name: '', 29 | }, 30 | ], 31 | }]; 32 | fixture.detectChanges(); 33 | }); 34 | 35 | it('should create', () => { 36 | expect(component).toBeTruthy(); 37 | }); 38 | }); 39 | -------------------------------------------------------------------------------- /projects/@ledge-framework/render/src/lib/chart/ledge-sunburst/ledge-sunburst.component.ts: -------------------------------------------------------------------------------- 1 | import { AfterViewInit, Component, ElementRef, Input, OnInit, ViewChild } from '@angular/core'; 2 | import * as echarts from 'echarts'; 3 | import { LedgeListItem } from '../../components/model/ledge-chart.model'; 4 | 5 | 6 | @Component({ 7 | selector: 'ledge-sunburst', 8 | templateUrl: './ledge-sunburst.component.html', 9 | styleUrls: ['./ledge-sunburst.component.scss'] 10 | }) 11 | export class LedgeSunburstComponent implements OnInit, AfterViewInit { 12 | @Input() 13 | data: LedgeListItem[]; 14 | 15 | @Input() 16 | config: any; 17 | 18 | @ViewChild('chart', {}) chart: ElementRef; 19 | 20 | private childLevel = 0; 21 | 22 | ngOnInit(): void { 23 | } 24 | 25 | ngAfterViewInit(): void { 26 | const myChart = echarts.init(this.chart.nativeElement); 27 | const result = this.setValue(this.data, 0); 28 | const option = this.buildOption(result); 29 | myChart.setOption(option as any); 30 | } 31 | 32 | private buildOption(treeData: any) { 33 | return { 34 | visualMap: { 35 | type: 'continuous', 36 | min: 0, 37 | max: 10, 38 | inRange: { 39 | color: ['#2D5F73', '#538EA6', '#F2D1B3', '#F2B8A2', '#F28C8C'] 40 | } 41 | }, 42 | series: { 43 | type: 'sunburst', 44 | data: treeData, 45 | radius: [0, '90%'], 46 | label: { 47 | rotate: 'radial' 48 | } 49 | } 50 | }; 51 | } 52 | 53 | private setValue(list: LedgeListItem[], value) { 54 | this.childLevel++; 55 | for (const item of list) { 56 | if (item.children) { 57 | this.setValue(item.children, value); 58 | } else { 59 | item.value = 1; 60 | } 61 | 62 | if (item.name && item.name.endsWith('*')) { 63 | item.itemStyle = { 64 | color: '#F54F4A' 65 | }; 66 | } 67 | } 68 | 69 | this.childLevel--; 70 | return list; 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /projects/@ledge-framework/render/src/lib/chart/ledge-tech-radar/ledge-tech-radar.component.html: -------------------------------------------------------------------------------- 1 |
2 | 3 |
4 | -------------------------------------------------------------------------------- /projects/@ledge-framework/render/src/lib/chart/ledge-tech-radar/ledge-tech-radar.component.scss: -------------------------------------------------------------------------------- 1 | :host { 2 | margin: 0 auto; 3 | padding: 0 20px; 4 | max-width: 1200px; 5 | } 6 | -------------------------------------------------------------------------------- /projects/@ledge-framework/render/src/lib/chart/ledge-tech-radar/ledge-tech-radar.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { LedgeTechRadarComponent } from './ledge-tech-radar.component'; 4 | 5 | describe('LedgeTechRadarComponent', () => { 6 | let component: LedgeTechRadarComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ LedgeTechRadarComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(LedgeTechRadarComponent); 18 | component = fixture.componentInstance; 19 | component.data = [{ 20 | children: [ 21 | { 22 | children: [ 23 | { 24 | children: [], 25 | name: '', 26 | }, 27 | ], 28 | name: '', 29 | }, 30 | ], 31 | }]; 32 | fixture.detectChanges(); 33 | }); 34 | 35 | it('should create', () => { 36 | expect(component).toBeTruthy(); 37 | }); 38 | }); 39 | -------------------------------------------------------------------------------- /projects/@ledge-framework/render/src/lib/chart/ledge-tree/ledge-tree.component.html: -------------------------------------------------------------------------------- 1 |
2 | 3 |
4 | -------------------------------------------------------------------------------- /projects/@ledge-framework/render/src/lib/chart/ledge-tree/ledge-tree.component.scss: -------------------------------------------------------------------------------- 1 | :host { 2 | min-height: 800px; 3 | } 4 | -------------------------------------------------------------------------------- /projects/@ledge-framework/render/src/lib/chart/ledge-tree/ledge-tree.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { LedgeTreeComponent } from './ledge-tree.component'; 4 | 5 | describe('LedgeTreeComponent', () => { 6 | let component: LedgeTreeComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ LedgeTreeComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(LedgeTreeComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /projects/@ledge-framework/render/src/lib/components/component-checklist/component-checklist.component.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | 4 | 5 | 6 | 7 | 8 |
9 |
10 | -------------------------------------------------------------------------------- /projects/@ledge-framework/render/src/lib/components/component-checklist/component-checklist.component.scss: -------------------------------------------------------------------------------- 1 | .component-checklist { 2 | border: 1px solid #eee; 3 | padding: 8px 8px 0 8px; 4 | margin-top: 4px; 5 | border-radius: 4px; 6 | } 7 | 8 | .title { 9 | font-size: 16px; 10 | padding: 0; 11 | font-weight: 300; 12 | } 13 | 14 | .description { 15 | font-weight: lighter; 16 | font-size: 12px; 17 | } 18 | 19 | .checklist-item { 20 | height: 24px; 21 | line-height: 24px; 22 | } 23 | -------------------------------------------------------------------------------- /projects/@ledge-framework/render/src/lib/components/component-checklist/component-checklist.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { ComponentChecklistComponent } from './component-checklist.component'; 4 | import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; 5 | import { RouterTestingModule } from '@angular/router/testing'; 6 | import { LedgeStorageService } from '../../services/ledge-storage.service'; 7 | import { FormsModule, ReactiveFormsModule } from '@angular/forms'; 8 | 9 | describe('ChecklistComponent', () => { 10 | let component: ComponentChecklistComponent; 11 | let fixture: ComponentFixture; 12 | 13 | beforeEach(async(() => { 14 | TestBed.configureTestingModule({ 15 | imports: [ 16 | BrowserAnimationsModule, 17 | RouterTestingModule, 18 | FormsModule, 19 | ReactiveFormsModule, 20 | ], 21 | providers: [LedgeStorageService], 22 | declarations: [] 23 | }) 24 | .compileComponents(); 25 | })); 26 | 27 | beforeEach(() => { 28 | fixture = TestBed.createComponent(ComponentChecklistComponent); 29 | component = fixture.componentInstance; 30 | fixture.detectChanges(); 31 | }); 32 | 33 | it('should create', () => { 34 | expect(component).toBeTruthy(); 35 | }); 36 | }); 37 | -------------------------------------------------------------------------------- /projects/@ledge-framework/render/src/lib/components/component-checklist/component-checklist.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, EventEmitter, Input, OnChanges, OnInit, Output, SimpleChanges } from '@angular/core'; 2 | import { MatCheckboxChange } from '@angular/material/checkbox'; 3 | 4 | import { ChecklistModel } from '../model/checklist.model'; 5 | 6 | @Component({ 7 | selector: 'component-checklist', 8 | templateUrl: './component-checklist.component.html', 9 | styleUrls: ['./component-checklist.component.scss'] 10 | }) 11 | export class ComponentChecklistComponent implements OnInit, OnChanges { 12 | @Input() checklists: ChecklistModel[] = []; 13 | @Input() name: string; 14 | 15 | @Output() updateParent = new EventEmitter(); 16 | 17 | constructor() { 18 | } 19 | 20 | ngOnInit() { 21 | 22 | } 23 | 24 | completeChange($event: MatCheckboxChange) { 25 | this.updateParent.emit($event.checked); 26 | } 27 | 28 | ngOnChanges(changes: SimpleChanges): void { 29 | if (!!changes.checklists) { 30 | this.checklists = changes.checklists.currentValue as ChecklistModel[]; 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /projects/@ledge-framework/render/src/lib/components/component-rating-item/component-rating-item.component.html: -------------------------------------------------------------------------------- 1 | {{item.displayName}} : {{item.chartValue}} 2 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /projects/@ledge-framework/render/src/lib/components/component-rating-item/component-rating-item.component.scss: -------------------------------------------------------------------------------- 1 | :host { 2 | font-size: 16px; 3 | } 4 | -------------------------------------------------------------------------------- /projects/@ledge-framework/render/src/lib/components/component-rating-item/component-rating-item.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { ComponentRatingItemComponent } from './component-rating-item.component'; 4 | import { MarkdownModule } from 'ngx-markdown'; 5 | import { LedgeRenderModule } from '../../ledge-render.module'; 6 | 7 | describe('MarkdownRatingItemComponent', () => { 8 | let component: ComponentRatingItemComponent; 9 | let fixture: ComponentFixture; 10 | 11 | beforeEach(async(() => { 12 | TestBed.configureTestingModule({ 13 | imports: [LedgeRenderModule, MarkdownModule], 14 | declarations: [ComponentRatingItemComponent], 15 | }).compileComponents(); 16 | })); 17 | 18 | beforeEach(() => { 19 | fixture = TestBed.createComponent(ComponentRatingItemComponent); 20 | component = fixture.componentInstance; 21 | component.item = { 22 | id: '', 23 | name: '23442' 24 | }; 25 | fixture.detectChanges(); 26 | }); 27 | 28 | it('should create', () => { 29 | expect(component).toBeTruthy(); 30 | }); 31 | 32 | it('should reg touch', () => { 33 | const mockTouch = jasmine.createSpy('touch'); 34 | component.registerOnTouched(mockTouch); 35 | component.onTouched({}); 36 | expect(mockTouch).toHaveBeenCalled(); 37 | }); 38 | 39 | it('should reg change', () => { 40 | const mockChange = jasmine.createSpy('change'); 41 | component.registerOnChange(mockChange); 42 | component.onChange('a'); 43 | expect(mockChange).toHaveBeenCalled(); 44 | }); 45 | 46 | it('should change state', () => { 47 | component.setDisabledState(true); 48 | expect(component.disabled).toEqual(true); 49 | }); 50 | }); 51 | -------------------------------------------------------------------------------- /projects/@ledge-framework/render/src/lib/components/component-rating-item/component-rating-item.component.ts: -------------------------------------------------------------------------------- 1 | import { 2 | Component, 3 | EventEmitter, 4 | forwardRef, 5 | Input, 6 | OnInit, 7 | Output, 8 | } from '@angular/core'; 9 | import { NG_VALUE_ACCESSOR } from '@angular/forms'; 10 | import { MatSliderChange } from '@angular/material/slider'; 11 | import { RatingItemModel } from '../model/rating.model'; 12 | 13 | @Component({ 14 | selector: 'component-rating-item', 15 | templateUrl: './component-rating-item.component.html', 16 | styleUrls: ['./component-rating-item.component.scss'], 17 | providers: [ 18 | { 19 | provide: NG_VALUE_ACCESSOR, 20 | useExisting: forwardRef(() => ComponentRatingItemComponent), 21 | multi: true, 22 | }, 23 | ], 24 | }) 25 | export class ComponentRatingItemComponent implements OnInit { 26 | @Input() item: RatingItemModel; 27 | @Output() itemChange = new EventEmitter(); 28 | 29 | disabled = false; 30 | 31 | onChange(_) {} 32 | 33 | onTouched(_) {} 34 | 35 | ngOnInit() { 36 | const nameValuesSplit = this.item.name.split(': '); 37 | this.item.displayName = nameValuesSplit[0]; 38 | if (nameValuesSplit.length > 1) { 39 | this.item.chartValue = parseInt(nameValuesSplit[1], 10); 40 | } 41 | } 42 | 43 | registerOnChange(fn: any): void { 44 | this.onChange = fn; 45 | this.itemChange.emit = fn; 46 | } 47 | 48 | registerOnTouched(fn: any): void { 49 | this.onTouched = fn; 50 | } 51 | 52 | setDisabledState(isDisabled: boolean): void { 53 | this.disabled = isDisabled; 54 | } 55 | 56 | writeValue(obj: any): void { 57 | if (obj !== null && obj !== undefined) { 58 | this.item = obj; 59 | } 60 | } 61 | 62 | updateValue($event: MatSliderChange) { 63 | this.itemChange.emit(this.item); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /projects/@ledge-framework/render/src/lib/components/component-rating/component-rating.component.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | 6 | 7 | 8 | 9 |
10 |
11 | -------------------------------------------------------------------------------- /projects/@ledge-framework/render/src/lib/components/component-rating/component-rating.component.scss: -------------------------------------------------------------------------------- 1 | ul { 2 | li { 3 | font-size: 1.2em; 4 | } 5 | 6 | ul { 7 | li { 8 | font-size: 1em; 9 | line-height: 1.2em !important; 10 | margin-left: 2em; 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /projects/@ledge-framework/render/src/lib/components/component-rating/component-rating.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | import { MarkdownModule } from 'ngx-markdown'; 3 | 4 | import { ComponentRatingComponent } from './component-rating.component'; 5 | import { LedgeRenderModule } from '../../ledge-render.module'; 6 | 7 | describe('MarkdownRatingComponent', () => { 8 | let component: ComponentRatingComponent; 9 | let fixture: ComponentFixture; 10 | 11 | beforeEach(async(() => { 12 | TestBed.configureTestingModule({ 13 | imports: [LedgeRenderModule, MarkdownModule], 14 | declarations: [ComponentRatingComponent], 15 | }).compileComponents(); 16 | })); 17 | 18 | beforeEach(() => { 19 | fixture = TestBed.createComponent(ComponentRatingComponent); 20 | component = fixture.componentInstance; 21 | fixture.detectChanges(); 22 | }); 23 | 24 | it('should create', () => { 25 | component.onChange('aa'); 26 | component.onTouched({}); 27 | expect(component).toBeTruthy(); 28 | }); 29 | 30 | it('should reg touch', () => { 31 | const mockTouch = jasmine.createSpy('touch'); 32 | component.registerOnTouched(mockTouch); 33 | component.onTouched({}); 34 | expect(mockTouch).toHaveBeenCalled(); 35 | }); 36 | 37 | it('should reg change', () => { 38 | const mockChange = jasmine.createSpy('change'); 39 | component.registerOnChange(mockChange); 40 | component.onChange('a'); 41 | expect(mockChange).toHaveBeenCalled(); 42 | }); 43 | 44 | it('should change state', () => { 45 | component.setDisabledState(true); 46 | expect(component.disabled).toEqual(true); 47 | }); 48 | }); 49 | -------------------------------------------------------------------------------- /projects/@ledge-framework/render/src/lib/components/component-rating/component-rating.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, EventEmitter, forwardRef, Input, OnInit, Output } from '@angular/core'; 2 | import { ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms'; 3 | import { RatingItemModel } from '../model/rating.model'; 4 | 5 | @Component({ 6 | selector: 'component-rating', 7 | templateUrl: './component-rating.component.html', 8 | styleUrls: ['./component-rating.component.scss'], 9 | providers: [ 10 | { 11 | provide: NG_VALUE_ACCESSOR, 12 | useExisting: forwardRef(() => ComponentRatingComponent), 13 | multi: true, 14 | }, 15 | ], 16 | }) 17 | export class ComponentRatingComponent implements OnInit, ControlValueAccessor { 18 | @Input() data: any[]; 19 | @Output() dataChange = new EventEmitter(); 20 | 21 | @Input() isParent = false; 22 | @Input() instanceKey: string; 23 | 24 | disabled = false; 25 | 26 | onChange(_) {} 27 | 28 | onTouched(_) {} 29 | 30 | constructor() {} 31 | 32 | ngOnInit(): void { 33 | } 34 | 35 | registerOnChange(fn: any): void { 36 | this.onChange = fn; 37 | } 38 | 39 | registerOnTouched(fn: any): void { 40 | this.onTouched = fn; 41 | } 42 | 43 | setDisabledState(isDisabled: boolean): void { 44 | this.disabled = isDisabled; 45 | } 46 | 47 | writeValue(obj: any): void { 48 | if (obj !== null) { 49 | this.data = obj; 50 | } 51 | } 52 | 53 | changeForm($event: any, item: RatingItemModel, index: number) { 54 | item.name = item.displayName + ': ' + item.chartValue; 55 | this.data[index] = item; 56 | this.dataChange.emit(this.data); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /projects/@ledge-framework/render/src/lib/components/component-todo/component-todo.component.html: -------------------------------------------------------------------------------- 1 |
2 | 3 | 4 | 5 | 6 |
7 | -------------------------------------------------------------------------------- /projects/@ledge-framework/render/src/lib/components/component-todo/component-todo.component.scss: -------------------------------------------------------------------------------- 1 | .complete { 2 | text-decoration: line-through; 3 | } 4 | 5 | .title { 6 | font-weight: 300; 7 | font-size: 14px; 8 | } 9 | 10 | .description { 11 | font-weight: lighter; 12 | font-size: 12px; 13 | } 14 | -------------------------------------------------------------------------------- /projects/@ledge-framework/render/src/lib/components/component-todo/component-todo.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; 3 | 4 | import { ComponentTodoComponent } from './component-todo.component'; 5 | import { LedgeStorageService } from '../../services/ledge-storage.service'; 6 | import { FormsModule, ReactiveFormsModule } from '@angular/forms'; 7 | import { CustomMaterialModule } from '../../custom-material.module'; 8 | 9 | describe('TodoComponent', () => { 10 | let component: ComponentTodoComponent; 11 | let fixture: ComponentFixture; 12 | 13 | beforeEach(async(() => { 14 | TestBed.configureTestingModule({ 15 | imports: [ 16 | BrowserAnimationsModule, 17 | FormsModule, 18 | CustomMaterialModule, 19 | ReactiveFormsModule 20 | ], 21 | providers: [LedgeStorageService], 22 | declarations: [ComponentTodoComponent] 23 | }) 24 | .compileComponents(); 25 | })); 26 | 27 | beforeEach(() => { 28 | fixture = TestBed.createComponent(ComponentTodoComponent); 29 | component = fixture.componentInstance; 30 | fixture.detectChanges(); 31 | }); 32 | 33 | it('should create', () => { 34 | expect(component).toBeTruthy(); 35 | }); 36 | }); 37 | -------------------------------------------------------------------------------- /projects/@ledge-framework/render/src/lib/components/component-todo/component-todo.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, EventEmitter, forwardRef, Input, OnDestroy, OnInit, Output } from '@angular/core'; 2 | import { ControlValueAccessor, FormBuilder, FormGroup, NG_VALUE_ACCESSOR, Validators } from '@angular/forms'; 3 | import { Subject } from 'rxjs'; 4 | import { MatCheckboxChange } from '@angular/material/checkbox'; 5 | 6 | import { TodoModel } from '../model/todo.model'; 7 | import { LedgeStorageService } from '../../services/ledge-storage.service'; 8 | 9 | @Component({ 10 | selector: 'component-todo', 11 | templateUrl: './component-todo.component.html', 12 | styleUrls: ['./component-todo.component.scss'], 13 | providers: [ 14 | { 15 | provide: NG_VALUE_ACCESSOR, 16 | useExisting: forwardRef(() => ComponentTodoComponent), 17 | multi: true 18 | } 19 | ] 20 | }) 21 | export class ComponentTodoComponent implements OnInit, OnDestroy, ControlValueAccessor { 22 | @Input() form: FormGroup; 23 | @Input() toDos: TodoModel[] = []; 24 | @Input() disableInput = false; 25 | 26 | @Output() formChange = new EventEmitter(); 27 | 28 | private unsubscribe = new Subject(); 29 | private disabled = false; 30 | 31 | onChange(change: any) { 32 | } 33 | 34 | onTouched() { 35 | } 36 | 37 | constructor(private formBuilder: FormBuilder, private storage: LedgeStorageService) { 38 | } 39 | 40 | ngOnInit() { 41 | this.form = this.formBuilder.group({ 42 | todo: ['', [ 43 | Validators.required, 44 | Validators.minLength(2) 45 | ]] 46 | }); 47 | 48 | this.form.valueChanges.subscribe(() => { 49 | this.formChange.emit(this.form); 50 | }); 51 | } 52 | 53 | addToDo(value) { 54 | this.toDos.push({ 55 | id: Math.random(), 56 | checked: false, 57 | name: value 58 | }); 59 | } 60 | 61 | ngOnDestroy() { 62 | this.unsubscribe.next(); 63 | this.unsubscribe.complete(); 64 | } 65 | 66 | completeChange($event: MatCheckboxChange, toDo: TodoModel) { 67 | toDo.checked = $event.checked; 68 | this.onChange(this.toDos); 69 | } 70 | 71 | submitTodo() { 72 | if (this.form.valid) { 73 | this.addToDo(this.form.value.todo); 74 | this.form.controls.todo.setValue(null); 75 | } 76 | } 77 | 78 | registerOnChange(fn: any): void { 79 | this.onChange = fn; 80 | } 81 | 82 | registerOnTouched(fn: any): void { 83 | this.onTouched = fn; 84 | } 85 | 86 | setDisabledState(isDisabled: boolean): void { 87 | this.disabled = isDisabled; 88 | } 89 | 90 | writeValue(value: any): void { 91 | if (value !== null && value !== undefined) { 92 | this.toDos = value; 93 | } 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /projects/@ledge-framework/render/src/lib/components/ledge-card/ledge-card.component.html: -------------------------------------------------------------------------------- 1 |
2 |
8 |
{{ data.header }}
9 |
10 |
11 |

12 | {{ cell }} 13 |

14 |
15 |
16 | -------------------------------------------------------------------------------- /projects/@ledge-framework/render/src/lib/components/ledge-card/ledge-card.component.scss: -------------------------------------------------------------------------------- 1 | $background: #f3f4f5; 2 | $border-color: #e8e8e8; 3 | $black: #111; 4 | 5 | .card { 6 | position: relative; 7 | margin: 0; 8 | padding: 0; 9 | font-size: 14px; 10 | font-variant: tabular-nums; 11 | box-sizing: border-box; 12 | line-height: 1.5; 13 | list-style: none; 14 | background-color: $background; 15 | border-radius: 2px; 16 | transition: all 0.3s; 17 | max-width: 300px; 18 | min-width: 140px; 19 | height: 100%; 20 | 21 | &-head { 22 | height: 60px; 23 | padding: 0 24px; 24 | color: $black; 25 | font-size: 16px; 26 | border-bottom: 1px solid $border-color; 27 | text-align: center; 28 | 29 | .title { 30 | display: inline-block; 31 | flex: 1; 32 | padding: 13px 0; 33 | overflow: hidden; 34 | white-space: nowrap; 35 | text-overflow: ellipsis; 36 | font-size: 18px; 37 | font-weight: 600; 38 | font-stretch: normal; 39 | line-height: 1.89; 40 | letter-spacing: 0.75px; 41 | } 42 | } 43 | 44 | &-body { 45 | padding: 20px 20px 0 20px; 46 | zoom: 1; 47 | 48 | p { 49 | font-size: 14px; 50 | font-style: normal; 51 | line-height: 1.57; 52 | letter-spacing: normal; 53 | text-align: center; 54 | color: $black; 55 | margin-bottom: 19px; 56 | } 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /projects/@ledge-framework/render/src/lib/components/ledge-card/ledge-card.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { LedgeCardComponent } from './ledge-card.component'; 4 | 5 | describe('LedgeCardComponent', () => { 6 | let component: LedgeCardComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ LedgeCardComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(LedgeCardComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /projects/@ledge-framework/render/src/lib/components/ledge-card/ledge-card.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit, Input } from '@angular/core'; 2 | import LedgeCardColors from './lege-card-colors'; 3 | 4 | interface CardData { 5 | header: string; 6 | cells: string[]; 7 | index?: number; 8 | } 9 | 10 | interface HeaderStyle { 11 | bg: string; 12 | font: string; 13 | } 14 | 15 | @Component({ 16 | selector: 'ledge-card', 17 | templateUrl: './ledge-card.component.html', 18 | styleUrls: ['./ledge-card.component.scss'], 19 | }) 20 | export class LedgeCardComponent implements OnInit { 21 | @Input() 22 | data: CardData = { 23 | header: '', 24 | cells: [], 25 | index: -1, 26 | }; 27 | @Input() 28 | headerStyle: HeaderStyle = { 29 | bg: '#fff', 30 | font: '#333', 31 | }; 32 | 33 | constructor() {} 34 | 35 | ngOnInit(): void {} 36 | 37 | /* TODO:更好的实现方式 */ 38 | getHeaderStyle() { 39 | let idx = this.data.index; 40 | 41 | if (!idx && idx !== 0) { 42 | idx = Math.floor(Math.random() * 10); 43 | } 44 | const bgColor = (this.headerStyle && this.headerStyle.bg) || LedgeCardColors[idx]; 45 | const fontColor = (this.headerStyle && this.headerStyle.font) || '#333'; 46 | 47 | return { 48 | 'background-color': bgColor, 49 | color: fontColor, 50 | }; 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /projects/@ledge-framework/render/src/lib/components/ledge-card/lege-card-colors.ts: -------------------------------------------------------------------------------- 1 | const LedgeCardColors = [ 2 | '#e55852', 3 | '#e98832', 4 | '#f0d668', 5 | '#47c0af', 6 | '#387fd5', 7 | '#7753df', 8 | '#079948', 9 | '#00A2A1', 10 | '#666666', 11 | '#F37C20', 12 | ]; 13 | 14 | export default LedgeCardColors; 15 | -------------------------------------------------------------------------------- /projects/@ledge-framework/render/src/lib/components/ledge-checklist/ledge-checklist.component.html: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /projects/@ledge-framework/render/src/lib/components/ledge-checklist/ledge-checklist.component.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ledge-framework/engine/66b893282ed856ee6db29130e1144eb4e4d415fc/projects/@ledge-framework/render/src/lib/components/ledge-checklist/ledge-checklist.component.scss -------------------------------------------------------------------------------- /projects/@ledge-framework/render/src/lib/components/ledge-checklist/ledge-checklist.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { LedgeChecklistComponent } from './ledge-checklist.component'; 4 | 5 | describe('LedgeChecklistComponent', () => { 6 | let component: LedgeChecklistComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ LedgeChecklistComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(LedgeChecklistComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | component.ngOnInit(); 24 | expect(component).toBeTruthy(); 25 | }); 26 | }); 27 | -------------------------------------------------------------------------------- /projects/@ledge-framework/render/src/lib/components/ledge-checklist/ledge-checklist.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, Input, OnChanges, OnInit, SimpleChanges } from '@angular/core'; 2 | import { LedgeListItem } from '../model/ledge-chart.model'; 3 | import { CheckItem, ChecklistModel } from '../model/checklist.model'; 4 | 5 | @Component({ 6 | selector: 'ledge-checklist', 7 | templateUrl: './ledge-checklist.component.html', 8 | styleUrls: ['./ledge-checklist.component.scss'] 9 | }) 10 | export class LedgeChecklistComponent implements OnInit, OnChanges { 11 | @Input() 12 | data: LedgeListItem[]; 13 | 14 | @Input() 15 | config: any; 16 | checklists: any; 17 | title: any; 18 | 19 | ngOnInit(): void { 20 | } 21 | 22 | ngOnChanges(changes: SimpleChanges): void { 23 | this.renderData(); 24 | } 25 | 26 | private renderData() { 27 | this.title = encodeURIComponent(this.data[0].name); 28 | const items = this.data[0].children; 29 | const checklists: ChecklistModel[] = []; 30 | for (const item of items) { 31 | const checklist: ChecklistModel = { 32 | name: item.name, 33 | description: '', 34 | subitems: [] 35 | }; 36 | 37 | if ((item as object).hasOwnProperty('checked')) { 38 | checklist.checked = item.checked; 39 | } 40 | for (const child of item.children) { 41 | const splitName = child.name.split(':'); 42 | const subItem: CheckItem = { 43 | name: splitName[0], 44 | description: splitName.length > 1 ? splitName[1] : '' 45 | }; 46 | if ((child as object).hasOwnProperty('checked')) { 47 | subItem.checked = child.checked; 48 | } 49 | checklist.subitems.push(subItem); 50 | } 51 | checklists.push(checklist); 52 | } 53 | this.checklists = checklists; 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /projects/@ledge-framework/render/src/lib/components/ledge-dev-process/ledge-dev-process.component.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 | {{column.name}} 5 |
6 |
7 |
{{section.name}}
8 |
9 |
10 | {{item.name}} 11 | {{item.name}} 12 |
13 |
14 |
15 |
16 |
17 | -------------------------------------------------------------------------------- /projects/@ledge-framework/render/src/lib/components/ledge-dev-process/ledge-dev-process.component.scss: -------------------------------------------------------------------------------- 1 | .dev-process { 2 | display: flex; 3 | 4 | .process-column { 5 | flex-direction: column; 6 | width: 100%; 7 | padding: 4px; 8 | 9 | 10 | .column-title { 11 | text-align: center; 12 | color: #fff; 13 | padding: 1em 0; 14 | } 15 | 16 | .section-block { 17 | flex: 1; 18 | position: relative; 19 | margin-top: 1em; 20 | background: #fff; 21 | 22 | .section-name { 23 | top: -0.5em; 24 | left: 1em; 25 | padding: 0 1em; 26 | position: absolute; 27 | background: #fff; 28 | } 29 | 30 | .section-items { 31 | border: 1px solid #222; 32 | padding-top: 0.5em; 33 | 34 | .section-item { 35 | display: inline-block; 36 | 37 | .pure-text { 38 | padding: 16px 8px; 39 | } 40 | 41 | img { 42 | display: inline-block; 43 | width: 60px; 44 | height: auto; 45 | margin: 0; 46 | } 47 | } 48 | } 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /projects/@ledge-framework/render/src/lib/components/ledge-dev-process/ledge-dev-process.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { LedgeDevProcessComponent } from './ledge-dev-process.component'; 4 | 5 | describe('LedgeDevProcessComponent', () => { 6 | let component: LedgeDevProcessComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ LedgeDevProcessComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(LedgeDevProcessComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /projects/@ledge-framework/render/src/lib/components/ledge-dev-process/ledge-dev-process.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, Input, OnInit } from '@angular/core'; 2 | import { LedgeListItem } from '../model/ledge-chart.model'; 3 | 4 | @Component({ 5 | selector: 'ledge-dev-process', 6 | templateUrl: './ledge-dev-process.component.html', 7 | styleUrls: ['./ledge-dev-process.component.scss'] 8 | }) 9 | export class LedgeDevProcessComponent implements OnInit { 10 | @Input() 11 | data: LedgeListItem[]; 12 | 13 | @Input() 14 | config: any; 15 | 16 | imagesShow: any = {}; 17 | 18 | constructor() { 19 | } 20 | 21 | ngOnInit(): void { 22 | 23 | } 24 | 25 | getImageUrl(name: string) { 26 | return `https://phodal.github.io/logo/png/${this.getItemName(name)}.png`; 27 | } 28 | 29 | updateUrl(name: string, $event: any) { 30 | this.imagesShow[name] = { 31 | showImage: false 32 | }; 33 | } 34 | 35 | showImage(name: string) { 36 | if (this.imagesShow[name] === undefined) { 37 | return true; 38 | } 39 | 40 | if (this.imagesShow[name] && this.imagesShow[name].showImage) { 41 | return true; 42 | } 43 | 44 | return false; 45 | } 46 | 47 | getItemName(name: string) { 48 | return name.toLowerCase().replace(/\s/g, '-'); 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /projects/@ledge-framework/render/src/lib/components/ledge-kanban/README.md: -------------------------------------------------------------------------------- 1 | based on: https://github.com/Devstackr/kanban-angular-layout 2 | -------------------------------------------------------------------------------- /projects/@ledge-framework/render/src/lib/components/ledge-kanban/ledge-kanban.component.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |

{{ board.name }}

4 |
5 | 6 |
7 | 8 |
9 |
10 | 11 |
12 | {{ column.name }} 13 |
14 | 15 |
19 |
20 | {{ item }} 21 |
22 |
23 |
24 | 25 |
26 | 27 |
28 | 29 |
30 | -------------------------------------------------------------------------------- /projects/@ledge-framework/render/src/lib/components/ledge-kanban/ledge-kanban.component.scss: -------------------------------------------------------------------------------- 1 | $medium-grey: #ddd; 2 | $fontColor: white; 3 | $bgColor: #7753df; 4 | $boardColor: rgba(white, 0.5); 5 | 6 | .root { 7 | display: flex; 8 | flex-direction: column; 9 | height: 100%; 10 | } 11 | 12 | .board { 13 | display: flex; 14 | flex-direction: column; 15 | flex-grow: 1; 16 | min-width: 0; 17 | min-height: 0; 18 | background: $bgColor; 19 | 20 | .board-bar { 21 | padding: 8px 15px; 22 | 23 | .board-name { 24 | font-size: 20px; 25 | font-weight: bold; 26 | color: $fontColor; 27 | text-align: left; 28 | } 29 | } 30 | 31 | .board-wrapper { 32 | display: flex; 33 | flex-grow: 1; 34 | overflow-x: auto; 35 | 36 | .board-columns { 37 | display: flex; 38 | flex-grow: 1; 39 | 40 | .board-column { 41 | display: flex; 42 | flex-direction: column; 43 | flex-grow: 1; 44 | flex-basis: 0; // to force the columns to all be the same size, regardless of content 45 | min-width: 250px; 46 | margin: 12px; 47 | padding: 12px; 48 | border-radius: 4px; 49 | background: $boardColor; 50 | 51 | &:not(:first-child) { 52 | margin-left: 0; 53 | } 54 | 55 | .column-title { 56 | font-size: 20px; 57 | font-weight: 800; 58 | text-transform: uppercase; 59 | margin-bottom: 20px; 60 | } 61 | } 62 | } 63 | } 64 | } 65 | 66 | .tasks-container { 67 | flex-grow: 1; 68 | overflow-y: auto; 69 | } 70 | 71 | .task { 72 | display: flex; 73 | padding: 15px 12px; 74 | background: $fontColor; 75 | border-bottom: solid 1px $medium-grey; 76 | border-radius: 4px; 77 | margin-bottom: 15px; 78 | box-shadow: 0 5px 5px -3px rgba(0, 0, 0, 0.05), 79 | 0 3px 14px 2px rgba(0, 0, 0, 0.05); 80 | } 81 | 82 | .cdk-drag-preview { 83 | box-sizing: border-box; 84 | border-radius: 4px; 85 | box-shadow: 0 5px 5px -3px rgba(0, 0, 0, 0.2), 86 | 0 8px 10px 1px rgba(0, 0, 0, 0.14), 87 | 0 3px 14px 2px rgba(0, 0, 0, 0.12); 88 | } 89 | 90 | .cdk-drag-placeholder { 91 | opacity: 0; 92 | } 93 | 94 | .cdk-drag-animating { 95 | transition: transform 250ms cubic-bezier(0, 0, 0.2, 1); 96 | } 97 | 98 | .tasks-container.cdk-drop-list-dragging .task:not(.cdk-drag-placeholder) { 99 | transition: transform 250ms cubic-bezier(0, 0, 0.2, 1); 100 | } 101 | -------------------------------------------------------------------------------- /projects/@ledge-framework/render/src/lib/components/ledge-kanban/ledge-kanban.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { LedgeKanbanComponent } from './ledge-kanban.component'; 4 | 5 | describe('LedgeKanbanComponent', () => { 6 | let component: LedgeKanbanComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ LedgeKanbanComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(LedgeKanbanComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /projects/@ledge-framework/render/src/lib/components/ledge-kanban/ledge-kanban.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, Input, OnChanges, OnInit, SimpleChanges } from '@angular/core'; 2 | import { LedgeListItem } from '../model/ledge-chart.model'; 3 | import { CdkDragDrop, moveItemInArray, transferArrayItem } from '@angular/cdk/drag-drop'; 4 | import { Column } from './model/column'; 5 | import { Board } from './model/board'; 6 | 7 | @Component({ 8 | selector: 'ledge-kanban', 9 | templateUrl: './ledge-kanban.component.html', 10 | styleUrls: ['./ledge-kanban.component.scss'] 11 | }) 12 | export class LedgeKanbanComponent implements OnInit, OnChanges { 13 | @Input() 14 | data: LedgeListItem[]; 15 | 16 | @Input() 17 | config: any; 18 | 19 | board: Board = new Board('', []); 20 | 21 | constructor() { 22 | } 23 | 24 | ngOnInit(): void { 25 | } 26 | 27 | ngOnChanges(changes: SimpleChanges): void { 28 | this.updateKanbanData(); 29 | } 30 | 31 | private updateKanbanData() { 32 | if (this.data.length <= 0) { 33 | return; 34 | } 35 | 36 | const kanbanData = this.data[0]; 37 | 38 | this.board = new Board(kanbanData.name, []); 39 | for (const column of kanbanData.children) { 40 | const col = new Column(column.name, []); 41 | if (!!column.children) { 42 | for (const cell of column.children) { 43 | col.tasks.push(cell.name); 44 | } 45 | } 46 | this.board.columns.push(col); 47 | } 48 | } 49 | 50 | drop(event: CdkDragDrop) { 51 | if (event.previousContainer === event.container) { 52 | moveItemInArray(event.container.data, event.previousIndex, event.currentIndex); 53 | } else { 54 | transferArrayItem(event.previousContainer.data, 55 | event.container.data, 56 | event.previousIndex, 57 | event.currentIndex); 58 | } 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /projects/@ledge-framework/render/src/lib/components/ledge-kanban/model/board.ts: -------------------------------------------------------------------------------- 1 | import { Column } from './column'; 2 | 3 | export class Board { 4 | constructor(public name: string, public columns: Column[]) {} 5 | } 6 | -------------------------------------------------------------------------------- /projects/@ledge-framework/render/src/lib/components/ledge-kanban/model/column.ts: -------------------------------------------------------------------------------- 1 | export class Column { 2 | constructor(public name: string, public tasks: string[]) {} 3 | } 4 | -------------------------------------------------------------------------------- /projects/@ledge-framework/render/src/lib/components/ledge-maturity/ledge-maturity.component.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | 7 |
8 | 9 |
10 | 11 |
12 |
13 | -------------------------------------------------------------------------------- /projects/@ledge-framework/render/src/lib/components/ledge-maturity/ledge-maturity.component.scss: -------------------------------------------------------------------------------- 1 | .ledge-maturity { 2 | display: flex; 3 | flex-wrap:wrap; 4 | 5 | .left { 6 | width:60%; 7 | } 8 | .right { 9 | width: 40%; 10 | display: flex; 11 | align-items: center; 12 | justify-content: center; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /projects/@ledge-framework/render/src/lib/components/ledge-maturity/ledge-maturity.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { LedgeMaturityComponent } from './ledge-maturity.component'; 4 | 5 | describe('LedgeMaturityComponent', () => { 6 | let component: LedgeMaturityComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ LedgeMaturityComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(LedgeMaturityComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /projects/@ledge-framework/render/src/lib/components/ledge-maturity/ledge-maturity.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, Input, OnChanges, OnInit, SimpleChanges } from '@angular/core'; 2 | import { LedgeListItem } from '../model/ledge-chart.model'; 3 | import { RatingListModel } from '../model/rating.model'; 4 | 5 | @Component({ 6 | selector: 'ledge-maturity', 7 | templateUrl: './ledge-maturity.component.html', 8 | styleUrls: ['./ledge-maturity.component.scss'] 9 | }) 10 | export class LedgeMaturityComponent implements OnInit, OnChanges { 11 | @Input() 12 | data: LedgeListItem[]; 13 | chartData: LedgeListItem[]; 14 | ratingData: RatingListModel; 15 | 16 | @Input() 17 | config: any; 18 | checklists: any; 19 | title: any; 20 | 21 | ngOnInit(): void { 22 | } 23 | 24 | ngOnChanges(changes: SimpleChanges): void { 25 | if (changes.data) { 26 | this.data = changes.data.currentValue; 27 | this.chartData = this.data; 28 | this.ratingData = this.data[0].children as any; 29 | } 30 | } 31 | 32 | updateData($event: any) { 33 | this.chartData[0].children = $event; 34 | this.chartData = JSON.parse(JSON.stringify(this.chartData)); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /projects/@ledge-framework/render/src/lib/components/ledge-mermaid/ledge-mermaid.component.html: -------------------------------------------------------------------------------- 1 |
2 | -------------------------------------------------------------------------------- /projects/@ledge-framework/render/src/lib/components/ledge-mermaid/ledge-mermaid.component.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ledge-framework/engine/66b893282ed856ee6db29130e1144eb4e4d415fc/projects/@ledge-framework/render/src/lib/components/ledge-mermaid/ledge-mermaid.component.scss -------------------------------------------------------------------------------- /projects/@ledge-framework/render/src/lib/components/ledge-mermaid/ledge-mermaid.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { LedgeMermaidComponent } from './ledge-mermaid.component'; 4 | import { TohtmlPipe } from '../../pipes/tohtml.pipe'; 5 | 6 | describe('LedgeMermaidComponent', () => { 7 | let component: LedgeMermaidComponent; 8 | let fixture: ComponentFixture; 9 | 10 | beforeEach(async(() => { 11 | TestBed.configureTestingModule({ 12 | declarations: [LedgeMermaidComponent, TohtmlPipe], 13 | }).compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(LedgeMermaidComponent); 18 | component = fixture.componentInstance; 19 | component.data = `gantt 20 | title 双周迭代模型 21 | dateFormat YYYY-MM-DD 22 | axisFormat W%U 23 | 24 | section A 组 25 | 需求评审排期 :a1, 2020-01-05, 7d 26 | 提供 UI 素材 :a2, after a1 ,7d 27 | API 开发 :a3, after a1 , 7d 28 | 第一周开始 :done, a4, after a3 , 7d 29 | 第二周开始 :done, a5, after a4 , 7d 30 | 提测 :crit, a6, after a5 , 7d 31 | 灰度全量 :crit, a7, after a6 , 3d 32 | 33 | section B 组 34 | 需求评审排期 :b1, 2020-01-19, 7d 35 | 提供 UI 素材 :b2, after b1 ,7d 36 | API 开发 :b3, after b1 , 7d 37 | 第一周开始 :done, b4, after b3 , 7d 38 | 第二周开始 :done, b5, after b4 , 7d 39 | 提测 :crit, b6, after b5 , 7d 40 | 灰度全量 :crit, b7, after b6 , 3d 41 | `; 42 | fixture.detectChanges(); 43 | }); 44 | 45 | it('should create', () => { 46 | expect(component).toBeTruthy(); 47 | }); 48 | }); 49 | -------------------------------------------------------------------------------- /projects/@ledge-framework/render/src/lib/components/ledge-mermaid/ledge-mermaid.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit, Input } from '@angular/core'; 2 | import * as mermaid from 'mermaid'; 3 | 4 | @Component({ 5 | selector: 'ledge-mermaid', 6 | templateUrl: './ledge-mermaid.component.html', 7 | styleUrls: ['./ledge-mermaid.component.scss'], 8 | }) 9 | export class LedgeMermaidComponent implements OnInit { 10 | @Input() 11 | data: string; 12 | code: string; 13 | 14 | constructor() { 15 | } 16 | 17 | ngOnInit(): void { 18 | mermaid.default.mermaidAPI.initialize({ 19 | theme: 'default', 20 | gantt: { 21 | titleTopMargin: 25, 22 | barHeight: 48, 23 | barGap: 4, 24 | topPadding: 50, 25 | leftPadding: 75, 26 | gridLineStartPadding: 35, 27 | fontSize: 18, 28 | fontFamily: '"Open-Sans", "sans-serif"', 29 | numberSectionStyles: 4, 30 | axisFormat: '%Y-%m-%d', 31 | } 32 | }); 33 | 34 | mermaid.default.mermaidAPI.render( 35 | `mermaid-${Math.random().toString(32).slice(2)}`, 36 | this.data, 37 | (code) => { 38 | this.code = code; 39 | } 40 | ); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /projects/@ledge-framework/render/src/lib/components/ledge-process-step/ledge-process-step.component.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | 4 | {{head}} 5 | 6 |
7 |
8 |
9 |
{{row.name}}
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 | -------------------------------------------------------------------------------- /projects/@ledge-framework/render/src/lib/components/ledge-process-step/ledge-process-step.component.scss: -------------------------------------------------------------------------------- 1 | @import '../../theme/base/type'; 2 | 3 | .markdown-process-step { 4 | display: flex; 5 | margin: 2em auto; 6 | flex: 1; 7 | flex-direction: column; 8 | position: relative; 9 | } 10 | 11 | .step-heads { 12 | height: 32px; 13 | } 14 | 15 | 16 | .ledge-type { 17 | padding: 6px 10px; 18 | border-radius: 6px; 19 | margin-left: 6px; 20 | //color: #fff; 21 | 22 | @extend .ledge-type; 23 | } 24 | 25 | 26 | .process-step-columns { 27 | top: 2em; 28 | display: flex; 29 | flex-direction: row; 30 | justify-content: space-between; 31 | } 32 | -------------------------------------------------------------------------------- /projects/@ledge-framework/render/src/lib/components/ledge-process-step/ledge-process-step.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { LedgeProcessStepComponent } from './ledge-process-step.component'; 4 | 5 | describe('ProcessStepComponent', () => { 6 | let component: LedgeProcessStepComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ LedgeProcessStepComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(LedgeProcessStepComponent); 18 | component = fixture.componentInstance; 19 | component.config = { 20 | heads: [] 21 | }; 22 | component.data = [{ 23 | children: [{ 24 | name: '[1] hello' 25 | }] 26 | }]; 27 | fixture.detectChanges(); 28 | }); 29 | 30 | it('should create', () => { 31 | expect(component).toBeTruthy(); 32 | }); 33 | 34 | it('should build cell type', () => { 35 | expect(component.data[0].children[0].type).toEqual('type_1'); 36 | }); 37 | }); 38 | -------------------------------------------------------------------------------- /projects/@ledge-framework/render/src/lib/components/ledge-process-step/ledge-process-step.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, Input, OnInit } from '@angular/core'; 2 | import { LedgeListItem } from '../model/ledge-chart.model'; 3 | 4 | @Component({ 5 | selector: 'ledge-process-step', 6 | templateUrl: './ledge-process-step.component.html', 7 | styleUrls: ['./ledge-process-step.component.scss'] 8 | }) 9 | export class LedgeProcessStepComponent implements OnInit { 10 | @Input() data: LedgeListItem[]; 11 | @Input() config: any; 12 | regex = /\[(\d+)\]\s?(.*)/; 13 | items = []; 14 | 15 | constructor() { } 16 | 17 | ngOnInit(): void { 18 | if (!this.data) { 19 | return; 20 | } 21 | 22 | if (this.regex.test(this.data[0].children[0].name)) { 23 | this.data.map((column) => { 24 | column.children.map((cell) => { 25 | const regExpExecArray = this.regex.exec(cell.name); 26 | if (regExpExecArray && regExpExecArray.length >= 2) { 27 | cell.type = 'type_' + regExpExecArray[1]; 28 | cell.name = regExpExecArray[2]; 29 | } 30 | }); 31 | }); 32 | } 33 | 34 | this.items = this.data; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /projects/@ledge-framework/render/src/lib/components/ledge-step-line/ledge-step-line.component.html: -------------------------------------------------------------------------------- 1 | 2 |
3 |
7 | {{ dataOne.name }} 8 | 13 |
14 |
15 | 16 |
17 |
18 | 22 | {{ dataTwo.name }} 23 |
24 |
25 |
26 | 27 | 28 |
29 |
30 | {{ item.name }} 31 | 32 |
33 |
34 |
35 | -------------------------------------------------------------------------------- /projects/@ledge-framework/render/src/lib/components/ledge-step-line/ledge-step-line.component.scss: -------------------------------------------------------------------------------- 1 | $black: #111; 2 | $white: #fff; 3 | 4 | @mixin arrow { 5 | width: 0; 6 | height: 0; 7 | border: 12px solid; 8 | } 9 | :host { 10 | display: flex; 11 | align-items: center; 12 | justify-content: center; 13 | flex-wrap: wrap; 14 | } 15 | .step-line { 16 | display: flex; 17 | align-items: flex-start; 18 | width: 930px; 19 | &-reverse { 20 | flex-direction: row-reverse; 21 | } 22 | 23 | &-wrap { 24 | flex-wrap: wrap; 25 | justify-content: center; 26 | } 27 | 28 | > div { 29 | display: flex; 30 | align-items: center; 31 | } 32 | 33 | .step-item { 34 | display: flex; 35 | align-items: center; 36 | justify-content: center; 37 | min-width: 154px; 38 | width: max-content; 39 | height: 60px; 40 | border-radius: 30px; 41 | background-color: $black; 42 | font-size: 18px; 43 | color: $white; 44 | line-height: 34px; 45 | } 46 | 47 | .arrow { 48 | &-right { 49 | @include arrow; 50 | margin: 0 2px 0 14px; 51 | border-color: transparent transparent transparent $black; 52 | } 53 | 54 | &-left { 55 | @include arrow; 56 | margin: 0 14px 0 2px; 57 | border-color: transparent $black transparent transparent; 58 | } 59 | 60 | &-down { 61 | @include arrow; 62 | margin: 14px 0 2px 0; 63 | border-color: $black transparent transparent transparent; 64 | } 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /projects/@ledge-framework/render/src/lib/components/ledge-step-line/ledge-step-line.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { LedgeStepLineComponent } from './ledge-step-line.component'; 4 | 5 | describe('LedgeStepLineComponent', () => { 6 | let component: LedgeStepLineComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ LedgeStepLineComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(LedgeStepLineComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /projects/@ledge-framework/render/src/lib/components/ledge-step-line/ledge-step-line.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit, Input } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'ledge-step-line', 5 | templateUrl: './ledge-step-line.component.html', 6 | styleUrls: ['./ledge-step-line.component.scss'], 7 | }) 8 | export class LedgeStepLineComponent implements OnInit { 9 | @Input() data = []; 10 | 11 | constructor() {} 12 | 13 | ngOnInit(): void {} 14 | } 15 | -------------------------------------------------------------------------------- /projects/@ledge-framework/render/src/lib/components/ledge-table-step/ledge-table-step.component.html: -------------------------------------------------------------------------------- 1 |
2 |
9 | 12 |
17 |
21 | 22 | 24 | 25 | 26 | 27 |
28 | 39 |
43 | 44 | 46 | 47 | 48 | 49 |
50 |
51 |
52 |
53 |
54 | -------------------------------------------------------------------------------- /projects/@ledge-framework/render/src/lib/components/ledge-table-step/ledge-table-step.component.scss: -------------------------------------------------------------------------------- 1 | $black: #111; 2 | $white: #fff; 3 | $gray: #999aaa; 4 | 5 | @mixin arrow { 6 | width: 0; 7 | height: 0; 8 | border: 12px solid; 9 | position: absolute; 10 | } 11 | 12 | @mixin rect { 13 | position: absolute; 14 | width: 16px; 15 | height: 12px; 16 | background-color: $gray; 17 | } 18 | 19 | :host ::ng-deep { 20 | ledge-card { 21 | .card { 22 | min-width: 220px; 23 | } 24 | } 25 | } 26 | 27 | .table-steps { 28 | display: block; 29 | } 30 | 31 | .step-row { 32 | display: flex; 33 | align-items: flex-start; 34 | height: 430px; 35 | margin-bottom: 15px; 36 | 37 | .column { 38 | display: flex; 39 | align-items: center; 40 | height: 90%; 41 | } 42 | 43 | &-reverse { 44 | flex-direction: row-reverse; 45 | } 46 | 47 | &-reverse > &-wrap { 48 | flex-direction: column-reverse; 49 | } 50 | 51 | &-wrap { 52 | flex-wrap: wrap; 53 | justify-content: center; 54 | } 55 | } 56 | 57 | .arrow-down-symbol { 58 | position: relative; 59 | left: 18px; 60 | } 61 | 62 | .arrow { 63 | position: relative; 64 | width: 68px; 65 | 66 | &-right { 67 | @include arrow; 68 | left: 30px; 69 | border-color: transparent transparent transparent $gray; 70 | } 71 | 72 | &-left { 73 | @include arrow; 74 | right: 30px; 75 | border-color: transparent $gray transparent transparent; 76 | } 77 | 78 | &-down { 79 | @include arrow; 80 | top: 30px; 81 | border-color: $gray transparent transparent transparent; 82 | } 83 | } 84 | 85 | .rect { 86 | &-left { 87 | @include rect; 88 | top: 6px; 89 | left: 18px; 90 | } 91 | 92 | &-right { 93 | @include rect; 94 | top: 6px; 95 | right: 18px; 96 | } 97 | 98 | &-down { 99 | @include rect; 100 | top: 18px; 101 | left: 6px; 102 | width: 12px; 103 | height: 18px; 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /projects/@ledge-framework/render/src/lib/components/ledge-table-step/ledge-table-step.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { LedgeTableStepComponent } from './ledge-table-step.component'; 4 | 5 | describe('LedgeTableStepComponent', () => { 6 | let component: LedgeTableStepComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ LedgeTableStepComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(LedgeTableStepComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /projects/@ledge-framework/render/src/lib/components/ledge-table-step/ledge-table-step.component.ts: -------------------------------------------------------------------------------- 1 | import { 2 | AfterViewInit, 3 | ChangeDetectorRef, 4 | Component, 5 | ElementRef, 6 | Input, 7 | OnInit, 8 | Renderer2, 9 | ViewChild, 10 | } from '@angular/core'; 11 | import { LedgeTable } from '../model/ledge-chart.model'; 12 | 13 | @Component({ 14 | selector: 'ledge-table-step', 15 | templateUrl: './ledge-table-step.component.html', 16 | styleUrls: ['./ledge-table-step.component.scss'], 17 | }) 18 | export class LedgeTableStepComponent implements OnInit, AfterViewInit { 19 | @Input() data: LedgeTable = { 20 | header: [], 21 | cells: [], 22 | }; 23 | @Input() config = { 24 | rowHeight: '', 25 | column: 4, 26 | colors: [], 27 | }; 28 | 29 | @ViewChild('tableStep') 30 | tableStepEl: ElementRef; 31 | 32 | column = 4; 33 | rowHeight = '430px'; // card column 的高度 34 | stepRowHeight = '430px'; // 每行高度 35 | rowNums = []; 36 | headers = []; 37 | 38 | itemWidth = 288; // 每个item 最小占用宽度 39 | arrowWidth = 68; // 每个箭头占用宽度 40 | 41 | constructor(private renderer: Renderer2, private cdr: ChangeDetectorRef) {} 42 | 43 | ngOnInit(): void {} 44 | 45 | init() { 46 | this.headers = []; 47 | this.column = this.config.column || this.column; 48 | const headerLen = this.data.header.length; 49 | const rowNum = Math.ceil(headerLen / this.column); 50 | 51 | let i = 0; 52 | const tempHeaders = []; 53 | while (i < rowNum && headerLen) { 54 | const currentIdx = i * this.column; 55 | const endIdx = i !== rowNum - 1 ? currentIdx + this.column : headerLen; 56 | const arr = this.data.header.slice(currentIdx, endIdx); 57 | tempHeaders.push(arr); 58 | i++; 59 | } 60 | this.headers = [...tempHeaders]; 61 | this.rowHeight = this.config.rowHeight || this.rowHeight; 62 | this.stepRowHeight = Number(this.rowHeight.replace('px', '')) + 44 + 'px'; 63 | } 64 | 65 | ngAfterViewInit(): void { 66 | // 依赖父级div宽度做自适应 67 | const parentContainer = this.tableStepEl.nativeElement.parentElement 68 | .parentElement; 69 | const parentContainerWidth = parentContainer.getBoundingClientRect().width; 70 | 71 | // 当前宽度自动判断最大列数,最小不小于4列 72 | if ( 73 | !this.config.column && 74 | Math.ceil(parentContainerWidth / this.itemWidth) > 4 75 | ) { 76 | const c = parentContainerWidth / this.itemWidth; 77 | // 最后一列剩余70% 的空间可以强行多一列,避免空白过多不美观 78 | this.column = 79 | `0.${String(c).split('.')[1]}` > '0.7' ? Math.ceil(c) : Math.floor(c); 80 | } 81 | this.init(); 82 | 83 | // 动态设置每行step 宽度,使得对齐和自动箭头换行 84 | const rowWidth = this.column * this.itemWidth - this.arrowWidth; 85 | this.renderer.setStyle( 86 | this.tableStepEl.nativeElement, 87 | 'width', 88 | `${rowWidth}px` 89 | ); 90 | this.cdr.detectChanges(); 91 | } 92 | 93 | isShowIconBeforeCard(data, hIndex, column, index, last, lastH) { 94 | return ( 95 | ((hIndex + 1) % 2 === 0 && 96 | hIndex * column + index !== data.header.length - 1) || 97 | (!last && lastH && this.headers.length > 1 && (hIndex + 1) % 2 === 0) 98 | ); 99 | } 100 | 101 | isShowIconAfterCard(data, hIndex, column, index) { 102 | return ( 103 | (hIndex + 1) % 2 !== 0 && 104 | hIndex * column + index !== data.header.length - 1 105 | ); 106 | } 107 | } 108 | -------------------------------------------------------------------------------- /projects/@ledge-framework/render/src/lib/components/model/checklist.model.ts: -------------------------------------------------------------------------------- 1 | export interface ChecklistModel { 2 | name: string; 3 | priority?: string; 4 | description: string; 5 | tools?: string[]; 6 | checked?: boolean; 7 | documentation?: string[]; 8 | tags?: []; 9 | subitems?: CheckItem[]; 10 | } 11 | 12 | export interface CheckItem { 13 | name: string; 14 | checked?: boolean; 15 | description: string; 16 | } 17 | -------------------------------------------------------------------------------- /projects/@ledge-framework/render/src/lib/components/model/ledge-chart-converter.ts: -------------------------------------------------------------------------------- 1 | const LedgeChartConverter = { 2 | toTreeData(data: any) { 3 | if (!data) { 4 | return {}; 5 | } 6 | 7 | if (data && data.length === 1) { 8 | const anies = this.transformTreeData(data); 9 | return anies[0]; 10 | } 11 | 12 | const treeInfo = this.transformTreeData(data); 13 | return { 14 | name: '', 15 | children: treeInfo, 16 | config: data.config, 17 | }; 18 | }, 19 | 20 | transformTreeData(data: any) { 21 | const nodes = []; 22 | for (const item of data) { 23 | const node: any = {}; 24 | node.name = item.name; 25 | if (item.children && item.children.length > 0) { 26 | node.children = this.transformTreeData(item.children); 27 | } 28 | nodes.push(node); 29 | } 30 | return nodes; 31 | }, 32 | }; 33 | 34 | export default LedgeChartConverter; 35 | -------------------------------------------------------------------------------- /projects/@ledge-framework/render/src/lib/components/model/ledge-chart.model.ts: -------------------------------------------------------------------------------- 1 | export interface ChartData { 2 | name: string; 3 | value: string | number; 4 | itemStyle: any; 5 | } 6 | 7 | export interface BarChart { 8 | xAxis: ChartData[]; 9 | yAxis: ChartData[][]; 10 | } 11 | 12 | export interface LedgeChartModel { 13 | title: string; 14 | barChart?: BarChart; 15 | } 16 | 17 | export interface LedgeTable { 18 | header: any[]; 19 | cells: any[][]; 20 | } 21 | 22 | export interface LedgeListItem { 23 | children?: LedgeListItem[]; 24 | name?: string; 25 | checked?: boolean; 26 | 27 | value?: number; 28 | itemStyle?: any; 29 | type?: any; 30 | } 31 | 32 | export interface LedgeList { 33 | children: LedgeListItem[]; 34 | } 35 | -------------------------------------------------------------------------------- /projects/@ledge-framework/render/src/lib/components/model/ledge-markdown-converter.spec.ts: -------------------------------------------------------------------------------- 1 | import LedgeMarkdownConverter from './ledge-markdown-converter'; 2 | 3 | describe('LedgeMarkdownConverter', () => { 4 | it('should identify table', () => { 5 | const code = ` 6 | | Challenge;Skill/Ability | low | high | 7 | |-|-|-| 8 | | low | | boredom | 9 | | high | anxiety | flow | 10 | `; 11 | const json = LedgeMarkdownConverter.toJson(code); 12 | expect(json.tables.length).toEqual(1); 13 | expect(json.tables[0].header.length).toEqual(3); 14 | expect(json.tables[0].cells.length).toEqual(3); 15 | expect(json.tables[0].cells[0].length).toEqual(2); 16 | }); 17 | 18 | it('should get config', () => { 19 | const code = ` 20 | 21 | config: {"type": "line-model"} 22 | `; 23 | const json = LedgeMarkdownConverter.toJson(code); 24 | expect(json.config.type).toEqual('line-model'); 25 | }); 26 | 27 | it('should build list', () => { 28 | const code = ` 29 | - a 30 | - b 31 | - c 32 | `; 33 | const json = LedgeMarkdownConverter.toJson(code); 34 | expect(json.lists.length).toEqual(1); 35 | expect(json.lists[0].children.length).toEqual(3); 36 | }); 37 | 38 | it('should build list with children', () => { 39 | const code = ` 40 | - a 41 | - b 42 | `; 43 | const json = LedgeMarkdownConverter.toJson(code); 44 | expect(json.lists.length).toEqual(1); 45 | expect(json.lists[0].children[0].children.length).toEqual(1); 46 | }); 47 | 48 | it('should success build for pie chart', () => { 49 | const code = `pie 50 | - Some & < > " title 51 | - a: 4 52 | - b: 12 53 | - c: 21 54 | - d: 19 55 | `; 56 | const json = LedgeMarkdownConverter.toJson(code); 57 | expect(json.lists.length).toEqual(1); 58 | expect(json.lists[0].children[0].name).toEqual('Some & < > " title'); 59 | }); 60 | }); 61 | -------------------------------------------------------------------------------- /projects/@ledge-framework/render/src/lib/components/model/ledge-markdown-converter.ts: -------------------------------------------------------------------------------- 1 | import marked from 'marked/lib/marked'; 2 | 3 | const renderer = new marked.Renderer(); 4 | renderer.link = (href, title, text) => { 5 | const link = marked.Renderer.prototype.link.call(renderer, href, title, text); 6 | if (/^https:\/\//.test(href) || /^http:\/\//.test(href)) { 7 | return link.replace('"']/, 19 | escapeReplace: /[&<>"']/g, 20 | escapeTestNoEncode: /[<>"']|&(?!#?\w+;)/, 21 | escapeReplaceNoEncode: /[<>"']|&(?!#?\w+;)/g, 22 | escapeReplacements: { 23 | '&': '&', 24 | '<': '<', 25 | '>': '>', 26 | '"': '"', 27 | '\'': ''', 28 | }, 29 | 30 | transpose(array: any[][]) { 31 | if (array.length === 0) { 32 | return; 33 | } 34 | 35 | return array[0].map((col, i) => array.map(row => row[i])); 36 | }, 37 | 38 | getEscapeReplacement(ch) { 39 | return this.escapeReplacements[ch]; 40 | }, 41 | 42 | escape(html: string, encode: boolean) { 43 | if (encode) { 44 | if (this.escapeTest.test(html)) { 45 | return html.replace( 46 | this.escapeReplace, 47 | this.getEscapeReplacement.bind(this) 48 | ); 49 | } 50 | } else { 51 | if (this.escapeTestNoEncode.test(html)) { 52 | return html.replace( 53 | this.escapeReplaceNoEncode, 54 | this.getEscapeReplacement.bind(this) 55 | ); 56 | } 57 | } 58 | 59 | return html; 60 | }, 61 | 62 | unescaped: (text: string) => text 63 | .replace(/&/g, '&') 64 | .replace(/>/g, '>') 65 | .replace(/</g, '<') 66 | .replace(/"/g, '"') 67 | .replace(/'/g, '\''), 68 | 69 | toJson(code: any) { 70 | let config: any = {}; 71 | const tables = []; 72 | const lists = []; 73 | let result = '{'; 74 | 75 | const tokens: marked.Token[] | any = marked.lexer(code); 76 | for (const token of tokens) { 77 | switch (token.type) { 78 | case 'list_start': { 79 | result += '"children": ['; 80 | break; 81 | } 82 | case 'list_item_start': { 83 | result += '{'; 84 | if (token.task) { 85 | result += `"checked": ${token.checked}, `; 86 | } 87 | break; 88 | } 89 | case 'text': { 90 | let text = marked.inlineLexer(token.text, tokens.links); 91 | text = this.unescaped(text); 92 | 93 | result += `"name": ${JSON.stringify(text)},`; 94 | break; 95 | } 96 | case 'list_item_end': { 97 | result += '},'; 98 | break; 99 | } 100 | case 'list_end': { 101 | result += ']'; 102 | break; 103 | } 104 | case 'table': { 105 | const cells = this.transpose(token.cells); 106 | tables.push({ 107 | header: token.header, 108 | cells, 109 | }); 110 | break; 111 | } 112 | case 'paragraph': { 113 | if (token.text.startsWith('config:')) { 114 | const configText = token.text.split('config:')[1]; 115 | config = JSON.parse(configText); 116 | } 117 | break; 118 | } 119 | case 'space': 120 | break; 121 | default: { 122 | console.log(token); 123 | } 124 | } 125 | } 126 | 127 | result = result 128 | .replace(/,]/g, ']') 129 | .replace(/,}/g, '}') 130 | .replace(/},}/g, '}}'); 131 | 132 | result += '}'; 133 | try { 134 | const list = JSON.parse(result); 135 | lists.push(list); 136 | } catch (e) { 137 | console.log(result); 138 | console.error(e); 139 | } 140 | 141 | return { tables, config, lists }; 142 | }, 143 | }; 144 | 145 | export default LedgeMarkdownConverter; 146 | -------------------------------------------------------------------------------- /projects/@ledge-framework/render/src/lib/components/model/markdown.helper.ts: -------------------------------------------------------------------------------- 1 | // tslint:disable-next-line:max-line-length 2 | // REFS: https://github.com/todotxt/todo.txt-android/blob/614e0b5eb688cae8236f33c64d7e791d1030cf3c/app/src/main/java/com/todotxt/todotxttouch/task/TextSplitter.java 3 | import shortid from 'shortid'; 4 | import { MarkdownListModel } from './markdown.model'; 5 | 6 | const COMPLETED_PATTERN = /(\[[x|X]] )(.*)/; 7 | const ID_PATTERN = /(\s\$([A-Za-z0-9_-]{7,14})) (.*)/; 8 | const TAG_PATTERN = /(?:^|\s)\+(\S*\w)/g; 9 | 10 | const MarkdownHelper = { 11 | todoCompiled(text: any): MarkdownListModel { 12 | const originText = text; 13 | let completed = false; 14 | let id; 15 | 16 | TAG_PATTERN.lastIndex = 0; 17 | 18 | const idMatch = ID_PATTERN.exec(text); 19 | if (idMatch && idMatch.length && idMatch.length > 1) { 20 | id = idMatch[2]; 21 | text = idMatch[3]; 22 | } 23 | 24 | const completeMatch = COMPLETED_PATTERN.exec(text); 25 | if (completeMatch && completeMatch.length && completeMatch.length > 1) { 26 | completed = true; 27 | text = completeMatch[2]; 28 | } 29 | 30 | if (!id) { 31 | id = shortid.generate(); 32 | } 33 | 34 | return { 35 | originText, 36 | id, 37 | completed, 38 | text, 39 | }; 40 | }, 41 | 42 | markdownToJSON(tokens: marked.Token[], originTasks) { 43 | let tasks; 44 | let result = '{'; 45 | let checkString = ''; 46 | let config = ''; 47 | 48 | for (const token of tokens) { 49 | if (token.type !== 'text') { 50 | checkString = ''; 51 | } 52 | switch (token.type) { 53 | case 'list_start': { 54 | result += '"children": ['; 55 | break; 56 | } 57 | case 'list_item_start': { 58 | result += '{ "item": '; 59 | if ((token as any).checked) { 60 | checkString = '[x] '; 61 | } else { 62 | checkString = ''; 63 | } 64 | break; 65 | } 66 | case 'text': { 67 | if ( 68 | token.text.includes('[x] ') || 69 | token.text.includes('[X] ') || 70 | token.text.includes('[ ] ') 71 | ) { 72 | checkString = ''; 73 | } 74 | result += 75 | JSON.stringify( 76 | MarkdownHelper.todoCompiled(checkString + token.text) 77 | ) + ','; 78 | break; 79 | } 80 | case 'list_item_end': { 81 | result += '},'; 82 | break; 83 | } 84 | case 'list_end': { 85 | result += ']'; 86 | break; 87 | } 88 | case 'paragraph': { 89 | if (token.text.startsWith('config:')) { 90 | const configText = token.text.split('config:')[1]; 91 | config = JSON.parse(configText); 92 | } 93 | break; 94 | } 95 | default: { 96 | console.log(token); 97 | } 98 | } 99 | } 100 | 101 | result = result.replace(/,]/g, ']').replace(/},}/g, '}}'); 102 | result += '}'; 103 | 104 | try { 105 | tasks = JSON.parse(result).children; 106 | tasks.config = config; 107 | } catch (e) { 108 | tasks = originTasks; 109 | } 110 | 111 | return tasks; 112 | }, 113 | 114 | buildRatingValue(item: MarkdownListModel) { 115 | let text = item.text; 116 | let value = 3; 117 | 118 | const execArray = /(.*):\s*(\d)/.exec(text); 119 | if (execArray && execArray.length >= 3) { 120 | text = execArray[1]; 121 | value = parseInt(execArray[2], 10); 122 | 123 | item.chartText = text; 124 | item.chartValue = value; 125 | } 126 | 127 | return item; 128 | }, 129 | 130 | updateTextFromRatingValue(item: MarkdownListModel) { 131 | const execArray = /(.*)\:\s*(\d)/.exec(item.text); 132 | if (execArray && execArray.length >= 3) { 133 | const text = execArray[1]; 134 | item.text = text + ': ' + item.chartValue; 135 | } else { 136 | item.text = item.text + ': ' + item.chartValue; 137 | } 138 | 139 | return item; 140 | }, 141 | }; 142 | 143 | export default MarkdownHelper; 144 | -------------------------------------------------------------------------------- /projects/@ledge-framework/render/src/lib/components/model/markdown.model.ts: -------------------------------------------------------------------------------- 1 | export interface MarkdownListModel { 2 | id: string; 3 | completed: boolean; 4 | editable?: boolean; 5 | startDate?: string; 6 | endDate?: string; 7 | text: string; 8 | originText?: string; 9 | context?: string; 10 | priority?: string; 11 | mail?: string; 12 | tag?: string[]; 13 | 14 | chartText?: string; 15 | chartValue?: number; 16 | chartFutureValue?: number; 17 | } 18 | -------------------------------------------------------------------------------- /projects/@ledge-framework/render/src/lib/components/model/rating.model.ts: -------------------------------------------------------------------------------- 1 | export interface RatingItemModel { 2 | id?: string; 3 | name: string; 4 | displayName?: string; 5 | chartValue?: number; 6 | } 7 | 8 | export interface RatingListModel { 9 | name?: string; 10 | children?: RatingItemModel; 11 | } 12 | -------------------------------------------------------------------------------- /projects/@ledge-framework/render/src/lib/components/model/todo.model.ts: -------------------------------------------------------------------------------- 1 | export interface TodoModel { 2 | id?: number; 3 | name: string; 4 | description?: string; 5 | checked: boolean; 6 | } 7 | -------------------------------------------------------------------------------- /projects/@ledge-framework/render/src/lib/custom-material.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { MatSliderModule } from '@angular/material/slider'; 3 | import { DragDropModule } from '@angular/cdk/drag-drop'; 4 | import { MatCheckboxModule } from '@angular/material/checkbox'; 5 | 6 | const modules = [ 7 | MatSliderModule, 8 | MatCheckboxModule, 9 | 10 | // CDK 11 | DragDropModule, 12 | ]; 13 | 14 | @NgModule({ 15 | imports: modules, 16 | exports: modules, 17 | }) 18 | export class CustomMaterialModule {} 19 | -------------------------------------------------------------------------------- /projects/@ledge-framework/render/src/lib/ledge-render.component.scss: -------------------------------------------------------------------------------- 1 | @import "styles/list-style"; 2 | 3 | .ledge-render { 4 | width: 100%; 5 | 6 | virtual-scroller { 7 | width: 100%; 8 | 9 | .render-item { 10 | display: block; 11 | } 12 | } 13 | } 14 | 15 | .render-item { 16 | padding: 0 2em; 17 | } 18 | 19 | .card-column { 20 | padding: 0 0.5rem !important; 21 | } 22 | 23 | ul { 24 | padding-left: 1em; 25 | 26 | li { 27 | white-space: pre-wrap; 28 | 29 | &.task-list-item { 30 | list-style: none; 31 | 32 | input[type='checkbox'] { 33 | margin: 0 0.2em 0.25em -1.6em; 34 | vertical-align: middle; 35 | } 36 | } 37 | } 38 | } 39 | .step-line { 40 | display: flex; 41 | } 42 | -------------------------------------------------------------------------------- /projects/@ledge-framework/render/src/lib/pipes/tohtml.pipe.spec.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '@angular/core'; 2 | import { ComponentFixture, TestBed } from '@angular/core/testing'; 3 | import { By } from '@angular/platform-browser'; 4 | import { LedgeRenderModule } from '../ledge-render.module'; 5 | 6 | 7 | describe('Pipe: tohtml', () => { 8 | let fixture: ComponentFixture; 9 | 10 | beforeEach(() => { 11 | TestBed.configureTestingModule({ 12 | imports: [LedgeRenderModule], 13 | declarations: [TestComponent], 14 | }); 15 | fixture = TestBed.createComponent(TestComponent); 16 | fixture.detectChanges(); 17 | }); 18 | 19 | [ 20 | { value: '', result: `` }, 21 | { value: 'ledge', result: `ledge` }, 22 | ].forEach((item: any) => { 23 | it(`${item.value.toString()} muse be ${item.result}`, () => { 24 | fixture.componentInstance.value = item.value; 25 | fixture.detectChanges(); 26 | expect( 27 | (fixture.debugElement.query(By.css('#result')) 28 | .nativeElement as HTMLElement).textContent 29 | ).toBe(item.result); 30 | }); 31 | }); 32 | }); 33 | 34 | @Component({ 35 | template: `
`, 36 | }) 37 | class TestComponent { 38 | value = ''; 39 | } 40 | -------------------------------------------------------------------------------- /projects/@ledge-framework/render/src/lib/pipes/tohtml.pipe.ts: -------------------------------------------------------------------------------- 1 | import { Pipe, PipeTransform } from '@angular/core'; 2 | import { DomSanitizer, SafeHtml } from '@angular/platform-browser'; 3 | 4 | @Pipe({ name: 'tohtml' }) 5 | export class TohtmlPipe implements PipeTransform { 6 | constructor(private dom: DomSanitizer) {} 7 | 8 | transform(html: string): string | SafeHtml { 9 | return html ? this.dom.bypassSecurityTrustHtml(html) : ''; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /projects/@ledge-framework/render/src/lib/services/ledge-storage.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | 3 | @Injectable() 4 | export class LedgeStorageService { 5 | get storage() { 6 | return window.localStorage; 7 | } 8 | 9 | getItem(key: string) { 10 | const json = this.storage.getItem(key); 11 | return json ? JSON.parse(json) : {}; 12 | } 13 | 14 | getItemString(key: string) { 15 | return this.storage.getItem(key); 16 | } 17 | 18 | setItemString(key: string, value: string) { 19 | return this.storage.setItem(key, value); 20 | } 21 | 22 | setItem(key: string, value: string | object) { 23 | const storageValue = value ? JSON.stringify(value) : ''; 24 | return this.storage.setItem(key, storageValue); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /projects/@ledge-framework/render/src/lib/styles/_list-style.scss: -------------------------------------------------------------------------------- 1 | .list-style { 2 | margin: 20px; 3 | 4 | &.list-style-circle { 5 | display: flex; 6 | color: #fff; 7 | text-align: center; 8 | 9 | .list-style-item { 10 | width: 200px; 11 | height: 200px; 12 | border-radius: 200px; 13 | line-height: 200px; 14 | margin-left: 20px; 15 | } 16 | } 17 | 18 | &.list-style-group-square { 19 | display: flex; 20 | color: #fff; 21 | text-align: center; 22 | 23 | > .list-style-item { 24 | width: 320px; 25 | height: 240px; 26 | font-size: 1.2em; 27 | padding: 3em 0 0 0; 28 | 29 | .sub-item, 30 | &.sub-item { 31 | .list-style-item { 32 | font-size: 0.8em; 33 | width: auto; 34 | } 35 | } 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /projects/@ledge-framework/render/src/lib/support/ledgeColors.ts: -------------------------------------------------------------------------------- 1 | const LedgeColors = [ 2 | '#F37C20', 3 | '#E9BD1E', 4 | '#00A2A1', 5 | '#0062CE', 6 | '#666666', 7 | '#DC5332', 8 | '#079948', 9 | '#999999', 10 | '#800080', 11 | '#003366', 12 | '#AA217E', 13 | '#55acee', 14 | '#444444', 15 | '#61bb46', 16 | '#007C78' 17 | ]; 18 | 19 | // component-todo: refactor vars for color 20 | 21 | export default LedgeColors; 22 | -------------------------------------------------------------------------------- /projects/@ledge-framework/render/src/lib/theme/base/_behavior.scss: -------------------------------------------------------------------------------- 1 | .noselect { 2 | -webkit-touch-callout: none; /* iOS Safari */ 3 | -webkit-user-select: none; /* Safari */ 4 | -khtml-user-select: none; /* Konqueror HTML */ 5 | -moz-user-select: none; /* Old versions of Firefox */ 6 | -ms-user-select: none; /* Internet Explorer/Edge */ 7 | user-select: none; 8 | /* Non-prefixed version, currently supported by Chrome, Opera and Firefox */ 9 | } 10 | -------------------------------------------------------------------------------- /projects/@ledge-framework/render/src/lib/theme/base/_type.scss: -------------------------------------------------------------------------------- 1 | .ledge-type { 2 | $themeColours: ( 3 | 0: #F37C20, 4 | 1: #E9BD1E, 5 | 2: #00A2A1, 6 | 3: #0062CE, 7 | 4: #666666, 8 | 5: #DC5332, 9 | 6: #079948, 10 | 7: #999999, 11 | 8: #800080, 12 | 9: #003366, 13 | 10: #AA217E, 14 | 11: #55acee, 15 | 12: #444444, 16 | 13: #61bb46, 17 | 14: #007C78 18 | ); 19 | 20 | @each $i, $color in $themeColours { 21 | &.type_#{$i} { 22 | background: $color; 23 | } 24 | &.type_#{$i}:after { 25 | border-left: 22px solid $color; 26 | } 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /projects/@ledge-framework/render/src/lib/theme/fish-bone.scss: -------------------------------------------------------------------------------- 1 | .label-0 { 2 | font-size: 2em; 3 | } 4 | 5 | .label-1 { 6 | font-size: 1.5em; 7 | fill: #111; 8 | } 9 | 10 | .label-2 { 11 | font-size: 1em; 12 | fill: #444; 13 | } 14 | 15 | .label-3 { 16 | font-size: .9em; 17 | fill: #888; 18 | } 19 | 20 | .label-4 { 21 | font-size: .8em; 22 | fill: #aaa; 23 | } 24 | 25 | .link-0 { 26 | stroke: #000; 27 | stroke-width: 2px 28 | } 29 | 30 | .link-1 { 31 | stroke: #333; 32 | stroke-width: 1px 33 | } 34 | 35 | .link-2, .link-3, .link-4 { 36 | stroke: #666; 37 | stroke-width: .5px; 38 | } 39 | -------------------------------------------------------------------------------- /projects/@ledge-framework/render/src/lib/theme/graphviz.scss: -------------------------------------------------------------------------------- 1 | .graphviz { 2 | width: 100%; 3 | 4 | padding: 1em; 5 | 6 | svg { 7 | border: 1px solid #999; 8 | 9 | width: 100%; 10 | min-height: 400px; 11 | } 12 | 13 | .output { 14 | height: 100%; 15 | display: block; 16 | } 17 | 18 | .node { 19 | white-space: nowrap; 20 | } 21 | 22 | .node rect, 23 | .node circle, 24 | .node ellipse { 25 | stroke: #333; 26 | fill: #fff; 27 | stroke-width: 1.5px; 28 | } 29 | 30 | .cluster rect { 31 | stroke: #333; 32 | fill: #000; 33 | fill-opacity: 0.1; 34 | stroke-width: 1.5px; 35 | } 36 | 37 | .edgePath path.path { 38 | stroke: #333; 39 | stroke-width: 1.5px; 40 | fill: none; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /projects/@ledge-framework/render/src/lib/theme/index.scss: -------------------------------------------------------------------------------- 1 | @import "fish-bone"; 2 | @import "graphviz"; 3 | @import "maturity"; 4 | @import "mermaid"; 5 | @import "process-table"; 6 | @import "tech-radar"; 7 | @import "tree"; 8 | -------------------------------------------------------------------------------- /projects/@ledge-framework/render/src/lib/theme/maturity.scss: -------------------------------------------------------------------------------- 1 | .ledge-maturity { 2 | .mat-list-base .mat-list-item, .mat-list-base .mat-list-option { 3 | height: 24px; 4 | } 5 | 6 | .mat-list-base { 7 | padding-top: 0; 8 | } 9 | 10 | .mat-slider-horizontal { 11 | height: 32px; 12 | } 13 | 14 | .mat-slider-horizontal .mat-slider-wrapper { 15 | top: 13px; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /projects/@ledge-framework/render/src/lib/theme/mermaid.scss: -------------------------------------------------------------------------------- 1 | .mermaid-graph { 2 | margin: 2em 0; 3 | 4 | //tspan { 5 | // font-size: 2em; 6 | //} 7 | } 8 | -------------------------------------------------------------------------------- /projects/@ledge-framework/render/src/lib/theme/tech-radar.scss: -------------------------------------------------------------------------------- 1 | 2 | /* Colors */ 3 | $color1: #868e96; 4 | $color2: #ec7b1a; 5 | $color3: #dc5332; 6 | $color4: #55acee; 7 | $black: #000; 8 | 9 | .color-1 { 10 | color: $color1; 11 | fill: $color1; 12 | stroke: $color1; 13 | } 14 | 15 | .color-2 { 16 | color: $color2; 17 | fill: $color2; 18 | stroke: $color2; 19 | } 20 | 21 | .color-3 { 22 | color: $color3; 23 | fill: $color3; 24 | stroke: $color3; 25 | } 26 | 27 | .color-4 { 28 | color: $color4; 29 | fill: $color4; 30 | stroke: $color4; 31 | } 32 | 33 | .color-5 { 34 | color: #847575; 35 | fill: #847575; 36 | stroke: #847575; 37 | } 38 | 39 | /** Radar **/ 40 | .ledge-tech-radar{ 41 | /* Disable some webkit features to make the radar feel more native */ 42 | -webkit-user-select: none; 43 | -webkit-tap-highlight-color: transparent; 44 | -webkit-touch-callout: none; 45 | display: grid; 46 | grid-column-gap: 20px; 47 | grid-template-columns: 1fr 1fr; 48 | } 49 | 50 | #radarChart { 51 | display: inline-block; 52 | grid-column: 1 /span 2; 53 | width: 100%; 54 | height: 100% 55 | } 56 | 57 | /* swap the last to legends as they run clockwise around the circle */ 58 | .ledge-tech-radar> .legend-2 { 59 | grid-row: 3; 60 | grid-column: 2; 61 | } 62 | 63 | .ledge-tech-radar> .legend-3 { 64 | grid-row: 3; 65 | grid-column: 1; 66 | } 67 | 68 | .tech-circle text, 69 | .tech-circle circle { 70 | cursor: pointer; 71 | font-size: 0.8em; 72 | transition: 0.25s ease-in-out; 73 | } 74 | 75 | .tech-circle.active text, 76 | .tech-circle.active circle { 77 | transform: scale(2); 78 | font-size: 1.2em; 79 | } 80 | 81 | @media (min-width: 1000px) { 82 | .ledge-tech-radar{ 83 | grid-template-columns: 1fr 3fr 1fr; 84 | grid-template-rows: 1fr 1fr; 85 | } 86 | 87 | #radarChart { 88 | grid-row: 1 / span 2; 89 | grid-column: 2; 90 | justify-self: center; 91 | align-self: center; 92 | } 93 | 94 | .legend li.active a { 95 | color: $black; 96 | } 97 | 98 | .ledge-tech-radar> .legend-0 { 99 | grid-column: 1; 100 | grid-row: 1; 101 | } 102 | 103 | .ledge-tech-radar> .legend-1 { 104 | grid-column: 3; 105 | grid-row: 1; 106 | } 107 | 108 | .ledge-tech-radar> .legend-2 { 109 | grid-column: 3; 110 | grid-row: 2 111 | } 112 | 113 | .ledge-tech-radar> .legend-3 { 114 | grid-column: 1; 115 | grid-row: 2; 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /projects/@ledge-framework/render/src/lib/theme/tree.scss: -------------------------------------------------------------------------------- 1 | .ledge-tree { 2 | .node circle { 3 | fill: #fff; 4 | stroke: steelblue; 5 | stroke-width: 3px; 6 | } 7 | 8 | .node text { 9 | font: 12px sans-serif; 10 | } 11 | 12 | .link { 13 | fill: none; 14 | stroke: #ccc; 15 | stroke-width: 2px; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /projects/@ledge-framework/render/src/lib/toolset/toolset.component.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |
{{item.name}}
5 |
6 | 7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 | -------------------------------------------------------------------------------- /projects/@ledge-framework/render/src/lib/toolset/toolset.component.scss: -------------------------------------------------------------------------------- 1 | :host { 2 | padding: 4em; 3 | } 4 | 5 | .slider { 6 | width: 100%; 7 | padding-left: 2em; 8 | padding-top: 2em; 9 | display: flex; 10 | flex-direction: column; 11 | 12 | div { 13 | display: inline-block; 14 | } 15 | 16 | .name { 17 | width: 100px; 18 | } 19 | 20 | .slide { 21 | width: auto; 22 | } 23 | 24 | .slide-element { 25 | width: 300px; 26 | } 27 | } 28 | 29 | .line-chart { 30 | 31 | .toolset-chart { 32 | width: 1200px; 33 | height: 600px; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /projects/@ledge-framework/render/src/lib/toolset/toolset.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { ToolsetComponent } from './toolset.component'; 4 | import { CustomMaterialModule } from '../custom-material.module'; 5 | 6 | describe('ToolsetComponent', () => { 7 | let component: ToolsetComponent; 8 | let fixture: ComponentFixture; 9 | 10 | beforeEach(async(() => { 11 | TestBed.configureTestingModule({ 12 | imports: [CustomMaterialModule], 13 | declarations: [ ToolsetComponent ] 14 | }) 15 | .compileComponents(); 16 | })); 17 | 18 | beforeEach(() => { 19 | fixture = TestBed.createComponent(ToolsetComponent); 20 | component = fixture.componentInstance; 21 | component.option = {id: '1', type: 'line-chart', data: []}; 22 | 23 | fixture.detectChanges(); 24 | }); 25 | 26 | it('should create', () => { 27 | expect(component).toBeTruthy(); 28 | }); 29 | }); 30 | -------------------------------------------------------------------------------- /projects/@ledge-framework/render/src/lib/toolset/toolset.component.ts: -------------------------------------------------------------------------------- 1 | import { 2 | AfterViewInit, 3 | Component, 4 | ElementRef, 5 | Input, 6 | OnInit, 7 | ViewChild 8 | } from '@angular/core'; 9 | import * as echarts from 'echarts'; 10 | import { ToolsetOption } from './toolset'; 11 | 12 | @Component({ 13 | selector: 'toolset', 14 | templateUrl: './toolset.component.html', 15 | styleUrls: ['./toolset.component.scss'], 16 | }) 17 | export class ToolsetComponent implements OnInit, AfterViewInit { 18 | @ViewChild('tool', {}) toolEl: ElementRef; 19 | @ViewChild('lineChart', {}) lineChartEl: ElementRef; 20 | 21 | @Input() 22 | option: ToolsetOption; 23 | 24 | constructor() {} 25 | 26 | ngOnInit(): void { 27 | // console.log(this.option); 28 | } 29 | 30 | setToolsetStyle(option: ToolsetOption) { 31 | const element = document.getElementById(option.id); 32 | if (element == null) { 33 | return; 34 | } 35 | 36 | if (this.toolEl && this.toolEl.nativeElement) { 37 | this.toolEl.nativeElement.setAttribute( 38 | 'style', 39 | `z-index: 999; top: ${element.offsetTop}px;position:absolute` 40 | ); 41 | if (this.toolEl.nativeElement.clientHeight !== 0) { 42 | element.setAttribute( 43 | 'style', 44 | `height: calc(${this.toolEl.nativeElement.clientHeight}px + 2em)` 45 | ); 46 | } 47 | } 48 | } 49 | 50 | ngAfterViewInit(): void { 51 | if (this.option.type === 'line-chart') { 52 | this.renderLineChart(this.option.data); 53 | } 54 | 55 | setTimeout(() => { 56 | this.setToolsetStyle(this.option); 57 | }, 500); 58 | } 59 | 60 | private renderLineChart(data) { 61 | const myChart = echarts.init(this.lineChartEl.nativeElement); 62 | const option = { 63 | width: 500, 64 | height: 500, 65 | xAxis: { 66 | type: 'category', 67 | data: ['Low', '挑战', 'High'], 68 | axisLine: { 69 | symbol: ['none', 'arrow'], 70 | symbolSize: [10, 20], 71 | }, 72 | axisTick: { 73 | show: false, 74 | }, 75 | }, 76 | yAxis: { 77 | type: 'category', 78 | data: ['Low', '能力', 'High'], 79 | axisLine: { 80 | symbol: ['none', 'arrow'], 81 | symbolSize: [10, 20], 82 | }, 83 | axisTick: { 84 | show: false, 85 | }, 86 | }, 87 | series: [ 88 | { 89 | data: [], 90 | type: 'line', 91 | smooth: true, 92 | }, 93 | ], 94 | }; 95 | 96 | myChart.setOption(option as any); 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /projects/@ledge-framework/render/src/lib/toolset/toolset.ts: -------------------------------------------------------------------------------- 1 | export interface ToolsetOption { 2 | id: string; 3 | type?: string; // slider 4 | data: any[]; 5 | offsetHeight?: string; 6 | height?: string; 7 | } 8 | -------------------------------------------------------------------------------- /projects/@ledge-framework/render/src/public-api.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Public API Surface of ledge-render 3 | */ 4 | 5 | export * from './lib/ledge-render.component'; 6 | export * from './lib/ledge-render.module'; 7 | export * from './lib/toolset/toolset'; 8 | export * from './lib/pipes/tohtml.pipe'; 9 | 10 | // todo: refactor 11 | export * from './lib/components/component-checklist/component-checklist.component'; 12 | 13 | -------------------------------------------------------------------------------- /projects/@ledge-framework/render/src/test.ts: -------------------------------------------------------------------------------- 1 | // This file is required by karma.conf.js and loads recursively all the .spec and framework files 2 | 3 | import 'zone.js/dist/zone'; 4 | import 'zone.js/dist/zone-testing'; 5 | import { getTestBed } from '@angular/core/testing'; 6 | import { 7 | BrowserDynamicTestingModule, 8 | platformBrowserDynamicTesting 9 | } from '@angular/platform-browser-dynamic/testing'; 10 | 11 | declare const require: { 12 | context(path: string, deep?: boolean, filter?: RegExp): { 13 | keys(): string[]; 14 | (id: string): T; 15 | }; 16 | }; 17 | 18 | // First, initialize the Angular testing environment. 19 | getTestBed().initTestEnvironment( 20 | BrowserDynamicTestingModule, 21 | platformBrowserDynamicTesting() 22 | ); 23 | // Then we find all the tests. 24 | const context = require.context('./', true, /\.spec\.ts$/); 25 | // And load the modules. 26 | context.keys().map(context); 27 | -------------------------------------------------------------------------------- /projects/@ledge-framework/render/tsconfig.lib.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../out-tsc/lib", 5 | "target": "es2015", 6 | "declaration": true, 7 | "inlineSources": true, 8 | "types": [], 9 | "lib": [ 10 | "dom", 11 | "es2018" 12 | ] 13 | }, 14 | "angularCompilerOptions": { 15 | "skipTemplateCodegen": true, 16 | "strictMetadataEmit": true, 17 | "enableResourceInlining": true 18 | }, 19 | "exclude": [ 20 | "src/test.ts", 21 | "**/*.spec.ts" 22 | ] 23 | } 24 | -------------------------------------------------------------------------------- /projects/@ledge-framework/render/tsconfig.lib.prod.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.lib.json", 3 | "angularCompilerOptions": { 4 | "enableIvy": false 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /projects/@ledge-framework/render/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../out-tsc/spec", 5 | "types": [ 6 | "jasmine", 7 | "node" 8 | ] 9 | }, 10 | "files": [ 11 | "src/test.ts" 12 | ], 13 | "include": [ 14 | "**/*.spec.ts", 15 | "**/*.d.ts" 16 | ] 17 | } 18 | -------------------------------------------------------------------------------- /projects/@ledge-framework/render/tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../../tslint.json", 3 | "rules": { 4 | "directive-selector": [ 5 | true, 6 | "attribute", 7 | "lib", 8 | "camelCase", 9 | "ledge" 10 | ], 11 | "component-selector": [ 12 | true, 13 | "element", 14 | "lib", 15 | "kebab-case", 16 | "ledge" 17 | ] 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /projects/@ledge-framework/render/yarn.lock: -------------------------------------------------------------------------------- 1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 2 | # yarn lockfile v1 3 | 4 | 5 | -------------------------------------------------------------------------------- /projects/@ledge-framework/view/README.md: -------------------------------------------------------------------------------- 1 | # Ledge Framework Engine 2 | 3 | > Legde framework is a documentation as code practises framework. 4 | 5 | demo page: [https://devops.phodal.com/helper](https://devops.phodal.com/helper) 6 | 7 | online editor: [https://devops.phodal.com/helper](https://devops.phodal.com/helper) 8 | 9 | ![CI](https://github.com/ledge-framework/engine/workflows/CI/badge.svg) 10 | 11 | ## Syntax 12 | 13 | ### Ledge extend code syntax 14 | 15 | ```` 16 | ```process-step 17 | - step1 18 | - demo 19 | - kanban 20 | ``` 21 | ```` 22 | 23 | - Chart 24 | - echarts. Echarts chart. 25 | - chart. Echarts bar chart. 26 | - mindmap. Markdown List to mindmap. 27 | - radar. Markdown List to radar chart. 28 | - tech radar. Markdown list to tech radar chart. 29 | - pie。Pie chart 30 | - quadrant。quadrant chart 31 | - pyramid。pyramid chart 32 | - graphviz。dot to graph 33 | - process visualization 34 | - process-table。process chart 35 | - process-step。process chart 2 36 | - process-card。card process chart 37 | - dev-process。process with logo 38 | - step-line。title only line chart 39 | - table-step。with arrow table chart 40 | - checklist。checklists 41 | - mermaid。use [mermaid](https://mermaid-js.github.io/mermaid/) as visual tools 42 | - toolset。use toolset components to extends 43 | - slider 44 | - line-chart 45 | - pipeline。ci pipeline 46 | - maturity。check, rating with radrar for maturity 47 | 48 | ### slide examples 49 | 50 | ```` 51 | ```toolset 52 | - 用户体验 53 | - 时间 54 | - 成本 55 | - 安全 56 | - 范围 57 | 58 | config: {"type": "slider"} 59 | ``` 60 | ```` 61 | 62 | ## Usage 63 | 64 | ### Use with Web Components 65 | 66 | 1. import styles 67 | 68 | ```html 69 | 70 | ``` 71 | 72 | 2. import code 73 | 74 | ```html 75 |
76 | 84 | ``` 85 | 86 | 3. import script 87 | 88 | ```html 89 | 90 | 91 | 92 | ``` 93 | 94 | ### Use in Angular 95 | 96 | 1.install: `yarn add @ledge-framework/render` 97 | 2.import module 98 | 99 | ``` 100 | import { LedgeRenderModule } from '@ledge-framework/render'; 101 | 102 | @NgModule({ 103 | imports: [ 104 | ... 105 | LedgeRenderModule, 106 | ] 107 | ... 108 | }) 109 | ``` 110 | 111 | 3. import styles 112 | 113 | ``` 114 | @import "~@ledge-framework/render/prebuild-theme/index.css"; 115 | ``` 116 | 117 | or import in `angular.json` 118 | 119 | 4.use it 120 | 121 | ``` 122 | 123 | ``` 124 | 125 | ## LICENSE 126 | 127 | @ 2020 [LiuuY](https://github.com/LiuuY) && [Phodal Huang](https://github.com/phodal). This code is distributed under the MPL license. See `LICENSE` in this directory. 128 | -------------------------------------------------------------------------------- /projects/@ledge-framework/view/karma.conf.js: -------------------------------------------------------------------------------- 1 | // Karma configuration file, see link for more information 2 | // https://karma-runner.github.io/1.0/config/configuration-file.html 3 | 4 | module.exports = function (config) { 5 | config.set({ 6 | basePath: '', 7 | frameworks: ['jasmine', '@angular-devkit/build-angular'], 8 | plugins: [ 9 | require('karma-jasmine'), 10 | require('karma-chrome-launcher'), 11 | require('karma-jasmine-html-reporter'), 12 | require('karma-coverage-istanbul-reporter'), 13 | require('@angular-devkit/build-angular/plugins/karma'), 14 | ], 15 | client: { 16 | clearContext: false, // leave Jasmine Spec Runner output visible in browser 17 | }, 18 | coverageIstanbulReporter: { 19 | dir: require('path').join(__dirname, '../../coverage/ledge-view'), 20 | reports: ['html', 'lcovonly', 'text-summary'], 21 | fixWebpackSourcePaths: true, 22 | }, 23 | reporters: ['progress', 'kjhtml'], 24 | port: 9876, 25 | colors: true, 26 | logLevel: config.LOG_INFO, 27 | autoWatch: true, 28 | browsers: ['Chrome'], 29 | singleRun: false, 30 | customLaunchers: { 31 | ChromeHeadlessCI: { 32 | base: 'ChromeHeadless', 33 | flags: ['--no-sandbox', '--disable-gpu'], 34 | }, 35 | }, 36 | restartOnFileChange: true, 37 | }); 38 | }; 39 | -------------------------------------------------------------------------------- /projects/@ledge-framework/view/ng-package.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "../../../node_modules/ng-packagr/ng-package.schema.json", 3 | "dest": "../../../dist/@ledge-framework/view", 4 | "lib": { 5 | "entryFile": "src/public-api.ts" 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /projects/@ledge-framework/view/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@ledge-framework/view", 3 | "version": "1.0.2", 4 | "description": "Ledge Framework render, a powerful markdown render.", 5 | "license": "MPL-2.0", 6 | "repository": "https://github.com/phodal/ledge", 7 | "scirpts": { 8 | "build": "ng build --prod" 9 | }, 10 | "contributors": [ 11 | { 12 | "name": "LiuuY", 13 | "email": "mail4c59@gmail.com", 14 | "url": "https://github.com/LiuuY" 15 | }, 16 | { 17 | "name": "Phodal HUANG", 18 | "url": "https://github.com/phodal/" 19 | } 20 | ], 21 | "private": false, 22 | "peerDependencies": { 23 | "@angular/cdk": "^9.1.1", 24 | "@angular/common": "^9.0.5", 25 | "@angular/core": "^9.0.5", 26 | "@angular/forms": "^9.0.5", 27 | "@angular/material": "^9.1.1", 28 | "@angular/router": "^9.1.1", 29 | "tslib": "^1.10.0", 30 | "@ledge-framework/render": "1.0.0", 31 | "ngx-markdown": "^9.0.0" 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /projects/@ledge-framework/view/src/lib/custom-material.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { MatIconModule } from '@angular/material/icon'; 3 | import { MatSidenavModule } from '@angular/material/sidenav'; 4 | import { MatButtonModule } from '@angular/material/button'; 5 | 6 | const modules = [ 7 | MatSidenavModule, 8 | MatIconModule, 9 | MatButtonModule 10 | ]; 11 | 12 | @NgModule({ 13 | imports: modules, 14 | exports: modules, 15 | }) 16 | export class CustomMaterialModule {} 17 | -------------------------------------------------------------------------------- /projects/@ledge-framework/view/src/lib/ledge-markdown-render/ledge-markdown-render.component.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
    10 |
    11 |
    12 |
    13 |
    14 | 19 | 24 | 25 |
    26 |
    27 |
    28 | 29 |
    30 | 35 | 36 |
    37 | 38 | 39 |
    40 | 43 |
    44 | -------------------------------------------------------------------------------- /projects/@ledge-framework/view/src/lib/ledge-markdown-render/ledge-markdown-render.component.scss: -------------------------------------------------------------------------------- 1 | :host { 2 | position: relative; 3 | box-sizing: border-box; 4 | } 5 | 6 | .no-toc-markdown { 7 | width: 95%; 8 | margin: 1em auto 0; 9 | } 10 | 11 | .editit { 12 | float: right; 13 | top: 44px; 14 | position: relative; 15 | right: 30px; 16 | 17 | :hover { 18 | cursor: pointer; 19 | } 20 | } 21 | 22 | .sticky { 23 | position: fixed; 24 | overflow-y: scroll; 25 | z-index: 10; 26 | top: 0; 27 | height: 100vh; 28 | } 29 | 30 | .scroll-to-top { 31 | position: fixed; 32 | bottom: 64px; 33 | right: 32px; 34 | opacity: 0; 35 | transition: all 0.2s ease-in-out; 36 | } 37 | 38 | .show-scrollTop { 39 | opacity: 1; 40 | z-index: 999; 41 | transition: all 0.2s ease-in-out; 42 | } 43 | -------------------------------------------------------------------------------- /projects/@ledge-framework/view/src/lib/ledge-markdown-render/ledge-markdown-render.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { LedgeMarkdownRenderComponent } from './ledge-markdown-render.component'; 4 | import { RouterTestingModule } from '@angular/router/testing'; 5 | import { MarkdownModule, MarkedOptions } from 'ngx-markdown'; 6 | import { SecurityContext } from '@angular/core'; 7 | import { HttpClient, HttpClientModule } from '@angular/common/http'; 8 | import { LedgeRenderModule } from '@ledge-framework/render'; 9 | 10 | import { CustomMaterialModule } from '../custom-material.module'; 11 | 12 | 13 | describe('MarkdownRenderComponent', () => { 14 | let component: LedgeMarkdownRenderComponent; 15 | let fixture: ComponentFixture; 16 | 17 | beforeEach(async(() => { 18 | TestBed.configureTestingModule({ 19 | imports: [ 20 | HttpClientModule, 21 | CustomMaterialModule, 22 | LedgeRenderModule, 23 | MarkdownModule.forRoot({ 24 | sanitize: SecurityContext.NONE, 25 | loader: HttpClient, 26 | markedOptions: { 27 | provide: MarkedOptions, 28 | useValue: { 29 | gfm: true, 30 | breaks: false, 31 | pedantic: false, 32 | smartLists: true, 33 | smartypants: false, 34 | langPrefix: 'language-', 35 | headerPrefix: '', 36 | headerIds: true, 37 | }, 38 | }, 39 | }), RouterTestingModule], 40 | declarations: [LedgeMarkdownRenderComponent], 41 | }).compileComponents(); 42 | })); 43 | 44 | beforeEach(() => { 45 | fixture = TestBed.createComponent(LedgeMarkdownRenderComponent); 46 | component = fixture.componentInstance; 47 | component.data = ` 48 | # h1 49 | 50 | ## h2 51 | 52 | [link](link) 53 | 54 | `; 55 | fixture.detectChanges(); 56 | }); 57 | 58 | it('should create', () => { 59 | expect(component).toBeTruthy(); 60 | }); 61 | 62 | it('should build toc str', () => { 63 | expect(component.tocStr) 64 | .toEqual(`
    h1 65 | 66 |
    `); 67 | }); 68 | 69 | it('should scroll to top when call scrollToTop', () => { 70 | component.sticky = true; 71 | const scrollTop = window.scrollTo; 72 | window.scrollTo = jasmine.createSpy('scroll'); 73 | 74 | component.scrollToTop(); 75 | expect(component.sticky).toBeFalse(); 76 | expect(window.scrollTo).toHaveBeenCalled(); 77 | 78 | window.scrollTo = scrollTop; 79 | }); 80 | 81 | it('should not show sticky button when not scroll', () => { 82 | component.handleScroll({}); 83 | expect(component.sticky).toBeFalse(); 84 | }); 85 | }); 86 | -------------------------------------------------------------------------------- /projects/@ledge-framework/view/src/lib/ledge-markdown-render/tocify.ts: -------------------------------------------------------------------------------- 1 | export interface TocItem { 2 | anchor: string; 3 | level: number; 4 | text: string; 5 | children?: TocItem[]; 6 | } 7 | 8 | export type TocItems = TocItem[]; // TOC目录树结构 9 | 10 | export default class Tocify { 11 | anchors: string[]; 12 | tocItems: TocItems = []; 13 | 14 | constructor() { 15 | this.anchors = []; 16 | this.tocItems = []; 17 | } 18 | 19 | add(text: string, level: number, id: string = '', anchor: string) { 20 | this.anchors.push(anchor); 21 | const item = { anchor, level, text }; 22 | const items = this.tocItems; 23 | 24 | if (items.length === 0) { 25 | // 第一个 item 直接 push 26 | items.push(item); 27 | } else { 28 | let lastItem = items[items.length - 1]; // 最后一个 item 29 | 30 | if (item.level > lastItem.level) { 31 | // item 是 lastItem 的 children 32 | for (let i = lastItem.level + 1; i <= 6; i++) { 33 | const { children } = lastItem; 34 | if (!children) { 35 | // 如果 children 不存在 36 | lastItem.children = [item]; 37 | break; 38 | } 39 | 40 | lastItem = children[children.length - 1]; // 重置 lastItem 为 children 的最后一个 item 41 | 42 | if (item.level <= lastItem.level) { 43 | // item level 小于或等于 lastItem level 都视为与 children 同级 44 | children.push(item); 45 | break; 46 | } 47 | } 48 | } else { 49 | // 置于最顶级 50 | items.push(item); 51 | } 52 | } 53 | 54 | return anchor; 55 | } 56 | 57 | reset() { 58 | this.tocItems = []; 59 | this.anchors = []; 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /projects/@ledge-framework/view/src/lib/ledge-multiple-docs/doc-route.model.ts: -------------------------------------------------------------------------------- 1 | export interface DocRoute { 2 | displayName: string; 3 | source: string; 4 | default?: boolean; 5 | } 6 | -------------------------------------------------------------------------------- /projects/@ledge-framework/view/src/lib/ledge-multiple-docs/ledge-multiple-docs.component.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |
      4 |
    • 8 | {{item.displayName}} 9 |
    • 10 |
    11 |
    12 | 13 | 17 | 18 | 19 |
    20 | -------------------------------------------------------------------------------- /projects/@ledge-framework/view/src/lib/ledge-multiple-docs/ledge-multiple-docs.component.scss: -------------------------------------------------------------------------------- 1 | @import '../../../../../../node_modules/@angular/material/theming'; 2 | 3 | .multiple-docs { 4 | min-height: 600px; 5 | } 6 | 7 | .left-drawer { 8 | width: 15%; 9 | min-width: 200px; 10 | 11 | h2 { 12 | padding: 20px 0; 13 | text-align: center; 14 | font-weight: bold; 15 | border-bottom: 1px solid rgba(0, 0, 0, 0.12); 16 | margin-bottom: 0; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /projects/@ledge-framework/view/src/lib/ledge-multiple-docs/ledge-multiple-docs.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | import { HttpClientModule } from '@angular/common/http'; 3 | import { RouterTestingModule } from '@angular/router/testing'; 4 | import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; 5 | import { BrowserTestingModule } from '@angular/platform-browser/testing'; 6 | import { LedgeRenderModule } from '@ledge-framework/render'; 7 | 8 | import { LedgeMultipleDocsComponent } from './ledge-multiple-docs.component'; 9 | import { CustomMaterialModule } from '../custom-material.module'; 10 | 11 | describe('LedgeMultipleDocsComponent', () => { 12 | let component: LedgeMultipleDocsComponent; 13 | let fixture: ComponentFixture; 14 | 15 | beforeEach(async(() => { 16 | TestBed.configureTestingModule({ 17 | imports: [ 18 | RouterTestingModule, 19 | LedgeRenderModule, 20 | CustomMaterialModule, 21 | BrowserAnimationsModule, 22 | BrowserTestingModule, 23 | HttpClientModule, 24 | ], 25 | declarations: [LedgeMultipleDocsComponent], 26 | }).compileComponents(); 27 | })); 28 | 29 | beforeEach(() => { 30 | fixture = TestBed.createComponent(LedgeMultipleDocsComponent); 31 | component = fixture.componentInstance; 32 | fixture.detectChanges(); 33 | }); 34 | 35 | it('should create', () => { 36 | expect(component).toBeTruthy(); 37 | }); 38 | }); 39 | -------------------------------------------------------------------------------- /projects/@ledge-framework/view/src/lib/ledge-multiple-docs/ledge-multiple-docs.component.ts: -------------------------------------------------------------------------------- 1 | import { 2 | Component, 3 | Input, 4 | OnChanges, 5 | OnInit, 6 | SimpleChanges, 7 | ViewChild, 8 | } from '@angular/core'; 9 | import { MatDrawerContent } from '@angular/material/sidenav'; 10 | import { Title } from '@angular/platform-browser'; 11 | import { HttpClient, HttpHeaders } from '@angular/common/http'; 12 | 13 | import { DocRoute } from './doc-route.model'; 14 | 15 | @Component({ 16 | selector: 'ledge-multiple-docs', 17 | templateUrl: './ledge-multiple-docs.component.html', 18 | styleUrls: ['./ledge-multiple-docs.component.scss'], 19 | }) 20 | export class LedgeMultipleDocsComponent implements OnInit, OnChanges { 21 | @ViewChild('drawerContent', { static: false }) 22 | drawerContent: MatDrawerContent; 23 | 24 | srcUrl: string; 25 | content: string; 26 | 27 | @Input() items: DocRoute[]; 28 | @Input() currentUrl: string; 29 | @Input() urlPrefix: string; 30 | @Input() source: string; 31 | @Input() baseUrl: string; 32 | 33 | constructor(private title: Title, private http: HttpClient) {} 34 | 35 | ngOnInit(): void {} 36 | 37 | ngOnChanges(changes: SimpleChanges): void { 38 | if (changes.source) { 39 | this.source = changes.source.currentValue; 40 | this.configSource(this.source); 41 | } 42 | } 43 | 44 | private configSource(value: string) { 45 | this.getItem(value); 46 | } 47 | 48 | async getItem(source: string) { 49 | this.srcUrl = this.buildSrc(source); 50 | this.source = source; 51 | 52 | const headers = new HttpHeaders().set( 53 | 'Content-Type', 54 | 'text/plain; charset=utf-8' 55 | ); 56 | this.http 57 | .get(this.srcUrl, { headers, responseType: 'text' }) 58 | .subscribe((response) => { 59 | this.resetScrollbar(); 60 | this.content = response; 61 | }); 62 | } 63 | 64 | private resetScrollbar() { 65 | if (!!this.drawerContent) { 66 | if (!this.drawerContent.hasOwnProperty('nativeElement')) { 67 | this.drawerContent.getElementRef().nativeElement.scrollTop = 0; 68 | } 69 | } 70 | } 71 | 72 | private buildSrc(source: string) { 73 | return `assets/docs/${this.urlPrefix}/${source}.md`; 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /projects/@ledge-framework/view/src/lib/ledge-view.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { LedgeMarkdownRenderComponent } from './ledge-markdown-render/ledge-markdown-render.component'; 3 | import { CommonModule } from '@angular/common'; 4 | import { FormsModule, ReactiveFormsModule } from '@angular/forms'; 5 | import { VirtualScrollerModule } from 'ngx-virtual-scroller'; 6 | 7 | import { LedgeRenderModule } from '@ledge-framework/render'; 8 | import { CustomMaterialModule } from './custom-material.module'; 9 | import { LedgeMultipleDocsComponent } from './ledge-multiple-docs/ledge-multiple-docs.component'; 10 | import { RouterModule } from '@angular/router'; 11 | import { MatButtonModule } from '@angular/material/button'; 12 | 13 | 14 | @NgModule({ 15 | declarations: [LedgeMarkdownRenderComponent, LedgeMultipleDocsComponent], 16 | imports: [ 17 | CommonModule, 18 | FormsModule, 19 | ReactiveFormsModule, 20 | CustomMaterialModule, 21 | VirtualScrollerModule, 22 | RouterModule, 23 | LedgeRenderModule 24 | ], 25 | exports: [LedgeMarkdownRenderComponent, LedgeMultipleDocsComponent] 26 | }) 27 | export class LedgeViewModule { 28 | } 29 | -------------------------------------------------------------------------------- /projects/@ledge-framework/view/src/public-api.ts: -------------------------------------------------------------------------------- 1 | /* 2 | * Public API Surface of ledge-view 3 | */ 4 | 5 | export * from './lib/ledge-multiple-docs/ledge-multiple-docs.component'; 6 | export * from './lib/ledge-markdown-render/ledge-markdown-render.component'; 7 | export * from './lib/ledge-view.module'; 8 | -------------------------------------------------------------------------------- /projects/@ledge-framework/view/src/test.ts: -------------------------------------------------------------------------------- 1 | // This file is required by karma.conf.js and loads recursively all the .spec and framework files 2 | 3 | import 'zone.js/dist/zone'; 4 | import 'zone.js/dist/zone-testing'; 5 | import { getTestBed } from '@angular/core/testing'; 6 | import { 7 | BrowserDynamicTestingModule, 8 | platformBrowserDynamicTesting 9 | } from '@angular/platform-browser-dynamic/testing'; 10 | 11 | declare const require: { 12 | context(path: string, deep?: boolean, filter?: RegExp): { 13 | keys(): string[]; 14 | (id: string): T; 15 | }; 16 | }; 17 | 18 | // First, initialize the Angular testing environment. 19 | getTestBed().initTestEnvironment( 20 | BrowserDynamicTestingModule, 21 | platformBrowserDynamicTesting() 22 | ); 23 | // Then we find all the tests. 24 | const context = require.context('./', true, /\.spec\.ts$/); 25 | // And load the modules. 26 | context.keys().map(context); 27 | -------------------------------------------------------------------------------- /projects/@ledge-framework/view/tsconfig.lib.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../out-tsc/lib", 5 | "target": "es2015", 6 | "declaration": true, 7 | "inlineSources": true, 8 | "types": [], 9 | "lib": [ 10 | "dom", 11 | "es2018" 12 | ] 13 | }, 14 | "angularCompilerOptions": { 15 | "skipTemplateCodegen": true, 16 | "strictMetadataEmit": true, 17 | "enableResourceInlining": true 18 | }, 19 | "exclude": [ 20 | "src/test.ts", 21 | "**/*.spec.ts" 22 | ] 23 | } 24 | 25 | -------------------------------------------------------------------------------- /projects/@ledge-framework/view/tsconfig.lib.prod.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.lib.json", 3 | "angularCompilerOptions": { 4 | "enableIvy": false 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /projects/@ledge-framework/view/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../../out-tsc/spec", 5 | "types": [ 6 | "jasmine", 7 | "node" 8 | ] 9 | }, 10 | "files": [ 11 | "src/test.ts" 12 | ], 13 | "include": [ 14 | "**/*.spec.ts", 15 | "**/*.d.ts" 16 | ] 17 | } 18 | -------------------------------------------------------------------------------- /projects/@ledge-framework/view/tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../../tslint.json", 3 | "rules": { 4 | "directive-selector": [ 5 | true, 6 | "attribute", 7 | "lib", 8 | "camelCase", 9 | "ledge" 10 | ], 11 | "component-selector": [ 12 | true, 13 | "element", 14 | "lib", 15 | "kebab-case", 16 | "ledge" 17 | ] 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /projects/@ledge-framework/view/yarn.lock: -------------------------------------------------------------------------------- 1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 2 | # yarn lockfile v1 3 | 4 | 5 | -------------------------------------------------------------------------------- /src/app/app-routing.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { Routes, RouterModule } from '@angular/router'; 3 | 4 | 5 | const routes: Routes = [ 6 | { 7 | path: 'helper', 8 | loadChildren: () => 9 | import('./ledge-editor/ledge-editor.module').then( 10 | (m) => m.LedgeEditorModule 11 | ), 12 | } 13 | ]; 14 | 15 | @NgModule({ 16 | imports: [RouterModule.forRoot(routes)], 17 | exports: [RouterModule] 18 | }) 19 | export class AppRoutingModule { } 20 | -------------------------------------------------------------------------------- /src/app/app.module.ts: -------------------------------------------------------------------------------- 1 | import { BrowserModule } from '@angular/platform-browser'; 2 | import { DoBootstrap, Injector, NgModule } from '@angular/core'; 3 | import { AngularSplitModule } from 'angular-split'; 4 | import { AppRoutingModule } from './app-routing.module'; 5 | 6 | import { createCustomElement } from '@angular/elements'; 7 | import { LedgeComponent } from './ledge/ledge.component'; 8 | 9 | import { LedgeRenderModule } from '@ledge-framework/render'; 10 | 11 | @NgModule({ 12 | declarations: [ 13 | LedgeComponent 14 | ], 15 | imports: [ 16 | BrowserModule, 17 | AngularSplitModule.forRoot(), 18 | LedgeRenderModule, 19 | AppRoutingModule 20 | ], 21 | providers: [], 22 | // bootstrap: [LedgeComponent], 23 | entryComponents: [LedgeComponent] 24 | }) 25 | export class AppModule implements DoBootstrap { 26 | constructor(private injector: Injector) { 27 | if (customElements.get('ledge')) { 28 | return; 29 | } 30 | 31 | const webComponent = createCustomElement(LedgeComponent, {injector: this.injector}); 32 | customElements.define('ledge-theme', webComponent); 33 | } 34 | 35 | ngDoBootstrap() { 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/app/globals.d.ts: -------------------------------------------------------------------------------- 1 | declare module '*.md'; 2 | 3 | declare module '*.json' { 4 | const value: any; 5 | export default value; 6 | } 7 | -------------------------------------------------------------------------------- /src/app/ledge-editor/ledge-editor.component.html: -------------------------------------------------------------------------------- 1 | 8 | 9 |
    21 |
    22 | 23 | 24 | 25 |
    26 | -------------------------------------------------------------------------------- /src/app/ledge-editor/ledge-editor.component.scss: -------------------------------------------------------------------------------- 1 | .helper { 2 | display: flex; 3 | flex-grow: 1; 4 | height: calc(100vh - 64px); 5 | overflow-y: hidden; 6 | padding: 0 0.2em; 7 | } 8 | 9 | .source { 10 | position: relative; 11 | 12 | .md-editor { 13 | font-size: 14px; 14 | margin-left: 1em; 15 | padding: 8px; 16 | width: 100%; 17 | height: 100%; 18 | } 19 | 20 | .toolbar { 21 | position: absolute; 22 | top: 0; 23 | background: #fff; 24 | right: 0; 25 | height: 30px; 26 | width: 150px; 27 | padding: 0 12px; 28 | z-index: 100; 29 | display: flex; 30 | justify-content: center; 31 | align-items: center; 32 | box-shadow: #c8c8c8 1px 1px 8px 1px; 33 | 34 | mat-select { 35 | width: 84px; 36 | } 37 | } 38 | } 39 | 40 | .sample { 41 | height: 100%; 42 | flex-shrink: 0; 43 | overflow-y: hidden; 44 | } 45 | -------------------------------------------------------------------------------- /src/app/ledge-editor/ledge-editor.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { LedgeEditorComponent } from './ledge-editor.component'; 4 | import { LedgeEditorModule } from './ledge-editor.module'; 5 | 6 | import 'brace/index'; 7 | 8 | describe('LedgeHelperComponent', () => { 9 | let component: LedgeEditorComponent; 10 | let fixture: ComponentFixture; 11 | 12 | beforeEach(async(() => { 13 | TestBed.configureTestingModule({ 14 | imports: [ 15 | LedgeEditorModule, 16 | ], 17 | declarations: [LedgeEditorComponent], 18 | }).compileComponents(); 19 | })); 20 | 21 | beforeEach(() => { 22 | fixture = TestBed.createComponent(LedgeEditorComponent); 23 | component = fixture.componentInstance; 24 | fixture.detectChanges(); 25 | }); 26 | 27 | it('should create', () => { 28 | expect(component).toBeTruthy(); 29 | }); 30 | }); 31 | -------------------------------------------------------------------------------- /src/app/ledge-editor/ledge-editor.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnDestroy, OnInit, ViewChild } from '@angular/core'; 2 | import { EMPTY, Subject, Subscription } from 'rxjs'; 3 | import { debounceTime, distinctUntilChanged, switchMap } from 'rxjs/operators'; 4 | import { SplitAreaDirective, SplitComponent } from 'angular-split'; 5 | 6 | import * as mdData from 'raw-loader!../../assets/docs/help.md'; 7 | 8 | import 'brace/index'; 9 | import 'brace/theme/github'; 10 | 11 | @Component({ 12 | selector: 'ledge-editor', 13 | templateUrl: './ledge-editor.component.html', 14 | styleUrls: ['./ledge-editor.component.scss'], 15 | }) 16 | export class LedgeEditorComponent implements OnInit, OnDestroy { 17 | content = mdData.default; 18 | 19 | @ViewChild('split', { static: false }) split: SplitComponent; 20 | @ViewChild('area1', { static: false }) area1: SplitAreaDirective; 21 | @ViewChild('area2', { static: false }) area2: SplitAreaDirective; 22 | 23 | direction = 'horizontal'; 24 | sizes = { 25 | percent: { 26 | area1: 30, 27 | area2: 70, 28 | }, 29 | pixel: { 30 | area1: 120, 31 | area2: '*', 32 | area3: 160, 33 | }, 34 | }; 35 | aceOptions = { 36 | enableBasicAutocompletion: true, 37 | enableSnippets: true, 38 | enableLiveAutocompletion: true, 39 | }; 40 | acEditor: any; 41 | themeSelected = 'github'; 42 | term$ = new Subject(); 43 | private searchSubscription: Subscription; 44 | 45 | constructor() { 46 | this.searchSubscription = this.term$ 47 | .pipe( 48 | debounceTime(500), 49 | distinctUntilChanged(), 50 | switchMap((term) => { 51 | this.content = term; 52 | return EMPTY; 53 | }) 54 | ) 55 | .subscribe(); 56 | } 57 | 58 | ngOnInit(): void {} 59 | 60 | ngOnDestroy(): void { 61 | if (this.searchSubscription) { 62 | this.searchSubscription.unsubscribe(); 63 | this.searchSubscription = null; 64 | } 65 | } 66 | 67 | dragEnd(unit, { sizes }) { 68 | if (unit === 'percent') { 69 | this.sizes.percent.area1 = sizes[0]; 70 | this.sizes.percent.area2 = sizes[1]; 71 | } else if (unit === 'pixel') { 72 | this.sizes.pixel.area1 = sizes[0]; 73 | this.sizes.pixel.area2 = sizes[1]; 74 | this.sizes.pixel.area3 = sizes[2]; 75 | } 76 | } 77 | 78 | onAceChange($event) { 79 | this.term$.next($event); 80 | } 81 | 82 | editorRef($event) { 83 | this.acEditor = $event; 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /src/app/ledge-editor/ledge-editor.module.ts: -------------------------------------------------------------------------------- 1 | import { CommonModule } from '@angular/common'; 2 | import { NgModule } from '@angular/core'; 3 | import { FormsModule } from '@angular/forms'; 4 | import { RouterModule } from '@angular/router'; 5 | import { LedgeRenderModule } from '@ledge-framework/render'; 6 | import { AngularSplitModule } from 'angular-split'; 7 | import { AceEditorModule } from 'ngx-ace-tern'; 8 | 9 | import { LedgeEditorComponent } from './ledge-editor.component'; 10 | 11 | @NgModule({ 12 | declarations: [LedgeEditorComponent], 13 | imports: [ 14 | CommonModule, 15 | FormsModule, 16 | LedgeRenderModule, 17 | AceEditorModule, 18 | AngularSplitModule.forRoot(), 19 | RouterModule.forChild([{ path: '', component: LedgeEditorComponent }]), 20 | ], 21 | }) 22 | export class LedgeEditorModule {} 23 | -------------------------------------------------------------------------------- /src/app/ledge/ledge.component.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /src/app/ledge/ledge.component.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ledge-framework/engine/66b893282ed856ee6db29130e1144eb4e4d415fc/src/app/ledge/ledge.component.scss -------------------------------------------------------------------------------- /src/app/ledge/ledge.component.spec.ts: -------------------------------------------------------------------------------- 1 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 2 | 3 | import { LedgeComponent } from './ledge.component'; 4 | 5 | describe('LedgeComponent', () => { 6 | let component: LedgeComponent; 7 | let fixture: ComponentFixture; 8 | 9 | beforeEach(async(() => { 10 | TestBed.configureTestingModule({ 11 | declarations: [ LedgeComponent ] 12 | }) 13 | .compileComponents(); 14 | })); 15 | 16 | beforeEach(() => { 17 | fixture = TestBed.createComponent(LedgeComponent); 18 | component = fixture.componentInstance; 19 | fixture.detectChanges(); 20 | }); 21 | 22 | it('should create', () => { 23 | expect(component).toBeTruthy(); 24 | }); 25 | }); 26 | -------------------------------------------------------------------------------- /src/app/ledge/ledge.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, Input, OnChanges, OnInit, SimpleChanges } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'ledge-theme', 5 | templateUrl: './ledge.component.html', 6 | styleUrls: ['./ledge.component.scss'] 7 | }) 8 | export class LedgeComponent implements OnInit, OnChanges { 9 | @Input() content; 10 | 11 | constructor() { 12 | } 13 | 14 | ngOnInit(): void { 15 | 16 | } 17 | 18 | ngOnChanges(changes: SimpleChanges) { 19 | if (changes) { 20 | const {content = null} = changes; 21 | this.content = content?.currentValue || null; 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/assets/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ledge-framework/engine/66b893282ed856ee6db29130e1144eb4e4d415fc/src/assets/.gitkeep -------------------------------------------------------------------------------- /src/environments/environment.prod.ts: -------------------------------------------------------------------------------- 1 | export const environment = { 2 | production: true 3 | }; 4 | -------------------------------------------------------------------------------- /src/environments/environment.ts: -------------------------------------------------------------------------------- 1 | // This file can be replaced during build by using the `fileReplacements` array. 2 | // `ng build --prod` replaces `environment.ts` with `environment.prod.ts`. 3 | // The list of file replacements can be found in `angular.json`. 4 | 5 | export const environment = { 6 | production: false 7 | }; 8 | 9 | /* 10 | * For easier debugging in development mode, you can import the following file 11 | * to ignore zone related error stack frames such as `zone.run`, `zoneDelegate.invokeTask`. 12 | * 13 | * This import should be commented out in production mode because it will have a negative impact 14 | * on performance if an error is thrown. 15 | */ 16 | // import 'zone.js/dist/zone-error'; // Included with Angular CLI. 17 | -------------------------------------------------------------------------------- /src/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ledge-framework/engine/66b893282ed856ee6db29130e1144eb4e4d415fc/src/favicon.ico -------------------------------------------------------------------------------- /src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Ledge 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /src/main.ts: -------------------------------------------------------------------------------- 1 | import { enableProdMode } from '@angular/core'; 2 | import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; 3 | 4 | import { AppModule } from './app/app.module'; 5 | import { environment } from './environments/environment'; 6 | 7 | if (environment.production) { 8 | enableProdMode(); 9 | } 10 | 11 | platformBrowserDynamic().bootstrapModule(AppModule) 12 | .catch(err => console.error(err)); 13 | -------------------------------------------------------------------------------- /src/polyfills.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * This file includes polyfills needed by Angular and is loaded before the app. 3 | * You can add your own extra polyfills to this file. 4 | * 5 | * This file is divided into 2 sections: 6 | * 1. Browser polyfills. These are applied before loading ZoneJS and are sorted by browsers. 7 | * 2. Application imports. Files imported after ZoneJS that should be loaded before your main 8 | * file. 9 | * 10 | * The current setup is for so-called "evergreen" browsers; the last versions of browsers that 11 | * automatically update themselves. This includes Safari >= 10, Chrome >= 55 (including Opera), 12 | * Edge >= 13 on the desktop, and iOS 10 and Chrome on mobile. 13 | * 14 | * Learn more in https://angular.io/guide/browser-support 15 | */ 16 | 17 | /*************************************************************************************************** 18 | * BROWSER POLYFILLS 19 | */ 20 | 21 | /** IE10 and IE11 requires the following for NgClass support on SVG elements */ 22 | // import 'classlist.js'; // Run `npm install --save classlist.js`. 23 | 24 | /** 25 | * Web Animations `@angular/platform-browser/animations` 26 | * Only required if AnimationBuilder is used within the application and using IE/Edge or Safari. 27 | * Standard animation support in Angular DOES NOT require any polyfills (as of Angular 6.0). 28 | */ 29 | // import 'web-animations-js'; // Run `npm install --save web-animations-js`. 30 | 31 | /** 32 | * By default, zone.js will patch all possible macroTask and DomEvents 33 | * user can disable parts of macroTask/DomEvents patch by setting following flags 34 | * because those flags need to be set before `zone.js` being loaded, and webpack 35 | * will put import in the top of bundle, so user need to create a separate file 36 | * in this directory (for example: zone-flags.ts), and put the following flags 37 | * into that file, and then add the following code before importing zone.js. 38 | * import './zone-flags'; 39 | * 40 | * The flags allowed in zone-flags.ts are listed here. 41 | * 42 | * The following flags will work for all browsers. 43 | * 44 | * (window as any).__Zone_disable_requestAnimationFrame = true; // disable patch requestAnimationFrame 45 | * (window as any).__Zone_disable_on_property = true; // disable patch onProperty such as onclick 46 | * (window as any).__zone_symbol__UNPATCHED_EVENTS = ['scroll', 'mousemove']; // disable patch specified eventNames 47 | * 48 | * in IE/Edge developer tools, the addEventListener will also be wrapped by zone.js 49 | * with the following flag, it will bypass `zone.js` patch for IE/Edge 50 | * 51 | * (window as any).__Zone_enable_cross_context_check = true; 52 | * 53 | */ 54 | 55 | /*************************************************************************************************** 56 | * Zone JS is required by default for Angular itself. 57 | */ 58 | import 'zone.js/dist/zone'; // Included with Angular CLI. 59 | 60 | 61 | /*************************************************************************************************** 62 | * APPLICATION IMPORTS 63 | */ 64 | import 'document-register-element'; 65 | -------------------------------------------------------------------------------- /src/styles.scss: -------------------------------------------------------------------------------- 1 | @import "~@ledge-framework/render/prebuild-theme/index.css"; 2 | -------------------------------------------------------------------------------- /src/test.ts: -------------------------------------------------------------------------------- 1 | // This file is required by karma.conf.js and loads recursively all the .spec and framework files 2 | 3 | import 'zone.js/dist/zone-testing'; 4 | import { getTestBed } from '@angular/core/testing'; 5 | import { 6 | BrowserDynamicTestingModule, 7 | platformBrowserDynamicTesting 8 | } from '@angular/platform-browser-dynamic/testing'; 9 | 10 | declare const require: { 11 | context(path: string, deep?: boolean, filter?: RegExp): { 12 | keys(): string[]; 13 | (id: string): T; 14 | }; 15 | }; 16 | 17 | // First, initialize the Angular testing environment. 18 | getTestBed().initTestEnvironment( 19 | BrowserDynamicTestingModule, 20 | platformBrowserDynamicTesting() 21 | ); 22 | // Then we find all the tests. 23 | const context = require.context('./', true, /\.spec\.ts$/); 24 | // And load the modules. 25 | context.keys().map(context); 26 | -------------------------------------------------------------------------------- /stories/9qPuTQRMg-support-web-components.feature: -------------------------------------------------------------------------------- 1 | # id: 9qPuTQRMg 2 | # startDate: 2020-05-19T15:07:31Z 3 | # endDate: 2020-05-19T15:10:48Z 4 | # priority: 5 | # status: doing 6 | # author: fdhuang 7 | # title: support web components 8 | # language: zh-CN 9 | @math 10 | 功能:support web components 11 | 12 | 场景: Web Components 对于 Jekyll 的支持 13 | 假设: 14 | 当: 一个开发者使用 ledge framework 时 15 | 并且: 用户使用的是 Jekyll 主题时 16 | 那么: 用户应该可以直接通过 WC 组件引入 17 | -------------------------------------------------------------------------------- /tsconfig.app.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "./out-tsc/app", 5 | "types": [] 6 | }, 7 | "files": [ 8 | "src/main.ts", 9 | "src/polyfills.ts" 10 | ], 11 | "include": [ 12 | "src/**/*.d.ts" 13 | ] 14 | } 15 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compileOnSave": false, 3 | "compilerOptions": { 4 | "baseUrl": "./", 5 | "outDir": "./dist/out-tsc", 6 | "sourceMap": true, 7 | "declaration": false, 8 | "downlevelIteration": true, 9 | "experimentalDecorators": true, 10 | "module": "esnext", 11 | "moduleResolution": "node", 12 | "importHelpers": true, 13 | "target": "es2015", 14 | "typeRoots": [ 15 | "node_modules/@types" 16 | ], 17 | "lib": [ 18 | "es2018", 19 | "dom" 20 | ] 21 | }, 22 | "angularCompilerOptions": { 23 | "fullTemplateTypeCheck": true, 24 | "strictInjectionParameters": true 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "./out-tsc/spec", 5 | "types": [ 6 | "jasmine", 7 | "node" 8 | ] 9 | }, 10 | "files": [ 11 | "src/test.ts", 12 | "src/polyfills.ts" 13 | ], 14 | "include": [ 15 | "src/**/*.spec.ts", 16 | "src/**/*.d.ts" 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "tslint:recommended", 3 | "rules": { 4 | "array-type": false, 5 | "arrow-parens": false, 6 | "deprecation": { 7 | "severity": "warning" 8 | }, 9 | "component-class-suffix": true, 10 | "contextual-lifecycle": true, 11 | "directive-class-suffix": true, 12 | "directive-selector": [ 13 | true, 14 | "attribute", 15 | "app", 16 | "camelCase", 17 | "ledge" 18 | ], 19 | "component-selector": [ 20 | true, 21 | "element", 22 | "app", 23 | "kebab-case", 24 | "ledge" 25 | ], 26 | "import-blacklist": [ 27 | true, 28 | "rxjs/Rx" 29 | ], 30 | "interface-name": false, 31 | "max-classes-per-file": false, 32 | "max-line-length": [ 33 | true, 34 | 140 35 | ], 36 | "member-access": false, 37 | "member-ordering": [ 38 | true, 39 | { 40 | "order": [ 41 | "static-field", 42 | "instance-field", 43 | "static-method", 44 | "instance-method" 45 | ] 46 | } 47 | ], 48 | "no-consecutive-blank-lines": false, 49 | "no-console": [ 50 | true, 51 | "debug", 52 | "info", 53 | "time", 54 | "timeEnd", 55 | "trace" 56 | ], 57 | "no-empty": false, 58 | "no-inferrable-types": [ 59 | true, 60 | "ignore-params" 61 | ], 62 | "no-non-null-assertion": true, 63 | "no-redundant-jsdoc": true, 64 | "no-switch-case-fall-through": true, 65 | "no-var-requires": false, 66 | "object-literal-key-quotes": [ 67 | true, 68 | "as-needed" 69 | ], 70 | "object-literal-sort-keys": false, 71 | "ordered-imports": false, 72 | "quotemark": [ 73 | true, 74 | "single" 75 | ], 76 | "trailing-comma": false, 77 | "no-conflicting-lifecycle": true, 78 | "no-host-metadata-property": true, 79 | "no-input-rename": true, 80 | "no-inputs-metadata-property": true, 81 | "no-output-native": true, 82 | "no-output-on-prefix": true, 83 | "no-output-rename": true, 84 | "no-outputs-metadata-property": true, 85 | "template-banana-in-box": true, 86 | "template-no-negated-async": true, 87 | "use-lifecycle-interface": true, 88 | "use-pipe-transform-interface": true 89 | }, 90 | "rulesDirectory": [ 91 | "codelyzer" 92 | ] 93 | } 94 | --------------------------------------------------------------------------------