diff --git a/console/package-lock.json b/console/package-lock.json index 19876cb786..e4f541e63d 100644 --- a/console/package-lock.json +++ b/console/package-lock.json @@ -37,6 +37,7 @@ "libphonenumber-js": "^1.10.30", "material-design-icons-iconfont": "^6.1.1", "moment": "^2.29.4", + "opentype.js": "^1.3.4", "ngx-color": "^9.0.0", "rxjs": "~7.8.0", "tinycolor2": "^1.6.0", @@ -61,6 +62,7 @@ "@types/jasminewd2": "~2.0.10", "@types/jsonwebtoken": "^9.0.1", "@types/node": "^18.15.11", + "@types/opentype.js": "^1.3.4", "@types/qrcode": "^1.5.0", "@types/uuid": "^9.0.1", "@typescript-eslint/eslint-plugin": "^5.59.11", @@ -4458,6 +4460,12 @@ "resolved": "https://registry.npmjs.org/@types/node/-/node-18.16.9.tgz", "integrity": "sha512-IeB32oIV4oGArLrd7znD2rkHQ6EDCM+2Sr76dJnrHwv9OHBTTM6nuDLK9bmikXzPa0ZlWMWtRGo/Uw4mrzQedA==" }, + "node_modules/@types/opentype.js": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/@types/opentype.js/-/opentype.js-1.3.4.tgz", + "integrity": "sha512-6fbXi67I07ugNM+FExwJnfuui2hD7hraD6nqjr3UnqsbBpxSkrtmO6tBubPdNAjqRT9TVkquVkNS9IkgTtq6/w==", + "dev": true + }, "node_modules/@types/q": { "version": "0.0.32", "resolved": "https://registry.npmjs.org/@types/q/-/q-0.0.32.tgz", @@ -12578,6 +12586,21 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/opentype.js": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/opentype.js/-/opentype.js-1.3.4.tgz", + "integrity": "sha512-d2JE9RP/6uagpQAVtJoF0pJJA/fgai89Cc50Yp0EJHk+eLp6QQ7gBoblsnubRULNY132I0J1QKMJ+JTbMqz4sw==", + "dependencies": { + "string.prototype.codepointat": "^0.2.1", + "tiny-inflate": "^1.0.3" + }, + "bin": { + "ot": "bin/ot" + }, + "engines": { + "node": ">= 8.0.0" + } + }, "node_modules/optionator": { "version": "0.9.1", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", @@ -15205,6 +15228,11 @@ "node": ">=8" } }, + "node_modules/string.prototype.codepointat": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/string.prototype.codepointat/-/string.prototype.codepointat-0.2.1.tgz", + "integrity": "sha512-2cBVCj6I4IOvEnjgO/hWqXjqBGsY+zwPmHl12Srk9IXSZ56Jwwmy+66XO5Iut/oQVR7t5ihYdLB0GMa4alEUcg==" + }, "node_modules/strip-ansi": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", @@ -15546,6 +15574,11 @@ "integrity": "sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==", "dev": true }, + "node_modules/tiny-inflate": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/tiny-inflate/-/tiny-inflate-1.0.3.tgz", + "integrity": "sha512-pkY1fj1cKHb2seWDy0B16HeWyczlJA9/WW3u3c4z/NiWDsO3DOU5D7nhTLE9CF0yXv/QZFY7sEJmj24dK+Rrqw==" + }, "node_modules/tinycolor2": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/tinycolor2/-/tinycolor2-1.6.0.tgz", diff --git a/console/package.json b/console/package.json index f1bb3aed4d..f9f1b262ad 100644 --- a/console/package.json +++ b/console/package.json @@ -41,6 +41,7 @@ "libphonenumber-js": "^1.10.30", "material-design-icons-iconfont": "^6.1.1", "moment": "^2.29.4", + "opentype.js": "^1.3.4", "ngx-color": "^9.0.0", "rxjs": "~7.8.0", "tinycolor2": "^1.6.0", @@ -65,6 +66,7 @@ "@types/jasminewd2": "~2.0.10", "@types/jsonwebtoken": "^9.0.1", "@types/node": "^18.15.11", + "@types/opentype.js": "^1.3.4", "@types/qrcode": "^1.5.0", "@types/uuid": "^9.0.1", "@typescript-eslint/eslint-plugin": "^5.59.11", diff --git a/console/src/app/modules/policies/private-labeling-policy/private-labeling-policy.component.html b/console/src/app/modules/policies/private-labeling-policy/private-labeling-policy.component.html index cffa8034de..6ec47521a8 100644 --- a/console/src/app/modules/policies/private-labeling-policy/private-labeling-policy.component.html +++ b/console/src/app/modules/policies/private-labeling-policy/private-labeling-policy.component.html @@ -492,7 +492,9 @@
text_fields - + {{ + fontName + }}
diff --git a/console/src/app/modules/policies/private-labeling-policy/private-labeling-policy.component.scss b/console/src/app/modules/policies/private-labeling-policy/private-labeling-policy.component.scss index 78a2f7e8d1..c7d1371029 100644 --- a/console/src/app/modules/policies/private-labeling-policy/private-labeling-policy.component.scss +++ b/console/src/app/modules/policies/private-labeling-policy/private-labeling-policy.component.scss @@ -243,8 +243,6 @@ } .font-preview { - height: 70px; - width: 70px; display: flex; align-items: center; justify-content: center; @@ -252,22 +250,17 @@ margin-bottom: 1rem; border: 1px solid map-get($foreground, divider); position: relative; + padding: 1rem 0.5rem 1rem 0.75rem; - .icon { - position: absolute; - top: 50%; - left: 50%; - transform: translateX(-50%) translateY(-50%); + .font-name { + margin-left: 0.5rem; + font-size: 16px; } .dl-btn { z-index: 2; - position: absolute; - right: 0; - top: 0; cursor: pointer; visibility: hidden; - transform: translateX(50%) translateY(-50%); } &:hover { diff --git a/console/src/app/modules/policies/private-labeling-policy/private-labeling-policy.component.ts b/console/src/app/modules/policies/private-labeling-policy/private-labeling-policy.component.ts index 6fb17bc86f..6e579352de 100644 --- a/console/src/app/modules/policies/private-labeling-policy/private-labeling-policy.component.ts +++ b/console/src/app/modules/policies/private-labeling-policy/private-labeling-policy.component.ts @@ -31,6 +31,7 @@ import { } from 'src/app/services/theme.service'; import { ToastService } from 'src/app/services/toast.service'; +import * as opentype from 'opentype.js'; import { InfoSectionType } from '../../info-section/info-section.component'; import { WarnDialogComponent } from '../../warn-dialog/warn-dialog.component'; import { PolicyComponentServiceType } from '../policy-component-types.enum'; @@ -88,6 +89,8 @@ export class PrivateLabelingPolicyComponent implements OnInit, OnDestroy { public ColorType: any = ColorType; public AssetType: any = AssetType; + public fontName = ''; + public refreshPreview: EventEmitter = new EventEmitter(); public org!: Org.AsObject; public InfoSectionType: any = InfoSectionType; @@ -180,6 +183,10 @@ export class PrivateLabelingPolicyComponent implements OnInit, OnDestroy { if (file) { const formData = new FormData(); formData.append('file', file); + + this.getFontName(file); + this.previewNewFont(file); + switch (this.serviceType) { case PolicyComponentServiceType.MGMT: return this.handleFontUploadPromise(this.assetService.upload(AssetEndpoint.MGMTFONT, formData, this.org.id)); @@ -199,6 +206,7 @@ export class PrivateLabelingPolicyComponent implements OnInit, OnDestroy { this.getPreviewData().then((data) => { if (data.policy) { this.previewData = data.policy; + this.fontName = ''; } }); }, 1000); @@ -374,6 +382,11 @@ export class PrivateLabelingPolicyComponent implements OnInit, OnDestroy { .then((data) => { if (data.policy) { this.previewData = data.policy; + if (this.previewData?.fontUrl) { + this.fetchFontMetadataAndPreview(this.previewData.fontUrl); + } else { + this.fontName = 'Could not parse font name'; + } this.loading = false; } }) @@ -385,6 +398,11 @@ export class PrivateLabelingPolicyComponent implements OnInit, OnDestroy { .then((data) => { if (data.policy) { this.data = data.policy; + if (this.data?.fontUrl) { + this.fetchFontMetadataAndPreview(this.data?.fontUrl); + } else { + this.fontName = 'Could not parse font name'; + } this.loading = false; } }) @@ -678,6 +696,45 @@ export class PrivateLabelingPolicyComponent implements OnInit, OnDestroy { }); } + private fetchFontMetadataAndPreview(url: string): void { + fetch(url) + .then((res) => res.blob()) + .then((blob) => { + this.getFontName(blob); + this.previewNewFont(blob); + }); + } + + private getFontName(blob: Blob): void { + const reader = new FileReader(); + reader.onload = (e) => { + if (e.target && e.target.result) { + try { + const font = opentype.parse(e.target.result); + this.fontName = font.names.fullName['en']; + } catch (e) { + this.fontName = 'Could not parse font name'; + } + } + }; + reader.readAsArrayBuffer(blob); + } + + private previewNewFont(blob: Blob): void { + const reader = new FileReader(); + + reader.onload = (e) => { + if (e.target) { + let customFont = new FontFace('brandingFont', `url(${e.target.result})`); + // typescript complains that add is not found but + // indeed it is https://developer.mozilla.org/en-US/docs/Web/API/FontFaceSet/add + // @ts-ignore + document.fonts.add(customFont); + } + }; + reader.readAsDataURL(blob); + } + // /** // * defaults to false because urls are distinct anyway // */