(
+ 'meta[name=cdn-host]',
+ );
+ if (cdnHost) {
+ assetHost = cdnHost.content || '';
+ }
+});
diff --git a/app/javascript/mastodon/utils/environment.ts b/app/javascript/mastodon/utils/environment.ts
new file mode 100644
index 00000000000000..b6371499f63694
--- /dev/null
+++ b/app/javascript/mastodon/utils/environment.ts
@@ -0,0 +1,7 @@
+export function isDevelopment() {
+ return process.env.NODE_ENV === 'development';
+}
+
+export function isProduction() {
+ return process.env.NODE_ENV === 'production';
+}
diff --git a/app/javascript/mastodon/utils/html.js b/app/javascript/mastodon/utils/html.js
deleted file mode 100644
index 247e98c88a7f31..00000000000000
--- a/app/javascript/mastodon/utils/html.js
+++ /dev/null
@@ -1,6 +0,0 @@
-// NB: This function can still return unsafe HTML
-export const unescapeHTML = (html) => {
- const wrapper = document.createElement('div');
- wrapper.innerHTML = html.replace(/
/g, '\n').replace(/<\/p>/g, '\n\n').replace(/<[^>]*>/g, '');
- return wrapper.textContent;
-};
diff --git a/app/javascript/mastodon/utils/html.ts b/app/javascript/mastodon/utils/html.ts
new file mode 100644
index 00000000000000..0145a045516e7a
--- /dev/null
+++ b/app/javascript/mastodon/utils/html.ts
@@ -0,0 +1,9 @@
+// NB: This function can still return unsafe HTML
+export const unescapeHTML = (html: string) => {
+ const wrapper = document.createElement('div');
+ wrapper.innerHTML = html
+ .replace(/
/g, '\n')
+ .replace(/<\/p>
/g, '\n\n')
+ .replace(/<[^>]*>/g, '');
+ return wrapper.textContent;
+};
diff --git a/app/javascript/mastodon/utils/icons.jsx b/app/javascript/mastodon/utils/icons.tsx
similarity index 69%
rename from app/javascript/mastodon/utils/icons.jsx
rename to app/javascript/mastodon/utils/icons.tsx
index be566032e06445..6e432e32fa4e49 100644
--- a/app/javascript/mastodon/utils/icons.jsx
+++ b/app/javascript/mastodon/utils/icons.tsx
@@ -1,13 +1,23 @@
// Copied from emoji-mart for consistency with emoji picker and since
// they don't export the icons in the package
export const loupeIcon = (
-