Skip to content

Commit

Permalink
feat(email-templates): library and app for email generation (#2243)
Browse files Browse the repository at this point in the history
  • Loading branch information
bsahitya authored Sep 18, 2024
1 parent c35611e commit ad32f51
Show file tree
Hide file tree
Showing 53 changed files with 4,488 additions and 47 deletions.
36 changes: 36 additions & 0 deletions apps/email-generator/.eslintrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
{
"extends": ["../../.eslintrc.json"],
"ignorePatterns": ["!**/*"],
"overrides": [
{
"files": ["*.ts"],
"extends": [
"plugin:@nx/angular",
"plugin:@angular-eslint/template/process-inline-templates"
],
"rules": {
"@angular-eslint/directive-selector": [
"error",
{
"type": "attribute",
"prefix": "app",
"style": "camelCase"
}
],
"@angular-eslint/component-selector": [
"error",
{
"type": "element",
"prefix": "app",
"style": "kebab-case"
}
]
}
},
{
"files": ["*.html"],
"extends": ["plugin:@nx/angular-template"],
"rules": {}
}
]
}
27 changes: 27 additions & 0 deletions apps/email-generator/jest.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
/* eslint-disable */
export default {
displayName: 'email-generator',
preset: '../../jest.preset.js',
setupFilesAfterEnv: ['<rootDir>/src/test-setup.ts'],
globals: {},
coverageDirectory: '../../coverage/apps/email-generator',
transform: {
'^.+\\.(ts|mjs|js|html)$': [
'jest-preset-angular',
{
tsconfig: '<rootDir>/tsconfig.spec.json',
stringifyContentPathRegex: '\\.(html|svg)$',
},
],
},
transformIgnorePatterns: [
'node_modules/(?!.*\\.mjs$)',
'node_modules/(?!(monaco-editor)/)',
],
snapshotSerializers: [
'jest-preset-angular/build/serializers/no-ng-attributes',
'jest-preset-angular/build/serializers/ng-snapshot',
'jest-preset-angular/build/serializers/html-comment',
],
passWithNoTests: true,
};
32 changes: 32 additions & 0 deletions apps/email-generator/monaco-webpack.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
const MonacoWebpackPlugin = require('monaco-editor-webpack-plugin');

module.exports = {
module: {
rules: [
{
test: /\.css$/,
resourceQuery: /raw/, // This will only match .css?raw
use: 'raw-loader',
},
{
test: /\.mjml$/,
resourceQuery: /raw/, // This will only match .mjml?raw
use: 'raw-loader',
},
{
test: /\.css$/,
include: [/node_modules\/monaco-editor/],
use: ['style-loader', 'css-loader'],
},
{
test: /\.ttf$/,
type: 'asset/resource',
},
],
},
plugins: [
new MonacoWebpackPlugin({
languages: ['css', 'html'],
}),
],
};
93 changes: 93 additions & 0 deletions apps/email-generator/project.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
{
"name": "email-generator",
"$schema": "../../node_modules/nx/schemas/project-schema.json",
"projectType": "application",
"prefix": "app",
"sourceRoot": "apps/email-generator/src",
"tags": [],
"targets": {
"build": {
"executor": "@angular-builders/custom-webpack:browser",
"outputs": ["{options.outputPath}"],
"options": {
"customWebpackConfig": {
"path": "apps/email-generator/monaco-webpack.config.js",
"mergeRules": {
"module.rules": "prepend"
}
},
"allowedCommonJsDependencies": [
"monaco-editor",
"@covalent/email-templates"
],
"outputPath": "dist/apps/email-generator",
"index": "apps/email-generator/src/index.html",
"main": "apps/email-generator/src/main.ts",
"polyfills": ["zone.js"],
"tsConfig": "apps/email-generator/tsconfig.app.json",
"inlineStyleLanguage": "scss",
"assets": [
"apps/email-generator/src/favicon.ico",
"apps/email-generator/src/assets"
],
"styles": ["apps/email-generator/src/styles.scss"],
"scripts": []
},
"configurations": {
"production": {
"budgets": [
{
"type": "initial",
"maximumWarning": "5mb",
"maximumError": "6mb"
},
{
"type": "anyComponentStyle",
"maximumWarning": "2kb",
"maximumError": "4kb"
}
],
"outputHashing": "all"
},
"development": {
"buildOptimizer": false,
"optimization": false,
"vendorChunk": true,
"extractLicenses": false,
"sourceMap": true,
"namedChunks": true
}
},
"defaultConfiguration": "production"
},
"serve": {
"executor": "@angular-builders/custom-webpack:dev-server",
"configurations": {
"production": {
"buildTarget": "email-generator:build:production"
},
"development": {
"buildTarget": "email-generator:build:development"
}
},
"defaultConfiguration": "development"
},

"lint": {
"executor": "@nx/eslint:lint"
},
"test": {
"executor": "@nx/jest:jest",
"outputs": ["{workspaceRoot}/coverage/{projectRoot}"],
"options": {
"jestConfig": "apps/email-generator/jest.config.ts"
}
},
"serve-static": {
"executor": "@nx/web:file-server",
"options": {
"buildTarget": "email-generator:build"
}
}
}
}
27 changes: 27 additions & 0 deletions apps/email-generator/src/app/app.component.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<div class="app">
<div class="title">
<span
class="material-symbols-outlined menu-icon"
(click)="toggleSideSheet()"
>
menu
</span>
<img
src="https://cdn.jsdelivr.net/gh/bsahitya/wysiwyg-email-editor/public/images/teradata.svg"
alt=""
/>
<h2>Email generator</h2>
</div>
<app-editor [value]="selectedTemplate"></app-editor>
</div>
<app-side-sheet
[isOpen]="isSideSheetOpen"
(closeSheet)="toggleSideSheet()"
title="Templates"
>
<app-tree-list
#template
[nodes]="templateNodes"
(itemClick)="selectTemplate($event)"
></app-tree-list>
</app-side-sheet>
44 changes: 44 additions & 0 deletions apps/email-generator/src/app/app.component.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
.app {
background-color: var(--cv-light-background);
}

.title {
align-items: center;
display: flex;
gap: 0.75rem;
padding: 0.75rem;
}

.title h2 {
font-weight: 500;
margin: 0.25rem 0 0 0.25rem;
}

.title img {
width: 65px;
}

.material-symbols-outlined {
font-family: 'Material Symbols Outlined';
font-weight: 600;
font-style: normal;
font-size: 24px; /* Preferred icon size */
display: inline-block;
line-height: 1;
text-transform: none;
letter-spacing: normal;
word-wrap: normal;
white-space: nowrap;
direction: ltr;
}

.menu-icon {
cursor: pointer;
padding: 5px;
}

.menu-icon:hover {
background-color: var(--cv-light-secondary);
border-radius: 50%;
color: var(--cv-light-on-secondary);
}
68 changes: 68 additions & 0 deletions apps/email-generator/src/app/app.component.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import { Component } from '@angular/core';
import { RouterModule } from '@angular/router';
import { EditorComponent } from './editor/editor.component';
import {
TemplateNode,
TreeListComponent,
} from './tree-list/tree-list.component';
import { CommonModule } from '@angular/common';
import { SideSheetComponent } from './side-sheet/side-sheet.component';
import { getEmailTemplates, EmailTemplate } from '@covalent/email-templates';

@Component({
standalone: true,
imports: [
CommonModule,
RouterModule,
EditorComponent,
TreeListComponent,
SideSheetComponent,
],
selector: 'app-root',
templateUrl: './app.component.html',
styleUrl: './app.component.scss',
})
export class AppComponent {
emailTemplates = getEmailTemplates();
isSideSheetOpen = false;
selectedTemplate = '';
templateNodes: TemplateNode[] = [];
title = 'Email Editor';

constructor() {
this.parseTemplates(this.emailTemplates);
}

parseTemplates(data: EmailTemplate[]): void {
this.templateNodes = [];
const categories: { [key: string]: TemplateNode } = {};

data.forEach((item) => {
if (!categories[item.category]) {
// Create a new category node if it doesn't exist
categories[item.category] = {
title: item.category,
templates: [],
};
}

// Add the individual template to the category's templates
categories[item.category].templates?.push({
title: item.name,
value: item.content,
});
});

// Convert the categories object into an array of TemplateNodes
this.templateNodes = Object.values(categories);
this.selectedTemplate = this.emailTemplates[0].content;
}

selectTemplate(template: string): void {
this.selectedTemplate = template;
}

toggleSideSheet(): void {
this.isSideSheetOpen = !this.isSideSheetOpen;
}
}
7 changes: 7 additions & 0 deletions apps/email-generator/src/app/app.config.ts
Original file line number Diff line number Diff line change
@@ -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)],
};
3 changes: 3 additions & 0 deletions apps/email-generator/src/app/app.routes.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import { Route } from '@angular/router';

export const appRoutes: Route[] = [];
24 changes: 24 additions & 0 deletions apps/email-generator/src/app/editor/editor.component.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<div class="editor-container">
<div class="editor-left">
<div class="buttons">
<button (click)="formatCode()">FORMAT</button>
<button (click)="handleCopyClick('mjml')">COPY MJML</button>
<button (click)="handleCopyClick('html')">COPY HTML</button>
</div>
<td-code-editor
(editorInitialized)="handleEditorInitialisation($event)"
[style.height]="'calc(100vh - 125px)'"
language="html"
[editorOptions]="{
minimap: { enabled: false },
scrollBeyondLastLine: false,
}"
[theme]="'cv-light'"
[value]="value"
(editorValueChange)="handleValueChange()"
></td-code-editor>
</div>
<div class="editor-right">
<app-preview [html]="htmlContent"></app-preview>
</div>
</div>
Loading

0 comments on commit ad32f51

Please sign in to comment.