Skip to content

Commit

Permalink
Handle emoji in text (#132)
Browse files Browse the repository at this point in the history
* chore: clean some stuff

* feat: extract emojis in text & use appropriate font to generate & integrate them into final mesh

* chore: add a "bug" section & rearrange top bar

* chore: try to fix this f******* test
  • Loading branch information
romgere authored May 31, 2024
1 parent 79d3c34 commit 81fbf53
Show file tree
Hide file tree
Showing 35 changed files with 475 additions and 118 deletions.
36 changes: 20 additions & 16 deletions app/components/about.hbs
Original file line number Diff line number Diff line change
@@ -1,32 +1,36 @@
<calcite-button
appearance="transparent"
kind="neutral"
scale="m"
id="about-button"
icon-start="information"
appearance='transparent'
kind='neutral'
scale='m'
id='about-button'
icon-start='information'
...attributes
/>
<calcite-tooltip reference-element='about-button' placement='bottom'>
<span>{{t 'info.label'}}</span>
</calcite-tooltip>

<calcite-popover
label={{t "info.label"}}
heading={{t "info.label"}}
reference-element="about-button"
label={{t 'info.label'}}
heading={{t 'info.label'}}
reference-element='about-button'
closable
auto-close
>
<div class="m-2">
<p class="center">
{{t "info.made_by"
<div class='m-2'>
<p class='center'>
{{t
'info.made_by'
author=this.authorLink
ember=this.emberLink
three=this.threeLink
htmlSafe=true
}}
</p>
<p class="center">
<a href="https://github.com/romgere/text2stl" target="_blank" rel="noopener noreferrer">{{t "info.github"}}</a>
</p>
<p class="center">
<a href="https://github.com/romgere/text2stl/issues/new" target="_blank" rel="noopener noreferrer">{{t "info.issue"}}</a>
<p class='center'>
<a href='https://github.com/romgere/text2stl' target='_blank' rel='noopener noreferrer'>{{t
'info.github'
}}</a>
</p>
</div>
</calcite-popover>
50 changes: 50 additions & 0 deletions app/components/issue.hbs
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
<calcite-button
appearance='transparent'
kind='neutral'
scale='m'
id='issue-button'
icon-start='debug'
...attributes
/>

<calcite-tooltip reference-element='issue-button' placement='bottom'>
<span>{{t 'issue.label'}}</span>
</calcite-tooltip>

<calcite-popover
label={{t 'issue.label'}}
heading={{t 'issue.label'}}
reference-element='issue-button'
closable
auto-close
>
<div class='m-2 w-40'>
<h2 class='center'>{{t 'issue.info'}}</h2>

<p class='center'>{{t 'issue.know_bug.free' htmlSafe=true}}</p>
<hr class='w-30p' />

<p class='center'>{{t 'issue.know_bug.font' htmlSafe=true}}</p>
<p class='center'>{{t 'issue.know_bug.font1'}}</p>
<hr class='w-30p' />

<p class='center'>{{t 'issue.know_bug.emoji' htmlSafe=true}}</p>
<p class='center'>{{t 'issue.know_bug.emoji1'}}</p>
<p class='center'>{{t 'issue.know_bug.emoji2'}}</p>
<hr class='w-30p' />

<p class='center'>{{t 'issue.know_bug.three_js' htmlSafe=true}}</p>

<p class='center mt-5'>

<calcite-button
icon-start='debug'
target='_blank'
rel='noopener noreferrer'
href='https://github.com/romgere/text2stl/issues/new'
>{{t 'issue.know_bug.submit'}}</calcite-button>
<br />
<small>{{t 'issue.know_bug.gh_account' htmlSafe=true}}</small>
</p>
</div>
</calcite-popover>
2 changes: 1 addition & 1 deletion app/components/settings-form/support.hbs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
<calcite-label layout='inline-space-between'>
{{t (concat 'directions.' pos)}}
<calcite-input-number
class='w-70'
class='w-70p'
placeholder={{concat
(t 'text_settings.supportPadding')
' - '
Expand Down
16 changes: 8 additions & 8 deletions app/components/theme-switcher.hbs
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
<calcite-button
appearance="transparent"
kind="neutral"
scale="m"
id="theme-switcher"
icon-start={{if this.isLightTheme "brightness" "moon"}}
appearance='transparent'
kind='neutral'
scale='m'
id='theme-switcher'
icon-start={{if this.isLightTheme 'brightness' 'moon'}}
...attributes
{{on "click" this.switchTheme}}
{{on 'click' this.switchTheme}}
/>
<calcite-tooltip reference-element="theme-switcher">
<span>{{t "switch_theme_tooltip" current=this.theme}}</span>
<calcite-tooltip reference-element='theme-switcher' placement='bottom'>
<span>{{t 'switch_theme_tooltip' current=this.theme}}</span>
</calcite-tooltip>
59 changes: 59 additions & 0 deletions app/misc/extract-emoji.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
export type StringPart = {
type: 'text' | 'emoji';
value: string;
};

export default function extractEmoji(str: string) {
const emojiRE = /(\p{EPres}|\p{ExtPict})+/gu;

const extraction: StringPart[] = [];
const execList: RegExpExecArray[] = [];
let exec: RegExpExecArray | null = null;

while ((exec = emojiRE.exec(str))) {
execList.push(exec);
}

// No emoji at all
if (!execList.length) {
extraction.push({
type: 'text',
value: str,
});
} else {
if (execList[0].index) {
extraction.push({
type: 'text',
value: str.substring(0, execList[0].index),
});
}

for (const [i, e] of execList.entries()) {
extraction.push({
type: 'emoji',
value: e[0],
});

const eLength = e[0].length; // Emoji lenght
const eEndIdx = e.index + eLength; // Emoji end index in string
const nextEmojiIdx = execList[i + 1]?.index ?? 0; // Next emoji index

// Handle text between current emoji & next one
if (nextEmojiIdx > eEndIdx) {
extraction.push({
type: 'text',
value: str.substring(eEndIdx, execList[i + 1].index),
});
}
// Handle text between last emoji & end of string
else if (i === execList.length - 1 && eEndIdx < str.length) {
extraction.push({
type: 'text',
value: str.substring(eEndIdx, str.length),
});
}
}
}

return extraction;
}
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
2 changes: 1 addition & 1 deletion app/modifiers/three-renderer.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import Modifier, { ArgsFor } from 'ember-modifier';
import * as THREE from 'three';
import { OrbitControls } from 'text2stl/utils/OrbitControls';
import { OrbitControls } from 'text2stl/misc/threejs/OrbitControls';
import { tracked } from '@glimmer/tracking';
import config from 'text2stl/config/environment';
import { registerDestructor } from '@ember/destroyable';
Expand Down
3 changes: 2 additions & 1 deletion app/routes/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,9 @@ export default class AppRoute extends Route {
async model({ locale }: { locale: string }) {
this.intl.locale = locale === 'en-us' ? locale : [locale, 'en-us'];
// No await here, let's the loading happen & await for it in generator route
this.fontManager.loadFont();
this.harfbuzz.loadWASM();
this.fontManager.loadFont();
this.fontManager.loadEmojiFont();
}

afterModel() {
Expand Down
3 changes: 3 additions & 0 deletions app/routes/app/generator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,9 @@ export default class GeneratorRoute extends Route {

// Ensure font list is fully load
await this.fontManager.loadFont();
// Ensure emoji font is fully load
await this.fontManager.loadEmojiFont();

// Ensure harfbuzzJS is fully load (WASM loaded & lib instance created)
await this.harfbuzz.loadWASM();

Expand Down
4 changes: 2 additions & 2 deletions app/services/file-exporter.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import Service from '@ember/service';
import { STLExporter } from 'text2stl/utils/STLExporter';
import { OBJExporter } from 'text2stl/utils/OBJExporter';
import { STLExporter } from 'text2stl/misc/threejs/STLExporter';
import { OBJExporter } from 'text2stl/misc/threejs/OBJExporter';

import type { Mesh } from 'three';

Expand Down
27 changes: 27 additions & 0 deletions app/services/font-manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ const {

const FONT_BASE_URL = 'https://fonts.googleapis.com/css';
const LIST_BASE_URL = 'https://www.googleapis.com/webfonts/v1/webfonts';
const EMOJI_FONT_FILE = '/NotoEmoji-Regular.ttf';

type GoogleFontApiResponse = {
items: {
Expand Down Expand Up @@ -132,6 +133,16 @@ export default class FontManagerService extends Service {

fontCache: Record<string, FaceAndFont> = {};

_emojiFont?: FaceAndFont;

get emojiFont() {
if (!this._emojiFont) {
throw 'Emoji font not loaded, please call loadEmojiFont() first.';
}

return this._emojiFont;
}

// For easy mock
fetch(input: RequestInfo, init?: RequestInit | undefined): Promise<Response> {
return fetch(input, init);
Expand Down Expand Up @@ -266,6 +277,22 @@ export default class FontManagerService extends Service {
return this.openHBFont(fontAsBuffer);
}

private async _loadEmojiFont() {
await this.harfbuzz.loadWASM();
const res = await this.fetch(EMOJI_FONT_FILE);
const fontData = await res.arrayBuffer();
this._emojiFont = this.openHBFont(fontData);
}

loadEmojiFontPromise: undefined | Promise<void> = undefined;
async loadEmojiFont() {
if (!this.loadEmojiFontPromise) {
this.loadEmojiFontPromise = this._loadEmojiFont();
}

await this.loadEmojiFontPromise;
}

private chunk<T>(array: T[], chunkSize: number) {
const length = Math.ceil(array.length / chunkSize);
const chunks = new Array(length).fill(0);
Expand Down
Loading

0 comments on commit 81fbf53

Please sign in to comment.