Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Handle emoji in text #132

Merged
merged 4 commits into from
May 31, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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.
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
Loading