diff --git a/public/locales/en.json b/public/locales/en.json index 9515c380..f7127904 100644 --- a/public/locales/en.json +++ b/public/locales/en.json @@ -446,6 +446,7 @@ "segment_dm": "Direct", "segment_channels": "Channels", "segment_bots": "Robots", + "refreshing": "Refreshing…", "self_row_label": "You", "self_row_preview": "Settings & profile", "message_me_label": "me", diff --git a/public/locales/ru.json b/public/locales/ru.json index 42a3d815..6bded616 100644 --- a/public/locales/ru.json +++ b/public/locales/ru.json @@ -448,6 +448,7 @@ "segment_dm": "Личные", "segment_channels": "Каналы", "segment_bots": "Роботы", + "refreshing": "Обновляем…", "self_row_label": "Я", "self_row_preview": "Настройки и профиль", "message_me_label": "я", diff --git a/public/res/img/mascot-dance.png b/public/res/img/mascot-dance.png new file mode 100644 index 00000000..f377a232 Binary files /dev/null and b/public/res/img/mascot-dance.png differ diff --git a/public/res/img/mascot-dance.webm b/public/res/img/mascot-dance.webm new file mode 100644 index 00000000..1d0bcaca Binary files /dev/null and b/public/res/img/mascot-dance.webm differ diff --git a/src/app/components/mobile-tabs-pager/style.css.ts b/src/app/components/mobile-tabs-pager/style.css.ts index 533cb282..e944a297 100644 --- a/src/app/components/mobile-tabs-pager/style.css.ts +++ b/src/app/components/mobile-tabs-pager/style.css.ts @@ -6,7 +6,7 @@ import { color } from 'folds'; // horizontally; `align-items: stretch` on the parent fills vertically. // // `touch-action: pan-y` lets the browser keep doing native vertical -// scroll (DM list virtualizer, curtain peek pull-down) without us +// scroll (DM list virtualizer, curtain pull-to-refresh) without us // having to call preventDefault on every move — only the pager's own // listener calls preventDefault, and only after axis-resolve commits // to "horizontal". @@ -93,7 +93,7 @@ export const pagerRoot = style({ // top in the safe-top + tabsRow band — the void is contained to // the carve area, tabs stay visible. The horseshoe's `appBody` // flips back to opaque on the same signal so the void doesn't -// bleed into the chip-area band between the static header and +// bleed into the mascot/form band between the static header and // the curtain top either. The curtain pin gesture is gated off // in the same state (see `StreamHeader.gestureDisabled`) so no // pin can race the elevation flip. diff --git a/src/app/components/stream-header/Chip.tsx b/src/app/components/stream-header/Chip.tsx deleted file mode 100644 index 417e4783..00000000 --- a/src/app/components/stream-header/Chip.tsx +++ /dev/null @@ -1,32 +0,0 @@ -import React from 'react'; -import { Icon, IconSrc } from 'folds'; -import * as css from './StreamHeader.css'; - -type ChipProps = { - iconSrc: IconSrc; - label: string; - onClick: () => void; - // When the curtain covers the chip its row is `height: 0` / - // `overflow: hidden`. We also flip `tabIndex` so keyboard users - // can't focus the invisible button on desktop (where peek-drag is - // unavailable). Re-enabled when the row is revealed. - hidden: boolean; -}; - -// Pill-shaped reveal button shown when the user drags the curtain down -// to a peek stage. Same geometry as the inline form's input bar so the -// transition chip → input feels like a content swap, not a layout move. -export function Chip({ iconSrc, label, onClick, hidden }: ChipProps) { - return ( - - ); -} diff --git a/src/app/components/stream-header/RefreshMascot.tsx b/src/app/components/stream-header/RefreshMascot.tsx new file mode 100644 index 00000000..e14f4c2b --- /dev/null +++ b/src/app/components/stream-header/RefreshMascot.tsx @@ -0,0 +1,85 @@ +import React, { useMemo } from 'react'; +import { Text } from 'folds'; +import { isNativePlatform } from '../../utils/capacitor'; + +// Dancing-mascot pull-to-refresh asset — the pink "evil mascot" working +// out (dumbbells + radar rings), cut to a seamless 2s loop, background +// keyed to alpha, VP9. SEPARATE from the auth `mascot.*` (the purple +// idle mascot), which is unchanged. +import mascotPoster from '../../../../public/res/img/mascot-dance.png'; +import mascotWebm from '../../../../public/res/img/mascot-dance.webm'; +import * as css from './StreamHeader.css'; + +type RefreshMascotProps = { + // Caption under the mascot («Обновляем…»). Passed by StreamHeader so the + // copy stays in the i18n layer rather than baked in here. + caption: string; + // True while the curtain is revealing — or resting at — the refresh card + // (refresh snap, or a live down-drag from closed). Only then do we mount + // the looping