mirror of
https://github.com/glitch-soc/mastodon.git
synced 2026-03-29 03:00:33 +02:00
Merge commit 'c4f47adb49663f24ee80d9174ab24431a8c165c0' into glitch-soc/merge-upstream
Too many conflicts to list, because of webpack → vite migration.
This commit is contained in:
@@ -9,6 +9,7 @@ services:
|
|||||||
environment:
|
environment:
|
||||||
RAILS_ENV: development
|
RAILS_ENV: development
|
||||||
NODE_ENV: development
|
NODE_ENV: development
|
||||||
|
VITE_RUBY_HOST: 0.0.0.0
|
||||||
BIND: 0.0.0.0
|
BIND: 0.0.0.0
|
||||||
BOOTSNAP_CACHE_DIR: /tmp
|
BOOTSNAP_CACHE_DIR: /tmp
|
||||||
REDIS_HOST: redis
|
REDIS_HOST: redis
|
||||||
@@ -22,11 +23,12 @@ services:
|
|||||||
ES_PORT: '9200'
|
ES_PORT: '9200'
|
||||||
LIBRE_TRANSLATE_ENDPOINT: http://libretranslate:5000
|
LIBRE_TRANSLATE_ENDPOINT: http://libretranslate:5000
|
||||||
LOCAL_DOMAIN: ${LOCAL_DOMAIN:-localhost:3000}
|
LOCAL_DOMAIN: ${LOCAL_DOMAIN:-localhost:3000}
|
||||||
|
VITE_DEV_SERVER_PUBLIC: ${VITE_DEV_SERVER_PUBLIC:-localhost:3036}
|
||||||
# Overrides default command so things don't shut down after the process ends.
|
# Overrides default command so things don't shut down after the process ends.
|
||||||
command: sleep infinity
|
command: sleep infinity
|
||||||
ports:
|
ports:
|
||||||
- '3000:3000'
|
- '3000:3000'
|
||||||
- '3035:3035'
|
- '3036:3036'
|
||||||
- '4000:4000'
|
- '4000:4000'
|
||||||
networks:
|
networks:
|
||||||
- external_network
|
- external_network
|
||||||
|
|||||||
17
.github/renovate.json5
vendored
17
.github/renovate.json5
vendored
@@ -25,23 +25,6 @@
|
|||||||
'tesseract.js', // Requires code changes
|
'tesseract.js', // Requires code changes
|
||||||
'react-hotkeys', // Requires code changes
|
'react-hotkeys', // Requires code changes
|
||||||
|
|
||||||
// Requires Webpacker upgrade or replacement
|
|
||||||
'@svgr/webpack',
|
|
||||||
'@types/webpack',
|
|
||||||
'babel-loader',
|
|
||||||
'compression-webpack-plugin',
|
|
||||||
'css-loader',
|
|
||||||
'imports-loader',
|
|
||||||
'mini-css-extract-plugin',
|
|
||||||
'postcss-loader',
|
|
||||||
'sass-loader',
|
|
||||||
'terser-webpack-plugin',
|
|
||||||
'webpack',
|
|
||||||
'webpack-assets-manifest',
|
|
||||||
'webpack-bundle-analyzer',
|
|
||||||
'webpack-dev-server',
|
|
||||||
'webpack-cli',
|
|
||||||
|
|
||||||
// react-router: Requires manual upgrade
|
// react-router: Requires manual upgrade
|
||||||
'history',
|
'history',
|
||||||
'react-router-dom',
|
'react-router-dom',
|
||||||
|
|||||||
4
.github/workflows/test-ruby.yml
vendored
4
.github/workflows/test-ruby.yml
vendored
@@ -49,7 +49,7 @@ jobs:
|
|||||||
public/assets
|
public/assets
|
||||||
public/packs
|
public/packs
|
||||||
public/packs-test
|
public/packs-test
|
||||||
tmp/cache/webpacker
|
tmp/cache/vite
|
||||||
key: ${{ matrix.mode }}-assets-${{ github.head_ref || github.ref_name }}-${{ github.sha }}
|
key: ${{ matrix.mode }}-assets-${{ github.head_ref || github.ref_name }}-${{ github.sha }}
|
||||||
restore-keys: |
|
restore-keys: |
|
||||||
${{ matrix.mode }}-assets-${{ github.head_ref || github.ref_name }}-${{ github.sha }}
|
${{ matrix.mode }}-assets-${{ github.head_ref || github.ref_name }}-${{ github.sha }}
|
||||||
@@ -63,7 +63,7 @@ jobs:
|
|||||||
|
|
||||||
- name: Archive asset artifacts
|
- name: Archive asset artifacts
|
||||||
run: |
|
run: |
|
||||||
tar --exclude={"*.br","*.gz"} -zcf artifacts.tar.gz public/assets public/packs*
|
tar --exclude={"*.br","*.gz"} -zcf artifacts.tar.gz public/assets public/packs* tmp/cache/vite/last-build*.json
|
||||||
|
|
||||||
- uses: actions/upload-artifact@v4
|
- uses: actions/upload-artifact@v4
|
||||||
if: matrix.mode == 'test'
|
if: matrix.mode == 'test'
|
||||||
|
|||||||
3
.gitignore
vendored
3
.gitignore
vendored
@@ -21,10 +21,11 @@
|
|||||||
/public/system
|
/public/system
|
||||||
/public/assets
|
/public/assets
|
||||||
/public/packs
|
/public/packs
|
||||||
|
/public/packs-dev
|
||||||
/public/packs-test
|
/public/packs-test
|
||||||
.env
|
.env
|
||||||
.env.production
|
.env.production
|
||||||
/node_modules/
|
node_modules/
|
||||||
/build/
|
/build/
|
||||||
|
|
||||||
# Ignore Vagrant files
|
# Ignore Vagrant files
|
||||||
|
|||||||
@@ -18,10 +18,6 @@
|
|||||||
!/log/.keep
|
!/log/.keep
|
||||||
/tmp
|
/tmp
|
||||||
/coverage
|
/coverage
|
||||||
/public/system
|
|
||||||
/public/assets
|
|
||||||
/public/packs
|
|
||||||
/public/packs-test
|
|
||||||
.env
|
.env
|
||||||
.env.production
|
.env.production
|
||||||
.env.development
|
.env.development
|
||||||
@@ -60,6 +56,7 @@ docker-compose.override.yml
|
|||||||
/public/packs
|
/public/packs
|
||||||
/public/packs-test
|
/public/packs-test
|
||||||
/public/system
|
/public/system
|
||||||
|
/public/vite*
|
||||||
|
|
||||||
# Ignore emoji map file
|
# Ignore emoji map file
|
||||||
/app/javascript/mastodon/features/emoji/emoji_map.json
|
/app/javascript/mastodon/features/emoji/emoji_map.json
|
||||||
|
|||||||
3
Gemfile
3
Gemfile
@@ -95,7 +95,6 @@ gem 'tty-prompt', '~> 0.23', require: false
|
|||||||
gem 'twitter-text', '~> 3.1.0'
|
gem 'twitter-text', '~> 3.1.0'
|
||||||
gem 'tzinfo-data', '~> 1.2023'
|
gem 'tzinfo-data', '~> 1.2023'
|
||||||
gem 'webauthn', '~> 3.0'
|
gem 'webauthn', '~> 3.0'
|
||||||
gem 'webpacker', '~> 5.4'
|
|
||||||
gem 'webpush', github: 'mastodon/webpush', ref: '9631ac63045cfabddacc69fc06e919b4c13eb913'
|
gem 'webpush', github: 'mastodon/webpush', ref: '9631ac63045cfabddacc69fc06e919b4c13eb913'
|
||||||
|
|
||||||
gem 'json-ld'
|
gem 'json-ld'
|
||||||
@@ -230,3 +229,5 @@ gem 'rubyzip', '~> 2.3'
|
|||||||
gem 'hcaptcha', '~> 7.1'
|
gem 'hcaptcha', '~> 7.1'
|
||||||
|
|
||||||
gem 'mail', '~> 2.8'
|
gem 'mail', '~> 2.8'
|
||||||
|
|
||||||
|
gem 'vite_rails', '~> 3.0.19'
|
||||||
|
|||||||
18
Gemfile.lock
18
Gemfile.lock
@@ -203,6 +203,7 @@ GEM
|
|||||||
railties (>= 5)
|
railties (>= 5)
|
||||||
dotenv (3.1.8)
|
dotenv (3.1.8)
|
||||||
drb (2.2.1)
|
drb (2.2.1)
|
||||||
|
dry-cli (1.2.0)
|
||||||
elasticsearch (7.17.11)
|
elasticsearch (7.17.11)
|
||||||
elasticsearch-api (= 7.17.11)
|
elasticsearch-api (= 7.17.11)
|
||||||
elasticsearch-transport (= 7.17.11)
|
elasticsearch-transport (= 7.17.11)
|
||||||
@@ -806,7 +807,6 @@ GEM
|
|||||||
rexml (~> 3.2, >= 3.2.5)
|
rexml (~> 3.2, >= 3.2.5)
|
||||||
rubyzip (>= 1.2.2, < 3.0)
|
rubyzip (>= 1.2.2, < 3.0)
|
||||||
websocket (~> 1.0)
|
websocket (~> 1.0)
|
||||||
semantic_range (3.1.0)
|
|
||||||
shoulda-matchers (6.5.0)
|
shoulda-matchers (6.5.0)
|
||||||
activesupport (>= 5.2.0)
|
activesupport (>= 5.2.0)
|
||||||
sidekiq (6.5.12)
|
sidekiq (6.5.12)
|
||||||
@@ -892,6 +892,15 @@ GEM
|
|||||||
validate_url (1.0.15)
|
validate_url (1.0.15)
|
||||||
activemodel (>= 3.0.0)
|
activemodel (>= 3.0.0)
|
||||||
public_suffix
|
public_suffix
|
||||||
|
vite_rails (3.0.19)
|
||||||
|
railties (>= 5.1, < 9)
|
||||||
|
vite_ruby (~> 3.0, >= 3.2.2)
|
||||||
|
vite_ruby (3.9.2)
|
||||||
|
dry-cli (>= 0.7, < 2)
|
||||||
|
logger (~> 1.6)
|
||||||
|
mutex_m
|
||||||
|
rack-proxy (~> 0.6, >= 0.6.1)
|
||||||
|
zeitwerk (~> 2.2)
|
||||||
warden (1.2.9)
|
warden (1.2.9)
|
||||||
rack (>= 2.0.9)
|
rack (>= 2.0.9)
|
||||||
webauthn (3.4.0)
|
webauthn (3.4.0)
|
||||||
@@ -910,11 +919,6 @@ GEM
|
|||||||
addressable (>= 2.8.0)
|
addressable (>= 2.8.0)
|
||||||
crack (>= 0.3.2)
|
crack (>= 0.3.2)
|
||||||
hashdiff (>= 0.4.0, < 2.0.0)
|
hashdiff (>= 0.4.0, < 2.0.0)
|
||||||
webpacker (5.4.4)
|
|
||||||
activesupport (>= 5.2)
|
|
||||||
rack-proxy (>= 0.6.1)
|
|
||||||
railties (>= 5.2)
|
|
||||||
semantic_range (>= 2.3.0)
|
|
||||||
webrick (1.9.1)
|
webrick (1.9.1)
|
||||||
websocket (1.2.11)
|
websocket (1.2.11)
|
||||||
websocket-driver (0.7.7)
|
websocket-driver (0.7.7)
|
||||||
@@ -1078,9 +1082,9 @@ DEPENDENCIES
|
|||||||
tty-prompt (~> 0.23)
|
tty-prompt (~> 0.23)
|
||||||
twitter-text (~> 3.1.0)
|
twitter-text (~> 3.1.0)
|
||||||
tzinfo-data (~> 1.2023)
|
tzinfo-data (~> 1.2023)
|
||||||
|
vite_rails (~> 3.0.19)
|
||||||
webauthn (~> 3.0)
|
webauthn (~> 3.0)
|
||||||
webmock (~> 3.18)
|
webmock (~> 3.18)
|
||||||
webpacker (~> 5.4)
|
|
||||||
webpush!
|
webpush!
|
||||||
xorcist (~> 1.1)
|
xorcist (~> 1.1)
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
web: env PORT=3000 RAILS_ENV=development bundle exec puma -C config/puma.rb
|
web: env PORT=3000 RAILS_ENV=development bundle exec puma -C config/puma.rb
|
||||||
sidekiq: env PORT=3000 RAILS_ENV=development bundle exec sidekiq
|
sidekiq: env PORT=3000 RAILS_ENV=development bundle exec sidekiq
|
||||||
stream: env PORT=4000 yarn workspace @mastodon/streaming start
|
stream: env PORT=4000 yarn workspace @mastodon/streaming start
|
||||||
webpack: bin/webpack-dev-server
|
vite: yarn dev
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ module ThemingConcern
|
|||||||
def current_skin
|
def current_skin
|
||||||
@current_skin ||= begin
|
@current_skin ||= begin
|
||||||
skins = Themes.instance.skins_for(current_flavour)
|
skins = Themes.instance.skins_for(current_flavour)
|
||||||
[current_user&.setting_skin, Setting.skin, 'system', 'default'].find { |skin| skins.include?(skin) }
|
[current_user&.setting_skin, Setting.skin, 'system', 'application'].find { |skin| skins.include?(skin) }
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -248,22 +248,8 @@ module ApplicationHelper
|
|||||||
end
|
end
|
||||||
|
|
||||||
# glitch-soc addition to handle the multiple flavors
|
# glitch-soc addition to handle the multiple flavors
|
||||||
def preload_locale_pack
|
def flavoured_vite_typescript_tag(pack_name, **)
|
||||||
supported_locales = Themes.instance.flavour(current_flavour)['locales']
|
vite_typescript_tag("#{Themes.instance.flavour(current_flavour)['pack_directory'].delete_prefix('app/javascript/')}/#{pack_name}", **)
|
||||||
preload_pack_asset "locales/#{current_flavour}/#{I18n.locale}-json.js" if supported_locales.include?(I18n.locale.to_s)
|
|
||||||
end
|
|
||||||
|
|
||||||
def flavoured_javascript_pack_tag(pack_name, **)
|
|
||||||
javascript_pack_tag("flavours/#{current_flavour}/#{pack_name}", **)
|
|
||||||
end
|
|
||||||
|
|
||||||
def flavoured_stylesheet_pack_tag(pack_name, **)
|
|
||||||
stylesheet_pack_tag("flavours/#{current_flavour}/#{pack_name}", **)
|
|
||||||
end
|
|
||||||
|
|
||||||
def preload_signed_in_js_packs
|
|
||||||
preload_files = Themes.instance.flavour(current_flavour)&.fetch('signed_in_preload', nil) || []
|
|
||||||
safe_join(preload_files.map { |entry| preload_pack_asset entry })
|
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ module RoutingHelper
|
|||||||
extend ActiveSupport::Concern
|
extend ActiveSupport::Concern
|
||||||
|
|
||||||
include ActionView::Helpers::AssetTagHelper
|
include ActionView::Helpers::AssetTagHelper
|
||||||
include Webpacker::Helper
|
include ViteRails::TagHelpers
|
||||||
|
|
||||||
included do
|
included do
|
||||||
include Rails.application.routes.url_helpers
|
include Rails.application.routes.url_helpers
|
||||||
@@ -25,7 +25,7 @@ module RoutingHelper
|
|||||||
end
|
end
|
||||||
|
|
||||||
def frontend_asset_path(source, **)
|
def frontend_asset_path(source, **)
|
||||||
asset_pack_path("media/#{source}", **)
|
vite_asset_path(source, **)
|
||||||
end
|
end
|
||||||
|
|
||||||
def frontend_asset_url(source, **)
|
def frontend_asset_url(source, **)
|
||||||
|
|||||||
@@ -6,11 +6,13 @@ module ThemeHelper
|
|||||||
|
|
||||||
if theme == 'system'
|
if theme == 'system'
|
||||||
''.html_safe.tap do |tags|
|
''.html_safe.tap do |tags|
|
||||||
tags << stylesheet_pack_tag("skins/#{flavour}/mastodon-light", media: 'not all and (prefers-color-scheme: dark)', crossorigin: 'anonymous')
|
tags << vite_stylesheet_tag("skins/#{flavour}/mastodon-light.scss", media: 'not all and (prefers-color-scheme: dark)', crossorigin: 'anonymous')
|
||||||
tags << stylesheet_pack_tag("skins/#{flavour}/default", media: '(prefers-color-scheme: dark)', crossorigin: 'anonymous')
|
tags << vite_stylesheet_tag("skins/#{flavour}/application.scss", media: '(prefers-color-scheme: dark)', crossorigin: 'anonymous')
|
||||||
end
|
end
|
||||||
|
elsif theme == 'default'
|
||||||
|
vite_stylesheet_tag "skins/#{flavour}/application.scss", media: 'all', crossorigin: 'anonymous'
|
||||||
else
|
else
|
||||||
stylesheet_pack_tag "skins/#{flavour}/#{theme}", media: 'all', crossorigin: 'anonymous'
|
vite_stylesheet_tag "skins/#{flavour}/#{theme}.scss", media: 'all', crossorigin: 'anonymous'
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
import './public-path';
|
|
||||||
import { createRoot } from 'react-dom/client';
|
import { createRoot } from 'react-dom/client';
|
||||||
|
|
||||||
import Rails from '@rails/ujs';
|
import Rails from '@rails/ujs';
|
||||||
@@ -273,7 +272,7 @@ async function mountReactComponent(element: Element) {
|
|||||||
);
|
);
|
||||||
|
|
||||||
const { default: Component } = (await import(
|
const { default: Component } = (await import(
|
||||||
`@/mastodon/components/admin/${componentName}`
|
`@/mastodon/components/admin/${componentName}.jsx`
|
||||||
)) as { default: React.ComponentType };
|
)) as { default: React.ComponentType };
|
||||||
|
|
||||||
const root = createRoot(element);
|
const root = createRoot(element);
|
||||||
|
|||||||
@@ -1,11 +1,6 @@
|
|||||||
import './public-path';
|
import { loadLocale } from 'mastodon/locales';
|
||||||
import main from 'mastodon/main';
|
import main from 'mastodon/main';
|
||||||
|
import { loadPolyfills } from 'mastodon/polyfills';
|
||||||
import { start } from '../mastodon/common';
|
|
||||||
import { loadLocale } from '../mastodon/locales';
|
|
||||||
import { loadPolyfills } from '../mastodon/polyfills';
|
|
||||||
|
|
||||||
start();
|
|
||||||
|
|
||||||
loadPolyfills()
|
loadPolyfills()
|
||||||
.then(loadLocale)
|
.then(loadLocale)
|
||||||
|
|||||||
@@ -1,4 +0,0 @@
|
|||||||
/* This file is a hack to have something more reliable than the upstream `common` tag
|
|
||||||
that is implicitly generated as the common chunk through webpack's `splitChunks` config */
|
|
||||||
|
|
||||||
import './public-path';
|
|
||||||
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 { createRoot } from 'react-dom/client';
|
||||||
|
|
||||||
import { afterInitialRender } from 'mastodon/hooks/useRenderSignal';
|
import { afterInitialRender } from 'mastodon/hooks/useRenderSignal';
|
||||||
|
|
||||||
import { start } from '../mastodon/common';
|
|
||||||
import { Status } from '../mastodon/features/standalone/status';
|
import { Status } from '../mastodon/features/standalone/status';
|
||||||
import { loadPolyfills } from '../mastodon/polyfills';
|
import { loadPolyfills } from '../mastodon/polyfills';
|
||||||
import ready from '../mastodon/ready';
|
import ready from '../mastodon/ready';
|
||||||
|
|
||||||
start();
|
|
||||||
|
|
||||||
function loaded() {
|
function loaded() {
|
||||||
const mountNode = document.getElementById('mastodon-status');
|
const mountNode = document.getElementById('mastodon-status');
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
import './public-path';
|
|
||||||
import ready from '../mastodon/ready';
|
import ready from '../mastodon/ready';
|
||||||
|
|
||||||
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 { createRoot } from 'react-dom/client';
|
||||||
|
|
||||||
import './public-path';
|
|
||||||
|
|
||||||
import { IntlMessageFormat } from 'intl-messageformat';
|
import { IntlMessageFormat } from 'intl-messageformat';
|
||||||
import type { MessageDescriptor, PrimitiveType } from 'react-intl';
|
import type { MessageDescriptor, PrimitiveType } from 'react-intl';
|
||||||
import { defineMessages } from 'react-intl';
|
import { defineMessages } from 'react-intl';
|
||||||
@@ -10,7 +8,6 @@ import Rails from '@rails/ujs';
|
|||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
import { throttle } from 'lodash';
|
import { throttle } from 'lodash';
|
||||||
|
|
||||||
import { start } from '../mastodon/common';
|
|
||||||
import { timeAgoString } from '../mastodon/components/relative_timestamp';
|
import { timeAgoString } from '../mastodon/components/relative_timestamp';
|
||||||
import emojify from '../mastodon/features/emoji/emoji';
|
import emojify from '../mastodon/features/emoji/emoji';
|
||||||
import loadKeyboardExtensions from '../mastodon/load_keyboard_extensions';
|
import loadKeyboardExtensions from '../mastodon/load_keyboard_extensions';
|
||||||
@@ -20,8 +17,6 @@ import ready from '../mastodon/ready';
|
|||||||
|
|
||||||
import 'cocoon-js-vanilla';
|
import 'cocoon-js-vanilla';
|
||||||
|
|
||||||
start();
|
|
||||||
|
|
||||||
const messages = defineMessages({
|
const messages = defineMessages({
|
||||||
usernameTaken: {
|
usernameTaken: {
|
||||||
id: 'username.taken',
|
id: 'username.taken',
|
||||||
@@ -153,9 +148,7 @@ function loaded() {
|
|||||||
const reactComponents = document.querySelectorAll('[data-component]');
|
const reactComponents = document.querySelectorAll('[data-component]');
|
||||||
|
|
||||||
if (reactComponents.length > 0) {
|
if (reactComponents.length > 0) {
|
||||||
import(
|
import('../mastodon/containers/media_container')
|
||||||
/* webpackChunkName: "containers/media_container" */ '../mastodon/containers/media_container'
|
|
||||||
)
|
|
||||||
.then(({ default: MediaContainer }) => {
|
.then(({ default: MediaContainer }) => {
|
||||||
reactComponents.forEach((component) => {
|
reactComponents.forEach((component) => {
|
||||||
Array.from(component.children).forEach((child) => {
|
Array.from(component.children).forEach((child) => {
|
||||||
|
|||||||
@@ -8,8 +8,6 @@ and performs no other task.
|
|||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import './public-path';
|
|
||||||
|
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
|
|
||||||
interface JRDLink {
|
interface JRDLink {
|
||||||
|
|||||||
@@ -1,13 +1,9 @@
|
|||||||
import './public-path';
|
|
||||||
import { createRoot } from 'react-dom/client';
|
import { createRoot } from 'react-dom/client';
|
||||||
|
|
||||||
import { start } from '../mastodon/common';
|
|
||||||
import ComposeContainer from '../mastodon/containers/compose_container';
|
import ComposeContainer from '../mastodon/containers/compose_container';
|
||||||
import { loadPolyfills } from '../mastodon/polyfills';
|
import { loadPolyfills } from '../mastodon/polyfills';
|
||||||
import ready from '../mastodon/ready';
|
import ready from '../mastodon/ready';
|
||||||
|
|
||||||
start();
|
|
||||||
|
|
||||||
function loaded() {
|
function loaded() {
|
||||||
const mountNode = document.getElementById('mastodon-compose');
|
const mountNode = document.getElementById('mastodon-compose');
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
import './public-path';
|
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
|
|
||||||
import ready from '../mastodon/ready';
|
import ready from '../mastodon/ready';
|
||||||
|
|||||||
@@ -1,8 +1,6 @@
|
|||||||
import Rails from '@rails/ujs';
|
import Rails from '@rails/ujs';
|
||||||
|
|
||||||
export function start() {
|
export function start() {
|
||||||
require.context('@/images/', true, /\.(jpg|png|svg)$/);
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
Rails.start();
|
Rails.start();
|
||||||
} catch {
|
} catch {
|
||||||
@@ -18,8 +18,8 @@ import StarIcon from '@/material-icons/400-24px/star-fill.svg?react';
|
|||||||
import StarBorderIcon from '@/material-icons/400-24px/star.svg?react';
|
import StarBorderIcon from '@/material-icons/400-24px/star.svg?react';
|
||||||
import VisibilityIcon from '@/material-icons/400-24px/visibility.svg?react';
|
import VisibilityIcon from '@/material-icons/400-24px/visibility.svg?react';
|
||||||
import RepeatActiveIcon from '@/svg-icons/repeat_active.svg?react';
|
import RepeatActiveIcon from '@/svg-icons/repeat_active.svg?react';
|
||||||
import RepeatDisabledIcon from '@/svg-icons/repeat_disabled.svg';
|
import RepeatDisabledIcon from '@/svg-icons/repeat_disabled.svg?react';
|
||||||
import RepeatPrivateIcon from '@/svg-icons/repeat_private.svg';
|
import RepeatPrivateIcon from '@/svg-icons/repeat_private.svg?react';
|
||||||
import RepeatPrivateActiveIcon from '@/svg-icons/repeat_private_active.svg?react';
|
import RepeatPrivateActiveIcon from '@/svg-icons/repeat_private_active.svg?react';
|
||||||
import { identityContextPropShape, withIdentity } from 'flavours/glitch/identity_context';
|
import { identityContextPropShape, withIdentity } from 'flavours/glitch/identity_context';
|
||||||
import { PERMISSION_MANAGE_USERS, PERMISSION_MANAGE_FEDERATION } from 'flavours/glitch/permissions';
|
import { PERMISSION_MANAGE_USERS, PERMISSION_MANAGE_FEDERATION } from 'flavours/glitch/permissions';
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
import '@/entrypoints/public-path';
|
|
||||||
import { createRoot } from 'react-dom/client';
|
import { createRoot } from 'react-dom/client';
|
||||||
|
|
||||||
import Rails from '@rails/ujs';
|
import Rails from '@rails/ujs';
|
||||||
@@ -273,7 +272,7 @@ async function mountReactComponent(element: Element) {
|
|||||||
);
|
);
|
||||||
|
|
||||||
const { default: Component } = (await import(
|
const { default: Component } = (await import(
|
||||||
`@/flavours/glitch/components/admin/${componentName}`
|
`@/flavours/glitch/components/admin/${componentName}.jsx`
|
||||||
)) as { default: React.ComponentType };
|
)) as { default: React.ComponentType };
|
||||||
|
|
||||||
const root = createRoot(element);
|
const root = createRoot(element);
|
||||||
|
|||||||
@@ -1,12 +1,7 @@
|
|||||||
import '@/entrypoints/public-path';
|
|
||||||
|
|
||||||
import { start } from 'flavours/glitch/common';
|
|
||||||
import { loadLocale } from 'flavours/glitch/locales';
|
import { loadLocale } from 'flavours/glitch/locales';
|
||||||
import main from 'flavours/glitch/main';
|
import main from 'flavours/glitch/main';
|
||||||
import { loadPolyfills } from 'flavours/glitch/polyfills';
|
import { loadPolyfills } from 'flavours/glitch/polyfills';
|
||||||
|
|
||||||
start();
|
|
||||||
|
|
||||||
loadPolyfills()
|
loadPolyfills()
|
||||||
.then(loadLocale)
|
.then(loadLocale)
|
||||||
.then(main)
|
.then(main)
|
||||||
|
|||||||
@@ -1,7 +0,0 @@
|
|||||||
/* This file is a hack to have something more reliable than the upstream `common` tag
|
|
||||||
that is implicitly generated as the common chunk through webpack's `splitChunks` config */
|
|
||||||
|
|
||||||
import '@/entrypoints/public-path';
|
|
||||||
|
|
||||||
// This is a hack to ensures that webpack compiles our images.
|
|
||||||
require.context('../images', true);
|
|
||||||
3
app/javascript/flavours/glitch/entrypoints/common.ts
Normal file
3
app/javascript/flavours/glitch/entrypoints/common.ts
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
import { start } from 'flavours/glitch/common';
|
||||||
|
|
||||||
|
start();
|
||||||
@@ -1,15 +1,10 @@
|
|||||||
import { createRoot } from 'react-dom/client';
|
import { createRoot } from 'react-dom/client';
|
||||||
|
|
||||||
import '@/entrypoints/public-path';
|
|
||||||
|
|
||||||
import { start } from 'flavours/glitch/common';
|
|
||||||
import { Status } from 'flavours/glitch/features/standalone/status';
|
import { Status } from 'flavours/glitch/features/standalone/status';
|
||||||
import { afterInitialRender } from 'flavours/glitch/hooks/useRenderSignal';
|
import { afterInitialRender } from 'flavours/glitch/hooks/useRenderSignal';
|
||||||
import { loadPolyfills } from 'flavours/glitch/polyfills';
|
import { loadPolyfills } from 'flavours/glitch/polyfills';
|
||||||
import ready from 'flavours/glitch/ready';
|
import ready from 'flavours/glitch/ready';
|
||||||
|
|
||||||
start();
|
|
||||||
|
|
||||||
function loaded() {
|
function loaded() {
|
||||||
const mountNode = document.getElementById('mastodon-status');
|
const mountNode = document.getElementById('mastodon-status');
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
import '@/entrypoints/public-path';
|
|
||||||
import ready from 'flavours/glitch/ready';
|
import ready from 'flavours/glitch/ready';
|
||||||
|
|
||||||
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,7 +1,5 @@
|
|||||||
import { createRoot } from 'react-dom/client';
|
import { createRoot } from 'react-dom/client';
|
||||||
|
|
||||||
import '@/entrypoints/public-path';
|
|
||||||
|
|
||||||
import { IntlMessageFormat } from 'intl-messageformat';
|
import { IntlMessageFormat } from 'intl-messageformat';
|
||||||
import type { MessageDescriptor, PrimitiveType } from 'react-intl';
|
import type { MessageDescriptor, PrimitiveType } from 'react-intl';
|
||||||
import { defineMessages } from 'react-intl';
|
import { defineMessages } from 'react-intl';
|
||||||
@@ -10,7 +8,6 @@ import Rails from '@rails/ujs';
|
|||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
import { throttle } from 'lodash';
|
import { throttle } from 'lodash';
|
||||||
|
|
||||||
import { start } from 'flavours/glitch/common';
|
|
||||||
import { timeAgoString } from 'flavours/glitch/components/relative_timestamp';
|
import { timeAgoString } from 'flavours/glitch/components/relative_timestamp';
|
||||||
import emojify from 'flavours/glitch/features/emoji/emoji';
|
import emojify from 'flavours/glitch/features/emoji/emoji';
|
||||||
import loadKeyboardExtensions from 'flavours/glitch/load_keyboard_extensions';
|
import loadKeyboardExtensions from 'flavours/glitch/load_keyboard_extensions';
|
||||||
@@ -20,8 +17,6 @@ import ready from 'flavours/glitch/ready';
|
|||||||
|
|
||||||
import 'cocoon-js-vanilla';
|
import 'cocoon-js-vanilla';
|
||||||
|
|
||||||
start();
|
|
||||||
|
|
||||||
const messages = defineMessages({
|
const messages = defineMessages({
|
||||||
usernameTaken: {
|
usernameTaken: {
|
||||||
id: 'username.taken',
|
id: 'username.taken',
|
||||||
@@ -153,9 +148,7 @@ function loaded() {
|
|||||||
const reactComponents = document.querySelectorAll('[data-component]');
|
const reactComponents = document.querySelectorAll('[data-component]');
|
||||||
|
|
||||||
if (reactComponents.length > 0) {
|
if (reactComponents.length > 0) {
|
||||||
import(
|
import('flavours/glitch/containers/media_container')
|
||||||
/* webpackChunkName: "containers/media_container" */ 'flavours/glitch/containers/media_container'
|
|
||||||
)
|
|
||||||
.then(({ default: MediaContainer }) => {
|
.then(({ default: MediaContainer }) => {
|
||||||
reactComponents.forEach((component) => {
|
reactComponents.forEach((component) => {
|
||||||
Array.from(component.children).forEach((child) => {
|
Array.from(component.children).forEach((child) => {
|
||||||
|
|||||||
@@ -8,8 +8,6 @@ and performs no other task.
|
|||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import '@/entrypoints/public-path';
|
|
||||||
|
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
|
|
||||||
interface JRDLink {
|
interface JRDLink {
|
||||||
|
|||||||
@@ -1,13 +1,9 @@
|
|||||||
import '@/entrypoints/public-path';
|
|
||||||
import { createRoot } from 'react-dom/client';
|
import { createRoot } from 'react-dom/client';
|
||||||
|
|
||||||
import { start } from 'flavours/glitch/common';
|
|
||||||
import ComposeContainer from 'flavours/glitch/containers/compose_container';
|
import ComposeContainer from 'flavours/glitch/containers/compose_container';
|
||||||
import { loadPolyfills } from 'flavours/glitch/polyfills';
|
import { loadPolyfills } from 'flavours/glitch/polyfills';
|
||||||
import ready from 'flavours/glitch/ready';
|
import ready from 'flavours/glitch/ready';
|
||||||
|
|
||||||
start();
|
|
||||||
|
|
||||||
function loaded() {
|
function loaded() {
|
||||||
const mountNode = document.getElementById('mastodon-compose');
|
const mountNode = document.getElementById('mastodon-compose');
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
import '@/entrypoints/public-path';
|
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
|
|
||||||
import ready from 'flavours/glitch/ready';
|
import ready from 'flavours/glitch/ready';
|
||||||
|
|||||||
@@ -15,10 +15,6 @@ import type { List as ImmutableList, Map as ImmutableMap } from 'immutable';
|
|||||||
import { useSpring, animated } from '@react-spring/web';
|
import { useSpring, animated } from '@react-spring/web';
|
||||||
import Textarea from 'react-textarea-autosize';
|
import Textarea from 'react-textarea-autosize';
|
||||||
import { length } from 'stringz';
|
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 'flavours/glitch/actions/alerts';
|
import { showAlertForError } from 'flavours/glitch/actions/alerts';
|
||||||
import { uploadThumbnail } from 'flavours/glitch/actions/compose';
|
import { uploadThumbnail } from 'flavours/glitch/actions/compose';
|
||||||
@@ -350,9 +346,15 @@ export const AltTextModal = forwardRef<ModalRef, Props & Partial<RestoreProps>>(
|
|||||||
|
|
||||||
fetchTesseract()
|
fetchTesseract()
|
||||||
.then(async ({ createWorker }) => {
|
.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, {
|
const worker = await createWorker('eng', 1, {
|
||||||
workerPath: tesseractWorkerPath as string,
|
workerPath: tesseractWorkerPath.default,
|
||||||
corePath: tesseractCorePath as string,
|
corePath: tesseractCorePath.default,
|
||||||
langPath: `${assetHost}/ocr/lang-data`,
|
langPath: `${assetHost}/ocr/lang-data`,
|
||||||
cacheMethod: 'write',
|
cacheMethod: 'write',
|
||||||
});
|
});
|
||||||
@@ -501,5 +503,4 @@ export const AltTextModal = forwardRef<ModalRef, Props & Partial<RestoreProps>>(
|
|||||||
);
|
);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
AltTextModal.displayName = 'AltTextModal';
|
AltTextModal.displayName = 'AltTextModal';
|
||||||
|
|||||||
@@ -9,28 +9,27 @@
|
|||||||
// to ensure that the prevaled file is regenerated by Babel
|
// to ensure that the prevaled file is regenerated by Babel
|
||||||
// version: 4
|
// version: 4
|
||||||
|
|
||||||
const { NimbleEmojiIndex } = require('emoji-mart');
|
import { NimbleEmojiIndex } from 'emoji-mart';
|
||||||
const { uncompress: emojiMartUncompress } = require('emoji-mart/dist/utils/data');
|
import { uncompress as emojiMartUncompress } from 'emoji-mart/dist/utils/data';
|
||||||
|
|
||||||
|
import data from './emoji_data.json';
|
||||||
let data = require('./emoji_data.json');
|
import emojiMap from './emoji_map.json';
|
||||||
const emojiMap = require('./emoji_map.json');
|
import { unicodeToFilename } from './unicode_to_filename';
|
||||||
const { unicodeToFilename } = require('./unicode_to_filename');
|
import { unicodeToUnifiedName } from './unicode_to_unified_name';
|
||||||
const { unicodeToUnifiedName } = require('./unicode_to_unified_name');
|
|
||||||
|
|
||||||
emojiMartUncompress(data);
|
emojiMartUncompress(data);
|
||||||
|
|
||||||
const emojiMartData = data;
|
const emojiMartData = data;
|
||||||
const emojiIndex = new NimbleEmojiIndex(emojiMartData);
|
const emojiIndex = new NimbleEmojiIndex(emojiMartData);
|
||||||
|
|
||||||
const excluded = ['®', '©', '™'];
|
const excluded = ['®', '©', '™'];
|
||||||
const skinTones = ['🏻', '🏼', '🏽', '🏾', '🏿'];
|
const skinTones = ['🏻', '🏼', '🏽', '🏾', '🏿'];
|
||||||
const shortcodeMap = {};
|
const shortcodeMap = {};
|
||||||
|
|
||||||
const shortCodesToEmojiData = {};
|
const shortCodesToEmojiData = {};
|
||||||
const emojisWithoutShortCodes = [];
|
const emojisWithoutShortCodes = [];
|
||||||
|
|
||||||
Object.keys(emojiIndex.emojis).forEach(key => {
|
Object.keys(emojiIndex.emojis).forEach((key) => {
|
||||||
let emoji = emojiIndex.emojis[key];
|
let emoji = emojiIndex.emojis[key];
|
||||||
|
|
||||||
// Emojis with skin tone modifiers are stored like this
|
// Emojis with skin tone modifiers are stored like this
|
||||||
@@ -41,22 +40,22 @@ Object.keys(emojiIndex.emojis).forEach(key => {
|
|||||||
shortcodeMap[emoji.native] = emoji.id;
|
shortcodeMap[emoji.native] = emoji.id;
|
||||||
});
|
});
|
||||||
|
|
||||||
const stripModifiers = unicode => {
|
const stripModifiers = (unicode) => {
|
||||||
skinTones.forEach(tone => {
|
skinTones.forEach((tone) => {
|
||||||
unicode = unicode.replace(tone, '');
|
unicode = unicode.replace(tone, '');
|
||||||
});
|
});
|
||||||
|
|
||||||
return unicode;
|
return unicode;
|
||||||
};
|
};
|
||||||
|
|
||||||
Object.keys(emojiMap).forEach(key => {
|
Object.keys(emojiMap).forEach((key) => {
|
||||||
if (excluded.includes(key)) {
|
if (excluded.includes(key)) {
|
||||||
delete emojiMap[key];
|
delete emojiMap[key];
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const normalizedKey = stripModifiers(key);
|
const normalizedKey = stripModifiers(key);
|
||||||
let shortcode = shortcodeMap[normalizedKey];
|
let shortcode = shortcodeMap[normalizedKey];
|
||||||
|
|
||||||
if (!shortcode) {
|
if (!shortcode) {
|
||||||
shortcode = shortcodeMap[normalizedKey + '\uFE0F'];
|
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];
|
let emoji = emojiIndex.emojis[key];
|
||||||
|
|
||||||
// Emojis with skin tone modifiers are stored like this
|
// 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];
|
let { short_names, search, unified } = emojiMartData.emojis[key];
|
||||||
|
|
||||||
if (short_names[0] !== key) {
|
if (short_names[0] !== key) {
|
||||||
throw new Error('The compressor expects the first short_code to be the ' +
|
throw new Error(
|
||||||
'key. It may need to be rewritten if the emoji change such that this ' +
|
'The compressor expects the first short_code to be the ' +
|
||||||
'is no longer the case.');
|
'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
|
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
|
// JSON.parse/stringify is to emulate what @preval is doing and avoid any
|
||||||
// inconsistent behavior in dev mode
|
// inconsistent behavior in dev mode
|
||||||
module.exports = JSON.parse(JSON.stringify([
|
export default JSON.parse(
|
||||||
shortCodesToEmojiData,
|
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
|
* The property `skins` is not found in the current context.
|
||||||
* that expect the presence of `skins` property.
|
* This could potentially lead to issues when interacting with modules or data structures
|
||||||
* Currently, no definitions or references to `skins` property can be found in:
|
* that expect the presence of `skins` property.
|
||||||
* - {@link node_modules/emoji-mart/dist/utils/data.js}
|
* Currently, no definitions or references to `skins` property can be found in:
|
||||||
* - {@link node_modules/emoji-mart/data/all.json}
|
* - {@link node_modules/emoji-mart/dist/utils/data.js}
|
||||||
* - {@link app/javascript/mastodon/features/emoji/emoji_compressed.d.ts#Skins}
|
* - {@link node_modules/emoji-mart/data/all.json}
|
||||||
* Future refactorings or updates should consider adding definitions or handling for `skins` property.
|
* - {@link app/javascript/flavours/glitch/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.skins,
|
||||||
emojiMartData.aliases,
|
emojiMartData.categories,
|
||||||
emojisWithoutShortCodes
|
emojiMartData.aliases,
|
||||||
]));
|
emojisWithoutShortCodes,
|
||||||
|
]),
|
||||||
|
);
|
||||||
@@ -3,9 +3,13 @@
|
|||||||
// emojiIndex.search functionality.
|
// emojiIndex.search functionality.
|
||||||
import type { BaseEmoji } from 'emoji-mart';
|
import type { BaseEmoji } from 'emoji-mart';
|
||||||
import type { Emoji } from 'emoji-mart/dist-es/utils/data';
|
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';
|
import { unicodeToUnifiedName } from './unicode_to_unified_name';
|
||||||
|
|
||||||
type Emojis = Record<
|
type Emojis = Record<
|
||||||
|
|||||||
@@ -2,11 +2,13 @@
|
|||||||
// (i.e. the svg filename) and a shortCode intended to be shown
|
// (i.e. the svg filename) and a shortCode intended to be shown
|
||||||
// as a "title" attribute in an HTML element (aka tooltip).
|
// 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 {
|
import type {
|
||||||
FilenameData,
|
FilenameData,
|
||||||
ShortCodesToEmojiDataKey,
|
ShortCodesToEmojiDataKey,
|
||||||
} from './emoji_compressed';
|
} from 'virtual:mastodon-emoji-compressed';
|
||||||
import emojiCompressed from './emoji_compressed';
|
|
||||||
import { unicodeToFilename } from './unicode_to_filename';
|
import { unicodeToFilename } from './unicode_to_filename';
|
||||||
|
|
||||||
type UnicodeMapping = Record<
|
type UnicodeMapping = Record<
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
// taken from:
|
// taken from:
|
||||||
// https://github.com/twitter/twemoji/blob/47732c7/twemoji-generator.js#L848-L866
|
// https://github.com/twitter/twemoji/blob/47732c7/twemoji-generator.js#L848-L866
|
||||||
exports.unicodeToFilename = (str) => {
|
export const unicodeToFilename = (str) => {
|
||||||
let result = '';
|
let result = '';
|
||||||
let charCode = 0;
|
let charCode = 0;
|
||||||
let p = 0;
|
let p = 0;
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ function padLeft(str, num) {
|
|||||||
return str;
|
return str;
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.unicodeToUnifiedName = (str) => {
|
export const unicodeToUnifiedName = (str) => {
|
||||||
let output = '';
|
let output = '';
|
||||||
|
|
||||||
for (let i = 0; i < str.length; i += 2) {
|
for (let i = 0; i < str.length; i += 2) {
|
||||||
|
|||||||
@@ -1,243 +1,243 @@
|
|||||||
export function EmojiPicker () {
|
export function EmojiPicker () {
|
||||||
return import(/* webpackChunkName: "flavours/glitch/async/emoji_picker" */'../../emoji/emoji_picker');
|
return import('../../emoji/emoji_picker');
|
||||||
}
|
}
|
||||||
|
|
||||||
export function Compose () {
|
export function Compose () {
|
||||||
return import(/* webpackChunkName: "flavours/glitch/async/compose" */'../../compose');
|
return import('../../compose');
|
||||||
}
|
}
|
||||||
|
|
||||||
export function Notifications () {
|
export function Notifications () {
|
||||||
return import(/* webpackChunkName: "flavours/glitch/async/notifications" */'../../notifications_v2');
|
return import('../../notifications_v2');
|
||||||
}
|
}
|
||||||
|
|
||||||
export function HomeTimeline () {
|
export function HomeTimeline () {
|
||||||
return import(/* webpackChunkName: "flavours/glitch/async/home_timeline" */'../../home_timeline');
|
return import('../../home_timeline');
|
||||||
}
|
}
|
||||||
|
|
||||||
export function PublicTimeline () {
|
export function PublicTimeline () {
|
||||||
return import(/* webpackChunkName: "flavours/glitch/async/public_timeline" */'../../public_timeline');
|
return import('../../public_timeline');
|
||||||
}
|
}
|
||||||
|
|
||||||
export function CommunityTimeline () {
|
export function CommunityTimeline () {
|
||||||
return import(/* webpackChunkName: "flavours/glitch/async/community_timeline" */'../../community_timeline');
|
return import('../../community_timeline');
|
||||||
}
|
}
|
||||||
|
|
||||||
export function Firehose () {
|
export function Firehose () {
|
||||||
return import(/* webpackChunkName: "flavours/glitch/async/firehose" */'../../firehose');
|
return import('../../firehose');
|
||||||
}
|
}
|
||||||
|
|
||||||
export function HashtagTimeline () {
|
export function HashtagTimeline () {
|
||||||
return import(/* webpackChunkName: "flavours/glitch/async/hashtag_timeline" */'../../hashtag_timeline');
|
return import('../../hashtag_timeline');
|
||||||
}
|
}
|
||||||
|
|
||||||
export function ListTimeline () {
|
export function ListTimeline () {
|
||||||
return import(/* webpackChunkName: "flavours/glitch/async/list_timeline" */'../../list_timeline');
|
return import('../../list_timeline');
|
||||||
}
|
}
|
||||||
|
|
||||||
export function Lists () {
|
export function Lists () {
|
||||||
return import(/* webpackChunkName: "flavours/glitch/async/lists" */'../../lists');
|
return import('../../lists');
|
||||||
}
|
}
|
||||||
|
|
||||||
export function DirectTimeline() {
|
export function DirectTimeline() {
|
||||||
return import(/* webpackChunkName: "flavours/glitch/async/direct_timeline" */'../../direct_timeline');
|
return import('../../direct_timeline');
|
||||||
}
|
}
|
||||||
|
|
||||||
export function Status () {
|
export function Status () {
|
||||||
return import(/* webpackChunkName: "flavours/glitch/async/status" */'../../status');
|
return import('../../status');
|
||||||
}
|
}
|
||||||
|
|
||||||
export function GettingStarted () {
|
export function GettingStarted () {
|
||||||
return import(/* webpackChunkName: "flavours/glitch/async/getting_started" */'../../getting_started');
|
return import('../../getting_started');
|
||||||
}
|
}
|
||||||
|
|
||||||
export function GettingStartedMisc () {
|
export function GettingStartedMisc () {
|
||||||
return import(/* webpackChunkName: "flavours/glitch/async/getting_started_misc" */'../../getting_started_misc');
|
return import('../../getting_started_misc');
|
||||||
}
|
}
|
||||||
|
|
||||||
export function KeyboardShortcuts () {
|
export function KeyboardShortcuts () {
|
||||||
return import(/* webpackChunkName: "flavours/glitch/async/keyboard_shortcuts" */'../../keyboard_shortcuts');
|
return import('../../keyboard_shortcuts');
|
||||||
}
|
}
|
||||||
|
|
||||||
export function PinnedStatuses () {
|
export function PinnedStatuses () {
|
||||||
return import(/* webpackChunkName: "flavours/glitch/async/pinned_statuses" */'../../pinned_statuses');
|
return import('../../pinned_statuses');
|
||||||
}
|
}
|
||||||
|
|
||||||
export function AccountTimeline () {
|
export function AccountTimeline () {
|
||||||
return import(/* webpackChunkName: "flavours/glitch/async/account_timeline" */'../../account_timeline');
|
return import('../../account_timeline');
|
||||||
}
|
}
|
||||||
|
|
||||||
export function AccountGallery () {
|
export function AccountGallery () {
|
||||||
return import(/* webpackChunkName: "flavours/glitch/async/account_gallery" */'../../account_gallery');
|
return import('../../account_gallery');
|
||||||
}
|
}
|
||||||
|
|
||||||
export function AccountFeatured() {
|
export function AccountFeatured() {
|
||||||
return import(/* webpackChunkName: "flavours/glitch/async/account_featured" */'../../account_featured');
|
return import('../../account_featured');
|
||||||
}
|
}
|
||||||
|
|
||||||
export function Followers () {
|
export function Followers () {
|
||||||
return import(/* webpackChunkName: "flavours/glitch/async/followers" */'../../followers');
|
return import('../../followers');
|
||||||
}
|
}
|
||||||
|
|
||||||
export function Following () {
|
export function Following () {
|
||||||
return import(/* webpackChunkName: "flavours/glitch/async/following" */'../../following');
|
return import('../../following');
|
||||||
}
|
}
|
||||||
|
|
||||||
export function Reblogs () {
|
export function Reblogs () {
|
||||||
return import(/* webpackChunkName: "flavours/glitch/async/reblogs" */'../../reblogs');
|
return import('../../reblogs');
|
||||||
}
|
}
|
||||||
|
|
||||||
export function Favourites () {
|
export function Favourites () {
|
||||||
return import(/* webpackChunkName: "flavours/glitch/async/favourites" */'../../favourites');
|
return import('../../favourites');
|
||||||
}
|
}
|
||||||
|
|
||||||
export function FollowRequests () {
|
export function FollowRequests () {
|
||||||
return import(/* webpackChunkName: "flavours/glitch/async/follow_requests" */'../../follow_requests');
|
return import('../../follow_requests');
|
||||||
}
|
}
|
||||||
|
|
||||||
export function FavouritedStatuses () {
|
export function FavouritedStatuses () {
|
||||||
return import(/* webpackChunkName: "flavours/glitch/async/favourited_statuses" */'../../favourited_statuses');
|
return import('../../favourited_statuses');
|
||||||
}
|
}
|
||||||
|
|
||||||
export function FollowedTags () {
|
export function FollowedTags () {
|
||||||
return import(/* webpackChunkName: "flavours/glitch/async/followed_tags" */'../../followed_tags');
|
return import('../../followed_tags');
|
||||||
}
|
}
|
||||||
|
|
||||||
export function BookmarkedStatuses () {
|
export function BookmarkedStatuses () {
|
||||||
return import(/* webpackChunkName: "flavours/glitch/async/bookmarked_statuses" */'../../bookmarked_statuses');
|
return import('../../bookmarked_statuses');
|
||||||
}
|
}
|
||||||
|
|
||||||
export function Blocks () {
|
export function Blocks () {
|
||||||
return import(/* webpackChunkName: "flavours/glitch/async/blocks" */'../../blocks');
|
return import('../../blocks');
|
||||||
}
|
}
|
||||||
|
|
||||||
export function DomainBlocks () {
|
export function DomainBlocks () {
|
||||||
return import(/* webpackChunkName: "flavours/glitch/async/domain_blocks" */'../../domain_blocks');
|
return import('../../domain_blocks');
|
||||||
}
|
}
|
||||||
|
|
||||||
export function Mutes () {
|
export function Mutes () {
|
||||||
return import(/* webpackChunkName: "flavours/glitch/async/mutes" */'../../mutes');
|
return import('../../mutes');
|
||||||
}
|
}
|
||||||
|
|
||||||
export function MuteModal () {
|
export function MuteModal () {
|
||||||
return import(/* webpackChunkName: "flavours/glitch/async/mute_modal" */'../components/mute_modal');
|
return import('../components/mute_modal');
|
||||||
}
|
}
|
||||||
|
|
||||||
export function BlockModal () {
|
export function BlockModal () {
|
||||||
return import(/* webpackChunkName: "flavours/glitch/async/block_modal" */'../components/block_modal');
|
return import('../components/block_modal');
|
||||||
}
|
}
|
||||||
|
|
||||||
export function DomainBlockModal () {
|
export function DomainBlockModal () {
|
||||||
return import(/* webpackChunkName: "flavours/glitch/async/modals/domain_block_modal" */'../components/domain_block_modal');
|
return import('../components/domain_block_modal');
|
||||||
}
|
}
|
||||||
|
|
||||||
export function ReportModal () {
|
export function ReportModal () {
|
||||||
return import(/* webpackChunkName: "flavours/glitch/async/report_modal" */'../components/report_modal');
|
return import('../components/report_modal');
|
||||||
}
|
}
|
||||||
|
|
||||||
export function SettingsModal () {
|
export function SettingsModal () {
|
||||||
return import(/* webpackChunkName: "flavours/glitch/async/settings_modal" */'../../local_settings');
|
return import('../../local_settings');
|
||||||
}
|
}
|
||||||
|
|
||||||
export function IgnoreNotificationsModal () {
|
export function IgnoreNotificationsModal () {
|
||||||
return import(/* webpackChunkName: "flavours/glitch/async/ignore_notifications_modal" */'../components/ignore_notifications_modal');
|
return import('../components/ignore_notifications_modal');
|
||||||
}
|
}
|
||||||
|
|
||||||
export function MediaGallery () {
|
export function MediaGallery () {
|
||||||
return import(/* webpackChunkName: "flavours/glitch/async/media_gallery" */'../../../components/media_gallery');
|
return import('../../../components/media_gallery');
|
||||||
}
|
}
|
||||||
|
|
||||||
export function Video () {
|
export function Video () {
|
||||||
return import(/* webpackChunkName: "flavours/glitch/async/video" */'../../video');
|
return import('../../video');
|
||||||
}
|
}
|
||||||
|
|
||||||
export function EmbedModal () {
|
export function EmbedModal () {
|
||||||
return import(/* webpackChunkName: "flavours/glitch/async/embed_modal" */'../components/embed_modal');
|
return import('../components/embed_modal');
|
||||||
}
|
}
|
||||||
|
|
||||||
export function ListAdder () {
|
export function ListAdder () {
|
||||||
return import(/* webpackChunkName: "features/glitch/async/list_adder" */'../../list_adder');
|
return import('../../list_adder');
|
||||||
}
|
}
|
||||||
|
|
||||||
export function Tesseract () {
|
export function Tesseract () {
|
||||||
return import(/*webpackChunkName: "tesseract" */'tesseract.js');
|
return import('tesseract.js');
|
||||||
}
|
}
|
||||||
|
|
||||||
export function Audio () {
|
export function Audio () {
|
||||||
return import(/* webpackChunkName: "features/glitch/async/audio" */'../../audio');
|
return import('../../audio');
|
||||||
}
|
}
|
||||||
|
|
||||||
export function Directory () {
|
export function Directory () {
|
||||||
return import(/* webpackChunkName: "features/glitch/async/directory" */'../../directory');
|
return import('../../directory');
|
||||||
}
|
}
|
||||||
|
|
||||||
export function OnboardingProfile () {
|
export function OnboardingProfile () {
|
||||||
return import(/* webpackChunkName: "features/glitch/async/onboarding" */'../../onboarding/profile');
|
return import('../../onboarding/profile');
|
||||||
}
|
}
|
||||||
|
|
||||||
export function OnboardingFollows () {
|
export function OnboardingFollows () {
|
||||||
return import(/* webpackChunkName: "features/glitch/async/onboarding" */'../../onboarding/follows');
|
return import('../../onboarding/follows');
|
||||||
}
|
}
|
||||||
|
|
||||||
export function CompareHistoryModal () {
|
export function CompareHistoryModal () {
|
||||||
return import(/*webpackChunkName: "flavours/glitch/async/compare_history_modal" */'../components/compare_history_modal');
|
return import('../components/compare_history_modal');
|
||||||
}
|
}
|
||||||
|
|
||||||
export function Explore () {
|
export function Explore () {
|
||||||
return import(/* webpackChunkName: "flavours/glitch/async/explore" */'../../explore');
|
return import('../../explore');
|
||||||
}
|
}
|
||||||
|
|
||||||
export function Search () {
|
export function Search () {
|
||||||
return import(/* webpackChunkName: "features/glitch/async/explore" */'../../search');
|
return import('../../search');
|
||||||
}
|
}
|
||||||
|
|
||||||
export function FilterModal () {
|
export function FilterModal () {
|
||||||
return import(/*webpackChunkName: "flavours/glitch/async/filter_modal" */'../components/filter_modal');
|
return import('../components/filter_modal');
|
||||||
}
|
}
|
||||||
|
|
||||||
export function InteractionModal () {
|
export function InteractionModal () {
|
||||||
return import(/*webpackChunkName: "flavours/glitch/async/modals/interaction_modal" */'../../interaction_modal');
|
return import('../../interaction_modal');
|
||||||
}
|
}
|
||||||
|
|
||||||
export function SubscribedLanguagesModal () {
|
export function SubscribedLanguagesModal () {
|
||||||
return import(/*webpackChunkName: "flavours/glitch/async/modals/subscribed_languages_modal" */'../../subscribed_languages_modal');
|
return import('../../subscribed_languages_modal');
|
||||||
}
|
}
|
||||||
|
|
||||||
export function ClosedRegistrationsModal () {
|
export function ClosedRegistrationsModal () {
|
||||||
return import(/*webpackChunkName: "flavours/glitch/async/modals/closed_registrations_modal" */'../../closed_registrations_modal');
|
return import('../../closed_registrations_modal');
|
||||||
}
|
}
|
||||||
|
|
||||||
export function About () {
|
export function About () {
|
||||||
return import(/*webpackChunkName: "features/glitch/async/about" */'../../about');
|
return import('../../about');
|
||||||
}
|
}
|
||||||
|
|
||||||
export function PrivacyPolicy () {
|
export function PrivacyPolicy () {
|
||||||
return import(/*webpackChunkName: "features/glitch/async/privacy_policy" */'../../privacy_policy');
|
return import('../../privacy_policy');
|
||||||
}
|
}
|
||||||
|
|
||||||
export function TermsOfService () {
|
export function TermsOfService () {
|
||||||
return import(/*webpackChunkName: "features/glitch/async/terms_of_service" */'../../terms_of_service');
|
return import('../../terms_of_service');
|
||||||
}
|
}
|
||||||
|
|
||||||
export function NotificationRequests () {
|
export function NotificationRequests () {
|
||||||
return import(/*webpackChunkName: "features/glitch/notifications/requests" */'../../notifications/requests');
|
return import('../../notifications/requests');
|
||||||
}
|
}
|
||||||
|
|
||||||
export function NotificationRequest () {
|
export function NotificationRequest () {
|
||||||
return import(/*webpackChunkName: "features/glitch/notifications/request" */'../../notifications/request');
|
return import('../../notifications/request');
|
||||||
}
|
}
|
||||||
|
|
||||||
export function LinkTimeline () {
|
export function LinkTimeline () {
|
||||||
return import(/*webpackChunkName: "features/glitch/link_timeline" */'../../link_timeline');
|
return import('../../link_timeline');
|
||||||
}
|
}
|
||||||
|
|
||||||
export function AnnualReportModal () {
|
export function AnnualReportModal () {
|
||||||
return import(/*webpackChunkName: "flavours/glitch/async/modals/annual_report_modal" */'../components/annual_report_modal');
|
return import('../components/annual_report_modal');
|
||||||
}
|
}
|
||||||
|
|
||||||
export function ListEdit () {
|
export function ListEdit () {
|
||||||
return import(/*webpackChunkName: "flavours/glitch/async/lists" */'../../lists/new');
|
return import('../../lists/new');
|
||||||
}
|
}
|
||||||
|
|
||||||
export function ListMembers () {
|
export function ListMembers () {
|
||||||
return import(/* webpackChunkName: "flavours/glitch/async/lists" */'../../lists/members');
|
return import('../../lists/members');
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
// can at least log in using KaiOS devices).
|
// can at least log in using KaiOS devices).
|
||||||
|
|
||||||
function importArrowKeyNavigation() {
|
function importArrowKeyNavigation() {
|
||||||
return import(/* webpackChunkName: "arrow-key-navigation" */ 'arrow-key-navigation');
|
return import('arrow-key-navigation');
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function loadKeyboardExtensions() {
|
export default function loadKeyboardExtensions() {
|
||||||
|
|||||||
@@ -5,6 +5,13 @@ import { isLocaleLoaded, setLocale } from './global_locale';
|
|||||||
|
|
||||||
const localeLoadingSemaphore = new Semaphore(1);
|
const localeLoadingSemaphore = new Semaphore(1);
|
||||||
|
|
||||||
|
const upstreamLocaleFiles = import.meta.glob<{ default: LocaleData['messages'] }>([
|
||||||
|
'@/mastodon/locales/*.json',
|
||||||
|
]);
|
||||||
|
const localeFiles = import.meta.glob<{ default: LocaleData['messages'] }>([
|
||||||
|
'./*.json',
|
||||||
|
]);
|
||||||
|
|
||||||
export async function loadLocale() {
|
export async function loadLocale() {
|
||||||
// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing -- we want to match empty strings
|
// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing -- we want to match empty strings
|
||||||
const locale = document.querySelector<HTMLElement>('html')?.lang || 'en';
|
const locale = document.querySelector<HTMLElement>('html')?.lang || 'en';
|
||||||
@@ -17,21 +24,23 @@ export async function loadLocale() {
|
|||||||
// if the locale is already set, then do nothing
|
// if the locale is already set, then do nothing
|
||||||
if (isLocaleLoaded()) return;
|
if (isLocaleLoaded()) return;
|
||||||
|
|
||||||
const upstreamLocaleData = await import(
|
// If there is no locale file, then fallback to english
|
||||||
/* webpackMode: "lazy" */
|
const upstreamLocaleFile = Object.hasOwn(upstreamLocaleFiles, `@/mastodon/locales/${locale}.json`)
|
||||||
/* webpackChunkName: "locales/vanilla/[request]" */
|
? upstreamLocaleFiles[`/mastodon/locales/${locale}.json`]
|
||||||
/* webpackInclude: /\.json$/ */
|
: upstreamLocaleFiles['/mastodon/locales/en.json'];
|
||||||
/* webpackPreload: true */
|
|
||||||
`mastodon/locales/${locale}.json`
|
|
||||||
) as LocaleData['messages'];
|
|
||||||
|
|
||||||
const localeData = await import(
|
if (!upstreamLocaleFile) throw new Error('Could not load the upstream locale JSON file');
|
||||||
/* webpackMode: "lazy" */
|
|
||||||
/* webpackChunkName: "locales/glitch/[request]" */
|
const { default: upstreamLocaleData } = await upstreamLocaleFile();
|
||||||
/* webpackInclude: /\.json$/ */
|
|
||||||
/* webpackPreload: true */
|
// If there is no locale file, then fallback to english
|
||||||
`flavours/glitch/locales/${locale}.json`
|
const localeFile = Object.hasOwn(localeFiles, `./${locale}.json`)
|
||||||
) as LocaleData['messages'];
|
? 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: { ...upstreamLocaleData, ...localeData }, locale });
|
setLocale({ messages: { ...upstreamLocaleData, ...localeData }, locale });
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -7,17 +7,19 @@ import * as perf from 'flavours/glitch/performance';
|
|||||||
import ready from 'flavours/glitch/ready';
|
import ready from 'flavours/glitch/ready';
|
||||||
import { store } from 'flavours/glitch/store';
|
import { store } from 'flavours/glitch/store';
|
||||||
|
|
||||||
import { isProduction } from './utils/environment';
|
import { isProduction, isDevelopment } from './utils/environment';
|
||||||
|
|
||||||
/**
|
|
||||||
* @returns {Promise<void>}
|
|
||||||
*/
|
|
||||||
function main() {
|
function main() {
|
||||||
perf.start('main()');
|
perf.start('main()');
|
||||||
|
|
||||||
return ready(async () => {
|
return ready(async () => {
|
||||||
const mountNode = document.getElementById('mastodon');
|
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);
|
const root = createRoot(mountNode);
|
||||||
root.render(<Mastodon {...props} />);
|
root.render(<Mastodon {...props} />);
|
||||||
@@ -25,8 +27,10 @@ function main() {
|
|||||||
|
|
||||||
if (isProduction() && me && 'serviceWorker' in navigator) {
|
if (isProduction() && me && 'serviceWorker' in navigator) {
|
||||||
const { Workbox } = await import('workbox-window');
|
const { Workbox } = await import('workbox-window');
|
||||||
const wb = new Workbox('/sw.js');
|
const wb = new Workbox(
|
||||||
/** @type {ServiceWorkerRegistration} */
|
isDevelopment() ? '/packs-dev/dev-sw.js?dev-sw' : '/sw.js',
|
||||||
|
{ type: 'module', scope: '/' },
|
||||||
|
);
|
||||||
let registration;
|
let registration;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -35,8 +39,14 @@ function main() {
|
|||||||
console.error(err);
|
console.error(err);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (registration && 'Notification' in window && Notification.permission === 'granted') {
|
if (
|
||||||
const registerPushNotifications = await import('flavours/glitch/actions/push_notifications');
|
registration &&
|
||||||
|
'Notification' in window &&
|
||||||
|
Notification.permission === 'granted'
|
||||||
|
) {
|
||||||
|
const registerPushNotifications = await import(
|
||||||
|
'flavours/glitch/actions/push_notifications'
|
||||||
|
);
|
||||||
|
|
||||||
store.dispatch(registerPushNotifications.register());
|
store.dispatch(registerPushNotifications.register());
|
||||||
}
|
}
|
||||||
@@ -46,4 +56,5 @@ function main() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// eslint-disable-next-line import/no-default-export
|
||||||
export default main;
|
export default main;
|
||||||
@@ -1,24 +1,11 @@
|
|||||||
//
|
//
|
||||||
// Tools for performance debugging, only enabled in development mode.
|
// Tools for performance debugging, only enabled in development mode.
|
||||||
// Open up Chrome Dev Tools, then Timeline, then User Timing to see output.
|
// 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 * as marky from 'marky';
|
||||||
|
|
||||||
import { isDevelopment } from './utils/environment';
|
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) {
|
export function start(name) {
|
||||||
if (isDevelopment()) {
|
if (isDevelopment()) {
|
||||||
marky.mark(name);
|
marky.mark(name);
|
||||||
|
|||||||
@@ -2,10 +2,13 @@
|
|||||||
// If there are no polyfills, then this is just Promise.resolve() which means
|
// 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).
|
// 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';
|
import { loadIntlPolyfills } from './intl';
|
||||||
|
|
||||||
function importExtraPolyfills() {
|
function importExtraPolyfills() {
|
||||||
return import(/* webpackChunkName: "extra_polyfills" */ './extra_polyfills');
|
return import('./extra_polyfills');
|
||||||
}
|
}
|
||||||
|
|
||||||
export function loadPolyfills() {
|
export function loadPolyfills() {
|
||||||
|
|||||||
@@ -54,11 +54,9 @@ async function loadIntlPluralRulesPolyfills(locale: string) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// Load the polyfill 1st BEFORE loading data
|
// Load the polyfill 1st BEFORE loading data
|
||||||
|
await import('@formatjs/intl-pluralrules/polyfill-force');
|
||||||
await import(
|
await import(
|
||||||
/* webpackChunkName: "i18n-pluralrules-polyfill" */ '@formatjs/intl-pluralrules/polyfill-force'
|
`../../../../../node_modules/@formatjs/intl-pluralrules/locale-data/${unsupportedLocale}.js`
|
||||||
);
|
|
||||||
await import(
|
|
||||||
/* webpackChunkName: "i18n-pluralrules-polyfill-[request]" */ `@formatjs/intl-pluralrules/locale-data/${unsupportedLocale}`
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -70,11 +68,9 @@ async function loadIntlPluralRulesPolyfills(locale: string) {
|
|||||||
// }
|
// }
|
||||||
// // Load the polyfill 1st BEFORE loading data
|
// // Load the polyfill 1st BEFORE loading data
|
||||||
// await import(
|
// await import(
|
||||||
// /* webpackChunkName: "i18n-relativetimeformat-polyfill" */
|
|
||||||
// '@formatjs/intl-relativetimeformat/polyfill-force'
|
// '@formatjs/intl-relativetimeformat/polyfill-force'
|
||||||
// );
|
// );
|
||||||
// await import(
|
// await import(
|
||||||
// /* webpackChunkName: "i18n-relativetimeformat-polyfill-[request]" */
|
|
||||||
// `@formatjs/intl-relativetimeformat/locale-data/${unsupportedLocale}`
|
// `@formatjs/intl-relativetimeformat/locale-data/${unsupportedLocale}`
|
||||||
// );
|
// );
|
||||||
// }
|
// }
|
||||||
|
|||||||
@@ -1451,8 +1451,8 @@ a.sparkline {
|
|||||||
inset-inline-start: 10px;
|
inset-inline-start: 10px;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
background:
|
background:
|
||||||
url('~images/warning-stripes.svg') repeat-y left,
|
url('@/images/warning-stripes.svg') repeat-y left,
|
||||||
url('~images/warning-stripes.svg') repeat-y right,
|
url('@/images/warning-stripes.svg') repeat-y right,
|
||||||
var(--background-color);
|
var(--background-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,8 +2,8 @@
|
|||||||
@use 'mixins';
|
@use 'mixins';
|
||||||
@use 'variables';
|
@use 'variables';
|
||||||
@use 'css_variables';
|
@use 'css_variables';
|
||||||
@use 'styles/fonts/roboto';
|
@use '@/styles/fonts/roboto';
|
||||||
@use 'styles/fonts/roboto-mono';
|
@use '@/styles/fonts/roboto-mono';
|
||||||
|
|
||||||
@use 'reset';
|
@use 'reset';
|
||||||
@use 'basics';
|
@use 'basics';
|
||||||
|
|||||||
@@ -641,7 +641,7 @@ body > [data-popper-placement] {
|
|||||||
align-items: stretch;
|
align-items: stretch;
|
||||||
|
|
||||||
&__border {
|
&__border {
|
||||||
background: url('~images/warning-stripes.svg') repeat-y;
|
background: url('@/images/warning-stripes.svg') repeat-y;
|
||||||
width: 5px;
|
width: 5px;
|
||||||
flex: 0 0 auto;
|
flex: 0 0 auto;
|
||||||
|
|
||||||
|
|||||||
@@ -394,7 +394,7 @@ code {
|
|||||||
max-width: 100%;
|
max-width: 100%;
|
||||||
height: auto;
|
height: auto;
|
||||||
border-radius: var(--avatar-border-radius);
|
border-radius: var(--avatar-border-radius);
|
||||||
background: url('images/void.png');
|
background: url('@/images/void.png');
|
||||||
|
|
||||||
&[src$='missing.png'] {
|
&[src$='missing.png'] {
|
||||||
visibility: hidden;
|
visibility: hidden;
|
||||||
|
|||||||
@@ -44,7 +44,7 @@
|
|||||||
content: '';
|
content: '';
|
||||||
width: 24px;
|
width: 24px;
|
||||||
height: 20px;
|
height: 20px;
|
||||||
mask-image: url('~images/quote.svg');
|
mask-image: url('@/images/quote.svg');
|
||||||
background-color: var(--rich-text-decorations-color);
|
background-color: var(--rich-text-decorations-color);
|
||||||
position: absolute;
|
position: absolute;
|
||||||
inset-inline-start: 0;
|
inset-inline-start: 0;
|
||||||
|
|||||||
@@ -1,7 +1,11 @@
|
|||||||
export function isDevelopment() {
|
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() {
|
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,8 +1,6 @@
|
|||||||
import Rails from '@rails/ujs';
|
import Rails from '@rails/ujs';
|
||||||
|
|
||||||
export function start() {
|
export function start() {
|
||||||
require.context('../images/', true, /\.(jpg|png|svg)$/);
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
Rails.start();
|
Rails.start();
|
||||||
} catch {
|
} catch {
|
||||||
@@ -9,7 +9,7 @@ import ImmutablePropTypes from 'react-immutable-proptypes';
|
|||||||
import ImmutablePureComponent from 'react-immutable-pure-component';
|
import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||||
import { connect } from 'react-redux';
|
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 BookmarkBorderIcon from '@/material-icons/400-24px/bookmark.svg?react';
|
||||||
import MoreHorizIcon from '@/material-icons/400-24px/more_horiz.svg?react';
|
import MoreHorizIcon from '@/material-icons/400-24px/more_horiz.svg?react';
|
||||||
import RepeatIcon from '@/material-icons/400-24px/repeat.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 { useSpring, animated } from '@react-spring/web';
|
||||||
import Textarea from 'react-textarea-autosize';
|
import Textarea from 'react-textarea-autosize';
|
||||||
import { length } from 'stringz';
|
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 { showAlertForError } from 'mastodon/actions/alerts';
|
||||||
import { uploadThumbnail } from 'mastodon/actions/compose';
|
import { uploadThumbnail } from 'mastodon/actions/compose';
|
||||||
@@ -350,9 +346,15 @@ export const AltTextModal = forwardRef<ModalRef, Props & Partial<RestoreProps>>(
|
|||||||
|
|
||||||
fetchTesseract()
|
fetchTesseract()
|
||||||
.then(async ({ createWorker }) => {
|
.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, {
|
const worker = await createWorker('eng', 1, {
|
||||||
workerPath: tesseractWorkerPath as string,
|
workerPath: tesseractWorkerPath.default,
|
||||||
corePath: tesseractCorePath as string,
|
corePath: tesseractCorePath.default,
|
||||||
langPath: `${assetHost}/ocr/lang-data`,
|
langPath: `${assetHost}/ocr/lang-data`,
|
||||||
cacheMethod: 'write',
|
cacheMethod: 'write',
|
||||||
});
|
});
|
||||||
@@ -501,5 +503,4 @@ export const AltTextModal = forwardRef<ModalRef, Props & Partial<RestoreProps>>(
|
|||||||
);
|
);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
AltTextModal.displayName = 'AltTextModal';
|
AltTextModal.displayName = 'AltTextModal';
|
||||||
|
|||||||
@@ -9,28 +9,27 @@
|
|||||||
// to ensure that the prevaled file is regenerated by Babel
|
// to ensure that the prevaled file is regenerated by Babel
|
||||||
// version: 4
|
// version: 4
|
||||||
|
|
||||||
const { NimbleEmojiIndex } = require('emoji-mart');
|
import { NimbleEmojiIndex } from 'emoji-mart';
|
||||||
const { uncompress: emojiMartUncompress } = require('emoji-mart/dist/utils/data');
|
import { uncompress as emojiMartUncompress } from 'emoji-mart/dist/utils/data';
|
||||||
|
|
||||||
|
import data from './emoji_data.json';
|
||||||
let data = require('./emoji_data.json');
|
import emojiMap from './emoji_map.json';
|
||||||
const emojiMap = require('./emoji_map.json');
|
import { unicodeToFilename } from './unicode_to_filename';
|
||||||
const { unicodeToFilename } = require('./unicode_to_filename');
|
import { unicodeToUnifiedName } from './unicode_to_unified_name';
|
||||||
const { unicodeToUnifiedName } = require('./unicode_to_unified_name');
|
|
||||||
|
|
||||||
emojiMartUncompress(data);
|
emojiMartUncompress(data);
|
||||||
|
|
||||||
const emojiMartData = data;
|
const emojiMartData = data;
|
||||||
const emojiIndex = new NimbleEmojiIndex(emojiMartData);
|
const emojiIndex = new NimbleEmojiIndex(emojiMartData);
|
||||||
|
|
||||||
const excluded = ['®', '©', '™'];
|
const excluded = ['®', '©', '™'];
|
||||||
const skinTones = ['🏻', '🏼', '🏽', '🏾', '🏿'];
|
const skinTones = ['🏻', '🏼', '🏽', '🏾', '🏿'];
|
||||||
const shortcodeMap = {};
|
const shortcodeMap = {};
|
||||||
|
|
||||||
const shortCodesToEmojiData = {};
|
const shortCodesToEmojiData = {};
|
||||||
const emojisWithoutShortCodes = [];
|
const emojisWithoutShortCodes = [];
|
||||||
|
|
||||||
Object.keys(emojiIndex.emojis).forEach(key => {
|
Object.keys(emojiIndex.emojis).forEach((key) => {
|
||||||
let emoji = emojiIndex.emojis[key];
|
let emoji = emojiIndex.emojis[key];
|
||||||
|
|
||||||
// Emojis with skin tone modifiers are stored like this
|
// Emojis with skin tone modifiers are stored like this
|
||||||
@@ -41,22 +40,22 @@ Object.keys(emojiIndex.emojis).forEach(key => {
|
|||||||
shortcodeMap[emoji.native] = emoji.id;
|
shortcodeMap[emoji.native] = emoji.id;
|
||||||
});
|
});
|
||||||
|
|
||||||
const stripModifiers = unicode => {
|
const stripModifiers = (unicode) => {
|
||||||
skinTones.forEach(tone => {
|
skinTones.forEach((tone) => {
|
||||||
unicode = unicode.replace(tone, '');
|
unicode = unicode.replace(tone, '');
|
||||||
});
|
});
|
||||||
|
|
||||||
return unicode;
|
return unicode;
|
||||||
};
|
};
|
||||||
|
|
||||||
Object.keys(emojiMap).forEach(key => {
|
Object.keys(emojiMap).forEach((key) => {
|
||||||
if (excluded.includes(key)) {
|
if (excluded.includes(key)) {
|
||||||
delete emojiMap[key];
|
delete emojiMap[key];
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const normalizedKey = stripModifiers(key);
|
const normalizedKey = stripModifiers(key);
|
||||||
let shortcode = shortcodeMap[normalizedKey];
|
let shortcode = shortcodeMap[normalizedKey];
|
||||||
|
|
||||||
if (!shortcode) {
|
if (!shortcode) {
|
||||||
shortcode = shortcodeMap[normalizedKey + '\uFE0F'];
|
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];
|
let emoji = emojiIndex.emojis[key];
|
||||||
|
|
||||||
// Emojis with skin tone modifiers are stored like this
|
// 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];
|
let { short_names, search, unified } = emojiMartData.emojis[key];
|
||||||
|
|
||||||
if (short_names[0] !== key) {
|
if (short_names[0] !== key) {
|
||||||
throw new Error('The compressor expects the first short_code to be the ' +
|
throw new Error(
|
||||||
'key. It may need to be rewritten if the emoji change such that this ' +
|
'The compressor expects the first short_code to be the ' +
|
||||||
'is no longer the case.');
|
'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
|
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
|
// JSON.parse/stringify is to emulate what @preval is doing and avoid any
|
||||||
// inconsistent behavior in dev mode
|
// inconsistent behavior in dev mode
|
||||||
module.exports = JSON.parse(JSON.stringify([
|
export default JSON.parse(
|
||||||
shortCodesToEmojiData,
|
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
|
* The property `skins` is not found in the current context.
|
||||||
* that expect the presence of `skins` property.
|
* This could potentially lead to issues when interacting with modules or data structures
|
||||||
* Currently, no definitions or references to `skins` property can be found in:
|
* that expect the presence of `skins` property.
|
||||||
* - {@link node_modules/emoji-mart/dist/utils/data.js}
|
* Currently, no definitions or references to `skins` property can be found in:
|
||||||
* - {@link node_modules/emoji-mart/data/all.json}
|
* - {@link node_modules/emoji-mart/dist/utils/data.js}
|
||||||
* - {@link app/javascript/flavours/glitch/features/emoji/emoji_compressed.d.ts#Skins}
|
* - {@link node_modules/emoji-mart/data/all.json}
|
||||||
* Future refactorings or updates should consider adding definitions or handling for `skins` property.
|
* - {@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.skins,
|
||||||
emojiMartData.aliases,
|
emojiMartData.categories,
|
||||||
emojisWithoutShortCodes
|
emojiMartData.aliases,
|
||||||
]));
|
emojisWithoutShortCodes,
|
||||||
|
]),
|
||||||
|
);
|
||||||
@@ -3,9 +3,13 @@
|
|||||||
// emojiIndex.search functionality.
|
// emojiIndex.search functionality.
|
||||||
import type { BaseEmoji } from 'emoji-mart';
|
import type { BaseEmoji } from 'emoji-mart';
|
||||||
import type { Emoji } from 'emoji-mart/dist-es/utils/data';
|
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';
|
import { unicodeToUnifiedName } from './unicode_to_unified_name';
|
||||||
|
|
||||||
type Emojis = Record<
|
type Emojis = Record<
|
||||||
|
|||||||
@@ -2,11 +2,13 @@
|
|||||||
// (i.e. the svg filename) and a shortCode intended to be shown
|
// (i.e. the svg filename) and a shortCode intended to be shown
|
||||||
// as a "title" attribute in an HTML element (aka tooltip).
|
// 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 {
|
import type {
|
||||||
FilenameData,
|
FilenameData,
|
||||||
ShortCodesToEmojiDataKey,
|
ShortCodesToEmojiDataKey,
|
||||||
} from './emoji_compressed';
|
} from 'virtual:mastodon-emoji-compressed';
|
||||||
import emojiCompressed from './emoji_compressed';
|
|
||||||
import { unicodeToFilename } from './unicode_to_filename';
|
import { unicodeToFilename } from './unicode_to_filename';
|
||||||
|
|
||||||
type UnicodeMapping = Record<
|
type UnicodeMapping = Record<
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
// taken from:
|
// taken from:
|
||||||
// https://github.com/twitter/twemoji/blob/47732c7/twemoji-generator.js#L848-L866
|
// https://github.com/twitter/twemoji/blob/47732c7/twemoji-generator.js#L848-L866
|
||||||
exports.unicodeToFilename = (str) => {
|
export const unicodeToFilename = (str) => {
|
||||||
let result = '';
|
let result = '';
|
||||||
let charCode = 0;
|
let charCode = 0;
|
||||||
let p = 0;
|
let p = 0;
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ function padLeft(str, num) {
|
|||||||
return str;
|
return str;
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.unicodeToUnifiedName = (str) => {
|
export const unicodeToUnifiedName = (str) => {
|
||||||
let output = '';
|
let output = '';
|
||||||
|
|
||||||
for (let i = 0; i < str.length; i += 2) {
|
for (let i = 0; i < str.length; i += 2) {
|
||||||
|
|||||||
@@ -1,235 +1,235 @@
|
|||||||
export function EmojiPicker () {
|
export function EmojiPicker () {
|
||||||
return import(/* webpackChunkName: "emoji_picker" */'../../emoji/emoji_picker');
|
return import('../../emoji/emoji_picker');
|
||||||
}
|
}
|
||||||
|
|
||||||
export function Compose () {
|
export function Compose () {
|
||||||
return import(/* webpackChunkName: "features/compose" */'../../compose');
|
return import('../../compose');
|
||||||
}
|
}
|
||||||
|
|
||||||
export function Notifications () {
|
export function Notifications () {
|
||||||
return import(/* webpackChunkName: "features/notifications" */'../../notifications_v2');
|
return import('../../notifications_v2');
|
||||||
}
|
}
|
||||||
|
|
||||||
export function HomeTimeline () {
|
export function HomeTimeline () {
|
||||||
return import(/* webpackChunkName: "features/home_timeline" */'../../home_timeline');
|
return import('../../home_timeline');
|
||||||
}
|
}
|
||||||
|
|
||||||
export function PublicTimeline () {
|
export function PublicTimeline () {
|
||||||
return import(/* webpackChunkName: "features/public_timeline" */'../../public_timeline');
|
return import('../../public_timeline');
|
||||||
}
|
}
|
||||||
|
|
||||||
export function CommunityTimeline () {
|
export function CommunityTimeline () {
|
||||||
return import(/* webpackChunkName: "features/community_timeline" */'../../community_timeline');
|
return import('../../community_timeline');
|
||||||
}
|
}
|
||||||
|
|
||||||
export function Firehose () {
|
export function Firehose () {
|
||||||
return import(/* webpackChunkName: "features/firehose" */'../../firehose');
|
return import('../../firehose');
|
||||||
}
|
}
|
||||||
|
|
||||||
export function HashtagTimeline () {
|
export function HashtagTimeline () {
|
||||||
return import(/* webpackChunkName: "features/hashtag_timeline" */'../../hashtag_timeline');
|
return import('../../hashtag_timeline');
|
||||||
}
|
}
|
||||||
|
|
||||||
export function DirectTimeline() {
|
export function DirectTimeline() {
|
||||||
return import(/* webpackChunkName: "features/direct_timeline" */'../../direct_timeline');
|
return import('../../direct_timeline');
|
||||||
}
|
}
|
||||||
|
|
||||||
export function ListTimeline () {
|
export function ListTimeline () {
|
||||||
return import(/* webpackChunkName: "features/list_timeline" */'../../list_timeline');
|
return import('../../list_timeline');
|
||||||
}
|
}
|
||||||
|
|
||||||
export function Lists () {
|
export function Lists () {
|
||||||
return import(/* webpackChunkName: "features/lists" */'../../lists');
|
return import('../../lists');
|
||||||
}
|
}
|
||||||
|
|
||||||
export function Status () {
|
export function Status () {
|
||||||
return import(/* webpackChunkName: "features/status" */'../../status');
|
return import('../../status');
|
||||||
}
|
}
|
||||||
|
|
||||||
export function GettingStarted () {
|
export function GettingStarted () {
|
||||||
return import(/* webpackChunkName: "features/getting_started" */'../../getting_started');
|
return import('../../getting_started');
|
||||||
}
|
}
|
||||||
|
|
||||||
export function KeyboardShortcuts () {
|
export function KeyboardShortcuts () {
|
||||||
return import(/* webpackChunkName: "features/keyboard_shortcuts" */'../../keyboard_shortcuts');
|
return import('../../keyboard_shortcuts');
|
||||||
}
|
}
|
||||||
|
|
||||||
export function PinnedStatuses () {
|
export function PinnedStatuses () {
|
||||||
return import(/* webpackChunkName: "features/pinned_statuses" */'../../pinned_statuses');
|
return import('../../pinned_statuses');
|
||||||
}
|
}
|
||||||
|
|
||||||
export function AccountTimeline () {
|
export function AccountTimeline () {
|
||||||
return import(/* webpackChunkName: "features/account_timeline" */'../../account_timeline');
|
return import('../../account_timeline');
|
||||||
}
|
}
|
||||||
|
|
||||||
export function AccountGallery () {
|
export function AccountGallery () {
|
||||||
return import(/* webpackChunkName: "features/account_gallery" */'../../account_gallery');
|
return import('../../account_gallery');
|
||||||
}
|
}
|
||||||
|
|
||||||
export function AccountFeatured() {
|
export function AccountFeatured() {
|
||||||
return import(/* webpackChunkName: "features/account_featured" */'../../account_featured');
|
return import('../../account_featured');
|
||||||
}
|
}
|
||||||
|
|
||||||
export function Followers () {
|
export function Followers () {
|
||||||
return import(/* webpackChunkName: "features/followers" */'../../followers');
|
return import('../../followers');
|
||||||
}
|
}
|
||||||
|
|
||||||
export function Following () {
|
export function Following () {
|
||||||
return import(/* webpackChunkName: "features/following" */'../../following');
|
return import('../../following');
|
||||||
}
|
}
|
||||||
|
|
||||||
export function Reblogs () {
|
export function Reblogs () {
|
||||||
return import(/* webpackChunkName: "features/reblogs" */'../../reblogs');
|
return import('../../reblogs');
|
||||||
}
|
}
|
||||||
|
|
||||||
export function Favourites () {
|
export function Favourites () {
|
||||||
return import(/* webpackChunkName: "features/favourites" */'../../favourites');
|
return import('../../favourites');
|
||||||
}
|
}
|
||||||
|
|
||||||
export function FollowRequests () {
|
export function FollowRequests () {
|
||||||
return import(/* webpackChunkName: "features/follow_requests" */'../../follow_requests');
|
return import('../../follow_requests');
|
||||||
}
|
}
|
||||||
|
|
||||||
export function FavouritedStatuses () {
|
export function FavouritedStatuses () {
|
||||||
return import(/* webpackChunkName: "features/favourited_statuses" */'../../favourited_statuses');
|
return import('../../favourited_statuses');
|
||||||
}
|
}
|
||||||
|
|
||||||
export function FollowedTags () {
|
export function FollowedTags () {
|
||||||
return import(/* webpackChunkName: "features/followed_tags" */'../../followed_tags');
|
return import('../../followed_tags');
|
||||||
}
|
}
|
||||||
|
|
||||||
export function BookmarkedStatuses () {
|
export function BookmarkedStatuses () {
|
||||||
return import(/* webpackChunkName: "features/bookmarked_statuses" */'../../bookmarked_statuses');
|
return import('../../bookmarked_statuses');
|
||||||
}
|
}
|
||||||
|
|
||||||
export function Blocks () {
|
export function Blocks () {
|
||||||
return import(/* webpackChunkName: "features/blocks" */'../../blocks');
|
return import('../../blocks');
|
||||||
}
|
}
|
||||||
|
|
||||||
export function DomainBlocks () {
|
export function DomainBlocks () {
|
||||||
return import(/* webpackChunkName: "features/domain_blocks" */'../../domain_blocks');
|
return import('../../domain_blocks');
|
||||||
}
|
}
|
||||||
|
|
||||||
export function Mutes () {
|
export function Mutes () {
|
||||||
return import(/* webpackChunkName: "features/mutes" */'../../mutes');
|
return import('../../mutes');
|
||||||
}
|
}
|
||||||
|
|
||||||
export function MuteModal () {
|
export function MuteModal () {
|
||||||
return import(/* webpackChunkName: "modals/mute_modal" */'../components/mute_modal');
|
return import('../components/mute_modal');
|
||||||
}
|
}
|
||||||
|
|
||||||
export function BlockModal () {
|
export function BlockModal () {
|
||||||
return import(/* webpackChunkName: "modals/block_modal" */'../components/block_modal');
|
return import('../components/block_modal');
|
||||||
}
|
}
|
||||||
|
|
||||||
export function DomainBlockModal () {
|
export function DomainBlockModal () {
|
||||||
return import(/* webpackChunkName: "modals/domain_block_modal" */'../components/domain_block_modal');
|
return import('../components/domain_block_modal');
|
||||||
}
|
}
|
||||||
|
|
||||||
export function ReportModal () {
|
export function ReportModal () {
|
||||||
return import(/* webpackChunkName: "modals/report_modal" */'../components/report_modal');
|
return import('../components/report_modal');
|
||||||
}
|
}
|
||||||
|
|
||||||
export function IgnoreNotificationsModal () {
|
export function IgnoreNotificationsModal () {
|
||||||
return import(/* webpackChunkName: "modals/domain_block_modal" */'../components/ignore_notifications_modal');
|
return import('../components/ignore_notifications_modal');
|
||||||
}
|
}
|
||||||
|
|
||||||
export function MediaGallery () {
|
export function MediaGallery () {
|
||||||
return import(/* webpackChunkName: "status/media_gallery" */'../../../components/media_gallery');
|
return import('../../../components/media_gallery');
|
||||||
}
|
}
|
||||||
|
|
||||||
export function Video () {
|
export function Video () {
|
||||||
return import(/* webpackChunkName: "features/video" */'../../video');
|
return import('../../video');
|
||||||
}
|
}
|
||||||
|
|
||||||
export function EmbedModal () {
|
export function EmbedModal () {
|
||||||
return import(/* webpackChunkName: "modals/embed_modal" */'../components/embed_modal');
|
return import('../components/embed_modal');
|
||||||
}
|
}
|
||||||
|
|
||||||
export function ListAdder () {
|
export function ListAdder () {
|
||||||
return import(/*webpackChunkName: "features/list_adder" */'../../list_adder');
|
return import('../../list_adder');
|
||||||
}
|
}
|
||||||
|
|
||||||
export function Tesseract () {
|
export function Tesseract () {
|
||||||
return import(/*webpackChunkName: "tesseract" */'tesseract.js');
|
return import('tesseract.js');
|
||||||
}
|
}
|
||||||
|
|
||||||
export function Audio () {
|
export function Audio () {
|
||||||
return import(/* webpackChunkName: "features/audio" */'../../audio');
|
return import('../../audio');
|
||||||
}
|
}
|
||||||
|
|
||||||
export function Directory () {
|
export function Directory () {
|
||||||
return import(/* webpackChunkName: "features/directory" */'../../directory');
|
return import('../../directory');
|
||||||
}
|
}
|
||||||
|
|
||||||
export function OnboardingProfile () {
|
export function OnboardingProfile () {
|
||||||
return import(/* webpackChunkName: "features/onboarding" */'../../onboarding/profile');
|
return import('../../onboarding/profile');
|
||||||
}
|
}
|
||||||
|
|
||||||
export function OnboardingFollows () {
|
export function OnboardingFollows () {
|
||||||
return import(/* webpackChunkName: "features/onboarding" */'../../onboarding/follows');
|
return import('../../onboarding/follows');
|
||||||
}
|
}
|
||||||
|
|
||||||
export function CompareHistoryModal () {
|
export function CompareHistoryModal () {
|
||||||
return import(/*webpackChunkName: "modals/compare_history_modal" */'../components/compare_history_modal');
|
return import('../components/compare_history_modal');
|
||||||
}
|
}
|
||||||
|
|
||||||
export function Explore () {
|
export function Explore () {
|
||||||
return import(/* webpackChunkName: "features/explore" */'../../explore');
|
return import('../../explore');
|
||||||
}
|
}
|
||||||
|
|
||||||
export function Search () {
|
export function Search () {
|
||||||
return import(/* webpackChunkName: "features/explore" */'../../search');
|
return import('../../search');
|
||||||
}
|
}
|
||||||
|
|
||||||
export function FilterModal () {
|
export function FilterModal () {
|
||||||
return import(/*webpackChunkName: "modals/filter_modal" */'../components/filter_modal');
|
return import('../components/filter_modal');
|
||||||
}
|
}
|
||||||
|
|
||||||
export function InteractionModal () {
|
export function InteractionModal () {
|
||||||
return import(/*webpackChunkName: "modals/interaction_modal" */'../../interaction_modal');
|
return import('../../interaction_modal');
|
||||||
}
|
}
|
||||||
|
|
||||||
export function SubscribedLanguagesModal () {
|
export function SubscribedLanguagesModal () {
|
||||||
return import(/*webpackChunkName: "modals/subscribed_languages_modal" */'../../subscribed_languages_modal');
|
return import('../../subscribed_languages_modal');
|
||||||
}
|
}
|
||||||
|
|
||||||
export function ClosedRegistrationsModal () {
|
export function ClosedRegistrationsModal () {
|
||||||
return import(/*webpackChunkName: "modals/closed_registrations_modal" */'../../closed_registrations_modal');
|
return import('../../closed_registrations_modal');
|
||||||
}
|
}
|
||||||
|
|
||||||
export function About () {
|
export function About () {
|
||||||
return import(/*webpackChunkName: "features/about" */'../../about');
|
return import('../../about');
|
||||||
}
|
}
|
||||||
|
|
||||||
export function PrivacyPolicy () {
|
export function PrivacyPolicy () {
|
||||||
return import(/*webpackChunkName: "features/privacy_policy" */'../../privacy_policy');
|
return import('../../privacy_policy');
|
||||||
}
|
}
|
||||||
|
|
||||||
export function TermsOfService () {
|
export function TermsOfService () {
|
||||||
return import(/*webpackChunkName: "features/terms_of_service" */'../../terms_of_service');
|
return import('../../terms_of_service');
|
||||||
}
|
}
|
||||||
|
|
||||||
export function NotificationRequests () {
|
export function NotificationRequests () {
|
||||||
return import(/*webpackChunkName: "features/notifications/requests" */'../../notifications/requests');
|
return import('../../notifications/requests');
|
||||||
}
|
}
|
||||||
|
|
||||||
export function NotificationRequest () {
|
export function NotificationRequest () {
|
||||||
return import(/*webpackChunkName: "features/notifications/request" */'../../notifications/request');
|
return import('../../notifications/request');
|
||||||
}
|
}
|
||||||
|
|
||||||
export function LinkTimeline () {
|
export function LinkTimeline () {
|
||||||
return import(/*webpackChunkName: "features/link_timeline" */'../../link_timeline');
|
return import('../../link_timeline');
|
||||||
}
|
}
|
||||||
|
|
||||||
export function AnnualReportModal () {
|
export function AnnualReportModal () {
|
||||||
return import(/*webpackChunkName: "modals/annual_report_modal" */'../components/annual_report_modal');
|
return import('../components/annual_report_modal');
|
||||||
}
|
}
|
||||||
|
|
||||||
export function ListEdit () {
|
export function ListEdit () {
|
||||||
return import(/*webpackChunkName: "features/lists" */'../../lists/new');
|
return import('../../lists/new');
|
||||||
}
|
}
|
||||||
|
|
||||||
export function ListMembers () {
|
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).
|
// can at least log in using KaiOS devices).
|
||||||
|
|
||||||
function importArrowKeyNavigation() {
|
function importArrowKeyNavigation() {
|
||||||
return import(/* webpackChunkName: "arrow-key-navigation" */ 'arrow-key-navigation');
|
return import('arrow-key-navigation');
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function loadKeyboardExtensions() {
|
export default function loadKeyboardExtensions() {
|
||||||
|
|||||||
@@ -5,6 +5,10 @@ import { isLocaleLoaded, setLocale } from './global_locale';
|
|||||||
|
|
||||||
const localeLoadingSemaphore = new Semaphore(1);
|
const localeLoadingSemaphore = new Semaphore(1);
|
||||||
|
|
||||||
|
const localeFiles = import.meta.glob<{ default: LocaleData['messages'] }>([
|
||||||
|
'./*.json',
|
||||||
|
]);
|
||||||
|
|
||||||
export async function loadLocale() {
|
export async function loadLocale() {
|
||||||
// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing -- we want to match empty strings
|
// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing -- we want to match empty strings
|
||||||
const locale = document.querySelector<HTMLElement>('html')?.lang || 'en';
|
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 the locale is already set, then do nothing
|
||||||
if (isLocaleLoaded()) return;
|
if (isLocaleLoaded()) return;
|
||||||
|
|
||||||
const localeData = (await import(
|
// If there is no locale file, then fallback to english
|
||||||
/* webpackMode: "lazy" */
|
const localeFile = Object.hasOwn(localeFiles, `./${locale}.json`)
|
||||||
/* webpackChunkName: "locales/vanilla/[request]" */
|
? localeFiles[`./${locale}.json`]
|
||||||
/* webpackInclude: /\.json$/ */
|
: localeFiles['./en.json'];
|
||||||
/* webpackPreload: true */
|
|
||||||
`mastodon/locales/${locale}.json`
|
if (!localeFile) throw new Error('Could not load the locale JSON file');
|
||||||
)) as LocaleData['messages'];
|
|
||||||
|
const { default: localeData } = await localeFile();
|
||||||
|
|
||||||
setLocale({ messages: localeData, locale });
|
setLocale({ messages: localeData, locale });
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -7,17 +7,19 @@ import * as perf from 'mastodon/performance';
|
|||||||
import ready from 'mastodon/ready';
|
import ready from 'mastodon/ready';
|
||||||
import { store } from 'mastodon/store';
|
import { store } from 'mastodon/store';
|
||||||
|
|
||||||
import { isProduction } from './utils/environment';
|
import { isProduction, isDevelopment } from './utils/environment';
|
||||||
|
|
||||||
/**
|
|
||||||
* @returns {Promise<void>}
|
|
||||||
*/
|
|
||||||
function main() {
|
function main() {
|
||||||
perf.start('main()');
|
perf.start('main()');
|
||||||
|
|
||||||
return ready(async () => {
|
return ready(async () => {
|
||||||
const mountNode = document.getElementById('mastodon');
|
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);
|
const root = createRoot(mountNode);
|
||||||
root.render(<Mastodon {...props} />);
|
root.render(<Mastodon {...props} />);
|
||||||
@@ -25,8 +27,10 @@ function main() {
|
|||||||
|
|
||||||
if (isProduction() && me && 'serviceWorker' in navigator) {
|
if (isProduction() && me && 'serviceWorker' in navigator) {
|
||||||
const { Workbox } = await import('workbox-window');
|
const { Workbox } = await import('workbox-window');
|
||||||
const wb = new Workbox('/sw.js');
|
const wb = new Workbox(
|
||||||
/** @type {ServiceWorkerRegistration} */
|
isDevelopment() ? '/packs-dev/dev-sw.js?dev-sw' : '/sw.js',
|
||||||
|
{ type: 'module', scope: '/' },
|
||||||
|
);
|
||||||
let registration;
|
let registration;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@@ -35,8 +39,14 @@ function main() {
|
|||||||
console.error(err);
|
console.error(err);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (registration && 'Notification' in window && Notification.permission === 'granted') {
|
if (
|
||||||
const registerPushNotifications = await import('mastodon/actions/push_notifications');
|
registration &&
|
||||||
|
'Notification' in window &&
|
||||||
|
Notification.permission === 'granted'
|
||||||
|
) {
|
||||||
|
const registerPushNotifications = await import(
|
||||||
|
'mastodon/actions/push_notifications'
|
||||||
|
);
|
||||||
|
|
||||||
store.dispatch(registerPushNotifications.register());
|
store.dispatch(registerPushNotifications.register());
|
||||||
}
|
}
|
||||||
@@ -46,4 +56,5 @@ function main() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// eslint-disable-next-line import/no-default-export
|
||||||
export default main;
|
export default main;
|
||||||
@@ -1,24 +1,11 @@
|
|||||||
//
|
//
|
||||||
// Tools for performance debugging, only enabled in development mode.
|
// Tools for performance debugging, only enabled in development mode.
|
||||||
// Open up Chrome Dev Tools, then Timeline, then User Timing to see output.
|
// 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 * as marky from 'marky';
|
||||||
|
|
||||||
import { isDevelopment } from './utils/environment';
|
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) {
|
export function start(name) {
|
||||||
if (isDevelopment()) {
|
if (isDevelopment()) {
|
||||||
marky.mark(name);
|
marky.mark(name);
|
||||||
|
|||||||
@@ -2,10 +2,13 @@
|
|||||||
// If there are no polyfills, then this is just Promise.resolve() which means
|
// 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).
|
// 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';
|
import { loadIntlPolyfills } from './intl';
|
||||||
|
|
||||||
function importExtraPolyfills() {
|
function importExtraPolyfills() {
|
||||||
return import(/* webpackChunkName: "extra_polyfills" */ './extra_polyfills');
|
return import('./extra_polyfills');
|
||||||
}
|
}
|
||||||
|
|
||||||
export function loadPolyfills() {
|
export function loadPolyfills() {
|
||||||
|
|||||||
@@ -54,11 +54,9 @@ async function loadIntlPluralRulesPolyfills(locale: string) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// Load the polyfill 1st BEFORE loading data
|
// Load the polyfill 1st BEFORE loading data
|
||||||
|
await import('@formatjs/intl-pluralrules/polyfill-force');
|
||||||
await import(
|
await import(
|
||||||
/* webpackChunkName: "i18n-pluralrules-polyfill" */ '@formatjs/intl-pluralrules/polyfill-force'
|
`../../../../node_modules/@formatjs/intl-pluralrules/locale-data/${unsupportedLocale}.js`
|
||||||
);
|
|
||||||
await import(
|
|
||||||
/* webpackChunkName: "i18n-pluralrules-polyfill-[request]" */ `@formatjs/intl-pluralrules/locale-data/${unsupportedLocale}`
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -70,11 +68,9 @@ async function loadIntlPluralRulesPolyfills(locale: string) {
|
|||||||
// }
|
// }
|
||||||
// // Load the polyfill 1st BEFORE loading data
|
// // Load the polyfill 1st BEFORE loading data
|
||||||
// await import(
|
// await import(
|
||||||
// /* webpackChunkName: "i18n-relativetimeformat-polyfill" */
|
|
||||||
// '@formatjs/intl-relativetimeformat/polyfill-force'
|
// '@formatjs/intl-relativetimeformat/polyfill-force'
|
||||||
// );
|
// );
|
||||||
// await import(
|
// await import(
|
||||||
// /* webpackChunkName: "i18n-relativetimeformat-polyfill-[request]" */
|
|
||||||
// `@formatjs/intl-relativetimeformat/locale-data/${unsupportedLocale}`
|
// `@formatjs/intl-relativetimeformat/locale-data/${unsupportedLocale}`
|
||||||
// );
|
// );
|
||||||
// }
|
// }
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
import { ExpirationPlugin } from 'workbox-expiration';
|
import { ExpirationPlugin } from 'workbox-expiration';
|
||||||
import { precacheAndRoute } from 'workbox-precaching';
|
|
||||||
import { registerRoute } from 'workbox-routing';
|
import { registerRoute } from 'workbox-routing';
|
||||||
import { CacheFirst } from 'workbox-strategies';
|
import { CacheFirst } from 'workbox-strategies';
|
||||||
|
|
||||||
@@ -15,10 +14,9 @@ function fetchRoot() {
|
|||||||
return fetch('/', { credentials: 'include', redirect: 'manual' });
|
return fetch('/', { credentials: 'include', redirect: 'manual' });
|
||||||
}
|
}
|
||||||
|
|
||||||
precacheAndRoute(self.__WB_MANIFEST);
|
|
||||||
|
|
||||||
registerRoute(
|
registerRoute(
|
||||||
/locale_.*\.js$/,
|
/intl\/.*\.js$/,
|
||||||
new CacheFirst({
|
new CacheFirst({
|
||||||
cacheName: `${CACHE_NAME_PREFIX}locales`,
|
cacheName: `${CACHE_NAME_PREFIX}locales`,
|
||||||
plugins: [
|
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 { IntlMessageFormat } from 'intl-messageformat';
|
||||||
|
|
||||||
import { unescape } from 'lodash';
|
import { unescape } from 'lodash';
|
||||||
|
// see config/vite/plugins/sw-locales
|
||||||
import locales from './web_push_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 MAX_NOTIFICATIONS = 5;
|
||||||
const GROUP_TAG = 'tag';
|
const GROUP_TAG = 'tag';
|
||||||
|
|||||||
@@ -1,7 +1,11 @@
|
|||||||
export function isDevelopment() {
|
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() {
|
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
app/javascript/skins/glitch/application.scss
Normal file
1
app/javascript/skins/glitch/application.scss
Normal file
@@ -0,0 +1 @@
|
|||||||
|
@use '@/flavours/glitch/styles/application';
|
||||||
1
app/javascript/skins/glitch/contrast.scss
Normal file
1
app/javascript/skins/glitch/contrast.scss
Normal file
@@ -0,0 +1 @@
|
|||||||
|
@use '@/flavours/glitch/styles/contrast';
|
||||||
@@ -1 +0,0 @@
|
|||||||
@use 'flavours/glitch/styles/contrast';
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
@use 'flavours/glitch/styles/application';
|
|
||||||
1
app/javascript/skins/glitch/mastodon-light.scss
Normal file
1
app/javascript/skins/glitch/mastodon-light.scss
Normal file
@@ -0,0 +1 @@
|
|||||||
|
@use '@/flavours/glitch/styles/mastodon-light';
|
||||||
@@ -1 +0,0 @@
|
|||||||
@use 'flavours/glitch/styles/mastodon-light';
|
|
||||||
1
app/javascript/skins/vanilla/application.scss
Normal file
1
app/javascript/skins/vanilla/application.scss
Normal file
@@ -0,0 +1 @@
|
|||||||
|
@use '@/styles/application';
|
||||||
1
app/javascript/skins/vanilla/contrast.scss
Normal file
1
app/javascript/skins/vanilla/contrast.scss
Normal file
@@ -0,0 +1 @@
|
|||||||
|
@use '@/styles/contrast';
|
||||||
@@ -1 +0,0 @@
|
|||||||
@use 'styles/contrast';
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
@use 'styles/application';
|
|
||||||
1
app/javascript/skins/vanilla/mastodon-light.scss
Normal file
1
app/javascript/skins/vanilla/mastodon-light.scss
Normal file
@@ -0,0 +1 @@
|
|||||||
|
@use '@/styles/mastodon-light';
|
||||||
@@ -1 +0,0 @@
|
|||||||
@use 'styles/mastodon-light';
|
|
||||||
1
app/javascript/skins/vanilla/win95.scss
Normal file
1
app/javascript/skins/vanilla/win95.scss
Normal file
@@ -0,0 +1 @@
|
|||||||
|
@use '@/styles/win95';
|
||||||
@@ -1 +0,0 @@
|
|||||||
@use 'styles/win95';
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
@use 'fonts/inter';
|
@use '../fonts/inter';
|
||||||
|
|
||||||
body {
|
body {
|
||||||
accent-color: #6364ff;
|
accent-color: #6364ff;
|
||||||
@@ -259,7 +259,7 @@ table + p {
|
|||||||
.email-header-td {
|
.email-header-td {
|
||||||
padding: 16px 32px;
|
padding: 16px 32px;
|
||||||
background-color: #1b001f;
|
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-position: left top;
|
||||||
background-repeat: repeat;
|
background-repeat: repeat;
|
||||||
}
|
}
|
||||||
@@ -426,7 +426,7 @@ table + p {
|
|||||||
|
|
||||||
// Body content
|
// Body content
|
||||||
.email-body-td {
|
.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-position: left top;
|
||||||
background-repeat: no-repeat;
|
background-repeat: no-repeat;
|
||||||
}
|
}
|
||||||
@@ -922,7 +922,7 @@ table + p {
|
|||||||
// Extra content on light purple background
|
// Extra content on light purple background
|
||||||
.email-extra-wave {
|
.email-extra-wave {
|
||||||
height: 42px;
|
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-position: bottom center;
|
||||||
background-repeat: no-repeat;
|
background-repeat: no-repeat;
|
||||||
}
|
}
|
||||||
@@ -930,7 +930,7 @@ table + p {
|
|||||||
.email-extra-td {
|
.email-extra-td {
|
||||||
padding: 32px 32px 24px;
|
padding: 32px 32px 24px;
|
||||||
background-color: #f0f0ff;
|
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 {
|
.email-column-td {
|
||||||
padding-top: 8px;
|
padding-top: 8px;
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
@font-face {
|
@font-face {
|
||||||
font-family: Inter;
|
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');
|
format('woff2-variations');
|
||||||
font-weight: 100 900;
|
font-weight: 100 900;
|
||||||
font-style: normal;
|
font-style: normal;
|
||||||
|
|||||||
@@ -2,10 +2,10 @@
|
|||||||
font-family: mastodon-font-monospace;
|
font-family: mastodon-font-monospace;
|
||||||
src:
|
src:
|
||||||
local('Roboto Mono'),
|
local('Roboto Mono'),
|
||||||
url('~fonts/roboto-mono/robotomono-regular-webfont.woff2') format('woff2'),
|
url('@/fonts/roboto-mono/robotomono-regular-webfont.woff2') format('woff2'),
|
||||||
url('~fonts/roboto-mono/robotomono-regular-webfont.woff') format('woff'),
|
url('@/fonts/roboto-mono/robotomono-regular-webfont.woff') format('woff'),
|
||||||
url('~fonts/roboto-mono/robotomono-regular-webfont.ttf') format('truetype'),
|
url('@/fonts/roboto-mono/robotomono-regular-webfont.ttf') format('truetype'),
|
||||||
url('~fonts/roboto-mono/robotomono-regular-webfont.svg#roboto_monoregular')
|
url('@/fonts/roboto-mono/robotomono-regular-webfont.svg#roboto_monoregular')
|
||||||
format('svg');
|
format('svg');
|
||||||
font-weight: 400;
|
font-weight: 400;
|
||||||
font-display: swap;
|
font-display: swap;
|
||||||
|
|||||||
@@ -2,10 +2,10 @@
|
|||||||
font-family: mastodon-font-sans-serif;
|
font-family: mastodon-font-sans-serif;
|
||||||
src:
|
src:
|
||||||
local('Roboto Italic'),
|
local('Roboto Italic'),
|
||||||
url('~fonts/roboto/roboto-italic-webfont.woff2') format('woff2'),
|
url('@/fonts/roboto/roboto-italic-webfont.woff2') format('woff2'),
|
||||||
url('~fonts/roboto/roboto-italic-webfont.woff') format('woff'),
|
url('@/fonts/roboto/roboto-italic-webfont.woff') format('woff'),
|
||||||
url('~fonts/roboto/roboto-italic-webfont.ttf') format('truetype'),
|
url('@/fonts/roboto/roboto-italic-webfont.ttf') format('truetype'),
|
||||||
url('~fonts/roboto/roboto-italic-webfont.svg#roboto-italic-webfont')
|
url('@/fonts/roboto/roboto-italic-webfont.svg#roboto-italic-webfont')
|
||||||
format('svg');
|
format('svg');
|
||||||
font-weight: normal;
|
font-weight: normal;
|
||||||
font-display: swap;
|
font-display: swap;
|
||||||
@@ -16,10 +16,10 @@
|
|||||||
font-family: mastodon-font-sans-serif;
|
font-family: mastodon-font-sans-serif;
|
||||||
src:
|
src:
|
||||||
local('Roboto Bold'),
|
local('Roboto Bold'),
|
||||||
url('~fonts/roboto/roboto-bold-webfont.woff2') format('woff2'),
|
url('@/fonts/roboto/roboto-bold-webfont.woff2') format('woff2'),
|
||||||
url('~fonts/roboto/roboto-bold-webfont.woff') format('woff'),
|
url('@/fonts/roboto/roboto-bold-webfont.woff') format('woff'),
|
||||||
url('~fonts/roboto/roboto-bold-webfont.ttf') format('truetype'),
|
url('@/fonts/roboto/roboto-bold-webfont.ttf') format('truetype'),
|
||||||
url('~fonts/roboto/roboto-bold-webfont.svg#roboto-bold-webfont')
|
url('@/fonts/roboto/roboto-bold-webfont.svg#roboto-bold-webfont')
|
||||||
format('svg');
|
format('svg');
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
font-display: swap;
|
font-display: swap;
|
||||||
@@ -30,10 +30,10 @@
|
|||||||
font-family: mastodon-font-sans-serif;
|
font-family: mastodon-font-sans-serif;
|
||||||
src:
|
src:
|
||||||
local('Roboto Medium'),
|
local('Roboto Medium'),
|
||||||
url('~fonts/roboto/roboto-medium-webfont.woff2') format('woff2'),
|
url('@/fonts/roboto/roboto-medium-webfont.woff2') format('woff2'),
|
||||||
url('~fonts/roboto/roboto-medium-webfont.woff') format('woff'),
|
url('@/fonts/roboto/roboto-medium-webfont.woff') format('woff'),
|
||||||
url('~fonts/roboto/roboto-medium-webfont.ttf') format('truetype'),
|
url('@/fonts/roboto/roboto-medium-webfont.ttf') format('truetype'),
|
||||||
url('~fonts/roboto/roboto-medium-webfont.svg#roboto-medium-webfont')
|
url('@/fonts/roboto/roboto-medium-webfont.svg#roboto-medium-webfont')
|
||||||
format('svg');
|
format('svg');
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
font-display: swap;
|
font-display: swap;
|
||||||
@@ -44,10 +44,10 @@
|
|||||||
font-family: mastodon-font-sans-serif;
|
font-family: mastodon-font-sans-serif;
|
||||||
src:
|
src:
|
||||||
local('Roboto'),
|
local('Roboto'),
|
||||||
url('~fonts/roboto/roboto-regular-webfont.woff2') format('woff2'),
|
url('@/fonts/roboto/roboto-regular-webfont.woff2') format('woff2'),
|
||||||
url('~fonts/roboto/roboto-regular-webfont.woff') format('woff'),
|
url('@/fonts/roboto/roboto-regular-webfont.woff') format('woff'),
|
||||||
url('~fonts/roboto/roboto-regular-webfont.ttf') format('truetype'),
|
url('@/fonts/roboto/roboto-regular-webfont.ttf') format('truetype'),
|
||||||
url('~fonts/roboto/roboto-regular-webfont.svg#roboto-regular-webfont')
|
url('@/fonts/roboto/roboto-regular-webfont.svg#roboto-regular-webfont')
|
||||||
format('svg');
|
format('svg');
|
||||||
font-weight: normal;
|
font-weight: normal;
|
||||||
font-display: swap;
|
font-display: swap;
|
||||||
|
|||||||
@@ -1446,8 +1446,8 @@ a.sparkline {
|
|||||||
inset-inline-start: 10px;
|
inset-inline-start: 10px;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
background:
|
background:
|
||||||
url('~images/warning-stripes.svg') repeat-y left,
|
url('@/images/warning-stripes.svg') repeat-y left,
|
||||||
url('~images/warning-stripes.svg') repeat-y right,
|
url('@/images/warning-stripes.svg') repeat-y right,
|
||||||
var(--background-color);
|
var(--background-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -641,7 +641,7 @@ body > [data-popper-placement] {
|
|||||||
align-items: stretch;
|
align-items: stretch;
|
||||||
|
|
||||||
&__border {
|
&__border {
|
||||||
background: url('~images/warning-stripes.svg') repeat-y;
|
background: url('@/images/warning-stripes.svg') repeat-y;
|
||||||
width: 5px;
|
width: 5px;
|
||||||
flex: 0 0 auto;
|
flex: 0 0 auto;
|
||||||
|
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user