Convert from Webpack to Vite (#34450)
Co-authored-by: Renaud Chaput <renchap@gmail.com>
This commit is contained in:
		@@ -1,4 +1,3 @@
 | 
			
		||||
import './public-path';
 | 
			
		||||
import { createRoot } from 'react-dom/client';
 | 
			
		||||
 | 
			
		||||
import Rails from '@rails/ujs';
 | 
			
		||||
@@ -273,7 +272,7 @@ async function mountReactComponent(element: Element) {
 | 
			
		||||
  );
 | 
			
		||||
 | 
			
		||||
  const { default: Component } = (await import(
 | 
			
		||||
    `@/mastodon/components/admin/${componentName}`
 | 
			
		||||
    `@/mastodon/components/admin/${componentName}.jsx`
 | 
			
		||||
  )) as { default: React.ComponentType };
 | 
			
		||||
 | 
			
		||||
  const root = createRoot(element);
 | 
			
		||||
 
 | 
			
		||||
@@ -1,11 +1,6 @@
 | 
			
		||||
import './public-path';
 | 
			
		||||
import { loadLocale } from 'mastodon/locales';
 | 
			
		||||
import main from 'mastodon/main';
 | 
			
		||||
 | 
			
		||||
import { start } from '../mastodon/common';
 | 
			
		||||
import { loadLocale } from '../mastodon/locales';
 | 
			
		||||
import { loadPolyfills } from '../mastodon/polyfills';
 | 
			
		||||
 | 
			
		||||
start();
 | 
			
		||||
import { loadPolyfills } from 'mastodon/polyfills';
 | 
			
		||||
 | 
			
		||||
loadPolyfills()
 | 
			
		||||
  .then(loadLocale)
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										3
									
								
								app/javascript/entrypoints/common.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								app/javascript/entrypoints/common.ts
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,3 @@
 | 
			
		||||
import { start } from 'mastodon/common';
 | 
			
		||||
 | 
			
		||||
start();
 | 
			
		||||
@@ -1,15 +1,11 @@
 | 
			
		||||
import './public-path';
 | 
			
		||||
import { createRoot } from 'react-dom/client';
 | 
			
		||||
 | 
			
		||||
import { afterInitialRender } from 'mastodon/hooks/useRenderSignal';
 | 
			
		||||
 | 
			
		||||
import { start } from '../mastodon/common';
 | 
			
		||||
import { Status } from '../mastodon/features/standalone/status';
 | 
			
		||||
import { loadPolyfills } from '../mastodon/polyfills';
 | 
			
		||||
import ready from '../mastodon/ready';
 | 
			
		||||
 | 
			
		||||
start();
 | 
			
		||||
 | 
			
		||||
function loaded() {
 | 
			
		||||
  const mountNode = document.getElementById('mastodon-status');
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,4 +1,3 @@
 | 
			
		||||
import './public-path';
 | 
			
		||||
import ready from '../mastodon/ready';
 | 
			
		||||
 | 
			
		||||
ready(() => {
 | 
			
		||||
 
 | 
			
		||||
@@ -1,4 +0,0 @@
 | 
			
		||||
/* Placeholder file to have `inert.scss` compiled by Webpack
 | 
			
		||||
   This is used by the `wicg-inert` polyfill */
 | 
			
		||||
 | 
			
		||||
import '../styles/inert.scss';
 | 
			
		||||
@@ -1,3 +0,0 @@
 | 
			
		||||
import '../styles/mailer.scss';
 | 
			
		||||
 | 
			
		||||
require.context('../icons');
 | 
			
		||||
@@ -1,23 +0,0 @@
 | 
			
		||||
// Dynamically set webpack's loading path depending on a meta header, in order
 | 
			
		||||
// to share the same assets regardless of instance configuration.
 | 
			
		||||
// See https://webpack.js.org/guides/public-path/#on-the-fly
 | 
			
		||||
 | 
			
		||||
function removeOuterSlashes(string: string) {
 | 
			
		||||
  return string.replace(/^\/*/, '').replace(/\/*$/, '');
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function formatPublicPath(host = '', path = '') {
 | 
			
		||||
  let formattedHost = removeOuterSlashes(host);
 | 
			
		||||
  if (formattedHost && !/^http/i.test(formattedHost)) {
 | 
			
		||||
    formattedHost = `//${formattedHost}`;
 | 
			
		||||
  }
 | 
			
		||||
  const formattedPath = removeOuterSlashes(path);
 | 
			
		||||
  return `${formattedHost}/${formattedPath}/`;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const cdnHost = document.querySelector<HTMLMetaElement>('meta[name=cdn-host]');
 | 
			
		||||
 | 
			
		||||
__webpack_public_path__ = formatPublicPath(
 | 
			
		||||
  cdnHost ? cdnHost.content : '',
 | 
			
		||||
  process.env.PUBLIC_OUTPUT_PATH,
 | 
			
		||||
);
 | 
			
		||||
@@ -1,7 +1,5 @@
 | 
			
		||||
import { createRoot } from 'react-dom/client';
 | 
			
		||||
 | 
			
		||||
import './public-path';
 | 
			
		||||
 | 
			
		||||
import { IntlMessageFormat } from 'intl-messageformat';
 | 
			
		||||
import type { MessageDescriptor, PrimitiveType } from 'react-intl';
 | 
			
		||||
import { defineMessages } from 'react-intl';
 | 
			
		||||
@@ -10,7 +8,6 @@ import Rails from '@rails/ujs';
 | 
			
		||||
import axios from 'axios';
 | 
			
		||||
import { throttle } from 'lodash';
 | 
			
		||||
 | 
			
		||||
import { start } from '../mastodon/common';
 | 
			
		||||
import { timeAgoString } from '../mastodon/components/relative_timestamp';
 | 
			
		||||
import emojify from '../mastodon/features/emoji/emoji';
 | 
			
		||||
import loadKeyboardExtensions from '../mastodon/load_keyboard_extensions';
 | 
			
		||||
@@ -20,8 +17,6 @@ import ready from '../mastodon/ready';
 | 
			
		||||
 | 
			
		||||
import 'cocoon-js-vanilla';
 | 
			
		||||
 | 
			
		||||
start();
 | 
			
		||||
 | 
			
		||||
const messages = defineMessages({
 | 
			
		||||
  usernameTaken: {
 | 
			
		||||
    id: 'username.taken',
 | 
			
		||||
@@ -153,9 +148,7 @@ function loaded() {
 | 
			
		||||
  const reactComponents = document.querySelectorAll('[data-component]');
 | 
			
		||||
 | 
			
		||||
  if (reactComponents.length > 0) {
 | 
			
		||||
    import(
 | 
			
		||||
      /* webpackChunkName: "containers/media_container" */ '../mastodon/containers/media_container'
 | 
			
		||||
    )
 | 
			
		||||
    import('../mastodon/containers/media_container')
 | 
			
		||||
      .then(({ default: MediaContainer }) => {
 | 
			
		||||
        reactComponents.forEach((component) => {
 | 
			
		||||
          Array.from(component.children).forEach((child) => {
 | 
			
		||||
 
 | 
			
		||||
@@ -8,8 +8,6 @@ and performs no other task.
 | 
			
		||||
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
import './public-path';
 | 
			
		||||
 | 
			
		||||
import axios from 'axios';
 | 
			
		||||
 | 
			
		||||
interface JRDLink {
 | 
			
		||||
 
 | 
			
		||||
@@ -1,13 +1,9 @@
 | 
			
		||||
import './public-path';
 | 
			
		||||
import { createRoot } from 'react-dom/client';
 | 
			
		||||
 | 
			
		||||
import { start } from '../mastodon/common';
 | 
			
		||||
import ComposeContainer from '../mastodon/containers/compose_container';
 | 
			
		||||
import { loadPolyfills } from '../mastodon/polyfills';
 | 
			
		||||
import ready from '../mastodon/ready';
 | 
			
		||||
 | 
			
		||||
start();
 | 
			
		||||
 | 
			
		||||
function loaded() {
 | 
			
		||||
  const mountNode = document.getElementById('mastodon-compose');
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -1,4 +1,3 @@
 | 
			
		||||
import './public-path';
 | 
			
		||||
import axios from 'axios';
 | 
			
		||||
 | 
			
		||||
import ready from '../mastodon/ready';
 | 
			
		||||
 
 | 
			
		||||
@@ -1,8 +1,6 @@
 | 
			
		||||
import Rails from '@rails/ujs';
 | 
			
		||||
 | 
			
		||||
export function start() {
 | 
			
		||||
  require.context('../images/', true, /\.(jpg|png|svg)$/);
 | 
			
		||||
 | 
			
		||||
  try {
 | 
			
		||||
    Rails.start();
 | 
			
		||||
  } catch {
 | 
			
		||||
@@ -9,7 +9,7 @@ import ImmutablePropTypes from 'react-immutable-proptypes';
 | 
			
		||||
import ImmutablePureComponent from 'react-immutable-pure-component';
 | 
			
		||||
import { connect } from 'react-redux';
 | 
			
		||||
 | 
			
		||||
import BookmarkIcon from '@/material-icons/400-24px/bookmark-fill.svg';
 | 
			
		||||
import BookmarkIcon from '@/material-icons/400-24px/bookmark-fill.svg?react';
 | 
			
		||||
import BookmarkBorderIcon from '@/material-icons/400-24px/bookmark.svg?react';
 | 
			
		||||
import MoreHorizIcon from '@/material-icons/400-24px/more_horiz.svg?react';
 | 
			
		||||
import RepeatIcon from '@/material-icons/400-24px/repeat.svg?react';
 | 
			
		||||
 
 | 
			
		||||
@@ -15,10 +15,6 @@ import type { List as ImmutableList, Map as ImmutableMap } from 'immutable';
 | 
			
		||||
import { useSpring, animated } from '@react-spring/web';
 | 
			
		||||
import Textarea from 'react-textarea-autosize';
 | 
			
		||||
import { length } from 'stringz';
 | 
			
		||||
// eslint-disable-next-line import/extensions
 | 
			
		||||
import tesseractWorkerPath from 'tesseract.js/dist/worker.min.js';
 | 
			
		||||
// eslint-disable-next-line import/no-extraneous-dependencies
 | 
			
		||||
import tesseractCorePath from 'tesseract.js-core/tesseract-core.wasm.js';
 | 
			
		||||
 | 
			
		||||
import { showAlertForError } from 'mastodon/actions/alerts';
 | 
			
		||||
import { uploadThumbnail } from 'mastodon/actions/compose';
 | 
			
		||||
@@ -350,9 +346,15 @@ export const AltTextModal = forwardRef<ModalRef, Props & Partial<RestoreProps>>(
 | 
			
		||||
 | 
			
		||||
      fetchTesseract()
 | 
			
		||||
        .then(async ({ createWorker }) => {
 | 
			
		||||
          const [tesseractWorkerPath, tesseractCorePath] = await Promise.all([
 | 
			
		||||
            // eslint-disable-next-line import/extensions
 | 
			
		||||
            import('tesseract.js/dist/worker.min.js?url'),
 | 
			
		||||
            // eslint-disable-next-line import/no-extraneous-dependencies
 | 
			
		||||
            import('tesseract.js-core/tesseract-core.wasm.js?url'),
 | 
			
		||||
          ]);
 | 
			
		||||
          const worker = await createWorker('eng', 1, {
 | 
			
		||||
            workerPath: tesseractWorkerPath as string,
 | 
			
		||||
            corePath: tesseractCorePath as string,
 | 
			
		||||
            workerPath: tesseractWorkerPath.default,
 | 
			
		||||
            corePath: tesseractCorePath.default,
 | 
			
		||||
            langPath: `${assetHost}/ocr/lang-data`,
 | 
			
		||||
            cacheMethod: 'write',
 | 
			
		||||
          });
 | 
			
		||||
@@ -501,5 +503,4 @@ export const AltTextModal = forwardRef<ModalRef, Props & Partial<RestoreProps>>(
 | 
			
		||||
    );
 | 
			
		||||
  },
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
AltTextModal.displayName = 'AltTextModal';
 | 
			
		||||
 
 | 
			
		||||
@@ -9,28 +9,27 @@
 | 
			
		||||
// to ensure that the prevaled file is regenerated by Babel
 | 
			
		||||
// version: 4
 | 
			
		||||
 | 
			
		||||
const { NimbleEmojiIndex } = require('emoji-mart');
 | 
			
		||||
const { uncompress: emojiMartUncompress } = require('emoji-mart/dist/utils/data');
 | 
			
		||||
import { NimbleEmojiIndex } from 'emoji-mart';
 | 
			
		||||
import { uncompress as emojiMartUncompress } from 'emoji-mart/dist/utils/data';
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
let data = require('./emoji_data.json');
 | 
			
		||||
const emojiMap = require('./emoji_map.json');
 | 
			
		||||
const { unicodeToFilename } = require('./unicode_to_filename');
 | 
			
		||||
const { unicodeToUnifiedName } = require('./unicode_to_unified_name');
 | 
			
		||||
import data from './emoji_data.json';
 | 
			
		||||
import emojiMap from './emoji_map.json';
 | 
			
		||||
import { unicodeToFilename } from './unicode_to_filename';
 | 
			
		||||
import { unicodeToUnifiedName } from './unicode_to_unified_name';
 | 
			
		||||
 | 
			
		||||
emojiMartUncompress(data);
 | 
			
		||||
 | 
			
		||||
const emojiMartData = data;
 | 
			
		||||
const emojiIndex = new NimbleEmojiIndex(emojiMartData);
 | 
			
		||||
 | 
			
		||||
const excluded       = ['®', '©', '™'];
 | 
			
		||||
const skinTones      = ['🏻', '🏼', '🏽', '🏾', '🏿'];
 | 
			
		||||
const shortcodeMap   = {};
 | 
			
		||||
const excluded = ['®', '©', '™'];
 | 
			
		||||
const skinTones = ['🏻', '🏼', '🏽', '🏾', '🏿'];
 | 
			
		||||
const shortcodeMap = {};
 | 
			
		||||
 | 
			
		||||
const shortCodesToEmojiData = {};
 | 
			
		||||
const emojisWithoutShortCodes = [];
 | 
			
		||||
 | 
			
		||||
Object.keys(emojiIndex.emojis).forEach(key => {
 | 
			
		||||
Object.keys(emojiIndex.emojis).forEach((key) => {
 | 
			
		||||
  let emoji = emojiIndex.emojis[key];
 | 
			
		||||
 | 
			
		||||
  // Emojis with skin tone modifiers are stored like this
 | 
			
		||||
@@ -41,22 +40,22 @@ Object.keys(emojiIndex.emojis).forEach(key => {
 | 
			
		||||
  shortcodeMap[emoji.native] = emoji.id;
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
const stripModifiers = unicode => {
 | 
			
		||||
  skinTones.forEach(tone => {
 | 
			
		||||
const stripModifiers = (unicode) => {
 | 
			
		||||
  skinTones.forEach((tone) => {
 | 
			
		||||
    unicode = unicode.replace(tone, '');
 | 
			
		||||
  });
 | 
			
		||||
 | 
			
		||||
  return unicode;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
Object.keys(emojiMap).forEach(key => {
 | 
			
		||||
Object.keys(emojiMap).forEach((key) => {
 | 
			
		||||
  if (excluded.includes(key)) {
 | 
			
		||||
    delete emojiMap[key];
 | 
			
		||||
    return;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  const normalizedKey = stripModifiers(key);
 | 
			
		||||
  let shortcode       = shortcodeMap[normalizedKey];
 | 
			
		||||
  let shortcode = shortcodeMap[normalizedKey];
 | 
			
		||||
 | 
			
		||||
  if (!shortcode) {
 | 
			
		||||
    shortcode = shortcodeMap[normalizedKey + '\uFE0F'];
 | 
			
		||||
@@ -82,7 +81,7 @@ Object.keys(emojiMap).forEach(key => {
 | 
			
		||||
  }
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
Object.keys(emojiIndex.emojis).forEach(key => {
 | 
			
		||||
Object.keys(emojiIndex.emojis).forEach((key) => {
 | 
			
		||||
  let emoji = emojiIndex.emojis[key];
 | 
			
		||||
 | 
			
		||||
  // Emojis with skin tone modifiers are stored like this
 | 
			
		||||
@@ -94,9 +93,11 @@ Object.keys(emojiIndex.emojis).forEach(key => {
 | 
			
		||||
  let { short_names, search, unified } = emojiMartData.emojis[key];
 | 
			
		||||
 | 
			
		||||
  if (short_names[0] !== key) {
 | 
			
		||||
    throw new Error('The compressor expects the first short_code to be the ' +
 | 
			
		||||
      'key. It may need to be rewritten if the emoji change such that this ' +
 | 
			
		||||
      'is no longer the case.');
 | 
			
		||||
    throw new Error(
 | 
			
		||||
      'The compressor expects the first short_code to be the ' +
 | 
			
		||||
        'key. It may need to be rewritten if the emoji change such that this ' +
 | 
			
		||||
        'is no longer the case.',
 | 
			
		||||
    );
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  short_names = short_names.slice(1); // first short name can be inferred from the key
 | 
			
		||||
@@ -117,20 +118,22 @@ Object.keys(emojiIndex.emojis).forEach(key => {
 | 
			
		||||
 | 
			
		||||
// JSON.parse/stringify is to emulate what @preval is doing and avoid any
 | 
			
		||||
// inconsistent behavior in dev mode
 | 
			
		||||
module.exports = JSON.parse(JSON.stringify([
 | 
			
		||||
  shortCodesToEmojiData,
 | 
			
		||||
  /*
 | 
			
		||||
   * The property `skins` is not found in the current context.
 | 
			
		||||
   * This could potentially lead to issues when interacting with modules or data structures
 | 
			
		||||
   * that expect the presence of `skins` property.
 | 
			
		||||
   * Currently, no definitions or references to `skins` property can be found in:
 | 
			
		||||
   * - {@link node_modules/emoji-mart/dist/utils/data.js}
 | 
			
		||||
   * - {@link node_modules/emoji-mart/data/all.json}
 | 
			
		||||
   * - {@link app/javascript/mastodon/features/emoji/emoji_compressed.d.ts#Skins}
 | 
			
		||||
   * Future refactorings or updates should consider adding definitions or handling for `skins` property.
 | 
			
		||||
   */
 | 
			
		||||
  emojiMartData.skins,
 | 
			
		||||
  emojiMartData.categories,
 | 
			
		||||
  emojiMartData.aliases,
 | 
			
		||||
  emojisWithoutShortCodes
 | 
			
		||||
]));
 | 
			
		||||
export default JSON.parse(
 | 
			
		||||
  JSON.stringify([
 | 
			
		||||
    shortCodesToEmojiData,
 | 
			
		||||
    /*
 | 
			
		||||
     * The property `skins` is not found in the current context.
 | 
			
		||||
     * This could potentially lead to issues when interacting with modules or data structures
 | 
			
		||||
     * that expect the presence of `skins` property.
 | 
			
		||||
     * Currently, no definitions or references to `skins` property can be found in:
 | 
			
		||||
     * - {@link node_modules/emoji-mart/dist/utils/data.js}
 | 
			
		||||
     * - {@link node_modules/emoji-mart/data/all.json}
 | 
			
		||||
     * - {@link app/javascript/mastodon/features/emoji/emoji_compressed.d.ts#Skins}
 | 
			
		||||
     * Future refactorings or updates should consider adding definitions or handling for `skins` property.
 | 
			
		||||
     */
 | 
			
		||||
    emojiMartData.skins,
 | 
			
		||||
    emojiMartData.categories,
 | 
			
		||||
    emojiMartData.aliases,
 | 
			
		||||
    emojisWithoutShortCodes,
 | 
			
		||||
  ]),
 | 
			
		||||
);
 | 
			
		||||
@@ -3,9 +3,13 @@
 | 
			
		||||
// emojiIndex.search functionality.
 | 
			
		||||
import type { BaseEmoji } from 'emoji-mart';
 | 
			
		||||
import type { Emoji } from 'emoji-mart/dist-es/utils/data';
 | 
			
		||||
// eslint-disable-next-line import/no-unresolved
 | 
			
		||||
import emojiCompressed from 'virtual:mastodon-emoji-compressed';
 | 
			
		||||
import type {
 | 
			
		||||
  Search,
 | 
			
		||||
  ShortCodesToEmojiData,
 | 
			
		||||
} from 'virtual:mastodon-emoji-compressed';
 | 
			
		||||
 | 
			
		||||
import type { Search, ShortCodesToEmojiData } from './emoji_compressed';
 | 
			
		||||
import emojiCompressed from './emoji_compressed';
 | 
			
		||||
import { unicodeToUnifiedName } from './unicode_to_unified_name';
 | 
			
		||||
 | 
			
		||||
type Emojis = Record<
 | 
			
		||||
 
 | 
			
		||||
@@ -2,11 +2,13 @@
 | 
			
		||||
// (i.e. the svg filename) and a shortCode intended to be shown
 | 
			
		||||
// as a "title" attribute in an HTML element (aka tooltip).
 | 
			
		||||
 | 
			
		||||
// eslint-disable-next-line import/no-unresolved
 | 
			
		||||
import emojiCompressed from 'virtual:mastodon-emoji-compressed';
 | 
			
		||||
import type {
 | 
			
		||||
  FilenameData,
 | 
			
		||||
  ShortCodesToEmojiDataKey,
 | 
			
		||||
} from './emoji_compressed';
 | 
			
		||||
import emojiCompressed from './emoji_compressed';
 | 
			
		||||
} from 'virtual:mastodon-emoji-compressed';
 | 
			
		||||
 | 
			
		||||
import { unicodeToFilename } from './unicode_to_filename';
 | 
			
		||||
 | 
			
		||||
type UnicodeMapping = Record<
 | 
			
		||||
 
 | 
			
		||||
@@ -1,6 +1,6 @@
 | 
			
		||||
// taken from:
 | 
			
		||||
// https://github.com/twitter/twemoji/blob/47732c7/twemoji-generator.js#L848-L866
 | 
			
		||||
exports.unicodeToFilename = (str) => {
 | 
			
		||||
export const unicodeToFilename = (str) => {
 | 
			
		||||
  let result = '';
 | 
			
		||||
  let charCode = 0;
 | 
			
		||||
  let p = 0;
 | 
			
		||||
 
 | 
			
		||||
@@ -6,7 +6,7 @@ function padLeft(str, num) {
 | 
			
		||||
  return str;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
exports.unicodeToUnifiedName = (str) => {
 | 
			
		||||
export const unicodeToUnifiedName = (str) => {
 | 
			
		||||
  let output = '';
 | 
			
		||||
 | 
			
		||||
  for (let i = 0; i < str.length; i += 2) {
 | 
			
		||||
 
 | 
			
		||||
@@ -1,235 +1,235 @@
 | 
			
		||||
export function EmojiPicker () {
 | 
			
		||||
  return import(/* webpackChunkName: "emoji_picker" */'../../emoji/emoji_picker');
 | 
			
		||||
  return import('../../emoji/emoji_picker');
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function Compose () {
 | 
			
		||||
  return import(/* webpackChunkName: "features/compose" */'../../compose');
 | 
			
		||||
  return import('../../compose');
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function Notifications () {
 | 
			
		||||
  return import(/* webpackChunkName: "features/notifications" */'../../notifications_v2');
 | 
			
		||||
  return import('../../notifications_v2');
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function HomeTimeline () {
 | 
			
		||||
  return import(/* webpackChunkName: "features/home_timeline" */'../../home_timeline');
 | 
			
		||||
  return import('../../home_timeline');
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function PublicTimeline () {
 | 
			
		||||
  return import(/* webpackChunkName: "features/public_timeline" */'../../public_timeline');
 | 
			
		||||
  return import('../../public_timeline');
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function CommunityTimeline () {
 | 
			
		||||
  return import(/* webpackChunkName: "features/community_timeline" */'../../community_timeline');
 | 
			
		||||
  return import('../../community_timeline');
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function Firehose () {
 | 
			
		||||
  return import(/* webpackChunkName: "features/firehose" */'../../firehose');
 | 
			
		||||
  return import('../../firehose');
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function HashtagTimeline () {
 | 
			
		||||
  return import(/* webpackChunkName: "features/hashtag_timeline" */'../../hashtag_timeline');
 | 
			
		||||
  return import('../../hashtag_timeline');
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function DirectTimeline() {
 | 
			
		||||
  return import(/* webpackChunkName: "features/direct_timeline" */'../../direct_timeline');
 | 
			
		||||
  return import('../../direct_timeline');
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function ListTimeline () {
 | 
			
		||||
  return import(/* webpackChunkName: "features/list_timeline" */'../../list_timeline');
 | 
			
		||||
  return import('../../list_timeline');
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function Lists () {
 | 
			
		||||
  return import(/* webpackChunkName: "features/lists" */'../../lists');
 | 
			
		||||
  return import('../../lists');
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function Status () {
 | 
			
		||||
  return import(/* webpackChunkName: "features/status" */'../../status');
 | 
			
		||||
  return import('../../status');
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function GettingStarted () {
 | 
			
		||||
  return import(/* webpackChunkName: "features/getting_started" */'../../getting_started');
 | 
			
		||||
  return import('../../getting_started');
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function KeyboardShortcuts () {
 | 
			
		||||
  return import(/* webpackChunkName: "features/keyboard_shortcuts" */'../../keyboard_shortcuts');
 | 
			
		||||
  return import('../../keyboard_shortcuts');
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function PinnedStatuses () {
 | 
			
		||||
  return import(/* webpackChunkName: "features/pinned_statuses" */'../../pinned_statuses');
 | 
			
		||||
  return import('../../pinned_statuses');
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function AccountTimeline () {
 | 
			
		||||
  return import(/* webpackChunkName: "features/account_timeline" */'../../account_timeline');
 | 
			
		||||
  return import('../../account_timeline');
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function AccountGallery () {
 | 
			
		||||
  return import(/* webpackChunkName: "features/account_gallery" */'../../account_gallery');
 | 
			
		||||
  return import('../../account_gallery');
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function AccountFeatured() {
 | 
			
		||||
  return import(/* webpackChunkName: "features/account_featured" */'../../account_featured');
 | 
			
		||||
  return import('../../account_featured');
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function Followers () {
 | 
			
		||||
  return import(/* webpackChunkName: "features/followers" */'../../followers');
 | 
			
		||||
  return import('../../followers');
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function Following () {
 | 
			
		||||
  return import(/* webpackChunkName: "features/following" */'../../following');
 | 
			
		||||
  return import('../../following');
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function Reblogs () {
 | 
			
		||||
  return import(/* webpackChunkName: "features/reblogs" */'../../reblogs');
 | 
			
		||||
  return import('../../reblogs');
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function Favourites () {
 | 
			
		||||
  return import(/* webpackChunkName: "features/favourites" */'../../favourites');
 | 
			
		||||
  return import('../../favourites');
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function FollowRequests () {
 | 
			
		||||
  return import(/* webpackChunkName: "features/follow_requests" */'../../follow_requests');
 | 
			
		||||
  return import('../../follow_requests');
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function FavouritedStatuses () {
 | 
			
		||||
  return import(/* webpackChunkName: "features/favourited_statuses" */'../../favourited_statuses');
 | 
			
		||||
  return import('../../favourited_statuses');
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function FollowedTags () {
 | 
			
		||||
  return import(/* webpackChunkName: "features/followed_tags" */'../../followed_tags');
 | 
			
		||||
  return import('../../followed_tags');
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function BookmarkedStatuses () {
 | 
			
		||||
  return import(/* webpackChunkName: "features/bookmarked_statuses" */'../../bookmarked_statuses');
 | 
			
		||||
  return import('../../bookmarked_statuses');
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function Blocks () {
 | 
			
		||||
  return import(/* webpackChunkName: "features/blocks" */'../../blocks');
 | 
			
		||||
  return import('../../blocks');
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function DomainBlocks () {
 | 
			
		||||
  return import(/* webpackChunkName: "features/domain_blocks" */'../../domain_blocks');
 | 
			
		||||
  return import('../../domain_blocks');
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function Mutes () {
 | 
			
		||||
  return import(/* webpackChunkName: "features/mutes" */'../../mutes');
 | 
			
		||||
  return import('../../mutes');
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function MuteModal () {
 | 
			
		||||
  return import(/* webpackChunkName: "modals/mute_modal" */'../components/mute_modal');
 | 
			
		||||
  return import('../components/mute_modal');
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function BlockModal () {
 | 
			
		||||
  return import(/* webpackChunkName: "modals/block_modal" */'../components/block_modal');
 | 
			
		||||
  return import('../components/block_modal');
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function DomainBlockModal () {
 | 
			
		||||
  return import(/* webpackChunkName: "modals/domain_block_modal" */'../components/domain_block_modal');
 | 
			
		||||
  return import('../components/domain_block_modal');
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function ReportModal () {
 | 
			
		||||
  return import(/* webpackChunkName: "modals/report_modal" */'../components/report_modal');
 | 
			
		||||
  return import('../components/report_modal');
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function IgnoreNotificationsModal () {
 | 
			
		||||
  return import(/* webpackChunkName: "modals/domain_block_modal" */'../components/ignore_notifications_modal');
 | 
			
		||||
  return import('../components/ignore_notifications_modal');
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function MediaGallery () {
 | 
			
		||||
  return import(/* webpackChunkName: "status/media_gallery" */'../../../components/media_gallery');
 | 
			
		||||
  return import('../../../components/media_gallery');
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function Video () {
 | 
			
		||||
  return import(/* webpackChunkName: "features/video" */'../../video');
 | 
			
		||||
  return import('../../video');
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function EmbedModal () {
 | 
			
		||||
  return import(/* webpackChunkName: "modals/embed_modal" */'../components/embed_modal');
 | 
			
		||||
  return import('../components/embed_modal');
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function ListAdder () {
 | 
			
		||||
  return import(/*webpackChunkName: "features/list_adder" */'../../list_adder');
 | 
			
		||||
  return import('../../list_adder');
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function Tesseract () {
 | 
			
		||||
  return import(/*webpackChunkName: "tesseract" */'tesseract.js');
 | 
			
		||||
  return import('tesseract.js');
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function Audio () {
 | 
			
		||||
  return import(/* webpackChunkName: "features/audio" */'../../audio');
 | 
			
		||||
  return import('../../audio');
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function Directory () {
 | 
			
		||||
  return import(/* webpackChunkName: "features/directory" */'../../directory');
 | 
			
		||||
  return import('../../directory');
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function OnboardingProfile () {
 | 
			
		||||
  return import(/* webpackChunkName: "features/onboarding" */'../../onboarding/profile');
 | 
			
		||||
  return import('../../onboarding/profile');
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function OnboardingFollows () {
 | 
			
		||||
  return import(/* webpackChunkName: "features/onboarding" */'../../onboarding/follows');
 | 
			
		||||
  return import('../../onboarding/follows');
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function CompareHistoryModal () {
 | 
			
		||||
  return import(/*webpackChunkName: "modals/compare_history_modal" */'../components/compare_history_modal');
 | 
			
		||||
  return import('../components/compare_history_modal');
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function Explore () {
 | 
			
		||||
  return import(/* webpackChunkName: "features/explore" */'../../explore');
 | 
			
		||||
  return import('../../explore');
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function Search () {
 | 
			
		||||
  return import(/* webpackChunkName: "features/explore" */'../../search');
 | 
			
		||||
  return import('../../search');
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function FilterModal () {
 | 
			
		||||
  return import(/*webpackChunkName: "modals/filter_modal" */'../components/filter_modal');
 | 
			
		||||
  return import('../components/filter_modal');
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function InteractionModal () {
 | 
			
		||||
  return import(/*webpackChunkName: "modals/interaction_modal" */'../../interaction_modal');
 | 
			
		||||
  return import('../../interaction_modal');
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function SubscribedLanguagesModal () {
 | 
			
		||||
  return import(/*webpackChunkName: "modals/subscribed_languages_modal" */'../../subscribed_languages_modal');
 | 
			
		||||
  return import('../../subscribed_languages_modal');
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function ClosedRegistrationsModal () {
 | 
			
		||||
  return import(/*webpackChunkName: "modals/closed_registrations_modal" */'../../closed_registrations_modal');
 | 
			
		||||
  return import('../../closed_registrations_modal');
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function About () {
 | 
			
		||||
  return import(/*webpackChunkName: "features/about" */'../../about');
 | 
			
		||||
  return import('../../about');
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function PrivacyPolicy () {
 | 
			
		||||
  return import(/*webpackChunkName: "features/privacy_policy" */'../../privacy_policy');
 | 
			
		||||
  return import('../../privacy_policy');
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function TermsOfService () {
 | 
			
		||||
  return import(/*webpackChunkName: "features/terms_of_service" */'../../terms_of_service');
 | 
			
		||||
  return import('../../terms_of_service');
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function NotificationRequests () {
 | 
			
		||||
  return import(/*webpackChunkName: "features/notifications/requests" */'../../notifications/requests');
 | 
			
		||||
  return import('../../notifications/requests');
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function NotificationRequest () {
 | 
			
		||||
  return import(/*webpackChunkName: "features/notifications/request" */'../../notifications/request');
 | 
			
		||||
  return import('../../notifications/request');
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function LinkTimeline () {
 | 
			
		||||
  return import(/*webpackChunkName: "features/link_timeline" */'../../link_timeline');
 | 
			
		||||
  return import('../../link_timeline');
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function AnnualReportModal () {
 | 
			
		||||
  return import(/*webpackChunkName: "modals/annual_report_modal" */'../components/annual_report_modal');
 | 
			
		||||
  return import('../components/annual_report_modal');
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function ListEdit () {
 | 
			
		||||
  return import(/*webpackChunkName: "features/lists" */'../../lists/new');
 | 
			
		||||
  return import('../../lists/new');
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function ListMembers () {
 | 
			
		||||
  return import(/* webpackChunkName: "features/lists" */'../../lists/members');
 | 
			
		||||
  return import('../../lists/members');
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -3,7 +3,7 @@
 | 
			
		||||
// can at least log in using KaiOS devices).
 | 
			
		||||
 | 
			
		||||
function importArrowKeyNavigation() {
 | 
			
		||||
  return import(/* webpackChunkName: "arrow-key-navigation" */ 'arrow-key-navigation');
 | 
			
		||||
  return import('arrow-key-navigation');
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export default function loadKeyboardExtensions() {
 | 
			
		||||
 
 | 
			
		||||
@@ -5,6 +5,10 @@ import { isLocaleLoaded, setLocale } from './global_locale';
 | 
			
		||||
 | 
			
		||||
const localeLoadingSemaphore = new Semaphore(1);
 | 
			
		||||
 | 
			
		||||
const localeFiles = import.meta.glob<{ default: LocaleData['messages'] }>([
 | 
			
		||||
  './*.json',
 | 
			
		||||
]);
 | 
			
		||||
 | 
			
		||||
export async function loadLocale() {
 | 
			
		||||
  // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing -- we want to match empty strings
 | 
			
		||||
  const locale = document.querySelector<HTMLElement>('html')?.lang || 'en';
 | 
			
		||||
@@ -17,13 +21,14 @@ export async function loadLocale() {
 | 
			
		||||
    // if the locale is already set, then do nothing
 | 
			
		||||
    if (isLocaleLoaded()) return;
 | 
			
		||||
 | 
			
		||||
    const localeData = (await import(
 | 
			
		||||
      /* webpackMode: "lazy" */
 | 
			
		||||
      /* webpackChunkName: "locale/[request]" */
 | 
			
		||||
      /* webpackInclude: /\.json$/ */
 | 
			
		||||
      /* webpackPreload: true */
 | 
			
		||||
      `mastodon/locales/${locale}.json`
 | 
			
		||||
    )) as LocaleData['messages'];
 | 
			
		||||
    // If there is no locale file, then fallback to english
 | 
			
		||||
    const localeFile = Object.hasOwn(localeFiles, `./${locale}.json`)
 | 
			
		||||
      ? localeFiles[`./${locale}.json`]
 | 
			
		||||
      : localeFiles['./en.json'];
 | 
			
		||||
 | 
			
		||||
    if (!localeFile) throw new Error('Could not load the locale JSON file');
 | 
			
		||||
 | 
			
		||||
    const { default: localeData } = await localeFile();
 | 
			
		||||
 | 
			
		||||
    setLocale({ messages: localeData, locale });
 | 
			
		||||
  });
 | 
			
		||||
 
 | 
			
		||||
@@ -7,17 +7,19 @@ import * as perf from 'mastodon/performance';
 | 
			
		||||
import ready from 'mastodon/ready';
 | 
			
		||||
import { store } from 'mastodon/store';
 | 
			
		||||
 | 
			
		||||
import { isProduction } from './utils/environment';
 | 
			
		||||
import { isProduction, isDevelopment } from './utils/environment';
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @returns {Promise<void>}
 | 
			
		||||
 */
 | 
			
		||||
function main() {
 | 
			
		||||
  perf.start('main()');
 | 
			
		||||
 | 
			
		||||
  return ready(async () => {
 | 
			
		||||
    const mountNode = document.getElementById('mastodon');
 | 
			
		||||
    const props = JSON.parse(mountNode.getAttribute('data-props'));
 | 
			
		||||
    if (!mountNode) {
 | 
			
		||||
      throw new Error('Mount node not found');
 | 
			
		||||
    }
 | 
			
		||||
    const props = JSON.parse(
 | 
			
		||||
      mountNode.getAttribute('data-props') ?? '{}',
 | 
			
		||||
    ) as Record<string, unknown>;
 | 
			
		||||
 | 
			
		||||
    const root = createRoot(mountNode);
 | 
			
		||||
    root.render(<Mastodon {...props} />);
 | 
			
		||||
@@ -25,8 +27,10 @@ function main() {
 | 
			
		||||
 | 
			
		||||
    if (isProduction() && me && 'serviceWorker' in navigator) {
 | 
			
		||||
      const { Workbox } = await import('workbox-window');
 | 
			
		||||
      const wb = new Workbox('/sw.js');
 | 
			
		||||
      /** @type {ServiceWorkerRegistration} */
 | 
			
		||||
      const wb = new Workbox(
 | 
			
		||||
        isDevelopment() ? '/packs-dev/dev-sw.js?dev-sw' : '/sw.js',
 | 
			
		||||
        { type: 'module', scope: '/' },
 | 
			
		||||
      );
 | 
			
		||||
      let registration;
 | 
			
		||||
 | 
			
		||||
      try {
 | 
			
		||||
@@ -35,8 +39,14 @@ function main() {
 | 
			
		||||
        console.error(err);
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      if (registration && 'Notification' in window && Notification.permission === 'granted') {
 | 
			
		||||
        const registerPushNotifications = await import('mastodon/actions/push_notifications');
 | 
			
		||||
      if (
 | 
			
		||||
        registration &&
 | 
			
		||||
        'Notification' in window &&
 | 
			
		||||
        Notification.permission === 'granted'
 | 
			
		||||
      ) {
 | 
			
		||||
        const registerPushNotifications = await import(
 | 
			
		||||
          'mastodon/actions/push_notifications'
 | 
			
		||||
        );
 | 
			
		||||
 | 
			
		||||
        store.dispatch(registerPushNotifications.register());
 | 
			
		||||
      }
 | 
			
		||||
@@ -46,4 +56,5 @@ function main() {
 | 
			
		||||
  });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// eslint-disable-next-line import/no-default-export
 | 
			
		||||
export default main;
 | 
			
		||||
@@ -1,24 +1,11 @@
 | 
			
		||||
//
 | 
			
		||||
// Tools for performance debugging, only enabled in development mode.
 | 
			
		||||
// Open up Chrome Dev Tools, then Timeline, then User Timing to see output.
 | 
			
		||||
// Also see config/webpack/loaders/mark.js for the webpack loader marks.
 | 
			
		||||
 | 
			
		||||
import * as marky from 'marky';
 | 
			
		||||
 | 
			
		||||
import { isDevelopment } from './utils/environment';
 | 
			
		||||
 | 
			
		||||
if (isDevelopment()) {
 | 
			
		||||
  if (typeof performance !== 'undefined' && performance.setResourceTimingBufferSize) {
 | 
			
		||||
    // Increase Firefox's performance entry limit; otherwise it's capped to 150.
 | 
			
		||||
    // See: https://bugzilla.mozilla.org/show_bug.cgi?id=1331135
 | 
			
		||||
    performance.setResourceTimingBufferSize(Infinity);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  // allows us to easily do e.g. ReactPerf.printWasted() while debugging
 | 
			
		||||
  //window.ReactPerf = require('react-addons-perf');
 | 
			
		||||
  //window.ReactPerf.start();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function start(name) {
 | 
			
		||||
  if (isDevelopment()) {
 | 
			
		||||
    marky.mark(name);
 | 
			
		||||
 
 | 
			
		||||
@@ -2,10 +2,13 @@
 | 
			
		||||
// If there are no polyfills, then this is just Promise.resolve() which means
 | 
			
		||||
// it will execute in the same tick of the event loop (i.e. near-instant).
 | 
			
		||||
 | 
			
		||||
// eslint-disable-next-line import/extensions -- This file is virtual so it thinks it has an extension
 | 
			
		||||
import 'vite/modulepreload-polyfill';
 | 
			
		||||
 | 
			
		||||
import { loadIntlPolyfills } from './intl';
 | 
			
		||||
 | 
			
		||||
function importExtraPolyfills() {
 | 
			
		||||
  return import(/* webpackChunkName: "extra_polyfills" */ './extra_polyfills');
 | 
			
		||||
  return import('./extra_polyfills');
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function loadPolyfills() {
 | 
			
		||||
 
 | 
			
		||||
@@ -54,11 +54,9 @@ async function loadIntlPluralRulesPolyfills(locale: string) {
 | 
			
		||||
    return;
 | 
			
		||||
  }
 | 
			
		||||
  // Load the polyfill 1st BEFORE loading data
 | 
			
		||||
  await import('@formatjs/intl-pluralrules/polyfill-force');
 | 
			
		||||
  await import(
 | 
			
		||||
    /* webpackChunkName: "i18n-pluralrules-polyfill" */ '@formatjs/intl-pluralrules/polyfill-force'
 | 
			
		||||
  );
 | 
			
		||||
  await import(
 | 
			
		||||
    /* webpackChunkName: "i18n-pluralrules-polyfill-[request]" */ `@formatjs/intl-pluralrules/locale-data/${unsupportedLocale}`
 | 
			
		||||
    `../../../../node_modules/@formatjs/intl-pluralrules/locale-data/${unsupportedLocale}.js`
 | 
			
		||||
  );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -70,11 +68,9 @@ async function loadIntlPluralRulesPolyfills(locale: string) {
 | 
			
		||||
//   }
 | 
			
		||||
//   // Load the polyfill 1st BEFORE loading data
 | 
			
		||||
//   await import(
 | 
			
		||||
//     /* webpackChunkName: "i18n-relativetimeformat-polyfill" */
 | 
			
		||||
//     '@formatjs/intl-relativetimeformat/polyfill-force'
 | 
			
		||||
//   );
 | 
			
		||||
//   await import(
 | 
			
		||||
//     /* webpackChunkName: "i18n-relativetimeformat-polyfill-[request]" */
 | 
			
		||||
//     `@formatjs/intl-relativetimeformat/locale-data/${unsupportedLocale}`
 | 
			
		||||
//   );
 | 
			
		||||
// }
 | 
			
		||||
 
 | 
			
		||||
@@ -1,5 +1,4 @@
 | 
			
		||||
import { ExpirationPlugin } from 'workbox-expiration';
 | 
			
		||||
import { precacheAndRoute } from 'workbox-precaching';
 | 
			
		||||
import { registerRoute } from 'workbox-routing';
 | 
			
		||||
import { CacheFirst } from 'workbox-strategies';
 | 
			
		||||
 | 
			
		||||
@@ -15,10 +14,9 @@ function fetchRoot() {
 | 
			
		||||
  return fetch('/', { credentials: 'include', redirect: 'manual' });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
precacheAndRoute(self.__WB_MANIFEST);
 | 
			
		||||
 | 
			
		||||
registerRoute(
 | 
			
		||||
  /locale_.*\.js$/,
 | 
			
		||||
  /intl\/.*\.js$/,
 | 
			
		||||
  new CacheFirst({
 | 
			
		||||
    cacheName: `${CACHE_NAME_PREFIX}locales`,
 | 
			
		||||
    plugins: [
 | 
			
		||||
@@ -1,41 +0,0 @@
 | 
			
		||||
/* @preval */
 | 
			
		||||
 | 
			
		||||
const fs   = require('fs');
 | 
			
		||||
const path = require('path');
 | 
			
		||||
 | 
			
		||||
const { defineMessages } = require('react-intl');
 | 
			
		||||
 | 
			
		||||
const messages = defineMessages({
 | 
			
		||||
  mentioned_you: { id: 'notification.mentioned_you', defaultMessage: '{name} mentioned you' },
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
const filtered  = {};
 | 
			
		||||
const filenames = fs.readdirSync(path.resolve(__dirname, '../locales'));
 | 
			
		||||
 | 
			
		||||
filenames.forEach(filename => {
 | 
			
		||||
  if (!filename.match(/\.json$/)) return;
 | 
			
		||||
 | 
			
		||||
  const content = fs.readFileSync(path.resolve(__dirname, `../locales/${filename}`), 'utf-8');
 | 
			
		||||
  const full    = JSON.parse(content);
 | 
			
		||||
  const locale  = filename.split('.')[0];
 | 
			
		||||
 | 
			
		||||
  filtered[locale] = {
 | 
			
		||||
    'notification.favourite': full['notification.favourite'] || '',
 | 
			
		||||
    'notification.follow': full['notification.follow'] || '',
 | 
			
		||||
    'notification.follow_request': full['notification.follow_request'] || '',
 | 
			
		||||
    'notification.mention': full[messages.mentioned_you.id] || '',
 | 
			
		||||
    'notification.reblog': full['notification.reblog'] || '',
 | 
			
		||||
    'notification.poll': full['notification.poll'] || '',
 | 
			
		||||
    'notification.status': full['notification.status'] || '',
 | 
			
		||||
    'notification.update': full['notification.update'] || '',
 | 
			
		||||
    'notification.admin.sign_up': full['notification.admin.sign_up'] || '',
 | 
			
		||||
 | 
			
		||||
    'status.show_more': full['status.show_more'] || '',
 | 
			
		||||
    'status.reblog': full['status.reblog'] || '',
 | 
			
		||||
    'status.favourite': full['status.favourite'] || '',
 | 
			
		||||
 | 
			
		||||
    'notifications.group': full['notifications.group'] || '',
 | 
			
		||||
  };
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
module.exports = JSON.parse(JSON.stringify(filtered));
 | 
			
		||||
@@ -1,8 +1,10 @@
 | 
			
		||||
import { IntlMessageFormat } from 'intl-messageformat';
 | 
			
		||||
 | 
			
		||||
import { unescape } from 'lodash';
 | 
			
		||||
 | 
			
		||||
import locales from './web_push_locales';
 | 
			
		||||
// see config/vite/plugins/sw-locales
 | 
			
		||||
// it needs to be updated when new locale keys are used in this file
 | 
			
		||||
// eslint-disable-next-line import/no-unresolved
 | 
			
		||||
import locales from "virtual:mastodon-sw-locales";
 | 
			
		||||
 | 
			
		||||
const MAX_NOTIFICATIONS = 5;
 | 
			
		||||
const GROUP_TAG = 'tag';
 | 
			
		||||
 
 | 
			
		||||
@@ -1,7 +1,11 @@
 | 
			
		||||
export function isDevelopment() {
 | 
			
		||||
  return process.env.NODE_ENV === 'development';
 | 
			
		||||
  if (typeof process !== 'undefined')
 | 
			
		||||
    return process.env.NODE_ENV === 'development';
 | 
			
		||||
  else return import.meta.env.DEV;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function isProduction() {
 | 
			
		||||
  return process.env.NODE_ENV === 'production';
 | 
			
		||||
  if (typeof process !== 'undefined')
 | 
			
		||||
    return process.env.NODE_ENV === 'production';
 | 
			
		||||
  else return import.meta.env.PROD;
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,4 +1,4 @@
 | 
			
		||||
@use 'fonts/inter';
 | 
			
		||||
@use '../fonts/inter';
 | 
			
		||||
 | 
			
		||||
body {
 | 
			
		||||
  accent-color: #6364ff;
 | 
			
		||||
@@ -259,7 +259,7 @@ table + p {
 | 
			
		||||
.email-header-td {
 | 
			
		||||
  padding: 16px 32px;
 | 
			
		||||
  background-color: #1b001f;
 | 
			
		||||
  background-image: url('../images/mailer-new/common/header-bg-start.png');
 | 
			
		||||
  background-image: url('../../images/mailer-new/common/header-bg-start.png');
 | 
			
		||||
  background-position: left top;
 | 
			
		||||
  background-repeat: repeat;
 | 
			
		||||
}
 | 
			
		||||
@@ -426,7 +426,7 @@ table + p {
 | 
			
		||||
 | 
			
		||||
// Body content
 | 
			
		||||
.email-body-td {
 | 
			
		||||
  background-image: url('../images/mailer-new/common/header-bg-end.png');
 | 
			
		||||
  background-image: url('../../images/mailer-new/common/header-bg-end.png');
 | 
			
		||||
  background-position: left top;
 | 
			
		||||
  background-repeat: no-repeat;
 | 
			
		||||
}
 | 
			
		||||
@@ -922,7 +922,7 @@ table + p {
 | 
			
		||||
// Extra content on light purple background
 | 
			
		||||
.email-extra-wave {
 | 
			
		||||
  height: 42px;
 | 
			
		||||
  background-image: url('../images/mailer-new/welcome/purple-extra-soft-wave.png');
 | 
			
		||||
  background-image: url('../../images/mailer-new/welcome/purple-extra-soft-wave.png');
 | 
			
		||||
  background-position: bottom center;
 | 
			
		||||
  background-repeat: no-repeat;
 | 
			
		||||
}
 | 
			
		||||
@@ -930,7 +930,7 @@ table + p {
 | 
			
		||||
.email-extra-td {
 | 
			
		||||
  padding: 32px 32px 24px;
 | 
			
		||||
  background-color: #f0f0ff;
 | 
			
		||||
  background-image: url('../images/mailer-new/welcome/purple-extra-soft-spacer.png'); // Using an image to maintain the color even in forced dark modes
 | 
			
		||||
  background-image: url('../../images/mailer-new/welcome/purple-extra-soft-spacer.png'); // Using an image to maintain the color even in forced dark modes
 | 
			
		||||
 | 
			
		||||
  .email-column-td {
 | 
			
		||||
    padding-top: 8px;
 | 
			
		||||
@@ -1,6 +1,6 @@
 | 
			
		||||
@font-face {
 | 
			
		||||
  font-family: Inter;
 | 
			
		||||
  src: url('../fonts/inter/inter-variable-font-slnt-wght.woff2')
 | 
			
		||||
  src: url('../../fonts/inter/inter-variable-font-slnt-wght.woff2')
 | 
			
		||||
    format('woff2-variations');
 | 
			
		||||
  font-weight: 100 900;
 | 
			
		||||
  font-style: normal;
 | 
			
		||||
 
 | 
			
		||||
@@ -393,7 +393,7 @@ code {
 | 
			
		||||
      max-width: 100%;
 | 
			
		||||
      height: auto;
 | 
			
		||||
      border-radius: var(--avatar-border-radius);
 | 
			
		||||
      background: url('images/void.png');
 | 
			
		||||
      background: url('@/images/void.png');
 | 
			
		||||
 | 
			
		||||
      &[src$='missing.png'] {
 | 
			
		||||
        visibility: hidden;
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										19
									
								
								app/javascript/types/image.d.ts
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										19
									
								
								app/javascript/types/image.d.ts
									
									
									
									
										vendored
									
									
								
							@@ -1,3 +1,5 @@
 | 
			
		||||
/// <reference types="vite-plugin-svgr/client" />
 | 
			
		||||
 | 
			
		||||
/* eslint-disable import/no-default-export */
 | 
			
		||||
declare module '*.avif' {
 | 
			
		||||
  const path: string;
 | 
			
		||||
@@ -19,23 +21,6 @@ declare module '*.png' {
 | 
			
		||||
  export default path;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
declare module '*.svg' {
 | 
			
		||||
  const path: string;
 | 
			
		||||
  export default path;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
declare module '*.svg?react' {
 | 
			
		||||
  import type React from 'react';
 | 
			
		||||
 | 
			
		||||
  interface SVGPropsWithTitle extends React.SVGProps<SVGSVGElement> {
 | 
			
		||||
    title?: string;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  const ReactComponent: React.FC<SVGPropsWithTitle>;
 | 
			
		||||
 | 
			
		||||
  export default ReactComponent;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
declare module '*.webp' {
 | 
			
		||||
  const path: string;
 | 
			
		||||
  export default path;
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										59
									
								
								app/javascript/types/virtual.d.ts
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										59
									
								
								app/javascript/types/virtual.d.ts
									
									
									
									
										vendored
									
									
										Normal file
									
								
							@@ -0,0 +1,59 @@
 | 
			
		||||
declare module 'virtual:mastodon-emoji-compressed' {
 | 
			
		||||
  import type { BaseEmoji, EmojiData, NimbleEmojiIndex } from 'emoji-mart';
 | 
			
		||||
  import type { Category, Data, Emoji } from 'emoji-mart/dist-es/utils/data';
 | 
			
		||||
  /*
 | 
			
		||||
   * The 'search' property, although not defined in the [`Emoji`]{@link node_modules/@types/emoji-mart/dist-es/utils/data.d.ts#Emoji} type,
 | 
			
		||||
   * is used in the application.
 | 
			
		||||
   * This could be due to an oversight by the library maintainer.
 | 
			
		||||
   * The `search` property is defined and used [here]{@link node_modules/emoji-mart/dist/utils/data.js#uncompress}.
 | 
			
		||||
   */
 | 
			
		||||
  export type Search = string;
 | 
			
		||||
  /*
 | 
			
		||||
   * The 'skins' property does not exist in the application data.
 | 
			
		||||
   * This could be a potential area of refactoring or error handling.
 | 
			
		||||
   * The non-existence of 'skins' property is evident at [this location]{@link app/javascript/mastodon/features/emoji/emoji_compressed.js:121}.
 | 
			
		||||
   */
 | 
			
		||||
  type Skins = null;
 | 
			
		||||
 | 
			
		||||
  type Filename = string;
 | 
			
		||||
  type UnicodeFilename = string;
 | 
			
		||||
  export type FilenameData = [
 | 
			
		||||
    filename: Filename,
 | 
			
		||||
    unicodeFilename?: UnicodeFilename,
 | 
			
		||||
  ][];
 | 
			
		||||
  export type ShortCodesToEmojiDataKey =
 | 
			
		||||
    | EmojiData['id']
 | 
			
		||||
    | BaseEmoji['native']
 | 
			
		||||
    | keyof NimbleEmojiIndex['emojis'];
 | 
			
		||||
 | 
			
		||||
  type SearchData = [
 | 
			
		||||
    BaseEmoji['native'],
 | 
			
		||||
    Emoji['short_names'],
 | 
			
		||||
    Search,
 | 
			
		||||
    Emoji['unified'],
 | 
			
		||||
  ];
 | 
			
		||||
 | 
			
		||||
  export type ShortCodesToEmojiData = Record<
 | 
			
		||||
    ShortCodesToEmojiDataKey,
 | 
			
		||||
    [FilenameData, SearchData]
 | 
			
		||||
  >;
 | 
			
		||||
  type EmojisWithoutShortCodes = FilenameData;
 | 
			
		||||
 | 
			
		||||
  type EmojiCompressed = [
 | 
			
		||||
    ShortCodesToEmojiData,
 | 
			
		||||
    Skins,
 | 
			
		||||
    Category[],
 | 
			
		||||
    Data['aliases'],
 | 
			
		||||
    EmojisWithoutShortCodes,
 | 
			
		||||
    Data,
 | 
			
		||||
  ];
 | 
			
		||||
 | 
			
		||||
  /*
 | 
			
		||||
   * `emoji_compressed.js` uses `babel-plugin-preval`, which makes it difficult to convert to TypeScript.
 | 
			
		||||
   * As a temporary solution, we are allowing a default export here to apply the TypeScript type `EmojiCompressed` to the JS file export.
 | 
			
		||||
   * - {@link app/javascript/mastodon/features/emoji/emoji_compressed.js}
 | 
			
		||||
   */
 | 
			
		||||
  declare const emojiCompressed: EmojiCompressed;
 | 
			
		||||
 | 
			
		||||
  export default emojiCompressed; // eslint-disable-line import/no-default-export
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user