From 21ddb0c782aca39ff75b67c1649741cea581e7c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marina=20L=C3=B3pez?= Date: Fri, 24 May 2024 17:09:25 +0200 Subject: [PATCH] feat: create table plugin --- README.md | 2 +- apps/table-plugin/eslint.config.js | 43 + apps/table-plugin/project.json | 89 ++ apps/table-plugin/src/app/app.component.css | 123 +++ apps/table-plugin/src/app/app.component.html | 91 ++ apps/table-plugin/src/app/app.component.ts | 123 +++ apps/table-plugin/src/app/app.config.ts | 7 + apps/table-plugin/src/app/app.routes.ts | 3 + apps/table-plugin/src/app/model.ts | 35 + .../src/app/nx-welcome.component.ts | 907 ++++++++++++++++++ apps/table-plugin/src/assets/.gitkeep | 0 apps/table-plugin/src/assets/close.svg | 1 + .../src/assets/icon.png} | Bin apps/table-plugin/src/assets/manifest.json | 8 + apps/table-plugin/src/favicon.ico | Bin 0 -> 15086 bytes apps/table-plugin/src/index.html | 13 + apps/table-plugin/src/main.ts | 7 + apps/table-plugin/src/plugin.ts | 120 +++ apps/table-plugin/src/styles.css | 1 + apps/table-plugin/tsconfig.app.json | 10 + apps/table-plugin/tsconfig.editor.json | 7 + apps/table-plugin/tsconfig.json | 33 + apps/table-plugin/tsconfig.plugin.json | 8 + package.json | 4 +- 24 files changed, 1631 insertions(+), 4 deletions(-) create mode 100644 apps/table-plugin/eslint.config.js create mode 100644 apps/table-plugin/project.json create mode 100644 apps/table-plugin/src/app/app.component.css create mode 100644 apps/table-plugin/src/app/app.component.html create mode 100644 apps/table-plugin/src/app/app.component.ts create mode 100644 apps/table-plugin/src/app/app.config.ts create mode 100644 apps/table-plugin/src/app/app.routes.ts create mode 100644 apps/table-plugin/src/app/model.ts create mode 100644 apps/table-plugin/src/app/nx-welcome.component.ts create mode 100644 apps/table-plugin/src/assets/.gitkeep create mode 100644 apps/table-plugin/src/assets/close.svg rename apps/{avatar_plugin_table.png => table-plugin/src/assets/icon.png} (100%) create mode 100644 apps/table-plugin/src/assets/manifest.json create mode 100644 apps/table-plugin/src/favicon.ico create mode 100644 apps/table-plugin/src/index.html create mode 100644 apps/table-plugin/src/main.ts create mode 100644 apps/table-plugin/src/plugin.ts create mode 100644 apps/table-plugin/src/styles.css create mode 100644 apps/table-plugin/tsconfig.app.json create mode 100644 apps/table-plugin/tsconfig.editor.json create mode 100644 apps/table-plugin/tsconfig.json create mode 100644 apps/table-plugin/tsconfig.plugin.json diff --git a/README.md b/README.md index 8fea2d6..fcb56be 100644 --- a/README.md +++ b/README.md @@ -71,7 +71,7 @@ Open in your browser: `http://localhost:4210/` | icons-plugin | Tool to add icons from [Feather](https://feathericons.com/) | 4303 | npm run start:plugin:icons | http://localhost:4303/assets/manifest.json | | lorem-ipsum-plugin | Generate Lorem ipsum text | 4304 | npm run start:plugin:loremipsum | http://localhost:4304/assets/manifest.json | | create-palette-plugin | Creates a board with all the palette colors | 4305 | npm run start:plugin:palette | http://localhost:4305/assets/manifest.json | -| import-table | -- | 4306 | -- | -- | +| table-plugin | Create or import table | 4306 | npm run start:table-plugin | http://localhost:4306/assets/manifest.json | | -- | ## Web Apps diff --git a/apps/table-plugin/eslint.config.js b/apps/table-plugin/eslint.config.js new file mode 100644 index 0000000..29c2176 --- /dev/null +++ b/apps/table-plugin/eslint.config.js @@ -0,0 +1,43 @@ +import baseConfig from '../../eslint.config.js'; +import { compat } from '../../eslint.base.config.js'; + +export default [ + ...baseConfig, + ...compat + .config({ + extends: [ + 'plugin:@nx/angular', + 'plugin:@angular-eslint/template/process-inline-templates', + ], + }) + .map((config) => ({ + ...config, + files: ['**/*.ts'], + rules: { + '@angular-eslint/directive-selector': [ + 'error', + { + type: 'attribute', + prefix: 'app', + style: 'camelCase', + }, + ], + '@angular-eslint/component-selector': [ + 'error', + { + type: 'element', + prefix: 'app', + style: 'kebab-case', + }, + ], + }, + })), + ...compat + .config({ extends: ['plugin:@nx/angular-template'] }) + .map((config) => ({ + ...config, + files: ['**/*.html'], + rules: {}, + })), + { ignores: ['**/assets/*.js'] }, +]; diff --git a/apps/table-plugin/project.json b/apps/table-plugin/project.json new file mode 100644 index 0000000..0b44595 --- /dev/null +++ b/apps/table-plugin/project.json @@ -0,0 +1,89 @@ +{ + "name": "table-plugin", + "$schema": "../../node_modules/nx/schemas/project-schema.json", + "projectType": "application", + "prefix": "app", + "sourceRoot": "apps/table-plugin/src", + "tags": [], + "targets": { + "build": { + "executor": "@angular-devkit/build-angular:application", + "outputs": ["{options.outputPath}"], + "options": { + "outputPath": "dist/apps/table-plugin", + "index": "apps/table-plugin/src/index.html", + "browser": "apps/table-plugin/src/main.ts", + "polyfills": ["zone.js"], + "tsConfig": "apps/table-plugin/tsconfig.app.json", + "assets": [ + "apps/table-plugin/src/favicon.ico", + "apps/table-plugin/src/assets" + ], + "styles": [ + "libs/plugins-styles/src/lib/styles.css", + "apps/table-plugin/src/styles.css" + ], + "optimization": { + "scripts": true, + "styles": true, + "fonts": false + }, + "scripts": [] + }, + "configurations": { + "production": { + "budgets": [ + { + "type": "initial", + "maximumWarning": "500kb", + "maximumError": "1mb" + }, + { + "type": "anyComponentStyle", + "maximumWarning": "2kb", + "maximumError": "4kb" + } + ], + "outputHashing": "all" + }, + "development": { + "optimization": false, + "extractLicenses": false, + "sourceMap": true + } + }, + "defaultConfiguration": "production" + }, + "serve": { + "executor": "@angular-devkit/build-angular:dev-server", + "configurations": { + "production": { + "buildTarget": "table-plugin:build:production" + }, + "development": { + "buildTarget": "table-plugin:build:development" + } + }, + "defaultConfiguration": "development" + }, + "extract-i18n": { + "executor": "@angular-devkit/build-angular:extract-i18n", + "options": { + "buildTarget": "table-plugin:build" + } + }, + "buildPlugin": { + "executor": "@nx/esbuild:esbuild", + "outputs": ["{options.outputPath}"], + "options": { + "minify": true, + "outputPath": "apps/table-plugin/src/assets/", + "main": "apps/table-plugin/src/plugin.ts", + "tsConfig": "apps/table-plugin/tsconfig.plugin.json", + "generatePackageJson": false, + "format": ["esm"], + "deleteOutputPath": false + } + } + } +} diff --git a/apps/table-plugin/src/app/app.component.css b/apps/table-plugin/src/app/app.component.css new file mode 100644 index 0000000..cd44abd --- /dev/null +++ b/apps/table-plugin/src/app/app.component.css @@ -0,0 +1,123 @@ +.text { + margin-block-start: var(--spacing-24); +} + +.input-container { + background-color: var(--db-tertiary); + border-radius: var(--spacing-8); + color: #8a9ca2; + font-size: var(--font-size-s); + font-weight: var(--font-weight-bold); + line-height: var(--font-line-height-s); + margin-block-start: var(--spacing-8); + padding: var(--spacing-8) var(--spacing-24) var(--spacing-8) var(--spacing-24); + text-transform: uppercase; + &:hover { + cursor: pointer; + } +} +.inputfile { + block-size: 1px; + border: 0; + clip: rect(1px 1px 1px 1px); + clip: rect(1px, 1px, 1px, 1px); + clip-path: inset(50%); + inline-size: 1px; + margin: 0; + overflow: hidden; + padding: 0; + position: absolute; + white-space: nowrap; +} + +.inputfile + label { + display: block; + text-align: center; + + &:hover { + cursor: pointer; + } +} + +hr { + border-block-end: 2px solid var(--db-quaternary); + margin-block: var(--spacing-24); +} + +.table-grid { + background-color: var(--db-tertiary); + display: grid; + grid-template-columns: repeat(8, auto); + grid-template-rows: repeat(6, auto); + border-radius: var(--spacing-8); + padding: 10px; + margin-block: var(--spacing-16) var(--spacing-20); +} + +.cell { + align-items: center; + block-size: 26px; + display: flex; + justify-content: center; +} + +.square { + block-size: 22px; + border: 1px solid var(--df-secondary); + border-radius: var(--spacing-4); + display: block; + inline-size: 22px; + + &.active { + background-color: var(--da-primary); + } + + &:hover { + background-color: var(--da-tertiary); + cursor: pointer; + } +} + +.checkbox-container { + margin-block-end: var(--spacing-12); +} + +.new-table { + align-items: center; + block-size: 22px; + display: flex; + justify-content: space-between; + + & .text { + margin-block-start: 0; + } +} + +.tag { + border: 1px solid var(--da-primary); + border-radius: var(--spacing-4); + color: var(--da-primary); + font-size: var(--font-size-s); + font-weight: var(--font-weight-bold); + line-height: var(--font-line-height-s); + padding: var(--spacing-4); +} + +.error { + align-items: center; + background-color: var(--error-950); + border: 1px solid var(--error-700); + border-radius: var(--spacing-8); + display: flex; + margin-block-start: var(--spacing-8); + padding: var(--spacing-8); + + & .close-icon:hover { + cursor: pointer; + } + + & .message { + color: var(--lb-primary); + margin-inline-start: var(--spacing-8); + } +} diff --git a/apps/table-plugin/src/app/app.component.html b/apps/table-plugin/src/app/app.component.html new file mode 100644 index 0000000..55950be --- /dev/null +++ b/apps/table-plugin/src/app/app.component.html @@ -0,0 +1,91 @@ +
+

Import a data file (CSV)

+
+ close error + Something was wrong.
+ Make sure the formst is .csv
+
+
+ + +
+
+
+

Or create a new table

+ {{ selectedRow }} rows x {{ selectedColumn }} cols +
+
+ + + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
diff --git a/apps/table-plugin/src/app/app.component.ts b/apps/table-plugin/src/app/app.component.ts new file mode 100644 index 0000000..a42dfce --- /dev/null +++ b/apps/table-plugin/src/app/app.component.ts @@ -0,0 +1,123 @@ +import { Component, inject } from '@angular/core'; +import { ActivatedRoute, RouterModule } from '@angular/router'; +import { toSignal } from '@angular/core/rxjs-interop'; +import { CommonModule } from '@angular/common'; +import type { Cell, PluginMessageEvent, TableOptions } from '../app/model'; +import { filter, fromEvent, map, merge, take } from 'rxjs'; +import { FormsModule } from '@angular/forms'; + +@Component({ + standalone: true, + imports: [RouterModule, CommonModule, FormsModule], + selector: 'app-root', + templateUrl: './app.component.html', + styleUrl: './app.component.css', + host: { + '[attr.data-theme]': 'theme()', + }, +}) +export class AppComponent { + public table: string[][] = []; + public cells = [...Array(48).keys()]; + public selectedRow = 0; + public selectedColumn = 0; + public selectedCell: Cell | undefined; + public tableOptions: TableOptions = { + filledHeaderRow: true, + filledHeaderColumn: false, + borders: true, + alternateRows: true, + }; + public fileError = false; + + route = inject(ActivatedRoute); + messages$ = fromEvent>(window, 'message'); + + initialTheme$ = this.route.queryParamMap.pipe( + map((params) => params.get('theme')), + filter((theme) => !!theme), + take(1) + ); + + theme = toSignal( + merge( + this.initialTheme$, + this.messages$.pipe( + filter((event) => event.data.type === 'theme'), + map((event) => { + return event.data.content; + }) + ) + ) + ); + + onSelectFile(event: Event) { + const target = event.target as HTMLInputElement; + if ( + target.files && + target.files[0] && + target.files[0].type === 'text/csv' + ) { + var reader = new FileReader(); + reader.readAsText(target.files[0]); + reader.onload = (e) => { + this.table = (e?.target?.result as string) + ?.split(/\r?\n|\r|\n/g) + .map((it) => it.trim()) + .filter((it) => it !== '') + .map((it) => it.split(',')); + + this.sendMessage({ + content: { + import: this.table, + type: 'import', + options: this.tableOptions, + }, + type: 'table', + }); + }; + } else { + this.fileError = true; + } + } + + createTable(cell: number) { + const data = this.getCellColRow(cell); + this.sendMessage({ + content: { + new: { column: data.column, row: data.row }, + type: 'new', + options: this.tableOptions, + }, + type: 'table', + }); + } + + setColRow(cell: number) { + this.clearError(); + this.selectedCell = this.getCellColRow(cell); + this.selectedColumn = this.selectedCell.column; + this.selectedRow = this.selectedCell.row; + } + + clearColRow() { + this.selectedCell = undefined; + this.selectedColumn = 0; + this.selectedRow = 0; + } + + clearError() { + this.fileError = false; + } + + getCellColRow(cell: number) { + return { + column: (cell % 8) + 1, + row: Math.floor(cell / 8) + 1, + }; + } + + private sendMessage(message: PluginMessageEvent): void { + parent.postMessage(message, '*'); + } +} diff --git a/apps/table-plugin/src/app/app.config.ts b/apps/table-plugin/src/app/app.config.ts new file mode 100644 index 0000000..ed40494 --- /dev/null +++ b/apps/table-plugin/src/app/app.config.ts @@ -0,0 +1,7 @@ +import { ApplicationConfig } from '@angular/core'; +import { provideRouter } from '@angular/router'; +import { appRoutes } from './app.routes'; + +export const appConfig: ApplicationConfig = { + providers: [provideRouter(appRoutes)], +}; diff --git a/apps/table-plugin/src/app/app.routes.ts b/apps/table-plugin/src/app/app.routes.ts new file mode 100644 index 0000000..8762dfe --- /dev/null +++ b/apps/table-plugin/src/app/app.routes.ts @@ -0,0 +1,3 @@ +import { Route } from '@angular/router'; + +export const appRoutes: Route[] = []; diff --git a/apps/table-plugin/src/app/model.ts b/apps/table-plugin/src/app/model.ts new file mode 100644 index 0000000..70efa6b --- /dev/null +++ b/apps/table-plugin/src/app/model.ts @@ -0,0 +1,35 @@ +export interface InitPluginEvent { + type: 'init'; + content: { + theme: string; + }; +} + +export interface TablePluginEvent { + type: 'table'; + content: { + import?: string[][]; + new?: Cell; + type: 'new' | 'import'; + options: TableOptions; + }; +} + +export interface ThemePluginEvent { + type: 'theme'; + content: string; +} + +export type PluginMessageEvent = + | InitPluginEvent + | TablePluginEvent + | ThemePluginEvent; + +export type Cell = { column: number; row: number }; + +export type TableOptions = { + filledHeaderRow: boolean; + filledHeaderColumn: boolean; + borders: boolean; + alternateRows: boolean; +}; diff --git a/apps/table-plugin/src/app/nx-welcome.component.ts b/apps/table-plugin/src/app/nx-welcome.component.ts new file mode 100644 index 0000000..d473ea1 --- /dev/null +++ b/apps/table-plugin/src/app/nx-welcome.component.ts @@ -0,0 +1,907 @@ +import { Component, ViewEncapsulation } from '@angular/core'; +import { CommonModule } from '@angular/common'; + +@Component({ + selector: 'app-nx-welcome', + standalone: true, + imports: [CommonModule], + template: ` + + +
+
+ +
+

+ Hello there, + Welcome table-plugin 👋 +

+
+ +
+
+

+ + + + You're up and running +

+ What's next? +
+
+ + + +
+
+ + + +
+

Next steps

+

Here are some things you can do with Nx:

+
+ + + + + Add UI library + +
# Generate UI lib
+nx g @nx/angular:lib ui
+# Add a component
+nx g @nx/angular:component ui/src/lib/button
+
+
+ + + + + View project details + +
nx show project table-plugin --web
+
+
+ + + + + View interactive project graph + +
nx graph
+
+
+ + + + + Run affected commands + +
# see what's been affected by changes
+nx affected:graph
+# run tests for current changes
+nx affected:test
+# run e2e tests for current changes
+nx affected:e2e
+
+
+

+ Carefully crafted with + + + +

+
+
+ `, + styles: [], + encapsulation: ViewEncapsulation.None, +}) +export class NxWelcomeComponent {} diff --git a/apps/table-plugin/src/assets/.gitkeep b/apps/table-plugin/src/assets/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/apps/table-plugin/src/assets/close.svg b/apps/table-plugin/src/assets/close.svg new file mode 100644 index 0000000..b9f8c89 --- /dev/null +++ b/apps/table-plugin/src/assets/close.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/apps/avatar_plugin_table.png b/apps/table-plugin/src/assets/icon.png similarity index 100% rename from apps/avatar_plugin_table.png rename to apps/table-plugin/src/assets/icon.png diff --git a/apps/table-plugin/src/assets/manifest.json b/apps/table-plugin/src/assets/manifest.json new file mode 100644 index 0000000..c603dac --- /dev/null +++ b/apps/table-plugin/src/assets/manifest.json @@ -0,0 +1,8 @@ +{ + "name": "Table plugin", + "host": "http://localhost:4306", + "description": "Table plugin to import or create tables", + "code": "/assets/plugin.js", + "icon": "/assets/icon.png", + "permissions": ["page:read", "file:read", "selection:read"] +} diff --git a/apps/table-plugin/src/favicon.ico b/apps/table-plugin/src/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..317ebcb2336e0833a22dddf0ab287849f26fda57 GIT binary patch literal 15086 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 + + + + table-plugin + + + + + + + + diff --git a/apps/table-plugin/src/main.ts b/apps/table-plugin/src/main.ts new file mode 100644 index 0000000..514c89a --- /dev/null +++ b/apps/table-plugin/src/main.ts @@ -0,0 +1,7 @@ +import { bootstrapApplication } from '@angular/platform-browser'; +import { appConfig } from './app/app.config'; +import { AppComponent } from './app/app.component'; + +bootstrapApplication(AppComponent, appConfig).catch((err) => + console.error(err) +); diff --git a/apps/table-plugin/src/plugin.ts b/apps/table-plugin/src/plugin.ts new file mode 100644 index 0000000..a27b397 --- /dev/null +++ b/apps/table-plugin/src/plugin.ts @@ -0,0 +1,120 @@ +import { PluginMessageEvent } from './app/model'; + +penpot.ui.open('Plugin table', `?theme=${penpot.getTheme()}`, { + width: 235, + height: 510, +}); + +penpot.on('themechange', (theme) => { + penpot.ui.sendMessage({ type: 'theme', content: theme }); +}); + +penpot.ui.onMessage((message) => { + if (message.type === 'table') { + let numRows = 0; + let numCols = 0; + if (message.content.type === 'import' && message.content.import) { + numRows = message.content.import.length; + numCols = message.content.import[0].length; + } else if (message.content.new) { + numRows = message.content.new.row; + numCols = message.content.new.column; + } + + const frame = penpot.createFrame(); + frame.name = 'Table'; + + const viewport = penpot.viewport; + frame.x = viewport.center.x - 150; + frame.y = viewport.center.y - 200; + frame.resize(numCols * 160, numRows * 50); + frame.borderRadius = 8; + + // create grid + const grid = frame.addGridLayout(); + + for (let i = 0; i < numRows; i++) { + grid.addRow('auto'); + } + + for (let i = 0; i < numCols; i++) { + grid.addColumn('auto'); + } + + grid.alignItems = 'center'; + grid.justifyItems = 'start'; + grid.justifyContent = 'stretch'; + grid.alignContent = 'stretch'; + + // create text + for (let row = 0; row < numRows; row++) { + for (let col = 0; col < numCols; col++) { + const board = penpot.createFrame(); + + if (col === 0 && row === 0) { + board.borderRadiusTopLeft = 8; + } else if (col === 0 && row === numRows - 1) { + board.borderRadiusBottomRight = 8; + } else if (col === numCols - 1 && row === 0) { + board.borderRadiusTopRight = 8; + } else if (col === numCols - 1 && row === numRows - 1) { + board.borderRadiusBottomRight = 8; + } + + grid.appendChild(board, row + 1, col + 1); + + if (board.layoutChild) { + board.layoutChild.horizontalSizing = 'fill'; + board.layoutChild.verticalSizing = 'fill'; + } + + if (message.content.options.alternateRows && !(row % 2)) { + board.fills = [{ fillColor: '#f8f9fc' }]; + } + + if ( + (message.content.options.filledHeaderRow && row === 0) || + (message.content.options.filledHeaderColumn && col === 0) + ) { + board.fills = [{ fillColor: '#d9dfea' }]; + } + + if (message.content.options.borders) { + board.strokes = [ + { + strokeColor: '#d4dadc', + strokeStyle: 'solid', + strokeWidth: 0.5, + strokeAlignment: 'center', + }, + ]; + } + + const flex = board.addFlexLayout(); + flex.alignItems = 'center'; + flex.justifyContent = 'start'; + flex.verticalPadding = 10; + flex.horizontalPadding = 20; + + let text; + if (message.content.type === 'import' && message.content.import) { + text = penpot.createText(message.content.import[row][col]); + } else if (message.content.new) { + text = + row === 0 ? penpot.createText('Header') : penpot.createText('Cell'); + } + + if (text) { + text.growType = 'auto-width'; + text.fontFamily = 'Work Sans'; + text.fontId = 'gfont-work-sans'; + text.fontVariantId = row === 0 ? '500' : 'regular'; + text.fontSize = '12'; + text.fontWeight = row === 0 ? '500' : '400'; + board.appendChild(text); + } + } + } + penpot.closePlugin(); + } +}); diff --git a/apps/table-plugin/src/styles.css b/apps/table-plugin/src/styles.css new file mode 100644 index 0000000..90d4ee0 --- /dev/null +++ b/apps/table-plugin/src/styles.css @@ -0,0 +1 @@ +/* You can add global styles to this file, and also import other style files */ diff --git a/apps/table-plugin/tsconfig.app.json b/apps/table-plugin/tsconfig.app.json new file mode 100644 index 0000000..fff4a41 --- /dev/null +++ b/apps/table-plugin/tsconfig.app.json @@ -0,0 +1,10 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "../../dist/out-tsc", + "types": [] + }, + "files": ["src/main.ts"], + "include": ["src/**/*.d.ts"], + "exclude": ["jest.config.ts", "src/**/*.test.ts", "src/**/*.spec.ts"] +} diff --git a/apps/table-plugin/tsconfig.editor.json b/apps/table-plugin/tsconfig.editor.json new file mode 100644 index 0000000..4ee6393 --- /dev/null +++ b/apps/table-plugin/tsconfig.editor.json @@ -0,0 +1,7 @@ +{ + "extends": "./tsconfig.json", + "include": ["src/**/*.ts"], + "compilerOptions": { + "types": [] + } +} diff --git a/apps/table-plugin/tsconfig.json b/apps/table-plugin/tsconfig.json new file mode 100644 index 0000000..4c48587 --- /dev/null +++ b/apps/table-plugin/tsconfig.json @@ -0,0 +1,33 @@ +{ + "compilerOptions": { + "target": "es2022", + "useDefineForClassFields": false, + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true, + "strict": true, + "noImplicitOverride": true, + "noPropertyAccessFromIndexSignature": true, + "noImplicitReturns": true, + "noFallthroughCasesInSwitch": true + }, + "files": [], + "include": [], + "references": [ + { + "path": "./tsconfig.app.json" + }, + { + "path": "./tsconfig.editor.json" + }, + { + "path": "./tsconfig.plugin.json" + } + ], + "extends": "../../tsconfig.base.json", + "angularCompilerOptions": { + "enableI18nLegacyMessageIdFormat": false, + "strictInjectionParameters": true, + "strictInputAccessModifiers": true, + "strictTemplates": true + } +} diff --git a/apps/table-plugin/tsconfig.plugin.json b/apps/table-plugin/tsconfig.plugin.json new file mode 100644 index 0000000..961987f --- /dev/null +++ b/apps/table-plugin/tsconfig.plugin.json @@ -0,0 +1,8 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "types": [] + }, + "files": ["src/plugin.ts"], + "include": ["../../libs/plugin-types/index.d.ts"] +} diff --git a/package.json b/package.json index bf72043..4abe7ca 100644 --- a/package.json +++ b/package.json @@ -5,17 +5,15 @@ "license": "MIT", "scripts": { "start": "npm run start:app:runtime", - "start:app:runtime": "concurrently --kill-others --names build,server \"npx nx run plugins-runtime:build --watch --mode development\" \"npx nx run plugins-runtime:preview\"", "start:app:styles-example": "npx nx run example-styles:serve --host 0.0.0.0 --port 4201", - "start:plugin:all": "concurrently --kill-others \"npm:start:plugin:*(!all)\"", "start:plugin:poc-state": "npx nx run-many --targets=buildPlugin,serve --projects=poc-state-plugin --watch --host 0.0.0.0 --port 4301", "start:contrast-plugin": "npx nx run-many --targets=buildPlugin,serve --projects=contrast-plugin --watch --host 0.0.0.0 --port 4302", "start:plugin:icons": "npx nx run-many --targets=buildPlugin,serve --projects=icons-plugin --watch --host 0.0.0.0 --port 4303", "start:plugin:loremipsum": "npx nx run-many --targets=buildPlugin,serve --projects=lorem-ipsum-plugin --watch --port 4304", "start:plugin:palette": "npx nx run create-palette-plugin:build --watch & npx nx run create-palette-plugin:preview", - + "start:plugin:table": "npx nx run-many --targets=buildPlugin,serve --projects=table-plugin --watch --port 4306", "build": "npx nx build plugins-runtime --emptyOutDir=true", "lint": "nx run-many --all --target=lint --parallel", "lint:affected": "npx nx affected --target=lint",