~cytrogen/masto-fe

95a1fde6b68a2dabdb19aa34be4e9e73422a7760 — Claire 2 years ago 2d09653 + 73b64b8
Merge commit '73b64b89170cb72854a1709186c62ce31f476889' into glitch-soc/merge-upstream

Conflicts:
- `app/javascript/styles/fonts/roboto-mono.scss`:
  Upstream updated the linter, which changed a few linter rules.
  Some of those changed lines are different in glitch-soc because we use
  different paths for the assets.
  Applied the same style rules on our version of the file.
- `app/javascript/styles/fonts/roboto.scss`:
  Upstream updated the linter, which changed a few linter rules.
  Some of those changed lines are different in glitch-soc because we use
  different paths for the assets.
  Applied the same style rules on our version of the file.
M app/javascript/mastodon/components/animated_number.tsx => app/javascript/mastodon/components/animated_number.tsx +1 -1
@@ 32,7 32,7 @@ export const AnimatedNumber: React.FC<Props> = ({ value, obfuscate }) => {
  const willEnter = useCallback(() => ({ y: -1 * direction }), [direction]);
  const willLeave = useCallback(
    () => ({ y: spring(1 * direction, { damping: 35, stiffness: 400 }) }),
    [direction]
    [direction],
  );

  if (reduceMotion) {

M app/javascript/mastodon/components/counters.tsx => app/javascript/mastodon/components/counters.tsx +3 -3
@@ 4,7 4,7 @@ import { FormattedMessage } from 'react-intl';

export const StatusesCounter = (
  displayNumber: React.ReactNode,
  pluralReady: number
  pluralReady: number,
) => (
  <FormattedMessage
    id='account.statuses_counter'


@@ 18,7 18,7 @@ export const StatusesCounter = (

export const FollowingCounter = (
  displayNumber: React.ReactNode,
  pluralReady: number
  pluralReady: number,
) => (
  <FormattedMessage
    id='account.following_counter'


@@ 32,7 32,7 @@ export const FollowingCounter = (

export const FollowersCounter = (
  displayNumber: React.ReactNode,
  pluralReady: number
  pluralReady: number,
) => (
  <FormattedMessage
    id='account.followers_counter'

M app/javascript/mastodon/components/gifv.tsx => app/javascript/mastodon/components/gifv.tsx +1 -1
@@ 32,7 32,7 @@ export const GIFV: React.FC<Props> = ({
        onClick();
      }
    },
    [onClick]
    [onClick],
  );

  return (

M app/javascript/mastodon/components/relative_timestamp.tsx => app/javascript/mastodon/components/relative_timestamp.tsx +7 -7
@@ 108,7 108,7 @@ export const timeAgoString = (
  now: number,
  year: number,
  timeGiven: boolean,
  short?: boolean
  short?: boolean,
) => {
  const delta = now - date.getTime();



@@ 118,28 118,28 @@ export const timeAgoString = (
    relativeTime = intl.formatMessage(messages.today);
  } else if (delta < 10 * SECOND) {
    relativeTime = intl.formatMessage(
      short ? messages.just_now : messages.just_now_full
      short ? messages.just_now : messages.just_now_full,
    );
  } else if (delta < 7 * DAY) {
    if (delta < MINUTE) {
      relativeTime = intl.formatMessage(
        short ? messages.seconds : messages.seconds_full,
        { number: Math.floor(delta / SECOND) }
        { number: Math.floor(delta / SECOND) },
      );
    } else if (delta < HOUR) {
      relativeTime = intl.formatMessage(
        short ? messages.minutes : messages.minutes_full,
        { number: Math.floor(delta / MINUTE) }
        { number: Math.floor(delta / MINUTE) },
      );
    } else if (delta < DAY) {
      relativeTime = intl.formatMessage(
        short ? messages.hours : messages.hours_full,
        { number: Math.floor(delta / HOUR) }
        { number: Math.floor(delta / HOUR) },
      );
    } else {
      relativeTime = intl.formatMessage(
        short ? messages.days : messages.days_full,
        { number: Math.floor(delta / DAY) }
        { number: Math.floor(delta / DAY) },
      );
    }
  } else if (date.getFullYear() === year) {


@@ 158,7 158,7 @@ const timeRemainingString = (
  intl: IntlShape,
  date: Date,
  now: number,
  timeGiven = true
  timeGiven = true,
) => {
  const delta = date.getTime() - now;


M app/javascript/mastodon/components/short_number.tsx => app/javascript/mastodon/components/short_number.tsx +2 -2
@@ 6,7 6,7 @@ import { toShortNumber, pluralReady, DECIMAL_UNITS } from '../utils/numbers';

type ShortNumberRenderer = (
  displayNumber: JSX.Element,
  pluralReady: number
  pluralReady: number,
) => JSX.Element;

interface ShortNumberProps {


@@ 25,7 25,7 @@ export const ShortNumberRenderer: React.FC<ShortNumberProps> = ({

  if (children && renderer) {
    console.warn(
      'Both renderer prop and renderer as a child provided. This is a mistake and you really should fix that. Only renderer passed as a child will be used.'
      'Both renderer prop and renderer as a child provided. This is a mistake and you really should fix that. Only renderer passed as a child will be used.',
    );
  }


M app/javascript/mastodon/features/emoji/emoji_compressed.d.ts => app/javascript/mastodon/features/emoji/emoji_compressed.d.ts +2 -2
@@ 25,7 25,7 @@ export type SearchData = [
  BaseEmoji['native'],
  Emoji['short_names'],
  Search,
  Emoji['unified']
  Emoji['unified'],
];

export interface ShortCodesToEmojiData {


@@ 38,7 38,7 @@ export type EmojiCompressed = [
  Skins,
  Category[],
  Data['aliases'],
  EmojisWithoutShortCodes
  EmojisWithoutShortCodes,
];

/*

M app/javascript/mastodon/polyfills/base_polyfills.ts => app/javascript/mastodon/polyfills/base_polyfills.ts +1 -1
@@ 12,7 12,7 @@ if (!HTMLCanvasElement.prototype.toBlob) {
      this: HTMLCanvasElement,
      callback: BlobCallback,
      type = 'image/png',
      quality: unknown
      quality: unknown,
    ) {
      const dataURL: string = this.toDataURL(type, quality);
      let data;

M app/javascript/mastodon/reducers/index.ts => app/javascript/mastodon/reducers/index.ts +1 -1
@@ 99,7 99,7 @@ const initialRootState = Object.fromEntries(
    reducer(undefined, {
      // empty action
    }),
  ])
  ]),
);

const RootStateRecord = ImmutableRecord(initialRootState, 'RootState');

M app/javascript/mastodon/reducers/modal.ts => app/javascript/mastodon/reducers/modal.ts +7 -7
@@ 35,7 35,7 @@ interface PopModalOption {
}
const popModal = (
  state: State,
  { modalType, ignoreFocus }: PopModalOption
  { modalType, ignoreFocus }: PopModalOption,
): State => {
  if (
    modalType === undefined ||


@@ 52,12 52,12 @@ const popModal = (
const pushModal = (
  state: State,
  modalType: ModalType,
  modalProps: ModalProps
  modalProps: ModalProps,
): State => {
  return state.withMutations((record) => {
    record.set('ignoreFocus', false);
    record.update('stack', (stack) =>
      stack.unshift(Modal({ modalType, modalProps }))
      stack.unshift(Modal({ modalType, modalProps })),
    );
  });
};


@@ 68,14 68,14 @@ export function modalReducer(
    modalType: ModalType;
    ignoreFocus: boolean;
    modalProps: Record<string, unknown>;
  }>
  }>,
) {
  switch (action.type) {
    case openModal.type:
      return pushModal(
        state,
        action.payload.modalType,
        action.payload.modalProps
        action.payload.modalProps,
      );
    case closeModal.type:
      return popModal(state, action.payload);


@@ 85,8 85,8 @@ export function modalReducer(
      return state.update('stack', (stack) =>
        stack.filterNot(
          // @ts-expect-error TIMELINE_DELETE action is not typed yet.
          (modal) => modal.get('modalProps').statusId === action.id
        )
          (modal) => modal.get('modalProps').statusId === action.id,
        ),
      );
    default:
      return state;

M app/javascript/mastodon/scroll.ts => app/javascript/mastodon/scroll.ts +2 -2
@@ 3,12 3,12 @@ const easingOutQuint = (
  t: number,
  b: number,
  c: number,
  d: number
  d: number,
) => c * ((t = t / d - 1) * t * t * t * t + 1) + b;
const scroll = (
  node: Element,
  key: 'scrollTop' | 'scrollLeft',
  target: number
  target: number,
) => {
  const startTime = Date.now();
  const offset = node[key];

M app/javascript/mastodon/store/index.ts => app/javascript/mastodon/store/index.ts +1 -1
@@ 30,7 30,7 @@ export const store = configureStore({
      .concat(
        loadingBarMiddleware({
          promiseTypeSuffixes: ['REQUEST', 'SUCCESS', 'FAIL'],
        })
        }),
      )
      .concat(errorsMiddleware)
      .concat(soundsMiddleware()),

M app/javascript/mastodon/store/middlewares/loading_bar.ts => app/javascript/mastodon/store/middlewares/loading_bar.ts +1 -1
@@ 14,7 14,7 @@ const defaultTypeSuffixes: Config['promiseTypeSuffixes'] = [
];

export const loadingBarMiddleware = (
  config: Config = {}
  config: Config = {},
): Middleware<Record<string, never>, RootState> => {
  const promiseTypeSuffixes = config.promiseTypeSuffixes || defaultTypeSuffixes;


M app/javascript/mastodon/utils/hashtags.ts => app/javascript/mastodon/utils/hashtags.ts +2 -2
@@ 6,7 6,7 @@ const buildHashtagPatternRegex = () => {
  try {
    return new RegExp(
      `(?:^|[^\\/\\)\\w])#(([${WORD}_][${WORD}${HASHTAG_SEPARATORS}]*[${ALPHA}${HASHTAG_SEPARATORS}][${WORD}${HASHTAG_SEPARATORS}]*[${WORD}_])|([${WORD}_]*[${ALPHA}][${WORD}_]*))`,
      'iu'
      'iu',
    );
  } catch {
    return /(?:^|[^/)\w])#(\w*[a-zA-Z·]\w*)/i;


@@ 17,7 17,7 @@ const buildHashtagRegex = () => {
  try {
    return new RegExp(
      `^(([${WORD}_][${WORD}${HASHTAG_SEPARATORS}]*[${ALPHA}${HASHTAG_SEPARATORS}][${WORD}${HASHTAG_SEPARATORS}]*[${WORD}_])|([${WORD}_]*[${ALPHA}][${WORD}_]*))$`,
      'iu'
      'iu',
    );
  } catch {
    return /^(\w*[a-zA-Z·]\w*)$/i;

M app/javascript/mastodon/utils/numbers.ts => app/javascript/mastodon/utils/numbers.ts +1 -1
@@ 55,7 55,7 @@ export function toShortNumber(sourceNumber: number): ShortNumber {
 */
export function pluralReady(
  sourceNumber: number,
  division: DecimalUnits
  division: DecimalUnits,
): number {
  if (division == null || division < DECIMAL_UNITS.HUNDRED) {
    return sourceNumber;

M app/javascript/styles/fonts/roboto-mono.scss => app/javascript/styles/fonts/roboto-mono.scss +2 -1
@@ 1,6 1,7 @@
@font-face {
  font-family: mastodon-font-monospace;
  src: local('Roboto Mono'),
  src:
    local('Roboto Mono'),
    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.ttf') format('truetype'),

M app/javascript/styles/fonts/roboto.scss => app/javascript/styles/fonts/roboto.scss +8 -4
@@ 1,6 1,7 @@
@font-face {
  font-family: mastodon-font-sans-serif;
  src: local('Roboto Italic'),
  src:
    local('Roboto Italic'),
    url('~fonts/roboto/roboto-italic-webfont.woff2') format('woff2'),
    url('~fonts/roboto/roboto-italic-webfont.woff') format('woff'),
    url('~fonts/roboto/roboto-italic-webfont.ttf') format('truetype'),


@@ 13,7 14,8 @@

@font-face {
  font-family: mastodon-font-sans-serif;
  src: local('Roboto Bold'),
  src:
    local('Roboto Bold'),
    url('~fonts/roboto/roboto-bold-webfont.woff2') format('woff2'),
    url('~fonts/roboto/roboto-bold-webfont.woff') format('woff'),
    url('~fonts/roboto/roboto-bold-webfont.ttf') format('truetype'),


@@ 26,7 28,8 @@

@font-face {
  font-family: mastodon-font-sans-serif;
  src: local('Roboto Medium'),
  src:
    local('Roboto Medium'),
    url('~fonts/roboto/roboto-medium-webfont.woff2') format('woff2'),
    url('~fonts/roboto/roboto-medium-webfont.woff') format('woff'),
    url('~fonts/roboto/roboto-medium-webfont.ttf') format('truetype'),


@@ 39,7 42,8 @@

@font-face {
  font-family: mastodon-font-sans-serif;
  src: local('Roboto'),
  src:
    local('Roboto'),
    url('~fonts/roboto/roboto-regular-webfont.woff2') format('woff2'),
    url('~fonts/roboto/roboto-regular-webfont.woff') format('woff'),
    url('~fonts/roboto/roboto-regular-webfont.ttf') format('truetype'),

M app/javascript/styles/mastodon/basics.scss => app/javascript/styles/mastodon/basics.scss +13 -3
@@ 31,9 31,19 @@ body {
    // Droid Sans => Older Androids (<4.0)
    // Helvetica Neue => Older macOS <10.11
    // $font-sans-serif => web-font (Roboto) fallback and newer Androids (>=4.0)
    font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI',
      Oxygen, Ubuntu, Cantarell, 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
      $font-sans-serif, sans-serif;
    font-family:
      system-ui,
      -apple-system,
      BlinkMacSystemFont,
      'Segoe UI',
      Oxygen,
      Ubuntu,
      Cantarell,
      'Fira Sans',
      'Droid Sans',
      'Helvetica Neue',
      $font-sans-serif,
      sans-serif;
  }

  &.app-body {

M app/javascript/styles/mastodon/components.scss => app/javascript/styles/mastodon/components.scss +15 -6
@@ 747,7 747,9 @@ body > [data-popper-placement] {
}

.no-reduce-motion .spoiler-input {
  transition: height 0.4s ease, opacity 0.4s ease;
  transition:
    height 0.4s ease,
    opacity 0.4s ease;
}

.sign-in-banner {


@@ 3954,7 3956,9 @@ a.status-card.compact:hover {
  overflow-y: auto;
  border-bottom: 1px solid lighten($ui-base-color, 8%);
  color: $darker-text-color;
  transition: max-height 150ms ease-in-out, opacity 300ms linear;
  transition:
    max-height 150ms ease-in-out,
    opacity 300ms linear;
  opacity: 1;
  z-index: 1;
  position: relative;


@@ 6935,7 6939,8 @@ noscript {
  .navigation-bar {
    & > a:first-child {
      will-change: margin-top, margin-inline-start, margin-inline-end, width;
      transition: margin-top $duration $delay,
      transition:
        margin-top $duration $delay,
        margin-inline-start $duration ($duration + $delay),
        margin-inline-end $duration ($duration + $delay);
    }


@@ 6948,12 6953,15 @@ noscript {
    .navigation-bar__actions {
      & > .icon-button.close {
        will-change: opacity transform;
        transition: opacity $duration * 0.5 $delay, transform $duration $delay;
        transition:
          opacity $duration * 0.5 $delay,
          transform $duration $delay;
      }

      & > .compose__action-bar .icon-button {
        will-change: opacity transform;
        transition: opacity $duration * 0.5 $delay + $duration * 0.5,
        transition:
          opacity $duration * 0.5 $delay + $duration * 0.5,
          transform $duration $delay;
      }
    }


@@ 9094,7 9102,8 @@ noscript {
  backdrop-filter: blur(8px);
  border: 1px solid rgba(lighten($classic-base-color, 4%), 0.85);
  border-radius: 8px;
  box-shadow: 0 10px 15px -3px rgba($base-shadow-color, 0.25),
  box-shadow:
    0 10px 15px -3px rgba($base-shadow-color, 0.25),
    0 4px 6px -4px rgba($base-shadow-color, 0.25);
  cursor: default;
  transition: 0.5s cubic-bezier(0.89, 0.01, 0.5, 1.1);

M package.json => package.json +2 -2
@@ 194,7 194,7 @@
    "eslint-plugin-import": "~2.27.5",
    "eslint-plugin-jsdoc": "^46.1.0",
    "eslint-plugin-jsx-a11y": "~6.7.1",
    "eslint-plugin-prettier": "^4.2.1",
    "eslint-plugin-prettier": "^5.0.0",
    "eslint-plugin-promise": "~6.1.1",
    "eslint-plugin-react": "~7.32.2",
    "eslint-plugin-react-hooks": "^4.6.0",


@@ 202,7 202,7 @@
    "jest": "^29.5.0",
    "jest-environment-jsdom": "^29.5.0",
    "lint-staged": "^13.2.2",
    "prettier": "^2.8.8",
    "prettier": "^3.0.0",
    "react-test-renderer": "^18.2.0",
    "stylelint": "^15.10.1",
    "stylelint-config-standard-scss": "^10.0.0",

M yarn.lock => yarn.lock +10 -8
@@ 5145,12 5145,13 @@ eslint-plugin-jsx-a11y@~6.7.1:
    object.fromentries "^2.0.6"
    semver "^6.3.0"

eslint-plugin-prettier@^4.2.1:
  version "4.2.1"
  resolved "https://registry.yarnpkg.com/eslint-plugin-prettier/-/eslint-plugin-prettier-4.2.1.tgz#651cbb88b1dab98bfd42f017a12fa6b2d993f94b"
  integrity sha512-f/0rXLXUt0oFYs8ra4w49wYZBG5GKZpAYsJSm6rnYL5uVDjd+zowwMwVZHnAjf4edNrKpCDYfXDgmRE/Ak7QyQ==
eslint-plugin-prettier@^5.0.0:
  version "5.0.0"
  resolved "https://registry.yarnpkg.com/eslint-plugin-prettier/-/eslint-plugin-prettier-5.0.0.tgz#6887780ed95f7708340ec79acfdf60c35b9be57a"
  integrity sha512-AgaZCVuYDXHUGxj/ZGu1u8H8CYgDY3iG6w5kUFw4AzMVXzB7VvbKgYR4nATIN+OvUrghMbiDLeimVjVY5ilq3w==
  dependencies:
    prettier-linter-helpers "^1.0.0"
    synckit "^0.8.5"

eslint-plugin-promise@~6.1.1:
  version "6.1.1"


@@ 9320,10 9321,10 @@ prettier-linter-helpers@^1.0.0:
  dependencies:
    fast-diff "^1.1.2"

prettier@^2.8.8:
  version "2.8.8"
  resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.8.8.tgz#e8c5d7e98a4305ffe3de2e1fc4aca1a71c28b1da"
  integrity sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==
prettier@^3.0.0:
  version "3.0.0"
  resolved "https://registry.yarnpkg.com/prettier/-/prettier-3.0.0.tgz#e7b19f691245a21d618c68bc54dc06122f6105ae"
  integrity sha512-zBf5eHpwHOGPC47h0zrPyNn+eAEIdEzfywMoYn2XPi0P44Zp0tSq64rq0xAREh4auw2cJZHo9QUob+NqCQky4g==

pretty-bytes@^5.3.0, pretty-bytes@^5.4.1:
  version "5.6.0"


@@ 10916,6 10917,7 @@ stringz@^2.1.0:
    char-regex "^1.0.2"

"strip-ansi-cjs@npm:strip-ansi@^6.0.1", strip-ansi@^6.0.0, strip-ansi@^6.0.1:
  name strip-ansi-cjs
  version "6.0.1"
  resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9"
  integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==