├── .dockerignore ├── .editorconfig ├── .github └── FUNDING.yml ├── .gitignore ├── Dockerfile ├── Makefile ├── README.md ├── docs └── assets │ ├── macos-dark.png │ └── macos-light.png ├── heroku.yml ├── lerna.json ├── package.json └── packages ├── angular-test ├── .gitignore ├── README.md ├── angular.json ├── package-lock.json ├── package.json ├── src │ ├── .browserslistrc │ ├── app │ │ ├── app-routing.module.ts │ │ ├── app.component.html │ │ ├── app.component.scss │ │ ├── app.component.ts │ │ ├── app.module.ts │ │ ├── components │ │ │ ├── api-doc.component.scss │ │ │ └── doc.module.ts │ │ ├── decorators.ts │ │ ├── docu │ │ │ ├── docu.module.ts │ │ │ ├── icons.component.scss │ │ │ ├── icons.component.ts │ │ │ └── view-debugger.component.ts │ │ └── windows │ │ │ ├── first-window.component.ts │ │ │ └── second-window.component.ts │ ├── assets │ │ ├── .gitkeep │ │ ├── bg.png │ │ └── docs │ │ │ ├── app.md │ │ │ ├── button-group.md │ │ │ ├── button.md │ │ │ ├── checkbox.md │ │ │ ├── dialog.md │ │ │ ├── emoji.md │ │ │ ├── form.md │ │ │ ├── getting-started.md │ │ │ ├── icon.md │ │ │ ├── indicator.md │ │ │ ├── input.md │ │ │ ├── list.md │ │ │ ├── menu.md │ │ │ ├── radiobox.md │ │ │ ├── select.md │ │ │ ├── slider.md │ │ │ ├── table.md │ │ │ ├── welcome.md │ │ │ ├── window-manager.md │ │ │ ├── window-manager.ts │ │ │ ├── window-sidebar.md │ │ │ ├── window-toolbar.md │ │ │ └── window.md │ ├── electron.ts │ ├── environments │ │ ├── environment.prod.ts │ │ └── environment.ts │ ├── favicon.ico │ ├── index.html │ ├── karma.conf.js │ ├── main.ts │ ├── polyfills.ts │ ├── styles.scss │ ├── test.ts │ ├── tsconfig.app.json │ ├── tsconfig.spec.json │ └── tslint.json ├── tsconfig.json ├── tslint.json └── webpack.electron.js └── native-ui ├── .npmignore ├── angular.json ├── create-font.ts ├── emoji-map.ts ├── karma.conf.js ├── ng-package.json ├── package-lock.json ├── package.json ├── preload.js ├── src ├── assets │ ├── UIElements.sketch │ ├── docs.json │ ├── fonts │ │ ├── icon-names.json │ │ ├── ui-icons.svg │ │ ├── ui-icons.ttf │ │ └── ui-icons.woff │ ├── icons.sketch │ └── icons │ │ ├── 15_text-format-align-center.svg │ │ ├── 15_text-format-align-left.svg │ │ ├── 15_text-format-align-right.svg │ │ ├── 15_text-format-bold.svg │ │ ├── 15_text-format-bullets.svg │ │ ├── 15_text-format-code.svg │ │ ├── 15_text-format-indent.svg │ │ ├── 15_text-format-italic.svg │ │ ├── 15_text-format-strikethrough.svg │ │ ├── 15_text-format-underline.svg │ │ ├── 15_text-format-unindent.svg │ │ ├── add.svg │ │ ├── archive.svg │ │ ├── arrow-small-down.svg │ │ ├── arrow-small-left.svg │ │ ├── arrow-small-right.svg │ │ ├── arrow-small-up.svg │ │ ├── arrow.svg │ │ ├── arrow_down.svg │ │ ├── arrow_up.svg │ │ ├── arrows.svg │ │ ├── check.svg │ │ ├── clear.svg │ │ ├── color-theme.svg │ │ ├── comment.svg │ │ ├── compare.svg │ │ ├── download.svg │ │ ├── drag.svg │ │ ├── edit.svg │ │ ├── envelop.svg │ │ ├── eye.svg │ │ ├── filter.svg │ │ ├── flag.svg │ │ ├── folder.svg │ │ ├── garbage.svg │ │ ├── gnome_close.svg │ │ ├── gnome_maximize.svg │ │ ├── gnome_minimize.svg │ │ ├── help.svg │ │ ├── list.svg │ │ ├── play.svg │ │ ├── record.svg │ │ ├── remove.svg │ │ ├── search.svg │ │ ├── share.svg │ │ ├── star.svg │ │ ├── toggle-sidebar.svg │ │ ├── toggle_bottom.svg │ │ ├── toggle_left.svg │ │ ├── toggle_right.svg │ │ ├── toggle_sidebar.svg │ │ ├── triangle_down.svg │ │ ├── triangle_right.svg │ │ └── zoom-to-fit.svg ├── components │ ├── app │ │ ├── cd-counter.component.ts │ │ ├── dui-responsive.directive.ts │ │ ├── dui-view.directive.ts │ │ ├── index.ts │ │ ├── menu.component.ts │ │ ├── pipes.ts │ │ ├── token.ts │ │ └── utils.ts │ ├── button │ │ ├── button-group.component.scss │ │ ├── button-groups.component.scss │ │ ├── button.component.scss │ │ ├── button.component.ts │ │ ├── dropdow.component.scss │ │ ├── dropdown-item.component.scss │ │ ├── dropdown.component.ts │ │ ├── index.ts │ │ ├── overlay-arrow-dark.svg │ │ ├── overlay-arrow.svg │ │ ├── tab-button.component.scss │ │ └── tab-button.component.ts │ ├── checkbox │ │ ├── checkbox.component.scss │ │ ├── checkbox.component.ts │ │ └── index.ts │ ├── core │ │ ├── index.ts │ │ └── render-component.directive.ts │ ├── dialog │ │ ├── dialog-error.component.scss │ │ ├── dialog-wrapper.component.scss │ │ ├── dialog.component.ts │ │ ├── dialog.ts │ │ ├── index.ts │ │ └── progress-dialog.component.ts │ ├── emoji │ │ ├── emoji-dropdown.component.scss │ │ ├── emoji-dropdown.component.ts │ │ ├── emoji.component.scss │ │ ├── emoji.component.ts │ │ ├── emoji_apple_32.png │ │ ├── emoji_pretty.json │ │ ├── emojis.ts │ │ └── index.ts │ ├── form │ │ ├── form-row.component.scss │ │ ├── form.component.scss │ │ ├── form.component.ts │ │ └── index.ts │ ├── icon │ │ ├── icon.component.ts │ │ └── index.ts │ ├── indicator │ │ ├── index.ts │ │ ├── indicator.component.scss │ │ └── indicator.component.ts │ ├── input │ │ ├── index.ts │ │ ├── input.component.scss │ │ └── input.component.ts │ ├── list │ │ ├── index.ts │ │ ├── list-item.component.scss │ │ ├── list-title.component.scss │ │ ├── list.component.scss │ │ └── list.component.ts │ ├── radiobox │ │ ├── index.ts │ │ ├── radiobox.component.scss │ │ └── radiobox.component.ts │ ├── select │ │ ├── index.ts │ │ ├── selectbox.component.scss │ │ └── selectbox.component.ts │ ├── slider │ │ ├── index.ts │ │ ├── slider.component.scss │ │ └── slider.component.ts │ ├── splitter │ │ ├── index.ts │ │ ├── splitter.component.scss │ │ └── splitter.component.ts │ ├── table │ │ ├── index.ts │ │ ├── table.component.scss │ │ └── table.component.ts │ └── window │ │ ├── external-window.component.ts │ │ ├── external-window.ts │ │ ├── index.ts │ │ ├── window-content.component.scss │ │ ├── window-content.component.ts │ │ ├── window-footer.component.scss │ │ ├── window-footer.component.ts │ │ ├── window-frame.component.scss │ │ ├── window-header.component.scss │ │ ├── window-header.component.ts │ │ ├── window-menu.ts │ │ ├── window-sidebar.component.scss │ │ ├── window-sidebar.component.ts │ │ ├── window-state.ts │ │ ├── window.component.scss │ │ └── window.component.ts ├── core │ ├── form.ts │ └── utils.ts ├── index.ts └── scss │ ├── all.scss │ ├── icon.scss │ ├── mixins.scss │ └── reset.scss ├── test └── test.ts ├── tsconfig.json ├── tsconfig.lib.json ├── tsconfig.prod.json ├── tsconfig.spec.json ├── tslint.json └── webpack.config.js /.dockerignore: -------------------------------------------------------------------------------- 1 | packages/*/node_modules 2 | packages/angular-test/dist 3 | Dockerfile 4 | .dockerignore 5 | .git 6 | .idea 7 | Makefile 8 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # Editor configuration, see https://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | charset = utf-8 6 | indent_style = space 7 | indent_size = 4 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | 11 | [*.json] 12 | indent_size = 2 13 | 14 | [Makefile] 15 | indent_style = tab 16 | 17 | [*.md] 18 | max_line_length = off 19 | trim_trailing_whitespace = false 20 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: marcj 2 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .idea 3 | packages/native-ui/dist 4 | packages/native-ui/bin/create-font* 5 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM node:alpine 2 | 3 | RUN npm config set unsafe-perm true 4 | RUN npm i -g lerna npm-local-development 5 | RUN apk --no-cache add git 6 | 7 | ADD package.json /lib/package.json 8 | ADD lerna.json /lib/lerna.json 9 | ADD packages/native-ui/package.json /lib/packages/native-ui/package.json 10 | #ADD packages/native-ui/package-lock.json /lib/packages/native-ui/package-lock.json 11 | 12 | ADD packages/angular-test/package.json /lib/packages/angular-test/package.json 13 | ADD packages/angular-test/package-lock.json /lib/packages/angular-test/package-lock.json 14 | 15 | RUN cd /lib && npm run bootstrap 16 | 17 | ADD . /lib 18 | RUN cd /lib && npm-local-development --no-watcher 19 | RUN cd /lib/packages/native-ui && npm run docs 20 | RUN cd /lib/packages/angular-test && ./node_modules/.bin/ng build --prod 21 | 22 | FROM nginx:alpine 23 | 24 | ENV PORT=8080 25 | 26 | COPY --from=0 /lib/packages/angular-test/dist/angular-desktop-ui /usr/share/nginx/html 27 | 28 | RUN echo "gzip on; \ 29 | gzip_buffers 16 8k; \ 30 | gzip_comp_level 1; \ 31 | gzip_http_version 1.1; \ 32 | gzip_min_length 10; \ 33 | gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript image/x-icon application/vnd.ms-fontobject font/opentype application/x-font-ttf; \ 34 | gzip_vary on; \ 35 | gzip_proxied any; # Compression for all requests. \ 36 | ## No need for regexps. See \ 37 | ## http://wiki.nginx.org/NginxHttpGzipModule#gzip_disable \ 38 | gzip_disable msie6;" > /etc/nginx/conf.d/gzip.conf 39 | 40 | RUN sed -i -e "s/index.htm;/;\n try_files \$uri \$uri\/ \/index.html;/g" /etc/nginx/conf.d/default.conf 41 | 42 | CMD sed -i -e "s/listen 80/listen $PORT/g" /etc/nginx/conf.d/default.conf && nginx -g 'daemon off;' 43 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | docker-image: 2 | docker build -t angular-desktop-ui/web . 3 | 4 | publish: 5 | heroku container:login 6 | heroku container:push web 7 | heroku container:release web 8 | -------------------------------------------------------------------------------- /docs/assets/macos-dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcj/angular-desktop-ui/71f9435eeed6fb23437b45d7a57d9adba5bc93b0/docs/assets/macos-dark.png -------------------------------------------------------------------------------- /docs/assets/macos-light.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcj/angular-desktop-ui/71f9435eeed6fb23437b45d7a57d9adba5bc93b0/docs/assets/macos-light.png -------------------------------------------------------------------------------- /heroku.yml: -------------------------------------------------------------------------------- 1 | build: 2 | docker: 3 | web: Dockerfile 4 | -------------------------------------------------------------------------------- /lerna.json: -------------------------------------------------------------------------------- 1 | { 2 | "packages": [ 3 | "packages/*" 4 | ], 5 | "version": "0.4.2" 6 | } 7 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "root", 3 | "author": "Marc J. Schmidt ", 4 | "license": "MIT", 5 | "scripts": { 6 | "test": "jest --coverage", 7 | "bootstrap": "lerna bootstrap --no-ci --nohoist \\*", 8 | "publish": "lerna publish" 9 | }, 10 | "devDependencies": { 11 | "@types/jest": "^23.3.9", 12 | "@types/node": "^10.12.5", 13 | "coveralls": "^3.0.2", 14 | "jest": "^23.6.0", 15 | "jest-extended": "^0.11.0", 16 | "lerna": "^3.4.3", 17 | "ts-jest": "^23.10.4", 18 | "ts-node": "^7.0.1", 19 | "tslint": "^5.9.1" 20 | }, 21 | "engines": { 22 | "node": ">= 8.9.0" 23 | }, 24 | "jest": { 25 | "testURL": "http://localhost/", 26 | "moduleFileExtensions": [ 27 | "ts", 28 | "tsx", 29 | "js" 30 | ], 31 | "collectCoverageFrom": [ 32 | "**/*.{ts}", 33 | "!**/node_modules/**", 34 | "!**/lib/**/*", 35 | "!**/*.d.ts" 36 | ], 37 | "transform": { 38 | "^.+\\.(ts|tsx)$": "ts-jest" 39 | }, 40 | "testMatch": [ 41 | "**/*.spec.ts" 42 | ], 43 | "setupTestFrameworkScriptFile": "jest-extended" 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /packages/angular-test/.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 | 8 | # dependencies 9 | /node_modules 10 | 11 | # profiling files 12 | chrome-profiler-events.json 13 | speed-measure-plugin.json 14 | 15 | # IDEs and editors 16 | /.idea 17 | .project 18 | .classpath 19 | .c9/ 20 | *.launch 21 | .settings/ 22 | *.sublime-workspace 23 | 24 | # IDE - VSCode 25 | .vscode/* 26 | !.vscode/settings.json 27 | !.vscode/tasks.json 28 | !.vscode/launch.json 29 | !.vscode/extensions.json 30 | 31 | # misc 32 | /.sass-cache 33 | /connect.lock 34 | /coverage 35 | /libpeerconnection.log 36 | npm-debug.log 37 | yarn-error.log 38 | testem.log 39 | /typings 40 | 41 | # System Files 42 | .DS_Store 43 | Thumbs.db 44 | -------------------------------------------------------------------------------- /packages/angular-test/README.md: -------------------------------------------------------------------------------- 1 | # IconfontGenerator 2 | 3 | This project was generated with [Angular CLI](https://github.com/angular/angular-cli) version 7.1.0. 4 | 5 | ## Development server 6 | 7 | Run `ng serve` for a dev server. Navigate to `http://localhost:4200/`. The app will automatically reload if you change any of the source files. 8 | 9 | ## Code scaffolding 10 | 11 | Run `ng generate component component-name` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module`. 12 | 13 | ## Build 14 | 15 | Run `ng build` to build the project. The build artifacts will be stored in the `dist/` directory. Use the `--prod` flag for a production build. 16 | 17 | ## Running unit tests 18 | 19 | Run `ng test` to execute the unit tests via [Karma](https://karma-runner.github.io). 20 | 21 | ## Running end-to-end tests 22 | 23 | Run `ng e2e` to execute the end-to-end tests via [Protractor](http://www.protractortest.org/). 24 | 25 | ## Further help 26 | 27 | To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI README](https://github.com/angular/angular-cli/blob/master/README.md). 28 | -------------------------------------------------------------------------------- /packages/angular-test/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "angular-desktop-ui", 3 | "version": "0.4.2", 4 | "scripts": { 5 | "ng": "ng", 6 | "start": "ng serve", 7 | "build": "ng build", 8 | "watch": "ng build --watch", 9 | "test": "ng test", 10 | "lint": "ng lint", 11 | "e2e": "ng e2e", 12 | "electron:build": "webpack-cli --mode development --progress --config webpack.electron.js", 13 | "electron:watch": "webpack-cli --mode development --watch --progress --config webpack.electron.js", 14 | "electron:start": "electron .", 15 | "electron:local": "npm run build:prod && electron .", 16 | "electron:linux": "npm run build:prod && npx electron-builder build --linux", 17 | "electron:windows": "npm run build:prod && npx electron-builder build --windows", 18 | "electron:mac": "npm run build:prod && npx electron-builder build --mac" 19 | }, 20 | "bin": "dist/electron/electron.js", 21 | "main": "dist/electron/electron.js", 22 | "private": true, 23 | "sideEffects": false, 24 | "dependencies": { 25 | "@angular/animations": "^11.0.0", 26 | "@angular/cdk": "^9.0.0", 27 | "@angular/common": "^11.0.0", 28 | "@angular/compiler": "^11.0.0", 29 | "@angular/core": "^11.0.0", 30 | "@angular/forms": "^11.0.0", 31 | "@angular/platform-browser": "^11.0.0", 32 | "@angular/platform-browser-dynamic": "^11.0.0", 33 | "@angular/router": "^11.0.0", 34 | "@marcj/estdlib": "^0.1.17", 35 | "buffer": "^5.4.3", 36 | "core-js": "^2.5.4", 37 | "electron": "^7.1.9", 38 | "highlight.js": "^9.15.6", 39 | "npm-local-development": "^0.3.1", 40 | "rxjs": "~6.5.4", 41 | "showdown": "^1.9.0", 42 | "ts-node": "^8.0.2", 43 | "tslib": "^2.0.0", 44 | "zone.js": "~0.10.3" 45 | }, 46 | "browserslist": [ 47 | "last 2 Chrome versions" 48 | ], 49 | "devDependencies": { 50 | "@angular-devkit/build-angular": "^0.1100.1", 51 | "@angular/cli": "^11.0.1", 52 | "@angular/compiler-cli": "^11.0.0", 53 | "@angular/language-service": "^11.0.0", 54 | "@babel/core": "^7.1.6", 55 | "@babel/preset-env": "^7.1.6", 56 | "@marcj/angular-desktop-ui": "^0.4.2", 57 | "@types/highlight.js": "^9.12.3", 58 | "@types/jasmine": "~3.6.0", 59 | "@types/jasminewd2": "~2.0.3", 60 | "@types/node": "^12.11.1", 61 | "@types/showdown": "^1.9.2", 62 | "babel-loader": "^8.0.4", 63 | "codelyzer": "^6.0.0", 64 | "jasmine-core": "~3.6.0", 65 | "jasmine-spec-reporter": "~5.0.0", 66 | "karma": "~5.0.0", 67 | "karma-chrome-launcher": "~3.1.0", 68 | "karma-coverage-istanbul-reporter": "~3.0.2", 69 | "karma-jasmine": "~4.0.0", 70 | "karma-jasmine-html-reporter": "^1.5.0", 71 | "protractor": "~7.0.0", 72 | "ts-loader": "^5.3.0", 73 | "tslint": "~6.1.0", 74 | "typescript": "^4.0.5", 75 | "webpack": "^4.29.4", 76 | "webpack-cli": "^3.1.2", 77 | "webpack-visualizer-plugin": "^0.1.11" 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /packages/angular-test/src/.browserslistrc: -------------------------------------------------------------------------------- 1 | # This file is currently used by autoprefixer to adjust CSS to support the below specified browsers 2 | # For additional information regarding the format and rule options, please see: 3 | # https://github.com/browserslist/browserslist#queries 4 | # 5 | # For IE 9-11 support, please remove 'not' from the last line of the file and adjust as needed 6 | 7 | > 0.5% 8 | last 2 versions 9 | Firefox ESR 10 | not dead 11 | not IE 9-11 -------------------------------------------------------------------------------- /packages/angular-test/src/app/app-routing.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { Routes, RouterModule } from '@angular/router'; 3 | import {MarkdownDocComponent} from './components/doc.module'; 4 | 5 | const routes: Routes = [ 6 | {path: '', redirectTo: 'doc/welcome', pathMatch: 'full'}, 7 | {path: 'doc/:id', component: MarkdownDocComponent}, 8 | ]; 9 | 10 | @NgModule({ 11 | imports: [RouterModule.forRoot(routes, { relativeLinkResolution: 'legacy' })], 12 | exports: [RouterModule] 13 | }) 14 | export class AppRoutingModule { } 15 | -------------------------------------------------------------------------------- /packages/angular-test/src/app/app.component.scss: -------------------------------------------------------------------------------- 1 | ::ng-deep body:not(.electron) { 2 | background-image: url(../assets/bg.png); 3 | 4 | dui-window.main { 5 | margin: 50px; 6 | height: calc(100% - 100px); 7 | width: calc(100% - 100px); 8 | border-radius: 4px; 9 | overflow: hidden; 10 | background: var(--dui-window-content-bg-trans); 11 | } 12 | } 13 | 14 | ::ng-deep body.platform-web { 15 | dui-window.main { 16 | margin: 0; 17 | border: 0; 18 | height: 100%; 19 | width: 100%; 20 | border-radius: 0; 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /packages/angular-test/src/app/app.component.ts: -------------------------------------------------------------------------------- 1 | import {Component} from '@angular/core'; 2 | import {DuiApp, DuiDialog} from "@marcj/angular-desktop-ui"; 3 | 4 | @Component({ 5 | selector: 'app-root', 6 | templateUrl: './app.component.html', 7 | styleUrls: ['./app.component.scss'], 8 | }) 9 | export class AppComponent { 10 | public sidebarVisible = true; 11 | 12 | constructor( 13 | public duiApp: DuiApp, 14 | public dialog: DuiDialog, 15 | ) { 16 | this.duiApp.setPlatform('darwin'); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /packages/angular-test/src/app/app.module.ts: -------------------------------------------------------------------------------- 1 | import {BrowserModule} from '@angular/platform-browser'; 2 | import {NgModule} from '@angular/core'; 3 | import { 4 | DuiAppModule, 5 | DuiButtonModule, 6 | DuiCheckboxModule, 7 | DuiDialogModule, 8 | DuiEmojiModule, 9 | DuiFormComponent, 10 | DuiIconModule, 11 | DuiIndicatorModule, 12 | DuiInputModule, 13 | DuiListModule, 14 | DuiRadioboxModule, 15 | DuiSelectModule, 16 | DuiSliderModule, 17 | DuiTableModule, 18 | DuiWindowModule 19 | } from '@marcj/angular-desktop-ui'; 20 | 21 | import {AppRoutingModule} from './app-routing.module'; 22 | import {AppComponent} from './app.component'; 23 | import {HttpClientModule} from "@angular/common/http"; 24 | import {FormsModule, ReactiveFormsModule} from "@angular/forms"; 25 | import {DocModule} from "./components/doc.module"; 26 | import {DocuModule} from "./docu/docu.module"; 27 | import {SecondWindowComponent} from "./windows/second-window.component"; 28 | import {FirstWindowComponent} from "./windows/first-window.component"; 29 | import {WindowManager} from "../assets/docs/window-manager"; 30 | 31 | 32 | @NgModule({ 33 | declarations: [ 34 | AppComponent, 35 | FirstWindowComponent, 36 | SecondWindowComponent, 37 | WindowManager, 38 | ], 39 | imports: [ 40 | HttpClientModule, 41 | FormsModule, 42 | ReactiveFormsModule, 43 | BrowserModule, 44 | AppRoutingModule, 45 | 46 | DuiAppModule.forRoot(), 47 | DuiWindowModule.forRoot(), 48 | 49 | DuiCheckboxModule, 50 | DuiButtonModule, 51 | DuiInputModule, 52 | DuiFormComponent, 53 | DuiRadioboxModule, 54 | DuiSelectModule, 55 | DuiIconModule, 56 | DuiListModule, 57 | DuiTableModule, 58 | DuiButtonModule, 59 | DuiDialogModule, 60 | DuiEmojiModule, 61 | DuiSliderModule, 62 | DuiIndicatorModule, 63 | 64 | DocuModule, 65 | DocModule.forRoot(), 66 | ], 67 | entryComponents: [ 68 | ], 69 | providers: [], 70 | bootstrap: [AppComponent] 71 | }) 72 | export class AppModule { 73 | } 74 | 75 | DocModule.parent = AppModule; 76 | -------------------------------------------------------------------------------- /packages/angular-test/src/app/components/api-doc.component.scss: -------------------------------------------------------------------------------- 1 | :host { 2 | display: block; 3 | margin-top: 35px; 4 | margin-bottom: 35px; 5 | } 6 | 7 | .title { 8 | display: flex; 9 | margin-bottom: 10px; 10 | dui-input { 11 | margin-left: auto; 12 | } 13 | } 14 | 15 | p { 16 | color: gray; 17 | } 18 | 19 | table { 20 | width: 100%; 21 | table-layout: fixed; 22 | 23 | th { 24 | font-weight: 400; 25 | padding: 13px 32px; 26 | text-align: left; 27 | background: #f5f5f5; 28 | } 29 | 30 | td { 31 | font-weight: 400; 32 | padding: 8px 16px; 33 | border: 1px solid rgba(0,0,0,.03); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /packages/angular-test/src/app/decorators.ts: -------------------------------------------------------------------------------- 1 | 2 | export const RegisteredDocComponents: {[name: string]: any} = {}; 3 | 4 | export function RegisterDocu(name: string) { 5 | return function(target: any) { 6 | RegisteredDocComponents[name] = target; 7 | }; 8 | } 9 | -------------------------------------------------------------------------------- /packages/angular-test/src/app/docu/docu.module.ts: -------------------------------------------------------------------------------- 1 | import {NgModule} from "@angular/core"; 2 | import {CommonModule} from "@angular/common"; 3 | import {ViewDebuggerComponent} from "./view-debugger.component"; 4 | import {DuiAppModule, DuiIconModule, DuiInputModule} from "@marcj/angular-desktop-ui"; 5 | import {IconsComponent} from "./icons.component"; 6 | import {FormsModule} from "@angular/forms"; 7 | 8 | 9 | @NgModule({ 10 | declarations: [ 11 | ViewDebuggerComponent, 12 | IconsComponent 13 | ], 14 | exports: [ 15 | ViewDebuggerComponent, 16 | IconsComponent 17 | ], 18 | imports: [ 19 | CommonModule, 20 | FormsModule, 21 | DuiAppModule, 22 | DuiIconModule, 23 | DuiInputModule, 24 | ], 25 | providers: [], 26 | }) 27 | export class DocuModule { 28 | } 29 | -------------------------------------------------------------------------------- /packages/angular-test/src/app/docu/icons.component.scss: -------------------------------------------------------------------------------- 1 | .icons { 2 | margin-top: 10px; 3 | display: grid; 4 | grid-template-columns: repeat(auto-fit, minmax(200px , auto)); 5 | grid-column-gap: 10px; 6 | grid-row-gap: 10px; 7 | } 8 | 9 | .icon { 10 | display: flex; 11 | flex-direction: column; 12 | align-items: center; 13 | height: 50px; 14 | border: 1px solid var(--line-color-light); 15 | border-radius: 4px; 16 | text-align: center; 17 | padding: 5px; 18 | 19 | .name { 20 | white-space: nowrap; 21 | font-size: 11px; 22 | user-select: text; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /packages/angular-test/src/app/docu/icons.component.ts: -------------------------------------------------------------------------------- 1 | import {ChangeDetectorRef, Component, OnInit} from "@angular/core"; 2 | import {HttpClient} from "@angular/common/http"; 3 | 4 | @Component({ 5 | selector: 'icons-browser', 6 | template: ` 7 | 9 | 10 |
11 |
12 | 13 |
{{icon}}
14 |
15 |
16 | `, 17 | styleUrls: ['./icons.component.scss'] 18 | }) 19 | export class IconsComponent implements OnInit { 20 | public icons?: any; 21 | 22 | public query = ''; 23 | 24 | constructor( 25 | protected httpClient: HttpClient, 26 | public cd: ChangeDetectorRef 27 | ) { 28 | } 29 | 30 | filter(value: string[]) { 31 | if (!this.query) return value; 32 | 33 | return value.filter(v => v.indexOf(this.query) !== -1); 34 | } 35 | 36 | async ngOnInit(): Promise { 37 | if (this.icons === undefined) { 38 | this.icons = await this.httpClient.get('assets/fonts/icon-names.json').toPromise(); 39 | } 40 | 41 | this.cd.detectChanges(); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /packages/angular-test/src/app/docu/view-debugger.component.ts: -------------------------------------------------------------------------------- 1 | import {Viewable, ViewState} from "@marcj/angular-desktop-ui"; 2 | import {Component} from "@angular/core"; 3 | 4 | @Component({ 5 | selector: 'view-debugger', 6 | template: ` 7 | id={{viewState.id}}, attached={{viewState.attached|json}} 8 | 9 | 10 | `, 11 | styles: [` 12 | :host { 13 | display: block; 14 | margin: 5px; 15 | padding: 5px; 16 | border: 1px solid silver; 17 | display: block !important; 18 | } 19 | `] 20 | }) 21 | export class ViewDebuggerComponent implements Viewable { 22 | readonly viewState = new ViewState; 23 | } 24 | -------------------------------------------------------------------------------- /packages/angular-test/src/app/windows/first-window.component.ts: -------------------------------------------------------------------------------- 1 | import {Component} from "@angular/core"; 2 | import {DuiExternalWindow} from "@marcj/angular-desktop-ui"; 3 | import {SecondWindowComponent} from "./second-window.component"; 4 | 5 | @Component({ 6 | template: ` 7 | 8 | 9 | First window 10 | 11 | 12 |

Hi, what's up?

13 | Open third window 14 | Open dialog 15 | Confirm 16 | 17 | A 18 | B 19 | C 20 | 21 |
22 | 23 | This is a lovely little dialog. 24 | 25 | Close 26 | 27 | 28 |
29 | ` 30 | }) 31 | export class FirstWindowComponent { 32 | public select = 'a'; 33 | 34 | constructor(protected duiWindow: DuiExternalWindow) { 35 | } 36 | 37 | public openThird() { 38 | this.duiWindow.open(SecondWindowComponent, {}, {alwaysRaised: true}); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /packages/angular-test/src/app/windows/second-window.component.ts: -------------------------------------------------------------------------------- 1 | import {Component} from "@angular/core"; 2 | 3 | @Component({ 4 | template: ` 5 | 6 | 7 | Second window 8 | 9 | 10 |

I'm the second window. Nothing to see here

11 |
12 | 13 | 14 | Close 15 | 16 | 17 |
18 | ` 19 | }) 20 | export class SecondWindowComponent { 21 | } 22 | -------------------------------------------------------------------------------- /packages/angular-test/src/assets/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcj/angular-desktop-ui/71f9435eeed6fb23437b45d7a57d9adba5bc93b0/packages/angular-test/src/assets/.gitkeep -------------------------------------------------------------------------------- /packages/angular-test/src/assets/bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcj/angular-desktop-ui/71f9435eeed6fb23437b45d7a57d9adba5bc93b0/packages/angular-test/src/assets/bg.png -------------------------------------------------------------------------------- /packages/angular-test/src/assets/docs/app.md: -------------------------------------------------------------------------------- 1 |

App

2 | 3 | ```typescript 4 | import {DuiAppModule} from '@marcj/angular-desktop-ui'; 5 | ``` 6 | 7 | 8 |

duiView

9 | 10 | ```javascript 11 | //@angular 12 | return { 13 | tab: 'first', 14 | deep: false, 15 | dummy: false, 16 | } 17 | ``` 18 | 19 | ```html 20 | Dummy 21 | First 22 | First child 23 | Second 24 | Third 25 | 26 |
27 | result: (tab={{tab}}, deep={{deep}}) 28 | 29 | 30 | 31 | 32 | 33 |
34 | ``` 35 | -------------------------------------------------------------------------------- /packages/angular-test/src/assets/docs/button-group.md: -------------------------------------------------------------------------------- 1 |

Button group

2 | 3 | ```typescript 4 | import {DuiButtonModule} from '@marcj/angular-desktop-ui'; 5 | ``` 6 | 7 | ```html 8 |

9 | 10 | Cool 11 | Right 12 | Yes 13 | 14 |

15 | 16 |

17 | 18 | Cool 19 | Right 20 | Yes 21 | 22 |

23 | 24 |

25 | 26 | Cool 27 | Right 28 | Yes 29 | 30 |

31 | 32 |

33 | 34 | 35 | 36 | 37 |

38 |

39 | 40 | Split button 41 | 42 | 43 | 44 |

45 | Hi there! 46 | Thanks! 47 |
48 | 49 |

50 | ``` 51 | 52 | 53 | -------------------------------------------------------------------------------- /packages/angular-test/src/assets/docs/button.md: -------------------------------------------------------------------------------- 1 |

Button

2 | 3 | ```typescript 4 | import {DuiButtonModule} from '@marcj/angular-desktop-ui'; 5 | ``` 6 | 7 | 8 | ```javascript 9 | //@angular 10 | return {disabled: false} 11 | ``` 12 | 13 | ```html 14 |

15 | Default Button 16 |

17 | 18 |

19 | Active Button 20 |

21 | 22 |

23 | Textured button 24 |

25 | 26 |

27 | Square button
28 |

29 | 30 |

31 | 32 |

33 | 34 |

35 | 36 | Dropdown 37 | 38 | 39 |

40 | Hi there! 41 |
42 | 43 |

44 | 45 |

46 | 47 | Dropdown items 48 | 49 | 50 | Flag A 51 | Flag B 52 | Flag C 53 | 54 | Reset 55 | 56 |

57 | 58 | Disable all 59 | ``` 60 | 61 | 62 | 63 | -------------------------------------------------------------------------------- /packages/angular-test/src/assets/docs/checkbox.md: -------------------------------------------------------------------------------- 1 |

Checkbox

2 | 3 | ```typescript 4 | import {DuiCheckboxModule} from '@marcj/angular-desktop-ui'; 5 | ``` 6 | 7 | 8 | ```javascript 9 | //@angular 10 | return {active: false} 11 | ``` 12 | 13 | ```html 14 |

15 | Disable all
16 | Active: {{active}} 17 |

18 |

19 | Disabled
20 |

21 | ``` 22 | 23 | 24 | -------------------------------------------------------------------------------- /packages/angular-test/src/assets/docs/emoji.md: -------------------------------------------------------------------------------- 1 |

Emoji

2 | 3 | ```typescript 4 | import {DuiEmojiModule} from '@marcj/angular-desktop-ui'; 5 | ``` 6 | 7 | 8 | ```javascript 9 | //@angular 10 | return { 11 | emoji: ':slightly_smiling_face:', 12 | lastUses: [':slightly_smiling_face:', ':+1:', ':-1:'] 13 | } 14 | ``` 15 | 16 | ```html 17 |

18 | 19 | 20 | 21 | 22 |
23 | Name: {{emoji}} 24 |

25 | 26 | 27 | Choose emoji 28 | 29 | 30 | ``` 31 | 32 | 33 | -------------------------------------------------------------------------------- /packages/angular-test/src/assets/docs/form.md: -------------------------------------------------------------------------------- 1 | ```javascript 2 | //@angular 3 | return {disabled: false, disabledAll: false, i: 0} 4 | ``` 5 | 6 |

Form

7 | 8 | ```typescript 9 | import {DuiFormComponent} from '@marcj/angular-desktop-ui'; 10 | ``` 11 | 12 | 13 | ```html 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | Checkbox A 34 | 35 | 36 | 37 | Radio A
38 | Radio B 39 |

40 | Chosen: {{radioValue}} 41 |

42 |
43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | Option A 51 | Option B 52 | 53 | 54 | 55 | 56 | 57 | Option X 58 | Option Y 59 | 60 | 61 | 62 | 63 | 64 | Option A 65 | Option B 66 | 67 | 68 | 69 | 70 | Button 73 | {{i}} 74 | 75 | 76 | 77 | Textured Button 78 | 79 | 80 | 81 | Square button 82 | 83 | 84 | 85 | Disabled 86 | 87 |
88 | 89 | 90 | Disable all 91 | 92 |
93 | ``` 94 |
95 | 96 | 97 | 98 | 99 | -------------------------------------------------------------------------------- /packages/angular-test/src/assets/docs/indicator.md: -------------------------------------------------------------------------------- 1 |

Indicator

2 | 3 | ```typescript 4 | import {DuiIndicatorModule} from '@marcj/angular-desktop-ui'; 5 | ``` 6 | 7 | 8 | ```javascript 9 | //@angular 10 | return {progress: 0.5} 11 | ``` 12 | 13 | ```html 14 | {{progress}}
15 |
16 |
17 |
18 | 19 |

20 | 21 |

22 | ``` 23 | 24 | 25 | -------------------------------------------------------------------------------- /packages/angular-test/src/assets/docs/input.md: -------------------------------------------------------------------------------- 1 |

Input

2 | 3 | ```typescript 4 | import {DuiInputModule} from '@marcj/angular-desktop-ui'; 5 | ``` 6 | 7 | 8 | ```javascript 9 | //@angular 10 | return {name: 'Peter'} 11 | ``` 12 | 13 | ```html 14 | 15 | 16 | clear 17 | 18 | 19 | 20 |

21 | default with placeholder 22 |

23 | 24 |

25 | default 26 |

27 | 28 |

29 | clearer 30 |

31 | 32 |

33 | textured 34 |

35 | 36 |

37 | round 38 |

39 | 40 |

41 | round lightFocus 42 |

43 |

44 | round lightFocus semiTransparent 45 |

46 | 47 |

48 | 49 |

50 | 51 |

52 | 53 |

54 | 55 |

56 | 57 |

58 | 59 | ``` 60 | 61 | 62 | -------------------------------------------------------------------------------- /packages/angular-test/src/assets/docs/list.md: -------------------------------------------------------------------------------- 1 | ```javascript 2 | //@angular 3 | return { 4 | sidebarVisible: true, 5 | selected: 'button', 6 | } 7 | ``` 8 | 9 |

List

10 | 11 | ```typescript 12 | import {DuiListModule} from '@marcj/angular-desktop-ui'; 13 | ``` 14 | 15 | ```html 16 |
17 | 18 | Button 19 | Button Group 20 | Window 21 | Toolbar 22 | Sidebar 23 | Checkbox 24 | Radiobox 25 | Select 26 | 27 |
28 |

29 | Selected dui-list-item: {{selected}} 30 |

31 | ``` 32 | 33 |

List with category titles

34 | 35 | ```html 36 |
37 | 38 | Form controls 39 | Button 40 | Button Group 41 | 42 | Window 43 | Window 44 | Toolbar 45 | Sidebar 46 | 47 | Buttons & Indicators 48 | Checkbox 49 | Radiobox 50 | Select 51 | 52 |
53 |

54 | Selected dui-list-item: {{selected}} 55 |

56 | ``` 57 | 58 | 59 | 60 | 61 | 62 | 63 | -------------------------------------------------------------------------------- /packages/angular-test/src/assets/docs/menu.md: -------------------------------------------------------------------------------- 1 |

Window Menu

2 | 3 | ```typescript 4 | import {DuiAppModule} from '@marcj/angular-desktop-ui'; 5 | ``` 6 | 7 |

8 | Directives to manipulate the application's and windows's OS menu bar. 9 | This only works when the app is running in Electron. 10 |

11 | 12 |

13 | See Electron documentation to check what property values are available.
14 | electronjs.org/docs/api/menu-item 15 |

16 | 17 | ```html 18 | Show menu 2 (Electron only) 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | ``` 28 | -------------------------------------------------------------------------------- /packages/angular-test/src/assets/docs/radiobox.md: -------------------------------------------------------------------------------- 1 |

Checkbox

2 | 3 | ```typescript 4 | import {DuiCheckboxModule} from '@marcj/angular-desktop-ui'; 5 | ``` 6 | 7 | 8 | ```javascript 9 | //@angular 10 | return {radioValue: 'a'} 11 | ``` 12 | 13 | ```html 14 | 15 | Radio A
16 | Radio B
17 | Radio C 18 |

19 | Chosen: {{radioValue}} 20 |

21 | 22 | Radio A
23 | Radio B
24 | Radio C 25 | ``` 26 | 27 | 28 | -------------------------------------------------------------------------------- /packages/angular-test/src/assets/docs/select.md: -------------------------------------------------------------------------------- 1 |

Checkbox

2 | 3 | ```typescript 4 | import {DuiSelectModule} from '@marcj/angular-desktop-ui'; 5 | ``` 6 | 7 | 8 | ```javascript 9 | //@angular 10 | return { 11 | manyItems: [...Array(255).keys()].map(x => x + 1), 12 | radioValue: 'a' 13 | } 14 | ``` 15 | 16 | ```html 17 |

18 | 19 | Option A 20 | Option B 21 | Option C 22 | 23 | 24 | Option A 25 | Option B 26 | Option C 27 | 28 |

29 | 30 | Option A 31 | Option B 32 | Option C 33 | 34 | 35 | Option A 36 | Option B 37 | Option C 38 | 39 | 40 | Option A 41 | Option B 42 | Option C 43 | 44 |

45 | Chosen: {{radioValue}} 46 |

47 | 48 | 49 | 50 | Option A 51 | 52 | 53 | 54 | 55 | Option B 56 | 57 | 58 | 59 | 60 | Option CCCCCCCCCC 61 | 62 | 63 | 64 |

65 | 66 | Reset 67 | Option A 68 | Option B 69 | Option C 70 | 71 |

72 |

73 | 74 | Option #{{item}} 75 | 76 |

77 | ``` 78 | 79 | 80 | -------------------------------------------------------------------------------- /packages/angular-test/src/assets/docs/slider.md: -------------------------------------------------------------------------------- 1 |

Table

2 | 3 | ```typescript 4 | import {DuiSliderModule} from '@marcj/angular-desktop-ui'; 5 | ``` 6 | 7 | ```javascript 8 | //@angular 9 | return { 10 | value: 0.30, 11 | value2: 60, 12 | value3: 75, 13 | } 14 | ``` 15 | 16 | ```html 17 |

18 |
19 | Value: {{value}} 20 |

21 |

22 |
23 | Value2: {{value2}} 24 |

25 | 26 |

27 |
28 | Value3: {{value3}} 29 |

30 | 31 |

32 |
33 |

34 | ``` 35 | -------------------------------------------------------------------------------- /packages/angular-test/src/assets/docs/welcome.md: -------------------------------------------------------------------------------- 1 |

Angular Desktop UI

2 | 3 | 4 |

5 | 6 |

7 | 8 |

9 | Source: github.com/marcj/angular-desktop-ui
10 | License: MIT 11 |

12 | 13 |

14 | This is a Typescript library offering you desktop UI widgets in Angular 9+ Ivy only and Electron framework integration. 15 | It's mostly targeted at web applications that want to behave and look like native desktop applications. 16 |

17 | 18 |

19 | The goal is to provide a high-performance UI kit that behaves and looks exactly like the UI of desktop operating systems. 20 | Thus with less hover states, no text selection, and only with animations/colors that users are already familiar with. 21 |

22 | 23 |

Features

24 | 25 | 39 | -------------------------------------------------------------------------------- /packages/angular-test/src/assets/docs/window-manager.md: -------------------------------------------------------------------------------- 1 |

Window

2 | 3 | ```typescript 4 | import {DuiWindowModule} from '@marcj/angular-desktop-ui'; 5 | ``` 6 | 7 |

8 | DuiWindowModule provides also a simple window manager that allows you to open Electron windows via Angular directly. 9 |

10 | 11 |

12 | WARNING: still in development. Does not work yet in prod builds. 13 |

14 |

15 | Note: When you open a second window, the root window (where angular was initially loaded) needs to stay loaded all the time (you can hide it though). 16 |

17 | 18 | 19 | 20 | ```html 21 | Open first window 22 | Open second window 23 | ``` 24 | 25 | -------------------------------------------------------------------------------- /packages/angular-test/src/assets/docs/window-manager.ts: -------------------------------------------------------------------------------- 1 | import {FirstWindowComponent} from "../../app/windows/first-window.component"; 2 | import {SecondWindowComponent} from "../../app/windows/second-window.component"; 3 | import {DuiExternalWindow, ExternalWindowComponent} from "@marcj/angular-desktop-ui"; 4 | import {Component} from "@angular/core"; 5 | import {RegisterDocu} from "../../app/decorators"; 6 | 7 | @Component({ 8 | template: '', 9 | }) 10 | @RegisterDocu('window-manager') 11 | export class WindowManager { 12 | public firstWindow?: ExternalWindowComponent; 13 | public secondWindow?: ExternalWindowComponent; 14 | 15 | constructor( 16 | public externalWindow: DuiExternalWindow, 17 | ) { 18 | } 19 | 20 | openFirstWindow() { 21 | if (this.firstWindow) { 22 | return; 23 | } 24 | 25 | const {window} = this.externalWindow.open(FirstWindowComponent, {}, {alwaysRaised: true}); 26 | this.firstWindow = window; 27 | window.closed.subscribe(() => { 28 | this.firstWindow = undefined; 29 | }) 30 | } 31 | 32 | openSecondWindow() { 33 | if (this.secondWindow) { 34 | return; 35 | } 36 | 37 | const {window} = this.externalWindow.open(SecondWindowComponent, {}, {alwaysRaised: true}); 38 | this.secondWindow = window; 39 | window.closed.subscribe(() => { 40 | this.secondWindow = undefined; 41 | }) 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /packages/angular-test/src/assets/docs/window-sidebar.md: -------------------------------------------------------------------------------- 1 | 2 | ```javascript 3 | //@angular 4 | return { 5 | sidebarVisible: true, 6 | selected: 'button', 7 | } 8 | ``` 9 | 10 |

Window sidebar

11 | 12 | ```typescript 13 | import {DuiWindowModule} from '@marcj/angular-desktop-ui'; 14 | ``` 15 | 16 | 17 | 18 | ```html 19 | 20 | 21 | Angular Desktop UI 22 | 23 | 24 | 25 | 26 | 27 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | Form controls 36 | Button 37 | Button Group 38 | Window 39 | Window 40 | Toolbar 41 | Sidebar 42 | Buttons & Indicators 43 | Checkbox 44 | Radiobox 45 | Select 46 | 47 | 48 |
49 | Selected dui-list-item: {{selected}} 50 |
51 |
52 |
53 | ``` 54 |
55 | 56 | 57 | -------------------------------------------------------------------------------- /packages/angular-test/src/assets/docs/window-toolbar.md: -------------------------------------------------------------------------------- 1 |

Window toolbar

2 | 3 | ```typescript 4 | import {DuiWindowModule} from '@marcj/angular-desktop-ui'; 5 | ``` 6 | 7 | 8 | ```html 9 | 10 | 11 | Angular Desktop UI 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 21 | 22 | 23 | 24 | Cool 25 | Right 26 | Yes 27 | 28 | 29 | 30 | 31 | 32 | 33 | 35 | 36 | 37 | 38 | 39 | 40 | Sidebar 41 | 42 | 43 | Content 44 | 45 | 46 | ``` 47 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /packages/angular-test/src/electron.ts: -------------------------------------------------------------------------------- 1 | import 'reflect-metadata'; 2 | import {app, BrowserWindow, ipcMain, Menu, screen, systemPreferences, Tray} from 'electron'; 3 | import * as path from 'path'; 4 | 5 | let win: BrowserWindow | null; 6 | 7 | // app.commandLine.appendSwitch('ignore-gpu-blacklist'); 8 | 9 | app.dock.hide(); 10 | // app.disableHardwareAcceleration(); 11 | 12 | const assetsPath = path.join(__dirname, '../assets'); 13 | 14 | async function createWindow() { 15 | if (win) { 16 | return; 17 | } 18 | 19 | app.dock.show(); 20 | 21 | // Create the browser window. 22 | win = new BrowserWindow({ 23 | center: true, 24 | width: 800, 25 | // frame: false, 26 | height: 700, 27 | vibrancy: 'window', 28 | transparent: true, 29 | backgroundColor: "#80FFFFFF", 30 | webPreferences: { 31 | scrollBounce: true, 32 | allowRunningInsecureContent: false, 33 | preload: __dirname + '/../../node_modules/@marcj/angular-desktop-ui/preload.js', 34 | nativeWindowOpen: true, 35 | }, 36 | titleBarStyle: 'hidden', 37 | // icon: path.join(assetsPath, 'icons/64x64.png') 38 | }); 39 | 40 | win.webContents.openDevTools({mode: 'undocked'}); 41 | win.loadURL('http://127.0.0.1:4200'); 42 | 43 | win.on('closed', () => { 44 | // Dereference the window object, usually you would store window 45 | // in an array if your app supports multi windows, this is the time 46 | // when you should delete the corresponding element. 47 | win = null; 48 | app.dock.hide(); 49 | }); 50 | } 51 | 52 | // This method will be called when Electron has finished 53 | // initialization and is ready to create browser windows. 54 | // Some APIs can only be used after this event occurs. 55 | app.on('ready', async () => { 56 | await createWindow(); 57 | }); 58 | 59 | // app.on('test', () => { 60 | // console.log('test', arguments); 61 | // }); 62 | 63 | // Quit when all windows are closed. 64 | app.on('window-all-closed', () => { 65 | app.quit(); 66 | 67 | // On OS X it is common for applications and their menu bar 68 | // to stay active until the user quits explicitly with Cmd + Q 69 | // if (process.platform !== 'darwin') { 70 | // app.quit(); 71 | // } 72 | }); 73 | 74 | app.on('activate', () => { 75 | // On OS X it's common to re-create a window in the app when the 76 | // dock icon is clicked and there are no other windows open. 77 | if (win === null) { 78 | createWindow(); 79 | } 80 | }); 81 | -------------------------------------------------------------------------------- /packages/angular-test/src/environments/environment.prod.ts: -------------------------------------------------------------------------------- 1 | export const environment = { 2 | production: true 3 | }; 4 | -------------------------------------------------------------------------------- /packages/angular-test/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 | -------------------------------------------------------------------------------- /packages/angular-test/src/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcj/angular-desktop-ui/71f9435eeed6fb23437b45d7a57d9adba5bc93b0/packages/angular-test/src/favicon.ico -------------------------------------------------------------------------------- /packages/angular-test/src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Angular Desktop UI 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /packages/angular-test/src/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'), 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 | }); 31 | }; -------------------------------------------------------------------------------- /packages/angular-test/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 | ngZone: 'noop' 13 | }) 14 | .catch(err => console.error(err)); 15 | -------------------------------------------------------------------------------- /packages/angular-test/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: any; 11 | 12 | // First, initialize the Angular testing environment. 13 | getTestBed().initTestEnvironment( 14 | BrowserDynamicTestingModule, 15 | platformBrowserDynamicTesting() 16 | ); 17 | // Then we find all the tests. 18 | const context = require.context('./', true, /\.spec\.ts$/); 19 | // And load the modules. 20 | context.keys().map(context); 21 | -------------------------------------------------------------------------------- /packages/angular-test/src/tsconfig.app.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../out-tsc/app", 5 | "types": [] 6 | }, 7 | "files": [ 8 | "main.ts", 9 | "polyfills.ts" 10 | ] 11 | } 12 | -------------------------------------------------------------------------------- /packages/angular-test/src/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 | "test.ts", 12 | "polyfills.ts" 13 | ], 14 | "include": [ 15 | "**/*.spec.ts", 16 | "**/*.d.ts" 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /packages/angular-test/src/tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tslint.json", 3 | "rules": { 4 | "directive-selector": [ 5 | true, 6 | "attribute", 7 | "app", 8 | "camelCase" 9 | ], 10 | "component-selector": [ 11 | true, 12 | "element", 13 | "app", 14 | "kebab-case" 15 | ] 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /packages/angular-test/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compileOnSave": false, 3 | "compilerOptions": { 4 | "outDir": "./dist/out-tsc", 5 | "sourceMap": true, 6 | "declaration": false, 7 | "strict": true, 8 | "moduleResolution": "node", 9 | "emitDecoratorMetadata": true, 10 | "experimentalDecorators": true, 11 | "preserveSymlinks": true, 12 | "target": "es2017", 13 | "allowSyntheticDefaultImports": true, 14 | "typeRoots": [ 15 | "node_modules/@types" 16 | ], 17 | "lib": [ 18 | "es2017", 19 | "es2016", 20 | "es2015", 21 | "dom" 22 | ] 23 | }, 24 | "include": [ 25 | "./src", 26 | "node_modules/@marcj/angular-desktop-ui/src/**/*.ts" 27 | ], 28 | "exclude": [ 29 | "src/electron.ts" 30 | ] 31 | } 32 | -------------------------------------------------------------------------------- /packages/angular-test/tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "rules": { 3 | "arrow-return-shorthand": true, 4 | "callable-types": true, 5 | "class-name": true, 6 | "curly": true, 7 | "deprecation": { 8 | "severity": "warn" 9 | }, 10 | "eofline": true, 11 | "forin": true, 12 | "import-blacklist": [ 13 | true, 14 | "rxjs/Rx" 15 | ], 16 | "import-spacing": true, 17 | "indent": [ 18 | true, 19 | "spaces" 20 | ], 21 | "interface-over-type-literal": true, 22 | "label-position": true, 23 | "max-line-length": [ 24 | true, 25 | 140 26 | ], 27 | "member-access": false, 28 | "member-ordering": [ 29 | true, 30 | { 31 | "order": [ 32 | "static-field", 33 | "instance-field", 34 | "static-method", 35 | "instance-method" 36 | ] 37 | } 38 | ], 39 | "no-arg": true, 40 | "no-bitwise": true, 41 | "no-console": [ 42 | true, 43 | "debug", 44 | "info", 45 | "time", 46 | "timeEnd", 47 | "trace" 48 | ], 49 | "no-construct": true, 50 | "no-debugger": true, 51 | "no-duplicate-super": true, 52 | "no-empty": false, 53 | "no-empty-interface": true, 54 | "no-eval": true, 55 | "no-inferrable-types": [ 56 | true, 57 | "ignore-params" 58 | ], 59 | "no-misused-new": true, 60 | "no-non-null-assertion": true, 61 | "no-redundant-jsdoc": true, 62 | "no-shadowed-variable": true, 63 | "no-string-literal": false, 64 | "no-string-throw": true, 65 | "no-switch-case-fall-through": true, 66 | "no-unnecessary-initializer": true, 67 | "no-unused-expression": true, 68 | "no-var-keyword": true, 69 | "object-literal-sort-keys": false, 70 | "one-line": [ 71 | true, 72 | "check-open-brace", 73 | "check-catch", 74 | "check-else", 75 | "check-whitespace" 76 | ], 77 | "prefer-const": true, 78 | "quotemark": [ 79 | true, 80 | "single" 81 | ], 82 | "radix": true, 83 | "semicolon": [ 84 | true, 85 | "always" 86 | ], 87 | "triple-equals": [ 88 | true, 89 | "allow-null-check" 90 | ], 91 | "typedef-whitespace": [ 92 | true, 93 | { 94 | "call-signature": "nospace", 95 | "index-signature": "nospace", 96 | "parameter": "nospace", 97 | "property-declaration": "nospace", 98 | "variable-declaration": "nospace" 99 | } 100 | ], 101 | "unified-signatures": true, 102 | "variable-name": false, 103 | "whitespace": [ 104 | true, 105 | "check-branch", 106 | "check-decl", 107 | "check-operator", 108 | "check-separator", 109 | "check-type" 110 | ], 111 | "no-output-on-prefix": true, 112 | "use-input-property-decorator": true, 113 | "use-output-property-decorator": true, 114 | "use-host-property-decorator": true, 115 | "no-input-rename": true, 116 | "no-output-rename": true, 117 | "use-life-cycle-interface": true, 118 | "use-pipe-transform-interface": true, 119 | "component-class-suffix": true, 120 | "directive-class-suffix": true 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /packages/angular-test/webpack.electron.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const Visualizer = require('webpack-visualizer-plugin'); 3 | 4 | module.exports = { 5 | target: 'node', 6 | devtool: 'inline-source-map', 7 | entry: path.resolve(__dirname, 'src/electron.ts'), 8 | output: { 9 | filename: 'electron.js', 10 | path: path.resolve(__dirname, 'dist/electron/') 11 | }, 12 | resolve: { 13 | extensions: ['.tsx', '.ts', '.js'], 14 | symlinks: false 15 | }, 16 | optimization: { 17 | usedExports: true 18 | }, 19 | plugins: [new Visualizer({ 20 | filename: './statistics.html' 21 | })], 22 | node: { 23 | __dirname: false, 24 | __filename: false, 25 | }, 26 | externals: { 27 | 'electron': 'require("electron")', 28 | 'net': 'require("net")', 29 | 'remote': 'require("remote")', 30 | 'shell': 'require("shell")', 31 | 'app': 'require("app")', 32 | 'ipc': 'require("ipc")', 33 | 'fs': 'require("fs")', 34 | 'buffer': 'require("buffer")', 35 | 'system': '{}', 36 | 'file': '{}', 37 | 'electron-config': 'require("electron-config")' 38 | }, 39 | module: { 40 | rules: [ 41 | { 42 | // We are piping through babel to get Webpack 4 Tree Shaking support with { 'sideEffects' : false } 43 | loader: 'babel-loader' 44 | }, 45 | { 46 | test: /\.tsx?$/, 47 | loader: 'ts-loader', 48 | options: { 49 | allowTsInNodeModules: true, 50 | transpileOnly: true, 51 | // Since we are piping trough babel we have to target es2016 52 | compilerOptions: { 53 | target: "es2016", 54 | module: "es2015" 55 | }, 56 | }, 57 | include: [ 58 | path.resolve(__dirname), 59 | path.resolve(__dirname, 'node_modules/@deepkit/core/'), 60 | ], 61 | } 62 | ] 63 | } 64 | }; 65 | -------------------------------------------------------------------------------- /packages/native-ui/.npmignore: -------------------------------------------------------------------------------- 1 | assets/UIElements.sketch 2 | dist 3 | -------------------------------------------------------------------------------- /packages/native-ui/angular.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "./node_modules/@angular/cli/lib/config/schema.json", 3 | "version": 1, 4 | "newProjectRoot": "projects", 5 | "projects": { 6 | "angular-desktop-ui": { 7 | "projectType": "library", 8 | "root": "", 9 | "sourceRoot": "./src", 10 | "prefix": "lib", 11 | "architect": { 12 | "build": { 13 | "builder": "@angular-devkit/build-angular:ng-packagr", 14 | "options": { 15 | "tsConfig": "tsconfig.lib.json", 16 | "project": "ng-package.json" 17 | }, 18 | "configurations": { 19 | "production": { 20 | "tsConfig": "tsconfig.prod.json" 21 | } 22 | } 23 | }, 24 | "test": { 25 | "builder": "@angular-devkit/build-angular:karma", 26 | "options": { 27 | "main": "test/test.ts", 28 | "tsConfig": "tsconfig.spec.json", 29 | "karmaConfig": "karma.conf.js" 30 | } 31 | }, 32 | "lint": { 33 | "builder": "@angular-devkit/build-angular:tslint", 34 | "options": { 35 | "tsConfig": [ 36 | "tsconfig.json" 37 | ], 38 | "exclude": [ 39 | "**/node_modules/**" 40 | ] 41 | } 42 | } 43 | } 44 | } 45 | }, 46 | "defaultProject": "angular-desktop-ui" 47 | } 48 | -------------------------------------------------------------------------------- /packages/native-ui/emoji-map.ts: -------------------------------------------------------------------------------- 1 | import {readFile, writeFile} from "fs-extra"; 2 | import {eachPair} from "@marcj/estdlib"; 3 | 4 | (async () => { 5 | //this was created by using package `emoji-datasource` 6 | const file = await readFile('src/components/emoji/emoji_pretty.json', 'utf8'); 7 | 8 | const result: {[name: string]: any} = {}; 9 | const categories: {[name: string]: string[]} = {}; 10 | 11 | const fileEmojis: any[] = JSON.parse(file); 12 | 13 | fileEmojis.sort((a, b) => { 14 | return a.sort_order < b.sort_order ? -1 : +1; 15 | }); 16 | 17 | for (const emoji of fileEmojis) { 18 | result[emoji['short_name']] = { 19 | id: emoji['unified'], 20 | name: emoji['name'] || emoji['short_name'], 21 | shortName: emoji['short_name'], 22 | x: emoji['sheet_x'], 23 | y: emoji['sheet_y'], 24 | }; 25 | 26 | if (!categories[emoji['category']]) { 27 | categories[emoji['category']] = [emoji['short_name']]; 28 | } else { 29 | categories[emoji['category']].push(emoji['short_name']); 30 | } 31 | 32 | } 33 | 34 | const categoriesNormalized = []; 35 | for (const [name, emojis] of eachPair(categories)) { 36 | categoriesNormalized.push({ 37 | name: name, 38 | emojis: emojis, 39 | }) 40 | } 41 | 42 | const mapTS = ` 43 | export interface Emoji { 44 | id: string; 45 | name: string; 46 | shortName: string; 47 | x: number; 48 | y: number; 49 | } 50 | 51 | export interface EmojiCategory { 52 | name: string; 53 | emojis: string[]; 54 | } 55 | 56 | export const emojis: {[id: string]: Emoji} = ${JSON.stringify(result)}; 57 | export const categories: EmojiCategory[] = ${JSON.stringify(categoriesNormalized)}; 58 | `; 59 | 60 | await writeFile('src/components/emoji/emojis.ts', mapTS); 61 | 62 | })(); 63 | -------------------------------------------------------------------------------- /packages/native-ui/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/my-lib'), 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 | restartOnFileChange: true 31 | }); 32 | }; 33 | -------------------------------------------------------------------------------- /packages/native-ui/ng-package.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "node_modules/ng-packagr/ng-package.schema.json", 3 | "dest": "dist/", 4 | "lib": { 5 | "entryFile": "src/index.ts" 6 | }, 7 | "whitelistedNonPeerDependencies": [ 8 | "." 9 | ] 10 | } 11 | -------------------------------------------------------------------------------- /packages/native-ui/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@marcj/angular-desktop-ui", 3 | "version": "0.4.2", 4 | "description": "library offering you desktop UI widgets in Angular 7+", 5 | "keywords": [ 6 | "Desktop", 7 | "UI", 8 | "MacOs" 9 | ], 10 | "bin": { 11 | "dui-create-font": "./bin/create-font.js" 12 | }, 13 | "repository": "https://github.com/marcj/angular-desktop-ui", 14 | "author": "Marc J. Schmidt ", 15 | "license": "MIT", 16 | "sideEffects": false, 17 | "main": "src/index.ts", 18 | "scripts": { 19 | "emoji": "ts-node emoji-map.ts", 20 | "font": "node bin/create-font.js", 21 | "build": "webpack && node bin/create-font.js && npm run docs", 22 | "prepublishOnly": "npm run build", 23 | "docs": "typedoc --json src/assets/docs.json --mode modules src" 24 | }, 25 | "browserslist": [ 26 | "last 2 Chrome versions" 27 | ], 28 | "dependencies": { 29 | "@marcj/estdlib": "^0.1.17", 30 | "@marcj/estdlib-rxjs": "^0.1.17", 31 | "@types/hammerjs": "^2.0.36", 32 | "hammerjs": "^2.0.8", 33 | "path": "^0.12.7", 34 | "tslib": "^2.0.0" 35 | }, 36 | "publishConfig": { 37 | "access": "public" 38 | }, 39 | "peerDependencies": { 40 | "@angular/cdk": ">11.0.0", 41 | "electron": ">7.1.9", 42 | "rxjs": "^6.5.3" 43 | }, 44 | "devDependencies": { 45 | "@angular-devkit/build-angular": "~0.1100.1", 46 | "@angular-devkit/schematics": "^11.0.1", 47 | "@angular/animations": "^11.0.0", 48 | "@angular/cdk": "^11.0.0", 49 | "@angular/cli": "^11.0.1", 50 | "@angular/common": "^11.0.0", 51 | "@angular/compiler": "^11.0.0", 52 | "@angular/compiler-cli": "^11.0.0", 53 | "@angular/core": "^11.0.0", 54 | "@angular/forms": "^11.0.0", 55 | "@angular/platform-browser": "^11.0.0", 56 | "@angular/platform-browser-dynamic": "^11.0.0", 57 | "@angular/router": "^11.0.0", 58 | "@types/fs-extra": "^8.0.1", 59 | "@types/node": "^12.12.26", 60 | "awesome-typescript-loader": "^5.2.1", 61 | "fs-extra": "^8.1.0", 62 | "rxjs": "~6.5.3", 63 | "svg2ttf": "^4.2.0", 64 | "svgicons2svgfont": "^9.0.4", 65 | "transformation-matrix-js": "2.7.1", 66 | "ttf2woff": "^2.0.1", 67 | "typedoc": "^0.16.7", 68 | "typescript": "^4.0.5", 69 | "webpack": "^4.41.5", 70 | "webpack-cli": "^3.3.10", 71 | "zone.js": "~0.10.3" 72 | }, 73 | "gitHead": "f4dad36e0e38e131344410e0329a647b993da1d0" 74 | } 75 | -------------------------------------------------------------------------------- /packages/native-ui/preload.js: -------------------------------------------------------------------------------- 1 | window.electron = require('electron'); 2 | -------------------------------------------------------------------------------- /packages/native-ui/src/assets/UIElements.sketch: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcj/angular-desktop-ui/71f9435eeed6fb23437b45d7a57d9adba5bc93b0/packages/native-ui/src/assets/UIElements.sketch -------------------------------------------------------------------------------- /packages/native-ui/src/assets/fonts/icon-names.json: -------------------------------------------------------------------------------- 1 | ["15_text-format-align-center","15_text-format-align-left","15_text-format-align-right","15_text-format-bold","15_text-format-bullets","15_text-format-code","15_text-format-indent","15_text-format-italic","15_text-format-strikethrough","15_text-format-underline","15_text-format-unindent","add","archive","arrow-small-down","arrow-small-left","arrow-small-right","arrow-small-up","arrow","arrow_down","arrow_up","arrows","check","clear","color-theme","comment","compare","download","drag","edit","envelop","eye","filter","flag","folder","garbage","gnome_close","gnome_maximize","gnome_minimize","help","list","play","record","remove","search","share","star","toggle-sidebar","toggle_bottom","toggle_left","toggle_right","toggle_sidebar","triangle_down","triangle_right","zoom-to-fit"] -------------------------------------------------------------------------------- /packages/native-ui/src/assets/fonts/ui-icons.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcj/angular-desktop-ui/71f9435eeed6fb23437b45d7a57d9adba5bc93b0/packages/native-ui/src/assets/fonts/ui-icons.ttf -------------------------------------------------------------------------------- /packages/native-ui/src/assets/fonts/ui-icons.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcj/angular-desktop-ui/71f9435eeed6fb23437b45d7a57d9adba5bc93b0/packages/native-ui/src/assets/fonts/ui-icons.woff -------------------------------------------------------------------------------- /packages/native-ui/src/assets/icons.sketch: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcj/angular-desktop-ui/71f9435eeed6fb23437b45d7a57d9adba5bc93b0/packages/native-ui/src/assets/icons.sketch -------------------------------------------------------------------------------- /packages/native-ui/src/assets/icons/15_text-format-align-center.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 15_text-format-align-center 5 | Created with Sketch. 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /packages/native-ui/src/assets/icons/15_text-format-align-left.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 15_text-format-align-left 5 | Created with Sketch. 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /packages/native-ui/src/assets/icons/15_text-format-align-right.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 15_text-format-align-right 5 | Created with Sketch. 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /packages/native-ui/src/assets/icons/15_text-format-bold.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 15_text-format-bold 5 | Created with Sketch. 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /packages/native-ui/src/assets/icons/15_text-format-bullets.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 15_text-format-bullets 5 | Created with Sketch. 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /packages/native-ui/src/assets/icons/15_text-format-code.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 15_text-format-code 5 | Created with Sketch. 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /packages/native-ui/src/assets/icons/15_text-format-indent.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 15_text-format-indent 5 | Created with Sketch. 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /packages/native-ui/src/assets/icons/15_text-format-italic.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 15_text-format-italic 5 | Created with Sketch. 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /packages/native-ui/src/assets/icons/15_text-format-strikethrough.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 15_text-format-strikethrough 5 | Created with Sketch. 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /packages/native-ui/src/assets/icons/15_text-format-underline.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 15_text-format-underline 5 | Created with Sketch. 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /packages/native-ui/src/assets/icons/15_text-format-unindent.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 15_text-format-unindent 5 | Created with Sketch. 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /packages/native-ui/src/assets/icons/add.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | add 5 | Created with Sketch. 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /packages/native-ui/src/assets/icons/archive.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | archive 5 | Created with Sketch. 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /packages/native-ui/src/assets/icons/arrow-small-down.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | arrow-small-down 5 | Created with Sketch. 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /packages/native-ui/src/assets/icons/arrow-small-left.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | arrow-small-left 5 | Created with Sketch. 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /packages/native-ui/src/assets/icons/arrow-small-right.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | arrow-small-right 5 | Created with Sketch. 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /packages/native-ui/src/assets/icons/arrow-small-up.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | arrow-small-up 5 | Created with Sketch. 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /packages/native-ui/src/assets/icons/arrow.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | arrow 5 | Created with Sketch. 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /packages/native-ui/src/assets/icons/arrow_down.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | arrow_down 5 | Created with Sketch. 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /packages/native-ui/src/assets/icons/arrow_up.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | arrow_up 5 | Created with Sketch. 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /packages/native-ui/src/assets/icons/arrows.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | arrows 5 | Created with Sketch. 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /packages/native-ui/src/assets/icons/check.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | check 5 | Created with Sketch. 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /packages/native-ui/src/assets/icons/clear.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | clear 5 | Created with Sketch. 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /packages/native-ui/src/assets/icons/color-theme.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | color-theme 5 | Created with Sketch. 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /packages/native-ui/src/assets/icons/comment.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | comment 5 | Created with Sketch. 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /packages/native-ui/src/assets/icons/compare.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | compare 5 | Created with Sketch. 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /packages/native-ui/src/assets/icons/drag.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | drag 5 | Created with Sketch. 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /packages/native-ui/src/assets/icons/edit.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | edit 5 | Created with Sketch. 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /packages/native-ui/src/assets/icons/envelop.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | envelop 5 | Created with Sketch. 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /packages/native-ui/src/assets/icons/eye.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | eye 5 | Created with Sketch. 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /packages/native-ui/src/assets/icons/filter.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | filter 5 | Created with Sketch. 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /packages/native-ui/src/assets/icons/flag.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | flag 5 | Created with Sketch. 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /packages/native-ui/src/assets/icons/folder.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | folder 5 | Created with Sketch. 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /packages/native-ui/src/assets/icons/garbage.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | garbage 5 | Created with Sketch. 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /packages/native-ui/src/assets/icons/gnome_close.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | gnome_close 5 | Created with Sketch. 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /packages/native-ui/src/assets/icons/gnome_maximize.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | gnome_maximize 5 | Created with Sketch. 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /packages/native-ui/src/assets/icons/gnome_minimize.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | gnome_minimize 5 | Created with Sketch. 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /packages/native-ui/src/assets/icons/help.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | help 5 | Created with Sketch. 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /packages/native-ui/src/assets/icons/list.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | list 5 | Created with Sketch. 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /packages/native-ui/src/assets/icons/play.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | play 5 | Created with Sketch. 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /packages/native-ui/src/assets/icons/record.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | record 5 | Created with Sketch. 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /packages/native-ui/src/assets/icons/remove.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | remove 5 | Created with Sketch. 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /packages/native-ui/src/assets/icons/search.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | search 5 | Created with Sketch. 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /packages/native-ui/src/assets/icons/share.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | share 5 | Created with Sketch. 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /packages/native-ui/src/assets/icons/star.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | star 5 | Created with Sketch. 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /packages/native-ui/src/assets/icons/toggle-sidebar.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | toggle-sidebar 5 | Created with Sketch. 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /packages/native-ui/src/assets/icons/toggle_bottom.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | toggle_bottom 5 | Created with Sketch. 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /packages/native-ui/src/assets/icons/toggle_left.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | toggle_left 5 | Created with Sketch. 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /packages/native-ui/src/assets/icons/toggle_right.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | toggle_right 5 | Created with Sketch. 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /packages/native-ui/src/assets/icons/toggle_sidebar.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | toggle-sidebar 5 | Created with Sketch. 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /packages/native-ui/src/assets/icons/triangle_down.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | triangle_down 5 | Created with Sketch. 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /packages/native-ui/src/assets/icons/triangle_right.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | triangle_right 5 | Created with Sketch. 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /packages/native-ui/src/assets/icons/zoom-to-fit.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | zoom-to-fit 5 | Created with Sketch. 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /packages/native-ui/src/components/app/cd-counter.component.ts: -------------------------------------------------------------------------------- 1 | import {Component, Input} from "@angular/core"; 2 | 3 | @Component({ 4 | selector: 'dui-cd-counter', 5 | template: `{{counter}}` 6 | }) 7 | export class CdCounterComponent { 8 | private i = 0; 9 | 10 | @Input() name?: string; 11 | 12 | get counter() { 13 | this.i++; 14 | return this.i; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /packages/native-ui/src/components/app/dui-responsive.directive.ts: -------------------------------------------------------------------------------- 1 | import {Directive, ElementRef, HostListener, Input, OnInit} from "@angular/core"; 2 | import {eachPair} from "@marcj/estdlib"; 3 | 4 | @Directive({ 5 | selector: '[duiClassMin]', 6 | }) 7 | export class DuiResponsiveDirective implements OnInit { 8 | clazz: { [className: string]: boolean } = {}; 9 | protected lastRequest: any; 10 | 11 | @Input() duiClassMin: { [className: string]: number } = {}; 12 | 13 | constructor( 14 | private element: ElementRef, 15 | ) {} 16 | 17 | ngOnInit() { 18 | this.onResize(); 19 | } 20 | 21 | @HostListener('window:resize') 22 | onResize() { 23 | if (this.lastRequest) { 24 | cancelAnimationFrame(this.lastRequest); 25 | } 26 | 27 | this.lastRequest = requestAnimationFrame(() => { 28 | const element: HTMLElement = this.element.nativeElement; 29 | for (const [name, number] of eachPair(this.duiClassMin)) { 30 | const valid = element.offsetWidth > number; 31 | if (this.clazz[name] !== valid) { 32 | this.clazz[name] = valid; 33 | if (valid) { 34 | element.classList.add(name); 35 | } else { 36 | element.classList.remove(name); 37 | } 38 | } 39 | } 40 | }); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /packages/native-ui/src/components/app/dui-view.directive.ts: -------------------------------------------------------------------------------- 1 | import {Directive, EmbeddedViewRef, Injectable, Input, OnDestroy, TemplateRef, ViewContainerRef} from "@angular/core"; 2 | import {detectChangesNextFrame, scheduleWindowResizeEvent} from "./utils"; 3 | 4 | let i = 0; 5 | 6 | let currentViewDirective: ViewDirective | undefined; 7 | 8 | @Injectable() 9 | export class ViewState { 10 | public id = i++; 11 | 12 | public viewDirective?: ViewDirective = currentViewDirective; 13 | 14 | get attached() { 15 | return this.viewDirective ? this.viewDirective.isVisible() : true; 16 | } 17 | } 18 | 19 | @Directive({ 20 | selector: '[duiView]', 21 | providers: [{provide: ViewState, useClass: ViewState}] 22 | }) 23 | export class ViewDirective implements OnDestroy { 24 | protected view?: EmbeddedViewRef; 25 | 26 | protected visible = false; 27 | 28 | public readonly parentViewDirective: ViewDirective | undefined; 29 | 30 | constructor( 31 | protected template: TemplateRef, 32 | protected viewContainer: ViewContainerRef, 33 | ) { 34 | this.parentViewDirective = currentViewDirective; 35 | } 36 | 37 | public isVisible() { 38 | if (this.view) { 39 | for (const node of this.view.rootNodes) { 40 | if (node.style && node.offsetParent !== null) { 41 | return true; 42 | } 43 | } 44 | 45 | return false; 46 | } 47 | 48 | return this.visible; 49 | } 50 | 51 | @Input() 52 | set duiView(v: boolean) { 53 | if (this.visible === v) return; 54 | 55 | this.visible = v; 56 | 57 | if (this.visible) { 58 | if (this.view) { 59 | this.view.rootNodes.map(element => { 60 | if (element.style) { 61 | element.style.display = ''; 62 | } 63 | }); 64 | this.view!.reattach(); 65 | this.view.markForCheck(); 66 | scheduleWindowResizeEvent(); 67 | return; 68 | } 69 | 70 | const old = currentViewDirective; 71 | currentViewDirective = this; 72 | this.view = this.viewContainer.createEmbeddedView(this.template); 73 | currentViewDirective = old; 74 | } else { 75 | if (this.view) { 76 | this.view!.rootNodes.map(element => { 77 | if (element.style) { 78 | element.style.display = 'none'; 79 | } 80 | }); 81 | //let the last change detection run so ViewState have correct state 82 | this.view!.detectChanges(); 83 | this.view!.detach(); 84 | this.view.markForCheck(); 85 | detectChangesNextFrame(this.view); 86 | } 87 | } 88 | } 89 | 90 | ngOnDestroy() { 91 | if (this.view) { 92 | this.view.destroy(); 93 | } 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /packages/native-ui/src/components/app/pipes.ts: -------------------------------------------------------------------------------- 1 | import {ChangeDetectorRef, OnDestroy, Pipe, PipeTransform, WrappedValue} from "@angular/core"; 2 | import {Observable, Subscription} from "rxjs"; 3 | import {detectChangesNextFrame} from "./utils"; 4 | 5 | /** 6 | * Almost the same as |async pipe, but renders directly (detectChanges() instead of marking it only(markForCheck()) 7 | * on ChangeDetectorRef. 8 | */ 9 | @Pipe({name: 'asyncRender', pure: false}) 10 | export class AsyncRenderPipe implements OnDestroy, PipeTransform { 11 | protected subscription?: Subscription; 12 | protected lastValue?: any; 13 | protected lastReturnedValue?: any; 14 | 15 | constructor( 16 | protected cd: ChangeDetectorRef) { 17 | } 18 | 19 | ngOnDestroy(): void { 20 | if (this.subscription) this.subscription.unsubscribe(); 21 | } 22 | 23 | transform(value?: Observable): T | undefined { 24 | if (this.lastValue !== value) { 25 | if (this.subscription) this.subscription.unsubscribe(); 26 | this.lastReturnedValue = undefined; 27 | this.lastValue = value; 28 | 29 | if (value) { 30 | this.subscription = value.subscribe((next) => { 31 | this.lastReturnedValue = next; 32 | detectChangesNextFrame(this.cd); 33 | }); 34 | } 35 | } 36 | 37 | return this.lastReturnedValue; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /packages/native-ui/src/components/app/token.ts: -------------------------------------------------------------------------------- 1 | import {InjectionToken} from "@angular/core"; 2 | 3 | export const ELECTRON_WINDOW = new InjectionToken('Electron window'); 4 | 5 | export const IN_DIALOG = new InjectionToken('In dialog'); 6 | -------------------------------------------------------------------------------- /packages/native-ui/src/components/app/utils.ts: -------------------------------------------------------------------------------- 1 | import {ApplicationRef, ChangeDetectorRef, Directive, ElementRef, HostListener, Input, OnChanges} from "@angular/core"; 2 | import {Electron} from "../../core/utils"; 3 | 4 | 5 | @Directive({ 6 | selector: '[openExternal], a[href]', 7 | }) 8 | export class OpenExternalDirective implements OnChanges { 9 | @Input('openExternal') private openExternal: string = ''; 10 | @Input('href') private href: string = ''; 11 | 12 | constructor(private element: ElementRef) { 13 | // this.element.nativeElement.href = '#'; 14 | } 15 | 16 | ngOnChanges(): void { 17 | // this.element.nativeElement.href = this.getLink(); 18 | } 19 | 20 | getLink() { 21 | return this.openExternal || this.href; 22 | } 23 | 24 | @HostListener('click', ['$event']) 25 | onClick(event: Event) { 26 | event.stopPropagation(); 27 | event.preventDefault(); 28 | 29 | if (Electron.isAvailable()) { 30 | event.preventDefault(); 31 | Electron.getRemote().shell.openExternal(this.getLink()); 32 | } else { 33 | window.open(this.getLink(), '_blank'); 34 | } 35 | } 36 | } 37 | 38 | let lastScheduleResize: any; 39 | 40 | export function scheduleWindowResizeEvent() { 41 | if (lastScheduleResize) cancelAnimationFrame(lastScheduleResize); 42 | lastScheduleResize = requestAnimationFrame(() => { 43 | window.dispatchEvent(new Event('resize')); 44 | lastScheduleResize = undefined; 45 | }) 46 | } 47 | 48 | 49 | let lastFrameRequest: any; 50 | let lastFrameRequestStack = new Set(); 51 | 52 | export class ZonelessChangeDetector { 53 | static app: ApplicationRef | undefined = undefined; 54 | 55 | static getApp() { 56 | if (!ZonelessChangeDetector.app) { 57 | throw new Error('ZonelessChangeDetector.app not set yet'); 58 | } 59 | 60 | return ZonelessChangeDetector.app; 61 | } 62 | } 63 | 64 | /** 65 | * This handy function makes sure that in the next animation frame the given ChangeDetectorRef is called. 66 | * It makes automatically sure that it is only called once per frame. 67 | */ 68 | export function detectChangesNextFrame(cd?: ChangeDetectorRef) { 69 | if (cd) { 70 | lastFrameRequestStack.add(cd); 71 | } 72 | 73 | if (lastFrameRequest) { 74 | return; 75 | } 76 | 77 | lastFrameRequest = requestAnimationFrame(() => { 78 | lastFrameRequest = undefined; 79 | for (const i of lastFrameRequestStack) { 80 | i.markForCheck(); 81 | } 82 | //since ivy we have to use tick() instead of and can not use i.detectChanges(). 83 | ZonelessChangeDetector.getApp().tick(); 84 | lastFrameRequestStack.clear(); 85 | }); 86 | } 87 | -------------------------------------------------------------------------------- /packages/native-ui/src/components/button/button-group.component.scss: -------------------------------------------------------------------------------- 1 | :host { 2 | //fix for non-integer widths, making icons blurry that come behind those elements 3 | display: inline-table; 4 | line-height: 0; 5 | white-space: nowrap; 6 | } 7 | 8 | //:host ::ng-deep > * { 9 | // margin-right: 6px; 10 | //} 11 | 12 | :host ::ng-deep > * { 13 | margin-right: 6px; 14 | } 15 | :host:last-child ::ng-deep > *:last-child { 16 | margin-right: 0; 17 | } 18 | 19 | :host ::ng-deep dui-button.active { 20 | z-index: 1; 21 | } 22 | 23 | :host.float-right { 24 | margin-left: auto; 25 | } 26 | 27 | :host.with-animation { 28 | transition: padding-left 300ms ease-in-out; 29 | } 30 | 31 | :host-context(.dark).padding-none { 32 | ::ng-deep dui-select:not(:first-child), 33 | ::ng-deep dui-button:not(.square):not(:first-child) { 34 | border-left: 1px solid #484c50 !important; 35 | } 36 | } 37 | 38 | :host.padding-none { 39 | margin-right: 7px; 40 | } 41 | 42 | :host.padding-none ::ng-deep > * { 43 | margin-right: -1px; 44 | 45 | &:not(:first-child) { 46 | border-top-left-radius: 0; 47 | border-bottom-left-radius: 0; 48 | } 49 | 50 | &:not(:last-child) { 51 | border-top-right-radius: 0; 52 | border-bottom-right-radius: 0; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /packages/native-ui/src/components/button/button-groups.component.scss: -------------------------------------------------------------------------------- 1 | 2 | :host { 3 | padding: 8px; 4 | display: flex; 5 | white-space: nowrap; 6 | word-break: keep-all; 7 | 8 | &.align-center { 9 | justify-content: center; 10 | } 11 | 12 | &.align-right { 13 | justify-content: flex-end; 14 | } 15 | } 16 | 17 | :host ::ng-deep > *:not(dui-button-group) { 18 | margin-right: 6px; 19 | } 20 | -------------------------------------------------------------------------------- /packages/native-ui/src/components/button/dropdow.component.scss: -------------------------------------------------------------------------------- 1 | @import "../../scss/mixins"; 2 | 3 | :host { 4 | display: none; 5 | } 6 | 7 | .dui-dropdown { 8 | flex: 1; 9 | 10 | @include background-vibrancy; 11 | 12 | border-top: 1px solid #d0d0d0; 13 | border-left: 1px solid #c5c5c5; 14 | border-right: 1px solid #c5c5c5; 15 | border-bottom: 1px solid #b9b9b9; 16 | 17 | box-shadow: 0 4px 14px 0 rgba(133, 129, 129, 0.44); 18 | display: flex; 19 | border-radius: 5px; 20 | overflow: hidden; 21 | 22 | &:focus { 23 | outline: 0; 24 | } 25 | 26 | 27 | > div.content { 28 | flex: 1; 29 | padding: 4px 0; 30 | min-height: 25px; 31 | border-radius: 5px; 32 | } 33 | } 34 | 35 | .dui-dropdown-arrow { 36 | position: absolute; 37 | top: -14px; 38 | left: calc(50% - 28px / 2); 39 | width: 28px; 40 | height: 15px; 41 | 42 | background-image: url(./overlay-arrow.svg); 43 | background-repeat: no-repeat; 44 | } 45 | 46 | ::ng-deep .dark { 47 | .dui-dropdown-arrow { 48 | height: 16px; 49 | background-image: url(./overlay-arrow-dark.svg); 50 | } 51 | 52 | .dui-dropdown { 53 | box-shadow: 0 4px 12px 0 rgba(45, 45, 45, 0.77); 54 | 55 | border-top: 1px solid #0a0b0c; 56 | border-left: 1px solid #07090a; 57 | border-right: 1px solid #07090a; 58 | border-bottom: 1px solid #050607; 59 | 60 | > div.content { 61 | border-top: 1px solid #5f5f5f; 62 | border-left: 1px solid #5f5f5f; 63 | border-right: 1px solid #5f5f5f; 64 | border-bottom: 1px solid #5f5f5f; 65 | } 66 | 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /packages/native-ui/src/components/button/dropdown-item.component.scss: -------------------------------------------------------------------------------- 1 | :host { 2 | padding: 1px 23px; 3 | position: relative; 4 | overflow: hidden; 5 | 6 | display: flex; 7 | flex-direction: row; 8 | flex-wrap: nowrap; 9 | justify-content: flex-start; 10 | align-items: center; 11 | 12 | dui-icon.selected { 13 | position: absolute; 14 | color: var(--color-black); 15 | left: 6px; 16 | top: 3px; 17 | } 18 | 19 | &.selected { 20 | 21 | } 22 | 23 | &.disabled { 24 | opacity: 0.8; 25 | pointer-events: none; 26 | } 27 | 28 | &:not(.disabled):hover { 29 | background-color: var(--dui-selection); 30 | color: white; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /packages/native-ui/src/components/button/index.ts: -------------------------------------------------------------------------------- 1 | import {NgModule} from "@angular/core"; 2 | import { 3 | ButtonComponent, 4 | ButtonGroupComponent, 5 | ButtonGroupsComponent, 6 | FileChooserDirective, FileDropDirective, FilePickerDirective 7 | } from "./button.component"; 8 | import {CommonModule} from "@angular/common"; 9 | import {DuiIconModule} from "../icon"; 10 | import { 11 | DropdownComponent, 12 | DropdownItemComponent, 13 | DropdownSplitterComponent, 14 | OpenDropdownDirective, 15 | ContextDropdownDirective, 16 | } from "./dropdown.component"; 17 | import {FormsModule} from "@angular/forms"; 18 | import {TabButtonComponent} from './tab-button.component' 19 | 20 | export * from "./dropdown.component"; 21 | export * from './button.component' 22 | export * from './tab-button.component' 23 | 24 | @NgModule({ 25 | declarations: [ 26 | ButtonComponent, 27 | ButtonGroupComponent, 28 | ButtonGroupsComponent, 29 | DropdownComponent, 30 | DropdownItemComponent, 31 | DropdownSplitterComponent, 32 | OpenDropdownDirective, 33 | ContextDropdownDirective, 34 | FileChooserDirective, 35 | TabButtonComponent, 36 | FilePickerDirective, 37 | FileDropDirective, 38 | ], 39 | exports: [ 40 | ButtonComponent, 41 | ButtonGroupComponent, 42 | ButtonGroupsComponent, 43 | DropdownComponent, 44 | DropdownItemComponent, 45 | DropdownSplitterComponent, 46 | OpenDropdownDirective, 47 | ContextDropdownDirective, 48 | FileChooserDirective, 49 | TabButtonComponent, 50 | FilePickerDirective, 51 | FileDropDirective, 52 | ], 53 | imports: [ 54 | CommonModule, 55 | FormsModule, 56 | DuiIconModule, 57 | ] 58 | }) 59 | export class DuiButtonModule { 60 | 61 | } 62 | -------------------------------------------------------------------------------- /packages/native-ui/src/components/button/overlay-arrow-dark.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | overlay-arrow-dark 5 | Created with Sketch. 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /packages/native-ui/src/components/button/overlay-arrow.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | overlay-arrow 5 | Created with Sketch. 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /packages/native-ui/src/components/button/tab-button.component.scss: -------------------------------------------------------------------------------- 1 | :host { 2 | vertical-align: middle; 3 | position: relative; 4 | height: 17px; 5 | line-height: 17px; 6 | padding: 4px 7px; 7 | font-weight: 500; //medium 8 | color: #808080; 9 | 10 | font-size: 11px; 11 | overflow: hidden; 12 | text-overflow: ellipsis; 13 | text-align: center; 14 | 15 | display: inline-flex; 16 | justify-content: center; 17 | align-items: center; 18 | cursor: default; 19 | user-select: none; 20 | white-space: nowrap; 21 | text-overflow: ellipsis; 22 | 23 | border-radius: 2px; 24 | } 25 | 26 | :host:hover { 27 | color: white; 28 | background-color: var(--dui-selection-hover); 29 | } 30 | 31 | :host.active { 32 | color: white; 33 | background-color: var(--dui-selection); 34 | } 35 | -------------------------------------------------------------------------------- /packages/native-ui/src/components/button/tab-button.component.ts: -------------------------------------------------------------------------------- 1 | import {Component, Input} from "@angular/core"; 2 | 3 | @Component({ 4 | selector: 'dui-tab-button', 5 | template: ` 6 | 7 | `, 8 | host: { 9 | '[attr.tabindex]': '1', 10 | '[class.active]': 'active !== false', 11 | }, 12 | styleUrls: ['./tab-button.component.scss'] 13 | }) 14 | export class TabButtonComponent { 15 | /** 16 | * Whether the button is active (pressed) 17 | */ 18 | @Input() active: boolean | '' = false; 19 | } 20 | -------------------------------------------------------------------------------- /packages/native-ui/src/components/checkbox/checkbox.component.scss: -------------------------------------------------------------------------------- 1 | :host { 2 | display: inline-block; 3 | vertical-align: middle; 4 | height: 20px; 5 | line-height: 20px; 6 | text-align: left; 7 | 8 | &:focus { 9 | outline: 0; 10 | //outline: 1px solid #4686de; 11 | } 12 | } 13 | 14 | :host.disabled { 15 | opacity: 0.6; 16 | pointer-events: none; 17 | } 18 | 19 | .box { 20 | width: 14px; 21 | height: 14px; 22 | line-height: 14px; 23 | margin-right: 4px; 24 | vertical-align: top; 25 | margin-top: 2px; 26 | 27 | background: white; 28 | border-top: 1px solid #a5a5a5; 29 | border-left: 1px solid #b8b8b8; 30 | border-right: 1px solid #b8b8b8; 31 | border-bottom: 1px solid #b8b8b8; 32 | border-radius: 3px; 33 | 34 | display: inline-flex; 35 | align-items: center; 36 | //transition: all 0.08s ease-in; 37 | } 38 | 39 | 40 | dui-icon { 41 | opacity: 0; 42 | } 43 | 44 | :host.checked .box { 45 | background: #3b88fd; 46 | border: 1px solid #338EF4; 47 | 48 | dui-icon { 49 | opacity: 1; 50 | color: white; 51 | text-shadow: 0 1px 1px rgba(77, 77, 77, 0.65); 52 | } 53 | } 54 | 55 | :host-context(.dark) { 56 | .box { 57 | background-image: linear-gradient(-180deg, #515151 0%, #6A6A6A 100%); 58 | //background: linear-gradient(-180deg, rgba(255, 255, 255, 0.14) 0%, rgba(255, 255, 255, 0.28) 100%); 59 | box-shadow: 0 0 1px 0 rgba(0, 0, 0, 0.40), 0 0 1px 0 rgba(0, 0, 0, 0.20), inset 0 0 0 0 rgba(255, 255, 255, 0.25), inset 0 1px 0 0 rgba(255, 255, 255, 0.06); 60 | border: 1px solid transparent; 61 | } 62 | 63 | &:active .box { 64 | background-image: none; 65 | background-color: #7c7c7c; 66 | } 67 | 68 | &.checked { 69 | .box { 70 | background-image: linear-gradient(-180deg, #1769E5 0%, #165FD0 100%); 71 | } 72 | 73 | &:active .box { 74 | background-image: none; 75 | background-color: #1f76ed; 76 | } 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /packages/native-ui/src/components/checkbox/checkbox.component.ts: -------------------------------------------------------------------------------- 1 | import { 2 | ChangeDetectionStrategy, 3 | ChangeDetectorRef, 4 | Component, DoCheck, 5 | HostBinding, 6 | HostListener, Injectable, 7 | Injector, SkipSelf 8 | } from "@angular/core"; 9 | import {ngValueAccessor, ValueAccessorBase} from "../../core/form"; 10 | 11 | @Component({ 12 | selector: 'dui-checkbox', 13 | template: ` 14 | 15 | 16 | 17 | 18 | `, 19 | styleUrls: ['./checkbox.component.scss'], 20 | providers: [ngValueAccessor(CheckboxComponent)], 21 | changeDetection: ChangeDetectionStrategy.OnPush, 22 | }) 23 | export class CheckboxComponent extends ValueAccessorBase { 24 | @HostBinding('tabindex') 25 | get tabIndex() { 26 | return 1; 27 | } 28 | 29 | @HostBinding('class.checked') 30 | get isChecked() { 31 | return true === this.innerValue; 32 | } 33 | 34 | @HostListener('click') 35 | public onClick() { 36 | if (this.isDisabled) return; 37 | 38 | this.touch(); 39 | this.innerValue = !this.innerValue; 40 | } 41 | 42 | constructor( 43 | protected injector: Injector, 44 | public readonly cd: ChangeDetectorRef, 45 | @SkipSelf() public readonly cdParent: ChangeDetectorRef, 46 | ) { 47 | super(injector, cd, cdParent); 48 | } 49 | 50 | } 51 | -------------------------------------------------------------------------------- /packages/native-ui/src/components/checkbox/index.ts: -------------------------------------------------------------------------------- 1 | import {NgModule} from "@angular/core"; 2 | import {CheckboxComponent} from "./checkbox.component"; 3 | import {DuiIconModule} from "../icon"; 4 | 5 | export * from './checkbox.component' 6 | 7 | @NgModule({ 8 | declarations: [ 9 | CheckboxComponent 10 | ], 11 | exports: [ 12 | CheckboxComponent 13 | ], 14 | imports: [ 15 | DuiIconModule, 16 | ] 17 | }) 18 | export class DuiCheckboxModule { 19 | 20 | } 21 | -------------------------------------------------------------------------------- /packages/native-ui/src/components/core/index.ts: -------------------------------------------------------------------------------- 1 | import {NgModule} from "@angular/core"; 2 | import {RenderComponentDirective} from "./render-component.directive"; 3 | 4 | export * from './render-component.directive' 5 | 6 | @NgModule({ 7 | declarations: [ 8 | RenderComponentDirective, 9 | ], 10 | exports: [ 11 | RenderComponentDirective, 12 | ], 13 | providers: [], 14 | imports: [ 15 | ] 16 | }) 17 | export class DuiCoreModule { 18 | 19 | } 20 | -------------------------------------------------------------------------------- /packages/native-ui/src/components/core/render-component.directive.ts: -------------------------------------------------------------------------------- 1 | import { 2 | AfterViewInit, 3 | ApplicationRef, 4 | ComponentFactoryResolver, 5 | ComponentRef, 6 | Directive, 7 | Input, 8 | OnDestroy, 9 | ViewContainerRef 10 | } from "@angular/core"; 11 | import {eachPair} from "@marcj/estdlib"; 12 | 13 | @Directive({ 14 | selector: '[renderComponent]', 15 | }) 16 | export class RenderComponentDirective implements AfterViewInit, OnDestroy { 17 | @Input() renderComponent: any; 18 | @Input() renderComponentInputs: { [name: string]: any } = {}; 19 | 20 | public component?: ComponentRef; 21 | 22 | constructor( 23 | protected app: ApplicationRef, 24 | protected resolver: ComponentFactoryResolver, 25 | protected viewContainerRef: ViewContainerRef, 26 | ) { 27 | } 28 | 29 | ngAfterViewInit(): void { 30 | const factoryMain = this.resolver.resolveComponentFactory(this.renderComponent); 31 | const original = (factoryMain.create as any).bind(factoryMain); 32 | factoryMain.create = (...args: any[]) => { 33 | const comp = original(...args); 34 | 35 | for (const [i, v] of eachPair(this.renderComponentInputs)) { 36 | comp.instance[i] = v; 37 | } 38 | 39 | return comp; 40 | }; 41 | 42 | this.component = this.viewContainerRef.createComponent(factoryMain, 0, this.viewContainerRef.injector); 43 | 44 | this.app.tick(); 45 | } 46 | 47 | ngOnDestroy(): void { 48 | if (this.component) { 49 | this.component.destroy(); 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /packages/native-ui/src/components/dialog/dialog-error.component.scss: -------------------------------------------------------------------------------- 1 | :host { 2 | display: block; 3 | padding: 3px 0; 4 | width: 100%; 5 | color: var(--color-red); 6 | } 7 | -------------------------------------------------------------------------------- /packages/native-ui/src/components/dialog/dialog-wrapper.component.scss: -------------------------------------------------------------------------------- 1 | @keyframes dialog-fade-in { 2 | from { 3 | top: -200px; 4 | } 5 | 6 | to { 7 | top: 0; 8 | } 9 | } 10 | 11 | ::ng-deep { 12 | .cdk-overlay-pane { 13 | overflow: hidden; 14 | display: flex; 15 | } 16 | 17 | .cdk-overlay-pane > ng-component { 18 | flex: 1; 19 | display: flex; 20 | max-width: 100%; 21 | } 22 | 23 | .cdk-overlay-pane dui-window { 24 | position: relative !important; 25 | 26 | flex: 1; 27 | height: auto; 28 | margin: 25px; 29 | width: calc(100% - 50px); 30 | margin-top: 0; 31 | max-height: 100%; 32 | border: 1px solid #b8b8b8; 33 | box-shadow: 0 5px 10px 2px rgba(0, 0, 0, 0.22); 34 | 35 | dui-window-content > .content { 36 | padding-left: 20px !important; 37 | padding-right: 20px !important; 38 | padding-bottom: 5px !important; 39 | } 40 | } 41 | 42 | .dialog-overlay-with-animation dui-window { 43 | animation: 0.2s dialog-fade-in ease-out; 44 | } 45 | 46 | .cdk-overlay-dark-backdrop { 47 | background: rgba(0, 0, 0, 0.001) 48 | } 49 | } 50 | 51 | 52 | .dialog-actions { 53 | padding: 20px; 54 | padding-top: 15px; 55 | background-color: #ececec; 56 | 57 | text-align: right; 58 | display: flex; 59 | justify-content: flex-end; 60 | flex-wrap: wrap; 61 | 62 | ::ng-deep > * { 63 | margin: 0 5px; 64 | 65 | &:last-child { 66 | margin-right: 0; 67 | } 68 | 69 | &:first-child { 70 | margin-left: 0; 71 | } 72 | } 73 | } 74 | 75 | ::ng-deep .dark { 76 | .dialog-actions { 77 | background-color: var(--dui-window-content-bg); 78 | } 79 | 80 | ::ng-deep .cdk-overlay-pane dui-window { 81 | border: 1px solid #060708; 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /packages/native-ui/src/components/dialog/index.ts: -------------------------------------------------------------------------------- 1 | import {NgModule} from "@angular/core"; 2 | import {DuiWindowModule} from "../window"; 3 | import { 4 | CloseDialogDirective, 5 | DialogActionsComponent, 6 | DialogComponent, 7 | DialogDirective, 8 | DialogErrorComponent, 9 | DialogWrapperComponent, 10 | } from "./dialog.component"; 11 | import {OverlayModule} from "@angular/cdk/overlay"; 12 | import {CommonModule} from "@angular/common"; 13 | import {DuiDialog, DuiDialogAlert, DuiDialogConfirm, DuiDialogConfirmDirective, DuiDialogPrompt} from "./dialog"; 14 | import {DuiButtonModule} from "../button"; 15 | import {DuiCoreModule} from "../core"; 16 | import {DuiInputModule} from "../input"; 17 | import {FormsModule} from "@angular/forms"; 18 | import {DuiDialogProgress} from "./progress-dialog.component"; 19 | 20 | export * from "./dialog.component"; 21 | export * from "./dialog"; 22 | export * from "./progress-dialog.component"; 23 | 24 | @NgModule({ 25 | declarations: [ 26 | DialogComponent, 27 | DialogDirective, 28 | DialogActionsComponent, 29 | CloseDialogDirective, 30 | DuiDialogConfirmDirective, 31 | DuiDialogAlert, 32 | DuiDialogConfirm, 33 | DuiDialogPrompt, 34 | DuiDialogProgress, 35 | DialogWrapperComponent, 36 | DialogErrorComponent, 37 | ], 38 | exports: [ 39 | DialogDirective, 40 | DialogComponent, 41 | DialogActionsComponent, 42 | CloseDialogDirective, 43 | DuiDialogConfirmDirective, 44 | DuiDialogAlert, 45 | DuiDialogConfirm, 46 | DuiDialogPrompt, 47 | DuiDialogProgress, 48 | DialogErrorComponent, 49 | ], 50 | entryComponents: [ 51 | DialogComponent, 52 | DuiDialogAlert, 53 | DuiDialogConfirm, 54 | DuiDialogPrompt, 55 | DialogWrapperComponent, 56 | ], 57 | providers: [ 58 | DuiDialog, 59 | ], 60 | imports: [ 61 | FormsModule, 62 | CommonModule, 63 | OverlayModule, 64 | DuiWindowModule, 65 | DuiButtonModule, 66 | DuiCoreModule, 67 | DuiInputModule, 68 | ] 69 | }) 70 | export class DuiDialogModule { 71 | 72 | } 73 | -------------------------------------------------------------------------------- /packages/native-ui/src/components/dialog/progress-dialog.component.ts: -------------------------------------------------------------------------------- 1 | import {BehaviorSubject} from "rxjs"; 2 | import {Component, Input, OnInit} from "@angular/core"; 3 | import {DialogComponent} from "./dialog.component"; 4 | 5 | class State { 6 | title: string = ''; 7 | step: number = 0; 8 | steps: number = 1; 9 | } 10 | 11 | export class ProgressDialogState extends BehaviorSubject { 12 | protected readonly state = new State; 13 | 14 | public readonly closer = new BehaviorSubject(false); 15 | 16 | constructor() { 17 | super(undefined); 18 | this.next(this.state); 19 | } 20 | 21 | public cancel() { 22 | this.closer.next(true); 23 | } 24 | 25 | public close() { 26 | this.closer.next(true); 27 | } 28 | 29 | public async waitForClose(): Promise { 30 | return new Promise((resolve, reject) => { 31 | this.closer.subscribe((next) => { 32 | if (next) { 33 | resolve(next); 34 | } 35 | }); 36 | }); 37 | } 38 | 39 | set title(v: string) { 40 | this.state.title = v; 41 | this.next(this.state); 42 | } 43 | 44 | get title(): string { 45 | return this.state.title; 46 | } 47 | 48 | set step(v: number) { 49 | this.state.step = v; 50 | this.next(this.state); 51 | } 52 | 53 | get step(): number { 54 | return this.state.step; 55 | } 56 | 57 | set steps(v: number) { 58 | this.state.steps = v; 59 | this.next(this.state); 60 | } 61 | 62 | get steps(): number { 63 | return this.state.steps; 64 | } 65 | } 66 | 67 | @Component({ 68 | template: ` 69 |
70 |

{{state.title}}

71 |
72 |
73 | {{state.step}} / {{state.steps}} 74 |
75 | 76 |
77 |
78 | 79 | 80 | 81 | 82 | ` 83 | }) 84 | export class DuiDialogProgress implements OnInit { 85 | @Input() public state$!: ProgressDialogState; 86 | 87 | constructor(protected dialog: DialogComponent) { 88 | } 89 | 90 | ngOnInit(): void { 91 | this.state$.closer.subscribe((v) => { 92 | if (v) { 93 | this.dialog.close(v); 94 | } 95 | }); 96 | } 97 | 98 | onCancelClick() { 99 | this.state$.closer.next(true); 100 | this.dialog.close(false); 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /packages/native-ui/src/components/emoji/emoji-dropdown.component.scss: -------------------------------------------------------------------------------- 1 | 2 | :host { 3 | display: none; 4 | } 5 | 6 | .category-title { 7 | font-size: 12px; 8 | margin-top: 15px; 9 | text-transform: uppercase; 10 | font-weight: 500; 11 | color: var(--text-grey); 12 | letter-spacing: -0.3px; 13 | } 14 | 15 | 16 | .emoji-image { 17 | display: inline-block; 18 | background-image: url(./emoji_apple_32.png); 19 | background-repeat: no-repeat; 20 | width: 32px; 21 | height: 32px; 22 | transform: scale((1/32*26)); 23 | } 24 | 25 | .emoji { 26 | display: inline-block; 27 | width: 32px; 28 | height: 32px; 29 | text-align: center; 30 | border-radius: 3px; 31 | 32 | &.selected, &:active { 33 | background: rgba(180, 206, 239, 0.85); 34 | } 35 | } 36 | 37 | .emojis { 38 | margin-top: 7px; 39 | display: grid; 40 | width: 100%; 41 | grid-gap: 4px; 42 | grid-template-columns: repeat(auto-fill, 32px); 43 | } 44 | 45 | .dropdown { 46 | padding: 10px 13px; 47 | } 48 | 49 | -------------------------------------------------------------------------------- /packages/native-ui/src/components/emoji/emoji.component.scss: -------------------------------------------------------------------------------- 1 | :host { 2 | display: inline-block; 3 | overflow: hidden; 4 | } 5 | 6 | .emoji-image { 7 | display: inline-block; 8 | background-image: url(./emoji_apple_32.png); 9 | background-repeat: no-repeat; 10 | width: 32px; 11 | height: 32px; 12 | transform-origin: left top; 13 | } 14 | -------------------------------------------------------------------------------- /packages/native-ui/src/components/emoji/emoji.component.ts: -------------------------------------------------------------------------------- 1 | import {Component, Input} from "@angular/core"; 2 | import {Emoji, emojis} from "./emojis"; 3 | 4 | @Component({ 5 | selector: 'dui-emoji', 6 | template: ` 7 |
11 |
12 | `, 13 | host: { 14 | '[style.height.px]': 'size', 15 | '[style.width.px]': 'size', 16 | }, 17 | styleUrls: ['./emoji.component.scss'] 18 | }) 19 | export class EmojiComponent { 20 | @Input() name!: string; 21 | @Input() size: number = 16; 22 | 23 | get emoji(): Emoji | undefined { 24 | if (this.name) { 25 | if (this.name[0] === ':') return emojis[this.name.substring(1, this.name.length - 1)]; 26 | return emojis[this.name] 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /packages/native-ui/src/components/emoji/emoji_apple_32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcj/angular-desktop-ui/71f9435eeed6fb23437b45d7a57d9adba5bc93b0/packages/native-ui/src/components/emoji/emoji_apple_32.png -------------------------------------------------------------------------------- /packages/native-ui/src/components/emoji/index.ts: -------------------------------------------------------------------------------- 1 | import {NgModule} from "@angular/core"; 2 | import {FormsModule} from "@angular/forms"; 3 | import {CommonModule} from "@angular/common"; 4 | import {EmojiDropdownComponent, EmojiDropdownDirective} from "./emoji-dropdown.component"; 5 | import {DuiInputModule} from "../input"; 6 | import {DuiButtonModule} from "../button"; 7 | import {EmojiComponent} from "./emoji.component"; 8 | 9 | export {EmojiComponent} from "./emoji.component"; 10 | 11 | export {EmojiDropdownComponent, EmojiDropdownDirective} from "./emoji-dropdown.component"; 12 | 13 | @NgModule({ 14 | declarations: [ 15 | EmojiDropdownComponent, 16 | EmojiDropdownDirective, 17 | EmojiComponent, 18 | ], 19 | exports: [ 20 | EmojiDropdownComponent, 21 | EmojiDropdownDirective, 22 | EmojiComponent, 23 | ], 24 | entryComponents: [ 25 | EmojiDropdownComponent, 26 | ], 27 | imports: [ 28 | FormsModule, 29 | CommonModule, 30 | DuiInputModule, 31 | DuiButtonModule, 32 | ] 33 | }) 34 | export class DuiEmojiModule { 35 | 36 | } 37 | -------------------------------------------------------------------------------- /packages/native-ui/src/components/form/form-row.component.scss: -------------------------------------------------------------------------------- 1 | :host { 2 | display: flex; 3 | margin-bottom: 12px; 4 | 5 | > div:first-child { 6 | width: 30%; 7 | margin-right: 8px; 8 | line-height: 20px; 9 | text-align: right; 10 | } 11 | 12 | .field { 13 | flex: 1; 14 | 15 | ::ng-deep > * { 16 | width: 100%; 17 | } 18 | } 19 | } 20 | 21 | .error { 22 | margin-top: 2px; 23 | color: var(--color-red); 24 | } 25 | -------------------------------------------------------------------------------- /packages/native-ui/src/components/form/form.component.scss: -------------------------------------------------------------------------------- 1 | :host { 2 | display: block; 3 | margin-top: 15px; 4 | } 5 | 6 | .error { 7 | padding: 5px; 8 | color: var(--color-red); 9 | } 10 | -------------------------------------------------------------------------------- /packages/native-ui/src/components/form/index.ts: -------------------------------------------------------------------------------- 1 | import {NgModule} from "@angular/core"; 2 | import {FormComponent, FormRowComponent} from "./form.component"; 3 | import {FormsModule, ReactiveFormsModule} from "@angular/forms"; 4 | import {CommonModule} from "@angular/common"; 5 | 6 | export * from "./form.component"; 7 | 8 | @NgModule({ 9 | declarations: [ 10 | FormComponent, 11 | FormRowComponent, 12 | ], 13 | exports: [ 14 | FormComponent, 15 | FormRowComponent, 16 | ], 17 | imports: [ 18 | CommonModule, 19 | FormsModule, 20 | ReactiveFormsModule, 21 | ] 22 | }) 23 | export class DuiFormComponent { 24 | 25 | } 26 | -------------------------------------------------------------------------------- /packages/native-ui/src/components/icon/icon.component.ts: -------------------------------------------------------------------------------- 1 | import {Component, HostBinding, Input, OnChanges, OnInit} from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'dui-icon', 5 | template: `{{name}}`, 6 | host: { 7 | '[class.ui-icon]': 'true', 8 | '[style.fontSize.px]': 'usedSize', 9 | '[style.height.px]': 'usedSize', 10 | '[style.width.px]': 'usedSize', 11 | '[style.color]': 'color', 12 | }, 13 | styles: [` 14 | :host { 15 | display: inline-block; 16 | vertical-align: middle; 17 | text-align: center; 18 | font-size: 17px; 19 | height: 17px; 20 | width: 17px; 21 | } 22 | 23 | :host:focus { 24 | outline: 0; 25 | } 26 | 27 | :host.disabled { 28 | opacity: 0.6; 29 | } 30 | 31 | :host.clickable:hover { 32 | opacity: 0.7; 33 | } 34 | 35 | :host.clickable:active { 36 | color: var(--dui-selection); 37 | } 38 | `] 39 | }) 40 | export class IconComponent implements OnInit, OnChanges { 41 | /** 42 | * The icon for this button. Either a icon name same as for dui-icon, or an image path. 43 | */ 44 | @Input() name?: string; 45 | 46 | /** 47 | * Change in the icon size. Should not be necessary usually. 48 | */ 49 | @Input() size?: number; 50 | 51 | @Input() clickable: boolean | '' = false; 52 | 53 | @Input() color?: string; 54 | 55 | public usedSize = 17; 56 | 57 | @HostBinding('class.clickable') 58 | get isClickable() { 59 | return false !== this.clickable; 60 | } 61 | 62 | @Input() disabled: boolean = false; 63 | @HostBinding('class.disabled') 64 | get isDisabled() { 65 | return false !== this.disabled; 66 | } 67 | 68 | constructor() { 69 | } 70 | 71 | ngOnChanges(): void { 72 | if (this.size) { 73 | this.usedSize = this.size; 74 | } 75 | 76 | if (!this.size && this.name) { 77 | const pos = this.name.indexOf('_'); 78 | if (pos !== -1) { 79 | const potentialNumber = parseInt(this.name.slice(0, pos), 10); 80 | if (potentialNumber) { 81 | this.usedSize = potentialNumber; 82 | } 83 | } 84 | } 85 | } 86 | 87 | 88 | ngOnInit() { 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /packages/native-ui/src/components/icon/index.ts: -------------------------------------------------------------------------------- 1 | import {NgModule} from '@angular/core'; 2 | 3 | import {IconComponent} from './icon.component'; 4 | 5 | export * from './icon.component'; 6 | 7 | @NgModule({ 8 | imports: [], 9 | exports: [IconComponent], 10 | declarations: [IconComponent], 11 | providers: [], 12 | }) 13 | export class DuiIconModule { 14 | } 15 | -------------------------------------------------------------------------------- /packages/native-ui/src/components/indicator/index.ts: -------------------------------------------------------------------------------- 1 | import {NgModule} from "@angular/core"; 2 | import {CommonModule} from "@angular/common"; 3 | import {IndicatorComponent} from "./indicator.component"; 4 | 5 | export * from './indicator.component'; 6 | 7 | @NgModule({ 8 | declarations: [ 9 | IndicatorComponent, 10 | ], 11 | exports: [ 12 | IndicatorComponent, 13 | ], 14 | imports: [ 15 | CommonModule, 16 | ] 17 | }) 18 | export class DuiIndicatorModule { 19 | 20 | } 21 | -------------------------------------------------------------------------------- /packages/native-ui/src/components/indicator/indicator.component.scss: -------------------------------------------------------------------------------- 1 | :host { 2 | position: relative; 3 | width: 150px; 4 | height: 7px; 5 | border-radius: 3px; 6 | background-color: #dbdbdb; 7 | overflow: hidden; 8 | display: inline-block; 9 | 10 | &::after { 11 | content: ''; 12 | position: absolute; 13 | left: 0; 14 | right: 0; 15 | top: 0; 16 | bottom: 0; 17 | border: 1px solid rgba(103, 101, 101, 0.11); 18 | } 19 | } 20 | 21 | .active { 22 | position: absolute; 23 | left: 0; 24 | top: 0; 25 | bottom: 0; 26 | 27 | border-top-left-radius: 3px; 28 | border-bottom-left-radius: 3px; 29 | width: 30%; 30 | transition: all 0.1s ease-in; 31 | background-color: var(--dui-selection-light); 32 | 33 | &.invisible { 34 | opacity: 0; 35 | } 36 | } 37 | 38 | :host-context(.light) { 39 | //border-top: 1px solid #dddddd; 40 | //border-bottom: 1px solid #dddddd; 41 | 42 | .active { 43 | border-top: 1px solid #9cb2ea; 44 | border-bottom: 1px solid #9cb2ea; 45 | border-right: 1px solid rgba(255, 255, 255, 0.16); 46 | } 47 | 48 | &::after { 49 | top: 1px; 50 | bottom: 1px; 51 | } 52 | } 53 | 54 | :host-context(.dark) { 55 | background-color: #58534f; 56 | 57 | .active { 58 | border-right: 1px solid rgba(52, 52, 52, 0.2); 59 | } 60 | 61 | &::after { 62 | top: 0; 63 | bottom: 0; 64 | border: 1px solid rgba(52, 52, 52, 0.23); 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /packages/native-ui/src/components/indicator/indicator.component.ts: -------------------------------------------------------------------------------- 1 | import {Component, Input} from "@angular/core"; 2 | 3 | @Component({ 4 | selector: 'dui-indicator', 5 | template: ` 6 |
7 | `, 8 | styleUrls: ['./indicator.component.scss'] 9 | }) 10 | export class IndicatorComponent { 11 | @Input() step = 0; 12 | } 13 | -------------------------------------------------------------------------------- /packages/native-ui/src/components/input/index.ts: -------------------------------------------------------------------------------- 1 | import {NgModule} from "@angular/core"; 2 | import {InputComponent} from "./input.component"; 3 | import {FormsModule} from "@angular/forms"; 4 | import {CommonModule} from "@angular/common"; 5 | import {DuiIconModule} from "../icon"; 6 | 7 | export * from './input.component'; 8 | 9 | @NgModule({ 10 | declarations: [ 11 | InputComponent 12 | ], 13 | exports: [ 14 | InputComponent, 15 | ], 16 | imports: [ 17 | CommonModule, 18 | FormsModule, 19 | DuiIconModule, 20 | ] 21 | }) 22 | export class DuiInputModule { 23 | 24 | } 25 | -------------------------------------------------------------------------------- /packages/native-ui/src/components/list/index.ts: -------------------------------------------------------------------------------- 1 | import {NgModule} from '@angular/core'; 2 | import {ListComponent, ListItemComponent, ListTitleComponent} from './list.component'; 3 | 4 | export * from './list.component'; 5 | 6 | @NgModule({ 7 | imports: [], 8 | exports: [ 9 | ListComponent, 10 | ListItemComponent, 11 | ListTitleComponent, 12 | ], 13 | declarations: [ 14 | ListComponent, 15 | ListItemComponent, 16 | ListTitleComponent, 17 | ], 18 | providers: [], 19 | }) 20 | export class DuiListModule { 21 | } 22 | -------------------------------------------------------------------------------- /packages/native-ui/src/components/list/list-item.component.scss: -------------------------------------------------------------------------------- 1 | :host { 2 | display: block; 3 | padding: 4px 20px; 4 | font-size: 11px; 5 | font-weight: 500; 6 | } 7 | -------------------------------------------------------------------------------- /packages/native-ui/src/components/list/list-title.component.scss: -------------------------------------------------------------------------------- 1 | :host { 2 | display: block; 3 | padding: 4px 10px; 4 | font-size: 11px; 5 | font-weight: 600; 6 | color: #45484a; 7 | } 8 | 9 | :host-context(.dark) { 10 | color: #a6aaad; 11 | } 12 | -------------------------------------------------------------------------------- /packages/native-ui/src/components/list/list.component.scss: -------------------------------------------------------------------------------- 1 | :host { 2 | display: block; 3 | height: 100%; 4 | 5 | &:focus { 6 | outline: 0; 7 | } 8 | } 9 | 10 | :host.disabled > * { 11 | opacity: 0.6; 12 | } 13 | 14 | :host ::ng-deep dui-list-item.selected { 15 | background-color: var(--dui-selection-unfocused); 16 | } 17 | 18 | :host:focus.focusable ::ng-deep dui-list-item.selected { 19 | background-color: var(--dui-selection); 20 | color: white; 21 | --text-light: #d1d1d1; 22 | } 23 | 24 | :host-context(.light).white { 25 | background-color: white; 26 | border: 1px solid #c5c5c5; 27 | 28 | &:not(:focus) ::ng-deep dui-list-item.selected { 29 | background-color: #dcdcdc; 30 | } 31 | } 32 | 33 | :host-context(.dark).white { 34 | background-color: #1e1e1e; 35 | border: 1px solid #565656; 36 | } 37 | 38 | 39 | :host.delimiter-line { 40 | ::ng-deep dui-list-item { 41 | border-bottom: 1px solid var(--line-color-light); 42 | 43 | &.selected { 44 | border-bottom: 1px solid transparent; 45 | } 46 | } 47 | 48 | &:focus ::ng-deep dui-list-item.selected { 49 | margin-top: -1px; 50 | border-top: 1px solid transparent; 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /packages/native-ui/src/components/radiobox/index.ts: -------------------------------------------------------------------------------- 1 | import {NgModule} from "@angular/core"; 2 | import {RadioboxComponent} from "./radiobox.component"; 3 | 4 | export * from './radiobox.component'; 5 | 6 | @NgModule({ 7 | declarations: [ 8 | RadioboxComponent 9 | ], 10 | exports: [ 11 | RadioboxComponent 12 | ] 13 | }) 14 | export class DuiRadioboxModule { 15 | 16 | } 17 | -------------------------------------------------------------------------------- /packages/native-ui/src/components/radiobox/radiobox.component.scss: -------------------------------------------------------------------------------- 1 | :host { 2 | display: inline-block; 3 | vertical-align: middle; 4 | height: 20px; 5 | line-height: 20px; 6 | text-align: left; 7 | 8 | &:focus { 9 | outline: 0; 10 | //outline: 1px solid #4686de; 11 | } 12 | } 13 | 14 | :host.disabled { 15 | opacity: 0.6; 16 | pointer-events: none; 17 | } 18 | 19 | .box { 20 | position: relative; 21 | display: inline-block; 22 | width: 16px; 23 | height: 16px; 24 | line-height: 14px; 25 | margin-right: 4px; 26 | vertical-align: top; 27 | margin-top: 2px; 28 | border-radius: 14px; 29 | 30 | background: white; 31 | border: 1px solid #adadad; 32 | 33 | transition: all 0.08s ease-in; 34 | } 35 | 36 | .circle { 37 | position: absolute; 38 | left: calc(50% - 3px); 39 | top: calc(50% - 3px); 40 | width: 6px; 41 | height: 6px; 42 | border-radius: 6px; 43 | background-color: white; 44 | opacity: 0; 45 | box-shadow: 0 1px 3px #1a6adf; 46 | } 47 | 48 | :host.checked .box { 49 | background: #3b88fd; 50 | border: 1px solid #338EF4; 51 | 52 | .circle { 53 | opacity: 1; 54 | } 55 | } 56 | 57 | 58 | :host-context(.dark) { 59 | .box { 60 | background: linear-gradient(-180deg, rgba(255, 255, 255, 0.14) 0%, rgba(255, 255, 255, 0.28) 100%); 61 | box-shadow: 0 0 1px 0 rgba(0, 0, 0, 0.40), 0 0 1px 0 rgba(0, 0, 0, 0.20), inset 0 0 0 0 rgba(255, 255, 255, 0.25), inset 0 1px 0 0 rgba(255, 255, 255, 0.06); 62 | border: 1px solid transparent; 63 | } 64 | 65 | &.checked .box { 66 | background-image: linear-gradient(-180deg, #1768E5 0%, #145CCC 100%); 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /packages/native-ui/src/components/radiobox/radiobox.component.ts: -------------------------------------------------------------------------------- 1 | import {ChangeDetectorRef, Component, HostBinding, HostListener, Injector, Input, SkipSelf} from "@angular/core"; 2 | import {ngValueAccessor, ValueAccessorBase} from "../../core/form"; 3 | 4 | @Component({ 5 | selector: 'dui-radiobox', 6 | template: ` 7 |
8 | 9 | `, 10 | styleUrls: ['./radiobox.component.scss'], 11 | providers: [ngValueAccessor(RadioboxComponent)] 12 | }) 13 | export class RadioboxComponent extends ValueAccessorBase { 14 | @Input() value?: T; 15 | 16 | @HostBinding('tabindex') 17 | get tabIndex() { 18 | return 1; 19 | } 20 | 21 | @HostBinding('class.checked') 22 | get isChecked() { 23 | return this.value === this.innerValue; 24 | } 25 | 26 | constructor( 27 | protected injector: Injector, 28 | public readonly cd: ChangeDetectorRef, 29 | @SkipSelf() public readonly cdParent: ChangeDetectorRef, 30 | ) { 31 | super(injector, cd, cdParent); 32 | } 33 | 34 | @HostListener('click') 35 | public onClick() { 36 | if (this.isDisabled) return; 37 | 38 | this.innerValue = this.value; 39 | this.touch(); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /packages/native-ui/src/components/select/index.ts: -------------------------------------------------------------------------------- 1 | import {NgModule} from "@angular/core"; 2 | import {DynamicOptionDirective, OptionDirective, SelectboxComponent} from "./selectbox.component"; 3 | import {FormsModule} from "@angular/forms"; 4 | import {CommonModule} from "@angular/common"; 5 | import {DuiIconModule} from "../icon"; 6 | import {DuiButtonModule} from "../button"; 7 | 8 | export * from "./selectbox.component"; 9 | 10 | @NgModule({ 11 | declarations: [ 12 | SelectboxComponent, 13 | OptionDirective, 14 | DynamicOptionDirective, 15 | ], 16 | exports: [ 17 | SelectboxComponent, 18 | OptionDirective, 19 | DynamicOptionDirective, 20 | ], 21 | imports: [ 22 | FormsModule, 23 | CommonModule, 24 | DuiIconModule, 25 | DuiButtonModule, 26 | ] 27 | }) 28 | export class DuiSelectModule { 29 | 30 | } 31 | -------------------------------------------------------------------------------- /packages/native-ui/src/components/slider/index.ts: -------------------------------------------------------------------------------- 1 | import {NgModule} from "@angular/core"; 2 | import {FormsModule} from "@angular/forms"; 3 | import {CommonModule} from "@angular/common"; 4 | import {DuiIconModule} from "../icon"; 5 | import {DuiButtonModule} from "../button"; 6 | import {SliderComponent} from "./slider.component"; 7 | 8 | export * from './slider.component'; 9 | 10 | @NgModule({ 11 | declarations: [ 12 | SliderComponent, 13 | ], 14 | exports: [ 15 | SliderComponent, 16 | ], 17 | imports: [ 18 | FormsModule, 19 | CommonModule, 20 | DuiIconModule, 21 | DuiButtonModule, 22 | ] 23 | }) 24 | export class DuiSliderModule { 25 | 26 | } 27 | -------------------------------------------------------------------------------- /packages/native-ui/src/components/slider/slider.component.scss: -------------------------------------------------------------------------------- 1 | :host { 2 | display: inline-block; 3 | position: relative; 4 | width: 150px; 5 | 6 | --knob-size: 17px; 7 | --height: 17px; 8 | 9 | height: var(--height); 10 | } 11 | 12 | .bg { 13 | margin-top: 7px; 14 | height: 3px; 15 | background-color: var(--line-color); 16 | border-radius: 1px; 17 | } 18 | 19 | .active-line { 20 | margin-top: 7px; 21 | border-radius: 3px; 22 | width: 30%; 23 | height: 3px; 24 | background-color: var(--dui-selection); 25 | } 26 | 27 | .knob-container { 28 | position: absolute; 29 | top: 0; 30 | left: 0; 31 | right: var(--knob-size); 32 | } 33 | 34 | .knob { 35 | position: absolute; 36 | top: 0; 37 | left: 0; 38 | width: var(--knob-size); 39 | height: var(--knob-size); 40 | border: 1px solid #c9c9c9; 41 | background-color: white; 42 | border-radius: var(--knob-size); 43 | } 44 | 45 | :host-context(.dark) { 46 | --knob-size: 15px; 47 | 48 | .knob { 49 | background-color: #cbcbcb; 50 | top: 1px; 51 | } 52 | } 53 | 54 | :host.mini { 55 | --knob-size: 11px; 56 | --height: 11px; 57 | opacity: 0.8; 58 | 59 | .bg, .active-line { 60 | margin-top: 4px; 61 | } 62 | 63 | .active-line { 64 | background-color: var(--line-color-prominent); 65 | } 66 | } 67 | 68 | :host-context(.dark).mini { 69 | --knob-size: 9px; 70 | } 71 | 72 | -------------------------------------------------------------------------------- /packages/native-ui/src/components/splitter/index.ts: -------------------------------------------------------------------------------- 1 | import {NgModule} from '@angular/core'; 2 | 3 | import {SplitterComponent} from './splitter.component'; 4 | 5 | export * from './splitter.component'; 6 | 7 | @NgModule({ 8 | imports: [], 9 | exports: [SplitterComponent], 10 | declarations: [SplitterComponent], 11 | providers: [], 12 | }) 13 | export class DuiSplitterModule { 14 | } 15 | -------------------------------------------------------------------------------- /packages/native-ui/src/components/splitter/splitter.component.scss: -------------------------------------------------------------------------------- 1 | :host { 2 | position: absolute; 3 | } 4 | 5 | :host.splitter-right { 6 | width: 5px; 7 | right: -2px; 8 | top: 0; 9 | bottom: 0; 10 | cursor: ew-resize; 11 | } 12 | 13 | :host.splitter-left { 14 | width: 5px; 15 | left: -2px; 16 | top: 0; 17 | bottom: 0; 18 | cursor: ew-resize; 19 | } 20 | 21 | :host.splitter-top { 22 | top: -2px; 23 | left: 0; 24 | right: 0; 25 | height: 5px; 26 | cursor: ns-resize; 27 | } 28 | 29 | :host.splitter-bottom { 30 | bottom: -2px; 31 | left: 0; 32 | right: 0; 33 | height: 5px; 34 | cursor: ns-resize; 35 | } 36 | 37 | :host.splitter-with-indicator.splitter-right:before { 38 | content: ''; 39 | position: absolute; 40 | height: 100%; 41 | width: 1px; 42 | left: 2px; 43 | background: #d6d6d6; 44 | } 45 | 46 | 47 | :host-context(.dark).splitter-with-indicator.splitter-right:before { 48 | background: #474747; 49 | } 50 | -------------------------------------------------------------------------------- /packages/native-ui/src/components/table/index.ts: -------------------------------------------------------------------------------- 1 | import {NgModule} from '@angular/core'; 2 | import { 3 | TableCellDirective, 4 | TableColumnDirective, 5 | TableComponent, 6 | TableCustomHeaderContextMenuDirective, 7 | TableCustomRowContextMenuDirective, 8 | TableHeaderDirective 9 | } from "./table.component"; 10 | import {CommonModule} from "@angular/common"; 11 | import {DuiIconModule} from "../icon"; 12 | import {DuiSplitterModule} from "../splitter"; 13 | import {ScrollingModule} from "@angular/cdk/scrolling"; 14 | import {DuiButtonModule} from "../button"; 15 | 16 | export * from "./table.component"; 17 | 18 | @NgModule({ 19 | exports: [ 20 | TableCellDirective, 21 | TableColumnDirective, 22 | TableHeaderDirective, 23 | TableComponent, 24 | TableCustomRowContextMenuDirective, 25 | TableCustomHeaderContextMenuDirective, 26 | ], 27 | declarations: [ 28 | TableCellDirective, 29 | TableColumnDirective, 30 | TableHeaderDirective, 31 | TableComponent, 32 | TableCustomRowContextMenuDirective, 33 | TableCustomHeaderContextMenuDirective, 34 | ], 35 | providers: [], 36 | imports: [ 37 | CommonModule, 38 | DuiIconModule, 39 | DuiSplitterModule, 40 | ScrollingModule, 41 | DuiButtonModule, 42 | ], 43 | }) 44 | export class DuiTableModule { 45 | } 46 | -------------------------------------------------------------------------------- /packages/native-ui/src/components/window/external-window.ts: -------------------------------------------------------------------------------- 1 | import {ApplicationRef, ComponentFactoryResolver, Injectable, Injector, Type, ViewContainerRef} from "@angular/core"; 2 | import {ExternalWindowComponent} from "./external-window.component"; 3 | import {ComponentPortal, DomPortalHost} from "@angular/cdk/portal"; 4 | 5 | @Injectable() 6 | export class DuiExternalWindow { 7 | constructor( 8 | protected resolver: ComponentFactoryResolver, 9 | protected app: ApplicationRef, 10 | protected injector: Injector, 11 | ) { 12 | 13 | } 14 | 15 | public open( 16 | component: Type, 17 | inputs: { [name: string]: any } = {}, 18 | options: { 19 | alwaysRaised?: boolean, 20 | } = {}, 21 | viewContainerRef: ViewContainerRef | null = null, 22 | ): { window: ExternalWindowComponent, instance: T } { 23 | const portalHost = new DomPortalHost( 24 | document.body, 25 | this.resolver, 26 | this.app, 27 | this.injector 28 | ); 29 | 30 | //todo, get viewContainerRef from WindowRegistry? 31 | const portal = new ComponentPortal(ExternalWindowComponent, viewContainerRef, viewContainerRef ? viewContainerRef.injector : null); 32 | 33 | const comp = portalHost.attach(portal); 34 | 35 | if (options && options.alwaysRaised) { 36 | comp.instance.alwaysRaised = true; 37 | } 38 | comp.instance.component = component; 39 | comp.instance.componentInputs = inputs; 40 | 41 | comp.instance.show(); 42 | comp.changeDetectorRef.detectChanges(); 43 | 44 | comp.instance.closed.subscribe(() => { 45 | comp.destroy(); 46 | }); 47 | 48 | return { 49 | window: comp.instance, 50 | instance: comp.instance.wrapperComponentRef!.instance!.renderComponentDirective!.component!.instance, 51 | }; 52 | } 53 | 54 | } 55 | -------------------------------------------------------------------------------- /packages/native-ui/src/components/window/index.ts: -------------------------------------------------------------------------------- 1 | import {ModuleWithProviders, NgModule} from "@angular/core"; 2 | import {WindowContentComponent} from "./window-content.component"; 3 | import {WindowComponent, WindowFrameComponent} from "./window.component"; 4 | import {WindowFooterComponent} from "./window-footer.component"; 5 | import { 6 | WindowHeaderComponent, 7 | WindowToolbarComponent, 8 | WindowToolbarContainerComponent 9 | } from "./window-header.component"; 10 | import {CommonModule} from "@angular/common"; 11 | import {WindowSidebarComponent} from "./window-sidebar.component"; 12 | import {DuiSplitterModule} from "../splitter"; 13 | import {DuiIconModule} from "../icon"; 14 | import {WindowRegistry} from "./window-state"; 15 | 16 | import { 17 | ExternalDialogDirective, 18 | ExternalDialogWrapperComponent, 19 | ExternalWindowComponent 20 | } from "./external-window.component"; 21 | import {DuiExternalWindow} from "./external-window"; 22 | import {DuiCoreModule} from "../core"; 23 | 24 | export * from "./window.component"; 25 | export * from "./external-window"; 26 | export * from "./external-window.component"; 27 | export * from "./window-content.component"; 28 | export * from "./window-header.component"; 29 | export * from "./window-footer.component"; 30 | export * from "./window-menu"; 31 | export * from "./window-sidebar.component"; 32 | 33 | @NgModule({ 34 | declarations: [ 35 | WindowContentComponent, 36 | WindowComponent, 37 | WindowFrameComponent, 38 | WindowFooterComponent, 39 | WindowHeaderComponent, 40 | WindowToolbarComponent, 41 | WindowToolbarContainerComponent, 42 | WindowSidebarComponent, 43 | ExternalWindowComponent, 44 | ExternalDialogWrapperComponent, 45 | ExternalDialogDirective, 46 | ], 47 | exports: [ 48 | WindowContentComponent, 49 | WindowComponent, 50 | WindowFrameComponent, 51 | WindowFooterComponent, 52 | WindowHeaderComponent, 53 | WindowToolbarComponent, 54 | WindowToolbarContainerComponent, 55 | WindowSidebarComponent, 56 | ExternalWindowComponent, 57 | ExternalDialogWrapperComponent, 58 | ExternalDialogDirective, 59 | ], 60 | entryComponents: [ 61 | ExternalWindowComponent, 62 | ], 63 | providers: [ 64 | DuiExternalWindow, 65 | ], 66 | imports: [ 67 | CommonModule, 68 | DuiSplitterModule, 69 | DuiIconModule, 70 | DuiCoreModule, 71 | ] 72 | }) 73 | export class DuiWindowModule { 74 | static forRoot(): ModuleWithProviders { 75 | return { 76 | ngModule: DuiWindowModule, 77 | providers: [WindowRegistry] 78 | } 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /packages/native-ui/src/components/window/window-content.component.scss: -------------------------------------------------------------------------------- 1 | :host { 2 | display: flex; 3 | flex: 1; 4 | overflow: hidden; 5 | flex-direction: row-reverse; 6 | 7 | .sidebar { 8 | position: relative; 9 | width: 250px; 10 | flex-shrink: 0; 11 | overflow: visible; 12 | border-right: 1px solid var(--line-sidebar); 13 | 14 | .hider { 15 | width: 100%; 16 | height: 100%; 17 | position: relative; 18 | overflow: hidden; 19 | } 20 | 21 | dui-splitter { 22 | right: -4px; 23 | } 24 | 25 | &.with-animation { 26 | transition: width 0.3s ease-in-out; 27 | } 28 | 29 | &.hidden { 30 | width: 0 !important; 31 | } 32 | } 33 | 34 | .sidebar-container { 35 | width: 100%; 36 | height: 100%; 37 | max-height: 100%; 38 | position: relative; 39 | overflow: hidden; 40 | text-overflow: ellipsis; 41 | } 42 | 43 | .content { 44 | flex: 1; 45 | position: relative; 46 | padding: 14px; 47 | overflow: auto; 48 | max-height: 100%; 49 | } 50 | 51 | &:not(.transparent) .content { 52 | background-color: var(--dui-window-content-bg); 53 | } 54 | } 55 | 56 | :host.no-vibrancy { 57 | .sidebar { 58 | border-right: 1px solid #c7ced3; 59 | background-color: #dfe6eb; 60 | } 61 | } 62 | 63 | :host-context(.dark) { 64 | &.no-vibrancy { 65 | .sidebar { 66 | background-color: #2a3136; 67 | } 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /packages/native-ui/src/components/window/window-footer.component.scss: -------------------------------------------------------------------------------- 1 | :host { 2 | position: absolute; 3 | left: 0; 4 | right: 0; 5 | bottom: 0; 6 | height: 26px; 7 | line-height: 26px; 8 | font-size: 11px; 9 | padding: 0 10px; 10 | font-weight: 500; 11 | color: rgba(0, 0, 0, 0.73); 12 | background: #F0F0F0; 13 | border-top: 1px solid #CECECE; 14 | } 15 | 16 | :host-context(.dark) { 17 | background: #282c32; 18 | border-top: 1px solid #4a4e54; 19 | color: white; 20 | } 21 | -------------------------------------------------------------------------------- /packages/native-ui/src/components/window/window-footer.component.ts: -------------------------------------------------------------------------------- 1 | import {Component} from "@angular/core"; 2 | 3 | @Component({ 4 | selector: 'dui-window-footer', 5 | template: '', 6 | styleUrls: ['./window-footer.component.scss'] 7 | }) 8 | export class WindowFooterComponent {} 9 | -------------------------------------------------------------------------------- /packages/native-ui/src/components/window/window-frame.component.scss: -------------------------------------------------------------------------------- 1 | :host { 2 | position: relative; 3 | display: block; 4 | margin: 100px 25px; 5 | border-radius: 4px; 6 | box-shadow: 0 12px 40px 4px rgba(0, 0, 0, 0.36); 7 | } 8 | 9 | :host ::ng-deep dui-window { 10 | border-radius: 4px; 11 | overflow: hidden; 12 | } 13 | -------------------------------------------------------------------------------- /packages/native-ui/src/components/window/window-menu.ts: -------------------------------------------------------------------------------- 1 | import {MenuDirective} from "../app/menu.component"; 2 | import {arrayRemoveItem} from "@marcj/estdlib"; 3 | import {Subscription} from "rxjs"; 4 | import {Injectable} from "@angular/core"; 5 | import {Electron} from "../../core/utils"; 6 | 7 | @Injectable() 8 | export class WindowMenuState { 9 | menus: MenuDirective[] = []; 10 | focused = true; 11 | 12 | subscriptions = new Map(); 13 | 14 | addMenu(menu: MenuDirective) { 15 | this.menus.push(menu); 16 | this.subscriptions.set(menu, menu.change.subscribe(() => { 17 | this.build(); 18 | })); 19 | 20 | this.build(); 21 | } 22 | 23 | removeMenu(menu: MenuDirective) { 24 | this.subscriptions.get(menu)!.unsubscribe(); 25 | this.subscriptions.delete(menu); 26 | arrayRemoveItem(this.menus, menu); 27 | this.build(); 28 | } 29 | 30 | build() { 31 | requestAnimationFrame(() => { 32 | this._build(); 33 | }) 34 | } 35 | 36 | protected _build() { 37 | const template = []; 38 | 39 | //todo, merge menus with same id(), id falls back to role+label 40 | // then we can use fileMenu in sub views and add sub menu items as we want 41 | for (const menu of this.menus) { 42 | if (menu.validOs()) { 43 | template.push(menu.buildTemplate()); 44 | } 45 | } 46 | 47 | if (!template.length) { 48 | template.push(...[ 49 | {role: 'appMenu'}, 50 | {role: 'fileMenu'}, 51 | {role: 'editMenu'}, 52 | {role: 'viewMenu'}, 53 | {role: 'windowMenu'}, 54 | ]); 55 | } 56 | 57 | if (Electron.isAvailable()) { 58 | const remote: any = Electron.getRemote(); 59 | if (remote) { 60 | try { 61 | const menu = remote.Menu.buildFromTemplate(template); 62 | remote.Menu.setApplicationMenu(menu); 63 | } catch (error) { 64 | console.error('Could not buildFromTemplate', template); 65 | console.error(error); 66 | } 67 | } else { 68 | console.warn('Not in electron environment'); 69 | } 70 | } 71 | } 72 | 73 | focus() { 74 | //set our electron menu 75 | //Menu.setApplicationMenu() 76 | this.build(); 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /packages/native-ui/src/components/window/window-sidebar.component.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcj/angular-desktop-ui/71f9435eeed6fb23437b45d7a57d9adba5bc93b0/packages/native-ui/src/components/window/window-sidebar.component.scss -------------------------------------------------------------------------------- /packages/native-ui/src/components/window/window-sidebar.component.ts: -------------------------------------------------------------------------------- 1 | import {Component, TemplateRef, ViewChild} from "@angular/core"; 2 | 3 | @Component({ 4 | selector: 'dui-window-sidebar', 5 | template: ` 6 | 7 | 8 | 9 | `, 10 | styleUrls: ['./window-sidebar.component.scss'], 11 | }) 12 | export class WindowSidebarComponent { 13 | @ViewChild('templateRef', {static: true}) public template!: TemplateRef; 14 | } 15 | -------------------------------------------------------------------------------- /packages/native-ui/src/components/window/window.component.scss: -------------------------------------------------------------------------------- 1 | :host { 2 | position: relative; 3 | height: 100%; 4 | width: 100%; 5 | display: flex; 6 | flex-direction: column; 7 | } 8 | 9 | .disable-inputs { 10 | position: absolute; 11 | left: 0; 12 | right: 0; 13 | top: 0; 14 | bottom: 0; 15 | opacity: 0.001; 16 | background-color: black; 17 | z-index: 1000000; 18 | } 19 | 20 | :host-context(.electron.platform-darwin.light) { 21 | background: #ffffffad; 22 | } 23 | 24 | :host-context(.platform-native.dark):not(.in-dialog) { 25 | border-top: 1px solid #868686; 26 | border-right: 1px solid #5d5d5d; 27 | border-left: 1px solid #5d5d5d; 28 | border-bottom: 1px solid #5b5b5b; 29 | } 30 | -------------------------------------------------------------------------------- /packages/native-ui/src/index.ts: -------------------------------------------------------------------------------- 1 | export {ValueAccessorBase, ngValueAccessor} from './core/form'; 2 | export * from './core/form'; 3 | export * from './core/utils'; 4 | export * from './components/app'; 5 | export * from './components/checkbox'; 6 | export * from './components/button'; 7 | export * from './components/input'; 8 | export * from './components/form'; 9 | export * from './components/radiobox'; 10 | export * from './components/select'; 11 | export * from './components/window'; 12 | export * from './components/icon'; 13 | export * from './components/list'; 14 | export * from './components/table'; 15 | export * from './components/splitter'; 16 | export * from './components/dialog'; 17 | export * from './components/core'; 18 | export * from './components/emoji'; 19 | export * from './components/slider'; 20 | export * from './components/indicator'; 21 | -------------------------------------------------------------------------------- /packages/native-ui/src/scss/icon.scss: -------------------------------------------------------------------------------- 1 | @font-face { 2 | font-family: 'Desktop UI icon Mono'; 3 | src: url("../assets/fonts/ui-icons.svg") format('svg'), url("../assets/fonts/ui-icons.woff") format('woff'), url("../assets/fonts/ui-icons.ttf") format('ttf'); 4 | font-weight: normal; 5 | font-style: normal; 6 | } 7 | 8 | .ui-icon { 9 | font-family: 'Desktop UI icon Mono' !important; 10 | font-weight: normal !important; 11 | font-style: normal !important; 12 | font-size: 17px; 13 | display: inline-block; 14 | line-height: 1; 15 | text-transform: none; 16 | letter-spacing: normal; 17 | word-wrap: normal; 18 | white-space: nowrap; 19 | direction: ltr; 20 | 21 | /* Support for all WebKit browsers. */ 22 | -webkit-font-smoothing: antialiased; 23 | /* Support for Safari and Chrome. */ 24 | text-rendering: optimizeLegibility; 25 | 26 | /* Support for Firefox. */ 27 | -moz-osx-font-smoothing: grayscale; 28 | 29 | /* Support for IE. */ 30 | font-feature-settings: 'liga'; 31 | } 32 | -------------------------------------------------------------------------------- /packages/native-ui/src/scss/mixins.scss: -------------------------------------------------------------------------------- 1 | $focusOutlineColor: #6da0e7; 2 | $focusOutlineColorDark: #2a729c; 3 | 4 | @mixin box-textured { 5 | border-top: 1px solid #c9cac9; 6 | border-bottom: 1px solid #a1a1a1; 7 | border-left: 1px solid #c6c7c6; 8 | border-right: 1px solid #c6c7c6; 9 | background-image: linear-gradient(-180deg, #FDFDFD 5%, #FAFAFA 5%, #F6F6F6 55%, #F1F1F1 99%); 10 | box-shadow: none; 11 | } 12 | 13 | @mixin box-textured-active { 14 | background-image: linear-gradient(-180deg, #EEEEEE 5%, #E4E4E4 5%, #E2E2E2 49%, #DCDCDC 100%); 15 | } 16 | 17 | 18 | @mixin box-textured-dark { 19 | color: white; 20 | 21 | background-image: linear-gradient(-180deg, #787878 1px, #696969 1px, #696969 95%); 22 | border-top: 1px solid #313131; 23 | border-bottom: 1px solid #2a2a2a; 24 | border-left: 1px solid #303030; 25 | border-right: 1px solid #303030; 26 | } 27 | 28 | @mixin box-textured-dark-active { 29 | background-image: none; 30 | background-color: #797f84; 31 | } 32 | 33 | @mixin box-textured-dark-toolbar { 34 | background-image: linear-gradient(-180deg, #6A6A6A 0%, #676767 100%); 35 | border-top: 1px solid #7b7b7b; 36 | border-bottom: 1px solid #676767; 37 | border-left: 1px solid #69696a; 38 | border-right: 1px solid #69696a; 39 | box-shadow: none; 40 | } 41 | 42 | @mixin box-textured-dark-toolbar-active { 43 | background-image: linear-gradient(-180deg, #858484 0%, #818181 100%); 44 | border-top: 1px solid #939393; 45 | border-bottom: 1px solid #818181; 46 | border-left: 1px solid #818181; 47 | border-right: 1px solid #818181; 48 | } 49 | 50 | @mixin focus-border { 51 | outline: 0; 52 | border-color: $focusOutlineColor; 53 | box-shadow: 3px 3px 0 $focusOutlineColor, -3px -3px 0 $focusOutlineColor, -3px 3px 0 $focusOutlineColor, 3px -3px 0 $focusOutlineColor; 54 | } 55 | 56 | @mixin focus-border-dark { 57 | border-color: $focusOutlineColorDark; 58 | box-shadow: 3px 3px 0 $focusOutlineColorDark, -3px -3px 0 $focusOutlineColorDark, -3px 3px 0 $focusOutlineColorDark, 3px -3px 0 $focusOutlineColorDark; 59 | } 60 | 61 | 62 | @mixin background-vibrancy { 63 | backdrop-filter: var(--dui-background-vibrancy); 64 | background-color: var(--dui-toolbar-bg-trans); 65 | } 66 | -------------------------------------------------------------------------------- /packages/native-ui/src/scss/reset.scss: -------------------------------------------------------------------------------- 1 | /* http://meyerweb.com/eric/tools/css/reset/ 2 | v2.0 | 20110126 3 | License: none (public domain) 4 | */ 5 | 6 | html, body, div, span, applet, object, iframe, 7 | h1, h2, h3, h4, h5, h6, p, blockquote, pre, 8 | a, abbr, acronym, address, big, cite, code, 9 | del, dfn, em, img, ins, kbd, q, s, samp, 10 | small, strike, strong, sub, sup, tt, var, 11 | b, u, i, center, 12 | dl, dt, dd, ol, ul, li, 13 | fieldset, form, label, legend, 14 | table, caption, tbody, tfoot, thead, tr, th, td, 15 | article, aside, canvas, details, embed, 16 | figure, figcaption, footer, header, hgroup, 17 | menu, nav, output, ruby, section, summary, 18 | time, mark, audio, video { 19 | margin: 0; 20 | padding: 0; 21 | border: 0; 22 | font-size: 100%; 23 | font: inherit; 24 | vertical-align: baseline; 25 | } 26 | 27 | /* HTML5 display-role reset for older browsers */ 28 | article, aside, details, figcaption, figure, 29 | footer, header, hgroup, menu, nav, section { 30 | display: block; 31 | } 32 | 33 | body { 34 | line-height: 1; 35 | } 36 | 37 | blockquote, q { 38 | quotes: none; 39 | } 40 | 41 | blockquote:before, blockquote:after, 42 | q:before, q:after { 43 | content: ''; 44 | content: none; 45 | } 46 | 47 | table { 48 | border-collapse: collapse; 49 | border-spacing: 0; 50 | } 51 | -------------------------------------------------------------------------------- /packages/native-ui/test/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 | -------------------------------------------------------------------------------- /packages/native-ui/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "baseUrl": "./", 4 | "outDir": "./dist", 5 | "moduleResolution": "node", 6 | "emitDecoratorMetadata": true, 7 | "experimentalDecorators": true, 8 | "downlevelIteration": true, 9 | "sourceMap": true, 10 | "declaration": true, 11 | "strict": true, 12 | "target": "es2015", 13 | "esModuleInterop": true, 14 | "typeRoots": [ 15 | "node_modules/@types" 16 | ], 17 | "lib": [ 18 | "es2018", 19 | "dom" 20 | ], 21 | "paths": { 22 | "angular-desktop-ui": [ 23 | "dist/" 24 | ] 25 | } 26 | }, 27 | "include": [ 28 | "./src", 29 | "create-font.ts" 30 | ], 31 | "angularCompilerOptions": { 32 | "fullTemplateTypeCheck": true, 33 | "strictInjectionParameters": true 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /packages/native-ui/tsconfig.lib.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.json", 3 | "compilerOptions": { 4 | "declarationMap": true 5 | }, 6 | "angularCompilerOptions": { 7 | "skipTemplateCodegen": true, 8 | "strictMetadataEmit": true, 9 | "enableResourceInlining": true 10 | }, 11 | "exclude": [ 12 | "src/test.ts", 13 | "**/*.spec.ts" 14 | ] 15 | } 16 | -------------------------------------------------------------------------------- /packages/native-ui/tsconfig.prod.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./tsconfig.lib.json", 3 | "compilerOptions": { 4 | "declarationMap": false 5 | }, 6 | "angularCompilerOptions": { 7 | "enableIvy": false 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /packages/native-ui/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 | -------------------------------------------------------------------------------- /packages/native-ui/tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "rules": { 3 | "directive-selector": [ 4 | true, 5 | "attribute", 6 | "lib", 7 | "camelCase" 8 | ], 9 | "component-selector": [ 10 | true, 11 | "element", 12 | "lib", 13 | "kebab-case" 14 | ] 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /packages/native-ui/webpack.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | 3 | module.exports = { 4 | entry: { 5 | 'create-font': path.resolve(__dirname, 'create-font.ts'), 6 | }, 7 | output: { 8 | filename: '[name].js', 9 | path: path.resolve(__dirname, 'bin/') 10 | }, 11 | resolve: { 12 | extensions: ['.tsx', '.ts', '.js'], 13 | symlinks: false, 14 | }, 15 | target: 'node', 16 | // mode: 'production', 17 | devtool: 'cheap-module-source-map', 18 | node: { 19 | __dirname: false, 20 | __filename: false, 21 | }, 22 | module: { 23 | rules: [ 24 | { 25 | test: /\.ts$/, 26 | loader: 'awesome-typescript-loader', 27 | options: { 28 | allowTsInNodeModules: true, 29 | }, 30 | }, 31 | ] 32 | } 33 | } 34 | ; 35 | --------------------------------------------------------------------------------